tryscript 0.1.4 → 0.1.5
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 +2 -2
- package/dist/bin.cjs +7 -300
- package/dist/bin.cjs.map +1 -1
- package/dist/bin.mjs +8 -301
- package/dist/bin.mjs.map +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.d.cts +10 -8
- package/dist/index.d.mts +10 -8
- package/dist/index.mjs +1 -1
- package/dist/{src-D60Uy8QA.mjs → src-CC3xA1cp.mjs} +117 -7
- package/dist/src-CC3xA1cp.mjs.map +1 -0
- package/dist/{src-BGWMAShO.cjs → src-D-bd-j9T.cjs} +116 -6
- package/dist/src-D-bd-j9T.cjs.map +1 -0
- package/docs/tryscript-reference.md +158 -65
- package/package.json +2 -4
- package/dist/src-BGWMAShO.cjs.map +0 -1
- package/dist/src-D60Uy8QA.mjs.map +0 -1
package/README.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# tryscript
|
|
2
2
|
|
|
3
|
-
[](https://github.com/jlevy/tryscript/actions/runs/
|
|
4
|
-
[](https://github.com/jlevy/tryscript/actions/runs/
|
|
3
|
+
[](https://github.com/jlevy/tryscript/actions/runs/21087258139)
|
|
4
|
+
[](https://github.com/jlevy/tryscript/actions/runs/21087258139)
|
|
5
5
|
[](https://www.npmjs.com/package/tryscript)
|
|
6
6
|
[](https://x.com/ojoshe)
|
|
7
7
|
|
package/dist/bin.cjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
|
|
4
|
-
const require_src = require('./src-
|
|
4
|
+
const require_src = require('./src-D-bd-j9T.cjs');
|
|
5
5
|
let node_url = require("node:url");
|
|
6
6
|
let node_fs = require("node:fs");
|
|
7
7
|
let node_path = require("node:path");
|
|
@@ -170,237 +170,6 @@ function buildUpdatedBlock(block, result) {
|
|
|
170
170
|
return lines.join("\n");
|
|
171
171
|
}
|
|
172
172
|
|
|
173
|
-
//#endregion
|
|
174
|
-
//#region src/lib/lcov.ts
|
|
175
|
-
/**
|
|
176
|
-
* LCOV parsing, merging, and writing utilities.
|
|
177
|
-
*
|
|
178
|
-
* LCOV format reference:
|
|
179
|
-
* - SF: Source file path
|
|
180
|
-
* - DA:linenum,hitcount - Line data
|
|
181
|
-
* - FN:linenum,funcname - Function definition
|
|
182
|
-
* - FNDA:hitcount,funcname - Function hit data
|
|
183
|
-
* - FNF: Functions found count
|
|
184
|
-
* - FNH: Functions hit count
|
|
185
|
-
* - BRF: Branches found count
|
|
186
|
-
* - BRH: Branches hit count
|
|
187
|
-
* - BRDA:line,block,branch,taken - Branch data
|
|
188
|
-
* - LF: Lines found count
|
|
189
|
-
* - LH: Lines hit count
|
|
190
|
-
* - end_of_record - End of file record
|
|
191
|
-
*/
|
|
192
|
-
/**
|
|
193
|
-
* Parse LCOV content into structured data.
|
|
194
|
-
*/
|
|
195
|
-
function parseLcov(content) {
|
|
196
|
-
const files = /* @__PURE__ */ new Map();
|
|
197
|
-
let currentFile = null;
|
|
198
|
-
for (const line of content.split("\n")) {
|
|
199
|
-
const trimmed = line.trim();
|
|
200
|
-
if (trimmed.startsWith("SF:")) {
|
|
201
|
-
const path = trimmed.slice(3);
|
|
202
|
-
currentFile = {
|
|
203
|
-
path,
|
|
204
|
-
lines: /* @__PURE__ */ new Map(),
|
|
205
|
-
functions: /* @__PURE__ */ new Map(),
|
|
206
|
-
branches: []
|
|
207
|
-
};
|
|
208
|
-
files.set(path, currentFile);
|
|
209
|
-
} else if (trimmed.startsWith("DA:") && currentFile) {
|
|
210
|
-
const parts = trimmed.slice(3).split(",");
|
|
211
|
-
const lineNumber = parseInt(parts[0], 10);
|
|
212
|
-
const hitCount = parseInt(parts[1], 10);
|
|
213
|
-
currentFile.lines.set(lineNumber, {
|
|
214
|
-
lineNumber,
|
|
215
|
-
hitCount
|
|
216
|
-
});
|
|
217
|
-
} else if (trimmed.startsWith("FN:") && currentFile) {
|
|
218
|
-
const parts = trimmed.slice(3).split(",");
|
|
219
|
-
const lineNumber = parseInt(parts[0], 10);
|
|
220
|
-
const name = parts.slice(1).join(",");
|
|
221
|
-
if (!currentFile.functions.has(name)) currentFile.functions.set(name, {
|
|
222
|
-
name,
|
|
223
|
-
lineNumber,
|
|
224
|
-
hitCount: 0
|
|
225
|
-
});
|
|
226
|
-
else currentFile.functions.get(name).lineNumber = lineNumber;
|
|
227
|
-
} else if (trimmed.startsWith("FNDA:") && currentFile) {
|
|
228
|
-
const parts = trimmed.slice(5).split(",");
|
|
229
|
-
const hitCount = parseInt(parts[0], 10);
|
|
230
|
-
const name = parts.slice(1).join(",");
|
|
231
|
-
if (currentFile.functions.has(name)) currentFile.functions.get(name).hitCount = hitCount;
|
|
232
|
-
else currentFile.functions.set(name, {
|
|
233
|
-
name,
|
|
234
|
-
lineNumber: 0,
|
|
235
|
-
hitCount
|
|
236
|
-
});
|
|
237
|
-
} else if (trimmed.startsWith("BRDA:") && currentFile) {
|
|
238
|
-
const parts = trimmed.slice(5).split(",");
|
|
239
|
-
currentFile.branches.push({
|
|
240
|
-
line: parseInt(parts[0], 10),
|
|
241
|
-
block: parseInt(parts[1], 10),
|
|
242
|
-
branch: parseInt(parts[2], 10),
|
|
243
|
-
taken: parts[3] === "-" ? -1 : parseInt(parts[3], 10)
|
|
244
|
-
});
|
|
245
|
-
} else if (trimmed === "end_of_record") currentFile = null;
|
|
246
|
-
}
|
|
247
|
-
return { files };
|
|
248
|
-
}
|
|
249
|
-
/**
|
|
250
|
-
* Merge multiple LCOV data structures, taking max hit counts.
|
|
251
|
-
*/
|
|
252
|
-
function mergeLcov(...lcovs) {
|
|
253
|
-
const merged = /* @__PURE__ */ new Map();
|
|
254
|
-
for (const lcov of lcovs) for (const [path, file] of lcov.files) if (!merged.has(path)) merged.set(path, {
|
|
255
|
-
path,
|
|
256
|
-
lines: new Map(file.lines),
|
|
257
|
-
functions: new Map(file.functions),
|
|
258
|
-
branches: [...file.branches]
|
|
259
|
-
});
|
|
260
|
-
else {
|
|
261
|
-
const existing = merged.get(path);
|
|
262
|
-
for (const [lineNum, lineData] of file.lines) {
|
|
263
|
-
const existingLine = existing.lines.get(lineNum);
|
|
264
|
-
if (existingLine) existingLine.hitCount = Math.max(existingLine.hitCount, lineData.hitCount);
|
|
265
|
-
else existing.lines.set(lineNum, { ...lineData });
|
|
266
|
-
}
|
|
267
|
-
for (const [name, funcData] of file.functions) {
|
|
268
|
-
const existingFunc = existing.functions.get(name);
|
|
269
|
-
if (existingFunc) existingFunc.hitCount = Math.max(existingFunc.hitCount, funcData.hitCount);
|
|
270
|
-
else existing.functions.set(name, { ...funcData });
|
|
271
|
-
}
|
|
272
|
-
for (const branch of file.branches) {
|
|
273
|
-
const existingBranch = existing.branches.find((b) => b.line === branch.line && b.block === branch.block && b.branch === branch.branch);
|
|
274
|
-
if (existingBranch) {
|
|
275
|
-
if (branch.taken >= 0) existingBranch.taken = existingBranch.taken >= 0 ? Math.max(existingBranch.taken, branch.taken) : branch.taken;
|
|
276
|
-
} else existing.branches.push({ ...branch });
|
|
277
|
-
}
|
|
278
|
-
}
|
|
279
|
-
return { files: merged };
|
|
280
|
-
}
|
|
281
|
-
/**
|
|
282
|
-
* Convert LCOV data back to LCOV format string.
|
|
283
|
-
*/
|
|
284
|
-
function formatLcov(lcov) {
|
|
285
|
-
const lines = [];
|
|
286
|
-
for (const file of lcov.files.values()) {
|
|
287
|
-
lines.push(`SF:${file.path}`);
|
|
288
|
-
const sortedFunctions = [...file.functions.values()].sort((a, b) => a.lineNumber - b.lineNumber);
|
|
289
|
-
for (const func of sortedFunctions) lines.push(`FN:${func.lineNumber},${func.name}`);
|
|
290
|
-
for (const func of sortedFunctions) lines.push(`FNDA:${func.hitCount},${func.name}`);
|
|
291
|
-
const fnf = file.functions.size;
|
|
292
|
-
const fnh = [...file.functions.values()].filter((f) => f.hitCount > 0).length;
|
|
293
|
-
lines.push(`FNF:${fnf}`);
|
|
294
|
-
lines.push(`FNH:${fnh}`);
|
|
295
|
-
for (const branch of file.branches) {
|
|
296
|
-
const taken = branch.taken < 0 ? "-" : branch.taken.toString();
|
|
297
|
-
lines.push(`BRDA:${branch.line},${branch.block},${branch.branch},${taken}`);
|
|
298
|
-
}
|
|
299
|
-
const brf = file.branches.length;
|
|
300
|
-
const brh = file.branches.filter((b) => b.taken > 0).length;
|
|
301
|
-
lines.push(`BRF:${brf}`);
|
|
302
|
-
lines.push(`BRH:${brh}`);
|
|
303
|
-
const sortedLines = [...file.lines.values()].sort((a, b) => a.lineNumber - b.lineNumber);
|
|
304
|
-
for (const line of sortedLines) lines.push(`DA:${line.lineNumber},${line.hitCount}`);
|
|
305
|
-
const lf = file.lines.size;
|
|
306
|
-
const lh = [...file.lines.values()].filter((l) => l.hitCount > 0).length;
|
|
307
|
-
lines.push(`LF:${lf}`);
|
|
308
|
-
lines.push(`LH:${lh}`);
|
|
309
|
-
lines.push("end_of_record");
|
|
310
|
-
}
|
|
311
|
-
return lines.join("\n") + "\n";
|
|
312
|
-
}
|
|
313
|
-
/**
|
|
314
|
-
* Convert LCOV data to JSON summary format (compatible with istanbul/vitest).
|
|
315
|
-
*/
|
|
316
|
-
function lcovToJsonSummary(lcov) {
|
|
317
|
-
const withPct = (total, covered) => ({
|
|
318
|
-
total,
|
|
319
|
-
covered,
|
|
320
|
-
skipped: 0,
|
|
321
|
-
pct: total > 0 ? parseFloat((covered / total * 100).toFixed(2)) : 100
|
|
322
|
-
});
|
|
323
|
-
const totals = {
|
|
324
|
-
lines: {
|
|
325
|
-
total: 0,
|
|
326
|
-
covered: 0
|
|
327
|
-
},
|
|
328
|
-
functions: {
|
|
329
|
-
total: 0,
|
|
330
|
-
covered: 0
|
|
331
|
-
},
|
|
332
|
-
branches: {
|
|
333
|
-
total: 0,
|
|
334
|
-
covered: 0
|
|
335
|
-
}
|
|
336
|
-
};
|
|
337
|
-
const summary = { total: {
|
|
338
|
-
lines: withPct(0, 0),
|
|
339
|
-
statements: withPct(0, 0),
|
|
340
|
-
functions: withPct(0, 0),
|
|
341
|
-
branches: withPct(0, 0),
|
|
342
|
-
branchesTrue: {
|
|
343
|
-
total: 0,
|
|
344
|
-
covered: 0,
|
|
345
|
-
skipped: 0,
|
|
346
|
-
pct: 100
|
|
347
|
-
}
|
|
348
|
-
} };
|
|
349
|
-
for (const file of lcov.files.values()) {
|
|
350
|
-
const linesTotal = file.lines.size;
|
|
351
|
-
const linesCovered = [...file.lines.values()].filter((l) => l.hitCount > 0).length;
|
|
352
|
-
const funcsTotal = file.functions.size;
|
|
353
|
-
const funcsCovered = [...file.functions.values()].filter((f) => f.hitCount > 0).length;
|
|
354
|
-
const branchesTotal = file.branches.length;
|
|
355
|
-
const branchesCovered = file.branches.filter((b) => b.taken > 0).length;
|
|
356
|
-
summary[file.path] = {
|
|
357
|
-
lines: withPct(linesTotal, linesCovered),
|
|
358
|
-
statements: withPct(linesTotal, linesCovered),
|
|
359
|
-
functions: withPct(funcsTotal, funcsCovered),
|
|
360
|
-
branches: withPct(branchesTotal, branchesCovered)
|
|
361
|
-
};
|
|
362
|
-
totals.lines.total += linesTotal;
|
|
363
|
-
totals.lines.covered += linesCovered;
|
|
364
|
-
totals.functions.total += funcsTotal;
|
|
365
|
-
totals.functions.covered += funcsCovered;
|
|
366
|
-
totals.branches.total += branchesTotal;
|
|
367
|
-
totals.branches.covered += branchesCovered;
|
|
368
|
-
}
|
|
369
|
-
summary.total = {
|
|
370
|
-
lines: withPct(totals.lines.total, totals.lines.covered),
|
|
371
|
-
statements: withPct(totals.lines.total, totals.lines.covered),
|
|
372
|
-
functions: withPct(totals.functions.total, totals.functions.covered),
|
|
373
|
-
branches: withPct(totals.branches.total, totals.branches.covered),
|
|
374
|
-
branchesTrue: {
|
|
375
|
-
total: 0,
|
|
376
|
-
covered: 0,
|
|
377
|
-
skipped: 0,
|
|
378
|
-
pct: 100
|
|
379
|
-
}
|
|
380
|
-
};
|
|
381
|
-
return summary;
|
|
382
|
-
}
|
|
383
|
-
/**
|
|
384
|
-
* Read and parse an LCOV file.
|
|
385
|
-
*/
|
|
386
|
-
function readLcovFile(path) {
|
|
387
|
-
return parseLcov((0, node_fs.readFileSync)(path, "utf8"));
|
|
388
|
-
}
|
|
389
|
-
/**
|
|
390
|
-
* Write LCOV data to a file.
|
|
391
|
-
*/
|
|
392
|
-
function writeLcovFile(path, lcov) {
|
|
393
|
-
(0, node_fs.mkdirSync)((0, node_path.dirname)(path), { recursive: true });
|
|
394
|
-
(0, node_fs.writeFileSync)(path, formatLcov(lcov));
|
|
395
|
-
}
|
|
396
|
-
/**
|
|
397
|
-
* Write JSON summary to a file.
|
|
398
|
-
*/
|
|
399
|
-
function writeJsonSummary(path, summary) {
|
|
400
|
-
(0, node_fs.mkdirSync)((0, node_path.dirname)(path), { recursive: true });
|
|
401
|
-
(0, node_fs.writeFileSync)(path, JSON.stringify(summary, null, 2));
|
|
402
|
-
}
|
|
403
|
-
|
|
404
173
|
//#endregion
|
|
405
174
|
//#region src/lib/coverage.ts
|
|
406
175
|
/**
|
|
@@ -506,33 +275,6 @@ async function cleanupCoverageContext(ctx) {
|
|
|
506
275
|
});
|
|
507
276
|
} catch {}
|
|
508
277
|
}
|
|
509
|
-
/**
|
|
510
|
-
* Merge external LCOV file with generated coverage.
|
|
511
|
-
* Reads the generated lcov.info, merges with external LCOV, and writes back.
|
|
512
|
-
* Also generates coverage-summary.json for badge generation.
|
|
513
|
-
*
|
|
514
|
-
* @returns Object with merged coverage percentages, or null if merge failed
|
|
515
|
-
*/
|
|
516
|
-
function mergeExternalCoverage(reportsDir, externalLcovPath) {
|
|
517
|
-
const generatedLcovPath = (0, node_path.join)(reportsDir, "lcov.info");
|
|
518
|
-
if (!(0, node_fs.existsSync)(externalLcovPath)) {
|
|
519
|
-
console.error(`External LCOV file not found: ${externalLcovPath}`);
|
|
520
|
-
return null;
|
|
521
|
-
}
|
|
522
|
-
if (!(0, node_fs.existsSync)(generatedLcovPath)) {
|
|
523
|
-
console.error(`Generated LCOV file not found: ${generatedLcovPath}`);
|
|
524
|
-
console.error("Make sure \"lcov\" is included in reporters");
|
|
525
|
-
return null;
|
|
526
|
-
}
|
|
527
|
-
const mergedLcov = mergeLcov(readLcovFile(externalLcovPath), readLcovFile(generatedLcovPath));
|
|
528
|
-
writeLcovFile(generatedLcovPath, mergedLcov);
|
|
529
|
-
const summary = lcovToJsonSummary(mergedLcov);
|
|
530
|
-
writeJsonSummary((0, node_path.join)(reportsDir, "coverage-summary.json"), summary);
|
|
531
|
-
return {
|
|
532
|
-
lines: summary.total.lines.pct,
|
|
533
|
-
functions: summary.total.functions.pct
|
|
534
|
-
};
|
|
535
|
-
}
|
|
536
278
|
|
|
537
279
|
//#endregion
|
|
538
280
|
//#region src/cli/commands/run.ts
|
|
@@ -540,7 +282,7 @@ function mergeExternalCoverage(reportsDir, externalLcovPath) {
|
|
|
540
282
|
* Register the run command.
|
|
541
283
|
*/
|
|
542
284
|
function registerRunCommand(program) {
|
|
543
|
-
program.command("run").description("Run golden tests").argument("[files...]", "Test files to run (default: **/*.tryscript.md)").option("--update", "Update golden files with actual output").option("--diff", "Show diff on failure (default: true)").option("--no-diff", "Hide diff on failure").option("--fail-fast", "Stop on first failure").option("--filter <pattern>", "Filter tests by name pattern").option("--verbose", "Show detailed output including passing test output").option("--quiet", "Suppress non-essential output (only show failures)").option("--coverage", "Enable code coverage collection (requires c8)").option("--coverage-dir <dir>", "Coverage output directory (default: coverage-tryscript)").option("--coverage-reporter <reporter...>", "Coverage reporters (default: text, html). Can be specified multiple times.").option("--coverage-exclude <pattern...>", "Patterns to exclude from coverage (c8 --exclude). Can be specified multiple times.").option("--coverage-exclude-node-modules", "Exclude node_modules from coverage (c8 --exclude-node-modules, default: true)").option("--no-coverage-exclude-node-modules", "Include node_modules in coverage (c8 --no-exclude-node-modules)").option("--coverage-exclude-after-remap", "Apply exclude logic after sourcemap remapping (c8 --exclude-after-remap)").option("--coverage-skip-full", "Hide files with 100% coverage (c8 --skip-full)").option("--coverage-allow-external", "Allow files from outside cwd (c8 --allowExternal)").option("--coverage-monocart", "Use monocart for accurate line counts, better for merging with vitest (c8 --experimental-monocart)").
|
|
285
|
+
program.command("run").description("Run golden tests").argument("[files...]", "Test files to run (default: **/*.tryscript.md)").option("--update", "Update golden files with actual output").option("--diff", "Show diff on failure (default: true)").option("--no-diff", "Hide diff on failure").option("--fail-fast", "Stop on first failure").option("--filter <pattern>", "Filter tests by name pattern").option("--verbose", "Show detailed output including passing test output").option("--quiet", "Suppress non-essential output (only show failures)").option("--coverage", "Enable code coverage collection (requires c8)").option("--coverage-dir <dir>", "Coverage output directory (default: coverage-tryscript)").option("--coverage-reporter <reporter...>", "Coverage reporters (default: text, html). Can be specified multiple times.").option("--coverage-exclude <pattern...>", "Patterns to exclude from coverage (c8 --exclude). Can be specified multiple times.").option("--coverage-exclude-node-modules", "Exclude node_modules from coverage (c8 --exclude-node-modules, default: true)").option("--no-coverage-exclude-node-modules", "Include node_modules in coverage (c8 --no-exclude-node-modules)").option("--coverage-exclude-after-remap", "Apply exclude logic after sourcemap remapping (c8 --exclude-after-remap)").option("--coverage-skip-full", "Hide files with 100% coverage (c8 --skip-full)").option("--coverage-allow-external", "Allow files from outside cwd (c8 --allowExternal)").option("--coverage-monocart", "Use monocart for accurate line counts, better for merging with vitest (c8 --experimental-monocart)").action(runCommand$1);
|
|
544
286
|
}
|
|
545
287
|
async function runCommand$1(files, options) {
|
|
546
288
|
const startTime = Date.now();
|
|
@@ -569,26 +311,16 @@ async function runCommand$1(files, options) {
|
|
|
569
311
|
logError("Coverage requires c8. Install with: npm install -D c8");
|
|
570
312
|
process.exit(1);
|
|
571
313
|
}
|
|
572
|
-
let reporters = options.coverageReporter ?? globalConfig.coverage?.reporters;
|
|
573
|
-
if (options.mergeLcov) {
|
|
574
|
-
if (!reporters) reporters = [
|
|
575
|
-
"text",
|
|
576
|
-
"html",
|
|
577
|
-
"lcov"
|
|
578
|
-
];
|
|
579
|
-
else if (!reporters.includes("lcov")) reporters = [...reporters, "lcov"];
|
|
580
|
-
}
|
|
581
314
|
coverageCtx = await createCoverageContext({
|
|
582
315
|
...globalConfig.coverage,
|
|
583
316
|
reportsDir: options.coverageDir ?? globalConfig.coverage?.reportsDir,
|
|
584
|
-
reporters,
|
|
317
|
+
reporters: options.coverageReporter ?? globalConfig.coverage?.reporters,
|
|
585
318
|
exclude: options.coverageExclude ?? globalConfig.coverage?.exclude,
|
|
586
319
|
excludeNodeModules: options.coverageExcludeNodeModules ?? globalConfig.coverage?.excludeNodeModules,
|
|
587
320
|
excludeAfterRemap: options.coverageExcludeAfterRemap ?? globalConfig.coverage?.excludeAfterRemap,
|
|
588
321
|
skipFull: options.coverageSkipFull ?? globalConfig.coverage?.skipFull,
|
|
589
322
|
allowExternal: options.coverageAllowExternal ?? globalConfig.coverage?.allowExternal,
|
|
590
|
-
monocart: options.coverageMonocart ?? globalConfig.coverage?.monocart
|
|
591
|
-
mergeLcov: options.mergeLcov ?? globalConfig.coverage?.mergeLcov
|
|
323
|
+
monocart: options.coverageMonocart ?? globalConfig.coverage?.monocart
|
|
592
324
|
});
|
|
593
325
|
coverageEnv = getCoverageEnv(coverageCtx);
|
|
594
326
|
}
|
|
@@ -662,11 +394,6 @@ async function runCommand$1(files, options) {
|
|
|
662
394
|
console.error("\nGenerating coverage report...");
|
|
663
395
|
try {
|
|
664
396
|
await generateCoverageReport(coverageCtx);
|
|
665
|
-
if (coverageCtx.options.mergeLcov) {
|
|
666
|
-
console.error(`Merging with external coverage: ${coverageCtx.options.mergeLcov}`);
|
|
667
|
-
const merged = mergeExternalCoverage(coverageCtx.options.reportsDir, coverageCtx.options.mergeLcov);
|
|
668
|
-
if (merged) console.error(colors.success(`Merged coverage: ${merged.lines}% lines, ${merged.functions}% functions`));
|
|
669
|
-
}
|
|
670
397
|
console.error(colors.success(`Coverage report written to ${coverageCtx.options.reportsDir}/`));
|
|
671
398
|
} catch (error) {
|
|
672
399
|
logError(`Failed to generate coverage report: ${error instanceof Error ? error.message : String(error)}`);
|
|
@@ -683,7 +410,7 @@ async function runCommand$1(files, options) {
|
|
|
683
410
|
* Register the coverage command.
|
|
684
411
|
*/
|
|
685
412
|
function registerCoverageCommand(program) {
|
|
686
|
-
program.command("coverage").description("Run commands with merged V8 coverage").argument("<commands...>", "Commands to run (each will inherit coverage environment)").option("--reports-dir <dir>", "Coverage output directory (default: coverage)").option("--reporters <reporters>", "Comma-separated coverage reporters (default: text,json,json-summary,lcov,html)").option("--include <patterns>", "Comma-separated patterns to include in coverage").option("--exclude <patterns>", "Comma-separated patterns to exclude from coverage").option("--exclude-node-modules", "Exclude node_modules from coverage (default: true)", true).option("--no-exclude-node-modules", "Include node_modules in coverage").option("--exclude-after-remap", "Apply exclude logic after sourcemap remapping").option("--skip-full", "Hide files with 100% coverage").option("--allow-external", "Allow files from outside cwd").option("--monocart", "Use monocart for accurate line counts (recommended for merging)").option("--src <dir>", "Source directory for sourcemap remapping (default: src)").option("--verbose", "Show coverage summary after each command for debugging").
|
|
413
|
+
program.command("coverage").description("Run commands with merged V8 coverage").argument("<commands...>", "Commands to run (each will inherit coverage environment)").option("--reports-dir <dir>", "Coverage output directory (default: coverage)").option("--reporters <reporters>", "Comma-separated coverage reporters (default: text,json,json-summary,lcov,html)").option("--include <patterns>", "Comma-separated patterns to include in coverage").option("--exclude <patterns>", "Comma-separated patterns to exclude from coverage").option("--exclude-node-modules", "Exclude node_modules from coverage (default: true)", true).option("--no-exclude-node-modules", "Include node_modules in coverage").option("--exclude-after-remap", "Apply exclude logic after sourcemap remapping").option("--skip-full", "Hide files with 100% coverage").option("--allow-external", "Allow files from outside cwd").option("--monocart", "Use monocart for accurate line counts (recommended for merging)").option("--src <dir>", "Source directory for sourcemap remapping (default: src)").option("--verbose", "Show coverage summary after each command for debugging").action(coverageCommand);
|
|
687
414
|
}
|
|
688
415
|
/**
|
|
689
416
|
* Run a command with inherited coverage environment.
|
|
@@ -879,32 +606,12 @@ async function coverageCommand(commands, options) {
|
|
|
879
606
|
if (parsedOptions.verbose && stats.fileCount > 0) await generateTextReport(coverageTemp, parsedOptions, command);
|
|
880
607
|
previousFileCount = stats.fileCount;
|
|
881
608
|
}
|
|
882
|
-
console.error(colors.info("\n=== Generating coverage report ==="));
|
|
609
|
+
console.error(colors.info("\n=== Generating merged coverage report ==="));
|
|
883
610
|
if (!await generateReport(coverageTemp, parsedOptions)) {
|
|
884
611
|
logError("Failed to generate coverage report");
|
|
885
612
|
process.exit(1);
|
|
886
613
|
}
|
|
887
|
-
|
|
888
|
-
if (parsedOptions.mergeLcov) {
|
|
889
|
-
const externalLcovPath = parsedOptions.mergeLcov;
|
|
890
|
-
const generatedLcovPath = (0, node_path.join)(reportsDir, "lcov.info");
|
|
891
|
-
if (!(0, node_fs.existsSync)(externalLcovPath)) {
|
|
892
|
-
logError(`External LCOV file not found: ${externalLcovPath}`);
|
|
893
|
-
process.exit(1);
|
|
894
|
-
}
|
|
895
|
-
if (!(0, node_fs.existsSync)(generatedLcovPath)) {
|
|
896
|
-
logError(`Generated LCOV file not found: ${generatedLcovPath}`);
|
|
897
|
-
logError("Make sure \"lcov\" is included in reporters");
|
|
898
|
-
process.exit(1);
|
|
899
|
-
}
|
|
900
|
-
console.error(colors.info(`\nMerging with external coverage: ${externalLcovPath}`));
|
|
901
|
-
const mergedLcov = mergeLcov(readLcovFile(externalLcovPath), readLcovFile(generatedLcovPath));
|
|
902
|
-
writeLcovFile(generatedLcovPath, mergedLcov);
|
|
903
|
-
const summary = lcovToJsonSummary(mergedLcov);
|
|
904
|
-
writeJsonSummary((0, node_path.join)(reportsDir, "coverage-summary.json"), summary);
|
|
905
|
-
console.error(colors.success(`\nMerged coverage: ${summary.total.lines.pct}% lines, ${summary.total.functions.pct}% functions`));
|
|
906
|
-
}
|
|
907
|
-
console.error(colors.success(`\nCoverage report written to ${reportsDir}/`));
|
|
614
|
+
console.error(colors.success(`\nCoverage report written to ${parsedOptions.reportsDir ?? "coverage"}/`));
|
|
908
615
|
} finally {
|
|
909
616
|
await (0, node_fs_promises.rm)(coverageTemp, {
|
|
910
617
|
recursive: true,
|