@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.
- package/README.md +1 -1
- package/dist/src/cli.d.ts +2 -0
- package/dist/{cli.js → src/cli.js} +91 -58
- package/dist/{declarations.d.ts → src/declarations.d.ts} +3 -5
- package/dist/{declarations.js → src/declarations.js} +48 -145
- package/dist/src/dependency-catalog.d.ts +18 -0
- package/dist/src/dependency-catalog.js +132 -0
- package/dist/src/devcontainer.d.ts +58 -0
- package/dist/src/devcontainer.js +202 -0
- package/dist/src/editor-customization.d.ts +12 -0
- package/dist/src/editor-customization.js +108 -0
- package/dist/{generation-context.d.ts → src/generation-context.d.ts} +2 -3
- package/dist/{generation-context.js → src/generation-context.js} +4 -1
- package/dist/src/module-graph.d.ts +34 -0
- package/dist/src/module-graph.js +58 -0
- package/dist/{next-step-instructions.d.ts → src/next-step-instructions.d.ts} +2 -4
- package/dist/{next-step-instructions.js → src/next-step-instructions.js} +49 -24
- package/dist/{package-addition.d.ts → src/package-addition.d.ts} +1 -1
- package/dist/src/package-addition.js +343 -0
- package/dist/src/preset-projection.d.ts +66 -0
- package/dist/src/preset-projection.js +7 -0
- package/dist/{project-github.d.ts → src/project-github.d.ts} +3 -9
- package/dist/{project-github.js → src/project-github.js} +27 -42
- package/dist/{renderer.d.ts → src/renderer.d.ts} +16 -2
- package/dist/{renderer.js → src/renderer.js} +95 -12
- package/dist/src/runtime-paths.d.ts +1 -0
- package/dist/src/runtime-paths.js +11 -0
- package/dist/src/template-boundary-check.d.ts +34 -0
- package/dist/src/template-boundary-check.js +448 -0
- package/dist/{toolchain-resolution.d.ts → src/toolchain-resolution.d.ts} +0 -1
- package/dist/{toolchain-resolution.js → src/toolchain-resolution.js} +1 -1
- package/dist/templates/hono-api/projection.d.ts +6 -0
- package/dist/templates/hono-api/projection.js +538 -0
- package/dist/templates/projection-plans.d.ts +7 -0
- package/dist/templates/projection-plans.js +94 -0
- package/dist/templates/registry.d.ts +7 -0
- package/dist/templates/registry.js +42 -0
- package/dist/templates/rust-bin/projection.d.ts +9 -0
- package/dist/templates/rust-bin/projection.js +390 -0
- package/dist/templates/ts-lib/projection.d.ts +6 -0
- package/dist/templates/ts-lib/projection.js +523 -0
- package/dist/templates/vue-app/projection.d.ts +6 -0
- package/dist/templates/vue-app/projection.js +757 -0
- package/dist/templates/vue-hono-app/projection.d.ts +8 -0
- package/dist/templates/vue-hono-app/projection.js +693 -0
- package/package.json +38 -28
- package/pnpm-workspace.yaml +35 -0
- package/templates/hono-api/.github/dependabot.yml +13 -0
- package/templates/rust-bin/.github/dependabot.yml +18 -1
- package/templates/rust-bin/rust-toolchain.toml +3 -0
- package/templates/rust-bin/rustfmt.toml +2 -0
- package/templates/shared/devcontainer/browser-test.Dockerfile +2 -0
- package/templates/shared/devcontainer/node-pnpm.Dockerfile +6 -0
- package/templates/shared/devcontainer/rust.Dockerfile +16 -0
- package/templates/shared/editor-customization/capabilities.json +56 -0
- package/templates/ts-lib/.github/dependabot.yml +13 -0
- package/templates/ts-lib/src/index.ts +5 -1
- package/templates/vue-app/.github/dependabot.yml +13 -0
- package/templates/vue-app/.github/workflows/check.yml +1 -1
- package/templates/vue-app/test/e2e/app.spec.ts +4 -1
- package/templates/vue-hono-app/.github/dependabot.yml +13 -0
- package/templates/vue-hono-app/web/test/e2e/app.spec.ts +4 -1
- package/dist/cli.d.ts +0 -3
- package/dist/cli.d.ts.map +0 -1
- package/dist/declarations.d.ts.map +0 -1
- package/dist/devcontainer.d.ts +0 -17
- package/dist/devcontainer.d.ts.map +0 -1
- package/dist/devcontainer.js +0 -23
- package/dist/generation-context.d.ts.map +0 -1
- package/dist/hono-api.d.ts +0 -3
- package/dist/hono-api.d.ts.map +0 -1
- package/dist/hono-api.js +0 -210
- package/dist/module-graph.d.ts +0 -45
- package/dist/module-graph.d.ts.map +0 -1
- package/dist/module-graph.js +0 -187
- package/dist/next-step-instructions.d.ts.map +0 -1
- package/dist/package-addition.d.ts.map +0 -1
- package/dist/package-addition.js +0 -560
- package/dist/project-github.d.ts.map +0 -1
- package/dist/renderer.d.ts.map +0 -1
- package/dist/rust-bin.d.ts +0 -8
- package/dist/rust-bin.d.ts.map +0 -1
- package/dist/rust-bin.js +0 -208
- package/dist/toolchain-resolution.d.ts.map +0 -1
- package/dist/ts-lib.d.ts +0 -8
- package/dist/ts-lib.d.ts.map +0 -1
- package/dist/ts-lib.js +0 -214
- package/dist/vue-app.d.ts +0 -3
- package/dist/vue-app.d.ts.map +0 -1
- package/dist/vue-app.js +0 -301
- package/dist/vue-hono-app.d.ts +0 -7
- package/dist/vue-hono-app.d.ts.map +0 -1
- package/dist/vue-hono-app.js +0 -440
- package/templates/shared/oxc/package.json +0 -18
- package/templates/shared/oxc/tsconfig.json +0 -11
package/README.md
CHANGED
|
@@ -12,7 +12,7 @@ Available commands:
|
|
|
12
12
|
|
|
13
13
|
```sh
|
|
14
14
|
template init <dir> --preset <name> --yes
|
|
15
|
-
template add package --preset <name> --name <name>
|
|
15
|
+
template add package --preset <name> --name <name> [--path <package-path>]
|
|
16
16
|
template presets
|
|
17
17
|
template schema preset
|
|
18
18
|
template schema blueprint
|
|
@@ -2,21 +2,17 @@
|
|
|
2
2
|
import { readFile } from "node:fs/promises";
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
import { createInterface } from "node:readline/promises";
|
|
5
|
-
import {
|
|
6
|
-
import { initRustBinProject } from "./rust-bin.js";
|
|
7
|
-
import { initTsLibProject } from "./ts-lib.js";
|
|
8
|
-
import { initVueHonoAppProject } from "./vue-hono-app.js";
|
|
9
|
-
import { initVueAppProject } from "./vue-app.js";
|
|
10
|
-
import { addPackage } from "./package-addition.js";
|
|
11
|
-
import { assembleGenerationContext } from "./generation-context.js";
|
|
12
|
-
import { planNextStepInstructions, } from "./next-step-instructions.js";
|
|
5
|
+
import { findBuiltInPresetProjection, projectPresetThroughRegistry, } from "../templates/registry.js";
|
|
13
6
|
import { blueprintJsonSchema, builtInPresets, presetFileJsonSchema, validatePresetFile, validateProjectBlueprint, } from "./declarations.js";
|
|
7
|
+
import { assembleGenerationContext, } from "./generation-context.js";
|
|
8
|
+
import { addPackage } from "./package-addition.js";
|
|
9
|
+
import { planNextStepInstructionsForProjection, } from "./preset-projection.js";
|
|
14
10
|
import { resolveToolchainVersions, } from "./toolchain-resolution.js";
|
|
15
11
|
function usage() {
|
|
16
12
|
return [
|
|
17
13
|
"Usage:",
|
|
18
14
|
" template init <dir> --preset <name> --yes",
|
|
19
|
-
" template add package --preset <name> --name <name>",
|
|
15
|
+
" template add package --preset <name> --name <name> [--path <package-path>]",
|
|
20
16
|
" template presets",
|
|
21
17
|
" template schema preset",
|
|
22
18
|
" template schema blueprint",
|
|
@@ -26,6 +22,7 @@ function usage() {
|
|
|
26
22
|
"Options:",
|
|
27
23
|
" --preset <name> Project preset to generate",
|
|
28
24
|
" --name <name> Package name to add",
|
|
25
|
+
" --path <path> Two-segment Package Path to add",
|
|
29
26
|
" --scope <name> Package scope for workspace package names",
|
|
30
27
|
" --yes Accept defaults for non-interactive generation",
|
|
31
28
|
" --dry-run Print the planned generation without writing files",
|
|
@@ -50,7 +47,9 @@ async function readJsonDeclaration(filePath) {
|
|
|
50
47
|
}
|
|
51
48
|
}
|
|
52
49
|
function formatValidationIssues(issues) {
|
|
53
|
-
return issues
|
|
50
|
+
return issues
|
|
51
|
+
.map((issue) => ` - ${issue.path}: ${issue.message}`)
|
|
52
|
+
.join("\n");
|
|
54
53
|
}
|
|
55
54
|
function formatPresetCatalog() {
|
|
56
55
|
return [
|
|
@@ -117,20 +116,31 @@ function normalizeNpmScope(value) {
|
|
|
117
116
|
function supportedPreset(name) {
|
|
118
117
|
const preset = builtInPresets.find((candidate) => candidate.name === name && candidate.generation === "supported");
|
|
119
118
|
if (!preset) {
|
|
120
|
-
throw new Error(
|
|
119
|
+
throw new Error(formatSupportedPresetError());
|
|
121
120
|
}
|
|
122
121
|
return preset;
|
|
123
122
|
}
|
|
124
|
-
function
|
|
125
|
-
|
|
123
|
+
function formatSupportedPresetError() {
|
|
124
|
+
const supportedPresetNames = builtInPresets
|
|
125
|
+
.filter((preset) => preset.generation === "supported")
|
|
126
|
+
.map((preset) => preset.name);
|
|
127
|
+
return `Only the ${formatList(supportedPresetNames)} presets are supported in this version`;
|
|
126
128
|
}
|
|
127
|
-
function
|
|
128
|
-
|
|
129
|
+
function formatList(values) {
|
|
130
|
+
if (values.length <= 1) {
|
|
131
|
+
return values[0] ?? "";
|
|
132
|
+
}
|
|
133
|
+
return `${values.slice(0, -1).join(", ")}, and ${values.at(-1)}`;
|
|
129
134
|
}
|
|
130
135
|
function blueprintForInit(options) {
|
|
131
136
|
const preset = supportedPreset(options.preset);
|
|
132
|
-
const
|
|
133
|
-
|
|
137
|
+
const projection = findBuiltInPresetProjection(preset.name);
|
|
138
|
+
if (projection) {
|
|
139
|
+
return projection.blueprint({
|
|
140
|
+
targetDir: options.dir,
|
|
141
|
+
scope: options.scope,
|
|
142
|
+
});
|
|
143
|
+
}
|
|
134
144
|
const blueprint = {
|
|
135
145
|
schemaVersion: 1,
|
|
136
146
|
preset: preset.name,
|
|
@@ -140,12 +150,6 @@ function blueprintForInit(options) {
|
|
|
140
150
|
if (preset.supportedPackageManagers[0]) {
|
|
141
151
|
blueprint.packageManager = preset.supportedPackageManagers[0];
|
|
142
152
|
}
|
|
143
|
-
if (preset.name === "vue-hono-app") {
|
|
144
|
-
blueprint.packages = [
|
|
145
|
-
{ name: `@${packageScope}/web`, path: "apps/web" },
|
|
146
|
-
{ name: `@${packageScope}/api`, path: "apps/api" },
|
|
147
|
-
];
|
|
148
|
-
}
|
|
149
153
|
return blueprint;
|
|
150
154
|
}
|
|
151
155
|
function formatBlueprintSummary(targetDir, blueprint) {
|
|
@@ -167,11 +171,14 @@ function formatBlueprintSummary(targetDir, blueprint) {
|
|
|
167
171
|
lines.push(` Features: ${blueprint.features.join(", ")}`);
|
|
168
172
|
return lines.join("\n");
|
|
169
173
|
}
|
|
170
|
-
function
|
|
171
|
-
const
|
|
174
|
+
function formatProjectionNextSteps(targetDir, projectionPlan) {
|
|
175
|
+
const steps = planNextStepInstructionsForProjection({
|
|
176
|
+
targetDir,
|
|
177
|
+
plan: projectionPlan,
|
|
178
|
+
});
|
|
172
179
|
return [
|
|
173
180
|
"Next Step Instructions:",
|
|
174
|
-
...
|
|
181
|
+
...steps.map((step) => ` ${step.label}: ${step.display}`),
|
|
175
182
|
].join("\n");
|
|
176
183
|
}
|
|
177
184
|
function toolchainReport(toolchain) {
|
|
@@ -199,7 +206,7 @@ function toolchainResolutionSourceFromEnv() {
|
|
|
199
206
|
return undefined;
|
|
200
207
|
}
|
|
201
208
|
async function generationContextForInit(options, blueprint) {
|
|
202
|
-
if (options.preset
|
|
209
|
+
if (!findBuiltInPresetProjection(options.preset)) {
|
|
203
210
|
return undefined;
|
|
204
211
|
}
|
|
205
212
|
return assembleGenerationContext({
|
|
@@ -213,38 +220,37 @@ async function generationContextForInit(options, blueprint) {
|
|
|
213
220
|
});
|
|
214
221
|
}
|
|
215
222
|
async function generateInitProject(options, generationContext) {
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
}
|
|
224
|
-
if (options.preset === "vue-app") {
|
|
225
|
-
await initVueAppProject(options.dir);
|
|
226
|
-
return;
|
|
227
|
-
}
|
|
228
|
-
if (options.preset === "vue-hono-app") {
|
|
229
|
-
await initVueHonoAppProject(options.dir, { scope: options.scope });
|
|
230
|
-
return;
|
|
231
|
-
}
|
|
232
|
-
if (options.preset === "rust-bin") {
|
|
233
|
-
await initRustBinProject(options.dir, { generationContext });
|
|
223
|
+
const projection = findBuiltInPresetProjection(options.preset);
|
|
224
|
+
if (projection) {
|
|
225
|
+
if (!generationContext) {
|
|
226
|
+
throw new Error(`Missing Generation Context for Preset Projection: ${options.preset}`);
|
|
227
|
+
}
|
|
228
|
+
const plan = projection.project(generationContext);
|
|
229
|
+
await projection.render({ targetDir: options.dir, plan });
|
|
234
230
|
return;
|
|
235
231
|
}
|
|
236
|
-
throw new Error(
|
|
232
|
+
throw new Error(formatSupportedPresetError());
|
|
237
233
|
}
|
|
238
234
|
function printInitComplete(options, blueprint, generationContext) {
|
|
239
|
-
const
|
|
240
|
-
|
|
235
|
+
const projectionPlan = generationContext
|
|
236
|
+
? projectPresetThroughRegistry(generationContext)
|
|
237
|
+
: undefined;
|
|
238
|
+
if (!projectionPlan) {
|
|
239
|
+
throw new Error(`Missing Preset Projection plan: ${blueprint.preset}`);
|
|
240
|
+
}
|
|
241
|
+
const nextSteps = planNextStepInstructionsForProjection({
|
|
242
|
+
targetDir: options.dir,
|
|
243
|
+
plan: projectionPlan,
|
|
244
|
+
});
|
|
241
245
|
if (options.json) {
|
|
242
246
|
printJson({
|
|
243
247
|
command: "init",
|
|
244
248
|
dryRun: false,
|
|
245
249
|
targetDir: options.dir,
|
|
246
250
|
blueprint,
|
|
247
|
-
toolchain: generationContext
|
|
251
|
+
toolchain: generationContext
|
|
252
|
+
? toolchainReport(generationContext.toolchain)
|
|
253
|
+
: undefined,
|
|
248
254
|
nextSteps,
|
|
249
255
|
});
|
|
250
256
|
return;
|
|
@@ -253,7 +259,7 @@ function printInitComplete(options, blueprint, generationContext) {
|
|
|
253
259
|
if (generationContext) {
|
|
254
260
|
console.log(formatToolchainReport(generationContext.toolchain));
|
|
255
261
|
}
|
|
256
|
-
console.log(
|
|
262
|
+
console.log(formatProjectionNextSteps(options.dir, projectionPlan));
|
|
257
263
|
}
|
|
258
264
|
function isInteractiveTerminal() {
|
|
259
265
|
return Boolean(process.stdin.isTTY && process.stdout.isTTY);
|
|
@@ -266,7 +272,8 @@ async function confirmInit(targetDir, blueprint) {
|
|
|
266
272
|
});
|
|
267
273
|
try {
|
|
268
274
|
const answer = await readline.question("Generate this project? [y/N] ");
|
|
269
|
-
return answer.trim().toLowerCase() === "y" ||
|
|
275
|
+
return (answer.trim().toLowerCase() === "y" ||
|
|
276
|
+
answer.trim().toLowerCase() === "yes");
|
|
270
277
|
}
|
|
271
278
|
finally {
|
|
272
279
|
readline.close();
|
|
@@ -275,6 +282,7 @@ async function confirmInit(targetDir, blueprint) {
|
|
|
275
282
|
function parseAddPackageOptions(args) {
|
|
276
283
|
let preset = "";
|
|
277
284
|
let name = "";
|
|
285
|
+
let packagePath;
|
|
278
286
|
for (let index = 2; index < args.length; index += 1) {
|
|
279
287
|
const arg = args[index];
|
|
280
288
|
if (arg === "--preset") {
|
|
@@ -295,6 +303,15 @@ function parseAddPackageOptions(args) {
|
|
|
295
303
|
index += 1;
|
|
296
304
|
continue;
|
|
297
305
|
}
|
|
306
|
+
if (arg === "--path") {
|
|
307
|
+
const value = args[index + 1];
|
|
308
|
+
if (!value) {
|
|
309
|
+
throw new Error("--path requires a value");
|
|
310
|
+
}
|
|
311
|
+
packagePath = value;
|
|
312
|
+
index += 1;
|
|
313
|
+
continue;
|
|
314
|
+
}
|
|
298
315
|
throw new Error(`Unknown option: ${arg}`);
|
|
299
316
|
}
|
|
300
317
|
if (!preset) {
|
|
@@ -303,7 +320,7 @@ function parseAddPackageOptions(args) {
|
|
|
303
320
|
if (!name) {
|
|
304
321
|
throw new Error("add package requires --name");
|
|
305
322
|
}
|
|
306
|
-
return { preset, name };
|
|
323
|
+
return { preset, name, path: packagePath };
|
|
307
324
|
}
|
|
308
325
|
async function main(args) {
|
|
309
326
|
const command = args[0];
|
|
@@ -352,23 +369,34 @@ async function main(args) {
|
|
|
352
369
|
const blueprint = blueprintForInit(options);
|
|
353
370
|
if (options.dryRun) {
|
|
354
371
|
const generationContext = await generationContextForInit(options, blueprint);
|
|
355
|
-
const
|
|
356
|
-
|
|
372
|
+
const projectionPlan = generationContext
|
|
373
|
+
? projectPresetThroughRegistry(generationContext)
|
|
374
|
+
: undefined;
|
|
375
|
+
if (!projectionPlan) {
|
|
376
|
+
throw new Error(`Missing Preset Projection plan: ${blueprint.preset}`);
|
|
377
|
+
}
|
|
378
|
+
const nextSteps = planNextStepInstructionsForProjection({
|
|
357
379
|
targetDir: options.dir,
|
|
358
|
-
|
|
380
|
+
plan: projectionPlan,
|
|
381
|
+
});
|
|
359
382
|
if (options.json) {
|
|
360
383
|
printJson({
|
|
361
384
|
command: "init",
|
|
362
385
|
dryRun: true,
|
|
363
386
|
targetDir: options.dir,
|
|
364
387
|
blueprint,
|
|
365
|
-
toolchain: generationContext
|
|
388
|
+
toolchain: generationContext
|
|
389
|
+
? toolchainReport(generationContext.toolchain)
|
|
390
|
+
: undefined,
|
|
366
391
|
nextSteps,
|
|
367
392
|
});
|
|
368
393
|
return;
|
|
369
394
|
}
|
|
370
395
|
console.log(formatBlueprintSummary(options.dir, blueprint));
|
|
371
|
-
|
|
396
|
+
if (generationContext) {
|
|
397
|
+
console.log(formatToolchainReport(generationContext.toolchain));
|
|
398
|
+
}
|
|
399
|
+
console.log(formatProjectionNextSteps(options.dir, projectionPlan));
|
|
372
400
|
return;
|
|
373
401
|
}
|
|
374
402
|
if (!options.yes && (options.json || !isInteractiveTerminal())) {
|
|
@@ -384,7 +412,12 @@ async function main(args) {
|
|
|
384
412
|
}
|
|
385
413
|
if (command === "add" && args[1] === "package") {
|
|
386
414
|
const options = parseAddPackageOptions(args);
|
|
387
|
-
await addPackage({
|
|
415
|
+
await addPackage({
|
|
416
|
+
cwd: process.cwd(),
|
|
417
|
+
preset: options.preset,
|
|
418
|
+
name: options.name,
|
|
419
|
+
path: options.path,
|
|
420
|
+
});
|
|
388
421
|
console.log(`Added ${options.preset} package ${options.name}`);
|
|
389
422
|
return;
|
|
390
423
|
}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import * as v from "valibot";
|
|
2
|
-
export type PresetName = "ts-lib" | "hono-api" | "vue-app" | "vue-hono-app" | "rust-bin" | "ts-app" | "node-cli";
|
|
3
2
|
export type BuiltInPreset = {
|
|
4
|
-
name:
|
|
3
|
+
name: string;
|
|
5
4
|
title: string;
|
|
6
5
|
description: string;
|
|
7
6
|
generation: "supported" | "future";
|
|
@@ -68,7 +67,7 @@ export declare const presetFileJsonSchema: {
|
|
|
68
67
|
readonly type: "array";
|
|
69
68
|
readonly minItems: 1;
|
|
70
69
|
readonly items: {
|
|
71
|
-
readonly enum: readonly ["
|
|
70
|
+
readonly enum: readonly ["multi-package"];
|
|
72
71
|
};
|
|
73
72
|
readonly uniqueItems: true;
|
|
74
73
|
};
|
|
@@ -100,7 +99,7 @@ export declare const blueprintJsonSchema: {
|
|
|
100
99
|
readonly enum: readonly ["pnpm"];
|
|
101
100
|
};
|
|
102
101
|
readonly projectKind: {
|
|
103
|
-
readonly enum: readonly ["
|
|
102
|
+
readonly enum: readonly ["multi-package"];
|
|
104
103
|
};
|
|
105
104
|
readonly features: {
|
|
106
105
|
readonly type: "array";
|
|
@@ -163,4 +162,3 @@ export type ValidationResult<T> = {
|
|
|
163
162
|
export declare function validatePresetFile(input: unknown): ValidationResult<PresetFile>;
|
|
164
163
|
export declare function findBuiltInPreset(name: string): BuiltInPreset | undefined;
|
|
165
164
|
export declare function validateProjectBlueprint(input: unknown): ValidationResult<ProjectBlueprint>;
|
|
166
|
-
//# sourceMappingURL=declarations.d.ts.map
|
|
@@ -1,113 +1,6 @@
|
|
|
1
1
|
import * as v from "valibot";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
name: "ts-lib",
|
|
5
|
-
title: "TypeScript library",
|
|
6
|
-
description: "Strict TypeScript package with pnpm catalog tooling.",
|
|
7
|
-
generation: "supported",
|
|
8
|
-
supportedPackageManagers: ["pnpm"],
|
|
9
|
-
supportedProjectKinds: ["single-package"],
|
|
10
|
-
features: [
|
|
11
|
-
"pnpm-catalog",
|
|
12
|
-
"oxc-format-lint",
|
|
13
|
-
"strict-typescript",
|
|
14
|
-
"root-check",
|
|
15
|
-
"fix-command",
|
|
16
|
-
"devcontainer",
|
|
17
|
-
"github-actions",
|
|
18
|
-
"dependabot"
|
|
19
|
-
]
|
|
20
|
-
},
|
|
21
|
-
{
|
|
22
|
-
name: "hono-api",
|
|
23
|
-
title: "Hono API",
|
|
24
|
-
description: "Single-package Hono Node API with strict TypeScript tooling.",
|
|
25
|
-
generation: "supported",
|
|
26
|
-
supportedPackageManagers: ["pnpm"],
|
|
27
|
-
supportedProjectKinds: ["single-package"],
|
|
28
|
-
features: [
|
|
29
|
-
"pnpm-catalog",
|
|
30
|
-
"oxc-format-lint",
|
|
31
|
-
"strict-typescript",
|
|
32
|
-
"root-check",
|
|
33
|
-
"fix-command",
|
|
34
|
-
"devcontainer",
|
|
35
|
-
"github-actions",
|
|
36
|
-
"dependabot"
|
|
37
|
-
]
|
|
38
|
-
},
|
|
39
|
-
{
|
|
40
|
-
name: "vue-app",
|
|
41
|
-
title: "Vue app",
|
|
42
|
-
description: "Single-package Vue app with Vite, Tailwind, Pinia, and test tooling.",
|
|
43
|
-
generation: "supported",
|
|
44
|
-
supportedPackageManagers: ["pnpm"],
|
|
45
|
-
supportedProjectKinds: ["single-package"],
|
|
46
|
-
features: [
|
|
47
|
-
"pnpm-catalog",
|
|
48
|
-
"oxc-format-lint",
|
|
49
|
-
"strict-typescript",
|
|
50
|
-
"root-check",
|
|
51
|
-
"fix-command",
|
|
52
|
-
"devcontainer",
|
|
53
|
-
"github-actions",
|
|
54
|
-
"dependabot"
|
|
55
|
-
]
|
|
56
|
-
},
|
|
57
|
-
{
|
|
58
|
-
name: "vue-hono-app",
|
|
59
|
-
title: "Vue Hono app",
|
|
60
|
-
description: "Full-stack Vue and Hono workspace with Hono RPC typing.",
|
|
61
|
-
generation: "supported",
|
|
62
|
-
supportedPackageManagers: ["pnpm"],
|
|
63
|
-
supportedProjectKinds: ["multi-package"],
|
|
64
|
-
features: [
|
|
65
|
-
"pnpm-catalog",
|
|
66
|
-
"oxc-format-lint",
|
|
67
|
-
"strict-typescript",
|
|
68
|
-
"root-check",
|
|
69
|
-
"fix-command",
|
|
70
|
-
"devcontainer",
|
|
71
|
-
"github-actions",
|
|
72
|
-
"dependabot"
|
|
73
|
-
]
|
|
74
|
-
},
|
|
75
|
-
{
|
|
76
|
-
name: "rust-bin",
|
|
77
|
-
title: "Rust binary",
|
|
78
|
-
description: "Single-package Rust native binary with rustfmt, clippy, and cargo tests.",
|
|
79
|
-
generation: "supported",
|
|
80
|
-
supportedPackageManagers: ["pnpm"],
|
|
81
|
-
supportedProjectKinds: ["single-package"],
|
|
82
|
-
features: [
|
|
83
|
-
"root-check",
|
|
84
|
-
"fix-command",
|
|
85
|
-
"devcontainer",
|
|
86
|
-
"github-actions",
|
|
87
|
-
"dependabot",
|
|
88
|
-
"rustfmt-clippy",
|
|
89
|
-
"cargo-test"
|
|
90
|
-
]
|
|
91
|
-
},
|
|
92
|
-
{
|
|
93
|
-
name: "ts-app",
|
|
94
|
-
title: "TypeScript application",
|
|
95
|
-
description: "Future application preset metadata.",
|
|
96
|
-
generation: "future",
|
|
97
|
-
supportedPackageManagers: ["pnpm"],
|
|
98
|
-
supportedProjectKinds: ["single-package"],
|
|
99
|
-
features: []
|
|
100
|
-
},
|
|
101
|
-
{
|
|
102
|
-
name: "node-cli",
|
|
103
|
-
title: "Node.js CLI",
|
|
104
|
-
description: "Future command-line preset metadata.",
|
|
105
|
-
generation: "future",
|
|
106
|
-
supportedPackageManagers: ["pnpm"],
|
|
107
|
-
supportedProjectKinds: ["single-package"],
|
|
108
|
-
features: []
|
|
109
|
-
}
|
|
110
|
-
];
|
|
2
|
+
import { builtInPresetMetadata } from "../templates/registry.js";
|
|
3
|
+
export const builtInPresets = builtInPresetMetadata;
|
|
111
4
|
const featureNames = [
|
|
112
5
|
"pnpm-catalog",
|
|
113
6
|
"oxc-format-lint",
|
|
@@ -119,7 +12,7 @@ const featureNames = [
|
|
|
119
12
|
"dependabot",
|
|
120
13
|
"rustfmt-clippy",
|
|
121
14
|
"cargo-test",
|
|
122
|
-
"native-binary-release"
|
|
15
|
+
"native-binary-release",
|
|
123
16
|
];
|
|
124
17
|
export const presetFileJsonSchema = {
|
|
125
18
|
$schema: "https://json-schema.org/draft/2020-12/schema",
|
|
@@ -134,7 +27,7 @@ export const presetFileJsonSchema = {
|
|
|
134
27
|
"description",
|
|
135
28
|
"supportedPackageManagers",
|
|
136
29
|
"supportedProjectKinds",
|
|
137
|
-
"features"
|
|
30
|
+
"features",
|
|
138
31
|
],
|
|
139
32
|
properties: {
|
|
140
33
|
schemaVersion: { const: 1 },
|
|
@@ -144,20 +37,20 @@ export const presetFileJsonSchema = {
|
|
|
144
37
|
supportedPackageManagers: {
|
|
145
38
|
type: "array",
|
|
146
39
|
items: { enum: ["pnpm"] },
|
|
147
|
-
uniqueItems: true
|
|
40
|
+
uniqueItems: true,
|
|
148
41
|
},
|
|
149
42
|
supportedProjectKinds: {
|
|
150
43
|
type: "array",
|
|
151
44
|
minItems: 1,
|
|
152
|
-
items: { enum: ["
|
|
153
|
-
uniqueItems: true
|
|
45
|
+
items: { enum: ["multi-package"] },
|
|
46
|
+
uniqueItems: true,
|
|
154
47
|
},
|
|
155
48
|
features: {
|
|
156
49
|
type: "array",
|
|
157
50
|
items: { enum: featureNames },
|
|
158
|
-
uniqueItems: true
|
|
159
|
-
}
|
|
160
|
-
}
|
|
51
|
+
uniqueItems: true,
|
|
52
|
+
},
|
|
53
|
+
},
|
|
161
54
|
};
|
|
162
55
|
export const blueprintJsonSchema = {
|
|
163
56
|
$schema: "https://json-schema.org/draft/2020-12/schema",
|
|
@@ -170,11 +63,11 @@ export const blueprintJsonSchema = {
|
|
|
170
63
|
schemaVersion: { const: 1 },
|
|
171
64
|
preset: { type: "string", minLength: 1 },
|
|
172
65
|
packageManager: { enum: ["pnpm"] },
|
|
173
|
-
projectKind: { enum: ["
|
|
66
|
+
projectKind: { enum: ["multi-package"] },
|
|
174
67
|
features: {
|
|
175
68
|
type: "array",
|
|
176
69
|
items: { enum: featureNames },
|
|
177
|
-
uniqueItems: true
|
|
70
|
+
uniqueItems: true,
|
|
178
71
|
},
|
|
179
72
|
packages: {
|
|
180
73
|
type: "array",
|
|
@@ -184,15 +77,18 @@ export const blueprintJsonSchema = {
|
|
|
184
77
|
required: ["name", "path"],
|
|
185
78
|
properties: {
|
|
186
79
|
name: { type: "string", minLength: 1 },
|
|
187
|
-
path: { type: "string", minLength: 1 }
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
}
|
|
80
|
+
path: { type: "string", minLength: 1 },
|
|
81
|
+
},
|
|
82
|
+
},
|
|
83
|
+
},
|
|
84
|
+
},
|
|
192
85
|
};
|
|
193
86
|
const nonEmptyString = v.pipe(v.string(), v.minLength(1));
|
|
194
87
|
const packageManagerSchema = v.picklist(["pnpm"]);
|
|
195
|
-
const projectKindSchema = v.picklist([
|
|
88
|
+
const projectKindSchema = v.picklist([
|
|
89
|
+
"single-package",
|
|
90
|
+
"multi-package",
|
|
91
|
+
]);
|
|
196
92
|
const featureNameSchema = v.picklist(featureNames);
|
|
197
93
|
export const presetFileSchema = v.strictObject({
|
|
198
94
|
schemaVersion: v.literal(1),
|
|
@@ -201,7 +97,7 @@ export const presetFileSchema = v.strictObject({
|
|
|
201
97
|
description: nonEmptyString,
|
|
202
98
|
supportedPackageManagers: v.array(packageManagerSchema),
|
|
203
99
|
supportedProjectKinds: v.pipe(v.array(projectKindSchema), v.minLength(1)),
|
|
204
|
-
features: v.array(featureNameSchema)
|
|
100
|
+
features: v.array(featureNameSchema),
|
|
205
101
|
});
|
|
206
102
|
export const projectBlueprintSchema = v.strictObject({
|
|
207
103
|
schemaVersion: v.literal(1),
|
|
@@ -211,8 +107,8 @@ export const projectBlueprintSchema = v.strictObject({
|
|
|
211
107
|
features: v.array(featureNameSchema),
|
|
212
108
|
packages: v.optional(v.array(v.strictObject({
|
|
213
109
|
name: nonEmptyString,
|
|
214
|
-
path: nonEmptyString
|
|
215
|
-
})))
|
|
110
|
+
path: nonEmptyString,
|
|
111
|
+
}))),
|
|
216
112
|
});
|
|
217
113
|
function formatIssuePath(issue) {
|
|
218
114
|
if (!issue.path || issue.path.length === 0) {
|
|
@@ -223,7 +119,7 @@ function formatIssuePath(issue) {
|
|
|
223
119
|
function shapeIssues(issues) {
|
|
224
120
|
return issues.map((issue) => ({
|
|
225
121
|
path: formatIssuePath(issue),
|
|
226
|
-
message: issue.message
|
|
122
|
+
message: issue.message,
|
|
227
123
|
}));
|
|
228
124
|
}
|
|
229
125
|
function duplicateIssues(values, path) {
|
|
@@ -237,7 +133,7 @@ function duplicateIssues(values, path) {
|
|
|
237
133
|
}
|
|
238
134
|
return [...duplicates].map((value) => ({
|
|
239
135
|
path,
|
|
240
|
-
message: `Duplicate value: ${value}
|
|
136
|
+
message: `Duplicate value: ${value}`,
|
|
241
137
|
}));
|
|
242
138
|
}
|
|
243
139
|
function generationSupportIssue(preset, path) {
|
|
@@ -246,7 +142,13 @@ function generationSupportIssue(preset, path) {
|
|
|
246
142
|
}
|
|
247
143
|
return {
|
|
248
144
|
path,
|
|
249
|
-
message: `Preset ${preset.name} is not supported for generation in this version
|
|
145
|
+
message: `Preset ${preset.name} is not supported for generation in this version`,
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
function unsupportedSinglePackageProjectShapeIssue(path) {
|
|
149
|
+
return {
|
|
150
|
+
path,
|
|
151
|
+
message: "single-package Project Shape is unsupported in V1; use the workspace monorepo Project Shape",
|
|
250
152
|
};
|
|
251
153
|
}
|
|
252
154
|
export function validatePresetFile(input) {
|
|
@@ -257,8 +159,11 @@ export function validatePresetFile(input) {
|
|
|
257
159
|
const semanticIssues = [
|
|
258
160
|
...duplicateIssues(result.output.supportedPackageManagers, "$.supportedPackageManagers"),
|
|
259
161
|
...duplicateIssues(result.output.supportedProjectKinds, "$.supportedProjectKinds"),
|
|
260
|
-
...duplicateIssues(result.output.features, "$.features")
|
|
162
|
+
...duplicateIssues(result.output.features, "$.features"),
|
|
261
163
|
];
|
|
164
|
+
if (result.output.supportedProjectKinds.includes("single-package")) {
|
|
165
|
+
semanticIssues.push(unsupportedSinglePackageProjectShapeIssue("$.supportedProjectKinds"));
|
|
166
|
+
}
|
|
262
167
|
const builtInPreset = findBuiltInPreset(result.output.name);
|
|
263
168
|
const unsupportedGeneration = builtInPreset
|
|
264
169
|
? generationSupportIssue(builtInPreset, "$.name")
|
|
@@ -282,12 +187,15 @@ export function validateProjectBlueprint(input) {
|
|
|
282
187
|
const blueprint = result.output;
|
|
283
188
|
const preset = findBuiltInPreset(blueprint.preset);
|
|
284
189
|
const semanticIssues = [
|
|
285
|
-
...duplicateIssues(blueprint.features, "$.features")
|
|
190
|
+
...duplicateIssues(blueprint.features, "$.features"),
|
|
286
191
|
];
|
|
192
|
+
if (blueprint.projectKind === "single-package") {
|
|
193
|
+
semanticIssues.push(unsupportedSinglePackageProjectShapeIssue("$.projectKind"));
|
|
194
|
+
}
|
|
287
195
|
if (!preset) {
|
|
288
196
|
semanticIssues.push({
|
|
289
197
|
path: "$.preset",
|
|
290
|
-
message: `Unknown built-in preset: ${blueprint.preset}
|
|
198
|
+
message: `Unknown built-in preset: ${blueprint.preset}`,
|
|
291
199
|
});
|
|
292
200
|
}
|
|
293
201
|
else {
|
|
@@ -299,19 +207,20 @@ export function validateProjectBlueprint(input) {
|
|
|
299
207
|
!preset.supportedPackageManagers.includes(blueprint.packageManager)) {
|
|
300
208
|
semanticIssues.push({
|
|
301
209
|
path: "$.packageManager",
|
|
302
|
-
message: `${blueprint.packageManager} is not supported by preset ${preset.name}
|
|
210
|
+
message: `${blueprint.packageManager} is not supported by preset ${preset.name}`,
|
|
303
211
|
});
|
|
304
212
|
}
|
|
305
|
-
if (!blueprint.packageManager &&
|
|
213
|
+
if (!blueprint.packageManager &&
|
|
214
|
+
preset.supportedPackageManagers.length > 0) {
|
|
306
215
|
semanticIssues.push({
|
|
307
216
|
path: "$.packageManager",
|
|
308
|
-
message: `packageManager is required by preset ${preset.name}
|
|
217
|
+
message: `packageManager is required by preset ${preset.name}`,
|
|
309
218
|
});
|
|
310
219
|
}
|
|
311
220
|
if (!preset.supportedProjectKinds.includes(blueprint.projectKind)) {
|
|
312
221
|
semanticIssues.push({
|
|
313
222
|
path: "$.projectKind",
|
|
314
|
-
message: `${blueprint.projectKind} is not supported by preset ${preset.name}
|
|
223
|
+
message: `${blueprint.projectKind} is not supported by preset ${preset.name}`,
|
|
315
224
|
});
|
|
316
225
|
}
|
|
317
226
|
const supportedFeatures = new Set(preset.features);
|
|
@@ -319,18 +228,12 @@ export function validateProjectBlueprint(input) {
|
|
|
319
228
|
if (!supportedFeatures.has(feature)) {
|
|
320
229
|
semanticIssues.push({
|
|
321
230
|
path: "$.features",
|
|
322
|
-
message: `${feature} is not supported by preset ${preset.name}
|
|
231
|
+
message: `${feature} is not supported by preset ${preset.name}`,
|
|
323
232
|
});
|
|
324
233
|
}
|
|
325
234
|
}
|
|
326
235
|
}
|
|
327
236
|
if (blueprint.packages) {
|
|
328
|
-
if (blueprint.projectKind === "single-package" && blueprint.packages.length > 1) {
|
|
329
|
-
semanticIssues.push({
|
|
330
|
-
path: "$.packages",
|
|
331
|
-
message: "single-package blueprints support exactly one package"
|
|
332
|
-
});
|
|
333
|
-
}
|
|
334
237
|
semanticIssues.push(...duplicateIssues(blueprint.packages.map((projectPackage) => projectPackage.name), "$.packages.name"), ...duplicateIssues(blueprint.packages.map((projectPackage) => projectPackage.path), "$.packages.path"));
|
|
335
238
|
}
|
|
336
239
|
if (semanticIssues.length > 0) {
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export type TemplateDependencyCatalog = Record<string, string>;
|
|
2
|
+
export type GeneratedDependencyCatalogOptions = {
|
|
3
|
+
readonly dependencies: readonly string[];
|
|
4
|
+
readonly packages?: readonly string[];
|
|
5
|
+
readonly allowBuilds?: Record<string, boolean>;
|
|
6
|
+
};
|
|
7
|
+
export type GeneratedPackageManifestDependencies = {
|
|
8
|
+
readonly dependencies?: Record<string, string>;
|
|
9
|
+
readonly devDependencies?: Record<string, string>;
|
|
10
|
+
readonly optionalDependencies?: Record<string, string>;
|
|
11
|
+
readonly peerDependencies?: Record<string, string>;
|
|
12
|
+
};
|
|
13
|
+
export declare function loadTemplateDependencyCatalog(): TemplateDependencyCatalog;
|
|
14
|
+
export declare function selectTemplateDependencyCatalogEntries(dependencies: readonly string[], catalog?: TemplateDependencyCatalog): TemplateDependencyCatalog;
|
|
15
|
+
export declare function collectGeneratedManifestCatalogDependencies(manifests: readonly GeneratedPackageManifestDependencies[]): string[];
|
|
16
|
+
export declare function collectGeneratedManifestCatalogReferences(manifests: readonly GeneratedPackageManifestDependencies[]): string[];
|
|
17
|
+
export declare function pnpmWorkspaceYamlWithCatalogDependencies(workspaceYaml: string, dependencies: readonly string[], templateCatalog?: TemplateDependencyCatalog): string;
|
|
18
|
+
export declare function renderGeneratedPnpmWorkspaceYaml(options: GeneratedDependencyCatalogOptions): string;
|