@hominis/fireforge 0.35.0 → 0.36.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 +29 -0
- package/README.md +34 -9
- package/dist/bin/fireforge.js +21 -6
- package/dist/src/cli.js +22 -5
- package/dist/src/commands/bootstrap-checks.js +0 -1
- package/dist/src/commands/bootstrap.d.ts +2 -1
- package/dist/src/commands/bootstrap.js +16 -7
- package/dist/src/commands/build.js +4 -3
- package/dist/src/commands/config.js +30 -10
- package/dist/src/commands/discard.js +18 -3
- package/dist/src/commands/doctor/post-rebase-audit.js +0 -1
- package/dist/src/commands/doctor-check-core.js +0 -1
- package/dist/src/commands/doctor-external-toolchains.d.ts +3 -0
- package/dist/src/commands/doctor-external-toolchains.js +54 -0
- package/dist/src/commands/doctor-furnace-jar.js +0 -1
- package/dist/src/commands/doctor-furnace-manifest-sync.js +0 -1
- package/dist/src/commands/doctor-furnace.js +2 -2
- package/dist/src/commands/doctor-working-tree.js +0 -1
- package/dist/src/commands/doctor.js +4 -1
- package/dist/src/commands/download.js +28 -13
- package/dist/src/commands/export-all.js +5 -3
- package/dist/src/commands/export-flow.js +12 -7
- package/dist/src/commands/export-placement-gate.js +0 -1
- package/dist/src/commands/export-placement-policy.js +0 -1
- package/dist/src/commands/export-shared.d.ts +5 -1
- package/dist/src/commands/export-shared.js +18 -6
- package/dist/src/commands/export.js +15 -10
- package/dist/src/commands/furnace/apply.js +22 -6
- package/dist/src/commands/furnace/chrome-doc-remove.js +0 -1
- package/dist/src/commands/furnace/chrome-doc-templates.js +0 -1
- package/dist/src/commands/furnace/chrome-doc-tests.js +0 -1
- package/dist/src/commands/furnace/chrome-doc.js +0 -1
- package/dist/src/commands/furnace/create-browser-test.js +0 -1
- package/dist/src/commands/furnace/create-dry-run.js +0 -1
- package/dist/src/commands/furnace/create-features.js +0 -1
- package/dist/src/commands/furnace/create-mochikit.js +0 -1
- package/dist/src/commands/furnace/create-readback.js +0 -1
- package/dist/src/commands/furnace/create-templates.js +0 -1
- package/dist/src/commands/furnace/create-validation.js +0 -1
- package/dist/src/commands/furnace/create-xpcshell.js +0 -1
- package/dist/src/commands/furnace/create.js +0 -1
- package/dist/src/commands/furnace/deploy.js +7 -83
- package/dist/src/commands/furnace/diff.js +0 -1
- package/dist/src/commands/furnace/index.js +59 -25
- package/dist/src/commands/furnace/init.js +0 -1
- package/dist/src/commands/furnace/list.js +0 -1
- package/dist/src/commands/furnace/override.js +0 -1
- package/dist/src/commands/furnace/preview.js +3 -3
- package/dist/src/commands/furnace/refresh.js +0 -1
- package/dist/src/commands/furnace/remove-state.d.ts +15 -0
- package/dist/src/commands/furnace/remove-state.js +47 -1
- package/dist/src/commands/furnace/remove.js +3 -9
- package/dist/src/commands/furnace/rename-browser-test.js +1 -5
- package/dist/src/commands/furnace/rename-helpers.d.ts +6 -0
- package/dist/src/commands/furnace/rename-helpers.js +30 -1
- package/dist/src/commands/furnace/rename-xpcshell.js +7 -6
- package/dist/src/commands/furnace/rename.js +15 -36
- package/dist/src/commands/furnace/scan.js +0 -1
- package/dist/src/commands/furnace/status.js +0 -1
- package/dist/src/commands/furnace/sync.js +76 -4
- package/dist/src/commands/furnace/validate.js +0 -1
- package/dist/src/commands/furnace/validation-output.js +0 -1
- package/dist/src/commands/import.js +35 -9
- package/dist/src/commands/lint-per-patch.js +19 -7
- package/dist/src/commands/lint.js +13 -3
- package/dist/src/commands/manifest.js +1 -2
- package/dist/src/commands/package.js +2 -1
- package/dist/src/commands/patch/compact.js +1 -1
- package/dist/src/commands/patch/delete.js +1 -1
- package/dist/src/commands/patch/index.js +1 -1
- package/dist/src/commands/patch/lint-ignore.js +21 -6
- package/dist/src/commands/patch/move-files.js +1 -1
- package/dist/src/commands/patch/patch-context.js +0 -1
- package/dist/src/commands/patch/rename.js +4 -4
- package/dist/src/commands/patch/reorder.js +3 -4
- package/dist/src/commands/patch/split-plan.js +2 -1
- package/dist/src/commands/patch/split.js +4 -4
- package/dist/src/commands/patch/staged-dependency.js +1 -1
- package/dist/src/commands/patch/tier.js +18 -5
- package/dist/src/commands/re-export-bulk-scan.js +0 -1
- package/dist/src/commands/re-export-files.js +1 -1
- package/dist/src/commands/re-export-options.js +0 -1
- package/dist/src/commands/re-export-scan.js +0 -1
- package/dist/src/commands/re-export.js +6 -4
- package/dist/src/commands/rebase/abort.js +2 -9
- package/dist/src/commands/rebase/confirm.js +0 -1
- package/dist/src/commands/rebase/conflict-summary.js +0 -1
- package/dist/src/commands/rebase/continue.js +0 -1
- package/dist/src/commands/rebase/index.d.ts +1 -1
- package/dist/src/commands/rebase/index.js +10 -15
- package/dist/src/commands/rebase/patch-loop.js +38 -7
- package/dist/src/commands/rebase/summary.js +2 -3
- package/dist/src/commands/rebase.js +0 -1
- package/dist/src/commands/register.js +1 -1
- package/dist/src/commands/reset.js +16 -9
- package/dist/src/commands/resolve.js +2 -2
- package/dist/src/commands/run.js +4 -4
- package/dist/src/commands/setup-support.js +0 -1
- package/dist/src/commands/setup.js +1 -2
- package/dist/src/commands/source.js +1 -2
- package/dist/src/commands/status-output.js +1 -12
- package/dist/src/commands/status.js +147 -133
- package/dist/src/commands/test-appdir.js +0 -1
- package/dist/src/commands/test-diagnose.js +18 -2
- package/dist/src/commands/test-modes.d.ts +15 -0
- package/dist/src/commands/test-modes.js +61 -0
- package/dist/src/commands/test-register.d.ts +4 -0
- package/dist/src/commands/test-register.js +64 -0
- package/dist/src/commands/test-run.d.ts +23 -7
- package/dist/src/commands/test-run.js +15 -14
- package/dist/src/commands/test.d.ts +0 -4
- package/dist/src/commands/test.js +85 -86
- package/dist/src/commands/token-coverage.js +0 -1
- package/dist/src/commands/token.js +1 -2
- package/dist/src/commands/typecheck.js +1 -1
- package/dist/src/commands/verify.js +3 -9
- package/dist/src/commands/watch.js +5 -1
- package/dist/src/commands/wire.js +1 -1
- package/dist/src/core/ast-utils.js +0 -1
- package/dist/src/core/brand-validation.js +0 -1
- package/dist/src/core/branding.js +0 -1
- package/dist/src/core/browser-wire.js +0 -1
- package/dist/src/core/build-audit-platform.js +0 -1
- package/dist/src/core/build-audit-registration.js +0 -1
- package/dist/src/core/build-audit-resolve.js +0 -1
- package/dist/src/core/build-audit-transforms.js +0 -1
- package/dist/src/core/build-audit.js +0 -1
- package/dist/src/core/build-baseline-types.js +0 -1
- package/dist/src/core/build-baseline.js +0 -1
- package/dist/src/core/build-prepare.js +2 -2
- package/dist/src/core/config-mutate.js +0 -1
- package/dist/src/core/config-paths.d.ts +2 -2
- package/dist/src/core/config-paths.js +6 -1
- package/dist/src/core/config-state.js +0 -1
- package/dist/src/core/config-validate-patch-policy.js +0 -1
- package/dist/src/core/config-validate-test-toolchains.d.ts +8 -0
- package/dist/src/core/config-validate-test-toolchains.js +105 -0
- package/dist/src/core/config-validate.js +3 -1
- package/dist/src/core/config.js +0 -1
- package/dist/src/core/destructive.js +0 -1
- package/dist/src/core/diff-hunks.js +13 -7
- package/dist/src/core/engine-changes.js +0 -1
- package/dist/src/core/engine-session-lock.d.ts +12 -0
- package/dist/src/core/engine-session-lock.js +45 -0
- package/dist/src/core/file-lock.d.ts +8 -0
- package/dist/src/core/file-lock.js +157 -48
- package/dist/src/core/firefox-archive.d.ts +4 -0
- package/dist/src/core/firefox-archive.js +6 -1
- package/dist/src/core/firefox-cache.js +60 -4
- package/dist/src/core/firefox-download.js +0 -1
- package/dist/src/core/firefox-extract.js +75 -16
- package/dist/src/core/firefox-ignorefile.js +0 -1
- package/dist/src/core/firefox.d.ts +12 -0
- package/dist/src/core/firefox.js +64 -2
- package/dist/src/core/furnace-apply-dry-run.js +0 -1
- package/dist/src/core/furnace-apply-ftl.d.ts +7 -3
- package/dist/src/core/furnace-apply-ftl.js +10 -5
- package/dist/src/core/furnace-apply-helpers.js +0 -1
- package/dist/src/core/furnace-apply-output.js +2 -2
- package/dist/src/core/furnace-apply.d.ts +7 -1
- package/dist/src/core/furnace-apply.js +47 -13
- package/dist/src/core/furnace-checksum-utils.js +0 -1
- package/dist/src/core/furnace-config-array-utils.js +0 -1
- package/dist/src/core/furnace-config-custom.js +0 -1
- package/dist/src/core/furnace-config-order.js +0 -1
- package/dist/src/core/furnace-config-tokens.js +0 -1
- package/dist/src/core/furnace-config-validate.js +0 -1
- package/dist/src/core/furnace-config.d.ts +11 -0
- package/dist/src/core/furnace-config.js +37 -1
- package/dist/src/core/furnace-constants.js +0 -1
- package/dist/src/core/furnace-css-fragments.js +0 -1
- package/dist/src/core/furnace-graph-utils.js +0 -1
- package/dist/src/core/furnace-jsconfig.d.ts +2 -3
- package/dist/src/core/furnace-jsconfig.js +25 -18
- package/dist/src/core/furnace-marker.js +0 -1
- package/dist/src/core/furnace-operation.js +0 -1
- package/dist/src/core/furnace-refresh.js +0 -1
- package/dist/src/core/furnace-registration-ast.d.ts +14 -0
- package/dist/src/core/furnace-registration-ast.js +1 -2
- package/dist/src/core/furnace-registration-remove.js +0 -1
- package/dist/src/core/furnace-registration-validate.js +1 -5
- package/dist/src/core/furnace-registration.js +0 -1
- package/dist/src/core/furnace-rollback.js +0 -1
- package/dist/src/core/furnace-scanner.js +0 -1
- package/dist/src/core/furnace-staleness.js +0 -1
- package/dist/src/core/furnace-state-persist.d.ts +72 -0
- package/dist/src/core/furnace-state-persist.js +118 -0
- package/dist/src/core/furnace-step-errors.d.ts +23 -0
- package/dist/src/core/furnace-step-errors.js +25 -0
- package/dist/src/core/furnace-stories.js +0 -1
- package/dist/src/core/furnace-validate-accessibility.js +0 -1
- package/dist/src/core/furnace-validate-checks.js +0 -1
- package/dist/src/core/furnace-validate-compatibility.js +0 -1
- package/dist/src/core/furnace-validate-helpers.js +0 -1
- package/dist/src/core/furnace-validate-registration.js +7 -7
- package/dist/src/core/furnace-validate-structure.d.ts +8 -0
- package/dist/src/core/furnace-validate-structure.js +11 -2
- package/dist/src/core/furnace-validate.js +0 -1
- package/dist/src/core/furnace-version-drift.d.ts +6 -3
- package/dist/src/core/furnace-version-drift.js +6 -4
- package/dist/src/core/git-base.js +0 -1
- package/dist/src/core/git-diff.js +0 -1
- package/dist/src/core/git-file-ops.js +0 -1
- package/dist/src/core/git-status.d.ts +13 -0
- package/dist/src/core/git-status.js +32 -2
- package/dist/src/core/git.d.ts +10 -1
- package/dist/src/core/git.js +63 -6
- package/dist/src/core/license-headers.js +0 -1
- package/dist/src/core/lint-cache.js +0 -1
- package/dist/src/core/lint-projection.js +0 -1
- package/dist/src/core/mach-build-artifacts.js +0 -1
- package/dist/src/core/mach-error-hints.js +0 -1
- package/dist/src/core/mach-mozconfig.js +0 -1
- package/dist/src/core/mach-python.js +0 -1
- package/dist/src/core/mach-resource-shim.js +0 -1
- package/dist/src/core/mach.js +0 -1
- package/dist/src/core/manifest-helpers.js +0 -1
- package/dist/src/core/manifest-register.js +0 -1
- package/dist/src/core/manifest-rules.js +0 -1
- package/dist/src/core/manifest-tokenizers.js +0 -1
- package/dist/src/core/marionette-port.d.ts +8 -0
- package/dist/src/core/marionette-port.js +34 -3
- package/dist/src/core/marionette-preflight.js +0 -1
- package/dist/src/core/markdown-table.js +0 -1
- package/dist/src/core/ownership-table.js +2 -9
- package/dist/src/core/parser-fallback.js +0 -1
- package/dist/src/core/patch-apply-fuzz.d.ts +27 -9
- package/dist/src/core/patch-apply-fuzz.js +71 -34
- package/dist/src/core/patch-apply.d.ts +30 -0
- package/dist/src/core/patch-apply.js +101 -18
- package/dist/src/core/patch-artifact-normalize.d.ts +18 -5
- package/dist/src/core/patch-artifact-normalize.js +19 -15
- package/dist/src/core/patch-export-coverage.js +0 -1
- package/dist/src/core/patch-export-metadata.js +0 -1
- package/dist/src/core/patch-export-update.js +2 -3
- package/dist/src/core/patch-export.d.ts +2 -6
- package/dist/src/core/patch-export.js +24 -48
- package/dist/src/core/patch-files.js +0 -1
- package/dist/src/core/patch-identifier-suggest.js +0 -1
- package/dist/src/core/patch-lint-checkjs.js +0 -1
- package/dist/src/core/patch-lint-chrome-jsdoc.js +0 -1
- package/dist/src/core/patch-lint-cross.js +0 -1
- package/dist/src/core/patch-lint-css.js +0 -1
- package/dist/src/core/patch-lint-diff-tag.js +0 -1
- package/dist/src/core/patch-lint-diff.d.ts +2 -1
- package/dist/src/core/patch-lint-diff.js +17 -32
- package/dist/src/core/patch-lint-imports.js +0 -1
- package/dist/src/core/patch-lint-jsdoc.js +0 -1
- package/dist/src/core/patch-lint-observer.js +0 -1
- package/dist/src/core/patch-lint-ownership.js +0 -1
- package/dist/src/core/patch-lint-reexports.js +0 -1
- package/dist/src/core/patch-lint.d.ts +37 -2
- package/dist/src/core/patch-lint.js +47 -34
- package/dist/src/core/patch-lock.js +0 -1
- package/dist/src/core/patch-manifest-consistency.js +9 -1
- package/dist/src/core/patch-manifest-io.d.ts +16 -0
- package/dist/src/core/patch-manifest-io.js +30 -5
- package/dist/src/core/patch-manifest-query.js +18 -10
- package/dist/src/core/patch-manifest-resolve.js +0 -1
- package/dist/src/core/patch-manifest-validate.js +0 -1
- package/dist/src/core/patch-manifest.d.ts +1 -1
- package/dist/src/core/patch-manifest.js +1 -2
- package/dist/src/core/patch-parse.d.ts +59 -0
- package/dist/src/core/patch-parse.js +209 -92
- package/dist/src/core/patch-policy.js +0 -1
- package/dist/src/core/patch-registration-refs.js +16 -26
- package/dist/src/core/patch-source-metadata.js +0 -1
- package/dist/src/core/patch-transform.d.ts +4 -0
- package/dist/src/core/patch-transform.js +30 -38
- package/dist/src/core/rebase-session.js +0 -1
- package/dist/src/core/register-browser-content.js +0 -1
- package/dist/src/core/register-module.js +0 -1
- package/dist/src/core/register-result.js +0 -1
- package/dist/src/core/register-scaffold.js +0 -1
- package/dist/src/core/register-shared-css.js +0 -1
- package/dist/src/core/register-test-manifest.js +0 -1
- package/dist/src/core/register-xpcshell-test.js +0 -1
- package/dist/src/core/shared-ftl.js +0 -1
- package/dist/src/core/signal-critical.js +0 -1
- package/dist/src/core/smoke-patterns.js +0 -1
- package/dist/src/core/state-file.js +0 -1
- package/dist/src/core/status-classify.d.ts +16 -0
- package/dist/src/core/status-classify.js +24 -16
- package/dist/src/core/test-harness-crash.d.ts +64 -7
- package/dist/src/core/test-harness-crash.js +196 -15
- package/dist/src/core/test-harness-output.js +0 -1
- package/dist/src/core/test-path-scope.d.ts +21 -13
- package/dist/src/core/test-path-scope.js +43 -28
- package/dist/src/core/test-stale-check.js +0 -1
- package/dist/src/core/test-stale-symlink.js +0 -1
- package/dist/src/core/test-xpcshell-retry.js +0 -1
- package/dist/src/core/token-coverage.js +0 -1
- package/dist/src/core/token-dark-mode.js +0 -1
- package/dist/src/core/token-docs.js +0 -1
- package/dist/src/core/token-manager.js +0 -1
- package/dist/src/core/token-scaffold.js +0 -1
- package/dist/src/core/token-variant.js +0 -1
- package/dist/src/core/toolchain-preflight.d.ts +31 -10
- package/dist/src/core/toolchain-preflight.js +97 -36
- package/dist/src/core/typecheck-shim.js +13 -1
- package/dist/src/core/typecheck.js +0 -1
- package/dist/src/core/wire-destroy.js +0 -1
- package/dist/src/core/wire-dom-fragment.js +0 -1
- package/dist/src/core/wire-init.js +0 -1
- package/dist/src/core/wire-subscript.js +0 -1
- package/dist/src/core/wire-targets.js +0 -1
- package/dist/src/core/wire-utils.js +0 -1
- package/dist/src/core/xpcshell-appdir.js +1 -4
- package/dist/src/errors/base.d.ts +29 -0
- package/dist/src/errors/base.js +35 -1
- package/dist/src/errors/build.js +0 -1
- package/dist/src/errors/codes.d.ts +6 -0
- package/dist/src/errors/codes.js +6 -1
- package/dist/src/errors/config.js +0 -1
- package/dist/src/errors/download.js +0 -1
- package/dist/src/errors/furnace.d.ts +11 -1
- package/dist/src/errors/furnace.js +6 -5
- package/dist/src/errors/git.js +0 -1
- package/dist/src/errors/patch.d.ts +17 -0
- package/dist/src/errors/patch.js +29 -1
- package/dist/src/errors/rebase.js +0 -1
- package/dist/src/errors/run.js +1 -1
- package/dist/src/index.js +0 -1
- package/dist/src/types/cli.js +0 -1
- package/dist/src/types/commands/index.js +0 -1
- package/dist/src/types/commands/options.d.ts +13 -5
- package/dist/src/types/commands/options.js +0 -1
- package/dist/src/types/commands/patches.d.ts +8 -0
- package/dist/src/types/commands/patches.js +0 -1
- package/dist/src/types/commands/project.d.ts +11 -2
- package/dist/src/types/commands/project.js +0 -1
- package/dist/src/types/config.d.ts +32 -0
- package/dist/src/types/config.js +0 -1
- package/dist/src/types/furnace.d.ts +10 -0
- package/dist/src/types/furnace.js +0 -1
- package/dist/src/types/index.js +0 -1
- package/dist/src/types/typecheck.js +0 -1
- package/dist/src/utils/elapsed.js +0 -1
- package/dist/src/utils/errors.js +0 -1
- package/dist/src/utils/fs.js +37 -5
- package/dist/src/utils/logger.d.ts +7 -0
- package/dist/src/utils/logger.js +85 -3
- package/dist/src/utils/options.d.ts +15 -0
- package/dist/src/utils/options.js +25 -1
- package/dist/src/utils/package-root.js +11 -4
- package/dist/src/utils/parse.js +0 -1
- package/dist/src/utils/paths.js +0 -1
- package/dist/src/utils/platform.js +0 -1
- package/dist/src/utils/process.d.ts +33 -4
- package/dist/src/utils/process.js +183 -28
- package/dist/src/utils/regex.d.ts +13 -3
- package/dist/src/utils/regex.js +53 -4
- package/dist/src/utils/validation.d.ts +0 -12
- package/dist/src/utils/validation.js +13 -26
- package/package.json +8 -7
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
// SPDX-License-Identifier: EUPL-1.2
|
|
2
|
-
import { Option } from 'commander';
|
|
2
|
+
import { Command, Option } from 'commander';
|
|
3
|
+
import { withEngineSessionLock } from '../../core/engine-session-lock.js';
|
|
3
4
|
import { pickDefined } from '../../utils/options.js';
|
|
4
5
|
import { furnaceApplyCommand } from './apply.js';
|
|
5
6
|
import { furnaceChromeDocCreateCommand } from './chrome-doc.js';
|
|
@@ -18,20 +19,12 @@ import { furnaceScanCommand } from './scan.js';
|
|
|
18
19
|
import { furnaceStatusCommand } from './status.js';
|
|
19
20
|
import { furnaceSyncCommand } from './sync.js';
|
|
20
21
|
import { furnaceValidateCommand } from './validate.js';
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
*/
|
|
27
|
-
function registerFurnaceInfoCommands(furnace, context) {
|
|
22
|
+
async function runEngineLockedFurnaceCommand(context, command, operation) {
|
|
23
|
+
const projectRoot = context.getProjectRoot();
|
|
24
|
+
await withEngineSessionLock(projectRoot, command, () => operation(projectRoot));
|
|
25
|
+
}
|
|
26
|
+
function registerFurnaceApplyCommand(furnace, context) {
|
|
28
27
|
const { getProjectRoot, withErrorHandling } = context;
|
|
29
|
-
furnace
|
|
30
|
-
.command('status [name]')
|
|
31
|
-
.description('Show component status and registration details')
|
|
32
|
-
.action(withErrorHandling(async (name) => {
|
|
33
|
-
await furnaceStatusCommand(getProjectRoot(), name);
|
|
34
|
-
}));
|
|
35
28
|
furnace
|
|
36
29
|
.command('apply [name]')
|
|
37
30
|
.description('Apply components to the engine (optionally a single component)')
|
|
@@ -39,8 +32,17 @@ function registerFurnaceInfoCommands(furnace, context) {
|
|
|
39
32
|
.option('--force', 'Proceed despite baseVersion drift (stale overrides)')
|
|
40
33
|
.option('-w, --watch', 'Watch component directories and re-apply on changes')
|
|
41
34
|
.action(withErrorHandling(async (name, options) => {
|
|
42
|
-
|
|
35
|
+
const parsed = pickDefined(options ?? {});
|
|
36
|
+
const run = (projectRoot) => furnaceApplyCommand(projectRoot, name, parsed);
|
|
37
|
+
if (parsed.dryRun === true) {
|
|
38
|
+
await run(getProjectRoot());
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
await runEngineLockedFurnaceCommand(context, 'furnace apply', run);
|
|
43
42
|
}));
|
|
43
|
+
}
|
|
44
|
+
function registerFurnaceDeployCommand(furnace, context) {
|
|
45
|
+
const { getProjectRoot, withErrorHandling } = context;
|
|
44
46
|
furnace
|
|
45
47
|
.command('deploy [name]')
|
|
46
48
|
.description('Apply components and validate in one step')
|
|
@@ -48,8 +50,48 @@ function registerFurnaceInfoCommands(furnace, context) {
|
|
|
48
50
|
.option('--force', 'Proceed despite baseVersion drift (stale overrides)')
|
|
49
51
|
.option('--skip-validate', 'Skip the validation step (apply only)')
|
|
50
52
|
.action(withErrorHandling(async (name, options) => {
|
|
51
|
-
|
|
53
|
+
const parsed = pickDefined(options ?? {});
|
|
54
|
+
const run = (projectRoot) => furnaceDeployCommand(projectRoot, name, parsed);
|
|
55
|
+
if (parsed.dryRun === true) {
|
|
56
|
+
await run(getProjectRoot());
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
await runEngineLockedFurnaceCommand(context, 'furnace deploy', run);
|
|
60
|
+
}));
|
|
61
|
+
}
|
|
62
|
+
function registerFurnaceSyncCommand(furnace, context) {
|
|
63
|
+
const { getProjectRoot, withErrorHandling } = context;
|
|
64
|
+
furnace
|
|
65
|
+
.command('sync')
|
|
66
|
+
.description('Refresh drifted overrides and re-apply all components (recommended after fireforge download)')
|
|
67
|
+
.option('--dry-run', 'Show what would change without modifying files (reads may overlap concurrent mutations)')
|
|
68
|
+
.addOption(new Option('-s, --strategy <strategy>', 'Auto-resolve merge conflicts (ours = keep local, theirs = accept upstream)').choices(['ours', 'theirs']))
|
|
69
|
+
.action(withErrorHandling(async (options) => {
|
|
70
|
+
const parsed = pickDefined(options);
|
|
71
|
+
const run = (projectRoot) => furnaceSyncCommand(projectRoot, parsed);
|
|
72
|
+
if (parsed.dryRun === true) {
|
|
73
|
+
await run(getProjectRoot());
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
await runEngineLockedFurnaceCommand(context, 'furnace sync', run);
|
|
52
77
|
}));
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Registers Furnace commands for querying component state: status, scan,
|
|
81
|
+
* and action commands like apply, deploy, and create.
|
|
82
|
+
* @param furnace - Parent Furnace command
|
|
83
|
+
* @param context - Shared CLI registration context
|
|
84
|
+
*/
|
|
85
|
+
function registerFurnaceInfoCommands(furnace, context) {
|
|
86
|
+
const { getProjectRoot, withErrorHandling } = context;
|
|
87
|
+
furnace
|
|
88
|
+
.command('status [name]')
|
|
89
|
+
.description('Show component status and registration details')
|
|
90
|
+
.action(withErrorHandling(async (name) => {
|
|
91
|
+
await furnaceStatusCommand(getProjectRoot(), name);
|
|
92
|
+
}));
|
|
93
|
+
registerFurnaceApplyCommand(furnace, context);
|
|
94
|
+
registerFurnaceDeployCommand(furnace, context);
|
|
53
95
|
furnace
|
|
54
96
|
.command('scan')
|
|
55
97
|
.description('Scan engine for available components. Report-only by default: persist the discovered ' +
|
|
@@ -188,14 +230,7 @@ function registerFurnaceModifyCommands(furnace, context) {
|
|
|
188
230
|
.action(withErrorHandling(async (oldName, newName) => {
|
|
189
231
|
await furnaceRenameCommand(getProjectRoot(), oldName, newName);
|
|
190
232
|
}));
|
|
191
|
-
furnace
|
|
192
|
-
.command('sync')
|
|
193
|
-
.description('Refresh drifted overrides and re-apply all components (recommended after fireforge download)')
|
|
194
|
-
.option('--dry-run', 'Show what would change without modifying files (reads may overlap concurrent mutations)')
|
|
195
|
-
.addOption(new Option('-s, --strategy <strategy>', 'Auto-resolve merge conflicts (ours = keep local, theirs = accept upstream)').choices(['ours', 'theirs']))
|
|
196
|
-
.action(withErrorHandling(async (options) => {
|
|
197
|
-
await furnaceSyncCommand(getProjectRoot(), pickDefined(options));
|
|
198
|
-
}));
|
|
233
|
+
registerFurnaceSyncCommand(furnace, context);
|
|
199
234
|
}
|
|
200
235
|
/** Registers the furnace command on the CLI program. */
|
|
201
236
|
export function registerFurnace(program, context) {
|
|
@@ -209,4 +244,3 @@ export function registerFurnace(program, context) {
|
|
|
209
244
|
registerFurnaceInfoCommands(furnace, context);
|
|
210
245
|
registerFurnaceModifyCommands(furnace, context);
|
|
211
246
|
}
|
|
212
|
-
//# sourceMappingURL=index.js.map
|
|
@@ -5,6 +5,7 @@ import { applyAllComponents } from '../../core/furnace-apply.js';
|
|
|
5
5
|
import { furnaceConfigExists, loadFurnaceConfig, updateFurnaceState, } from '../../core/furnace-config.js';
|
|
6
6
|
import { runFurnaceMutation } from '../../core/furnace-operation.js';
|
|
7
7
|
import { restoreRollbackJournal } from '../../core/furnace-rollback.js';
|
|
8
|
+
import { countEntriesWithBlockingStepErrors } from '../../core/furnace-step-errors.js';
|
|
8
9
|
import { cleanStories, syncStories } from '../../core/furnace-stories.js';
|
|
9
10
|
import { hasBuildArtifacts, runMach, runMachCapture } from '../../core/mach.js';
|
|
10
11
|
import { FurnaceError } from '../../errors/furnace.js';
|
|
@@ -68,7 +69,7 @@ function reportPreviewStagingFailures(stageResult) {
|
|
|
68
69
|
}
|
|
69
70
|
}
|
|
70
71
|
}
|
|
71
|
-
const appliedWithStepErrorsCount = stageResult.applied
|
|
72
|
+
const appliedWithStepErrorsCount = countEntriesWithBlockingStepErrors(stageResult.applied);
|
|
72
73
|
const totalFailures = stageResult.errors.length + appliedWithStepErrorsCount;
|
|
73
74
|
throw new FurnaceError(`${totalFailures} component${totalFailures === 1 ? '' : 's'} failed to stage for preview`);
|
|
74
75
|
}
|
|
@@ -273,7 +274,7 @@ export async function furnacePreviewCommand(projectRoot, options = {}) {
|
|
|
273
274
|
if (previewJournal) {
|
|
274
275
|
ctx.registerJournal(previewJournal);
|
|
275
276
|
}
|
|
276
|
-
const appliedWithStepErrorsCount = stageResult.applied
|
|
277
|
+
const appliedWithStepErrorsCount = countEntriesWithBlockingStepErrors(stageResult.applied);
|
|
277
278
|
const totalFailures = stageResult.errors.length + appliedWithStepErrorsCount;
|
|
278
279
|
if (totalFailures > 0) {
|
|
279
280
|
stageSpinner.error('Failed to stage components');
|
|
@@ -362,4 +363,3 @@ export async function furnacePreviewCommand(projectRoot, options = {}) {
|
|
|
362
363
|
}
|
|
363
364
|
outro('Storybook stopped');
|
|
364
365
|
}
|
|
365
|
-
//# sourceMappingURL=preview.js.map
|
|
@@ -1,5 +1,20 @@
|
|
|
1
|
+
import { type RollbackJournal } from '../../core/furnace-rollback.js';
|
|
1
2
|
import type { FurnaceState } from '../../types/furnace.js';
|
|
2
3
|
/**
|
|
3
4
|
* Removes every checksum entry owned by the removed component.
|
|
4
5
|
*/
|
|
5
6
|
export declare function dropChecksumsByPrefix(state: FurnaceState, prefix: string): FurnaceState;
|
|
7
|
+
/**
|
|
8
|
+
* Deletes the files a custom component deployed into its engine targetPath.
|
|
9
|
+
*
|
|
10
|
+
* Per-file, never a recursive `removeDir` of the whole directory: nothing
|
|
11
|
+
* stops two components from sharing a targetPath (or a hand-edited config
|
|
12
|
+
* from pointing at an upstream-shared directory), and the recursive delete
|
|
13
|
+
* permanently destroyed the co-located files on success — the rollback
|
|
14
|
+
* journal only protects the failure path. Deployed files come from the
|
|
15
|
+
* component's state checksums, falling back to the conventional
|
|
16
|
+
* `<name>.{mjs,css,ftl}` set when state carries no record (cleared by a
|
|
17
|
+
* --force download or rebase). The directory itself is removed only when
|
|
18
|
+
* nothing else lives in it afterwards.
|
|
19
|
+
*/
|
|
20
|
+
export declare function removeDeployedCustomFiles(projectRoot: string, engineDir: string, name: string, targetPath: string, journal: RollbackJournal): Promise<void>;
|
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
// SPDX-License-Identifier: EUPL-1.2
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
import { loadFurnaceState } from '../../core/furnace-config.js';
|
|
4
|
+
import { snapshotFile } from '../../core/furnace-rollback.js';
|
|
5
|
+
import { pathExists, removeDir, removeFile } from '../../utils/fs.js';
|
|
6
|
+
import { info } from '../../utils/logger.js';
|
|
1
7
|
/**
|
|
2
8
|
* Removes every checksum entry owned by the removed component.
|
|
3
9
|
*/
|
|
@@ -11,4 +17,44 @@ export function dropChecksumsByPrefix(state, prefix) {
|
|
|
11
17
|
}
|
|
12
18
|
return result;
|
|
13
19
|
}
|
|
14
|
-
|
|
20
|
+
/**
|
|
21
|
+
* Deletes the files a custom component deployed into its engine targetPath.
|
|
22
|
+
*
|
|
23
|
+
* Per-file, never a recursive `removeDir` of the whole directory: nothing
|
|
24
|
+
* stops two components from sharing a targetPath (or a hand-edited config
|
|
25
|
+
* from pointing at an upstream-shared directory), and the recursive delete
|
|
26
|
+
* permanently destroyed the co-located files on success — the rollback
|
|
27
|
+
* journal only protects the failure path. Deployed files come from the
|
|
28
|
+
* component's state checksums, falling back to the conventional
|
|
29
|
+
* `<name>.{mjs,css,ftl}` set when state carries no record (cleared by a
|
|
30
|
+
* --force download or rebase). The directory itself is removed only when
|
|
31
|
+
* nothing else lives in it afterwards.
|
|
32
|
+
*/
|
|
33
|
+
export async function removeDeployedCustomFiles(projectRoot, engineDir, name, targetPath, journal) {
|
|
34
|
+
const engineTargetDir = join(engineDir, targetPath);
|
|
35
|
+
if (!(await pathExists(engineTargetDir)))
|
|
36
|
+
return;
|
|
37
|
+
const state = await loadFurnaceState(projectRoot);
|
|
38
|
+
const checksumPrefix = `custom/${name}/`;
|
|
39
|
+
const recordedFiles = Object.keys(state.appliedChecksums ?? {})
|
|
40
|
+
.filter((key) => key.startsWith(checksumPrefix))
|
|
41
|
+
.map((key) => key.slice(checksumPrefix.length));
|
|
42
|
+
const deployedFiles = recordedFiles.length > 0 ? recordedFiles : [`${name}.mjs`, `${name}.css`, `${name}.ftl`];
|
|
43
|
+
let deletedCount = 0;
|
|
44
|
+
for (const file of deployedFiles) {
|
|
45
|
+
const target = join(engineTargetDir, file);
|
|
46
|
+
if (await pathExists(target)) {
|
|
47
|
+
await snapshotFile(journal, target);
|
|
48
|
+
await removeFile(target);
|
|
49
|
+
deletedCount++;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
if (deletedCount > 0) {
|
|
53
|
+
info(`Deleted ${deletedCount} deployed file(s) from engine/${targetPath}/`);
|
|
54
|
+
}
|
|
55
|
+
const { readdir } = await import('node:fs/promises');
|
|
56
|
+
if ((await readdir(engineTargetDir)).length === 0) {
|
|
57
|
+
await removeDir(engineTargetDir);
|
|
58
|
+
info(`Removed now-empty engine/${targetPath}/`);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
@@ -16,7 +16,7 @@ import { FurnaceError } from '../../errors/furnace.js';
|
|
|
16
16
|
import { toError } from '../../utils/errors.js';
|
|
17
17
|
import { pathExists, readText, removeDir, removeFile, writeText } from '../../utils/fs.js';
|
|
18
18
|
import { cancel, info, intro, isCancel, outro, warn } from '../../utils/logger.js';
|
|
19
|
-
import { dropChecksumsByPrefix } from './remove-state.js';
|
|
19
|
+
import { dropChecksumsByPrefix, removeDeployedCustomFiles } from './remove-state.js';
|
|
20
20
|
/**
|
|
21
21
|
* Removes an entire TOML section (header + body lines) for a given test file.
|
|
22
22
|
* Matches from `["filename"]` up to the next section header `[` or end-of-file,
|
|
@@ -457,14 +457,9 @@ export async function furnaceRemoveCommand(projectRoot, name, options = {}) {
|
|
|
457
457
|
await removeDir(dir);
|
|
458
458
|
info(`Deleted components/custom/${name}/`);
|
|
459
459
|
}
|
|
460
|
-
// Clean up deployed files in engine
|
|
460
|
+
// Clean up deployed files in engine (per-file — see helper doc).
|
|
461
461
|
if (customConfig?.targetPath) {
|
|
462
|
-
|
|
463
|
-
if (await pathExists(engineDir)) {
|
|
464
|
-
await snapshotDir(journal, engineDir);
|
|
465
|
-
await removeDir(engineDir);
|
|
466
|
-
info(`Deleted deployed files from engine/${customConfig.targetPath}/`);
|
|
467
|
-
}
|
|
462
|
+
await removeDeployedCustomFiles(projectRoot, paths.engine, name, customConfig.targetPath, journal);
|
|
468
463
|
}
|
|
469
464
|
// Localized components deploy a .ftl outside targetPath into the
|
|
470
465
|
// shared Fluent tree; apply writes it, so remove must delete it too
|
|
@@ -530,4 +525,3 @@ export async function furnaceRemoveCommand(projectRoot, name, options = {}) {
|
|
|
530
525
|
info(`Removed "${name}" from furnace.json`);
|
|
531
526
|
outro('Component removed');
|
|
532
527
|
}
|
|
533
|
-
//# sourceMappingURL=remove.js.map
|
|
@@ -1,9 +1,6 @@
|
|
|
1
1
|
// SPDX-License-Identifier: EUPL-1.2
|
|
2
2
|
import { tagNameToClassName } from '../../core/furnace-constants.js';
|
|
3
|
-
|
|
4
|
-
function escapeRegex(input) {
|
|
5
|
-
return input.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
6
|
-
}
|
|
3
|
+
import { escapeRegex } from '../../utils/regex.js';
|
|
7
4
|
function deriveTestStem(componentName, binaryName) {
|
|
8
5
|
const strippedName = componentName.startsWith('moz-') ? componentName.slice(4) : componentName;
|
|
9
6
|
const withoutBinaryPrefix = strippedName.startsWith(binaryName + '-')
|
|
@@ -25,4 +22,3 @@ export function updateBrowserChromeTestContent(content, oldName, newName, binary
|
|
|
25
22
|
.replace(new RegExp(escapeRegex(oldUnderscored), 'g'), newUnderscored)
|
|
26
23
|
.replace(new RegExp(escapeRegex(oldTestStem), 'g'), newTestStem);
|
|
27
24
|
}
|
|
28
|
-
//# sourceMappingURL=rename-browser-test.js.map
|
|
@@ -11,3 +11,9 @@ export declare function updateConfigForCustomRename(config: FurnaceConfig, oldNa
|
|
|
11
11
|
* Re-keys an override component config entry.
|
|
12
12
|
*/
|
|
13
13
|
export declare function updateConfigForOverrideRename(config: FurnaceConfig, oldName: string, newName: string): void;
|
|
14
|
+
/**
|
|
15
|
+
* Re-keys checksum entries in furnace-state.json from the old component name
|
|
16
|
+
* to the new name so that `doctor` doesn't flag stale entries and the next
|
|
17
|
+
* `apply` can correctly detect whether the renamed component has changed.
|
|
18
|
+
*/
|
|
19
|
+
export declare function rekeyStateChecksums(projectRoot: string, componentType: string, oldName: string, newName: string): Promise<void>;
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
// SPDX-License-Identifier: EUPL-1.2
|
|
2
|
+
import { updateFurnaceState } from '../../core/furnace-config.js';
|
|
1
3
|
/**
|
|
2
4
|
* Applies a component rename to scaffold-owned filenames only.
|
|
3
5
|
*/
|
|
@@ -39,4 +41,31 @@ export function updateConfigForOverrideRename(config, oldName, newName) {
|
|
|
39
41
|
// eslint-disable-next-line @typescript-eslint/no-dynamic-delete -- idiomatic key removal from config record
|
|
40
42
|
delete config.overrides[oldName];
|
|
41
43
|
}
|
|
42
|
-
|
|
44
|
+
/**
|
|
45
|
+
* Re-keys checksum entries in furnace-state.json from the old component name
|
|
46
|
+
* to the new name so that `doctor` doesn't flag stale entries and the next
|
|
47
|
+
* `apply` can correctly detect whether the renamed component has changed.
|
|
48
|
+
*/
|
|
49
|
+
export async function rekeyStateChecksums(projectRoot, componentType, oldName, newName) {
|
|
50
|
+
const oldPrefix = `${componentType}/${oldName}/`;
|
|
51
|
+
const newPrefix = `${componentType}/${newName}/`;
|
|
52
|
+
await updateFurnaceState(projectRoot, (state) => {
|
|
53
|
+
const result = { ...state };
|
|
54
|
+
for (const field of ['appliedChecksums', 'engineChecksums']) {
|
|
55
|
+
const checksums = state[field];
|
|
56
|
+
if (!checksums)
|
|
57
|
+
continue;
|
|
58
|
+
const updated = {};
|
|
59
|
+
for (const [key, value] of Object.entries(checksums)) {
|
|
60
|
+
if (key.startsWith(oldPrefix)) {
|
|
61
|
+
updated[newPrefix + key.slice(oldPrefix.length)] = value;
|
|
62
|
+
}
|
|
63
|
+
else {
|
|
64
|
+
updated[key] = value;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
result[field] = updated;
|
|
68
|
+
}
|
|
69
|
+
return result;
|
|
70
|
+
});
|
|
71
|
+
}
|
|
@@ -19,14 +19,11 @@ import { readdir } from 'node:fs/promises';
|
|
|
19
19
|
import { join } from 'node:path';
|
|
20
20
|
import { loadConfig } from '../../core/config.js';
|
|
21
21
|
import { xpcshellTestParentDir } from '../../core/furnace-constants.js';
|
|
22
|
-
import { snapshotFile } from '../../core/furnace-rollback.js';
|
|
22
|
+
import { recordCreatedDir, snapshotFile, } from '../../core/furnace-rollback.js';
|
|
23
23
|
import { toError } from '../../utils/errors.js';
|
|
24
24
|
import { ensureDir, pathExists, readText, removeDir, removeFile, writeText, } from '../../utils/fs.js';
|
|
25
25
|
import { info, warn } from '../../utils/logger.js';
|
|
26
|
-
|
|
27
|
-
function escapeRegex(input) {
|
|
28
|
-
return input.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
29
|
-
}
|
|
26
|
+
import { escapeRegex } from '../../utils/regex.js';
|
|
30
27
|
/**
|
|
31
28
|
* Renames an xpcshell test scaffold in place. Moves the directory,
|
|
32
29
|
* rewrites the test filename, updates the `[test_name]` section header
|
|
@@ -64,6 +61,10 @@ export async function renameXpcshellTestFiles(engineDir, projectRoot, oldName, n
|
|
|
64
61
|
const oldTestFileName = `test_${oldUnderscored}_packaged.js`;
|
|
65
62
|
const newTestFileName = `test_${newUnderscored}_packaged.js`;
|
|
66
63
|
try {
|
|
64
|
+
// Journal the new scaffold dir + files so rollback (including the
|
|
65
|
+
// SIGINT path) removes them; only the old-name files were journaled
|
|
66
|
+
// before, so a failed rename stranded the new-name scaffold.
|
|
67
|
+
recordCreatedDir(journal, newScaffoldDir);
|
|
67
68
|
await ensureDir(newScaffoldDir);
|
|
68
69
|
const entries = await readdir(oldScaffoldDir, { withFileTypes: true });
|
|
69
70
|
for (const entry of entries) {
|
|
@@ -73,6 +74,7 @@ export async function renameXpcshellTestFiles(engineDir, projectRoot, oldName, n
|
|
|
73
74
|
const renamedFileName = entry.name === oldTestFileName ? newTestFileName : entry.name;
|
|
74
75
|
const newFilePath = join(newScaffoldDir, renamedFileName);
|
|
75
76
|
await snapshotFile(journal, oldFilePath);
|
|
77
|
+
await snapshotFile(journal, newFilePath);
|
|
76
78
|
const body = await readText(oldFilePath);
|
|
77
79
|
let updated = body;
|
|
78
80
|
if (entry.name === 'xpcshell.toml') {
|
|
@@ -94,4 +96,3 @@ export async function renameXpcshellTestFiles(engineDir, projectRoot, oldName, n
|
|
|
94
96
|
warn(`Could not rename xpcshell scaffold — ${toError(error).message}. Rename the scaffold files manually if needed.`);
|
|
95
97
|
}
|
|
96
98
|
}
|
|
97
|
-
//# sourceMappingURL=rename-xpcshell.js.map
|
|
@@ -2,25 +2,22 @@
|
|
|
2
2
|
import { readdir } from 'node:fs/promises';
|
|
3
3
|
import { join } from 'node:path';
|
|
4
4
|
import { getProjectPaths, loadConfig } from '../../core/config.js';
|
|
5
|
-
import { getFurnacePaths, loadFurnaceConfig,
|
|
5
|
+
import { getFurnacePaths, loadFurnaceConfig, writeFurnaceConfig, } from '../../core/furnace-config.js';
|
|
6
6
|
import { isComponentSourceFile, resolveFtlChromeSubPath, resolveFtlDir, resolveFtlLocaleJarMnPath, tagNameToClassName, } from '../../core/furnace-constants.js';
|
|
7
7
|
import { recordFurnaceRollbackFailure, runFurnaceMutation } from '../../core/furnace-operation.js';
|
|
8
8
|
import { addCustomElementRegistration, addJarMnEntries, addLocaleFtlJarMnEntry, removeCustomElementRegistration, removeJarMnEntries, removeLocaleFtlJarMnEntry, } from '../../core/furnace-registration.js';
|
|
9
9
|
import { CUSTOM_ELEMENT_TAG_PATTERN, CUSTOM_ELEMENT_TAG_RULES, } from '../../core/furnace-registration-validate.js';
|
|
10
|
-
import { createRollbackJournal, restoreRollbackJournalOrThrow, snapshotDir, snapshotFile, } from '../../core/furnace-rollback.js';
|
|
10
|
+
import { createRollbackJournal, recordCreatedDir, restoreRollbackJournalOrThrow, snapshotDir, snapshotFile, } from '../../core/furnace-rollback.js';
|
|
11
11
|
import { getStoriesDir } from '../../core/furnace-stories.js';
|
|
12
12
|
import { InvalidArgumentError } from '../../errors/base.js';
|
|
13
13
|
import { FurnaceError } from '../../errors/furnace.js';
|
|
14
14
|
import { toError } from '../../utils/errors.js';
|
|
15
15
|
import { copyFile, ensureDir, pathExists, readText, removeDir, removeFile, writeText, } from '../../utils/fs.js';
|
|
16
16
|
import { info, intro, note, outro, warn } from '../../utils/logger.js';
|
|
17
|
+
import { escapeRegex } from '../../utils/regex.js';
|
|
17
18
|
import { updateBrowserChromeTestContent } from './rename-browser-test.js';
|
|
18
|
-
import { renameComponentFileName, updateConfigForCustomRename, updateConfigForOverrideRename, } from './rename-helpers.js';
|
|
19
|
+
import { rekeyStateChecksums, renameComponentFileName, updateConfigForCustomRename, updateConfigForOverrideRename, } from './rename-helpers.js';
|
|
19
20
|
import { renameXpcshellTestFiles } from './rename-xpcshell.js';
|
|
20
|
-
/** Escapes regex metacharacters so a user-supplied name is literal inside a RegExp. */
|
|
21
|
-
function escapeRegex(input) {
|
|
22
|
-
return input.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
23
|
-
}
|
|
24
21
|
/**
|
|
25
22
|
* Derives the test file name for a component, matching the convention used by
|
|
26
23
|
* `furnace create --with-tests`.
|
|
@@ -58,6 +55,7 @@ async function renameTestFiles(engineDir, projectRoot, oldName, newName, journal
|
|
|
58
55
|
if (await pathExists(oldTestPath)) {
|
|
59
56
|
try {
|
|
60
57
|
await snapshotFile(journal, oldTestPath);
|
|
58
|
+
await snapshotFile(journal, newTestPath);
|
|
61
59
|
const content = await readText(oldTestPath);
|
|
62
60
|
await writeText(newTestPath, updateBrowserChromeTestContent(content, oldName, newName, binaryName));
|
|
63
61
|
await removeFile(oldTestPath);
|
|
@@ -144,6 +142,7 @@ async function renameMochikitTestFiles(engineDir, oldName, newName, journal) {
|
|
|
144
142
|
.replace(new RegExp(`Test the ${escapeRegex(oldName)} `, 'g'), `Test the ${newName} `)
|
|
145
143
|
.replace(new RegExp(`add_task\\(async function test_${escapeRegex(oldName.replace(/-/g, '_'))}_defined\\(`, 'g'), `add_task(async function test_${newName.replace(/-/g, '_')}_defined(`)
|
|
146
144
|
.replace(new RegExp(`"${escapeRegex(oldName)} custom element`, 'g'), `"${newName} custom element`);
|
|
145
|
+
await snapshotFile(journal, newTestPath);
|
|
147
146
|
await writeText(newTestPath, updatedContent);
|
|
148
147
|
await removeFile(oldTestPath);
|
|
149
148
|
info(`Renamed mochikit test: ${oldTestFileName} → ${newTestFileName}`);
|
|
@@ -209,7 +208,14 @@ async function performRenameMutations(args) {
|
|
|
209
208
|
}
|
|
210
209
|
await snapshotDir(journal, oldDir);
|
|
211
210
|
await snapshotFile(journal, args.furnaceConfigPath);
|
|
211
|
+
// Journal the state file BEFORE step 4 re-keys its checksums, plus
|
|
212
|
+
// the new dir and every new-name destination below (a snapshot of a
|
|
213
|
+
// missing path records {existed: false} → rollback DELETES it).
|
|
214
|
+
// Without these, a failed or SIGINT'd rename stranded the new-name
|
|
215
|
+
// scaffold and kept re-keyed state for a nonexistent component.
|
|
216
|
+
await snapshotFile(journal, getFurnacePaths(projectRoot).furnaceState);
|
|
212
217
|
// 1. Create new directory with renamed files and updated content
|
|
218
|
+
recordCreatedDir(journal, newDir);
|
|
213
219
|
await ensureDir(newDir);
|
|
214
220
|
const entries = await readdir(oldDir, { withFileTypes: true });
|
|
215
221
|
for (const entry of entries) {
|
|
@@ -227,6 +233,7 @@ async function performRenameMutations(args) {
|
|
|
227
233
|
const newFileName = renameComponentFileName(oldFileName, oldName, newName);
|
|
228
234
|
const oldPath = join(oldDir, oldFileName);
|
|
229
235
|
const newPath = join(newDir, newFileName);
|
|
236
|
+
await snapshotFile(journal, newPath);
|
|
230
237
|
if (isComponentSourceFile(oldFileName)) {
|
|
231
238
|
let content = await readText(oldPath);
|
|
232
239
|
// Use word-boundary-aware patterns so substrings in other
|
|
@@ -320,34 +327,6 @@ async function performRenameMutations(args) {
|
|
|
320
327
|
}
|
|
321
328
|
});
|
|
322
329
|
}
|
|
323
|
-
/**
|
|
324
|
-
* Re-keys checksum entries in furnace-state.json from the old component name
|
|
325
|
-
* to the new name so that `doctor` doesn't flag stale entries and the next
|
|
326
|
-
* `apply` can correctly detect whether the renamed component has changed.
|
|
327
|
-
*/
|
|
328
|
-
async function rekeyStateChecksums(projectRoot, componentType, oldName, newName) {
|
|
329
|
-
const oldPrefix = `${componentType}/${oldName}/`;
|
|
330
|
-
const newPrefix = `${componentType}/${newName}/`;
|
|
331
|
-
await updateFurnaceState(projectRoot, (state) => {
|
|
332
|
-
const result = { ...state };
|
|
333
|
-
for (const field of ['appliedChecksums', 'engineChecksums']) {
|
|
334
|
-
const checksums = state[field];
|
|
335
|
-
if (!checksums)
|
|
336
|
-
continue;
|
|
337
|
-
const updated = {};
|
|
338
|
-
for (const [key, value] of Object.entries(checksums)) {
|
|
339
|
-
if (key.startsWith(oldPrefix)) {
|
|
340
|
-
updated[newPrefix + key.slice(oldPrefix.length)] = value;
|
|
341
|
-
}
|
|
342
|
-
else {
|
|
343
|
-
updated[key] = value;
|
|
344
|
-
}
|
|
345
|
-
}
|
|
346
|
-
result[field] = updated;
|
|
347
|
-
}
|
|
348
|
-
return result;
|
|
349
|
-
});
|
|
350
|
-
}
|
|
351
330
|
async function updateEngineRegistrations(engineDir, oldName, newName, newDir, ftlDir, isLocalized, journal) {
|
|
352
331
|
const customElementsPath = join(engineDir, 'toolkit/content/customElements.js');
|
|
353
332
|
const jarMnPath = join(engineDir, 'toolkit/content/jar.mn');
|
|
@@ -372,6 +351,7 @@ async function updateEngineRegistrations(engineDir, oldName, newName, newDir, ft
|
|
|
372
351
|
const newFtlPath = join(ftlDirPath, `${newName}.ftl`);
|
|
373
352
|
if (await pathExists(oldFtlPath)) {
|
|
374
353
|
await snapshotFile(journal, oldFtlPath);
|
|
354
|
+
await snapshotFile(journal, newFtlPath);
|
|
375
355
|
const ftlContent = await readText(oldFtlPath);
|
|
376
356
|
await writeText(newFtlPath, ftlContent);
|
|
377
357
|
await removeFile(oldFtlPath);
|
|
@@ -463,4 +443,3 @@ export async function furnaceRenameCommand(projectRoot, oldName, newName) {
|
|
|
463
443
|
' 3. Run "fireforge furnace apply" to update the engine', newName);
|
|
464
444
|
outro('Rename complete');
|
|
465
445
|
}
|
|
466
|
-
//# sourceMappingURL=rename.js.map
|
|
@@ -199,4 +199,3 @@ export async function furnaceStatusCommand(projectRoot, name) {
|
|
|
199
199
|
info('Tip: run `fireforge furnace status <name>` for detailed component info, or `fireforge furnace --help` for all subcommands.');
|
|
200
200
|
outro('Status complete');
|
|
201
201
|
}
|
|
202
|
-
//# sourceMappingURL=status.js.map
|
|
@@ -1,15 +1,56 @@
|
|
|
1
1
|
// SPDX-License-Identifier: EUPL-1.2
|
|
2
|
+
import { readdir } from 'node:fs/promises';
|
|
3
|
+
import { join } from 'node:path';
|
|
2
4
|
import { getProjectPaths, loadConfig } from '../../core/config.js';
|
|
3
5
|
import { applyAllComponents } from '../../core/furnace-apply.js';
|
|
4
6
|
import { logApplyResult } from '../../core/furnace-apply-output.js';
|
|
5
|
-
import { furnaceConfigExists, loadFurnaceConfig } from '../../core/furnace-config.js';
|
|
7
|
+
import { furnaceConfigExists, getFurnacePaths, loadFurnaceConfig, } from '../../core/furnace-config.js';
|
|
6
8
|
import { reportJsconfigPathsSync } from '../../core/furnace-jsconfig.js';
|
|
7
9
|
import { runFurnaceMutation } from '../../core/furnace-operation.js';
|
|
10
|
+
import { countEntriesWithBlockingStepErrors } from '../../core/furnace-step-errors.js';
|
|
11
|
+
import { containsMergeConflictMarkers } from '../../core/furnace-validate-structure.js';
|
|
8
12
|
import { findOverrideBaseVersionDrift, formatOverrideBaseVersionDriftWarning, } from '../../core/furnace-version-drift.js';
|
|
9
13
|
import { FurnaceError } from '../../errors/furnace.js';
|
|
10
|
-
import { pathExists } from '../../utils/fs.js';
|
|
14
|
+
import { pathExists, readText } from '../../utils/fs.js';
|
|
11
15
|
import { info, intro, outro, spinner, warn } from '../../utils/logger.js';
|
|
12
16
|
import { furnaceRefreshCommand } from './refresh.js';
|
|
17
|
+
/**
|
|
18
|
+
* Scans every configured override/custom component workspace for files
|
|
19
|
+
* carrying unresolved merge conflict markers. Returns the component names
|
|
20
|
+
* (sorted, unique) that must be resolved before an apply may run.
|
|
21
|
+
*/
|
|
22
|
+
async function findComponentsWithConflictMarkers(furnacePaths, config) {
|
|
23
|
+
const conflicted = new Set();
|
|
24
|
+
const componentDirs = [
|
|
25
|
+
...Object.keys(config.overrides).map((name) => ({
|
|
26
|
+
name,
|
|
27
|
+
dir: join(furnacePaths.overridesDir, name),
|
|
28
|
+
})),
|
|
29
|
+
...Object.keys(config.custom).map((name) => ({
|
|
30
|
+
name,
|
|
31
|
+
dir: join(furnacePaths.customDir, name),
|
|
32
|
+
})),
|
|
33
|
+
];
|
|
34
|
+
for (const { name, dir } of componentDirs) {
|
|
35
|
+
if (!(await pathExists(dir)))
|
|
36
|
+
continue;
|
|
37
|
+
const entries = await readdir(dir, { withFileTypes: true });
|
|
38
|
+
for (const entry of entries) {
|
|
39
|
+
if (!entry.isFile())
|
|
40
|
+
continue;
|
|
41
|
+
if (!entry.name.endsWith('.mjs') &&
|
|
42
|
+
!entry.name.endsWith('.css') &&
|
|
43
|
+
!entry.name.endsWith('.ftl')) {
|
|
44
|
+
continue;
|
|
45
|
+
}
|
|
46
|
+
if (containsMergeConflictMarkers(await readText(join(dir, entry.name)))) {
|
|
47
|
+
conflicted.add(name);
|
|
48
|
+
break;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return [...conflicted].sort();
|
|
53
|
+
}
|
|
13
54
|
/**
|
|
14
55
|
* Runs the furnace sync command: detects overrides with baseVersion drift,
|
|
15
56
|
* refreshes them (three-way merge), and re-applies all components.
|
|
@@ -57,6 +98,38 @@ export async function furnaceSyncCommand(projectRoot, options = {}) {
|
|
|
57
98
|
else {
|
|
58
99
|
info('All overrides are up-to-date with the current Firefox version.');
|
|
59
100
|
}
|
|
101
|
+
// Phase 2.5: post-refresh gates. Refresh deliberately leaves conflict
|
|
102
|
+
// markers in workspace files and does NOT bump baseVersion on conflict —
|
|
103
|
+
// so before this gate existed, sync would warn about conflicts and then
|
|
104
|
+
// copy the marker-laden files straight into the engine via Phase 3,
|
|
105
|
+
// producing a broken build from the one command whose whole purpose is a
|
|
106
|
+
// safe upgrade. Apply/deploy both enforce a drift gate; sync must not be
|
|
107
|
+
// the back door around it.
|
|
108
|
+
if (!options.dryRun) {
|
|
109
|
+
const refreshedConfig = await loadFurnaceConfig(projectRoot);
|
|
110
|
+
const furnacePaths = getFurnacePaths(projectRoot);
|
|
111
|
+
const conflicted = await findComponentsWithConflictMarkers(furnacePaths, refreshedConfig);
|
|
112
|
+
const remainingDrift = findOverrideBaseVersionDrift(refreshedConfig, forgeConfig.firefox.version);
|
|
113
|
+
if (conflicted.length > 0 || remainingDrift.length > 0) {
|
|
114
|
+
if (conflicted.length > 0) {
|
|
115
|
+
warn(`Unresolved merge conflicts in: ${conflicted.join(', ')}`);
|
|
116
|
+
}
|
|
117
|
+
for (const entry of remainingDrift) {
|
|
118
|
+
warn(formatOverrideBaseVersionDriftWarning(entry));
|
|
119
|
+
}
|
|
120
|
+
throw new FurnaceError('Sync stopped before applying: ' +
|
|
121
|
+
(conflicted.length > 0
|
|
122
|
+
? `${conflicted.length} component(s) contain unresolved merge conflict markers` +
|
|
123
|
+
(remainingDrift.length > 0 ? ' and ' : '')
|
|
124
|
+
: '') +
|
|
125
|
+
(remainingDrift.length > 0
|
|
126
|
+
? `${remainingDrift.length} override(s) still have baseVersion drift`
|
|
127
|
+
: '') +
|
|
128
|
+
'. Resolve the conflicts in the component workspace files, re-run ' +
|
|
129
|
+
'"fireforge furnace refresh <name>" to update baseVersion, then run ' +
|
|
130
|
+
'"fireforge furnace sync" again. Nothing was applied to the engine.');
|
|
131
|
+
}
|
|
132
|
+
}
|
|
60
133
|
// Phase 3: Re-apply all components to the engine
|
|
61
134
|
if (!options.dryRun) {
|
|
62
135
|
info('\nApplying all components to engine...');
|
|
@@ -64,7 +137,7 @@ export async function furnaceSyncCommand(projectRoot, options = {}) {
|
|
|
64
137
|
const result = await runFurnaceMutation(projectRoot, 'apply-rollback', (ctx) => applyAllComponents(projectRoot, false, { operationContext: ctx }), { dryRun: false });
|
|
65
138
|
applySpinner.stop('Components applied');
|
|
66
139
|
logApplyResult(result, false);
|
|
67
|
-
const appliedWithStepErrorsCount = result.applied
|
|
140
|
+
const appliedWithStepErrorsCount = countEntriesWithBlockingStepErrors(result.applied);
|
|
68
141
|
const totalFailures = result.errors.length + appliedWithStepErrorsCount;
|
|
69
142
|
if (totalFailures > 0) {
|
|
70
143
|
throw new FurnaceError(`${totalFailures} component${totalFailures === 1 ? '' : 's'} failed to apply cleanly`);
|
|
@@ -76,4 +149,3 @@ export async function furnaceSyncCommand(projectRoot, options = {}) {
|
|
|
76
149
|
outro('Dry run complete');
|
|
77
150
|
}
|
|
78
151
|
}
|
|
79
|
-
//# sourceMappingURL=sync.js.map
|