supercov 0.0.33 → 0.0.35

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.
@@ -201,11 +201,6 @@ probe would have proven are declared for that file. Setting
201
201
  chosen files on that same path deliberately, which is the escape hatch if
202
202
  instrumentation ever disagrees with one of yours.
203
203
 
204
- An obligation Supercov declares unmeasured leaves the obligation totals and is
205
- reported as a measurement limit rather than a gap. Its line still counts in
206
- the line total, as it does for every other language, so a file with declared
207
- obligations reads slightly pessimistically on lines.
208
-
209
204
  Ruby 3.3 does not apply its `Coverage` module to code compiled by a load hook,
210
205
  so on 3.3 Supercov measures through `Coverage` alone: lines, methods and the
211
206
  branches Ruby reports itself. Everything that needs a probe (multi-condition
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "supercov",
3
- "version": "0.0.33",
3
+ "version": "0.0.35",
4
4
  "description": "Zero-edit, runner-aware coverage completeness for JavaScript, TypeScript, Rust, and Python test suites",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -28,9 +28,9 @@
28
28
  "access": "public"
29
29
  },
30
30
  "exports": {
31
- "./playwright": "./runtime/javascript/playwright.js",
31
+ "./playwright": "./runtime/javascript/playwright.mjs",
32
32
  "./register": "./runtime/javascript/register.mjs",
33
- "./vitest": "./runtime/javascript/vitest.js"
33
+ "./vitest": "./runtime/javascript/vitest.mjs"
34
34
  },
35
35
  "scripts": {
36
36
  "build": "cargo build -p supercov",
@@ -64,19 +64,21 @@
64
64
  "benchmark:check": "cargo build --release -p supercov && node scripts/rust-transform-benchmark.mjs",
65
65
  "benchmark:python-monitoring": "cargo build -p supercov && node scripts/python-monitoring-benchmark.mjs",
66
66
  "check": "cargo fmt --all -- --check && cargo clippy --workspace --all-targets -- -D warnings && npm run test && npm run test:runtime && npm run test:rust-assets && node scripts/package-preflight.mjs",
67
- "release:check": "npm run check && npm run test:engine && npm run test:fixture && npm run test:watchdog && npm run test:engine-contract && npm run test:agent && npm run test:python-monitoring && npm run test:ruby-coverage && npm run test:packed-npx && npm run test:clang-mcdc && npm run benchmark:check",
67
+ "release:check": "npm run check && npm run test:engine && npm run test:fixture && npm run test:watchdog && npm run test:engine-contract && npm run test:agent && npm run test:child-attribution && npm run test:host-loader && npm run test:python-monitoring && npm run test:ruby-coverage && npm run test:packed-npx && npm run test:clang-mcdc && npm run benchmark:check",
68
68
  "prepack": "node scripts/package-preflight.mjs",
69
69
  "prepublishOnly": "npm run release:check",
70
+ "test:child-attribution": "cargo build -p supercov && node scripts/rust-child-attribution-integration.mjs",
71
+ "test:host-loader": "cargo build -p supercov && node scripts/rust-host-loader-integration.mjs",
70
72
  "test:python-monitoring": "cargo build -p supercov && node scripts/python-monitoring-integration.mjs",
71
73
  "test:ruby-coverage": "cargo build -p supercov && node scripts/ruby-coverage-integration.mjs"
72
74
  },
73
75
  "optionalDependencies": {
74
- "@supercov/cli-darwin-arm64": "0.0.33",
75
- "@supercov/cli-darwin-x64": "0.0.33",
76
- "@supercov/cli-linux-arm64-gnu": "0.0.33",
77
- "@supercov/cli-linux-arm64-musl": "0.0.33",
78
- "@supercov/cli-linux-x64-gnu": "0.0.33",
79
- "@supercov/cli-linux-x64-musl": "0.0.33"
76
+ "@supercov/cli-darwin-arm64": "0.0.35",
77
+ "@supercov/cli-darwin-x64": "0.0.35",
78
+ "@supercov/cli-linux-arm64-gnu": "0.0.35",
79
+ "@supercov/cli-linux-arm64-musl": "0.0.35",
80
+ "@supercov/cli-linux-x64-gnu": "0.0.35",
81
+ "@supercov/cli-linux-x64-musl": "0.0.35"
80
82
  },
81
83
  "peerDependencies": {
82
84
  "@playwright/test": ">=1.55.0",
@@ -1,5 +1,5 @@
1
1
  import nativeAssert from "node:assert";
2
- import { createNodeAssertAdapter, setStrictAssertAdapter } from "./nodeAssertAdapter.js";
2
+ import { createNodeAssertAdapter, setStrictAssertAdapter } from "./nodeAssertAdapter.mjs";
3
3
  const adapter = createNodeAssertAdapter(nativeAssert, "node:assert");
4
4
  const strictAdapter = createNodeAssertAdapter(nativeAssert.strict, "node:assert/strict");
5
5
  setStrictAssertAdapter(adapter, strictAdapter);
@@ -1,4 +1,4 @@
1
- import { withNodeAssertionPhase } from "./runtime.js";
1
+ import { withNodeAssertionPhase } from "./runtime.mjs";
2
2
  const ASSERTION_METHODS = new Set([
3
3
  "deepEqual",
4
4
  "deepStrictEqual",
@@ -1,5 +1,5 @@
1
1
  import nativeAssert from "node:assert/strict";
2
- import { createNodeAssertAdapter, setStrictAssertAdapter } from "./nodeAssertAdapter.js";
2
+ import { createNodeAssertAdapter, setStrictAssertAdapter } from "./nodeAssertAdapter.mjs";
3
3
  const adapter = createNodeAssertAdapter(nativeAssert, "node:assert/strict");
4
4
  setStrictAssertAdapter(adapter, adapter);
5
5
  export default adapter;
@@ -1,8 +1,8 @@
1
1
  import * as native from "node:test";
2
2
  import { fileURLToPath } from "node:url";
3
3
  import vm from "node:vm";
4
- import { beginBufferedServerEvidence, flushBufferedServerEvidence, takeNodeAssertionPhases, withCoverageCarrier, } from "./runtime.js";
5
- import { callerLocation, runnerExecutionScope, writeRunnerEvidence, } from "./runnerEvidence.js";
4
+ import { beginBufferedServerEvidence, flushBufferedServerEvidence, takeNodeAssertionPhases, withCoverageCarrier, } from "./runtime.mjs";
5
+ import { callerLocation, runnerExecutionScope, writeRunnerEvidence, } from "./runnerEvidence.mjs";
6
6
  function callbackIndex(args) {
7
7
  for (let index = args.length - 1; index >= 0; index -= 1)
8
8
  if (typeof args[index] === "function")
@@ -18,7 +18,7 @@ function testOptions(args, index) {
18
18
  }
19
19
  // node:test derives a test's reported location from the direct caller of the
20
20
  // registration call, and the adapter is that caller: every failing test
21
- // reported "test at .../nodeTest.js". A compiled trampoline carrying the
21
+ // reported "test at .../nodeTest.mjs". A compiled trampoline carrying the
22
22
  // user's call site as its script origin registers the test instead, so the
23
23
  // runner sees the location a direct call would have produced. The padded
24
24
  // second line puts the call expression at the user's exact line and column.
@@ -14,10 +14,10 @@ import https from "node:https";
14
14
  import { syncBuiltinESMExports } from "node:module";
15
15
  import { relative, resolve, sep } from "node:path";
16
16
  import * as standardPlaywright from "@playwright/test";
17
- import * as coverageRuntime from "./runtime.js";
18
- import { inferTestProvenance } from "./provenance.js";
19
- import { appendJsonLineDurableSync, appendJsonLineSync } from "./atomic.js";
20
- import { COVERAGE_PHASE_HEADER, COVERAGE_PHASE_COOKIE, COVERAGE_SCOPE_COOKIE, COVERAGE_SCOPE_HEADER, COVERAGE_CARRIER_ENV, encodeCoverageCarrier, encodeCoverageScope, serverEvidenceDirectory, serverEvidencePath, } from "./transport.js";
17
+ import * as coverageRuntime from "./runtime.mjs";
18
+ import { inferTestProvenance } from "./provenance.mjs";
19
+ import { appendJsonLineDurableSync, appendJsonLineSync } from "./atomic.mjs";
20
+ import { COVERAGE_PHASE_HEADER, COVERAGE_PHASE_COOKIE, COVERAGE_SCOPE_COOKIE, COVERAGE_SCOPE_HEADER, COVERAGE_CARRIER_ENV, encodeCoverageCarrier, encodeCoverageScope, serverEvidenceDirectory, serverEvidencePath, } from "./transport.mjs";
21
21
  export * from "@playwright/test";
22
22
  const generatedTargetModule = "__SUPERCOV_PLAYWRIGHT_MODULE__";
23
23
  const targetModule = process.env["SUPERCOV_PLAYWRIGHT_MODULE"] ??
@@ -1,6 +1,6 @@
1
1
  import { relative, resolve, sep } from "node:path";
2
- import { inferTestProvenance } from "./provenance.js";
3
- import { appendJsonLineDurableSync, appendJsonLineSync } from "./atomic.js";
2
+ import { inferTestProvenance } from "./provenance.mjs";
3
+ import { appendJsonLineDurableSync, appendJsonLineSync } from "./atomic.mjs";
4
4
  const GENERATED_EVIDENCE_DIRECTORY = "__SUPERCOV_EVIDENCE_DIRECTORY__";
5
5
  const evidenceWriterIdentity = () => (process.env.SUPERCOV_EXECUTION_LOG_SHARD ?? `pid-${process.pid}`)
6
6
  .replace(/[^A-Za-z0-9_-]/g, "_");
@@ -9,8 +9,8 @@ var __rewriteRelativeImportExtension = (this && this.__rewriteRelativeImportExte
9
9
  import Module, { register, syncBuiltinESMExports } from "node:module";
10
10
  import { closeSync, openSync, unlinkSync } from "node:fs";
11
11
  import { resolve } from "node:path";
12
- import { installLaunchSupervisor, wrapImportedCapability } from "./launchSupervisor.js";
13
- import { __supercovBindCapabilityWrapper } from "./capability.js";
12
+ import { installLaunchSupervisor, wrapImportedCapability } from "./launchSupervisor.mjs";
13
+ import { __supercovBindCapabilityWrapper } from "./capability.mjs";
14
14
  installLaunchSupervisor();
15
15
  // Instrumented sources import the browser-safe capability seam; bind the
16
16
  // real supervisor implementation before any user module evaluates.
@@ -77,7 +77,7 @@ if (process.env.SUPERCOV_DURABLE_EVIDENCE_EACH_TEST === "1") {
77
77
  // test through an opaque runner that bypasses the ordinary Playwright or
78
78
  // node:test import boundary. The remote-launch adapter marks that process;
79
79
  // initialize the runtime before its transformed module can evaluate.
80
- globalThis.__SUPERCOV_DIRECT_RUNTIME__ ??= await import("./runtime.js");
80
+ globalThis.__SUPERCOV_DIRECT_RUNTIME__ ??= await import("./runtime.mjs");
81
81
  process.__SUPERCOV_DIRECT_RUNTIME__ ??= globalThis.__SUPERCOV_DIRECT_RUNTIME__;
82
82
  }
83
83
  // Workers are independent Node processes and an explicit `execArgv: []`
@@ -119,9 +119,9 @@ const generatedJestConfig = process.env.SUPERCOV_GENERATED_JEST_CONFIG;
119
119
  const entrypoint = process.argv[1]?.replaceAll("\\", "/") ?? "";
120
120
  const playwrightTarget = process.env.SUPERCOV_PLAYWRIGHT_MODULE;
121
121
  const projectRoot = process.env.SUPERCOV_PROJECT_ROOT?.replaceAll("\\", "/").replace(/\/$/, "");
122
- const nodeTestWrapper = new URL("./nodeTest.js", import.meta.url).href;
123
- const nodeAssertWrapper = new URL("./nodeAssert.js", import.meta.url).href;
124
- const nodeAssertStrictWrapper = new URL("./nodeAssertStrict.js", import.meta.url).href;
122
+ const nodeTestWrapper = new URL("./nodeTest.mjs", import.meta.url).href;
123
+ const nodeAssertWrapper = new URL("./nodeAssert.mjs", import.meta.url).href;
124
+ const nodeAssertStrictWrapper = new URL("./nodeAssertStrict.mjs", import.meta.url).href;
125
125
  const isPlaywrightEntrypoint = /\/(?:node_modules\/\.bin\/playwright|node_modules\/(?:@playwright\/test|playwright)\/(?:cli\.js|.*\/program\.js))$/.test(entrypoint);
126
126
  const isJestEntrypoint = /\/node_modules\/(?:\.bin\/jest|(?:jest|jest-cli)\/bin\/jest\.js)$/.test(entrypoint);
127
127
  if (generatedPlaywrightConfig && isPlaywrightEntrypoint)
@@ -209,7 +209,7 @@ if (process.env.SUPERCOV_CJS_INTERCEPT === "1" &&
209
209
  const projectRoot = process.env.SUPERCOV_PROJECT_ROOT;
210
210
  const originalPlaywrightConfig = process.env.SUPERCOV_ORIGINAL_PLAYWRIGHT_CONFIG
211
211
  ?.replaceAll("\\", "/");
212
- const wrapper = await import(__rewriteRelativeImportExtension(new URL("./playwright.js", import.meta.url)));
212
+ const wrapper = await import(__rewriteRelativeImportExtension(new URL("./playwright.mjs", import.meta.url)));
213
213
  const originalLoad = Module._load;
214
214
  Module._load = function supercovLoad(request, parent, isMain) {
215
215
  const parentFile = parent?.filename?.replaceAll("\\", "/");
@@ -4,7 +4,7 @@ const GENERATED_TARGET = "__SUPERCOV_PLAYWRIGHT_MODULE__";
4
4
  const TARGET = process.env.SUPERCOV_PLAYWRIGHT_MODULE ??
5
5
  (GENERATED_TARGET.startsWith("__") ? "@playwright/test" : GENERATED_TARGET);
6
6
  const REPLACEMENT = process.env.SUPERCOV_PLAYWRIGHT_WRAPPER ??
7
- "./.supercov/node_modules/playwright.js";
7
+ "./.supercov/node_modules/playwright.mjs";
8
8
  const PROJECT_ROOT = process.env.SUPERCOV_PROJECT_ROOT;
9
9
  const ORIGINAL_CONFIG = process.env.SUPERCOV_ORIGINAL_PLAYWRIGHT_CONFIG;
10
10
  function belongsToProject(parentURL) {
@@ -29,10 +29,10 @@ export async function resolve(specifier, context, nextResolve) {
29
29
  // source-local copy keeps strict rootDir compilers happy; this fallback
30
30
  // resolves the emitted import to Supercov's generated runtime without
31
31
  // requiring the project's build to copy our helper directory.
32
- if (specifier.endsWith("/.supercov/node_modules/runtime.js") &&
32
+ if (specifier.endsWith("/.supercov/node_modules/runtime.mjs") &&
33
33
  belongsToProject(context.parentURL)) {
34
34
  return {
35
- url: new URL("./runtime.js", import.meta.url).href,
35
+ url: new URL("./runtime.mjs", import.meta.url).href,
36
36
  shortCircuit: true,
37
37
  };
38
38
  }
@@ -40,7 +40,7 @@ export async function resolve(specifier, context, nextResolve) {
40
40
  (specifier === "node:test" || specifier === "test") &&
41
41
  belongsToProject(context.parentURL)) {
42
42
  return {
43
- url: new URL("./nodeTest.js", import.meta.url).href,
43
+ url: new URL("./nodeTest.mjs", import.meta.url).href,
44
44
  shortCircuit: true,
45
45
  };
46
46
  }
@@ -48,7 +48,7 @@ export async function resolve(specifier, context, nextResolve) {
48
48
  ["assert", "node:assert", "assert/strict", "node:assert/strict"].includes(specifier) &&
49
49
  belongsToProject(context.parentURL)) {
50
50
  return {
51
- url: new URL(specifier.endsWith("/strict") ? "./nodeAssertStrict.js" : "./nodeAssert.js", import.meta.url).href,
51
+ url: new URL(specifier.endsWith("/strict") ? "./nodeAssertStrict.mjs" : "./nodeAssert.mjs", import.meta.url).href,
52
52
  shortCircuit: true,
53
53
  };
54
54
  }
@@ -2,9 +2,9 @@ import { createHash, randomBytes } from "node:crypto";
2
2
  import { mkdirSync, readFileSync } from "node:fs";
3
3
  import { relative, resolve, sep } from "node:path";
4
4
  import { fileURLToPath } from "node:url";
5
- import { atomicWriteFileSync } from "./atomic.js";
6
- import { inferTestProvenance } from "./provenance.js";
7
- import { serverEvidencePath } from "./transport.js";
5
+ import { atomicWriteFileSync } from "./atomic.mjs";
6
+ import { inferTestProvenance } from "./provenance.mjs";
7
+ import { serverEvidencePath } from "./transport.mjs";
8
8
 
9
9
  let cachedProcessInstanceToken;
10
10
  function processInstanceToken() {
@@ -480,12 +480,59 @@ function appendDurableBackgroundRecord(fs, runId, record) {
480
480
  return path;
481
481
  }
482
482
  var _a7;
483
+ // Evidence buffered for the current turn is lost when a signal ends the
484
+ // process, because "exit" does not run for one -- and killing a child in
485
+ // teardown is exactly how a suite stops a gateway it started. Flush on the
486
+ // terminating signals as well as on exit.
487
+ //
488
+ // Exactly one listener per signal serves every flusher: two of our own would
489
+ // each see a sibling listener, neither would judge itself alone, and a
490
+ // signalled process would stay alive. Having flushed, restore what the signal
491
+ // would have done -- if nothing else is listening the program expected to die,
492
+ // so re-raise with our listener gone; if the program installed its own handler
493
+ // it deliberately suppressed that default and we must not exit on its behalf.
494
+ function flushOnTermination(flush) {
495
+ var _a9;
496
+ if (typeof process === "undefined")
497
+ return;
498
+ const flushers = (_a9 = runtimeGlobal.__SUPERCOV_TERMINATION_FLUSHERS__) != null ? _a9 : /* @__PURE__ */ new Set();
499
+ runtimeGlobal.__SUPERCOV_TERMINATION_FLUSHERS__ = flushers;
500
+ flushers.add(flush);
501
+ if (runtimeGlobal.__SUPERCOV_TERMINATION_INSTALLED__)
502
+ return;
503
+ runtimeGlobal.__SUPERCOV_TERMINATION_INSTALLED__ = true;
504
+ const drain = () => {
505
+ var _a10;
506
+ for (const value of (_a10 = runtimeGlobal.__SUPERCOV_TERMINATION_FLUSHERS__) != null ? _a10 : []) {
507
+ try {
508
+ value();
509
+ } catch (e) {
510
+ }
511
+ }
512
+ };
513
+ try {
514
+ process.on("exit", drain);
515
+ } catch (e) {
516
+ }
517
+ for (const signal of ["SIGTERM", "SIGINT", "SIGHUP", "SIGBREAK"]) {
518
+ try {
519
+ process.on(signal, () => {
520
+ drain();
521
+ if (process.listenerCount(signal) <= 1) {
522
+ process.removeAllListeners(signal);
523
+ process.kill(process.pid, signal);
524
+ }
525
+ });
526
+ } catch (e) {
527
+ }
528
+ }
529
+ }
483
530
  if (!isBrowser) {
484
531
  const flushers = (_a7 = runtimeGlobal.__SUPERCOV_BUFFER_FLUSHERS__) != null ? _a7 : /* @__PURE__ */ new Set();
485
532
  runtimeGlobal.__SUPERCOV_BUFFER_FLUSHERS__ = flushers;
486
533
  flushers.add(flushAllBufferedServerEvidence);
487
534
  if (!runtimeGlobal.__SUPERCOV_BUFFER_EXIT_INSTALLED__) {
488
- process.once("exit", () => {
535
+ flushOnTermination(() => {
489
536
  var _a8;
490
537
  for (const flush of (_a8 = runtimeGlobal.__SUPERCOV_BUFFER_FLUSHERS__) != null ? _a8 : [])
491
538
  flush();
@@ -538,7 +585,7 @@ function enqueueServerAppend(directory, path, line, runId) {
538
585
  if (!state.serverExitHookInstalled && typeof process !== "undefined") {
539
586
  state.serverExitHookInstalled = true;
540
587
  try {
541
- process.on("exit", flushServerAppends);
588
+ flushOnTermination(flushServerAppends);
542
589
  } catch (e) {
543
590
  }
544
591
  }
@@ -1238,6 +1285,7 @@ export {
1238
1285
  enableRuntimeSnapshotEvidence,
1239
1286
  flushBufferedBackgroundEvidence,
1240
1287
  flushBufferedServerEvidence,
1288
+ flushOnTermination,
1241
1289
  loopBegin,
1242
1290
  loopEnd,
1243
1291
  loopEntered,
@@ -2,9 +2,9 @@ import { createHash } from "node:crypto";
2
2
  import { mkdirSync } from "node:fs";
3
3
  import { relative, resolve, sep } from "node:path";
4
4
  import { afterEach, beforeEach } from "vitest";
5
- import { coverageSnapshot as localCoverageSnapshot, activateCoverageScope as localActivateCoverageScope, enableRuntimeSnapshotEvidence as localEnableRuntimeSnapshotEvidence, resetCoverage as localResetCoverage, takeNodeAssertionPhases as localTakeNodeAssertionPhases, } from "./runtime.js";
6
- import { inferTestProvenance } from "./provenance.js";
7
- import { atomicWriteFileSync } from "./atomic.js";
5
+ import { coverageSnapshot as localCoverageSnapshot, activateCoverageScope as localActivateCoverageScope, enableRuntimeSnapshotEvidence as localEnableRuntimeSnapshotEvidence, resetCoverage as localResetCoverage, takeNodeAssertionPhases as localTakeNodeAssertionPhases, } from "./runtime.mjs";
6
+ import { inferTestProvenance } from "./provenance.mjs";
7
+ import { atomicWriteFileSync } from "./atomic.mjs";
8
8
  const evidenceDirectory = process.env["SUPERCOV_EVIDENCE_DIR"];
9
9
  const emittedSetupFiles = new Set();
10
10
  const attempts = new Map();
@@ -1,8 +1,8 @@
1
1
  import { mkdirSync } from "node:fs";
2
2
  import { relative, resolve, sep } from "node:path";
3
3
  import { fileURLToPath } from "node:url";
4
- import { inferTestProvenance } from "./provenance.js";
5
- import { atomicWriteFileSync } from "./atomic.js";
4
+ import { inferTestProvenance } from "./provenance.mjs";
5
+ import { atomicWriteFileSync } from "./atomic.mjs";
6
6
  function sourcePath(moduleId) {
7
7
  const absolute = moduleId.startsWith("file:")
8
8
  ? fileURLToPath(moduleId)
File without changes