@hominis/fireforge 0.50.0 → 0.51.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 +47 -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/test-build-furnace.d.ts +3 -2
- package/dist/src/commands/test-build-furnace.js +8 -2
- package/dist/src/commands/test-build-phase.js +24 -7
- 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 +211 -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 +9 -0
- package/dist/src/commands/test-orchestrate.js +22 -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 +4 -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 +65 -75
- package/dist/src/commands/token-lint.js +48 -8
- package/dist/src/commands/verify.js +9 -2
- 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 +10 -3
- package/dist/src/core/furnace-config-validate-exceptions.js +39 -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 +4 -2
- package/dist/src/core/furnace-validate-accessibility.js +61 -27
- package/dist/src/core/furnace-validate-exceptions.d.ts +12 -4
- package/dist/src/core/furnace-validate-exceptions.js +41 -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 +27 -0
- package/dist/src/core/negative-control-compiled.js +73 -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 +36 -3
- package/dist/src/core/test-run-completeness.js +57 -17
- 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 +5 -1
- package/dist/src/core/typecheck-shim.js +115 -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 +20 -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 +94 -9
- package/docs/furnace.md +43 -1
- package/docs/lifecycle-invariants.md +13 -11
- package/docs/machine-output.md +64 -18
- package/docs/patch-workflow.md +174 -13
- package/docs/testing.md +73 -4
- package/package.json +3 -3
|
@@ -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 {};
|
|
@@ -24,6 +24,16 @@ export const LINT_IGNORE_CEILING_RULES = [
|
|
|
24
24
|
'large-patch-lines',
|
|
25
25
|
'large-patch-files',
|
|
26
26
|
];
|
|
27
|
+
/** The only rule whose findings carry a {@link PatchSizeShare}. */
|
|
28
|
+
const SHARE_RULE = 'large-patch-lines';
|
|
29
|
+
const SHARES = ['product', 'test'];
|
|
30
|
+
/**
|
|
31
|
+
* The key a ceiling is stored under: the rule, plus `#<share>` for a
|
|
32
|
+
* share-scoped ceiling, so one rule can carry a ceiling per share.
|
|
33
|
+
*/
|
|
34
|
+
function ceilingKey(rule, share) {
|
|
35
|
+
return share === undefined ? rule : `${rule}#${share}`;
|
|
36
|
+
}
|
|
27
37
|
/** Narrows an entry to the ceiling form. */
|
|
28
38
|
export function isLintIgnoreCeiling(entry) {
|
|
29
39
|
return typeof entry !== 'string';
|
|
@@ -32,9 +42,19 @@ export function isLintIgnoreCeiling(entry) {
|
|
|
32
42
|
export function lintIgnoreRule(entry) {
|
|
33
43
|
return isLintIgnoreCeiling(entry) ? entry.rule : entry;
|
|
34
44
|
}
|
|
35
|
-
/**
|
|
45
|
+
/**
|
|
46
|
+
* One-word rendering for summaries and dry runs: `file-too-large<=1200`,
|
|
47
|
+
* `large-patch-lines[test]<=900`.
|
|
48
|
+
*/
|
|
36
49
|
export function formatLintIgnoreEntry(entry) {
|
|
37
|
-
|
|
50
|
+
if (!isLintIgnoreCeiling(entry))
|
|
51
|
+
return entry;
|
|
52
|
+
const share = entry.share === undefined ? '' : `[${entry.share}]`;
|
|
53
|
+
return `${entry.rule}${share}<=${String(entry.max)}`;
|
|
54
|
+
}
|
|
55
|
+
/** The identity an entry is upserted and deduplicated by. */
|
|
56
|
+
function entryKey(entry) {
|
|
57
|
+
return isLintIgnoreCeiling(entry) ? ceilingKey(entry.rule, entry.share) : entry;
|
|
38
58
|
}
|
|
39
59
|
/** Renders a list for messages, `(empty)` when there is nothing to show. */
|
|
40
60
|
export function formatLintIgnoreList(entries) {
|
|
@@ -43,7 +63,11 @@ export function formatLintIgnoreList(entries) {
|
|
|
43
63
|
function sameEntry(a, b) {
|
|
44
64
|
if (!isLintIgnoreCeiling(a) || !isLintIgnoreCeiling(b))
|
|
45
65
|
return a === b;
|
|
46
|
-
return a.rule === b.rule &&
|
|
66
|
+
return (a.rule === b.rule &&
|
|
67
|
+
a.max === b.max &&
|
|
68
|
+
a.reason === b.reason &&
|
|
69
|
+
a.share === b.share &&
|
|
70
|
+
JSON.stringify(a.meta) === JSON.stringify(b.meta));
|
|
47
71
|
}
|
|
48
72
|
/**
|
|
49
73
|
* Validates a raw `lintIgnore` value from `patches.json`.
|
|
@@ -53,6 +77,9 @@ function sameEntry(a, b) {
|
|
|
53
77
|
* integer `max` and a non-empty `reason`, and must be the only entry for
|
|
54
78
|
* its rule: a bare ID beside a ceiling for the same rule would make the
|
|
55
79
|
* ceiling dead, and two ceilings would leave the effective one ambiguous.
|
|
80
|
+
* The one exception is `large-patch-lines`, which may carry one ceiling
|
|
81
|
+
* per `share` instead of a single share-less one. `meta` must be a JSON
|
|
82
|
+
* object and is kept verbatim.
|
|
56
83
|
*
|
|
57
84
|
* @param raw - The value under `lintIgnore`
|
|
58
85
|
* @param label - Field label for error messages, e.g. `patches[3].lintIgnore`
|
|
@@ -73,13 +100,21 @@ export function parseLintIgnoreEntries(raw, label) {
|
|
|
73
100
|
}
|
|
74
101
|
entries.push(parseCeiling(item, itemLabel));
|
|
75
102
|
}
|
|
103
|
+
const sharedRules = new Set();
|
|
76
104
|
for (const entry of entries) {
|
|
77
105
|
if (!isLintIgnoreCeiling(entry))
|
|
78
106
|
continue;
|
|
79
|
-
|
|
80
|
-
|
|
107
|
+
const key = ceilingKey(entry.rule, entry.share);
|
|
108
|
+
const clash = ceilingRules.has(key) ||
|
|
109
|
+
entries.includes(entry.rule) ||
|
|
110
|
+
(entry.share === undefined ? sharedRules.has(entry.rule) : ceilingRules.has(entry.rule));
|
|
111
|
+
if (clash) {
|
|
112
|
+
throw new Error(`${label} names "${entry.rule}" more than once; keep a single entry (bare or ceiling) ` +
|
|
113
|
+
'per rule, or one ceiling per share');
|
|
81
114
|
}
|
|
82
|
-
ceilingRules.add(
|
|
115
|
+
ceilingRules.add(key);
|
|
116
|
+
if (entry.share !== undefined)
|
|
117
|
+
sharedRules.add(entry.rule);
|
|
83
118
|
}
|
|
84
119
|
return entries;
|
|
85
120
|
}
|
|
@@ -88,11 +123,11 @@ function parseCeiling(item, label) {
|
|
|
88
123
|
throw new Error(`${label} must be a check ID string or a { rule, max, reason } object`);
|
|
89
124
|
}
|
|
90
125
|
const record = item;
|
|
91
|
-
const unknownKeys = Object.keys(record).filter((key) => key
|
|
126
|
+
const unknownKeys = Object.keys(record).filter((key) => !CEILING_KEYS.has(key));
|
|
92
127
|
if (unknownKeys.length > 0) {
|
|
93
128
|
throw new Error(`${label} has unknown field(s): ${unknownKeys.join(', ')}`);
|
|
94
129
|
}
|
|
95
|
-
const { rule, max, reason } = record;
|
|
130
|
+
const { rule, max, reason, share, meta } = record;
|
|
96
131
|
if (typeof rule !== 'string' || !LINT_IGNORE_CEILING_RULES.includes(rule)) {
|
|
97
132
|
throw new Error(`${label}.rule must be one of the measured size rules: ${LINT_IGNORE_CEILING_RULES.join(', ')}`);
|
|
98
133
|
}
|
|
@@ -102,8 +137,22 @@ function parseCeiling(item, label) {
|
|
|
102
137
|
if (typeof reason !== 'string' || reason.trim() === '') {
|
|
103
138
|
throw new Error(`${label}.reason must be a non-empty string`);
|
|
104
139
|
}
|
|
105
|
-
|
|
140
|
+
const ceiling = { rule, max, reason };
|
|
141
|
+
if (share !== undefined) {
|
|
142
|
+
if (rule !== SHARE_RULE || !SHARES.includes(share)) {
|
|
143
|
+
throw new Error(`${label}.share must be "product" or "test", and only on ${SHARE_RULE}`);
|
|
144
|
+
}
|
|
145
|
+
ceiling.share = share;
|
|
146
|
+
}
|
|
147
|
+
if (meta !== undefined) {
|
|
148
|
+
if (meta === null || typeof meta !== 'object' || Array.isArray(meta)) {
|
|
149
|
+
throw new Error(`${label}.meta must be a JSON object`);
|
|
150
|
+
}
|
|
151
|
+
ceiling.meta = meta;
|
|
152
|
+
}
|
|
153
|
+
return ceiling;
|
|
106
154
|
}
|
|
155
|
+
const CEILING_KEYS = new Set(['rule', 'max', 'reason', 'share', 'meta']);
|
|
107
156
|
/**
|
|
108
157
|
* Builds the waiver filter for a patch's entries.
|
|
109
158
|
*
|
|
@@ -117,7 +166,7 @@ export function buildLintIgnoreChecks(entries) {
|
|
|
117
166
|
const ceilings = new Map();
|
|
118
167
|
for (const entry of entries) {
|
|
119
168
|
if (isLintIgnoreCeiling(entry))
|
|
120
|
-
ceilings.set(entry.rule, entry);
|
|
169
|
+
ceilings.set(ceilingKey(entry.rule, entry.share), entry);
|
|
121
170
|
else
|
|
122
171
|
plain.add(entry);
|
|
123
172
|
}
|
|
@@ -138,38 +187,52 @@ export function lintIgnoreCacheTokens(checks) {
|
|
|
138
187
|
* semantics `export` / `re-export --lint-ignore` have always had. A bare ID
|
|
139
188
|
* whose rule already has an entry (bare or ceiling) is a no-op: widening a
|
|
140
189
|
* reviewed ceiling to an unbounded waiver is `patch lint-ignore`'s job, where
|
|
141
|
-
* it is confirmed explicitly.
|
|
190
|
+
* it is confirmed explicitly. Ceilings deduplicate by rule and share, so a
|
|
191
|
+
* rule's per-share ceilings all survive.
|
|
142
192
|
*
|
|
143
193
|
* @returns The merged list, or undefined when it is empty
|
|
144
194
|
*/
|
|
145
195
|
export function mergeLintIgnoreIds(existing, ids) {
|
|
146
196
|
const merged = [];
|
|
197
|
+
const keys = new Set();
|
|
147
198
|
const rules = new Set();
|
|
148
199
|
for (const entry of [...(existing ?? []), ...(ids ?? [])]) {
|
|
149
|
-
const
|
|
150
|
-
if (
|
|
200
|
+
const blocked = isLintIgnoreCeiling(entry) ? keys.has(entryKey(entry)) : rules.has(entry);
|
|
201
|
+
if (blocked)
|
|
151
202
|
continue;
|
|
152
|
-
|
|
203
|
+
keys.add(entryKey(entry));
|
|
204
|
+
rules.add(lintIgnoreRule(entry));
|
|
153
205
|
merged.push(entry);
|
|
154
206
|
}
|
|
155
207
|
return merged.length > 0 ? merged : undefined;
|
|
156
208
|
}
|
|
157
209
|
/**
|
|
158
|
-
* Adds or replaces entries
|
|
159
|
-
*
|
|
160
|
-
* `--add <rule> --max <n>` sets or moves the ceiling
|
|
210
|
+
* Adds or replaces entries, the `patch lint-ignore --add` semantics: an
|
|
211
|
+
* explicit `--add <rule>` turns a rule's ceilings into a bare waiver,
|
|
212
|
+
* `--add <rule> --max <n>` sets or moves the rule's ceiling, and a
|
|
213
|
+
* share-scoped ceiling replaces only its own share (plus any bare or
|
|
214
|
+
* share-less entry for the rule, which it would contradict).
|
|
161
215
|
*
|
|
162
216
|
* @returns The new list, or undefined when it is empty
|
|
163
217
|
*/
|
|
164
218
|
export function upsertLintIgnoreEntries(existing, additions) {
|
|
165
|
-
|
|
219
|
+
let next = [...existing];
|
|
166
220
|
for (const addition of additions) {
|
|
167
221
|
const rule = lintIgnoreRule(addition);
|
|
168
|
-
const
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
222
|
+
const scoped = isLintIgnoreCeiling(addition) && addition.share !== undefined;
|
|
223
|
+
const replaced = (entry) => lintIgnoreRule(entry) === rule &&
|
|
224
|
+
(!scoped ||
|
|
225
|
+
!isLintIgnoreCeiling(entry) ||
|
|
226
|
+
entry.share === undefined ||
|
|
227
|
+
entryKey(entry) === entryKey(addition));
|
|
228
|
+
const index = next.findIndex(replaced);
|
|
229
|
+
const kept = next.filter((entry) => !replaced(entry));
|
|
230
|
+
// The addition takes the first replaced entry's place, so a moved
|
|
231
|
+
// ceiling keeps its position in the list.
|
|
232
|
+
next =
|
|
233
|
+
index === -1
|
|
234
|
+
? [...kept, addition]
|
|
235
|
+
: [...kept.slice(0, index), addition, ...kept.slice(index)];
|
|
173
236
|
}
|
|
174
237
|
return mergeLintIgnoreIds(next, undefined);
|
|
175
238
|
}
|
|
@@ -200,7 +263,7 @@ export function partitionLintIgnoredIssues(issues, checks) {
|
|
|
200
263
|
suppressed.push(issue);
|
|
201
264
|
continue;
|
|
202
265
|
}
|
|
203
|
-
const ceiling =
|
|
266
|
+
const ceiling = ceilingFor(issue, checks);
|
|
204
267
|
if (ceiling === undefined) {
|
|
205
268
|
kept.push(issue);
|
|
206
269
|
continue;
|
|
@@ -209,12 +272,31 @@ export function partitionLintIgnoredIssues(issues, checks) {
|
|
|
209
272
|
suppressed.push(issue);
|
|
210
273
|
continue;
|
|
211
274
|
}
|
|
275
|
+
// A notice never gates, so a ceiling does not bound it: one past `max`
|
|
276
|
+
// surfaces as the plain notice it is, not as an exceeded waiver.
|
|
277
|
+
if (issue.severity === 'notice') {
|
|
278
|
+
kept.push(issue);
|
|
279
|
+
continue;
|
|
280
|
+
}
|
|
212
281
|
kept.push({ ...issue, message: `${issue.message} ${describeExceededCeiling(ceiling)}` });
|
|
213
282
|
}
|
|
214
283
|
return { kept, suppressed };
|
|
215
284
|
}
|
|
285
|
+
/** The ceiling that governs `issue`: its share's, else the rule's share-less one. */
|
|
286
|
+
function ceilingFor(issue, checks) {
|
|
287
|
+
const ceilings = checks?.ceilings;
|
|
288
|
+
if (ceilings === undefined)
|
|
289
|
+
return undefined;
|
|
290
|
+
if (issue.share !== undefined) {
|
|
291
|
+
const scoped = ceilings.get(ceilingKey(issue.check, issue.share));
|
|
292
|
+
if (scoped !== undefined)
|
|
293
|
+
return scoped;
|
|
294
|
+
}
|
|
295
|
+
return ceilings.get(issue.check);
|
|
296
|
+
}
|
|
216
297
|
function describeExceededCeiling(ceiling) {
|
|
217
|
-
|
|
298
|
+
const share = ceiling.share === undefined ? '' : ` (${ceiling.share} share)`;
|
|
299
|
+
return (`This exceeds the patch's lintIgnore ceiling for ${ceiling.rule}${share} ` +
|
|
218
300
|
`(max ${String(ceiling.max)}: ${ceiling.reason}).`);
|
|
219
301
|
}
|
|
220
302
|
/** True when `checks` waives `issue` (see {@link partitionLintIgnoredIssues}). */
|
|
@@ -242,6 +324,31 @@ export function filterLintIgnoredByOwners(issues, owners) {
|
|
|
242
324
|
return issues;
|
|
243
325
|
return issues.filter((issue) => !(byFile.get(issue.file) ?? []).some((checks) => isLintIgnored(issue, checks)));
|
|
244
326
|
}
|
|
327
|
+
function judgeWaiver(rule, max, share, issues, patchMeasurements) {
|
|
328
|
+
const findings = issues.filter((issue) => issue.check === rule && (share === undefined || issue.share === share));
|
|
329
|
+
const measured = findings
|
|
330
|
+
.map((issue) => issue.measurement)
|
|
331
|
+
.filter((value) => value !== undefined);
|
|
332
|
+
// A share-scoped ceiling has no patch-level fallback: the total counts
|
|
333
|
+
// both shares, which is not what it bounds.
|
|
334
|
+
const fallback = share !== undefined
|
|
335
|
+
? null
|
|
336
|
+
: rule === 'large-patch-lines'
|
|
337
|
+
? patchMeasurements.lines
|
|
338
|
+
: rule === 'large-patch-files'
|
|
339
|
+
? patchMeasurements.files
|
|
340
|
+
: null;
|
|
341
|
+
const measurement = measured.length > 0 ? Math.max(...measured) : fallback;
|
|
342
|
+
const gating = findings.filter((issue) => issue.severity !== 'notice');
|
|
343
|
+
const exceeded = max !== null &&
|
|
344
|
+
gating.some((issue) => issue.measurement !== undefined && issue.measurement > max);
|
|
345
|
+
const state = exceeded
|
|
346
|
+
? 'exceeded'
|
|
347
|
+
: gating.length > 0
|
|
348
|
+
? 'within'
|
|
349
|
+
: 'removable';
|
|
350
|
+
return { measurement, state };
|
|
351
|
+
}
|
|
245
352
|
/**
|
|
246
353
|
* Evaluates each ceiling on a patch against the findings its lint produced
|
|
247
354
|
* (both surfaced and suppressed).
|
|
@@ -257,26 +364,48 @@ export function evaluateLintIgnoreCeilings(entries, issues, patchMeasurements) {
|
|
|
257
364
|
for (const entry of entries ?? []) {
|
|
258
365
|
if (!isLintIgnoreCeiling(entry))
|
|
259
366
|
continue;
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
.
|
|
264
|
-
|
|
265
|
-
?
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
: null;
|
|
269
|
-
const measurement = measured.length > 0 ? Math.max(...measured) : fallback;
|
|
270
|
-
const gating = findings.some((issue) => issue.severity !== 'notice');
|
|
271
|
-
const state = measured.some((value) => value > entry.max)
|
|
272
|
-
? 'exceeded'
|
|
273
|
-
: gating
|
|
274
|
-
? 'within'
|
|
275
|
-
: 'removable';
|
|
276
|
-
statuses.push({ rule: entry.rule, max: entry.max, reason: entry.reason, measurement, state });
|
|
367
|
+
statuses.push({
|
|
368
|
+
rule: entry.rule,
|
|
369
|
+
max: entry.max,
|
|
370
|
+
reason: entry.reason,
|
|
371
|
+
...(entry.share !== undefined ? { share: entry.share } : {}),
|
|
372
|
+
...(entry.meta !== undefined ? { meta: entry.meta } : {}),
|
|
373
|
+
...judgeWaiver(entry.rule, entry.max, entry.share, issues, patchMeasurements),
|
|
374
|
+
});
|
|
277
375
|
}
|
|
278
376
|
return statuses;
|
|
279
377
|
}
|
|
378
|
+
/**
|
|
379
|
+
* Evaluates every waiver on a patch, bare IDs included, so a waiver audit
|
|
380
|
+
* reads each one's current measurement from the report instead of
|
|
381
|
+
* re-measuring bare waivers from `suppressedIssues`.
|
|
382
|
+
*
|
|
383
|
+
* @param entries - The patch's `lintIgnore`
|
|
384
|
+
* @param issues - Every finding of the patch's lint, surfaced and suppressed
|
|
385
|
+
* @param patchMeasurements - See {@link evaluateLintIgnoreCeilings}
|
|
386
|
+
*/
|
|
387
|
+
export function evaluateLintIgnoreWaivers(entries, issues, patchMeasurements) {
|
|
388
|
+
return (entries ?? []).map((entry) => {
|
|
389
|
+
if (!isLintIgnoreCeiling(entry)) {
|
|
390
|
+
return {
|
|
391
|
+
kind: 'bare',
|
|
392
|
+
rule: entry,
|
|
393
|
+
max: null,
|
|
394
|
+
reason: null,
|
|
395
|
+
...judgeWaiver(entry, null, undefined, issues, patchMeasurements),
|
|
396
|
+
};
|
|
397
|
+
}
|
|
398
|
+
return {
|
|
399
|
+
kind: 'ceiling',
|
|
400
|
+
rule: entry.rule,
|
|
401
|
+
max: entry.max,
|
|
402
|
+
reason: entry.reason,
|
|
403
|
+
...(entry.share !== undefined ? { share: entry.share } : {}),
|
|
404
|
+
...(entry.meta !== undefined ? { meta: entry.meta } : {}),
|
|
405
|
+
...judgeWaiver(entry.rule, entry.max, entry.share, issues, patchMeasurements),
|
|
406
|
+
};
|
|
407
|
+
});
|
|
408
|
+
}
|
|
280
409
|
/**
|
|
281
410
|
* Notice-severity findings for ceilings that are no longer needed, so the
|
|
282
411
|
* waiver's removal is prompted by the tool that enforces it rather than
|
|
@@ -287,10 +416,11 @@ export function removableCeilingIssues(patchFilename, statuses) {
|
|
|
287
416
|
.filter((status) => status.state === 'removable')
|
|
288
417
|
.map((status) => {
|
|
289
418
|
const now = status.measurement === null ? 'below its notice band' : `at ${String(status.measurement)}`;
|
|
419
|
+
const share = status.share === undefined ? '' : `, ${status.share} share`;
|
|
290
420
|
return {
|
|
291
421
|
file: patchFilename,
|
|
292
422
|
check: 'lint-ignore-removable',
|
|
293
|
-
message: `lintIgnore ceiling for ${status.rule} (max ${String(status.max)}) is no longer needed: ` +
|
|
423
|
+
message: `lintIgnore ceiling for ${status.rule} (max ${String(status.max)}${share}) is no longer needed: ` +
|
|
294
424
|
`the measurement is ${now}, under the rule's own warning threshold. ` +
|
|
295
425
|
`Remove it with "fireforge patch lint-ignore ${patchFilename} --remove ${status.rule}".`,
|
|
296
426
|
severity: 'notice',
|
|
@@ -51,6 +51,16 @@ export declare function resolvePatchOwnedChromeScripts(currentNewFiles: Set<stri
|
|
|
51
51
|
* `patch-lint-ownership.test.ts`.
|
|
52
52
|
*/
|
|
53
53
|
export declare function isTestScriptFile(file: string): boolean;
|
|
54
|
+
/**
|
|
55
|
+
* For each test script, the ES modules (`.mjs`, `.sys.mjs`) the queue
|
|
56
|
+
* creates up to and including the test's own patch: what its imports can
|
|
57
|
+
* resolve to in a per-test checkJs program. A test no patch touches sees
|
|
58
|
+
* every module the queue creates.
|
|
59
|
+
*
|
|
60
|
+
* @param patchQueueCtx - The queue, in apply order
|
|
61
|
+
* @returns Lookup from a test script path to its resolvable modules
|
|
62
|
+
*/
|
|
63
|
+
export declare function resolvableModulesForTests(patchQueueCtx: PatchQueueContext): (testFile: string) => ReadonlySet<string>;
|
|
54
64
|
/**
|
|
55
65
|
* Returns the set of patch-owned test `.js` files. Same
|
|
56
66
|
* ownership semantics as {@link resolvePatchOwnedSysMjs}. Consumed by the
|
|
@@ -84,6 +84,32 @@ export function isTestScriptFile(file) {
|
|
|
84
84
|
const basename = file.split('/').pop() ?? '';
|
|
85
85
|
return /^(?:browser_|test_|xpcshell_).*\.js$/.test(basename);
|
|
86
86
|
}
|
|
87
|
+
/**
|
|
88
|
+
* For each test script, the ES modules (`.mjs`, `.sys.mjs`) the queue
|
|
89
|
+
* creates up to and including the test's own patch: what its imports can
|
|
90
|
+
* resolve to in a per-test checkJs program. A test no patch touches sees
|
|
91
|
+
* every module the queue creates.
|
|
92
|
+
*
|
|
93
|
+
* @param patchQueueCtx - The queue, in apply order
|
|
94
|
+
* @returns Lookup from a test script path to its resolvable modules
|
|
95
|
+
*/
|
|
96
|
+
export function resolvableModulesForTests(patchQueueCtx) {
|
|
97
|
+
const byTest = new Map();
|
|
98
|
+
const upTo = new Set();
|
|
99
|
+
for (const entry of patchQueueCtx.entries) {
|
|
100
|
+
for (const file of entry.newFiles.keys()) {
|
|
101
|
+
if (file.endsWith('.mjs') && !isTestScriptFile(file))
|
|
102
|
+
upTo.add(file);
|
|
103
|
+
}
|
|
104
|
+
const snapshot = new Set(upTo);
|
|
105
|
+
for (const file of [...entry.newFiles.keys(), ...entry.modifiedFileAdditions.keys()]) {
|
|
106
|
+
if (isTestScriptFile(file) && !byTest.has(file))
|
|
107
|
+
byTest.set(file, snapshot);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
const all = upTo;
|
|
111
|
+
return (testFile) => byTest.get(testFile) ?? all;
|
|
112
|
+
}
|
|
87
113
|
/**
|
|
88
114
|
* Returns the set of patch-owned test `.js` files. Same
|
|
89
115
|
* ownership semantics as {@link resolvePatchOwnedSysMjs}. Consumed by the
|
|
@@ -248,19 +248,26 @@ function formatPatchSizeMessage(subject, band, thresholds) {
|
|
|
248
248
|
*/
|
|
249
249
|
function lineChecks(measurement, tier, thresholds, config) {
|
|
250
250
|
const perClass = measurement.metric === 'addedCode' && tier === 'general';
|
|
251
|
-
if (!perClass
|
|
251
|
+
if (!perClass) {
|
|
252
252
|
return [{ count: measurement.lines, thresholds: thresholds.lines, scope: '' }];
|
|
253
253
|
}
|
|
254
|
+
if (measurement.testLines === 0) {
|
|
255
|
+
return [
|
|
256
|
+
{ count: measurement.lines, thresholds: thresholds.lines, scope: '', share: 'product' },
|
|
257
|
+
];
|
|
258
|
+
}
|
|
254
259
|
return [
|
|
255
260
|
{
|
|
256
261
|
count: measurement.lines - measurement.testLines,
|
|
257
262
|
thresholds: thresholds.lines,
|
|
258
263
|
scope: ' in non-test files',
|
|
264
|
+
share: 'product',
|
|
259
265
|
},
|
|
260
266
|
{
|
|
261
267
|
count: measurement.testLines,
|
|
262
268
|
thresholds: getPatchSizeThresholds('test', config).lines,
|
|
263
269
|
scope: ' in test files (test tier)',
|
|
270
|
+
share: 'test',
|
|
264
271
|
},
|
|
265
272
|
];
|
|
266
273
|
}
|
|
@@ -317,6 +324,7 @@ export function lintPatchSize(filesAffected, measured, patchTier, config) {
|
|
|
317
324
|
message: formatPatchSizeMessage(subject, band, check.thresholds),
|
|
318
325
|
severity: band,
|
|
319
326
|
measurement: check.count,
|
|
327
|
+
...(check.share !== undefined ? { share: check.share } : {}),
|
|
320
328
|
});
|
|
321
329
|
}
|
|
322
330
|
return issues;
|