/
babel-transformer.ts
56 lines (52 loc) · 1.97 KB
/
babel-transformer.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
import { traverse } from '@babel/core';
/* eslint-disable @typescript-eslint/no-duplicate-imports */
// @ts-expect-error The babel types don't define "File" yet
import { File } from '@babel/core';
/* eslint-enable @typescript-eslint/no-duplicate-imports */
import { placeMutants } from '../mutant-placers';
import { mutate } from '../mutators';
import { instrumentationBabelHeader, isTypeNode, isImportDeclaration } from '../util/syntax-helpers';
import { AstFormat } from '../syntax';
import { AstTransformer } from '.';
export const transformBabel: AstTransformer<AstFormat.JS | AstFormat.TS> = (
{ root, originFileName, rawContent, offset },
mutantCollector,
{ options }
) => {
// Wrap the AST in a `new File`, so `nodePath.buildCodeFrameError` works
// https://github.com/babel/babel/issues/11889
const file = new File({ filename: originFileName }, { code: rawContent, ast: root });
traverse(file.ast, {
enter(path) {
if (isTypeNode(path) || isImportDeclaration(path) || path.isDecorator()) {
// Don't mutate type declarations or import statements
path.skip();
} else {
mutate(path, options).forEach((mutant) => {
mutantCollector.add(originFileName, mutant, offset?.position, offset?.line);
});
}
},
exit(path) {
const mutants = mutantCollector.findUnplacedMutantsInScope(path.node);
if (placeMutants(path, mutants, originFileName)) {
path.skip();
mutantCollector.markMutantsAsPlaced(mutants);
}
},
});
if (mutantCollector.hasPlacedMutants(originFileName)) {
// Be sure to leave comments like `// @flow` in.
let header = instrumentationBabelHeader;
if (Array.isArray(root.program.body[0]?.leadingComments)) {
header = [
{
...instrumentationBabelHeader[0],
leadingComments: root.program.body[0]?.leadingComments,
},
...instrumentationBabelHeader.slice(1),
];
}
root.program.body.unshift(...header);
}
};