@hominis/fireforge 0.38.0 → 0.40.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 +41 -0
- package/README.md +25 -1
- package/dist/src/cli.js +7 -0
- package/dist/src/commands/build.js +8 -3
- package/dist/src/commands/discard.js +75 -50
- package/dist/src/commands/export-flow.d.ts +1 -1
- package/dist/src/commands/export-flow.js +21 -10
- package/dist/src/commands/export-placement-gate.js +1 -1
- package/dist/src/commands/export-shared.js +31 -5
- package/dist/src/commands/import.js +5 -0
- package/dist/src/commands/lint-per-patch.js +97 -18
- package/dist/src/commands/lint-report.d.ts +21 -0
- package/dist/src/commands/lint-report.js +62 -0
- package/dist/src/commands/lint.js +23 -19
- package/dist/src/commands/manifest.js +2 -0
- package/dist/src/commands/patch/lint-ignore.js +20 -1
- package/dist/src/commands/patch/move-files-into.d.ts +47 -0
- package/dist/src/commands/patch/move-files-into.js +245 -0
- package/dist/src/commands/patch/move-files.js +27 -13
- package/dist/src/commands/patch/rename.js +5 -2
- package/dist/src/commands/patch/staged-dependency.js +102 -14
- package/dist/src/commands/re-export-adjacent.d.ts +34 -0
- package/dist/src/commands/re-export-adjacent.js +106 -0
- package/dist/src/commands/re-export-options.js +3 -0
- package/dist/src/commands/re-export.js +42 -53
- package/dist/src/commands/reset.js +5 -0
- package/dist/src/commands/run.js +18 -2
- package/dist/src/commands/status-check.d.ts +35 -0
- package/dist/src/commands/status-check.js +88 -0
- package/dist/src/commands/status-output.d.ts +9 -0
- package/dist/src/commands/status-output.js +33 -1
- package/dist/src/commands/status.js +33 -8
- package/dist/src/commands/test-diagnose.d.ts +1 -1
- package/dist/src/commands/test-diagnose.js +9 -3
- package/dist/src/commands/test-modes.d.ts +21 -0
- package/dist/src/commands/test-modes.js +42 -0
- package/dist/src/commands/test-run.d.ts +2 -0
- package/dist/src/commands/test-run.js +26 -5
- package/dist/src/commands/test.js +38 -32
- package/dist/src/commands/token.js +4 -1
- package/dist/src/commands/tree.d.ts +16 -0
- package/dist/src/commands/tree.js +174 -0
- package/dist/src/core/build-baseline-types.d.ts +7 -0
- package/dist/src/core/build-baseline.d.ts +1 -1
- package/dist/src/core/build-baseline.js +2 -1
- package/dist/src/core/build-prepare.d.ts +9 -0
- package/dist/src/core/build-prepare.js +24 -0
- package/dist/src/core/config-validate.js +25 -0
- package/dist/src/core/discard-baseline.d.ts +60 -0
- package/dist/src/core/discard-baseline.js +232 -0
- package/dist/src/core/license-headers.d.ts +12 -0
- package/dist/src/core/license-headers.js +27 -0
- package/dist/src/core/lint-cache.d.ts +15 -5
- package/dist/src/core/lint-cache.js +17 -5
- package/dist/src/core/patch-export.d.ts +12 -3
- package/dist/src/core/patch-export.js +13 -3
- package/dist/src/core/patch-lint-checkjs.d.ts +25 -2
- package/dist/src/core/patch-lint-checkjs.js +85 -16
- package/dist/src/core/patch-lint-cross.d.ts +9 -1
- package/dist/src/core/patch-lint-cross.js +69 -9
- package/dist/src/core/patch-lint-css.js +64 -16
- package/dist/src/core/patch-lint-diff.d.ts +8 -0
- package/dist/src/core/patch-lint-diff.js +31 -0
- package/dist/src/core/patch-lint-mozbuild.d.ts +18 -0
- package/dist/src/core/patch-lint-mozbuild.js +104 -0
- package/dist/src/core/patch-lint-ownership.d.ts +21 -0
- package/dist/src/core/patch-lint-ownership.js +30 -0
- package/dist/src/core/patch-lint-reexports.d.ts +1 -1
- package/dist/src/core/patch-lint.d.ts +23 -0
- package/dist/src/core/patch-lint.js +34 -3
- package/dist/src/core/patch-manifest.d.ts +1 -1
- package/dist/src/core/patch-policy.d.ts +14 -1
- package/dist/src/core/patch-policy.js +13 -2
- package/dist/src/core/smoke-patterns.d.ts +24 -8
- package/dist/src/core/smoke-patterns.js +23 -12
- package/dist/src/core/status-classify.d.ts +16 -0
- package/dist/src/core/status-classify.js +20 -6
- package/dist/src/core/test-harness-crash.d.ts +10 -0
- package/dist/src/core/test-harness-crash.js +16 -0
- package/dist/src/core/test-stale-check.d.ts +15 -0
- package/dist/src/core/test-stale-check.js +37 -1
- package/dist/src/core/token-category.d.ts +40 -0
- package/dist/src/core/token-category.js +264 -0
- package/dist/src/core/token-manager.d.ts +7 -0
- package/dist/src/core/token-manager.js +82 -193
- package/dist/src/core/token-variant.d.ts +7 -0
- package/dist/src/core/token-variant.js +9 -0
- package/dist/src/core/tree-cow.d.ts +18 -0
- package/dist/src/core/tree-cow.js +71 -0
- package/dist/src/core/tree-guard.d.ts +35 -0
- package/dist/src/core/tree-guard.js +124 -0
- package/dist/src/core/tree-store.d.ts +53 -0
- package/dist/src/core/tree-store.js +214 -0
- package/dist/src/core/typecheck-shim.d.ts +27 -0
- package/dist/src/core/typecheck-shim.js +58 -4
- package/dist/src/core/typecheck.js +14 -3
- package/dist/src/core/xpcshell-profile-dir.d.ts +12 -0
- package/dist/src/core/xpcshell-profile-dir.js +45 -0
- package/dist/src/errors/git.d.ts +8 -0
- package/dist/src/errors/git.js +17 -0
- package/dist/src/index.d.ts +2 -0
- package/dist/src/index.js +1 -0
- package/dist/src/types/commands/options.d.ts +45 -2
- package/dist/src/types/config.d.ts +34 -0
- package/dist/src/utils/validation.d.ts +10 -0
- package/dist/src/utils/validation.js +29 -0
- package/package.json +6 -6
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
import { dirname, isAbsolute, relative, resolve } from 'node:path';
|
|
22
22
|
import { pathExists } from '../utils/fs.js';
|
|
23
23
|
import { verbose } from '../utils/logger.js';
|
|
24
|
-
import { composeShimSource, SHIM_FILENAME, SUPPRESSED_DIAGNOSTIC_CODES } from './typecheck-shim.js';
|
|
24
|
+
import { composeShimSource, SHIM_FILENAME, SUPPRESSED_DIAGNOSTIC_CODES, UNDEFINED_IDENTIFIER_CODES, UNDEFINED_IDENTIFIER_HINT, } from './typecheck-shim.js';
|
|
25
25
|
/**
|
|
26
26
|
* Sentinel string surfaced as a `TypecheckIssue.message` when the
|
|
27
27
|
* project's jsconfig sets `checkJs: false`. Exported so tests can
|
|
@@ -131,7 +131,7 @@ export async function runTypecheck(projectRoot, cfg) {
|
|
|
131
131
|
});
|
|
132
132
|
continue;
|
|
133
133
|
}
|
|
134
|
-
results.push(await runTypecheckForProject(ts, projectRoot, projectPath, shimSource));
|
|
134
|
+
results.push(await runTypecheckForProject(ts, projectRoot, projectPath, shimSource, cfg.undefinedIdentifiers ?? 'warning'));
|
|
135
135
|
}
|
|
136
136
|
return results;
|
|
137
137
|
}
|
|
@@ -149,7 +149,7 @@ function resolveProjectExtraShim(cfg, projectPath) {
|
|
|
149
149
|
return cfg.extraShim;
|
|
150
150
|
}
|
|
151
151
|
/** Runs typecheck for a single jsconfig path, isolating its failures. */
|
|
152
|
-
async function runTypecheckForProject(ts, projectRoot, projectPath, shimSource) {
|
|
152
|
+
async function runTypecheckForProject(ts, projectRoot, projectPath, shimSource, undefinedIdentifiers = 'warning') {
|
|
153
153
|
const absConfig = resolve(projectRoot, projectPath);
|
|
154
154
|
if (!(await pathExists(absConfig))) {
|
|
155
155
|
return {
|
|
@@ -268,6 +268,17 @@ async function runTypecheckForProject(ts, projectRoot, projectPath, shimSource)
|
|
|
268
268
|
// can't act on them and they would clutter CI logs.
|
|
269
269
|
if (diag.file?.fileName === shimPath)
|
|
270
270
|
continue;
|
|
271
|
+
if (UNDEFINED_IDENTIFIER_CODES.has(diag.code)) {
|
|
272
|
+
if (undefinedIdentifiers === 'off')
|
|
273
|
+
continue;
|
|
274
|
+
const issue = diagnosticToIssue(ts, diag, absConfig, projectPath);
|
|
275
|
+
issues.push({
|
|
276
|
+
...issue,
|
|
277
|
+
category: undefinedIdentifiers,
|
|
278
|
+
message: `${issue.message} ${UNDEFINED_IDENTIFIER_HINT}`,
|
|
279
|
+
});
|
|
280
|
+
continue;
|
|
281
|
+
}
|
|
271
282
|
issues.push(diagnosticToIssue(ts, diag, absConfig, projectPath));
|
|
272
283
|
}
|
|
273
284
|
verbose(`typecheck: ${projectPath} — analyzed ${String(parsed.fileNames.length)} file(s), found ${String(issues.length)} issue(s)`);
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export declare const XPCSHELL_PROFILE_ENV_VAR = "XPCSHELL_TEST_PROFILE_DIR";
|
|
2
|
+
/**
|
|
3
|
+
* Runs `fn` with a fresh per-invocation xpcshell profile directory
|
|
4
|
+
* injected into the environment, removing the directory afterwards
|
|
5
|
+
* (best-effort — a failure to clean up warns and leaves the mkdtemp dir
|
|
6
|
+
* for the OS tmp reaper; the harness may still hold files briefly).
|
|
7
|
+
*
|
|
8
|
+
* An operator-provided `XPCSHELL_TEST_PROFILE_DIR` (in `baseEnv` or the
|
|
9
|
+
* process environment) is respected verbatim: no directory is minted and
|
|
10
|
+
* NOTHING is deleted — we never remove a directory we did not create.
|
|
11
|
+
*/
|
|
12
|
+
export declare function withXpcshellProfileDir<T>(baseEnv: Record<string, string> | undefined, fn: (env: Record<string, string>) => Promise<T>): Promise<T>;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
// SPDX-License-Identifier: EUPL-1.2
|
|
2
|
+
/**
|
|
3
|
+
* Per-invocation xpcshell profile directory (FORGE G15b).
|
|
4
|
+
*
|
|
5
|
+
* Firefox's xpcshell harness defaults `XPCSHELL_TEST_PROFILE_DIR` to a
|
|
6
|
+
* FIXED path (`$TMPDIR/firefox/xpcshellprofile`), so two overlapping
|
|
7
|
+
* harness invocations — concurrent `fireforge test` processes, or future
|
|
8
|
+
* verification-tree shards — corrupt each other's profiles. FireForge
|
|
9
|
+
* never set the variable; this helper mints a fresh `mkdtemp` directory
|
|
10
|
+
* per harness invocation and exports it through the mach env channel.
|
|
11
|
+
*/
|
|
12
|
+
import { mkdtemp, rm } from 'node:fs/promises';
|
|
13
|
+
import { tmpdir } from 'node:os';
|
|
14
|
+
import { join } from 'node:path';
|
|
15
|
+
import { toError } from '../utils/errors.js';
|
|
16
|
+
import { warn } from '../utils/logger.js';
|
|
17
|
+
export const XPCSHELL_PROFILE_ENV_VAR = 'XPCSHELL_TEST_PROFILE_DIR';
|
|
18
|
+
/**
|
|
19
|
+
* Runs `fn` with a fresh per-invocation xpcshell profile directory
|
|
20
|
+
* injected into the environment, removing the directory afterwards
|
|
21
|
+
* (best-effort — a failure to clean up warns and leaves the mkdtemp dir
|
|
22
|
+
* for the OS tmp reaper; the harness may still hold files briefly).
|
|
23
|
+
*
|
|
24
|
+
* An operator-provided `XPCSHELL_TEST_PROFILE_DIR` (in `baseEnv` or the
|
|
25
|
+
* process environment) is respected verbatim: no directory is minted and
|
|
26
|
+
* NOTHING is deleted — we never remove a directory we did not create.
|
|
27
|
+
*/
|
|
28
|
+
export async function withXpcshellProfileDir(baseEnv, fn) {
|
|
29
|
+
const operatorProvided = baseEnv?.[XPCSHELL_PROFILE_ENV_VAR] ?? process.env[XPCSHELL_PROFILE_ENV_VAR];
|
|
30
|
+
if (operatorProvided !== undefined && operatorProvided !== '') {
|
|
31
|
+
return fn({ ...baseEnv, [XPCSHELL_PROFILE_ENV_VAR]: operatorProvided });
|
|
32
|
+
}
|
|
33
|
+
const profileDir = await mkdtemp(join(tmpdir(), 'fireforge-xpcshell-profile-'));
|
|
34
|
+
try {
|
|
35
|
+
return await fn({ ...baseEnv, [XPCSHELL_PROFILE_ENV_VAR]: profileDir });
|
|
36
|
+
}
|
|
37
|
+
finally {
|
|
38
|
+
try {
|
|
39
|
+
await rm(profileDir, { recursive: true, force: true });
|
|
40
|
+
}
|
|
41
|
+
catch (error) {
|
|
42
|
+
warn(`Could not clean up xpcshell profile dir ${profileDir}: ${toError(error).message}`);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
package/dist/src/errors/git.d.ts
CHANGED
|
@@ -39,6 +39,14 @@ export declare class GitIndexLockError extends GitError {
|
|
|
39
39
|
constructor(lockPath: string, ageMs?: number | undefined);
|
|
40
40
|
get userMessage(): string;
|
|
41
41
|
}
|
|
42
|
+
/**
|
|
43
|
+
* Detects transient git `index.lock` contention — an external git process
|
|
44
|
+
* holding `.git/index.lock` while we stage or diff. Mirrors the message
|
|
45
|
+
* heuristics `core/git.ts` uses when wrapping stale-lock failures during
|
|
46
|
+
* download, but lives here so command modules can consult it without
|
|
47
|
+
* importing (frequently vi.mocked) core git internals.
|
|
48
|
+
*/
|
|
49
|
+
export declare function isGitIndexLockConflict(error: unknown): boolean;
|
|
42
50
|
/**
|
|
43
51
|
* Error thrown when `git add` (monolithic or chunked) exceeds the
|
|
44
52
|
* configured timeout while indexing the Firefox source tree.
|
package/dist/src/errors/git.js
CHANGED
|
@@ -96,6 +96,23 @@ export class GitIndexLockError extends GitError {
|
|
|
96
96
|
' 3. Re-run "fireforge download --force"');
|
|
97
97
|
}
|
|
98
98
|
}
|
|
99
|
+
/**
|
|
100
|
+
* Detects transient git `index.lock` contention — an external git process
|
|
101
|
+
* holding `.git/index.lock` while we stage or diff. Mirrors the message
|
|
102
|
+
* heuristics `core/git.ts` uses when wrapping stale-lock failures during
|
|
103
|
+
* download, but lives here so command modules can consult it without
|
|
104
|
+
* importing (frequently vi.mocked) core git internals.
|
|
105
|
+
*/
|
|
106
|
+
export function isGitIndexLockConflict(error) {
|
|
107
|
+
if (error instanceof GitIndexLockError) {
|
|
108
|
+
return true;
|
|
109
|
+
}
|
|
110
|
+
if (!(error instanceof GitError)) {
|
|
111
|
+
return false;
|
|
112
|
+
}
|
|
113
|
+
return (/index\.lock/i.test(error.message) &&
|
|
114
|
+
/(unable to create|another git process seems to be running|file exists|locked)/i.test(error.message));
|
|
115
|
+
}
|
|
99
116
|
/**
|
|
100
117
|
* Error thrown when `git add` (monolithic or chunked) exceeds the
|
|
101
118
|
* configured timeout while indexing the Firefox source tree.
|
package/dist/src/index.d.ts
CHANGED
|
@@ -14,6 +14,8 @@ export { loadConfig, validateConfig } from './core/config.js';
|
|
|
14
14
|
export { applyAllComponents } from './core/furnace-apply.js';
|
|
15
15
|
export { ensureFurnaceConfig, loadFurnaceConfig, loadFurnaceState, saveFurnaceState, validateFurnaceConfig, } from './core/furnace-config.js';
|
|
16
16
|
export { validateAllComponents, validateComponent } from './core/furnace-validate.js';
|
|
17
|
+
export type { PatchSizeTierDecision } from './core/patch-lint.js';
|
|
18
|
+
export { countNonBinaryDiffLines, getPatchSizeThresholds, resolvePatchSizeTier, } from './core/patch-lint.js';
|
|
17
19
|
export type { AddTokenOptions, AddTokenResult, TokenMode } from './core/token-manager.js';
|
|
18
20
|
export { addToken, getTokensCssPath, validateTokenAdd } from './core/token-manager.js';
|
|
19
21
|
export { CancellationError, CommandError, FireForgeError, GeneralError, InvalidArgumentError, ResolutionError, } from './errors/base.js';
|
package/dist/src/index.js
CHANGED
|
@@ -15,6 +15,7 @@ export { loadConfig, validateConfig } from './core/config.js';
|
|
|
15
15
|
export { applyAllComponents } from './core/furnace-apply.js';
|
|
16
16
|
export { ensureFurnaceConfig, loadFurnaceConfig, loadFurnaceState, saveFurnaceState, validateFurnaceConfig, } from './core/furnace-config.js';
|
|
17
17
|
export { validateAllComponents, validateComponent } from './core/furnace-validate.js';
|
|
18
|
+
export { countNonBinaryDiffLines, getPatchSizeThresholds, resolvePatchSizeTier, } from './core/patch-lint.js';
|
|
18
19
|
export { addToken, getTokensCssPath, validateTokenAdd } from './core/token-manager.js';
|
|
19
20
|
export { CancellationError, CommandError, FireForgeError, GeneralError, InvalidArgumentError, ResolutionError, } from './errors/base.js';
|
|
20
21
|
export { ExitCode } from './errors/codes.js';
|
|
@@ -160,6 +160,12 @@ export interface ResetOptions {
|
|
|
160
160
|
* Options for the discard command.
|
|
161
161
|
*/
|
|
162
162
|
export interface DiscardOptions {
|
|
163
|
+
/**
|
|
164
|
+
* Restore to pristine upstream (HEAD) instead of the patch-applied
|
|
165
|
+
* baseline; deletes patch-created files (the pre-0.39.0 semantics —
|
|
166
|
+
* FORGE F1).
|
|
167
|
+
*/
|
|
168
|
+
toUpstream?: boolean;
|
|
163
169
|
/** Show what would be discarded without doing it */
|
|
164
170
|
dryRun?: boolean;
|
|
165
171
|
/** Skip confirmation prompt */
|
|
@@ -273,6 +279,16 @@ export interface ReExportOptions {
|
|
|
273
279
|
* the command implementation ignores it.
|
|
274
280
|
*/
|
|
275
281
|
waitLock?: number | boolean;
|
|
282
|
+
/**
|
|
283
|
+
* Refuse (non-zero exit, patch not written) a scan-less re-export when
|
|
284
|
+
* unmanaged files exist adjacent to the patch's ownership, instead of
|
|
285
|
+
* warning. Gate-driven workflows use this so a freshly created file
|
|
286
|
+
* beside a patch's owned files cannot be silently left out of the
|
|
287
|
+
* refreshed body. Only meaningful on the plain path — mutually
|
|
288
|
+
* exclusive with `--scan` and `--files`, which set filesAffected
|
|
289
|
+
* explicitly.
|
|
290
|
+
*/
|
|
291
|
+
refuseAdjacentUnmanaged?: boolean;
|
|
276
292
|
}
|
|
277
293
|
/**
|
|
278
294
|
* Options for the `fireforge patch tier` subcommand. Sets or clears the
|
|
@@ -795,8 +811,27 @@ export interface StatusOptions {
|
|
|
795
811
|
* patch as an ownership conflict.
|
|
796
812
|
*/
|
|
797
813
|
ownership?: boolean;
|
|
814
|
+
/**
|
|
815
|
+
* Print the recorded test-packaging coverage of the last build baseline
|
|
816
|
+
* (scope, timestamp, recording invocation) and exit. Read-only — the
|
|
817
|
+
* counterpart to the out-of-coverage test refusal (FORGE F11).
|
|
818
|
+
*/
|
|
819
|
+
testCoverage?: boolean;
|
|
798
820
|
/** Output machine-readable JSON instead of human-readable text. */
|
|
799
821
|
json?: boolean;
|
|
822
|
+
/**
|
|
823
|
+
* Exit non-zero when any classification in the fail policy is
|
|
824
|
+
* non-empty (default policy: unmanaged, patch-owned-drift, conflict).
|
|
825
|
+
* Composes with the default view and `--json`; refused alongside
|
|
826
|
+
* `--raw`/`--unmanaged`/`--ownership`/`--test-coverage` (FORGE G1).
|
|
827
|
+
*/
|
|
828
|
+
check?: boolean;
|
|
829
|
+
/**
|
|
830
|
+
* Comma-separated classification list replacing the default `--check`
|
|
831
|
+
* policy. Implies `--check`. Unknown values refuse, naming the valid
|
|
832
|
+
* classification set.
|
|
833
|
+
*/
|
|
834
|
+
failOn?: string;
|
|
800
835
|
}
|
|
801
836
|
/**
|
|
802
837
|
* Options for the token add command.
|
|
@@ -888,8 +923,9 @@ export interface LintCommandOptions {
|
|
|
888
923
|
* the cross-patch rules once over the whole queue so queue-level
|
|
889
924
|
* findings (duplicate creations, forward imports) still surface.
|
|
890
925
|
*
|
|
891
|
-
*
|
|
892
|
-
*
|
|
926
|
+
* Positional file arguments change meaning under this flag: they are
|
|
927
|
+
* PATCH selectors resolved like {@link patches} entries, not engine
|
|
928
|
+
* file paths (FORGE G14).
|
|
893
929
|
*/
|
|
894
930
|
perPatch?: boolean;
|
|
895
931
|
/**
|
|
@@ -911,4 +947,11 @@ export interface LintCommandOptions {
|
|
|
911
947
|
* for CLI consistency, but only `--per-patch` currently uses the cache.
|
|
912
948
|
*/
|
|
913
949
|
noCache?: boolean;
|
|
950
|
+
/**
|
|
951
|
+
* With `--per-patch`, write a machine-readable JSON report (schemaVersion
|
|
952
|
+
* 1: per-patch lineCount, filesAffected, tier, thresholds, issues, and
|
|
953
|
+
* lintIgnore-suppressed issues) to this path (FORGE G9/G10). Requires
|
|
954
|
+
* {@link perPatch}.
|
|
955
|
+
*/
|
|
956
|
+
report?: string;
|
|
914
957
|
}
|
|
@@ -181,6 +181,14 @@ export interface TypecheckConfig {
|
|
|
181
181
|
* mismatch). A narrowed project sets `null` here to stay clean.
|
|
182
182
|
*/
|
|
183
183
|
projectOverrides?: Record<string, string | null>;
|
|
184
|
+
/**
|
|
185
|
+
* How to report undefined free identifiers (TS2304/TS2552). These were
|
|
186
|
+
* historically suppressed as shim-gap noise, which also hid genuine
|
|
187
|
+
* missing imports until they crashed at runtime (FORGE F12). Default
|
|
188
|
+
* `'warning'`: visible without failing the gate. `'error'` makes them
|
|
189
|
+
* blocking; `'off'` restores the historical suppression.
|
|
190
|
+
*/
|
|
191
|
+
undefinedIdentifiers?: PatchLintSeverityGate;
|
|
184
192
|
}
|
|
185
193
|
/**
|
|
186
194
|
* Wire command configuration.
|
|
@@ -245,6 +253,25 @@ export interface PatchLintConfig {
|
|
|
245
253
|
* behaviour (built-in shim only).
|
|
246
254
|
*/
|
|
247
255
|
checkJsExtraShim?: string;
|
|
256
|
+
/**
|
|
257
|
+
* Extend the checkJs pass to patch-owned test `.js` files
|
|
258
|
+
* (`browser_*` / `test_*` / `xpcshell_*` basenames and files under a
|
|
259
|
+
* `/test/` path), each checked as its own small script-scope program
|
|
260
|
+
* with same-directory patch-owned `head*.js` helpers included (FORGE
|
|
261
|
+
* G5 — a harness global that does not exist should fail at the patch
|
|
262
|
+
* boundary where the test was authored, not in a downstream
|
|
263
|
+
* jsconfig-project run). Opt-in: it is a new failure surface with
|
|
264
|
+
* nonzero compile cost. Requires `checkJs: true`.
|
|
265
|
+
*/
|
|
266
|
+
checkJsTestFiles?: boolean;
|
|
267
|
+
/**
|
|
268
|
+
* Project-relative `.d.ts` appended to the built-in test-harness shim
|
|
269
|
+
* (loose `TestUtils`/`BrowserTestUtils`/`add_task`/… declarations) for
|
|
270
|
+
* the `checkJsTestFiles` pass — a consumer-typed `TestUtils` here is
|
|
271
|
+
* what turns a call to a nonexistent harness member into a TS2339 at
|
|
272
|
+
* export time. Requires `checkJsTestFiles: true`.
|
|
273
|
+
*/
|
|
274
|
+
checkJsTestShim?: string;
|
|
248
275
|
/** File paths exempt from the raw-color-value check (exact or basename match) */
|
|
249
276
|
rawColorAllowlist?: string[];
|
|
250
277
|
/** Enforce JSDoc on class-method exports in patch-owned .sys.mjs files. Default: 'off'. */
|
|
@@ -262,6 +289,13 @@ export interface PatchLintConfig {
|
|
|
262
289
|
* 'off'.
|
|
263
290
|
*/
|
|
264
291
|
chromeScriptJsDoc?: PatchLintSeverityGate;
|
|
292
|
+
/**
|
|
293
|
+
* How the checkJs pass reports undefined free identifiers
|
|
294
|
+
* (TS2304/TS2552). Same semantics as `typecheck.undefinedIdentifiers`
|
|
295
|
+
* (FORGE F12); the two flows share the suppression policy so a patch
|
|
296
|
+
* cannot pass one and fail the other. Default: 'warning'.
|
|
297
|
+
*/
|
|
298
|
+
undefinedIdentifiers?: PatchLintSeverityGate;
|
|
265
299
|
}
|
|
266
300
|
/**
|
|
267
301
|
* Build mode for mach.
|
|
@@ -128,6 +128,16 @@ export declare function validateTokenName(name: string): string | undefined;
|
|
|
128
128
|
* @throws InvalidArgumentError if the resulting name is not a valid CSS custom property.
|
|
129
129
|
*/
|
|
130
130
|
export declare function normalizeTokenName(name: string): string;
|
|
131
|
+
/**
|
|
132
|
+
* Normalizes a patch display name against its category (FORGE G13):
|
|
133
|
+
* strips a trailing `.patch` and any redundant `NNN-<category>-` /
|
|
134
|
+
* `<category>-` prefixes, case-insensitively and repeatedly, mirroring
|
|
135
|
+
* the filename slug pipeline's require-the-category-token rule — a bare
|
|
136
|
+
* leading number is never stripped, so names like `2-step-verification`
|
|
137
|
+
* survive intact. Falls back to the `.patch`-stripped stem when the
|
|
138
|
+
* strip would empty the name.
|
|
139
|
+
*/
|
|
140
|
+
export declare function normalizePatchDisplayName(name: string, category: string): string;
|
|
131
141
|
/**
|
|
132
142
|
* Validates a patch name.
|
|
133
143
|
* @param name - The patch name to validate
|
|
@@ -251,6 +251,35 @@ export function normalizeTokenName(name) {
|
|
|
251
251
|
const stripped = name.replace(/^--/, '');
|
|
252
252
|
return `--${stripped}`;
|
|
253
253
|
}
|
|
254
|
+
/**
|
|
255
|
+
* Normalizes a patch display name against its category (FORGE G13):
|
|
256
|
+
* strips a trailing `.patch` and any redundant `NNN-<category>-` /
|
|
257
|
+
* `<category>-` prefixes, case-insensitively and repeatedly, mirroring
|
|
258
|
+
* the filename slug pipeline's require-the-category-token rule — a bare
|
|
259
|
+
* leading number is never stripped, so names like `2-step-verification`
|
|
260
|
+
* survive intact. Falls back to the `.patch`-stripped stem when the
|
|
261
|
+
* strip would empty the name.
|
|
262
|
+
*/
|
|
263
|
+
export function normalizePatchDisplayName(name, category) {
|
|
264
|
+
const stem = name.trim().replace(/\.patch$/i, '');
|
|
265
|
+
const escaped = category.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
266
|
+
const prefixes = [
|
|
267
|
+
new RegExp(`^\\d+[-_ ]+${escaped}[-_ ]+`, 'i'),
|
|
268
|
+
new RegExp(`^${escaped}[-_ ]+`, 'i'),
|
|
269
|
+
];
|
|
270
|
+
let stripped = stem;
|
|
271
|
+
let changed = true;
|
|
272
|
+
while (changed) {
|
|
273
|
+
changed = false;
|
|
274
|
+
for (const prefix of prefixes) {
|
|
275
|
+
if (prefix.test(stripped)) {
|
|
276
|
+
stripped = stripped.replace(prefix, '');
|
|
277
|
+
changed = true;
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
return stripped.length > 0 ? stripped : stem;
|
|
282
|
+
}
|
|
254
283
|
/**
|
|
255
284
|
* Validates a patch name.
|
|
256
285
|
* @param name - The patch name to validate
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hominis/fireforge",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.40.0",
|
|
4
4
|
"description": "FireForge — a build tool for customizing Firefox",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/src/index.js",
|
|
@@ -58,7 +58,7 @@
|
|
|
58
58
|
"commander": "^15.0.0",
|
|
59
59
|
"estree-walker": "^3.0.3",
|
|
60
60
|
"jsonc-parser": "^3.3.1",
|
|
61
|
-
"magic-string": "^
|
|
61
|
+
"magic-string": "^1.1.0",
|
|
62
62
|
"picocolors": "^1.1.0"
|
|
63
63
|
},
|
|
64
64
|
"devDependencies": {
|
|
@@ -66,16 +66,16 @@
|
|
|
66
66
|
"@types/estree": "^1.0.8",
|
|
67
67
|
"@types/node": "^26.0.0",
|
|
68
68
|
"@vitest/coverage-v8": "^4.1.2",
|
|
69
|
-
"dpdm": "4.
|
|
69
|
+
"dpdm": "4.3.0",
|
|
70
70
|
"eslint": "^10.0.0",
|
|
71
71
|
"eslint-config-prettier": "^10.1.8",
|
|
72
72
|
"eslint-plugin-jsdoc": "^63.0.0",
|
|
73
|
-
"eslint-plugin-simple-import-sort": "^
|
|
73
|
+
"eslint-plugin-simple-import-sort": "^14.0.0",
|
|
74
74
|
"fast-check": "^4.6.0",
|
|
75
75
|
"husky": "^9.1.7",
|
|
76
|
-
"knip": "6.
|
|
76
|
+
"knip": "6.29.0",
|
|
77
77
|
"lint-staged": "^17.0.4",
|
|
78
|
-
"prettier": "3.9.
|
|
78
|
+
"prettier": "3.9.6",
|
|
79
79
|
"tsx": "^4.7.0",
|
|
80
80
|
"typescript": "~6.0.0",
|
|
81
81
|
"typescript-eslint": "^8.0.0",
|