@hominis/fireforge 0.43.1 → 0.44.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 (470) hide show
  1. package/CHANGELOG.md +126 -0
  2. package/README.md +10 -1
  3. package/dist/bin/fireforge.d.ts +4 -9
  4. package/dist/bin/fireforge.js +42 -40
  5. package/dist/build-info.json +4 -4
  6. package/dist/src/cli.js +74 -8
  7. package/dist/src/commands/bootstrap.js +17 -20
  8. package/dist/src/commands/build.js +25 -32
  9. package/dist/src/commands/config.js +34 -41
  10. package/dist/src/commands/discard.js +8 -9
  11. package/dist/src/commands/doctor-check-core.d.ts +4 -18
  12. package/dist/src/commands/doctor-check-core.js +8 -35
  13. package/dist/src/commands/doctor-external-toolchains.js +2 -2
  14. package/dist/src/commands/doctor-furnace-config-sync.d.ts +18 -0
  15. package/dist/src/commands/{doctor-furnace-manifest-sync.js → doctor-furnace-config-sync.js} +27 -26
  16. package/dist/src/commands/doctor-furnace-jar.d.ts +7 -9
  17. package/dist/src/commands/doctor-furnace-jar.js +7 -9
  18. package/dist/src/commands/doctor-furnace.js +21 -24
  19. package/dist/src/commands/doctor-orphaned-harness.d.ts +16 -20
  20. package/dist/src/commands/doctor-orphaned-harness.js +18 -44
  21. package/dist/src/commands/doctor-post-rebase-audit.d.ts +2 -0
  22. package/dist/src/commands/{doctor/post-rebase-audit.js → doctor-post-rebase-audit.js} +3 -3
  23. package/dist/src/commands/doctor-working-tree.d.ts +10 -12
  24. package/dist/src/commands/doctor-working-tree.js +11 -18
  25. package/dist/src/commands/doctor.js +35 -53
  26. package/dist/src/commands/download.js +32 -48
  27. package/dist/src/commands/export-all.js +29 -33
  28. package/dist/src/commands/export-flow.js +6 -6
  29. package/dist/src/commands/export-placement-conflicts.js +10 -9
  30. package/dist/src/commands/export-placement-gate.js +5 -5
  31. package/dist/src/commands/export-shared.d.ts +30 -33
  32. package/dist/src/commands/export-shared.js +45 -43
  33. package/dist/src/commands/export.js +21 -27
  34. package/dist/src/commands/furnace/apply.js +14 -23
  35. package/dist/src/commands/furnace/chrome-doc-remove.js +14 -21
  36. package/dist/src/commands/furnace/chrome-doc-templates.d.ts +23 -23
  37. package/dist/src/commands/furnace/chrome-doc-templates.js +23 -23
  38. package/dist/src/commands/furnace/chrome-doc-tests.js +26 -29
  39. package/dist/src/commands/furnace/chrome-doc.d.ts +16 -17
  40. package/dist/src/commands/furnace/chrome-doc.js +31 -41
  41. package/dist/src/commands/furnace/create-browser-test.d.ts +4 -4
  42. package/dist/src/commands/furnace/create-browser-test.js +8 -8
  43. package/dist/src/commands/furnace/create-mochikit.d.ts +6 -7
  44. package/dist/src/commands/furnace/create-mochikit.js +8 -9
  45. package/dist/src/commands/furnace/create-readback.d.ts +12 -13
  46. package/dist/src/commands/furnace/create-readback.js +12 -13
  47. package/dist/src/commands/furnace/create-templates.d.ts +22 -28
  48. package/dist/src/commands/furnace/create-templates.js +35 -30
  49. package/dist/src/commands/furnace/create-xpcshell.js +2 -2
  50. package/dist/src/commands/furnace/create.js +33 -23
  51. package/dist/src/commands/furnace/deploy.js +16 -24
  52. package/dist/src/commands/furnace/diff.js +9 -9
  53. package/dist/src/commands/furnace/init.js +33 -36
  54. package/dist/src/commands/furnace/override.js +23 -25
  55. package/dist/src/commands/furnace/preview.js +47 -67
  56. package/dist/src/commands/furnace/refresh.js +12 -16
  57. package/dist/src/commands/furnace/remove-mutations.d.ts +3 -6
  58. package/dist/src/commands/furnace/remove-mutations.js +9 -16
  59. package/dist/src/commands/furnace/remove-state.js +1 -1
  60. package/dist/src/commands/furnace/remove.js +33 -38
  61. package/dist/src/commands/furnace/rename-xpcshell.d.ts +8 -11
  62. package/dist/src/commands/furnace/rename-xpcshell.js +8 -11
  63. package/dist/src/commands/furnace/rename.js +59 -69
  64. package/dist/src/commands/furnace/scan.js +19 -33
  65. package/dist/src/commands/furnace/status.js +12 -9
  66. package/dist/src/commands/furnace/sync.js +9 -16
  67. package/dist/src/commands/furnace/validate.js +20 -20
  68. package/dist/src/commands/import.js +42 -35
  69. package/dist/src/commands/lint-per-patch.js +15 -10
  70. package/dist/src/commands/lint-per-run-checkjs.d.ts +13 -13
  71. package/dist/src/commands/lint-per-run-checkjs.js +13 -13
  72. package/dist/src/commands/lint-report.js +6 -7
  73. package/dist/src/commands/lint.d.ts +15 -16
  74. package/dist/src/commands/lint.js +86 -102
  75. package/dist/src/commands/package.js +6 -11
  76. package/dist/src/commands/patch/compact.js +1 -1
  77. package/dist/src/commands/patch/delete.js +24 -33
  78. package/dist/src/commands/patch/index.d.ts +5 -6
  79. package/dist/src/commands/patch/index.js +10 -12
  80. package/dist/src/commands/patch/lint-ignore.js +14 -13
  81. package/dist/src/commands/patch/move-files-create.d.ts +6 -6
  82. package/dist/src/commands/patch/move-files-create.js +8 -8
  83. package/dist/src/commands/patch/move-files-into.d.ts +6 -6
  84. package/dist/src/commands/patch/move-files-into.js +8 -8
  85. package/dist/src/commands/patch/patch-context.d.ts +2 -3
  86. package/dist/src/commands/patch/patch-context.js +2 -3
  87. package/dist/src/commands/patch/rename.d.ts +10 -11
  88. package/dist/src/commands/patch/rename.js +11 -12
  89. package/dist/src/commands/patch/reorder.js +8 -9
  90. package/dist/src/commands/patch/split-plan.js +1 -1
  91. package/dist/src/commands/patch/split.d.ts +8 -10
  92. package/dist/src/commands/patch/split.js +9 -11
  93. package/dist/src/commands/patch/staged-dependency-validate.js +8 -8
  94. package/dist/src/commands/patch/staged-dependency.js +7 -3
  95. package/dist/src/commands/patch/tier.d.ts +9 -9
  96. package/dist/src/commands/patch/tier.js +18 -15
  97. package/dist/src/commands/re-export-adjacent.js +9 -8
  98. package/dist/src/commands/re-export-bulk-scan.d.ts +9 -9
  99. package/dist/src/commands/re-export-bulk-scan.js +22 -21
  100. package/dist/src/commands/re-export-drift.js +10 -10
  101. package/dist/src/commands/re-export-files.d.ts +6 -7
  102. package/dist/src/commands/re-export-files.js +34 -44
  103. package/dist/src/commands/re-export-lint.d.ts +10 -13
  104. package/dist/src/commands/re-export-lint.js +16 -14
  105. package/dist/src/commands/re-export-options.d.ts +6 -6
  106. package/dist/src/commands/re-export-options.js +6 -6
  107. package/dist/src/commands/re-export-register.d.ts +4 -10
  108. package/dist/src/commands/re-export-register.js +5 -11
  109. package/dist/src/commands/re-export-scan.js +1 -1
  110. package/dist/src/commands/re-export-single.d.ts +3 -3
  111. package/dist/src/commands/re-export-single.js +33 -25
  112. package/dist/src/commands/re-export.js +13 -21
  113. package/dist/src/commands/rebase/abort.js +3 -3
  114. package/dist/src/commands/rebase/confirm.js +2 -1
  115. package/dist/src/commands/rebase/continue.d.ts +1 -1
  116. package/dist/src/commands/rebase/continue.js +14 -9
  117. package/dist/src/commands/rebase/index.js +11 -11
  118. package/dist/src/commands/rebase/patch-loop.d.ts +7 -1
  119. package/dist/src/commands/rebase/patch-loop.js +60 -39
  120. package/dist/src/commands/rebase/summary.js +1 -1
  121. package/dist/src/commands/register.js +5 -7
  122. package/dist/src/commands/reset.js +2 -1
  123. package/dist/src/commands/resolve.d.ts +16 -13
  124. package/dist/src/commands/resolve.js +30 -33
  125. package/dist/src/commands/run.js +33 -35
  126. package/dist/src/commands/setup-support.js +15 -19
  127. package/dist/src/commands/setup.js +13 -9
  128. package/dist/src/commands/status-check.d.ts +6 -6
  129. package/dist/src/commands/status-json.d.ts +6 -6
  130. package/dist/src/commands/status-json.js +5 -0
  131. package/dist/src/commands/status-output.d.ts +5 -5
  132. package/dist/src/commands/status-output.js +6 -6
  133. package/dist/src/commands/status-ownership.d.ts +16 -14
  134. package/dist/src/commands/status-ownership.js +16 -14
  135. package/dist/src/commands/status.js +42 -34
  136. package/dist/src/commands/test-build-phase.js +26 -13
  137. package/dist/src/commands/test-diagnose.js +44 -44
  138. package/dist/src/commands/test-register.js +1 -0
  139. package/dist/src/commands/test-run.d.ts +14 -16
  140. package/dist/src/commands/test-run.js +21 -13
  141. package/dist/src/commands/test-stale-gate.d.ts +15 -16
  142. package/dist/src/commands/test-stale-gate.js +15 -16
  143. package/dist/src/commands/test-verdict.d.ts +20 -3
  144. package/dist/src/commands/test-verdict.js +30 -0
  145. package/dist/src/commands/test.js +83 -76
  146. package/dist/src/commands/token-coverage.js +3 -4
  147. package/dist/src/commands/token.js +16 -18
  148. package/dist/src/commands/tree.js +47 -31
  149. package/dist/src/commands/typecheck.d.ts +10 -12
  150. package/dist/src/commands/typecheck.js +24 -27
  151. package/dist/src/commands/verify.js +13 -15
  152. package/dist/src/commands/watch.js +21 -23
  153. package/dist/src/commands/wire.js +52 -62
  154. package/dist/src/core/ast-utils.d.ts +8 -7
  155. package/dist/src/core/ast-utils.js +8 -7
  156. package/dist/src/core/branding.d.ts +9 -14
  157. package/dist/src/core/branding.js +7 -11
  158. package/dist/src/core/browser-wire.d.ts +1 -1
  159. package/dist/src/core/browser-wire.js +14 -19
  160. package/dist/src/core/build-audit-platform.js +25 -33
  161. package/dist/src/core/build-audit-registration.js +17 -25
  162. package/dist/src/core/build-audit-resolve.d.ts +15 -17
  163. package/dist/src/core/build-audit-resolve.js +27 -33
  164. package/dist/src/core/build-audit-transforms.js +18 -19
  165. package/dist/src/core/build-audit.js +28 -42
  166. package/dist/src/core/build-baseline-types.d.ts +29 -35
  167. package/dist/src/core/build-baseline.d.ts +5 -4
  168. package/dist/src/core/build-baseline.js +14 -14
  169. package/dist/src/core/build-overwrite-guard.d.ts +7 -14
  170. package/dist/src/core/build-overwrite-guard.js +17 -27
  171. package/dist/src/core/build-prepare.d.ts +2 -2
  172. package/dist/src/core/build-prepare.js +8 -9
  173. package/dist/src/core/config-state.js +12 -4
  174. package/dist/src/core/config-validate.js +8 -5
  175. package/dist/src/core/config.d.ts +5 -8
  176. package/dist/src/core/config.js +7 -16
  177. package/dist/src/core/coverage-extend.d.ts +15 -13
  178. package/dist/src/core/coverage-extend.js +15 -13
  179. package/dist/src/core/destructive.d.ts +31 -9
  180. package/dist/src/core/destructive.js +29 -26
  181. package/dist/src/core/diff-hunks.js +10 -12
  182. package/dist/src/core/discard-baseline.d.ts +8 -8
  183. package/dist/src/core/discard-baseline.js +16 -15
  184. package/dist/src/core/display-state.d.ts +12 -14
  185. package/dist/src/core/display-state.js +12 -14
  186. package/dist/src/core/engine-changes.d.ts +2 -4
  187. package/dist/src/core/engine-changes.js +2 -4
  188. package/dist/src/core/engine-precondition.d.ts +28 -13
  189. package/dist/src/core/engine-precondition.js +25 -10
  190. package/dist/src/core/engine-session-lock.d.ts +47 -21
  191. package/dist/src/core/engine-session-lock.js +168 -33
  192. package/dist/src/core/export-moved-code-shape.d.ts +10 -10
  193. package/dist/src/core/export-moved-code-shape.js +10 -10
  194. package/dist/src/core/file-lock.d.ts +62 -5
  195. package/dist/src/core/file-lock.js +196 -59
  196. package/dist/src/core/firefox-cache.js +1 -3
  197. package/dist/src/core/firefox-extract.js +10 -14
  198. package/dist/src/core/firefox.d.ts +7 -5
  199. package/dist/src/core/firefox.js +4 -5
  200. package/dist/src/core/furnace-apply-dry-run.d.ts +2 -2
  201. package/dist/src/core/furnace-apply-dry-run.js +3 -2
  202. package/dist/src/core/furnace-apply-ftl.d.ts +7 -9
  203. package/dist/src/core/furnace-apply-ftl.js +12 -12
  204. package/dist/src/core/furnace-apply-helpers.d.ts +7 -7
  205. package/dist/src/core/furnace-apply-helpers.js +19 -16
  206. package/dist/src/core/furnace-apply-overwrite-warn.d.ts +8 -9
  207. package/dist/src/core/furnace-apply-overwrite-warn.js +8 -9
  208. package/dist/src/core/furnace-apply-undeploy-actions.d.ts +3 -4
  209. package/dist/src/core/furnace-apply-undeploy-actions.js +3 -4
  210. package/dist/src/core/furnace-apply.d.ts +5 -8
  211. package/dist/src/core/furnace-apply.js +19 -24
  212. package/dist/src/core/furnace-checksum-utils.d.ts +14 -0
  213. package/dist/src/core/furnace-checksum-utils.js +16 -0
  214. package/dist/src/core/furnace-config.d.ts +21 -30
  215. package/dist/src/core/furnace-config.js +32 -54
  216. package/dist/src/core/furnace-constants.d.ts +8 -0
  217. package/dist/src/core/furnace-constants.js +10 -2
  218. package/dist/src/core/furnace-css-fragments.d.ts +5 -5
  219. package/dist/src/core/furnace-css-fragments.js +5 -5
  220. package/dist/src/core/furnace-jsconfig.d.ts +11 -12
  221. package/dist/src/core/furnace-jsconfig.js +11 -12
  222. package/dist/src/core/furnace-marker.d.ts +7 -8
  223. package/dist/src/core/furnace-marker.js +7 -8
  224. package/dist/src/core/furnace-operation.d.ts +31 -0
  225. package/dist/src/core/furnace-operation.js +54 -17
  226. package/dist/src/core/furnace-precondition.d.ts +61 -0
  227. package/dist/src/core/furnace-precondition.js +67 -0
  228. package/dist/src/core/furnace-registration-remove.d.ts +5 -6
  229. package/dist/src/core/furnace-registration-remove.js +6 -7
  230. package/dist/src/core/furnace-registration-validate.d.ts +13 -0
  231. package/dist/src/core/furnace-registration-validate.js +20 -1
  232. package/dist/src/core/furnace-registration.d.ts +5 -6
  233. package/dist/src/core/furnace-registration.js +10 -12
  234. package/dist/src/core/furnace-rollback.js +7 -7
  235. package/dist/src/core/furnace-scanner.d.ts +1 -0
  236. package/dist/src/core/furnace-scanner.js +1 -2
  237. package/dist/src/core/furnace-stale-export.d.ts +10 -10
  238. package/dist/src/core/furnace-stale-export.js +10 -10
  239. package/dist/src/core/furnace-state-persist.d.ts +6 -8
  240. package/dist/src/core/furnace-state-persist.js +6 -8
  241. package/dist/src/core/furnace-validate-accessibility.d.ts +22 -0
  242. package/dist/src/core/furnace-validate-accessibility.js +310 -1
  243. package/dist/src/core/furnace-validate-compatibility.js +141 -1
  244. package/dist/src/core/furnace-validate-helpers.d.ts +5 -116
  245. package/dist/src/core/furnace-validate-helpers.js +0 -491
  246. package/dist/src/core/furnace-validate-registration.d.ts +7 -0
  247. package/dist/src/core/furnace-validate-registration.js +115 -41
  248. package/dist/src/core/furnace-validate.d.ts +16 -0
  249. package/dist/src/core/furnace-validate.js +188 -145
  250. package/dist/src/core/furnace-version-drift.d.ts +10 -11
  251. package/dist/src/core/furnace-version-drift.js +10 -11
  252. package/dist/src/core/git-base.d.ts +7 -9
  253. package/dist/src/core/git-base.js +7 -9
  254. package/dist/src/core/git-diff.d.ts +20 -9
  255. package/dist/src/core/git-diff.js +148 -63
  256. package/dist/src/core/git-file-ops.d.ts +19 -19
  257. package/dist/src/core/git-file-ops.js +19 -19
  258. package/dist/src/core/git-readonly-index.d.ts +53 -19
  259. package/dist/src/core/git-readonly-index.js +75 -31
  260. package/dist/src/core/git-status.d.ts +5 -6
  261. package/dist/src/core/git-status.js +5 -6
  262. package/dist/src/core/git.d.ts +9 -10
  263. package/dist/src/core/git.js +54 -70
  264. package/dist/src/core/license-headers.d.ts +17 -23
  265. package/dist/src/core/license-headers.js +17 -23
  266. package/dist/src/core/mach-build-artifacts.d.ts +9 -9
  267. package/dist/src/core/mach-build-artifacts.js +57 -19
  268. package/dist/src/core/mach-error-hints.js +42 -29
  269. package/dist/src/core/mach-known-noise-filter.d.ts +15 -16
  270. package/dist/src/core/mach-known-noise-filter.js +18 -20
  271. package/dist/src/core/mach-mozconfig.d.ts +14 -0
  272. package/dist/src/core/mach-mozconfig.js +30 -0
  273. package/dist/src/core/mach-resource-shim.d.ts +43 -58
  274. package/dist/src/core/mach-resource-shim.js +50 -67
  275. package/dist/src/core/mach.d.ts +37 -41
  276. package/dist/src/core/mach.js +50 -51
  277. package/dist/src/core/marionette-port.d.ts +36 -1
  278. package/dist/src/core/marionette-port.js +96 -31
  279. package/dist/src/core/marionette-preflight.d.ts +8 -12
  280. package/dist/src/core/marionette-preflight.js +86 -52
  281. package/dist/src/core/mochitest-server-port.d.ts +42 -0
  282. package/dist/src/core/mochitest-server-port.js +119 -0
  283. package/dist/src/core/module-resolution-preflight.d.ts +9 -11
  284. package/dist/src/core/module-resolution-preflight.js +9 -11
  285. package/dist/src/core/moz-manifest-helpers.d.ts +79 -0
  286. package/dist/src/core/moz-manifest-helpers.js +163 -0
  287. package/dist/src/core/{manifest-register.d.ts → moz-manifest-register.d.ts} +1 -1
  288. package/dist/src/core/{manifest-register.js → moz-manifest-register.js} +13 -28
  289. package/dist/src/core/{manifest-rules.d.ts → moz-manifest-rules.d.ts} +10 -1
  290. package/dist/src/core/{manifest-rules.js → moz-manifest-rules.js} +31 -24
  291. package/dist/src/core/{manifest-tokenizers.d.ts → moz-manifest-tokenizers.d.ts} +3 -5
  292. package/dist/src/core/{manifest-tokenizers.js → moz-manifest-tokenizers.js} +9 -12
  293. package/dist/src/core/ownership-table.d.ts +14 -16
  294. package/dist/src/core/ownership-table.js +14 -16
  295. package/dist/src/core/parser-fallback.d.ts +15 -1
  296. package/dist/src/core/parser-fallback.js +22 -3
  297. package/dist/src/core/patch-apply-fuzz.d.ts +10 -12
  298. package/dist/src/core/patch-apply-fuzz.js +15 -18
  299. package/dist/src/core/patch-apply.d.ts +13 -34
  300. package/dist/src/core/patch-apply.js +16 -76
  301. package/dist/src/core/patch-artifact-normalize.d.ts +13 -15
  302. package/dist/src/core/patch-artifact-normalize.js +13 -15
  303. package/dist/src/core/patch-export-metadata.d.ts +12 -2
  304. package/dist/src/core/patch-export-metadata.js +13 -4
  305. package/dist/src/core/patch-export-update.d.ts +13 -1
  306. package/dist/src/core/patch-export-update.js +25 -8
  307. package/dist/src/core/patch-export.d.ts +15 -8
  308. package/dist/src/core/patch-export.js +10 -11
  309. package/dist/src/core/patch-files.d.ts +5 -6
  310. package/dist/src/core/patch-files.js +5 -6
  311. package/dist/src/core/patch-identifier-suggest.d.ts +7 -12
  312. package/dist/src/core/patch-identifier-suggest.js +14 -19
  313. package/dist/src/core/patch-lint-binary.d.ts +51 -0
  314. package/dist/src/core/patch-lint-binary.js +39 -0
  315. package/dist/src/core/{lint-cache.d.ts → patch-lint-cache.d.ts} +5 -5
  316. package/dist/src/core/{lint-cache.js → patch-lint-cache.js} +21 -23
  317. package/dist/src/core/patch-lint-checkjs.d.ts +16 -16
  318. package/dist/src/core/patch-lint-checkjs.js +16 -16
  319. package/dist/src/core/patch-lint-chrome-jsdoc.d.ts +6 -9
  320. package/dist/src/core/patch-lint-chrome-jsdoc.js +10 -14
  321. package/dist/src/core/patch-lint-creators.d.ts +8 -8
  322. package/dist/src/core/patch-lint-creators.js +8 -8
  323. package/dist/src/core/patch-lint-cross.d.ts +17 -20
  324. package/dist/src/core/patch-lint-cross.js +16 -16
  325. package/dist/src/core/patch-lint-css.d.ts +3 -5
  326. package/dist/src/core/patch-lint-css.js +17 -22
  327. package/dist/src/core/patch-lint-diff-tag.d.ts +14 -16
  328. package/dist/src/core/patch-lint-diff-tag.js +14 -16
  329. package/dist/src/core/patch-lint-jsdoc.d.ts +7 -8
  330. package/dist/src/core/patch-lint-jsdoc.js +26 -19
  331. package/dist/src/core/patch-lint-mozbuild.js +20 -20
  332. package/dist/src/core/patch-lint-observer.d.ts +7 -7
  333. package/dist/src/core/patch-lint-observer.js +7 -7
  334. package/dist/src/core/patch-lint.d.ts +38 -29
  335. package/dist/src/core/patch-lint.js +89 -121
  336. package/dist/src/core/patch-lock.d.ts +1 -1
  337. package/dist/src/core/patch-lock.js +45 -9
  338. package/dist/src/core/patch-manifest-consistency.d.ts +2 -1
  339. package/dist/src/core/patch-manifest-consistency.js +25 -27
  340. package/dist/src/core/patch-manifest-io.js +14 -18
  341. package/dist/src/core/patch-manifest-resolve.d.ts +9 -12
  342. package/dist/src/core/patch-manifest-resolve.js +9 -12
  343. package/dist/src/core/patch-manifest-validate.d.ts +6 -1
  344. package/dist/src/core/patch-manifest-validate.js +25 -13
  345. package/dist/src/core/patch-parse.d.ts +24 -13
  346. package/dist/src/core/patch-parse.js +19 -14
  347. package/dist/src/core/patch-policy.d.ts +2 -2
  348. package/dist/src/core/patch-policy.js +2 -2
  349. package/dist/src/core/patch-registration-refs.d.ts +7 -8
  350. package/dist/src/core/patch-registration-refs.js +9 -9
  351. package/dist/src/core/process-cpu-time.d.ts +12 -0
  352. package/dist/src/core/process-cpu-time.js +52 -0
  353. package/dist/src/core/rebase-session.d.ts +38 -26
  354. package/dist/src/core/rebase-session.js +55 -28
  355. package/dist/src/core/register-browser-content.js +9 -74
  356. package/dist/src/core/{register-test-manifest.js → register-browser-test.js} +7 -42
  357. package/dist/src/core/register-module.js +10 -43
  358. package/dist/src/core/register-scaffold.d.ts +8 -8
  359. package/dist/src/core/register-scaffold.js +10 -10
  360. package/dist/src/core/register-shared-css.d.ts +9 -12
  361. package/dist/src/core/register-shared-css.js +17 -87
  362. package/dist/src/core/register-xpcshell-test.d.ts +6 -7
  363. package/dist/src/core/register-xpcshell-test.js +7 -8
  364. package/dist/src/core/shared-ftl.js +12 -4
  365. package/dist/src/core/state-file.d.ts +45 -0
  366. package/dist/src/core/state-file.js +34 -0
  367. package/dist/src/core/status-binary.d.ts +18 -11
  368. package/dist/src/core/status-binary.js +19 -12
  369. package/dist/src/core/status-classify.d.ts +30 -36
  370. package/dist/src/core/status-classify.js +21 -26
  371. package/dist/src/core/test-changed-prefs.d.ts +30 -0
  372. package/dist/src/core/test-changed-prefs.js +78 -0
  373. package/dist/src/core/test-harness-crash.d.ts +25 -63
  374. package/dist/src/core/test-harness-crash.js +121 -142
  375. package/dist/src/core/test-harness-signature.d.ts +18 -0
  376. package/dist/src/core/test-harness-signature.js +13 -0
  377. package/dist/src/core/test-path-scope.d.ts +12 -15
  378. package/dist/src/core/test-path-scope.js +15 -18
  379. package/dist/src/core/test-stale-check.d.ts +17 -17
  380. package/dist/src/core/test-stale-check.js +50 -43
  381. package/dist/src/core/test-stall-triage.d.ts +51 -0
  382. package/dist/src/core/test-stall-triage.js +126 -0
  383. package/dist/src/core/token-category.js +5 -7
  384. package/dist/src/core/token-coverage.js +9 -9
  385. package/dist/src/core/token-dark-mode.d.ts +9 -11
  386. package/dist/src/core/token-dark-mode.js +9 -11
  387. package/dist/src/core/token-docs.d.ts +2 -0
  388. package/dist/src/core/token-docs.js +2 -0
  389. package/dist/src/core/token-manager.d.ts +10 -2
  390. package/dist/src/core/token-manager.js +17 -8
  391. package/dist/src/core/token-scaffold.d.ts +7 -7
  392. package/dist/src/core/token-scaffold.js +7 -7
  393. package/dist/src/core/token-variant.d.ts +4 -4
  394. package/dist/src/core/token-variant.js +4 -4
  395. package/dist/src/core/toolchain-preflight.d.ts +20 -21
  396. package/dist/src/core/toolchain-preflight.js +28 -31
  397. package/dist/src/core/tree-guard.js +12 -2
  398. package/dist/src/core/tree-store.d.ts +41 -27
  399. package/dist/src/core/tree-store.js +63 -42
  400. package/dist/src/core/typecheck-shim.d.ts +23 -24
  401. package/dist/src/core/typecheck-shim.js +23 -24
  402. package/dist/src/core/typecheck.js +8 -8
  403. package/dist/src/core/wire-destroy.d.ts +3 -3
  404. package/dist/src/core/wire-destroy.js +7 -15
  405. package/dist/src/core/wire-dom-fragment.d.ts +9 -17
  406. package/dist/src/core/wire-dom-fragment.js +11 -44
  407. package/dist/src/core/wire-init.d.ts +2 -3
  408. package/dist/src/core/wire-init.js +8 -19
  409. package/dist/src/core/wire-subscript.d.ts +2 -3
  410. package/dist/src/core/wire-subscript.js +4 -13
  411. package/dist/src/core/wire-utils.d.ts +7 -8
  412. package/dist/src/core/wire-utils.js +7 -8
  413. package/dist/src/core/xpcshell-appdir.d.ts +38 -45
  414. package/dist/src/core/xpcshell-appdir.js +38 -45
  415. package/dist/src/errors/base.d.ts +37 -16
  416. package/dist/src/errors/base.js +37 -16
  417. package/dist/src/errors/build.d.ts +13 -1
  418. package/dist/src/errors/build.js +14 -2
  419. package/dist/src/errors/codes.d.ts +16 -0
  420. package/dist/src/errors/codes.js +16 -0
  421. package/dist/src/errors/furnace.d.ts +4 -4
  422. package/dist/src/errors/git.d.ts +6 -10
  423. package/dist/src/errors/git.js +6 -10
  424. package/dist/src/errors/patch.d.ts +7 -7
  425. package/dist/src/errors/patch.js +7 -7
  426. package/dist/src/errors/rebase.d.ts +4 -4
  427. package/dist/src/errors/rebase.js +4 -4
  428. package/dist/src/index.d.ts +7 -1
  429. package/dist/src/index.js +5 -0
  430. package/dist/src/types/commands/index.d.ts +2 -2
  431. package/dist/src/types/commands/options.d.ts +88 -70
  432. package/dist/src/types/commands/patches.d.ts +24 -34
  433. package/dist/src/types/commands/project.d.ts +5 -34
  434. package/dist/src/types/config.d.ts +25 -23
  435. package/dist/src/types/config.js +6 -1
  436. package/dist/src/types/furnace.d.ts +37 -13
  437. package/dist/src/types/furnace.js +19 -1
  438. package/dist/src/types/index.d.ts +3 -3
  439. package/dist/src/utils/build-info.d.ts +7 -8
  440. package/dist/src/utils/build-info.js +12 -11
  441. package/dist/src/utils/errors.d.ts +6 -8
  442. package/dist/src/utils/errors.js +6 -8
  443. package/dist/src/utils/logger.d.ts +27 -10
  444. package/dist/src/utils/logger.js +28 -16
  445. package/dist/src/utils/machine-output.d.ts +12 -0
  446. package/dist/src/utils/machine-output.js +33 -0
  447. package/dist/src/utils/options.d.ts +31 -14
  448. package/dist/src/utils/options.js +86 -30
  449. package/dist/src/utils/paths.d.ts +10 -8
  450. package/dist/src/utils/paths.js +10 -8
  451. package/dist/src/utils/platform.d.ts +0 -25
  452. package/dist/src/utils/platform.js +1 -42
  453. package/dist/src/utils/process-group.d.ts +9 -4
  454. package/dist/src/utils/process-group.js +19 -5
  455. package/dist/src/utils/process.d.ts +42 -7
  456. package/dist/src/utils/process.js +44 -17
  457. package/dist/src/utils/ps-duration.d.ts +31 -0
  458. package/dist/src/utils/ps-duration.js +70 -0
  459. package/dist/src/utils/regex.d.ts +9 -10
  460. package/dist/src/utils/regex.js +9 -10
  461. package/dist/src/utils/validation.d.ts +58 -28
  462. package/dist/src/utils/validation.js +60 -33
  463. package/package.json +2 -2
  464. package/dist/src/commands/doctor/post-rebase-audit.d.ts +0 -2
  465. package/dist/src/commands/doctor-furnace-manifest-sync.d.ts +0 -18
  466. package/dist/src/core/manifest-helpers.d.ts +0 -38
  467. package/dist/src/core/manifest-helpers.js +0 -120
  468. /package/dist/src/core/{lint-projection.d.ts → patch-lint-projection.d.ts} +0 -0
  469. /package/dist/src/core/{lint-projection.js → patch-lint-projection.js} +0 -0
  470. /package/dist/src/core/{register-test-manifest.d.ts → register-browser-test.d.ts} +0 -0
@@ -0,0 +1,42 @@
1
+ import { type MarionettePortHolder } from './marionette-port.js';
2
+ /** Default port the mochitest harness binds its httpd to. */
3
+ export declare const DEFAULT_MOCHITEST_SERVER_PORT = 8888;
4
+ /**
5
+ * True when the holder is recognizably the mochitest harness's own
6
+ * `server.js`, launched from an objdir.
7
+ *
8
+ * Both halves are required. `server.js` alone is one of the most common
9
+ * filenames in existence — a developer's unrelated Node service must never
10
+ * be mistaken for harness debris and offered up for termination — so the
11
+ * command line must ALSO show the xpcshell/objdir provenance that only the
12
+ * harness's httpd has.
13
+ */
14
+ export declare function isMochitestServerHolder(holder: MarionettePortHolder): boolean;
15
+ /**
16
+ * Refuses a mochitest dispatch when the harness's server port is held, and
17
+ * — only for a recognized stale harness httpd, and only when the operator
18
+ * opted in — terminates it first.
19
+ *
20
+ * An UNRECOGNIZED listener is a refusal too, never a kill. Refusing is the
21
+ * kinder outcome: mochitest cannot bind the port either way, so the choice
22
+ * is between a one-line refusal now and a 370 s stall whose signature says
23
+ * nothing about ports. But FireForge has no business killing a process it
24
+ * cannot attribute to the harness.
25
+ *
26
+ * Best-effort by construction: {@link probeMarionettePort} reports an
27
+ * unprobeable port as free, so a host without `lsof` runs exactly as before.
28
+ *
29
+ * @param port - Port to probe (default {@link DEFAULT_MOCHITEST_SERVER_PORT})
30
+ * @param options - `killStaleServer` opts into terminating a recognized holder
31
+ */
32
+ export declare function ensureMochitestServerPortAvailable(port?: number, options?: {
33
+ killStaleServer?: boolean;
34
+ }): Promise<void>;
35
+ /**
36
+ * Builds the operator-facing refusal. Exported for direct unit testing.
37
+ *
38
+ * @param port - The probed port
39
+ * @param holder - The listener found on it
40
+ * @param recognized - Whether it is the harness's own `server.js`
41
+ */
42
+ export declare function describeMochitestServerRefusal(port: number, holder: MarionettePortHolder, recognized: boolean): string;
@@ -0,0 +1,119 @@
1
+ // SPDX-License-Identifier: EUPL-1.2
2
+ /**
3
+ * Mochitest HTTP server port preflight.
4
+ *
5
+ * The mochitest harness serves its test manifest from an xpcshell-hosted
6
+ * httpd (`server.js`) on `127.0.0.1:8888`. When a previous run is killed
7
+ * between browser launch and teardown, that server can survive — sometimes
8
+ * wedged at 100% CPU and unkillable by the harness's own SIGKILL — and it
9
+ * keeps the port.
10
+ *
11
+ * The next run then does something much worse than failing: its fresh
12
+ * browser connects to the ZOMBIE server, which cannot serve the new
13
+ * manifest, so the run stalls between browser startup and `TEST_START` and
14
+ * dies on the 370 s no-output timeout with `Ran 0 checks`. Nothing in that
15
+ * signature names the port, so the failure survives fresh builds and reads
16
+ * as a defect in the change under test — one downstream report spent a
17
+ * multi-hour bisect on it before `lsof -nP -iTCP:8888` gave the answer in
18
+ * one line.
19
+ *
20
+ * `--kill-stale-marionette` never covered this: it clears the browser and
21
+ * the Marionette control port, and the httpd is neither. This preflight is
22
+ * the missing half, and it deliberately reuses {@link probeMarionettePort},
23
+ * which is port-generic, rather than growing a second probe.
24
+ */
25
+ import { GeneralError } from '../errors/base.js';
26
+ import { exec } from '../utils/process.js';
27
+ import { probeMarionettePort } from './marionette-port.js';
28
+ /** Default port the mochitest harness binds its httpd to. */
29
+ export const DEFAULT_MOCHITEST_SERVER_PORT = 8888;
30
+ /**
31
+ * True when the holder is recognizably the mochitest harness's own
32
+ * `server.js`, launched from an objdir.
33
+ *
34
+ * Both halves are required. `server.js` alone is one of the most common
35
+ * filenames in existence — a developer's unrelated Node service must never
36
+ * be mistaken for harness debris and offered up for termination — so the
37
+ * command line must ALSO show the xpcshell/objdir provenance that only the
38
+ * harness's httpd has.
39
+ */
40
+ export function isMochitestServerHolder(holder) {
41
+ const line = holder.commandLine;
42
+ if (!/\bserver\.js\b/.test(line))
43
+ return false;
44
+ return /\bxpcshell\b/.test(line) || /\/obj-[^/\s]*\//.test(line) || /\b_tests\b/.test(line);
45
+ }
46
+ /**
47
+ * Refuses a mochitest dispatch when the harness's server port is held, and
48
+ * — only for a recognized stale harness httpd, and only when the operator
49
+ * opted in — terminates it first.
50
+ *
51
+ * An UNRECOGNIZED listener is a refusal too, never a kill. Refusing is the
52
+ * kinder outcome: mochitest cannot bind the port either way, so the choice
53
+ * is between a one-line refusal now and a 370 s stall whose signature says
54
+ * nothing about ports. But FireForge has no business killing a process it
55
+ * cannot attribute to the harness.
56
+ *
57
+ * Best-effort by construction: {@link probeMarionettePort} reports an
58
+ * unprobeable port as free, so a host without `lsof` runs exactly as before.
59
+ *
60
+ * @param port - Port to probe (default {@link DEFAULT_MOCHITEST_SERVER_PORT})
61
+ * @param options - `killStaleServer` opts into terminating a recognized holder
62
+ */
63
+ export async function ensureMochitestServerPortAvailable(port = DEFAULT_MOCHITEST_SERVER_PORT, options = {}) {
64
+ const probe = await probeMarionettePort(port);
65
+ if (!probe.inUse || !probe.holder)
66
+ return;
67
+ const holder = probe.holder;
68
+ const recognized = isMochitestServerHolder(holder);
69
+ if (recognized && options.killStaleServer === true) {
70
+ try {
71
+ if (process.platform === 'win32') {
72
+ await exec('powershell.exe', [
73
+ '-NoProfile',
74
+ '-NonInteractive',
75
+ '-Command',
76
+ `Stop-Process -Id ${holder.pid} -Force`,
77
+ ]);
78
+ }
79
+ else {
80
+ process.kill(holder.pid, 'SIGTERM');
81
+ }
82
+ return;
83
+ }
84
+ catch {
85
+ // Fall through to the refusal: a wedged httpd is exactly the case
86
+ // that ignores SIGTERM, and reporting it is more useful than
87
+ // pretending the port is now free.
88
+ }
89
+ }
90
+ throw new GeneralError(describeMochitestServerRefusal(port, holder, recognized));
91
+ }
92
+ /**
93
+ * Builds the operator-facing refusal. Exported for direct unit testing.
94
+ *
95
+ * @param port - The probed port
96
+ * @param holder - The listener found on it
97
+ * @param recognized - Whether it is the harness's own `server.js`
98
+ */
99
+ export function describeMochitestServerRefusal(port, holder, recognized) {
100
+ const killHint = process.platform === 'win32'
101
+ ? `Stop-Process -Id ${holder.pid} -Force`
102
+ : `kill -9 ${holder.pid}`;
103
+ const evidence = `The mochitest server port ${String(port)} is already held by ${holder.command} ` +
104
+ `(PID ${String(holder.pid)}).\n` +
105
+ ` command: ${holder.commandLine}\n` +
106
+ " A browser launched now would connect to THAT server, which cannot serve this run's " +
107
+ 'manifest — the run would stall before TEST_START and die on the no-output timeout with ' +
108
+ '"Ran 0 checks".\n';
109
+ if (recognized) {
110
+ return (evidence +
111
+ " This is the mochitest harness's own server.js, so it is debris from an interrupted run. " +
112
+ 'Retry with "--kill-stale-marionette" to have FireForge stop it, or stop it yourself with ' +
113
+ `"${killHint}" (a wedged httpd can ignore SIGTERM).`);
114
+ }
115
+ return (evidence +
116
+ " This is NOT the mochitest harness's server.js, so FireForge will not offer to kill it. " +
117
+ `Stop the holder yourself with "${killHint}" if it is yours, or free the port, then retry. ` +
118
+ `Diagnose with "lsof -nP -iTCP:${String(port)}".`);
119
+ }
@@ -2,24 +2,22 @@
2
2
  * Engine-aware resolution preflight for queue-owned system modules.
3
3
  *
4
4
  * An `.sys.mjs` that a packaged module imports but whose `EXTRA_JS_MODULES`
5
- * registration never landed kills every xpcshell suite
6
- * with `xpcshell return code: -11` and ZERO output — no import error, no
7
- * stack, nothing. The 0.41.0 `unregistered-system-module` check catches
8
- * this class, but only in one shape: a module NEWLY CREATED by a patch in
9
- * the projected queue. The class recurred through the other shape — three
10
- * modules imported from an ALREADY-EXISTING module before their moz.build
11
- * lines landed — and cost a full rebuild cycle before anyone recognised it.
5
+ * registration never landed kills every xpcshell suite with `xpcshell return
6
+ * code: -11` and ZERO output — no import error, no stack, nothing. The
7
+ * queue-level `unregistered-system-module` check catches one shape of this:
8
+ * a module NEWLY CREATED by a patch in the projected queue. The other shape
9
+ * — modules imported from an ALREADY-EXISTING module before their moz.build
10
+ * lines land — slips past it entirely.
12
11
  *
13
12
  * This preflight closes that gap by asking the question against the ENGINE
14
13
  * rather than against a projected diff: for every `resource:///modules/…`
15
14
  * specifier imported by any queue-owned module, does the module it names
16
15
  * exist, and is it registered in a moz.build that covers it?
17
16
  *
18
- * Scope is the queue-owned file set on purpose. A specifier that resolves
19
- * to no owned file is an UPSTREAM Firefox module, which FireForge does not
17
+ * Scope is the queue-owned file set on purpose. A specifier that resolves to
18
+ * no owned file is an UPSTREAM Firefox module, which FireForge does not
20
19
  * police and cannot cheaply enumerate; policing only what the fork owns is
21
- * both the actionable set and the one that produced every recorded
22
- * incident.
20
+ * both the actionable set and the one that produces real incidents.
23
21
  */
24
22
  /** Why a queue-owned module import does not resolve to a packaged module. */
25
23
  export type UnresolvedModuleReason = 'missing-file' | 'unregistered';
@@ -3,24 +3,22 @@
3
3
  * Engine-aware resolution preflight for queue-owned system modules.
4
4
  *
5
5
  * An `.sys.mjs` that a packaged module imports but whose `EXTRA_JS_MODULES`
6
- * registration never landed kills every xpcshell suite
7
- * with `xpcshell return code: -11` and ZERO output — no import error, no
8
- * stack, nothing. The 0.41.0 `unregistered-system-module` check catches
9
- * this class, but only in one shape: a module NEWLY CREATED by a patch in
10
- * the projected queue. The class recurred through the other shape — three
11
- * modules imported from an ALREADY-EXISTING module before their moz.build
12
- * lines landed — and cost a full rebuild cycle before anyone recognised it.
6
+ * registration never landed kills every xpcshell suite with `xpcshell return
7
+ * code: -11` and ZERO output — no import error, no stack, nothing. The
8
+ * queue-level `unregistered-system-module` check catches one shape of this:
9
+ * a module NEWLY CREATED by a patch in the projected queue. The other shape
10
+ * — modules imported from an ALREADY-EXISTING module before their moz.build
11
+ * lines land — slips past it entirely.
13
12
  *
14
13
  * This preflight closes that gap by asking the question against the ENGINE
15
14
  * rather than against a projected diff: for every `resource:///modules/…`
16
15
  * specifier imported by any queue-owned module, does the module it names
17
16
  * exist, and is it registered in a moz.build that covers it?
18
17
  *
19
- * Scope is the queue-owned file set on purpose. A specifier that resolves
20
- * to no owned file is an UPSTREAM Firefox module, which FireForge does not
18
+ * Scope is the queue-owned file set on purpose. A specifier that resolves to
19
+ * no owned file is an UPSTREAM Firefox module, which FireForge does not
21
20
  * police and cannot cheaply enumerate; policing only what the fork owns is
22
- * both the actionable set and the one that produced every recorded
23
- * incident.
21
+ * both the actionable set and the one that produces real incidents.
24
22
  */
25
23
  import { dirname, join } from 'node:path';
26
24
  import { toError } from '../utils/errors.js';
@@ -0,0 +1,79 @@
1
+ import type { MozBuildToken } from './moz-manifest-tokenizers.js';
2
+ /**
3
+ * Ordering comparator matching mozbuild's `StrictOrderingOnAppendList`
4
+ * (`mozbuild.util.UnsortedError`): entries are compared **case-insensitively**,
5
+ * so `HominisAppearanceController` (`appe`) sorts before
6
+ * `HominisAppMenuIntegration` (`appm`) even though a raw byte comparison
7
+ * places the uppercase `M` (0x4D) before the lowercase `e` (0x65).
8
+ *
9
+ * A naive `a > b` insertion landed the new entry in byte order, which
10
+ * `mach configure` then rejected with `UnsortedError`, aborting the build.
11
+ * Ties on the lower-cased key fall back to byte order so the comparison is
12
+ * total and stable.
13
+ */
14
+ export declare function mozbuildSortCompare(a: string, b: string): number;
15
+ /**
16
+ * Find alphabetical position within tokenized moz.build list items.
17
+ */
18
+ export declare function findAlphabeticalMozBuildPosition(tokens: MozBuildToken[], newKey: string): {
19
+ insertIndex: number;
20
+ previousEntry: string | undefined;
21
+ };
22
+ /**
23
+ * Inserts one entry into a tokenized jar.mn / jar.inc.mn, honouring an
24
+ * explicit `--after` anchor and falling back to alphabetical placement when
25
+ * the anchor is not found.
26
+ *
27
+ * Shared by the two jar.mn registrars (browser content, shared CSS), which
28
+ * differ only in the sort pattern, the sort key and the "could not find the
29
+ * section" message, so the anchor-fallback semantics — silently falling back
30
+ * rather than refusing, and reporting `afterFallback` so the caller can say
31
+ * so — are defined once.
32
+ *
33
+ * Deliberately jar.mn-specific: the moz.build list form has no `after` anchor
34
+ * and no section concept, so a single generic helper over both families
35
+ * would carry parameters that are meaningless on one side. See
36
+ * {@link insertMozBuildListEntry} for its twin.
37
+ *
38
+ * @param content - Full manifest text
39
+ * @param entry - The already-formatted line to insert
40
+ * @param options - Sort pattern/key, refusal message, and optional anchor
41
+ * @returns The rewritten text plus where it landed and how
42
+ */
43
+ export declare function insertJarMnEntry(content: string, entry: string, options: {
44
+ sortPattern: RegExp;
45
+ sortKey: string;
46
+ missingSectionMessage: string;
47
+ after?: string | undefined;
48
+ }): {
49
+ result: string;
50
+ insertIndex: number;
51
+ previousEntry: string | undefined;
52
+ afterFallback: boolean;
53
+ };
54
+ /**
55
+ * Inserts one entry alphabetically into a moz.build Python list block.
56
+ *
57
+ * Shared by the two moz.build registrars (module list, browser test
58
+ * manifests), which differ only in the list pattern, the sort key and the
59
+ * refusal message.
60
+ *
61
+ * `tokenizeMozBuildList` **mutates `lines` in place** when it normalizes the
62
+ * single-line `FOO += []` form into the multi-line shape, and that rewrite is
63
+ * what makes the caller's `splice` land inside the list body. The splice
64
+ * below therefore has to run against the same array the tokenizer was
65
+ * handed; a wrapper that tokenized a copy would silently break it.
66
+ *
67
+ * @param content - Full moz.build text
68
+ * @param entry - The already-formatted line to insert
69
+ * @param options - List pattern, sort key, and refusal message
70
+ * @returns The rewritten text and the entry it landed after
71
+ */
72
+ export declare function insertMozBuildListEntry(content: string, entry: string, options: {
73
+ listPattern: RegExp;
74
+ sortKey: string;
75
+ missingListMessage: string;
76
+ }): {
77
+ result: string;
78
+ previousEntry: string | undefined;
79
+ };
@@ -0,0 +1,163 @@
1
+ // SPDX-License-Identifier: EUPL-1.2
2
+ import { GeneralError } from '../errors/base.js';
3
+ import { escapeRegex } from '../utils/regex.js';
4
+ import { tokenizeJarMn, tokenizeMozBuildList } from './moz-manifest-tokenizers.js';
5
+ /**
6
+ * Ordering comparator matching mozbuild's `StrictOrderingOnAppendList`
7
+ * (`mozbuild.util.UnsortedError`): entries are compared **case-insensitively**,
8
+ * so `HominisAppearanceController` (`appe`) sorts before
9
+ * `HominisAppMenuIntegration` (`appm`) even though a raw byte comparison
10
+ * places the uppercase `M` (0x4D) before the lowercase `e` (0x65).
11
+ *
12
+ * A naive `a > b` insertion landed the new entry in byte order, which
13
+ * `mach configure` then rejected with `UnsortedError`, aborting the build.
14
+ * Ties on the lower-cased key fall back to byte order so the comparison is
15
+ * total and stable.
16
+ */
17
+ export function mozbuildSortCompare(a, b) {
18
+ const la = a.toLowerCase();
19
+ const lb = b.toLowerCase();
20
+ if (la < lb)
21
+ return -1;
22
+ if (la > lb)
23
+ return 1;
24
+ if (a < b)
25
+ return -1;
26
+ if (a > b)
27
+ return 1;
28
+ return 0;
29
+ }
30
+ /**
31
+ * Find alphabetical position within a tokenized jar.mn section. Private:
32
+ * {@link insertJarMnEntry} is the only caller and the only entry point
33
+ * the jar.mn registrars should use.
34
+ */
35
+ function findAlphabeticalTokenPosition(tokens, sectionTargetPattern, newKey) {
36
+ // Find entry tokens in the section matching the pattern
37
+ const sectionEntries = tokens.filter((t) => t.type === 'entry' && t.parsed && sectionTargetPattern.test(t.parsed.target));
38
+ let insertLineIndex;
39
+ let previousEntry;
40
+ if (sectionEntries.length === 0) {
41
+ // Empty section: find the section header and insert after it
42
+ const headerToken = tokens.find((t) => t.type === 'header' || (t.type === 'directive' && sectionTargetPattern.test(t.raw)));
43
+ if (headerToken) {
44
+ return { insertIndex: headerToken.lineIndex + 1, previousEntry: undefined };
45
+ }
46
+ return { insertIndex: -1, previousEntry: undefined };
47
+ }
48
+ // Default: after the last section entry
49
+ insertLineIndex = (sectionEntries[sectionEntries.length - 1]?.lineIndex ?? 0) + 1;
50
+ for (const entry of sectionEntries) {
51
+ if (!entry.parsed)
52
+ continue;
53
+ const match = sectionTargetPattern.exec(entry.parsed.target);
54
+ const key = match?.[1] ?? entry.parsed.target;
55
+ if (mozbuildSortCompare(key, newKey) > 0) {
56
+ insertLineIndex = entry.lineIndex;
57
+ break;
58
+ }
59
+ insertLineIndex = entry.lineIndex + 1;
60
+ previousEntry = entry.raw.trim();
61
+ }
62
+ return { insertIndex: insertLineIndex, previousEntry };
63
+ }
64
+ /**
65
+ * Find alphabetical position within tokenized moz.build list items.
66
+ */
67
+ export function findAlphabeticalMozBuildPosition(tokens, newKey) {
68
+ const items = tokens.filter((t) => t.type === 'list-item');
69
+ if (items.length === 0) {
70
+ // Insert after list-open
71
+ const openToken = tokens.find((t) => t.type === 'list-open');
72
+ return { insertIndex: (openToken?.lineIndex ?? 0) + 1, previousEntry: undefined };
73
+ }
74
+ let insertLineIndex = (items[items.length - 1]?.lineIndex ?? 0) + 1;
75
+ let previousEntry;
76
+ for (const item of items) {
77
+ const key = item.parsed?.value ?? '';
78
+ if (mozbuildSortCompare(key, newKey) > 0) {
79
+ insertLineIndex = item.lineIndex;
80
+ break;
81
+ }
82
+ insertLineIndex = item.lineIndex + 1;
83
+ previousEntry = item.raw.trim();
84
+ }
85
+ return { insertIndex: insertLineIndex, previousEntry };
86
+ }
87
+ /**
88
+ * Inserts one entry into a tokenized jar.mn / jar.inc.mn, honouring an
89
+ * explicit `--after` anchor and falling back to alphabetical placement when
90
+ * the anchor is not found.
91
+ *
92
+ * Shared by the two jar.mn registrars (browser content, shared CSS), which
93
+ * differ only in the sort pattern, the sort key and the "could not find the
94
+ * section" message, so the anchor-fallback semantics — silently falling back
95
+ * rather than refusing, and reporting `afterFallback` so the caller can say
96
+ * so — are defined once.
97
+ *
98
+ * Deliberately jar.mn-specific: the moz.build list form has no `after` anchor
99
+ * and no section concept, so a single generic helper over both families
100
+ * would carry parameters that are meaningless on one side. See
101
+ * {@link insertMozBuildListEntry} for its twin.
102
+ *
103
+ * @param content - Full manifest text
104
+ * @param entry - The already-formatted line to insert
105
+ * @param options - Sort pattern/key, refusal message, and optional anchor
106
+ * @returns The rewritten text plus where it landed and how
107
+ */
108
+ export function insertJarMnEntry(content, entry, options) {
109
+ const lines = content.split('\n');
110
+ const tokens = tokenizeJarMn(lines);
111
+ let afterFallback = false;
112
+ let insertIndex;
113
+ let previousEntry;
114
+ const alphabetical = () => findAlphabeticalTokenPosition(tokens, options.sortPattern, options.sortKey);
115
+ if (options.after) {
116
+ const afterPattern = new RegExp(`(?:^|/)${escapeRegex(options.after)}(?:\\s|\\)|$)`);
117
+ const afterToken = tokens.find((t) => afterPattern.test(t.raw));
118
+ if (afterToken) {
119
+ insertIndex = afterToken.lineIndex + 1;
120
+ previousEntry = afterToken.raw.trim();
121
+ }
122
+ else {
123
+ afterFallback = true;
124
+ ({ insertIndex, previousEntry } = alphabetical());
125
+ }
126
+ }
127
+ else {
128
+ ({ insertIndex, previousEntry } = alphabetical());
129
+ }
130
+ if (insertIndex === -1) {
131
+ throw new GeneralError(options.missingSectionMessage);
132
+ }
133
+ lines.splice(insertIndex, 0, entry);
134
+ return { result: lines.join('\n'), insertIndex, previousEntry, afterFallback };
135
+ }
136
+ /**
137
+ * Inserts one entry alphabetically into a moz.build Python list block.
138
+ *
139
+ * Shared by the two moz.build registrars (module list, browser test
140
+ * manifests), which differ only in the list pattern, the sort key and the
141
+ * refusal message.
142
+ *
143
+ * `tokenizeMozBuildList` **mutates `lines` in place** when it normalizes the
144
+ * single-line `FOO += []` form into the multi-line shape, and that rewrite is
145
+ * what makes the caller's `splice` land inside the list body. The splice
146
+ * below therefore has to run against the same array the tokenizer was
147
+ * handed; a wrapper that tokenized a copy would silently break it.
148
+ *
149
+ * @param content - Full moz.build text
150
+ * @param entry - The already-formatted line to insert
151
+ * @param options - List pattern, sort key, and refusal message
152
+ * @returns The rewritten text and the entry it landed after
153
+ */
154
+ export function insertMozBuildListEntry(content, entry, options) {
155
+ const lines = content.split('\n');
156
+ const listResult = tokenizeMozBuildList(lines, options.listPattern);
157
+ if (!listResult) {
158
+ throw new GeneralError(options.missingListMessage);
159
+ }
160
+ const { insertIndex, previousEntry } = findAlphabeticalMozBuildPosition(listResult.tokens, options.sortKey);
161
+ lines.splice(insertIndex, 0, entry);
162
+ return { result: lines.join('\n'), previousEntry };
163
+ }
@@ -7,9 +7,9 @@
7
7
  import type { RegisterResult } from './register-result.js';
8
8
  export type { RegisterResult } from './register-result.js';
9
9
  export { registerBrowserContent } from './register-browser-content.js';
10
+ export { deregisterTestManifest, registerTestManifest } from './register-browser-test.js';
10
11
  export { registerFireForgeModule } from './register-module.js';
11
12
  export { registerSharedCSS } from './register-shared-css.js';
12
- export { deregisterTestManifest, registerTestManifest } from './register-test-manifest.js';
13
13
  /**
14
14
  * Registers a widget file (mjs or css) in toolkit/content/jar.mn.
15
15
  *
@@ -8,12 +8,12 @@
8
8
  import { join } from 'node:path';
9
9
  import { GeneralError } from '../errors/base.js';
10
10
  import { pathExists, readText, writeText } from '../utils/fs.js';
11
- import { findAlphabeticalPosition } from './manifest-helpers.js';
11
+ import { insertJarMnEntry } from './moz-manifest-helpers.js';
12
12
  // Re-export from split modules so existing import sites continue working
13
13
  export { registerBrowserContent } from './register-browser-content.js';
14
+ export { deregisterTestManifest, registerTestManifest } from './register-browser-test.js';
14
15
  export { registerFireForgeModule } from './register-module.js';
15
16
  export { registerSharedCSS } from './register-shared-css.js';
16
- export { deregisterTestManifest, registerTestManifest } from './register-test-manifest.js';
17
17
  // ---------------------------------------------------------------------------
18
18
  // toolkit/content/jar.mn — widget registration
19
19
  // ---------------------------------------------------------------------------
@@ -30,37 +30,22 @@ export async function registerToolkitWidget(engineDir, tagName, fileName, dryRun
30
30
  throw new GeneralError(`Manifest not found: ${manifest}`);
31
31
  }
32
32
  const entry = ` content/global/elements/${fileName} (widgets/${tagName}/${fileName})`.replace(/\\/g, '/');
33
- let content = await readText(manifestPath);
33
+ const content = await readText(manifestPath);
34
34
  // Idempotency check
35
35
  if (content.includes(`content/global/elements/${fileName}`)) {
36
36
  return { manifest, entry, skipped: true };
37
37
  }
38
- const lines = content.split('\n');
39
- // Find insertion point among existing content/global/elements/ lines
40
- const extractKey = (line) => {
41
- const match = /^\s+content\/global\/elements\/([^\s]+)/.exec(line);
42
- return match?.[1];
43
- };
44
- let sectionStart = -1;
45
- let sectionEnd = lines.length;
46
- for (let i = 0; i < lines.length; i++) {
47
- const line = lines[i];
48
- if (line === undefined)
49
- continue;
50
- if (/^\s+content\/global\/elements\//.test(line)) {
51
- if (sectionStart === -1)
52
- sectionStart = i;
53
- sectionEnd = i + 1;
54
- }
55
- }
56
- if (sectionStart === -1) {
57
- throw new GeneralError('Could not find content/global/elements/ section in toolkit/content/jar.mn');
58
- }
59
- const { insertIndex, previousEntry } = findAlphabeticalPosition(lines, sectionStart, sectionEnd, fileName, extractKey);
60
- lines.splice(insertIndex, 0, entry);
61
- content = lines.join('\n');
38
+ // Tokenized like the other three jar.mn registrars. The hand-rolled
39
+ // line scan this replaced re-derived the section bounds and the sort
40
+ // key with its own regexes, so it was the one jar.mn target that did
41
+ // not inherit fixes made to the shared path.
42
+ const { result, previousEntry } = insertJarMnEntry(content, entry, {
43
+ sortPattern: /content\/global\/elements\/([^\s]+)/,
44
+ sortKey: fileName,
45
+ missingSectionMessage: 'Could not find content/global/elements/ section in toolkit/content/jar.mn',
46
+ });
62
47
  if (!dryRun) {
63
- await writeText(manifestPath, content);
48
+ await writeText(manifestPath, result);
64
49
  }
65
50
  return { manifest, entry, previousEntry, skipped: false };
66
51
  }
@@ -1,4 +1,4 @@
1
- import type { RegisterResult } from './manifest-register.js';
1
+ import type { RegisterResult } from './moz-manifest-register.js';
2
2
  /** Pattern rules mapping file paths to manifest types */
3
3
  export interface PatternRule {
4
4
  /** Regex to match the file path (relative to engine/) */
@@ -9,6 +9,15 @@ export interface PatternRule {
9
9
  register: (engineDir: string, after: string | undefined, dryRun: boolean, ...args: string[]) => Promise<RegisterResult>;
10
10
  /** Extract arguments from the regex match */
11
11
  extractArgs: (match: RegExpMatchArray) => string[];
12
+ /**
13
+ * Whether this rule's manifest supports `--after` placement.
14
+ *
15
+ * Four of the six rules ignore the flag entirely: the CLI accepts
16
+ * `--after`, the adapter takes it as `_after`, and the operator gets a
17
+ * silently alphabetical insertion with no indication their placement was
18
+ * dropped. Declaring it lets {@link registerFile} say so.
19
+ */
20
+ supportsAfter: boolean;
12
21
  }
13
22
  /**
14
23
  * Returns manifest registration rules for the supported engine file