Skip to content

Commit

Permalink
fix(babel-transformer): respect top of the file comments/pragma (#2783)
Browse files Browse the repository at this point in the history
Make sure top-level file comments are preserved, like `// @flow`. 

Co-authored-by: Nico Jansen <jansennico@gmail.com>
  • Loading branch information
swist and nicojs committed Mar 11, 2021
1 parent 547a25c commit ca42276
Show file tree
Hide file tree
Showing 15 changed files with 2,691 additions and 2,493 deletions.
53 changes: 53 additions & 0 deletions e2e/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions e2e/package.json
Expand Up @@ -8,6 +8,7 @@
"@babel/plugin-proposal-class-properties": "~7.8.3",
"@babel/plugin-proposal-pipeline-operator": "~7.8.3",
"@babel/preset-env": "~7.8.3",
"@babel/preset-flow": "7.12.13",
"@types/node": "^10.12.18",
"@types/semver": "~6.2.0",
"ajv": "~7.0.2",
Expand Down
16 changes: 16 additions & 0 deletions e2e/test/flow-test-project/.babelrc
@@ -0,0 +1,16 @@
{
"presets": [
"@babel/preset-flow",
[
"@babel/preset-env",
{
"targets": {
"edge": "16",
"firefox": "57",
"chrome": "62",
"safari": "11"
}
}
]
]
}
5 changes: 5 additions & 0 deletions e2e/test/flow-test-project/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 11 additions & 0 deletions e2e/test/flow-test-project/package.json
@@ -0,0 +1,11 @@
{
"name": "flow-jest-project",
"version": "0.0.0",
"private": true,
"description": "A module to test a flow project, see https://flow.org/",
"scripts": {
"test:unit": "jest",
"test": "stryker run",
"posttest": "mocha --no-config --require ../../tasks/ts-node-register.js verify/*.ts"
}
}
6 changes: 6 additions & 0 deletions e2e/test/flow-test-project/src/square.js
@@ -0,0 +1,6 @@
// @flow
export function square(n: number): number {
const result: Array<?number> = [];
const cat = new Set<string>();
return n * n;
}
8 changes: 8 additions & 0 deletions e2e/test/flow-test-project/src/square.spec.js
@@ -0,0 +1,8 @@
import { square } from './square';
import { expect } from 'chai';

describe('square', () => {
it('should provide 4 when given 2', () => {
expect(square(2)).eq(4);
});
});
13 changes: 13 additions & 0 deletions e2e/test/flow-test-project/stryker.conf.json
@@ -0,0 +1,13 @@
{
"$schema": "../../node_modules/@stryker-mutator/core/schema/stryker-schema.json",
"reporters": [
"clear-text",
"event-recorder"
],
"concurrency": 2,
"commandRunner": {
"command": "npm run test:unit"
},
"symlinkNodeModules": false,
"fileLogLevel": "info"
}
16 changes: 16 additions & 0 deletions e2e/test/flow-test-project/verify/.babelrc
@@ -0,0 +1,16 @@
{
"presets": [
"@babel/preset-flow",
[
"@babel/preset-env",
{
"targets": {
"edge": "16",
"firefox": "57",
"chrome": "62",
"safari": "11"
}
}
]
]
}
19 changes: 19 additions & 0 deletions e2e/test/flow-test-project/verify/verify.ts
@@ -0,0 +1,19 @@
import { expectMetrics } from '../../../helpers';

describe('After running stryker on jest-react project', () => {
it('should report expected scores', async () => {
await expectMetrics({
killed: 2,
ignored: 0,
survived: 1,
mutationScore: 66.67,
});
/*
-----------|---------|----------|-----------|------------|----------|---------|
File | % score | # killed | # timeout | # survived | # no cov | # error |
-----------|---------|----------|-----------|------------|----------|---------|
All files | 66.67 | 2 | 0 | 1 | 0 | 0 |
square.js | 66.67 | 2 | 0 | 1 | 0 | 0 |
-----------|---------|----------|-----------|------------|----------|---------|*/
});
});
13 changes: 12 additions & 1 deletion packages/instrumenter/src/transformers/babel-transformer.ts
Expand Up @@ -40,6 +40,17 @@ export const transformBabel: AstTransformer<AstFormat.JS | AstFormat.TS> = (
},
});
if (mutantCollector.hasPlacedMutants(originFileName)) {
root.program.body.unshift(...instrumentationBabelHeader);
// 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);
}
};
7 changes: 5 additions & 2 deletions packages/instrumenter/src/util/syntax-helpers.ts
Expand Up @@ -2,6 +2,7 @@ import { INSTRUMENTER_CONSTANTS as ID } from '@stryker-mutator/api/core';
import { types, NodePath } from '@babel/core';
import traverse from '@babel/traverse';
import { parse } from '@babel/parser';
import { deepFreeze } from '@stryker-mutator/util';

import { Mutant } from '../mutant';

Expand All @@ -14,7 +15,8 @@ const IS_MUTANT_ACTIVE_HELPER = 'stryMutAct_9fa48';
/**
* Returns syntax for the header if JS/TS files
*/
export const instrumentationBabelHeader = parse(`function ${STRYKER_NAMESPACE_HELPER}(){
export const instrumentationBabelHeader = deepFreeze(
parse(`function ${STRYKER_NAMESPACE_HELPER}(){
var g = new Function("return this")();
var ns = g.${ID.NAMESPACE} || (g.${ID.NAMESPACE} = {});
if (ns.${ID.ACTIVE_MUTANT} === undefined && g.process && g.process.env && g.process.env.${ID.ACTIVE_MUTANT_ENV_VARIABLE}) {
Expand Down Expand Up @@ -51,7 +53,8 @@ function ${IS_MUTANT_ACTIVE_HELPER}(id) {
}
${IS_MUTANT_ACTIVE_HELPER} = isActive;
return isActive(id);
}`).program.body;
}`).program.body
) as readonly types.Statement[]; // cast here, otherwise the thing gets unwieldy to handle

/**
* returns syntax for `global.activeMutant === $mutantId`
Expand Down

0 comments on commit ca42276

Please sign in to comment.