/** * One candidate importer to resolve a package version against, identified by * its path relative to the workspace root (POSIX, `.` for the root) and the * version range it declares for the package, if any. */ export interface ImporterCandidate { relPath: string; declaredRange?: string; } /** * Describes the package we want to resolve a version for. * * `importers` is the chain of candidate importers ordered from nearest (the * workspace member that owns the Playwright config, or a deeper directory) up * to the workspace root. This mirrors Node's upward module resolution: a * package required from a deep directory resolves to the first `node_modules` * found walking up the tree, which may belong to a physically-enclosing * workspace member rather than the root. Each lockfile format uses this chain * differently (see the individual parsers). */ export interface LockfilePackageQuery { /** The package whose version we want, e.g. `@playwright/test`. */ packageName: string; /** Candidate importers, ordered nearest → workspace root. */ importers: ImporterCandidate[]; } /** * Resolves a package version from an npm `package-lock.json`. * * Only lockfileVersion 2 and 3 are supported, which key the flat `packages` * map by node_modules path relative to the workspace root (e.g. * `node_modules/@playwright/test` when hoisted, or * `packages/a/node_modules/@playwright/test` when a member pins a conflicting * version). lockfileVersion 1 (npm 6) only has a nested `dependencies` tree and * is unsupported — we return `undefined` so the caller falls back. * * The map keys are physical node_modules paths, so resolution is a single * lexical walk up the path segments of the *nearest* importer — that walk * already visits every ancestor up to the root and finds the enclosing copy. * The walk, not the candidate list, is the resolution mechanism; iterating the * other candidates would be redundant. */ export declare function parseNpmLockfileVersion(content: string, query: LockfilePackageQuery): string | undefined; /** * Resolves a package version from a `pnpm-lock.yaml`. * * pnpm records a per-importer resolved version under * `importers..{dependencies,devDependencies,optionalDependencies}`. * The value is a bare version string (lockfile v5) or a `{ specifier, version }` * map (v6/v9). Catalog entries still carry a resolved `version`, so they need * no special handling. The version may carry a pnpm peer suffix, which we * strip. * * We walk the importer chain nearest → root and return the first importer that * declares the package. With pnpm's default isolated linker a package required * from a non-declaring member resolves up the filesystem to the nearest * enclosing member that does declare it — which is exactly the nearest * declaring importer in this chain. (The `node-linker=hoisted` and PnP layouts * can diverge; those degrade to the caller's node_modules fallback.) */ export declare function parsePnpmLockfileVersion(content: string, query: LockfilePackageQuery): string | undefined; /** * Resolves a package version from a bun text lockfile (`bun.lock`). * * bun.lock is JSONC. The `packages` map keys the hoisted copy by bare name * (`@playwright/test`) and a member's pinned override by the declaring member's * *name* (`some-package/@playwright/test`). Member names are recorded in * `workspaces..name` (the root uses the `""` key). Each entry's value * is an array whose first element is `name@version`. * * Resolution is two-phase: probe every candidate's member-scoped key nearest → * root first, and only fall back to the hoisted key once all member-scoped * probes miss. A naive per-candidate "first hit wins" would return the hoisted * version as soon as the nearest (non-declaring) member is reached, masking a * deeper member's pinned override that Node would actually resolve. * * The binary lockfile (`bun.lockb`) is not handled here; the caller skips it. */ export declare function parseBunLockfileVersion(content: string, query: LockfilePackageQuery): string | undefined; /** * Resolves a package version from a `yarn.lock`, dispatching to the classic or * berry parser. Berry lockfiles carry a `__metadata:` block; classic ones do * not. The lockfile is parsed once, then resolved across the importer chain. */ export declare function parseYarnLockfileVersion(content: string, query: LockfilePackageQuery): string | undefined;