@d-es-ign/stryker-js-instrumenter 9.6.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/LICENSE +201 -0
- package/dist/src/create-instrumenter.d.ts +16 -0
- package/dist/src/create-instrumenter.d.ts.map +1 -0
- package/dist/src/create-instrumenter.js +15 -0
- package/dist/src/create-instrumenter.js.map +1 -0
- package/dist/src/disable-type-checks.d.ts +11 -0
- package/dist/src/disable-type-checks.d.ts.map +1 -0
- package/dist/src/disable-type-checks.js +125 -0
- package/dist/src/disable-type-checks.js.map +1 -0
- package/dist/src/file.d.ts +6 -0
- package/dist/src/file.d.ts.map +1 -0
- package/dist/src/file.js +2 -0
- package/dist/src/file.js.map +1 -0
- package/dist/src/frameworks/angular-ignorer.d.ts +16 -0
- package/dist/src/frameworks/angular-ignorer.d.ts.map +1 -0
- package/dist/src/frameworks/angular-ignorer.js +85 -0
- package/dist/src/frameworks/angular-ignorer.js.map +1 -0
- package/dist/src/frameworks/index.d.ts +4 -0
- package/dist/src/frameworks/index.d.ts.map +1 -0
- package/dist/src/frameworks/index.js +7 -0
- package/dist/src/frameworks/index.js.map +1 -0
- package/dist/src/index.d.ts +9 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +8 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/instrument-result.d.ts +7 -0
- package/dist/src/instrument-result.d.ts.map +1 -0
- package/dist/src/instrument-result.js +2 -0
- package/dist/src/instrument-result.js.map +1 -0
- package/dist/src/instrumenter-options.d.ts +5 -0
- package/dist/src/instrumenter-options.d.ts.map +1 -0
- package/dist/src/instrumenter-options.js +2 -0
- package/dist/src/instrumenter-options.js.map +1 -0
- package/dist/src/instrumenter-tokens.d.ts +6 -0
- package/dist/src/instrumenter-tokens.d.ts.map +1 -0
- package/dist/src/instrumenter-tokens.js +6 -0
- package/dist/src/instrumenter-tokens.js.map +1 -0
- package/dist/src/instrumenter.d.ts +24 -0
- package/dist/src/instrumenter.d.ts.map +1 -0
- package/dist/src/instrumenter.js +76 -0
- package/dist/src/instrumenter.js.map +1 -0
- package/dist/src/mutant-placers/expression-mutant-placer.d.ts +10 -0
- package/dist/src/mutant-placers/expression-mutant-placer.d.ts.map +1 -0
- package/dist/src/mutant-placers/expression-mutant-placer.js +144 -0
- package/dist/src/mutant-placers/expression-mutant-placer.js.map +1 -0
- package/dist/src/mutant-placers/index.d.ts +5 -0
- package/dist/src/mutant-placers/index.d.ts.map +1 -0
- package/dist/src/mutant-placers/index.js +11 -0
- package/dist/src/mutant-placers/index.js.map +1 -0
- package/dist/src/mutant-placers/mutant-placer.d.ts +8 -0
- package/dist/src/mutant-placers/mutant-placer.d.ts.map +1 -0
- package/dist/src/mutant-placers/mutant-placer.js +2 -0
- package/dist/src/mutant-placers/mutant-placer.js.map +1 -0
- package/dist/src/mutant-placers/statement-mutant-placer.d.ts +8 -0
- package/dist/src/mutant-placers/statement-mutant-placer.d.ts.map +1 -0
- package/dist/src/mutant-placers/statement-mutant-placer.js +24 -0
- package/dist/src/mutant-placers/statement-mutant-placer.js.map +1 -0
- package/dist/src/mutant-placers/switch-case-mutant-placer.d.ts +14 -0
- package/dist/src/mutant-placers/switch-case-mutant-placer.d.ts.map +1 -0
- package/dist/src/mutant-placers/switch-case-mutant-placer.js +29 -0
- package/dist/src/mutant-placers/switch-case-mutant-placer.js.map +1 -0
- package/dist/src/mutant-placers/throw-placement-error.d.ts +5 -0
- package/dist/src/mutant-placers/throw-placement-error.d.ts.map +1 -0
- package/dist/src/mutant-placers/throw-placement-error.js +17 -0
- package/dist/src/mutant-placers/throw-placement-error.js.map +1 -0
- package/dist/src/mutant.d.ts +27 -0
- package/dist/src/mutant.d.ts.map +1 -0
- package/dist/src/mutant.js +80 -0
- package/dist/src/mutant.js.map +1 -0
- package/dist/src/mutators/arithmetic-operator-mutator.d.ts +3 -0
- package/dist/src/mutators/arithmetic-operator-mutator.d.ts.map +1 -0
- package/dist/src/mutators/arithmetic-operator-mutator.js +34 -0
- package/dist/src/mutators/arithmetic-operator-mutator.js.map +1 -0
- package/dist/src/mutators/array-declaration-mutator.d.ts +3 -0
- package/dist/src/mutators/array-declaration-mutator.d.ts.map +1 -0
- package/dist/src/mutators/array-declaration-mutator.js +26 -0
- package/dist/src/mutators/array-declaration-mutator.js.map +1 -0
- package/dist/src/mutators/arrow-function-mutator.d.ts +3 -0
- package/dist/src/mutators/arrow-function-mutator.d.ts.map +1 -0
- package/dist/src/mutators/arrow-function-mutator.js +14 -0
- package/dist/src/mutators/arrow-function-mutator.js.map +1 -0
- package/dist/src/mutators/assignment-operator-mutator.d.ts +3 -0
- package/dist/src/mutators/assignment-operator-mutator.d.ts.map +1 -0
- package/dist/src/mutators/assignment-operator-mutator.js +42 -0
- package/dist/src/mutators/assignment-operator-mutator.js.map +1 -0
- package/dist/src/mutators/block-statement-mutator.d.ts +3 -0
- package/dist/src/mutators/block-statement-mutator.d.ts.map +1 -0
- package/dist/src/mutators/block-statement-mutator.js +63 -0
- package/dist/src/mutators/block-statement-mutator.js.map +1 -0
- package/dist/src/mutators/boolean-literal-mutator.d.ts +3 -0
- package/dist/src/mutators/boolean-literal-mutator.d.ts.map +1 -0
- package/dist/src/mutators/boolean-literal-mutator.js +17 -0
- package/dist/src/mutators/boolean-literal-mutator.js.map +1 -0
- package/dist/src/mutators/conditional-expression-mutator.d.ts +3 -0
- package/dist/src/mutators/conditional-expression-mutator.d.ts.map +1 -0
- package/dist/src/mutators/conditional-expression-mutator.js +81 -0
- package/dist/src/mutators/conditional-expression-mutator.js.map +1 -0
- package/dist/src/mutators/equality-operator-mutator.d.ts +3 -0
- package/dist/src/mutators/equality-operator-mutator.d.ts.map +1 -0
- package/dist/src/mutators/equality-operator-mutator.js +28 -0
- package/dist/src/mutators/equality-operator-mutator.js.map +1 -0
- package/dist/src/mutators/index.d.ts +4 -0
- package/dist/src/mutators/index.d.ts.map +1 -0
- package/dist/src/mutators/index.js +4 -0
- package/dist/src/mutators/index.js.map +1 -0
- package/dist/src/mutators/logical-operator-mutator.d.ts +3 -0
- package/dist/src/mutators/logical-operator-mutator.d.ts.map +1 -0
- package/dist/src/mutators/logical-operator-mutator.js +21 -0
- package/dist/src/mutators/logical-operator-mutator.js.map +1 -0
- package/dist/src/mutators/method-expression-mutator.d.ts +3 -0
- package/dist/src/mutators/method-expression-mutator.d.ts.map +1 -0
- package/dist/src/mutators/method-expression-mutator.js +65 -0
- package/dist/src/mutators/method-expression-mutator.js.map +1 -0
- package/dist/src/mutators/mutate.d.ts +3 -0
- package/dist/src/mutators/mutate.d.ts.map +1 -0
- package/dist/src/mutators/mutate.js +35 -0
- package/dist/src/mutators/mutate.js.map +1 -0
- package/dist/src/mutators/mutator-options.d.ts +5 -0
- package/dist/src/mutators/mutator-options.d.ts.map +1 -0
- package/dist/src/mutators/mutator-options.js +2 -0
- package/dist/src/mutators/mutator-options.js.map +1 -0
- package/dist/src/mutators/node-mutator.d.ts +6 -0
- package/dist/src/mutators/node-mutator.d.ts.map +1 -0
- package/dist/src/mutators/node-mutator.js +2 -0
- package/dist/src/mutators/node-mutator.js.map +1 -0
- package/dist/src/mutators/object-literal-mutator.d.ts +3 -0
- package/dist/src/mutators/object-literal-mutator.d.ts.map +1 -0
- package/dist/src/mutators/object-literal-mutator.js +11 -0
- package/dist/src/mutators/object-literal-mutator.js.map +1 -0
- package/dist/src/mutators/optional-chaining-mutator.d.ts +15 -0
- package/dist/src/mutators/optional-chaining-mutator.d.ts.map +1 -0
- package/dist/src/mutators/optional-chaining-mutator.js +28 -0
- package/dist/src/mutators/optional-chaining-mutator.js.map +1 -0
- package/dist/src/mutators/regex-mutator.d.ts +3 -0
- package/dist/src/mutators/regex-mutator.d.ts.map +1 -0
- package/dist/src/mutators/regex-mutator.js +53 -0
- package/dist/src/mutators/regex-mutator.js.map +1 -0
- package/dist/src/mutators/string-literal-mutator.d.ts +3 -0
- package/dist/src/mutators/string-literal-mutator.d.ts.map +1 -0
- package/dist/src/mutators/string-literal-mutator.js +36 -0
- package/dist/src/mutators/string-literal-mutator.js.map +1 -0
- package/dist/src/mutators/unary-operator-mutator.d.ts +3 -0
- package/dist/src/mutators/unary-operator-mutator.d.ts.map +1 -0
- package/dist/src/mutators/unary-operator-mutator.js +27 -0
- package/dist/src/mutators/unary-operator-mutator.js.map +1 -0
- package/dist/src/mutators/update-operator-mutator.d.ts +3 -0
- package/dist/src/mutators/update-operator-mutator.d.ts.map +1 -0
- package/dist/src/mutators/update-operator-mutator.js +17 -0
- package/dist/src/mutators/update-operator-mutator.js.map +1 -0
- package/dist/src/parsers/create-parser.d.ts +5 -0
- package/dist/src/parsers/create-parser.d.ts.map +1 -0
- package/dist/src/parsers/create-parser.js +58 -0
- package/dist/src/parsers/create-parser.js.map +1 -0
- package/dist/src/parsers/html-parser.d.ts +4 -0
- package/dist/src/parsers/html-parser.d.ts.map +1 -0
- package/dist/src/parsers/html-parser.js +96 -0
- package/dist/src/parsers/html-parser.js.map +1 -0
- package/dist/src/parsers/index.d.ts +5 -0
- package/dist/src/parsers/index.d.ts.map +1 -0
- package/dist/src/parsers/index.js +3 -0
- package/dist/src/parsers/index.js.map +1 -0
- package/dist/src/parsers/js-parser.d.ts +4 -0
- package/dist/src/parsers/js-parser.d.ts.map +1 -0
- package/dist/src/parsers/js-parser.js +50 -0
- package/dist/src/parsers/js-parser.js.map +1 -0
- package/dist/src/parsers/parse-error.d.ts +5 -0
- package/dist/src/parsers/parse-error.d.ts.map +1 -0
- package/dist/src/parsers/parse-error.js +6 -0
- package/dist/src/parsers/parse-error.js.map +1 -0
- package/dist/src/parsers/parser-context.d.ts +6 -0
- package/dist/src/parsers/parser-context.d.ts.map +1 -0
- package/dist/src/parsers/parser-context.js +2 -0
- package/dist/src/parsers/parser-context.js.map +1 -0
- package/dist/src/parsers/parser-options.d.ts +4 -0
- package/dist/src/parsers/parser-options.d.ts.map +1 -0
- package/dist/src/parsers/parser-options.js +2 -0
- package/dist/src/parsers/parser-options.js.map +1 -0
- package/dist/src/parsers/svelte-parser.d.ts +4 -0
- package/dist/src/parsers/svelte-parser.d.ts.map +1 -0
- package/dist/src/parsers/svelte-parser.js +169 -0
- package/dist/src/parsers/svelte-parser.js.map +1 -0
- package/dist/src/parsers/ts-parser.d.ts +9 -0
- package/dist/src/parsers/ts-parser.d.ts.map +1 -0
- package/dist/src/parsers/ts-parser.js +54 -0
- package/dist/src/parsers/ts-parser.js.map +1 -0
- package/dist/src/printers/html-printer.d.ts +4 -0
- package/dist/src/printers/html-printer.d.ts.map +1 -0
- package/dist/src/printers/html-printer.js +15 -0
- package/dist/src/printers/html-printer.js.map +1 -0
- package/dist/src/printers/index.d.ts +7 -0
- package/dist/src/printers/index.d.ts.map +1 -0
- package/dist/src/printers/index.js +23 -0
- package/dist/src/printers/index.js.map +1 -0
- package/dist/src/printers/js-printer.d.ts +4 -0
- package/dist/src/printers/js-printer.d.ts.map +1 -0
- package/dist/src/printers/js-printer.js +6 -0
- package/dist/src/printers/js-printer.js.map +1 -0
- package/dist/src/printers/svelte-printer.d.ts +4 -0
- package/dist/src/printers/svelte-printer.d.ts.map +1 -0
- package/dist/src/printers/svelte-printer.js +28 -0
- package/dist/src/printers/svelte-printer.js.map +1 -0
- package/dist/src/printers/ts-printer.d.ts +4 -0
- package/dist/src/printers/ts-printer.d.ts.map +1 -0
- package/dist/src/printers/ts-printer.js +9 -0
- package/dist/src/printers/ts-printer.js.map +1 -0
- package/dist/src/syntax/index.d.ts +86 -0
- package/dist/src/syntax/index.d.ts.map +1 -0
- package/dist/src/syntax/index.js +9 -0
- package/dist/src/syntax/index.js.map +1 -0
- package/dist/src/transformers/babel-transformer.d.ts +4 -0
- package/dist/src/transformers/babel-transformer.d.ts.map +1 -0
- package/dist/src/transformers/babel-transformer.js +142 -0
- package/dist/src/transformers/babel-transformer.js.map +1 -0
- package/dist/src/transformers/directive-bookkeeper.d.ts +19 -0
- package/dist/src/transformers/directive-bookkeeper.d.ts.map +1 -0
- package/dist/src/transformers/directive-bookkeeper.js +108 -0
- package/dist/src/transformers/directive-bookkeeper.js.map +1 -0
- package/dist/src/transformers/html-transformer.d.ts +4 -0
- package/dist/src/transformers/html-transformer.d.ts.map +1 -0
- package/dist/src/transformers/html-transformer.js +6 -0
- package/dist/src/transformers/html-transformer.js.map +1 -0
- package/dist/src/transformers/ignorer-bookkeeper.d.ts +18 -0
- package/dist/src/transformers/ignorer-bookkeeper.d.ts.map +1 -0
- package/dist/src/transformers/ignorer-bookkeeper.js +29 -0
- package/dist/src/transformers/ignorer-bookkeeper.js.map +1 -0
- package/dist/src/transformers/index.d.ts +6 -0
- package/dist/src/transformers/index.d.ts.map +1 -0
- package/dist/src/transformers/index.js +4 -0
- package/dist/src/transformers/index.js.map +1 -0
- package/dist/src/transformers/mutant-collector.d.ts +19 -0
- package/dist/src/transformers/mutant-collector.d.ts.map +1 -0
- package/dist/src/transformers/mutant-collector.js +25 -0
- package/dist/src/transformers/mutant-collector.js.map +1 -0
- package/dist/src/transformers/svelte-transformer.d.ts +4 -0
- package/dist/src/transformers/svelte-transformer.d.ts.map +1 -0
- package/dist/src/transformers/svelte-transformer.js +46 -0
- package/dist/src/transformers/svelte-transformer.js.map +1 -0
- package/dist/src/transformers/transformer-options.d.ts +6 -0
- package/dist/src/transformers/transformer-options.d.ts.map +1 -0
- package/dist/src/transformers/transformer-options.js +2 -0
- package/dist/src/transformers/transformer-options.js.map +1 -0
- package/dist/src/transformers/transformer.d.ts +22 -0
- package/dist/src/transformers/transformer.d.ts.map +1 -0
- package/dist/src/transformers/transformer.js +30 -0
- package/dist/src/transformers/transformer.js.map +1 -0
- package/dist/src/util/binary-operator.d.ts +2 -0
- package/dist/src/util/binary-operator.d.ts.map +1 -0
- package/dist/src/util/binary-operator.js +2 -0
- package/dist/src/util/binary-operator.js.map +1 -0
- package/dist/src/util/index.d.ts +4 -0
- package/dist/src/util/index.d.ts.map +1 -0
- package/dist/src/util/index.js +4 -0
- package/dist/src/util/index.js.map +1 -0
- package/dist/src/util/position-converter.d.ts +16 -0
- package/dist/src/util/position-converter.d.ts.map +1 -0
- package/dist/src/util/position-converter.js +126 -0
- package/dist/src/util/position-converter.js.map +1 -0
- package/dist/src/util/syntax-helpers.d.ts +60 -0
- package/dist/src/util/syntax-helpers.d.ts.map +1 -0
- package/dist/src/util/syntax-helpers.js +217 -0
- package/dist/src/util/syntax-helpers.js.map +1 -0
- package/package.json +64 -0
- package/src/create-instrumenter.ts +30 -0
- package/src/disable-type-checks.ts +153 -0
- package/src/file.ts +6 -0
- package/src/frameworks/angular-ignorer.ts +129 -0
- package/src/frameworks/index.ts +9 -0
- package/src/index.ts +8 -0
- package/src/instrument-result.ts +8 -0
- package/src/instrumenter-options.ts +5 -0
- package/src/instrumenter-tokens.ts +5 -0
- package/src/instrumenter.ts +100 -0
- package/src/mutant-placers/expression-mutant-placer.ts +210 -0
- package/src/mutant-placers/index.ts +12 -0
- package/src/mutant-placers/mutant-placer.ts +9 -0
- package/src/mutant-placers/statement-mutant-placer.ts +39 -0
- package/src/mutant-placers/switch-case-mutant-placer.ts +41 -0
- package/src/mutant-placers/throw-placement-error.ts +34 -0
- package/src/mutant.ts +101 -0
- package/src/mutators/arithmetic-operator-mutator.ts +51 -0
- package/src/mutators/array-declaration-mutator.ts +36 -0
- package/src/mutators/arrow-function-mutator.ts +22 -0
- package/src/mutators/assignment-operator-mutator.ts +59 -0
- package/src/mutators/block-statement-mutator.ts +89 -0
- package/src/mutators/boolean-literal-mutator.ts +24 -0
- package/src/mutators/conditional-expression-mutator.ts +92 -0
- package/src/mutators/equality-operator-mutator.ts +35 -0
- package/src/mutators/index.ts +3 -0
- package/src/mutators/logical-operator-mutator.ts +29 -0
- package/src/mutators/method-expression-mutator.ts +99 -0
- package/src/mutators/mutate.ts +36 -0
- package/src/mutators/mutator-options.ts +4 -0
- package/src/mutators/node-mutator.ts +6 -0
- package/src/mutators/object-literal-mutator.ts +15 -0
- package/src/mutators/optional-chaining-mutator.ts +39 -0
- package/src/mutators/regex-mutator.ts +69 -0
- package/src/mutators/string-literal-mutator.ts +49 -0
- package/src/mutators/unary-operator-mutator.ts +39 -0
- package/src/mutators/update-operator-mutator.ts +26 -0
- package/src/parsers/create-parser.ts +78 -0
- package/src/parsers/html-parser.ts +138 -0
- package/src/parsers/index.ts +5 -0
- package/src/parsers/js-parser.ts +58 -0
- package/src/parsers/parse-error.ts +9 -0
- package/src/parsers/parser-context.ts +15 -0
- package/src/parsers/parser-options.ts +3 -0
- package/src/parsers/svelte-parser.ts +255 -0
- package/src/parsers/ts-parser.ts +69 -0
- package/src/printers/html-printer.ts +20 -0
- package/src/printers/index.ts +33 -0
- package/src/printers/js-printer.ts +11 -0
- package/src/printers/svelte-printer.ts +34 -0
- package/src/printers/ts-printer.ts +14 -0
- package/src/syntax/index.ts +97 -0
- package/src/transformers/babel-transformer.ts +217 -0
- package/src/transformers/directive-bookkeeper.ts +173 -0
- package/src/transformers/html-transformer.ts +13 -0
- package/src/transformers/ignorer-bookkeeper.ts +41 -0
- package/src/transformers/index.ts +6 -0
- package/src/transformers/mutant-collector.ts +44 -0
- package/src/transformers/svelte-transformer.ts +57 -0
- package/src/transformers/transformer-options.ts +7 -0
- package/src/transformers/transformer.ts +54 -0
- package/src/util/binary-operator.ts +23 -0
- package/src/util/index.ts +3 -0
- package/src/util/position-converter.ts +145 -0
- package/src/util/syntax-helpers.ts +301 -0
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
import babel, { type NodePath, type types } from '@babel/core';
|
|
2
|
+
|
|
3
|
+
// @ts-expect-error The babel types don't define "File" yet
|
|
4
|
+
import { File } from '@babel/core';
|
|
5
|
+
|
|
6
|
+
import {
|
|
7
|
+
isImportDeclaration,
|
|
8
|
+
isTypeNode,
|
|
9
|
+
locationIncluded,
|
|
10
|
+
locationOverlaps,
|
|
11
|
+
placeHeaderIfNeeded,
|
|
12
|
+
} from '../util/syntax-helpers.js';
|
|
13
|
+
import { ScriptFormat } from '../syntax/index.js';
|
|
14
|
+
import {
|
|
15
|
+
allMutantPlacers,
|
|
16
|
+
MutantPlacer,
|
|
17
|
+
throwPlacementError,
|
|
18
|
+
} from '../mutant-placers/index.js';
|
|
19
|
+
import { Mutable, Mutant } from '../mutant.js';
|
|
20
|
+
import { allMutators } from '../mutators/index.js';
|
|
21
|
+
|
|
22
|
+
import { DirectiveBookkeeper } from './directive-bookkeeper.js';
|
|
23
|
+
import { IgnorerBookkeeper } from './ignorer-bookkeeper.js';
|
|
24
|
+
|
|
25
|
+
import { AstTransformer } from './index.js';
|
|
26
|
+
|
|
27
|
+
const { traverse } = babel;
|
|
28
|
+
|
|
29
|
+
interface MutantsPlacement<TNode extends types.Node> {
|
|
30
|
+
appliedMutants: Map<Mutant, TNode>;
|
|
31
|
+
placer: MutantPlacer<TNode>;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
type PlacementMap = Map<types.Node, MutantsPlacement<types.Node>>;
|
|
35
|
+
|
|
36
|
+
export const transformBabel: AstTransformer<ScriptFormat> = (
|
|
37
|
+
{ root, originFileName, rawContent, offset },
|
|
38
|
+
mutantCollector,
|
|
39
|
+
{ options, mutateDescription, logger },
|
|
40
|
+
mutators = allMutators,
|
|
41
|
+
mutantPlacers = allMutantPlacers,
|
|
42
|
+
) => {
|
|
43
|
+
// Wrap the AST in a `new File`, so `nodePath.buildCodeFrameError` works
|
|
44
|
+
// https://github.com/babel/babel/issues/11889
|
|
45
|
+
const file = new File(
|
|
46
|
+
{ filename: originFileName },
|
|
47
|
+
{ code: rawContent, ast: root },
|
|
48
|
+
);
|
|
49
|
+
|
|
50
|
+
// Create a placementMap for the mutation switching bookkeeping
|
|
51
|
+
const placementMap: PlacementMap = new Map();
|
|
52
|
+
|
|
53
|
+
// Create the bookkeeper responsible for the // Stryker ... directives
|
|
54
|
+
const directiveBookkeeper = new DirectiveBookkeeper(
|
|
55
|
+
logger,
|
|
56
|
+
mutators,
|
|
57
|
+
originFileName,
|
|
58
|
+
);
|
|
59
|
+
|
|
60
|
+
// The ignorer bookkeeper is responsible for keeping track of the ignored node and the reason why it is ignored
|
|
61
|
+
const ignorerBookkeeper = new IgnorerBookkeeper(options.ignorers);
|
|
62
|
+
|
|
63
|
+
// Now start the actual traversing of the AST
|
|
64
|
+
//
|
|
65
|
+
// On the way down:
|
|
66
|
+
// * Treat the tree as immutable.
|
|
67
|
+
// * Identify the nodes that can be used to place mutants on in the placement map.
|
|
68
|
+
// * Generate the mutants on each node.
|
|
69
|
+
// * When a node generated mutants, do a short walk back up and register them in the placement map
|
|
70
|
+
// * Call the `applied` method using the placement node, that way the mutant will capture the AST with mutation all the way to the placement node
|
|
71
|
+
//
|
|
72
|
+
// On the way up:
|
|
73
|
+
// * If this node has mutants in the placementMap, place them in the AST.
|
|
74
|
+
//
|
|
75
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
|
76
|
+
traverse(file.ast, {
|
|
77
|
+
enter(path) {
|
|
78
|
+
directiveBookkeeper.processStrykerDirectives(path.node);
|
|
79
|
+
if (shouldSkip(path)) {
|
|
80
|
+
path.skip();
|
|
81
|
+
} else {
|
|
82
|
+
ignorerBookkeeper.enterNode(path);
|
|
83
|
+
addToPlacementMapIfPossible(path);
|
|
84
|
+
if (shouldMutate(path)) {
|
|
85
|
+
const mutantsToPlace = collectMutants(path);
|
|
86
|
+
if (mutantsToPlace.length) {
|
|
87
|
+
registerInPlacementMap(path, mutantsToPlace);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
},
|
|
92
|
+
exit(path) {
|
|
93
|
+
placeMutantsIfNeeded(path);
|
|
94
|
+
ignorerBookkeeper.leaveNode(path);
|
|
95
|
+
},
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
placeHeaderIfNeeded(mutantCollector, originFileName, options, root);
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* If mutants were collected, be sure to register them in the placement map.
|
|
102
|
+
*/
|
|
103
|
+
function registerInPlacementMap(path: NodePath, mutantsToPlace: Mutant[]) {
|
|
104
|
+
const placementPath = path.find((ancestor) =>
|
|
105
|
+
placementMap.has(ancestor.node),
|
|
106
|
+
);
|
|
107
|
+
if (placementPath) {
|
|
108
|
+
const { appliedMutants } = placementMap.get(placementPath.node)!;
|
|
109
|
+
mutantsToPlace.forEach((mutant) =>
|
|
110
|
+
appliedMutants.set(mutant, mutant.applied(placementPath.node)),
|
|
111
|
+
);
|
|
112
|
+
} else {
|
|
113
|
+
throw new Error(
|
|
114
|
+
`Mutants cannot be placed. This shouldn't happen! Unplaced mutants: ${JSON.stringify(mutantsToPlace, null, 2)}`,
|
|
115
|
+
);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* If this node can be used to place mutants on, add to the placement map
|
|
121
|
+
*/
|
|
122
|
+
function addToPlacementMapIfPossible(path: NodePath) {
|
|
123
|
+
const placer = mutantPlacers.find((p) => p.canPlace(path));
|
|
124
|
+
if (placer) {
|
|
125
|
+
placementMap.set(path.node, { appliedMutants: new Map(), placer });
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Don't traverse import declarations, decorators and nodes that don't have overlap with the selected mutation ranges
|
|
131
|
+
*/
|
|
132
|
+
function shouldSkip(path: NodePath) {
|
|
133
|
+
return (
|
|
134
|
+
isTypeNode(path) ||
|
|
135
|
+
isImportDeclaration(path) ||
|
|
136
|
+
path.isDecorator() ||
|
|
137
|
+
!mutateDescription ||
|
|
138
|
+
(Array.isArray(mutateDescription) &&
|
|
139
|
+
mutateDescription.every(
|
|
140
|
+
(range) => !locationOverlaps(range, path.node.loc!),
|
|
141
|
+
))
|
|
142
|
+
);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
function shouldMutate(path: NodePath) {
|
|
146
|
+
return (
|
|
147
|
+
mutateDescription === true ||
|
|
148
|
+
(Array.isArray(mutateDescription) &&
|
|
149
|
+
mutateDescription.some((range) =>
|
|
150
|
+
locationIncluded(range, path.node.loc!),
|
|
151
|
+
))
|
|
152
|
+
);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Place mutants that are assigned to the current node path (on exit)
|
|
157
|
+
*/
|
|
158
|
+
function placeMutantsIfNeeded(path: NodePath) {
|
|
159
|
+
const mutantsPlacement = placementMap.get(path.node);
|
|
160
|
+
if (mutantsPlacement?.appliedMutants.size) {
|
|
161
|
+
try {
|
|
162
|
+
mutantsPlacement.placer.place(path, mutantsPlacement.appliedMutants);
|
|
163
|
+
path.skip();
|
|
164
|
+
} catch (error) {
|
|
165
|
+
throwPlacementError(
|
|
166
|
+
error as Error,
|
|
167
|
+
path,
|
|
168
|
+
mutantsPlacement.placer,
|
|
169
|
+
[...mutantsPlacement.appliedMutants.keys()],
|
|
170
|
+
originFileName,
|
|
171
|
+
);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* Collect the mutants for the current node and return the non-ignored.
|
|
178
|
+
*/
|
|
179
|
+
function collectMutants(path: NodePath) {
|
|
180
|
+
return [...mutate(path)]
|
|
181
|
+
.map((mutable) =>
|
|
182
|
+
mutantCollector.collect(originFileName, path.node, mutable, offset),
|
|
183
|
+
)
|
|
184
|
+
.filter((mutant) => !mutant.ignoreReason);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Generate mutants for the current node.
|
|
189
|
+
*/
|
|
190
|
+
function* mutate(node: NodePath): Iterable<Mutable> {
|
|
191
|
+
for (const mutator of mutators) {
|
|
192
|
+
for (const replacement of mutator.mutate(node)) {
|
|
193
|
+
yield {
|
|
194
|
+
replacement,
|
|
195
|
+
mutatorName: mutator.name,
|
|
196
|
+
ignoreReason:
|
|
197
|
+
directiveBookkeeper.findIgnoreReason(
|
|
198
|
+
node.node.loc!.start.line,
|
|
199
|
+
mutator.name,
|
|
200
|
+
) ??
|
|
201
|
+
findExcludedMutatorIgnoreReason(mutator.name) ??
|
|
202
|
+
ignorerBookkeeper.currentIgnoreMessage,
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
function findExcludedMutatorIgnoreReason(
|
|
208
|
+
mutatorName: string,
|
|
209
|
+
): string | undefined {
|
|
210
|
+
if (options.excludedMutations.includes(mutatorName)) {
|
|
211
|
+
return `Ignored because of excluded mutation "${mutatorName}"`;
|
|
212
|
+
} else {
|
|
213
|
+
return undefined;
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
};
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
import type { types } from '@babel/core';
|
|
2
|
+
import { notEmpty } from '@stryker-mutator/util';
|
|
3
|
+
|
|
4
|
+
import { Logger } from '@stryker-mutator/api/logging';
|
|
5
|
+
|
|
6
|
+
import { NodeMutator } from '../mutators/node-mutator.js';
|
|
7
|
+
|
|
8
|
+
const WILDCARD = 'all';
|
|
9
|
+
const DEFAULT_REASON = 'Ignored using a comment';
|
|
10
|
+
|
|
11
|
+
type IgnoreReason = string | undefined;
|
|
12
|
+
|
|
13
|
+
interface Rule {
|
|
14
|
+
findIgnoreReason(mutatorName: string, line: number): IgnoreReason;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
class IgnoreRule implements Rule {
|
|
18
|
+
constructor(
|
|
19
|
+
public mutatorNames: string[],
|
|
20
|
+
public line: number | undefined,
|
|
21
|
+
public ignoreReason: IgnoreReason,
|
|
22
|
+
public previousRule: Rule,
|
|
23
|
+
) {}
|
|
24
|
+
|
|
25
|
+
private matches(mutatorName: string, line: number): boolean {
|
|
26
|
+
const lineMatches = () => this.line === undefined || this.line === line;
|
|
27
|
+
const mutatorMatches = () =>
|
|
28
|
+
this.mutatorNames.includes(mutatorName) ||
|
|
29
|
+
this.mutatorNames.includes(WILDCARD);
|
|
30
|
+
return lineMatches() && mutatorMatches();
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
public findIgnoreReason(mutatorName: string, line: number): IgnoreReason {
|
|
34
|
+
if (this.matches(mutatorName, line)) {
|
|
35
|
+
return this.ignoreReason;
|
|
36
|
+
}
|
|
37
|
+
return this.previousRule.findIgnoreReason(mutatorName, line);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
class RestoreRule extends IgnoreRule {
|
|
42
|
+
constructor(
|
|
43
|
+
mutatorNames: string[],
|
|
44
|
+
line: number | undefined,
|
|
45
|
+
previousRule: Rule,
|
|
46
|
+
) {
|
|
47
|
+
super(mutatorNames, line, undefined, previousRule);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const rootRule: Rule = {
|
|
52
|
+
findIgnoreReason() {
|
|
53
|
+
return undefined;
|
|
54
|
+
},
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Responsible for the bookkeeping of "// Stryker" directives like "disable" and "restore".
|
|
59
|
+
*/
|
|
60
|
+
export class DirectiveBookkeeper {
|
|
61
|
+
// https://regex101.com/r/nWLLLm/1
|
|
62
|
+
private readonly strykerCommentDirectiveRegex =
|
|
63
|
+
/^\s?Stryker (disable|restore)(?: (next-line))? ([a-zA-Z, ]+)(?::(.+)?)?/;
|
|
64
|
+
|
|
65
|
+
private currentIgnoreRule = rootRule;
|
|
66
|
+
private readonly allMutatorNames: string[];
|
|
67
|
+
|
|
68
|
+
constructor(
|
|
69
|
+
private readonly logger: Logger,
|
|
70
|
+
private readonly allMutators: NodeMutator[],
|
|
71
|
+
private readonly originFileName: string,
|
|
72
|
+
) {
|
|
73
|
+
this.allMutatorNames = this.allMutators.map((x) => x.name.toLowerCase());
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
public processStrykerDirectives({ loc, leadingComments }: types.Node): void {
|
|
77
|
+
leadingComments
|
|
78
|
+
?.map((comment) => ({
|
|
79
|
+
comment,
|
|
80
|
+
matchResult: this.strykerCommentDirectiveRegex.exec(comment.value) as
|
|
81
|
+
| [
|
|
82
|
+
fullMatch: string,
|
|
83
|
+
directiveType: string,
|
|
84
|
+
scope: string | undefined,
|
|
85
|
+
mutators: string,
|
|
86
|
+
reason: string | undefined,
|
|
87
|
+
]
|
|
88
|
+
| null,
|
|
89
|
+
}))
|
|
90
|
+
.filter(({ matchResult }) => notEmpty(matchResult))
|
|
91
|
+
.forEach(({ comment, matchResult }) => {
|
|
92
|
+
const [, directiveType, scope, mutators, optionalReason] = matchResult!;
|
|
93
|
+
let mutatorNames = mutators.split(',').map((mutator) => mutator.trim());
|
|
94
|
+
this.warnAboutUnusedDirective(
|
|
95
|
+
mutatorNames,
|
|
96
|
+
directiveType,
|
|
97
|
+
scope,
|
|
98
|
+
comment,
|
|
99
|
+
);
|
|
100
|
+
mutatorNames = mutatorNames.map((mutator) => mutator.toLowerCase());
|
|
101
|
+
const reason = (optionalReason ?? DEFAULT_REASON).trim();
|
|
102
|
+
switch (directiveType) {
|
|
103
|
+
case 'disable':
|
|
104
|
+
switch (scope) {
|
|
105
|
+
case 'next-line':
|
|
106
|
+
this.currentIgnoreRule = new IgnoreRule(
|
|
107
|
+
mutatorNames,
|
|
108
|
+
loc!.start.line,
|
|
109
|
+
reason,
|
|
110
|
+
this.currentIgnoreRule,
|
|
111
|
+
);
|
|
112
|
+
break;
|
|
113
|
+
default:
|
|
114
|
+
this.currentIgnoreRule = new IgnoreRule(
|
|
115
|
+
mutatorNames,
|
|
116
|
+
undefined,
|
|
117
|
+
reason,
|
|
118
|
+
this.currentIgnoreRule,
|
|
119
|
+
);
|
|
120
|
+
break;
|
|
121
|
+
}
|
|
122
|
+
break;
|
|
123
|
+
case 'restore':
|
|
124
|
+
switch (scope) {
|
|
125
|
+
case 'next-line':
|
|
126
|
+
this.currentIgnoreRule = new RestoreRule(
|
|
127
|
+
mutatorNames,
|
|
128
|
+
loc!.start.line,
|
|
129
|
+
this.currentIgnoreRule,
|
|
130
|
+
);
|
|
131
|
+
break;
|
|
132
|
+
default:
|
|
133
|
+
this.currentIgnoreRule = new RestoreRule(
|
|
134
|
+
mutatorNames,
|
|
135
|
+
undefined,
|
|
136
|
+
this.currentIgnoreRule,
|
|
137
|
+
);
|
|
138
|
+
break;
|
|
139
|
+
}
|
|
140
|
+
break;
|
|
141
|
+
}
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
public findIgnoreReason(
|
|
146
|
+
line: number,
|
|
147
|
+
mutatorName: string,
|
|
148
|
+
): string | undefined {
|
|
149
|
+
mutatorName = mutatorName.toLowerCase();
|
|
150
|
+
return this.currentIgnoreRule.findIgnoreReason(mutatorName, line);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
private warnAboutUnusedDirective(
|
|
154
|
+
mutators: string[],
|
|
155
|
+
directiveType: string,
|
|
156
|
+
scope: string | undefined,
|
|
157
|
+
comment: types.Comment,
|
|
158
|
+
) {
|
|
159
|
+
for (const mutator of mutators) {
|
|
160
|
+
if (mutator === WILDCARD) continue;
|
|
161
|
+
if (!this.allMutatorNames.includes(mutator.toLowerCase())) {
|
|
162
|
+
this.logger.warn(
|
|
163
|
+
// Scope can be global and therefore undefined
|
|
164
|
+
`Unused 'Stryker ${
|
|
165
|
+
scope ? directiveType + ' ' + scope : directiveType
|
|
166
|
+
}' directive. Mutator with name '${mutator}' not found. Directive found at: ${this.originFileName}:${comment.loc!.start.line}:${
|
|
167
|
+
comment.loc!.start.column
|
|
168
|
+
}.`,
|
|
169
|
+
);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { AstFormat } from '../syntax/index.js';
|
|
2
|
+
|
|
3
|
+
import { AstTransformer } from './index.js';
|
|
4
|
+
|
|
5
|
+
export const transformHtml: AstTransformer<AstFormat.Html> = (
|
|
6
|
+
{ root },
|
|
7
|
+
mutantCollector,
|
|
8
|
+
context,
|
|
9
|
+
) => {
|
|
10
|
+
root.scripts.forEach((ast) => {
|
|
11
|
+
context.transform(ast, mutantCollector, context);
|
|
12
|
+
});
|
|
13
|
+
};
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { types, NodePath as BabelNodePath } from '@babel/core';
|
|
2
|
+
|
|
3
|
+
import type { Ignorer } from '@stryker-mutator/api/ignore';
|
|
4
|
+
|
|
5
|
+
declare module '@stryker-mutator/api/ignore' {
|
|
6
|
+
// eslint-disable-next-line @typescript-eslint/no-empty-object-type
|
|
7
|
+
interface NodePath extends BabelNodePath {}
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Responsible for keeping track of the active ignore message and node using the configured ignore-plugins.
|
|
12
|
+
*/
|
|
13
|
+
export class IgnorerBookkeeper {
|
|
14
|
+
private readonly ignorers;
|
|
15
|
+
private activeIgnored?: { node: types.Node; message: string };
|
|
16
|
+
|
|
17
|
+
public get currentIgnoreMessage(): string | undefined {
|
|
18
|
+
return this.activeIgnored?.message;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
constructor(ignorers: Ignorer[]) {
|
|
22
|
+
this.ignorers = ignorers;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
public enterNode(path: BabelNodePath): void {
|
|
26
|
+
if (!this.activeIgnored) {
|
|
27
|
+
this.ignorers.forEach((ignorer) => {
|
|
28
|
+
const message = ignorer.shouldIgnore(path);
|
|
29
|
+
if (message) {
|
|
30
|
+
this.activeIgnored = { node: path.node, message };
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
public leaveNode(path: BabelNodePath): void {
|
|
37
|
+
if (this.activeIgnored?.node === path.node) {
|
|
38
|
+
this.activeIgnored = undefined;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import type { types } from '@babel/core';
|
|
2
|
+
import { Position } from '@stryker-mutator/api/core';
|
|
3
|
+
|
|
4
|
+
import { Mutant, Mutable } from '../mutant.js';
|
|
5
|
+
|
|
6
|
+
export class MutantCollector {
|
|
7
|
+
private readonly _mutants: Mutant[] = [];
|
|
8
|
+
|
|
9
|
+
public get mutants(): readonly Mutant[] {
|
|
10
|
+
return this._mutants;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Adds mutants to the internal mutant list.
|
|
15
|
+
* @param fileName file name that houses the mutant
|
|
16
|
+
* @param original The node to mutate
|
|
17
|
+
* @param mutables the named node mutation to be added
|
|
18
|
+
* @param contextPath the context where these mutants are found and should be placed as close by as possible
|
|
19
|
+
* @param offset offset of mutant nodes
|
|
20
|
+
* @returns The mutant (for testability)
|
|
21
|
+
*/
|
|
22
|
+
public collect(
|
|
23
|
+
fileName: string,
|
|
24
|
+
original: types.Node,
|
|
25
|
+
mutable: Mutable,
|
|
26
|
+
offset: Position = { line: 0, column: 0 },
|
|
27
|
+
): Mutant {
|
|
28
|
+
const mutant = new Mutant(
|
|
29
|
+
this._mutants.length.toString(),
|
|
30
|
+
fileName,
|
|
31
|
+
original,
|
|
32
|
+
mutable,
|
|
33
|
+
offset,
|
|
34
|
+
);
|
|
35
|
+
this._mutants.push(mutant);
|
|
36
|
+
return mutant;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
public hasPlacedMutants(fileName: string): boolean {
|
|
40
|
+
return this.mutants.some(
|
|
41
|
+
(mutant) => mutant.fileName === fileName && !mutant.ignoreReason,
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { notEmpty } from '@stryker-mutator/util';
|
|
2
|
+
|
|
3
|
+
import { types } from '@babel/core';
|
|
4
|
+
|
|
5
|
+
import { AstFormat } from '../syntax/index.js';
|
|
6
|
+
import { placeHeader } from '../util/syntax-helpers.js';
|
|
7
|
+
|
|
8
|
+
import { AstTransformer } from './transformer.js';
|
|
9
|
+
|
|
10
|
+
const moduleScriptStart = '<script context="module">\n';
|
|
11
|
+
const moduleScript = `${moduleScriptStart}\n</script>\n`;
|
|
12
|
+
|
|
13
|
+
export const transformSvelte: AstTransformer<AstFormat.Svelte> = (
|
|
14
|
+
svelte,
|
|
15
|
+
mutantCollector,
|
|
16
|
+
context,
|
|
17
|
+
) => {
|
|
18
|
+
const { root, originFileName } = svelte;
|
|
19
|
+
[root.moduleScript, ...root.additionalScripts]
|
|
20
|
+
.filter(notEmpty)
|
|
21
|
+
.forEach((script) => {
|
|
22
|
+
context.transform(script.ast, mutantCollector, {
|
|
23
|
+
...context,
|
|
24
|
+
options: {
|
|
25
|
+
...context.options,
|
|
26
|
+
noHeader: true,
|
|
27
|
+
},
|
|
28
|
+
});
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
if (mutantCollector.hasPlacedMutants(originFileName)) {
|
|
32
|
+
// We need to place the instrumentation header inside the `<script context="module">` script
|
|
33
|
+
// If there already is a module script, place it there. If not, we need to add it.
|
|
34
|
+
|
|
35
|
+
if (!root.moduleScript) {
|
|
36
|
+
root.moduleScript = {
|
|
37
|
+
ast: {
|
|
38
|
+
format: AstFormat.JS,
|
|
39
|
+
root: types.file(types.program([])),
|
|
40
|
+
rawContent: '',
|
|
41
|
+
originFileName,
|
|
42
|
+
},
|
|
43
|
+
range: {
|
|
44
|
+
start: moduleScriptStart.length,
|
|
45
|
+
end: moduleScriptStart.length,
|
|
46
|
+
},
|
|
47
|
+
isExpression: false,
|
|
48
|
+
};
|
|
49
|
+
svelte.rawContent = `${moduleScript}${svelte.rawContent}`;
|
|
50
|
+
svelte.root.additionalScripts.forEach((script) => {
|
|
51
|
+
script.range.start += moduleScript.length;
|
|
52
|
+
script.range.end += moduleScript.length;
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
placeHeader(root.moduleScript.ast.root);
|
|
56
|
+
}
|
|
57
|
+
};
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { MutateDescription } from '@stryker-mutator/api/core';
|
|
2
|
+
import { I } from '@stryker-mutator/util';
|
|
3
|
+
import { Logger } from '@stryker-mutator/api/logging';
|
|
4
|
+
|
|
5
|
+
import { Ast, AstByFormat, AstFormat } from '../syntax/index.js';
|
|
6
|
+
|
|
7
|
+
import { TransformerOptions } from './transformer-options.js';
|
|
8
|
+
import { transformBabel } from './babel-transformer.js';
|
|
9
|
+
import { transformHtml } from './html-transformer.js';
|
|
10
|
+
import { MutantCollector } from './mutant-collector.js';
|
|
11
|
+
import { transformSvelte } from './svelte-transformer.js';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Transform the AST by generating mutants and placing them in the AST.
|
|
15
|
+
* Supports all AST formats supported by Stryker.
|
|
16
|
+
* @param ast The Abstract Syntax Tree
|
|
17
|
+
* @param mutantCollector the mutant collector that will be used to register and administer mutants
|
|
18
|
+
* @param transformerContext the options used during transforming
|
|
19
|
+
*/
|
|
20
|
+
export function transform(
|
|
21
|
+
ast: Ast,
|
|
22
|
+
mutantCollector: I<MutantCollector>,
|
|
23
|
+
transformerContext: Omit<TransformerContext, 'transform'>,
|
|
24
|
+
): void {
|
|
25
|
+
const context: TransformerContext = {
|
|
26
|
+
...transformerContext,
|
|
27
|
+
transform,
|
|
28
|
+
};
|
|
29
|
+
switch (ast.format) {
|
|
30
|
+
case AstFormat.Html:
|
|
31
|
+
transformHtml(ast, mutantCollector, context);
|
|
32
|
+
break;
|
|
33
|
+
case AstFormat.JS:
|
|
34
|
+
case AstFormat.TS:
|
|
35
|
+
case AstFormat.Tsx:
|
|
36
|
+
transformBabel(ast, mutantCollector, context);
|
|
37
|
+
break;
|
|
38
|
+
case AstFormat.Svelte:
|
|
39
|
+
transformSvelte(ast, mutantCollector, context);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export type AstTransformer<T extends AstFormat> = (
|
|
44
|
+
ast: AstByFormat[T],
|
|
45
|
+
mutantCollector: I<MutantCollector>,
|
|
46
|
+
context: TransformerContext,
|
|
47
|
+
) => void;
|
|
48
|
+
|
|
49
|
+
export interface TransformerContext {
|
|
50
|
+
transform: AstTransformer<AstFormat>;
|
|
51
|
+
options: TransformerOptions;
|
|
52
|
+
mutateDescription: MutateDescription;
|
|
53
|
+
logger: Logger;
|
|
54
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export type BinaryOperator =
|
|
2
|
+
| '-'
|
|
3
|
+
| '!='
|
|
4
|
+
| '!=='
|
|
5
|
+
| '*'
|
|
6
|
+
| '**'
|
|
7
|
+
| '/'
|
|
8
|
+
| '&'
|
|
9
|
+
| '%'
|
|
10
|
+
| '^'
|
|
11
|
+
| '+'
|
|
12
|
+
| '<'
|
|
13
|
+
| '<<'
|
|
14
|
+
| '<='
|
|
15
|
+
| '=='
|
|
16
|
+
| '==='
|
|
17
|
+
| '>'
|
|
18
|
+
| '>='
|
|
19
|
+
| '>>'
|
|
20
|
+
| '>>>'
|
|
21
|
+
| '|'
|
|
22
|
+
| 'in'
|
|
23
|
+
| 'instanceof';
|