@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
|
@@ -8,6 +8,7 @@ import { findAllPatchesForFilesWithDetails, } from './patch-export-coverage.js';
|
|
|
8
8
|
import { addPatchToManifest, loadPatchesManifestForWrite, PATCHES_MANIFEST, savePatchesManifest, } from './patch-manifest.js';
|
|
9
9
|
import { formatPatchOrder, requirePatchOrder } from './patch-parse.js';
|
|
10
10
|
import { allocatePolicyOrder, enforcePatchPolicy } from './patch-policy.js';
|
|
11
|
+
import { manifestWithRetiredSlots } from './patch-retired.js';
|
|
11
12
|
export { findAllPatchesForFiles, findAllPatchesForFilesWithDetails, } from './patch-export-coverage.js';
|
|
12
13
|
import { escapeRegex } from '../utils/regex.js';
|
|
13
14
|
export { mutatePatchMetadata, updatePatchMetadata } from './patch-export-metadata.js';
|
|
@@ -273,10 +274,8 @@ async function computeExportPlanUnderLock(input) {
|
|
|
273
274
|
supersededDetails,
|
|
274
275
|
supersededPatches,
|
|
275
276
|
manifestBefore: manifestBefore ?? null,
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
patches: afterPatches,
|
|
279
|
-
},
|
|
277
|
+
// A patch landing on a retired order fills that slot.
|
|
278
|
+
manifestAfter: manifestWithRetiredSlots(manifestBefore, afterPatches),
|
|
280
279
|
};
|
|
281
280
|
}
|
|
282
281
|
/**
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Explains an implicit-`any` checkJs finding that comes from a URL import
|
|
3
|
+
* the per-patch program cannot resolve.
|
|
4
|
+
*
|
|
5
|
+
* The program only holds patch-owned files (and, for a test, its own
|
|
6
|
+
* directory's head.js), so a `resource:///` or `chrome://` import of a
|
|
7
|
+
* module another patch creates falls back to the shim's
|
|
8
|
+
* `declare module 'resource:*'` wildcard and types as `any`. A callback
|
|
9
|
+
* over its values then has implicitly-`any` parameters under
|
|
10
|
+
* `checkJsStrict`, while the whole-tree `fireforge typecheck`, which sees
|
|
11
|
+
* the module, is clean. Without the note the two disagree with no
|
|
12
|
+
* explanation. Split out of patch-lint-checkjs.ts for the line budget.
|
|
13
|
+
*/
|
|
14
|
+
/** Unresolved URL import specifiers, keyed by the importing file's TS path. */
|
|
15
|
+
export type AnyTypedImports = Map<string, Set<string>>;
|
|
16
|
+
/**
|
|
17
|
+
* The note an implicit-`any` finding carries when its file imports a
|
|
18
|
+
* `resource://`/`chrome://` module this checkJs program could not resolve.
|
|
19
|
+
* Such an import types as `any` (the shim's wildcard module), so a
|
|
20
|
+
* callback over its values has implicitly-`any` parameters here while the
|
|
21
|
+
* whole-tree `fireforge typecheck`, which sees the module, is clean.
|
|
22
|
+
*/
|
|
23
|
+
export declare function anyTypedImportHint(code: number, specifiers: ReadonlySet<string> | undefined): string;
|
|
24
|
+
/**
|
|
25
|
+
* The host's `resolveModuleNameLiterals`: owned specifiers first, then a
|
|
26
|
+
* reviewed `paths` mapping, recording every URL import that resolves to
|
|
27
|
+
* neither.
|
|
28
|
+
*
|
|
29
|
+
* @param resolveOwned - Patch-owned specifier resolver
|
|
30
|
+
* @param resolveViaPaths - Optional `paths` resolver
|
|
31
|
+
* @param into - Map that collects the unresolved URL imports
|
|
32
|
+
*/
|
|
33
|
+
export declare function createModuleLiteralResolver<Resolved>(resolveOwned: (specifier: string) => Resolved | undefined, resolveViaPaths: ((specifier: string) => Resolved | undefined) | undefined, into: AnyTypedImports): (moduleLiterals: readonly {
|
|
34
|
+
text: string;
|
|
35
|
+
}[], containingFile: string) => Array<{
|
|
36
|
+
resolvedModule: Resolved | undefined;
|
|
37
|
+
}>;
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
// SPDX-License-Identifier: EUPL-1.2
|
|
2
|
+
/**
|
|
3
|
+
* Explains an implicit-`any` checkJs finding that comes from a URL import
|
|
4
|
+
* the per-patch program cannot resolve.
|
|
5
|
+
*
|
|
6
|
+
* The program only holds patch-owned files (and, for a test, its own
|
|
7
|
+
* directory's head.js), so a `resource:///` or `chrome://` import of a
|
|
8
|
+
* module another patch creates falls back to the shim's
|
|
9
|
+
* `declare module 'resource:*'` wildcard and types as `any`. A callback
|
|
10
|
+
* over its values then has implicitly-`any` parameters under
|
|
11
|
+
* `checkJsStrict`, while the whole-tree `fireforge typecheck`, which sees
|
|
12
|
+
* the module, is clean. Without the note the two disagree with no
|
|
13
|
+
* explanation. Split out of patch-lint-checkjs.ts for the line budget.
|
|
14
|
+
*/
|
|
15
|
+
/** TypeScript's implicit-`any` diagnostic codes (noImplicitAny). */
|
|
16
|
+
const IMPLICIT_ANY_CODES = new Set([
|
|
17
|
+
7005, 7006, 7008, 7010, 7011, 7019, 7031, 7034,
|
|
18
|
+
]);
|
|
19
|
+
function recordAnyTypedImport(into, containingFile, specifier) {
|
|
20
|
+
if (!/^(?:resource|chrome):/.test(specifier))
|
|
21
|
+
return;
|
|
22
|
+
const list = into.get(containingFile) ?? new Set();
|
|
23
|
+
list.add(specifier);
|
|
24
|
+
into.set(containingFile, list);
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* The note an implicit-`any` finding carries when its file imports a
|
|
28
|
+
* `resource://`/`chrome://` module this checkJs program could not resolve.
|
|
29
|
+
* Such an import types as `any` (the shim's wildcard module), so a
|
|
30
|
+
* callback over its values has implicitly-`any` parameters here while the
|
|
31
|
+
* whole-tree `fireforge typecheck`, which sees the module, is clean.
|
|
32
|
+
*/
|
|
33
|
+
export function anyTypedImportHint(code, specifiers) {
|
|
34
|
+
if (!IMPLICIT_ANY_CODES.has(code) || specifiers === undefined || specifiers.size === 0)
|
|
35
|
+
return '';
|
|
36
|
+
const list = [...specifiers].sort().join(', ');
|
|
37
|
+
return (` (This file imports ${list}, which this per-patch checkJs program cannot resolve — ` +
|
|
38
|
+
'the module is created by another patch outside this program, a later one or one this ' +
|
|
39
|
+
'test does not share a directory with — so the import is typed `any`. Annotate the ' +
|
|
40
|
+
'parameter explicitly; the whole-tree "fireforge typecheck" resolves the real type.)');
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* The host's `resolveModuleNameLiterals`: owned specifiers first, then a
|
|
44
|
+
* reviewed `paths` mapping, recording every URL import that resolves to
|
|
45
|
+
* neither.
|
|
46
|
+
*
|
|
47
|
+
* @param resolveOwned - Patch-owned specifier resolver
|
|
48
|
+
* @param resolveViaPaths - Optional `paths` resolver
|
|
49
|
+
* @param into - Map that collects the unresolved URL imports
|
|
50
|
+
*/
|
|
51
|
+
export function createModuleLiteralResolver(resolveOwned, resolveViaPaths, into) {
|
|
52
|
+
return (moduleLiterals, containingFile) => moduleLiterals.map((literal) => {
|
|
53
|
+
const owned = resolveOwned(literal.text);
|
|
54
|
+
if (owned)
|
|
55
|
+
return { resolvedModule: owned };
|
|
56
|
+
const viaPaths = resolveViaPaths?.(literal.text);
|
|
57
|
+
if (viaPaths === undefined)
|
|
58
|
+
recordAnyTypedImport(into, containingFile, literal.text);
|
|
59
|
+
return { resolvedModule: viaPaths };
|
|
60
|
+
});
|
|
61
|
+
}
|
|
@@ -31,6 +31,7 @@ import { pathExists } from '../utils/fs.js';
|
|
|
31
31
|
import { verbose } from '../utils/logger.js';
|
|
32
32
|
import { normalizePathSlashes } from '../utils/paths.js';
|
|
33
33
|
import { withGeckoDomTypes } from './gecko-dom-types.js';
|
|
34
|
+
import { anyTypedImportHint, createModuleLiteralResolver, } from './patch-lint-checkjs-any-import.js';
|
|
34
35
|
import { withSharedSourceFiles } from './patch-lint-checkjs-cache.js';
|
|
35
36
|
import { collectUnmanagedCompanions, retargetUnmanagedCompanionHints, } from './patch-lint-unmanaged-companion.js';
|
|
36
37
|
import { composeShimSource, SHIM_FILENAME, SUPPRESSED_DIAGNOSTIC_CODES, TEST_HARNESS_SHIM, UNDEFINED_IDENTIFIER_CODES, UNDEFINED_IDENTIFIER_HINT, } from './typecheck-shim.js';
|
|
@@ -293,6 +294,9 @@ export async function runCheckJsGrouped(input) {
|
|
|
293
294
|
...overrides,
|
|
294
295
|
};
|
|
295
296
|
const resolveOwnedSpecifier = createOwnedSpecifierResolver(ts, ownedAbsolute);
|
|
297
|
+
// URL imports this program cannot resolve, per importing file (see
|
|
298
|
+
// patch-lint-checkjs-any-import.ts).
|
|
299
|
+
const anyTypedImports = new Map();
|
|
296
300
|
// Custom compiler host: reads patch-owned files from disk, returns
|
|
297
301
|
// the shim for the shim path, and returns empty content for
|
|
298
302
|
// anything else to avoid reading the full Firefox tree.
|
|
@@ -333,17 +337,10 @@ export async function runCheckJsGrouped(input) {
|
|
|
333
337
|
return shimSource;
|
|
334
338
|
return defaultHost.readFile(fileName);
|
|
335
339
|
},
|
|
336
|
-
resolveModuleNameLiterals(
|
|
337
|
-
return moduleLiterals.map((literal) => {
|
|
338
|
-
const owned = resolveOwnedSpecifier(literal.text);
|
|
339
|
-
if (owned)
|
|
340
|
-
return { resolvedModule: owned };
|
|
341
|
-
return { resolvedModule: resolveViaPaths?.(literal.text) };
|
|
342
|
-
});
|
|
343
|
-
},
|
|
340
|
+
resolveModuleNameLiterals: createModuleLiteralResolver(resolveOwnedSpecifier, resolveViaPaths, anyTypedImports),
|
|
344
341
|
};
|
|
345
342
|
const program = ts.createProgram(rootFiles, options, withSharedSourceFiles(host, input.sourceFileCache, shimPath, shimSource));
|
|
346
|
-
const byFile = groupOwnedDiagnostics(ts, [...program.getSemanticDiagnostics(), ...program.getSyntacticDiagnostics()], relByAbsolute, input.mode?.undefinedIdentifiers ?? 'warning');
|
|
343
|
+
const byFile = groupOwnedDiagnostics(ts, [...program.getSemanticDiagnostics(), ...program.getSyntacticDiagnostics()], relByAbsolute, input.mode?.undefinedIdentifiers ?? 'warning', anyTypedImports);
|
|
347
344
|
verbose(`checkJs: analyzed ${rootFiles.length - 1} file(s) across ${byFile.size} owning file(s)`);
|
|
348
345
|
return { byFile, global: [] };
|
|
349
346
|
}
|
|
@@ -354,7 +351,7 @@ export async function runCheckJsGrouped(input) {
|
|
|
354
351
|
* or shim files are dropped. Only owned files (in `relByAbsolute`) carry
|
|
355
352
|
* findings.
|
|
356
353
|
*/
|
|
357
|
-
function groupOwnedDiagnostics(ts, diagnostics, relByAbsolute, undefinedIdentifiers = 'warning') {
|
|
354
|
+
function groupOwnedDiagnostics(ts, diagnostics, relByAbsolute, undefinedIdentifiers = 'warning', anyTypedImports = new Map()) {
|
|
358
355
|
const byFile = new Map();
|
|
359
356
|
for (const diag of diagnostics) {
|
|
360
357
|
if (SUPPRESSED_DIAGNOSTIC_CODES.has(diag.code))
|
|
@@ -386,7 +383,7 @@ function groupOwnedDiagnostics(ts, diagnostics, relByAbsolute, undefinedIdentifi
|
|
|
386
383
|
check: 'checkjs-type-error',
|
|
387
384
|
message: isUndefinedIdentifier
|
|
388
385
|
? `Line ${line}: ${messageText} ${UNDEFINED_IDENTIFIER_HINT}`
|
|
389
|
-
: `Line ${line}: ${messageText}`,
|
|
386
|
+
: `Line ${line}: ${messageText}${anyTypedImportHint(diag.code, anyTypedImports.get(sourceFile.fileName))}`,
|
|
390
387
|
severity,
|
|
391
388
|
});
|
|
392
389
|
byFile.set(relPath, bucket);
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Line counting for the size rules: raw lines, code lines, and the per-line
|
|
3
|
+
* code mask the `addedCode` patch-size metric reads off a file's
|
|
4
|
+
* post-image.
|
|
5
|
+
*
|
|
6
|
+
* "Code" means a line left non-blank once comments are blanked. JS goes
|
|
7
|
+
* through acorn's tokenizer (`stripJsCommentsParsed`), so a regex literal
|
|
8
|
+
* containing `/*`, a string containing `//`, nested template literals,
|
|
9
|
+
* JSDoc and a shebang are all judged correctly, and a blank line inside a
|
|
10
|
+
* template literal counts as blank.
|
|
11
|
+
*/
|
|
12
|
+
/**
|
|
13
|
+
* Counts the lines of `content` the way `wc -l` reports them. A naive
|
|
14
|
+
* `split('\n').length` over-counts by one for any content ending in `\n`
|
|
15
|
+
* (the common case), making the size rules fire one line early against
|
|
16
|
+
* the operator's own `wc -l` measurement.
|
|
17
|
+
*/
|
|
18
|
+
export declare function countRawLines(content: string): number;
|
|
19
|
+
/** The result of {@link countCodeLines}. */
|
|
20
|
+
export interface CodeLineCount {
|
|
21
|
+
/**
|
|
22
|
+
* Lines that carry code: non-blank once comments are blanked. When the
|
|
23
|
+
* source could not be tokenized this is the raw line count instead, the
|
|
24
|
+
* upper bound, so an unparsable file never measures smaller than it is.
|
|
25
|
+
*/
|
|
26
|
+
lines: number;
|
|
27
|
+
/** False when acorn could tokenize the source neither as a module nor as a script. */
|
|
28
|
+
parsed: boolean;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Counts the code lines of a JS source: comments are blanked by acorn's
|
|
32
|
+
* tokenizer (module goal first, then script, since chrome subscripts are
|
|
33
|
+
* scripts) and the non-blank lines are counted. When neither goal
|
|
34
|
+
* tokenizes, the raw line count is returned with `parsed: false`. A regex
|
|
35
|
+
* fallback would under-count, which fails open.
|
|
36
|
+
*
|
|
37
|
+
* @param content - JS source text
|
|
38
|
+
*/
|
|
39
|
+
export declare function countCodeLines(content: string): CodeLineCount;
|
|
40
|
+
/** The per-line code mask of one post-image. */
|
|
41
|
+
export interface CodeLineMask {
|
|
42
|
+
/** `code[i]` is true when line `i + 1` carries code. */
|
|
43
|
+
code: boolean[];
|
|
44
|
+
/** False for a JS file acorn could not tokenize; every non-blank line then counts. */
|
|
45
|
+
parsed: boolean;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Classifies every line of a file's post-image as code or not, by file
|
|
49
|
+
* kind: JS through acorn, CSS block comments, `<!-- -->` in markup, and
|
|
50
|
+
* whole-line `#` comments (`;` for `.ini`/`.in`, `!` for `.properties`) in
|
|
51
|
+
* Fluent, manifests, `moz.build` and similar. Any other file counts every
|
|
52
|
+
* non-blank line. In CSS, lines inside a Furnace fragment expansion
|
|
53
|
+
* (`@fireforge-include` … `@fireforge-end-include`) are not code of this
|
|
54
|
+
* file: they are a copy of a shared fragment.
|
|
55
|
+
*
|
|
56
|
+
* @param file - Engine-relative path, used only to pick the file kind
|
|
57
|
+
* @param content - The post-image text
|
|
58
|
+
*/
|
|
59
|
+
export declare function codeLineMask(file: string, content: string): CodeLineMask;
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
// SPDX-License-Identifier: EUPL-1.2
|
|
2
|
+
/**
|
|
3
|
+
* Line counting for the size rules: raw lines, code lines, and the per-line
|
|
4
|
+
* code mask the `addedCode` patch-size metric reads off a file's
|
|
5
|
+
* post-image.
|
|
6
|
+
*
|
|
7
|
+
* "Code" means a line left non-blank once comments are blanked. JS goes
|
|
8
|
+
* through acorn's tokenizer (`stripJsCommentsParsed`), so a regex literal
|
|
9
|
+
* containing `/*`, a string containing `//`, nested template literals,
|
|
10
|
+
* JSDoc and a shebang are all judged correctly, and a blank line inside a
|
|
11
|
+
* template literal counts as blank.
|
|
12
|
+
*/
|
|
13
|
+
import { stripJsCommentsParsed } from '../utils/regex.js';
|
|
14
|
+
import { expandedFragmentLineMask } from './furnace-css-fragments.js';
|
|
15
|
+
import { maskCssComments } from './patch-lint-css.js';
|
|
16
|
+
/**
|
|
17
|
+
* Splits content into lines the way `wc -l` reports them: a trailing
|
|
18
|
+
* newline terminates the last line rather than starting an empty extra one.
|
|
19
|
+
*/
|
|
20
|
+
function splitContentLines(content) {
|
|
21
|
+
const lines = content.split('\n');
|
|
22
|
+
if (lines[lines.length - 1] === '')
|
|
23
|
+
lines.pop();
|
|
24
|
+
return lines;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Counts the lines of `content` the way `wc -l` reports them. A naive
|
|
28
|
+
* `split('\n').length` over-counts by one for any content ending in `\n`
|
|
29
|
+
* (the common case), making the size rules fire one line early against
|
|
30
|
+
* the operator's own `wc -l` measurement.
|
|
31
|
+
*/
|
|
32
|
+
export function countRawLines(content) {
|
|
33
|
+
return splitContentLines(content).length;
|
|
34
|
+
}
|
|
35
|
+
const isBlank = (line) => line.trim() === '';
|
|
36
|
+
/**
|
|
37
|
+
* Counts the code lines of a JS source: comments are blanked by acorn's
|
|
38
|
+
* tokenizer (module goal first, then script, since chrome subscripts are
|
|
39
|
+
* scripts) and the non-blank lines are counted. When neither goal
|
|
40
|
+
* tokenizes, the raw line count is returned with `parsed: false`. A regex
|
|
41
|
+
* fallback would under-count, which fails open.
|
|
42
|
+
*
|
|
43
|
+
* @param content - JS source text
|
|
44
|
+
*/
|
|
45
|
+
export function countCodeLines(content) {
|
|
46
|
+
const stripped = stripJsCommentsParsed(content);
|
|
47
|
+
if (stripped === null)
|
|
48
|
+
return { lines: countRawLines(content), parsed: false };
|
|
49
|
+
return {
|
|
50
|
+
lines: splitContentLines(stripped).filter((line) => !isBlank(line)).length,
|
|
51
|
+
parsed: true,
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
const JS_FILE = /\.(?:m?js|jsm|cjs)$/;
|
|
55
|
+
const MARKUP_FILE = /\.(?:x?html|xml|svg|xul|dtd)$/;
|
|
56
|
+
const HASH_COMMENT_FILE = /(?:\.(?:ftl|properties|toml|ini|mn|build|py|conf|configure|sh|ya?ml|in|cfg|mozbuild)|(?:^|\/)(?:Makefile|mozconfig))$/;
|
|
57
|
+
/** Line-comment leaders per hash-comment file kind. */
|
|
58
|
+
function lineCommentPattern(file) {
|
|
59
|
+
if (/\.(?:ini|in)$/.test(file))
|
|
60
|
+
return /^\s*[#;]/;
|
|
61
|
+
if (file.endsWith('.properties'))
|
|
62
|
+
return /^\s*[#!]/;
|
|
63
|
+
return /^\s*#/;
|
|
64
|
+
}
|
|
65
|
+
/** Masks `<!-- … -->` comments, keeping newlines. Unclosed comments run to EOF. */
|
|
66
|
+
function maskMarkupComments(source) {
|
|
67
|
+
return source.replace(/<!--[\s\S]*?(?:-->|$)/g, (m) => m.replace(/[^\n]/g, ' '));
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Classifies every line of a file's post-image as code or not, by file
|
|
71
|
+
* kind: JS through acorn, CSS block comments, `<!-- -->` in markup, and
|
|
72
|
+
* whole-line `#` comments (`;` for `.ini`/`.in`, `!` for `.properties`) in
|
|
73
|
+
* Fluent, manifests, `moz.build` and similar. Any other file counts every
|
|
74
|
+
* non-blank line. In CSS, lines inside a Furnace fragment expansion
|
|
75
|
+
* (`@fireforge-include` … `@fireforge-end-include`) are not code of this
|
|
76
|
+
* file: they are a copy of a shared fragment.
|
|
77
|
+
*
|
|
78
|
+
* @param file - Engine-relative path, used only to pick the file kind
|
|
79
|
+
* @param content - The post-image text
|
|
80
|
+
*/
|
|
81
|
+
export function codeLineMask(file, content) {
|
|
82
|
+
if (JS_FILE.test(file)) {
|
|
83
|
+
const stripped = stripJsCommentsParsed(content);
|
|
84
|
+
const source = stripped ?? content;
|
|
85
|
+
return { code: source.split('\n').map((line) => !isBlank(line)), parsed: stripped !== null };
|
|
86
|
+
}
|
|
87
|
+
if (file.endsWith('.css')) {
|
|
88
|
+
const inFragment = expandedFragmentLineMask(content);
|
|
89
|
+
const code = maskCssComments(content)
|
|
90
|
+
.split('\n')
|
|
91
|
+
.map((line, i) => !isBlank(line) && inFragment[i] !== true);
|
|
92
|
+
return { code, parsed: true };
|
|
93
|
+
}
|
|
94
|
+
if (MARKUP_FILE.test(file)) {
|
|
95
|
+
return {
|
|
96
|
+
code: maskMarkupComments(content)
|
|
97
|
+
.split('\n')
|
|
98
|
+
.map((l) => !isBlank(l)),
|
|
99
|
+
parsed: true,
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
const comment = HASH_COMMENT_FILE.test(file) ? lineCommentPattern(file) : undefined;
|
|
103
|
+
const code = content.split('\n').map((line) => !isBlank(line) && !comment?.test(line));
|
|
104
|
+
return { code, parsed: true };
|
|
105
|
+
}
|
|
@@ -20,7 +20,7 @@ import { collectNewFileCreatorsByPath } from './patch-lint-creators.js';
|
|
|
20
20
|
import { detectNewFilesInDiff, extractAddedLinesPerFile } from './patch-lint-diff.js';
|
|
21
21
|
import { lintPatchQueueForwardRegistrations } from './patch-lint-forward-registration.js';
|
|
22
22
|
import { lintPatchQueueModuleRegistrations } from './patch-lint-module-registration.js';
|
|
23
|
-
import { describeRegistrationFailure, findStagedRegistrationFailure, isLaterOwner, quoteRegistrationLine, } from './patch-lint-staged-registration.js';
|
|
23
|
+
import { describeRegistrationFailure, findStagedRegistrationFailure, isLaterOwner, quoteRegistrationLine, STAGED_DEPENDENCY_REASON_PLACEHOLDER, stagedDependencyUnusedFingerprint, } from './patch-lint-staged-registration.js';
|
|
24
24
|
import { loadPatchesManifest } from './patch-manifest-io.js';
|
|
25
25
|
import { categoryRangeForOrder, categoryRangeLabel } from './patch-policy.js';
|
|
26
26
|
import { extractNewFileContentsFromDiff } from './patch-transform.js';
|
|
@@ -493,13 +493,21 @@ export function lintPatchQueueForwardImports(ctx) {
|
|
|
493
493
|
const stagedCommands = laterOwners
|
|
494
494
|
.map((o) => `fireforge patch staged-dependency ${entry.filename} --add ` +
|
|
495
495
|
`--file ${sitePath} --specifier "${specifier}" ` +
|
|
496
|
-
`--creates ${o.fullPath} --owner ${o.filename}`)
|
|
496
|
+
`--creates ${o.fullPath} --owner ${o.filename} ${STAGED_DEPENDENCY_REASON_PLACEHOLDER}`)
|
|
497
497
|
.join('; ');
|
|
498
498
|
issues.push({
|
|
499
499
|
file: sitePath,
|
|
500
500
|
check: 'forward-import',
|
|
501
501
|
patches: [entry.filename],
|
|
502
502
|
fingerprint: `forward-import|${sitePath}|${cleaned}|${fingerprintOwners}`,
|
|
503
|
+
stagedDeclarations: laterOwners.map((o) => ({
|
|
504
|
+
patch: entry.filename,
|
|
505
|
+
kind: 'import',
|
|
506
|
+
file: sitePath,
|
|
507
|
+
specifier,
|
|
508
|
+
creates: o.fullPath,
|
|
509
|
+
owner: o.filename,
|
|
510
|
+
})),
|
|
503
511
|
message: `${sitePath} in ${entry.filename} imports "${specifier}", ` +
|
|
504
512
|
`but the matching new file is created by a later patch: ${ownersSummary}. ` +
|
|
505
513
|
'Reorder the patches so the dependency is created first, move the import ' +
|
|
@@ -518,7 +526,7 @@ export function lintPatchQueueForwardImports(ctx) {
|
|
|
518
526
|
file: dependency.file,
|
|
519
527
|
check: 'staged-dependency-unused',
|
|
520
528
|
patches: [entry.filename],
|
|
521
|
-
fingerprint:
|
|
529
|
+
fingerprint: stagedDependencyUnusedFingerprint(entry.filename, dependency),
|
|
522
530
|
message: `${entry.filename} declares a staged forward import from ${dependency.file} ` +
|
|
523
531
|
`to "${dependency.specifier}" / ${dependency.creates}, but that exact forward dependency was not found. ` +
|
|
524
532
|
'Remove the stale declaration with "fireforge patch staged-dependency --remove" or update it to match the current queue.',
|
|
@@ -541,7 +549,7 @@ export function lintPatchQueueForwardImports(ctx) {
|
|
|
541
549
|
file: registration.file,
|
|
542
550
|
check: 'staged-dependency-unused',
|
|
543
551
|
patches: [entry.filename],
|
|
544
|
-
fingerprint:
|
|
552
|
+
fingerprint: stagedDependencyUnusedFingerprint(entry.filename, registration),
|
|
545
553
|
message: `${entry.filename} declares a staged registration in ${registration.file} ` +
|
|
546
554
|
`("${registration.line}") for ${registration.creates}, but ${describeRegistrationFailure(failure)} ` +
|
|
547
555
|
'Remove the stale declaration with: ' +
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* CSS patch-lint rules: introduced raw color values
|
|
3
|
-
* custom-property references.
|
|
2
|
+
* CSS patch-lint rules: introduced raw color values, non-tokenized
|
|
3
|
+
* custom-property references, and (opt-in) token scales over created CSS.
|
|
4
4
|
*
|
|
5
5
|
* Split out of `patch-lint.ts` so each rule family stays within the
|
|
6
6
|
* per-file line budget. `patch-lint.ts` re-exports `lintPatchedCss` so
|
|
@@ -8,6 +8,12 @@
|
|
|
8
8
|
*/
|
|
9
9
|
import type { PatchLintIssue } from '../types/commands/index.js';
|
|
10
10
|
import type { FireForgeConfig } from '../types/config.js';
|
|
11
|
+
/**
|
|
12
|
+
* Masks CSS block comments with spaces, preserving newlines so line
|
|
13
|
+
* numbers stay stable. An unclosed trailing `/*` is masked to EOF,
|
|
14
|
+
* matching how a CSS parser treats it.
|
|
15
|
+
*/
|
|
16
|
+
export declare function maskCssComments(source: string): string;
|
|
11
17
|
/**
|
|
12
18
|
* Lints patched CSS files for introduced raw color values and non-tokenized
|
|
13
19
|
* custom properties.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// SPDX-License-Identifier: EUPL-1.2
|
|
2
2
|
/**
|
|
3
|
-
* CSS patch-lint rules: introduced raw color values
|
|
4
|
-
* custom-property references.
|
|
3
|
+
* CSS patch-lint rules: introduced raw color values, non-tokenized
|
|
4
|
+
* custom-property references, and (opt-in) token scales over created CSS.
|
|
5
5
|
*
|
|
6
6
|
* Split out of `patch-lint.ts` so each rule family stays within the
|
|
7
7
|
* per-file line budget. `patch-lint.ts` re-exports `lintPatchedCss` so
|
|
@@ -13,7 +13,8 @@ import { pathExists, readText } from '../utils/fs.js';
|
|
|
13
13
|
import { verbose } from '../utils/logger.js';
|
|
14
14
|
import { hasRawCssColors } from '../utils/regex.js';
|
|
15
15
|
import { loadFurnaceConfig } from './furnace-config.js';
|
|
16
|
-
import { extractAddedLineNumbersPerFile, extractAddedLinesPerFile } from './patch-lint-diff.js';
|
|
16
|
+
import { detectNewFilesInDiff, extractAddedLineNumbersPerFile, extractAddedLinesPerFile, } from './patch-lint-diff.js';
|
|
17
|
+
import { lintTokenScales } from './patch-lint-token-scale.js';
|
|
17
18
|
/**
|
|
18
19
|
* Loads the furnace token-prefix lint inputs gracefully. Returns
|
|
19
20
|
* undefined (skipping the token-prefix check) when furnace.json cannot
|
|
@@ -41,7 +42,7 @@ async function loadCssTokenContext(repoDir) {
|
|
|
41
42
|
* numbers stay stable. An unclosed trailing `/*` is masked to EOF,
|
|
42
43
|
* matching how a CSS parser treats it.
|
|
43
44
|
*/
|
|
44
|
-
function maskCssComments(source) {
|
|
45
|
+
export function maskCssComments(source) {
|
|
45
46
|
const masked = source.replace(/\/\*[\s\S]*?\*\//g, (m) => m.replace(/[^\n]/g, ' '));
|
|
46
47
|
const openerIndex = masked.indexOf('/*');
|
|
47
48
|
if (openerIndex === -1)
|
|
@@ -197,6 +198,9 @@ export async function lintPatchedCss(repoDir, affectedFiles, diffContent, config
|
|
|
197
198
|
const addedLineNumbersByFile = diffContent
|
|
198
199
|
? extractAddedLineNumbersPerFile(diffContent)
|
|
199
200
|
: undefined;
|
|
201
|
+
// `patchLint.tokenScales` governs only CSS the patch creates.
|
|
202
|
+
const tokenScales = config?.patchLint?.tokenScales ?? [];
|
|
203
|
+
const createdFiles = diffContent && tokenScales.length > 0 ? detectNewFilesInDiff(diffContent) : new Set();
|
|
200
204
|
for (const file of cssFiles) {
|
|
201
205
|
const filePath = join(repoDir, file);
|
|
202
206
|
if (!(await pathExists(filePath)))
|
|
@@ -213,6 +217,8 @@ export async function lintPatchedCss(repoDir, affectedFiles, diffContent, config
|
|
|
213
217
|
issues,
|
|
214
218
|
});
|
|
215
219
|
checkTokenPrefixViolations(file, cssContent, addedLinesByFile, tokenContext, issues);
|
|
220
|
+
if (createdFiles.has(file))
|
|
221
|
+
issues.push(...lintTokenScales(file, rawCss, tokenScales));
|
|
216
222
|
}
|
|
217
223
|
return issues;
|
|
218
224
|
}
|
|
@@ -13,7 +13,9 @@
|
|
|
13
13
|
* lines failed a gate with a message calling 750 soft. The message below
|
|
14
14
|
* says what the band is (a warning) and what a zero-warning gate does with
|
|
15
15
|
* it, and the thresholds are now tunable, so a project whose file-size
|
|
16
|
-
* policy differs has a dial instead of an argument.
|
|
16
|
+
* policy differs has a dial instead of an argument. The notice band is the
|
|
17
|
+
* design target: advisory, and its message says so rather than borrowing
|
|
18
|
+
* the warning band's gate sentence.
|
|
17
19
|
*/
|
|
18
20
|
import type { PatchLintFileSizeThresholds } from '../types/config.js';
|
|
19
21
|
/** A fully resolved threshold triple. */
|
|
@@ -38,14 +40,19 @@ export declare function resolveFileSizeThresholds(overrides: PatchLintFileSizeTh
|
|
|
38
40
|
/**
|
|
39
41
|
* Renders the `file-too-large` message for a given band.
|
|
40
42
|
*
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
*
|
|
43
|
+
* Each band says what it means for a gate. A notice is over the design
|
|
44
|
+
* target and advisory: it never fails `--max-warnings 0`, and saying it
|
|
45
|
+
* did once got a test suite split for nothing. A warning is what a
|
|
46
|
+
* zero-warning gate fails on, so it names that and the dial. Only the
|
|
47
|
+
* error band suggests splitting, because a test-file split pushes against
|
|
48
|
+
* one suite per subject and should not be the default advice below it.
|
|
49
|
+
* Every band names the unit, which matters once `fileSizeMetric` makes
|
|
50
|
+
* code lines a choice.
|
|
45
51
|
*/
|
|
46
52
|
export declare function formatFileTooLargeMessage(args: {
|
|
47
53
|
label: string;
|
|
48
54
|
lineCount: number;
|
|
55
|
+
unit: 'lines' | 'code lines';
|
|
49
56
|
thresholds: ResolvedFileSizeTier;
|
|
50
57
|
band: 'notice' | 'warning' | 'error';
|
|
51
58
|
verb: string;
|
|
@@ -14,7 +14,9 @@
|
|
|
14
14
|
* lines failed a gate with a message calling 750 soft. The message below
|
|
15
15
|
* says what the band is (a warning) and what a zero-warning gate does with
|
|
16
16
|
* it, and the thresholds are now tunable, so a project whose file-size
|
|
17
|
-
* policy differs has a dial instead of an argument.
|
|
17
|
+
* policy differs has a dial instead of an argument. The notice band is the
|
|
18
|
+
* design target: advisory, and its message says so rather than borrowing
|
|
19
|
+
* the warning band's gate sentence.
|
|
18
20
|
*/
|
|
19
21
|
/** Built-in defaults, per file class. */
|
|
20
22
|
export const DEFAULT_FILE_SIZE_THRESHOLDS = {
|
|
@@ -36,18 +38,27 @@ export function resolveFileSizeThresholds(overrides, isTest) {
|
|
|
36
38
|
/**
|
|
37
39
|
* Renders the `file-too-large` message for a given band.
|
|
38
40
|
*
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
*
|
|
42
|
-
*
|
|
41
|
+
* Each band says what it means for a gate. A notice is over the design
|
|
42
|
+
* target and advisory: it never fails `--max-warnings 0`, and saying it
|
|
43
|
+
* did once got a test suite split for nothing. A warning is what a
|
|
44
|
+
* zero-warning gate fails on, so it names that and the dial. Only the
|
|
45
|
+
* error band suggests splitting, because a test-file split pushes against
|
|
46
|
+
* one suite per subject and should not be the default advice below it.
|
|
47
|
+
* Every band names the unit, which matters once `fileSizeMetric` makes
|
|
48
|
+
* code lines a choice.
|
|
43
49
|
*/
|
|
44
50
|
export function formatFileTooLargeMessage(args) {
|
|
45
|
-
const { label, lineCount, thresholds, band, verb } = args;
|
|
51
|
+
const { label, lineCount, unit, thresholds, band, verb } = args;
|
|
52
|
+
const measured = `${label} has ${lineCount} ${unit}`;
|
|
46
53
|
if (band === 'error') {
|
|
47
|
-
return `${
|
|
54
|
+
return `${measured} (error threshold: ${thresholds.error}). Consider ${verb}.`;
|
|
48
55
|
}
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
56
|
+
const limits = `(warning threshold: ${thresholds.warning}, error threshold: ${thresholds.error})`;
|
|
57
|
+
if (band === 'notice') {
|
|
58
|
+
return (`${measured}, over the design target of ${thresholds.notice} ${limits}. ` +
|
|
59
|
+
'Advisory; does not fail --max-warnings 0.');
|
|
60
|
+
}
|
|
61
|
+
return (`${measured} ${limits}. ` +
|
|
62
|
+
'Reported as a warning, which a gate running --max-warnings 0 treats as a failure; ' +
|
|
63
|
+
'tune "patchLint.fileSizeThresholds" if these limits are wrong for this project.');
|
|
53
64
|
}
|
|
@@ -24,6 +24,24 @@ export interface ForwardRegistration {
|
|
|
24
24
|
/** Paste-and-run declaration that records the stage as intentional. */
|
|
25
25
|
command: string;
|
|
26
26
|
}
|
|
27
|
+
/** True for a jar.mn, moz.build or test manifest, the carriers {@link resolveCarrierReferences} reads. */
|
|
28
|
+
export declare function isRegistrationCarrier(file: string): boolean;
|
|
29
|
+
/**
|
|
30
|
+
* The engine paths named by the lines of one jar.mn, moz.build or test
|
|
31
|
+
* manifest, resolved the way this rule resolves them. Exported for a caller
|
|
32
|
+
* outside the queue lint (re-export's adjacency belt asks which files a
|
|
33
|
+
* patch's added registration lines name). A `customElements.js` chrome URL
|
|
34
|
+
* resolves only through the queue's jar.mn index, so it is not covered.
|
|
35
|
+
*
|
|
36
|
+
* @param rawPath - Engine-relative path of the carrier
|
|
37
|
+
* @param content - The carrier lines to read (typically the added ones)
|
|
38
|
+
* @returns One entry per resolvable token. `exact` is set when it has no wildcard.
|
|
39
|
+
*/
|
|
40
|
+
export declare function resolveCarrierReferences(rawPath: string, content: string): {
|
|
41
|
+
line: string;
|
|
42
|
+
exact?: string;
|
|
43
|
+
matches: (candidate: string) => boolean;
|
|
44
|
+
}[];
|
|
27
45
|
/** The discharge command, in the exact shape the support-files arm prints. */
|
|
28
46
|
export declare function formatRegistrationDeclaration(patch: string, file: string, line: string, creates: string, owner: string): string;
|
|
29
47
|
/**
|
|
@@ -28,7 +28,7 @@ import { basename, dirname, posix } from 'node:path';
|
|
|
28
28
|
import { normalizePathSlashes } from '../utils/paths.js';
|
|
29
29
|
import { escapeRegex } from '../utils/regex.js';
|
|
30
30
|
import { parseJarMnEntry } from './build-audit-registration.js';
|
|
31
|
-
import { isLaterOwner, quoteRegistrationLine } from './patch-lint-staged-registration.js';
|
|
31
|
+
import { isLaterOwner, quoteRegistrationLine, STAGED_DEPENDENCY_REASON_PLACEHOLDER, } from './patch-lint-staged-registration.js';
|
|
32
32
|
const TEST_MANIFEST_BASENAMES = new Set([
|
|
33
33
|
'xpcshell.toml',
|
|
34
34
|
'xpcshell.ini',
|
|
@@ -153,20 +153,45 @@ function customElementsReferences(file, content, jarTargets) {
|
|
|
153
153
|
}
|
|
154
154
|
return refs;
|
|
155
155
|
}
|
|
156
|
+
/** True for a jar.mn, moz.build or test manifest, the carriers {@link resolveCarrierReferences} reads. */
|
|
157
|
+
export function isRegistrationCarrier(file) {
|
|
158
|
+
const name = basename(normalizePathSlashes(file));
|
|
159
|
+
return name === 'jar.mn' || name === 'moz.build' || TEST_MANIFEST_BASENAMES.has(name);
|
|
160
|
+
}
|
|
161
|
+
function carrierReferences(file, content) {
|
|
162
|
+
const name = basename(file);
|
|
163
|
+
if (name === 'jar.mn')
|
|
164
|
+
return jarMnReferences(file, content);
|
|
165
|
+
if (name === 'moz.build')
|
|
166
|
+
return mozBuildReferences(file, content);
|
|
167
|
+
if (TEST_MANIFEST_BASENAMES.has(name))
|
|
168
|
+
return testManifestReferences(file, content);
|
|
169
|
+
return [];
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* The engine paths named by the lines of one jar.mn, moz.build or test
|
|
173
|
+
* manifest, resolved the way this rule resolves them. Exported for a caller
|
|
174
|
+
* outside the queue lint (re-export's adjacency belt asks which files a
|
|
175
|
+
* patch's added registration lines name). A `customElements.js` chrome URL
|
|
176
|
+
* resolves only through the queue's jar.mn index, so it is not covered.
|
|
177
|
+
*
|
|
178
|
+
* @param rawPath - Engine-relative path of the carrier
|
|
179
|
+
* @param content - The carrier lines to read (typically the added ones)
|
|
180
|
+
* @returns One entry per resolvable token. `exact` is set when it has no wildcard.
|
|
181
|
+
*/
|
|
182
|
+
export function resolveCarrierReferences(rawPath, content) {
|
|
183
|
+
return carrierReferences(normalizePathSlashes(rawPath), content);
|
|
184
|
+
}
|
|
156
185
|
function referencesFor(entry, jarTargets) {
|
|
157
186
|
const refs = [];
|
|
158
187
|
for (const [rawPath, content] of [...entry.newFiles, ...entry.modifiedFileAdditions]) {
|
|
159
188
|
const file = normalizePathSlashes(rawPath);
|
|
160
|
-
|
|
161
|
-
if (name === 'jar.mn')
|
|
162
|
-
refs.push(...jarMnReferences(file, content));
|
|
163
|
-
else if (name === 'moz.build')
|
|
164
|
-
refs.push(...mozBuildReferences(file, content));
|
|
165
|
-
else if (TEST_MANIFEST_BASENAMES.has(name))
|
|
166
|
-
refs.push(...testManifestReferences(file, content));
|
|
167
|
-
else if (name === 'customElements.js') {
|
|
189
|
+
if (basename(file) === 'customElements.js') {
|
|
168
190
|
refs.push(...customElementsReferences(file, content, jarTargets));
|
|
169
191
|
}
|
|
192
|
+
else {
|
|
193
|
+
refs.push(...carrierReferences(file, content));
|
|
194
|
+
}
|
|
170
195
|
}
|
|
171
196
|
return refs;
|
|
172
197
|
}
|
|
@@ -178,7 +203,7 @@ function isDeclared(entry, file, created) {
|
|
|
178
203
|
export function formatRegistrationDeclaration(patch, file, line, creates, owner) {
|
|
179
204
|
return (`fireforge patch staged-dependency ${patch} --add --kind registration ` +
|
|
180
205
|
`--file ${file} --line "${quoteRegistrationLine(line)}" ` +
|
|
181
|
-
`--creates ${creates} --owner ${owner}`);
|
|
206
|
+
`--creates ${creates} --owner ${owner} ${STAGED_DEPENDENCY_REASON_PLACEHOLDER}`);
|
|
182
207
|
}
|
|
183
208
|
/**
|
|
184
209
|
* Finds every undeclared forward registration in the extended carriers:
|