@ykdz/template 0.0.0
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.
- package/LICENSE +21 -0
- package/README.md +35 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +353 -0
- package/dist/declarations.d.ts +166 -0
- package/dist/declarations.d.ts.map +1 -0
- package/dist/declarations.js +340 -0
- package/dist/hono-api.d.ts +2 -0
- package/dist/hono-api.d.ts.map +1 -0
- package/dist/hono-api.js +247 -0
- package/dist/package-addition.d.ts +7 -0
- package/dist/package-addition.d.ts.map +1 -0
- package/dist/package-addition.js +580 -0
- package/dist/renderer.d.ts +44 -0
- package/dist/renderer.d.ts.map +1 -0
- package/dist/renderer.js +379 -0
- package/dist/rust-bin.d.ts +2 -0
- package/dist/rust-bin.d.ts.map +1 -0
- package/dist/rust-bin.js +206 -0
- package/dist/ts-lib.d.ts +2 -0
- package/dist/ts-lib.d.ts.map +1 -0
- package/dist/ts-lib.js +220 -0
- package/dist/vue-app.d.ts +2 -0
- package/dist/vue-app.d.ts.map +1 -0
- package/dist/vue-app.js +339 -0
- package/dist/vue-hono-app.d.ts +4 -0
- package/dist/vue-hono-app.d.ts.map +1 -0
- package/dist/vue-hono-app.js +484 -0
- package/package.json +54 -0
- package/templates/hono-api/src/app.ts +5 -0
- package/templates/hono-api/src/server.ts +14 -0
- package/templates/hono-api/test/app.test.ts +10 -0
- package/templates/hono-api/vitest.config.ts +13 -0
- package/templates/rust-bin/src/main.rs +18 -0
- package/templates/ts-lib/src/index.ts +7 -0
- package/templates/vue-app/env.d.ts +1 -0
- package/templates/vue-app/index.html +12 -0
- package/templates/vue-app/playwright.config.ts +20 -0
- package/templates/vue-app/src/App.vue +33 -0
- package/templates/vue-app/src/main.ts +6 -0
- package/templates/vue-app/src/stores/counter.ts +12 -0
- package/templates/vue-app/src/style.css +1 -0
- package/templates/vue-app/test/app.test.ts +13 -0
- package/templates/vue-app/test/e2e/app.spec.ts +9 -0
- package/templates/vue-app/vite.config.ts +13 -0
- package/templates/vue-app/vitest.config.ts +14 -0
- package/templates/vue-hono-app/api/src/index.ts +3 -0
- package/templates/vue-hono-app/api/src/runtime.ts +5 -0
- package/templates/vue-hono-app/api/src/server.ts +14 -0
- package/templates/vue-hono-app/api/test/app.test.ts +10 -0
- package/templates/vue-hono-app/api/vitest.config.ts +7 -0
- package/templates/vue-hono-app/web/env.d.ts +9 -0
- package/templates/vue-hono-app/web/index.html +12 -0
- package/templates/vue-hono-app/web/playwright.config.ts +21 -0
- package/templates/vue-hono-app/web/src/App.vue +42 -0
- package/templates/vue-hono-app/web/src/api.ts +8 -0
- package/templates/vue-hono-app/web/src/main.ts +6 -0
- package/templates/vue-hono-app/web/src/stores/counter.ts +12 -0
- package/templates/vue-hono-app/web/src/style.css +1 -0
- package/templates/vue-hono-app/web/test/app.test.ts +13 -0
- package/templates/vue-hono-app/web/test/e2e/app.spec.ts +10 -0
- package/templates/vue-hono-app/web/vite.config.ts +29 -0
- package/templates/vue-hono-app/web/vitest.config.ts +16 -0
|
@@ -0,0 +1,580 @@
|
|
|
1
|
+
import { mkdir, readFile, stat, writeFile } from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { fileURLToPath } from "node:url";
|
|
4
|
+
import { renderProject } from "./renderer.js";
|
|
5
|
+
import { validateProjectBlueprint } from "./declarations.js";
|
|
6
|
+
function projectNameFromBlueprint(blueprint) {
|
|
7
|
+
const firstPackage = blueprint.packages?.[0];
|
|
8
|
+
const match = firstPackage?.name.match(/^@([^/]+)\//);
|
|
9
|
+
if (!match) {
|
|
10
|
+
throw new Error("Cannot infer workspace package scope from the stored Project Blueprint");
|
|
11
|
+
}
|
|
12
|
+
return match[1];
|
|
13
|
+
}
|
|
14
|
+
function assertSafePackageLeaf(name) {
|
|
15
|
+
if (!/^[a-z0-9][a-z0-9-]*$/.test(name)) {
|
|
16
|
+
throw new Error("--name must be a lowercase package leaf name using letters, numbers, and hyphens");
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
async function readJson(filePath) {
|
|
20
|
+
return JSON.parse(await readFile(filePath, "utf8"));
|
|
21
|
+
}
|
|
22
|
+
async function writeJson(filePath, value) {
|
|
23
|
+
await writeFile(filePath, `${JSON.stringify(value, null, 2)}\n`, "utf8");
|
|
24
|
+
}
|
|
25
|
+
async function assertMissing(targetPath) {
|
|
26
|
+
try {
|
|
27
|
+
await stat(targetPath);
|
|
28
|
+
}
|
|
29
|
+
catch (error) {
|
|
30
|
+
if (isNodeError(error) && error.code === "ENOENT") {
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
throw error;
|
|
34
|
+
}
|
|
35
|
+
throw new Error(`Package Addition would overwrite an existing path: ${targetPath}`);
|
|
36
|
+
}
|
|
37
|
+
function isNodeError(error) {
|
|
38
|
+
return error instanceof Error && "code" in error;
|
|
39
|
+
}
|
|
40
|
+
function isRecord(value) {
|
|
41
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
42
|
+
}
|
|
43
|
+
function tsLibPackageJson(packageName) {
|
|
44
|
+
return {
|
|
45
|
+
name: packageName,
|
|
46
|
+
version: "0.0.0",
|
|
47
|
+
private: true,
|
|
48
|
+
files: ["dist"],
|
|
49
|
+
type: "module",
|
|
50
|
+
exports: {
|
|
51
|
+
".": {
|
|
52
|
+
default: "./dist/index.js",
|
|
53
|
+
types: "./dist/index.d.ts"
|
|
54
|
+
}
|
|
55
|
+
},
|
|
56
|
+
scripts: {
|
|
57
|
+
build: "tsc -p tsconfig.json && tsc-alias -p tsconfig.json",
|
|
58
|
+
check: "pnpm run typecheck && pnpm run lint && pnpm run format:check",
|
|
59
|
+
fix: "pnpm run format:write && pnpm run lint:fix",
|
|
60
|
+
"format:check": "oxfmt --check .",
|
|
61
|
+
"format:write": "oxfmt --write .",
|
|
62
|
+
lint: "oxlint . --deny-warnings",
|
|
63
|
+
"lint:fix": "oxlint . --fix --deny-warnings",
|
|
64
|
+
typecheck: "tsc -p tsconfig.json --noEmit"
|
|
65
|
+
},
|
|
66
|
+
devDependencies: {
|
|
67
|
+
"@types/node": "catalog:",
|
|
68
|
+
oxfmt: "catalog:",
|
|
69
|
+
oxlint: "catalog:",
|
|
70
|
+
"tsc-alias": "catalog:",
|
|
71
|
+
typescript: "catalog:"
|
|
72
|
+
},
|
|
73
|
+
engines: {
|
|
74
|
+
node: ">=22.0.0"
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
function tsLibPackageOperations(packagePath, packageName) {
|
|
79
|
+
return [
|
|
80
|
+
{
|
|
81
|
+
kind: "writeJson",
|
|
82
|
+
to: `${packagePath}/package.json`,
|
|
83
|
+
value: tsLibPackageJson(packageName),
|
|
84
|
+
multilineArrays: ["files"]
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
kind: "writeJson",
|
|
88
|
+
to: `${packagePath}/tsconfig.json`,
|
|
89
|
+
value: {
|
|
90
|
+
compilerOptions: {
|
|
91
|
+
composite: true,
|
|
92
|
+
declaration: true,
|
|
93
|
+
declarationMap: true,
|
|
94
|
+
module: "NodeNext",
|
|
95
|
+
moduleResolution: "NodeNext",
|
|
96
|
+
noEmitOnError: true,
|
|
97
|
+
outDir: "dist",
|
|
98
|
+
paths: {
|
|
99
|
+
"@/*": ["./src/*"]
|
|
100
|
+
},
|
|
101
|
+
rootDir: "src",
|
|
102
|
+
skipLibCheck: false,
|
|
103
|
+
strict: true,
|
|
104
|
+
target: "ES2022",
|
|
105
|
+
types: ["node"]
|
|
106
|
+
},
|
|
107
|
+
include: ["src/**/*.ts"]
|
|
108
|
+
}
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
kind: "writeJson",
|
|
112
|
+
to: `${packagePath}/.oxlintrc.json`,
|
|
113
|
+
value: {
|
|
114
|
+
categories: {
|
|
115
|
+
correctness: "error",
|
|
116
|
+
suspicious: "error"
|
|
117
|
+
},
|
|
118
|
+
plugins: ["typescript", "oxc"]
|
|
119
|
+
}
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
kind: "writeJson",
|
|
123
|
+
to: `${packagePath}/.oxfmtrc.json`,
|
|
124
|
+
value: {
|
|
125
|
+
printWidth: 100,
|
|
126
|
+
singleQuote: false,
|
|
127
|
+
trailingComma: "none"
|
|
128
|
+
}
|
|
129
|
+
},
|
|
130
|
+
{
|
|
131
|
+
kind: "copyFile",
|
|
132
|
+
from: "src/index.ts",
|
|
133
|
+
to: `${packagePath}/src/index.ts`
|
|
134
|
+
}
|
|
135
|
+
];
|
|
136
|
+
}
|
|
137
|
+
function honoApiPackageJson(packageName) {
|
|
138
|
+
return {
|
|
139
|
+
name: packageName,
|
|
140
|
+
version: "0.0.0",
|
|
141
|
+
private: true,
|
|
142
|
+
type: "module",
|
|
143
|
+
scripts: {
|
|
144
|
+
build: "tsc -p tsconfig.build.json && tsc-alias -p tsconfig.build.json",
|
|
145
|
+
check: "pnpm run format:check && pnpm run lint && pnpm run typecheck && pnpm run build && pnpm run test",
|
|
146
|
+
fix: "pnpm run format:write && pnpm run lint:fix",
|
|
147
|
+
"format:check": "oxfmt --check .",
|
|
148
|
+
"format:write": "oxfmt --write .",
|
|
149
|
+
lint: "oxlint . --deny-warnings",
|
|
150
|
+
"lint:fix": "oxlint . --fix --deny-warnings",
|
|
151
|
+
start: "node dist/server.js",
|
|
152
|
+
test: "vitest run",
|
|
153
|
+
typecheck: "tsc -p tsconfig.json --noEmit"
|
|
154
|
+
},
|
|
155
|
+
dependencies: {
|
|
156
|
+
"@hono/node-server": "catalog:",
|
|
157
|
+
hono: "catalog:"
|
|
158
|
+
},
|
|
159
|
+
devDependencies: {
|
|
160
|
+
"@types/node": "catalog:",
|
|
161
|
+
oxfmt: "catalog:",
|
|
162
|
+
oxlint: "catalog:",
|
|
163
|
+
"tsc-alias": "catalog:",
|
|
164
|
+
typescript: "catalog:",
|
|
165
|
+
vitest: "catalog:"
|
|
166
|
+
},
|
|
167
|
+
engines: {
|
|
168
|
+
node: ">=22.0.0"
|
|
169
|
+
}
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
function honoApiPackageOperations(packagePath, packageName) {
|
|
173
|
+
return [
|
|
174
|
+
{
|
|
175
|
+
kind: "writeJson",
|
|
176
|
+
to: `${packagePath}/package.json`,
|
|
177
|
+
value: honoApiPackageJson(packageName)
|
|
178
|
+
},
|
|
179
|
+
{
|
|
180
|
+
kind: "writeJson",
|
|
181
|
+
to: `${packagePath}/tsconfig.json`,
|
|
182
|
+
value: {
|
|
183
|
+
compilerOptions: {
|
|
184
|
+
composite: true,
|
|
185
|
+
module: "NodeNext",
|
|
186
|
+
moduleResolution: "NodeNext",
|
|
187
|
+
noEmitOnError: true,
|
|
188
|
+
paths: {
|
|
189
|
+
"@/*": ["./src/*"]
|
|
190
|
+
},
|
|
191
|
+
skipLibCheck: false,
|
|
192
|
+
strict: true,
|
|
193
|
+
target: "ES2022",
|
|
194
|
+
types: ["node", "vitest/globals"]
|
|
195
|
+
},
|
|
196
|
+
include: ["src/**/*.ts", "test/**/*.ts", "vitest.config.ts"]
|
|
197
|
+
}
|
|
198
|
+
},
|
|
199
|
+
{
|
|
200
|
+
kind: "writeJson",
|
|
201
|
+
to: `${packagePath}/tsconfig.build.json`,
|
|
202
|
+
value: {
|
|
203
|
+
extends: "./tsconfig.json",
|
|
204
|
+
compilerOptions: {
|
|
205
|
+
outDir: "dist",
|
|
206
|
+
rootDir: "src",
|
|
207
|
+
types: ["node"]
|
|
208
|
+
},
|
|
209
|
+
include: ["src/**/*.ts"]
|
|
210
|
+
}
|
|
211
|
+
},
|
|
212
|
+
{
|
|
213
|
+
kind: "writeJson",
|
|
214
|
+
to: `${packagePath}/.oxlintrc.json`,
|
|
215
|
+
value: {
|
|
216
|
+
categories: {
|
|
217
|
+
correctness: "error",
|
|
218
|
+
suspicious: "error"
|
|
219
|
+
},
|
|
220
|
+
plugins: ["typescript", "oxc"]
|
|
221
|
+
}
|
|
222
|
+
},
|
|
223
|
+
{
|
|
224
|
+
kind: "writeJson",
|
|
225
|
+
to: `${packagePath}/.oxfmtrc.json`,
|
|
226
|
+
value: {
|
|
227
|
+
printWidth: 100,
|
|
228
|
+
singleQuote: false,
|
|
229
|
+
trailingComma: "none"
|
|
230
|
+
}
|
|
231
|
+
},
|
|
232
|
+
{ kind: "copyFile", from: "src/app.ts", to: `${packagePath}/src/app.ts` },
|
|
233
|
+
{ kind: "copyFile", from: "src/server.ts", to: `${packagePath}/src/server.ts` },
|
|
234
|
+
{ kind: "copyFile", from: "test/app.test.ts", to: `${packagePath}/test/app.test.ts` },
|
|
235
|
+
{ kind: "copyFile", from: "vitest.config.ts", to: `${packagePath}/vitest.config.ts` }
|
|
236
|
+
];
|
|
237
|
+
}
|
|
238
|
+
function vueAppPackageJson(packageName) {
|
|
239
|
+
return {
|
|
240
|
+
name: packageName,
|
|
241
|
+
version: "0.0.0",
|
|
242
|
+
private: true,
|
|
243
|
+
type: "module",
|
|
244
|
+
scripts: {
|
|
245
|
+
build: "vite build",
|
|
246
|
+
check: "pnpm run format:check && pnpm run lint && pnpm run typecheck && pnpm run build && pnpm run test && pnpm run test:e2e",
|
|
247
|
+
dev: "vite",
|
|
248
|
+
fix: "pnpm run format:write && pnpm run lint:fix",
|
|
249
|
+
"format:check": "oxfmt --check .",
|
|
250
|
+
"format:write": "oxfmt --write .",
|
|
251
|
+
lint: "oxlint . --deny-warnings",
|
|
252
|
+
"lint:fix": "oxlint . --fix --deny-warnings",
|
|
253
|
+
preview: "vite preview",
|
|
254
|
+
test: "vitest run",
|
|
255
|
+
"test:e2e": "pnpm run build && playwright test",
|
|
256
|
+
typecheck: "vue-tsc --build --noEmit"
|
|
257
|
+
},
|
|
258
|
+
dependencies: {
|
|
259
|
+
"@vueuse/core": "catalog:",
|
|
260
|
+
pinia: "catalog:",
|
|
261
|
+
vue: "catalog:"
|
|
262
|
+
},
|
|
263
|
+
devDependencies: {
|
|
264
|
+
"@playwright/test": "catalog:",
|
|
265
|
+
"@tailwindcss/vite": "catalog:",
|
|
266
|
+
"@types/node": "catalog:",
|
|
267
|
+
"@types/web-bluetooth": "catalog:",
|
|
268
|
+
"@vitejs/plugin-vue": "catalog:",
|
|
269
|
+
"@vue/tsconfig": "catalog:",
|
|
270
|
+
oxfmt: "catalog:",
|
|
271
|
+
oxlint: "catalog:",
|
|
272
|
+
tailwindcss: "catalog:",
|
|
273
|
+
typescript: "catalog:",
|
|
274
|
+
vite: "catalog:",
|
|
275
|
+
vitest: "catalog:",
|
|
276
|
+
"vue-tsc": "catalog:"
|
|
277
|
+
},
|
|
278
|
+
engines: {
|
|
279
|
+
node: ">=22.0.0"
|
|
280
|
+
}
|
|
281
|
+
};
|
|
282
|
+
}
|
|
283
|
+
function vueAppPackageOperations(packagePath, packageName) {
|
|
284
|
+
return [
|
|
285
|
+
{ kind: "writeJson", to: `${packagePath}/package.json`, value: vueAppPackageJson(packageName) },
|
|
286
|
+
{
|
|
287
|
+
kind: "writeJson",
|
|
288
|
+
to: `${packagePath}/tsconfig.json`,
|
|
289
|
+
value: {
|
|
290
|
+
files: [],
|
|
291
|
+
references: [
|
|
292
|
+
{ path: "./tsconfig.app.json" },
|
|
293
|
+
{ path: "./tsconfig.test.json" },
|
|
294
|
+
{ path: "./tsconfig.node.json" }
|
|
295
|
+
]
|
|
296
|
+
}
|
|
297
|
+
},
|
|
298
|
+
{
|
|
299
|
+
kind: "writeJson",
|
|
300
|
+
to: `${packagePath}/tsconfig.app.json`,
|
|
301
|
+
value: {
|
|
302
|
+
extends: "@vue/tsconfig/tsconfig.dom.json",
|
|
303
|
+
compilerOptions: {
|
|
304
|
+
baseUrl: ".",
|
|
305
|
+
composite: true,
|
|
306
|
+
module: "ESNext",
|
|
307
|
+
moduleResolution: "Bundler",
|
|
308
|
+
noEmitOnError: true,
|
|
309
|
+
paths: {
|
|
310
|
+
"@/*": ["./src/*"]
|
|
311
|
+
},
|
|
312
|
+
skipLibCheck: false,
|
|
313
|
+
strict: true,
|
|
314
|
+
target: "ES2022",
|
|
315
|
+
tsBuildInfoFile: "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
|
|
316
|
+
types: ["web-bluetooth"]
|
|
317
|
+
},
|
|
318
|
+
include: ["env.d.ts", "src/**/*.ts", "src/**/*.vue"]
|
|
319
|
+
}
|
|
320
|
+
},
|
|
321
|
+
{
|
|
322
|
+
kind: "writeJson",
|
|
323
|
+
to: `${packagePath}/tsconfig.test.json`,
|
|
324
|
+
value: {
|
|
325
|
+
extends: "./tsconfig.app.json",
|
|
326
|
+
compilerOptions: {
|
|
327
|
+
lib: ["ESNext", "DOM", "DOM.Iterable"],
|
|
328
|
+
tsBuildInfoFile: "./node_modules/.tmp/tsconfig.test.tsbuildinfo",
|
|
329
|
+
types: ["node", "vitest/globals", "web-bluetooth"]
|
|
330
|
+
},
|
|
331
|
+
include: ["env.d.ts", "src/**/*.ts", "src/**/*.vue", "test/**/*.ts"]
|
|
332
|
+
}
|
|
333
|
+
},
|
|
334
|
+
{
|
|
335
|
+
kind: "writeJson",
|
|
336
|
+
to: `${packagePath}/tsconfig.node.json`,
|
|
337
|
+
value: {
|
|
338
|
+
compilerOptions: {
|
|
339
|
+
composite: true,
|
|
340
|
+
module: "ESNext",
|
|
341
|
+
moduleResolution: "Bundler",
|
|
342
|
+
noEmitOnError: true,
|
|
343
|
+
lib: ["ESNext", "DOM", "DOM.Iterable"],
|
|
344
|
+
skipLibCheck: false,
|
|
345
|
+
strict: true,
|
|
346
|
+
target: "ES2022",
|
|
347
|
+
tsBuildInfoFile: "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
|
|
348
|
+
types: ["node"]
|
|
349
|
+
},
|
|
350
|
+
include: ["playwright.config.ts", "vite.config.ts", "vitest.config.ts"]
|
|
351
|
+
}
|
|
352
|
+
},
|
|
353
|
+
{
|
|
354
|
+
kind: "writeJson",
|
|
355
|
+
to: `${packagePath}/.oxlintrc.json`,
|
|
356
|
+
value: {
|
|
357
|
+
categories: {
|
|
358
|
+
correctness: "error",
|
|
359
|
+
suspicious: "error"
|
|
360
|
+
},
|
|
361
|
+
plugins: ["typescript", "oxc", "vue"]
|
|
362
|
+
}
|
|
363
|
+
},
|
|
364
|
+
{
|
|
365
|
+
kind: "writeJson",
|
|
366
|
+
to: `${packagePath}/.oxfmtrc.json`,
|
|
367
|
+
value: {
|
|
368
|
+
printWidth: 100,
|
|
369
|
+
singleQuote: false,
|
|
370
|
+
trailingComma: "none"
|
|
371
|
+
}
|
|
372
|
+
},
|
|
373
|
+
{ kind: "copyFile", from: "env.d.ts", to: `${packagePath}/env.d.ts` },
|
|
374
|
+
{ kind: "copyFile", from: "index.html", to: `${packagePath}/index.html` },
|
|
375
|
+
{ kind: "copyFile", from: "playwright.config.ts", to: `${packagePath}/playwright.config.ts` },
|
|
376
|
+
{ kind: "copyFile", from: "vite.config.ts", to: `${packagePath}/vite.config.ts` },
|
|
377
|
+
{ kind: "copyFile", from: "vitest.config.ts", to: `${packagePath}/vitest.config.ts` },
|
|
378
|
+
{ kind: "copyFile", from: "src/App.vue", to: `${packagePath}/src/App.vue` },
|
|
379
|
+
{ kind: "copyFile", from: "src/main.ts", to: `${packagePath}/src/main.ts` },
|
|
380
|
+
{ kind: "copyFile", from: "src/style.css", to: `${packagePath}/src/style.css` },
|
|
381
|
+
{ kind: "copyFile", from: "src/stores/counter.ts", to: `${packagePath}/src/stores/counter.ts` },
|
|
382
|
+
{ kind: "copyFile", from: "test/app.test.ts", to: `${packagePath}/test/app.test.ts` },
|
|
383
|
+
{ kind: "copyFile", from: "test/e2e/app.spec.ts", to: `${packagePath}/test/e2e/app.spec.ts` }
|
|
384
|
+
];
|
|
385
|
+
}
|
|
386
|
+
function packagePathForPreset(preset, name) {
|
|
387
|
+
if (preset === "ts-lib") {
|
|
388
|
+
return `packages/${name}`;
|
|
389
|
+
}
|
|
390
|
+
if (preset === "hono-api" || preset === "vue-app") {
|
|
391
|
+
return `apps/${name}`;
|
|
392
|
+
}
|
|
393
|
+
throw new Error("Only the ts-lib, hono-api, and vue-app package presets are supported for Package Addition in this version");
|
|
394
|
+
}
|
|
395
|
+
function packageOperationsForPreset(preset, packagePath, packageName) {
|
|
396
|
+
if (preset === "ts-lib") {
|
|
397
|
+
return tsLibPackageOperations(packagePath, packageName);
|
|
398
|
+
}
|
|
399
|
+
if (preset === "hono-api") {
|
|
400
|
+
return honoApiPackageOperations(packagePath, packageName);
|
|
401
|
+
}
|
|
402
|
+
if (preset === "vue-app") {
|
|
403
|
+
return vueAppPackageOperations(packagePath, packageName);
|
|
404
|
+
}
|
|
405
|
+
throw new Error("Only the ts-lib, hono-api, and vue-app package presets are supported for Package Addition in this version");
|
|
406
|
+
}
|
|
407
|
+
function rootTsReferencesForPreset(preset, packagePath) {
|
|
408
|
+
if (preset === "vue-app") {
|
|
409
|
+
return [
|
|
410
|
+
`./${packagePath}/tsconfig.app.json`,
|
|
411
|
+
`./${packagePath}/tsconfig.test.json`,
|
|
412
|
+
`./${packagePath}/tsconfig.node.json`
|
|
413
|
+
];
|
|
414
|
+
}
|
|
415
|
+
return [`./${packagePath}/tsconfig.json`];
|
|
416
|
+
}
|
|
417
|
+
function templateSourceRoot(preset) {
|
|
418
|
+
return path.join(path.dirname(fileURLToPath(import.meta.url)), "..", "templates", preset);
|
|
419
|
+
}
|
|
420
|
+
function localPortsFromText(text) {
|
|
421
|
+
return [
|
|
422
|
+
...text.matchAll(/port:\s*(\d+)/g),
|
|
423
|
+
...text.matchAll(/--port\s+(\d+)/g),
|
|
424
|
+
...text.matchAll(/https?:\/\/(?:localhost|127\.0\.0\.1):(\d+)/g)
|
|
425
|
+
].map((match) => Number(match[1]));
|
|
426
|
+
}
|
|
427
|
+
async function usedPlaywrightPorts(root, blueprint) {
|
|
428
|
+
const ports = new Set();
|
|
429
|
+
for (const projectPackage of blueprint.packages ?? []) {
|
|
430
|
+
try {
|
|
431
|
+
const configText = await readFile(path.join(root, projectPackage.path, "playwright.config.ts"), "utf8");
|
|
432
|
+
for (const port of localPortsFromText(configText)) {
|
|
433
|
+
ports.add(port);
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
catch (error) {
|
|
437
|
+
if (!isNodeError(error) || error.code !== "ENOENT") {
|
|
438
|
+
throw error;
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
return ports;
|
|
443
|
+
}
|
|
444
|
+
async function nextVuePreviewPort(root, blueprint) {
|
|
445
|
+
const usedPorts = await usedPlaywrightPorts(root, blueprint);
|
|
446
|
+
let port = 4173;
|
|
447
|
+
while (usedPorts.has(port)) {
|
|
448
|
+
port += 1;
|
|
449
|
+
}
|
|
450
|
+
return port;
|
|
451
|
+
}
|
|
452
|
+
function vueAppPlaywrightConfig(previewPort) {
|
|
453
|
+
return `import { defineConfig, devices } from "@playwright/test";
|
|
454
|
+
|
|
455
|
+
const previewUrl = "http://127.0.0.1:${previewPort}";
|
|
456
|
+
|
|
457
|
+
export default defineConfig({
|
|
458
|
+
testDir: "./test/e2e",
|
|
459
|
+
use: {
|
|
460
|
+
baseURL: previewUrl,
|
|
461
|
+
trace: "on-first-retry"
|
|
462
|
+
},
|
|
463
|
+
webServer: {
|
|
464
|
+
command: "pnpm run preview --host 127.0.0.1 --port ${previewPort}",
|
|
465
|
+
reuseExistingServer: !process.env.CI,
|
|
466
|
+
url: previewUrl
|
|
467
|
+
},
|
|
468
|
+
projects: [
|
|
469
|
+
{
|
|
470
|
+
name: "chromium",
|
|
471
|
+
use: { ...devices["Desktop Chrome"] }
|
|
472
|
+
}
|
|
473
|
+
]
|
|
474
|
+
});
|
|
475
|
+
`;
|
|
476
|
+
}
|
|
477
|
+
async function readGeneratedWorkspaceBlueprint(root) {
|
|
478
|
+
const blueprintPath = path.join(root, ".project-kit/blueprint.json");
|
|
479
|
+
const result = validateProjectBlueprint(await readJson(blueprintPath));
|
|
480
|
+
if (!result.ok) {
|
|
481
|
+
throw new Error("Package Addition requires a valid .project-kit/blueprint.json");
|
|
482
|
+
}
|
|
483
|
+
const blueprint = result.value;
|
|
484
|
+
if (blueprint.projectKind !== "multi-package") {
|
|
485
|
+
throw new Error("Package Addition only supports existing workspace Generated Repositories");
|
|
486
|
+
}
|
|
487
|
+
if (blueprint.packageManager !== "pnpm") {
|
|
488
|
+
throw new Error("Package Addition only supports pnpm workspace Generated Repositories");
|
|
489
|
+
}
|
|
490
|
+
if (!blueprint.packages || blueprint.packages.length === 0) {
|
|
491
|
+
throw new Error("Package Addition requires package definitions in the stored Project Blueprint");
|
|
492
|
+
}
|
|
493
|
+
await stat(path.join(root, "turbo.json"));
|
|
494
|
+
await stat(path.join(root, "pnpm-workspace.yaml"));
|
|
495
|
+
return blueprint;
|
|
496
|
+
}
|
|
497
|
+
function workspaceTextWithPackageGlob(text, glob) {
|
|
498
|
+
if (text.includes(` - ${glob}`)) {
|
|
499
|
+
return text;
|
|
500
|
+
}
|
|
501
|
+
const nextText = text.replace(/^packages:\n/m, `packages:\n - ${glob}\n`);
|
|
502
|
+
if (nextText === text) {
|
|
503
|
+
throw new Error("Cannot update pnpm workspace membership: missing packages section");
|
|
504
|
+
}
|
|
505
|
+
return nextText;
|
|
506
|
+
}
|
|
507
|
+
function assertRootTsconfig(input) {
|
|
508
|
+
if (!isRecord(input)) {
|
|
509
|
+
throw new Error("Cannot update root TypeScript project references: tsconfig.json must be an object");
|
|
510
|
+
}
|
|
511
|
+
const references = input.references;
|
|
512
|
+
if (references === undefined) {
|
|
513
|
+
return;
|
|
514
|
+
}
|
|
515
|
+
if (!Array.isArray(references)) {
|
|
516
|
+
throw new Error("Cannot update root TypeScript project references: references must be an array");
|
|
517
|
+
}
|
|
518
|
+
for (const reference of references) {
|
|
519
|
+
if (!isRecord(reference) || typeof reference.path !== "string") {
|
|
520
|
+
throw new Error("Cannot update root TypeScript project references: each reference must have a string path");
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
function rootTsconfigWithReferences(input, referencePaths) {
|
|
525
|
+
assertRootTsconfig(input);
|
|
526
|
+
const tsconfig = input;
|
|
527
|
+
const references = tsconfig.references ?? [];
|
|
528
|
+
for (const referencePath of referencePaths) {
|
|
529
|
+
if (!references.some((reference) => reference.path === referencePath)) {
|
|
530
|
+
references.push({ path: referencePath });
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
return { ...tsconfig, references };
|
|
534
|
+
}
|
|
535
|
+
function blueprintWithPackage(blueprint, packageName, packagePath) {
|
|
536
|
+
const nextBlueprint = {
|
|
537
|
+
...blueprint,
|
|
538
|
+
packages: [...(blueprint.packages ?? []), { name: packageName, path: packagePath }]
|
|
539
|
+
};
|
|
540
|
+
const result = validateProjectBlueprint(nextBlueprint);
|
|
541
|
+
if (!result.ok) {
|
|
542
|
+
throw new Error("Package Addition would write an invalid .project-kit/blueprint.json");
|
|
543
|
+
}
|
|
544
|
+
return result.value;
|
|
545
|
+
}
|
|
546
|
+
async function planRootUpdates(root, blueprint, packageName, packagePath, preset) {
|
|
547
|
+
const workspaceText = workspaceTextWithPackageGlob(await readFile(path.join(root, "pnpm-workspace.yaml"), "utf8"), packagePath.startsWith("apps/") ? "apps/*" : "packages/*");
|
|
548
|
+
const rootTsconfig = rootTsconfigWithReferences(await readJson(path.join(root, "tsconfig.json")), rootTsReferencesForPreset(preset, packagePath));
|
|
549
|
+
return {
|
|
550
|
+
blueprint: blueprintWithPackage(blueprint, packageName, packagePath),
|
|
551
|
+
rootTsconfig,
|
|
552
|
+
workspaceText
|
|
553
|
+
};
|
|
554
|
+
}
|
|
555
|
+
export async function addPackage(options) {
|
|
556
|
+
assertSafePackageLeaf(options.name);
|
|
557
|
+
const root = path.resolve(options.cwd);
|
|
558
|
+
const blueprint = await readGeneratedWorkspaceBlueprint(root);
|
|
559
|
+
const projectName = projectNameFromBlueprint(blueprint);
|
|
560
|
+
const packagePath = packagePathForPreset(options.preset, options.name);
|
|
561
|
+
const packageName = `@${projectName}/${options.name}`;
|
|
562
|
+
const vuePreviewPort = options.preset === "vue-app" ? await nextVuePreviewPort(root, blueprint) : undefined;
|
|
563
|
+
if (blueprint.packages?.some((pkg) => pkg.name === packageName || pkg.path === packagePath)) {
|
|
564
|
+
throw new Error(`Package Addition conflicts with an existing package definition: ${packageName}`);
|
|
565
|
+
}
|
|
566
|
+
await assertMissing(path.join(root, packagePath));
|
|
567
|
+
const rootUpdatePlan = await planRootUpdates(root, blueprint, packageName, packagePath, options.preset);
|
|
568
|
+
await mkdir(path.join(root, packagePath), { recursive: true });
|
|
569
|
+
await renderProject({
|
|
570
|
+
sourceRoot: templateSourceRoot(options.preset),
|
|
571
|
+
targetRoot: root,
|
|
572
|
+
operations: packageOperationsForPreset(options.preset, packagePath, packageName)
|
|
573
|
+
});
|
|
574
|
+
if (vuePreviewPort !== undefined) {
|
|
575
|
+
await writeFile(path.join(root, packagePath, "playwright.config.ts"), vueAppPlaywrightConfig(vuePreviewPort), "utf8");
|
|
576
|
+
}
|
|
577
|
+
await writeFile(path.join(root, "pnpm-workspace.yaml"), rootUpdatePlan.workspaceText, "utf8");
|
|
578
|
+
await writeJson(path.join(root, "tsconfig.json"), rootUpdatePlan.rootTsconfig);
|
|
579
|
+
await writeJson(path.join(root, ".project-kit/blueprint.json"), rootUpdatePlan.blueprint);
|
|
580
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
type RenderVariables = Record<string, string>;
|
|
2
|
+
export type CopyFileOperation = {
|
|
3
|
+
kind: "copyFile";
|
|
4
|
+
from: string;
|
|
5
|
+
to: string;
|
|
6
|
+
};
|
|
7
|
+
export type WriteJsonOperation = {
|
|
8
|
+
kind: "writeJson";
|
|
9
|
+
to: string;
|
|
10
|
+
value: unknown;
|
|
11
|
+
multilineArrays?: string[];
|
|
12
|
+
};
|
|
13
|
+
export type MergeJsonOperation = {
|
|
14
|
+
kind: "mergeJson";
|
|
15
|
+
to: string;
|
|
16
|
+
value: unknown;
|
|
17
|
+
};
|
|
18
|
+
export type WriteTextOperation = {
|
|
19
|
+
kind: "writeText";
|
|
20
|
+
to: string;
|
|
21
|
+
text: string;
|
|
22
|
+
};
|
|
23
|
+
export type SetExecutableOperation = {
|
|
24
|
+
kind: "setExecutable";
|
|
25
|
+
path: string;
|
|
26
|
+
executable: boolean;
|
|
27
|
+
};
|
|
28
|
+
export type ReplaceAnchorsOperation = {
|
|
29
|
+
kind: "replaceAnchors";
|
|
30
|
+
path: string;
|
|
31
|
+
language: "typescript";
|
|
32
|
+
replacements: Record<string, string>;
|
|
33
|
+
};
|
|
34
|
+
export type RenderOperation = CopyFileOperation | WriteJsonOperation | MergeJsonOperation | WriteTextOperation | SetExecutableOperation | ReplaceAnchorsOperation;
|
|
35
|
+
export type RenderProjectOptions = {
|
|
36
|
+
sourceRoot: string;
|
|
37
|
+
targetRoot: string;
|
|
38
|
+
variables?: RenderVariables;
|
|
39
|
+
operations: RenderOperation[];
|
|
40
|
+
};
|
|
41
|
+
export declare function renderProject(options: RenderProjectOptions): Promise<void>;
|
|
42
|
+
export declare function renderNewProject(options: RenderProjectOptions): Promise<void>;
|
|
43
|
+
export {};
|
|
44
|
+
//# sourceMappingURL=renderer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"renderer.d.ts","sourceRoot":"","sources":["../src/renderer.ts"],"names":[],"mappings":"AAgBA,KAAK,eAAe,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AAE9C,MAAM,MAAM,iBAAiB,GAAG;IAC9B,IAAI,EAAE,UAAU,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;CACZ,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG;IAC/B,IAAI,EAAE,WAAW,CAAC;IAClB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,OAAO,CAAC;IACf,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;CAC5B,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG;IAC/B,IAAI,EAAE,WAAW,CAAC;IAClB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,OAAO,CAAC;CAChB,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG;IAC/B,IAAI,EAAE,WAAW,CAAC;IAClB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AAEF,MAAM,MAAM,sBAAsB,GAAG;IACnC,IAAI,EAAE,eAAe,CAAC;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,OAAO,CAAC;CACrB,CAAC;AAEF,MAAM,MAAM,uBAAuB,GAAG;IACpC,IAAI,EAAE,gBAAgB,CAAC;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,YAAY,CAAC;IACvB,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACtC,CAAC;AAEF,MAAM,MAAM,eAAe,GACvB,iBAAiB,GACjB,kBAAkB,GAClB,kBAAkB,GAClB,kBAAkB,GAClB,sBAAsB,GACtB,uBAAuB,CAAC;AAE5B,MAAM,MAAM,oBAAoB,GAAG;IACjC,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,eAAe,CAAC;IAC5B,UAAU,EAAE,eAAe,EAAE,CAAC;CAC/B,CAAC;AA8eF,wBAAsB,aAAa,CAAC,OAAO,EAAE,oBAAoB,GAAG,OAAO,CAAC,IAAI,CAAC,CAkChF;AAiCD,wBAAsB,gBAAgB,CAAC,OAAO,EAAE,oBAAoB,GAAG,OAAO,CAAC,IAAI,CAAC,CAmBnF"}
|