@kidd-cli/cli 0.1.2 → 0.1.4

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.
@@ -1,12 +1,10 @@
1
- import { n as renderTemplate, t as writeFiles } from "../../write-DDGnajpV.mjs";
2
- import { t as detectProject } from "../../detect-CSSt9GdX.mjs";
1
+ import { n as isKebabCase, r as renderTemplate, t as writeFiles } from "../../write-CdoqLFeH.mjs";
2
+ import { t as detectProject } from "../../detect-DcO0_CWy.mjs";
3
3
  import { command } from "@kidd-cli/core";
4
4
  import { join } from "node:path";
5
5
  import { loadConfig } from "@kidd-cli/config/loader";
6
6
  import { z } from "zod";
7
-
8
7
  //#region src/commands/add/command.ts
9
- const KEBAB_CASE_CHARS_RE = /^[a-z][\da-z-]*$/;
10
8
  const addCommandCommand = command({
11
9
  args: z.object({
12
10
  args: z.boolean().describe("Include args schema").optional(),
@@ -18,8 +16,7 @@ const addCommandCommand = command({
18
16
  const [detectError, project] = await detectProject(process.cwd());
19
17
  if (detectError) return ctx.fail(detectError.message);
20
18
  if (!project) return ctx.fail("Not in a kidd project. Run `kidd init` first.");
21
- const [configError, configResult] = await loadConfig({ cwd: project.rootDir });
22
- if (configError) {}
19
+ const [, configResult] = await loadConfig({ cwd: project.rootDir });
23
20
  const commandName = await resolveCommandName(ctx);
24
21
  const commandDescription = await resolveDescription(ctx);
25
22
  const includeArgs = await resolveIncludeArgs(ctx);
@@ -50,24 +47,11 @@ const addCommandCommand = command({
50
47
  return ctx.fail(writeError.message);
51
48
  }
52
49
  ctx.spinner.stop("Command created!");
53
- result.written.map((file) => ctx.output.raw(` created ${file}`));
54
- result.skipped.map((file) => ctx.output.raw(` skipped ${file} (already exists)`));
50
+ const summary = [...result.written.map((file) => ` created ${file}`), ...result.skipped.map((file) => ` skipped ${file} (already exists)`)].join("\n");
51
+ if (summary.length > 0) ctx.output.raw(summary);
55
52
  }
56
53
  });
57
54
  /**
58
- * Check whether a string is valid kebab-case.
59
- *
60
- * @param value - The string to validate.
61
- * @returns True when the string is kebab-case.
62
- * @private
63
- */
64
- function isKebabCase(value) {
65
- if (!KEBAB_CASE_CHARS_RE.test(value)) return false;
66
- if (value.endsWith("-")) return false;
67
- if (value.includes("--")) return false;
68
- return true;
69
- }
70
- /**
71
55
  * Resolve the command name from args or prompt.
72
56
  *
73
57
  * @param ctx - Command context.
@@ -110,7 +94,7 @@ async function resolveDescription(ctx) {
110
94
  * @private
111
95
  */
112
96
  async function resolveIncludeArgs(ctx) {
113
- if (ctx.args.args !== void 0 && ctx.args.args !== null) return ctx.args.args;
97
+ if (ctx.args.args !== void 0) return ctx.args.args;
114
98
  return ctx.prompts.confirm({
115
99
  initialValue: true,
116
100
  message: "Include args schema?"
@@ -132,6 +116,5 @@ function resolveCommandsDir(configResult, rootDir) {
132
116
  if (configResult) return join(rootDir, configResult.config.commands ?? DEFAULT_COMMANDS);
133
117
  return join(rootDir, DEFAULT_COMMANDS);
134
118
  }
135
-
136
119
  //#endregion
137
- export { addCommandCommand as default };
120
+ export { addCommandCommand as default };
@@ -1,7 +1,5 @@
1
1
  import { command } from "@kidd-cli/core";
2
-
3
2
  //#region src/commands/add/index.ts
4
3
  const addCommand = command({ description: "Add a command or middleware to your project" });
5
-
6
4
  //#endregion
7
- export { addCommand as default };
5
+ export { addCommand as default };
@@ -1,11 +1,9 @@
1
- import { n as renderTemplate, t as writeFiles } from "../../write-DDGnajpV.mjs";
2
- import { t as detectProject } from "../../detect-CSSt9GdX.mjs";
1
+ import { n as isKebabCase, r as renderTemplate, t as writeFiles } from "../../write-CdoqLFeH.mjs";
2
+ import { t as detectProject } from "../../detect-DcO0_CWy.mjs";
3
3
  import { command } from "@kidd-cli/core";
4
4
  import { join } from "node:path";
5
5
  import { z } from "zod";
6
-
7
6
  //#region src/commands/add/middleware.ts
8
- const KEBAB_CASE_CHARS_RE = /^[a-z][\da-z-]*$/;
9
7
  const addMiddlewareCommand = command({
10
8
  args: z.object({
11
9
  description: z.string().describe("Middleware description").optional(),
@@ -44,24 +42,11 @@ const addMiddlewareCommand = command({
44
42
  return ctx.fail(writeError.message);
45
43
  }
46
44
  ctx.spinner.stop("Middleware created!");
47
- result.written.map((file) => ctx.output.raw(` created ${file}`));
48
- result.skipped.map((file) => ctx.output.raw(` skipped ${file} (already exists)`));
45
+ const summary = [...result.written.map((file) => ` created ${file}`), ...result.skipped.map((file) => ` skipped ${file} (already exists)`)].join("\n");
46
+ if (summary.length > 0) ctx.output.raw(summary);
49
47
  }
50
48
  });
51
49
  /**
52
- * Check whether a string is valid kebab-case.
53
- *
54
- * @param value - The string to validate.
55
- * @returns True when the string is kebab-case.
56
- * @private
57
- */
58
- function isKebabCase(value) {
59
- if (!KEBAB_CASE_CHARS_RE.test(value)) return false;
60
- if (value.endsWith("-")) return false;
61
- if (value.includes("--")) return false;
62
- return true;
63
- }
64
- /**
65
50
  * Resolve the middleware name from args or prompt.
66
51
  *
67
52
  * @param ctx - Command context.
@@ -96,6 +81,5 @@ async function resolveDescription(ctx) {
96
81
  placeholder: "What does this middleware do?"
97
82
  });
98
83
  }
99
-
100
84
  //#endregion
101
- export { addMiddlewareCommand as default };
85
+ export { addMiddlewareCommand as default };
@@ -1,9 +1,9 @@
1
+ import { t as extractConfig } from "../config-helpers-wZhBJJXJ.mjs";
1
2
  import { command } from "@kidd-cli/core";
2
3
  import { relative } from "node:path";
3
4
  import { build, compile, resolveTargetLabel } from "@kidd-cli/bundler";
4
5
  import { loadConfig } from "@kidd-cli/config/loader";
5
6
  import { z } from "zod";
6
-
7
7
  //#region src/commands/build.ts
8
8
  /**
9
9
  * Build a kidd CLI project for production using tsdown.
@@ -21,9 +21,8 @@ const buildCommand = command({
21
21
  description: "Build a kidd CLI project for production",
22
22
  handler: async (ctx) => {
23
23
  const cwd = process.cwd();
24
- const [configError, configResult] = await loadConfig({ cwd });
24
+ const [, configResult] = await loadConfig({ cwd });
25
25
  const config = extractConfig(configResult);
26
- if (configError) {}
27
26
  ctx.spinner.start("Bundling with tsdown...");
28
27
  const [buildError, buildOutput] = await build({
29
28
  config,
@@ -73,17 +72,6 @@ const buildCommand = command({
73
72
  }
74
73
  });
75
74
  /**
76
- * Extract a KiddConfig from a load result, falling back to empty defaults.
77
- *
78
- * @private
79
- * @param result - The result from loadConfig, or null when loading failed.
80
- * @returns The loaded config or an empty object (all KiddConfig fields are optional).
81
- */
82
- function extractConfig(result) {
83
- if (result) return result.config;
84
- return {};
85
- }
86
- /**
87
75
  * Determine whether compilation should run based on CLI flags and config.
88
76
  *
89
77
  * Resolution order:
@@ -158,6 +146,5 @@ function formatBinariesNote(params) {
158
146
  const maxLen = Math.max(...params.binaries.map((b) => b.label.length));
159
147
  return params.binaries.map((binary) => `${binary.label.padEnd(maxLen)} ${relative(params.cwd, binary.path)}`).join("\n");
160
148
  }
161
-
162
149
  //#endregion
163
- export { buildCommand as default };
150
+ export { buildCommand as default };
@@ -1,8 +1,8 @@
1
+ import { t as extractConfig } from "../config-helpers-wZhBJJXJ.mjs";
1
2
  import { autoload, command } from "@kidd-cli/core";
2
3
  import { join } from "node:path";
3
4
  import { loadConfig } from "@kidd-cli/config/loader";
4
5
  import { existsSync } from "node:fs";
5
-
6
6
  //#region src/commands/commands.ts
7
7
  /**
8
8
  * Display the command tree for a kidd CLI project.
@@ -15,10 +15,8 @@ const commandsCommand = command({
15
15
  description: "Display the command tree for a kidd CLI project",
16
16
  handler: async (ctx) => {
17
17
  const cwd = process.cwd();
18
- const [configError, configResult] = await loadConfig({ cwd });
19
- const config = extractConfig(configResult);
20
- if (configError) {}
21
- const commandsDir = join(cwd, config.commands ?? "commands");
18
+ const [, configResult] = await loadConfig({ cwd });
19
+ const commandsDir = join(cwd, extractConfig(configResult).commands ?? "commands");
22
20
  if (!existsSync(commandsDir)) ctx.fail(`Commands directory not found: ${commandsDir}`);
23
21
  ctx.spinner.start("Scanning commands...");
24
22
  const tree = await buildTree(await autoload({ dir: commandsDir }));
@@ -31,17 +29,6 @@ const commandsCommand = command({
31
29
  }
32
30
  });
33
31
  /**
34
- * Extract a KiddConfig from a load result, falling back to empty defaults.
35
- *
36
- * @private
37
- * @param result - The result from loadConfig, or null when loading failed.
38
- * @returns The loaded config or an empty object (all KiddConfig fields are optional).
39
- */
40
- function extractConfig(result) {
41
- if (result) return result.config;
42
- return {};
43
- }
44
- /**
45
32
  * Resolve a command's subcommands field, which may be a Promise, a map, or undefined.
46
33
  *
47
34
  * @private
@@ -130,6 +117,5 @@ function formatLabel(name, description) {
130
117
  if (description) return `${name} — ${description}`;
131
118
  return name;
132
119
  }
133
-
134
120
  //#endregion
135
- export { commandsCommand as default };
121
+ export { commandsCommand as default };
@@ -1,7 +1,7 @@
1
+ import { t as extractConfig } from "../config-helpers-wZhBJJXJ.mjs";
1
2
  import { command } from "@kidd-cli/core";
2
3
  import { watch } from "@kidd-cli/bundler";
3
4
  import { loadConfig } from "@kidd-cli/config/loader";
4
-
5
5
  //#region src/commands/dev.ts
6
6
  /**
7
7
  * Start a kidd CLI project in development mode with file watching.
@@ -13,9 +13,8 @@ const devCommand = command({
13
13
  description: "Start a kidd CLI project in development mode",
14
14
  handler: async (ctx) => {
15
15
  const cwd = process.cwd();
16
- const [configError, configResult] = await loadConfig({ cwd });
16
+ const [, configResult] = await loadConfig({ cwd });
17
17
  const config = extractConfig(configResult);
18
- if (configError) {}
19
18
  ctx.spinner.start("Starting dev server...");
20
19
  const [watchError] = await watch({
21
20
  config,
@@ -29,17 +28,6 @@ const devCommand = command({
29
28
  }
30
29
  });
31
30
  /**
32
- * Extract a KiddConfig from a load result, falling back to empty defaults.
33
- *
34
- * @private
35
- * @param result - The result from loadConfig, or null when loading failed.
36
- * @returns The loaded config or an empty object (all KiddConfig fields are optional).
37
- */
38
- function extractConfig(result) {
39
- if (result) return result.config;
40
- return {};
41
- }
42
- /**
43
31
  * Create an onSuccess callback that tracks first-build state.
44
32
  *
45
33
  * On the first invocation the spinner is stopped and a "watching" message is
@@ -63,6 +51,5 @@ function createOnSuccess(ctx) {
63
51
  ctx.logger.success("Rebuilt successfully");
64
52
  };
65
53
  }
66
-
67
54
  //#endregion
68
- export { devCommand as default };
55
+ export { devCommand as default };
@@ -3,11 +3,11 @@ import { dirname, join, relative } from "node:path";
3
3
  import { readManifest } from "@kidd-cli/utils/manifest";
4
4
  import { loadConfig } from "@kidd-cli/config/loader";
5
5
  import { z } from "zod";
6
+ import { attemptAsync, err, match, ok } from "@kidd-cli/utils/fp";
6
7
  import pc from "picocolors";
7
- import { access, mkdir, readFile, writeFile } from "node:fs/promises";
8
- import { attemptAsync, err, ok } from "@kidd-cli/utils/fp";
8
+ import { mkdir, readFile, writeFile } from "node:fs/promises";
9
+ import { fileExists } from "@kidd-cli/utils/fs";
9
10
  import { jsonParse, jsonStringify } from "@kidd-cli/utils/json";
10
-
11
11
  //#region src/lib/checks.ts
12
12
  /**
13
13
  * Default entry point for the CLI source.
@@ -440,17 +440,6 @@ async function readRawPackageJson(cwd) {
440
440
  return ok(data);
441
441
  }
442
442
  /**
443
- * Check whether a path exists on disk.
444
- *
445
- * @private
446
- * @param filePath - The path to check.
447
- * @returns True when the path is accessible, false otherwise.
448
- */
449
- async function fileExists(filePath) {
450
- const [accessError] = await attemptAsync(() => access(filePath));
451
- return accessError === null;
452
- }
453
- /**
454
443
  * Extract a KiddConfig from a load result, returning null when absent.
455
444
  *
456
445
  * @private
@@ -503,7 +492,6 @@ async function updatePackageJson(cwd, transform) {
503
492
  if (writeError) return err(`Failed to write package.json: ${writeError.message}`);
504
493
  return ok();
505
494
  }
506
-
507
495
  //#endregion
508
496
  //#region src/commands/doctor.ts
509
497
  /**
@@ -618,24 +606,23 @@ async function applyFixes(results, context) {
618
606
  * @param fixResults - The fix results (empty when --fix was not used).
619
607
  */
620
608
  function displayResults(ctx, results, fixResults) {
621
- results.map((result) => formatResultLine(ctx, result, fixResults));
609
+ const output = results.map((result) => formatResultLine(result, fixResults)).join("");
610
+ if (output.length > 0) ctx.output.raw(output);
622
611
  }
623
612
  /**
624
- * Format and display a single check result line with optional hint.
613
+ * Format a single check result line with optional hint.
625
614
  *
626
615
  * @private
627
- * @param ctx - The command context.
628
- * @param result - The check result to display.
616
+ * @param result - The check result to format.
629
617
  * @param fixResults - The fix results to check for applied fixes.
618
+ * @returns The formatted result line string.
630
619
  */
631
- function formatResultLine(ctx, result, fixResults) {
620
+ function formatResultLine(result, fixResults) {
632
621
  const appliedFix = fixResults.find((f) => f.name === result.name && f.fixed);
633
- if (appliedFix) {
634
- ctx.output.raw(` ${formatDisplayStatus("fix")} ${result.name} - ${appliedFix.message}\n`);
635
- return;
636
- }
637
- ctx.output.raw(` ${formatDisplayStatus(result.status)} ${result.name} - ${result.message}\n`);
638
- if (result.hint && result.status !== "pass") ctx.output.raw(` ${pc.dim(`→ ${result.hint}`)}\n`);
622
+ if (appliedFix) return ` ${formatDisplayStatus("fix")} ${result.name} - ${appliedFix.message}\n`;
623
+ const line = ` ${formatDisplayStatus(result.status)} ${result.name} - ${result.message}\n`;
624
+ if (result.hint && result.status !== "pass") return `${line} ${pc.dim(`→ ${result.hint}`)}\n`;
625
+ return line;
639
626
  }
640
627
  /**
641
628
  * Format a display status with color.
@@ -647,10 +634,7 @@ function formatResultLine(ctx, result, fixResults) {
647
634
  * @returns A colored string representation of the status.
648
635
  */
649
636
  function formatDisplayStatus(status) {
650
- if (status === "pass") return pc.green("pass");
651
- if (status === "warn") return pc.yellow("warn");
652
- if (status === "fix") return pc.blue("fix ");
653
- return pc.red("fail");
637
+ return match(status).with("pass", () => pc.green("pass")).with("warn", () => pc.yellow("warn")).with("fix", () => pc.blue("fix ")).with("fail", () => pc.red("fail")).exhaustive();
654
638
  }
655
639
  /**
656
640
  * Format the summary line with counts.
@@ -675,6 +659,5 @@ function pluralizeCheck(count) {
675
659
  if (count === 1) return "check";
676
660
  return "checks";
677
661
  }
678
-
679
662
  //#endregion
680
- export { doctorCommand as default };
663
+ export { doctorCommand as default };
@@ -1,13 +1,29 @@
1
- import { n as renderTemplate, t as writeFiles } from "../write-DDGnajpV.mjs";
1
+ import { n as isKebabCase, r as renderTemplate, t as writeFiles } from "../write-CdoqLFeH.mjs";
2
2
  import { createRequire } from "node:module";
3
3
  import { command } from "@kidd-cli/core";
4
4
  import { dirname, join } from "node:path";
5
5
  import { readManifest } from "@kidd-cli/utils/manifest";
6
6
  import { z } from "zod";
7
7
  import { attempt } from "@kidd-cli/utils/fp";
8
-
8
+ //#region src/generated/template-versions.ts
9
+ /**
10
+ * Zod version from the workspace catalog.
11
+ */
12
+ const ZOD_VERSION = "^4.3.6";
13
+ /**
14
+ * TypeScript version from the workspace catalog.
15
+ */
16
+ const TYPESCRIPT_VERSION = "^5.9.3";
17
+ /**
18
+ * Vitest version from the workspace catalog.
19
+ */
20
+ const VITEST_VERSION = "^4.0.18";
21
+ /**
22
+ * Tsdown version from the workspace catalog.
23
+ */
24
+ const TSDOWN_VERSION = "^0.21.1";
25
+ //#endregion
9
26
  //#region src/commands/init.ts
10
- const KEBAB_CASE_CHARS_RE = /^[a-z][\da-z-]*$/;
11
27
  const initCommand = command({
12
28
  args: z.object({
13
29
  description: z.string().describe("Project description").optional(),
@@ -35,7 +51,11 @@ const initCommand = command({
35
51
  coreVersion,
36
52
  description: projectDescription,
37
53
  name: projectName,
38
- packageManager
54
+ packageManager,
55
+ tsdownVersion: TSDOWN_VERSION,
56
+ typescriptVersion: TYPESCRIPT_VERSION,
57
+ vitestVersion: VITEST_VERSION,
58
+ zodVersion: ZOD_VERSION
39
59
  }
40
60
  });
41
61
  if (renderError) {
@@ -59,19 +79,6 @@ const initCommand = command({
59
79
  }
60
80
  });
61
81
  /**
62
- * Check whether a string is valid kebab-case.
63
- *
64
- * @param value - The string to validate.
65
- * @returns True when the string is kebab-case.
66
- * @private
67
- */
68
- function isKebabCase(value) {
69
- if (!KEBAB_CASE_CHARS_RE.test(value)) return false;
70
- if (value.endsWith("-")) return false;
71
- if (value.includes("--")) return false;
72
- return true;
73
- }
74
- /**
75
82
  * Resolve the project name from args or prompt.
76
83
  *
77
84
  * @param ctx - Command context.
@@ -141,7 +148,7 @@ async function resolvePackageManager(ctx) {
141
148
  * @private
142
149
  */
143
150
  async function resolveIncludeExample(ctx) {
144
- if (ctx.args.example !== void 0 && ctx.args.example !== null) return ctx.args.example;
151
+ if (ctx.args.example !== void 0) return ctx.args.example;
145
152
  return ctx.prompts.confirm({
146
153
  initialValue: true,
147
154
  message: "Include example command?"
@@ -204,6 +211,5 @@ async function resolveDependencyVersion(packageName) {
204
211
  if (manifestError || !manifest.version) return DEFAULT_VERSION;
205
212
  return manifest.version;
206
213
  }
207
-
208
214
  //#endregion
209
- export { initCommand as default };
215
+ export { initCommand as default };
@@ -0,0 +1,13 @@
1
+ //#region src/lib/config-helpers.ts
2
+ /**
3
+ * Extract a KiddConfig from a load result, falling back to empty defaults.
4
+ *
5
+ * @param result - The result from loadConfig, or null when loading failed.
6
+ * @returns The loaded config or an empty object (all KiddConfig fields are optional).
7
+ */
8
+ function extractConfig(result) {
9
+ if (result) return result.config;
10
+ return {};
11
+ }
12
+ //#endregion
13
+ export { extractConfig as t };
@@ -1,7 +1,7 @@
1
1
  import { join } from "node:path";
2
- import { access, readFile } from "node:fs/promises";
3
2
  import { attemptAsync, ok, toErrorMessage } from "@kidd-cli/utils/fp";
4
-
3
+ import { readFile } from "node:fs/promises";
4
+ import { fileExists } from "@kidd-cli/utils/fs";
5
5
  //#region src/lib/detect.ts
6
6
  /**
7
7
  * Detect whether the given directory contains a kidd-based CLI project.
@@ -57,17 +57,5 @@ async function readPackageJson(filePath) {
57
57
  }, null];
58
58
  }
59
59
  }
60
- /**
61
- * Check whether a path exists on disk.
62
- *
63
- * @param filePath - The path to check.
64
- * @returns True when the path is accessible, false otherwise.
65
- * @private
66
- */
67
- async function fileExists(filePath) {
68
- const [err] = await attemptAsync(() => access(filePath));
69
- return err === null;
70
- }
71
-
72
60
  //#endregion
73
- export { detectProject as t };
61
+ export { detectProject as t };
package/dist/index.mjs CHANGED
@@ -1,7 +1,6 @@
1
1
  import { cli } from "@kidd-cli/core";
2
2
  import { join } from "node:path";
3
3
  import { readManifest } from "@kidd-cli/utils/manifest";
4
-
5
4
  //#region src/manifest.ts
6
5
  /**
7
6
  * Read and validate the CLI package manifest.
@@ -26,7 +25,6 @@ async function loadCLIManifest(baseDir) {
26
25
  version: manifest.version
27
26
  };
28
27
  }
29
-
30
28
  //#endregion
31
29
  //#region src/index.ts
32
30
  const manifest = await loadCLIManifest(import.meta.dirname);
@@ -36,6 +34,5 @@ await cli({
36
34
  name: manifest.name,
37
35
  version: manifest.version
38
36
  });
39
-
40
37
  //#endregion
41
- export { };
38
+ export {};
@@ -5,7 +5,7 @@
5
5
  "keywords": [],
6
6
  "license": "MIT",
7
7
  "bin": {
8
- "{{ name }}": "./dist/index.js"
8
+ "{{ name }}": "./dist/index.mjs"
9
9
  },
10
10
  "files": [
11
11
  "dist"
@@ -19,11 +19,12 @@
19
19
  },
20
20
  "dependencies": {
21
21
  "@kidd-cli/core": "^{{ coreVersion }}",
22
- "zod": "^3.24.0"
22
+ "zod": "{{ zodVersion }}"
23
23
  },
24
24
  "devDependencies": {
25
25
  "@kidd-cli/cli": "^{{ cliVersion }}",
26
- "typescript": "^5.7.0",
27
- "vitest": "^4.0.0"
26
+ "tsdown": "{{ tsdownVersion }}",
27
+ "typescript": "{{ typescriptVersion }}",
28
+ "vitest": "{{ vitestVersion }}"
28
29
  }
29
30
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "compilerOptions": {
3
- "target": "ES2022",
3
+ "target": "ES2024",
4
4
  "module": "ESNext",
5
5
  "moduleResolution": "bundler",
6
6
  "strict": true,
@@ -1,8 +1,8 @@
1
1
  import { dirname, join, relative } from "node:path";
2
- import { access, mkdir, readFile, readdir, writeFile } from "node:fs/promises";
3
- import { attemptAsync, ok, toErrorMessage } from "@kidd-cli/utils/fp";
2
+ import { ok, toErrorMessage } from "@kidd-cli/utils/fp";
3
+ import { mkdir, readFile, readdir, writeFile } from "node:fs/promises";
4
+ import { fileExists } from "@kidd-cli/utils/fs";
4
5
  import { Liquid } from "liquidjs";
5
-
6
6
  //#region src/lib/render.ts
7
7
  /**
8
8
  * Render all `.liquid` templates in a directory using LiquidJS.
@@ -91,7 +91,21 @@ function isGenerateError(value) {
91
91
  if (typeof value !== "object" || value === null) return false;
92
92
  return "type" in value && "message" in value;
93
93
  }
94
-
94
+ //#endregion
95
+ //#region src/lib/validate.ts
96
+ const KEBAB_CASE_CHARS_RE = /^[a-z][\da-z-]*$/;
97
+ /**
98
+ * Check whether a string is valid kebab-case.
99
+ *
100
+ * @param value - The string to validate.
101
+ * @returns True when the string is kebab-case.
102
+ */
103
+ function isKebabCase(value) {
104
+ if (!KEBAB_CASE_CHARS_RE.test(value)) return false;
105
+ if (value.endsWith("-")) return false;
106
+ if (value.includes("--")) return false;
107
+ return true;
108
+ }
95
109
  //#endregion
96
110
  //#region src/lib/write.ts
97
111
  /**
@@ -105,18 +119,13 @@ function isGenerateError(value) {
105
119
  * @returns An async Result with counts of written/skipped files or a GenerateError.
106
120
  */
107
121
  async function writeFiles(params) {
108
- const written = [];
109
- const skipped = [];
110
122
  const results = await Promise.all(params.files.map((file) => writeSingleFile(file, params.outputDir, params.overwrite)));
111
123
  const firstError = results.find((r) => r[0] !== null);
112
124
  if (firstError) return [firstError[0], null];
113
125
  const validStatuses = results.filter((r) => r[1] !== null);
114
- const writtenPaths = validStatuses.filter(([, status]) => status.action === "written").map(([, status]) => status.path);
115
- const skippedPaths = validStatuses.filter(([, status]) => status.action === "skipped").map(([, status]) => status.path);
116
- writtenPaths.map((p) => written.push(p));
117
- skippedPaths.map((p) => skipped.push(p));
126
+ const written = validStatuses.filter(([, status]) => status.action === "written").map(([, status]) => status.path);
118
127
  return ok({
119
- skipped,
128
+ skipped: validStatuses.filter(([, status]) => status.action === "skipped").map(([, status]) => status.path),
120
129
  written
121
130
  });
122
131
  }
@@ -150,17 +159,5 @@ async function writeSingleFile(file, outputDir, overwrite) {
150
159
  }, null];
151
160
  }
152
161
  }
153
- /**
154
- * Check whether a path exists on disk.
155
- *
156
- * @param filePath - The path to check.
157
- * @returns True when the path is accessible, false otherwise.
158
- * @private
159
- */
160
- async function fileExists(filePath) {
161
- const [err] = await attemptAsync(() => access(filePath));
162
- return err === null;
163
- }
164
-
165
162
  //#endregion
166
- export { renderTemplate as n, writeFiles as t };
163
+ export { isKebabCase as n, renderTemplate as r, writeFiles as t };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kidd-cli/cli",
3
- "version": "0.1.2",
3
+ "version": "0.1.4",
4
4
  "description": "DX companion CLI for the kidd framework",
5
5
  "keywords": [
6
6
  "cli",
@@ -22,20 +22,21 @@
22
22
  ],
23
23
  "type": "module",
24
24
  "dependencies": {
25
- "fs-extra": "^11.3.3",
26
- "liquidjs": "^10.24.0",
25
+ "fs-extra": "^11.3.4",
26
+ "liquidjs": "^10.25.0",
27
27
  "picocolors": "^1.1.1",
28
28
  "zod": "^4.3.6",
29
- "@kidd-cli/bundler": "0.1.1",
30
- "@kidd-cli/config": "0.1.1",
31
- "@kidd-cli/core": "0.1.2",
32
- "@kidd-cli/utils": "0.1.1"
29
+ "@kidd-cli/bundler": "0.1.3",
30
+ "@kidd-cli/config": "0.1.3",
31
+ "@kidd-cli/core": "0.3.0",
32
+ "@kidd-cli/utils": "0.1.3"
33
33
  },
34
34
  "devDependencies": {
35
35
  "@types/fs-extra": "^11.0.4",
36
- "tsdown": "0.21.0-beta.2",
36
+ "tsdown": "0.21.1",
37
37
  "typescript": "^5.9.3",
38
- "vitest": "^4.0.18"
38
+ "vitest": "^4.0.18",
39
+ "yaml": "^2.8.0"
39
40
  },
40
41
  "scripts": {
41
42
  "build": "tsdown && mkdir -p dist/lib && cp -r src/lib/templates dist/lib/templates",
@@ -43,6 +44,7 @@
43
44
  "lint": "oxlint --ignore-pattern node_modules",
44
45
  "lint:fix": "oxlint --fix --ignore-pattern node_modules",
45
46
  "test": "vitest run",
47
+ "test:coverage": "vitest run --coverage",
46
48
  "test:watch": "vitest"
47
49
  }
48
50
  }