create-m5kdev 0.7.0 → 0.8.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (66) hide show
  1. package/dist/src/constants.d.mts +7 -0
  2. package/dist/src/constants.mjs +10 -0
  3. package/dist/src/constants.mjs.map +1 -0
  4. package/dist/src/create.d.mts +12 -0
  5. package/dist/src/create.mjs +33 -0
  6. package/dist/src/create.mjs.map +1 -0
  7. package/dist/src/fs.d.mts +10 -0
  8. package/dist/src/fs.mjs +50 -0
  9. package/dist/src/fs.mjs.map +1 -0
  10. package/dist/src/index.d.mts +1 -0
  11. package/dist/src/index.mjs +12 -0
  12. package/dist/src/index.mjs.map +1 -0
  13. package/dist/src/paths.d.mts +5 -0
  14. package/dist/src/paths.mjs +13 -0
  15. package/dist/src/paths.mjs.map +1 -0
  16. package/dist/src/prompts.d.mts +7 -0
  17. package/dist/src/prompts.mjs +45 -0
  18. package/dist/src/prompts.mjs.map +1 -0
  19. package/dist/src/runCli.d.mts +12 -0
  20. package/dist/src/runCli.mjs +101 -0
  21. package/dist/src/runCli.mjs.map +1 -0
  22. package/dist/src/strings.d.mts +11 -0
  23. package/dist/src/strings.mjs +34 -0
  24. package/dist/src/strings.mjs.map +1 -0
  25. package/dist/src/types.d.mts +22 -0
  26. package/package.json +3 -2
  27. package/dist/__tests__/create.smoke.test.js +0 -91
  28. package/dist/__tests__/create.test.js +0 -102
  29. package/dist/__tests__/runCli.test.js +0 -44
  30. package/dist/__tests__/strings.test.js +0 -24
  31. package/dist/constants.js +0 -9
  32. package/dist/create.js +0 -54
  33. package/dist/fs.js +0 -119
  34. package/dist/index.js +0 -9
  35. package/dist/paths.js +0 -14
  36. package/dist/prompts.js +0 -98
  37. package/dist/runCli.js +0 -119
  38. package/dist/src/__tests__/create.smoke.test.js +0 -56
  39. package/dist/src/__tests__/create.test.d.ts +0 -1
  40. package/dist/src/__tests__/create.test.js +0 -55
  41. package/dist/src/__tests__/runCli.test.d.ts +0 -1
  42. package/dist/src/__tests__/runCli.test.js +0 -44
  43. package/dist/src/__tests__/strings.test.d.ts +0 -1
  44. package/dist/src/__tests__/strings.test.js +0 -24
  45. package/dist/src/constants.d.ts +0 -3
  46. package/dist/src/constants.js +0 -9
  47. package/dist/src/create.d.ts +0 -7
  48. package/dist/src/create.js +0 -36
  49. package/dist/src/fs.d.ts +0 -5
  50. package/dist/src/fs.js +0 -60
  51. package/dist/src/index.d.ts +0 -2
  52. package/dist/src/index.js +0 -9
  53. package/dist/src/paths.d.ts +0 -1
  54. package/dist/src/paths.js +0 -14
  55. package/dist/src/prompts.d.ts +0 -2
  56. package/dist/src/prompts.js +0 -55
  57. package/dist/src/runCli.d.ts +0 -9
  58. package/dist/src/runCli.js +0 -107
  59. package/dist/src/strings.d.ts +0 -6
  60. package/dist/src/strings.js +0 -47
  61. package/dist/src/types.d.ts +0 -18
  62. package/dist/src/types.js +0 -2
  63. package/dist/strings.js +0 -47
  64. package/dist/tsconfig.tsbuildinfo +0 -1
  65. package/dist/types.js +0 -2
  66. /package/dist/src/{__tests__/create.smoke.test.d.ts → types.mjs} +0 -0
@@ -0,0 +1,7 @@
1
+ //#region src/constants.d.ts
2
+ declare const TEMPLATE_NAME = "minimal-app";
3
+ declare const DEFAULT_APP_NAME = "M5 Starter";
4
+ declare function getDefaultDescription(appName: string): string;
5
+ //#endregion
6
+ export { DEFAULT_APP_NAME, TEMPLATE_NAME, getDefaultDescription };
7
+ //# sourceMappingURL=constants.d.mts.map
@@ -0,0 +1,10 @@
1
+ //#region src/constants.ts
2
+ const TEMPLATE_NAME = "minimal-app";
3
+ const DEFAULT_APP_NAME = "M5 Starter";
4
+ function getDefaultDescription(appName) {
5
+ return `${appName} is a blog publishing platform scaffolded with the m5kdev stack.`;
6
+ }
7
+ //#endregion
8
+ export { DEFAULT_APP_NAME, TEMPLATE_NAME, getDefaultDescription };
9
+
10
+ //# sourceMappingURL=constants.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.mjs","names":[],"sources":["../../src/constants.ts"],"sourcesContent":["export const TEMPLATE_NAME = \"minimal-app\";\r\n\r\nexport const DEFAULT_APP_NAME = \"M5 Starter\";\r\n\r\nexport function getDefaultDescription(appName: string): string {\r\n return `${appName} is a blog publishing platform scaffolded with the m5kdev stack.`;\r\n}\r\n"],"mappings":";AAAA,MAAa,gBAAgB;AAE7B,MAAa,mBAAmB;AAEhC,SAAgB,sBAAsB,SAAyB;AAC7D,QAAO,GAAG,QAAQ"}
@@ -0,0 +1,12 @@
1
+ import { CreateCommandOptions, TemplateContext } from "./types.mjs";
2
+
3
+ //#region src/create.d.ts
4
+ interface ScaffoldResult {
5
+ context: TemplateContext;
6
+ targetDirectory: string;
7
+ templateName: string;
8
+ }
9
+ declare function scaffoldProject(initialOptions: CreateCommandOptions): Promise<ScaffoldResult>;
10
+ //#endregion
11
+ export { ScaffoldResult, scaffoldProject };
12
+ //# sourceMappingURL=create.d.mts.map
@@ -0,0 +1,33 @@
1
+ import { TEMPLATE_NAME } from "./constants.mjs";
2
+ import { createBetterAuthSecret, derivePackageScope, slugifyAppName } from "./strings.mjs";
3
+ import { copyTemplateDirectory, ensureDirectoryState, runGitInit, runInstall } from "./fs.mjs";
4
+ import { getTemplateRoot } from "./paths.mjs";
5
+ import { resolveCreateCommandOptions } from "./prompts.mjs";
6
+ import path from "node:path";
7
+ //#region src/create.ts
8
+ async function scaffoldProject(initialOptions) {
9
+ const options = await resolveCreateCommandOptions(initialOptions);
10
+ const appSlug = slugifyAppName(options.appName);
11
+ const targetDirectory = path.resolve(process.cwd(), options.targetDirectory);
12
+ const templateDirectory = getTemplateRoot();
13
+ const context = {
14
+ appName: options.appName,
15
+ appDescription: options.appDescription,
16
+ appSlug,
17
+ packageScope: derivePackageScope(appSlug),
18
+ betterAuthSecret: createBetterAuthSecret()
19
+ };
20
+ await ensureDirectoryState(targetDirectory, options.force);
21
+ await copyTemplateDirectory(templateDirectory, targetDirectory, context);
22
+ if (!options.skipGit) await runGitInit(targetDirectory);
23
+ if (!options.skipInstall) await runInstall(targetDirectory);
24
+ return {
25
+ context,
26
+ targetDirectory,
27
+ templateName: TEMPLATE_NAME
28
+ };
29
+ }
30
+ //#endregion
31
+ export { scaffoldProject };
32
+
33
+ //# sourceMappingURL=create.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"create.mjs","names":[],"sources":["../../src/create.ts"],"sourcesContent":["import path from \"node:path\";\r\nimport { TEMPLATE_NAME } from \"./constants\";\r\nimport { copyTemplateDirectory, ensureDirectoryState, runGitInit, runInstall } from \"./fs\";\r\nimport { getTemplateRoot } from \"./paths\";\r\nimport { resolveCreateCommandOptions } from \"./prompts\";\r\nimport { createBetterAuthSecret, derivePackageScope, slugifyAppName } from \"./strings\";\r\nimport type { CreateCommandOptions, TemplateContext } from \"./types\";\r\n\r\nexport interface ScaffoldResult {\r\n context: TemplateContext;\r\n targetDirectory: string;\r\n templateName: string;\r\n}\r\n\r\nexport async function scaffoldProject(initialOptions: CreateCommandOptions): Promise<ScaffoldResult> {\r\n const options = await resolveCreateCommandOptions(initialOptions);\r\n const appSlug = slugifyAppName(options.appName!);\r\n const targetDirectory = path.resolve(process.cwd(), options.targetDirectory!);\r\n const templateDirectory = getTemplateRoot();\r\n\r\n const context: TemplateContext = {\r\n appName: options.appName!,\r\n appDescription: options.appDescription!,\r\n appSlug,\r\n packageScope: derivePackageScope(appSlug),\r\n betterAuthSecret: createBetterAuthSecret(),\r\n };\r\n\r\n await ensureDirectoryState(targetDirectory, options.force);\r\n await copyTemplateDirectory(templateDirectory, targetDirectory, context);\r\n\r\n if (!options.skipGit) {\r\n await runGitInit(targetDirectory);\r\n }\r\n\r\n if (!options.skipInstall) {\r\n await runInstall(targetDirectory);\r\n }\r\n\r\n return {\r\n context,\r\n targetDirectory,\r\n templateName: TEMPLATE_NAME,\r\n };\r\n}\r\n"],"mappings":";;;;;;;AAcA,eAAsB,gBAAgB,gBAA+D;CACnG,MAAM,UAAU,MAAM,4BAA4B,eAAe;CACjE,MAAM,UAAU,eAAe,QAAQ,QAAS;CAChD,MAAM,kBAAkB,KAAK,QAAQ,QAAQ,KAAK,EAAE,QAAQ,gBAAiB;CAC7E,MAAM,oBAAoB,iBAAiB;CAE3C,MAAM,UAA2B;EAC/B,SAAS,QAAQ;EACjB,gBAAgB,QAAQ;EACxB;EACA,cAAc,mBAAmB,QAAQ;EACzC,kBAAkB,wBAAwB;EAC3C;AAED,OAAM,qBAAqB,iBAAiB,QAAQ,MAAM;AAC1D,OAAM,sBAAsB,mBAAmB,iBAAiB,QAAQ;AAExE,KAAI,CAAC,QAAQ,QACX,OAAM,WAAW,gBAAgB;AAGnC,KAAI,CAAC,QAAQ,YACX,OAAM,WAAW,gBAAgB;AAGnC,QAAO;EACL;EACA;EACA,cAAc;EACf"}
@@ -0,0 +1,10 @@
1
+ import { TemplateContext } from "./types.mjs";
2
+
3
+ //#region src/fs.d.ts
4
+ declare function ensureDirectoryState(targetDirectory: string, force: boolean): Promise<void>;
5
+ declare function copyTemplateDirectory(templateDirectory: string, targetDirectory: string, context: TemplateContext): Promise<void>;
6
+ declare function runInstall(targetDirectory: string): Promise<void>;
7
+ declare function runGitInit(targetDirectory: string): Promise<void>;
8
+ //#endregion
9
+ export { copyTemplateDirectory, ensureDirectoryState, runGitInit, runInstall };
10
+ //# sourceMappingURL=fs.d.mts.map
@@ -0,0 +1,50 @@
1
+ import { renderTemplate } from "./strings.mjs";
2
+ import path from "node:path";
3
+ import { execFile } from "node:child_process";
4
+ import fs from "node:fs/promises";
5
+ import { promisify } from "node:util";
6
+ //#region src/fs.ts
7
+ const execFileAsync = promisify(execFile);
8
+ const TEMPLATE_LINE_ENDING = "\r\n";
9
+ async function ensureDirectoryState(targetDirectory, force) {
10
+ const stat = await fs.stat(targetDirectory).catch(() => null);
11
+ if (!stat) {
12
+ await fs.mkdir(targetDirectory, { recursive: true });
13
+ return;
14
+ }
15
+ if (!stat.isDirectory()) throw new Error(`Target path is not a directory: ${targetDirectory}`);
16
+ if ((await fs.readdir(targetDirectory)).length > 0 && !force) throw new Error(`Target directory is not empty: ${targetDirectory}. Re-run with --force to overwrite.`);
17
+ }
18
+ async function copyTemplateDirectory(templateDirectory, targetDirectory, context) {
19
+ const entries = await fs.readdir(templateDirectory, { withFileTypes: true });
20
+ for (const entry of entries) {
21
+ const sourcePath = path.join(templateDirectory, entry.name);
22
+ const targetName = entry.name.endsWith(".tpl") ? entry.name.slice(0, -4) : entry.name;
23
+ const targetPath = path.join(targetDirectory, targetName);
24
+ if (entry.isDirectory()) {
25
+ await fs.mkdir(targetPath, { recursive: true });
26
+ await copyTemplateDirectory(sourcePath, targetPath, context);
27
+ continue;
28
+ }
29
+ if (!entry.isFile()) continue;
30
+ const rendered = renderTemplate(await fs.readFile(sourcePath, "utf8"), context).replace(/\r?\n/g, TEMPLATE_LINE_ENDING);
31
+ await fs.mkdir(path.dirname(targetPath), { recursive: true });
32
+ await fs.writeFile(targetPath, rendered, "utf8");
33
+ }
34
+ }
35
+ async function runInstall(targetDirectory) {
36
+ await execFileAsync("pnpm", ["install"], {
37
+ cwd: targetDirectory,
38
+ env: process.env
39
+ });
40
+ }
41
+ async function runGitInit(targetDirectory) {
42
+ await execFileAsync("git", ["init"], {
43
+ cwd: targetDirectory,
44
+ env: process.env
45
+ });
46
+ }
47
+ //#endregion
48
+ export { copyTemplateDirectory, ensureDirectoryState, runGitInit, runInstall };
49
+
50
+ //# sourceMappingURL=fs.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fs.mjs","names":[],"sources":["../../src/fs.ts"],"sourcesContent":["import { execFile } from \"node:child_process\";\r\nimport fs from \"node:fs/promises\";\r\nimport path from \"node:path\";\r\nimport { promisify } from \"node:util\";\r\nimport type { TemplateContext } from \"./types\";\r\nimport { renderTemplate } from \"./strings\";\r\n\r\nconst execFileAsync = promisify(execFile);\r\nconst TEMPLATE_LINE_ENDING = \"\\r\\n\";\r\n\r\nexport async function ensureDirectoryState(\r\n targetDirectory: string,\r\n force: boolean\r\n): Promise<void> {\r\n const stat = await fs.stat(targetDirectory).catch(() => null);\r\n\r\n if (!stat) {\r\n await fs.mkdir(targetDirectory, { recursive: true });\r\n return;\r\n }\r\n\r\n if (!stat.isDirectory()) {\r\n throw new Error(`Target path is not a directory: ${targetDirectory}`);\r\n }\r\n\r\n const entries = await fs.readdir(targetDirectory);\r\n if (entries.length > 0 && !force) {\r\n throw new Error(\r\n `Target directory is not empty: ${targetDirectory}. Re-run with --force to overwrite.`\r\n );\r\n }\r\n}\r\n\r\nexport async function copyTemplateDirectory(\r\n templateDirectory: string,\r\n targetDirectory: string,\r\n context: TemplateContext\r\n): Promise<void> {\r\n const entries = await fs.readdir(templateDirectory, { withFileTypes: true });\r\n\r\n for (const entry of entries) {\r\n const sourcePath = path.join(templateDirectory, entry.name);\r\n const targetName = entry.name.endsWith(\".tpl\") ? entry.name.slice(0, -4) : entry.name;\r\n const targetPath = path.join(targetDirectory, targetName);\r\n\r\n if (entry.isDirectory()) {\r\n await fs.mkdir(targetPath, { recursive: true });\r\n await copyTemplateDirectory(sourcePath, targetPath, context);\r\n continue;\r\n }\r\n\r\n if (!entry.isFile()) {\r\n continue;\r\n }\r\n\r\n const content = await fs.readFile(sourcePath, \"utf8\");\r\n const rendered = renderTemplate(content, context).replace(/\\r?\\n/g, TEMPLATE_LINE_ENDING);\r\n await fs.mkdir(path.dirname(targetPath), { recursive: true });\r\n await fs.writeFile(targetPath, rendered, \"utf8\");\r\n }\r\n}\r\n\r\nexport async function runInstall(targetDirectory: string): Promise<void> {\r\n await execFileAsync(\"pnpm\", [\"install\"], {\r\n cwd: targetDirectory,\r\n env: process.env,\r\n });\r\n}\r\n\r\nexport async function runGitInit(targetDirectory: string): Promise<void> {\r\n await execFileAsync(\"git\", [\"init\"], {\r\n cwd: targetDirectory,\r\n env: process.env,\r\n });\r\n}\r\n"],"mappings":";;;;;;AAOA,MAAM,gBAAgB,UAAU,SAAS;AACzC,MAAM,uBAAuB;AAE7B,eAAsB,qBACpB,iBACA,OACe;CACf,MAAM,OAAO,MAAM,GAAG,KAAK,gBAAgB,CAAC,YAAY,KAAK;AAE7D,KAAI,CAAC,MAAM;AACT,QAAM,GAAG,MAAM,iBAAiB,EAAE,WAAW,MAAM,CAAC;AACpD;;AAGF,KAAI,CAAC,KAAK,aAAa,CACrB,OAAM,IAAI,MAAM,mCAAmC,kBAAkB;AAIvE,MADgB,MAAM,GAAG,QAAQ,gBAAgB,EACrC,SAAS,KAAK,CAAC,MACzB,OAAM,IAAI,MACR,kCAAkC,gBAAgB,qCACnD;;AAIL,eAAsB,sBACpB,mBACA,iBACA,SACe;CACf,MAAM,UAAU,MAAM,GAAG,QAAQ,mBAAmB,EAAE,eAAe,MAAM,CAAC;AAE5E,MAAK,MAAM,SAAS,SAAS;EAC3B,MAAM,aAAa,KAAK,KAAK,mBAAmB,MAAM,KAAK;EAC3D,MAAM,aAAa,MAAM,KAAK,SAAS,OAAO,GAAG,MAAM,KAAK,MAAM,GAAG,GAAG,GAAG,MAAM;EACjF,MAAM,aAAa,KAAK,KAAK,iBAAiB,WAAW;AAEzD,MAAI,MAAM,aAAa,EAAE;AACvB,SAAM,GAAG,MAAM,YAAY,EAAE,WAAW,MAAM,CAAC;AAC/C,SAAM,sBAAsB,YAAY,YAAY,QAAQ;AAC5D;;AAGF,MAAI,CAAC,MAAM,QAAQ,CACjB;EAIF,MAAM,WAAW,eADD,MAAM,GAAG,SAAS,YAAY,OAAO,EACZ,QAAQ,CAAC,QAAQ,UAAU,qBAAqB;AACzF,QAAM,GAAG,MAAM,KAAK,QAAQ,WAAW,EAAE,EAAE,WAAW,MAAM,CAAC;AAC7D,QAAM,GAAG,UAAU,YAAY,UAAU,OAAO;;;AAIpD,eAAsB,WAAW,iBAAwC;AACvE,OAAM,cAAc,QAAQ,CAAC,UAAU,EAAE;EACvC,KAAK;EACL,KAAK,QAAQ;EACd,CAAC;;AAGJ,eAAsB,WAAW,iBAAwC;AACvE,OAAM,cAAc,OAAO,CAAC,OAAO,EAAE;EACnC,KAAK;EACL,KAAK,QAAQ;EACd,CAAC"}
@@ -0,0 +1 @@
1
+ export { };
@@ -0,0 +1,12 @@
1
+ #!/usr/bin/env node
2
+ import { runCli } from "./runCli.mjs";
3
+ //#region src/index.ts
4
+ runCli(process.argv.slice(2)).catch((error) => {
5
+ const message = error instanceof Error ? error.message : String(error);
6
+ console.error(message);
7
+ process.exitCode = 1;
8
+ });
9
+ //#endregion
10
+ export {};
11
+
12
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../../src/index.ts"],"sourcesContent":["#!/usr/bin/env node\r\n\r\nimport { runCli } from \"./runCli\";\r\n\r\nrunCli(process.argv.slice(2)).catch((error: unknown) => {\r\n const message = error instanceof Error ? error.message : String(error);\r\n console.error(message);\r\n process.exitCode = 1;\r\n});\r\n"],"mappings":";;;AAIA,OAAO,QAAQ,KAAK,MAAM,EAAE,CAAC,CAAC,OAAO,UAAmB;CACtD,MAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM;AACtE,SAAQ,MAAM,QAAQ;AACtB,SAAQ,WAAW;EACnB"}
@@ -0,0 +1,5 @@
1
+ //#region src/paths.d.ts
2
+ declare function getTemplateRoot(): string;
3
+ //#endregion
4
+ export { getTemplateRoot };
5
+ //# sourceMappingURL=paths.d.mts.map
@@ -0,0 +1,13 @@
1
+ import { TEMPLATE_NAME } from "./constants.mjs";
2
+ import path from "node:path";
3
+ import fs from "node:fs";
4
+ //#region src/paths.ts
5
+ function getTemplateRoot() {
6
+ const sourcePath = path.resolve(__dirname, "../templates", TEMPLATE_NAME);
7
+ if (fs.existsSync(sourcePath)) return sourcePath;
8
+ return path.resolve(__dirname, "../../templates", TEMPLATE_NAME);
9
+ }
10
+ //#endregion
11
+ export { getTemplateRoot };
12
+
13
+ //# sourceMappingURL=paths.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"paths.mjs","names":[],"sources":["../../src/paths.ts"],"sourcesContent":["import fs from \"node:fs\";\r\nimport path from \"node:path\";\r\nimport { TEMPLATE_NAME } from \"./constants\";\r\n\r\nexport function getTemplateRoot(): string {\r\n const sourcePath = path.resolve(__dirname, \"../templates\", TEMPLATE_NAME);\r\n if (fs.existsSync(sourcePath)) {\r\n return sourcePath;\r\n }\r\n\r\n return path.resolve(__dirname, \"../../templates\", TEMPLATE_NAME);\r\n}\r\n"],"mappings":";;;;AAIA,SAAgB,kBAA0B;CACxC,MAAM,aAAa,KAAK,QAAQ,WAAW,gBAAgB,cAAc;AACzE,KAAI,GAAG,WAAW,WAAW,CAC3B,QAAO;AAGT,QAAO,KAAK,QAAQ,WAAW,mBAAmB,cAAc"}
@@ -0,0 +1,7 @@
1
+ import { CreateCommandOptions } from "./types.mjs";
2
+
3
+ //#region src/prompts.d.ts
4
+ declare function resolveCreateCommandOptions(options: CreateCommandOptions): Promise<CreateCommandOptions>;
5
+ //#endregion
6
+ export { resolveCreateCommandOptions };
7
+ //# sourceMappingURL=prompts.d.mts.map
@@ -0,0 +1,45 @@
1
+ import { DEFAULT_APP_NAME, getDefaultDescription } from "./constants.mjs";
2
+ import { slugifyAppName, toDisplayName } from "./strings.mjs";
3
+ import readline from "node:readline/promises";
4
+ import { stdin, stdout } from "node:process";
5
+ //#region src/prompts.ts
6
+ function requireInteractive(yes) {
7
+ if (!yes && !process.stdin.isTTY) throw new Error("Missing required values in a non-interactive shell. Pass --yes or provide flags.");
8
+ }
9
+ async function promptValue(question, fallback) {
10
+ const rl = readline.createInterface({
11
+ input: stdin,
12
+ output: stdout
13
+ });
14
+ try {
15
+ const suffix = fallback ? ` (${fallback})` : "";
16
+ return (await rl.question(`${question}${suffix}: `)).trim() || fallback || "";
17
+ } finally {
18
+ rl.close();
19
+ }
20
+ }
21
+ async function resolveCreateCommandOptions(options) {
22
+ const resolved = { ...options };
23
+ if (!resolved.appName) {
24
+ requireInteractive(resolved.yes);
25
+ resolved.appName = resolved.yes ? resolved.targetDirectory ? toDisplayName(pathBaseName(resolved.targetDirectory)) : DEFAULT_APP_NAME : await promptValue("App name", resolved.targetDirectory ? pathBaseName(resolved.targetDirectory) : DEFAULT_APP_NAME);
26
+ }
27
+ resolved.appName = toDisplayName(resolved.appName);
28
+ if (!resolved.targetDirectory) {
29
+ requireInteractive(resolved.yes);
30
+ resolved.targetDirectory = resolved.yes ? slugifyAppName(resolved.appName) : await promptValue("Target directory", slugifyAppName(resolved.appName));
31
+ }
32
+ if (!resolved.appDescription) {
33
+ requireInteractive(resolved.yes);
34
+ const fallback = getDefaultDescription(resolved.appName);
35
+ resolved.appDescription = resolved.yes ? fallback : await promptValue("App description", fallback);
36
+ }
37
+ return resolved;
38
+ }
39
+ function pathBaseName(value) {
40
+ return value.replace(/[\\/]+$/g, "").split(/[\\/]/).filter(Boolean).at(-1) || "M5 Starter";
41
+ }
42
+ //#endregion
43
+ export { resolveCreateCommandOptions };
44
+
45
+ //# sourceMappingURL=prompts.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prompts.mjs","names":[],"sources":["../../src/prompts.ts"],"sourcesContent":["import readline from \"node:readline/promises\";\r\nimport { stdin as input, stdout as output } from \"node:process\";\r\nimport { DEFAULT_APP_NAME, getDefaultDescription } from \"./constants\";\r\nimport { slugifyAppName, toDisplayName } from \"./strings\";\r\nimport type { CreateCommandOptions } from \"./types\";\r\n\r\nfunction requireInteractive(yes: boolean): void {\r\n if (!yes && !process.stdin.isTTY) {\r\n throw new Error(\"Missing required values in a non-interactive shell. Pass --yes or provide flags.\");\r\n }\r\n}\r\n\r\nasync function promptValue(question: string, fallback?: string): Promise<string> {\r\n const rl = readline.createInterface({ input, output });\r\n\r\n try {\r\n const suffix = fallback ? ` (${fallback})` : \"\";\r\n const response = await rl.question(`${question}${suffix}: `);\r\n return response.trim() || fallback || \"\";\r\n } finally {\r\n rl.close();\r\n }\r\n}\r\n\r\nexport async function resolveCreateCommandOptions(\r\n options: CreateCommandOptions\r\n): Promise<CreateCommandOptions> {\r\n const resolved = { ...options };\r\n\r\n if (!resolved.appName) {\r\n requireInteractive(resolved.yes);\r\n resolved.appName = resolved.yes\r\n ? resolved.targetDirectory\r\n ? toDisplayName(pathBaseName(resolved.targetDirectory))\r\n : DEFAULT_APP_NAME\r\n : await promptValue(\"App name\", resolved.targetDirectory ? pathBaseName(resolved.targetDirectory) : DEFAULT_APP_NAME);\r\n }\r\n\r\n resolved.appName = toDisplayName(resolved.appName);\r\n\r\n if (!resolved.targetDirectory) {\r\n requireInteractive(resolved.yes);\r\n resolved.targetDirectory = resolved.yes\r\n ? slugifyAppName(resolved.appName)\r\n : await promptValue(\"Target directory\", slugifyAppName(resolved.appName));\r\n }\r\n\r\n if (!resolved.appDescription) {\r\n requireInteractive(resolved.yes);\r\n const fallback = getDefaultDescription(resolved.appName);\r\n resolved.appDescription = resolved.yes\r\n ? fallback\r\n : await promptValue(\"App description\", fallback);\r\n }\r\n\r\n return resolved;\r\n}\r\n\r\nfunction pathBaseName(value: string): string {\r\n const normalized = value.replace(/[\\\\/]+$/g, \"\");\r\n const segments = normalized.split(/[\\\\/]/).filter(Boolean);\r\n return segments.at(-1) || DEFAULT_APP_NAME;\r\n}\r\n"],"mappings":";;;;;AAMA,SAAS,mBAAmB,KAAoB;AAC9C,KAAI,CAAC,OAAO,CAAC,QAAQ,MAAM,MACzB,OAAM,IAAI,MAAM,mFAAmF;;AAIvG,eAAe,YAAY,UAAkB,UAAoC;CAC/E,MAAM,KAAK,SAAS,gBAAgB;EAAE,OAAA;EAAO,QAAA;EAAQ,CAAC;AAEtD,KAAI;EACF,MAAM,SAAS,WAAW,KAAK,SAAS,KAAK;AAE7C,UADiB,MAAM,GAAG,SAAS,GAAG,WAAW,OAAO,IAAI,EAC5C,MAAM,IAAI,YAAY;WAC9B;AACR,KAAG,OAAO;;;AAId,eAAsB,4BACpB,SAC+B;CAC/B,MAAM,WAAW,EAAE,GAAG,SAAS;AAE/B,KAAI,CAAC,SAAS,SAAS;AACrB,qBAAmB,SAAS,IAAI;AAChC,WAAS,UAAU,SAAS,MACxB,SAAS,kBACP,cAAc,aAAa,SAAS,gBAAgB,CAAC,GACrD,mBACF,MAAM,YAAY,YAAY,SAAS,kBAAkB,aAAa,SAAS,gBAAgB,GAAG,iBAAiB;;AAGzH,UAAS,UAAU,cAAc,SAAS,QAAQ;AAElD,KAAI,CAAC,SAAS,iBAAiB;AAC7B,qBAAmB,SAAS,IAAI;AAChC,WAAS,kBAAkB,SAAS,MAChC,eAAe,SAAS,QAAQ,GAChC,MAAM,YAAY,oBAAoB,eAAe,SAAS,QAAQ,CAAC;;AAG7E,KAAI,CAAC,SAAS,gBAAgB;AAC5B,qBAAmB,SAAS,IAAI;EAChC,MAAM,WAAW,sBAAsB,SAAS,QAAQ;AACxD,WAAS,iBAAiB,SAAS,MAC/B,WACA,MAAM,YAAY,mBAAmB,SAAS;;AAGpD,QAAO;;AAGT,SAAS,aAAa,OAAuB;AAG3C,QAFmB,MAAM,QAAQ,YAAY,GAAG,CACpB,MAAM,QAAQ,CAAC,OAAO,QAAQ,CAC1C,GAAG,GAAG,IAAA"}
@@ -0,0 +1,12 @@
1
+ //#region src/runCli.d.ts
2
+ interface ParsedCli {
3
+ command?: string;
4
+ directory?: string;
5
+ help?: boolean;
6
+ options: Record<string, string | boolean>;
7
+ }
8
+ declare function runCli(argv: readonly string[]): Promise<void>;
9
+ declare function parseCli(argv: readonly string[]): ParsedCli;
10
+ //#endregion
11
+ export { parseCli, runCli };
12
+ //# sourceMappingURL=runCli.d.mts.map
@@ -0,0 +1,101 @@
1
+ import { scaffoldProject } from "./create.mjs";
2
+ //#region src/runCli.ts
3
+ async function runCli(argv) {
4
+ const parsed = parseCli(argv);
5
+ if (!parsed.command || parsed.help || parsed.command === "--help" || parsed.command === "-h" || parsed.command === "help") {
6
+ printHelp();
7
+ return;
8
+ }
9
+ if (parsed.command !== "create") throw new Error(`Unknown command: ${parsed.command}`);
10
+ const options = toCreateCommandOptions(parsed);
11
+ const result = await scaffoldProject(options);
12
+ console.log("");
13
+ console.log(`Scaffolded ${result.context.appName} in ${result.targetDirectory}`);
14
+ console.log("");
15
+ console.log("Next steps:");
16
+ console.log(` cd ${result.targetDirectory}`);
17
+ if (options.skipInstall) console.log(" pnpm install");
18
+ console.log(" pnpm --filter ./apps/server sync");
19
+ console.log(" pnpm dev");
20
+ }
21
+ function parseCli(argv) {
22
+ const [command, ...rest] = normalizeCliArgv(argv);
23
+ const options = {};
24
+ let directory;
25
+ let help = false;
26
+ for (let index = 0; index < rest.length; index += 1) {
27
+ const token = rest[index];
28
+ if (token === "--help" || token === "-h") {
29
+ help = true;
30
+ continue;
31
+ }
32
+ if (!token.startsWith("--")) {
33
+ directory ??= token;
34
+ continue;
35
+ }
36
+ const [rawKey, inlineValue] = token.slice(2).split("=", 2);
37
+ if (isBooleanFlag(rawKey)) {
38
+ options[rawKey] = true;
39
+ continue;
40
+ }
41
+ const nextValue = inlineValue ?? rest[index + 1];
42
+ if (!nextValue || nextValue.startsWith("--")) throw new Error(`Missing value for --${rawKey}`);
43
+ options[rawKey] = nextValue;
44
+ if (inlineValue === void 0) index += 1;
45
+ }
46
+ return {
47
+ command,
48
+ directory,
49
+ help,
50
+ options
51
+ };
52
+ }
53
+ function normalizeCliArgv(argv) {
54
+ const [firstToken] = argv;
55
+ if (!firstToken || firstToken === "create" || firstToken === "--help" || firstToken === "-h") return argv;
56
+ if (firstToken === "help") return ["--help"];
57
+ return ["create", ...argv];
58
+ }
59
+ function isBooleanFlag(value) {
60
+ return [
61
+ "yes",
62
+ "force",
63
+ "skip-install",
64
+ "skip-git"
65
+ ].includes(value);
66
+ }
67
+ function toCreateCommandOptions(parsed) {
68
+ return {
69
+ targetDirectory: parsed.directory,
70
+ appName: getStringOption(parsed.options, "name"),
71
+ appDescription: getStringOption(parsed.options, "description"),
72
+ yes: Boolean(parsed.options.yes),
73
+ force: Boolean(parsed.options.force),
74
+ skipInstall: Boolean(parsed.options["skip-install"]),
75
+ skipGit: Boolean(parsed.options["skip-git"])
76
+ };
77
+ }
78
+ function getStringOption(options, key) {
79
+ const value = options[key];
80
+ return typeof value === "string" ? value : void 0;
81
+ }
82
+ function printHelp() {
83
+ console.log("m5kdev");
84
+ console.log("");
85
+ console.log("Usage:");
86
+ console.log(" pnpm create m5kdev [directory] [options]");
87
+ console.log(" m5kdev [directory] [options]");
88
+ console.log(" m5kdev create [directory] [options]");
89
+ console.log("");
90
+ console.log("Options:");
91
+ console.log(" --name <value> Set the app name");
92
+ console.log(" --description <value> Set the app description");
93
+ console.log(" --yes Accept defaults for missing prompts");
94
+ console.log(" --force Allow writing into a non-empty directory");
95
+ console.log(" --skip-install Skip pnpm install");
96
+ console.log(" --skip-git Skip git init");
97
+ }
98
+ //#endregion
99
+ export { parseCli, runCli };
100
+
101
+ //# sourceMappingURL=runCli.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runCli.mjs","names":[],"sources":["../../src/runCli.ts"],"sourcesContent":["import { scaffoldProject } from \"./create\";\r\nimport type { CreateCommandOptions } from \"./types\";\r\n\r\ninterface ParsedCli {\n command?: string;\n directory?: string;\n help?: boolean;\n options: Record<string, string | boolean>;\n}\n\r\nexport async function runCli(argv: readonly string[]): Promise<void> {\r\n const parsed = parseCli(argv);\r\n\r\n if (\n !parsed.command ||\n parsed.help ||\n parsed.command === \"--help\" ||\n parsed.command === \"-h\" ||\n parsed.command === \"help\"\n ) {\n printHelp();\n return;\n }\n\r\n if (parsed.command !== \"create\") {\r\n throw new Error(`Unknown command: ${parsed.command}`);\r\n }\r\n\r\n const options = toCreateCommandOptions(parsed);\r\n const result = await scaffoldProject(options);\r\n\r\n console.log(\"\");\r\n console.log(`Scaffolded ${result.context.appName} in ${result.targetDirectory}`);\r\n console.log(\"\");\r\n console.log(\"Next steps:\");\r\n console.log(` cd ${result.targetDirectory}`);\r\n if (options.skipInstall) {\r\n console.log(\" pnpm install\");\r\n }\r\n console.log(\" pnpm --filter ./apps/server sync\");\r\n console.log(\" pnpm dev\");\r\n}\r\n\r\nexport function parseCli(argv: readonly string[]): ParsedCli {\n const normalizedArgv = normalizeCliArgv(argv);\n const [command, ...rest] = normalizedArgv;\n const options: Record<string, string | boolean> = {};\n let directory: string | undefined;\n let help = false;\n\n for (let index = 0; index < rest.length; index += 1) {\n const token = rest[index];\n\n if (token === \"--help\" || token === \"-h\") {\n help = true;\n continue;\n }\n\n if (!token.startsWith(\"--\")) {\n directory ??= token;\n continue;\n }\r\n\r\n const [rawKey, inlineValue] = token.slice(2).split(\"=\", 2);\r\n\r\n if (isBooleanFlag(rawKey)) {\r\n options[rawKey] = true;\r\n continue;\r\n }\r\n\r\n const nextValue = inlineValue ?? rest[index + 1];\r\n if (!nextValue || nextValue.startsWith(\"--\")) {\r\n throw new Error(`Missing value for --${rawKey}`);\r\n }\r\n\r\n options[rawKey] = nextValue;\r\n if (inlineValue === undefined) {\r\n index += 1;\r\n }\r\n }\n\n return { command, directory, help, options };\n}\n\nfunction normalizeCliArgv(argv: readonly string[]): readonly string[] {\n const [firstToken] = argv;\n\n if (!firstToken || firstToken === \"create\" || firstToken === \"--help\" || firstToken === \"-h\") {\n return argv;\n }\n\n if (firstToken === \"help\") {\n return [\"--help\"];\n }\n\n return [\"create\", ...argv];\n}\n\r\nfunction isBooleanFlag(value: string): boolean {\r\n return [\"yes\", \"force\", \"skip-install\", \"skip-git\"].includes(value);\r\n}\r\n\r\nfunction toCreateCommandOptions(parsed: ParsedCli): CreateCommandOptions {\r\n return {\r\n targetDirectory: parsed.directory,\r\n appName: getStringOption(parsed.options, \"name\"),\r\n appDescription: getStringOption(parsed.options, \"description\"),\r\n yes: Boolean(parsed.options.yes),\r\n force: Boolean(parsed.options.force),\r\n skipInstall: Boolean(parsed.options[\"skip-install\"]),\r\n skipGit: Boolean(parsed.options[\"skip-git\"]),\r\n };\r\n}\r\n\r\nfunction getStringOption(\r\n options: Record<string, string | boolean>,\r\n key: string\r\n): string | undefined {\r\n const value = options[key];\r\n return typeof value === \"string\" ? value : undefined;\r\n}\r\n\r\nfunction printHelp(): void {\n console.log(\"m5kdev\");\n console.log(\"\");\n console.log(\"Usage:\");\n console.log(\" pnpm create m5kdev [directory] [options]\");\n console.log(\" m5kdev [directory] [options]\");\n console.log(\" m5kdev create [directory] [options]\");\n console.log(\"\");\n console.log(\"Options:\");\n console.log(\" --name <value> Set the app name\");\r\n console.log(\" --description <value> Set the app description\");\r\n console.log(\" --yes Accept defaults for missing prompts\");\r\n console.log(\" --force Allow writing into a non-empty directory\");\r\n console.log(\" --skip-install Skip pnpm install\");\r\n console.log(\" --skip-git Skip git init\");\r\n}\r\n"],"mappings":";;AAUA,eAAsB,OAAO,MAAwC;CACnE,MAAM,SAAS,SAAS,KAAK;AAE7B,KACE,CAAC,OAAO,WACR,OAAO,QACP,OAAO,YAAY,YACnB,OAAO,YAAY,QACnB,OAAO,YAAY,QACnB;AACA,aAAW;AACX;;AAGF,KAAI,OAAO,YAAY,SACrB,OAAM,IAAI,MAAM,oBAAoB,OAAO,UAAU;CAGvD,MAAM,UAAU,uBAAuB,OAAO;CAC9C,MAAM,SAAS,MAAM,gBAAgB,QAAQ;AAE7C,SAAQ,IAAI,GAAG;AACf,SAAQ,IAAI,cAAc,OAAO,QAAQ,QAAQ,MAAM,OAAO,kBAAkB;AAChF,SAAQ,IAAI,GAAG;AACf,SAAQ,IAAI,cAAc;AAC1B,SAAQ,IAAI,QAAQ,OAAO,kBAAkB;AAC7C,KAAI,QAAQ,YACV,SAAQ,IAAI,iBAAiB;AAE/B,SAAQ,IAAI,qCAAqC;AACjD,SAAQ,IAAI,aAAa;;AAG3B,SAAgB,SAAS,MAAoC;CAE3D,MAAM,CAAC,SAAS,GAAG,QADI,iBAAiB,KAAK;CAE7C,MAAM,UAA4C,EAAE;CACpD,IAAI;CACJ,IAAI,OAAO;AAEX,MAAK,IAAI,QAAQ,GAAG,QAAQ,KAAK,QAAQ,SAAS,GAAG;EACnD,MAAM,QAAQ,KAAK;AAEnB,MAAI,UAAU,YAAY,UAAU,MAAM;AACxC,UAAO;AACP;;AAGF,MAAI,CAAC,MAAM,WAAW,KAAK,EAAE;AAC3B,iBAAc;AACd;;EAGF,MAAM,CAAC,QAAQ,eAAe,MAAM,MAAM,EAAE,CAAC,MAAM,KAAK,EAAE;AAE1D,MAAI,cAAc,OAAO,EAAE;AACzB,WAAQ,UAAU;AAClB;;EAGF,MAAM,YAAY,eAAe,KAAK,QAAQ;AAC9C,MAAI,CAAC,aAAa,UAAU,WAAW,KAAK,CAC1C,OAAM,IAAI,MAAM,uBAAuB,SAAS;AAGlD,UAAQ,UAAU;AAClB,MAAI,gBAAgB,KAAA,EAClB,UAAS;;AAIb,QAAO;EAAE;EAAS;EAAW;EAAM;EAAS;;AAG9C,SAAS,iBAAiB,MAA4C;CACpE,MAAM,CAAC,cAAc;AAErB,KAAI,CAAC,cAAc,eAAe,YAAY,eAAe,YAAY,eAAe,KACtF,QAAO;AAGT,KAAI,eAAe,OACjB,QAAO,CAAC,SAAS;AAGnB,QAAO,CAAC,UAAU,GAAG,KAAK;;AAG5B,SAAS,cAAc,OAAwB;AAC7C,QAAO;EAAC;EAAO;EAAS;EAAgB;EAAW,CAAC,SAAS,MAAM;;AAGrE,SAAS,uBAAuB,QAAyC;AACvE,QAAO;EACL,iBAAiB,OAAO;EACxB,SAAS,gBAAgB,OAAO,SAAS,OAAO;EAChD,gBAAgB,gBAAgB,OAAO,SAAS,cAAc;EAC9D,KAAK,QAAQ,OAAO,QAAQ,IAAI;EAChC,OAAO,QAAQ,OAAO,QAAQ,MAAM;EACpC,aAAa,QAAQ,OAAO,QAAQ,gBAAgB;EACpD,SAAS,QAAQ,OAAO,QAAQ,YAAY;EAC7C;;AAGH,SAAS,gBACP,SACA,KACoB;CACpB,MAAM,QAAQ,QAAQ;AACtB,QAAO,OAAO,UAAU,WAAW,QAAQ,KAAA;;AAG7C,SAAS,YAAkB;AACzB,SAAQ,IAAI,SAAS;AACrB,SAAQ,IAAI,GAAG;AACf,SAAQ,IAAI,SAAS;AACrB,SAAQ,IAAI,6CAA6C;AACzD,SAAQ,IAAI,iCAAiC;AAC7C,SAAQ,IAAI,wCAAwC;AACpD,SAAQ,IAAI,GAAG;AACf,SAAQ,IAAI,WAAW;AACvB,SAAQ,IAAI,8CAA8C;AAC1D,SAAQ,IAAI,qDAAqD;AACjE,SAAQ,IAAI,iEAAiE;AAC7E,SAAQ,IAAI,sEAAsE;AAClF,SAAQ,IAAI,+CAA+C;AAC3D,SAAQ,IAAI,2CAA2C"}
@@ -0,0 +1,11 @@
1
+ import { TemplateContext } from "./types.mjs";
2
+
3
+ //#region src/strings.d.ts
4
+ declare function slugifyAppName(value: string): string;
5
+ declare function derivePackageScope(appSlug: string): string;
6
+ declare function toDisplayName(value: string): string;
7
+ declare function createBetterAuthSecret(): string;
8
+ declare function renderTemplate(content: string, context: TemplateContext): string;
9
+ //#endregion
10
+ export { createBetterAuthSecret, derivePackageScope, renderTemplate, slugifyAppName, toDisplayName };
11
+ //# sourceMappingURL=strings.d.mts.map
@@ -0,0 +1,34 @@
1
+ import { randomBytes } from "node:crypto";
2
+ //#region src/strings.ts
3
+ function slugifyAppName(value) {
4
+ const slug = value.trim().toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+/g, "").replace(/-+$/g, "").replace(/-{2,}/g, "-");
5
+ if (!slug) throw new Error("Unable to derive an app slug from the provided name.");
6
+ return slug;
7
+ }
8
+ function derivePackageScope(appSlug) {
9
+ return `@${appSlug}`;
10
+ }
11
+ function toDisplayName(value) {
12
+ const normalized = value.trim();
13
+ if (!normalized) throw new Error("App name cannot be empty.");
14
+ return normalized;
15
+ }
16
+ function createBetterAuthSecret() {
17
+ return randomBytes(24).toString("base64url");
18
+ }
19
+ function renderTemplate(content, context) {
20
+ const replacements = {
21
+ APP_NAME: context.appName,
22
+ APP_DESCRIPTION: context.appDescription,
23
+ APP_SLUG: context.appSlug,
24
+ PACKAGE_SCOPE: context.packageScope,
25
+ BETTER_AUTH_SECRET: context.betterAuthSecret
26
+ };
27
+ return content.replace(/\{\{([A-Z_]+)\}\}/g, (match, token) => {
28
+ return replacements[token] ?? match;
29
+ });
30
+ }
31
+ //#endregion
32
+ export { createBetterAuthSecret, derivePackageScope, renderTemplate, slugifyAppName, toDisplayName };
33
+
34
+ //# sourceMappingURL=strings.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"strings.mjs","names":[],"sources":["../../src/strings.ts"],"sourcesContent":["import { randomBytes } from \"node:crypto\";\r\nimport type { TemplateContext } from \"./types\";\r\n\r\nexport function slugifyAppName(value: string): string {\r\n const slug = value\r\n .trim()\r\n .toLowerCase()\r\n .replace(/[^a-z0-9]+/g, \"-\")\r\n .replace(/^-+/g, \"\")\r\n .replace(/-+$/g, \"\")\r\n .replace(/-{2,}/g, \"-\");\r\n\r\n if (!slug) {\r\n throw new Error(\"Unable to derive an app slug from the provided name.\");\r\n }\r\n\r\n return slug;\r\n}\r\n\r\nexport function derivePackageScope(appSlug: string): string {\r\n return `@${appSlug}`;\r\n}\r\n\r\nexport function toDisplayName(value: string): string {\r\n const normalized = value.trim();\r\n if (!normalized) {\r\n throw new Error(\"App name cannot be empty.\");\r\n }\r\n\r\n return normalized;\r\n}\r\n\r\nexport function createBetterAuthSecret(): string {\r\n return randomBytes(24).toString(\"base64url\");\r\n}\r\n\r\nexport function renderTemplate(content: string, context: TemplateContext): string {\r\n const replacements: Record<string, string> = {\r\n APP_NAME: context.appName,\r\n APP_DESCRIPTION: context.appDescription,\r\n APP_SLUG: context.appSlug,\r\n PACKAGE_SCOPE: context.packageScope,\r\n BETTER_AUTH_SECRET: context.betterAuthSecret,\r\n };\r\n\r\n return content.replace(/\\{\\{([A-Z_]+)\\}\\}/g, (match, token: string) => {\r\n const replacement = replacements[token];\r\n return replacement ?? match;\r\n });\r\n}\r\n"],"mappings":";;AAGA,SAAgB,eAAe,OAAuB;CACpD,MAAM,OAAO,MACV,MAAM,CACN,aAAa,CACb,QAAQ,eAAe,IAAI,CAC3B,QAAQ,QAAQ,GAAG,CACnB,QAAQ,QAAQ,GAAG,CACnB,QAAQ,UAAU,IAAI;AAEzB,KAAI,CAAC,KACH,OAAM,IAAI,MAAM,uDAAuD;AAGzE,QAAO;;AAGT,SAAgB,mBAAmB,SAAyB;AAC1D,QAAO,IAAI;;AAGb,SAAgB,cAAc,OAAuB;CACnD,MAAM,aAAa,MAAM,MAAM;AAC/B,KAAI,CAAC,WACH,OAAM,IAAI,MAAM,4BAA4B;AAG9C,QAAO;;AAGT,SAAgB,yBAAiC;AAC/C,QAAO,YAAY,GAAG,CAAC,SAAS,YAAY;;AAG9C,SAAgB,eAAe,SAAiB,SAAkC;CAChF,MAAM,eAAuC;EAC3C,UAAU,QAAQ;EAClB,iBAAiB,QAAQ;EACzB,UAAU,QAAQ;EAClB,eAAe,QAAQ;EACvB,oBAAoB,QAAQ;EAC7B;AAED,QAAO,QAAQ,QAAQ,uBAAuB,OAAO,UAAkB;AAErE,SADoB,aAAa,UACX;GACtB"}
@@ -0,0 +1,22 @@
1
+ //#region src/types.d.ts
2
+ interface PromptValues {
3
+ targetDirectory?: string;
4
+ appName?: string;
5
+ appDescription?: string;
6
+ }
7
+ interface CreateCommandOptions extends PromptValues {
8
+ yes: boolean;
9
+ force: boolean;
10
+ skipInstall: boolean;
11
+ skipGit: boolean;
12
+ }
13
+ interface TemplateContext {
14
+ appName: string;
15
+ appDescription: string;
16
+ appSlug: string;
17
+ packageScope: string;
18
+ betterAuthSecret: string;
19
+ }
20
+ //#endregion
21
+ export { CreateCommandOptions, PromptValues, TemplateContext };
22
+ //# sourceMappingURL=types.d.mts.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-m5kdev",
3
- "version": "0.7.0",
3
+ "version": "0.8.2",
4
4
  "license": "GPL-3.0-only",
5
5
  "repository": {
6
6
  "type": "git",
@@ -24,10 +24,11 @@
24
24
  "@types/node": "20.19.11",
25
25
  "jest": "30.1.3",
26
26
  "ts-jest": "29.4.4",
27
+ "tsdown": "0.21.7",
27
28
  "typescript": "5.9.2"
28
29
  },
29
30
  "scripts": {
30
- "build": "tsc --build",
31
+ "build": "tsdown",
31
32
  "lint": "biome check .",
32
33
  "lint:fix": "biome check . --write",
33
34
  "check-types": "tsc --noEmit",
@@ -1,91 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- var tslib_1 = require("tslib");
4
- var node_child_process_1 = require("node:child_process");
5
- var promises_1 = tslib_1.__importDefault(require("node:fs/promises"));
6
- var node_os_1 = tslib_1.__importDefault(require("node:os"));
7
- var node_path_1 = tslib_1.__importDefault(require("node:path"));
8
- var node_util_1 = require("node:util");
9
- var create_1 = require("../create");
10
- var execFileAsync = (0, node_util_1.promisify)(node_child_process_1.execFile);
11
- var maybeDescribe = process.env.CLI_SMOKE === "1" ? describe : describe.skip;
12
- maybeDescribe("create command smoke test", function () {
13
- var tempRoot = "";
14
- var initialCwd = "";
15
- beforeAll(function () { return tslib_1.__awaiter(void 0, void 0, void 0, function () {
16
- return tslib_1.__generator(this, function (_a) {
17
- switch (_a.label) {
18
- case 0:
19
- initialCwd = process.cwd();
20
- return [4 /*yield*/, promises_1.default.mkdtemp(node_path_1.default.join(node_os_1.default.tmpdir(), "m5kdev-cli-smoke-"))];
21
- case 1:
22
- tempRoot = _a.sent();
23
- process.chdir(tempRoot);
24
- return [2 /*return*/];
25
- }
26
- });
27
- }); });
28
- afterAll(function () { return tslib_1.__awaiter(void 0, void 0, void 0, function () {
29
- return tslib_1.__generator(this, function (_a) {
30
- switch (_a.label) {
31
- case 0:
32
- process.chdir(initialCwd);
33
- return [4 /*yield*/, promises_1.default.rm(tempRoot, { recursive: true, force: true })];
34
- case 1:
35
- _a.sent();
36
- return [2 /*return*/];
37
- }
38
- });
39
- }); });
40
- it("scaffolds a project and runs the generated commands", function () { return tslib_1.__awaiter(void 0, void 0, void 0, function () {
41
- var result;
42
- return tslib_1.__generator(this, function (_a) {
43
- switch (_a.label) {
44
- case 0:
45
- jest.setTimeout(10 * 60 * 1000);
46
- return [4 /*yield*/, (0, create_1.scaffoldProject)({
47
- targetDirectory: "smoke-app",
48
- appName: "Smoke App",
49
- appDescription: "Smoke test app",
50
- yes: true,
51
- force: false,
52
- skipInstall: false,
53
- skipGit: true,
54
- })];
55
- case 1:
56
- result = _a.sent();
57
- return [4 /*yield*/, execFileAsync("pnpm", ["check-types"], {
58
- cwd: result.targetDirectory,
59
- env: process.env,
60
- })];
61
- case 2:
62
- _a.sent();
63
- return [4 /*yield*/, execFileAsync("pnpm", ["lint"], {
64
- cwd: result.targetDirectory,
65
- env: process.env,
66
- })];
67
- case 3:
68
- _a.sent();
69
- return [4 /*yield*/, execFileAsync("pnpm", ["--filter", "./apps/server", "sync"], {
70
- cwd: result.targetDirectory,
71
- env: process.env,
72
- })];
73
- case 4:
74
- _a.sent();
75
- return [4 /*yield*/, execFileAsync("pnpm", ["--filter", "./apps/server", "build"], {
76
- cwd: result.targetDirectory,
77
- env: process.env,
78
- })];
79
- case 5:
80
- _a.sent();
81
- return [4 /*yield*/, execFileAsync("pnpm", ["--filter", "./apps/webapp", "build"], {
82
- cwd: result.targetDirectory,
83
- env: process.env,
84
- })];
85
- case 6:
86
- _a.sent();
87
- return [2 /*return*/];
88
- }
89
- });
90
- }); });
91
- });