Skip to content
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): improve packages recognition when the package version is an external package #29529

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
119 changes: 118 additions & 1 deletion packages/nx/src/plugins/js/lock-file/yarn-parser.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -937,6 +937,123 @@ __metadata:
}
`);
});

it('should parse external module by yarn classic', () => {
const lockFile = `# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1


"@babel/[email protected]", "@babel/runtime@^7.1.2", "@babel/runtime@^7.10.3", "@babel/runtime@^7.12.1", "@babel/runtime@^7.12.13", "@babel/runtime@^7.12.5", "@babel/runtime@^7.17.8", "@babel/runtime@^7.20.13", "@babel/runtime@^7.21.0", "@babel/runtime@^7.22.6", "@babel/runtime@^7.23.2", "@babel/runtime@^7.23.8", "@babel/runtime@^7.23.9", "@babel/runtime@^7.24.4", "@babel/runtime@^7.25.9", "@babel/runtime@^7.5.5", "@babel/runtime@^7.6.2", "@babel/runtime@^7.6.3", "@babel/runtime@^7.7.2", "@babel/runtime@^7.7.6", "@babel/runtime@^7.8.4", "@babel/runtime@^7.9.2":
version "7.26.0"
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.26.0.tgz#8600c2f595f277c60815256418b85356a65173c1"
integrity sha512-FDSOghenHTiToteC/QRlv2q3DhPZ/oOXTBoirfWNx1Cx3TMVcGWQtMMmQcSvb/JjpNeGzx8Pq/b4fKEJuWm1sw==

"@docusaurus/[email protected]":
version "3.7.0"
resolved "https://registry.yarnpkg.com/@docusaurus/core/-/core-3.7.0.tgz#e871586d099093723dfe6de81c1ce610aeb20292"
integrity sha512-b0fUmaL+JbzDIQaamzpAFpTviiaU4cX3Qz8cuo14+HGBCwa0evEK0UYCBFY3n4cLzL8Op1BueeroUD2LYAIHbQ==
dependencies:
"@docusaurus/module-type-aliases" "3.7.0"
react-helmet-async "npm:@slorber/[email protected]"

"@docusaurus/[email protected]":
version "3.7.0"
resolved "https://registry.yarnpkg.com/@docusaurus/module-type-aliases/-/module-type-aliases-3.7.0.tgz#15c0745b829c6966c5b3b2c2527c72b54830b0e5"
integrity sha512-g7WdPqDNaqA60CmBrr0cORTrsOit77hbsTj7xE2l71YhBn79sxdm7WMK7wfhcaafkbpIh7jv5ef5TOpf1Xv9Lg==
dependencies:
react-helmet-async "npm:@slorber/react-helmet-async@*"

"react-helmet-async@npm:@slorber/react-helmet-async@*", "react-helmet-async@npm:@slorber/[email protected]":
version "1.3.0"
resolved "https://registry.yarnpkg.com/@slorber/react-helmet-async/-/react-helmet-async-1.3.0.tgz#11fbc6094605cf60aa04a28c17e0aab894b4ecff"
integrity sha512-e9/OK8VhwUSc67diWI8Rb3I0YgI9/SBQtnhe9aEuK6MhZm7ntZZimXgwXnd8W96YTmSOb9M4d8LwhRZyhWr/1A==
dependencies:
"@babel/runtime" "^7.12.5"
`;

const packageJson: PackageJson = {
name: '@my-ns/example',
version: '0.0.1',
type: 'commonjs',
dependencies: {
'@docusaurus/core': '3.7.0',
},
};

const hash = uniq('mock-hash');
const externalNodes = getYarnLockfileNodes(lockFile, hash, packageJson);
const pg = {
nodes: {},
dependencies: {},
externalNodes,
};
const ctx: CreateDependenciesContext = {
projects: {},
externalNodes,
fileMap: {
nonProjectFiles: [],
projectFileMap: {},
},
filesToProcess: {
nonProjectFiles: [],
projectFileMap: {},
},
nxJsonConfiguration: null,
workspaceRoot: '/virtual',
};
const dependencies = getYarnLockfileDependencies(lockFile, hash, ctx);
const builder = new ProjectGraphBuilder(pg);
for (const dep of dependencies) {
builder.addDependency(
dep.source,
dep.target,
dep.type,
'sourceFile' in dep ? dep.sourceFile : null
);
}
const graph = builder.getUpdatedProjectGraph();

expect(graph.externalNodes).toMatchInlineSnapshot(`
{
"npm:@babel/[email protected]": {
"data": {
"hash": "sha512-FDSOghenHTiToteC/QRlv2q3DhPZ/oOXTBoirfWNx1Cx3TMVcGWQtMMmQcSvb/JjpNeGzx8Pq/b4fKEJuWm1sw==",
"packageName": "@babel/runtime",
"version": "7.26.0",
},
"name": "npm:@babel/[email protected]",
"type": "npm",
},
"npm:@docusaurus/[email protected]": {
"data": {
"hash": "sha512-b0fUmaL+JbzDIQaamzpAFpTviiaU4cX3Qz8cuo14+HGBCwa0evEK0UYCBFY3n4cLzL8Op1BueeroUD2LYAIHbQ==",
"packageName": "@docusaurus/core",
"version": "3.7.0",
},
"name": "npm:@docusaurus/[email protected]",
"type": "npm",
},
"npm:@docusaurus/[email protected]": {
"data": {
"hash": "sha512-g7WdPqDNaqA60CmBrr0cORTrsOit77hbsTj7xE2l71YhBn79sxdm7WMK7wfhcaafkbpIh7jv5ef5TOpf1Xv9Lg==",
"packageName": "@docusaurus/module-type-aliases",
"version": "3.7.0",
},
"name": "npm:@docusaurus/[email protected]",
"type": "npm",
},
"npm:react-helmet-async": {
"data": {
"hash": "sha512-e9/OK8VhwUSc67diWI8Rb3I0YgI9/SBQtnhe9aEuK6MhZm7ntZZimXgwXnd8W96YTmSOb9M4d8LwhRZyhWr/1A==",
"packageName": "react-helmet-async",
"version": "npm:@slorber/react-helmet-async@*",
},
"name": "npm:react-helmet-async",
"type": "npm",
},
}
`);
});
});
});

Expand Down Expand Up @@ -2809,5 +2926,5 @@ __metadata:
});

function uniq(str: string) {
return `str-${(Math.random() * 10000).toFixed(0)}`;
return `${str}-${(Math.random() * 10000).toFixed(0)}`;
}
30 changes: 17 additions & 13 deletions packages/nx/src/plugins/js/lock-file/yarn-parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ export function getYarnLockfileNodes(
// yarn classic splits keys when parsing so we need to stich them back together
const groupedDependencies = groupDependencies(dependencies, isBerry);

return getNodes(groupedDependencies, packageJson, keyMap, isBerry);
return getNodes(groupedDependencies, packageJson, isBerry);
}

export function getYarnLockfileDependencies(
Expand All @@ -92,7 +92,7 @@ export function getYarnLockfileDependencies(
// yarn classic splits keys when parsing so we need to stich them back together
const groupedDependencies = groupDependencies(dependencies, isBerry);

return getDependencies(groupedDependencies, keyMap, ctx);
return getDependencies(groupedDependencies, ctx);
}

function getPackageNameKeyPairs(keys: string): Map<string, Set<string>> {
Expand All @@ -111,7 +111,6 @@ function getPackageNameKeyPairs(keys: string): Map<string, Set<string>> {
function getNodes(
dependencies: Record<string, YarnDependency>,
packageJson: NormalizedPackageJson,
keyMap: Map<string, ProjectGraphExternalNode>,
isBerry: boolean
) {
const nodes: Map<string, Map<string, ProjectGraphExternalNode>> = new Map();
Expand All @@ -131,7 +130,12 @@ function getNodes(
nameKeyPairs.forEach((keySet, packageName) => {
const keysArray = Array.from(keySet);
// use key relevant to the package name
const version = findVersion(packageName, keysArray[0], snapshot, isBerry);
const [version, isAlias] = findVersion(
packageName,
keysArray[0],
snapshot,
isBerry
);

// use keys linked to the extracted package name
keysArray.forEach((key) => {
Expand All @@ -144,9 +148,10 @@ function getNodes(

const node: ProjectGraphExternalNode = {
type: 'npm',
name: version
? `npm:${packageName}@${version}`
: `npm:${packageName}`,
name:
version && !isAlias
? `npm:${packageName}@${version}`
: `npm:${packageName}`,
data: {
version,
packageName,
Expand Down Expand Up @@ -229,15 +234,15 @@ function findVersion(
key: string,
snapshot: YarnDependency,
isBerry: boolean
): string {
): [string, boolean] | [string] {
const versionRange = key.slice(key.indexOf('@', 1) + 1);
// check for alias packages
const isAlias = isBerry
? snapshot.resolution && !snapshot.resolution.startsWith(`${packageName}@`)
: versionRange.startsWith('npm:');

if (isAlias) {
return versionRange;
return [versionRange, true];
}
// check for berry tarball packages
if (
Expand All @@ -247,14 +252,14 @@ function findVersion(
snapshot.resolution.split('::')[0] !==
`${packageName}@npm:${snapshot.version}`
) {
return snapshot.resolution.slice(packageName.length + 1);
return [snapshot.resolution.slice(packageName.length + 1)];
}

if (!isBerry && isTarballPackage(versionRange, snapshot)) {
return snapshot.resolved;
return [snapshot.resolved];
}
// otherwise it's a standard version
return snapshot.version;
return [snapshot.version];
}

// check if snapshot represents tarball package
Expand Down Expand Up @@ -289,7 +294,6 @@ function getHoistedVersion(packageName: string): string {

function getDependencies(
dependencies: Record<string, YarnDependency>,
keyMap: Map<string, ProjectGraphExternalNode>,
ctx: CreateDependenciesContext
) {
const projectGraphDependencies: RawProjectGraphDependency[] = [];
Expand Down
Loading