@mutineerjs/mutineer 0.2.4 → 0.3.2

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 (132) hide show
  1. package/README.md +48 -42
  2. package/dist/bin/mutineer.js +0 -0
  3. package/dist/mutators/__tests__/operator.spec.js +169 -0
  4. package/dist/mutators/__tests__/registry.spec.js +6 -0
  5. package/dist/mutators/__tests__/return-value.spec.js +239 -0
  6. package/dist/mutators/__tests__/utils.spec.js +68 -1
  7. package/dist/mutators/operator.d.ts +25 -0
  8. package/dist/mutators/operator.js +50 -0
  9. package/dist/mutators/registry.d.ts +6 -28
  10. package/dist/mutators/registry.js +14 -66
  11. package/dist/mutators/return-value.d.ts +39 -0
  12. package/dist/mutators/return-value.js +104 -0
  13. package/dist/mutators/utils.d.ts +21 -0
  14. package/dist/mutators/utils.js +44 -27
  15. package/dist/runner/__tests__/pool-executor.spec.js +2 -4
  16. package/dist/runner/__tests__/variants.spec.js +3 -1
  17. package/dist/runner/discover.js +2 -1
  18. package/dist/runner/jest/__tests__/adapter.spec.js +1 -1
  19. package/dist/runner/jest/__tests__/pool.spec.js +5 -6
  20. package/dist/runner/jest/__tests__/worker-runtime.spec.js +2 -2
  21. package/dist/runner/jest/adapter.js +1 -1
  22. package/dist/runner/jest/pool.d.ts +1 -1
  23. package/dist/runner/jest/pool.js +6 -6
  24. package/dist/runner/jest/worker.mjs +1 -1
  25. package/dist/runner/pool-executor.js +1 -1
  26. package/dist/runner/shared/__tests__/redirect-state.spec.js +3 -3
  27. package/dist/runner/shared/index.d.ts +1 -1
  28. package/dist/runner/shared/index.js +1 -1
  29. package/dist/runner/shared/redirect-state.d.ts +2 -2
  30. package/dist/runner/shared/redirect-state.js +4 -4
  31. package/dist/runner/types.d.ts +1 -1
  32. package/dist/runner/vitest/__tests__/adapter.spec.js +1 -1
  33. package/dist/runner/vitest/__tests__/pool.spec.js +1 -1
  34. package/dist/runner/vitest/__tests__/redirect-loader.spec.js +83 -1
  35. package/dist/runner/vitest/__tests__/worker-runtime.spec.js +84 -0
  36. package/dist/runner/vitest/adapter.js +1 -1
  37. package/dist/runner/vitest/index.d.ts +0 -1
  38. package/dist/runner/vitest/index.js +0 -1
  39. package/dist/runner/vitest/pool.d.ts +1 -1
  40. package/dist/runner/vitest/pool.js +7 -7
  41. package/dist/runner/vitest/redirect-loader.d.ts +1 -1
  42. package/dist/runner/vitest/redirect-loader.js +1 -1
  43. package/dist/runner/vitest/worker-runtime.js +3 -3
  44. package/dist/runner/vitest/worker.mjs +1 -1
  45. package/dist/utils/__tests__/coverage.spec.js +167 -0
  46. package/dist/utils/__tests__/progress.spec.js +96 -0
  47. package/package.json +71 -22
  48. package/dist/admin/assets/index-B7nXq-e7.js +0 -32
  49. package/dist/admin/assets/index-B7nXq-e7.js.map +0 -1
  50. package/dist/admin/assets/index-BDQLkBUE.js +0 -32
  51. package/dist/admin/assets/index-BDQLkBUE.js.map +0 -1
  52. package/dist/admin/assets/index-DVkP-Tc7.css +0 -1
  53. package/dist/admin/index.html +0 -13
  54. package/dist/admin/server/admin.d.ts +0 -6
  55. package/dist/admin/server/admin.js +0 -234
  56. package/dist/bin/mutate-vitest.d.ts +0 -2
  57. package/dist/bin/mutate-vitest.js +0 -90
  58. package/dist/plugin/viteMutate.d.ts +0 -15
  59. package/dist/plugin/viteMutate.js +0 -52
  60. package/dist/plugin/vitest.setup.d.ts +0 -47
  61. package/dist/plugin/vitest.setup.js +0 -118
  62. package/dist/plugin/withVitest.d.ts +0 -13
  63. package/dist/plugin/withVitest.js +0 -30
  64. package/dist/runner/__tests__/orchestrator.spec.js +0 -55
  65. package/dist/runner/adapters/__tests__/jest.spec.js +0 -88
  66. package/dist/runner/adapters/__tests__/vitest-worker-runtime.spec.d.ts +0 -1
  67. package/dist/runner/adapters/__tests__/vitest-worker-runtime.spec.js +0 -59
  68. package/dist/runner/adapters/__tests__/vitest.spec.d.ts +0 -1
  69. package/dist/runner/adapters/__tests__/vitest.spec.js +0 -118
  70. package/dist/runner/adapters/index.d.ts +0 -10
  71. package/dist/runner/adapters/index.js +0 -9
  72. package/dist/runner/adapters/jest/__tests__/index.spec.d.ts +0 -1
  73. package/dist/runner/adapters/jest/__tests__/index.spec.js +0 -88
  74. package/dist/runner/adapters/jest/index.d.ts +0 -24
  75. package/dist/runner/adapters/jest/index.js +0 -216
  76. package/dist/runner/adapters/jest/worker-runtime.d.ts +0 -37
  77. package/dist/runner/adapters/jest/worker-runtime.js +0 -171
  78. package/dist/runner/adapters/jest-worker-runtime.d.ts +0 -37
  79. package/dist/runner/adapters/jest-worker-runtime.js +0 -171
  80. package/dist/runner/adapters/jest.d.ts +0 -24
  81. package/dist/runner/adapters/jest.js +0 -216
  82. package/dist/runner/adapters/types.d.ts +0 -89
  83. package/dist/runner/adapters/types.js +0 -8
  84. package/dist/runner/adapters/vitest/__tests__/index.spec.d.ts +0 -1
  85. package/dist/runner/adapters/vitest/__tests__/index.spec.js +0 -118
  86. package/dist/runner/adapters/vitest/__tests__/worker-runtime.spec.d.ts +0 -1
  87. package/dist/runner/adapters/vitest/__tests__/worker-runtime.spec.js +0 -59
  88. package/dist/runner/adapters/vitest/index.d.ts +0 -33
  89. package/dist/runner/adapters/vitest/index.js +0 -267
  90. package/dist/runner/adapters/vitest/worker-runtime.d.ts +0 -25
  91. package/dist/runner/adapters/vitest/worker-runtime.js +0 -118
  92. package/dist/runner/adapters/vitest-worker-runtime.d.ts +0 -25
  93. package/dist/runner/adapters/vitest-worker-runtime.js +0 -118
  94. package/dist/runner/adapters/vitest.d.ts +0 -33
  95. package/dist/runner/adapters/vitest.js +0 -267
  96. package/dist/runner/pool/__tests__/index.spec.d.ts +0 -1
  97. package/dist/runner/pool/__tests__/index.spec.js +0 -83
  98. package/dist/runner/pool/__tests__/pool-plugin.spec.d.ts +0 -1
  99. package/dist/runner/pool/__tests__/pool-plugin.spec.js +0 -59
  100. package/dist/runner/pool/__tests__/pool-redirect-loader.spec.d.ts +0 -1
  101. package/dist/runner/pool/__tests__/pool-redirect-loader.spec.js +0 -78
  102. package/dist/runner/pool/index.d.ts +0 -8
  103. package/dist/runner/pool/index.js +0 -9
  104. package/dist/runner/pool/jest/pool.d.ts +0 -52
  105. package/dist/runner/pool/jest/pool.js +0 -309
  106. package/dist/runner/pool/jest/worker.d.mts +0 -1
  107. package/dist/runner/pool/jest/worker.mjs +0 -60
  108. package/dist/runner/pool/jest-pool.d.ts +0 -52
  109. package/dist/runner/pool/jest-pool.js +0 -309
  110. package/dist/runner/pool/jest-worker.d.mts +0 -1
  111. package/dist/runner/pool/jest-worker.mjs +0 -60
  112. package/dist/runner/pool/plugin.d.ts +0 -18
  113. package/dist/runner/pool/plugin.js +0 -60
  114. package/dist/runner/pool/pool-plugin.d.ts +0 -18
  115. package/dist/runner/pool/pool-plugin.js +0 -60
  116. package/dist/runner/pool/pool-redirect-loader.d.ts +0 -19
  117. package/dist/runner/pool/pool-redirect-loader.js +0 -116
  118. package/dist/runner/pool/pool-redirect-loader.mjs +0 -146
  119. package/dist/runner/pool/redirect-loader.d.ts +0 -19
  120. package/dist/runner/pool/redirect-loader.js +0 -116
  121. package/dist/runner/pool/vitest/pool.d.ts +0 -70
  122. package/dist/runner/pool/vitest/pool.js +0 -376
  123. package/dist/runner/pool/vitest/worker.d.mts +0 -15
  124. package/dist/runner/pool/vitest/worker.mjs +0 -96
  125. package/dist/runner/pool/vitest-worker.d.mts +0 -15
  126. package/dist/runner/pool/vitest-worker.mjs +0 -96
  127. package/dist/runner/shared-module-redirect.d.ts +0 -56
  128. package/dist/runner/shared-module-redirect.js +0 -84
  129. package/dist/types/api.d.ts +0 -20
  130. package/dist/types/api.js +0 -1
  131. /package/dist/{runner/__tests__/orchestrator.spec.d.ts → mutators/__tests__/operator.spec.d.ts} +0 -0
  132. /package/dist/{runner/adapters/__tests__/jest.spec.d.ts → mutators/__tests__/return-value.spec.d.ts} +0 -0
@@ -1,146 +0,0 @@
1
- /**
2
- * Dynamic ESM loader for persistent Vitest workers.
3
- *
4
- * Unlike the fast runner's static loader (which reads env vars at startup),
5
- * this loader reads the redirect target from globalThis.__mutineer_redirect__
6
- * on each resolution, allowing dynamic changes during the worker's lifetime.
7
- *
8
- * This enables the worker to test multiple mutations without restarting.
9
- */
10
-
11
- import { register, builtinModules } from 'node:module'
12
- import { pathToFileURL, fileURLToPath } from 'node:url'
13
- import path from 'node:path'
14
- import fs from 'node:fs'
15
-
16
- // Register this file as the loader hooks module
17
- register(import.meta.url, {
18
- parentURL: import.meta.url,
19
- data: { debug: process.env.MUTINEER_DEBUG === '1' }
20
- })
21
-
22
- let DEBUG = process.env.MUTINEER_DEBUG === '1'
23
-
24
- export function initialize(data) {
25
- if (data?.debug !== undefined) {
26
- DEBUG = data.debug
27
- }
28
- }
29
-
30
- /**
31
- * Try to resolve a .js import to a .ts file (TypeScript ESM convention)
32
- */
33
- function tryResolveTsExtension(specifier, parentURL) {
34
- if (!specifier.endsWith('.js') || !specifier.startsWith('.')) {
35
- return null
36
- }
37
-
38
- let parentPath
39
- try {
40
- parentPath = fileURLToPath(parentURL)
41
- } catch {
42
- return null
43
- }
44
- const parentDir = path.dirname(parentPath)
45
-
46
- // If the parent is in a __mutineer__ directory, also try the parent's parent
47
- const dirsToTry = [parentDir]
48
- if (path.basename(parentDir) === '__mutineer__') {
49
- dirsToTry.push(path.dirname(parentDir))
50
- }
51
-
52
- const tsSpecifier = specifier.slice(0, -3) + '.ts'
53
- const tsxSpecifier = specifier.slice(0, -3) + '.tsx'
54
-
55
- for (const dir of dirsToTry) {
56
- const tsPath = path.resolve(dir, tsSpecifier)
57
- if (fs.existsSync(tsPath)) {
58
- return pathToFileURL(tsPath).href
59
- }
60
-
61
- const tsxPath = path.resolve(dir, tsxSpecifier)
62
- if (fs.existsSync(tsxPath)) {
63
- return pathToFileURL(tsxPath).href
64
- }
65
- }
66
-
67
- return null
68
- }
69
-
70
- /**
71
- * Get the current redirect config from globalThis (set by the worker)
72
- */
73
- function getRedirect() {
74
- const redirect = globalThis.__mutineer_redirect__
75
- if (!redirect?.from || !redirect?.to) {
76
- return null
77
- }
78
- return {
79
- from: path.resolve(redirect.from),
80
- fromUrl: pathToFileURL(path.resolve(redirect.from)).href,
81
- to: redirect.to,
82
- }
83
- }
84
-
85
- export async function resolve(specifier, context, nextResolve) {
86
- const redirect = getRedirect()
87
- const isBuiltin = specifier.startsWith('node:') || builtinModules.includes(specifier)
88
- const isNodeModulesSpec = specifier.includes('node_modules')
89
-
90
- const shouldLog = DEBUG && !isBuiltin && !isNodeModulesSpec
91
-
92
- if (shouldLog) {
93
- console.error(`[pool-loader] resolve: ${specifier}`)
94
- if (redirect) {
95
- console.error(`[pool-loader] active redirect: ${redirect.from} -> ${redirect.to}`)
96
- }
97
- }
98
-
99
- // Try to resolve .js -> .ts for TypeScript ESM imports
100
- const tsResolved = tryResolveTsExtension(specifier, context.parentURL)
101
- if (tsResolved) {
102
- if (DEBUG) console.error(`[pool-loader] .js -> .ts: ${specifier} -> ${tsResolved}`)
103
-
104
- // Check if this is our redirect target
105
- if (redirect && tsResolved === redirect.fromUrl) {
106
- if (DEBUG) console.error(`[pool-loader] REDIRECTING ${tsResolved} -> ${pathToFileURL(redirect.to).href}`)
107
- return {
108
- url: pathToFileURL(redirect.to).href,
109
- shortCircuit: true
110
- }
111
- }
112
-
113
- return {
114
- url: tsResolved,
115
- shortCircuit: true
116
- }
117
- }
118
-
119
- // Let the default resolver handle it
120
- let resolved
121
- try {
122
- resolved = await nextResolve(specifier, context)
123
- } catch (e) {
124
- throw e
125
- }
126
-
127
- const resolvedInNodeModules = resolved?.url?.includes('/node_modules/')
128
- const resolvedBuiltin = resolved?.url?.startsWith('node:')
129
- if (shouldLog && !resolvedInNodeModules && !resolvedBuiltin) console.error(`[pool-loader] resolved ${specifier} to ${resolved.url}`)
130
-
131
- // Check if this resolves to our redirect target
132
- if (redirect && resolved.url === redirect.fromUrl) {
133
- if (DEBUG) console.error(`[pool-loader] REDIRECTING ${resolved.url} -> ${pathToFileURL(redirect.to).href}`)
134
- return {
135
- ...resolved,
136
- url: pathToFileURL(redirect.to).href,
137
- shortCircuit: true
138
- }
139
- }
140
-
141
- return resolved
142
- }
143
-
144
- export async function load(url, context, nextLoad) {
145
- return nextLoad(url, context)
146
- }
@@ -1,19 +0,0 @@
1
- /**
2
- * Dynamic ESM loader for persistent Vitest workers.
3
- *
4
- * Reads redirect targets from globalThis.__mutineer_redirect__ on each resolution
5
- * so workers can swap files without restarting.
6
- */
7
- declare global {
8
- var __mutineer_redirect__: {
9
- from: string | null;
10
- to: string | null;
11
- } | undefined;
12
- }
13
- export declare function initialize(data: {
14
- debug?: boolean;
15
- } | undefined): void;
16
- export declare function resolve(specifier: string, context: {
17
- parentURL?: string;
18
- }, nextResolve: (specifier: string, context: any) => Promise<any>): Promise<any>;
19
- export declare function load(url: string, context: unknown, nextLoad: (u: string, c: unknown) => Promise<unknown>): Promise<unknown>;
@@ -1,116 +0,0 @@
1
- /**
2
- * Dynamic ESM loader for persistent Vitest workers.
3
- *
4
- * Reads redirect targets from globalThis.__mutineer_redirect__ on each resolution
5
- * so workers can swap files without restarting.
6
- */
7
- import { register, builtinModules } from 'node:module';
8
- import { pathToFileURL, fileURLToPath } from 'node:url';
9
- import path from 'node:path';
10
- import fs from 'node:fs';
11
- // Register this file as the loader hooks module
12
- register(import.meta.url, {
13
- parentURL: import.meta.url,
14
- data: { debug: process.env.MUTINEER_DEBUG === '1' }
15
- });
16
- let DEBUG = process.env.MUTINEER_DEBUG === '1';
17
- export function initialize(data) {
18
- if (data?.debug !== undefined) {
19
- DEBUG = data.debug;
20
- }
21
- }
22
- /**
23
- * Try to resolve a .js import to a .ts or .tsx file (TypeScript ESM convention)
24
- */
25
- function tryResolveTsExtension(specifier, parentURL) {
26
- if (!specifier.endsWith('.js') || !specifier.startsWith('.')) {
27
- return null;
28
- }
29
- let parentPath;
30
- try {
31
- parentPath = fileURLToPath(parentURL ?? '');
32
- }
33
- catch {
34
- return null;
35
- }
36
- const parentDir = path.dirname(parentPath);
37
- // If the parent is in a __mutineer__ directory, also try the parent's parent
38
- const dirsToTry = [parentDir];
39
- if (path.basename(parentDir) === '__mutineer__') {
40
- dirsToTry.push(path.dirname(parentDir));
41
- }
42
- const tsSpecifier = specifier.slice(0, -3) + '.ts';
43
- const tsxSpecifier = specifier.slice(0, -3) + '.tsx';
44
- for (const dir of dirsToTry) {
45
- const tsPath = path.resolve(dir, tsSpecifier);
46
- if (fs.existsSync(tsPath)) {
47
- return pathToFileURL(tsPath).href;
48
- }
49
- const tsxPath = path.resolve(dir, tsxSpecifier);
50
- if (fs.existsSync(tsxPath)) {
51
- return pathToFileURL(tsxPath).href;
52
- }
53
- }
54
- return null;
55
- }
56
- function getRedirect() {
57
- const redirect = globalThis.__mutineer_redirect__;
58
- if (!redirect?.from || !redirect?.to) {
59
- return null;
60
- }
61
- return {
62
- from: path.resolve(redirect.from),
63
- fromUrl: pathToFileURL(path.resolve(redirect.from)).href,
64
- to: redirect.to,
65
- };
66
- }
67
- export async function resolve(specifier, context, nextResolve) {
68
- const redirect = getRedirect();
69
- const isBuiltin = specifier.startsWith('node:') || builtinModules.includes(specifier);
70
- const isNodeModulesSpec = specifier.includes('node_modules');
71
- const shouldLog = DEBUG && !isBuiltin && !isNodeModulesSpec;
72
- if (shouldLog) {
73
- console.error(`[pool-loader] resolve: ${specifier}`);
74
- if (redirect) {
75
- console.error(`[pool-loader] active redirect: ${redirect.from} -> ${redirect.to}`);
76
- }
77
- }
78
- // Try to resolve .js -> .ts for TypeScript ESM imports
79
- const tsResolved = tryResolveTsExtension(specifier, context.parentURL);
80
- if (tsResolved) {
81
- if (shouldLog)
82
- console.error(`[pool-loader] .js -> .ts: ${specifier} -> ${tsResolved}`);
83
- // Check if this is our redirect target
84
- if (redirect && tsResolved === redirect.fromUrl) {
85
- if (DEBUG)
86
- console.error(`[pool-loader] REDIRECTING ${tsResolved} -> ${pathToFileURL(redirect.to).href}`);
87
- return {
88
- url: pathToFileURL(redirect.to).href,
89
- shortCircuit: true
90
- };
91
- }
92
- return {
93
- url: tsResolved,
94
- shortCircuit: true
95
- };
96
- }
97
- const resolved = await nextResolve(specifier, context);
98
- const resolvedInNodeModules = resolved?.url?.includes('/node_modules/');
99
- const resolvedBuiltin = resolved?.url?.startsWith('node:');
100
- if (shouldLog && !resolvedInNodeModules && !resolvedBuiltin)
101
- console.error(`[pool-loader] resolved ${specifier} to ${resolved.url}`);
102
- // Check if this resolves to our redirect target
103
- if (redirect && resolved.url === redirect.fromUrl) {
104
- if (DEBUG)
105
- console.error(`[pool-loader] REDIRECTING ${resolved.url} -> ${pathToFileURL(redirect.to).href}`);
106
- return {
107
- ...resolved,
108
- url: pathToFileURL(redirect.to).href,
109
- shortCircuit: true
110
- };
111
- }
112
- return resolved;
113
- }
114
- export async function load(url, context, nextLoad) {
115
- return nextLoad(url, context);
116
- }
@@ -1,70 +0,0 @@
1
- /**
2
- * Vitest Worker Pool
3
- *
4
- * Manages a pool of persistent Vitest worker processes that can run
5
- * multiple mutations without restarting, providing significant speedup
6
- * over the per-spawn approach.
7
- *
8
- * Each worker:
9
- * - Starts Vitest in watch mode via programmatic API
10
- * - Receives mutations via stdin (JSON)
11
- * - Uses dynamic redirect loader to swap module at runtime
12
- * - Returns results via stdout (JSON)
13
- */
14
- import { EventEmitter } from 'node:events';
15
- import type { MutantPayload, MutantRunResult, MutantRunSummary } from '../../../types/mutant.js';
16
- declare class VitestWorker extends EventEmitter {
17
- private readonly cwd;
18
- private readonly vitestConfig?;
19
- private readonly debug;
20
- readonly id: string;
21
- private process;
22
- private rl;
23
- private pendingTask;
24
- private ready;
25
- private shuttingDown;
26
- constructor(id: string, cwd: string, vitestConfig?: string | undefined, debug?: boolean);
27
- start(): Promise<void>;
28
- private handleMessage;
29
- private handleExit;
30
- isReady(): boolean;
31
- isBusy(): boolean;
32
- run(mutant: MutantPayload, tests: string[], timeoutMs?: number): Promise<MutantRunSummary>;
33
- shutdown(): Promise<void>;
34
- kill(): void;
35
- private log;
36
- }
37
- export interface VitestPoolOptions {
38
- cwd: string;
39
- concurrency: number;
40
- vitestConfig?: string;
41
- timeoutMs?: number;
42
- debug?: boolean;
43
- createWorker?: (id: string, opts: {
44
- cwd: string;
45
- vitestConfig?: string;
46
- debug: boolean;
47
- }) => VitestWorker;
48
- }
49
- export declare class VitestPool {
50
- private workers;
51
- private availableWorkers;
52
- private waitingTasks;
53
- private readonly options;
54
- private initialized;
55
- private shuttingDown;
56
- constructor(options: VitestPoolOptions);
57
- init(): Promise<void>;
58
- private handleWorkerExit;
59
- private acquireWorker;
60
- private releaseWorker;
61
- run(mutant: MutantPayload, tests: string[]): Promise<MutantRunSummary>;
62
- shutdown(): Promise<void>;
63
- private log;
64
- }
65
- /**
66
- * Run a single mutation using the pool.
67
- * Convenience function for integration with orchestrator.
68
- */
69
- export declare function runWithPool(pool: VitestPool, mutant: MutantPayload, tests: readonly string[]): Promise<MutantRunResult>;
70
- export type { MutantPayload, MutantRunResult, MutantRunSummary } from '../../../types/mutant.js';