@hominis/fireforge 0.44.4 → 0.46.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 (378) hide show
  1. package/CHANGELOG.md +120 -0
  2. package/dist/bin/fireforge.js +6 -0
  3. package/dist/build-info.json +4 -4
  4. package/dist/src/cli-usage-error.d.ts +46 -0
  5. package/dist/src/cli-usage-error.js +81 -0
  6. package/dist/src/cli.d.ts +5 -1
  7. package/dist/src/cli.js +20 -21
  8. package/dist/src/commands/bootstrap.js +1 -2
  9. package/dist/src/commands/build.js +15 -6
  10. package/dist/src/commands/destructive-decision.d.ts +19 -0
  11. package/dist/src/commands/destructive-decision.js +31 -0
  12. package/dist/src/commands/doctor-check-core.d.ts +0 -6
  13. package/dist/src/commands/doctor-check-core.js +0 -8
  14. package/dist/src/commands/doctor-orphaned-harness.d.ts +0 -6
  15. package/dist/src/commands/doctor-orphaned-harness.js +4 -12
  16. package/dist/src/commands/doctor-post-rebase-audit.js +1 -1
  17. package/dist/src/commands/doctor-source-pin.d.ts +29 -0
  18. package/dist/src/commands/doctor-source-pin.js +81 -0
  19. package/dist/src/commands/doctor.d.ts +2 -0
  20. package/dist/src/commands/doctor.js +9 -8
  21. package/dist/src/commands/download.js +35 -24
  22. package/dist/src/commands/export-all.js +21 -4
  23. package/dist/src/commands/export-flow.js +15 -60
  24. package/dist/src/commands/export-placement-conflicts.js +3 -3
  25. package/dist/src/commands/export-placement-gate.js +2 -8
  26. package/dist/src/commands/export-placement-policy.js +3 -5
  27. package/dist/src/commands/export-shared.d.ts +42 -23
  28. package/dist/src/commands/export-shared.js +4 -19
  29. package/dist/src/commands/export.js +10 -1
  30. package/dist/src/commands/furnace/authoring-config.d.ts +13 -0
  31. package/dist/src/commands/furnace/authoring-config.js +19 -0
  32. package/dist/src/commands/furnace/chrome-doc-remove.js +1 -1
  33. package/dist/src/commands/furnace/create-browser-test.js +3 -8
  34. package/dist/src/commands/furnace/create-dry-run.js +2 -5
  35. package/dist/src/commands/furnace/create-templates.d.ts +17 -1
  36. package/dist/src/commands/furnace/create-templates.js +2 -1
  37. package/dist/src/commands/furnace/create.js +25 -19
  38. package/dist/src/commands/furnace/deploy.js +11 -2
  39. package/dist/src/commands/furnace/init.js +2 -1
  40. package/dist/src/commands/furnace/override.js +28 -19
  41. package/dist/src/commands/furnace/refresh.js +9 -1
  42. package/dist/src/commands/furnace/remove-mutations.d.ts +6 -7
  43. package/dist/src/commands/furnace/remove-mutations.js +0 -1
  44. package/dist/src/commands/furnace/remove.js +2 -6
  45. package/dist/src/commands/furnace/rename-browser-test.js +1 -7
  46. package/dist/src/commands/furnace/rename.js +29 -29
  47. package/dist/src/commands/furnace/status.js +12 -9
  48. package/dist/src/commands/furnace/test-file-name.d.ts +28 -0
  49. package/dist/src/commands/furnace/test-file-name.js +39 -0
  50. package/dist/src/commands/furnace/validation-output.d.ts +21 -9
  51. package/dist/src/commands/furnace/validation-output.js +3 -8
  52. package/dist/src/commands/import.js +2 -9
  53. package/dist/src/commands/lint-per-patch.d.ts +2 -2
  54. package/dist/src/commands/lint-per-patch.js +19 -4
  55. package/dist/src/commands/lint-per-run-checkjs.d.ts +2 -2
  56. package/dist/src/commands/lint.d.ts +2 -1
  57. package/dist/src/commands/lint.js +1 -1
  58. package/dist/src/commands/manifest.js +1 -1
  59. package/dist/src/commands/package.js +2 -4
  60. package/dist/src/commands/patch/compact.js +14 -15
  61. package/dist/src/commands/patch/delete.js +15 -25
  62. package/dist/src/commands/patch/entry-projection.d.ts +13 -0
  63. package/dist/src/commands/patch/entry-projection.js +24 -0
  64. package/dist/src/commands/patch/lint-ignore.d.ts +0 -8
  65. package/dist/src/commands/patch/lint-ignore.js +19 -29
  66. package/dist/src/commands/patch/move-files-create.js +24 -10
  67. package/dist/src/commands/patch/move-files-into.js +38 -37
  68. package/dist/src/commands/patch/move-files.js +4 -13
  69. package/dist/src/commands/patch/rename.js +27 -41
  70. package/dist/src/commands/patch/reorder.js +25 -38
  71. package/dist/src/commands/patch/split-plan.d.ts +4 -5
  72. package/dist/src/commands/patch/split-plan.js +4 -11
  73. package/dist/src/commands/patch/split.js +45 -43
  74. package/dist/src/commands/patch/staged-dependency.js +16 -22
  75. package/dist/src/commands/patch/tier.js +15 -25
  76. package/dist/src/commands/patch-rename-map.d.ts +19 -0
  77. package/dist/src/commands/patch-rename-map.js +36 -0
  78. package/dist/src/commands/pending-resolution.d.ts +15 -0
  79. package/dist/src/commands/pending-resolution.js +25 -0
  80. package/dist/src/commands/re-export-adjacent.d.ts +32 -2
  81. package/dist/src/commands/re-export-adjacent.js +51 -10
  82. package/dist/src/commands/re-export-bulk-scan.js +6 -10
  83. package/dist/src/commands/re-export-drift.d.ts +8 -0
  84. package/dist/src/commands/re-export-drift.js +65 -4
  85. package/dist/src/commands/re-export-files.d.ts +2 -3
  86. package/dist/src/commands/re-export-files.js +38 -32
  87. package/dist/src/commands/re-export-lint.d.ts +3 -4
  88. package/dist/src/commands/re-export-lint.js +9 -2
  89. package/dist/src/commands/re-export-options.js +19 -5
  90. package/dist/src/commands/re-export-register.js +5 -1
  91. package/dist/src/commands/re-export-scan.js +8 -8
  92. package/dist/src/commands/re-export-single.d.ts +22 -3
  93. package/dist/src/commands/re-export-single.js +19 -11
  94. package/dist/src/commands/re-export.js +44 -27
  95. package/dist/src/commands/rebase/abort.js +3 -8
  96. package/dist/src/commands/rebase/continue.js +12 -12
  97. package/dist/src/commands/rebase/index.js +2 -2
  98. package/dist/src/commands/rebase/patch-loop.d.ts +2 -2
  99. package/dist/src/commands/rebase/patch-loop.js +2 -7
  100. package/dist/src/commands/resolve.js +18 -10
  101. package/dist/src/commands/run.d.ts +0 -13
  102. package/dist/src/commands/run.js +12 -25
  103. package/dist/src/commands/setup-support.d.ts +16 -4
  104. package/dist/src/commands/setup-support.js +16 -16
  105. package/dist/src/commands/setup.js +3 -9
  106. package/dist/src/commands/source.js +8 -1
  107. package/dist/src/commands/status-check.js +2 -2
  108. package/dist/src/commands/status-output.js +2 -2
  109. package/dist/src/commands/status.js +3 -4
  110. package/dist/src/commands/test-build-phase.d.ts +2 -2
  111. package/dist/src/commands/test-build-phase.js +33 -8
  112. package/dist/src/commands/test-diagnose.js +14 -5
  113. package/dist/src/commands/test-modes.d.ts +2 -2
  114. package/dist/src/commands/test-modes.js +0 -1
  115. package/dist/src/commands/test-register.js +6 -3
  116. package/dist/src/commands/test-run.js +29 -21
  117. package/dist/src/commands/test-stale-gate.js +8 -5
  118. package/dist/src/commands/test-verdict.d.ts +16 -2
  119. package/dist/src/commands/test-verdict.js +18 -3
  120. package/dist/src/commands/test.js +51 -7
  121. package/dist/src/commands/token-list.d.ts +26 -0
  122. package/dist/src/commands/token-list.js +153 -0
  123. package/dist/src/commands/token.js +17 -1
  124. package/dist/src/commands/tree.js +7 -2
  125. package/dist/src/commands/typecheck.js +9 -9
  126. package/dist/src/commands/wire.js +4 -3
  127. package/dist/src/core/branding.d.ts +0 -7
  128. package/dist/src/core/branding.js +3 -2
  129. package/dist/src/core/browser-wire.js +6 -3
  130. package/dist/src/core/build-audit-platform.d.ts +29 -0
  131. package/dist/src/core/build-audit-platform.js +140 -0
  132. package/dist/src/core/build-audit-registration.js +3 -2
  133. package/dist/src/core/build-audit-skip.d.ts +57 -0
  134. package/dist/src/core/build-audit-skip.js +112 -0
  135. package/dist/src/core/build-audit.d.ts +15 -2
  136. package/dist/src/core/build-audit.js +154 -12
  137. package/dist/src/core/build-baseline.d.ts +45 -28
  138. package/dist/src/core/build-baseline.js +6 -29
  139. package/dist/src/core/build-jar-escalation.d.ts +64 -0
  140. package/dist/src/core/build-jar-escalation.js +128 -0
  141. package/dist/src/core/build-overwrite-guard.js +1 -1
  142. package/dist/src/core/build-prepare.d.ts +5 -2
  143. package/dist/src/core/build-prepare.js +34 -6
  144. package/dist/src/core/config-paths.d.ts +2 -6
  145. package/dist/src/core/config-paths.js +4 -2
  146. package/dist/src/core/config-state.d.ts +0 -6
  147. package/dist/src/core/config-state.js +1 -19
  148. package/dist/src/core/config-validate-build-audit.d.ts +8 -0
  149. package/dist/src/core/config-validate-build-audit.js +80 -0
  150. package/dist/src/core/config-validate-file-size.d.ts +12 -0
  151. package/dist/src/core/config-validate-file-size.js +65 -0
  152. package/dist/src/core/config-validate-patch-policy.d.ts +2 -2
  153. package/dist/src/core/config-validate-patch-policy.js +3 -3
  154. package/dist/src/core/config-validate-test-toolchains.d.ts +2 -2
  155. package/dist/src/core/config-validate-test-toolchains.js +4 -5
  156. package/dist/src/core/config-validate.js +20 -3
  157. package/dist/src/core/config.d.ts +2 -2
  158. package/dist/src/core/config.js +11 -15
  159. package/dist/src/core/coverage-extend.js +4 -4
  160. package/dist/src/core/discard-baseline.js +7 -7
  161. package/dist/src/core/engine-precondition.d.ts +1 -9
  162. package/dist/src/core/engine-precondition.js +3 -8
  163. package/dist/src/core/engine-session-lock.js +13 -17
  164. package/dist/src/core/export-moved-code-shape.js +2 -2
  165. package/dist/src/core/file-lock-owner.d.ts +103 -0
  166. package/dist/src/core/file-lock-owner.js +259 -0
  167. package/dist/src/core/file-lock.d.ts +2 -7
  168. package/dist/src/core/file-lock.js +40 -91
  169. package/dist/src/core/firefox-cache.d.ts +13 -1
  170. package/dist/src/core/firefox-cache.js +59 -34
  171. package/dist/src/core/firefox-download.d.ts +15 -0
  172. package/dist/src/core/firefox-download.js +37 -21
  173. package/dist/src/core/firefox-extract.d.ts +6 -5
  174. package/dist/src/core/firefox-extract.js +36 -18
  175. package/dist/src/core/firefox.d.ts +30 -32
  176. package/dist/src/core/firefox.js +5 -36
  177. package/dist/src/core/furnace-apply-dry-run.d.ts +1 -6
  178. package/dist/src/core/furnace-apply-dry-run.js +1 -7
  179. package/dist/src/core/furnace-apply-helpers.d.ts +0 -11
  180. package/dist/src/core/furnace-apply-helpers.js +8 -19
  181. package/dist/src/core/furnace-apply-overwrite-warn.js +4 -2
  182. package/dist/src/core/furnace-apply.d.ts +1 -1
  183. package/dist/src/core/furnace-apply.js +30 -10
  184. package/dist/src/core/furnace-config.d.ts +1 -1
  185. package/dist/src/core/furnace-config.js +23 -36
  186. package/dist/src/core/furnace-constants.js +3 -2
  187. package/dist/src/core/furnace-dir-entry.d.ts +20 -0
  188. package/dist/src/core/furnace-dir-entry.js +21 -0
  189. package/dist/src/core/furnace-operation.d.ts +2 -0
  190. package/dist/src/core/furnace-operation.js +3 -1
  191. package/dist/src/core/furnace-refresh.d.ts +18 -6
  192. package/dist/src/core/furnace-refresh.js +3 -6
  193. package/dist/src/core/furnace-registration-ast.d.ts +0 -1
  194. package/dist/src/core/furnace-registration-ast.js +0 -3
  195. package/dist/src/core/furnace-registration.d.ts +2 -1
  196. package/dist/src/core/furnace-registration.js +22 -29
  197. package/dist/src/core/furnace-scanner.js +3 -6
  198. package/dist/src/core/furnace-state-persist.d.ts +2 -2
  199. package/dist/src/core/furnace-validate-registration.js +5 -7
  200. package/dist/src/core/git-base.d.ts +3 -1
  201. package/dist/src/core/git-base.js +25 -3
  202. package/dist/src/core/git-diff-new-file.d.ts +40 -0
  203. package/dist/src/core/git-diff-new-file.js +119 -0
  204. package/dist/src/core/git-diff.d.ts +9 -9
  205. package/dist/src/core/git-diff.js +88 -157
  206. package/dist/src/core/git-file-ops.d.ts +0 -7
  207. package/dist/src/core/git-file-ops.js +4 -28
  208. package/dist/src/core/git-readonly-index.d.ts +0 -2
  209. package/dist/src/core/git-readonly-index.js +0 -4
  210. package/dist/src/core/git-status.d.ts +7 -0
  211. package/dist/src/core/git-status.js +21 -9
  212. package/dist/src/core/git.d.ts +0 -6
  213. package/dist/src/core/git.js +14 -43
  214. package/dist/src/core/harness-orphans.d.ts +73 -0
  215. package/dist/src/core/harness-orphans.js +187 -0
  216. package/dist/src/core/history-log.d.ts +19 -0
  217. package/dist/src/core/history-log.js +29 -0
  218. package/dist/src/core/mach-error-hints.d.ts +0 -5
  219. package/dist/src/core/mach-error-hints.js +1 -1
  220. package/dist/src/core/mach-known-noise-filter.d.ts +25 -3
  221. package/dist/src/core/mach-known-noise-filter.js +31 -10
  222. package/dist/src/core/mach-mozconfig.js +2 -1
  223. package/dist/src/core/mach-python.d.ts +2 -0
  224. package/dist/src/core/mach-python.js +12 -7
  225. package/dist/src/core/mach-resource-shim.d.ts +13 -1
  226. package/dist/src/core/mach-resource-shim.js +112 -9
  227. package/dist/src/core/mach.d.ts +46 -53
  228. package/dist/src/core/mach.js +31 -83
  229. package/dist/src/core/marionette-port.d.ts +0 -17
  230. package/dist/src/core/marionette-port.js +12 -58
  231. package/dist/src/core/marionette-preflight.js +9 -27
  232. package/dist/src/core/mochitest-server-port.js +3 -3
  233. package/dist/src/core/moz-manifest-rules.js +37 -33
  234. package/dist/src/core/patch-apply-fuzz.js +4 -4
  235. package/dist/src/core/patch-apply.d.ts +4 -5
  236. package/dist/src/core/patch-apply.js +55 -32
  237. package/dist/src/core/patch-export-coverage.d.ts +0 -9
  238. package/dist/src/core/patch-export-coverage.js +1 -30
  239. package/dist/src/core/patch-export-update.d.ts +18 -1
  240. package/dist/src/core/patch-export-update.js +4 -3
  241. package/dist/src/core/patch-export.d.ts +11 -21
  242. package/dist/src/core/patch-export.js +44 -66
  243. package/dist/src/core/patch-files.d.ts +0 -4
  244. package/dist/src/core/patch-files.js +0 -11
  245. package/dist/src/core/patch-lint-binary.d.ts +6 -12
  246. package/dist/src/core/patch-lint-cache.d.ts +17 -1
  247. package/dist/src/core/patch-lint-cache.js +3 -6
  248. package/dist/src/core/patch-lint-checkjs.d.ts +33 -16
  249. package/dist/src/core/patch-lint-checkjs.js +43 -25
  250. package/dist/src/core/patch-lint-creators.d.ts +2 -6
  251. package/dist/src/core/patch-lint-cross.d.ts +16 -8
  252. package/dist/src/core/patch-lint-cross.js +49 -92
  253. package/dist/src/core/patch-lint-css.js +10 -6
  254. package/dist/src/core/patch-lint-file-size.d.ts +52 -0
  255. package/dist/src/core/patch-lint-file-size.js +53 -0
  256. package/dist/src/core/patch-lint-forward-registration.d.ts +58 -0
  257. package/dist/src/core/patch-lint-forward-registration.js +210 -0
  258. package/dist/src/core/patch-lint-jsdoc.js +36 -36
  259. package/dist/src/core/patch-lint-module-registration.d.ts +2 -8
  260. package/dist/src/core/patch-lint-prettier.d.ts +36 -0
  261. package/dist/src/core/patch-lint-prettier.js +126 -0
  262. package/dist/src/core/patch-lint-queue-types.d.ts +60 -0
  263. package/dist/src/core/patch-lint-queue-types.js +12 -0
  264. package/dist/src/core/patch-lint-staged-registration.d.ts +61 -0
  265. package/dist/src/core/patch-lint-staged-registration.js +90 -0
  266. package/dist/src/core/patch-lint-unmanaged-companion.d.ts +106 -0
  267. package/dist/src/core/patch-lint-unmanaged-companion.js +214 -0
  268. package/dist/src/core/patch-lint.d.ts +14 -9
  269. package/dist/src/core/patch-lint.js +27 -27
  270. package/dist/src/core/patch-lock.js +3 -3
  271. package/dist/src/core/patch-manifest-io.js +8 -7
  272. package/dist/src/core/patch-parse.d.ts +19 -8
  273. package/dist/src/core/patch-parse.js +25 -0
  274. package/dist/src/core/patch-policy.js +15 -27
  275. package/dist/src/core/patch-source-metadata.d.ts +1 -3
  276. package/dist/src/core/patch-source-metadata.js +0 -4
  277. package/dist/src/core/patch-transform.d.ts +21 -8
  278. package/dist/src/core/patch-transform.js +38 -10
  279. package/dist/src/core/process-cpu-time.js +1 -1
  280. package/dist/src/core/rebase-session.d.ts +2 -8
  281. package/dist/src/core/rebase-session.js +5 -17
  282. package/dist/src/core/register-browser-content.js +3 -2
  283. package/dist/src/core/register-browser-test.js +2 -1
  284. package/dist/src/core/register-module.js +2 -1
  285. package/dist/src/core/register-scaffold.js +5 -4
  286. package/dist/src/core/register-shared-css.js +2 -1
  287. package/dist/src/core/run-log-redact.d.ts +38 -0
  288. package/dist/src/core/run-log-redact.js +69 -0
  289. package/dist/src/core/run-log.d.ts +13 -2
  290. package/dist/src/core/run-log.js +67 -18
  291. package/dist/src/core/signal-critical.js +2 -4
  292. package/dist/src/core/smoke-patterns.d.ts +0 -1
  293. package/dist/src/core/smoke-patterns.js +18 -11
  294. package/dist/src/core/state-file.d.ts +12 -1
  295. package/dist/src/core/state-file.js +14 -1
  296. package/dist/src/core/status-classify.js +2 -1
  297. package/dist/src/core/test-changed-prefs.js +26 -11
  298. package/dist/src/core/test-harness-crash.js +61 -48
  299. package/dist/src/core/test-harness-verdict-notes.d.ts +55 -0
  300. package/dist/src/core/test-harness-verdict-notes.js +48 -0
  301. package/dist/src/core/test-stale-check.d.ts +23 -8
  302. package/dist/src/core/test-stale-check.js +77 -4
  303. package/dist/src/core/test-stall-triage.js +37 -19
  304. package/dist/src/core/test-xpcshell-retry.d.ts +26 -7
  305. package/dist/src/core/test-xpcshell-retry.js +14 -11
  306. package/dist/src/core/token-category.d.ts +33 -0
  307. package/dist/src/core/token-category.js +56 -48
  308. package/dist/src/core/token-dark-mode.js +2 -14
  309. package/dist/src/core/token-inventory.d.ts +56 -0
  310. package/dist/src/core/token-inventory.js +109 -0
  311. package/dist/src/core/token-manager.d.ts +1 -1
  312. package/dist/src/core/token-manager.js +1 -1
  313. package/dist/src/core/token-variant.js +21 -22
  314. package/dist/src/core/toolchain-preflight.js +1 -1
  315. package/dist/src/core/tree-cow.d.ts +0 -2
  316. package/dist/src/core/tree-cow.js +2 -2
  317. package/dist/src/core/tree-store.js +4 -5
  318. package/dist/src/core/typecheck.js +2 -2
  319. package/dist/src/core/wire-dom-fragment.js +6 -17
  320. package/dist/src/core/wire-utils.js +5 -17
  321. package/dist/src/core/xpcshell-appdir.js +2 -4
  322. package/dist/src/errors/base.d.ts +53 -1
  323. package/dist/src/errors/base.js +79 -11
  324. package/dist/src/errors/build.d.ts +28 -0
  325. package/dist/src/errors/build.js +51 -10
  326. package/dist/src/errors/config.d.ts +0 -14
  327. package/dist/src/errors/config.js +13 -34
  328. package/dist/src/errors/download.d.ts +13 -0
  329. package/dist/src/errors/download.js +53 -24
  330. package/dist/src/errors/furnace.js +8 -9
  331. package/dist/src/errors/git.d.ts +8 -8
  332. package/dist/src/errors/git.js +20 -30
  333. package/dist/src/errors/patch.js +8 -10
  334. package/dist/src/errors/rebase.js +7 -7
  335. package/dist/src/types/commands/options.d.ts +96 -123
  336. package/dist/src/types/commands/patches.d.ts +17 -6
  337. package/dist/src/types/config.d.ts +75 -2
  338. package/dist/src/types/index.d.ts +0 -1
  339. package/dist/src/utils/assert.d.ts +3 -15
  340. package/dist/src/utils/assert.js +1 -18
  341. package/dist/src/utils/build-info.d.ts +1 -1
  342. package/dist/src/utils/child-env.d.ts +2 -1
  343. package/dist/src/utils/elapsed.js +10 -1
  344. package/dist/src/utils/fs.d.ts +4 -2
  345. package/dist/src/utils/fs.js +11 -14
  346. package/dist/src/utils/hash.d.ts +12 -0
  347. package/dist/src/utils/hash.js +16 -0
  348. package/dist/src/utils/line-dispatch.d.ts +15 -0
  349. package/dist/src/utils/line-dispatch.js +48 -0
  350. package/dist/src/utils/options.d.ts +1 -7
  351. package/dist/src/utils/options.js +6 -7
  352. package/dist/src/utils/package-root.js +3 -12
  353. package/dist/src/utils/platform.d.ts +0 -4
  354. package/dist/src/utils/process-group.d.ts +2 -1
  355. package/dist/src/utils/process-group.js +20 -19
  356. package/dist/src/utils/process.d.ts +40 -26
  357. package/dist/src/utils/process.js +115 -166
  358. package/dist/src/utils/ps-duration.js +3 -3
  359. package/dist/src/utils/sleep.d.ts +26 -0
  360. package/dist/src/utils/sleep.js +31 -0
  361. package/dist/src/utils/validation.d.ts +2 -38
  362. package/dist/src/utils/validation.js +7 -16
  363. package/docs/configuration.md +136 -1
  364. package/docs/exit-codes.md +34 -20
  365. package/docs/lifecycle-invariants.md +18 -12
  366. package/docs/machine-output.md +31 -8
  367. package/docs/patch-workflow.md +2 -1
  368. package/docs/run-logs.md +44 -4
  369. package/docs/testing.md +70 -11
  370. package/package.json +8 -7
  371. package/dist/src/commands/rebase.d.ts +0 -4
  372. package/dist/src/commands/rebase.js +0 -5
  373. package/dist/src/core/patch-artifact-normalize.d.ts +0 -21
  374. package/dist/src/core/patch-artifact-normalize.js +0 -24
  375. package/dist/src/core/patch-lint-reexports.d.ts +0 -7
  376. package/dist/src/core/patch-lint-reexports.js +0 -8
  377. package/dist/src/core/wire-targets.d.ts +0 -7
  378. package/dist/src/core/wire-targets.js +0 -8
@@ -13,6 +13,22 @@ export interface UpdatePatchPolicyGate {
13
13
  command: string;
14
14
  forceUnsafe?: boolean;
15
15
  }
16
+ export interface UpdatePatchAndMetadataOptions {
17
+ /** Patch directory holding the body and `patches.json`. */
18
+ patchesDir: string;
19
+ /** Patch file to rewrite. */
20
+ filename: string;
21
+ /** New patch body; an identical body skips the write. */
22
+ newContent: string;
23
+ /** Manifest-row fields to merge into the patch's metadata. */
24
+ updates: Partial<PatchMetadata>;
25
+ /** Hook run under the lock after the mutation succeeds. */
26
+ onCommitted?: UpdatePatchCommittedHook | undefined;
27
+ /** Policy gate run against the under-lock projected manifest. */
28
+ policyGate?: UpdatePatchPolicyGate | undefined;
29
+ /** Wait budget and command name for the patch directory lock. */
30
+ lockOptions?: PatchDirectoryLockOptions | undefined;
31
+ }
16
32
  /**
17
33
  * Updates a patch file body and its manifest row under the same patch
18
34
  * directory lock. Intended for commands like `re-export --files` where the
@@ -26,7 +42,8 @@ export interface UpdatePatchPolicyGate {
26
42
  * unexpected rewrite in `git status`. Metadata still moves either way — only
27
43
  * the redundant byte-for-byte write is elided.
28
44
  *
45
+ * @param options - See {@link UpdatePatchAndMetadataOptions}
29
46
  * @returns True when the patch body on disk changed, false when it was
30
47
  * already byte-identical to the new content.
31
48
  */
32
- export declare function updatePatchAndMetadata(patchesDir: string, filename: string, newContent: string, updates: Partial<PatchMetadata>, onCommitted?: UpdatePatchCommittedHook, policyGate?: UpdatePatchPolicyGate, lockOptions?: PatchDirectoryLockOptions): Promise<boolean>;
49
+ export declare function updatePatchAndMetadata(options: UpdatePatchAndMetadataOptions): Promise<boolean>;
@@ -5,7 +5,6 @@ import { toError } from '../utils/errors.js';
5
5
  import { pathExists, readText, writeText } from '../utils/fs.js';
6
6
  import { warn } from '../utils/logger.js';
7
7
  import { withPatchDirectoryLock } from './patch-apply.js';
8
- import { normalizePatchArtifact } from './patch-artifact-normalize.js';
9
8
  import { loadPatchesManifestForWrite, mutatePatchRowsInManifest } from './patch-manifest.js';
10
9
  import { buildProjectedManifest, enforcePatchPolicy } from './patch-policy.js';
11
10
  /**
@@ -21,10 +20,12 @@ import { buildProjectedManifest, enforcePatchPolicy } from './patch-policy.js';
21
20
  * unexpected rewrite in `git status`. Metadata still moves either way — only
22
21
  * the redundant byte-for-byte write is elided.
23
22
  *
23
+ * @param options - See {@link UpdatePatchAndMetadataOptions}
24
24
  * @returns True when the patch body on disk changed, false when it was
25
25
  * already byte-identical to the new content.
26
26
  */
27
- export async function updatePatchAndMetadata(patchesDir, filename, newContent, updates, onCommitted, policyGate, lockOptions = {}) {
27
+ export async function updatePatchAndMetadata(options) {
28
+ const { patchesDir, filename, newContent, updates, onCommitted, policyGate, lockOptions = {}, } = options;
28
29
  return withPatchDirectoryLock(patchesDir, async () => {
29
30
  const manifest = await loadPatchesManifestForWrite(patchesDir);
30
31
  if (!manifest) {
@@ -49,7 +50,7 @@ export async function updatePatchAndMetadata(patchesDir, filename, newContent, u
49
50
  forceUnsafe: policyGate.forceUnsafe === true,
50
51
  });
51
52
  }
52
- const normalized = normalizePatchArtifact(newContent);
53
+ const normalized = newContent;
53
54
  const bodyChanged = normalized !== originalContent;
54
55
  let patchWritten = false;
55
56
  try {
@@ -2,9 +2,19 @@ import type { PatchCategory, PatchesManifest, PatchInfo, PatchMetadata } from '.
2
2
  import type { FireForgeConfig } from '../types/config.js';
3
3
  import { type SupersedeCoverageDetail } from './patch-export-coverage.js';
4
4
  import type { PatchDirectoryLockOptions } from './patch-lock.js';
5
- export { findAllPatchesForFiles, findAllPatchesForFilesWithDetails, findSupersededPatches, isPatchFullyCovered, type SupersedeCoverageDetail, } from './patch-export-coverage.js';
5
+ export { findAllPatchesForFiles, findAllPatchesForFilesWithDetails, } from './patch-export-coverage.js';
6
6
  export { mutatePatchMetadata, updatePatchMetadata } from './patch-export-metadata.js';
7
7
  export { updatePatchAndMetadata } from './patch-export-update.js';
8
+ /**
9
+ * Projects the planning subset out of a wider export input (commit input,
10
+ * dry-run preview input) — the fields `planExport` /
11
+ * `computeExportPlanUnderLock` read. Optional fields are copied only when
12
+ * present so the plan input never carries explicit `undefined` keys, which
13
+ * would otherwise leak into the written metadata via spread. The commit
14
+ * path and the dry-run preview both go through this one projection so
15
+ * they cannot drift field by field.
16
+ */
17
+ export declare function buildPlanExportInput(input: PlanExportInput): PlanExportInput;
8
18
  /**
9
19
  * Gets the next patch number for a new patch.
10
20
  * @param patchesDir - Path to the patches directory
@@ -91,26 +101,6 @@ export interface CommitExportedPatchResult {
91
101
  * to filename allocation or supersede detection lands in both automatically.
92
102
  */
93
103
  export declare function commitExportedPatch(input: CommitExportedPatchInput): Promise<CommitExportedPatchResult>;
94
- /**
95
- * Parses a patch filename to extract order, category, and name.
96
- * Supports both new format (001-category-name.patch) and legacy (001-name.patch).
97
- */
98
- export declare function parseFilename(filename: string): {
99
- order: number;
100
- category: PatchCategory | null;
101
- name: string;
102
- };
103
- /**
104
- * Finds an existing patch that contains the specified file.
105
- * Returns the most recent (highest order) patch if multiple exist.
106
- * @param patchesDir - Path to the patches directory
107
- * @param filePath - File path to search for
108
- * @returns The patch info and metadata, or null if not found
109
- */
110
- export declare function findExistingPatchForFile(patchesDir: string, filePath: string): Promise<{
111
- patch: PatchInfo;
112
- metadata: PatchMetadata;
113
- } | null>;
114
104
  /**
115
105
  * Updates the content of a patch file.
116
106
  * @param patchPath - Path to the patch file
@@ -3,17 +3,39 @@ import { join } from 'node:path';
3
3
  import { toError } from '../utils/errors.js';
4
4
  import { pathExists, readText, removeFile, writeText } from '../utils/fs.js';
5
5
  import { warn } from '../utils/logger.js';
6
- import { PATCH_CATEGORIES } from '../utils/validation.js';
7
6
  import { discoverPatches, withPatchDirectoryLock } from './patch-apply.js';
8
- import { normalizePatchArtifact } from './patch-artifact-normalize.js';
9
7
  import { findAllPatchesForFilesWithDetails, } from './patch-export-coverage.js';
10
- import { addPatchToManifest, findPatchesAffectingFile, loadPatchesManifestForWrite, PATCHES_MANIFEST, savePatchesManifest, } from './patch-manifest.js';
11
- import { requirePatchOrder } from './patch-parse.js';
8
+ import { addPatchToManifest, loadPatchesManifestForWrite, PATCHES_MANIFEST, savePatchesManifest, } from './patch-manifest.js';
9
+ import { formatPatchOrder, requirePatchOrder } from './patch-parse.js';
12
10
  import { allocatePolicyOrder, enforcePatchPolicy } from './patch-policy.js';
13
- export { findAllPatchesForFiles, findAllPatchesForFilesWithDetails, findSupersededPatches, isPatchFullyCovered, } from './patch-export-coverage.js';
11
+ export { findAllPatchesForFiles, findAllPatchesForFilesWithDetails, } from './patch-export-coverage.js';
14
12
  import { escapeRegex } from '../utils/regex.js';
15
13
  export { mutatePatchMetadata, updatePatchMetadata } from './patch-export-metadata.js';
16
14
  export { updatePatchAndMetadata } from './patch-export-update.js';
15
+ /**
16
+ * Projects the planning subset out of a wider export input (commit input,
17
+ * dry-run preview input) — the fields `planExport` /
18
+ * `computeExportPlanUnderLock` read. Optional fields are copied only when
19
+ * present so the plan input never carries explicit `undefined` keys, which
20
+ * would otherwise leak into the written metadata via spread. The commit
21
+ * path and the dry-run preview both go through this one projection so
22
+ * they cannot drift field by field.
23
+ */
24
+ export function buildPlanExportInput(input) {
25
+ return {
26
+ patchesDir: input.patchesDir,
27
+ category: input.category,
28
+ name: input.name,
29
+ description: input.description,
30
+ filesAffected: input.filesAffected,
31
+ sourceEsrVersion: input.sourceEsrVersion,
32
+ ...(input.sourceProduct !== undefined ? { sourceProduct: input.sourceProduct } : {}),
33
+ ...(input.sourceVersion !== undefined ? { sourceVersion: input.sourceVersion } : {}),
34
+ ...(input.tier !== undefined ? { tier: input.tier } : {}),
35
+ ...(input.lintIgnore !== undefined ? { lintIgnore: input.lintIgnore } : {}),
36
+ ...(input.config !== undefined ? { config: input.config } : {}),
37
+ };
38
+ }
17
39
  /**
18
40
  * Gets the next patch number for a new patch.
19
41
  * @param patchesDir - Path to the patches directory
@@ -110,19 +132,7 @@ export async function getNextPatchFilename(patchesDir, category, name) {
110
132
  */
111
133
  export async function commitExportedPatch(input) {
112
134
  return withPatchDirectoryLock(input.patchesDir, async () => {
113
- const plan = await computeExportPlanUnderLock({
114
- patchesDir: input.patchesDir,
115
- category: input.category,
116
- name: input.name,
117
- description: input.description,
118
- filesAffected: input.filesAffected,
119
- sourceEsrVersion: input.sourceEsrVersion,
120
- ...(input.sourceProduct !== undefined ? { sourceProduct: input.sourceProduct } : {}),
121
- ...(input.sourceVersion !== undefined ? { sourceVersion: input.sourceVersion } : {}),
122
- ...(input.tier !== undefined ? { tier: input.tier } : {}),
123
- ...(input.lintIgnore !== undefined ? { lintIgnore: input.lintIgnore } : {}),
124
- ...(input.config !== undefined ? { config: input.config } : {}),
125
- });
135
+ const plan = await computeExportPlanUnderLock(buildPlanExportInput(input));
126
136
  if (input.config !== undefined) {
127
137
  enforcePatchPolicy({
128
138
  config: input.config,
@@ -140,7 +150,20 @@ export async function commitExportedPatch(input) {
140
150
  }
141
151
  }
142
152
  try {
143
- await writeText(patchPath, normalizePatchArtifact(input.diff));
153
+ // Patch bodies are written byte-for-byte as git produced them, including the
154
+ // single-space rendering of a blank context line.
155
+ //
156
+ // Do NOT add a whitespace-trimming pass here or at any other write site.
157
+ // Stripping marker lines whose payload is pure whitespace (`/^[ +-]\s+$/` →
158
+ // bare marker) corrupts real content: Firefox sources contain whitespace-only
159
+ // lines, so a ` `/`-` line whose payload was two spaces no longer matches the
160
+ // pristine tree and the freshly exported patch fails `git apply --check`,
161
+ // while a `+` line silently changes what the patch produces. The repository
162
+ // whitespace check already exempts `patches/*.patch`
163
+ // (scripts/check-worktree-whitespace.mjs), and the byte-fidelity contract is
164
+ // pinned end-to-end by `git-diff-latin1-roundtrip.test.ts` and
165
+ // `re-export.integration.test.ts`.
166
+ await writeText(patchPath, input.diff);
144
167
  await addPatchToManifest(input.patchesDir, plan.metadata, plan.supersededPatches.map((p) => p.filename));
145
168
  for (const oldPatch of plan.supersededPatches) {
146
169
  await removeFile(oldPatch.path);
@@ -188,58 +211,13 @@ export async function commitExportedPatch(input) {
188
211
  };
189
212
  }, input.lockOptions ?? {});
190
213
  }
191
- /**
192
- * Parses a patch filename to extract order, category, and name.
193
- * Supports both new format (001-category-name.patch) and legacy (001-name.patch).
194
- */
195
- export function parseFilename(filename) {
196
- // New format: 001-ui-sidebar.patch
197
- const newMatch = /^(\d+)-([a-z]+)-(.+)\.patch$/.exec(filename);
198
- if (newMatch?.[1] && newMatch[2] && newMatch[3]) {
199
- const orderStr = newMatch[1];
200
- const category = newMatch[2];
201
- const name = newMatch[3];
202
- if (PATCH_CATEGORIES.includes(category)) {
203
- return {
204
- order: parseInt(orderStr, 10),
205
- category,
206
- name,
207
- };
208
- }
209
- }
210
- // Legacy format: 001-name.patch
211
- const legacyMatch = /^(\d+)-(.+)\.patch$/.exec(filename);
212
- if (legacyMatch?.[1] && legacyMatch[2]) {
213
- return {
214
- order: parseInt(legacyMatch[1], 10),
215
- category: null,
216
- name: legacyMatch[2],
217
- };
218
- }
219
- return { order: Infinity, category: null, name: filename };
220
- }
221
- /**
222
- * Finds an existing patch that contains the specified file.
223
- * Returns the most recent (highest order) patch if multiple exist.
224
- * @param patchesDir - Path to the patches directory
225
- * @param filePath - File path to search for
226
- * @returns The patch info and metadata, or null if not found
227
- */
228
- export async function findExistingPatchForFile(patchesDir, filePath) {
229
- const affectingPatches = await findPatchesAffectingFile(patchesDir, filePath);
230
- if (affectingPatches.length === 0) {
231
- return null;
232
- }
233
- // Return the most recent (highest order) patch
234
- return affectingPatches[affectingPatches.length - 1] ?? null;
235
- }
236
214
  /**
237
215
  * Updates the content of a patch file.
238
216
  * @param patchPath - Path to the patch file
239
217
  * @param newContent - New patch content
240
218
  */
241
219
  export async function updatePatch(patchPath, newContent) {
242
- await writeText(patchPath, normalizePatchArtifact(newContent));
220
+ await writeText(patchPath, newContent);
243
221
  }
244
222
  /**
245
223
  * Internal planning helper. Does NOT take the patch directory lock — the
@@ -259,7 +237,7 @@ async function computeExportPlanUnderLock(input) {
259
237
  ? allocatePolicyOrder(input.config, manifestBefore?.patches ?? [], input.category)
260
238
  : null;
261
239
  const patchFilename = policyOrder !== null
262
- ? `${String(policyOrder).padStart(3, '0')}-${input.category}-${patchNameSlug(input.name, input.category)}.patch`
240
+ ? `${formatPatchOrder(policyOrder)}-${input.category}-${patchNameSlug(input.name, input.category)}.patch`
263
241
  : await getNextPatchFilename(input.patchesDir, input.category, input.name);
264
242
  const patchPath = join(input.patchesDir, patchFilename);
265
243
  const metadata = {
@@ -3,10 +3,6 @@ import type { PatchInfo } from '../types/commands/index.js';
3
3
  export declare function discoverPatches(patchesDir: string): Promise<PatchInfo[]>;
4
4
  /** Counts the patch files currently present in a patch directory. */
5
5
  export declare function countPatches(patchesDir: string): Promise<number>;
6
- /** Checks whether a patch creates a new file rather than modifying an existing one. */
7
- export declare function isNewFilePatch(patchPath: string): Promise<boolean>;
8
- /** Returns the first target file path referenced by a patch, if any. */
9
- export declare function getTargetFileFromPatch(patchPath: string): Promise<string | null>;
10
6
  /**
11
7
  * Returns all target file paths referenced by a multi-file patch.
12
8
  *
@@ -24,17 +24,6 @@ export async function countPatches(patchesDir) {
24
24
  const patches = await discoverPatches(patchesDir);
25
25
  return patches.length;
26
26
  }
27
- /** Checks whether a patch creates a new file rather than modifying an existing one. */
28
- export async function isNewFilePatch(patchPath) {
29
- const content = await readText(patchPath);
30
- return content.includes('new file mode') && content.includes('--- /dev/null');
31
- }
32
- /** Returns the first target file path referenced by a patch, if any. */
33
- export async function getTargetFileFromPatch(patchPath) {
34
- const content = await readText(patchPath);
35
- const match = /^\+\+\+ b\/(.+)$/m.exec(content);
36
- return match?.[1] ?? null;
37
- }
38
27
  /**
39
28
  * Returns all target file paths referenced by a multi-file patch.
40
29
  *
@@ -21,20 +21,14 @@
21
21
  * cross-patch lint graph.
22
22
  */
23
23
  import type { PatchLintIssue } from '../types/commands/index.js';
24
+ import type { PatchQueueBodyEntry, PatchQueueView } from './patch-lint-queue-types.js';
24
25
  /**
25
- * The slice of a queue entry this rule reads. Declared structurally rather
26
- * than importing `PatchQueueEntry` from `patch-lint-cross.ts`, which imports
27
- * this module back — the local shape keeps the dependency edge one-way and
28
- * `dpdm` clean, matching `patch-lint-module-registration.ts`.
26
+ * Queue view accepted by {@link lintPatchQueueBinaryBodies}. Described
27
+ * structurally rather than by importing `PatchQueueContext` from
28
+ * `patch-lint-cross.ts`, which imports this module back — the shared leaf
29
+ * type keeps the dependency edge one-way and `dpdm` clean.
29
30
  */
30
- interface BinaryBodyQueueEntry {
31
- filename: string;
32
- diff: string;
33
- }
34
- /** Queue view accepted by {@link lintPatchQueueBinaryBodies}. */
35
- interface BinaryBodyQueueContext {
36
- entries: readonly BinaryBodyQueueEntry[];
37
- }
31
+ type BinaryBodyQueueContext = PatchQueueView<PatchQueueBodyEntry>;
38
32
  /** Lint check identifier emitted by {@link lintPatchQueueBinaryBodies}. */
39
33
  export declare const BINARY_BODY_CHECK = "binary-body-not-reconstructable";
40
34
  /**
@@ -58,5 +58,21 @@ export interface CachedPerPatchLint {
58
58
  * is compared explicitly rather than trusted to the key.
59
59
  */
60
60
  export declare function getCachedPerPatchLintIssues(cache: PerPatchLintCacheFile, patchFilename: string, key: string, lintIgnore?: Iterable<string>): CachedPerPatchLint | undefined;
61
+ export interface SetCachedPerPatchLintIssuesInput {
62
+ /** Cache file to mutate in place. */
63
+ cache: PerPatchLintCacheFile;
64
+ /** Patch the payload belongs to; also the cache entry key. */
65
+ patchFilename: string;
66
+ /** Fingerprint the payload is valid for. */
67
+ key: string;
68
+ /** Reported issues, stored as copies. */
69
+ issues: PatchLintIssue[];
70
+ /** Issues suppressed by `lintIgnore`, stored as copies. */
71
+ suppressed: PatchLintIssue[];
72
+ /** Line count the run measured. */
73
+ lineCount: number;
74
+ /** Suppression ids in force for the run, normalized on store. */
75
+ lintIgnore?: Iterable<string> | undefined;
76
+ }
61
77
  /** Stores the per-patch lint payload after a successful lint calculation. */
62
- export declare function setCachedPerPatchLintIssues(cache: PerPatchLintCacheFile, patchFilename: string, key: string, issues: PatchLintIssue[], suppressed: PatchLintIssue[], lineCount: number, lintIgnore?: Iterable<string>): void;
78
+ export declare function setCachedPerPatchLintIssues(input: SetCachedPerPatchLintIssuesInput): void;
@@ -1,8 +1,8 @@
1
1
  // SPDX-License-Identifier: EUPL-1.2
2
- import { createHash } from 'node:crypto';
3
2
  import { readFile } from 'node:fs/promises';
4
3
  import { join, resolve } from 'node:path';
5
4
  import { pathExists, readJson, writeJson } from '../utils/fs.js';
5
+ import { sha256Hex } from '../utils/hash.js';
6
6
  import { getPackageVersion } from '../utils/package-root.js';
7
7
  import { getFurnacePaths } from './furnace-config.js';
8
8
  import { git } from './git-base.js';
@@ -42,10 +42,6 @@ function stableJson(value) {
42
42
  .map(([key, item]) => `${JSON.stringify(key)}:${stableJson(item)}`)
43
43
  .join(',')}}`;
44
44
  }
45
- /** Computes a SHA-256 hex digest for text or binary content. */
46
- function sha256Hex(content) {
47
- return createHash('sha256').update(content).digest('hex');
48
- }
49
45
  /** Computes a stable SHA-256 digest for JSON-compatible data. */
50
46
  function stableHash(value) {
51
47
  return sha256Hex(stableJson(value));
@@ -223,7 +219,8 @@ export function getCachedPerPatchLintIssues(cache, patchFilename, key, lintIgnor
223
219
  };
224
220
  }
225
221
  /** Stores the per-patch lint payload after a successful lint calculation. */
226
- export function setCachedPerPatchLintIssues(cache, patchFilename, key, issues, suppressed, lineCount, lintIgnore) {
222
+ export function setCachedPerPatchLintIssues(input) {
223
+ const { cache, patchFilename, key, issues, suppressed, lineCount, lintIgnore } = input;
227
224
  cache.entries[patchFilename] = {
228
225
  key,
229
226
  patchFilename,
@@ -46,6 +46,37 @@ export interface GroupedCheckJsResult {
46
46
  byFile: Map<string, PatchLintIssue[]>;
47
47
  global: PatchLintIssue[];
48
48
  }
49
+ /** Inputs for {@link runCheckJsGrouped}. */
50
+ export interface RunCheckJsGroupedInput {
51
+ /** Absolute engine (repository) directory. */
52
+ repoDir: string;
53
+ /**
54
+ * Patch-owned `.sys.mjs` paths (relative to `repoDir`) the program should
55
+ * see and resolve against.
56
+ */
57
+ resolutionOwned: Set<string>;
58
+ /**
59
+ * Optional project-relative extra `.d.ts` appended to the built-in
60
+ * Firefox-globals shim (from `patchLint.checkJsExtraShim`).
61
+ */
62
+ extraShimPath?: string;
63
+ /** Absolute project root for resolving `extraShimPath`. */
64
+ projectRoot?: string;
65
+ /** Strictness preset plus allowlisted compiler-option overrides. */
66
+ mode?: CheckJsMode;
67
+ /** Optional shim text appended AFTER the consumer shim. */
68
+ builtinShimSuffix?: string;
69
+ /**
70
+ * When set, only these repo-relative files become program ROOTS;
71
+ * resolution (and the host allowlist) still spans all of
72
+ * `resolutionOwned`, so a subset root's cross-patch imports type-check
73
+ * against the real owning sources while unrelated owned files are never
74
+ * parsed. `.mjs` files are module-scoped, so a root's diagnostics are
75
+ * identical whether other owned files are roots or mere resolution
76
+ * targets.
77
+ */
78
+ rootScope?: ReadonlySet<string>;
79
+ }
49
80
  /**
50
81
  * Builds the checkJs program **once** over `resolutionOwned` and returns its
51
82
  * diagnostics grouped by originating file. Callers slice the result by their
@@ -54,24 +85,10 @@ export interface GroupedCheckJsResult {
54
85
  * every file in `resolutionOwned`, so cross-patch `resource:///`/`chrome://`
55
86
  * imports resolve to real sources.
56
87
  *
57
- * @param repoDir - Absolute engine (repository) directory
58
- * @param resolutionOwned - Patch-owned `.sys.mjs` paths (relative to repoDir)
59
- * the program should see and resolve against
60
- * @param extraShimPath - Optional project-relative extra `.d.ts` appended to
61
- * the built-in Firefox-globals shim (from `patchLint.checkJsExtraShim`)
62
- * @param projectRoot - Absolute project root for resolving `extraShimPath`
63
- * @param mode - Strictness preset plus allowlisted compiler-option overrides
64
- * @param builtinShimSuffix - Optional shim text appended AFTER the consumer
65
- * shim
66
- * @param rootScope - When set, only these repo-relative files become program
67
- * ROOTS; resolution (and the host allowlist) still spans all of
68
- * `resolutionOwned`, so a subset root's cross-patch imports type-check
69
- * against the real owning sources while unrelated owned files are never
70
- * parsed. `.mjs` files are module-scoped, so a root's diagnostics are
71
- * identical whether other owned files are roots or mere resolution targets.
88
+ * @param input - Program inputs; see {@link RunCheckJsGroupedInput}
72
89
  * @returns Diagnostics grouped per owning file plus run-level errors
73
90
  */
74
- export declare function runCheckJsGrouped(repoDir: string, resolutionOwned: Set<string>, extraShimPath?: string, projectRoot?: string, mode?: CheckJsMode, builtinShimSuffix?: string, rootScope?: ReadonlySet<string>): Promise<GroupedCheckJsResult>;
91
+ export declare function runCheckJsGrouped(input: RunCheckJsGroupedInput): Promise<GroupedCheckJsResult>;
75
92
  /**
76
93
  * Flattens a {@link runCheckJsGrouped} run into a single issue list. When
77
94
  * `reportScope` is supplied, only diagnostics from files in that set are
@@ -30,6 +30,7 @@ import { toError } from '../utils/errors.js';
30
30
  import { pathExists } from '../utils/fs.js';
31
31
  import { verbose } from '../utils/logger.js';
32
32
  import { normalizePathSlashes } from '../utils/paths.js';
33
+ import { collectUnmanagedCompanions, retargetUnmanagedCompanionHints, } from './patch-lint-unmanaged-companion.js';
33
34
  import { composeShimSource, SHIM_FILENAME, SUPPRESSED_DIAGNOSTIC_CODES, TEST_HARNESS_SHIM, UNDEFINED_IDENTIFIER_CODES, UNDEFINED_IDENTIFIER_HINT, } from './typecheck-shim.js';
34
35
  // ---------------------------------------------------------------------------
35
36
  // Public API
@@ -161,24 +162,11 @@ function createPathsResolver(ts, paths, baseDir, fileExists, onResolved) {
161
162
  * every file in `resolutionOwned`, so cross-patch `resource:///`/`chrome://`
162
163
  * imports resolve to real sources.
163
164
  *
164
- * @param repoDir - Absolute engine (repository) directory
165
- * @param resolutionOwned - Patch-owned `.sys.mjs` paths (relative to repoDir)
166
- * the program should see and resolve against
167
- * @param extraShimPath - Optional project-relative extra `.d.ts` appended to
168
- * the built-in Firefox-globals shim (from `patchLint.checkJsExtraShim`)
169
- * @param projectRoot - Absolute project root for resolving `extraShimPath`
170
- * @param mode - Strictness preset plus allowlisted compiler-option overrides
171
- * @param builtinShimSuffix - Optional shim text appended AFTER the consumer
172
- * shim
173
- * @param rootScope - When set, only these repo-relative files become program
174
- * ROOTS; resolution (and the host allowlist) still spans all of
175
- * `resolutionOwned`, so a subset root's cross-patch imports type-check
176
- * against the real owning sources while unrelated owned files are never
177
- * parsed. `.mjs` files are module-scoped, so a root's diagnostics are
178
- * identical whether other owned files are roots or mere resolution targets.
165
+ * @param input - Program inputs; see {@link RunCheckJsGroupedInput}
179
166
  * @returns Diagnostics grouped per owning file plus run-level errors
180
167
  */
181
- export async function runCheckJsGrouped(repoDir, resolutionOwned, extraShimPath, projectRoot, mode, builtinShimSuffix, rootScope) {
168
+ export async function runCheckJsGrouped(input) {
169
+ const { repoDir, resolutionOwned, extraShimPath, rootScope } = input;
182
170
  const empty = { byFile: new Map(), global: [] };
183
171
  if (resolutionOwned.size === 0)
184
172
  return empty;
@@ -226,12 +214,14 @@ export async function runCheckJsGrouped(repoDir, resolutionOwned, extraShimPath,
226
214
  // also undefined, so the resolution target is irrelevant.
227
215
  let shimSource;
228
216
  try {
229
- const composed = await composeShimSource(projectRoot ?? repoDir, extraShimPath);
217
+ const composed = await composeShimSource(input.projectRoot ?? repoDir, extraShimPath);
230
218
  // The suffix (e.g. the loose test-harness baseline) goes
231
219
  // AFTER the consumer's extra shim: TypeScript resolves conflicting
232
220
  // `declare var` redeclarations to the FIRST declaration, so a typed
233
221
  // consumer declaration must precede the loose fallback to win.
234
- shimSource = builtinShimSuffix ? `${composed.source}\n${builtinShimSuffix}` : composed.source;
222
+ shimSource = input.builtinShimSuffix
223
+ ? `${composed.source}\n${input.builtinShimSuffix}`
224
+ : composed.source;
235
225
  if (composed.extraShimAppended) {
236
226
  verbose(`checkJs: extra shim ${extraShimPath ?? ''} appended to Firefox globals shim`);
237
227
  }
@@ -251,7 +241,7 @@ export async function runCheckJsGrouped(repoDir, resolutionOwned, extraShimPath,
251
241
  }
252
242
  const shimPath = toTsPath(resolve(repoDir, SHIM_FILENAME));
253
243
  rootFiles.push(shimPath);
254
- const strict = mode?.strict === true;
244
+ const strict = input.mode?.strict === true;
255
245
  const strictness = strict
256
246
  ? { strict: true, noImplicitAny: true }
257
247
  : {
@@ -265,7 +255,7 @@ export async function runCheckJsGrouped(repoDir, resolutionOwned, extraShimPath,
265
255
  // sources without a hand-generated ambient stub shim.
266
256
  const overrides = {};
267
257
  let pathsMapping;
268
- const co = mode?.compilerOptions;
258
+ const co = input.mode?.compilerOptions;
269
259
  if (co) {
270
260
  for (const key of Object.keys(co)) {
271
261
  const v = co[key];
@@ -350,7 +340,7 @@ export async function runCheckJsGrouped(repoDir, resolutionOwned, extraShimPath,
350
340
  },
351
341
  };
352
342
  const program = ts.createProgram(rootFiles, options, host);
353
- const byFile = groupOwnedDiagnostics(ts, [...program.getSemanticDiagnostics(), ...program.getSyntacticDiagnostics()], relByAbsolute, mode?.undefinedIdentifiers ?? 'warning');
343
+ const byFile = groupOwnedDiagnostics(ts, [...program.getSemanticDiagnostics(), ...program.getSyntacticDiagnostics()], relByAbsolute, input.mode?.undefinedIdentifiers ?? 'warning');
354
344
  verbose(`checkJs: analyzed ${rootFiles.length - 1} file(s) across ${byFile.size} owning file(s)`);
355
345
  return { byFile, global: [] };
356
346
  }
@@ -416,7 +406,13 @@ function groupOwnedDiagnostics(ts, diagnostics, relByAbsolute, undefinedIdentifi
416
406
  * @returns Array of lint issues from TS diagnostics
417
407
  */
418
408
  export async function runCheckJs(repoDir, patchOwnedFiles, extraShimPath, projectRoot, mode, reportScope) {
419
- const { byFile, global } = await runCheckJsGrouped(repoDir, patchOwnedFiles, extraShimPath, projectRoot, mode);
409
+ const { byFile, global } = await runCheckJsGrouped({
410
+ repoDir,
411
+ resolutionOwned: patchOwnedFiles,
412
+ ...(extraShimPath !== undefined ? { extraShimPath } : {}),
413
+ ...(projectRoot !== undefined ? { projectRoot } : {}),
414
+ ...(mode !== undefined ? { mode } : {}),
415
+ });
420
416
  const issues = [...global];
421
417
  for (const [rel, list] of byFile) {
422
418
  if (reportScope && !reportScope.has(rel))
@@ -464,6 +460,7 @@ export async function runCheckJsTestFilesGrouped(repoDir, testFiles, patchLint,
464
460
  const mode = modeFromPatchLintConfig(patchLint);
465
461
  const seenGlobal = new Set();
466
462
  const files = [...testFiles].sort((a, b) => a.localeCompare(b));
463
+ const companions = await collectUnmanagedCompanions(repoDir, files, testFiles);
467
464
  for (const file of files) {
468
465
  // Under a rootScope only the scoped files get their own program, but
469
466
  // head.js helper discovery still spans the full owned set so a scoped
@@ -480,10 +477,22 @@ export async function runCheckJsTestFilesGrouped(repoDir, testFiles, patchLint,
480
477
  roots.add(candidate);
481
478
  }
482
479
  }
483
- const result = await runCheckJsGrouped(repoDir, roots, patchLint.checkJsTestShim, projectRoot, mode, TEST_HARNESS_SHIM);
480
+ const result = await runCheckJsGrouped({
481
+ repoDir,
482
+ resolutionOwned: roots,
483
+ ...(patchLint.checkJsTestShim !== undefined
484
+ ? { extraShimPath: patchLint.checkJsTestShim }
485
+ : {}),
486
+ projectRoot,
487
+ mode,
488
+ builtinShimSuffix: TEST_HARNESS_SHIM,
489
+ });
484
490
  const own = result.byFile.get(file);
485
491
  if (own && own.length > 0) {
486
- merged.byFile.set(file, [...(merged.byFile.get(file) ?? []), ...own]);
492
+ merged.byFile.set(file, [
493
+ ...(merged.byFile.get(file) ?? []),
494
+ ...retargetUnmanagedCompanionHints(own, companions),
495
+ ]);
487
496
  }
488
497
  for (const globalIssue of result.global) {
489
498
  if (seenGlobal.has(globalIssue.message))
@@ -522,7 +531,16 @@ function modeFromPatchLintConfig(patchLint) {
522
531
  * (`--patches`); resolution still spans the whole queue
523
532
  */
524
533
  export async function invokePatchLintCheckJsGrouped(repoDir, patchOwnedFiles, patchLint, projectRoot, rootScope) {
525
- return runCheckJsGrouped(repoDir, patchOwnedFiles, patchLint.checkJsExtraShim, projectRoot, modeFromPatchLintConfig(patchLint), undefined, rootScope);
534
+ return runCheckJsGrouped({
535
+ repoDir,
536
+ resolutionOwned: patchOwnedFiles,
537
+ ...(patchLint.checkJsExtraShim !== undefined
538
+ ? { extraShimPath: patchLint.checkJsExtraShim }
539
+ : {}),
540
+ projectRoot,
541
+ mode: modeFromPatchLintConfig(patchLint),
542
+ ...(rootScope !== undefined ? { rootScope } : {}),
543
+ });
526
544
  }
527
545
  /**
528
546
  * Cheap probe reproducing the only run-level ("global") checkJs findings the
@@ -10,13 +10,9 @@
10
10
  * so a discarded context frees its map; a caller that mutates a context
11
11
  * entry in place must call {@link invalidateNewFileCreatorsCache}.
12
12
  */
13
+ import type { PatchQueueBodyEntry, PatchQueueView } from './patch-lint-queue-types.js';
13
14
  /** The slice of a queue context the creators map is derived from. */
14
- interface CreatorsContext {
15
- entries: {
16
- filename: string;
17
- diff: string;
18
- }[];
19
- }
15
+ type CreatorsContext = PatchQueueView<PatchQueueBodyEntry>;
20
16
  /** Drops the memoised creators map after an in-place context entry update. */
21
17
  export declare function invalidateNewFileCreatorsCache(ctx: CreatorsContext): void;
22
18
  /**
@@ -34,6 +34,17 @@ export interface PatchQueueEntry {
34
34
  * are not indexed here.
35
35
  */
36
36
  newFiles: Map<string, string>;
37
+ /**
38
+ * Every path this patch CREATES, whatever the body kind — text, a
39
+ * reconstructable `GIT binary patch`, or a payload-less
40
+ * `Binary files … differ` stub. `newFiles` is text-only by design (a
41
+ * binary authors no imports, so the import rules gain nothing from it and
42
+ * `extractNewFileContent` correctly refuses to decode one), but "does a
43
+ * later patch create this path" is a question about existence after apply,
44
+ * not about content — and answering it from `newFiles` made every binary
45
+ * creation invisible to the staged-registration rules.
46
+ */
47
+ createdFiles: Set<string>;
37
48
  /**
38
49
  * Map from existing-file path → concatenated added lines from the patch's
39
50
  * hunks against that file (joined with `\n`). Populated for files the
@@ -109,13 +120,10 @@ export declare function isForwardImportableFile(path: string): boolean;
109
120
  * Returns the raw specifier strings — callers should take the leaf basename
110
121
  * to match against the newFileIndex, because we do not resolve `resource://`
111
122
  * URLs to engine file paths.
112
- */
113
- export declare function extractImportSpecifiers(source: string): string[];
114
- /**
115
- * Internal form of {@link extractImportSpecifiers} that also returns the
116
- * (0-indexed) line number where each specifier was found. Used by the
117
- * forward-import rule so it can correlate specifiers against the
118
- * ignore-marker line set and skip suppressed matches.
123
+ *
124
+ * Also returns the (0-indexed) line number where each specifier was found, so
125
+ * the forward-import rule can correlate specifiers against the ignore-marker
126
+ * line set and skip suppressed matches.
119
127
  */
120
128
  export interface ExtractedSpecifier {
121
129
  specifier: string;
@@ -123,7 +131,7 @@ export interface ExtractedSpecifier {
123
131
  }
124
132
  /**
125
133
  * Returns import specifiers plus 0-indexed line numbers, preserving the
126
- * same matching behavior as {@link extractImportSpecifiers}.
134
+ * same matching behavior as {@link extractImportSpecifiersWithLines}.
127
135
  */
128
136
  export declare function extractImportSpecifiersWithLines(source: string): ExtractedSpecifier[];
129
137
  /**