@hominis/fireforge 0.49.1 → 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 +41 -0
- 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-templates.d.ts +8 -3
- package/dist/src/commands/furnace/create-templates.js +8 -23
- 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 +2 -2
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* budgets. `gatePlacementPlan` owns every policy/confirmation decision a
|
|
5
5
|
* placement export makes before the locked commit in `export.ts` runs.
|
|
6
6
|
*/
|
|
7
|
-
import type { ExportOptions
|
|
7
|
+
import type { ExportOptions } from '../types/commands/index.js';
|
|
8
8
|
import type { FireForgeConfig } from '../types/config.js';
|
|
9
9
|
import type { SpinnerHandle } from '../utils/logger.js';
|
|
10
10
|
import { type PlacementPlan } from './export-flow.js';
|
|
@@ -14,7 +14,11 @@ import { type PlacementPlan } from './export-flow.js';
|
|
|
14
14
|
* shares this shape. With exactOptionalPropertyTypes the keys must be
|
|
15
15
|
* omitted entirely (not set to undefined) when the flags are absent.
|
|
16
16
|
*/
|
|
17
|
-
export declare function patchMetadataExtras(options: ExportOptions):
|
|
17
|
+
export declare function patchMetadataExtras(options: ExportOptions): {
|
|
18
|
+
tier?: 'branding';
|
|
19
|
+
/** CLI flags only ever carry bare check IDs. */
|
|
20
|
+
lintIgnore?: string[];
|
|
21
|
+
};
|
|
18
22
|
/**
|
|
19
23
|
* Resolves and gates the placement plan when any placement flag
|
|
20
24
|
* (`--order`/`--before`/`--after`) was given: rejects the `--supersede`
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { LintIgnoreChecks } from '../core/patch-lint-ignore.js';
|
|
1
2
|
import type { PatchesManifest, PatchLintIssue } from '../types/commands/index.js';
|
|
2
3
|
import type { ExportOptions, PatchCategory } from '../types/commands/index.js';
|
|
3
4
|
import type { FireForgeConfig } from '../types/config.js';
|
|
@@ -22,7 +23,7 @@ export interface RunPatchLintOptions {
|
|
|
22
23
|
* `large-patch-lines` on a cohesive branding bundle that genuinely cannot
|
|
23
24
|
* be split.
|
|
24
25
|
*/
|
|
25
|
-
ignoreChecks?:
|
|
26
|
+
ignoreChecks?: LintIgnoreChecks | undefined;
|
|
26
27
|
/**
|
|
27
28
|
* Optional explicit tier override (threaded from `PatchMetadata.tier`).
|
|
28
29
|
* Forces the branding-tier thresholds when set, independent of the
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Lets `export --order` land a new system module whose moz.build line is
|
|
3
|
+
* still unexported working-tree drift in the patch that registers it.
|
|
4
|
+
*
|
|
5
|
+
* The two refusals used to deadlock: the module's export failed
|
|
6
|
+
* `unregistered-system-module` because no patch body carried its moz.build
|
|
7
|
+
* line yet, and the registering patch could not be re-exported first
|
|
8
|
+
* because its line named a file no patch created. The way through is
|
|
9
|
+
* declared intent plus evidence: when the registering patch carries a
|
|
10
|
+
* staged registration for the module and the working tree's moz.build has
|
|
11
|
+
* exactly that line, the export is accepted and the operator is told to
|
|
12
|
+
* re-export the registering patch next. Without the declaration the
|
|
13
|
+
* refusal names the steps, with the exact `patch staged-dependency`
|
|
14
|
+
* command, instead of stopping at "register it".
|
|
15
|
+
*
|
|
16
|
+
* Consumed by export-flow.ts.
|
|
17
|
+
*/
|
|
18
|
+
import type { PatchQueueContext } from '../core/patch-lint.js';
|
|
19
|
+
import type { PatchLintIssue } from '../types/commands/index.js';
|
|
20
|
+
/** Result of {@link acceptTreeRegisteredModules}. */
|
|
21
|
+
export interface TreeRegistrationOutcome {
|
|
22
|
+
/** The projected errors left after accepted modules are removed. */
|
|
23
|
+
remaining: PatchLintIssue[];
|
|
24
|
+
/** One note per accepted module, naming the re-export to run next. */
|
|
25
|
+
accepted: string[];
|
|
26
|
+
/** Detail lines for modules whose registration is in the tree but undeclared. */
|
|
27
|
+
advice: string[];
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Removes `unregistered-system-module` findings for modules the pending
|
|
31
|
+
* export creates when a queue patch declares their registration as a
|
|
32
|
+
* staged dependency and the working tree's moz.build carries that line.
|
|
33
|
+
* For a module whose line is in the tree but undeclared, returns the steps
|
|
34
|
+
* that make it acceptable.
|
|
35
|
+
*
|
|
36
|
+
* @param args - The engine directory (the working tree), the current queue,
|
|
37
|
+
* the filename the pending export would take, the files it creates, and
|
|
38
|
+
* the placement projection's error findings
|
|
39
|
+
*/
|
|
40
|
+
export declare function acceptTreeRegisteredModules(args: {
|
|
41
|
+
engineDir: string;
|
|
42
|
+
baseCtx: PatchQueueContext;
|
|
43
|
+
newFilename: string;
|
|
44
|
+
pendingNewFiles: ReadonlySet<string>;
|
|
45
|
+
projectedIssues: readonly PatchLintIssue[];
|
|
46
|
+
}): Promise<TreeRegistrationOutcome>;
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
// SPDX-License-Identifier: EUPL-1.2
|
|
2
|
+
/**
|
|
3
|
+
* Lets `export --order` land a new system module whose moz.build line is
|
|
4
|
+
* still unexported working-tree drift in the patch that registers it.
|
|
5
|
+
*
|
|
6
|
+
* The two refusals used to deadlock: the module's export failed
|
|
7
|
+
* `unregistered-system-module` because no patch body carried its moz.build
|
|
8
|
+
* line yet, and the registering patch could not be re-exported first
|
|
9
|
+
* because its line named a file no patch created. The way through is
|
|
10
|
+
* declared intent plus evidence: when the registering patch carries a
|
|
11
|
+
* staged registration for the module and the working tree's moz.build has
|
|
12
|
+
* exactly that line, the export is accepted and the operator is told to
|
|
13
|
+
* re-export the registering patch next. Without the declaration the
|
|
14
|
+
* refusal names the steps, with the exact `patch staged-dependency`
|
|
15
|
+
* command, instead of stopping at "register it".
|
|
16
|
+
*
|
|
17
|
+
* Consumed by export-flow.ts.
|
|
18
|
+
*/
|
|
19
|
+
import { basename, dirname, join } from 'node:path';
|
|
20
|
+
import { STAGED_DEPENDENCY_REASON_PLACEHOLDER } from '../core/patch-lint-staged-registration.js';
|
|
21
|
+
import { pathExists, readText } from '../utils/fs.js';
|
|
22
|
+
async function readLines(path) {
|
|
23
|
+
if (!(await pathExists(path)))
|
|
24
|
+
return undefined;
|
|
25
|
+
return (await readText(path)).split('\n').map((line) => line.trim());
|
|
26
|
+
}
|
|
27
|
+
/** The nearest moz.build at or above `modulePath` whose lines name `leaf` quoted. */
|
|
28
|
+
async function findTreeRegistration(engineDir, modulePath) {
|
|
29
|
+
const leaf = basename(modulePath);
|
|
30
|
+
let dir = dirname(modulePath);
|
|
31
|
+
for (;;) {
|
|
32
|
+
const file = dir === '.' ? 'moz.build' : `${dir}/moz.build`;
|
|
33
|
+
const line = (await readLines(join(engineDir, file)))?.find((candidate) => candidate.includes(`"${leaf}"`) || candidate.includes(`'${leaf}'`));
|
|
34
|
+
if (line !== undefined)
|
|
35
|
+
return { file, line };
|
|
36
|
+
if (dir === '.' || dir === '')
|
|
37
|
+
return undefined;
|
|
38
|
+
const parent = dirname(dir);
|
|
39
|
+
dir = parent === dir ? '.' : parent;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Removes `unregistered-system-module` findings for modules the pending
|
|
44
|
+
* export creates when a queue patch declares their registration as a
|
|
45
|
+
* staged dependency and the working tree's moz.build carries that line.
|
|
46
|
+
* For a module whose line is in the tree but undeclared, returns the steps
|
|
47
|
+
* that make it acceptable.
|
|
48
|
+
*
|
|
49
|
+
* @param args - The engine directory (the working tree), the current queue,
|
|
50
|
+
* the filename the pending export would take, the files it creates, and
|
|
51
|
+
* the placement projection's error findings
|
|
52
|
+
*/
|
|
53
|
+
export async function acceptTreeRegisteredModules(args) {
|
|
54
|
+
const outcome = { remaining: [], accepted: [], advice: [] };
|
|
55
|
+
for (const issue of args.projectedIssues) {
|
|
56
|
+
if (issue.check !== 'unregistered-system-module' || !args.pendingNewFiles.has(issue.file)) {
|
|
57
|
+
outcome.remaining.push(issue);
|
|
58
|
+
continue;
|
|
59
|
+
}
|
|
60
|
+
const declared = args.baseCtx.entries.flatMap((entry) => (entry.metadata?.stagedDependencies?.registrations ?? [])
|
|
61
|
+
.filter((registration) => registration.creates === issue.file &&
|
|
62
|
+
(registration.owner === undefined || registration.owner === args.newFilename))
|
|
63
|
+
.map((registration) => ({ holder: entry.filename, registration })));
|
|
64
|
+
let accepted = false;
|
|
65
|
+
for (const { holder, registration } of declared) {
|
|
66
|
+
const lines = await readLines(join(args.engineDir, registration.file));
|
|
67
|
+
if (lines?.includes(registration.line.trim()) !== true)
|
|
68
|
+
continue;
|
|
69
|
+
outcome.accepted.push(`${issue.file} is registered by the working tree's ${registration.file} ` +
|
|
70
|
+
`("${registration.line.trim()}"), which ${holder} declares as a staged registration ` +
|
|
71
|
+
`but has not exported yet. Re-export ${holder} right after this export to land the ` +
|
|
72
|
+
`line: fireforge re-export ${holder}`);
|
|
73
|
+
accepted = true;
|
|
74
|
+
break;
|
|
75
|
+
}
|
|
76
|
+
if (accepted)
|
|
77
|
+
continue;
|
|
78
|
+
outcome.remaining.push(issue);
|
|
79
|
+
const tree = await findTreeRegistration(args.engineDir, issue.file);
|
|
80
|
+
if (tree === undefined)
|
|
81
|
+
continue;
|
|
82
|
+
const owner = args.baseCtx.entries.find((entry) => entry.metadata?.filesAffected.includes(tree.file))?.filename;
|
|
83
|
+
if (owner === undefined)
|
|
84
|
+
continue;
|
|
85
|
+
outcome.advice.push('', `${issue.file} is registered in the working tree's ${tree.file}, but ${owner} has not ` +
|
|
86
|
+
'exported that line. Land both without untangling the tree:', ` 1. fireforge patch staged-dependency ${owner} --add --kind registration --file ${tree.file} ` +
|
|
87
|
+
`--line "${tree.line.replace(/\\/g, '\\\\').replace(/"/g, '\\"')}" --creates ${issue.file} ` +
|
|
88
|
+
`--owner ${args.newFilename} ${STAGED_DEPENDENCY_REASON_PLACEHOLDER}`, ' 2. re-run this export (a declared registration present in the working tree is accepted)', ` 3. fireforge re-export ${owner}`);
|
|
89
|
+
}
|
|
90
|
+
return outcome;
|
|
91
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The remedy printed under a forward-import refusal from `re-export`
|
|
3
|
+
* (plain refresh and `--scan` adoption alike): the earliest order the files
|
|
4
|
+
* can take as their own later patch, and the exact `patch staged-dependency
|
|
5
|
+
* --add` commands that declare the edges instead.
|
|
6
|
+
*
|
|
7
|
+
* The refusal used to end with "export them with --order <n> or run
|
|
8
|
+
* patch staged-dependency --add", which left the operator to work out both
|
|
9
|
+
* the number and every flag of the declaration from the finding text.
|
|
10
|
+
*/
|
|
11
|
+
import type { PatchesManifest, PatchLintIssue } from '../types/commands/index.js';
|
|
12
|
+
import type { FireForgeConfig } from '../types/config.js';
|
|
13
|
+
/** Inputs to {@link formatForwardImportRemedy}. */
|
|
14
|
+
export interface ForwardImportRemedyInput {
|
|
15
|
+
/** What to do after the fix, e.g. "re-running the scan". */
|
|
16
|
+
reRunHint: string;
|
|
17
|
+
/** The refusal's findings; only `forward-import` and `forward-registration` ones are read. */
|
|
18
|
+
issues: readonly PatchLintIssue[];
|
|
19
|
+
/** Current manifest (null when unavailable: the order is then not named). */
|
|
20
|
+
manifest: PatchesManifest | null;
|
|
21
|
+
/** Project config; only `patchPolicy` is read. */
|
|
22
|
+
config?: Pick<FireForgeConfig, 'patchPolicy'>;
|
|
23
|
+
/** Category the files would be exported under (the refused patch's). */
|
|
24
|
+
category?: string;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Renders the remedy lines. Falls back to the generic sentence when the
|
|
28
|
+
* findings carry no structured declarations.
|
|
29
|
+
*
|
|
30
|
+
* @param input - See {@link ForwardImportRemedyInput}
|
|
31
|
+
*/
|
|
32
|
+
export declare function formatForwardImportRemedy(input: ForwardImportRemedyInput): string;
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
// SPDX-License-Identifier: EUPL-1.2
|
|
2
|
+
/**
|
|
3
|
+
* The remedy printed under a forward-import refusal from `re-export`
|
|
4
|
+
* (plain refresh and `--scan` adoption alike): the earliest order the files
|
|
5
|
+
* can take as their own later patch, and the exact `patch staged-dependency
|
|
6
|
+
* --add` commands that declare the edges instead.
|
|
7
|
+
*
|
|
8
|
+
* The refusal used to end with "export them with --order <n> or run
|
|
9
|
+
* patch staged-dependency --add", which left the operator to work out both
|
|
10
|
+
* the number and every flag of the declaration from the finding text.
|
|
11
|
+
*/
|
|
12
|
+
import { STAGED_DEPENDENCY_REASON_PLACEHOLDER } from '../core/patch-lint-staged-registration.js';
|
|
13
|
+
import { earliestLegalOrderAfter } from '../core/patch-order-legal.js';
|
|
14
|
+
import { formatPatchOrder } from '../core/patch-parse.js';
|
|
15
|
+
function quoteArg(value) {
|
|
16
|
+
return `"${value.replace(/\\/g, '\\\\').replace(/"/g, '\\"')}"`;
|
|
17
|
+
}
|
|
18
|
+
function declarationCommand(declaration) {
|
|
19
|
+
const anchor = declaration.kind === 'import'
|
|
20
|
+
? `--specifier ${quoteArg(declaration.specifier ?? '')}`
|
|
21
|
+
: `--kind registration --line ${quoteArg(declaration.line ?? '')}`;
|
|
22
|
+
return (`fireforge patch staged-dependency ${declaration.patch} --add --file ${declaration.file} ` +
|
|
23
|
+
`${anchor} --creates ${declaration.creates} --owner ${declaration.owner} ` +
|
|
24
|
+
STAGED_DEPENDENCY_REASON_PLACEHOLDER);
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Renders the remedy lines. Falls back to the generic sentence when the
|
|
28
|
+
* findings carry no structured declarations.
|
|
29
|
+
*
|
|
30
|
+
* @param input - See {@link ForwardImportRemedyInput}
|
|
31
|
+
*/
|
|
32
|
+
export function formatForwardImportRemedy(input) {
|
|
33
|
+
const declarations = input.issues
|
|
34
|
+
.filter((issue) => issue.check === 'forward-import' || issue.check === 'forward-registration')
|
|
35
|
+
.flatMap((issue) => issue.stagedDeclarations ?? []);
|
|
36
|
+
const ownerOrders = declarations
|
|
37
|
+
.map((declaration) => input.manifest?.patches.find((patch) => patch.filename === declaration.owner)?.order)
|
|
38
|
+
.filter((order) => order !== undefined);
|
|
39
|
+
const latestOwner = ownerOrders.length > 0 ? Math.max(...ownerOrders) : undefined;
|
|
40
|
+
const legalOrder = latestOwner !== undefined && input.manifest !== null && input.category !== undefined
|
|
41
|
+
? earliestLegalOrderAfter(input.config ?? {}, input.manifest, input.category, latestOwner)
|
|
42
|
+
: null;
|
|
43
|
+
const orderText = legalOrder !== null
|
|
44
|
+
? `"fireforge export <files> --order ${formatPatchOrder(legalOrder)}"; ` +
|
|
45
|
+
`${formatPatchOrder(legalOrder)} is the earliest legal order after the latest creator ` +
|
|
46
|
+
`(${formatPatchOrder(latestOwner ?? legalOrder)})`
|
|
47
|
+
: '"fireforge export --order <n>"';
|
|
48
|
+
const lines = [
|
|
49
|
+
`Export those files as their own later patch (${orderText}; or ` +
|
|
50
|
+
'"fireforge patch split --order <n>"), or declare the intentional dependency with ' +
|
|
51
|
+
`"fireforge patch staged-dependency --add" before ${input.reRunHint}` +
|
|
52
|
+
(declarations.length > 0 ? ':' : '.'),
|
|
53
|
+
];
|
|
54
|
+
const seen = new Set();
|
|
55
|
+
for (const declaration of declarations) {
|
|
56
|
+
const command = declarationCommand(declaration);
|
|
57
|
+
if (seen.has(command))
|
|
58
|
+
continue;
|
|
59
|
+
seen.add(command);
|
|
60
|
+
lines.push(` ${command}`);
|
|
61
|
+
}
|
|
62
|
+
return lines.join('\n');
|
|
63
|
+
}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { watch as fsWatch } from 'node:fs';
|
|
3
3
|
import { loadConfig } from '../../core/config.js';
|
|
4
4
|
import { applyAllComponents, computeComponentChecksums } from '../../core/furnace-apply.js';
|
|
5
|
-
import { logApplyResult } from '../../core/furnace-apply-output.js';
|
|
5
|
+
import { formatSkipBreakdown, logApplyResult } from '../../core/furnace-apply-output.js';
|
|
6
6
|
import { getFurnacePaths } from '../../core/furnace-config.js';
|
|
7
7
|
import { isComponentSourceFile } from '../../core/furnace-constants.js';
|
|
8
8
|
import { runFurnaceMutation, waitLockMutationOptions } from '../../core/furnace-operation.js';
|
|
@@ -108,7 +108,7 @@ async function runWatchLoop(projectRoot) {
|
|
|
108
108
|
}
|
|
109
109
|
const applied = result.applied.length;
|
|
110
110
|
const skipped = result.skipped.length;
|
|
111
|
-
info(`Re-applied: ${applied} applied, ${skipped} skipped`);
|
|
111
|
+
info(`Re-applied: ${applied} applied, ${skipped} skipped${formatSkipBreakdown(result.skipped)}`);
|
|
112
112
|
retryNeeded = false;
|
|
113
113
|
lastChecksums = await snapshotWatchedChecksums(watchDirs);
|
|
114
114
|
}
|
|
@@ -318,7 +318,7 @@ export async function furnaceApplyCommand(projectRoot, name, options = {}) {
|
|
|
318
318
|
outro(`Dry run complete — would apply ${appliedCount}, skip ${skippedCount}`);
|
|
319
319
|
}
|
|
320
320
|
else {
|
|
321
|
-
outro(`Applied ${appliedCount}, skipped ${skippedCount}`);
|
|
321
|
+
outro(`Applied ${appliedCount}, skipped ${skippedCount}${formatSkipBreakdown(result.skipped)}`);
|
|
322
322
|
}
|
|
323
323
|
// Watch mode: re-apply on file changes in component directories
|
|
324
324
|
if (options.watch && !dryRun) {
|
|
@@ -2,8 +2,9 @@
|
|
|
2
2
|
* `fireforge furnace chrome-doc remove <name>` removes the files and
|
|
3
3
|
* registrations created by `furnace chrome-doc create`.
|
|
4
4
|
*/
|
|
5
|
+
import type { FurnaceLockWaitable } from '../../types/commands/index.js';
|
|
5
6
|
/** Options for `furnace chrome-doc remove`. */
|
|
6
|
-
export interface FurnaceChromeDocRemoveOptions {
|
|
7
|
+
export interface FurnaceChromeDocRemoveOptions extends FurnaceLockWaitable {
|
|
7
8
|
/** Skip confirmation. Required for real non-interactive removal. */
|
|
8
9
|
yes?: boolean;
|
|
9
10
|
/** Print the removal plan without writing files. */
|
|
@@ -8,7 +8,7 @@ import { join } from 'node:path';
|
|
|
8
8
|
import { confirm } from '@clack/prompts';
|
|
9
9
|
import { loadConfig } from '../../core/config.js';
|
|
10
10
|
import { stdioIsInteractive } from '../../core/destructive.js';
|
|
11
|
-
import { completeJournalRollback, runFurnaceMutation, } from '../../core/furnace-operation.js';
|
|
11
|
+
import { completeJournalRollback, runFurnaceMutation, waitLockMutationOptions, } from '../../core/furnace-operation.js';
|
|
12
12
|
import { assertFurnaceEngineReady } from '../../core/furnace-precondition.js';
|
|
13
13
|
import { createRollbackJournal, snapshotDir, snapshotFile, } from '../../core/furnace-rollback.js';
|
|
14
14
|
import { FurnaceError } from '../../errors/furnace.js';
|
|
@@ -138,7 +138,7 @@ export async function furnaceChromeDocRemoveCommand(projectRoot, name, options =
|
|
|
138
138
|
plan,
|
|
139
139
|
binaryName: forgeConfig.binaryName,
|
|
140
140
|
operationContext: ctx,
|
|
141
|
-
}));
|
|
141
|
+
}), waitLockMutationOptions(options.waitLockSeconds));
|
|
142
142
|
info(`Removed ${result.removedFiles} source file${result.removedFiles === 1 ? '' : 's'} and ` +
|
|
143
143
|
`${result.removedJarEntries} jar registration${result.removedJarEntries === 1 ? '' : 's'} for "${name}".`);
|
|
144
144
|
if (result.removedTestDir) {
|
|
@@ -15,8 +15,9 @@
|
|
|
15
15
|
* mid-scaffold restores every touched file. A successful run leaves the tree
|
|
16
16
|
* ready for `fireforge build`.
|
|
17
17
|
*/
|
|
18
|
+
import type { FurnaceLockWaitable } from '../../types/commands/index.js';
|
|
18
19
|
/** Options for `furnace chrome-doc create`. */
|
|
19
|
-
export interface FurnaceChromeDocCreateOptions {
|
|
20
|
+
export interface FurnaceChromeDocCreateOptions extends FurnaceLockWaitable {
|
|
20
21
|
/**
|
|
21
22
|
* Emit the titlebar-buttonbox markup and leave platform window controls
|
|
22
23
|
* visible. Defaults to `true` because the common case is a full chrome
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
import { join } from 'node:path';
|
|
20
20
|
import { loadConfig } from '../../core/config.js';
|
|
21
21
|
import { furnaceConfigExists, loadFurnaceConfig } from '../../core/furnace-config.js';
|
|
22
|
-
import { completeJournalRollback, runFurnaceMutation, } from '../../core/furnace-operation.js';
|
|
22
|
+
import { completeJournalRollback, runFurnaceMutation, waitLockMutationOptions, } from '../../core/furnace-operation.js';
|
|
23
23
|
import { assertFurnaceEngineReady } from '../../core/furnace-precondition.js';
|
|
24
24
|
import { createRollbackJournal, recordCreatedDir, snapshotFile, } from '../../core/furnace-rollback.js';
|
|
25
25
|
import { DEFAULT_LICENSE, getLicenseHeader } from '../../core/license-headers.js';
|
|
@@ -343,7 +343,7 @@ export async function furnaceChromeDocCreateCommand(projectRoot, name, options =
|
|
|
343
343
|
browserWindow,
|
|
344
344
|
binaryName: forgeConfig.binaryName,
|
|
345
345
|
operationContext: ctx,
|
|
346
|
-
}));
|
|
346
|
+
}), waitLockMutationOptions(options.waitLockSeconds));
|
|
347
347
|
const nextSteps = [
|
|
348
348
|
` 1. Edit engine/browser/base/content/${name}.xhtml and fill in the body.`,
|
|
349
349
|
` 2. Localize strings in engine/browser/locales/en-US/browser/${name}.ftl.`,
|
|
@@ -26,9 +26,14 @@ export interface GenerateMjsContentOptions {
|
|
|
26
26
|
* `MozXULElement`. Calling it from `connectedCallback` on a Lit-based
|
|
27
27
|
* component throws `TypeError: this.insertFTLIfNeeded is not a function` at
|
|
28
28
|
* every connect. Upstream Firefox components (e.g. `moz-input-folder.mjs`)
|
|
29
|
-
* solve this with a module-level guarded call on `window.MozXULElement
|
|
30
|
-
*
|
|
31
|
-
*
|
|
29
|
+
* solve this with a module-level guarded call on `window.MozXULElement`, and
|
|
30
|
+
* the template mirrors that call so `--localized` produces functional code.
|
|
31
|
+
*
|
|
32
|
+
* The template emits no `connectedCallback`/`disconnectedCallback` pair for
|
|
33
|
+
* Fluent. `MozLitElement` already connects its shadow render root to
|
|
34
|
+
* `document.l10n` on connect and disconnects it on disconnect, so a second
|
|
35
|
+
* `l10n.connectRoot(shadowRoot)` registers the same root twice, which
|
|
36
|
+
* `DOMLocalization::ConnectRoot` asserts against in debug builds.
|
|
32
37
|
*
|
|
33
38
|
* Path resolution precedence (when `localized` is true):
|
|
34
39
|
* 1. `sharedFtl`: used verbatim. The caller has resolved it from
|
|
@@ -11,9 +11,14 @@
|
|
|
11
11
|
* `MozXULElement`. Calling it from `connectedCallback` on a Lit-based
|
|
12
12
|
* component throws `TypeError: this.insertFTLIfNeeded is not a function` at
|
|
13
13
|
* every connect. Upstream Firefox components (e.g. `moz-input-folder.mjs`)
|
|
14
|
-
* solve this with a module-level guarded call on `window.MozXULElement
|
|
15
|
-
*
|
|
16
|
-
*
|
|
14
|
+
* solve this with a module-level guarded call on `window.MozXULElement`, and
|
|
15
|
+
* the template mirrors that call so `--localized` produces functional code.
|
|
16
|
+
*
|
|
17
|
+
* The template emits no `connectedCallback`/`disconnectedCallback` pair for
|
|
18
|
+
* Fluent. `MozLitElement` already connects its shadow render root to
|
|
19
|
+
* `document.l10n` on connect and disconnects it on disconnect, so a second
|
|
20
|
+
* `l10n.connectRoot(shadowRoot)` registers the same root twice, which
|
|
21
|
+
* `DOMLocalization::ConnectRoot` asserts against in debug builds.
|
|
17
22
|
*
|
|
18
23
|
* Path resolution precedence (when `localized` is true):
|
|
19
24
|
* 1. `sharedFtl`: used verbatim. The caller has resolved it from
|
|
@@ -45,25 +50,6 @@ export function generateMjsContent(options) {
|
|
|
45
50
|
const ftlModulePreamble = localized
|
|
46
51
|
? `
|
|
47
52
|
window.MozXULElement?.insertFTLIfNeeded(${JSON.stringify(ftlPath)});
|
|
48
|
-
`
|
|
49
|
-
: '';
|
|
50
|
-
const lifecycleHooks = localized
|
|
51
|
-
? `
|
|
52
|
-
connectedCallback() {
|
|
53
|
-
super.connectedCallback();
|
|
54
|
-
const { shadowRoot } = this;
|
|
55
|
-
if (shadowRoot) {
|
|
56
|
-
this.ownerDocument.l10n?.connectRoot(shadowRoot);
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
disconnectedCallback() {
|
|
61
|
-
super.disconnectedCallback();
|
|
62
|
-
const { shadowRoot } = this;
|
|
63
|
-
if (shadowRoot) {
|
|
64
|
-
this.ownerDocument.l10n?.disconnectRoot(shadowRoot);
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
53
|
`
|
|
68
54
|
: '';
|
|
69
55
|
return `${header}
|
|
@@ -80,7 +66,6 @@ class ${className} extends MozLitElement {
|
|
|
80
66
|
/** @type {Record<string, unknown>} */
|
|
81
67
|
static properties = {};
|
|
82
68
|
|
|
83
|
-
${lifecycleHooks}
|
|
84
69
|
render() {
|
|
85
70
|
return html\`
|
|
86
71
|
<link rel="stylesheet" href="chrome://global/content/elements/${name}.css" />
|
|
@@ -5,7 +5,7 @@ import { getProjectPaths, loadConfig } from '../../core/config.js';
|
|
|
5
5
|
import { stdioIsInteractive } from '../../core/destructive.js';
|
|
6
6
|
import { getFurnacePaths, writeFurnaceConfig } from '../../core/furnace-config.js';
|
|
7
7
|
import { resolveFtlChromeSubPath, tagNameToClassName, WIDGETS_DIR, } from '../../core/furnace-constants.js';
|
|
8
|
-
import { completeJournalRollback, runFurnaceMutation, } from '../../core/furnace-operation.js';
|
|
8
|
+
import { completeJournalRollback, runFurnaceMutation, waitLockMutationOptions, } from '../../core/furnace-operation.js';
|
|
9
9
|
import { CUSTOM_ELEMENT_TAG_PATTERN, CUSTOM_ELEMENT_TAG_RULES, describeTagNameProblem, } from '../../core/furnace-registration-validate.js';
|
|
10
10
|
import { createRollbackJournal, recordCreatedDir, snapshotFile, } from '../../core/furnace-rollback.js';
|
|
11
11
|
import { isComponentInEngine, scanWidgetsDirectory } from '../../core/furnace-scanner.js';
|
|
@@ -394,7 +394,7 @@ export async function furnaceCreateCommand(projectRoot, name, options = {}) {
|
|
|
394
394
|
testStyle,
|
|
395
395
|
testDir,
|
|
396
396
|
operationContext: ctx,
|
|
397
|
-
}));
|
|
397
|
+
}), waitLockMutationOptions(options.waitLockSeconds));
|
|
398
398
|
note(formatSuccessNote({
|
|
399
399
|
componentName,
|
|
400
400
|
files,
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Targeted `furnace deploy <name>...`: one or more named components applied
|
|
3
|
+
* under ONE furnace lock hold.
|
|
4
|
+
*
|
|
5
|
+
* Deploying a set of widgets one invocation at a time put every call at the
|
|
6
|
+
* back of the engine-lock queue, so a forty-widget deploy waited forty
|
|
7
|
+
* times. Naming them together waits once. Each named component is still its
|
|
8
|
+
* own atomic unit (applied, then its state persisted, before the next one
|
|
9
|
+
* starts), exactly as a single-name deploy, so a failure or signal midway
|
|
10
|
+
* leaves every earlier component committed and consistent.
|
|
11
|
+
*/
|
|
12
|
+
import { type ApplyAllComponentsResult } from '../../core/furnace-apply.js';
|
|
13
|
+
import type { FurnacePaths } from '../../core/furnace-config.js';
|
|
14
|
+
import type { FurnaceOperationContext } from '../../core/furnace-operation.js';
|
|
15
|
+
import type { FurnaceConfig } from '../../types/furnace.js';
|
|
16
|
+
import { type FragmentIncluderRefresh } from './deploy-fragment-includers.js';
|
|
17
|
+
/** Outcome of {@link deployNamedComponents}. */
|
|
18
|
+
export type NamedDeployOutcome = {
|
|
19
|
+
kind: 'stock';
|
|
20
|
+
stock: string[];
|
|
21
|
+
} | {
|
|
22
|
+
kind: 'result';
|
|
23
|
+
result: ApplyAllComponentsResult;
|
|
24
|
+
includers: FragmentIncluderRefresh;
|
|
25
|
+
/** Named entries that are stock (warned about, never applied). */
|
|
26
|
+
stock: string[];
|
|
27
|
+
/** Named entries that are overrides or custom components, in order. */
|
|
28
|
+
deployed: string[];
|
|
29
|
+
};
|
|
30
|
+
/**
|
|
31
|
+
* Applies each named override or custom component through the same
|
|
32
|
+
* pipeline as deploy-all (`applyAllComponents` with a `componentName`
|
|
33
|
+
* filter), persisting each one's state right after it applies cleanly.
|
|
34
|
+
* Only then are the other stale includers of the fragments the cleanly
|
|
35
|
+
* applied components include refreshed, so an includer that is itself
|
|
36
|
+
* named is applied once, as a named component.
|
|
37
|
+
*
|
|
38
|
+
* Must run inside one `runFurnaceMutation` so the whole set shares a single
|
|
39
|
+
* lock hold.
|
|
40
|
+
*/
|
|
41
|
+
export declare function deployNamedComponents(args: {
|
|
42
|
+
projectRoot: string;
|
|
43
|
+
names: readonly string[];
|
|
44
|
+
config: FurnaceConfig;
|
|
45
|
+
furnacePaths: FurnacePaths;
|
|
46
|
+
isDryRun: boolean;
|
|
47
|
+
operationContext: FurnaceOperationContext;
|
|
48
|
+
}): Promise<NamedDeployOutcome>;
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
// SPDX-License-Identifier: EUPL-1.2
|
|
2
|
+
/**
|
|
3
|
+
* Targeted `furnace deploy <name>...`: one or more named components applied
|
|
4
|
+
* under ONE furnace lock hold.
|
|
5
|
+
*
|
|
6
|
+
* Deploying a set of widgets one invocation at a time put every call at the
|
|
7
|
+
* back of the engine-lock queue, so a forty-widget deploy waited forty
|
|
8
|
+
* times. Naming them together waits once. Each named component is still its
|
|
9
|
+
* own atomic unit (applied, then its state persisted, before the next one
|
|
10
|
+
* starts), exactly as a single-name deploy, so a failure or signal midway
|
|
11
|
+
* leaves every earlier component committed and consistent.
|
|
12
|
+
*/
|
|
13
|
+
import { applyAllComponents } from '../../core/furnace-apply.js';
|
|
14
|
+
import { getPersistableAppliedEntry, persistSingleComponentState, shouldPersistSingleComponentState, } from '../../core/furnace-state-persist.js';
|
|
15
|
+
import { FurnaceError } from '../../errors/furnace.js';
|
|
16
|
+
import { mergeApplyResults, refreshStaleFragmentIncluders, } from './deploy-fragment-includers.js';
|
|
17
|
+
/**
|
|
18
|
+
* Splits the requested names into deployable and stock entries, refusing
|
|
19
|
+
* the whole invocation before any write when one is unknown. Duplicates
|
|
20
|
+
* are dropped, keeping the first occurrence.
|
|
21
|
+
*/
|
|
22
|
+
function partitionDeployNames(names, config) {
|
|
23
|
+
const deployable = [];
|
|
24
|
+
const stock = [];
|
|
25
|
+
for (const name of new Set(names)) {
|
|
26
|
+
if (name in config.overrides || name in config.custom)
|
|
27
|
+
deployable.push(name);
|
|
28
|
+
else if (config.stock.includes(name))
|
|
29
|
+
stock.push(name);
|
|
30
|
+
else
|
|
31
|
+
throw new FurnaceError(`Component "${name}" not found in furnace.json.`, name);
|
|
32
|
+
}
|
|
33
|
+
return { deployable, stock };
|
|
34
|
+
}
|
|
35
|
+
/** Folds several includer refreshes into one, without repeating a tag. */
|
|
36
|
+
function mergeIncluderRefreshes(refreshes, named) {
|
|
37
|
+
// A named component is reported as deployed in its own right, never as
|
|
38
|
+
// an includer some other named component refreshed on its behalf.
|
|
39
|
+
const refreshed = [...new Set(refreshes.flatMap((r) => r.refreshed))].filter((tag) => !named.has(tag));
|
|
40
|
+
return {
|
|
41
|
+
fragments: [...new Set(refreshes.flatMap((r) => r.fragments))].sort(),
|
|
42
|
+
refreshed,
|
|
43
|
+
failed: refreshes.flatMap((r) => r.failed).filter((f) => !named.has(f.tag)),
|
|
44
|
+
results: refreshes.flatMap((r) => r.results),
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Applies each named override or custom component through the same
|
|
49
|
+
* pipeline as deploy-all (`applyAllComponents` with a `componentName`
|
|
50
|
+
* filter), persisting each one's state right after it applies cleanly.
|
|
51
|
+
* Only then are the other stale includers of the fragments the cleanly
|
|
52
|
+
* applied components include refreshed, so an includer that is itself
|
|
53
|
+
* named is applied once, as a named component.
|
|
54
|
+
*
|
|
55
|
+
* Must run inside one `runFurnaceMutation` so the whole set shares a single
|
|
56
|
+
* lock hold.
|
|
57
|
+
*/
|
|
58
|
+
export async function deployNamedComponents(args) {
|
|
59
|
+
const { projectRoot, names, config, furnacePaths, isDryRun, operationContext } = args;
|
|
60
|
+
const { deployable, stock } = partitionDeployNames(names, config);
|
|
61
|
+
if (deployable.length === 0)
|
|
62
|
+
return { kind: 'stock', stock };
|
|
63
|
+
const results = [];
|
|
64
|
+
const clean = [];
|
|
65
|
+
for (const name of deployable) {
|
|
66
|
+
const result = await applyAllComponents(projectRoot, isDryRun, {
|
|
67
|
+
componentName: name,
|
|
68
|
+
persistState: false,
|
|
69
|
+
operationContext,
|
|
70
|
+
});
|
|
71
|
+
results.push(result);
|
|
72
|
+
// Each named deploy is atomic: state is persisted only when every apply
|
|
73
|
+
// step succeeded, and any rollback has already restored the engine.
|
|
74
|
+
if (shouldPersistSingleComponentState(result, isDryRun)) {
|
|
75
|
+
await persistSingleComponentState(projectRoot, getPersistableAppliedEntry('Deploy', name, result.applied[0]), furnacePaths);
|
|
76
|
+
clean.push(name);
|
|
77
|
+
}
|
|
78
|
+
else if (isDryRun) {
|
|
79
|
+
clean.push(name);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
// Other deployed includers of a fragment these components include would
|
|
83
|
+
// otherwise keep a stale expansion. Only after a clean, persisted apply
|
|
84
|
+
// (dry-run always previews).
|
|
85
|
+
const refreshes = [];
|
|
86
|
+
for (const name of clean) {
|
|
87
|
+
refreshes.push(await refreshStaleFragmentIncluders({
|
|
88
|
+
projectRoot,
|
|
89
|
+
name,
|
|
90
|
+
config,
|
|
91
|
+
furnacePaths,
|
|
92
|
+
isDryRun,
|
|
93
|
+
operationContext,
|
|
94
|
+
}));
|
|
95
|
+
}
|
|
96
|
+
const includers = mergeIncluderRefreshes(refreshes, new Set(deployable));
|
|
97
|
+
const [first, ...rest] = results;
|
|
98
|
+
// `deployable` is non-empty, so `first` is always set.
|
|
99
|
+
const primary = first;
|
|
100
|
+
return {
|
|
101
|
+
kind: 'result',
|
|
102
|
+
result: mergeApplyResults(primary, [...rest, ...includers.results]),
|
|
103
|
+
includers,
|
|
104
|
+
stock,
|
|
105
|
+
deployed: deployable,
|
|
106
|
+
};
|
|
107
|
+
}
|
|
@@ -2,7 +2,8 @@ import type { FurnaceDeployOptions } from '../../types/commands/index.js';
|
|
|
2
2
|
/**
|
|
3
3
|
* Runs the furnace deploy command: apply components then validate in one step.
|
|
4
4
|
* @param projectRoot - Root directory of the project
|
|
5
|
-
* @param
|
|
5
|
+
* @param names - Component name(s) to deploy, all under one lock hold
|
|
6
|
+
* (deploys all when omitted or empty)
|
|
6
7
|
* @param options - Command options
|
|
7
8
|
*/
|
|
8
|
-
export declare function furnaceDeployCommand(projectRoot: string,
|
|
9
|
+
export declare function furnaceDeployCommand(projectRoot: string, names?: string | readonly string[], options?: FurnaceDeployOptions): Promise<void>;
|