@hominis/fireforge 0.49.2 → 0.51.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 +87 -1
- package/README.md +1 -1
- package/dist/bin/fireforge.js +6 -0
- package/dist/build-info.json +4 -4
- package/dist/src/commands/build-prelock.d.ts +20 -0
- package/dist/src/commands/build-prelock.js +50 -0
- package/dist/src/commands/build.d.ts +3 -1
- package/dist/src/commands/build.js +13 -6
- package/dist/src/commands/check-report.d.ts +41 -0
- package/dist/src/commands/check-report.js +91 -0
- package/dist/src/commands/check-run.d.ts +33 -0
- package/dist/src/commands/check-run.js +112 -0
- package/dist/src/commands/check-steps.d.ts +75 -0
- package/dist/src/commands/check-steps.js +200 -0
- package/dist/src/commands/check.d.ts +32 -0
- package/dist/src/commands/check.js +160 -0
- package/dist/src/commands/config.js +5 -6
- package/dist/src/commands/declarations-report.d.ts +43 -0
- package/dist/src/commands/declarations-report.js +76 -0
- package/dist/src/commands/doctor-engine-eslint.js +6 -1
- package/dist/src/commands/doctor-source-pin.js +4 -1
- package/dist/src/commands/export-adopt-check.d.ts +38 -0
- package/dist/src/commands/export-adopt-check.js +98 -0
- package/dist/src/commands/export-flow.js +29 -14
- package/dist/src/commands/export-placement-gate.d.ts +6 -2
- package/dist/src/commands/export-placement-gate.js +8 -0
- package/dist/src/commands/export-shared.d.ts +2 -1
- package/dist/src/commands/export-staged-registration.d.ts +46 -0
- package/dist/src/commands/export-staged-registration.js +91 -0
- package/dist/src/commands/forward-import-remedy.d.ts +32 -0
- package/dist/src/commands/forward-import-remedy.js +63 -0
- package/dist/src/commands/furnace/apply.js +3 -3
- package/dist/src/commands/furnace/chrome-doc-remove.d.ts +2 -1
- package/dist/src/commands/furnace/chrome-doc-remove.js +2 -2
- package/dist/src/commands/furnace/chrome-doc.d.ts +2 -1
- package/dist/src/commands/furnace/chrome-doc.js +2 -2
- package/dist/src/commands/furnace/create.js +2 -2
- package/dist/src/commands/furnace/deploy-named.d.ts +48 -0
- package/dist/src/commands/furnace/deploy-named.js +107 -0
- package/dist/src/commands/furnace/deploy.d.ts +3 -2
- package/dist/src/commands/furnace/deploy.js +50 -86
- package/dist/src/commands/furnace/diff.js +26 -3
- package/dist/src/commands/furnace/index.js +66 -41
- package/dist/src/commands/furnace/init.js +13 -6
- package/dist/src/commands/furnace/override.js +4 -2
- package/dist/src/commands/furnace/preview.js +4 -3
- package/dist/src/commands/furnace/refresh.js +2 -2
- package/dist/src/commands/furnace/remove.js +4 -3
- package/dist/src/commands/furnace/rename-dry-run.d.ts +29 -0
- package/dist/src/commands/furnace/rename-dry-run.js +127 -0
- package/dist/src/commands/furnace/rename-helpers.d.ts +7 -0
- package/dist/src/commands/furnace/rename-helpers.js +15 -1
- package/dist/src/commands/furnace/rename-registrations.d.ts +41 -0
- package/dist/src/commands/furnace/rename-registrations.js +98 -0
- package/dist/src/commands/furnace/rename.d.ts +2 -1
- package/dist/src/commands/furnace/rename.js +28 -66
- package/dist/src/commands/furnace/scan.d.ts +9 -4
- package/dist/src/commands/furnace/scan.js +11 -9
- package/dist/src/commands/furnace/sync.js +3 -2
- package/dist/src/commands/furnace/validate-report.d.ts +45 -0
- package/dist/src/commands/furnace/validate-report.js +91 -0
- package/dist/src/commands/furnace/validate.d.ts +1 -1
- package/dist/src/commands/furnace/validate.js +151 -113
- package/dist/src/commands/furnace/validation-output.js +14 -3
- package/dist/src/commands/lint-per-patch.js +36 -61
- package/dist/src/commands/lint-per-run-checkjs.js +2 -2
- package/dist/src/commands/lint-report.d.ts +8 -4
- package/dist/src/commands/lint-report.js +20 -5
- package/dist/src/commands/lint.js +15 -34
- package/dist/src/commands/manifest.js +4 -0
- package/dist/src/commands/park.d.ts +22 -0
- package/dist/src/commands/park.js +232 -0
- package/dist/src/commands/patch/delete-gap-notice.js +3 -1
- package/dist/src/commands/patch/delete.d.ts +1 -1
- package/dist/src/commands/patch/delete.js +24 -104
- package/dist/src/commands/patch/index.d.ts +3 -3
- package/dist/src/commands/patch/index.js +10 -4
- package/dist/src/commands/patch/lint-ignore-from.d.ts +44 -0
- package/dist/src/commands/patch/lint-ignore-from.js +142 -0
- package/dist/src/commands/patch/lint-ignore.d.ts +5 -1
- package/dist/src/commands/patch/lint-ignore.js +78 -31
- package/dist/src/commands/patch/move-files-create.js +34 -18
- package/dist/src/commands/patch/move-files-into.js +15 -7
- package/dist/src/commands/patch/move-files.js +6 -2
- package/dist/src/commands/patch/removal-created-files.d.ts +48 -0
- package/dist/src/commands/patch/removal-created-files.js +83 -0
- package/dist/src/commands/patch/removal-dependents.d.ts +63 -0
- package/dist/src/commands/patch/removal-dependents.js +133 -0
- package/dist/src/commands/patch/rename.js +20 -1
- package/dist/src/commands/patch/reserve.d.ts +33 -0
- package/dist/src/commands/patch/reserve.js +152 -0
- package/dist/src/commands/patch/retire.d.ts +34 -0
- package/dist/src/commands/patch/retire.js +133 -0
- package/dist/src/commands/patch/split-plan.d.ts +17 -8
- package/dist/src/commands/patch/split-plan.js +60 -28
- package/dist/src/commands/patch/split-staged.d.ts +108 -0
- package/dist/src/commands/patch/split-staged.js +202 -0
- package/dist/src/commands/patch/split.d.ts +5 -0
- package/dist/src/commands/patch/split.js +62 -17
- package/dist/src/commands/patch/stage.d.ts +34 -0
- package/dist/src/commands/patch/stage.js +153 -0
- package/dist/src/commands/patch/staged-dependency-batch.d.ts +48 -0
- package/dist/src/commands/patch/staged-dependency-batch.js +176 -0
- package/dist/src/commands/patch/staged-dependency-entries.d.ts +36 -0
- package/dist/src/commands/patch/staged-dependency-entries.js +52 -0
- package/dist/src/commands/patch/staged-dependency-from.d.ts +14 -0
- package/dist/src/commands/patch/staged-dependency-from.js +108 -0
- package/dist/src/commands/patch/staged-dependency-remove.d.ts +31 -0
- package/dist/src/commands/patch/staged-dependency-remove.js +80 -0
- package/dist/src/commands/patch/staged-dependency.js +54 -139
- package/dist/src/commands/re-export-adjacent-registrations.d.ts +20 -0
- package/dist/src/commands/re-export-adjacent-registrations.js +75 -0
- package/dist/src/commands/re-export-adjacent.d.ts +50 -2
- package/dist/src/commands/re-export-adjacent.js +160 -40
- package/dist/src/commands/re-export-bulk-scan.d.ts +2 -1
- package/dist/src/commands/re-export-bulk-scan.js +22 -7
- package/dist/src/commands/re-export-drift.d.ts +36 -8
- package/dist/src/commands/re-export-drift.js +73 -49
- package/dist/src/commands/re-export-files.js +11 -8
- package/dist/src/commands/re-export-hunks.d.ts +35 -0
- package/dist/src/commands/re-export-hunks.js +220 -0
- package/dist/src/commands/re-export-lint.d.ts +2 -1
- package/dist/src/commands/re-export-lint.js +23 -10
- package/dist/src/commands/re-export-options.js +74 -6
- package/dist/src/commands/re-export-preflight.d.ts +23 -0
- package/dist/src/commands/re-export-preflight.js +160 -0
- package/dist/src/commands/re-export-purity-scope.d.ts +18 -0
- package/dist/src/commands/re-export-purity-scope.js +131 -0
- package/dist/src/commands/re-export-register.js +56 -17
- package/dist/src/commands/re-export-removed.d.ts +13 -2
- package/dist/src/commands/re-export-removed.js +57 -12
- package/dist/src/commands/re-export-scan-owner.d.ts +44 -0
- package/dist/src/commands/re-export-scan-owner.js +116 -0
- package/dist/src/commands/re-export-scan.d.ts +19 -9
- package/dist/src/commands/re-export-scan.js +60 -24
- package/dist/src/commands/re-export-single.js +122 -46
- package/dist/src/commands/re-export-stale-registrations.d.ts +18 -0
- package/dist/src/commands/re-export-stale-registrations.js +62 -0
- package/dist/src/commands/re-export-summary.d.ts +28 -0
- package/dist/src/commands/re-export-summary.js +36 -0
- package/dist/src/commands/re-export.js +71 -57
- package/dist/src/commands/rebase/index.js +17 -17
- package/dist/src/commands/run.js +16 -2
- package/dist/src/commands/status-check.d.ts +55 -16
- package/dist/src/commands/status-check.js +92 -37
- package/dist/src/commands/status-json.d.ts +22 -9
- package/dist/src/commands/status-json.js +47 -32
- package/dist/src/commands/status-output.js +3 -1
- package/dist/src/commands/status-scope.d.ts +37 -0
- package/dist/src/commands/status-scope.js +54 -0
- package/dist/src/commands/status.js +66 -23
- package/dist/src/commands/test-browser-preflight.js +19 -3
- package/dist/src/commands/test-build-furnace.d.ts +22 -0
- package/dist/src/commands/test-build-furnace.js +54 -0
- package/dist/src/commands/test-build-phase.js +64 -41
- package/dist/src/commands/test-checkjs.js +10 -2
- package/dist/src/commands/test-diagnose.js +7 -0
- package/dist/src/commands/test-dispatch.d.ts +39 -0
- package/dist/src/commands/test-dispatch.js +211 -0
- package/dist/src/commands/test-furnace-reach.d.ts +37 -0
- package/dist/src/commands/test-furnace-reach.js +132 -0
- package/dist/src/commands/test-modes.d.ts +16 -1
- package/dist/src/commands/test-modes.js +24 -1
- package/dist/src/commands/test-multi-verdict.d.ts +61 -0
- package/dist/src/commands/test-multi-verdict.js +111 -0
- package/dist/src/commands/test-orchestrate.d.ts +52 -0
- package/dist/src/commands/test-orchestrate.js +240 -0
- package/dist/src/commands/test-perf-scope.d.ts +50 -0
- package/dist/src/commands/test-perf-scope.js +138 -0
- package/dist/src/commands/test-prelock.d.ts +51 -0
- package/dist/src/commands/test-prelock.js +273 -0
- package/dist/src/commands/test-register.js +69 -10
- package/dist/src/commands/test-results.d.ts +62 -0
- package/dist/src/commands/test-results.js +62 -0
- package/dist/src/commands/test-run.d.ts +13 -55
- package/dist/src/commands/test-run.js +74 -99
- package/dist/src/commands/test-shards.d.ts +110 -0
- package/dist/src/commands/test-shards.js +255 -0
- package/dist/src/commands/test-stale-gate.d.ts +5 -1
- package/dist/src/commands/test-stale-gate.js +60 -28
- package/dist/src/commands/test-verdict.d.ts +11 -1
- package/dist/src/commands/test-verdict.js +28 -1
- package/dist/src/commands/test.d.ts +6 -1
- package/dist/src/commands/test.js +120 -124
- package/dist/src/commands/token-lint.d.ts +14 -0
- package/dist/src/commands/token-lint.js +151 -0
- package/dist/src/commands/token.js +10 -0
- package/dist/src/commands/verify-scope.d.ts +28 -0
- package/dist/src/commands/verify-scope.js +67 -0
- package/dist/src/commands/verify.d.ts +10 -2
- package/dist/src/commands/verify.js +67 -36
- package/dist/src/core/build-baseline-types.d.ts +46 -0
- package/dist/src/core/build-baseline-validate.js +19 -0
- package/dist/src/core/build-baseline.d.ts +5 -1
- package/dist/src/core/build-baseline.js +3 -1
- package/dist/src/core/build-overwrite-guard.d.ts +50 -0
- package/dist/src/core/build-overwrite-guard.js +84 -4
- package/dist/src/core/build-prepare.d.ts +13 -0
- package/dist/src/core/build-prepare.js +42 -10
- package/dist/src/core/build-run-record.d.ts +74 -0
- package/dist/src/core/build-run-record.js +136 -0
- package/dist/src/core/checkjs-support-heads.d.ts +41 -0
- package/dist/src/core/checkjs-support-heads.js +104 -0
- package/dist/src/core/config-paths.d.ts +2 -2
- package/dist/src/core/config-paths.js +10 -0
- package/dist/src/core/config-validate-check.d.ts +8 -0
- package/dist/src/core/config-validate-check.js +219 -0
- package/dist/src/core/config-validate-file-size.d.ts +9 -6
- package/dist/src/core/config-validate-file-size.js +91 -2
- package/dist/src/core/config-validate-history.d.ts +11 -0
- package/dist/src/core/config-validate-history.js +38 -0
- package/dist/src/core/config-validate-patch-policy.js +100 -0
- package/dist/src/core/config-validate-test-toolchains.js +21 -0
- package/dist/src/core/config-validate-token-scales.d.ts +9 -0
- package/dist/src/core/config-validate-token-scales.js +92 -0
- package/dist/src/core/config-validate.js +20 -5
- package/dist/src/core/config.d.ts +5 -0
- package/dist/src/core/config.js +16 -0
- package/dist/src/core/coverage-dispatch.d.ts +24 -0
- package/dist/src/core/coverage-dispatch.js +44 -0
- package/dist/src/core/coverage-extend.d.ts +70 -45
- package/dist/src/core/coverage-extend.js +199 -144
- package/dist/src/core/coverage-records.d.ts +108 -0
- package/dist/src/core/coverage-records.js +384 -0
- package/dist/src/core/destructive.d.ts +7 -4
- package/dist/src/core/destructive.js +10 -10
- package/dist/src/core/engine-session-lock.d.ts +16 -1
- package/dist/src/core/engine-session-lock.js +38 -10
- package/dist/src/core/export-moved-code-shape.d.ts +49 -11
- package/dist/src/core/export-moved-code-shape.js +135 -44
- package/dist/src/core/file-lock-queue.d.ts +67 -0
- package/dist/src/core/file-lock-queue.js +221 -0
- package/dist/src/core/file-lock-shared.d.ts +57 -0
- package/dist/src/core/file-lock-shared.js +117 -0
- package/dist/src/core/file-lock.d.ts +13 -25
- package/dist/src/core/file-lock.js +163 -140
- package/dist/src/core/furnace-apply-output.d.ts +10 -0
- package/dist/src/core/furnace-apply-output.js +31 -1
- package/dist/src/core/furnace-apply.js +22 -12
- package/dist/src/core/furnace-composed-source.d.ts +76 -0
- package/dist/src/core/furnace-composed-source.js +167 -0
- package/dist/src/core/furnace-config-validate-exceptions.d.ts +16 -0
- package/dist/src/core/furnace-config-validate-exceptions.js +102 -0
- package/dist/src/core/furnace-config-validate.js +14 -0
- package/dist/src/core/furnace-css-fragments.d.ts +10 -0
- package/dist/src/core/furnace-css-fragments.js +26 -0
- package/dist/src/core/furnace-operation.d.ts +3 -3
- package/dist/src/core/furnace-registration-jar-inplace.d.ts +12 -0
- package/dist/src/core/furnace-registration-jar-inplace.js +80 -0
- package/dist/src/core/furnace-registration-remove.d.ts +22 -1
- package/dist/src/core/furnace-registration-remove.js +53 -17
- package/dist/src/core/furnace-registration-rename.d.ts +26 -0
- package/dist/src/core/furnace-registration-rename.js +77 -0
- package/dist/src/core/furnace-registration.d.ts +14 -4
- package/dist/src/core/furnace-registration.js +44 -10
- package/dist/src/core/furnace-staleness.d.ts +7 -0
- package/dist/src/core/furnace-staleness.js +34 -24
- package/dist/src/core/furnace-validate-accessibility.d.ts +8 -4
- package/dist/src/core/furnace-validate-accessibility.js +71 -28
- package/dist/src/core/furnace-validate-exceptions.d.ts +48 -0
- package/dist/src/core/furnace-validate-exceptions.js +80 -0
- package/dist/src/core/furnace-validate-icon-button.d.ts +7 -0
- package/dist/src/core/furnace-validate-icon-button.js +78 -0
- package/dist/src/core/furnace-validate.js +1 -1
- package/dist/src/core/harness-port-fallback.d.ts +60 -0
- package/dist/src/core/harness-port-fallback.js +96 -0
- package/dist/src/core/history-log-file.d.ts +61 -0
- package/dist/src/core/history-log-file.js +164 -0
- package/dist/src/core/history-log.d.ts +2 -1
- package/dist/src/core/history-log.js +2 -1
- package/dist/src/core/json-preserving-edit.d.ts +22 -0
- package/dist/src/core/json-preserving-edit.js +199 -0
- package/dist/src/core/line-prefixer.d.ts +18 -0
- package/dist/src/core/line-prefixer.js +34 -0
- package/dist/src/core/mach.d.ts +7 -0
- package/dist/src/core/mach.js +32 -10
- package/dist/src/core/module-resolution-preflight.d.ts +19 -3
- package/dist/src/core/module-resolution-preflight.js +24 -6
- package/dist/src/core/negative-control-compiled.d.ts +27 -0
- package/dist/src/core/negative-control-compiled.js +73 -0
- package/dist/src/core/negative-control-diff.d.ts +51 -0
- package/dist/src/core/negative-control-diff.js +179 -0
- package/dist/src/core/negative-control.d.ts +150 -0
- package/dist/src/core/negative-control.js +399 -0
- package/dist/src/core/objdir-install-manifests.d.ts +73 -0
- package/dist/src/core/objdir-install-manifests.js +226 -0
- package/dist/src/core/park-store.d.ts +63 -0
- package/dist/src/core/park-store.js +216 -0
- package/dist/src/core/patch-export-update.d.ts +6 -0
- package/dist/src/core/patch-export-update.js +13 -3
- package/dist/src/core/patch-export.d.ts +3 -2
- package/dist/src/core/patch-export.js +22 -16
- package/dist/src/core/patch-files.js +26 -8
- package/dist/src/core/patch-lint-checkjs-any-import.d.ts +39 -0
- package/dist/src/core/patch-lint-checkjs-any-import.js +63 -0
- package/dist/src/core/patch-lint-checkjs-diagnostics.d.ts +17 -0
- package/dist/src/core/patch-lint-checkjs-diagnostics.js +32 -0
- package/dist/src/core/patch-lint-checkjs.d.ts +10 -1
- package/dist/src/core/patch-lint-checkjs.js +20 -13
- package/dist/src/core/patch-lint-code-lines.d.ts +59 -0
- package/dist/src/core/patch-lint-code-lines.js +105 -0
- package/dist/src/core/patch-lint-cross.d.ts +3 -1
- package/dist/src/core/patch-lint-cross.js +17 -4
- package/dist/src/core/patch-lint-css.d.ts +8 -2
- package/dist/src/core/patch-lint-css.js +24 -14
- package/dist/src/core/patch-lint-file-size.d.ts +12 -5
- package/dist/src/core/patch-lint-file-size.js +22 -11
- package/dist/src/core/patch-lint-forward-registration-extended.d.ts +23 -0
- package/dist/src/core/patch-lint-forward-registration-extended.js +36 -11
- package/dist/src/core/patch-lint-forward-registration.js +10 -0
- package/dist/src/core/patch-lint-ignore.d.ts +196 -0
- package/dist/src/core/patch-lint-ignore.js +429 -0
- package/dist/src/core/patch-lint-ownership.d.ts +10 -0
- package/dist/src/core/patch-lint-ownership.js +26 -0
- package/dist/src/core/patch-lint-size-thresholds.d.ts +52 -0
- package/dist/src/core/patch-lint-size-thresholds.js +110 -0
- package/dist/src/core/patch-lint-size.d.ts +117 -0
- package/dist/src/core/patch-lint-size.js +331 -0
- package/dist/src/core/patch-lint-staged-registration.d.ts +18 -1
- package/dist/src/core/patch-lint-staged-registration.js +20 -0
- package/dist/src/core/patch-lint-token-scale.d.ts +57 -0
- package/dist/src/core/patch-lint-token-scale.js +286 -0
- package/dist/src/core/patch-lint.d.ts +11 -83
- package/dist/src/core/patch-lint.js +66 -288
- package/dist/src/core/patch-lock.js +7 -6
- package/dist/src/core/patch-manifest-consistency.js +7 -6
- package/dist/src/core/patch-manifest-io.d.ts +6 -3
- package/dist/src/core/patch-manifest-io.js +27 -9
- package/dist/src/core/patch-manifest-key-order.d.ts +24 -0
- package/dist/src/core/patch-manifest-key-order.js +61 -0
- package/dist/src/core/patch-manifest-stage.d.ts +46 -0
- package/dist/src/core/patch-manifest-stage.js +96 -0
- package/dist/src/core/patch-manifest-validate.js +61 -3
- package/dist/src/core/patch-order-legal.d.ts +26 -0
- package/dist/src/core/patch-order-legal.js +88 -0
- package/dist/src/core/patch-policy-content.d.ts +40 -0
- package/dist/src/core/patch-policy-content.js +216 -0
- package/dist/src/core/patch-policy.d.ts +22 -5
- package/dist/src/core/patch-policy.js +26 -12
- package/dist/src/core/patch-retired.d.ts +57 -0
- package/dist/src/core/patch-retired.js +92 -0
- package/dist/src/core/patch-subset.d.ts +16 -0
- package/dist/src/core/patch-subset.js +66 -0
- package/dist/src/core/preflight-wait.d.ts +20 -0
- package/dist/src/core/preflight-wait.js +38 -0
- package/dist/src/core/rebase-from-version.d.ts +46 -0
- package/dist/src/core/rebase-from-version.js +71 -0
- package/dist/src/core/run-log.d.ts +26 -0
- package/dist/src/core/run-log.js +106 -4
- package/dist/src/core/run-profile.d.ts +7 -0
- package/dist/src/core/run-profile.js +7 -1
- package/dist/src/core/smoke-patterns.d.ts +5 -0
- package/dist/src/core/smoke-patterns.js +13 -0
- package/dist/src/core/test-harness-crash.d.ts +19 -1
- package/dist/src/core/test-harness-crash.js +8 -9
- package/dist/src/core/test-harness-signature.d.ts +33 -0
- package/dist/src/core/test-harness-signature.js +23 -1
- package/dist/src/core/test-raw-log.d.ts +66 -0
- package/dist/src/core/test-raw-log.js +122 -0
- package/dist/src/core/test-run-completeness.d.ts +90 -0
- package/dist/src/core/test-run-completeness.js +184 -0
- package/dist/src/core/test-stale-check.d.ts +27 -1
- package/dist/src/core/test-stale-check.js +39 -49
- package/dist/src/core/test-stale-exempt.d.ts +40 -0
- package/dist/src/core/test-stale-exempt.js +70 -0
- package/dist/src/core/test-xpcshell-retry.d.ts +2 -0
- package/dist/src/core/test-xpcshell-retry.js +2 -1
- package/dist/src/core/token-lint.d.ts +53 -0
- package/dist/src/core/token-lint.js +131 -0
- package/dist/src/core/token-sibling-sheets.d.ts +46 -0
- package/dist/src/core/token-sibling-sheets.js +119 -0
- package/dist/src/core/tree-guard.js +5 -0
- package/dist/src/core/typecheck-shim.d.ts +6 -2
- package/dist/src/core/typecheck-shim.js +205 -4
- package/dist/src/core/typecheck.js +3 -1
- package/dist/src/index.d.ts +14 -3
- package/dist/src/index.js +6 -1
- package/dist/src/types/commands/index.d.ts +2 -2
- package/dist/src/types/commands/options.d.ts +212 -24
- package/dist/src/types/commands/patches.d.ts +118 -1
- package/dist/src/types/config.d.ts +264 -0
- package/dist/src/types/config.js +9 -0
- package/dist/src/types/furnace.d.ts +63 -1
- package/dist/src/types/furnace.js +7 -0
- package/dist/src/types/index.d.ts +1 -1
- package/dist/src/utils/options.d.ts +36 -7
- package/dist/src/utils/options.js +94 -8
- package/dist/src/utils/path-glob.d.ts +15 -0
- package/dist/src/utils/path-glob.js +47 -0
- package/dist/src/utils/regex.d.ts +15 -3
- package/dist/src/utils/regex.js +37 -16
- package/docs/configuration.md +369 -11
- package/docs/exit-codes.md +18 -1
- package/docs/furnace.md +139 -3
- package/docs/lifecycle-invariants.md +65 -30
- package/docs/machine-output.md +120 -12
- package/docs/patch-workflow.md +458 -22
- package/docs/run-logs.md +20 -1
- package/docs/testing.md +346 -21
- package/package.json +3 -3
|
@@ -121,6 +121,105 @@ function assertPolicyRangesDoNotOverlap(ranges, label) {
|
|
|
121
121
|
}
|
|
122
122
|
}
|
|
123
123
|
}
|
|
124
|
+
function parseNonEmptyString(raw, label) {
|
|
125
|
+
if (typeof raw !== 'string' || raw.trim() === '') {
|
|
126
|
+
throw new ConfigError(`Config field "${label}" must be a non-empty string`);
|
|
127
|
+
}
|
|
128
|
+
return raw;
|
|
129
|
+
}
|
|
130
|
+
function parseGlobList(raw, label) {
|
|
131
|
+
if (!Array.isArray(raw) || raw.length === 0) {
|
|
132
|
+
throw new ConfigError(`Config field "${label}" must be a non-empty array of path globs`);
|
|
133
|
+
}
|
|
134
|
+
return raw.map((entry, index) => parseNonEmptyString(entry, `${label}[${index}]`));
|
|
135
|
+
}
|
|
136
|
+
function parseUpstreamAllowEntry(raw, label, defaultMarker) {
|
|
137
|
+
if (typeof raw === 'string')
|
|
138
|
+
return parseNonEmptyString(raw, label);
|
|
139
|
+
let rec;
|
|
140
|
+
try {
|
|
141
|
+
rec = parseObject(raw, label);
|
|
142
|
+
}
|
|
143
|
+
catch {
|
|
144
|
+
throw new ConfigError(`Config field "${label}" must be a path glob or an object`);
|
|
145
|
+
}
|
|
146
|
+
const entry = {
|
|
147
|
+
path: parseNonEmptyString(rec.raw('path'), `${label}.path`),
|
|
148
|
+
};
|
|
149
|
+
const addOnly = rec.raw('addOnly');
|
|
150
|
+
if (addOnly !== undefined) {
|
|
151
|
+
if (typeof addOnly !== 'boolean') {
|
|
152
|
+
throw new ConfigError(`Config field "${label}.addOnly" must be a boolean`);
|
|
153
|
+
}
|
|
154
|
+
entry.addOnly = addOnly;
|
|
155
|
+
}
|
|
156
|
+
const marker = rec.raw('marker');
|
|
157
|
+
if (marker !== undefined)
|
|
158
|
+
entry.marker = parseNonEmptyString(marker, `${label}.marker`);
|
|
159
|
+
if (entry.addOnly === true && entry.marker === undefined && defaultMarker === undefined) {
|
|
160
|
+
throw new ConfigError(`Config field "${label}" sets addOnly but no marker: set "${label}.marker" or "patchPolicy.addOnlyMarker"`);
|
|
161
|
+
}
|
|
162
|
+
return entry;
|
|
163
|
+
}
|
|
164
|
+
function parseScopeRule(raw, label) {
|
|
165
|
+
let rec;
|
|
166
|
+
try {
|
|
167
|
+
rec = parseObject(raw, label);
|
|
168
|
+
}
|
|
169
|
+
catch {
|
|
170
|
+
throw new ConfigError(`Config field "${label}" must be an object`);
|
|
171
|
+
}
|
|
172
|
+
const rule = { files: parseGlobList(rec.raw('files'), `${label}.files`) };
|
|
173
|
+
const category = rec.raw('category');
|
|
174
|
+
if (category !== undefined) {
|
|
175
|
+
rule.category = parsePatchPolicyCategory(category, `${label}.category`);
|
|
176
|
+
}
|
|
177
|
+
const filenamePattern = optionalConfigString(rec, 'filenamePattern', `${label}.filenamePattern`);
|
|
178
|
+
if (filenamePattern !== undefined) {
|
|
179
|
+
try {
|
|
180
|
+
new RegExp(filenamePattern);
|
|
181
|
+
}
|
|
182
|
+
catch (error) {
|
|
183
|
+
throw new ConfigError(`Config field "${label}.filenamePattern" must be a valid regular expression: ${toError(error).message}`);
|
|
184
|
+
}
|
|
185
|
+
rule.filenamePattern = filenamePattern;
|
|
186
|
+
}
|
|
187
|
+
if (rule.category === undefined && rule.filenamePattern === undefined) {
|
|
188
|
+
throw new ConfigError(`Config field "${label}" must set "category" or "filenamePattern" to select the patches it scopes`);
|
|
189
|
+
}
|
|
190
|
+
return rule;
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* Parses the registration-only policy fields: `upstreamAllowlist`,
|
|
194
|
+
* `addOnlyMarker`, `scopeRules` and `verifyDocumentPaths`. All opt-in.
|
|
195
|
+
*/
|
|
196
|
+
function parsePatchPolicyContentRules(rec, out) {
|
|
197
|
+
const addOnlyMarker = rec.raw('addOnlyMarker');
|
|
198
|
+
if (addOnlyMarker !== undefined) {
|
|
199
|
+
out.addOnlyMarker = parseNonEmptyString(addOnlyMarker, 'patchPolicy.addOnlyMarker');
|
|
200
|
+
}
|
|
201
|
+
const allowlist = rec.raw('upstreamAllowlist');
|
|
202
|
+
if (allowlist !== undefined) {
|
|
203
|
+
if (!Array.isArray(allowlist)) {
|
|
204
|
+
throw new ConfigError('Config field "patchPolicy.upstreamAllowlist" must be an array');
|
|
205
|
+
}
|
|
206
|
+
out.upstreamAllowlist = allowlist.map((entry, index) => parseUpstreamAllowEntry(entry, `patchPolicy.upstreamAllowlist[${index}]`, out.addOnlyMarker));
|
|
207
|
+
}
|
|
208
|
+
const scopeRules = rec.raw('scopeRules');
|
|
209
|
+
if (scopeRules !== undefined) {
|
|
210
|
+
if (!Array.isArray(scopeRules)) {
|
|
211
|
+
throw new ConfigError('Config field "patchPolicy.scopeRules" must be an array');
|
|
212
|
+
}
|
|
213
|
+
out.scopeRules = scopeRules.map((entry, index) => parseScopeRule(entry, `patchPolicy.scopeRules[${index}]`));
|
|
214
|
+
}
|
|
215
|
+
const verifyDocumentPaths = rec.raw('verifyDocumentPaths');
|
|
216
|
+
if (verifyDocumentPaths !== undefined) {
|
|
217
|
+
if (typeof verifyDocumentPaths !== 'boolean') {
|
|
218
|
+
throw new ConfigError('Config field "patchPolicy.verifyDocumentPaths" must be a boolean');
|
|
219
|
+
}
|
|
220
|
+
out.verifyDocumentPaths = verifyDocumentPaths;
|
|
221
|
+
}
|
|
222
|
+
}
|
|
124
223
|
/** Parses and validates the optional patch policy config block. */
|
|
125
224
|
export function parsePatchPolicyBlock(rec) {
|
|
126
225
|
const out = { ranges: [] };
|
|
@@ -170,5 +269,6 @@ export function parsePatchPolicyBlock(rec) {
|
|
|
170
269
|
out.reservedRanges = reservedRangesRaw.map((entry, index) => parsePatchPolicyReservedRange(entry, `patchPolicy.reservedRanges[${index}]`));
|
|
171
270
|
assertPolicyRangesDoNotOverlap(out.reservedRanges, 'patchPolicy.reservedRanges');
|
|
172
271
|
}
|
|
272
|
+
parsePatchPolicyContentRules(rec, out);
|
|
173
273
|
return out;
|
|
174
274
|
}
|
|
@@ -52,6 +52,27 @@ export function parseTestBlock(rec, config) {
|
|
|
52
52
|
}
|
|
53
53
|
out.reapOrphans = reapOrphans;
|
|
54
54
|
}
|
|
55
|
+
const mochitestPorts = testRec.raw('mochitestPorts');
|
|
56
|
+
if (mochitestPorts !== undefined) {
|
|
57
|
+
if (mochitestPorts !== 'fixed' && mochitestPorts !== 'auto') {
|
|
58
|
+
throw new ConfigError('Config field "test.mochitestPorts" must be "fixed" or "auto"');
|
|
59
|
+
}
|
|
60
|
+
out.mochitestPorts = mochitestPorts;
|
|
61
|
+
}
|
|
62
|
+
const lockMode = testRec.raw('lockMode');
|
|
63
|
+
if (lockMode !== undefined) {
|
|
64
|
+
if (lockMode !== 'exclusive' && lockMode !== 'shared') {
|
|
65
|
+
throw new ConfigError('Config field "test.lockMode" must be "exclusive" or "shared"');
|
|
66
|
+
}
|
|
67
|
+
out.lockMode = lockMode;
|
|
68
|
+
}
|
|
69
|
+
const furnaceApply = testRec.raw('furnaceApply');
|
|
70
|
+
if (furnaceApply !== undefined) {
|
|
71
|
+
if (furnaceApply !== 'all' && furnaceApply !== 'reached' && furnaceApply !== 'none') {
|
|
72
|
+
throw new ConfigError('Config field "test.furnaceApply" must be "all", "reached" or "none"');
|
|
73
|
+
}
|
|
74
|
+
out.furnaceApply = furnaceApply;
|
|
75
|
+
}
|
|
55
76
|
config.test = out;
|
|
56
77
|
}
|
|
57
78
|
/** Parses optional project-specific external toolchain doctor probes. */
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Validation for `fireforge.json#patchLint.tokenScales`.
|
|
3
|
+
*
|
|
4
|
+
* Unknown keys are refused: a misspelt `allowInCalc` or `minFiles` would
|
|
5
|
+
* otherwise loosen or drop a scale without a word.
|
|
6
|
+
*/
|
|
7
|
+
import type { PatchLintTokenScale } from '../types/config.js';
|
|
8
|
+
/** Parses and validates `patchLint.tokenScales`. */
|
|
9
|
+
export declare function parsePatchLintTokenScales(raw: unknown): PatchLintTokenScale[];
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
// SPDX-License-Identifier: EUPL-1.2
|
|
2
|
+
/**
|
|
3
|
+
* Validation for `fireforge.json#patchLint.tokenScales`.
|
|
4
|
+
*
|
|
5
|
+
* Unknown keys are refused: a misspelt `allowInCalc` or `minFiles` would
|
|
6
|
+
* otherwise loosen or drop a scale without a word.
|
|
7
|
+
*/
|
|
8
|
+
import { ConfigError } from '../errors/config.js';
|
|
9
|
+
import { parseObject } from '../utils/parse.js';
|
|
10
|
+
const SCALE_KEYS = [
|
|
11
|
+
'properties',
|
|
12
|
+
'prefix',
|
|
13
|
+
'allowLiterals',
|
|
14
|
+
'allow',
|
|
15
|
+
'allowInCalc',
|
|
16
|
+
'offsetCap',
|
|
17
|
+
'exclude',
|
|
18
|
+
'minFiles',
|
|
19
|
+
];
|
|
20
|
+
const PREFIX_PATTERN = /^--[\w-]+$/;
|
|
21
|
+
function parseNames(raw, label, required) {
|
|
22
|
+
if (raw === undefined && !required)
|
|
23
|
+
return undefined;
|
|
24
|
+
if (!Array.isArray(raw) ||
|
|
25
|
+
(required && raw.length === 0) ||
|
|
26
|
+
raw.some((value) => typeof value !== 'string' || value.trim() === '')) {
|
|
27
|
+
throw new ConfigError(`Config field "${label}" must be ${required ? 'a non-empty' : 'an'} array of non-empty strings`);
|
|
28
|
+
}
|
|
29
|
+
return raw;
|
|
30
|
+
}
|
|
31
|
+
function parsePrefix(raw, label) {
|
|
32
|
+
const prefixes = Array.isArray(raw) ? raw : [raw];
|
|
33
|
+
if (prefixes.length === 0 ||
|
|
34
|
+
prefixes.some((prefix) => typeof prefix !== 'string' || !PREFIX_PATTERN.test(prefix))) {
|
|
35
|
+
throw new ConfigError(`Config field "${label}.prefix" must be a custom-property prefix such as "--mybrowser-space-", or a non-empty list of them`);
|
|
36
|
+
}
|
|
37
|
+
return Array.isArray(raw) ? prefixes : raw;
|
|
38
|
+
}
|
|
39
|
+
function parseNumber(raw, label, integer) {
|
|
40
|
+
const valid = typeof raw === 'number' && Number.isFinite(raw) && (integer ? Number.isInteger(raw) : true);
|
|
41
|
+
if (!valid || raw < (integer ? 1 : 0)) {
|
|
42
|
+
throw new ConfigError(`Config field "${label}" must be ${integer ? 'a positive integer' : 'a non-negative number'}`);
|
|
43
|
+
}
|
|
44
|
+
return raw;
|
|
45
|
+
}
|
|
46
|
+
function parseTokenScale(raw, label) {
|
|
47
|
+
let rec;
|
|
48
|
+
try {
|
|
49
|
+
rec = parseObject(raw, label);
|
|
50
|
+
}
|
|
51
|
+
catch {
|
|
52
|
+
throw new ConfigError(`Config field "${label}" must be an object`);
|
|
53
|
+
}
|
|
54
|
+
for (const key of Object.keys(raw)) {
|
|
55
|
+
if (!SCALE_KEYS.includes(key)) {
|
|
56
|
+
throw new ConfigError(`Config field "${label}" has unknown key "${key}"`);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
const properties = parseNames(rec.raw('properties'), `${label}.properties`, true) ?? [];
|
|
60
|
+
const scale = { properties, prefix: parsePrefix(rec.raw('prefix'), label) };
|
|
61
|
+
const allowLiterals = parseNames(rec.raw('allowLiterals'), `${label}.allowLiterals`, false);
|
|
62
|
+
if (allowLiterals !== undefined)
|
|
63
|
+
scale.allowLiterals = allowLiterals;
|
|
64
|
+
const allow = parseNames(rec.raw('allow'), `${label}.allow`, false);
|
|
65
|
+
if (allow !== undefined) {
|
|
66
|
+
const malformed = allow.find((name) => !name.startsWith('--'));
|
|
67
|
+
if (malformed !== undefined) {
|
|
68
|
+
throw new ConfigError(`Config field "${label}.allow" entries must be custom-property names starting with "--" (got "${malformed}")`);
|
|
69
|
+
}
|
|
70
|
+
scale.allow = allow;
|
|
71
|
+
}
|
|
72
|
+
const allowInCalc = parseNames(rec.raw('allowInCalc'), `${label}.allowInCalc`, false);
|
|
73
|
+
if (allowInCalc !== undefined)
|
|
74
|
+
scale.allowInCalc = allowInCalc;
|
|
75
|
+
const offsetCap = rec.raw('offsetCap');
|
|
76
|
+
if (offsetCap !== undefined)
|
|
77
|
+
scale.offsetCap = parseNumber(offsetCap, `${label}.offsetCap`, false);
|
|
78
|
+
const exclude = parseNames(rec.raw('exclude'), `${label}.exclude`, false);
|
|
79
|
+
if (exclude !== undefined)
|
|
80
|
+
scale.exclude = exclude;
|
|
81
|
+
const minFiles = rec.raw('minFiles');
|
|
82
|
+
if (minFiles !== undefined)
|
|
83
|
+
scale.minFiles = parseNumber(minFiles, `${label}.minFiles`, true);
|
|
84
|
+
return scale;
|
|
85
|
+
}
|
|
86
|
+
/** Parses and validates `patchLint.tokenScales`. */
|
|
87
|
+
export function parsePatchLintTokenScales(raw) {
|
|
88
|
+
if (!Array.isArray(raw)) {
|
|
89
|
+
throw new ConfigError('Config field "patchLint.tokenScales" must be an array');
|
|
90
|
+
}
|
|
91
|
+
return raw.map((entry, index) => parseTokenScale(entry, `patchLint.tokenScales[${index}]`));
|
|
92
|
+
}
|
|
@@ -9,9 +9,12 @@ import { isContainedRelativePath, isExplicitAbsolutePath } from '../utils/paths.
|
|
|
9
9
|
import { describeProductVersionIncompatibility, FIREFOX_PRODUCTS, isObject, isValidAppId, isValidFirefoxCandidate, isValidFirefoxProduct, isValidFirefoxVersion, isValidProjectLicense, PROJECT_LICENSES, } from '../utils/validation.js';
|
|
10
10
|
import { SUPPORTED_CONFIG_ROOT_KEYS } from './config-paths.js';
|
|
11
11
|
import { parseBuildAuditConfig } from './config-validate-build-audit.js';
|
|
12
|
-
import {
|
|
12
|
+
import { parseCheckConfig } from './config-validate-check.js';
|
|
13
|
+
import { parsePatchLintSizeFields } from './config-validate-file-size.js';
|
|
14
|
+
import { parseHistoryBlock } from './config-validate-history.js';
|
|
13
15
|
import { parsePatchPolicyBlock } from './config-validate-patch-policy.js';
|
|
14
16
|
import { parseExternalToolchainsBlock, parseTestBlock } from './config-validate-test-toolchains.js';
|
|
17
|
+
import { parsePatchLintTokenScales } from './config-validate-token-scales.js';
|
|
15
18
|
/**
|
|
16
19
|
* Parses and validates the four required identity fields (`name`,
|
|
17
20
|
* `vendor`, `appId`, `binaryName`): all non-empty strings, with
|
|
@@ -167,6 +170,7 @@ export function validateConfig(data) {
|
|
|
167
170
|
config.buildAudit = parseBuildAuditConfig(buildAuditRaw);
|
|
168
171
|
}
|
|
169
172
|
parseTestBlock(rec, config);
|
|
173
|
+
parseHistoryBlock(rec, config);
|
|
170
174
|
parseExternalToolchainsBlock(rec, config);
|
|
171
175
|
parseWireBlock(rec, config);
|
|
172
176
|
parseLicenseField(rec, config);
|
|
@@ -190,6 +194,11 @@ export function validateConfig(data) {
|
|
|
190
194
|
if (typecheckRec) {
|
|
191
195
|
config.typecheck = parseTypecheckBlock(typecheckRec);
|
|
192
196
|
}
|
|
197
|
+
// `fireforge check` policy and project steps.
|
|
198
|
+
const checkRaw = rec.raw('check');
|
|
199
|
+
if (checkRaw !== undefined) {
|
|
200
|
+
config.check = parseCheckConfig(checkRaw);
|
|
201
|
+
}
|
|
193
202
|
// Warn on unknown root keys
|
|
194
203
|
const knownRootKeys = new Set(SUPPORTED_CONFIG_ROOT_KEYS);
|
|
195
204
|
for (const key of rec.keys()) {
|
|
@@ -372,10 +381,7 @@ function parsePatchLintBlock(rec) {
|
|
|
372
381
|
}
|
|
373
382
|
out.rawColorAllowlist = rawColorAllowlist;
|
|
374
383
|
}
|
|
375
|
-
|
|
376
|
-
if (fileSizeThresholds !== undefined) {
|
|
377
|
-
out.fileSizeThresholds = parsePatchLintFileSizeThresholds(fileSizeThresholds);
|
|
378
|
-
}
|
|
384
|
+
Object.assign(out, parsePatchLintSizeFields((key) => rec.raw(key)));
|
|
379
385
|
const forwardRegistration = rec.raw('forwardRegistration');
|
|
380
386
|
if (forwardRegistration !== undefined) {
|
|
381
387
|
if (forwardRegistration !== 'support-files' && forwardRegistration !== 'extended') {
|
|
@@ -383,6 +389,9 @@ function parsePatchLintBlock(rec) {
|
|
|
383
389
|
}
|
|
384
390
|
out.forwardRegistration = forwardRegistration;
|
|
385
391
|
}
|
|
392
|
+
const tokenScales = rec.raw('tokenScales');
|
|
393
|
+
if (tokenScales !== undefined)
|
|
394
|
+
out.tokenScales = parsePatchLintTokenScales(tokenScales);
|
|
386
395
|
for (const key of PATCH_LINT_SEVERITY_GATE_KEYS) {
|
|
387
396
|
const gate = parseSeverityGate(rec.raw(key), `patchLint.${key}`);
|
|
388
397
|
if (gate !== undefined)
|
|
@@ -462,6 +471,12 @@ function parseTypecheckBlock(rec) {
|
|
|
462
471
|
if (undefinedIdentifiers !== undefined) {
|
|
463
472
|
out.undefinedIdentifiers = undefinedIdentifiers;
|
|
464
473
|
}
|
|
474
|
+
const litTypes = rec.raw('litTypes');
|
|
475
|
+
if (litTypes !== undefined && typeof litTypes !== 'boolean') {
|
|
476
|
+
throw new ConfigError('Config field "typecheck.litTypes" must be a boolean');
|
|
477
|
+
}
|
|
478
|
+
if (litTypes !== undefined)
|
|
479
|
+
out.litTypes = litTypes;
|
|
465
480
|
return out;
|
|
466
481
|
}
|
|
467
482
|
/**
|
|
@@ -54,6 +54,11 @@ export declare function writeConfig(root: string, config: FireForgeConfig): Prom
|
|
|
54
54
|
* This is used by CLI `config --force`, where callers may intentionally write
|
|
55
55
|
* keys or value shapes outside the validated FireForgeConfig schema.
|
|
56
56
|
*
|
|
57
|
+
* An existing file is edited in place: only the values that differ from the
|
|
58
|
+
* document on disk are rewritten, so a one-key change keeps the file's
|
|
59
|
+
* formatting (compact objects and arrays, indentation, key order) and stays
|
|
60
|
+
* a one-hunk diff. A missing or unparseable file is written in full.
|
|
61
|
+
*
|
|
57
62
|
* Individual writes are atomic via {@link writeJson} (temp file + rename),
|
|
58
63
|
* but atomicity alone does not prevent lost updates across concurrent
|
|
59
64
|
* writers: each writer reads an old copy, mutates its own in-memory view,
|
package/dist/src/core/config.js
CHANGED
|
@@ -16,6 +16,7 @@ import { isObject } from '../utils/validation.js';
|
|
|
16
16
|
import { getProjectPaths } from './config-paths.js';
|
|
17
17
|
import { validateConfig } from './config-validate.js';
|
|
18
18
|
import { createSiblingLockPath, withFileLock } from './file-lock.js';
|
|
19
|
+
import { rewriteJsonPreservingFormat } from './json-preserving-edit.js';
|
|
19
20
|
// ---- re-exports ----
|
|
20
21
|
export { mutateConfig } from './config-mutate.js';
|
|
21
22
|
export { FIREFORGE_DIR, getProjectPaths, SUPPORTED_CONFIG_PATHS, SUPPORTED_CONFIG_ROOT_KEYS, } from './config-paths.js';
|
|
@@ -109,6 +110,11 @@ export async function writeConfig(root, config) {
|
|
|
109
110
|
* This is used by CLI `config --force`, where callers may intentionally write
|
|
110
111
|
* keys or value shapes outside the validated FireForgeConfig schema.
|
|
111
112
|
*
|
|
113
|
+
* An existing file is edited in place: only the values that differ from the
|
|
114
|
+
* document on disk are rewritten, so a one-key change keeps the file's
|
|
115
|
+
* formatting (compact objects and arrays, indentation, key order) and stays
|
|
116
|
+
* a one-hunk diff. A missing or unparseable file is written in full.
|
|
117
|
+
*
|
|
112
118
|
* Individual writes are atomic via {@link writeJson} (temp file + rename),
|
|
113
119
|
* but atomicity alone does not prevent lost updates across concurrent
|
|
114
120
|
* writers: each writer reads an old copy, mutates its own in-memory view,
|
|
@@ -119,6 +125,16 @@ export async function writeConfig(root, config) {
|
|
|
119
125
|
*/
|
|
120
126
|
export async function writeConfigDocument(root, config) {
|
|
121
127
|
const paths = getProjectPaths(root);
|
|
128
|
+
if (await fsUtils.pathExists(paths.config)) {
|
|
129
|
+
const current = await fsUtils.readText(paths.config);
|
|
130
|
+
// `FireForgeConfig` is plain parsed-config data, so it is a JSON object.
|
|
131
|
+
const edited = rewriteJsonPreservingFormat(current, config);
|
|
132
|
+
if (edited !== undefined) {
|
|
133
|
+
if (edited !== current)
|
|
134
|
+
await fsUtils.writeText(paths.config, edited);
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
122
138
|
await fsUtils.writeJson(paths.config, config);
|
|
123
139
|
}
|
|
124
140
|
/**
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dispatch-time half of per-path coverage. A scoped build that followed a
|
|
3
|
+
* full build carries the full build's anchor forward instead of collapsing
|
|
4
|
+
* the claim to its own paths. A requested path outside the scoped list is
|
|
5
|
+
* then still covered while its own staging inputs are unchanged against
|
|
6
|
+
* that anchor, and a refusal names the inputs that did change.
|
|
7
|
+
*/
|
|
8
|
+
import type { BuildBaseline } from './build-baseline-types.js';
|
|
9
|
+
/** A requested path no recorded claim covers, with the inputs that explain it. */
|
|
10
|
+
export interface UncoveredRequest {
|
|
11
|
+
path: string;
|
|
12
|
+
/** Staging inputs changed since the carried full build. Empty when unknown. */
|
|
13
|
+
changed: string[];
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Re-checks the paths the scoped list does not cover against the carried
|
|
17
|
+
* full-build anchor. Returns the paths that stay uncovered.
|
|
18
|
+
*
|
|
19
|
+
* @param engineDir - Path to the engine directory
|
|
20
|
+
* @param baseline - Last successful build's baseline
|
|
21
|
+
* @param uncovered - Request paths outside the scoped list
|
|
22
|
+
* @param fullSuite - The sentinel standing for a path-less (full-suite) request
|
|
23
|
+
*/
|
|
24
|
+
export declare function filterByCarriedFullCoverage(engineDir: string, baseline: BuildBaseline | undefined, uncovered: readonly string[], fullSuite: string): Promise<UncoveredRequest[]>;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
// SPDX-License-Identifier: EUPL-1.2
|
|
2
|
+
/**
|
|
3
|
+
* Dispatch-time half of per-path coverage. A scoped build that followed a
|
|
4
|
+
* full build carries the full build's anchor forward instead of collapsing
|
|
5
|
+
* the claim to its own paths. A requested path outside the scoped list is
|
|
6
|
+
* then still covered while its own staging inputs are unchanged against
|
|
7
|
+
* that anchor, and a refusal names the inputs that did change.
|
|
8
|
+
*/
|
|
9
|
+
import { toError } from '../utils/errors.js';
|
|
10
|
+
import { verbose } from '../utils/logger.js';
|
|
11
|
+
import { collectStagingInputs, findChangedInputs, hashEngineFile, readEngineContentState, } from './coverage-records.js';
|
|
12
|
+
/**
|
|
13
|
+
* Re-checks the paths the scoped list does not cover against the carried
|
|
14
|
+
* full-build anchor. Returns the paths that stay uncovered.
|
|
15
|
+
*
|
|
16
|
+
* @param engineDir - Path to the engine directory
|
|
17
|
+
* @param baseline - Last successful build's baseline
|
|
18
|
+
* @param uncovered - Request paths outside the scoped list
|
|
19
|
+
* @param fullSuite - The sentinel standing for a path-less (full-suite) request
|
|
20
|
+
*/
|
|
21
|
+
export async function filterByCarriedFullCoverage(engineDir, baseline, uncovered, fullSuite) {
|
|
22
|
+
const unresolved = uncovered.map((path) => ({ path, changed: [] }));
|
|
23
|
+
const anchor = baseline?.fullCoverageAnchor;
|
|
24
|
+
if (anchor === undefined || uncovered.length === 0)
|
|
25
|
+
return unresolved;
|
|
26
|
+
if ((await hashEngineFile(engineDir, 'mozconfig')) !== anchor.mozconfigHash)
|
|
27
|
+
return unresolved;
|
|
28
|
+
let state;
|
|
29
|
+
try {
|
|
30
|
+
state = await readEngineContentState(engineDir);
|
|
31
|
+
}
|
|
32
|
+
catch (error) {
|
|
33
|
+
verbose(`Coverage check: engine state unreadable — ${toError(error).message}`);
|
|
34
|
+
return unresolved;
|
|
35
|
+
}
|
|
36
|
+
const remaining = [];
|
|
37
|
+
for (const path of uncovered) {
|
|
38
|
+
const inputs = path === fullSuite ? undefined : await collectStagingInputs(engineDir, path);
|
|
39
|
+
const changed = await findChangedInputs(state, anchor, inputs);
|
|
40
|
+
if (changed === undefined || changed.length > 0)
|
|
41
|
+
remaining.push({ path, changed: changed ?? [] });
|
|
42
|
+
}
|
|
43
|
+
return remaining;
|
|
44
|
+
}
|
|
@@ -1,62 +1,87 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
*
|
|
2
|
+
* Decides which earlier packaging claims a scoped `fireforge test --build`
|
|
3
|
+
* keeps. Retention is per staged path (see `coverage-records.ts`): an
|
|
4
|
+
* earlier path stays covered while its own staging inputs are unchanged,
|
|
5
|
+
* whatever moved elsewhere in the engine, and a full claim narrows to
|
|
6
|
+
* per-path checks once something outside the new scope changed instead of
|
|
7
|
+
* collapsing to this build's paths. `--extend-coverage` turns any drop into
|
|
8
|
+
* a refusal before the build.
|
|
9
|
+
*
|
|
10
|
+
* Fingerprints must be complete: a legacy packageable-only record cannot
|
|
5
11
|
* prove that a test fixture or manifest still matches its staged copy.
|
|
6
12
|
*/
|
|
7
|
-
import {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
13
|
+
import type { BuildBaseline, CoverageAnchor, CoverageRecord, TestPackagingCoverage } from './build-baseline-types.js';
|
|
14
|
+
export { hashEngineFile } from './coverage-records.js';
|
|
15
|
+
/** What a dropped full claim is called in notices and refusals. */
|
|
16
|
+
export declare const FULL_CLAIM_LABEL = "full coverage";
|
|
17
|
+
/** An earlier claim this build cannot keep, and why. */
|
|
18
|
+
export interface DroppedClaim {
|
|
19
|
+
/** Request path, or {@link FULL_CLAIM_LABEL}. */
|
|
20
|
+
path: string;
|
|
21
|
+
/** Staging inputs whose content changed since the claim was staged. */
|
|
22
|
+
changed: string[];
|
|
23
|
+
/** Why the claim cannot be verified at all, when no input list explains it. */
|
|
24
|
+
reason?: string;
|
|
25
|
+
}
|
|
26
|
+
/** What a scoped build keeps of the recorded coverage. */
|
|
27
|
+
export interface CoverageRetentionPlan {
|
|
28
|
+
/** The previous claim was full and nothing outside this build's scope moved. */
|
|
29
|
+
keepFull: boolean;
|
|
30
|
+
/** Earlier per-path records kept, refreshed for this build's paths. */
|
|
31
|
+
retained: Record<string, CoverageRecord>;
|
|
32
|
+
/** Full-build anchor carried for dispatch-time per-path checks. */
|
|
33
|
+
fullAnchor: CoverageAnchor | undefined;
|
|
34
|
+
/** Changed inputs that narrowed a full claim to per-path checks. */
|
|
35
|
+
narrowedBy: string[];
|
|
36
|
+
/** Earlier claims this build cannot keep. */
|
|
37
|
+
dropped: DroppedClaim[];
|
|
38
|
+
}
|
|
39
|
+
/** The baseline-wide anchor a baseline's own fields describe, when complete. */
|
|
40
|
+
export declare function baselineAnchor(baseline: BuildBaseline): CoverageAnchor | undefined;
|
|
18
41
|
/**
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
42
|
+
* Plans which earlier claims a scoped build over `requested` keeps. Runs
|
|
43
|
+
* before the build lock, so a refusal costs neither build time nor the
|
|
44
|
+
* lock. The mozconfig half runs later, via {@link applyMozconfigAnchor}.
|
|
45
|
+
*
|
|
22
46
|
* @param engineDir - Path to the engine directory
|
|
23
|
-
* @param
|
|
47
|
+
* @param previous - Baseline recorded by the previous build
|
|
48
|
+
* @param requested - Normalized request paths this build packages
|
|
24
49
|
*/
|
|
25
|
-
export declare function
|
|
50
|
+
export declare function planCoverageRetention(engineDir: string, previous: BuildBaseline | undefined, requested: string[]): Promise<CoverageRetentionPlan>;
|
|
26
51
|
/**
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
* costs no build time.
|
|
52
|
+
* Applies the mozconfig half of the anchor: a claim staged under a different
|
|
53
|
+
* `engine/mozconfig` is dropped. Runs after `prepareBuildEnvironment`
|
|
54
|
+
* regenerated the file this build configures with, and before mach.
|
|
55
|
+
*
|
|
32
56
|
* @param engineDir - Path to the engine directory
|
|
33
|
-
* @param
|
|
57
|
+
* @param plan - Plan from {@link planCoverageRetention}
|
|
34
58
|
*/
|
|
35
|
-
export declare function
|
|
59
|
+
export declare function applyMozconfigAnchor(engineDir: string, plan: CoverageRetentionPlan): Promise<CoverageRetentionPlan>;
|
|
60
|
+
/** Fields a scoped build writes onto its baseline. */
|
|
61
|
+
export interface RecordedCoverage {
|
|
62
|
+
testPackagingCoverage: TestPackagingCoverage;
|
|
63
|
+
testCoverageRecords?: Record<string, CoverageRecord>;
|
|
64
|
+
fullCoverageAnchor?: CoverageAnchor;
|
|
65
|
+
}
|
|
36
66
|
/**
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
*
|
|
67
|
+
* The coverage a green scoped build records: `'full'` when the plan kept a
|
|
68
|
+
* full claim, otherwise this build's paths with fresh records plus every
|
|
69
|
+
* retained earlier path, and the carried full anchor.
|
|
40
70
|
*
|
|
41
|
-
* @param
|
|
71
|
+
* @param engineDir - Path to the engine directory
|
|
72
|
+
* @param plan - Plan after {@link applyMozconfigAnchor}
|
|
42
73
|
* @param requested - Normalized request paths this build packaged
|
|
43
74
|
*/
|
|
44
|
-
export declare function
|
|
75
|
+
export declare function recordScopedCoverage(engineDir: string, plan: CoverageRetentionPlan, requested: string[]): Promise<RecordedCoverage>;
|
|
76
|
+
/** Renders one dropped claim with its cause. */
|
|
77
|
+
export declare function describeDroppedClaim(claim: DroppedClaim): string;
|
|
45
78
|
/**
|
|
46
|
-
*
|
|
47
|
-
*
|
|
48
|
-
* without matching copy.
|
|
49
|
-
* @param result - Failing result from an anchor check
|
|
79
|
+
* The notice a scoped build prints about earlier coverage, or undefined
|
|
80
|
+
* when nothing was dropped or narrowed.
|
|
50
81
|
*/
|
|
51
|
-
export declare function
|
|
52
|
-
reason: ExtendAnchorReason;
|
|
53
|
-
detail: string[];
|
|
54
|
-
}): string;
|
|
82
|
+
export declare function formatCoverageRetentionNotice(plan: CoverageRetentionPlan): string | undefined;
|
|
55
83
|
/**
|
|
56
|
-
*
|
|
57
|
-
*
|
|
58
|
-
* treats as "cannot prove unchanged", i.e. a refusal.
|
|
59
|
-
* @param engineDir - Path to the engine directory
|
|
60
|
-
* @param relPath - Engine-relative POSIX path
|
|
84
|
+
* The `--extend-coverage` refusal: the flag asks that no earlier claim be
|
|
85
|
+
* dropped, and the plan would drop some.
|
|
61
86
|
*/
|
|
62
|
-
export declare function
|
|
87
|
+
export declare function formatExtendCoverageRefusal(dropped: readonly DroppedClaim[]): string;
|