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/cli.cjs
CHANGED
|
@@ -93,7 +93,7 @@ var init_TimeoutError = __esm({
|
|
|
93
93
|
|
|
94
94
|
// node_modules/es-toolkit/dist/promise/delay.mjs
|
|
95
95
|
function delay(ms, { signal } = {}) {
|
|
96
|
-
return new Promise((
|
|
96
|
+
return new Promise((resolve9, reject) => {
|
|
97
97
|
const abortError = () => {
|
|
98
98
|
reject(new AbortError());
|
|
99
99
|
};
|
|
@@ -106,7 +106,7 @@ function delay(ms, { signal } = {}) {
|
|
|
106
106
|
}
|
|
107
107
|
const timeoutId = setTimeout(() => {
|
|
108
108
|
signal?.removeEventListener("abort", abortHandler);
|
|
109
|
-
|
|
109
|
+
resolve9();
|
|
110
110
|
}, ms);
|
|
111
111
|
signal?.addEventListener("abort", abortHandler, { once: true });
|
|
112
112
|
});
|
|
@@ -171,11 +171,11 @@ var init_exec = __esm({
|
|
|
171
171
|
child.stderr?.on("data", (chunk) => {
|
|
172
172
|
stderr += String(chunk);
|
|
173
173
|
});
|
|
174
|
-
const exec = new Promise((
|
|
174
|
+
const exec = new Promise((resolve9, reject) => {
|
|
175
175
|
child.on("error", reject);
|
|
176
176
|
child.on(
|
|
177
177
|
"close",
|
|
178
|
-
(code) => Number(code) === 0 ?
|
|
178
|
+
(code) => Number(code) === 0 ? resolve9(stdout) : reject(new Error(stderr || `exit ${code}`))
|
|
179
179
|
);
|
|
180
180
|
});
|
|
181
181
|
try {
|
|
@@ -195,7 +195,7 @@ var init_exec = __esm({
|
|
|
195
195
|
throw caughtError;
|
|
196
196
|
}
|
|
197
197
|
};
|
|
198
|
-
runExitCode = async (cmd, args, opts = {}) => new Promise((
|
|
198
|
+
runExitCode = async (cmd, args, opts = {}) => new Promise((resolve9, reject) => {
|
|
199
199
|
const child = (0, import_node_child_process.spawn)(cmd, [...args], {
|
|
200
200
|
cwd: opts.cwd,
|
|
201
201
|
env: opts.env,
|
|
@@ -204,9 +204,9 @@ var init_exec = __esm({
|
|
|
204
204
|
windowsHide: true
|
|
205
205
|
});
|
|
206
206
|
child.on("error", reject);
|
|
207
|
-
child.on("close", (code) =>
|
|
207
|
+
child.on("close", (code) => resolve9(Number(code)));
|
|
208
208
|
});
|
|
209
|
-
runWithCapture = async (cmd, args, opts) => new Promise((
|
|
209
|
+
runWithCapture = async (cmd, args, opts) => new Promise((resolve9, reject) => {
|
|
210
210
|
const child = (0, import_node_child_process.spawn)(cmd, [...args], {
|
|
211
211
|
cwd: opts.cwd,
|
|
212
212
|
env: opts.env,
|
|
@@ -222,7 +222,7 @@ var init_exec = __esm({
|
|
|
222
222
|
buf += String(chunk);
|
|
223
223
|
});
|
|
224
224
|
child.on("error", reject);
|
|
225
|
-
child.on("close", (code) =>
|
|
225
|
+
child.on("close", (code) => resolve9({ code: Number(code), output: buf }));
|
|
226
226
|
});
|
|
227
227
|
}
|
|
228
228
|
});
|
|
@@ -263,7 +263,8 @@ var init_args = __esm({
|
|
|
263
263
|
coverageMode: (value) => ({ type: "coverageMode", value }),
|
|
264
264
|
coverageMaxFiles: (value) => ({ type: "coverageMaxFiles", value }),
|
|
265
265
|
coverageMaxHotspots: (value) => ({ type: "coverageMaxHotspots", value }),
|
|
266
|
-
coveragePageFit: (value) => ({ type: "coveragePageFit", value })
|
|
266
|
+
coveragePageFit: (value) => ({ type: "coveragePageFit", value }),
|
|
267
|
+
changed: (value) => ({ type: "changed", value })
|
|
267
268
|
};
|
|
268
269
|
Some = (value) => ({ _tag: "some", value });
|
|
269
270
|
None = { _tag: "none" };
|
|
@@ -460,6 +461,18 @@ var init_args = __esm({
|
|
|
460
461
|
"--coverage.root=",
|
|
461
462
|
(value) => step([ActionBuilders.coverageRoot((value.split("=")[1] ?? "").trim())])
|
|
462
463
|
),
|
|
464
|
+
// --changed flag: selects changed files via git (all|staged|unstaged)
|
|
465
|
+
rule.eq("--changed", () => step([ActionBuilders.changed("all")])),
|
|
466
|
+
rule.startsWith("--changed=", (value) => {
|
|
467
|
+
const raw = (value.split("=")[1] ?? "").trim().toLowerCase();
|
|
468
|
+
const mode = raw === "staged" ? "staged" : raw === "unstaged" ? "unstaged" : "all";
|
|
469
|
+
return step([ActionBuilders.changed(mode)]);
|
|
470
|
+
}),
|
|
471
|
+
rule.withLookahead("--changed", (_flag, lookahead) => {
|
|
472
|
+
const raw = String(lookahead).trim().toLowerCase();
|
|
473
|
+
const mode = raw === "staged" ? "staged" : raw === "unstaged" ? "unstaged" : "all";
|
|
474
|
+
return step([ActionBuilders.changed(mode)], true);
|
|
475
|
+
}),
|
|
463
476
|
rule.withLookahead(
|
|
464
477
|
"-t",
|
|
465
478
|
(flag, lookahead) => step(
|
|
@@ -562,6 +575,8 @@ var init_args = __esm({
|
|
|
562
575
|
return { vitest: [], jest: [], coverage: false, coverageMaxHotspots: action.value };
|
|
563
576
|
case "coveragePageFit":
|
|
564
577
|
return { vitest: [], jest: [], coverage: false, coveragePageFit: action.value };
|
|
578
|
+
case "changed":
|
|
579
|
+
return { vitest: [], jest: [], coverage: false, changed: action.value };
|
|
565
580
|
case "jestArg":
|
|
566
581
|
return { vitest: [], jest: [action.value], coverage: false };
|
|
567
582
|
case "vitestArg":
|
|
@@ -601,6 +616,7 @@ var init_args = __esm({
|
|
|
601
616
|
}
|
|
602
617
|
return {
|
|
603
618
|
...next,
|
|
619
|
+
...right.changed !== void 0 || left.changed !== void 0 ? { changed: right.changed ?? left.changed } : {},
|
|
604
620
|
...right.coverageAbortOnFailure !== void 0 || left.coverageAbortOnFailure !== void 0 ? { coverageAbortOnFailure: right.coverageAbortOnFailure ?? left.coverageAbortOnFailure } : {},
|
|
605
621
|
...right.coverageDetail !== void 0 || left.coverageDetail !== void 0 ? { coverageDetail: right.coverageDetail ?? left.coverageDetail } : {},
|
|
606
622
|
...right.coverageShowCode !== void 0 || left.coverageShowCode !== void 0 ? { coverageShowCode: right.coverageShowCode ?? left.coverageShowCode } : {},
|
|
@@ -686,7 +702,8 @@ var init_args = __esm({
|
|
|
686
702
|
...coverageMaxHotspotsLocal !== void 0 ? { coverageMaxHotspots: coverageMaxHotspotsLocal } : {},
|
|
687
703
|
coveragePageFit,
|
|
688
704
|
...contrib.editorCmd !== void 0 ? { editorCmd: contrib.editorCmd } : {},
|
|
689
|
-
...contrib.workspaceRoot !== void 0 ? { workspaceRoot: contrib.workspaceRoot } : {}
|
|
705
|
+
...contrib.workspaceRoot !== void 0 ? { workspaceRoot: contrib.workspaceRoot } : {},
|
|
706
|
+
...contrib.changed !== void 0 ? { changed: contrib.changed } : {}
|
|
690
707
|
};
|
|
691
708
|
return out;
|
|
692
709
|
};
|
|
@@ -1960,14 +1977,13 @@ var require_lib = __commonJS({
|
|
|
1960
1977
|
});
|
|
1961
1978
|
|
|
1962
1979
|
// src/lib/program.ts
|
|
1963
|
-
var
|
|
1980
|
+
var path10 = __toESM(require("node:path"), 1);
|
|
1964
1981
|
var os2 = __toESM(require("node:os"), 1);
|
|
1965
1982
|
var fsSync3 = __toESM(require("node:fs"), 1);
|
|
1966
|
-
var import_istanbul_lib_coverage2 = require("istanbul-lib-coverage");
|
|
1967
1983
|
var fs5 = __toESM(require("node:fs/promises"), 1);
|
|
1968
1984
|
var LibReport = __toESM(require("istanbul-lib-report"), 1);
|
|
1969
|
-
var
|
|
1970
|
-
var
|
|
1985
|
+
var Reports = __toESM(require("istanbul-reports"), 1);
|
|
1986
|
+
var import_istanbul_lib_coverage2 = require("istanbul-lib-coverage");
|
|
1971
1987
|
init_env_utils();
|
|
1972
1988
|
init_exec();
|
|
1973
1989
|
init_args();
|
|
@@ -2922,7 +2938,7 @@ var compositeBarPct = (summary, hotspots) => {
|
|
|
2922
2938
|
};
|
|
2923
2939
|
|
|
2924
2940
|
// src/lib/coverage-print.ts
|
|
2925
|
-
var
|
|
2941
|
+
var path8 = __toESM(require("node:path"), 1);
|
|
2926
2942
|
var fsSync2 = __toESM(require("node:fs"), 1);
|
|
2927
2943
|
init_env_utils();
|
|
2928
2944
|
init_exec();
|
|
@@ -3092,6 +3108,71 @@ var renderTable = (columns, rows) => {
|
|
|
3092
3108
|
};
|
|
3093
3109
|
var barCell = (pct) => (padded) => bar(pct, padded.length);
|
|
3094
3110
|
|
|
3111
|
+
// src/lib/relevance.ts
|
|
3112
|
+
var path7 = __toESM(require("node:path"), 1);
|
|
3113
|
+
init_args();
|
|
3114
|
+
init_fast_related();
|
|
3115
|
+
var normalizeAbs = (inputPath) => path7.resolve(inputPath).replace(/\\/g, "/");
|
|
3116
|
+
var compareBooleanDesc = (left, right) => {
|
|
3117
|
+
if (left === right) {
|
|
3118
|
+
return 0;
|
|
3119
|
+
}
|
|
3120
|
+
return right ? 1 : -1;
|
|
3121
|
+
};
|
|
3122
|
+
var compareNumberAsc = (left, right) => left - right;
|
|
3123
|
+
var compareStringAsc = (left, right) => left.localeCompare(right);
|
|
3124
|
+
var fileFailed = (file) => Boolean(
|
|
3125
|
+
(file.status ?? "") === "failed" || (file.testResults ?? []).some((assertion) => (assertion.status ?? "") === "failed")
|
|
3126
|
+
);
|
|
3127
|
+
var composeComparators = (...comparators) => (left, right) => {
|
|
3128
|
+
for (const cmp of comparators) {
|
|
3129
|
+
const result = cmp(left, right);
|
|
3130
|
+
if (result !== 0) {
|
|
3131
|
+
return result;
|
|
3132
|
+
}
|
|
3133
|
+
}
|
|
3134
|
+
return 0;
|
|
3135
|
+
};
|
|
3136
|
+
var comparatorForRank = (rankByPath) => {
|
|
3137
|
+
const rankOrInf = (absPath) => rankByPath.has(absPath) ? rankByPath.get(absPath) : Number.POSITIVE_INFINITY;
|
|
3138
|
+
return composeComparators(
|
|
3139
|
+
(left, right) => compareBooleanDesc(fileFailed(left), fileFailed(right)),
|
|
3140
|
+
(left, right) => compareNumberAsc(
|
|
3141
|
+
rankOrInf(normalizeAbs(left.testFilePath)),
|
|
3142
|
+
rankOrInf(normalizeAbs(right.testFilePath))
|
|
3143
|
+
),
|
|
3144
|
+
(left, right) => compareStringAsc(normalizeAbs(left.testFilePath), normalizeAbs(right.testFilePath))
|
|
3145
|
+
);
|
|
3146
|
+
};
|
|
3147
|
+
var computeDirectnessRank = async (opts) => {
|
|
3148
|
+
const selectionKey = opts.productionSeeds.map((abs) => path7.relative(opts.repoRoot, abs).replace(/\\/g, "/")).sort((left, right) => left.localeCompare(right)).join("|");
|
|
3149
|
+
const related = await cachedRelated({
|
|
3150
|
+
repoRoot: opts.repoRoot,
|
|
3151
|
+
selectionKey,
|
|
3152
|
+
compute: () => findRelatedTestsFast({
|
|
3153
|
+
repoRoot: opts.repoRoot,
|
|
3154
|
+
productionPaths: opts.productionSeeds,
|
|
3155
|
+
testGlobs: DEFAULT_TEST_GLOBS,
|
|
3156
|
+
excludeGlobs: opts.excludeGlobs ?? DEFAULT_EXCLUDE,
|
|
3157
|
+
timeoutMs: 1500
|
|
3158
|
+
})
|
|
3159
|
+
});
|
|
3160
|
+
const out = /* @__PURE__ */ new Map();
|
|
3161
|
+
related.forEach((abs, index) => {
|
|
3162
|
+
out.set(normalizeAbs(abs), index);
|
|
3163
|
+
});
|
|
3164
|
+
return out;
|
|
3165
|
+
};
|
|
3166
|
+
var sortTestResultsWithRank = (rankByPath, results) => results.slice().sort(comparatorForRank(rankByPath));
|
|
3167
|
+
var comparatorForPathRank = (rankByPath) => {
|
|
3168
|
+
const rankOrInf = (absPath) => rankByPath.has(absPath) ? rankByPath.get(absPath) : Number.POSITIVE_INFINITY;
|
|
3169
|
+
return composeComparators(
|
|
3170
|
+
(left, right) => compareNumberAsc(rankOrInf(normalizeAbs(left)), rankOrInf(normalizeAbs(right))),
|
|
3171
|
+
(left, right) => compareStringAsc(normalizeAbs(left), normalizeAbs(right))
|
|
3172
|
+
);
|
|
3173
|
+
};
|
|
3174
|
+
var sortPathsWithRank = (rankByPath, paths) => paths.slice().sort(comparatorForPathRank(rankByPath));
|
|
3175
|
+
|
|
3095
3176
|
// src/lib/coverage-print.ts
|
|
3096
3177
|
var printDetailedCoverage = async (opts) => {
|
|
3097
3178
|
const files = opts.map.files().sort((fileA, fileB) => {
|
|
@@ -3102,7 +3183,7 @@ var printDetailedCoverage = async (opts) => {
|
|
|
3102
3183
|
for (const abs of files) {
|
|
3103
3184
|
const fc = opts.map.fileCoverageFor(abs);
|
|
3104
3185
|
const sum = fc.toSummary();
|
|
3105
|
-
const rel =
|
|
3186
|
+
const rel = path8.relative(opts.root, abs).replace(/\\/g, "/");
|
|
3106
3187
|
const blocks = computeUncoveredBlocks(fc);
|
|
3107
3188
|
const misses = missedBranches(fc);
|
|
3108
3189
|
const missFns = missedFunctions(fc);
|
|
@@ -3111,9 +3192,9 @@ var printDetailedCoverage = async (opts) => {
|
|
|
3111
3192
|
const branchesPctText = `${sum.branches.pct.toFixed(1)}%`;
|
|
3112
3193
|
const header = `${ansi.bold(rel)} lines ${tintPct(sum.lines.pct)(
|
|
3113
3194
|
linesPctText
|
|
3114
|
-
)} ${barCell(compositeBarPct(sum, blocks))("".padEnd(14))} funcs ${tintPct(
|
|
3115
|
-
|
|
3116
|
-
)
|
|
3195
|
+
)} ${barCell(compositeBarPct(sum, blocks))("".padEnd(14))} funcs ${tintPct(sum.functions.pct)(
|
|
3196
|
+
funcsPctText
|
|
3197
|
+
)} branches ${tintPct(sum.branches.pct)(branchesPctText)}`;
|
|
3117
3198
|
console.info(header);
|
|
3118
3199
|
const max = opts.limitPerFile === "all" ? Number.POSITIVE_INFINITY : opts.limitPerFile ?? 5;
|
|
3119
3200
|
const compareRangesByLengthDescThenStart = (firstRange, secondRange) => {
|
|
@@ -3140,10 +3221,8 @@ var printDetailedCoverage = async (opts) => {
|
|
|
3140
3221
|
abs,
|
|
3141
3222
|
block.start,
|
|
3142
3223
|
opts.editorCmd
|
|
3143
|
-
)}\x07${
|
|
3144
|
-
const label = ` ${ansi.yellow(`L${block.start}`)}\u2013${ansi.yellow(
|
|
3145
|
-
`L${block.end}`
|
|
3146
|
-
)} ${link}`;
|
|
3224
|
+
)}\x07${path8.basename(abs)}:${block.start}\x1B]8;;\x07`;
|
|
3225
|
+
const label = ` ${ansi.yellow(`L${block.start}`)}\u2013${ansi.yellow(`L${block.end}`)} ${link}`;
|
|
3147
3226
|
console.info(label);
|
|
3148
3227
|
if (opts.showCode && src.length) {
|
|
3149
3228
|
const lines = src.split(/\r?\n/);
|
|
@@ -3163,7 +3242,7 @@ var printDetailedCoverage = async (opts) => {
|
|
|
3163
3242
|
abs,
|
|
3164
3243
|
fn.line,
|
|
3165
3244
|
opts.editorCmd
|
|
3166
|
-
)}\x07${
|
|
3245
|
+
)}\x07${path8.basename(abs)}:${fn.line}\x1B]8;;\x07`;
|
|
3167
3246
|
console.info(` - ${fn.name} @ ${link}`);
|
|
3168
3247
|
}
|
|
3169
3248
|
}
|
|
@@ -3174,12 +3253,8 @@ var printDetailedCoverage = async (opts) => {
|
|
|
3174
3253
|
abs,
|
|
3175
3254
|
br.line,
|
|
3176
3255
|
opts.editorCmd
|
|
3177
|
-
)}\x07${
|
|
3178
|
-
console.info(
|
|
3179
|
-
` - branch#${br.id} @ ${link} missed paths: [${br.zeroPaths.join(
|
|
3180
|
-
", "
|
|
3181
|
-
)}]`
|
|
3182
|
-
);
|
|
3256
|
+
)}\x07${path8.basename(abs)}:${br.line}\x1B]8;;\x07`;
|
|
3257
|
+
console.info(` - branch#${br.id} @ ${link} missed paths: [${br.zeroPaths.join(", ")}]`);
|
|
3183
3258
|
}
|
|
3184
3259
|
}
|
|
3185
3260
|
console.info("");
|
|
@@ -3199,7 +3274,7 @@ var printCompactCoverage = async (opts) => {
|
|
|
3199
3274
|
for (const abs of files.slice(0, fileCap)) {
|
|
3200
3275
|
const fc = opts.map.fileCoverageFor(abs);
|
|
3201
3276
|
const sum = fc.toSummary();
|
|
3202
|
-
const rel =
|
|
3277
|
+
const rel = path8.relative(opts.root, abs).replace(/\\/g, "/");
|
|
3203
3278
|
const compareRangesByLengthDescThenStart = (firstRange, secondRange) => {
|
|
3204
3279
|
const secondLength = secondRange.end - secondRange.start;
|
|
3205
3280
|
const firstLength = firstRange.end - firstRange.start;
|
|
@@ -3213,9 +3288,9 @@ var printCompactCoverage = async (opts) => {
|
|
|
3213
3288
|
const branchesPctText = `${sum.branches.pct.toFixed(1)}%`;
|
|
3214
3289
|
const header = `${ansi.bold(rel)} lines ${tintPct(sum.lines.pct)(
|
|
3215
3290
|
linesPctText
|
|
3216
|
-
)} ${barCell(compositeBarPct(sum, blocks))("".padEnd(14))} funcs ${tintPct(
|
|
3217
|
-
|
|
3218
|
-
)
|
|
3291
|
+
)} ${barCell(compositeBarPct(sum, blocks))("".padEnd(14))} funcs ${tintPct(sum.functions.pct)(
|
|
3292
|
+
funcsPctText
|
|
3293
|
+
)} branches ${tintPct(sum.branches.pct)(branchesPctText)}`;
|
|
3219
3294
|
console.info(header);
|
|
3220
3295
|
const hotspots = blocks.slice(0, maxHotspotsDerived);
|
|
3221
3296
|
if (hotspots.length) {
|
|
@@ -3226,10 +3301,8 @@ var printCompactCoverage = async (opts) => {
|
|
|
3226
3301
|
abs,
|
|
3227
3302
|
hotspot.start,
|
|
3228
3303
|
opts.editorCmd
|
|
3229
|
-
)}\x07${
|
|
3230
|
-
console.info(
|
|
3231
|
-
` - L${hotspot.start}\u2013L${hotspot.end} (${len} lines) ${link}`
|
|
3232
|
-
);
|
|
3304
|
+
)}\x07${path8.basename(abs)}:${hotspot.start}\x1B]8;;\x07`;
|
|
3305
|
+
console.info(` - L${hotspot.start}\u2013L${hotspot.end} (${len} lines) ${link}`);
|
|
3233
3306
|
}
|
|
3234
3307
|
}
|
|
3235
3308
|
const functionsList = missFns.slice(0, maxFunctionsDerived);
|
|
@@ -3241,7 +3314,7 @@ var printCompactCoverage = async (opts) => {
|
|
|
3241
3314
|
abs,
|
|
3242
3315
|
fn.line,
|
|
3243
3316
|
opts.editorCmd
|
|
3244
|
-
)}\x07${
|
|
3317
|
+
)}\x07${path8.basename(abs)}:${fn.line}\x1B]8;;\x07`
|
|
3245
3318
|
);
|
|
3246
3319
|
}
|
|
3247
3320
|
}
|
|
@@ -3256,7 +3329,7 @@ var printCompactCoverage = async (opts) => {
|
|
|
3256
3329
|
abs,
|
|
3257
3330
|
br.line,
|
|
3258
3331
|
opts.editorCmd
|
|
3259
|
-
)}\x07${
|
|
3332
|
+
)}\x07${path8.basename(abs)}:${br.line}\x1B]8;;\x07`
|
|
3260
3333
|
);
|
|
3261
3334
|
}
|
|
3262
3335
|
}
|
|
@@ -3265,9 +3338,7 @@ var printCompactCoverage = async (opts) => {
|
|
|
3265
3338
|
const restBrs = Math.max(0, misses.length - branchesList.length);
|
|
3266
3339
|
if (restHs + restFns + restBrs > 0) {
|
|
3267
3340
|
console.info(
|
|
3268
|
-
ansi.dim(
|
|
3269
|
-
` \u2026 truncated: +${restHs} hotspots, +${restFns} funcs, +${restBrs} branches`
|
|
3270
|
-
)
|
|
3341
|
+
ansi.dim(` \u2026 truncated: +${restHs} hotspots, +${restFns} funcs, +${restBrs} branches`)
|
|
3271
3342
|
);
|
|
3272
3343
|
}
|
|
3273
3344
|
console.info("");
|
|
@@ -3304,7 +3375,7 @@ var shortenPathPreservingFilename = (relPath, maxWidth, opts) => {
|
|
|
3304
3375
|
return { stem: base.slice(0, -ending.length), ext: ending };
|
|
3305
3376
|
}
|
|
3306
3377
|
}
|
|
3307
|
-
const ext2 =
|
|
3378
|
+
const ext2 = path8.extname(base);
|
|
3308
3379
|
return { stem: base.slice(0, -ext2.length), ext: ext2 };
|
|
3309
3380
|
};
|
|
3310
3381
|
const sliceBalanced = (input, width) => {
|
|
@@ -3387,12 +3458,7 @@ var shortenPathPreservingFilename = (relPath, maxWidth, opts) => {
|
|
|
3387
3458
|
const tailParts = tailSrc.map((segment) => segment);
|
|
3388
3459
|
let hidAny = false;
|
|
3389
3460
|
const build = () => {
|
|
3390
|
-
const label2 = joinParts(
|
|
3391
|
-
headParts,
|
|
3392
|
-
tailParts,
|
|
3393
|
-
hideMiddle2 || hidAny,
|
|
3394
|
-
baseLabel
|
|
3395
|
-
);
|
|
3461
|
+
const label2 = joinParts(headParts, tailParts, hideMiddle2 || hidAny, baseLabel);
|
|
3396
3462
|
return { label: label2, width: visibleWidth(label2) };
|
|
3397
3463
|
};
|
|
3398
3464
|
let { label, width } = build();
|
|
@@ -3485,13 +3551,7 @@ var shortenPathPreservingFilename = (relPath, maxWidth, opts) => {
|
|
|
3485
3551
|
return { headRaw: headRaw2, tailRaw: tailRaw2, hideMiddle: hideMiddle2 };
|
|
3486
3552
|
};
|
|
3487
3553
|
let { headRaw, tailRaw, hideMiddle } = buildRaw(headCount, tailCount);
|
|
3488
|
-
let candidate = tryTrimDirsToFit(
|
|
3489
|
-
headRaw,
|
|
3490
|
-
tailRaw,
|
|
3491
|
-
hideMiddle,
|
|
3492
|
-
baseFull,
|
|
3493
|
-
maxWidth
|
|
3494
|
-
);
|
|
3554
|
+
let candidate = tryTrimDirsToFit(headRaw, tailRaw, hideMiddle, baseFull, maxWidth);
|
|
3495
3555
|
if (!candidate) {
|
|
3496
3556
|
return baseFull;
|
|
3497
3557
|
}
|
|
@@ -3500,13 +3560,7 @@ var shortenPathPreservingFilename = (relPath, maxWidth, opts) => {
|
|
|
3500
3560
|
if (headCount + tailCount < total) {
|
|
3501
3561
|
const tryTail = Math.min(tailCount + 1, total - headCount);
|
|
3502
3562
|
({ headRaw, tailRaw, hideMiddle } = buildRaw(headCount, tryTail));
|
|
3503
|
-
const candTail = tryTrimDirsToFit(
|
|
3504
|
-
headRaw,
|
|
3505
|
-
tailRaw,
|
|
3506
|
-
hideMiddle,
|
|
3507
|
-
baseFull,
|
|
3508
|
-
maxWidth
|
|
3509
|
-
);
|
|
3563
|
+
const candTail = tryTrimDirsToFit(headRaw, tailRaw, hideMiddle, baseFull, maxWidth);
|
|
3510
3564
|
if (candTail) {
|
|
3511
3565
|
tailCount = tryTail;
|
|
3512
3566
|
candidate = candTail;
|
|
@@ -3516,13 +3570,7 @@ var shortenPathPreservingFilename = (relPath, maxWidth, opts) => {
|
|
|
3516
3570
|
if (!advanced && headCount + tailCount < total) {
|
|
3517
3571
|
const tryHead = Math.min(headCount + 1, total - tailCount);
|
|
3518
3572
|
({ headRaw, tailRaw, hideMiddle } = buildRaw(tryHead, tailCount));
|
|
3519
|
-
const candHead = tryTrimDirsToFit(
|
|
3520
|
-
headRaw,
|
|
3521
|
-
tailRaw,
|
|
3522
|
-
hideMiddle,
|
|
3523
|
-
baseFull,
|
|
3524
|
-
maxWidth
|
|
3525
|
-
);
|
|
3573
|
+
const candHead = tryTrimDirsToFit(headRaw, tailRaw, hideMiddle, baseFull, maxWidth);
|
|
3526
3574
|
if (candHead) {
|
|
3527
3575
|
headCount = tryHead;
|
|
3528
3576
|
candidate = candHead;
|
|
@@ -3584,7 +3632,7 @@ var buildDistanceMapFromTests = async (executedTestsAbs, rootDir) => {
|
|
|
3584
3632
|
const queue = [];
|
|
3585
3633
|
const seen = /* @__PURE__ */ new Set();
|
|
3586
3634
|
for (const testAbs of executedTestsAbs) {
|
|
3587
|
-
const testPathNormalized =
|
|
3635
|
+
const testPathNormalized = path8.resolve(testAbs).replace(/\\/g, "/");
|
|
3588
3636
|
dist.set(testPathNormalized, 0);
|
|
3589
3637
|
queue.push([testPathNormalized, 0]);
|
|
3590
3638
|
}
|
|
@@ -3603,12 +3651,7 @@ var buildDistanceMapFromTests = async (executedTestsAbs, rootDir) => {
|
|
|
3603
3651
|
const specs = await extractImportSpecs2(currentFile, specsCache);
|
|
3604
3652
|
const nextDistance = currentDistance + 1;
|
|
3605
3653
|
for (const spec of specs) {
|
|
3606
|
-
const resolved = resolveImportWithRoot(
|
|
3607
|
-
currentFile,
|
|
3608
|
-
spec,
|
|
3609
|
-
rootDir,
|
|
3610
|
-
resolutionCache
|
|
3611
|
-
);
|
|
3654
|
+
const resolved = resolveImportWithRoot(currentFile, spec, rootDir, resolutionCache);
|
|
3612
3655
|
const usable = resolved && !resolved.includes("/node_modules/");
|
|
3613
3656
|
if (usable) {
|
|
3614
3657
|
const existing = dist.get(resolved);
|
|
@@ -3623,13 +3666,10 @@ var buildDistanceMapFromTests = async (executedTestsAbs, rootDir) => {
|
|
|
3623
3666
|
return dist;
|
|
3624
3667
|
};
|
|
3625
3668
|
var renderPerFileCompositeTable = async (opts) => {
|
|
3626
|
-
const rel =
|
|
3669
|
+
const rel = path8.relative(opts.root, opts.absPath).replace(/\\/g, "/");
|
|
3627
3670
|
const sum = opts.file.toSummary();
|
|
3628
3671
|
const rowsAvail = typeof process.stdout.rows === "number" && process.stdout.rows > 10 ? process.stdout.rows : 40;
|
|
3629
|
-
const tableBudget = Math.max(
|
|
3630
|
-
14,
|
|
3631
|
-
Math.min(opts.maxRows ?? rowsAvail - 1, rowsAvail + 8)
|
|
3632
|
-
);
|
|
3672
|
+
const tableBudget = Math.max(14, Math.min(opts.maxRows ?? rowsAvail - 1, rowsAvail + 8));
|
|
3633
3673
|
const rowBudget = Math.max(6, tableBudget - 6);
|
|
3634
3674
|
const blocks = computeUncoveredBlocks(opts.file).slice().sort((firstRange, secondRange) => {
|
|
3635
3675
|
const firstLength = firstRange.end - firstRange.start;
|
|
@@ -3673,9 +3713,7 @@ var renderPerFileCompositeTable = async (opts) => {
|
|
|
3673
3713
|
rows.push([
|
|
3674
3714
|
cell(
|
|
3675
3715
|
rel,
|
|
3676
|
-
(padded) => ansi.dim(
|
|
3677
|
-
shortenPathPreservingFilename(rel, padded.length).padEnd(padded.length)
|
|
3678
|
-
)
|
|
3716
|
+
(padded) => ansi.dim(shortenPathPreservingFilename(rel, padded.length).padEnd(padded.length))
|
|
3679
3717
|
),
|
|
3680
3718
|
cell("Totals", ansi.dim),
|
|
3681
3719
|
cell("\u2014", ansi.dim),
|
|
@@ -3694,11 +3732,7 @@ var renderPerFileCompositeTable = async (opts) => {
|
|
|
3694
3732
|
rows.push([
|
|
3695
3733
|
cell(
|
|
3696
3734
|
rel,
|
|
3697
|
-
(padded) => ansi.dim(
|
|
3698
|
-
shortenPathPreservingFilename(rel, padded.length).padEnd(
|
|
3699
|
-
padded.length
|
|
3700
|
-
)
|
|
3701
|
-
)
|
|
3735
|
+
(padded) => ansi.dim(shortenPathPreservingFilename(rel, padded.length).padEnd(padded.length))
|
|
3702
3736
|
),
|
|
3703
3737
|
cell("Hotspots", ansi.dim),
|
|
3704
3738
|
cell("", ansi.dim),
|
|
@@ -3712,14 +3746,8 @@ var renderPerFileCompositeTable = async (opts) => {
|
|
|
3712
3746
|
rows.push([
|
|
3713
3747
|
cell(rel, (padded) => {
|
|
3714
3748
|
const width = padded.length;
|
|
3715
|
-
const display = shortenPathPreservingFilename(rel, width).padEnd(
|
|
3716
|
-
|
|
3717
|
-
);
|
|
3718
|
-
return linkifyPadded(
|
|
3719
|
-
opts.absPath,
|
|
3720
|
-
hotspotRange.start,
|
|
3721
|
-
opts.editorCmd
|
|
3722
|
-
)(display);
|
|
3749
|
+
const display = shortenPathPreservingFilename(rel, width).padEnd(width);
|
|
3750
|
+
return linkifyPadded(opts.absPath, hotspotRange.start, opts.editorCmd)(display);
|
|
3723
3751
|
}),
|
|
3724
3752
|
cell("Hotspot"),
|
|
3725
3753
|
cell(`L${hotspotRange.start}\u2013L${hotspotRange.end}`),
|
|
@@ -3736,11 +3764,7 @@ var renderPerFileCompositeTable = async (opts) => {
|
|
|
3736
3764
|
rows.push([
|
|
3737
3765
|
cell(
|
|
3738
3766
|
rel,
|
|
3739
|
-
(padded) => ansi.dim(
|
|
3740
|
-
shortenPathPreservingFilename(rel, padded.length).padEnd(
|
|
3741
|
-
padded.length
|
|
3742
|
-
)
|
|
3743
|
-
)
|
|
3767
|
+
(padded) => ansi.dim(shortenPathPreservingFilename(rel, padded.length).padEnd(padded.length))
|
|
3744
3768
|
),
|
|
3745
3769
|
cell("Functions", ansi.dim),
|
|
3746
3770
|
cell("", ansi.dim),
|
|
@@ -3754,14 +3778,8 @@ var renderPerFileCompositeTable = async (opts) => {
|
|
|
3754
3778
|
rows.push([
|
|
3755
3779
|
cell(rel, (padded) => {
|
|
3756
3780
|
const width = padded.length;
|
|
3757
|
-
const display = shortenPathPreservingFilename(rel, width).padEnd(
|
|
3758
|
-
|
|
3759
|
-
);
|
|
3760
|
-
return linkifyPadded(
|
|
3761
|
-
opts.absPath,
|
|
3762
|
-
missedFunction.line,
|
|
3763
|
-
opts.editorCmd
|
|
3764
|
-
)(display);
|
|
3781
|
+
const display = shortenPathPreservingFilename(rel, width).padEnd(width);
|
|
3782
|
+
return linkifyPadded(opts.absPath, missedFunction.line, opts.editorCmd)(display);
|
|
3765
3783
|
}),
|
|
3766
3784
|
cell("Func"),
|
|
3767
3785
|
cell(`L${missedFunction.line}`),
|
|
@@ -3778,11 +3796,7 @@ var renderPerFileCompositeTable = async (opts) => {
|
|
|
3778
3796
|
rows.push([
|
|
3779
3797
|
cell(
|
|
3780
3798
|
rel,
|
|
3781
|
-
(padded) => ansi.dim(
|
|
3782
|
-
shortenPathPreservingFilename(rel, padded.length).padEnd(
|
|
3783
|
-
padded.length
|
|
3784
|
-
)
|
|
3785
|
-
)
|
|
3799
|
+
(padded) => ansi.dim(shortenPathPreservingFilename(rel, padded.length).padEnd(padded.length))
|
|
3786
3800
|
),
|
|
3787
3801
|
cell("Branches", ansi.dim),
|
|
3788
3802
|
cell("", ansi.dim),
|
|
@@ -3796,14 +3810,8 @@ var renderPerFileCompositeTable = async (opts) => {
|
|
|
3796
3810
|
rows.push([
|
|
3797
3811
|
cell(rel, (padded) => {
|
|
3798
3812
|
const width = padded.length;
|
|
3799
|
-
const display = shortenPathPreservingFilename(rel, width).padEnd(
|
|
3800
|
-
|
|
3801
|
-
);
|
|
3802
|
-
return linkifyPadded(
|
|
3803
|
-
opts.absPath,
|
|
3804
|
-
missedBranch.line,
|
|
3805
|
-
opts.editorCmd
|
|
3806
|
-
)(display);
|
|
3813
|
+
const display = shortenPathPreservingFilename(rel, width).padEnd(width);
|
|
3814
|
+
return linkifyPadded(opts.absPath, missedBranch.line, opts.editorCmd)(display);
|
|
3807
3815
|
}),
|
|
3808
3816
|
cell("Branch"),
|
|
3809
3817
|
cell(`L${missedBranch.line}`),
|
|
@@ -3811,9 +3819,7 @@ var renderPerFileCompositeTable = async (opts) => {
|
|
|
3811
3819
|
cell(""),
|
|
3812
3820
|
cell(""),
|
|
3813
3821
|
cell(""),
|
|
3814
|
-
cell(
|
|
3815
|
-
`#${missedBranch.id} missed [${missedBranch.zeroPaths.join(", ")}]`
|
|
3816
|
-
)
|
|
3822
|
+
cell(`#${missedBranch.id} missed [${missedBranch.zeroPaths.join(", ")}]`)
|
|
3817
3823
|
]);
|
|
3818
3824
|
}
|
|
3819
3825
|
}
|
|
@@ -3833,9 +3839,7 @@ var renderPerFileCompositeTable = async (opts) => {
|
|
|
3833
3839
|
rows.push([
|
|
3834
3840
|
cell(rel, (padded) => {
|
|
3835
3841
|
const width = padded.length;
|
|
3836
|
-
const display = shortenPathPreservingFilename(rel, width).padEnd(
|
|
3837
|
-
width
|
|
3838
|
-
);
|
|
3842
|
+
const display = shortenPathPreservingFilename(rel, width).padEnd(width);
|
|
3839
3843
|
return linkifyPadded(opts.absPath, ln, opts.editorCmd)(display);
|
|
3840
3844
|
}),
|
|
3841
3845
|
cell("Line"),
|
|
@@ -3848,16 +3852,7 @@ var renderPerFileCompositeTable = async (opts) => {
|
|
|
3848
3852
|
]);
|
|
3849
3853
|
}
|
|
3850
3854
|
while (rows.length < target) {
|
|
3851
|
-
rows.push([
|
|
3852
|
-
cell(""),
|
|
3853
|
-
cell(""),
|
|
3854
|
-
cell(""),
|
|
3855
|
-
cell(""),
|
|
3856
|
-
cell(""),
|
|
3857
|
-
cell(""),
|
|
3858
|
-
cell(""),
|
|
3859
|
-
cell("")
|
|
3860
|
-
]);
|
|
3855
|
+
rows.push([cell(""), cell(""), cell(""), cell(""), cell(""), cell(""), cell(""), cell("")]);
|
|
3861
3856
|
}
|
|
3862
3857
|
}
|
|
3863
3858
|
}
|
|
@@ -3865,20 +3860,17 @@ var renderPerFileCompositeTable = async (opts) => {
|
|
|
3865
3860
|
console.info(table);
|
|
3866
3861
|
const sep = ansi.gray(
|
|
3867
3862
|
"\u2500".repeat(
|
|
3868
|
-
Math.max(
|
|
3869
|
-
20,
|
|
3870
|
-
typeof process.stdout.columns === "number" ? process.stdout.columns : 100
|
|
3871
|
-
)
|
|
3863
|
+
Math.max(20, typeof process.stdout.columns === "number" ? process.stdout.columns : 100)
|
|
3872
3864
|
)
|
|
3873
3865
|
);
|
|
3874
3866
|
console.info(sep);
|
|
3875
3867
|
};
|
|
3876
3868
|
var printPerFileCompositeTables = async (opts) => {
|
|
3877
3869
|
const selectionAbs = (opts.selectionPaths ?? []).map(
|
|
3878
|
-
(selPath) =>
|
|
3870
|
+
(selPath) => path8.resolve(selPath).replace(/\\/g, "/")
|
|
3879
3871
|
);
|
|
3880
3872
|
const changedAbs = (opts.changedFiles ?? []).map(
|
|
3881
|
-
(chgPath) =>
|
|
3873
|
+
(chgPath) => path8.resolve(chgPath).replace(/\\/g, "/")
|
|
3882
3874
|
);
|
|
3883
3875
|
const tokenizeForSimilarity = (filePathForTokens) => new Set(
|
|
3884
3876
|
filePathForTokens.toLowerCase().replace(/[^a-z0-9/_\-.]/g, " ").split(/[/_.-]+/).filter(Boolean)
|
|
@@ -3894,15 +3886,15 @@ var printPerFileCompositeTables = async (opts) => {
|
|
|
3894
3886
|
return intersectionCount / unionSize;
|
|
3895
3887
|
};
|
|
3896
3888
|
const isSameDirOrChild = (firstAbs, secondAbs) => {
|
|
3897
|
-
const dirA =
|
|
3898
|
-
const dirB =
|
|
3889
|
+
const dirA = path8.dirname(firstAbs).replace(/\\/g, "/");
|
|
3890
|
+
const dirB = path8.dirname(secondAbs).replace(/\\/g, "/");
|
|
3899
3891
|
return dirA === dirB || dirB.startsWith(`${dirA}/`) || dirA.startsWith(`${dirB}/`);
|
|
3900
3892
|
};
|
|
3901
3893
|
const selectionTokens = selectionAbs.map(tokenizeForSimilarity);
|
|
3902
3894
|
const changedTokens = changedAbs.map(tokenizeForSimilarity);
|
|
3903
|
-
const executedTestsAbs = (opts.executedTests ?? []).map((testPath) =>
|
|
3895
|
+
const executedTestsAbs = (opts.executedTests ?? []).map((testPath) => path8.resolve(testPath).replace(/\\/g, "/")).filter((absPath) => absPath.length > 0);
|
|
3904
3896
|
const testTokens = executedTestsAbs.map(tokenizeForSimilarity);
|
|
3905
|
-
const allMapFilesAbs = opts.map.files().map((absPath) =>
|
|
3897
|
+
const allMapFilesAbs = opts.map.files().map((absPath) => path8.resolve(absPath).replace(/\\/g, "/"));
|
|
3906
3898
|
const uncoveredCandidates = allMapFilesAbs.filter((absPath) => {
|
|
3907
3899
|
const sum = opts.map.fileCoverageFor(absPath).toSummary();
|
|
3908
3900
|
return !(sum.lines.pct >= 100 && sum.functions.pct >= 100 && sum.branches.pct >= 100);
|
|
@@ -3919,33 +3911,24 @@ var printPerFileCompositeTables = async (opts) => {
|
|
|
3919
3911
|
const selectionSetAbs = new Set(selectionAbs);
|
|
3920
3912
|
const scored = await Promise.all(
|
|
3921
3913
|
candidates.map(async (abs) => {
|
|
3922
|
-
const rel =
|
|
3914
|
+
const rel = path8.relative(opts.root, abs).replace(/\\/g, "/");
|
|
3923
3915
|
const sum = opts.map.fileCoverageFor(abs).toSummary();
|
|
3924
3916
|
const pct = Number.isFinite(sum.lines.pct) ? sum.lines.pct : 0;
|
|
3925
|
-
const absNorm =
|
|
3917
|
+
const absNorm = path8.resolve(abs).replace(/\\/g, "/");
|
|
3926
3918
|
const selfTokens = tokenizeForSimilarity(absNorm);
|
|
3927
3919
|
const selSim = Math.max(
|
|
3928
3920
|
0,
|
|
3929
|
-
...selectionTokens.map(
|
|
3930
|
-
(selectionTokenSet) => jaccard(selfTokens, selectionTokenSet)
|
|
3931
|
-
)
|
|
3921
|
+
...selectionTokens.map((selectionTokenSet) => jaccard(selfTokens, selectionTokenSet))
|
|
3932
3922
|
);
|
|
3933
3923
|
const chgSim = Math.max(
|
|
3934
3924
|
0,
|
|
3935
|
-
...changedTokens.map(
|
|
3936
|
-
(changedTokenSet) => jaccard(selfTokens, changedTokenSet)
|
|
3937
|
-
)
|
|
3938
|
-
);
|
|
3939
|
-
const tstSim = Math.max(
|
|
3940
|
-
0,
|
|
3941
|
-
...testTokens.map((tset) => jaccard(selfTokens, tset))
|
|
3925
|
+
...changedTokens.map((changedTokenSet) => jaccard(selfTokens, changedTokenSet))
|
|
3942
3926
|
);
|
|
3927
|
+
const tstSim = Math.max(0, ...testTokens.map((tset) => jaccard(selfTokens, tset)));
|
|
3943
3928
|
const nearSelection = selectionAbs.some(
|
|
3944
3929
|
(selectionPath) => isSameDirOrChild(absNorm, selectionPath)
|
|
3945
3930
|
);
|
|
3946
|
-
const nearChanged = changedAbs.some(
|
|
3947
|
-
(changedPath) => isSameDirOrChild(absNorm, changedPath)
|
|
3948
|
-
);
|
|
3931
|
+
const nearChanged = changedAbs.some((changedPath) => isSameDirOrChild(absNorm, changedPath));
|
|
3949
3932
|
const related = selSim > 0 || chgSim > 0 || nearSelection || nearChanged;
|
|
3950
3933
|
const distance = selectionSetAbs.has(absNorm) ? 0 : distFromTests.get(absNorm) ?? INF;
|
|
3951
3934
|
let group = 6;
|
|
@@ -3969,9 +3952,12 @@ var printPerFileCompositeTables = async (opts) => {
|
|
|
3969
3952
|
return { abs: absNorm, rel, linesPct: pct, group, score, distance };
|
|
3970
3953
|
})
|
|
3971
3954
|
);
|
|
3972
|
-
|
|
3973
|
-
|
|
3974
|
-
|
|
3955
|
+
const prodSeeds = selectionAbs.length > 0 ? selectionAbs : changedAbs;
|
|
3956
|
+
const rank = await computeDirectnessRank({ repoRoot: opts.root, productionSeeds: prodSeeds });
|
|
3957
|
+
let files = sortPathsWithRank(
|
|
3958
|
+
rank,
|
|
3959
|
+
scored.map((s) => s.abs)
|
|
3960
|
+
);
|
|
3975
3961
|
if (selectionAbs.length > 0) {
|
|
3976
3962
|
const selectionSet = new Set(selectionAbs);
|
|
3977
3963
|
const selectedHead = files.filter((filePath) => selectionSet.has(filePath));
|
|
@@ -3994,7 +3980,7 @@ var printPerFileCompositeTables = async (opts) => {
|
|
|
3994
3980
|
};
|
|
3995
3981
|
|
|
3996
3982
|
// src/lib/jest-bridge.ts
|
|
3997
|
-
var
|
|
3983
|
+
var path9 = __toESM(require("node:path"), 1);
|
|
3998
3984
|
var fs4 = __toESM(require("node:fs"), 1);
|
|
3999
3985
|
var util = __toESM(require("node:util"), 1);
|
|
4000
3986
|
var import_json5 = __toESM(require_lib(), 1);
|
|
@@ -4069,7 +4055,7 @@ var extractBridgePath = (raw, cwd) => {
|
|
|
4069
4055
|
return null;
|
|
4070
4056
|
}
|
|
4071
4057
|
const jsonPath = matches[matches.length - 1][1].trim().replace(/^["'`]|["'`]$/g, "");
|
|
4072
|
-
return
|
|
4058
|
+
return path9.isAbsolute(jsonPath) ? jsonPath : path9.resolve(cwd, jsonPath);
|
|
4073
4059
|
};
|
|
4074
4060
|
var drawRule = (label) => {
|
|
4075
4061
|
const width = Math.max(
|
|
@@ -4668,7 +4654,7 @@ var buildStackSection = (mergedForStack, ctx, fallbackLoc) => {
|
|
|
4668
4654
|
const loc = deepestProjectLoc(mergedForStack, ctx.projectHint);
|
|
4669
4655
|
if (loc) {
|
|
4670
4656
|
const href = preferredEditorHref(loc.file, loc.line, ctx.editorCmd);
|
|
4671
|
-
out.push(` ${ansi.dim("at")} ${osc8(`${
|
|
4657
|
+
out.push(` ${ansi.dim("at")} ${osc8(`${path9.basename(loc.file)}:${loc.line}`, href)}`);
|
|
4672
4658
|
}
|
|
4673
4659
|
out.push("");
|
|
4674
4660
|
return out;
|
|
@@ -4947,7 +4933,7 @@ function renderVitestFromJestJSON(data, opts) {
|
|
|
4947
4933
|
const deepestLoc = deepestProjectLoc(mergedForStack, projectHint);
|
|
4948
4934
|
const locLink = deepestLoc && (() => {
|
|
4949
4935
|
const href = preferredEditorHref(deepestLoc.file, deepestLoc.line, opts?.editorCmd);
|
|
4950
|
-
const base = `${
|
|
4936
|
+
const base = `${path9.basename(deepestLoc.file)}:${deepestLoc.line}`;
|
|
4951
4937
|
return osc8(base, href);
|
|
4952
4938
|
})();
|
|
4953
4939
|
const headerLine = `${ansi.white(header)}${locLink ? ` ${ansi.dim(`(${locLink})`)}` : ""}`;
|
|
@@ -4992,13 +4978,8 @@ ${footer}`;
|
|
|
4992
4978
|
}
|
|
4993
4979
|
|
|
4994
4980
|
// src/lib/program.ts
|
|
4995
|
-
var import_meta = {};
|
|
4996
4981
|
var jestBin = "./node_modules/.bin/jest";
|
|
4997
4982
|
var babelNodeBin = "./node_modules/.bin/babel-node";
|
|
4998
|
-
var moduleSpecifierForRequire = (
|
|
4999
|
-
// @ts-ignore
|
|
5000
|
-
typeof __filename !== "undefined" ? __filename : import_meta.url
|
|
5001
|
-
);
|
|
5002
4983
|
var registerSignalHandlersOnce = () => {
|
|
5003
4984
|
let handled = false;
|
|
5004
4985
|
const on = (sig) => {
|
|
@@ -5016,7 +4997,6 @@ Received ${sig}, exiting...
|
|
|
5016
4997
|
};
|
|
5017
4998
|
var isDebug = () => Boolean(process.env.TEST_CLI_DEBUG);
|
|
5018
4999
|
var mergeLcov = async () => {
|
|
5019
|
-
const jestLcovPath = "coverage/jest/lcov.info";
|
|
5020
5000
|
const vitestLcovPath = "coverage/vitest/lcov.info";
|
|
5021
5001
|
const mergedOutPath = "coverage/lcov.info";
|
|
5022
5002
|
const readOrEmpty = async (filePath) => {
|
|
@@ -5027,7 +5007,7 @@ var mergeLcov = async () => {
|
|
|
5027
5007
|
}
|
|
5028
5008
|
};
|
|
5029
5009
|
let vitestContent = "";
|
|
5030
|
-
|
|
5010
|
+
const jestParts = [];
|
|
5031
5011
|
try {
|
|
5032
5012
|
vitestContent = await readOrEmpty(vitestLcovPath);
|
|
5033
5013
|
} catch (readVitestError) {
|
|
@@ -5035,20 +5015,46 @@ var mergeLcov = async () => {
|
|
|
5035
5015
|
console.info(`read vitest lcov failed: ${String(readVitestError)}`);
|
|
5036
5016
|
}
|
|
5037
5017
|
}
|
|
5018
|
+
const collectLcovs = (dir) => {
|
|
5019
|
+
const out = [];
|
|
5020
|
+
try {
|
|
5021
|
+
const entries = fsSync3.readdirSync(dir, { withFileTypes: true });
|
|
5022
|
+
for (const entry of entries) {
|
|
5023
|
+
const full = path10.join(dir, entry.name);
|
|
5024
|
+
if (entry.isDirectory()) {
|
|
5025
|
+
out.push(...collectLcovs(full));
|
|
5026
|
+
} else if (entry.isFile() && entry.name === "lcov.info") {
|
|
5027
|
+
out.push(full);
|
|
5028
|
+
}
|
|
5029
|
+
}
|
|
5030
|
+
} catch {
|
|
5031
|
+
}
|
|
5032
|
+
return out;
|
|
5033
|
+
};
|
|
5038
5034
|
try {
|
|
5039
|
-
|
|
5035
|
+
const jestRoot = path10.join("coverage", "jest");
|
|
5036
|
+
const candidates = [path10.join(jestRoot, "lcov.info"), ...collectLcovs(jestRoot)].map((candidatePath) => path10.resolve(candidatePath)).filter((absolutePath, index, arr) => arr.indexOf(absolutePath) === index);
|
|
5037
|
+
for (const filePath of candidates) {
|
|
5038
|
+
try {
|
|
5039
|
+
const content = await readOrEmpty(filePath);
|
|
5040
|
+
if (content.trim()) {
|
|
5041
|
+
jestParts.push(content.trim());
|
|
5042
|
+
}
|
|
5043
|
+
} catch {
|
|
5044
|
+
}
|
|
5045
|
+
}
|
|
5040
5046
|
} catch (readJestError) {
|
|
5041
5047
|
if (isDebug()) {
|
|
5042
|
-
console.info(`
|
|
5048
|
+
console.info(`scan jest lcov failed: ${String(readJestError)}`);
|
|
5043
5049
|
}
|
|
5044
5050
|
}
|
|
5045
|
-
if (!vitestContent &&
|
|
5051
|
+
if (!vitestContent && jestParts.length === 0) {
|
|
5046
5052
|
if (isDebug()) {
|
|
5047
5053
|
console.info("No coverage outputs found to merge.");
|
|
5048
5054
|
}
|
|
5049
5055
|
return;
|
|
5050
5056
|
}
|
|
5051
|
-
const merged = [vitestContent.trim(),
|
|
5057
|
+
const merged = [vitestContent.trim(), ...jestParts].filter(Boolean).join("\n");
|
|
5052
5058
|
if (merged.length > 0) {
|
|
5053
5059
|
await (await import("node:fs/promises")).mkdir("coverage", { recursive: true });
|
|
5054
5060
|
await (await import("node:fs/promises")).writeFile(mergedOutPath, `${merged}
|
|
@@ -5061,23 +5067,40 @@ var mergeLcov = async () => {
|
|
|
5061
5067
|
}
|
|
5062
5068
|
};
|
|
5063
5069
|
var emitMergedCoverage = async (ui, opts) => {
|
|
5064
|
-
const jestJson = path9.join("coverage", "jest", "coverage-final.json");
|
|
5065
|
-
const jSize = fsSync3.existsSync(jestJson) ? fsSync3.statSync(jestJson).size : -1;
|
|
5066
|
-
const jestSizeLabel = jSize >= 0 ? `${jSize} bytes` : "missing";
|
|
5067
|
-
if (isDebug()) {
|
|
5068
|
-
console.info(`Coverage JSON probe \u2192 jest: ${jestSizeLabel}`);
|
|
5069
|
-
}
|
|
5070
|
-
const jestData = await readCoverageJson(jestJson);
|
|
5071
|
-
const jestFilesCount = Object.keys(jestData).length;
|
|
5072
|
-
if (isDebug()) {
|
|
5073
|
-
console.info(`Decoded coverage entries \u2192 jest: ${jestFilesCount}`);
|
|
5074
|
-
}
|
|
5075
5070
|
const map = (0, import_istanbul_lib_coverage2.createCoverageMap)({});
|
|
5076
|
-
|
|
5071
|
+
const listJsons = (dir) => {
|
|
5072
|
+
const out = [];
|
|
5073
|
+
try {
|
|
5074
|
+
const entries = fsSync3.readdirSync(dir, { withFileTypes: true });
|
|
5075
|
+
for (const entry of entries) {
|
|
5076
|
+
const full = path10.join(dir, entry.name);
|
|
5077
|
+
if (entry.isDirectory()) {
|
|
5078
|
+
out.push(...listJsons(full));
|
|
5079
|
+
} else if (entry.isFile() && entry.name === "coverage-final.json") {
|
|
5080
|
+
out.push(full);
|
|
5081
|
+
}
|
|
5082
|
+
}
|
|
5083
|
+
} catch {
|
|
5084
|
+
}
|
|
5085
|
+
return out;
|
|
5086
|
+
};
|
|
5087
|
+
const coverageRoot = path10.join("coverage", "jest");
|
|
5088
|
+
const jsonCandidates = [
|
|
5089
|
+
path10.join(coverageRoot, "coverage-final.json"),
|
|
5090
|
+
...listJsons(coverageRoot)
|
|
5091
|
+
].map((candidatePath) => path10.resolve(candidatePath)).filter((absolutePath, index, arr) => {
|
|
5092
|
+
const isFirst = arr.indexOf(absolutePath) === index;
|
|
5093
|
+
const exists = fsSync3.existsSync(absolutePath);
|
|
5094
|
+
return isFirst && exists;
|
|
5095
|
+
});
|
|
5096
|
+
for (const jsonPath of jsonCandidates) {
|
|
5077
5097
|
try {
|
|
5078
|
-
|
|
5098
|
+
const data = await readCoverageJson(jsonPath);
|
|
5099
|
+
if (Object.keys(data).length) {
|
|
5100
|
+
map.merge(data);
|
|
5101
|
+
}
|
|
5079
5102
|
} catch (mergeJestError) {
|
|
5080
|
-
console.warn(`Failed merging jest coverage JSON: ${String(mergeJestError)}`);
|
|
5103
|
+
console.warn(`Failed merging jest coverage JSON @ ${jsonPath}: ${String(mergeJestError)}`);
|
|
5081
5104
|
}
|
|
5082
5105
|
}
|
|
5083
5106
|
if (map.files().length === 0) {
|
|
@@ -5127,11 +5150,14 @@ var emitMergedCoverage = async (ui, opts) => {
|
|
|
5127
5150
|
executedTests: opts.executedTests ?? []
|
|
5128
5151
|
});
|
|
5129
5152
|
const context = LibReport.createContext({
|
|
5130
|
-
dir:
|
|
5153
|
+
dir: path10.resolve("coverage", "merged"),
|
|
5131
5154
|
coverageMap: filteredMap,
|
|
5132
5155
|
defaultSummarizer: "nested"
|
|
5133
5156
|
});
|
|
5134
|
-
const reporters = ui === "jest" ? [
|
|
5157
|
+
const reporters = ui === "jest" ? [Reports.create("text", { file: "coverage.txt" })] : [
|
|
5158
|
+
Reports.create("text", { file: "coverage.txt" }),
|
|
5159
|
+
Reports.create("text-summary", { file: "coverage-summary.txt" })
|
|
5160
|
+
];
|
|
5135
5161
|
const colorizeIstanbulLine = (lineText) => {
|
|
5136
5162
|
const separator = /^[-=\s]+$/;
|
|
5137
5163
|
if (separator.test(lineText.trim())) {
|
|
@@ -5192,8 +5218,8 @@ var emitMergedCoverage = async (ui, opts) => {
|
|
|
5192
5218
|
for (const reporter of reporters) {
|
|
5193
5219
|
reporter.execute(context);
|
|
5194
5220
|
}
|
|
5195
|
-
const textPath =
|
|
5196
|
-
const summaryPath =
|
|
5221
|
+
const textPath = path10.resolve("coverage", "merged", "coverage.txt");
|
|
5222
|
+
const summaryPath = path10.resolve("coverage", "merged", "coverage-summary.txt");
|
|
5197
5223
|
const filesToPrint = [];
|
|
5198
5224
|
if (fsSync3.existsSync(textPath)) {
|
|
5199
5225
|
filesToPrint.push(textPath);
|
|
@@ -5218,7 +5244,7 @@ var emitMergedCoverage = async (ui, opts) => {
|
|
|
5218
5244
|
}
|
|
5219
5245
|
}
|
|
5220
5246
|
} else {
|
|
5221
|
-
const stdoutReporters = ui === "jest" ? [(
|
|
5247
|
+
const stdoutReporters = ui === "jest" ? [Reports.create("text", {})] : [Reports.create("text", {}), Reports.create("text-summary", {})];
|
|
5222
5248
|
for (const reporter of stdoutReporters) {
|
|
5223
5249
|
reporter.execute(context);
|
|
5224
5250
|
}
|
|
@@ -5275,17 +5301,43 @@ var program = async () => {
|
|
|
5275
5301
|
coverageMode,
|
|
5276
5302
|
coverageMaxFiles: coverageMaxFilesArg,
|
|
5277
5303
|
coverageMaxHotspots: coverageMaxHotspotsArg,
|
|
5278
|
-
coveragePageFit
|
|
5304
|
+
coveragePageFit,
|
|
5305
|
+
changed
|
|
5279
5306
|
} = deriveArgs(argv);
|
|
5280
|
-
|
|
5307
|
+
const getChangedFiles = async (mode, cwd) => {
|
|
5308
|
+
const collect = async (cmd, args) => {
|
|
5309
|
+
try {
|
|
5310
|
+
const out = await runText(cmd, args, {
|
|
5311
|
+
cwd,
|
|
5312
|
+
env: safeEnv(process.env, {}),
|
|
5313
|
+
timeoutMs: 4e3
|
|
5314
|
+
});
|
|
5315
|
+
return out.split(/\r?\n/).map((line) => line.trim()).filter(Boolean);
|
|
5316
|
+
} catch {
|
|
5317
|
+
return [];
|
|
5318
|
+
}
|
|
5319
|
+
};
|
|
5320
|
+
const staged = mode === "staged" || mode === "all" ? await collect("git", ["diff", "--name-only", "--diff-filter=ACMRTUXB", "--cached"]) : [];
|
|
5321
|
+
const unstagedTracked = mode === "unstaged" || mode === "all" ? await collect("git", ["diff", "--name-only", "--diff-filter=ACMRTUXB"]) : [];
|
|
5322
|
+
const untracked = mode === "unstaged" || mode === "all" ? await collect("git", ["ls-files", "--others", "--exclude-standard"]) : [];
|
|
5323
|
+
const rels = Array.from(/* @__PURE__ */ new Set([...staged, ...unstagedTracked, ...untracked]));
|
|
5324
|
+
return rels.map((rel) => path10.resolve(cwd, rel).replace(/\\/g, "/")).filter((abs) => !abs.includes("/node_modules/") && !abs.includes("/coverage/"));
|
|
5325
|
+
};
|
|
5326
|
+
const repoRootForChanged = workspaceRoot ?? await findRepoRoot();
|
|
5327
|
+
const changedSelectionAbs = changed ? await getChangedFiles(changed, repoRootForChanged) : [];
|
|
5328
|
+
const selectionPathsAugmented = changedSelectionAbs.length ? Array.from(/* @__PURE__ */ new Set([...selectionPaths, ...changedSelectionAbs])) : selectionPaths;
|
|
5329
|
+
const selectionSpecifiedAugmented = Boolean(selectionSpecified || changedSelectionAbs.length > 0);
|
|
5330
|
+
console.info(
|
|
5331
|
+
`Selection \u2192 specified=${selectionSpecifiedAugmented} paths=${selectionPathsAugmented.length}`
|
|
5332
|
+
);
|
|
5281
5333
|
const { jest } = argsForDiscovery(["run"], jestArgs);
|
|
5282
|
-
const selectionLooksLikeTest =
|
|
5334
|
+
const selectionLooksLikeTest = selectionPathsAugmented.some(
|
|
5283
5335
|
(pathText) => /\.(test|spec)\.[tj]sx?$/i.test(pathText) || /(^|\/)tests?\//i.test(pathText)
|
|
5284
5336
|
);
|
|
5285
|
-
const selectionLooksLikePath =
|
|
5337
|
+
const selectionLooksLikePath = selectionPathsAugmented.some(
|
|
5286
5338
|
(pathText) => /[\\/]/.test(pathText) || /\.(m?[tj]sx?)$/i.test(pathText)
|
|
5287
5339
|
);
|
|
5288
|
-
const selectionHasPaths =
|
|
5340
|
+
const selectionHasPaths = selectionPathsAugmented.length > 0;
|
|
5289
5341
|
const repoRootForDiscovery = workspaceRoot ?? await findRepoRoot();
|
|
5290
5342
|
const expandProductionSelections = async (tokens, repoRoot) => {
|
|
5291
5343
|
const results = /* @__PURE__ */ new Set();
|
|
@@ -5294,18 +5346,18 @@ var program = async () => {
|
|
|
5294
5346
|
if (!token) {
|
|
5295
5347
|
continue;
|
|
5296
5348
|
}
|
|
5297
|
-
const isAbs =
|
|
5349
|
+
const isAbs = path10.isAbsolute(token);
|
|
5298
5350
|
const looksLikeRelPath = /[\\/]/.test(token);
|
|
5299
5351
|
let candidateFromRoot;
|
|
5300
5352
|
if (token.startsWith("/")) {
|
|
5301
|
-
candidateFromRoot =
|
|
5353
|
+
candidateFromRoot = path10.join(repoRoot, token.slice(1));
|
|
5302
5354
|
} else if (looksLikeRelPath) {
|
|
5303
|
-
candidateFromRoot =
|
|
5355
|
+
candidateFromRoot = path10.join(repoRoot, token);
|
|
5304
5356
|
} else {
|
|
5305
5357
|
candidateFromRoot = void 0;
|
|
5306
5358
|
}
|
|
5307
5359
|
const tryPushIfProd = (absPath) => {
|
|
5308
|
-
const norm =
|
|
5360
|
+
const norm = path10.resolve(absPath).replace(/\\/g, "/");
|
|
5309
5361
|
const isTest = /(^|\/)tests?\//i.test(norm) || /\.(test|spec)\.[tj]sx?$/i.test(norm);
|
|
5310
5362
|
if (!isTest && fsSync3.existsSync(norm)) {
|
|
5311
5363
|
results.add(norm);
|
|
@@ -5327,7 +5379,7 @@ var program = async () => {
|
|
|
5327
5379
|
}),
|
|
5328
5380
|
timeoutMs: 4e3
|
|
5329
5381
|
});
|
|
5330
|
-
const matches = out.split(/\r?\n/).map((line) => line.trim()).filter(Boolean).map((rel) =>
|
|
5382
|
+
const matches = out.split(/\r?\n/).map((line) => line.trim()).filter(Boolean).map((rel) => path10.resolve(repoRoot, rel).replace(/\\/g, "/")).filter(
|
|
5331
5383
|
(abs) => !abs.includes("/node_modules/") && !abs.includes("/coverage/") && !/(^|\/)tests?\//i.test(abs) && !/\.(test|spec)\.[tj]sx?$/i.test(abs)
|
|
5332
5384
|
);
|
|
5333
5385
|
matches.forEach((abs) => results.add(abs));
|
|
@@ -5336,20 +5388,20 @@ var program = async () => {
|
|
|
5336
5388
|
}
|
|
5337
5389
|
return Array.from(results);
|
|
5338
5390
|
};
|
|
5339
|
-
const initialProdSelections =
|
|
5391
|
+
const initialProdSelections = selectionPathsAugmented.filter(
|
|
5340
5392
|
(pathText) => (/[\\/]/.test(pathText) || /\.(m?[tj]sx?)$/i.test(pathText)) && !/(^|\/)tests?\//i.test(pathText) && !/\.(test|spec)\.[tj]sx?$/i.test(pathText)
|
|
5341
5393
|
);
|
|
5342
|
-
const expandedProdSelections = initialProdSelections.length ? initialProdSelections : await expandProductionSelections(
|
|
5394
|
+
const expandedProdSelections = initialProdSelections.length ? initialProdSelections : await expandProductionSelections(selectionPathsAugmented, repoRootForDiscovery);
|
|
5343
5395
|
const selectionIncludesProdPaths = expandedProdSelections.length > 0;
|
|
5344
5396
|
console.info(
|
|
5345
5397
|
`Selection classify \u2192 looksLikePath=${selectionLooksLikePath} looksLikeTest=${selectionLooksLikeTest} prodPaths=${selectionIncludesProdPaths}`
|
|
5346
5398
|
);
|
|
5347
|
-
const stripPathTokens = (args) => args.filter((token) => !
|
|
5399
|
+
const stripPathTokens = (args) => args.filter((token) => !selectionPathsAugmented.includes(token));
|
|
5348
5400
|
const jestDiscoveryArgs = selectionIncludesProdPaths ? stripPathTokens(jest) : jest;
|
|
5349
5401
|
const projectConfigs = [];
|
|
5350
5402
|
try {
|
|
5351
|
-
const baseCfg =
|
|
5352
|
-
const tsCfg =
|
|
5403
|
+
const baseCfg = path10.resolve("jest.config.js");
|
|
5404
|
+
const tsCfg = path10.resolve("jest.ts.config.js");
|
|
5353
5405
|
if (fsSync3.existsSync(baseCfg)) {
|
|
5354
5406
|
projectConfigs.push(baseCfg);
|
|
5355
5407
|
}
|
|
@@ -5366,7 +5418,7 @@ var program = async () => {
|
|
|
5366
5418
|
);
|
|
5367
5419
|
const prodSelections2 = expandedProdSelections;
|
|
5368
5420
|
for (const cfg of projectConfigs) {
|
|
5369
|
-
const cfgCwd =
|
|
5421
|
+
const cfgCwd = path10.dirname(cfg);
|
|
5370
5422
|
const allTests = await discoverJestResilient([...jestDiscoveryArgs, "--config", cfg], {
|
|
5371
5423
|
cwd: cfgCwd
|
|
5372
5424
|
});
|
|
@@ -5379,7 +5431,7 @@ var program = async () => {
|
|
|
5379
5431
|
});
|
|
5380
5432
|
} catch (err) {
|
|
5381
5433
|
if (isDebug()) {
|
|
5382
|
-
console.warn(`direct selection failed for project ${
|
|
5434
|
+
console.warn(`direct selection failed for project ${path10.basename(cfg)}: ${String(err)}`);
|
|
5383
5435
|
}
|
|
5384
5436
|
}
|
|
5385
5437
|
perProjectFiles.set(cfg, directPerProject);
|
|
@@ -5391,7 +5443,7 @@ var program = async () => {
|
|
|
5391
5443
|
)} | related=${selectionIncludesProdPaths} | cwd=${repoRootForDiscovery}`
|
|
5392
5444
|
);
|
|
5393
5445
|
for (const cfg of projectConfigs) {
|
|
5394
|
-
const cfgCwd =
|
|
5446
|
+
const cfgCwd = path10.dirname(cfg);
|
|
5395
5447
|
const files = await discoverJestResilient([...jestDiscoveryArgs, "--config", cfg], {
|
|
5396
5448
|
cwd: cfgCwd
|
|
5397
5449
|
});
|
|
@@ -5401,18 +5453,18 @@ var program = async () => {
|
|
|
5401
5453
|
const perProjectFiltered = /* @__PURE__ */ new Map();
|
|
5402
5454
|
for (const cfg of projectConfigs) {
|
|
5403
5455
|
const files = perProjectFiles.get(cfg) ?? [];
|
|
5404
|
-
const selectionTestPaths =
|
|
5456
|
+
const selectionTestPaths = selectionPathsAugmented.filter(
|
|
5405
5457
|
(pathToken) => /\.(test|spec)\.[tj]sx?$/i.test(pathToken) || /(^|\/)tests?\//i.test(pathToken)
|
|
5406
5458
|
);
|
|
5407
5459
|
const candidates = selectionHasPaths && selectionLooksLikeTest ? selectionTestPaths : files;
|
|
5408
5460
|
const absFiles = candidates.map(
|
|
5409
|
-
(candidatePath) =>
|
|
5461
|
+
(candidatePath) => path10.isAbsolute(candidatePath) ? candidatePath : path10.join(repoRootForDiscovery, candidatePath)
|
|
5410
5462
|
).map((absolutePath) => absolutePath.replace(/\\/g, "/"));
|
|
5411
5463
|
const onlyOwned = await filterCandidatesForProject(
|
|
5412
5464
|
cfg,
|
|
5413
5465
|
jestDiscoveryArgs,
|
|
5414
5466
|
absFiles,
|
|
5415
|
-
|
|
5467
|
+
path10.dirname(cfg)
|
|
5416
5468
|
);
|
|
5417
5469
|
perProjectFiltered.set(cfg, onlyOwned);
|
|
5418
5470
|
}
|
|
@@ -5424,7 +5476,7 @@ var program = async () => {
|
|
|
5424
5476
|
if (selectionHasPaths && prodSelections.length > 0) {
|
|
5425
5477
|
console.info(`rg related \u2192 prodSelections=${prodSelections.length} (starting)`);
|
|
5426
5478
|
const repoRootForRefinement = workspaceRoot ?? await findRepoRoot();
|
|
5427
|
-
const selectionKey = prodSelections.map((absPath) =>
|
|
5479
|
+
const selectionKey = prodSelections.map((absPath) => path10.relative(repoRootForRefinement, absPath).replace(/\\/g, "/")).sort((firstPath, secondPath) => firstPath.localeCompare(secondPath)).join("|");
|
|
5428
5480
|
const { cachedRelated: cachedRelated2, findRelatedTestsFast: findRelatedTestsFast2, DEFAULT_TEST_GLOBS: DEFAULT_TEST_GLOBS2 } = await Promise.resolve().then(() => (init_fast_related(), fast_related_exports));
|
|
5429
5481
|
const { DEFAULT_EXCLUDE: DEFAULT_EXCLUDE2 } = await Promise.resolve().then(() => (init_args(), args_exports));
|
|
5430
5482
|
const rgMatches = await cachedRelated2({
|
|
@@ -5454,7 +5506,7 @@ var program = async () => {
|
|
|
5454
5506
|
cfg,
|
|
5455
5507
|
jestDiscoveryArgs,
|
|
5456
5508
|
rgCandidates,
|
|
5457
|
-
|
|
5509
|
+
path10.dirname(cfg)
|
|
5458
5510
|
);
|
|
5459
5511
|
perProjectFromRg.set(cfg, owned);
|
|
5460
5512
|
}
|
|
@@ -5469,9 +5521,9 @@ var program = async () => {
|
|
|
5469
5521
|
} else {
|
|
5470
5522
|
const repoRootForScan = repoRootForDiscovery;
|
|
5471
5523
|
const toSeeds = (abs) => {
|
|
5472
|
-
const rel =
|
|
5524
|
+
const rel = path10.relative(repoRootForScan, abs).replace(/\\/g, "/");
|
|
5473
5525
|
const withoutExt = rel.replace(/\.(m?[tj]sx?)$/i, "");
|
|
5474
|
-
const base =
|
|
5526
|
+
const base = path10.basename(withoutExt);
|
|
5475
5527
|
const segs = withoutExt.split("/");
|
|
5476
5528
|
const tail2 = segs.slice(-2).join("/");
|
|
5477
5529
|
return Array.from(new Set([withoutExt, base, tail2].filter(Boolean)));
|
|
@@ -5486,8 +5538,8 @@ var program = async () => {
|
|
|
5486
5538
|
}
|
|
5487
5539
|
};
|
|
5488
5540
|
const resolveLocalImport = (fromFile, spec) => {
|
|
5489
|
-
const baseDir =
|
|
5490
|
-
const cand =
|
|
5541
|
+
const baseDir = path10.dirname(fromFile);
|
|
5542
|
+
const cand = path10.resolve(baseDir, spec);
|
|
5491
5543
|
const exts = ["", ".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs"];
|
|
5492
5544
|
for (const ext of exts) {
|
|
5493
5545
|
const full = ext ? `${cand}${ext}` : cand;
|
|
@@ -5496,7 +5548,7 @@ var program = async () => {
|
|
|
5496
5548
|
}
|
|
5497
5549
|
}
|
|
5498
5550
|
for (const ext of exts) {
|
|
5499
|
-
const full =
|
|
5551
|
+
const full = path10.join(cand, `index${ext}`);
|
|
5500
5552
|
if (fsSync3.existsSync(full)) {
|
|
5501
5553
|
return full;
|
|
5502
5554
|
}
|
|
@@ -5550,7 +5602,7 @@ var program = async () => {
|
|
|
5550
5602
|
cfg,
|
|
5551
5603
|
jestDiscoveryArgs,
|
|
5552
5604
|
keptCandidates,
|
|
5553
|
-
|
|
5605
|
+
path10.dirname(cfg)
|
|
5554
5606
|
);
|
|
5555
5607
|
perProjectFromScan.set(cfg, owned);
|
|
5556
5608
|
}
|
|
@@ -5577,9 +5629,9 @@ var program = async () => {
|
|
|
5577
5629
|
if (effectiveJestFiles.length === 0) {
|
|
5578
5630
|
const repoRoot = repoRootForRefinement;
|
|
5579
5631
|
const seeds = prodSelections.map(
|
|
5580
|
-
(abs) =>
|
|
5632
|
+
(abs) => path10.relative(repoRoot, abs).replace(/\\/g, "/").replace(/\.(m?[tj]sx?)$/i, "")
|
|
5581
5633
|
).flatMap((rel) => {
|
|
5582
|
-
const base =
|
|
5634
|
+
const base = path10.basename(rel);
|
|
5583
5635
|
const segments = rel.split("/");
|
|
5584
5636
|
return Array.from(new Set([rel, base, segments.slice(-2).join("/")].filter(Boolean)));
|
|
5585
5637
|
});
|
|
@@ -5592,8 +5644,8 @@ var program = async () => {
|
|
|
5592
5644
|
}
|
|
5593
5645
|
};
|
|
5594
5646
|
const resolveLocalImport = (fromFile, spec) => {
|
|
5595
|
-
const baseDir =
|
|
5596
|
-
const candidate =
|
|
5647
|
+
const baseDir = path10.dirname(fromFile);
|
|
5648
|
+
const candidate = path10.resolve(baseDir, spec);
|
|
5597
5649
|
const extensions = ["", ".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs", ".mts", ".cts"];
|
|
5598
5650
|
for (const ext of extensions) {
|
|
5599
5651
|
const fullPath = ext ? `${candidate}${ext}` : candidate;
|
|
@@ -5602,7 +5654,7 @@ var program = async () => {
|
|
|
5602
5654
|
}
|
|
5603
5655
|
}
|
|
5604
5656
|
for (const ext of extensions) {
|
|
5605
|
-
const fullPath =
|
|
5657
|
+
const fullPath = path10.join(candidate, `index${ext}`);
|
|
5606
5658
|
if (fsSync3.existsSync(fullPath)) {
|
|
5607
5659
|
return fullPath;
|
|
5608
5660
|
}
|
|
@@ -5721,8 +5773,8 @@ var program = async () => {
|
|
|
5721
5773
|
}
|
|
5722
5774
|
}
|
|
5723
5775
|
const jestDecision = decideShouldRunJest([], effectiveJestFiles, {
|
|
5724
|
-
selectionSpecified,
|
|
5725
|
-
selectionPaths
|
|
5776
|
+
selectionSpecified: selectionSpecifiedAugmented,
|
|
5777
|
+
selectionPaths: selectionPathsAugmented
|
|
5726
5778
|
});
|
|
5727
5779
|
const { shouldRunJest } = jestDecision;
|
|
5728
5780
|
const jestCount = effectiveJestFiles.length;
|
|
@@ -5740,45 +5792,63 @@ var program = async () => {
|
|
|
5740
5792
|
}
|
|
5741
5793
|
console.info(`Run plan \u2192 Jest maybe=${shouldRunJest} (projects=${projectConfigs.length})`);
|
|
5742
5794
|
let jestExitCode = 0;
|
|
5795
|
+
const allBridgeJson = [];
|
|
5743
5796
|
const executedTestFilesSet = /* @__PURE__ */ new Set();
|
|
5744
5797
|
if (shouldRunJest) {
|
|
5745
5798
|
console.info("Starting Jest (no Vitest targets)\u2026");
|
|
5746
5799
|
await runJestBootstrap();
|
|
5747
5800
|
const jestRunArgs = selectionIncludesProdPaths ? stripPathTokens(jestArgs) : jestArgs;
|
|
5801
|
+
const sanitizedJestRunArgs = jestRunArgs.filter(
|
|
5802
|
+
(arg) => !/^--coverageDirectory(?:=|$)/.test(String(arg))
|
|
5803
|
+
);
|
|
5748
5804
|
const projectsToRun = projectConfigs.filter(
|
|
5749
5805
|
(cfg) => (perProjectFiltered.get(cfg) ?? []).length > 0
|
|
5750
5806
|
);
|
|
5751
|
-
const totalProjectsToRun = projectsToRun.length;
|
|
5752
5807
|
const stripFooter = (text) => {
|
|
5753
5808
|
const lines = text.split("\n");
|
|
5754
5809
|
const idx = lines.findIndex((ln) => /^Test Files\s/.test(stripAnsiSimple(ln)));
|
|
5755
5810
|
return idx >= 0 ? lines.slice(0, idx).join("\n").trimEnd() : text;
|
|
5756
5811
|
};
|
|
5812
|
+
const prodSeedsForRun = (() => {
|
|
5813
|
+
const changedAbs = (changedSelectionAbs ?? []).map(
|
|
5814
|
+
(absPath) => path10.resolve(absPath).replace(/\\/g, "/")
|
|
5815
|
+
);
|
|
5816
|
+
const selAbs = selectionPathsAugmented.map(
|
|
5817
|
+
(pathToken) => path10.resolve(pathToken).replace(/\\/g, "/")
|
|
5818
|
+
);
|
|
5819
|
+
return (changedAbs.length ? changedAbs : selAbs).filter(
|
|
5820
|
+
(abs) => /[\\/]/.test(abs) && !/(^|\/)tests?\//i.test(abs) && !/\.(test|spec)\.[tj]sx?$/i.test(abs)
|
|
5821
|
+
);
|
|
5822
|
+
})();
|
|
5823
|
+
const repoRootForRank = repoRootForDiscovery;
|
|
5824
|
+
const fileRank = await computeDirectnessRank({
|
|
5825
|
+
repoRoot: repoRootForRank,
|
|
5826
|
+
productionSeeds: prodSeedsForRun
|
|
5827
|
+
});
|
|
5757
5828
|
for (let projIndex = 0; projIndex < projectsToRun.length; projIndex += 1) {
|
|
5758
5829
|
const cfg = projectsToRun[projIndex];
|
|
5759
|
-
const isLastProject = projIndex === totalProjectsToRun - 1;
|
|
5760
5830
|
const files = perProjectFiltered.get(cfg) ?? [];
|
|
5761
5831
|
if (files.length === 0) {
|
|
5762
|
-
console.info(`Project ${
|
|
5832
|
+
console.info(`Project ${path10.basename(cfg)}: 0 matching tests after filter; skipping.`);
|
|
5763
5833
|
continue;
|
|
5764
5834
|
}
|
|
5765
5835
|
files.forEach(
|
|
5766
|
-
(absTestPath) => executedTestFilesSet.add(
|
|
5836
|
+
(absTestPath) => executedTestFilesSet.add(path10.resolve(absTestPath).replace(/\\/g, "/"))
|
|
5767
5837
|
);
|
|
5768
|
-
const outJson =
|
|
5838
|
+
const outJson = path10.join(
|
|
5769
5839
|
os2.tmpdir(),
|
|
5770
5840
|
`jest-bridge-${Date.now()}-${Math.random().toString(36).slice(2)}.json`
|
|
5771
5841
|
);
|
|
5772
|
-
const reporterPath =
|
|
5842
|
+
const reporterPath = path10.resolve("scripts/jest-vitest-bridge.cjs");
|
|
5773
5843
|
try {
|
|
5774
5844
|
if (!fsSync3.existsSync(reporterPath)) {
|
|
5775
|
-
fsSync3.mkdirSync(
|
|
5845
|
+
fsSync3.mkdirSync(path10.dirname(reporterPath), { recursive: true });
|
|
5776
5846
|
fsSync3.writeFileSync(reporterPath, JEST_BRIDGE_REPORTER_SOURCE, "utf8");
|
|
5777
5847
|
}
|
|
5778
5848
|
} catch (ensureReporterError) {
|
|
5779
5849
|
console.warn(`Unable to ensure jest bridge reporter: ${String(ensureReporterError)}`);
|
|
5780
5850
|
}
|
|
5781
|
-
const selectedFilesForCoverage =
|
|
5851
|
+
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}`);
|
|
5782
5852
|
const coverageFromArgs = [];
|
|
5783
5853
|
for (const relPath of selectedFilesForCoverage) {
|
|
5784
5854
|
coverageFromArgs.push("--collectCoverageFrom", relPath);
|
|
@@ -5792,14 +5862,17 @@ var program = async () => {
|
|
|
5792
5862
|
"--config",
|
|
5793
5863
|
cfg,
|
|
5794
5864
|
"--runTestsByPath",
|
|
5795
|
-
|
|
5796
|
-
reporterPath,
|
|
5865
|
+
`--reporters=${reporterPath}`,
|
|
5797
5866
|
"--silent",
|
|
5798
5867
|
"--colors",
|
|
5799
5868
|
"--json",
|
|
5800
5869
|
"--outputFile",
|
|
5801
5870
|
outJson,
|
|
5802
|
-
...
|
|
5871
|
+
...sanitizedJestRunArgs,
|
|
5872
|
+
...collectCoverage ? [
|
|
5873
|
+
"--coverageDirectory",
|
|
5874
|
+
path10.join("coverage", "jest", path10.basename(cfg).replace(/[^a-zA-Z0-9_.-]+/g, "_"))
|
|
5875
|
+
] : [],
|
|
5803
5876
|
...coverageFromArgs,
|
|
5804
5877
|
"--passWithNoTests",
|
|
5805
5878
|
...files
|
|
@@ -5825,10 +5898,22 @@ var program = async () => {
|
|
|
5825
5898
|
const jsonText = fsSync3.readFileSync(outJson, "utf8");
|
|
5826
5899
|
const parsed = JSON.parse(jsonText);
|
|
5827
5900
|
const bridge = coerceJestJsonToBridge(parsed);
|
|
5828
|
-
|
|
5829
|
-
|
|
5830
|
-
|
|
5831
|
-
|
|
5901
|
+
allBridgeJson.push(bridge);
|
|
5902
|
+
try {
|
|
5903
|
+
const reordered = {
|
|
5904
|
+
...bridge,
|
|
5905
|
+
testResults: sortTestResultsWithRank(fileRank, bridge.testResults).reverse()
|
|
5906
|
+
};
|
|
5907
|
+
pretty = renderVitestFromJestJSON(reordered, {
|
|
5908
|
+
cwd: repoRootForDiscovery,
|
|
5909
|
+
...editorCmd !== void 0 ? { editorCmd } : {}
|
|
5910
|
+
});
|
|
5911
|
+
} catch {
|
|
5912
|
+
pretty = renderVitestFromJestJSON(bridge, {
|
|
5913
|
+
cwd: repoRootForDiscovery,
|
|
5914
|
+
...editorCmd !== void 0 ? { editorCmd } : {}
|
|
5915
|
+
});
|
|
5916
|
+
}
|
|
5832
5917
|
if (debug) {
|
|
5833
5918
|
const preview = pretty.split("\n").slice(0, 3).join("\n");
|
|
5834
5919
|
console.info(`pretty preview (json):
|
|
@@ -5852,9 +5937,7 @@ ${preview}${pretty.includes("\n") ? "\n\u2026" : ""}`);
|
|
|
5852
5937
|
${preview}${pretty.includes("\n") ? "\n\u2026" : ""}`);
|
|
5853
5938
|
}
|
|
5854
5939
|
}
|
|
5855
|
-
|
|
5856
|
-
pretty = stripFooter(pretty);
|
|
5857
|
-
}
|
|
5940
|
+
pretty = stripFooter(pretty);
|
|
5858
5941
|
if (pretty.trim().length > 0) {
|
|
5859
5942
|
process.stdout.write(pretty.endsWith("\n") ? pretty : `${pretty}
|
|
5860
5943
|
`);
|
|
@@ -5866,15 +5949,69 @@ ${preview}${pretty.includes("\n") ? "\n\u2026" : ""}`);
|
|
|
5866
5949
|
} else {
|
|
5867
5950
|
console.info("Jest run skipped based on selection and thresholds.");
|
|
5868
5951
|
}
|
|
5869
|
-
if (
|
|
5870
|
-
|
|
5952
|
+
if (allBridgeJson.length > 0) {
|
|
5953
|
+
const agg = allBridgeJson.map((bridge) => bridge.aggregated);
|
|
5954
|
+
const sum = (select) => agg.reduce((total, item) => total + (select(item) || 0), 0);
|
|
5955
|
+
const startTime = Math.min(
|
|
5956
|
+
...allBridgeJson.map((bridge) => Number(bridge.startTime || Date.now()))
|
|
5957
|
+
);
|
|
5958
|
+
const unified = {
|
|
5959
|
+
startTime,
|
|
5960
|
+
testResults: allBridgeJson.flatMap((bridge) => bridge.testResults),
|
|
5961
|
+
aggregated: {
|
|
5962
|
+
numTotalTestSuites: sum((item) => item.numTotalTestSuites),
|
|
5963
|
+
numPassedTestSuites: sum((item) => item.numPassedTestSuites),
|
|
5964
|
+
numFailedTestSuites: sum((item) => item.numFailedTestSuites),
|
|
5965
|
+
numTotalTests: sum((item) => item.numTotalTests),
|
|
5966
|
+
numPassedTests: sum((item) => item.numPassedTests),
|
|
5967
|
+
numFailedTests: sum((item) => item.numFailedTests),
|
|
5968
|
+
numPendingTests: sum((item) => item.numPendingTests),
|
|
5969
|
+
numTodoTests: sum((item) => item.numTodoTests),
|
|
5970
|
+
startTime,
|
|
5971
|
+
success: agg.every((item) => Boolean(item.success)),
|
|
5972
|
+
runTimeMs: sum((item) => Number(item.runTimeMs ?? 0))
|
|
5973
|
+
}
|
|
5974
|
+
};
|
|
5975
|
+
try {
|
|
5976
|
+
const prodSeeds = (() => {
|
|
5977
|
+
const changedAbs = (changedSelectionAbs ?? []).map(
|
|
5978
|
+
(absPath) => path10.resolve(absPath).replace(/\\/g, "/")
|
|
5979
|
+
);
|
|
5980
|
+
const selAbs = selectionPathsAugmented.map(
|
|
5981
|
+
(pathToken) => path10.resolve(pathToken).replace(/\\/g, "/")
|
|
5982
|
+
);
|
|
5983
|
+
return (changedAbs.length ? changedAbs : selAbs).filter(
|
|
5984
|
+
(abs) => /[\\/]/.test(abs) && !/(^|\/)tests?\//i.test(abs) && !/\.(test|spec)\.[tj]sx?$/i.test(abs)
|
|
5985
|
+
);
|
|
5986
|
+
})();
|
|
5987
|
+
const unifiedRank = await computeDirectnessRank({
|
|
5988
|
+
repoRoot: repoRootForDiscovery,
|
|
5989
|
+
productionSeeds: prodSeeds
|
|
5990
|
+
});
|
|
5991
|
+
const ordered = sortTestResultsWithRank(unifiedRank, unified.testResults).reverse();
|
|
5992
|
+
unified.testResults = ordered;
|
|
5993
|
+
} catch {
|
|
5994
|
+
}
|
|
5995
|
+
const text = renderVitestFromJestJSON(unified, {
|
|
5996
|
+
cwd: repoRootForDiscovery,
|
|
5997
|
+
...editorCmd !== void 0 ? { editorCmd } : {}
|
|
5998
|
+
});
|
|
5999
|
+
if (text.trim().length > 0) {
|
|
6000
|
+
process.stdout.write(text.endsWith("\n") ? text : `${text}
|
|
6001
|
+
`);
|
|
6002
|
+
}
|
|
6003
|
+
}
|
|
6004
|
+
const finalExitCode = jestExitCode;
|
|
6005
|
+
if (collectCoverage && shouldRunJest && coverageAbortOnFailure && finalExitCode !== 0) {
|
|
6006
|
+
process.exit(finalExitCode);
|
|
6007
|
+
return;
|
|
5871
6008
|
}
|
|
5872
6009
|
if (collectCoverage && shouldRunJest) {
|
|
5873
6010
|
await mergeLcov();
|
|
5874
6011
|
const repoRoot = workspaceRoot ?? await findRepoRoot();
|
|
5875
6012
|
const mergedOptsBase = {
|
|
5876
|
-
selectionSpecified,
|
|
5877
|
-
selectionPaths,
|
|
6013
|
+
selectionSpecified: selectionSpecifiedAugmented,
|
|
6014
|
+
selectionPaths: selectionPathsAugmented,
|
|
5878
6015
|
includeGlobs,
|
|
5879
6016
|
excludeGlobs,
|
|
5880
6017
|
workspaceRoot: repoRoot,
|
|
@@ -5889,7 +6026,6 @@ ${preview}${pretty.includes("\n") ? "\n\u2026" : ""}`);
|
|
|
5889
6026
|
};
|
|
5890
6027
|
await emitMergedCoverage(coverageUi, mergedOptsBase);
|
|
5891
6028
|
}
|
|
5892
|
-
const finalExitCode = jestExitCode;
|
|
5893
6029
|
process.exit(finalExitCode);
|
|
5894
6030
|
};
|
|
5895
6031
|
|