feat: provide wantedLockfile to shouldForceResolve (#10330)

This commit is contained in:
Trevor Burnham
2025-12-18 19:41:10 -05:00
committed by GitHub
parent e46a652939
commit 8b5dcaac4d
4 changed files with 42 additions and 4 deletions

View File

@@ -69,9 +69,10 @@ export interface CustomResolver {
* Use this to implement custom cache invalidation logic (e.g., time-based expiry, version checks).
*
* @param wantedDependency - The dependency to check for force re-resolution
* @param wantedLockfile - The current lockfile contents
* @returns true to force re-resolution of all dependencies
*/
shouldForceResolve?: (wantedDependency: WantedDependency) => boolean | Promise<boolean>
shouldForceResolve?: (wantedDependency: WantedDependency, wantedLockfile: LockfileObject) => boolean | Promise<boolean>
}
export interface CustomFetcher {

View File

@@ -146,7 +146,7 @@ interface CustomResolver {
resolve?: (wantedDependency: WantedDependency, opts: ResolveOptions) => ResolveResult | Promise<ResolveResult>
// Force resolution check
shouldForceResolve?: (wantedDependency: WantedDependency) => boolean | Promise<boolean>
shouldForceResolve?: (wantedDependency: WantedDependency, wantedLockfile: LockfileObject) => boolean | Promise<boolean>
}
```
@@ -164,7 +164,7 @@ interface CustomFetcher {
* `canResolve(wantedDependency)` - Returns `true` if this resolver can resolve the given package descriptor
* `resolve(wantedDependency, opts)` - Resolves a package descriptor to a resolution. Should return an object with `id` and `resolution`
* `shouldForceResolve(wantedDependency)` - Return `true` to trigger full resolution of all packages (skipping the "Lockfile is up to date" optimization)
* `shouldForceResolve(wantedDependency, wantedLockfile)` - Return `true` to trigger full resolution of all packages (skipping the "Lockfile is up to date" optimization). The lockfile contents are provided to enable comparisons with the latest resolved version.
**Custom Fetcher Methods:**

View File

@@ -36,7 +36,7 @@ export async function checkCustomResolverForceResolve (
if (canResolve && customResolver.shouldForceResolve) {
// eslint-disable-next-line no-await-in-loop
const shouldForce = await customResolver.shouldForceResolve(wantedDependency)
const shouldForce = await customResolver.shouldForceResolve(wantedDependency, wantedLockfile)
if (shouldForce) {
return true

View File

@@ -563,4 +563,41 @@ describe('checkCustomResolverForceResolve', () => {
expect(result).toBe(false)
})
test('passes lockfile to shouldForceResolve', async () => {
let receivedLockfile: LockfileObject | undefined
const lockfile: LockfileObject = {
lockfileVersion: '9.0',
importers: {
'.': {
specifiers: { 'test-pkg': '1.0.0' },
dependencies: { 'test-pkg': '1.0.0' },
},
} as any, // eslint-disable-line @typescript-eslint/no-explicit-any
packages: {
'/test-pkg@1.0.0': {
resolution: { tarball: 'http://example.com/test-pkg-1.0.0.tgz', integrity: 'sha512-test' },
},
} as any, // eslint-disable-line @typescript-eslint/no-explicit-any
}
const resolver: CustomResolver = {
canResolve: () => true,
shouldForceResolve: (_wantedDep, wantedLockfile) => {
receivedLockfile = wantedLockfile
return false
},
}
const projects: ProjectWithManifest[] = [
{
id: '.' as ProjectId,
manifest: {
dependencies: { 'test-pkg': '1.0.0' },
} as any, // eslint-disable-line @typescript-eslint/no-explicit-any
},
]
await checkCustomResolverForceResolve([resolver], lockfile, projects)
expect(receivedLockfile).toBe(lockfile)
})
})