@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
|
@@ -6,7 +6,7 @@ import { getProjectPaths, loadConfig } from '../../core/config.js';
|
|
|
6
6
|
import { stdioIsInteractive } from '../../core/destructive.js';
|
|
7
7
|
import { getFurnacePaths, loadFurnaceConfig, loadFurnaceState, updateFurnaceState, writeFurnaceConfig, } from '../../core/furnace-config.js';
|
|
8
8
|
import { resolveFtlDir, xpcshellTestParentDir } from '../../core/furnace-constants.js';
|
|
9
|
-
import { completeJournalRollback, runFurnaceMutation } from '../../core/furnace-operation.js';
|
|
9
|
+
import { completeJournalRollback, runFurnaceMutation, waitLockMutationOptions, } from '../../core/furnace-operation.js';
|
|
10
10
|
import { createRollbackJournal, snapshotDir, snapshotFile, } from '../../core/furnace-rollback.js';
|
|
11
11
|
import { isGitRepository } from '../../core/git.js';
|
|
12
12
|
import { deregisterTestManifest } from '../../core/moz-manifest-register.js';
|
|
@@ -343,7 +343,7 @@ export async function furnaceRemoveCommand(projectRoot, name, options = {}) {
|
|
|
343
343
|
// rollback pathway.
|
|
344
344
|
const paths = getProjectPaths(projectRoot);
|
|
345
345
|
await requireGitEngineForRemove(type, name, paths.engine);
|
|
346
|
-
|
|
346
|
+
const mutate = async (ctx) => {
|
|
347
347
|
const journal = createRollbackJournal();
|
|
348
348
|
ctx.registerJournal(journal);
|
|
349
349
|
try {
|
|
@@ -408,7 +408,8 @@ export async function furnaceRemoveCommand(projectRoot, name, options = {}) {
|
|
|
408
408
|
subject: `component "${name}"`,
|
|
409
409
|
});
|
|
410
410
|
}
|
|
411
|
-
}
|
|
411
|
+
};
|
|
412
|
+
await runFurnaceMutation(projectRoot, 'remove-rollback', mutate, waitLockMutationOptions(options.waitLockSeconds));
|
|
412
413
|
info(`Removed "${name}" from furnace.json`);
|
|
413
414
|
outro('Component removed');
|
|
414
415
|
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `furnace rename --dry-run`: the plan a rename would carry out, rendered
|
|
3
|
+
* from reads only. A rename edits three engine registration files besides
|
|
4
|
+
* moving the component, and before this none of those edits was visible
|
|
5
|
+
* until it had run.
|
|
6
|
+
*/
|
|
7
|
+
import type { FurnaceConfig } from '../../types/furnace.js';
|
|
8
|
+
/** Inputs for {@link renderRenamePlan}. */
|
|
9
|
+
export interface RenamePlanInput {
|
|
10
|
+
config: FurnaceConfig;
|
|
11
|
+
oldName: string;
|
|
12
|
+
newName: string;
|
|
13
|
+
/** Workspace directory of the component being renamed. */
|
|
14
|
+
oldDir: string;
|
|
15
|
+
/** On-disk directory label: `custom` or `overrides`. */
|
|
16
|
+
componentDirLabel: 'custom' | 'overrides';
|
|
17
|
+
engineDir: string;
|
|
18
|
+
/** Project marker a freshly added registration line would carry. */
|
|
19
|
+
markerComment: string | undefined;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Renders the rename plan: workspace file moves, the furnace.json re-key,
|
|
23
|
+
* and, for a custom component, every engine edit the real run would make
|
|
24
|
+
* (registrations only when the component is registered).
|
|
25
|
+
*
|
|
26
|
+
* @param input - See {@link RenamePlanInput}
|
|
27
|
+
* @returns The plan as display lines joined by newlines
|
|
28
|
+
*/
|
|
29
|
+
export declare function renderRenamePlan(input: RenamePlanInput): Promise<string>;
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
// SPDX-License-Identifier: EUPL-1.2
|
|
2
|
+
/**
|
|
3
|
+
* `furnace rename --dry-run`: the plan a rename would carry out, rendered
|
|
4
|
+
* from reads only. A rename edits three engine registration files besides
|
|
5
|
+
* moving the component, and before this none of those edits was visible
|
|
6
|
+
* until it had run.
|
|
7
|
+
*/
|
|
8
|
+
import { readdir } from 'node:fs/promises';
|
|
9
|
+
import { join } from 'node:path';
|
|
10
|
+
import { isComponentSourceFile, JAR_MN, resolveFtlChromeSubPath, resolveFtlDir, resolveFtlLocaleJarMnPath, } from '../../core/furnace-constants.js';
|
|
11
|
+
import { hasLocaleFtlJarMnEntry } from '../../core/furnace-registration.js';
|
|
12
|
+
import { isTagAlreadyRegistered } from '../../core/furnace-registration-ast.js';
|
|
13
|
+
import { pathExists, readText } from '../../utils/fs.js';
|
|
14
|
+
import { renameComponentFileName, renameTagInDescription } from './rename-helpers.js';
|
|
15
|
+
/** Plan lines for the workspace move and the furnace.json re-key. */
|
|
16
|
+
async function workspaceLines(input) {
|
|
17
|
+
const { config, oldName, newName, oldDir, componentDirLabel } = input;
|
|
18
|
+
const lines = [
|
|
19
|
+
`Workspace: components/${componentDirLabel}/${oldName}/ → components/${componentDirLabel}/${newName}/`,
|
|
20
|
+
];
|
|
21
|
+
const entries = (await readdir(oldDir, { withFileTypes: true }))
|
|
22
|
+
.filter((entry) => entry.isFile())
|
|
23
|
+
.map((entry) => entry.name)
|
|
24
|
+
.sort();
|
|
25
|
+
for (const fileName of entries) {
|
|
26
|
+
const renamed = renameComponentFileName(fileName, oldName, newName);
|
|
27
|
+
const rewrite = isComponentSourceFile(fileName) ? ' (tag and class references rewritten)' : '';
|
|
28
|
+
lines.push(` ${fileName}${renamed === fileName ? '' : ` → ${renamed}`}${rewrite}`);
|
|
29
|
+
}
|
|
30
|
+
const entry = config.custom[oldName] ?? config.overrides[oldName];
|
|
31
|
+
lines.push(`furnace.json: "${oldName}" → "${newName}"`);
|
|
32
|
+
if (entry) {
|
|
33
|
+
const description = renameTagInDescription(entry.description, oldName, newName);
|
|
34
|
+
if (description !== entry.description) {
|
|
35
|
+
lines.push(` description: "${entry.description}" → "${description}"`);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
return lines;
|
|
39
|
+
}
|
|
40
|
+
/** Plan line for the customElements.js registration. */
|
|
41
|
+
async function customElementsLine(input) {
|
|
42
|
+
const { engineDir, oldName, newName, markerComment } = input;
|
|
43
|
+
const path = join(engineDir, 'toolkit/content/customElements.js');
|
|
44
|
+
if (!(await pathExists(path)))
|
|
45
|
+
return undefined;
|
|
46
|
+
const content = await readText(path);
|
|
47
|
+
const oldRegistered = isTagAlreadyRegistered(content, oldName);
|
|
48
|
+
if (isTagAlreadyRegistered(content, newName)) {
|
|
49
|
+
return `customElements.js: "${newName}" is already registered${oldRegistered ? `; remove the "${oldName}" entry` : ''}`;
|
|
50
|
+
}
|
|
51
|
+
if (oldRegistered) {
|
|
52
|
+
return `customElements.js: rewrite the "${oldName}" entry in place as "${newName}" (position and marker comments kept)`;
|
|
53
|
+
}
|
|
54
|
+
const marker = markerComment !== undefined ? ` marked // ${markerComment}:` : '';
|
|
55
|
+
return `customElements.js: add a "${newName}" entry${marker}`;
|
|
56
|
+
}
|
|
57
|
+
/** Plan line for the toolkit/content/jar.mn widget lines. */
|
|
58
|
+
async function jarLine(input) {
|
|
59
|
+
const { engineDir, oldName, newName, oldDir } = input;
|
|
60
|
+
const path = join(engineDir, JAR_MN);
|
|
61
|
+
if (!(await pathExists(path)))
|
|
62
|
+
return undefined;
|
|
63
|
+
const oldLines = (await readText(path))
|
|
64
|
+
.split('\n')
|
|
65
|
+
.filter((line) => line.includes(`(widgets/${oldName}/`)).length;
|
|
66
|
+
const newFiles = (await readdir(oldDir, { withFileTypes: true }))
|
|
67
|
+
.filter((entry) => entry.isFile() && /\.(?:mjs|css)$/.test(entry.name))
|
|
68
|
+
.map((entry) => renameComponentFileName(entry.name, oldName, newName))
|
|
69
|
+
.sort();
|
|
70
|
+
return (`${JAR_MN}: replace ${oldLines} "${oldName}" line(s) with ` +
|
|
71
|
+
(newFiles.length > 0 ? newFiles.join(', ') : 'none (no .mjs/.css files)'));
|
|
72
|
+
}
|
|
73
|
+
/** Plan lines for the deployed .ftl and its locale jar.mn line. */
|
|
74
|
+
async function localeLines(input, componentConfig) {
|
|
75
|
+
const { config, engineDir, oldName, newName } = input;
|
|
76
|
+
if (!componentConfig.localized)
|
|
77
|
+
return [];
|
|
78
|
+
const ftlDir = resolveFtlDir(config.ftlBasePath);
|
|
79
|
+
const lines = [];
|
|
80
|
+
if (await pathExists(join(engineDir, ftlDir, `${oldName}.ftl`))) {
|
|
81
|
+
lines.push(`${ftlDir}/${oldName}.ftl → ${newName}.ftl`);
|
|
82
|
+
}
|
|
83
|
+
const chromeSubPath = resolveFtlChromeSubPath(ftlDir);
|
|
84
|
+
const localeJarRel = resolveFtlLocaleJarMnPath(ftlDir);
|
|
85
|
+
if (chromeSubPath === undefined || localeJarRel === undefined)
|
|
86
|
+
return lines;
|
|
87
|
+
const present = await hasLocaleFtlJarMnEntry(engineDir, localeJarRel, oldName, chromeSubPath);
|
|
88
|
+
if (componentConfig.sharedFtl !== undefined) {
|
|
89
|
+
lines.push(`${localeJarRel}: no per-component line (sharedFtl: ${componentConfig.sharedFtl})` +
|
|
90
|
+
(present ? `; remove the stale "${oldName}.ftl" line` : ''));
|
|
91
|
+
}
|
|
92
|
+
else {
|
|
93
|
+
lines.push(present
|
|
94
|
+
? `${localeJarRel}: re-point the "${oldName}.ftl" line to "${newName}.ftl"`
|
|
95
|
+
: `${localeJarRel}: no "${oldName}.ftl" line to re-point (left unchanged)`);
|
|
96
|
+
}
|
|
97
|
+
return lines;
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Renders the rename plan: workspace file moves, the furnace.json re-key,
|
|
101
|
+
* and, for a custom component, every engine edit the real run would make
|
|
102
|
+
* (registrations only when the component is registered).
|
|
103
|
+
*
|
|
104
|
+
* @param input - See {@link RenamePlanInput}
|
|
105
|
+
* @returns The plan as display lines joined by newlines
|
|
106
|
+
*/
|
|
107
|
+
export async function renderRenamePlan(input) {
|
|
108
|
+
const lines = await workspaceLines(input);
|
|
109
|
+
const componentConfig = input.config.custom[input.oldName];
|
|
110
|
+
if (!componentConfig || !(await pathExists(input.engineDir))) {
|
|
111
|
+
return lines.join('\n');
|
|
112
|
+
}
|
|
113
|
+
lines.push('Engine:');
|
|
114
|
+
const engineLines = componentConfig.register
|
|
115
|
+
? [
|
|
116
|
+
await customElementsLine(input),
|
|
117
|
+
await jarLine(input),
|
|
118
|
+
...(await localeLines(input, componentConfig)),
|
|
119
|
+
].filter((line) => line !== undefined)
|
|
120
|
+
: ['registrations untouched (register: false)'];
|
|
121
|
+
if (await pathExists(join(input.engineDir, componentConfig.targetPath))) {
|
|
122
|
+
engineLines.push(`remove the stale deployed directory ${componentConfig.targetPath}/`);
|
|
123
|
+
}
|
|
124
|
+
lines.push(...engineLines.map((line) => ` ${line}`));
|
|
125
|
+
lines.push('Test scaffolds named after the old tag are renamed when present.');
|
|
126
|
+
return lines.join('\n');
|
|
127
|
+
}
|
|
@@ -3,6 +3,13 @@ import type { FurnaceConfig } from '../../types/furnace.js';
|
|
|
3
3
|
* Applies a component rename to scaffold-owned filenames only.
|
|
4
4
|
*/
|
|
5
5
|
export declare function renameComponentFileName(fileName: string, oldName: string, newName: string): string;
|
|
6
|
+
/**
|
|
7
|
+
* Rewrites whole-tag mentions of the old name in a component description,
|
|
8
|
+
* so a rename does not carry a description that still names the old tag.
|
|
9
|
+
* Boundary-aware like the source rewrite: `moz-panel` inside
|
|
10
|
+
* `moz-panel-group` is left alone.
|
|
11
|
+
*/
|
|
12
|
+
export declare function renameTagInDescription(description: string, oldName: string, newName: string): string;
|
|
6
13
|
/**
|
|
7
14
|
* Re-keys a custom component config entry and same-config compose references.
|
|
8
15
|
*/
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
// SPDX-License-Identifier: EUPL-1.2
|
|
2
2
|
import { updateFurnaceState } from '../../core/furnace-config.js';
|
|
3
|
+
import { escapeRegex } from '../../utils/regex.js';
|
|
3
4
|
/**
|
|
4
5
|
* Applies a component rename to scaffold-owned filenames only.
|
|
5
6
|
*/
|
|
@@ -11,6 +12,15 @@ export function renameComponentFileName(fileName, oldName, newName) {
|
|
|
11
12
|
}
|
|
12
13
|
return fileName;
|
|
13
14
|
}
|
|
15
|
+
/**
|
|
16
|
+
* Rewrites whole-tag mentions of the old name in a component description,
|
|
17
|
+
* so a rename does not carry a description that still names the old tag.
|
|
18
|
+
* Boundary-aware like the source rewrite: `moz-panel` inside
|
|
19
|
+
* `moz-panel-group` is left alone.
|
|
20
|
+
*/
|
|
21
|
+
export function renameTagInDescription(description, oldName, newName) {
|
|
22
|
+
return description.replace(new RegExp(`(?<![\\w-])${escapeRegex(oldName)}(?![\\w-])`, 'g'), newName);
|
|
23
|
+
}
|
|
14
24
|
/**
|
|
15
25
|
* Re-keys a custom component config entry and same-config compose references.
|
|
16
26
|
*/
|
|
@@ -20,6 +30,7 @@ export function updateConfigForCustomRename(config, oldName, newName) {
|
|
|
20
30
|
return;
|
|
21
31
|
config.custom[newName] = {
|
|
22
32
|
...oldConfig,
|
|
33
|
+
description: renameTagInDescription(oldConfig.description, oldName, newName),
|
|
23
34
|
targetPath: oldConfig.targetPath.replace(new RegExp(`(^|/)${oldName}$`), `$1${newName}`),
|
|
24
35
|
};
|
|
25
36
|
// eslint-disable-next-line @typescript-eslint/no-dynamic-delete -- idiomatic key removal from config record
|
|
@@ -37,7 +48,10 @@ export function updateConfigForOverrideRename(config, oldName, newName) {
|
|
|
37
48
|
const oldConfig = config.overrides[oldName];
|
|
38
49
|
if (!oldConfig)
|
|
39
50
|
return;
|
|
40
|
-
config.overrides[newName] = {
|
|
51
|
+
config.overrides[newName] = {
|
|
52
|
+
...oldConfig,
|
|
53
|
+
description: renameTagInDescription(oldConfig.description, oldName, newName),
|
|
54
|
+
};
|
|
41
55
|
// eslint-disable-next-line @typescript-eslint/no-dynamic-delete -- idiomatic key removal from config record
|
|
42
56
|
delete config.overrides[oldName];
|
|
43
57
|
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Engine registration edits for `furnace rename`: the customElements.js
|
|
3
|
+
* entry (rewritten in place, keeping its marker comments), the
|
|
4
|
+
* toolkit/content/jar.mn widget lines, the deployed `.ftl`, and the locale
|
|
5
|
+
* jar.mn line (re-pointed only when one existed, never for `sharedFtl`).
|
|
6
|
+
*/
|
|
7
|
+
import { type RollbackJournal } from '../../core/furnace-rollback.js';
|
|
8
|
+
import type { CustomComponentConfig } from '../../types/furnace.js';
|
|
9
|
+
/**
|
|
10
|
+
* The project marker (`// <MARKER>:`) a registration line written by the
|
|
11
|
+
* rename carries, resolved exactly as `furnace apply` resolves it. An
|
|
12
|
+
* unreadable fireforge.json degrades to no marker rather than failing the
|
|
13
|
+
* rename.
|
|
14
|
+
*/
|
|
15
|
+
export declare function loadMarkerComment(projectRoot: string): Promise<string | undefined>;
|
|
16
|
+
/** Inputs for {@link updateEngineRegistrations}. */
|
|
17
|
+
export interface UpdateEngineRegistrationsOptions {
|
|
18
|
+
/** Absolute path to the engine checkout. */
|
|
19
|
+
engineDir: string;
|
|
20
|
+
/** Tag name being renamed away from. */
|
|
21
|
+
oldName: string;
|
|
22
|
+
/** Tag name being renamed to. */
|
|
23
|
+
newName: string;
|
|
24
|
+
/** Workspace directory holding the renamed component's files. */
|
|
25
|
+
newDir: string;
|
|
26
|
+
/** Engine-relative directory localized components deploy their `.ftl` into. */
|
|
27
|
+
ftlDir: string;
|
|
28
|
+
/** The renamed component's furnace.json entry (`localized`, `sharedFtl`). */
|
|
29
|
+
componentConfig: CustomComponentConfig;
|
|
30
|
+
/** Project marker for a registration line the rename has to add fresh. */
|
|
31
|
+
markerComment: string | undefined;
|
|
32
|
+
/** Rollback journal every write is recorded in. */
|
|
33
|
+
journal: RollbackJournal;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Re-points the engine-side registrations (customElements.js, jar.mn, and
|
|
37
|
+
* the localized `.ftl` entries) from the old tag name to the new one.
|
|
38
|
+
*
|
|
39
|
+
* @param options - See {@link UpdateEngineRegistrationsOptions}
|
|
40
|
+
*/
|
|
41
|
+
export declare function updateEngineRegistrations(options: UpdateEngineRegistrationsOptions): Promise<void>;
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
// SPDX-License-Identifier: EUPL-1.2
|
|
2
|
+
/**
|
|
3
|
+
* Engine registration edits for `furnace rename`: the customElements.js
|
|
4
|
+
* entry (rewritten in place, keeping its marker comments), the
|
|
5
|
+
* toolkit/content/jar.mn widget lines, the deployed `.ftl`, and the locale
|
|
6
|
+
* jar.mn line (re-pointed only when one existed, never for `sharedFtl`).
|
|
7
|
+
*/
|
|
8
|
+
import { readdir } from 'node:fs/promises';
|
|
9
|
+
import { join } from 'node:path';
|
|
10
|
+
import { loadConfig } from '../../core/config.js';
|
|
11
|
+
import { resolveFtlChromeSubPath, resolveFtlLocaleJarMnPath, } from '../../core/furnace-constants.js';
|
|
12
|
+
import { resolveFurnaceMarkerComment } from '../../core/furnace-marker.js';
|
|
13
|
+
import { addCustomElementRegistration, addJarMnEntries, addLocaleFtlJarMnEntry, removeCustomElementRegistration, removeJarMnEntries, removeLocaleFtlJarMnEntry, renameCustomElementRegistration, } from '../../core/furnace-registration.js';
|
|
14
|
+
import { snapshotFile } from '../../core/furnace-rollback.js';
|
|
15
|
+
import { pathExists, readText, removeFile, writeText } from '../../utils/fs.js';
|
|
16
|
+
/**
|
|
17
|
+
* The project marker (`// <MARKER>:`) a registration line written by the
|
|
18
|
+
* rename carries, resolved exactly as `furnace apply` resolves it. An
|
|
19
|
+
* unreadable fireforge.json degrades to no marker rather than failing the
|
|
20
|
+
* rename.
|
|
21
|
+
*/
|
|
22
|
+
export async function loadMarkerComment(projectRoot) {
|
|
23
|
+
try {
|
|
24
|
+
return resolveFurnaceMarkerComment(await loadConfig(projectRoot));
|
|
25
|
+
}
|
|
26
|
+
catch {
|
|
27
|
+
return undefined;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Re-points the engine-side registrations (customElements.js, jar.mn, and
|
|
32
|
+
* the localized `.ftl` entries) from the old tag name to the new one.
|
|
33
|
+
*
|
|
34
|
+
* @param options - See {@link UpdateEngineRegistrationsOptions}
|
|
35
|
+
*/
|
|
36
|
+
export async function updateEngineRegistrations(options) {
|
|
37
|
+
const { engineDir, oldName, newName, newDir, ftlDir, componentConfig, markerComment, journal } = options;
|
|
38
|
+
const customElementsPath = join(engineDir, 'toolkit/content/customElements.js');
|
|
39
|
+
const jarMnPath = join(engineDir, 'toolkit/content/jar.mn');
|
|
40
|
+
if (await pathExists(customElementsPath)) {
|
|
41
|
+
await snapshotFile(journal, customElementsPath);
|
|
42
|
+
// Rewrite the existing entry in place: it keeps its position, layout and
|
|
43
|
+
// trailing `// <MARKER>:` comments. Only when there is no entry to
|
|
44
|
+
// rewrite is a fresh one added, carrying the project marker like every
|
|
45
|
+
// line `furnace apply` writes.
|
|
46
|
+
if (!(await renameCustomElementRegistration(engineDir, oldName, newName))) {
|
|
47
|
+
await removeCustomElementRegistration(engineDir, oldName);
|
|
48
|
+
await addCustomElementRegistration(engineDir, newName, `chrome://global/content/elements/${newName}.mjs`, markerComment !== undefined ? { markerComment } : {});
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
if (await pathExists(jarMnPath)) {
|
|
52
|
+
await snapshotFile(journal, jarMnPath);
|
|
53
|
+
await removeJarMnEntries(engineDir, oldName);
|
|
54
|
+
const files = (await readdir(newDir, { withFileTypes: true }))
|
|
55
|
+
.filter((e) => e.isFile() && (e.name.endsWith('.mjs') || e.name.endsWith('.css')))
|
|
56
|
+
.map((e) => e.name);
|
|
57
|
+
if (files.length > 0) {
|
|
58
|
+
await addJarMnEntries(engineDir, newName, files);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
// Rename FTL localization files in the engine locale directory
|
|
62
|
+
const ftlDirPath = join(engineDir, ftlDir);
|
|
63
|
+
const oldFtlPath = join(ftlDirPath, `${oldName}.ftl`);
|
|
64
|
+
const newFtlPath = join(ftlDirPath, `${newName}.ftl`);
|
|
65
|
+
if (await pathExists(oldFtlPath)) {
|
|
66
|
+
await snapshotFile(journal, oldFtlPath);
|
|
67
|
+
await snapshotFile(journal, newFtlPath);
|
|
68
|
+
const ftlContent = await readText(oldFtlPath);
|
|
69
|
+
await writeText(newFtlPath, ftlContent);
|
|
70
|
+
await removeFile(oldFtlPath);
|
|
71
|
+
}
|
|
72
|
+
// Re-point the locale jar.mn chrome registration when the component is
|
|
73
|
+
// localized. Renaming the .ftl file on disk alone leaves the locale
|
|
74
|
+
// jar.mn pointing at `locale/.../${oldName}.ftl`, so `furnace validate`
|
|
75
|
+
// passes while the engine still carries a stale registration for the
|
|
76
|
+
// now-missing file. Only an existing line is re-pointed: a `sharedFtl`
|
|
77
|
+
// component has no per-component .ftl, and adding a line for one names a
|
|
78
|
+
// file that does not exist (an unmanaged edit `mach build` trips over).
|
|
79
|
+
if (componentConfig.localized) {
|
|
80
|
+
const chromeSubPath = resolveFtlChromeSubPath(ftlDir);
|
|
81
|
+
const localeJarRel = resolveFtlLocaleJarMnPath(ftlDir);
|
|
82
|
+
if (chromeSubPath !== undefined && localeJarRel !== undefined) {
|
|
83
|
+
const localeJarAbs = join(engineDir, localeJarRel);
|
|
84
|
+
if (await pathExists(localeJarAbs)) {
|
|
85
|
+
await snapshotFile(journal, localeJarAbs);
|
|
86
|
+
const removed = await removeLocaleFtlJarMnEntry(engineDir, localeJarRel, oldName, chromeSubPath);
|
|
87
|
+
if (removed && componentConfig.sharedFtl === undefined) {
|
|
88
|
+
await addLocaleFtlJarMnEntry(engineDir, localeJarRel, newName, chromeSubPath);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
import type { FurnaceRenameOptions } from '../../types/commands/index.js';
|
|
1
2
|
/**
|
|
2
3
|
* Renames a custom or override component atomically: updates directory name,
|
|
3
4
|
* file names, file contents, furnace.json, and engine registrations.
|
|
4
5
|
*/
|
|
5
|
-
export declare function furnaceRenameCommand(projectRoot: string, oldName: string, newName: string): Promise<void>;
|
|
6
|
+
export declare function furnaceRenameCommand(projectRoot: string, oldName: string, newName: string, options?: FurnaceRenameOptions): Promise<void>;
|
|
@@ -3,9 +3,8 @@ import { readdir } from 'node:fs/promises';
|
|
|
3
3
|
import { join } from 'node:path';
|
|
4
4
|
import { getProjectPaths, loadConfig } from '../../core/config.js';
|
|
5
5
|
import { getFurnacePaths, loadFurnaceConfig, writeFurnaceConfig, } from '../../core/furnace-config.js';
|
|
6
|
-
import { isComponentSourceFile,
|
|
7
|
-
import { completeJournalRollback, runFurnaceMutation } from '../../core/furnace-operation.js';
|
|
8
|
-
import { addCustomElementRegistration, addJarMnEntries, addLocaleFtlJarMnEntry, removeCustomElementRegistration, removeJarMnEntries, removeLocaleFtlJarMnEntry, } from '../../core/furnace-registration.js';
|
|
6
|
+
import { isComponentSourceFile, resolveFtlDir, tagNameToClassName, } from '../../core/furnace-constants.js';
|
|
7
|
+
import { completeJournalRollback, runFurnaceMutation, waitLockMutationOptions, } from '../../core/furnace-operation.js';
|
|
9
8
|
import { CUSTOM_ELEMENT_TAG_PATTERN, CUSTOM_ELEMENT_TAG_RULES, } from '../../core/furnace-registration-validate.js';
|
|
10
9
|
import { createRollbackJournal, recordCreatedDir, snapshotDir, snapshotFile, } from '../../core/furnace-rollback.js';
|
|
11
10
|
import { getStoriesDir } from '../../core/furnace-stories.js';
|
|
@@ -16,7 +15,9 @@ import { copyFile, ensureDir, pathExists, readText, removeDir, removeFile, write
|
|
|
16
15
|
import { info, intro, note, outro, warn } from '../../utils/logger.js';
|
|
17
16
|
import { escapeRegex } from '../../utils/regex.js';
|
|
18
17
|
import { updateBrowserChromeTestContent } from './rename-browser-test.js';
|
|
18
|
+
import { renderRenamePlan } from './rename-dry-run.js';
|
|
19
19
|
import { rekeyStateChecksums, renameComponentFileName, updateConfigForCustomRename, updateConfigForOverrideRename, } from './rename-helpers.js';
|
|
20
|
+
import { loadMarkerComment, updateEngineRegistrations } from './rename-registrations.js';
|
|
20
21
|
import { renameXpcshellTestFiles } from './rename-xpcshell.js';
|
|
21
22
|
import { browserTestFileName } from './test-file-name.js';
|
|
22
23
|
/**
|
|
@@ -165,7 +166,7 @@ async function performRenameMutations(args) {
|
|
|
165
166
|
const { projectRoot, oldName, newName } = args;
|
|
166
167
|
const oldClassName = tagNameToClassName(oldName);
|
|
167
168
|
const newClassName = tagNameToClassName(newName);
|
|
168
|
-
|
|
169
|
+
const mutate = async (ctx) => {
|
|
169
170
|
const journal = createRollbackJournal();
|
|
170
171
|
ctx.registerJournal(journal);
|
|
171
172
|
let newDir = args.newDir;
|
|
@@ -245,16 +246,16 @@ async function performRenameMutations(args) {
|
|
|
245
246
|
}
|
|
246
247
|
await writeFurnaceConfig(projectRoot, config);
|
|
247
248
|
// 3. Update engine registrations (custom components only)
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
const isLocalized = config.custom[newName].localized;
|
|
249
|
+
const newConfig = config.custom[newName];
|
|
250
|
+
if (isCustom && newConfig?.register && (await pathExists(args.engineDir))) {
|
|
251
251
|
await updateEngineRegistrations({
|
|
252
252
|
engineDir: args.engineDir,
|
|
253
253
|
oldName,
|
|
254
254
|
newName,
|
|
255
255
|
newDir,
|
|
256
|
-
ftlDir,
|
|
257
|
-
|
|
256
|
+
ftlDir: resolveFtlDir(config.ftlBasePath),
|
|
257
|
+
componentConfig: newConfig,
|
|
258
|
+
markerComment: await loadMarkerComment(projectRoot),
|
|
258
259
|
journal,
|
|
259
260
|
});
|
|
260
261
|
}
|
|
@@ -318,68 +319,15 @@ async function performRenameMutations(args) {
|
|
|
318
319
|
subject: `rename "${oldName}" → "${newName}"`,
|
|
319
320
|
});
|
|
320
321
|
}
|
|
321
|
-
}
|
|
322
|
-
|
|
323
|
-
/**
|
|
324
|
-
* Re-points the engine-side registrations (customElements.js, jar.mn, and
|
|
325
|
-
* the localized `.ftl` entries) from the old tag name to the new one.
|
|
326
|
-
*
|
|
327
|
-
* @param options - See {@link UpdateEngineRegistrationsOptions}
|
|
328
|
-
*/
|
|
329
|
-
async function updateEngineRegistrations(options) {
|
|
330
|
-
const { engineDir, oldName, newName, newDir, ftlDir, isLocalized, journal } = options;
|
|
331
|
-
const customElementsPath = join(engineDir, 'toolkit/content/customElements.js');
|
|
332
|
-
const jarMnPath = join(engineDir, 'toolkit/content/jar.mn');
|
|
333
|
-
if (await pathExists(customElementsPath)) {
|
|
334
|
-
await snapshotFile(journal, customElementsPath);
|
|
335
|
-
await removeCustomElementRegistration(engineDir, oldName);
|
|
336
|
-
await addCustomElementRegistration(engineDir, newName, `chrome://global/content/elements/${newName}.mjs`);
|
|
337
|
-
}
|
|
338
|
-
if (await pathExists(jarMnPath)) {
|
|
339
|
-
await snapshotFile(journal, jarMnPath);
|
|
340
|
-
await removeJarMnEntries(engineDir, oldName);
|
|
341
|
-
const files = (await readdir(newDir, { withFileTypes: true }))
|
|
342
|
-
.filter((e) => e.isFile() && (e.name.endsWith('.mjs') || e.name.endsWith('.css')))
|
|
343
|
-
.map((e) => e.name);
|
|
344
|
-
if (files.length > 0) {
|
|
345
|
-
await addJarMnEntries(engineDir, newName, files);
|
|
346
|
-
}
|
|
347
|
-
}
|
|
348
|
-
// Rename FTL localization files in the engine locale directory
|
|
349
|
-
const ftlDirPath = join(engineDir, ftlDir);
|
|
350
|
-
const oldFtlPath = join(ftlDirPath, `${oldName}.ftl`);
|
|
351
|
-
const newFtlPath = join(ftlDirPath, `${newName}.ftl`);
|
|
352
|
-
if (await pathExists(oldFtlPath)) {
|
|
353
|
-
await snapshotFile(journal, oldFtlPath);
|
|
354
|
-
await snapshotFile(journal, newFtlPath);
|
|
355
|
-
const ftlContent = await readText(oldFtlPath);
|
|
356
|
-
await writeText(newFtlPath, ftlContent);
|
|
357
|
-
await removeFile(oldFtlPath);
|
|
358
|
-
}
|
|
359
|
-
// Re-wire the locale jar.mn chrome registration when the component is
|
|
360
|
-
// localized. `updateEngineRegistrations` renames the .ftl file on disk but
|
|
361
|
-
// leaves the locale jar.mn pointing at `locale/.../${oldName}.ftl`, so
|
|
362
|
-
// `furnace validate` passes while the engine still carries a stale
|
|
363
|
-
// registration for the now-missing file.
|
|
364
|
-
if (isLocalized) {
|
|
365
|
-
const chromeSubPath = resolveFtlChromeSubPath(ftlDir);
|
|
366
|
-
const localeJarRel = resolveFtlLocaleJarMnPath(ftlDir);
|
|
367
|
-
if (chromeSubPath !== undefined && localeJarRel !== undefined) {
|
|
368
|
-
const localeJarAbs = join(engineDir, localeJarRel);
|
|
369
|
-
if (await pathExists(localeJarAbs)) {
|
|
370
|
-
await snapshotFile(journal, localeJarAbs);
|
|
371
|
-
await removeLocaleFtlJarMnEntry(engineDir, localeJarRel, oldName, chromeSubPath);
|
|
372
|
-
await addLocaleFtlJarMnEntry(engineDir, localeJarRel, newName, chromeSubPath);
|
|
373
|
-
}
|
|
374
|
-
}
|
|
375
|
-
}
|
|
322
|
+
};
|
|
323
|
+
await runFurnaceMutation(projectRoot, 'rename-rollback', mutate, waitLockMutationOptions(args.waitLockSeconds));
|
|
376
324
|
}
|
|
377
325
|
/**
|
|
378
326
|
* Renames a custom or override component atomically: updates directory name,
|
|
379
327
|
* file names, file contents, furnace.json, and engine registrations.
|
|
380
328
|
*/
|
|
381
|
-
export async function furnaceRenameCommand(projectRoot, oldName, newName) {
|
|
382
|
-
intro('Furnace Rename');
|
|
329
|
+
export async function furnaceRenameCommand(projectRoot, oldName, newName, options = {}) {
|
|
330
|
+
intro(options.dryRun ? 'Furnace Rename (dry run)' : 'Furnace Rename');
|
|
383
331
|
if (!CUSTOM_ELEMENT_TAG_PATTERN.test(oldName)) {
|
|
384
332
|
throw new InvalidArgumentError(`Invalid source name "${oldName}": ${CUSTOM_ELEMENT_TAG_RULES}`, 'old-name');
|
|
385
333
|
}
|
|
@@ -419,6 +367,19 @@ export async function furnaceRenameCommand(projectRoot, oldName, newName) {
|
|
|
419
367
|
if (await pathExists(newDir)) {
|
|
420
368
|
throw new FurnaceError(`Target directory already exists: components/${componentDirLabel}/${newName}`, newName);
|
|
421
369
|
}
|
|
370
|
+
if (options.dryRun) {
|
|
371
|
+
note(await renderRenamePlan({
|
|
372
|
+
config,
|
|
373
|
+
oldName,
|
|
374
|
+
newName,
|
|
375
|
+
oldDir,
|
|
376
|
+
componentDirLabel,
|
|
377
|
+
engineDir: paths.engine,
|
|
378
|
+
markerComment: await loadMarkerComment(projectRoot),
|
|
379
|
+
}), `${oldName} → ${newName}`);
|
|
380
|
+
outro('Dry run complete (no files modified)');
|
|
381
|
+
return;
|
|
382
|
+
}
|
|
422
383
|
await performRenameMutations({
|
|
423
384
|
projectRoot,
|
|
424
385
|
oldName,
|
|
@@ -427,6 +388,7 @@ export async function furnaceRenameCommand(projectRoot, oldName, newName) {
|
|
|
427
388
|
furnaceConfigPath: furnacePaths.furnaceConfig,
|
|
428
389
|
furnacePaths,
|
|
429
390
|
engineDir: paths.engine,
|
|
391
|
+
waitLockSeconds: options.waitLockSeconds,
|
|
430
392
|
});
|
|
431
393
|
note(`Component renamed: ${oldName} → ${newName}\n\n` +
|
|
432
394
|
`Directory: components/${componentDirLabel}/${newName}/\n\n` +
|
|
@@ -1,9 +1,14 @@
|
|
|
1
|
+
import type { FurnaceLockWaitable } from '../../types/commands/index.js';
|
|
2
|
+
/** Options for `furnace scan`. */
|
|
3
|
+
export interface FurnaceScanOptions extends FurnaceLockWaitable {
|
|
4
|
+
/** Search additional Firefox directories beyond the default widgets path. */
|
|
5
|
+
deep?: boolean;
|
|
6
|
+
/** Persist every untracked component into furnace.json's stock section. */
|
|
7
|
+
track?: boolean;
|
|
8
|
+
}
|
|
1
9
|
/**
|
|
2
10
|
* Runs the furnace scan command to discover MozLitElement components.
|
|
3
11
|
* @param projectRoot - Root directory of the project
|
|
4
12
|
* @param options - Scan options
|
|
5
13
|
*/
|
|
6
|
-
export declare function furnaceScanCommand(projectRoot: string, options?:
|
|
7
|
-
deep?: boolean;
|
|
8
|
-
track?: boolean;
|
|
9
|
-
}): Promise<void>;
|
|
14
|
+
export declare function furnaceScanCommand(projectRoot: string, options?: FurnaceScanOptions): Promise<void>;
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { confirm, multiselect, select } from '@clack/prompts';
|
|
3
3
|
import { stdioIsInteractive } from '../../core/destructive.js';
|
|
4
4
|
import { ensureFurnaceConfig, furnaceConfigExists, getFurnacePaths, loadFurnaceConfig, writeFurnaceConfig, } from '../../core/furnace-config.js';
|
|
5
|
-
import { completeJournalRollback, runFurnaceMutation } from '../../core/furnace-operation.js';
|
|
5
|
+
import { completeJournalRollback, runFurnaceMutation, waitLockMutationOptions, } from '../../core/furnace-operation.js';
|
|
6
6
|
import { assertFurnaceEngineReady } from '../../core/furnace-precondition.js';
|
|
7
7
|
import { createRollbackJournal, snapshotFile } from '../../core/furnace-rollback.js';
|
|
8
8
|
import { DEEP_SCAN_PATHS, scanWidgetsDirectory } from '../../core/furnace-scanner.js';
|
|
@@ -13,8 +13,9 @@ import { furnaceOverrideCommand } from './override.js';
|
|
|
13
13
|
* @param components - Components discovered in the engine scan
|
|
14
14
|
* @param tracked - Existing Furnace tracking map keyed by tag name
|
|
15
15
|
* @param projectRoot - Root directory of the project
|
|
16
|
+
* @param waitLockSeconds - Resolved `--wait-lock` budget for the furnace lock
|
|
16
17
|
*/
|
|
17
|
-
async function promptAddComponents(components, tracked, projectRoot) {
|
|
18
|
+
async function promptAddComponents(components, tracked, projectRoot, waitLockSeconds) {
|
|
18
19
|
const untrackedComponents = components.filter((c) => !tracked.has(c.tagName));
|
|
19
20
|
const shouldAdd = await confirm({ message: 'Add components to furnace.json?' });
|
|
20
21
|
if (isCancel(shouldAdd) || !shouldAdd) {
|
|
@@ -36,7 +37,7 @@ async function promptAddComponents(components, tracked, projectRoot) {
|
|
|
36
37
|
outro('Scan complete');
|
|
37
38
|
return;
|
|
38
39
|
}
|
|
39
|
-
await persistStockComponents(projectRoot, selected);
|
|
40
|
+
await persistStockComponents(projectRoot, selected, waitLockSeconds);
|
|
40
41
|
const addedNames = selected;
|
|
41
42
|
success(`Added ${addedNames.length} component${addedNames.length === 1 ? '' : 's'} to furnace.json`);
|
|
42
43
|
// Offer to immediately override one of the just-added stock components.
|
|
@@ -54,7 +55,7 @@ async function promptAddComponents(components, tracked, projectRoot) {
|
|
|
54
55
|
cancel('Cancelled');
|
|
55
56
|
return;
|
|
56
57
|
}
|
|
57
|
-
await furnaceOverrideCommand(projectRoot, overrideTarget);
|
|
58
|
+
await furnaceOverrideCommand(projectRoot, overrideTarget, waitLockSeconds !== undefined ? { waitLockSeconds } : {});
|
|
58
59
|
}
|
|
59
60
|
/**
|
|
60
61
|
* Persists discovered component tag names into the `stock` section of
|
|
@@ -69,8 +70,8 @@ async function promptAddComponents(components, tracked, projectRoot) {
|
|
|
69
70
|
* auto-created cleans up after itself instead of leaving an unwanted default
|
|
70
71
|
* config behind.
|
|
71
72
|
*/
|
|
72
|
-
async function persistStockComponents(projectRoot, names) {
|
|
73
|
-
|
|
73
|
+
async function persistStockComponents(projectRoot, names, waitLockSeconds) {
|
|
74
|
+
const mutate = async (ctx) => {
|
|
74
75
|
const journal = createRollbackJournal();
|
|
75
76
|
ctx.registerJournal(journal);
|
|
76
77
|
const furnacePaths = getFurnacePaths(projectRoot);
|
|
@@ -96,7 +97,8 @@ async function persistStockComponents(projectRoot, names) {
|
|
|
96
97
|
subject: `furnace.json update during scan`,
|
|
97
98
|
});
|
|
98
99
|
}
|
|
99
|
-
}
|
|
100
|
+
};
|
|
101
|
+
await runFurnaceMutation(projectRoot, 'scan-rollback', mutate, waitLockMutationOptions(waitLockSeconds));
|
|
100
102
|
}
|
|
101
103
|
/**
|
|
102
104
|
* Renders a component's discovered capabilities as a display suffix. Shared
|
|
@@ -172,14 +174,14 @@ export async function furnaceScanCommand(projectRoot, options = {}) {
|
|
|
172
174
|
return;
|
|
173
175
|
}
|
|
174
176
|
const untrackedNames = untrackedComponentList.map((c) => c.tagName);
|
|
175
|
-
await persistStockComponents(projectRoot, untrackedNames);
|
|
177
|
+
await persistStockComponents(projectRoot, untrackedNames, options.waitLockSeconds);
|
|
176
178
|
success(`Tracked ${untrackedNames.length} component${untrackedNames.length === 1 ? '' : 's'} in the stock section of furnace.json`);
|
|
177
179
|
outro('Scan complete');
|
|
178
180
|
return;
|
|
179
181
|
}
|
|
180
182
|
const isInteractive = stdioIsInteractive();
|
|
181
183
|
if (isInteractive && untrackedCount > 0) {
|
|
182
|
-
await promptAddComponents(components, tracked, projectRoot);
|
|
184
|
+
await promptAddComponents(components, tracked, projectRoot, options.waitLockSeconds);
|
|
183
185
|
return;
|
|
184
186
|
}
|
|
185
187
|
if (untrackedCount > 0) {
|
|
@@ -3,7 +3,7 @@ import { readdir } from 'node:fs/promises';
|
|
|
3
3
|
import { join } from 'node:path';
|
|
4
4
|
import { loadConfig } from '../../core/config.js';
|
|
5
5
|
import { applyAllComponents } from '../../core/furnace-apply.js';
|
|
6
|
-
import { logApplyResult } from '../../core/furnace-apply-output.js';
|
|
6
|
+
import { formatSkipBreakdown, logApplyResult } from '../../core/furnace-apply-output.js';
|
|
7
7
|
import { getFurnacePaths, loadFurnaceConfig } from '../../core/furnace-config.js';
|
|
8
8
|
import { reportJsconfigPathsSync } from '../../core/furnace-jsconfig.js';
|
|
9
9
|
import { runFurnaceMutation, waitLockMutationOptions } from '../../core/furnace-operation.js';
|
|
@@ -136,7 +136,8 @@ export async function furnaceSyncCommand(projectRoot, options = {}) {
|
|
|
136
136
|
throw new FurnaceError(`${totalFailures} component${totalFailures === 1 ? '' : 's'} failed to apply cleanly`);
|
|
137
137
|
}
|
|
138
138
|
await reportJsconfigPathsSync(projectRoot, config, false);
|
|
139
|
-
outro(`Sync complete — ${result.applied.length} applied, ${result.skipped.length} skipped`
|
|
139
|
+
outro(`Sync complete — ${result.applied.length} applied, ${result.skipped.length} skipped` +
|
|
140
|
+
formatSkipBreakdown(result.skipped));
|
|
140
141
|
}
|
|
141
142
|
else {
|
|
142
143
|
outro('Dry run complete');
|