-
Notifications
You must be signed in to change notification settings - Fork 2.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix(core): ensure correct package name matching when parsing pnpm lock file #17613
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -18,7 +18,7 @@ import { | |
ProjectGraph, | ||
ProjectGraphExternalNode, | ||
} from '../../../config/project-graph'; | ||
import { fileHasher, hashArray } from '../../../hasher/file-hasher'; | ||
import { hashArray } from '../../../hasher/file-hasher'; | ||
|
||
export function parsePnpmLockfile( | ||
lockFileContent: string, | ||
|
@@ -43,39 +43,40 @@ function addNodes( | |
const nodes: Map<string, Map<string, ProjectGraphExternalNode>> = new Map(); | ||
|
||
Object.entries(data.packages).forEach(([key, snapshot]) => { | ||
const packageName = findPackageName(key, snapshot, data); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Instead of single value we return an array |
||
const rawVersion = findVersion(key, packageName); | ||
const version = parseBaseVersion(rawVersion, isV6); | ||
|
||
// we don't need to keep duplicates, we can just track the keys | ||
const existingNode = nodes.get(packageName)?.get(version); | ||
if (existingNode) { | ||
keyMap.set(key, existingNode); | ||
return; | ||
} | ||
findPackageNames(key, snapshot, data).forEach((packageName) => { | ||
const rawVersion = findVersion(key, packageName); | ||
const version = parseBaseVersion(rawVersion, isV6); | ||
|
||
// we don't need to keep duplicates, we can just track the keys | ||
const existingNode = nodes.get(packageName)?.get(version); | ||
if (existingNode) { | ||
keyMap.set(key, existingNode); | ||
return; | ||
} | ||
|
||
const node: ProjectGraphExternalNode = { | ||
type: 'npm', | ||
name: version ? `npm:${packageName}@${version}` : `npm:${packageName}`, | ||
data: { | ||
version, | ||
packageName, | ||
hash: | ||
snapshot.resolution?.['integrity'] || | ||
hashArray( | ||
snapshot.resolution?.['tarball'] | ||
? [snapshot.resolution['tarball']] | ||
: [packageName, version] | ||
), | ||
}, | ||
}; | ||
|
||
keyMap.set(key, node); | ||
if (!nodes.has(packageName)) { | ||
nodes.set(packageName, new Map([[version, node]])); | ||
} else { | ||
nodes.get(packageName).set(version, node); | ||
} | ||
const node: ProjectGraphExternalNode = { | ||
type: 'npm', | ||
name: version ? `npm:${packageName}@${version}` : `npm:${packageName}`, | ||
data: { | ||
version, | ||
packageName, | ||
hash: | ||
snapshot.resolution?.['integrity'] || | ||
hashArray( | ||
snapshot.resolution?.['tarball'] | ||
? [snapshot.resolution['tarball']] | ||
: [packageName, version] | ||
), | ||
}, | ||
}; | ||
|
||
keyMap.set(key, node); | ||
if (!nodes.has(packageName)) { | ||
nodes.set(packageName, new Map([[version, node]])); | ||
} else { | ||
nodes.get(packageName).set(version, node); | ||
} | ||
}); | ||
}); | ||
|
||
const hoistedDeps = loadPnpmHoistedDepsDefinition(); | ||
|
@@ -280,11 +281,14 @@ function findVersion(key: string, packageName: string): string { | |
return key; | ||
} | ||
|
||
function findPackageName( | ||
function findPackageNames( | ||
key: string, | ||
snapshot: PackageSnapshot, | ||
data: Lockfile | ||
): string { | ||
): string[] { | ||
const packageNames = new Set<string>(); | ||
const originalPackageName = extractNameFromKey(key); | ||
|
||
const matchPropValue = (record: Record<string, string>): string => { | ||
if (!record) { | ||
return undefined; | ||
|
@@ -293,6 +297,13 @@ function findPackageName( | |
if (index > -1) { | ||
return Object.keys(record)[index]; | ||
} | ||
// check if non aliased name is found | ||
if ( | ||
record[originalPackageName] && | ||
key.startsWith(`/${originalPackageName}/${record[originalPackageName]}`) | ||
) { | ||
return originalPackageName; | ||
} | ||
}; | ||
|
||
const matchedDependencyName = ( | ||
|
@@ -307,25 +318,28 @@ function findPackageName( | |
|
||
// snapshot already has a name | ||
if (snapshot.name) { | ||
return snapshot.name; | ||
packageNames.add(snapshot.name); | ||
} | ||
// it'a a root dependency | ||
const rootDependencyName = | ||
matchedDependencyName(data.importers['.']) || | ||
// only root importers have devDependencies | ||
matchPropValue(data.importers['.'].devDependencies); | ||
if (rootDependencyName) { | ||
return rootDependencyName; | ||
packageNames.add(rootDependencyName); | ||
} | ||
// find a snapshot that has a dependency that points to this snapshot | ||
const snapshots = Object.values(data.packages); | ||
for (let i = 0; i < snapshots.length; i++) { | ||
const dependencyName = matchedDependencyName(snapshots[i]); | ||
if (dependencyName) { | ||
return dependencyName; | ||
packageNames.add(dependencyName); | ||
} | ||
} | ||
return extractNameFromKey(key); | ||
if (packageNames.size === 0) { | ||
packageNames.add(originalPackageName); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Package can be overridden in the version meta which we don't parse at the moment (version 5.x has this info hashed) so we add this explicitly if not found otherwise: The following line says that despite dependency is [email protected] we will use 4.8.4 so that would end up being the only installed version:
|
||
} | ||
return Array.from(packageNames); | ||
} | ||
|
||
function getVersion(key: string, packageName: string): string { | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unused import