@hominis/fireforge 0.49.2 → 0.51.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 (400) hide show
  1. package/CHANGELOG.md +87 -1
  2. package/README.md +1 -1
  3. package/dist/bin/fireforge.js +6 -0
  4. package/dist/build-info.json +4 -4
  5. package/dist/src/commands/build-prelock.d.ts +20 -0
  6. package/dist/src/commands/build-prelock.js +50 -0
  7. package/dist/src/commands/build.d.ts +3 -1
  8. package/dist/src/commands/build.js +13 -6
  9. package/dist/src/commands/check-report.d.ts +41 -0
  10. package/dist/src/commands/check-report.js +91 -0
  11. package/dist/src/commands/check-run.d.ts +33 -0
  12. package/dist/src/commands/check-run.js +112 -0
  13. package/dist/src/commands/check-steps.d.ts +75 -0
  14. package/dist/src/commands/check-steps.js +200 -0
  15. package/dist/src/commands/check.d.ts +32 -0
  16. package/dist/src/commands/check.js +160 -0
  17. package/dist/src/commands/config.js +5 -6
  18. package/dist/src/commands/declarations-report.d.ts +43 -0
  19. package/dist/src/commands/declarations-report.js +76 -0
  20. package/dist/src/commands/doctor-engine-eslint.js +6 -1
  21. package/dist/src/commands/doctor-source-pin.js +4 -1
  22. package/dist/src/commands/export-adopt-check.d.ts +38 -0
  23. package/dist/src/commands/export-adopt-check.js +98 -0
  24. package/dist/src/commands/export-flow.js +29 -14
  25. package/dist/src/commands/export-placement-gate.d.ts +6 -2
  26. package/dist/src/commands/export-placement-gate.js +8 -0
  27. package/dist/src/commands/export-shared.d.ts +2 -1
  28. package/dist/src/commands/export-staged-registration.d.ts +46 -0
  29. package/dist/src/commands/export-staged-registration.js +91 -0
  30. package/dist/src/commands/forward-import-remedy.d.ts +32 -0
  31. package/dist/src/commands/forward-import-remedy.js +63 -0
  32. package/dist/src/commands/furnace/apply.js +3 -3
  33. package/dist/src/commands/furnace/chrome-doc-remove.d.ts +2 -1
  34. package/dist/src/commands/furnace/chrome-doc-remove.js +2 -2
  35. package/dist/src/commands/furnace/chrome-doc.d.ts +2 -1
  36. package/dist/src/commands/furnace/chrome-doc.js +2 -2
  37. package/dist/src/commands/furnace/create.js +2 -2
  38. package/dist/src/commands/furnace/deploy-named.d.ts +48 -0
  39. package/dist/src/commands/furnace/deploy-named.js +107 -0
  40. package/dist/src/commands/furnace/deploy.d.ts +3 -2
  41. package/dist/src/commands/furnace/deploy.js +50 -86
  42. package/dist/src/commands/furnace/diff.js +26 -3
  43. package/dist/src/commands/furnace/index.js +66 -41
  44. package/dist/src/commands/furnace/init.js +13 -6
  45. package/dist/src/commands/furnace/override.js +4 -2
  46. package/dist/src/commands/furnace/preview.js +4 -3
  47. package/dist/src/commands/furnace/refresh.js +2 -2
  48. package/dist/src/commands/furnace/remove.js +4 -3
  49. package/dist/src/commands/furnace/rename-dry-run.d.ts +29 -0
  50. package/dist/src/commands/furnace/rename-dry-run.js +127 -0
  51. package/dist/src/commands/furnace/rename-helpers.d.ts +7 -0
  52. package/dist/src/commands/furnace/rename-helpers.js +15 -1
  53. package/dist/src/commands/furnace/rename-registrations.d.ts +41 -0
  54. package/dist/src/commands/furnace/rename-registrations.js +98 -0
  55. package/dist/src/commands/furnace/rename.d.ts +2 -1
  56. package/dist/src/commands/furnace/rename.js +28 -66
  57. package/dist/src/commands/furnace/scan.d.ts +9 -4
  58. package/dist/src/commands/furnace/scan.js +11 -9
  59. package/dist/src/commands/furnace/sync.js +3 -2
  60. package/dist/src/commands/furnace/validate-report.d.ts +45 -0
  61. package/dist/src/commands/furnace/validate-report.js +91 -0
  62. package/dist/src/commands/furnace/validate.d.ts +1 -1
  63. package/dist/src/commands/furnace/validate.js +151 -113
  64. package/dist/src/commands/furnace/validation-output.js +14 -3
  65. package/dist/src/commands/lint-per-patch.js +36 -61
  66. package/dist/src/commands/lint-per-run-checkjs.js +2 -2
  67. package/dist/src/commands/lint-report.d.ts +8 -4
  68. package/dist/src/commands/lint-report.js +20 -5
  69. package/dist/src/commands/lint.js +15 -34
  70. package/dist/src/commands/manifest.js +4 -0
  71. package/dist/src/commands/park.d.ts +22 -0
  72. package/dist/src/commands/park.js +232 -0
  73. package/dist/src/commands/patch/delete-gap-notice.js +3 -1
  74. package/dist/src/commands/patch/delete.d.ts +1 -1
  75. package/dist/src/commands/patch/delete.js +24 -104
  76. package/dist/src/commands/patch/index.d.ts +3 -3
  77. package/dist/src/commands/patch/index.js +10 -4
  78. package/dist/src/commands/patch/lint-ignore-from.d.ts +44 -0
  79. package/dist/src/commands/patch/lint-ignore-from.js +142 -0
  80. package/dist/src/commands/patch/lint-ignore.d.ts +5 -1
  81. package/dist/src/commands/patch/lint-ignore.js +78 -31
  82. package/dist/src/commands/patch/move-files-create.js +34 -18
  83. package/dist/src/commands/patch/move-files-into.js +15 -7
  84. package/dist/src/commands/patch/move-files.js +6 -2
  85. package/dist/src/commands/patch/removal-created-files.d.ts +48 -0
  86. package/dist/src/commands/patch/removal-created-files.js +83 -0
  87. package/dist/src/commands/patch/removal-dependents.d.ts +63 -0
  88. package/dist/src/commands/patch/removal-dependents.js +133 -0
  89. package/dist/src/commands/patch/rename.js +20 -1
  90. package/dist/src/commands/patch/reserve.d.ts +33 -0
  91. package/dist/src/commands/patch/reserve.js +152 -0
  92. package/dist/src/commands/patch/retire.d.ts +34 -0
  93. package/dist/src/commands/patch/retire.js +133 -0
  94. package/dist/src/commands/patch/split-plan.d.ts +17 -8
  95. package/dist/src/commands/patch/split-plan.js +60 -28
  96. package/dist/src/commands/patch/split-staged.d.ts +108 -0
  97. package/dist/src/commands/patch/split-staged.js +202 -0
  98. package/dist/src/commands/patch/split.d.ts +5 -0
  99. package/dist/src/commands/patch/split.js +62 -17
  100. package/dist/src/commands/patch/stage.d.ts +34 -0
  101. package/dist/src/commands/patch/stage.js +153 -0
  102. package/dist/src/commands/patch/staged-dependency-batch.d.ts +48 -0
  103. package/dist/src/commands/patch/staged-dependency-batch.js +176 -0
  104. package/dist/src/commands/patch/staged-dependency-entries.d.ts +36 -0
  105. package/dist/src/commands/patch/staged-dependency-entries.js +52 -0
  106. package/dist/src/commands/patch/staged-dependency-from.d.ts +14 -0
  107. package/dist/src/commands/patch/staged-dependency-from.js +108 -0
  108. package/dist/src/commands/patch/staged-dependency-remove.d.ts +31 -0
  109. package/dist/src/commands/patch/staged-dependency-remove.js +80 -0
  110. package/dist/src/commands/patch/staged-dependency.js +54 -139
  111. package/dist/src/commands/re-export-adjacent-registrations.d.ts +20 -0
  112. package/dist/src/commands/re-export-adjacent-registrations.js +75 -0
  113. package/dist/src/commands/re-export-adjacent.d.ts +50 -2
  114. package/dist/src/commands/re-export-adjacent.js +160 -40
  115. package/dist/src/commands/re-export-bulk-scan.d.ts +2 -1
  116. package/dist/src/commands/re-export-bulk-scan.js +22 -7
  117. package/dist/src/commands/re-export-drift.d.ts +36 -8
  118. package/dist/src/commands/re-export-drift.js +73 -49
  119. package/dist/src/commands/re-export-files.js +11 -8
  120. package/dist/src/commands/re-export-hunks.d.ts +35 -0
  121. package/dist/src/commands/re-export-hunks.js +220 -0
  122. package/dist/src/commands/re-export-lint.d.ts +2 -1
  123. package/dist/src/commands/re-export-lint.js +23 -10
  124. package/dist/src/commands/re-export-options.js +74 -6
  125. package/dist/src/commands/re-export-preflight.d.ts +23 -0
  126. package/dist/src/commands/re-export-preflight.js +160 -0
  127. package/dist/src/commands/re-export-purity-scope.d.ts +18 -0
  128. package/dist/src/commands/re-export-purity-scope.js +131 -0
  129. package/dist/src/commands/re-export-register.js +56 -17
  130. package/dist/src/commands/re-export-removed.d.ts +13 -2
  131. package/dist/src/commands/re-export-removed.js +57 -12
  132. package/dist/src/commands/re-export-scan-owner.d.ts +44 -0
  133. package/dist/src/commands/re-export-scan-owner.js +116 -0
  134. package/dist/src/commands/re-export-scan.d.ts +19 -9
  135. package/dist/src/commands/re-export-scan.js +60 -24
  136. package/dist/src/commands/re-export-single.js +122 -46
  137. package/dist/src/commands/re-export-stale-registrations.d.ts +18 -0
  138. package/dist/src/commands/re-export-stale-registrations.js +62 -0
  139. package/dist/src/commands/re-export-summary.d.ts +28 -0
  140. package/dist/src/commands/re-export-summary.js +36 -0
  141. package/dist/src/commands/re-export.js +71 -57
  142. package/dist/src/commands/rebase/index.js +17 -17
  143. package/dist/src/commands/run.js +16 -2
  144. package/dist/src/commands/status-check.d.ts +55 -16
  145. package/dist/src/commands/status-check.js +92 -37
  146. package/dist/src/commands/status-json.d.ts +22 -9
  147. package/dist/src/commands/status-json.js +47 -32
  148. package/dist/src/commands/status-output.js +3 -1
  149. package/dist/src/commands/status-scope.d.ts +37 -0
  150. package/dist/src/commands/status-scope.js +54 -0
  151. package/dist/src/commands/status.js +66 -23
  152. package/dist/src/commands/test-browser-preflight.js +19 -3
  153. package/dist/src/commands/test-build-furnace.d.ts +22 -0
  154. package/dist/src/commands/test-build-furnace.js +54 -0
  155. package/dist/src/commands/test-build-phase.js +64 -41
  156. package/dist/src/commands/test-checkjs.js +10 -2
  157. package/dist/src/commands/test-diagnose.js +7 -0
  158. package/dist/src/commands/test-dispatch.d.ts +39 -0
  159. package/dist/src/commands/test-dispatch.js +211 -0
  160. package/dist/src/commands/test-furnace-reach.d.ts +37 -0
  161. package/dist/src/commands/test-furnace-reach.js +132 -0
  162. package/dist/src/commands/test-modes.d.ts +16 -1
  163. package/dist/src/commands/test-modes.js +24 -1
  164. package/dist/src/commands/test-multi-verdict.d.ts +61 -0
  165. package/dist/src/commands/test-multi-verdict.js +111 -0
  166. package/dist/src/commands/test-orchestrate.d.ts +52 -0
  167. package/dist/src/commands/test-orchestrate.js +240 -0
  168. package/dist/src/commands/test-perf-scope.d.ts +50 -0
  169. package/dist/src/commands/test-perf-scope.js +138 -0
  170. package/dist/src/commands/test-prelock.d.ts +51 -0
  171. package/dist/src/commands/test-prelock.js +273 -0
  172. package/dist/src/commands/test-register.js +69 -10
  173. package/dist/src/commands/test-results.d.ts +62 -0
  174. package/dist/src/commands/test-results.js +62 -0
  175. package/dist/src/commands/test-run.d.ts +13 -55
  176. package/dist/src/commands/test-run.js +74 -99
  177. package/dist/src/commands/test-shards.d.ts +110 -0
  178. package/dist/src/commands/test-shards.js +255 -0
  179. package/dist/src/commands/test-stale-gate.d.ts +5 -1
  180. package/dist/src/commands/test-stale-gate.js +60 -28
  181. package/dist/src/commands/test-verdict.d.ts +11 -1
  182. package/dist/src/commands/test-verdict.js +28 -1
  183. package/dist/src/commands/test.d.ts +6 -1
  184. package/dist/src/commands/test.js +120 -124
  185. package/dist/src/commands/token-lint.d.ts +14 -0
  186. package/dist/src/commands/token-lint.js +151 -0
  187. package/dist/src/commands/token.js +10 -0
  188. package/dist/src/commands/verify-scope.d.ts +28 -0
  189. package/dist/src/commands/verify-scope.js +67 -0
  190. package/dist/src/commands/verify.d.ts +10 -2
  191. package/dist/src/commands/verify.js +67 -36
  192. package/dist/src/core/build-baseline-types.d.ts +46 -0
  193. package/dist/src/core/build-baseline-validate.js +19 -0
  194. package/dist/src/core/build-baseline.d.ts +5 -1
  195. package/dist/src/core/build-baseline.js +3 -1
  196. package/dist/src/core/build-overwrite-guard.d.ts +50 -0
  197. package/dist/src/core/build-overwrite-guard.js +84 -4
  198. package/dist/src/core/build-prepare.d.ts +13 -0
  199. package/dist/src/core/build-prepare.js +42 -10
  200. package/dist/src/core/build-run-record.d.ts +74 -0
  201. package/dist/src/core/build-run-record.js +136 -0
  202. package/dist/src/core/checkjs-support-heads.d.ts +41 -0
  203. package/dist/src/core/checkjs-support-heads.js +104 -0
  204. package/dist/src/core/config-paths.d.ts +2 -2
  205. package/dist/src/core/config-paths.js +10 -0
  206. package/dist/src/core/config-validate-check.d.ts +8 -0
  207. package/dist/src/core/config-validate-check.js +219 -0
  208. package/dist/src/core/config-validate-file-size.d.ts +9 -6
  209. package/dist/src/core/config-validate-file-size.js +91 -2
  210. package/dist/src/core/config-validate-history.d.ts +11 -0
  211. package/dist/src/core/config-validate-history.js +38 -0
  212. package/dist/src/core/config-validate-patch-policy.js +100 -0
  213. package/dist/src/core/config-validate-test-toolchains.js +21 -0
  214. package/dist/src/core/config-validate-token-scales.d.ts +9 -0
  215. package/dist/src/core/config-validate-token-scales.js +92 -0
  216. package/dist/src/core/config-validate.js +20 -5
  217. package/dist/src/core/config.d.ts +5 -0
  218. package/dist/src/core/config.js +16 -0
  219. package/dist/src/core/coverage-dispatch.d.ts +24 -0
  220. package/dist/src/core/coverage-dispatch.js +44 -0
  221. package/dist/src/core/coverage-extend.d.ts +70 -45
  222. package/dist/src/core/coverage-extend.js +199 -144
  223. package/dist/src/core/coverage-records.d.ts +108 -0
  224. package/dist/src/core/coverage-records.js +384 -0
  225. package/dist/src/core/destructive.d.ts +7 -4
  226. package/dist/src/core/destructive.js +10 -10
  227. package/dist/src/core/engine-session-lock.d.ts +16 -1
  228. package/dist/src/core/engine-session-lock.js +38 -10
  229. package/dist/src/core/export-moved-code-shape.d.ts +49 -11
  230. package/dist/src/core/export-moved-code-shape.js +135 -44
  231. package/dist/src/core/file-lock-queue.d.ts +67 -0
  232. package/dist/src/core/file-lock-queue.js +221 -0
  233. package/dist/src/core/file-lock-shared.d.ts +57 -0
  234. package/dist/src/core/file-lock-shared.js +117 -0
  235. package/dist/src/core/file-lock.d.ts +13 -25
  236. package/dist/src/core/file-lock.js +163 -140
  237. package/dist/src/core/furnace-apply-output.d.ts +10 -0
  238. package/dist/src/core/furnace-apply-output.js +31 -1
  239. package/dist/src/core/furnace-apply.js +22 -12
  240. package/dist/src/core/furnace-composed-source.d.ts +76 -0
  241. package/dist/src/core/furnace-composed-source.js +167 -0
  242. package/dist/src/core/furnace-config-validate-exceptions.d.ts +16 -0
  243. package/dist/src/core/furnace-config-validate-exceptions.js +102 -0
  244. package/dist/src/core/furnace-config-validate.js +14 -0
  245. package/dist/src/core/furnace-css-fragments.d.ts +10 -0
  246. package/dist/src/core/furnace-css-fragments.js +26 -0
  247. package/dist/src/core/furnace-operation.d.ts +3 -3
  248. package/dist/src/core/furnace-registration-jar-inplace.d.ts +12 -0
  249. package/dist/src/core/furnace-registration-jar-inplace.js +80 -0
  250. package/dist/src/core/furnace-registration-remove.d.ts +22 -1
  251. package/dist/src/core/furnace-registration-remove.js +53 -17
  252. package/dist/src/core/furnace-registration-rename.d.ts +26 -0
  253. package/dist/src/core/furnace-registration-rename.js +77 -0
  254. package/dist/src/core/furnace-registration.d.ts +14 -4
  255. package/dist/src/core/furnace-registration.js +44 -10
  256. package/dist/src/core/furnace-staleness.d.ts +7 -0
  257. package/dist/src/core/furnace-staleness.js +34 -24
  258. package/dist/src/core/furnace-validate-accessibility.d.ts +8 -4
  259. package/dist/src/core/furnace-validate-accessibility.js +71 -28
  260. package/dist/src/core/furnace-validate-exceptions.d.ts +48 -0
  261. package/dist/src/core/furnace-validate-exceptions.js +80 -0
  262. package/dist/src/core/furnace-validate-icon-button.d.ts +7 -0
  263. package/dist/src/core/furnace-validate-icon-button.js +78 -0
  264. package/dist/src/core/furnace-validate.js +1 -1
  265. package/dist/src/core/harness-port-fallback.d.ts +60 -0
  266. package/dist/src/core/harness-port-fallback.js +96 -0
  267. package/dist/src/core/history-log-file.d.ts +61 -0
  268. package/dist/src/core/history-log-file.js +164 -0
  269. package/dist/src/core/history-log.d.ts +2 -1
  270. package/dist/src/core/history-log.js +2 -1
  271. package/dist/src/core/json-preserving-edit.d.ts +22 -0
  272. package/dist/src/core/json-preserving-edit.js +199 -0
  273. package/dist/src/core/line-prefixer.d.ts +18 -0
  274. package/dist/src/core/line-prefixer.js +34 -0
  275. package/dist/src/core/mach.d.ts +7 -0
  276. package/dist/src/core/mach.js +32 -10
  277. package/dist/src/core/module-resolution-preflight.d.ts +19 -3
  278. package/dist/src/core/module-resolution-preflight.js +24 -6
  279. package/dist/src/core/negative-control-compiled.d.ts +27 -0
  280. package/dist/src/core/negative-control-compiled.js +73 -0
  281. package/dist/src/core/negative-control-diff.d.ts +51 -0
  282. package/dist/src/core/negative-control-diff.js +179 -0
  283. package/dist/src/core/negative-control.d.ts +150 -0
  284. package/dist/src/core/negative-control.js +399 -0
  285. package/dist/src/core/objdir-install-manifests.d.ts +73 -0
  286. package/dist/src/core/objdir-install-manifests.js +226 -0
  287. package/dist/src/core/park-store.d.ts +63 -0
  288. package/dist/src/core/park-store.js +216 -0
  289. package/dist/src/core/patch-export-update.d.ts +6 -0
  290. package/dist/src/core/patch-export-update.js +13 -3
  291. package/dist/src/core/patch-export.d.ts +3 -2
  292. package/dist/src/core/patch-export.js +22 -16
  293. package/dist/src/core/patch-files.js +26 -8
  294. package/dist/src/core/patch-lint-checkjs-any-import.d.ts +39 -0
  295. package/dist/src/core/patch-lint-checkjs-any-import.js +63 -0
  296. package/dist/src/core/patch-lint-checkjs-diagnostics.d.ts +17 -0
  297. package/dist/src/core/patch-lint-checkjs-diagnostics.js +32 -0
  298. package/dist/src/core/patch-lint-checkjs.d.ts +10 -1
  299. package/dist/src/core/patch-lint-checkjs.js +20 -13
  300. package/dist/src/core/patch-lint-code-lines.d.ts +59 -0
  301. package/dist/src/core/patch-lint-code-lines.js +105 -0
  302. package/dist/src/core/patch-lint-cross.d.ts +3 -1
  303. package/dist/src/core/patch-lint-cross.js +17 -4
  304. package/dist/src/core/patch-lint-css.d.ts +8 -2
  305. package/dist/src/core/patch-lint-css.js +24 -14
  306. package/dist/src/core/patch-lint-file-size.d.ts +12 -5
  307. package/dist/src/core/patch-lint-file-size.js +22 -11
  308. package/dist/src/core/patch-lint-forward-registration-extended.d.ts +23 -0
  309. package/dist/src/core/patch-lint-forward-registration-extended.js +36 -11
  310. package/dist/src/core/patch-lint-forward-registration.js +10 -0
  311. package/dist/src/core/patch-lint-ignore.d.ts +196 -0
  312. package/dist/src/core/patch-lint-ignore.js +429 -0
  313. package/dist/src/core/patch-lint-ownership.d.ts +10 -0
  314. package/dist/src/core/patch-lint-ownership.js +26 -0
  315. package/dist/src/core/patch-lint-size-thresholds.d.ts +52 -0
  316. package/dist/src/core/patch-lint-size-thresholds.js +110 -0
  317. package/dist/src/core/patch-lint-size.d.ts +117 -0
  318. package/dist/src/core/patch-lint-size.js +331 -0
  319. package/dist/src/core/patch-lint-staged-registration.d.ts +18 -1
  320. package/dist/src/core/patch-lint-staged-registration.js +20 -0
  321. package/dist/src/core/patch-lint-token-scale.d.ts +57 -0
  322. package/dist/src/core/patch-lint-token-scale.js +286 -0
  323. package/dist/src/core/patch-lint.d.ts +11 -83
  324. package/dist/src/core/patch-lint.js +66 -288
  325. package/dist/src/core/patch-lock.js +7 -6
  326. package/dist/src/core/patch-manifest-consistency.js +7 -6
  327. package/dist/src/core/patch-manifest-io.d.ts +6 -3
  328. package/dist/src/core/patch-manifest-io.js +27 -9
  329. package/dist/src/core/patch-manifest-key-order.d.ts +24 -0
  330. package/dist/src/core/patch-manifest-key-order.js +61 -0
  331. package/dist/src/core/patch-manifest-stage.d.ts +46 -0
  332. package/dist/src/core/patch-manifest-stage.js +96 -0
  333. package/dist/src/core/patch-manifest-validate.js +61 -3
  334. package/dist/src/core/patch-order-legal.d.ts +26 -0
  335. package/dist/src/core/patch-order-legal.js +88 -0
  336. package/dist/src/core/patch-policy-content.d.ts +40 -0
  337. package/dist/src/core/patch-policy-content.js +216 -0
  338. package/dist/src/core/patch-policy.d.ts +22 -5
  339. package/dist/src/core/patch-policy.js +26 -12
  340. package/dist/src/core/patch-retired.d.ts +57 -0
  341. package/dist/src/core/patch-retired.js +92 -0
  342. package/dist/src/core/patch-subset.d.ts +16 -0
  343. package/dist/src/core/patch-subset.js +66 -0
  344. package/dist/src/core/preflight-wait.d.ts +20 -0
  345. package/dist/src/core/preflight-wait.js +38 -0
  346. package/dist/src/core/rebase-from-version.d.ts +46 -0
  347. package/dist/src/core/rebase-from-version.js +71 -0
  348. package/dist/src/core/run-log.d.ts +26 -0
  349. package/dist/src/core/run-log.js +106 -4
  350. package/dist/src/core/run-profile.d.ts +7 -0
  351. package/dist/src/core/run-profile.js +7 -1
  352. package/dist/src/core/smoke-patterns.d.ts +5 -0
  353. package/dist/src/core/smoke-patterns.js +13 -0
  354. package/dist/src/core/test-harness-crash.d.ts +19 -1
  355. package/dist/src/core/test-harness-crash.js +8 -9
  356. package/dist/src/core/test-harness-signature.d.ts +33 -0
  357. package/dist/src/core/test-harness-signature.js +23 -1
  358. package/dist/src/core/test-raw-log.d.ts +66 -0
  359. package/dist/src/core/test-raw-log.js +122 -0
  360. package/dist/src/core/test-run-completeness.d.ts +90 -0
  361. package/dist/src/core/test-run-completeness.js +184 -0
  362. package/dist/src/core/test-stale-check.d.ts +27 -1
  363. package/dist/src/core/test-stale-check.js +39 -49
  364. package/dist/src/core/test-stale-exempt.d.ts +40 -0
  365. package/dist/src/core/test-stale-exempt.js +70 -0
  366. package/dist/src/core/test-xpcshell-retry.d.ts +2 -0
  367. package/dist/src/core/test-xpcshell-retry.js +2 -1
  368. package/dist/src/core/token-lint.d.ts +53 -0
  369. package/dist/src/core/token-lint.js +131 -0
  370. package/dist/src/core/token-sibling-sheets.d.ts +46 -0
  371. package/dist/src/core/token-sibling-sheets.js +119 -0
  372. package/dist/src/core/tree-guard.js +5 -0
  373. package/dist/src/core/typecheck-shim.d.ts +6 -2
  374. package/dist/src/core/typecheck-shim.js +205 -4
  375. package/dist/src/core/typecheck.js +3 -1
  376. package/dist/src/index.d.ts +14 -3
  377. package/dist/src/index.js +6 -1
  378. package/dist/src/types/commands/index.d.ts +2 -2
  379. package/dist/src/types/commands/options.d.ts +212 -24
  380. package/dist/src/types/commands/patches.d.ts +118 -1
  381. package/dist/src/types/config.d.ts +264 -0
  382. package/dist/src/types/config.js +9 -0
  383. package/dist/src/types/furnace.d.ts +63 -1
  384. package/dist/src/types/furnace.js +7 -0
  385. package/dist/src/types/index.d.ts +1 -1
  386. package/dist/src/utils/options.d.ts +36 -7
  387. package/dist/src/utils/options.js +94 -8
  388. package/dist/src/utils/path-glob.d.ts +15 -0
  389. package/dist/src/utils/path-glob.js +47 -0
  390. package/dist/src/utils/regex.d.ts +15 -3
  391. package/dist/src/utils/regex.js +37 -16
  392. package/docs/configuration.md +369 -11
  393. package/docs/exit-codes.md +18 -1
  394. package/docs/furnace.md +139 -3
  395. package/docs/lifecycle-invariants.md +65 -30
  396. package/docs/machine-output.md +120 -12
  397. package/docs/patch-workflow.md +458 -22
  398. package/docs/run-logs.md +20 -1
  399. package/docs/testing.md +346 -21
  400. package/package.json +3 -3
@@ -2,12 +2,13 @@
2
2
  import { join } from 'node:path';
3
3
  import { toError } from '../utils/errors.js';
4
4
  import { pathExists, readText, removeFile, writeText } from '../utils/fs.js';
5
- import { warn } from '../utils/logger.js';
5
+ import { info, warn } from '../utils/logger.js';
6
6
  import { discoverPatches, withPatchDirectoryLock } from './patch-apply.js';
7
7
  import { findAllPatchesForFilesWithDetails, } from './patch-export-coverage.js';
8
8
  import { addPatchToManifest, loadPatchesManifestForWrite, PATCHES_MANIFEST, savePatchesManifest, } from './patch-manifest.js';
9
9
  import { formatPatchOrder, requirePatchOrder } from './patch-parse.js';
10
10
  import { allocatePolicyOrder, enforcePatchPolicy } from './patch-policy.js';
11
+ import { manifestWithRetiredSlots, reservationAt, reservedOrderSet } from './patch-retired.js';
11
12
  export { findAllPatchesForFiles, findAllPatchesForFilesWithDetails, } from './patch-export-coverage.js';
12
13
  import { escapeRegex } from '../utils/regex.js';
13
14
  export { mutatePatchMetadata, updatePatchMetadata } from './patch-export-metadata.js';
@@ -39,18 +40,16 @@ export function buildPlanExportInput(input) {
39
40
  /**
40
41
  * Gets the next patch number for a new patch.
41
42
  * @param patchesDir - Path to the patches directory
43
+ * @param reserved - Orders held by `patch reserve`, skipped
42
44
  * @returns Next patch number (e.g., "005" for 4 existing patches)
43
45
  */
44
- export async function getNextPatchNumber(patchesDir) {
46
+ export async function getNextPatchNumber(patchesDir, reserved = new Set()) {
45
47
  const patches = await discoverPatches(patchesDir);
46
- if (patches.length === 0) {
47
- return '001';
48
- }
49
48
  const finitePatches = patches.filter((p) => Number.isFinite(p.order));
50
- if (finitePatches.length === 0)
51
- return '001';
52
49
  const maxOrder = finitePatches.reduce((max, p) => Math.max(max, p.order), 0);
53
- const nextNumber = maxOrder + 1;
50
+ let nextNumber = maxOrder + 1;
51
+ while (reserved.has(nextNumber))
52
+ nextNumber++;
54
53
  return String(nextNumber).padStart(Math.max(3, String(nextNumber).length), '0');
55
54
  }
56
55
  /**
@@ -117,8 +116,8 @@ export function patchNameSlug(name, category) {
117
116
  * @param name - Human-readable name
118
117
  * @returns Filename like "001-ui-sidebar.patch"
119
118
  */
120
- export async function getNextPatchFilename(patchesDir, category, name) {
121
- const patchNumber = await getNextPatchNumber(patchesDir);
119
+ export async function getNextPatchFilename(patchesDir, category, name, reserved = new Set()) {
120
+ const patchNumber = await getNextPatchNumber(patchesDir, reserved);
122
121
  const sanitizedName = patchNameSlug(name, category);
123
122
  return `${patchNumber}-${category}-${sanitizedName}.patch`;
124
123
  }
@@ -233,12 +232,15 @@ async function computeExportPlanUnderLock(input) {
233
232
  // wipes the queue metadata, and the rollback path would then delete
234
233
  // patches.json entirely because manifestBefore looked absent.
235
234
  const manifestBefore = await loadPatchesManifestForWrite(input.patchesDir);
235
+ // A default allocation never lands on a reservation; only an explicit
236
+ // `--order` placement fills one.
237
+ const reserved = reservedOrderSet(manifestBefore ?? {});
236
238
  const policyOrder = input.config !== undefined
237
- ? allocatePolicyOrder(input.config, manifestBefore?.patches ?? [], input.category)
239
+ ? allocatePolicyOrder(input.config, manifestBefore?.patches ?? [], input.category, reserved)
238
240
  : null;
239
241
  const patchFilename = policyOrder !== null
240
242
  ? `${formatPatchOrder(policyOrder)}-${input.category}-${patchNameSlug(input.name, input.category)}.patch`
241
- : await getNextPatchFilename(input.patchesDir, input.category, input.name);
243
+ : await getNextPatchFilename(input.patchesDir, input.category, input.name, reserved);
242
244
  const patchPath = join(input.patchesDir, patchFilename);
243
245
  const metadata = {
244
246
  filename: patchFilename,
@@ -266,6 +268,12 @@ async function computeExportPlanUnderLock(input) {
266
268
  const afterPatches = (manifestBefore?.patches ?? []).filter((p) => !supersededSet.has(p.filename) && p.filename !== patchFilename);
267
269
  afterPatches.push(metadata);
268
270
  afterPatches.sort((a, b) => a.order - b.order || a.filename.localeCompare(b.filename));
271
+ const reservation = reservationAt(manifestBefore, metadata.order);
272
+ if (reservation !== undefined) {
273
+ info(`Order ${formatPatchOrder(metadata.order)} was reserved by ${reservation.owner}` +
274
+ `${reservation.reason !== undefined ? ` (${reservation.reason})` : ''}; ` +
275
+ 'this export fills the reservation.');
276
+ }
269
277
  return {
270
278
  patchFilename,
271
279
  patchPath,
@@ -273,10 +281,8 @@ async function computeExportPlanUnderLock(input) {
273
281
  supersededDetails,
274
282
  supersededPatches,
275
283
  manifestBefore: manifestBefore ?? null,
276
- manifestAfter: {
277
- version: 1,
278
- patches: afterPatches,
279
- },
284
+ // A patch landing on a retired or reserved order fills that slot.
285
+ manifestAfter: manifestWithRetiredSlots(manifestBefore, afterPatches),
280
286
  };
281
287
  }
282
288
  /**
@@ -1,5 +1,5 @@
1
1
  // SPDX-License-Identifier: EUPL-1.2
2
- import { readdir } from 'node:fs/promises';
2
+ import { readdir, stat } from 'node:fs/promises';
3
3
  import { extname, join } from 'node:path';
4
4
  import { pathExists, readText } from '../utils/fs.js';
5
5
  import { extractAffectedFiles, extractOrder } from './patch-parse.js';
@@ -9,16 +9,34 @@ export async function discoverPatches(patchesDir) {
9
9
  return [];
10
10
  }
11
11
  const entries = await readdir(patchesDir, { withFileTypes: true });
12
- const patches = entries
13
- .filter((entry) => entry.isFile() && extname(entry.name) === '.patch')
14
- .map((entry) => ({
15
- path: join(patchesDir, entry.name),
16
- filename: entry.name,
17
- order: extractOrder(entry.name),
18
- }));
12
+ const patches = [];
13
+ for (const entry of entries) {
14
+ if (extname(entry.name) !== '.patch')
15
+ continue;
16
+ // A symlinked patch (a scratch queue built from links to the real
17
+ // patches) counts when it resolves to a regular file; a dangling link or
18
+ // a link to a directory does not.
19
+ if (!entry.isFile() &&
20
+ !(entry.isSymbolicLink() && (await isLinkToFile(patchesDir, entry.name)))) {
21
+ continue;
22
+ }
23
+ patches.push({
24
+ path: join(patchesDir, entry.name),
25
+ filename: entry.name,
26
+ order: extractOrder(entry.name),
27
+ });
28
+ }
19
29
  patches.sort((a, b) => a.order - b.order || a.filename.localeCompare(b.filename));
20
30
  return patches;
21
31
  }
32
+ async function isLinkToFile(dir, name) {
33
+ try {
34
+ return (await stat(join(dir, name))).isFile();
35
+ }
36
+ catch {
37
+ return false;
38
+ }
39
+ }
22
40
  /** Counts the patch files currently present in a patch directory. */
23
41
  export async function countPatches(patchesDir) {
24
42
  const patches = await discoverPatches(patchesDir);
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Explains an implicit-`any` checkJs finding that comes from a URL import
3
+ * the per-patch program cannot resolve.
4
+ *
5
+ * The program resolves URL imports only to modules the queue creates (for
6
+ * a test, those created up to its own patch, plus its directory's
7
+ * head.js), so a `resource:///` or `chrome://` import of a module a later
8
+ * patch creates, an upstream module, or a basename two patches create
9
+ * falls back to the shim's `declare module 'resource:*'` wildcard and
10
+ * types as `any`. A callback
11
+ * over its values then has implicitly-`any` parameters under
12
+ * `checkJsStrict`, while the whole-tree `fireforge typecheck`, which sees
13
+ * the module, is clean. Without the note the two disagree with no
14
+ * explanation. Split out of patch-lint-checkjs.ts for the line budget.
15
+ */
16
+ /** Unresolved URL import specifiers, keyed by the importing file's TS path. */
17
+ export type AnyTypedImports = Map<string, Set<string>>;
18
+ /**
19
+ * The note an implicit-`any` finding carries when its file imports a
20
+ * `resource://`/`chrome://` module this checkJs program could not resolve.
21
+ * Such an import types as `any` (the shim's wildcard module), so a
22
+ * callback over its values has implicitly-`any` parameters here while the
23
+ * whole-tree `fireforge typecheck`, which sees the module, is clean.
24
+ */
25
+ export declare function anyTypedImportHint(code: number, specifiers: ReadonlySet<string> | undefined): string;
26
+ /**
27
+ * The host's `resolveModuleNameLiterals`: owned specifiers first, then a
28
+ * reviewed `paths` mapping, recording every URL import that resolves to
29
+ * neither.
30
+ *
31
+ * @param resolveOwned - Patch-owned specifier resolver
32
+ * @param resolveViaPaths - Optional `paths` resolver
33
+ * @param into - Map that collects the unresolved URL imports
34
+ */
35
+ export declare function createModuleLiteralResolver<Resolved>(resolveOwned: (specifier: string) => Resolved | undefined, resolveViaPaths: ((specifier: string) => Resolved | undefined) | undefined, into: AnyTypedImports): (moduleLiterals: readonly {
36
+ text: string;
37
+ }[], containingFile: string) => Array<{
38
+ resolvedModule: Resolved | undefined;
39
+ }>;
@@ -0,0 +1,63 @@
1
+ // SPDX-License-Identifier: EUPL-1.2
2
+ /**
3
+ * Explains an implicit-`any` checkJs finding that comes from a URL import
4
+ * the per-patch program cannot resolve.
5
+ *
6
+ * The program resolves URL imports only to modules the queue creates (for
7
+ * a test, those created up to its own patch, plus its directory's
8
+ * head.js), so a `resource:///` or `chrome://` import of a module a later
9
+ * patch creates, an upstream module, or a basename two patches create
10
+ * falls back to the shim's `declare module 'resource:*'` wildcard and
11
+ * types as `any`. A callback
12
+ * over its values then has implicitly-`any` parameters under
13
+ * `checkJsStrict`, while the whole-tree `fireforge typecheck`, which sees
14
+ * the module, is clean. Without the note the two disagree with no
15
+ * explanation. Split out of patch-lint-checkjs.ts for the line budget.
16
+ */
17
+ /** TypeScript's implicit-`any` diagnostic codes (noImplicitAny). */
18
+ const IMPLICIT_ANY_CODES = new Set([
19
+ 7005, 7006, 7008, 7010, 7011, 7019, 7031, 7034,
20
+ ]);
21
+ function recordAnyTypedImport(into, containingFile, specifier) {
22
+ if (!/^(?:resource|chrome):/.test(specifier))
23
+ return;
24
+ const list = into.get(containingFile) ?? new Set();
25
+ list.add(specifier);
26
+ into.set(containingFile, list);
27
+ }
28
+ /**
29
+ * The note an implicit-`any` finding carries when its file imports a
30
+ * `resource://`/`chrome://` module this checkJs program could not resolve.
31
+ * Such an import types as `any` (the shim's wildcard module), so a
32
+ * callback over its values has implicitly-`any` parameters here while the
33
+ * whole-tree `fireforge typecheck`, which sees the module, is clean.
34
+ */
35
+ export function anyTypedImportHint(code, specifiers) {
36
+ if (!IMPLICIT_ANY_CODES.has(code) || specifiers === undefined || specifiers.size === 0)
37
+ return '';
38
+ const list = [...specifiers].sort().join(', ');
39
+ return (` (This file imports ${list}, which this per-patch checkJs program cannot resolve — ` +
40
+ 'no patch up to this one creates the module under that name: a later patch creates it, ' +
41
+ 'it is upstream, or two patches create the same basename — so the import is typed `any`. ' +
42
+ 'Annotate the parameter explicitly; the whole-tree "fireforge typecheck" resolves the real type.)');
43
+ }
44
+ /**
45
+ * The host's `resolveModuleNameLiterals`: owned specifiers first, then a
46
+ * reviewed `paths` mapping, recording every URL import that resolves to
47
+ * neither.
48
+ *
49
+ * @param resolveOwned - Patch-owned specifier resolver
50
+ * @param resolveViaPaths - Optional `paths` resolver
51
+ * @param into - Map that collects the unresolved URL imports
52
+ */
53
+ export function createModuleLiteralResolver(resolveOwned, resolveViaPaths, into) {
54
+ return (moduleLiterals, containingFile) => moduleLiterals.map((literal) => {
55
+ const owned = resolveOwned(literal.text);
56
+ if (owned)
57
+ return { resolvedModule: owned };
58
+ const viaPaths = resolveViaPaths?.(literal.text);
59
+ if (viaPaths === undefined)
60
+ recordAnyTypedImport(into, containingFile, literal.text);
61
+ return { resolvedModule: viaPaths };
62
+ });
63
+ }
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Collects a checkJs program's diagnostics, for every file or for a report
3
+ * scope only. A per-test program resolves the modules its imports reach
4
+ * (see `runCheckJsTestFilesGrouped`), and asking for the whole program's
5
+ * diagnostics would type-check each of those modules once per test, so a
6
+ * scoped run asks only for the files it reports. Split out of
7
+ * patch-lint-checkjs.ts for the line budget.
8
+ */
9
+ /**
10
+ * The program's semantic and syntactic diagnostics, limited to the files
11
+ * `reportOnly` names when it is set.
12
+ *
13
+ * @param program - The built program
14
+ * @param relByAbsolute - Owned files: TS path → repo-relative path
15
+ * @param reportOnly - Repo-relative files to collect for, or all when unset
16
+ */
17
+ export declare function collectCheckJsDiagnostics(program: import('typescript').Program, relByAbsolute: ReadonlyMap<string, string>, reportOnly: ReadonlySet<string> | undefined): import('typescript').Diagnostic[];
@@ -0,0 +1,32 @@
1
+ // SPDX-License-Identifier: EUPL-1.2
2
+ /**
3
+ * Collects a checkJs program's diagnostics, for every file or for a report
4
+ * scope only. A per-test program resolves the modules its imports reach
5
+ * (see `runCheckJsTestFilesGrouped`), and asking for the whole program's
6
+ * diagnostics would type-check each of those modules once per test, so a
7
+ * scoped run asks only for the files it reports. Split out of
8
+ * patch-lint-checkjs.ts for the line budget.
9
+ */
10
+ /**
11
+ * The program's semantic and syntactic diagnostics, limited to the files
12
+ * `reportOnly` names when it is set.
13
+ *
14
+ * @param program - The built program
15
+ * @param relByAbsolute - Owned files: TS path → repo-relative path
16
+ * @param reportOnly - Repo-relative files to collect for, or all when unset
17
+ */
18
+ export function collectCheckJsDiagnostics(program, relByAbsolute, reportOnly) {
19
+ if (reportOnly === undefined) {
20
+ return [...program.getSemanticDiagnostics(), ...program.getSyntacticDiagnostics()];
21
+ }
22
+ return program
23
+ .getSourceFiles()
24
+ .filter((sourceFile) => {
25
+ const rel = relByAbsolute.get(sourceFile.fileName);
26
+ return rel !== undefined && reportOnly.has(rel);
27
+ })
28
+ .flatMap((sourceFile) => [
29
+ ...program.getSemanticDiagnostics(sourceFile),
30
+ ...program.getSyntacticDiagnostics(sourceFile),
31
+ ]);
32
+ }
@@ -82,6 +82,8 @@ export interface RunCheckJsGroupedInput {
82
82
  * compiler options and shim in one run. See {@link runCheckJsTestFilesGrouped}.
83
83
  */
84
84
  sourceFileCache?: CheckJsSourceFileCache;
85
+ /** When set, diagnostics are collected only for these repo-relative files. */
86
+ reportOnly?: ReadonlySet<string>;
85
87
  }
86
88
  /**
87
89
  * Builds the checkJs program once over `resolutionOwned` and returns its
@@ -136,12 +138,19 @@ export declare function invokePatchLintCheckJs(repoDir: string, patchOwnedFiles:
136
138
  * reported per program (head helpers report from their own program), and
137
139
  * run-level errors are de-duplicated across programs.
138
140
  *
141
+ * With `resolvableModules`, a test's `resource:///` and `chrome://`
142
+ * imports also resolve to the modules it returns for that test (the
143
+ * modules the queue creates up to the test's own patch), so a test that
144
+ * imports an earlier patch's module is typed against its real source
145
+ * instead of the shim's `any` wildcard. Those modules are resolution
146
+ * targets only: never roots, and never reported on.
147
+ *
139
148
  * @param repoDir - Absolute engine (repository) directory
140
149
  * @param testFiles - Patch-owned test-script paths (repo-relative)
141
150
  * @param patchLint - The resolved `patchLint` config block
142
151
  * @param projectRoot - FireForge project root for shim resolution
143
152
  */
144
- export declare function runCheckJsTestFilesGrouped(repoDir: string, testFiles: Set<string>, patchLint: PatchLintConfig, projectRoot: string, rootScope?: ReadonlySet<string>): Promise<GroupedCheckJsResult>;
153
+ export declare function runCheckJsTestFilesGrouped(repoDir: string, testFiles: Set<string>, patchLint: PatchLintConfig, projectRoot: string, rootScope?: ReadonlySet<string>, resolvableModules?: (testFile: string) => ReadonlySet<string>): Promise<GroupedCheckJsResult>;
145
154
  /**
146
155
  * Grouped variant of {@link invokePatchLintCheckJs}: builds one queue-wide
147
156
  * checkJs program over `patchOwnedFiles` and returns its findings grouped by
@@ -31,7 +31,9 @@ import { pathExists } from '../utils/fs.js';
31
31
  import { verbose } from '../utils/logger.js';
32
32
  import { normalizePathSlashes } from '../utils/paths.js';
33
33
  import { withGeckoDomTypes } from './gecko-dom-types.js';
34
+ import { anyTypedImportHint, createModuleLiteralResolver, } from './patch-lint-checkjs-any-import.js';
34
35
  import { withSharedSourceFiles } from './patch-lint-checkjs-cache.js';
36
+ import { collectCheckJsDiagnostics } from './patch-lint-checkjs-diagnostics.js';
35
37
  import { collectUnmanagedCompanions, retargetUnmanagedCompanionHints, } from './patch-lint-unmanaged-companion.js';
36
38
  import { composeShimSource, SHIM_FILENAME, SUPPRESSED_DIAGNOSTIC_CODES, TEST_HARNESS_SHIM, UNDEFINED_IDENTIFIER_CODES, UNDEFINED_IDENTIFIER_HINT, } from './typecheck-shim.js';
37
39
  // ---------------------------------------------------------------------------
@@ -293,6 +295,9 @@ export async function runCheckJsGrouped(input) {
293
295
  ...overrides,
294
296
  };
295
297
  const resolveOwnedSpecifier = createOwnedSpecifierResolver(ts, ownedAbsolute);
298
+ // URL imports this program cannot resolve, per importing file (see
299
+ // patch-lint-checkjs-any-import.ts).
300
+ const anyTypedImports = new Map();
296
301
  // Custom compiler host: reads patch-owned files from disk, returns
297
302
  // the shim for the shim path, and returns empty content for
298
303
  // anything else to avoid reading the full Firefox tree.
@@ -333,17 +338,10 @@ export async function runCheckJsGrouped(input) {
333
338
  return shimSource;
334
339
  return defaultHost.readFile(fileName);
335
340
  },
336
- resolveModuleNameLiterals(moduleLiterals) {
337
- return moduleLiterals.map((literal) => {
338
- const owned = resolveOwnedSpecifier(literal.text);
339
- if (owned)
340
- return { resolvedModule: owned };
341
- return { resolvedModule: resolveViaPaths?.(literal.text) };
342
- });
343
- },
341
+ resolveModuleNameLiterals: createModuleLiteralResolver(resolveOwnedSpecifier, resolveViaPaths, anyTypedImports),
344
342
  };
345
343
  const program = ts.createProgram(rootFiles, options, withSharedSourceFiles(host, input.sourceFileCache, shimPath, shimSource));
346
- const byFile = groupOwnedDiagnostics(ts, [...program.getSemanticDiagnostics(), ...program.getSyntacticDiagnostics()], relByAbsolute, input.mode?.undefinedIdentifiers ?? 'warning');
344
+ const byFile = groupOwnedDiagnostics(ts, collectCheckJsDiagnostics(program, relByAbsolute, input.reportOnly), relByAbsolute, input.mode?.undefinedIdentifiers ?? 'warning', anyTypedImports);
347
345
  verbose(`checkJs: analyzed ${rootFiles.length - 1} file(s) across ${byFile.size} owning file(s)`);
348
346
  return { byFile, global: [] };
349
347
  }
@@ -354,7 +352,7 @@ export async function runCheckJsGrouped(input) {
354
352
  * or shim files are dropped. Only owned files (in `relByAbsolute`) carry
355
353
  * findings.
356
354
  */
357
- function groupOwnedDiagnostics(ts, diagnostics, relByAbsolute, undefinedIdentifiers = 'warning') {
355
+ function groupOwnedDiagnostics(ts, diagnostics, relByAbsolute, undefinedIdentifiers = 'warning', anyTypedImports = new Map()) {
358
356
  const byFile = new Map();
359
357
  for (const diag of diagnostics) {
360
358
  if (SUPPRESSED_DIAGNOSTIC_CODES.has(diag.code))
@@ -386,7 +384,7 @@ function groupOwnedDiagnostics(ts, diagnostics, relByAbsolute, undefinedIdentifi
386
384
  check: 'checkjs-type-error',
387
385
  message: isUndefinedIdentifier
388
386
  ? `Line ${line}: ${messageText} ${UNDEFINED_IDENTIFIER_HINT}`
389
- : `Line ${line}: ${messageText}`,
387
+ : `Line ${line}: ${messageText}${anyTypedImportHint(diag.code, anyTypedImports.get(sourceFile.fileName))}`,
390
388
  severity,
391
389
  });
392
390
  byFile.set(relPath, bucket);
@@ -451,12 +449,19 @@ export async function invokePatchLintCheckJs(repoDir, patchOwnedFiles, patchLint
451
449
  * reported per program (head helpers report from their own program), and
452
450
  * run-level errors are de-duplicated across programs.
453
451
  *
452
+ * With `resolvableModules`, a test's `resource:///` and `chrome://`
453
+ * imports also resolve to the modules it returns for that test (the
454
+ * modules the queue creates up to the test's own patch), so a test that
455
+ * imports an earlier patch's module is typed against its real source
456
+ * instead of the shim's `any` wildcard. Those modules are resolution
457
+ * targets only: never roots, and never reported on.
458
+ *
454
459
  * @param repoDir - Absolute engine (repository) directory
455
460
  * @param testFiles - Patch-owned test-script paths (repo-relative)
456
461
  * @param patchLint - The resolved `patchLint` config block
457
462
  * @param projectRoot - FireForge project root for shim resolution
458
463
  */
459
- export async function runCheckJsTestFilesGrouped(repoDir, testFiles, patchLint, projectRoot, rootScope) {
464
+ export async function runCheckJsTestFilesGrouped(repoDir, testFiles, patchLint, projectRoot, rootScope, resolvableModules) {
460
465
  const merged = { byFile: new Map(), global: [] };
461
466
  if (testFiles.size === 0)
462
467
  return merged;
@@ -487,7 +492,9 @@ export async function runCheckJsTestFilesGrouped(repoDir, testFiles, patchLint,
487
492
  }
488
493
  const result = await runCheckJsGrouped({
489
494
  repoDir,
490
- resolutionOwned: roots,
495
+ resolutionOwned: new Set([...roots, ...(resolvableModules?.(file) ?? [])]),
496
+ rootScope: roots,
497
+ reportOnly: new Set([file]),
491
498
  ...(patchLint.checkJsTestShim !== undefined
492
499
  ? { extraShimPath: patchLint.checkJsTestShim }
493
500
  : {}),
@@ -0,0 +1,59 @@
1
+ /**
2
+ * Line counting for the size rules: raw lines, code lines, and the per-line
3
+ * code mask the `addedCode` patch-size metric reads off a file's
4
+ * post-image.
5
+ *
6
+ * "Code" means a line left non-blank once comments are blanked. JS goes
7
+ * through acorn's tokenizer (`stripJsCommentsParsed`), so a regex literal
8
+ * containing `/*`, a string containing `//`, nested template literals,
9
+ * JSDoc and a shebang are all judged correctly, and a blank line inside a
10
+ * template literal counts as blank.
11
+ */
12
+ /**
13
+ * Counts the lines of `content` the way `wc -l` reports them. A naive
14
+ * `split('\n').length` over-counts by one for any content ending in `\n`
15
+ * (the common case), making the size rules fire one line early against
16
+ * the operator's own `wc -l` measurement.
17
+ */
18
+ export declare function countRawLines(content: string): number;
19
+ /** The result of {@link countCodeLines}. */
20
+ export interface CodeLineCount {
21
+ /**
22
+ * Lines that carry code: non-blank once comments are blanked. When the
23
+ * source could not be tokenized this is the raw line count instead, the
24
+ * upper bound, so an unparsable file never measures smaller than it is.
25
+ */
26
+ lines: number;
27
+ /** False when acorn could tokenize the source neither as a module nor as a script. */
28
+ parsed: boolean;
29
+ }
30
+ /**
31
+ * Counts the code lines of a JS source: comments are blanked by acorn's
32
+ * tokenizer (module goal first, then script, since chrome subscripts are
33
+ * scripts) and the non-blank lines are counted. When neither goal
34
+ * tokenizes, the raw line count is returned with `parsed: false`. A regex
35
+ * fallback would under-count, which fails open.
36
+ *
37
+ * @param content - JS source text
38
+ */
39
+ export declare function countCodeLines(content: string): CodeLineCount;
40
+ /** The per-line code mask of one post-image. */
41
+ export interface CodeLineMask {
42
+ /** `code[i]` is true when line `i + 1` carries code. */
43
+ code: boolean[];
44
+ /** False for a JS file acorn could not tokenize; every non-blank line then counts. */
45
+ parsed: boolean;
46
+ }
47
+ /**
48
+ * Classifies every line of a file's post-image as code or not, by file
49
+ * kind: JS through acorn, CSS block comments, `<!-- -->` in markup, and
50
+ * whole-line `#` comments (`;` for `.ini`/`.in`, `!` for `.properties`) in
51
+ * Fluent, manifests, `moz.build` and similar. Any other file counts every
52
+ * non-blank line. In CSS, lines inside a Furnace fragment expansion
53
+ * (`@fireforge-include` … `@fireforge-end-include`) are not code of this
54
+ * file: they are a copy of a shared fragment.
55
+ *
56
+ * @param file - Engine-relative path, used only to pick the file kind
57
+ * @param content - The post-image text
58
+ */
59
+ export declare function codeLineMask(file: string, content: string): CodeLineMask;
@@ -0,0 +1,105 @@
1
+ // SPDX-License-Identifier: EUPL-1.2
2
+ /**
3
+ * Line counting for the size rules: raw lines, code lines, and the per-line
4
+ * code mask the `addedCode` patch-size metric reads off a file's
5
+ * post-image.
6
+ *
7
+ * "Code" means a line left non-blank once comments are blanked. JS goes
8
+ * through acorn's tokenizer (`stripJsCommentsParsed`), so a regex literal
9
+ * containing `/*`, a string containing `//`, nested template literals,
10
+ * JSDoc and a shebang are all judged correctly, and a blank line inside a
11
+ * template literal counts as blank.
12
+ */
13
+ import { stripJsCommentsParsed } from '../utils/regex.js';
14
+ import { expandedFragmentLineMask } from './furnace-css-fragments.js';
15
+ import { maskCssComments } from './patch-lint-css.js';
16
+ /**
17
+ * Splits content into lines the way `wc -l` reports them: a trailing
18
+ * newline terminates the last line rather than starting an empty extra one.
19
+ */
20
+ function splitContentLines(content) {
21
+ const lines = content.split('\n');
22
+ if (lines[lines.length - 1] === '')
23
+ lines.pop();
24
+ return lines;
25
+ }
26
+ /**
27
+ * Counts the lines of `content` the way `wc -l` reports them. A naive
28
+ * `split('\n').length` over-counts by one for any content ending in `\n`
29
+ * (the common case), making the size rules fire one line early against
30
+ * the operator's own `wc -l` measurement.
31
+ */
32
+ export function countRawLines(content) {
33
+ return splitContentLines(content).length;
34
+ }
35
+ const isBlank = (line) => line.trim() === '';
36
+ /**
37
+ * Counts the code lines of a JS source: comments are blanked by acorn's
38
+ * tokenizer (module goal first, then script, since chrome subscripts are
39
+ * scripts) and the non-blank lines are counted. When neither goal
40
+ * tokenizes, the raw line count is returned with `parsed: false`. A regex
41
+ * fallback would under-count, which fails open.
42
+ *
43
+ * @param content - JS source text
44
+ */
45
+ export function countCodeLines(content) {
46
+ const stripped = stripJsCommentsParsed(content);
47
+ if (stripped === null)
48
+ return { lines: countRawLines(content), parsed: false };
49
+ return {
50
+ lines: splitContentLines(stripped).filter((line) => !isBlank(line)).length,
51
+ parsed: true,
52
+ };
53
+ }
54
+ const JS_FILE = /\.(?:m?js|jsm|cjs)$/;
55
+ const MARKUP_FILE = /\.(?:x?html|xml|svg|xul|dtd)$/;
56
+ const HASH_COMMENT_FILE = /(?:\.(?:ftl|properties|toml|ini|mn|build|py|conf|configure|sh|ya?ml|in|cfg|mozbuild)|(?:^|\/)(?:Makefile|mozconfig))$/;
57
+ /** Line-comment leaders per hash-comment file kind. */
58
+ function lineCommentPattern(file) {
59
+ if (/\.(?:ini|in)$/.test(file))
60
+ return /^\s*[#;]/;
61
+ if (file.endsWith('.properties'))
62
+ return /^\s*[#!]/;
63
+ return /^\s*#/;
64
+ }
65
+ /** Masks `<!-- … -->` comments, keeping newlines. Unclosed comments run to EOF. */
66
+ function maskMarkupComments(source) {
67
+ return source.replace(/<!--[\s\S]*?(?:-->|$)/g, (m) => m.replace(/[^\n]/g, ' '));
68
+ }
69
+ /**
70
+ * Classifies every line of a file's post-image as code or not, by file
71
+ * kind: JS through acorn, CSS block comments, `<!-- -->` in markup, and
72
+ * whole-line `#` comments (`;` for `.ini`/`.in`, `!` for `.properties`) in
73
+ * Fluent, manifests, `moz.build` and similar. Any other file counts every
74
+ * non-blank line. In CSS, lines inside a Furnace fragment expansion
75
+ * (`@fireforge-include` … `@fireforge-end-include`) are not code of this
76
+ * file: they are a copy of a shared fragment.
77
+ *
78
+ * @param file - Engine-relative path, used only to pick the file kind
79
+ * @param content - The post-image text
80
+ */
81
+ export function codeLineMask(file, content) {
82
+ if (JS_FILE.test(file)) {
83
+ const stripped = stripJsCommentsParsed(content);
84
+ const source = stripped ?? content;
85
+ return { code: source.split('\n').map((line) => !isBlank(line)), parsed: stripped !== null };
86
+ }
87
+ if (file.endsWith('.css')) {
88
+ const inFragment = expandedFragmentLineMask(content);
89
+ const code = maskCssComments(content)
90
+ .split('\n')
91
+ .map((line, i) => !isBlank(line) && inFragment[i] !== true);
92
+ return { code, parsed: true };
93
+ }
94
+ if (MARKUP_FILE.test(file)) {
95
+ return {
96
+ code: maskMarkupComments(content)
97
+ .split('\n')
98
+ .map((l) => !isBlank(l)),
99
+ parsed: true,
100
+ };
101
+ }
102
+ const comment = HASH_COMMENT_FILE.test(file) ? lineCommentPattern(file) : undefined;
103
+ const code = content.split('\n').map((line) => !isBlank(line) && !comment?.test(line));
104
+ return { code, parsed: true };
105
+ }
@@ -10,7 +10,7 @@
10
10
  * module.
11
11
  */
12
12
  import type { PatchLintIssue, PatchMetadata } from '../types/commands/index.js';
13
- import type { FireForgeConfig, PatchPolicyConfig } from '../types/config.js';
13
+ import type { FireForgeConfig, PatchLintTokenScale, PatchPolicyConfig } from '../types/config.js';
14
14
  import type { ForwardRegistrationScope } from './patch-lint-forward-registration-extended.js';
15
15
  /**
16
16
  * One patch's contribution to {@link PatchQueueContext}.
@@ -82,6 +82,8 @@ export interface PatchQueueContext {
82
82
  * `patchLint.forwardRegistration`. Absent = `support-files` only.
83
83
  */
84
84
  forwardRegistration?: ForwardRegistrationScope;
85
+ /** `patchLint.tokenScales`, for the scales' `minFiles` floors. */
86
+ tokenScales?: PatchLintTokenScale[];
85
87
  }
86
88
  /**
87
89
  * Builds a {@link PatchQueueContext} by reading every .patch file in the