@d-es-ign/stryker-js-core 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 (631) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +96 -0
  3. package/bin/stryker +2 -0
  4. package/bin/stryker.js +6 -0
  5. package/dist/src/checker/checker-child-process-proxy.d.ts +16 -0
  6. package/dist/src/checker/checker-child-process-proxy.d.ts.map +1 -0
  7. package/dist/src/checker/checker-child-process-proxy.js +22 -0
  8. package/dist/src/checker/checker-child-process-proxy.js.map +1 -0
  9. package/dist/src/checker/checker-facade.d.ts +9 -0
  10. package/dist/src/checker/checker-facade.d.ts.map +1 -0
  11. package/dist/src/checker/checker-facade.js +52 -0
  12. package/dist/src/checker/checker-facade.js.map +1 -0
  13. package/dist/src/checker/checker-factory.d.ts +10 -0
  14. package/dist/src/checker/checker-factory.d.ts.map +1 -0
  15. package/dist/src/checker/checker-factory.js +10 -0
  16. package/dist/src/checker/checker-factory.js.map +1 -0
  17. package/dist/src/checker/checker-resource.d.ts +8 -0
  18. package/dist/src/checker/checker-resource.d.ts.map +1 -0
  19. package/dist/src/checker/checker-resource.js +2 -0
  20. package/dist/src/checker/checker-resource.js.map +1 -0
  21. package/dist/src/checker/checker-retry-decorator.d.ts +12 -0
  22. package/dist/src/checker/checker-retry-decorator.d.ts.map +1 -0
  23. package/dist/src/checker/checker-retry-decorator.js +37 -0
  24. package/dist/src/checker/checker-retry-decorator.js.map +1 -0
  25. package/dist/src/checker/checker-worker.d.ts +14 -0
  26. package/dist/src/checker/checker-worker.d.ts.map +1 -0
  27. package/dist/src/checker/checker-worker.js +41 -0
  28. package/dist/src/checker/checker-worker.js.map +1 -0
  29. package/dist/src/checker/index.d.ts +4 -0
  30. package/dist/src/checker/index.d.ts.map +1 -0
  31. package/dist/src/checker/index.js +4 -0
  32. package/dist/src/checker/index.js.map +1 -0
  33. package/dist/src/child-proxy/child-process-crashed-error.d.ts +8 -0
  34. package/dist/src/child-proxy/child-process-crashed-error.d.ts.map +1 -0
  35. package/dist/src/child-proxy/child-process-crashed-error.js +16 -0
  36. package/dist/src/child-proxy/child-process-crashed-error.js.map +1 -0
  37. package/dist/src/child-proxy/child-process-proxy-worker.d.ts +32 -0
  38. package/dist/src/child-proxy/child-process-proxy-worker.d.ts.map +1 -0
  39. package/dist/src/child-proxy/child-process-proxy-worker.js +148 -0
  40. package/dist/src/child-proxy/child-process-proxy-worker.js.map +1 -0
  41. package/dist/src/child-proxy/child-process-proxy.d.ts +45 -0
  42. package/dist/src/child-proxy/child-process-proxy.d.ts.map +1 -0
  43. package/dist/src/child-proxy/child-process-proxy.js +232 -0
  44. package/dist/src/child-proxy/child-process-proxy.js.map +1 -0
  45. package/dist/src/child-proxy/id-generator.d.ts +5 -0
  46. package/dist/src/child-proxy/id-generator.d.ts.map +1 -0
  47. package/dist/src/child-proxy/id-generator.js +7 -0
  48. package/dist/src/child-proxy/id-generator.js.map +1 -0
  49. package/dist/src/child-proxy/message-protocol.d.ts +71 -0
  50. package/dist/src/child-proxy/message-protocol.d.ts.map +1 -0
  51. package/dist/src/child-proxy/message-protocol.js +34 -0
  52. package/dist/src/child-proxy/message-protocol.js.map +1 -0
  53. package/dist/src/child-proxy/out-of-memory-error.d.ts +5 -0
  54. package/dist/src/child-proxy/out-of-memory-error.d.ts.map +1 -0
  55. package/dist/src/child-proxy/out-of-memory-error.js +11 -0
  56. package/dist/src/child-proxy/out-of-memory-error.js.map +1 -0
  57. package/dist/src/concurrent/concurrency-token-provider.d.ts +20 -0
  58. package/dist/src/concurrent/concurrency-token-provider.d.ts.map +1 -0
  59. package/dist/src/concurrent/concurrency-token-provider.js +68 -0
  60. package/dist/src/concurrent/concurrency-token-provider.js.map +1 -0
  61. package/dist/src/concurrent/index.d.ts +4 -0
  62. package/dist/src/concurrent/index.d.ts.map +1 -0
  63. package/dist/src/concurrent/index.js +4 -0
  64. package/dist/src/concurrent/index.js.map +1 -0
  65. package/dist/src/concurrent/pool.d.ts +49 -0
  66. package/dist/src/concurrent/pool.d.ts.map +1 -0
  67. package/dist/src/concurrent/pool.js +137 -0
  68. package/dist/src/concurrent/pool.js.map +1 -0
  69. package/dist/src/concurrent/resource-decorator.d.ts +14 -0
  70. package/dist/src/concurrent/resource-decorator.d.ts.map +1 -0
  71. package/dist/src/concurrent/resource-decorator.js +24 -0
  72. package/dist/src/concurrent/resource-decorator.js.map +1 -0
  73. package/dist/src/config/config-file-formats.d.ts +6 -0
  74. package/dist/src/config/config-file-formats.d.ts.map +1 -0
  75. package/dist/src/config/config-file-formats.js +23 -0
  76. package/dist/src/config/config-file-formats.js.map +1 -0
  77. package/dist/src/config/config-reader.d.ts +23 -0
  78. package/dist/src/config/config-reader.d.ts.map +1 -0
  79. package/dist/src/config/config-reader.js +141 -0
  80. package/dist/src/config/config-reader.js.map +1 -0
  81. package/dist/src/config/file-matcher.d.ts +10 -0
  82. package/dist/src/config/file-matcher.d.ts.map +1 -0
  83. package/dist/src/config/file-matcher.js +31 -0
  84. package/dist/src/config/file-matcher.js.map +1 -0
  85. package/dist/src/config/index.d.ts +6 -0
  86. package/dist/src/config/index.d.ts.map +1 -0
  87. package/dist/src/config/index.js +6 -0
  88. package/dist/src/config/index.js.map +1 -0
  89. package/dist/src/config/meta-schema-builder.d.ts +10 -0
  90. package/dist/src/config/meta-schema-builder.d.ts.map +1 -0
  91. package/dist/src/config/meta-schema-builder.js +30 -0
  92. package/dist/src/config/meta-schema-builder.js.map +1 -0
  93. package/dist/src/config/options-validator.d.ts +28 -0
  94. package/dist/src/config/options-validator.d.ts.map +1 -0
  95. package/dist/src/config/options-validator.js +213 -0
  96. package/dist/src/config/options-validator.js.map +1 -0
  97. package/dist/src/config/validation-errors.d.ts +7 -0
  98. package/dist/src/config/validation-errors.d.ts.map +1 -0
  99. package/dist/src/config/validation-errors.js +154 -0
  100. package/dist/src/config/validation-errors.js.map +1 -0
  101. package/dist/src/di/core-tokens.d.ts +40 -0
  102. package/dist/src/di/core-tokens.d.ts.map +1 -0
  103. package/dist/src/di/core-tokens.js +40 -0
  104. package/dist/src/di/core-tokens.js.map +1 -0
  105. package/dist/src/di/index.d.ts +4 -0
  106. package/dist/src/di/index.d.ts.map +1 -0
  107. package/dist/src/di/index.js +4 -0
  108. package/dist/src/di/index.js.map +1 -0
  109. package/dist/src/di/plugin-creator.d.ts +10 -0
  110. package/dist/src/di/plugin-creator.d.ts.map +1 -0
  111. package/dist/src/di/plugin-creator.js +51 -0
  112. package/dist/src/di/plugin-creator.js.map +1 -0
  113. package/dist/src/di/plugin-loader.d.ts +41 -0
  114. package/dist/src/di/plugin-loader.d.ts.map +1 -0
  115. package/dist/src/di/plugin-loader.js +153 -0
  116. package/dist/src/di/plugin-loader.js.map +1 -0
  117. package/dist/src/errors.d.ts +5 -0
  118. package/dist/src/errors.d.ts.map +1 -0
  119. package/dist/src/errors.js +13 -0
  120. package/dist/src/errors.js.map +1 -0
  121. package/dist/src/fs/file-system.d.ts +19 -0
  122. package/dist/src/fs/file-system.d.ts.map +1 -0
  123. package/dist/src/fs/file-system.js +52 -0
  124. package/dist/src/fs/file-system.js.map +1 -0
  125. package/dist/src/fs/index.d.ts +5 -0
  126. package/dist/src/fs/index.d.ts.map +1 -0
  127. package/dist/src/fs/index.js +5 -0
  128. package/dist/src/fs/index.js.map +1 -0
  129. package/dist/src/fs/project-file.d.ts +26 -0
  130. package/dist/src/fs/project-file.d.ts.map +1 -0
  131. package/dist/src/fs/project-file.js +87 -0
  132. package/dist/src/fs/project-file.js.map +1 -0
  133. package/dist/src/fs/project-reader.d.ts +51 -0
  134. package/dist/src/fs/project-reader.d.ts.map +1 -0
  135. package/dist/src/fs/project-reader.js +335 -0
  136. package/dist/src/fs/project-reader.js.map +1 -0
  137. package/dist/src/fs/project.d.ts +22 -0
  138. package/dist/src/fs/project.d.ts.map +1 -0
  139. package/dist/src/fs/project.js +65 -0
  140. package/dist/src/fs/project.js.map +1 -0
  141. package/dist/src/index.d.ts +5 -0
  142. package/dist/src/index.d.ts.map +1 -0
  143. package/dist/src/index.js +6 -0
  144. package/dist/src/index.js.map +1 -0
  145. package/dist/src/initializer/custom-initializers/angular-initializer.d.ts +17 -0
  146. package/dist/src/initializer/custom-initializers/angular-initializer.d.ts.map +1 -0
  147. package/dist/src/initializer/custom-initializers/angular-initializer.js +74 -0
  148. package/dist/src/initializer/custom-initializers/angular-initializer.js.map +1 -0
  149. package/dist/src/initializer/custom-initializers/custom-initializer.d.ts +13 -0
  150. package/dist/src/initializer/custom-initializers/custom-initializer.d.ts.map +1 -0
  151. package/dist/src/initializer/custom-initializers/custom-initializer.js +2 -0
  152. package/dist/src/initializer/custom-initializers/custom-initializer.js.map +1 -0
  153. package/dist/src/initializer/custom-initializers/index.d.ts +14 -0
  154. package/dist/src/initializer/custom-initializers/index.d.ts.map +1 -0
  155. package/dist/src/initializer/custom-initializers/index.js +16 -0
  156. package/dist/src/initializer/custom-initializers/index.js.map +1 -0
  157. package/dist/src/initializer/custom-initializers/react-initializer.d.ts +12 -0
  158. package/dist/src/initializer/custom-initializers/react-initializer.d.ts.map +1 -0
  159. package/dist/src/initializer/custom-initializers/react-initializer.js +25 -0
  160. package/dist/src/initializer/custom-initializers/react-initializer.js.map +1 -0
  161. package/dist/src/initializer/custom-initializers/svelte-initializer.d.ts +6 -0
  162. package/dist/src/initializer/custom-initializers/svelte-initializer.d.ts.map +1 -0
  163. package/dist/src/initializer/custom-initializers/svelte-initializer.js +33 -0
  164. package/dist/src/initializer/custom-initializers/svelte-initializer.js.map +1 -0
  165. package/dist/src/initializer/custom-initializers/vue-js-initializer.d.ts +11 -0
  166. package/dist/src/initializer/custom-initializers/vue-js-initializer.d.ts.map +1 -0
  167. package/dist/src/initializer/custom-initializers/vue-js-initializer.js +20 -0
  168. package/dist/src/initializer/custom-initializers/vue-js-initializer.js.map +1 -0
  169. package/dist/src/initializer/gitignore-writer.d.ts +7 -0
  170. package/dist/src/initializer/gitignore-writer.d.ts.map +1 -0
  171. package/dist/src/initializer/gitignore-writer.js +28 -0
  172. package/dist/src/initializer/gitignore-writer.js.map +1 -0
  173. package/dist/src/initializer/index.d.ts +6 -0
  174. package/dist/src/initializer/index.d.ts.map +1 -0
  175. package/dist/src/initializer/index.js +29 -0
  176. package/dist/src/initializer/index.js.map +1 -0
  177. package/dist/src/initializer/initializer-tokens.d.ts +9 -0
  178. package/dist/src/initializer/initializer-tokens.d.ts.map +1 -0
  179. package/dist/src/initializer/initializer-tokens.js +9 -0
  180. package/dist/src/initializer/initializer-tokens.js.map +1 -0
  181. package/dist/src/initializer/inquire.d.ts +12 -0
  182. package/dist/src/initializer/inquire.d.ts.map +1 -0
  183. package/dist/src/initializer/inquire.js +12 -0
  184. package/dist/src/initializer/inquire.js.map +1 -0
  185. package/dist/src/initializer/npm-client.d.ts +22 -0
  186. package/dist/src/initializer/npm-client.d.ts.map +1 -0
  187. package/dist/src/initializer/npm-client.js +65 -0
  188. package/dist/src/initializer/npm-client.js.map +1 -0
  189. package/dist/src/initializer/npm-registry.d.ts +13 -0
  190. package/dist/src/initializer/npm-registry.d.ts.map +1 -0
  191. package/dist/src/initializer/npm-registry.js +36 -0
  192. package/dist/src/initializer/npm-registry.js.map +1 -0
  193. package/dist/src/initializer/package-info.d.ts +10 -0
  194. package/dist/src/initializer/package-info.d.ts.map +1 -0
  195. package/dist/src/initializer/package-info.js +2 -0
  196. package/dist/src/initializer/package-info.js.map +1 -0
  197. package/dist/src/initializer/prompt-option.d.ts +6 -0
  198. package/dist/src/initializer/prompt-option.d.ts.map +1 -0
  199. package/dist/src/initializer/prompt-option.js +2 -0
  200. package/dist/src/initializer/prompt-option.js.map +1 -0
  201. package/dist/src/initializer/stryker-config-writer.d.ts +27 -0
  202. package/dist/src/initializer/stryker-config-writer.d.ts.map +1 -0
  203. package/dist/src/initializer/stryker-config-writer.js +106 -0
  204. package/dist/src/initializer/stryker-config-writer.js.map +1 -0
  205. package/dist/src/initializer/stryker-initializer.d.ts +45 -0
  206. package/dist/src/initializer/stryker-initializer.d.ts.map +1 -0
  207. package/dist/src/initializer/stryker-initializer.js +184 -0
  208. package/dist/src/initializer/stryker-initializer.js.map +1 -0
  209. package/dist/src/initializer/stryker-inquirer.d.ts +15 -0
  210. package/dist/src/initializer/stryker-inquirer.d.ts.map +1 -0
  211. package/dist/src/initializer/stryker-inquirer.js +72 -0
  212. package/dist/src/initializer/stryker-inquirer.js.map +1 -0
  213. package/dist/src/logging/index.d.ts +6 -0
  214. package/dist/src/logging/index.d.ts.map +1 -0
  215. package/dist/src/logging/index.js +5 -0
  216. package/dist/src/logging/index.js.map +1 -0
  217. package/dist/src/logging/logger-impl.d.ts +19 -0
  218. package/dist/src/logging/logger-impl.d.ts.map +1 -0
  219. package/dist/src/logging/logger-impl.js +64 -0
  220. package/dist/src/logging/logger-impl.js.map +1 -0
  221. package/dist/src/logging/logging-backend.d.ts +22 -0
  222. package/dist/src/logging/logging-backend.d.ts.map +1 -0
  223. package/dist/src/logging/logging-backend.js +65 -0
  224. package/dist/src/logging/logging-backend.js.map +1 -0
  225. package/dist/src/logging/logging-client.d.ts +16 -0
  226. package/dist/src/logging/logging-client.d.ts.map +1 -0
  227. package/dist/src/logging/logging-client.js +44 -0
  228. package/dist/src/logging/logging-client.js.map +1 -0
  229. package/dist/src/logging/logging-event.d.ts +23 -0
  230. package/dist/src/logging/logging-event.d.ts.map +1 -0
  231. package/dist/src/logging/logging-event.js +63 -0
  232. package/dist/src/logging/logging-event.js.map +1 -0
  233. package/dist/src/logging/logging-server.d.ts +15 -0
  234. package/dist/src/logging/logging-server.d.ts.map +1 -0
  235. package/dist/src/logging/logging-server.js +43 -0
  236. package/dist/src/logging/logging-server.js.map +1 -0
  237. package/dist/src/logging/logging-sink.d.ts +7 -0
  238. package/dist/src/logging/logging-sink.d.ts.map +1 -0
  239. package/dist/src/logging/logging-sink.js +2 -0
  240. package/dist/src/logging/logging-sink.js.map +1 -0
  241. package/dist/src/logging/priority.d.ts +12 -0
  242. package/dist/src/logging/priority.d.ts.map +1 -0
  243. package/dist/src/logging/priority.js +13 -0
  244. package/dist/src/logging/priority.js.map +1 -0
  245. package/dist/src/logging/provide-logging.d.ts +30 -0
  246. package/dist/src/logging/provide-logging.d.ts.map +1 -0
  247. package/dist/src/logging/provide-logging.js +45 -0
  248. package/dist/src/logging/provide-logging.js.map +1 -0
  249. package/dist/src/mutants/diff-statistics-collector.d.ts +14 -0
  250. package/dist/src/mutants/diff-statistics-collector.d.ts.map +1 -0
  251. package/dist/src/mutants/diff-statistics-collector.js +40 -0
  252. package/dist/src/mutants/diff-statistics-collector.js.map +1 -0
  253. package/dist/src/mutants/incremental-differ.d.ts +39 -0
  254. package/dist/src/mutants/incremental-differ.d.ts.map +1 -0
  255. package/dist/src/mutants/incremental-differ.js +547 -0
  256. package/dist/src/mutants/incremental-differ.js.map +1 -0
  257. package/dist/src/mutants/index.d.ts +4 -0
  258. package/dist/src/mutants/index.d.ts.map +1 -0
  259. package/dist/src/mutants/index.js +4 -0
  260. package/dist/src/mutants/index.js.map +1 -0
  261. package/dist/src/mutants/mutant-test-planner.d.ts +36 -0
  262. package/dist/src/mutants/mutant-test-planner.d.ts.map +1 -0
  263. package/dist/src/mutants/mutant-test-planner.js +237 -0
  264. package/dist/src/mutants/mutant-test-planner.js.map +1 -0
  265. package/dist/src/mutants/test-coverage.d.ts +22 -0
  266. package/dist/src/mutants/test-coverage.d.ts.map +1 -0
  267. package/dist/src/mutants/test-coverage.js +87 -0
  268. package/dist/src/mutants/test-coverage.js.map +1 -0
  269. package/dist/src/process/1-prepare-executor.d.ts +22 -0
  270. package/dist/src/process/1-prepare-executor.d.ts.map +1 -0
  271. package/dist/src/process/1-prepare-executor.js +86 -0
  272. package/dist/src/process/1-prepare-executor.js.map +1 -0
  273. package/dist/src/process/2-mutant-instrumenter-executor.d.ts +39 -0
  274. package/dist/src/process/2-mutant-instrumenter-executor.d.ts.map +1 -0
  275. package/dist/src/process/2-mutant-instrumenter-executor.js +58 -0
  276. package/dist/src/process/2-mutant-instrumenter-executor.js.map +1 -0
  277. package/dist/src/process/3-dry-run-executor.d.ts +50 -0
  278. package/dist/src/process/3-dry-run-executor.d.ts.map +1 -0
  279. package/dist/src/process/3-dry-run-executor.js +164 -0
  280. package/dist/src/process/3-dry-run-executor.js.map +1 -0
  281. package/dist/src/process/4-mutation-test-executor.d.ts +56 -0
  282. package/dist/src/process/4-mutation-test-executor.d.ts.map +1 -0
  283. package/dist/src/process/4-mutation-test-executor.js +152 -0
  284. package/dist/src/process/4-mutation-test-executor.js.map +1 -0
  285. package/dist/src/process/index.d.ts +5 -0
  286. package/dist/src/process/index.d.ts.map +1 -0
  287. package/dist/src/process/index.js +5 -0
  288. package/dist/src/process/index.js.map +1 -0
  289. package/dist/src/reporters/broadcast-reporter.d.ts +25 -0
  290. package/dist/src/reporters/broadcast-reporter.d.ts.map +1 -0
  291. package/dist/src/reporters/broadcast-reporter.js +74 -0
  292. package/dist/src/reporters/broadcast-reporter.js.map +1 -0
  293. package/dist/src/reporters/ci/circle-provider.d.ts +11 -0
  294. package/dist/src/reporters/ci/circle-provider.d.ts.map +1 -0
  295. package/dist/src/reporters/ci/circle-provider.js +33 -0
  296. package/dist/src/reporters/ci/circle-provider.js.map +1 -0
  297. package/dist/src/reporters/ci/github-actions-provider.d.ts +9 -0
  298. package/dist/src/reporters/ci/github-actions-provider.d.ts.map +1 -0
  299. package/dist/src/reporters/ci/github-actions-provider.js +21 -0
  300. package/dist/src/reporters/ci/github-actions-provider.js.map +1 -0
  301. package/dist/src/reporters/ci/provider.d.ts +22 -0
  302. package/dist/src/reporters/ci/provider.d.ts.map +1 -0
  303. package/dist/src/reporters/ci/provider.js +24 -0
  304. package/dist/src/reporters/ci/provider.js.map +1 -0
  305. package/dist/src/reporters/ci/travis-provider.d.ts +9 -0
  306. package/dist/src/reporters/ci/travis-provider.d.ts.map +1 -0
  307. package/dist/src/reporters/ci/travis-provider.js +19 -0
  308. package/dist/src/reporters/ci/travis-provider.js.map +1 -0
  309. package/dist/src/reporters/clear-text-reporter.d.ts +23 -0
  310. package/dist/src/reporters/clear-text-reporter.d.ts.map +1 -0
  311. package/dist/src/reporters/clear-text-reporter.js +174 -0
  312. package/dist/src/reporters/clear-text-reporter.js.map +1 -0
  313. package/dist/src/reporters/clear-text-score-table.d.ts +22 -0
  314. package/dist/src/reporters/clear-text-score-table.d.ts.map +1 -0
  315. package/dist/src/reporters/clear-text-score-table.js +191 -0
  316. package/dist/src/reporters/clear-text-score-table.js.map +1 -0
  317. package/dist/src/reporters/dashboard-reporter/dashboard-reporter-client.d.ts +19 -0
  318. package/dist/src/reporters/dashboard-reporter/dashboard-reporter-client.d.ts.map +1 -0
  319. package/dist/src/reporters/dashboard-reporter/dashboard-reporter-client.js +54 -0
  320. package/dist/src/reporters/dashboard-reporter/dashboard-reporter-client.js.map +1 -0
  321. package/dist/src/reporters/dashboard-reporter/dashboard-reporter.d.ts +21 -0
  322. package/dist/src/reporters/dashboard-reporter/dashboard-reporter.d.ts.map +1 -0
  323. package/dist/src/reporters/dashboard-reporter/dashboard-reporter.js +62 -0
  324. package/dist/src/reporters/dashboard-reporter/dashboard-reporter.js.map +1 -0
  325. package/dist/src/reporters/dashboard-reporter/index.d.ts +7 -0
  326. package/dist/src/reporters/dashboard-reporter/index.d.ts.map +1 -0
  327. package/dist/src/reporters/dashboard-reporter/index.js +15 -0
  328. package/dist/src/reporters/dashboard-reporter/index.js.map +1 -0
  329. package/dist/src/reporters/dashboard-reporter/report.d.ts +6 -0
  330. package/dist/src/reporters/dashboard-reporter/report.d.ts.map +1 -0
  331. package/dist/src/reporters/dashboard-reporter/report.js +2 -0
  332. package/dist/src/reporters/dashboard-reporter/report.js.map +1 -0
  333. package/dist/src/reporters/dashboard-reporter/tokens.d.ts +6 -0
  334. package/dist/src/reporters/dashboard-reporter/tokens.d.ts.map +1 -0
  335. package/dist/src/reporters/dashboard-reporter/tokens.js +6 -0
  336. package/dist/src/reporters/dashboard-reporter/tokens.js.map +1 -0
  337. package/dist/src/reporters/dots-reporter.d.ts +7 -0
  338. package/dist/src/reporters/dots-reporter.d.ts.map +1 -0
  339. package/dist/src/reporters/dots-reporter.js +29 -0
  340. package/dist/src/reporters/dots-reporter.js.map +1 -0
  341. package/dist/src/reporters/event-recorder-reporter.d.ts +22 -0
  342. package/dist/src/reporters/event-recorder-reporter.d.ts.map +1 -0
  343. package/dist/src/reporters/event-recorder-reporter.js +53 -0
  344. package/dist/src/reporters/event-recorder-reporter.js.map +1 -0
  345. package/dist/src/reporters/html-reporter.d.ts +14 -0
  346. package/dist/src/reporters/html-reporter.d.ts.map +1 -0
  347. package/dist/src/reporters/html-reporter.js +65 -0
  348. package/dist/src/reporters/html-reporter.js.map +1 -0
  349. package/dist/src/reporters/index.d.ts +6 -0
  350. package/dist/src/reporters/index.d.ts.map +1 -0
  351. package/dist/src/reporters/index.js +24 -0
  352. package/dist/src/reporters/index.js.map +1 -0
  353. package/dist/src/reporters/json-reporter.d.ts +15 -0
  354. package/dist/src/reporters/json-reporter.d.ts.map +1 -0
  355. package/dist/src/reporters/json-reporter.js +29 -0
  356. package/dist/src/reporters/json-reporter.js.map +1 -0
  357. package/dist/src/reporters/mutation-test-report-helper.d.ts +40 -0
  358. package/dist/src/reporters/mutation-test-report-helper.d.ts.map +1 -0
  359. package/dist/src/reporters/mutation-test-report-helper.js +298 -0
  360. package/dist/src/reporters/mutation-test-report-helper.js.map +1 -0
  361. package/dist/src/reporters/mutation-timings-reporter.d.ts +14 -0
  362. package/dist/src/reporters/mutation-timings-reporter.d.ts.map +1 -0
  363. package/dist/src/reporters/mutation-timings-reporter.js +49 -0
  364. package/dist/src/reporters/mutation-timings-reporter.js.map +1 -0
  365. package/dist/src/reporters/progress-append-only-reporter.d.ts +10 -0
  366. package/dist/src/reporters/progress-append-only-reporter.d.ts.map +1 -0
  367. package/dist/src/reporters/progress-append-only-reporter.js +25 -0
  368. package/dist/src/reporters/progress-append-only-reporter.js.map +1 -0
  369. package/dist/src/reporters/progress-bar.d.ts +8 -0
  370. package/dist/src/reporters/progress-bar.d.ts.map +1 -0
  371. package/dist/src/reporters/progress-bar.js +6 -0
  372. package/dist/src/reporters/progress-bar.js.map +1 -0
  373. package/dist/src/reporters/progress-keeper.d.ts +27 -0
  374. package/dist/src/reporters/progress-keeper.d.ts.map +1 -0
  375. package/dist/src/reporters/progress-keeper.js +77 -0
  376. package/dist/src/reporters/progress-keeper.js.map +1 -0
  377. package/dist/src/reporters/progress-reporter.d.ts +11 -0
  378. package/dist/src/reporters/progress-reporter.d.ts.map +1 -0
  379. package/dist/src/reporters/progress-reporter.js +40 -0
  380. package/dist/src/reporters/progress-reporter.js.map +1 -0
  381. package/dist/src/reporters/reporter-util.d.ts +5 -0
  382. package/dist/src/reporters/reporter-util.d.ts.map +1 -0
  383. package/dist/src/reporters/reporter-util.js +19 -0
  384. package/dist/src/reporters/reporter-util.js.map +1 -0
  385. package/dist/src/reporters/strict-reporter.d.ts +3 -0
  386. package/dist/src/reporters/strict-reporter.d.ts.map +1 -0
  387. package/dist/src/reporters/strict-reporter.js +2 -0
  388. package/dist/src/reporters/strict-reporter.js.map +1 -0
  389. package/dist/src/sandbox/create-preprocessor.d.ts +7 -0
  390. package/dist/src/sandbox/create-preprocessor.d.ts.map +1 -0
  391. package/dist/src/sandbox/create-preprocessor.js +16 -0
  392. package/dist/src/sandbox/create-preprocessor.js.map +1 -0
  393. package/dist/src/sandbox/disable-type-checks-preprocessor.d.ts +18 -0
  394. package/dist/src/sandbox/disable-type-checks-preprocessor.d.ts.map +1 -0
  395. package/dist/src/sandbox/disable-type-checks-preprocessor.js +43 -0
  396. package/dist/src/sandbox/disable-type-checks-preprocessor.js.map +1 -0
  397. package/dist/src/sandbox/file-preprocessor.d.ts +10 -0
  398. package/dist/src/sandbox/file-preprocessor.d.ts.map +1 -0
  399. package/dist/src/sandbox/file-preprocessor.js +2 -0
  400. package/dist/src/sandbox/file-preprocessor.js.map +1 -0
  401. package/dist/src/sandbox/index.d.ts +4 -0
  402. package/dist/src/sandbox/index.d.ts.map +1 -0
  403. package/dist/src/sandbox/index.js +3 -0
  404. package/dist/src/sandbox/index.js.map +1 -0
  405. package/dist/src/sandbox/multi-preprocessor.d.ts +8 -0
  406. package/dist/src/sandbox/multi-preprocessor.d.ts.map +1 -0
  407. package/dist/src/sandbox/multi-preprocessor.js +12 -0
  408. package/dist/src/sandbox/multi-preprocessor.js.map +1 -0
  409. package/dist/src/sandbox/sandbox.d.ts +43 -0
  410. package/dist/src/sandbox/sandbox.d.ts.map +1 -0
  411. package/dist/src/sandbox/sandbox.js +134 -0
  412. package/dist/src/sandbox/sandbox.js.map +1 -0
  413. package/dist/src/sandbox/ts-config-preprocessor.d.ts +46 -0
  414. package/dist/src/sandbox/ts-config-preprocessor.d.ts.map +1 -0
  415. package/dist/src/sandbox/ts-config-preprocessor.js +112 -0
  416. package/dist/src/sandbox/ts-config-preprocessor.js.map +1 -0
  417. package/dist/src/stryker-cli.d.ts +15 -0
  418. package/dist/src/stryker-cli.d.ts.map +1 -0
  419. package/dist/src/stryker-cli.js +168 -0
  420. package/dist/src/stryker-cli.js.map +1 -0
  421. package/dist/src/stryker-package.d.ts +5 -0
  422. package/dist/src/stryker-package.d.ts.map +1 -0
  423. package/dist/src/stryker-package.js +7 -0
  424. package/dist/src/stryker-package.js.map +1 -0
  425. package/dist/src/stryker-server.d.ts +40 -0
  426. package/dist/src/stryker-server.d.ts.map +1 -0
  427. package/dist/src/stryker-server.js +234 -0
  428. package/dist/src/stryker-server.js.map +1 -0
  429. package/dist/src/stryker.d.ts +31 -0
  430. package/dist/src/stryker.d.ts.map +1 -0
  431. package/dist/src/stryker.js +86 -0
  432. package/dist/src/stryker.js.map +1 -0
  433. package/dist/src/test-runner/child-process-test-runner-proxy.d.ts +19 -0
  434. package/dist/src/test-runner/child-process-test-runner-proxy.d.ts.map +1 -0
  435. package/dist/src/test-runner/child-process-test-runner-proxy.js +45 -0
  436. package/dist/src/test-runner/child-process-test-runner-proxy.js.map +1 -0
  437. package/dist/src/test-runner/child-process-test-runner-worker.d.ts +14 -0
  438. package/dist/src/test-runner/child-process-test-runner-worker.d.ts.map +1 -0
  439. package/dist/src/test-runner/child-process-test-runner-worker.js +45 -0
  440. package/dist/src/test-runner/child-process-test-runner-worker.js.map +1 -0
  441. package/dist/src/test-runner/command-test-runner.d.ts +31 -0
  442. package/dist/src/test-runner/command-test-runner.d.ts.map +1 -0
  443. package/dist/src/test-runner/command-test-runner.js +144 -0
  444. package/dist/src/test-runner/command-test-runner.js.map +1 -0
  445. package/dist/src/test-runner/index.d.ts +11 -0
  446. package/dist/src/test-runner/index.d.ts.map +1 -0
  447. package/dist/src/test-runner/index.js +18 -0
  448. package/dist/src/test-runner/index.js.map +1 -0
  449. package/dist/src/test-runner/max-test-runner-reuse-decorator.d.ts +14 -0
  450. package/dist/src/test-runner/max-test-runner-reuse-decorator.d.ts.map +1 -0
  451. package/dist/src/test-runner/max-test-runner-reuse-decorator.js +25 -0
  452. package/dist/src/test-runner/max-test-runner-reuse-decorator.js.map +1 -0
  453. package/dist/src/test-runner/reload-environment-decorator.d.ts +11 -0
  454. package/dist/src/test-runner/reload-environment-decorator.d.ts.map +1 -0
  455. package/dist/src/test-runner/reload-environment-decorator.js +56 -0
  456. package/dist/src/test-runner/reload-environment-decorator.js.map +1 -0
  457. package/dist/src/test-runner/retry-rejected-decorator.d.ts +15 -0
  458. package/dist/src/test-runner/retry-rejected-decorator.d.ts.map +1 -0
  459. package/dist/src/test-runner/retry-rejected-decorator.js +59 -0
  460. package/dist/src/test-runner/retry-rejected-decorator.js.map +1 -0
  461. package/dist/src/test-runner/test-runner-decorator.d.ts +8 -0
  462. package/dist/src/test-runner/test-runner-decorator.d.ts.map +1 -0
  463. package/dist/src/test-runner/test-runner-decorator.js +13 -0
  464. package/dist/src/test-runner/test-runner-decorator.js.map +1 -0
  465. package/dist/src/test-runner/timeout-decorator.d.ts +15 -0
  466. package/dist/src/test-runner/timeout-decorator.d.ts.map +1 -0
  467. package/dist/src/test-runner/timeout-decorator.js +51 -0
  468. package/dist/src/test-runner/timeout-decorator.js.map +1 -0
  469. package/dist/src/unexpected-exit-handler.d.ts +13 -0
  470. package/dist/src/unexpected-exit-handler.d.ts.map +1 -0
  471. package/dist/src/unexpected-exit-handler.js +28 -0
  472. package/dist/src/unexpected-exit-handler.js.map +1 -0
  473. package/dist/src/utils/file-utils.d.ts +30 -0
  474. package/dist/src/utils/file-utils.d.ts.map +1 -0
  475. package/dist/src/utils/file-utils.js +101 -0
  476. package/dist/src/utils/file-utils.js.map +1 -0
  477. package/dist/src/utils/index.d.ts +7 -0
  478. package/dist/src/utils/index.d.ts.map +1 -0
  479. package/dist/src/utils/index.js +7 -0
  480. package/dist/src/utils/index.js.map +1 -0
  481. package/dist/src/utils/json-rpc-event-deserializer.d.ts +5 -0
  482. package/dist/src/utils/json-rpc-event-deserializer.d.ts.map +1 -0
  483. package/dist/src/utils/json-rpc-event-deserializer.js +42 -0
  484. package/dist/src/utils/json-rpc-event-deserializer.js.map +1 -0
  485. package/dist/src/utils/object-utils.d.ts +37 -0
  486. package/dist/src/utils/object-utils.d.ts.map +1 -0
  487. package/dist/src/utils/object-utils.js +91 -0
  488. package/dist/src/utils/object-utils.js.map +1 -0
  489. package/dist/src/utils/string-builder.d.ts +9 -0
  490. package/dist/src/utils/string-builder.d.ts.map +1 -0
  491. package/dist/src/utils/string-builder.js +26 -0
  492. package/dist/src/utils/string-builder.js.map +1 -0
  493. package/dist/src/utils/string-utils.d.ts +12 -0
  494. package/dist/src/utils/string-utils.d.ts.map +1 -0
  495. package/dist/src/utils/string-utils.js +54 -0
  496. package/dist/src/utils/string-utils.js.map +1 -0
  497. package/dist/src/utils/temporary-directory.d.ts +18 -0
  498. package/dist/src/utils/temporary-directory.d.ts.map +1 -0
  499. package/dist/src/utils/temporary-directory.js +63 -0
  500. package/dist/src/utils/temporary-directory.js.map +1 -0
  501. package/dist/src/utils/timer.d.ts +14 -0
  502. package/dist/src/utils/timer.d.ts.map +1 -0
  503. package/dist/src/utils/timer.js +53 -0
  504. package/dist/src/utils/timer.js.map +1 -0
  505. package/package.json +106 -0
  506. package/schema/stryker-schema.json +855 -0
  507. package/src/checker/checker-child-process-proxy.ts +67 -0
  508. package/src/checker/checker-facade.ts +90 -0
  509. package/src/checker/checker-factory.ts +46 -0
  510. package/src/checker/checker-resource.ts +12 -0
  511. package/src/checker/checker-retry-decorator.ts +57 -0
  512. package/src/checker/checker-worker.ts +62 -0
  513. package/src/checker/index.ts +3 -0
  514. package/src/child-proxy/child-process-crashed-error.ts +16 -0
  515. package/src/child-proxy/child-process-proxy-worker.ts +203 -0
  516. package/src/child-proxy/child-process-proxy.ts +353 -0
  517. package/src/child-proxy/id-generator.ts +6 -0
  518. package/src/child-proxy/message-protocol.ts +87 -0
  519. package/src/child-proxy/out-of-memory-error.ts +11 -0
  520. package/src/concurrent/concurrency-token-provider.ts +106 -0
  521. package/src/concurrent/index.ts +3 -0
  522. package/src/concurrent/pool.ts +209 -0
  523. package/src/concurrent/resource-decorator.ts +28 -0
  524. package/src/config/config-file-formats.ts +31 -0
  525. package/src/config/config-reader.ts +193 -0
  526. package/src/config/file-matcher.ts +36 -0
  527. package/src/config/index.ts +5 -0
  528. package/src/config/meta-schema-builder.ts +50 -0
  529. package/src/config/options-validator.ts +317 -0
  530. package/src/config/validation-errors.ts +192 -0
  531. package/src/di/core-tokens.ts +39 -0
  532. package/src/di/index.ts +4 -0
  533. package/src/di/plugin-creator.ts +102 -0
  534. package/src/di/plugin-loader.ts +245 -0
  535. package/src/errors.ts +12 -0
  536. package/src/fs/file-system.ts +63 -0
  537. package/src/fs/index.ts +4 -0
  538. package/src/fs/project-file.ts +100 -0
  539. package/src/fs/project-reader.ts +493 -0
  540. package/src/fs/project.ts +98 -0
  541. package/src/index.ts +7 -0
  542. package/src/initializer/custom-initializers/angular-initializer.ts +95 -0
  543. package/src/initializer/custom-initializers/custom-initializer.ts +14 -0
  544. package/src/initializer/custom-initializers/index.ts +31 -0
  545. package/src/initializer/custom-initializers/react-initializer.ts +35 -0
  546. package/src/initializer/custom-initializers/svelte-initializer.ts +40 -0
  547. package/src/initializer/custom-initializers/vue-js-initializer.ts +30 -0
  548. package/src/initializer/gitignore-writer.ts +33 -0
  549. package/src/initializer/index.ts +35 -0
  550. package/src/initializer/initializer-tokens.ts +8 -0
  551. package/src/initializer/inquire.ts +17 -0
  552. package/src/initializer/npm-client.ts +103 -0
  553. package/src/initializer/npm-registry.ts +48 -0
  554. package/src/initializer/package-info.ts +10 -0
  555. package/src/initializer/prompt-option.ts +6 -0
  556. package/src/initializer/stryker-config-writer.ts +158 -0
  557. package/src/initializer/stryker-initializer.ts +278 -0
  558. package/src/initializer/stryker-inquirer.ts +101 -0
  559. package/src/logging/index.ts +5 -0
  560. package/src/logging/logger-impl.ts +81 -0
  561. package/src/logging/logging-backend.ts +90 -0
  562. package/src/logging/logging-client.ts +56 -0
  563. package/src/logging/logging-event.ts +94 -0
  564. package/src/logging/logging-server.ts +56 -0
  565. package/src/logging/logging-sink.ts +7 -0
  566. package/src/logging/priority.ts +15 -0
  567. package/src/logging/provide-logging.ts +70 -0
  568. package/src/mutants/diff-statistics-collector.ts +47 -0
  569. package/src/mutants/incremental-differ.ts +771 -0
  570. package/src/mutants/index.ts +3 -0
  571. package/src/mutants/mutant-test-planner.ts +357 -0
  572. package/src/mutants/test-coverage.ts +125 -0
  573. package/src/process/1-prepare-executor.ts +133 -0
  574. package/src/process/2-mutant-instrumenter-executor.ts +122 -0
  575. package/src/process/3-dry-run-executor.ts +262 -0
  576. package/src/process/4-mutation-test-executor.ts +272 -0
  577. package/src/process/index.ts +4 -0
  578. package/src/reporters/broadcast-reporter.ts +129 -0
  579. package/src/reporters/ci/circle-provider.ts +50 -0
  580. package/src/reporters/ci/github-actions-provider.ts +22 -0
  581. package/src/reporters/ci/provider.ts +42 -0
  582. package/src/reporters/ci/travis-provider.ts +24 -0
  583. package/src/reporters/clear-text-reporter.ts +245 -0
  584. package/src/reporters/clear-text-score-table.ts +305 -0
  585. package/src/reporters/dashboard-reporter/dashboard-reporter-client.ts +89 -0
  586. package/src/reporters/dashboard-reporter/dashboard-reporter.ts +97 -0
  587. package/src/reporters/dashboard-reporter/index.ts +30 -0
  588. package/src/reporters/dashboard-reporter/report.ts +6 -0
  589. package/src/reporters/dashboard-reporter/tokens.ts +5 -0
  590. package/src/reporters/dots-reporter.ts +33 -0
  591. package/src/reporters/event-recorder-reporter.ts +88 -0
  592. package/src/reporters/html-reporter.ts +87 -0
  593. package/src/reporters/index.ts +48 -0
  594. package/src/reporters/json-reporter.ts +45 -0
  595. package/src/reporters/mutation-test-report-helper.ts +425 -0
  596. package/src/reporters/mutation-timings-reporter.ts +78 -0
  597. package/src/reporters/progress-append-only-reporter.ts +36 -0
  598. package/src/reporters/progress-bar.ts +6 -0
  599. package/src/reporters/progress-keeper.ts +113 -0
  600. package/src/reporters/progress-reporter.ts +62 -0
  601. package/src/reporters/reporter-util.ts +20 -0
  602. package/src/reporters/strict-reporter.ts +3 -0
  603. package/src/sandbox/create-preprocessor.ts +27 -0
  604. package/src/sandbox/disable-type-checks-preprocessor.ts +70 -0
  605. package/src/sandbox/file-preprocessor.ts +10 -0
  606. package/src/sandbox/index.ts +3 -0
  607. package/src/sandbox/multi-preprocessor.ts +13 -0
  608. package/src/sandbox/sandbox.ts +198 -0
  609. package/src/sandbox/ts-config-preprocessor.ts +168 -0
  610. package/src/stryker-cli.ts +363 -0
  611. package/src/stryker-package.ts +19 -0
  612. package/src/stryker-server.ts +334 -0
  613. package/src/stryker.ts +126 -0
  614. package/src/test-runner/child-process-test-runner-proxy.ts +94 -0
  615. package/src/test-runner/child-process-test-runner-worker.ts +66 -0
  616. package/src/test-runner/command-test-runner.ts +190 -0
  617. package/src/test-runner/index.ts +74 -0
  618. package/src/test-runner/max-test-runner-reuse-decorator.ts +41 -0
  619. package/src/test-runner/reload-environment-decorator.ts +72 -0
  620. package/src/test-runner/retry-rejected-decorator.ts +79 -0
  621. package/src/test-runner/test-runner-decorator.ts +22 -0
  622. package/src/test-runner/timeout-decorator.ts +71 -0
  623. package/src/unexpected-exit-handler.ts +36 -0
  624. package/src/utils/file-utils.ts +113 -0
  625. package/src/utils/index.ts +6 -0
  626. package/src/utils/json-rpc-event-deserializer.ts +48 -0
  627. package/src/utils/object-utils.ts +106 -0
  628. package/src/utils/string-builder.ts +30 -0
  629. package/src/utils/string-utils.ts +61 -0
  630. package/src/utils/temporary-directory.ts +83 -0
  631. package/src/utils/timer.ts +58 -0
@@ -0,0 +1,771 @@
1
+ import path from 'path';
2
+
3
+ import { diff_match_patch as DiffMatchPatch } from 'diff-match-patch';
4
+ import chalk from 'chalk';
5
+ import {
6
+ schema,
7
+ Mutant,
8
+ Position,
9
+ Location,
10
+ StrykerOptions,
11
+ FileDescriptions,
12
+ MutateDescription,
13
+ } from '@stryker-mutator/api/core';
14
+ import { Logger } from '@stryker-mutator/api/logging';
15
+ import { TestResult, TestStatus } from '@stryker-mutator/api/test-runner';
16
+ import {
17
+ I,
18
+ normalizeFileName,
19
+ normalizeLineEndings,
20
+ notEmpty,
21
+ } from '@stryker-mutator/util';
22
+ import { TestDefinition } from 'mutation-testing-report-schema';
23
+ import { commonTokens } from '@stryker-mutator/api/plugin';
24
+
25
+ import {
26
+ DiffChange,
27
+ DiffStatisticsCollector,
28
+ } from './diff-statistics-collector.js';
29
+ import { TestCoverage } from './test-coverage.js';
30
+
31
+ /**
32
+ * The 'diff match patch' high-performant 'diffing' of files.
33
+ * @see https://github.com/google/diff-match-patch
34
+ */
35
+ const diffMatchPatch = new DiffMatchPatch();
36
+
37
+ /**
38
+ * This class is responsible for calculating the diff between a run and a previous run based on the incremental report.
39
+ *
40
+ * Since the ids of tests and mutants can differ across reports (they are only unique within 1 report), this class
41
+ * identifies mutants and tests by attributes that make them unique:
42
+ * - Mutant: file name, mutator name, location and replacement
43
+ * - Test: test name, test file name (if present) and location (if present).
44
+ *
45
+ * We're storing these identifiers in local variables (maps and sets) as strings.
46
+ * We should move to 'records' for these when they come available: https://github.com/tc39/proposal-record-tuple
47
+ *
48
+ * A mutant result from the previous run is reused if the following conditions were met:
49
+ * - The location of the mutant refers to a piece of code that didn't change
50
+ * - If mutant was killed:
51
+ * - The culprit test wasn't changed
52
+ * - If the mutant survived:
53
+ * - No test was added
54
+ *
55
+ * It uses google's "diff-match-patch" project to calculate the new locations for tests and mutants, see link.
56
+ * @link https://github.com/google/diff-match-patch
57
+ */
58
+ export class IncrementalDiffer {
59
+ public mutantStatisticsCollector: DiffStatisticsCollector | undefined;
60
+ public testStatisticsCollector: DiffStatisticsCollector | undefined;
61
+ private readonly mutateDescriptionByRelativeFileName: Map<
62
+ string,
63
+ MutateDescription
64
+ >;
65
+
66
+ public static inject = [
67
+ commonTokens.logger,
68
+ commonTokens.options,
69
+ commonTokens.fileDescriptions,
70
+ ] as const;
71
+ constructor(
72
+ private readonly logger: Logger,
73
+ private readonly options: StrykerOptions,
74
+ fileDescriptions: FileDescriptions,
75
+ ) {
76
+ this.mutateDescriptionByRelativeFileName = new Map(
77
+ Object.entries(fileDescriptions).map(([name, description]) => [
78
+ toRelativeNormalizedFileName(name),
79
+ description.mutate,
80
+ ]),
81
+ );
82
+ }
83
+
84
+ private isInMutatedScope(
85
+ relativeFileName: string,
86
+ mutant: schema.MutantResult,
87
+ ): boolean {
88
+ const mutate =
89
+ this.mutateDescriptionByRelativeFileName.get(relativeFileName);
90
+ return (
91
+ mutate === true ||
92
+ (Array.isArray(mutate) &&
93
+ mutate.some((range) => locationIncluded(range, mutant.location)))
94
+ );
95
+ }
96
+
97
+ public diff(
98
+ currentMutants: readonly Mutant[],
99
+ testCoverage: I<TestCoverage>,
100
+ incrementalReport: schema.MutationTestResult,
101
+ currentRelativeFiles: Map<string, string>,
102
+ ): readonly Mutant[] {
103
+ const { files, testFiles } = incrementalReport;
104
+ const mutantStatisticsCollector = new DiffStatisticsCollector();
105
+ const testStatisticsCollector = new DiffStatisticsCollector();
106
+
107
+ // Expose the collectors for unit testing purposes
108
+ this.mutantStatisticsCollector = mutantStatisticsCollector;
109
+ this.testStatisticsCollector = testStatisticsCollector;
110
+
111
+ // Collect what we can reuse, while correcting for diff in the locations
112
+ const reusableMutantsByKey = collectReusableMutantsByKey(this.logger);
113
+ const { byId: oldTestsById, byKey: oldTestInfoByKey } =
114
+ collectReusableTestInfo(this.logger);
115
+
116
+ // Collect some helper maps and sets
117
+ const {
118
+ oldCoverageByMutantKey: oldCoverageTestKeysByMutantKey,
119
+ oldKilledByMutantKey: oldKilledTestKeysByMutantKey,
120
+ } = collectOldKilledAndCoverageMatrix();
121
+ const oldTestKeys = new Set(
122
+ [...oldTestsById.values()].map(({ key }) => key),
123
+ );
124
+ const newTestKeys = new Set(
125
+ [...testCoverage.testsById].map(([, test]) =>
126
+ testToIdentifyingKey(test, toRelativeNormalizedFileName(test.fileName)),
127
+ ),
128
+ );
129
+
130
+ // Create a dictionary to more easily get test information
131
+ const testInfoByKey = collectCurrentTestInfo();
132
+
133
+ // Mark which tests are added
134
+ for (const [key, { relativeFileName }] of testInfoByKey) {
135
+ if (!oldTestKeys.has(key)) {
136
+ testStatisticsCollector.count(relativeFileName, 'added');
137
+ }
138
+ }
139
+
140
+ // Make sure that tests that didn't run this time around aren't forgotten
141
+ for (const [
142
+ testKey,
143
+ {
144
+ test: { name, location },
145
+ relativeFileName,
146
+ },
147
+ ] of oldTestInfoByKey) {
148
+ if (!testInfoByKey.has(testKey)) {
149
+ const test: TestResult = {
150
+ status: TestStatus.Success,
151
+ id: testKey,
152
+ name,
153
+ startPosition: location?.start,
154
+ timeSpentMs: 0,
155
+ fileName: path.resolve(relativeFileName),
156
+ };
157
+ testInfoByKey.set(testKey, {
158
+ test,
159
+ relativeFileName: relativeFileName,
160
+ });
161
+ testCoverage.addTest(test);
162
+ }
163
+ }
164
+
165
+ // Done with preparations, time to map over the mutants
166
+ let reusedMutantCount = 0;
167
+ const currentMutantKeys = new Set<string>();
168
+ const mutants = currentMutants.map((mutant) => {
169
+ const relativeFileName = toRelativeNormalizedFileName(mutant.fileName);
170
+ const mutantKey = mutantToIdentifyingKey(mutant, relativeFileName);
171
+ currentMutantKeys.add(mutantKey);
172
+ if (!mutant.status && !this.options.force) {
173
+ const oldMutant = reusableMutantsByKey.get(mutantKey);
174
+ if (oldMutant) {
175
+ const coveringTests = testCoverage.forMutant(mutant.id);
176
+ const killedByTestKeys = oldKilledTestKeysByMutantKey.get(mutantKey);
177
+ if (
178
+ mutantCanBeReused(
179
+ mutant,
180
+ oldMutant,
181
+ mutantKey,
182
+ coveringTests,
183
+ killedByTestKeys,
184
+ )
185
+ ) {
186
+ reusedMutantCount++;
187
+ const { status, statusReason, testsCompleted } = oldMutant;
188
+ const executedTests = (oldMutant as { executedTests?: unknown })
189
+ .executedTests;
190
+ return {
191
+ ...mutant,
192
+ status,
193
+ statusReason,
194
+ testsCompleted,
195
+ executedTests,
196
+ coveredBy: [...(coveringTests ?? [])].map(({ id }) => id),
197
+ killedBy: testKeysToId(killedByTestKeys),
198
+ };
199
+ }
200
+ } else {
201
+ mutantStatisticsCollector.count(relativeFileName, 'added');
202
+ }
203
+ }
204
+ return mutant;
205
+ });
206
+
207
+ // Make sure that old mutants that didn't run this time around aren't forgotten
208
+
209
+ for (const [mutantKey, oldResult] of reusableMutantsByKey) {
210
+ // Do an additional check to see if the mutant is in mutated range.
211
+ //
212
+ // For example:
213
+ // ```diff
214
+ // - return a || b;
215
+ // + return a && b;
216
+ // ```
217
+ // The conditional expression mutator here decides to _not_ mutate b to `false` the second time around. (even though the text of "b" itself didn't change)
218
+ // Not doing this additional check would result in a sticky mutant that is never removed
219
+ if (
220
+ !currentMutantKeys.has(mutantKey) &&
221
+ !this.isInMutatedScope(oldResult.relativeFileName, oldResult)
222
+ ) {
223
+ const coverage = oldCoverageTestKeysByMutantKey.get(mutantKey) ?? [];
224
+ const killed = oldKilledTestKeysByMutantKey.get(mutantKey) ?? [];
225
+ const coveredBy = testKeysToId(coverage);
226
+ const killedBy = testKeysToId(killed);
227
+ const reusedMutant = {
228
+ ...oldResult,
229
+ id: mutantKey,
230
+ fileName: path.resolve(oldResult.relativeFileName),
231
+ replacement: oldResult.replacement ?? oldResult.mutatorName,
232
+ coveredBy,
233
+ killedBy,
234
+ };
235
+ mutants.push(reusedMutant);
236
+ testCoverage.addCoverage(reusedMutant.id, coveredBy);
237
+ }
238
+ }
239
+
240
+ if (this.logger.isInfoEnabled()) {
241
+ const testInfo = testCoverage.hasCoverage
242
+ ? `\n\tTests:\t\t${testStatisticsCollector.createTotalsReport()}`
243
+ : '';
244
+ this.logger.info(
245
+ `Incremental report:\n\tMutants:\t${mutantStatisticsCollector.createTotalsReport()}` +
246
+ testInfo +
247
+ `\n\tResult:\t\t${chalk.yellowBright(reusedMutantCount)} of ${currentMutants.length} mutant result(s) are reused.`,
248
+ );
249
+ }
250
+ if (this.logger.isDebugEnabled()) {
251
+ const lineSeparator = '\n\t\t';
252
+ const noChanges = 'No changes';
253
+ const detailedMutantSummary = `${lineSeparator}${mutantStatisticsCollector.createDetailedReport().join(lineSeparator) || noChanges}`;
254
+ const detailedTestsSummary = `${lineSeparator}${testStatisticsCollector.createDetailedReport().join(lineSeparator) || noChanges}`;
255
+ this.logger.debug(
256
+ `Detailed incremental report:\n\tMutants: ${detailedMutantSummary}\n\tTests: ${detailedTestsSummary}`,
257
+ );
258
+ }
259
+ return mutants;
260
+
261
+ function testKeysToId(testKeys: Iterable<string> | undefined) {
262
+ return [...(testKeys ?? [])]
263
+ .map((id) => testInfoByKey.get(id))
264
+ .filter(notEmpty)
265
+ .map(({ test: { id } }) => id);
266
+ }
267
+
268
+ function collectReusableMutantsByKey(log: Logger) {
269
+ return new Map(
270
+ Object.entries(files).flatMap(([fileName, oldFile]) => {
271
+ const relativeFileName = toRelativeNormalizedFileName(fileName);
272
+ const currentFileSource = currentRelativeFiles.get(relativeFileName);
273
+ if (currentFileSource) {
274
+ log.trace('Diffing %s', relativeFileName);
275
+ const { results, removeCount } = performFileDiff(
276
+ oldFile.source,
277
+ currentFileSource,
278
+ oldFile.mutants,
279
+ );
280
+ mutantStatisticsCollector.count(
281
+ relativeFileName,
282
+ 'removed',
283
+ removeCount,
284
+ );
285
+ return results.map((m) => [
286
+ mutantToIdentifyingKey(m, relativeFileName),
287
+ {
288
+ ...m,
289
+ relativeFileName,
290
+ },
291
+ ]);
292
+ }
293
+ mutantStatisticsCollector.count(
294
+ relativeFileName,
295
+ 'removed',
296
+ oldFile.mutants.length,
297
+ );
298
+ // File has since been deleted, these mutants are not reused
299
+ return [];
300
+ }),
301
+ );
302
+ }
303
+
304
+ function collectReusableTestInfo(log: Logger) {
305
+ const byId = new Map<
306
+ string,
307
+ { relativeFileName: string; test: TestDefinition; key: string }
308
+ >();
309
+ const byKey = new Map<string, TestInfo>();
310
+
311
+ Object.entries(testFiles ?? {}).forEach(([fileName, oldTestFile]) => {
312
+ const relativeFileName = toRelativeNormalizedFileName(fileName);
313
+ const currentFileSource = currentRelativeFiles.get(relativeFileName);
314
+ if (currentFileSource === undefined && fileName !== '') {
315
+ // An empty file name means the test runner cannot report test file locations.
316
+ // If the current file is undefined while the test runner can report test file locations, it means it has been deleted
317
+ log.debug('Test file removed: %s', relativeFileName);
318
+ testStatisticsCollector.count(
319
+ relativeFileName,
320
+ 'removed',
321
+ oldTestFile.tests.length,
322
+ );
323
+ } else if (
324
+ currentFileSource !== undefined &&
325
+ oldTestFile.source !== undefined
326
+ ) {
327
+ log.trace('Diffing %s', relativeFileName);
328
+ const locatedTests = closeLocations(oldTestFile);
329
+ const { results, removeCount } = performFileDiff(
330
+ oldTestFile.source,
331
+ currentFileSource,
332
+ locatedTests,
333
+ );
334
+ testStatisticsCollector.count(
335
+ relativeFileName,
336
+ 'removed',
337
+ removeCount,
338
+ );
339
+ results.forEach((test) => {
340
+ const key = testToIdentifyingKey(test, relativeFileName);
341
+ const testInfo = { key, test, relativeFileName };
342
+ byId.set(test.id, testInfo);
343
+ byKey.set(key, testInfo);
344
+ });
345
+ } else {
346
+ // No sources to compare, we should do our best with the info we do have
347
+ oldTestFile.tests.map((test) => {
348
+ const key = testToIdentifyingKey(test, relativeFileName);
349
+ const testInfo = { key, test, relativeFileName };
350
+ byId.set(test.id, testInfo);
351
+ byKey.set(key, testInfo);
352
+ });
353
+ }
354
+ });
355
+ return { byId, byKey };
356
+ }
357
+
358
+ function collectOldKilledAndCoverageMatrix() {
359
+ const oldCoverageByMutantKey = new Map<string, Set<string>>();
360
+ const oldKilledByMutantKey = new Map<string, Set<string>>();
361
+
362
+ for (const [key, mutant] of reusableMutantsByKey) {
363
+ const killedRow = new Set(
364
+ mutant.killedBy
365
+ ?.map((testId) => oldTestsById.get(testId)?.key)
366
+ .filter(notEmpty),
367
+ );
368
+ const coverageRow = new Set(
369
+ mutant.coveredBy
370
+ ?.map((testId) => oldTestsById.get(testId)?.key)
371
+ .filter(notEmpty),
372
+ );
373
+ killedRow.forEach((killed) => coverageRow.add(killed));
374
+ oldCoverageByMutantKey.set(key, coverageRow);
375
+ oldKilledByMutantKey.set(key, killedRow);
376
+ }
377
+ return { oldCoverageByMutantKey, oldKilledByMutantKey };
378
+ }
379
+
380
+ function collectCurrentTestInfo() {
381
+ const byTestKey = new Map<
382
+ string,
383
+ { relativeFileName: string; test: TestResult }
384
+ >();
385
+ for (const testResult of testCoverage.testsById.values()) {
386
+ const relativeFileName = toRelativeNormalizedFileName(
387
+ testResult.fileName,
388
+ );
389
+ const key = testToIdentifyingKey(testResult, relativeFileName);
390
+ const info = { relativeFileName, test: testResult, key: key };
391
+ byTestKey.set(key, info);
392
+ }
393
+
394
+ return byTestKey;
395
+ }
396
+
397
+ function mutantCanBeReused(
398
+ mutant: Mutant,
399
+ oldMutant: schema.MutantResult,
400
+ mutantKey: string,
401
+ coveringTests: ReadonlySet<TestResult> | undefined,
402
+ oldKillingTests: Set<string> | undefined,
403
+ ): boolean {
404
+ if (!testCoverage.hasCoverage) {
405
+ // This is the best we can do when the test runner didn't report coverage.
406
+ // We assume that all mutant test results can be reused,
407
+ // End users can use --force to force retesting of certain mutants
408
+ return true;
409
+ }
410
+ if (oldMutant.status === 'Ignored') {
411
+ // Was previously ignored, but not anymore, we need to run it now
412
+ return false;
413
+ }
414
+
415
+ const testsDiff = diffTestCoverage(
416
+ mutant.id,
417
+ oldCoverageTestKeysByMutantKey.get(mutantKey),
418
+ coveringTests,
419
+ );
420
+ if (oldMutant.status === 'Killed') {
421
+ if (oldKillingTests) {
422
+ for (const killingTest of oldKillingTests) {
423
+ if (testsDiff.get(killingTest) === 'same') {
424
+ return true;
425
+ }
426
+ }
427
+ }
428
+ // Killing tests has changed or no longer exists
429
+ return false;
430
+ }
431
+ for (const action of testsDiff.values()) {
432
+ if (action === 'added') {
433
+ // A non-killed mutant got a new test, we need to run it
434
+ return false;
435
+ }
436
+ }
437
+ // A non-killed mutant did not get new tests, no need to rerun it
438
+ return true;
439
+ }
440
+
441
+ /**
442
+ * Determines if there is a diff between old test coverage and new test coverage.
443
+ */
444
+ function diffTestCoverage(
445
+ mutantId: string,
446
+ oldCoveringTestKeys: Set<string> | undefined,
447
+ newCoveringTests: ReadonlySet<TestResult> | undefined,
448
+ ): Map<string, DiffAction> {
449
+ const result = new Map<string, DiffAction>();
450
+ if (newCoveringTests) {
451
+ for (const newTest of newCoveringTests) {
452
+ const key = testToIdentifyingKey(
453
+ newTest,
454
+ toRelativeNormalizedFileName(newTest.fileName),
455
+ );
456
+ result.set(key, oldCoveringTestKeys?.has(key) ? 'same' : 'added');
457
+ }
458
+ }
459
+ if (oldCoveringTestKeys) {
460
+ const isStatic = testCoverage.hasStaticCoverage(mutantId);
461
+ for (const oldTestKey of oldCoveringTestKeys) {
462
+ if (!result.has(oldTestKey)) {
463
+ // Static mutants might not have covering tests, but the test might still exist
464
+ if (isStatic && newTestKeys.has(oldTestKey)) {
465
+ result.set(oldTestKey, 'same');
466
+ } else {
467
+ result.set(oldTestKey, 'removed');
468
+ }
469
+ }
470
+ }
471
+ }
472
+ return result;
473
+ }
474
+ }
475
+ }
476
+
477
+ /**
478
+ * Finds the diff of mutants and tests. Removes mutants / tests that no longer exist (changed or removed). Updates locations of mutants or tests that do still exist.
479
+ * @param oldCode The old code to use for the diff
480
+ * @param newCode The new (current) code to use for the diff
481
+ * @param items The mutants or tests to be looked . These will be treated as immutable.
482
+ * @returns A list of items with updated locations, without items that are changed.
483
+ */
484
+ function performFileDiff<T extends { location: Location }>(
485
+ oldCode: string,
486
+ newCode: string,
487
+ items: T[],
488
+ ): { results: T[]; removeCount: number } {
489
+ const oldSourceNormalized = normalizeLineEndings(oldCode);
490
+ const currentSrcNormalized = normalizeLineEndings(newCode);
491
+ const diffChanges = diffMatchPatch.diff_main(
492
+ oldSourceNormalized,
493
+ currentSrcNormalized,
494
+ );
495
+
496
+ const toDo = new Set(
497
+ items.map((m) => ({ ...m, location: deepClone(m.location) })),
498
+ );
499
+ const [added, removed] = [1, -1];
500
+ const done: T[] = [];
501
+ const currentPosition: Position = { column: 0, line: 0 };
502
+ let removeCount = 0;
503
+ for (const [change, text] of diffChanges) {
504
+ if (toDo.size === 0) {
505
+ // There are more changes, but nothing left to update.
506
+ break;
507
+ }
508
+ const offset = calculateOffset(text);
509
+ if (change === added) {
510
+ for (const test of toDo) {
511
+ const { location } = test;
512
+ if (
513
+ gte(currentPosition, location.start) &&
514
+ gte(location.end, currentPosition)
515
+ ) {
516
+ // This item cannot be reused, code was added here
517
+ removeCount++;
518
+ toDo.delete(test);
519
+ } else {
520
+ locationAdd(
521
+ location,
522
+ offset,
523
+ currentPosition.line === location.start.line,
524
+ );
525
+ }
526
+ }
527
+ positionMove(currentPosition, offset);
528
+ } else if (change === removed) {
529
+ for (const item of toDo) {
530
+ const {
531
+ location: { start },
532
+ } = item;
533
+ const endOffset = positionMove({ ...currentPosition }, offset);
534
+ if (gte(endOffset, start)) {
535
+ // This item cannot be reused, the code it covers has changed
536
+ removeCount++;
537
+ toDo.delete(item);
538
+ } else {
539
+ locationAdd(
540
+ item.location,
541
+ negate(offset),
542
+ currentPosition.line === start.line,
543
+ );
544
+ }
545
+ }
546
+ } else {
547
+ positionMove(currentPosition, offset);
548
+ toDo.forEach((item) => {
549
+ const { end } = item.location;
550
+ if (gte(currentPosition, end)) {
551
+ // We're done with this item, it can be reused
552
+ toDo.delete(item);
553
+ done.push(item);
554
+ }
555
+ });
556
+ }
557
+ }
558
+ done.push(...toDo);
559
+ return { results: done, removeCount };
560
+ }
561
+
562
+ /**
563
+ * A greater-than-equals implementation for positions
564
+ */
565
+ function gte(a: Position, b: Position) {
566
+ return a.line > b.line || (a.line === b.line && a.column >= b.column);
567
+ }
568
+
569
+ function locationIncluded(haystack: Location, needle: Location) {
570
+ const startIncluded = gte(needle.start, haystack.start);
571
+ const endIncluded = gte(haystack.end, needle.end);
572
+ return startIncluded && endIncluded;
573
+ }
574
+
575
+ function deepClone(loc: Location): Location {
576
+ return { start: { ...loc.start }, end: { ...loc.end } };
577
+ }
578
+
579
+ /**
580
+ * Reduces a mutant to a string that identifies the mutant across reports.
581
+ * Consists of the relative file name, mutator name, replacement, and location
582
+ */
583
+ function mutantToIdentifyingKey(
584
+ {
585
+ mutatorName,
586
+ replacement,
587
+ location: { start, end },
588
+ }: Pick<Mutant, 'location' | 'mutatorName'> & { replacement?: string },
589
+ relativeFileName: string,
590
+ ) {
591
+ return `${relativeFileName}@${start.line}:${start.column}-${end.line}:${end.column}\n${mutatorName}: ${replacement}`;
592
+ }
593
+
594
+ function testToIdentifyingKey(
595
+ {
596
+ name,
597
+ location,
598
+ startPosition,
599
+ }: Pick<schema.TestDefinition, 'location' | 'name'> &
600
+ Pick<TestResult, 'startPosition'>,
601
+ relativeFileName: string | undefined,
602
+ ) {
603
+ startPosition = startPosition ?? location?.start ?? { line: 0, column: 0 };
604
+ return `${relativeFileName}@${startPosition.line}:${startPosition.column}\n${name}`;
605
+ }
606
+
607
+ export function toRelativeNormalizedFileName(
608
+ fileName: string | undefined,
609
+ ): string {
610
+ return normalizeFileName(path.relative(process.cwd(), fileName ?? ''));
611
+ }
612
+
613
+ function calculateOffset(text: string): Position {
614
+ const pos: Position = { line: 0, column: 0 };
615
+ for (const char of text) {
616
+ if (char === '\n') {
617
+ pos.line++;
618
+ pos.column = 0;
619
+ } else {
620
+ pos.column++;
621
+ }
622
+ }
623
+ return pos;
624
+ }
625
+
626
+ function positionMove(pos: Position, diff: Position): Position {
627
+ pos.line += diff.line;
628
+ if (diff.line === 0) {
629
+ pos.column += diff.column;
630
+ } else {
631
+ pos.column = diff.column;
632
+ }
633
+ return pos;
634
+ }
635
+
636
+ function locationAdd(
637
+ { start, end }: Location,
638
+ { line, column }: Position,
639
+ currentLine: boolean,
640
+ ) {
641
+ start.line += line;
642
+ if (currentLine) {
643
+ start.column += column;
644
+ }
645
+ end.line += line;
646
+ if (line === 0 && currentLine) {
647
+ end.column += column;
648
+ }
649
+ }
650
+
651
+ function negate({ line, column }: Position): Position {
652
+ return { line: -1 * line, column: -1 * column };
653
+ }
654
+
655
+ interface TestInfo {
656
+ relativeFileName: string;
657
+ test: TestDefinition;
658
+ key: string;
659
+ }
660
+
661
+ type DiffAction = DiffChange | 'same';
662
+
663
+ /**
664
+ * Sets the end position of each test to the start position of the next test.
665
+ * This is an educated guess and necessary.
666
+ * If a test has no location, it is assumed it spans the entire file (line 0 to Infinity)
667
+ *
668
+ * Knowing the end location of tests is necessary in order to know if the test was changed.
669
+ */
670
+ function closeLocations(testFile: schema.TestFile): LocatedTest[] {
671
+ const locatedTests: LocatedTest[] = [];
672
+ const openEndedTests: OpenEndedTest[] = [];
673
+
674
+ testFile.tests.forEach((test) => {
675
+ if (testHasLocation(test)) {
676
+ if (isClosed(test)) {
677
+ locatedTests.push(test);
678
+ } else {
679
+ openEndedTests.push(test);
680
+ }
681
+ } else {
682
+ locatedTests.push({
683
+ ...test,
684
+ location: {
685
+ start: { line: 0, column: 0 },
686
+ end: { line: Number.POSITIVE_INFINITY, column: 0 },
687
+ },
688
+ });
689
+ }
690
+ });
691
+
692
+ if (openEndedTests.length) {
693
+ // Sort the opened tests in order to close their locations
694
+ openEndedTests.sort(
695
+ (a, b) => a.location.start.line - b.location.start.line,
696
+ );
697
+ const openEndedTestSet = new Set(openEndedTests);
698
+ const startPositions = uniqueStartPositions(openEndedTests);
699
+
700
+ let currentPositionIndex = 0;
701
+ openEndedTestSet.forEach((test) => {
702
+ if (
703
+ eqPosition(test.location.start, startPositions[currentPositionIndex])
704
+ ) {
705
+ currentPositionIndex++;
706
+ }
707
+ if (startPositions[currentPositionIndex]) {
708
+ locatedTests.push({
709
+ ...test,
710
+ location: {
711
+ start: test.location.start,
712
+ end: startPositions[currentPositionIndex],
713
+ },
714
+ });
715
+ openEndedTestSet.delete(test);
716
+ }
717
+ });
718
+
719
+ // Don't forget about the last tests
720
+ openEndedTestSet.forEach((lastTest) => {
721
+ locatedTests.push({
722
+ ...lastTest,
723
+ location: {
724
+ start: lastTest.location.start,
725
+ end: { line: Number.POSITIVE_INFINITY, column: 0 },
726
+ },
727
+ });
728
+ });
729
+ }
730
+
731
+ return locatedTests;
732
+ }
733
+
734
+ /**
735
+ * Determines the unique start positions of a sorted list of tests in order
736
+ */
737
+ function uniqueStartPositions(sortedTests: OpenEndedTest[]) {
738
+ let current: Position | undefined;
739
+ const startPositions = sortedTests.reduce<Position[]>(
740
+ (collector, { location: { start } }) => {
741
+ if (
742
+ !current ||
743
+ current.line !== start.line ||
744
+ current.column !== start.column
745
+ ) {
746
+ current = start;
747
+ collector.push(current);
748
+ }
749
+ return collector;
750
+ },
751
+ [],
752
+ );
753
+ return startPositions;
754
+ }
755
+
756
+ function testHasLocation(test: schema.TestDefinition): test is OpenEndedTest {
757
+ return !!test.location?.start;
758
+ }
759
+
760
+ function isClosed(test: Required<schema.TestDefinition>): test is LocatedTest {
761
+ return !!test.location.end;
762
+ }
763
+
764
+ function eqPosition(start: Position, end?: Position): boolean {
765
+ return start.column === end?.column && start.line === end.line;
766
+ }
767
+
768
+ type LocatedTest = schema.TestDefinition & { location: Location };
769
+ type OpenEndedTest = schema.TestDefinition & {
770
+ location: schema.OpenEndLocation;
771
+ };