@hominis/fireforge 0.33.0 → 0.34.1
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 +16 -0
- package/dist/src/commands/build.js +9 -1
- package/dist/src/commands/doctor-furnace-jar.d.ts +16 -0
- package/dist/src/commands/doctor-furnace-jar.js +47 -0
- package/dist/src/commands/doctor-furnace.js +2 -0
- package/dist/src/commands/export-flow.js +4 -1
- package/dist/src/commands/export-placement-gate.js +4 -1
- package/dist/src/commands/export.js +61 -4
- package/dist/src/commands/furnace/chrome-doc-templates.d.ts +20 -0
- package/dist/src/commands/furnace/chrome-doc-templates.js +52 -0
- package/dist/src/commands/furnace/chrome-doc.d.ts +10 -0
- package/dist/src/commands/furnace/chrome-doc.js +31 -4
- package/dist/src/commands/furnace/create-browser-test.d.ts +30 -0
- package/dist/src/commands/furnace/create-browser-test.js +180 -0
- package/dist/src/commands/furnace/create-mochikit.js +11 -4
- package/dist/src/commands/furnace/create-xpcshell.d.ts +1 -1
- package/dist/src/commands/furnace/create-xpcshell.js +38 -12
- package/dist/src/commands/furnace/create.js +7 -114
- package/dist/src/commands/furnace/index.js +6 -1
- package/dist/src/commands/furnace/scan.d.ts +1 -0
- package/dist/src/commands/furnace/scan.js +57 -27
- package/dist/src/commands/furnace/validate.js +17 -1
- package/dist/src/commands/re-export-options.d.ts +26 -0
- package/dist/src/commands/re-export-options.js +48 -1
- package/dist/src/commands/re-export.js +4 -1
- package/dist/src/commands/register.js +10 -1
- package/dist/src/commands/test-diagnose.js +12 -0
- package/dist/src/commands/test.js +29 -22
- package/dist/src/core/furnace-registration.d.ts +24 -0
- package/dist/src/core/furnace-registration.js +56 -3
- package/dist/src/core/furnace-validate-registration.js +18 -0
- package/dist/src/core/mach-resource-shim.d.ts +70 -16
- package/dist/src/core/mach-resource-shim.js +310 -52
- package/dist/src/core/mach.d.ts +51 -10
- package/dist/src/core/mach.js +76 -32
- package/dist/src/core/manifest-helpers.d.ts +13 -0
- package/dist/src/core/manifest-helpers.js +1 -1
- package/dist/src/core/manifest-rules.d.ts +13 -3
- package/dist/src/core/manifest-rules.js +44 -17
- package/dist/src/core/patch-export.d.ts +10 -0
- package/dist/src/core/patch-export.js +23 -2
- package/dist/src/core/register-module.d.ts +1 -1
- package/dist/src/core/register-module.js +15 -2
- package/dist/src/core/register-result.d.ts +9 -0
- package/dist/src/core/register-scaffold.d.ts +55 -0
- package/dist/src/core/register-scaffold.js +146 -0
- package/dist/src/core/register-test-manifest.js +3 -1
- package/dist/src/core/register-xpcshell-test.d.ts +30 -0
- package/dist/src/core/register-xpcshell-test.js +96 -0
- package/dist/src/core/test-harness-crash.d.ts +26 -1
- package/dist/src/core/test-harness-crash.js +149 -11
- package/dist/src/core/xpcshell-appdir.d.ts +7 -0
- package/dist/src/core/xpcshell-appdir.js +12 -3
- package/dist/src/types/commands/options.d.ts +12 -0
- package/package.json +3 -3
|
@@ -32,7 +32,32 @@ export interface HarnessCrashSignature {
|
|
|
32
32
|
export interface HarnessRunVerdict {
|
|
33
33
|
kind: HarnessRunClassification;
|
|
34
34
|
signature?: HarnessCrashSignature;
|
|
35
|
+
/**
|
|
36
|
+
* Set when a non-zero mach exit code was overridden because the output
|
|
37
|
+
* embeds a completed green summary — the exit code followed harness
|
|
38
|
+
* noise, not a test result. Callers should surface a note.
|
|
39
|
+
*/
|
|
40
|
+
greenSummaryOverride?: boolean;
|
|
35
41
|
}
|
|
42
|
+
/**
|
|
43
|
+
* Strips non-signal noise from captured output before crash-signature
|
|
44
|
+
* matching: resource-monitor degradation warnings, and traceback blocks
|
|
45
|
+
* that mach caught itself (telemetry submission tracebacks are printed but
|
|
46
|
+
* never abort the run). The stripped text is used ONLY as crash evidence —
|
|
47
|
+
* classification of test results still reads the full output.
|
|
48
|
+
*/
|
|
49
|
+
export declare function stripNonSignalNoise(output: string): string;
|
|
50
|
+
/**
|
|
51
|
+
* True when the output embeds a COMPLETED, GREEN suite summary: an
|
|
52
|
+
* execution signal, `Unexpected results: 0` (and no non-zero unexpected
|
|
53
|
+
* count), a `SUITE_END` marker, and no real `TEST-UNEXPECTED-*` lines.
|
|
54
|
+
* Such a run finished its suite; any startup-traceback-shaped noise in the
|
|
55
|
+
* same output is by definition non-fatal, so this vetoes signature-based
|
|
56
|
+
* crash classification (field report: fully green sharded runs reported
|
|
57
|
+
* `CRASH (N attempts)` because degradation warnings matched the psutil
|
|
58
|
+
* signals). Exported for direct unit testing.
|
|
59
|
+
*/
|
|
60
|
+
export declare function hasCompletedGreenSummary(output: string): boolean;
|
|
36
61
|
/**
|
|
37
62
|
* Detects the known harness-crash shapes in captured mach output.
|
|
38
63
|
* Returns undefined for anything that looks like a genuine test result.
|
|
@@ -55,7 +80,7 @@ export declare function detectHarnessCrashSignature(output: string): HarnessCras
|
|
|
55
80
|
*/
|
|
56
81
|
export declare function classifyHarnessRun(exitCode: number, output: string, requestedPaths: readonly string[]): HarnessRunVerdict;
|
|
57
82
|
/** Builds the operator-facing failure message after retries are exhausted. */
|
|
58
|
-
export declare function buildHarnessCrashMessage(signature: HarnessCrashSignature, attempts: number): string;
|
|
83
|
+
export declare function buildHarnessCrashMessage(signature: HarnessCrashSignature, attempts: number, commandLabel?: string): string;
|
|
59
84
|
/**
|
|
60
85
|
* Builds the message for a run that produced no `TEST-START` despite
|
|
61
86
|
* requesting paths — including exit-code-zero runs whose `Passed: 0`
|
|
@@ -23,6 +23,15 @@
|
|
|
23
23
|
* of reporting phantom test failures (or phantom passes).
|
|
24
24
|
*/
|
|
25
25
|
const TEST_START_PATTERN = /\bTEST-START\b/;
|
|
26
|
+
/**
|
|
27
|
+
* Structured-log execution marker (`mach xpcshell-test` mozlog output uses
|
|
28
|
+
* `TEST_START`/`SUITE_END` with underscores, not the hyphenated
|
|
29
|
+
* `TEST-START` the browser-chrome dispatch prints).
|
|
30
|
+
*/
|
|
31
|
+
const STRUCTURED_TEST_START_PATTERN = /\bTEST_START\b/;
|
|
32
|
+
const SUITE_END_PATTERN = /\bSUITE_END\b/;
|
|
33
|
+
const GREEN_UNEXPECTED_SUMMARY_PATTERN = /\bUnexpected results:\s*0\b/;
|
|
34
|
+
const NONZERO_UNEXPECTED_SUMMARY_PATTERN = /\bUnexpected results:\s*[1-9]/;
|
|
26
35
|
/**
|
|
27
36
|
* Execution signals emitted by the suite-specific xpcshell dispatch
|
|
28
37
|
* (`mach xpcshell-test`), which does NOT print `TEST-START` lines the way
|
|
@@ -47,6 +56,17 @@ const NO_OUTPUT_TIMEOUT_PATTERN = /timed out after \d+ seconds with no output/i;
|
|
|
47
56
|
* on macOS. Each is matched per-line so the evidence line in the report is
|
|
48
57
|
* the concrete failure, not the whole traceback.
|
|
49
58
|
*/
|
|
59
|
+
// Downstream report (0.34.0 cycle): a pre-fix _DegradedReading fallback that
|
|
60
|
+
// wasn't a real namedtuple duck type crashed mozsystemmonitor on the fallback
|
|
61
|
+
// itself (`_build_meta` subscripts the reading; `_collect` unpacks it); a
|
|
62
|
+
// startup abort with zero TEST-START lines from this family is a crash, not
|
|
63
|
+
// a test failure. The `_collect failed` variant is caught-and-logged, so it
|
|
64
|
+
// carries no Traceback header — it gets its own zero-TEST-START check in
|
|
65
|
+
// `detectHarnessCrashSignature` besides joining the traceback cluster.
|
|
66
|
+
const DEGRADED_READING_CRASH_SIGNALS = [
|
|
67
|
+
/'_DegradedReading' object is not subscriptable/,
|
|
68
|
+
/'_DegradedReading' object is not iterable/,
|
|
69
|
+
];
|
|
50
70
|
const STARTUP_TRACEBACK_SIGNALS = [
|
|
51
71
|
/AttributeError:.*SystemResourceMonitor/,
|
|
52
72
|
/'SystemResourceMonitor' object has no attribute/,
|
|
@@ -55,6 +75,7 @@ const STARTUP_TRACEBACK_SIGNALS = [
|
|
|
55
75
|
/HOST_VM_INFO64/,
|
|
56
76
|
/\(ipc\/mig\) array not large enough/,
|
|
57
77
|
/psutil\.[A-Za-z]*Error/,
|
|
78
|
+
...DEGRADED_READING_CRASH_SIGNALS,
|
|
58
79
|
];
|
|
59
80
|
function findLine(output, patterns) {
|
|
60
81
|
for (const line of output.split(/\r?\n/)) {
|
|
@@ -63,6 +84,91 @@ function findLine(output, patterns) {
|
|
|
63
84
|
}
|
|
64
85
|
return undefined;
|
|
65
86
|
}
|
|
87
|
+
/**
|
|
88
|
+
* Non-signal noise lines: the resource-monitor degrade path (FireForge's
|
|
89
|
+
* own guard plus mozlog's `_collect failed`) prints warnings on runs that
|
|
90
|
+
* then complete green. Field report (0.34.0 cycle): every multi-file suite
|
|
91
|
+
* was reported CRASH because these lines matched the startup-traceback
|
|
92
|
+
* signals even though the embedded summary was fully green. They are
|
|
93
|
+
* excluded from crash evidence entirely.
|
|
94
|
+
*/
|
|
95
|
+
const NOISE_LINE_PATTERNS = [
|
|
96
|
+
/\bUserWarning\b/,
|
|
97
|
+
/psutil failed to run/i,
|
|
98
|
+
// `_collect failed` chatter is noise on green runs, EXCEPT the
|
|
99
|
+
// `_DegradedReading` variant: that is the crash evidence for the
|
|
100
|
+
// "object is not iterable" startup-abort signature above and must
|
|
101
|
+
// survive stripNonSignalNoise.
|
|
102
|
+
/_collect failed(?!.*_DegradedReading)/i,
|
|
103
|
+
/FireForge: host resource monitor degraded/i,
|
|
104
|
+
/warnings\.warn\(/,
|
|
105
|
+
];
|
|
106
|
+
/** Matches the caught/telemetry context that marks a traceback as benign. */
|
|
107
|
+
const BENIGN_TRACEBACK_CONTEXT = /telemetry|glean/i;
|
|
108
|
+
/**
|
|
109
|
+
* Strips non-signal noise from captured output before crash-signature
|
|
110
|
+
* matching: resource-monitor degradation warnings, and traceback blocks
|
|
111
|
+
* that mach caught itself (telemetry submission tracebacks are printed but
|
|
112
|
+
* never abort the run). The stripped text is used ONLY as crash evidence —
|
|
113
|
+
* classification of test results still reads the full output.
|
|
114
|
+
*/
|
|
115
|
+
export function stripNonSignalNoise(output) {
|
|
116
|
+
const lines = output.split(/\r?\n/);
|
|
117
|
+
const kept = [];
|
|
118
|
+
for (let i = 0; i < lines.length; i += 1) {
|
|
119
|
+
const line = lines[i] ?? '';
|
|
120
|
+
if (NOISE_LINE_PATTERNS.some((p) => p.test(line)))
|
|
121
|
+
continue;
|
|
122
|
+
if (TRACEBACK_PATTERN.test(line)) {
|
|
123
|
+
// Collect the whole traceback block: the header, indented frame/code
|
|
124
|
+
// lines, and the trailing unindented exception line.
|
|
125
|
+
const block = [line];
|
|
126
|
+
let j = i + 1;
|
|
127
|
+
for (; j < lines.length; j += 1) {
|
|
128
|
+
const blockLine = lines[j] ?? '';
|
|
129
|
+
block.push(blockLine);
|
|
130
|
+
const isIndented = /^\s/.test(blockLine) || blockLine.trim().length === 0;
|
|
131
|
+
if (!isIndented)
|
|
132
|
+
break; // unindented exception line terminates the block
|
|
133
|
+
}
|
|
134
|
+
if (BENIGN_TRACEBACK_CONTEXT.test(block.join('\n'))) {
|
|
135
|
+
i = j; // drop the whole caught-telemetry traceback block
|
|
136
|
+
continue;
|
|
137
|
+
}
|
|
138
|
+
// A real traceback stays in evidence line-by-line (minus noise lines
|
|
139
|
+
// already filtered above).
|
|
140
|
+
}
|
|
141
|
+
kept.push(line);
|
|
142
|
+
}
|
|
143
|
+
return kept.join('\n');
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* True when the output carries any execution signal: the browser-chrome
|
|
147
|
+
* `TEST-START` marker, the structured-log `TEST_START` marker, or the
|
|
148
|
+
* suite-specific xpcshell result-summary block.
|
|
149
|
+
*/
|
|
150
|
+
function hasExecutionSignal(output) {
|
|
151
|
+
return (TEST_START_PATTERN.test(output) ||
|
|
152
|
+
STRUCTURED_TEST_START_PATTERN.test(output) ||
|
|
153
|
+
hasXpcshellResultSummary(output));
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* True when the output embeds a COMPLETED, GREEN suite summary: an
|
|
157
|
+
* execution signal, `Unexpected results: 0` (and no non-zero unexpected
|
|
158
|
+
* count), a `SUITE_END` marker, and no real `TEST-UNEXPECTED-*` lines.
|
|
159
|
+
* Such a run finished its suite; any startup-traceback-shaped noise in the
|
|
160
|
+
* same output is by definition non-fatal, so this vetoes signature-based
|
|
161
|
+
* crash classification (field report: fully green sharded runs reported
|
|
162
|
+
* `CRASH (N attempts)` because degradation warnings matched the psutil
|
|
163
|
+
* signals). Exported for direct unit testing.
|
|
164
|
+
*/
|
|
165
|
+
export function hasCompletedGreenSummary(output) {
|
|
166
|
+
return (hasExecutionSignal(output) &&
|
|
167
|
+
SUITE_END_PATTERN.test(output) &&
|
|
168
|
+
GREEN_UNEXPECTED_SUMMARY_PATTERN.test(output) &&
|
|
169
|
+
!NONZERO_UNEXPECTED_SUMMARY_PATTERN.test(output) &&
|
|
170
|
+
realUnexpectedFailureLines(output).length === 0);
|
|
171
|
+
}
|
|
66
172
|
/**
|
|
67
173
|
* True when the captured output carries the suite-specific xpcshell
|
|
68
174
|
* result-summary block, which proves tests executed even though the
|
|
@@ -83,13 +189,22 @@ function realUnexpectedFailureLines(output) {
|
|
|
83
189
|
* Returns undefined for anything that looks like a genuine test result.
|
|
84
190
|
*/
|
|
85
191
|
export function detectHarnessCrashSignature(output) {
|
|
86
|
-
const hasTestStart =
|
|
192
|
+
const hasTestStart = hasExecutionSignal(output);
|
|
87
193
|
const realFailures = realUnexpectedFailureLines(output);
|
|
88
|
-
//
|
|
89
|
-
//
|
|
90
|
-
//
|
|
91
|
-
|
|
92
|
-
|
|
194
|
+
// A completed green embedded summary vetoes signature-based crash
|
|
195
|
+
// classification outright: the suite finished, so any startup-shaped
|
|
196
|
+
// noise in the same output was non-fatal. (The post-green shutdown
|
|
197
|
+
// re-entry shape below is exempt — it is deliberately a crash verdict on
|
|
198
|
+
// an otherwise-green log, keyed on its own explicit markers.)
|
|
199
|
+
const greenSummaryVeto = hasCompletedGreenSummary(output);
|
|
200
|
+
// Startup traceback cluster (resource monitor / psutil), scanned over
|
|
201
|
+
// noise-stripped evidence so degradation warnings and caught telemetry
|
|
202
|
+
// tracebacks never count. Real test failures take precedence: a
|
|
203
|
+
// traceback printed during teardown of a genuinely failing run must not
|
|
204
|
+
// get the whole run retried.
|
|
205
|
+
const evidence = stripNonSignalNoise(output);
|
|
206
|
+
if (!greenSummaryVeto && TRACEBACK_PATTERN.test(evidence) && realFailures.length === 0) {
|
|
207
|
+
const signalLine = findLine(evidence, STARTUP_TRACEBACK_SIGNALS);
|
|
93
208
|
if (signalLine) {
|
|
94
209
|
return { reason: 'harness startup traceback (resource monitor/psutil)', line: signalLine };
|
|
95
210
|
}
|
|
@@ -98,7 +213,19 @@ export function detectHarnessCrashSignature(output) {
|
|
|
98
213
|
// the no-output timeout. A trailing "Passed: 0" summary is part of this
|
|
99
214
|
// shape and must not be read as a result.
|
|
100
215
|
if (!hasTestStart) {
|
|
101
|
-
|
|
216
|
+
// Startup abort on the degraded-reading fallback family: the `_collect
|
|
217
|
+
// failed: '_DegradedReading' ...` variant is caught-and-logged (no
|
|
218
|
+
// Traceback header), so the traceback cluster above never sees it.
|
|
219
|
+
if (realFailures.length === 0) {
|
|
220
|
+
const degradedLine = findLine(evidence, DEGRADED_READING_CRASH_SIGNALS);
|
|
221
|
+
if (degradedLine) {
|
|
222
|
+
return {
|
|
223
|
+
reason: 'degraded resource reading crashed the harness fallback (_DegradedReading)',
|
|
224
|
+
line: degradedLine,
|
|
225
|
+
};
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
const timeoutLine = findLine(evidence, [NO_OUTPUT_TIMEOUT_PATTERN]);
|
|
102
229
|
if (timeoutLine) {
|
|
103
230
|
return { reason: 'no-output timeout before any test started', line: timeoutLine };
|
|
104
231
|
}
|
|
@@ -133,15 +260,26 @@ export function classifyHarnessRun(exitCode, output, requestedPaths) {
|
|
|
133
260
|
if (signature) {
|
|
134
261
|
return { kind: 'harness-crash', signature };
|
|
135
262
|
}
|
|
136
|
-
const ranTests =
|
|
263
|
+
const ranTests = hasExecutionSignal(output);
|
|
137
264
|
if (!ranTests && requestedPaths.length > 0) {
|
|
138
265
|
return { kind: 'no-tests' };
|
|
139
266
|
}
|
|
140
|
-
|
|
267
|
+
if (exitCode === 0) {
|
|
268
|
+
return { kind: 'tests-ran-ok' };
|
|
269
|
+
}
|
|
270
|
+
// Exit codes follow the corrected verdict: a run whose embedded summary
|
|
271
|
+
// completed green is a pass even when the wrapper exit code went
|
|
272
|
+
// non-zero on harness noise (field report: a fully green --no-shard run
|
|
273
|
+
// exited 1). Real failures always carry a non-zero unexpected count or
|
|
274
|
+
// TEST-UNEXPECTED lines, both of which fail the green-summary check.
|
|
275
|
+
if (hasCompletedGreenSummary(output)) {
|
|
276
|
+
return { kind: 'tests-ran-ok', greenSummaryOverride: true };
|
|
277
|
+
}
|
|
278
|
+
return { kind: 'test-failures' };
|
|
141
279
|
}
|
|
142
280
|
/** Builds the operator-facing failure message after retries are exhausted. */
|
|
143
|
-
export function buildHarnessCrashMessage(signature, attempts) {
|
|
144
|
-
return (
|
|
281
|
+
export function buildHarnessCrashMessage(signature, attempts, commandLabel = 'mach test') {
|
|
282
|
+
return (`${commandLabel} crashed in the harness itself (not in your tests) on all ${attempts} attempt(s).\n\n` +
|
|
145
283
|
`Detected shape: ${signature.reason}\n` +
|
|
146
284
|
`Evidence line: ${signature.line}\n\n` +
|
|
147
285
|
'This failure mode is environmental (mozlog resource monitor / psutil on macOS, focus-stall ' +
|
|
@@ -77,6 +77,13 @@ export declare function parseAppdirFromToml(tomlText: string, key: string): {
|
|
|
77
77
|
*
|
|
78
78
|
* Special-cases `startPath` itself when it already ends with
|
|
79
79
|
* `xpcshell.toml` — operators sometimes pass a manifest path directly.
|
|
80
|
+
*
|
|
81
|
+
* When `startPath` is a DIRECTORY, the walk starts at the directory itself
|
|
82
|
+
* (checking `<dir>/xpcshell.toml` first) rather than at its parent. Field
|
|
83
|
+
* report (0.34.0 cycle): a directory whose own manifest is an
|
|
84
|
+
* `xpcshell.toml` was classified non-xpcshell — the walk began at the
|
|
85
|
+
* parent, missed the manifest, and `fireforge test <dir>` dispatched to
|
|
86
|
+
* the mochitest runner, which found no mochitests.
|
|
80
87
|
*/
|
|
81
88
|
export declare function findNearestXpcshellManifest(engineDir: string, startPath: string): Promise<string | null>;
|
|
82
89
|
/**
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
* test.ts; we skip injection when `--app-path=` already appears in the
|
|
39
39
|
* forwarded args).
|
|
40
40
|
*/
|
|
41
|
-
import { readdir } from 'node:fs/promises';
|
|
41
|
+
import { readdir, stat } from 'node:fs/promises';
|
|
42
42
|
import { dirname, join, resolve, sep } from 'node:path';
|
|
43
43
|
import { pathExists, readJson, readText } from '../utils/fs.js';
|
|
44
44
|
import { isObject, isString } from '../utils/validation.js';
|
|
@@ -110,19 +110,28 @@ function stripQuotes(raw) {
|
|
|
110
110
|
*
|
|
111
111
|
* Special-cases `startPath` itself when it already ends with
|
|
112
112
|
* `xpcshell.toml` — operators sometimes pass a manifest path directly.
|
|
113
|
+
*
|
|
114
|
+
* When `startPath` is a DIRECTORY, the walk starts at the directory itself
|
|
115
|
+
* (checking `<dir>/xpcshell.toml` first) rather than at its parent. Field
|
|
116
|
+
* report (0.34.0 cycle): a directory whose own manifest is an
|
|
117
|
+
* `xpcshell.toml` was classified non-xpcshell — the walk began at the
|
|
118
|
+
* parent, missed the manifest, and `fireforge test <dir>` dispatched to
|
|
119
|
+
* the mochitest runner, which found no mochitests.
|
|
113
120
|
*/
|
|
114
121
|
export async function findNearestXpcshellManifest(engineDir, startPath) {
|
|
115
122
|
const absStart = resolve(engineDir, startPath);
|
|
116
123
|
if (absStart.toLowerCase().endsWith(`${sep}xpcshell.toml`)) {
|
|
117
124
|
return (await pathExists(absStart)) ? absStart : null;
|
|
118
125
|
}
|
|
126
|
+
const startIsDirectory = await stat(absStart).then((stats) => stats.isDirectory(), () => false);
|
|
119
127
|
const engineAbs = resolve(engineDir);
|
|
120
128
|
let current = absStart;
|
|
121
|
-
// First iteration
|
|
129
|
+
// First iteration resolves the starting directory (the path itself for a
|
|
130
|
+
// directory argument, its parent for a file); subsequent ones walk up.
|
|
122
131
|
// Cap iterations defensively — a pathological symlink loop would
|
|
123
132
|
// otherwise spin until the call stack overflows.
|
|
124
133
|
for (let i = 0; i < 64; i += 1) {
|
|
125
|
-
const dir = i === 0 ? dirname(absStart) : dirname(current);
|
|
134
|
+
const dir = i === 0 ? (startIsDirectory ? absStart : dirname(absStart)) : dirname(current);
|
|
126
135
|
const candidate = join(dir, 'xpcshell.toml');
|
|
127
136
|
if (await pathExists(candidate))
|
|
128
137
|
return candidate;
|
|
@@ -530,6 +530,16 @@ export interface FurnaceRemoveOptions {
|
|
|
530
530
|
export interface FurnaceCreateOptions {
|
|
531
531
|
/** Component description */
|
|
532
532
|
description?: string;
|
|
533
|
+
/**
|
|
534
|
+
* Engine-relative directory the test scaffold writes into, instead of
|
|
535
|
+
* the default `browser/base/content/test/<binaryName>/` (browser-chrome)
|
|
536
|
+
* or `browser/base/content/test/<binaryName>-xpcshell/<component>/`
|
|
537
|
+
* (xpcshell). Must stay under `browser/base/content/test/` so the
|
|
538
|
+
* manifest registration keeps working. Not supported for
|
|
539
|
+
* `--test-style=mochikit` (that harness lives in the upstream
|
|
540
|
+
* toolkit/content/tests/widgets tree).
|
|
541
|
+
*/
|
|
542
|
+
testDir?: string;
|
|
533
543
|
/** Include Fluent l10n support */
|
|
534
544
|
localized?: boolean;
|
|
535
545
|
/** Register in customElements.js (default: true) */
|
|
@@ -614,6 +624,8 @@ export interface WireOptions {
|
|
|
614
624
|
export interface RegisterOptions {
|
|
615
625
|
dryRun?: boolean;
|
|
616
626
|
after?: string;
|
|
627
|
+
/** Scaffold a missing manifest (moz.build / xpcshell.toml) and wire the parent chain. */
|
|
628
|
+
createManifest?: boolean;
|
|
617
629
|
}
|
|
618
630
|
/**
|
|
619
631
|
* Options for the patch delete command.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hominis/fireforge",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.34.1",
|
|
4
4
|
"description": "FireForge — a build tool for customizing Firefox",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/src/index.js",
|
|
@@ -72,9 +72,9 @@
|
|
|
72
72
|
"eslint-plugin-simple-import-sort": "^13.0.0",
|
|
73
73
|
"fast-check": "^4.6.0",
|
|
74
74
|
"husky": "^9.1.7",
|
|
75
|
-
"knip": "6.
|
|
75
|
+
"knip": "6.23.0",
|
|
76
76
|
"lint-staged": "^17.0.4",
|
|
77
|
-
"prettier": "
|
|
77
|
+
"prettier": "3.9.4",
|
|
78
78
|
"tsx": "^4.7.0",
|
|
79
79
|
"typescript": "~6.0.0",
|
|
80
80
|
"typescript-eslint": "^8.0.0",
|