@hominis/fireforge 0.43.1 → 0.44.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 +126 -0
- package/README.md +10 -1
- package/dist/bin/fireforge.d.ts +4 -9
- package/dist/bin/fireforge.js +42 -40
- package/dist/build-info.json +4 -4
- package/dist/src/cli.js +74 -8
- package/dist/src/commands/bootstrap.js +17 -20
- package/dist/src/commands/build.js +25 -32
- package/dist/src/commands/config.js +34 -41
- package/dist/src/commands/discard.js +8 -9
- package/dist/src/commands/doctor-check-core.d.ts +4 -18
- package/dist/src/commands/doctor-check-core.js +8 -35
- package/dist/src/commands/doctor-external-toolchains.js +2 -2
- package/dist/src/commands/doctor-furnace-config-sync.d.ts +18 -0
- package/dist/src/commands/{doctor-furnace-manifest-sync.js → doctor-furnace-config-sync.js} +27 -26
- package/dist/src/commands/doctor-furnace-jar.d.ts +7 -9
- package/dist/src/commands/doctor-furnace-jar.js +7 -9
- package/dist/src/commands/doctor-furnace.js +21 -24
- package/dist/src/commands/doctor-orphaned-harness.d.ts +16 -20
- package/dist/src/commands/doctor-orphaned-harness.js +18 -44
- package/dist/src/commands/doctor-post-rebase-audit.d.ts +2 -0
- package/dist/src/commands/{doctor/post-rebase-audit.js → doctor-post-rebase-audit.js} +3 -3
- package/dist/src/commands/doctor-working-tree.d.ts +10 -12
- package/dist/src/commands/doctor-working-tree.js +11 -18
- package/dist/src/commands/doctor.js +35 -53
- package/dist/src/commands/download.js +32 -48
- package/dist/src/commands/export-all.js +29 -33
- package/dist/src/commands/export-flow.js +6 -6
- package/dist/src/commands/export-placement-conflicts.js +10 -9
- package/dist/src/commands/export-placement-gate.js +5 -5
- package/dist/src/commands/export-shared.d.ts +30 -33
- package/dist/src/commands/export-shared.js +45 -43
- package/dist/src/commands/export.js +21 -27
- package/dist/src/commands/furnace/apply.js +14 -23
- package/dist/src/commands/furnace/chrome-doc-remove.js +14 -21
- package/dist/src/commands/furnace/chrome-doc-templates.d.ts +23 -23
- package/dist/src/commands/furnace/chrome-doc-templates.js +23 -23
- package/dist/src/commands/furnace/chrome-doc-tests.js +26 -29
- package/dist/src/commands/furnace/chrome-doc.d.ts +16 -17
- package/dist/src/commands/furnace/chrome-doc.js +31 -41
- package/dist/src/commands/furnace/create-browser-test.d.ts +4 -4
- package/dist/src/commands/furnace/create-browser-test.js +8 -8
- package/dist/src/commands/furnace/create-mochikit.d.ts +6 -7
- package/dist/src/commands/furnace/create-mochikit.js +8 -9
- package/dist/src/commands/furnace/create-readback.d.ts +12 -13
- package/dist/src/commands/furnace/create-readback.js +12 -13
- package/dist/src/commands/furnace/create-templates.d.ts +22 -28
- package/dist/src/commands/furnace/create-templates.js +35 -30
- package/dist/src/commands/furnace/create-xpcshell.js +2 -2
- package/dist/src/commands/furnace/create.js +33 -23
- package/dist/src/commands/furnace/deploy.js +16 -24
- package/dist/src/commands/furnace/diff.js +9 -9
- package/dist/src/commands/furnace/init.js +33 -36
- package/dist/src/commands/furnace/override.js +23 -25
- package/dist/src/commands/furnace/preview.js +47 -67
- package/dist/src/commands/furnace/refresh.js +12 -16
- package/dist/src/commands/furnace/remove-mutations.d.ts +3 -6
- package/dist/src/commands/furnace/remove-mutations.js +9 -16
- package/dist/src/commands/furnace/remove-state.js +1 -1
- package/dist/src/commands/furnace/remove.js +33 -38
- package/dist/src/commands/furnace/rename-xpcshell.d.ts +8 -11
- package/dist/src/commands/furnace/rename-xpcshell.js +8 -11
- package/dist/src/commands/furnace/rename.js +59 -69
- package/dist/src/commands/furnace/scan.js +19 -33
- package/dist/src/commands/furnace/status.js +12 -9
- package/dist/src/commands/furnace/sync.js +9 -16
- package/dist/src/commands/furnace/validate.js +20 -20
- package/dist/src/commands/import.js +42 -35
- package/dist/src/commands/lint-per-patch.js +15 -10
- package/dist/src/commands/lint-per-run-checkjs.d.ts +13 -13
- package/dist/src/commands/lint-per-run-checkjs.js +13 -13
- package/dist/src/commands/lint-report.js +6 -7
- package/dist/src/commands/lint.d.ts +15 -16
- package/dist/src/commands/lint.js +86 -102
- package/dist/src/commands/package.js +6 -11
- package/dist/src/commands/patch/compact.js +1 -1
- package/dist/src/commands/patch/delete.js +24 -33
- package/dist/src/commands/patch/index.d.ts +5 -6
- package/dist/src/commands/patch/index.js +10 -12
- package/dist/src/commands/patch/lint-ignore.js +14 -13
- package/dist/src/commands/patch/move-files-create.d.ts +6 -6
- package/dist/src/commands/patch/move-files-create.js +8 -8
- package/dist/src/commands/patch/move-files-into.d.ts +6 -6
- package/dist/src/commands/patch/move-files-into.js +8 -8
- package/dist/src/commands/patch/patch-context.d.ts +2 -3
- package/dist/src/commands/patch/patch-context.js +2 -3
- package/dist/src/commands/patch/rename.d.ts +10 -11
- package/dist/src/commands/patch/rename.js +11 -12
- package/dist/src/commands/patch/reorder.js +8 -9
- package/dist/src/commands/patch/split-plan.js +1 -1
- package/dist/src/commands/patch/split.d.ts +8 -10
- package/dist/src/commands/patch/split.js +9 -11
- package/dist/src/commands/patch/staged-dependency-validate.js +8 -8
- package/dist/src/commands/patch/staged-dependency.js +7 -3
- package/dist/src/commands/patch/tier.d.ts +9 -9
- package/dist/src/commands/patch/tier.js +18 -15
- package/dist/src/commands/re-export-adjacent.js +9 -8
- package/dist/src/commands/re-export-bulk-scan.d.ts +9 -9
- package/dist/src/commands/re-export-bulk-scan.js +22 -21
- package/dist/src/commands/re-export-drift.js +10 -10
- package/dist/src/commands/re-export-files.d.ts +6 -7
- package/dist/src/commands/re-export-files.js +34 -44
- package/dist/src/commands/re-export-lint.d.ts +10 -13
- package/dist/src/commands/re-export-lint.js +16 -14
- package/dist/src/commands/re-export-options.d.ts +6 -6
- package/dist/src/commands/re-export-options.js +6 -6
- package/dist/src/commands/re-export-register.d.ts +4 -10
- package/dist/src/commands/re-export-register.js +5 -11
- package/dist/src/commands/re-export-scan.js +1 -1
- package/dist/src/commands/re-export-single.d.ts +3 -3
- package/dist/src/commands/re-export-single.js +33 -25
- package/dist/src/commands/re-export.js +13 -21
- package/dist/src/commands/rebase/abort.js +3 -3
- package/dist/src/commands/rebase/confirm.js +2 -1
- package/dist/src/commands/rebase/continue.d.ts +1 -1
- package/dist/src/commands/rebase/continue.js +14 -9
- package/dist/src/commands/rebase/index.js +11 -11
- package/dist/src/commands/rebase/patch-loop.d.ts +7 -1
- package/dist/src/commands/rebase/patch-loop.js +60 -39
- package/dist/src/commands/rebase/summary.js +1 -1
- package/dist/src/commands/register.js +5 -7
- package/dist/src/commands/reset.js +2 -1
- package/dist/src/commands/resolve.d.ts +16 -13
- package/dist/src/commands/resolve.js +30 -33
- package/dist/src/commands/run.js +33 -35
- package/dist/src/commands/setup-support.js +15 -19
- package/dist/src/commands/setup.js +13 -9
- package/dist/src/commands/status-check.d.ts +6 -6
- package/dist/src/commands/status-json.d.ts +6 -6
- package/dist/src/commands/status-json.js +5 -0
- package/dist/src/commands/status-output.d.ts +5 -5
- package/dist/src/commands/status-output.js +6 -6
- package/dist/src/commands/status-ownership.d.ts +16 -14
- package/dist/src/commands/status-ownership.js +16 -14
- package/dist/src/commands/status.js +42 -34
- package/dist/src/commands/test-build-phase.js +26 -13
- package/dist/src/commands/test-diagnose.js +44 -44
- package/dist/src/commands/test-register.js +1 -0
- package/dist/src/commands/test-run.d.ts +14 -16
- package/dist/src/commands/test-run.js +21 -13
- package/dist/src/commands/test-stale-gate.d.ts +15 -16
- package/dist/src/commands/test-stale-gate.js +15 -16
- package/dist/src/commands/test-verdict.d.ts +20 -3
- package/dist/src/commands/test-verdict.js +30 -0
- package/dist/src/commands/test.js +83 -76
- package/dist/src/commands/token-coverage.js +3 -4
- package/dist/src/commands/token.js +16 -18
- package/dist/src/commands/tree.js +47 -31
- package/dist/src/commands/typecheck.d.ts +10 -12
- package/dist/src/commands/typecheck.js +24 -27
- package/dist/src/commands/verify.js +13 -15
- package/dist/src/commands/watch.js +21 -23
- package/dist/src/commands/wire.js +52 -62
- package/dist/src/core/ast-utils.d.ts +8 -7
- package/dist/src/core/ast-utils.js +8 -7
- package/dist/src/core/branding.d.ts +9 -14
- package/dist/src/core/branding.js +7 -11
- package/dist/src/core/browser-wire.d.ts +1 -1
- package/dist/src/core/browser-wire.js +14 -19
- package/dist/src/core/build-audit-platform.js +25 -33
- package/dist/src/core/build-audit-registration.js +17 -25
- package/dist/src/core/build-audit-resolve.d.ts +15 -17
- package/dist/src/core/build-audit-resolve.js +27 -33
- package/dist/src/core/build-audit-transforms.js +18 -19
- package/dist/src/core/build-audit.js +28 -42
- package/dist/src/core/build-baseline-types.d.ts +29 -35
- package/dist/src/core/build-baseline.d.ts +5 -4
- package/dist/src/core/build-baseline.js +14 -14
- package/dist/src/core/build-overwrite-guard.d.ts +7 -14
- package/dist/src/core/build-overwrite-guard.js +17 -27
- package/dist/src/core/build-prepare.d.ts +2 -2
- package/dist/src/core/build-prepare.js +8 -9
- package/dist/src/core/config-state.js +12 -4
- package/dist/src/core/config-validate.js +8 -5
- package/dist/src/core/config.d.ts +5 -8
- package/dist/src/core/config.js +7 -16
- package/dist/src/core/coverage-extend.d.ts +15 -13
- package/dist/src/core/coverage-extend.js +15 -13
- package/dist/src/core/destructive.d.ts +31 -9
- package/dist/src/core/destructive.js +29 -26
- package/dist/src/core/diff-hunks.js +10 -12
- package/dist/src/core/discard-baseline.d.ts +8 -8
- package/dist/src/core/discard-baseline.js +16 -15
- package/dist/src/core/display-state.d.ts +12 -14
- package/dist/src/core/display-state.js +12 -14
- package/dist/src/core/engine-changes.d.ts +2 -4
- package/dist/src/core/engine-changes.js +2 -4
- package/dist/src/core/engine-precondition.d.ts +28 -13
- package/dist/src/core/engine-precondition.js +25 -10
- package/dist/src/core/engine-session-lock.d.ts +47 -21
- package/dist/src/core/engine-session-lock.js +168 -33
- package/dist/src/core/export-moved-code-shape.d.ts +10 -10
- package/dist/src/core/export-moved-code-shape.js +10 -10
- package/dist/src/core/file-lock.d.ts +62 -5
- package/dist/src/core/file-lock.js +196 -59
- package/dist/src/core/firefox-cache.js +1 -3
- package/dist/src/core/firefox-extract.js +10 -14
- package/dist/src/core/firefox.d.ts +7 -5
- package/dist/src/core/firefox.js +4 -5
- package/dist/src/core/furnace-apply-dry-run.d.ts +2 -2
- package/dist/src/core/furnace-apply-dry-run.js +3 -2
- package/dist/src/core/furnace-apply-ftl.d.ts +7 -9
- package/dist/src/core/furnace-apply-ftl.js +12 -12
- package/dist/src/core/furnace-apply-helpers.d.ts +7 -7
- package/dist/src/core/furnace-apply-helpers.js +19 -16
- package/dist/src/core/furnace-apply-overwrite-warn.d.ts +8 -9
- package/dist/src/core/furnace-apply-overwrite-warn.js +8 -9
- package/dist/src/core/furnace-apply-undeploy-actions.d.ts +3 -4
- package/dist/src/core/furnace-apply-undeploy-actions.js +3 -4
- package/dist/src/core/furnace-apply.d.ts +5 -8
- package/dist/src/core/furnace-apply.js +19 -24
- package/dist/src/core/furnace-checksum-utils.d.ts +14 -0
- package/dist/src/core/furnace-checksum-utils.js +16 -0
- package/dist/src/core/furnace-config.d.ts +21 -30
- package/dist/src/core/furnace-config.js +32 -54
- package/dist/src/core/furnace-constants.d.ts +8 -0
- package/dist/src/core/furnace-constants.js +10 -2
- package/dist/src/core/furnace-css-fragments.d.ts +5 -5
- package/dist/src/core/furnace-css-fragments.js +5 -5
- package/dist/src/core/furnace-jsconfig.d.ts +11 -12
- package/dist/src/core/furnace-jsconfig.js +11 -12
- package/dist/src/core/furnace-marker.d.ts +7 -8
- package/dist/src/core/furnace-marker.js +7 -8
- package/dist/src/core/furnace-operation.d.ts +31 -0
- package/dist/src/core/furnace-operation.js +54 -17
- package/dist/src/core/furnace-precondition.d.ts +61 -0
- package/dist/src/core/furnace-precondition.js +67 -0
- package/dist/src/core/furnace-registration-remove.d.ts +5 -6
- package/dist/src/core/furnace-registration-remove.js +6 -7
- package/dist/src/core/furnace-registration-validate.d.ts +13 -0
- package/dist/src/core/furnace-registration-validate.js +20 -1
- package/dist/src/core/furnace-registration.d.ts +5 -6
- package/dist/src/core/furnace-registration.js +10 -12
- package/dist/src/core/furnace-rollback.js +7 -7
- package/dist/src/core/furnace-scanner.d.ts +1 -0
- package/dist/src/core/furnace-scanner.js +1 -2
- package/dist/src/core/furnace-stale-export.d.ts +10 -10
- package/dist/src/core/furnace-stale-export.js +10 -10
- package/dist/src/core/furnace-state-persist.d.ts +6 -8
- package/dist/src/core/furnace-state-persist.js +6 -8
- package/dist/src/core/furnace-validate-accessibility.d.ts +22 -0
- package/dist/src/core/furnace-validate-accessibility.js +310 -1
- package/dist/src/core/furnace-validate-compatibility.js +141 -1
- package/dist/src/core/furnace-validate-helpers.d.ts +5 -116
- package/dist/src/core/furnace-validate-helpers.js +0 -491
- package/dist/src/core/furnace-validate-registration.d.ts +7 -0
- package/dist/src/core/furnace-validate-registration.js +115 -41
- package/dist/src/core/furnace-validate.d.ts +16 -0
- package/dist/src/core/furnace-validate.js +188 -145
- package/dist/src/core/furnace-version-drift.d.ts +10 -11
- package/dist/src/core/furnace-version-drift.js +10 -11
- package/dist/src/core/git-base.d.ts +7 -9
- package/dist/src/core/git-base.js +7 -9
- package/dist/src/core/git-diff.d.ts +20 -9
- package/dist/src/core/git-diff.js +148 -63
- package/dist/src/core/git-file-ops.d.ts +19 -19
- package/dist/src/core/git-file-ops.js +19 -19
- package/dist/src/core/git-readonly-index.d.ts +53 -19
- package/dist/src/core/git-readonly-index.js +75 -31
- package/dist/src/core/git-status.d.ts +5 -6
- package/dist/src/core/git-status.js +5 -6
- package/dist/src/core/git.d.ts +9 -10
- package/dist/src/core/git.js +54 -70
- package/dist/src/core/license-headers.d.ts +17 -23
- package/dist/src/core/license-headers.js +17 -23
- package/dist/src/core/mach-build-artifacts.d.ts +9 -9
- package/dist/src/core/mach-build-artifacts.js +57 -19
- package/dist/src/core/mach-error-hints.js +42 -29
- package/dist/src/core/mach-known-noise-filter.d.ts +15 -16
- package/dist/src/core/mach-known-noise-filter.js +18 -20
- package/dist/src/core/mach-mozconfig.d.ts +14 -0
- package/dist/src/core/mach-mozconfig.js +30 -0
- package/dist/src/core/mach-resource-shim.d.ts +43 -58
- package/dist/src/core/mach-resource-shim.js +50 -67
- package/dist/src/core/mach.d.ts +37 -41
- package/dist/src/core/mach.js +50 -51
- package/dist/src/core/marionette-port.d.ts +36 -1
- package/dist/src/core/marionette-port.js +96 -31
- package/dist/src/core/marionette-preflight.d.ts +8 -12
- package/dist/src/core/marionette-preflight.js +86 -52
- package/dist/src/core/mochitest-server-port.d.ts +42 -0
- package/dist/src/core/mochitest-server-port.js +119 -0
- package/dist/src/core/module-resolution-preflight.d.ts +9 -11
- package/dist/src/core/module-resolution-preflight.js +9 -11
- package/dist/src/core/moz-manifest-helpers.d.ts +79 -0
- package/dist/src/core/moz-manifest-helpers.js +163 -0
- package/dist/src/core/{manifest-register.d.ts → moz-manifest-register.d.ts} +1 -1
- package/dist/src/core/{manifest-register.js → moz-manifest-register.js} +13 -28
- package/dist/src/core/{manifest-rules.d.ts → moz-manifest-rules.d.ts} +10 -1
- package/dist/src/core/{manifest-rules.js → moz-manifest-rules.js} +31 -24
- package/dist/src/core/{manifest-tokenizers.d.ts → moz-manifest-tokenizers.d.ts} +3 -5
- package/dist/src/core/{manifest-tokenizers.js → moz-manifest-tokenizers.js} +9 -12
- package/dist/src/core/ownership-table.d.ts +14 -16
- package/dist/src/core/ownership-table.js +14 -16
- package/dist/src/core/parser-fallback.d.ts +15 -1
- package/dist/src/core/parser-fallback.js +22 -3
- package/dist/src/core/patch-apply-fuzz.d.ts +10 -12
- package/dist/src/core/patch-apply-fuzz.js +15 -18
- package/dist/src/core/patch-apply.d.ts +13 -34
- package/dist/src/core/patch-apply.js +16 -76
- package/dist/src/core/patch-artifact-normalize.d.ts +13 -15
- package/dist/src/core/patch-artifact-normalize.js +13 -15
- package/dist/src/core/patch-export-metadata.d.ts +12 -2
- package/dist/src/core/patch-export-metadata.js +13 -4
- package/dist/src/core/patch-export-update.d.ts +13 -1
- package/dist/src/core/patch-export-update.js +25 -8
- package/dist/src/core/patch-export.d.ts +15 -8
- package/dist/src/core/patch-export.js +10 -11
- package/dist/src/core/patch-files.d.ts +5 -6
- package/dist/src/core/patch-files.js +5 -6
- package/dist/src/core/patch-identifier-suggest.d.ts +7 -12
- package/dist/src/core/patch-identifier-suggest.js +14 -19
- package/dist/src/core/patch-lint-binary.d.ts +51 -0
- package/dist/src/core/patch-lint-binary.js +39 -0
- package/dist/src/core/{lint-cache.d.ts → patch-lint-cache.d.ts} +5 -5
- package/dist/src/core/{lint-cache.js → patch-lint-cache.js} +21 -23
- package/dist/src/core/patch-lint-checkjs.d.ts +16 -16
- package/dist/src/core/patch-lint-checkjs.js +16 -16
- package/dist/src/core/patch-lint-chrome-jsdoc.d.ts +6 -9
- package/dist/src/core/patch-lint-chrome-jsdoc.js +10 -14
- package/dist/src/core/patch-lint-creators.d.ts +8 -8
- package/dist/src/core/patch-lint-creators.js +8 -8
- package/dist/src/core/patch-lint-cross.d.ts +17 -20
- package/dist/src/core/patch-lint-cross.js +16 -16
- package/dist/src/core/patch-lint-css.d.ts +3 -5
- package/dist/src/core/patch-lint-css.js +17 -22
- package/dist/src/core/patch-lint-diff-tag.d.ts +14 -16
- package/dist/src/core/patch-lint-diff-tag.js +14 -16
- package/dist/src/core/patch-lint-jsdoc.d.ts +7 -8
- package/dist/src/core/patch-lint-jsdoc.js +26 -19
- package/dist/src/core/patch-lint-mozbuild.js +20 -20
- package/dist/src/core/patch-lint-observer.d.ts +7 -7
- package/dist/src/core/patch-lint-observer.js +7 -7
- package/dist/src/core/patch-lint.d.ts +38 -29
- package/dist/src/core/patch-lint.js +89 -121
- package/dist/src/core/patch-lock.d.ts +1 -1
- package/dist/src/core/patch-lock.js +45 -9
- package/dist/src/core/patch-manifest-consistency.d.ts +2 -1
- package/dist/src/core/patch-manifest-consistency.js +25 -27
- package/dist/src/core/patch-manifest-io.js +14 -18
- package/dist/src/core/patch-manifest-resolve.d.ts +9 -12
- package/dist/src/core/patch-manifest-resolve.js +9 -12
- package/dist/src/core/patch-manifest-validate.d.ts +6 -1
- package/dist/src/core/patch-manifest-validate.js +25 -13
- package/dist/src/core/patch-parse.d.ts +24 -13
- package/dist/src/core/patch-parse.js +19 -14
- package/dist/src/core/patch-policy.d.ts +2 -2
- package/dist/src/core/patch-policy.js +2 -2
- package/dist/src/core/patch-registration-refs.d.ts +7 -8
- package/dist/src/core/patch-registration-refs.js +9 -9
- package/dist/src/core/process-cpu-time.d.ts +12 -0
- package/dist/src/core/process-cpu-time.js +52 -0
- package/dist/src/core/rebase-session.d.ts +38 -26
- package/dist/src/core/rebase-session.js +55 -28
- package/dist/src/core/register-browser-content.js +9 -74
- package/dist/src/core/{register-test-manifest.js → register-browser-test.js} +7 -42
- package/dist/src/core/register-module.js +10 -43
- package/dist/src/core/register-scaffold.d.ts +8 -8
- package/dist/src/core/register-scaffold.js +10 -10
- package/dist/src/core/register-shared-css.d.ts +9 -12
- package/dist/src/core/register-shared-css.js +17 -87
- package/dist/src/core/register-xpcshell-test.d.ts +6 -7
- package/dist/src/core/register-xpcshell-test.js +7 -8
- package/dist/src/core/shared-ftl.js +12 -4
- package/dist/src/core/state-file.d.ts +45 -0
- package/dist/src/core/state-file.js +34 -0
- package/dist/src/core/status-binary.d.ts +18 -11
- package/dist/src/core/status-binary.js +19 -12
- package/dist/src/core/status-classify.d.ts +30 -36
- package/dist/src/core/status-classify.js +21 -26
- package/dist/src/core/test-changed-prefs.d.ts +30 -0
- package/dist/src/core/test-changed-prefs.js +78 -0
- package/dist/src/core/test-harness-crash.d.ts +25 -63
- package/dist/src/core/test-harness-crash.js +121 -142
- package/dist/src/core/test-harness-signature.d.ts +18 -0
- package/dist/src/core/test-harness-signature.js +13 -0
- package/dist/src/core/test-path-scope.d.ts +12 -15
- package/dist/src/core/test-path-scope.js +15 -18
- package/dist/src/core/test-stale-check.d.ts +17 -17
- package/dist/src/core/test-stale-check.js +50 -43
- package/dist/src/core/test-stall-triage.d.ts +51 -0
- package/dist/src/core/test-stall-triage.js +126 -0
- package/dist/src/core/token-category.js +5 -7
- package/dist/src/core/token-coverage.js +9 -9
- package/dist/src/core/token-dark-mode.d.ts +9 -11
- package/dist/src/core/token-dark-mode.js +9 -11
- package/dist/src/core/token-docs.d.ts +2 -0
- package/dist/src/core/token-docs.js +2 -0
- package/dist/src/core/token-manager.d.ts +10 -2
- package/dist/src/core/token-manager.js +17 -8
- package/dist/src/core/token-scaffold.d.ts +7 -7
- package/dist/src/core/token-scaffold.js +7 -7
- package/dist/src/core/token-variant.d.ts +4 -4
- package/dist/src/core/token-variant.js +4 -4
- package/dist/src/core/toolchain-preflight.d.ts +20 -21
- package/dist/src/core/toolchain-preflight.js +28 -31
- package/dist/src/core/tree-guard.js +12 -2
- package/dist/src/core/tree-store.d.ts +41 -27
- package/dist/src/core/tree-store.js +63 -42
- package/dist/src/core/typecheck-shim.d.ts +23 -24
- package/dist/src/core/typecheck-shim.js +23 -24
- package/dist/src/core/typecheck.js +8 -8
- package/dist/src/core/wire-destroy.d.ts +3 -3
- package/dist/src/core/wire-destroy.js +7 -15
- package/dist/src/core/wire-dom-fragment.d.ts +9 -17
- package/dist/src/core/wire-dom-fragment.js +11 -44
- package/dist/src/core/wire-init.d.ts +2 -3
- package/dist/src/core/wire-init.js +8 -19
- package/dist/src/core/wire-subscript.d.ts +2 -3
- package/dist/src/core/wire-subscript.js +4 -13
- package/dist/src/core/wire-utils.d.ts +7 -8
- package/dist/src/core/wire-utils.js +7 -8
- package/dist/src/core/xpcshell-appdir.d.ts +38 -45
- package/dist/src/core/xpcshell-appdir.js +38 -45
- package/dist/src/errors/base.d.ts +37 -16
- package/dist/src/errors/base.js +37 -16
- package/dist/src/errors/build.d.ts +13 -1
- package/dist/src/errors/build.js +14 -2
- package/dist/src/errors/codes.d.ts +16 -0
- package/dist/src/errors/codes.js +16 -0
- package/dist/src/errors/furnace.d.ts +4 -4
- package/dist/src/errors/git.d.ts +6 -10
- package/dist/src/errors/git.js +6 -10
- package/dist/src/errors/patch.d.ts +7 -7
- package/dist/src/errors/patch.js +7 -7
- package/dist/src/errors/rebase.d.ts +4 -4
- package/dist/src/errors/rebase.js +4 -4
- package/dist/src/index.d.ts +7 -1
- package/dist/src/index.js +5 -0
- package/dist/src/types/commands/index.d.ts +2 -2
- package/dist/src/types/commands/options.d.ts +88 -70
- package/dist/src/types/commands/patches.d.ts +24 -34
- package/dist/src/types/commands/project.d.ts +5 -34
- package/dist/src/types/config.d.ts +25 -23
- package/dist/src/types/config.js +6 -1
- package/dist/src/types/furnace.d.ts +37 -13
- package/dist/src/types/furnace.js +19 -1
- package/dist/src/types/index.d.ts +3 -3
- package/dist/src/utils/build-info.d.ts +7 -8
- package/dist/src/utils/build-info.js +12 -11
- package/dist/src/utils/errors.d.ts +6 -8
- package/dist/src/utils/errors.js +6 -8
- package/dist/src/utils/logger.d.ts +27 -10
- package/dist/src/utils/logger.js +28 -16
- package/dist/src/utils/machine-output.d.ts +12 -0
- package/dist/src/utils/machine-output.js +33 -0
- package/dist/src/utils/options.d.ts +31 -14
- package/dist/src/utils/options.js +86 -30
- package/dist/src/utils/paths.d.ts +10 -8
- package/dist/src/utils/paths.js +10 -8
- package/dist/src/utils/platform.d.ts +0 -25
- package/dist/src/utils/platform.js +1 -42
- package/dist/src/utils/process-group.d.ts +9 -4
- package/dist/src/utils/process-group.js +19 -5
- package/dist/src/utils/process.d.ts +42 -7
- package/dist/src/utils/process.js +44 -17
- package/dist/src/utils/ps-duration.d.ts +31 -0
- package/dist/src/utils/ps-duration.js +70 -0
- package/dist/src/utils/regex.d.ts +9 -10
- package/dist/src/utils/regex.js +9 -10
- package/dist/src/utils/validation.d.ts +58 -28
- package/dist/src/utils/validation.js +60 -33
- package/package.json +2 -2
- package/dist/src/commands/doctor/post-rebase-audit.d.ts +0 -2
- package/dist/src/commands/doctor-furnace-manifest-sync.d.ts +0 -18
- package/dist/src/core/manifest-helpers.d.ts +0 -38
- package/dist/src/core/manifest-helpers.js +0 -120
- /package/dist/src/core/{lint-projection.d.ts → patch-lint-projection.d.ts} +0 -0
- /package/dist/src/core/{lint-projection.js → patch-lint-projection.js} +0 -0
- /package/dist/src/core/{register-test-manifest.d.ts → register-browser-test.d.ts} +0 -0
|
@@ -7,6 +7,7 @@ import { pathExists, readText } from '../utils/fs.js';
|
|
|
7
7
|
import { warn } from '../utils/logger.js';
|
|
8
8
|
import { escapeRegex, stripJsComments } from '../utils/regex.js';
|
|
9
9
|
import { getProjectPaths, loadConfig } from './config.js';
|
|
10
|
+
import { normalizeForChecksum } from './furnace-checksum-utils.js';
|
|
10
11
|
import { getFurnacePaths } from './furnace-config.js';
|
|
11
12
|
import { CUSTOM_ELEMENTS_JS, FTL_DIR, JAR_MN } from './furnace-constants.js';
|
|
12
13
|
import { expandCssFragments, listFragmentIncludes } from './furnace-css-fragments.js';
|
|
@@ -124,8 +125,12 @@ export async function checkRegistrationConsistency(root, name, config, ftlDir) {
|
|
|
124
125
|
}
|
|
125
126
|
}
|
|
126
127
|
const destContent = await readText(destPath);
|
|
127
|
-
|
|
128
|
-
|
|
128
|
+
// Same normalization the checksums written by apply use. These three
|
|
129
|
+
// comparisons hashed raw bytes, so on a CRLF checkout `furnace status`
|
|
130
|
+
// and `furnace validate` reported drift for files apply had just
|
|
131
|
+
// decided were identical.
|
|
132
|
+
const srcHash = createHash('sha256').update(normalizeForChecksum(srcContent)).digest('hex');
|
|
133
|
+
const destHash = createHash('sha256').update(normalizeForChecksum(destContent)).digest('hex');
|
|
129
134
|
if (srcHash !== destHash) {
|
|
130
135
|
status.driftedFiles.push(entry.name);
|
|
131
136
|
status.filesInSync = false;
|
|
@@ -150,8 +155,10 @@ export async function checkRegistrationConsistency(root, name, config, ftlDir) {
|
|
|
150
155
|
else {
|
|
151
156
|
const srcContent = await readText(ftlSrc);
|
|
152
157
|
const destContent = await readText(ftlDest);
|
|
153
|
-
const srcHash = createHash('sha256').update(srcContent).digest('hex');
|
|
154
|
-
const destHash = createHash('sha256')
|
|
158
|
+
const srcHash = createHash('sha256').update(normalizeForChecksum(srcContent)).digest('hex');
|
|
159
|
+
const destHash = createHash('sha256')
|
|
160
|
+
.update(normalizeForChecksum(destContent))
|
|
161
|
+
.digest('hex');
|
|
155
162
|
if (srcHash !== destHash) {
|
|
156
163
|
status.driftedFiles.push(ftlName);
|
|
157
164
|
status.filesInSync = false;
|
|
@@ -225,11 +232,9 @@ export async function validateJarMnEntries(root, config) {
|
|
|
225
232
|
}
|
|
226
233
|
}
|
|
227
234
|
// Stale registrations: lines pointing at component files that no longer
|
|
228
|
-
// exist in the workspace
|
|
229
|
-
//
|
|
230
|
-
//
|
|
231
|
-
// report: both validate --fix and doctor --repair-furnace reported
|
|
232
|
-
// success without pruning).
|
|
235
|
+
// exist in the workspace, left behind by a rename or delete. These break
|
|
236
|
+
// `mach build` at packaging ("File ... not found"), so they are errors and
|
|
237
|
+
// `--fix` prunes them.
|
|
233
238
|
const staleEntries = await findStaleJarMnEntries(engineDir, furnacePaths.customDir, Object.keys(config.custom));
|
|
234
239
|
for (const stale of staleEntries) {
|
|
235
240
|
issues.push({
|
|
@@ -261,47 +266,106 @@ const AUTO_DETECT_HOST_DIR = 'browser/base/content';
|
|
|
261
266
|
* `already`, so callers can merge them with the caller-configured set
|
|
262
267
|
* without producing double entries in warning output.
|
|
263
268
|
*
|
|
264
|
-
*
|
|
265
|
-
*
|
|
266
|
-
* `tokenHostDocuments
|
|
267
|
-
*
|
|
268
|
-
*
|
|
269
|
+
* This catches a fork that mounts a custom element from its own top-level
|
|
270
|
+
* chrome document (e.g. `mybrowser.xhtml`) without setting
|
|
271
|
+
* `tokenHostDocuments`: scanning only the stock `browser.xhtml` would miss
|
|
272
|
+
* the tokens CSS link in the ACTUAL host document and false-fire the
|
|
273
|
+
* warning.
|
|
269
274
|
*
|
|
270
275
|
* @param engineDir Absolute engine root.
|
|
271
276
|
* @param tagName Custom element tag the CSS belongs to.
|
|
272
277
|
* @param already Paths already in the scan set (POSIX, engine-relative).
|
|
273
278
|
*/
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
+
/**
|
|
280
|
+
* Per-run caches for work that is invariant across components.
|
|
281
|
+
*
|
|
282
|
+
* `validateAllComponents` walks every component, and re-parsing
|
|
283
|
+
* `fireforge.json` plus re-scanning every `.xhtml` under the chrome-document
|
|
284
|
+
* directory per component is one config parse and one full directory read
|
|
285
|
+
* PER COMPONENT, for work that depends only on the project and the engine.
|
|
286
|
+
*
|
|
287
|
+
* Keyed by root/engine dir and cleared by
|
|
288
|
+
* {@link resetRegistrationValidationCaches} at the start of each run, so a
|
|
289
|
+
* long-lived process (the test suite, `watch`) never serves a stale read.
|
|
290
|
+
*/
|
|
291
|
+
const tokensCssFileNameCache = new Map();
|
|
292
|
+
const chromeDocumentCache = new Map();
|
|
293
|
+
/**
|
|
294
|
+
* Whether a batch validation is in flight.
|
|
295
|
+
*
|
|
296
|
+
* The caches are consulted ONLY while this is set. Outside a batch — a direct
|
|
297
|
+
* `validateComponent` call from `furnace status`, from apply's consistency
|
|
298
|
+
* check, or from a test — every read goes to disk, so a caller that mutates
|
|
299
|
+
* the engine between calls can never be served a stale document.
|
|
300
|
+
*/
|
|
301
|
+
let batchInFlight = false;
|
|
302
|
+
/**
|
|
303
|
+
* Runs `body` with the per-run caches enabled, then clears them.
|
|
304
|
+
*
|
|
305
|
+
* @param body - The batch to run
|
|
306
|
+
* @returns Whatever `body` resolves to
|
|
307
|
+
*/
|
|
308
|
+
export async function withRegistrationValidationCache(body) {
|
|
309
|
+
const outer = batchInFlight;
|
|
310
|
+
batchInFlight = true;
|
|
279
311
|
try {
|
|
280
|
-
|
|
312
|
+
return await body();
|
|
281
313
|
}
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
314
|
+
finally {
|
|
315
|
+
batchInFlight = outer;
|
|
316
|
+
if (!outer) {
|
|
317
|
+
tokensCssFileNameCache.clear();
|
|
318
|
+
chromeDocumentCache.clear();
|
|
319
|
+
}
|
|
286
320
|
}
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
321
|
+
}
|
|
322
|
+
/**
|
|
323
|
+
* Reads every chrome document under the auto-detect directory once per run.
|
|
324
|
+
*
|
|
325
|
+
* @param engineDir - Absolute path to the engine checkout
|
|
326
|
+
* @returns Map of engine-relative document path to its content
|
|
327
|
+
*/
|
|
328
|
+
async function loadChromeDocuments(engineDir) {
|
|
329
|
+
const cached = batchInFlight ? chromeDocumentCache.get(engineDir) : undefined;
|
|
330
|
+
if (cached)
|
|
331
|
+
return cached;
|
|
332
|
+
const documents = new Map();
|
|
333
|
+
const contentDir = join(engineDir, AUTO_DETECT_HOST_DIR);
|
|
334
|
+
if (await pathExists(contentDir)) {
|
|
335
|
+
let entries;
|
|
297
336
|
try {
|
|
298
|
-
|
|
337
|
+
entries = await readdir(contentDir);
|
|
299
338
|
}
|
|
300
339
|
catch {
|
|
301
|
-
//
|
|
302
|
-
//
|
|
303
|
-
|
|
340
|
+
// No readable chrome-document directory means no documents reference
|
|
341
|
+
// the tag, which is the same verdict as an empty directory.
|
|
342
|
+
entries = [];
|
|
343
|
+
}
|
|
344
|
+
for (const entry of entries) {
|
|
345
|
+
if (!entry.endsWith('.xhtml'))
|
|
346
|
+
continue;
|
|
347
|
+
const rel = `${AUTO_DETECT_HOST_DIR}/${entry}`;
|
|
348
|
+
try {
|
|
349
|
+
documents.set(rel, await readText(join(contentDir, entry)));
|
|
350
|
+
}
|
|
351
|
+
catch {
|
|
352
|
+
// Unreadable document: treated as not referencing the tag.
|
|
353
|
+
}
|
|
304
354
|
}
|
|
355
|
+
}
|
|
356
|
+
if (batchInFlight)
|
|
357
|
+
chromeDocumentCache.set(engineDir, documents);
|
|
358
|
+
return documents;
|
|
359
|
+
}
|
|
360
|
+
async function autoDetectTokenHostDocuments(engineDir, tagName, already) {
|
|
361
|
+
// Reads the directory ONCE per run rather than once per component: only the
|
|
362
|
+
// tag being searched for differs between components.
|
|
363
|
+
const documents = await loadChromeDocuments(engineDir);
|
|
364
|
+
const alreadySet = new Set(already);
|
|
365
|
+
const detected = [];
|
|
366
|
+
for (const [relPath, content] of documents) {
|
|
367
|
+
if (alreadySet.has(relPath))
|
|
368
|
+
continue;
|
|
305
369
|
if (content.includes(tagName)) {
|
|
306
370
|
detected.push(relPath);
|
|
307
371
|
}
|
|
@@ -337,9 +401,19 @@ export async function validateTokenLink(componentDir, tagName, root, tokenPrefix
|
|
|
337
401
|
: DEFAULT_TOKEN_HOST_DOCUMENTS;
|
|
338
402
|
let tokensCssFile;
|
|
339
403
|
try {
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
404
|
+
// Cached per run: the filename depends on `binaryName` alone, so parsing
|
|
405
|
+
// fireforge.json once per token-using component was pure repetition.
|
|
406
|
+
const cachedName = batchInFlight ? tokensCssFileNameCache.get(root) : undefined;
|
|
407
|
+
if (cachedName !== undefined) {
|
|
408
|
+
tokensCssFile = cachedName;
|
|
409
|
+
}
|
|
410
|
+
else {
|
|
411
|
+
const forgeConfig = await loadConfig(root);
|
|
412
|
+
const segments = getTokensCssPath(forgeConfig.binaryName).split('/');
|
|
413
|
+
tokensCssFile = segments[segments.length - 1] ?? '';
|
|
414
|
+
if (batchInFlight)
|
|
415
|
+
tokensCssFileNameCache.set(root, tokensCssFile);
|
|
416
|
+
}
|
|
343
417
|
}
|
|
344
418
|
catch (error) {
|
|
345
419
|
const reason = toError(error).message;
|
|
@@ -23,3 +23,19 @@ export declare function validateComponent(componentDir: string, tagName: string,
|
|
|
23
23
|
* @returns Map of component name to its validation issues
|
|
24
24
|
*/
|
|
25
25
|
export declare function validateAllComponents(root: string): Promise<Map<string, ValidationIssue[]>>;
|
|
26
|
+
/**
|
|
27
|
+
* Flags engine-side files that a previous deploy of `tagName` left behind
|
|
28
|
+
* after their workspace source was renamed or removed.
|
|
29
|
+
*
|
|
30
|
+
* Detection keys on the furnace state file: every `appliedChecksums` entry
|
|
31
|
+
* under `custom/<tagName>/` whose workspace source no longer exists but whose
|
|
32
|
+
* engine target is still present is an orphan. The next deploy prunes it, but
|
|
33
|
+
* until then jar.mn and the deployed directory disagree with the workspace,
|
|
34
|
+
* and a re-export could capture the stale state into a patch.
|
|
35
|
+
*
|
|
36
|
+
* Custom components only: override undeploys restore the upstream baseline
|
|
37
|
+
* rather than deleting files, so "orphan" has no meaning there.
|
|
38
|
+
*/
|
|
39
|
+
export declare function findOrphanedEngineFiles(root: string, config: FurnaceConfig, tagName: string, state: {
|
|
40
|
+
appliedChecksums?: Record<string, string>;
|
|
41
|
+
}, ftlDir: string): Promise<ValidationIssue[]>;
|
|
@@ -4,13 +4,15 @@ import { join } from 'node:path';
|
|
|
4
4
|
import { toError } from '../utils/errors.js';
|
|
5
5
|
import { pathExists } from '../utils/fs.js';
|
|
6
6
|
import { getProjectPaths, loadConfig } from './config.js';
|
|
7
|
+
import { extractComponentChecksums } from './furnace-checksum-utils.js';
|
|
7
8
|
import { getFurnacePaths, loadFurnaceConfig, loadFurnaceState } from './furnace-config.js';
|
|
8
9
|
import { resolveFtlDir, xpcshellTestParentDir } from './furnace-constants.js';
|
|
9
10
|
import { validateCssFragments } from './furnace-css-fragments.js';
|
|
10
11
|
import { detectComposesCycles, validateComposesReferences } from './furnace-graph-utils.js';
|
|
11
12
|
import { findJsconfigPathsDrift } from './furnace-jsconfig.js';
|
|
12
13
|
import { validateAccessibility, validateCompatibility, validateJarMnEntries, validateRegistrationPatterns, validateStructure, validateTokenLink, } from './furnace-validate-checks.js';
|
|
13
|
-
import {
|
|
14
|
+
import { createIssue } from './furnace-validate-helpers.js';
|
|
15
|
+
import { withRegistrationValidationCache } from './furnace-validate-registration.js';
|
|
14
16
|
import { findOverrideBaseVersionDrift, } from './furnace-version-drift.js';
|
|
15
17
|
function buildOverrideVersionDriftIssues(config, currentVersion, tagName) {
|
|
16
18
|
return findOverrideBaseVersionDrift(config, currentVersion)
|
|
@@ -59,9 +61,8 @@ export async function validateComponent(componentDir, tagName, type, config, roo
|
|
|
59
61
|
if (root) {
|
|
60
62
|
issues.push(...(await validateTokenLink(componentDir, tagName, root, config?.tokenPrefix, config?.tokenHostDocuments)));
|
|
61
63
|
}
|
|
62
|
-
// CSS fragment checks
|
|
63
|
-
//
|
|
64
|
-
// refreshes.
|
|
64
|
+
// CSS fragment checks: missing fragment files are structural errors;
|
|
65
|
+
// stale deployed expansions are drift the next deploy refreshes.
|
|
65
66
|
if (type === 'custom') {
|
|
66
67
|
const furnacePaths = getFurnacePaths(root ?? join(componentDir, '..', '..', '..'));
|
|
67
68
|
const engineTargetDir = root && config?.custom[tagName]
|
|
@@ -69,11 +70,10 @@ export async function validateComponent(componentDir, tagName, type, config, roo
|
|
|
69
70
|
: undefined;
|
|
70
71
|
issues.push(...(await validateCssFragments(componentDir, tagName, furnacePaths.sharedDir, engineTargetDir)));
|
|
71
72
|
}
|
|
72
|
-
// Engine-side orphan detection
|
|
73
|
-
//
|
|
74
|
-
//
|
|
75
|
-
//
|
|
76
|
-
// later re-export.
|
|
73
|
+
// Engine-side orphan detection: files a previous deploy placed in the
|
|
74
|
+
// engine whose workspace source has since been renamed or deleted.
|
|
75
|
+
// Surfaces as drift even when every current workspace file is in sync,
|
|
76
|
+
// which is the gap that lets stale jar.mn lines reach a later re-export.
|
|
77
77
|
if (root && config && type === 'custom') {
|
|
78
78
|
const state = await loadFurnaceState(root);
|
|
79
79
|
issues.push(...(await findOrphanedEngineFiles(root, config, tagName, state, resolveFtlDir(config.ftlBasePath))));
|
|
@@ -102,160 +102,165 @@ export async function validateComponent(componentDir, tagName, type, config, roo
|
|
|
102
102
|
* @returns Map of component name to its validation issues
|
|
103
103
|
*/
|
|
104
104
|
export async function validateAllComponents(root) {
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
//
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
105
|
+
// Wrapped so the config parse and the chrome-document scan happen once for
|
|
106
|
+
// the whole batch instead of once per component. The caches are inert
|
|
107
|
+
// outside this window, so a direct `validateComponent` caller is never
|
|
108
|
+
// served a stale read.
|
|
109
|
+
return await withRegistrationValidationCache(async () => {
|
|
110
|
+
const config = await loadFurnaceConfig(root);
|
|
111
|
+
const furnacePaths = getFurnacePaths(root);
|
|
112
|
+
const results = new Map();
|
|
113
|
+
// Validate composition graph integrity (dangling references and cycles)
|
|
114
|
+
try {
|
|
115
|
+
validateComposesReferences(config.stock, config.overrides, config.custom);
|
|
116
|
+
}
|
|
117
|
+
catch (err) {
|
|
118
|
+
const message = toError(err).message;
|
|
119
|
+
// Attribute the issue to the first custom component with a bad composes reference
|
|
120
|
+
for (const [name, cfg] of Object.entries(config.custom)) {
|
|
121
|
+
if (cfg.composes) {
|
|
122
|
+
const existing = results.get(name) ?? [];
|
|
123
|
+
existing.push({
|
|
124
|
+
component: name,
|
|
125
|
+
severity: 'error',
|
|
126
|
+
check: 'composes-dangling-reference',
|
|
127
|
+
message,
|
|
128
|
+
});
|
|
129
|
+
results.set(name, existing);
|
|
130
|
+
break;
|
|
131
|
+
}
|
|
126
132
|
}
|
|
127
133
|
}
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
134
|
+
try {
|
|
135
|
+
detectComposesCycles(config.custom);
|
|
136
|
+
}
|
|
137
|
+
catch (err) {
|
|
138
|
+
const message = toError(err).message;
|
|
139
|
+
// Attribute the cycle issue to the first custom component in the cycle
|
|
140
|
+
for (const name of Object.keys(config.custom)) {
|
|
141
|
+
if (config.custom[name]?.composes) {
|
|
142
|
+
const existing = results.get(name) ?? [];
|
|
143
|
+
existing.push({
|
|
144
|
+
component: name,
|
|
145
|
+
severity: 'error',
|
|
146
|
+
check: 'composes-cycle',
|
|
147
|
+
message,
|
|
148
|
+
});
|
|
149
|
+
results.set(name, existing);
|
|
150
|
+
break;
|
|
151
|
+
}
|
|
146
152
|
}
|
|
147
153
|
}
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
154
|
+
// Override components
|
|
155
|
+
for (const name of Object.keys(config.overrides)) {
|
|
156
|
+
const componentDir = join(furnacePaths.overridesDir, name);
|
|
157
|
+
if (!(await pathExists(componentDir))) {
|
|
158
|
+
results.set(name, [
|
|
159
|
+
{
|
|
160
|
+
component: name,
|
|
161
|
+
severity: 'error',
|
|
162
|
+
check: 'missing-component-dir',
|
|
163
|
+
message: `Component directory not found: components/overrides/${name}`,
|
|
164
|
+
},
|
|
165
|
+
]);
|
|
166
|
+
continue;
|
|
167
|
+
}
|
|
168
|
+
const issues = await validateComponent(componentDir, name, 'override', config, root);
|
|
169
|
+
results.set(name, issues);
|
|
162
170
|
}
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
171
|
+
// Custom components
|
|
172
|
+
for (const name of Object.keys(config.custom)) {
|
|
173
|
+
const componentDir = join(furnacePaths.customDir, name);
|
|
174
|
+
if (!(await pathExists(componentDir))) {
|
|
175
|
+
results.set(name, [
|
|
176
|
+
{
|
|
177
|
+
component: name,
|
|
178
|
+
severity: 'error',
|
|
179
|
+
check: 'missing-component-dir',
|
|
180
|
+
message: `Component directory not found: components/custom/${name}`,
|
|
181
|
+
},
|
|
182
|
+
]);
|
|
183
|
+
continue;
|
|
184
|
+
}
|
|
185
|
+
// Pass root so that per-component token link validation runs.
|
|
186
|
+
// Skip registration/jar.mn checks inside validateComponent — the aggregate
|
|
187
|
+
// validators below run them exactly once across all components, which both
|
|
188
|
+
// surfaces cross-component issues and avoids double-counting.
|
|
189
|
+
const issues = await validateComponent(componentDir, name, 'custom', config, root, {
|
|
190
|
+
skipAggregateChecks: true,
|
|
191
|
+
});
|
|
192
|
+
results.set(name, issues);
|
|
179
193
|
}
|
|
180
|
-
//
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
// surfaces cross-component issues and avoids double-counting.
|
|
184
|
-
const issues = await validateComponent(componentDir, name, 'custom', config, root, {
|
|
185
|
-
skipAggregateChecks: true,
|
|
186
|
-
});
|
|
187
|
-
results.set(name, issues);
|
|
188
|
-
}
|
|
189
|
-
// Registration pattern validation (customElements.js Pattern A vs B)
|
|
190
|
-
const registrationIssues = await validateRegistrationPatterns(root, config);
|
|
191
|
-
for (const issue of registrationIssues) {
|
|
192
|
-
const existing = results.get(issue.component) ?? [];
|
|
193
|
-
existing.push(issue);
|
|
194
|
-
results.set(issue.component, existing);
|
|
195
|
-
}
|
|
196
|
-
// jar.mn entry validation
|
|
197
|
-
const jarMnIssues = await validateJarMnEntries(root, config);
|
|
198
|
-
for (const issue of jarMnIssues) {
|
|
199
|
-
const existing = results.get(issue.component) ?? [];
|
|
200
|
-
existing.push(issue);
|
|
201
|
-
results.set(issue.component, existing);
|
|
202
|
-
}
|
|
203
|
-
// 2026-04-24 eval Finding 5: orphan xpcshell scaffold detection.
|
|
204
|
-
// `furnace create --with-tests --xpcshell` scaffolds a test directory
|
|
205
|
-
// at `browser/base/content/test/<binary>-xpcshell/<name>/`, and prior
|
|
206
|
-
// `furnace remove` + `furnace rename` flows did not touch that tree.
|
|
207
|
-
// A leftover scaffold whose `<name>` is not in furnace.json is almost
|
|
208
|
-
// always the aftermath of one of those incomplete flows; flag it as
|
|
209
|
-
// an `orphan-xpcshell-scaffold` error so operators know to delete or
|
|
210
|
-
// re-create the scaffold instead of discovering the mismatch only at
|
|
211
|
-
// test run time. Missing engine or missing scaffold parent directory
|
|
212
|
-
// both degrade silently — this check never introduces noise on a
|
|
213
|
-
// project that never used xpcshell scaffolding.
|
|
214
|
-
try {
|
|
215
|
-
const orphanIssues = await findOrphanXpcshellScaffolds(root, config);
|
|
216
|
-
for (const issue of orphanIssues) {
|
|
194
|
+
// Registration pattern validation (customElements.js Pattern A vs B)
|
|
195
|
+
const registrationIssues = await validateRegistrationPatterns(root, config);
|
|
196
|
+
for (const issue of registrationIssues) {
|
|
217
197
|
const existing = results.get(issue.component) ?? [];
|
|
218
198
|
existing.push(issue);
|
|
219
199
|
results.set(issue.component, existing);
|
|
220
200
|
}
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
201
|
+
// jar.mn entry validation
|
|
202
|
+
const jarMnIssues = await validateJarMnEntries(root, config);
|
|
203
|
+
for (const issue of jarMnIssues) {
|
|
204
|
+
const existing = results.get(issue.component) ?? [];
|
|
205
|
+
existing.push(issue);
|
|
206
|
+
results.set(issue.component, existing);
|
|
207
|
+
}
|
|
208
|
+
// Orphan xpcshell scaffold detection.
|
|
209
|
+
// `furnace create --with-tests --xpcshell` scaffolds a test directory at
|
|
210
|
+
// `browser/base/content/test/<binary>-xpcshell/<name>/`. A leftover
|
|
211
|
+
// scaffold whose `<name>` is not in furnace.json is almost always the
|
|
212
|
+
// aftermath of an incomplete `furnace remove` or `rename`; flag it as an
|
|
213
|
+
// `orphan-xpcshell-scaffold` error so operators delete or re-create the
|
|
214
|
+
// scaffold instead of discovering the mismatch at test run time. A
|
|
215
|
+
// missing engine or scaffold parent directory degrades silently, so this
|
|
216
|
+
// check never adds noise on a project that never used xpcshell
|
|
217
|
+
// scaffolding.
|
|
233
218
|
try {
|
|
234
|
-
const
|
|
235
|
-
|
|
236
|
-
const detail = [
|
|
237
|
-
...drift.added.map((key) => `missing: ${key}`),
|
|
238
|
-
...drift.updated.map((key) => `stale: ${key}`),
|
|
239
|
-
...drift.pruned.map((key) => `orphaned: ${key}`),
|
|
240
|
-
].join('; ');
|
|
241
|
-
const issue = {
|
|
242
|
-
component: 'furnace',
|
|
243
|
-
severity: 'warning',
|
|
244
|
-
check: 'jsconfig-paths-drift',
|
|
245
|
-
message: `${config.typecheckJsconfig} chrome-module paths are out of sync with the workspace (${detail}). ` +
|
|
246
|
-
'Run "fireforge furnace deploy" to update them.',
|
|
247
|
-
};
|
|
219
|
+
const orphanIssues = await findOrphanXpcshellScaffolds(root, config);
|
|
220
|
+
for (const issue of orphanIssues) {
|
|
248
221
|
const existing = results.get(issue.component) ?? [];
|
|
249
222
|
existing.push(issue);
|
|
250
223
|
results.set(issue.component, existing);
|
|
251
224
|
}
|
|
252
225
|
}
|
|
253
226
|
catch {
|
|
254
|
-
//
|
|
255
|
-
//
|
|
227
|
+
// Validation degrades gracefully — the absence of an engine
|
|
228
|
+
// directory, permission denial reading the scaffold tree, or any
|
|
229
|
+
// other transient fs issue should never cascade into false
|
|
230
|
+
// "orphan" reports.
|
|
256
231
|
}
|
|
257
|
-
|
|
258
|
-
|
|
232
|
+
// jsconfig chrome-module paths drift: when `typecheckJsconfig` is
|
|
233
|
+
// configured, deploy maintains a paths mapping per deployed module file;
|
|
234
|
+
// missing or stale entries mean typed cross-module imports are silently
|
|
235
|
+
// degrading to `any` in the consumer's typecheck.
|
|
236
|
+
if (config.typecheckJsconfig) {
|
|
237
|
+
try {
|
|
238
|
+
const drift = await findJsconfigPathsDrift(root, config);
|
|
239
|
+
if (drift.changed) {
|
|
240
|
+
const detail = [
|
|
241
|
+
...drift.added.map((key) => `missing: ${key}`),
|
|
242
|
+
...drift.updated.map((key) => `stale: ${key}`),
|
|
243
|
+
...drift.pruned.map((key) => `orphaned: ${key}`),
|
|
244
|
+
].join('; ');
|
|
245
|
+
const issue = {
|
|
246
|
+
component: 'furnace',
|
|
247
|
+
severity: 'warning',
|
|
248
|
+
check: 'jsconfig-paths-drift',
|
|
249
|
+
message: `${config.typecheckJsconfig} chrome-module paths are out of sync with the workspace (${detail}). ` +
|
|
250
|
+
'Run "fireforge furnace deploy" to update them.',
|
|
251
|
+
};
|
|
252
|
+
const existing = results.get(issue.component) ?? [];
|
|
253
|
+
existing.push(issue);
|
|
254
|
+
results.set(issue.component, existing);
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
catch {
|
|
258
|
+
// Drift detection must not break validation when the jsconfig is
|
|
259
|
+
// missing or unparsable — deploy reports those cases with guidance.
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
return results;
|
|
263
|
+
});
|
|
259
264
|
}
|
|
260
265
|
/**
|
|
261
266
|
* Scans the per-binary xpcshell scaffold directory for entries whose
|
|
@@ -300,3 +305,41 @@ async function findOrphanXpcshellScaffolds(root, config) {
|
|
|
300
305
|
}
|
|
301
306
|
return issues;
|
|
302
307
|
}
|
|
308
|
+
/**
|
|
309
|
+
* Flags engine-side files that a previous deploy of `tagName` left behind
|
|
310
|
+
* after their workspace source was renamed or removed.
|
|
311
|
+
*
|
|
312
|
+
* Detection keys on the furnace state file: every `appliedChecksums` entry
|
|
313
|
+
* under `custom/<tagName>/` whose workspace source no longer exists but whose
|
|
314
|
+
* engine target is still present is an orphan. The next deploy prunes it, but
|
|
315
|
+
* until then jar.mn and the deployed directory disagree with the workspace,
|
|
316
|
+
* and a re-export could capture the stale state into a patch.
|
|
317
|
+
*
|
|
318
|
+
* Custom components only: override undeploys restore the upstream baseline
|
|
319
|
+
* rather than deleting files, so "orphan" has no meaning there.
|
|
320
|
+
*/
|
|
321
|
+
export async function findOrphanedEngineFiles(root, config, tagName, state, ftlDir) {
|
|
322
|
+
const customConfig = config.custom[tagName];
|
|
323
|
+
if (!customConfig)
|
|
324
|
+
return [];
|
|
325
|
+
const previous = extractComponentChecksums(state.appliedChecksums, 'custom', tagName);
|
|
326
|
+
const fileNames = Object.keys(previous);
|
|
327
|
+
if (fileNames.length === 0)
|
|
328
|
+
return [];
|
|
329
|
+
const { engine: engineDir, componentsDir } = getProjectPaths(root);
|
|
330
|
+
const componentDir = join(componentsDir, 'custom', tagName);
|
|
331
|
+
const issues = [];
|
|
332
|
+
for (const fileName of fileNames) {
|
|
333
|
+
if (await pathExists(join(componentDir, fileName)))
|
|
334
|
+
continue;
|
|
335
|
+
const enginePath = fileName.endsWith('.ftl')
|
|
336
|
+
? join(engineDir, ftlDir, fileName)
|
|
337
|
+
: join(engineDir, customConfig.targetPath, fileName);
|
|
338
|
+
if (!(await pathExists(enginePath)))
|
|
339
|
+
continue;
|
|
340
|
+
issues.push(createIssue(tagName, 'warning', 'orphaned-engine-file', `Engine file ${fileName} was deployed by a previous apply but its workspace source ` +
|
|
341
|
+
`is gone (renamed or deleted). The deployed copy${customConfig.register ? ' and any stale jar.mn entry' : ''} ` +
|
|
342
|
+
`will linger until the next deploy prunes it. Run "fireforge furnace deploy ${tagName}".`));
|
|
343
|
+
}
|
|
344
|
+
return issues;
|
|
345
|
+
}
|