@ykdz/template 0.0.19 → 0.0.21
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/node_modules/@ykdz/template-builtin-source/dist/templates/vue-app/projection.js +4 -4
- package/node_modules/@ykdz/template-builtin-source/templates/rust-bin/.github/dependabot.yml +5 -0
- package/node_modules/@ykdz/template-builtin-source/templates/ts-lib/.github/dependabot.yml +5 -0
- package/node_modules/@ykdz/template-builtin-source/templates/vike-app/.github/dependabot.yml +5 -0
- package/node_modules/@ykdz/template-builtin-source/templates/vike-app/db/src/db.ts +4 -1
- package/node_modules/@ykdz/template-builtin-source/templates/vike-app/db/test/todos.test.ts +3 -0
- package/node_modules/@ykdz/template-builtin-source/templates/vue-app/.github/dependabot.yml +5 -0
- package/node_modules/@ykdz/template-builtin-source/templates/vue-hono-app/.github/dependabot.yml +5 -0
- package/node_modules/@ykdz/template-core/dist/generated-scenarios.d.ts +6 -0
- package/node_modules/@ykdz/template-core/dist/generated-scenarios.js +86 -2
- package/node_modules/@ykdz/template-core/dist/pnpm-workspace.yaml +5 -5
- package/node_modules/@ykdz/template-core/dist/project-github.js +1 -1
- package/node_modules/@ykdz/template-core/dist/projection-capabilities.js +10 -10
- package/package.json +3 -3
|
@@ -123,8 +123,8 @@ function packageAdditionOperations(packagePath, packageNameValue, nodeVersion) {
|
|
|
123
123
|
exactOptionalPropertyTypes: true,
|
|
124
124
|
forceConsistentCasingInFileNames: true,
|
|
125
125
|
isolatedModules: true,
|
|
126
|
-
module: "
|
|
127
|
-
moduleResolution: "
|
|
126
|
+
module: "esnext",
|
|
127
|
+
moduleResolution: "bundler",
|
|
128
128
|
noEmitOnError: true,
|
|
129
129
|
noFallthroughCasesInSwitch: true,
|
|
130
130
|
noImplicitOverride: true,
|
|
@@ -164,8 +164,8 @@ function packageAdditionOperations(packagePath, packageNameValue, nodeVersion) {
|
|
|
164
164
|
exactOptionalPropertyTypes: true,
|
|
165
165
|
forceConsistentCasingInFileNames: true,
|
|
166
166
|
isolatedModules: true,
|
|
167
|
-
module: "
|
|
168
|
-
moduleResolution: "
|
|
167
|
+
module: "esnext",
|
|
168
|
+
moduleResolution: "bundler",
|
|
169
169
|
noEmitOnError: true,
|
|
170
170
|
lib: ["ESNext", "DOM", "DOM.Iterable"],
|
|
171
171
|
noFallthroughCasesInSwitch: true,
|
|
@@ -2,13 +2,16 @@ import { mkdirSync } from "node:fs";
|
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
|
|
4
4
|
import { drizzle } from "drizzle-orm/node-sqlite";
|
|
5
|
+
import { defineRelations } from "drizzle-orm/relations";
|
|
5
6
|
|
|
6
7
|
import * as schema from "#db/schema";
|
|
7
8
|
|
|
9
|
+
const relations = defineRelations(schema);
|
|
10
|
+
|
|
8
11
|
export type Database = ReturnType<typeof createDatabase>;
|
|
9
12
|
|
|
10
13
|
export function createDatabase(databaseFile = process.env.DATABASE_FILE) {
|
|
11
14
|
const file = databaseFile ?? "./data/app.sqlite";
|
|
12
15
|
mkdirSync(path.dirname(file), { recursive: true });
|
|
13
|
-
return drizzle(file, {
|
|
16
|
+
return drizzle(file, { relations });
|
|
14
17
|
}
|
|
@@ -14,5 +14,8 @@ describe("todo queries", () => {
|
|
|
14
14
|
await expect(listTodos(db)).resolves.toEqual(
|
|
15
15
|
expect.arrayContaining([expect.objectContaining({ title })]),
|
|
16
16
|
);
|
|
17
|
+
await expect(db.query.todos.findMany()).resolves.toEqual(
|
|
18
|
+
expect.arrayContaining([expect.objectContaining({ title })]),
|
|
19
|
+
);
|
|
17
20
|
});
|
|
18
21
|
});
|
|
@@ -46,10 +46,16 @@ export type GeneratedScenarioRunnerOptions = {
|
|
|
46
46
|
readonly reporter?: GeneratedScenarioReporter;
|
|
47
47
|
readonly deterministicToolchainEnv?: Record<string, string>;
|
|
48
48
|
readonly rootCheckLock?: ExclusiveLock;
|
|
49
|
+
readonly replayCache?: GeneratedScenarioReplayCache | undefined;
|
|
49
50
|
};
|
|
50
51
|
export type ExclusiveLock = {
|
|
51
52
|
readonly run: <T>(callback: () => Promise<T>) => Promise<T>;
|
|
52
53
|
};
|
|
54
|
+
export type GeneratedScenarioReplayCache = {
|
|
55
|
+
readonly directory: string;
|
|
56
|
+
readonly read: boolean;
|
|
57
|
+
readonly write: boolean;
|
|
58
|
+
};
|
|
53
59
|
export declare function generatedScenarioChildProcessEnv(env?: Record<string, string>): NodeJS.ProcessEnv;
|
|
54
60
|
export declare function createExclusiveLock(): ExclusiveLock;
|
|
55
61
|
export declare function generatedScenarioId(scenario: Pick<GeneratedScenario, "basePreset" | "addedPreset" | "linkFrom">): string;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { mkdir, readdir, readFile, stat, writeFile } from "node:fs/promises";
|
|
2
3
|
import path from "node:path";
|
|
3
4
|
import { PackageAdditionSupport } from "@ykdz/template-shared";
|
|
4
5
|
import { execa } from "execa";
|
|
@@ -13,6 +14,7 @@ const defaultDeterministicToolchainEnv = {
|
|
|
13
14
|
TEMPLATE_TOOLCHAIN_RESOLUTION: "bundled-fallback",
|
|
14
15
|
};
|
|
15
16
|
const defaultFixtureConcurrency = 2;
|
|
17
|
+
const scenarioFingerprintVersion = 1;
|
|
16
18
|
const storedBlueprintSchema = v.object({
|
|
17
19
|
packages: v.optional(v.array(v.object({
|
|
18
20
|
name: v.string(),
|
|
@@ -171,6 +173,68 @@ function packageLeaf(packagePath) {
|
|
|
171
173
|
function hasSourceDirectoryPath(sourceFile) {
|
|
172
174
|
return sourceFile.startsWith("src/") || sourceFile.includes("/src/");
|
|
173
175
|
}
|
|
176
|
+
function scenarioFingerprintPrefix(scenario) {
|
|
177
|
+
return JSON.stringify({
|
|
178
|
+
version: scenarioFingerprintVersion,
|
|
179
|
+
scenario,
|
|
180
|
+
platform: process.platform,
|
|
181
|
+
arch: process.arch,
|
|
182
|
+
nodeMajor: process.versions.node.split(".")[0],
|
|
183
|
+
qualityGateProtocol: "lockfile-only-snapshot-then-fix-check",
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
async function hashGeneratedScenarioDirectory(scenario, projectDir) {
|
|
187
|
+
const hash = createHash("sha256");
|
|
188
|
+
hash.update(scenarioFingerprintPrefix(scenario));
|
|
189
|
+
await hashDirectoryEntries(projectDir, projectDir, hash);
|
|
190
|
+
return hash.digest("hex");
|
|
191
|
+
}
|
|
192
|
+
async function hashDirectoryEntries(rootDir, currentDir, hash) {
|
|
193
|
+
const entries = await readdir(currentDir, { withFileTypes: true });
|
|
194
|
+
for (const entry of entries.toSorted((left, right) => left.name.localeCompare(right.name))) {
|
|
195
|
+
if (entry.name === "node_modules" || entry.name === ".git") {
|
|
196
|
+
continue;
|
|
197
|
+
}
|
|
198
|
+
const entryPath = path.join(currentDir, entry.name);
|
|
199
|
+
const relativePath = path
|
|
200
|
+
.relative(rootDir, entryPath)
|
|
201
|
+
.split(path.sep)
|
|
202
|
+
.join("/");
|
|
203
|
+
if (entry.isDirectory()) {
|
|
204
|
+
hash.update(`dir\0${relativePath}\0`);
|
|
205
|
+
await hashDirectoryEntries(rootDir, entryPath, hash);
|
|
206
|
+
continue;
|
|
207
|
+
}
|
|
208
|
+
if (!entry.isFile()) {
|
|
209
|
+
const fileStat = await stat(entryPath);
|
|
210
|
+
hash.update(`special\0${relativePath}\0${fileStat.mode.toString(8)}\0`);
|
|
211
|
+
continue;
|
|
212
|
+
}
|
|
213
|
+
const fileStat = await stat(entryPath);
|
|
214
|
+
hash.update(`file\0${relativePath}\0${fileStat.mode.toString(8)}\0`);
|
|
215
|
+
hash.update(await readFile(entryPath));
|
|
216
|
+
hash.update("\0");
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
async function scenarioReplayMarkerExists(cache, fingerprint) {
|
|
220
|
+
try {
|
|
221
|
+
await readFile(path.join(cache.directory, `${fingerprint}.passed`), "utf8");
|
|
222
|
+
return true;
|
|
223
|
+
}
|
|
224
|
+
catch (error) {
|
|
225
|
+
if (error &&
|
|
226
|
+
typeof error === "object" &&
|
|
227
|
+
"code" in error &&
|
|
228
|
+
error.code === "ENOENT") {
|
|
229
|
+
return false;
|
|
230
|
+
}
|
|
231
|
+
throw error;
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
async function writeScenarioReplayMarker(cache, fingerprint, scenario) {
|
|
235
|
+
await mkdir(cache.directory, { recursive: true });
|
|
236
|
+
await writeFile(path.join(cache.directory, `${fingerprint}.passed`), `${JSON.stringify({ scenario, fingerprint })}\n`, "utf8");
|
|
237
|
+
}
|
|
174
238
|
export function packageLeafNameForAddedPreset(manifest, presetName) {
|
|
175
239
|
const preset = manifest.presets.find((entry) => entry.name === presetName);
|
|
176
240
|
if (!preset) {
|
|
@@ -383,9 +447,14 @@ export function generatedScenarioQualityGateSteps(manifest, scenario, projectDir
|
|
|
383
447
|
async function runGeneratedScenarioQualityGate(manifest, scenario, projectDir, addedPackagePath, options) {
|
|
384
448
|
const steps = generatedScenarioQualityGateSteps(manifest, scenario, projectDir, addedPackagePath, options);
|
|
385
449
|
const requiresSerializedPlaywrightRootCheck = generatedScenarioRequiresSerializedRootCheck(steps);
|
|
450
|
+
let replayFingerprint;
|
|
386
451
|
for (const step of steps) {
|
|
387
452
|
if (step.id === "install-dependencies") {
|
|
388
|
-
await runGeneratedScenarioInstallStep(step, scenario, options);
|
|
453
|
+
const installResult = await runGeneratedScenarioInstallStep(step, scenario, options);
|
|
454
|
+
replayFingerprint = installResult.fingerprint;
|
|
455
|
+
if (installResult.replayed) {
|
|
456
|
+
return;
|
|
457
|
+
}
|
|
389
458
|
continue;
|
|
390
459
|
}
|
|
391
460
|
const env = step.id === "run-root-check" ? { CI: "1" } : undefined;
|
|
@@ -401,13 +470,27 @@ async function runGeneratedScenarioQualityGate(manifest, scenario, projectDir, a
|
|
|
401
470
|
}
|
|
402
471
|
await runStep();
|
|
403
472
|
}
|
|
473
|
+
if (options.replayCache?.write && replayFingerprint !== undefined) {
|
|
474
|
+
await writeScenarioReplayMarker(options.replayCache, replayFingerprint, scenario);
|
|
475
|
+
options.reporter.info?.(`-- Stored passed fixture replay marker for ${scenario.label}: ${replayFingerprint}`);
|
|
476
|
+
}
|
|
404
477
|
}
|
|
405
478
|
async function runGeneratedScenarioInstallStep(step, scenario, options) {
|
|
406
479
|
await options.runCommand(step.command, ["install", "--lockfile-only", "--prefer-offline", "--no-frozen-lockfile"], step.cwd, { logPrefix: scenario.label });
|
|
480
|
+
let replayFingerprint;
|
|
481
|
+
if (options.replayCache) {
|
|
482
|
+
replayFingerprint = await hashGeneratedScenarioDirectory(scenario, step.cwd);
|
|
483
|
+
if (options.replayCache.read &&
|
|
484
|
+
(await scenarioReplayMarkerExists(options.replayCache, replayFingerprint))) {
|
|
485
|
+
options.reporter.info?.(`-- Replayed passed fixture ${scenario.label}: ${replayFingerprint}`);
|
|
486
|
+
return { fingerprint: replayFingerprint, replayed: true };
|
|
487
|
+
}
|
|
488
|
+
}
|
|
407
489
|
await options.runCommand(step.command, ["fetch"], step.cwd, {
|
|
408
490
|
logPrefix: scenario.label,
|
|
409
491
|
});
|
|
410
492
|
await options.runCommand(step.command, ["install", "--offline", "--frozen-lockfile"], step.cwd, { logPrefix: scenario.label });
|
|
493
|
+
return { fingerprint: replayFingerprint, replayed: false };
|
|
411
494
|
}
|
|
412
495
|
async function checkGeneratedScenario(manifest, scenario, workspace, options) {
|
|
413
496
|
options.reporter.info?.(`\n== ${scenario.label} ==`);
|
|
@@ -446,6 +529,7 @@ function normalizeRunnerOptions(options) {
|
|
|
446
529
|
},
|
|
447
530
|
deterministicToolchainEnv: options.deterministicToolchainEnv ?? defaultDeterministicToolchainEnv,
|
|
448
531
|
rootCheckLock: options.rootCheckLock ?? createExclusiveLock(),
|
|
532
|
+
replayCache: options.replayCache,
|
|
449
533
|
};
|
|
450
534
|
}
|
|
451
535
|
export async function runGeneratedScenariosConcurrently(manifest, scenarios, workspace, concurrency, options) {
|
|
@@ -12,16 +12,16 @@ catalog:
|
|
|
12
12
|
"@vitejs/plugin-vue": ^6.0.7
|
|
13
13
|
"@vikejs/hono": ^0.2.1
|
|
14
14
|
"@vue/tsconfig": ^0.9.1
|
|
15
|
-
drizzle-kit: 1.0.0-
|
|
16
|
-
drizzle-orm: 1.0.0-
|
|
15
|
+
drizzle-kit: 1.0.0-rc.4
|
|
16
|
+
drizzle-orm: 1.0.0-rc.4
|
|
17
17
|
execa: ^9.6.1
|
|
18
18
|
hono: ^4.12.27
|
|
19
|
-
oxfmt: ^0.
|
|
19
|
+
oxfmt: ^0.58.0
|
|
20
20
|
oxlint: ^1.72.0
|
|
21
21
|
oxlint-tsgolint: ^0.24.0
|
|
22
22
|
pinia: ^3.0.4
|
|
23
23
|
tailwindcss: ^4.3.2
|
|
24
|
-
telefunc: ^0.2.
|
|
24
|
+
telefunc: ^0.2.22
|
|
25
25
|
tsc-alias: ^1.8.17
|
|
26
26
|
tsx: ^4.22.4
|
|
27
27
|
turbo: 2.10.2
|
|
@@ -30,7 +30,7 @@ catalog:
|
|
|
30
30
|
vite: ^8.1.2
|
|
31
31
|
vike: ^0.4.260
|
|
32
32
|
vike-vue: ^0.9.12
|
|
33
|
-
vitest: ^4.1.
|
|
33
|
+
vitest: ^4.1.10
|
|
34
34
|
vue: ^3.5.39
|
|
35
35
|
vue-tsc: ^3.3.6
|
|
36
36
|
yaml: ^2.9.0
|
|
@@ -60,7 +60,7 @@ function renderDependabotUpdate(ecosystem, directory, interval) {
|
|
|
60
60
|
` interval: ${interval}`,
|
|
61
61
|
];
|
|
62
62
|
if (ecosystem === "npm") {
|
|
63
|
-
lines.push(" ignore:", ' - dependency-name: "@types/node"', " update-types:", " - version-update:semver-major");
|
|
63
|
+
lines.push(" groups:", " drizzle:", " patterns:", ' - "drizzle-*"', ' - "drizzle-orm"', " ignore:", ' - dependency-name: "@types/node"', " update-types:", " - version-update:semver-major");
|
|
64
64
|
}
|
|
65
65
|
if (ecosystem === "docker") {
|
|
66
66
|
lines.push(" ignore:", " - dependency-name: mcr.microsoft.com/devcontainers/typescript-node", " update-types:", " - version-update:semver-major");
|
|
@@ -1616,8 +1616,8 @@ function nodePackageTsconfigOperations(nodePackage, workspace) {
|
|
|
1616
1616
|
compilerOptions: {
|
|
1617
1617
|
...strictTypeScriptCompilerOptions({
|
|
1618
1618
|
composite: true,
|
|
1619
|
-
module: "
|
|
1620
|
-
moduleResolution: "
|
|
1619
|
+
module: "esnext",
|
|
1620
|
+
moduleResolution: "bundler",
|
|
1621
1621
|
paths: { "#/*": ["./*"] },
|
|
1622
1622
|
tsBuildInfoFile: "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
|
|
1623
1623
|
types: ["node"],
|
|
@@ -1658,8 +1658,8 @@ function nodePackageTsconfigOperations(nodePackage, workspace) {
|
|
|
1658
1658
|
compilerOptions: {
|
|
1659
1659
|
...strictTypeScriptCompilerOptions({
|
|
1660
1660
|
composite: true,
|
|
1661
|
-
module: "
|
|
1662
|
-
moduleResolution: "
|
|
1661
|
+
module: "esnext",
|
|
1662
|
+
moduleResolution: "bundler",
|
|
1663
1663
|
lib: ["ESNext", "DOM", "DOM.Iterable"],
|
|
1664
1664
|
paths: { "#/*": ["./*"] },
|
|
1665
1665
|
tsBuildInfoFile: "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
|
|
@@ -1730,8 +1730,8 @@ function nodePackageTsconfigOperations(nodePackage, workspace) {
|
|
|
1730
1730
|
extends: "@vue/tsconfig/tsconfig.dom.json",
|
|
1731
1731
|
compilerOptions: strictTypeScriptCompilerOptions({
|
|
1732
1732
|
composite: true,
|
|
1733
|
-
module: "
|
|
1734
|
-
moduleResolution: "
|
|
1733
|
+
module: "esnext",
|
|
1734
|
+
moduleResolution: "bundler",
|
|
1735
1735
|
tsBuildInfoFile: "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
|
|
1736
1736
|
types: ["web-bluetooth"],
|
|
1737
1737
|
}),
|
|
@@ -1758,8 +1758,8 @@ function nodePackageTsconfigOperations(nodePackage, workspace) {
|
|
|
1758
1758
|
value: {
|
|
1759
1759
|
compilerOptions: strictTypeScriptCompilerOptions({
|
|
1760
1760
|
composite: true,
|
|
1761
|
-
module: "
|
|
1762
|
-
moduleResolution: "
|
|
1761
|
+
module: "esnext",
|
|
1762
|
+
moduleResolution: "bundler",
|
|
1763
1763
|
lib: ["ESNext", "DOM", "DOM.Iterable"],
|
|
1764
1764
|
...(workspace.packages.length > 1
|
|
1765
1765
|
? { outDir: "./node_modules/.tmp/tsconfig.node" }
|
|
@@ -1898,8 +1898,8 @@ function vikeDbTsconfigJson() {
|
|
|
1898
1898
|
composite: true,
|
|
1899
1899
|
declaration: true,
|
|
1900
1900
|
declarationMap: true,
|
|
1901
|
-
module: "
|
|
1902
|
-
moduleResolution: "
|
|
1901
|
+
module: "esnext",
|
|
1902
|
+
moduleResolution: "bundler",
|
|
1903
1903
|
paths: { "#db/*": ["./src/*"] },
|
|
1904
1904
|
rootDir: ".",
|
|
1905
1905
|
types: ["node"],
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ykdz/template",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.21",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Project template generator for YKDZ starter projects.",
|
|
6
6
|
"keywords": [
|
|
@@ -34,13 +34,13 @@
|
|
|
34
34
|
"dependencies": {
|
|
35
35
|
"typescript": "^6.0.3",
|
|
36
36
|
"valibot": "^1.4.2",
|
|
37
|
-
"@ykdz/template-builtin-source": "0.0.0",
|
|
38
37
|
"@ykdz/template-core": "0.0.0",
|
|
38
|
+
"@ykdz/template-builtin-source": "0.0.0",
|
|
39
39
|
"@ykdz/template-shared": "0.0.0"
|
|
40
40
|
},
|
|
41
41
|
"devDependencies": {
|
|
42
42
|
"@types/node": "^24.0.0",
|
|
43
|
-
"oxfmt": "^0.
|
|
43
|
+
"oxfmt": "^0.58.0",
|
|
44
44
|
"oxlint": "^1.72.0",
|
|
45
45
|
"oxlint-tsgolint": "^0.24.0"
|
|
46
46
|
},
|