@hominis/fireforge 0.52.0 → 0.54.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 +45 -0
- package/dist/build-info.json +4 -4
- package/dist/src/commands/bootstrap.js +2 -3
- package/dist/src/commands/build-prelock.d.ts +3 -3
- package/dist/src/commands/build-prelock.js +3 -3
- package/dist/src/commands/build.js +4 -0
- package/dist/src/commands/declarations-report.d.ts +9 -3
- package/dist/src/commands/declarations-report.js +18 -11
- package/dist/src/commands/discard.js +3 -3
- package/dist/src/commands/doctor-furnace-config-sync.js +4 -4
- package/dist/src/commands/doctor-furnace.js +5 -5
- package/dist/src/commands/export-adopt-check.d.ts +5 -6
- package/dist/src/commands/export-adopt-check.js +5 -6
- package/dist/src/commands/export-flow.js +6 -9
- package/dist/src/commands/export-staged-registration.d.ts +4 -4
- package/dist/src/commands/export-staged-registration.js +4 -4
- package/dist/src/commands/forward-import-remedy.d.ts +2 -3
- package/dist/src/commands/forward-import-remedy.js +2 -3
- package/dist/src/commands/furnace/create-dry-run.d.ts +2 -2
- package/dist/src/commands/furnace/deploy-fragment-includers.d.ts +2 -2
- package/dist/src/commands/furnace/deploy-fragment-includers.js +2 -2
- package/dist/src/commands/furnace/index.js +2 -2
- package/dist/src/commands/lint.js +4 -4
- package/dist/src/commands/patch/compact.js +1 -1
- package/dist/src/commands/patch/lint-ignore-from.d.ts +3 -4
- package/dist/src/commands/patch/lint-ignore-from.js +3 -4
- package/dist/src/commands/patch/move-files-adopt.d.ts +33 -0
- package/dist/src/commands/patch/move-files-adopt.js +65 -0
- package/dist/src/commands/patch/move-files-create.js +41 -20
- package/dist/src/commands/patch/move-files-into.d.ts +18 -0
- package/dist/src/commands/patch/move-files-into.js +125 -60
- package/dist/src/commands/patch/move-files-retire.d.ts +39 -0
- package/dist/src/commands/patch/move-files-retire.js +91 -0
- package/dist/src/commands/patch/move-files.d.ts +3 -0
- package/dist/src/commands/patch/move-files.js +42 -12
- package/dist/src/commands/patch/move-size-tier.d.ts +27 -0
- package/dist/src/commands/patch/move-size-tier.js +66 -0
- package/dist/src/commands/patch/rename.js +1 -1
- package/dist/src/commands/patch/reorder-projection.d.ts +17 -0
- package/dist/src/commands/patch/reorder-projection.js +49 -0
- package/dist/src/commands/patch/reorder-shift.d.ts +30 -0
- package/dist/src/commands/patch/reorder-shift.js +307 -0
- package/dist/src/commands/patch/reorder.d.ts +9 -15
- package/dist/src/commands/patch/reorder.js +52 -50
- package/dist/src/commands/patch/split-plan.d.ts +31 -3
- package/dist/src/commands/patch/split-plan.js +36 -12
- package/dist/src/commands/patch/split-staged.d.ts +2 -2
- package/dist/src/commands/patch/split-staged.js +2 -2
- package/dist/src/commands/patch/split.js +18 -5
- package/dist/src/commands/patch/staged-dependency-entries.d.ts +9 -1
- package/dist/src/commands/patch/staged-dependency-entries.js +32 -4
- package/dist/src/commands/patch/staged-dependency-from.js +15 -9
- package/dist/src/commands/patch/staged-dependency-remove.d.ts +26 -4
- package/dist/src/commands/patch/staged-dependency-remove.js +60 -23
- package/dist/src/commands/patch/staged-dependency.js +35 -24
- package/dist/src/commands/patch/tier.js +2 -2
- package/dist/src/commands/patch-rename-map.d.ts +14 -3
- package/dist/src/commands/patch-rename-map.js +21 -3
- package/dist/src/commands/re-export-adjacent.d.ts +4 -5
- package/dist/src/commands/re-export-lint.d.ts +4 -3
- package/dist/src/commands/re-export-lint.js +4 -3
- package/dist/src/commands/re-export-options.js +8 -2
- package/dist/src/commands/re-export-preflight.js +1 -2
- package/dist/src/commands/re-export-purity-scope.d.ts +1 -1
- package/dist/src/commands/re-export-purity-scope.js +13 -7
- package/dist/src/commands/re-export-retired-declarations.d.ts +22 -0
- package/dist/src/commands/re-export-retired-declarations.js +113 -0
- package/dist/src/commands/re-export-single.js +2 -2
- package/dist/src/commands/re-export-stale-registrations.d.ts +27 -6
- package/dist/src/commands/re-export-stale-registrations.js +65 -21
- package/dist/src/commands/re-export.js +4 -0
- package/dist/src/commands/rebase/continue.js +3 -3
- package/dist/src/commands/register.js +5 -4
- package/dist/src/commands/run.js +11 -4
- package/dist/src/commands/status.js +1 -1
- package/dist/src/commands/test-build-furnace.d.ts +1 -2
- package/dist/src/commands/test-build-furnace.js +1 -2
- package/dist/src/commands/test-build-phase.d.ts +8 -0
- package/dist/src/commands/test-build-phase.js +42 -7
- package/dist/src/commands/test-control-restore.d.ts +40 -0
- package/dist/src/commands/test-control-restore.js +86 -0
- package/dist/src/commands/test-dispatch.js +68 -7
- package/dist/src/commands/test-multi-verdict.js +1 -0
- package/dist/src/commands/test-orchestrate.d.ts +6 -0
- package/dist/src/commands/test-orchestrate.js +32 -1
- package/dist/src/commands/test-perf-scope.d.ts +1 -1
- package/dist/src/commands/test-perf-scope.js +1 -1
- package/dist/src/commands/test-prelock.d.ts +18 -8
- package/dist/src/commands/test-prelock.js +42 -14
- package/dist/src/commands/test-register.js +4 -3
- package/dist/src/commands/test-results.d.ts +10 -1
- package/dist/src/commands/test-results.js +20 -3
- package/dist/src/commands/test-run.d.ts +6 -0
- package/dist/src/commands/test-run.js +23 -4
- package/dist/src/commands/test-shards.d.ts +7 -3
- package/dist/src/commands/test-shards.js +24 -7
- package/dist/src/commands/test-stale-gate.d.ts +6 -1
- package/dist/src/commands/test-stale-gate.js +40 -2
- package/dist/src/commands/test-verdict.d.ts +5 -3
- package/dist/src/commands/test.js +14 -2
- package/dist/src/commands/token.js +2 -2
- package/dist/src/commands/verify.js +1 -1
- package/dist/src/commands/watch.js +1 -1
- package/dist/src/commands/wire.js +1 -1
- package/dist/src/core/build-audit-resolve.d.ts +4 -5
- package/dist/src/core/build-audit-resolve.js +4 -5
- package/dist/src/core/build-audit-skip.d.ts +2 -2
- package/dist/src/core/build-audit.d.ts +3 -4
- package/dist/src/core/build-baseline-types.d.ts +24 -3
- package/dist/src/core/build-baseline-validate.d.ts +30 -1
- package/dist/src/core/build-baseline-validate.js +127 -35
- package/dist/src/core/build-baseline.d.ts +8 -2
- package/dist/src/core/build-baseline.js +25 -16
- package/dist/src/core/build-jar-escalation.d.ts +4 -4
- package/dist/src/core/build-jar-escalation.js +4 -4
- package/dist/src/core/build-prepare.js +4 -4
- package/dist/src/core/config-validate.js +4 -4
- package/dist/src/core/coverage-extend.d.ts +5 -3
- package/dist/src/core/coverage-extend.js +8 -3
- package/dist/src/core/coverage-records.d.ts +4 -5
- package/dist/src/core/coverage-records.js +4 -5
- package/dist/src/core/destructive.d.ts +2 -2
- package/dist/src/core/destructive.js +2 -2
- package/dist/src/core/discard-baseline.d.ts +2 -2
- package/dist/src/core/discard-baseline.js +3 -3
- package/dist/src/core/engine-session-lock.d.ts +1 -1
- package/dist/src/core/engine-session-lock.js +1 -1
- package/dist/src/core/file-lock-owner.d.ts +5 -5
- package/dist/src/core/file-lock-owner.js +5 -5
- package/dist/src/core/file-lock-queue.js +6 -8
- package/dist/src/core/file-lock-shared.d.ts +4 -4
- package/dist/src/core/file-lock-shared.js +4 -4
- package/dist/src/core/file-lock.js +7 -10
- package/dist/src/core/firefox.js +2 -2
- package/dist/src/core/furnace-apply-overwrite-warn.d.ts +1 -1
- package/dist/src/core/furnace-apply-overwrite-warn.js +1 -1
- package/dist/src/core/furnace-apply.js +3 -3
- package/dist/src/core/furnace-operation.js +5 -5
- package/dist/src/core/furnace-registration-jar-inplace.js +5 -6
- package/dist/src/core/furnace-registration-rename.d.ts +5 -5
- package/dist/src/core/furnace-registration-rename.js +5 -5
- package/dist/src/core/furnace-registration-validate.d.ts +2 -1
- package/dist/src/core/furnace-registration-validate.js +2 -1
- package/dist/src/core/furnace-registration.js +2 -2
- package/dist/src/core/git-base.js +4 -3
- package/dist/src/core/git-diff.js +1 -1
- package/dist/src/core/git.js +1 -1
- package/dist/src/core/harness-orphans.d.ts +6 -6
- package/dist/src/core/harness-orphans.js +6 -6
- package/dist/src/core/harness-port-reservation.d.ts +60 -0
- package/dist/src/core/harness-port-reservation.js +122 -0
- package/dist/src/core/history-log-file.d.ts +9 -9
- package/dist/src/core/history-log-file.js +15 -15
- package/dist/src/core/history-log.d.ts +3 -3
- package/dist/src/core/history-log.js +3 -3
- package/dist/src/core/launchable-build.d.ts +39 -0
- package/dist/src/core/launchable-build.js +85 -0
- package/dist/src/core/marionette-port.js +1 -3
- package/dist/src/core/moz-manifest-rules.js +3 -2
- package/dist/src/core/negative-control-compiled.d.ts +13 -3
- package/dist/src/core/negative-control-compiled.js +27 -5
- package/dist/src/core/negative-control-diff.js +31 -6
- package/dist/src/core/parser-fallback.d.ts +5 -5
- package/dist/src/core/parser-fallback.js +5 -5
- package/dist/src/core/patch-identifier-suggest.d.ts +6 -0
- package/dist/src/core/patch-identifier-suggest.js +11 -4
- package/dist/src/core/patch-lint-checkjs.d.ts +1 -1
- package/dist/src/core/patch-lint-checkjs.js +1 -1
- package/dist/src/core/patch-lint-css.js +2 -2
- package/dist/src/core/patch-lint-file-size.d.ts +5 -7
- package/dist/src/core/patch-lint-file-size.js +5 -7
- package/dist/src/core/patch-lint-ignore.d.ts +3 -3
- package/dist/src/core/patch-lint-ignore.js +3 -3
- package/dist/src/core/patch-lint-prettier.d.ts +4 -6
- package/dist/src/core/patch-lint-prettier.js +4 -6
- package/dist/src/core/patch-lint-projection.d.ts +1 -1
- package/dist/src/core/patch-lint-projection.js +1 -1
- package/dist/src/core/patch-lint-queue-types.d.ts +2 -2
- package/dist/src/core/patch-lint-queue-types.js +2 -2
- package/dist/src/core/patch-manifest-consistency.d.ts +2 -2
- package/dist/src/core/patch-manifest-consistency.js +2 -2
- package/dist/src/core/patch-manifest-io.d.ts +5 -1
- package/dist/src/core/patch-manifest-io.js +12 -10
- package/dist/src/core/patch-manifest-key-order.d.ts +3 -4
- package/dist/src/core/patch-manifest-key-order.js +3 -4
- package/dist/src/core/patch-parse.d.ts +3 -3
- package/dist/src/core/patch-parse.js +3 -3
- package/dist/src/core/patch-policy.d.ts +1 -1
- package/dist/src/core/patch-policy.js +1 -1
- package/dist/src/core/patch-source-metadata.d.ts +1 -1
- package/dist/src/core/patch-source-metadata.js +1 -1
- package/dist/src/core/patch-subset.d.ts +5 -3
- package/dist/src/core/patch-subset.js +8 -7
- package/dist/src/core/patch-transform.d.ts +2 -2
- package/dist/src/core/patch-transform.js +2 -2
- package/dist/src/core/rebase-session.js +4 -6
- package/dist/src/core/register-xpcshell-test.d.ts +28 -7
- package/dist/src/core/register-xpcshell-test.js +76 -27
- package/dist/src/core/run-log.d.ts +8 -8
- package/dist/src/core/run-log.js +8 -8
- package/dist/src/core/status-classify.d.ts +1 -2
- package/dist/src/core/status-classify.js +1 -2
- package/dist/src/core/test-harness-crash.d.ts +5 -3
- package/dist/src/core/test-harness-crash.js +13 -14
- package/dist/src/core/test-harness-infra.d.ts +32 -0
- package/dist/src/core/test-harness-infra.js +69 -0
- package/dist/src/core/test-harness-signature.d.ts +6 -0
- package/dist/src/core/test-stale-check.d.ts +38 -0
- package/dist/src/core/test-stale-check.js +82 -1
- package/dist/src/core/test-stall-triage.js +5 -7
- package/dist/src/core/token-category.js +2 -2
- package/dist/src/core/token-inventory.js +3 -3
- package/dist/src/core/token-manager.d.ts +2 -2
- package/dist/src/core/token-manager.js +5 -7
- package/dist/src/core/token-variant.d.ts +6 -6
- package/dist/src/core/token-variant.js +7 -7
- package/dist/src/core/typecheck-shim.js +1 -1
- package/dist/src/core/wire-destroy.d.ts +1 -1
- package/dist/src/core/wire-destroy.js +1 -1
- package/dist/src/core/wire-dom-fragment.js +1 -1
- package/dist/src/core/wire-init.d.ts +1 -1
- package/dist/src/core/wire-init.js +1 -1
- package/dist/src/core/wire-subscript.d.ts +1 -1
- package/dist/src/core/wire-subscript.js +1 -1
- package/dist/src/core/wire-utils.d.ts +2 -2
- package/dist/src/core/wire-utils.js +3 -3
- package/dist/src/errors/base.d.ts +1 -1
- package/dist/src/errors/base.js +1 -1
- package/dist/src/errors/rebase.d.ts +1 -1
- package/dist/src/errors/rebase.js +1 -1
- package/dist/src/types/commands/options.d.ts +38 -3
- package/dist/src/types/config.d.ts +5 -7
- package/dist/src/utils/options.js +2 -2
- package/dist/src/utils/process.js +2 -2
- package/dist/src/utils/regex.d.ts +2 -2
- package/dist/src/utils/regex.js +3 -3
- package/dist/src/utils/sleep.d.ts +5 -6
- package/dist/src/utils/sleep.js +5 -6
- package/dist/src/utils/validation.js +2 -2
- package/docs/configuration.md +28 -23
- package/docs/exit-codes.md +8 -11
- package/docs/furnace.md +3 -3
- package/docs/lifecycle-invariants.md +36 -45
- package/docs/machine-output.md +41 -24
- package/docs/patch-workflow.md +140 -29
- package/docs/run-logs.md +8 -9
- package/docs/testing.md +114 -48
- package/package.json +1 -1
|
@@ -11,9 +11,9 @@ 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
13
|
import { stagedDependencyDelta } from './staged-dependency-batch.js';
|
|
14
|
-
import { applyMode, countStagedEntries, dependencyLabel, importView, registrationView, } from './staged-dependency-entries.js';
|
|
14
|
+
import { applyMode, countReasonUpdates, countStagedEntries, dependencyLabel, importView, registrationView, } from './staged-dependency-entries.js';
|
|
15
15
|
import { runBatchAdd } from './staged-dependency-from.js';
|
|
16
|
-
import { selectRemovalEntries } from './staged-dependency-remove.js';
|
|
16
|
+
import { declarationNoun, inferRemovalKinds, selectRemovalEntries, } from './staged-dependency-remove.js';
|
|
17
17
|
import { validateStagedDependencyAdd } from './staged-dependency-validate.js';
|
|
18
18
|
/** Joins the names of the missing flags for error attribution. */
|
|
19
19
|
function missingFlagList(pairs) {
|
|
@@ -89,20 +89,25 @@ function requireRegistrationOptions(options) {
|
|
|
89
89
|
/**
|
|
90
90
|
* Renders a one-line summary of a staged-dependency metadata change.
|
|
91
91
|
*/
|
|
92
|
-
function describeStagedDependencyChange(
|
|
93
|
-
const
|
|
92
|
+
function describeStagedDependencyChange(before, after, mode, kinds, targets) {
|
|
93
|
+
const beforeCount = countStagedEntries(before);
|
|
94
|
+
const afterCount = countStagedEntries(after);
|
|
95
|
+
const targetKinds = [...new Set(targets.map((target) => target.kind))];
|
|
96
|
+
const noun = declarationNoun(targetKinds.length > 0 ? targetKinds : kinds);
|
|
94
97
|
if (mode === 'clear') {
|
|
95
98
|
return beforeCount === 0
|
|
96
99
|
? 'stagedDependencies was already empty — no change'
|
|
97
100
|
: `cleared ${beforeCount} staged dependency declaration(s)`;
|
|
98
101
|
}
|
|
99
|
-
const label = targets.map((
|
|
102
|
+
const label = targets.map(({ kind, view }) => dependencyLabel(kind, view)).join('; ');
|
|
100
103
|
if (targets.length === 0)
|
|
101
104
|
return 'stagedDependencies unchanged';
|
|
102
105
|
if (mode === 'add') {
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
+
if (afterCount !== beforeCount)
|
|
107
|
+
return `added ${noun}: ${label}`;
|
|
108
|
+
return countReasonUpdates(before, after) > 0
|
|
109
|
+
? `updated 1 ${noun} reason in place: ${label}`
|
|
110
|
+
: `${noun} already present: ${label}`;
|
|
106
111
|
}
|
|
107
112
|
return afterCount === beforeCount
|
|
108
113
|
? `no ${noun} matched: ${label}`
|
|
@@ -123,7 +128,11 @@ export async function patchStagedDependencyCommand(projectRoot, identifier, opti
|
|
|
123
128
|
await runBatchAdd(projectRoot, identifier, mode, options);
|
|
124
129
|
return;
|
|
125
130
|
}
|
|
126
|
-
|
|
131
|
+
// Without --kind, --remove searches the kind its matcher names, or both.
|
|
132
|
+
const kinds = (mode === 'remove' ? inferRemovalKinds(options) : undefined) ?? [
|
|
133
|
+
kindFromOptions(options),
|
|
134
|
+
];
|
|
135
|
+
const kind = kinds.length === 1 ? kinds[0] : undefined;
|
|
127
136
|
// The patch queue loads before the declaration fields resolve so
|
|
128
137
|
// `--remove` can infer `--creates` from the target patch's staged
|
|
129
138
|
// entries.
|
|
@@ -132,31 +141,32 @@ export async function patchStagedDependencyCommand(projectRoot, identifier, opti
|
|
|
132
141
|
const importDependency = mode === 'add' && kind === 'import' ? requireForwardImportOptions(options) : undefined;
|
|
133
142
|
const registrationDependency = mode === 'add' && kind === 'registration' ? requireRegistrationOptions(options) : undefined;
|
|
134
143
|
// Shape-check --add declarations against the loaded queue: a
|
|
135
|
-
// patch-name-shaped --creates/--file is refused
|
|
144
|
+
// patch-name-shaped --creates/--file is refused here instead of surfacing
|
|
136
145
|
// later as an undischargeable staged-dependency-unused.
|
|
137
146
|
const added = importDependency ?? registrationDependency;
|
|
138
147
|
if (added !== undefined) {
|
|
139
148
|
validateStagedDependencyAdd(added, manifest.patches);
|
|
140
149
|
}
|
|
141
150
|
const targets = mode === 'remove'
|
|
142
|
-
? selectRemovalEntries(
|
|
151
|
+
? selectRemovalEntries(kinds, options, targetPatch.stagedDependencies)
|
|
143
152
|
: importDependency !== undefined
|
|
144
|
-
? [importView(importDependency)]
|
|
153
|
+
? [{ kind: 'import', view: importView(importDependency) }]
|
|
145
154
|
: registrationDependency !== undefined
|
|
146
|
-
? [registrationView(registrationDependency)]
|
|
155
|
+
? [{ kind: 'registration', view: registrationView(registrationDependency) }]
|
|
147
156
|
: [];
|
|
148
|
-
const applyKind = (entries,
|
|
149
|
-
if (!
|
|
157
|
+
const applyKind = (entries, entryKind, toView, addition) => {
|
|
158
|
+
if (!kinds.includes(entryKind))
|
|
150
159
|
return [...entries];
|
|
160
|
+
const own = targets.filter((target) => target.kind === entryKind).map(({ view }) => view);
|
|
151
161
|
if (mode !== 'remove')
|
|
152
|
-
return applyMode(entries, mode,
|
|
153
|
-
return
|
|
162
|
+
return applyMode(entries, mode, own[0], toView, addition);
|
|
163
|
+
return own.reduce((remaining, target) => applyMode(remaining, 'remove', target, toView, undefined), [...entries]);
|
|
154
164
|
};
|
|
155
165
|
const applyToStaged = (staged) => {
|
|
156
166
|
if (mode === 'clear')
|
|
157
167
|
return {};
|
|
158
|
-
const forwardImports = applyKind(staged?.forwardImports ?? [],
|
|
159
|
-
const registrations = applyKind(staged?.registrations ?? [],
|
|
168
|
+
const forwardImports = applyKind(staged?.forwardImports ?? [], 'import', importView, importDependency);
|
|
169
|
+
const registrations = applyKind(staged?.registrations ?? [], 'registration', registrationView, registrationDependency);
|
|
160
170
|
return {
|
|
161
171
|
...(forwardImports.length > 0 ? { forwardImports } : {}),
|
|
162
172
|
...(registrations.length > 0 ? { registrations } : {}),
|
|
@@ -164,7 +174,7 @@ export async function patchStagedDependencyCommand(projectRoot, identifier, opti
|
|
|
164
174
|
};
|
|
165
175
|
const existing = targetPatch.stagedDependencies;
|
|
166
176
|
const projected = applyToStaged(existing);
|
|
167
|
-
const summary = describeStagedDependencyChange(
|
|
177
|
+
const summary = describeStagedDependencyChange(existing, projected, mode, kinds, targets);
|
|
168
178
|
if (isDryRun) {
|
|
169
179
|
info(`[dry-run] ${targetPatch.filename}: ${summary}.`);
|
|
170
180
|
outro('Dry run complete — no changes made');
|
|
@@ -184,7 +194,7 @@ export async function patchStagedDependencyCommand(projectRoot, identifier, opti
|
|
|
184
194
|
}
|
|
185
195
|
const before = result.before.stagedDependencies;
|
|
186
196
|
const after = result.after.stagedDependencies;
|
|
187
|
-
info(`${targetPatch.filename}: ${describeStagedDependencyChange(
|
|
197
|
+
info(`${targetPatch.filename}: ${describeStagedDependencyChange(before, after, mode, kinds, targets)}.`);
|
|
188
198
|
if (mode === 'remove' && countStagedEntries(after) === countStagedEntries(before)) {
|
|
189
199
|
// The selection matched when the queue was read; a peer removed the
|
|
190
200
|
// entries before the locked write. Still a miss, so still a refusal.
|
|
@@ -197,7 +207,8 @@ export async function patchStagedDependencyCommand(projectRoot, identifier, opti
|
|
|
197
207
|
args: {
|
|
198
208
|
filename: targetPatch.filename,
|
|
199
209
|
mode,
|
|
200
|
-
kind
|
|
210
|
+
// A kind-less --remove searched both kinds; the delta names which.
|
|
211
|
+
...(kind !== undefined ? { kind } : {}),
|
|
201
212
|
...stagedDependencyDelta(before, after),
|
|
202
213
|
},
|
|
203
214
|
...(options.yes === true ? { yes: true } : {}),
|
|
@@ -219,13 +230,13 @@ export function registerPatchStagedDependency(parent, context) {
|
|
|
219
230
|
.option('--add', 'Add a staged dependency declaration')
|
|
220
231
|
.option('--remove', 'Remove matching staged dependency declaration(s); a selection that matches nothing exits 8')
|
|
221
232
|
.option('--clear', 'Drop the stagedDependencies field entirely')
|
|
222
|
-
.option('--kind <kind>', 'Declaration shape: "import" (forward import, the default) or "registration" (jar.mn packaging line, customElements or actor registration)')
|
|
233
|
+
.option('--kind <kind>', 'Declaration shape: "import" (forward import, the default) or "registration" (jar.mn packaging line, customElements or actor registration); --remove without it takes the kind --specifier or --line names, or both kinds')
|
|
223
234
|
.option('--file <path>', 'Declaring file path relative to engine/')
|
|
224
235
|
.option('--specifier <specifier>', 'Exact import specifier as it appears in source (--kind import)')
|
|
225
236
|
.option('--line <text>', 'Registration/packaging line as the patch adds it, compared whitespace-insensitively (--kind registration)')
|
|
226
237
|
.option('--creates <path>', 'Later-created file path relative to engine/ (with --remove and no --file: removes every declaration for that path)')
|
|
227
238
|
.option('--owner <patch>', 'Exact later patch filename expected to create --creates')
|
|
228
|
-
.option('--reason <text>', 'Human-readable rationale stored with the declaration (with --from: the default for entries without one)')
|
|
239
|
+
.option('--reason <text>', 'Human-readable rationale stored with the declaration; --add on a declaration already present replaces its reason in place (with --from: the default for entries without one)')
|
|
229
240
|
.option('--from <json-file>', 'Add every declaration in a JSON file under one lock hold (--add only): a "lint --per-patch --report" ' +
|
|
230
241
|
"document (its findings' stagedDeclarations for this patch) or an array of " +
|
|
231
242
|
'{ file, specifier | line, creates, owner?, reason?, patch? } entries')
|
|
@@ -63,8 +63,8 @@ export async function patchTierCommand(projectRoot, identifier, options = {}) {
|
|
|
63
63
|
: `change tier from "${before}" to "${after}"`;
|
|
64
64
|
// Destructive-operation contract (docs/lifecycle-invariants.md): manifest
|
|
65
65
|
// metadata mutations get summary + dry-run + confirmation/--yes + history
|
|
66
|
-
// uniformly
|
|
67
|
-
// the
|
|
66
|
+
// uniformly, so --yes skips a real prompt rather than only appearing in
|
|
67
|
+
// the history record.
|
|
68
68
|
const decision = await confirmDestructive({
|
|
69
69
|
operation: 'patch-tier',
|
|
70
70
|
title: `Patch tier: ${target.filename}`,
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Structural equality for patch rename maps, shared by the placement-mode
|
|
3
3
|
* export preview/commit check (`export-flow.ts`) and `patch reorder`'s
|
|
4
|
-
* under-lock drift check.
|
|
5
|
-
*
|
|
6
|
-
* drifting.
|
|
4
|
+
* under-lock drift check. One helper for the sorted-entries comparison
|
|
5
|
+
* keeps the two commit gates from drifting.
|
|
7
6
|
*/
|
|
8
7
|
import type { PatchRenameEntry } from '../core/patch-manifest.js';
|
|
9
8
|
/**
|
|
@@ -17,3 +16,15 @@ export declare function getSortedRenameEntries(renameMap: Map<string, PatchRenam
|
|
|
17
16
|
* triple matches positionally.
|
|
18
17
|
*/
|
|
19
18
|
export declare function renameMapsEqual(left: Map<string, PatchRenameEntry>, right: Map<string, PatchRenameEntry>): boolean;
|
|
19
|
+
/**
|
|
20
|
+
* Writes a committed rename map as one JSON object, old filename to new
|
|
21
|
+
* filename in the queue's new order (`{}` when nothing was renumbered), so
|
|
22
|
+
* a session can rewrite its references to the renumbered patches from the
|
|
23
|
+
* file instead of from the printed summary. Used by `patch reorder
|
|
24
|
+
* --map-out` and `patch split --map-out`.
|
|
25
|
+
*
|
|
26
|
+
* @param path - Output path, relative to the working directory
|
|
27
|
+
* @param renameMap - The committed rename map
|
|
28
|
+
* @returns The absolute path written
|
|
29
|
+
*/
|
|
30
|
+
export declare function writeRenameMapFile(path: string, renameMap: Map<string, PatchRenameEntry>): Promise<string>;
|
|
@@ -2,10 +2,11 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* Structural equality for patch rename maps, shared by the placement-mode
|
|
4
4
|
* export preview/commit check (`export-flow.ts`) and `patch reorder`'s
|
|
5
|
-
* under-lock drift check.
|
|
6
|
-
*
|
|
7
|
-
* drifting.
|
|
5
|
+
* under-lock drift check. One helper for the sorted-entries comparison
|
|
6
|
+
* keeps the two commit gates from drifting.
|
|
8
7
|
*/
|
|
8
|
+
import { dirname, resolve } from 'node:path';
|
|
9
|
+
import { ensureDir, writeJson } from '../utils/fs.js';
|
|
9
10
|
/**
|
|
10
11
|
* Rename-map entries ordered by target order, so previews, history entries
|
|
11
12
|
* and equality checks all walk the queue in its final on-disk order.
|
|
@@ -34,3 +35,20 @@ export function renameMapsEqual(left, right) {
|
|
|
34
35
|
leftEntry.newOrder === rightEntry.newOrder);
|
|
35
36
|
});
|
|
36
37
|
}
|
|
38
|
+
/**
|
|
39
|
+
* Writes a committed rename map as one JSON object, old filename to new
|
|
40
|
+
* filename in the queue's new order (`{}` when nothing was renumbered), so
|
|
41
|
+
* a session can rewrite its references to the renumbered patches from the
|
|
42
|
+
* file instead of from the printed summary. Used by `patch reorder
|
|
43
|
+
* --map-out` and `patch split --map-out`.
|
|
44
|
+
*
|
|
45
|
+
* @param path - Output path, relative to the working directory
|
|
46
|
+
* @param renameMap - The committed rename map
|
|
47
|
+
* @returns The absolute path written
|
|
48
|
+
*/
|
|
49
|
+
export async function writeRenameMapFile(path, renameMap) {
|
|
50
|
+
const absolute = resolve(path);
|
|
51
|
+
await ensureDir(dirname(absolute));
|
|
52
|
+
await writeJson(absolute, Object.fromEntries(getSortedRenameEntries(renameMap).map(([from, entry]) => [from, entry.newFilename])));
|
|
53
|
+
return absolute;
|
|
54
|
+
}
|
|
@@ -62,11 +62,10 @@ export declare function findMissingFiles(engineDir: string, files: readonly stri
|
|
|
62
62
|
/**
|
|
63
63
|
* One unmanaged file and the owned directory that made it adjacent.
|
|
64
64
|
*
|
|
65
|
-
* The anchor
|
|
66
|
-
*
|
|
67
|
-
*
|
|
68
|
-
*
|
|
69
|
-
* adjacency by hand from the manifest.
|
|
65
|
+
* The anchor names which of the patch's owned locations the file sits
|
|
66
|
+
* beside, so an unattended run can triage a refusal on a patch that owns
|
|
67
|
+
* files in several directories without re-deriving the adjacency by hand
|
|
68
|
+
* from the manifest.
|
|
70
69
|
*/
|
|
71
70
|
export interface AdjacentUnmanagedFile {
|
|
72
71
|
/** Engine-relative path of the unmanaged file. */
|
|
@@ -108,9 +108,10 @@ export declare function storeReExportLintResult(lintCtx: ReExportLintContext, pa
|
|
|
108
108
|
* when the projection introduces error-severity cross-patch findings the
|
|
109
109
|
* current queue does not have (a forward import an earlier owner gained,
|
|
110
110
|
* say). Mirrors `re-export --files` (its projected-state conflict) and the
|
|
111
|
-
* `--scan` adoption gate, which only
|
|
112
|
-
* re-export of an unchanged file set with new CONTENT
|
|
113
|
-
* queue
|
|
111
|
+
* `--scan` adoption gate, which only covers files a scan adopted: without
|
|
112
|
+
* this a plain re-export of an unchanged file set with new CONTENT would
|
|
113
|
+
* pass, and the queue would carry the error until the next `export`
|
|
114
|
+
* placement refused it.
|
|
114
115
|
*
|
|
115
116
|
* Runs in dry-run. `--force-unsafe` downgrades the refusal to warnings;
|
|
116
117
|
* `--skip-lint` does not bypass it, same as `--files`. The baseline is the
|
|
@@ -221,9 +221,10 @@ export async function storeReExportLintResult(lintCtx, patchFilename, projectedM
|
|
|
221
221
|
* when the projection introduces error-severity cross-patch findings the
|
|
222
222
|
* current queue does not have (a forward import an earlier owner gained,
|
|
223
223
|
* say). Mirrors `re-export --files` (its projected-state conflict) and the
|
|
224
|
-
* `--scan` adoption gate, which only
|
|
225
|
-
* re-export of an unchanged file set with new CONTENT
|
|
226
|
-
* queue
|
|
224
|
+
* `--scan` adoption gate, which only covers files a scan adopted: without
|
|
225
|
+
* this a plain re-export of an unchanged file set with new CONTENT would
|
|
226
|
+
* pass, and the queue would carry the error until the next `export`
|
|
227
|
+
* placement refused it.
|
|
227
228
|
*
|
|
228
229
|
* Runs in dry-run. `--force-unsafe` downgrades the refusal to warnings;
|
|
229
230
|
* `--skip-lint` does not bypass it, same as `--files`. The baseline is the
|
|
@@ -97,10 +97,16 @@ function validatePathFlagValues(options) {
|
|
|
97
97
|
}
|
|
98
98
|
}
|
|
99
99
|
}
|
|
100
|
+
/**
|
|
101
|
+
* A retirement names its owner among explicitly selected patches. It
|
|
102
|
+
* combines with `--scan`: the retired path leaves the scan's base first,
|
|
103
|
+
* and the scan cannot adopt it back, since a retired created file is absent
|
|
104
|
+
* and a retired upstream file is clean at HEAD.
|
|
105
|
+
*/
|
|
100
106
|
function validateExpectedRemovalUsage(patches, options) {
|
|
101
107
|
if (options.expectRemoved?.length &&
|
|
102
|
-
(options.
|
|
103
|
-
throw new InvalidArgumentError('--expect-removed requires explicit selected patches and
|
|
108
|
+
(options.all || options.files !== undefined || patches.length === 0)) {
|
|
109
|
+
throw new InvalidArgumentError('--expect-removed requires explicit selected patches and cannot combine with --files or --all.', '--expect-removed');
|
|
104
110
|
}
|
|
105
111
|
}
|
|
106
112
|
/**
|
|
@@ -6,8 +6,7 @@
|
|
|
6
6
|
* Under contention the lock wait runs to many minutes, and an argument the
|
|
7
7
|
* run was always going to refuse (an empty patch name from an unquoted
|
|
8
8
|
* `"$@"`, a changed-file path passed as a positional, a path flag that
|
|
9
|
-
* swallowed the next flag)
|
|
10
|
-
* checks read the manifest and a path-scoped `git status` without the lock.
|
|
9
|
+
* swallowed the next flag) is reported before that wait: these checks read the manifest and a path-scoped `git status` without the lock.
|
|
11
10
|
* The command repeats its own resolution under the lock, so a manifest that
|
|
12
11
|
* changes in between is still read fresh there.
|
|
13
12
|
*/
|
|
@@ -13,6 +13,6 @@ export declare function fingerprintScopedDryRunState(engineDir: string, patchesD
|
|
|
13
13
|
/**
|
|
14
14
|
* Names whoever else wrote during the dry run: history records from other
|
|
15
15
|
* invocations since it started, and a live holder of the engine-session
|
|
16
|
-
* lock (which a dry run
|
|
16
|
+
* lock (which a dry run does not take). Empty when there is no evidence.
|
|
17
17
|
*/
|
|
18
18
|
export declare function describeForeignWriters(patchesDir: string, sinceMs: number): Promise<string[]>;
|
|
@@ -2,10 +2,9 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* The scoped half of the `re-export --dry-run` purity guard.
|
|
4
4
|
*
|
|
5
|
-
* A dry run takes no engine-session lock
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
* immediate repeat was clean. The scoped fingerprint covers only what the
|
|
5
|
+
* A dry run takes no engine-session lock, so peers keep writing while it
|
|
6
|
+
* runs. A whole-tree fingerprint would report every peer's write as
|
|
7
|
+
* "invariant violated … This is a FireForge bug". The scoped fingerprint covers only what the
|
|
9
8
|
* dry run could touch: the selected patches' bodies and manifest rows, the
|
|
10
9
|
* engine files they own, the engine HEAD and the engine index. A mismatch
|
|
11
10
|
* that remains is attributed to a foreign writer when the history log or
|
|
@@ -17,6 +16,7 @@ import { readEngineSessionLockStatus } from '../core/engine-session-lock.js';
|
|
|
17
16
|
import { git } from '../core/git-base.js';
|
|
18
17
|
import { historyRecordIdentity, resolveHistoryLogPath } from '../core/history-log-file.js';
|
|
19
18
|
import { PATCHES_MANIFEST } from '../core/patch-manifest-io.js';
|
|
19
|
+
import { canonicalizePatchRow } from '../core/patch-manifest-key-order.js';
|
|
20
20
|
import { GeneralError } from '../errors/base.js';
|
|
21
21
|
import { getNodeErrorCode, toError } from '../utils/errors.js';
|
|
22
22
|
import { sha256Hex } from '../utils/hash.js';
|
|
@@ -33,7 +33,11 @@ async function hashOrAbsent(path, label) {
|
|
|
33
33
|
throw new GeneralError(`[dry-run] cannot fingerprint ${label} for the purity guard: ${toError(error).message}`, error);
|
|
34
34
|
}
|
|
35
35
|
}
|
|
36
|
-
/**
|
|
36
|
+
/**
|
|
37
|
+
* The selected rows of `patches.json`, so a peer's write to another row is
|
|
38
|
+
* not a violation. Rows are hashed in canonical key order: a peer's write
|
|
39
|
+
* that only canonicalizes a selected row's key order changes no content.
|
|
40
|
+
*/
|
|
37
41
|
async function selectedRowsFingerprint(patchesDir, filenames) {
|
|
38
42
|
let raw;
|
|
39
43
|
try {
|
|
@@ -47,7 +51,9 @@ async function selectedRowsFingerprint(patchesDir, filenames) {
|
|
|
47
51
|
try {
|
|
48
52
|
const parsed = JSON.parse(raw);
|
|
49
53
|
const rows = isObject(parsed) && isArray(parsed['patches']) ? parsed['patches'] : [];
|
|
50
|
-
const selected = rows
|
|
54
|
+
const selected = rows
|
|
55
|
+
.filter((row) => isObject(row) && typeof row['filename'] === 'string' && filenames.has(row['filename']))
|
|
56
|
+
.map((row) => (isObject(row) ? canonicalizePatchRow(row) : row));
|
|
51
57
|
return sha256Hex(JSON.stringify(selected));
|
|
52
58
|
}
|
|
53
59
|
catch {
|
|
@@ -112,7 +118,7 @@ async function foreignHistoryRecords(projectRoot, sinceMs) {
|
|
|
112
118
|
/**
|
|
113
119
|
* Names whoever else wrote during the dry run: history records from other
|
|
114
120
|
* invocations since it started, and a live holder of the engine-session
|
|
115
|
-
* lock (which a dry run
|
|
121
|
+
* lock (which a dry run does not take). Empty when there is no evidence.
|
|
116
122
|
*/
|
|
117
123
|
export async function describeForeignWriters(patchesDir, sinceMs) {
|
|
118
124
|
const projectRoot = dirname(resolve(patchesDir));
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { PatchesManifest, PatchMetadata, ReExportOptions } from '../types/commands/index.js';
|
|
2
|
+
import type { ProjectPaths } from '../types/config.js';
|
|
3
|
+
/** What {@link dropRetiredPathDeclarations} needs from the run. */
|
|
4
|
+
export interface RetiredPathDeclarationsArgs {
|
|
5
|
+
/** Resolved project paths. */
|
|
6
|
+
paths: ProjectPaths;
|
|
7
|
+
/** The queue as the run loaded it (judged in a dry run). */
|
|
8
|
+
manifest: PatchesManifest;
|
|
9
|
+
/** The run's options; `expectRemoved` holds the validated paths. */
|
|
10
|
+
options: ReExportOptions;
|
|
11
|
+
/** The run's selected patches. */
|
|
12
|
+
selectedPatches: readonly PatchMetadata[];
|
|
13
|
+
/** Name the drops without writing. */
|
|
14
|
+
isDryRun: boolean;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Drops (or, in a dry run, names) every staged declaration whose `creates`
|
|
18
|
+
* path this run retired. Runs after the selected patches are written, so a
|
|
19
|
+
* path whose owner failed to re-export is still owned and its declarations
|
|
20
|
+
* stay.
|
|
21
|
+
*/
|
|
22
|
+
export declare function dropRetiredPathDeclarations(args: RetiredPathDeclarationsArgs): Promise<void>;
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
// SPDX-License-Identifier: EUPL-1.2
|
|
2
|
+
/**
|
|
3
|
+
* `re-export --expect-removed` drops the staged declarations whose
|
|
4
|
+
* `creates` path the run retires.
|
|
5
|
+
*
|
|
6
|
+
* Retiring a file would otherwise leave another patch's staged
|
|
7
|
+
* registration (or forward import) for it in place, unflagged until the
|
|
8
|
+
* per-patch lint after both re-exports reported `staged-dependency-unused`.
|
|
9
|
+
* The run that retires the path drops every such declaration, in any patch of the queue, in one manifest
|
|
10
|
+
* update, and names each one.
|
|
11
|
+
*/
|
|
12
|
+
import { withPatchDirectoryLock } from '../core/patch-lock.js';
|
|
13
|
+
import { loadPatchesManifestForWrite, mutatePatchRowsInManifest } from '../core/patch-manifest.js';
|
|
14
|
+
import { info } from '../utils/logger.js';
|
|
15
|
+
import { recordStagedDeclarationPrune, } from './re-export-stale-registrations.js';
|
|
16
|
+
/**
|
|
17
|
+
* Finds the declarations whose `creates` path is retired and owned by no
|
|
18
|
+
* patch outside `retiring`.
|
|
19
|
+
*
|
|
20
|
+
* @param manifest - The queue to judge
|
|
21
|
+
* @param removed - The run's `--expect-removed` paths
|
|
22
|
+
* @param retiring - Patches whose ownership of a removed path does not
|
|
23
|
+
* count: the selected owners in a dry run, whose rows are not rewritten
|
|
24
|
+
* yet; nothing after the write, where a failed owner still owns its path
|
|
25
|
+
*/
|
|
26
|
+
function planRetiredDeclarationDrops(manifest, removed, retiring) {
|
|
27
|
+
const orphaned = new Set(removed.filter((file) => !manifest.patches.some((patch) => !retiring.has(patch.filename) && patch.filesAffected.includes(file))));
|
|
28
|
+
if (orphaned.size === 0)
|
|
29
|
+
return [];
|
|
30
|
+
const drops = [];
|
|
31
|
+
for (const patch of manifest.patches) {
|
|
32
|
+
const drop = planHolderDrop(patch, orphaned);
|
|
33
|
+
if (drop !== undefined)
|
|
34
|
+
drops.push(drop);
|
|
35
|
+
}
|
|
36
|
+
return drops;
|
|
37
|
+
}
|
|
38
|
+
function planHolderDrop(patch, orphaned) {
|
|
39
|
+
const forwardImports = patch.stagedDependencies?.forwardImports ?? [];
|
|
40
|
+
const registrations = patch.stagedDependencies?.registrations ?? [];
|
|
41
|
+
const dropped = [
|
|
42
|
+
...registrations
|
|
43
|
+
.filter((entry) => orphaned.has(entry.creates))
|
|
44
|
+
.map((entry) => ({ kind: 'registration', ...entry })),
|
|
45
|
+
...forwardImports
|
|
46
|
+
.filter((entry) => orphaned.has(entry.creates))
|
|
47
|
+
.map((entry) => ({ kind: 'import', ...entry })),
|
|
48
|
+
];
|
|
49
|
+
if (dropped.length === 0)
|
|
50
|
+
return undefined;
|
|
51
|
+
const keptImports = forwardImports.filter((entry) => !orphaned.has(entry.creates));
|
|
52
|
+
const keptRegistrations = registrations.filter((entry) => !orphaned.has(entry.creates));
|
|
53
|
+
const staged = {
|
|
54
|
+
...(keptImports.length > 0 ? { forwardImports: keptImports } : {}),
|
|
55
|
+
...(keptRegistrations.length > 0 ? { registrations: keptRegistrations } : {}),
|
|
56
|
+
};
|
|
57
|
+
return {
|
|
58
|
+
holder: patch.filename,
|
|
59
|
+
dropped,
|
|
60
|
+
stagedDependencies: Object.keys(staged).length > 0 ? staged : undefined,
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
function reportRetiredDeclarationDrops(drops, isDryRun) {
|
|
64
|
+
const verb = isDryRun ? 'would drop' : 'drops';
|
|
65
|
+
for (const { holder, dropped } of drops) {
|
|
66
|
+
for (const entry of dropped) {
|
|
67
|
+
const what = entry.kind === 'registration'
|
|
68
|
+
? `staged registration ${entry.file} "${entry.line.trim()}"`
|
|
69
|
+
: `staged forward-import ${entry.file} "${entry.specifier}"`;
|
|
70
|
+
info(`${holder}: ${verb} ${what}: --expect-removed retires ${entry.creates}.`);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Drops (or, in a dry run, names) every staged declaration whose `creates`
|
|
76
|
+
* path this run retired. Runs after the selected patches are written, so a
|
|
77
|
+
* path whose owner failed to re-export is still owned and its declarations
|
|
78
|
+
* stay.
|
|
79
|
+
*/
|
|
80
|
+
export async function dropRetiredPathDeclarations(args) {
|
|
81
|
+
const { manifest, isDryRun } = args;
|
|
82
|
+
const patchesDir = args.paths.patches;
|
|
83
|
+
const removed = args.options.expectRemoved ?? [];
|
|
84
|
+
const selected = new Set(args.selectedPatches.map((patch) => patch.filename));
|
|
85
|
+
if (removed.length === 0)
|
|
86
|
+
return;
|
|
87
|
+
if (isDryRun) {
|
|
88
|
+
reportRetiredDeclarationDrops(planRetiredDeclarationDrops(manifest, removed, selected), isDryRun);
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
const drops = await withPatchDirectoryLock(patchesDir, async () => {
|
|
92
|
+
const current = await loadPatchesManifestForWrite(patchesDir);
|
|
93
|
+
if (!current)
|
|
94
|
+
return [];
|
|
95
|
+
const planned = planRetiredDeclarationDrops(current, removed, new Set());
|
|
96
|
+
const byHolder = new Map(planned.map((drop) => [drop.holder, drop]));
|
|
97
|
+
if (byHolder.size === 0)
|
|
98
|
+
return [];
|
|
99
|
+
await mutatePatchRowsInManifest(patchesDir, [...byHolder.keys()], (existing) => {
|
|
100
|
+
const drop = byHolder.get(existing.filename);
|
|
101
|
+
if (drop === undefined)
|
|
102
|
+
return null;
|
|
103
|
+
return drop.stagedDependencies === undefined
|
|
104
|
+
? { unset: ['stagedDependencies'] }
|
|
105
|
+
: { set: { stagedDependencies: drop.stagedDependencies } };
|
|
106
|
+
});
|
|
107
|
+
return planned;
|
|
108
|
+
}, { command: 're-export' });
|
|
109
|
+
reportRetiredDeclarationDrops(drops, isDryRun);
|
|
110
|
+
for (const drop of drops) {
|
|
111
|
+
await recordStagedDeclarationPrune(patchesDir, drop.holder, drop.dropped, 'staged declarations on retired paths');
|
|
112
|
+
}
|
|
113
|
+
}
|
|
@@ -23,7 +23,7 @@ import { reportForeignDrift } from './re-export-drift.js';
|
|
|
23
23
|
import { buildHunkSelectedDiff, hunkSelectionOf } from './re-export-hunks.js';
|
|
24
24
|
import { assertRefreshedBodyHasNoNewQueueErrors, lintReExportedPatch, refreshQueueCtxEntry, storeReExportLintResult, } from './re-export-lint.js';
|
|
25
25
|
import { assertScanAdoptionsHaveNoForwardImports, assertScanFileAdditionsHaveDiffHunks, confirmBroadScanAdditions, scanPatchFilesForReExport, } from './re-export-scan.js';
|
|
26
|
-
import { planStaleRegistrationDrop, recordStaleRegistrationDrop, reportStaleRegistrationDrop, } from './re-export-stale-registrations.js';
|
|
26
|
+
import { findPendingRegistrationCreates, planStaleRegistrationDrop, recordStaleRegistrationDrop, reportStaleRegistrationDrop, } from './re-export-stale-registrations.js';
|
|
27
27
|
const GIT_INDEX_LOCK_RETRY_MS = 300;
|
|
28
28
|
/**
|
|
29
29
|
* Retries a single patch re-export exactly once when the failure is
|
|
@@ -211,7 +211,7 @@ async function reExportSinglePatch(args) {
|
|
|
211
211
|
return false;
|
|
212
212
|
}
|
|
213
213
|
const { updates, ignoreChecks, effectiveTier, existingIgnoreSet, flagIgnoreSet } = computeReExportUpdates(patch, options, currentFilesAffected);
|
|
214
|
-
const stalePlan = planStaleRegistrationDrop(manifest, patch, currentFilesAffected);
|
|
214
|
+
const stalePlan = planStaleRegistrationDrop(manifest, patch, currentFilesAffected, await findPendingRegistrationCreates(paths.engine, manifest, patch, currentFilesAffected, adjacentCtx.expectedNew));
|
|
215
215
|
if (stalePlan !== undefined)
|
|
216
216
|
reportStaleRegistrationDrop(patch.filename, stalePlan, isDryRun);
|
|
217
217
|
const unset = applyStaleRegistrationDrop(stalePlan, updates);
|
|
@@ -1,18 +1,39 @@
|
|
|
1
|
-
import type { PatchesManifest, PatchMetadata, PatchStagedDependencies, PatchStagedRegistration } from '../types/commands/index.js';
|
|
1
|
+
import type { PatchesManifest, PatchMetadata, PatchStagedDependencies, PatchStagedForwardImport, PatchStagedRegistration } from '../types/commands/index.js';
|
|
2
2
|
/** The holder's registrations split by whether the queue still owns `creates`. */
|
|
3
3
|
export interface StaleRegistrationPlan {
|
|
4
4
|
/** Registrations whose `creates` path no patch owns. */
|
|
5
5
|
dropped: PatchStagedRegistration[];
|
|
6
|
+
/** Unowned registrations kept because their `creates` file is pending adoption. */
|
|
7
|
+
pending: PatchStagedRegistration[];
|
|
6
8
|
/** The staged block to write, or undefined when nothing is left. */
|
|
7
9
|
stagedDependencies: PatchStagedDependencies | undefined;
|
|
8
10
|
}
|
|
11
|
+
/**
|
|
12
|
+
* The unowned `creates` paths of `patch`'s registrations that are pending
|
|
13
|
+
* adoption: the file exists in `engine/`, or is an `--expect-new` path of
|
|
14
|
+
* this run. Such a registration is waiting for its subject patch's scan.
|
|
15
|
+
*/
|
|
16
|
+
export declare function findPendingRegistrationCreates(engineDir: string, manifest: PatchesManifest, patch: PatchMetadata, currentFilesAffected: readonly string[], expectedNew: ReadonlySet<string>): Promise<Set<string>>;
|
|
9
17
|
/**
|
|
10
18
|
* Finds `patch`'s registrations whose `creates` path no patch in the queue
|
|
11
|
-
* owns, judging `patch` by the file list this re-export will write.
|
|
12
|
-
*
|
|
19
|
+
* owns, judging `patch` by the file list this re-export will write. A
|
|
20
|
+
* registration whose `creates` path is in `pending` (see
|
|
21
|
+
* {@link findPendingRegistrationCreates}) is kept and reported instead.
|
|
22
|
+
* Returns undefined when nothing is stale or pending.
|
|
13
23
|
*/
|
|
14
|
-
export declare function planStaleRegistrationDrop(manifest: PatchesManifest, patch: PatchMetadata, currentFilesAffected: readonly string[]): StaleRegistrationPlan | undefined;
|
|
15
|
-
/** Names each dropped registration, in both a dry run and a write. */
|
|
24
|
+
export declare function planStaleRegistrationDrop(manifest: PatchesManifest, patch: PatchMetadata, currentFilesAffected: readonly string[], pendingCreates?: ReadonlySet<string>): StaleRegistrationPlan | undefined;
|
|
25
|
+
/** Names each dropped and each kept-pending registration, in both a dry run and a write. */
|
|
16
26
|
export declare function reportStaleRegistrationDrop(patchFilename: string, plan: StaleRegistrationPlan, isDryRun: boolean): void;
|
|
17
|
-
/**
|
|
27
|
+
/** One declaration a re-export pruned, as the history log records it. */
|
|
28
|
+
export type PrunedStagedDeclaration = ({
|
|
29
|
+
kind: 'registration';
|
|
30
|
+
} & PatchStagedRegistration) | ({
|
|
31
|
+
kind: 'import';
|
|
32
|
+
} & PatchStagedForwardImport);
|
|
33
|
+
/**
|
|
34
|
+
* Records declarations a re-export pruned from one patch as a delta, like
|
|
35
|
+
* `staged-dependency --remove`.
|
|
36
|
+
*/
|
|
37
|
+
export declare function recordStagedDeclarationPrune(patchesDir: string, patchFilename: string, removed: readonly PrunedStagedDeclaration[], what: string): Promise<void>;
|
|
38
|
+
/** Records the dropped registrations as a delta, like `staged-dependency --remove`. */
|
|
18
39
|
export declare function recordStaleRegistrationDrop(patchesDir: string, patchFilename: string, plan: StaleRegistrationPlan): Promise<void>;
|