diff --git a/packages/create-gen-app/README.md b/packages/create-gen-app/README.md index 5aa9664..7384377 100644 --- a/packages/create-gen-app/README.md +++ b/packages/create-gen-app/README.md @@ -21,7 +21,7 @@ A TypeScript-first CLI/library for cloning template repositories, asking the use ## Features - Clone any Git repo (or GitHub `org/repo` shorthand) and optionally select a branch + subdirectory -- Extract template variables from filenames and file contents using the safer `____VARIABLE____` convention +- Extract template variables from filenames and file contents using the safer `____variable____` convention - Merge auto-discovered variables with `.questions.{json,js}` (questions win, including `ignore` patterns) - Interactive prompts powered by `inquirerer`, with CLI flag overrides (`--VAR value`) and non-TTY mode for CI - Built-in CLI (`create-gen-app` / `cga`) that discovers templates, prompts once, and writes output safely @@ -84,14 +84,14 @@ await createGen({ Variables should be wrapped in four underscores on each side: ``` -____PROJECT_NAME____/ - src/____MODULE_NAME____.ts +____projectName____/ + src/____moduleName____.ts ``` ```typescript -// ____MODULE_NAME____.ts -export const projectName = "____PROJECT_NAME____"; -export const author = "____USERFULLNAME____"; +// ____moduleName____.ts +export const projectName = "____projectName____"; +export const author = "____fullName____"; ``` ### Custom Questions & Ignore Rules @@ -103,13 +103,13 @@ Create a `.questions.json`: "ignore": ["__tests__", "docs/drafts"], "questions": [ { - "name": "____USERFULLNAME____", + "name": "____fullName____", "type": "text", "message": "Enter author full name", "required": true }, { - "name": "____LICENSE____", + "name": "____license____", "type": "list", "message": "Choose a license", "options": ["MIT", "Apache-2.0", "ISC", "GPL-3.0"] @@ -118,7 +118,7 @@ Create a `.questions.json`: } ``` -Or `.questions.js` for dynamic logic. Question names can use `____VAR____` or plain `VAR`; they'll be normalized automatically. +Or `.questions.js` for dynamic logic. Question names can use `____var____` or plain `VAR`; they'll be normalized automatically. ### License Templates @@ -136,4 +136,4 @@ No code changes are needed; the CLI discovers templates at runtime and will warn - `promptUser(extracted, argv, noTty)` – run interactive questions with CLI overrides and alias deduping - `replaceVariables(templateDir, outputDir, extracted, answers)` – copy files, rename paths, render licenses -See `dev/README.md` for the local development helper script (`pnpm dev`). \ No newline at end of file +See `dev/README.md` for the local development helper script (`pnpm dev`). diff --git a/packages/create-gen-app/__tests__/create-gen.test.ts b/packages/create-gen-app/__tests__/create-gen.test.ts index 6576b0b..00b3558 100644 --- a/packages/create-gen-app/__tests__/create-gen.test.ts +++ b/packages/create-gen-app/__tests__/create-gen.test.ts @@ -45,10 +45,10 @@ describe("create-gen-app", () => { describe("extractVariables", () => { it("should extract variables from filenames", async () => { fs.writeFileSync( - path.join(testTempDir, "____PROJECT_NAME____.txt"), + path.join(testTempDir, "____projectName____.txt"), "content" ); - fs.writeFileSync(path.join(testTempDir, "____AUTHOR____.md"), "content"); + fs.writeFileSync(path.join(testTempDir, "____author____.md"), "content"); const result = await extractVariables(testTempDir); @@ -62,7 +62,7 @@ describe("create-gen-app", () => { it("should extract variables from file contents", async () => { fs.writeFileSync( path.join(testTempDir, "test.txt"), - "Hello ____USER_NAME____, welcome to ____PROJECT_NAME____!" + "Hello ____userName____, welcome to ____projectName____!" ); const result = await extractVariables(testTempDir); @@ -77,11 +77,11 @@ describe("create-gen-app", () => { }); it("should extract variables from nested directories", async () => { - const nestedDir = path.join(testTempDir, "src", "____MODULE_NAME____"); + const nestedDir = path.join(testTempDir, "src", "____moduleName____"); fs.mkdirSync(nestedDir, { recursive: true }); fs.writeFileSync( - path.join(nestedDir, "____FILE_NAME____.ts"), - 'export const ____CONSTANT____ = "value";' + path.join(nestedDir, "____fileName____.ts"), + 'export const ____constant____ = "value";' ); const result = await extractVariables(testTempDir); @@ -163,7 +163,7 @@ module.exports = { it("should skip .questions.json and .questions.js from variable extraction", async () => { fs.writeFileSync( path.join(testTempDir, ".questions.json"), - '{"questions": [{"name": "____SHOULD_NOT_EXTRACT____"}]}' + '{"questions": [{"name": "____shouldNotExtract____"}]}' ); const result = await extractVariables(testTempDir); @@ -176,7 +176,7 @@ module.exports = { it("should handle variables with different casings", async () => { fs.writeFileSync( path.join(testTempDir, "test.txt"), - "____lowercase____ ____UPPERCASE____ ____CamelCase____ ____snake_case____" + "____lowercase____ ____uppercase____ ____CamelCase____ ____snake_case____" ); const result = await extractVariables(testTempDir); @@ -210,9 +210,9 @@ module.exports = { const extractedVariables: ExtractedVariables = { fileReplacers: [ - { variable: "PROJECT_NAME", pattern: /____PROJECT_NAME____/g }, + { variable: "projectName", pattern: /____projectName____/g }, ], - contentReplacers: [{ variable: "AUTHOR", pattern: /____AUTHOR____/g }], + contentReplacers: [{ variable: "author", pattern: /____author____/g }], projectQuestions: null, }; @@ -272,7 +272,7 @@ module.exports = { const extractedVariables: ExtractedVariables = { fileReplacers: [ - { variable: "PROJECT_NAME", pattern: /____PROJECT_NAME____/g }, + { variable: "projectName", pattern: /____projectName____/g }, ], contentReplacers: [], projectQuestions: null, @@ -298,7 +298,7 @@ module.exports = { const extractedVariables: ExtractedVariables = { fileReplacers: [], contentReplacers: [ - { variable: "USERFULLNAME", pattern: /____USERFULLNAME____/g }, + { variable: "fullName", pattern: /____fullName____/g }, ], projectQuestions: { questions: [ @@ -330,7 +330,7 @@ module.exports = { const extractedVariables: ExtractedVariables = { fileReplacers: [], contentReplacers: [ - { variable: "MODULEDESC", pattern: /____MODULEDESC____/g }, + { variable: "moduleDesc", pattern: /____moduleDesc____/g }, ], projectQuestions: { questions: [ @@ -363,7 +363,7 @@ module.exports = { const extractedVariables: ExtractedVariables = { fileReplacers: [], contentReplacers: [ - { variable: "USERFULLNAME", pattern: /____USERFULLNAME____/g }, + { variable: "fullName", pattern: /____fullName____/g }, ], projectQuestions: { questions: [ @@ -394,7 +394,7 @@ module.exports = { const extractedVariables: ExtractedVariables = { fileReplacers: [], contentReplacers: [ - { variable: "MODULEDESC", pattern: /____MODULEDESC____/g }, + { variable: "moduleDesc", pattern: /____moduleDesc____/g }, ], projectQuestions: { questions: [ @@ -417,7 +417,7 @@ module.exports = { it("should replace variables in file contents", async () => { fs.writeFileSync( path.join(testTempDir, "README.md"), - "# ____PROJECT_NAME____\n\nBy ____AUTHOR____" + "# ____projectName____\n\nBy ____author____" ); const extractedVariables = await extractVariables(testTempDir); @@ -443,7 +443,7 @@ module.exports = { it("should replace variables in filenames", async () => { fs.writeFileSync( - path.join(testTempDir, "____PROJECT_NAME____.config.js"), + path.join(testTempDir, "____projectName____.config.js"), "module.exports = {};" ); @@ -466,11 +466,11 @@ module.exports = { }); it("should replace variables in nested directory names", async () => { - const nestedDir = path.join(testTempDir, "src", "____MODULE_NAME____"); + const nestedDir = path.join(testTempDir, "src", "____moduleName____"); fs.mkdirSync(nestedDir, { recursive: true }); fs.writeFileSync( path.join(nestedDir, "index.ts"), - 'export const name = "____MODULE_NAME____";' + 'export const name = "____moduleName____";' ); const extractedVariables = await extractVariables(testTempDir); @@ -517,7 +517,7 @@ module.exports = { it("should handle multiple occurrences of the same variable", async () => { fs.writeFileSync( path.join(testTempDir, "test.txt"), - "____NAME____ loves ____NAME____ and ____NAME____ is great!" + "____name____ loves ____name____ and ____name____ is great!" ); const extractedVariables = await extractVariables(testTempDir); @@ -578,7 +578,7 @@ module.exports = { fs.mkdirSync(ignoredDir); fs.writeFileSync( path.join(ignoredDir, "example.txt"), - "This file has ____IGNORED____ variable" + "This file has ____ignored____ variable" ); fs.writeFileSync( path.join(testTempDir, ".questions.json"), diff --git a/packages/create-gen-app/src/extract.ts b/packages/create-gen-app/src/extract.ts index e53e17f..ed2d2c0 100644 --- a/packages/create-gen-app/src/extract.ts +++ b/packages/create-gen-app/src/extract.ts @@ -11,7 +11,7 @@ import { const PLACEHOLDER_BOUNDARY = "____"; /** - * Pattern to match ____VARIABLE____ in filenames and content + * Pattern to match ____variable____ in filenames and content */ const VARIABLE_PATTERN = new RegExp( `${PLACEHOLDER_BOUNDARY}([A-Za-z_][A-Za-z0-9_]*)${PLACEHOLDER_BOUNDARY}`, diff --git a/packages/create-gen-app/src/types.ts b/packages/create-gen-app/src/types.ts index 45a23f2..928cca3 100644 --- a/packages/create-gen-app/src/types.ts +++ b/packages/create-gen-app/src/types.ts @@ -11,7 +11,7 @@ export interface Questions { } /** - * Variable extracted from filename patterns like ____VARIABLE____ + * Variable extracted from filename patterns like ____variable____ */ export interface FileReplacer { variable: string; @@ -19,7 +19,7 @@ export interface FileReplacer { } /** - * Variable extracted from file content patterns like ____VARIABLE____ + * Variable extracted from file content patterns like ____variable____ */ export interface ContentReplacer { variable: string;