@hominis/fireforge 0.45.0 → 0.46.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 +80 -0
- package/dist/bin/fireforge.js +6 -0
- package/dist/build-info.json +4 -4
- package/dist/src/cli-usage-error.d.ts +46 -0
- package/dist/src/cli-usage-error.js +81 -0
- package/dist/src/cli.d.ts +5 -1
- package/dist/src/cli.js +20 -21
- package/dist/src/commands/bootstrap.js +1 -2
- package/dist/src/commands/build.js +15 -6
- package/dist/src/commands/destructive-decision.d.ts +19 -0
- package/dist/src/commands/destructive-decision.js +31 -0
- package/dist/src/commands/doctor-check-core.d.ts +0 -6
- package/dist/src/commands/doctor-check-core.js +0 -8
- package/dist/src/commands/doctor-orphaned-harness.d.ts +0 -6
- package/dist/src/commands/doctor-orphaned-harness.js +4 -12
- package/dist/src/commands/doctor-post-rebase-audit.js +1 -1
- package/dist/src/commands/doctor.d.ts +2 -0
- package/dist/src/commands/doctor.js +7 -8
- package/dist/src/commands/download.js +35 -24
- package/dist/src/commands/export-all.js +21 -4
- package/dist/src/commands/export-flow.js +15 -45
- package/dist/src/commands/export-placement-conflicts.js +3 -3
- package/dist/src/commands/export-placement-gate.js +2 -8
- package/dist/src/commands/export-placement-policy.js +3 -5
- package/dist/src/commands/export-shared.d.ts +42 -23
- package/dist/src/commands/export-shared.js +4 -19
- package/dist/src/commands/export.js +10 -1
- package/dist/src/commands/furnace/authoring-config.d.ts +13 -0
- package/dist/src/commands/furnace/authoring-config.js +19 -0
- package/dist/src/commands/furnace/chrome-doc-remove.js +1 -1
- package/dist/src/commands/furnace/create-browser-test.js +3 -8
- package/dist/src/commands/furnace/create-dry-run.js +2 -5
- package/dist/src/commands/furnace/create-templates.d.ts +17 -1
- package/dist/src/commands/furnace/create-templates.js +2 -1
- package/dist/src/commands/furnace/create.js +25 -19
- package/dist/src/commands/furnace/deploy.js +11 -2
- package/dist/src/commands/furnace/init.js +2 -1
- package/dist/src/commands/furnace/override.js +28 -19
- package/dist/src/commands/furnace/refresh.js +9 -1
- package/dist/src/commands/furnace/remove-mutations.d.ts +6 -7
- package/dist/src/commands/furnace/remove-mutations.js +0 -1
- package/dist/src/commands/furnace/remove.js +2 -6
- package/dist/src/commands/furnace/rename-browser-test.js +1 -7
- package/dist/src/commands/furnace/rename.js +29 -29
- package/dist/src/commands/furnace/status.js +12 -9
- package/dist/src/commands/furnace/test-file-name.d.ts +28 -0
- package/dist/src/commands/furnace/test-file-name.js +39 -0
- package/dist/src/commands/furnace/validation-output.d.ts +21 -9
- package/dist/src/commands/furnace/validation-output.js +3 -8
- package/dist/src/commands/import.js +2 -9
- package/dist/src/commands/lint-per-patch.d.ts +2 -2
- package/dist/src/commands/lint-per-patch.js +19 -4
- package/dist/src/commands/lint-per-run-checkjs.d.ts +2 -2
- package/dist/src/commands/lint.d.ts +2 -1
- package/dist/src/commands/lint.js +1 -1
- package/dist/src/commands/manifest.js +1 -1
- package/dist/src/commands/package.js +2 -4
- package/dist/src/commands/patch/compact.js +14 -15
- package/dist/src/commands/patch/delete.js +15 -25
- package/dist/src/commands/patch/entry-projection.d.ts +13 -0
- package/dist/src/commands/patch/entry-projection.js +24 -0
- package/dist/src/commands/patch/lint-ignore.d.ts +0 -8
- package/dist/src/commands/patch/lint-ignore.js +19 -29
- package/dist/src/commands/patch/move-files-create.js +24 -10
- package/dist/src/commands/patch/move-files-into.js +38 -34
- package/dist/src/commands/patch/move-files.js +4 -13
- package/dist/src/commands/patch/rename.js +27 -41
- package/dist/src/commands/patch/reorder.js +25 -38
- package/dist/src/commands/patch/split-plan.d.ts +4 -5
- package/dist/src/commands/patch/split-plan.js +4 -8
- package/dist/src/commands/patch/split.js +45 -43
- package/dist/src/commands/patch/staged-dependency.js +16 -22
- package/dist/src/commands/patch/tier.js +15 -25
- package/dist/src/commands/patch-rename-map.d.ts +19 -0
- package/dist/src/commands/patch-rename-map.js +36 -0
- package/dist/src/commands/pending-resolution.d.ts +15 -0
- package/dist/src/commands/pending-resolution.js +25 -0
- package/dist/src/commands/re-export-adjacent.d.ts +24 -2
- package/dist/src/commands/re-export-adjacent.js +32 -16
- package/dist/src/commands/re-export-bulk-scan.js +6 -10
- package/dist/src/commands/re-export-drift.js +4 -4
- package/dist/src/commands/re-export-files.d.ts +2 -3
- package/dist/src/commands/re-export-files.js +38 -29
- package/dist/src/commands/re-export-lint.d.ts +3 -4
- package/dist/src/commands/re-export-lint.js +9 -2
- package/dist/src/commands/re-export-scan.js +5 -2
- package/dist/src/commands/re-export-single.d.ts +22 -3
- package/dist/src/commands/re-export-single.js +19 -11
- package/dist/src/commands/re-export.js +28 -11
- package/dist/src/commands/rebase/abort.js +3 -8
- package/dist/src/commands/rebase/continue.js +12 -12
- package/dist/src/commands/rebase/index.js +2 -2
- package/dist/src/commands/rebase/patch-loop.d.ts +2 -2
- package/dist/src/commands/rebase/patch-loop.js +2 -7
- package/dist/src/commands/resolve.js +18 -10
- package/dist/src/commands/run.d.ts +0 -13
- package/dist/src/commands/run.js +12 -25
- package/dist/src/commands/setup-support.d.ts +16 -4
- package/dist/src/commands/setup-support.js +16 -16
- package/dist/src/commands/setup.js +3 -9
- package/dist/src/commands/source.js +8 -1
- package/dist/src/commands/status-check.js +2 -2
- package/dist/src/commands/status-output.js +2 -2
- package/dist/src/commands/status.js +3 -4
- package/dist/src/commands/test-build-phase.d.ts +2 -2
- package/dist/src/commands/test-build-phase.js +31 -7
- package/dist/src/commands/test-modes.d.ts +2 -2
- package/dist/src/commands/test-modes.js +0 -1
- package/dist/src/commands/test-register.js +5 -3
- package/dist/src/commands/test-run.js +25 -18
- package/dist/src/commands/test-stale-gate.js +4 -4
- package/dist/src/commands/test-verdict.d.ts +16 -2
- package/dist/src/commands/test-verdict.js +18 -3
- package/dist/src/commands/test.js +42 -5
- package/dist/src/commands/token-list.d.ts +26 -0
- package/dist/src/commands/token-list.js +153 -0
- package/dist/src/commands/token.js +17 -1
- package/dist/src/commands/tree.js +7 -2
- package/dist/src/commands/typecheck.js +9 -9
- package/dist/src/commands/wire.js +4 -3
- package/dist/src/core/branding.d.ts +0 -7
- package/dist/src/core/branding.js +3 -2
- package/dist/src/core/browser-wire.js +6 -3
- package/dist/src/core/build-audit-platform.d.ts +29 -0
- package/dist/src/core/build-audit-platform.js +140 -0
- package/dist/src/core/build-audit-registration.js +3 -2
- package/dist/src/core/build-audit-skip.d.ts +57 -0
- package/dist/src/core/build-audit-skip.js +112 -0
- package/dist/src/core/build-audit.d.ts +15 -2
- package/dist/src/core/build-audit.js +110 -10
- package/dist/src/core/build-baseline.d.ts +45 -28
- package/dist/src/core/build-baseline.js +6 -29
- package/dist/src/core/build-jar-escalation.js +3 -2
- package/dist/src/core/build-overwrite-guard.js +1 -1
- package/dist/src/core/build-prepare.d.ts +0 -8
- package/dist/src/core/build-prepare.js +7 -12
- package/dist/src/core/config-paths.d.ts +2 -6
- package/dist/src/core/config-paths.js +4 -2
- package/dist/src/core/config-state.d.ts +0 -6
- package/dist/src/core/config-state.js +1 -19
- package/dist/src/core/config-validate-build-audit.d.ts +8 -0
- package/dist/src/core/config-validate-build-audit.js +80 -0
- package/dist/src/core/config-validate-file-size.js +1 -1
- package/dist/src/core/config-validate-patch-policy.d.ts +2 -2
- package/dist/src/core/config-validate-patch-policy.js +3 -3
- package/dist/src/core/config-validate-test-toolchains.d.ts +2 -2
- package/dist/src/core/config-validate-test-toolchains.js +4 -5
- package/dist/src/core/config-validate.js +14 -3
- package/dist/src/core/config.d.ts +2 -2
- package/dist/src/core/config.js +11 -15
- package/dist/src/core/coverage-extend.js +4 -4
- package/dist/src/core/discard-baseline.js +7 -7
- package/dist/src/core/engine-precondition.d.ts +1 -9
- package/dist/src/core/engine-precondition.js +3 -8
- package/dist/src/core/engine-session-lock.js +13 -17
- package/dist/src/core/export-moved-code-shape.js +2 -2
- package/dist/src/core/file-lock-owner.d.ts +103 -0
- package/dist/src/core/file-lock-owner.js +259 -0
- package/dist/src/core/file-lock.d.ts +2 -7
- package/dist/src/core/file-lock.js +40 -91
- package/dist/src/core/firefox-cache.d.ts +13 -1
- package/dist/src/core/firefox-cache.js +59 -34
- package/dist/src/core/firefox-download.d.ts +15 -0
- package/dist/src/core/firefox-download.js +37 -21
- package/dist/src/core/firefox-extract.d.ts +6 -5
- package/dist/src/core/firefox-extract.js +36 -18
- package/dist/src/core/firefox.d.ts +30 -32
- package/dist/src/core/firefox.js +5 -36
- package/dist/src/core/furnace-apply-dry-run.d.ts +1 -6
- package/dist/src/core/furnace-apply-dry-run.js +1 -7
- package/dist/src/core/furnace-apply-helpers.d.ts +0 -11
- package/dist/src/core/furnace-apply-helpers.js +8 -19
- package/dist/src/core/furnace-apply-overwrite-warn.js +4 -2
- package/dist/src/core/furnace-apply.d.ts +1 -1
- package/dist/src/core/furnace-apply.js +30 -10
- package/dist/src/core/furnace-config.d.ts +1 -1
- package/dist/src/core/furnace-config.js +23 -36
- package/dist/src/core/furnace-constants.js +3 -2
- package/dist/src/core/furnace-dir-entry.d.ts +20 -0
- package/dist/src/core/furnace-dir-entry.js +21 -0
- package/dist/src/core/furnace-operation.d.ts +2 -0
- package/dist/src/core/furnace-operation.js +3 -1
- package/dist/src/core/furnace-refresh.d.ts +18 -6
- package/dist/src/core/furnace-refresh.js +3 -6
- package/dist/src/core/furnace-registration-ast.d.ts +0 -1
- package/dist/src/core/furnace-registration-ast.js +0 -3
- package/dist/src/core/furnace-registration.d.ts +2 -1
- package/dist/src/core/furnace-registration.js +22 -29
- package/dist/src/core/furnace-scanner.js +3 -6
- package/dist/src/core/furnace-state-persist.d.ts +2 -2
- package/dist/src/core/furnace-validate-registration.js +5 -7
- package/dist/src/core/git-base.d.ts +3 -1
- package/dist/src/core/git-base.js +25 -3
- package/dist/src/core/git-diff-new-file.d.ts +40 -0
- package/dist/src/core/git-diff-new-file.js +119 -0
- package/dist/src/core/git-diff.d.ts +9 -9
- package/dist/src/core/git-diff.js +88 -157
- package/dist/src/core/git-file-ops.d.ts +0 -7
- package/dist/src/core/git-file-ops.js +4 -28
- package/dist/src/core/git-readonly-index.d.ts +0 -2
- package/dist/src/core/git-readonly-index.js +0 -4
- package/dist/src/core/git-status.d.ts +7 -0
- package/dist/src/core/git-status.js +21 -9
- package/dist/src/core/git.d.ts +0 -6
- package/dist/src/core/git.js +14 -43
- package/dist/src/core/harness-orphans.js +8 -7
- package/dist/src/core/history-log.d.ts +19 -0
- package/dist/src/core/history-log.js +29 -0
- package/dist/src/core/mach-error-hints.d.ts +0 -5
- package/dist/src/core/mach-error-hints.js +1 -1
- package/dist/src/core/mach-known-noise-filter.d.ts +4 -3
- package/dist/src/core/mach-known-noise-filter.js +7 -9
- package/dist/src/core/mach-mozconfig.js +2 -1
- package/dist/src/core/mach-python.d.ts +2 -0
- package/dist/src/core/mach-python.js +12 -7
- package/dist/src/core/mach-resource-shim.d.ts +13 -1
- package/dist/src/core/mach-resource-shim.js +112 -9
- package/dist/src/core/mach.d.ts +39 -53
- package/dist/src/core/mach.js +13 -81
- package/dist/src/core/marionette-port.d.ts +0 -17
- package/dist/src/core/marionette-port.js +12 -58
- package/dist/src/core/marionette-preflight.js +9 -27
- package/dist/src/core/mochitest-server-port.js +3 -3
- package/dist/src/core/moz-manifest-rules.js +37 -33
- package/dist/src/core/patch-apply-fuzz.js +4 -4
- package/dist/src/core/patch-apply.d.ts +4 -5
- package/dist/src/core/patch-apply.js +6 -12
- package/dist/src/core/patch-export-coverage.d.ts +0 -9
- package/dist/src/core/patch-export-coverage.js +1 -30
- package/dist/src/core/patch-export-update.d.ts +18 -1
- package/dist/src/core/patch-export-update.js +4 -3
- package/dist/src/core/patch-export.d.ts +11 -21
- package/dist/src/core/patch-export.js +44 -66
- package/dist/src/core/patch-files.d.ts +0 -4
- package/dist/src/core/patch-files.js +0 -11
- package/dist/src/core/patch-lint-binary.d.ts +6 -12
- package/dist/src/core/patch-lint-cache.d.ts +17 -1
- package/dist/src/core/patch-lint-cache.js +3 -6
- package/dist/src/core/patch-lint-checkjs.d.ts +33 -16
- package/dist/src/core/patch-lint-checkjs.js +37 -24
- package/dist/src/core/patch-lint-creators.d.ts +2 -6
- package/dist/src/core/patch-lint-cross.d.ts +16 -8
- package/dist/src/core/patch-lint-cross.js +49 -92
- package/dist/src/core/patch-lint-css.js +10 -6
- package/dist/src/core/patch-lint-file-size.js +3 -3
- package/dist/src/core/patch-lint-forward-registration.d.ts +58 -0
- package/dist/src/core/patch-lint-forward-registration.js +210 -0
- package/dist/src/core/patch-lint-jsdoc.js +36 -36
- package/dist/src/core/patch-lint-module-registration.d.ts +2 -8
- package/dist/src/core/patch-lint-prettier.js +1 -1
- package/dist/src/core/patch-lint-queue-types.d.ts +60 -0
- package/dist/src/core/patch-lint-queue-types.js +12 -0
- package/dist/src/core/patch-lint-staged-registration.d.ts +61 -0
- package/dist/src/core/patch-lint-staged-registration.js +90 -0
- package/dist/src/core/patch-lint.d.ts +14 -9
- package/dist/src/core/patch-lint.js +4 -3
- package/dist/src/core/patch-lock.js +3 -3
- package/dist/src/core/patch-manifest-io.js +8 -7
- package/dist/src/core/patch-parse.d.ts +19 -8
- package/dist/src/core/patch-parse.js +25 -0
- package/dist/src/core/patch-policy.js +15 -27
- package/dist/src/core/patch-source-metadata.d.ts +1 -3
- package/dist/src/core/patch-source-metadata.js +0 -4
- package/dist/src/core/patch-transform.d.ts +0 -8
- package/dist/src/core/patch-transform.js +0 -10
- package/dist/src/core/process-cpu-time.js +1 -1
- package/dist/src/core/rebase-session.d.ts +2 -8
- package/dist/src/core/rebase-session.js +5 -17
- package/dist/src/core/register-browser-content.js +3 -2
- package/dist/src/core/register-browser-test.js +2 -1
- package/dist/src/core/register-module.js +2 -1
- package/dist/src/core/register-scaffold.js +5 -4
- package/dist/src/core/register-shared-css.js +2 -1
- package/dist/src/core/run-log-redact.d.ts +38 -0
- package/dist/src/core/run-log-redact.js +69 -0
- package/dist/src/core/run-log.d.ts +13 -2
- package/dist/src/core/run-log.js +67 -18
- package/dist/src/core/signal-critical.js +2 -4
- package/dist/src/core/smoke-patterns.d.ts +0 -1
- package/dist/src/core/smoke-patterns.js +6 -11
- package/dist/src/core/state-file.d.ts +12 -1
- package/dist/src/core/state-file.js +14 -1
- package/dist/src/core/status-classify.js +2 -1
- package/dist/src/core/test-changed-prefs.js +26 -11
- package/dist/src/core/test-harness-crash.js +2 -2
- package/dist/src/core/test-stale-check.d.ts +0 -2
- package/dist/src/core/test-stale-check.js +2 -2
- package/dist/src/core/test-xpcshell-retry.d.ts +26 -7
- package/dist/src/core/test-xpcshell-retry.js +14 -11
- package/dist/src/core/token-category.d.ts +33 -0
- package/dist/src/core/token-category.js +56 -48
- package/dist/src/core/token-dark-mode.js +2 -14
- package/dist/src/core/token-inventory.d.ts +56 -0
- package/dist/src/core/token-inventory.js +109 -0
- package/dist/src/core/token-manager.d.ts +1 -1
- package/dist/src/core/token-manager.js +1 -1
- package/dist/src/core/token-variant.js +21 -22
- package/dist/src/core/toolchain-preflight.js +1 -1
- package/dist/src/core/tree-cow.d.ts +0 -2
- package/dist/src/core/tree-cow.js +2 -2
- package/dist/src/core/tree-store.js +4 -5
- package/dist/src/core/typecheck.js +2 -2
- package/dist/src/core/wire-dom-fragment.js +6 -17
- package/dist/src/core/wire-utils.js +5 -17
- package/dist/src/core/xpcshell-appdir.js +2 -4
- package/dist/src/errors/base.d.ts +53 -1
- package/dist/src/errors/base.js +79 -11
- package/dist/src/errors/build.js +20 -28
- package/dist/src/errors/config.d.ts +0 -14
- package/dist/src/errors/config.js +13 -34
- package/dist/src/errors/download.d.ts +13 -0
- package/dist/src/errors/download.js +53 -24
- package/dist/src/errors/furnace.js +8 -9
- package/dist/src/errors/git.d.ts +8 -8
- package/dist/src/errors/git.js +20 -30
- package/dist/src/errors/patch.js +8 -10
- package/dist/src/errors/rebase.js +7 -7
- package/dist/src/types/commands/options.d.ts +77 -123
- package/dist/src/types/config.d.ts +34 -2
- package/dist/src/types/index.d.ts +0 -1
- package/dist/src/utils/assert.d.ts +3 -15
- package/dist/src/utils/assert.js +1 -18
- package/dist/src/utils/build-info.d.ts +1 -1
- package/dist/src/utils/child-env.d.ts +2 -1
- package/dist/src/utils/elapsed.js +10 -1
- package/dist/src/utils/fs.js +8 -13
- package/dist/src/utils/hash.d.ts +12 -0
- package/dist/src/utils/hash.js +16 -0
- package/dist/src/utils/line-dispatch.d.ts +15 -0
- package/dist/src/utils/line-dispatch.js +48 -0
- package/dist/src/utils/options.d.ts +1 -7
- package/dist/src/utils/options.js +6 -7
- package/dist/src/utils/package-root.js +3 -12
- package/dist/src/utils/platform.d.ts +0 -4
- package/dist/src/utils/process-group.d.ts +2 -1
- package/dist/src/utils/process-group.js +20 -19
- package/dist/src/utils/process.d.ts +40 -26
- package/dist/src/utils/process.js +115 -166
- package/dist/src/utils/ps-duration.js +3 -3
- package/dist/src/utils/sleep.d.ts +26 -0
- package/dist/src/utils/sleep.js +31 -0
- package/dist/src/utils/validation.d.ts +2 -38
- package/dist/src/utils/validation.js +7 -16
- package/docs/configuration.md +89 -1
- package/docs/exit-codes.md +31 -19
- package/docs/lifecycle-invariants.md +18 -12
- package/docs/machine-output.md +31 -8
- package/docs/patch-workflow.md +2 -1
- package/docs/run-logs.md +44 -4
- package/docs/testing.md +8 -1
- package/package.json +8 -7
- package/dist/src/commands/rebase.d.ts +0 -4
- package/dist/src/commands/rebase.js +0 -5
- package/dist/src/core/patch-artifact-normalize.d.ts +0 -21
- package/dist/src/core/patch-artifact-normalize.js +0 -24
- package/dist/src/core/patch-lint-reexports.d.ts +0 -7
- package/dist/src/core/patch-lint-reexports.js +0 -8
- package/dist/src/core/wire-targets.d.ts +0 -7
- package/dist/src/core/wire-targets.js +0 -8
|
@@ -4,6 +4,7 @@ import { constants as osConstants } from 'node:os';
|
|
|
4
4
|
import { StringDecoder } from 'node:string_decoder';
|
|
5
5
|
import { ExecTimeoutError } from '../errors/base.js';
|
|
6
6
|
import { buildChildEnv } from './child-env.js';
|
|
7
|
+
import { dispatchCompleteLines } from './line-dispatch.js';
|
|
7
8
|
import { killProcessTree, sweepProcessGroup } from './process-group.js';
|
|
8
9
|
// 50 MB cap per stream to prevent OOM — large toolchain builds (e.g. Firefox, Chromium)
|
|
9
10
|
// can easily blow past this, so we truncate rather than let the buffer grow unbounded.
|
|
@@ -57,12 +58,25 @@ function buildSignalFromTimeout(timeout) {
|
|
|
57
58
|
* {@link ExecTimeoutError} naming the command and budget instead of Node's
|
|
58
59
|
* opaque `AbortError: The operation was aborted`.
|
|
59
60
|
*/
|
|
60
|
-
function toExecRejection(error, command, args, timeout) {
|
|
61
|
+
function toExecRejection(error, command, args, timeout, output) {
|
|
61
62
|
if (timeout !== undefined && error.name === 'AbortError') {
|
|
62
|
-
return new ExecTimeoutError(command, args, timeout, error);
|
|
63
|
+
return new ExecTimeoutError(command, args, timeout, error, output);
|
|
63
64
|
}
|
|
64
65
|
return error;
|
|
65
66
|
}
|
|
67
|
+
/**
|
|
68
|
+
* Snapshot of what two collectors hold, for carrying onto a timeout
|
|
69
|
+
* rejection. Without it a `git add -A` killed at its budget rejected with
|
|
70
|
+
* nothing but the budget — the partial stdout/stderr that said what git was
|
|
71
|
+
* doing when it died was already collected and simply dropped.
|
|
72
|
+
*/
|
|
73
|
+
function collectedOutput(out, err) {
|
|
74
|
+
return {
|
|
75
|
+
stdout: out.getText(),
|
|
76
|
+
stderr: err.getText(),
|
|
77
|
+
truncated: out.wasTruncated() || err.wasTruncated(),
|
|
78
|
+
};
|
|
79
|
+
}
|
|
66
80
|
function exitCodeFromClose(code, signal) {
|
|
67
81
|
if (code !== null) {
|
|
68
82
|
return code;
|
|
@@ -95,7 +109,7 @@ export async function exec(command, args, options = {}) {
|
|
|
95
109
|
child.stdout.on('data', out.onData);
|
|
96
110
|
child.stderr.on('data', err.onData);
|
|
97
111
|
child.on('error', (error) => {
|
|
98
|
-
reject(toExecRejection(error, command, args, options.timeout));
|
|
112
|
+
reject(toExecRejection(error, command, args, options.timeout, collectedOutput(out, err)));
|
|
99
113
|
});
|
|
100
114
|
child.on('close', (code, signal) => {
|
|
101
115
|
resolve({
|
|
@@ -109,48 +123,48 @@ export async function exec(command, args, options = {}) {
|
|
|
109
123
|
});
|
|
110
124
|
}
|
|
111
125
|
/**
|
|
112
|
-
*
|
|
113
|
-
*
|
|
114
|
-
*
|
|
115
|
-
*
|
|
116
|
-
*
|
|
126
|
+
* The shared body of every spawn wrapper that outlives its call: detach
|
|
127
|
+
* decision, shutdown forwarding, closure tracking, process-group sweep and
|
|
128
|
+
* typed timeout rejection.
|
|
129
|
+
*
|
|
130
|
+
* `execStream`, `execInherit` and `execInheritCapture` each hand-rolled this
|
|
131
|
+
* sequence, and the copies drifted: `execStream` was the one that omitted
|
|
132
|
+
* {@link trackChildClosure}, so the bin signal handler did not wait for
|
|
133
|
+
* `runMachStream`'s children on Ctrl+C and the forwarder's SIGTERM → grace →
|
|
134
|
+
* SIGKILL escalation could not finish before the parent exited — the exact
|
|
135
|
+
* failure the tracking set was introduced to fix, left unwired in one copy.
|
|
136
|
+
* Keeping the sequence in one place is what stops that recurring.
|
|
137
|
+
*
|
|
138
|
+
* `exec` deliberately stays outside: it neither forwards signals nor tracks
|
|
139
|
+
* closure, because it is for short-lived helpers that no one Ctrl+Cs through.
|
|
140
|
+
* `execSmokeRun` also stays outside: its deadline owns the SIGTERM → grace →
|
|
141
|
+
* SIGKILL escalation directly, so it shares no forwarder with the others.
|
|
142
|
+
*
|
|
143
|
+
* @param spec - The variant's stdio, stream wiring, grace budget and result shape
|
|
144
|
+
* @returns Whatever `spec.result` builds from the child's `close` event
|
|
117
145
|
*/
|
|
118
|
-
|
|
146
|
+
async function spawnTracked(spec) {
|
|
147
|
+
const { command, args, options } = spec;
|
|
119
148
|
return new Promise((resolve, reject) => {
|
|
120
149
|
const usesProcessGroup = options.processGroup === true && process.platform !== 'win32';
|
|
121
|
-
const child =
|
|
150
|
+
const child = spec.spawnChild({
|
|
122
151
|
cwd: options.cwd,
|
|
123
152
|
env: buildChildEnv(options),
|
|
124
|
-
stdio: ['ignore', 'pipe', 'pipe'],
|
|
125
153
|
signal: buildSignalFromTimeout(options.timeout),
|
|
126
154
|
detached: usesProcessGroup,
|
|
127
155
|
});
|
|
128
156
|
const groupPid = usesProcessGroup ? child.pid : undefined;
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
options.onStdout?.(chunk);
|
|
135
|
-
});
|
|
136
|
-
child.stderr.on('data', (data) => {
|
|
137
|
-
const chunk = stderrDecoder.write(data);
|
|
138
|
-
if (chunk.length > 0)
|
|
139
|
-
options.onStderr?.(chunk);
|
|
140
|
-
});
|
|
141
|
-
// A detached group leader no longer receives the terminal's Ctrl+C, so
|
|
142
|
-
// the forwarder is mandatory (not just graceful-UX) when processGroup
|
|
143
|
-
// is set. Group-aware: kills route to the whole tree.
|
|
144
|
-
const forwarder = options.processGroup === true
|
|
145
|
-
? installGracefulShutdownForwarder(child, 1500, (signal) => {
|
|
157
|
+
spec.attach?.(child);
|
|
158
|
+
// Group-aware kills route to the whole tree; a non-group child is killed
|
|
159
|
+
// directly by the forwarder's own `child.kill`.
|
|
160
|
+
const killTarget = options.processGroup === true
|
|
161
|
+
? (signal) => {
|
|
146
162
|
killProcessTree(child, signal, usesProcessGroup);
|
|
147
|
-
}
|
|
163
|
+
}
|
|
164
|
+
: undefined;
|
|
165
|
+
const forwarder = spec.forwardWithoutProcessGroup || options.processGroup === true
|
|
166
|
+
? installGracefulShutdownForwarder(child, spec.graceMs, killTarget)
|
|
148
167
|
: undefined;
|
|
149
|
-
// Closure tracking: this was the one wrapper that omitted it, so the bin
|
|
150
|
-
// signal handler did not wait for `runMachStream`'s children on Ctrl+C
|
|
151
|
-
// and the forwarder's SIGTERM → grace → SIGKILL escalation above could
|
|
152
|
-
// not finish before the parent exited — the exact failure the tracking
|
|
153
|
-
// set was introduced to fix, left unwired here.
|
|
154
168
|
const closure = trackChildClosure();
|
|
155
169
|
child.on('error', (error) => {
|
|
156
170
|
// Abort/startup failure: make sure a partially-started tree does not
|
|
@@ -161,13 +175,13 @@ export async function execStream(command, args, options = {}) {
|
|
|
161
175
|
}
|
|
162
176
|
forwarder?.dispose();
|
|
163
177
|
closure.settle();
|
|
164
|
-
reject(toExecRejection(error, command, args, options.timeout));
|
|
178
|
+
reject(toExecRejection(error, command, args, options.timeout, spec.rejectionOutput?.()));
|
|
165
179
|
});
|
|
166
180
|
child.on('close', (code, signal) => {
|
|
167
181
|
forwarder?.dispose();
|
|
168
182
|
const finish = () => {
|
|
169
183
|
closure.settle();
|
|
170
|
-
resolve(
|
|
184
|
+
resolve(spec.result(code, signal));
|
|
171
185
|
};
|
|
172
186
|
if (groupPid !== undefined) {
|
|
173
187
|
sweepProcessGroup(groupPid).then(finish, finish);
|
|
@@ -178,6 +192,41 @@ export async function execStream(command, args, options = {}) {
|
|
|
178
192
|
});
|
|
179
193
|
});
|
|
180
194
|
}
|
|
195
|
+
/**
|
|
196
|
+
* Executes a command and streams its output.
|
|
197
|
+
* @param command - Command to execute
|
|
198
|
+
* @param args - Command arguments
|
|
199
|
+
* @param options - Execution options
|
|
200
|
+
* @returns Exit code of the process
|
|
201
|
+
*/
|
|
202
|
+
export async function execStream(command, args, options = {}) {
|
|
203
|
+
return spawnTracked({
|
|
204
|
+
command,
|
|
205
|
+
args,
|
|
206
|
+
options,
|
|
207
|
+
graceMs: 1500,
|
|
208
|
+
// A detached group leader no longer receives the terminal's Ctrl+C, so
|
|
209
|
+
// the forwarder is mandatory (not just graceful-UX) when processGroup
|
|
210
|
+
// is set — but a plain streamed child does not get one.
|
|
211
|
+
forwardWithoutProcessGroup: false,
|
|
212
|
+
spawnChild: (base) => spawn(command, args, { ...base, stdio: ['ignore', 'pipe', 'pipe'] }),
|
|
213
|
+
attach: (child) => {
|
|
214
|
+
const stdoutDecoder = new StringDecoder('utf8');
|
|
215
|
+
const stderrDecoder = new StringDecoder('utf8');
|
|
216
|
+
child.stdout.on('data', (data) => {
|
|
217
|
+
const chunk = stdoutDecoder.write(data);
|
|
218
|
+
if (chunk.length > 0)
|
|
219
|
+
options.onStdout?.(chunk);
|
|
220
|
+
});
|
|
221
|
+
child.stderr.on('data', (data) => {
|
|
222
|
+
const chunk = stderrDecoder.write(data);
|
|
223
|
+
if (chunk.length > 0)
|
|
224
|
+
options.onStderr?.(chunk);
|
|
225
|
+
});
|
|
226
|
+
},
|
|
227
|
+
result: exitCodeFromClose,
|
|
228
|
+
});
|
|
229
|
+
}
|
|
181
230
|
/**
|
|
182
231
|
* Close-promises of children whose shutdown the CLI must wait for when a
|
|
183
232
|
* termination signal arrives. A bin signal handler that calls `process.exit`
|
|
@@ -253,44 +302,14 @@ export async function waitForActiveChildShutdown(timeoutMs) {
|
|
|
253
302
|
* @returns Exit code of the process
|
|
254
303
|
*/
|
|
255
304
|
export async function execInherit(command, args, options = {}) {
|
|
256
|
-
return
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
});
|
|
265
|
-
const groupPid = usesProcessGroup ? child.pid : undefined;
|
|
266
|
-
const graceMs = options.shutdownGraceMs ?? 1500;
|
|
267
|
-
const { dispose } = installGracefulShutdownForwarder(child, graceMs, options.processGroup === true
|
|
268
|
-
? (signal) => {
|
|
269
|
-
killProcessTree(child, signal, usesProcessGroup);
|
|
270
|
-
}
|
|
271
|
-
: undefined);
|
|
272
|
-
const closure = trackChildClosure();
|
|
273
|
-
child.on('error', (error) => {
|
|
274
|
-
if (options.processGroup === true) {
|
|
275
|
-
killProcessTree(child, 'SIGKILL', usesProcessGroup);
|
|
276
|
-
}
|
|
277
|
-
dispose();
|
|
278
|
-
closure.settle();
|
|
279
|
-
reject(toExecRejection(error, command, args, options.timeout));
|
|
280
|
-
});
|
|
281
|
-
child.on('close', (code, signal) => {
|
|
282
|
-
dispose();
|
|
283
|
-
const finish = () => {
|
|
284
|
-
closure.settle();
|
|
285
|
-
resolve(exitCodeFromClose(code, signal));
|
|
286
|
-
};
|
|
287
|
-
if (groupPid !== undefined) {
|
|
288
|
-
sweepProcessGroup(groupPid).then(finish, finish);
|
|
289
|
-
}
|
|
290
|
-
else {
|
|
291
|
-
finish();
|
|
292
|
-
}
|
|
293
|
-
});
|
|
305
|
+
return spawnTracked({
|
|
306
|
+
command,
|
|
307
|
+
args,
|
|
308
|
+
options,
|
|
309
|
+
graceMs: options.shutdownGraceMs ?? 1500,
|
|
310
|
+
forwardWithoutProcessGroup: true,
|
|
311
|
+
spawnChild: (base) => spawn(command, args, { ...base, stdio: 'inherit' }),
|
|
312
|
+
result: exitCodeFromClose,
|
|
294
313
|
});
|
|
295
314
|
}
|
|
296
315
|
/**
|
|
@@ -365,54 +384,27 @@ export function installGracefulShutdownForwarder(child, graceMs, killTarget) {
|
|
|
365
384
|
* @returns Execution result with stdout, stderr, and exit code
|
|
366
385
|
*/
|
|
367
386
|
export async function execInheritCapture(command, args, options = {}) {
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
})
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
child.on('error', (error) => {
|
|
390
|
-
if (options.processGroup === true) {
|
|
391
|
-
killProcessTree(child, 'SIGKILL', usesProcessGroup);
|
|
392
|
-
}
|
|
393
|
-
dispose();
|
|
394
|
-
closure.settle();
|
|
395
|
-
reject(toExecRejection(error, command, args, options.timeout));
|
|
396
|
-
});
|
|
397
|
-
child.on('close', (code, signal) => {
|
|
398
|
-
dispose();
|
|
399
|
-
const finish = () => {
|
|
400
|
-
closure.settle();
|
|
401
|
-
resolve({
|
|
402
|
-
stdout: out.getText(),
|
|
403
|
-
stderr: err.getText(),
|
|
404
|
-
exitCode: exitCodeFromClose(code, signal),
|
|
405
|
-
stdoutTruncated: out.wasTruncated(),
|
|
406
|
-
stderrTruncated: err.wasTruncated(),
|
|
407
|
-
});
|
|
408
|
-
};
|
|
409
|
-
if (groupPid !== undefined) {
|
|
410
|
-
sweepProcessGroup(groupPid).then(finish, finish);
|
|
411
|
-
}
|
|
412
|
-
else {
|
|
413
|
-
finish();
|
|
414
|
-
}
|
|
415
|
-
});
|
|
387
|
+
const out = createStreamCollector(options.mirror?.stdout ?? process.stdout);
|
|
388
|
+
const err = createStreamCollector(options.mirror?.stderr ?? process.stderr);
|
|
389
|
+
return spawnTracked({
|
|
390
|
+
command,
|
|
391
|
+
args,
|
|
392
|
+
options,
|
|
393
|
+
graceMs: options.shutdownGraceMs ?? 1500,
|
|
394
|
+
forwardWithoutProcessGroup: true,
|
|
395
|
+
spawnChild: (base) => spawn(command, args, { ...base, stdio: ['inherit', 'pipe', 'pipe'] }),
|
|
396
|
+
attach: (child) => {
|
|
397
|
+
child.stdout.on('data', out.onData);
|
|
398
|
+
child.stderr.on('data', err.onData);
|
|
399
|
+
},
|
|
400
|
+
result: (code, signal) => ({
|
|
401
|
+
stdout: out.getText(),
|
|
402
|
+
stderr: err.getText(),
|
|
403
|
+
exitCode: exitCodeFromClose(code, signal),
|
|
404
|
+
stdoutTruncated: out.wasTruncated(),
|
|
405
|
+
stderrTruncated: err.wasTruncated(),
|
|
406
|
+
}),
|
|
407
|
+
rejectionOutput: () => collectedOutput(out, err),
|
|
416
408
|
});
|
|
417
409
|
}
|
|
418
410
|
/**
|
|
@@ -542,48 +534,6 @@ export async function execSmokeRun(command, args, options) {
|
|
|
542
534
|
});
|
|
543
535
|
});
|
|
544
536
|
}
|
|
545
|
-
/**
|
|
546
|
-
* Cap on the partial-line tail kept between chunks. A child emitting one
|
|
547
|
-
* enormous line with no terminator (minified JS dumped to stderr, a raw
|
|
548
|
-
* binary blob) would otherwise grow the buffer without bound — the 50 MB cap
|
|
549
|
-
* guards the collector, not these line buffers. When the tail exceeds the
|
|
550
|
-
* cap it is dispatched as a synthetic (oversized) line so the matchers still
|
|
551
|
-
* see its content, then the buffer resets.
|
|
552
|
-
*/
|
|
553
|
-
const MAX_PARTIAL_LINE_SIZE = 1024 * 1024;
|
|
554
|
-
/**
|
|
555
|
-
* Drains complete lines from `buffer`, dispatching each to `cb`. Treats
|
|
556
|
-
* `\n`, `\r\n`, and lone `\r` as line terminators — the lone-`\r` case
|
|
557
|
-
* matters for progress-bar style output (mach, cargo) that repaints a line
|
|
558
|
-
* with carriage returns and never sends a newline, which otherwise
|
|
559
|
-
* accumulates indefinitely. A single trailing `\r` is held back since it may
|
|
560
|
-
* be the first half of a `\r\n` pair split across chunks. Returns the
|
|
561
|
-
* remaining partial line — callers keep accumulating into it.
|
|
562
|
-
*/
|
|
563
|
-
function dispatchCompleteLines(buffer, cb) {
|
|
564
|
-
let searchFrom = 0;
|
|
565
|
-
for (;;) {
|
|
566
|
-
const nl = buffer.indexOf('\n', searchFrom);
|
|
567
|
-
const cr = buffer.indexOf('\r', searchFrom);
|
|
568
|
-
const idx = nl === -1 ? cr : cr === -1 ? nl : Math.min(nl, cr);
|
|
569
|
-
if (idx === -1)
|
|
570
|
-
break;
|
|
571
|
-
if (buffer[idx] === '\r' && idx === buffer.length - 1) {
|
|
572
|
-
// Possible first half of a chunk-split \r\n — wait for the next chunk.
|
|
573
|
-
break;
|
|
574
|
-
}
|
|
575
|
-
const line = buffer.slice(0, idx);
|
|
576
|
-
const terminatorLength = buffer[idx] === '\r' && buffer[idx + 1] === '\n' ? 2 : 1;
|
|
577
|
-
buffer = buffer.slice(idx + terminatorLength);
|
|
578
|
-
searchFrom = 0;
|
|
579
|
-
cb?.(line);
|
|
580
|
-
}
|
|
581
|
-
if (buffer.length > MAX_PARTIAL_LINE_SIZE) {
|
|
582
|
-
cb?.(buffer);
|
|
583
|
-
return '';
|
|
584
|
-
}
|
|
585
|
-
return buffer;
|
|
586
|
-
}
|
|
587
537
|
/**
|
|
588
538
|
* Finds an executable in the system PATH.
|
|
589
539
|
* @param name - Name of the executable
|
|
@@ -602,8 +552,7 @@ export async function findExecutable(name) {
|
|
|
602
552
|
}
|
|
603
553
|
return undefined;
|
|
604
554
|
}
|
|
605
|
-
catch
|
|
606
|
-
void error;
|
|
555
|
+
catch {
|
|
607
556
|
return undefined;
|
|
608
557
|
}
|
|
609
558
|
}
|
|
@@ -58,13 +58,13 @@ export function formatPsDuration(seconds) {
|
|
|
58
58
|
if (Number.isNaN(seconds) || seconds < 0)
|
|
59
59
|
return undefined;
|
|
60
60
|
if (seconds < 60)
|
|
61
|
-
return `${
|
|
61
|
+
return `${Math.floor(seconds)}s`;
|
|
62
62
|
if (seconds < 3600) {
|
|
63
63
|
const m = Math.floor(seconds / 60);
|
|
64
64
|
const s = Math.floor(seconds % 60);
|
|
65
|
-
return `${
|
|
65
|
+
return `${m}m${String(s).padStart(2, '0')}s`;
|
|
66
66
|
}
|
|
67
67
|
const h = Math.floor(seconds / 3600);
|
|
68
68
|
const m = Math.floor((seconds % 3600) / 60);
|
|
69
|
-
return `${
|
|
69
|
+
return `${h}h${String(m).padStart(2, '0')}m`;
|
|
70
70
|
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The single awaitable delay used across FireForge.
|
|
3
|
+
*
|
|
4
|
+
* Five modules had grown a private copy of this (`sleep`, `delay`,
|
|
5
|
+
* `sweepDelay`) and four more sites inlined
|
|
6
|
+
* `new Promise((resolve) => setTimeout(resolve, ms))`. The copies disagreed on
|
|
7
|
+
* the one property that actually matters — whether the pending timer holds the
|
|
8
|
+
* event loop open — and the disagreement was invisible at each call site. Both
|
|
9
|
+
* behaviours now live here, and callers state which one they need.
|
|
10
|
+
*
|
|
11
|
+
* The default is a ref'd timer, because the dangerous mistake is the other
|
|
12
|
+
* one: an unref'd delay awaited between a SIGTERM and its escalation lets Node
|
|
13
|
+
* exit mid-grace and skip the escalation entirely.
|
|
14
|
+
*
|
|
15
|
+
* Deliberately built on the global `setTimeout` rather than
|
|
16
|
+
* `node:timers/promises`: the suites that drive retry and grace-period logic
|
|
17
|
+
* use vitest fake timers, which patch the global but not the promisified
|
|
18
|
+
* module, so the tidier import would make every timing path untestable.
|
|
19
|
+
* @param ms - Milliseconds to wait.
|
|
20
|
+
* @param options - Pass `unref: true` when a pending delay must not keep the
|
|
21
|
+
* process alive (background probes, best-effort retries during shutdown).
|
|
22
|
+
* @returns A promise that resolves once the delay has elapsed.
|
|
23
|
+
*/
|
|
24
|
+
export declare function sleep(ms: number, options?: {
|
|
25
|
+
unref?: boolean;
|
|
26
|
+
}): Promise<void>;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
// SPDX-License-Identifier: EUPL-1.2
|
|
2
|
+
/**
|
|
3
|
+
* The single awaitable delay used across FireForge.
|
|
4
|
+
*
|
|
5
|
+
* Five modules had grown a private copy of this (`sleep`, `delay`,
|
|
6
|
+
* `sweepDelay`) and four more sites inlined
|
|
7
|
+
* `new Promise((resolve) => setTimeout(resolve, ms))`. The copies disagreed on
|
|
8
|
+
* the one property that actually matters — whether the pending timer holds the
|
|
9
|
+
* event loop open — and the disagreement was invisible at each call site. Both
|
|
10
|
+
* behaviours now live here, and callers state which one they need.
|
|
11
|
+
*
|
|
12
|
+
* The default is a ref'd timer, because the dangerous mistake is the other
|
|
13
|
+
* one: an unref'd delay awaited between a SIGTERM and its escalation lets Node
|
|
14
|
+
* exit mid-grace and skip the escalation entirely.
|
|
15
|
+
*
|
|
16
|
+
* Deliberately built on the global `setTimeout` rather than
|
|
17
|
+
* `node:timers/promises`: the suites that drive retry and grace-period logic
|
|
18
|
+
* use vitest fake timers, which patch the global but not the promisified
|
|
19
|
+
* module, so the tidier import would make every timing path untestable.
|
|
20
|
+
* @param ms - Milliseconds to wait.
|
|
21
|
+
* @param options - Pass `unref: true` when a pending delay must not keep the
|
|
22
|
+
* process alive (background probes, best-effort retries during shutdown).
|
|
23
|
+
* @returns A promise that resolves once the delay has elapsed.
|
|
24
|
+
*/
|
|
25
|
+
export function sleep(ms, options) {
|
|
26
|
+
return new Promise((resolve) => {
|
|
27
|
+
const timer = setTimeout(resolve, ms);
|
|
28
|
+
if (options?.unref === true)
|
|
29
|
+
timer.unref();
|
|
30
|
+
});
|
|
31
|
+
}
|
|
@@ -73,40 +73,12 @@ export declare function isValidFirefoxVersion(version: string): boolean;
|
|
|
73
73
|
* Accepts formats like "build1", "build2", "build12" (no leading zero).
|
|
74
74
|
*/
|
|
75
75
|
export declare function isValidFirefoxCandidate(candidate: string): boolean;
|
|
76
|
-
/**
|
|
77
|
-
* Naming contract for this module's checks.
|
|
78
|
-
*
|
|
79
|
-
* `validate*` is easy to spread across incompatible return contracts — some
|
|
80
|
-
* throwing and returning void, some returning an issue list, some a parsed
|
|
81
|
-
* value, some a boolean, some an error MESSAGE — and a caller cannot tell
|
|
82
|
-
* which from the name. Passing a THROWING `validate*` to a clack `validate`
|
|
83
|
-
* callback, which expects a returned message, kills the prompt instead of
|
|
84
|
-
* re-prompting.
|
|
85
|
-
*
|
|
86
|
-
* The two dominant contracts keep the prefix:
|
|
87
|
-
* - `validate*` — throws on failure, or returns an issue list.
|
|
88
|
-
* - `is*` / `has*` — a type predicate or boolean.
|
|
89
|
-
* The message-returning minority is `describe*Problem`, which reads as what
|
|
90
|
-
* it is: a description of what is wrong, or `undefined`.
|
|
91
|
-
*
|
|
92
|
-
* `assert*` is uniform throughout: throw-or-continue.
|
|
93
|
-
*/
|
|
94
|
-
/**
|
|
95
|
-
* Valid Firefox product identifiers.
|
|
96
|
-
*
|
|
97
|
-
* `satisfies readonly FirefoxProduct[]` links the runtime list to the union
|
|
98
|
-
* in ONE direction: it rejects an entry here that the union does not
|
|
99
|
-
* declare. It cannot see a union member missing from this list — widening a
|
|
100
|
-
* `readonly T[]` check never fails for being short. The reverse direction is
|
|
101
|
-
* covered by the exhaustive switch in `utils/__tests__/validation.test.ts`,
|
|
102
|
-
* which fails to compile when the union grows.
|
|
103
|
-
*/
|
|
104
76
|
export declare const FIREFOX_PRODUCTS: readonly ["firefox", "firefox-esr", "firefox-beta", "firefox-devedition"];
|
|
105
77
|
/**
|
|
106
78
|
* Validates a Firefox product string.
|
|
107
79
|
*
|
|
108
|
-
* A type predicate, matching its
|
|
109
|
-
*
|
|
80
|
+
* A type predicate, matching its sibling {@link isValidProjectLicense}.
|
|
81
|
+
* Returning plain `boolean` would force
|
|
110
82
|
* `as FirefoxProduct` casts at the call sites even though the `.includes`
|
|
111
83
|
* check IS the runtime proof.
|
|
112
84
|
*/
|
|
@@ -141,10 +113,6 @@ export declare const isValidProjectLicense: (value: string) => value is "EUPL-1.
|
|
|
141
113
|
* Valid patch categories.
|
|
142
114
|
*/
|
|
143
115
|
export declare const PATCH_CATEGORIES: readonly ["branding", "ui", "privacy", "security", "infra"];
|
|
144
|
-
/**
|
|
145
|
-
* Validates a patch category string.
|
|
146
|
-
*/
|
|
147
|
-
export declare const isValidPatchCategory: (value: string) => value is "branding" | "ui" | "privacy" | "security" | "infra";
|
|
148
116
|
/**
|
|
149
117
|
* Infers the Firefox product type from a version string.
|
|
150
118
|
* Returns undefined if no clear inference can be made.
|
|
@@ -166,10 +134,6 @@ export declare function describeProductVersionIncompatibility(version: string, p
|
|
|
166
134
|
* Accepts reverse-domain format like "org.example.browser"
|
|
167
135
|
*/
|
|
168
136
|
export declare function isValidAppId(appId: string): boolean;
|
|
169
|
-
/**
|
|
170
|
-
* Checks if a value is defined (not undefined or null).
|
|
171
|
-
*/
|
|
172
|
-
export declare function isDefined<T>(value: T | undefined | null): value is T;
|
|
173
137
|
/**
|
|
174
138
|
* Validates that a string is a legal CSS custom property identifier (the part after `--`).
|
|
175
139
|
*
|
|
@@ -89,7 +89,7 @@ export function isArray(value) {
|
|
|
89
89
|
* @returns True if value is a JSON object node
|
|
90
90
|
*/
|
|
91
91
|
export function isJsonObject(value) {
|
|
92
|
-
return
|
|
92
|
+
return isObject(value);
|
|
93
93
|
}
|
|
94
94
|
/**
|
|
95
95
|
* Validates a Firefox version string.
|
|
@@ -132,20 +132,21 @@ export function isValidFirefoxCandidate(candidate) {
|
|
|
132
132
|
* in ONE direction: it rejects an entry here that the union does not
|
|
133
133
|
* declare. It cannot see a union member missing from this list — widening a
|
|
134
134
|
* `readonly T[]` check never fails for being short. The reverse direction is
|
|
135
|
-
* covered by the
|
|
136
|
-
*
|
|
135
|
+
* covered by the `ExhaustiveFirefoxProductList` operand below, which stops
|
|
136
|
+
* compiling when the union grows past this list.
|
|
137
137
|
*/
|
|
138
|
-
|
|
138
|
+
const FIREFOX_PRODUCT_VALUES = [
|
|
139
139
|
'firefox',
|
|
140
140
|
'firefox-esr',
|
|
141
141
|
'firefox-beta',
|
|
142
142
|
'firefox-devedition',
|
|
143
143
|
];
|
|
144
|
+
export const FIREFOX_PRODUCTS = FIREFOX_PRODUCT_VALUES;
|
|
144
145
|
/**
|
|
145
146
|
* Validates a Firefox product string.
|
|
146
147
|
*
|
|
147
|
-
* A type predicate, matching its
|
|
148
|
-
*
|
|
148
|
+
* A type predicate, matching its sibling {@link isValidProjectLicense}.
|
|
149
|
+
* Returning plain `boolean` would force
|
|
149
150
|
* `as FirefoxProduct` casts at the call sites even though the `.includes`
|
|
150
151
|
* check IS the runtime proof.
|
|
151
152
|
*/
|
|
@@ -182,10 +183,6 @@ export const isValidProjectLicense = makeEnumGuard(PROJECT_LICENSES);
|
|
|
182
183
|
* Valid patch categories.
|
|
183
184
|
*/
|
|
184
185
|
export const PATCH_CATEGORIES = ['branding', 'ui', 'privacy', 'security', 'infra'];
|
|
185
|
-
/**
|
|
186
|
-
* Validates a patch category string.
|
|
187
|
-
*/
|
|
188
|
-
export const isValidPatchCategory = makeEnumGuard(PATCH_CATEGORIES);
|
|
189
186
|
/**
|
|
190
187
|
* Checks whether a Firefox version string has an ESR suffix.
|
|
191
188
|
*/
|
|
@@ -257,12 +254,6 @@ export function describeProductVersionIncompatibility(version, product) {
|
|
|
257
254
|
export function isValidAppId(appId) {
|
|
258
255
|
return /^[a-z][a-z0-9]*(\.[a-z][a-z0-9]*)+$/.test(appId);
|
|
259
256
|
}
|
|
260
|
-
/**
|
|
261
|
-
* Checks if a value is defined (not undefined or null).
|
|
262
|
-
*/
|
|
263
|
-
export function isDefined(value) {
|
|
264
|
-
return value !== undefined && value !== null;
|
|
265
|
-
}
|
|
266
257
|
/**
|
|
267
258
|
* Validates that a string is a legal CSS custom property identifier (the part after `--`).
|
|
268
259
|
*
|