oxmutate 2.0.1 → 2.1.0

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/dist/cli.js CHANGED
@@ -58,6 +58,8 @@ function overridesFrom(o, root) {
58
58
  overrides.timeoutMS = o['mutantTimeout'];
59
59
  if (o['strykerCompat'] === true)
60
60
  overrides.strykerCompat = true;
61
+ if (o['ignoreStatic'] === true)
62
+ overrides.ignoreStatic = true;
61
63
  if (o['incremental'] === true)
62
64
  overrides.incremental = true;
63
65
  if (typeof o['flakyReruns'] === 'number')
@@ -87,6 +89,7 @@ const runCommand = defineCommand({
87
89
  concurrency: { type: 'number', description: 'worker processes (default: cores - 1, at most 8)' },
88
90
  mutantTimeout: { type: 'number', description: 'absolute slack per mutant, ms (default 500; Stryker 5000)' },
89
91
  strykerCompat: { type: 'boolean', description: 'reproduce Stryker 10.0.0 skips (no mutants inside `as` casts or enums)' },
92
+ ignoreStatic: { type: 'boolean', description: 'skip static mutants (module-level code): faster, and the score leaves them out' },
90
93
  incremental: { type: 'boolean', description: 'reuse verdicts whose source and covering tests did not change' },
91
94
  flakyReruns: { type: 'number', description: 're-runs for verdicts with nondeterministic tests (default 2; 0 disables)' },
92
95
  reporter: { type: 'string', description: 'comma-separated: clear-text, json, sarif, html (default clear-text,json)' },
package/dist/config.d.ts CHANGED
@@ -6,6 +6,8 @@ export interface Thresholds {
6
6
  /** Fail the run (exit 1) below this score. `null`: never fail on score. */
7
7
  break: number | null;
8
8
  }
9
+ /** Why a static mutant is Ignored under `ignoreStatic`; the summary counts them by it. */
10
+ export declare const IGNORE_STATIC_REASON = "static mutant (ignoreStatic)";
9
11
  export interface Options {
10
12
  root: string;
11
13
  mutate: string[];
package/dist/config.js CHANGED
@@ -3,6 +3,7 @@ import { availableParallelism } from 'node:os';
3
3
  import path from 'node:path';
4
4
  import { pathToFileURL } from 'node:url';
5
5
  import { resolveEsm } from './resolve.js';
6
+ export const IGNORE_STATIC_REASON = 'static mutant (ignoreStatic)';
6
7
  const NOT_NEEDED = {
7
8
  inPlace: 'oxmutate never copies or rewrites the project; instrumented sources are served from memory',
8
9
  tempDirName: 'no sandbox directory exists',
@@ -5,7 +5,7 @@ import path from 'node:path';
5
5
  import { ambientRuntime, run as spawn } from 'bellpull';
6
6
  import { checkSurvivors } from './checker.js';
7
7
  import { runCommandMutants } from './command-runner.js';
8
- import { disables } from './config.js';
8
+ import { IGNORE_STATIC_REASON, disables } from './config.js';
9
9
  import { rangeDisables } from './directives.js';
10
10
  import { guardDisk, isClean } from './diskguard.js';
11
11
  import { globToRegExp, matchFiles } from './files.js';
@@ -271,7 +271,7 @@ export async function run(options) {
271
271
  m.static = true;
272
272
  if (options.ignoreStatic) {
273
273
  m.status = 'Ignored';
274
- m.statusReason = 'static mutant (ignoreStatic)';
274
+ m.statusReason = IGNORE_STATIC_REASON;
275
275
  }
276
276
  }
277
277
  }
package/dist/reports.js CHANGED
@@ -1,6 +1,7 @@
1
1
  import { mkdirSync, readFileSync, writeFileSync } from 'node:fs';
2
2
  import { createRequire } from 'node:module';
3
3
  import path from 'node:path';
4
+ import { IGNORE_STATIC_REASON } from './config.js';
4
5
  export const VERSION = JSON.parse(readFileSync(new URL('../package.json', import.meta.url), 'utf8')).version;
5
6
  const REPLACEMENT_WIDTH = 60;
6
7
  const ELLIPSIS = '...';
@@ -116,10 +117,25 @@ function frozenLine(r) {
116
117
  const sign = f.delta >= 0 ? '+' : '';
117
118
  return [` frozen oracle vs ${f.base}: ${f.headScore.toFixed(2)}% with the change's tests, ${f.baseScore.toFixed(2)}% with the base's (${sign}${f.delta.toFixed(2)}), ${String(f.weakened.length)} mutant(s) the change stopped detecting`];
118
119
  }
119
- function whereItWent(s) {
120
+ const STATIC_SHARE_WORTH_SAYING = 0.5;
121
+ const PERCENT = 100;
122
+ function staticLine(r) {
123
+ const statics = r.mutants.filter((m) => m.static);
124
+ if (statics.length === 0)
125
+ return [];
126
+ const ignored = statics.filter((m) => m.statusReason === IGNORE_STATIC_REASON).length;
127
+ if (ignored > 0)
128
+ return [` static mutants: ${String(ignored)} ignored (ignoreStatic), not scored`];
129
+ const share = r.stats.wallMs > 0 ? r.stats.staticMs / r.stats.wallMs : 0;
130
+ const hint = share >= STATIC_SHARE_WORTH_SAYING ? '; --ignore-static skips them, and the score then leaves them out' : '';
131
+ return [` static mutants: ${String(statics.length)} decided in ${(r.stats.staticMs / MS_PER_S).toFixed(1)} s, ${(share * PERCENT).toFixed(0)}% of the run${hint}`];
132
+ }
133
+ function whereItWent(r) {
134
+ const s = r.stats;
120
135
  const lines = [];
121
136
  if (s.warmUnitMs > 0)
122
137
  lines.push(` warm servers ran ${(s.warmUnitMs / MS_PER_S).toFixed(1)} s, ${(s.warmArmedMs / MS_PER_S).toFixed(1)} s of it inside test runs`);
138
+ lines.push(...staticLine(r));
123
139
  const c = s.isolatedByCause;
124
140
  const causes = [`static ${String(c.static)}`, `stopped ${String(c.stopped)}`, `unfinished ${String(c.unfinished)}`, `re-run ${String(c.rerun)}`, `survivors confirmed ${String(c.confirm)}`, `flaky ${String(c.flaky)}`];
125
141
  if (s.isolatedRuns > 0)
@@ -142,7 +158,7 @@ export function textSummary(r, opts = {}) {
142
158
  const corrected = corrections(s);
143
159
  if (corrected.length)
144
160
  lines.push(` corrected: ${corrected.join(' · ')}`);
145
- lines.push(...whereItWent(s));
161
+ lines.push(...whereItWent(r));
146
162
  lines.push(...frozenLine(r));
147
163
  lines.push(...specLines(r));
148
164
  const survivors = r.mutants.filter((m) => m.status === 'Survived' || m.status === 'NoCoverage');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "oxmutate",
3
- "version": "2.0.1",
3
+ "version": "2.1.0",
4
4
  "description": "Mutation testing for JavaScript and TypeScript on the oxc engine, run warm inside the project's own Vitest, with CI lanes, SARIF and an agent surface. No dependency outside the burgee family. A Stryker migration path.",
5
5
  "license": "MIT",
6
6
  "author": "Ofri Peretz <ofriperetzdev@gmail.com>",