@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,15 @@
1
+ import { Ast, AstFormat, AstByFormat } from '../syntax/index.js';
2
+
3
+ export interface ParserContext {
4
+ parse<T extends AstFormat>(
5
+ code: string,
6
+ fileName: string,
7
+ formatOverride?: T,
8
+ ): Promise<AstByFormat[T]>;
9
+ }
10
+
11
+ export type Parser<T extends Ast = Ast> = (
12
+ text: string,
13
+ fileName: string,
14
+ context: ParserContext,
15
+ ) => Promise<T>;
@@ -0,0 +1,3 @@
1
+ export interface ParserOptions {
2
+ plugins: unknown[] | null;
3
+ }
@@ -0,0 +1,255 @@
1
+ import type { BaseNode, Program } from 'estree';
2
+ import type { AST } from 'svelte/compiler';
3
+
4
+ import { notEmpty } from '@stryker-mutator/util';
5
+
6
+ import { satisfies } from 'semver';
7
+
8
+ import {
9
+ AstFormat,
10
+ SvelteAst,
11
+ TemplateScript,
12
+ SvelteRootNode,
13
+ } from '../syntax/index.js';
14
+ import { PositionConverter } from '../util/index.js';
15
+
16
+ import { ParserContext } from './parser-context.js';
17
+
18
+ interface Range {
19
+ start: number;
20
+ end: number;
21
+ }
22
+ interface TemplateRange extends Range {
23
+ isExpression: boolean;
24
+ }
25
+
26
+ interface TemplateScriptRange extends TemplateRange {
27
+ format: AstFormat.JS | AstFormat.TS;
28
+ }
29
+
30
+ interface ScriptTag {
31
+ content: string;
32
+ attributes: Record<string, boolean | string>;
33
+ }
34
+
35
+ type RangedProgram = Program & Range;
36
+ const MIN_SVELTE_VERSION = '>=3.30';
37
+ export async function parse(
38
+ text: string,
39
+ fileName: string,
40
+ context: ParserContext,
41
+ ): Promise<SvelteAst> {
42
+ const {
43
+ parse: svelteParse,
44
+ preprocess,
45
+ VERSION,
46
+ } = await import('svelte/compiler');
47
+ let walk: typeof import('estree-walker').walk;
48
+
49
+ if (!satisfies(VERSION, MIN_SVELTE_VERSION)) {
50
+ throw new Error(
51
+ `Svelte version ${VERSION} not supported. Expected: ${MIN_SVELTE_VERSION} (processing file ${fileName})`,
52
+ );
53
+ }
54
+ /*
55
+ Allow instrumentation of Svelte 5 projects without dropping support for Svelte 4.
56
+ Due to the way Svelte 5 is structured, we can no longer use the typings from Svelte 4, even though
57
+ we use the legacy AST. The full Svelte 5 migration should update these typings to use the new AST.
58
+ */
59
+ if (satisfies(VERSION, '>=5')) {
60
+ ({ walk } = await import(
61
+ import.meta.resolve('estree-walker', import.meta.resolve('svelte'))
62
+ ));
63
+ } else {
64
+ // Svelte 4
65
+ ({ walk } = await import('svelte/compiler'));
66
+ }
67
+
68
+ const positionConverter = new PositionConverter(text);
69
+ const { replacedCode, scriptMap } = await replaceScripts(text);
70
+ const svelteAst = svelteParse(replacedCode, { filename: fileName });
71
+
72
+ const moduleScriptRange = getModuleScriptRange(svelteAst);
73
+ const templateRanges = getTemplateScriptRanges(svelteAst);
74
+ const { remappedModuleScriptRange, remappedScriptRanges } =
75
+ remapScriptLocations(
76
+ replacedCode,
77
+ scriptMap,
78
+ moduleScriptRange,
79
+ templateRanges,
80
+ );
81
+
82
+ const [moduleScript, ...additionalScripts] = await Promise.all([
83
+ parseTemplateScriptIfDefined(remappedModuleScriptRange),
84
+ ...remappedScriptRanges.map(parseTemplateScript),
85
+ ]);
86
+ const root: SvelteRootNode = { moduleScript, additionalScripts };
87
+
88
+ return {
89
+ originFileName: fileName,
90
+ rawContent: text,
91
+ format: AstFormat.Svelte,
92
+ root,
93
+ };
94
+
95
+ /**
96
+ * Replaces script tags with placeholders.
97
+ * This is needed, because svelte's `parse` doesn't support `lang="ts"`.
98
+ */
99
+ async function replaceScripts(code: string) {
100
+ const map = new Map<string, ScriptTag>();
101
+ let scriptIndex = 0;
102
+ const result = await preprocess(code, {
103
+ script(script) {
104
+ const scriptName = `script${scriptIndex++}`;
105
+ map.set(scriptName, script);
106
+ return { code: scriptName };
107
+ },
108
+ });
109
+ return { replacedCode: result.code, scriptMap: map };
110
+ }
111
+
112
+ function getTemplateScriptRanges(ast: Record<string, any>): TemplateRange[] {
113
+ const ranges: TemplateRange[] = [];
114
+
115
+ if (ast.instance) {
116
+ const { start, end } = ast.instance.content as RangedProgram;
117
+ ranges.push({ start, end, isExpression: false });
118
+ }
119
+
120
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-argument
121
+ walk(ast.html, {
122
+ enter(n) {
123
+ const node = n as any;
124
+ if (
125
+ node.type === 'Element' &&
126
+ node.name === 'script' &&
127
+ node.children?.[0].type === 'Text'
128
+ ) {
129
+ const textContentNode = node.children[0] as AST.Text;
130
+ ranges.push({
131
+ start: textContentNode.start,
132
+ end: textContentNode.end,
133
+ isExpression: false,
134
+ });
135
+ }
136
+
137
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-argument
138
+ const templateExpression = collectTemplateExpression(node);
139
+ if (templateExpression) {
140
+ const { start, end } = templateExpression;
141
+ ranges.push({ start, end, isExpression: true });
142
+ }
143
+ },
144
+ });
145
+
146
+ return ranges;
147
+ }
148
+
149
+ async function parseTemplateScriptIfDefined(
150
+ range?: TemplateScriptRange,
151
+ ): Promise<TemplateScript | undefined> {
152
+ if (range) {
153
+ return parseTemplateScript(range);
154
+ }
155
+ return;
156
+ }
157
+ async function parseTemplateScript({
158
+ start,
159
+ end,
160
+ isExpression,
161
+ format,
162
+ }: TemplateScriptRange): Promise<TemplateScript> {
163
+ const scriptText = text.slice(start, end);
164
+ const parsed = await context.parse(scriptText, fileName, format);
165
+ return {
166
+ ast: {
167
+ ...parsed,
168
+ offset: positionConverter.positionFromOffset(start),
169
+ },
170
+ range: { start, end },
171
+ isExpression,
172
+ };
173
+ }
174
+ }
175
+
176
+ function getModuleScriptRange(
177
+ svelteAst: Record<string, any>,
178
+ ): TemplateRange | undefined {
179
+ if (svelteAst.module) {
180
+ const script = svelteAst.module.content as RangedProgram;
181
+ return { start: script.start, end: script.end, isExpression: false };
182
+ }
183
+ return;
184
+ }
185
+
186
+ /**
187
+ * Remaps script locations back to the original places using the script map
188
+ */
189
+ function remapScriptLocations(
190
+ code: string,
191
+ scriptMap: Map<string, ScriptTag>,
192
+ moduleScriptRange: TemplateRange | undefined,
193
+ templateRanges: TemplateRange[],
194
+ ): {
195
+ remappedModuleScriptRange: TemplateScriptRange | undefined;
196
+ remappedScriptRanges: TemplateScriptRange[];
197
+ } {
198
+ const scriptRanges = [moduleScriptRange, ...templateRanges]
199
+ .filter(notEmpty)
200
+ .sort((a, b) => a.start - b.start);
201
+ let offset = 0;
202
+ let newModuleScriptRange: TemplateScriptRange | undefined;
203
+ const newScriptRanges: TemplateScriptRange[] = scriptRanges.map((range) => {
204
+ const script = code.substring(range.start, range.end);
205
+ const actualScript = scriptMap.get(script);
206
+ const start = range.start + offset;
207
+ if (actualScript) {
208
+ const scriptRange: TemplateScriptRange = {
209
+ start,
210
+ end: start + actualScript.content.length,
211
+ isExpression: range.isExpression,
212
+ format:
213
+ actualScript.attributes.lang === 'ts' ? AstFormat.TS : AstFormat.JS,
214
+ };
215
+ offset += actualScript.content.length - script.length;
216
+ if (range === moduleScriptRange) {
217
+ newModuleScriptRange = scriptRange;
218
+ }
219
+ return scriptRange;
220
+ } else {
221
+ // Template script is always JS
222
+ return {
223
+ start,
224
+ end: start + script.length,
225
+ isExpression: range.isExpression,
226
+ format: AstFormat.JS,
227
+ };
228
+ }
229
+ });
230
+ return {
231
+ remappedModuleScriptRange: newModuleScriptRange,
232
+ remappedScriptRanges: newScriptRanges.filter(
233
+ (range) => range !== newModuleScriptRange,
234
+ ),
235
+ };
236
+ }
237
+
238
+ function collectTemplateExpression(node: {
239
+ type: string;
240
+ expression: BaseNode & Range;
241
+ }): (BaseNode & Range) | undefined {
242
+ switch (node.type) {
243
+ case 'MustacheTag':
244
+ case 'RawMustacheTag':
245
+ case 'IfBlock':
246
+ case 'ConstTag':
247
+ case 'EachBlock':
248
+ case 'AwaitBlock':
249
+ case 'KeyBlock':
250
+ case 'EventHandler':
251
+ return node.expression;
252
+ default:
253
+ return undefined;
254
+ }
255
+ }
@@ -0,0 +1,69 @@
1
+ import { createRequire } from 'module';
2
+
3
+ import babel from '@babel/core';
4
+
5
+ import { AstFormat, TSAst, TsxAst } from '../syntax/index.js';
6
+
7
+ const { types, parseAsync } = babel;
8
+ const require = createRequire(import.meta.url);
9
+ /**
10
+ * See https://babeljs.io/docs/en/babel-preset-typescript
11
+ * @param text The text to parse
12
+ * @param fileName The name of the file
13
+ */
14
+ export async function parseTS(text: string, fileName: string): Promise<TSAst> {
15
+ return {
16
+ originFileName: fileName,
17
+ rawContent: text,
18
+ format: AstFormat.TS,
19
+ root: await parse(text, fileName, false),
20
+ };
21
+ }
22
+
23
+ export async function parseTsx(
24
+ text: string,
25
+ fileName: string,
26
+ ): Promise<TsxAst> {
27
+ return {
28
+ root: await parse(text, fileName, true),
29
+ format: AstFormat.Tsx,
30
+ originFileName: fileName,
31
+ rawContent: text,
32
+ };
33
+ }
34
+
35
+ async function parse(
36
+ text: string,
37
+ fileName: string,
38
+ isTSX: boolean,
39
+ ): Promise<babel.types.File> {
40
+ const ast = await parseAsync(text, {
41
+ filename: fileName,
42
+ parserOpts: {
43
+ ranges: true,
44
+ },
45
+ configFile: false,
46
+ babelrc: false,
47
+ presets: [
48
+ [
49
+ require.resolve('@babel/preset-typescript'),
50
+ { isTSX, allExtensions: true },
51
+ ],
52
+ ],
53
+ plugins: [
54
+ [require.resolve('@babel/plugin-proposal-decorators'), { legacy: true }],
55
+ [require.resolve('@babel/plugin-transform-explicit-resource-management')],
56
+ ],
57
+ });
58
+ if (ast === null) {
59
+ throw new Error(
60
+ `Expected ${fileName} to contain a babel.types.file, but it yielded null`,
61
+ );
62
+ }
63
+ if (types.isProgram(ast)) {
64
+ throw new Error(
65
+ `Expected ${fileName} to contain a babel.types.file, but was a program`,
66
+ );
67
+ }
68
+ return ast;
69
+ }
@@ -0,0 +1,20 @@
1
+ import { HtmlAst } from '../syntax/index.js';
2
+
3
+ import { Printer } from './index.js';
4
+
5
+ export const print: Printer<HtmlAst> = (ast, context) => {
6
+ const sortedScripts = [...ast.root.scripts].sort(
7
+ (a, b) => a.root.start! - b.root.start!,
8
+ );
9
+ let currentIndex = 0;
10
+ let html = '';
11
+ for (const script of sortedScripts) {
12
+ html += ast.rawContent.substring(currentIndex, script.root.start!);
13
+ html += '\n';
14
+ html += context.print(script, context);
15
+ html += '\n';
16
+ currentIndex = script.root.end!;
17
+ }
18
+ html += ast.rawContent.substr(currentIndex);
19
+ return html;
20
+ };
@@ -0,0 +1,33 @@
1
+ import { Ast, AstFormat } from '../syntax/index.js';
2
+
3
+ import { print as htmlPrint } from './html-printer.js';
4
+ import { print as jsPrint } from './js-printer.js';
5
+ import { print as tsPrint } from './ts-printer.js';
6
+ import { print as sveltePrint } from './svelte-printer.js';
7
+
8
+ export type Printer<T extends Ast> = (
9
+ file: T,
10
+ context: PrinterContext,
11
+ ) => string;
12
+
13
+ export interface PrinterContext {
14
+ print: Printer<Ast>;
15
+ }
16
+
17
+ export function print(file: Ast): string {
18
+ const context: PrinterContext = {
19
+ print,
20
+ };
21
+ switch (file.format) {
22
+ case AstFormat.JS:
23
+ return jsPrint(file, context);
24
+ case AstFormat.TS:
25
+ return tsPrint(file, context);
26
+ case AstFormat.Tsx:
27
+ return tsPrint(file, context);
28
+ case AstFormat.Html:
29
+ return htmlPrint(file, context);
30
+ case AstFormat.Svelte:
31
+ return sveltePrint(file, context);
32
+ }
33
+ }
@@ -0,0 +1,11 @@
1
+ import generator from '@babel/generator';
2
+
3
+ import { JSAst } from '../syntax/index.js';
4
+
5
+ import { Printer } from './index.js';
6
+
7
+ const generate = generator.default;
8
+
9
+ export const print: Printer<JSAst> = (file) => {
10
+ return generate(file.root, { sourceMaps: false }).code;
11
+ };
@@ -0,0 +1,34 @@
1
+ import { notEmpty } from '@stryker-mutator/util';
2
+
3
+ import { SvelteAst } from '../syntax/index.js';
4
+
5
+ import { Printer } from './index.js';
6
+
7
+ export const print: Printer<SvelteAst> = ({ root, rawContent }, context) => {
8
+ let currentIndex = 0;
9
+ let outputText = '';
10
+
11
+ const sortedScripts = [root.moduleScript, ...root.additionalScripts]
12
+ .filter(notEmpty)
13
+ .sort((a, b) => a.range.start - b.range.start);
14
+ for (const script of sortedScripts) {
15
+ if (script.isExpression) {
16
+ const code = context.print(script.ast, context);
17
+ const codeWithoutSemicolon = code.slice(0, -1);
18
+ outputText +=
19
+ rawContent.substring(currentIndex, script.range.start) +
20
+ codeWithoutSemicolon;
21
+ currentIndex = script.range.end;
22
+ } else {
23
+ outputText += rawContent.substring(currentIndex, script.range.start);
24
+ outputText += '\n';
25
+ outputText += context.print(script.ast, context);
26
+ outputText += '\n';
27
+ currentIndex = script.range.end;
28
+ }
29
+ }
30
+
31
+ outputText += rawContent.substring(currentIndex);
32
+
33
+ return outputText;
34
+ };
@@ -0,0 +1,14 @@
1
+ import generator from '@babel/generator';
2
+
3
+ import { TSAst, TsxAst } from '../syntax/index.js';
4
+
5
+ import { Printer } from './index.js';
6
+
7
+ const generate = generator.default;
8
+
9
+ export const print: Printer<TSAst | TsxAst> = (file) => {
10
+ return generate(file.root, {
11
+ decoratorsBeforeExport: true,
12
+ sourceMaps: false,
13
+ }).code;
14
+ };
@@ -0,0 +1,97 @@
1
+ import type { types as babelTypes } from '@babel/core';
2
+ import { Position } from '@stryker-mutator/api/core';
3
+
4
+ export enum AstFormat {
5
+ Html = 'html',
6
+ JS = 'js',
7
+ TS = 'ts',
8
+ Tsx = 'tsx',
9
+ Svelte = 'svelte',
10
+ }
11
+
12
+ export interface AstByFormat {
13
+ [AstFormat.Html]: HtmlAst;
14
+ [AstFormat.JS]: JSAst;
15
+ [AstFormat.TS]: TSAst;
16
+ [AstFormat.Tsx]: TsxAst;
17
+ [AstFormat.Svelte]: SvelteAst;
18
+ }
19
+ export type Ast = HtmlAst | JSAst | SvelteAst | TSAst | TsxAst;
20
+
21
+ export type ScriptFormat = AstFormat.JS | AstFormat.TS | AstFormat.Tsx;
22
+ export type ScriptAst = JSAst | TSAst | TsxAst;
23
+ export interface BaseAst {
24
+ originFileName: string;
25
+ rawContent: string;
26
+ root: Ast['root'];
27
+ offset?: Position;
28
+ }
29
+
30
+ /**
31
+ * Represents an Html AST.
32
+ */
33
+ export interface HtmlAst extends BaseAst {
34
+ format: AstFormat.Html;
35
+ root: HtmlRootNode;
36
+ }
37
+
38
+ /**
39
+ * Represents a TS AST
40
+ */
41
+ export interface JSAst extends BaseAst {
42
+ format: AstFormat.JS;
43
+ root: babelTypes.File;
44
+ }
45
+
46
+ /**
47
+ * Represents a TS AST
48
+ */
49
+ export interface TSAst extends BaseAst {
50
+ format: AstFormat.TS;
51
+ root: babelTypes.File;
52
+ }
53
+
54
+ /**
55
+ * Represents a TS AST
56
+ */
57
+ export interface TsxAst extends BaseAst {
58
+ format: AstFormat.Tsx;
59
+ root: babelTypes.File;
60
+ }
61
+
62
+ /**
63
+ * Represents a Svelte AST
64
+ */
65
+ export interface SvelteAst extends BaseAst {
66
+ format: AstFormat.Svelte;
67
+ root: SvelteRootNode;
68
+ }
69
+
70
+ /**
71
+ * Represents the root node of an HTML AST
72
+ * We've taken a shortcut here, instead of representing the entire AST, we're only representing the script tags.
73
+ * We might need to expand this in the future if we would ever want to support mutating the actual HTML (rather than only the JS/TS)
74
+ */
75
+ export interface HtmlRootNode {
76
+ scripts: ScriptAst[];
77
+ }
78
+
79
+ export interface SvelteRootNode {
80
+ moduleScript?: TemplateScript;
81
+ additionalScripts: TemplateScript[];
82
+ }
83
+
84
+ /**
85
+ * Represents a svelte script or binding expression
86
+ * We've taken a shortcut here, instead of representing the entire AST, we're only representing the script tags and expression bindings.
87
+ */
88
+ export interface TemplateScript {
89
+ ast: ScriptAst;
90
+ range: Range;
91
+ isExpression: boolean;
92
+ }
93
+
94
+ export interface Range {
95
+ start: number;
96
+ end: number;
97
+ }