create-windy 0.5.0 → 0.5.2
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
CHANGED
|
@@ -2563,15 +2563,25 @@ async function materializeSelectedModules(targetDirectory, selectedNames) {
|
|
|
2563
2563
|
]),
|
|
2564
2564
|
...moduleDistributionCatalog.filter(({ databaseLineageOwner }) => databaseLineageOwner === "module").flatMap(({ databaseTables }) => databaseTables)
|
|
2565
2565
|
], removed.flatMap(({ databaseStatementTokens }) => databaseStatementTokens));
|
|
2566
|
-
const removedRoots = removed.flatMap((manifest) => [
|
|
2566
|
+
const removedRoots = collapseRemovalRoots(removed.flatMap((manifest) => [
|
|
2567
2567
|
...manifest.packages,
|
|
2568
2568
|
...manifest.fileRoots,
|
|
2569
2569
|
...manifest.documentation,
|
|
2570
2570
|
...manifest.schemaFiles
|
|
2571
|
-
]);
|
|
2571
|
+
]));
|
|
2572
2572
|
await Promise.all([...new Set(removedRoots)].map((path) => rm3(join7(targetDirectory, path), { recursive: true, force: true })));
|
|
2573
2573
|
await pruneWorkspaceReferences(targetDirectory, removedPackageNames, removedRoots);
|
|
2574
2574
|
}
|
|
2575
|
+
function collapseRemovalRoots(paths) {
|
|
2576
|
+
const roots = [];
|
|
2577
|
+
for (const path of [...new Set(paths)].sort((left, right) => left.length - right.length || left.localeCompare(right))) {
|
|
2578
|
+
if (roots.some((root) => path === root || path.startsWith(`${root}/`))) {
|
|
2579
|
+
continue;
|
|
2580
|
+
}
|
|
2581
|
+
roots.push(path);
|
|
2582
|
+
}
|
|
2583
|
+
return roots.sort();
|
|
2584
|
+
}
|
|
2575
2585
|
async function stripModuleBlocks(root, selected) {
|
|
2576
2586
|
for (const path of await collectFiles2(root)) {
|
|
2577
2587
|
if (!textExtensions.has(extname(path)))
|
|
@@ -2661,16 +2671,27 @@ async function pruneDatabaseArtifacts(root, tableNames, statementTokens) {
|
|
|
2661
2671
|
for (const path of await collectFiles2(drizzleRoot)) {
|
|
2662
2672
|
if (path.endsWith(".sql")) {
|
|
2663
2673
|
const source = await readFile6(path, "utf8");
|
|
2664
|
-
const statements = source.split("--> statement-breakpoint").map((statement) => statement.trim()).filter(Boolean)
|
|
2665
|
-
|
|
2674
|
+
const statements = source.split("--> statement-breakpoint").map((statement) => statement.trim()).filter(Boolean);
|
|
2675
|
+
const retained = statements.filter((statement) => !tablePatterns.some((pattern) => pattern.test(statement)) && !statementTokens.some((token) => statement.includes(token)));
|
|
2676
|
+
if (retained.length === statements.length)
|
|
2677
|
+
continue;
|
|
2678
|
+
await writeFile5(path, retained.length ? `${retained.join(`
|
|
2666
2679
|
--> statement-breakpoint
|
|
2667
2680
|
`)}
|
|
2668
2681
|
` : `-- \u6B64 migration \u7684\u6A21\u5757\u672A\u88AB\u5F53\u524D\u9879\u76EE\u9009\u62E9\u3002
|
|
2669
2682
|
`);
|
|
2670
2683
|
} else if (path.endsWith("_snapshot.json")) {
|
|
2671
2684
|
const snapshot = JSON.parse(await readFile6(path, "utf8"));
|
|
2672
|
-
|
|
2673
|
-
|
|
2685
|
+
let changed = false;
|
|
2686
|
+
for (const name of tableNames) {
|
|
2687
|
+
const key = `public.${name}`;
|
|
2688
|
+
if (!Object.hasOwn(snapshot.tables ?? {}, key))
|
|
2689
|
+
continue;
|
|
2690
|
+
delete snapshot.tables?.[key];
|
|
2691
|
+
changed = true;
|
|
2692
|
+
}
|
|
2693
|
+
if (!changed)
|
|
2694
|
+
continue;
|
|
2674
2695
|
await writeFile5(path, `${JSON.stringify(snapshot, null, 2)}
|
|
2675
2696
|
`);
|
|
2676
2697
|
}
|
|
@@ -7558,6 +7579,16 @@ var recipes = [
|
|
|
7558
7579
|
id: "starter-0.4.1-to-0.5.0",
|
|
7559
7580
|
from: "0.4.1",
|
|
7560
7581
|
to: "0.5.0"
|
|
7582
|
+
},
|
|
7583
|
+
{
|
|
7584
|
+
id: "starter-0.5.0-to-0.5.1",
|
|
7585
|
+
from: "0.5.0",
|
|
7586
|
+
to: "0.5.1"
|
|
7587
|
+
},
|
|
7588
|
+
{
|
|
7589
|
+
id: "starter-0.5.1-to-0.5.2",
|
|
7590
|
+
from: "0.5.1",
|
|
7591
|
+
to: "0.5.2"
|
|
7561
7592
|
}
|
|
7562
7593
|
];
|
|
7563
7594
|
function resolveRecipeChain(sourceVersion, targetVersion) {
|
|
@@ -8441,6 +8472,146 @@ import { join as join23 } from "path";
|
|
|
8441
8472
|
import { mkdtemp as mkdtemp2, rm as rm6, writeFile as writeFile12 } from "fs/promises";
|
|
8442
8473
|
import { tmpdir as tmpdir2 } from "os";
|
|
8443
8474
|
import { join as join22 } from "path";
|
|
8475
|
+
|
|
8476
|
+
// src/update/merge-convergent-additions.ts
|
|
8477
|
+
async function reconcileConvergentAdditions(input) {
|
|
8478
|
+
const [oursDiff, theirsDiff] = await Promise.all([
|
|
8479
|
+
diff(input.root, input.basePath, input.oursPath),
|
|
8480
|
+
diff(input.root, input.basePath, input.theirsPath)
|
|
8481
|
+
]);
|
|
8482
|
+
if (oursDiff === undefined || theirsDiff === undefined)
|
|
8483
|
+
return;
|
|
8484
|
+
const oursAdditions = pureAdditions(oursDiff);
|
|
8485
|
+
const theirsAdditions = pureAdditions(theirsDiff);
|
|
8486
|
+
const oursByContent = new Map;
|
|
8487
|
+
for (const addition of oursAdditions) {
|
|
8488
|
+
const key = addition.lines.join(`
|
|
8489
|
+
`);
|
|
8490
|
+
oursByContent.set(key, [...oursByContent.get(key) ?? [], addition]);
|
|
8491
|
+
}
|
|
8492
|
+
const decode = (content) => new TextDecoder().decode(content);
|
|
8493
|
+
const baseLines = decode(input.base).split(`
|
|
8494
|
+
`);
|
|
8495
|
+
const oursLines = decode(input.ours).split(`
|
|
8496
|
+
`);
|
|
8497
|
+
const theirsLines = decode(input.theirs).split(`
|
|
8498
|
+
`);
|
|
8499
|
+
const mergedLines = input.merged.split(`
|
|
8500
|
+
`);
|
|
8501
|
+
const convergent = theirsAdditions.flatMap((addition) => {
|
|
8502
|
+
if (!isSubstantial(addition.lines) || !isNamedClassMethod(addition.lines)) {
|
|
8503
|
+
return [];
|
|
8504
|
+
}
|
|
8505
|
+
const key = addition.lines.join(`
|
|
8506
|
+
`);
|
|
8507
|
+
const matchingOurs = oursByContent.get(key);
|
|
8508
|
+
if (matchingOurs?.length !== 1)
|
|
8509
|
+
return [];
|
|
8510
|
+
if (theirsAdditions.filter((candidate2) => candidate2.lines.join(`
|
|
8511
|
+
`) === key).length !== 1) {
|
|
8512
|
+
return [];
|
|
8513
|
+
}
|
|
8514
|
+
const oursContainer = enclosingClass(oursLines, matchingOurs[0]);
|
|
8515
|
+
const theirsContainer = enclosingClass(theirsLines, addition);
|
|
8516
|
+
if (!oursContainer || oursContainer !== theirsContainer)
|
|
8517
|
+
return [];
|
|
8518
|
+
return countSequence(baseLines, addition.lines) === 0 && countSequence(oursLines, addition.lines) === 1 && countSequence(theirsLines, addition.lines) === 1 && countSequence(mergedLines, addition.lines) > 1 ? [{ ours: matchingOurs[0], theirs: addition }] : [];
|
|
8519
|
+
});
|
|
8520
|
+
if (convergent.length !== 1)
|
|
8521
|
+
return;
|
|
8522
|
+
const candidate = convergent[0];
|
|
8523
|
+
if (!candidate)
|
|
8524
|
+
return;
|
|
8525
|
+
const oursWithout = withoutAddition(oursLines, candidate.ours);
|
|
8526
|
+
const theirsWithout = withoutAddition(theirsLines, candidate.theirs);
|
|
8527
|
+
if (!oursWithout || !theirsWithout || !sameLines(oursWithout, theirsWithout)) {
|
|
8528
|
+
return;
|
|
8529
|
+
}
|
|
8530
|
+
return input.ours;
|
|
8531
|
+
}
|
|
8532
|
+
async function diff(root, basePath, branchPath) {
|
|
8533
|
+
const result2 = await captureProcess("git", ["diff", "--no-index", "--unified=0", "--no-color", basePath, branchPath], root);
|
|
8534
|
+
return result2.code === 0 || result2.code === 1 ? result2.stdout : undefined;
|
|
8535
|
+
}
|
|
8536
|
+
function pureAdditions(diff2) {
|
|
8537
|
+
const lines = diff2.split(`
|
|
8538
|
+
`);
|
|
8539
|
+
const additions = [];
|
|
8540
|
+
for (let index = 0;index < lines.length; index += 1) {
|
|
8541
|
+
const match = /^@@ -\d+(?:,(\d+))? \+(\d+)(?:,(\d+))? @@/.exec(lines[index] ?? "");
|
|
8542
|
+
if (!match)
|
|
8543
|
+
continue;
|
|
8544
|
+
const oldCount = match[1] === undefined ? 1 : Number(match[1]);
|
|
8545
|
+
const start = Number(match[2]);
|
|
8546
|
+
const newCount = match[3] === undefined ? 1 : Number(match[3]);
|
|
8547
|
+
if (oldCount !== 0 || newCount === 0)
|
|
8548
|
+
continue;
|
|
8549
|
+
const added = [];
|
|
8550
|
+
for (let cursor = index + 1;cursor < lines.length; cursor += 1) {
|
|
8551
|
+
const line = lines[cursor] ?? "";
|
|
8552
|
+
if (line.startsWith("@@ "))
|
|
8553
|
+
break;
|
|
8554
|
+
if (line.startsWith("+"))
|
|
8555
|
+
added.push(line.slice(1));
|
|
8556
|
+
}
|
|
8557
|
+
if (added.length === newCount)
|
|
8558
|
+
additions.push({ start, lines: added });
|
|
8559
|
+
}
|
|
8560
|
+
return additions;
|
|
8561
|
+
}
|
|
8562
|
+
function isSubstantial(lines) {
|
|
8563
|
+
return lines.filter((line) => line.trim()).length >= 3 && lines.join(`
|
|
8564
|
+
`).length >= 32;
|
|
8565
|
+
}
|
|
8566
|
+
function isNamedClassMethod(lines) {
|
|
8567
|
+
const first = lines.find((line) => line.trim())?.trim() ?? "";
|
|
8568
|
+
const last = [...lines].reverse().find((line) => line.trim())?.trim() ?? "";
|
|
8569
|
+
return /^(?:(?:public|protected|private|static|abstract|override|async|declare|get|set)\s+)*(?:\*\s*)?[A-Za-z_$][\w$]*\s*(?:<[^>{}]*>)?\s*\(/.test(first) && lines.some((line) => line.includes("{")) && /^}\s*;?$/.test(last);
|
|
8570
|
+
}
|
|
8571
|
+
function enclosingClass(lines, addition) {
|
|
8572
|
+
const memberIndent = leadingWhitespace(addition.lines.find((line) => line.trim()) ?? "");
|
|
8573
|
+
for (let index = addition.start - 2;index >= 0; index -= 1) {
|
|
8574
|
+
const line = lines[index] ?? "";
|
|
8575
|
+
if (!line.trim() || leadingWhitespace(line) >= memberIndent)
|
|
8576
|
+
continue;
|
|
8577
|
+
const match = /^(\s*)(?:(?:export|default|abstract|declare)\s+)*class\s+([A-Za-z_$][\w$]*)\b/.exec(line);
|
|
8578
|
+
if (!match)
|
|
8579
|
+
return;
|
|
8580
|
+
const name = match[2] ?? "";
|
|
8581
|
+
const ordinal = lines.slice(0, index + 1).filter((candidate) => new RegExp(`^\\s*(?:(?:export|default|abstract|declare)\\s+)*class\\s+${escapeRegExp2(name)}\\b`).test(candidate)).length;
|
|
8582
|
+
return `${name}#${ordinal}`;
|
|
8583
|
+
}
|
|
8584
|
+
}
|
|
8585
|
+
function leadingWhitespace(line) {
|
|
8586
|
+
return /^\s*/.exec(line)?.[0].length ?? 0;
|
|
8587
|
+
}
|
|
8588
|
+
function escapeRegExp2(value) {
|
|
8589
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
8590
|
+
}
|
|
8591
|
+
function countSequence(lines, sequence) {
|
|
8592
|
+
let count = 0;
|
|
8593
|
+
for (let index = 0;index <= lines.length - sequence.length; index += 1) {
|
|
8594
|
+
if (sameLines(lines.slice(index, index + sequence.length), sequence)) {
|
|
8595
|
+
count += 1;
|
|
8596
|
+
}
|
|
8597
|
+
}
|
|
8598
|
+
return count;
|
|
8599
|
+
}
|
|
8600
|
+
function withoutAddition(lines, addition) {
|
|
8601
|
+
const index = addition.start - 1;
|
|
8602
|
+
if (!sameLines(lines.slice(index, index + addition.lines.length), addition.lines)) {
|
|
8603
|
+
return;
|
|
8604
|
+
}
|
|
8605
|
+
return [
|
|
8606
|
+
...lines.slice(0, index),
|
|
8607
|
+
...lines.slice(index + addition.lines.length)
|
|
8608
|
+
];
|
|
8609
|
+
}
|
|
8610
|
+
function sameLines(left, right) {
|
|
8611
|
+
return left.length === right.length && left.every((line, index) => line === right[index]);
|
|
8612
|
+
}
|
|
8613
|
+
|
|
8614
|
+
// src/update/merge.ts
|
|
8444
8615
|
async function mergeTextFile(base, ours, theirs) {
|
|
8445
8616
|
const root = await mkdtemp2(join22(tmpdir2(), "windy-merge-"));
|
|
8446
8617
|
try {
|
|
@@ -8454,6 +8625,19 @@ async function mergeTextFile(base, ours, theirs) {
|
|
|
8454
8625
|
]);
|
|
8455
8626
|
const result2 = await captureProcess("git", ["merge-file", "-p", "--diff3", oursPath, basePath, theirsPath], root);
|
|
8456
8627
|
if (result2.code === 0) {
|
|
8628
|
+
const reconciledContent = await reconcileConvergentAdditions({
|
|
8629
|
+
root,
|
|
8630
|
+
basePath,
|
|
8631
|
+
oursPath,
|
|
8632
|
+
theirsPath,
|
|
8633
|
+
base,
|
|
8634
|
+
ours,
|
|
8635
|
+
theirs,
|
|
8636
|
+
merged: result2.stdout
|
|
8637
|
+
});
|
|
8638
|
+
if (reconciledContent !== undefined) {
|
|
8639
|
+
return { content: reconciledContent };
|
|
8640
|
+
}
|
|
8457
8641
|
return { content: new TextEncoder().encode(result2.stdout) };
|
|
8458
8642
|
}
|
|
8459
8643
|
if (result2.code === 1) {
|
|
@@ -8634,6 +8818,11 @@ function mergeValue(base, ours, theirs, path2, conflicts) {
|
|
|
8634
8818
|
return theirs;
|
|
8635
8819
|
if (equal(theirs, base))
|
|
8636
8820
|
return ours;
|
|
8821
|
+
if (path2 === "package.json.files") {
|
|
8822
|
+
const files = mergeAppendOnlyStringSet(base, ours, theirs);
|
|
8823
|
+
if (files)
|
|
8824
|
+
return files;
|
|
8825
|
+
}
|
|
8637
8826
|
if (isObject(base) && isObject(ours) && isObject(theirs)) {
|
|
8638
8827
|
const output = {};
|
|
8639
8828
|
const keys = new Set([
|
|
@@ -8654,6 +8843,15 @@ function mergeValue(base, ours, theirs, path2, conflicts) {
|
|
|
8654
8843
|
function equal(left, right) {
|
|
8655
8844
|
return JSON.stringify(left) === JSON.stringify(right);
|
|
8656
8845
|
}
|
|
8846
|
+
function mergeAppendOnlyStringSet(base, ours, theirs) {
|
|
8847
|
+
if (!isStringArray(base) || !isStringArray(ours) || !isStringArray(theirs) || !base.every((value) => ours.includes(value) && theirs.includes(value))) {
|
|
8848
|
+
return;
|
|
8849
|
+
}
|
|
8850
|
+
return [...new Set([...ours, ...theirs])].sort();
|
|
8851
|
+
}
|
|
8852
|
+
function isStringArray(value) {
|
|
8853
|
+
return Array.isArray(value) && value.every((item) => typeof item === "string");
|
|
8854
|
+
}
|
|
8657
8855
|
function isObject(value) {
|
|
8658
8856
|
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
8659
8857
|
}
|
|
@@ -8836,6 +9034,33 @@ function resolveModuleRecipeIds(request) {
|
|
|
8836
9034
|
return lifecycle.updatedModules.flatMap((name) => catalog.get(name).updateRecipes);
|
|
8837
9035
|
}
|
|
8838
9036
|
|
|
9037
|
+
// src/update/planner-project-owned-tests.ts
|
|
9038
|
+
var testSuffixes = [
|
|
9039
|
+
".webtest.ts",
|
|
9040
|
+
".webtest.tsx",
|
|
9041
|
+
".test.ts",
|
|
9042
|
+
".test.tsx"
|
|
9043
|
+
];
|
|
9044
|
+
var sourceExtensions = [".vue", ".ts", ".tsx", ".js", ".jsx"];
|
|
9045
|
+
function preserveTestsForExistingProjectOwnedSources(files, sourceEntries) {
|
|
9046
|
+
const projectOwnedSourcePaths = new Set([...sourceEntries.values()].filter(({ ownership }) => ownership === "project-owned").map(({ path: path2 }) => path2));
|
|
9047
|
+
for (const file of files) {
|
|
9048
|
+
if (file.ownership !== "project-owned" || file.action !== "create" || !hasExistingSourceForTest(file.path, projectOwnedSourcePaths)) {
|
|
9049
|
+
continue;
|
|
9050
|
+
}
|
|
9051
|
+
file.action = "preserve";
|
|
9052
|
+
file.reason = "\u9879\u76EE\u81EA\u6709\u5B9E\u73B0\u5DF2\u5B58\u5728\uFF0C\u4E0D\u65B0\u589E\u4E0A\u6E38\u884C\u4E3A\u6D4B\u8BD5";
|
|
9053
|
+
delete file.content;
|
|
9054
|
+
}
|
|
9055
|
+
}
|
|
9056
|
+
function hasExistingSourceForTest(path2, sourcePaths) {
|
|
9057
|
+
const suffix = testSuffixes.find((candidate) => path2.endsWith(candidate));
|
|
9058
|
+
if (!suffix)
|
|
9059
|
+
return false;
|
|
9060
|
+
const stem = path2.slice(0, -suffix.length);
|
|
9061
|
+
return sourceExtensions.some((extension) => sourcePaths.has(`${stem}${extension}`));
|
|
9062
|
+
}
|
|
9063
|
+
|
|
8839
9064
|
// src/update/planner-snapshots.ts
|
|
8840
9065
|
import { readFile as readFile20, stat as stat2 } from "fs/promises";
|
|
8841
9066
|
import { join as join24 } from "path";
|
|
@@ -8995,6 +9220,7 @@ async function createUpdatePlan(request, artifacts) {
|
|
|
8995
9220
|
manageGeneratedProjectOwned: request.targetModules !== undefined,
|
|
8996
9221
|
forcePlatformBaseline: request.forcePlatformBaseline === true
|
|
8997
9222
|
});
|
|
9223
|
+
preserveTestsForExistingProjectOwnedSources(files, sourceEntries);
|
|
8998
9224
|
await deriveDockerfilePlans(files, projectSnapshots, new Set([
|
|
8999
9225
|
...paths,
|
|
9000
9226
|
...workspaceSnapshot.manifests.keys(),
|
package/package.json
CHANGED
|
@@ -1,7 +1,26 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
|
|
2
|
+
interface GpuMonitorSnapshot {
|
|
3
|
+
status: "available" | "not-detected" | "unavailable";
|
|
4
|
+
provider: "NVIDIA";
|
|
5
|
+
message: string;
|
|
6
|
+
devices: Array<{
|
|
7
|
+
index: number;
|
|
8
|
+
uuid: string;
|
|
9
|
+
name: string;
|
|
10
|
+
usagePercent: number | null;
|
|
11
|
+
memoryUsedBytes: number | null;
|
|
12
|
+
memoryTotalBytes: number | null;
|
|
13
|
+
memoryUsagePercent: number | null;
|
|
14
|
+
temperatureCelsius: number | null;
|
|
15
|
+
processes: Array<{
|
|
16
|
+
pid: number;
|
|
17
|
+
name: string;
|
|
18
|
+
usedMemoryBytes: number | null;
|
|
19
|
+
}>;
|
|
20
|
+
}>;
|
|
21
|
+
}
|
|
3
22
|
|
|
4
|
-
defineProps<{ gpu:
|
|
23
|
+
defineProps<{ gpu: GpuMonitorSnapshot }>();
|
|
5
24
|
|
|
6
25
|
function formatBytes(value: number | null) {
|
|
7
26
|
if (value === null) return "未知";
|