@ykdz/template 0.0.6 → 0.0.8

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 (118) hide show
  1. package/dist/{src/cli.js → cli.js} +101 -44
  2. package/node_modules/@ykdz/template-builtin-source/dist/src/index.d.ts +22 -0
  3. package/node_modules/@ykdz/template-builtin-source/dist/src/index.js +92 -0
  4. package/node_modules/@ykdz/template-builtin-source/dist/templates/hono-api/projection.d.ts +6 -0
  5. package/node_modules/@ykdz/template-builtin-source/dist/templates/hono-api/projection.js +230 -0
  6. package/node_modules/@ykdz/template-builtin-source/dist/templates/projection-plans.d.ts +7 -0
  7. package/node_modules/@ykdz/template-builtin-source/dist/templates/projection-plans.js +94 -0
  8. package/node_modules/@ykdz/template-builtin-source/dist/templates/registry.d.ts +2 -0
  9. package/node_modules/@ykdz/template-builtin-source/dist/templates/registry.js +15 -0
  10. package/node_modules/@ykdz/template-builtin-source/dist/templates/rust-bin/projection.d.ts +9 -0
  11. package/node_modules/@ykdz/template-builtin-source/dist/templates/rust-bin/projection.js +103 -0
  12. package/node_modules/@ykdz/template-builtin-source/dist/templates/ts-lib/projection.d.ts +6 -0
  13. package/node_modules/@ykdz/template-builtin-source/dist/templates/ts-lib/projection.js +214 -0
  14. package/node_modules/@ykdz/template-builtin-source/dist/templates/vue-app/projection.d.ts +6 -0
  15. package/node_modules/@ykdz/template-builtin-source/dist/templates/vue-app/projection.js +353 -0
  16. package/node_modules/@ykdz/template-builtin-source/dist/templates/vue-hono-app/projection.d.ts +8 -0
  17. package/node_modules/@ykdz/template-builtin-source/dist/templates/vue-hono-app/projection.js +203 -0
  18. package/node_modules/@ykdz/template-builtin-source/package.json +46 -0
  19. package/{templates → node_modules/@ykdz/template-builtin-source/templates}/shared/oxc/node/oxlint.config.ts +3 -0
  20. package/{templates → node_modules/@ykdz/template-builtin-source/templates}/shared/oxc/vue/oxlint.config.ts +3 -0
  21. package/{dist/src → node_modules/@ykdz/template-core/dist}/declarations.d.ts +7 -4
  22. package/{dist/src → node_modules/@ykdz/template-core/dist}/declarations.js +11 -13
  23. package/{dist/src → node_modules/@ykdz/template-core/dist}/dependency-catalog.js +2 -0
  24. package/{dist/src → node_modules/@ykdz/template-core/dist}/editor-customization.js +3 -1
  25. package/{dist/src → node_modules/@ykdz/template-core/dist}/generated-scenarios.d.ts +2 -0
  26. package/{dist/src → node_modules/@ykdz/template-core/dist}/generated-scenarios.js +16 -5
  27. package/node_modules/@ykdz/template-core/dist/package-addition.d.ts +12 -0
  28. package/{dist/src → node_modules/@ykdz/template-core/dist}/package-addition.js +11 -10
  29. package/{pnpm-workspace.yaml → node_modules/@ykdz/template-core/dist/pnpm-workspace.yaml} +3 -1
  30. package/{dist/src → node_modules/@ykdz/template-core/dist}/preset-source.d.ts +1 -3
  31. package/{dist/src → node_modules/@ykdz/template-core/dist}/preset-source.js +13 -29
  32. package/{dist/src → node_modules/@ykdz/template-core/dist}/projection-capabilities.d.ts +10 -2
  33. package/{dist/src → node_modules/@ykdz/template-core/dist}/projection-capabilities.js +22 -49
  34. package/{dist/src → node_modules/@ykdz/template-core/dist}/renderer.js +12 -4
  35. package/{dist/src → node_modules/@ykdz/template-core/dist}/runtime-paths.js +2 -0
  36. package/{dist/src → node_modules/@ykdz/template-core/dist}/toolchain-resolution.js +1 -1
  37. package/node_modules/@ykdz/template-core/package.json +27 -0
  38. package/package.json +14 -34
  39. package/README.md +0 -35
  40. package/dist/src/package-addition.d.ts +0 -8
  41. /package/dist/{src/cli.d.ts → cli.d.ts} +0 -0
  42. /package/{templates → node_modules/@ykdz/template-builtin-source/templates}/hono-api/.github/dependabot.yml +0 -0
  43. /package/{templates → node_modules/@ykdz/template-builtin-source/templates}/hono-api/.github/workflows/check.yml +0 -0
  44. /package/{templates → node_modules/@ykdz/template-builtin-source/templates}/hono-api/src/app.ts +0 -0
  45. /package/{templates → node_modules/@ykdz/template-builtin-source/templates}/hono-api/src/server.ts +0 -0
  46. /package/{templates → node_modules/@ykdz/template-builtin-source/templates}/hono-api/test/app.test.ts +0 -0
  47. /package/{templates → node_modules/@ykdz/template-builtin-source/templates}/hono-api/vitest.config.ts +0 -0
  48. /package/{templates → node_modules/@ykdz/template-builtin-source/templates}/preset-source.json +0 -0
  49. /package/{templates → node_modules/@ykdz/template-builtin-source/templates}/rust-bin/.github/dependabot.yml +0 -0
  50. /package/{templates → node_modules/@ykdz/template-builtin-source/templates}/rust-bin/.github/workflows/check.yml +0 -0
  51. /package/{templates → node_modules/@ykdz/template-builtin-source/templates}/rust-bin/rust-toolchain.toml +0 -0
  52. /package/{templates → node_modules/@ykdz/template-builtin-source/templates}/rust-bin/rustfmt.toml +0 -0
  53. /package/{templates → node_modules/@ykdz/template-builtin-source/templates}/rust-bin/src/main.rs +0 -0
  54. /package/{templates → node_modules/@ykdz/template-builtin-source/templates}/shared/devcontainer/browser-test.Dockerfile +0 -0
  55. /package/{templates → node_modules/@ykdz/template-builtin-source/templates}/shared/devcontainer/node-pnpm.Dockerfile +0 -0
  56. /package/{templates → node_modules/@ykdz/template-builtin-source/templates}/shared/devcontainer/rust.Dockerfile +0 -0
  57. /package/{templates → node_modules/@ykdz/template-builtin-source/templates}/shared/editor-customization/capabilities.json +0 -0
  58. /package/{templates → node_modules/@ykdz/template-builtin-source/templates}/shared/oxc/oxfmt.config.ts +0 -0
  59. /package/{templates → node_modules/@ykdz/template-builtin-source/templates}/ts-lib/.github/dependabot.yml +0 -0
  60. /package/{templates → node_modules/@ykdz/template-builtin-source/templates}/ts-lib/.github/workflows/check.yml +0 -0
  61. /package/{templates → node_modules/@ykdz/template-builtin-source/templates}/ts-lib/src/index.ts +0 -0
  62. /package/{templates → node_modules/@ykdz/template-builtin-source/templates}/ts-lib/src/name-schema.ts +0 -0
  63. /package/{templates → node_modules/@ykdz/template-builtin-source/templates}/vue-app/.github/dependabot.yml +0 -0
  64. /package/{templates → node_modules/@ykdz/template-builtin-source/templates}/vue-app/.github/workflows/check.yml +0 -0
  65. /package/{templates → node_modules/@ykdz/template-builtin-source/templates}/vue-app/env.d.ts +0 -0
  66. /package/{templates → node_modules/@ykdz/template-builtin-source/templates}/vue-app/index.html +0 -0
  67. /package/{templates → node_modules/@ykdz/template-builtin-source/templates}/vue-app/playwright.config.ts +0 -0
  68. /package/{templates → node_modules/@ykdz/template-builtin-source/templates}/vue-app/playwright.package-addition.config.ts +0 -0
  69. /package/{templates → node_modules/@ykdz/template-builtin-source/templates}/vue-app/src/App.vue +0 -0
  70. /package/{templates → node_modules/@ykdz/template-builtin-source/templates}/vue-app/src/main.ts +0 -0
  71. /package/{templates → node_modules/@ykdz/template-builtin-source/templates}/vue-app/src/stores/counter.ts +0 -0
  72. /package/{templates → node_modules/@ykdz/template-builtin-source/templates}/vue-app/src/style.css +0 -0
  73. /package/{templates → node_modules/@ykdz/template-builtin-source/templates}/vue-app/test/app.test.ts +0 -0
  74. /package/{templates → node_modules/@ykdz/template-builtin-source/templates}/vue-app/test/e2e/app.spec.ts +0 -0
  75. /package/{templates → node_modules/@ykdz/template-builtin-source/templates}/vue-app/vite.config.ts +0 -0
  76. /package/{templates → node_modules/@ykdz/template-builtin-source/templates}/vue-app/vitest.config.ts +0 -0
  77. /package/{templates → node_modules/@ykdz/template-builtin-source/templates}/vue-hono-app/.github/dependabot.yml +0 -0
  78. /package/{templates → node_modules/@ykdz/template-builtin-source/templates}/vue-hono-app/.github/workflows/check.yml +0 -0
  79. /package/{templates → node_modules/@ykdz/template-builtin-source/templates}/vue-hono-app/api/src/index.ts +0 -0
  80. /package/{templates → node_modules/@ykdz/template-builtin-source/templates}/vue-hono-app/api/src/runtime.ts +0 -0
  81. /package/{templates → node_modules/@ykdz/template-builtin-source/templates}/vue-hono-app/api/src/server.ts +0 -0
  82. /package/{templates → node_modules/@ykdz/template-builtin-source/templates}/vue-hono-app/api/test/app.test.ts +0 -0
  83. /package/{templates → node_modules/@ykdz/template-builtin-source/templates}/vue-hono-app/api/vitest.config.ts +0 -0
  84. /package/{templates → node_modules/@ykdz/template-builtin-source/templates}/vue-hono-app/web/env.d.ts +0 -0
  85. /package/{templates → node_modules/@ykdz/template-builtin-source/templates}/vue-hono-app/web/index.html +0 -0
  86. /package/{templates → node_modules/@ykdz/template-builtin-source/templates}/vue-hono-app/web/playwright.config.ts +0 -0
  87. /package/{templates → node_modules/@ykdz/template-builtin-source/templates}/vue-hono-app/web/src/App.vue +0 -0
  88. /package/{templates → node_modules/@ykdz/template-builtin-source/templates}/vue-hono-app/web/src/api.ts +0 -0
  89. /package/{templates → node_modules/@ykdz/template-builtin-source/templates}/vue-hono-app/web/src/main.ts +0 -0
  90. /package/{templates → node_modules/@ykdz/template-builtin-source/templates}/vue-hono-app/web/src/stores/counter.ts +0 -0
  91. /package/{templates → node_modules/@ykdz/template-builtin-source/templates}/vue-hono-app/web/src/style.css +0 -0
  92. /package/{templates → node_modules/@ykdz/template-builtin-source/templates}/vue-hono-app/web/test/app.test.ts +0 -0
  93. /package/{templates → node_modules/@ykdz/template-builtin-source/templates}/vue-hono-app/web/test/e2e/app.spec.ts +0 -0
  94. /package/{templates → node_modules/@ykdz/template-builtin-source/templates}/vue-hono-app/web/vite.config.ts +0 -0
  95. /package/{templates → node_modules/@ykdz/template-builtin-source/templates}/vue-hono-app/web/vitest.config.ts +0 -0
  96. /package/{dist/src → node_modules/@ykdz/template-core/dist}/dependency-catalog.d.ts +0 -0
  97. /package/{dist/src → node_modules/@ykdz/template-core/dist}/devcontainer.d.ts +0 -0
  98. /package/{dist/src → node_modules/@ykdz/template-core/dist}/devcontainer.js +0 -0
  99. /package/{dist/src → node_modules/@ykdz/template-core/dist}/editor-customization.d.ts +0 -0
  100. /package/{dist/src → node_modules/@ykdz/template-core/dist}/generation-context.d.ts +0 -0
  101. /package/{dist/src → node_modules/@ykdz/template-core/dist}/generation-context.js +0 -0
  102. /package/{dist/src → node_modules/@ykdz/template-core/dist}/module-graph.d.ts +0 -0
  103. /package/{dist/src → node_modules/@ykdz/template-core/dist}/module-graph.js +0 -0
  104. /package/{dist/src → node_modules/@ykdz/template-core/dist}/next-step-instructions.d.ts +0 -0
  105. /package/{dist/src → node_modules/@ykdz/template-core/dist}/next-step-instructions.js +0 -0
  106. /package/{dist/src → node_modules/@ykdz/template-core/dist}/package-addition-support.d.ts +0 -0
  107. /package/{dist/src → node_modules/@ykdz/template-core/dist}/package-addition-support.js +0 -0
  108. /package/{dist/src → node_modules/@ykdz/template-core/dist}/package-linking.d.ts +0 -0
  109. /package/{dist/src → node_modules/@ykdz/template-core/dist}/package-linking.js +0 -0
  110. /package/{dist/src → node_modules/@ykdz/template-core/dist}/preset-projection.d.ts +0 -0
  111. /package/{dist/src → node_modules/@ykdz/template-core/dist}/preset-projection.js +0 -0
  112. /package/{dist/src → node_modules/@ykdz/template-core/dist}/project-github.d.ts +0 -0
  113. /package/{dist/src → node_modules/@ykdz/template-core/dist}/project-github.js +0 -0
  114. /package/{dist/src → node_modules/@ykdz/template-core/dist}/renderer.d.ts +0 -0
  115. /package/{dist/src → node_modules/@ykdz/template-core/dist}/runtime-paths.d.ts +0 -0
  116. /package/{dist/src → node_modules/@ykdz/template-core/dist}/template-boundary-check.d.ts +0 -0
  117. /package/{dist/src → node_modules/@ykdz/template-core/dist}/template-boundary-check.js +0 -0
  118. /package/{dist/src → node_modules/@ykdz/template-core/dist}/toolchain-resolution.d.ts +0 -0
@@ -2,17 +2,23 @@
2
2
  import { readFile } from "node:fs/promises";
3
3
  import path from "node:path";
4
4
  import { createInterface } from "node:readline/promises";
5
- import { blueprintJsonSchema, builtInPresets, presetFileJsonSchema, validatePresetFile, validateProjectBlueprint, } from "./declarations.js";
6
- import { assembleGenerationContext, } from "./generation-context.js";
7
- import { addPackage } from "./package-addition.js";
8
- import { planNextStepInstructionsForProjection, } from "./preset-projection.js";
9
- import { findBuiltInPresetSourceManifestPreset, presetSourceManifestJsonSchema, validateBuiltInPresetSourceManifest, validatePresetSourceManifest, } from "./preset-source.js";
10
- import { blueprintForPresetSourcePreset, projectPresetSourcePreset, } from "./projection-capabilities.js";
11
- import { renderNewProject } from "./renderer.js";
12
- import { resolveToolchainVersions, } from "./toolchain-resolution.js";
5
+ import { builtInPresetProjectionSourceRoots, builtInPresets, findBuiltInPresetSourceManifestPreset, loadBuiltInPresetSourceManifest, projectBuiltInPresetSourcePreset, } from "@ykdz/template-builtin-source";
6
+ import { blueprintJsonSchema, presetFileJsonSchema, validatePresetFile, validateProjectBlueprint, } from "@ykdz/template-core/declarations";
7
+ import { assembleGenerationContext, } from "@ykdz/template-core/generation-context";
8
+ import { addPackage } from "@ykdz/template-core/package-addition";
9
+ import { planNextStepInstructionsForProjection, } from "@ykdz/template-core/preset-projection";
10
+ import { presetSourceManifestJsonSchema, validateBuiltInPresetSourceManifest, validatePresetSourceManifest, } from "@ykdz/template-core/preset-source";
11
+ import { blueprintForPresetSourcePreset } from "@ykdz/template-core/projection-capabilities";
12
+ import { renderNewProject } from "@ykdz/template-core/renderer";
13
+ import { resolveToolchainVersions, } from "@ykdz/template-core/toolchain-resolution";
13
14
  function usage() {
14
15
  return [
16
+ "Project Kit template CLI",
17
+ "",
15
18
  "Usage:",
19
+ " template <command> [options]",
20
+ "",
21
+ "Commands:",
16
22
  " template init <dir> --preset <name> --yes",
17
23
  " template add package --preset <name> --name <name> [--path <package-path>] [--link-from <package-path>]...",
18
24
  " template presets",
@@ -24,14 +30,14 @@ function usage() {
24
30
  " template blueprint validate <path>",
25
31
  "",
26
32
  "Options:",
27
- " --preset <name> Project preset to generate",
28
- " --name <name> Package name to add",
29
- " --path <path> Two-segment Package Path to add",
33
+ " --preset <name> Project preset to generate",
34
+ " --name <name> Package name to add",
35
+ " --path <path> Two-segment Package Path to add",
30
36
  " --link-from <path> Existing consumer Package Path to link from; repeatable",
31
- " --scope <name> Package scope for workspace package names",
32
- " --yes Accept defaults for non-interactive generation",
33
- " --dry-run Print the planned generation without writing files",
34
- " --json Print machine-readable output",
37
+ " --scope <name> Package scope for workspace package names",
38
+ " --yes Accept defaults for non-interactive generation",
39
+ " --dry-run Print the planned generation without writing files",
40
+ " --json Print machine-readable output",
35
41
  ].join("\n");
36
42
  }
37
43
  function printJson(value) {
@@ -46,7 +52,9 @@ async function readJsonDeclaration(filePath) {
46
52
  }
47
53
  catch (error) {
48
54
  if (error instanceof SyntaxError) {
49
- throw new Error(`Invalid JSON in ${filePath}: ${error.message}`);
55
+ throw new Error(`Invalid JSON in ${filePath}: ${error.message}`, {
56
+ cause: error,
57
+ });
50
58
  }
51
59
  throw error;
52
60
  }
@@ -56,10 +64,18 @@ function formatValidationIssues(issues) {
56
64
  .map((issue) => ` - ${issue.path}: ${issue.message}`)
57
65
  .join("\n");
58
66
  }
67
+ function formatFieldRows(rows) {
68
+ const width = Math.max(...rows.map(([label]) => `${label}:`.length));
69
+ return rows.map(([label, value]) => ` ${`${label}:`.padEnd(width)} ${value}`);
70
+ }
59
71
  function formatPresetCatalog() {
60
72
  return [
61
73
  "Built-in presets",
62
- ...builtInPresets.map((preset) => ` ${preset.name.padEnd(8)} ${preset.title} (${preset.generation}) - ${preset.description}`),
74
+ "",
75
+ ...formatFieldRows(builtInPresets.map((preset) => [
76
+ preset.name,
77
+ `${preset.title} (${preset.generation}) - ${preset.description}`,
78
+ ])),
63
79
  ].join("\n");
64
80
  }
65
81
  function parseInitOptions(args) {
@@ -145,23 +161,29 @@ function blueprintForInit(options) {
145
161
  });
146
162
  }
147
163
  function formatBlueprintSummary(targetDir, blueprint) {
148
- const lines = [
149
- "Project Blueprint",
150
- ` Target: ${targetDir}`,
151
- ` Preset: ${blueprint.preset}`,
152
- ` Project kind: ${blueprint.projectKind}`,
164
+ const rows = [
165
+ ["Target", targetDir],
166
+ ["Preset", blueprint.preset],
167
+ ["Project kind", blueprint.projectKind],
153
168
  ];
154
169
  if (blueprint.packageManager) {
155
- lines.push(` Package manager: ${blueprint.packageManager}`);
156
- }
157
- if (blueprint.packages) {
158
- lines.push(" Packages:");
159
- for (const pkg of blueprint.packages) {
160
- lines.push(` - ${pkg.name} (${pkg.path})`);
161
- }
170
+ rows.push(["Package manager", blueprint.packageManager]);
162
171
  }
163
- lines.push(` Features: ${blueprint.features.join(", ")}`);
164
- return lines.join("\n");
172
+ return [
173
+ "Project Blueprint",
174
+ "",
175
+ ...formatFieldRows(rows),
176
+ ...(blueprint.packages
177
+ ? [
178
+ "",
179
+ " Packages:",
180
+ ...blueprint.packages.map((pkg) => ` - ${pkg.name} (${pkg.path})`),
181
+ ]
182
+ : []),
183
+ "",
184
+ " Features:",
185
+ ...blueprint.features.map((feature) => ` - ${feature}`),
186
+ ].join("\n");
165
187
  }
166
188
  function formatProjectionNextSteps(targetDir, projectionPlan) {
167
189
  const steps = planNextStepInstructionsForProjection({
@@ -170,7 +192,11 @@ function formatProjectionNextSteps(targetDir, projectionPlan) {
170
192
  });
171
193
  return [
172
194
  "Next Step Instructions:",
173
- ...steps.map((step) => ` ${step.label}: ${step.display}`),
195
+ "",
196
+ ...steps.flatMap((step, index) => [
197
+ ` ${index + 1}. ${step.label}`,
198
+ ` ${step.display}`,
199
+ ]),
174
200
  ].join("\n");
175
201
  }
176
202
  function toolchainReport(toolchain) {
@@ -184,9 +210,12 @@ function toolchainReport(toolchain) {
184
210
  function formatToolchainReport(toolchain) {
185
211
  return [
186
212
  "Toolchain Resolution:",
187
- ` Source: ${toolchain.source}`,
188
- ` Node LTS major: ${toolchain.nodeLtsMajor.value}`,
189
- ` Package Manager Pin: ${toolchain.packageManagerPin.value}`,
213
+ "",
214
+ ...formatFieldRows([
215
+ ["Source", toolchain.source],
216
+ ["Node LTS major", toolchain.nodeLtsMajor.value],
217
+ ["Package Manager Pin", toolchain.packageManagerPin.value],
218
+ ]),
190
219
  ...toolchain.diagnostics.map((diagnostic) => ` ${diagnostic}`),
191
220
  ].join("\n");
192
221
  }
@@ -220,7 +249,7 @@ async function generateInitProject(options, generationContext) {
220
249
  if (!generationContext) {
221
250
  throw new Error(`Missing Generation Context for Preset Projection: ${options.preset}`);
222
251
  }
223
- const plan = projectPresetSourcePreset({
252
+ const plan = projectBuiltInPresetSourcePreset({
224
253
  preset,
225
254
  context: generationContext,
226
255
  });
@@ -234,7 +263,7 @@ async function generateInitProject(options, generationContext) {
234
263
  function printInitComplete(options, blueprint, generationContext) {
235
264
  const preset = findBuiltInPresetSourceManifestPreset(blueprint.preset);
236
265
  const projectionPlan = generationContext && preset?.projection
237
- ? projectPresetSourcePreset({ preset, context: generationContext })
266
+ ? projectBuiltInPresetSourcePreset({ preset, context: generationContext })
238
267
  : undefined;
239
268
  if (!projectionPlan) {
240
269
  throw new Error(`Missing Preset Projection plan: ${blueprint.preset}`);
@@ -256,10 +285,19 @@ function printInitComplete(options, blueprint, generationContext) {
256
285
  });
257
286
  return;
258
287
  }
259
- console.log(`Initialized ${options.preset} project in ${options.dir}`);
288
+ console.log([
289
+ "Initialized project",
290
+ "",
291
+ ...formatFieldRows([
292
+ ["Preset", options.preset],
293
+ ["Target", options.dir],
294
+ ]),
295
+ ].join("\n"));
260
296
  if (generationContext) {
297
+ console.log("");
261
298
  console.log(formatToolchainReport(generationContext.toolchain));
262
299
  }
300
+ console.log("");
263
301
  console.log(formatProjectionNextSteps(options.dir, projectionPlan));
264
302
  }
265
303
  function isInteractiveTerminal() {
@@ -360,7 +398,9 @@ async function main(args) {
360
398
  if (!filePath) {
361
399
  throw new Error("preset validate requires a path");
362
400
  }
363
- const result = validatePresetFile(await readJsonDeclaration(filePath));
401
+ const result = validatePresetFile(await readJsonDeclaration(filePath), {
402
+ presets: builtInPresets,
403
+ });
364
404
  if (!result.ok) {
365
405
  throw new Error(`Preset file is invalid:\n${formatValidationIssues(result.issues)}`);
366
406
  }
@@ -398,7 +438,9 @@ async function main(args) {
398
438
  if (!filePath) {
399
439
  throw new Error("blueprint validate requires a path");
400
440
  }
401
- const result = validateProjectBlueprint(await readJsonDeclaration(filePath));
441
+ const result = validateProjectBlueprint(await readJsonDeclaration(filePath), {
442
+ presets: builtInPresets,
443
+ });
402
444
  if (!result.ok) {
403
445
  throw new Error(`Blueprint is invalid:\n${formatValidationIssues(result.issues)}`);
404
446
  }
@@ -413,7 +455,10 @@ async function main(args) {
413
455
  const preset = findBuiltInPresetSourceManifestPreset(options.preset);
414
456
  const projectionPlan = generationContext
415
457
  ? preset?.projection
416
- ? projectPresetSourcePreset({ preset, context: generationContext })
458
+ ? projectBuiltInPresetSourcePreset({
459
+ preset,
460
+ context: generationContext,
461
+ })
417
462
  : undefined
418
463
  : undefined;
419
464
  if (!projectionPlan) {
@@ -438,8 +483,10 @@ async function main(args) {
438
483
  }
439
484
  console.log(formatBlueprintSummary(options.dir, blueprint));
440
485
  if (generationContext) {
486
+ console.log("");
441
487
  console.log(formatToolchainReport(generationContext.toolchain));
442
488
  }
489
+ console.log("");
443
490
  console.log(formatProjectionNextSteps(options.dir, projectionPlan));
444
491
  return;
445
492
  }
@@ -462,8 +509,18 @@ async function main(args) {
462
509
  name: options.name,
463
510
  path: options.path,
464
511
  linkFrom: options.linkFrom,
512
+ presetSourceManifest: loadBuiltInPresetSourceManifest(),
513
+ projectionSourceRoots: builtInPresetProjectionSourceRoots(),
465
514
  });
466
- console.log(`Added ${options.preset} package ${options.name}`);
515
+ console.log([
516
+ "Added package",
517
+ "",
518
+ ...formatFieldRows([
519
+ ["Preset", options.preset],
520
+ ["Name", options.name],
521
+ ...(options.path ? [["Path", options.path]] : []),
522
+ ]),
523
+ ].join("\n"));
467
524
  return;
468
525
  }
469
526
  if (command === "--help" || command === "-h") {
@@ -474,8 +531,8 @@ async function main(args) {
474
531
  }
475
532
  main(process.argv.slice(2)).catch((error) => {
476
533
  const message = error instanceof Error ? error.message : String(error);
477
- console.error(message);
534
+ console.error(`Error: ${message}`);
478
535
  console.error("");
479
- console.error(usage());
536
+ console.error("Run `template --help` for usage.");
480
537
  process.exitCode = 1;
481
538
  });
@@ -0,0 +1,22 @@
1
+ import type { BuiltInPreset } from "@ykdz/template-core/declarations";
2
+ import type { GenerationContext } from "@ykdz/template-core/generation-context";
3
+ import type { PresetPackageAdditionOptions } from "@ykdz/template-core/preset-projection";
4
+ import { type PresetSourceManifest, type PresetSourceManifestPreset } from "@ykdz/template-core/preset-source";
5
+ import { type PresetProjectionSourceRoots, type PresetProjectionDeclaration } from "@ykdz/template-core/projection-capabilities";
6
+ export { findPresetSourceManifestPreset, loadPresetSourceManifestFile, manifestReferencedSourceFiles, presetSourceManifestJsonSchema, validateBuiltInPresetSourceManifest, validatePresetSourceManifest, type PresetSourceManifest, type PresetSourceManifestPreset, } from "@ykdz/template-core/preset-source";
7
+ export declare function builtInPresetSourceRoot(...segments: string[]): string;
8
+ export declare function builtInPresetProjectionSourceRoots(): PresetProjectionSourceRoots;
9
+ export declare function loadBuiltInPresetSourceManifest(): PresetSourceManifest;
10
+ export declare const builtInPresets: readonly BuiltInPreset[];
11
+ export declare function findBuiltInPreset(name: string): BuiltInPreset | undefined;
12
+ export declare function findBuiltInPresetSourceManifestPreset(presetName: string): PresetSourceManifestPreset | undefined;
13
+ export declare function loadBuiltInPresetProjectionDeclaration(presetName: string): PresetProjectionDeclaration;
14
+ export declare function projectBuiltInPresetSourcePreset(options: {
15
+ readonly preset: PresetSourceManifestPreset;
16
+ readonly context: GenerationContext;
17
+ }): import("@ykdz/template-core/preset-projection").PresetProjectionPlan;
18
+ export declare function defaultPackagePathForBuiltInPackageAddition(preset: PresetSourceManifestPreset, packageLeafName: string): string;
19
+ export declare function planBuiltInPackageAddition(options: {
20
+ readonly preset: PresetSourceManifestPreset;
21
+ readonly addition: PresetPackageAdditionOptions;
22
+ }): Promise<import("@ykdz/template-core/preset-projection").PresetPackageAdditionPlan>;
@@ -0,0 +1,92 @@
1
+ import { readFileSync } from "node:fs";
2
+ import path from "node:path";
3
+ import { fileURLToPath } from "node:url";
4
+ import { findPresetSourceManifestPreset, validateBuiltInPresetSourceManifest, } from "@ykdz/template-core/preset-source";
5
+ import { defaultPackagePathForPresetSourcePackageAddition, planPresetSourcePackageAddition, projectPresetSourcePreset, validateProjectionCapabilities, } from "@ykdz/template-core/projection-capabilities";
6
+ export { findPresetSourceManifestPreset, loadPresetSourceManifestFile, manifestReferencedSourceFiles, presetSourceManifestJsonSchema, validateBuiltInPresetSourceManifest, validatePresetSourceManifest, } from "@ykdz/template-core/preset-source";
7
+ export function builtInPresetSourceRoot(...segments) {
8
+ const moduleDir = path.dirname(fileURLToPath(import.meta.url));
9
+ const candidates = [
10
+ path.join(moduleDir, "..", "..", "templates", ...segments),
11
+ path.join(moduleDir, "..", "templates", ...segments),
12
+ path.join(moduleDir, "..", "..", "..", "template-builtin-source", "templates", ...segments),
13
+ ];
14
+ return (candidates.find((candidate) => readPathExists(candidate)) ?? candidates[0]);
15
+ }
16
+ function readPathExists(filePath) {
17
+ try {
18
+ readFileSync(filePath);
19
+ return true;
20
+ }
21
+ catch (error) {
22
+ if (error instanceof Error &&
23
+ "code" in error &&
24
+ error.code === "EISDIR") {
25
+ return true;
26
+ }
27
+ if (error instanceof Error &&
28
+ "code" in error &&
29
+ error.code === "ENOENT") {
30
+ return false;
31
+ }
32
+ return false;
33
+ }
34
+ }
35
+ export function builtInPresetProjectionSourceRoots() {
36
+ return {
37
+ preset(sourcePreset) {
38
+ return builtInPresetSourceRoot(sourcePreset);
39
+ },
40
+ sharedOxc() {
41
+ return builtInPresetSourceRoot("shared", "oxc");
42
+ },
43
+ sharedDevcontainer() {
44
+ return builtInPresetSourceRoot("shared", "devcontainer");
45
+ },
46
+ };
47
+ }
48
+ export function loadBuiltInPresetSourceManifest() {
49
+ const filePath = builtInPresetSourceRoot("preset-source.json");
50
+ const result = validateBuiltInPresetSourceManifest(JSON.parse(readFileSync(filePath, "utf8")), { sourceRoot: path.dirname(filePath) });
51
+ if (!result.ok) {
52
+ throw new Error(`Built-in Preset Source Manifest is invalid:\n${result.issues
53
+ .map((issue) => ` - ${issue.path}: ${issue.message}`)
54
+ .join("\n")}`);
55
+ }
56
+ return result.value;
57
+ }
58
+ export const builtInPresets = loadBuiltInPresetSourceManifest().presets;
59
+ export function findBuiltInPreset(name) {
60
+ return builtInPresets.find((preset) => preset.name === name);
61
+ }
62
+ export function findBuiltInPresetSourceManifestPreset(presetName) {
63
+ return findPresetSourceManifestPreset(loadBuiltInPresetSourceManifest(), presetName);
64
+ }
65
+ export function loadBuiltInPresetProjectionDeclaration(presetName) {
66
+ const preset = findBuiltInPresetSourceManifestPreset(presetName);
67
+ if (!preset?.projection) {
68
+ throw new Error(`Built-in Preset ${presetName} must declare a Projection Declaration`);
69
+ }
70
+ const result = validateProjectionCapabilities(preset.projection);
71
+ if (!result.ok) {
72
+ throw new Error(`Built-in Preset ${presetName} Projection Declaration is invalid:\n${result.issues
73
+ .map((issue) => ` - ${issue.path}: ${issue.message}`)
74
+ .join("\n")}`);
75
+ }
76
+ return result.value;
77
+ }
78
+ export function projectBuiltInPresetSourcePreset(options) {
79
+ return projectPresetSourcePreset({
80
+ ...options,
81
+ sourceRoots: builtInPresetProjectionSourceRoots(),
82
+ });
83
+ }
84
+ export function defaultPackagePathForBuiltInPackageAddition(preset, packageLeafName) {
85
+ return defaultPackagePathForPresetSourcePackageAddition(preset, packageLeafName, builtInPresetProjectionSourceRoots());
86
+ }
87
+ export function planBuiltInPackageAddition(options) {
88
+ return planPresetSourcePackageAddition({
89
+ ...options,
90
+ sourceRoots: builtInPresetProjectionSourceRoots(),
91
+ });
92
+ }
@@ -0,0 +1,6 @@
1
+ import type { BuiltInPreset, ProjectBlueprint } from "@ykdz/template-core/declarations";
2
+ import type { PresetBlueprintOptions, PresetProjection } from "@ykdz/template-core/preset-projection";
3
+ export declare const honoApiPresetMetadata: BuiltInPreset;
4
+ export declare function honoApiBlueprint(options?: PresetBlueprintOptions): ProjectBlueprint;
5
+ export declare function projectHonoApiPackageScripts(): Record<string, string>;
6
+ export declare const honoApiPresetProjection: PresetProjection;
@@ -0,0 +1,230 @@
1
+ import { existsSync } from "node:fs";
2
+ import path from "node:path";
3
+ import { fileURLToPath } from "node:url";
4
+ import { builtInPresetProjectionSourceRoots, loadBuiltInPresetProjectionDeclaration, } from "@ykdz/template-builtin-source";
5
+ import { renderFixCommand, renderRootCheckCommand, } from "@ykdz/template-core/module-graph";
6
+ import { PackageAdditionSupport } from "@ykdz/template-core/package-addition-support";
7
+ import { packageManifestExposureFields, planPackageLinks, } from "@ykdz/template-core/package-linking";
8
+ import { interpretPresetProjectionDeclaration } from "@ykdz/template-core/projection-capabilities";
9
+ import { renderNewProject, } from "@ykdz/template-core/renderer";
10
+ export const honoApiPresetMetadata = {
11
+ name: "hono-api",
12
+ title: "Hono API",
13
+ description: "Hono Node API workspace with strict TypeScript tooling.",
14
+ generation: "supported",
15
+ supportedPackageManagers: ["pnpm"],
16
+ supportedProjectKinds: ["multi-package"],
17
+ packageAdditionSupport: PackageAdditionSupport.Supported,
18
+ features: [
19
+ "pnpm-catalog",
20
+ "oxc-format-lint",
21
+ "strict-typescript",
22
+ "root-check",
23
+ "fix-command",
24
+ "devcontainer",
25
+ "github-actions",
26
+ "dependabot",
27
+ ],
28
+ };
29
+ const apiPackageBoundary = {
30
+ kind: "package-boundary",
31
+ path: ".",
32
+ };
33
+ function planHonoApiPackageChecks() {
34
+ return {
35
+ components: [
36
+ { kind: "oxc-format-check", owner: apiPackageBoundary },
37
+ { kind: "oxc-lint", owner: apiPackageBoundary },
38
+ { kind: "typescript-typecheck", owner: apiPackageBoundary },
39
+ { kind: "build", owner: apiPackageBoundary },
40
+ { kind: "unit-test", owner: apiPackageBoundary },
41
+ ],
42
+ environmentNeeds: [],
43
+ };
44
+ }
45
+ function planHonoApiPackageFixes() {
46
+ return {
47
+ components: [
48
+ { kind: "oxc-format-write", owner: apiPackageBoundary },
49
+ { kind: "oxc-lint-fix", owner: apiPackageBoundary },
50
+ ],
51
+ };
52
+ }
53
+ function projectNameFromDir(targetDir) {
54
+ return path.basename(path.resolve(targetDir));
55
+ }
56
+ function packageScopeFromOptions(options) {
57
+ return options.scope ?? projectNameFromDir(options.targetDir);
58
+ }
59
+ function scopedPackageName(packageScope) {
60
+ return `@${packageScope}/api`;
61
+ }
62
+ export function honoApiBlueprint(options = { targetDir: process.cwd() }) {
63
+ const packageScope = packageScopeFromOptions(options);
64
+ return {
65
+ schemaVersion: 1,
66
+ preset: "hono-api",
67
+ packageManager: "pnpm",
68
+ projectKind: "multi-package",
69
+ features: [...honoApiPresetMetadata.features],
70
+ packages: [{ name: scopedPackageName(packageScope), path: "apps/api" }],
71
+ };
72
+ }
73
+ export function projectHonoApiPackageScripts() {
74
+ return {
75
+ build: "tsc -p tsconfig.build.json && tsc-alias -p tsconfig.build.json",
76
+ check: renderRootCheckCommand(planHonoApiPackageChecks()),
77
+ fix: renderFixCommand(planHonoApiPackageFixes()),
78
+ "format:check": "oxfmt --check --config ../../oxfmt.config.ts .",
79
+ "format:write": "oxfmt --write --config ../../oxfmt.config.ts .",
80
+ lint: "oxlint --config ../../oxlint.config.ts . --deny-warnings",
81
+ "lint:fix": "oxlint --config ../../oxlint.config.ts . --fix --deny-warnings",
82
+ start: "node dist/server.js",
83
+ test: "vitest run",
84
+ typecheck: "tsc -p tsconfig.json --noEmit",
85
+ };
86
+ }
87
+ function packageAdditionOperations(packagePath, packageNameValue, nodeVersion) {
88
+ const packageExposure = planPackageLinks([
89
+ {
90
+ name: packageNameValue,
91
+ path: packagePath,
92
+ role: "runtime-service",
93
+ sourcePreset: "hono-api",
94
+ },
95
+ ]).exposuresByPackagePath.get(packagePath);
96
+ if (packageExposure === undefined) {
97
+ throw new Error(`Missing Package Exposure for ${packagePath}`);
98
+ }
99
+ const exposureFields = packageManifestExposureFields(packageExposure);
100
+ return [
101
+ {
102
+ kind: "writeJson",
103
+ to: `${packagePath}/package.json`,
104
+ value: {
105
+ name: packageNameValue,
106
+ version: "0.0.0",
107
+ private: true,
108
+ type: "module",
109
+ types: exposureFields.types,
110
+ exports: exposureFields.exports,
111
+ imports: exposureFields.imports,
112
+ scripts: projectHonoApiPackageScripts(),
113
+ dependencies: {
114
+ "@hono/node-server": "catalog:",
115
+ hono: "catalog:",
116
+ },
117
+ devDependencies: {
118
+ "@types/node": "catalog:",
119
+ oxfmt: "catalog:",
120
+ oxlint: "catalog:",
121
+ "tsc-alias": "catalog:",
122
+ typescript: "catalog:",
123
+ vitest: "catalog:",
124
+ },
125
+ engines: {
126
+ node: nodeVersion,
127
+ },
128
+ },
129
+ },
130
+ {
131
+ kind: "writeJson",
132
+ to: `${packagePath}/tsconfig.json`,
133
+ value: {
134
+ compilerOptions: {
135
+ composite: true,
136
+ module: "NodeNext",
137
+ moduleResolution: "NodeNext",
138
+ noEmitOnError: true,
139
+ skipLibCheck: false,
140
+ strict: true,
141
+ target: "ES2022",
142
+ types: ["node", "vitest/globals"],
143
+ },
144
+ include: ["src/**/*.ts", "test/**/*.ts", "vitest.config.ts"],
145
+ },
146
+ },
147
+ {
148
+ kind: "writeJson",
149
+ to: `${packagePath}/tsconfig.build.json`,
150
+ value: {
151
+ extends: "./tsconfig.json",
152
+ compilerOptions: {
153
+ outDir: "dist",
154
+ rootDir: "src",
155
+ types: ["node"],
156
+ },
157
+ include: ["src/**/*.ts"],
158
+ },
159
+ },
160
+ { kind: "copyFile", from: "src/app.ts", to: `${packagePath}/src/app.ts` },
161
+ {
162
+ kind: "copyFile",
163
+ from: "src/server.ts",
164
+ to: `${packagePath}/src/server.ts`,
165
+ },
166
+ {
167
+ kind: "copyFile",
168
+ from: "test/app.test.ts",
169
+ to: `${packagePath}/test/app.test.ts`,
170
+ },
171
+ {
172
+ kind: "copyFile",
173
+ from: "vitest.config.ts",
174
+ to: `${packagePath}/vitest.config.ts`,
175
+ },
176
+ ];
177
+ }
178
+ function packageAdditionPlan(packageNameValue, packagePath, nodeVersion) {
179
+ const [workspaceCollection] = packagePath.split("/");
180
+ return {
181
+ packagePath,
182
+ workspacePackageGlob: `${workspaceCollection}/*`,
183
+ packageRole: "runtime-service",
184
+ packageSourcePreset: "hono-api",
185
+ sourceRoot: templateSourceRoot(),
186
+ sourceRoots: { sharedOxc: sharedOxcSourceRoot() },
187
+ operations: packageAdditionOperations(packagePath, packageNameValue, nodeVersion),
188
+ };
189
+ }
190
+ function templateSourceRoot() {
191
+ const projectionDir = path.dirname(fileURLToPath(import.meta.url));
192
+ const publishedTemplateRoot = path.join(projectionDir, "..", "..", "..", "templates", "hono-api");
193
+ return existsSync(path.join(publishedTemplateRoot, "src", "app.ts"))
194
+ ? publishedTemplateRoot
195
+ : projectionDir;
196
+ }
197
+ function sharedOxcSourceRoot() {
198
+ const projectionDir = path.dirname(fileURLToPath(import.meta.url));
199
+ const publishedSharedRoot = path.join(projectionDir, "..", "..", "..", "templates", "shared", "oxc");
200
+ return existsSync(path.join(publishedSharedRoot, "oxfmt.config.ts"))
201
+ ? publishedSharedRoot
202
+ : path.join(projectionDir, "..", "shared", "oxc");
203
+ }
204
+ export const honoApiPresetProjection = {
205
+ metadata: honoApiPresetMetadata,
206
+ capabilities: {
207
+ packageAddition: {
208
+ planPackageAddition({ packageName, packagePath, nodeVersion, }) {
209
+ return packageAdditionPlan(packageName, packagePath, nodeVersion);
210
+ },
211
+ },
212
+ },
213
+ blueprint: honoApiBlueprint,
214
+ project(context) {
215
+ return interpretPresetProjectionDeclaration({
216
+ preset: honoApiPresetMetadata,
217
+ declaration: loadBuiltInPresetProjectionDeclaration("hono-api"),
218
+ context,
219
+ sourceRoots: builtInPresetProjectionSourceRoots(),
220
+ });
221
+ },
222
+ async render({ targetDir, plan }) {
223
+ await renderNewProject({
224
+ sourceRoot: plan.sourceRoot,
225
+ sourceRoots: plan.sourceRoots,
226
+ targetRoot: targetDir,
227
+ operations: [...plan.operations],
228
+ });
229
+ },
230
+ };
@@ -0,0 +1,7 @@
1
+ import type { CheckComponent, CheckPlan, FixComponent, FixPlan } from "@ykdz/template-core/module-graph";
2
+ export type NodeCheckPlanTarget = "hono-api" | "vue-app" | "vue-hono-root" | "vue-hono-api" | "vue-hono-web";
3
+ export type NodeFixPlanTarget = "hono-api" | "vue-app" | "vue-hono-root" | "vue-hono-api" | "vue-hono-web";
4
+ export declare function selectNodeCheckComponents(target: NodeCheckPlanTarget): CheckComponent[];
5
+ export declare function selectNodeFixComponents(target: NodeFixPlanTarget): FixComponent[];
6
+ export declare function planNodeChecks(target: NodeCheckPlanTarget): CheckPlan;
7
+ export declare function planNodeFixes(target: NodeFixPlanTarget): FixPlan;