@hominis/fireforge 0.49.2 → 0.50.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 +40 -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 +28 -0
- package/dist/src/commands/check-report.js +78 -0
- package/dist/src/commands/check-run.d.ts +28 -0
- package/dist/src/commands/check-run.js +104 -0
- package/dist/src/commands/check-steps.d.ts +67 -0
- package/dist/src/commands/check-steps.js +175 -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/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-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 +93 -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 +127 -114
- package/dist/src/commands/furnace/validation-output.js +14 -3
- package/dist/src/commands/lint-per-patch.js +31 -60
- package/dist/src/commands/lint-report.d.ts +8 -4
- package/dist/src/commands/lint-report.js +15 -5
- package/dist/src/commands/lint.js +15 -34
- package/dist/src/commands/manifest.js +2 -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 +13 -98
- package/dist/src/commands/patch/index.d.ts +1 -1
- package/dist/src/commands/patch/index.js +4 -2
- package/dist/src/commands/patch/lint-ignore.d.ts +5 -1
- package/dist/src/commands/patch/lint-ignore.js +65 -28
- package/dist/src/commands/patch/move-files-create.js +26 -17
- package/dist/src/commands/patch/move-files-into.js +5 -3
- package/dist/src/commands/patch/move-files.js +3 -1
- 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 +7 -0
- package/dist/src/commands/patch/retire.d.ts +34 -0
- package/dist/src/commands/patch/retire.js +128 -0
- package/dist/src/commands/patch/split-plan.d.ts +7 -7
- package/dist/src/commands/patch/split-plan.js +45 -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 +51 -15
- 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.js +14 -41
- 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 +45 -2
- package/dist/src/commands/re-export-adjacent.js +156 -37
- 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-lint.d.ts +2 -1
- package/dist/src/commands/re-export-lint.js +23 -10
- package/dist/src/commands/re-export-options.js +45 -4
- 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-register.js +42 -17
- package/dist/src/commands/re-export-removed.d.ts +12 -1
- package/dist/src/commands/re-export-removed.js +41 -11
- 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 +17 -9
- package/dist/src/commands/re-export-scan.js +56 -23
- package/dist/src/commands/re-export-single.js +22 -6
- 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 +37 -24
- 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 +21 -0
- package/dist/src/commands/test-build-furnace.js +48 -0
- package/dist/src/commands/test-build-phase.js +47 -41
- package/dist/src/commands/test-checkjs.js +7 -0
- package/dist/src/commands/test-diagnose.js +7 -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 +43 -0
- package/dist/src/commands/test-orchestrate.js +222 -0
- package/dist/src/commands/test-perf-scope.d.ts +29 -0
- package/dist/src/commands/test-perf-scope.js +83 -0
- package/dist/src/commands/test-prelock.d.ts +51 -0
- package/dist/src/commands/test-prelock.js +177 -0
- package/dist/src/commands/test-register.js +54 -10
- package/dist/src/commands/test-run.js +4 -1
- package/dist/src/commands/test-stale-gate.js +57 -27
- package/dist/src/commands/test-verdict.d.ts +10 -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 +66 -60
- package/dist/src/commands/token-lint.d.ts +14 -0
- package/dist/src/commands/token-lint.js +111 -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 +59 -35
- 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 +7 -0
- package/dist/src/core/build-prepare.js +14 -8
- 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 +8 -0
- package/dist/src/core/config-validate-check.d.ts +8 -0
- package/dist/src/core/config-validate-check.js +143 -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 +7 -0
- package/dist/src/core/config-validate-token-scales.d.ts +6 -0
- package/dist/src/core/config-validate-token-scales.js +50 -0
- package/dist/src/core/config-validate.js +14 -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 +97 -0
- package/dist/src/core/coverage-records.js +350 -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 +10 -1
- package/dist/src/core/engine-session-lock.js +28 -8
- 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.d.ts +4 -25
- package/dist/src/core/file-lock.js +105 -138
- 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 +12 -2
- 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 +9 -0
- package/dist/src/core/furnace-config-validate-exceptions.js +71 -0
- package/dist/src/core/furnace-config-validate.js +8 -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-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 +4 -2
- package/dist/src/core/furnace-validate-accessibility.js +10 -1
- package/dist/src/core/furnace-validate-exceptions.d.ts +40 -0
- package/dist/src/core/furnace-validate-exceptions.js +43 -0
- package/dist/src/core/furnace-validate-icon-button.d.ts +7 -0
- package/dist/src/core/furnace-validate-icon-button.js +49 -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 +157 -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/mach.js +8 -1
- package/dist/src/core/negative-control-diff.d.ts +39 -0
- package/dist/src/core/negative-control-diff.js +136 -0
- package/dist/src/core/negative-control.d.ts +138 -0
- package/dist/src/core/negative-control.js +356 -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/patch-export-update.d.ts +2 -0
- package/dist/src/core/patch-export-update.js +1 -0
- package/dist/src/core/patch-export.js +3 -4
- package/dist/src/core/patch-lint-checkjs-any-import.d.ts +37 -0
- package/dist/src/core/patch-lint-checkjs-any-import.js +61 -0
- package/dist/src/core/patch-lint-checkjs.js +8 -11
- 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.js +12 -4
- package/dist/src/core/patch-lint-css.d.ts +8 -2
- package/dist/src/core/patch-lint-css.js +10 -4
- 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 +18 -0
- package/dist/src/core/patch-lint-forward-registration-extended.js +35 -10
- package/dist/src/core/patch-lint-forward-registration.js +10 -0
- package/dist/src/core/patch-lint-ignore.d.ts +152 -0
- package/dist/src/core/patch-lint-ignore.js +299 -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 +323 -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 +39 -0
- package/dist/src/core/patch-lint-token-scale.js +109 -0
- package/dist/src/core/patch-lint.d.ts +11 -83
- package/dist/src/core/patch-lint.js +64 -286
- 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 +19 -8
- package/dist/src/core/patch-manifest-validate.js +34 -2
- package/dist/src/core/patch-order-legal.d.ts +25 -0
- package/dist/src/core/patch-order-legal.js +83 -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 +16 -3
- package/dist/src/core/patch-policy.js +16 -9
- package/dist/src/core/patch-retired.d.ts +35 -0
- package/dist/src/core/patch-retired.js +54 -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 +20 -0
- package/dist/src/core/run-log.js +89 -3
- 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 +18 -1
- package/dist/src/core/test-harness-crash.js +6 -4
- package/dist/src/core/test-harness-signature.d.ts +17 -0
- package/dist/src/core/test-harness-signature.js +4 -0
- package/dist/src/core/test-run-completeness.d.ts +57 -0
- package/dist/src/core/test-run-completeness.js +144 -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/token-lint.d.ts +50 -0
- package/dist/src/core/token-lint.js +126 -0
- package/dist/src/core/tree-guard.js +3 -0
- package/dist/src/core/typecheck-shim.d.ts +1 -1
- package/dist/src/core/typecheck-shim.js +90 -2
- package/dist/src/index.d.ts +8 -3
- package/dist/src/index.js +3 -1
- package/dist/src/types/commands/index.d.ts +2 -2
- package/dist/src/types/commands/options.d.ts +148 -21
- package/dist/src/types/commands/patches.d.ts +75 -1
- package/dist/src/types/config.d.ts +192 -0
- package/dist/src/types/config.js +9 -0
- package/dist/src/types/furnace.d.ts +43 -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 +34 -6
- package/dist/src/utils/options.js +86 -5
- 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 +282 -9
- package/docs/exit-codes.md +18 -1
- package/docs/furnace.md +97 -3
- package/docs/lifecycle-invariants.md +52 -19
- package/docs/machine-output.md +74 -12
- package/docs/patch-workflow.md +297 -22
- package/docs/run-logs.md +20 -1
- package/docs/testing.md +276 -20
- package/package.json +1 -1
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
* (`re-export-adjacent.ts`) warns about unmanaged neighbour files but is
|
|
10
10
|
* structurally blind to drift inside owned files. This module compares
|
|
11
11
|
* the old body against the refreshed body per file and reports the
|
|
12
|
-
* payload lines that are about to enter the body. Under
|
|
12
|
+
* payload lines that are about to enter or leave the body. Under
|
|
13
13
|
* `--refuse-foreign-drift` the patch is skipped and the run exits
|
|
14
14
|
* non-zero, mirroring `--refuse-adjacent-unmanaged`.
|
|
15
15
|
*
|
|
@@ -74,8 +74,15 @@ function multisetExcess(next, previous) {
|
|
|
74
74
|
}
|
|
75
75
|
return excess;
|
|
76
76
|
}
|
|
77
|
-
|
|
77
|
+
/**
|
|
78
|
+
* Summarizes the hunks of `payload` that carry the budgeted `+`/`-` lines.
|
|
79
|
+
* `describe` renders the per-hunk counts, so the old body's dropped lines
|
|
80
|
+
* read in the same engine-edit direction as the new body's absorbed ones.
|
|
81
|
+
*/
|
|
82
|
+
function summarizeForeignHunks(payload, foreignAdded, foreignRemoved, describe) {
|
|
78
83
|
const summaries = [];
|
|
84
|
+
if (payload === undefined)
|
|
85
|
+
return summaries;
|
|
79
86
|
const addedBudget = new Map(foreignAdded);
|
|
80
87
|
const removedBudget = new Map(foreignRemoved);
|
|
81
88
|
for (const section of payload.sections) {
|
|
@@ -101,7 +108,7 @@ function summarizeForeignHunks(payload, foreignAdded, foreignRemoved) {
|
|
|
101
108
|
}
|
|
102
109
|
}
|
|
103
110
|
if (added > 0 || removed > 0) {
|
|
104
|
-
summaries.push(`@@ -${hunk.oldStart},${hunk.oldCount} +${hunk.newStart},${hunk.newCount} @@ (
|
|
111
|
+
summaries.push(`@@ -${hunk.oldStart},${hunk.oldCount} +${hunk.newStart},${hunk.newCount} @@ ${describe(added, removed)}`);
|
|
105
112
|
}
|
|
106
113
|
}
|
|
107
114
|
}
|
|
@@ -113,47 +120,71 @@ function countExcess(excess) {
|
|
|
113
120
|
total += count;
|
|
114
121
|
return total;
|
|
115
122
|
}
|
|
123
|
+
const EMPTY_PAYLOAD_LINES = new Map();
|
|
116
124
|
/**
|
|
117
125
|
* Pure comparison: per owned file, which `+`/`-` payload lines the
|
|
118
|
-
* refreshed body carries that the old body did not
|
|
119
|
-
*
|
|
120
|
-
*
|
|
126
|
+
* refreshed body carries that the old body did not, and which the old body
|
|
127
|
+
* carried that the refreshed one dropped. Both directions are drift: a
|
|
128
|
+
* concurrent session deleting a line the patch added changes the patch as
|
|
129
|
+
* surely as one adding a line, and a belt that only saw absorbed lines let
|
|
130
|
+
* such a deletion through silently. Files not in `previousFilesAffected`
|
|
131
|
+
* are skipped, since those are intentional adoptions (`--scan`) or
|
|
132
|
+
* retirements (`--expect-removed`) rather than drift.
|
|
121
133
|
*/
|
|
122
134
|
export function computeForeignDrift(oldBody, newBody, previousFilesAffected) {
|
|
123
135
|
const owned = new Set(previousFilesAffected);
|
|
124
136
|
const oldByFile = collectPayloadByFile(oldBody);
|
|
125
137
|
const newByFile = collectPayloadByFile(newBody);
|
|
126
138
|
const drift = [];
|
|
127
|
-
|
|
139
|
+
// New-body order first, then files only the old body carried.
|
|
140
|
+
const files = new Set([...newByFile.keys(), ...oldByFile.keys()]);
|
|
141
|
+
for (const file of files) {
|
|
128
142
|
if (!owned.has(file))
|
|
129
143
|
continue;
|
|
144
|
+
const next = newByFile.get(file);
|
|
130
145
|
const previous = oldByFile.get(file);
|
|
131
|
-
if (next
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
146
|
+
if (next?.isBinary === true || previous?.isBinary === true) {
|
|
147
|
+
if (binaryContentChanged(next, previous)) {
|
|
148
|
+
drift.push({
|
|
149
|
+
file,
|
|
150
|
+
addedLines: 0,
|
|
151
|
+
removedLines: 0,
|
|
152
|
+
hunkSummaries: [],
|
|
153
|
+
binaryChanged: true,
|
|
154
|
+
});
|
|
138
155
|
}
|
|
139
156
|
continue;
|
|
140
157
|
}
|
|
141
|
-
const
|
|
142
|
-
const
|
|
143
|
-
const
|
|
144
|
-
const
|
|
158
|
+
const absorbedAdded = multisetExcess(next?.added ?? EMPTY_PAYLOAD_LINES, previous?.added ?? EMPTY_PAYLOAD_LINES);
|
|
159
|
+
const absorbedRemoved = multisetExcess(next?.removed ?? EMPTY_PAYLOAD_LINES, previous?.removed ?? EMPTY_PAYLOAD_LINES);
|
|
160
|
+
const droppedAdded = multisetExcess(previous?.added ?? EMPTY_PAYLOAD_LINES, next?.added ?? EMPTY_PAYLOAD_LINES);
|
|
161
|
+
const droppedRemoved = multisetExcess(previous?.removed ?? EMPTY_PAYLOAD_LINES, next?.removed ?? EMPTY_PAYLOAD_LINES);
|
|
162
|
+
const addedLines = countExcess(absorbedAdded) + countExcess(droppedRemoved);
|
|
163
|
+
const removedLines = countExcess(absorbedRemoved) + countExcess(droppedAdded);
|
|
145
164
|
if (addedLines === 0 && removedLines === 0)
|
|
146
165
|
continue;
|
|
147
166
|
drift.push({
|
|
148
167
|
file,
|
|
149
168
|
addedLines,
|
|
150
169
|
removedLines,
|
|
151
|
-
hunkSummaries:
|
|
170
|
+
hunkSummaries: [
|
|
171
|
+
...summarizeForeignHunks(next, absorbedAdded, absorbedRemoved, (plus, minus) => `(+${plus}/-${minus})`),
|
|
172
|
+
// A dropped `+` line is one the engine lost; a dropped `-` line is an
|
|
173
|
+
// upstream line the engine has back.
|
|
174
|
+
...summarizeForeignHunks(previous, droppedAdded, droppedRemoved, (plus, minus) => `in the old body, dropped (+${minus}/-${plus})`),
|
|
175
|
+
].slice(0, MAX_HUNK_SUMMARIES_PER_FILE),
|
|
152
176
|
binaryChanged: false,
|
|
153
177
|
});
|
|
154
178
|
}
|
|
155
179
|
return drift;
|
|
156
180
|
}
|
|
181
|
+
/** True when a binary section appeared, vanished, or its new-side blob hash moved. */
|
|
182
|
+
function binaryContentChanged(next, previous) {
|
|
183
|
+
if (next?.binaryNewHash === undefined || previous?.binaryNewHash === undefined)
|
|
184
|
+
return true;
|
|
185
|
+
return !(next.binaryNewHash.startsWith(previous.binaryNewHash) ||
|
|
186
|
+
previous.binaryNewHash.startsWith(next.binaryNewHash));
|
|
187
|
+
}
|
|
157
188
|
/**
|
|
158
189
|
* Reads the old body, prints the always-on drift preview (including under
|
|
159
190
|
* dry-run and `--scan`), and, when `ctx.refuseForeignDrift` is set,
|
|
@@ -161,6 +192,10 @@ export function computeForeignDrift(oldBody, newBody, previousFilesAffected) {
|
|
|
161
192
|
*/
|
|
162
193
|
export async function reportForeignDrift(args) {
|
|
163
194
|
const { patch, patchesDir, engineDir, newDiffContent, ctx } = args;
|
|
195
|
+
for (const file of args.adoptedFiles ?? []) {
|
|
196
|
+
if (ctx.expectedDriftFiles.has(file))
|
|
197
|
+
ctx.expectedSeen.add(file);
|
|
198
|
+
}
|
|
164
199
|
const oldPath = join(patchesDir, patch.filename);
|
|
165
200
|
let oldBody;
|
|
166
201
|
try {
|
|
@@ -172,7 +207,7 @@ export async function reportForeignDrift(args) {
|
|
|
172
207
|
catch (error) {
|
|
173
208
|
return refuseUnreadableBaseline(ctx, patch.filename, `old body unreadable (${toError(error).message})`);
|
|
174
209
|
}
|
|
175
|
-
const drift = computeForeignDrift(oldBody, newDiffContent, patch.filesAffected);
|
|
210
|
+
const drift = computeForeignDrift(oldBody, newDiffContent, args.ownedFiles ?? patch.filesAffected);
|
|
176
211
|
ctx.evaluationRuns += 1;
|
|
177
212
|
if (drift.length === 0)
|
|
178
213
|
return false;
|
|
@@ -184,7 +219,7 @@ export async function reportForeignDrift(args) {
|
|
|
184
219
|
const recentlyEdited = await findFilesEditedSinceLastExport(engineDir, oldPath, drift.map((d) => d.file));
|
|
185
220
|
const totalLines = drift.reduce((sum, d) => sum + d.addedLines + d.removedLines, 0);
|
|
186
221
|
const lineNoun = totalLines === 1 ? 'line' : 'lines';
|
|
187
|
-
warn(`${patch.filename}: refreshed body
|
|
222
|
+
warn(`${patch.filename}: refreshed body changes ${totalLines} ${lineNoun} against the old patch body (${drift.length} file(s)):`);
|
|
188
223
|
for (const entry of drift.slice(0, MAX_FILES_REPORTED)) {
|
|
189
224
|
const expectedTag = ctx.expectedDriftFiles.has(entry.file) ? ' (expected via --expect)' : '';
|
|
190
225
|
const authorshipTag = recentlyEdited.has(entry.file)
|
|
@@ -194,7 +229,7 @@ export async function reportForeignDrift(args) {
|
|
|
194
229
|
info(` ${entry.file}: binary content changed${expectedTag}${authorshipTag}`);
|
|
195
230
|
continue;
|
|
196
231
|
}
|
|
197
|
-
info(` ${entry.file}: +${entry.addedLines}
|
|
232
|
+
info(` ${entry.file}: +${entry.addedLines} added / -${entry.removedLines} removed line(s)${expectedTag}${authorshipTag}`);
|
|
198
233
|
for (const summary of entry.hunkSummaries) {
|
|
199
234
|
info(` ${summary}`);
|
|
200
235
|
}
|
|
@@ -274,31 +309,24 @@ function refuseUnreadableBaseline(ctx, patchFilename, detail) {
|
|
|
274
309
|
/**
|
|
275
310
|
* States, verbatim in the notice, what the `--expect` whitelist is compared
|
|
276
311
|
* against and when. This notice is the only feedback an operator gets that
|
|
277
|
-
* the drift belt looked at the files they named,
|
|
278
|
-
*
|
|
279
|
-
* over an edit that was captured correctly, and none of the causes it named
|
|
280
|
-
* held, so the operator's only recourse was `grep -c` on the written body.
|
|
281
|
-
*
|
|
282
|
-
* The measurement, stated exactly:
|
|
312
|
+
* the drift belt looked at the files they named, so it has to describe the
|
|
313
|
+
* measurement exactly:
|
|
283
314
|
*
|
|
284
315
|
* - Compared: for each file already in the patch's `filesAffected`, the
|
|
285
316
|
* `+`/`-` payload lines the refreshed body carries that the old patch
|
|
286
|
-
* body did not
|
|
287
|
-
*
|
|
317
|
+
* body did not, and the ones the old body carried that the refreshed body
|
|
318
|
+
* dropped (`computeForeignDrift`). It is a content comparison in both
|
|
319
|
+
* directions, so a deletion-only edit is drift too.
|
|
288
320
|
* - When: per patch, on the body about to be written, before the write.
|
|
289
321
|
* Never against post-write state.
|
|
290
322
|
*
|
|
291
|
-
*
|
|
292
|
-
*
|
|
293
|
-
*
|
|
294
|
-
* is absorbed, so there is no drift to see. The belt exists to catch a
|
|
295
|
-
* concurrent session's edits being silently swallowed into a body, not
|
|
296
|
-
* every difference between two bodies. Stating that is the fix. Widening
|
|
297
|
-
* the comparison would turn every ordinary line removal into a refusal.
|
|
323
|
+
* An earlier copy compared one direction only, so a correctly captured
|
|
324
|
+
* deletion read as an `--expect` that matched nothing, and a peer's
|
|
325
|
+
* deletion in a file outside `--expect` passed the belt silently.
|
|
298
326
|
*/
|
|
299
327
|
const EXPECT_MEASUREMENT_NOTE = '--expect is evaluated against CONTENT, before the write: for each file already in the ' +
|
|
300
|
-
"patch's filesAffected, the payload lines the refreshed body
|
|
301
|
-
'body
|
|
328
|
+
"patch's filesAffected, the payload lines the refreshed body adds or drops against the old " +
|
|
329
|
+
'patch body. It never looks at post-write state.';
|
|
302
330
|
/**
|
|
303
331
|
* Names `--expect` paths that never drifted this run. A typo'd
|
|
304
332
|
* `--expect` path silently degrades the flag back to refusing the slice it
|
|
@@ -318,17 +346,13 @@ export function warnUnseenExpectedDrift(driftCtx) {
|
|
|
318
346
|
`${unseen.join(', ')}.\n` +
|
|
319
347
|
`${EXPECT_MEASUREMENT_NOTE}\n` +
|
|
320
348
|
'Causes, in rough order of likelihood:\n' +
|
|
321
|
-
|
|
322
|
-
'
|
|
323
|
-
'
|
|
324
|
-
'with "grep -c" on the written patch body.\n' +
|
|
325
|
-
" 2. A typo in the path, or a path not in the patch's filesAffected (files adopted " +
|
|
326
|
-
'this run via --scan/--scan-file are excluded from the comparison by design).\n' +
|
|
327
|
-
' 3. Adoption already captured it: a "re-export <p> --scan --scan-file <f>" run also ' +
|
|
349
|
+
" 1. A typo in the path, or a path in none of the selected patches' filesAffected and " +
|
|
350
|
+
'not adopted by this run.\n' +
|
|
351
|
+
' 2. Adoption already captured it: a "re-export <p> --scan --scan-file <f>" run also ' +
|
|
328
352
|
"captures that patch's other drifted files, so a scan-less re-export afterwards " +
|
|
329
|
-
'legitimately sees nothing left to
|
|
353
|
+
'legitimately sees nothing left to change. Informational — a chain that treats this ' +
|
|
330
354
|
'warning as an error will false-red on it.\n' +
|
|
331
|
-
'
|
|
332
|
-
'
|
|
355
|
+
' 3. The slice was already captured by an earlier export in this session.\n' +
|
|
356
|
+
' 4. The engine content already matches the patch body — a concurrent session may have ' +
|
|
333
357
|
'exported the same change, so the drift converged before this run looked.');
|
|
334
358
|
}
|
|
@@ -7,6 +7,7 @@ import { listTrackedInHead } from '../core/git-file-ops.js';
|
|
|
7
7
|
import { extractAffectedFiles } from '../core/patch-apply.js';
|
|
8
8
|
import { updatePatchAndMetadata } from '../core/patch-export.js';
|
|
9
9
|
import { buildPatchQueueContext, formatPatchLintIssue, lintPatchQueue, } from '../core/patch-lint.js';
|
|
10
|
+
import { buildLintIgnoreChecks, mergeLintIgnoreIds } from '../core/patch-lint-ignore.js';
|
|
10
11
|
import { computeProjectedLintRegressions } from '../core/patch-lint-projection.js';
|
|
11
12
|
import { loadPatchesManifest } from '../core/patch-manifest.js';
|
|
12
13
|
import { buildProjectedManifest, enforcePatchPolicy } from '../core/patch-policy.js';
|
|
@@ -25,10 +26,8 @@ import { projectEntryBody } from './patch/entry-projection.js';
|
|
|
25
26
|
* so the caller can drop the field rather than write an empty array.
|
|
26
27
|
*/
|
|
27
28
|
function resolveEffectiveTierAndLintIgnore(target, options) {
|
|
28
|
-
const existingIgnoreSet = new Set(target.lintIgnore ?? []);
|
|
29
29
|
const flagIgnoreSet = new Set(options.lintIgnore ?? []);
|
|
30
|
-
const
|
|
31
|
-
const effectiveLintIgnore = mergedIgnoreSet.size > 0 ? [...mergedIgnoreSet] : undefined;
|
|
30
|
+
const effectiveLintIgnore = mergeLintIgnoreIds(target.lintIgnore, [...flagIgnoreSet]);
|
|
32
31
|
const effectiveTier = options.tier ?? target.tier;
|
|
33
32
|
return { effectiveTier, effectiveLintIgnore, flagIgnoreSet };
|
|
34
33
|
}
|
|
@@ -39,8 +38,10 @@ function resolveEffectiveTierAndLintIgnore(target, options) {
|
|
|
39
38
|
* shrink. Pre-existing cross-patch errors are surfaced as a non-blocking
|
|
40
39
|
* warning so the user does not walk away thinking the queue is clean.
|
|
41
40
|
*/
|
|
42
|
-
async function runProjectedCrossPatchLint(patchesDir, targetFilename, projectedDiff) {
|
|
43
|
-
|
|
41
|
+
async function runProjectedCrossPatchLint(patchesDir, targetFilename, projectedDiff, config) {
|
|
42
|
+
// The config threads `patchLint.forwardRegistration` through, so a forward
|
|
43
|
+
// jar.mn registration is judged the way `lint --per-patch` judges it.
|
|
44
|
+
const baseCtx = await buildPatchQueueContext(patchesDir, config);
|
|
44
45
|
const projection = projectEntryBody(projectedDiff);
|
|
45
46
|
const projectedEntries = baseCtx.entries.map((entry) => {
|
|
46
47
|
if (entry.filename !== targetFilename)
|
|
@@ -48,7 +49,7 @@ async function runProjectedCrossPatchLint(patchesDir, targetFilename, projectedD
|
|
|
48
49
|
return { ...entry, ...projection };
|
|
49
50
|
});
|
|
50
51
|
const baselineIssues = lintPatchQueue(baseCtx).filter((i) => i.severity === 'error');
|
|
51
|
-
const projectedIssues = lintPatchQueue({ entries: projectedEntries }).filter((i) => i.severity === 'error');
|
|
52
|
+
const projectedIssues = lintPatchQueue({ ...baseCtx, entries: projectedEntries }).filter((i) => i.severity === 'error');
|
|
52
53
|
const regressions = computeProjectedLintRegressions(baselineIssues, projectedIssues);
|
|
53
54
|
if (baselineIssues.length > 0 && regressions.length === 0) {
|
|
54
55
|
warn(`Note: projected queue still has ${baselineIssues.length} pre-existing ` +
|
|
@@ -223,7 +224,7 @@ export async function reExportFilesInPlace(paths, selectedPatches, options, conf
|
|
|
223
224
|
// `--tier` and `--lint-ignore` participate too, with append/union
|
|
224
225
|
// semantics on the lint-ignore list.
|
|
225
226
|
const { effectiveTier, effectiveLintIgnore, flagIgnoreSet } = resolveEffectiveTierAndLintIgnore(target, options);
|
|
226
|
-
const ignoreChecks =
|
|
227
|
+
const ignoreChecks = buildLintIgnoreChecks(effectiveLintIgnore);
|
|
227
228
|
const patchQueueCtx = (await pathExists(paths.patches))
|
|
228
229
|
? await buildPatchQueueContext(paths.patches)
|
|
229
230
|
: undefined;
|
|
@@ -237,7 +238,7 @@ export async function reExportFilesInPlace(paths, selectedPatches, options, conf
|
|
|
237
238
|
ignoreChecks,
|
|
238
239
|
patchTier: effectiveTier,
|
|
239
240
|
});
|
|
240
|
-
const conflicts = await runProjectedCrossPatchLint(paths.patches, target.filename, projectedDiff);
|
|
241
|
+
const conflicts = await runProjectedCrossPatchLint(paths.patches, target.filename, projectedDiff, config);
|
|
241
242
|
const filesUpdates = buildFilesModeMetadataUpdates(actualProjectedFiles, options, effectiveLintIgnore, flagIgnoreSet);
|
|
242
243
|
const manifest = await loadPatchesManifest(paths.patches);
|
|
243
244
|
if (manifest) {
|
|
@@ -246,6 +247,7 @@ export async function reExportFilesInPlace(paths, selectedPatches, options, conf
|
|
|
246
247
|
manifest: buildProjectedManifest(manifest, manifest.patches.map((entry) => entry.filename === target.filename ? { ...entry, ...filesUpdates } : entry)),
|
|
247
248
|
command: 're-export --files',
|
|
248
249
|
forceUnsafe: options.forceUnsafe === true,
|
|
250
|
+
scope: [target.filename],
|
|
249
251
|
});
|
|
250
252
|
}
|
|
251
253
|
const decision = await confirmFilesModeProjection({
|
|
@@ -297,6 +299,7 @@ export async function reExportFilesInPlace(paths, selectedPatches, options, conf
|
|
|
297
299
|
config,
|
|
298
300
|
command: 're-export --files',
|
|
299
301
|
forceUnsafe: options.forceUnsafe === true,
|
|
302
|
+
scope: [target.filename],
|
|
300
303
|
},
|
|
301
304
|
});
|
|
302
305
|
success(`Re-exported ${target.filename}`);
|
|
@@ -21,6 +21,7 @@
|
|
|
21
21
|
*/
|
|
22
22
|
import { type PatchQueueContext } from '../core/patch-lint.js';
|
|
23
23
|
import { type PerPatchLintCacheFile } from '../core/patch-lint-cache.js';
|
|
24
|
+
import { type LintIgnoreChecks } from '../core/patch-lint-ignore.js';
|
|
24
25
|
import type { PatchLintIssue, PatchMetadata } from '../types/commands/index.js';
|
|
25
26
|
import type { FireForgeConfig, ProjectPaths } from '../types/config.js';
|
|
26
27
|
import { type PerRunCheckJs } from './lint-per-run-checkjs.js';
|
|
@@ -92,7 +93,7 @@ export declare function lintReExportedPatch(args: {
|
|
|
92
93
|
existingFiles: string[];
|
|
93
94
|
diffContent: string;
|
|
94
95
|
skipLint?: boolean;
|
|
95
|
-
ignoreChecks?:
|
|
96
|
+
ignoreChecks?: LintIgnoreChecks;
|
|
96
97
|
patchTier?: 'branding';
|
|
97
98
|
}): Promise<ReExportLintResult | null>;
|
|
98
99
|
/**
|
|
@@ -20,18 +20,20 @@
|
|
|
20
20
|
* (`refreshQueueCtxEntry`), so later iterations of an `--all` run lint
|
|
21
21
|
* against the just-refreshed body instead of the stale one.
|
|
22
22
|
*/
|
|
23
|
-
import { buildPatchQueueContext,
|
|
23
|
+
import { buildPatchQueueContext, detectNewFilesInDiff, formatPatchLintIssue, lintExportedPatch, lintPatchQueue, measurePatchSize, resolvePatchSizeTier, } from '../core/patch-lint.js';
|
|
24
24
|
import { buildPerPatchLintCacheKey, getCachedPerPatchLintIssues, getPerPatchLintCacheHeadSha, loadPerPatchLintCache, savePerPatchLintCache, setCachedPerPatchLintIssues, } from '../core/patch-lint-cache.js';
|
|
25
25
|
import { invalidateNewFileCreatorsCache } from '../core/patch-lint-cross.js';
|
|
26
|
+
import { lintIgnoreCacheTokens } from '../core/patch-lint-ignore.js';
|
|
26
27
|
import { resolvePatchOwnedSysMjs } from '../core/patch-lint-ownership.js';
|
|
27
28
|
import { computeProjectedLintRegressions } from '../core/patch-lint-projection.js';
|
|
28
29
|
import { GeneralError } from '../errors/base.js';
|
|
29
30
|
import { pathExists } from '../utils/fs.js';
|
|
30
31
|
import { info, warn } from '../utils/logger.js';
|
|
31
32
|
import { reportPatchLintOutcome } from './export-shared.js';
|
|
33
|
+
import { formatForwardImportRemedy } from './forward-import-remedy.js';
|
|
32
34
|
import { buildPerRunCheckJs } from './lint-per-run-checkjs.js';
|
|
33
35
|
import { projectEntryBody } from './patch/entry-projection.js';
|
|
34
|
-
import {
|
|
36
|
+
import { categoryOf, manifestFromQueue } from './re-export-scan.js';
|
|
35
37
|
/**
|
|
36
38
|
* Builds the once-per-invocation lint context.
|
|
37
39
|
*
|
|
@@ -135,7 +137,7 @@ export async function lintReExportedPatch(args) {
|
|
|
135
137
|
queueContext: patchQueueCtx,
|
|
136
138
|
...(lintCtx.engineHeadSha === undefined ? {} : { engineHeadSha: lintCtx.engineHeadSha }),
|
|
137
139
|
});
|
|
138
|
-
const cached = getCachedPerPatchLintIssues(cache, patch.filename, cacheKey, args.ignoreChecks);
|
|
140
|
+
const cached = getCachedPerPatchLintIssues(cache, patch.filename, cacheKey, lintIgnoreCacheTokens(args.ignoreChecks));
|
|
139
141
|
if (cached) {
|
|
140
142
|
lintCtx.reusedCacheEntries++;
|
|
141
143
|
reportPatchLintOutcome([...globalIssues, ...cached.issues], args.skipLint);
|
|
@@ -167,8 +169,10 @@ export async function lintReExportedPatch(args) {
|
|
|
167
169
|
else if (patchQueueCtx) {
|
|
168
170
|
lintOptions.checkJsReportScope = resolvePatchOwnedSysMjs(detectNewFilesInDiff(diffContent));
|
|
169
171
|
}
|
|
172
|
+
const patchSize = await measurePatchSize(paths.engine, diffContent, existingFiles, config);
|
|
170
173
|
const issues = await lintExportedPatch(paths.engine, existingFiles, diffContent, config, {
|
|
171
174
|
...lintOptions,
|
|
175
|
+
patchSizeMeasurement: patchSize,
|
|
172
176
|
...(patchQueueCtx ? { patchQueueCtx } : {}),
|
|
173
177
|
...(args.ignoreChecks ? { ignoreChecks: args.ignoreChecks } : {}),
|
|
174
178
|
...(args.patchTier ? { patchTier: args.patchTier } : {}),
|
|
@@ -177,8 +181,8 @@ export async function lintReExportedPatch(args) {
|
|
|
177
181
|
return {
|
|
178
182
|
issues,
|
|
179
183
|
suppressed: suppressedIssues,
|
|
180
|
-
lineCount:
|
|
181
|
-
lintIgnore:
|
|
184
|
+
lineCount: patchSize.lines,
|
|
185
|
+
lintIgnore: lintIgnoreCacheTokens(args.ignoreChecks),
|
|
182
186
|
};
|
|
183
187
|
}
|
|
184
188
|
/**
|
|
@@ -236,10 +240,11 @@ export function assertRefreshedBodyHasNoNewQueueErrors(args) {
|
|
|
236
240
|
const projectedEntries = ctx.entries.map((entry) => entry.filename === patchFilename ? { ...entry, ...projection } : entry);
|
|
237
241
|
const isError = (issue) => issue.severity === 'error';
|
|
238
242
|
const baseline = lintPatchQueue(ctx).filter(isError);
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
+
// The whole context carries over (patchPolicy and the
|
|
244
|
+
// `patchLint.forwardRegistration` scope): dropping the scope here let a
|
|
245
|
+
// forward jar.mn registration pass this gate and surface only in the
|
|
246
|
+
// later queue audit, separately from the forward import it packages.
|
|
247
|
+
const projected = lintPatchQueue({ ...ctx, entries: projectedEntries }).filter(isError);
|
|
243
248
|
const regressions = computeProjectedLintRegressions(baseline, projected);
|
|
244
249
|
if (regressions.length === 0) {
|
|
245
250
|
if (baseline.length > 0 && !lintCtx.queueBaselineWarned) {
|
|
@@ -253,7 +258,15 @@ export function assertRefreshedBodyHasNoNewQueueErrors(args) {
|
|
|
253
258
|
const hasForwardImport = regressions.some((issue) => issue.check === 'forward-import');
|
|
254
259
|
const message = `Refusing to re-export ${patchFilename} because the refreshed body introduces ` +
|
|
255
260
|
`${regressions.length} new cross-patch lint error${regressions.length === 1 ? '' : 's'}:\n${details}` +
|
|
256
|
-
(hasForwardImport
|
|
261
|
+
(hasForwardImport
|
|
262
|
+
? `\n${formatForwardImportRemedy({
|
|
263
|
+
reRunHint: 're-running the re-export',
|
|
264
|
+
issues: regressions,
|
|
265
|
+
manifest: manifestFromQueue(ctx),
|
|
266
|
+
config: lintCtx.config,
|
|
267
|
+
...categoryOf(ctx, patchFilename),
|
|
268
|
+
})}`
|
|
269
|
+
: '');
|
|
257
270
|
if (forceUnsafe) {
|
|
258
271
|
warn(message);
|
|
259
272
|
warn('Proceeding because --force-unsafe was provided.');
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
// SPDX-License-Identifier: EUPL-1.2
|
|
2
2
|
import { InvalidArgumentError } from '../errors/base.js';
|
|
3
3
|
import { info } from '../utils/logger.js';
|
|
4
|
+
import { validateScanFileOwners } from './re-export-scan-owner.js';
|
|
4
5
|
/**
|
|
5
6
|
* Heuristic for `--files` positional folding: an extra positional that
|
|
6
7
|
* contains a path separator and is not a `.patch` filename is an engine
|
|
@@ -62,6 +63,39 @@ function validateWhitelistFlagDependencies(options) {
|
|
|
62
63
|
options.refuseAdjacentUnmanaged !== true) {
|
|
63
64
|
throw new InvalidArgumentError('--expect-unmanaged names approved exceptions to --refuse-adjacent-unmanaged and has no effect without it. Pass --refuse-adjacent-unmanaged, or drop --expect-unmanaged.', '--expect-unmanaged');
|
|
64
65
|
}
|
|
66
|
+
for (const [flag, values] of [
|
|
67
|
+
['--expect-new', options.expectNew],
|
|
68
|
+
['--adjacent-ignore', options.adjacentIgnore],
|
|
69
|
+
]) {
|
|
70
|
+
if (values !== undefined && values.length > 0 && options.refuseAdjacentUnmanaged !== true) {
|
|
71
|
+
throw new InvalidArgumentError(`${flag} relaxes --refuse-adjacent-unmanaged and has no effect without it. Pass --refuse-adjacent-unmanaged, or drop ${flag}.`, flag);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
if (options.adjacentIgnore?.some((entry) => entry.includes('**'))) {
|
|
75
|
+
throw new InvalidArgumentError('--adjacent-ignore takes a path or a glob whose * stays within one path segment; ** is refused, because a subtree carve-out is how a reviewed exception becomes a blanket one.', '--adjacent-ignore');
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Refuses a path-valued flag whose value starts with `-`. Commander hands a
|
|
80
|
+
* required option value whatever follows it, so a list that ended early
|
|
81
|
+
* (`--expect-unmanaged --dry-run`) silently turned the next flag into a path
|
|
82
|
+
* and the dry run into a write. No engine path starts with a dash.
|
|
83
|
+
*/
|
|
84
|
+
function validatePathFlagValues(options) {
|
|
85
|
+
for (const [flag, values] of [
|
|
86
|
+
['--expect', options.expect],
|
|
87
|
+
['--expect-unmanaged', options.expectUnmanaged],
|
|
88
|
+
['--expect-new', options.expectNew],
|
|
89
|
+
['--expect-removed', options.expectRemoved],
|
|
90
|
+
['--adjacent-ignore', options.adjacentIgnore],
|
|
91
|
+
['--scan-file', options.scanFiles],
|
|
92
|
+
]) {
|
|
93
|
+
const swallowed = (values ?? []).filter((value) => value.trim().startsWith('-'));
|
|
94
|
+
if (swallowed.length > 0) {
|
|
95
|
+
throw new InvalidArgumentError(`${flag} was given ${swallowed.map((value) => `"${value}"`).join(', ')}, which is a flag, not an engine path: ` +
|
|
96
|
+
`the ${flag} before it had no value, so it took the next argument. Give every ${flag} a path.`, flag);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
65
99
|
}
|
|
66
100
|
function validateExpectedRemovalUsage(patches, options) {
|
|
67
101
|
if (options.expectRemoved?.length &&
|
|
@@ -71,6 +105,9 @@ function validateExpectedRemovalUsage(patches, options) {
|
|
|
71
105
|
}
|
|
72
106
|
/** Validates mutually exclusive `re-export` targeting and metadata options. */
|
|
73
107
|
export function validateReExportOptionCombinations(patches, options) {
|
|
108
|
+
// First: a swallowed flag would otherwise surface as whichever
|
|
109
|
+
// combination error it happens to trip, naming the wrong problem.
|
|
110
|
+
validatePathFlagValues(options);
|
|
74
111
|
validateExpectedRemovalUsage(patches, options);
|
|
75
112
|
if (options.files !== undefined) {
|
|
76
113
|
if (options.all || options.scan) {
|
|
@@ -91,9 +128,10 @@ export function validateReExportOptionCombinations(patches, options) {
|
|
|
91
128
|
if (options.scanFilesManifest !== undefined) {
|
|
92
129
|
throw new InvalidArgumentError('--scan-file cannot be combined with --scan-files.', '--scan-file');
|
|
93
130
|
}
|
|
94
|
-
if (options.all
|
|
95
|
-
throw new InvalidArgumentError('--scan-file
|
|
131
|
+
if (options.all) {
|
|
132
|
+
throw new InvalidArgumentError('--scan-file cannot be combined with --all. Pass the target patch identifiers.', '--scan-file');
|
|
96
133
|
}
|
|
134
|
+
validateScanFileOwners(patches, options.scanFiles);
|
|
97
135
|
}
|
|
98
136
|
if (options.scanFilesManifest !== undefined) {
|
|
99
137
|
if (!options.scan)
|
|
@@ -105,8 +143,11 @@ export function validateReExportOptionCombinations(patches, options) {
|
|
|
105
143
|
if (options.refuseAdjacentUnmanaged === true && (options.scan || options.files !== undefined)) {
|
|
106
144
|
throw new InvalidArgumentError('--refuse-adjacent-unmanaged applies to the scan-less path only and cannot be combined with --scan or --files (those set filesAffected explicitly).', '--refuse-adjacent-unmanaged');
|
|
107
145
|
}
|
|
108
|
-
|
|
109
|
-
|
|
146
|
+
// Beside --scan the belt covers the files each patch already owns; the
|
|
147
|
+
// files a scan adopts are the run's stated intent. --files replaces the
|
|
148
|
+
// file list outright, so there is no owned set left to guard.
|
|
149
|
+
if (options.refuseForeignDrift === true && options.files !== undefined) {
|
|
150
|
+
throw new InvalidArgumentError('--refuse-foreign-drift cannot be combined with --files (it sets filesAffected explicitly and captures the current engine state).', '--refuse-foreign-drift');
|
|
110
151
|
}
|
|
111
152
|
validateWhitelistFlagDependencies(options);
|
|
112
153
|
const usingTierFlag = options.tier !== undefined;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { ReExportOptions } from '../types/commands/index.js';
|
|
2
|
+
/**
|
|
3
|
+
* Reads a path list file: one engine-relative path per line, blank lines
|
|
4
|
+
* and `#` comment lines ignored. Backs `--expect-from`, which exists because
|
|
5
|
+
* a list held in one shell variable reaches the CLI as one argument under
|
|
6
|
+
* zsh, and splitting it by hand left every path after the first as a
|
|
7
|
+
* positional patch name.
|
|
8
|
+
*
|
|
9
|
+
* @param file - The list file, relative to the working directory
|
|
10
|
+
* @param flag - Flag name for error messages
|
|
11
|
+
*/
|
|
12
|
+
export declare function readPathListFile(file: string, flag: string): Promise<string[]>;
|
|
13
|
+
/**
|
|
14
|
+
* Runs every lock-free argument check: empty or unknown patch names
|
|
15
|
+
* (naming an engine file passed by mistake), option combinations, path
|
|
16
|
+
* flag values that are flags, and path flag values that name no changed
|
|
17
|
+
* file. Throws the refusal the locked run would have thrown, only sooner.
|
|
18
|
+
*
|
|
19
|
+
* @param projectRoot - Project root
|
|
20
|
+
* @param patches - Positional patch arguments as given
|
|
21
|
+
* @param options - Options as the command layer builds them
|
|
22
|
+
*/
|
|
23
|
+
export declare function preflightReExportArguments(projectRoot: string, patches: readonly string[], options: ReExportOptions): Promise<void>;
|