@ykdz/template 0.0.0 → 0.0.1
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/dist/cli.js +101 -28
- package/dist/hono-api.d.ts.map +1 -1
- package/dist/hono-api.js +17 -56
- package/dist/package-addition.d.ts.map +1 -1
- package/dist/package-addition.js +31 -51
- package/dist/post-commands.d.ts +40 -0
- package/dist/post-commands.d.ts.map +1 -0
- package/dist/post-commands.js +154 -0
- package/dist/renderer.d.ts +2 -0
- package/dist/renderer.d.ts.map +1 -1
- package/dist/renderer.js +7 -1
- package/dist/rust-bin.d.ts.map +1 -1
- package/dist/rust-bin.js +4 -36
- package/dist/ts-lib.d.ts.map +1 -1
- package/dist/ts-lib.js +17 -56
- package/dist/vue-app.d.ts.map +1 -1
- package/dist/vue-app.js +17 -57
- package/dist/vue-hono-app.d.ts.map +1 -1
- package/dist/vue-hono-app.js +28 -76
- package/package.json +23 -16
- package/templates/hono-api/.github/dependabot.yml +10 -0
- package/templates/hono-api/.github/workflows/check.yml +19 -0
- package/templates/hono-api/src/server.ts +3 -2
- package/templates/hono-api/vitest.config.ts +5 -4
- package/templates/rust-bin/.github/dependabot.yml +10 -0
- package/templates/rust-bin/.github/workflows/check.yml +18 -0
- package/templates/shared/oxc/node/oxlint.config.ts +9 -0
- package/templates/shared/oxc/oxfmt.config.ts +8 -0
- package/templates/shared/oxc/package.json +18 -0
- package/templates/shared/oxc/tsconfig.json +11 -0
- package/templates/shared/oxc/vue/oxlint.config.ts +9 -0
- package/templates/ts-lib/.github/dependabot.yml +10 -0
- package/templates/ts-lib/.github/workflows/check.yml +19 -0
- package/templates/vue-app/.github/dependabot.yml +10 -0
- package/templates/vue-app/.github/workflows/check.yml +20 -0
- package/templates/vue-app/playwright.config.ts +5 -5
- package/templates/vue-app/src/App.vue +15 -5
- package/templates/vue-app/src/main.ts +2 -0
- package/templates/vue-app/test/app.test.ts +1 -0
- package/templates/vue-app/test/e2e/app.spec.ts +3 -1
- package/templates/vue-app/vite.config.ts +6 -5
- package/templates/vue-app/vitest.config.ts +5 -4
- package/templates/vue-hono-app/.github/dependabot.yml +10 -0
- package/templates/vue-hono-app/.github/workflows/check.yml +20 -0
- package/templates/vue-hono-app/api/src/server.ts +3 -2
- package/templates/vue-hono-app/api/vitest.config.ts +2 -2
- package/templates/vue-hono-app/web/playwright.config.ts +9 -7
- package/templates/vue-hono-app/web/src/App.vue +12 -4
- package/templates/vue-hono-app/web/src/api.ts +1 -1
- package/templates/vue-hono-app/web/src/main.ts +2 -0
- package/templates/vue-hono-app/web/test/app.test.ts +1 -0
- package/templates/vue-hono-app/web/test/e2e/app.spec.ts +3 -1
- package/templates/vue-hono-app/web/vite.config.ts +13 -10
- package/templates/vue-hono-app/web/vitest.config.ts +6 -5
package/dist/cli.js
CHANGED
|
@@ -8,6 +8,7 @@ import { initTsLibProject } from "./ts-lib.js";
|
|
|
8
8
|
import { initVueHonoAppProject } from "./vue-hono-app.js";
|
|
9
9
|
import { initVueAppProject } from "./vue-app.js";
|
|
10
10
|
import { addPackage } from "./package-addition.js";
|
|
11
|
+
import { planPostCommands, runPostCommands } from "./post-commands.js";
|
|
11
12
|
import { blueprintJsonSchema, builtInPresets, presetFileJsonSchema, validatePresetFile, validateProjectBlueprint } from "./declarations.js";
|
|
12
13
|
function usage() {
|
|
13
14
|
return [
|
|
@@ -25,6 +26,7 @@ function usage() {
|
|
|
25
26
|
" --name <name> Package name to add",
|
|
26
27
|
" --scope <name> Package scope for workspace package names",
|
|
27
28
|
" --yes Accept defaults for non-interactive generation",
|
|
29
|
+
" --ready Run template-maintained Post Commands after writing files",
|
|
28
30
|
" --dry-run Print the planned generation without writing files",
|
|
29
31
|
" --json Print machine-readable output"
|
|
30
32
|
].join("\n");
|
|
@@ -61,6 +63,7 @@ function parseInitOptions(args) {
|
|
|
61
63
|
let yes = false;
|
|
62
64
|
let dryRun = false;
|
|
63
65
|
let json = false;
|
|
66
|
+
let ready = false;
|
|
64
67
|
let scope;
|
|
65
68
|
for (let index = 2; index < args.length; index += 1) {
|
|
66
69
|
const arg = args[index];
|
|
@@ -72,6 +75,10 @@ function parseInitOptions(args) {
|
|
|
72
75
|
dryRun = true;
|
|
73
76
|
continue;
|
|
74
77
|
}
|
|
78
|
+
if (arg === "--ready") {
|
|
79
|
+
ready = true;
|
|
80
|
+
continue;
|
|
81
|
+
}
|
|
75
82
|
if (arg === "--json") {
|
|
76
83
|
json = true;
|
|
77
84
|
continue;
|
|
@@ -99,7 +106,7 @@ function parseInitOptions(args) {
|
|
|
99
106
|
if (!dir) {
|
|
100
107
|
throw new Error("init requires a target directory");
|
|
101
108
|
}
|
|
102
|
-
return { dir, preset, yes, dryRun, json, scope };
|
|
109
|
+
return { dir, preset, yes, dryRun, json, ready, scope };
|
|
103
110
|
}
|
|
104
111
|
function normalizeNpmScope(value) {
|
|
105
112
|
if (value !== value.trim() || /\s/.test(value)) {
|
|
@@ -164,6 +171,18 @@ function formatBlueprintSummary(targetDir, blueprint) {
|
|
|
164
171
|
lines.push(` Features: ${blueprint.features.join(", ")}`);
|
|
165
172
|
return lines.join("\n");
|
|
166
173
|
}
|
|
174
|
+
function formatPostCommand(command) {
|
|
175
|
+
return [command.command, ...command.args].join(" ");
|
|
176
|
+
}
|
|
177
|
+
function formatPostCommandPlan(commands) {
|
|
178
|
+
if (commands.length === 0) {
|
|
179
|
+
return ["Post Commands:", " (none)"].join("\n");
|
|
180
|
+
}
|
|
181
|
+
return [
|
|
182
|
+
"Post Commands:",
|
|
183
|
+
...commands.map((command) => ` ${command.label}: ${formatPostCommand(command)}`)
|
|
184
|
+
].join("\n");
|
|
185
|
+
}
|
|
167
186
|
function nextStepsForPreset(preset) {
|
|
168
187
|
if (preset === "rust-bin") {
|
|
169
188
|
return ["cd <target>", "./scripts/check"];
|
|
@@ -176,19 +195,78 @@ function formatNextSteps(targetDir, preset) {
|
|
|
176
195
|
...nextStepsForPreset(preset).map((step) => ` ${step.replace("<target>", targetDir)}`)
|
|
177
196
|
].join("\n");
|
|
178
197
|
}
|
|
179
|
-
function
|
|
198
|
+
function postCommandReport(planned, executions, skipped) {
|
|
199
|
+
return {
|
|
200
|
+
planned: planned.map((command) => ({
|
|
201
|
+
id: command.id,
|
|
202
|
+
label: command.label,
|
|
203
|
+
command: command.command,
|
|
204
|
+
args: [...command.args],
|
|
205
|
+
cwd: command.cwd
|
|
206
|
+
})),
|
|
207
|
+
run: executions
|
|
208
|
+
.filter((execution) => execution.status === "run")
|
|
209
|
+
.map((execution) => ({
|
|
210
|
+
id: execution.command.id,
|
|
211
|
+
exitCode: execution.exitCode
|
|
212
|
+
})),
|
|
213
|
+
failed: executions
|
|
214
|
+
.filter((execution) => execution.status === "failed")
|
|
215
|
+
.map((execution) => ({
|
|
216
|
+
id: execution.command.id,
|
|
217
|
+
exitCode: execution.exitCode,
|
|
218
|
+
error: execution.error
|
|
219
|
+
})),
|
|
220
|
+
skipped
|
|
221
|
+
};
|
|
222
|
+
}
|
|
223
|
+
function failedPostCommand(executions) {
|
|
224
|
+
return executions.find((execution) => execution.status === "failed");
|
|
225
|
+
}
|
|
226
|
+
function skippedPostCommands(commands, reason) {
|
|
227
|
+
return commands.map((command) => ({ id: command.id, reason }));
|
|
228
|
+
}
|
|
229
|
+
async function generateInitProject(options) {
|
|
230
|
+
if (options.preset === "ts-lib") {
|
|
231
|
+
await initTsLibProject(options.dir);
|
|
232
|
+
return;
|
|
233
|
+
}
|
|
234
|
+
if (options.preset === "hono-api") {
|
|
235
|
+
await initHonoApiProject(options.dir);
|
|
236
|
+
return;
|
|
237
|
+
}
|
|
238
|
+
if (options.preset === "vue-app") {
|
|
239
|
+
await initVueAppProject(options.dir);
|
|
240
|
+
return;
|
|
241
|
+
}
|
|
242
|
+
if (options.preset === "vue-hono-app") {
|
|
243
|
+
await initVueHonoAppProject(options.dir, { scope: options.scope });
|
|
244
|
+
return;
|
|
245
|
+
}
|
|
246
|
+
if (options.preset === "rust-bin") {
|
|
247
|
+
await initRustBinProject(options.dir);
|
|
248
|
+
return;
|
|
249
|
+
}
|
|
250
|
+
throw new Error("Only the ts-lib, hono-api, vue-app, vue-hono-app, and rust-bin presets are supported in this version");
|
|
251
|
+
}
|
|
252
|
+
function printInitComplete(options, blueprint, report) {
|
|
180
253
|
const preset = blueprint.preset;
|
|
181
254
|
if (options.json) {
|
|
182
255
|
printJson({
|
|
183
256
|
command: "init",
|
|
184
257
|
dryRun: false,
|
|
258
|
+
ready: options.ready,
|
|
185
259
|
targetDir: options.dir,
|
|
186
260
|
blueprint,
|
|
261
|
+
postCommands: report,
|
|
187
262
|
nextSteps: nextStepsForPreset(preset).map((step) => step.replace("<target>", options.dir))
|
|
188
263
|
});
|
|
189
264
|
return;
|
|
190
265
|
}
|
|
191
266
|
console.log(`Initialized ${options.preset} project in ${options.dir}`);
|
|
267
|
+
if (options.ready) {
|
|
268
|
+
console.log(formatPostCommandPlan(report.planned));
|
|
269
|
+
}
|
|
192
270
|
console.log(formatNextSteps(options.dir, preset));
|
|
193
271
|
}
|
|
194
272
|
function isInteractiveTerminal() {
|
|
@@ -287,16 +365,23 @@ async function main(args) {
|
|
|
287
365
|
const options = parseInitOptions(args);
|
|
288
366
|
const blueprint = blueprintForInit(options);
|
|
289
367
|
if (options.dryRun) {
|
|
368
|
+
const postCommandPlan = planPostCommands({
|
|
369
|
+
preset: blueprint.preset,
|
|
370
|
+
targetDir: options.dir
|
|
371
|
+
});
|
|
290
372
|
if (options.json) {
|
|
291
373
|
printJson({
|
|
292
374
|
command: "init",
|
|
293
375
|
dryRun: true,
|
|
376
|
+
ready: options.ready,
|
|
294
377
|
targetDir: options.dir,
|
|
295
|
-
blueprint
|
|
378
|
+
blueprint,
|
|
379
|
+
postCommands: postCommandReport(postCommandPlan.commands, [], skippedPostCommands(postCommandPlan.commands, "dry-run"))
|
|
296
380
|
});
|
|
297
381
|
return;
|
|
298
382
|
}
|
|
299
383
|
console.log(formatBlueprintSummary(options.dir, blueprint));
|
|
384
|
+
console.log(formatPostCommandPlan(postCommandPlan.commands));
|
|
300
385
|
return;
|
|
301
386
|
}
|
|
302
387
|
if (!options.yes && (options.json || !isInteractiveTerminal())) {
|
|
@@ -305,32 +390,20 @@ async function main(args) {
|
|
|
305
390
|
if (!options.yes && !(await confirmInit(options.dir, blueprint))) {
|
|
306
391
|
throw new Error("Init cancelled");
|
|
307
392
|
}
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
if (
|
|
319
|
-
|
|
320
|
-
printInitComplete(options, blueprint);
|
|
321
|
-
return;
|
|
322
|
-
}
|
|
323
|
-
if (options.preset === "vue-hono-app") {
|
|
324
|
-
await initVueHonoAppProject(options.dir, { scope: options.scope });
|
|
325
|
-
printInitComplete(options, blueprint);
|
|
326
|
-
return;
|
|
327
|
-
}
|
|
328
|
-
if (options.preset === "rust-bin") {
|
|
329
|
-
await initRustBinProject(options.dir);
|
|
330
|
-
printInitComplete(options, blueprint);
|
|
331
|
-
return;
|
|
393
|
+
const postCommandPlan = planPostCommands({
|
|
394
|
+
preset: blueprint.preset,
|
|
395
|
+
targetDir: options.dir
|
|
396
|
+
});
|
|
397
|
+
await generateInitProject(options);
|
|
398
|
+
const executions = options.ready ? await runPostCommands({ plan: postCommandPlan }) : [];
|
|
399
|
+
const failedExecution = failedPostCommand(executions);
|
|
400
|
+
printInitComplete(options, blueprint, postCommandReport(postCommandPlan.commands, executions, options.ready
|
|
401
|
+
? []
|
|
402
|
+
: skippedPostCommands(postCommandPlan.commands, "ready-mode-not-requested")));
|
|
403
|
+
if (failedExecution) {
|
|
404
|
+
throw new Error(failedExecution.error);
|
|
332
405
|
}
|
|
333
|
-
|
|
406
|
+
return;
|
|
334
407
|
}
|
|
335
408
|
if (command === "add" && args[1] === "package") {
|
|
336
409
|
const options = parseAddPackageOptions(args);
|
package/dist/hono-api.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hono-api.d.ts","sourceRoot":"","sources":["../src/hono-api.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"hono-api.d.ts","sourceRoot":"","sources":["../src/hono-api.ts"],"names":[],"mappings":"AAiNA,wBAAsB,kBAAkB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAOzE"}
|
package/dist/hono-api.js
CHANGED
|
@@ -50,7 +50,7 @@ function packageJson(projectName) {
|
|
|
50
50
|
vitest: "catalog:"
|
|
51
51
|
},
|
|
52
52
|
engines: {
|
|
53
|
-
node: "
|
|
53
|
+
node: "22"
|
|
54
54
|
},
|
|
55
55
|
packageManager: "pnpm@10.0.0"
|
|
56
56
|
};
|
|
@@ -114,24 +114,16 @@ function operationsForHonoApi(projectName) {
|
|
|
114
114
|
}
|
|
115
115
|
},
|
|
116
116
|
{
|
|
117
|
-
kind: "
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
correctness: "error",
|
|
122
|
-
suspicious: "error"
|
|
123
|
-
},
|
|
124
|
-
plugins: ["typescript", "oxc"]
|
|
125
|
-
}
|
|
117
|
+
kind: "copyFile",
|
|
118
|
+
sourceRoot: "sharedOxc",
|
|
119
|
+
from: "node/oxlint.config.ts",
|
|
120
|
+
to: "oxlint.config.ts"
|
|
126
121
|
},
|
|
127
122
|
{
|
|
128
|
-
kind: "
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
singleQuote: false,
|
|
133
|
-
trailingComma: "none"
|
|
134
|
-
}
|
|
123
|
+
kind: "copyFile",
|
|
124
|
+
sourceRoot: "sharedOxc",
|
|
125
|
+
from: "oxfmt.config.ts",
|
|
126
|
+
to: "oxfmt.config.ts"
|
|
135
127
|
},
|
|
136
128
|
{
|
|
137
129
|
kind: "writeText",
|
|
@@ -189,58 +181,27 @@ function operationsForHonoApi(projectName) {
|
|
|
189
181
|
}
|
|
190
182
|
},
|
|
191
183
|
{
|
|
192
|
-
kind: "
|
|
184
|
+
kind: "copyFile",
|
|
185
|
+
from: ".github/workflows/check.yml",
|
|
193
186
|
to: ".github/workflows/check.yml",
|
|
194
|
-
text: [
|
|
195
|
-
"name: Check",
|
|
196
|
-
"",
|
|
197
|
-
"on:",
|
|
198
|
-
" pull_request:",
|
|
199
|
-
" push:",
|
|
200
|
-
" branches:",
|
|
201
|
-
" - main",
|
|
202
|
-
"",
|
|
203
|
-
"jobs:",
|
|
204
|
-
" check:",
|
|
205
|
-
" runs-on: ubuntu-latest",
|
|
206
|
-
" steps:",
|
|
207
|
-
" - uses: actions/checkout@v4",
|
|
208
|
-
" - uses: pnpm/action-setup@v4",
|
|
209
|
-
" with:",
|
|
210
|
-
" version: 10.0.0",
|
|
211
|
-
" - uses: actions/setup-node@v4",
|
|
212
|
-
" with:",
|
|
213
|
-
" node-version: 22",
|
|
214
|
-
" - run: pnpm install",
|
|
215
|
-
" - run: pnpm run check",
|
|
216
|
-
""
|
|
217
|
-
].join("\n")
|
|
218
187
|
},
|
|
219
188
|
{
|
|
220
|
-
kind: "
|
|
189
|
+
kind: "copyFile",
|
|
190
|
+
from: ".github/dependabot.yml",
|
|
221
191
|
to: ".github/dependabot.yml",
|
|
222
|
-
text: [
|
|
223
|
-
"version: 2",
|
|
224
|
-
"updates:",
|
|
225
|
-
" - package-ecosystem: npm",
|
|
226
|
-
" directory: /",
|
|
227
|
-
" schedule:",
|
|
228
|
-
" interval: weekly",
|
|
229
|
-
" - package-ecosystem: github-actions",
|
|
230
|
-
" directory: /",
|
|
231
|
-
" schedule:",
|
|
232
|
-
" interval: weekly",
|
|
233
|
-
""
|
|
234
|
-
].join("\n")
|
|
235
192
|
}
|
|
236
193
|
];
|
|
237
194
|
}
|
|
238
195
|
function templateSourceRoot() {
|
|
239
196
|
return path.join(path.dirname(fileURLToPath(import.meta.url)), "..", "templates", "hono-api");
|
|
240
197
|
}
|
|
198
|
+
function sharedOxcSourceRoot() {
|
|
199
|
+
return path.join(path.dirname(fileURLToPath(import.meta.url)), "..", "templates", "shared", "oxc");
|
|
200
|
+
}
|
|
241
201
|
export async function initHonoApiProject(targetDir) {
|
|
242
202
|
await renderNewProject({
|
|
243
203
|
sourceRoot: templateSourceRoot(),
|
|
204
|
+
sourceRoots: { sharedOxc: sharedOxcSourceRoot() },
|
|
244
205
|
targetRoot: targetDir,
|
|
245
206
|
operations: operationsForHonoApi(projectNameFromDir(targetDir))
|
|
246
207
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"package-addition.d.ts","sourceRoot":"","sources":["../src/package-addition.ts"],"names":[],"mappings":"AAMA,MAAM,MAAM,iBAAiB,GAAG;IAC9B,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;
|
|
1
|
+
{"version":3,"file":"package-addition.d.ts","sourceRoot":"","sources":["../src/package-addition.ts"],"names":[],"mappings":"AAMA,MAAM,MAAM,iBAAiB,GAAG;IAC9B,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AAqnBF,wBAAsB,UAAU,CAAC,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC,CA2C1E"}
|
package/dist/package-addition.js
CHANGED
|
@@ -71,7 +71,7 @@ function tsLibPackageJson(packageName) {
|
|
|
71
71
|
typescript: "catalog:"
|
|
72
72
|
},
|
|
73
73
|
engines: {
|
|
74
|
-
node: "
|
|
74
|
+
node: "22"
|
|
75
75
|
}
|
|
76
76
|
};
|
|
77
77
|
}
|
|
@@ -108,24 +108,16 @@ function tsLibPackageOperations(packagePath, packageName) {
|
|
|
108
108
|
}
|
|
109
109
|
},
|
|
110
110
|
{
|
|
111
|
-
kind: "
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
correctness: "error",
|
|
116
|
-
suspicious: "error"
|
|
117
|
-
},
|
|
118
|
-
plugins: ["typescript", "oxc"]
|
|
119
|
-
}
|
|
111
|
+
kind: "copyFile",
|
|
112
|
+
sourceRoot: "sharedOxc",
|
|
113
|
+
from: "node/oxlint.config.ts",
|
|
114
|
+
to: `${packagePath}/oxlint.config.ts`
|
|
120
115
|
},
|
|
121
116
|
{
|
|
122
|
-
kind: "
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
singleQuote: false,
|
|
127
|
-
trailingComma: "none"
|
|
128
|
-
}
|
|
117
|
+
kind: "copyFile",
|
|
118
|
+
sourceRoot: "sharedOxc",
|
|
119
|
+
from: "oxfmt.config.ts",
|
|
120
|
+
to: `${packagePath}/oxfmt.config.ts`
|
|
129
121
|
},
|
|
130
122
|
{
|
|
131
123
|
kind: "copyFile",
|
|
@@ -165,7 +157,7 @@ function honoApiPackageJson(packageName) {
|
|
|
165
157
|
vitest: "catalog:"
|
|
166
158
|
},
|
|
167
159
|
engines: {
|
|
168
|
-
node: "
|
|
160
|
+
node: "22"
|
|
169
161
|
}
|
|
170
162
|
};
|
|
171
163
|
}
|
|
@@ -210,24 +202,16 @@ function honoApiPackageOperations(packagePath, packageName) {
|
|
|
210
202
|
}
|
|
211
203
|
},
|
|
212
204
|
{
|
|
213
|
-
kind: "
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
correctness: "error",
|
|
218
|
-
suspicious: "error"
|
|
219
|
-
},
|
|
220
|
-
plugins: ["typescript", "oxc"]
|
|
221
|
-
}
|
|
205
|
+
kind: "copyFile",
|
|
206
|
+
sourceRoot: "sharedOxc",
|
|
207
|
+
from: "node/oxlint.config.ts",
|
|
208
|
+
to: `${packagePath}/oxlint.config.ts`
|
|
222
209
|
},
|
|
223
210
|
{
|
|
224
|
-
kind: "
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
singleQuote: false,
|
|
229
|
-
trailingComma: "none"
|
|
230
|
-
}
|
|
211
|
+
kind: "copyFile",
|
|
212
|
+
sourceRoot: "sharedOxc",
|
|
213
|
+
from: "oxfmt.config.ts",
|
|
214
|
+
to: `${packagePath}/oxfmt.config.ts`
|
|
231
215
|
},
|
|
232
216
|
{ kind: "copyFile", from: "src/app.ts", to: `${packagePath}/src/app.ts` },
|
|
233
217
|
{ kind: "copyFile", from: "src/server.ts", to: `${packagePath}/src/server.ts` },
|
|
@@ -276,7 +260,7 @@ function vueAppPackageJson(packageName) {
|
|
|
276
260
|
"vue-tsc": "catalog:"
|
|
277
261
|
},
|
|
278
262
|
engines: {
|
|
279
|
-
node: "
|
|
263
|
+
node: "22"
|
|
280
264
|
}
|
|
281
265
|
};
|
|
282
266
|
}
|
|
@@ -351,24 +335,16 @@ function vueAppPackageOperations(packagePath, packageName) {
|
|
|
351
335
|
}
|
|
352
336
|
},
|
|
353
337
|
{
|
|
354
|
-
kind: "
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
correctness: "error",
|
|
359
|
-
suspicious: "error"
|
|
360
|
-
},
|
|
361
|
-
plugins: ["typescript", "oxc", "vue"]
|
|
362
|
-
}
|
|
338
|
+
kind: "copyFile",
|
|
339
|
+
sourceRoot: "sharedOxc",
|
|
340
|
+
from: "vue/oxlint.config.ts",
|
|
341
|
+
to: `${packagePath}/oxlint.config.ts`
|
|
363
342
|
},
|
|
364
343
|
{
|
|
365
|
-
kind: "
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
singleQuote: false,
|
|
370
|
-
trailingComma: "none"
|
|
371
|
-
}
|
|
344
|
+
kind: "copyFile",
|
|
345
|
+
sourceRoot: "sharedOxc",
|
|
346
|
+
from: "oxfmt.config.ts",
|
|
347
|
+
to: `${packagePath}/oxfmt.config.ts`
|
|
372
348
|
},
|
|
373
349
|
{ kind: "copyFile", from: "env.d.ts", to: `${packagePath}/env.d.ts` },
|
|
374
350
|
{ kind: "copyFile", from: "index.html", to: `${packagePath}/index.html` },
|
|
@@ -417,6 +393,9 @@ function rootTsReferencesForPreset(preset, packagePath) {
|
|
|
417
393
|
function templateSourceRoot(preset) {
|
|
418
394
|
return path.join(path.dirname(fileURLToPath(import.meta.url)), "..", "templates", preset);
|
|
419
395
|
}
|
|
396
|
+
function sharedOxcSourceRoot() {
|
|
397
|
+
return path.join(path.dirname(fileURLToPath(import.meta.url)), "..", "templates", "shared", "oxc");
|
|
398
|
+
}
|
|
420
399
|
function localPortsFromText(text) {
|
|
421
400
|
return [
|
|
422
401
|
...text.matchAll(/port:\s*(\d+)/g),
|
|
@@ -568,6 +547,7 @@ export async function addPackage(options) {
|
|
|
568
547
|
await mkdir(path.join(root, packagePath), { recursive: true });
|
|
569
548
|
await renderProject({
|
|
570
549
|
sourceRoot: templateSourceRoot(options.preset),
|
|
550
|
+
sourceRoots: { sharedOxc: sharedOxcSourceRoot() },
|
|
571
551
|
targetRoot: root,
|
|
572
552
|
operations: packageOperationsForPreset(options.preset, packagePath, packageName)
|
|
573
553
|
});
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { PresetName } from "./declarations.js";
|
|
2
|
+
export type PostCommand = {
|
|
3
|
+
id: string;
|
|
4
|
+
label: string;
|
|
5
|
+
command: string;
|
|
6
|
+
args: readonly string[];
|
|
7
|
+
cwd: string;
|
|
8
|
+
};
|
|
9
|
+
export type PlanPostCommandsOptions = {
|
|
10
|
+
preset: PresetName;
|
|
11
|
+
targetDir: string;
|
|
12
|
+
};
|
|
13
|
+
declare const postCommandPlanBrand: unique symbol;
|
|
14
|
+
export type PostCommandPlan = {
|
|
15
|
+
readonly preset: PresetName;
|
|
16
|
+
readonly targetDir: string;
|
|
17
|
+
readonly commands: readonly PostCommand[];
|
|
18
|
+
readonly [postCommandPlanBrand]: true;
|
|
19
|
+
};
|
|
20
|
+
export type PostCommandExecution = {
|
|
21
|
+
command: PostCommand;
|
|
22
|
+
status: "run";
|
|
23
|
+
exitCode: 0;
|
|
24
|
+
} | {
|
|
25
|
+
command: PostCommand;
|
|
26
|
+
status: "failed";
|
|
27
|
+
exitCode: number | null;
|
|
28
|
+
error: string;
|
|
29
|
+
};
|
|
30
|
+
export type PostCommandExecutor = (command: PostCommand) => Promise<{
|
|
31
|
+
exitCode: number;
|
|
32
|
+
}>;
|
|
33
|
+
export type RunPostCommandsOptions = {
|
|
34
|
+
plan: PostCommandPlan;
|
|
35
|
+
executor?: PostCommandExecutor;
|
|
36
|
+
};
|
|
37
|
+
export declare function planPostCommands(options: PlanPostCommandsOptions): PostCommandPlan;
|
|
38
|
+
export declare function runPostCommands(options: RunPostCommandsOptions): Promise<PostCommandExecution[]>;
|
|
39
|
+
export {};
|
|
40
|
+
//# sourceMappingURL=post-commands.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"post-commands.d.ts","sourceRoot":"","sources":["../src/post-commands.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAEpD,MAAM,MAAM,WAAW,GAAG;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,SAAS,MAAM,EAAE,CAAC;IACxB,GAAG,EAAE,MAAM,CAAC;CACb,CAAC;AAEF,MAAM,MAAM,uBAAuB,GAAG;IACpC,MAAM,EAAE,UAAU,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF,QAAA,MAAM,oBAAoB,EAAE,OAAO,MAAkC,CAAC;AAEtE,MAAM,MAAM,eAAe,GAAG;IAC5B,QAAQ,CAAC,MAAM,EAAE,UAAU,CAAC;IAC5B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,QAAQ,EAAE,SAAS,WAAW,EAAE,CAAC;IAC1C,QAAQ,CAAC,CAAC,oBAAoB,CAAC,EAAE,IAAI,CAAC;CACvC,CAAC;AAEF,MAAM,MAAM,oBAAoB,GAC5B;IACE,OAAO,EAAE,WAAW,CAAC;IACrB,MAAM,EAAE,KAAK,CAAC;IACd,QAAQ,EAAE,CAAC,CAAC;CACb,GACD;IACE,OAAO,EAAE,WAAW,CAAC;IACrB,MAAM,EAAE,QAAQ,CAAC;IACjB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,KAAK,EAAE,MAAM,CAAC;CACf,CAAC;AAEN,MAAM,MAAM,mBAAmB,GAAG,CAChC,OAAO,EAAE,WAAW,KACjB,OAAO,CAAC;IAAE,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC;AAEnC,MAAM,MAAM,sBAAsB,GAAG;IACnC,IAAI,EAAE,eAAe,CAAC;IACtB,QAAQ,CAAC,EAAE,mBAAmB,CAAC;CAChC,CAAC;AAmEF,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,uBAAuB,GAAG,eAAe,CAalF;AAoED,wBAAsB,eAAe,CACnC,OAAO,EAAE,sBAAsB,GAC9B,OAAO,CAAC,oBAAoB,EAAE,CAAC,CAqCjC"}
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
import { spawn } from "node:child_process";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
const postCommandPlanBrand = Symbol("PostCommandPlan");
|
|
4
|
+
const packageManagerPin = "pnpm@10.0.0";
|
|
5
|
+
const nodeReadyCommands = [
|
|
6
|
+
{
|
|
7
|
+
id: "node-enable-corepack",
|
|
8
|
+
label: "Enable Corepack",
|
|
9
|
+
command: "corepack",
|
|
10
|
+
args: ["enable"]
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
id: "node-refresh-package-manager-pin",
|
|
14
|
+
label: "Refresh Package Manager Pin and Install Dependencies",
|
|
15
|
+
command: "corepack",
|
|
16
|
+
args: ["use", packageManagerPin]
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
id: "node-run-fix",
|
|
20
|
+
label: "Run Fix Command",
|
|
21
|
+
command: "pnpm",
|
|
22
|
+
args: ["run", "fix"]
|
|
23
|
+
}
|
|
24
|
+
];
|
|
25
|
+
const vueReadyCommand = {
|
|
26
|
+
id: "vue-install-playwright-browsers",
|
|
27
|
+
label: "Install Playwright browser assets",
|
|
28
|
+
command: "pnpm",
|
|
29
|
+
args: ["exec", "playwright", "install", "chromium"]
|
|
30
|
+
};
|
|
31
|
+
const vueHonoReadyCommand = {
|
|
32
|
+
id: "vue-hono-install-playwright-browsers",
|
|
33
|
+
label: "Install Playwright browser assets for web workspace",
|
|
34
|
+
command: "pnpm",
|
|
35
|
+
args: ["--filter", "./apps/web", "exec", "playwright", "install", "chromium"]
|
|
36
|
+
};
|
|
37
|
+
function postCommandsForPreset(options) {
|
|
38
|
+
if (options.preset !== "ts-lib" &&
|
|
39
|
+
options.preset !== "hono-api" &&
|
|
40
|
+
options.preset !== "vue-app" &&
|
|
41
|
+
options.preset !== "vue-hono-app") {
|
|
42
|
+
return [];
|
|
43
|
+
}
|
|
44
|
+
const commands = [...nodeReadyCommands];
|
|
45
|
+
if (options.preset === "vue-app") {
|
|
46
|
+
commands.push(vueReadyCommand);
|
|
47
|
+
}
|
|
48
|
+
if (options.preset === "vue-hono-app") {
|
|
49
|
+
commands.push(vueHonoReadyCommand);
|
|
50
|
+
}
|
|
51
|
+
return commands.map((command) => ({
|
|
52
|
+
...command,
|
|
53
|
+
cwd: options.targetDir
|
|
54
|
+
}));
|
|
55
|
+
}
|
|
56
|
+
export function planPostCommands(options) {
|
|
57
|
+
const targetDir = path.resolve(options.targetDir);
|
|
58
|
+
const commands = postCommandsForPreset({
|
|
59
|
+
preset: options.preset,
|
|
60
|
+
targetDir
|
|
61
|
+
}).map((command) => Object.freeze(command));
|
|
62
|
+
return Object.freeze({
|
|
63
|
+
preset: options.preset,
|
|
64
|
+
targetDir,
|
|
65
|
+
commands: Object.freeze(commands),
|
|
66
|
+
[postCommandPlanBrand]: true
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
async function defaultExecutor(command) {
|
|
70
|
+
return await new Promise((resolve, reject) => {
|
|
71
|
+
const child = spawn(command.command, [...command.args], {
|
|
72
|
+
cwd: command.cwd,
|
|
73
|
+
stdio: "ignore"
|
|
74
|
+
});
|
|
75
|
+
child.once("error", reject);
|
|
76
|
+
child.once("close", (exitCode) => {
|
|
77
|
+
resolve({ exitCode: exitCode ?? 1 });
|
|
78
|
+
});
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
function isWithinDirectory(parentDir, childPath) {
|
|
82
|
+
const relativePath = path.relative(path.resolve(parentDir), path.resolve(childPath));
|
|
83
|
+
return (relativePath === "" ||
|
|
84
|
+
(!relativePath.startsWith("..") && !path.isAbsolute(relativePath)));
|
|
85
|
+
}
|
|
86
|
+
function sameCommand(left, right) {
|
|
87
|
+
return (left.id === right.id &&
|
|
88
|
+
left.label === right.label &&
|
|
89
|
+
left.command === right.command &&
|
|
90
|
+
left.args.length === right.args.length &&
|
|
91
|
+
left.args.every((arg, index) => arg === right.args[index]) &&
|
|
92
|
+
path.resolve(left.cwd) === path.resolve(right.cwd));
|
|
93
|
+
}
|
|
94
|
+
function validatePostCommandPlan(plan) {
|
|
95
|
+
const expectedCommands = postCommandsForPreset({
|
|
96
|
+
preset: plan.preset,
|
|
97
|
+
targetDir: path.resolve(plan.targetDir)
|
|
98
|
+
});
|
|
99
|
+
const expectedCommandIds = new Set(expectedCommands.map((command) => command.id));
|
|
100
|
+
for (const command of plan.commands) {
|
|
101
|
+
if (!isWithinDirectory(plan.targetDir, command.cwd)) {
|
|
102
|
+
throw new Error(`Post Command cwd must stay within the target directory: ${command.id}`);
|
|
103
|
+
}
|
|
104
|
+
if (!expectedCommandIds.has(command.id)) {
|
|
105
|
+
throw new Error(`Unplanned Post Command: ${command.id}`);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
if (plan.commands.length !== expectedCommands.length) {
|
|
109
|
+
throw new Error("Post Command plan must match the complete planned sequence");
|
|
110
|
+
}
|
|
111
|
+
for (const [index, command] of plan.commands.entries()) {
|
|
112
|
+
const expectedCommand = expectedCommands[index];
|
|
113
|
+
if (!expectedCommand || command.id !== expectedCommand.id) {
|
|
114
|
+
throw new Error("Post Command plan must match the complete planned sequence");
|
|
115
|
+
}
|
|
116
|
+
if (!sameCommand(command, expectedCommand)) {
|
|
117
|
+
throw new Error(`Post Command does not match the planned template command: ${command.id}`);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
export async function runPostCommands(options) {
|
|
122
|
+
const executor = options.executor ?? defaultExecutor;
|
|
123
|
+
const results = [];
|
|
124
|
+
validatePostCommandPlan(options.plan);
|
|
125
|
+
for (const command of options.plan.commands) {
|
|
126
|
+
try {
|
|
127
|
+
const result = await executor(command);
|
|
128
|
+
if (result.exitCode !== 0) {
|
|
129
|
+
results.push({
|
|
130
|
+
command,
|
|
131
|
+
status: "failed",
|
|
132
|
+
exitCode: result.exitCode,
|
|
133
|
+
error: `Post Command failed with exit code ${result.exitCode}: ${command.id}`
|
|
134
|
+
});
|
|
135
|
+
break;
|
|
136
|
+
}
|
|
137
|
+
results.push({ command, status: "run", exitCode: 0 });
|
|
138
|
+
}
|
|
139
|
+
catch (error) {
|
|
140
|
+
const exitCode = error instanceof Error && "exitCode" in error && typeof error.exitCode === "number"
|
|
141
|
+
? error.exitCode
|
|
142
|
+
: null;
|
|
143
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
144
|
+
results.push({
|
|
145
|
+
command,
|
|
146
|
+
status: "failed",
|
|
147
|
+
exitCode,
|
|
148
|
+
error: `Post Command failed: ${command.id}: ${message}`
|
|
149
|
+
});
|
|
150
|
+
break;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
return results;
|
|
154
|
+
}
|