@ykdz/template 0.0.8 → 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 (39) 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 +23 -4
  6. package/node_modules/@ykdz/template-builtin-source/dist/templates/vue-hono-app/projection.js +6 -6
  7. package/node_modules/@ykdz/template-builtin-source/package.json +15 -2
  8. package/node_modules/@ykdz/template-builtin-source/templates/preset-source.json +14 -2
  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-hono-app/web/env.d.ts +7 -0
  14. package/node_modules/@ykdz/template-core/dist/declarations.js +34 -1
  15. package/node_modules/@ykdz/template-core/dist/dependency-catalog.js +11 -6
  16. package/node_modules/@ykdz/template-core/dist/devcontainer.d.ts +5 -5
  17. package/node_modules/@ykdz/template-core/dist/editor-customization.js +20 -29
  18. package/node_modules/@ykdz/template-core/dist/generated-scenarios.d.ts +4 -4
  19. package/node_modules/@ykdz/template-core/dist/generated-scenarios.js +29 -9
  20. package/node_modules/@ykdz/template-core/dist/generation-context.js +8 -3
  21. package/node_modules/@ykdz/template-core/dist/next-step-instructions.js +3 -0
  22. package/node_modules/@ykdz/template-core/dist/package-addition.d.ts +2 -2
  23. package/node_modules/@ykdz/template-core/dist/package-addition.js +22 -8
  24. package/node_modules/@ykdz/template-core/dist/pnpm-workspace.yaml +1 -0
  25. package/node_modules/@ykdz/template-core/dist/preset-projection.d.ts +3 -3
  26. package/node_modules/@ykdz/template-core/dist/preset-projection.js +1 -0
  27. package/node_modules/@ykdz/template-core/dist/preset-source.js +60 -45
  28. package/node_modules/@ykdz/template-core/dist/project-github.d.ts +3 -3
  29. package/node_modules/@ykdz/template-core/dist/project-github.js +1 -0
  30. package/node_modules/@ykdz/template-core/dist/projection-capabilities.d.ts +7 -3
  31. package/node_modules/@ykdz/template-core/dist/projection-capabilities.js +187 -120
  32. package/node_modules/@ykdz/template-core/dist/renderer.d.ts +2 -2
  33. package/node_modules/@ykdz/template-core/dist/renderer.js +2 -2
  34. package/node_modules/@ykdz/template-core/dist/template-boundary-check.d.ts +1 -1
  35. package/node_modules/@ykdz/template-core/dist/template-boundary-check.js +8 -10
  36. package/node_modules/@ykdz/template-core/dist/toolchain-resolution.d.ts +5 -5
  37. package/node_modules/@ykdz/template-core/dist/toolchain-resolution.js +9 -10
  38. package/node_modules/@ykdz/template-core/package.json +9 -2
  39. 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",
@@ -205,21 +225,23 @@ const capabilityInterpreters = {
205
225
  state.rootScriptFragments["format:write"] =
206
226
  "oxfmt --write --config oxfmt.config.ts oxlint.config.ts oxfmt.config.ts";
207
227
  state.rootScriptFragments.lint =
208
- "oxlint --config oxlint.config.ts oxlint.config.ts oxfmt.config.ts --deny-warnings";
228
+ "oxlint --config oxlint.config.ts oxlint.config.ts oxfmt.config.ts";
209
229
  state.rootScriptFragments["lint:fix"] =
210
- "oxlint --config oxlint.config.ts oxlint.config.ts oxfmt.config.ts --fix --deny-warnings";
230
+ "oxlint --config oxlint.config.ts oxlint.config.ts oxfmt.config.ts --fix";
211
231
  state.packageScriptFragments["format:check"] =
212
232
  "oxfmt --check --config ../../oxfmt.config.ts .";
213
233
  state.packageScriptFragments["format:write"] =
214
234
  "oxfmt --write --config ../../oxfmt.config.ts .";
215
235
  state.packageScriptFragments.lint =
216
- "oxlint --config ../../oxlint.config.ts . --deny-warnings";
236
+ "oxlint --config ../../oxlint.config.ts .";
217
237
  state.packageScriptFragments["lint:fix"] =
218
- "oxlint --config ../../oxlint.config.ts . --fix --deny-warnings";
238
+ "oxlint --config ../../oxlint.config.ts . --fix";
219
239
  state.rootDevDependencies.add("oxfmt");
220
240
  state.rootDevDependencies.add("oxlint");
241
+ state.rootDevDependencies.add("oxlint-tsgolint");
221
242
  state.packageDevDependencies.add("oxfmt");
222
243
  state.packageDevDependencies.add("oxlint");
244
+ state.packageDevDependencies.add("oxlint-tsgolint");
223
245
  state.editorCustomizationCapabilities.push("oxc-format-lint");
224
246
  state.flags.fixCommand = true;
225
247
  state.operationFactories.push(oxcFormatLintOperations);
@@ -244,6 +266,52 @@ const capabilityInterpreters = {
244
266
  },
245
267
  },
246
268
  };
269
+ function contributeProjectionCapability(capability, state) {
270
+ switch (capability.kind) {
271
+ case "workspace-library-package":
272
+ capabilityInterpreters["workspace-library-package"].contribute({
273
+ capability,
274
+ state,
275
+ });
276
+ return;
277
+ case "workspace-node-packages":
278
+ capabilityInterpreters["workspace-node-packages"].contribute({
279
+ capability,
280
+ state,
281
+ });
282
+ return;
283
+ case "rust-binary-workspace":
284
+ capabilityInterpreters["rust-binary-workspace"].contribute({
285
+ capability,
286
+ state,
287
+ });
288
+ return;
289
+ case "strict-typescript-root":
290
+ capabilityInterpreters["strict-typescript-root"].contribute({
291
+ capability,
292
+ state,
293
+ });
294
+ return;
295
+ case "oxc-format-lint":
296
+ capabilityInterpreters["oxc-format-lint"].contribute({
297
+ capability,
298
+ state,
299
+ });
300
+ return;
301
+ case "node-pnpm-devcontainer":
302
+ capabilityInterpreters["node-pnpm-devcontainer"].contribute({
303
+ capability,
304
+ state,
305
+ });
306
+ return;
307
+ case "github-maintenance":
308
+ capabilityInterpreters["github-maintenance"].contribute({
309
+ capability,
310
+ state,
311
+ });
312
+ return;
313
+ }
314
+ }
247
315
  export function validateProjectionCapabilities(input) {
248
316
  if (!isRecord(input) || !Array.isArray(input.capabilities)) {
249
317
  return {
@@ -274,7 +342,7 @@ export function validateProjectionCapabilities(input) {
274
342
  });
275
343
  return;
276
344
  }
277
- if (!projectionCapabilityKindSet.has(capability.kind)) {
345
+ if (!isProjectionCapabilityKind(capability.kind)) {
278
346
  issues.push({
279
347
  path: `${pathPrefix}.kind`,
280
348
  message: `Unknown Projection Capability kind: ${capability.kind}`,
@@ -282,7 +350,7 @@ export function validateProjectionCapabilities(input) {
282
350
  return;
283
351
  }
284
352
  const kind = capability.kind;
285
- issues.push(...unknownCapabilityPropertyIssues(capability, pathPrefix));
353
+ issues.push(...unknownCapabilityPropertyIssues(kind, capability, pathPrefix));
286
354
  if (kind === "workspace-library-package") {
287
355
  const workspaceCapability = parseWorkspaceLibraryPackageCapability(capability, pathPrefix);
288
356
  if (Array.isArray(workspaceCapability)) {
@@ -358,10 +426,7 @@ export function interpretPresetProjectionDeclaration(options) {
358
426
  }
359
427
  const state = createProjectionCompositionState(options.sourceRoots);
360
428
  for (const capability of validation.value.capabilities) {
361
- capabilityInterpreters[capability.kind].contribute({
362
- capability: capability,
363
- state,
364
- });
429
+ contributeProjectionCapability(capability, state);
365
430
  }
366
431
  const checkPlan = {
367
432
  components: state.rootCheckComponents,
@@ -405,10 +470,11 @@ export function interpretPresetProjectionDeclaration(options) {
405
470
  export function blueprintForPresetSourcePreset(preset, options = { targetDir: process.cwd() }) {
406
471
  const packageScope = options.scope ?? projectNameFromDir(options.targetDir);
407
472
  const projectName = projectNameFromDir(options.targetDir);
473
+ const packageManager = preset.supportedPackageManagers[0];
408
474
  const blueprint = {
409
475
  schemaVersion: 1,
410
476
  preset: preset.name,
411
- packageManager: preset.supportedPackageManagers[0],
477
+ ...(packageManager === undefined ? {} : { packageManager }),
412
478
  projectKind: preset.supportedProjectKinds[0] ?? "multi-package",
413
479
  features: [...preset.features],
414
480
  };
@@ -502,11 +568,29 @@ function createProjectionCompositionState(sourceRoots) {
502
568
  function isRecord(value) {
503
569
  return typeof value === "object" && value !== null && !Array.isArray(value);
504
570
  }
571
+ function isProjectionCapabilityKind(value) {
572
+ return projectionCapabilityKindSet.has(value);
573
+ }
574
+ function isWorkspaceNodePackageKind(value) {
575
+ return typeof value === "string" && workspaceNodePackageKindSet.has(value);
576
+ }
577
+ function isWorkspaceNodePackagePath(value) {
578
+ return typeof value === "string" && workspaceNodePackagePathSet.has(value);
579
+ }
505
580
  function isNonEmptyString(value) {
506
581
  return typeof value === "string" && value.length > 0;
507
582
  }
508
- function unknownCapabilityPropertyIssues(capability, pathPrefix) {
509
- const kind = capability.kind;
583
+ function nonEmptyStringArray(value) {
584
+ const strings = [];
585
+ for (const entry of value) {
586
+ if (!isNonEmptyString(entry)) {
587
+ return undefined;
588
+ }
589
+ strings.push(entry);
590
+ }
591
+ return strings.length === 0 ? undefined : strings;
592
+ }
593
+ function unknownCapabilityPropertyIssues(kind, capability, pathPrefix) {
510
594
  const allowedKeys = new Set(exactCapabilityKeys[kind]);
511
595
  return Object.keys(capability)
512
596
  .filter((key) => !allowedKeys.has(key))
@@ -517,6 +601,7 @@ function unknownCapabilityPropertyIssues(capability, pathPrefix) {
517
601
  }
518
602
  function parseWorkspaceLibraryPackageCapability(capability, pathPrefix) {
519
603
  const issues = [];
604
+ let sourceFiles = [];
520
605
  if (capability.workspacePackageGlob !== "packages/*") {
521
606
  issues.push({
522
607
  path: `${pathPrefix}.workspacePackageGlob`,
@@ -541,12 +626,17 @@ function parseWorkspaceLibraryPackageCapability(capability, pathPrefix) {
541
626
  message: "workspace-library-package sourceFiles must be a non-empty array",
542
627
  });
543
628
  }
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
- });
629
+ else {
630
+ const parsedSourceFiles = nonEmptyStringArray(capability.sourceFiles);
631
+ if (parsedSourceFiles === undefined) {
632
+ issues.push({
633
+ path: `${pathPrefix}.sourceFiles`,
634
+ message: "workspace-library-package sourceFiles must be a non-empty array of paths",
635
+ });
636
+ }
637
+ else {
638
+ sourceFiles = parsedSourceFiles;
639
+ }
550
640
  }
551
641
  if (issues.length > 0) {
552
642
  return issues;
@@ -556,7 +646,7 @@ function parseWorkspaceLibraryPackageCapability(capability, pathPrefix) {
556
646
  workspacePackageGlob: "packages/*",
557
647
  packageRole: "shared-library",
558
648
  packageSourcePreset: "ts-lib",
559
- sourceFiles: capability.sourceFiles,
649
+ sourceFiles,
560
650
  };
561
651
  }
562
652
  function parseWorkspaceNodePackagesCapability(capability, pathPrefix) {
@@ -607,13 +697,18 @@ function parseWorkspaceNodePackage(value, pathPrefix) {
607
697
  },
608
698
  ];
609
699
  }
610
- if (value.kind !== "hono-api" && value.kind !== "vue-app") {
700
+ const kind = isWorkspaceNodePackageKind(value.kind) ? value.kind : undefined;
701
+ const packagePath = isWorkspaceNodePackagePath(value.path)
702
+ ? value.path
703
+ : undefined;
704
+ let sourceFiles = [];
705
+ if (kind === undefined) {
611
706
  issues.push({
612
707
  path: `${pathPrefix}.kind`,
613
708
  message: "workspace-node-packages package kind must be hono-api or vue-app",
614
709
  });
615
710
  }
616
- if (value.path !== "apps/api" && value.path !== "apps/web") {
711
+ if (packagePath === undefined) {
617
712
  issues.push({
618
713
  path: `${pathPrefix}.path`,
619
714
  message: "workspace-node-packages package path must be apps/api or apps/web",
@@ -625,12 +720,17 @@ function parseWorkspaceNodePackage(value, pathPrefix) {
625
720
  message: "workspace-node-packages package sourceFiles must be a non-empty array",
626
721
  });
627
722
  }
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
- });
723
+ else {
724
+ const parsedSourceFiles = nonEmptyStringArray(value.sourceFiles);
725
+ if (parsedSourceFiles === undefined) {
726
+ issues.push({
727
+ path: `${pathPrefix}.sourceFiles`,
728
+ message: "workspace-node-packages package sourceFiles must be a non-empty array of paths",
729
+ });
730
+ }
731
+ else {
732
+ sourceFiles = parsedSourceFiles;
733
+ }
634
734
  }
635
735
  const allowedKeys = new Set(["kind", "path", "sourceFiles"]);
636
736
  for (const key of Object.keys(value)) {
@@ -644,10 +744,13 @@ function parseWorkspaceNodePackage(value, pathPrefix) {
644
744
  if (issues.length > 0) {
645
745
  return issues;
646
746
  }
747
+ if (kind === undefined || packagePath === undefined) {
748
+ throw new Error(`workspace-node-packages package validation failed without diagnostics at ${pathPrefix}`);
749
+ }
647
750
  return {
648
- kind: value.kind,
649
- path: value.path,
650
- sourceFiles: value.sourceFiles,
751
+ kind,
752
+ path: packagePath,
753
+ sourceFiles,
651
754
  };
652
755
  }
653
756
  function parseWorkspaceNodePackageLinks(value, pathPrefix, declaredPackagePaths, issues) {
@@ -712,6 +815,7 @@ function parseWorkspaceNodePackageLinks(value, pathPrefix, declaredPackagePaths,
712
815
  }
713
816
  function parseRustBinaryWorkspaceCapability(capability, pathPrefix) {
714
817
  const issues = [];
818
+ let sourceFiles = [];
715
819
  if (capability.workspacePackageGlob !== "packages/*") {
716
820
  issues.push({
717
821
  path: `${pathPrefix}.workspacePackageGlob`,
@@ -724,12 +828,17 @@ function parseRustBinaryWorkspaceCapability(capability, pathPrefix) {
724
828
  message: "rust-binary-workspace sourceFiles must be a non-empty array",
725
829
  });
726
830
  }
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
- });
831
+ else {
832
+ const parsedSourceFiles = nonEmptyStringArray(capability.sourceFiles);
833
+ if (parsedSourceFiles === undefined) {
834
+ issues.push({
835
+ path: `${pathPrefix}.sourceFiles`,
836
+ message: "rust-binary-workspace sourceFiles must be a non-empty array of paths",
837
+ });
838
+ }
839
+ else {
840
+ sourceFiles = parsedSourceFiles;
841
+ }
733
842
  }
734
843
  if (issues.length > 0) {
735
844
  return issues;
@@ -737,7 +846,7 @@ function parseRustBinaryWorkspaceCapability(capability, pathPrefix) {
737
846
  return {
738
847
  kind: "rust-binary-workspace",
739
848
  workspacePackageGlob: "packages/*",
740
- sourceFiles: capability.sourceFiles,
849
+ sourceFiles,
741
850
  };
742
851
  }
743
852
  function duplicateCapabilityIssues(capabilities) {
@@ -848,10 +957,7 @@ function stateForProjectionDeclaration(declaration, sourceRoots) {
848
957
  }
849
958
  const state = createProjectionCompositionState(sourceRoots);
850
959
  for (const capability of validation.value.capabilities) {
851
- capabilityInterpreters[capability.kind].contribute({
852
- capability: capability,
853
- state,
854
- });
960
+ contributeProjectionCapability(capability, state);
855
961
  }
856
962
  return state;
857
963
  }
@@ -875,6 +981,9 @@ function packageAdditionCapabilityForState(presetName, state) {
875
981
  throw new Error(`Preset ${presetName} is an initialization-only workspace and cannot be used for Package Addition`);
876
982
  }
877
983
  const nodePackage = state.nodeWorkspace.packages[0];
984
+ if (nodePackage === undefined) {
985
+ throw new Error(`Preset ${presetName} must declare one package for Package Addition`);
986
+ }
878
987
  return {
879
988
  sourcePreset: nodePackage.kind,
880
989
  workspacePackageGlob: state.nodeWorkspace.workspacePackageGlob,
@@ -983,19 +1092,15 @@ function libraryPackageAdditionOperations(options) {
983
1092
  }
984
1093
  function libraryTsconfigJson() {
985
1094
  return {
986
- compilerOptions: {
1095
+ compilerOptions: strictTypeScriptCompilerOptions({
987
1096
  composite: true,
988
1097
  declaration: true,
989
1098
  declarationMap: true,
990
- module: "NodeNext",
991
- moduleResolution: "NodeNext",
992
- noEmitOnError: true,
1099
+ module: "nodenext",
1100
+ moduleResolution: "nodenext",
993
1101
  rootDir: "src",
994
- skipLibCheck: false,
995
- strict: true,
996
- target: "ES2022",
997
1102
  types: ["node"],
998
- },
1103
+ }),
999
1104
  include: ["src/**/*.ts"],
1000
1105
  };
1001
1106
  }
@@ -1147,7 +1252,11 @@ function hasVuePackage(capability) {
1147
1252
  }
1148
1253
  function sourceRootPreset(capability) {
1149
1254
  if (capability.packages.length === 1) {
1150
- return capability.packages[0].kind;
1255
+ const nodePackage = capability.packages[0];
1256
+ if (nodePackage === undefined) {
1257
+ throw new Error("Node package workspace must contain one package");
1258
+ }
1259
+ return nodePackage.kind;
1151
1260
  }
1152
1261
  return "vue-hono-app";
1153
1262
  }
@@ -1297,6 +1406,7 @@ function honoApiPackageJson(context, packageName, scripts, exposureFields) {
1297
1406
  "@types/node": "catalog:",
1298
1407
  oxfmt: "catalog:",
1299
1408
  oxlint: "catalog:",
1409
+ "oxlint-tsgolint": "catalog:",
1300
1410
  "tsc-alias": "catalog:",
1301
1411
  ...(scripts.dev === undefined ? {} : { tsx: "catalog:" }),
1302
1412
  typescript: "catalog:",
@@ -1338,6 +1448,7 @@ function vuePackageJson(context, packageName, scripts, packageLinkDependencies =
1338
1448
  "@vue/tsconfig": "catalog:",
1339
1449
  oxfmt: "catalog:",
1340
1450
  oxlint: "catalog:",
1451
+ "oxlint-tsgolint": "catalog:",
1341
1452
  tailwindcss: "catalog:",
1342
1453
  typescript: "catalog:",
1343
1454
  vite: "catalog:",
@@ -1350,7 +1461,7 @@ function vuePackageJson(context, packageName, scripts, packageLinkDependencies =
1350
1461
  };
1351
1462
  }
1352
1463
  function catalogDependencies(dependencies) {
1353
- return Object.fromEntries([...dependencies].sort().map((dependency) => [dependency, "catalog:"]));
1464
+ return Object.fromEntries([...dependencies].toSorted().map((dependency) => [dependency, "catalog:"]));
1354
1465
  }
1355
1466
  function generationRecord(context) {
1356
1467
  return {
@@ -1762,8 +1873,8 @@ function nodePackageScripts(nodePackage, workspace) {
1762
1873
  const oxcScripts = {
1763
1874
  "format:check": "oxfmt --check --config ../../oxfmt.config.ts .",
1764
1875
  "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",
1876
+ lint: "oxlint --config ../../oxlint.config.ts .",
1877
+ "lint:fix": "oxlint --config ../../oxlint.config.ts . --fix",
1767
1878
  };
1768
1879
  if (nodePackage.kind === "hono-api") {
1769
1880
  const checks = {
@@ -1833,19 +1944,15 @@ function nodePackageTsconfigOperations(nodePackage, workspace) {
1833
1944
  kind: "writeJson",
1834
1945
  to: `${nodePackage.path}/tsconfig.json`,
1835
1946
  value: {
1836
- compilerOptions: {
1947
+ compilerOptions: strictTypeScriptCompilerOptions({
1837
1948
  composite: true,
1838
1949
  ...(workspace.packages.length > 1
1839
1950
  ? { declaration: true, declarationMap: true }
1840
1951
  : {}),
1841
- module: "NodeNext",
1842
- moduleResolution: "NodeNext",
1843
- noEmitOnError: true,
1844
- skipLibCheck: false,
1845
- strict: true,
1846
- target: "ES2022",
1952
+ module: "nodenext",
1953
+ moduleResolution: "nodenext",
1847
1954
  types: ["node", "vitest/globals"],
1848
- },
1955
+ }),
1849
1956
  include: ["src/**/*.ts", "test/**/*.ts", "vitest.config.ts"],
1850
1957
  },
1851
1958
  },
@@ -1882,17 +1989,13 @@ function nodePackageTsconfigOperations(nodePackage, workspace) {
1882
1989
  to: `${nodePackage.path}/tsconfig.app.json`,
1883
1990
  value: {
1884
1991
  extends: "@vue/tsconfig/tsconfig.dom.json",
1885
- compilerOptions: {
1992
+ compilerOptions: strictTypeScriptCompilerOptions({
1886
1993
  composite: true,
1887
1994
  module: "ESNext",
1888
1995
  moduleResolution: "Bundler",
1889
- noEmitOnError: true,
1890
- skipLibCheck: false,
1891
- strict: true,
1892
- target: "ES2022",
1893
1996
  tsBuildInfoFile: "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
1894
1997
  types: ["web-bluetooth"],
1895
- },
1998
+ }),
1896
1999
  include: ["env.d.ts", "src/**/*.ts", "src/**/*.vue"],
1897
2000
  },
1898
2001
  },
@@ -1913,21 +2016,17 @@ function nodePackageTsconfigOperations(nodePackage, workspace) {
1913
2016
  kind: "writeJson",
1914
2017
  to: `${nodePackage.path}/tsconfig.node.json`,
1915
2018
  value: {
1916
- compilerOptions: {
2019
+ compilerOptions: strictTypeScriptCompilerOptions({
1917
2020
  composite: true,
1918
2021
  module: "ESNext",
1919
2022
  moduleResolution: "Bundler",
1920
- noEmitOnError: true,
1921
2023
  lib: ["ESNext", "DOM", "DOM.Iterable"],
1922
2024
  ...(workspace.packages.length > 1
1923
2025
  ? { outDir: "./node_modules/.tmp/tsconfig.node" }
1924
2026
  : {}),
1925
- skipLibCheck: false,
1926
- strict: true,
1927
- target: "ES2022",
1928
2027
  tsBuildInfoFile: "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
1929
2028
  types: ["node"],
1930
- },
2029
+ }),
1931
2030
  include: ["playwright.config.ts", "vite.config.ts", "vitest.config.ts"],
1932
2031
  },
1933
2032
  },
@@ -2014,6 +2113,17 @@ function strictTypescriptOperations({ context, state, }) {
2014
2113
  if (state.package === undefined && state.nodeWorkspace === undefined) {
2015
2114
  throw new Error("strict-typescript-root requires a workspace package layout");
2016
2115
  }
2116
+ const rootConfigTsconfigOperation = () => {
2117
+ if (state.sourceRoots.sharedOxc === undefined) {
2118
+ throw new Error("strict-typescript-root requires shared OXC source when rendering tsconfig.config.json");
2119
+ }
2120
+ return {
2121
+ kind: "copyFile",
2122
+ from: "tsconfig.config.json",
2123
+ to: "tsconfig.config.json",
2124
+ sourceRoot: "sharedOxc",
2125
+ };
2126
+ };
2017
2127
  if (state.nodeWorkspace !== undefined) {
2018
2128
  return [
2019
2129
  {
@@ -2024,21 +2134,7 @@ function strictTypescriptOperations({ context, state, }) {
2024
2134
  references: rootTsconfigReferences(state.nodeWorkspace),
2025
2135
  },
2026
2136
  },
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
- },
2137
+ rootConfigTsconfigOperation(),
2042
2138
  ];
2043
2139
  }
2044
2140
  const libraryPackage = state.package;
@@ -2050,40 +2146,11 @@ function strictTypescriptOperations({ context, state, }) {
2050
2146
  files: [],
2051
2147
  },
2052
2148
  },
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
- },
2149
+ rootConfigTsconfigOperation(),
2068
2150
  {
2069
2151
  kind: "writeJson",
2070
2152
  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
- },
2153
+ value: libraryTsconfigJson(),
2087
2154
  },
2088
2155
  ];
2089
2156
  }
@@ -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
  };
@@ -233,14 +233,12 @@ function jsonValuesEqual(left, right) {
233
233
  return false;
234
234
  }
235
235
  const leftEntries = Object.entries(left);
236
- const rightRecord = right;
237
- const rightKeys = new Set(Object.keys(rightRecord));
238
- return (leftEntries.length === rightKeys.size &&
236
+ const rightEntries = Object.entries(right);
237
+ const rightValues = new Map(rightEntries);
238
+ return (leftEntries.length === rightEntries.length &&
239
239
  leftEntries.every(([key, value]) => {
240
- rightKeys.delete(key);
241
- return jsonValuesEqual(value, rightRecord[key]);
242
- }) &&
243
- rightKeys.size === 0);
240
+ return (rightValues.has(key) && jsonValuesEqual(value, rightValues.get(key)));
241
+ }));
244
242
  }
245
243
  function expressionMatchesJsonValue(expression, expectedValue) {
246
244
  const literalValue = expressionLiteralJsonValue(expression);
@@ -383,12 +381,12 @@ function isStructuralTurboValue(value) {
383
381
  });
384
382
  }
385
383
  const rootTsconfigConfigCompilerOptions = {
386
- module: "NodeNext",
387
- moduleResolution: "NodeNext",
384
+ module: "nodenext",
385
+ moduleResolution: "nodenext",
388
386
  noEmitOnError: true,
389
387
  skipLibCheck: false,
390
388
  strict: true,
391
- target: "ES2022",
389
+ target: "es2023",
392
390
  };
393
391
  const rootTsconfigConfigIncludes = new Set([
394
392
  "oxlint.config.ts",
@@ -14,15 +14,15 @@ export type ResolvedToolchainVersions = {
14
14
  readonly diagnostics: string[];
15
15
  };
16
16
  export type ResolveToolchainVersionsOptions = {
17
- readonly source?: ToolchainResolutionSource | "auto";
18
- readonly fetchJson?: (url: string) => Promise<unknown>;
19
- readonly nodeReleaseIndexUrl?: string;
20
- readonly pnpmRegistryUrl?: string;
17
+ readonly source?: ToolchainResolutionSource | "auto" | undefined;
18
+ readonly fetchJson?: ((url: string) => Promise<unknown>) | undefined;
19
+ readonly nodeReleaseIndexUrl?: string | undefined;
20
+ readonly pnpmRegistryUrl?: string | undefined;
21
21
  };
22
22
  export declare const nodeReleaseIndexUrl = "https://nodejs.org/dist/index.json";
23
23
  export declare const pnpmRegistryUrl = "https://registry.npmjs.org/pnpm";
24
24
  type OnlineToolchainResolutionContractOptions = {
25
- readonly fetchJson?: (url: string) => Promise<unknown>;
25
+ readonly fetchJson?: ((url: string) => Promise<unknown>) | undefined;
26
26
  };
27
27
  export type OnlineToolchainResolutionContractResult = {
28
28
  readonly nodeLtsMajor: NodeLtsMajor;