headlamp 0.1.5 → 0.1.8
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/README.md +30 -2
- package/dist/cli.cjs +398 -262
- package/dist/cli.cjs.map +4 -4
- package/dist/index.js +405 -266
- package/dist/index.js.map +4 -4
- package/package.json +10 -4
- package/scripts/build.mjs +117 -0
- package/scripts/postinstall.mjs +13 -0
- package/scripts/print-publish-log.mjs +29 -0
package/dist/index.js
CHANGED
|
@@ -67,7 +67,8 @@ var init_args = __esm({
|
|
|
67
67
|
coverageMode: (value) => ({ type: "coverageMode", value }),
|
|
68
68
|
coverageMaxFiles: (value) => ({ type: "coverageMaxFiles", value }),
|
|
69
69
|
coverageMaxHotspots: (value) => ({ type: "coverageMaxHotspots", value }),
|
|
70
|
-
coveragePageFit: (value) => ({ type: "coveragePageFit", value })
|
|
70
|
+
coveragePageFit: (value) => ({ type: "coveragePageFit", value }),
|
|
71
|
+
changed: (value) => ({ type: "changed", value })
|
|
71
72
|
};
|
|
72
73
|
Some = (value) => ({ _tag: "some", value });
|
|
73
74
|
None = { _tag: "none" };
|
|
@@ -264,6 +265,18 @@ var init_args = __esm({
|
|
|
264
265
|
"--coverage.root=",
|
|
265
266
|
(value) => step([ActionBuilders.coverageRoot((value.split("=")[1] ?? "").trim())])
|
|
266
267
|
),
|
|
268
|
+
// --changed flag: selects changed files via git (all|staged|unstaged)
|
|
269
|
+
rule.eq("--changed", () => step([ActionBuilders.changed("all")])),
|
|
270
|
+
rule.startsWith("--changed=", (value) => {
|
|
271
|
+
const raw = (value.split("=")[1] ?? "").trim().toLowerCase();
|
|
272
|
+
const mode = raw === "staged" ? "staged" : raw === "unstaged" ? "unstaged" : "all";
|
|
273
|
+
return step([ActionBuilders.changed(mode)]);
|
|
274
|
+
}),
|
|
275
|
+
rule.withLookahead("--changed", (_flag, lookahead) => {
|
|
276
|
+
const raw = String(lookahead).trim().toLowerCase();
|
|
277
|
+
const mode = raw === "staged" ? "staged" : raw === "unstaged" ? "unstaged" : "all";
|
|
278
|
+
return step([ActionBuilders.changed(mode)], true);
|
|
279
|
+
}),
|
|
267
280
|
rule.withLookahead(
|
|
268
281
|
"-t",
|
|
269
282
|
(flag, lookahead) => step(
|
|
@@ -366,6 +379,8 @@ var init_args = __esm({
|
|
|
366
379
|
return { vitest: [], jest: [], coverage: false, coverageMaxHotspots: action.value };
|
|
367
380
|
case "coveragePageFit":
|
|
368
381
|
return { vitest: [], jest: [], coverage: false, coveragePageFit: action.value };
|
|
382
|
+
case "changed":
|
|
383
|
+
return { vitest: [], jest: [], coverage: false, changed: action.value };
|
|
369
384
|
case "jestArg":
|
|
370
385
|
return { vitest: [], jest: [action.value], coverage: false };
|
|
371
386
|
case "vitestArg":
|
|
@@ -405,6 +420,7 @@ var init_args = __esm({
|
|
|
405
420
|
}
|
|
406
421
|
return {
|
|
407
422
|
...next,
|
|
423
|
+
...right.changed !== void 0 || left.changed !== void 0 ? { changed: right.changed ?? left.changed } : {},
|
|
408
424
|
...right.coverageAbortOnFailure !== void 0 || left.coverageAbortOnFailure !== void 0 ? { coverageAbortOnFailure: right.coverageAbortOnFailure ?? left.coverageAbortOnFailure } : {},
|
|
409
425
|
...right.coverageDetail !== void 0 || left.coverageDetail !== void 0 ? { coverageDetail: right.coverageDetail ?? left.coverageDetail } : {},
|
|
410
426
|
...right.coverageShowCode !== void 0 || left.coverageShowCode !== void 0 ? { coverageShowCode: right.coverageShowCode ?? left.coverageShowCode } : {},
|
|
@@ -490,7 +506,8 @@ var init_args = __esm({
|
|
|
490
506
|
...coverageMaxHotspotsLocal !== void 0 ? { coverageMaxHotspots: coverageMaxHotspotsLocal } : {},
|
|
491
507
|
coveragePageFit,
|
|
492
508
|
...contrib.editorCmd !== void 0 ? { editorCmd: contrib.editorCmd } : {},
|
|
493
|
-
...contrib.workspaceRoot !== void 0 ? { workspaceRoot: contrib.workspaceRoot } : {}
|
|
509
|
+
...contrib.workspaceRoot !== void 0 ? { workspaceRoot: contrib.workspaceRoot } : {},
|
|
510
|
+
...contrib.changed !== void 0 ? { changed: contrib.changed } : {}
|
|
494
511
|
};
|
|
495
512
|
return out;
|
|
496
513
|
};
|
|
@@ -557,7 +574,7 @@ var init_TimeoutError = __esm({
|
|
|
557
574
|
|
|
558
575
|
// node_modules/es-toolkit/dist/promise/delay.mjs
|
|
559
576
|
function delay(ms, { signal } = {}) {
|
|
560
|
-
return new Promise((
|
|
577
|
+
return new Promise((resolve9, reject) => {
|
|
561
578
|
const abortError = () => {
|
|
562
579
|
reject(new AbortError());
|
|
563
580
|
};
|
|
@@ -570,7 +587,7 @@ function delay(ms, { signal } = {}) {
|
|
|
570
587
|
}
|
|
571
588
|
const timeoutId = setTimeout(() => {
|
|
572
589
|
signal?.removeEventListener("abort", abortHandler);
|
|
573
|
-
|
|
590
|
+
resolve9();
|
|
574
591
|
}, ms);
|
|
575
592
|
signal?.addEventListener("abort", abortHandler, { once: true });
|
|
576
593
|
});
|
|
@@ -635,11 +652,11 @@ var init_exec = __esm({
|
|
|
635
652
|
child.stderr?.on("data", (chunk) => {
|
|
636
653
|
stderr += String(chunk);
|
|
637
654
|
});
|
|
638
|
-
const exec = new Promise((
|
|
655
|
+
const exec = new Promise((resolve9, reject) => {
|
|
639
656
|
child.on("error", reject);
|
|
640
657
|
child.on(
|
|
641
658
|
"close",
|
|
642
|
-
(code) => Number(code) === 0 ?
|
|
659
|
+
(code) => Number(code) === 0 ? resolve9(stdout) : reject(new Error(stderr || `exit ${code}`))
|
|
643
660
|
);
|
|
644
661
|
});
|
|
645
662
|
try {
|
|
@@ -659,7 +676,7 @@ var init_exec = __esm({
|
|
|
659
676
|
throw caughtError;
|
|
660
677
|
}
|
|
661
678
|
};
|
|
662
|
-
runExitCode = async (cmd, args, opts = {}) => new Promise((
|
|
679
|
+
runExitCode = async (cmd, args, opts = {}) => new Promise((resolve9, reject) => {
|
|
663
680
|
const child = spawn(cmd, [...args], {
|
|
664
681
|
cwd: opts.cwd,
|
|
665
682
|
env: opts.env,
|
|
@@ -668,9 +685,9 @@ var init_exec = __esm({
|
|
|
668
685
|
windowsHide: true
|
|
669
686
|
});
|
|
670
687
|
child.on("error", reject);
|
|
671
|
-
child.on("close", (code) =>
|
|
688
|
+
child.on("close", (code) => resolve9(Number(code)));
|
|
672
689
|
});
|
|
673
|
-
runWithCapture = async (cmd, args, opts) => new Promise((
|
|
690
|
+
runWithCapture = async (cmd, args, opts) => new Promise((resolve9, reject) => {
|
|
674
691
|
const child = spawn(cmd, [...args], {
|
|
675
692
|
cwd: opts.cwd,
|
|
676
693
|
env: opts.env,
|
|
@@ -686,7 +703,7 @@ var init_exec = __esm({
|
|
|
686
703
|
buf += String(chunk);
|
|
687
704
|
});
|
|
688
705
|
child.on("error", reject);
|
|
689
|
-
child.on("close", (code) =>
|
|
706
|
+
child.on("close", (code) => resolve9({ code: Number(code), output: buf }));
|
|
690
707
|
});
|
|
691
708
|
}
|
|
692
709
|
});
|
|
@@ -1097,8 +1114,8 @@ var require_utils = __commonJS({
|
|
|
1097
1114
|
}
|
|
1098
1115
|
return output;
|
|
1099
1116
|
};
|
|
1100
|
-
exports.basename = (
|
|
1101
|
-
const segs =
|
|
1117
|
+
exports.basename = (path11, { windows } = {}) => {
|
|
1118
|
+
const segs = path11.split(windows ? /[\\/]/ : "/");
|
|
1102
1119
|
const last = segs[segs.length - 1];
|
|
1103
1120
|
if (last === "") {
|
|
1104
1121
|
return segs[segs.length - 2];
|
|
@@ -2168,7 +2185,7 @@ var require_parse = __commonJS({
|
|
|
2168
2185
|
if (opts2.noglobstar === true) return star;
|
|
2169
2186
|
return `(${capture}(?:(?!${START_ANCHOR}${opts2.dot ? DOTS_SLASH : DOT_LITERAL}).)*?)`;
|
|
2170
2187
|
};
|
|
2171
|
-
const
|
|
2188
|
+
const create2 = (str) => {
|
|
2172
2189
|
switch (str) {
|
|
2173
2190
|
case "*":
|
|
2174
2191
|
return `${nodot}${ONE_CHAR}${star}`;
|
|
@@ -2189,14 +2206,14 @@ var require_parse = __commonJS({
|
|
|
2189
2206
|
default: {
|
|
2190
2207
|
const match = /^(.*?)\.(\w+)$/.exec(str);
|
|
2191
2208
|
if (!match) return;
|
|
2192
|
-
const source2 =
|
|
2209
|
+
const source2 = create2(match[1]);
|
|
2193
2210
|
if (!source2) return;
|
|
2194
2211
|
return source2 + DOT_LITERAL + match[2];
|
|
2195
2212
|
}
|
|
2196
2213
|
}
|
|
2197
2214
|
};
|
|
2198
2215
|
const output = utils.removePrefix(input, state);
|
|
2199
|
-
let source =
|
|
2216
|
+
let source = create2(output);
|
|
2200
2217
|
if (source && opts.strictSlashes !== true) {
|
|
2201
2218
|
source += `${SLASH_LITERAL}?`;
|
|
2202
2219
|
}
|
|
@@ -4688,8 +4705,75 @@ var compositeBarPct = (summary, hotspots) => {
|
|
|
4688
4705
|
// src/lib/coverage-print.ts
|
|
4689
4706
|
init_env_utils();
|
|
4690
4707
|
init_exec();
|
|
4691
|
-
import * as
|
|
4708
|
+
import * as path8 from "node:path";
|
|
4692
4709
|
import * as fsSync2 from "node:fs";
|
|
4710
|
+
|
|
4711
|
+
// src/lib/relevance.ts
|
|
4712
|
+
init_args();
|
|
4713
|
+
init_fast_related();
|
|
4714
|
+
import * as path7 from "node:path";
|
|
4715
|
+
var normalizeAbs = (inputPath) => path7.resolve(inputPath).replace(/\\/g, "/");
|
|
4716
|
+
var compareBooleanDesc = (left, right) => {
|
|
4717
|
+
if (left === right) {
|
|
4718
|
+
return 0;
|
|
4719
|
+
}
|
|
4720
|
+
return right ? 1 : -1;
|
|
4721
|
+
};
|
|
4722
|
+
var compareNumberAsc = (left, right) => left - right;
|
|
4723
|
+
var compareStringAsc = (left, right) => left.localeCompare(right);
|
|
4724
|
+
var fileFailed = (file) => Boolean(
|
|
4725
|
+
(file.status ?? "") === "failed" || (file.testResults ?? []).some((assertion) => (assertion.status ?? "") === "failed")
|
|
4726
|
+
);
|
|
4727
|
+
var composeComparators = (...comparators) => (left, right) => {
|
|
4728
|
+
for (const cmp of comparators) {
|
|
4729
|
+
const result = cmp(left, right);
|
|
4730
|
+
if (result !== 0) {
|
|
4731
|
+
return result;
|
|
4732
|
+
}
|
|
4733
|
+
}
|
|
4734
|
+
return 0;
|
|
4735
|
+
};
|
|
4736
|
+
var comparatorForRank = (rankByPath) => {
|
|
4737
|
+
const rankOrInf = (absPath) => rankByPath.has(absPath) ? rankByPath.get(absPath) : Number.POSITIVE_INFINITY;
|
|
4738
|
+
return composeComparators(
|
|
4739
|
+
(left, right) => compareBooleanDesc(fileFailed(left), fileFailed(right)),
|
|
4740
|
+
(left, right) => compareNumberAsc(
|
|
4741
|
+
rankOrInf(normalizeAbs(left.testFilePath)),
|
|
4742
|
+
rankOrInf(normalizeAbs(right.testFilePath))
|
|
4743
|
+
),
|
|
4744
|
+
(left, right) => compareStringAsc(normalizeAbs(left.testFilePath), normalizeAbs(right.testFilePath))
|
|
4745
|
+
);
|
|
4746
|
+
};
|
|
4747
|
+
var computeDirectnessRank = async (opts) => {
|
|
4748
|
+
const selectionKey = opts.productionSeeds.map((abs) => path7.relative(opts.repoRoot, abs).replace(/\\/g, "/")).sort((left, right) => left.localeCompare(right)).join("|");
|
|
4749
|
+
const related = await cachedRelated({
|
|
4750
|
+
repoRoot: opts.repoRoot,
|
|
4751
|
+
selectionKey,
|
|
4752
|
+
compute: () => findRelatedTestsFast({
|
|
4753
|
+
repoRoot: opts.repoRoot,
|
|
4754
|
+
productionPaths: opts.productionSeeds,
|
|
4755
|
+
testGlobs: DEFAULT_TEST_GLOBS,
|
|
4756
|
+
excludeGlobs: opts.excludeGlobs ?? DEFAULT_EXCLUDE,
|
|
4757
|
+
timeoutMs: 1500
|
|
4758
|
+
})
|
|
4759
|
+
});
|
|
4760
|
+
const out = /* @__PURE__ */ new Map();
|
|
4761
|
+
related.forEach((abs, index) => {
|
|
4762
|
+
out.set(normalizeAbs(abs), index);
|
|
4763
|
+
});
|
|
4764
|
+
return out;
|
|
4765
|
+
};
|
|
4766
|
+
var sortTestResultsWithRank = (rankByPath, results) => results.slice().sort(comparatorForRank(rankByPath));
|
|
4767
|
+
var comparatorForPathRank = (rankByPath) => {
|
|
4768
|
+
const rankOrInf = (absPath) => rankByPath.has(absPath) ? rankByPath.get(absPath) : Number.POSITIVE_INFINITY;
|
|
4769
|
+
return composeComparators(
|
|
4770
|
+
(left, right) => compareNumberAsc(rankOrInf(normalizeAbs(left)), rankOrInf(normalizeAbs(right))),
|
|
4771
|
+
(left, right) => compareStringAsc(normalizeAbs(left), normalizeAbs(right))
|
|
4772
|
+
);
|
|
4773
|
+
};
|
|
4774
|
+
var sortPathsWithRank = (rankByPath, paths) => paths.slice().sort(comparatorForPathRank(rankByPath));
|
|
4775
|
+
|
|
4776
|
+
// src/lib/coverage-print.ts
|
|
4693
4777
|
var printDetailedCoverage = async (opts) => {
|
|
4694
4778
|
const files = opts.map.files().sort((fileA, fileB) => {
|
|
4695
4779
|
const summaryA = opts.map.fileCoverageFor(fileA).toSummary();
|
|
@@ -4699,7 +4783,7 @@ var printDetailedCoverage = async (opts) => {
|
|
|
4699
4783
|
for (const abs of files) {
|
|
4700
4784
|
const fc = opts.map.fileCoverageFor(abs);
|
|
4701
4785
|
const sum = fc.toSummary();
|
|
4702
|
-
const rel =
|
|
4786
|
+
const rel = path8.relative(opts.root, abs).replace(/\\/g, "/");
|
|
4703
4787
|
const blocks = computeUncoveredBlocks(fc);
|
|
4704
4788
|
const misses = missedBranches(fc);
|
|
4705
4789
|
const missFns = missedFunctions(fc);
|
|
@@ -4708,9 +4792,9 @@ var printDetailedCoverage = async (opts) => {
|
|
|
4708
4792
|
const branchesPctText = `${sum.branches.pct.toFixed(1)}%`;
|
|
4709
4793
|
const header = `${ansi.bold(rel)} lines ${tintPct(sum.lines.pct)(
|
|
4710
4794
|
linesPctText
|
|
4711
|
-
)} ${barCell(compositeBarPct(sum, blocks))("".padEnd(14))} funcs ${tintPct(
|
|
4712
|
-
|
|
4713
|
-
)
|
|
4795
|
+
)} ${barCell(compositeBarPct(sum, blocks))("".padEnd(14))} funcs ${tintPct(sum.functions.pct)(
|
|
4796
|
+
funcsPctText
|
|
4797
|
+
)} branches ${tintPct(sum.branches.pct)(branchesPctText)}`;
|
|
4714
4798
|
console.info(header);
|
|
4715
4799
|
const max = opts.limitPerFile === "all" ? Number.POSITIVE_INFINITY : opts.limitPerFile ?? 5;
|
|
4716
4800
|
const compareRangesByLengthDescThenStart = (firstRange, secondRange) => {
|
|
@@ -4737,10 +4821,8 @@ var printDetailedCoverage = async (opts) => {
|
|
|
4737
4821
|
abs,
|
|
4738
4822
|
block.start,
|
|
4739
4823
|
opts.editorCmd
|
|
4740
|
-
)}\x07${
|
|
4741
|
-
const label = ` ${ansi.yellow(`L${block.start}`)}\u2013${ansi.yellow(
|
|
4742
|
-
`L${block.end}`
|
|
4743
|
-
)} ${link}`;
|
|
4824
|
+
)}\x07${path8.basename(abs)}:${block.start}\x1B]8;;\x07`;
|
|
4825
|
+
const label = ` ${ansi.yellow(`L${block.start}`)}\u2013${ansi.yellow(`L${block.end}`)} ${link}`;
|
|
4744
4826
|
console.info(label);
|
|
4745
4827
|
if (opts.showCode && src.length) {
|
|
4746
4828
|
const lines = src.split(/\r?\n/);
|
|
@@ -4760,7 +4842,7 @@ var printDetailedCoverage = async (opts) => {
|
|
|
4760
4842
|
abs,
|
|
4761
4843
|
fn.line,
|
|
4762
4844
|
opts.editorCmd
|
|
4763
|
-
)}\x07${
|
|
4845
|
+
)}\x07${path8.basename(abs)}:${fn.line}\x1B]8;;\x07`;
|
|
4764
4846
|
console.info(` - ${fn.name} @ ${link}`);
|
|
4765
4847
|
}
|
|
4766
4848
|
}
|
|
@@ -4771,12 +4853,8 @@ var printDetailedCoverage = async (opts) => {
|
|
|
4771
4853
|
abs,
|
|
4772
4854
|
br.line,
|
|
4773
4855
|
opts.editorCmd
|
|
4774
|
-
)}\x07${
|
|
4775
|
-
console.info(
|
|
4776
|
-
` - branch#${br.id} @ ${link} missed paths: [${br.zeroPaths.join(
|
|
4777
|
-
", "
|
|
4778
|
-
)}]`
|
|
4779
|
-
);
|
|
4856
|
+
)}\x07${path8.basename(abs)}:${br.line}\x1B]8;;\x07`;
|
|
4857
|
+
console.info(` - branch#${br.id} @ ${link} missed paths: [${br.zeroPaths.join(", ")}]`);
|
|
4780
4858
|
}
|
|
4781
4859
|
}
|
|
4782
4860
|
console.info("");
|
|
@@ -4796,7 +4874,7 @@ var printCompactCoverage = async (opts) => {
|
|
|
4796
4874
|
for (const abs of files.slice(0, fileCap)) {
|
|
4797
4875
|
const fc = opts.map.fileCoverageFor(abs);
|
|
4798
4876
|
const sum = fc.toSummary();
|
|
4799
|
-
const rel =
|
|
4877
|
+
const rel = path8.relative(opts.root, abs).replace(/\\/g, "/");
|
|
4800
4878
|
const compareRangesByLengthDescThenStart = (firstRange, secondRange) => {
|
|
4801
4879
|
const secondLength = secondRange.end - secondRange.start;
|
|
4802
4880
|
const firstLength = firstRange.end - firstRange.start;
|
|
@@ -4810,9 +4888,9 @@ var printCompactCoverage = async (opts) => {
|
|
|
4810
4888
|
const branchesPctText = `${sum.branches.pct.toFixed(1)}%`;
|
|
4811
4889
|
const header = `${ansi.bold(rel)} lines ${tintPct(sum.lines.pct)(
|
|
4812
4890
|
linesPctText
|
|
4813
|
-
)} ${barCell(compositeBarPct(sum, blocks))("".padEnd(14))} funcs ${tintPct(
|
|
4814
|
-
|
|
4815
|
-
)
|
|
4891
|
+
)} ${barCell(compositeBarPct(sum, blocks))("".padEnd(14))} funcs ${tintPct(sum.functions.pct)(
|
|
4892
|
+
funcsPctText
|
|
4893
|
+
)} branches ${tintPct(sum.branches.pct)(branchesPctText)}`;
|
|
4816
4894
|
console.info(header);
|
|
4817
4895
|
const hotspots = blocks.slice(0, maxHotspotsDerived);
|
|
4818
4896
|
if (hotspots.length) {
|
|
@@ -4823,10 +4901,8 @@ var printCompactCoverage = async (opts) => {
|
|
|
4823
4901
|
abs,
|
|
4824
4902
|
hotspot.start,
|
|
4825
4903
|
opts.editorCmd
|
|
4826
|
-
)}\x07${
|
|
4827
|
-
console.info(
|
|
4828
|
-
` - L${hotspot.start}\u2013L${hotspot.end} (${len} lines) ${link}`
|
|
4829
|
-
);
|
|
4904
|
+
)}\x07${path8.basename(abs)}:${hotspot.start}\x1B]8;;\x07`;
|
|
4905
|
+
console.info(` - L${hotspot.start}\u2013L${hotspot.end} (${len} lines) ${link}`);
|
|
4830
4906
|
}
|
|
4831
4907
|
}
|
|
4832
4908
|
const functionsList = missFns.slice(0, maxFunctionsDerived);
|
|
@@ -4838,7 +4914,7 @@ var printCompactCoverage = async (opts) => {
|
|
|
4838
4914
|
abs,
|
|
4839
4915
|
fn.line,
|
|
4840
4916
|
opts.editorCmd
|
|
4841
|
-
)}\x07${
|
|
4917
|
+
)}\x07${path8.basename(abs)}:${fn.line}\x1B]8;;\x07`
|
|
4842
4918
|
);
|
|
4843
4919
|
}
|
|
4844
4920
|
}
|
|
@@ -4853,7 +4929,7 @@ var printCompactCoverage = async (opts) => {
|
|
|
4853
4929
|
abs,
|
|
4854
4930
|
br.line,
|
|
4855
4931
|
opts.editorCmd
|
|
4856
|
-
)}\x07${
|
|
4932
|
+
)}\x07${path8.basename(abs)}:${br.line}\x1B]8;;\x07`
|
|
4857
4933
|
);
|
|
4858
4934
|
}
|
|
4859
4935
|
}
|
|
@@ -4862,9 +4938,7 @@ var printCompactCoverage = async (opts) => {
|
|
|
4862
4938
|
const restBrs = Math.max(0, misses.length - branchesList.length);
|
|
4863
4939
|
if (restHs + restFns + restBrs > 0) {
|
|
4864
4940
|
console.info(
|
|
4865
|
-
ansi.dim(
|
|
4866
|
-
` \u2026 truncated: +${restHs} hotspots, +${restFns} funcs, +${restBrs} branches`
|
|
4867
|
-
)
|
|
4941
|
+
ansi.dim(` \u2026 truncated: +${restHs} hotspots, +${restFns} funcs, +${restBrs} branches`)
|
|
4868
4942
|
);
|
|
4869
4943
|
}
|
|
4870
4944
|
console.info("");
|
|
@@ -4901,7 +4975,7 @@ var shortenPathPreservingFilename = (relPath, maxWidth, opts) => {
|
|
|
4901
4975
|
return { stem: base.slice(0, -ending.length), ext: ending };
|
|
4902
4976
|
}
|
|
4903
4977
|
}
|
|
4904
|
-
const ext2 =
|
|
4978
|
+
const ext2 = path8.extname(base);
|
|
4905
4979
|
return { stem: base.slice(0, -ext2.length), ext: ext2 };
|
|
4906
4980
|
};
|
|
4907
4981
|
const sliceBalanced = (input, width) => {
|
|
@@ -4984,12 +5058,7 @@ var shortenPathPreservingFilename = (relPath, maxWidth, opts) => {
|
|
|
4984
5058
|
const tailParts = tailSrc.map((segment) => segment);
|
|
4985
5059
|
let hidAny = false;
|
|
4986
5060
|
const build = () => {
|
|
4987
|
-
const label2 = joinParts(
|
|
4988
|
-
headParts,
|
|
4989
|
-
tailParts,
|
|
4990
|
-
hideMiddle2 || hidAny,
|
|
4991
|
-
baseLabel
|
|
4992
|
-
);
|
|
5061
|
+
const label2 = joinParts(headParts, tailParts, hideMiddle2 || hidAny, baseLabel);
|
|
4993
5062
|
return { label: label2, width: visibleWidth(label2) };
|
|
4994
5063
|
};
|
|
4995
5064
|
let { label, width } = build();
|
|
@@ -5082,13 +5151,7 @@ var shortenPathPreservingFilename = (relPath, maxWidth, opts) => {
|
|
|
5082
5151
|
return { headRaw: headRaw2, tailRaw: tailRaw2, hideMiddle: hideMiddle2 };
|
|
5083
5152
|
};
|
|
5084
5153
|
let { headRaw, tailRaw, hideMiddle } = buildRaw(headCount, tailCount);
|
|
5085
|
-
let candidate = tryTrimDirsToFit(
|
|
5086
|
-
headRaw,
|
|
5087
|
-
tailRaw,
|
|
5088
|
-
hideMiddle,
|
|
5089
|
-
baseFull,
|
|
5090
|
-
maxWidth
|
|
5091
|
-
);
|
|
5154
|
+
let candidate = tryTrimDirsToFit(headRaw, tailRaw, hideMiddle, baseFull, maxWidth);
|
|
5092
5155
|
if (!candidate) {
|
|
5093
5156
|
return baseFull;
|
|
5094
5157
|
}
|
|
@@ -5097,13 +5160,7 @@ var shortenPathPreservingFilename = (relPath, maxWidth, opts) => {
|
|
|
5097
5160
|
if (headCount + tailCount < total) {
|
|
5098
5161
|
const tryTail = Math.min(tailCount + 1, total - headCount);
|
|
5099
5162
|
({ headRaw, tailRaw, hideMiddle } = buildRaw(headCount, tryTail));
|
|
5100
|
-
const candTail = tryTrimDirsToFit(
|
|
5101
|
-
headRaw,
|
|
5102
|
-
tailRaw,
|
|
5103
|
-
hideMiddle,
|
|
5104
|
-
baseFull,
|
|
5105
|
-
maxWidth
|
|
5106
|
-
);
|
|
5163
|
+
const candTail = tryTrimDirsToFit(headRaw, tailRaw, hideMiddle, baseFull, maxWidth);
|
|
5107
5164
|
if (candTail) {
|
|
5108
5165
|
tailCount = tryTail;
|
|
5109
5166
|
candidate = candTail;
|
|
@@ -5113,13 +5170,7 @@ var shortenPathPreservingFilename = (relPath, maxWidth, opts) => {
|
|
|
5113
5170
|
if (!advanced && headCount + tailCount < total) {
|
|
5114
5171
|
const tryHead = Math.min(headCount + 1, total - tailCount);
|
|
5115
5172
|
({ headRaw, tailRaw, hideMiddle } = buildRaw(tryHead, tailCount));
|
|
5116
|
-
const candHead = tryTrimDirsToFit(
|
|
5117
|
-
headRaw,
|
|
5118
|
-
tailRaw,
|
|
5119
|
-
hideMiddle,
|
|
5120
|
-
baseFull,
|
|
5121
|
-
maxWidth
|
|
5122
|
-
);
|
|
5173
|
+
const candHead = tryTrimDirsToFit(headRaw, tailRaw, hideMiddle, baseFull, maxWidth);
|
|
5123
5174
|
if (candHead) {
|
|
5124
5175
|
headCount = tryHead;
|
|
5125
5176
|
candidate = candHead;
|
|
@@ -5181,7 +5232,7 @@ var buildDistanceMapFromTests = async (executedTestsAbs, rootDir) => {
|
|
|
5181
5232
|
const queue = [];
|
|
5182
5233
|
const seen = /* @__PURE__ */ new Set();
|
|
5183
5234
|
for (const testAbs of executedTestsAbs) {
|
|
5184
|
-
const testPathNormalized =
|
|
5235
|
+
const testPathNormalized = path8.resolve(testAbs).replace(/\\/g, "/");
|
|
5185
5236
|
dist.set(testPathNormalized, 0);
|
|
5186
5237
|
queue.push([testPathNormalized, 0]);
|
|
5187
5238
|
}
|
|
@@ -5200,12 +5251,7 @@ var buildDistanceMapFromTests = async (executedTestsAbs, rootDir) => {
|
|
|
5200
5251
|
const specs = await extractImportSpecs2(currentFile, specsCache);
|
|
5201
5252
|
const nextDistance = currentDistance + 1;
|
|
5202
5253
|
for (const spec of specs) {
|
|
5203
|
-
const resolved = resolveImportWithRoot(
|
|
5204
|
-
currentFile,
|
|
5205
|
-
spec,
|
|
5206
|
-
rootDir,
|
|
5207
|
-
resolutionCache
|
|
5208
|
-
);
|
|
5254
|
+
const resolved = resolveImportWithRoot(currentFile, spec, rootDir, resolutionCache);
|
|
5209
5255
|
const usable = resolved && !resolved.includes("/node_modules/");
|
|
5210
5256
|
if (usable) {
|
|
5211
5257
|
const existing = dist.get(resolved);
|
|
@@ -5220,13 +5266,10 @@ var buildDistanceMapFromTests = async (executedTestsAbs, rootDir) => {
|
|
|
5220
5266
|
return dist;
|
|
5221
5267
|
};
|
|
5222
5268
|
var renderPerFileCompositeTable = async (opts) => {
|
|
5223
|
-
const rel =
|
|
5269
|
+
const rel = path8.relative(opts.root, opts.absPath).replace(/\\/g, "/");
|
|
5224
5270
|
const sum = opts.file.toSummary();
|
|
5225
5271
|
const rowsAvail = typeof process.stdout.rows === "number" && process.stdout.rows > 10 ? process.stdout.rows : 40;
|
|
5226
|
-
const tableBudget = Math.max(
|
|
5227
|
-
14,
|
|
5228
|
-
Math.min(opts.maxRows ?? rowsAvail - 1, rowsAvail + 8)
|
|
5229
|
-
);
|
|
5272
|
+
const tableBudget = Math.max(14, Math.min(opts.maxRows ?? rowsAvail - 1, rowsAvail + 8));
|
|
5230
5273
|
const rowBudget = Math.max(6, tableBudget - 6);
|
|
5231
5274
|
const blocks = computeUncoveredBlocks(opts.file).slice().sort((firstRange, secondRange) => {
|
|
5232
5275
|
const firstLength = firstRange.end - firstRange.start;
|
|
@@ -5270,9 +5313,7 @@ var renderPerFileCompositeTable = async (opts) => {
|
|
|
5270
5313
|
rows.push([
|
|
5271
5314
|
cell(
|
|
5272
5315
|
rel,
|
|
5273
|
-
(padded) => ansi.dim(
|
|
5274
|
-
shortenPathPreservingFilename(rel, padded.length).padEnd(padded.length)
|
|
5275
|
-
)
|
|
5316
|
+
(padded) => ansi.dim(shortenPathPreservingFilename(rel, padded.length).padEnd(padded.length))
|
|
5276
5317
|
),
|
|
5277
5318
|
cell("Totals", ansi.dim),
|
|
5278
5319
|
cell("\u2014", ansi.dim),
|
|
@@ -5291,11 +5332,7 @@ var renderPerFileCompositeTable = async (opts) => {
|
|
|
5291
5332
|
rows.push([
|
|
5292
5333
|
cell(
|
|
5293
5334
|
rel,
|
|
5294
|
-
(padded) => ansi.dim(
|
|
5295
|
-
shortenPathPreservingFilename(rel, padded.length).padEnd(
|
|
5296
|
-
padded.length
|
|
5297
|
-
)
|
|
5298
|
-
)
|
|
5335
|
+
(padded) => ansi.dim(shortenPathPreservingFilename(rel, padded.length).padEnd(padded.length))
|
|
5299
5336
|
),
|
|
5300
5337
|
cell("Hotspots", ansi.dim),
|
|
5301
5338
|
cell("", ansi.dim),
|
|
@@ -5309,14 +5346,8 @@ var renderPerFileCompositeTable = async (opts) => {
|
|
|
5309
5346
|
rows.push([
|
|
5310
5347
|
cell(rel, (padded) => {
|
|
5311
5348
|
const width = padded.length;
|
|
5312
|
-
const display = shortenPathPreservingFilename(rel, width).padEnd(
|
|
5313
|
-
|
|
5314
|
-
);
|
|
5315
|
-
return linkifyPadded(
|
|
5316
|
-
opts.absPath,
|
|
5317
|
-
hotspotRange.start,
|
|
5318
|
-
opts.editorCmd
|
|
5319
|
-
)(display);
|
|
5349
|
+
const display = shortenPathPreservingFilename(rel, width).padEnd(width);
|
|
5350
|
+
return linkifyPadded(opts.absPath, hotspotRange.start, opts.editorCmd)(display);
|
|
5320
5351
|
}),
|
|
5321
5352
|
cell("Hotspot"),
|
|
5322
5353
|
cell(`L${hotspotRange.start}\u2013L${hotspotRange.end}`),
|
|
@@ -5333,11 +5364,7 @@ var renderPerFileCompositeTable = async (opts) => {
|
|
|
5333
5364
|
rows.push([
|
|
5334
5365
|
cell(
|
|
5335
5366
|
rel,
|
|
5336
|
-
(padded) => ansi.dim(
|
|
5337
|
-
shortenPathPreservingFilename(rel, padded.length).padEnd(
|
|
5338
|
-
padded.length
|
|
5339
|
-
)
|
|
5340
|
-
)
|
|
5367
|
+
(padded) => ansi.dim(shortenPathPreservingFilename(rel, padded.length).padEnd(padded.length))
|
|
5341
5368
|
),
|
|
5342
5369
|
cell("Functions", ansi.dim),
|
|
5343
5370
|
cell("", ansi.dim),
|
|
@@ -5351,14 +5378,8 @@ var renderPerFileCompositeTable = async (opts) => {
|
|
|
5351
5378
|
rows.push([
|
|
5352
5379
|
cell(rel, (padded) => {
|
|
5353
5380
|
const width = padded.length;
|
|
5354
|
-
const display = shortenPathPreservingFilename(rel, width).padEnd(
|
|
5355
|
-
|
|
5356
|
-
);
|
|
5357
|
-
return linkifyPadded(
|
|
5358
|
-
opts.absPath,
|
|
5359
|
-
missedFunction.line,
|
|
5360
|
-
opts.editorCmd
|
|
5361
|
-
)(display);
|
|
5381
|
+
const display = shortenPathPreservingFilename(rel, width).padEnd(width);
|
|
5382
|
+
return linkifyPadded(opts.absPath, missedFunction.line, opts.editorCmd)(display);
|
|
5362
5383
|
}),
|
|
5363
5384
|
cell("Func"),
|
|
5364
5385
|
cell(`L${missedFunction.line}`),
|
|
@@ -5375,11 +5396,7 @@ var renderPerFileCompositeTable = async (opts) => {
|
|
|
5375
5396
|
rows.push([
|
|
5376
5397
|
cell(
|
|
5377
5398
|
rel,
|
|
5378
|
-
(padded) => ansi.dim(
|
|
5379
|
-
shortenPathPreservingFilename(rel, padded.length).padEnd(
|
|
5380
|
-
padded.length
|
|
5381
|
-
)
|
|
5382
|
-
)
|
|
5399
|
+
(padded) => ansi.dim(shortenPathPreservingFilename(rel, padded.length).padEnd(padded.length))
|
|
5383
5400
|
),
|
|
5384
5401
|
cell("Branches", ansi.dim),
|
|
5385
5402
|
cell("", ansi.dim),
|
|
@@ -5393,14 +5410,8 @@ var renderPerFileCompositeTable = async (opts) => {
|
|
|
5393
5410
|
rows.push([
|
|
5394
5411
|
cell(rel, (padded) => {
|
|
5395
5412
|
const width = padded.length;
|
|
5396
|
-
const display = shortenPathPreservingFilename(rel, width).padEnd(
|
|
5397
|
-
|
|
5398
|
-
);
|
|
5399
|
-
return linkifyPadded(
|
|
5400
|
-
opts.absPath,
|
|
5401
|
-
missedBranch.line,
|
|
5402
|
-
opts.editorCmd
|
|
5403
|
-
)(display);
|
|
5413
|
+
const display = shortenPathPreservingFilename(rel, width).padEnd(width);
|
|
5414
|
+
return linkifyPadded(opts.absPath, missedBranch.line, opts.editorCmd)(display);
|
|
5404
5415
|
}),
|
|
5405
5416
|
cell("Branch"),
|
|
5406
5417
|
cell(`L${missedBranch.line}`),
|
|
@@ -5408,9 +5419,7 @@ var renderPerFileCompositeTable = async (opts) => {
|
|
|
5408
5419
|
cell(""),
|
|
5409
5420
|
cell(""),
|
|
5410
5421
|
cell(""),
|
|
5411
|
-
cell(
|
|
5412
|
-
`#${missedBranch.id} missed [${missedBranch.zeroPaths.join(", ")}]`
|
|
5413
|
-
)
|
|
5422
|
+
cell(`#${missedBranch.id} missed [${missedBranch.zeroPaths.join(", ")}]`)
|
|
5414
5423
|
]);
|
|
5415
5424
|
}
|
|
5416
5425
|
}
|
|
@@ -5430,9 +5439,7 @@ var renderPerFileCompositeTable = async (opts) => {
|
|
|
5430
5439
|
rows.push([
|
|
5431
5440
|
cell(rel, (padded) => {
|
|
5432
5441
|
const width = padded.length;
|
|
5433
|
-
const display = shortenPathPreservingFilename(rel, width).padEnd(
|
|
5434
|
-
width
|
|
5435
|
-
);
|
|
5442
|
+
const display = shortenPathPreservingFilename(rel, width).padEnd(width);
|
|
5436
5443
|
return linkifyPadded(opts.absPath, ln, opts.editorCmd)(display);
|
|
5437
5444
|
}),
|
|
5438
5445
|
cell("Line"),
|
|
@@ -5445,16 +5452,7 @@ var renderPerFileCompositeTable = async (opts) => {
|
|
|
5445
5452
|
]);
|
|
5446
5453
|
}
|
|
5447
5454
|
while (rows.length < target) {
|
|
5448
|
-
rows.push([
|
|
5449
|
-
cell(""),
|
|
5450
|
-
cell(""),
|
|
5451
|
-
cell(""),
|
|
5452
|
-
cell(""),
|
|
5453
|
-
cell(""),
|
|
5454
|
-
cell(""),
|
|
5455
|
-
cell(""),
|
|
5456
|
-
cell("")
|
|
5457
|
-
]);
|
|
5455
|
+
rows.push([cell(""), cell(""), cell(""), cell(""), cell(""), cell(""), cell(""), cell("")]);
|
|
5458
5456
|
}
|
|
5459
5457
|
}
|
|
5460
5458
|
}
|
|
@@ -5462,20 +5460,17 @@ var renderPerFileCompositeTable = async (opts) => {
|
|
|
5462
5460
|
console.info(table);
|
|
5463
5461
|
const sep = ansi.gray(
|
|
5464
5462
|
"\u2500".repeat(
|
|
5465
|
-
Math.max(
|
|
5466
|
-
20,
|
|
5467
|
-
typeof process.stdout.columns === "number" ? process.stdout.columns : 100
|
|
5468
|
-
)
|
|
5463
|
+
Math.max(20, typeof process.stdout.columns === "number" ? process.stdout.columns : 100)
|
|
5469
5464
|
)
|
|
5470
5465
|
);
|
|
5471
5466
|
console.info(sep);
|
|
5472
5467
|
};
|
|
5473
5468
|
var printPerFileCompositeTables = async (opts) => {
|
|
5474
5469
|
const selectionAbs = (opts.selectionPaths ?? []).map(
|
|
5475
|
-
(selPath) =>
|
|
5470
|
+
(selPath) => path8.resolve(selPath).replace(/\\/g, "/")
|
|
5476
5471
|
);
|
|
5477
5472
|
const changedAbs = (opts.changedFiles ?? []).map(
|
|
5478
|
-
(chgPath) =>
|
|
5473
|
+
(chgPath) => path8.resolve(chgPath).replace(/\\/g, "/")
|
|
5479
5474
|
);
|
|
5480
5475
|
const tokenizeForSimilarity = (filePathForTokens) => new Set(
|
|
5481
5476
|
filePathForTokens.toLowerCase().replace(/[^a-z0-9/_\-.]/g, " ").split(/[/_.-]+/).filter(Boolean)
|
|
@@ -5491,15 +5486,15 @@ var printPerFileCompositeTables = async (opts) => {
|
|
|
5491
5486
|
return intersectionCount / unionSize;
|
|
5492
5487
|
};
|
|
5493
5488
|
const isSameDirOrChild = (firstAbs, secondAbs) => {
|
|
5494
|
-
const dirA =
|
|
5495
|
-
const dirB =
|
|
5489
|
+
const dirA = path8.dirname(firstAbs).replace(/\\/g, "/");
|
|
5490
|
+
const dirB = path8.dirname(secondAbs).replace(/\\/g, "/");
|
|
5496
5491
|
return dirA === dirB || dirB.startsWith(`${dirA}/`) || dirA.startsWith(`${dirB}/`);
|
|
5497
5492
|
};
|
|
5498
5493
|
const selectionTokens = selectionAbs.map(tokenizeForSimilarity);
|
|
5499
5494
|
const changedTokens = changedAbs.map(tokenizeForSimilarity);
|
|
5500
|
-
const executedTestsAbs = (opts.executedTests ?? []).map((testPath) =>
|
|
5495
|
+
const executedTestsAbs = (opts.executedTests ?? []).map((testPath) => path8.resolve(testPath).replace(/\\/g, "/")).filter((absPath) => absPath.length > 0);
|
|
5501
5496
|
const testTokens = executedTestsAbs.map(tokenizeForSimilarity);
|
|
5502
|
-
const allMapFilesAbs = opts.map.files().map((absPath) =>
|
|
5497
|
+
const allMapFilesAbs = opts.map.files().map((absPath) => path8.resolve(absPath).replace(/\\/g, "/"));
|
|
5503
5498
|
const uncoveredCandidates = allMapFilesAbs.filter((absPath) => {
|
|
5504
5499
|
const sum = opts.map.fileCoverageFor(absPath).toSummary();
|
|
5505
5500
|
return !(sum.lines.pct >= 100 && sum.functions.pct >= 100 && sum.branches.pct >= 100);
|
|
@@ -5516,33 +5511,24 @@ var printPerFileCompositeTables = async (opts) => {
|
|
|
5516
5511
|
const selectionSetAbs = new Set(selectionAbs);
|
|
5517
5512
|
const scored = await Promise.all(
|
|
5518
5513
|
candidates.map(async (abs) => {
|
|
5519
|
-
const rel =
|
|
5514
|
+
const rel = path8.relative(opts.root, abs).replace(/\\/g, "/");
|
|
5520
5515
|
const sum = opts.map.fileCoverageFor(abs).toSummary();
|
|
5521
5516
|
const pct = Number.isFinite(sum.lines.pct) ? sum.lines.pct : 0;
|
|
5522
|
-
const absNorm =
|
|
5517
|
+
const absNorm = path8.resolve(abs).replace(/\\/g, "/");
|
|
5523
5518
|
const selfTokens = tokenizeForSimilarity(absNorm);
|
|
5524
5519
|
const selSim = Math.max(
|
|
5525
5520
|
0,
|
|
5526
|
-
...selectionTokens.map(
|
|
5527
|
-
(selectionTokenSet) => jaccard(selfTokens, selectionTokenSet)
|
|
5528
|
-
)
|
|
5521
|
+
...selectionTokens.map((selectionTokenSet) => jaccard(selfTokens, selectionTokenSet))
|
|
5529
5522
|
);
|
|
5530
5523
|
const chgSim = Math.max(
|
|
5531
5524
|
0,
|
|
5532
|
-
...changedTokens.map(
|
|
5533
|
-
(changedTokenSet) => jaccard(selfTokens, changedTokenSet)
|
|
5534
|
-
)
|
|
5535
|
-
);
|
|
5536
|
-
const tstSim = Math.max(
|
|
5537
|
-
0,
|
|
5538
|
-
...testTokens.map((tset) => jaccard(selfTokens, tset))
|
|
5525
|
+
...changedTokens.map((changedTokenSet) => jaccard(selfTokens, changedTokenSet))
|
|
5539
5526
|
);
|
|
5527
|
+
const tstSim = Math.max(0, ...testTokens.map((tset) => jaccard(selfTokens, tset)));
|
|
5540
5528
|
const nearSelection = selectionAbs.some(
|
|
5541
5529
|
(selectionPath) => isSameDirOrChild(absNorm, selectionPath)
|
|
5542
5530
|
);
|
|
5543
|
-
const nearChanged = changedAbs.some(
|
|
5544
|
-
(changedPath) => isSameDirOrChild(absNorm, changedPath)
|
|
5545
|
-
);
|
|
5531
|
+
const nearChanged = changedAbs.some((changedPath) => isSameDirOrChild(absNorm, changedPath));
|
|
5546
5532
|
const related = selSim > 0 || chgSim > 0 || nearSelection || nearChanged;
|
|
5547
5533
|
const distance = selectionSetAbs.has(absNorm) ? 0 : distFromTests.get(absNorm) ?? INF;
|
|
5548
5534
|
let group = 6;
|
|
@@ -5566,9 +5552,12 @@ var printPerFileCompositeTables = async (opts) => {
|
|
|
5566
5552
|
return { abs: absNorm, rel, linesPct: pct, group, score, distance };
|
|
5567
5553
|
})
|
|
5568
5554
|
);
|
|
5569
|
-
|
|
5570
|
-
|
|
5571
|
-
|
|
5555
|
+
const prodSeeds = selectionAbs.length > 0 ? selectionAbs : changedAbs;
|
|
5556
|
+
const rank = await computeDirectnessRank({ repoRoot: opts.root, productionSeeds: prodSeeds });
|
|
5557
|
+
let files = sortPathsWithRank(
|
|
5558
|
+
rank,
|
|
5559
|
+
scored.map((s) => s.abs)
|
|
5560
|
+
);
|
|
5572
5561
|
if (selectionAbs.length > 0) {
|
|
5573
5562
|
const selectionSet = new Set(selectionAbs);
|
|
5574
5563
|
const selectedHead = files.filter((filePath) => selectionSet.has(filePath));
|
|
@@ -5592,7 +5581,7 @@ var printPerFileCompositeTables = async (opts) => {
|
|
|
5592
5581
|
|
|
5593
5582
|
// src/lib/jest-bridge.ts
|
|
5594
5583
|
var import_json5 = __toESM(require_lib(), 1);
|
|
5595
|
-
import * as
|
|
5584
|
+
import * as path9 from "node:path";
|
|
5596
5585
|
import * as fs4 from "node:fs";
|
|
5597
5586
|
import * as util from "node:util";
|
|
5598
5587
|
var extractBridgePath = (raw, cwd) => {
|
|
@@ -5603,7 +5592,7 @@ var extractBridgePath = (raw, cwd) => {
|
|
|
5603
5592
|
return null;
|
|
5604
5593
|
}
|
|
5605
5594
|
const jsonPath = matches[matches.length - 1][1].trim().replace(/^["'`]|["'`]$/g, "");
|
|
5606
|
-
return
|
|
5595
|
+
return path9.isAbsolute(jsonPath) ? jsonPath : path9.resolve(cwd, jsonPath);
|
|
5607
5596
|
};
|
|
5608
5597
|
var drawRule = (label) => {
|
|
5609
5598
|
const width = Math.max(
|
|
@@ -6251,7 +6240,7 @@ var buildStackSection = (mergedForStack, ctx, fallbackLoc) => {
|
|
|
6251
6240
|
const loc = deepestProjectLoc(mergedForStack, ctx.projectHint);
|
|
6252
6241
|
if (loc) {
|
|
6253
6242
|
const href = preferredEditorHref(loc.file, loc.line, ctx.editorCmd);
|
|
6254
|
-
out.push(` ${ansi.dim("at")} ${osc8(`${
|
|
6243
|
+
out.push(` ${ansi.dim("at")} ${osc8(`${path9.basename(loc.file)}:${loc.line}`, href)}`);
|
|
6255
6244
|
}
|
|
6256
6245
|
out.push("");
|
|
6257
6246
|
return out;
|
|
@@ -6530,7 +6519,7 @@ function renderVitestFromJestJSON(data, opts) {
|
|
|
6530
6519
|
const deepestLoc = deepestProjectLoc(mergedForStack, projectHint);
|
|
6531
6520
|
const locLink = deepestLoc && (() => {
|
|
6532
6521
|
const href = preferredEditorHref(deepestLoc.file, deepestLoc.line, opts?.editorCmd);
|
|
6533
|
-
const base = `${
|
|
6522
|
+
const base = `${path9.basename(deepestLoc.file)}:${deepestLoc.line}`;
|
|
6534
6523
|
return osc8(base, href);
|
|
6535
6524
|
})();
|
|
6536
6525
|
const headerLine = `${ansi.white(header)}${locLink ? ` ${ansi.dim(`(${locLink})`)}` : ""}`;
|
|
@@ -6578,20 +6567,15 @@ ${footer}`;
|
|
|
6578
6567
|
init_env_utils();
|
|
6579
6568
|
init_exec();
|
|
6580
6569
|
init_args();
|
|
6581
|
-
import * as
|
|
6570
|
+
import * as path10 from "node:path";
|
|
6582
6571
|
import * as os2 from "node:os";
|
|
6583
6572
|
import * as fsSync3 from "node:fs";
|
|
6584
|
-
import { createCoverageMap as createCoverageMap2 } from "istanbul-lib-coverage";
|
|
6585
6573
|
import * as fs5 from "node:fs/promises";
|
|
6586
6574
|
import * as LibReport from "istanbul-lib-report";
|
|
6587
|
-
import
|
|
6588
|
-
import
|
|
6575
|
+
import * as Reports from "istanbul-reports";
|
|
6576
|
+
import { createCoverageMap as createCoverageMap2 } from "istanbul-lib-coverage";
|
|
6589
6577
|
var jestBin = "./node_modules/.bin/jest";
|
|
6590
6578
|
var babelNodeBin = "./node_modules/.bin/babel-node";
|
|
6591
|
-
var moduleSpecifierForRequire = (
|
|
6592
|
-
// @ts-ignore
|
|
6593
|
-
typeof __filename !== "undefined" ? __filename : import.meta.url
|
|
6594
|
-
);
|
|
6595
6579
|
var registerSignalHandlersOnce = () => {
|
|
6596
6580
|
let handled = false;
|
|
6597
6581
|
const on = (sig) => {
|
|
@@ -6609,7 +6593,6 @@ Received ${sig}, exiting...
|
|
|
6609
6593
|
};
|
|
6610
6594
|
var isDebug = () => Boolean(process.env.TEST_CLI_DEBUG);
|
|
6611
6595
|
var mergeLcov = async () => {
|
|
6612
|
-
const jestLcovPath = "coverage/jest/lcov.info";
|
|
6613
6596
|
const vitestLcovPath = "coverage/vitest/lcov.info";
|
|
6614
6597
|
const mergedOutPath = "coverage/lcov.info";
|
|
6615
6598
|
const readOrEmpty = async (filePath) => {
|
|
@@ -6620,7 +6603,7 @@ var mergeLcov = async () => {
|
|
|
6620
6603
|
}
|
|
6621
6604
|
};
|
|
6622
6605
|
let vitestContent = "";
|
|
6623
|
-
|
|
6606
|
+
const jestParts = [];
|
|
6624
6607
|
try {
|
|
6625
6608
|
vitestContent = await readOrEmpty(vitestLcovPath);
|
|
6626
6609
|
} catch (readVitestError) {
|
|
@@ -6628,20 +6611,46 @@ var mergeLcov = async () => {
|
|
|
6628
6611
|
console.info(`read vitest lcov failed: ${String(readVitestError)}`);
|
|
6629
6612
|
}
|
|
6630
6613
|
}
|
|
6614
|
+
const collectLcovs = (dir) => {
|
|
6615
|
+
const out = [];
|
|
6616
|
+
try {
|
|
6617
|
+
const entries = fsSync3.readdirSync(dir, { withFileTypes: true });
|
|
6618
|
+
for (const entry of entries) {
|
|
6619
|
+
const full = path10.join(dir, entry.name);
|
|
6620
|
+
if (entry.isDirectory()) {
|
|
6621
|
+
out.push(...collectLcovs(full));
|
|
6622
|
+
} else if (entry.isFile() && entry.name === "lcov.info") {
|
|
6623
|
+
out.push(full);
|
|
6624
|
+
}
|
|
6625
|
+
}
|
|
6626
|
+
} catch {
|
|
6627
|
+
}
|
|
6628
|
+
return out;
|
|
6629
|
+
};
|
|
6631
6630
|
try {
|
|
6632
|
-
|
|
6631
|
+
const jestRoot = path10.join("coverage", "jest");
|
|
6632
|
+
const candidates = [path10.join(jestRoot, "lcov.info"), ...collectLcovs(jestRoot)].map((candidatePath) => path10.resolve(candidatePath)).filter((absolutePath, index, arr) => arr.indexOf(absolutePath) === index);
|
|
6633
|
+
for (const filePath of candidates) {
|
|
6634
|
+
try {
|
|
6635
|
+
const content = await readOrEmpty(filePath);
|
|
6636
|
+
if (content.trim()) {
|
|
6637
|
+
jestParts.push(content.trim());
|
|
6638
|
+
}
|
|
6639
|
+
} catch {
|
|
6640
|
+
}
|
|
6641
|
+
}
|
|
6633
6642
|
} catch (readJestError) {
|
|
6634
6643
|
if (isDebug()) {
|
|
6635
|
-
console.info(`
|
|
6644
|
+
console.info(`scan jest lcov failed: ${String(readJestError)}`);
|
|
6636
6645
|
}
|
|
6637
6646
|
}
|
|
6638
|
-
if (!vitestContent &&
|
|
6647
|
+
if (!vitestContent && jestParts.length === 0) {
|
|
6639
6648
|
if (isDebug()) {
|
|
6640
6649
|
console.info("No coverage outputs found to merge.");
|
|
6641
6650
|
}
|
|
6642
6651
|
return;
|
|
6643
6652
|
}
|
|
6644
|
-
const merged = [vitestContent.trim(),
|
|
6653
|
+
const merged = [vitestContent.trim(), ...jestParts].filter(Boolean).join("\n");
|
|
6645
6654
|
if (merged.length > 0) {
|
|
6646
6655
|
await (await import("node:fs/promises")).mkdir("coverage", { recursive: true });
|
|
6647
6656
|
await (await import("node:fs/promises")).writeFile(mergedOutPath, `${merged}
|
|
@@ -6654,23 +6663,40 @@ var mergeLcov = async () => {
|
|
|
6654
6663
|
}
|
|
6655
6664
|
};
|
|
6656
6665
|
var emitMergedCoverage = async (ui, opts) => {
|
|
6657
|
-
const jestJson = path9.join("coverage", "jest", "coverage-final.json");
|
|
6658
|
-
const jSize = fsSync3.existsSync(jestJson) ? fsSync3.statSync(jestJson).size : -1;
|
|
6659
|
-
const jestSizeLabel = jSize >= 0 ? `${jSize} bytes` : "missing";
|
|
6660
|
-
if (isDebug()) {
|
|
6661
|
-
console.info(`Coverage JSON probe \u2192 jest: ${jestSizeLabel}`);
|
|
6662
|
-
}
|
|
6663
|
-
const jestData = await readCoverageJson(jestJson);
|
|
6664
|
-
const jestFilesCount = Object.keys(jestData).length;
|
|
6665
|
-
if (isDebug()) {
|
|
6666
|
-
console.info(`Decoded coverage entries \u2192 jest: ${jestFilesCount}`);
|
|
6667
|
-
}
|
|
6668
6666
|
const map = createCoverageMap2({});
|
|
6669
|
-
|
|
6667
|
+
const listJsons = (dir) => {
|
|
6668
|
+
const out = [];
|
|
6670
6669
|
try {
|
|
6671
|
-
|
|
6670
|
+
const entries = fsSync3.readdirSync(dir, { withFileTypes: true });
|
|
6671
|
+
for (const entry of entries) {
|
|
6672
|
+
const full = path10.join(dir, entry.name);
|
|
6673
|
+
if (entry.isDirectory()) {
|
|
6674
|
+
out.push(...listJsons(full));
|
|
6675
|
+
} else if (entry.isFile() && entry.name === "coverage-final.json") {
|
|
6676
|
+
out.push(full);
|
|
6677
|
+
}
|
|
6678
|
+
}
|
|
6679
|
+
} catch {
|
|
6680
|
+
}
|
|
6681
|
+
return out;
|
|
6682
|
+
};
|
|
6683
|
+
const coverageRoot = path10.join("coverage", "jest");
|
|
6684
|
+
const jsonCandidates = [
|
|
6685
|
+
path10.join(coverageRoot, "coverage-final.json"),
|
|
6686
|
+
...listJsons(coverageRoot)
|
|
6687
|
+
].map((candidatePath) => path10.resolve(candidatePath)).filter((absolutePath, index, arr) => {
|
|
6688
|
+
const isFirst = arr.indexOf(absolutePath) === index;
|
|
6689
|
+
const exists = fsSync3.existsSync(absolutePath);
|
|
6690
|
+
return isFirst && exists;
|
|
6691
|
+
});
|
|
6692
|
+
for (const jsonPath of jsonCandidates) {
|
|
6693
|
+
try {
|
|
6694
|
+
const data = await readCoverageJson(jsonPath);
|
|
6695
|
+
if (Object.keys(data).length) {
|
|
6696
|
+
map.merge(data);
|
|
6697
|
+
}
|
|
6672
6698
|
} catch (mergeJestError) {
|
|
6673
|
-
console.warn(`Failed merging jest coverage JSON: ${String(mergeJestError)}`);
|
|
6699
|
+
console.warn(`Failed merging jest coverage JSON @ ${jsonPath}: ${String(mergeJestError)}`);
|
|
6674
6700
|
}
|
|
6675
6701
|
}
|
|
6676
6702
|
if (map.files().length === 0) {
|
|
@@ -6720,11 +6746,14 @@ var emitMergedCoverage = async (ui, opts) => {
|
|
|
6720
6746
|
executedTests: opts.executedTests ?? []
|
|
6721
6747
|
});
|
|
6722
6748
|
const context = LibReport.createContext({
|
|
6723
|
-
dir:
|
|
6749
|
+
dir: path10.resolve("coverage", "merged"),
|
|
6724
6750
|
coverageMap: filteredMap,
|
|
6725
6751
|
defaultSummarizer: "nested"
|
|
6726
6752
|
});
|
|
6727
|
-
const reporters = ui === "jest" ? [
|
|
6753
|
+
const reporters = ui === "jest" ? [Reports.create("text", { file: "coverage.txt" })] : [
|
|
6754
|
+
Reports.create("text", { file: "coverage.txt" }),
|
|
6755
|
+
Reports.create("text-summary", { file: "coverage-summary.txt" })
|
|
6756
|
+
];
|
|
6728
6757
|
const colorizeIstanbulLine = (lineText) => {
|
|
6729
6758
|
const separator = /^[-=\s]+$/;
|
|
6730
6759
|
if (separator.test(lineText.trim())) {
|
|
@@ -6785,8 +6814,8 @@ var emitMergedCoverage = async (ui, opts) => {
|
|
|
6785
6814
|
for (const reporter of reporters) {
|
|
6786
6815
|
reporter.execute(context);
|
|
6787
6816
|
}
|
|
6788
|
-
const textPath =
|
|
6789
|
-
const summaryPath =
|
|
6817
|
+
const textPath = path10.resolve("coverage", "merged", "coverage.txt");
|
|
6818
|
+
const summaryPath = path10.resolve("coverage", "merged", "coverage-summary.txt");
|
|
6790
6819
|
const filesToPrint = [];
|
|
6791
6820
|
if (fsSync3.existsSync(textPath)) {
|
|
6792
6821
|
filesToPrint.push(textPath);
|
|
@@ -6811,7 +6840,7 @@ var emitMergedCoverage = async (ui, opts) => {
|
|
|
6811
6840
|
}
|
|
6812
6841
|
}
|
|
6813
6842
|
} else {
|
|
6814
|
-
const stdoutReporters = ui === "jest" ? [
|
|
6843
|
+
const stdoutReporters = ui === "jest" ? [Reports.create("text", {})] : [Reports.create("text", {}), Reports.create("text-summary", {})];
|
|
6815
6844
|
for (const reporter of stdoutReporters) {
|
|
6816
6845
|
reporter.execute(context);
|
|
6817
6846
|
}
|
|
@@ -6868,17 +6897,43 @@ var program = async () => {
|
|
|
6868
6897
|
coverageMode,
|
|
6869
6898
|
coverageMaxFiles: coverageMaxFilesArg,
|
|
6870
6899
|
coverageMaxHotspots: coverageMaxHotspotsArg,
|
|
6871
|
-
coveragePageFit
|
|
6900
|
+
coveragePageFit,
|
|
6901
|
+
changed
|
|
6872
6902
|
} = deriveArgs(argv);
|
|
6873
|
-
|
|
6903
|
+
const getChangedFiles = async (mode, cwd) => {
|
|
6904
|
+
const collect = async (cmd, args) => {
|
|
6905
|
+
try {
|
|
6906
|
+
const out = await runText(cmd, args, {
|
|
6907
|
+
cwd,
|
|
6908
|
+
env: safeEnv(process.env, {}),
|
|
6909
|
+
timeoutMs: 4e3
|
|
6910
|
+
});
|
|
6911
|
+
return out.split(/\r?\n/).map((line) => line.trim()).filter(Boolean);
|
|
6912
|
+
} catch {
|
|
6913
|
+
return [];
|
|
6914
|
+
}
|
|
6915
|
+
};
|
|
6916
|
+
const staged = mode === "staged" || mode === "all" ? await collect("git", ["diff", "--name-only", "--diff-filter=ACMRTUXB", "--cached"]) : [];
|
|
6917
|
+
const unstagedTracked = mode === "unstaged" || mode === "all" ? await collect("git", ["diff", "--name-only", "--diff-filter=ACMRTUXB"]) : [];
|
|
6918
|
+
const untracked = mode === "unstaged" || mode === "all" ? await collect("git", ["ls-files", "--others", "--exclude-standard"]) : [];
|
|
6919
|
+
const rels = Array.from(/* @__PURE__ */ new Set([...staged, ...unstagedTracked, ...untracked]));
|
|
6920
|
+
return rels.map((rel) => path10.resolve(cwd, rel).replace(/\\/g, "/")).filter((abs) => !abs.includes("/node_modules/") && !abs.includes("/coverage/"));
|
|
6921
|
+
};
|
|
6922
|
+
const repoRootForChanged = workspaceRoot ?? await findRepoRoot();
|
|
6923
|
+
const changedSelectionAbs = changed ? await getChangedFiles(changed, repoRootForChanged) : [];
|
|
6924
|
+
const selectionPathsAugmented = changedSelectionAbs.length ? Array.from(/* @__PURE__ */ new Set([...selectionPaths, ...changedSelectionAbs])) : selectionPaths;
|
|
6925
|
+
const selectionSpecifiedAugmented = Boolean(selectionSpecified || changedSelectionAbs.length > 0);
|
|
6926
|
+
console.info(
|
|
6927
|
+
`Selection \u2192 specified=${selectionSpecifiedAugmented} paths=${selectionPathsAugmented.length}`
|
|
6928
|
+
);
|
|
6874
6929
|
const { jest } = argsForDiscovery(["run"], jestArgs);
|
|
6875
|
-
const selectionLooksLikeTest =
|
|
6930
|
+
const selectionLooksLikeTest = selectionPathsAugmented.some(
|
|
6876
6931
|
(pathText) => /\.(test|spec)\.[tj]sx?$/i.test(pathText) || /(^|\/)tests?\//i.test(pathText)
|
|
6877
6932
|
);
|
|
6878
|
-
const selectionLooksLikePath =
|
|
6933
|
+
const selectionLooksLikePath = selectionPathsAugmented.some(
|
|
6879
6934
|
(pathText) => /[\\/]/.test(pathText) || /\.(m?[tj]sx?)$/i.test(pathText)
|
|
6880
6935
|
);
|
|
6881
|
-
const selectionHasPaths =
|
|
6936
|
+
const selectionHasPaths = selectionPathsAugmented.length > 0;
|
|
6882
6937
|
const repoRootForDiscovery = workspaceRoot ?? await findRepoRoot();
|
|
6883
6938
|
const expandProductionSelections = async (tokens, repoRoot) => {
|
|
6884
6939
|
const results = /* @__PURE__ */ new Set();
|
|
@@ -6887,18 +6942,18 @@ var program = async () => {
|
|
|
6887
6942
|
if (!token) {
|
|
6888
6943
|
continue;
|
|
6889
6944
|
}
|
|
6890
|
-
const isAbs =
|
|
6945
|
+
const isAbs = path10.isAbsolute(token);
|
|
6891
6946
|
const looksLikeRelPath = /[\\/]/.test(token);
|
|
6892
6947
|
let candidateFromRoot;
|
|
6893
6948
|
if (token.startsWith("/")) {
|
|
6894
|
-
candidateFromRoot =
|
|
6949
|
+
candidateFromRoot = path10.join(repoRoot, token.slice(1));
|
|
6895
6950
|
} else if (looksLikeRelPath) {
|
|
6896
|
-
candidateFromRoot =
|
|
6951
|
+
candidateFromRoot = path10.join(repoRoot, token);
|
|
6897
6952
|
} else {
|
|
6898
6953
|
candidateFromRoot = void 0;
|
|
6899
6954
|
}
|
|
6900
6955
|
const tryPushIfProd = (absPath) => {
|
|
6901
|
-
const norm =
|
|
6956
|
+
const norm = path10.resolve(absPath).replace(/\\/g, "/");
|
|
6902
6957
|
const isTest = /(^|\/)tests?\//i.test(norm) || /\.(test|spec)\.[tj]sx?$/i.test(norm);
|
|
6903
6958
|
if (!isTest && fsSync3.existsSync(norm)) {
|
|
6904
6959
|
results.add(norm);
|
|
@@ -6920,7 +6975,7 @@ var program = async () => {
|
|
|
6920
6975
|
}),
|
|
6921
6976
|
timeoutMs: 4e3
|
|
6922
6977
|
});
|
|
6923
|
-
const matches = out.split(/\r?\n/).map((line) => line.trim()).filter(Boolean).map((rel) =>
|
|
6978
|
+
const matches = out.split(/\r?\n/).map((line) => line.trim()).filter(Boolean).map((rel) => path10.resolve(repoRoot, rel).replace(/\\/g, "/")).filter(
|
|
6924
6979
|
(abs) => !abs.includes("/node_modules/") && !abs.includes("/coverage/") && !/(^|\/)tests?\//i.test(abs) && !/\.(test|spec)\.[tj]sx?$/i.test(abs)
|
|
6925
6980
|
);
|
|
6926
6981
|
matches.forEach((abs) => results.add(abs));
|
|
@@ -6929,20 +6984,20 @@ var program = async () => {
|
|
|
6929
6984
|
}
|
|
6930
6985
|
return Array.from(results);
|
|
6931
6986
|
};
|
|
6932
|
-
const initialProdSelections =
|
|
6987
|
+
const initialProdSelections = selectionPathsAugmented.filter(
|
|
6933
6988
|
(pathText) => (/[\\/]/.test(pathText) || /\.(m?[tj]sx?)$/i.test(pathText)) && !/(^|\/)tests?\//i.test(pathText) && !/\.(test|spec)\.[tj]sx?$/i.test(pathText)
|
|
6934
6989
|
);
|
|
6935
|
-
const expandedProdSelections = initialProdSelections.length ? initialProdSelections : await expandProductionSelections(
|
|
6990
|
+
const expandedProdSelections = initialProdSelections.length ? initialProdSelections : await expandProductionSelections(selectionPathsAugmented, repoRootForDiscovery);
|
|
6936
6991
|
const selectionIncludesProdPaths = expandedProdSelections.length > 0;
|
|
6937
6992
|
console.info(
|
|
6938
6993
|
`Selection classify \u2192 looksLikePath=${selectionLooksLikePath} looksLikeTest=${selectionLooksLikeTest} prodPaths=${selectionIncludesProdPaths}`
|
|
6939
6994
|
);
|
|
6940
|
-
const stripPathTokens = (args) => args.filter((token) => !
|
|
6995
|
+
const stripPathTokens = (args) => args.filter((token) => !selectionPathsAugmented.includes(token));
|
|
6941
6996
|
const jestDiscoveryArgs = selectionIncludesProdPaths ? stripPathTokens(jest) : jest;
|
|
6942
6997
|
const projectConfigs = [];
|
|
6943
6998
|
try {
|
|
6944
|
-
const baseCfg =
|
|
6945
|
-
const tsCfg =
|
|
6999
|
+
const baseCfg = path10.resolve("jest.config.js");
|
|
7000
|
+
const tsCfg = path10.resolve("jest.ts.config.js");
|
|
6946
7001
|
if (fsSync3.existsSync(baseCfg)) {
|
|
6947
7002
|
projectConfigs.push(baseCfg);
|
|
6948
7003
|
}
|
|
@@ -6959,7 +7014,7 @@ var program = async () => {
|
|
|
6959
7014
|
);
|
|
6960
7015
|
const prodSelections2 = expandedProdSelections;
|
|
6961
7016
|
for (const cfg of projectConfigs) {
|
|
6962
|
-
const cfgCwd =
|
|
7017
|
+
const cfgCwd = path10.dirname(cfg);
|
|
6963
7018
|
const allTests = await discoverJestResilient([...jestDiscoveryArgs, "--config", cfg], {
|
|
6964
7019
|
cwd: cfgCwd
|
|
6965
7020
|
});
|
|
@@ -6972,7 +7027,7 @@ var program = async () => {
|
|
|
6972
7027
|
});
|
|
6973
7028
|
} catch (err) {
|
|
6974
7029
|
if (isDebug()) {
|
|
6975
|
-
console.warn(`direct selection failed for project ${
|
|
7030
|
+
console.warn(`direct selection failed for project ${path10.basename(cfg)}: ${String(err)}`);
|
|
6976
7031
|
}
|
|
6977
7032
|
}
|
|
6978
7033
|
perProjectFiles.set(cfg, directPerProject);
|
|
@@ -6984,7 +7039,7 @@ var program = async () => {
|
|
|
6984
7039
|
)} | related=${selectionIncludesProdPaths} | cwd=${repoRootForDiscovery}`
|
|
6985
7040
|
);
|
|
6986
7041
|
for (const cfg of projectConfigs) {
|
|
6987
|
-
const cfgCwd =
|
|
7042
|
+
const cfgCwd = path10.dirname(cfg);
|
|
6988
7043
|
const files = await discoverJestResilient([...jestDiscoveryArgs, "--config", cfg], {
|
|
6989
7044
|
cwd: cfgCwd
|
|
6990
7045
|
});
|
|
@@ -6994,18 +7049,18 @@ var program = async () => {
|
|
|
6994
7049
|
const perProjectFiltered = /* @__PURE__ */ new Map();
|
|
6995
7050
|
for (const cfg of projectConfigs) {
|
|
6996
7051
|
const files = perProjectFiles.get(cfg) ?? [];
|
|
6997
|
-
const selectionTestPaths =
|
|
7052
|
+
const selectionTestPaths = selectionPathsAugmented.filter(
|
|
6998
7053
|
(pathToken) => /\.(test|spec)\.[tj]sx?$/i.test(pathToken) || /(^|\/)tests?\//i.test(pathToken)
|
|
6999
7054
|
);
|
|
7000
7055
|
const candidates = selectionHasPaths && selectionLooksLikeTest ? selectionTestPaths : files;
|
|
7001
7056
|
const absFiles = candidates.map(
|
|
7002
|
-
(candidatePath) =>
|
|
7057
|
+
(candidatePath) => path10.isAbsolute(candidatePath) ? candidatePath : path10.join(repoRootForDiscovery, candidatePath)
|
|
7003
7058
|
).map((absolutePath) => absolutePath.replace(/\\/g, "/"));
|
|
7004
7059
|
const onlyOwned = await filterCandidatesForProject(
|
|
7005
7060
|
cfg,
|
|
7006
7061
|
jestDiscoveryArgs,
|
|
7007
7062
|
absFiles,
|
|
7008
|
-
|
|
7063
|
+
path10.dirname(cfg)
|
|
7009
7064
|
);
|
|
7010
7065
|
perProjectFiltered.set(cfg, onlyOwned);
|
|
7011
7066
|
}
|
|
@@ -7017,7 +7072,7 @@ var program = async () => {
|
|
|
7017
7072
|
if (selectionHasPaths && prodSelections.length > 0) {
|
|
7018
7073
|
console.info(`rg related \u2192 prodSelections=${prodSelections.length} (starting)`);
|
|
7019
7074
|
const repoRootForRefinement = workspaceRoot ?? await findRepoRoot();
|
|
7020
|
-
const selectionKey = prodSelections.map((absPath) =>
|
|
7075
|
+
const selectionKey = prodSelections.map((absPath) => path10.relative(repoRootForRefinement, absPath).replace(/\\/g, "/")).sort((firstPath, secondPath) => firstPath.localeCompare(secondPath)).join("|");
|
|
7021
7076
|
const { cachedRelated: cachedRelated2, findRelatedTestsFast: findRelatedTestsFast2, DEFAULT_TEST_GLOBS: DEFAULT_TEST_GLOBS2 } = await Promise.resolve().then(() => (init_fast_related(), fast_related_exports));
|
|
7022
7077
|
const { DEFAULT_EXCLUDE: DEFAULT_EXCLUDE2 } = await Promise.resolve().then(() => (init_args(), args_exports));
|
|
7023
7078
|
const rgMatches = await cachedRelated2({
|
|
@@ -7047,7 +7102,7 @@ var program = async () => {
|
|
|
7047
7102
|
cfg,
|
|
7048
7103
|
jestDiscoveryArgs,
|
|
7049
7104
|
rgCandidates,
|
|
7050
|
-
|
|
7105
|
+
path10.dirname(cfg)
|
|
7051
7106
|
);
|
|
7052
7107
|
perProjectFromRg.set(cfg, owned);
|
|
7053
7108
|
}
|
|
@@ -7062,9 +7117,9 @@ var program = async () => {
|
|
|
7062
7117
|
} else {
|
|
7063
7118
|
const repoRootForScan = repoRootForDiscovery;
|
|
7064
7119
|
const toSeeds = (abs) => {
|
|
7065
|
-
const rel =
|
|
7120
|
+
const rel = path10.relative(repoRootForScan, abs).replace(/\\/g, "/");
|
|
7066
7121
|
const withoutExt = rel.replace(/\.(m?[tj]sx?)$/i, "");
|
|
7067
|
-
const base =
|
|
7122
|
+
const base = path10.basename(withoutExt);
|
|
7068
7123
|
const segs = withoutExt.split("/");
|
|
7069
7124
|
const tail2 = segs.slice(-2).join("/");
|
|
7070
7125
|
return Array.from(new Set([withoutExt, base, tail2].filter(Boolean)));
|
|
@@ -7079,8 +7134,8 @@ var program = async () => {
|
|
|
7079
7134
|
}
|
|
7080
7135
|
};
|
|
7081
7136
|
const resolveLocalImport = (fromFile, spec) => {
|
|
7082
|
-
const baseDir =
|
|
7083
|
-
const cand =
|
|
7137
|
+
const baseDir = path10.dirname(fromFile);
|
|
7138
|
+
const cand = path10.resolve(baseDir, spec);
|
|
7084
7139
|
const exts = ["", ".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs"];
|
|
7085
7140
|
for (const ext of exts) {
|
|
7086
7141
|
const full = ext ? `${cand}${ext}` : cand;
|
|
@@ -7089,7 +7144,7 @@ var program = async () => {
|
|
|
7089
7144
|
}
|
|
7090
7145
|
}
|
|
7091
7146
|
for (const ext of exts) {
|
|
7092
|
-
const full =
|
|
7147
|
+
const full = path10.join(cand, `index${ext}`);
|
|
7093
7148
|
if (fsSync3.existsSync(full)) {
|
|
7094
7149
|
return full;
|
|
7095
7150
|
}
|
|
@@ -7143,7 +7198,7 @@ var program = async () => {
|
|
|
7143
7198
|
cfg,
|
|
7144
7199
|
jestDiscoveryArgs,
|
|
7145
7200
|
keptCandidates,
|
|
7146
|
-
|
|
7201
|
+
path10.dirname(cfg)
|
|
7147
7202
|
);
|
|
7148
7203
|
perProjectFromScan.set(cfg, owned);
|
|
7149
7204
|
}
|
|
@@ -7170,9 +7225,9 @@ var program = async () => {
|
|
|
7170
7225
|
if (effectiveJestFiles.length === 0) {
|
|
7171
7226
|
const repoRoot = repoRootForRefinement;
|
|
7172
7227
|
const seeds = prodSelections.map(
|
|
7173
|
-
(abs) =>
|
|
7228
|
+
(abs) => path10.relative(repoRoot, abs).replace(/\\/g, "/").replace(/\.(m?[tj]sx?)$/i, "")
|
|
7174
7229
|
).flatMap((rel) => {
|
|
7175
|
-
const base =
|
|
7230
|
+
const base = path10.basename(rel);
|
|
7176
7231
|
const segments = rel.split("/");
|
|
7177
7232
|
return Array.from(new Set([rel, base, segments.slice(-2).join("/")].filter(Boolean)));
|
|
7178
7233
|
});
|
|
@@ -7185,8 +7240,8 @@ var program = async () => {
|
|
|
7185
7240
|
}
|
|
7186
7241
|
};
|
|
7187
7242
|
const resolveLocalImport = (fromFile, spec) => {
|
|
7188
|
-
const baseDir =
|
|
7189
|
-
const candidate =
|
|
7243
|
+
const baseDir = path10.dirname(fromFile);
|
|
7244
|
+
const candidate = path10.resolve(baseDir, spec);
|
|
7190
7245
|
const extensions = ["", ".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs", ".mts", ".cts"];
|
|
7191
7246
|
for (const ext of extensions) {
|
|
7192
7247
|
const fullPath = ext ? `${candidate}${ext}` : candidate;
|
|
@@ -7195,7 +7250,7 @@ var program = async () => {
|
|
|
7195
7250
|
}
|
|
7196
7251
|
}
|
|
7197
7252
|
for (const ext of extensions) {
|
|
7198
|
-
const fullPath =
|
|
7253
|
+
const fullPath = path10.join(candidate, `index${ext}`);
|
|
7199
7254
|
if (fsSync3.existsSync(fullPath)) {
|
|
7200
7255
|
return fullPath;
|
|
7201
7256
|
}
|
|
@@ -7314,8 +7369,8 @@ var program = async () => {
|
|
|
7314
7369
|
}
|
|
7315
7370
|
}
|
|
7316
7371
|
const jestDecision = decideShouldRunJest([], effectiveJestFiles, {
|
|
7317
|
-
selectionSpecified,
|
|
7318
|
-
selectionPaths
|
|
7372
|
+
selectionSpecified: selectionSpecifiedAugmented,
|
|
7373
|
+
selectionPaths: selectionPathsAugmented
|
|
7319
7374
|
});
|
|
7320
7375
|
const { shouldRunJest } = jestDecision;
|
|
7321
7376
|
const jestCount = effectiveJestFiles.length;
|
|
@@ -7333,45 +7388,63 @@ var program = async () => {
|
|
|
7333
7388
|
}
|
|
7334
7389
|
console.info(`Run plan \u2192 Jest maybe=${shouldRunJest} (projects=${projectConfigs.length})`);
|
|
7335
7390
|
let jestExitCode = 0;
|
|
7391
|
+
const allBridgeJson = [];
|
|
7336
7392
|
const executedTestFilesSet = /* @__PURE__ */ new Set();
|
|
7337
7393
|
if (shouldRunJest) {
|
|
7338
7394
|
console.info("Starting Jest (no Vitest targets)\u2026");
|
|
7339
7395
|
await runJestBootstrap();
|
|
7340
7396
|
const jestRunArgs = selectionIncludesProdPaths ? stripPathTokens(jestArgs) : jestArgs;
|
|
7397
|
+
const sanitizedJestRunArgs = jestRunArgs.filter(
|
|
7398
|
+
(arg) => !/^--coverageDirectory(?:=|$)/.test(String(arg))
|
|
7399
|
+
);
|
|
7341
7400
|
const projectsToRun = projectConfigs.filter(
|
|
7342
7401
|
(cfg) => (perProjectFiltered.get(cfg) ?? []).length > 0
|
|
7343
7402
|
);
|
|
7344
|
-
const totalProjectsToRun = projectsToRun.length;
|
|
7345
7403
|
const stripFooter = (text) => {
|
|
7346
7404
|
const lines = text.split("\n");
|
|
7347
7405
|
const idx = lines.findIndex((ln) => /^Test Files\s/.test(stripAnsiSimple(ln)));
|
|
7348
7406
|
return idx >= 0 ? lines.slice(0, idx).join("\n").trimEnd() : text;
|
|
7349
7407
|
};
|
|
7408
|
+
const prodSeedsForRun = (() => {
|
|
7409
|
+
const changedAbs = (changedSelectionAbs ?? []).map(
|
|
7410
|
+
(absPath) => path10.resolve(absPath).replace(/\\/g, "/")
|
|
7411
|
+
);
|
|
7412
|
+
const selAbs = selectionPathsAugmented.map(
|
|
7413
|
+
(pathToken) => path10.resolve(pathToken).replace(/\\/g, "/")
|
|
7414
|
+
);
|
|
7415
|
+
return (changedAbs.length ? changedAbs : selAbs).filter(
|
|
7416
|
+
(abs) => /[\\/]/.test(abs) && !/(^|\/)tests?\//i.test(abs) && !/\.(test|spec)\.[tj]sx?$/i.test(abs)
|
|
7417
|
+
);
|
|
7418
|
+
})();
|
|
7419
|
+
const repoRootForRank = repoRootForDiscovery;
|
|
7420
|
+
const fileRank = await computeDirectnessRank({
|
|
7421
|
+
repoRoot: repoRootForRank,
|
|
7422
|
+
productionSeeds: prodSeedsForRun
|
|
7423
|
+
});
|
|
7350
7424
|
for (let projIndex = 0; projIndex < projectsToRun.length; projIndex += 1) {
|
|
7351
7425
|
const cfg = projectsToRun[projIndex];
|
|
7352
|
-
const isLastProject = projIndex === totalProjectsToRun - 1;
|
|
7353
7426
|
const files = perProjectFiltered.get(cfg) ?? [];
|
|
7354
7427
|
if (files.length === 0) {
|
|
7355
|
-
console.info(`Project ${
|
|
7428
|
+
console.info(`Project ${path10.basename(cfg)}: 0 matching tests after filter; skipping.`);
|
|
7356
7429
|
continue;
|
|
7357
7430
|
}
|
|
7358
7431
|
files.forEach(
|
|
7359
|
-
(absTestPath) => executedTestFilesSet.add(
|
|
7432
|
+
(absTestPath) => executedTestFilesSet.add(path10.resolve(absTestPath).replace(/\\/g, "/"))
|
|
7360
7433
|
);
|
|
7361
|
-
const outJson =
|
|
7434
|
+
const outJson = path10.join(
|
|
7362
7435
|
os2.tmpdir(),
|
|
7363
7436
|
`jest-bridge-${Date.now()}-${Math.random().toString(36).slice(2)}.json`
|
|
7364
7437
|
);
|
|
7365
|
-
const reporterPath =
|
|
7438
|
+
const reporterPath = path10.resolve("scripts/jest-vitest-bridge.cjs");
|
|
7366
7439
|
try {
|
|
7367
7440
|
if (!fsSync3.existsSync(reporterPath)) {
|
|
7368
|
-
fsSync3.mkdirSync(
|
|
7441
|
+
fsSync3.mkdirSync(path10.dirname(reporterPath), { recursive: true });
|
|
7369
7442
|
fsSync3.writeFileSync(reporterPath, JEST_BRIDGE_REPORTER_SOURCE, "utf8");
|
|
7370
7443
|
}
|
|
7371
7444
|
} catch (ensureReporterError) {
|
|
7372
7445
|
console.warn(`Unable to ensure jest bridge reporter: ${String(ensureReporterError)}`);
|
|
7373
7446
|
}
|
|
7374
|
-
const selectedFilesForCoverage =
|
|
7447
|
+
const selectedFilesForCoverage = selectionPathsAugmented.filter((pathToken) => /[\\/]/.test(pathToken)).filter((pathToken) => !looksLikeTestPath(pathToken)).map((pathToken) => path10.relative(repoRootForDiscovery, pathToken).replace(/\\\\/g, "/")).filter((rel) => rel && !/^\.+\//.test(rel)).map((rel) => rel.startsWith("./") ? rel : `./${rel}`);
|
|
7375
7448
|
const coverageFromArgs = [];
|
|
7376
7449
|
for (const relPath of selectedFilesForCoverage) {
|
|
7377
7450
|
coverageFromArgs.push("--collectCoverageFrom", relPath);
|
|
@@ -7385,14 +7458,17 @@ var program = async () => {
|
|
|
7385
7458
|
"--config",
|
|
7386
7459
|
cfg,
|
|
7387
7460
|
"--runTestsByPath",
|
|
7388
|
-
|
|
7389
|
-
reporterPath,
|
|
7461
|
+
`--reporters=${reporterPath}`,
|
|
7390
7462
|
"--silent",
|
|
7391
7463
|
"--colors",
|
|
7392
7464
|
"--json",
|
|
7393
7465
|
"--outputFile",
|
|
7394
7466
|
outJson,
|
|
7395
|
-
...
|
|
7467
|
+
...sanitizedJestRunArgs,
|
|
7468
|
+
...collectCoverage ? [
|
|
7469
|
+
"--coverageDirectory",
|
|
7470
|
+
path10.join("coverage", "jest", path10.basename(cfg).replace(/[^a-zA-Z0-9_.-]+/g, "_"))
|
|
7471
|
+
] : [],
|
|
7396
7472
|
...coverageFromArgs,
|
|
7397
7473
|
"--passWithNoTests",
|
|
7398
7474
|
...files
|
|
@@ -7418,10 +7494,22 @@ var program = async () => {
|
|
|
7418
7494
|
const jsonText = fsSync3.readFileSync(outJson, "utf8");
|
|
7419
7495
|
const parsed = JSON.parse(jsonText);
|
|
7420
7496
|
const bridge = coerceJestJsonToBridge(parsed);
|
|
7421
|
-
|
|
7422
|
-
|
|
7423
|
-
|
|
7424
|
-
|
|
7497
|
+
allBridgeJson.push(bridge);
|
|
7498
|
+
try {
|
|
7499
|
+
const reordered = {
|
|
7500
|
+
...bridge,
|
|
7501
|
+
testResults: sortTestResultsWithRank(fileRank, bridge.testResults).reverse()
|
|
7502
|
+
};
|
|
7503
|
+
pretty = renderVitestFromJestJSON(reordered, {
|
|
7504
|
+
cwd: repoRootForDiscovery,
|
|
7505
|
+
...editorCmd !== void 0 ? { editorCmd } : {}
|
|
7506
|
+
});
|
|
7507
|
+
} catch {
|
|
7508
|
+
pretty = renderVitestFromJestJSON(bridge, {
|
|
7509
|
+
cwd: repoRootForDiscovery,
|
|
7510
|
+
...editorCmd !== void 0 ? { editorCmd } : {}
|
|
7511
|
+
});
|
|
7512
|
+
}
|
|
7425
7513
|
if (debug) {
|
|
7426
7514
|
const preview = pretty.split("\n").slice(0, 3).join("\n");
|
|
7427
7515
|
console.info(`pretty preview (json):
|
|
@@ -7445,9 +7533,7 @@ ${preview}${pretty.includes("\n") ? "\n\u2026" : ""}`);
|
|
|
7445
7533
|
${preview}${pretty.includes("\n") ? "\n\u2026" : ""}`);
|
|
7446
7534
|
}
|
|
7447
7535
|
}
|
|
7448
|
-
|
|
7449
|
-
pretty = stripFooter(pretty);
|
|
7450
|
-
}
|
|
7536
|
+
pretty = stripFooter(pretty);
|
|
7451
7537
|
if (pretty.trim().length > 0) {
|
|
7452
7538
|
process.stdout.write(pretty.endsWith("\n") ? pretty : `${pretty}
|
|
7453
7539
|
`);
|
|
@@ -7459,15 +7545,69 @@ ${preview}${pretty.includes("\n") ? "\n\u2026" : ""}`);
|
|
|
7459
7545
|
} else {
|
|
7460
7546
|
console.info("Jest run skipped based on selection and thresholds.");
|
|
7461
7547
|
}
|
|
7462
|
-
if (
|
|
7463
|
-
|
|
7548
|
+
if (allBridgeJson.length > 0) {
|
|
7549
|
+
const agg = allBridgeJson.map((bridge) => bridge.aggregated);
|
|
7550
|
+
const sum = (select) => agg.reduce((total, item) => total + (select(item) || 0), 0);
|
|
7551
|
+
const startTime = Math.min(
|
|
7552
|
+
...allBridgeJson.map((bridge) => Number(bridge.startTime || Date.now()))
|
|
7553
|
+
);
|
|
7554
|
+
const unified = {
|
|
7555
|
+
startTime,
|
|
7556
|
+
testResults: allBridgeJson.flatMap((bridge) => bridge.testResults),
|
|
7557
|
+
aggregated: {
|
|
7558
|
+
numTotalTestSuites: sum((item) => item.numTotalTestSuites),
|
|
7559
|
+
numPassedTestSuites: sum((item) => item.numPassedTestSuites),
|
|
7560
|
+
numFailedTestSuites: sum((item) => item.numFailedTestSuites),
|
|
7561
|
+
numTotalTests: sum((item) => item.numTotalTests),
|
|
7562
|
+
numPassedTests: sum((item) => item.numPassedTests),
|
|
7563
|
+
numFailedTests: sum((item) => item.numFailedTests),
|
|
7564
|
+
numPendingTests: sum((item) => item.numPendingTests),
|
|
7565
|
+
numTodoTests: sum((item) => item.numTodoTests),
|
|
7566
|
+
startTime,
|
|
7567
|
+
success: agg.every((item) => Boolean(item.success)),
|
|
7568
|
+
runTimeMs: sum((item) => Number(item.runTimeMs ?? 0))
|
|
7569
|
+
}
|
|
7570
|
+
};
|
|
7571
|
+
try {
|
|
7572
|
+
const prodSeeds = (() => {
|
|
7573
|
+
const changedAbs = (changedSelectionAbs ?? []).map(
|
|
7574
|
+
(absPath) => path10.resolve(absPath).replace(/\\/g, "/")
|
|
7575
|
+
);
|
|
7576
|
+
const selAbs = selectionPathsAugmented.map(
|
|
7577
|
+
(pathToken) => path10.resolve(pathToken).replace(/\\/g, "/")
|
|
7578
|
+
);
|
|
7579
|
+
return (changedAbs.length ? changedAbs : selAbs).filter(
|
|
7580
|
+
(abs) => /[\\/]/.test(abs) && !/(^|\/)tests?\//i.test(abs) && !/\.(test|spec)\.[tj]sx?$/i.test(abs)
|
|
7581
|
+
);
|
|
7582
|
+
})();
|
|
7583
|
+
const unifiedRank = await computeDirectnessRank({
|
|
7584
|
+
repoRoot: repoRootForDiscovery,
|
|
7585
|
+
productionSeeds: prodSeeds
|
|
7586
|
+
});
|
|
7587
|
+
const ordered = sortTestResultsWithRank(unifiedRank, unified.testResults).reverse();
|
|
7588
|
+
unified.testResults = ordered;
|
|
7589
|
+
} catch {
|
|
7590
|
+
}
|
|
7591
|
+
const text = renderVitestFromJestJSON(unified, {
|
|
7592
|
+
cwd: repoRootForDiscovery,
|
|
7593
|
+
...editorCmd !== void 0 ? { editorCmd } : {}
|
|
7594
|
+
});
|
|
7595
|
+
if (text.trim().length > 0) {
|
|
7596
|
+
process.stdout.write(text.endsWith("\n") ? text : `${text}
|
|
7597
|
+
`);
|
|
7598
|
+
}
|
|
7599
|
+
}
|
|
7600
|
+
const finalExitCode = jestExitCode;
|
|
7601
|
+
if (collectCoverage && shouldRunJest && coverageAbortOnFailure && finalExitCode !== 0) {
|
|
7602
|
+
process.exit(finalExitCode);
|
|
7603
|
+
return;
|
|
7464
7604
|
}
|
|
7465
7605
|
if (collectCoverage && shouldRunJest) {
|
|
7466
7606
|
await mergeLcov();
|
|
7467
7607
|
const repoRoot = workspaceRoot ?? await findRepoRoot();
|
|
7468
7608
|
const mergedOptsBase = {
|
|
7469
|
-
selectionSpecified,
|
|
7470
|
-
selectionPaths,
|
|
7609
|
+
selectionSpecified: selectionSpecifiedAugmented,
|
|
7610
|
+
selectionPaths: selectionPathsAugmented,
|
|
7471
7611
|
includeGlobs,
|
|
7472
7612
|
excludeGlobs,
|
|
7473
7613
|
workspaceRoot: repoRoot,
|
|
@@ -7482,7 +7622,6 @@ ${preview}${pretty.includes("\n") ? "\n\u2026" : ""}`);
|
|
|
7482
7622
|
};
|
|
7483
7623
|
await emitMergedCoverage(coverageUi, mergedOptsBase);
|
|
7484
7624
|
}
|
|
7485
|
-
const finalExitCode = jestExitCode;
|
|
7486
7625
|
process.exit(finalExitCode);
|
|
7487
7626
|
};
|
|
7488
7627
|
export {
|