@ykdz/template 0.0.8 → 0.0.10

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 (43) hide show
  1. package/dist/cli.js +7 -7
  2. package/node_modules/@ykdz/template-builtin-source/dist/src/index.js +10 -6
  3. package/node_modules/@ykdz/template-builtin-source/dist/templates/hono-api/projection.js +15 -5
  4. package/node_modules/@ykdz/template-builtin-source/dist/templates/ts-lib/projection.js +15 -5
  5. package/node_modules/@ykdz/template-builtin-source/dist/templates/vue-app/projection.js +31 -7
  6. package/node_modules/@ykdz/template-builtin-source/dist/templates/vue-hono-app/projection.js +7 -8
  7. package/node_modules/@ykdz/template-builtin-source/package.json +15 -2
  8. package/node_modules/@ykdz/template-builtin-source/templates/preset-source.json +18 -4
  9. package/node_modules/@ykdz/template-builtin-source/templates/shared/oxc/node/oxlint.config.ts +25 -3
  10. package/node_modules/@ykdz/template-builtin-source/templates/shared/oxc/tsconfig.config.json +20 -0
  11. package/node_modules/@ykdz/template-builtin-source/templates/shared/oxc/vue/oxlint.config.ts +27 -3
  12. package/node_modules/@ykdz/template-builtin-source/templates/vue-app/env.d.ts +7 -0
  13. package/node_modules/@ykdz/template-builtin-source/templates/vue-app/scripts/run-playwright.ts +25 -0
  14. package/node_modules/@ykdz/template-builtin-source/templates/vue-app/src/App.vue +18 -4
  15. package/node_modules/@ykdz/template-builtin-source/templates/vue-hono-app/web/env.d.ts +7 -0
  16. package/node_modules/@ykdz/template-builtin-source/templates/vue-hono-app/web/scripts/run-playwright.ts +25 -0
  17. package/node_modules/@ykdz/template-builtin-source/templates/vue-hono-app/web/src/App.vue +18 -4
  18. package/node_modules/@ykdz/template-core/dist/declarations.js +34 -1
  19. package/node_modules/@ykdz/template-core/dist/dependency-catalog.js +11 -6
  20. package/node_modules/@ykdz/template-core/dist/devcontainer.d.ts +5 -5
  21. package/node_modules/@ykdz/template-core/dist/editor-customization.js +20 -29
  22. package/node_modules/@ykdz/template-core/dist/generated-scenarios.d.ts +5 -4
  23. package/node_modules/@ykdz/template-core/dist/generated-scenarios.js +38 -10
  24. package/node_modules/@ykdz/template-core/dist/generation-context.js +8 -3
  25. package/node_modules/@ykdz/template-core/dist/next-step-instructions.js +3 -0
  26. package/node_modules/@ykdz/template-core/dist/package-addition.d.ts +2 -2
  27. package/node_modules/@ykdz/template-core/dist/package-addition.js +24 -9
  28. package/node_modules/@ykdz/template-core/dist/pnpm-workspace.yaml +4 -5
  29. package/node_modules/@ykdz/template-core/dist/preset-projection.d.ts +3 -3
  30. package/node_modules/@ykdz/template-core/dist/preset-projection.js +1 -0
  31. package/node_modules/@ykdz/template-core/dist/preset-source.js +60 -45
  32. package/node_modules/@ykdz/template-core/dist/project-github.d.ts +3 -3
  33. package/node_modules/@ykdz/template-core/dist/project-github.js +1 -0
  34. package/node_modules/@ykdz/template-core/dist/projection-capabilities.d.ts +7 -3
  35. package/node_modules/@ykdz/template-core/dist/projection-capabilities.js +196 -130
  36. package/node_modules/@ykdz/template-core/dist/renderer.d.ts +2 -2
  37. package/node_modules/@ykdz/template-core/dist/renderer.js +2 -2
  38. package/node_modules/@ykdz/template-core/dist/template-boundary-check.d.ts +1 -1
  39. package/node_modules/@ykdz/template-core/dist/template-boundary-check.js +8 -10
  40. package/node_modules/@ykdz/template-core/dist/toolchain-resolution.d.ts +5 -5
  41. package/node_modules/@ykdz/template-core/dist/toolchain-resolution.js +10 -11
  42. package/node_modules/@ykdz/template-core/package.json +9 -2
  43. package/package.json +12 -5
@@ -15,6 +15,8 @@ const projectionCapabilityKinds = [
15
15
  "github-maintenance",
16
16
  ];
17
17
  const projectionCapabilityKindSet = new Set(projectionCapabilityKinds);
18
+ const workspaceNodePackageKindSet = new Set(["hono-api", "vue-app"]);
19
+ const workspaceNodePackagePathSet = new Set(["apps/api", "apps/web"]);
18
20
  const strictTypescriptRootBoundary = {
19
21
  kind: "workspace-orchestration",
20
22
  path: ".",
@@ -71,6 +73,24 @@ const exactCapabilityKeys = {
71
73
  "github-maintenance": ["kind"],
72
74
  };
73
75
  const dependencyMaintenanceEcosystems = ["npm", "github-actions", "docker"];
76
+ function strictTypeScriptCompilerOptions(options) {
77
+ return {
78
+ ...options,
79
+ erasableSyntaxOnly: true,
80
+ exactOptionalPropertyTypes: true,
81
+ forceConsistentCasingInFileNames: true,
82
+ isolatedModules: true,
83
+ noEmitOnError: true,
84
+ noFallthroughCasesInSwitch: true,
85
+ noImplicitOverride: true,
86
+ noImplicitReturns: true,
87
+ noUncheckedIndexedAccess: true,
88
+ skipLibCheck: false,
89
+ strict: true,
90
+ target: "es2023",
91
+ verbatimModuleSyntax: true,
92
+ };
93
+ }
74
94
  const capabilityInterpreters = {
75
95
  "workspace-library-package": {
76
96
  kind: "workspace-library-package",
@@ -152,12 +172,6 @@ const capabilityInterpreters = {
152
172
  kind: "turbo-package-test",
153
173
  owner: workspaceBoundary,
154
174
  });
155
- if (hasVuePackage(state.nodeWorkspace)) {
156
- state.rootCheckComponents.push({
157
- kind: "turbo-package-e2e-test",
158
- owner: workspaceBoundary,
159
- });
160
- }
161
175
  }
162
176
  state.rootCheckComponents.push({
163
177
  kind: "turbo-package-check",
@@ -205,21 +219,23 @@ const capabilityInterpreters = {
205
219
  state.rootScriptFragments["format:write"] =
206
220
  "oxfmt --write --config oxfmt.config.ts oxlint.config.ts oxfmt.config.ts";
207
221
  state.rootScriptFragments.lint =
208
- "oxlint --config oxlint.config.ts oxlint.config.ts oxfmt.config.ts --deny-warnings";
222
+ "oxlint --config oxlint.config.ts oxlint.config.ts oxfmt.config.ts";
209
223
  state.rootScriptFragments["lint:fix"] =
210
- "oxlint --config oxlint.config.ts oxlint.config.ts oxfmt.config.ts --fix --deny-warnings";
224
+ "oxlint --config oxlint.config.ts oxlint.config.ts oxfmt.config.ts --fix";
211
225
  state.packageScriptFragments["format:check"] =
212
226
  "oxfmt --check --config ../../oxfmt.config.ts .";
213
227
  state.packageScriptFragments["format:write"] =
214
228
  "oxfmt --write --config ../../oxfmt.config.ts .";
215
229
  state.packageScriptFragments.lint =
216
- "oxlint --config ../../oxlint.config.ts . --deny-warnings";
230
+ "oxlint --config ../../oxlint.config.ts .";
217
231
  state.packageScriptFragments["lint:fix"] =
218
- "oxlint --config ../../oxlint.config.ts . --fix --deny-warnings";
232
+ "oxlint --config ../../oxlint.config.ts . --fix";
219
233
  state.rootDevDependencies.add("oxfmt");
220
234
  state.rootDevDependencies.add("oxlint");
235
+ state.rootDevDependencies.add("oxlint-tsgolint");
221
236
  state.packageDevDependencies.add("oxfmt");
222
237
  state.packageDevDependencies.add("oxlint");
238
+ state.packageDevDependencies.add("oxlint-tsgolint");
223
239
  state.editorCustomizationCapabilities.push("oxc-format-lint");
224
240
  state.flags.fixCommand = true;
225
241
  state.operationFactories.push(oxcFormatLintOperations);
@@ -244,6 +260,52 @@ const capabilityInterpreters = {
244
260
  },
245
261
  },
246
262
  };
263
+ function contributeProjectionCapability(capability, state) {
264
+ switch (capability.kind) {
265
+ case "workspace-library-package":
266
+ capabilityInterpreters["workspace-library-package"].contribute({
267
+ capability,
268
+ state,
269
+ });
270
+ return;
271
+ case "workspace-node-packages":
272
+ capabilityInterpreters["workspace-node-packages"].contribute({
273
+ capability,
274
+ state,
275
+ });
276
+ return;
277
+ case "rust-binary-workspace":
278
+ capabilityInterpreters["rust-binary-workspace"].contribute({
279
+ capability,
280
+ state,
281
+ });
282
+ return;
283
+ case "strict-typescript-root":
284
+ capabilityInterpreters["strict-typescript-root"].contribute({
285
+ capability,
286
+ state,
287
+ });
288
+ return;
289
+ case "oxc-format-lint":
290
+ capabilityInterpreters["oxc-format-lint"].contribute({
291
+ capability,
292
+ state,
293
+ });
294
+ return;
295
+ case "node-pnpm-devcontainer":
296
+ capabilityInterpreters["node-pnpm-devcontainer"].contribute({
297
+ capability,
298
+ state,
299
+ });
300
+ return;
301
+ case "github-maintenance":
302
+ capabilityInterpreters["github-maintenance"].contribute({
303
+ capability,
304
+ state,
305
+ });
306
+ return;
307
+ }
308
+ }
247
309
  export function validateProjectionCapabilities(input) {
248
310
  if (!isRecord(input) || !Array.isArray(input.capabilities)) {
249
311
  return {
@@ -274,7 +336,7 @@ export function validateProjectionCapabilities(input) {
274
336
  });
275
337
  return;
276
338
  }
277
- if (!projectionCapabilityKindSet.has(capability.kind)) {
339
+ if (!isProjectionCapabilityKind(capability.kind)) {
278
340
  issues.push({
279
341
  path: `${pathPrefix}.kind`,
280
342
  message: `Unknown Projection Capability kind: ${capability.kind}`,
@@ -282,7 +344,7 @@ export function validateProjectionCapabilities(input) {
282
344
  return;
283
345
  }
284
346
  const kind = capability.kind;
285
- issues.push(...unknownCapabilityPropertyIssues(capability, pathPrefix));
347
+ issues.push(...unknownCapabilityPropertyIssues(kind, capability, pathPrefix));
286
348
  if (kind === "workspace-library-package") {
287
349
  const workspaceCapability = parseWorkspaceLibraryPackageCapability(capability, pathPrefix);
288
350
  if (Array.isArray(workspaceCapability)) {
@@ -358,10 +420,7 @@ export function interpretPresetProjectionDeclaration(options) {
358
420
  }
359
421
  const state = createProjectionCompositionState(options.sourceRoots);
360
422
  for (const capability of validation.value.capabilities) {
361
- capabilityInterpreters[capability.kind].contribute({
362
- capability: capability,
363
- state,
364
- });
423
+ contributeProjectionCapability(capability, state);
365
424
  }
366
425
  const checkPlan = {
367
426
  components: state.rootCheckComponents,
@@ -405,10 +464,11 @@ export function interpretPresetProjectionDeclaration(options) {
405
464
  export function blueprintForPresetSourcePreset(preset, options = { targetDir: process.cwd() }) {
406
465
  const packageScope = options.scope ?? projectNameFromDir(options.targetDir);
407
466
  const projectName = projectNameFromDir(options.targetDir);
467
+ const packageManager = preset.supportedPackageManagers[0];
408
468
  const blueprint = {
409
469
  schemaVersion: 1,
410
470
  preset: preset.name,
411
- packageManager: preset.supportedPackageManagers[0],
471
+ ...(packageManager === undefined ? {} : { packageManager }),
412
472
  projectKind: preset.supportedProjectKinds[0] ?? "multi-package",
413
473
  features: [...preset.features],
414
474
  };
@@ -502,11 +562,29 @@ function createProjectionCompositionState(sourceRoots) {
502
562
  function isRecord(value) {
503
563
  return typeof value === "object" && value !== null && !Array.isArray(value);
504
564
  }
565
+ function isProjectionCapabilityKind(value) {
566
+ return projectionCapabilityKindSet.has(value);
567
+ }
568
+ function isWorkspaceNodePackageKind(value) {
569
+ return typeof value === "string" && workspaceNodePackageKindSet.has(value);
570
+ }
571
+ function isWorkspaceNodePackagePath(value) {
572
+ return typeof value === "string" && workspaceNodePackagePathSet.has(value);
573
+ }
505
574
  function isNonEmptyString(value) {
506
575
  return typeof value === "string" && value.length > 0;
507
576
  }
508
- function unknownCapabilityPropertyIssues(capability, pathPrefix) {
509
- const kind = capability.kind;
577
+ function nonEmptyStringArray(value) {
578
+ const strings = [];
579
+ for (const entry of value) {
580
+ if (!isNonEmptyString(entry)) {
581
+ return undefined;
582
+ }
583
+ strings.push(entry);
584
+ }
585
+ return strings.length === 0 ? undefined : strings;
586
+ }
587
+ function unknownCapabilityPropertyIssues(kind, capability, pathPrefix) {
510
588
  const allowedKeys = new Set(exactCapabilityKeys[kind]);
511
589
  return Object.keys(capability)
512
590
  .filter((key) => !allowedKeys.has(key))
@@ -517,6 +595,7 @@ function unknownCapabilityPropertyIssues(capability, pathPrefix) {
517
595
  }
518
596
  function parseWorkspaceLibraryPackageCapability(capability, pathPrefix) {
519
597
  const issues = [];
598
+ let sourceFiles = [];
520
599
  if (capability.workspacePackageGlob !== "packages/*") {
521
600
  issues.push({
522
601
  path: `${pathPrefix}.workspacePackageGlob`,
@@ -541,12 +620,17 @@ function parseWorkspaceLibraryPackageCapability(capability, pathPrefix) {
541
620
  message: "workspace-library-package sourceFiles must be a non-empty array",
542
621
  });
543
622
  }
544
- else if (capability.sourceFiles.length === 0 ||
545
- !capability.sourceFiles.every(isNonEmptyString)) {
546
- issues.push({
547
- path: `${pathPrefix}.sourceFiles`,
548
- message: "workspace-library-package sourceFiles must be a non-empty array of paths",
549
- });
623
+ else {
624
+ const parsedSourceFiles = nonEmptyStringArray(capability.sourceFiles);
625
+ if (parsedSourceFiles === undefined) {
626
+ issues.push({
627
+ path: `${pathPrefix}.sourceFiles`,
628
+ message: "workspace-library-package sourceFiles must be a non-empty array of paths",
629
+ });
630
+ }
631
+ else {
632
+ sourceFiles = parsedSourceFiles;
633
+ }
550
634
  }
551
635
  if (issues.length > 0) {
552
636
  return issues;
@@ -556,7 +640,7 @@ function parseWorkspaceLibraryPackageCapability(capability, pathPrefix) {
556
640
  workspacePackageGlob: "packages/*",
557
641
  packageRole: "shared-library",
558
642
  packageSourcePreset: "ts-lib",
559
- sourceFiles: capability.sourceFiles,
643
+ sourceFiles,
560
644
  };
561
645
  }
562
646
  function parseWorkspaceNodePackagesCapability(capability, pathPrefix) {
@@ -607,13 +691,18 @@ function parseWorkspaceNodePackage(value, pathPrefix) {
607
691
  },
608
692
  ];
609
693
  }
610
- if (value.kind !== "hono-api" && value.kind !== "vue-app") {
694
+ const kind = isWorkspaceNodePackageKind(value.kind) ? value.kind : undefined;
695
+ const packagePath = isWorkspaceNodePackagePath(value.path)
696
+ ? value.path
697
+ : undefined;
698
+ let sourceFiles = [];
699
+ if (kind === undefined) {
611
700
  issues.push({
612
701
  path: `${pathPrefix}.kind`,
613
702
  message: "workspace-node-packages package kind must be hono-api or vue-app",
614
703
  });
615
704
  }
616
- if (value.path !== "apps/api" && value.path !== "apps/web") {
705
+ if (packagePath === undefined) {
617
706
  issues.push({
618
707
  path: `${pathPrefix}.path`,
619
708
  message: "workspace-node-packages package path must be apps/api or apps/web",
@@ -625,12 +714,17 @@ function parseWorkspaceNodePackage(value, pathPrefix) {
625
714
  message: "workspace-node-packages package sourceFiles must be a non-empty array",
626
715
  });
627
716
  }
628
- else if (value.sourceFiles.length === 0 ||
629
- !value.sourceFiles.every(isNonEmptyString)) {
630
- issues.push({
631
- path: `${pathPrefix}.sourceFiles`,
632
- message: "workspace-node-packages package sourceFiles must be a non-empty array of paths",
633
- });
717
+ else {
718
+ const parsedSourceFiles = nonEmptyStringArray(value.sourceFiles);
719
+ if (parsedSourceFiles === undefined) {
720
+ issues.push({
721
+ path: `${pathPrefix}.sourceFiles`,
722
+ message: "workspace-node-packages package sourceFiles must be a non-empty array of paths",
723
+ });
724
+ }
725
+ else {
726
+ sourceFiles = parsedSourceFiles;
727
+ }
634
728
  }
635
729
  const allowedKeys = new Set(["kind", "path", "sourceFiles"]);
636
730
  for (const key of Object.keys(value)) {
@@ -644,10 +738,13 @@ function parseWorkspaceNodePackage(value, pathPrefix) {
644
738
  if (issues.length > 0) {
645
739
  return issues;
646
740
  }
741
+ if (kind === undefined || packagePath === undefined) {
742
+ throw new Error(`workspace-node-packages package validation failed without diagnostics at ${pathPrefix}`);
743
+ }
647
744
  return {
648
- kind: value.kind,
649
- path: value.path,
650
- sourceFiles: value.sourceFiles,
745
+ kind,
746
+ path: packagePath,
747
+ sourceFiles,
651
748
  };
652
749
  }
653
750
  function parseWorkspaceNodePackageLinks(value, pathPrefix, declaredPackagePaths, issues) {
@@ -712,6 +809,7 @@ function parseWorkspaceNodePackageLinks(value, pathPrefix, declaredPackagePaths,
712
809
  }
713
810
  function parseRustBinaryWorkspaceCapability(capability, pathPrefix) {
714
811
  const issues = [];
812
+ let sourceFiles = [];
715
813
  if (capability.workspacePackageGlob !== "packages/*") {
716
814
  issues.push({
717
815
  path: `${pathPrefix}.workspacePackageGlob`,
@@ -724,12 +822,17 @@ function parseRustBinaryWorkspaceCapability(capability, pathPrefix) {
724
822
  message: "rust-binary-workspace sourceFiles must be a non-empty array",
725
823
  });
726
824
  }
727
- else if (capability.sourceFiles.length === 0 ||
728
- !capability.sourceFiles.every(isNonEmptyString)) {
729
- issues.push({
730
- path: `${pathPrefix}.sourceFiles`,
731
- message: "rust-binary-workspace sourceFiles must be a non-empty array of paths",
732
- });
825
+ else {
826
+ const parsedSourceFiles = nonEmptyStringArray(capability.sourceFiles);
827
+ if (parsedSourceFiles === undefined) {
828
+ issues.push({
829
+ path: `${pathPrefix}.sourceFiles`,
830
+ message: "rust-binary-workspace sourceFiles must be a non-empty array of paths",
831
+ });
832
+ }
833
+ else {
834
+ sourceFiles = parsedSourceFiles;
835
+ }
733
836
  }
734
837
  if (issues.length > 0) {
735
838
  return issues;
@@ -737,7 +840,7 @@ function parseRustBinaryWorkspaceCapability(capability, pathPrefix) {
737
840
  return {
738
841
  kind: "rust-binary-workspace",
739
842
  workspacePackageGlob: "packages/*",
740
- sourceFiles: capability.sourceFiles,
843
+ sourceFiles,
741
844
  };
742
845
  }
743
846
  function duplicateCapabilityIssues(capabilities) {
@@ -848,10 +951,7 @@ function stateForProjectionDeclaration(declaration, sourceRoots) {
848
951
  }
849
952
  const state = createProjectionCompositionState(sourceRoots);
850
953
  for (const capability of validation.value.capabilities) {
851
- capabilityInterpreters[capability.kind].contribute({
852
- capability: capability,
853
- state,
854
- });
954
+ contributeProjectionCapability(capability, state);
855
955
  }
856
956
  return state;
857
957
  }
@@ -875,6 +975,9 @@ function packageAdditionCapabilityForState(presetName, state) {
875
975
  throw new Error(`Preset ${presetName} is an initialization-only workspace and cannot be used for Package Addition`);
876
976
  }
877
977
  const nodePackage = state.nodeWorkspace.packages[0];
978
+ if (nodePackage === undefined) {
979
+ throw new Error(`Preset ${presetName} must declare one package for Package Addition`);
980
+ }
878
981
  return {
879
982
  sourcePreset: nodePackage.kind,
880
983
  workspacePackageGlob: state.nodeWorkspace.workspacePackageGlob,
@@ -923,7 +1026,7 @@ function generationContextForPackageAddition(options) {
923
1026
  },
924
1027
  toolchain: {
925
1028
  nodeLtsMajor: { kind: "NodeLtsMajor", value: options.nodeVersion },
926
- packageManagerPin: { kind: "PackageManagerPin", value: "pnpm@10.0.0" },
1029
+ packageManagerPin: { kind: "PackageManagerPin", value: "pnpm@10.34.4" },
927
1030
  source: "bundled-fallback",
928
1031
  diagnostics: [],
929
1032
  },
@@ -983,19 +1086,15 @@ function libraryPackageAdditionOperations(options) {
983
1086
  }
984
1087
  function libraryTsconfigJson() {
985
1088
  return {
986
- compilerOptions: {
1089
+ compilerOptions: strictTypeScriptCompilerOptions({
987
1090
  composite: true,
988
1091
  declaration: true,
989
1092
  declarationMap: true,
990
- module: "NodeNext",
991
- moduleResolution: "NodeNext",
992
- noEmitOnError: true,
1093
+ module: "nodenext",
1094
+ moduleResolution: "nodenext",
993
1095
  rootDir: "src",
994
- skipLibCheck: false,
995
- strict: true,
996
- target: "ES2022",
997
1096
  types: ["node"],
998
- },
1097
+ }),
999
1098
  include: ["src/**/*.ts"],
1000
1099
  };
1001
1100
  }
@@ -1147,7 +1246,11 @@ function hasVuePackage(capability) {
1147
1246
  }
1148
1247
  function sourceRootPreset(capability) {
1149
1248
  if (capability.packages.length === 1) {
1150
- return capability.packages[0].kind;
1249
+ const nodePackage = capability.packages[0];
1250
+ if (nodePackage === undefined) {
1251
+ throw new Error("Node package workspace must contain one package");
1252
+ }
1253
+ return nodePackage.kind;
1151
1254
  }
1152
1255
  return "vue-hono-app";
1153
1256
  }
@@ -1297,6 +1400,7 @@ function honoApiPackageJson(context, packageName, scripts, exposureFields) {
1297
1400
  "@types/node": "catalog:",
1298
1401
  oxfmt: "catalog:",
1299
1402
  oxlint: "catalog:",
1403
+ "oxlint-tsgolint": "catalog:",
1300
1404
  "tsc-alias": "catalog:",
1301
1405
  ...(scripts.dev === undefined ? {} : { tsx: "catalog:" }),
1302
1406
  typescript: "catalog:",
@@ -1322,7 +1426,6 @@ function vuePackageJson(context, packageName, scripts, packageLinkDependencies =
1322
1426
  scripts,
1323
1427
  dependencies: {
1324
1428
  ...packageLinkDependencies,
1325
- "@vueuse/core": "catalog:",
1326
1429
  ...(Object.keys(packageLinkDependencies).length === 0
1327
1430
  ? {}
1328
1431
  : { hono: "catalog:" }),
@@ -1338,6 +1441,7 @@ function vuePackageJson(context, packageName, scripts, packageLinkDependencies =
1338
1441
  "@vue/tsconfig": "catalog:",
1339
1442
  oxfmt: "catalog:",
1340
1443
  oxlint: "catalog:",
1444
+ "oxlint-tsgolint": "catalog:",
1341
1445
  tailwindcss: "catalog:",
1342
1446
  typescript: "catalog:",
1343
1447
  vite: "catalog:",
@@ -1350,7 +1454,7 @@ function vuePackageJson(context, packageName, scripts, packageLinkDependencies =
1350
1454
  };
1351
1455
  }
1352
1456
  function catalogDependencies(dependencies) {
1353
- return Object.fromEntries([...dependencies].sort().map((dependency) => [dependency, "catalog:"]));
1457
+ return Object.fromEntries([...dependencies].toSorted().map((dependency) => [dependency, "catalog:"]));
1354
1458
  }
1355
1459
  function generationRecord(context) {
1356
1460
  return {
@@ -1762,8 +1866,8 @@ function nodePackageScripts(nodePackage, workspace) {
1762
1866
  const oxcScripts = {
1763
1867
  "format:check": "oxfmt --check --config ../../oxfmt.config.ts .",
1764
1868
  "format:write": "oxfmt --write --config ../../oxfmt.config.ts .",
1765
- lint: "oxlint --config ../../oxlint.config.ts . --deny-warnings",
1766
- "lint:fix": "oxlint --config ../../oxlint.config.ts . --fix --deny-warnings",
1869
+ lint: "oxlint --config ../../oxlint.config.ts .",
1870
+ "lint:fix": "oxlint --config ../../oxlint.config.ts . --fix",
1767
1871
  };
1768
1872
  if (nodePackage.kind === "hono-api") {
1769
1873
  const checks = {
@@ -1820,7 +1924,7 @@ function nodePackageScripts(nodePackage, workspace) {
1820
1924
  ...oxcScripts,
1821
1925
  preview: "vite preview",
1822
1926
  test: "vitest run",
1823
- "test:e2e": "pnpm run build && playwright test",
1927
+ "test:e2e": "pnpm run build && node --experimental-strip-types scripts/run-playwright.ts",
1824
1928
  typecheck: workspace.packages.length > 1
1825
1929
  ? "vue-tsc --build"
1826
1930
  : "vue-tsc --build --noEmit",
@@ -1833,19 +1937,15 @@ function nodePackageTsconfigOperations(nodePackage, workspace) {
1833
1937
  kind: "writeJson",
1834
1938
  to: `${nodePackage.path}/tsconfig.json`,
1835
1939
  value: {
1836
- compilerOptions: {
1940
+ compilerOptions: strictTypeScriptCompilerOptions({
1837
1941
  composite: true,
1838
1942
  ...(workspace.packages.length > 1
1839
1943
  ? { declaration: true, declarationMap: true }
1840
1944
  : {}),
1841
- module: "NodeNext",
1842
- moduleResolution: "NodeNext",
1843
- noEmitOnError: true,
1844
- skipLibCheck: false,
1845
- strict: true,
1846
- target: "ES2022",
1945
+ module: "nodenext",
1946
+ moduleResolution: "nodenext",
1847
1947
  types: ["node", "vitest/globals"],
1848
- },
1948
+ }),
1849
1949
  include: ["src/**/*.ts", "test/**/*.ts", "vitest.config.ts"],
1850
1950
  },
1851
1951
  },
@@ -1882,17 +1982,13 @@ function nodePackageTsconfigOperations(nodePackage, workspace) {
1882
1982
  to: `${nodePackage.path}/tsconfig.app.json`,
1883
1983
  value: {
1884
1984
  extends: "@vue/tsconfig/tsconfig.dom.json",
1885
- compilerOptions: {
1985
+ compilerOptions: strictTypeScriptCompilerOptions({
1886
1986
  composite: true,
1887
1987
  module: "ESNext",
1888
1988
  moduleResolution: "Bundler",
1889
- noEmitOnError: true,
1890
- skipLibCheck: false,
1891
- strict: true,
1892
- target: "ES2022",
1893
1989
  tsBuildInfoFile: "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
1894
1990
  types: ["web-bluetooth"],
1895
- },
1991
+ }),
1896
1992
  include: ["env.d.ts", "src/**/*.ts", "src/**/*.vue"],
1897
1993
  },
1898
1994
  },
@@ -1912,23 +2008,25 @@ function nodePackageTsconfigOperations(nodePackage, workspace) {
1912
2008
  {
1913
2009
  kind: "writeJson",
1914
2010
  to: `${nodePackage.path}/tsconfig.node.json`,
2011
+ multilineArrays: ["include"],
1915
2012
  value: {
1916
- compilerOptions: {
2013
+ compilerOptions: strictTypeScriptCompilerOptions({
1917
2014
  composite: true,
1918
2015
  module: "ESNext",
1919
2016
  moduleResolution: "Bundler",
1920
- noEmitOnError: true,
1921
2017
  lib: ["ESNext", "DOM", "DOM.Iterable"],
1922
2018
  ...(workspace.packages.length > 1
1923
2019
  ? { outDir: "./node_modules/.tmp/tsconfig.node" }
1924
2020
  : {}),
1925
- skipLibCheck: false,
1926
- strict: true,
1927
- target: "ES2022",
1928
2021
  tsBuildInfoFile: "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
1929
2022
  types: ["node"],
1930
- },
1931
- include: ["playwright.config.ts", "vite.config.ts", "vitest.config.ts"],
2023
+ }),
2024
+ include: [
2025
+ "playwright.config.ts",
2026
+ "scripts/**/*.ts",
2027
+ "vite.config.ts",
2028
+ "vitest.config.ts",
2029
+ ],
1932
2030
  },
1933
2031
  },
1934
2032
  ];
@@ -2014,6 +2112,17 @@ function strictTypescriptOperations({ context, state, }) {
2014
2112
  if (state.package === undefined && state.nodeWorkspace === undefined) {
2015
2113
  throw new Error("strict-typescript-root requires a workspace package layout");
2016
2114
  }
2115
+ const rootConfigTsconfigOperation = () => {
2116
+ if (state.sourceRoots.sharedOxc === undefined) {
2117
+ throw new Error("strict-typescript-root requires shared OXC source when rendering tsconfig.config.json");
2118
+ }
2119
+ return {
2120
+ kind: "copyFile",
2121
+ from: "tsconfig.config.json",
2122
+ to: "tsconfig.config.json",
2123
+ sourceRoot: "sharedOxc",
2124
+ };
2125
+ };
2017
2126
  if (state.nodeWorkspace !== undefined) {
2018
2127
  return [
2019
2128
  {
@@ -2024,21 +2133,7 @@ function strictTypescriptOperations({ context, state, }) {
2024
2133
  references: rootTsconfigReferences(state.nodeWorkspace),
2025
2134
  },
2026
2135
  },
2027
- {
2028
- kind: "writeJson",
2029
- to: "tsconfig.config.json",
2030
- value: {
2031
- compilerOptions: {
2032
- module: "NodeNext",
2033
- moduleResolution: "NodeNext",
2034
- noEmitOnError: true,
2035
- skipLibCheck: false,
2036
- strict: true,
2037
- target: "ES2022",
2038
- },
2039
- include: ["oxlint.config.ts", "oxfmt.config.ts"],
2040
- },
2041
- },
2136
+ rootConfigTsconfigOperation(),
2042
2137
  ];
2043
2138
  }
2044
2139
  const libraryPackage = state.package;
@@ -2050,40 +2145,11 @@ function strictTypescriptOperations({ context, state, }) {
2050
2145
  files: [],
2051
2146
  },
2052
2147
  },
2053
- {
2054
- kind: "writeJson",
2055
- to: "tsconfig.config.json",
2056
- value: {
2057
- compilerOptions: {
2058
- module: "NodeNext",
2059
- moduleResolution: "NodeNext",
2060
- noEmitOnError: true,
2061
- skipLibCheck: false,
2062
- strict: true,
2063
- target: "ES2022",
2064
- },
2065
- include: ["oxlint.config.ts", "oxfmt.config.ts"],
2066
- },
2067
- },
2148
+ rootConfigTsconfigOperation(),
2068
2149
  {
2069
2150
  kind: "writeJson",
2070
2151
  to: `${workspacePackagePath(context, libraryPackage)}/tsconfig.json`,
2071
- value: {
2072
- compilerOptions: {
2073
- composite: true,
2074
- declaration: true,
2075
- declarationMap: true,
2076
- module: "NodeNext",
2077
- moduleResolution: "NodeNext",
2078
- noEmitOnError: true,
2079
- rootDir: "src",
2080
- skipLibCheck: false,
2081
- strict: true,
2082
- target: "ES2022",
2083
- types: ["node"],
2084
- },
2085
- include: ["src/**/*.ts"],
2086
- },
2152
+ value: libraryTsconfigJson(),
2087
2153
  },
2088
2154
  ];
2089
2155
  }
@@ -50,9 +50,9 @@ export type ReplaceAnchorsOperation = {
50
50
  export type RenderOperation = CopyFileOperation | WriteJsonOperation | MergeJsonOperation | WriteTextOperation | WriteTextFromFragmentsOperation | WriteTextTemplateOperation | SetExecutableOperation | ReplaceAnchorsOperation;
51
51
  export type RenderProjectOptions = {
52
52
  sourceRoot: string;
53
- sourceRoots?: Record<string, string>;
53
+ sourceRoots?: Record<string, string> | undefined;
54
54
  targetRoot: string;
55
- variables?: RenderVariables;
55
+ variables?: RenderVariables | undefined;
56
56
  operations: RenderOperation[];
57
57
  };
58
58
  export declare function renderProject(options: RenderProjectOptions): Promise<void>;
@@ -65,7 +65,7 @@ function serializeJsonValue(value, indentation, pathSegments, multilineArrays, r
65
65
  if (!isRecord(value)) {
66
66
  return JSON.stringify(value);
67
67
  }
68
- const entries = Object.entries(value).sort(([left], [right]) => compareJsonKeys(left, right, pathSegments, rootKeyOrder));
68
+ const entries = Object.entries(value).toSorted(([left], [right]) => compareJsonKeys(left, right, pathSegments, rootKeyOrder));
69
69
  if (entries.length === 0) {
70
70
  return "{}";
71
71
  }
@@ -325,7 +325,7 @@ async function findTypeScriptAnchorRanges(sourceText) {
325
325
  }
326
326
  function replaceRanges(sourceText, ranges, replacements) {
327
327
  let nextText = sourceText;
328
- for (const range of [...ranges].sort((a, b) => b.start - a.start)) {
328
+ for (const range of ranges.toSorted((a, b) => b.start - a.start)) {
329
329
  const replacement = replacements[range.name];
330
330
  if (replacement === undefined) {
331
331
  continue;
@@ -18,7 +18,7 @@ export type TemplateBoundaryCheckProjection = {
18
18
  readonly sourceFilePath: string;
19
19
  readonly plan: {
20
20
  readonly sourceRoot: string;
21
- readonly sourceRoots?: Record<string, string>;
21
+ readonly sourceRoots?: Record<string, string> | undefined;
22
22
  readonly operations: readonly RenderOperation[];
23
23
  };
24
24
  };