Skip to content
Closed
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
7 changes: 7 additions & 0 deletions src/analyze/duplicate-dependencies.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,13 @@ function resolveDuplicateDependencies(
): Map<string, Version[]> {
const resolvedDependencies: Map<string, Version[]> = new Map();
for (const pkg of lockfile.packages) {
// npm workspace links appear in package-lock.json without a version.
// They are not real installed versions and should not participate in
// duplicate-version analysis.
if (typeof pkg.version !== 'string' || pkg.version.length === 0) {
continue;
}

const entry: Version = {
version: pkg.version,
parents: []
Expand Down
26 changes: 26 additions & 0 deletions src/test/__snapshots__/duplicate-dependencies.test.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,32 @@ exports[`Duplicate Dependency Detection > should detect multiple versions 1`] =
}
`;

exports[`Duplicate Dependency Detection > should ignore workspace link entries without versions 1`] = `
{
"messages": [
{
"message": "[duplicate dependency] shared-lib has 2 installed versions:
1.0.0 via the following 1 package(s) package-a@1.0.0
2.0.0 via the following 1 package(s) package-b@1.0.0
💡 Suggestions
- Consider upgrading consuming packages as this may resolve this duplicate version.
",
"score": 0,
"severity": "warning",
},
],
"stats": {
"extraStats": [
{
"label": "Duplicate Dependency Count",
"name": "duplicateDependencyCount",
"value": 1,
},
],
},
}
`;

exports[`Duplicate Dependency Detection > should not detect duplicates when there are none 1`] = `
{
"messages": [],
Expand Down
77 changes: 77 additions & 0 deletions src/test/duplicate-dependencies.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -182,4 +182,81 @@ describe('Duplicate Dependency Detection', () => {

expect(stats).toMatchSnapshot();
});

it('should ignore workspace link entries without versions', async () => {
const sharedLibv1: ParsedDependency = {
name: 'shared-lib',
version: '1.0.0',
dependencies: [],
devDependencies: [],
optionalDependencies: [],
peerDependencies: []
};
const sharedLibv2: ParsedDependency = {
name: 'shared-lib',
version: '2.0.0',
dependencies: [],
devDependencies: [],
optionalDependencies: [],
peerDependencies: []
};
const workspaceLink = {
name: 'react-native-dotgrid',
dependencies: [],
devDependencies: [],
optionalDependencies: [],
peerDependencies: []
} as unknown as ParsedDependency;
const packageA: ParsedDependency = {
name: 'package-a',
version: '1.0.0',
dependencies: [sharedLibv1],
devDependencies: [],
peerDependencies: [],
optionalDependencies: []
};
const packageB: ParsedDependency = {
name: 'package-b',
version: '1.0.0',
dependencies: [sharedLibv2],
devDependencies: [],
peerDependencies: [],
optionalDependencies: []
};

context = {
fs: fileSystem,
root: '.',
messages: [],
stats: {
name: 'unknown',
version: 'unknown',
dependencyCount: {
production: 0,
development: 0
},
extraStats: []
},
lockfile: {
type: 'npm',
packages: [workspaceLink, packageA, packageB, sharedLibv1, sharedLibv2],
root: {
name: 'root-package',
version: '1.0.0',
dependencies: [workspaceLink, packageA, packageB],
devDependencies: [],
optionalDependencies: [],
peerDependencies: []
}
},
packageFile: {
name: 'test-package',
version: '1.0.0'
}
};

const stats = await runDuplicateDependencyAnalysis(context);

expect(stats).toMatchSnapshot();
});
});