@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.
- package/CHANGELOG.md +67 -0
- package/dist/build-info.json +4 -4
- package/dist/src/commands/check-report.d.ts +17 -4
- package/dist/src/commands/check-report.js +19 -6
- package/dist/src/commands/check-run.d.ts +5 -0
- package/dist/src/commands/check-run.js +9 -1
- package/dist/src/commands/check-steps.d.ts +8 -0
- package/dist/src/commands/check-steps.js +31 -6
- package/dist/src/commands/check.js +1 -1
- package/dist/src/commands/declarations-report.d.ts +43 -0
- package/dist/src/commands/declarations-report.js +76 -0
- package/dist/src/commands/export-placement-gate.js +8 -0
- package/dist/src/commands/furnace/rename-registrations.js +7 -2
- package/dist/src/commands/furnace/validate.js +26 -1
- package/dist/src/commands/lint-per-patch.js +6 -2
- package/dist/src/commands/lint-per-run-checkjs.js +2 -2
- package/dist/src/commands/lint-report.js +7 -2
- package/dist/src/commands/manifest.js +2 -0
- package/dist/src/commands/park.d.ts +22 -0
- package/dist/src/commands/park.js +232 -0
- package/dist/src/commands/patch/delete.js +11 -6
- package/dist/src/commands/patch/index.d.ts +3 -3
- package/dist/src/commands/patch/index.js +8 -4
- package/dist/src/commands/patch/lint-ignore-from.d.ts +44 -0
- package/dist/src/commands/patch/lint-ignore-from.js +142 -0
- package/dist/src/commands/patch/lint-ignore.js +39 -29
- package/dist/src/commands/patch/move-files-create.js +11 -4
- package/dist/src/commands/patch/move-files-into.js +10 -4
- package/dist/src/commands/patch/move-files.js +3 -1
- package/dist/src/commands/patch/removal-created-files.d.ts +48 -0
- package/dist/src/commands/patch/removal-created-files.js +83 -0
- package/dist/src/commands/patch/rename.js +15 -3
- package/dist/src/commands/patch/reserve.d.ts +33 -0
- package/dist/src/commands/patch/reserve.js +152 -0
- package/dist/src/commands/patch/retire.js +11 -6
- package/dist/src/commands/patch/split-plan.d.ts +10 -1
- package/dist/src/commands/patch/split-plan.js +16 -1
- package/dist/src/commands/patch/split.js +14 -5
- package/dist/src/commands/patch/stage.d.ts +34 -0
- package/dist/src/commands/patch/stage.js +153 -0
- package/dist/src/commands/patch/staged-dependency-remove.d.ts +31 -0
- package/dist/src/commands/patch/staged-dependency-remove.js +80 -0
- package/dist/src/commands/patch/staged-dependency.js +40 -98
- package/dist/src/commands/re-export-adjacent.d.ts +5 -0
- package/dist/src/commands/re-export-adjacent.js +4 -3
- package/dist/src/commands/re-export-bulk-scan.d.ts +2 -1
- package/dist/src/commands/re-export-bulk-scan.js +22 -7
- package/dist/src/commands/re-export-hunks.d.ts +35 -0
- package/dist/src/commands/re-export-hunks.js +220 -0
- package/dist/src/commands/re-export-options.js +29 -2
- package/dist/src/commands/re-export-purity-scope.d.ts +18 -0
- package/dist/src/commands/re-export-purity-scope.js +131 -0
- package/dist/src/commands/re-export-register.js +15 -1
- package/dist/src/commands/re-export-removed.d.ts +1 -1
- package/dist/src/commands/re-export-removed.js +17 -2
- package/dist/src/commands/re-export-scan.d.ts +2 -0
- package/dist/src/commands/re-export-scan.js +4 -1
- package/dist/src/commands/re-export-single.js +102 -42
- package/dist/src/commands/re-export-stale-registrations.d.ts +18 -0
- package/dist/src/commands/re-export-stale-registrations.js +62 -0
- package/dist/src/commands/re-export.js +35 -34
- package/dist/src/commands/status-output.js +5 -1
- package/dist/src/commands/test-build-furnace.d.ts +3 -2
- package/dist/src/commands/test-build-furnace.js +8 -2
- package/dist/src/commands/test-build-phase.d.ts +2 -0
- package/dist/src/commands/test-build-phase.js +34 -17
- package/dist/src/commands/test-checkjs.js +3 -2
- package/dist/src/commands/test-dispatch.d.ts +39 -0
- package/dist/src/commands/test-dispatch.js +220 -0
- package/dist/src/commands/test-furnace-reach.d.ts +37 -0
- package/dist/src/commands/test-furnace-reach.js +132 -0
- package/dist/src/commands/test-orchestrate.d.ts +14 -0
- package/dist/src/commands/test-orchestrate.js +25 -4
- package/dist/src/commands/test-perf-scope.d.ts +21 -0
- package/dist/src/commands/test-perf-scope.js +55 -0
- package/dist/src/commands/test-prelock.js +100 -4
- package/dist/src/commands/test-register.js +18 -3
- package/dist/src/commands/test-results.d.ts +62 -0
- package/dist/src/commands/test-results.js +62 -0
- package/dist/src/commands/test-run.d.ts +13 -55
- package/dist/src/commands/test-run.js +73 -101
- package/dist/src/commands/test-shards.d.ts +110 -0
- package/dist/src/commands/test-shards.js +255 -0
- package/dist/src/commands/test-stale-gate.d.ts +5 -1
- package/dist/src/commands/test-stale-gate.js +11 -2
- package/dist/src/commands/test-verdict.d.ts +2 -1
- package/dist/src/commands/test.d.ts +1 -1
- package/dist/src/commands/test.js +68 -75
- package/dist/src/commands/token-lint.js +48 -8
- package/dist/src/commands/verify.js +9 -2
- package/dist/src/core/build-baseline-types.d.ts +13 -0
- package/dist/src/core/build-baseline-validate.js +9 -0
- package/dist/src/core/build-baseline.js +7 -0
- package/dist/src/core/build-prepare.d.ts +6 -0
- package/dist/src/core/build-prepare.js +29 -3
- package/dist/src/core/config-paths.d.ts +1 -1
- package/dist/src/core/config-paths.js +2 -0
- package/dist/src/core/config-validate-check.js +83 -7
- package/dist/src/core/config-validate-test-toolchains.js +14 -0
- package/dist/src/core/config-validate-token-scales.d.ts +3 -0
- package/dist/src/core/config-validate-token-scales.js +47 -5
- package/dist/src/core/config-validate.js +6 -0
- package/dist/src/core/coverage-extend.js +2 -2
- package/dist/src/core/coverage-records.d.ts +11 -0
- package/dist/src/core/coverage-records.js +34 -0
- package/dist/src/core/engine-session-lock.d.ts +6 -0
- package/dist/src/core/engine-session-lock.js +10 -2
- package/dist/src/core/file-lock-shared.d.ts +57 -0
- package/dist/src/core/file-lock-shared.js +117 -0
- package/dist/src/core/file-lock.d.ts +9 -0
- package/dist/src/core/file-lock.js +58 -2
- package/dist/src/core/furnace-apply.js +10 -10
- package/dist/src/core/furnace-config-validate-exceptions.d.ts +11 -3
- package/dist/src/core/furnace-config-validate-exceptions.js +59 -8
- package/dist/src/core/furnace-config-validate.js +7 -1
- package/dist/src/core/furnace-registration-jar-inplace.d.ts +12 -0
- package/dist/src/core/furnace-registration-jar-inplace.js +80 -0
- package/dist/src/core/furnace-validate-accessibility.d.ts +5 -3
- package/dist/src/core/furnace-validate-accessibility.js +75 -30
- package/dist/src/core/furnace-validate-exceptions.d.ts +13 -4
- package/dist/src/core/furnace-validate-exceptions.js +59 -4
- package/dist/src/core/furnace-validate-icon-button.js +30 -1
- package/dist/src/core/history-log-file.js +8 -1
- package/dist/src/core/line-prefixer.d.ts +18 -0
- package/dist/src/core/line-prefixer.js +34 -0
- package/dist/src/core/mach.d.ts +7 -0
- package/dist/src/core/mach.js +24 -9
- package/dist/src/core/module-resolution-preflight.d.ts +19 -3
- package/dist/src/core/module-resolution-preflight.js +24 -6
- package/dist/src/core/negative-control-compiled.d.ts +36 -0
- package/dist/src/core/negative-control-compiled.js +87 -0
- package/dist/src/core/negative-control-diff.d.ts +14 -2
- package/dist/src/core/negative-control-diff.js +49 -6
- package/dist/src/core/negative-control.d.ts +12 -0
- package/dist/src/core/negative-control.js +48 -5
- package/dist/src/core/park-store.d.ts +63 -0
- package/dist/src/core/park-store.js +216 -0
- package/dist/src/core/patch-export-update.d.ts +4 -0
- package/dist/src/core/patch-export-update.js +12 -3
- package/dist/src/core/patch-export.d.ts +3 -2
- package/dist/src/core/patch-export.js +21 -14
- package/dist/src/core/patch-files.js +26 -8
- package/dist/src/core/patch-lint-checkjs-any-import.d.ts +6 -4
- package/dist/src/core/patch-lint-checkjs-any-import.js +9 -7
- package/dist/src/core/patch-lint-checkjs-diagnostics.d.ts +17 -0
- package/dist/src/core/patch-lint-checkjs-diagnostics.js +32 -0
- package/dist/src/core/patch-lint-checkjs.d.ts +10 -1
- package/dist/src/core/patch-lint-checkjs.js +13 -3
- package/dist/src/core/patch-lint-cross.d.ts +3 -1
- package/dist/src/core/patch-lint-cross.js +5 -0
- package/dist/src/core/patch-lint-css.js +14 -10
- package/dist/src/core/patch-lint-forward-registration-extended.d.ts +5 -0
- package/dist/src/core/patch-lint-forward-registration-extended.js +1 -1
- package/dist/src/core/patch-lint-ignore.d.ts +56 -12
- package/dist/src/core/patch-lint-ignore.js +173 -43
- package/dist/src/core/patch-lint-ownership.d.ts +10 -0
- package/dist/src/core/patch-lint-ownership.js +26 -0
- package/dist/src/core/patch-lint-size.js +9 -1
- package/dist/src/core/patch-lint-token-scale.d.ts +26 -8
- package/dist/src/core/patch-lint-token-scale.js +206 -29
- package/dist/src/core/patch-lint.js +2 -2
- package/dist/src/core/patch-manifest-io.js +8 -1
- package/dist/src/core/patch-manifest-key-order.d.ts +24 -0
- package/dist/src/core/patch-manifest-key-order.js +61 -0
- package/dist/src/core/patch-manifest-stage.d.ts +46 -0
- package/dist/src/core/patch-manifest-stage.js +96 -0
- package/dist/src/core/patch-manifest-validate.js +27 -1
- package/dist/src/core/patch-order-legal.d.ts +2 -1
- package/dist/src/core/patch-order-legal.js +7 -2
- package/dist/src/core/patch-policy.d.ts +6 -2
- package/dist/src/core/patch-policy.js +14 -7
- package/dist/src/core/patch-retired.d.ts +26 -4
- package/dist/src/core/patch-retired.js +40 -2
- package/dist/src/core/run-log.d.ts +6 -0
- package/dist/src/core/run-log.js +17 -1
- package/dist/src/core/test-harness-crash.d.ts +2 -1
- package/dist/src/core/test-harness-crash.js +5 -8
- package/dist/src/core/test-harness-signature.d.ts +16 -0
- package/dist/src/core/test-harness-signature.js +19 -1
- package/dist/src/core/test-raw-log.d.ts +66 -0
- package/dist/src/core/test-raw-log.js +122 -0
- package/dist/src/core/test-run-completeness.d.ts +47 -7
- package/dist/src/core/test-run-completeness.js +70 -23
- package/dist/src/core/test-stale-check.d.ts +10 -1
- package/dist/src/core/test-stale-check.js +15 -1
- package/dist/src/core/test-xpcshell-retry.d.ts +2 -0
- package/dist/src/core/test-xpcshell-retry.js +2 -1
- package/dist/src/core/token-lint.d.ts +5 -2
- package/dist/src/core/token-lint.js +8 -3
- package/dist/src/core/token-sibling-sheets.d.ts +46 -0
- package/dist/src/core/token-sibling-sheets.js +119 -0
- package/dist/src/core/tree-guard.js +2 -0
- package/dist/src/core/typecheck-shim.d.ts +6 -1
- package/dist/src/core/typecheck-shim.js +139 -2
- package/dist/src/core/typecheck.js +3 -1
- package/dist/src/index.d.ts +9 -3
- package/dist/src/index.js +4 -1
- package/dist/src/types/commands/index.d.ts +2 -2
- package/dist/src/types/commands/options.d.ts +68 -7
- package/dist/src/types/commands/patches.d.ts +43 -0
- package/dist/src/types/config.d.ts +74 -2
- package/dist/src/types/furnace.d.ts +29 -0
- package/dist/src/types/index.d.ts +1 -1
- package/dist/src/utils/options.d.ts +3 -2
- package/dist/src/utils/options.js +9 -4
- package/docs/configuration.md +110 -9
- package/docs/furnace.md +61 -1
- package/docs/lifecycle-invariants.md +13 -11
- package/docs/machine-output.md +68 -18
- package/docs/patch-workflow.md +174 -13
- package/docs/testing.md +89 -5
- 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
|
-
|
|
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 =
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
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
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
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
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
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
|
-
'
|
|
39
|
-
'
|
|
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,
|
|
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
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
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
|
|
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
|
-
/**
|
|
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
|
|
80
|
-
*
|
|
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
|
|
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
|
-
|
|
145
|
-
|
|
146
|
-
|
|
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 {};
|