@ykdz/template 0.0.7 → 0.0.9

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 (123) hide show
  1. package/dist/{src/cli.js → cli.js} +33 -21
  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 +96 -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 +240 -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 +224 -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 +372 -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 +59 -0
  19. package/{templates → node_modules/@ykdz/template-builtin-source/templates}/preset-source.json +14 -2
  20. package/node_modules/@ykdz/template-builtin-source/templates/shared/oxc/node/oxlint.config.ts +34 -0
  21. package/node_modules/@ykdz/template-builtin-source/templates/shared/oxc/tsconfig.config.json +20 -0
  22. package/node_modules/@ykdz/template-builtin-source/templates/shared/oxc/vue/oxlint.config.ts +36 -0
  23. package/node_modules/@ykdz/template-builtin-source/templates/vue-app/env.d.ts +8 -0
  24. package/node_modules/@ykdz/template-builtin-source/templates/vue-hono-app/web/env.d.ts +16 -0
  25. package/{dist/src → node_modules/@ykdz/template-core/dist}/declarations.d.ts +7 -4
  26. package/{dist/src → node_modules/@ykdz/template-core/dist}/declarations.js +45 -14
  27. package/{dist/src → node_modules/@ykdz/template-core/dist}/dependency-catalog.js +13 -6
  28. package/{dist/src → node_modules/@ykdz/template-core/dist}/devcontainer.d.ts +5 -5
  29. package/{dist/src → node_modules/@ykdz/template-core/dist}/editor-customization.js +23 -30
  30. package/{dist/src → node_modules/@ykdz/template-core/dist}/generated-scenarios.d.ts +6 -4
  31. package/{dist/src → node_modules/@ykdz/template-core/dist}/generated-scenarios.js +45 -14
  32. package/{dist/src → node_modules/@ykdz/template-core/dist}/generation-context.js +8 -3
  33. package/{dist/src → node_modules/@ykdz/template-core/dist}/next-step-instructions.js +3 -0
  34. package/node_modules/@ykdz/template-core/dist/package-addition.d.ts +12 -0
  35. package/{dist/src → node_modules/@ykdz/template-core/dist}/package-addition.js +33 -18
  36. package/{pnpm-workspace.yaml → node_modules/@ykdz/template-core/dist/pnpm-workspace.yaml} +4 -1
  37. package/{dist/src → node_modules/@ykdz/template-core/dist}/preset-projection.d.ts +3 -3
  38. package/{dist/src → node_modules/@ykdz/template-core/dist}/preset-projection.js +1 -0
  39. package/{dist/src → node_modules/@ykdz/template-core/dist}/preset-source.d.ts +1 -3
  40. package/{dist/src → node_modules/@ykdz/template-core/dist}/preset-source.js +73 -74
  41. package/{dist/src → node_modules/@ykdz/template-core/dist}/project-github.d.ts +3 -3
  42. package/{dist/src → node_modules/@ykdz/template-core/dist}/project-github.js +1 -0
  43. package/{dist/src → node_modules/@ykdz/template-core/dist}/projection-capabilities.d.ts +17 -5
  44. package/{dist/src → node_modules/@ykdz/template-core/dist}/projection-capabilities.js +209 -169
  45. package/{dist/src → node_modules/@ykdz/template-core/dist}/renderer.d.ts +2 -2
  46. package/{dist/src → node_modules/@ykdz/template-core/dist}/renderer.js +14 -6
  47. package/{dist/src → node_modules/@ykdz/template-core/dist}/runtime-paths.js +2 -0
  48. package/{dist/src → node_modules/@ykdz/template-core/dist}/template-boundary-check.d.ts +1 -1
  49. package/{dist/src → node_modules/@ykdz/template-core/dist}/template-boundary-check.js +8 -10
  50. package/{dist/src → node_modules/@ykdz/template-core/dist}/toolchain-resolution.d.ts +5 -5
  51. package/{dist/src → node_modules/@ykdz/template-core/dist}/toolchain-resolution.js +10 -11
  52. package/node_modules/@ykdz/template-core/package.json +34 -0
  53. package/package.json +18 -31
  54. package/README.md +0 -35
  55. package/dist/src/package-addition.d.ts +0 -8
  56. package/templates/shared/oxc/node/oxlint.config.ts +0 -9
  57. package/templates/shared/oxc/vue/oxlint.config.ts +0 -9
  58. package/templates/vue-app/env.d.ts +0 -1
  59. package/templates/vue-hono-app/web/env.d.ts +0 -9
  60. /package/dist/{src/cli.d.ts → cli.d.ts} +0 -0
  61. /package/{templates → node_modules/@ykdz/template-builtin-source/templates}/hono-api/.github/dependabot.yml +0 -0
  62. /package/{templates → node_modules/@ykdz/template-builtin-source/templates}/hono-api/.github/workflows/check.yml +0 -0
  63. /package/{templates → node_modules/@ykdz/template-builtin-source/templates}/hono-api/src/app.ts +0 -0
  64. /package/{templates → node_modules/@ykdz/template-builtin-source/templates}/hono-api/src/server.ts +0 -0
  65. /package/{templates → node_modules/@ykdz/template-builtin-source/templates}/hono-api/test/app.test.ts +0 -0
  66. /package/{templates → node_modules/@ykdz/template-builtin-source/templates}/hono-api/vitest.config.ts +0 -0
  67. /package/{templates → node_modules/@ykdz/template-builtin-source/templates}/rust-bin/.github/dependabot.yml +0 -0
  68. /package/{templates → node_modules/@ykdz/template-builtin-source/templates}/rust-bin/.github/workflows/check.yml +0 -0
  69. /package/{templates → node_modules/@ykdz/template-builtin-source/templates}/rust-bin/rust-toolchain.toml +0 -0
  70. /package/{templates → node_modules/@ykdz/template-builtin-source/templates}/rust-bin/rustfmt.toml +0 -0
  71. /package/{templates → node_modules/@ykdz/template-builtin-source/templates}/rust-bin/src/main.rs +0 -0
  72. /package/{templates → node_modules/@ykdz/template-builtin-source/templates}/shared/devcontainer/browser-test.Dockerfile +0 -0
  73. /package/{templates → node_modules/@ykdz/template-builtin-source/templates}/shared/devcontainer/node-pnpm.Dockerfile +0 -0
  74. /package/{templates → node_modules/@ykdz/template-builtin-source/templates}/shared/devcontainer/rust.Dockerfile +0 -0
  75. /package/{templates → node_modules/@ykdz/template-builtin-source/templates}/shared/editor-customization/capabilities.json +0 -0
  76. /package/{templates → node_modules/@ykdz/template-builtin-source/templates}/shared/oxc/oxfmt.config.ts +0 -0
  77. /package/{templates → node_modules/@ykdz/template-builtin-source/templates}/ts-lib/.github/dependabot.yml +0 -0
  78. /package/{templates → node_modules/@ykdz/template-builtin-source/templates}/ts-lib/.github/workflows/check.yml +0 -0
  79. /package/{templates → node_modules/@ykdz/template-builtin-source/templates}/ts-lib/src/index.ts +0 -0
  80. /package/{templates → node_modules/@ykdz/template-builtin-source/templates}/ts-lib/src/name-schema.ts +0 -0
  81. /package/{templates → node_modules/@ykdz/template-builtin-source/templates}/vue-app/.github/dependabot.yml +0 -0
  82. /package/{templates → node_modules/@ykdz/template-builtin-source/templates}/vue-app/.github/workflows/check.yml +0 -0
  83. /package/{templates → node_modules/@ykdz/template-builtin-source/templates}/vue-app/index.html +0 -0
  84. /package/{templates → node_modules/@ykdz/template-builtin-source/templates}/vue-app/playwright.config.ts +0 -0
  85. /package/{templates → node_modules/@ykdz/template-builtin-source/templates}/vue-app/playwright.package-addition.config.ts +0 -0
  86. /package/{templates → node_modules/@ykdz/template-builtin-source/templates}/vue-app/src/App.vue +0 -0
  87. /package/{templates → node_modules/@ykdz/template-builtin-source/templates}/vue-app/src/main.ts +0 -0
  88. /package/{templates → node_modules/@ykdz/template-builtin-source/templates}/vue-app/src/stores/counter.ts +0 -0
  89. /package/{templates → node_modules/@ykdz/template-builtin-source/templates}/vue-app/src/style.css +0 -0
  90. /package/{templates → node_modules/@ykdz/template-builtin-source/templates}/vue-app/test/app.test.ts +0 -0
  91. /package/{templates → node_modules/@ykdz/template-builtin-source/templates}/vue-app/test/e2e/app.spec.ts +0 -0
  92. /package/{templates → node_modules/@ykdz/template-builtin-source/templates}/vue-app/vite.config.ts +0 -0
  93. /package/{templates → node_modules/@ykdz/template-builtin-source/templates}/vue-app/vitest.config.ts +0 -0
  94. /package/{templates → node_modules/@ykdz/template-builtin-source/templates}/vue-hono-app/.github/dependabot.yml +0 -0
  95. /package/{templates → node_modules/@ykdz/template-builtin-source/templates}/vue-hono-app/.github/workflows/check.yml +0 -0
  96. /package/{templates → node_modules/@ykdz/template-builtin-source/templates}/vue-hono-app/api/src/index.ts +0 -0
  97. /package/{templates → node_modules/@ykdz/template-builtin-source/templates}/vue-hono-app/api/src/runtime.ts +0 -0
  98. /package/{templates → node_modules/@ykdz/template-builtin-source/templates}/vue-hono-app/api/src/server.ts +0 -0
  99. /package/{templates → node_modules/@ykdz/template-builtin-source/templates}/vue-hono-app/api/test/app.test.ts +0 -0
  100. /package/{templates → node_modules/@ykdz/template-builtin-source/templates}/vue-hono-app/api/vitest.config.ts +0 -0
  101. /package/{templates → node_modules/@ykdz/template-builtin-source/templates}/vue-hono-app/web/index.html +0 -0
  102. /package/{templates → node_modules/@ykdz/template-builtin-source/templates}/vue-hono-app/web/playwright.config.ts +0 -0
  103. /package/{templates → node_modules/@ykdz/template-builtin-source/templates}/vue-hono-app/web/src/App.vue +0 -0
  104. /package/{templates → node_modules/@ykdz/template-builtin-source/templates}/vue-hono-app/web/src/api.ts +0 -0
  105. /package/{templates → node_modules/@ykdz/template-builtin-source/templates}/vue-hono-app/web/src/main.ts +0 -0
  106. /package/{templates → node_modules/@ykdz/template-builtin-source/templates}/vue-hono-app/web/src/stores/counter.ts +0 -0
  107. /package/{templates → node_modules/@ykdz/template-builtin-source/templates}/vue-hono-app/web/src/style.css +0 -0
  108. /package/{templates → node_modules/@ykdz/template-builtin-source/templates}/vue-hono-app/web/test/app.test.ts +0 -0
  109. /package/{templates → node_modules/@ykdz/template-builtin-source/templates}/vue-hono-app/web/test/e2e/app.spec.ts +0 -0
  110. /package/{templates → node_modules/@ykdz/template-builtin-source/templates}/vue-hono-app/web/vite.config.ts +0 -0
  111. /package/{templates → node_modules/@ykdz/template-builtin-source/templates}/vue-hono-app/web/vitest.config.ts +0 -0
  112. /package/{dist/src → node_modules/@ykdz/template-core/dist}/dependency-catalog.d.ts +0 -0
  113. /package/{dist/src → node_modules/@ykdz/template-core/dist}/devcontainer.js +0 -0
  114. /package/{dist/src → node_modules/@ykdz/template-core/dist}/editor-customization.d.ts +0 -0
  115. /package/{dist/src → node_modules/@ykdz/template-core/dist}/generation-context.d.ts +0 -0
  116. /package/{dist/src → node_modules/@ykdz/template-core/dist}/module-graph.d.ts +0 -0
  117. /package/{dist/src → node_modules/@ykdz/template-core/dist}/module-graph.js +0 -0
  118. /package/{dist/src → node_modules/@ykdz/template-core/dist}/next-step-instructions.d.ts +0 -0
  119. /package/{dist/src → node_modules/@ykdz/template-core/dist}/package-addition-support.d.ts +0 -0
  120. /package/{dist/src → node_modules/@ykdz/template-core/dist}/package-addition-support.js +0 -0
  121. /package/{dist/src → node_modules/@ykdz/template-core/dist}/package-linking.d.ts +0 -0
  122. /package/{dist/src → node_modules/@ykdz/template-core/dist}/package-linking.js +0 -0
  123. /package/{dist/src → node_modules/@ykdz/template-core/dist}/runtime-paths.d.ts +0 -0
@@ -1,6 +1,7 @@
1
1
  import { readdir, readFile } from "node:fs/promises";
2
2
  import path from "node:path";
3
3
  import { execa } from "execa";
4
+ import * as v from "valibot";
4
5
  import { assembleGenerationContext } from "./generation-context.js";
5
6
  import { renderPlaywrightBrowserInstallCommand, } from "./module-graph.js";
6
7
  import { planNextStepInstructions } from "./next-step-instructions.js";
@@ -10,6 +11,18 @@ const defaultDeterministicToolchainEnv = {
10
11
  TEMPLATE_TOOLCHAIN_RESOLUTION: "bundled-fallback",
11
12
  };
12
13
  const defaultFixtureConcurrency = 2;
14
+ const storedBlueprintSchema = v.object({
15
+ packages: v.optional(v.array(v.object({
16
+ name: v.string(),
17
+ path: v.string(),
18
+ }))),
19
+ });
20
+ function cliSourceExecutionEnv(options, env = {}) {
21
+ return {
22
+ ...env,
23
+ TSX_TSCONFIG_PATH: path.join(options.repoRoot, "tsconfig.json"),
24
+ };
25
+ }
13
26
  export function createExclusiveLock() {
14
27
  let tail = Promise.resolve();
15
28
  return {
@@ -50,12 +63,14 @@ export function generatedScenarioLabel(scenario) {
50
63
  }
51
64
  return `${scenario.basePreset} + ${scenario.addedPreset}`;
52
65
  }
53
- function scenario(set, input) {
66
+ function createGeneratedScenario(set, input) {
54
67
  return {
55
68
  set,
56
69
  basePreset: input.basePreset,
57
- addedPreset: input.addedPreset,
58
- linkFrom: input.linkFrom ? [...input.linkFrom] : undefined,
70
+ ...(input.addedPreset === undefined
71
+ ? {}
72
+ : { addedPreset: input.addedPreset }),
73
+ ...(input.linkFrom === undefined ? {} : { linkFrom: [...input.linkFrom] }),
59
74
  id: generatedScenarioId(input),
60
75
  label: generatedScenarioLabel(input),
61
76
  };
@@ -65,14 +80,16 @@ export function selectGeneratedScenarios(manifest, set) {
65
80
  if (!contract) {
66
81
  throw new Error(`Preset Source ${manifest.name} does not declare a Fixture Matrix Contract`);
67
82
  }
68
- const initScenarios = contract.initSupport.map((support) => scenario(set, { basePreset: support.preset }));
83
+ const initScenarios = contract.initSupport.map((support) => createGeneratedScenario(set, { basePreset: support.preset }));
69
84
  if (set === "init") {
70
85
  return { runnable: initScenarios, skipped: [] };
71
86
  }
72
- const matrixScenarios = contract.supportedCombinations.map((combination) => scenario(set, {
87
+ const matrixScenarios = contract.supportedCombinations.map((combination) => createGeneratedScenario(set, {
73
88
  basePreset: combination.basePreset,
74
89
  addedPreset: combination.addedPreset,
75
- linkFrom: combination.linkFrom,
90
+ ...(combination.linkFrom === undefined
91
+ ? {}
92
+ : { linkFrom: combination.linkFrom }),
76
93
  }));
77
94
  const skipped = contract.semanticSkips.map((skip) => ({
78
95
  set,
@@ -99,7 +116,7 @@ export async function defaultGeneratedScenarioCommandRunner(command, args, cwd,
99
116
  console.log(`${prefix}$ ${[command, ...args].join(" ")}`);
100
117
  await execa(command, [...args], {
101
118
  cwd,
102
- env: options.env,
119
+ ...(options.env === undefined ? {} : { env: options.env }),
103
120
  stdio: "inherit",
104
121
  });
105
122
  }
@@ -115,7 +132,7 @@ async function generateScenario(scenario, workspace, options) {
115
132
  scenario.basePreset,
116
133
  "--yes",
117
134
  ], options.repoRoot, {
118
- env: options.deterministicToolchainEnv,
135
+ env: cliSourceExecutionEnv(options, options.deterministicToolchainEnv),
119
136
  logPrefix: scenario.label,
120
137
  });
121
138
  return projectDir;
@@ -137,7 +154,10 @@ async function applyPackageAddition(manifest, scenario, projectDir, options) {
137
154
  "--name",
138
155
  packageLeafName,
139
156
  ...linkFromArgs(scenario.linkFrom ?? []),
140
- ], projectDir, { logPrefix: scenario.label });
157
+ ], projectDir, {
158
+ env: cliSourceExecutionEnv(options),
159
+ logPrefix: scenario.label,
160
+ });
141
161
  await assertLinkedConsumerSourcesUnchanged(projectDir, beforeConsumerSources);
142
162
  return readAddedPackagePath(projectDir, packageLeafName);
143
163
  }
@@ -154,7 +174,7 @@ async function linkedConsumerSourceSnapshots(projectDir, packagePaths) {
154
174
  async function sourceFileSnapshot(sourceDir, currentDir = sourceDir) {
155
175
  const snapshot = {};
156
176
  const entries = await readdir(currentDir, { withFileTypes: true });
157
- for (const entry of entries.sort((left, right) => left.name.localeCompare(right.name))) {
177
+ for (const entry of entries.toSorted((left, right) => left.name.localeCompare(right.name))) {
158
178
  const entryPath = path.join(currentDir, entry.name);
159
179
  if (entry.isDirectory()) {
160
180
  Object.assign(snapshot, await sourceFileSnapshot(sourceDir, entryPath));
@@ -175,8 +195,14 @@ async function assertLinkedConsumerSourcesUnchanged(projectDir, beforeSnapshots)
175
195
  }
176
196
  }
177
197
  async function readAddedPackagePath(projectDir, packageLeafName) {
178
- const blueprint = JSON.parse(await readFile(path.join(projectDir, ".template", "blueprint.json"), "utf8"));
179
- const packageDefinition = blueprint.packages?.find((pkg) => path.basename(pkg.path) === packageLeafName);
198
+ const input = JSON.parse(await readFile(path.join(projectDir, ".template", "blueprint.json"), "utf8"));
199
+ const result = v.safeParse(storedBlueprintSchema, input);
200
+ if (!result.success) {
201
+ throw new Error(`Generated Repository blueprint is invalid: ${result.issues
202
+ .map((issue) => issue.message)
203
+ .join("; ")}`);
204
+ }
205
+ const packageDefinition = result.output.packages?.find((pkg) => path.basename(pkg.path) === packageLeafName);
180
206
  if (!packageDefinition) {
181
207
  throw new Error(`Package Addition fixture did not record package leaf ${packageLeafName}`);
182
208
  }
@@ -189,10 +215,11 @@ function projectionPlanForPreset(presetName, projectDir, manifest, options, pack
189
215
  }
190
216
  const blueprint = blueprintForPresetSourcePreset(preset, {
191
217
  targetDir: projectDir,
192
- scope: packageScope,
218
+ ...(packageScope === undefined ? {} : { scope: packageScope }),
193
219
  });
194
220
  return projectPresetSourcePreset({
195
221
  preset,
222
+ sourceRoots: options.projectionSourceRoots,
196
223
  context: assembleGenerationContext({
197
224
  targetDir: projectDir,
198
225
  blueprint,
@@ -238,6 +265,9 @@ function addedPresetEnvironmentNeeds(manifest, scenario, projectDir, addedPackag
238
265
  function environmentNeedStep(need, projectDir) {
239
266
  const display = renderPlaywrightBrowserInstallCommand(need);
240
267
  const [command, ...args] = display.split(" ");
268
+ if (command === undefined) {
269
+ throw new Error(`Cannot parse environment setup command: ${display}`);
270
+ }
241
271
  return {
242
272
  id: `install-${need.owner.path}-playwright-browsers`,
243
273
  command,
@@ -272,7 +302,7 @@ async function runGeneratedScenarioQualityGate(manifest, scenario, projectDir, a
272
302
  const env = step.id === "run-root-check" ? { CI: "1" } : undefined;
273
303
  const runStep = async () => {
274
304
  await options.runCommand(step.command, [...step.args], step.cwd, {
275
- env,
305
+ ...(env === undefined ? {} : { env }),
276
306
  logPrefix: scenario.label,
277
307
  });
278
308
  };
@@ -312,6 +342,7 @@ function normalizeRunnerOptions(options) {
312
342
  return {
313
343
  repoRoot: options.repoRoot,
314
344
  cliPath: options.cliPath,
345
+ projectionSourceRoots: options.projectionSourceRoots,
315
346
  runCommand: options.runCommand ?? defaultGeneratedScenarioCommandRunner,
316
347
  reporter: options.reporter ?? {
317
348
  info: console.log,
@@ -6,9 +6,14 @@ export function assembleGenerationContext(options) {
6
6
  value: path.basename(path.resolve(options.targetDir)),
7
7
  },
8
8
  preset: options.blueprint.preset,
9
- packageManager: options.blueprint.packageManager
10
- ? { kind: "PackageManager", value: options.blueprint.packageManager }
11
- : undefined,
9
+ ...(options.blueprint.packageManager
10
+ ? {
11
+ packageManager: {
12
+ kind: "PackageManager",
13
+ value: options.blueprint.packageManager,
14
+ },
15
+ }
16
+ : {}),
12
17
  blueprint: options.blueprint,
13
18
  toolchain: options.toolchain,
14
19
  };
@@ -73,6 +73,9 @@ function checkEnvironmentInstructions(plan) {
73
73
  return plan.checkPlan.environmentNeeds.map((need) => {
74
74
  const display = renderPlaywrightBrowserInstallCommand(need);
75
75
  const [command, ...args] = display.split(" ");
76
+ if (command === undefined) {
77
+ throw new Error(`Cannot parse environment setup command: ${display}`);
78
+ }
76
79
  return {
77
80
  id: need.owner.path === "apps/web"
78
81
  ? "install-web-playwright-browsers"
@@ -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 | undefined;
8
+ linkFrom?: readonly string[] | undefined;
9
+ presetSourceManifest: PresetSourceManifest;
10
+ projectionSourceRoots: PresetProjectionSourceRoots;
11
+ };
12
+ export declare function addPackage(options: AddPackageOptions): Promise<void>;
@@ -4,13 +4,13 @@ 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) {
11
11
  const firstPackage = blueprint.packages?.[0];
12
12
  const match = firstPackage?.name.match(/^@([^/]+)\//);
13
- if (match) {
13
+ if (match?.[1]) {
14
14
  return match[1];
15
15
  }
16
16
  if (/^[a-z0-9][a-z0-9._-]*$/.test(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
  }
@@ -314,9 +314,17 @@ async function packageManifestsForTaskGraph(options) {
314
314
  for (const packageDefinition of options.blueprint.packages ?? []) {
315
315
  const manifestOverride = options.manifestOverrides?.get(packageDefinition.path);
316
316
  const manifestFromOperations = generatedPackageManifestFromOperations(options.operations, packageDefinition.path);
317
- manifests.push(manifestOverride ??
318
- manifestFromOperations ??
319
- (await readJson(path.join(options.root, packageDefinition.path, "package.json"))));
317
+ if (manifestOverride !== undefined) {
318
+ manifests.push(manifestOverride);
319
+ continue;
320
+ }
321
+ if (manifestFromOperations !== undefined) {
322
+ manifests.push(manifestFromOperations);
323
+ continue;
324
+ }
325
+ const manifest = await readJson(path.join(options.root, packageDefinition.path, "package.json"));
326
+ assertObjectManifest(manifest, packageDefinition.path);
327
+ manifests.push(manifest);
320
328
  }
321
329
  return manifests;
322
330
  }
@@ -348,7 +356,7 @@ function assertObjectManifest(input, packagePath) {
348
356
  }
349
357
  }
350
358
  function recordSortedByKey(record) {
351
- return Object.fromEntries(Object.entries(record).sort(([left], [right]) => left.localeCompare(right)));
359
+ return Object.fromEntries(Object.entries(record).toSorted(([left], [right]) => left.localeCompare(right)));
352
360
  }
353
361
  async function consumerManifestUpdatesForPackageLinkIntents(options) {
354
362
  const updates = [];
@@ -425,16 +433,21 @@ function rootPackageJsonWithPackageTaskFilters(input, blueprint, packageManifest
425
433
  assertRootPackageJson(input);
426
434
  const workspacePackageGlobs = workspacePackageGlobsFromBlueprint(blueprint);
427
435
  const taskNames = turboTaskNamesForPackageManifests(packageManifests);
436
+ const checkScript = input.scripts.check;
437
+ const fixScript = input.scripts.fix;
438
+ if (checkScript === undefined || fixScript === undefined) {
439
+ throw new Error("Cannot update root Package Addition scripts: check and fix scripts are required");
440
+ }
428
441
  return {
429
442
  ...input,
430
443
  scripts: {
431
444
  ...input.scripts,
432
445
  check: rootScriptWithTurboPackageTasks({
433
- script: input.scripts.check,
446
+ script: checkScript,
434
447
  taskNames,
435
448
  workspacePackageGlobs,
436
449
  }),
437
- fix: rootScriptWithTurboPackageTask(input.scripts.fix, "fix", workspacePackageGlobs),
450
+ fix: rootScriptWithTurboPackageTask(fixScript, "fix", workspacePackageGlobs),
438
451
  },
439
452
  };
440
453
  }
@@ -483,6 +496,7 @@ function rootPackageJsonWithSharedOxcRuntimeDependencies(input, requiresSharedOx
483
496
  ...input.devDependencies,
484
497
  oxfmt: input.devDependencies?.oxfmt ?? "catalog:",
485
498
  oxlint: input.devDependencies?.oxlint ?? "catalog:",
499
+ "oxlint-tsgolint": input.devDependencies?.["oxlint-tsgolint"] ?? "catalog:",
486
500
  },
487
501
  };
488
502
  }
@@ -491,7 +505,7 @@ function catalogDependenciesWithSharedOxcRuntimeDependencies(catalogDependencies
491
505
  if (!requiresSharedOxcConfiguration) {
492
506
  return dependencies;
493
507
  }
494
- for (const dependency of ["oxfmt", "oxlint"]) {
508
+ for (const dependency of ["oxfmt", "oxlint", "oxlint-tsgolint"]) {
495
509
  if (!dependencies.includes(dependency)) {
496
510
  dependencies.push(dependency);
497
511
  }
@@ -622,18 +636,19 @@ export async function addPackage(options) {
622
636
  const repositoryMetadata = await readGeneratedRepositoryPackageMetadata(root);
623
637
  const projectName = projectNameFromBlueprint(blueprint, repositoryMetadata.projectName);
624
638
  const packageName = `@${projectName}/${options.name}`;
625
- const preset = findBuiltInPresetSourceManifestPreset(options.preset);
639
+ const preset = findPresetSourceManifestPreset(options.presetSourceManifest, options.preset);
626
640
  if (!preset) {
627
641
  throw new Error(`Unknown preset for Package Addition: ${options.preset}`);
628
642
  }
629
643
  if (preset.packageAdditionSupport !== PackageAdditionSupport.Supported) {
630
- throw new Error(formatUnsupportedPackageAdditionPresetError(options.preset));
644
+ throw new Error(formatUnsupportedPackageAdditionPresetError(options.preset, options.presetSourceManifest));
631
645
  }
632
646
  const packagePath = options.path
633
647
  ? validateExplicitPackagePath(options.path)
634
- : defaultPackagePathForPresetSourcePackageAddition(preset, options.name);
648
+ : defaultPackagePathForPresetSourcePackageAddition(preset, options.name, options.projectionSourceRoots);
635
649
  const additionPlan = await planPresetSourcePackageAddition({
636
650
  preset,
651
+ sourceRoots: options.projectionSourceRoots,
637
652
  addition: {
638
653
  root,
639
654
  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,9 +10,11 @@ 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
17
+ oxlint-tsgolint: ^0.24.0
16
18
  pinia: ^3.0.4
17
19
  tailwindcss: ^4.3.2
18
20
  tsc-alias: ^1.8.17
@@ -24,6 +26,7 @@ catalog:
24
26
  vitest: ^4.1.9
25
27
  vue: ^3.5.39
26
28
  vue-tsc: ^3.3.6
29
+ yaml: ^2.9.0
27
30
 
28
31
  allowBuilds:
29
32
  esbuild: true
@@ -20,7 +20,7 @@ export type PresetPackageAdditionPlan = {
20
20
  readonly packageRole: PackageRole;
21
21
  readonly packageSourcePreset: PackageSourcePreset;
22
22
  readonly sourceRoot: string;
23
- readonly sourceRoots?: Record<string, string>;
23
+ readonly sourceRoots?: Record<string, string> | undefined;
24
24
  readonly operations: readonly RenderOperation[];
25
25
  readonly textFiles?: readonly {
26
26
  readonly path: string;
@@ -32,7 +32,7 @@ export type PresetPackageAdditionCapability = {
32
32
  };
33
33
  export type PresetProjectionPlan = {
34
34
  readonly sourceRoot: string;
35
- readonly sourceRoots?: Record<string, string>;
35
+ readonly sourceRoots?: Record<string, string> | undefined;
36
36
  readonly operations: readonly RenderOperation[];
37
37
  readonly checkPlan: CheckPlan;
38
38
  readonly fixPlan: FixPlan;
@@ -48,7 +48,7 @@ export type PresetProjectionPlan = {
48
48
  };
49
49
  export type PresetBlueprintOptions = {
50
50
  readonly targetDir: string;
51
- readonly scope?: string;
51
+ readonly scope?: string | undefined;
52
52
  };
53
53
  export type RenderPresetProjectionOptions = {
54
54
  readonly targetDir: string;
@@ -1,3 +1,4 @@
1
+ import {} from "./module-graph.js";
1
2
  import { planNextStepInstructions, } from "./next-step-instructions.js";
2
3
  export function planNextStepInstructionsForProjection(options) {
3
4
  return planNextStepInstructions({
@@ -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
  }
@@ -799,6 +797,64 @@ function supportedProjectionDeclarationIssues(presets) {
799
797
  ]
800
798
  : []);
801
799
  }
800
+ function normalizePresetSourceManifestOutput(manifest) {
801
+ return {
802
+ schemaVersion: manifest.schemaVersion,
803
+ name: manifest.name,
804
+ sharedResources: manifest.sharedResources.map((resource) => ({
805
+ ...resource,
806
+ })),
807
+ ...(manifest.fixtureMatrix
808
+ ? {
809
+ fixtureMatrix: {
810
+ initSupport: manifest.fixtureMatrix.initSupport.map((support) => ({
811
+ ...support,
812
+ })),
813
+ packageAdditionSupport: manifest.fixtureMatrix.packageAdditionSupport.map((support) => ({
814
+ ...support,
815
+ })),
816
+ supportedCombinations: manifest.fixtureMatrix.supportedCombinations.map((combination) => ({
817
+ basePreset: combination.basePreset,
818
+ addedPreset: combination.addedPreset,
819
+ linkFrom: [...combination.linkFrom],
820
+ })),
821
+ semanticSkips: manifest.fixtureMatrix.semanticSkips.map((skip) => ({
822
+ ...skip,
823
+ })),
824
+ checkRequirements: [...manifest.fixtureMatrix.checkRequirements],
825
+ environmentPreparation: [
826
+ ...manifest.fixtureMatrix.environmentPreparation,
827
+ ],
828
+ },
829
+ }
830
+ : {}),
831
+ presets: manifest.presets.map((preset) => ({
832
+ name: preset.name,
833
+ title: preset.title,
834
+ description: preset.description,
835
+ generation: preset.generation,
836
+ packageAdditionSupport: preset.packageAdditionSupport,
837
+ supportedPackageManagers: [...preset.supportedPackageManagers],
838
+ supportedProjectKinds: [...preset.supportedProjectKinds],
839
+ features: [...preset.features],
840
+ dependencyCatalog: [...preset.dependencyCatalog],
841
+ ...(preset.projection
842
+ ? {
843
+ projection: normalizePresetProjectionDeclaration(preset.projection),
844
+ }
845
+ : {}),
846
+ ...(preset.source
847
+ ? {
848
+ source: {
849
+ roots: [...preset.source.roots],
850
+ files: [...preset.source.files],
851
+ sharedResources: [...preset.source.sharedResources],
852
+ },
853
+ }
854
+ : {}),
855
+ })),
856
+ };
857
+ }
802
858
  export function validatePresetSourceManifest(input, options = {}) {
803
859
  const inlineDependencyIssues = inlineDependencyCatalogSpecifierIssues(input);
804
860
  if (inlineDependencyIssues.length > 0) {
@@ -825,50 +881,7 @@ export function validatePresetSourceManifest(input, options = {}) {
825
881
  }
826
882
  return {
827
883
  ok: true,
828
- value: {
829
- ...result.output,
830
- sharedResources: result.output.sharedResources.map((resource) => ({
831
- ...resource,
832
- })),
833
- fixtureMatrix: result.output.fixtureMatrix
834
- ? {
835
- initSupport: result.output.fixtureMatrix.initSupport.map((support) => ({ ...support })),
836
- packageAdditionSupport: result.output.fixtureMatrix.packageAdditionSupport.map((support) => ({ ...support })),
837
- supportedCombinations: result.output.fixtureMatrix.supportedCombinations.map((combination) => ({
838
- ...combination,
839
- linkFrom: [...(combination.linkFrom ?? [])],
840
- })),
841
- semanticSkips: result.output.fixtureMatrix.semanticSkips.map((skip) => ({ ...skip })),
842
- checkRequirements: [
843
- ...result.output.fixtureMatrix.checkRequirements,
844
- ],
845
- environmentPreparation: [
846
- ...result.output.fixtureMatrix.environmentPreparation,
847
- ],
848
- }
849
- : undefined,
850
- presets: parsedManifest.presets.map((preset) => ({
851
- ...preset,
852
- supportedPackageManagers: [
853
- ...preset.supportedPackageManagers,
854
- ],
855
- supportedProjectKinds: [
856
- ...preset.supportedProjectKinds,
857
- ],
858
- features: [...preset.features],
859
- dependencyCatalog: [...(preset.dependencyCatalog ?? [])],
860
- projection: preset.projection
861
- ? normalizePresetProjectionDeclaration(preset.projection)
862
- : undefined,
863
- source: preset.source
864
- ? {
865
- roots: [...preset.source.roots],
866
- files: [...preset.source.files],
867
- sharedResources: [...preset.source.sharedResources],
868
- }
869
- : undefined,
870
- })),
871
- },
884
+ value: normalizePresetSourceManifestOutput(parsedManifest),
872
885
  };
873
886
  }
874
887
  export function validateBuiltInPresetSourceManifest(input, options = {}) {
@@ -910,7 +923,7 @@ export function manifestReferencedSourceFiles(manifest, sourceRoot) {
910
923
  addReference(file);
911
924
  }
912
925
  }
913
- return [...files].sort();
926
+ return [...files].toSorted();
914
927
  }
915
928
  export function loadPresetSourceManifestFile(filePath) {
916
929
  const result = validatePresetSourceManifest(JSON.parse(readFileSync(filePath, "utf8")), { sourceRoot: path.dirname(filePath) });
@@ -921,20 +934,6 @@ export function loadPresetSourceManifestFile(filePath) {
921
934
  }
922
935
  return result.value;
923
936
  }
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
937
  export function findPresetSourceManifestPreset(manifest, presetName) {
936
938
  return manifest.presets.find((preset) => preset.name === presetName);
937
939
  }
938
- export function findBuiltInPresetSourceManifestPreset(presetName) {
939
- return findPresetSourceManifestPreset(loadBuiltInPresetSourceManifest(), presetName);
940
- }
@@ -21,9 +21,9 @@ export type DependencyMaintenancePolicy = {
21
21
  };
22
22
  type ProjectCheckWorkflowOptions = {
23
23
  readonly checkPlan: CheckPlan;
24
- readonly capability?: CiCapability;
25
- readonly environmentPreparation?: Partial<CiEnvironmentPreparation>;
26
- readonly taskLayer?: PnpmTaskLayer;
24
+ readonly capability?: CiCapability | undefined;
25
+ readonly environmentPreparation?: Partial<CiEnvironmentPreparation> | undefined;
26
+ readonly taskLayer?: PnpmTaskLayer | undefined;
27
27
  };
28
28
  export declare function projectCheckWorkflow(options: ProjectCheckWorkflowOptions): string;
29
29
  export declare function projectDependabotConfig(policy: DependencyMaintenancePolicy): string;
@@ -1,3 +1,4 @@
1
+ import {} from "./module-graph.js";
1
2
  const defaultCiCapability = {
2
3
  workflowName: "Check",
3
4
  jobName: "check",