@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,39 @@
1
+ import babel, { type types } from '@babel/core';
2
+
3
+ import {
4
+ mutantTestExpression,
5
+ mutationCoverageSequenceExpression,
6
+ } from '../util/syntax-helpers.js';
7
+
8
+ import { MutantPlacer } from './mutant-placer.js';
9
+
10
+ const { types: t } = babel;
11
+
12
+ /**
13
+ * Mutant placer that places mutants in statements that allow it.
14
+ * It uses an `if` statement to do so
15
+ */
16
+ export const statementMutantPlacer: MutantPlacer<types.Statement> = {
17
+ name: 'statementMutantPlacer',
18
+ canPlace(path) {
19
+ return path.isStatement();
20
+ },
21
+ place(path, appliedMutants) {
22
+ let statement: types.Statement = t.blockStatement([
23
+ t.expressionStatement(
24
+ mutationCoverageSequenceExpression(appliedMutants.keys()),
25
+ ),
26
+ ...(path.isBlockStatement() ? path.node.body : [path.node]),
27
+ ]);
28
+ for (const [mutant, appliedMutant] of appliedMutants) {
29
+ statement = t.ifStatement(
30
+ mutantTestExpression(mutant.id),
31
+ t.blockStatement([appliedMutant]),
32
+ statement,
33
+ );
34
+ }
35
+ path.replaceWith(
36
+ path.isBlockStatement() ? t.blockStatement([statement]) : statement,
37
+ );
38
+ },
39
+ };
@@ -0,0 +1,41 @@
1
+ import babel, { type types } from '@babel/core';
2
+
3
+ import {
4
+ mutantTestExpression,
5
+ mutationCoverageSequenceExpression,
6
+ } from '../util/index.js';
7
+
8
+ import { MutantPlacer } from './mutant-placer.js';
9
+
10
+ /**
11
+ * Places the mutants with consequent of a SwitchCase node. Uses an if-statement to do so.
12
+ * @example
13
+ * case 'foo':
14
+ * if (stryMutAct_9fa48(0)) {} else {
15
+ * stryCov_9fa48(0);
16
+ * console.log('bar');
17
+ * break;
18
+ * }
19
+ */
20
+ export const switchCaseMutantPlacer: MutantPlacer<types.SwitchCase> = {
21
+ name: 'switchCaseMutantPlacer',
22
+ canPlace(path) {
23
+ return path.isSwitchCase();
24
+ },
25
+ place(path, appliedMutants) {
26
+ let consequence: types.Statement = babel.types.blockStatement([
27
+ babel.types.expressionStatement(
28
+ mutationCoverageSequenceExpression(appliedMutants.keys()),
29
+ ),
30
+ ...path.node.consequent,
31
+ ]);
32
+ for (const [mutant, appliedMutant] of appliedMutants) {
33
+ consequence = babel.types.ifStatement(
34
+ mutantTestExpression(mutant.id),
35
+ babel.types.blockStatement(appliedMutant.consequent),
36
+ consequence,
37
+ );
38
+ }
39
+ path.replaceWith(babel.types.switchCase(path.node.test, [consequence]));
40
+ },
41
+ };
@@ -0,0 +1,34 @@
1
+ import path from 'path';
2
+
3
+ import { NodePath } from '@babel/core';
4
+ import { propertyPath } from '@stryker-mutator/util';
5
+ import { StrykerOptions } from '@stryker-mutator/api/core';
6
+
7
+ import { Mutant } from '../mutant.js';
8
+
9
+ import { MutantPlacer } from './mutant-placer.js';
10
+
11
+ export function throwPlacementError(
12
+ error: Error,
13
+ nodePath: NodePath,
14
+ placer: MutantPlacer,
15
+ mutants: Mutant[],
16
+ fileName: string,
17
+ ): never {
18
+ const location = `${path.relative(process.cwd(), fileName)}:${nodePath.node.loc?.start.line}:${nodePath.node.loc?.start.column}`;
19
+ const message = `${placer.name} could not place mutants with type(s): "${new Intl.ListFormat('en').format(mutants.map((mutant) => mutant.mutatorName))}"`;
20
+ const errorMessage = `${location} ${message}. Either remove this file from the list of files to be mutated, or exclude the mutator (using ${propertyPath<StrykerOptions>()(
21
+ 'mutator',
22
+ 'excludedMutations',
23
+ )}). Please report this issue at https://github.com/stryker-mutator/stryker-js/issues/new?assignees=&labels=%F0%9F%90%9B+Bug&template=bug_report.md&title=${encodeURIComponent(
24
+ message,
25
+ )}. Original error: ${error.stack}`;
26
+ let builtError = new Error(errorMessage);
27
+ try {
28
+ // `buildCodeFrameError` is kind of flaky, see https://github.com/stryker-mutator/stryker-js/issues/2695
29
+ builtError = nodePath.buildCodeFrameError(errorMessage);
30
+ } catch {
31
+ // Idle, regular error will have to suffice
32
+ }
33
+ throw builtError;
34
+ }
package/src/mutant.ts ADDED
@@ -0,0 +1,101 @@
1
+ import babel, { type types } from '@babel/core';
2
+ import generate from '@babel/generator';
3
+ import {
4
+ Mutant as ApiMutant,
5
+ Location,
6
+ Position,
7
+ } from '@stryker-mutator/api/core';
8
+
9
+ import { deepCloneNode, eqNode } from './util/index.js';
10
+
11
+ const { traverse } = babel;
12
+
13
+ const generator = generate.default;
14
+
15
+ export interface Mutable {
16
+ mutatorName: string;
17
+ ignoreReason?: string;
18
+ replacement: types.Node;
19
+ }
20
+
21
+ export class Mutant implements Mutable {
22
+ public readonly replacementCode: string;
23
+ public readonly replacement: types.Node;
24
+ public readonly mutatorName: string;
25
+ public readonly ignoreReason: string | undefined;
26
+
27
+ constructor(
28
+ public readonly id: string,
29
+ public readonly fileName: string,
30
+ public readonly original: types.Node,
31
+ specs: Mutable,
32
+ public readonly offset: Position = { column: 0, line: 0 },
33
+ ) {
34
+ this.replacement = specs.replacement;
35
+ this.mutatorName = specs.mutatorName;
36
+ this.ignoreReason = specs.ignoreReason;
37
+ this.replacementCode = generator(this.replacement).code;
38
+ }
39
+
40
+ public toApiMutant(): ApiMutant {
41
+ return {
42
+ fileName: this.fileName,
43
+ id: this.id,
44
+ location: toApiLocation(this.original.loc!, this.offset),
45
+ mutatorName: this.mutatorName,
46
+ replacement: this.replacementCode,
47
+ statusReason: this.ignoreReason,
48
+ status: this.ignoreReason ? 'Ignored' : undefined,
49
+ };
50
+ }
51
+
52
+ /**
53
+ * Applies the mutant in (a copy of) the AST, without changing provided AST.
54
+ * Can the tree itself (in which case the replacement is returned),
55
+ * or can be nested in the given tree.
56
+ * @param originalTree The original node, which will be treated as readonly
57
+ */
58
+ public applied<TNode extends types.Node>(originalTree: TNode): TNode {
59
+ if (originalTree === this.original) {
60
+ return this.replacement as TNode;
61
+ } else {
62
+ const mutatedAst = deepCloneNode(originalTree);
63
+ let applied = false;
64
+ const { original, replacement } = this;
65
+ traverse(mutatedAst, {
66
+ noScope: true,
67
+ enter(path) {
68
+ if (eqNode(path.node, original)) {
69
+ path.replaceWith(replacement);
70
+ path.stop();
71
+ applied = true;
72
+ }
73
+ },
74
+ });
75
+ if (!applied) {
76
+ throw new Error(
77
+ `Could not apply mutant ${JSON.stringify(this.replacement)}.`,
78
+ );
79
+ }
80
+ return mutatedAst;
81
+ }
82
+ }
83
+ }
84
+
85
+ function toApiLocation(
86
+ source: types.SourceLocation,
87
+ offset: Position,
88
+ ): Location {
89
+ const loc = {
90
+ start: toPosition(source.start, offset),
91
+ end: toPosition(source.end, offset),
92
+ };
93
+ return loc;
94
+ }
95
+
96
+ function toPosition(source: Position, offset: Position): Position {
97
+ return {
98
+ column: source.column + (source.line === 1 ? offset.column : 0), // offset is zero-based
99
+ line: source.line + offset.line - 1, // Stryker works 0-based internally, offset is zero based as well
100
+ };
101
+ }
@@ -0,0 +1,51 @@
1
+ import type { types } from '@babel/core';
2
+
3
+ import { deepCloneNode } from '../util/index.js';
4
+
5
+ import { NodeMutator } from './node-mutator.js';
6
+
7
+ const arithmeticOperatorReplacements = Object.freeze({
8
+ '+': '-',
9
+ '-': '+',
10
+ '*': '/',
11
+ '/': '*',
12
+ '%': '*',
13
+ } as const);
14
+
15
+ export const arithmeticOperatorMutator: NodeMutator = {
16
+ name: 'ArithmeticOperator',
17
+
18
+ *mutate(path) {
19
+ if (
20
+ path.isBinaryExpression() &&
21
+ isSupported(path.node.operator, path.node)
22
+ ) {
23
+ const mutatedOperator =
24
+ arithmeticOperatorReplacements[path.node.operator];
25
+ const replacement = deepCloneNode(path.node);
26
+ replacement.operator = mutatedOperator;
27
+ yield replacement;
28
+ }
29
+ },
30
+ };
31
+
32
+ function isSupported(
33
+ operator: string,
34
+ node: types.BinaryExpression,
35
+ ): operator is keyof typeof arithmeticOperatorReplacements {
36
+ if (!Object.keys(arithmeticOperatorReplacements).includes(operator)) {
37
+ return false;
38
+ }
39
+
40
+ const stringTypes = ['StringLiteral', 'TemplateLiteral'];
41
+ const leftType =
42
+ node.left.type === 'BinaryExpression'
43
+ ? node.left.right.type
44
+ : node.left.type;
45
+
46
+ if (stringTypes.includes(node.right.type) || stringTypes.includes(leftType)) {
47
+ return false;
48
+ }
49
+
50
+ return true;
51
+ }
@@ -0,0 +1,36 @@
1
+ import babel, { type NodePath } from '@babel/core';
2
+
3
+ import { deepCloneNode } from '../util/index.js';
4
+
5
+ import { NodeMutator } from './node-mutator.js';
6
+
7
+ const { types } = babel;
8
+
9
+ export const arrayDeclarationMutator: NodeMutator = {
10
+ name: 'ArrayDeclaration',
11
+
12
+ *mutate(path: NodePath): Iterable<babel.types.Node> {
13
+ if (path.isArrayExpression()) {
14
+ const replacement = path.node.elements.length
15
+ ? types.arrayExpression()
16
+ : types.arrayExpression([types.stringLiteral('Stryker was here')]);
17
+ yield replacement;
18
+ }
19
+ if (
20
+ (path.isCallExpression() || path.isNewExpression()) &&
21
+ types.isIdentifier(path.node.callee) &&
22
+ path.node.callee.name === 'Array'
23
+ ) {
24
+ const mutatedCallArgs = path.node.arguments.length
25
+ ? []
26
+ : [types.arrayExpression()];
27
+ const replacement = types.isNewExpression(path.node)
28
+ ? types.newExpression(deepCloneNode(path.node.callee), mutatedCallArgs)
29
+ : types.callExpression(
30
+ deepCloneNode(path.node.callee),
31
+ mutatedCallArgs,
32
+ );
33
+ yield replacement;
34
+ }
35
+ },
36
+ };
@@ -0,0 +1,22 @@
1
+ import babel from '@babel/core';
2
+
3
+ const { types } = babel;
4
+
5
+ import { NodeMutator } from './index.js';
6
+
7
+ export const arrowFunctionMutator: NodeMutator = {
8
+ name: 'ArrowFunction',
9
+
10
+ *mutate(path) {
11
+ if (
12
+ path.isArrowFunctionExpression() &&
13
+ !types.isBlockStatement(path.node.body) &&
14
+ !(
15
+ types.isIdentifier(path.node.body) &&
16
+ path.node.body.name === 'undefined'
17
+ )
18
+ ) {
19
+ yield types.arrowFunctionExpression([], types.identifier('undefined'));
20
+ }
21
+ },
22
+ };
@@ -0,0 +1,59 @@
1
+ import type { types as t } from '@babel/core';
2
+
3
+ import { deepCloneNode } from '../util/index.js';
4
+
5
+ import { NodeMutator } from './index.js';
6
+
7
+ const assignmentOperatorReplacements = Object.freeze({
8
+ '+=': '-=',
9
+ '-=': '+=',
10
+ '*=': '/=',
11
+ '/=': '*=',
12
+ '%=': '*=',
13
+ '<<=': '>>=',
14
+ '>>=': '<<=',
15
+ '&=': '|=',
16
+ '|=': '&=',
17
+ '&&=': '||=',
18
+ '||=': '&&=',
19
+ '??=': '&&=',
20
+ } as const);
21
+
22
+ const stringTypes = Object.freeze(['StringLiteral', 'TemplateLiteral']);
23
+ const stringAssignmentTypes = Object.freeze(['&&=', '||=', '??=']);
24
+
25
+ export const assignmentOperatorMutator: NodeMutator = {
26
+ name: 'AssignmentOperator',
27
+
28
+ *mutate(path) {
29
+ if (
30
+ path.isAssignmentExpression() &&
31
+ isSupportedAssignmentOperator(path.node.operator) &&
32
+ isSupported(path.node)
33
+ ) {
34
+ const mutatedOperator =
35
+ assignmentOperatorReplacements[path.node.operator];
36
+ const replacement = deepCloneNode(path.node);
37
+ replacement.operator = mutatedOperator;
38
+ yield replacement;
39
+ }
40
+ },
41
+ };
42
+
43
+ function isSupportedAssignmentOperator(
44
+ operator: string,
45
+ ): operator is keyof typeof assignmentOperatorReplacements {
46
+ return Object.keys(assignmentOperatorReplacements).includes(operator);
47
+ }
48
+
49
+ function isSupported(node: t.AssignmentExpression): boolean {
50
+ // Excludes assignment operators that apply to strings.
51
+ if (
52
+ stringTypes.includes(node.right.type) &&
53
+ !stringAssignmentTypes.includes(node.operator)
54
+ ) {
55
+ return false;
56
+ }
57
+
58
+ return true;
59
+ }
@@ -0,0 +1,89 @@
1
+ import babel, { type NodePath } from '@babel/core';
2
+
3
+ import { NodeMutator } from './node-mutator.js';
4
+
5
+ const { types } = babel;
6
+
7
+ export const blockStatementMutator: NodeMutator = {
8
+ name: 'BlockStatement',
9
+
10
+ *mutate(path) {
11
+ if (path.isBlockStatement() && isValid(path)) {
12
+ yield types.blockStatement([]);
13
+ }
14
+ },
15
+ };
16
+
17
+ function isValid(path: NodePath<babel.types.BlockStatement>) {
18
+ return !isEmpty(path) && !isInvalidConstructorBody(path);
19
+ }
20
+
21
+ function isEmpty(path: NodePath<babel.types.BlockStatement>) {
22
+ return !path.node.body.length;
23
+ }
24
+
25
+ /**
26
+ * Checks to see if a statement is an invalid constructor body
27
+ * @example
28
+ * // Invalid!
29
+ * class Foo extends Bar {
30
+ * constructor(public baz: string) {
31
+ * super(42);
32
+ * }
33
+ * }
34
+ * @example
35
+ * // Invalid!
36
+ * class Foo extends Bar {
37
+ * public baz = 'string';
38
+ * constructor() {
39
+ * super(42);
40
+ * }
41
+ * }
42
+ * @see https://github.com/stryker-mutator/stryker-js/issues/2314
43
+ * @see https://github.com/stryker-mutator/stryker-js/issues/2474
44
+ */
45
+ function isInvalidConstructorBody(
46
+ blockStatement: NodePath<babel.types.BlockStatement>,
47
+ ): boolean {
48
+ return Boolean(
49
+ blockStatement.parentPath.isClassMethod() &&
50
+ blockStatement.parentPath.node.kind === 'constructor' &&
51
+ (containsTSParameterProperties(blockStatement.parentPath) ||
52
+ containsInitializedClassProperties(blockStatement.parentPath)) &&
53
+ hasSuperExpression(blockStatement),
54
+ );
55
+ }
56
+
57
+ function containsTSParameterProperties(
58
+ constructor: NodePath<babel.types.ClassMethod>,
59
+ ): boolean {
60
+ return constructor.node.params.some((param) =>
61
+ types.isTSParameterProperty(param),
62
+ );
63
+ }
64
+
65
+ function containsInitializedClassProperties(
66
+ constructor: NodePath<babel.types.ClassMethod>,
67
+ ): boolean {
68
+ return (
69
+ constructor.parentPath.isClassBody() &&
70
+ constructor.parentPath.node.body.some(
71
+ (classMember) => types.isClassProperty(classMember) && classMember.value,
72
+ )
73
+ );
74
+ }
75
+
76
+ function hasSuperExpression(
77
+ constructor: NodePath<babel.types.BlockStatement>,
78
+ ): boolean {
79
+ let hasSuper = false;
80
+ constructor.traverse({
81
+ Super(path) {
82
+ if (path.parentPath.isCallExpression()) {
83
+ path.stop();
84
+ hasSuper = true;
85
+ }
86
+ },
87
+ });
88
+ return hasSuper;
89
+ }
@@ -0,0 +1,24 @@
1
+ import babel from '@babel/core';
2
+
3
+ import { deepCloneNode } from '../util/index.js';
4
+
5
+ const { types } = babel;
6
+
7
+ import { NodeMutator } from './index.js';
8
+
9
+ export const booleanLiteralMutator: NodeMutator = {
10
+ name: 'BooleanLiteral',
11
+
12
+ *mutate(path) {
13
+ if (path.isBooleanLiteral()) {
14
+ yield types.booleanLiteral(!path.node.value);
15
+ }
16
+ if (
17
+ path.isUnaryExpression() &&
18
+ path.node.operator === '!' &&
19
+ path.node.prefix
20
+ ) {
21
+ yield deepCloneNode(path.node.argument);
22
+ }
23
+ },
24
+ };
@@ -0,0 +1,92 @@
1
+ import babel, { type NodePath } from '@babel/core';
2
+
3
+ import { deepCloneNode } from '../util/index.js';
4
+
5
+ import { NodeMutator } from './node-mutator.js';
6
+
7
+ const booleanOperators = Object.freeze([
8
+ '!=',
9
+ '!==',
10
+ '&&',
11
+ '<',
12
+ '<=',
13
+ '==',
14
+ '===',
15
+ '>',
16
+ '>=',
17
+ '||',
18
+ ]);
19
+
20
+ const { types } = babel;
21
+
22
+ export const conditionalExpressionMutator: NodeMutator = {
23
+ name: 'ConditionalExpression',
24
+
25
+ *mutate(path) {
26
+ if (isTestOfLoop(path)) {
27
+ yield types.booleanLiteral(false);
28
+ } else if (isTestOfCondition(path)) {
29
+ yield types.booleanLiteral(true);
30
+ yield types.booleanLiteral(false);
31
+ } else if (isBooleanExpression(path)) {
32
+ if (path.parent?.type === 'LogicalExpression') {
33
+ // For (x || y), do not generate the (true || y) mutation as it
34
+ // has the same behavior as the (true) mutator, handled in the
35
+ // isTestOfCondition branch above
36
+ if (path.parent.operator === '||') {
37
+ yield types.booleanLiteral(false);
38
+ return;
39
+ }
40
+ // For (x && y), do not generate the (false && y) mutation as it
41
+ // has the same behavior as the (false) mutator, handled in the
42
+ // isTestOfCondition branch above
43
+ if (path.parent.operator === '&&') {
44
+ yield types.booleanLiteral(true);
45
+ return;
46
+ }
47
+ }
48
+ yield types.booleanLiteral(true);
49
+ yield types.booleanLiteral(false);
50
+ } else if (path.isForStatement() && !path.node.test) {
51
+ const replacement = deepCloneNode(path.node);
52
+ replacement.test = types.booleanLiteral(false);
53
+ yield replacement;
54
+ } else if (path.isSwitchCase() && path.node.consequent.length > 0) {
55
+ // if not a fallthrough case
56
+ const replacement = deepCloneNode(path.node);
57
+ replacement.consequent = [];
58
+ yield replacement;
59
+ }
60
+ },
61
+ };
62
+
63
+ function isTestOfLoop(path: NodePath): boolean {
64
+ const { parentPath } = path;
65
+ if (!parentPath) {
66
+ return false;
67
+ }
68
+ return (
69
+ (parentPath.isForStatement() ||
70
+ parentPath.isWhileStatement() ||
71
+ parentPath.isDoWhileStatement()) &&
72
+ parentPath.node.test === path.node
73
+ );
74
+ }
75
+
76
+ function isTestOfCondition(path: NodePath): boolean {
77
+ const { parentPath } = path;
78
+ if (!parentPath) {
79
+ return false;
80
+ }
81
+ return (
82
+ parentPath.isIfStatement() /*|| parentPath.isConditionalExpression()*/ &&
83
+ parentPath.node.test === path.node
84
+ );
85
+ }
86
+
87
+ function isBooleanExpression(path: NodePath) {
88
+ return (
89
+ (path.isBinaryExpression() || path.isLogicalExpression()) &&
90
+ booleanOperators.includes(path.node.operator)
91
+ );
92
+ }
@@ -0,0 +1,35 @@
1
+ import babel from '@babel/core';
2
+
3
+ import { NodeMutator } from './node-mutator.js';
4
+
5
+ const { types: t } = babel;
6
+
7
+ const operators = {
8
+ '<': ['<=', '>='],
9
+ '<=': ['<', '>'],
10
+ '>': ['>=', '<='],
11
+ '>=': ['>', '<'],
12
+ '==': ['!='],
13
+ '!=': ['=='],
14
+ '===': ['!=='],
15
+ '!==': ['==='],
16
+ } as const;
17
+
18
+ function isEqualityOperator(
19
+ operator: string,
20
+ ): operator is keyof typeof operators {
21
+ return Object.keys(operators).includes(operator);
22
+ }
23
+ export const equalityOperatorMutator: NodeMutator = {
24
+ name: 'EqualityOperator',
25
+
26
+ *mutate(path) {
27
+ if (path.isBinaryExpression() && isEqualityOperator(path.node.operator)) {
28
+ for (const mutableOperator of operators[path.node.operator]) {
29
+ const replacement = t.cloneNode(path.node, true);
30
+ replacement.operator = mutableOperator;
31
+ yield replacement;
32
+ }
33
+ }
34
+ },
35
+ };
@@ -0,0 +1,3 @@
1
+ export * from './node-mutator.js';
2
+ export * from './mutator-options.js';
3
+ export * from './mutate.js';
@@ -0,0 +1,29 @@
1
+ import { deepCloneNode } from '../util/index.js';
2
+
3
+ import { NodeMutator } from './index.js';
4
+
5
+ const logicalOperatorReplacements = Object.freeze({
6
+ '&&': '||',
7
+ '||': '&&',
8
+ '??': '&&',
9
+ } as const);
10
+
11
+ export const logicalOperatorMutator: NodeMutator = {
12
+ name: 'LogicalOperator',
13
+
14
+ *mutate(path) {
15
+ if (path.isLogicalExpression() && isSupported(path.node.operator)) {
16
+ const mutatedOperator = logicalOperatorReplacements[path.node.operator];
17
+
18
+ const replacement = deepCloneNode(path.node);
19
+ replacement.operator = mutatedOperator;
20
+ yield replacement;
21
+ }
22
+ },
23
+ };
24
+
25
+ function isSupported(
26
+ operator: string,
27
+ ): operator is keyof typeof logicalOperatorReplacements {
28
+ return Object.keys(logicalOperatorReplacements).includes(operator);
29
+ }