@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
@@ -15,11 +15,32 @@
15
15
  * - Two registration shapes are recognised:
16
16
  * (A) Standalone statement:
17
17
  * customElements.setElementCreationCallback("tag", ...);
18
- * (B) Entry inside a `for (... of [ ... ])` registration array:
18
+ * (B) Entry inside a `for (... of [ ... ])` registration array, or an
19
+ * array declared by name and iterated with `for (... of NAME)`:
19
20
  * ["tag", "chrome://..."]
20
21
  * Both are deleted together with any trailing comma and newline so the
21
22
  * resulting file is still valid JavaScript.
22
23
  */
24
+ import type * as estree from 'estree';
25
+ import { type AcornESTreeNode } from './ast-utils.js';
26
+ /** A `[start, end)` source range in customElements.js. */
27
+ export interface RemovalRange {
28
+ start: number;
29
+ end: number;
30
+ }
31
+ /**
32
+ * Walks the AST and returns the source range of every registration of
33
+ * `tagName`: each `[tag, module]` entry of a registration list, and each
34
+ * statement enclosing a `setElementCreationCallback(tag, ...)` call.
35
+ * Ancestor tracking lets us tell an "entry" array from a random
36
+ * `["moz-foo", ...]` literal (only direct children of a registration list
37
+ * are entries). Shared by removal and the in-place rename.
38
+ *
39
+ * @param ast - Parsed customElements.js
40
+ * @param tagName - Tag whose registrations to find
41
+ * @returns Unexpanded `[start, end)` ranges, in source order
42
+ */
43
+ export declare function findRegistrationRanges(ast: AcornESTreeNode<estree.Program>, tagName: string): RemovalRange[];
23
44
  /**
24
45
  * Removes a custom element registration from customElements.js.
25
46
  *
@@ -16,7 +16,8 @@
16
16
  * - Two registration shapes are recognised:
17
17
  * (A) Standalone statement:
18
18
  * customElements.setElementCreationCallback("tag", ...);
19
- * (B) Entry inside a `for (... of [ ... ])` registration array:
19
+ * (B) Entry inside a `for (... of [ ... ])` registration array, or an
20
+ * array declared by name and iterated with `for (... of NAME)`:
20
21
  * ["tag", "chrome://..."]
21
22
  * Both are deleted together with any trailing comma and newline so the
22
23
  * resulting file is still valid JavaScript.
@@ -120,28 +121,63 @@ function isStandaloneCallbackCallFor(call, tagName) {
120
121
  return tagArg.value === tagName;
121
122
  }
122
123
  /**
123
- * Walks the AST and collects every removal range for `tagName`. Ancestor
124
- * tracking lets us tell an "entry" array from a random `["moz-foo", ...]`
125
- * literal (only direct children of the outer registration `ArrayExpression`
126
- * are entries) and lets us lift a `setElementCreationCallback` call up to
127
- * its enclosing statement.
124
+ * Names of the identifiers used as the right-hand side of a `for (... of X)`
125
+ * loop. A registration list declared as `const ELEMENTS = [...]` and
126
+ * iterated by name is a registration array just like an inline literal: the
127
+ * add path (`addCustomElementRegistration`) has always written into
128
+ * it, so the remove and rename paths must find entries there too or a
129
+ * rename leaves the old entry behind.
128
130
  */
129
- function collectRemovalRanges(ast, content, tagName) {
131
+ function collectForOfIdentifiers(ast) {
132
+ const names = new Set();
133
+ walkAST(ast, {
134
+ enter(node) {
135
+ if (node.type !== 'ForOfStatement')
136
+ return;
137
+ const right = asEstree(node).right;
138
+ if (right.type === 'Identifier')
139
+ names.add(right.name);
140
+ },
141
+ });
142
+ return names;
143
+ }
144
+ /** True when `parent`/`grandparent` make an array a registration list. */
145
+ function isRegistrationList(parent, grandparent, forOfIdentifiers) {
146
+ if (parent?.type !== 'ArrayExpression' || !grandparent)
147
+ return false;
148
+ if (grandparent.type === 'ForOfStatement')
149
+ return true;
150
+ if (grandparent.type !== 'VariableDeclarator')
151
+ return false;
152
+ const id = asEstree(grandparent).id;
153
+ return id.type === 'Identifier' && forOfIdentifiers.has(id.name);
154
+ }
155
+ /**
156
+ * Walks the AST and returns the source range of every registration of
157
+ * `tagName`: each `[tag, module]` entry of a registration list, and each
158
+ * statement enclosing a `setElementCreationCallback(tag, ...)` call.
159
+ * Ancestor tracking lets us tell an "entry" array from a random
160
+ * `["moz-foo", ...]` literal (only direct children of a registration list
161
+ * are entries). Shared by removal and the in-place rename.
162
+ *
163
+ * @param ast - Parsed customElements.js
164
+ * @param tagName - Tag whose registrations to find
165
+ * @returns Unexpanded `[start, end)` ranges, in source order
166
+ */
167
+ export function findRegistrationRanges(ast, tagName) {
130
168
  const ranges = [];
131
169
  const ancestors = [];
170
+ const forOfIdentifiers = collectForOfIdentifiers(ast);
132
171
  walkAST(ast, {
133
172
  enter(node) {
134
- // Entry array: [tag, module] inside the outer for-of array literal.
135
- // The immediate parent must be an ArrayExpression (the registration
136
- // list) whose own grandparent is the `for (...) of <array>` loop.
173
+ // Entry array: [tag, module] inside a registration list, either the
174
+ // for-of array literal itself or an array declared by name and
175
+ // iterated by a for-of loop.
137
176
  if (node.type === 'ArrayExpression' && isEntryArrayFor(node, tagName)) {
138
177
  const parent = ancestors[ancestors.length - 1];
139
178
  const grandparent = ancestors[ancestors.length - 2];
140
- if (parent &&
141
- parent.type === 'ArrayExpression' &&
142
- grandparent &&
143
- grandparent.type === 'ForOfStatement') {
144
- ranges.push(expandRemovalRange(content, node.start, node.end));
179
+ if (isRegistrationList(parent, grandparent, forOfIdentifiers)) {
180
+ ranges.push({ start: node.start, end: node.end });
145
181
  }
146
182
  }
147
183
  // Standalone call: customElements.setElementCreationCallback(tag, …)
@@ -162,7 +198,7 @@ function collectRemovalRanges(ast, content, tagName) {
162
198
  }
163
199
  }
164
200
  const target = enclosing ?? call;
165
- ranges.push(expandRemovalRange(content, target.start, target.end));
201
+ ranges.push({ start: target.start, end: target.end });
166
202
  }
167
203
  }
168
204
  ancestors.push(node);
@@ -207,7 +243,7 @@ export async function removeCustomElementRegistration(engineDir, tagName) {
207
243
  // risks corrupting it. The caller's regex fallback handles the retry.
208
244
  return;
209
245
  }
210
- const ranges = collectRemovalRanges(ast, content, tagName);
246
+ const ranges = findRegistrationRanges(ast, tagName).map((range) => expandRemovalRange(content, range.start, range.end));
211
247
  if (ranges.length === 0) {
212
248
  return;
213
249
  }
@@ -0,0 +1,26 @@
1
+ /**
2
+ * In-place rename of a custom element registration in customElements.js.
3
+ *
4
+ * `furnace rename` used to remove the old entry and add a new one. On a
5
+ * registration list the remove path could not see, that left the old entry
6
+ * beside the new one, and the new entry was written without the project
7
+ * marker every sibling line carries (`// <MARKER>:`), so the next lint
8
+ * flagged it as an unmarked engine edit. Rewriting the tag and module
9
+ * literals inside the existing entry keeps the entry's position, layout and
10
+ * trailing marker comments exactly as they were.
11
+ */
12
+ /**
13
+ * Renames `oldTag`'s registration in customElements.js in place.
14
+ *
15
+ * Returns false, writing nothing, when the file is missing or unparsable,
16
+ * holds no registration for `oldTag`, or already registers `newTag` (an
17
+ * in-place rewrite would then register it twice); the caller then falls
18
+ * back to remove-and-add, whose add is idempotent. Never parses with a line-based heuristic: an unparsable
19
+ * file is a doctor problem, not something a rename edits around.
20
+ *
21
+ * @param engineDir - Path to the Firefox engine source root
22
+ * @param oldTag - Tag being renamed away from
23
+ * @param newTag - Tag being renamed to
24
+ * @returns True when at least one registration was rewritten
25
+ */
26
+ export declare function renameCustomElementRegistration(engineDir: string, oldTag: string, newTag: string): Promise<boolean>;
@@ -0,0 +1,77 @@
1
+ // SPDX-License-Identifier: EUPL-1.2
2
+ /**
3
+ * In-place rename of a custom element registration in customElements.js.
4
+ *
5
+ * `furnace rename` used to remove the old entry and add a new one. On a
6
+ * registration list the remove path could not see, that left the old entry
7
+ * beside the new one, and the new entry was written without the project
8
+ * marker every sibling line carries (`// <MARKER>:`), so the next lint
9
+ * flagged it as an unmarked engine edit. Rewriting the tag and module
10
+ * literals inside the existing entry keeps the entry's position, layout and
11
+ * trailing marker comments exactly as they were.
12
+ */
13
+ import { join } from 'node:path';
14
+ import MagicString from 'magic-string';
15
+ import { pathExists, readText, writeText } from '../utils/fs.js';
16
+ import { escapeRegex } from '../utils/regex.js';
17
+ import { parseScript } from './ast-utils.js';
18
+ import { CUSTOM_ELEMENTS_JS } from './furnace-constants.js';
19
+ import { isTagAlreadyRegistered } from './furnace-registration-ast.js';
20
+ import { findRegistrationRanges } from './furnace-registration-remove.js';
21
+ /**
22
+ * Rewrites the old tag's literals inside one registration's source: the
23
+ * quoted tag itself and the module file name in its chrome:// URI.
24
+ * Everything else in the range (indentation, line breaks, comments between
25
+ * elements) is left byte-for-byte.
26
+ */
27
+ function renameRegistrationSource(source, oldTag, newTag) {
28
+ const escaped = escapeRegex(oldTag);
29
+ return source
30
+ .replace(new RegExp(`(["'])${escaped}\\1`, 'g'), `$1${newTag}$1`)
31
+ .replace(new RegExp(`/${escaped}(\\.m?js["'])`, 'g'), `/${newTag}$1`);
32
+ }
33
+ /**
34
+ * Renames `oldTag`'s registration in customElements.js in place.
35
+ *
36
+ * Returns false, writing nothing, when the file is missing or unparsable,
37
+ * holds no registration for `oldTag`, or already registers `newTag` (an
38
+ * in-place rewrite would then register it twice); the caller then falls
39
+ * back to remove-and-add, whose add is idempotent. Never parses with a line-based heuristic: an unparsable
40
+ * file is a doctor problem, not something a rename edits around.
41
+ *
42
+ * @param engineDir - Path to the Firefox engine source root
43
+ * @param oldTag - Tag being renamed away from
44
+ * @param newTag - Tag being renamed to
45
+ * @returns True when at least one registration was rewritten
46
+ */
47
+ export async function renameCustomElementRegistration(engineDir, oldTag, newTag) {
48
+ const filePath = join(engineDir, CUSTOM_ELEMENTS_JS);
49
+ if (!(await pathExists(filePath)))
50
+ return false;
51
+ const content = await readText(filePath);
52
+ if (!content.includes(`"${oldTag}"`) && !content.includes(`'${oldTag}'`))
53
+ return false;
54
+ if (isTagAlreadyRegistered(content, newTag))
55
+ return false;
56
+ let ranges;
57
+ try {
58
+ ranges = findRegistrationRanges(parseScript(content), oldTag);
59
+ }
60
+ catch {
61
+ return false;
62
+ }
63
+ if (ranges.length === 0)
64
+ return false;
65
+ const ms = new MagicString(content);
66
+ for (const range of ranges) {
67
+ const source = content.slice(range.start, range.end);
68
+ const renamed = renameRegistrationSource(source, oldTag, newTag);
69
+ if (renamed !== source)
70
+ ms.overwrite(range.start, range.end, renamed);
71
+ }
72
+ const next = ms.toString();
73
+ if (next === content)
74
+ return false;
75
+ await writeText(filePath, next);
76
+ return true;
77
+ }
@@ -1,5 +1,6 @@
1
1
  export { addCustomElementRegistration, validateCustomElementRegistration, } from './furnace-registration-ast.js';
2
2
  export { removeCustomElementRegistration } from './furnace-registration-remove.js';
3
+ export { renameCustomElementRegistration } from './furnace-registration-rename.js';
3
4
  /**
4
5
  * Adds jar.mn entries that map chrome:// URIs to on-disk paths for a
5
6
  * component's files.
@@ -21,9 +22,9 @@ export { removeCustomElementRegistration } from './furnace-registration-remove.j
21
22
  * in alphabetical order relative to these.
22
23
  * - **Fallback**: if no `content/global/elements/` line exists (empty
23
24
  * project), looks for any `content/global/` line and inserts after it.
24
- * - **Idempotency**: entries already present (checked by exact path match
25
- * on `content/global/elements/{file}` with a trailing whitespace or
26
- * end-of-line boundary) are skipped.
25
+ * - **Idempotency**: entries already present anywhere in the file (an exact
26
+ * target match on `content/global/elements/{file}`, or a source match on
27
+ * `(widgets/{tagName}/{file})`) are skipped, including hand-written ones.
27
28
  *
28
29
  * If Firefox upstream changes the jar.mn section ordering or switches to a
29
30
  * different resource registration mechanism, the preflight validation in
@@ -57,11 +58,20 @@ export declare function addJarMnEntries(engineDir: string, tagName: string, file
57
58
  * @returns Number of entries inserted (0 when already present, or jar.mn missing)
58
59
  */
59
60
  export declare function addLocaleFtlJarMnEntry(engineDir: string, jarMnRelPath: string, tagName: string, chromeSubPath: string): Promise<number>;
61
+ /**
62
+ * True when the locale jar.mn carries a per-widget line for `tagName`.
63
+ * False when the jar.mn is missing. Used by `furnace rename --dry-run` to
64
+ * say whether a rename would re-point a line or leave the jar alone.
65
+ */
66
+ export declare function hasLocaleFtlJarMnEntry(engineDir: string, jarMnRelPath: string, tagName: string, chromeSubPath: string): Promise<boolean>;
60
67
  /**
61
68
  * Removes a locale jar.mn entry previously written by `addLocaleFtlJarMnEntry`.
62
69
  * Idempotent: if the entry is absent or the file is missing, nothing happens.
70
+ *
71
+ * @returns True when a line was removed, so a rename re-points only an
72
+ * entry that existed instead of inventing one
63
73
  */
64
- export declare function removeLocaleFtlJarMnEntry(engineDir: string, jarMnRelPath: string, tagName: string, chromeSubPath: string): Promise<void>;
74
+ export declare function removeLocaleFtlJarMnEntry(engineDir: string, jarMnRelPath: string, tagName: string, chromeSubPath: string): Promise<boolean>;
65
75
  /**
66
76
  * Removes all jar.mn entries for a given tag name.
67
77
  *
@@ -27,8 +27,24 @@ function detectJarMnIndent(lines) {
27
27
  // Re-export everything from the AST module so existing imports keep working
28
28
  export { addCustomElementRegistration, validateCustomElementRegistration, } from './furnace-registration-ast.js';
29
29
  export { removeCustomElementRegistration } from './furnace-registration-remove.js';
30
+ export { renameCustomElementRegistration } from './furnace-registration-rename.js';
30
31
  import { escapeRegex } from '../utils/regex.js';
31
32
  import { JAR_MN } from './furnace-constants.js';
33
+ /**
34
+ * True when jar.mn already registers `file` of component `tagName` anywhere
35
+ * in the file: either a line targeting `content/global/elements/<file>` or a
36
+ * line sourcing `(widgets/<tagName>/<file>)`. The position of the existing
37
+ * line is irrelevant. A hand-written line below an unrelated entry counts
38
+ * exactly like one Furnace wrote itself, so apply never adds a second line
39
+ * and mach never fails with "Item already in manifest". Boundary-aware so
40
+ * `moz-card.css` does not match `moz-card-group.css`.
41
+ */
42
+ function isJarMnFileRegistered(content, tagName, file) {
43
+ const escapedFile = escapeRegex(file);
44
+ const target = new RegExp(`content/global/elements/${escapedFile}(?:\\s|$)`, 'm');
45
+ const source = new RegExp(`\\(widgets/${escapeRegex(tagName)}/${escapedFile}\\)`);
46
+ return target.test(content) || source.test(content);
47
+ }
32
48
  /**
33
49
  * Adds jar.mn entries that map chrome:// URIs to on-disk paths for a
34
50
  * component's files.
@@ -50,9 +66,9 @@ import { JAR_MN } from './furnace-constants.js';
50
66
  * in alphabetical order relative to these.
51
67
  * - **Fallback**: if no `content/global/elements/` line exists (empty
52
68
  * project), looks for any `content/global/` line and inserts after it.
53
- * - **Idempotency**: entries already present (checked by exact path match
54
- * on `content/global/elements/{file}` with a trailing whitespace or
55
- * end-of-line boundary) are skipped.
69
+ * - **Idempotency**: entries already present anywhere in the file (an exact
70
+ * target match on `content/global/elements/{file}`, or a source match on
71
+ * `(widgets/{tagName}/{file})`) are skipped, including hand-written ones.
56
72
  *
57
73
  * If Firefox upstream changes the jar.mn section ordering or switches to a
58
74
  * different resource registration mechanism, the preflight validation in
@@ -70,9 +86,8 @@ export async function addJarMnEntries(engineDir, tagName, files) {
70
86
  }
71
87
  let content = await readText(filePath);
72
88
  const lines = content.split('\n');
73
- // Filter to files not already registered. Use a word-boundary-aware
74
- // check so that "moz-card.css" does not match "moz-card-group.css".
75
- const newFiles = files.filter((f) => !new RegExp(`content/global/elements/${escapeRegex(f)}(?:\\s|$)`, 'm').test(content));
89
+ // Filter to files not already registered anywhere in the jar.
90
+ const newFiles = [...new Set(files)].filter((f) => !isJarMnFileRegistered(content, tagName, f));
76
91
  if (newFiles.length === 0)
77
92
  return 0;
78
93
  // Build new entry lines using the indent detected from existing entries.
@@ -181,22 +196,41 @@ function detectLocaleJarMnIndent(lines, chromeSubPath) {
181
196
  // Fall back to any existing `locale/...` indent before giving up.
182
197
  return detectIndent(lines, exact) ?? detectIndent(lines, /^(\s+)locale\//) ?? ' ';
183
198
  }
199
+ /** Matches a per-widget locale jar.mn line for `<chromeSubPath>/<tagName>.ftl`. */
200
+ function localeFtlJarMnPattern(tagName, chromeSubPath) {
201
+ return new RegExp(`locale\\/(?:@AB_CD@|[a-zA-Z-]+)\\/${escapeRegex(chromeSubPath)}\\/${escapeRegex(tagName)}\\.ftl`);
202
+ }
203
+ /**
204
+ * True when the locale jar.mn carries a per-widget line for `tagName`.
205
+ * False when the jar.mn is missing. Used by `furnace rename --dry-run` to
206
+ * say whether a rename would re-point a line or leave the jar alone.
207
+ */
208
+ export async function hasLocaleFtlJarMnEntry(engineDir, jarMnRelPath, tagName, chromeSubPath) {
209
+ const filePath = join(engineDir, jarMnRelPath);
210
+ if (!(await pathExists(filePath)))
211
+ return false;
212
+ return localeFtlJarMnPattern(tagName, chromeSubPath).test(await readText(filePath));
213
+ }
184
214
  /**
185
215
  * Removes a locale jar.mn entry previously written by `addLocaleFtlJarMnEntry`.
186
216
  * Idempotent: if the entry is absent or the file is missing, nothing happens.
217
+ *
218
+ * @returns True when a line was removed, so a rename re-points only an
219
+ * entry that existed instead of inventing one
187
220
  */
188
221
  export async function removeLocaleFtlJarMnEntry(engineDir, jarMnRelPath, tagName, chromeSubPath) {
189
222
  const filePath = join(engineDir, jarMnRelPath);
190
223
  if (!(await pathExists(filePath))) {
191
- return;
224
+ return false;
192
225
  }
193
226
  const content = await readText(filePath);
194
227
  const lines = content.split('\n');
195
- const pattern = new RegExp(`locale\\/(?:@AB_CD@|[a-zA-Z-]+)\\/${escapeRegex(chromeSubPath)}\\/${escapeRegex(tagName)}\\.ftl`);
228
+ const pattern = localeFtlJarMnPattern(tagName, chromeSubPath);
196
229
  const filtered = lines.filter((line) => !pattern.test(line));
197
230
  if (filtered.length === lines.length)
198
- return;
231
+ return false;
199
232
  await writeText(filePath, filtered.join('\n'));
233
+ return true;
200
234
  }
201
235
  /**
202
236
  * Removes all jar.mn entries for a given tag name.
@@ -284,7 +318,7 @@ export async function validateJarMnInsertionForFiles(engineDir, tagName, files)
284
318
  }
285
319
  const content = await readText(filePath);
286
320
  const lines = content.split('\n');
287
- const newFiles = files.filter((f) => !new RegExp(`content/global/elements/${escapeRegex(f)}(?:\\s|$)`, 'm').test(content));
321
+ const newFiles = files.filter((f) => !isJarMnFileRegistered(content, tagName, f));
288
322
  if (newFiles.length === 0)
289
323
  return;
290
324
  const elementLinePattern = /^\s+content\/global\/elements\/([^.]+)\./;
@@ -8,6 +8,13 @@
8
8
  * The check is advisory only: errors (broken furnace config, partial
9
9
  * state, transient filesystem failure) must never block the caller.
10
10
  */
11
+ /**
12
+ * Names of the tracked override and custom components whose source changed
13
+ * on disk since the last apply, i.e. edits engine/ does not hold yet.
14
+ * Throws on a broken config or state; {@link warnIfFurnaceStale} downgrades
15
+ * that.
16
+ */
17
+ export declare function listStaleFurnaceComponents(projectRoot: string): Promise<string[]>;
11
18
  /**
12
19
  * Emits a warning when any tracked override or custom component has
13
20
  * changed on disk since the last apply. Safe to call from any build-time
@@ -13,6 +13,39 @@ import { pathExists } from '../utils/fs.js';
13
13
  import { verbose, warn } from '../utils/logger.js';
14
14
  import { extractComponentChecksums, hasComponentChanged } from './furnace-apply-helpers.js';
15
15
  import { furnaceConfigExists, getFurnacePaths, loadFurnaceConfig, loadFurnaceState, } from './furnace-config.js';
16
+ /**
17
+ * Names of the tracked override and custom components whose source changed
18
+ * on disk since the last apply, i.e. edits engine/ does not hold yet.
19
+ * Throws on a broken config or state; {@link warnIfFurnaceStale} downgrades
20
+ * that.
21
+ */
22
+ export async function listStaleFurnaceComponents(projectRoot) {
23
+ if (!(await furnaceConfigExists(projectRoot)))
24
+ return [];
25
+ const config = await loadFurnaceConfig(projectRoot);
26
+ const state = await loadFurnaceState(projectRoot);
27
+ const furnacePaths = getFurnacePaths(projectRoot);
28
+ if (!state.appliedChecksums)
29
+ return [];
30
+ const stale = [];
31
+ for (const name of Object.keys(config.overrides)) {
32
+ const dir = `${furnacePaths.overridesDir}/${name}`;
33
+ if (!(await pathExists(dir)))
34
+ continue;
35
+ const prev = extractComponentChecksums(state.appliedChecksums, 'override', name);
36
+ if (await hasComponentChanged(dir, prev))
37
+ stale.push(name);
38
+ }
39
+ for (const name of Object.keys(config.custom)) {
40
+ const dir = `${furnacePaths.customDir}/${name}`;
41
+ if (!(await pathExists(dir)))
42
+ continue;
43
+ const prev = extractComponentChecksums(state.appliedChecksums, 'custom', name);
44
+ if (await hasComponentChanged(dir, prev))
45
+ stale.push(name);
46
+ }
47
+ return stale;
48
+ }
16
49
  /**
17
50
  * Emits a warning when any tracked override or custom component has
18
51
  * changed on disk since the last apply. Safe to call from any build-time
@@ -21,30 +54,7 @@ import { furnaceConfigExists, getFurnacePaths, loadFurnaceConfig, loadFurnaceSta
21
54
  */
22
55
  export async function warnIfFurnaceStale(projectRoot) {
23
56
  try {
24
- if (!(await furnaceConfigExists(projectRoot)))
25
- return;
26
- const config = await loadFurnaceConfig(projectRoot);
27
- const state = await loadFurnaceState(projectRoot);
28
- const furnacePaths = getFurnacePaths(projectRoot);
29
- if (!state.appliedChecksums)
30
- return;
31
- const stale = [];
32
- for (const name of Object.keys(config.overrides)) {
33
- const dir = `${furnacePaths.overridesDir}/${name}`;
34
- if (!(await pathExists(dir)))
35
- continue;
36
- const prev = extractComponentChecksums(state.appliedChecksums, 'override', name);
37
- if (await hasComponentChanged(dir, prev))
38
- stale.push(name);
39
- }
40
- for (const name of Object.keys(config.custom)) {
41
- const dir = `${furnacePaths.customDir}/${name}`;
42
- if (!(await pathExists(dir)))
43
- continue;
44
- const prev = extractComponentChecksums(state.appliedChecksums, 'custom', name);
45
- if (await hasComponentChanged(dir, prev))
46
- stale.push(name);
47
- }
57
+ const stale = await listStaleFurnaceComponents(projectRoot);
48
58
  if (stale.length > 0) {
49
59
  warn(`Furnace component${stale.length === 1 ? '' : 's'} modified since last apply: ${stale.join(', ')}. ` +
50
60
  'Run "fireforge furnace apply" (or "fireforge build" which auto-applies) to update the engine.');
@@ -1,7 +1,9 @@
1
- import type { CustomComponentConfig, ValidationIssue } from '../types/furnace.js';
1
+ import type { CustomComponentConfig, FurnaceOptInCheck, ValidationIssue } from '../types/furnace.js';
2
2
  /**
3
- * Validates accessibility patterns in a component's .mjs file.
4
- * Checks for ARIA roles, keyboard handlers, l10n, and focus delegation.
3
+ * Validates accessibility patterns in a component's composed source: its
4
+ * host module and every companion module (see
5
+ * {@link readComposedComponentSource}). Checks for ARIA roles, keyboard
6
+ * handlers, l10n, and focus delegation.
5
7
  *
6
8
  * @param componentDir - Directory holding the component's sources
7
9
  * @param tagName - Custom element tag name, used to locate `<tagName>.mjs`
@@ -11,8 +13,10 @@ import type { CustomComponentConfig, ValidationIssue } from '../types/furnace.js
11
13
  * (`keyboardCovered: true`) or via `composes` naming a native-interactive
12
14
  * inner element. Optional so stock/override callers and test fixtures
13
15
  * without config in scope can continue to call without changes.
16
+ * @param optInChecks - `furnace.json#optInChecks`. `icon-button-label`
17
+ * adds the icon-only `<moz-button>` naming check.
14
18
  */
15
- export declare function validateAccessibility(componentDir: string, tagName: string, customConfig?: CustomComponentConfig): Promise<ValidationIssue[]>;
19
+ export declare function validateAccessibility(componentDir: string, tagName: string, customConfig?: CustomComponentConfig, optInChecks?: readonly FurnaceOptInCheck[]): Promise<ValidationIssue[]>;
16
20
  /**
17
21
  * Detects hardcoded user-visible template text that should usually be
18
22
  * localized.