@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
@@ -1,6 +1,4 @@
1
1
  import * as v from "valibot";
2
- import { loadBuiltInPresetSourceManifest } from "./preset-source.js";
3
- export const builtInPresets = loadBuiltInPresetSourceManifest().presets;
4
2
  const featureNames = [
5
3
  "pnpm-catalog",
6
4
  "oxc-format-lint",
@@ -180,7 +178,7 @@ function unsupportedSinglePackageProjectShapeIssue(path) {
180
178
  message: "single-package Project Shape is unsupported in V1; use the workspace monorepo Project Shape",
181
179
  };
182
180
  }
183
- export function validatePresetFile(input) {
181
+ export function validatePresetFile(input, options = {}) {
184
182
  const result = v.safeParse(presetFileSchema, input);
185
183
  if (!result.success) {
186
184
  return { ok: false, issues: shapeIssues(result.issues) };
@@ -193,9 +191,9 @@ export function validatePresetFile(input) {
193
191
  if (result.output.supportedProjectKinds.includes("single-package")) {
194
192
  semanticIssues.push(unsupportedSinglePackageProjectShapeIssue("$.supportedProjectKinds"));
195
193
  }
196
- const builtInPreset = findBuiltInPreset(result.output.name);
197
- const unsupportedGeneration = builtInPreset
198
- ? generationSupportIssue(builtInPreset, "$.name")
194
+ const catalogPreset = findPreset(options.presets ?? [], result.output.name);
195
+ const unsupportedGeneration = catalogPreset
196
+ ? generationSupportIssue(catalogPreset, "$.name")
199
197
  : undefined;
200
198
  if (unsupportedGeneration) {
201
199
  semanticIssues.push(unsupportedGeneration);
@@ -205,29 +203,29 @@ export function validatePresetFile(input) {
205
203
  }
206
204
  return { ok: true, value: result.output };
207
205
  }
208
- export function findBuiltInPreset(name) {
209
- return builtInPresets.find((preset) => preset.name === name);
206
+ export function findPreset(presets, name) {
207
+ return presets.find((preset) => preset.name === name);
210
208
  }
211
- export function validateProjectBlueprint(input) {
209
+ export function validateProjectBlueprint(input, options = {}) {
212
210
  const result = v.safeParse(projectBlueprintSchema, input);
213
211
  if (!result.success) {
214
212
  return { ok: false, issues: shapeIssues(result.issues) };
215
213
  }
216
214
  const blueprint = result.output;
217
- const preset = findBuiltInPreset(blueprint.preset);
215
+ const preset = findPreset(options.presets ?? [], blueprint.preset);
218
216
  const semanticIssues = [
219
217
  ...duplicateIssues(blueprint.features, "$.features"),
220
218
  ];
221
219
  if (blueprint.projectKind === "single-package") {
222
220
  semanticIssues.push(unsupportedSinglePackageProjectShapeIssue("$.projectKind"));
223
221
  }
224
- if (!preset) {
222
+ if (options.presets && !preset) {
225
223
  semanticIssues.push({
226
224
  path: "$.preset",
227
- message: `Unknown built-in preset: ${blueprint.preset}`,
225
+ message: `Unknown ${options.presetLabel ?? "built-in"} preset: ${blueprint.preset}`,
228
226
  });
229
227
  }
230
- else {
228
+ else if (preset) {
231
229
  const unsupportedGeneration = generationSupportIssue(preset, "$.preset");
232
230
  if (unsupportedGeneration) {
233
231
  semanticIssues.push(unsupportedGeneration);
@@ -4,8 +4,10 @@ import { fileURLToPath } from "node:url";
4
4
  function templateRepositoryRoot() {
5
5
  const moduleDir = path.dirname(fileURLToPath(import.meta.url));
6
6
  const candidates = [
7
+ moduleDir,
7
8
  path.resolve(moduleDir, ".."),
8
9
  path.resolve(moduleDir, "..", ".."),
10
+ path.resolve(moduleDir, "..", "..", ".."),
9
11
  ];
10
12
  return (candidates.find((candidate) => existsSync(path.join(candidate, "pnpm-workspace.yaml"))) ?? candidates[0]);
11
13
  }
@@ -15,10 +15,12 @@ const defaultOxcConfigPaths = {
15
15
  const declarations = loadEditorCustomizationDeclarations();
16
16
  function editorCustomizationDeclarationPath() {
17
17
  const moduleDirectory = path.dirname(fileURLToPath(import.meta.url));
18
- const relativeDeclarationPath = "templates/shared/editor-customization/capabilities.json";
18
+ const relativeDeclarationPath = "builtin-source/templates/shared/editor-customization/capabilities.json";
19
19
  const candidates = [
20
20
  path.resolve(moduleDirectory, "..", relativeDeclarationPath),
21
21
  path.resolve(moduleDirectory, "..", "..", relativeDeclarationPath),
22
+ path.resolve(moduleDirectory, "..", "..", "template-builtin-source", "templates", "shared", "editor-customization", "capabilities.json"),
23
+ path.resolve(moduleDirectory, "..", "..", "..", "packages", relativeDeclarationPath),
22
24
  ];
23
25
  const declarationPath = candidates.find((candidate) => existsSync(candidate));
24
26
  if (!declarationPath) {
@@ -1,4 +1,5 @@
1
1
  import type { PresetSourceManifest } from "./preset-source.js";
2
+ import { type PresetProjectionSourceRoots } from "./projection-capabilities.js";
2
3
  export type GeneratedScenarioSet = "init" | "package-addition-matrix";
3
4
  export type GeneratedScenario = {
4
5
  readonly set: GeneratedScenarioSet;
@@ -38,6 +39,7 @@ export type GeneratedScenarioReporter = {
38
39
  export type GeneratedScenarioRunnerOptions = {
39
40
  readonly repoRoot: string;
40
41
  readonly cliPath: string;
42
+ readonly projectionSourceRoots: PresetProjectionSourceRoots;
41
43
  readonly runCommand?: GeneratedScenarioCommandRunner;
42
44
  readonly reporter?: GeneratedScenarioReporter;
43
45
  readonly deterministicToolchainEnv?: Record<string, string>;
@@ -10,6 +10,12 @@ const defaultDeterministicToolchainEnv = {
10
10
  TEMPLATE_TOOLCHAIN_RESOLUTION: "bundled-fallback",
11
11
  };
12
12
  const defaultFixtureConcurrency = 2;
13
+ function cliSourceExecutionEnv(options, env = {}) {
14
+ return {
15
+ ...env,
16
+ TSX_TSCONFIG_PATH: path.join(options.repoRoot, "tsconfig.json"),
17
+ };
18
+ }
13
19
  export function createExclusiveLock() {
14
20
  let tail = Promise.resolve();
15
21
  return {
@@ -50,7 +56,7 @@ export function generatedScenarioLabel(scenario) {
50
56
  }
51
57
  return `${scenario.basePreset} + ${scenario.addedPreset}`;
52
58
  }
53
- function scenario(set, input) {
59
+ function createGeneratedScenario(set, input) {
54
60
  return {
55
61
  set,
56
62
  basePreset: input.basePreset,
@@ -65,11 +71,11 @@ export function selectGeneratedScenarios(manifest, set) {
65
71
  if (!contract) {
66
72
  throw new Error(`Preset Source ${manifest.name} does not declare a Fixture Matrix Contract`);
67
73
  }
68
- const initScenarios = contract.initSupport.map((support) => scenario(set, { basePreset: support.preset }));
74
+ const initScenarios = contract.initSupport.map((support) => createGeneratedScenario(set, { basePreset: support.preset }));
69
75
  if (set === "init") {
70
76
  return { runnable: initScenarios, skipped: [] };
71
77
  }
72
- const matrixScenarios = contract.supportedCombinations.map((combination) => scenario(set, {
78
+ const matrixScenarios = contract.supportedCombinations.map((combination) => createGeneratedScenario(set, {
73
79
  basePreset: combination.basePreset,
74
80
  addedPreset: combination.addedPreset,
75
81
  linkFrom: combination.linkFrom,
@@ -115,7 +121,7 @@ async function generateScenario(scenario, workspace, options) {
115
121
  scenario.basePreset,
116
122
  "--yes",
117
123
  ], options.repoRoot, {
118
- env: options.deterministicToolchainEnv,
124
+ env: cliSourceExecutionEnv(options, options.deterministicToolchainEnv),
119
125
  logPrefix: scenario.label,
120
126
  });
121
127
  return projectDir;
@@ -137,7 +143,10 @@ async function applyPackageAddition(manifest, scenario, projectDir, options) {
137
143
  "--name",
138
144
  packageLeafName,
139
145
  ...linkFromArgs(scenario.linkFrom ?? []),
140
- ], projectDir, { logPrefix: scenario.label });
146
+ ], projectDir, {
147
+ env: cliSourceExecutionEnv(options),
148
+ logPrefix: scenario.label,
149
+ });
141
150
  await assertLinkedConsumerSourcesUnchanged(projectDir, beforeConsumerSources);
142
151
  return readAddedPackagePath(projectDir, packageLeafName);
143
152
  }
@@ -193,6 +202,7 @@ function projectionPlanForPreset(presetName, projectDir, manifest, options, pack
193
202
  });
194
203
  return projectPresetSourcePreset({
195
204
  preset,
205
+ sourceRoots: options.projectionSourceRoots,
196
206
  context: assembleGenerationContext({
197
207
  targetDir: projectDir,
198
208
  blueprint,
@@ -312,6 +322,7 @@ function normalizeRunnerOptions(options) {
312
322
  return {
313
323
  repoRoot: options.repoRoot,
314
324
  cliPath: options.cliPath,
325
+ projectionSourceRoots: options.projectionSourceRoots,
315
326
  runCommand: options.runCommand ?? defaultGeneratedScenarioCommandRunner,
316
327
  reporter: options.reporter ?? {
317
328
  info: console.log,
@@ -0,0 +1,12 @@
1
+ import { type PresetSourceManifest } from "./preset-source.js";
2
+ import { type PresetProjectionSourceRoots } from "./projection-capabilities.js";
3
+ export type AddPackageOptions = {
4
+ cwd: string;
5
+ preset: string;
6
+ name: string;
7
+ path?: string;
8
+ linkFrom?: readonly string[];
9
+ presetSourceManifest: PresetSourceManifest;
10
+ projectionSourceRoots: PresetProjectionSourceRoots;
11
+ };
12
+ export declare function addPackage(options: AddPackageOptions): Promise<void>;
@@ -4,7 +4,7 @@ import { validateProjectBlueprint, } from "./declarations.js";
4
4
  import { collectGeneratedManifestCatalogReferences, pnpmWorkspaceYamlWithCatalogDependencies, } from "./dependency-catalog.js";
5
5
  import { PackageAdditionSupport } from "./package-addition-support.js";
6
6
  import { assertTypeScriptPackageBoundaryForLinkIntent, packageTurboTasks, planPackageLinks, } from "./package-linking.js";
7
- import { findBuiltInPresetSourceManifestPreset, loadBuiltInPresetSourceManifest, } from "./preset-source.js";
7
+ import { findPresetSourceManifestPreset, } from "./preset-source.js";
8
8
  import { defaultPackagePathForPresetSourcePackageAddition, planPresetSourcePackageAddition, } from "./projection-capabilities.js";
9
9
  import { renderProject } from "./renderer.js";
10
10
  function projectNameFromBlueprint(blueprint, fallbackProjectName) {
@@ -75,16 +75,16 @@ function validateExplicitPackagePath(packagePath) {
75
75
  }
76
76
  return packagePath;
77
77
  }
78
- function supportedPackageAdditionPresetNames() {
79
- return loadBuiltInPresetSourceManifest()
80
- .presets.filter((preset) => preset.packageAdditionSupport === PackageAdditionSupport.Supported)
78
+ function supportedPackageAdditionPresetNames(manifest) {
79
+ return manifest.presets
80
+ .filter((preset) => preset.packageAdditionSupport === PackageAdditionSupport.Supported)
81
81
  .map((preset) => preset.name);
82
82
  }
83
- function formatUnsupportedPackageAdditionPresetError(preset) {
83
+ function formatUnsupportedPackageAdditionPresetError(preset, manifest) {
84
84
  return [
85
85
  `Preset ${preset} cannot be used for Package Addition.`,
86
86
  "It can still initialize a Generated Repository, but it cannot be added to an existing one.",
87
- `Supported Package Addition presets: ${supportedPackageAdditionPresetNames().join(", ")}`,
87
+ `Supported Package Addition presets: ${supportedPackageAdditionPresetNames(manifest).join(", ")}`,
88
88
  ].join("\n");
89
89
  }
90
90
  function assertNoPackageConflict(blueprint, packageName, packagePath) {
@@ -228,7 +228,7 @@ async function readGeneratedWorkspaceBlueprint(root) {
228
228
  catch (error) {
229
229
  if (error instanceof SyntaxError ||
230
230
  (isNodeError(error) && error.code === "ENOENT")) {
231
- throw new Error("Package Addition requires a valid .template/blueprint.json");
231
+ throw new Error("Package Addition requires a valid .template/blueprint.json", { cause: error });
232
232
  }
233
233
  throw error;
234
234
  }
@@ -622,18 +622,19 @@ export async function addPackage(options) {
622
622
  const repositoryMetadata = await readGeneratedRepositoryPackageMetadata(root);
623
623
  const projectName = projectNameFromBlueprint(blueprint, repositoryMetadata.projectName);
624
624
  const packageName = `@${projectName}/${options.name}`;
625
- const preset = findBuiltInPresetSourceManifestPreset(options.preset);
625
+ const preset = findPresetSourceManifestPreset(options.presetSourceManifest, options.preset);
626
626
  if (!preset) {
627
627
  throw new Error(`Unknown preset for Package Addition: ${options.preset}`);
628
628
  }
629
629
  if (preset.packageAdditionSupport !== PackageAdditionSupport.Supported) {
630
- throw new Error(formatUnsupportedPackageAdditionPresetError(options.preset));
630
+ throw new Error(formatUnsupportedPackageAdditionPresetError(options.preset, options.presetSourceManifest));
631
631
  }
632
632
  const packagePath = options.path
633
633
  ? validateExplicitPackagePath(options.path)
634
- : defaultPackagePathForPresetSourcePackageAddition(preset, options.name);
634
+ : defaultPackagePathForPresetSourcePackageAddition(preset, options.name, options.projectionSourceRoots);
635
635
  const additionPlan = await planPresetSourcePackageAddition({
636
636
  preset,
637
+ sourceRoots: options.projectionSourceRoots,
637
638
  addition: {
638
639
  root,
639
640
  blueprint,
@@ -1,5 +1,5 @@
1
1
  packages:
2
- - .
2
+ - packages/*
3
3
 
4
4
  catalog:
5
5
  "@hono/node-server": ^2.0.6
@@ -10,6 +10,7 @@ catalog:
10
10
  "@vitejs/plugin-vue": ^6.0.7
11
11
  "@vue/tsconfig": ^0.9.1
12
12
  "@vueuse/core": ^14.3.0
13
+ execa: ^9.6.1
13
14
  hono: ^4.12.27
14
15
  oxfmt: ^0.57.0
15
16
  oxlint: ^1.72.0
@@ -24,6 +25,7 @@ catalog:
24
25
  vitest: ^4.1.9
25
26
  vue: ^3.5.39
26
27
  vue-tsc: ^3.3.6
28
+ yaml: ^2.9.0
27
29
 
28
30
  allowBuilds:
29
31
  esbuild: true
@@ -229,7 +229,7 @@ export declare const presetSourceManifestJsonSchema: {
229
229
  readonly features: {
230
230
  readonly type: "array";
231
231
  readonly items: {
232
- readonly enum: ("devcontainer" | "oxc-format-lint" | "cargo-test" | "github-actions" | "dependabot" | "pnpm-catalog" | "strict-typescript" | "root-check" | "fix-command" | "rustfmt-clippy" | "native-binary-release")[];
232
+ readonly enum: ("pnpm-catalog" | "oxc-format-lint" | "strict-typescript" | "root-check" | "fix-command" | "devcontainer" | "github-actions" | "dependabot" | "rustfmt-clippy" | "cargo-test" | "native-binary-release")[];
233
233
  };
234
234
  readonly uniqueItems: true;
235
235
  };
@@ -425,6 +425,4 @@ export declare function validatePresetSourceManifest(input: unknown, options?: P
425
425
  export declare function validateBuiltInPresetSourceManifest(input: unknown, options?: PresetSourceManifestValidationOptions): ValidationResult<PresetSourceManifest>;
426
426
  export declare function manifestReferencedSourceFiles(manifest: PresetSourceManifest, sourceRoot: string): string[];
427
427
  export declare function loadPresetSourceManifestFile(filePath: string): PresetSourceManifest;
428
- export declare function loadBuiltInPresetSourceManifest(): PresetSourceManifest;
429
428
  export declare function findPresetSourceManifestPreset(manifest: PresetSourceManifest, presetName: string): PresetSourceManifestPreset | undefined;
430
- export declare function findBuiltInPresetSourceManifestPreset(presetName: string): PresetSourceManifestPreset | undefined;
@@ -1,11 +1,9 @@
1
1
  import { existsSync, readdirSync, readFileSync, realpathSync, statSync, } from "node:fs";
2
2
  import path from "node:path";
3
- import { fileURLToPath } from "node:url";
4
3
  import * as v from "valibot";
5
4
  import { loadTemplateDependencyCatalog, } from "./dependency-catalog.js";
6
5
  import { PackageAdditionSupport } from "./package-addition-support.js";
7
6
  import { normalizePresetProjectionDeclaration, projectionCapabilityIssues, } from "./projection-capabilities.js";
8
- import { packageTemplateRoot } from "./runtime-paths.js";
9
7
  const featureNames = [
10
8
  "pnpm-catalog",
11
9
  "oxc-format-lint",
@@ -402,34 +400,34 @@ function formatIssuePath(issue) {
402
400
  if (!issue.path || issue.path.length === 0) {
403
401
  return "$";
404
402
  }
405
- return issue.path.reduce((path, item) => {
403
+ return issue.path.reduce((issuePath, item) => {
406
404
  if (typeof item.key === "number") {
407
- return `${path}[${item.key}]`;
405
+ return `${issuePath}[${item.key}]`;
408
406
  }
409
- return `${path}.${String(item.key)}`;
407
+ return `${issuePath}.${String(item.key)}`;
410
408
  }, "$");
411
409
  }
412
410
  function shapeIssues(issues) {
413
411
  return issues.map((issue) => {
414
- const path = formatIssuePath(issue);
415
- const missingPresetMetadata = path.match(/^\$\.presets\[\d+\]\.(.+)$/);
412
+ const validationPath = formatIssuePath(issue);
413
+ const missingPresetMetadata = validationPath.match(/^\$\.presets\[\d+\]\.(.+)$/);
416
414
  if (missingPresetMetadata && issue.message.includes("received undefined")) {
417
415
  return {
418
- path,
416
+ path: validationPath,
419
417
  message: `Preset metadata is missing required field: ${missingPresetMetadata[1]}`,
420
418
  };
421
419
  }
422
420
  if (issue.message.startsWith("Invalid key:") &&
423
- /\.(body|content|text)$/.test(path)) {
424
- const key = path.split(".").at(-1);
421
+ /\.(body|content|text)$/.test(validationPath)) {
422
+ const key = validationPath.split(".").at(-1);
425
423
  return {
426
- path,
424
+ path: validationPath,
427
425
  message: `Preset Source Manifests must reference Generated Repository file bodies by path, not inline ${key}`,
428
426
  };
429
427
  }
430
428
  return {
431
- path,
432
- message: path.match(/^\$\.presets\[\d+\]\.packageAdditionSupport$/)
429
+ path: validationPath,
430
+ message: validationPath.match(/^\$\.presets\[\d+\]\.packageAdditionSupport$/)
433
431
  ? "Package Addition Support must be one of: supported, unsupported"
434
432
  : issue.message,
435
433
  };
@@ -449,7 +447,7 @@ function duplicatePresetNameIssues(presets) {
449
447
  message: `Duplicate Preset name: ${name}`,
450
448
  }));
451
449
  }
452
- function duplicateValueIssues(values, path) {
450
+ function duplicateValueIssues(values, validationPath) {
453
451
  const seen = new Set();
454
452
  const duplicates = new Set();
455
453
  for (const value of values) {
@@ -459,7 +457,7 @@ function duplicateValueIssues(values, path) {
459
457
  seen.add(value);
460
458
  }
461
459
  return [...duplicates].map((value) => ({
462
- path,
460
+ path: validationPath,
463
461
  message: `Duplicate value: ${value}`,
464
462
  }));
465
463
  }
@@ -921,20 +919,6 @@ export function loadPresetSourceManifestFile(filePath) {
921
919
  }
922
920
  return result.value;
923
921
  }
924
- export function loadBuiltInPresetSourceManifest() {
925
- const moduleDir = path.dirname(fileURLToPath(import.meta.url));
926
- const filePath = packageTemplateRoot(moduleDir, "preset-source.json");
927
- const result = validateBuiltInPresetSourceManifest(JSON.parse(readFileSync(filePath, "utf8")), { sourceRoot: path.dirname(filePath) });
928
- if (!result.ok) {
929
- throw new Error(`Built-in Preset Source Manifest is invalid:\n${result.issues
930
- .map((issue) => ` - ${issue.path}: ${issue.message}`)
931
- .join("\n")}`);
932
- }
933
- return result.value;
934
- }
935
922
  export function findPresetSourceManifestPreset(manifest, presetName) {
936
923
  return manifest.presets.find((preset) => preset.name === presetName);
937
924
  }
938
- export function findBuiltInPresetSourceManifestPreset(presetName) {
939
- return findPresetSourceManifestPreset(loadBuiltInPresetSourceManifest(), presetName);
940
- }
@@ -46,6 +46,12 @@ export type ProjectionCapabilityDeclaration = WorkspaceLibraryPackageCapabilityD
46
46
  export type PresetProjectionDeclaration = {
47
47
  readonly capabilities: readonly ProjectionCapabilityDeclaration[];
48
48
  };
49
+ export type ProjectionSourcePreset = "hono-api" | "rust-bin" | "ts-lib" | "vue-app" | "vue-hono-app";
50
+ export type PresetProjectionSourceRoots = {
51
+ readonly preset: (sourcePreset: ProjectionSourcePreset) => string;
52
+ readonly sharedOxc: () => string;
53
+ readonly sharedDevcontainer: () => string;
54
+ };
49
55
  export declare function validateProjectionCapabilities(input: unknown): ValidationResult<PresetProjectionDeclaration>;
50
56
  export declare function projectionCapabilityIssues(presets: readonly PresetSourceManifestPreset[]): ValidationIssue[];
51
57
  export declare function normalizePresetProjectionDeclaration(declaration: PresetProjectionDeclaration): PresetProjectionDeclaration;
@@ -53,15 +59,17 @@ export declare function interpretPresetProjectionDeclaration(options: {
53
59
  readonly preset: PresetSourceManifestPreset;
54
60
  readonly declaration: PresetProjectionDeclaration;
55
61
  readonly context: GenerationContext;
62
+ readonly sourceRoots: PresetProjectionSourceRoots;
56
63
  }): PresetProjectionPlan;
57
64
  export declare function blueprintForPresetSourcePreset(preset: PresetSourceManifestPreset, options?: PresetBlueprintOptions): ProjectBlueprint;
58
65
  export declare function projectPresetSourcePreset(options: {
59
66
  readonly preset: PresetSourceManifestPreset;
60
67
  readonly context: GenerationContext;
68
+ readonly sourceRoots: PresetProjectionSourceRoots;
61
69
  }): PresetProjectionPlan;
62
70
  export declare function planPresetSourcePackageAddition(options: {
63
71
  readonly preset: PresetSourceManifestPreset;
64
72
  readonly addition: PresetPackageAdditionOptions;
73
+ readonly sourceRoots: PresetProjectionSourceRoots;
65
74
  }): Promise<PresetPackageAdditionPlan>;
66
- export declare function defaultPackagePathForPresetSourcePackageAddition(preset: PresetSourceManifestPreset, packageLeafName: string): string;
67
- export declare function loadBuiltInPresetProjectionDeclaration(presetName: string): PresetProjectionDeclaration;
75
+ export declare function defaultPackagePathForPresetSourcePackageAddition(preset: PresetSourceManifestPreset, packageLeafName: string, sourceRoots: PresetProjectionSourceRoots): string;
@@ -1,13 +1,10 @@
1
- import { readFileSync } from "node:fs";
2
1
  import { readFile } from "node:fs/promises";
3
2
  import path from "node:path";
4
- import { fileURLToPath } from "node:url";
5
3
  import { collectGeneratedManifestCatalogDependencies, collectGeneratedManifestCatalogReferences, renderGeneratedPnpmWorkspaceYaml, } from "./dependency-catalog.js";
6
4
  import { browserTestToolLayer, checkedDockerfileFirstNodePnpmDevcontainer, dockerfileFirstRustPnpmDevcontainer, nodePnpmToolLayer, rustToolLayer, } from "./devcontainer.js";
7
5
  import { editorCustomizationForCapabilities, } from "./editor-customization.js";
8
6
  import { renderFixCommand, renderRootCheckCommand, } from "./module-graph.js";
9
7
  import { packageManifestExposureFields, planPackageLinks, } from "./package-linking.js";
10
- import { packageTemplateRoot } from "./runtime-paths.js";
11
8
  const projectionCapabilityKinds = [
12
9
  "workspace-library-package",
13
10
  "workspace-node-packages",
@@ -26,10 +23,6 @@ const workspacePackageBoundary = {
26
23
  kind: "package-boundary",
27
24
  path: ".",
28
25
  };
29
- const workspacePackageCollectionBoundary = {
30
- kind: "package-boundary",
31
- path: "packages/*",
32
- };
33
26
  const requiredPlanCapabilityProviders = [
34
27
  {
35
28
  flag: "rootCheck",
@@ -83,7 +76,7 @@ const capabilityInterpreters = {
83
76
  kind: "workspace-library-package",
84
77
  contribute({ capability, state }) {
85
78
  state.package = capability;
86
- state.sourceRoot = templateSourceRoot(capability.packageSourcePreset);
79
+ state.sourceRoot = templateSourceRoot(state, capability.packageSourcePreset);
87
80
  state.packageDependencies.add("valibot");
88
81
  state.operationFactories.push(workspaceLibraryPackageOperations);
89
82
  },
@@ -92,7 +85,7 @@ const capabilityInterpreters = {
92
85
  kind: "workspace-node-packages",
93
86
  contribute({ capability, state }) {
94
87
  state.nodeWorkspace = capability;
95
- state.sourceRoot = templateSourceRootForPreset(sourceRootPreset(capability));
88
+ state.sourceRoot = templateSourceRootForPreset(state, sourceRootPreset(capability));
96
89
  state.operationFactories.push(workspaceNodePackagesOperations);
97
90
  if (capability.packages.length > 1) {
98
91
  state.rootScriptFragments.dev = "turbo run dev --parallel";
@@ -112,8 +105,9 @@ const capabilityInterpreters = {
112
105
  kind: "rust-binary-workspace",
113
106
  contribute({ capability, state }) {
114
107
  state.rustWorkspace = capability;
115
- state.sourceRoot = templateSourceRootForPreset("rust-bin");
116
- state.sourceRoots.sharedDevcontainer = sharedDevcontainerSourceRoot();
108
+ state.sourceRoot = templateSourceRootForPreset(state, "rust-bin");
109
+ state.sourceRoots.sharedDevcontainer =
110
+ state.projectionSourceRoots.sharedDevcontainer();
117
111
  state.rootCheckComponents.push({
118
112
  kind: "turbo-package-check",
119
113
  owner: workspaceGlobBoundary(capability.workspacePackageGlob),
@@ -186,7 +180,7 @@ const capabilityInterpreters = {
186
180
  "oxc-format-lint": {
187
181
  kind: "oxc-format-lint",
188
182
  contribute({ state }) {
189
- state.sourceRoots.sharedOxc = sharedOxcSourceRoot();
183
+ state.sourceRoots.sharedOxc = state.projectionSourceRoots.sharedOxc();
190
184
  state.rootCheckComponents.unshift({
191
185
  kind: "oxc-format-check",
192
186
  owner: strictTypescriptRootBoundary,
@@ -234,7 +228,8 @@ const capabilityInterpreters = {
234
228
  "node-pnpm-devcontainer": {
235
229
  kind: "node-pnpm-devcontainer",
236
230
  contribute({ state }) {
237
- state.sourceRoots.sharedDevcontainer = sharedDevcontainerSourceRoot();
231
+ state.sourceRoots.sharedDevcontainer =
232
+ state.projectionSourceRoots.sharedDevcontainer();
238
233
  state.flags.devcontainer = true;
239
234
  state.operationFactories.push(nodePnpmDevcontainerOperations);
240
235
  },
@@ -361,7 +356,7 @@ export function interpretPresetProjectionDeclaration(options) {
361
356
  .map((issue) => ` - ${issue.path}: ${issue.message}`)
362
357
  .join("\n")}`);
363
358
  }
364
- const state = createProjectionCompositionState();
359
+ const state = createProjectionCompositionState(options.sourceRoots);
365
360
  for (const capability of validation.value.capabilities) {
366
361
  capabilityInterpreters[capability.kind].contribute({
367
362
  capability: capability,
@@ -437,13 +432,14 @@ export function projectPresetSourcePreset(options) {
437
432
  preset: options.preset,
438
433
  declaration: options.preset.projection,
439
434
  context: options.context,
435
+ sourceRoots: options.sourceRoots,
440
436
  });
441
437
  }
442
438
  export async function planPresetSourcePackageAddition(options) {
443
439
  if (options.preset.projection === undefined) {
444
440
  throw new Error(`Preset ${options.preset.name} declares Package Addition support but has no Projection Declaration`);
445
441
  }
446
- const state = stateForProjectionDeclaration(options.preset.projection);
442
+ const state = stateForProjectionDeclaration(options.preset.projection, options.sourceRoots);
447
443
  const additionCapability = packageAdditionCapabilityForState(options.preset.name, state);
448
444
  return {
449
445
  packagePath: options.addition.packagePath,
@@ -451,7 +447,7 @@ export async function planPresetSourcePackageAddition(options) {
451
447
  workspaceMembershipGlob: `${packageCollectionFromPackagePath(options.addition.packagePath)}/*`,
452
448
  packageRole: additionCapability.packageRole,
453
449
  packageSourcePreset: additionCapability.packageSourcePreset,
454
- sourceRoot: templateSourceRootForPreset(additionCapability.sourcePreset),
450
+ sourceRoot: templateSourceRootForPreset(state, additionCapability.sourcePreset),
455
451
  sourceRoots: state.sourceRoots,
456
452
  operations: [
457
453
  ...packageAdditionOperationsForCapability({
@@ -475,34 +471,17 @@ export async function planPresetSourcePackageAddition(options) {
475
471
  ],
476
472
  };
477
473
  }
478
- export function defaultPackagePathForPresetSourcePackageAddition(preset, packageLeafName) {
474
+ export function defaultPackagePathForPresetSourcePackageAddition(preset, packageLeafName, sourceRoots) {
479
475
  if (preset.projection === undefined) {
480
476
  throw new Error(`Preset ${preset.name} declares Package Addition support but has no Projection Declaration`);
481
477
  }
482
- const state = stateForProjectionDeclaration(preset.projection);
478
+ const state = stateForProjectionDeclaration(preset.projection, sourceRoots);
483
479
  const additionCapability = packageAdditionCapabilityForState(preset.name, state);
484
480
  return `${packageCollection(additionCapability.workspacePackageGlob)}/${packageLeafName}`;
485
481
  }
486
- export function loadBuiltInPresetProjectionDeclaration(presetName) {
487
- const manifestPath = path.join(packageTemplateRoot(path.dirname(fileURLToPath(import.meta.url))), "preset-source.json");
488
- const manifest = JSON.parse(readFileSync(manifestPath, "utf8"));
489
- if (!isRecord(manifest) || !Array.isArray(manifest.presets)) {
490
- throw new Error("Built-in Preset Source Manifest must declare presets");
491
- }
492
- const preset = manifest.presets.find((candidate) => isRecord(candidate) && candidate.name === presetName);
493
- if (!isRecord(preset) || preset.projection === undefined) {
494
- throw new Error(`Built-in Preset ${presetName} must declare a Projection Declaration`);
495
- }
496
- const result = validateProjectionCapabilities(preset.projection);
497
- if (!result.ok) {
498
- throw new Error(`Built-in Preset ${presetName} Projection Declaration is invalid:\n${result.issues
499
- .map((issue) => ` - ${issue.path}: ${issue.message}`)
500
- .join("\n")}`);
501
- }
502
- return result.value;
503
- }
504
- function createProjectionCompositionState() {
482
+ function createProjectionCompositionState(sourceRoots) {
505
483
  return {
484
+ projectionSourceRoots: sourceRoots,
506
485
  sourceRoots: {},
507
486
  rootCheckComponents: [],
508
487
  rootCheckEnvironmentNeeds: [],
@@ -860,14 +839,14 @@ function blueprintPackagesForCapabilities(capabilities, packageScope, projectNam
860
839
  return [];
861
840
  });
862
841
  }
863
- function stateForProjectionDeclaration(declaration) {
842
+ function stateForProjectionDeclaration(declaration, sourceRoots) {
864
843
  const validation = validateProjectionCapabilities(declaration);
865
844
  if (!validation.ok) {
866
845
  throw new Error(`Projection Declaration is invalid:\n${validation.issues
867
846
  .map((issue) => ` - ${issue.path}: ${issue.message}`)
868
847
  .join("\n")}`);
869
848
  }
870
- const state = createProjectionCompositionState();
849
+ const state = createProjectionCompositionState(sourceRoots);
871
850
  for (const capability of validation.value.capabilities) {
872
851
  capabilityInterpreters[capability.kind].contribute({
873
852
  capability: capability,
@@ -2193,15 +2172,9 @@ function githubMaintenanceOperations() {
2193
2172
  },
2194
2173
  ];
2195
2174
  }
2196
- function templateSourceRoot(sourcePreset) {
2197
- return templateSourceRootForPreset(sourcePreset);
2198
- }
2199
- function templateSourceRootForPreset(sourcePreset) {
2200
- return packageTemplateRoot(path.dirname(fileURLToPath(import.meta.url)), sourcePreset);
2201
- }
2202
- function sharedOxcSourceRoot() {
2203
- return packageTemplateRoot(path.dirname(fileURLToPath(import.meta.url)), "shared", "oxc");
2175
+ function templateSourceRoot(state, sourcePreset) {
2176
+ return templateSourceRootForPreset(state, sourcePreset);
2204
2177
  }
2205
- function sharedDevcontainerSourceRoot() {
2206
- return packageTemplateRoot(path.dirname(fileURLToPath(import.meta.url)), "shared", "devcontainer");
2178
+ function templateSourceRootForPreset(state, sourcePreset) {
2179
+ return state.projectionSourceRoots.preset(sourcePreset);
2207
2180
  }
@@ -380,7 +380,9 @@ async function copyGeneratedFile(from, to) {
380
380
  }
381
381
  catch (error) {
382
382
  if (isNodeError(error) && error.code === "EEXIST") {
383
- throw new Error(`Refusing to overwrite existing file: ${to}`);
383
+ throw new Error(`Refusing to overwrite existing file: ${to}`, {
384
+ cause: error,
385
+ });
384
386
  }
385
387
  throw error;
386
388
  }
@@ -394,7 +396,9 @@ async function writeGeneratedFile(to, text, overwrite = false) {
394
396
  }
395
397
  catch (error) {
396
398
  if (isNodeError(error) && error.code === "EEXIST") {
397
- throw new Error(`Refusing to overwrite existing file: ${to}`);
399
+ throw new Error(`Refusing to overwrite existing file: ${to}`, {
400
+ cause: error,
401
+ });
398
402
  }
399
403
  throw error;
400
404
  }
@@ -447,7 +451,9 @@ async function commitStagedProject(stagingRoot, targetRoot) {
447
451
  // The target disappeared between the emptiness check and commit.
448
452
  }
449
453
  else if (isNodeError(error) && error.code === "ENOTEMPTY") {
450
- throw new Error(`Target directory is not empty: ${targetRoot}`);
454
+ throw new Error(`Target directory is not empty: ${targetRoot}`, {
455
+ cause: error,
456
+ });
451
457
  }
452
458
  else {
453
459
  throw error;
@@ -460,7 +466,9 @@ async function commitStagedProject(stagingRoot, targetRoot) {
460
466
  catch (error) {
461
467
  if (isNodeError(error) &&
462
468
  ["EEXIST", "ENOTEMPTY", "ENOTDIR", "EISDIR"].includes(error.code ?? "")) {
463
- throw new Error(`Refusing to overwrite existing target: ${targetRoot}`);
469
+ throw new Error(`Refusing to overwrite existing target: ${targetRoot}`, {
470
+ cause: error,
471
+ });
464
472
  }
465
473
  throw error;
466
474
  }