@hominis/fireforge 0.49.2 → 0.50.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 (334) hide show
  1. package/CHANGELOG.md +40 -1
  2. package/README.md +1 -1
  3. package/dist/bin/fireforge.js +6 -0
  4. package/dist/build-info.json +4 -4
  5. package/dist/src/commands/build-prelock.d.ts +20 -0
  6. package/dist/src/commands/build-prelock.js +50 -0
  7. package/dist/src/commands/build.d.ts +3 -1
  8. package/dist/src/commands/build.js +13 -6
  9. package/dist/src/commands/check-report.d.ts +28 -0
  10. package/dist/src/commands/check-report.js +78 -0
  11. package/dist/src/commands/check-run.d.ts +28 -0
  12. package/dist/src/commands/check-run.js +104 -0
  13. package/dist/src/commands/check-steps.d.ts +67 -0
  14. package/dist/src/commands/check-steps.js +175 -0
  15. package/dist/src/commands/check.d.ts +32 -0
  16. package/dist/src/commands/check.js +160 -0
  17. package/dist/src/commands/config.js +5 -6
  18. package/dist/src/commands/doctor-engine-eslint.js +6 -1
  19. package/dist/src/commands/doctor-source-pin.js +4 -1
  20. package/dist/src/commands/export-adopt-check.d.ts +38 -0
  21. package/dist/src/commands/export-adopt-check.js +98 -0
  22. package/dist/src/commands/export-flow.js +29 -14
  23. package/dist/src/commands/export-placement-gate.d.ts +6 -2
  24. package/dist/src/commands/export-shared.d.ts +2 -1
  25. package/dist/src/commands/export-staged-registration.d.ts +46 -0
  26. package/dist/src/commands/export-staged-registration.js +91 -0
  27. package/dist/src/commands/forward-import-remedy.d.ts +32 -0
  28. package/dist/src/commands/forward-import-remedy.js +63 -0
  29. package/dist/src/commands/furnace/apply.js +3 -3
  30. package/dist/src/commands/furnace/chrome-doc-remove.d.ts +2 -1
  31. package/dist/src/commands/furnace/chrome-doc-remove.js +2 -2
  32. package/dist/src/commands/furnace/chrome-doc.d.ts +2 -1
  33. package/dist/src/commands/furnace/chrome-doc.js +2 -2
  34. package/dist/src/commands/furnace/create.js +2 -2
  35. package/dist/src/commands/furnace/deploy-named.d.ts +48 -0
  36. package/dist/src/commands/furnace/deploy-named.js +107 -0
  37. package/dist/src/commands/furnace/deploy.d.ts +3 -2
  38. package/dist/src/commands/furnace/deploy.js +50 -86
  39. package/dist/src/commands/furnace/diff.js +26 -3
  40. package/dist/src/commands/furnace/index.js +66 -41
  41. package/dist/src/commands/furnace/init.js +13 -6
  42. package/dist/src/commands/furnace/override.js +4 -2
  43. package/dist/src/commands/furnace/preview.js +4 -3
  44. package/dist/src/commands/furnace/refresh.js +2 -2
  45. package/dist/src/commands/furnace/remove.js +4 -3
  46. package/dist/src/commands/furnace/rename-dry-run.d.ts +29 -0
  47. package/dist/src/commands/furnace/rename-dry-run.js +127 -0
  48. package/dist/src/commands/furnace/rename-helpers.d.ts +7 -0
  49. package/dist/src/commands/furnace/rename-helpers.js +15 -1
  50. package/dist/src/commands/furnace/rename-registrations.d.ts +41 -0
  51. package/dist/src/commands/furnace/rename-registrations.js +93 -0
  52. package/dist/src/commands/furnace/rename.d.ts +2 -1
  53. package/dist/src/commands/furnace/rename.js +28 -66
  54. package/dist/src/commands/furnace/scan.d.ts +9 -4
  55. package/dist/src/commands/furnace/scan.js +11 -9
  56. package/dist/src/commands/furnace/sync.js +3 -2
  57. package/dist/src/commands/furnace/validate-report.d.ts +45 -0
  58. package/dist/src/commands/furnace/validate-report.js +91 -0
  59. package/dist/src/commands/furnace/validate.d.ts +1 -1
  60. package/dist/src/commands/furnace/validate.js +127 -114
  61. package/dist/src/commands/furnace/validation-output.js +14 -3
  62. package/dist/src/commands/lint-per-patch.js +31 -60
  63. package/dist/src/commands/lint-report.d.ts +8 -4
  64. package/dist/src/commands/lint-report.js +15 -5
  65. package/dist/src/commands/lint.js +15 -34
  66. package/dist/src/commands/manifest.js +2 -0
  67. package/dist/src/commands/patch/delete-gap-notice.js +3 -1
  68. package/dist/src/commands/patch/delete.d.ts +1 -1
  69. package/dist/src/commands/patch/delete.js +13 -98
  70. package/dist/src/commands/patch/index.d.ts +1 -1
  71. package/dist/src/commands/patch/index.js +4 -2
  72. package/dist/src/commands/patch/lint-ignore.d.ts +5 -1
  73. package/dist/src/commands/patch/lint-ignore.js +65 -28
  74. package/dist/src/commands/patch/move-files-create.js +26 -17
  75. package/dist/src/commands/patch/move-files-into.js +5 -3
  76. package/dist/src/commands/patch/move-files.js +3 -1
  77. package/dist/src/commands/patch/removal-dependents.d.ts +63 -0
  78. package/dist/src/commands/patch/removal-dependents.js +133 -0
  79. package/dist/src/commands/patch/rename.js +7 -0
  80. package/dist/src/commands/patch/retire.d.ts +34 -0
  81. package/dist/src/commands/patch/retire.js +128 -0
  82. package/dist/src/commands/patch/split-plan.d.ts +7 -7
  83. package/dist/src/commands/patch/split-plan.js +45 -28
  84. package/dist/src/commands/patch/split-staged.d.ts +108 -0
  85. package/dist/src/commands/patch/split-staged.js +202 -0
  86. package/dist/src/commands/patch/split.d.ts +5 -0
  87. package/dist/src/commands/patch/split.js +51 -15
  88. package/dist/src/commands/patch/staged-dependency-batch.d.ts +48 -0
  89. package/dist/src/commands/patch/staged-dependency-batch.js +176 -0
  90. package/dist/src/commands/patch/staged-dependency-entries.d.ts +36 -0
  91. package/dist/src/commands/patch/staged-dependency-entries.js +52 -0
  92. package/dist/src/commands/patch/staged-dependency-from.d.ts +14 -0
  93. package/dist/src/commands/patch/staged-dependency-from.js +108 -0
  94. package/dist/src/commands/patch/staged-dependency.js +14 -41
  95. package/dist/src/commands/re-export-adjacent-registrations.d.ts +20 -0
  96. package/dist/src/commands/re-export-adjacent-registrations.js +75 -0
  97. package/dist/src/commands/re-export-adjacent.d.ts +45 -2
  98. package/dist/src/commands/re-export-adjacent.js +156 -37
  99. package/dist/src/commands/re-export-drift.d.ts +36 -8
  100. package/dist/src/commands/re-export-drift.js +73 -49
  101. package/dist/src/commands/re-export-files.js +11 -8
  102. package/dist/src/commands/re-export-lint.d.ts +2 -1
  103. package/dist/src/commands/re-export-lint.js +23 -10
  104. package/dist/src/commands/re-export-options.js +45 -4
  105. package/dist/src/commands/re-export-preflight.d.ts +23 -0
  106. package/dist/src/commands/re-export-preflight.js +160 -0
  107. package/dist/src/commands/re-export-register.js +42 -17
  108. package/dist/src/commands/re-export-removed.d.ts +12 -1
  109. package/dist/src/commands/re-export-removed.js +41 -11
  110. package/dist/src/commands/re-export-scan-owner.d.ts +44 -0
  111. package/dist/src/commands/re-export-scan-owner.js +116 -0
  112. package/dist/src/commands/re-export-scan.d.ts +17 -9
  113. package/dist/src/commands/re-export-scan.js +56 -23
  114. package/dist/src/commands/re-export-single.js +22 -6
  115. package/dist/src/commands/re-export-summary.d.ts +28 -0
  116. package/dist/src/commands/re-export-summary.js +36 -0
  117. package/dist/src/commands/re-export.js +37 -24
  118. package/dist/src/commands/rebase/index.js +17 -17
  119. package/dist/src/commands/run.js +16 -2
  120. package/dist/src/commands/status-check.d.ts +55 -16
  121. package/dist/src/commands/status-check.js +92 -37
  122. package/dist/src/commands/status-json.d.ts +22 -9
  123. package/dist/src/commands/status-json.js +47 -32
  124. package/dist/src/commands/status-output.js +3 -1
  125. package/dist/src/commands/status-scope.d.ts +37 -0
  126. package/dist/src/commands/status-scope.js +54 -0
  127. package/dist/src/commands/status.js +66 -23
  128. package/dist/src/commands/test-browser-preflight.js +19 -3
  129. package/dist/src/commands/test-build-furnace.d.ts +21 -0
  130. package/dist/src/commands/test-build-furnace.js +48 -0
  131. package/dist/src/commands/test-build-phase.js +47 -41
  132. package/dist/src/commands/test-checkjs.js +7 -0
  133. package/dist/src/commands/test-diagnose.js +7 -0
  134. package/dist/src/commands/test-modes.d.ts +16 -1
  135. package/dist/src/commands/test-modes.js +24 -1
  136. package/dist/src/commands/test-multi-verdict.d.ts +61 -0
  137. package/dist/src/commands/test-multi-verdict.js +111 -0
  138. package/dist/src/commands/test-orchestrate.d.ts +43 -0
  139. package/dist/src/commands/test-orchestrate.js +222 -0
  140. package/dist/src/commands/test-perf-scope.d.ts +29 -0
  141. package/dist/src/commands/test-perf-scope.js +83 -0
  142. package/dist/src/commands/test-prelock.d.ts +51 -0
  143. package/dist/src/commands/test-prelock.js +177 -0
  144. package/dist/src/commands/test-register.js +54 -10
  145. package/dist/src/commands/test-run.js +4 -1
  146. package/dist/src/commands/test-stale-gate.js +57 -27
  147. package/dist/src/commands/test-verdict.d.ts +10 -1
  148. package/dist/src/commands/test-verdict.js +28 -1
  149. package/dist/src/commands/test.d.ts +6 -1
  150. package/dist/src/commands/test.js +66 -60
  151. package/dist/src/commands/token-lint.d.ts +14 -0
  152. package/dist/src/commands/token-lint.js +111 -0
  153. package/dist/src/commands/token.js +10 -0
  154. package/dist/src/commands/verify-scope.d.ts +28 -0
  155. package/dist/src/commands/verify-scope.js +67 -0
  156. package/dist/src/commands/verify.d.ts +10 -2
  157. package/dist/src/commands/verify.js +59 -35
  158. package/dist/src/core/build-baseline-types.d.ts +46 -0
  159. package/dist/src/core/build-baseline-validate.js +19 -0
  160. package/dist/src/core/build-baseline.d.ts +5 -1
  161. package/dist/src/core/build-baseline.js +3 -1
  162. package/dist/src/core/build-overwrite-guard.d.ts +50 -0
  163. package/dist/src/core/build-overwrite-guard.js +84 -4
  164. package/dist/src/core/build-prepare.d.ts +7 -0
  165. package/dist/src/core/build-prepare.js +14 -8
  166. package/dist/src/core/build-run-record.d.ts +74 -0
  167. package/dist/src/core/build-run-record.js +136 -0
  168. package/dist/src/core/checkjs-support-heads.d.ts +41 -0
  169. package/dist/src/core/checkjs-support-heads.js +104 -0
  170. package/dist/src/core/config-paths.d.ts +2 -2
  171. package/dist/src/core/config-paths.js +8 -0
  172. package/dist/src/core/config-validate-check.d.ts +8 -0
  173. package/dist/src/core/config-validate-check.js +143 -0
  174. package/dist/src/core/config-validate-file-size.d.ts +9 -6
  175. package/dist/src/core/config-validate-file-size.js +91 -2
  176. package/dist/src/core/config-validate-history.d.ts +11 -0
  177. package/dist/src/core/config-validate-history.js +38 -0
  178. package/dist/src/core/config-validate-patch-policy.js +100 -0
  179. package/dist/src/core/config-validate-test-toolchains.js +7 -0
  180. package/dist/src/core/config-validate-token-scales.d.ts +6 -0
  181. package/dist/src/core/config-validate-token-scales.js +50 -0
  182. package/dist/src/core/config-validate.js +14 -5
  183. package/dist/src/core/config.d.ts +5 -0
  184. package/dist/src/core/config.js +16 -0
  185. package/dist/src/core/coverage-dispatch.d.ts +24 -0
  186. package/dist/src/core/coverage-dispatch.js +44 -0
  187. package/dist/src/core/coverage-extend.d.ts +70 -45
  188. package/dist/src/core/coverage-extend.js +199 -144
  189. package/dist/src/core/coverage-records.d.ts +97 -0
  190. package/dist/src/core/coverage-records.js +350 -0
  191. package/dist/src/core/destructive.d.ts +7 -4
  192. package/dist/src/core/destructive.js +10 -10
  193. package/dist/src/core/engine-session-lock.d.ts +10 -1
  194. package/dist/src/core/engine-session-lock.js +28 -8
  195. package/dist/src/core/export-moved-code-shape.d.ts +49 -11
  196. package/dist/src/core/export-moved-code-shape.js +135 -44
  197. package/dist/src/core/file-lock-queue.d.ts +67 -0
  198. package/dist/src/core/file-lock-queue.js +221 -0
  199. package/dist/src/core/file-lock.d.ts +4 -25
  200. package/dist/src/core/file-lock.js +105 -138
  201. package/dist/src/core/furnace-apply-output.d.ts +10 -0
  202. package/dist/src/core/furnace-apply-output.js +31 -1
  203. package/dist/src/core/furnace-apply.js +12 -2
  204. package/dist/src/core/furnace-composed-source.d.ts +76 -0
  205. package/dist/src/core/furnace-composed-source.js +167 -0
  206. package/dist/src/core/furnace-config-validate-exceptions.d.ts +9 -0
  207. package/dist/src/core/furnace-config-validate-exceptions.js +71 -0
  208. package/dist/src/core/furnace-config-validate.js +8 -0
  209. package/dist/src/core/furnace-css-fragments.d.ts +10 -0
  210. package/dist/src/core/furnace-css-fragments.js +26 -0
  211. package/dist/src/core/furnace-operation.d.ts +3 -3
  212. package/dist/src/core/furnace-registration-remove.d.ts +22 -1
  213. package/dist/src/core/furnace-registration-remove.js +53 -17
  214. package/dist/src/core/furnace-registration-rename.d.ts +26 -0
  215. package/dist/src/core/furnace-registration-rename.js +77 -0
  216. package/dist/src/core/furnace-registration.d.ts +14 -4
  217. package/dist/src/core/furnace-registration.js +44 -10
  218. package/dist/src/core/furnace-staleness.d.ts +7 -0
  219. package/dist/src/core/furnace-staleness.js +34 -24
  220. package/dist/src/core/furnace-validate-accessibility.d.ts +4 -2
  221. package/dist/src/core/furnace-validate-accessibility.js +10 -1
  222. package/dist/src/core/furnace-validate-exceptions.d.ts +40 -0
  223. package/dist/src/core/furnace-validate-exceptions.js +43 -0
  224. package/dist/src/core/furnace-validate-icon-button.d.ts +7 -0
  225. package/dist/src/core/furnace-validate-icon-button.js +49 -0
  226. package/dist/src/core/furnace-validate.js +1 -1
  227. package/dist/src/core/harness-port-fallback.d.ts +60 -0
  228. package/dist/src/core/harness-port-fallback.js +96 -0
  229. package/dist/src/core/history-log-file.d.ts +61 -0
  230. package/dist/src/core/history-log-file.js +157 -0
  231. package/dist/src/core/history-log.d.ts +2 -1
  232. package/dist/src/core/history-log.js +2 -1
  233. package/dist/src/core/json-preserving-edit.d.ts +22 -0
  234. package/dist/src/core/json-preserving-edit.js +199 -0
  235. package/dist/src/core/mach.js +8 -1
  236. package/dist/src/core/negative-control-diff.d.ts +39 -0
  237. package/dist/src/core/negative-control-diff.js +136 -0
  238. package/dist/src/core/negative-control.d.ts +138 -0
  239. package/dist/src/core/negative-control.js +356 -0
  240. package/dist/src/core/objdir-install-manifests.d.ts +73 -0
  241. package/dist/src/core/objdir-install-manifests.js +226 -0
  242. package/dist/src/core/patch-export-update.d.ts +2 -0
  243. package/dist/src/core/patch-export-update.js +1 -0
  244. package/dist/src/core/patch-export.js +3 -4
  245. package/dist/src/core/patch-lint-checkjs-any-import.d.ts +37 -0
  246. package/dist/src/core/patch-lint-checkjs-any-import.js +61 -0
  247. package/dist/src/core/patch-lint-checkjs.js +8 -11
  248. package/dist/src/core/patch-lint-code-lines.d.ts +59 -0
  249. package/dist/src/core/patch-lint-code-lines.js +105 -0
  250. package/dist/src/core/patch-lint-cross.js +12 -4
  251. package/dist/src/core/patch-lint-css.d.ts +8 -2
  252. package/dist/src/core/patch-lint-css.js +10 -4
  253. package/dist/src/core/patch-lint-file-size.d.ts +12 -5
  254. package/dist/src/core/patch-lint-file-size.js +22 -11
  255. package/dist/src/core/patch-lint-forward-registration-extended.d.ts +18 -0
  256. package/dist/src/core/patch-lint-forward-registration-extended.js +35 -10
  257. package/dist/src/core/patch-lint-forward-registration.js +10 -0
  258. package/dist/src/core/patch-lint-ignore.d.ts +152 -0
  259. package/dist/src/core/patch-lint-ignore.js +299 -0
  260. package/dist/src/core/patch-lint-size-thresholds.d.ts +52 -0
  261. package/dist/src/core/patch-lint-size-thresholds.js +110 -0
  262. package/dist/src/core/patch-lint-size.d.ts +117 -0
  263. package/dist/src/core/patch-lint-size.js +323 -0
  264. package/dist/src/core/patch-lint-staged-registration.d.ts +18 -1
  265. package/dist/src/core/patch-lint-staged-registration.js +20 -0
  266. package/dist/src/core/patch-lint-token-scale.d.ts +39 -0
  267. package/dist/src/core/patch-lint-token-scale.js +109 -0
  268. package/dist/src/core/patch-lint.d.ts +11 -83
  269. package/dist/src/core/patch-lint.js +64 -286
  270. package/dist/src/core/patch-lock.js +7 -6
  271. package/dist/src/core/patch-manifest-consistency.js +7 -6
  272. package/dist/src/core/patch-manifest-io.d.ts +6 -3
  273. package/dist/src/core/patch-manifest-io.js +19 -8
  274. package/dist/src/core/patch-manifest-validate.js +34 -2
  275. package/dist/src/core/patch-order-legal.d.ts +25 -0
  276. package/dist/src/core/patch-order-legal.js +83 -0
  277. package/dist/src/core/patch-policy-content.d.ts +40 -0
  278. package/dist/src/core/patch-policy-content.js +216 -0
  279. package/dist/src/core/patch-policy.d.ts +16 -3
  280. package/dist/src/core/patch-policy.js +16 -9
  281. package/dist/src/core/patch-retired.d.ts +35 -0
  282. package/dist/src/core/patch-retired.js +54 -0
  283. package/dist/src/core/patch-subset.d.ts +16 -0
  284. package/dist/src/core/patch-subset.js +66 -0
  285. package/dist/src/core/preflight-wait.d.ts +20 -0
  286. package/dist/src/core/preflight-wait.js +38 -0
  287. package/dist/src/core/rebase-from-version.d.ts +46 -0
  288. package/dist/src/core/rebase-from-version.js +71 -0
  289. package/dist/src/core/run-log.d.ts +20 -0
  290. package/dist/src/core/run-log.js +89 -3
  291. package/dist/src/core/run-profile.d.ts +7 -0
  292. package/dist/src/core/run-profile.js +7 -1
  293. package/dist/src/core/smoke-patterns.d.ts +5 -0
  294. package/dist/src/core/smoke-patterns.js +13 -0
  295. package/dist/src/core/test-harness-crash.d.ts +18 -1
  296. package/dist/src/core/test-harness-crash.js +6 -4
  297. package/dist/src/core/test-harness-signature.d.ts +17 -0
  298. package/dist/src/core/test-harness-signature.js +4 -0
  299. package/dist/src/core/test-run-completeness.d.ts +57 -0
  300. package/dist/src/core/test-run-completeness.js +144 -0
  301. package/dist/src/core/test-stale-check.d.ts +27 -1
  302. package/dist/src/core/test-stale-check.js +39 -49
  303. package/dist/src/core/test-stale-exempt.d.ts +40 -0
  304. package/dist/src/core/test-stale-exempt.js +70 -0
  305. package/dist/src/core/token-lint.d.ts +50 -0
  306. package/dist/src/core/token-lint.js +126 -0
  307. package/dist/src/core/tree-guard.js +3 -0
  308. package/dist/src/core/typecheck-shim.d.ts +1 -1
  309. package/dist/src/core/typecheck-shim.js +90 -2
  310. package/dist/src/index.d.ts +8 -3
  311. package/dist/src/index.js +3 -1
  312. package/dist/src/types/commands/index.d.ts +2 -2
  313. package/dist/src/types/commands/options.d.ts +148 -21
  314. package/dist/src/types/commands/patches.d.ts +75 -1
  315. package/dist/src/types/config.d.ts +192 -0
  316. package/dist/src/types/config.js +9 -0
  317. package/dist/src/types/furnace.d.ts +43 -1
  318. package/dist/src/types/furnace.js +7 -0
  319. package/dist/src/types/index.d.ts +1 -1
  320. package/dist/src/utils/options.d.ts +34 -6
  321. package/dist/src/utils/options.js +86 -5
  322. package/dist/src/utils/path-glob.d.ts +15 -0
  323. package/dist/src/utils/path-glob.js +47 -0
  324. package/dist/src/utils/regex.d.ts +15 -3
  325. package/dist/src/utils/regex.js +37 -16
  326. package/docs/configuration.md +282 -9
  327. package/docs/exit-codes.md +18 -1
  328. package/docs/furnace.md +97 -3
  329. package/docs/lifecycle-invariants.md +52 -19
  330. package/docs/machine-output.md +74 -12
  331. package/docs/patch-workflow.md +297 -22
  332. package/docs/run-logs.md +20 -1
  333. package/docs/testing.md +276 -20
  334. package/package.json +1 -1
@@ -8,6 +8,7 @@ import { findAllPatchesForFilesWithDetails, } from './patch-export-coverage.js';
8
8
  import { addPatchToManifest, loadPatchesManifestForWrite, PATCHES_MANIFEST, savePatchesManifest, } from './patch-manifest.js';
9
9
  import { formatPatchOrder, requirePatchOrder } from './patch-parse.js';
10
10
  import { allocatePolicyOrder, enforcePatchPolicy } from './patch-policy.js';
11
+ import { manifestWithRetiredSlots } from './patch-retired.js';
11
12
  export { findAllPatchesForFiles, findAllPatchesForFilesWithDetails, } from './patch-export-coverage.js';
12
13
  import { escapeRegex } from '../utils/regex.js';
13
14
  export { mutatePatchMetadata, updatePatchMetadata } from './patch-export-metadata.js';
@@ -273,10 +274,8 @@ async function computeExportPlanUnderLock(input) {
273
274
  supersededDetails,
274
275
  supersededPatches,
275
276
  manifestBefore: manifestBefore ?? null,
276
- manifestAfter: {
277
- version: 1,
278
- patches: afterPatches,
279
- },
277
+ // A patch landing on a retired order fills that slot.
278
+ manifestAfter: manifestWithRetiredSlots(manifestBefore, afterPatches),
280
279
  };
281
280
  }
282
281
  /**
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Explains an implicit-`any` checkJs finding that comes from a URL import
3
+ * the per-patch program cannot resolve.
4
+ *
5
+ * The program only holds patch-owned files (and, for a test, its own
6
+ * directory's head.js), so a `resource:///` or `chrome://` import of a
7
+ * module another patch creates falls back to the shim's
8
+ * `declare module 'resource:*'` wildcard and types as `any`. A callback
9
+ * over its values then has implicitly-`any` parameters under
10
+ * `checkJsStrict`, while the whole-tree `fireforge typecheck`, which sees
11
+ * the module, is clean. Without the note the two disagree with no
12
+ * explanation. Split out of patch-lint-checkjs.ts for the line budget.
13
+ */
14
+ /** Unresolved URL import specifiers, keyed by the importing file's TS path. */
15
+ export type AnyTypedImports = Map<string, Set<string>>;
16
+ /**
17
+ * The note an implicit-`any` finding carries when its file imports a
18
+ * `resource://`/`chrome://` module this checkJs program could not resolve.
19
+ * Such an import types as `any` (the shim's wildcard module), so a
20
+ * callback over its values has implicitly-`any` parameters here while the
21
+ * whole-tree `fireforge typecheck`, which sees the module, is clean.
22
+ */
23
+ export declare function anyTypedImportHint(code: number, specifiers: ReadonlySet<string> | undefined): string;
24
+ /**
25
+ * The host's `resolveModuleNameLiterals`: owned specifiers first, then a
26
+ * reviewed `paths` mapping, recording every URL import that resolves to
27
+ * neither.
28
+ *
29
+ * @param resolveOwned - Patch-owned specifier resolver
30
+ * @param resolveViaPaths - Optional `paths` resolver
31
+ * @param into - Map that collects the unresolved URL imports
32
+ */
33
+ export declare function createModuleLiteralResolver<Resolved>(resolveOwned: (specifier: string) => Resolved | undefined, resolveViaPaths: ((specifier: string) => Resolved | undefined) | undefined, into: AnyTypedImports): (moduleLiterals: readonly {
34
+ text: string;
35
+ }[], containingFile: string) => Array<{
36
+ resolvedModule: Resolved | undefined;
37
+ }>;
@@ -0,0 +1,61 @@
1
+ // SPDX-License-Identifier: EUPL-1.2
2
+ /**
3
+ * Explains an implicit-`any` checkJs finding that comes from a URL import
4
+ * the per-patch program cannot resolve.
5
+ *
6
+ * The program only holds patch-owned files (and, for a test, its own
7
+ * directory's head.js), so a `resource:///` or `chrome://` import of a
8
+ * module another patch creates falls back to the shim's
9
+ * `declare module 'resource:*'` wildcard and types as `any`. A callback
10
+ * over its values then has implicitly-`any` parameters under
11
+ * `checkJsStrict`, while the whole-tree `fireforge typecheck`, which sees
12
+ * the module, is clean. Without the note the two disagree with no
13
+ * explanation. Split out of patch-lint-checkjs.ts for the line budget.
14
+ */
15
+ /** TypeScript's implicit-`any` diagnostic codes (noImplicitAny). */
16
+ const IMPLICIT_ANY_CODES = new Set([
17
+ 7005, 7006, 7008, 7010, 7011, 7019, 7031, 7034,
18
+ ]);
19
+ function recordAnyTypedImport(into, containingFile, specifier) {
20
+ if (!/^(?:resource|chrome):/.test(specifier))
21
+ return;
22
+ const list = into.get(containingFile) ?? new Set();
23
+ list.add(specifier);
24
+ into.set(containingFile, list);
25
+ }
26
+ /**
27
+ * The note an implicit-`any` finding carries when its file imports a
28
+ * `resource://`/`chrome://` module this checkJs program could not resolve.
29
+ * Such an import types as `any` (the shim's wildcard module), so a
30
+ * callback over its values has implicitly-`any` parameters here while the
31
+ * whole-tree `fireforge typecheck`, which sees the module, is clean.
32
+ */
33
+ export function anyTypedImportHint(code, specifiers) {
34
+ if (!IMPLICIT_ANY_CODES.has(code) || specifiers === undefined || specifiers.size === 0)
35
+ return '';
36
+ const list = [...specifiers].sort().join(', ');
37
+ return (` (This file imports ${list}, which this per-patch checkJs program cannot resolve — ` +
38
+ 'the module is created by another patch outside this program, a later one or one this ' +
39
+ 'test does not share a directory with — so the import is typed `any`. Annotate the ' +
40
+ 'parameter explicitly; the whole-tree "fireforge typecheck" resolves the real type.)');
41
+ }
42
+ /**
43
+ * The host's `resolveModuleNameLiterals`: owned specifiers first, then a
44
+ * reviewed `paths` mapping, recording every URL import that resolves to
45
+ * neither.
46
+ *
47
+ * @param resolveOwned - Patch-owned specifier resolver
48
+ * @param resolveViaPaths - Optional `paths` resolver
49
+ * @param into - Map that collects the unresolved URL imports
50
+ */
51
+ export function createModuleLiteralResolver(resolveOwned, resolveViaPaths, into) {
52
+ return (moduleLiterals, containingFile) => moduleLiterals.map((literal) => {
53
+ const owned = resolveOwned(literal.text);
54
+ if (owned)
55
+ return { resolvedModule: owned };
56
+ const viaPaths = resolveViaPaths?.(literal.text);
57
+ if (viaPaths === undefined)
58
+ recordAnyTypedImport(into, containingFile, literal.text);
59
+ return { resolvedModule: viaPaths };
60
+ });
61
+ }
@@ -31,6 +31,7 @@ import { pathExists } from '../utils/fs.js';
31
31
  import { verbose } from '../utils/logger.js';
32
32
  import { normalizePathSlashes } from '../utils/paths.js';
33
33
  import { withGeckoDomTypes } from './gecko-dom-types.js';
34
+ import { anyTypedImportHint, createModuleLiteralResolver, } from './patch-lint-checkjs-any-import.js';
34
35
  import { withSharedSourceFiles } from './patch-lint-checkjs-cache.js';
35
36
  import { collectUnmanagedCompanions, retargetUnmanagedCompanionHints, } from './patch-lint-unmanaged-companion.js';
36
37
  import { composeShimSource, SHIM_FILENAME, SUPPRESSED_DIAGNOSTIC_CODES, TEST_HARNESS_SHIM, UNDEFINED_IDENTIFIER_CODES, UNDEFINED_IDENTIFIER_HINT, } from './typecheck-shim.js';
@@ -293,6 +294,9 @@ export async function runCheckJsGrouped(input) {
293
294
  ...overrides,
294
295
  };
295
296
  const resolveOwnedSpecifier = createOwnedSpecifierResolver(ts, ownedAbsolute);
297
+ // URL imports this program cannot resolve, per importing file (see
298
+ // patch-lint-checkjs-any-import.ts).
299
+ const anyTypedImports = new Map();
296
300
  // Custom compiler host: reads patch-owned files from disk, returns
297
301
  // the shim for the shim path, and returns empty content for
298
302
  // anything else to avoid reading the full Firefox tree.
@@ -333,17 +337,10 @@ export async function runCheckJsGrouped(input) {
333
337
  return shimSource;
334
338
  return defaultHost.readFile(fileName);
335
339
  },
336
- resolveModuleNameLiterals(moduleLiterals) {
337
- return moduleLiterals.map((literal) => {
338
- const owned = resolveOwnedSpecifier(literal.text);
339
- if (owned)
340
- return { resolvedModule: owned };
341
- return { resolvedModule: resolveViaPaths?.(literal.text) };
342
- });
343
- },
340
+ resolveModuleNameLiterals: createModuleLiteralResolver(resolveOwnedSpecifier, resolveViaPaths, anyTypedImports),
344
341
  };
345
342
  const program = ts.createProgram(rootFiles, options, withSharedSourceFiles(host, input.sourceFileCache, shimPath, shimSource));
346
- const byFile = groupOwnedDiagnostics(ts, [...program.getSemanticDiagnostics(), ...program.getSyntacticDiagnostics()], relByAbsolute, input.mode?.undefinedIdentifiers ?? 'warning');
343
+ const byFile = groupOwnedDiagnostics(ts, [...program.getSemanticDiagnostics(), ...program.getSyntacticDiagnostics()], relByAbsolute, input.mode?.undefinedIdentifiers ?? 'warning', anyTypedImports);
347
344
  verbose(`checkJs: analyzed ${rootFiles.length - 1} file(s) across ${byFile.size} owning file(s)`);
348
345
  return { byFile, global: [] };
349
346
  }
@@ -354,7 +351,7 @@ export async function runCheckJsGrouped(input) {
354
351
  * or shim files are dropped. Only owned files (in `relByAbsolute`) carry
355
352
  * findings.
356
353
  */
357
- function groupOwnedDiagnostics(ts, diagnostics, relByAbsolute, undefinedIdentifiers = 'warning') {
354
+ function groupOwnedDiagnostics(ts, diagnostics, relByAbsolute, undefinedIdentifiers = 'warning', anyTypedImports = new Map()) {
358
355
  const byFile = new Map();
359
356
  for (const diag of diagnostics) {
360
357
  if (SUPPRESSED_DIAGNOSTIC_CODES.has(diag.code))
@@ -386,7 +383,7 @@ function groupOwnedDiagnostics(ts, diagnostics, relByAbsolute, undefinedIdentifi
386
383
  check: 'checkjs-type-error',
387
384
  message: isUndefinedIdentifier
388
385
  ? `Line ${line}: ${messageText} ${UNDEFINED_IDENTIFIER_HINT}`
389
- : `Line ${line}: ${messageText}`,
386
+ : `Line ${line}: ${messageText}${anyTypedImportHint(diag.code, anyTypedImports.get(sourceFile.fileName))}`,
390
387
  severity,
391
388
  });
392
389
  byFile.set(relPath, bucket);
@@ -0,0 +1,59 @@
1
+ /**
2
+ * Line counting for the size rules: raw lines, code lines, and the per-line
3
+ * code mask the `addedCode` patch-size metric reads off a file's
4
+ * post-image.
5
+ *
6
+ * "Code" means a line left non-blank once comments are blanked. JS goes
7
+ * through acorn's tokenizer (`stripJsCommentsParsed`), so a regex literal
8
+ * containing `/*`, a string containing `//`, nested template literals,
9
+ * JSDoc and a shebang are all judged correctly, and a blank line inside a
10
+ * template literal counts as blank.
11
+ */
12
+ /**
13
+ * Counts the lines of `content` the way `wc -l` reports them. A naive
14
+ * `split('\n').length` over-counts by one for any content ending in `\n`
15
+ * (the common case), making the size rules fire one line early against
16
+ * the operator's own `wc -l` measurement.
17
+ */
18
+ export declare function countRawLines(content: string): number;
19
+ /** The result of {@link countCodeLines}. */
20
+ export interface CodeLineCount {
21
+ /**
22
+ * Lines that carry code: non-blank once comments are blanked. When the
23
+ * source could not be tokenized this is the raw line count instead, the
24
+ * upper bound, so an unparsable file never measures smaller than it is.
25
+ */
26
+ lines: number;
27
+ /** False when acorn could tokenize the source neither as a module nor as a script. */
28
+ parsed: boolean;
29
+ }
30
+ /**
31
+ * Counts the code lines of a JS source: comments are blanked by acorn's
32
+ * tokenizer (module goal first, then script, since chrome subscripts are
33
+ * scripts) and the non-blank lines are counted. When neither goal
34
+ * tokenizes, the raw line count is returned with `parsed: false`. A regex
35
+ * fallback would under-count, which fails open.
36
+ *
37
+ * @param content - JS source text
38
+ */
39
+ export declare function countCodeLines(content: string): CodeLineCount;
40
+ /** The per-line code mask of one post-image. */
41
+ export interface CodeLineMask {
42
+ /** `code[i]` is true when line `i + 1` carries code. */
43
+ code: boolean[];
44
+ /** False for a JS file acorn could not tokenize; every non-blank line then counts. */
45
+ parsed: boolean;
46
+ }
47
+ /**
48
+ * Classifies every line of a file's post-image as code or not, by file
49
+ * kind: JS through acorn, CSS block comments, `<!-- -->` in markup, and
50
+ * whole-line `#` comments (`;` for `.ini`/`.in`, `!` for `.properties`) in
51
+ * Fluent, manifests, `moz.build` and similar. Any other file counts every
52
+ * non-blank line. In CSS, lines inside a Furnace fragment expansion
53
+ * (`@fireforge-include` … `@fireforge-end-include`) are not code of this
54
+ * file: they are a copy of a shared fragment.
55
+ *
56
+ * @param file - Engine-relative path, used only to pick the file kind
57
+ * @param content - The post-image text
58
+ */
59
+ export declare function codeLineMask(file: string, content: string): CodeLineMask;
@@ -0,0 +1,105 @@
1
+ // SPDX-License-Identifier: EUPL-1.2
2
+ /**
3
+ * Line counting for the size rules: raw lines, code lines, and the per-line
4
+ * code mask the `addedCode` patch-size metric reads off a file's
5
+ * post-image.
6
+ *
7
+ * "Code" means a line left non-blank once comments are blanked. JS goes
8
+ * through acorn's tokenizer (`stripJsCommentsParsed`), so a regex literal
9
+ * containing `/*`, a string containing `//`, nested template literals,
10
+ * JSDoc and a shebang are all judged correctly, and a blank line inside a
11
+ * template literal counts as blank.
12
+ */
13
+ import { stripJsCommentsParsed } from '../utils/regex.js';
14
+ import { expandedFragmentLineMask } from './furnace-css-fragments.js';
15
+ import { maskCssComments } from './patch-lint-css.js';
16
+ /**
17
+ * Splits content into lines the way `wc -l` reports them: a trailing
18
+ * newline terminates the last line rather than starting an empty extra one.
19
+ */
20
+ function splitContentLines(content) {
21
+ const lines = content.split('\n');
22
+ if (lines[lines.length - 1] === '')
23
+ lines.pop();
24
+ return lines;
25
+ }
26
+ /**
27
+ * Counts the lines of `content` the way `wc -l` reports them. A naive
28
+ * `split('\n').length` over-counts by one for any content ending in `\n`
29
+ * (the common case), making the size rules fire one line early against
30
+ * the operator's own `wc -l` measurement.
31
+ */
32
+ export function countRawLines(content) {
33
+ return splitContentLines(content).length;
34
+ }
35
+ const isBlank = (line) => line.trim() === '';
36
+ /**
37
+ * Counts the code lines of a JS source: comments are blanked by acorn's
38
+ * tokenizer (module goal first, then script, since chrome subscripts are
39
+ * scripts) and the non-blank lines are counted. When neither goal
40
+ * tokenizes, the raw line count is returned with `parsed: false`. A regex
41
+ * fallback would under-count, which fails open.
42
+ *
43
+ * @param content - JS source text
44
+ */
45
+ export function countCodeLines(content) {
46
+ const stripped = stripJsCommentsParsed(content);
47
+ if (stripped === null)
48
+ return { lines: countRawLines(content), parsed: false };
49
+ return {
50
+ lines: splitContentLines(stripped).filter((line) => !isBlank(line)).length,
51
+ parsed: true,
52
+ };
53
+ }
54
+ const JS_FILE = /\.(?:m?js|jsm|cjs)$/;
55
+ const MARKUP_FILE = /\.(?:x?html|xml|svg|xul|dtd)$/;
56
+ const HASH_COMMENT_FILE = /(?:\.(?:ftl|properties|toml|ini|mn|build|py|conf|configure|sh|ya?ml|in|cfg|mozbuild)|(?:^|\/)(?:Makefile|mozconfig))$/;
57
+ /** Line-comment leaders per hash-comment file kind. */
58
+ function lineCommentPattern(file) {
59
+ if (/\.(?:ini|in)$/.test(file))
60
+ return /^\s*[#;]/;
61
+ if (file.endsWith('.properties'))
62
+ return /^\s*[#!]/;
63
+ return /^\s*#/;
64
+ }
65
+ /** Masks `<!-- … -->` comments, keeping newlines. Unclosed comments run to EOF. */
66
+ function maskMarkupComments(source) {
67
+ return source.replace(/<!--[\s\S]*?(?:-->|$)/g, (m) => m.replace(/[^\n]/g, ' '));
68
+ }
69
+ /**
70
+ * Classifies every line of a file's post-image as code or not, by file
71
+ * kind: JS through acorn, CSS block comments, `<!-- -->` in markup, and
72
+ * whole-line `#` comments (`;` for `.ini`/`.in`, `!` for `.properties`) in
73
+ * Fluent, manifests, `moz.build` and similar. Any other file counts every
74
+ * non-blank line. In CSS, lines inside a Furnace fragment expansion
75
+ * (`@fireforge-include` … `@fireforge-end-include`) are not code of this
76
+ * file: they are a copy of a shared fragment.
77
+ *
78
+ * @param file - Engine-relative path, used only to pick the file kind
79
+ * @param content - The post-image text
80
+ */
81
+ export function codeLineMask(file, content) {
82
+ if (JS_FILE.test(file)) {
83
+ const stripped = stripJsCommentsParsed(content);
84
+ const source = stripped ?? content;
85
+ return { code: source.split('\n').map((line) => !isBlank(line)), parsed: stripped !== null };
86
+ }
87
+ if (file.endsWith('.css')) {
88
+ const inFragment = expandedFragmentLineMask(content);
89
+ const code = maskCssComments(content)
90
+ .split('\n')
91
+ .map((line, i) => !isBlank(line) && inFragment[i] !== true);
92
+ return { code, parsed: true };
93
+ }
94
+ if (MARKUP_FILE.test(file)) {
95
+ return {
96
+ code: maskMarkupComments(content)
97
+ .split('\n')
98
+ .map((l) => !isBlank(l)),
99
+ parsed: true,
100
+ };
101
+ }
102
+ const comment = HASH_COMMENT_FILE.test(file) ? lineCommentPattern(file) : undefined;
103
+ const code = content.split('\n').map((line) => !isBlank(line) && !comment?.test(line));
104
+ return { code, parsed: true };
105
+ }
@@ -20,7 +20,7 @@ import { collectNewFileCreatorsByPath } from './patch-lint-creators.js';
20
20
  import { detectNewFilesInDiff, extractAddedLinesPerFile } from './patch-lint-diff.js';
21
21
  import { lintPatchQueueForwardRegistrations } from './patch-lint-forward-registration.js';
22
22
  import { lintPatchQueueModuleRegistrations } from './patch-lint-module-registration.js';
23
- import { describeRegistrationFailure, findStagedRegistrationFailure, isLaterOwner, quoteRegistrationLine, } from './patch-lint-staged-registration.js';
23
+ import { describeRegistrationFailure, findStagedRegistrationFailure, isLaterOwner, quoteRegistrationLine, STAGED_DEPENDENCY_REASON_PLACEHOLDER, stagedDependencyUnusedFingerprint, } from './patch-lint-staged-registration.js';
24
24
  import { loadPatchesManifest } from './patch-manifest-io.js';
25
25
  import { categoryRangeForOrder, categoryRangeLabel } from './patch-policy.js';
26
26
  import { extractNewFileContentsFromDiff } from './patch-transform.js';
@@ -493,13 +493,21 @@ export function lintPatchQueueForwardImports(ctx) {
493
493
  const stagedCommands = laterOwners
494
494
  .map((o) => `fireforge patch staged-dependency ${entry.filename} --add ` +
495
495
  `--file ${sitePath} --specifier "${specifier}" ` +
496
- `--creates ${o.fullPath} --owner ${o.filename}`)
496
+ `--creates ${o.fullPath} --owner ${o.filename} ${STAGED_DEPENDENCY_REASON_PLACEHOLDER}`)
497
497
  .join('; ');
498
498
  issues.push({
499
499
  file: sitePath,
500
500
  check: 'forward-import',
501
501
  patches: [entry.filename],
502
502
  fingerprint: `forward-import|${sitePath}|${cleaned}|${fingerprintOwners}`,
503
+ stagedDeclarations: laterOwners.map((o) => ({
504
+ patch: entry.filename,
505
+ kind: 'import',
506
+ file: sitePath,
507
+ specifier,
508
+ creates: o.fullPath,
509
+ owner: o.filename,
510
+ })),
503
511
  message: `${sitePath} in ${entry.filename} imports "${specifier}", ` +
504
512
  `but the matching new file is created by a later patch: ${ownersSummary}. ` +
505
513
  'Reorder the patches so the dependency is created first, move the import ' +
@@ -518,7 +526,7 @@ export function lintPatchQueueForwardImports(ctx) {
518
526
  file: dependency.file,
519
527
  check: 'staged-dependency-unused',
520
528
  patches: [entry.filename],
521
- fingerprint: `staged-dependency-unused|${entry.filename}|${dependency.file}|${dependency.specifier}|${dependency.creates}|${dependency.owner ?? ''}`,
529
+ fingerprint: stagedDependencyUnusedFingerprint(entry.filename, dependency),
522
530
  message: `${entry.filename} declares a staged forward import from ${dependency.file} ` +
523
531
  `to "${dependency.specifier}" / ${dependency.creates}, but that exact forward dependency was not found. ` +
524
532
  'Remove the stale declaration with "fireforge patch staged-dependency --remove" or update it to match the current queue.',
@@ -541,7 +549,7 @@ export function lintPatchQueueForwardImports(ctx) {
541
549
  file: registration.file,
542
550
  check: 'staged-dependency-unused',
543
551
  patches: [entry.filename],
544
- fingerprint: `staged-dependency-unused|${entry.filename}|${registration.file}|reg:${registration.line}|${registration.creates}|${registration.owner ?? ''}`,
552
+ fingerprint: stagedDependencyUnusedFingerprint(entry.filename, registration),
545
553
  message: `${entry.filename} declares a staged registration in ${registration.file} ` +
546
554
  `("${registration.line}") for ${registration.creates}, but ${describeRegistrationFailure(failure)} ` +
547
555
  'Remove the stale declaration with: ' +
@@ -1,6 +1,6 @@
1
1
  /**
2
- * CSS patch-lint rules: introduced raw color values and non-tokenized
3
- * custom-property references.
2
+ * CSS patch-lint rules: introduced raw color values, non-tokenized
3
+ * custom-property references, and (opt-in) token scales over created CSS.
4
4
  *
5
5
  * Split out of `patch-lint.ts` so each rule family stays within the
6
6
  * per-file line budget. `patch-lint.ts` re-exports `lintPatchedCss` so
@@ -8,6 +8,12 @@
8
8
  */
9
9
  import type { PatchLintIssue } from '../types/commands/index.js';
10
10
  import type { FireForgeConfig } from '../types/config.js';
11
+ /**
12
+ * Masks CSS block comments with spaces, preserving newlines so line
13
+ * numbers stay stable. An unclosed trailing `/*` is masked to EOF,
14
+ * matching how a CSS parser treats it.
15
+ */
16
+ export declare function maskCssComments(source: string): string;
11
17
  /**
12
18
  * Lints patched CSS files for introduced raw color values and non-tokenized
13
19
  * custom properties.
@@ -1,7 +1,7 @@
1
1
  // SPDX-License-Identifier: EUPL-1.2
2
2
  /**
3
- * CSS patch-lint rules: introduced raw color values and non-tokenized
4
- * custom-property references.
3
+ * CSS patch-lint rules: introduced raw color values, non-tokenized
4
+ * custom-property references, and (opt-in) token scales over created CSS.
5
5
  *
6
6
  * Split out of `patch-lint.ts` so each rule family stays within the
7
7
  * per-file line budget. `patch-lint.ts` re-exports `lintPatchedCss` so
@@ -13,7 +13,8 @@ import { pathExists, readText } from '../utils/fs.js';
13
13
  import { verbose } from '../utils/logger.js';
14
14
  import { hasRawCssColors } from '../utils/regex.js';
15
15
  import { loadFurnaceConfig } from './furnace-config.js';
16
- import { extractAddedLineNumbersPerFile, extractAddedLinesPerFile } from './patch-lint-diff.js';
16
+ import { detectNewFilesInDiff, extractAddedLineNumbersPerFile, extractAddedLinesPerFile, } from './patch-lint-diff.js';
17
+ import { lintTokenScales } from './patch-lint-token-scale.js';
17
18
  /**
18
19
  * Loads the furnace token-prefix lint inputs gracefully. Returns
19
20
  * undefined (skipping the token-prefix check) when furnace.json cannot
@@ -41,7 +42,7 @@ async function loadCssTokenContext(repoDir) {
41
42
  * numbers stay stable. An unclosed trailing `/*` is masked to EOF,
42
43
  * matching how a CSS parser treats it.
43
44
  */
44
- function maskCssComments(source) {
45
+ export function maskCssComments(source) {
45
46
  const masked = source.replace(/\/\*[\s\S]*?\*\//g, (m) => m.replace(/[^\n]/g, ' '));
46
47
  const openerIndex = masked.indexOf('/*');
47
48
  if (openerIndex === -1)
@@ -197,6 +198,9 @@ export async function lintPatchedCss(repoDir, affectedFiles, diffContent, config
197
198
  const addedLineNumbersByFile = diffContent
198
199
  ? extractAddedLineNumbersPerFile(diffContent)
199
200
  : undefined;
201
+ // `patchLint.tokenScales` governs only CSS the patch creates.
202
+ const tokenScales = config?.patchLint?.tokenScales ?? [];
203
+ const createdFiles = diffContent && tokenScales.length > 0 ? detectNewFilesInDiff(diffContent) : new Set();
200
204
  for (const file of cssFiles) {
201
205
  const filePath = join(repoDir, file);
202
206
  if (!(await pathExists(filePath)))
@@ -213,6 +217,8 @@ export async function lintPatchedCss(repoDir, affectedFiles, diffContent, config
213
217
  issues,
214
218
  });
215
219
  checkTokenPrefixViolations(file, cssContent, addedLinesByFile, tokenContext, issues);
220
+ if (createdFiles.has(file))
221
+ issues.push(...lintTokenScales(file, rawCss, tokenScales));
216
222
  }
217
223
  return issues;
218
224
  }
@@ -13,7 +13,9 @@
13
13
  * lines failed a gate with a message calling 750 soft. The message below
14
14
  * says what the band is (a warning) and what a zero-warning gate does with
15
15
  * it, and the thresholds are now tunable, so a project whose file-size
16
- * policy differs has a dial instead of an argument.
16
+ * policy differs has a dial instead of an argument. The notice band is the
17
+ * design target: advisory, and its message says so rather than borrowing
18
+ * the warning band's gate sentence.
17
19
  */
18
20
  import type { PatchLintFileSizeThresholds } from '../types/config.js';
19
21
  /** A fully resolved threshold triple. */
@@ -38,14 +40,19 @@ export declare function resolveFileSizeThresholds(overrides: PatchLintFileSizeTh
38
40
  /**
39
41
  * Renders the `file-too-large` message for a given band.
40
42
  *
41
- * The `warning` and `notice` bands name the gate consequence explicitly:
42
- * the number is advisory to patch-lint and blocking to a `--max-warnings 0`
43
- * gate, and an operator deciding whether to decompose a file needs to know
44
- * which of those they are looking at.
43
+ * Each band says what it means for a gate. A notice is over the design
44
+ * target and advisory: it never fails `--max-warnings 0`, and saying it
45
+ * did once got a test suite split for nothing. A warning is what a
46
+ * zero-warning gate fails on, so it names that and the dial. Only the
47
+ * error band suggests splitting, because a test-file split pushes against
48
+ * one suite per subject and should not be the default advice below it.
49
+ * Every band names the unit, which matters once `fileSizeMetric` makes
50
+ * code lines a choice.
45
51
  */
46
52
  export declare function formatFileTooLargeMessage(args: {
47
53
  label: string;
48
54
  lineCount: number;
55
+ unit: 'lines' | 'code lines';
49
56
  thresholds: ResolvedFileSizeTier;
50
57
  band: 'notice' | 'warning' | 'error';
51
58
  verb: string;
@@ -14,7 +14,9 @@
14
14
  * lines failed a gate with a message calling 750 soft. The message below
15
15
  * says what the band is (a warning) and what a zero-warning gate does with
16
16
  * it, and the thresholds are now tunable, so a project whose file-size
17
- * policy differs has a dial instead of an argument.
17
+ * policy differs has a dial instead of an argument. The notice band is the
18
+ * design target: advisory, and its message says so rather than borrowing
19
+ * the warning band's gate sentence.
18
20
  */
19
21
  /** Built-in defaults, per file class. */
20
22
  export const DEFAULT_FILE_SIZE_THRESHOLDS = {
@@ -36,18 +38,27 @@ export function resolveFileSizeThresholds(overrides, isTest) {
36
38
  /**
37
39
  * Renders the `file-too-large` message for a given band.
38
40
  *
39
- * The `warning` and `notice` bands name the gate consequence explicitly:
40
- * the number is advisory to patch-lint and blocking to a `--max-warnings 0`
41
- * gate, and an operator deciding whether to decompose a file needs to know
42
- * which of those they are looking at.
41
+ * Each band says what it means for a gate. A notice is over the design
42
+ * target and advisory: it never fails `--max-warnings 0`, and saying it
43
+ * did once got a test suite split for nothing. A warning is what a
44
+ * zero-warning gate fails on, so it names that and the dial. Only the
45
+ * error band suggests splitting, because a test-file split pushes against
46
+ * one suite per subject and should not be the default advice below it.
47
+ * Every band names the unit, which matters once `fileSizeMetric` makes
48
+ * code lines a choice.
43
49
  */
44
50
  export function formatFileTooLargeMessage(args) {
45
- const { label, lineCount, thresholds, band, verb } = args;
51
+ const { label, lineCount, unit, thresholds, band, verb } = args;
52
+ const measured = `${label} has ${lineCount} ${unit}`;
46
53
  if (band === 'error') {
47
- return `${label} has ${lineCount} lines (error threshold: ${thresholds.error}). Consider ${verb}.`;
54
+ return `${measured} (error threshold: ${thresholds.error}). Consider ${verb}.`;
48
55
  }
49
- return (`${label} has ${lineCount} lines (warning threshold: ${thresholds.warning}, ` +
50
- `error threshold: ${thresholds.error}). Consider ${verb}. ` +
51
- `Reported as a ${band}, which a gate running --max-warnings 0 treats as a failure; ` +
52
- `tune "patchLint.fileSizeThresholds" if these limits are wrong for this project.`);
56
+ const limits = `(warning threshold: ${thresholds.warning}, error threshold: ${thresholds.error})`;
57
+ if (band === 'notice') {
58
+ return (`${measured}, over the design target of ${thresholds.notice} ${limits}. ` +
59
+ 'Advisory; does not fail --max-warnings 0.');
60
+ }
61
+ return (`${measured} ${limits}. ` +
62
+ 'Reported as a warning, which a gate running --max-warnings 0 treats as a failure; ' +
63
+ 'tune "patchLint.fileSizeThresholds" if these limits are wrong for this project.');
53
64
  }
@@ -24,6 +24,24 @@ export interface ForwardRegistration {
24
24
  /** Paste-and-run declaration that records the stage as intentional. */
25
25
  command: string;
26
26
  }
27
+ /** True for a jar.mn, moz.build or test manifest, the carriers {@link resolveCarrierReferences} reads. */
28
+ export declare function isRegistrationCarrier(file: string): boolean;
29
+ /**
30
+ * The engine paths named by the lines of one jar.mn, moz.build or test
31
+ * manifest, resolved the way this rule resolves them. Exported for a caller
32
+ * outside the queue lint (re-export's adjacency belt asks which files a
33
+ * patch's added registration lines name). A `customElements.js` chrome URL
34
+ * resolves only through the queue's jar.mn index, so it is not covered.
35
+ *
36
+ * @param rawPath - Engine-relative path of the carrier
37
+ * @param content - The carrier lines to read (typically the added ones)
38
+ * @returns One entry per resolvable token. `exact` is set when it has no wildcard.
39
+ */
40
+ export declare function resolveCarrierReferences(rawPath: string, content: string): {
41
+ line: string;
42
+ exact?: string;
43
+ matches: (candidate: string) => boolean;
44
+ }[];
27
45
  /** The discharge command, in the exact shape the support-files arm prints. */
28
46
  export declare function formatRegistrationDeclaration(patch: string, file: string, line: string, creates: string, owner: string): string;
29
47
  /**
@@ -28,7 +28,7 @@ import { basename, dirname, posix } from 'node:path';
28
28
  import { normalizePathSlashes } from '../utils/paths.js';
29
29
  import { escapeRegex } from '../utils/regex.js';
30
30
  import { parseJarMnEntry } from './build-audit-registration.js';
31
- import { isLaterOwner, quoteRegistrationLine } from './patch-lint-staged-registration.js';
31
+ import { isLaterOwner, quoteRegistrationLine, STAGED_DEPENDENCY_REASON_PLACEHOLDER, } from './patch-lint-staged-registration.js';
32
32
  const TEST_MANIFEST_BASENAMES = new Set([
33
33
  'xpcshell.toml',
34
34
  'xpcshell.ini',
@@ -153,20 +153,45 @@ function customElementsReferences(file, content, jarTargets) {
153
153
  }
154
154
  return refs;
155
155
  }
156
+ /** True for a jar.mn, moz.build or test manifest, the carriers {@link resolveCarrierReferences} reads. */
157
+ export function isRegistrationCarrier(file) {
158
+ const name = basename(normalizePathSlashes(file));
159
+ return name === 'jar.mn' || name === 'moz.build' || TEST_MANIFEST_BASENAMES.has(name);
160
+ }
161
+ function carrierReferences(file, content) {
162
+ const name = basename(file);
163
+ if (name === 'jar.mn')
164
+ return jarMnReferences(file, content);
165
+ if (name === 'moz.build')
166
+ return mozBuildReferences(file, content);
167
+ if (TEST_MANIFEST_BASENAMES.has(name))
168
+ return testManifestReferences(file, content);
169
+ return [];
170
+ }
171
+ /**
172
+ * The engine paths named by the lines of one jar.mn, moz.build or test
173
+ * manifest, resolved the way this rule resolves them. Exported for a caller
174
+ * outside the queue lint (re-export's adjacency belt asks which files a
175
+ * patch's added registration lines name). A `customElements.js` chrome URL
176
+ * resolves only through the queue's jar.mn index, so it is not covered.
177
+ *
178
+ * @param rawPath - Engine-relative path of the carrier
179
+ * @param content - The carrier lines to read (typically the added ones)
180
+ * @returns One entry per resolvable token. `exact` is set when it has no wildcard.
181
+ */
182
+ export function resolveCarrierReferences(rawPath, content) {
183
+ return carrierReferences(normalizePathSlashes(rawPath), content);
184
+ }
156
185
  function referencesFor(entry, jarTargets) {
157
186
  const refs = [];
158
187
  for (const [rawPath, content] of [...entry.newFiles, ...entry.modifiedFileAdditions]) {
159
188
  const file = normalizePathSlashes(rawPath);
160
- const name = basename(file);
161
- if (name === 'jar.mn')
162
- refs.push(...jarMnReferences(file, content));
163
- else if (name === 'moz.build')
164
- refs.push(...mozBuildReferences(file, content));
165
- else if (TEST_MANIFEST_BASENAMES.has(name))
166
- refs.push(...testManifestReferences(file, content));
167
- else if (name === 'customElements.js') {
189
+ if (basename(file) === 'customElements.js') {
168
190
  refs.push(...customElementsReferences(file, content, jarTargets));
169
191
  }
192
+ else {
193
+ refs.push(...carrierReferences(file, content));
194
+ }
170
195
  }
171
196
  return refs;
172
197
  }
@@ -178,7 +203,7 @@ function isDeclared(entry, file, created) {
178
203
  export function formatRegistrationDeclaration(patch, file, line, creates, owner) {
179
204
  return (`fireforge patch staged-dependency ${patch} --add --kind registration ` +
180
205
  `--file ${file} --line "${quoteRegistrationLine(line)}" ` +
181
- `--creates ${creates} --owner ${owner}`);
206
+ `--creates ${creates} --owner ${owner} ${STAGED_DEPENDENCY_REASON_PLACEHOLDER}`);
182
207
  }
183
208
  /**
184
209
  * Finds every undeclared forward registration in the extended carriers: