supercov 0.0.42 → 0.0.44

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.
Files changed (47) hide show
  1. package/README.md +23 -3
  2. package/analyzers/typescript/README.md +59 -0
  3. package/analyzers/typescript/bin/compiler-identity.mjs +78 -0
  4. package/analyzers/typescript/bin/identity.mjs +71 -0
  5. package/analyzers/typescript/bin/query.mjs +29 -0
  6. package/analyzers/typescript/dist/analyze.js +5273 -0
  7. package/analyzers/typescript/dist/archive.js +337 -0
  8. package/analyzers/typescript/dist/awaited-observations.js +376 -0
  9. package/analyzers/typescript/dist/build-identity.json +1 -0
  10. package/analyzers/typescript/dist/compiler.js +32 -0
  11. package/analyzers/typescript/dist/frontend.js +75 -0
  12. package/analyzers/typescript/dist/mock-counts.js +2517 -0
  13. package/analyzers/typescript/dist/native-frontend.js +271 -0
  14. package/analyzers/typescript/dist/pragmas.js +186 -0
  15. package/analyzers/typescript/dist/types.js +1 -0
  16. package/analyzers/typescript/package.json +27 -0
  17. package/analyzers/typescript/src/analyze.ts +6180 -0
  18. package/analyzers/typescript/src/archive.ts +471 -0
  19. package/analyzers/typescript/src/awaited-observations.ts +561 -0
  20. package/analyzers/typescript/src/compiler.ts +49 -0
  21. package/analyzers/typescript/src/frontend.ts +136 -0
  22. package/analyzers/typescript/src/mock-counts.ts +3219 -0
  23. package/analyzers/typescript/src/native-frontend.ts +315 -0
  24. package/analyzers/typescript/src/pragmas.ts +284 -0
  25. package/analyzers/typescript/src/types.ts +45 -0
  26. package/analyzers/typescript/tsconfig.json +12 -0
  27. package/docs/agent-loop.md +129 -31
  28. package/docs/assertion-evidence.md +694 -0
  29. package/docs/cli.md +25 -15
  30. package/docs/code-verification.md +4 -0
  31. package/docs/coverage-model.md +6 -6
  32. package/docs/evidence.md +6 -6
  33. package/docs/getting-started.md +60 -72
  34. package/docs/performance.md +4 -4
  35. package/docs/supported-suites.md +40 -9
  36. package/docs/troubleshooting.md +8 -8
  37. package/docs/verification.md +14 -2
  38. package/docs/workspace-isolation.md +1 -1
  39. package/package.json +35 -15
  40. package/runtime/javascript/jest.cjs +134 -0
  41. package/runtime/javascript/jest.config.mjs +39 -0
  42. package/runtime/javascript/jestReporter.mjs +77 -0
  43. package/runtime/javascript/nodeAssertAdapter.mjs +32 -8
  44. package/runtime/javascript/nodeTest.mjs +13 -5
  45. package/runtime/javascript/register.mjs +22 -4
  46. package/runtime/javascript/runnerEvidence.mjs +33 -11
  47. package/runtime/javascript/runtime.mjs +73 -16
@@ -144,6 +144,12 @@ function createState() {
144
144
  decisions: /* @__PURE__ */ new Map(),
145
145
  hits: /* @__PURE__ */ new Set(),
146
146
  events: [],
147
+ // Position of the test-file statement currently executing ("file:line:column"), set by the
148
+ // instrumented test module; production hits recorded meanwhile are attributed to it.
149
+ testStatement: void 0,
150
+ // Per value-position logical expression (`a && b`, `a || b`, `a ?? b`): the distinct
151
+ // (right operand evaluated?, result truthy?) pairs seen, keyed by branch id.
152
+ logicals: /* @__PURE__ */ new Map(),
147
153
  eventKeys: /* @__PURE__ */ new Set(),
148
154
  bufferedAttempts: /* @__PURE__ */ new Set(),
149
155
  serverBuffers: /* @__PURE__ */ new Map(),
@@ -293,17 +299,26 @@ function decisionSnapshot() {
293
299
  vectors: [...decision.vectors.values()]
294
300
  }));
295
301
  }
302
+ function logicalSnapshot() {
303
+ return [...state.logicals.entries()].map(([id, vectors]) => ({
304
+ id,
305
+ vectors: [...vectors.values()]
306
+ }));
307
+ }
296
308
  function coverageSnapshot() {
297
309
  return {
298
310
  decisions: decisionSnapshot(),
299
311
  hits: [...state.hits],
300
- events: state.events
312
+ events: state.events,
313
+ logicals: logicalSnapshot()
301
314
  };
302
315
  }
303
316
  function resetCoverage(testId2) {
304
317
  state.decisions.clear();
305
318
  state.hits.clear();
306
319
  state.events.length = 0;
320
+ state.testStatement = void 0;
321
+ state.logicals.clear();
307
322
  state.eventKeys.clear();
308
323
  state.probeV2ContextEpochs.clear();
309
324
  activateProbeV2Key(`reset\0${state.probeV2NextEpoch}`, true);
@@ -604,21 +619,22 @@ function appendServer(record) {
604
619
  var _a8, _b, _c, _d;
605
620
  if (state.runtimeSnapshots) {
606
621
  const timestampMs = (_a8 = record.timestampMs) != null ? _a8 : Date.now();
622
+ const statement = record.statementId ? { statementId: record.statementId } : {};
607
623
  if (record.type === "decision") {
608
- recordBrowserEvent(__spreadProps(__spreadValues({
624
+ recordBrowserEvent(__spreadProps(__spreadValues(__spreadValues({
609
625
  type: "decision",
610
626
  id: record.meta.id,
611
627
  vector: record.vector,
612
628
  timestampMs
613
- }, record.phaseId ? { phaseId: record.phaseId } : {}), {
629
+ }, record.phaseId ? { phaseId: record.phaseId } : {}), statement), {
614
630
  environment: "server"
615
631
  }));
616
632
  } else {
617
- recordBrowserEvent(__spreadProps(__spreadValues({
633
+ recordBrowserEvent(__spreadProps(__spreadValues(__spreadValues({
618
634
  type: "hit",
619
635
  id: record.id,
620
636
  timestampMs
621
- }, record.phaseId ? { phaseId: record.phaseId } : {}), {
637
+ }, record.phaseId ? { phaseId: record.phaseId } : {}), statement), {
622
638
  environment: "server"
623
639
  }));
624
640
  }
@@ -705,9 +721,11 @@ function withCoverageCarrier(carrier, callback) {
705
721
  function assertionPhaseState(scope) {
706
722
  const key = attemptKey(scope);
707
723
  const existing = state.assertionPhases.get(key);
708
- if (existing)
724
+ if (existing) {
725
+ existing.phaseIds ??= new Set(existing.phases.filter(phase => phase.kind === "assertion").map(phase => phase.id));
709
726
  return existing;
710
- const created = { counter: 0, phases: [] };
727
+ }
728
+ const created = { counter: 0, phases: [], phaseIds: new Set() };
711
729
  state.assertionPhases.set(key, created);
712
730
  return created;
713
731
  }
@@ -737,9 +755,13 @@ function withNodeAssertionPhase(operation, source, callback) {
737
755
  const scope = context.scope;
738
756
  if (!scope)
739
757
  return callback();
740
- const existing = context.phaseId ? assertionPhaseState(scope).phases.find((phase2) => phase2.id === context.phaseId && phase2.kind === "assertion") : void 0;
758
+ const existing = context.phaseId && assertionPhaseState(scope).phaseIds.has(context.phaseId);
741
759
  if (existing)
742
760
  return callback();
761
+ // The adapter's stack is only a fallback. Avoid formatting it when a lexical
762
+ // probe already supplied the active phase's exact original-source identity.
763
+ if (typeof source === "function")
764
+ source = source();
743
765
  const bridged = (_a8 = runtimeGlobal.__SUPERCOV_ASSERTION_PHASE_BRIDGE__) == null ? void 0 : _a8.call(runtimeGlobal, operation, source, callback);
744
766
  if (bridged == null ? void 0 : bridged.handled)
745
767
  return bridged.value;
@@ -752,6 +774,7 @@ function withNodeAssertionPhase(operation, source, callback) {
752
774
  startedAtMs: Date.now()
753
775
  });
754
776
  attempt.phases.push(phase);
777
+ attempt.phaseIds.add(phase.id);
755
778
  try {
756
779
  const result = withCoverageCarrier({ version: 1, scope, phaseId: phase.id }, callback);
757
780
  if (result && typeof result.then === "function")
@@ -769,6 +792,16 @@ function withNodeAssertionPhase(operation, source, callback) {
769
792
  throw cleanInstrumentationStack(error);
770
793
  }
771
794
  }
795
+ // Resolve the target exactly once, before argument evaluation, just like a
796
+ // native call reference. The closure carries only source identity and receiver;
797
+ // it never captures an assertion phase or mutable current-statement state across
798
+ // await. Rejected arguments therefore create no phase, and awaited producer work
799
+ // is not retroactively attributed to the assertion invocation.
800
+ function bindNodeAssertion(operation, source, receiver, method) {
801
+ const target = method === void 0 ? receiver : receiver[method];
802
+ const thisArgument = method === void 0 ? void 0 : receiver;
803
+ return (...args) => withNodeAssertionPhase(operation, source, () => Reflect.apply(target, thisArgument, args));
804
+ }
772
805
  function takeNodeAssertionPhases(scope) {
773
806
  var _a8, _b;
774
807
  const key = attemptKey(scope);
@@ -962,25 +995,31 @@ function recordBrowserEvent(event) {
962
995
  state.events.push(event);
963
996
  return true;
964
997
  }
998
+ function testStatement(source) {
999
+ state.testStatement = typeof source === "string" && source.length > 0 ? source : void 0;
1000
+ }
1001
+ function statementFields() {
1002
+ return state.testStatement ? { statementId: state.testStatement } : {};
1003
+ }
965
1004
  function coverageHit(id) {
966
1005
  state.hits.add(id);
967
1006
  const timestampMs = Date.now();
968
1007
  const phaseId = currentPhaseId();
969
1008
  if (isBrowser) {
970
- if (recordBrowserEvent(__spreadProps(__spreadValues({
1009
+ if (recordBrowserEvent(__spreadProps(__spreadValues(__spreadValues({
971
1010
  type: "hit",
972
1011
  id,
973
1012
  timestampMs
974
- }, phaseId ? { phaseId } : {}), {
1013
+ }, phaseId ? { phaseId } : {}), statementFields()), {
975
1014
  environment: "browser"
976
1015
  })))
977
1016
  persistBrowser();
978
1017
  } else {
979
- appendServer(__spreadValues({
1018
+ appendServer(__spreadValues(__spreadValues({
980
1019
  type: "hit",
981
1020
  id,
982
1021
  timestampMs
983
- }, phaseId ? { phaseId } : {}));
1022
+ }, phaseId ? { phaseId } : {}), statementFields()));
984
1023
  }
985
1024
  }
986
1025
  function registerProbeV2(definition) {
@@ -1113,6 +1152,20 @@ function selectionRight(frame, value, inferredName) {
1113
1152
  }
1114
1153
  function selectionEnd(frame, value) {
1115
1154
  coverageHit(frame.rightEvaluated ? frame.rightId : frame.shortId);
1155
+ // Per-operand outcomes for the verifier: which side was selected and whether the result is
1156
+ // truthy. With the operator (known from the manifest) this gives each operand's outcome.
1157
+ const separator = frame.shortId.lastIndexOf(":");
1158
+ if (separator > 0) {
1159
+ const branchId = frame.shortId.slice(0, separator);
1160
+ const right = frame.rightEvaluated;
1161
+ const truthy = Boolean(value);
1162
+ let vectors = state.logicals.get(branchId);
1163
+ if (!vectors) {
1164
+ vectors = /* @__PURE__ */ new Map();
1165
+ state.logicals.set(branchId, vectors);
1166
+ }
1167
+ vectors.set(`${right ? "R" : "S"}${truthy ? "T" : "F"}`, { right, truthy });
1168
+ }
1116
1169
  return value;
1117
1170
  }
1118
1171
  function optionalSelect(shortId, continuedId, value) {
@@ -1201,22 +1254,22 @@ function mcdcEnd(frame, value) {
1201
1254
  const timestampMs = Date.now();
1202
1255
  const phaseId = currentPhaseId();
1203
1256
  if (isBrowser) {
1204
- if (recordBrowserEvent(__spreadProps(__spreadValues({
1257
+ if (recordBrowserEvent(__spreadProps(__spreadValues(__spreadValues({
1205
1258
  type: "decision",
1206
1259
  id: decision.meta.id,
1207
1260
  vector,
1208
1261
  timestampMs
1209
- }, phaseId ? { phaseId } : {}), {
1262
+ }, phaseId ? { phaseId } : {}), statementFields()), {
1210
1263
  environment: "browser"
1211
1264
  })))
1212
1265
  persistBrowser();
1213
1266
  } else {
1214
- appendServer(__spreadValues({
1267
+ appendServer(__spreadValues(__spreadValues({
1215
1268
  type: "decision",
1216
1269
  meta: decision.meta,
1217
1270
  vector,
1218
1271
  timestampMs
1219
- }, phaseId ? { phaseId } : {}));
1272
+ }, phaseId ? { phaseId } : {}), statementFields()));
1220
1273
  }
1221
1274
  return value;
1222
1275
  }
@@ -1257,6 +1310,8 @@ const directRuntimeApi = {
1257
1310
  selectionEnd,
1258
1311
  selectionRight,
1259
1312
  takeNodeAssertionPhases,
1313
+ bindNodeAssertion,
1314
+ testStatement,
1260
1315
  tryBegin,
1261
1316
  tryCatch,
1262
1317
  tryEnd,
@@ -1306,6 +1361,8 @@ export {
1306
1361
  selectionEnd,
1307
1362
  selectionRight,
1308
1363
  takeNodeAssertionPhases,
1364
+ bindNodeAssertion,
1365
+ testStatement,
1309
1366
  tryBegin,
1310
1367
  tryCatch,
1311
1368
  tryEnd,