@hominis/fireforge 0.42.0 → 0.43.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 +75 -34
- package/dist/build-info.json +4 -4
- package/dist/src/cli.js +21 -2
- package/dist/src/commands/build.js +7 -1
- package/dist/src/commands/config.js +16 -27
- package/dist/src/commands/discard.js +1 -1
- package/dist/src/commands/export-flow.js +13 -3
- package/dist/src/commands/export-placement-conflicts.js +1 -1
- package/dist/src/commands/export-shared.d.ts +1 -1
- package/dist/src/commands/export-shared.js +4 -5
- package/dist/src/commands/furnace/chrome-doc-remove.js +3 -0
- package/dist/src/commands/furnace/chrome-doc.js +3 -0
- package/dist/src/commands/furnace/create.js +3 -0
- package/dist/src/commands/furnace/override.js +3 -0
- package/dist/src/commands/furnace/preview.js +3 -0
- package/dist/src/commands/furnace/refresh.js +3 -0
- package/dist/src/commands/furnace/remove.js +3 -0
- package/dist/src/commands/furnace/rename.js +3 -0
- package/dist/src/commands/furnace/scan.js +3 -0
- package/dist/src/commands/import.js +1 -1
- package/dist/src/commands/lint-per-patch.js +16 -8
- package/dist/src/commands/lint-per-run-checkjs.d.ts +4 -4
- package/dist/src/commands/lint-per-run-checkjs.js +4 -4
- package/dist/src/commands/lint-report.js +1 -1
- package/dist/src/commands/lint.js +2 -2
- package/dist/src/commands/patch/lint-ignore.js +1 -1
- package/dist/src/commands/patch/move-files-create.js +5 -3
- package/dist/src/commands/patch/move-files-into.d.ts +1 -1
- package/dist/src/commands/patch/move-files-into.js +5 -3
- package/dist/src/commands/patch/move-files.js +1 -1
- package/dist/src/commands/patch/rename.js +1 -1
- package/dist/src/commands/patch/reorder.d.ts +1 -2
- package/dist/src/commands/patch/reorder.js +1 -2
- package/dist/src/commands/patch/split.js +5 -3
- package/dist/src/commands/patch/staged-dependency-validate.js +1 -1
- package/dist/src/commands/patch/staged-dependency.js +4 -4
- package/dist/src/commands/re-export-adjacent.js +1 -1
- package/dist/src/commands/re-export-bulk-scan.d.ts +1 -1
- package/dist/src/commands/re-export-bulk-scan.js +5 -4
- package/dist/src/commands/re-export-drift.d.ts +4 -4
- package/dist/src/commands/re-export-drift.js +47 -8
- package/dist/src/commands/re-export-lint.d.ts +7 -5
- package/dist/src/commands/re-export-lint.js +9 -8
- package/dist/src/commands/re-export-single.d.ts +1 -1
- package/dist/src/commands/re-export-single.js +5 -4
- package/dist/src/commands/re-export.js +26 -14
- package/dist/src/commands/reset.js +1 -1
- package/dist/src/commands/run.js +1 -1
- package/dist/src/commands/source.js +6 -6
- package/dist/src/commands/status-check.d.ts +1 -1
- package/dist/src/commands/status-check.js +1 -1
- package/dist/src/commands/status-json.d.ts +2 -2
- package/dist/src/commands/status-json.js +1 -1
- package/dist/src/commands/status-output.d.ts +1 -1
- package/dist/src/commands/status-output.js +1 -1
- package/dist/src/commands/status.js +21 -7
- package/dist/src/commands/test-build-phase.d.ts +2 -2
- package/dist/src/commands/test-build-phase.js +9 -6
- package/dist/src/commands/test-diagnose.js +8 -1
- package/dist/src/commands/test-modes.d.ts +2 -2
- package/dist/src/commands/test-modes.js +3 -3
- package/dist/src/commands/test-register.js +7 -2
- package/dist/src/commands/test-run.d.ts +6 -0
- package/dist/src/commands/test-run.js +32 -3
- package/dist/src/commands/test-stale-gate.js +7 -2
- package/dist/src/commands/test.js +4 -4
- package/dist/src/commands/tree.js +2 -2
- package/dist/src/commands/typecheck.d.ts +2 -1
- package/dist/src/commands/typecheck.js +59 -3
- package/dist/src/commands/verify.js +26 -1
- package/dist/src/core/ast-utils.js +14 -2
- package/dist/src/core/browser-wire.js +9 -1
- package/dist/src/core/build-baseline-types.d.ts +1 -1
- package/dist/src/core/build-baseline.d.ts +1 -1
- package/dist/src/core/build-baseline.js +1 -1
- package/dist/src/core/build-overwrite-guard.d.ts +49 -0
- package/dist/src/core/build-overwrite-guard.js +112 -0
- package/dist/src/core/build-prepare.d.ts +13 -5
- package/dist/src/core/build-prepare.js +42 -9
- package/dist/src/core/config-mutate.d.ts +3 -2
- package/dist/src/core/config-mutate.js +5 -2
- package/dist/src/core/config.d.ts +3 -2
- package/dist/src/core/config.js +2 -0
- package/dist/src/core/coverage-extend.d.ts +1 -1
- package/dist/src/core/coverage-extend.js +1 -1
- package/dist/src/core/destructive.d.ts +23 -0
- package/dist/src/core/destructive.js +45 -4
- package/dist/src/core/diff-hunks.js +31 -17
- package/dist/src/core/discard-baseline.d.ts +1 -1
- package/dist/src/core/discard-baseline.js +1 -1
- package/dist/src/core/display-state.d.ts +52 -0
- package/dist/src/core/display-state.js +89 -0
- package/dist/src/core/engine-session-lock.d.ts +20 -0
- package/dist/src/core/engine-session-lock.js +84 -14
- package/dist/src/core/export-moved-code-shape.d.ts +60 -0
- package/dist/src/core/export-moved-code-shape.js +129 -0
- package/dist/src/core/file-lock.d.ts +44 -0
- package/dist/src/core/file-lock.js +157 -42
- package/dist/src/core/furnace-apply-helpers.d.ts +1 -1
- package/dist/src/core/furnace-apply-helpers.js +1 -1
- package/dist/src/core/furnace-apply-output.js +1 -1
- package/dist/src/core/furnace-apply-overwrite-warn.d.ts +2 -2
- package/dist/src/core/furnace-apply-overwrite-warn.js +2 -2
- package/dist/src/core/furnace-apply-undeploy-actions.d.ts +1 -1
- package/dist/src/core/furnace-apply-undeploy-actions.js +1 -1
- package/dist/src/core/furnace-apply.js +13 -1
- package/dist/src/core/furnace-config-custom.d.ts +2 -1
- package/dist/src/core/furnace-config-order.d.ts +2 -1
- package/dist/src/core/furnace-config-order.js +9 -4
- package/dist/src/core/furnace-config-validate.d.ts +4 -3
- package/dist/src/core/furnace-config-validate.js +3 -3
- package/dist/src/core/furnace-config.js +5 -0
- package/dist/src/core/furnace-operation.d.ts +12 -0
- package/dist/src/core/furnace-operation.js +125 -1
- package/dist/src/core/furnace-rollback.d.ts +17 -0
- package/dist/src/core/furnace-rollback.js +35 -1
- package/dist/src/core/git-base.js +7 -2
- package/dist/src/core/git-diff.js +11 -2
- package/dist/src/core/git-readonly-index.d.ts +59 -0
- package/dist/src/core/git-readonly-index.js +137 -0
- package/dist/src/core/license-headers.d.ts +1 -1
- package/dist/src/core/license-headers.js +1 -1
- package/dist/src/core/lint-cache.d.ts +15 -5
- package/dist/src/core/lint-cache.js +35 -8
- package/dist/src/core/mach-known-noise-filter.d.ts +21 -0
- package/dist/src/core/mach-known-noise-filter.js +23 -0
- package/dist/src/core/mach-mozconfig.js +12 -2
- package/dist/src/core/module-resolution-preflight.d.ts +51 -0
- package/dist/src/core/module-resolution-preflight.js +155 -0
- package/dist/src/core/patch-export.js +2 -1
- package/dist/src/core/patch-identifier-suggest.js +29 -3
- package/dist/src/core/patch-lint-checkjs.d.ts +5 -5
- package/dist/src/core/patch-lint-checkjs.js +6 -6
- package/dist/src/core/patch-lint-creators.d.ts +1 -1
- package/dist/src/core/patch-lint-creators.js +1 -1
- package/dist/src/core/patch-lint-cross.d.ts +1 -1
- package/dist/src/core/patch-lint-cross.js +4 -4
- package/dist/src/core/patch-lint-css.js +1 -1
- package/dist/src/core/patch-lint-diff.d.ts +1 -1
- package/dist/src/core/patch-lint-diff.js +1 -1
- package/dist/src/core/patch-lint-jsdoc.js +4 -2
- package/dist/src/core/patch-lint-module-registration.d.ts +13 -0
- package/dist/src/core/patch-lint-module-registration.js +13 -4
- package/dist/src/core/patch-lint-mozbuild.d.ts +1 -1
- package/dist/src/core/patch-lint-mozbuild.js +1 -1
- package/dist/src/core/patch-lint-ownership.d.ts +2 -2
- package/dist/src/core/patch-lint-ownership.js +2 -2
- package/dist/src/core/patch-lint.d.ts +2 -2
- package/dist/src/core/patch-lint.js +3 -3
- package/dist/src/core/patch-lock.d.ts +21 -0
- package/dist/src/core/patch-lock.js +29 -2
- package/dist/src/core/patch-manifest-io.d.ts +2 -1
- package/dist/src/core/patch-manifest-io.js +49 -0
- package/dist/src/core/patch-parse.d.ts +18 -0
- package/dist/src/core/patch-parse.js +24 -1
- package/dist/src/core/patch-policy.d.ts +2 -2
- package/dist/src/core/patch-policy.js +2 -2
- package/dist/src/core/smoke-patterns.d.ts +1 -1
- package/dist/src/core/status-binary.d.ts +1 -1
- package/dist/src/core/status-binary.js +1 -1
- package/dist/src/core/status-classify.d.ts +1 -1
- package/dist/src/core/status-classify.js +2 -2
- package/dist/src/core/test-harness-crash.d.ts +69 -3
- package/dist/src/core/test-harness-crash.js +174 -9
- package/dist/src/core/test-stale-check.d.ts +1 -1
- package/dist/src/core/test-stale-check.js +1 -1
- package/dist/src/core/token-category.js +1 -1
- package/dist/src/core/token-manager.d.ts +1 -1
- package/dist/src/core/token-manager.js +5 -5
- package/dist/src/core/tree-cow.js +1 -1
- package/dist/src/core/tree-guard.js +2 -2
- package/dist/src/core/tree-store.js +1 -1
- package/dist/src/core/typecheck-shim.d.ts +2 -2
- package/dist/src/core/typecheck-shim.js +2 -2
- package/dist/src/core/typecheck.js +10 -0
- package/dist/src/core/xpcshell-profile-dir.js +1 -1
- package/dist/src/errors/base.d.ts +22 -1
- package/dist/src/errors/base.js +32 -1
- package/dist/src/errors/codes.d.ts +10 -0
- package/dist/src/errors/codes.js +10 -0
- package/dist/src/types/commands/options.d.ts +27 -11
- package/dist/src/types/commands/patches.d.ts +1 -1
- package/dist/src/types/config.d.ts +2 -2
- package/dist/src/types/furnace.d.ts +1 -1
- package/dist/src/types/json.d.ts +22 -0
- package/dist/src/types/json.js +11 -0
- package/dist/src/utils/assert.d.ts +46 -0
- package/dist/src/utils/assert.js +83 -0
- package/dist/src/utils/build-info.d.ts +1 -1
- package/dist/src/utils/build-info.js +1 -1
- package/dist/src/utils/logger.d.ts +20 -0
- package/dist/src/utils/logger.js +26 -0
- package/dist/src/utils/options.d.ts +12 -0
- package/dist/src/utils/options.js +39 -0
- package/dist/src/utils/stdio-drain.d.ts +1 -1
- package/dist/src/utils/stdio-drain.js +1 -1
- package/dist/src/utils/validation.d.ts +12 -1
- package/dist/src/utils/validation.js +13 -1
- package/package.json +3 -3
|
@@ -66,6 +66,14 @@ export interface BuildOptions {
|
|
|
66
66
|
* for any mismatch the rewriter cannot prove safe.
|
|
67
67
|
*/
|
|
68
68
|
rewriteMozinfo?: boolean;
|
|
69
|
+
/**
|
|
70
|
+
* Refuse the build (rather than warn) when it would overwrite engine
|
|
71
|
+
* content recorded in neither a patch body nor the pristine baseline
|
|
72
|
+
*. The default is a loud warning, because an interactive
|
|
73
|
+
* operator often means to discard the drift; a scripted gate on a
|
|
74
|
+
* multi-session checkout wants the hard stop.
|
|
75
|
+
*/
|
|
76
|
+
refuseUnexportedDrift?: boolean;
|
|
69
77
|
/**
|
|
70
78
|
* Parsed `--wait-lock [seconds]` value (`true` for the bare flag, meaning
|
|
71
79
|
* 60). Consumed at the CLI layer to bound the engine-session-lock wait;
|
|
@@ -163,7 +171,7 @@ export interface DiscardOptions {
|
|
|
163
171
|
/**
|
|
164
172
|
* Restore to pristine upstream (HEAD) instead of the patch-applied
|
|
165
173
|
* baseline; deletes patch-created files (the pre-0.39.0 semantics —
|
|
166
|
-
*
|
|
174
|
+
*).
|
|
167
175
|
*/
|
|
168
176
|
toUpstream?: boolean;
|
|
169
177
|
/** Show what would be discarded without doing it */
|
|
@@ -293,7 +301,7 @@ export interface ReExportOptions {
|
|
|
293
301
|
* Bypass per-patch lint result cache reads AND writes for this
|
|
294
302
|
* invocation (`--no-cache`). The cache is what makes a repeat
|
|
295
303
|
* re-export of an unchanged patch skip the checkJs program build
|
|
296
|
-
* entirely
|
|
304
|
+
* entirely.
|
|
297
305
|
*/
|
|
298
306
|
noCache?: boolean;
|
|
299
307
|
/**
|
|
@@ -309,7 +317,7 @@ export interface ReExportOptions {
|
|
|
309
317
|
* Engine-relative files whose drift is EXPECTED (`--expect`, repeatable;
|
|
310
318
|
* requires `--refuse-foreign-drift`). The content-based drift detector
|
|
311
319
|
* cannot tell the exporting session's own slice edits from another
|
|
312
|
-
* session's
|
|
320
|
+
* session's, so a real slice export under the refusal flag
|
|
313
321
|
* names its intended files here: drift confined to expected files
|
|
314
322
|
* proceeds, drift anywhere else still refuses.
|
|
315
323
|
*/
|
|
@@ -518,12 +526,12 @@ export interface TestOptions {
|
|
|
518
526
|
* MIXED harnesses allowed) and exit without dispatching tests. One
|
|
519
527
|
* ~10-minute build then covers both an xpcshell and a browser-chrome
|
|
520
528
|
* half of a slice; run each harness afterwards without `--build`
|
|
521
|
-
|
|
529
|
+
*. Emits `FIREFORGE-VERDICT: PASS` on success.
|
|
522
530
|
*/
|
|
523
531
|
buildOnly?: boolean;
|
|
524
532
|
/**
|
|
525
533
|
* Union the paths this build packages onto the recorded coverage claim
|
|
526
|
-
* instead of REPLACING it
|
|
534
|
+
* instead of REPLACING it, so successive scoped builds
|
|
527
535
|
* accumulate and an earlier slice's build-less runs stay covered. Valid
|
|
528
536
|
* only with `--build`/`--build-only` and explicit paths. Refused
|
|
529
537
|
* fail-closed unless the build anchor is unchanged: same engine HEAD,
|
|
@@ -871,6 +879,14 @@ export interface PatchCompactOptions {
|
|
|
871
879
|
*/
|
|
872
880
|
export interface StatusOptions {
|
|
873
881
|
raw?: boolean;
|
|
882
|
+
/**
|
|
883
|
+
* Report the engine-session lock instead of file status:
|
|
884
|
+
* holder pid, the command it is running, how long it has held the lock,
|
|
885
|
+
* and how many waiters are queued behind it. Read-only — it never
|
|
886
|
+
* acquires the lock, so it is safe to run while a build or test holds
|
|
887
|
+
* it, which is exactly when an operator asks.
|
|
888
|
+
*/
|
|
889
|
+
lock?: boolean;
|
|
874
890
|
unmanaged?: boolean;
|
|
875
891
|
/**
|
|
876
892
|
* Render a flat file→owning-patch ownership table instead of the three-
|
|
@@ -882,7 +898,7 @@ export interface StatusOptions {
|
|
|
882
898
|
/**
|
|
883
899
|
* Print the recorded test-packaging coverage of the last build baseline
|
|
884
900
|
* (scope, timestamp, recording invocation) and exit. Read-only — the
|
|
885
|
-
* counterpart to the out-of-coverage test refusal
|
|
901
|
+
* counterpart to the out-of-coverage test refusal.
|
|
886
902
|
*/
|
|
887
903
|
testCoverage?: boolean;
|
|
888
904
|
/** Output machine-readable JSON instead of human-readable text. */
|
|
@@ -891,7 +907,7 @@ export interface StatusOptions {
|
|
|
891
907
|
* With `--json`: emit only the summary counts (plus the offending
|
|
892
908
|
* files per fail-set classification when the `--check`/`--fail-on`
|
|
893
909
|
* policy is active), omitting the per-file `files[]` payload that
|
|
894
|
-
* grows with the queue
|
|
910
|
+
* grows with the queue. Refused without `--json`.
|
|
895
911
|
*/
|
|
896
912
|
summary?: boolean;
|
|
897
913
|
/**
|
|
@@ -899,7 +915,7 @@ export interface StatusOptions {
|
|
|
899
915
|
* `ownership` block — the flat path→owning-patch rows plus
|
|
900
916
|
* managed/unmanaged/conflict counts — so a gate reads ownership,
|
|
901
917
|
* classification, and the check verdict from ONE scan instead of three
|
|
902
|
-
* back-to-back `status` invocations
|
|
918
|
+
* back-to-back `status` invocations. A modifier, not a mode:
|
|
903
919
|
* exit semantics are unchanged, so ownership conflicts still fail only
|
|
904
920
|
* the human `--ownership` mode. Refused without `--json`.
|
|
905
921
|
*/
|
|
@@ -908,7 +924,7 @@ export interface StatusOptions {
|
|
|
908
924
|
* Exit non-zero when any classification in the fail policy is
|
|
909
925
|
* non-empty (default policy: unmanaged, patch-owned-drift, conflict).
|
|
910
926
|
* Composes with the default view and `--json`; refused alongside
|
|
911
|
-
* `--raw`/`--unmanaged`/`--ownership`/`--test-coverage
|
|
927
|
+
* `--raw`/`--unmanaged`/`--ownership`/`--test-coverage`.
|
|
912
928
|
*/
|
|
913
929
|
check?: boolean;
|
|
914
930
|
/**
|
|
@@ -1010,7 +1026,7 @@ export interface LintCommandOptions {
|
|
|
1010
1026
|
*
|
|
1011
1027
|
* Positional file arguments change meaning under this flag: they are
|
|
1012
1028
|
* PATCH selectors resolved like {@link patches} entries, not engine
|
|
1013
|
-
* file paths
|
|
1029
|
+
* file paths.
|
|
1014
1030
|
*/
|
|
1015
1031
|
perPatch?: boolean;
|
|
1016
1032
|
/**
|
|
@@ -1035,7 +1051,7 @@ export interface LintCommandOptions {
|
|
|
1035
1051
|
/**
|
|
1036
1052
|
* With `--per-patch`, write a machine-readable JSON report (schemaVersion
|
|
1037
1053
|
* 1: per-patch lineCount, filesAffected, tier, thresholds, issues, and
|
|
1038
|
-
* lintIgnore-suppressed issues) to this path
|
|
1054
|
+
* lintIgnore-suppressed issues) to this path. Requires
|
|
1039
1055
|
* {@link perPatch}.
|
|
1040
1056
|
*/
|
|
1041
1057
|
report?: string;
|
|
@@ -217,7 +217,7 @@ export interface PatchLintIssue {
|
|
|
217
217
|
* patch, or every creator for a duplicate-creation clash). Used by the
|
|
218
218
|
* export placement gate to attribute projected errors to the exported
|
|
219
219
|
* patch vs pre-existing patches without parsing messages or the
|
|
220
|
-
* rename-sensitive fingerprint
|
|
220
|
+
* rename-sensitive fingerprint.
|
|
221
221
|
*/
|
|
222
222
|
patches?: string[];
|
|
223
223
|
/** Severity: errors block export, warnings are advisory, notices are informational (not counted) */
|
|
@@ -184,7 +184,7 @@ export interface TypecheckConfig {
|
|
|
184
184
|
/**
|
|
185
185
|
* How to report undefined free identifiers (TS2304/TS2552). These were
|
|
186
186
|
* historically suppressed as shim-gap noise, which also hid genuine
|
|
187
|
-
* missing imports until they crashed at runtime
|
|
187
|
+
* missing imports until they crashed at runtime. Default
|
|
188
188
|
* `'warning'`: visible without failing the gate. `'error'` makes them
|
|
189
189
|
* blocking; `'off'` restores the historical suppression.
|
|
190
190
|
*/
|
|
@@ -292,7 +292,7 @@ export interface PatchLintConfig {
|
|
|
292
292
|
/**
|
|
293
293
|
* How the checkJs pass reports undefined free identifiers
|
|
294
294
|
* (TS2304/TS2552). Same semantics as `typecheck.undefinedIdentifiers`
|
|
295
|
-
|
|
295
|
+
*; the two flows share the suppression policy so a patch
|
|
296
296
|
* cannot pass one and fail the other. Default: 'warning'.
|
|
297
297
|
*/
|
|
298
298
|
undefinedIdentifiers?: PatchLintSeverityGate;
|
|
@@ -263,7 +263,7 @@ export interface ApplyResult {
|
|
|
263
263
|
/**
|
|
264
264
|
* Operator-facing warnings, printed by `logApplyResult`. Populated when
|
|
265
265
|
* apply overwrote a deployed, patch-owned file whose engine bytes
|
|
266
|
-
* differed from the component source
|
|
266
|
+
* differed from the component source — the case where a
|
|
267
267
|
* shipped engine-only fix is silently reverted by the copy.
|
|
268
268
|
*/
|
|
269
269
|
warnings?: string[];
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Domain types for raw JSON documents (fireforge.json, furnace.json).
|
|
3
|
+
*
|
|
4
|
+
* FireForge deliberately reads and writes some documents in their raw,
|
|
5
|
+
* unvalidated form — e.g. `fireforge config --force` round-trips keys that
|
|
6
|
+
* the validated `FireForgeConfig` schema would strip. These types give that
|
|
7
|
+
* pipeline a concrete value contract: every value is JSON data, never a
|
|
8
|
+
* function, class instance, symbol, or other non-serializable runtime value.
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* Any value representable in a JSON document.
|
|
12
|
+
*/
|
|
13
|
+
export type JsonValue = string | number | boolean | null | JsonValue[] | JsonObject;
|
|
14
|
+
/**
|
|
15
|
+
* A JSON object node. `undefined` is admitted as a property value (not a
|
|
16
|
+
* `JsonValue`) so in-memory documents can be built field-by-field from
|
|
17
|
+
* optional inputs; `JSON.stringify` drops such properties on write, exactly
|
|
18
|
+
* like an absent key.
|
|
19
|
+
*/
|
|
20
|
+
export interface JsonObject {
|
|
21
|
+
[key: string]: JsonValue | undefined;
|
|
22
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
// SPDX-License-Identifier: EUPL-1.2
|
|
2
|
+
/**
|
|
3
|
+
* Domain types for raw JSON documents (fireforge.json, furnace.json).
|
|
4
|
+
*
|
|
5
|
+
* FireForge deliberately reads and writes some documents in their raw,
|
|
6
|
+
* unvalidated form — e.g. `fireforge config --force` round-trips keys that
|
|
7
|
+
* the validated `FireForgeConfig` schema would strip. These types give that
|
|
8
|
+
* pipeline a concrete value contract: every value is JSON data, never a
|
|
9
|
+
* function, class instance, symbol, or other non-serializable runtime value.
|
|
10
|
+
*/
|
|
11
|
+
export {};
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A failure description, or a thunk producing one.
|
|
3
|
+
*
|
|
4
|
+
* The thunk form exists so a hot call site pays nothing on the passing
|
|
5
|
+
* path — `assert(ok, () => \`bad state: ${JSON.stringify(x)}\`)` builds
|
|
6
|
+
* the string only when the assertion actually fails, where a plain
|
|
7
|
+
* template literal would build it on every call.
|
|
8
|
+
*/
|
|
9
|
+
export type AssertionMessage = string | (() => string);
|
|
10
|
+
/**
|
|
11
|
+
* Asserts that an internal invariant holds.
|
|
12
|
+
*
|
|
13
|
+
* @param condition - The invariant. Falsy means it was violated.
|
|
14
|
+
* @param message - What was supposed to be true, phrased as the invariant
|
|
15
|
+
* rather than the symptom (e.g. "rollback journal registered before
|
|
16
|
+
* first mutation", not "journal is undefined"). Pass a thunk on a hot
|
|
17
|
+
* path.
|
|
18
|
+
* @throws {@link InternalInvariantError} when `condition` is falsy.
|
|
19
|
+
*/
|
|
20
|
+
export declare function assert(condition: unknown, message: AssertionMessage): asserts condition;
|
|
21
|
+
/**
|
|
22
|
+
* Asserts that a value is neither `null` nor `undefined`, narrowing it in
|
|
23
|
+
* place for the statements that follow.
|
|
24
|
+
*
|
|
25
|
+
* Use this in statement position, where the value is already bound to a
|
|
26
|
+
* name. Use {@link expectDefined} in expression position, where it is not.
|
|
27
|
+
*
|
|
28
|
+
* @param value - The value that should be present
|
|
29
|
+
* @param message - What was supposed to be present, and why
|
|
30
|
+
* @throws {@link InternalInvariantError} when `value` is `null` or `undefined`.
|
|
31
|
+
*/
|
|
32
|
+
export declare function assertDefined<T>(value: T, message: AssertionMessage): asserts value is NonNullable<T>;
|
|
33
|
+
/**
|
|
34
|
+
* Returns a value that must be present, throwing if it is not.
|
|
35
|
+
*
|
|
36
|
+
* The expression-position counterpart to {@link assertDefined}: it checks
|
|
37
|
+
* and returns in one step, so an indexed read can be asserted inline
|
|
38
|
+
* (`push({ content: expectDefined(lines[k], …) })`) without first binding
|
|
39
|
+
* it to a local.
|
|
40
|
+
*
|
|
41
|
+
* @param value - The value that should be present
|
|
42
|
+
* @param message - What was supposed to be present, and why
|
|
43
|
+
* @returns `value`, narrowed to exclude `null` and `undefined`
|
|
44
|
+
* @throws {@link InternalInvariantError} when `value` is `null` or `undefined`.
|
|
45
|
+
*/
|
|
46
|
+
export declare function expectDefined<T>(value: T, message: AssertionMessage): NonNullable<T>;
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
// SPDX-License-Identifier: EUPL-1.2
|
|
2
|
+
/**
|
|
3
|
+
* Runtime assertions for FireForge's own internal invariants.
|
|
4
|
+
*
|
|
5
|
+
* These check state that FireForge itself established — a journal was
|
|
6
|
+
* registered before the first mutation, a lock is held before a write,
|
|
7
|
+
* manifest ordering is contiguous after a renumber. They are NOT input
|
|
8
|
+
* validation: anything derived from user input, the filesystem, or a
|
|
9
|
+
* subprocess belongs in a typed error from `src/errors/` with a
|
|
10
|
+
* `userMessage` that tells the operator what to do. An assertion failure
|
|
11
|
+
* says the opposite — that nothing the operator could have done would
|
|
12
|
+
* have prevented it.
|
|
13
|
+
*
|
|
14
|
+
* Every check routes through a helper here rather than being open-coded
|
|
15
|
+
* as `if (!condition) throw`. That is deliberate: an inline throw adds a
|
|
16
|
+
* permanently-uncovered branch to every function it appears in, and the
|
|
17
|
+
* per-module coverage floors in `scripts/check-coverage-thresholds.mjs`
|
|
18
|
+
* would pay for it in ~40 places. Routed through a call, the branch lives
|
|
19
|
+
* here once and is covered here once, and the `complexity` ceiling in
|
|
20
|
+
* `eslint.config.js` does not see it at all.
|
|
21
|
+
*
|
|
22
|
+
* This module is a leaf: it imports the error class and nothing else, per
|
|
23
|
+
* the dependency-direction note in `src/utils/errors.ts`.
|
|
24
|
+
*/
|
|
25
|
+
import { InternalInvariantError } from '../errors/base.js';
|
|
26
|
+
/**
|
|
27
|
+
* Resolves an {@link AssertionMessage} at failure time.
|
|
28
|
+
* @param message - Literal description, or a thunk producing one
|
|
29
|
+
* @returns The description text
|
|
30
|
+
*/
|
|
31
|
+
function resolveMessage(message) {
|
|
32
|
+
return typeof message === 'function' ? message() : message;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Asserts that an internal invariant holds.
|
|
36
|
+
*
|
|
37
|
+
* @param condition - The invariant. Falsy means it was violated.
|
|
38
|
+
* @param message - What was supposed to be true, phrased as the invariant
|
|
39
|
+
* rather than the symptom (e.g. "rollback journal registered before
|
|
40
|
+
* first mutation", not "journal is undefined"). Pass a thunk on a hot
|
|
41
|
+
* path.
|
|
42
|
+
* @throws {@link InternalInvariantError} when `condition` is falsy.
|
|
43
|
+
*/
|
|
44
|
+
export function assert(condition, message) {
|
|
45
|
+
if (!condition) {
|
|
46
|
+
throw new InternalInvariantError(resolveMessage(message));
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Asserts that a value is neither `null` nor `undefined`, narrowing it in
|
|
51
|
+
* place for the statements that follow.
|
|
52
|
+
*
|
|
53
|
+
* Use this in statement position, where the value is already bound to a
|
|
54
|
+
* name. Use {@link expectDefined} in expression position, where it is not.
|
|
55
|
+
*
|
|
56
|
+
* @param value - The value that should be present
|
|
57
|
+
* @param message - What was supposed to be present, and why
|
|
58
|
+
* @throws {@link InternalInvariantError} when `value` is `null` or `undefined`.
|
|
59
|
+
*/
|
|
60
|
+
export function assertDefined(value, message) {
|
|
61
|
+
if (value === null || value === undefined) {
|
|
62
|
+
throw new InternalInvariantError(resolveMessage(message));
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Returns a value that must be present, throwing if it is not.
|
|
67
|
+
*
|
|
68
|
+
* The expression-position counterpart to {@link assertDefined}: it checks
|
|
69
|
+
* and returns in one step, so an indexed read can be asserted inline
|
|
70
|
+
* (`push({ content: expectDefined(lines[k], …) })`) without first binding
|
|
71
|
+
* it to a local.
|
|
72
|
+
*
|
|
73
|
+
* @param value - The value that should be present
|
|
74
|
+
* @param message - What was supposed to be present, and why
|
|
75
|
+
* @returns `value`, narrowed to exclude `null` and `undefined`
|
|
76
|
+
* @throws {@link InternalInvariantError} when `value` is `null` or `undefined`.
|
|
77
|
+
*/
|
|
78
|
+
export function expectDefined(value, message) {
|
|
79
|
+
if (value === null || value === undefined) {
|
|
80
|
+
throw new InternalInvariantError(resolveMessage(message));
|
|
81
|
+
}
|
|
82
|
+
return value;
|
|
83
|
+
}
|
|
@@ -4,7 +4,7 @@ export interface BuildIdentity {
|
|
|
4
4
|
dirty: boolean;
|
|
5
5
|
/**
|
|
6
6
|
* Content hash of the uncommitted diff, present only for a DIRTY
|
|
7
|
-
* installed build
|
|
7
|
+
* installed build. Two packs from the same HEAD with
|
|
8
8
|
* different uncommitted content share `shortCommit` and the `.dirty`
|
|
9
9
|
* marker, so without this they report byte-identical `--version`
|
|
10
10
|
* strings — which is what made a field report against
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// SPDX-License-Identifier: EUPL-1.2
|
|
2
2
|
/**
|
|
3
|
-
* Build identity for `--version
|
|
3
|
+
* Build identity for `--version`. Three distinct builds
|
|
4
4
|
* shipped as plain "0.41.0" — consumers had to fingerprint tarballs by
|
|
5
5
|
* sha256 to know which build a claim was verified against. `--version`
|
|
6
6
|
* now reports `<semver>+g<short-sha>[.dirty[.<content-hash>]]`:
|
|
@@ -38,6 +38,26 @@ export declare function info(message: string): void;
|
|
|
38
38
|
export declare function success(message: string): void;
|
|
39
39
|
/** Logs a warning message. */
|
|
40
40
|
export declare function warn(message: string): void;
|
|
41
|
+
/**
|
|
42
|
+
* Prefix that marks a line as FireForge's own explanatory output rather
|
|
43
|
+
* than a defect. Kept greppable so downstream filters can whitelist it.
|
|
44
|
+
*/
|
|
45
|
+
export declare const NOTICE_PREFIX = "[FireForge] NOTICE:";
|
|
46
|
+
/**
|
|
47
|
+
* Logs one of FireForge's own "why this is happening / why this is slow"
|
|
48
|
+
* explanations at WARNING severity.
|
|
49
|
+
*
|
|
50
|
+
* These lines are not warnings about the operator's code — they explain a
|
|
51
|
+
* decision FireForge just made (escalating an incremental build to a full
|
|
52
|
+
* one, sharding a run, skipping a step). Emitted through `info` they were
|
|
53
|
+
* silently dropped by agent-facing output filters that keep only warnings
|
|
54
|
+
* and errors, leaving a multi-minute build with no explanation and reading
|
|
55
|
+
* as a hang. There are very few such lines and they are exactly the ones a
|
|
56
|
+
* non-interactive operator needs, so they ride the warning channel and
|
|
57
|
+
* carry {@link NOTICE_PREFIX} so a reader can still tell them apart from a
|
|
58
|
+
* real warning.
|
|
59
|
+
*/
|
|
60
|
+
export declare function notice(message: string): void;
|
|
41
61
|
/** Logs an error message. */
|
|
42
62
|
export declare function error(message: string): void;
|
|
43
63
|
/** Logs an in-progress step message. */
|
package/dist/src/utils/logger.js
CHANGED
|
@@ -117,6 +117,32 @@ export function warn(message) {
|
|
|
117
117
|
}
|
|
118
118
|
p.log.warn(message);
|
|
119
119
|
}
|
|
120
|
+
/**
|
|
121
|
+
* Prefix that marks a line as FireForge's own explanatory output rather
|
|
122
|
+
* than a defect. Kept greppable so downstream filters can whitelist it.
|
|
123
|
+
*/
|
|
124
|
+
export const NOTICE_PREFIX = '[FireForge] NOTICE:';
|
|
125
|
+
/**
|
|
126
|
+
* Logs one of FireForge's own "why this is happening / why this is slow"
|
|
127
|
+
* explanations at WARNING severity.
|
|
128
|
+
*
|
|
129
|
+
* These lines are not warnings about the operator's code — they explain a
|
|
130
|
+
* decision FireForge just made (escalating an incremental build to a full
|
|
131
|
+
* one, sharding a run, skipping a step). Emitted through `info` they were
|
|
132
|
+
* silently dropped by agent-facing output filters that keep only warnings
|
|
133
|
+
* and errors, leaving a multi-minute build with no explanation and reading
|
|
134
|
+
* as a hang. There are very few such lines and they are exactly the ones a
|
|
135
|
+
* non-interactive operator needs, so they ride the warning channel and
|
|
136
|
+
* carry {@link NOTICE_PREFIX} so a reader can still tell them apart from a
|
|
137
|
+
* real warning.
|
|
138
|
+
*/
|
|
139
|
+
export function notice(message) {
|
|
140
|
+
if (routeToStderr()) {
|
|
141
|
+
writeDiagnostic('warning: ', `${NOTICE_PREFIX} ${message}`);
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
p.log.warn(`${NOTICE_PREFIX} ${message}`);
|
|
145
|
+
}
|
|
120
146
|
/** Logs an error message. */
|
|
121
147
|
export function error(message) {
|
|
122
148
|
if (routeToStderr()) {
|
|
@@ -49,6 +49,18 @@ export declare function stringListOption(): [(value: string, previous: string[])
|
|
|
49
49
|
* invalid-argument channel).
|
|
50
50
|
*/
|
|
51
51
|
export declare function resolveWaitLockSeconds(value: string | number | boolean | undefined): number | undefined;
|
|
52
|
+
/**
|
|
53
|
+
* True when `command` already declares `--wait-lock` itself. Used by the
|
|
54
|
+
* CLI wiring to add the accept-and-ignore variant only where the honoring
|
|
55
|
+
* one is absent.
|
|
56
|
+
*/
|
|
57
|
+
export declare function hasWaitLockOption(command: Command): boolean;
|
|
58
|
+
/**
|
|
59
|
+
* Recursively gives every command in the tree a `--wait-lock` flag: the
|
|
60
|
+
* honoring registration where one already exists, the accept-and-ignore
|
|
61
|
+
* one everywhere else.
|
|
62
|
+
*/
|
|
63
|
+
export declare function ensureWaitLockOptionEverywhere(command: Command): void;
|
|
52
64
|
/**
|
|
53
65
|
* Registers the shared `--wait-lock [seconds]` flag on a lock-taking
|
|
54
66
|
* command (the engine session lock for engine-mutating commands, the patch
|
|
@@ -86,6 +86,45 @@ export function resolveWaitLockSeconds(value) {
|
|
|
86
86
|
}
|
|
87
87
|
return n;
|
|
88
88
|
}
|
|
89
|
+
/**
|
|
90
|
+
* Registers `--wait-lock [seconds]` on a command that takes NO lock, so a
|
|
91
|
+
* scripted sequence can blanket-append the flag without hitting a usage
|
|
92
|
+
* error.
|
|
93
|
+
*
|
|
94
|
+
* `export` / `re-export` / `build` / `test` / `patch move-files` all
|
|
95
|
+
* accept the flag; `status` and `patch staged-dependency` used to reject
|
|
96
|
+
* it with "unknown option", which killed the whole sequence with a usage
|
|
97
|
+
* error instead of a lock message. The flag is accepted and ignored here —
|
|
98
|
+
* never silently repurposed — and the help text says so, so nobody reads
|
|
99
|
+
* its presence as evidence that this command waits for anything.
|
|
100
|
+
*
|
|
101
|
+
* The value is parsed and validated exactly as the honoring variant does:
|
|
102
|
+
* `--wait-lock nonsense` must still be a usage error everywhere, or the
|
|
103
|
+
* uniformity would be a lie.
|
|
104
|
+
*/
|
|
105
|
+
function addAcceptedWaitLockOption(command) {
|
|
106
|
+
return command.option('--wait-lock [seconds]', 'Accepted for scripting uniformity and ignored: this command takes no FireForge lock', commanderArgParser((raw) => resolveWaitLockSeconds(raw)));
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* True when `command` already declares `--wait-lock` itself. Used by the
|
|
110
|
+
* CLI wiring to add the accept-and-ignore variant only where the honoring
|
|
111
|
+
* one is absent.
|
|
112
|
+
*/
|
|
113
|
+
export function hasWaitLockOption(command) {
|
|
114
|
+
return command.options.some((option) => option.long === '--wait-lock');
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Recursively gives every command in the tree a `--wait-lock` flag: the
|
|
118
|
+
* honoring registration where one already exists, the accept-and-ignore
|
|
119
|
+
* one everywhere else.
|
|
120
|
+
*/
|
|
121
|
+
export function ensureWaitLockOptionEverywhere(command) {
|
|
122
|
+
for (const sub of command.commands) {
|
|
123
|
+
if (!hasWaitLockOption(sub))
|
|
124
|
+
addAcceptedWaitLockOption(sub);
|
|
125
|
+
ensureWaitLockOptionEverywhere(sub);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
89
128
|
/**
|
|
90
129
|
* Registers the shared `--wait-lock [seconds]` flag on a lock-taking
|
|
91
130
|
* command (the engine session lock for engine-mutating commands, the patch
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Bounded stdio drain for delayed process exits
|
|
2
|
+
* Bounded stdio drain for delayed process exits.
|
|
3
3
|
*
|
|
4
4
|
* `process.exit()` discards whatever is still queued in an async writable —
|
|
5
5
|
* and stdout IS async when it is a pipe, with a 64 KiB kernel buffer on
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// SPDX-License-Identifier: EUPL-1.2
|
|
2
2
|
/**
|
|
3
|
-
* Bounded stdio drain for delayed process exits
|
|
3
|
+
* Bounded stdio drain for delayed process exits.
|
|
4
4
|
*
|
|
5
5
|
* `process.exit()` discards whatever is still queued in an async writable —
|
|
6
6
|
* and stdout IS async when it is a pipe, with a 64 KiB kernel buffer on
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { FirefoxProduct } from '../types/config.js';
|
|
2
|
+
import type { JsonObject, JsonValue } from '../types/json.js';
|
|
2
3
|
/**
|
|
3
4
|
* Checks whether a value is a string.
|
|
4
5
|
* @param value - Value to check
|
|
@@ -53,6 +54,16 @@ export declare function isObject(value: unknown): value is Record<string, unknow
|
|
|
53
54
|
* @returns True if value is an array
|
|
54
55
|
*/
|
|
55
56
|
export declare function isArray(value: unknown): value is unknown[];
|
|
57
|
+
/**
|
|
58
|
+
* Narrows a JSON value to a JSON object node (excludes arrays and `null`).
|
|
59
|
+
*
|
|
60
|
+
* Unlike {@link isObject} this accepts only values already known to be JSON
|
|
61
|
+
* data, so the narrowed `JsonObject` keeps its concrete value contract —
|
|
62
|
+
* use it when walking a `JsonValue` tree rather than at `unknown` boundaries.
|
|
63
|
+
* @param value - JSON value to check
|
|
64
|
+
* @returns True if value is a JSON object node
|
|
65
|
+
*/
|
|
66
|
+
export declare function isJsonObject(value: JsonValue | undefined): value is JsonObject;
|
|
56
67
|
/**
|
|
57
68
|
* Validates a Firefox version string.
|
|
58
69
|
* Accepts formats like "140.9.0", "140.9.1", "140.9.0esr", "147.0b1"
|
|
@@ -150,7 +161,7 @@ export declare function validateTokenName(name: string): string | undefined;
|
|
|
150
161
|
*/
|
|
151
162
|
export declare function normalizeTokenName(name: string): string;
|
|
152
163
|
/**
|
|
153
|
-
* Normalizes a patch display name against its category
|
|
164
|
+
* Normalizes a patch display name against its category:
|
|
154
165
|
* strips a trailing `.patch` and any redundant `NNN-<category>-` /
|
|
155
166
|
* `<category>-` prefixes, case-insensitively and repeatedly, mirroring
|
|
156
167
|
* the filename slug pipeline's require-the-category-token rule — a bare
|
|
@@ -79,6 +79,18 @@ export function isObject(value) {
|
|
|
79
79
|
export function isArray(value) {
|
|
80
80
|
return Array.isArray(value);
|
|
81
81
|
}
|
|
82
|
+
/**
|
|
83
|
+
* Narrows a JSON value to a JSON object node (excludes arrays and `null`).
|
|
84
|
+
*
|
|
85
|
+
* Unlike {@link isObject} this accepts only values already known to be JSON
|
|
86
|
+
* data, so the narrowed `JsonObject` keeps its concrete value contract —
|
|
87
|
+
* use it when walking a `JsonValue` tree rather than at `unknown` boundaries.
|
|
88
|
+
* @param value - JSON value to check
|
|
89
|
+
* @returns True if value is a JSON object node
|
|
90
|
+
*/
|
|
91
|
+
export function isJsonObject(value) {
|
|
92
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
93
|
+
}
|
|
82
94
|
/**
|
|
83
95
|
* Validates a Firefox version string.
|
|
84
96
|
* Accepts formats like "140.9.0", "140.9.1", "140.9.0esr", "147.0b1"
|
|
@@ -278,7 +290,7 @@ export function normalizeTokenName(name) {
|
|
|
278
290
|
return `--${stripped}`;
|
|
279
291
|
}
|
|
280
292
|
/**
|
|
281
|
-
* Normalizes a patch display name against its category
|
|
293
|
+
* Normalizes a patch display name against its category:
|
|
282
294
|
* strips a trailing `.patch` and any redundant `NNN-<category>-` /
|
|
283
295
|
* `<category>-` prefixes, case-insensitively and repeatedly, mirroring
|
|
284
296
|
* the filename slug pipeline's require-the-category-token rule — a bare
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hominis/fireforge",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.43.0",
|
|
4
4
|
"description": "FireForge — a build tool for customizing Firefox",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/src/index.js",
|
|
@@ -69,11 +69,11 @@
|
|
|
69
69
|
"dpdm": "4.3.0",
|
|
70
70
|
"eslint": "^10.0.0",
|
|
71
71
|
"eslint-config-prettier": "^10.1.8",
|
|
72
|
-
"eslint-plugin-jsdoc": "^
|
|
72
|
+
"eslint-plugin-jsdoc": "^64.1.0",
|
|
73
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.32.
|
|
76
|
+
"knip": "6.32.2",
|
|
77
77
|
"lint-staged": "^17.0.4",
|
|
78
78
|
"prettier": "3.9.6",
|
|
79
79
|
"tsx": "^4.7.0",
|