@hominis/fireforge 0.40.0 → 0.41.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 +79 -0
- package/README.md +16 -10
- package/dist/bin/fireforge.js +25 -4
- package/dist/build-info.json +9 -0
- package/dist/src/cli.js +20 -3
- package/dist/src/commands/bootstrap.js +5 -1
- package/dist/src/commands/discard.js +2 -22
- package/dist/src/commands/doctor/post-rebase-audit.js +27 -4
- package/dist/src/commands/doctor-check-core.d.ts +20 -0
- package/dist/src/commands/doctor-check-core.js +28 -0
- package/dist/src/commands/doctor-external-toolchains.js +2 -0
- package/dist/src/commands/doctor-furnace-manifest-sync.js +144 -46
- package/dist/src/commands/doctor-furnace.js +13 -11
- package/dist/src/commands/doctor-orphaned-harness.js +2 -1
- package/dist/src/commands/doctor.js +2 -2
- package/dist/src/commands/export-all.js +9 -1
- package/dist/src/commands/export-flow.js +13 -3
- package/dist/src/commands/export-placement-conflicts.d.ts +17 -0
- package/dist/src/commands/export-placement-conflicts.js +74 -0
- package/dist/src/commands/export-placement-gate.js +1 -1
- package/dist/src/commands/export-shared.d.ts +8 -1
- package/dist/src/commands/export-shared.js +16 -7
- package/dist/src/commands/export.js +2 -2
- package/dist/src/commands/furnace/apply.js +4 -3
- package/dist/src/commands/furnace/chrome-doc-remove.js +13 -2
- package/dist/src/commands/furnace/chrome-doc.js +13 -2
- package/dist/src/commands/furnace/create-browser-test.d.ts +5 -0
- package/dist/src/commands/furnace/create-browser-test.js +5 -0
- package/dist/src/commands/furnace/create.js +2 -2
- package/dist/src/commands/furnace/diff.js +2 -1
- package/dist/src/commands/furnace/init.js +4 -6
- package/dist/src/commands/furnace/override.js +2 -2
- package/dist/src/commands/furnace/remove-mutations.d.ts +40 -0
- package/dist/src/commands/furnace/remove-mutations.js +171 -0
- package/dist/src/commands/furnace/remove.js +21 -128
- package/dist/src/commands/furnace/rename-browser-test.js +54 -5
- package/dist/src/commands/furnace/scan.js +27 -36
- package/dist/src/commands/furnace/status.js +30 -28
- package/dist/src/commands/furnace/validate.js +25 -18
- package/dist/src/commands/import.js +6 -20
- package/dist/src/commands/lint-per-patch.js +12 -59
- package/dist/src/commands/lint-per-run-checkjs.d.ts +64 -0
- package/dist/src/commands/lint-per-run-checkjs.js +102 -0
- package/dist/src/commands/lint.js +4 -4
- package/dist/src/commands/manifest.js +1 -1
- package/dist/src/commands/package.js +9 -16
- package/dist/src/commands/patch/compact.js +5 -5
- package/dist/src/commands/patch/delete.js +5 -5
- package/dist/src/commands/patch/lint-ignore.js +3 -2
- package/dist/src/commands/patch/move-files-create.js +22 -4
- package/dist/src/commands/patch/move-files-into.js +14 -10
- package/dist/src/commands/patch/move-files.js +6 -5
- package/dist/src/commands/patch/rename.d.ts +2 -2
- package/dist/src/commands/patch/rename.js +151 -50
- package/dist/src/commands/patch/reorder.d.ts +9 -0
- package/dist/src/commands/patch/reorder.js +14 -10
- package/dist/src/commands/patch/split-plan.d.ts +13 -6
- package/dist/src/commands/patch/split-plan.js +22 -12
- package/dist/src/commands/patch/split.d.ts +1 -1
- package/dist/src/commands/patch/split.js +23 -9
- package/dist/src/commands/patch/staged-dependency-validate.d.ts +15 -0
- package/dist/src/commands/patch/staged-dependency-validate.js +49 -0
- package/dist/src/commands/patch/staged-dependency.js +10 -0
- package/dist/src/commands/re-export-adjacent.js +5 -6
- package/dist/src/commands/re-export-bulk-scan.d.ts +13 -0
- package/dist/src/commands/re-export-bulk-scan.js +142 -2
- package/dist/src/commands/re-export-drift.d.ts +74 -0
- package/dist/src/commands/re-export-drift.js +234 -0
- package/dist/src/commands/re-export-files.js +5 -3
- package/dist/src/commands/re-export-lint.d.ts +97 -0
- package/dist/src/commands/re-export-lint.js +210 -0
- package/dist/src/commands/re-export-options.js +8 -0
- package/dist/src/commands/re-export-register.d.ts +18 -0
- package/dist/src/commands/re-export-register.js +61 -0
- package/dist/src/commands/re-export-scan.js +13 -7
- package/dist/src/commands/re-export-single.d.ts +20 -0
- package/dist/src/commands/re-export-single.js +261 -0
- package/dist/src/commands/re-export.d.ts +0 -4
- package/dist/src/commands/re-export.js +113 -268
- package/dist/src/commands/rebase/abort.js +13 -4
- package/dist/src/commands/rebase/continue.js +11 -4
- package/dist/src/commands/rebase/index.js +19 -29
- package/dist/src/commands/rebase/patch-loop.js +12 -0
- package/dist/src/commands/reset.js +4 -23
- package/dist/src/commands/resolve.js +2 -9
- package/dist/src/commands/run.js +11 -21
- package/dist/src/commands/source.js +3 -9
- package/dist/src/commands/status-check.d.ts +13 -0
- package/dist/src/commands/status-check.js +31 -13
- package/dist/src/commands/status-json.d.ts +31 -0
- package/dist/src/commands/status-json.js +76 -0
- package/dist/src/commands/status-output.d.ts +1 -0
- package/dist/src/commands/status-output.js +10 -1
- package/dist/src/commands/status-ownership.d.ts +52 -0
- package/dist/src/commands/status-ownership.js +57 -0
- package/dist/src/commands/status.js +184 -175
- package/dist/src/commands/test-build-phase.d.ts +19 -0
- package/dist/src/commands/test-build-phase.js +168 -0
- package/dist/src/commands/test-diagnose.js +30 -2
- package/dist/src/commands/test-modes.d.ts +9 -1
- package/dist/src/commands/test-modes.js +46 -13
- package/dist/src/commands/test-register.js +59 -27
- package/dist/src/commands/test-run.d.ts +29 -3
- package/dist/src/commands/test-run.js +41 -4
- package/dist/src/commands/test-verdict.d.ts +32 -0
- package/dist/src/commands/test-verdict.js +48 -0
- package/dist/src/commands/test.d.ts +9 -0
- package/dist/src/commands/test.js +100 -123
- package/dist/src/commands/token-coverage.js +4 -9
- package/dist/src/commands/tree.d.ts +3 -0
- package/dist/src/commands/tree.js +171 -25
- package/dist/src/commands/verify.js +2 -2
- package/dist/src/commands/watch.js +22 -21
- package/dist/src/commands/wire.js +1 -1
- package/dist/src/core/ast-utils.d.ts +11 -0
- package/dist/src/core/ast-utils.js +11 -0
- package/dist/src/core/build-audit-platform.js +6 -1
- package/dist/src/core/build-audit-registration.js +2 -0
- package/dist/src/core/build-audit-resolve.d.ts +13 -0
- package/dist/src/core/build-audit-resolve.js +34 -13
- package/dist/src/core/build-audit.js +4 -20
- package/dist/src/core/build-baseline-types.d.ts +29 -8
- package/dist/src/core/build-baseline-types.js +2 -1
- package/dist/src/core/build-baseline.d.ts +10 -2
- package/dist/src/core/build-baseline.js +39 -8
- package/dist/src/core/build-prepare.d.ts +4 -0
- package/dist/src/core/build-prepare.js +7 -1
- package/dist/src/core/config-paths.d.ts +1 -1
- package/dist/src/core/config-paths.js +2 -0
- package/dist/src/core/config-validate-test-toolchains.js +3 -2
- package/dist/src/core/config-validate.js +34 -36
- package/dist/src/core/config.js +16 -3
- package/dist/src/core/coverage-extend.d.ts +89 -0
- package/dist/src/core/coverage-extend.js +188 -0
- package/dist/src/core/destructive.js +3 -1
- package/dist/src/core/discard-baseline.js +18 -4
- package/dist/src/core/engine-precondition.d.ts +35 -0
- package/dist/src/core/engine-precondition.js +50 -0
- package/dist/src/core/engine-session-lock.d.ts +38 -1
- package/dist/src/core/engine-session-lock.js +78 -4
- package/dist/src/core/file-lock.d.ts +7 -0
- package/dist/src/core/file-lock.js +20 -30
- package/dist/src/core/firefox.js +5 -2
- package/dist/src/core/furnace-apply-helpers.d.ts +12 -1
- package/dist/src/core/furnace-apply-helpers.js +12 -3
- package/dist/src/core/furnace-apply-output.js +9 -0
- package/dist/src/core/furnace-apply-overwrite-warn.d.ts +63 -0
- package/dist/src/core/furnace-apply-overwrite-warn.js +123 -0
- package/dist/src/core/furnace-apply-undeploy-actions.d.ts +11 -0
- package/dist/src/core/furnace-apply-undeploy-actions.js +49 -0
- package/dist/src/core/furnace-apply.d.ts +16 -4
- package/dist/src/core/furnace-apply.js +39 -43
- package/dist/src/core/furnace-config.js +2 -0
- package/dist/src/core/furnace-css-fragments.js +2 -0
- package/dist/src/core/furnace-jsconfig.js +14 -7
- package/dist/src/core/furnace-registration-ast.js +8 -8
- package/dist/src/core/furnace-registration-remove.js +6 -3
- package/dist/src/core/furnace-registration.js +9 -12
- package/dist/src/core/furnace-rollback.js +1 -1
- package/dist/src/core/furnace-scanner.js +2 -1
- package/dist/src/core/furnace-stale-export.js +2 -1
- package/dist/src/core/furnace-state-persist.d.ts +4 -6
- package/dist/src/core/furnace-validate-compatibility.js +4 -7
- package/dist/src/core/furnace-validate-helpers.js +33 -1
- package/dist/src/core/furnace-validate-registration.js +16 -0
- package/dist/src/core/furnace-validate.js +4 -2
- package/dist/src/core/git-diff.js +37 -2
- package/dist/src/core/lint-cache.d.ts +1 -1
- package/dist/src/core/lint-cache.js +33 -10
- package/dist/src/core/mach-build-artifacts.d.ts +63 -1
- package/dist/src/core/mach-build-artifacts.js +108 -2
- package/dist/src/core/mach-resource-shim.js +1 -0
- package/dist/src/core/marionette-port.d.ts +16 -0
- package/dist/src/core/marionette-port.js +93 -8
- package/dist/src/core/marionette-preflight.js +6 -5
- package/dist/src/core/patch-apply.d.ts +20 -13
- package/dist/src/core/patch-apply.js +32 -33
- package/dist/src/core/patch-export.js +3 -5
- package/dist/src/core/patch-lint-checkjs.d.ts +25 -3
- package/dist/src/core/patch-lint-checkjs.js +78 -7
- package/dist/src/core/patch-lint-chrome-jsdoc.js +9 -0
- package/dist/src/core/patch-lint-creators.d.ts +30 -0
- package/dist/src/core/patch-lint-creators.js +45 -0
- package/dist/src/core/patch-lint-cross.d.ts +1 -17
- package/dist/src/core/patch-lint-cross.js +16 -32
- package/dist/src/core/patch-lint-jsdoc.d.ts +3 -1
- package/dist/src/core/patch-lint-jsdoc.js +15 -5
- package/dist/src/core/patch-lint-module-registration.d.ts +15 -0
- package/dist/src/core/patch-lint-module-registration.js +88 -0
- package/dist/src/core/patch-lint-mozbuild.js +99 -11
- package/dist/src/core/patch-lint-reexports.d.ts +1 -0
- package/dist/src/core/patch-lint-reexports.js +1 -0
- package/dist/src/core/patch-lint.d.ts +8 -0
- package/dist/src/core/patch-lint.js +84 -6
- package/dist/src/core/patch-lock.d.ts +12 -1
- package/dist/src/core/patch-lock.js +40 -4
- package/dist/src/core/patch-manifest-consistency.js +15 -3
- package/dist/src/core/patch-parse.d.ts +8 -0
- package/dist/src/core/patch-parse.js +10 -0
- package/dist/src/core/patch-policy.d.ts +7 -0
- package/dist/src/core/patch-policy.js +4 -1
- package/dist/src/core/patch-transform.d.ts +10 -0
- package/dist/src/core/patch-transform.js +13 -2
- package/dist/src/core/rebase-session.d.ts +44 -2
- package/dist/src/core/rebase-session.js +114 -17
- package/dist/src/core/register-browser-content.js +2 -1
- package/dist/src/core/register-shared-css.js +2 -1
- package/dist/src/core/smoke-patterns.d.ts +0 -8
- package/dist/src/core/smoke-patterns.js +3 -2
- package/dist/src/core/status-binary.d.ts +55 -0
- package/dist/src/core/status-binary.js +124 -0
- package/dist/src/core/status-classify.d.ts +6 -1
- package/dist/src/core/status-classify.js +101 -73
- package/dist/src/core/test-harness-crash.d.ts +32 -1
- package/dist/src/core/test-harness-crash.js +59 -4
- package/dist/src/core/test-path-scope.js +2 -0
- package/dist/src/core/test-stale-check.js +1 -20
- package/dist/src/core/toolchain-preflight.js +24 -26
- package/dist/src/core/tree-guard.d.ts +1 -1
- package/dist/src/core/tree-guard.js +67 -12
- package/dist/src/core/tree-store.d.ts +86 -10
- package/dist/src/core/tree-store.js +310 -72
- package/dist/src/core/typecheck.js +2 -1
- package/dist/src/core/wire-destroy.js +14 -3
- package/dist/src/core/wire-init.js +37 -40
- package/dist/src/core/wire-subscript.js +11 -3
- package/dist/src/core/wire-utils.js +4 -4
- package/dist/src/core/xpcshell-appdir.js +3 -0
- package/dist/src/errors/base.d.ts +13 -0
- package/dist/src/errors/base.js +13 -0
- package/dist/src/errors/rebase.d.ts +13 -0
- package/dist/src/errors/rebase.js +17 -0
- package/dist/src/types/commands/options.d.ts +86 -1
- package/dist/src/types/commands/patches.d.ts +8 -0
- package/dist/src/types/furnace.d.ts +7 -0
- package/dist/src/utils/build-info.d.ts +31 -0
- package/dist/src/utils/build-info.js +98 -0
- package/dist/src/utils/concurrency.d.ts +8 -0
- package/dist/src/utils/concurrency.js +21 -0
- package/dist/src/utils/errors.d.ts +39 -0
- package/dist/src/utils/errors.js +55 -0
- package/dist/src/utils/fs.js +5 -12
- package/dist/src/utils/logger.d.ts +14 -2
- package/dist/src/utils/logger.js +43 -13
- package/dist/src/utils/options.d.ts +21 -4
- package/dist/src/utils/options.js +26 -6
- package/dist/src/utils/package-root.js +7 -4
- package/dist/src/utils/process-group.js +13 -2
- package/dist/src/utils/stdio-drain.d.ts +28 -0
- package/dist/src/utils/stdio-drain.js +54 -0
- package/dist/src/utils/validation.d.ts +23 -2
- package/dist/src/utils/validation.js +29 -3
- package/package.json +9 -9
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
// SPDX-License-Identifier: EUPL-1.2
|
|
2
2
|
import { readdir } from 'node:fs/promises';
|
|
3
3
|
import { join, relative, resolve, sep } from 'node:path';
|
|
4
|
+
import { GeneralError } from '../errors/base.js';
|
|
5
|
+
import { AmbiguousBuildArtifactsError } from '../errors/build.js';
|
|
4
6
|
import { toError } from '../utils/errors.js';
|
|
5
|
-
import { pathExists, readJson, writeJson } from '../utils/fs.js';
|
|
7
|
+
import { pathExists, readJson, readText, writeJson } from '../utils/fs.js';
|
|
6
8
|
import { verbose } from '../utils/logger.js';
|
|
7
9
|
import { getPlatform } from '../utils/platform.js';
|
|
8
10
|
import { isObject, isString } from '../utils/validation.js';
|
|
@@ -33,7 +35,11 @@ function validateBuildMozinfo(data) {
|
|
|
33
35
|
}
|
|
34
36
|
/**
|
|
35
37
|
* Checks if build artifacts exist in the engine directory.
|
|
36
|
-
* Looks for obj-* directories with a dist subdirectory.
|
|
38
|
+
* Looks for obj-* directories with a dist subdirectory. Detection is
|
|
39
|
+
* deliberately symlink-agnostic — building/running against a symlinked
|
|
40
|
+
* objdir in place is the user's own arrangement; the clone path, where a
|
|
41
|
+
* symlink would route writes into the original build, refuses separately
|
|
42
|
+
* (`assertCloneSafeObjdir` in tree-store.ts).
|
|
37
43
|
* @param engineDir - Path to the engine directory
|
|
38
44
|
* @returns Build artifact check result
|
|
39
45
|
*/
|
|
@@ -135,6 +141,8 @@ export async function hasRunnableBundle(engineDir, binaryName, objDir) {
|
|
|
135
141
|
entries = await readdir(distDir, { withFileTypes: true });
|
|
136
142
|
}
|
|
137
143
|
catch {
|
|
144
|
+
// No readable dist directory means no runnable bundle, which is exactly
|
|
145
|
+
// what the caller needs to know.
|
|
138
146
|
return { runnable: false };
|
|
139
147
|
}
|
|
140
148
|
for (const entry of entries) {
|
|
@@ -285,3 +293,101 @@ export async function attemptMozinfoRewrite(engineDir, objDir) {
|
|
|
285
293
|
...(newMozconfig ? { newMozconfig } : {}),
|
|
286
294
|
};
|
|
287
295
|
}
|
|
296
|
+
/**
|
|
297
|
+
* Shared build-artifact preflight: rejects ambiguous multi-objdir checkouts,
|
|
298
|
+
* artifacts whose metadata points at another tree, and (when
|
|
299
|
+
* `requireExisting`) missing or incomplete builds — each with the actionable
|
|
300
|
+
* message for that case.
|
|
301
|
+
*
|
|
302
|
+
* Takes an already-probed {@link BuildArtifactCheck} rather than probing
|
|
303
|
+
* itself, so it stays a pure validator: callers keep their own
|
|
304
|
+
* `hasBuildArtifacts` call (which their suites already stub) and this function
|
|
305
|
+
* needs no test double of its own.
|
|
306
|
+
*
|
|
307
|
+
* Five commands carried a character-identical copy of this ladder, including
|
|
308
|
+
* the same `ambiguous && objDirs && objDirs.length > 0` expression that
|
|
309
|
+
* `BuildArtifactCheck`'s boolean-plus-optionals shape forces at every reader.
|
|
310
|
+
* The shape itself is unchanged — it has several producers and a documented
|
|
311
|
+
* refusal contract (see the containment predicates below) — but it is now
|
|
312
|
+
* destructured in exactly one place.
|
|
313
|
+
*/
|
|
314
|
+
export function assertBuildArtifacts(engineDir, buildCheck, options) {
|
|
315
|
+
if (buildCheck.ambiguous && buildCheck.objDirs && buildCheck.objDirs.length > 0) {
|
|
316
|
+
throw new AmbiguousBuildArtifactsError(buildCheck.objDirs);
|
|
317
|
+
}
|
|
318
|
+
const mismatchMessage = buildArtifactMismatchMessage(engineDir, buildCheck, options.label);
|
|
319
|
+
if (mismatchMessage) {
|
|
320
|
+
throw new GeneralError(mismatchMessage);
|
|
321
|
+
}
|
|
322
|
+
if (options.requireExisting && !buildCheck.exists) {
|
|
323
|
+
const detail = buildCheck.objDir
|
|
324
|
+
? `Build artifacts incomplete in ${buildCheck.objDir}/`
|
|
325
|
+
: 'No build artifacts found (obj-*/ directory missing)';
|
|
326
|
+
throw new GeneralError(`${options.requirement} ${detail}\n\n${options.remediation}`);
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
/**
|
|
330
|
+
* Post-`mach configure` relocation check for a cloned objdir: confirms
|
|
331
|
+
* configure actually regenerated `<engineDir>/<objDir>` and that none of
|
|
332
|
+
* the four configure-generated root files (`config.status`, `backend.mk`,
|
|
333
|
+
* `Makefile`, `config/autoconf.mk`) still names `forbiddenDir` (the
|
|
334
|
+
* primary engine a relocated clone must never consult). Exit code 0 alone
|
|
335
|
+
* proves neither — a stray MOZCONFIG/MOZ_OBJDIR can steer configure at a
|
|
336
|
+
* different objdir entirely. Nested Makefiles are products of the verified
|
|
337
|
+
* `config.status` and are not scanned; `.deps` files are build products a
|
|
338
|
+
* configure cannot regenerate and are explicitly out of scope — any
|
|
339
|
+
* primary-path strings they retain are read-only staleness corrected by
|
|
340
|
+
* the first in-tree rebuild. Pure checker: returns a human-readable
|
|
341
|
+
* violation, or `undefined` when clean; callers own the error type and
|
|
342
|
+
* remediation copy. Unreadable metadata is itself a violation (fail
|
|
343
|
+
* closed).
|
|
344
|
+
*/
|
|
345
|
+
export async function findObjdirRelocationViolation(args) {
|
|
346
|
+
const { engineDir, objDir, forbiddenDir } = args;
|
|
347
|
+
const objDirPath = join(engineDir, objDir);
|
|
348
|
+
if (!(await pathExists(join(objDirPath, 'config.status')))) {
|
|
349
|
+
return (`${objDir}/config.status was not written — mach configure may have targeted a ` +
|
|
350
|
+
'different objdir (check MOZCONFIG / MOZ_OBJDIR)');
|
|
351
|
+
}
|
|
352
|
+
let mozinfo;
|
|
353
|
+
try {
|
|
354
|
+
mozinfo = validateBuildMozinfo(await readJson(join(objDirPath, 'mozinfo.json')));
|
|
355
|
+
}
|
|
356
|
+
catch (error) {
|
|
357
|
+
return `${objDir}/mozinfo.json could not be read after configure: ${toError(error).message}`;
|
|
358
|
+
}
|
|
359
|
+
const expectedSrcDir = resolve(engineDir);
|
|
360
|
+
const expectedObjDir = resolve(objDirPath);
|
|
361
|
+
const actualSrcDir = mozinfo.topsrcdir ? resolve(mozinfo.topsrcdir) : undefined;
|
|
362
|
+
const actualObjDir = mozinfo.topobjdir ? resolve(mozinfo.topobjdir) : undefined;
|
|
363
|
+
if (actualSrcDir !== expectedSrcDir) {
|
|
364
|
+
return `${objDir}/mozinfo.json topsrcdir resolves to ${actualSrcDir ?? '(absent)'}, expected ${expectedSrcDir}`;
|
|
365
|
+
}
|
|
366
|
+
if (actualObjDir !== expectedObjDir) {
|
|
367
|
+
return `${objDir}/mozinfo.json topobjdir resolves to ${actualObjDir ?? '(absent)'}, expected ${expectedObjDir}`;
|
|
368
|
+
}
|
|
369
|
+
// The canonical no-primary-paths assertion (mirrors the opt-in real-mach
|
|
370
|
+
// proof in scripts/run-full-firefox-integration.mjs): substring search on
|
|
371
|
+
// the resolved primary engine dir is collision-safe against the tree's own
|
|
372
|
+
// paths — `<primary>/.fireforge/trees/<name>/engine` never contains the
|
|
373
|
+
// substring `<primary>/engine`. Scans exactly the configure-generated
|
|
374
|
+
// root files; `config.status` is mandatory (checked above), the rest are
|
|
375
|
+
// optional-if-absent because not every configure backend writes them.
|
|
376
|
+
const forbidden = resolve(forbiddenDir);
|
|
377
|
+
for (const name of ['config.status', 'backend.mk', 'Makefile', 'config/autoconf.mk']) {
|
|
378
|
+
const filePath = join(objDirPath, ...name.split('/'));
|
|
379
|
+
if (name !== 'config.status' && !(await pathExists(filePath)))
|
|
380
|
+
continue;
|
|
381
|
+
let content;
|
|
382
|
+
try {
|
|
383
|
+
content = await readText(filePath);
|
|
384
|
+
}
|
|
385
|
+
catch (error) {
|
|
386
|
+
return `${objDir}/${name} could not be read after configure: ${toError(error).message}`;
|
|
387
|
+
}
|
|
388
|
+
if (content.includes(forbidden)) {
|
|
389
|
+
return `${objDir}/${name} still contains the primary engine path ${forbidden}`;
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
return undefined;
|
|
393
|
+
}
|
|
@@ -27,6 +27,22 @@ export interface MarionettePortProbeResult {
|
|
|
27
27
|
/** Details about the holder, when the probe recovered them. */
|
|
28
28
|
holder?: MarionettePortHolder;
|
|
29
29
|
}
|
|
30
|
+
/** A Firefox-family process launched from this project's built bundle. */
|
|
31
|
+
export interface RunningBundleProcess {
|
|
32
|
+
pid: number;
|
|
33
|
+
commandLine: string;
|
|
34
|
+
}
|
|
35
|
+
/** Pure parser kept exported so platform output handling is regression-testable. */
|
|
36
|
+
export declare function parseProcessList(stdout: string, launchableBinary: string): RunningBundleProcess[];
|
|
37
|
+
/**
|
|
38
|
+
* Refuses a browser-harness launch when this objdir's app is already alive,
|
|
39
|
+
* or terminates the parent when the operator explicitly opted into stale
|
|
40
|
+
* browser cleanup. This closes the no-listening-port variant of the stale
|
|
41
|
+
* Marionette process failure.
|
|
42
|
+
*/
|
|
43
|
+
export declare function ensureLaunchableBrowserNotRunning(launchableBinary: string, options?: {
|
|
44
|
+
killStaleBrowser?: boolean;
|
|
45
|
+
}): Promise<void>;
|
|
30
46
|
/**
|
|
31
47
|
* Probes whether the Marionette port is currently bound by a
|
|
32
48
|
* listener. The probe is best-effort: missing tooling returns
|
|
@@ -45,6 +45,88 @@ const BROWSER_BASENAMES = new Set([
|
|
|
45
45
|
'mybrowser',
|
|
46
46
|
'thunderbird',
|
|
47
47
|
]);
|
|
48
|
+
/**
|
|
49
|
+
* Finds browser processes whose command line names the exact launchable
|
|
50
|
+
* binary from this project's objdir. Unlike the Marionette-port probe, this
|
|
51
|
+
* also catches a wedged browser that survived a harness timeout but no longer
|
|
52
|
+
* owns the control port. Best-effort: unavailable process-list tooling yields
|
|
53
|
+
* an empty result rather than blocking tests.
|
|
54
|
+
*/
|
|
55
|
+
async function findRunningBundleProcesses(launchableBinary) {
|
|
56
|
+
try {
|
|
57
|
+
if (process.platform === 'win32') {
|
|
58
|
+
const escapedPath = launchableBinary.replaceAll("'", "''");
|
|
59
|
+
const script = `Get-CimInstance Win32_Process | Where-Object { $_.ExecutablePath -eq '${escapedPath}' } | ` +
|
|
60
|
+
'ForEach-Object { Write-Output ("$($_.ProcessId) $($_.CommandLine)") }';
|
|
61
|
+
const result = await exec('powershell.exe', [
|
|
62
|
+
'-NoProfile',
|
|
63
|
+
'-NonInteractive',
|
|
64
|
+
'-Command',
|
|
65
|
+
script,
|
|
66
|
+
]);
|
|
67
|
+
return parseProcessList(result.stdout, launchableBinary);
|
|
68
|
+
}
|
|
69
|
+
const result = await exec('ps', ['-axo', 'pid=,args=']);
|
|
70
|
+
return parseProcessList(result.stdout, launchableBinary);
|
|
71
|
+
}
|
|
72
|
+
catch {
|
|
73
|
+
return [];
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
/** Pure parser kept exported so platform output handling is regression-testable. */
|
|
77
|
+
export function parseProcessList(stdout, launchableBinary) {
|
|
78
|
+
const matches = [];
|
|
79
|
+
for (const line of stdout.split(/\r?\n/)) {
|
|
80
|
+
const match = /^\s*(\d+)\s+(.+)$/.exec(line);
|
|
81
|
+
if (!match?.[1] || !match[2]?.includes(launchableBinary))
|
|
82
|
+
continue;
|
|
83
|
+
const pid = Number(match[1]);
|
|
84
|
+
if (!Number.isSafeInteger(pid) || pid <= 0 || pid === process.pid)
|
|
85
|
+
continue;
|
|
86
|
+
matches.push({ pid, commandLine: match[2] });
|
|
87
|
+
}
|
|
88
|
+
return matches;
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Refuses a browser-harness launch when this objdir's app is already alive,
|
|
92
|
+
* or terminates the parent when the operator explicitly opted into stale
|
|
93
|
+
* browser cleanup. This closes the no-listening-port variant of the stale
|
|
94
|
+
* Marionette process failure.
|
|
95
|
+
*/
|
|
96
|
+
export async function ensureLaunchableBrowserNotRunning(launchableBinary, options = {}) {
|
|
97
|
+
const processes = await findRunningBundleProcesses(launchableBinary);
|
|
98
|
+
if (processes.length === 0)
|
|
99
|
+
return;
|
|
100
|
+
const parent = processes.find((candidate) => !candidate.commandLine.includes('-contentproc'));
|
|
101
|
+
const holder = parent ?? processes[0];
|
|
102
|
+
if (!holder)
|
|
103
|
+
return;
|
|
104
|
+
if (options.killStaleBrowser) {
|
|
105
|
+
try {
|
|
106
|
+
if (process.platform === 'win32') {
|
|
107
|
+
await exec('powershell.exe', [
|
|
108
|
+
'-NoProfile',
|
|
109
|
+
'-NonInteractive',
|
|
110
|
+
'-Command',
|
|
111
|
+
`Stop-Process -Id ${holder.pid} -Force`,
|
|
112
|
+
]);
|
|
113
|
+
}
|
|
114
|
+
else {
|
|
115
|
+
process.kill(holder.pid, 'SIGTERM');
|
|
116
|
+
}
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
catch (error) {
|
|
120
|
+
throw new GeneralError(`A browser from this objdir is still running (PID ${holder.pid}), but FireForge could not terminate it: ${toError(error).message}`);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
const killHint = process.platform === 'win32'
|
|
124
|
+
? `Stop-Process -Id ${holder.pid} -Force`
|
|
125
|
+
: `kill ${holder.pid} # or "kill -9 ${holder.pid}" if it doesn't exit`;
|
|
126
|
+
throw new GeneralError(`A browser from this project's objdir is already running (PID ${holder.pid}). ` +
|
|
127
|
+
'It may have survived a previously timed-out or interrupted "fireforge test" run and can wedge the next headed launch. ' +
|
|
128
|
+
`Stop it with "${killHint}", or retry with "--kill-stale-marionette".`);
|
|
129
|
+
}
|
|
48
130
|
/**
|
|
49
131
|
* Returns `true` when the holder's command basename or command-line
|
|
50
132
|
* flags clearly identify it as a Firefox-family browser with
|
|
@@ -110,13 +192,12 @@ async function probeWithLsof(port) {
|
|
|
110
192
|
}
|
|
111
193
|
return { inUse: true, holder: { pid, command, commandLine } };
|
|
112
194
|
}
|
|
113
|
-
catch
|
|
114
|
-
// `lsof` missing, or stdout parse
|
|
115
|
-
// port
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
}
|
|
195
|
+
catch {
|
|
196
|
+
// `lsof` missing, or its stdout did not parse. Either way the port state
|
|
197
|
+
// is unknown, and an unknown port is reported as free so the probe never
|
|
198
|
+
// blocks a run on its own uncertainty. (The errno test that used to sit
|
|
199
|
+
// here returned the same value as this fallthrough, so it decided
|
|
200
|
+
// nothing.)
|
|
120
201
|
return { inUse: false };
|
|
121
202
|
}
|
|
122
203
|
}
|
|
@@ -156,6 +237,8 @@ async function probeWithPowerShell(port) {
|
|
|
156
237
|
return { inUse: true, holder: { pid, command, commandLine } };
|
|
157
238
|
}
|
|
158
239
|
catch {
|
|
240
|
+
// Unparseable netstat/PowerShell output. The port state is unknown, and an unknown port
|
|
241
|
+
// is reported free so the probe never blocks a run on its own uncertainty.
|
|
159
242
|
return { inUse: false };
|
|
160
243
|
}
|
|
161
244
|
}
|
|
@@ -172,6 +255,8 @@ export async function probeMarionettePort(port = DEFAULT_MARIONETTE_PORT) {
|
|
|
172
255
|
platform = getPlatform();
|
|
173
256
|
}
|
|
174
257
|
catch {
|
|
258
|
+
// Unrecognised host platform — no probe strategy applies, so the port is
|
|
259
|
+
// reported free rather than blocking the run.
|
|
175
260
|
return { inUse: false };
|
|
176
261
|
}
|
|
177
262
|
if (platform === 'darwin' || platform === 'linux') {
|
|
@@ -241,7 +326,7 @@ export async function ensureMarionettePortAvailable(port = DEFAULT_MARIONETTE_PO
|
|
|
241
326
|
}
|
|
242
327
|
catch (error) {
|
|
243
328
|
throw new GeneralError(`Marionette port ${port} is held by stale browser ${holder.command} (PID ${holder.pid}), ` +
|
|
244
|
-
`but FireForge could not terminate it: ${error
|
|
329
|
+
`but FireForge could not terminate it: ${toError(error).message}`);
|
|
245
330
|
}
|
|
246
331
|
}
|
|
247
332
|
/**
|
|
@@ -17,6 +17,7 @@ import { mkdtemp, rm } from 'node:fs/promises';
|
|
|
17
17
|
import net from 'node:net';
|
|
18
18
|
import { tmpdir } from 'node:os';
|
|
19
19
|
import { join } from 'node:path';
|
|
20
|
+
import { toError } from '../utils/errors.js';
|
|
20
21
|
import { pathExists } from '../utils/fs.js';
|
|
21
22
|
import { info, warn } from '../utils/logger.js';
|
|
22
23
|
import { ensureMach } from './mach.js';
|
|
@@ -75,7 +76,7 @@ export async function runMarionettePreflight(engineDir, options = {}) {
|
|
|
75
76
|
await ensureMach(engineDir);
|
|
76
77
|
}
|
|
77
78
|
catch (error) {
|
|
78
|
-
return fail('mach-available', `mach not available in engine: ${error.message}`, elapsed());
|
|
79
|
+
return fail('mach-available', `mach not available in engine: ${toError(error).message}`, elapsed());
|
|
79
80
|
}
|
|
80
81
|
// Layer 3: Python that mach requires is discoverable.
|
|
81
82
|
let python;
|
|
@@ -83,7 +84,7 @@ export async function runMarionettePreflight(engineDir, options = {}) {
|
|
|
83
84
|
python = await getPython(engineDir);
|
|
84
85
|
}
|
|
85
86
|
catch (error) {
|
|
86
|
-
return fail('python-available', `Python interpreter required by mach is not available: ${error.message}`, elapsed());
|
|
87
|
+
return fail('python-available', `Python interpreter required by mach is not available: ${toError(error).message}`, elapsed());
|
|
87
88
|
}
|
|
88
89
|
// Layer 4: throwaway browser profile directory is creatable.
|
|
89
90
|
let profileDir;
|
|
@@ -91,7 +92,7 @@ export async function runMarionettePreflight(engineDir, options = {}) {
|
|
|
91
92
|
profileDir = await mkdtemp(join(tmpdir(), 'fireforge-marionette-'));
|
|
92
93
|
}
|
|
93
94
|
catch (error) {
|
|
94
|
-
return fail('profile-creatable', `Could not create a throwaway browser profile in ${tmpdir()}: ${error.message}`, elapsed());
|
|
95
|
+
return fail('profile-creatable', `Could not create a throwaway browser profile in ${tmpdir()}: ${toError(error).message}`, elapsed());
|
|
95
96
|
}
|
|
96
97
|
let child;
|
|
97
98
|
let stderrTail = '';
|
|
@@ -123,7 +124,7 @@ export async function runMarionettePreflight(engineDir, options = {}) {
|
|
|
123
124
|
});
|
|
124
125
|
}
|
|
125
126
|
catch (error) {
|
|
126
|
-
return fail('browser-spawns', `Could not spawn mach run: ${error.message}`, elapsed());
|
|
127
|
+
return fail('browser-spawns', `Could not spawn mach run: ${toError(error).message}`, elapsed());
|
|
127
128
|
}
|
|
128
129
|
const spawnedChild = child;
|
|
129
130
|
child.stderr?.on('data', (data) => {
|
|
@@ -183,7 +184,7 @@ export async function runMarionettePreflight(engineDir, options = {}) {
|
|
|
183
184
|
await rm(profileDir, { recursive: true, force: true });
|
|
184
185
|
}
|
|
185
186
|
catch (error) {
|
|
186
|
-
warn(`Could not clean up marionette preflight profile: ${error.message}`);
|
|
187
|
+
warn(`Could not clean up marionette preflight profile: ${toError(error).message}`);
|
|
187
188
|
}
|
|
188
189
|
}
|
|
189
190
|
}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Patch orchestration — coordinates patch discovery, application, and validation.
|
|
3
3
|
* Pure parsing, content transformation, and lock management are in separate modules.
|
|
4
4
|
*/
|
|
5
|
-
import type { ImportSummary, PatchResult } from '../types/commands/index.js';
|
|
5
|
+
import type { ImportSummary, PatchInfo, PatchMetadata, PatchResult } from '../types/commands/index.js';
|
|
6
6
|
export { PatchError } from '../errors/patch.js';
|
|
7
7
|
export { countPatches, discoverPatches, getAllTargetFilesFromPatch, getTargetFileFromPatch, isNewFilePatch, } from './patch-files.js';
|
|
8
8
|
export { withPatchDirectoryLock } from './patch-lock.js';
|
|
@@ -73,18 +73,25 @@ export declare function matchesUntilFilename(patchFilename: string, needle: stri
|
|
|
73
73
|
*/
|
|
74
74
|
export declare function applyPatchesWithContinue(patchesDir: string, engineDir: string, optionsOrContinue?: ApplyPatchesOptions | boolean): Promise<ImportSummary>;
|
|
75
75
|
/**
|
|
76
|
-
*
|
|
77
|
-
*
|
|
78
|
-
* @param engineDir - Path to the engine directory
|
|
79
|
-
* @param filePath - File path to compute content for
|
|
80
|
-
* @returns Content after all patches applied, or null if file doesn't exist
|
|
76
|
+
* Batched patched-content computation shared by status classification,
|
|
77
|
+
* import's unmanaged-dirty guard, and discard baseline planning.
|
|
81
78
|
*/
|
|
82
|
-
export
|
|
79
|
+
export interface PatchedContentContext {
|
|
80
|
+
/** Manifest rows, so callers don't re-load the manifest per file. */
|
|
81
|
+
manifestPatches: readonly PatchMetadata[];
|
|
82
|
+
/** Cumulative patched content for a file (null if absent at HEAD with no creator). */
|
|
83
|
+
computePatched: (filePath: string) => Promise<string | null>;
|
|
84
|
+
/** Patches affecting a file, sorted by order (from the shared inverted index). */
|
|
85
|
+
getAffectingPatches: (filePath: string) => readonly PatchInfo[];
|
|
86
|
+
/** Patch body text, memoized per patch path across the whole batch. */
|
|
87
|
+
readPatchBody: (patch: PatchInfo) => Promise<string>;
|
|
88
|
+
}
|
|
83
89
|
/**
|
|
84
|
-
* Builds a batched
|
|
85
|
-
*
|
|
86
|
-
*
|
|
87
|
-
*
|
|
88
|
-
*
|
|
90
|
+
* Builds a batched patched-content context that loads the manifest and
|
|
91
|
+
* discovers patch files ONCE for many lookups, and memoizes each patch
|
|
92
|
+
* body read across the batch. The old per-call helper re-ran
|
|
93
|
+
* `loadPatchesManifest` + `discoverPatches` and re-read every affecting
|
|
94
|
+
* patch body for every file — O(dirtyFiles × patches) redundant IO when
|
|
95
|
+
* classifying a broad engine edit session during `status` or `import`.
|
|
89
96
|
*/
|
|
90
|
-
export declare function
|
|
97
|
+
export declare function createPatchedContentContext(patchesDir: string, engineDir: string): Promise<PatchedContentContext>;
|
|
@@ -14,9 +14,9 @@ import { exec } from '../utils/process.js';
|
|
|
14
14
|
import { applyPatchIdempotent, reversePatch } from './git.js';
|
|
15
15
|
import { getFileContentFromHead } from './git-file-ops.js';
|
|
16
16
|
import { discoverPatches } from './patch-files.js';
|
|
17
|
-
import {
|
|
17
|
+
import { loadPatchesManifest } from './patch-manifest.js';
|
|
18
18
|
import { extractAffectedFiles, extractConflictingFiles, isNewFileInPatch } from './patch-parse.js';
|
|
19
|
-
import {
|
|
19
|
+
import { applyPatchTextToContent, extractNewFileContent } from './patch-transform.js';
|
|
20
20
|
// Re-export from split modules so existing import sites continue working
|
|
21
21
|
export { PatchError } from '../errors/patch.js';
|
|
22
22
|
export { countPatches, discoverPatches, getAllTargetFilesFromPatch, getTargetFileFromPatch, isNewFilePatch, } from './patch-files.js';
|
|
@@ -394,33 +394,14 @@ export async function applyPatchesWithContinue(patchesDir, engineDir, optionsOrC
|
|
|
394
394
|
};
|
|
395
395
|
}
|
|
396
396
|
/**
|
|
397
|
-
*
|
|
398
|
-
*
|
|
399
|
-
*
|
|
400
|
-
*
|
|
401
|
-
*
|
|
402
|
-
|
|
403
|
-
export async function computePatchedContent(patchesDir, engineDir, filePath) {
|
|
404
|
-
let content = await getFileContentFromHead(engineDir, filePath);
|
|
405
|
-
// Find all patches affecting this file
|
|
406
|
-
const affectingPatches = await findPatchesAffectingFile(patchesDir, filePath);
|
|
407
|
-
if (affectingPatches.length === 0) {
|
|
408
|
-
return content;
|
|
409
|
-
}
|
|
410
|
-
// Apply each patch in order
|
|
411
|
-
for (const { patch } of affectingPatches) {
|
|
412
|
-
content = await applyPatchToContent(content, patch.path, filePath);
|
|
413
|
-
}
|
|
414
|
-
return content;
|
|
415
|
-
}
|
|
416
|
-
/**
|
|
417
|
-
* Builds a batched variant of {@link computePatchedContent} that loads the
|
|
418
|
-
* manifest and discovers patch files ONCE for many lookups. The per-call
|
|
419
|
-
* function re-runs `loadPatchesManifest` + `discoverPatches` for every
|
|
420
|
-
* file — O(dirtyFiles × patches) redundant IO when classifying a broad
|
|
421
|
-
* engine edit session during `import`.
|
|
397
|
+
* Builds a batched patched-content context that loads the manifest and
|
|
398
|
+
* discovers patch files ONCE for many lookups, and memoizes each patch
|
|
399
|
+
* body read across the batch. The old per-call helper re-ran
|
|
400
|
+
* `loadPatchesManifest` + `discoverPatches` and re-read every affecting
|
|
401
|
+
* patch body for every file — O(dirtyFiles × patches) redundant IO when
|
|
402
|
+
* classifying a broad engine edit session during `status` or `import`.
|
|
422
403
|
*/
|
|
423
|
-
export async function
|
|
404
|
+
export async function createPatchedContentContext(patchesDir, engineDir) {
|
|
424
405
|
const manifest = await loadPatchesManifest(patchesDir);
|
|
425
406
|
const patches = await discoverPatches(patchesDir);
|
|
426
407
|
const patchByFilename = new Map(patches.map((p) => [p.filename, p]));
|
|
@@ -438,11 +419,29 @@ export async function createPatchedContentComputer(patchesDir, engineDir) {
|
|
|
438
419
|
for (const list of affectingByFile.values()) {
|
|
439
420
|
list.sort((a, b) => a.order - b.order);
|
|
440
421
|
}
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
422
|
+
// Promise-memoized so concurrent classification workers never read the
|
|
423
|
+
// same body twice (memoizing the promise, not the value, closes the
|
|
424
|
+
// window between two workers missing the cache at once).
|
|
425
|
+
const bodyPromises = new Map();
|
|
426
|
+
const readPatchBody = (patch) => {
|
|
427
|
+
let body = bodyPromises.get(patch.path);
|
|
428
|
+
if (!body) {
|
|
429
|
+
body = readText(patch.path);
|
|
430
|
+
bodyPromises.set(patch.path, body);
|
|
445
431
|
}
|
|
446
|
-
return
|
|
432
|
+
return body;
|
|
433
|
+
};
|
|
434
|
+
const getAffectingPatches = (filePath) => affectingByFile.get(filePath) ?? [];
|
|
435
|
+
return {
|
|
436
|
+
manifestPatches: manifest?.patches ?? [],
|
|
437
|
+
getAffectingPatches,
|
|
438
|
+
readPatchBody,
|
|
439
|
+
computePatched: async (filePath) => {
|
|
440
|
+
let content = await getFileContentFromHead(engineDir, filePath);
|
|
441
|
+
for (const patch of getAffectingPatches(filePath)) {
|
|
442
|
+
content = applyPatchTextToContent(content, await readPatchBody(patch), filePath);
|
|
443
|
+
}
|
|
444
|
+
return content;
|
|
445
|
+
},
|
|
447
446
|
};
|
|
448
447
|
}
|
|
@@ -10,6 +10,7 @@ import { findAllPatchesForFilesWithDetails, } from './patch-export-coverage.js';
|
|
|
10
10
|
import { addPatchToManifest, loadPatchesManifestForWrite, PATCHES_MANIFEST, savePatchesManifest, } from './patch-manifest.js';
|
|
11
11
|
import { allocatePolicyOrder, enforcePatchPolicy } from './patch-policy.js';
|
|
12
12
|
export { findAllPatchesForFiles, findAllPatchesForFilesWithDetails, findSupersededPatches, isPatchFullyCovered, } from './patch-export-coverage.js';
|
|
13
|
+
import { escapeRegex } from '../utils/regex.js';
|
|
13
14
|
export { mutatePatchMetadata, updatePatchMetadata } from './patch-export-metadata.js';
|
|
14
15
|
export { updatePatchAndMetadata } from './patch-export-update.js';
|
|
15
16
|
/**
|
|
@@ -45,9 +46,6 @@ export function sanitizeName(name) {
|
|
|
45
46
|
.replace(/^-+|-+$/g, '')
|
|
46
47
|
.slice(0, 50);
|
|
47
48
|
}
|
|
48
|
-
function escapeRegExp(value) {
|
|
49
|
-
return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
50
|
-
}
|
|
51
49
|
/**
|
|
52
50
|
* Strips a leading `NNN-<category>-` prefix from a sanitized name slug.
|
|
53
51
|
* Operators frequently pass the DESIRED FILENAME stem to `--name`
|
|
@@ -59,8 +57,8 @@ function escapeRegExp(value) {
|
|
|
59
57
|
*/
|
|
60
58
|
export function stripRedundantCategoryPrefix(sanitizedName, category) {
|
|
61
59
|
const prefixes = [
|
|
62
|
-
new RegExp(`^\\d+-${
|
|
63
|
-
new RegExp(`^${
|
|
60
|
+
new RegExp(`^\\d+-${escapeRegex(category)}-`),
|
|
61
|
+
new RegExp(`^${escapeRegex(category)}-`),
|
|
64
62
|
];
|
|
65
63
|
let stripped = sanitizedName;
|
|
66
64
|
let changed = true;
|
|
@@ -61,9 +61,17 @@ export interface GroupedCheckJsResult {
|
|
|
61
61
|
* the built-in Firefox-globals shim (from `patchLint.checkJsExtraShim`)
|
|
62
62
|
* @param projectRoot - Absolute project root for resolving `extraShimPath`
|
|
63
63
|
* @param mode - Strictness preset plus allowlisted compiler-option overrides
|
|
64
|
+
* @param builtinShimSuffix - Optional shim text appended AFTER the consumer shim
|
|
65
|
+
* @param rootScope - When set, only these repo-relative files become program
|
|
66
|
+
* ROOTS; resolution (and the host allowlist) still spans all of
|
|
67
|
+
* `resolutionOwned`, so a subset root's cross-patch imports type-check
|
|
68
|
+
* against the real owning sources while unrelated owned files are never
|
|
69
|
+
* parsed. `.mjs` files are module-scoped, so a root's diagnostics are
|
|
70
|
+
* identical whether other owned files are roots or mere resolution
|
|
71
|
+
* targets (pinned by the rootScope parity test — FORGE J1c).
|
|
64
72
|
* @returns Diagnostics grouped per owning file plus run-level errors
|
|
65
73
|
*/
|
|
66
|
-
export declare function runCheckJsGrouped(repoDir: string, resolutionOwned: Set<string>, extraShimPath?: string, projectRoot?: string, mode?: CheckJsMode, builtinShimSuffix?: string): Promise<GroupedCheckJsResult>;
|
|
74
|
+
export declare function runCheckJsGrouped(repoDir: string, resolutionOwned: Set<string>, extraShimPath?: string, projectRoot?: string, mode?: CheckJsMode, builtinShimSuffix?: string, rootScope?: ReadonlySet<string>): Promise<GroupedCheckJsResult>;
|
|
67
75
|
/**
|
|
68
76
|
* Flattens a {@link runCheckJsGrouped} run into a single issue list. When
|
|
69
77
|
* `reportScope` is supplied, only diagnostics from files in that set are
|
|
@@ -110,7 +118,7 @@ export declare function invokePatchLintCheckJs(repoDir: string, patchOwnedFiles:
|
|
|
110
118
|
* @param patchLint - The resolved `patchLint` config block
|
|
111
119
|
* @param projectRoot - FireForge project root for shim resolution
|
|
112
120
|
*/
|
|
113
|
-
export declare function runCheckJsTestFilesGrouped(repoDir: string, testFiles: Set<string>, patchLint: PatchLintConfig, projectRoot: string): Promise<GroupedCheckJsResult>;
|
|
121
|
+
export declare function runCheckJsTestFilesGrouped(repoDir: string, testFiles: Set<string>, patchLint: PatchLintConfig, projectRoot: string, rootScope?: ReadonlySet<string>): Promise<GroupedCheckJsResult>;
|
|
114
122
|
/**
|
|
115
123
|
* Grouped variant of {@link invokePatchLintCheckJs}: builds one queue-wide
|
|
116
124
|
* checkJs program over `patchOwnedFiles` and returns its findings grouped by
|
|
@@ -122,5 +130,19 @@ export declare function runCheckJsTestFilesGrouped(repoDir: string, testFiles: S
|
|
|
122
130
|
* @param patchOwnedFiles - Every patch-owned `.sys.mjs` in the queue
|
|
123
131
|
* @param patchLint - The resolved `patchLint` config block
|
|
124
132
|
* @param projectRoot - FireForge project root for shim resolution
|
|
133
|
+
* @param rootScope - Optional subset of files to use as program roots
|
|
134
|
+
* (`--patches`); resolution still spans the whole queue (FORGE J1c)
|
|
125
135
|
*/
|
|
126
|
-
export declare function invokePatchLintCheckJsGrouped(repoDir: string, patchOwnedFiles: Set<string>, patchLint: PatchLintConfig, projectRoot: string): Promise<GroupedCheckJsResult>;
|
|
136
|
+
export declare function invokePatchLintCheckJsGrouped(repoDir: string, patchOwnedFiles: Set<string>, patchLint: PatchLintConfig, projectRoot: string, rootScope?: ReadonlySet<string>): Promise<GroupedCheckJsResult>;
|
|
137
|
+
/**
|
|
138
|
+
* Cheap probe reproducing the only run-level ("global") checkJs findings
|
|
139
|
+
* the build path can produce — a missing `typescript` package and an
|
|
140
|
+
* unreadable consumer shim (`checkJsExtraShim`, and `checkJsTestShim`
|
|
141
|
+
* when `checkJsTestFiles` is on). The built program itself never
|
|
142
|
+
* contributes globals (see {@link runCheckJsGrouped}), so a warm
|
|
143
|
+
* all-cache-hit run can satisfy the "warm never reports less than cold"
|
|
144
|
+
* invariant (FORGE F5) with this probe instead of building the whole
|
|
145
|
+
* TypeScript program. Issue objects are byte-identical to the build
|
|
146
|
+
* path's, deduplicated by message like {@link runCheckJsTestFilesGrouped}.
|
|
147
|
+
*/
|
|
148
|
+
export declare function probeCheckJsGlobalIssues(patchLint: PatchLintConfig, projectRoot: string): Promise<PatchLintIssue[]>;
|