@ykdz/template 0.0.17 → 0.0.19
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 +61 -24
- package/node_modules/@ykdz/template-builtin-source/dist/templates/registry.js +0 -2
- package/node_modules/@ykdz/template-builtin-source/dist/templates/ts-lib/projection.js +4 -4
- package/node_modules/@ykdz/template-builtin-source/dist/templates/vike-app/projection.js +13 -2
- package/node_modules/@ykdz/template-builtin-source/dist/templates/vue-app/projection.js +6 -74
- package/node_modules/@ykdz/template-builtin-source/dist/templates/vue-hono-app/projection.js +23 -22
- package/node_modules/@ykdz/template-builtin-source/package.json +41 -8
- package/node_modules/@ykdz/template-builtin-source/templates/preset-source.json +69 -282
- package/node_modules/@ykdz/template-builtin-source/templates/rust-bin/src/main.rs +5 -2
- package/node_modules/@ykdz/template-builtin-source/templates/rust-bin/turbo.json +2 -1
- package/node_modules/@ykdz/template-builtin-source/templates/ts-lib/turbo.json +2 -1
- package/node_modules/@ykdz/template-builtin-source/templates/vike-app/{drizzle.config.ts → db/drizzle.config.ts} +2 -2
- package/node_modules/@ykdz/template-builtin-source/templates/vike-app/{database → db/src}/db.ts +1 -1
- package/node_modules/@ykdz/template-builtin-source/templates/vike-app/db/src/index.ts +1 -0
- package/node_modules/@ykdz/template-builtin-source/templates/vike-app/{database → db/src}/queries/todos.ts +4 -8
- package/node_modules/@ykdz/template-builtin-source/templates/vike-app/{test → db/test}/todos.test.ts +2 -2
- package/node_modules/@ykdz/template-builtin-source/templates/{hono-api → vike-app/db}/turbo.json +2 -1
- package/node_modules/@ykdz/template-builtin-source/templates/vike-app/{pages → web/pages}/index/+Page.telefunc.ts +3 -1
- package/node_modules/@ykdz/template-builtin-source/templates/vike-app/{pages → web/pages}/index/+Page.vue +1 -2
- package/node_modules/@ykdz/template-builtin-source/templates/vike-app/web/playwright.config.ts +43 -0
- package/node_modules/@ykdz/template-builtin-source/templates/vike-app/web/scripts/run-playwright.ts +62 -0
- package/node_modules/@ykdz/template-builtin-source/templates/vike-app/{server → web/server}/app.ts +1 -1
- package/node_modules/@ykdz/template-builtin-source/templates/vike-app/{test → web/test}/e2e/app.spec.ts +1 -1
- package/node_modules/@ykdz/template-builtin-source/templates/vike-app/web/turbo.json +12 -0
- package/node_modules/@ykdz/template-builtin-source/templates/vike-app/{types → web/types}/global.d.ts +1 -1
- package/node_modules/@ykdz/template-builtin-source/templates/vike-app/{vite.config.ts → web/vite.config.ts} +1 -0
- package/node_modules/@ykdz/template-builtin-source/templates/vue-app/playwright.config.ts +16 -3
- package/node_modules/@ykdz/template-builtin-source/templates/vue-app/scripts/run-playwright.ts +38 -1
- package/node_modules/@ykdz/template-builtin-source/templates/vue-app/turbo.json +1 -0
- package/node_modules/@ykdz/template-builtin-source/templates/vue-hono-app/api/turbo.json +1 -0
- package/node_modules/@ykdz/template-builtin-source/templates/vue-hono-app/web/playwright.config.ts +7 -9
- package/node_modules/@ykdz/template-builtin-source/templates/vue-hono-app/web/scripts/run-playwright.ts +79 -1
- package/node_modules/@ykdz/template-builtin-source/templates/vue-hono-app/web/src/App.vue +4 -5
- package/node_modules/@ykdz/template-builtin-source/templates/vue-hono-app/web/src/api.ts +9 -3
- package/node_modules/@ykdz/template-builtin-source/templates/vue-hono-app/web/test/e2e/app.spec.ts +1 -1
- package/node_modules/@ykdz/template-builtin-source/templates/vue-hono-app/web/turbo.json +1 -0
- package/node_modules/@ykdz/template-core/dist/Cargo.lock +16 -0
- package/node_modules/@ykdz/template-core/dist/Cargo.toml +12 -0
- package/node_modules/@ykdz/template-core/dist/dependency-catalog.d.ts +8 -0
- package/node_modules/@ykdz/template-core/dist/dependency-catalog.js +63 -2
- package/node_modules/@ykdz/template-core/dist/generated-scenarios.d.ts +1 -1
- package/node_modules/@ykdz/template-core/dist/generated-scenarios.js +104 -26
- package/node_modules/@ykdz/template-core/dist/module-graph.d.ts +1 -0
- package/node_modules/@ykdz/template-core/dist/module-graph.js +19 -12
- package/node_modules/@ykdz/template-core/dist/next-step-instructions.d.ts +8 -0
- package/node_modules/@ykdz/template-core/dist/next-step-instructions.js +65 -0
- package/node_modules/@ykdz/template-core/dist/package-addition.js +6 -12
- package/node_modules/@ykdz/template-core/dist/package-linking.d.ts +24 -0
- package/node_modules/@ykdz/template-core/dist/package-linking.js +35 -0
- package/node_modules/@ykdz/template-core/dist/preset-source.d.ts +2 -2
- package/node_modules/@ykdz/template-core/dist/projection-capabilities.js +240 -153
- package/node_modules/@ykdz/template-core/dist/template-boundary-check.js +46 -10
- package/node_modules/@ykdz/template-core/package.json +9 -5
- package/node_modules/@ykdz/template-shared/dist/index.d.ts +3 -152
- package/node_modules/@ykdz/template-shared/dist/index.js +49 -305
- package/node_modules/@ykdz/template-shared/package.json +8 -4
- package/package.json +5 -5
- package/node_modules/@ykdz/template-builtin-source/dist/templates/hono-api/projection.d.ts +0 -6
- package/node_modules/@ykdz/template-builtin-source/dist/templates/hono-api/projection.js +0 -213
- package/node_modules/@ykdz/template-builtin-source/templates/hono-api/.github/dependabot.yml +0 -23
- package/node_modules/@ykdz/template-builtin-source/templates/hono-api/.github/workflows/check.yml +0 -19
- package/node_modules/@ykdz/template-builtin-source/templates/hono-api/src/app.ts +0 -5
- package/node_modules/@ykdz/template-builtin-source/templates/hono-api/src/server.ts +0 -15
- package/node_modules/@ykdz/template-builtin-source/templates/hono-api/test/app.test.ts +0 -10
- package/node_modules/@ykdz/template-builtin-source/templates/hono-api/vitest.config.ts +0 -15
- package/node_modules/@ykdz/template-builtin-source/templates/vike-app/playwright.config.ts +0 -23
- package/node_modules/@ykdz/template-builtin-source/templates/vue-app/playwright.package-addition.config.ts +0 -22
- /package/node_modules/@ykdz/template-builtin-source/templates/vike-app/{database → db/src}/schema.ts +0 -0
- /package/node_modules/@ykdz/template-builtin-source/templates/vike-app/{+server.ts → web/+server.ts} +0 -0
- /package/node_modules/@ykdz/template-builtin-source/templates/vike-app/{.env.example → web/.env.example} +0 -0
- /package/node_modules/@ykdz/template-builtin-source/templates/vike-app/{assets → web/assets}/logo.svg +0 -0
- /package/node_modules/@ykdz/template-builtin-source/templates/vike-app/{components → web/components}/CounterButton.vue +0 -0
- /package/node_modules/@ykdz/template-builtin-source/templates/vike-app/{components → web/components}/PageShell.vue +0 -0
- /package/node_modules/@ykdz/template-builtin-source/templates/vike-app/{pages → web/pages}/+Head.vue +0 -0
- /package/node_modules/@ykdz/template-builtin-source/templates/vike-app/{pages → web/pages}/+Layout.vue +0 -0
- /package/node_modules/@ykdz/template-builtin-source/templates/vike-app/{pages → web/pages}/+config.ts +0 -0
- /package/node_modules/@ykdz/template-builtin-source/templates/vike-app/{pages → web/pages}/tailwind.css +0 -0
- /package/node_modules/@ykdz/template-builtin-source/templates/vike-app/{server → web/server}/api.ts +0 -0
- /package/node_modules/@ykdz/template-builtin-source/templates/vike-app/{types → web/types}/env.d.ts +0 -0
- /package/node_modules/@ykdz/template-builtin-source/templates/vike-app/{vitest.config.ts → web/vitest.config.ts} +0 -0
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import { readdir, readFile } from "node:fs/promises";
|
|
2
2
|
import path from "node:path";
|
|
3
|
+
import { PackageAdditionSupport } from "@ykdz/template-shared";
|
|
3
4
|
import { execa } from "execa";
|
|
4
5
|
import * as v from "valibot";
|
|
5
6
|
import { assembleGenerationContext } from "./generation-context.js";
|
|
6
7
|
import { playwrightBrowserAssetsEnvironmentNeed, } from "./module-graph.js";
|
|
7
8
|
import { planNextStepInstructions } from "./next-step-instructions.js";
|
|
9
|
+
import { canPlanPackageLinkIntent, } from "./package-linking.js";
|
|
8
10
|
import { findPresetSourceManifestPreset } from "./preset-source.js";
|
|
9
11
|
import { blueprintForPresetSourcePreset, projectPresetSourcePreset, } from "./projection-capabilities.js";
|
|
10
12
|
const defaultDeterministicToolchainEnv = {
|
|
@@ -83,40 +85,105 @@ function createGeneratedScenario(set, input) {
|
|
|
83
85
|
};
|
|
84
86
|
}
|
|
85
87
|
export function selectGeneratedScenarios(manifest, set) {
|
|
86
|
-
const
|
|
87
|
-
|
|
88
|
-
throw new Error(`Preset Source ${manifest.name} does not declare a Fixture Matrix Contract`);
|
|
89
|
-
}
|
|
90
|
-
const initScenarios = contract.initSupport.map((support) => createGeneratedScenario(set, { basePreset: support.preset }));
|
|
88
|
+
const supportedInitPresets = manifest.presets.filter((preset) => preset.generation === "supported");
|
|
89
|
+
const initScenarios = supportedInitPresets.map((preset) => createGeneratedScenario("init", { basePreset: preset.name }));
|
|
91
90
|
if (set === "init") {
|
|
92
91
|
return { runnable: initScenarios, skipped: [] };
|
|
93
92
|
}
|
|
94
|
-
const
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
:
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
basePreset:
|
|
104
|
-
addedPreset:
|
|
105
|
-
|
|
106
|
-
label: generatedScenarioLabel(skip),
|
|
107
|
-
reason: skip.reason,
|
|
108
|
-
}));
|
|
93
|
+
const addablePresets = manifest.presets.filter((preset) => preset.packageAdditionSupport === PackageAdditionSupport.Supported);
|
|
94
|
+
const focusedScenarios = selectFocusedGeneratedScenarios(manifest, addablePresets);
|
|
95
|
+
if (set === "focused") {
|
|
96
|
+
return {
|
|
97
|
+
runnable: focusedScenarios,
|
|
98
|
+
skipped: [],
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
const matrixScenarios = supportedInitPresets.flatMap((basePreset) => addablePresets.map((addedPreset) => createGeneratedScenario("package-addition-matrix", {
|
|
102
|
+
basePreset: basePreset.name,
|
|
103
|
+
addedPreset: addedPreset.name,
|
|
104
|
+
})));
|
|
109
105
|
return {
|
|
110
|
-
runnable: matrixScenarios,
|
|
111
|
-
skipped,
|
|
106
|
+
runnable: [...matrixScenarios, ...focusedScenarios],
|
|
107
|
+
skipped: [],
|
|
112
108
|
};
|
|
113
109
|
}
|
|
110
|
+
function selectFocusedGeneratedScenarios(manifest, addablePresets) {
|
|
111
|
+
return manifest.presets
|
|
112
|
+
.filter((preset) => preset.generation === "supported")
|
|
113
|
+
.flatMap((basePreset) => addablePresets.flatMap((addedPreset) => {
|
|
114
|
+
const consumerPackagePath = focusedPackageLinkConsumerPath(basePreset, addedPreset);
|
|
115
|
+
return consumerPackagePath === undefined
|
|
116
|
+
? []
|
|
117
|
+
: [
|
|
118
|
+
createGeneratedScenario("focused", {
|
|
119
|
+
basePreset: basePreset.name,
|
|
120
|
+
addedPreset: addedPreset.name,
|
|
121
|
+
linkFrom: [consumerPackagePath],
|
|
122
|
+
}),
|
|
123
|
+
];
|
|
124
|
+
}));
|
|
125
|
+
}
|
|
126
|
+
function focusedPackageLinkConsumerPath(basePreset, addedPreset) {
|
|
127
|
+
const providers = packageLinkProviderDefinitions(addedPreset);
|
|
128
|
+
return packageLinkConsumerDefinitions(basePreset).find((consumer) => providers.some((provider) => canPlanPackageLinkIntent({ consumer, provider })))?.path;
|
|
129
|
+
}
|
|
130
|
+
function packageLinkProviderDefinitions(preset) {
|
|
131
|
+
return (preset.projection?.capabilities.flatMap((capability) => {
|
|
132
|
+
if (capability.kind !== "workspace-library-package") {
|
|
133
|
+
return [];
|
|
134
|
+
}
|
|
135
|
+
const packageLeafName = `fixture-${preset.name}`;
|
|
136
|
+
return [
|
|
137
|
+
{
|
|
138
|
+
name: `@fixture/${packageLeafName}`,
|
|
139
|
+
path: `${packageCollection(capability.workspacePackageGlob)}/${packageLeafName}`,
|
|
140
|
+
role: capability.packageRole,
|
|
141
|
+
sourcePreset: capability.packageSourcePreset,
|
|
142
|
+
},
|
|
143
|
+
];
|
|
144
|
+
}) ?? []);
|
|
145
|
+
}
|
|
146
|
+
function packageLinkConsumerDefinitions(preset) {
|
|
147
|
+
return (preset.projection?.capabilities.flatMap((capability) => {
|
|
148
|
+
if (capability.kind !== "workspace-node-packages") {
|
|
149
|
+
return [];
|
|
150
|
+
}
|
|
151
|
+
return capability.packages
|
|
152
|
+
.filter((nodePackage) => nodePackage.sourceFiles.some((sourceFile) => hasSourceDirectoryPath(sourceFile)))
|
|
153
|
+
.map((nodePackage) => ({
|
|
154
|
+
name: `@fixture/${packageLeaf(nodePackage.path)}`,
|
|
155
|
+
path: nodePackage.path,
|
|
156
|
+
role: "runtime-service",
|
|
157
|
+
sourcePreset: nodePackage.kind,
|
|
158
|
+
}));
|
|
159
|
+
}) ?? []);
|
|
160
|
+
}
|
|
161
|
+
function packageCollection(workspacePackageGlob) {
|
|
162
|
+
const [collection, wildcard] = workspacePackageGlob.split("/");
|
|
163
|
+
if (!collection || wildcard !== "*") {
|
|
164
|
+
throw new Error(`Unsupported workspace package glob: ${workspacePackageGlob}`);
|
|
165
|
+
}
|
|
166
|
+
return collection;
|
|
167
|
+
}
|
|
168
|
+
function packageLeaf(packagePath) {
|
|
169
|
+
return packagePath.split("/").at(-1) ?? packagePath;
|
|
170
|
+
}
|
|
171
|
+
function hasSourceDirectoryPath(sourceFile) {
|
|
172
|
+
return sourceFile.startsWith("src/") || sourceFile.includes("/src/");
|
|
173
|
+
}
|
|
114
174
|
export function packageLeafNameForAddedPreset(manifest, presetName) {
|
|
115
|
-
const
|
|
116
|
-
if (!
|
|
117
|
-
throw new Error(`
|
|
175
|
+
const preset = manifest.presets.find((entry) => entry.name === presetName);
|
|
176
|
+
if (!preset) {
|
|
177
|
+
throw new Error(`Unknown fixture Package Addition preset: ${presetName}`);
|
|
178
|
+
}
|
|
179
|
+
if (preset.packageAdditionSupport !== PackageAdditionSupport.Supported) {
|
|
180
|
+
throw new Error(`Preset ${presetName} cannot be used for fixture Package Addition`);
|
|
118
181
|
}
|
|
119
|
-
|
|
182
|
+
const packageLeafName = `fixture-${presetName}`;
|
|
183
|
+
if (!/^[a-z0-9][a-z0-9-]*$/.test(packageLeafName)) {
|
|
184
|
+
throw new Error(`Fixture Package Addition leaf name for preset ${presetName} must be a lowercase package leaf name using letters, numbers, and hyphens`);
|
|
185
|
+
}
|
|
186
|
+
return packageLeafName;
|
|
120
187
|
}
|
|
121
188
|
export async function defaultGeneratedScenarioCommandRunner(command, args, cwd, options = {}) {
|
|
122
189
|
const prefix = options.logPrefix ? `[${options.logPrefix}] ` : "";
|
|
@@ -317,6 +384,10 @@ async function runGeneratedScenarioQualityGate(manifest, scenario, projectDir, a
|
|
|
317
384
|
const steps = generatedScenarioQualityGateSteps(manifest, scenario, projectDir, addedPackagePath, options);
|
|
318
385
|
const requiresSerializedPlaywrightRootCheck = generatedScenarioRequiresSerializedRootCheck(steps);
|
|
319
386
|
for (const step of steps) {
|
|
387
|
+
if (step.id === "install-dependencies") {
|
|
388
|
+
await runGeneratedScenarioInstallStep(step, scenario, options);
|
|
389
|
+
continue;
|
|
390
|
+
}
|
|
320
391
|
const env = step.id === "run-root-check" ? { CI: "1" } : undefined;
|
|
321
392
|
const runStep = async () => {
|
|
322
393
|
await options.runCommand(step.command, [...step.args], step.cwd, {
|
|
@@ -331,6 +402,13 @@ async function runGeneratedScenarioQualityGate(manifest, scenario, projectDir, a
|
|
|
331
402
|
await runStep();
|
|
332
403
|
}
|
|
333
404
|
}
|
|
405
|
+
async function runGeneratedScenarioInstallStep(step, scenario, options) {
|
|
406
|
+
await options.runCommand(step.command, ["install", "--lockfile-only", "--prefer-offline", "--no-frozen-lockfile"], step.cwd, { logPrefix: scenario.label });
|
|
407
|
+
await options.runCommand(step.command, ["fetch"], step.cwd, {
|
|
408
|
+
logPrefix: scenario.label,
|
|
409
|
+
});
|
|
410
|
+
await options.runCommand(step.command, ["install", "--offline", "--frozen-lockfile"], step.cwd, { logPrefix: scenario.label });
|
|
411
|
+
}
|
|
334
412
|
async function checkGeneratedScenario(manifest, scenario, workspace, options) {
|
|
335
413
|
options.reporter.info?.(`\n== ${scenario.label} ==`);
|
|
336
414
|
const projectDir = await generateScenario(scenario, workspace, options);
|
|
@@ -37,6 +37,7 @@ export type CheckPlan = {
|
|
|
37
37
|
export type FixPlan = {
|
|
38
38
|
readonly components: FixComponent[];
|
|
39
39
|
};
|
|
40
|
+
export declare function renderTurboRunCommand(taskNames: readonly string[], args?: readonly string[]): string;
|
|
40
41
|
export declare function checkComponentTaskName(component: CheckComponent): string;
|
|
41
42
|
export declare function fixComponentTaskName(component: FixComponent): string;
|
|
42
43
|
export declare function renderCheckLeafCommand(component: CheckComponent): string;
|
|
@@ -4,6 +4,13 @@ function renderTurboPackageFilter(owner) {
|
|
|
4
4
|
}
|
|
5
5
|
return `--filter './${owner.path}'`;
|
|
6
6
|
}
|
|
7
|
+
const turboAgentOutputArgs = [
|
|
8
|
+
"--output-logs=errors-only",
|
|
9
|
+
"--log-order=grouped",
|
|
10
|
+
];
|
|
11
|
+
export function renderTurboRunCommand(taskNames, args = []) {
|
|
12
|
+
return ["turbo run", ...taskNames, ...args, ...turboAgentOutputArgs].join(" ");
|
|
13
|
+
}
|
|
7
14
|
export function checkComponentTaskName(component) {
|
|
8
15
|
return checkComponentTaskNames(component)[0] ?? "check:run";
|
|
9
16
|
}
|
|
@@ -73,17 +80,17 @@ export function renderCheckLeafCommand(component) {
|
|
|
73
80
|
case "e2e-test":
|
|
74
81
|
return "pnpm run test:e2e";
|
|
75
82
|
case "turbo-check":
|
|
76
|
-
return "
|
|
83
|
+
return renderTurboRunCommand(["check"]);
|
|
77
84
|
case "turbo-package-typecheck":
|
|
78
|
-
return
|
|
85
|
+
return renderTurboRunCommand(["typecheck"], [renderTurboPackageFilter(component.owner)]);
|
|
79
86
|
case "turbo-package-build":
|
|
80
|
-
return
|
|
87
|
+
return renderTurboRunCommand(["build"], [renderTurboPackageFilter(component.owner)]);
|
|
81
88
|
case "turbo-package-test":
|
|
82
|
-
return
|
|
89
|
+
return renderTurboRunCommand(["test"], [renderTurboPackageFilter(component.owner)]);
|
|
83
90
|
case "turbo-package-e2e-test":
|
|
84
|
-
return
|
|
91
|
+
return renderTurboRunCommand(["test:e2e"], [renderTurboPackageFilter(component.owner)]);
|
|
85
92
|
case "turbo-package-check":
|
|
86
|
-
return
|
|
93
|
+
return renderTurboRunCommand(["check"], [renderTurboPackageFilter(component.owner)]);
|
|
87
94
|
case "rustfmt-check":
|
|
88
95
|
return "cargo fmt --all -- --check";
|
|
89
96
|
case "cargo-clippy":
|
|
@@ -99,24 +106,24 @@ export function renderFixLeafCommand(component) {
|
|
|
99
106
|
case "oxc-lint-fix":
|
|
100
107
|
return "pnpm run lint:fix";
|
|
101
108
|
case "turbo-fix":
|
|
102
|
-
return "
|
|
109
|
+
return renderTurboRunCommand(["fix"]);
|
|
103
110
|
case "turbo-package-fix":
|
|
104
|
-
return
|
|
111
|
+
return renderTurboRunCommand(["fix"], [renderTurboPackageFilter(component.owner)]);
|
|
105
112
|
case "rustfmt-write":
|
|
106
113
|
return "cargo fmt --all";
|
|
107
114
|
}
|
|
108
115
|
}
|
|
109
116
|
export function renderRootCheckCommand(plan) {
|
|
110
|
-
return
|
|
117
|
+
return renderTurboRunCommand(uniqueTaskNames([
|
|
111
118
|
...plan.components.flatMap(checkComponentTaskNames),
|
|
112
119
|
"check:run",
|
|
113
|
-
])
|
|
120
|
+
]));
|
|
114
121
|
}
|
|
115
122
|
export function renderFixCommand(plan) {
|
|
116
|
-
return
|
|
123
|
+
return renderTurboRunCommand(uniqueTaskNames([
|
|
117
124
|
...plan.components.flatMap(fixComponentTaskNames),
|
|
118
125
|
"fix:run",
|
|
119
|
-
])
|
|
126
|
+
]));
|
|
120
127
|
}
|
|
121
128
|
function playwrightBrowserInstallArgs(need, options = {}) {
|
|
122
129
|
const installArgs = [
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { CheckEnvironmentNeed } from "./module-graph.js";
|
|
2
2
|
import type { PresetProjectionPlan } from "./preset-projection.js";
|
|
3
|
+
import type { RenderOperation } from "./renderer.js";
|
|
3
4
|
export type NextStepInstruction = {
|
|
4
5
|
readonly id: string;
|
|
5
6
|
readonly label: string;
|
|
@@ -19,4 +20,11 @@ export type PlanNextStepInstructionsOptions = {
|
|
|
19
20
|
readonly targetDir: string;
|
|
20
21
|
readonly projectionPlan: PresetProjectionPlan;
|
|
21
22
|
};
|
|
23
|
+
export type FollowUpDocumentPlan = {
|
|
24
|
+
readonly enabled: boolean;
|
|
25
|
+
readonly path?: "TODO.md";
|
|
26
|
+
};
|
|
22
27
|
export declare function planNextStepInstructions(options: PlanNextStepInstructionsOptions): NextStepInstructionPlan;
|
|
28
|
+
export declare function formatNextStepInstructionsForCli(plan: NextStepInstructionPlan): string;
|
|
29
|
+
export declare function formatGeneratedFollowUpDocument(plan: NextStepInstructionPlan): string;
|
|
30
|
+
export declare function generatedFollowUpDocumentOperation(plan: NextStepInstructionPlan): RenderOperation;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import path from "node:path";
|
|
1
2
|
function rootCheckInstruction() {
|
|
2
3
|
return {
|
|
3
4
|
id: "run-root-check",
|
|
@@ -114,3 +115,67 @@ export function planNextStepInstructions(options) {
|
|
|
114
115
|
steps: Object.freeze([navigationStep, ...commandSteps].map((step) => Object.freeze(step))),
|
|
115
116
|
});
|
|
116
117
|
}
|
|
118
|
+
export function formatNextStepInstructionsForCli(plan) {
|
|
119
|
+
return [
|
|
120
|
+
"Next Step Instructions:",
|
|
121
|
+
"",
|
|
122
|
+
...plan.steps.flatMap((step, index) => [
|
|
123
|
+
` ${index + 1}. ${step.label}`,
|
|
124
|
+
` ${step.display}`,
|
|
125
|
+
]),
|
|
126
|
+
].join("\n");
|
|
127
|
+
}
|
|
128
|
+
function isOptionalGitInstruction(step) {
|
|
129
|
+
return step.id.startsWith("optional-git-");
|
|
130
|
+
}
|
|
131
|
+
function relativeCwd(plan, step) {
|
|
132
|
+
const targetDir = path.resolve(plan.targetDir);
|
|
133
|
+
const cwd = path.resolve(step.cwd);
|
|
134
|
+
if (cwd === targetDir) {
|
|
135
|
+
return undefined;
|
|
136
|
+
}
|
|
137
|
+
const relative = path.relative(targetDir, cwd);
|
|
138
|
+
if (!relative || relative.startsWith("..") || path.isAbsolute(relative)) {
|
|
139
|
+
return cwd;
|
|
140
|
+
}
|
|
141
|
+
return relative;
|
|
142
|
+
}
|
|
143
|
+
function taskTitle(step) {
|
|
144
|
+
const title = step.label.replace(/^Optional:\s*/, "");
|
|
145
|
+
return `${title.slice(0, 1).toUpperCase()}${title.slice(1)}`;
|
|
146
|
+
}
|
|
147
|
+
function formatTodoTask(plan, step) {
|
|
148
|
+
const taskLines = [`- [ ] ${taskTitle(step)}`];
|
|
149
|
+
const cwd = relativeCwd(plan, step);
|
|
150
|
+
if (cwd !== undefined) {
|
|
151
|
+
taskLines.push(` From \`${cwd}\`:`);
|
|
152
|
+
}
|
|
153
|
+
taskLines.push(` \`${step.display}\``);
|
|
154
|
+
return taskLines;
|
|
155
|
+
}
|
|
156
|
+
export function formatGeneratedFollowUpDocument(plan) {
|
|
157
|
+
const projectLocalSteps = plan.steps.filter((step) => step.kind === "command");
|
|
158
|
+
const nextSteps = projectLocalSteps.filter((step) => !isOptionalGitInstruction(step));
|
|
159
|
+
const optionalGitSteps = projectLocalSteps.filter(isOptionalGitInstruction);
|
|
160
|
+
return [
|
|
161
|
+
"# TODO",
|
|
162
|
+
"",
|
|
163
|
+
"Generated follow-up tasks for this repository.",
|
|
164
|
+
"",
|
|
165
|
+
"### Next Steps",
|
|
166
|
+
...nextSteps.flatMap((step) => formatTodoTask(plan, step)),
|
|
167
|
+
"",
|
|
168
|
+
"### Optional Git Setup",
|
|
169
|
+
...optionalGitSteps.flatMap((step) => formatTodoTask(plan, step)),
|
|
170
|
+
"",
|
|
171
|
+
"### Done ✓",
|
|
172
|
+
"",
|
|
173
|
+
].join("\n");
|
|
174
|
+
}
|
|
175
|
+
export function generatedFollowUpDocumentOperation(plan) {
|
|
176
|
+
return {
|
|
177
|
+
kind: "writeText",
|
|
178
|
+
to: "TODO.md",
|
|
179
|
+
text: formatGeneratedFollowUpDocument(plan),
|
|
180
|
+
};
|
|
181
|
+
}
|
|
@@ -3,7 +3,8 @@ import path from "node:path";
|
|
|
3
3
|
import { validateProjectBlueprint, } from "@ykdz/template-shared";
|
|
4
4
|
import { PackageAdditionSupport, } from "@ykdz/template-shared";
|
|
5
5
|
import { collectGeneratedManifestCatalogReferences, pnpmWorkspaceYamlWithCatalogDependencies, } from "./dependency-catalog.js";
|
|
6
|
-
import {
|
|
6
|
+
import { renderTurboRunCommand } from "./module-graph.js";
|
|
7
|
+
import { assertTypeScriptPackageBoundaryForLinkIntent, packageTurboConfig, planPackageLinks, } from "./package-linking.js";
|
|
7
8
|
import { findPresetSourceManifestPreset, } from "./preset-source.js";
|
|
8
9
|
import { defaultPackagePathForPresetSourcePackageAddition, planPresetSourcePackageAddition, } from "./projection-capabilities.js";
|
|
9
10
|
import { renderProject } from "./renderer.js";
|
|
@@ -385,11 +386,7 @@ function rootScriptWithTurboPackageTasks(options) {
|
|
|
385
386
|
const rootCommands = options.script
|
|
386
387
|
.split(" && ")
|
|
387
388
|
.filter((command) => !command.startsWith("turbo run "));
|
|
388
|
-
const turboCommand =
|
|
389
|
-
"turbo run",
|
|
390
|
-
...options.taskNames,
|
|
391
|
-
...(options.concurrency === undefined ? [] : ["--concurrency=1"]),
|
|
392
|
-
].join(" ");
|
|
389
|
+
const turboCommand = renderTurboRunCommand(options.taskNames);
|
|
393
390
|
return [...rootCommands, turboCommand].join(" && ");
|
|
394
391
|
}
|
|
395
392
|
function rootPackageJsonWithPackageTaskFilters(input, blueprint) {
|
|
@@ -415,7 +412,6 @@ function rootPackageJsonWithPackageTaskFilters(input, blueprint) {
|
|
|
415
412
|
"test:e2e:run",
|
|
416
413
|
"check:run",
|
|
417
414
|
],
|
|
418
|
-
concurrency: 1,
|
|
419
415
|
}),
|
|
420
416
|
fix: rootScriptWithTurboPackageTasks({
|
|
421
417
|
script: fixScript,
|
|
@@ -446,11 +442,9 @@ function packageManifestsNeedDependencyBuilds(manifests) {
|
|
|
446
442
|
return manifests.some((manifest) => Object.entries(manifest.dependencies ?? {}).some(([dependencyName, specifier]) => specifier === "workspace:*" && compiledPackageNames.has(dependencyName)));
|
|
447
443
|
}
|
|
448
444
|
function turboConfigForPackageManifests(manifests) {
|
|
449
|
-
return {
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
}),
|
|
453
|
-
};
|
|
445
|
+
return packageTurboConfig({
|
|
446
|
+
dependencyBuildsRequired: packageManifestsNeedDependencyBuilds(manifests),
|
|
447
|
+
});
|
|
454
448
|
}
|
|
455
449
|
function rootPackageJsonWithSharedOxcRuntimeDependencies(input, requiresSharedOxcConfiguration) {
|
|
456
450
|
if (!requiresSharedOxcConfiguration) {
|
|
@@ -32,12 +32,33 @@ export type PackageManifestExposureFields = {
|
|
|
32
32
|
readonly types?: string;
|
|
33
33
|
};
|
|
34
34
|
export type PackageLinkBoundaryDirection = "consumer" | "provider";
|
|
35
|
+
export type PackageLinkIntentCompatibility = {
|
|
36
|
+
readonly consumer: PackageDefinition;
|
|
37
|
+
readonly provider: PackageDefinition;
|
|
38
|
+
};
|
|
35
39
|
export type TurboTaskDefinition = {
|
|
36
40
|
readonly dependsOn?: readonly string[];
|
|
37
41
|
readonly outputs?: readonly string[];
|
|
38
42
|
readonly cache?: boolean;
|
|
39
43
|
};
|
|
40
44
|
export type TurboTaskGraph = Readonly<Record<string, TurboTaskDefinition>>;
|
|
45
|
+
export type TurboBoundaryRule = {
|
|
46
|
+
readonly dependencies?: {
|
|
47
|
+
readonly allow?: readonly string[];
|
|
48
|
+
readonly deny?: readonly string[];
|
|
49
|
+
};
|
|
50
|
+
readonly dependents?: {
|
|
51
|
+
readonly allow?: readonly string[];
|
|
52
|
+
readonly deny?: readonly string[];
|
|
53
|
+
};
|
|
54
|
+
};
|
|
55
|
+
export type TurboBoundaries = {
|
|
56
|
+
readonly tags: Readonly<Record<string, TurboBoundaryRule>>;
|
|
57
|
+
};
|
|
58
|
+
export type TurboConfig = {
|
|
59
|
+
readonly tasks: TurboTaskGraph;
|
|
60
|
+
readonly boundaries: TurboBoundaries;
|
|
61
|
+
};
|
|
41
62
|
export type PackageTurboTaskOptions = {
|
|
42
63
|
readonly dependencyBuildsRequired: boolean;
|
|
43
64
|
};
|
|
@@ -46,6 +67,9 @@ export declare function assertTypeScriptPackageBoundaryForLinkIntent(definition:
|
|
|
46
67
|
readonly role: PackageRole;
|
|
47
68
|
readonly sourcePreset: PackageSourcePreset;
|
|
48
69
|
};
|
|
70
|
+
export declare function canPlanPackageLinkIntent({ consumer, provider, }: PackageLinkIntentCompatibility): boolean;
|
|
49
71
|
export declare function planPackageLinks(definitions: readonly PackageDefinition[], intents?: readonly PackageLinkIntent[]): PackageLinkPlan;
|
|
50
72
|
export declare function packageTurboTasks({ dependencyBuildsRequired, }: PackageTurboTaskOptions): TurboTaskGraph;
|
|
73
|
+
export declare function generatedRepositoryTurboBoundaries(): TurboBoundaries;
|
|
74
|
+
export declare function packageTurboConfig(options: PackageTurboTaskOptions): TurboConfig;
|
|
51
75
|
export declare function packageManifestExposureFields(exposure: PackageExposure): PackageManifestExposureFields;
|
|
@@ -28,6 +28,17 @@ export function assertTypeScriptPackageBoundaryForLinkIntent(definition, directi
|
|
|
28
28
|
const relationship = direction === "consumer" ? "from native package" : "to native package";
|
|
29
29
|
throw new Error(`Package Link Intent ${relationship} ${definition.path} is unsupported in V1 TypeScript-only Project Linking`);
|
|
30
30
|
}
|
|
31
|
+
export function canPlanPackageLinkIntent({ consumer, provider, }) {
|
|
32
|
+
try {
|
|
33
|
+
assertTypeScriptPackageBoundaryForLinkIntent(consumer, "consumer");
|
|
34
|
+
assertTypeScriptPackageBoundaryForLinkIntent(provider, "provider");
|
|
35
|
+
derivePackageExposure(provider);
|
|
36
|
+
return true;
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
return false;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
31
42
|
export function planPackageLinks(definitions, intents = []) {
|
|
32
43
|
const definitionsByPath = new Map(definitions.map((definition) => [definition.path, definition]));
|
|
33
44
|
const manifestDependenciesByPackagePath = new Map();
|
|
@@ -85,6 +96,30 @@ export function packageTurboTasks({ dependencyBuildsRequired, }) {
|
|
|
85
96
|
"fix:run": { cache: false },
|
|
86
97
|
};
|
|
87
98
|
}
|
|
99
|
+
// Boundary violations are architecture problems. Do not loosen these rules to
|
|
100
|
+
// make a failing dependency graph pass; fix the dependency direction instead.
|
|
101
|
+
export function generatedRepositoryTurboBoundaries() {
|
|
102
|
+
return {
|
|
103
|
+
tags: {
|
|
104
|
+
app: {
|
|
105
|
+
dependencies: {
|
|
106
|
+
deny: ["app"],
|
|
107
|
+
},
|
|
108
|
+
},
|
|
109
|
+
library: {
|
|
110
|
+
dependencies: {
|
|
111
|
+
deny: ["app"],
|
|
112
|
+
},
|
|
113
|
+
},
|
|
114
|
+
},
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
export function packageTurboConfig(options) {
|
|
118
|
+
return {
|
|
119
|
+
tasks: packageTurboTasks(options),
|
|
120
|
+
boundaries: generatedRepositoryTurboBoundaries(),
|
|
121
|
+
};
|
|
122
|
+
}
|
|
88
123
|
export function packageManifestExposureFields(exposure) {
|
|
89
124
|
switch (exposure.kind) {
|
|
90
125
|
case "jit-source":
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import type { BuiltInPreset,
|
|
1
|
+
import type { BuiltInPreset, PresetSourceManifest, PresetSourceManifestPreset, PresetSourceManifestPresetSource, PresetSourceManifestSharedResource, ValidationResult } from "@ykdz/template-shared";
|
|
2
2
|
import { presetSourceManifestJsonSchema } from "@ykdz/template-shared";
|
|
3
3
|
import { type TemplateDependencyCatalog } from "./dependency-catalog.js";
|
|
4
4
|
export { presetSourceManifestJsonSchema };
|
|
5
|
-
export type { BuiltInPreset,
|
|
5
|
+
export type { BuiltInPreset, PresetSourceManifest, PresetSourceManifestPreset, PresetSourceManifestPresetSource, PresetSourceManifestSharedResource, };
|
|
6
6
|
export type PresetSourceManifestValidationOptions = {
|
|
7
7
|
readonly sourceRoot?: string;
|
|
8
8
|
readonly dependencyCatalog?: TemplateDependencyCatalog;
|