1 | import { execaCommand } from 'execa';
|
2 | import { Injector, tokens, commonTokens, PluginContext } from '@stryker-mutator/api/plugin';
|
3 | import { createInstrumenter, InstrumentResult } from '@stryker-mutator/instrumenter';
|
4 | import { StrykerOptions } from '@stryker-mutator/api/core';
|
5 | import { Reporter } from '@stryker-mutator/api/src/report';
|
6 | import { I } from '@stryker-mutator/util';
|
7 |
|
8 | import { coreTokens } from '../di/index.js';
|
9 | import { Sandbox } from '../sandbox/sandbox.js';
|
10 | import { LoggingClientContext } from '../logging/index.js';
|
11 | import { ConcurrencyTokenProvider, createCheckerPool } from '../concurrent/index.js';
|
12 | import { createCheckerFactory } from '../checker/index.js';
|
13 | import { createPreprocessor } from '../sandbox/index.js';
|
14 | import { Timer } from '../utils/timer.js';
|
15 | import { TemporaryDirectory } from '../utils/temporary-directory.js';
|
16 | import { UnexpectedExitHandler } from '../unexpected-exit-handler.js';
|
17 | import { FileSystem, Project } from '../fs/index.js';
|
18 |
|
19 | import { IdGenerator } from '../child-proxy/id-generator.js';
|
20 |
|
21 | import { DryRunContext } from './3-dry-run-executor.js';
|
22 |
|
23 | export interface MutantInstrumenterContext extends PluginContext {
|
24 | [commonTokens.options]: StrykerOptions;
|
25 | [coreTokens.project]: Project;
|
26 | [coreTokens.loggingContext]: LoggingClientContext;
|
27 | [coreTokens.reporter]: Required<Reporter>;
|
28 | [coreTokens.timer]: I<Timer>;
|
29 | [coreTokens.temporaryDirectory]: I<TemporaryDirectory>;
|
30 | [coreTokens.execa]: typeof execaCommand;
|
31 | [coreTokens.process]: NodeJS.Process;
|
32 | [coreTokens.unexpectedExitRegistry]: I<UnexpectedExitHandler>;
|
33 | [coreTokens.pluginModulePaths]: readonly string[];
|
34 | [coreTokens.fs]: I<FileSystem>;
|
35 | }
|
36 |
|
37 | export class MutantInstrumenterExecutor {
|
38 | public static readonly inject = tokens(commonTokens.injector, coreTokens.project, commonTokens.options);
|
39 | constructor(
|
40 | private readonly injector: Injector<MutantInstrumenterContext>,
|
41 | private readonly project: Project,
|
42 | private readonly options: StrykerOptions
|
43 | ) {}
|
44 |
|
45 | public async execute(): Promise<Injector<DryRunContext>> {
|
46 |
|
47 | const instrumenter = this.injector.injectFunction(createInstrumenter);
|
48 |
|
49 |
|
50 | const instrumentResult = await instrumenter.instrument(await this.readFilesToMutate(), this.options.mutator);
|
51 |
|
52 |
|
53 | const preprocess = this.injector.injectFunction(createPreprocessor);
|
54 | this.writeInstrumentedFiles(instrumentResult);
|
55 | await preprocess.preprocess(this.project);
|
56 |
|
57 |
|
58 | const concurrencyTokenProviderProvider = this.injector.provideClass(coreTokens.concurrencyTokenProvider, ConcurrencyTokenProvider);
|
59 | const concurrencyTokenProvider = concurrencyTokenProviderProvider.resolve(coreTokens.concurrencyTokenProvider);
|
60 |
|
61 | const checkerPoolProvider = concurrencyTokenProviderProvider
|
62 | .provideValue(coreTokens.checkerConcurrencyTokens, concurrencyTokenProvider.checkerToken$)
|
63 | .provideClass(coreTokens.workerIdGenerator, IdGenerator)
|
64 | .provideFactory(coreTokens.checkerFactory, createCheckerFactory)
|
65 | .provideFactory(coreTokens.checkerPool, createCheckerPool);
|
66 | const checkerPool = checkerPoolProvider.resolve(coreTokens.checkerPool);
|
67 | await checkerPool.init();
|
68 |
|
69 |
|
70 | const dryRunProvider = checkerPoolProvider.provideClass(coreTokens.sandbox, Sandbox).provideValue(coreTokens.mutants, instrumentResult.mutants);
|
71 | const sandbox = dryRunProvider.resolve(coreTokens.sandbox);
|
72 | await sandbox.init();
|
73 | return dryRunProvider;
|
74 | }
|
75 |
|
76 | private readFilesToMutate() {
|
77 | return Promise.all([...this.project.filesToMutate.values()].map((file) => file.toInstrumenterFile()));
|
78 | }
|
79 |
|
80 | private writeInstrumentedFiles(instrumentResult: InstrumentResult): void {
|
81 | for (const { name, content } of Object.values(instrumentResult.files)) {
|
82 | this.project.files.get(name)!.setContent(content);
|
83 | }
|
84 | }
|
85 | }
|