@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
@@ -18,6 +18,10 @@
18
18
  "id": "shared-oxc-format",
19
19
  "path": "shared/oxc/oxfmt.config.ts"
20
20
  },
21
+ {
22
+ "id": "shared-oxc-root-tsconfig",
23
+ "path": "shared/oxc/tsconfig.config.json"
24
+ },
21
25
  {
22
26
  "id": "shared-oxc-vue",
23
27
  "path": "shared/oxc/vue"
@@ -145,6 +149,7 @@
145
149
  "@types/node",
146
150
  "oxfmt",
147
151
  "oxlint",
152
+ "oxlint-tsgolint",
148
153
  "turbo",
149
154
  "typescript",
150
155
  "valibot"
@@ -170,7 +175,8 @@
170
175
  "shared-devcontainer",
171
176
  "shared-editor-customization",
172
177
  "shared-oxc-node",
173
- "shared-oxc-format"
178
+ "shared-oxc-format",
179
+ "shared-oxc-root-tsconfig"
174
180
  ]
175
181
  }
176
182
  },
@@ -198,6 +204,7 @@
198
204
  "hono",
199
205
  "oxfmt",
200
206
  "oxlint",
207
+ "oxlint-tsgolint",
201
208
  "tsc-alias",
202
209
  "turbo",
203
210
  "typescript",
@@ -234,7 +241,8 @@
234
241
  "shared-devcontainer",
235
242
  "shared-editor-customization",
236
243
  "shared-oxc-node",
237
- "shared-oxc-format"
244
+ "shared-oxc-format",
245
+ "shared-oxc-root-tsconfig"
238
246
  ]
239
247
  }
240
248
  },
@@ -266,6 +274,7 @@
266
274
  "@vueuse/core",
267
275
  "oxfmt",
268
276
  "oxlint",
277
+ "oxlint-tsgolint",
269
278
  "pinia",
270
279
  "tailwindcss",
271
280
  "turbo",
@@ -320,6 +329,7 @@
320
329
  "shared-devcontainer",
321
330
  "shared-editor-customization",
322
331
  "shared-oxc-format",
332
+ "shared-oxc-root-tsconfig",
323
333
  "shared-oxc-vue"
324
334
  ]
325
335
  }
@@ -354,6 +364,7 @@
354
364
  "hono",
355
365
  "oxfmt",
356
366
  "oxlint",
367
+ "oxlint-tsgolint",
357
368
  "pinia",
358
369
  "tailwindcss",
359
370
  "tsc-alias",
@@ -435,6 +446,7 @@
435
446
  "shared-editor-customization",
436
447
  "shared-oxc-node",
437
448
  "shared-oxc-format",
449
+ "shared-oxc-root-tsconfig",
438
450
  "shared-oxc-vue"
439
451
  ]
440
452
  }
@@ -0,0 +1,34 @@
1
+ import { defineConfig } from "oxlint";
2
+
3
+ export default defineConfig({
4
+ options: {
5
+ typeAware: true,
6
+ },
7
+ categories: {
8
+ correctness: "error",
9
+ suspicious: "warn",
10
+ },
11
+ plugins: [
12
+ "eslint",
13
+ "typescript",
14
+ "unicorn",
15
+ "oxc",
16
+ "node",
17
+ "import",
18
+ "vitest",
19
+ "promise",
20
+ ],
21
+ rules: {
22
+ "typescript/consistent-return": "off",
23
+ "typescript/no-misused-promises": "error",
24
+ "typescript/no-unsafe-argument": "warn",
25
+ "typescript/no-unsafe-assignment": "warn",
26
+ "typescript/no-unsafe-call": "warn",
27
+ "typescript/no-unsafe-member-access": "warn",
28
+ "typescript/no-unsafe-return": "warn",
29
+ "typescript/switch-exhaustiveness-check": "error",
30
+ "vitest/expect-expect": "off",
31
+ "vitest/no-conditional-expect": "off",
32
+ "vitest/require-to-throw-message": "off",
33
+ },
34
+ });
@@ -0,0 +1,20 @@
1
+ {
2
+ "compilerOptions": {
3
+ "erasableSyntaxOnly": true,
4
+ "exactOptionalPropertyTypes": true,
5
+ "forceConsistentCasingInFileNames": true,
6
+ "isolatedModules": true,
7
+ "module": "nodenext",
8
+ "moduleResolution": "nodenext",
9
+ "noEmitOnError": true,
10
+ "noFallthroughCasesInSwitch": true,
11
+ "noImplicitOverride": true,
12
+ "noImplicitReturns": true,
13
+ "noUncheckedIndexedAccess": true,
14
+ "skipLibCheck": false,
15
+ "strict": true,
16
+ "target": "es2023",
17
+ "verbatimModuleSyntax": true
18
+ },
19
+ "include": ["oxlint.config.ts", "oxfmt.config.ts"]
20
+ }
@@ -0,0 +1,36 @@
1
+ import { defineConfig } from "oxlint";
2
+
3
+ export default defineConfig({
4
+ options: {
5
+ typeAware: true,
6
+ },
7
+ categories: {
8
+ correctness: "error",
9
+ suspicious: "warn",
10
+ },
11
+ plugins: [
12
+ "eslint",
13
+ "typescript",
14
+ "unicorn",
15
+ "oxc",
16
+ "node",
17
+ "import",
18
+ "vitest",
19
+ "promise",
20
+ "vue",
21
+ ],
22
+ rules: {
23
+ "typescript/consistent-return": "off",
24
+ "import/no-unassigned-import": ["warn", { allow: ["**/*.css"] }],
25
+ "typescript/no-misused-promises": "error",
26
+ "typescript/no-unsafe-argument": "warn",
27
+ "typescript/no-unsafe-assignment": "warn",
28
+ "typescript/no-unsafe-call": "warn",
29
+ "typescript/no-unsafe-member-access": "warn",
30
+ "typescript/no-unsafe-return": "warn",
31
+ "typescript/switch-exhaustiveness-check": "error",
32
+ "vitest/expect-expect": "off",
33
+ "vitest/no-conditional-expect": "off",
34
+ "vitest/require-to-throw-message": "off",
35
+ },
36
+ });
@@ -0,0 +1,8 @@
1
+ /// <reference types="vite/client" />
2
+
3
+ declare module "*.vue" {
4
+ import type { DefineComponent } from "vue";
5
+
6
+ const component: DefineComponent<object, object, unknown>;
7
+ export default component;
8
+ }
@@ -0,0 +1,16 @@
1
+ /// <reference types="vite/client" />
2
+
3
+ declare module "*.vue" {
4
+ import type { DefineComponent } from "vue";
5
+
6
+ const component: DefineComponent<object, object, unknown>;
7
+ export default component;
8
+ }
9
+
10
+ interface ImportMetaEnv {
11
+ readonly VITE_API_BASE_URL?: string;
12
+ }
13
+
14
+ interface ImportMeta {
15
+ readonly env: ImportMetaEnv;
16
+ }
@@ -38,7 +38,6 @@ export type ProjectBlueprint = {
38
38
  packages?: ProjectPackage[];
39
39
  packageLinkIntents?: PackageLinkIntent[];
40
40
  };
41
- export declare const builtInPresets: readonly BuiltInPreset[];
42
41
  export declare const presetFileJsonSchema: {
43
42
  readonly $schema: "https://json-schema.org/draft/2020-12/schema";
44
43
  readonly $id: "https://ykdz.dev/schemas/project-kit/preset-file.schema.json";
@@ -195,6 +194,10 @@ export type ValidationResult<T> = {
195
194
  ok: false;
196
195
  issues: ValidationIssue[];
197
196
  };
198
- export declare function validatePresetFile(input: unknown): ValidationResult<PresetFile>;
199
- export declare function findBuiltInPreset(name: string): BuiltInPreset | undefined;
200
- export declare function validateProjectBlueprint(input: unknown): ValidationResult<ProjectBlueprint>;
197
+ export type PresetCatalogValidationOptions = {
198
+ readonly presets?: readonly BuiltInPreset[];
199
+ readonly presetLabel?: string;
200
+ };
201
+ export declare function validatePresetFile(input: unknown, options?: PresetCatalogValidationOptions): ValidationResult<PresetFile>;
202
+ export declare function findPreset(presets: readonly BuiltInPreset[], name: string): BuiltInPreset | undefined;
203
+ export declare function validateProjectBlueprint(input: unknown, options?: PresetCatalogValidationOptions): ValidationResult<ProjectBlueprint>;
@@ -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,62 @@ 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
+ function normalizeProjectBlueprint(blueprint) {
210
+ return {
211
+ schemaVersion: blueprint.schemaVersion,
212
+ preset: blueprint.preset,
213
+ ...(blueprint.packageManager === undefined
214
+ ? {}
215
+ : { packageManager: blueprint.packageManager }),
216
+ projectKind: blueprint.projectKind,
217
+ features: [...blueprint.features],
218
+ ...(blueprint.packages === undefined
219
+ ? {}
220
+ : {
221
+ packages: blueprint.packages.map((projectPackage) => ({
222
+ name: projectPackage.name,
223
+ path: projectPackage.path,
224
+ ...(projectPackage.role === undefined
225
+ ? {}
226
+ : { role: projectPackage.role }),
227
+ ...(projectPackage.sourcePreset === undefined
228
+ ? {}
229
+ : { sourcePreset: projectPackage.sourcePreset }),
230
+ })),
231
+ }),
232
+ ...(blueprint.packageLinkIntents === undefined
233
+ ? {}
234
+ : {
235
+ packageLinkIntents: blueprint.packageLinkIntents.map((intent) => ({
236
+ consumerPackagePath: intent.consumerPackagePath,
237
+ providerPackagePath: intent.providerPackagePath,
238
+ })),
239
+ }),
240
+ };
241
+ }
242
+ export function validateProjectBlueprint(input, options = {}) {
212
243
  const result = v.safeParse(projectBlueprintSchema, input);
213
244
  if (!result.success) {
214
245
  return { ok: false, issues: shapeIssues(result.issues) };
215
246
  }
216
- const blueprint = result.output;
217
- const preset = findBuiltInPreset(blueprint.preset);
247
+ const blueprint = normalizeProjectBlueprint(result.output);
248
+ const preset = findPreset(options.presets ?? [], blueprint.preset);
218
249
  const semanticIssues = [
219
250
  ...duplicateIssues(blueprint.features, "$.features"),
220
251
  ];
221
252
  if (blueprint.projectKind === "single-package") {
222
253
  semanticIssues.push(unsupportedSinglePackageProjectShapeIssue("$.projectKind"));
223
254
  }
224
- if (!preset) {
255
+ if (options.presets && !preset) {
225
256
  semanticIssues.push({
226
257
  path: "$.preset",
227
- message: `Unknown built-in preset: ${blueprint.preset}`,
258
+ message: `Unknown ${options.presetLabel ?? "built-in"} preset: ${blueprint.preset}`,
228
259
  });
229
260
  }
230
- else {
261
+ else if (preset) {
231
262
  const unsupportedGeneration = generationSupportIssue(preset, "$.preset");
232
263
  if (unsupportedGeneration) {
233
264
  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
  }
@@ -24,7 +26,12 @@ function parseTemplateDependencyCatalog(workspaceYaml) {
24
26
  if (!match) {
25
27
  continue;
26
28
  }
27
- catalog[match[1] ?? match[2]] = match[3];
29
+ const key = match[1] ?? match[2];
30
+ const version = match[3];
31
+ if (key === undefined || version === undefined) {
32
+ continue;
33
+ }
34
+ catalog[key] = version;
28
35
  }
29
36
  return catalog;
30
37
  }
@@ -33,7 +40,7 @@ export function loadTemplateDependencyCatalog() {
33
40
  }
34
41
  export function selectTemplateDependencyCatalogEntries(dependencies, catalog = loadTemplateDependencyCatalog()) {
35
42
  const selected = {};
36
- for (const dependency of [...dependencies].sort()) {
43
+ for (const dependency of dependencies.toSorted()) {
37
44
  const version = catalog[dependency];
38
45
  if (version === undefined) {
39
46
  throw new Error(`Template Dependency Catalog is missing dependency: ${dependency}`);
@@ -59,7 +66,7 @@ export function collectGeneratedManifestCatalogDependencies(manifests) {
59
66
  }
60
67
  }
61
68
  }
62
- return [...dependencies].sort();
69
+ return [...dependencies].toSorted();
63
70
  }
64
71
  export function collectGeneratedManifestCatalogReferences(manifests) {
65
72
  const dependencies = new Set();
@@ -77,7 +84,7 @@ export function collectGeneratedManifestCatalogReferences(manifests) {
77
84
  }
78
85
  }
79
86
  }
80
- return [...dependencies].sort();
87
+ return [...dependencies].toSorted();
81
88
  }
82
89
  function renderCatalogKey(key) {
83
90
  return key.startsWith("@") ? JSON.stringify(key) : key;
@@ -104,7 +111,7 @@ export function pnpmWorkspaceYamlWithCatalogDependencies(workspaceYaml, dependen
104
111
  const catalogLines = [
105
112
  "catalog:",
106
113
  ...Object.entries(nextCatalog)
107
- .sort(([left], [right]) => left.localeCompare(right))
114
+ .toSorted(([left], [right]) => left.localeCompare(right))
108
115
  .map(([dependency, version]) => ` ${renderCatalogKey(dependency)}: ${version}`),
109
116
  "",
110
117
  ];
@@ -124,7 +131,7 @@ export function renderGeneratedPnpmWorkspaceYaml(options) {
124
131
  ];
125
132
  if (options.allowBuilds) {
126
133
  lines.push("allowBuilds:", ...Object.entries(options.allowBuilds)
127
- .sort(([left], [right]) => left.localeCompare(right))
134
+ .toSorted(([left], [right]) => left.localeCompare(right))
128
135
  .map(([dependency, allowed]) => ` ${dependency}: ${allowed}`), "");
129
136
  }
130
137
  lines.push("catalog:", ...Object.entries(catalog).map(([dependency, version]) => ` ${renderCatalogKey(dependency)}: ${version}`), "");
@@ -38,21 +38,21 @@ export declare function dockerfileFirstNodePnpmDevcontainer(options: {
38
38
  readonly name: string;
39
39
  readonly layer: DevelopmentContainerNodePnpmLayer;
40
40
  readonly extensions: readonly string[];
41
- readonly settings?: Record<string, unknown>;
41
+ readonly settings?: Record<string, unknown> | undefined;
42
42
  }): DevelopmentContainerPlan;
43
43
  export declare function checkedDockerfileFirstNodePnpmDevcontainer(options: {
44
44
  readonly name: string;
45
45
  readonly layer: DevelopmentContainerNodePnpmLayer;
46
- readonly additionalLayers?: readonly DevelopmentContainerCapabilityLayer[];
46
+ readonly additionalLayers?: readonly DevelopmentContainerCapabilityLayer[] | undefined;
47
47
  readonly extensions: readonly string[];
48
- readonly settings?: Record<string, unknown>;
49
- readonly mounts?: readonly string[];
48
+ readonly settings?: Record<string, unknown> | undefined;
49
+ readonly mounts?: readonly string[] | undefined;
50
50
  }): DevelopmentContainerPlan;
51
51
  export declare function dockerfileFirstRustPnpmDevcontainer(options: {
52
52
  readonly name: string;
53
53
  readonly nodeLayer: DevelopmentContainerNodePnpmLayer;
54
54
  readonly rustLayer: DevelopmentContainerRustLayer;
55
55
  readonly extensions: readonly string[];
56
- readonly settings?: Record<string, unknown>;
56
+ readonly settings?: Record<string, unknown> | undefined;
57
57
  }): DevelopmentContainerPlan;
58
58
  export {};
@@ -1,6 +1,7 @@
1
1
  import { existsSync, readFileSync } from "node:fs";
2
2
  import path from "node:path";
3
3
  import { fileURLToPath } from "node:url";
4
+ import * as v from "valibot";
4
5
  const capabilityOrder = [
5
6
  "oxc-format-lint",
6
7
  "vue",
@@ -12,13 +13,28 @@ const defaultOxcConfigPaths = {
12
13
  formatter: "./oxfmt.config.ts",
13
14
  lint: "./oxlint.config.ts",
14
15
  };
16
+ const capabilityProjectionSchema = v.object({
17
+ extensions: v.array(v.string()),
18
+ settings: v.record(v.string(), v.unknown()),
19
+ });
20
+ const editorCustomizationDeclarationsSchema = v.object({
21
+ capabilities: v.object({
22
+ "oxc-format-lint": capabilityProjectionSchema,
23
+ vue: capabilityProjectionSchema,
24
+ tailwind: capabilityProjectionSchema,
25
+ "rust-tooling": capabilityProjectionSchema,
26
+ vitest: capabilityProjectionSchema,
27
+ }),
28
+ });
15
29
  const declarations = loadEditorCustomizationDeclarations();
16
30
  function editorCustomizationDeclarationPath() {
17
31
  const moduleDirectory = path.dirname(fileURLToPath(import.meta.url));
18
- const relativeDeclarationPath = "templates/shared/editor-customization/capabilities.json";
32
+ const relativeDeclarationPath = "builtin-source/templates/shared/editor-customization/capabilities.json";
19
33
  const candidates = [
20
34
  path.resolve(moduleDirectory, "..", relativeDeclarationPath),
21
35
  path.resolve(moduleDirectory, "..", "..", relativeDeclarationPath),
36
+ path.resolve(moduleDirectory, "..", "..", "template-builtin-source", "templates", "shared", "editor-customization", "capabilities.json"),
37
+ path.resolve(moduleDirectory, "..", "..", "..", "packages", relativeDeclarationPath),
22
38
  ];
23
39
  const declarationPath = candidates.find((candidate) => existsSync(candidate));
24
40
  if (!declarationPath) {
@@ -26,38 +42,15 @@ function editorCustomizationDeclarationPath() {
26
42
  }
27
43
  return declarationPath;
28
44
  }
29
- function isRecord(value) {
30
- return typeof value === "object" && value !== null && !Array.isArray(value);
31
- }
32
- function assertCapabilityProjection(capability, value) {
33
- if (!isRecord(value)) {
34
- throw new Error(`Editor customization ${capability} must be an object`);
35
- }
36
- const extensions = value.extensions;
37
- const settings = value.settings;
38
- if (!Array.isArray(extensions) ||
39
- extensions.some((extension) => typeof extension !== "string")) {
40
- throw new Error(`Editor customization ${capability} must declare string extensions`);
41
- }
42
- if (!isRecord(settings)) {
43
- throw new Error(`Editor customization ${capability} must declare object settings`);
44
- }
45
- }
46
45
  function loadEditorCustomizationDeclarations() {
47
46
  const source = JSON.parse(readFileSync(editorCustomizationDeclarationPath(), "utf8"));
48
- if (!isRecord(source) || !isRecord(source.capabilities)) {
49
- throw new Error("Editor customization declarations must contain capabilities");
47
+ const result = v.safeParse(editorCustomizationDeclarationsSchema, source);
48
+ if (!result.success) {
49
+ throw new Error(`Editor customization declarations are invalid: ${result.issues
50
+ .map((issue) => issue.message)
51
+ .join("; ")}`);
50
52
  }
51
- const capabilities = source.capabilities;
52
- for (const capability of capabilityOrder) {
53
- assertCapabilityProjection(capability, capabilities[capability]);
54
- }
55
- return {
56
- capabilities: Object.fromEntries(capabilityOrder.map((capability) => [
57
- capability,
58
- capabilities[capability],
59
- ])),
60
- };
53
+ return result.output;
61
54
  }
62
55
  function oxcConfigPathSettings(configPaths) {
63
56
  if (configPaths === "nested") {
@@ -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;
@@ -28,8 +29,8 @@ export type GeneratedScenarioCommandStep = {
28
29
  readonly display: string;
29
30
  };
30
31
  export type GeneratedScenarioCommandRunner = (command: string, args: readonly string[], cwd: string, options?: {
31
- readonly env?: Record<string, string>;
32
- readonly logPrefix?: string;
32
+ readonly env?: Record<string, string> | undefined;
33
+ readonly logPrefix?: string | undefined;
33
34
  }) => Promise<void>;
34
35
  export type GeneratedScenarioReporter = {
35
36
  readonly info?: (message: string) => void;
@@ -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>;
@@ -52,8 +54,8 @@ export declare function generatedScenarioLabel(scenario: Pick<GeneratedScenario,
52
54
  export declare function selectGeneratedScenarios(manifest: PresetSourceManifest, set: GeneratedScenarioSet): GeneratedScenarioSelection;
53
55
  export declare function packageLeafNameForAddedPreset(manifest: PresetSourceManifest, presetName: string): string;
54
56
  export declare function defaultGeneratedScenarioCommandRunner(command: string, args: readonly string[], cwd: string, options?: {
55
- readonly env?: Record<string, string>;
56
- readonly logPrefix?: string;
57
+ readonly env?: Record<string, string> | undefined;
58
+ readonly logPrefix?: string | undefined;
57
59
  }): Promise<void>;
58
60
  export declare function generatedScenarioQualityGateSteps(manifest: PresetSourceManifest, scenario: GeneratedScenario, projectDir: string, addedPackagePath: string | undefined, options: GeneratedScenarioRunnerOptions): GeneratedScenarioCommandStep[];
59
61
  export declare function fixtureConcurrency(scenarioCount: number): number;