headlamp 0.1.6 → 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 +391 -257
- package/dist/cli.cjs.map +4 -4
- package/dist/index.js +395 -258
- 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,7 +1977,7 @@ 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
1983
|
var fs5 = __toESM(require("node:fs/promises"), 1);
|
|
@@ -2921,7 +2938,7 @@ var compositeBarPct = (summary, hotspots) => {
|
|
|
2921
2938
|
};
|
|
2922
2939
|
|
|
2923
2940
|
// src/lib/coverage-print.ts
|
|
2924
|
-
var
|
|
2941
|
+
var path8 = __toESM(require("node:path"), 1);
|
|
2925
2942
|
var fsSync2 = __toESM(require("node:fs"), 1);
|
|
2926
2943
|
init_env_utils();
|
|
2927
2944
|
init_exec();
|
|
@@ -3091,6 +3108,71 @@ var renderTable = (columns, rows) => {
|
|
|
3091
3108
|
};
|
|
3092
3109
|
var barCell = (pct) => (padded) => bar(pct, padded.length);
|
|
3093
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
|
+
|
|
3094
3176
|
// src/lib/coverage-print.ts
|
|
3095
3177
|
var printDetailedCoverage = async (opts) => {
|
|
3096
3178
|
const files = opts.map.files().sort((fileA, fileB) => {
|
|
@@ -3101,7 +3183,7 @@ var printDetailedCoverage = async (opts) => {
|
|
|
3101
3183
|
for (const abs of files) {
|
|
3102
3184
|
const fc = opts.map.fileCoverageFor(abs);
|
|
3103
3185
|
const sum = fc.toSummary();
|
|
3104
|
-
const rel =
|
|
3186
|
+
const rel = path8.relative(opts.root, abs).replace(/\\/g, "/");
|
|
3105
3187
|
const blocks = computeUncoveredBlocks(fc);
|
|
3106
3188
|
const misses = missedBranches(fc);
|
|
3107
3189
|
const missFns = missedFunctions(fc);
|
|
@@ -3110,9 +3192,9 @@ var printDetailedCoverage = async (opts) => {
|
|
|
3110
3192
|
const branchesPctText = `${sum.branches.pct.toFixed(1)}%`;
|
|
3111
3193
|
const header = `${ansi.bold(rel)} lines ${tintPct(sum.lines.pct)(
|
|
3112
3194
|
linesPctText
|
|
3113
|
-
)} ${barCell(compositeBarPct(sum, blocks))("".padEnd(14))} funcs ${tintPct(
|
|
3114
|
-
|
|
3115
|
-
)
|
|
3195
|
+
)} ${barCell(compositeBarPct(sum, blocks))("".padEnd(14))} funcs ${tintPct(sum.functions.pct)(
|
|
3196
|
+
funcsPctText
|
|
3197
|
+
)} branches ${tintPct(sum.branches.pct)(branchesPctText)}`;
|
|
3116
3198
|
console.info(header);
|
|
3117
3199
|
const max = opts.limitPerFile === "all" ? Number.POSITIVE_INFINITY : opts.limitPerFile ?? 5;
|
|
3118
3200
|
const compareRangesByLengthDescThenStart = (firstRange, secondRange) => {
|
|
@@ -3139,10 +3221,8 @@ var printDetailedCoverage = async (opts) => {
|
|
|
3139
3221
|
abs,
|
|
3140
3222
|
block.start,
|
|
3141
3223
|
opts.editorCmd
|
|
3142
|
-
)}\x07${
|
|
3143
|
-
const label = ` ${ansi.yellow(`L${block.start}`)}\u2013${ansi.yellow(
|
|
3144
|
-
`L${block.end}`
|
|
3145
|
-
)} ${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}`;
|
|
3146
3226
|
console.info(label);
|
|
3147
3227
|
if (opts.showCode && src.length) {
|
|
3148
3228
|
const lines = src.split(/\r?\n/);
|
|
@@ -3162,7 +3242,7 @@ var printDetailedCoverage = async (opts) => {
|
|
|
3162
3242
|
abs,
|
|
3163
3243
|
fn.line,
|
|
3164
3244
|
opts.editorCmd
|
|
3165
|
-
)}\x07${
|
|
3245
|
+
)}\x07${path8.basename(abs)}:${fn.line}\x1B]8;;\x07`;
|
|
3166
3246
|
console.info(` - ${fn.name} @ ${link}`);
|
|
3167
3247
|
}
|
|
3168
3248
|
}
|
|
@@ -3173,12 +3253,8 @@ var printDetailedCoverage = async (opts) => {
|
|
|
3173
3253
|
abs,
|
|
3174
3254
|
br.line,
|
|
3175
3255
|
opts.editorCmd
|
|
3176
|
-
)}\x07${
|
|
3177
|
-
console.info(
|
|
3178
|
-
` - branch#${br.id} @ ${link} missed paths: [${br.zeroPaths.join(
|
|
3179
|
-
", "
|
|
3180
|
-
)}]`
|
|
3181
|
-
);
|
|
3256
|
+
)}\x07${path8.basename(abs)}:${br.line}\x1B]8;;\x07`;
|
|
3257
|
+
console.info(` - branch#${br.id} @ ${link} missed paths: [${br.zeroPaths.join(", ")}]`);
|
|
3182
3258
|
}
|
|
3183
3259
|
}
|
|
3184
3260
|
console.info("");
|
|
@@ -3198,7 +3274,7 @@ var printCompactCoverage = async (opts) => {
|
|
|
3198
3274
|
for (const abs of files.slice(0, fileCap)) {
|
|
3199
3275
|
const fc = opts.map.fileCoverageFor(abs);
|
|
3200
3276
|
const sum = fc.toSummary();
|
|
3201
|
-
const rel =
|
|
3277
|
+
const rel = path8.relative(opts.root, abs).replace(/\\/g, "/");
|
|
3202
3278
|
const compareRangesByLengthDescThenStart = (firstRange, secondRange) => {
|
|
3203
3279
|
const secondLength = secondRange.end - secondRange.start;
|
|
3204
3280
|
const firstLength = firstRange.end - firstRange.start;
|
|
@@ -3212,9 +3288,9 @@ var printCompactCoverage = async (opts) => {
|
|
|
3212
3288
|
const branchesPctText = `${sum.branches.pct.toFixed(1)}%`;
|
|
3213
3289
|
const header = `${ansi.bold(rel)} lines ${tintPct(sum.lines.pct)(
|
|
3214
3290
|
linesPctText
|
|
3215
|
-
)} ${barCell(compositeBarPct(sum, blocks))("".padEnd(14))} funcs ${tintPct(
|
|
3216
|
-
|
|
3217
|
-
)
|
|
3291
|
+
)} ${barCell(compositeBarPct(sum, blocks))("".padEnd(14))} funcs ${tintPct(sum.functions.pct)(
|
|
3292
|
+
funcsPctText
|
|
3293
|
+
)} branches ${tintPct(sum.branches.pct)(branchesPctText)}`;
|
|
3218
3294
|
console.info(header);
|
|
3219
3295
|
const hotspots = blocks.slice(0, maxHotspotsDerived);
|
|
3220
3296
|
if (hotspots.length) {
|
|
@@ -3225,10 +3301,8 @@ var printCompactCoverage = async (opts) => {
|
|
|
3225
3301
|
abs,
|
|
3226
3302
|
hotspot.start,
|
|
3227
3303
|
opts.editorCmd
|
|
3228
|
-
)}\x07${
|
|
3229
|
-
console.info(
|
|
3230
|
-
` - L${hotspot.start}\u2013L${hotspot.end} (${len} lines) ${link}`
|
|
3231
|
-
);
|
|
3304
|
+
)}\x07${path8.basename(abs)}:${hotspot.start}\x1B]8;;\x07`;
|
|
3305
|
+
console.info(` - L${hotspot.start}\u2013L${hotspot.end} (${len} lines) ${link}`);
|
|
3232
3306
|
}
|
|
3233
3307
|
}
|
|
3234
3308
|
const functionsList = missFns.slice(0, maxFunctionsDerived);
|
|
@@ -3240,7 +3314,7 @@ var printCompactCoverage = async (opts) => {
|
|
|
3240
3314
|
abs,
|
|
3241
3315
|
fn.line,
|
|
3242
3316
|
opts.editorCmd
|
|
3243
|
-
)}\x07${
|
|
3317
|
+
)}\x07${path8.basename(abs)}:${fn.line}\x1B]8;;\x07`
|
|
3244
3318
|
);
|
|
3245
3319
|
}
|
|
3246
3320
|
}
|
|
@@ -3255,7 +3329,7 @@ var printCompactCoverage = async (opts) => {
|
|
|
3255
3329
|
abs,
|
|
3256
3330
|
br.line,
|
|
3257
3331
|
opts.editorCmd
|
|
3258
|
-
)}\x07${
|
|
3332
|
+
)}\x07${path8.basename(abs)}:${br.line}\x1B]8;;\x07`
|
|
3259
3333
|
);
|
|
3260
3334
|
}
|
|
3261
3335
|
}
|
|
@@ -3264,9 +3338,7 @@ var printCompactCoverage = async (opts) => {
|
|
|
3264
3338
|
const restBrs = Math.max(0, misses.length - branchesList.length);
|
|
3265
3339
|
if (restHs + restFns + restBrs > 0) {
|
|
3266
3340
|
console.info(
|
|
3267
|
-
ansi.dim(
|
|
3268
|
-
` \u2026 truncated: +${restHs} hotspots, +${restFns} funcs, +${restBrs} branches`
|
|
3269
|
-
)
|
|
3341
|
+
ansi.dim(` \u2026 truncated: +${restHs} hotspots, +${restFns} funcs, +${restBrs} branches`)
|
|
3270
3342
|
);
|
|
3271
3343
|
}
|
|
3272
3344
|
console.info("");
|
|
@@ -3303,7 +3375,7 @@ var shortenPathPreservingFilename = (relPath, maxWidth, opts) => {
|
|
|
3303
3375
|
return { stem: base.slice(0, -ending.length), ext: ending };
|
|
3304
3376
|
}
|
|
3305
3377
|
}
|
|
3306
|
-
const ext2 =
|
|
3378
|
+
const ext2 = path8.extname(base);
|
|
3307
3379
|
return { stem: base.slice(0, -ext2.length), ext: ext2 };
|
|
3308
3380
|
};
|
|
3309
3381
|
const sliceBalanced = (input, width) => {
|
|
@@ -3386,12 +3458,7 @@ var shortenPathPreservingFilename = (relPath, maxWidth, opts) => {
|
|
|
3386
3458
|
const tailParts = tailSrc.map((segment) => segment);
|
|
3387
3459
|
let hidAny = false;
|
|
3388
3460
|
const build = () => {
|
|
3389
|
-
const label2 = joinParts(
|
|
3390
|
-
headParts,
|
|
3391
|
-
tailParts,
|
|
3392
|
-
hideMiddle2 || hidAny,
|
|
3393
|
-
baseLabel
|
|
3394
|
-
);
|
|
3461
|
+
const label2 = joinParts(headParts, tailParts, hideMiddle2 || hidAny, baseLabel);
|
|
3395
3462
|
return { label: label2, width: visibleWidth(label2) };
|
|
3396
3463
|
};
|
|
3397
3464
|
let { label, width } = build();
|
|
@@ -3484,13 +3551,7 @@ var shortenPathPreservingFilename = (relPath, maxWidth, opts) => {
|
|
|
3484
3551
|
return { headRaw: headRaw2, tailRaw: tailRaw2, hideMiddle: hideMiddle2 };
|
|
3485
3552
|
};
|
|
3486
3553
|
let { headRaw, tailRaw, hideMiddle } = buildRaw(headCount, tailCount);
|
|
3487
|
-
let candidate = tryTrimDirsToFit(
|
|
3488
|
-
headRaw,
|
|
3489
|
-
tailRaw,
|
|
3490
|
-
hideMiddle,
|
|
3491
|
-
baseFull,
|
|
3492
|
-
maxWidth
|
|
3493
|
-
);
|
|
3554
|
+
let candidate = tryTrimDirsToFit(headRaw, tailRaw, hideMiddle, baseFull, maxWidth);
|
|
3494
3555
|
if (!candidate) {
|
|
3495
3556
|
return baseFull;
|
|
3496
3557
|
}
|
|
@@ -3499,13 +3560,7 @@ var shortenPathPreservingFilename = (relPath, maxWidth, opts) => {
|
|
|
3499
3560
|
if (headCount + tailCount < total) {
|
|
3500
3561
|
const tryTail = Math.min(tailCount + 1, total - headCount);
|
|
3501
3562
|
({ headRaw, tailRaw, hideMiddle } = buildRaw(headCount, tryTail));
|
|
3502
|
-
const candTail = tryTrimDirsToFit(
|
|
3503
|
-
headRaw,
|
|
3504
|
-
tailRaw,
|
|
3505
|
-
hideMiddle,
|
|
3506
|
-
baseFull,
|
|
3507
|
-
maxWidth
|
|
3508
|
-
);
|
|
3563
|
+
const candTail = tryTrimDirsToFit(headRaw, tailRaw, hideMiddle, baseFull, maxWidth);
|
|
3509
3564
|
if (candTail) {
|
|
3510
3565
|
tailCount = tryTail;
|
|
3511
3566
|
candidate = candTail;
|
|
@@ -3515,13 +3570,7 @@ var shortenPathPreservingFilename = (relPath, maxWidth, opts) => {
|
|
|
3515
3570
|
if (!advanced && headCount + tailCount < total) {
|
|
3516
3571
|
const tryHead = Math.min(headCount + 1, total - tailCount);
|
|
3517
3572
|
({ headRaw, tailRaw, hideMiddle } = buildRaw(tryHead, tailCount));
|
|
3518
|
-
const candHead = tryTrimDirsToFit(
|
|
3519
|
-
headRaw,
|
|
3520
|
-
tailRaw,
|
|
3521
|
-
hideMiddle,
|
|
3522
|
-
baseFull,
|
|
3523
|
-
maxWidth
|
|
3524
|
-
);
|
|
3573
|
+
const candHead = tryTrimDirsToFit(headRaw, tailRaw, hideMiddle, baseFull, maxWidth);
|
|
3525
3574
|
if (candHead) {
|
|
3526
3575
|
headCount = tryHead;
|
|
3527
3576
|
candidate = candHead;
|
|
@@ -3583,7 +3632,7 @@ var buildDistanceMapFromTests = async (executedTestsAbs, rootDir) => {
|
|
|
3583
3632
|
const queue = [];
|
|
3584
3633
|
const seen = /* @__PURE__ */ new Set();
|
|
3585
3634
|
for (const testAbs of executedTestsAbs) {
|
|
3586
|
-
const testPathNormalized =
|
|
3635
|
+
const testPathNormalized = path8.resolve(testAbs).replace(/\\/g, "/");
|
|
3587
3636
|
dist.set(testPathNormalized, 0);
|
|
3588
3637
|
queue.push([testPathNormalized, 0]);
|
|
3589
3638
|
}
|
|
@@ -3602,12 +3651,7 @@ var buildDistanceMapFromTests = async (executedTestsAbs, rootDir) => {
|
|
|
3602
3651
|
const specs = await extractImportSpecs2(currentFile, specsCache);
|
|
3603
3652
|
const nextDistance = currentDistance + 1;
|
|
3604
3653
|
for (const spec of specs) {
|
|
3605
|
-
const resolved = resolveImportWithRoot(
|
|
3606
|
-
currentFile,
|
|
3607
|
-
spec,
|
|
3608
|
-
rootDir,
|
|
3609
|
-
resolutionCache
|
|
3610
|
-
);
|
|
3654
|
+
const resolved = resolveImportWithRoot(currentFile, spec, rootDir, resolutionCache);
|
|
3611
3655
|
const usable = resolved && !resolved.includes("/node_modules/");
|
|
3612
3656
|
if (usable) {
|
|
3613
3657
|
const existing = dist.get(resolved);
|
|
@@ -3622,13 +3666,10 @@ var buildDistanceMapFromTests = async (executedTestsAbs, rootDir) => {
|
|
|
3622
3666
|
return dist;
|
|
3623
3667
|
};
|
|
3624
3668
|
var renderPerFileCompositeTable = async (opts) => {
|
|
3625
|
-
const rel =
|
|
3669
|
+
const rel = path8.relative(opts.root, opts.absPath).replace(/\\/g, "/");
|
|
3626
3670
|
const sum = opts.file.toSummary();
|
|
3627
3671
|
const rowsAvail = typeof process.stdout.rows === "number" && process.stdout.rows > 10 ? process.stdout.rows : 40;
|
|
3628
|
-
const tableBudget = Math.max(
|
|
3629
|
-
14,
|
|
3630
|
-
Math.min(opts.maxRows ?? rowsAvail - 1, rowsAvail + 8)
|
|
3631
|
-
);
|
|
3672
|
+
const tableBudget = Math.max(14, Math.min(opts.maxRows ?? rowsAvail - 1, rowsAvail + 8));
|
|
3632
3673
|
const rowBudget = Math.max(6, tableBudget - 6);
|
|
3633
3674
|
const blocks = computeUncoveredBlocks(opts.file).slice().sort((firstRange, secondRange) => {
|
|
3634
3675
|
const firstLength = firstRange.end - firstRange.start;
|
|
@@ -3672,9 +3713,7 @@ var renderPerFileCompositeTable = async (opts) => {
|
|
|
3672
3713
|
rows.push([
|
|
3673
3714
|
cell(
|
|
3674
3715
|
rel,
|
|
3675
|
-
(padded) => ansi.dim(
|
|
3676
|
-
shortenPathPreservingFilename(rel, padded.length).padEnd(padded.length)
|
|
3677
|
-
)
|
|
3716
|
+
(padded) => ansi.dim(shortenPathPreservingFilename(rel, padded.length).padEnd(padded.length))
|
|
3678
3717
|
),
|
|
3679
3718
|
cell("Totals", ansi.dim),
|
|
3680
3719
|
cell("\u2014", ansi.dim),
|
|
@@ -3693,11 +3732,7 @@ var renderPerFileCompositeTable = async (opts) => {
|
|
|
3693
3732
|
rows.push([
|
|
3694
3733
|
cell(
|
|
3695
3734
|
rel,
|
|
3696
|
-
(padded) => ansi.dim(
|
|
3697
|
-
shortenPathPreservingFilename(rel, padded.length).padEnd(
|
|
3698
|
-
padded.length
|
|
3699
|
-
)
|
|
3700
|
-
)
|
|
3735
|
+
(padded) => ansi.dim(shortenPathPreservingFilename(rel, padded.length).padEnd(padded.length))
|
|
3701
3736
|
),
|
|
3702
3737
|
cell("Hotspots", ansi.dim),
|
|
3703
3738
|
cell("", ansi.dim),
|
|
@@ -3711,14 +3746,8 @@ var renderPerFileCompositeTable = async (opts) => {
|
|
|
3711
3746
|
rows.push([
|
|
3712
3747
|
cell(rel, (padded) => {
|
|
3713
3748
|
const width = padded.length;
|
|
3714
|
-
const display = shortenPathPreservingFilename(rel, width).padEnd(
|
|
3715
|
-
|
|
3716
|
-
);
|
|
3717
|
-
return linkifyPadded(
|
|
3718
|
-
opts.absPath,
|
|
3719
|
-
hotspotRange.start,
|
|
3720
|
-
opts.editorCmd
|
|
3721
|
-
)(display);
|
|
3749
|
+
const display = shortenPathPreservingFilename(rel, width).padEnd(width);
|
|
3750
|
+
return linkifyPadded(opts.absPath, hotspotRange.start, opts.editorCmd)(display);
|
|
3722
3751
|
}),
|
|
3723
3752
|
cell("Hotspot"),
|
|
3724
3753
|
cell(`L${hotspotRange.start}\u2013L${hotspotRange.end}`),
|
|
@@ -3735,11 +3764,7 @@ var renderPerFileCompositeTable = async (opts) => {
|
|
|
3735
3764
|
rows.push([
|
|
3736
3765
|
cell(
|
|
3737
3766
|
rel,
|
|
3738
|
-
(padded) => ansi.dim(
|
|
3739
|
-
shortenPathPreservingFilename(rel, padded.length).padEnd(
|
|
3740
|
-
padded.length
|
|
3741
|
-
)
|
|
3742
|
-
)
|
|
3767
|
+
(padded) => ansi.dim(shortenPathPreservingFilename(rel, padded.length).padEnd(padded.length))
|
|
3743
3768
|
),
|
|
3744
3769
|
cell("Functions", ansi.dim),
|
|
3745
3770
|
cell("", ansi.dim),
|
|
@@ -3753,14 +3778,8 @@ var renderPerFileCompositeTable = async (opts) => {
|
|
|
3753
3778
|
rows.push([
|
|
3754
3779
|
cell(rel, (padded) => {
|
|
3755
3780
|
const width = padded.length;
|
|
3756
|
-
const display = shortenPathPreservingFilename(rel, width).padEnd(
|
|
3757
|
-
|
|
3758
|
-
);
|
|
3759
|
-
return linkifyPadded(
|
|
3760
|
-
opts.absPath,
|
|
3761
|
-
missedFunction.line,
|
|
3762
|
-
opts.editorCmd
|
|
3763
|
-
)(display);
|
|
3781
|
+
const display = shortenPathPreservingFilename(rel, width).padEnd(width);
|
|
3782
|
+
return linkifyPadded(opts.absPath, missedFunction.line, opts.editorCmd)(display);
|
|
3764
3783
|
}),
|
|
3765
3784
|
cell("Func"),
|
|
3766
3785
|
cell(`L${missedFunction.line}`),
|
|
@@ -3777,11 +3796,7 @@ var renderPerFileCompositeTable = async (opts) => {
|
|
|
3777
3796
|
rows.push([
|
|
3778
3797
|
cell(
|
|
3779
3798
|
rel,
|
|
3780
|
-
(padded) => ansi.dim(
|
|
3781
|
-
shortenPathPreservingFilename(rel, padded.length).padEnd(
|
|
3782
|
-
padded.length
|
|
3783
|
-
)
|
|
3784
|
-
)
|
|
3799
|
+
(padded) => ansi.dim(shortenPathPreservingFilename(rel, padded.length).padEnd(padded.length))
|
|
3785
3800
|
),
|
|
3786
3801
|
cell("Branches", ansi.dim),
|
|
3787
3802
|
cell("", ansi.dim),
|
|
@@ -3795,14 +3810,8 @@ var renderPerFileCompositeTable = async (opts) => {
|
|
|
3795
3810
|
rows.push([
|
|
3796
3811
|
cell(rel, (padded) => {
|
|
3797
3812
|
const width = padded.length;
|
|
3798
|
-
const display = shortenPathPreservingFilename(rel, width).padEnd(
|
|
3799
|
-
|
|
3800
|
-
);
|
|
3801
|
-
return linkifyPadded(
|
|
3802
|
-
opts.absPath,
|
|
3803
|
-
missedBranch.line,
|
|
3804
|
-
opts.editorCmd
|
|
3805
|
-
)(display);
|
|
3813
|
+
const display = shortenPathPreservingFilename(rel, width).padEnd(width);
|
|
3814
|
+
return linkifyPadded(opts.absPath, missedBranch.line, opts.editorCmd)(display);
|
|
3806
3815
|
}),
|
|
3807
3816
|
cell("Branch"),
|
|
3808
3817
|
cell(`L${missedBranch.line}`),
|
|
@@ -3810,9 +3819,7 @@ var renderPerFileCompositeTable = async (opts) => {
|
|
|
3810
3819
|
cell(""),
|
|
3811
3820
|
cell(""),
|
|
3812
3821
|
cell(""),
|
|
3813
|
-
cell(
|
|
3814
|
-
`#${missedBranch.id} missed [${missedBranch.zeroPaths.join(", ")}]`
|
|
3815
|
-
)
|
|
3822
|
+
cell(`#${missedBranch.id} missed [${missedBranch.zeroPaths.join(", ")}]`)
|
|
3816
3823
|
]);
|
|
3817
3824
|
}
|
|
3818
3825
|
}
|
|
@@ -3832,9 +3839,7 @@ var renderPerFileCompositeTable = async (opts) => {
|
|
|
3832
3839
|
rows.push([
|
|
3833
3840
|
cell(rel, (padded) => {
|
|
3834
3841
|
const width = padded.length;
|
|
3835
|
-
const display = shortenPathPreservingFilename(rel, width).padEnd(
|
|
3836
|
-
width
|
|
3837
|
-
);
|
|
3842
|
+
const display = shortenPathPreservingFilename(rel, width).padEnd(width);
|
|
3838
3843
|
return linkifyPadded(opts.absPath, ln, opts.editorCmd)(display);
|
|
3839
3844
|
}),
|
|
3840
3845
|
cell("Line"),
|
|
@@ -3847,16 +3852,7 @@ var renderPerFileCompositeTable = async (opts) => {
|
|
|
3847
3852
|
]);
|
|
3848
3853
|
}
|
|
3849
3854
|
while (rows.length < target) {
|
|
3850
|
-
rows.push([
|
|
3851
|
-
cell(""),
|
|
3852
|
-
cell(""),
|
|
3853
|
-
cell(""),
|
|
3854
|
-
cell(""),
|
|
3855
|
-
cell(""),
|
|
3856
|
-
cell(""),
|
|
3857
|
-
cell(""),
|
|
3858
|
-
cell("")
|
|
3859
|
-
]);
|
|
3855
|
+
rows.push([cell(""), cell(""), cell(""), cell(""), cell(""), cell(""), cell(""), cell("")]);
|
|
3860
3856
|
}
|
|
3861
3857
|
}
|
|
3862
3858
|
}
|
|
@@ -3864,20 +3860,17 @@ var renderPerFileCompositeTable = async (opts) => {
|
|
|
3864
3860
|
console.info(table);
|
|
3865
3861
|
const sep = ansi.gray(
|
|
3866
3862
|
"\u2500".repeat(
|
|
3867
|
-
Math.max(
|
|
3868
|
-
20,
|
|
3869
|
-
typeof process.stdout.columns === "number" ? process.stdout.columns : 100
|
|
3870
|
-
)
|
|
3863
|
+
Math.max(20, typeof process.stdout.columns === "number" ? process.stdout.columns : 100)
|
|
3871
3864
|
)
|
|
3872
3865
|
);
|
|
3873
3866
|
console.info(sep);
|
|
3874
3867
|
};
|
|
3875
3868
|
var printPerFileCompositeTables = async (opts) => {
|
|
3876
3869
|
const selectionAbs = (opts.selectionPaths ?? []).map(
|
|
3877
|
-
(selPath) =>
|
|
3870
|
+
(selPath) => path8.resolve(selPath).replace(/\\/g, "/")
|
|
3878
3871
|
);
|
|
3879
3872
|
const changedAbs = (opts.changedFiles ?? []).map(
|
|
3880
|
-
(chgPath) =>
|
|
3873
|
+
(chgPath) => path8.resolve(chgPath).replace(/\\/g, "/")
|
|
3881
3874
|
);
|
|
3882
3875
|
const tokenizeForSimilarity = (filePathForTokens) => new Set(
|
|
3883
3876
|
filePathForTokens.toLowerCase().replace(/[^a-z0-9/_\-.]/g, " ").split(/[/_.-]+/).filter(Boolean)
|
|
@@ -3893,15 +3886,15 @@ var printPerFileCompositeTables = async (opts) => {
|
|
|
3893
3886
|
return intersectionCount / unionSize;
|
|
3894
3887
|
};
|
|
3895
3888
|
const isSameDirOrChild = (firstAbs, secondAbs) => {
|
|
3896
|
-
const dirA =
|
|
3897
|
-
const dirB =
|
|
3889
|
+
const dirA = path8.dirname(firstAbs).replace(/\\/g, "/");
|
|
3890
|
+
const dirB = path8.dirname(secondAbs).replace(/\\/g, "/");
|
|
3898
3891
|
return dirA === dirB || dirB.startsWith(`${dirA}/`) || dirA.startsWith(`${dirB}/`);
|
|
3899
3892
|
};
|
|
3900
3893
|
const selectionTokens = selectionAbs.map(tokenizeForSimilarity);
|
|
3901
3894
|
const changedTokens = changedAbs.map(tokenizeForSimilarity);
|
|
3902
|
-
const executedTestsAbs = (opts.executedTests ?? []).map((testPath) =>
|
|
3895
|
+
const executedTestsAbs = (opts.executedTests ?? []).map((testPath) => path8.resolve(testPath).replace(/\\/g, "/")).filter((absPath) => absPath.length > 0);
|
|
3903
3896
|
const testTokens = executedTestsAbs.map(tokenizeForSimilarity);
|
|
3904
|
-
const allMapFilesAbs = opts.map.files().map((absPath) =>
|
|
3897
|
+
const allMapFilesAbs = opts.map.files().map((absPath) => path8.resolve(absPath).replace(/\\/g, "/"));
|
|
3905
3898
|
const uncoveredCandidates = allMapFilesAbs.filter((absPath) => {
|
|
3906
3899
|
const sum = opts.map.fileCoverageFor(absPath).toSummary();
|
|
3907
3900
|
return !(sum.lines.pct >= 100 && sum.functions.pct >= 100 && sum.branches.pct >= 100);
|
|
@@ -3918,33 +3911,24 @@ var printPerFileCompositeTables = async (opts) => {
|
|
|
3918
3911
|
const selectionSetAbs = new Set(selectionAbs);
|
|
3919
3912
|
const scored = await Promise.all(
|
|
3920
3913
|
candidates.map(async (abs) => {
|
|
3921
|
-
const rel =
|
|
3914
|
+
const rel = path8.relative(opts.root, abs).replace(/\\/g, "/");
|
|
3922
3915
|
const sum = opts.map.fileCoverageFor(abs).toSummary();
|
|
3923
3916
|
const pct = Number.isFinite(sum.lines.pct) ? sum.lines.pct : 0;
|
|
3924
|
-
const absNorm =
|
|
3917
|
+
const absNorm = path8.resolve(abs).replace(/\\/g, "/");
|
|
3925
3918
|
const selfTokens = tokenizeForSimilarity(absNorm);
|
|
3926
3919
|
const selSim = Math.max(
|
|
3927
3920
|
0,
|
|
3928
|
-
...selectionTokens.map(
|
|
3929
|
-
(selectionTokenSet) => jaccard(selfTokens, selectionTokenSet)
|
|
3930
|
-
)
|
|
3921
|
+
...selectionTokens.map((selectionTokenSet) => jaccard(selfTokens, selectionTokenSet))
|
|
3931
3922
|
);
|
|
3932
3923
|
const chgSim = Math.max(
|
|
3933
3924
|
0,
|
|
3934
|
-
...changedTokens.map(
|
|
3935
|
-
(changedTokenSet) => jaccard(selfTokens, changedTokenSet)
|
|
3936
|
-
)
|
|
3937
|
-
);
|
|
3938
|
-
const tstSim = Math.max(
|
|
3939
|
-
0,
|
|
3940
|
-
...testTokens.map((tset) => jaccard(selfTokens, tset))
|
|
3925
|
+
...changedTokens.map((changedTokenSet) => jaccard(selfTokens, changedTokenSet))
|
|
3941
3926
|
);
|
|
3927
|
+
const tstSim = Math.max(0, ...testTokens.map((tset) => jaccard(selfTokens, tset)));
|
|
3942
3928
|
const nearSelection = selectionAbs.some(
|
|
3943
3929
|
(selectionPath) => isSameDirOrChild(absNorm, selectionPath)
|
|
3944
3930
|
);
|
|
3945
|
-
const nearChanged = changedAbs.some(
|
|
3946
|
-
(changedPath) => isSameDirOrChild(absNorm, changedPath)
|
|
3947
|
-
);
|
|
3931
|
+
const nearChanged = changedAbs.some((changedPath) => isSameDirOrChild(absNorm, changedPath));
|
|
3948
3932
|
const related = selSim > 0 || chgSim > 0 || nearSelection || nearChanged;
|
|
3949
3933
|
const distance = selectionSetAbs.has(absNorm) ? 0 : distFromTests.get(absNorm) ?? INF;
|
|
3950
3934
|
let group = 6;
|
|
@@ -3968,9 +3952,12 @@ var printPerFileCompositeTables = async (opts) => {
|
|
|
3968
3952
|
return { abs: absNorm, rel, linesPct: pct, group, score, distance };
|
|
3969
3953
|
})
|
|
3970
3954
|
);
|
|
3971
|
-
|
|
3972
|
-
|
|
3973
|
-
|
|
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
|
+
);
|
|
3974
3961
|
if (selectionAbs.length > 0) {
|
|
3975
3962
|
const selectionSet = new Set(selectionAbs);
|
|
3976
3963
|
const selectedHead = files.filter((filePath) => selectionSet.has(filePath));
|
|
@@ -3993,7 +3980,7 @@ var printPerFileCompositeTables = async (opts) => {
|
|
|
3993
3980
|
};
|
|
3994
3981
|
|
|
3995
3982
|
// src/lib/jest-bridge.ts
|
|
3996
|
-
var
|
|
3983
|
+
var path9 = __toESM(require("node:path"), 1);
|
|
3997
3984
|
var fs4 = __toESM(require("node:fs"), 1);
|
|
3998
3985
|
var util = __toESM(require("node:util"), 1);
|
|
3999
3986
|
var import_json5 = __toESM(require_lib(), 1);
|
|
@@ -4068,7 +4055,7 @@ var extractBridgePath = (raw, cwd) => {
|
|
|
4068
4055
|
return null;
|
|
4069
4056
|
}
|
|
4070
4057
|
const jsonPath = matches[matches.length - 1][1].trim().replace(/^["'`]|["'`]$/g, "");
|
|
4071
|
-
return
|
|
4058
|
+
return path9.isAbsolute(jsonPath) ? jsonPath : path9.resolve(cwd, jsonPath);
|
|
4072
4059
|
};
|
|
4073
4060
|
var drawRule = (label) => {
|
|
4074
4061
|
const width = Math.max(
|
|
@@ -4667,7 +4654,7 @@ var buildStackSection = (mergedForStack, ctx, fallbackLoc) => {
|
|
|
4667
4654
|
const loc = deepestProjectLoc(mergedForStack, ctx.projectHint);
|
|
4668
4655
|
if (loc) {
|
|
4669
4656
|
const href = preferredEditorHref(loc.file, loc.line, ctx.editorCmd);
|
|
4670
|
-
out.push(` ${ansi.dim("at")} ${osc8(`${
|
|
4657
|
+
out.push(` ${ansi.dim("at")} ${osc8(`${path9.basename(loc.file)}:${loc.line}`, href)}`);
|
|
4671
4658
|
}
|
|
4672
4659
|
out.push("");
|
|
4673
4660
|
return out;
|
|
@@ -4946,7 +4933,7 @@ function renderVitestFromJestJSON(data, opts) {
|
|
|
4946
4933
|
const deepestLoc = deepestProjectLoc(mergedForStack, projectHint);
|
|
4947
4934
|
const locLink = deepestLoc && (() => {
|
|
4948
4935
|
const href = preferredEditorHref(deepestLoc.file, deepestLoc.line, opts?.editorCmd);
|
|
4949
|
-
const base = `${
|
|
4936
|
+
const base = `${path9.basename(deepestLoc.file)}:${deepestLoc.line}`;
|
|
4950
4937
|
return osc8(base, href);
|
|
4951
4938
|
})();
|
|
4952
4939
|
const headerLine = `${ansi.white(header)}${locLink ? ` ${ansi.dim(`(${locLink})`)}` : ""}`;
|
|
@@ -4991,13 +4978,8 @@ ${footer}`;
|
|
|
4991
4978
|
}
|
|
4992
4979
|
|
|
4993
4980
|
// src/lib/program.ts
|
|
4994
|
-
var import_meta = {};
|
|
4995
4981
|
var jestBin = "./node_modules/.bin/jest";
|
|
4996
4982
|
var babelNodeBin = "./node_modules/.bin/babel-node";
|
|
4997
|
-
var moduleSpecifierForRequire = (
|
|
4998
|
-
// @ts-ignore
|
|
4999
|
-
typeof __filename !== "undefined" ? __filename : import_meta.url
|
|
5000
|
-
);
|
|
5001
4983
|
var registerSignalHandlersOnce = () => {
|
|
5002
4984
|
let handled = false;
|
|
5003
4985
|
const on = (sig) => {
|
|
@@ -5015,7 +4997,6 @@ Received ${sig}, exiting...
|
|
|
5015
4997
|
};
|
|
5016
4998
|
var isDebug = () => Boolean(process.env.TEST_CLI_DEBUG);
|
|
5017
4999
|
var mergeLcov = async () => {
|
|
5018
|
-
const jestLcovPath = "coverage/jest/lcov.info";
|
|
5019
5000
|
const vitestLcovPath = "coverage/vitest/lcov.info";
|
|
5020
5001
|
const mergedOutPath = "coverage/lcov.info";
|
|
5021
5002
|
const readOrEmpty = async (filePath) => {
|
|
@@ -5026,7 +5007,7 @@ var mergeLcov = async () => {
|
|
|
5026
5007
|
}
|
|
5027
5008
|
};
|
|
5028
5009
|
let vitestContent = "";
|
|
5029
|
-
|
|
5010
|
+
const jestParts = [];
|
|
5030
5011
|
try {
|
|
5031
5012
|
vitestContent = await readOrEmpty(vitestLcovPath);
|
|
5032
5013
|
} catch (readVitestError) {
|
|
@@ -5034,20 +5015,46 @@ var mergeLcov = async () => {
|
|
|
5034
5015
|
console.info(`read vitest lcov failed: ${String(readVitestError)}`);
|
|
5035
5016
|
}
|
|
5036
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
|
+
};
|
|
5037
5034
|
try {
|
|
5038
|
-
|
|
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
|
+
}
|
|
5039
5046
|
} catch (readJestError) {
|
|
5040
5047
|
if (isDebug()) {
|
|
5041
|
-
console.info(`
|
|
5048
|
+
console.info(`scan jest lcov failed: ${String(readJestError)}`);
|
|
5042
5049
|
}
|
|
5043
5050
|
}
|
|
5044
|
-
if (!vitestContent &&
|
|
5051
|
+
if (!vitestContent && jestParts.length === 0) {
|
|
5045
5052
|
if (isDebug()) {
|
|
5046
5053
|
console.info("No coverage outputs found to merge.");
|
|
5047
5054
|
}
|
|
5048
5055
|
return;
|
|
5049
5056
|
}
|
|
5050
|
-
const merged = [vitestContent.trim(),
|
|
5057
|
+
const merged = [vitestContent.trim(), ...jestParts].filter(Boolean).join("\n");
|
|
5051
5058
|
if (merged.length > 0) {
|
|
5052
5059
|
await (await import("node:fs/promises")).mkdir("coverage", { recursive: true });
|
|
5053
5060
|
await (await import("node:fs/promises")).writeFile(mergedOutPath, `${merged}
|
|
@@ -5060,23 +5067,40 @@ var mergeLcov = async () => {
|
|
|
5060
5067
|
}
|
|
5061
5068
|
};
|
|
5062
5069
|
var emitMergedCoverage = async (ui, opts) => {
|
|
5063
|
-
const jestJson = path9.join("coverage", "jest", "coverage-final.json");
|
|
5064
|
-
const jSize = fsSync3.existsSync(jestJson) ? fsSync3.statSync(jestJson).size : -1;
|
|
5065
|
-
const jestSizeLabel = jSize >= 0 ? `${jSize} bytes` : "missing";
|
|
5066
|
-
if (isDebug()) {
|
|
5067
|
-
console.info(`Coverage JSON probe \u2192 jest: ${jestSizeLabel}`);
|
|
5068
|
-
}
|
|
5069
|
-
const jestData = await readCoverageJson(jestJson);
|
|
5070
|
-
const jestFilesCount = Object.keys(jestData).length;
|
|
5071
|
-
if (isDebug()) {
|
|
5072
|
-
console.info(`Decoded coverage entries \u2192 jest: ${jestFilesCount}`);
|
|
5073
|
-
}
|
|
5074
5070
|
const map = (0, import_istanbul_lib_coverage2.createCoverageMap)({});
|
|
5075
|
-
|
|
5071
|
+
const listJsons = (dir) => {
|
|
5072
|
+
const out = [];
|
|
5076
5073
|
try {
|
|
5077
|
-
|
|
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) {
|
|
5097
|
+
try {
|
|
5098
|
+
const data = await readCoverageJson(jsonPath);
|
|
5099
|
+
if (Object.keys(data).length) {
|
|
5100
|
+
map.merge(data);
|
|
5101
|
+
}
|
|
5078
5102
|
} catch (mergeJestError) {
|
|
5079
|
-
console.warn(`Failed merging jest coverage JSON: ${String(mergeJestError)}`);
|
|
5103
|
+
console.warn(`Failed merging jest coverage JSON @ ${jsonPath}: ${String(mergeJestError)}`);
|
|
5080
5104
|
}
|
|
5081
5105
|
}
|
|
5082
5106
|
if (map.files().length === 0) {
|
|
@@ -5126,7 +5150,7 @@ var emitMergedCoverage = async (ui, opts) => {
|
|
|
5126
5150
|
executedTests: opts.executedTests ?? []
|
|
5127
5151
|
});
|
|
5128
5152
|
const context = LibReport.createContext({
|
|
5129
|
-
dir:
|
|
5153
|
+
dir: path10.resolve("coverage", "merged"),
|
|
5130
5154
|
coverageMap: filteredMap,
|
|
5131
5155
|
defaultSummarizer: "nested"
|
|
5132
5156
|
});
|
|
@@ -5194,8 +5218,8 @@ var emitMergedCoverage = async (ui, opts) => {
|
|
|
5194
5218
|
for (const reporter of reporters) {
|
|
5195
5219
|
reporter.execute(context);
|
|
5196
5220
|
}
|
|
5197
|
-
const textPath =
|
|
5198
|
-
const summaryPath =
|
|
5221
|
+
const textPath = path10.resolve("coverage", "merged", "coverage.txt");
|
|
5222
|
+
const summaryPath = path10.resolve("coverage", "merged", "coverage-summary.txt");
|
|
5199
5223
|
const filesToPrint = [];
|
|
5200
5224
|
if (fsSync3.existsSync(textPath)) {
|
|
5201
5225
|
filesToPrint.push(textPath);
|
|
@@ -5277,17 +5301,43 @@ var program = async () => {
|
|
|
5277
5301
|
coverageMode,
|
|
5278
5302
|
coverageMaxFiles: coverageMaxFilesArg,
|
|
5279
5303
|
coverageMaxHotspots: coverageMaxHotspotsArg,
|
|
5280
|
-
coveragePageFit
|
|
5304
|
+
coveragePageFit,
|
|
5305
|
+
changed
|
|
5281
5306
|
} = deriveArgs(argv);
|
|
5282
|
-
|
|
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
|
+
);
|
|
5283
5333
|
const { jest } = argsForDiscovery(["run"], jestArgs);
|
|
5284
|
-
const selectionLooksLikeTest =
|
|
5334
|
+
const selectionLooksLikeTest = selectionPathsAugmented.some(
|
|
5285
5335
|
(pathText) => /\.(test|spec)\.[tj]sx?$/i.test(pathText) || /(^|\/)tests?\//i.test(pathText)
|
|
5286
5336
|
);
|
|
5287
|
-
const selectionLooksLikePath =
|
|
5337
|
+
const selectionLooksLikePath = selectionPathsAugmented.some(
|
|
5288
5338
|
(pathText) => /[\\/]/.test(pathText) || /\.(m?[tj]sx?)$/i.test(pathText)
|
|
5289
5339
|
);
|
|
5290
|
-
const selectionHasPaths =
|
|
5340
|
+
const selectionHasPaths = selectionPathsAugmented.length > 0;
|
|
5291
5341
|
const repoRootForDiscovery = workspaceRoot ?? await findRepoRoot();
|
|
5292
5342
|
const expandProductionSelections = async (tokens, repoRoot) => {
|
|
5293
5343
|
const results = /* @__PURE__ */ new Set();
|
|
@@ -5296,18 +5346,18 @@ var program = async () => {
|
|
|
5296
5346
|
if (!token) {
|
|
5297
5347
|
continue;
|
|
5298
5348
|
}
|
|
5299
|
-
const isAbs =
|
|
5349
|
+
const isAbs = path10.isAbsolute(token);
|
|
5300
5350
|
const looksLikeRelPath = /[\\/]/.test(token);
|
|
5301
5351
|
let candidateFromRoot;
|
|
5302
5352
|
if (token.startsWith("/")) {
|
|
5303
|
-
candidateFromRoot =
|
|
5353
|
+
candidateFromRoot = path10.join(repoRoot, token.slice(1));
|
|
5304
5354
|
} else if (looksLikeRelPath) {
|
|
5305
|
-
candidateFromRoot =
|
|
5355
|
+
candidateFromRoot = path10.join(repoRoot, token);
|
|
5306
5356
|
} else {
|
|
5307
5357
|
candidateFromRoot = void 0;
|
|
5308
5358
|
}
|
|
5309
5359
|
const tryPushIfProd = (absPath) => {
|
|
5310
|
-
const norm =
|
|
5360
|
+
const norm = path10.resolve(absPath).replace(/\\/g, "/");
|
|
5311
5361
|
const isTest = /(^|\/)tests?\//i.test(norm) || /\.(test|spec)\.[tj]sx?$/i.test(norm);
|
|
5312
5362
|
if (!isTest && fsSync3.existsSync(norm)) {
|
|
5313
5363
|
results.add(norm);
|
|
@@ -5329,7 +5379,7 @@ var program = async () => {
|
|
|
5329
5379
|
}),
|
|
5330
5380
|
timeoutMs: 4e3
|
|
5331
5381
|
});
|
|
5332
|
-
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(
|
|
5333
5383
|
(abs) => !abs.includes("/node_modules/") && !abs.includes("/coverage/") && !/(^|\/)tests?\//i.test(abs) && !/\.(test|spec)\.[tj]sx?$/i.test(abs)
|
|
5334
5384
|
);
|
|
5335
5385
|
matches.forEach((abs) => results.add(abs));
|
|
@@ -5338,20 +5388,20 @@ var program = async () => {
|
|
|
5338
5388
|
}
|
|
5339
5389
|
return Array.from(results);
|
|
5340
5390
|
};
|
|
5341
|
-
const initialProdSelections =
|
|
5391
|
+
const initialProdSelections = selectionPathsAugmented.filter(
|
|
5342
5392
|
(pathText) => (/[\\/]/.test(pathText) || /\.(m?[tj]sx?)$/i.test(pathText)) && !/(^|\/)tests?\//i.test(pathText) && !/\.(test|spec)\.[tj]sx?$/i.test(pathText)
|
|
5343
5393
|
);
|
|
5344
|
-
const expandedProdSelections = initialProdSelections.length ? initialProdSelections : await expandProductionSelections(
|
|
5394
|
+
const expandedProdSelections = initialProdSelections.length ? initialProdSelections : await expandProductionSelections(selectionPathsAugmented, repoRootForDiscovery);
|
|
5345
5395
|
const selectionIncludesProdPaths = expandedProdSelections.length > 0;
|
|
5346
5396
|
console.info(
|
|
5347
5397
|
`Selection classify \u2192 looksLikePath=${selectionLooksLikePath} looksLikeTest=${selectionLooksLikeTest} prodPaths=${selectionIncludesProdPaths}`
|
|
5348
5398
|
);
|
|
5349
|
-
const stripPathTokens = (args) => args.filter((token) => !
|
|
5399
|
+
const stripPathTokens = (args) => args.filter((token) => !selectionPathsAugmented.includes(token));
|
|
5350
5400
|
const jestDiscoveryArgs = selectionIncludesProdPaths ? stripPathTokens(jest) : jest;
|
|
5351
5401
|
const projectConfigs = [];
|
|
5352
5402
|
try {
|
|
5353
|
-
const baseCfg =
|
|
5354
|
-
const tsCfg =
|
|
5403
|
+
const baseCfg = path10.resolve("jest.config.js");
|
|
5404
|
+
const tsCfg = path10.resolve("jest.ts.config.js");
|
|
5355
5405
|
if (fsSync3.existsSync(baseCfg)) {
|
|
5356
5406
|
projectConfigs.push(baseCfg);
|
|
5357
5407
|
}
|
|
@@ -5368,7 +5418,7 @@ var program = async () => {
|
|
|
5368
5418
|
);
|
|
5369
5419
|
const prodSelections2 = expandedProdSelections;
|
|
5370
5420
|
for (const cfg of projectConfigs) {
|
|
5371
|
-
const cfgCwd =
|
|
5421
|
+
const cfgCwd = path10.dirname(cfg);
|
|
5372
5422
|
const allTests = await discoverJestResilient([...jestDiscoveryArgs, "--config", cfg], {
|
|
5373
5423
|
cwd: cfgCwd
|
|
5374
5424
|
});
|
|
@@ -5381,7 +5431,7 @@ var program = async () => {
|
|
|
5381
5431
|
});
|
|
5382
5432
|
} catch (err) {
|
|
5383
5433
|
if (isDebug()) {
|
|
5384
|
-
console.warn(`direct selection failed for project ${
|
|
5434
|
+
console.warn(`direct selection failed for project ${path10.basename(cfg)}: ${String(err)}`);
|
|
5385
5435
|
}
|
|
5386
5436
|
}
|
|
5387
5437
|
perProjectFiles.set(cfg, directPerProject);
|
|
@@ -5393,7 +5443,7 @@ var program = async () => {
|
|
|
5393
5443
|
)} | related=${selectionIncludesProdPaths} | cwd=${repoRootForDiscovery}`
|
|
5394
5444
|
);
|
|
5395
5445
|
for (const cfg of projectConfigs) {
|
|
5396
|
-
const cfgCwd =
|
|
5446
|
+
const cfgCwd = path10.dirname(cfg);
|
|
5397
5447
|
const files = await discoverJestResilient([...jestDiscoveryArgs, "--config", cfg], {
|
|
5398
5448
|
cwd: cfgCwd
|
|
5399
5449
|
});
|
|
@@ -5403,18 +5453,18 @@ var program = async () => {
|
|
|
5403
5453
|
const perProjectFiltered = /* @__PURE__ */ new Map();
|
|
5404
5454
|
for (const cfg of projectConfigs) {
|
|
5405
5455
|
const files = perProjectFiles.get(cfg) ?? [];
|
|
5406
|
-
const selectionTestPaths =
|
|
5456
|
+
const selectionTestPaths = selectionPathsAugmented.filter(
|
|
5407
5457
|
(pathToken) => /\.(test|spec)\.[tj]sx?$/i.test(pathToken) || /(^|\/)tests?\//i.test(pathToken)
|
|
5408
5458
|
);
|
|
5409
5459
|
const candidates = selectionHasPaths && selectionLooksLikeTest ? selectionTestPaths : files;
|
|
5410
5460
|
const absFiles = candidates.map(
|
|
5411
|
-
(candidatePath) =>
|
|
5461
|
+
(candidatePath) => path10.isAbsolute(candidatePath) ? candidatePath : path10.join(repoRootForDiscovery, candidatePath)
|
|
5412
5462
|
).map((absolutePath) => absolutePath.replace(/\\/g, "/"));
|
|
5413
5463
|
const onlyOwned = await filterCandidatesForProject(
|
|
5414
5464
|
cfg,
|
|
5415
5465
|
jestDiscoveryArgs,
|
|
5416
5466
|
absFiles,
|
|
5417
|
-
|
|
5467
|
+
path10.dirname(cfg)
|
|
5418
5468
|
);
|
|
5419
5469
|
perProjectFiltered.set(cfg, onlyOwned);
|
|
5420
5470
|
}
|
|
@@ -5426,7 +5476,7 @@ var program = async () => {
|
|
|
5426
5476
|
if (selectionHasPaths && prodSelections.length > 0) {
|
|
5427
5477
|
console.info(`rg related \u2192 prodSelections=${prodSelections.length} (starting)`);
|
|
5428
5478
|
const repoRootForRefinement = workspaceRoot ?? await findRepoRoot();
|
|
5429
|
-
const selectionKey = prodSelections.map((absPath) =>
|
|
5479
|
+
const selectionKey = prodSelections.map((absPath) => path10.relative(repoRootForRefinement, absPath).replace(/\\/g, "/")).sort((firstPath, secondPath) => firstPath.localeCompare(secondPath)).join("|");
|
|
5430
5480
|
const { cachedRelated: cachedRelated2, findRelatedTestsFast: findRelatedTestsFast2, DEFAULT_TEST_GLOBS: DEFAULT_TEST_GLOBS2 } = await Promise.resolve().then(() => (init_fast_related(), fast_related_exports));
|
|
5431
5481
|
const { DEFAULT_EXCLUDE: DEFAULT_EXCLUDE2 } = await Promise.resolve().then(() => (init_args(), args_exports));
|
|
5432
5482
|
const rgMatches = await cachedRelated2({
|
|
@@ -5456,7 +5506,7 @@ var program = async () => {
|
|
|
5456
5506
|
cfg,
|
|
5457
5507
|
jestDiscoveryArgs,
|
|
5458
5508
|
rgCandidates,
|
|
5459
|
-
|
|
5509
|
+
path10.dirname(cfg)
|
|
5460
5510
|
);
|
|
5461
5511
|
perProjectFromRg.set(cfg, owned);
|
|
5462
5512
|
}
|
|
@@ -5471,9 +5521,9 @@ var program = async () => {
|
|
|
5471
5521
|
} else {
|
|
5472
5522
|
const repoRootForScan = repoRootForDiscovery;
|
|
5473
5523
|
const toSeeds = (abs) => {
|
|
5474
|
-
const rel =
|
|
5524
|
+
const rel = path10.relative(repoRootForScan, abs).replace(/\\/g, "/");
|
|
5475
5525
|
const withoutExt = rel.replace(/\.(m?[tj]sx?)$/i, "");
|
|
5476
|
-
const base =
|
|
5526
|
+
const base = path10.basename(withoutExt);
|
|
5477
5527
|
const segs = withoutExt.split("/");
|
|
5478
5528
|
const tail2 = segs.slice(-2).join("/");
|
|
5479
5529
|
return Array.from(new Set([withoutExt, base, tail2].filter(Boolean)));
|
|
@@ -5488,8 +5538,8 @@ var program = async () => {
|
|
|
5488
5538
|
}
|
|
5489
5539
|
};
|
|
5490
5540
|
const resolveLocalImport = (fromFile, spec) => {
|
|
5491
|
-
const baseDir =
|
|
5492
|
-
const cand =
|
|
5541
|
+
const baseDir = path10.dirname(fromFile);
|
|
5542
|
+
const cand = path10.resolve(baseDir, spec);
|
|
5493
5543
|
const exts = ["", ".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs"];
|
|
5494
5544
|
for (const ext of exts) {
|
|
5495
5545
|
const full = ext ? `${cand}${ext}` : cand;
|
|
@@ -5498,7 +5548,7 @@ var program = async () => {
|
|
|
5498
5548
|
}
|
|
5499
5549
|
}
|
|
5500
5550
|
for (const ext of exts) {
|
|
5501
|
-
const full =
|
|
5551
|
+
const full = path10.join(cand, `index${ext}`);
|
|
5502
5552
|
if (fsSync3.existsSync(full)) {
|
|
5503
5553
|
return full;
|
|
5504
5554
|
}
|
|
@@ -5552,7 +5602,7 @@ var program = async () => {
|
|
|
5552
5602
|
cfg,
|
|
5553
5603
|
jestDiscoveryArgs,
|
|
5554
5604
|
keptCandidates,
|
|
5555
|
-
|
|
5605
|
+
path10.dirname(cfg)
|
|
5556
5606
|
);
|
|
5557
5607
|
perProjectFromScan.set(cfg, owned);
|
|
5558
5608
|
}
|
|
@@ -5579,9 +5629,9 @@ var program = async () => {
|
|
|
5579
5629
|
if (effectiveJestFiles.length === 0) {
|
|
5580
5630
|
const repoRoot = repoRootForRefinement;
|
|
5581
5631
|
const seeds = prodSelections.map(
|
|
5582
|
-
(abs) =>
|
|
5632
|
+
(abs) => path10.relative(repoRoot, abs).replace(/\\/g, "/").replace(/\.(m?[tj]sx?)$/i, "")
|
|
5583
5633
|
).flatMap((rel) => {
|
|
5584
|
-
const base =
|
|
5634
|
+
const base = path10.basename(rel);
|
|
5585
5635
|
const segments = rel.split("/");
|
|
5586
5636
|
return Array.from(new Set([rel, base, segments.slice(-2).join("/")].filter(Boolean)));
|
|
5587
5637
|
});
|
|
@@ -5594,8 +5644,8 @@ var program = async () => {
|
|
|
5594
5644
|
}
|
|
5595
5645
|
};
|
|
5596
5646
|
const resolveLocalImport = (fromFile, spec) => {
|
|
5597
|
-
const baseDir =
|
|
5598
|
-
const candidate =
|
|
5647
|
+
const baseDir = path10.dirname(fromFile);
|
|
5648
|
+
const candidate = path10.resolve(baseDir, spec);
|
|
5599
5649
|
const extensions = ["", ".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs", ".mts", ".cts"];
|
|
5600
5650
|
for (const ext of extensions) {
|
|
5601
5651
|
const fullPath = ext ? `${candidate}${ext}` : candidate;
|
|
@@ -5604,7 +5654,7 @@ var program = async () => {
|
|
|
5604
5654
|
}
|
|
5605
5655
|
}
|
|
5606
5656
|
for (const ext of extensions) {
|
|
5607
|
-
const fullPath =
|
|
5657
|
+
const fullPath = path10.join(candidate, `index${ext}`);
|
|
5608
5658
|
if (fsSync3.existsSync(fullPath)) {
|
|
5609
5659
|
return fullPath;
|
|
5610
5660
|
}
|
|
@@ -5723,8 +5773,8 @@ var program = async () => {
|
|
|
5723
5773
|
}
|
|
5724
5774
|
}
|
|
5725
5775
|
const jestDecision = decideShouldRunJest([], effectiveJestFiles, {
|
|
5726
|
-
selectionSpecified,
|
|
5727
|
-
selectionPaths
|
|
5776
|
+
selectionSpecified: selectionSpecifiedAugmented,
|
|
5777
|
+
selectionPaths: selectionPathsAugmented
|
|
5728
5778
|
});
|
|
5729
5779
|
const { shouldRunJest } = jestDecision;
|
|
5730
5780
|
const jestCount = effectiveJestFiles.length;
|
|
@@ -5742,45 +5792,63 @@ var program = async () => {
|
|
|
5742
5792
|
}
|
|
5743
5793
|
console.info(`Run plan \u2192 Jest maybe=${shouldRunJest} (projects=${projectConfigs.length})`);
|
|
5744
5794
|
let jestExitCode = 0;
|
|
5795
|
+
const allBridgeJson = [];
|
|
5745
5796
|
const executedTestFilesSet = /* @__PURE__ */ new Set();
|
|
5746
5797
|
if (shouldRunJest) {
|
|
5747
5798
|
console.info("Starting Jest (no Vitest targets)\u2026");
|
|
5748
5799
|
await runJestBootstrap();
|
|
5749
5800
|
const jestRunArgs = selectionIncludesProdPaths ? stripPathTokens(jestArgs) : jestArgs;
|
|
5801
|
+
const sanitizedJestRunArgs = jestRunArgs.filter(
|
|
5802
|
+
(arg) => !/^--coverageDirectory(?:=|$)/.test(String(arg))
|
|
5803
|
+
);
|
|
5750
5804
|
const projectsToRun = projectConfigs.filter(
|
|
5751
5805
|
(cfg) => (perProjectFiltered.get(cfg) ?? []).length > 0
|
|
5752
5806
|
);
|
|
5753
|
-
const totalProjectsToRun = projectsToRun.length;
|
|
5754
5807
|
const stripFooter = (text) => {
|
|
5755
5808
|
const lines = text.split("\n");
|
|
5756
5809
|
const idx = lines.findIndex((ln) => /^Test Files\s/.test(stripAnsiSimple(ln)));
|
|
5757
5810
|
return idx >= 0 ? lines.slice(0, idx).join("\n").trimEnd() : text;
|
|
5758
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
|
+
});
|
|
5759
5828
|
for (let projIndex = 0; projIndex < projectsToRun.length; projIndex += 1) {
|
|
5760
5829
|
const cfg = projectsToRun[projIndex];
|
|
5761
|
-
const isLastProject = projIndex === totalProjectsToRun - 1;
|
|
5762
5830
|
const files = perProjectFiltered.get(cfg) ?? [];
|
|
5763
5831
|
if (files.length === 0) {
|
|
5764
|
-
console.info(`Project ${
|
|
5832
|
+
console.info(`Project ${path10.basename(cfg)}: 0 matching tests after filter; skipping.`);
|
|
5765
5833
|
continue;
|
|
5766
5834
|
}
|
|
5767
5835
|
files.forEach(
|
|
5768
|
-
(absTestPath) => executedTestFilesSet.add(
|
|
5836
|
+
(absTestPath) => executedTestFilesSet.add(path10.resolve(absTestPath).replace(/\\/g, "/"))
|
|
5769
5837
|
);
|
|
5770
|
-
const outJson =
|
|
5838
|
+
const outJson = path10.join(
|
|
5771
5839
|
os2.tmpdir(),
|
|
5772
5840
|
`jest-bridge-${Date.now()}-${Math.random().toString(36).slice(2)}.json`
|
|
5773
5841
|
);
|
|
5774
|
-
const reporterPath =
|
|
5842
|
+
const reporterPath = path10.resolve("scripts/jest-vitest-bridge.cjs");
|
|
5775
5843
|
try {
|
|
5776
5844
|
if (!fsSync3.existsSync(reporterPath)) {
|
|
5777
|
-
fsSync3.mkdirSync(
|
|
5845
|
+
fsSync3.mkdirSync(path10.dirname(reporterPath), { recursive: true });
|
|
5778
5846
|
fsSync3.writeFileSync(reporterPath, JEST_BRIDGE_REPORTER_SOURCE, "utf8");
|
|
5779
5847
|
}
|
|
5780
5848
|
} catch (ensureReporterError) {
|
|
5781
5849
|
console.warn(`Unable to ensure jest bridge reporter: ${String(ensureReporterError)}`);
|
|
5782
5850
|
}
|
|
5783
|
-
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}`);
|
|
5784
5852
|
const coverageFromArgs = [];
|
|
5785
5853
|
for (const relPath of selectedFilesForCoverage) {
|
|
5786
5854
|
coverageFromArgs.push("--collectCoverageFrom", relPath);
|
|
@@ -5794,14 +5862,17 @@ var program = async () => {
|
|
|
5794
5862
|
"--config",
|
|
5795
5863
|
cfg,
|
|
5796
5864
|
"--runTestsByPath",
|
|
5797
|
-
|
|
5798
|
-
reporterPath,
|
|
5865
|
+
`--reporters=${reporterPath}`,
|
|
5799
5866
|
"--silent",
|
|
5800
5867
|
"--colors",
|
|
5801
5868
|
"--json",
|
|
5802
5869
|
"--outputFile",
|
|
5803
5870
|
outJson,
|
|
5804
|
-
...
|
|
5871
|
+
...sanitizedJestRunArgs,
|
|
5872
|
+
...collectCoverage ? [
|
|
5873
|
+
"--coverageDirectory",
|
|
5874
|
+
path10.join("coverage", "jest", path10.basename(cfg).replace(/[^a-zA-Z0-9_.-]+/g, "_"))
|
|
5875
|
+
] : [],
|
|
5805
5876
|
...coverageFromArgs,
|
|
5806
5877
|
"--passWithNoTests",
|
|
5807
5878
|
...files
|
|
@@ -5827,10 +5898,22 @@ var program = async () => {
|
|
|
5827
5898
|
const jsonText = fsSync3.readFileSync(outJson, "utf8");
|
|
5828
5899
|
const parsed = JSON.parse(jsonText);
|
|
5829
5900
|
const bridge = coerceJestJsonToBridge(parsed);
|
|
5830
|
-
|
|
5831
|
-
|
|
5832
|
-
|
|
5833
|
-
|
|
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
|
+
}
|
|
5834
5917
|
if (debug) {
|
|
5835
5918
|
const preview = pretty.split("\n").slice(0, 3).join("\n");
|
|
5836
5919
|
console.info(`pretty preview (json):
|
|
@@ -5854,9 +5937,7 @@ ${preview}${pretty.includes("\n") ? "\n\u2026" : ""}`);
|
|
|
5854
5937
|
${preview}${pretty.includes("\n") ? "\n\u2026" : ""}`);
|
|
5855
5938
|
}
|
|
5856
5939
|
}
|
|
5857
|
-
|
|
5858
|
-
pretty = stripFooter(pretty);
|
|
5859
|
-
}
|
|
5940
|
+
pretty = stripFooter(pretty);
|
|
5860
5941
|
if (pretty.trim().length > 0) {
|
|
5861
5942
|
process.stdout.write(pretty.endsWith("\n") ? pretty : `${pretty}
|
|
5862
5943
|
`);
|
|
@@ -5868,15 +5949,69 @@ ${preview}${pretty.includes("\n") ? "\n\u2026" : ""}`);
|
|
|
5868
5949
|
} else {
|
|
5869
5950
|
console.info("Jest run skipped based on selection and thresholds.");
|
|
5870
5951
|
}
|
|
5871
|
-
if (
|
|
5872
|
-
|
|
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;
|
|
5873
6008
|
}
|
|
5874
6009
|
if (collectCoverage && shouldRunJest) {
|
|
5875
6010
|
await mergeLcov();
|
|
5876
6011
|
const repoRoot = workspaceRoot ?? await findRepoRoot();
|
|
5877
6012
|
const mergedOptsBase = {
|
|
5878
|
-
selectionSpecified,
|
|
5879
|
-
selectionPaths,
|
|
6013
|
+
selectionSpecified: selectionSpecifiedAugmented,
|
|
6014
|
+
selectionPaths: selectionPathsAugmented,
|
|
5880
6015
|
includeGlobs,
|
|
5881
6016
|
excludeGlobs,
|
|
5882
6017
|
workspaceRoot: repoRoot,
|
|
@@ -5891,7 +6026,6 @@ ${preview}${pretty.includes("\n") ? "\n\u2026" : ""}`);
|
|
|
5891
6026
|
};
|
|
5892
6027
|
await emitMergedCoverage(coverageUi, mergedOptsBase);
|
|
5893
6028
|
}
|
|
5894
|
-
const finalExitCode = jestExitCode;
|
|
5895
6029
|
process.exit(finalExitCode);
|
|
5896
6030
|
};
|
|
5897
6031
|
|