create-windy 0.5.1 → 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)))
|
|
@@ -7574,6 +7584,11 @@ var recipes = [
|
|
|
7574
7584
|
id: "starter-0.5.0-to-0.5.1",
|
|
7575
7585
|
from: "0.5.0",
|
|
7576
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"
|
|
7577
7592
|
}
|
|
7578
7593
|
];
|
|
7579
7594
|
function resolveRecipeChain(sourceVersion, targetVersion) {
|
|
@@ -8457,6 +8472,146 @@ import { join as join23 } from "path";
|
|
|
8457
8472
|
import { mkdtemp as mkdtemp2, rm as rm6, writeFile as writeFile12 } from "fs/promises";
|
|
8458
8473
|
import { tmpdir as tmpdir2 } from "os";
|
|
8459
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
|
|
8460
8615
|
async function mergeTextFile(base, ours, theirs) {
|
|
8461
8616
|
const root = await mkdtemp2(join22(tmpdir2(), "windy-merge-"));
|
|
8462
8617
|
try {
|
|
@@ -8470,6 +8625,19 @@ async function mergeTextFile(base, ours, theirs) {
|
|
|
8470
8625
|
]);
|
|
8471
8626
|
const result2 = await captureProcess("git", ["merge-file", "-p", "--diff3", oursPath, basePath, theirsPath], root);
|
|
8472
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
|
+
}
|
|
8473
8641
|
return { content: new TextEncoder().encode(result2.stdout) };
|
|
8474
8642
|
}
|
|
8475
8643
|
if (result2.code === 1) {
|
|
@@ -8866,6 +9034,33 @@ function resolveModuleRecipeIds(request) {
|
|
|
8866
9034
|
return lifecycle.updatedModules.flatMap((name) => catalog.get(name).updateRecipes);
|
|
8867
9035
|
}
|
|
8868
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
|
+
|
|
8869
9064
|
// src/update/planner-snapshots.ts
|
|
8870
9065
|
import { readFile as readFile20, stat as stat2 } from "fs/promises";
|
|
8871
9066
|
import { join as join24 } from "path";
|
|
@@ -9025,6 +9220,7 @@ async function createUpdatePlan(request, artifacts) {
|
|
|
9025
9220
|
manageGeneratedProjectOwned: request.targetModules !== undefined,
|
|
9026
9221
|
forcePlatformBaseline: request.forcePlatformBaseline === true
|
|
9027
9222
|
});
|
|
9223
|
+
preserveTestsForExistingProjectOwnedSources(files, sourceEntries);
|
|
9028
9224
|
await deriveDockerfilePlans(files, projectSnapshots, new Set([
|
|
9029
9225
|
...paths,
|
|
9030
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 "未知";
|