@ykdz/template 0.0.18 → 0.0.20
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/vike-app/projection.js +13 -2
- package/node_modules/@ykdz/template-builtin-source/dist/templates/vue-app/projection.js +5 -73
- package/node_modules/@ykdz/template-builtin-source/dist/templates/vue-hono-app/projection.js +3 -2
- package/node_modules/@ykdz/template-builtin-source/package.json +36 -3
- 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/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 +5 -9
- 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 +225 -139
- package/node_modules/@ykdz/template-core/dist/template-boundary-check.js +46 -10
- package/node_modules/@ykdz/template-core/package.json +5 -1
- 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 +4 -0
- package/package.json +2 -2
- 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);
|
|
@@ -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
|
+
}
|
|
@@ -4,7 +4,7 @@ import { validateProjectBlueprint, } from "@ykdz/template-shared";
|
|
|
4
4
|
import { PackageAdditionSupport, } from "@ykdz/template-shared";
|
|
5
5
|
import { collectGeneratedManifestCatalogReferences, pnpmWorkspaceYamlWithCatalogDependencies, } from "./dependency-catalog.js";
|
|
6
6
|
import { renderTurboRunCommand } from "./module-graph.js";
|
|
7
|
-
import { assertTypeScriptPackageBoundaryForLinkIntent,
|
|
7
|
+
import { assertTypeScriptPackageBoundaryForLinkIntent, packageTurboConfig, planPackageLinks, } from "./package-linking.js";
|
|
8
8
|
import { findPresetSourceManifestPreset, } from "./preset-source.js";
|
|
9
9
|
import { defaultPackagePathForPresetSourcePackageAddition, planPresetSourcePackageAddition, } from "./projection-capabilities.js";
|
|
10
10
|
import { renderProject } from "./renderer.js";
|
|
@@ -386,8 +386,7 @@ function rootScriptWithTurboPackageTasks(options) {
|
|
|
386
386
|
const rootCommands = options.script
|
|
387
387
|
.split(" && ")
|
|
388
388
|
.filter((command) => !command.startsWith("turbo run "));
|
|
389
|
-
const
|
|
390
|
-
const turboCommand = renderTurboRunCommand(options.taskNames, turboArgs);
|
|
389
|
+
const turboCommand = renderTurboRunCommand(options.taskNames);
|
|
391
390
|
return [...rootCommands, turboCommand].join(" && ");
|
|
392
391
|
}
|
|
393
392
|
function rootPackageJsonWithPackageTaskFilters(input, blueprint) {
|
|
@@ -413,7 +412,6 @@ function rootPackageJsonWithPackageTaskFilters(input, blueprint) {
|
|
|
413
412
|
"test:e2e:run",
|
|
414
413
|
"check:run",
|
|
415
414
|
],
|
|
416
|
-
concurrency: 1,
|
|
417
415
|
}),
|
|
418
416
|
fix: rootScriptWithTurboPackageTasks({
|
|
419
417
|
script: fixScript,
|
|
@@ -444,11 +442,9 @@ function packageManifestsNeedDependencyBuilds(manifests) {
|
|
|
444
442
|
return manifests.some((manifest) => Object.entries(manifest.dependencies ?? {}).some(([dependencyName, specifier]) => specifier === "workspace:*" && compiledPackageNames.has(dependencyName)));
|
|
445
443
|
}
|
|
446
444
|
function turboConfigForPackageManifests(manifests) {
|
|
447
|
-
return {
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
}),
|
|
451
|
-
};
|
|
445
|
+
return packageTurboConfig({
|
|
446
|
+
dependencyBuildsRequired: packageManifestsNeedDependencyBuilds(manifests),
|
|
447
|
+
});
|
|
452
448
|
}
|
|
453
449
|
function rootPackageJsonWithSharedOxcRuntimeDependencies(input, requiresSharedOxcConfiguration) {
|
|
454
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;
|