@hominis/fireforge 0.39.0 → 0.41.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 +100 -0
- package/README.md +35 -5
- package/dist/bin/fireforge.js +25 -4
- package/dist/build-info.json +9 -0
- package/dist/src/cli.js +27 -3
- package/dist/src/commands/bootstrap.js +5 -1
- package/dist/src/commands/discard.js +2 -22
- package/dist/src/commands/doctor/post-rebase-audit.js +27 -4
- package/dist/src/commands/doctor-check-core.d.ts +20 -0
- package/dist/src/commands/doctor-check-core.js +28 -0
- package/dist/src/commands/doctor-external-toolchains.js +2 -0
- package/dist/src/commands/doctor-furnace-manifest-sync.js +144 -46
- package/dist/src/commands/doctor-furnace.js +13 -11
- package/dist/src/commands/doctor-orphaned-harness.js +2 -1
- package/dist/src/commands/doctor.js +2 -2
- package/dist/src/commands/export-all.js +9 -1
- package/dist/src/commands/export-flow.js +27 -9
- package/dist/src/commands/export-placement-conflicts.d.ts +17 -0
- package/dist/src/commands/export-placement-conflicts.js +74 -0
- package/dist/src/commands/export-placement-gate.js +1 -1
- package/dist/src/commands/export-shared.d.ts +8 -1
- package/dist/src/commands/export-shared.js +30 -10
- package/dist/src/commands/export.js +2 -2
- package/dist/src/commands/furnace/apply.js +4 -3
- package/dist/src/commands/furnace/chrome-doc-remove.js +13 -2
- package/dist/src/commands/furnace/chrome-doc.js +13 -2
- package/dist/src/commands/furnace/create-browser-test.d.ts +5 -0
- package/dist/src/commands/furnace/create-browser-test.js +5 -0
- package/dist/src/commands/furnace/create.js +2 -2
- package/dist/src/commands/furnace/diff.js +2 -1
- package/dist/src/commands/furnace/init.js +4 -6
- package/dist/src/commands/furnace/override.js +2 -2
- package/dist/src/commands/furnace/remove-mutations.d.ts +40 -0
- package/dist/src/commands/furnace/remove-mutations.js +171 -0
- package/dist/src/commands/furnace/remove.js +21 -128
- package/dist/src/commands/furnace/rename-browser-test.js +54 -5
- package/dist/src/commands/furnace/scan.js +27 -36
- package/dist/src/commands/furnace/status.js +30 -28
- package/dist/src/commands/furnace/validate.js +25 -18
- package/dist/src/commands/import.js +6 -20
- package/dist/src/commands/lint-per-patch.js +73 -51
- package/dist/src/commands/lint-per-run-checkjs.d.ts +64 -0
- package/dist/src/commands/lint-per-run-checkjs.js +102 -0
- 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 +26 -22
- package/dist/src/commands/manifest.js +3 -1
- package/dist/src/commands/package.js +9 -16
- package/dist/src/commands/patch/compact.js +5 -5
- package/dist/src/commands/patch/delete.js +5 -5
- package/dist/src/commands/patch/lint-ignore.js +3 -2
- package/dist/src/commands/patch/move-files-create.js +22 -4
- package/dist/src/commands/patch/move-files-into.js +14 -10
- package/dist/src/commands/patch/move-files.js +6 -5
- package/dist/src/commands/patch/rename.d.ts +2 -2
- package/dist/src/commands/patch/rename.js +152 -51
- package/dist/src/commands/patch/reorder.d.ts +9 -0
- package/dist/src/commands/patch/reorder.js +14 -10
- package/dist/src/commands/patch/split-plan.d.ts +13 -6
- package/dist/src/commands/patch/split-plan.js +22 -12
- package/dist/src/commands/patch/split.d.ts +1 -1
- package/dist/src/commands/patch/split.js +23 -9
- package/dist/src/commands/patch/staged-dependency-validate.d.ts +15 -0
- package/dist/src/commands/patch/staged-dependency-validate.js +49 -0
- package/dist/src/commands/patch/staged-dependency.js +112 -14
- package/dist/src/commands/re-export-adjacent.d.ts +34 -0
- package/dist/src/commands/re-export-adjacent.js +105 -0
- package/dist/src/commands/re-export-bulk-scan.d.ts +13 -0
- package/dist/src/commands/re-export-bulk-scan.js +142 -2
- package/dist/src/commands/re-export-drift.d.ts +74 -0
- package/dist/src/commands/re-export-drift.js +234 -0
- package/dist/src/commands/re-export-files.js +5 -3
- package/dist/src/commands/re-export-lint.d.ts +97 -0
- package/dist/src/commands/re-export-lint.js +210 -0
- package/dist/src/commands/re-export-options.js +11 -0
- package/dist/src/commands/re-export-register.d.ts +18 -0
- package/dist/src/commands/re-export-register.js +61 -0
- package/dist/src/commands/re-export-scan.js +13 -7
- package/dist/src/commands/re-export-single.d.ts +20 -0
- package/dist/src/commands/re-export-single.js +261 -0
- package/dist/src/commands/re-export.d.ts +0 -4
- package/dist/src/commands/re-export.js +123 -289
- package/dist/src/commands/rebase/abort.js +13 -4
- package/dist/src/commands/rebase/continue.js +11 -4
- package/dist/src/commands/rebase/index.js +19 -29
- package/dist/src/commands/rebase/patch-loop.js +12 -0
- package/dist/src/commands/reset.js +4 -23
- package/dist/src/commands/resolve.js +2 -9
- package/dist/src/commands/run.js +29 -23
- package/dist/src/commands/source.js +3 -9
- package/dist/src/commands/status-check.d.ts +48 -0
- package/dist/src/commands/status-check.js +106 -0
- package/dist/src/commands/status-json.d.ts +31 -0
- package/dist/src/commands/status-json.js +76 -0
- package/dist/src/commands/status-output.d.ts +1 -0
- package/dist/src/commands/status-output.js +10 -1
- package/dist/src/commands/status-ownership.d.ts +52 -0
- package/dist/src/commands/status-ownership.js +57 -0
- package/dist/src/commands/status.js +190 -170
- package/dist/src/commands/test-build-phase.d.ts +19 -0
- package/dist/src/commands/test-build-phase.js +168 -0
- package/dist/src/commands/test-diagnose.js +30 -2
- package/dist/src/commands/test-modes.d.ts +9 -1
- package/dist/src/commands/test-modes.js +46 -13
- package/dist/src/commands/test-register.js +59 -27
- package/dist/src/commands/test-run.d.ts +29 -3
- package/dist/src/commands/test-run.js +59 -7
- package/dist/src/commands/test-verdict.d.ts +32 -0
- package/dist/src/commands/test-verdict.js +48 -0
- package/dist/src/commands/test.d.ts +9 -0
- package/dist/src/commands/test.js +100 -123
- package/dist/src/commands/token-coverage.js +4 -9
- package/dist/src/commands/token.js +4 -1
- package/dist/src/commands/tree.d.ts +19 -0
- package/dist/src/commands/tree.js +320 -0
- package/dist/src/commands/verify.js +2 -2
- package/dist/src/commands/watch.js +22 -21
- package/dist/src/commands/wire.js +1 -1
- package/dist/src/core/ast-utils.d.ts +11 -0
- package/dist/src/core/ast-utils.js +11 -0
- package/dist/src/core/build-audit-platform.js +6 -1
- package/dist/src/core/build-audit-registration.js +2 -0
- package/dist/src/core/build-audit-resolve.d.ts +13 -0
- package/dist/src/core/build-audit-resolve.js +34 -13
- package/dist/src/core/build-audit.js +4 -20
- package/dist/src/core/build-baseline-types.d.ts +29 -8
- package/dist/src/core/build-baseline-types.js +2 -1
- package/dist/src/core/build-baseline.d.ts +10 -2
- package/dist/src/core/build-baseline.js +39 -8
- package/dist/src/core/build-prepare.d.ts +4 -0
- package/dist/src/core/build-prepare.js +7 -1
- 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-test-toolchains.js +3 -2
- package/dist/src/core/config-validate.js +45 -30
- package/dist/src/core/config.js +16 -3
- package/dist/src/core/coverage-extend.d.ts +89 -0
- package/dist/src/core/coverage-extend.js +188 -0
- package/dist/src/core/destructive.js +3 -1
- package/dist/src/core/discard-baseline.js +18 -4
- package/dist/src/core/engine-precondition.d.ts +35 -0
- package/dist/src/core/engine-precondition.js +50 -0
- package/dist/src/core/engine-session-lock.d.ts +38 -1
- package/dist/src/core/engine-session-lock.js +78 -4
- package/dist/src/core/file-lock.d.ts +7 -0
- package/dist/src/core/file-lock.js +20 -30
- package/dist/src/core/firefox.js +5 -2
- package/dist/src/core/furnace-apply-helpers.d.ts +12 -1
- package/dist/src/core/furnace-apply-helpers.js +12 -3
- package/dist/src/core/furnace-apply-output.js +9 -0
- package/dist/src/core/furnace-apply-overwrite-warn.d.ts +63 -0
- package/dist/src/core/furnace-apply-overwrite-warn.js +123 -0
- package/dist/src/core/furnace-apply-undeploy-actions.d.ts +11 -0
- package/dist/src/core/furnace-apply-undeploy-actions.js +49 -0
- package/dist/src/core/furnace-apply.d.ts +16 -4
- package/dist/src/core/furnace-apply.js +39 -43
- package/dist/src/core/furnace-config.js +2 -0
- package/dist/src/core/furnace-css-fragments.js +2 -0
- package/dist/src/core/furnace-jsconfig.js +14 -7
- package/dist/src/core/furnace-registration-ast.js +8 -8
- package/dist/src/core/furnace-registration-remove.js +6 -3
- package/dist/src/core/furnace-registration.js +9 -12
- package/dist/src/core/furnace-rollback.js +1 -1
- package/dist/src/core/furnace-scanner.js +2 -1
- package/dist/src/core/furnace-stale-export.js +2 -1
- package/dist/src/core/furnace-state-persist.d.ts +4 -6
- package/dist/src/core/furnace-validate-compatibility.js +4 -7
- package/dist/src/core/furnace-validate-helpers.js +33 -1
- package/dist/src/core/furnace-validate-registration.js +16 -0
- package/dist/src/core/furnace-validate.js +4 -2
- package/dist/src/core/git-diff.js +37 -2
- package/dist/src/core/lint-cache.d.ts +15 -5
- package/dist/src/core/lint-cache.js +49 -14
- package/dist/src/core/mach-build-artifacts.d.ts +63 -1
- package/dist/src/core/mach-build-artifacts.js +108 -2
- package/dist/src/core/mach-resource-shim.js +1 -0
- package/dist/src/core/marionette-port.d.ts +16 -0
- package/dist/src/core/marionette-port.js +93 -8
- package/dist/src/core/marionette-preflight.js +6 -5
- package/dist/src/core/patch-apply.d.ts +20 -13
- package/dist/src/core/patch-apply.js +32 -33
- package/dist/src/core/patch-export.d.ts +2 -2
- package/dist/src/core/patch-export.js +4 -6
- package/dist/src/core/patch-lint-checkjs.d.ts +42 -2
- package/dist/src/core/patch-lint-checkjs.js +132 -8
- package/dist/src/core/patch-lint-chrome-jsdoc.js +9 -0
- package/dist/src/core/patch-lint-creators.d.ts +30 -0
- package/dist/src/core/patch-lint-creators.js +45 -0
- package/dist/src/core/patch-lint-cross.d.ts +1 -17
- package/dist/src/core/patch-lint-cross.js +16 -32
- 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-jsdoc.d.ts +3 -1
- package/dist/src/core/patch-lint-jsdoc.js +15 -5
- package/dist/src/core/patch-lint-module-registration.d.ts +15 -0
- package/dist/src/core/patch-lint-module-registration.js +88 -0
- package/dist/src/core/patch-lint-mozbuild.js +99 -11
- 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 +2 -1
- package/dist/src/core/patch-lint-reexports.js +1 -0
- package/dist/src/core/patch-lint.d.ts +31 -0
- package/dist/src/core/patch-lint.js +114 -8
- package/dist/src/core/patch-lock.d.ts +12 -1
- package/dist/src/core/patch-lock.js +40 -4
- package/dist/src/core/patch-manifest-consistency.js +15 -3
- package/dist/src/core/patch-manifest.d.ts +1 -1
- package/dist/src/core/patch-parse.d.ts +8 -0
- package/dist/src/core/patch-parse.js +10 -0
- package/dist/src/core/patch-policy.d.ts +7 -0
- package/dist/src/core/patch-policy.js +4 -1
- package/dist/src/core/patch-transform.d.ts +10 -0
- package/dist/src/core/patch-transform.js +13 -2
- package/dist/src/core/rebase-session.d.ts +44 -2
- package/dist/src/core/rebase-session.js +114 -17
- package/dist/src/core/register-browser-content.js +2 -1
- package/dist/src/core/register-shared-css.js +2 -1
- package/dist/src/core/smoke-patterns.d.ts +24 -16
- package/dist/src/core/smoke-patterns.js +26 -14
- package/dist/src/core/status-binary.d.ts +55 -0
- package/dist/src/core/status-binary.js +124 -0
- package/dist/src/core/status-classify.d.ts +22 -1
- package/dist/src/core/status-classify.js +112 -70
- package/dist/src/core/test-harness-crash.d.ts +32 -1
- package/dist/src/core/test-harness-crash.js +59 -4
- package/dist/src/core/test-path-scope.js +2 -0
- package/dist/src/core/test-stale-check.js +1 -20
- 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 +48 -196
- package/dist/src/core/toolchain-preflight.js +24 -26
- 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 +179 -0
- package/dist/src/core/tree-store.d.ts +129 -0
- package/dist/src/core/tree-store.js +452 -0
- package/dist/src/core/typecheck-shim.d.ts +14 -0
- package/dist/src/core/typecheck-shim.js +41 -2
- package/dist/src/core/typecheck.js +2 -1
- package/dist/src/core/wire-destroy.js +14 -3
- package/dist/src/core/wire-init.js +37 -40
- package/dist/src/core/wire-subscript.js +11 -3
- package/dist/src/core/wire-utils.js +4 -4
- package/dist/src/core/xpcshell-appdir.js +3 -0
- 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/base.d.ts +13 -0
- package/dist/src/errors/base.js +13 -0
- package/dist/src/errors/git.d.ts +8 -0
- package/dist/src/errors/git.js +17 -0
- package/dist/src/errors/rebase.d.ts +13 -0
- package/dist/src/errors/rebase.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 +119 -3
- package/dist/src/types/commands/patches.d.ts +8 -0
- package/dist/src/types/config.d.ts +19 -0
- package/dist/src/types/furnace.d.ts +7 -0
- package/dist/src/utils/build-info.d.ts +31 -0
- package/dist/src/utils/build-info.js +98 -0
- package/dist/src/utils/concurrency.d.ts +8 -0
- package/dist/src/utils/concurrency.js +21 -0
- package/dist/src/utils/errors.d.ts +39 -0
- package/dist/src/utils/errors.js +55 -0
- package/dist/src/utils/fs.js +5 -12
- package/dist/src/utils/logger.d.ts +14 -2
- package/dist/src/utils/logger.js +43 -13
- package/dist/src/utils/options.d.ts +21 -4
- package/dist/src/utils/options.js +26 -6
- package/dist/src/utils/package-root.js +7 -4
- package/dist/src/utils/process-group.js +13 -2
- package/dist/src/utils/stdio-drain.d.ts +28 -0
- package/dist/src/utils/stdio-drain.js +54 -0
- package/dist/src/utils/validation.d.ts +33 -2
- package/dist/src/utils/validation.js +57 -2
- package/package.json +13 -13
|
@@ -8,7 +8,7 @@ import { GeneralError } from '../errors/base.js';
|
|
|
8
8
|
import { BuildError } from '../errors/build.js';
|
|
9
9
|
import { pathExists, readText, writeText } from '../utils/fs.js';
|
|
10
10
|
import { escapeRegex } from '../utils/regex.js';
|
|
11
|
-
import { detectIndent, getNodeSource, parseScript } from './ast-utils.js';
|
|
11
|
+
import { asEstree, detectIndent, getNodeSource, parseScript, } from './ast-utils.js';
|
|
12
12
|
import { withParserFallback } from './parser-fallback.js';
|
|
13
13
|
import { assertBraceBalancePreserved, coerceToCall, extractNameFromExpression, findInsertionAfterFireforgeBlocks, findMethodBody, findMethodBraceIndex, validateWireName, walkToTryBlockEnd, } from './wire-utils.js';
|
|
14
14
|
const BROWSER_INIT_JS = 'browser/base/content/browser-init.js';
|
|
@@ -18,6 +18,30 @@ const BROWSER_INIT_JS = 'browser/base/content/browser-init.js';
|
|
|
18
18
|
* fallback code paths agree on the shape.
|
|
19
19
|
*/
|
|
20
20
|
const DEFAULT_MARKER = 'FIREFORGE:';
|
|
21
|
+
/**
|
|
22
|
+
* Default insertion point: after the last consecutive fireforge block, or at
|
|
23
|
+
* the top of the method body when there is none.
|
|
24
|
+
*
|
|
25
|
+
* Both callers below — the `--after`-target-not-found fallthrough and the
|
|
26
|
+
* no-`--after` default — ran a character-for-character copy of this ladder,
|
|
27
|
+
* including both throw guards. `browser-init.js` is written through those two
|
|
28
|
+
* independent paths and they MUST emit identical blocks, so having one
|
|
29
|
+
* implementation enforces the invariant rather than merely tidying.
|
|
30
|
+
*/
|
|
31
|
+
function resolveDefaultInsertion(content, body, fireforgeBlocks) {
|
|
32
|
+
if (fireforgeBlocks.length > 0) {
|
|
33
|
+
const lastBlock = fireforgeBlocks[fireforgeBlocks.length - 1];
|
|
34
|
+
if (!lastBlock)
|
|
35
|
+
throw new GeneralError('Unexpected empty fireforgeBlocks array');
|
|
36
|
+
return { insertPos: lastBlock.end, indent: detectIndent(content, lastBlock.start) };
|
|
37
|
+
}
|
|
38
|
+
const firstStmt = body.body[0];
|
|
39
|
+
if (firstStmt) {
|
|
40
|
+
const insertPos = asEstree(firstStmt).start;
|
|
41
|
+
return { insertPos, indent: detectIndent(content, insertPos) };
|
|
42
|
+
}
|
|
43
|
+
return { insertPos: body.start + 1, indent: ' ' };
|
|
44
|
+
}
|
|
21
45
|
/**
|
|
22
46
|
* AST-based implementation: finds onLoad() method body, locates existing
|
|
23
47
|
* fireforge init blocks (TryStatements containing typeof guards), and inserts
|
|
@@ -47,7 +71,7 @@ export function addInitAST(content, expression, after, marker = DEFAULT_MARKER)
|
|
|
47
71
|
const fireforgeBlocks = [];
|
|
48
72
|
for (const stmt of body.body) {
|
|
49
73
|
if (stmt.type === 'TryStatement') {
|
|
50
|
-
const tryNode = stmt;
|
|
74
|
+
const tryNode = asEstree(stmt);
|
|
51
75
|
const src = getNodeSource(content, tryNode);
|
|
52
76
|
if (/typeof\s+\w+\s*!==\s*"undefined"/.test(src)) {
|
|
53
77
|
fireforgeBlocks.push(tryNode);
|
|
@@ -68,47 +92,12 @@ export function addInitAST(content, expression, after, marker = DEFAULT_MARKER)
|
|
|
68
92
|
}
|
|
69
93
|
else {
|
|
70
94
|
// --after target not found: fall through to default (after last fireforge block)
|
|
71
|
-
|
|
72
|
-
const lastBlock = fireforgeBlocks[fireforgeBlocks.length - 1];
|
|
73
|
-
if (!lastBlock)
|
|
74
|
-
throw new GeneralError('Unexpected empty fireforgeBlocks array');
|
|
75
|
-
insertPos = lastBlock.end;
|
|
76
|
-
indent = detectIndent(content, lastBlock.start);
|
|
77
|
-
}
|
|
78
|
-
else {
|
|
79
|
-
// No fireforge blocks, insert at top of method body
|
|
80
|
-
const firstStmt = body.body[0];
|
|
81
|
-
if (firstStmt) {
|
|
82
|
-
insertPos = firstStmt.start;
|
|
83
|
-
indent = detectIndent(content, insertPos);
|
|
84
|
-
}
|
|
85
|
-
else {
|
|
86
|
-
insertPos = body.start + 1;
|
|
87
|
-
indent = ' ';
|
|
88
|
-
}
|
|
89
|
-
}
|
|
95
|
+
({ insertPos, indent } = resolveDefaultInsertion(content, body, fireforgeBlocks));
|
|
90
96
|
}
|
|
91
97
|
}
|
|
92
98
|
else {
|
|
93
99
|
// Default: insert after the last consecutive fireforge block at the start
|
|
94
|
-
|
|
95
|
-
const lastBlock = fireforgeBlocks[fireforgeBlocks.length - 1];
|
|
96
|
-
if (!lastBlock)
|
|
97
|
-
throw new GeneralError('Unexpected empty fireforgeBlocks array');
|
|
98
|
-
insertPos = lastBlock.end;
|
|
99
|
-
indent = detectIndent(content, lastBlock.start);
|
|
100
|
-
}
|
|
101
|
-
else {
|
|
102
|
-
const firstStmt = body.body[0];
|
|
103
|
-
if (firstStmt) {
|
|
104
|
-
insertPos = firstStmt.start;
|
|
105
|
-
indent = detectIndent(content, insertPos);
|
|
106
|
-
}
|
|
107
|
-
else {
|
|
108
|
-
insertPos = body.start + 1;
|
|
109
|
-
indent = ' ';
|
|
110
|
-
}
|
|
111
|
-
}
|
|
100
|
+
({ insertPos, indent } = resolveDefaultInsertion(content, body, fireforgeBlocks));
|
|
112
101
|
}
|
|
113
102
|
const block = [
|
|
114
103
|
`${indent}// ${marker} wire-init ${name} — must be first, before Firefox subsystem`,
|
|
@@ -224,7 +213,15 @@ export async function addInitToBrowserInit(engineDir, expression, after, marker
|
|
|
224
213
|
if (initPattern.test(content)) {
|
|
225
214
|
return false;
|
|
226
215
|
}
|
|
227
|
-
const { value, usedFallback } = withParserFallback(() => addInitAST(content, expression, after, marker), () => legacyAddInit(content, expression, after, marker), BROWSER_INIT_JS
|
|
216
|
+
const { value, usedFallback } = withParserFallback(() => addInitAST(content, expression, after, marker), () => legacyAddInit(content, expression, after, marker), BROWSER_INIT_JS,
|
|
217
|
+
// Rethrow only the internal-invariant GeneralErrors ("Unexpected empty
|
|
218
|
+
// …array"): those are programming bugs, and retrying the legacy scanner
|
|
219
|
+
// cannot fix a broken invariant — it just buries the stack. Everything
|
|
220
|
+
// else still falls back, which is load-bearing: the AST path raises a raw
|
|
221
|
+
// acorn SyntaxError on chrome sources acorn cannot parse (preprocessor
|
|
222
|
+
// directives), and BuildError when the file's shape is unexpected. Both
|
|
223
|
+
// are exactly what the legacy scanner is here to handle.
|
|
224
|
+
(error) => error instanceof GeneralError);
|
|
228
225
|
if (usedFallback) {
|
|
229
226
|
assertBraceBalancePreserved(content, value, BROWSER_INIT_JS);
|
|
230
227
|
}
|
|
@@ -7,7 +7,7 @@ import MagicString from 'magic-string';
|
|
|
7
7
|
import { GeneralError } from '../errors/base.js';
|
|
8
8
|
import { BuildError } from '../errors/build.js';
|
|
9
9
|
import { pathExists, readText, writeText } from '../utils/fs.js';
|
|
10
|
-
import { detectIndent, getNodeSource, parseScript, walkAST, } from './ast-utils.js';
|
|
10
|
+
import { asEstree, detectIndent, getNodeSource, parseScript, walkAST, } from './ast-utils.js';
|
|
11
11
|
import { withParserFallback } from './parser-fallback.js';
|
|
12
12
|
import { assertBraceBalancePreserved, findNearestTryLine, validateWireName, walkToTryBlockEnd, } from './wire-utils.js';
|
|
13
13
|
const BROWSER_MAIN_JS = 'browser/base/content/browser-main.js';
|
|
@@ -28,7 +28,7 @@ export function addSubscriptAST(content, name, marker = DEFAULT_MARKER) {
|
|
|
28
28
|
walkAST(ast, {
|
|
29
29
|
enter(node) {
|
|
30
30
|
if (node.type === 'TryStatement') {
|
|
31
|
-
const n = node;
|
|
31
|
+
const n = asEstree(node);
|
|
32
32
|
const src = getNodeSource(content, n);
|
|
33
33
|
if (src.includes('loadSubScript')) {
|
|
34
34
|
tryNodes.push(n);
|
|
@@ -137,7 +137,15 @@ export async function addSubscriptToBrowserMain(engineDir, name, marker = DEFAUL
|
|
|
137
137
|
if (content.includes(`content/${name}.js"`)) {
|
|
138
138
|
return false;
|
|
139
139
|
}
|
|
140
|
-
const { value, usedFallback } = withParserFallback(() => addSubscriptAST(content, name, marker), () => legacyAddSubscript(content, name, marker), BROWSER_MAIN_JS
|
|
140
|
+
const { value, usedFallback } = withParserFallback(() => addSubscriptAST(content, name, marker), () => legacyAddSubscript(content, name, marker), BROWSER_MAIN_JS,
|
|
141
|
+
// Rethrow only the internal-invariant GeneralErrors ("Unexpected empty
|
|
142
|
+
// …array"): those are programming bugs, and retrying the legacy scanner
|
|
143
|
+
// cannot fix a broken invariant — it just buries the stack. Everything
|
|
144
|
+
// else still falls back, which is load-bearing: the AST path raises a raw
|
|
145
|
+
// acorn SyntaxError on chrome sources acorn cannot parse (preprocessor
|
|
146
|
+
// directives), and BuildError when the file's shape is unexpected. Both
|
|
147
|
+
// are exactly what the legacy scanner is here to handle.
|
|
148
|
+
(error) => error instanceof GeneralError);
|
|
141
149
|
if (usedFallback) {
|
|
142
150
|
assertBraceBalancePreserved(content, value, BROWSER_MAIN_JS);
|
|
143
151
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { GeneralError, ParserFallbackError } from '../errors/base.js';
|
|
2
|
-
import { walkAST } from './ast-utils.js';
|
|
2
|
+
import { asEstree, walkAST } from './ast-utils.js';
|
|
3
3
|
/**
|
|
4
4
|
* Validates a name for safe interpolation into generated JavaScript string literals.
|
|
5
5
|
* Rejects strings containing characters that could break out of JS strings or inject code.
|
|
@@ -336,13 +336,13 @@ export function findMethodBody(ast, methodName) {
|
|
|
336
336
|
if (found)
|
|
337
337
|
return;
|
|
338
338
|
if (node.type === 'Property') {
|
|
339
|
-
const prop = node;
|
|
339
|
+
const prop = asEstree(node);
|
|
340
340
|
if (prop.key.type === 'Identifier' &&
|
|
341
341
|
names.includes(prop.key.name) &&
|
|
342
342
|
(prop.value.type === 'FunctionExpression' ||
|
|
343
343
|
prop.value.type === 'ArrowFunctionExpression')) {
|
|
344
|
-
const fn = prop.value;
|
|
345
|
-
found = fn.body;
|
|
344
|
+
const fn = asEstree(prop.value);
|
|
345
|
+
found = asEstree(fn.body);
|
|
346
346
|
}
|
|
347
347
|
}
|
|
348
348
|
},
|
|
@@ -203,6 +203,7 @@ export async function resolveAbsoluteAppPath(objDirAbs, relativeAppdir) {
|
|
|
203
203
|
entries = await readdir(distDir);
|
|
204
204
|
}
|
|
205
205
|
catch {
|
|
206
|
+
// No readable dist directory means no appdir candidate can be resolved.
|
|
206
207
|
return null;
|
|
207
208
|
}
|
|
208
209
|
for (const entry of entries) {
|
|
@@ -254,6 +255,8 @@ export async function resolveXpcshellAppdirArg(engineDir, testPaths, objDirName)
|
|
|
254
255
|
body = await readText(manifestPath);
|
|
255
256
|
}
|
|
256
257
|
catch {
|
|
258
|
+
// An unreadable manifest cannot declare an appdir; skip it and keep
|
|
259
|
+
// walking the remaining candidates.
|
|
257
260
|
continue;
|
|
258
261
|
}
|
|
259
262
|
// Operator already migrated — harness will read the appname-keyed
|
|
@@ -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
|
+
}
|
|
@@ -83,6 +83,19 @@ export declare class ExecTimeoutError extends FireForgeError {
|
|
|
83
83
|
timeoutMs: number, cause?: unknown);
|
|
84
84
|
get userMessage(): string;
|
|
85
85
|
}
|
|
86
|
+
/**
|
|
87
|
+
* Error thrown when a file-lock wait times out because another process
|
|
88
|
+
* holds the lock (FORGE H5).
|
|
89
|
+
*
|
|
90
|
+
* Dedicated subclass so the CLI boundary renders lock contention as the
|
|
91
|
+
* one-line reason-first/remedy-second refusal it is — before this, the
|
|
92
|
+
* timeout surfaced as a plain `Error`, which `withErrorHandling` treats
|
|
93
|
+
* as an internal failure and prints with a five-frame stack. The refusal
|
|
94
|
+
* was always correct; the presentation made it look like a crash.
|
|
95
|
+
*/
|
|
96
|
+
export declare class LockContentionError extends FireForgeError {
|
|
97
|
+
readonly code: 1;
|
|
98
|
+
}
|
|
86
99
|
/**
|
|
87
100
|
* Error thrown when the user cancels an interactive prompt.
|
|
88
101
|
*/
|
package/dist/src/errors/base.js
CHANGED
|
@@ -113,6 +113,19 @@ export class ExecTimeoutError extends FireForgeError {
|
|
|
113
113
|
'If the host is just slow or loaded, re-running may succeed.');
|
|
114
114
|
}
|
|
115
115
|
}
|
|
116
|
+
/**
|
|
117
|
+
* Error thrown when a file-lock wait times out because another process
|
|
118
|
+
* holds the lock (FORGE H5).
|
|
119
|
+
*
|
|
120
|
+
* Dedicated subclass so the CLI boundary renders lock contention as the
|
|
121
|
+
* one-line reason-first/remedy-second refusal it is — before this, the
|
|
122
|
+
* timeout surfaced as a plain `Error`, which `withErrorHandling` treats
|
|
123
|
+
* as an internal failure and prints with a five-frame stack. The refusal
|
|
124
|
+
* was always correct; the presentation made it look like a crash.
|
|
125
|
+
*/
|
|
126
|
+
export class LockContentionError extends FireForgeError {
|
|
127
|
+
code = ExitCode.GENERAL_ERROR;
|
|
128
|
+
}
|
|
116
129
|
/**
|
|
117
130
|
* Error thrown when the user cancels an interactive prompt.
|
|
118
131
|
*/
|
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.
|
|
@@ -18,3 +18,16 @@ export declare class RebaseSessionExistsError extends RebaseError {
|
|
|
18
18
|
export declare class NoRebaseSessionError extends RebaseError {
|
|
19
19
|
constructor();
|
|
20
20
|
}
|
|
21
|
+
/**
|
|
22
|
+
* Thrown when the session file exists but cannot be used.
|
|
23
|
+
*
|
|
24
|
+
* This case had no error of its own before 0.41.0 and was reported as
|
|
25
|
+
* {@link NoRebaseSessionError} by `--continue`/`--abort` while `rebase`
|
|
26
|
+
* reported {@link RebaseSessionExistsError} — a closed cycle in which each
|
|
27
|
+
* command pointed at the other two. The message names the file so an operator
|
|
28
|
+
* always has a way out, and `--abort` now clears a corrupt session rather than
|
|
29
|
+
* refusing to run against one.
|
|
30
|
+
*/
|
|
31
|
+
export declare class CorruptRebaseSessionError extends RebaseError {
|
|
32
|
+
constructor(sessionPath: string, reason: string);
|
|
33
|
+
}
|
|
@@ -32,3 +32,20 @@ export class NoRebaseSessionError extends RebaseError {
|
|
|
32
32
|
super('No rebase session in progress. Start one with "fireforge rebase".');
|
|
33
33
|
}
|
|
34
34
|
}
|
|
35
|
+
/**
|
|
36
|
+
* Thrown when the session file exists but cannot be used.
|
|
37
|
+
*
|
|
38
|
+
* This case had no error of its own before 0.41.0 and was reported as
|
|
39
|
+
* {@link NoRebaseSessionError} by `--continue`/`--abort` while `rebase`
|
|
40
|
+
* reported {@link RebaseSessionExistsError} — a closed cycle in which each
|
|
41
|
+
* command pointed at the other two. The message names the file so an operator
|
|
42
|
+
* always has a way out, and `--abort` now clears a corrupt session rather than
|
|
43
|
+
* refusing to run against one.
|
|
44
|
+
*/
|
|
45
|
+
export class CorruptRebaseSessionError extends RebaseError {
|
|
46
|
+
constructor(sessionPath, reason) {
|
|
47
|
+
super(`The rebase session at ${sessionPath} cannot be read (${reason}).\n` +
|
|
48
|
+
'Run "fireforge rebase --abort" to discard it and restore the engine, ' +
|
|
49
|
+
'or delete the file to start over.');
|
|
50
|
+
}
|
|
51
|
+
}
|
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';
|
|
@@ -279,6 +279,41 @@ export interface ReExportOptions {
|
|
|
279
279
|
* the command implementation ignores it.
|
|
280
280
|
*/
|
|
281
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;
|
|
292
|
+
/**
|
|
293
|
+
* Bypass per-patch lint result cache reads AND writes for this
|
|
294
|
+
* invocation (`--no-cache`). The cache is what makes a repeat
|
|
295
|
+
* re-export of an unchanged patch skip the checkJs program build
|
|
296
|
+
* entirely (FORGE J1).
|
|
297
|
+
*/
|
|
298
|
+
noCache?: boolean;
|
|
299
|
+
/**
|
|
300
|
+
* Refuse (non-zero exit, patch not written) a re-export whose refreshed
|
|
301
|
+
* body would absorb engine lines not present in the old patch body —
|
|
302
|
+
* the multi-session guard against silently capturing another session's
|
|
303
|
+
* uncommitted edits in files the patch already owns. The drift preview
|
|
304
|
+
* always prints; this flag turns it into a hard stop. Mutually
|
|
305
|
+
* exclusive with `--scan` and `--files`.
|
|
306
|
+
*/
|
|
307
|
+
refuseForeignDrift?: boolean;
|
|
308
|
+
/**
|
|
309
|
+
* Engine-relative files whose drift is EXPECTED (`--expect`, repeatable;
|
|
310
|
+
* requires `--refuse-foreign-drift`). The content-based drift detector
|
|
311
|
+
* cannot tell the exporting session's own slice edits from another
|
|
312
|
+
* session's (FORGE L6), so a real slice export under the refusal flag
|
|
313
|
+
* names its intended files here: drift confined to expected files
|
|
314
|
+
* proceeds, drift anywhere else still refuses.
|
|
315
|
+
*/
|
|
316
|
+
expect?: string[];
|
|
282
317
|
}
|
|
283
318
|
/**
|
|
284
319
|
* Options for the `fireforge patch tier` subcommand. Sets or clears the
|
|
@@ -376,6 +411,8 @@ export interface PatchSplitOptions {
|
|
|
376
411
|
forceUnsafe?: boolean;
|
|
377
412
|
/** Skip per-patch lint of the projected bodies. */
|
|
378
413
|
skipLint?: boolean;
|
|
414
|
+
/** Wait budget for the patch directory lock (`--wait-lock [seconds]`). */
|
|
415
|
+
waitLock?: number | boolean;
|
|
379
416
|
}
|
|
380
417
|
/**
|
|
381
418
|
* Options for the `fireforge patch move-files` subcommand. Without
|
|
@@ -403,6 +440,8 @@ export interface PatchMoveFilesOptions {
|
|
|
403
440
|
forceUnsafe?: boolean;
|
|
404
441
|
/** Skip per-patch lint of the projected bodies. */
|
|
405
442
|
skipLint?: boolean;
|
|
443
|
+
/** Wait budget for the patch directory lock (`--wait-lock [seconds]`). */
|
|
444
|
+
waitLock?: number | boolean;
|
|
406
445
|
}
|
|
407
446
|
/**
|
|
408
447
|
* Options for the rebase command.
|
|
@@ -474,6 +513,24 @@ export interface TestOptions {
|
|
|
474
513
|
headless?: boolean;
|
|
475
514
|
/** Run incremental UI build before testing */
|
|
476
515
|
build?: boolean;
|
|
516
|
+
/**
|
|
517
|
+
* Run the scoped pre-test build (packaging exactly the requested paths,
|
|
518
|
+
* MIXED harnesses allowed) and exit without dispatching tests. One
|
|
519
|
+
* ~10-minute build then covers both an xpcshell and a browser-chrome
|
|
520
|
+
* half of a slice; run each harness afterwards without `--build`
|
|
521
|
+
* (FORGE J9). Emits `FIREFORGE-VERDICT: PASS` on success.
|
|
522
|
+
*/
|
|
523
|
+
buildOnly?: boolean;
|
|
524
|
+
/**
|
|
525
|
+
* Union the paths this build packages onto the recorded coverage claim
|
|
526
|
+
* instead of REPLACING it (FORGE L1), so successive scoped builds
|
|
527
|
+
* accumulate and an earlier slice's build-less runs stay covered. Valid
|
|
528
|
+
* only with `--build`/`--build-only` and explicit paths. Refused
|
|
529
|
+
* fail-closed unless the build anchor is unchanged: same engine HEAD,
|
|
530
|
+
* same `engine/mozconfig`, and every previously fingerprinted packageable
|
|
531
|
+
* file byte-identical. See `src/core/coverage-extend.ts`.
|
|
532
|
+
*/
|
|
533
|
+
extendCoverage?: boolean;
|
|
477
534
|
/** Forward mach's pathless auto-selection mode. Valid only with no explicit paths. */
|
|
478
535
|
auto?: boolean;
|
|
479
536
|
/**
|
|
@@ -735,6 +792,8 @@ export interface PatchDeleteOptions {
|
|
|
735
792
|
dryRun?: boolean;
|
|
736
793
|
/** Bypass the hard refusal when later patches depend on the target. */
|
|
737
794
|
forceUnsafe?: boolean;
|
|
795
|
+
/** Wait budget for the patch directory lock (`--wait-lock [seconds]`). */
|
|
796
|
+
waitLock?: number | boolean;
|
|
738
797
|
}
|
|
739
798
|
/**
|
|
740
799
|
* Options for the `fireforge patch rename` subcommand. Updates the
|
|
@@ -750,9 +809,22 @@ export interface PatchRenameOptions {
|
|
|
750
809
|
* New human-readable name. Sanitised the same way `export --name`
|
|
751
810
|
* sanitises into the filename slug (lowercase, non-alphanumerics
|
|
752
811
|
* collapsed to `-`, length-capped). The patch's `name` field stores
|
|
753
|
-
* the raw value; the filename uses the sanitised slug.
|
|
812
|
+
* the raw value; the filename uses the sanitised slug. Optional when
|
|
813
|
+
* `--category`/`--order`/`--description` carry the change.
|
|
754
814
|
*/
|
|
755
815
|
to?: string;
|
|
816
|
+
/**
|
|
817
|
+
* New category (validated against configured categories). Rewrites
|
|
818
|
+
* the filename prefix and the manifest row in one transaction —
|
|
819
|
+
* recategorising no longer requires `patch delete` + fresh export.
|
|
820
|
+
*/
|
|
821
|
+
category?: string;
|
|
822
|
+
/**
|
|
823
|
+
* Move the patch to this exact UNUSED sparse order. Collisions refuse
|
|
824
|
+
* with a pointer to `patch reorder` (which renumbers siblings); an
|
|
825
|
+
* order change is projected through cross-patch lint first.
|
|
826
|
+
*/
|
|
827
|
+
order?: number;
|
|
756
828
|
/**
|
|
757
829
|
* Replacement description. Omit to leave the description unchanged
|
|
758
830
|
* (intentional — operators frequently want to relabel the slug
|
|
@@ -765,6 +837,8 @@ export interface PatchRenameOptions {
|
|
|
765
837
|
yes?: boolean;
|
|
766
838
|
/** Bypass force-mode patchPolicy refusals. */
|
|
767
839
|
forceUnsafe?: boolean;
|
|
840
|
+
/** Wait budget for the patch directory lock (`--wait-lock [seconds]`). */
|
|
841
|
+
waitLock?: number | boolean;
|
|
768
842
|
}
|
|
769
843
|
/**
|
|
770
844
|
* Options for the patch reorder command.
|
|
@@ -776,6 +850,8 @@ export interface PatchReorderOptions {
|
|
|
776
850
|
yes?: boolean;
|
|
777
851
|
dryRun?: boolean;
|
|
778
852
|
forceUnsafe?: boolean;
|
|
853
|
+
/** Wait budget for the patch directory lock (`--wait-lock [seconds]`). */
|
|
854
|
+
waitLock?: number | boolean;
|
|
779
855
|
}
|
|
780
856
|
/**
|
|
781
857
|
* Options for the patch compact command.
|
|
@@ -787,6 +863,8 @@ export interface PatchCompactOptions {
|
|
|
787
863
|
dryRun?: boolean;
|
|
788
864
|
/** Bypass force-mode patchPolicy refusals. */
|
|
789
865
|
forceUnsafe?: boolean;
|
|
866
|
+
/** Wait budget for the patch directory lock (`--wait-lock [seconds]`). */
|
|
867
|
+
waitLock?: number | boolean;
|
|
790
868
|
}
|
|
791
869
|
/**
|
|
792
870
|
* Options for the status command.
|
|
@@ -809,6 +887,36 @@ export interface StatusOptions {
|
|
|
809
887
|
testCoverage?: boolean;
|
|
810
888
|
/** Output machine-readable JSON instead of human-readable text. */
|
|
811
889
|
json?: boolean;
|
|
890
|
+
/**
|
|
891
|
+
* With `--json`: emit only the summary counts (plus the offending
|
|
892
|
+
* files per fail-set classification when the `--check`/`--fail-on`
|
|
893
|
+
* policy is active), omitting the per-file `files[]` payload that
|
|
894
|
+
* grows with the queue (FORGE K8). Refused without `--json`.
|
|
895
|
+
*/
|
|
896
|
+
summary?: boolean;
|
|
897
|
+
/**
|
|
898
|
+
* With `--json` (and composing with `--summary`), append an additive
|
|
899
|
+
* `ownership` block — the flat path→owning-patch rows plus
|
|
900
|
+
* managed/unmanaged/conflict counts — so a gate reads ownership,
|
|
901
|
+
* classification, and the check verdict from ONE scan instead of three
|
|
902
|
+
* back-to-back `status` invocations (FORGE L3). A modifier, not a mode:
|
|
903
|
+
* exit semantics are unchanged, so ownership conflicts still fail only
|
|
904
|
+
* the human `--ownership` mode. Refused without `--json`.
|
|
905
|
+
*/
|
|
906
|
+
includeOwnership?: boolean;
|
|
907
|
+
/**
|
|
908
|
+
* Exit non-zero when any classification in the fail policy is
|
|
909
|
+
* non-empty (default policy: unmanaged, patch-owned-drift, conflict).
|
|
910
|
+
* Composes with the default view and `--json`; refused alongside
|
|
911
|
+
* `--raw`/`--unmanaged`/`--ownership`/`--test-coverage` (FORGE G1).
|
|
912
|
+
*/
|
|
913
|
+
check?: boolean;
|
|
914
|
+
/**
|
|
915
|
+
* Comma-separated classification list replacing the default `--check`
|
|
916
|
+
* policy. Implies `--check`. Unknown values refuse, naming the valid
|
|
917
|
+
* classification set.
|
|
918
|
+
*/
|
|
919
|
+
failOn?: string;
|
|
812
920
|
}
|
|
813
921
|
/**
|
|
814
922
|
* Options for the token add command.
|
|
@@ -900,8 +1008,9 @@ export interface LintCommandOptions {
|
|
|
900
1008
|
* the cross-patch rules once over the whole queue so queue-level
|
|
901
1009
|
* findings (duplicate creations, forward imports) still surface.
|
|
902
1010
|
*
|
|
903
|
-
*
|
|
904
|
-
*
|
|
1011
|
+
* Positional file arguments change meaning under this flag: they are
|
|
1012
|
+
* PATCH selectors resolved like {@link patches} entries, not engine
|
|
1013
|
+
* file paths (FORGE G14).
|
|
905
1014
|
*/
|
|
906
1015
|
perPatch?: boolean;
|
|
907
1016
|
/**
|
|
@@ -923,4 +1032,11 @@ export interface LintCommandOptions {
|
|
|
923
1032
|
* for CLI consistency, but only `--per-patch` currently uses the cache.
|
|
924
1033
|
*/
|
|
925
1034
|
noCache?: boolean;
|
|
1035
|
+
/**
|
|
1036
|
+
* With `--per-patch`, write a machine-readable JSON report (schemaVersion
|
|
1037
|
+
* 1: per-patch lineCount, filesAffected, tier, thresholds, issues, and
|
|
1038
|
+
* lintIgnore-suppressed issues) to this path (FORGE G9/G10). Requires
|
|
1039
|
+
* {@link perPatch}.
|
|
1040
|
+
*/
|
|
1041
|
+
report?: string;
|
|
926
1042
|
}
|
|
@@ -212,6 +212,14 @@ export interface PatchLintIssue {
|
|
|
212
212
|
fingerprint?: string;
|
|
213
213
|
/** Human-readable description of the issue */
|
|
214
214
|
message: string;
|
|
215
|
+
/**
|
|
216
|
+
* Queue entry filenames this issue implicates (the declaring/importing
|
|
217
|
+
* patch, or every creator for a duplicate-creation clash). Used by the
|
|
218
|
+
* export placement gate to attribute projected errors to the exported
|
|
219
|
+
* patch vs pre-existing patches without parsing messages or the
|
|
220
|
+
* rename-sensitive fingerprint (FORGE K9).
|
|
221
|
+
*/
|
|
222
|
+
patches?: string[];
|
|
215
223
|
/** Severity: errors block export, warnings are advisory, notices are informational (not counted) */
|
|
216
224
|
severity: 'error' | 'warning' | 'notice';
|
|
217
225
|
/**
|
|
@@ -253,6 +253,25 @@ export interface PatchLintConfig {
|
|
|
253
253
|
* behaviour (built-in shim only).
|
|
254
254
|
*/
|
|
255
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;
|
|
256
275
|
/** File paths exempt from the raw-color-value check (exact or basename match) */
|
|
257
276
|
rawColorAllowlist?: string[];
|
|
258
277
|
/** Enforce JSDoc on class-method exports in patch-owned .sys.mjs files. Default: 'off'. */
|
|
@@ -260,6 +260,13 @@ export interface ApplyResult {
|
|
|
260
260
|
* persisted — the engine has been restored to its pre-apply state.
|
|
261
261
|
*/
|
|
262
262
|
rolledBack?: boolean;
|
|
263
|
+
/**
|
|
264
|
+
* Operator-facing warnings, printed by `logApplyResult`. Populated when
|
|
265
|
+
* apply overwrote a deployed, patch-owned file whose engine bytes
|
|
266
|
+
* differed from the component source (FORGE J6) — the case where a
|
|
267
|
+
* shipped engine-only fix is silently reverted by the copy.
|
|
268
|
+
*/
|
|
269
|
+
warnings?: string[];
|
|
263
270
|
}
|
|
264
271
|
/**
|
|
265
272
|
* An action that would be performed during a dry-run deploy.
|