@hominis/fireforge 0.50.0 → 0.52.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 (212) hide show
  1. package/CHANGELOG.md +67 -0
  2. package/dist/build-info.json +4 -4
  3. package/dist/src/commands/check-report.d.ts +17 -4
  4. package/dist/src/commands/check-report.js +19 -6
  5. package/dist/src/commands/check-run.d.ts +5 -0
  6. package/dist/src/commands/check-run.js +9 -1
  7. package/dist/src/commands/check-steps.d.ts +8 -0
  8. package/dist/src/commands/check-steps.js +31 -6
  9. package/dist/src/commands/check.js +1 -1
  10. package/dist/src/commands/declarations-report.d.ts +43 -0
  11. package/dist/src/commands/declarations-report.js +76 -0
  12. package/dist/src/commands/export-placement-gate.js +8 -0
  13. package/dist/src/commands/furnace/rename-registrations.js +7 -2
  14. package/dist/src/commands/furnace/validate.js +26 -1
  15. package/dist/src/commands/lint-per-patch.js +6 -2
  16. package/dist/src/commands/lint-per-run-checkjs.js +2 -2
  17. package/dist/src/commands/lint-report.js +7 -2
  18. package/dist/src/commands/manifest.js +2 -0
  19. package/dist/src/commands/park.d.ts +22 -0
  20. package/dist/src/commands/park.js +232 -0
  21. package/dist/src/commands/patch/delete.js +11 -6
  22. package/dist/src/commands/patch/index.d.ts +3 -3
  23. package/dist/src/commands/patch/index.js +8 -4
  24. package/dist/src/commands/patch/lint-ignore-from.d.ts +44 -0
  25. package/dist/src/commands/patch/lint-ignore-from.js +142 -0
  26. package/dist/src/commands/patch/lint-ignore.js +39 -29
  27. package/dist/src/commands/patch/move-files-create.js +11 -4
  28. package/dist/src/commands/patch/move-files-into.js +10 -4
  29. package/dist/src/commands/patch/move-files.js +3 -1
  30. package/dist/src/commands/patch/removal-created-files.d.ts +48 -0
  31. package/dist/src/commands/patch/removal-created-files.js +83 -0
  32. package/dist/src/commands/patch/rename.js +15 -3
  33. package/dist/src/commands/patch/reserve.d.ts +33 -0
  34. package/dist/src/commands/patch/reserve.js +152 -0
  35. package/dist/src/commands/patch/retire.js +11 -6
  36. package/dist/src/commands/patch/split-plan.d.ts +10 -1
  37. package/dist/src/commands/patch/split-plan.js +16 -1
  38. package/dist/src/commands/patch/split.js +14 -5
  39. package/dist/src/commands/patch/stage.d.ts +34 -0
  40. package/dist/src/commands/patch/stage.js +153 -0
  41. package/dist/src/commands/patch/staged-dependency-remove.d.ts +31 -0
  42. package/dist/src/commands/patch/staged-dependency-remove.js +80 -0
  43. package/dist/src/commands/patch/staged-dependency.js +40 -98
  44. package/dist/src/commands/re-export-adjacent.d.ts +5 -0
  45. package/dist/src/commands/re-export-adjacent.js +4 -3
  46. package/dist/src/commands/re-export-bulk-scan.d.ts +2 -1
  47. package/dist/src/commands/re-export-bulk-scan.js +22 -7
  48. package/dist/src/commands/re-export-hunks.d.ts +35 -0
  49. package/dist/src/commands/re-export-hunks.js +220 -0
  50. package/dist/src/commands/re-export-options.js +29 -2
  51. package/dist/src/commands/re-export-purity-scope.d.ts +18 -0
  52. package/dist/src/commands/re-export-purity-scope.js +131 -0
  53. package/dist/src/commands/re-export-register.js +15 -1
  54. package/dist/src/commands/re-export-removed.d.ts +1 -1
  55. package/dist/src/commands/re-export-removed.js +17 -2
  56. package/dist/src/commands/re-export-scan.d.ts +2 -0
  57. package/dist/src/commands/re-export-scan.js +4 -1
  58. package/dist/src/commands/re-export-single.js +102 -42
  59. package/dist/src/commands/re-export-stale-registrations.d.ts +18 -0
  60. package/dist/src/commands/re-export-stale-registrations.js +62 -0
  61. package/dist/src/commands/re-export.js +35 -34
  62. package/dist/src/commands/status-output.js +5 -1
  63. package/dist/src/commands/test-build-furnace.d.ts +3 -2
  64. package/dist/src/commands/test-build-furnace.js +8 -2
  65. package/dist/src/commands/test-build-phase.d.ts +2 -0
  66. package/dist/src/commands/test-build-phase.js +34 -17
  67. package/dist/src/commands/test-checkjs.js +3 -2
  68. package/dist/src/commands/test-dispatch.d.ts +39 -0
  69. package/dist/src/commands/test-dispatch.js +220 -0
  70. package/dist/src/commands/test-furnace-reach.d.ts +37 -0
  71. package/dist/src/commands/test-furnace-reach.js +132 -0
  72. package/dist/src/commands/test-orchestrate.d.ts +14 -0
  73. package/dist/src/commands/test-orchestrate.js +25 -4
  74. package/dist/src/commands/test-perf-scope.d.ts +21 -0
  75. package/dist/src/commands/test-perf-scope.js +55 -0
  76. package/dist/src/commands/test-prelock.js +100 -4
  77. package/dist/src/commands/test-register.js +18 -3
  78. package/dist/src/commands/test-results.d.ts +62 -0
  79. package/dist/src/commands/test-results.js +62 -0
  80. package/dist/src/commands/test-run.d.ts +13 -55
  81. package/dist/src/commands/test-run.js +73 -101
  82. package/dist/src/commands/test-shards.d.ts +110 -0
  83. package/dist/src/commands/test-shards.js +255 -0
  84. package/dist/src/commands/test-stale-gate.d.ts +5 -1
  85. package/dist/src/commands/test-stale-gate.js +11 -2
  86. package/dist/src/commands/test-verdict.d.ts +2 -1
  87. package/dist/src/commands/test.d.ts +1 -1
  88. package/dist/src/commands/test.js +68 -75
  89. package/dist/src/commands/token-lint.js +48 -8
  90. package/dist/src/commands/verify.js +9 -2
  91. package/dist/src/core/build-baseline-types.d.ts +13 -0
  92. package/dist/src/core/build-baseline-validate.js +9 -0
  93. package/dist/src/core/build-baseline.js +7 -0
  94. package/dist/src/core/build-prepare.d.ts +6 -0
  95. package/dist/src/core/build-prepare.js +29 -3
  96. package/dist/src/core/config-paths.d.ts +1 -1
  97. package/dist/src/core/config-paths.js +2 -0
  98. package/dist/src/core/config-validate-check.js +83 -7
  99. package/dist/src/core/config-validate-test-toolchains.js +14 -0
  100. package/dist/src/core/config-validate-token-scales.d.ts +3 -0
  101. package/dist/src/core/config-validate-token-scales.js +47 -5
  102. package/dist/src/core/config-validate.js +6 -0
  103. package/dist/src/core/coverage-extend.js +2 -2
  104. package/dist/src/core/coverage-records.d.ts +11 -0
  105. package/dist/src/core/coverage-records.js +34 -0
  106. package/dist/src/core/engine-session-lock.d.ts +6 -0
  107. package/dist/src/core/engine-session-lock.js +10 -2
  108. package/dist/src/core/file-lock-shared.d.ts +57 -0
  109. package/dist/src/core/file-lock-shared.js +117 -0
  110. package/dist/src/core/file-lock.d.ts +9 -0
  111. package/dist/src/core/file-lock.js +58 -2
  112. package/dist/src/core/furnace-apply.js +10 -10
  113. package/dist/src/core/furnace-config-validate-exceptions.d.ts +11 -3
  114. package/dist/src/core/furnace-config-validate-exceptions.js +59 -8
  115. package/dist/src/core/furnace-config-validate.js +7 -1
  116. package/dist/src/core/furnace-registration-jar-inplace.d.ts +12 -0
  117. package/dist/src/core/furnace-registration-jar-inplace.js +80 -0
  118. package/dist/src/core/furnace-validate-accessibility.d.ts +5 -3
  119. package/dist/src/core/furnace-validate-accessibility.js +75 -30
  120. package/dist/src/core/furnace-validate-exceptions.d.ts +13 -4
  121. package/dist/src/core/furnace-validate-exceptions.js +59 -4
  122. package/dist/src/core/furnace-validate-icon-button.js +30 -1
  123. package/dist/src/core/history-log-file.js +8 -1
  124. package/dist/src/core/line-prefixer.d.ts +18 -0
  125. package/dist/src/core/line-prefixer.js +34 -0
  126. package/dist/src/core/mach.d.ts +7 -0
  127. package/dist/src/core/mach.js +24 -9
  128. package/dist/src/core/module-resolution-preflight.d.ts +19 -3
  129. package/dist/src/core/module-resolution-preflight.js +24 -6
  130. package/dist/src/core/negative-control-compiled.d.ts +36 -0
  131. package/dist/src/core/negative-control-compiled.js +87 -0
  132. package/dist/src/core/negative-control-diff.d.ts +14 -2
  133. package/dist/src/core/negative-control-diff.js +49 -6
  134. package/dist/src/core/negative-control.d.ts +12 -0
  135. package/dist/src/core/negative-control.js +48 -5
  136. package/dist/src/core/park-store.d.ts +63 -0
  137. package/dist/src/core/park-store.js +216 -0
  138. package/dist/src/core/patch-export-update.d.ts +4 -0
  139. package/dist/src/core/patch-export-update.js +12 -3
  140. package/dist/src/core/patch-export.d.ts +3 -2
  141. package/dist/src/core/patch-export.js +21 -14
  142. package/dist/src/core/patch-files.js +26 -8
  143. package/dist/src/core/patch-lint-checkjs-any-import.d.ts +6 -4
  144. package/dist/src/core/patch-lint-checkjs-any-import.js +9 -7
  145. package/dist/src/core/patch-lint-checkjs-diagnostics.d.ts +17 -0
  146. package/dist/src/core/patch-lint-checkjs-diagnostics.js +32 -0
  147. package/dist/src/core/patch-lint-checkjs.d.ts +10 -1
  148. package/dist/src/core/patch-lint-checkjs.js +13 -3
  149. package/dist/src/core/patch-lint-cross.d.ts +3 -1
  150. package/dist/src/core/patch-lint-cross.js +5 -0
  151. package/dist/src/core/patch-lint-css.js +14 -10
  152. package/dist/src/core/patch-lint-forward-registration-extended.d.ts +5 -0
  153. package/dist/src/core/patch-lint-forward-registration-extended.js +1 -1
  154. package/dist/src/core/patch-lint-ignore.d.ts +56 -12
  155. package/dist/src/core/patch-lint-ignore.js +173 -43
  156. package/dist/src/core/patch-lint-ownership.d.ts +10 -0
  157. package/dist/src/core/patch-lint-ownership.js +26 -0
  158. package/dist/src/core/patch-lint-size.js +9 -1
  159. package/dist/src/core/patch-lint-token-scale.d.ts +26 -8
  160. package/dist/src/core/patch-lint-token-scale.js +206 -29
  161. package/dist/src/core/patch-lint.js +2 -2
  162. package/dist/src/core/patch-manifest-io.js +8 -1
  163. package/dist/src/core/patch-manifest-key-order.d.ts +24 -0
  164. package/dist/src/core/patch-manifest-key-order.js +61 -0
  165. package/dist/src/core/patch-manifest-stage.d.ts +46 -0
  166. package/dist/src/core/patch-manifest-stage.js +96 -0
  167. package/dist/src/core/patch-manifest-validate.js +27 -1
  168. package/dist/src/core/patch-order-legal.d.ts +2 -1
  169. package/dist/src/core/patch-order-legal.js +7 -2
  170. package/dist/src/core/patch-policy.d.ts +6 -2
  171. package/dist/src/core/patch-policy.js +14 -7
  172. package/dist/src/core/patch-retired.d.ts +26 -4
  173. package/dist/src/core/patch-retired.js +40 -2
  174. package/dist/src/core/run-log.d.ts +6 -0
  175. package/dist/src/core/run-log.js +17 -1
  176. package/dist/src/core/test-harness-crash.d.ts +2 -1
  177. package/dist/src/core/test-harness-crash.js +5 -8
  178. package/dist/src/core/test-harness-signature.d.ts +16 -0
  179. package/dist/src/core/test-harness-signature.js +19 -1
  180. package/dist/src/core/test-raw-log.d.ts +66 -0
  181. package/dist/src/core/test-raw-log.js +122 -0
  182. package/dist/src/core/test-run-completeness.d.ts +47 -7
  183. package/dist/src/core/test-run-completeness.js +70 -23
  184. package/dist/src/core/test-stale-check.d.ts +10 -1
  185. package/dist/src/core/test-stale-check.js +15 -1
  186. package/dist/src/core/test-xpcshell-retry.d.ts +2 -0
  187. package/dist/src/core/test-xpcshell-retry.js +2 -1
  188. package/dist/src/core/token-lint.d.ts +5 -2
  189. package/dist/src/core/token-lint.js +8 -3
  190. package/dist/src/core/token-sibling-sheets.d.ts +46 -0
  191. package/dist/src/core/token-sibling-sheets.js +119 -0
  192. package/dist/src/core/tree-guard.js +2 -0
  193. package/dist/src/core/typecheck-shim.d.ts +6 -1
  194. package/dist/src/core/typecheck-shim.js +139 -2
  195. package/dist/src/core/typecheck.js +3 -1
  196. package/dist/src/index.d.ts +9 -3
  197. package/dist/src/index.js +4 -1
  198. package/dist/src/types/commands/index.d.ts +2 -2
  199. package/dist/src/types/commands/options.d.ts +68 -7
  200. package/dist/src/types/commands/patches.d.ts +43 -0
  201. package/dist/src/types/config.d.ts +74 -2
  202. package/dist/src/types/furnace.d.ts +29 -0
  203. package/dist/src/types/index.d.ts +1 -1
  204. package/dist/src/utils/options.d.ts +3 -2
  205. package/dist/src/utils/options.js +9 -4
  206. package/docs/configuration.md +110 -9
  207. package/docs/furnace.md +61 -1
  208. package/docs/lifecycle-invariants.md +13 -11
  209. package/docs/machine-output.md +68 -18
  210. package/docs/patch-workflow.md +174 -13
  211. package/docs/testing.md +89 -5
  212. package/package.json +3 -3
@@ -25,7 +25,7 @@ import { buildProjectedManifest, enforcePatchPolicy } from './patch-policy.js';
25
25
  * already byte-identical to the new content.
26
26
  */
27
27
  export async function updatePatchAndMetadata(options) {
28
- const { patchesDir, filename, newContent, updates, onCommitted, policyGate, lockOptions = {}, } = options;
28
+ const { patchesDir, filename, newContent, updates, unset = [], onCommitted, policyGate, lockOptions = {}, } = options;
29
29
  return withPatchDirectoryLock(patchesDir, async () => {
30
30
  const manifest = await loadPatchesManifestForWrite(patchesDir);
31
31
  if (!manifest) {
@@ -41,7 +41,7 @@ export async function updatePatchAndMetadata(options) {
41
41
  }
42
42
  const originalContent = await readText(patchPath);
43
43
  const existingPatch = manifest.patches[patchIndex];
44
- manifest.patches[patchIndex] = { ...existingPatch, ...updates };
44
+ manifest.patches[patchIndex] = withoutFields({ ...existingPatch, ...updates }, unset);
45
45
  if (policyGate !== undefined) {
46
46
  enforcePatchPolicy({
47
47
  config: policyGate.config,
@@ -59,7 +59,7 @@ export async function updatePatchAndMetadata(options) {
59
59
  await writeText(patchPath, normalized);
60
60
  patchWritten = true;
61
61
  }
62
- await mutatePatchRowsInManifest(patchesDir, [filename], () => ({ set: updates }));
62
+ await mutatePatchRowsInManifest(patchesDir, [filename], () => ({ set: updates, unset }));
63
63
  }
64
64
  catch (error) {
65
65
  if (patchWritten) {
@@ -84,3 +84,12 @@ export async function updatePatchAndMetadata(options) {
84
84
  return bodyChanged;
85
85
  }, lockOptions);
86
86
  }
87
+ /** A copy of `row` without `fields`. */
88
+ export function withoutFields(row, fields) {
89
+ if (fields.length === 0)
90
+ return row;
91
+ const copy = { ...row };
92
+ for (const field of fields)
93
+ Reflect.deleteProperty(copy, field);
94
+ return copy;
95
+ }
@@ -18,9 +18,10 @@ export declare function buildPlanExportInput(input: PlanExportInput): PlanExport
18
18
  /**
19
19
  * Gets the next patch number for a new patch.
20
20
  * @param patchesDir - Path to the patches directory
21
+ * @param reserved - Orders held by `patch reserve`, skipped
21
22
  * @returns Next patch number (e.g., "005" for 4 existing patches)
22
23
  */
23
- export declare function getNextPatchNumber(patchesDir: string): Promise<string>;
24
+ export declare function getNextPatchNumber(patchesDir: string, reserved?: ReadonlySet<number>): Promise<string>;
24
25
  /**
25
26
  * Sanitizes a human-readable name into a filename slug.
26
27
  *
@@ -59,7 +60,7 @@ export declare function patchNameSlug(name: string, category: string): string;
59
60
  * @param name - Human-readable name
60
61
  * @returns Filename like "001-ui-sidebar.patch"
61
62
  */
62
- export declare function getNextPatchFilename(patchesDir: string, category: PatchCategory, name: string): Promise<string>;
63
+ export declare function getNextPatchFilename(patchesDir: string, category: PatchCategory, name: string, reserved?: ReadonlySet<number>): Promise<string>;
63
64
  export interface CommitExportedPatchInput {
64
65
  patchesDir: string;
65
66
  category: PatchCategory;
@@ -2,13 +2,13 @@
2
2
  import { join } from 'node:path';
3
3
  import { toError } from '../utils/errors.js';
4
4
  import { pathExists, readText, removeFile, writeText } from '../utils/fs.js';
5
- import { warn } from '../utils/logger.js';
5
+ import { info, warn } from '../utils/logger.js';
6
6
  import { discoverPatches, withPatchDirectoryLock } from './patch-apply.js';
7
7
  import { findAllPatchesForFilesWithDetails, } from './patch-export-coverage.js';
8
8
  import { addPatchToManifest, loadPatchesManifestForWrite, PATCHES_MANIFEST, savePatchesManifest, } from './patch-manifest.js';
9
9
  import { formatPatchOrder, requirePatchOrder } from './patch-parse.js';
10
10
  import { allocatePolicyOrder, enforcePatchPolicy } from './patch-policy.js';
11
- import { manifestWithRetiredSlots } from './patch-retired.js';
11
+ import { manifestWithRetiredSlots, reservationAt, reservedOrderSet } from './patch-retired.js';
12
12
  export { findAllPatchesForFiles, findAllPatchesForFilesWithDetails, } from './patch-export-coverage.js';
13
13
  import { escapeRegex } from '../utils/regex.js';
14
14
  export { mutatePatchMetadata, updatePatchMetadata } from './patch-export-metadata.js';
@@ -40,18 +40,16 @@ export function buildPlanExportInput(input) {
40
40
  /**
41
41
  * Gets the next patch number for a new patch.
42
42
  * @param patchesDir - Path to the patches directory
43
+ * @param reserved - Orders held by `patch reserve`, skipped
43
44
  * @returns Next patch number (e.g., "005" for 4 existing patches)
44
45
  */
45
- export async function getNextPatchNumber(patchesDir) {
46
+ export async function getNextPatchNumber(patchesDir, reserved = new Set()) {
46
47
  const patches = await discoverPatches(patchesDir);
47
- if (patches.length === 0) {
48
- return '001';
49
- }
50
48
  const finitePatches = patches.filter((p) => Number.isFinite(p.order));
51
- if (finitePatches.length === 0)
52
- return '001';
53
49
  const maxOrder = finitePatches.reduce((max, p) => Math.max(max, p.order), 0);
54
- const nextNumber = maxOrder + 1;
50
+ let nextNumber = maxOrder + 1;
51
+ while (reserved.has(nextNumber))
52
+ nextNumber++;
55
53
  return String(nextNumber).padStart(Math.max(3, String(nextNumber).length), '0');
56
54
  }
57
55
  /**
@@ -118,8 +116,8 @@ export function patchNameSlug(name, category) {
118
116
  * @param name - Human-readable name
119
117
  * @returns Filename like "001-ui-sidebar.patch"
120
118
  */
121
- export async function getNextPatchFilename(patchesDir, category, name) {
122
- const patchNumber = await getNextPatchNumber(patchesDir);
119
+ export async function getNextPatchFilename(patchesDir, category, name, reserved = new Set()) {
120
+ const patchNumber = await getNextPatchNumber(patchesDir, reserved);
123
121
  const sanitizedName = patchNameSlug(name, category);
124
122
  return `${patchNumber}-${category}-${sanitizedName}.patch`;
125
123
  }
@@ -234,12 +232,15 @@ async function computeExportPlanUnderLock(input) {
234
232
  // wipes the queue metadata, and the rollback path would then delete
235
233
  // patches.json entirely because manifestBefore looked absent.
236
234
  const manifestBefore = await loadPatchesManifestForWrite(input.patchesDir);
235
+ // A default allocation never lands on a reservation; only an explicit
236
+ // `--order` placement fills one.
237
+ const reserved = reservedOrderSet(manifestBefore ?? {});
237
238
  const policyOrder = input.config !== undefined
238
- ? allocatePolicyOrder(input.config, manifestBefore?.patches ?? [], input.category)
239
+ ? allocatePolicyOrder(input.config, manifestBefore?.patches ?? [], input.category, reserved)
239
240
  : null;
240
241
  const patchFilename = policyOrder !== null
241
242
  ? `${formatPatchOrder(policyOrder)}-${input.category}-${patchNameSlug(input.name, input.category)}.patch`
242
- : await getNextPatchFilename(input.patchesDir, input.category, input.name);
243
+ : await getNextPatchFilename(input.patchesDir, input.category, input.name, reserved);
243
244
  const patchPath = join(input.patchesDir, patchFilename);
244
245
  const metadata = {
245
246
  filename: patchFilename,
@@ -267,6 +268,12 @@ async function computeExportPlanUnderLock(input) {
267
268
  const afterPatches = (manifestBefore?.patches ?? []).filter((p) => !supersededSet.has(p.filename) && p.filename !== patchFilename);
268
269
  afterPatches.push(metadata);
269
270
  afterPatches.sort((a, b) => a.order - b.order || a.filename.localeCompare(b.filename));
271
+ const reservation = reservationAt(manifestBefore, metadata.order);
272
+ if (reservation !== undefined) {
273
+ info(`Order ${formatPatchOrder(metadata.order)} was reserved by ${reservation.owner}` +
274
+ `${reservation.reason !== undefined ? ` (${reservation.reason})` : ''}; ` +
275
+ 'this export fills the reservation.');
276
+ }
270
277
  return {
271
278
  patchFilename,
272
279
  patchPath,
@@ -274,7 +281,7 @@ async function computeExportPlanUnderLock(input) {
274
281
  supersededDetails,
275
282
  supersededPatches,
276
283
  manifestBefore: manifestBefore ?? null,
277
- // A patch landing on a retired order fills that slot.
284
+ // A patch landing on a retired or reserved order fills that slot.
278
285
  manifestAfter: manifestWithRetiredSlots(manifestBefore, afterPatches),
279
286
  };
280
287
  }
@@ -1,5 +1,5 @@
1
1
  // SPDX-License-Identifier: EUPL-1.2
2
- import { readdir } from 'node:fs/promises';
2
+ import { readdir, stat } from 'node:fs/promises';
3
3
  import { extname, join } from 'node:path';
4
4
  import { pathExists, readText } from '../utils/fs.js';
5
5
  import { extractAffectedFiles, extractOrder } from './patch-parse.js';
@@ -9,16 +9,34 @@ export async function discoverPatches(patchesDir) {
9
9
  return [];
10
10
  }
11
11
  const entries = await readdir(patchesDir, { withFileTypes: true });
12
- const patches = entries
13
- .filter((entry) => entry.isFile() && extname(entry.name) === '.patch')
14
- .map((entry) => ({
15
- path: join(patchesDir, entry.name),
16
- filename: entry.name,
17
- order: extractOrder(entry.name),
18
- }));
12
+ const patches = [];
13
+ for (const entry of entries) {
14
+ if (extname(entry.name) !== '.patch')
15
+ continue;
16
+ // A symlinked patch (a scratch queue built from links to the real
17
+ // patches) counts when it resolves to a regular file; a dangling link or
18
+ // a link to a directory does not.
19
+ if (!entry.isFile() &&
20
+ !(entry.isSymbolicLink() && (await isLinkToFile(patchesDir, entry.name)))) {
21
+ continue;
22
+ }
23
+ patches.push({
24
+ path: join(patchesDir, entry.name),
25
+ filename: entry.name,
26
+ order: extractOrder(entry.name),
27
+ });
28
+ }
19
29
  patches.sort((a, b) => a.order - b.order || a.filename.localeCompare(b.filename));
20
30
  return patches;
21
31
  }
32
+ async function isLinkToFile(dir, name) {
33
+ try {
34
+ return (await stat(join(dir, name))).isFile();
35
+ }
36
+ catch {
37
+ return false;
38
+ }
39
+ }
22
40
  /** Counts the patch files currently present in a patch directory. */
23
41
  export async function countPatches(patchesDir) {
24
42
  const patches = await discoverPatches(patchesDir);
@@ -2,10 +2,12 @@
2
2
  * Explains an implicit-`any` checkJs finding that comes from a URL import
3
3
  * the per-patch program cannot resolve.
4
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
5
+ * The program resolves URL imports only to modules the queue creates (for
6
+ * a test, those created up to its own patch, plus its directory's
7
+ * head.js), so a `resource:///` or `chrome://` import of a module a later
8
+ * patch creates, an upstream module, or a basename two patches create
9
+ * falls back to the shim's `declare module 'resource:*'` wildcard and
10
+ * types as `any`. A callback
9
11
  * over its values then has implicitly-`any` parameters under
10
12
  * `checkJsStrict`, while the whole-tree `fireforge typecheck`, which sees
11
13
  * the module, is clean. Without the note the two disagree with no
@@ -3,10 +3,12 @@
3
3
  * Explains an implicit-`any` checkJs finding that comes from a URL import
4
4
  * the per-patch program cannot resolve.
5
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
6
+ * The program resolves URL imports only to modules the queue creates (for
7
+ * a test, those created up to its own patch, plus its directory's
8
+ * head.js), so a `resource:///` or `chrome://` import of a module a later
9
+ * patch creates, an upstream module, or a basename two patches create
10
+ * falls back to the shim's `declare module 'resource:*'` wildcard and
11
+ * types as `any`. A callback
10
12
  * over its values then has implicitly-`any` parameters under
11
13
  * `checkJsStrict`, while the whole-tree `fireforge typecheck`, which sees
12
14
  * the module, is clean. Without the note the two disagree with no
@@ -35,9 +37,9 @@ export function anyTypedImportHint(code, specifiers) {
35
37
  return '';
36
38
  const list = [...specifiers].sort().join(', ');
37
39
  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.)');
40
+ 'no patch up to this one creates the module under that name: a later patch creates it, ' +
41
+ 'it is upstream, or two patches create the same basename — so the import is typed `any`. ' +
42
+ 'Annotate the parameter explicitly; the whole-tree "fireforge typecheck" resolves the real type.)');
41
43
  }
42
44
  /**
43
45
  * The host's `resolveModuleNameLiterals`: owned specifiers first, then a
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Collects a checkJs program's diagnostics, for every file or for a report
3
+ * scope only. A per-test program resolves the modules its imports reach
4
+ * (see `runCheckJsTestFilesGrouped`), and asking for the whole program's
5
+ * diagnostics would type-check each of those modules once per test, so a
6
+ * scoped run asks only for the files it reports. Split out of
7
+ * patch-lint-checkjs.ts for the line budget.
8
+ */
9
+ /**
10
+ * The program's semantic and syntactic diagnostics, limited to the files
11
+ * `reportOnly` names when it is set.
12
+ *
13
+ * @param program - The built program
14
+ * @param relByAbsolute - Owned files: TS path → repo-relative path
15
+ * @param reportOnly - Repo-relative files to collect for, or all when unset
16
+ */
17
+ export declare function collectCheckJsDiagnostics(program: import('typescript').Program, relByAbsolute: ReadonlyMap<string, string>, reportOnly: ReadonlySet<string> | undefined): import('typescript').Diagnostic[];
@@ -0,0 +1,32 @@
1
+ // SPDX-License-Identifier: EUPL-1.2
2
+ /**
3
+ * Collects a checkJs program's diagnostics, for every file or for a report
4
+ * scope only. A per-test program resolves the modules its imports reach
5
+ * (see `runCheckJsTestFilesGrouped`), and asking for the whole program's
6
+ * diagnostics would type-check each of those modules once per test, so a
7
+ * scoped run asks only for the files it reports. Split out of
8
+ * patch-lint-checkjs.ts for the line budget.
9
+ */
10
+ /**
11
+ * The program's semantic and syntactic diagnostics, limited to the files
12
+ * `reportOnly` names when it is set.
13
+ *
14
+ * @param program - The built program
15
+ * @param relByAbsolute - Owned files: TS path → repo-relative path
16
+ * @param reportOnly - Repo-relative files to collect for, or all when unset
17
+ */
18
+ export function collectCheckJsDiagnostics(program, relByAbsolute, reportOnly) {
19
+ if (reportOnly === undefined) {
20
+ return [...program.getSemanticDiagnostics(), ...program.getSyntacticDiagnostics()];
21
+ }
22
+ return program
23
+ .getSourceFiles()
24
+ .filter((sourceFile) => {
25
+ const rel = relByAbsolute.get(sourceFile.fileName);
26
+ return rel !== undefined && reportOnly.has(rel);
27
+ })
28
+ .flatMap((sourceFile) => [
29
+ ...program.getSemanticDiagnostics(sourceFile),
30
+ ...program.getSyntacticDiagnostics(sourceFile),
31
+ ]);
32
+ }
@@ -82,6 +82,8 @@ export interface RunCheckJsGroupedInput {
82
82
  * compiler options and shim in one run. See {@link runCheckJsTestFilesGrouped}.
83
83
  */
84
84
  sourceFileCache?: CheckJsSourceFileCache;
85
+ /** When set, diagnostics are collected only for these repo-relative files. */
86
+ reportOnly?: ReadonlySet<string>;
85
87
  }
86
88
  /**
87
89
  * Builds the checkJs program once over `resolutionOwned` and returns its
@@ -136,12 +138,19 @@ export declare function invokePatchLintCheckJs(repoDir: string, patchOwnedFiles:
136
138
  * reported per program (head helpers report from their own program), and
137
139
  * run-level errors are de-duplicated across programs.
138
140
  *
141
+ * With `resolvableModules`, a test's `resource:///` and `chrome://`
142
+ * imports also resolve to the modules it returns for that test (the
143
+ * modules the queue creates up to the test's own patch), so a test that
144
+ * imports an earlier patch's module is typed against its real source
145
+ * instead of the shim's `any` wildcard. Those modules are resolution
146
+ * targets only: never roots, and never reported on.
147
+ *
139
148
  * @param repoDir - Absolute engine (repository) directory
140
149
  * @param testFiles - Patch-owned test-script paths (repo-relative)
141
150
  * @param patchLint - The resolved `patchLint` config block
142
151
  * @param projectRoot - FireForge project root for shim resolution
143
152
  */
144
- export declare function runCheckJsTestFilesGrouped(repoDir: string, testFiles: Set<string>, patchLint: PatchLintConfig, projectRoot: string, rootScope?: ReadonlySet<string>): Promise<GroupedCheckJsResult>;
153
+ export declare function runCheckJsTestFilesGrouped(repoDir: string, testFiles: Set<string>, patchLint: PatchLintConfig, projectRoot: string, rootScope?: ReadonlySet<string>, resolvableModules?: (testFile: string) => ReadonlySet<string>): Promise<GroupedCheckJsResult>;
145
154
  /**
146
155
  * Grouped variant of {@link invokePatchLintCheckJs}: builds one queue-wide
147
156
  * checkJs program over `patchOwnedFiles` and returns its findings grouped by
@@ -33,6 +33,7 @@ import { normalizePathSlashes } from '../utils/paths.js';
33
33
  import { withGeckoDomTypes } from './gecko-dom-types.js';
34
34
  import { anyTypedImportHint, createModuleLiteralResolver, } from './patch-lint-checkjs-any-import.js';
35
35
  import { withSharedSourceFiles } from './patch-lint-checkjs-cache.js';
36
+ import { collectCheckJsDiagnostics } from './patch-lint-checkjs-diagnostics.js';
36
37
  import { collectUnmanagedCompanions, retargetUnmanagedCompanionHints, } from './patch-lint-unmanaged-companion.js';
37
38
  import { composeShimSource, SHIM_FILENAME, SUPPRESSED_DIAGNOSTIC_CODES, TEST_HARNESS_SHIM, UNDEFINED_IDENTIFIER_CODES, UNDEFINED_IDENTIFIER_HINT, } from './typecheck-shim.js';
38
39
  // ---------------------------------------------------------------------------
@@ -340,7 +341,7 @@ export async function runCheckJsGrouped(input) {
340
341
  resolveModuleNameLiterals: createModuleLiteralResolver(resolveOwnedSpecifier, resolveViaPaths, anyTypedImports),
341
342
  };
342
343
  const program = ts.createProgram(rootFiles, options, withSharedSourceFiles(host, input.sourceFileCache, shimPath, shimSource));
343
- const byFile = groupOwnedDiagnostics(ts, [...program.getSemanticDiagnostics(), ...program.getSyntacticDiagnostics()], relByAbsolute, input.mode?.undefinedIdentifiers ?? 'warning', anyTypedImports);
344
+ const byFile = groupOwnedDiagnostics(ts, collectCheckJsDiagnostics(program, relByAbsolute, input.reportOnly), relByAbsolute, input.mode?.undefinedIdentifiers ?? 'warning', anyTypedImports);
344
345
  verbose(`checkJs: analyzed ${rootFiles.length - 1} file(s) across ${byFile.size} owning file(s)`);
345
346
  return { byFile, global: [] };
346
347
  }
@@ -448,12 +449,19 @@ export async function invokePatchLintCheckJs(repoDir, patchOwnedFiles, patchLint
448
449
  * reported per program (head helpers report from their own program), and
449
450
  * run-level errors are de-duplicated across programs.
450
451
  *
452
+ * With `resolvableModules`, a test's `resource:///` and `chrome://`
453
+ * imports also resolve to the modules it returns for that test (the
454
+ * modules the queue creates up to the test's own patch), so a test that
455
+ * imports an earlier patch's module is typed against its real source
456
+ * instead of the shim's `any` wildcard. Those modules are resolution
457
+ * targets only: never roots, and never reported on.
458
+ *
451
459
  * @param repoDir - Absolute engine (repository) directory
452
460
  * @param testFiles - Patch-owned test-script paths (repo-relative)
453
461
  * @param patchLint - The resolved `patchLint` config block
454
462
  * @param projectRoot - FireForge project root for shim resolution
455
463
  */
456
- export async function runCheckJsTestFilesGrouped(repoDir, testFiles, patchLint, projectRoot, rootScope) {
464
+ export async function runCheckJsTestFilesGrouped(repoDir, testFiles, patchLint, projectRoot, rootScope, resolvableModules) {
457
465
  const merged = { byFile: new Map(), global: [] };
458
466
  if (testFiles.size === 0)
459
467
  return merged;
@@ -484,7 +492,9 @@ export async function runCheckJsTestFilesGrouped(repoDir, testFiles, patchLint,
484
492
  }
485
493
  const result = await runCheckJsGrouped({
486
494
  repoDir,
487
- resolutionOwned: roots,
495
+ resolutionOwned: new Set([...roots, ...(resolvableModules?.(file) ?? [])]),
496
+ rootScope: roots,
497
+ reportOnly: new Set([file]),
488
498
  ...(patchLint.checkJsTestShim !== undefined
489
499
  ? { extraShimPath: patchLint.checkJsTestShim }
490
500
  : {}),
@@ -10,7 +10,7 @@
10
10
  * module.
11
11
  */
12
12
  import type { PatchLintIssue, PatchMetadata } from '../types/commands/index.js';
13
- import type { FireForgeConfig, PatchPolicyConfig } from '../types/config.js';
13
+ import type { FireForgeConfig, PatchLintTokenScale, PatchPolicyConfig } from '../types/config.js';
14
14
  import type { ForwardRegistrationScope } from './patch-lint-forward-registration-extended.js';
15
15
  /**
16
16
  * One patch's contribution to {@link PatchQueueContext}.
@@ -82,6 +82,8 @@ export interface PatchQueueContext {
82
82
  * `patchLint.forwardRegistration`. Absent = `support-files` only.
83
83
  */
84
84
  forwardRegistration?: ForwardRegistrationScope;
85
+ /** `patchLint.tokenScales`, for the scales' `minFiles` floors. */
86
+ tokenScales?: PatchLintTokenScale[];
85
87
  }
86
88
  /**
87
89
  * Builds a {@link PatchQueueContext} by reading every .patch file in the
@@ -21,6 +21,7 @@ import { detectNewFilesInDiff, extractAddedLinesPerFile } from './patch-lint-dif
21
21
  import { lintPatchQueueForwardRegistrations } from './patch-lint-forward-registration.js';
22
22
  import { lintPatchQueueModuleRegistrations } from './patch-lint-module-registration.js';
23
23
  import { describeRegistrationFailure, findStagedRegistrationFailure, isLaterOwner, quoteRegistrationLine, STAGED_DEPENDENCY_REASON_PLACEHOLDER, stagedDependencyUnusedFingerprint, } from './patch-lint-staged-registration.js';
24
+ import { lintTokenScaleFloors } from './patch-lint-token-scale.js';
24
25
  import { loadPatchesManifest } from './patch-manifest-io.js';
25
26
  import { categoryRangeForOrder, categoryRangeLabel } from './patch-policy.js';
26
27
  import { extractNewFileContentsFromDiff } from './patch-transform.js';
@@ -88,6 +89,9 @@ export async function buildPatchQueueContext(patchesDir, config) {
88
89
  ...(config?.patchLint?.forwardRegistration !== undefined
89
90
  ? { forwardRegistration: config.patchLint.forwardRegistration }
90
91
  : {}),
92
+ ...(config?.patchLint?.tokenScales !== undefined
93
+ ? { tokenScales: config.patchLint.tokenScales }
94
+ : {}),
91
95
  };
92
96
  }
93
97
  // The creators map (split out of `lintPatchQueueDuplicateCreations` so
@@ -581,5 +585,6 @@ export function lintPatchQueue(ctx) {
581
585
  ...lintPatchQueueModuleRegistrations(ctx),
582
586
  ...lintPatchQueueForwardRegistrations(ctx),
583
587
  ...lintPatchQueueBinaryBodies(ctx),
588
+ ...lintTokenScaleFloors(ctx.entries.flatMap((entry) => [...entry.newFiles]), ctx.tokenScales ?? []),
584
589
  ];
585
590
  }
@@ -43,16 +43,20 @@ async function loadCssTokenContext(repoDir) {
43
43
  * matching how a CSS parser treats it.
44
44
  */
45
45
  export function maskCssComments(source) {
46
- const masked = source.replace(/\/\*[\s\S]*?\*\//g, (m) => m.replace(/[^\n]/g, ' '));
47
- const openerIndex = masked.indexOf('/*');
48
- if (openerIndex === -1)
49
- return masked;
50
- return (masked.slice(0, openerIndex) +
51
- masked
52
- .slice(openerIndex)
53
- .split('\n')
54
- .map((line) => ' '.repeat(line.length))
55
- .join('\n'));
46
+ // Linear indexOf scan rather than a lazy `/\*[\s\S]*?\*\/` regex: with
47
+ // many openers and no closer, the regex retries from every `/*` to EOF
48
+ // (quadratic in file size).
49
+ let masked = '';
50
+ let cursor = 0;
51
+ for (;;) {
52
+ const open = source.indexOf('/*', cursor);
53
+ if (open === -1)
54
+ return masked + source.slice(cursor);
55
+ const close = source.indexOf('*/', open + 2);
56
+ const end = close === -1 ? source.length : close + 2;
57
+ masked += source.slice(cursor, open) + source.slice(open, end).replace(/[^\n]/g, ' ');
58
+ cursor = end;
59
+ }
56
60
  }
57
61
  const RAW_COLOR_IGNORE_MARKER = 'fireforge-ignore: raw-color-value';
58
62
  /**
@@ -24,6 +24,11 @@ export interface ForwardRegistration {
24
24
  /** Paste-and-run declaration that records the stage as intentional. */
25
25
  command: string;
26
26
  }
27
+ /**
28
+ * jar target → packaged source, over every jar.mn line the queue adds. Only
29
+ * exact (wildcard-free) sources can back a chrome URL lookup.
30
+ */
31
+ export declare function buildJarTargetIndex(entries: readonly PatchQueueForwardRegistrationEntry[]): Map<string, string>;
27
32
  /** True for a jar.mn, moz.build or test manifest, the carriers {@link resolveCarrierReferences} reads. */
28
33
  export declare function isRegistrationCarrier(file: string): boolean;
29
34
  /**
@@ -116,7 +116,7 @@ function testManifestReferences(file, content) {
116
116
  * jar target → packaged source, over every jar.mn line the queue adds. Only
117
117
  * exact (wildcard-free) sources can back a chrome URL lookup.
118
118
  */
119
- function buildJarTargetIndex(entries) {
119
+ export function buildJarTargetIndex(entries) {
120
120
  const index = new Map();
121
121
  for (const entry of entries) {
122
122
  for (const [file, content] of [...entry.newFiles, ...entry.modifiedFileAdditions]) {
@@ -13,7 +13,7 @@
13
13
  * (export, re-export, per-patch and aggregate lint, split, move-files)
14
14
  * shares one reading of an entry, and so `patch-lint.ts` only calls into it.
15
15
  */
16
- import type { LintIgnoreCeiling, LintIgnoreEntry, PatchLintIssue } from '../types/commands/index.js';
16
+ import type { LintIgnoreCeiling, LintIgnoreEntry, PatchLintIssue, PatchSizeShare } from '../types/commands/index.js';
17
17
  /**
18
18
  * The size rules whose findings carry a `measurement`, and therefore the
19
19
  * only rules a ceiling can bound. A ceiling on any other rule could never
@@ -22,7 +22,7 @@ import type { LintIgnoreCeiling, LintIgnoreEntry, PatchLintIssue } from '../type
22
22
  export declare const LINT_IGNORE_CEILING_RULES: readonly string[];
23
23
  /**
24
24
  * A waiver filter: the bare check IDs as a set (so a plain `Set<string>`
25
- * still satisfies the type), plus the ceilings keyed by rule.
25
+ * still satisfies the type), plus the ceilings keyed by {@link ceilingKey}.
26
26
  *
27
27
  * Bare IDs and ceilings are kept apart on purpose. A caller that only knows
28
28
  * `has()` treats a ceiling-waived rule as not waived, which fails closed.
@@ -34,7 +34,10 @@ export type LintIgnoreChecks = ReadonlySet<string> & {
34
34
  export declare function isLintIgnoreCeiling(entry: LintIgnoreEntry): entry is LintIgnoreCeiling;
35
35
  /** The check ID an entry names, whatever its form. */
36
36
  export declare function lintIgnoreRule(entry: LintIgnoreEntry): string;
37
- /** One-word rendering for summaries and dry runs: `file-too-large<=1200`. */
37
+ /**
38
+ * One-word rendering for summaries and dry runs: `file-too-large<=1200`,
39
+ * `large-patch-lines[test]<=900`.
40
+ */
38
41
  export declare function formatLintIgnoreEntry(entry: LintIgnoreEntry): string;
39
42
  /** Renders a list for messages, `(empty)` when there is nothing to show. */
40
43
  export declare function formatLintIgnoreList(entries: readonly LintIgnoreEntry[]): string;
@@ -46,6 +49,9 @@ export declare function formatLintIgnoreList(entries: readonly LintIgnoreEntry[]
46
49
  * integer `max` and a non-empty `reason`, and must be the only entry for
47
50
  * its rule: a bare ID beside a ceiling for the same rule would make the
48
51
  * ceiling dead, and two ceilings would leave the effective one ambiguous.
52
+ * The one exception is `large-patch-lines`, which may carry one ceiling
53
+ * per `share` instead of a single share-less one. `meta` must be a JSON
54
+ * object and is kept verbatim.
49
55
  *
50
56
  * @param raw - The value under `lintIgnore`
51
57
  * @param label - Field label for error messages, e.g. `patches[3].lintIgnore`
@@ -70,15 +76,18 @@ export declare function lintIgnoreCacheTokens(checks: LintIgnoreChecks | undefin
70
76
  * semantics `export` / `re-export --lint-ignore` have always had. A bare ID
71
77
  * whose rule already has an entry (bare or ceiling) is a no-op: widening a
72
78
  * reviewed ceiling to an unbounded waiver is `patch lint-ignore`'s job, where
73
- * it is confirmed explicitly.
79
+ * it is confirmed explicitly. Ceilings deduplicate by rule and share, so a
80
+ * rule's per-share ceilings all survive.
74
81
  *
75
82
  * @returns The merged list, or undefined when it is empty
76
83
  */
77
84
  export declare function mergeLintIgnoreIds(existing: readonly LintIgnoreEntry[] | undefined, ids: readonly string[] | undefined): LintIgnoreEntry[] | undefined;
78
85
  /**
79
- * Adds or replaces entries by rule, the `patch lint-ignore --add` semantics:
80
- * an explicit `--add <rule>` turns a ceiling into a bare waiver, and
81
- * `--add <rule> --max <n>` sets or moves the ceiling.
86
+ * Adds or replaces entries, the `patch lint-ignore --add` semantics: an
87
+ * explicit `--add <rule>` turns a rule's ceilings into a bare waiver,
88
+ * `--add <rule> --max <n>` sets or moves the rule's ceiling, and a
89
+ * share-scoped ceiling replaces only its own share (plus any bare or
90
+ * share-less entry for the rule, which it would contradict).
82
91
  *
83
92
  * @returns The new list, or undefined when it is empty
84
93
  */
@@ -120,16 +129,43 @@ export interface LintIgnoreCeilingStatus {
120
129
  rule: string;
121
130
  max: number;
122
131
  reason: string;
132
+ /** The share the ceiling bounds, when it is share-scoped. */
133
+ share?: PatchSizeShare;
134
+ /** The ceiling's `meta`, verbatim, when it has one. */
135
+ meta?: Record<string, unknown>;
123
136
  /** Largest current measurement for the rule, null when none was taken. */
124
137
  measurement: number | null;
125
138
  /**
126
- * `exceeded`: a finding measured past `max` and surfaced.
139
+ * `exceeded`: a warning- or error-band finding measured past `max` and
140
+ * surfaced. A notice never exceeds a ceiling: it gates nothing.
127
141
  * `removable`: the rule no longer reaches its own warning band, so the
128
142
  * waiver changes no gate and can be dropped.
129
143
  * `within`: the waiver is doing its job.
130
144
  */
131
145
  state: LintIgnoreCeilingState;
132
146
  }
147
+ /**
148
+ * One waiver's standing, bare or ceiling, as the report's
149
+ * `lintIgnoreWaivers` records it. A bare waiver has `max: null`; its
150
+ * `state` is `within` while the rule still finds something to suppress at
151
+ * warning band or above, and `removable` otherwise (informational: a bare
152
+ * waiver of a rule this lint does not run reads as removable too).
153
+ */
154
+ export interface LintIgnoreWaiverStatus {
155
+ kind: 'bare' | 'ceiling';
156
+ rule: string;
157
+ max: number | null;
158
+ reason: string | null;
159
+ share?: PatchSizeShare;
160
+ meta?: Record<string, unknown>;
161
+ measurement: number | null;
162
+ state: LintIgnoreCeilingState;
163
+ }
164
+ /** Patch-level measurements a size rule falls back to when it did not fire. */
165
+ interface PatchMeasurements {
166
+ lines: number;
167
+ files: number;
168
+ }
133
169
  /**
134
170
  * Evaluates each ceiling on a patch against the findings its lint produced
135
171
  * (both surfaced and suppressed).
@@ -140,13 +176,21 @@ export interface LintIgnoreCeilingStatus {
140
176
  * patch-size rule did not fire at all, so the report still shows the
141
177
  * current number
142
178
  */
143
- export declare function evaluateLintIgnoreCeilings(entries: readonly LintIgnoreEntry[] | undefined, issues: readonly PatchLintIssue[], patchMeasurements: {
144
- lines: number;
145
- files: number;
146
- }): LintIgnoreCeilingStatus[];
179
+ export declare function evaluateLintIgnoreCeilings(entries: readonly LintIgnoreEntry[] | undefined, issues: readonly PatchLintIssue[], patchMeasurements: PatchMeasurements): LintIgnoreCeilingStatus[];
180
+ /**
181
+ * Evaluates every waiver on a patch, bare IDs included, so a waiver audit
182
+ * reads each one's current measurement from the report instead of
183
+ * re-measuring bare waivers from `suppressedIssues`.
184
+ *
185
+ * @param entries - The patch's `lintIgnore`
186
+ * @param issues - Every finding of the patch's lint, surfaced and suppressed
187
+ * @param patchMeasurements - See {@link evaluateLintIgnoreCeilings}
188
+ */
189
+ export declare function evaluateLintIgnoreWaivers(entries: readonly LintIgnoreEntry[] | undefined, issues: readonly PatchLintIssue[], patchMeasurements: PatchMeasurements): LintIgnoreWaiverStatus[];
147
190
  /**
148
191
  * Notice-severity findings for ceilings that are no longer needed, so the
149
192
  * waiver's removal is prompted by the tool that enforces it rather than
150
193
  * discovered by hand.
151
194
  */
152
195
  export declare function removableCeilingIssues(patchFilename: string, statuses: readonly LintIgnoreCeilingStatus[]): PatchLintIssue[];
196
+ export {};