@ykdz/template 0.0.2 → 0.0.4

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 (95) hide show
  1. package/README.md +1 -1
  2. package/dist/src/cli.d.ts +2 -0
  3. package/dist/{cli.js → src/cli.js} +91 -58
  4. package/dist/{declarations.d.ts → src/declarations.d.ts} +3 -5
  5. package/dist/{declarations.js → src/declarations.js} +48 -145
  6. package/dist/src/dependency-catalog.d.ts +18 -0
  7. package/dist/src/dependency-catalog.js +132 -0
  8. package/dist/src/devcontainer.d.ts +58 -0
  9. package/dist/src/devcontainer.js +202 -0
  10. package/dist/src/editor-customization.d.ts +12 -0
  11. package/dist/src/editor-customization.js +108 -0
  12. package/dist/{generation-context.d.ts → src/generation-context.d.ts} +2 -3
  13. package/dist/{generation-context.js → src/generation-context.js} +4 -1
  14. package/dist/src/module-graph.d.ts +34 -0
  15. package/dist/src/module-graph.js +58 -0
  16. package/dist/{next-step-instructions.d.ts → src/next-step-instructions.d.ts} +2 -4
  17. package/dist/{next-step-instructions.js → src/next-step-instructions.js} +49 -24
  18. package/dist/{package-addition.d.ts → src/package-addition.d.ts} +1 -1
  19. package/dist/src/package-addition.js +343 -0
  20. package/dist/src/preset-projection.d.ts +66 -0
  21. package/dist/src/preset-projection.js +7 -0
  22. package/dist/{project-github.d.ts → src/project-github.d.ts} +3 -9
  23. package/dist/{project-github.js → src/project-github.js} +27 -42
  24. package/dist/{renderer.d.ts → src/renderer.d.ts} +16 -2
  25. package/dist/{renderer.js → src/renderer.js} +95 -12
  26. package/dist/src/runtime-paths.d.ts +1 -0
  27. package/dist/src/runtime-paths.js +11 -0
  28. package/dist/src/template-boundary-check.d.ts +34 -0
  29. package/dist/src/template-boundary-check.js +448 -0
  30. package/dist/{toolchain-resolution.d.ts → src/toolchain-resolution.d.ts} +0 -1
  31. package/dist/{toolchain-resolution.js → src/toolchain-resolution.js} +1 -1
  32. package/dist/templates/hono-api/projection.d.ts +6 -0
  33. package/dist/templates/hono-api/projection.js +538 -0
  34. package/dist/templates/projection-plans.d.ts +7 -0
  35. package/dist/templates/projection-plans.js +94 -0
  36. package/dist/templates/registry.d.ts +7 -0
  37. package/dist/templates/registry.js +42 -0
  38. package/dist/templates/rust-bin/projection.d.ts +9 -0
  39. package/dist/templates/rust-bin/projection.js +390 -0
  40. package/dist/templates/ts-lib/projection.d.ts +6 -0
  41. package/dist/templates/ts-lib/projection.js +523 -0
  42. package/dist/templates/vue-app/projection.d.ts +6 -0
  43. package/dist/templates/vue-app/projection.js +757 -0
  44. package/dist/templates/vue-hono-app/projection.d.ts +8 -0
  45. package/dist/templates/vue-hono-app/projection.js +693 -0
  46. package/package.json +38 -28
  47. package/pnpm-workspace.yaml +35 -0
  48. package/templates/hono-api/.github/dependabot.yml +13 -0
  49. package/templates/rust-bin/.github/dependabot.yml +18 -1
  50. package/templates/rust-bin/rust-toolchain.toml +3 -0
  51. package/templates/rust-bin/rustfmt.toml +2 -0
  52. package/templates/shared/devcontainer/browser-test.Dockerfile +2 -0
  53. package/templates/shared/devcontainer/node-pnpm.Dockerfile +6 -0
  54. package/templates/shared/devcontainer/rust.Dockerfile +16 -0
  55. package/templates/shared/editor-customization/capabilities.json +56 -0
  56. package/templates/ts-lib/.github/dependabot.yml +13 -0
  57. package/templates/ts-lib/src/index.ts +5 -1
  58. package/templates/vue-app/.github/dependabot.yml +13 -0
  59. package/templates/vue-app/.github/workflows/check.yml +1 -1
  60. package/templates/vue-app/test/e2e/app.spec.ts +4 -1
  61. package/templates/vue-hono-app/.github/dependabot.yml +13 -0
  62. package/templates/vue-hono-app/web/test/e2e/app.spec.ts +4 -1
  63. package/dist/cli.d.ts +0 -3
  64. package/dist/cli.d.ts.map +0 -1
  65. package/dist/declarations.d.ts.map +0 -1
  66. package/dist/devcontainer.d.ts +0 -17
  67. package/dist/devcontainer.d.ts.map +0 -1
  68. package/dist/devcontainer.js +0 -23
  69. package/dist/generation-context.d.ts.map +0 -1
  70. package/dist/hono-api.d.ts +0 -3
  71. package/dist/hono-api.d.ts.map +0 -1
  72. package/dist/hono-api.js +0 -210
  73. package/dist/module-graph.d.ts +0 -45
  74. package/dist/module-graph.d.ts.map +0 -1
  75. package/dist/module-graph.js +0 -187
  76. package/dist/next-step-instructions.d.ts.map +0 -1
  77. package/dist/package-addition.d.ts.map +0 -1
  78. package/dist/package-addition.js +0 -560
  79. package/dist/project-github.d.ts.map +0 -1
  80. package/dist/renderer.d.ts.map +0 -1
  81. package/dist/rust-bin.d.ts +0 -8
  82. package/dist/rust-bin.d.ts.map +0 -1
  83. package/dist/rust-bin.js +0 -208
  84. package/dist/toolchain-resolution.d.ts.map +0 -1
  85. package/dist/ts-lib.d.ts +0 -8
  86. package/dist/ts-lib.d.ts.map +0 -1
  87. package/dist/ts-lib.js +0 -214
  88. package/dist/vue-app.d.ts +0 -3
  89. package/dist/vue-app.d.ts.map +0 -1
  90. package/dist/vue-app.js +0 -301
  91. package/dist/vue-hono-app.d.ts +0 -7
  92. package/dist/vue-hono-app.d.ts.map +0 -1
  93. package/dist/vue-hono-app.js +0 -440
  94. package/templates/shared/oxc/package.json +0 -18
  95. package/templates/shared/oxc/tsconfig.json +0 -11
@@ -0,0 +1,757 @@
1
+ import { existsSync } from "node:fs";
2
+ import { readFile } from "node:fs/promises";
3
+ import path from "node:path";
4
+ import { fileURLToPath } from "node:url";
5
+ import { collectGeneratedManifestCatalogDependencies, renderGeneratedPnpmWorkspaceYaml, } from "../../src/dependency-catalog.js";
6
+ import { browserTestToolLayer, checkedDockerfileFirstNodePnpmDevcontainer, nodePnpmToolLayer, } from "../../src/devcontainer.js";
7
+ import { editorCustomizationForCapabilities } from "../../src/editor-customization.js";
8
+ import { renderFixCommand, renderRootCheckCommand, } from "../../src/module-graph.js";
9
+ import { renderNewProject } from "../../src/renderer.js";
10
+ const generatedBy = {
11
+ packageName: "@ykdz/template",
12
+ version: "0.0.0",
13
+ command: "template init --preset vue-app",
14
+ };
15
+ export const vueAppPresetMetadata = {
16
+ name: "vue-app",
17
+ title: "Vue app",
18
+ description: "Vue app workspace with Vite, Tailwind, Pinia, and test tooling.",
19
+ generation: "supported",
20
+ supportedPackageManagers: ["pnpm"],
21
+ supportedProjectKinds: ["multi-package"],
22
+ features: [
23
+ "pnpm-catalog",
24
+ "oxc-format-lint",
25
+ "strict-typescript",
26
+ "root-check",
27
+ "fix-command",
28
+ "devcontainer",
29
+ "github-actions",
30
+ "dependabot",
31
+ ],
32
+ };
33
+ const dependencyMaintenancePolicy = {
34
+ ecosystems: ["npm", "github-actions", "docker"],
35
+ interval: "weekly",
36
+ };
37
+ const webPackageBoundary = {
38
+ kind: "package-boundary",
39
+ path: ".",
40
+ };
41
+ const rootBoundary = {
42
+ kind: "workspace-orchestration",
43
+ path: ".",
44
+ };
45
+ const workspacePackageBoundary = {
46
+ kind: "package-boundary",
47
+ path: "apps/*",
48
+ };
49
+ const webWorkspaceBoundary = {
50
+ kind: "package-boundary",
51
+ path: "apps/web",
52
+ };
53
+ function planVueAppPackageChecks() {
54
+ return {
55
+ components: [
56
+ { kind: "oxc-format-check", owner: webPackageBoundary },
57
+ { kind: "oxc-lint", owner: webPackageBoundary },
58
+ { kind: "typescript-typecheck", owner: webPackageBoundary },
59
+ { kind: "build", owner: webPackageBoundary },
60
+ { kind: "unit-test", owner: webPackageBoundary },
61
+ { kind: "e2e-test", owner: webPackageBoundary },
62
+ ],
63
+ environmentNeeds: [],
64
+ };
65
+ }
66
+ function planVueAppRootChecks() {
67
+ return {
68
+ components: [
69
+ { kind: "oxc-format-check", owner: rootBoundary },
70
+ { kind: "oxc-lint", owner: rootBoundary },
71
+ { kind: "typescript-typecheck", owner: rootBoundary },
72
+ { kind: "turbo-package-check", owner: workspacePackageBoundary },
73
+ ],
74
+ environmentNeeds: [
75
+ {
76
+ kind: "playwright-browser-assets",
77
+ browser: "chromium",
78
+ owner: webWorkspaceBoundary,
79
+ },
80
+ ],
81
+ };
82
+ }
83
+ function planVueAppPackageFixes() {
84
+ return {
85
+ components: [
86
+ { kind: "oxc-format-write", owner: webPackageBoundary },
87
+ { kind: "oxc-lint-fix", owner: webPackageBoundary },
88
+ ],
89
+ };
90
+ }
91
+ function planVueAppRootFixes() {
92
+ return {
93
+ components: [
94
+ { kind: "oxc-format-write", owner: rootBoundary },
95
+ { kind: "oxc-lint-fix", owner: rootBoundary },
96
+ { kind: "turbo-package-fix", owner: workspacePackageBoundary },
97
+ ],
98
+ };
99
+ }
100
+ function projectNameFromDir(targetDir) {
101
+ return path.basename(path.resolve(targetDir));
102
+ }
103
+ function packageScopeFromOptions(options) {
104
+ return options.scope ?? projectNameFromDir(options.targetDir);
105
+ }
106
+ function packageName(packageScope) {
107
+ return `@${packageScope}/web`;
108
+ }
109
+ export function vueAppBlueprint(options = { targetDir: process.cwd() }) {
110
+ const packageScope = packageScopeFromOptions(options);
111
+ return {
112
+ schemaVersion: 1,
113
+ preset: "vue-app",
114
+ packageManager: "pnpm",
115
+ projectKind: "multi-package",
116
+ features: [...vueAppPresetMetadata.features],
117
+ packages: [{ name: packageName(packageScope), path: "apps/web" }],
118
+ };
119
+ }
120
+ function projectVueAppRootPackageScripts() {
121
+ return {
122
+ check: renderRootCheckCommand(planVueAppRootChecks()),
123
+ fix: renderFixCommand(planVueAppRootFixes()),
124
+ "format:check": "oxfmt --check --config oxfmt.config.ts oxlint.config.ts oxfmt.config.ts",
125
+ "format:write": "oxfmt --write --config oxfmt.config.ts oxlint.config.ts oxfmt.config.ts",
126
+ lint: "oxlint --config oxlint.config.ts oxlint.config.ts oxfmt.config.ts --deny-warnings",
127
+ "lint:fix": "oxlint --config oxlint.config.ts oxlint.config.ts oxfmt.config.ts --fix --deny-warnings",
128
+ typecheck: "tsc -p tsconfig.config.json --noEmit",
129
+ };
130
+ }
131
+ export function projectVueAppPackageScripts() {
132
+ return {
133
+ build: "vite build",
134
+ check: renderRootCheckCommand(planVueAppPackageChecks()),
135
+ dev: "vite",
136
+ fix: renderFixCommand(planVueAppPackageFixes()),
137
+ "format:check": "oxfmt --check --config ../../oxfmt.config.ts .",
138
+ "format:write": "oxfmt --write --config ../../oxfmt.config.ts .",
139
+ lint: "oxlint --config ../../oxlint.config.ts . --deny-warnings",
140
+ "lint:fix": "oxlint --config ../../oxlint.config.ts . --fix --deny-warnings",
141
+ preview: "vite preview",
142
+ test: "vitest run",
143
+ "test:e2e": "pnpm run build && playwright test",
144
+ typecheck: "vue-tsc --build --noEmit",
145
+ };
146
+ }
147
+ function rootPackageJson(context, packageScripts) {
148
+ return {
149
+ name: context.projectName.value,
150
+ version: "0.0.0",
151
+ private: true,
152
+ type: "module",
153
+ scripts: packageScripts,
154
+ devDependencies: {
155
+ oxfmt: "catalog:",
156
+ oxlint: "catalog:",
157
+ turbo: "catalog:",
158
+ typescript: "catalog:",
159
+ },
160
+ engines: {
161
+ node: context.toolchain.nodeLtsMajor.value,
162
+ },
163
+ packageManager: context.toolchain.packageManagerPin.value,
164
+ };
165
+ }
166
+ function webPackageName(context) {
167
+ const webPackage = context.blueprint.packages?.find((pkg) => pkg.path === "apps/web");
168
+ return webPackage?.name ?? packageName(context.projectName.value);
169
+ }
170
+ function webPackageJson(context) {
171
+ return {
172
+ name: webPackageName(context),
173
+ version: "0.0.0",
174
+ private: true,
175
+ type: "module",
176
+ scripts: projectVueAppPackageScripts(),
177
+ dependencies: {
178
+ "@vueuse/core": "catalog:",
179
+ pinia: "catalog:",
180
+ vue: "catalog:",
181
+ },
182
+ devDependencies: {
183
+ "@playwright/test": "catalog:",
184
+ "@tailwindcss/vite": "catalog:",
185
+ "@types/node": "catalog:",
186
+ "@types/web-bluetooth": "catalog:",
187
+ "@vitejs/plugin-vue": "catalog:",
188
+ "@vue/tsconfig": "catalog:",
189
+ oxfmt: "catalog:",
190
+ oxlint: "catalog:",
191
+ tailwindcss: "catalog:",
192
+ typescript: "catalog:",
193
+ vite: "catalog:",
194
+ vitest: "catalog:",
195
+ "vue-tsc": "catalog:",
196
+ },
197
+ engines: {
198
+ node: context.toolchain.nodeLtsMajor.value,
199
+ },
200
+ };
201
+ }
202
+ function generationRecord(context) {
203
+ return {
204
+ ...generatedBy,
205
+ toolchain: {
206
+ nodeLtsMajor: context.toolchain.nodeLtsMajor.value,
207
+ packageManagerPin: context.toolchain.packageManagerPin.value,
208
+ source: context.toolchain.source,
209
+ },
210
+ };
211
+ }
212
+ function operationsForVueApp(context, packageScripts, checkPlan) {
213
+ const editorCustomization = editorCustomizationForCapabilities([
214
+ "oxc-format-lint",
215
+ "vue",
216
+ "tailwind",
217
+ "vitest",
218
+ ]);
219
+ const developmentContainer = checkedDockerfileFirstNodePnpmDevcontainer({
220
+ name: context.projectName.value,
221
+ layer: nodePnpmToolLayer({
222
+ nodeVersion: context.toolchain.nodeLtsMajor.value,
223
+ packageManagerPin: context.toolchain.packageManagerPin.value,
224
+ }),
225
+ additionalLayers: [browserTestToolLayer()],
226
+ extensions: editorCustomization.extensions,
227
+ settings: editorCustomization.settings,
228
+ });
229
+ const rootManifest = rootPackageJson(context, packageScripts);
230
+ const webManifest = webPackageJson(context);
231
+ return [
232
+ {
233
+ kind: "writeJson",
234
+ to: "package.json",
235
+ value: rootManifest,
236
+ },
237
+ {
238
+ kind: "writeText",
239
+ to: "pnpm-workspace.yaml",
240
+ text: renderGeneratedPnpmWorkspaceYaml({
241
+ packages: ["apps/*"],
242
+ dependencies: collectGeneratedManifestCatalogDependencies([
243
+ rootManifest,
244
+ webManifest,
245
+ ]),
246
+ allowBuilds: {
247
+ esbuild: true,
248
+ },
249
+ }),
250
+ },
251
+ {
252
+ kind: "writeJson",
253
+ to: "turbo.json",
254
+ value: {
255
+ tasks: {
256
+ build: {
257
+ dependsOn: ["^build"],
258
+ outputs: ["dist/**"],
259
+ },
260
+ check: {
261
+ dependsOn: ["^build"],
262
+ },
263
+ dev: {
264
+ cache: false,
265
+ persistent: true,
266
+ },
267
+ fix: {
268
+ cache: false,
269
+ },
270
+ },
271
+ },
272
+ },
273
+ {
274
+ kind: "writeJson",
275
+ to: "tsconfig.json",
276
+ value: {
277
+ files: [],
278
+ references: [
279
+ { path: "./apps/web/tsconfig.app.json" },
280
+ { path: "./apps/web/tsconfig.test.json" },
281
+ { path: "./apps/web/tsconfig.node.json" },
282
+ ],
283
+ },
284
+ },
285
+ {
286
+ kind: "writeJson",
287
+ to: "tsconfig.config.json",
288
+ value: {
289
+ compilerOptions: {
290
+ module: "NodeNext",
291
+ moduleResolution: "NodeNext",
292
+ noEmitOnError: true,
293
+ skipLibCheck: false,
294
+ strict: true,
295
+ target: "ES2022",
296
+ },
297
+ include: ["oxlint.config.ts", "oxfmt.config.ts"],
298
+ },
299
+ },
300
+ {
301
+ kind: "writeJson",
302
+ to: "apps/web/package.json",
303
+ value: webManifest,
304
+ },
305
+ {
306
+ kind: "writeJson",
307
+ to: "apps/web/tsconfig.json",
308
+ value: {
309
+ files: [],
310
+ references: [
311
+ { path: "./tsconfig.app.json" },
312
+ { path: "./tsconfig.test.json" },
313
+ { path: "./tsconfig.node.json" },
314
+ ],
315
+ },
316
+ },
317
+ {
318
+ kind: "writeJson",
319
+ to: "apps/web/tsconfig.app.json",
320
+ value: {
321
+ extends: "@vue/tsconfig/tsconfig.dom.json",
322
+ compilerOptions: {
323
+ composite: true,
324
+ module: "ESNext",
325
+ moduleResolution: "Bundler",
326
+ noEmitOnError: true,
327
+ paths: {
328
+ "@/*": ["./src/*"],
329
+ },
330
+ skipLibCheck: false,
331
+ strict: true,
332
+ target: "ES2022",
333
+ tsBuildInfoFile: "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
334
+ types: ["web-bluetooth"],
335
+ },
336
+ include: ["env.d.ts", "src/**/*.ts", "src/**/*.vue"],
337
+ },
338
+ },
339
+ {
340
+ kind: "writeJson",
341
+ to: "apps/web/tsconfig.test.json",
342
+ value: {
343
+ extends: "./tsconfig.app.json",
344
+ compilerOptions: {
345
+ lib: ["ESNext", "DOM", "DOM.Iterable"],
346
+ tsBuildInfoFile: "./node_modules/.tmp/tsconfig.test.tsbuildinfo",
347
+ types: ["node", "vitest/globals", "web-bluetooth"],
348
+ },
349
+ include: ["env.d.ts", "src/**/*.ts", "src/**/*.vue", "test/**/*.ts"],
350
+ },
351
+ },
352
+ {
353
+ kind: "writeJson",
354
+ to: "apps/web/tsconfig.node.json",
355
+ value: {
356
+ compilerOptions: {
357
+ composite: true,
358
+ module: "ESNext",
359
+ moduleResolution: "Bundler",
360
+ noEmitOnError: true,
361
+ lib: ["ESNext", "DOM", "DOM.Iterable"],
362
+ skipLibCheck: false,
363
+ strict: true,
364
+ target: "ES2022",
365
+ tsBuildInfoFile: "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
366
+ types: ["node"],
367
+ },
368
+ include: ["playwright.config.ts", "vite.config.ts", "vitest.config.ts"],
369
+ },
370
+ },
371
+ {
372
+ kind: "copyFile",
373
+ sourceRoot: "sharedOxc",
374
+ from: "vue/oxlint.config.ts",
375
+ to: "oxlint.config.ts",
376
+ },
377
+ {
378
+ kind: "copyFile",
379
+ sourceRoot: "sharedOxc",
380
+ from: "oxfmt.config.ts",
381
+ to: "oxfmt.config.ts",
382
+ },
383
+ {
384
+ kind: "writeText",
385
+ to: ".gitignore",
386
+ text: [
387
+ "node_modules",
388
+ "dist",
389
+ "playwright-report",
390
+ "test-results",
391
+ ".env",
392
+ ".template/",
393
+ ".pnpm-store/",
394
+ "",
395
+ ].join("\n"),
396
+ },
397
+ { kind: "copyFile", from: "env.d.ts", to: "apps/web/env.d.ts" },
398
+ { kind: "copyFile", from: "index.html", to: "apps/web/index.html" },
399
+ {
400
+ kind: "copyFile",
401
+ from: "playwright.config.ts",
402
+ to: "apps/web/playwright.config.ts",
403
+ },
404
+ { kind: "copyFile", from: "vite.config.ts", to: "apps/web/vite.config.ts" },
405
+ {
406
+ kind: "copyFile",
407
+ from: "vitest.config.ts",
408
+ to: "apps/web/vitest.config.ts",
409
+ },
410
+ { kind: "copyFile", from: "src/App.vue", to: "apps/web/src/App.vue" },
411
+ { kind: "copyFile", from: "src/main.ts", to: "apps/web/src/main.ts" },
412
+ { kind: "copyFile", from: "src/style.css", to: "apps/web/src/style.css" },
413
+ {
414
+ kind: "copyFile",
415
+ from: "src/stores/counter.ts",
416
+ to: "apps/web/src/stores/counter.ts",
417
+ },
418
+ {
419
+ kind: "copyFile",
420
+ from: "test/app.test.ts",
421
+ to: "apps/web/test/app.test.ts",
422
+ },
423
+ {
424
+ kind: "copyFile",
425
+ from: "test/e2e/app.spec.ts",
426
+ to: "apps/web/test/e2e/app.spec.ts",
427
+ },
428
+ {
429
+ kind: "writeJson",
430
+ to: ".template/blueprint.json",
431
+ value: context.blueprint,
432
+ },
433
+ {
434
+ kind: "writeJson",
435
+ to: ".template/generated-by.json",
436
+ value: generationRecord(context),
437
+ },
438
+ {
439
+ kind: "writeJson",
440
+ to: ".devcontainer/devcontainer.json",
441
+ value: developmentContainer.devcontainer,
442
+ },
443
+ {
444
+ ...developmentContainer.dockerfileOperation,
445
+ },
446
+ {
447
+ kind: "writeJson",
448
+ to: ".vscode/extensions.json",
449
+ value: {
450
+ recommendations: editorCustomization.extensions,
451
+ },
452
+ multilineArrays: ["recommendations"],
453
+ },
454
+ {
455
+ kind: "writeJson",
456
+ to: ".vscode/settings.json",
457
+ value: editorCustomization.settings,
458
+ },
459
+ {
460
+ kind: "copyFile",
461
+ from: ".github/workflows/check.yml",
462
+ to: ".github/workflows/check.yml",
463
+ },
464
+ {
465
+ kind: "copyFile",
466
+ from: ".github/dependabot.yml",
467
+ to: ".github/dependabot.yml",
468
+ },
469
+ ];
470
+ }
471
+ function isNodeError(error) {
472
+ return error instanceof Error && "code" in error;
473
+ }
474
+ function localPortsFromText(text) {
475
+ return [
476
+ ...text.matchAll(/port:\s*(\d+)/g),
477
+ ...text.matchAll(/--port\s+(\d+)/g),
478
+ ...text.matchAll(/https?:\/\/(?:localhost|127\.0\.0\.1):(\d+)/g),
479
+ ].map((match) => Number(match[1]));
480
+ }
481
+ async function usedPlaywrightPorts(root, blueprint) {
482
+ const ports = new Set();
483
+ for (const projectPackage of blueprint.packages ?? []) {
484
+ try {
485
+ const configText = await readFile(path.join(root, projectPackage.path, "playwright.config.ts"), "utf8");
486
+ for (const port of localPortsFromText(configText)) {
487
+ ports.add(port);
488
+ }
489
+ }
490
+ catch (error) {
491
+ if (!isNodeError(error) || error.code !== "ENOENT") {
492
+ throw error;
493
+ }
494
+ }
495
+ }
496
+ return ports;
497
+ }
498
+ async function nextVuePreviewPort(root, blueprint) {
499
+ const usedPorts = await usedPlaywrightPorts(root, blueprint);
500
+ let port = 4173;
501
+ while (usedPorts.has(port)) {
502
+ port += 1;
503
+ }
504
+ return port;
505
+ }
506
+ function vueAppPlaywrightConfig(previewPort) {
507
+ return `import { defineConfig, devices } from "@playwright/test";
508
+
509
+ const previewUrl = "http://127.0.0.1:${previewPort}";
510
+
511
+ export default defineConfig({
512
+ testDir: "./test/e2e",
513
+ use: {
514
+ baseURL: previewUrl,
515
+ trace: "on-first-retry"
516
+ },
517
+ webServer: {
518
+ command: "pnpm run preview --host 127.0.0.1 --port ${previewPort}",
519
+ reuseExistingServer: !process.env.CI,
520
+ url: previewUrl
521
+ },
522
+ projects: [
523
+ {
524
+ name: "chromium",
525
+ use: { ...devices["Desktop Chrome"] }
526
+ }
527
+ ]
528
+ });
529
+ `;
530
+ }
531
+ function packageAdditionOperations(packagePath, packageName, nodeVersion) {
532
+ return [
533
+ {
534
+ kind: "writeJson",
535
+ to: `${packagePath}/package.json`,
536
+ value: {
537
+ name: packageName,
538
+ version: "0.0.0",
539
+ private: true,
540
+ type: "module",
541
+ scripts: projectVueAppPackageScripts(),
542
+ dependencies: {
543
+ "@vueuse/core": "catalog:",
544
+ pinia: "catalog:",
545
+ vue: "catalog:",
546
+ },
547
+ devDependencies: {
548
+ "@playwright/test": "catalog:",
549
+ "@tailwindcss/vite": "catalog:",
550
+ "@types/node": "catalog:",
551
+ "@types/web-bluetooth": "catalog:",
552
+ "@vitejs/plugin-vue": "catalog:",
553
+ "@vue/tsconfig": "catalog:",
554
+ oxfmt: "catalog:",
555
+ oxlint: "catalog:",
556
+ tailwindcss: "catalog:",
557
+ typescript: "catalog:",
558
+ vite: "catalog:",
559
+ vitest: "catalog:",
560
+ "vue-tsc": "catalog:",
561
+ },
562
+ engines: {
563
+ node: nodeVersion,
564
+ },
565
+ },
566
+ },
567
+ {
568
+ kind: "writeJson",
569
+ to: `${packagePath}/tsconfig.json`,
570
+ value: {
571
+ files: [],
572
+ references: [
573
+ { path: "./tsconfig.app.json" },
574
+ { path: "./tsconfig.test.json" },
575
+ { path: "./tsconfig.node.json" },
576
+ ],
577
+ },
578
+ },
579
+ {
580
+ kind: "writeJson",
581
+ to: `${packagePath}/tsconfig.app.json`,
582
+ value: {
583
+ extends: "@vue/tsconfig/tsconfig.dom.json",
584
+ compilerOptions: {
585
+ composite: true,
586
+ module: "ESNext",
587
+ moduleResolution: "Bundler",
588
+ noEmitOnError: true,
589
+ paths: {
590
+ "@/*": ["./src/*"],
591
+ },
592
+ skipLibCheck: false,
593
+ strict: true,
594
+ target: "ES2022",
595
+ tsBuildInfoFile: "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
596
+ types: ["web-bluetooth"],
597
+ },
598
+ include: ["env.d.ts", "src/**/*.ts", "src/**/*.vue"],
599
+ },
600
+ },
601
+ {
602
+ kind: "writeJson",
603
+ to: `${packagePath}/tsconfig.test.json`,
604
+ value: {
605
+ extends: "./tsconfig.app.json",
606
+ compilerOptions: {
607
+ lib: ["ESNext", "DOM", "DOM.Iterable"],
608
+ tsBuildInfoFile: "./node_modules/.tmp/tsconfig.test.tsbuildinfo",
609
+ types: ["node", "vitest/globals", "web-bluetooth"],
610
+ },
611
+ include: ["env.d.ts", "src/**/*.ts", "src/**/*.vue", "test/**/*.ts"],
612
+ },
613
+ },
614
+ {
615
+ kind: "writeJson",
616
+ to: `${packagePath}/tsconfig.node.json`,
617
+ value: {
618
+ compilerOptions: {
619
+ composite: true,
620
+ module: "ESNext",
621
+ moduleResolution: "Bundler",
622
+ noEmitOnError: true,
623
+ lib: ["ESNext", "DOM", "DOM.Iterable"],
624
+ skipLibCheck: false,
625
+ strict: true,
626
+ target: "ES2022",
627
+ tsBuildInfoFile: "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
628
+ types: ["node"],
629
+ },
630
+ include: ["playwright.config.ts", "vite.config.ts", "vitest.config.ts"],
631
+ },
632
+ },
633
+ { kind: "copyFile", from: "env.d.ts", to: `${packagePath}/env.d.ts` },
634
+ { kind: "copyFile", from: "index.html", to: `${packagePath}/index.html` },
635
+ {
636
+ kind: "copyFile",
637
+ from: "playwright.config.ts",
638
+ to: `${packagePath}/playwright.config.ts`,
639
+ },
640
+ {
641
+ kind: "copyFile",
642
+ from: "vite.config.ts",
643
+ to: `${packagePath}/vite.config.ts`,
644
+ },
645
+ {
646
+ kind: "copyFile",
647
+ from: "vitest.config.ts",
648
+ to: `${packagePath}/vitest.config.ts`,
649
+ },
650
+ { kind: "copyFile", from: "src/App.vue", to: `${packagePath}/src/App.vue` },
651
+ { kind: "copyFile", from: "src/main.ts", to: `${packagePath}/src/main.ts` },
652
+ {
653
+ kind: "copyFile",
654
+ from: "src/style.css",
655
+ to: `${packagePath}/src/style.css`,
656
+ },
657
+ {
658
+ kind: "copyFile",
659
+ from: "src/stores/counter.ts",
660
+ to: `${packagePath}/src/stores/counter.ts`,
661
+ },
662
+ {
663
+ kind: "copyFile",
664
+ from: "test/app.test.ts",
665
+ to: `${packagePath}/test/app.test.ts`,
666
+ },
667
+ {
668
+ kind: "copyFile",
669
+ from: "test/e2e/app.spec.ts",
670
+ to: `${packagePath}/test/e2e/app.spec.ts`,
671
+ },
672
+ ];
673
+ }
674
+ async function packageAdditionPlan({ root, blueprint, packageName, packagePath, nodeVersion, }) {
675
+ const [workspaceCollection] = packagePath.split("/");
676
+ const previewPort = await nextVuePreviewPort(root, blueprint);
677
+ return {
678
+ packagePath,
679
+ workspacePackageGlob: `${workspaceCollection}/*`,
680
+ rootTsconfigReferences: [
681
+ `./${packagePath}/tsconfig.app.json`,
682
+ `./${packagePath}/tsconfig.test.json`,
683
+ `./${packagePath}/tsconfig.node.json`,
684
+ ],
685
+ sourceRoot: templateSourceRoot(),
686
+ sourceRoots: { sharedOxc: sharedOxcSourceRoot() },
687
+ operations: packageAdditionOperations(packagePath, packageName, nodeVersion),
688
+ textFiles: [
689
+ {
690
+ path: `${packagePath}/playwright.config.ts`,
691
+ text: vueAppPlaywrightConfig(previewPort),
692
+ },
693
+ ],
694
+ };
695
+ }
696
+ function templateSourceRoot() {
697
+ const projectionDir = path.dirname(fileURLToPath(import.meta.url));
698
+ const publishedTemplateRoot = path.join(projectionDir, "..", "..", "..", "templates", "vue-app");
699
+ return existsSync(path.join(publishedTemplateRoot, "src", "App.vue"))
700
+ ? publishedTemplateRoot
701
+ : projectionDir;
702
+ }
703
+ function sharedOxcSourceRoot() {
704
+ const projectionDir = path.dirname(fileURLToPath(import.meta.url));
705
+ const publishedSharedRoot = path.join(projectionDir, "..", "..", "..", "templates", "shared", "oxc");
706
+ return existsSync(path.join(publishedSharedRoot, "oxfmt.config.ts"))
707
+ ? publishedSharedRoot
708
+ : path.join(projectionDir, "..", "shared", "oxc");
709
+ }
710
+ function sharedDevcontainerSourceRoot() {
711
+ const projectionDir = path.dirname(fileURLToPath(import.meta.url));
712
+ const publishedSharedRoot = path.join(projectionDir, "..", "..", "..", "templates", "shared", "devcontainer");
713
+ return existsSync(path.join(publishedSharedRoot, "node-pnpm.Dockerfile"))
714
+ ? publishedSharedRoot
715
+ : path.join(projectionDir, "..", "shared", "devcontainer");
716
+ }
717
+ export const vueAppPresetProjection = {
718
+ metadata: vueAppPresetMetadata,
719
+ capabilities: {
720
+ packageAddition: {
721
+ planPackageAddition: packageAdditionPlan,
722
+ },
723
+ },
724
+ blueprint: vueAppBlueprint,
725
+ project(context) {
726
+ const checkPlan = planVueAppRootChecks();
727
+ const fixPlan = planVueAppRootFixes();
728
+ const packageScripts = projectVueAppRootPackageScripts();
729
+ return {
730
+ sourceRoot: templateSourceRoot(),
731
+ sourceRoots: {
732
+ sharedDevcontainer: sharedDevcontainerSourceRoot(),
733
+ sharedOxc: sharedOxcSourceRoot(),
734
+ },
735
+ operations: operationsForVueApp(context, packageScripts, checkPlan),
736
+ checkPlan,
737
+ fixPlan,
738
+ dependencyMaintenancePolicy,
739
+ packageScripts,
740
+ capabilities: {
741
+ rootCheck: true,
742
+ fixCommand: true,
743
+ githubActions: true,
744
+ dependabot: true,
745
+ devcontainer: true,
746
+ },
747
+ };
748
+ },
749
+ async render({ targetDir, plan }) {
750
+ await renderNewProject({
751
+ sourceRoot: plan.sourceRoot,
752
+ sourceRoots: plan.sourceRoots,
753
+ targetRoot: targetDir,
754
+ operations: [...plan.operations],
755
+ });
756
+ },
757
+ };