@hominis/fireforge 0.44.4 → 0.46.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 +120 -0
- package/dist/bin/fireforge.js +6 -0
- package/dist/build-info.json +4 -4
- package/dist/src/cli-usage-error.d.ts +46 -0
- package/dist/src/cli-usage-error.js +81 -0
- package/dist/src/cli.d.ts +5 -1
- package/dist/src/cli.js +20 -21
- package/dist/src/commands/bootstrap.js +1 -2
- package/dist/src/commands/build.js +15 -6
- package/dist/src/commands/destructive-decision.d.ts +19 -0
- package/dist/src/commands/destructive-decision.js +31 -0
- package/dist/src/commands/doctor-check-core.d.ts +0 -6
- package/dist/src/commands/doctor-check-core.js +0 -8
- package/dist/src/commands/doctor-orphaned-harness.d.ts +0 -6
- package/dist/src/commands/doctor-orphaned-harness.js +4 -12
- package/dist/src/commands/doctor-post-rebase-audit.js +1 -1
- package/dist/src/commands/doctor-source-pin.d.ts +29 -0
- package/dist/src/commands/doctor-source-pin.js +81 -0
- package/dist/src/commands/doctor.d.ts +2 -0
- package/dist/src/commands/doctor.js +9 -8
- package/dist/src/commands/download.js +35 -24
- package/dist/src/commands/export-all.js +21 -4
- package/dist/src/commands/export-flow.js +15 -60
- package/dist/src/commands/export-placement-conflicts.js +3 -3
- package/dist/src/commands/export-placement-gate.js +2 -8
- package/dist/src/commands/export-placement-policy.js +3 -5
- package/dist/src/commands/export-shared.d.ts +42 -23
- package/dist/src/commands/export-shared.js +4 -19
- package/dist/src/commands/export.js +10 -1
- package/dist/src/commands/furnace/authoring-config.d.ts +13 -0
- package/dist/src/commands/furnace/authoring-config.js +19 -0
- package/dist/src/commands/furnace/chrome-doc-remove.js +1 -1
- package/dist/src/commands/furnace/create-browser-test.js +3 -8
- package/dist/src/commands/furnace/create-dry-run.js +2 -5
- package/dist/src/commands/furnace/create-templates.d.ts +17 -1
- package/dist/src/commands/furnace/create-templates.js +2 -1
- package/dist/src/commands/furnace/create.js +25 -19
- package/dist/src/commands/furnace/deploy.js +11 -2
- package/dist/src/commands/furnace/init.js +2 -1
- package/dist/src/commands/furnace/override.js +28 -19
- package/dist/src/commands/furnace/refresh.js +9 -1
- package/dist/src/commands/furnace/remove-mutations.d.ts +6 -7
- package/dist/src/commands/furnace/remove-mutations.js +0 -1
- package/dist/src/commands/furnace/remove.js +2 -6
- package/dist/src/commands/furnace/rename-browser-test.js +1 -7
- package/dist/src/commands/furnace/rename.js +29 -29
- package/dist/src/commands/furnace/status.js +12 -9
- package/dist/src/commands/furnace/test-file-name.d.ts +28 -0
- package/dist/src/commands/furnace/test-file-name.js +39 -0
- package/dist/src/commands/furnace/validation-output.d.ts +21 -9
- package/dist/src/commands/furnace/validation-output.js +3 -8
- package/dist/src/commands/import.js +2 -9
- package/dist/src/commands/lint-per-patch.d.ts +2 -2
- package/dist/src/commands/lint-per-patch.js +19 -4
- package/dist/src/commands/lint-per-run-checkjs.d.ts +2 -2
- package/dist/src/commands/lint.d.ts +2 -1
- package/dist/src/commands/lint.js +1 -1
- package/dist/src/commands/manifest.js +1 -1
- package/dist/src/commands/package.js +2 -4
- package/dist/src/commands/patch/compact.js +14 -15
- package/dist/src/commands/patch/delete.js +15 -25
- package/dist/src/commands/patch/entry-projection.d.ts +13 -0
- package/dist/src/commands/patch/entry-projection.js +24 -0
- package/dist/src/commands/patch/lint-ignore.d.ts +0 -8
- package/dist/src/commands/patch/lint-ignore.js +19 -29
- package/dist/src/commands/patch/move-files-create.js +24 -10
- package/dist/src/commands/patch/move-files-into.js +38 -37
- package/dist/src/commands/patch/move-files.js +4 -13
- package/dist/src/commands/patch/rename.js +27 -41
- package/dist/src/commands/patch/reorder.js +25 -38
- package/dist/src/commands/patch/split-plan.d.ts +4 -5
- package/dist/src/commands/patch/split-plan.js +4 -11
- package/dist/src/commands/patch/split.js +45 -43
- package/dist/src/commands/patch/staged-dependency.js +16 -22
- package/dist/src/commands/patch/tier.js +15 -25
- package/dist/src/commands/patch-rename-map.d.ts +19 -0
- package/dist/src/commands/patch-rename-map.js +36 -0
- package/dist/src/commands/pending-resolution.d.ts +15 -0
- package/dist/src/commands/pending-resolution.js +25 -0
- package/dist/src/commands/re-export-adjacent.d.ts +32 -2
- package/dist/src/commands/re-export-adjacent.js +51 -10
- package/dist/src/commands/re-export-bulk-scan.js +6 -10
- package/dist/src/commands/re-export-drift.d.ts +8 -0
- package/dist/src/commands/re-export-drift.js +65 -4
- package/dist/src/commands/re-export-files.d.ts +2 -3
- package/dist/src/commands/re-export-files.js +38 -32
- package/dist/src/commands/re-export-lint.d.ts +3 -4
- package/dist/src/commands/re-export-lint.js +9 -2
- package/dist/src/commands/re-export-options.js +19 -5
- package/dist/src/commands/re-export-register.js +5 -1
- package/dist/src/commands/re-export-scan.js +8 -8
- package/dist/src/commands/re-export-single.d.ts +22 -3
- package/dist/src/commands/re-export-single.js +19 -11
- package/dist/src/commands/re-export.js +44 -27
- package/dist/src/commands/rebase/abort.js +3 -8
- package/dist/src/commands/rebase/continue.js +12 -12
- package/dist/src/commands/rebase/index.js +2 -2
- package/dist/src/commands/rebase/patch-loop.d.ts +2 -2
- package/dist/src/commands/rebase/patch-loop.js +2 -7
- package/dist/src/commands/resolve.js +18 -10
- package/dist/src/commands/run.d.ts +0 -13
- package/dist/src/commands/run.js +12 -25
- package/dist/src/commands/setup-support.d.ts +16 -4
- package/dist/src/commands/setup-support.js +16 -16
- package/dist/src/commands/setup.js +3 -9
- package/dist/src/commands/source.js +8 -1
- package/dist/src/commands/status-check.js +2 -2
- package/dist/src/commands/status-output.js +2 -2
- package/dist/src/commands/status.js +3 -4
- package/dist/src/commands/test-build-phase.d.ts +2 -2
- package/dist/src/commands/test-build-phase.js +33 -8
- package/dist/src/commands/test-diagnose.js +14 -5
- package/dist/src/commands/test-modes.d.ts +2 -2
- package/dist/src/commands/test-modes.js +0 -1
- package/dist/src/commands/test-register.js +6 -3
- package/dist/src/commands/test-run.js +29 -21
- package/dist/src/commands/test-stale-gate.js +8 -5
- package/dist/src/commands/test-verdict.d.ts +16 -2
- package/dist/src/commands/test-verdict.js +18 -3
- package/dist/src/commands/test.js +51 -7
- package/dist/src/commands/token-list.d.ts +26 -0
- package/dist/src/commands/token-list.js +153 -0
- package/dist/src/commands/token.js +17 -1
- package/dist/src/commands/tree.js +7 -2
- package/dist/src/commands/typecheck.js +9 -9
- package/dist/src/commands/wire.js +4 -3
- package/dist/src/core/branding.d.ts +0 -7
- package/dist/src/core/branding.js +3 -2
- package/dist/src/core/browser-wire.js +6 -3
- package/dist/src/core/build-audit-platform.d.ts +29 -0
- package/dist/src/core/build-audit-platform.js +140 -0
- package/dist/src/core/build-audit-registration.js +3 -2
- package/dist/src/core/build-audit-skip.d.ts +57 -0
- package/dist/src/core/build-audit-skip.js +112 -0
- package/dist/src/core/build-audit.d.ts +15 -2
- package/dist/src/core/build-audit.js +154 -12
- package/dist/src/core/build-baseline.d.ts +45 -28
- package/dist/src/core/build-baseline.js +6 -29
- package/dist/src/core/build-jar-escalation.d.ts +64 -0
- package/dist/src/core/build-jar-escalation.js +128 -0
- package/dist/src/core/build-overwrite-guard.js +1 -1
- package/dist/src/core/build-prepare.d.ts +5 -2
- package/dist/src/core/build-prepare.js +34 -6
- package/dist/src/core/config-paths.d.ts +2 -6
- package/dist/src/core/config-paths.js +4 -2
- package/dist/src/core/config-state.d.ts +0 -6
- package/dist/src/core/config-state.js +1 -19
- package/dist/src/core/config-validate-build-audit.d.ts +8 -0
- package/dist/src/core/config-validate-build-audit.js +80 -0
- package/dist/src/core/config-validate-file-size.d.ts +12 -0
- package/dist/src/core/config-validate-file-size.js +65 -0
- package/dist/src/core/config-validate-patch-policy.d.ts +2 -2
- package/dist/src/core/config-validate-patch-policy.js +3 -3
- package/dist/src/core/config-validate-test-toolchains.d.ts +2 -2
- package/dist/src/core/config-validate-test-toolchains.js +4 -5
- package/dist/src/core/config-validate.js +20 -3
- package/dist/src/core/config.d.ts +2 -2
- package/dist/src/core/config.js +11 -15
- package/dist/src/core/coverage-extend.js +4 -4
- package/dist/src/core/discard-baseline.js +7 -7
- package/dist/src/core/engine-precondition.d.ts +1 -9
- package/dist/src/core/engine-precondition.js +3 -8
- package/dist/src/core/engine-session-lock.js +13 -17
- package/dist/src/core/export-moved-code-shape.js +2 -2
- package/dist/src/core/file-lock-owner.d.ts +103 -0
- package/dist/src/core/file-lock-owner.js +259 -0
- package/dist/src/core/file-lock.d.ts +2 -7
- package/dist/src/core/file-lock.js +40 -91
- package/dist/src/core/firefox-cache.d.ts +13 -1
- package/dist/src/core/firefox-cache.js +59 -34
- package/dist/src/core/firefox-download.d.ts +15 -0
- package/dist/src/core/firefox-download.js +37 -21
- package/dist/src/core/firefox-extract.d.ts +6 -5
- package/dist/src/core/firefox-extract.js +36 -18
- package/dist/src/core/firefox.d.ts +30 -32
- package/dist/src/core/firefox.js +5 -36
- package/dist/src/core/furnace-apply-dry-run.d.ts +1 -6
- package/dist/src/core/furnace-apply-dry-run.js +1 -7
- package/dist/src/core/furnace-apply-helpers.d.ts +0 -11
- package/dist/src/core/furnace-apply-helpers.js +8 -19
- package/dist/src/core/furnace-apply-overwrite-warn.js +4 -2
- package/dist/src/core/furnace-apply.d.ts +1 -1
- package/dist/src/core/furnace-apply.js +30 -10
- package/dist/src/core/furnace-config.d.ts +1 -1
- package/dist/src/core/furnace-config.js +23 -36
- package/dist/src/core/furnace-constants.js +3 -2
- package/dist/src/core/furnace-dir-entry.d.ts +20 -0
- package/dist/src/core/furnace-dir-entry.js +21 -0
- package/dist/src/core/furnace-operation.d.ts +2 -0
- package/dist/src/core/furnace-operation.js +3 -1
- package/dist/src/core/furnace-refresh.d.ts +18 -6
- package/dist/src/core/furnace-refresh.js +3 -6
- package/dist/src/core/furnace-registration-ast.d.ts +0 -1
- package/dist/src/core/furnace-registration-ast.js +0 -3
- package/dist/src/core/furnace-registration.d.ts +2 -1
- package/dist/src/core/furnace-registration.js +22 -29
- package/dist/src/core/furnace-scanner.js +3 -6
- package/dist/src/core/furnace-state-persist.d.ts +2 -2
- package/dist/src/core/furnace-validate-registration.js +5 -7
- package/dist/src/core/git-base.d.ts +3 -1
- package/dist/src/core/git-base.js +25 -3
- package/dist/src/core/git-diff-new-file.d.ts +40 -0
- package/dist/src/core/git-diff-new-file.js +119 -0
- package/dist/src/core/git-diff.d.ts +9 -9
- package/dist/src/core/git-diff.js +88 -157
- package/dist/src/core/git-file-ops.d.ts +0 -7
- package/dist/src/core/git-file-ops.js +4 -28
- package/dist/src/core/git-readonly-index.d.ts +0 -2
- package/dist/src/core/git-readonly-index.js +0 -4
- package/dist/src/core/git-status.d.ts +7 -0
- package/dist/src/core/git-status.js +21 -9
- package/dist/src/core/git.d.ts +0 -6
- package/dist/src/core/git.js +14 -43
- package/dist/src/core/harness-orphans.d.ts +73 -0
- package/dist/src/core/harness-orphans.js +187 -0
- package/dist/src/core/history-log.d.ts +19 -0
- package/dist/src/core/history-log.js +29 -0
- package/dist/src/core/mach-error-hints.d.ts +0 -5
- package/dist/src/core/mach-error-hints.js +1 -1
- package/dist/src/core/mach-known-noise-filter.d.ts +25 -3
- package/dist/src/core/mach-known-noise-filter.js +31 -10
- package/dist/src/core/mach-mozconfig.js +2 -1
- package/dist/src/core/mach-python.d.ts +2 -0
- package/dist/src/core/mach-python.js +12 -7
- package/dist/src/core/mach-resource-shim.d.ts +13 -1
- package/dist/src/core/mach-resource-shim.js +112 -9
- package/dist/src/core/mach.d.ts +46 -53
- package/dist/src/core/mach.js +31 -83
- package/dist/src/core/marionette-port.d.ts +0 -17
- package/dist/src/core/marionette-port.js +12 -58
- package/dist/src/core/marionette-preflight.js +9 -27
- package/dist/src/core/mochitest-server-port.js +3 -3
- package/dist/src/core/moz-manifest-rules.js +37 -33
- package/dist/src/core/patch-apply-fuzz.js +4 -4
- package/dist/src/core/patch-apply.d.ts +4 -5
- package/dist/src/core/patch-apply.js +55 -32
- package/dist/src/core/patch-export-coverage.d.ts +0 -9
- package/dist/src/core/patch-export-coverage.js +1 -30
- package/dist/src/core/patch-export-update.d.ts +18 -1
- package/dist/src/core/patch-export-update.js +4 -3
- package/dist/src/core/patch-export.d.ts +11 -21
- package/dist/src/core/patch-export.js +44 -66
- package/dist/src/core/patch-files.d.ts +0 -4
- package/dist/src/core/patch-files.js +0 -11
- package/dist/src/core/patch-lint-binary.d.ts +6 -12
- package/dist/src/core/patch-lint-cache.d.ts +17 -1
- package/dist/src/core/patch-lint-cache.js +3 -6
- package/dist/src/core/patch-lint-checkjs.d.ts +33 -16
- package/dist/src/core/patch-lint-checkjs.js +43 -25
- package/dist/src/core/patch-lint-creators.d.ts +2 -6
- package/dist/src/core/patch-lint-cross.d.ts +16 -8
- package/dist/src/core/patch-lint-cross.js +49 -92
- package/dist/src/core/patch-lint-css.js +10 -6
- package/dist/src/core/patch-lint-file-size.d.ts +52 -0
- package/dist/src/core/patch-lint-file-size.js +53 -0
- package/dist/src/core/patch-lint-forward-registration.d.ts +58 -0
- package/dist/src/core/patch-lint-forward-registration.js +210 -0
- package/dist/src/core/patch-lint-jsdoc.js +36 -36
- package/dist/src/core/patch-lint-module-registration.d.ts +2 -8
- package/dist/src/core/patch-lint-prettier.d.ts +36 -0
- package/dist/src/core/patch-lint-prettier.js +126 -0
- package/dist/src/core/patch-lint-queue-types.d.ts +60 -0
- package/dist/src/core/patch-lint-queue-types.js +12 -0
- package/dist/src/core/patch-lint-staged-registration.d.ts +61 -0
- package/dist/src/core/patch-lint-staged-registration.js +90 -0
- package/dist/src/core/patch-lint-unmanaged-companion.d.ts +106 -0
- package/dist/src/core/patch-lint-unmanaged-companion.js +214 -0
- package/dist/src/core/patch-lint.d.ts +14 -9
- package/dist/src/core/patch-lint.js +27 -27
- package/dist/src/core/patch-lock.js +3 -3
- package/dist/src/core/patch-manifest-io.js +8 -7
- package/dist/src/core/patch-parse.d.ts +19 -8
- package/dist/src/core/patch-parse.js +25 -0
- package/dist/src/core/patch-policy.js +15 -27
- package/dist/src/core/patch-source-metadata.d.ts +1 -3
- package/dist/src/core/patch-source-metadata.js +0 -4
- package/dist/src/core/patch-transform.d.ts +21 -8
- package/dist/src/core/patch-transform.js +38 -10
- package/dist/src/core/process-cpu-time.js +1 -1
- package/dist/src/core/rebase-session.d.ts +2 -8
- package/dist/src/core/rebase-session.js +5 -17
- package/dist/src/core/register-browser-content.js +3 -2
- package/dist/src/core/register-browser-test.js +2 -1
- package/dist/src/core/register-module.js +2 -1
- package/dist/src/core/register-scaffold.js +5 -4
- package/dist/src/core/register-shared-css.js +2 -1
- package/dist/src/core/run-log-redact.d.ts +38 -0
- package/dist/src/core/run-log-redact.js +69 -0
- package/dist/src/core/run-log.d.ts +13 -2
- package/dist/src/core/run-log.js +67 -18
- package/dist/src/core/signal-critical.js +2 -4
- package/dist/src/core/smoke-patterns.d.ts +0 -1
- package/dist/src/core/smoke-patterns.js +18 -11
- package/dist/src/core/state-file.d.ts +12 -1
- package/dist/src/core/state-file.js +14 -1
- package/dist/src/core/status-classify.js +2 -1
- package/dist/src/core/test-changed-prefs.js +26 -11
- package/dist/src/core/test-harness-crash.js +61 -48
- package/dist/src/core/test-harness-verdict-notes.d.ts +55 -0
- package/dist/src/core/test-harness-verdict-notes.js +48 -0
- package/dist/src/core/test-stale-check.d.ts +23 -8
- package/dist/src/core/test-stale-check.js +77 -4
- package/dist/src/core/test-stall-triage.js +37 -19
- package/dist/src/core/test-xpcshell-retry.d.ts +26 -7
- package/dist/src/core/test-xpcshell-retry.js +14 -11
- package/dist/src/core/token-category.d.ts +33 -0
- package/dist/src/core/token-category.js +56 -48
- package/dist/src/core/token-dark-mode.js +2 -14
- package/dist/src/core/token-inventory.d.ts +56 -0
- package/dist/src/core/token-inventory.js +109 -0
- package/dist/src/core/token-manager.d.ts +1 -1
- package/dist/src/core/token-manager.js +1 -1
- package/dist/src/core/token-variant.js +21 -22
- package/dist/src/core/toolchain-preflight.js +1 -1
- package/dist/src/core/tree-cow.d.ts +0 -2
- package/dist/src/core/tree-cow.js +2 -2
- package/dist/src/core/tree-store.js +4 -5
- package/dist/src/core/typecheck.js +2 -2
- package/dist/src/core/wire-dom-fragment.js +6 -17
- package/dist/src/core/wire-utils.js +5 -17
- package/dist/src/core/xpcshell-appdir.js +2 -4
- package/dist/src/errors/base.d.ts +53 -1
- package/dist/src/errors/base.js +79 -11
- package/dist/src/errors/build.d.ts +28 -0
- package/dist/src/errors/build.js +51 -10
- package/dist/src/errors/config.d.ts +0 -14
- package/dist/src/errors/config.js +13 -34
- package/dist/src/errors/download.d.ts +13 -0
- package/dist/src/errors/download.js +53 -24
- package/dist/src/errors/furnace.js +8 -9
- package/dist/src/errors/git.d.ts +8 -8
- package/dist/src/errors/git.js +20 -30
- package/dist/src/errors/patch.js +8 -10
- package/dist/src/errors/rebase.js +7 -7
- package/dist/src/types/commands/options.d.ts +96 -123
- package/dist/src/types/commands/patches.d.ts +17 -6
- package/dist/src/types/config.d.ts +75 -2
- package/dist/src/types/index.d.ts +0 -1
- package/dist/src/utils/assert.d.ts +3 -15
- package/dist/src/utils/assert.js +1 -18
- package/dist/src/utils/build-info.d.ts +1 -1
- package/dist/src/utils/child-env.d.ts +2 -1
- package/dist/src/utils/elapsed.js +10 -1
- package/dist/src/utils/fs.d.ts +4 -2
- package/dist/src/utils/fs.js +11 -14
- package/dist/src/utils/hash.d.ts +12 -0
- package/dist/src/utils/hash.js +16 -0
- package/dist/src/utils/line-dispatch.d.ts +15 -0
- package/dist/src/utils/line-dispatch.js +48 -0
- package/dist/src/utils/options.d.ts +1 -7
- package/dist/src/utils/options.js +6 -7
- package/dist/src/utils/package-root.js +3 -12
- package/dist/src/utils/platform.d.ts +0 -4
- package/dist/src/utils/process-group.d.ts +2 -1
- package/dist/src/utils/process-group.js +20 -19
- package/dist/src/utils/process.d.ts +40 -26
- package/dist/src/utils/process.js +115 -166
- package/dist/src/utils/ps-duration.js +3 -3
- package/dist/src/utils/sleep.d.ts +26 -0
- package/dist/src/utils/sleep.js +31 -0
- package/dist/src/utils/validation.d.ts +2 -38
- package/dist/src/utils/validation.js +7 -16
- package/docs/configuration.md +136 -1
- package/docs/exit-codes.md +34 -20
- package/docs/lifecycle-invariants.md +18 -12
- package/docs/machine-output.md +31 -8
- package/docs/patch-workflow.md +2 -1
- package/docs/run-logs.md +44 -4
- package/docs/testing.md +70 -11
- package/package.json +8 -7
- package/dist/src/commands/rebase.d.ts +0 -4
- package/dist/src/commands/rebase.js +0 -5
- package/dist/src/core/patch-artifact-normalize.d.ts +0 -21
- package/dist/src/core/patch-artifact-normalize.js +0 -24
- package/dist/src/core/patch-lint-reexports.d.ts +0 -7
- package/dist/src/core/patch-lint-reexports.js +0 -8
- package/dist/src/core/wire-targets.d.ts +0 -7
- package/dist/src/core/wire-targets.js +0 -8
|
@@ -46,8 +46,8 @@ function findAttachedJsDoc(comments, declStart, source) {
|
|
|
46
46
|
* loses the param name. String literal types may contain braces too, so
|
|
47
47
|
* quoted runs are skipped verbatim.
|
|
48
48
|
*
|
|
49
|
-
* @returns Index just past the matching close brace, or
|
|
50
|
-
* expression never closes (malformed doc — caller skips the tag).
|
|
49
|
+
* @returns Index just past the matching close brace, or undefined when the
|
|
50
|
+
* type expression never closes (malformed doc — caller skips the tag).
|
|
51
51
|
*/
|
|
52
52
|
function skipBalancedTypeBraces(jsDoc, start) {
|
|
53
53
|
let depth = 0;
|
|
@@ -73,7 +73,7 @@ function skipBalancedTypeBraces(jsDoc, start) {
|
|
|
73
73
|
return i + 1;
|
|
74
74
|
}
|
|
75
75
|
}
|
|
76
|
-
return
|
|
76
|
+
return undefined;
|
|
77
77
|
}
|
|
78
78
|
function extractParamNames(jsDoc) {
|
|
79
79
|
const names = [];
|
|
@@ -87,7 +87,7 @@ function extractParamNames(jsDoc) {
|
|
|
87
87
|
// inline object types or Record<…> generics don't truncate the scan.
|
|
88
88
|
if (jsDoc[i] === '{') {
|
|
89
89
|
const afterType = skipBalancedTypeBraces(jsDoc, i);
|
|
90
|
-
if (afterType ===
|
|
90
|
+
if (afterType === undefined)
|
|
91
91
|
continue;
|
|
92
92
|
i = afterType;
|
|
93
93
|
while (i < jsDoc.length && /\s/.test(jsDoc[i] ?? ''))
|
|
@@ -124,6 +124,17 @@ function hasPrivateOrInternalTag(jsDoc) {
|
|
|
124
124
|
function functionReturnsValue(node) {
|
|
125
125
|
return walkForReturn(node.body);
|
|
126
126
|
}
|
|
127
|
+
/**
|
|
128
|
+
* Narrows an arbitrary child value reached by walking a node's own
|
|
129
|
+
* properties to an ESTree node. Acorn's AST holds nodes, arrays of nodes,
|
|
130
|
+
* and plain scalars in the same property positions, so the discriminating
|
|
131
|
+
* `type` string is the only structural signal available.
|
|
132
|
+
*/
|
|
133
|
+
function isEstreeNode(value) {
|
|
134
|
+
if (typeof value !== 'object' || value === null || !('type' in value))
|
|
135
|
+
return false;
|
|
136
|
+
return typeof value.type === 'string';
|
|
137
|
+
}
|
|
127
138
|
function walkForReturn(node) {
|
|
128
139
|
if (node.type === 'ReturnStatement') {
|
|
129
140
|
return node.argument != null;
|
|
@@ -139,20 +150,16 @@ function walkForReturn(node) {
|
|
|
139
150
|
for (const [key, val] of entries) {
|
|
140
151
|
if (key === 'type')
|
|
141
152
|
continue;
|
|
142
|
-
if (val
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
if (walkForReturn(child))
|
|
147
|
-
return true;
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
else if ('type' in val) {
|
|
152
|
-
if (walkForReturn(val))
|
|
153
|
+
if (Array.isArray(val)) {
|
|
154
|
+
const children = val;
|
|
155
|
+
for (const child of children) {
|
|
156
|
+
if (isEstreeNode(child) && walkForReturn(child))
|
|
153
157
|
return true;
|
|
154
158
|
}
|
|
155
159
|
}
|
|
160
|
+
else if (isEstreeNode(val) && walkForReturn(val)) {
|
|
161
|
+
return true;
|
|
162
|
+
}
|
|
156
163
|
}
|
|
157
164
|
return false;
|
|
158
165
|
}
|
|
@@ -183,12 +190,7 @@ function findLocalDeclaration(body, name) {
|
|
|
183
190
|
// Line number helpers
|
|
184
191
|
// ---------------------------------------------------------------------------
|
|
185
192
|
function lineAt(source, offset) {
|
|
186
|
-
|
|
187
|
-
for (let i = 0; i < offset && i < source.length; i++) {
|
|
188
|
-
if (source[i] === '\n')
|
|
189
|
-
line++;
|
|
190
|
-
}
|
|
191
|
-
return line;
|
|
193
|
+
return source.slice(0, offset).split('\n').length;
|
|
192
194
|
}
|
|
193
195
|
/**
|
|
194
196
|
* Validates @param name matching and @returns presence on a function-like
|
|
@@ -198,21 +200,19 @@ function lineAt(source, offset) {
|
|
|
198
200
|
*/
|
|
199
201
|
function validateParamsAndReturns(fnNode, jsDoc, issues, ctx) {
|
|
200
202
|
const docText = jsDoc.value;
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
});
|
|
215
|
-
}
|
|
203
|
+
const actualParams = fnNode.params
|
|
204
|
+
.map((p) => (p.type === 'Identifier' ? p.name : null))
|
|
205
|
+
.filter((n) => n !== null);
|
|
206
|
+
if (actualParams.length > 0) {
|
|
207
|
+
const docParams = extractParamNames(docText);
|
|
208
|
+
for (const param of actualParams) {
|
|
209
|
+
if (!docParams.includes(param)) {
|
|
210
|
+
issues.push({
|
|
211
|
+
line: ctx.line,
|
|
212
|
+
check: ctx.paramCheck,
|
|
213
|
+
message: `Exported ${ctx.label} at line ${ctx.line}: @param "${param}" is missing or misnamed in JSDoc.`,
|
|
214
|
+
...(ctx.severity ? { severity: ctx.severity } : {}),
|
|
215
|
+
});
|
|
216
216
|
}
|
|
217
217
|
}
|
|
218
218
|
}
|
|
@@ -1,12 +1,6 @@
|
|
|
1
1
|
import type { PatchLintIssue } from '../types/commands/index.js';
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
newFiles: ReadonlyMap<string, string>;
|
|
5
|
-
modifiedFileAdditions: ReadonlyMap<string, string>;
|
|
6
|
-
}
|
|
7
|
-
interface ModuleRegistrationQueueContext {
|
|
8
|
-
entries: readonly ModuleRegistrationQueueEntry[];
|
|
9
|
-
}
|
|
2
|
+
import type { PatchQueueRegistrationEntry, PatchQueueView } from './patch-lint-queue-types.js';
|
|
3
|
+
type ModuleRegistrationQueueContext = PatchQueueView<PatchQueueRegistrationEntry>;
|
|
10
4
|
/**
|
|
11
5
|
* Maps Firefox's common system-module resource URLs to their source
|
|
12
6
|
* suffix. Exported alongside {@link extractResourceModuleSpecifiers} so
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Optional Prettier pass over patch-owned `.sys.mjs` modules.
|
|
3
|
+
*
|
|
4
|
+
* Until 0.45.0 no tier of the chain ran Prettier on `.sys.mjs` at all, so
|
|
5
|
+
* module formatting drift was caught by nothing and survived to a human
|
|
6
|
+
* reviewer. Worse, the obvious manual check was misleading in the same
|
|
7
|
+
* direction: a fork's ROOT `.prettierignore` typically excludes `engine/`,
|
|
8
|
+
* so `prettier --check --config engine/.prettierrc.js <engine files>` run
|
|
9
|
+
* from the repo root reports "all files use Prettier code style" for files
|
|
10
|
+
* that fail the identical check run from inside `engine/`. A root-level
|
|
11
|
+
* spot-check falsely refuted a correct reviewer finding on exactly this.
|
|
12
|
+
*
|
|
13
|
+
* This pass therefore runs prettier with `cwd` set to the ENGINE directory,
|
|
14
|
+
* so the engine's own `.prettierrc*` and `.prettierignore` resolve the way
|
|
15
|
+
* they do for anyone working in that tree, and the FireForge result agrees
|
|
16
|
+
* with the operator's own command.
|
|
17
|
+
*
|
|
18
|
+
* Opt-in (`patchLint.prettier`, default `'off'`): it spawns a process per
|
|
19
|
+
* lint and is a new failure surface on queues that never had one. When it
|
|
20
|
+
* is off, formatting is explicitly out of scope for the per-patch tier —
|
|
21
|
+
* that is the contract, not an accident.
|
|
22
|
+
*/
|
|
23
|
+
import type { PatchLintIssue } from '../types/commands/index.js';
|
|
24
|
+
import type { PatchLintSeverityGate } from '../types/config.js';
|
|
25
|
+
/**
|
|
26
|
+
* Runs `prettier --check` over `files` from inside the engine directory.
|
|
27
|
+
*
|
|
28
|
+
* @param engineDir - Absolute engine directory; also the `cwd`, which is
|
|
29
|
+
* what makes the engine's own config and ignore file authoritative
|
|
30
|
+
* @param projectRoot - FireForge project root, for the fallback binary
|
|
31
|
+
* @param files - Engine-relative patch-owned `.sys.mjs` paths
|
|
32
|
+
* @param gate - Severity for reported issues; `'off'` skips the pass
|
|
33
|
+
* @returns One issue per unformatted file, or a single run-level issue when
|
|
34
|
+
* prettier could not be run at all
|
|
35
|
+
*/
|
|
36
|
+
export declare function invokePatchLintPrettier(engineDir: string, projectRoot: string, files: readonly string[], gate: PatchLintSeverityGate): Promise<PatchLintIssue[]>;
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
// SPDX-License-Identifier: EUPL-1.2
|
|
2
|
+
/**
|
|
3
|
+
* Optional Prettier pass over patch-owned `.sys.mjs` modules.
|
|
4
|
+
*
|
|
5
|
+
* Until 0.45.0 no tier of the chain ran Prettier on `.sys.mjs` at all, so
|
|
6
|
+
* module formatting drift was caught by nothing and survived to a human
|
|
7
|
+
* reviewer. Worse, the obvious manual check was misleading in the same
|
|
8
|
+
* direction: a fork's ROOT `.prettierignore` typically excludes `engine/`,
|
|
9
|
+
* so `prettier --check --config engine/.prettierrc.js <engine files>` run
|
|
10
|
+
* from the repo root reports "all files use Prettier code style" for files
|
|
11
|
+
* that fail the identical check run from inside `engine/`. A root-level
|
|
12
|
+
* spot-check falsely refuted a correct reviewer finding on exactly this.
|
|
13
|
+
*
|
|
14
|
+
* This pass therefore runs prettier with `cwd` set to the ENGINE directory,
|
|
15
|
+
* so the engine's own `.prettierrc*` and `.prettierignore` resolve the way
|
|
16
|
+
* they do for anyone working in that tree, and the FireForge result agrees
|
|
17
|
+
* with the operator's own command.
|
|
18
|
+
*
|
|
19
|
+
* Opt-in (`patchLint.prettier`, default `'off'`): it spawns a process per
|
|
20
|
+
* lint and is a new failure surface on queues that never had one. When it
|
|
21
|
+
* is off, formatting is explicitly out of scope for the per-patch tier —
|
|
22
|
+
* that is the contract, not an accident.
|
|
23
|
+
*/
|
|
24
|
+
import { join } from 'node:path';
|
|
25
|
+
import { toError } from '../utils/errors.js';
|
|
26
|
+
import { pathExists } from '../utils/fs.js';
|
|
27
|
+
import { verbose } from '../utils/logger.js';
|
|
28
|
+
import { exec } from '../utils/process.js';
|
|
29
|
+
/** How long prettier gets before the pass gives up (ms). */
|
|
30
|
+
const PRETTIER_TIMEOUT_MS = 120_000;
|
|
31
|
+
/** Prettier's per-file `--check` failure line. */
|
|
32
|
+
const PRETTIER_WARN_LINE = /^\[warn]\s+(.+)$/;
|
|
33
|
+
/** Summary lines prettier prints alongside the per-file ones. */
|
|
34
|
+
const PRETTIER_SUMMARY_LINE = /^\[warn]\s+(?:Code style issues|Forgot to run)/;
|
|
35
|
+
/**
|
|
36
|
+
* Finds prettier, preferring a binary installed in the tree being checked.
|
|
37
|
+
*
|
|
38
|
+
* Order matters: the engine's own `node_modules` is the install whose
|
|
39
|
+
* version matches the engine's config, the project's is the next best
|
|
40
|
+
* guess, and `npx` is the last resort (it can download, so it is never
|
|
41
|
+
* preferred over something already present).
|
|
42
|
+
*/
|
|
43
|
+
async function resolvePrettier(engineDir, projectRoot) {
|
|
44
|
+
for (const root of [engineDir, projectRoot]) {
|
|
45
|
+
const candidate = join(root, 'node_modules', '.bin', 'prettier');
|
|
46
|
+
if (await pathExists(candidate)) {
|
|
47
|
+
return { command: candidate, prefixArgs: [] };
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
return { command: 'npx', prefixArgs: ['--no-install', 'prettier'] };
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Runs `prettier --check` over `files` from inside the engine directory.
|
|
54
|
+
*
|
|
55
|
+
* @param engineDir - Absolute engine directory; also the `cwd`, which is
|
|
56
|
+
* what makes the engine's own config and ignore file authoritative
|
|
57
|
+
* @param projectRoot - FireForge project root, for the fallback binary
|
|
58
|
+
* @param files - Engine-relative patch-owned `.sys.mjs` paths
|
|
59
|
+
* @param gate - Severity for reported issues; `'off'` skips the pass
|
|
60
|
+
* @returns One issue per unformatted file, or a single run-level issue when
|
|
61
|
+
* prettier could not be run at all
|
|
62
|
+
*/
|
|
63
|
+
export async function invokePatchLintPrettier(engineDir, projectRoot, files, gate) {
|
|
64
|
+
if (gate === 'off' || files.length === 0)
|
|
65
|
+
return [];
|
|
66
|
+
const severity = gate === 'error' ? 'error' : 'warning';
|
|
67
|
+
const invocation = await resolvePrettier(engineDir, projectRoot);
|
|
68
|
+
let result;
|
|
69
|
+
try {
|
|
70
|
+
result = await exec(invocation.command, [...invocation.prefixArgs, '--check', ...files], {
|
|
71
|
+
cwd: engineDir,
|
|
72
|
+
timeout: PRETTIER_TIMEOUT_MS,
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
catch (error) {
|
|
76
|
+
return [
|
|
77
|
+
{
|
|
78
|
+
file: '(prettier)',
|
|
79
|
+
check: 'prettier-format',
|
|
80
|
+
message: `patchLint.prettier is enabled but prettier could not be run (${toError(error).message}). ` +
|
|
81
|
+
'Install prettier in engine/ or the project root, or set "patchLint.prettier": "off".',
|
|
82
|
+
severity,
|
|
83
|
+
},
|
|
84
|
+
];
|
|
85
|
+
}
|
|
86
|
+
// Exit 0: everything formatted. Exit 1: at least one file differs. Any
|
|
87
|
+
// other code is prettier failing (bad config, unparseable file), which is
|
|
88
|
+
// a different finding and must not be reported as formatting drift.
|
|
89
|
+
if (result.exitCode === 0)
|
|
90
|
+
return [];
|
|
91
|
+
const output = `${result.stderr}\n${result.stdout}`;
|
|
92
|
+
if (result.exitCode !== 1) {
|
|
93
|
+
return [
|
|
94
|
+
{
|
|
95
|
+
file: '(prettier)',
|
|
96
|
+
check: 'prettier-format',
|
|
97
|
+
message: `prettier exited ${result.exitCode} without completing the check: ` +
|
|
98
|
+
output.trim().split('\n').slice(-5).join(' ').slice(0, 400),
|
|
99
|
+
severity,
|
|
100
|
+
},
|
|
101
|
+
];
|
|
102
|
+
}
|
|
103
|
+
const unformatted = new Set();
|
|
104
|
+
for (const line of output.split(/\r?\n/)) {
|
|
105
|
+
const trimmed = line.trim();
|
|
106
|
+
if (PRETTIER_SUMMARY_LINE.test(trimmed))
|
|
107
|
+
continue;
|
|
108
|
+
const match = PRETTIER_WARN_LINE.exec(trimmed);
|
|
109
|
+
const file = match?.[1]?.trim();
|
|
110
|
+
if (file !== undefined && file.length > 0)
|
|
111
|
+
unformatted.add(file);
|
|
112
|
+
}
|
|
113
|
+
if (unformatted.size === 0) {
|
|
114
|
+
verbose('patchLint.prettier: prettier exited 1 but named no file; reporting nothing.');
|
|
115
|
+
return [];
|
|
116
|
+
}
|
|
117
|
+
return [...unformatted].sort().map((file) => ({
|
|
118
|
+
file,
|
|
119
|
+
check: 'prettier-format',
|
|
120
|
+
message: `Not formatted per the project's Prettier configuration. Checked from inside engine/, ` +
|
|
121
|
+
`so engine/.prettierrc* and engine/.prettierignore apply — the same command run from the ` +
|
|
122
|
+
`repo root can report a false pass when the root .prettierignore excludes engine/. ` +
|
|
123
|
+
`Fix with "prettier --write ${file}" run from engine/.`,
|
|
124
|
+
severity,
|
|
125
|
+
}));
|
|
126
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Structural views of the cross-patch lint queue context.
|
|
3
|
+
*
|
|
4
|
+
* A leaf module by design: it imports nothing, so the individual rule
|
|
5
|
+
* modules can describe the slice of `PatchQueueContext` they read without
|
|
6
|
+
* importing `patch-lint-cross.ts` (which imports them back). Previously each
|
|
7
|
+
* rule re-declared its own private `{ entries }` interface; sharing them here
|
|
8
|
+
* keeps the dependency edge one-way and `dpdm` clean while stating the shape
|
|
9
|
+
* once.
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* The slice of a queue entry consumed by rules that read raw patch bodies
|
|
13
|
+
* (the new-file creators map, the binary-body check).
|
|
14
|
+
*/
|
|
15
|
+
export interface PatchQueueBodyEntry {
|
|
16
|
+
/** Filename on disk and in the manifest. */
|
|
17
|
+
filename: string;
|
|
18
|
+
/** Raw unified-diff content of the patch body. */
|
|
19
|
+
diff: string;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* The slice of a queue entry consumed by the module-registration rule: the
|
|
23
|
+
* per-path content maps rather than the raw diff.
|
|
24
|
+
*/
|
|
25
|
+
export interface PatchQueueRegistrationEntry {
|
|
26
|
+
/** Filename on disk and in the manifest. */
|
|
27
|
+
filename: string;
|
|
28
|
+
/** Newly-created file path → the content the patch would produce. */
|
|
29
|
+
newFiles: ReadonlyMap<string, string>;
|
|
30
|
+
/** Existing file path → the lines the patch adds to it. */
|
|
31
|
+
modifiedFileAdditions: ReadonlyMap<string, string>;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Structural queue view: the `entries` field of a `PatchQueueContext`,
|
|
35
|
+
* narrowed to whichever entry slice a rule needs.
|
|
36
|
+
*/
|
|
37
|
+
export interface PatchQueueView<TEntry> {
|
|
38
|
+
/** Entries in application order (lowest `order` first). */
|
|
39
|
+
entries: readonly TEntry[];
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* The slice consumed by the forward-registration rule: the same content maps
|
|
43
|
+
* the module-registration rule reads, plus the body-kind-agnostic creation
|
|
44
|
+
* set and the ordering/metadata needed to decide "later" and "declared".
|
|
45
|
+
*/
|
|
46
|
+
export interface PatchQueueForwardRegistrationEntry extends PatchQueueRegistrationEntry {
|
|
47
|
+
/** Order number from the manifest (or filename prefix fallback). */
|
|
48
|
+
order: number;
|
|
49
|
+
/** Every path this patch creates, whatever the body kind. */
|
|
50
|
+
createdFiles: ReadonlySet<string>;
|
|
51
|
+
/** Manifest metadata. Null when the patch file exists but has no entry. */
|
|
52
|
+
metadata: {
|
|
53
|
+
stagedDependencies?: {
|
|
54
|
+
registrations?: readonly {
|
|
55
|
+
file: string;
|
|
56
|
+
creates: string;
|
|
57
|
+
}[];
|
|
58
|
+
};
|
|
59
|
+
} | null;
|
|
60
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
// SPDX-License-Identifier: EUPL-1.2
|
|
2
|
+
/**
|
|
3
|
+
* Structural views of the cross-patch lint queue context.
|
|
4
|
+
*
|
|
5
|
+
* A leaf module by design: it imports nothing, so the individual rule
|
|
6
|
+
* modules can describe the slice of `PatchQueueContext` they read without
|
|
7
|
+
* importing `patch-lint-cross.ts` (which imports them back). Previously each
|
|
8
|
+
* rule re-declared its own private `{ entries }` interface; sharing them here
|
|
9
|
+
* keeps the dependency edge one-way and `dpdm` clean while stating the shape
|
|
10
|
+
* once.
|
|
11
|
+
*/
|
|
12
|
+
export {};
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import type { PatchStagedRegistration } from '../types/commands/index.js';
|
|
2
|
+
/** A patch that creates a given path, with its position in the queue. */
|
|
3
|
+
export interface NewFileOwner {
|
|
4
|
+
filename: string;
|
|
5
|
+
order: number;
|
|
6
|
+
fullPath: string;
|
|
7
|
+
}
|
|
8
|
+
/** The ordering fields `isLaterOwner` compares an owner against. */
|
|
9
|
+
export interface QueuePosition {
|
|
10
|
+
filename: string;
|
|
11
|
+
order: number;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Later-in-apply-order predicate shared by the forward-import scan, the
|
|
15
|
+
* forward-registration rule and the registration validation: strictly
|
|
16
|
+
* higher ordinal, or same ordinal with a lexicographically later filename
|
|
17
|
+
* (the apply loop's tiebreak).
|
|
18
|
+
*
|
|
19
|
+
* @param owner - The creating patch
|
|
20
|
+
* @param entry - The referencing patch
|
|
21
|
+
* @returns True when `owner` applies after `entry`
|
|
22
|
+
*/
|
|
23
|
+
export declare function isLaterOwner(owner: QueuePosition, entry: QueuePosition): boolean;
|
|
24
|
+
/** The slice of a queue entry the registration validation reads. */
|
|
25
|
+
export interface StagedRegistrationEntry extends QueuePosition {
|
|
26
|
+
newFiles: ReadonlyMap<string, string>;
|
|
27
|
+
modifiedFileAdditions: ReadonlyMap<string, string>;
|
|
28
|
+
}
|
|
29
|
+
/** Why a staged registration declaration failed validation. */
|
|
30
|
+
export type StagedRegistrationFailure = {
|
|
31
|
+
kind: 'line-absent';
|
|
32
|
+
} | {
|
|
33
|
+
kind: 'creates-unresolved';
|
|
34
|
+
} | {
|
|
35
|
+
kind: 'owner-mismatch';
|
|
36
|
+
creators: readonly NewFileOwner[];
|
|
37
|
+
};
|
|
38
|
+
/**
|
|
39
|
+
* Validates one registration-kind declaration against the patch content
|
|
40
|
+
* and the queue, mirroring {@link findMatchingStagedDependency}: the
|
|
41
|
+
* declared line must be added by this patch, `creates` must exactly match
|
|
42
|
+
* a file a LATER-ordered patch creates (an earlier-only creator means the
|
|
43
|
+
* dependency is already satisfied and the declaration is stale), and
|
|
44
|
+
* `owner`, when set, must name one of those creating patches. Returns
|
|
45
|
+
* undefined when valid.
|
|
46
|
+
*/
|
|
47
|
+
export declare function findStagedRegistrationFailure(entry: StagedRegistrationEntry, registration: PatchStagedRegistration, createdFileIndex: Map<string, NewFileOwner[]>): StagedRegistrationFailure | undefined;
|
|
48
|
+
/** Message tail for each {@link StagedRegistrationFailure} shape. */
|
|
49
|
+
export declare function describeRegistrationFailure(failure: StagedRegistrationFailure): string;
|
|
50
|
+
/**
|
|
51
|
+
* Renders `line` for the `--line "…"` argument of a paste-and-run
|
|
52
|
+
* `patch staged-dependency` command.
|
|
53
|
+
*
|
|
54
|
+
* A registration line is quoted for the shell in the messages that print
|
|
55
|
+
* the command, and a `support-files` element carries its own quotes
|
|
56
|
+
* (`"file_tiles_find.html",` is what a multi-line TOML array adds). Without
|
|
57
|
+
* escaping, the shell would eat them and the declaration would be written
|
|
58
|
+
* with a line the patch never adds — the exact mismatch that made the
|
|
59
|
+
* forward-registration remedy leave the declaring patch red.
|
|
60
|
+
*/
|
|
61
|
+
export declare function quoteRegistrationLine(line: string): string;
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
// SPDX-License-Identifier: EUPL-1.2
|
|
2
|
+
/**
|
|
3
|
+
* Validation of `--kind registration` staged-dependency declarations.
|
|
4
|
+
*
|
|
5
|
+
* Split out of `patch-lint-cross.ts` to keep that file inside the per-file
|
|
6
|
+
* line budget, and because the forward-registration rule needs the same
|
|
7
|
+
* apply-order predicate: two spellings of "later in the queue" would let the
|
|
8
|
+
* rule that FLAGS an undeclared registration and the rule that validates a
|
|
9
|
+
* DECLARED one disagree about the very same pair of patches.
|
|
10
|
+
*
|
|
11
|
+
* Exports helpers consumed by `patch-lint-cross.ts` and
|
|
12
|
+
* `patch-lint-forward-registration.ts`; no registrar, no rule of its own.
|
|
13
|
+
*/
|
|
14
|
+
import { basename } from 'node:path';
|
|
15
|
+
/**
|
|
16
|
+
* Later-in-apply-order predicate shared by the forward-import scan, the
|
|
17
|
+
* forward-registration rule and the registration validation: strictly
|
|
18
|
+
* higher ordinal, or same ordinal with a lexicographically later filename
|
|
19
|
+
* (the apply loop's tiebreak).
|
|
20
|
+
*
|
|
21
|
+
* @param owner - The creating patch
|
|
22
|
+
* @param entry - The referencing patch
|
|
23
|
+
* @returns True when `owner` applies after `entry`
|
|
24
|
+
*/
|
|
25
|
+
export function isLaterOwner(owner, entry) {
|
|
26
|
+
return (owner.order > entry.order || (owner.order === entry.order && owner.filename > entry.filename));
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Validates one registration-kind declaration against the patch content
|
|
30
|
+
* and the queue, mirroring {@link findMatchingStagedDependency}: the
|
|
31
|
+
* declared line must be added by this patch, `creates` must exactly match
|
|
32
|
+
* a file a LATER-ordered patch creates (an earlier-only creator means the
|
|
33
|
+
* dependency is already satisfied and the declaration is stale), and
|
|
34
|
+
* `owner`, when set, must name one of those creating patches. Returns
|
|
35
|
+
* undefined when valid.
|
|
36
|
+
*/
|
|
37
|
+
export function findStagedRegistrationFailure(entry, registration, createdFileIndex) {
|
|
38
|
+
if (!isRegistrationLinePresent(entry, registration))
|
|
39
|
+
return { kind: 'line-absent' };
|
|
40
|
+
const creators = (createdFileIndex.get(basename(registration.creates)) ?? []).filter((owner) => owner.fullPath === registration.creates && isLaterOwner(owner, entry));
|
|
41
|
+
if (creators.length === 0)
|
|
42
|
+
return { kind: 'creates-unresolved' };
|
|
43
|
+
if (registration.owner !== undefined &&
|
|
44
|
+
!creators.some((owner) => owner.filename === registration.owner)) {
|
|
45
|
+
return { kind: 'owner-mismatch', creators };
|
|
46
|
+
}
|
|
47
|
+
return undefined;
|
|
48
|
+
}
|
|
49
|
+
/** Message tail for each {@link StagedRegistrationFailure} shape. */
|
|
50
|
+
export function describeRegistrationFailure(failure) {
|
|
51
|
+
switch (failure.kind) {
|
|
52
|
+
case 'line-absent':
|
|
53
|
+
return 'the patch does not add that line.';
|
|
54
|
+
case 'creates-unresolved':
|
|
55
|
+
return ('no later-ordered patch creates that file — the declaration is stale, ' +
|
|
56
|
+
'or the queue order no longer stages it.');
|
|
57
|
+
case 'owner-mismatch':
|
|
58
|
+
return `that file is created by ${failure.creators.map((o) => o.filename).join(', ')}, not the declared owner.`;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* True when the declared registration/packaging line appears (trimmed)
|
|
63
|
+
* among the lines the patch introduces in the declaring file — either as a
|
|
64
|
+
* newly-created file's content or as added lines to an existing file
|
|
65
|
+
* (where jar.mn / customElements.js / actor-registration edits land).
|
|
66
|
+
*/
|
|
67
|
+
function isRegistrationLinePresent(entry, registration) {
|
|
68
|
+
const declared = registration.line.trim();
|
|
69
|
+
if (declared.length === 0)
|
|
70
|
+
return false;
|
|
71
|
+
const introduced = [
|
|
72
|
+
entry.newFiles.get(registration.file),
|
|
73
|
+
entry.modifiedFileAdditions.get(registration.file),
|
|
74
|
+
];
|
|
75
|
+
return introduced.some((content) => content !== undefined && content.split('\n').some((line) => line.trim() === declared));
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Renders `line` for the `--line "…"` argument of a paste-and-run
|
|
79
|
+
* `patch staged-dependency` command.
|
|
80
|
+
*
|
|
81
|
+
* A registration line is quoted for the shell in the messages that print
|
|
82
|
+
* the command, and a `support-files` element carries its own quotes
|
|
83
|
+
* (`"file_tiles_find.html",` is what a multi-line TOML array adds). Without
|
|
84
|
+
* escaping, the shell would eat them and the declaration would be written
|
|
85
|
+
* with a line the patch never adds — the exact mismatch that made the
|
|
86
|
+
* forward-registration remedy leave the declaring patch red.
|
|
87
|
+
*/
|
|
88
|
+
export function quoteRegistrationLine(line) {
|
|
89
|
+
return line.replace(/\\/g, '\\\\').replace(/"/g, '\\"');
|
|
90
|
+
}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Recognizes the one shape where the undefined-identifier hint sends the
|
|
3
|
+
* operator at the wrong remedy — and where taking that remedy would MASK a
|
|
4
|
+
* real bug.
|
|
5
|
+
*
|
|
6
|
+
* The shape: helpers are hoisted out of duplicated test files into a new
|
|
7
|
+
* `head_settings.js` that a managed `head.js` pulls in with
|
|
8
|
+
* `loadSubScript`. Until that companion is exported it belongs to no patch,
|
|
9
|
+
* so the per-patch checkJs program — which only ever loads patch-owned
|
|
10
|
+
* roots — cannot see any of its declarations. Every use of every hoisted
|
|
11
|
+
* helper is then reported as `Cannot find name`, and the generic hint
|
|
12
|
+
* offers three remedies of which the shim is the easiest: adding the
|
|
13
|
+
* globals to `extraShim` makes all of the warnings disappear AND makes a
|
|
14
|
+
* genuinely missing helper undetectable forever after.
|
|
15
|
+
*
|
|
16
|
+
* The warnings themselves are correct — the per-patch program's honest view
|
|
17
|
+
* of a file that is in no patch. Only the advice is wrong. FireForge
|
|
18
|
+
* already knows ownership, so when every undefined name in a file is
|
|
19
|
+
* declared at the top level of an UNMANAGED file that a managed head loads,
|
|
20
|
+
* it can name that file and the adoption command instead.
|
|
21
|
+
*
|
|
22
|
+
* Detection is deliberately conservative on both halves: a companion must
|
|
23
|
+
* be reachable from an actual `loadSubScript` call, and EVERY undefined
|
|
24
|
+
* name must resolve inside it. One unresolved name means the file may
|
|
25
|
+
* genuinely be missing a helper, and the generic hint stays.
|
|
26
|
+
*/
|
|
27
|
+
import type { PatchLintIssue } from '../types/commands/index.js';
|
|
28
|
+
/**
|
|
29
|
+
* String literals passed anywhere inside a `loadSubScript(...)` call.
|
|
30
|
+
*
|
|
31
|
+
* The mochitest idiom is
|
|
32
|
+
* `Services.scriptloader.loadSubScript(getRootDirectory(gTestPath) + "head_settings.js", this)`,
|
|
33
|
+
* so the useful signal is the `.js` literal inside the call, not a
|
|
34
|
+
* resolvable URL — the path half is computed at runtime.
|
|
35
|
+
*/
|
|
36
|
+
export declare function findLoadSubScriptTargets(source: string): string[];
|
|
37
|
+
/**
|
|
38
|
+
* Top-level declaration names in a script-scope file.
|
|
39
|
+
*
|
|
40
|
+
* Regex rather than a TS program on purpose: this runs only to decide the
|
|
41
|
+
* WORDING of a hint, the file is by definition outside every program the
|
|
42
|
+
* pass built, and a missed declaration degrades to the generic hint rather
|
|
43
|
+
* than to a wrong answer. Matching is anchored at column zero so a nested
|
|
44
|
+
* declaration inside a function body is not mistaken for a global.
|
|
45
|
+
*/
|
|
46
|
+
export declare function collectTopLevelDeclarations(source: string): Set<string>;
|
|
47
|
+
/** An unmanaged companion a managed head loads, plus what it declares. */
|
|
48
|
+
export interface UnmanagedCompanion {
|
|
49
|
+
/** Repo-relative path of the companion. */
|
|
50
|
+
file: string;
|
|
51
|
+
/** Repo-relative path of the managed head that loads it. */
|
|
52
|
+
loadedBy: string;
|
|
53
|
+
/** Top-level names the companion declares. */
|
|
54
|
+
declarations: Set<string>;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Resolves the unmanaged companions reachable from a set of managed head
|
|
58
|
+
* files, given a reader for repo-relative file content.
|
|
59
|
+
*
|
|
60
|
+
* A candidate qualifies only when it is NOT in `ownedFiles` and its content
|
|
61
|
+
* can be read — an unreadable or absent target is simply not a companion,
|
|
62
|
+
* and the generic hint applies.
|
|
63
|
+
*
|
|
64
|
+
* @param heads - Repo-relative managed head files, with their sources
|
|
65
|
+
* @param ownedFiles - Every patch-owned repo-relative path
|
|
66
|
+
* @param readFile - Reads a repo-relative file, or returns undefined
|
|
67
|
+
*/
|
|
68
|
+
export declare function resolveUnmanagedCompanions(heads: ReadonlyArray<{
|
|
69
|
+
file: string;
|
|
70
|
+
source: string;
|
|
71
|
+
}>, ownedFiles: ReadonlySet<string>, readFile: (repoRelative: string) => Promise<string | undefined>): Promise<UnmanagedCompanion[]>;
|
|
72
|
+
/**
|
|
73
|
+
* The replacement hint, when every undefined name resolves in one
|
|
74
|
+
* unmanaged companion.
|
|
75
|
+
*
|
|
76
|
+
* States the ownership fact first (that is the diagnosis), then the
|
|
77
|
+
* adoption command, and explicitly rules the shim OUT — the shim is what an
|
|
78
|
+
* operator reaches for by default here, and it is the one remedy that
|
|
79
|
+
* permanently hides a genuinely missing helper.
|
|
80
|
+
*/
|
|
81
|
+
export declare function formatUnmanagedCompanionHint(companion: UnmanagedCompanion): string;
|
|
82
|
+
/**
|
|
83
|
+
* Picks the companion that explains EVERY undefined identifier in
|
|
84
|
+
* `messages`, or undefined when none does.
|
|
85
|
+
*
|
|
86
|
+
* @param messages - Diagnostic messages reported for one file
|
|
87
|
+
* @param companions - Candidates from {@link resolveUnmanagedCompanions}
|
|
88
|
+
*/
|
|
89
|
+
export declare function explainUndefinedIdentifiers(messages: readonly string[], companions: readonly UnmanagedCompanion[]): UnmanagedCompanion | undefined;
|
|
90
|
+
/**
|
|
91
|
+
* Reads the head files in the owned test set and resolves the UNMANAGED
|
|
92
|
+
* companions they pull in with `loadSubScript`. Hoisting shared helpers
|
|
93
|
+
* into such a companion leaves it unowned until export, and every use of
|
|
94
|
+
* every helper then reports `Cannot find name` from an honest per-patch
|
|
95
|
+
* program — see `patch-lint-unmanaged-companion.ts` for why the generic
|
|
96
|
+
* hint is actively harmful there.
|
|
97
|
+
*
|
|
98
|
+
* Best-effort: an unreadable head simply contributes no companions.
|
|
99
|
+
*/
|
|
100
|
+
export declare function collectUnmanagedCompanions(repoDir: string, files: readonly string[], ownedFiles: ReadonlySet<string>): Promise<UnmanagedCompanion[]>;
|
|
101
|
+
/**
|
|
102
|
+
* Swaps the generic undefined-identifier hint for the ownership hint when
|
|
103
|
+
* one unmanaged companion explains EVERY undefined name in the file. Any
|
|
104
|
+
* other issue in the list is returned untouched.
|
|
105
|
+
*/
|
|
106
|
+
export declare function retargetUnmanagedCompanionHints(issues: readonly PatchLintIssue[], companions: readonly UnmanagedCompanion[]): PatchLintIssue[];
|