@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.
Files changed (327) hide show
  1. package/LICENSE +201 -0
  2. package/dist/src/create-instrumenter.d.ts +16 -0
  3. package/dist/src/create-instrumenter.d.ts.map +1 -0
  4. package/dist/src/create-instrumenter.js +15 -0
  5. package/dist/src/create-instrumenter.js.map +1 -0
  6. package/dist/src/disable-type-checks.d.ts +11 -0
  7. package/dist/src/disable-type-checks.d.ts.map +1 -0
  8. package/dist/src/disable-type-checks.js +125 -0
  9. package/dist/src/disable-type-checks.js.map +1 -0
  10. package/dist/src/file.d.ts +6 -0
  11. package/dist/src/file.d.ts.map +1 -0
  12. package/dist/src/file.js +2 -0
  13. package/dist/src/file.js.map +1 -0
  14. package/dist/src/frameworks/angular-ignorer.d.ts +16 -0
  15. package/dist/src/frameworks/angular-ignorer.d.ts.map +1 -0
  16. package/dist/src/frameworks/angular-ignorer.js +85 -0
  17. package/dist/src/frameworks/angular-ignorer.js.map +1 -0
  18. package/dist/src/frameworks/index.d.ts +4 -0
  19. package/dist/src/frameworks/index.d.ts.map +1 -0
  20. package/dist/src/frameworks/index.js +7 -0
  21. package/dist/src/frameworks/index.js.map +1 -0
  22. package/dist/src/index.d.ts +9 -0
  23. package/dist/src/index.d.ts.map +1 -0
  24. package/dist/src/index.js +8 -0
  25. package/dist/src/index.js.map +1 -0
  26. package/dist/src/instrument-result.d.ts +7 -0
  27. package/dist/src/instrument-result.d.ts.map +1 -0
  28. package/dist/src/instrument-result.js +2 -0
  29. package/dist/src/instrument-result.js.map +1 -0
  30. package/dist/src/instrumenter-options.d.ts +5 -0
  31. package/dist/src/instrumenter-options.d.ts.map +1 -0
  32. package/dist/src/instrumenter-options.js +2 -0
  33. package/dist/src/instrumenter-options.js.map +1 -0
  34. package/dist/src/instrumenter-tokens.d.ts +6 -0
  35. package/dist/src/instrumenter-tokens.d.ts.map +1 -0
  36. package/dist/src/instrumenter-tokens.js +6 -0
  37. package/dist/src/instrumenter-tokens.js.map +1 -0
  38. package/dist/src/instrumenter.d.ts +24 -0
  39. package/dist/src/instrumenter.d.ts.map +1 -0
  40. package/dist/src/instrumenter.js +76 -0
  41. package/dist/src/instrumenter.js.map +1 -0
  42. package/dist/src/mutant-placers/expression-mutant-placer.d.ts +10 -0
  43. package/dist/src/mutant-placers/expression-mutant-placer.d.ts.map +1 -0
  44. package/dist/src/mutant-placers/expression-mutant-placer.js +144 -0
  45. package/dist/src/mutant-placers/expression-mutant-placer.js.map +1 -0
  46. package/dist/src/mutant-placers/index.d.ts +5 -0
  47. package/dist/src/mutant-placers/index.d.ts.map +1 -0
  48. package/dist/src/mutant-placers/index.js +11 -0
  49. package/dist/src/mutant-placers/index.js.map +1 -0
  50. package/dist/src/mutant-placers/mutant-placer.d.ts +8 -0
  51. package/dist/src/mutant-placers/mutant-placer.d.ts.map +1 -0
  52. package/dist/src/mutant-placers/mutant-placer.js +2 -0
  53. package/dist/src/mutant-placers/mutant-placer.js.map +1 -0
  54. package/dist/src/mutant-placers/statement-mutant-placer.d.ts +8 -0
  55. package/dist/src/mutant-placers/statement-mutant-placer.d.ts.map +1 -0
  56. package/dist/src/mutant-placers/statement-mutant-placer.js +24 -0
  57. package/dist/src/mutant-placers/statement-mutant-placer.js.map +1 -0
  58. package/dist/src/mutant-placers/switch-case-mutant-placer.d.ts +14 -0
  59. package/dist/src/mutant-placers/switch-case-mutant-placer.d.ts.map +1 -0
  60. package/dist/src/mutant-placers/switch-case-mutant-placer.js +29 -0
  61. package/dist/src/mutant-placers/switch-case-mutant-placer.js.map +1 -0
  62. package/dist/src/mutant-placers/throw-placement-error.d.ts +5 -0
  63. package/dist/src/mutant-placers/throw-placement-error.d.ts.map +1 -0
  64. package/dist/src/mutant-placers/throw-placement-error.js +17 -0
  65. package/dist/src/mutant-placers/throw-placement-error.js.map +1 -0
  66. package/dist/src/mutant.d.ts +27 -0
  67. package/dist/src/mutant.d.ts.map +1 -0
  68. package/dist/src/mutant.js +80 -0
  69. package/dist/src/mutant.js.map +1 -0
  70. package/dist/src/mutators/arithmetic-operator-mutator.d.ts +3 -0
  71. package/dist/src/mutators/arithmetic-operator-mutator.d.ts.map +1 -0
  72. package/dist/src/mutators/arithmetic-operator-mutator.js +34 -0
  73. package/dist/src/mutators/arithmetic-operator-mutator.js.map +1 -0
  74. package/dist/src/mutators/array-declaration-mutator.d.ts +3 -0
  75. package/dist/src/mutators/array-declaration-mutator.d.ts.map +1 -0
  76. package/dist/src/mutators/array-declaration-mutator.js +26 -0
  77. package/dist/src/mutators/array-declaration-mutator.js.map +1 -0
  78. package/dist/src/mutators/arrow-function-mutator.d.ts +3 -0
  79. package/dist/src/mutators/arrow-function-mutator.d.ts.map +1 -0
  80. package/dist/src/mutators/arrow-function-mutator.js +14 -0
  81. package/dist/src/mutators/arrow-function-mutator.js.map +1 -0
  82. package/dist/src/mutators/assignment-operator-mutator.d.ts +3 -0
  83. package/dist/src/mutators/assignment-operator-mutator.d.ts.map +1 -0
  84. package/dist/src/mutators/assignment-operator-mutator.js +42 -0
  85. package/dist/src/mutators/assignment-operator-mutator.js.map +1 -0
  86. package/dist/src/mutators/block-statement-mutator.d.ts +3 -0
  87. package/dist/src/mutators/block-statement-mutator.d.ts.map +1 -0
  88. package/dist/src/mutators/block-statement-mutator.js +63 -0
  89. package/dist/src/mutators/block-statement-mutator.js.map +1 -0
  90. package/dist/src/mutators/boolean-literal-mutator.d.ts +3 -0
  91. package/dist/src/mutators/boolean-literal-mutator.d.ts.map +1 -0
  92. package/dist/src/mutators/boolean-literal-mutator.js +17 -0
  93. package/dist/src/mutators/boolean-literal-mutator.js.map +1 -0
  94. package/dist/src/mutators/conditional-expression-mutator.d.ts +3 -0
  95. package/dist/src/mutators/conditional-expression-mutator.d.ts.map +1 -0
  96. package/dist/src/mutators/conditional-expression-mutator.js +81 -0
  97. package/dist/src/mutators/conditional-expression-mutator.js.map +1 -0
  98. package/dist/src/mutators/equality-operator-mutator.d.ts +3 -0
  99. package/dist/src/mutators/equality-operator-mutator.d.ts.map +1 -0
  100. package/dist/src/mutators/equality-operator-mutator.js +28 -0
  101. package/dist/src/mutators/equality-operator-mutator.js.map +1 -0
  102. package/dist/src/mutators/index.d.ts +4 -0
  103. package/dist/src/mutators/index.d.ts.map +1 -0
  104. package/dist/src/mutators/index.js +4 -0
  105. package/dist/src/mutators/index.js.map +1 -0
  106. package/dist/src/mutators/logical-operator-mutator.d.ts +3 -0
  107. package/dist/src/mutators/logical-operator-mutator.d.ts.map +1 -0
  108. package/dist/src/mutators/logical-operator-mutator.js +21 -0
  109. package/dist/src/mutators/logical-operator-mutator.js.map +1 -0
  110. package/dist/src/mutators/method-expression-mutator.d.ts +3 -0
  111. package/dist/src/mutators/method-expression-mutator.d.ts.map +1 -0
  112. package/dist/src/mutators/method-expression-mutator.js +65 -0
  113. package/dist/src/mutators/method-expression-mutator.js.map +1 -0
  114. package/dist/src/mutators/mutate.d.ts +3 -0
  115. package/dist/src/mutators/mutate.d.ts.map +1 -0
  116. package/dist/src/mutators/mutate.js +35 -0
  117. package/dist/src/mutators/mutate.js.map +1 -0
  118. package/dist/src/mutators/mutator-options.d.ts +5 -0
  119. package/dist/src/mutators/mutator-options.d.ts.map +1 -0
  120. package/dist/src/mutators/mutator-options.js +2 -0
  121. package/dist/src/mutators/mutator-options.js.map +1 -0
  122. package/dist/src/mutators/node-mutator.d.ts +6 -0
  123. package/dist/src/mutators/node-mutator.d.ts.map +1 -0
  124. package/dist/src/mutators/node-mutator.js +2 -0
  125. package/dist/src/mutators/node-mutator.js.map +1 -0
  126. package/dist/src/mutators/object-literal-mutator.d.ts +3 -0
  127. package/dist/src/mutators/object-literal-mutator.d.ts.map +1 -0
  128. package/dist/src/mutators/object-literal-mutator.js +11 -0
  129. package/dist/src/mutators/object-literal-mutator.js.map +1 -0
  130. package/dist/src/mutators/optional-chaining-mutator.d.ts +15 -0
  131. package/dist/src/mutators/optional-chaining-mutator.d.ts.map +1 -0
  132. package/dist/src/mutators/optional-chaining-mutator.js +28 -0
  133. package/dist/src/mutators/optional-chaining-mutator.js.map +1 -0
  134. package/dist/src/mutators/regex-mutator.d.ts +3 -0
  135. package/dist/src/mutators/regex-mutator.d.ts.map +1 -0
  136. package/dist/src/mutators/regex-mutator.js +53 -0
  137. package/dist/src/mutators/regex-mutator.js.map +1 -0
  138. package/dist/src/mutators/string-literal-mutator.d.ts +3 -0
  139. package/dist/src/mutators/string-literal-mutator.d.ts.map +1 -0
  140. package/dist/src/mutators/string-literal-mutator.js +36 -0
  141. package/dist/src/mutators/string-literal-mutator.js.map +1 -0
  142. package/dist/src/mutators/unary-operator-mutator.d.ts +3 -0
  143. package/dist/src/mutators/unary-operator-mutator.d.ts.map +1 -0
  144. package/dist/src/mutators/unary-operator-mutator.js +27 -0
  145. package/dist/src/mutators/unary-operator-mutator.js.map +1 -0
  146. package/dist/src/mutators/update-operator-mutator.d.ts +3 -0
  147. package/dist/src/mutators/update-operator-mutator.d.ts.map +1 -0
  148. package/dist/src/mutators/update-operator-mutator.js +17 -0
  149. package/dist/src/mutators/update-operator-mutator.js.map +1 -0
  150. package/dist/src/parsers/create-parser.d.ts +5 -0
  151. package/dist/src/parsers/create-parser.d.ts.map +1 -0
  152. package/dist/src/parsers/create-parser.js +58 -0
  153. package/dist/src/parsers/create-parser.js.map +1 -0
  154. package/dist/src/parsers/html-parser.d.ts +4 -0
  155. package/dist/src/parsers/html-parser.d.ts.map +1 -0
  156. package/dist/src/parsers/html-parser.js +96 -0
  157. package/dist/src/parsers/html-parser.js.map +1 -0
  158. package/dist/src/parsers/index.d.ts +5 -0
  159. package/dist/src/parsers/index.d.ts.map +1 -0
  160. package/dist/src/parsers/index.js +3 -0
  161. package/dist/src/parsers/index.js.map +1 -0
  162. package/dist/src/parsers/js-parser.d.ts +4 -0
  163. package/dist/src/parsers/js-parser.d.ts.map +1 -0
  164. package/dist/src/parsers/js-parser.js +50 -0
  165. package/dist/src/parsers/js-parser.js.map +1 -0
  166. package/dist/src/parsers/parse-error.d.ts +5 -0
  167. package/dist/src/parsers/parse-error.d.ts.map +1 -0
  168. package/dist/src/parsers/parse-error.js +6 -0
  169. package/dist/src/parsers/parse-error.js.map +1 -0
  170. package/dist/src/parsers/parser-context.d.ts +6 -0
  171. package/dist/src/parsers/parser-context.d.ts.map +1 -0
  172. package/dist/src/parsers/parser-context.js +2 -0
  173. package/dist/src/parsers/parser-context.js.map +1 -0
  174. package/dist/src/parsers/parser-options.d.ts +4 -0
  175. package/dist/src/parsers/parser-options.d.ts.map +1 -0
  176. package/dist/src/parsers/parser-options.js +2 -0
  177. package/dist/src/parsers/parser-options.js.map +1 -0
  178. package/dist/src/parsers/svelte-parser.d.ts +4 -0
  179. package/dist/src/parsers/svelte-parser.d.ts.map +1 -0
  180. package/dist/src/parsers/svelte-parser.js +169 -0
  181. package/dist/src/parsers/svelte-parser.js.map +1 -0
  182. package/dist/src/parsers/ts-parser.d.ts +9 -0
  183. package/dist/src/parsers/ts-parser.d.ts.map +1 -0
  184. package/dist/src/parsers/ts-parser.js +54 -0
  185. package/dist/src/parsers/ts-parser.js.map +1 -0
  186. package/dist/src/printers/html-printer.d.ts +4 -0
  187. package/dist/src/printers/html-printer.d.ts.map +1 -0
  188. package/dist/src/printers/html-printer.js +15 -0
  189. package/dist/src/printers/html-printer.js.map +1 -0
  190. package/dist/src/printers/index.d.ts +7 -0
  191. package/dist/src/printers/index.d.ts.map +1 -0
  192. package/dist/src/printers/index.js +23 -0
  193. package/dist/src/printers/index.js.map +1 -0
  194. package/dist/src/printers/js-printer.d.ts +4 -0
  195. package/dist/src/printers/js-printer.d.ts.map +1 -0
  196. package/dist/src/printers/js-printer.js +6 -0
  197. package/dist/src/printers/js-printer.js.map +1 -0
  198. package/dist/src/printers/svelte-printer.d.ts +4 -0
  199. package/dist/src/printers/svelte-printer.d.ts.map +1 -0
  200. package/dist/src/printers/svelte-printer.js +28 -0
  201. package/dist/src/printers/svelte-printer.js.map +1 -0
  202. package/dist/src/printers/ts-printer.d.ts +4 -0
  203. package/dist/src/printers/ts-printer.d.ts.map +1 -0
  204. package/dist/src/printers/ts-printer.js +9 -0
  205. package/dist/src/printers/ts-printer.js.map +1 -0
  206. package/dist/src/syntax/index.d.ts +86 -0
  207. package/dist/src/syntax/index.d.ts.map +1 -0
  208. package/dist/src/syntax/index.js +9 -0
  209. package/dist/src/syntax/index.js.map +1 -0
  210. package/dist/src/transformers/babel-transformer.d.ts +4 -0
  211. package/dist/src/transformers/babel-transformer.d.ts.map +1 -0
  212. package/dist/src/transformers/babel-transformer.js +142 -0
  213. package/dist/src/transformers/babel-transformer.js.map +1 -0
  214. package/dist/src/transformers/directive-bookkeeper.d.ts +19 -0
  215. package/dist/src/transformers/directive-bookkeeper.d.ts.map +1 -0
  216. package/dist/src/transformers/directive-bookkeeper.js +108 -0
  217. package/dist/src/transformers/directive-bookkeeper.js.map +1 -0
  218. package/dist/src/transformers/html-transformer.d.ts +4 -0
  219. package/dist/src/transformers/html-transformer.d.ts.map +1 -0
  220. package/dist/src/transformers/html-transformer.js +6 -0
  221. package/dist/src/transformers/html-transformer.js.map +1 -0
  222. package/dist/src/transformers/ignorer-bookkeeper.d.ts +18 -0
  223. package/dist/src/transformers/ignorer-bookkeeper.d.ts.map +1 -0
  224. package/dist/src/transformers/ignorer-bookkeeper.js +29 -0
  225. package/dist/src/transformers/ignorer-bookkeeper.js.map +1 -0
  226. package/dist/src/transformers/index.d.ts +6 -0
  227. package/dist/src/transformers/index.d.ts.map +1 -0
  228. package/dist/src/transformers/index.js +4 -0
  229. package/dist/src/transformers/index.js.map +1 -0
  230. package/dist/src/transformers/mutant-collector.d.ts +19 -0
  231. package/dist/src/transformers/mutant-collector.d.ts.map +1 -0
  232. package/dist/src/transformers/mutant-collector.js +25 -0
  233. package/dist/src/transformers/mutant-collector.js.map +1 -0
  234. package/dist/src/transformers/svelte-transformer.d.ts +4 -0
  235. package/dist/src/transformers/svelte-transformer.d.ts.map +1 -0
  236. package/dist/src/transformers/svelte-transformer.js +46 -0
  237. package/dist/src/transformers/svelte-transformer.js.map +1 -0
  238. package/dist/src/transformers/transformer-options.d.ts +6 -0
  239. package/dist/src/transformers/transformer-options.d.ts.map +1 -0
  240. package/dist/src/transformers/transformer-options.js +2 -0
  241. package/dist/src/transformers/transformer-options.js.map +1 -0
  242. package/dist/src/transformers/transformer.d.ts +22 -0
  243. package/dist/src/transformers/transformer.d.ts.map +1 -0
  244. package/dist/src/transformers/transformer.js +30 -0
  245. package/dist/src/transformers/transformer.js.map +1 -0
  246. package/dist/src/util/binary-operator.d.ts +2 -0
  247. package/dist/src/util/binary-operator.d.ts.map +1 -0
  248. package/dist/src/util/binary-operator.js +2 -0
  249. package/dist/src/util/binary-operator.js.map +1 -0
  250. package/dist/src/util/index.d.ts +4 -0
  251. package/dist/src/util/index.d.ts.map +1 -0
  252. package/dist/src/util/index.js +4 -0
  253. package/dist/src/util/index.js.map +1 -0
  254. package/dist/src/util/position-converter.d.ts +16 -0
  255. package/dist/src/util/position-converter.d.ts.map +1 -0
  256. package/dist/src/util/position-converter.js +126 -0
  257. package/dist/src/util/position-converter.js.map +1 -0
  258. package/dist/src/util/syntax-helpers.d.ts +60 -0
  259. package/dist/src/util/syntax-helpers.d.ts.map +1 -0
  260. package/dist/src/util/syntax-helpers.js +217 -0
  261. package/dist/src/util/syntax-helpers.js.map +1 -0
  262. package/package.json +64 -0
  263. package/src/create-instrumenter.ts +30 -0
  264. package/src/disable-type-checks.ts +153 -0
  265. package/src/file.ts +6 -0
  266. package/src/frameworks/angular-ignorer.ts +129 -0
  267. package/src/frameworks/index.ts +9 -0
  268. package/src/index.ts +8 -0
  269. package/src/instrument-result.ts +8 -0
  270. package/src/instrumenter-options.ts +5 -0
  271. package/src/instrumenter-tokens.ts +5 -0
  272. package/src/instrumenter.ts +100 -0
  273. package/src/mutant-placers/expression-mutant-placer.ts +210 -0
  274. package/src/mutant-placers/index.ts +12 -0
  275. package/src/mutant-placers/mutant-placer.ts +9 -0
  276. package/src/mutant-placers/statement-mutant-placer.ts +39 -0
  277. package/src/mutant-placers/switch-case-mutant-placer.ts +41 -0
  278. package/src/mutant-placers/throw-placement-error.ts +34 -0
  279. package/src/mutant.ts +101 -0
  280. package/src/mutators/arithmetic-operator-mutator.ts +51 -0
  281. package/src/mutators/array-declaration-mutator.ts +36 -0
  282. package/src/mutators/arrow-function-mutator.ts +22 -0
  283. package/src/mutators/assignment-operator-mutator.ts +59 -0
  284. package/src/mutators/block-statement-mutator.ts +89 -0
  285. package/src/mutators/boolean-literal-mutator.ts +24 -0
  286. package/src/mutators/conditional-expression-mutator.ts +92 -0
  287. package/src/mutators/equality-operator-mutator.ts +35 -0
  288. package/src/mutators/index.ts +3 -0
  289. package/src/mutators/logical-operator-mutator.ts +29 -0
  290. package/src/mutators/method-expression-mutator.ts +99 -0
  291. package/src/mutators/mutate.ts +36 -0
  292. package/src/mutators/mutator-options.ts +4 -0
  293. package/src/mutators/node-mutator.ts +6 -0
  294. package/src/mutators/object-literal-mutator.ts +15 -0
  295. package/src/mutators/optional-chaining-mutator.ts +39 -0
  296. package/src/mutators/regex-mutator.ts +69 -0
  297. package/src/mutators/string-literal-mutator.ts +49 -0
  298. package/src/mutators/unary-operator-mutator.ts +39 -0
  299. package/src/mutators/update-operator-mutator.ts +26 -0
  300. package/src/parsers/create-parser.ts +78 -0
  301. package/src/parsers/html-parser.ts +138 -0
  302. package/src/parsers/index.ts +5 -0
  303. package/src/parsers/js-parser.ts +58 -0
  304. package/src/parsers/parse-error.ts +9 -0
  305. package/src/parsers/parser-context.ts +15 -0
  306. package/src/parsers/parser-options.ts +3 -0
  307. package/src/parsers/svelte-parser.ts +255 -0
  308. package/src/parsers/ts-parser.ts +69 -0
  309. package/src/printers/html-printer.ts +20 -0
  310. package/src/printers/index.ts +33 -0
  311. package/src/printers/js-printer.ts +11 -0
  312. package/src/printers/svelte-printer.ts +34 -0
  313. package/src/printers/ts-printer.ts +14 -0
  314. package/src/syntax/index.ts +97 -0
  315. package/src/transformers/babel-transformer.ts +217 -0
  316. package/src/transformers/directive-bookkeeper.ts +173 -0
  317. package/src/transformers/html-transformer.ts +13 -0
  318. package/src/transformers/ignorer-bookkeeper.ts +41 -0
  319. package/src/transformers/index.ts +6 -0
  320. package/src/transformers/mutant-collector.ts +44 -0
  321. package/src/transformers/svelte-transformer.ts +57 -0
  322. package/src/transformers/transformer-options.ts +7 -0
  323. package/src/transformers/transformer.ts +54 -0
  324. package/src/util/binary-operator.ts +23 -0
  325. package/src/util/index.ts +3 -0
  326. package/src/util/position-converter.ts +145 -0
  327. 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,6 @@
1
+ import { MutantCollector } from './mutant-collector.js';
2
+ import { TransformerOptions } from './transformer-options.js';
3
+
4
+ export type { TransformerOptions };
5
+ export { MutantCollector };
6
+ export * from './transformer.js';
@@ -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,7 @@
1
+ import { Ignorer } from '@stryker-mutator/api/ignore';
2
+
3
+ import { MutatorOptions } from '../mutators/index.js';
4
+
5
+ export interface TransformerOptions extends MutatorOptions {
6
+ ignorers: Ignorer[];
7
+ }
@@ -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';
@@ -0,0 +1,3 @@
1
+ export * from './syntax-helpers.js';
2
+ export * from './binary-operator.js';
3
+ export * from './position-converter.js';