@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,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `patch staged-dependency --add --from <json-file>`: adds every
|
|
3
|
+
* declaration a file supplies for one patch in a single manifest update
|
|
4
|
+
* under one lock hold. The file format and the history delta live in
|
|
5
|
+
* `staged-dependency-batch.ts`.
|
|
6
|
+
*/
|
|
7
|
+
import type { PatchStagedDependencyOptions } from '../../types/commands/index.js';
|
|
8
|
+
import { type StagedDependencyMode } from './staged-dependency-entries.js';
|
|
9
|
+
/**
|
|
10
|
+
* `--add --from <json-file>`: every declaration the file supplies for the
|
|
11
|
+
* target patch, validated up front and written in one manifest update
|
|
12
|
+
* under one lock hold, with one delta history record.
|
|
13
|
+
*/
|
|
14
|
+
export declare function runBatchAdd(projectRoot: string, identifier: string, mode: StagedDependencyMode, options: PatchStagedDependencyOptions): Promise<void>;
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
// SPDX-License-Identifier: EUPL-1.2
|
|
2
|
+
/**
|
|
3
|
+
* `patch staged-dependency --add --from <json-file>`: adds every
|
|
4
|
+
* declaration a file supplies for one patch in a single manifest update
|
|
5
|
+
* under one lock hold. The file format and the history delta live in
|
|
6
|
+
* `staged-dependency-batch.ts`.
|
|
7
|
+
*/
|
|
8
|
+
import { appendHistoryBestEffort } from '../../core/history-log.js';
|
|
9
|
+
import { mutatePatchMetadata } from '../../core/patch-export.js';
|
|
10
|
+
import { GeneralError, InvalidArgumentError } from '../../errors/base.js';
|
|
11
|
+
import { info, outro } from '../../utils/logger.js';
|
|
12
|
+
import { resolveWaitLockSeconds } from '../../utils/options.js';
|
|
13
|
+
import { requirePatchQueue, requirePatchTarget } from './patch-context.js';
|
|
14
|
+
import { readStagedDependencyBatch, stagedDependencyDelta, } from './staged-dependency-batch.js';
|
|
15
|
+
import { applyMode, countStagedEntries, importView, registrationView, } from './staged-dependency-entries.js';
|
|
16
|
+
import { validateStagedDependencyAdd } from './staged-dependency-validate.js';
|
|
17
|
+
/** Flags that describe one declaration and so cannot combine with `--from`. */
|
|
18
|
+
const SINGLE_DECLARATION_FLAGS = [
|
|
19
|
+
['--kind', 'kind'],
|
|
20
|
+
['--file', 'file'],
|
|
21
|
+
['--specifier', 'specifier'],
|
|
22
|
+
['--line', 'line'],
|
|
23
|
+
['--creates', 'creates'],
|
|
24
|
+
['--owner', 'owner'],
|
|
25
|
+
];
|
|
26
|
+
/** Adds every `--from` declaration not already present, keyed like a single `--add`. */
|
|
27
|
+
function mergeBatch(staged, batch) {
|
|
28
|
+
let forwardImports = [...(staged?.forwardImports ?? [])];
|
|
29
|
+
for (const entry of batch.forwardImports) {
|
|
30
|
+
forwardImports = applyMode(forwardImports, 'add', importView(entry), importView, entry);
|
|
31
|
+
}
|
|
32
|
+
let registrations = [...(staged?.registrations ?? [])];
|
|
33
|
+
for (const entry of batch.registrations) {
|
|
34
|
+
registrations = applyMode(registrations, 'add', registrationView(entry), registrationView, entry);
|
|
35
|
+
}
|
|
36
|
+
return {
|
|
37
|
+
...(forwardImports.length > 0 ? { forwardImports } : {}),
|
|
38
|
+
...(registrations.length > 0 ? { registrations } : {}),
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* `--add --from <json-file>`: every declaration the file supplies for the
|
|
43
|
+
* target patch, validated up front and written in one manifest update
|
|
44
|
+
* under one lock hold, with one delta history record.
|
|
45
|
+
*/
|
|
46
|
+
export async function runBatchAdd(projectRoot, identifier, mode, options) {
|
|
47
|
+
const from = options.from ?? '';
|
|
48
|
+
if (mode !== 'add') {
|
|
49
|
+
throw new InvalidArgumentError('--from only applies to --add.', '--from');
|
|
50
|
+
}
|
|
51
|
+
const clashing = SINGLE_DECLARATION_FLAGS.filter(([, key]) => options[key] !== undefined);
|
|
52
|
+
if (clashing.length > 0) {
|
|
53
|
+
throw new InvalidArgumentError(`--from supplies the declarations itself; drop ${clashing.map(([flag]) => flag).join(', ')}.`, '--from');
|
|
54
|
+
}
|
|
55
|
+
const { paths, manifest } = await requirePatchQueue(projectRoot);
|
|
56
|
+
const targetPatch = requirePatchTarget(identifier, manifest.patches);
|
|
57
|
+
const batch = await readStagedDependencyBatch(from, targetPatch.filename, options.reason);
|
|
58
|
+
for (const entry of [...batch.forwardImports, ...batch.registrations]) {
|
|
59
|
+
validateStagedDependencyAdd(entry, manifest.patches);
|
|
60
|
+
}
|
|
61
|
+
const supplied = batch.forwardImports.length + batch.registrations.length;
|
|
62
|
+
if (batch.skippedForOtherPatches > 0) {
|
|
63
|
+
info(`Skipped ${batch.skippedForOtherPatches} declaration(s) in ${from} that name another patch.`);
|
|
64
|
+
}
|
|
65
|
+
if (supplied === 0) {
|
|
66
|
+
info(`${from} holds no declarations for ${targetPatch.filename}; nothing to add.`);
|
|
67
|
+
outro('Patch staged-dependency complete');
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
const existing = targetPatch.stagedDependencies;
|
|
71
|
+
const projectedCount = countStagedEntries(mergeBatch(existing, batch));
|
|
72
|
+
const describe = (beforeCount, afterCount) => `added ${afterCount - beforeCount} of ${supplied} staged declaration(s) from ${from}` +
|
|
73
|
+
(supplied > afterCount - beforeCount
|
|
74
|
+
? ` (${supplied - (afterCount - beforeCount)} already present or repeated)`
|
|
75
|
+
: '');
|
|
76
|
+
if (options.dryRun === true) {
|
|
77
|
+
info(`[dry-run] ${targetPatch.filename}: ${describe(countStagedEntries(existing), projectedCount)}.`);
|
|
78
|
+
outro('Dry run complete — no changes made');
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
const result = await mutatePatchMetadata(paths.patches, targetPatch.filename, (current) => {
|
|
82
|
+
const after = mergeBatch(current.stagedDependencies, batch);
|
|
83
|
+
if (countStagedEntries(after) === 0)
|
|
84
|
+
return { unset: ['stagedDependencies'] };
|
|
85
|
+
return { set: { stagedDependencies: after } };
|
|
86
|
+
}, {
|
|
87
|
+
waitLockSeconds: resolveWaitLockSeconds(options.waitLock),
|
|
88
|
+
command: 'patch staged-dependency',
|
|
89
|
+
});
|
|
90
|
+
if (!result) {
|
|
91
|
+
throw new GeneralError(`Patch ${targetPatch.filename} disappeared from the manifest during the update. Re-run after investigating.`);
|
|
92
|
+
}
|
|
93
|
+
const before = result.before.stagedDependencies;
|
|
94
|
+
const after = result.after.stagedDependencies;
|
|
95
|
+
info(`${targetPatch.filename}: ${describe(countStagedEntries(before), countStagedEntries(after))}.`);
|
|
96
|
+
await appendHistoryBestEffort(paths.patches, {
|
|
97
|
+
operation: 'patch-staged-dependency',
|
|
98
|
+
args: {
|
|
99
|
+
filename: targetPatch.filename,
|
|
100
|
+
mode,
|
|
101
|
+
from,
|
|
102
|
+
...stagedDependencyDelta(before, after),
|
|
103
|
+
},
|
|
104
|
+
...(options.yes === true ? { yes: true } : {}),
|
|
105
|
+
result: 'ok',
|
|
106
|
+
}, `patch staged-dependency committed (${targetPatch.filename})`);
|
|
107
|
+
outro('Patch staged-dependency complete');
|
|
108
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `--remove` target selection for `patch staged-dependency`. Split out of
|
|
3
|
+
* `staged-dependency.ts` for the per-file line budget.
|
|
4
|
+
*
|
|
5
|
+
* A removal names its entries by any of `--file`, `--specifier`/`--line`,
|
|
6
|
+
* `--creates` and `--owner`, and must give at least `--creates` or the
|
|
7
|
+
* `--file` + matcher pair. Registration lines compare whitespace-
|
|
8
|
+
* insensitively (runs of whitespace collapse, ends trimmed), the way the
|
|
9
|
+
* lint compares them, so a line copied from a patch hunk matches the stored
|
|
10
|
+
* one whatever its padding. A selection that matches nothing is refused
|
|
11
|
+
* rather than reported as a no-op.
|
|
12
|
+
*/
|
|
13
|
+
import type { PatchStagedDependencies, PatchStagedDependencyOptions } from '../../types/commands/index.js';
|
|
14
|
+
import { type StagedDependencyKind, type StagedEntryView } from './staged-dependency-entries.js';
|
|
15
|
+
/**
|
|
16
|
+
* Resolves the staged entries a `--remove` invocation names. The returned
|
|
17
|
+
* views are the stored entries themselves, so the removal matches them
|
|
18
|
+
* exactly.
|
|
19
|
+
*
|
|
20
|
+
* - `--file` + matcher identifying one entry infers `--creates`.
|
|
21
|
+
* - `--file` + matcher identifying several entries without `--creates`
|
|
22
|
+
* refuses with the candidate list.
|
|
23
|
+
* - `--creates` alone selects every declaration for that created path.
|
|
24
|
+
*
|
|
25
|
+
* @param kind - Declaration kind (`--kind`)
|
|
26
|
+
* @param options - Command options
|
|
27
|
+
* @param staged - The target patch's current staged dependencies
|
|
28
|
+
* @returns The matching stored entries (never empty)
|
|
29
|
+
* @throws InvalidArgumentError when the selectors are insufficient or match nothing
|
|
30
|
+
*/
|
|
31
|
+
export declare function selectRemovalEntries(kind: StagedDependencyKind, options: PatchStagedDependencyOptions, staged: PatchStagedDependencies | undefined): StagedEntryView[];
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
// SPDX-License-Identifier: EUPL-1.2
|
|
2
|
+
/**
|
|
3
|
+
* `--remove` target selection for `patch staged-dependency`. Split out of
|
|
4
|
+
* `staged-dependency.ts` for the per-file line budget.
|
|
5
|
+
*
|
|
6
|
+
* A removal names its entries by any of `--file`, `--specifier`/`--line`,
|
|
7
|
+
* `--creates` and `--owner`, and must give at least `--creates` or the
|
|
8
|
+
* `--file` + matcher pair. Registration lines compare whitespace-
|
|
9
|
+
* insensitively (runs of whitespace collapse, ends trimmed), the way the
|
|
10
|
+
* lint compares them, so a line copied from a patch hunk matches the stored
|
|
11
|
+
* one whatever its padding. A selection that matches nothing is refused
|
|
12
|
+
* rather than reported as a no-op.
|
|
13
|
+
*/
|
|
14
|
+
import { GeneralError, InvalidArgumentError } from '../../errors/base.js';
|
|
15
|
+
import { info } from '../../utils/logger.js';
|
|
16
|
+
import { dependencyLabel, importView, registrationView, } from './staged-dependency-entries.js';
|
|
17
|
+
/** Collapses whitespace runs and trims, for registration-line comparison. */
|
|
18
|
+
function normalizeRegistrationLine(line) {
|
|
19
|
+
return line.trim().replace(/\s+/g, ' ');
|
|
20
|
+
}
|
|
21
|
+
function stagedViews(kind, staged) {
|
|
22
|
+
return kind === 'import'
|
|
23
|
+
? (staged?.forwardImports ?? []).map(importView)
|
|
24
|
+
: (staged?.registrations ?? []).map(registrationView);
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Resolves the staged entries a `--remove` invocation names. The returned
|
|
28
|
+
* views are the stored entries themselves, so the removal matches them
|
|
29
|
+
* exactly.
|
|
30
|
+
*
|
|
31
|
+
* - `--file` + matcher identifying one entry infers `--creates`.
|
|
32
|
+
* - `--file` + matcher identifying several entries without `--creates`
|
|
33
|
+
* refuses with the candidate list.
|
|
34
|
+
* - `--creates` alone selects every declaration for that created path.
|
|
35
|
+
*
|
|
36
|
+
* @param kind - Declaration kind (`--kind`)
|
|
37
|
+
* @param options - Command options
|
|
38
|
+
* @param staged - The target patch's current staged dependencies
|
|
39
|
+
* @returns The matching stored entries (never empty)
|
|
40
|
+
* @throws InvalidArgumentError when the selectors are insufficient or match nothing
|
|
41
|
+
*/
|
|
42
|
+
export function selectRemovalEntries(kind, options, staged) {
|
|
43
|
+
const matcherFlag = kind === 'import' ? '--specifier' : '--line';
|
|
44
|
+
const matcher = kind === 'import' ? options.specifier : options.line;
|
|
45
|
+
const hasPair = Boolean(options.file) && Boolean(matcher);
|
|
46
|
+
if (!options.creates && !hasPair) {
|
|
47
|
+
throw new InvalidArgumentError(`--remove${kind === 'registration' ? ' --kind registration' : ''} requires --creates, ` +
|
|
48
|
+
`or --file with ${matcherFlag}; --creates alone removes every declaration for that path.`, matcher && !options.file
|
|
49
|
+
? '--file'
|
|
50
|
+
: options.file && !matcher
|
|
51
|
+
? matcherFlag
|
|
52
|
+
: `--creates or --file + ${matcherFlag}`);
|
|
53
|
+
}
|
|
54
|
+
const wanted = matcher === undefined ? undefined : comparableMatcher(kind, matcher);
|
|
55
|
+
const views = stagedViews(kind, staged);
|
|
56
|
+
const candidates = views.filter((view) => (!options.file || view.file === options.file) &&
|
|
57
|
+
(wanted === undefined || comparableMatcher(kind, view.matcher) === wanted) &&
|
|
58
|
+
(!options.creates || view.creates === options.creates) &&
|
|
59
|
+
(options.owner === undefined || view.owner === options.owner));
|
|
60
|
+
if (candidates.length === 0) {
|
|
61
|
+
const noun = kind === 'import' ? 'staged forward-import' : 'staged registration';
|
|
62
|
+
const existing = views.length === 0
|
|
63
|
+
? `This patch has no ${noun}s.`
|
|
64
|
+
: `This patch's ${noun}s:\n${views.map((view) => ` - ${dependencyLabel(kind, view)}`).join('\n')}`;
|
|
65
|
+
throw new InvalidArgumentError(`--remove matched no ${noun}. ${existing}`, '--remove');
|
|
66
|
+
}
|
|
67
|
+
if (candidates.length > 1 && !options.creates) {
|
|
68
|
+
const list = candidates.map((view) => ` - ${dependencyLabel(kind, view)}`).join('\n');
|
|
69
|
+
const noun = kind === 'import' ? 'staged forward-imports' : 'staged registrations';
|
|
70
|
+
throw new GeneralError(`--remove matches ${candidates.length} ${noun} on this patch; pass --creates to pick one:\n${list}`);
|
|
71
|
+
}
|
|
72
|
+
const single = candidates.length === 1 ? candidates[0] : undefined;
|
|
73
|
+
if (single !== undefined && !options.creates) {
|
|
74
|
+
info(`Inferred --creates ${single.creates} from the single matching staged entry.`);
|
|
75
|
+
}
|
|
76
|
+
return candidates;
|
|
77
|
+
}
|
|
78
|
+
function comparableMatcher(kind, matcher) {
|
|
79
|
+
return kind === 'registration' ? normalizeRegistrationLine(matcher) : matcher;
|
|
80
|
+
}
|
|
@@ -10,6 +10,10 @@ import { GeneralError, InvalidArgumentError } from '../../errors/base.js';
|
|
|
10
10
|
import { info, intro, outro } from '../../utils/logger.js';
|
|
11
11
|
import { addWaitLockOption, resolveWaitLockSeconds } from '../../utils/options.js';
|
|
12
12
|
import { requirePatchQueue, requirePatchTarget } from './patch-context.js';
|
|
13
|
+
import { stagedDependencyDelta } from './staged-dependency-batch.js';
|
|
14
|
+
import { applyMode, countStagedEntries, dependencyLabel, importView, registrationView, } from './staged-dependency-entries.js';
|
|
15
|
+
import { runBatchAdd } from './staged-dependency-from.js';
|
|
16
|
+
import { selectRemovalEntries } from './staged-dependency-remove.js';
|
|
13
17
|
import { validateStagedDependencyAdd } from './staged-dependency-validate.js';
|
|
14
18
|
/** Joins the names of the missing flags for error attribution. */
|
|
15
19
|
function missingFlagList(pairs) {
|
|
@@ -82,128 +86,27 @@ function requireRegistrationOptions(options) {
|
|
|
82
86
|
dependency.reason = options.reason;
|
|
83
87
|
return dependency;
|
|
84
88
|
}
|
|
85
|
-
/**
|
|
86
|
-
* Resolves the `--remove` target for forward-imports:
|
|
87
|
-
* `--file` + `--specifier` suffice when they identify at most one staged
|
|
88
|
-
* entry. `--creates` is inferred from a unique match, an ambiguous match
|
|
89
|
-
* refuses with the candidate list, and no match falls through to the
|
|
90
|
-
* honest "no staged forward-import matched" summary.
|
|
91
|
-
*/
|
|
92
|
-
function resolveImportRemovalTarget(options, staged) {
|
|
93
|
-
if (!options.file || !options.specifier) {
|
|
94
|
-
throw new InvalidArgumentError('--remove requires --file and --specifier; --creates is only needed to disambiguate when several staged entries share them.', missingFlagList([
|
|
95
|
-
['--file', options.file],
|
|
96
|
-
['--specifier', options.specifier],
|
|
97
|
-
]));
|
|
98
|
-
}
|
|
99
|
-
if (options.creates) {
|
|
100
|
-
return requireForwardImportOptions(options);
|
|
101
|
-
}
|
|
102
|
-
const { file, specifier } = options;
|
|
103
|
-
const candidates = (staged?.forwardImports ?? []).filter((entry) => entry.file === file &&
|
|
104
|
-
entry.specifier === specifier &&
|
|
105
|
-
(options.owner === undefined || entry.owner === options.owner));
|
|
106
|
-
const single = candidates.length === 1 ? candidates[0] : undefined;
|
|
107
|
-
if (single !== undefined) {
|
|
108
|
-
info(`Inferred --creates ${single.creates} from the single matching staged entry.`);
|
|
109
|
-
return { ...single };
|
|
110
|
-
}
|
|
111
|
-
if (candidates.length > 1) {
|
|
112
|
-
const list = candidates
|
|
113
|
-
.map((entry) => ` - ${dependencyLabel('import', importView(entry))}`)
|
|
114
|
-
.join('\n');
|
|
115
|
-
throw new GeneralError(`--remove matches ${candidates.length} staged forward-imports on this patch; ` +
|
|
116
|
-
`pass --creates to pick one:\n${list}`);
|
|
117
|
-
}
|
|
118
|
-
return { file, specifier, creates: '(no match)' };
|
|
119
|
-
}
|
|
120
|
-
/** Registration twin of {@link resolveImportRemovalTarget}, keyed on `--line`. */
|
|
121
|
-
function resolveRegistrationRemovalTarget(options, staged) {
|
|
122
|
-
if (!options.file || !options.line) {
|
|
123
|
-
throw new InvalidArgumentError('--remove --kind registration requires --file and --line; --creates is only needed to disambiguate when several staged entries share them.', missingFlagList([
|
|
124
|
-
['--file', options.file],
|
|
125
|
-
['--line', options.line],
|
|
126
|
-
]));
|
|
127
|
-
}
|
|
128
|
-
if (options.creates) {
|
|
129
|
-
return requireRegistrationOptions(options);
|
|
130
|
-
}
|
|
131
|
-
const { file, line } = options;
|
|
132
|
-
const candidates = (staged?.registrations ?? []).filter((entry) => entry.file === file &&
|
|
133
|
-
entry.line === line &&
|
|
134
|
-
(options.owner === undefined || entry.owner === options.owner));
|
|
135
|
-
const single = candidates.length === 1 ? candidates[0] : undefined;
|
|
136
|
-
if (single !== undefined) {
|
|
137
|
-
info(`Inferred --creates ${single.creates} from the single matching staged entry.`);
|
|
138
|
-
return { ...single };
|
|
139
|
-
}
|
|
140
|
-
if (candidates.length > 1) {
|
|
141
|
-
const list = candidates
|
|
142
|
-
.map((entry) => ` - ${dependencyLabel('registration', registrationView(entry))}`)
|
|
143
|
-
.join('\n');
|
|
144
|
-
throw new GeneralError(`--remove matches ${candidates.length} staged registrations on this patch; ` +
|
|
145
|
-
`pass --creates to pick one:\n${list}`);
|
|
146
|
-
}
|
|
147
|
-
return { file, line, creates: '(no match)' };
|
|
148
|
-
}
|
|
149
|
-
function importView(dependency) {
|
|
150
|
-
return { ...dependency, matcher: dependency.specifier };
|
|
151
|
-
}
|
|
152
|
-
function registrationView(dependency) {
|
|
153
|
-
return { ...dependency, matcher: dependency.line };
|
|
154
|
-
}
|
|
155
|
-
function dependencyKey(view) {
|
|
156
|
-
return [view.file, view.matcher, view.creates, view.owner ?? ''].join('\0');
|
|
157
|
-
}
|
|
158
|
-
function dependencyLabel(kind, view) {
|
|
159
|
-
const owner = view.owner ? ` owner=${view.owner}` : '';
|
|
160
|
-
const reason = view.reason ? ` reason="${view.reason}"` : '';
|
|
161
|
-
if (kind === 'import') {
|
|
162
|
-
return `${view.file} imports "${view.matcher}" from ${view.creates}${owner}${reason}`;
|
|
163
|
-
}
|
|
164
|
-
return `${view.file} registers "${view.matcher}" for ${view.creates}${owner}${reason}`;
|
|
165
|
-
}
|
|
166
|
-
function matchesTarget(view, target) {
|
|
167
|
-
return (view.file === target.file &&
|
|
168
|
-
view.matcher === target.matcher &&
|
|
169
|
-
view.creates === target.creates &&
|
|
170
|
-
(target.owner === undefined || view.owner === target.owner));
|
|
171
|
-
}
|
|
172
|
-
function applyMode(existing, mode, target, toView, addition) {
|
|
173
|
-
if (mode === 'clear')
|
|
174
|
-
return [];
|
|
175
|
-
if (!target)
|
|
176
|
-
return [...existing];
|
|
177
|
-
if (mode === 'remove')
|
|
178
|
-
return existing.filter((entry) => !matchesTarget(toView(entry), target));
|
|
179
|
-
const seen = new Set(existing.map((entry) => dependencyKey(toView(entry))));
|
|
180
|
-
if (seen.has(dependencyKey(target)) || addition === undefined)
|
|
181
|
-
return [...existing];
|
|
182
|
-
return [...existing, addition];
|
|
183
|
-
}
|
|
184
89
|
/**
|
|
185
90
|
* Renders a one-line summary of a staged-dependency metadata change.
|
|
186
91
|
*/
|
|
187
|
-
function describeStagedDependencyChange(beforeCount, afterCount, mode, kind,
|
|
92
|
+
function describeStagedDependencyChange(beforeCount, afterCount, mode, kind, targets) {
|
|
188
93
|
const noun = kind === 'import' ? 'staged forward-import' : 'staged registration';
|
|
189
94
|
if (mode === 'clear') {
|
|
190
95
|
return beforeCount === 0
|
|
191
96
|
? 'stagedDependencies was already empty — no change'
|
|
192
97
|
: `cleared ${beforeCount} staged dependency declaration(s)`;
|
|
193
98
|
}
|
|
194
|
-
|
|
99
|
+
const label = targets.map((target) => dependencyLabel(kind, target)).join('; ');
|
|
100
|
+
if (targets.length === 0)
|
|
195
101
|
return 'stagedDependencies unchanged';
|
|
196
102
|
if (mode === 'add') {
|
|
197
103
|
return afterCount === beforeCount
|
|
198
|
-
? `${noun} already present: ${
|
|
199
|
-
: `added ${noun}: ${
|
|
104
|
+
? `${noun} already present: ${label}`
|
|
105
|
+
: `added ${noun}: ${label}`;
|
|
200
106
|
}
|
|
201
107
|
return afterCount === beforeCount
|
|
202
|
-
? `no ${noun} matched: ${
|
|
203
|
-
: `removed ${beforeCount - afterCount} ${noun} declaration(s): ${
|
|
204
|
-
}
|
|
205
|
-
function countStagedEntries(staged) {
|
|
206
|
-
return (staged?.forwardImports?.length ?? 0) + (staged?.registrations?.length ?? 0);
|
|
108
|
+
? `no ${noun} matched: ${label}`
|
|
109
|
+
: `removed ${beforeCount - afterCount} ${noun} declaration(s): ${label}`;
|
|
207
110
|
}
|
|
208
111
|
/**
|
|
209
112
|
* Runs the metadata-only staged-dependency mutation command.
|
|
@@ -216,41 +119,44 @@ export async function patchStagedDependencyCommand(projectRoot, identifier, opti
|
|
|
216
119
|
const isDryRun = options.dryRun === true;
|
|
217
120
|
intro(isDryRun ? 'FireForge patch staged-dependency (dry run)' : 'FireForge patch staged-dependency');
|
|
218
121
|
const mode = modeFromOptions(options);
|
|
122
|
+
if (options.from !== undefined) {
|
|
123
|
+
await runBatchAdd(projectRoot, identifier, mode, options);
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
219
126
|
const kind = kindFromOptions(options);
|
|
220
127
|
// The patch queue loads before the declaration fields resolve so
|
|
221
128
|
// `--remove` can infer `--creates` from the target patch's staged
|
|
222
129
|
// entries.
|
|
223
130
|
const { paths, manifest } = await requirePatchQueue(projectRoot);
|
|
224
131
|
const targetPatch = requirePatchTarget(identifier, manifest.patches);
|
|
225
|
-
const importDependency = mode === '
|
|
226
|
-
|
|
227
|
-
: mode === 'add'
|
|
228
|
-
? requireForwardImportOptions(options)
|
|
229
|
-
: resolveImportRemovalTarget(options, targetPatch.stagedDependencies);
|
|
230
|
-
const registrationDependency = mode === 'clear' || kind !== 'registration'
|
|
231
|
-
? undefined
|
|
232
|
-
: mode === 'add'
|
|
233
|
-
? requireRegistrationOptions(options)
|
|
234
|
-
: resolveRegistrationRemovalTarget(options, targetPatch.stagedDependencies);
|
|
132
|
+
const importDependency = mode === 'add' && kind === 'import' ? requireForwardImportOptions(options) : undefined;
|
|
133
|
+
const registrationDependency = mode === 'add' && kind === 'registration' ? requireRegistrationOptions(options) : undefined;
|
|
235
134
|
// Shape-check --add declarations against the loaded queue: a
|
|
236
135
|
// patch-name-shaped --creates/--file is refused now instead of surfacing
|
|
237
136
|
// later as an undischargeable staged-dependency-unused.
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
137
|
+
const added = importDependency ?? registrationDependency;
|
|
138
|
+
if (added !== undefined) {
|
|
139
|
+
validateStagedDependencyAdd(added, manifest.patches);
|
|
140
|
+
}
|
|
141
|
+
const targets = mode === 'remove'
|
|
142
|
+
? selectRemovalEntries(kind, options, targetPatch.stagedDependencies)
|
|
143
|
+
: importDependency !== undefined
|
|
144
|
+
? [importView(importDependency)]
|
|
145
|
+
: registrationDependency !== undefined
|
|
146
|
+
? [registrationView(registrationDependency)]
|
|
147
|
+
: [];
|
|
148
|
+
const applyKind = (entries, own, toView, addition) => {
|
|
149
|
+
if (!own)
|
|
150
|
+
return [...entries];
|
|
151
|
+
if (mode !== 'remove')
|
|
152
|
+
return applyMode(entries, mode, targets[0], toView, addition);
|
|
153
|
+
return targets.reduce((remaining, target) => applyMode(remaining, 'remove', target, toView, undefined), [...entries]);
|
|
154
|
+
};
|
|
249
155
|
const applyToStaged = (staged) => {
|
|
250
156
|
if (mode === 'clear')
|
|
251
157
|
return {};
|
|
252
|
-
const forwardImports =
|
|
253
|
-
const registrations =
|
|
158
|
+
const forwardImports = applyKind(staged?.forwardImports ?? [], kind === 'import', importView, importDependency);
|
|
159
|
+
const registrations = applyKind(staged?.registrations ?? [], kind === 'registration', registrationView, registrationDependency);
|
|
254
160
|
return {
|
|
255
161
|
...(forwardImports.length > 0 ? { forwardImports } : {}),
|
|
256
162
|
...(registrations.length > 0 ? { registrations } : {}),
|
|
@@ -258,7 +164,7 @@ export async function patchStagedDependencyCommand(projectRoot, identifier, opti
|
|
|
258
164
|
};
|
|
259
165
|
const existing = targetPatch.stagedDependencies;
|
|
260
166
|
const projected = applyToStaged(existing);
|
|
261
|
-
const summary = describeStagedDependencyChange(countStagedEntries(existing), countStagedEntries(projected), mode, kind,
|
|
167
|
+
const summary = describeStagedDependencyChange(countStagedEntries(existing), countStagedEntries(projected), mode, kind, targets);
|
|
262
168
|
if (isDryRun) {
|
|
263
169
|
info(`[dry-run] ${targetPatch.filename}: ${summary}.`);
|
|
264
170
|
outro('Dry run complete — no changes made');
|
|
@@ -278,15 +184,21 @@ export async function patchStagedDependencyCommand(projectRoot, identifier, opti
|
|
|
278
184
|
}
|
|
279
185
|
const before = result.before.stagedDependencies;
|
|
280
186
|
const after = result.after.stagedDependencies;
|
|
281
|
-
info(`${targetPatch.filename}: ${describeStagedDependencyChange(countStagedEntries(before), countStagedEntries(after), mode, kind,
|
|
187
|
+
info(`${targetPatch.filename}: ${describeStagedDependencyChange(countStagedEntries(before), countStagedEntries(after), mode, kind, targets)}.`);
|
|
188
|
+
if (mode === 'remove' && countStagedEntries(after) === countStagedEntries(before)) {
|
|
189
|
+
// The selection matched when the queue was read; a peer removed the
|
|
190
|
+
// entries before the locked write. Still a miss, so still a refusal.
|
|
191
|
+
throw new InvalidArgumentError(`${targetPatch.filename}: the selected staged declaration(s) were already gone when the manifest was written.`, '--remove');
|
|
192
|
+
}
|
|
282
193
|
await appendHistoryBestEffort(paths.patches, {
|
|
283
194
|
operation: 'patch-staged-dependency',
|
|
195
|
+
// Only the delta: the whole list on both sides grew the log
|
|
196
|
+
// quadratically with the list (see staged-dependency-batch.ts).
|
|
284
197
|
args: {
|
|
285
198
|
filename: targetPatch.filename,
|
|
286
199
|
mode,
|
|
287
200
|
kind,
|
|
288
|
-
before
|
|
289
|
-
after: after ?? {},
|
|
201
|
+
...stagedDependencyDelta(before, after),
|
|
290
202
|
},
|
|
291
203
|
...(options.yes === true ? { yes: true } : {}),
|
|
292
204
|
result: 'ok',
|
|
@@ -305,15 +217,18 @@ export function registerPatchStagedDependency(parent, context) {
|
|
|
305
217
|
.command('staged-dependency <name>')
|
|
306
218
|
.description('Edit PatchMetadata.stagedDependencies on a single patch (no .patch body rewrite).')
|
|
307
219
|
.option('--add', 'Add a staged dependency declaration')
|
|
308
|
-
.option('--remove', 'Remove matching staged dependency declaration(s)')
|
|
220
|
+
.option('--remove', 'Remove matching staged dependency declaration(s); a selection that matches nothing exits 8')
|
|
309
221
|
.option('--clear', 'Drop the stagedDependencies field entirely')
|
|
310
222
|
.option('--kind <kind>', 'Declaration shape: "import" (forward import, the default) or "registration" (jar.mn packaging line, customElements or actor registration)')
|
|
311
223
|
.option('--file <path>', 'Declaring file path relative to engine/')
|
|
312
224
|
.option('--specifier <specifier>', 'Exact import specifier as it appears in source (--kind import)')
|
|
313
|
-
.option('--line <text>', 'Registration/packaging line as the patch adds it, compared whitespace-
|
|
314
|
-
.option('--creates <path>', 'Later-created file path relative to engine/')
|
|
225
|
+
.option('--line <text>', 'Registration/packaging line as the patch adds it, compared whitespace-insensitively (--kind registration)')
|
|
226
|
+
.option('--creates <path>', 'Later-created file path relative to engine/ (with --remove and no --file: removes every declaration for that path)')
|
|
315
227
|
.option('--owner <patch>', 'Exact later patch filename expected to create --creates')
|
|
316
|
-
.option('--reason <text>', 'Human-readable rationale stored with the declaration')
|
|
228
|
+
.option('--reason <text>', 'Human-readable rationale stored with the declaration (with --from: the default for entries without one)')
|
|
229
|
+
.option('--from <json-file>', 'Add every declaration in a JSON file under one lock hold (--add only): a "lint --per-patch --report" ' +
|
|
230
|
+
"document (its findings' stagedDeclarations for this patch) or an array of " +
|
|
231
|
+
'{ file, specifier | line, creates, owner?, reason?, patch? } entries')
|
|
317
232
|
.option('--dry-run', 'Show what would change without writing')
|
|
318
233
|
.option('-y, --yes', 'Record scripted consent in the destructive-operation history log. This command never prompts; the flag exists for workflow uniformity with commands that do.');
|
|
319
234
|
addWaitLockOption(command).action(withErrorHandling(async (name, options) => {
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/** One changed engine file a registration line the patch adds names. */
|
|
2
|
+
export interface RegisteredChangedFile {
|
|
3
|
+
/** Engine-relative path of the named file. */
|
|
4
|
+
file: string;
|
|
5
|
+
/** Engine-relative path of the carrier whose added line names it. */
|
|
6
|
+
carrier: string;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Lists the changed (modified, deleted or untracked) engine files named by
|
|
10
|
+
* the registration lines the patch's owned carriers add relative to HEAD.
|
|
11
|
+
* Only added lines count: an upstream line naming an upstream file is not
|
|
12
|
+
* the patch's registration. A wildcard token is matched against the changed
|
|
13
|
+
* files under its carrier's directory, the only place such a token reaches
|
|
14
|
+
* without the build system.
|
|
15
|
+
*
|
|
16
|
+
* @param engineDir - Engine checkout
|
|
17
|
+
* @param ownedFiles - The patch's current filesAffected
|
|
18
|
+
* @returns Named changed files, first carrier wins, sorted by path
|
|
19
|
+
*/
|
|
20
|
+
export declare function findRegisteredChangedFiles(engineDir: string, ownedFiles: readonly string[]): Promise<RegisteredChangedFile[]>;
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
// SPDX-License-Identifier: EUPL-1.2
|
|
2
|
+
/**
|
|
3
|
+
* The registration arm of the scan-less re-export adjacency belt.
|
|
4
|
+
*
|
|
5
|
+
* A file the patch registers (a jar.mn, moz.build or test-manifest line the
|
|
6
|
+
* patch adds names it) belongs with the patch even when it lives in another
|
|
7
|
+
* directory, so an unmanaged one is adjacent in the sense that matters: the
|
|
8
|
+
* refreshed body would ship a registration for a file it leaves out. This
|
|
9
|
+
* module answers which changed engine files those lines name. The caller
|
|
10
|
+
* filters out owned, claimed and tool-managed paths.
|
|
11
|
+
*
|
|
12
|
+
* Split out of re-export-adjacent.ts to keep that module about the
|
|
13
|
+
* classification, not the carrier parsing.
|
|
14
|
+
*/
|
|
15
|
+
import { dirname } from 'node:path';
|
|
16
|
+
import { getDiffForFilesAgainstHead } from '../core/git-diff.js';
|
|
17
|
+
import { getDirtyFiles, getModifiedFilesInDir, getUntrackedFilesInDir, } from '../core/git-status.js';
|
|
18
|
+
import { extractAddedLinesPerFile } from '../core/patch-lint-diff.js';
|
|
19
|
+
import { isRegistrationCarrier, resolveCarrierReferences, } from '../core/patch-lint-forward-registration-extended.js';
|
|
20
|
+
import { normalizePathSlashes } from '../utils/paths.js';
|
|
21
|
+
/**
|
|
22
|
+
* Lists the changed (modified, deleted or untracked) engine files named by
|
|
23
|
+
* the registration lines the patch's owned carriers add relative to HEAD.
|
|
24
|
+
* Only added lines count: an upstream line naming an upstream file is not
|
|
25
|
+
* the patch's registration. A wildcard token is matched against the changed
|
|
26
|
+
* files under its carrier's directory, the only place such a token reaches
|
|
27
|
+
* without the build system.
|
|
28
|
+
*
|
|
29
|
+
* @param engineDir - Engine checkout
|
|
30
|
+
* @param ownedFiles - The patch's current filesAffected
|
|
31
|
+
* @returns Named changed files, first carrier wins, sorted by path
|
|
32
|
+
*/
|
|
33
|
+
export async function findRegisteredChangedFiles(engineDir, ownedFiles) {
|
|
34
|
+
const carriers = ownedFiles.filter(isRegistrationCarrier);
|
|
35
|
+
if (carriers.length === 0)
|
|
36
|
+
return [];
|
|
37
|
+
const diff = await getDiffForFilesAgainstHead(engineDir, carriers);
|
|
38
|
+
const exactToCarrier = new Map();
|
|
39
|
+
const wildcardsByCarrier = new Map();
|
|
40
|
+
for (const [carrier, lines] of extractAddedLinesPerFile(diff)) {
|
|
41
|
+
for (const ref of resolveCarrierReferences(carrier, lines.join('\n'))) {
|
|
42
|
+
if (ref.exact !== undefined) {
|
|
43
|
+
if (!exactToCarrier.has(ref.exact))
|
|
44
|
+
exactToCarrier.set(ref.exact, carrier);
|
|
45
|
+
}
|
|
46
|
+
else {
|
|
47
|
+
const list = wildcardsByCarrier.get(carrier) ?? [];
|
|
48
|
+
list.push(ref.matches);
|
|
49
|
+
wildcardsByCarrier.set(carrier, list);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
const found = new Map();
|
|
54
|
+
if (exactToCarrier.size > 0) {
|
|
55
|
+
for (const file of await getDirtyFiles(engineDir, [...exactToCarrier.keys()])) {
|
|
56
|
+
const carrier = exactToCarrier.get(file);
|
|
57
|
+
if (carrier !== undefined)
|
|
58
|
+
found.set(file, carrier);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
for (const [carrier, matchers] of wildcardsByCarrier) {
|
|
62
|
+
const scope = normalizePathSlashes(dirname(carrier));
|
|
63
|
+
const [modified, untracked] = await Promise.all([
|
|
64
|
+
getModifiedFilesInDir(engineDir, scope),
|
|
65
|
+
getUntrackedFilesInDir(engineDir, scope),
|
|
66
|
+
]);
|
|
67
|
+
for (const file of [...modified, ...untracked]) {
|
|
68
|
+
if (!found.has(file) && matchers.some((matches) => matches(file)))
|
|
69
|
+
found.set(file, carrier);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
return [...found.entries()]
|
|
73
|
+
.map(([file, carrier]) => ({ file, carrier }))
|
|
74
|
+
.sort((a, b) => a.file.localeCompare(b.file));
|
|
75
|
+
}
|