@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
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
// SPDX-License-Identifier: EUPL-1.2
|
|
2
|
+
/**
|
|
3
|
+
* `fireforge patch retire <name>`: removes a patch from the queue and keeps
|
|
4
|
+
* its order number spent as a retired slot in `patches.json#retired`.
|
|
5
|
+
*
|
|
6
|
+
* The case it exists for: a rename leaves a patch owning only files that no
|
|
7
|
+
* longer exist. `patch delete` opens a numeric gap that
|
|
8
|
+
* `patchPolicy.allowGaps: false` refuses, and `patch compact` renumbers
|
|
9
|
+
* every later patch, including ones a peer session has in flight. Retiring
|
|
10
|
+
* removes the patch file and row like a delete, and records the order as a
|
|
11
|
+
* placeholder the gap check counts as occupied. Nothing else reads the
|
|
12
|
+
* placeholder (see `core/patch-retired.ts`), and a later
|
|
13
|
+
* `export --order <n>` that takes the number fills it.
|
|
14
|
+
*
|
|
15
|
+
* Shares the delete's dependency refusal, dry-run, confirmation and history
|
|
16
|
+
* contract, so the two differ only in what happens to the order number.
|
|
17
|
+
*/
|
|
18
|
+
import { Command } from 'commander';
|
|
19
|
+
import { loadConfig } from '../../core/config.js';
|
|
20
|
+
import { confirmDestructive } from '../../core/destructive.js';
|
|
21
|
+
import { appendHistoryBestEffort } from '../../core/history-log.js';
|
|
22
|
+
import { buildPatchQueueContext } from '../../core/patch-lint.js';
|
|
23
|
+
import { withPatchDirectoryLock } from '../../core/patch-lock.js';
|
|
24
|
+
import { removePatchFileAndManifest } from '../../core/patch-manifest.js';
|
|
25
|
+
import { formatPatchOrder } from '../../core/patch-parse.js';
|
|
26
|
+
import { GeneralError } from '../../errors/base.js';
|
|
27
|
+
import { info, intro, outro } from '../../utils/logger.js';
|
|
28
|
+
import { addWaitLockOption, pickDefined, resolveWaitLockSeconds } from '../../utils/options.js';
|
|
29
|
+
import { proceedAfterDecision } from '../destructive-decision.js';
|
|
30
|
+
import { requirePatchQueue, requirePatchTarget } from './patch-context.js';
|
|
31
|
+
import { deleteCreatedFiles, planClaimedFiles, withCreatedFileLock, } from './removal-created-files.js';
|
|
32
|
+
import { collectRemovalDependents, queueSnapshot, removalConflict, warnDanglingStagedOwners, } from './removal-dependents.js';
|
|
33
|
+
/**
|
|
34
|
+
* Runs the `patch retire` command.
|
|
35
|
+
*
|
|
36
|
+
* @param projectRoot - Project root directory
|
|
37
|
+
* @param identifier - Patch filename, ordinal, or manifest name to retire
|
|
38
|
+
* @param options - Command options
|
|
39
|
+
*/
|
|
40
|
+
export async function patchRetireCommand(projectRoot, identifier, options = {}) {
|
|
41
|
+
intro(options.dryRun ? 'FireForge patch retire (dry run)' : 'FireForge patch retire');
|
|
42
|
+
const { paths, manifest } = await requirePatchQueue(projectRoot, {
|
|
43
|
+
missingDirMessage: 'Patches directory not found. No patches to retire.',
|
|
44
|
+
});
|
|
45
|
+
const target = requirePatchTarget(identifier, manifest.patches);
|
|
46
|
+
const baseCtx = await buildPatchQueueContext(paths.patches);
|
|
47
|
+
const dependents = collectRemovalDependents(baseCtx, target, {
|
|
48
|
+
noun: 'retirement',
|
|
49
|
+
verb: 'retire',
|
|
50
|
+
});
|
|
51
|
+
warnDanglingStagedOwners(baseCtx, target, 'retire');
|
|
52
|
+
const order = formatPatchOrder(target.order);
|
|
53
|
+
const claimed = await planClaimedFiles(baseCtx, target, paths.engine, options.deleteCreated === true);
|
|
54
|
+
const summary = [
|
|
55
|
+
`retire ${target.filename} (category: ${target.category}, order: ${order})`,
|
|
56
|
+
`description: ${target.description || '(none)'}`,
|
|
57
|
+
`order ${order} stays spent as a retired slot in patches.json; ` +
|
|
58
|
+
`"fireforge export --order ${order}" can fill it later`,
|
|
59
|
+
...claimed.summary,
|
|
60
|
+
];
|
|
61
|
+
const decision = await confirmDestructive({
|
|
62
|
+
operation: 'patch-retire',
|
|
63
|
+
title: `Retire ${target.filename}`,
|
|
64
|
+
summary,
|
|
65
|
+
yes: options.yes === true,
|
|
66
|
+
dryRun: options.dryRun === true,
|
|
67
|
+
unsafeOverride: options.forceUnsafe === true,
|
|
68
|
+
conflicts: removalConflict(dependents, target),
|
|
69
|
+
});
|
|
70
|
+
if (!proceedAfterDecision(decision, 'Retire cancelled'))
|
|
71
|
+
return;
|
|
72
|
+
const slot = {
|
|
73
|
+
order: target.order,
|
|
74
|
+
category: target.category,
|
|
75
|
+
filename: target.filename,
|
|
76
|
+
retiredAt: new Date().toISOString(),
|
|
77
|
+
...(options.reason !== undefined ? { reason: options.reason } : {}),
|
|
78
|
+
};
|
|
79
|
+
// Same locking and history contract as `patch delete`: the dependency
|
|
80
|
+
// scan approved before the prompt is re-checked under the lock, and the
|
|
81
|
+
// history record is appended inside it.
|
|
82
|
+
const waitLockSeconds = resolveWaitLockSeconds(options.waitLock);
|
|
83
|
+
await withCreatedFileLock(projectRoot, 'patch retire', claimed, waitLockSeconds, () => withPatchDirectoryLock(paths.patches, async () => {
|
|
84
|
+
const current = await buildPatchQueueContext(paths.patches);
|
|
85
|
+
if (queueSnapshot(current) !== queueSnapshot(baseCtx)) {
|
|
86
|
+
throw new GeneralError('Patch queue changed while waiting for confirmation or the lock. Re-run patch retire to review the current dependencies.');
|
|
87
|
+
}
|
|
88
|
+
await removePatchFileAndManifest(paths.patches, target.filename, slot);
|
|
89
|
+
await deleteCreatedFiles(paths.engine, claimed.deleteOnCommit);
|
|
90
|
+
await appendHistoryBestEffort(paths.patches, {
|
|
91
|
+
operation: 'patch-retire',
|
|
92
|
+
args: {
|
|
93
|
+
filename: target.filename,
|
|
94
|
+
order: target.order,
|
|
95
|
+
filesAffected: target.filesAffected,
|
|
96
|
+
...(claimed.deleteOnCommit.length > 0
|
|
97
|
+
? { deletedCreatedFiles: claimed.deleteOnCommit }
|
|
98
|
+
: {}),
|
|
99
|
+
...(options.reason !== undefined ? { reason: options.reason } : {}),
|
|
100
|
+
},
|
|
101
|
+
...(options.yes === true ? { yes: true } : {}),
|
|
102
|
+
...(options.forceUnsafe === true ? { unsafeOverride: true } : {}),
|
|
103
|
+
result: 'ok',
|
|
104
|
+
}, `patch retire committed (${target.filename})`);
|
|
105
|
+
}, { waitLockSeconds, command: 'patch retire' }));
|
|
106
|
+
info(`Retired ${target.filename}; order ${order} is kept as a retired slot.`);
|
|
107
|
+
if ((await loadConfig(projectRoot)).patchPolicy?.allowGaps !== false) {
|
|
108
|
+
info('patchPolicy.allowGaps is not false, so no check reads the retired slot; ' +
|
|
109
|
+
'"patch delete" would have had the same effect on this queue.');
|
|
110
|
+
}
|
|
111
|
+
outro('Retire complete');
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Registers the `patch retire` subcommand on the `patch` parent.
|
|
115
|
+
*
|
|
116
|
+
* @param parent - Parent Commander command
|
|
117
|
+
* @param context - Shared CLI registration context
|
|
118
|
+
*/
|
|
119
|
+
export function registerPatchRetire(parent, context) {
|
|
120
|
+
const { getProjectRoot, withErrorHandling } = context;
|
|
121
|
+
const command = parent
|
|
122
|
+
.command('retire <name>')
|
|
123
|
+
.description('Remove a patch from the queue but keep its order number as a retired slot, ' +
|
|
124
|
+
'so patchPolicy.allowGaps: false sees no gap and no later patch is renumbered (destructive)')
|
|
125
|
+
.option('--reason <text>', 'Rationale recorded on the retired slot')
|
|
126
|
+
.option('--dry-run', 'Show what would happen without writing')
|
|
127
|
+
.option('-y, --yes', 'Skip confirmation prompt (required for non-TTY)')
|
|
128
|
+
.option('--delete-created', 'Also delete the engine files this patch creates that are still on disk, instead of leaving them unmanaged')
|
|
129
|
+
.option('--force-unsafe', 'Bypass the refusal when a later patch depends on this patch (last resort)');
|
|
130
|
+
addWaitLockOption(command).action(withErrorHandling(async (name, options) => {
|
|
131
|
+
await patchRetireCommand(getProjectRoot(), name, pickDefined(options));
|
|
132
|
+
}));
|
|
133
|
+
}
|
|
@@ -7,10 +7,12 @@
|
|
|
7
7
|
*/
|
|
8
8
|
import { type ConflictReport } from '../../core/destructive.js';
|
|
9
9
|
import type { PatchQueueContext } from '../../core/patch-lint-cross.js';
|
|
10
|
-
import type { PatchStagedForwardImport } from '../../types/commands/index.js';
|
|
10
|
+
import type { PatchLintIssue, PatchStagedForwardImport } from '../../types/commands/index.js';
|
|
11
11
|
import type { PatchCategory, PatchesManifest, PatchMetadata } from '../../types/commands/index.js';
|
|
12
12
|
import type { FireForgeConfig } from '../../types/config.js';
|
|
13
|
+
import type { DeclarationRenamer } from '../declarations-report.js';
|
|
13
14
|
import { type PlacementPlan } from '../export-flow.js';
|
|
15
|
+
import { type SplitStagedMaintenance } from './split-staged.js';
|
|
14
16
|
/** Everything the commit step needs, computed and confirmed up front. */
|
|
15
17
|
export interface SplitPlan {
|
|
16
18
|
source: PatchMetadata;
|
|
@@ -38,6 +40,11 @@ export interface SplitPlan {
|
|
|
38
40
|
* and persisted on commit so the real per-patch gate stays clean.
|
|
39
41
|
*/
|
|
40
42
|
stagedDependencyAdditions: Map<string, PatchStagedForwardImport[]>;
|
|
43
|
+
/**
|
|
44
|
+
* Declarations the move re-homes on the new patch or drops as made
|
|
45
|
+
* unused. Populated by {@link runProjectedSplitLint}.
|
|
46
|
+
*/
|
|
47
|
+
stagedMaintenance: SplitStagedMaintenance;
|
|
41
48
|
}
|
|
42
49
|
/**
|
|
43
50
|
* Refuses the split unless the source patch currently owns every requested
|
|
@@ -51,13 +58,6 @@ export declare function assertSourceOwnsFiles(source: PatchMetadata, files: read
|
|
|
51
58
|
* source patch so hunk context is correct for the new file set.
|
|
52
59
|
*/
|
|
53
60
|
export declare function buildSplitDiff(engineDir: string, files: readonly string[], label: string, sourceFilename: string): Promise<string>;
|
|
54
|
-
/**
|
|
55
|
-
* Finds patches declaring a staged-dependency forward-import whose `owner`
|
|
56
|
-
* is the source patch and whose `creates` path moves to the new patch.
|
|
57
|
-
*/
|
|
58
|
-
export declare function findOwnerRewriteHolders(patches: readonly PatchMetadata[], sourceFilename: string, movedSet: ReadonlySet<string>): string[];
|
|
59
|
-
/** Rewrites split-affected owners on one manifest row. */
|
|
60
|
-
export declare function rewriteSplitOwners(patch: PatchMetadata, sourceFilename: string, movedSet: ReadonlySet<string>, newFilename: string): PatchMetadata;
|
|
61
61
|
/** Merges `decls` into a patch's `stagedDependencies.forwardImports` (no duplicates). */
|
|
62
62
|
export declare function mergeStagedForwardImports(patch: PatchMetadata, decls: readonly PatchStagedForwardImport[]): PatchMetadata;
|
|
63
63
|
/**
|
|
@@ -69,7 +69,9 @@ export declare function mergeStagedForwardImports(patch: PatchMetadata, decls: r
|
|
|
69
69
|
*/
|
|
70
70
|
export declare function runProjectedSplitLint(plan: SplitPlan, baseCtx: PatchQueueContext): {
|
|
71
71
|
conflicts: ConflictReport | null;
|
|
72
|
+
regressions: PatchLintIssue[];
|
|
72
73
|
stagedDependencyAdditions: Map<string, PatchStagedForwardImport[]>;
|
|
74
|
+
stagedMaintenance: SplitStagedMaintenance;
|
|
73
75
|
};
|
|
74
76
|
/** Builds the projected manifest for policy enforcement. */
|
|
75
77
|
export declare function projectSplitManifest(manifest: {
|
|
@@ -86,3 +88,10 @@ export declare function buildNewPatchMetadata(plan: SplitPlan, config: FireForge
|
|
|
86
88
|
* shown by `--dry-run` and by the destructive-operation confirmation prompt.
|
|
87
89
|
*/
|
|
88
90
|
export declare function buildSplitSummary(plan: SplitPlan): string[];
|
|
91
|
+
/**
|
|
92
|
+
* Maps a declaration the split projection proposes back onto the queue as
|
|
93
|
+
* it stands: renumbered patches take their current names, and an owner
|
|
94
|
+
* that is the patch the split would create is dropped (it does not exist
|
|
95
|
+
* until the split runs).
|
|
96
|
+
*/
|
|
97
|
+
export declare function splitDeclarationRenamer(plan: SplitPlan): DeclarationRenamer;
|
|
@@ -20,6 +20,7 @@ import { pathExists } from '../../utils/fs.js';
|
|
|
20
20
|
import { warn } from '../../utils/logger.js';
|
|
21
21
|
import {} from '../export-flow.js';
|
|
22
22
|
import { projectEntryBody } from './entry-projection.js';
|
|
23
|
+
import { describeStagedMaintenance, findDeclarationsMadeUnused, keptRelocatedDeclarations, relocatedSourceDeclarations, rewriteSplitOwners, withoutRelocatedDeclarations, } from './split-staged.js';
|
|
23
24
|
/**
|
|
24
25
|
* Refuses the split unless the source patch currently owns every requested
|
|
25
26
|
* file. Splitting out a file the source does not own would produce a new patch
|
|
@@ -58,29 +59,6 @@ export async function buildSplitDiff(engineDir, files, label, sourceFilename) {
|
|
|
58
59
|
}
|
|
59
60
|
return diff;
|
|
60
61
|
}
|
|
61
|
-
/**
|
|
62
|
-
* Finds patches declaring a staged-dependency forward-import whose `owner`
|
|
63
|
-
* is the source patch and whose `creates` path moves to the new patch.
|
|
64
|
-
*/
|
|
65
|
-
export function findOwnerRewriteHolders(patches, sourceFilename, movedSet) {
|
|
66
|
-
return patches
|
|
67
|
-
.filter((patch) => (patch.stagedDependencies?.forwardImports ?? []).some((fi) => fi.owner === sourceFilename && movedSet.has(fi.creates)))
|
|
68
|
-
.map((patch) => patch.filename);
|
|
69
|
-
}
|
|
70
|
-
/** Rewrites split-affected owners on one manifest row. */
|
|
71
|
-
export function rewriteSplitOwners(patch, sourceFilename, movedSet, newFilename) {
|
|
72
|
-
const forwardImports = patch.stagedDependencies?.forwardImports;
|
|
73
|
-
if (!forwardImports?.some((fi) => fi.owner === sourceFilename && movedSet.has(fi.creates))) {
|
|
74
|
-
return patch;
|
|
75
|
-
}
|
|
76
|
-
return {
|
|
77
|
-
...patch,
|
|
78
|
-
stagedDependencies: {
|
|
79
|
-
...patch.stagedDependencies,
|
|
80
|
-
forwardImports: forwardImports.map((fi) => fi.owner === sourceFilename && movedSet.has(fi.creates) ? { ...fi, owner: newFilename } : fi),
|
|
81
|
-
},
|
|
82
|
-
};
|
|
83
|
-
}
|
|
84
62
|
/** Builds the projected post-split queue entries (renumber + shrunken source + new patch). */
|
|
85
63
|
function buildProjectedSplitEntries(baseCtx, plan) {
|
|
86
64
|
const movedSet = new Set(plan.movedFiles);
|
|
@@ -90,6 +68,9 @@ function buildProjectedSplitEntries(baseCtx, plan) {
|
|
|
90
68
|
if (metadata) {
|
|
91
69
|
metadata = rewriteStagedDependencyOwners(metadata, ownerLookup);
|
|
92
70
|
metadata = rewriteSplitOwners(metadata, plan.source.filename, movedSet, plan.placement.newFilename);
|
|
71
|
+
if (entry.filename === plan.source.filename) {
|
|
72
|
+
metadata = withoutRelocatedDeclarations(metadata, movedSet);
|
|
73
|
+
}
|
|
93
74
|
}
|
|
94
75
|
const rename = plan.placement.renameMap.get(entry.filename);
|
|
95
76
|
const base = rename
|
|
@@ -99,10 +80,26 @@ function buildProjectedSplitEntries(baseCtx, plan) {
|
|
|
99
80
|
return base;
|
|
100
81
|
return { ...base, ...projectEntryBody(plan.remainingDiff) };
|
|
101
82
|
});
|
|
83
|
+
// Declarations whose declaring file moved travel with it, so the new
|
|
84
|
+
// patch's projected entry carries them (and only then needs metadata).
|
|
85
|
+
const relocated = relocatedSourceDeclarations(plan.source, movedSet, ownerLookup);
|
|
86
|
+
const hasRelocated = (relocated.forwardImports?.length ?? 0) + (relocated.registrations?.length ?? 0) > 0;
|
|
102
87
|
entries.push({
|
|
103
88
|
filename: plan.placement.newFilename,
|
|
104
89
|
order: plan.placement.insertionOrder,
|
|
105
|
-
metadata:
|
|
90
|
+
metadata: hasRelocated
|
|
91
|
+
? {
|
|
92
|
+
filename: plan.placement.newFilename,
|
|
93
|
+
order: plan.placement.insertionOrder,
|
|
94
|
+
category: plan.category,
|
|
95
|
+
name: plan.name,
|
|
96
|
+
description: plan.description,
|
|
97
|
+
createdAt: '',
|
|
98
|
+
sourceEsrVersion: plan.source.sourceEsrVersion,
|
|
99
|
+
filesAffected: plan.movedFiles,
|
|
100
|
+
stagedDependencies: relocated,
|
|
101
|
+
}
|
|
102
|
+
: null,
|
|
106
103
|
...projectEntryBody(plan.movedDiff),
|
|
107
104
|
});
|
|
108
105
|
entries.sort((a, b) => a.order - b.order || a.filename.localeCompare(b.filename));
|
|
@@ -184,13 +181,29 @@ export function runProjectedSplitLint(plan, baseCtx) {
|
|
|
184
181
|
// the new patch, then inject them before linting so they resolve.
|
|
185
182
|
const stagedDependencyAdditions = computeSplitStagedDependencyAdditions(projectedEntries, plan.placement.newFilename);
|
|
186
183
|
injectStagedDependencyAdditions(projectedEntries, stagedDependencyAdditions);
|
|
187
|
-
const
|
|
188
|
-
const
|
|
184
|
+
const baselineAll = lintPatchQueue(baseCtx);
|
|
185
|
+
const projectedAll = lintPatchQueue({
|
|
189
186
|
entries: projectedEntries,
|
|
190
187
|
// Keep the projection patch-policy-aware whenever the baseline is, so
|
|
191
188
|
// computeProjectedLintRegressions compares symmetric rule sets.
|
|
192
189
|
...(baseCtx.patchPolicy ? { patchPolicy: baseCtx.patchPolicy } : {}),
|
|
193
|
-
})
|
|
190
|
+
});
|
|
191
|
+
const baselineIssues = baselineAll.filter((i) => i.severity === 'error');
|
|
192
|
+
const projectedIssues = projectedAll.filter((i) => i.severity === 'error');
|
|
193
|
+
const oldNameByNew = new Map([...plan.placement.renameMap].map(([oldName, entry]) => [entry.newFilename, oldName]));
|
|
194
|
+
const stagedMaintenance = {
|
|
195
|
+
relocated: relocatedSourceDeclarations(plan.source, new Set(plan.movedFiles), (old) => plan.placement.renameMap.get(old)?.newFilename),
|
|
196
|
+
dropped: findDeclarationsMadeUnused({
|
|
197
|
+
baselineEntries: baseCtx.entries,
|
|
198
|
+
projectedEntries,
|
|
199
|
+
baselineIssues: baselineAll,
|
|
200
|
+
projectedIssues: projectedAll,
|
|
201
|
+
sourceFilename: plan.source.filename,
|
|
202
|
+
newFilename: plan.placement.newFilename,
|
|
203
|
+
mapBack: (name) => oldNameByNew.get(name) ?? name,
|
|
204
|
+
movedSet: new Set(plan.movedFiles),
|
|
205
|
+
}),
|
|
206
|
+
};
|
|
194
207
|
const regressions = computeProjectedLintRegressions(baselineIssues, projectedIssues);
|
|
195
208
|
if (baselineIssues.length > 0 && regressions.length === 0) {
|
|
196
209
|
warn(`Note: projected queue still has ${baselineIssues.length} pre-existing cross-patch ` +
|
|
@@ -202,7 +215,7 @@ export function runProjectedSplitLint(plan, baseCtx) {
|
|
|
202
215
|
reason: `split would introduce ${regressions.length} cross-patch lint error(s)`,
|
|
203
216
|
details: regressions.map(formatPatchLintIssue),
|
|
204
217
|
};
|
|
205
|
-
return { conflicts, stagedDependencyAdditions };
|
|
218
|
+
return { conflicts, regressions, stagedDependencyAdditions, stagedMaintenance };
|
|
206
219
|
}
|
|
207
220
|
/** Builds the projected manifest for policy enforcement. */
|
|
208
221
|
export function projectSplitManifest(manifest, plan, newMetadata) {
|
|
@@ -222,6 +235,8 @@ export function projectSplitManifest(manifest, plan, newMetadata) {
|
|
|
222
235
|
* source's provenance (product, version, category) onto the new patch.
|
|
223
236
|
*/
|
|
224
237
|
export function buildNewPatchMetadata(plan, config) {
|
|
238
|
+
const staged = keptRelocatedDeclarations(plan.stagedMaintenance, plan.placement.newFilename);
|
|
239
|
+
const hasStaged = (staged.forwardImports?.length ?? 0) + (staged.registrations?.length ?? 0) > 0;
|
|
225
240
|
return {
|
|
226
241
|
filename: plan.placement.newFilename,
|
|
227
242
|
order: plan.placement.insertionOrder,
|
|
@@ -231,6 +246,7 @@ export function buildNewPatchMetadata(plan, config) {
|
|
|
231
246
|
createdAt: new Date().toISOString(),
|
|
232
247
|
...buildPatchSourceMetadata(config.firefox),
|
|
233
248
|
filesAffected: plan.movedFiles,
|
|
249
|
+
...(hasStaged ? { stagedDependencies: staged } : {}),
|
|
234
250
|
};
|
|
235
251
|
}
|
|
236
252
|
/**
|
|
@@ -253,5 +269,21 @@ export function buildSplitSummary(plan) {
|
|
|
253
269
|
if (plan.ownerRewrites.length > 0) {
|
|
254
270
|
summary.push(`staged-dependency owners re-pointed to the new patch in: ${plan.ownerRewrites.join(', ')}`);
|
|
255
271
|
}
|
|
272
|
+
summary.push(...describeStagedMaintenance(plan.stagedMaintenance, plan.source.filename, plan.placement.newFilename));
|
|
256
273
|
return summary;
|
|
257
274
|
}
|
|
275
|
+
/**
|
|
276
|
+
* Maps a declaration the split projection proposes back onto the queue as
|
|
277
|
+
* it stands: renumbered patches take their current names, and an owner
|
|
278
|
+
* that is the patch the split would create is dropped (it does not exist
|
|
279
|
+
* until the split runs).
|
|
280
|
+
*/
|
|
281
|
+
export function splitDeclarationRenamer(plan) {
|
|
282
|
+
const oldNameByNew = new Map([...plan.placement.renameMap].map(([oldName, entry]) => [entry.newFilename, oldName]));
|
|
283
|
+
const current = (name) => oldNameByNew.get(name) ?? name;
|
|
284
|
+
return ({ owner, ...declaration }) => ({
|
|
285
|
+
...declaration,
|
|
286
|
+
patch: current(declaration.patch),
|
|
287
|
+
...(owner !== plan.placement.newFilename ? { owner: current(owner) } : {}),
|
|
288
|
+
});
|
|
289
|
+
}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Staged-dependency upkeep for `patch split` and `patch move-files
|
|
3
|
+
* --create`: the declarations a file move invalidates.
|
|
4
|
+
*
|
|
5
|
+
* Moving files into a new patch changes three kinds of declaration:
|
|
6
|
+
*
|
|
7
|
+
* - an `owner` that named the source for a `creates` path that moved now
|
|
8
|
+
* names the new patch (both kinds, see {@link rewriteSplitOwners});
|
|
9
|
+
* - a declaration the source holds for a site in a moved file belongs to
|
|
10
|
+
* the new patch, because the importing or registering line moved with
|
|
11
|
+
* the file ({@link relocatedSourceDeclarations});
|
|
12
|
+
* - a declaration that was in use before the move and is not after it
|
|
13
|
+
* (the new patch now applies before the importer, or the importer and
|
|
14
|
+
* the imported file landed in one patch) is dropped
|
|
15
|
+
* ({@link findDeclarationsMadeUnused}).
|
|
16
|
+
*
|
|
17
|
+
* Without this the move wrote the bodies and left the queue audit and the
|
|
18
|
+
* per-patch lint to report `queue-dependency-creates-unowned` and
|
|
19
|
+
* `staged-dependency-unused` afterwards, one `--remove`/`--add` pair per
|
|
20
|
+
* entry to repair by hand.
|
|
21
|
+
*/
|
|
22
|
+
import type { PatchQueueEntry } from '../../core/patch-lint.js';
|
|
23
|
+
import type { PatchLintIssue, PatchMetadata, PatchStagedDependencies, PatchStagedForwardImport, PatchStagedRegistration } from '../../types/commands/index.js';
|
|
24
|
+
/** One declaration of either kind. */
|
|
25
|
+
export type StagedDeclaration = PatchStagedForwardImport | PatchStagedRegistration;
|
|
26
|
+
/** A declaration the move made unused, named by its post-move holder. */
|
|
27
|
+
export interface DroppedStagedDeclaration {
|
|
28
|
+
/** Holder patch filename after the move (and any renumber). */
|
|
29
|
+
holder: string;
|
|
30
|
+
/** The declaration as the projected queue holds it. */
|
|
31
|
+
declaration: StagedDeclaration;
|
|
32
|
+
}
|
|
33
|
+
/** Declaration changes a split or `move-files --create` commits. */
|
|
34
|
+
export interface SplitStagedMaintenance {
|
|
35
|
+
/** Source declarations whose declaring file moved, re-homed on the new patch. */
|
|
36
|
+
relocated: PatchStagedDependencies;
|
|
37
|
+
/** Declarations in use before the move and unused after it. */
|
|
38
|
+
dropped: DroppedStagedDeclaration[];
|
|
39
|
+
}
|
|
40
|
+
/** An empty maintenance plan. */
|
|
41
|
+
export declare function emptyStagedMaintenance(): SplitStagedMaintenance;
|
|
42
|
+
/**
|
|
43
|
+
* The source's declarations whose declaring file moves, with owners passed
|
|
44
|
+
* through `ownerLookup` (the renumber the placement implies).
|
|
45
|
+
*
|
|
46
|
+
* @param source - The source patch's current manifest row
|
|
47
|
+
* @param movedSet - Files moving to the new patch
|
|
48
|
+
* @param ownerLookup - Old → new filename for renumbered patches
|
|
49
|
+
*/
|
|
50
|
+
export declare function relocatedSourceDeclarations(source: PatchMetadata, movedSet: ReadonlySet<string>, ownerLookup: (oldFilename: string) => string | undefined): PatchStagedDependencies;
|
|
51
|
+
/**
|
|
52
|
+
* Removes from the source row the declarations whose declaring file moved
|
|
53
|
+
* (they are re-homed on the new patch).
|
|
54
|
+
*/
|
|
55
|
+
export declare function withoutRelocatedDeclarations(source: PatchMetadata, movedSet: ReadonlySet<string>): PatchMetadata;
|
|
56
|
+
/**
|
|
57
|
+
* Re-points `owner` from the source to the new patch on every declaration
|
|
58
|
+
* (forward-import and registration alike) whose `creates` path moved.
|
|
59
|
+
*/
|
|
60
|
+
export declare function rewriteSplitOwners(patch: PatchMetadata, sourceFilename: string, movedSet: ReadonlySet<string>, newFilename: string): PatchMetadata;
|
|
61
|
+
/**
|
|
62
|
+
* Finds patches holding a declaration (either kind) whose `owner` is the
|
|
63
|
+
* source patch and whose `creates` path moves to the new patch.
|
|
64
|
+
*/
|
|
65
|
+
export declare function findOwnerRewriteHolders(patches: readonly PatchMetadata[], sourceFilename: string, movedSet: ReadonlySet<string>): string[];
|
|
66
|
+
/** Inputs to {@link findDeclarationsMadeUnused}. */
|
|
67
|
+
export interface MadeUnusedInput {
|
|
68
|
+
/** Queue entries before the move. */
|
|
69
|
+
baselineEntries: readonly PatchQueueEntry[];
|
|
70
|
+
/** Queue entries after the move, relocations and owner rewrites applied. */
|
|
71
|
+
projectedEntries: readonly PatchQueueEntry[];
|
|
72
|
+
/** Every finding of the baseline queue lint (all severities). */
|
|
73
|
+
baselineIssues: readonly PatchLintIssue[];
|
|
74
|
+
/** Every finding of the projected queue lint (all severities). */
|
|
75
|
+
projectedIssues: readonly PatchLintIssue[];
|
|
76
|
+
/** Source patch filename before the move. */
|
|
77
|
+
sourceFilename: string;
|
|
78
|
+
/** The new patch's filename. */
|
|
79
|
+
newFilename: string;
|
|
80
|
+
/** Projected → pre-move filename for renumbered patches. */
|
|
81
|
+
mapBack: (projectedFilename: string) => string;
|
|
82
|
+
/** Files moving to the new patch. */
|
|
83
|
+
movedSet: ReadonlySet<string>;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Declarations the projected queue reports `staged-dependency-unused` for
|
|
87
|
+
* that the baseline queue did not: the ones the move itself made unused.
|
|
88
|
+
* Only declarations the move touches are candidates (their `creates` path
|
|
89
|
+
* moved, or they were re-homed on the new patch), so pre-existing stale
|
|
90
|
+
* declarations elsewhere are left for the operator.
|
|
91
|
+
*/
|
|
92
|
+
export declare function findDeclarationsMadeUnused(input: MadeUnusedInput): DroppedStagedDeclaration[];
|
|
93
|
+
/**
|
|
94
|
+
* Removes the dropped declarations held by `patch` (matched by its
|
|
95
|
+
* post-move filename and the declaration's projected identity).
|
|
96
|
+
*/
|
|
97
|
+
export declare function withoutDroppedDeclarations(patch: PatchMetadata, dropped: readonly DroppedStagedDeclaration[]): PatchMetadata;
|
|
98
|
+
/** The relocated declarations the new patch keeps (relocated minus dropped). */
|
|
99
|
+
export declare function keptRelocatedDeclarations(maintenance: SplitStagedMaintenance, newFilename: string): PatchStagedDependencies;
|
|
100
|
+
/**
|
|
101
|
+
* Operator-facing lines naming every declaration the move re-homes or
|
|
102
|
+
* drops. Empty when the move touches no declaration.
|
|
103
|
+
*
|
|
104
|
+
* @param maintenance - The planned changes
|
|
105
|
+
* @param sourceFilename - Source patch filename
|
|
106
|
+
* @param newFilename - The new patch's filename
|
|
107
|
+
*/
|
|
108
|
+
export declare function describeStagedMaintenance(maintenance: SplitStagedMaintenance, sourceFilename: string, newFilename: string): string[];
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
// SPDX-License-Identifier: EUPL-1.2
|
|
2
|
+
/**
|
|
3
|
+
* Staged-dependency upkeep for `patch split` and `patch move-files
|
|
4
|
+
* --create`: the declarations a file move invalidates.
|
|
5
|
+
*
|
|
6
|
+
* Moving files into a new patch changes three kinds of declaration:
|
|
7
|
+
*
|
|
8
|
+
* - an `owner` that named the source for a `creates` path that moved now
|
|
9
|
+
* names the new patch (both kinds, see {@link rewriteSplitOwners});
|
|
10
|
+
* - a declaration the source holds for a site in a moved file belongs to
|
|
11
|
+
* the new patch, because the importing or registering line moved with
|
|
12
|
+
* the file ({@link relocatedSourceDeclarations});
|
|
13
|
+
* - a declaration that was in use before the move and is not after it
|
|
14
|
+
* (the new patch now applies before the importer, or the importer and
|
|
15
|
+
* the imported file landed in one patch) is dropped
|
|
16
|
+
* ({@link findDeclarationsMadeUnused}).
|
|
17
|
+
*
|
|
18
|
+
* Without this the move wrote the bodies and left the queue audit and the
|
|
19
|
+
* per-patch lint to report `queue-dependency-creates-unowned` and
|
|
20
|
+
* `staged-dependency-unused` afterwards, one `--remove`/`--add` pair per
|
|
21
|
+
* entry to repair by hand.
|
|
22
|
+
*/
|
|
23
|
+
import { stagedDependencyUnusedFingerprint } from '../../core/patch-lint-staged-registration.js';
|
|
24
|
+
/** An empty maintenance plan. */
|
|
25
|
+
export function emptyStagedMaintenance() {
|
|
26
|
+
return { relocated: {}, dropped: [] };
|
|
27
|
+
}
|
|
28
|
+
function declarationsOf(staged) {
|
|
29
|
+
return [...(staged?.forwardImports ?? []), ...(staged?.registrations ?? [])];
|
|
30
|
+
}
|
|
31
|
+
function matcherOf(declaration) {
|
|
32
|
+
return 'specifier' in declaration ? `i:${declaration.specifier}` : `r:${declaration.line}`;
|
|
33
|
+
}
|
|
34
|
+
/** Identity of a declaration, owner included. */
|
|
35
|
+
function declarationKey(declaration) {
|
|
36
|
+
return [
|
|
37
|
+
declaration.file,
|
|
38
|
+
matcherOf(declaration),
|
|
39
|
+
declaration.creates,
|
|
40
|
+
declaration.owner ?? '',
|
|
41
|
+
].join('\0');
|
|
42
|
+
}
|
|
43
|
+
/** Identity without the owner, which a renumber or split may rewrite. */
|
|
44
|
+
function declarationSiteKey(declaration) {
|
|
45
|
+
return [declaration.file, matcherOf(declaration), declaration.creates].join('\0');
|
|
46
|
+
}
|
|
47
|
+
function rebuildStaged(staged, keep, rewrite = (declaration) => declaration) {
|
|
48
|
+
const forwardImports = (staged?.forwardImports ?? [])
|
|
49
|
+
.filter(keep)
|
|
50
|
+
.map((entry) => rewrite(entry));
|
|
51
|
+
const registrations = (staged?.registrations ?? [])
|
|
52
|
+
.filter(keep)
|
|
53
|
+
.map((entry) => rewrite(entry));
|
|
54
|
+
return {
|
|
55
|
+
...(forwardImports.length > 0 ? { forwardImports } : {}),
|
|
56
|
+
...(registrations.length > 0 ? { registrations } : {}),
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
function hasDeclarations(staged) {
|
|
60
|
+
return declarationsOf(staged).length > 0;
|
|
61
|
+
}
|
|
62
|
+
/** Writes `staged` onto `patch`, dropping the field when it is empty. */
|
|
63
|
+
function withStaged(patch, staged) {
|
|
64
|
+
if (hasDeclarations(staged))
|
|
65
|
+
return { ...patch, stagedDependencies: staged };
|
|
66
|
+
if (patch.stagedDependencies === undefined)
|
|
67
|
+
return patch;
|
|
68
|
+
const rest = { ...patch };
|
|
69
|
+
delete rest.stagedDependencies;
|
|
70
|
+
return rest;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* The source's declarations whose declaring file moves, with owners passed
|
|
74
|
+
* through `ownerLookup` (the renumber the placement implies).
|
|
75
|
+
*
|
|
76
|
+
* @param source - The source patch's current manifest row
|
|
77
|
+
* @param movedSet - Files moving to the new patch
|
|
78
|
+
* @param ownerLookup - Old → new filename for renumbered patches
|
|
79
|
+
*/
|
|
80
|
+
export function relocatedSourceDeclarations(source, movedSet, ownerLookup) {
|
|
81
|
+
return rebuildStaged(source.stagedDependencies, (declaration) => movedSet.has(declaration.file), (declaration) => {
|
|
82
|
+
const owner = declaration.owner === undefined ? undefined : ownerLookup(declaration.owner);
|
|
83
|
+
return owner === undefined ? { ...declaration } : { ...declaration, owner };
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Removes from the source row the declarations whose declaring file moved
|
|
88
|
+
* (they are re-homed on the new patch).
|
|
89
|
+
*/
|
|
90
|
+
export function withoutRelocatedDeclarations(source, movedSet) {
|
|
91
|
+
if (!declarationsOf(source.stagedDependencies).some((d) => movedSet.has(d.file)))
|
|
92
|
+
return source;
|
|
93
|
+
return withStaged(source, rebuildStaged(source.stagedDependencies, (declaration) => !movedSet.has(declaration.file)));
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Re-points `owner` from the source to the new patch on every declaration
|
|
97
|
+
* (forward-import and registration alike) whose `creates` path moved.
|
|
98
|
+
*/
|
|
99
|
+
export function rewriteSplitOwners(patch, sourceFilename, movedSet, newFilename) {
|
|
100
|
+
const matches = (declaration) => declaration.owner === sourceFilename && movedSet.has(declaration.creates);
|
|
101
|
+
if (!declarationsOf(patch.stagedDependencies).some(matches))
|
|
102
|
+
return patch;
|
|
103
|
+
return {
|
|
104
|
+
...patch,
|
|
105
|
+
stagedDependencies: {
|
|
106
|
+
...patch.stagedDependencies,
|
|
107
|
+
...rebuildStaged(patch.stagedDependencies, () => true, (declaration) => matches(declaration) ? { ...declaration, owner: newFilename } : declaration),
|
|
108
|
+
},
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Finds patches holding a declaration (either kind) whose `owner` is the
|
|
113
|
+
* source patch and whose `creates` path moves to the new patch.
|
|
114
|
+
*/
|
|
115
|
+
export function findOwnerRewriteHolders(patches, sourceFilename, movedSet) {
|
|
116
|
+
return patches
|
|
117
|
+
.filter((patch) => declarationsOf(patch.stagedDependencies).some((declaration) => declaration.owner === sourceFilename && movedSet.has(declaration.creates)))
|
|
118
|
+
.map((patch) => patch.filename);
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Declarations the projected queue reports `staged-dependency-unused` for
|
|
122
|
+
* that the baseline queue did not: the ones the move itself made unused.
|
|
123
|
+
* Only declarations the move touches are candidates (their `creates` path
|
|
124
|
+
* moved, or they were re-homed on the new patch), so pre-existing stale
|
|
125
|
+
* declarations elsewhere are left for the operator.
|
|
126
|
+
*/
|
|
127
|
+
export function findDeclarationsMadeUnused(input) {
|
|
128
|
+
const unusedFingerprints = (issues) => new Set(issues
|
|
129
|
+
.filter((issue) => issue.check === 'staged-dependency-unused')
|
|
130
|
+
.map((issue) => issue.fingerprint ?? ''));
|
|
131
|
+
const baselineUnused = unusedFingerprints(input.baselineIssues);
|
|
132
|
+
const projectedUnused = unusedFingerprints(input.projectedIssues);
|
|
133
|
+
const baselineByHolder = new Map(input.baselineEntries.map((entry) => [entry.filename, entry.metadata]));
|
|
134
|
+
const dropped = [];
|
|
135
|
+
for (const entry of input.projectedEntries) {
|
|
136
|
+
const isNewPatch = entry.filename === input.newFilename;
|
|
137
|
+
for (const declaration of declarationsOf(entry.metadata?.stagedDependencies)) {
|
|
138
|
+
if (!isNewPatch && !input.movedSet.has(declaration.creates))
|
|
139
|
+
continue;
|
|
140
|
+
if (!projectedUnused.has(stagedDependencyUnusedFingerprint(entry.filename, declaration))) {
|
|
141
|
+
continue;
|
|
142
|
+
}
|
|
143
|
+
const originalHolder = isNewPatch ? input.sourceFilename : input.mapBack(entry.filename);
|
|
144
|
+
const original = declarationsOf(baselineByHolder.get(originalHolder)?.stagedDependencies).find((candidate) => declarationSiteKey(candidate) === declarationSiteKey(declaration));
|
|
145
|
+
if (original !== undefined &&
|
|
146
|
+
baselineUnused.has(stagedDependencyUnusedFingerprint(originalHolder, original))) {
|
|
147
|
+
continue;
|
|
148
|
+
}
|
|
149
|
+
dropped.push({ holder: entry.filename, declaration });
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
return dropped;
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Removes the dropped declarations held by `patch` (matched by its
|
|
156
|
+
* post-move filename and the declaration's projected identity).
|
|
157
|
+
*/
|
|
158
|
+
export function withoutDroppedDeclarations(patch, dropped) {
|
|
159
|
+
const keys = new Set(dropped
|
|
160
|
+
.filter((entry) => entry.holder === patch.filename)
|
|
161
|
+
.map((entry) => declarationKey(entry.declaration)));
|
|
162
|
+
if (keys.size === 0)
|
|
163
|
+
return patch;
|
|
164
|
+
return withStaged(patch, rebuildStaged(patch.stagedDependencies, (declaration) => !keys.has(declarationKey(declaration))));
|
|
165
|
+
}
|
|
166
|
+
/** The relocated declarations the new patch keeps (relocated minus dropped). */
|
|
167
|
+
export function keptRelocatedDeclarations(maintenance, newFilename) {
|
|
168
|
+
const keys = new Set(maintenance.dropped
|
|
169
|
+
.filter((entry) => entry.holder === newFilename)
|
|
170
|
+
.map((entry) => declarationKey(entry.declaration)));
|
|
171
|
+
return rebuildStaged(maintenance.relocated, (declaration) => !keys.has(declarationKey(declaration)));
|
|
172
|
+
}
|
|
173
|
+
function describeDeclaration(declaration) {
|
|
174
|
+
return 'specifier' in declaration
|
|
175
|
+
? `${declaration.file} imports "${declaration.specifier}" (${declaration.creates})`
|
|
176
|
+
: `${declaration.file} registers "${declaration.line}" (${declaration.creates})`;
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Operator-facing lines naming every declaration the move re-homes or
|
|
180
|
+
* drops. Empty when the move touches no declaration.
|
|
181
|
+
*
|
|
182
|
+
* @param maintenance - The planned changes
|
|
183
|
+
* @param sourceFilename - Source patch filename
|
|
184
|
+
* @param newFilename - The new patch's filename
|
|
185
|
+
*/
|
|
186
|
+
export function describeStagedMaintenance(maintenance, sourceFilename, newFilename) {
|
|
187
|
+
const lines = [];
|
|
188
|
+
const kept = declarationsOf(keptRelocatedDeclarations(maintenance, newFilename));
|
|
189
|
+
if (kept.length > 0) {
|
|
190
|
+
lines.push(`staged-dependency declarations moved from ${sourceFilename} to ${newFilename} (${kept.length}):`);
|
|
191
|
+
for (const declaration of kept)
|
|
192
|
+
lines.push(` ${describeDeclaration(declaration)}`);
|
|
193
|
+
}
|
|
194
|
+
if (maintenance.dropped.length > 0) {
|
|
195
|
+
lines.push(`staged-dependency declarations dropped because the move made them unused (${maintenance.dropped.length}):`);
|
|
196
|
+
for (const { holder, declaration } of maintenance.dropped) {
|
|
197
|
+
const shownHolder = holder === newFilename ? `${sourceFilename} → ${newFilename}` : holder;
|
|
198
|
+
lines.push(` ${shownHolder}: ${describeDeclaration(declaration)}`);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
return lines;
|
|
202
|
+
}
|
|
@@ -19,6 +19,11 @@ import type { CommandContext } from '../../types/cli.js';
|
|
|
19
19
|
import type { PatchMetadata, PatchSplitOptions } from '../../types/commands/index.js';
|
|
20
20
|
import type { FireForgeConfig } from '../../types/config.js';
|
|
21
21
|
import { type SplitPlan } from './split-plan.js';
|
|
22
|
+
/**
|
|
23
|
+
* Prints the owner rewrites and the declarations the move re-homed or
|
|
24
|
+
* dropped, after a committed split or `move-files --create`.
|
|
25
|
+
*/
|
|
26
|
+
export declare function reportSplitStagedChanges(plan: SplitPlan): void;
|
|
22
27
|
/**
|
|
23
28
|
* Commits a confirmed split under the patch directory lock: renumber →
|
|
24
29
|
* write new patch body → write shrunken source body → single manifest
|