Skip to content

Commit 028acdb

Browse files
committed
feat: add alias support for npm v1 v2 and v3
1 parent f8e6119 commit 028acdb

File tree

15 files changed

+4385
-35
lines changed

15 files changed

+4385
-35
lines changed
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import * as cloneDeep from 'lodash.clonedeep';
2+
export const rewriteAliasesInNpmLockV1 = (lockfileContent: string): string => {
3+
const jsonLockfile = JSON.parse(lockfileContent);
4+
for (const pkg in jsonLockfile.dependencies) {
5+
if (jsonLockfile.dependencies[pkg].version.startsWith('npm:')) {
6+
const aliasName = jsonLockfile.dependencies[pkg].version.substring(
7+
4,
8+
jsonLockfile.dependencies[pkg].version.lastIndexOf('@'),
9+
);
10+
jsonLockfile.dependencies[aliasName] = cloneDeep(
11+
jsonLockfile.dependencies[pkg],
12+
);
13+
jsonLockfile.dependencies[aliasName].version = jsonLockfile.dependencies[
14+
pkg
15+
].version.substring(
16+
jsonLockfile.dependencies[pkg].version.lastIndexOf('@') + 1,
17+
jsonLockfile.dependencies[pkg].version.length,
18+
);
19+
delete jsonLockfile.dependencies[pkg];
20+
}
21+
}
22+
23+
return JSON.stringify(jsonLockfile);
24+
};
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import { NpmLockPkg } from '../dep-graph-builders/npm-lock-v2/extract-npm-lock-v2-pkgs';
2+
3+
export const rewriteAliasesInNpmLockV2 = (
4+
lockfilePackages: Record<string, NpmLockPkg>,
5+
): Record<string, NpmLockPkg> => {
6+
// 1. Rewrite top level "" packages in "".dependencies
7+
const rootPkg = lockfilePackages[''];
8+
const lockFileToReturn: Record<string, NpmLockPkg> = lockfilePackages;
9+
if (rootPkg && rootPkg.dependencies) {
10+
const dependencies = rootPkg.dependencies;
11+
for (const pkgName in rootPkg.dependencies) {
12+
if (!rootPkg.dependencies[pkgName].startsWith('npm:')) {
13+
const aliasName = rootPkg.dependencies.dependencies[pkgName].substring(
14+
4,
15+
rootPkg.dependencies.dependencies[pkgName].lastIndexOf('@'),
16+
);
17+
const aliasVersion = rootPkg.dependencies.dependencies[
18+
pkgName
19+
].substring(
20+
rootPkg.dependencies.dependencies[pkgName].lastIndexOf('@') + 1,
21+
rootPkg.dependencies.dependencies[pkgName].length,
22+
);
23+
dependencies[aliasName] = aliasVersion;
24+
} else {
25+
dependencies[pkgName] = rootPkg.dependencies[pkgName];
26+
}
27+
}
28+
lockFileToReturn[''].dependencies = dependencies;
29+
}
30+
31+
// 2. Rewrite alias packages
32+
for (const pkgName in lockfilePackages) {
33+
if (pkgName != '' && lockfilePackages[pkgName].name) {
34+
lockFileToReturn[`node_modules/${lockfilePackages[pkgName].name}`] =
35+
lockfilePackages[pkgName];
36+
delete lockFileToReturn[pkgName];
37+
}
38+
}
39+
40+
return lockFileToReturn;
41+
};

lib/aliasesPreprocessors/yarn-lock-v1.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
export const rewriteAliasesInLockV1 = (lockfileContent: string): string => {
1+
export const rewriteAliasesInYarnLockV1 = (lockfileContent: string): string => {
22
const regex = /^(\s*)"(.+?@npm:)([^"]+)":/gm;
33

44
const lockfilePreprocessed = lockfileContent.replace(regex, '$1"$3":');

lib/aliasesPreprocessors/yarn-lock-v2.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { NormalisedPkgs } from '../dep-graph-builders/types';
22
import * as cloneDeep from 'lodash.clonedeep';
3-
export const rewriteAliasesInLockV2 = (
3+
export const rewriteAliasesInYarnLockV2 = (
44
lockfileNormalisedPkgs: NormalisedPkgs,
55
): NormalisedPkgs => {
66
const lockfileNormalisedPkgsPreprocessed: NormalisedPkgs = cloneDeep(

lib/dep-graph-builders/npm-lock-v2/index.ts

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ import * as semver from 'semver';
2121
import * as micromatch from 'micromatch';
2222
import * as pathUtil from 'path';
2323
import { eventLoopSpinner } from 'event-loop-spinner';
24+
import { rewriteAliasesPkgJson } from '../../aliasesPreprocessors/pkgJson';
25+
import { rewriteAliasesInNpmLockV2 } from '../../aliasesPreprocessors/npm-lock-v2';
2426

2527
export { extractPkgsFromNpmLockV2 };
2628

@@ -36,8 +38,14 @@ export const parseNpmLockV2Project = async (
3638
pruneNpmStrictOutOfSync,
3739
} = options;
3840

39-
const pkgJson: PackageJsonBase = parsePkgJson(pkgJsonContent);
40-
const pkgs = extractPkgsFromNpmLockV2(pkgLockContent);
41+
const pkgJson: PackageJsonBase = parsePkgJson(
42+
options.honorAliases
43+
? rewriteAliasesPkgJson(pkgJsonContent)
44+
: pkgJsonContent,
45+
);
46+
const pkgs = options.honorAliases
47+
? rewriteAliasesInNpmLockV2(extractPkgsFromNpmLockV2(pkgLockContent))
48+
: extractPkgsFromNpmLockV2(pkgLockContent);
4149

4250
const depgraph = await buildDepGraphNpmLockV2(pkgs, pkgJson, {
4351
includeDevDeps,

lib/dep-graph-builders/yarn-lock-v1/simple.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { buildDepGraphYarnLockV1Simple } from '.';
22
import { rewriteAliasesPkgJson } from '../../aliasesPreprocessors/pkgJson';
3-
import { rewriteAliasesInLockV1 } from '../../aliasesPreprocessors/yarn-lock-v1';
3+
import { rewriteAliasesInYarnLockV1 } from '../../aliasesPreprocessors/yarn-lock-v1';
44

55
import { PackageJsonBase, YarnLockV1ProjectParseOptions } from '../types';
66
import { parsePkgJson } from '../util';
@@ -22,7 +22,9 @@ export const parseYarnLockV1Project = async (
2222
} = options;
2323

2424
const pkgs = extractPkgsFromYarnLockV1(
25-
honorAliases ? rewriteAliasesInLockV1(yarnLockContent) : yarnLockContent,
25+
honorAliases
26+
? rewriteAliasesInYarnLockV1(yarnLockContent)
27+
: yarnLockContent,
2628
);
2729

2830
const pkgJson: PackageJsonBase = parsePkgJson(

lib/dep-graph-builders/yarn-lock-v2/simple.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import {
88
import { buildDepGraphYarnLockV2Simple } from './build-depgraph-simple';
99
import { DepGraph } from '@snyk/dep-graph';
1010
import { rewriteAliasesPkgJson } from '../../aliasesPreprocessors/pkgJson';
11-
import { rewriteAliasesInLockV2 } from '../../aliasesPreprocessors/yarn-lock-v2';
11+
import { rewriteAliasesInYarnLockV2 } from '../../aliasesPreprocessors/yarn-lock-v2';
1212

1313
export const parseYarnLockV2Project = async (
1414
pkgJsonContent: string,
@@ -25,7 +25,7 @@ export const parseYarnLockV2Project = async (
2525
} = options;
2626

2727
const pkgs = honorAliases
28-
? rewriteAliasesInLockV2(extractPkgsFromYarnLockV2(yarnLockContent))
28+
? rewriteAliasesInYarnLockV2(extractPkgsFromYarnLockV2(yarnLockContent))
2929
: extractPkgsFromYarnLockV2(yarnLockContent);
3030

3131
const pkgJson: PackageJsonBase = parsePkgJson(

lib/index.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,8 @@ import {
7070
getPnpmLockfileVersion,
7171
NodeLockfileVersion,
7272
} from './utils';
73+
import { rewriteAliasesInNpmLockV1 } from './aliasesPreprocessors/npm-lock-v1';
74+
import { rewriteAliasesPkgJson } from './aliasesPreprocessors/pkgJson';
7375
export {
7476
parseNpmLockV2Project,
7577
extractPkgsFromYarnLockV1,
@@ -156,6 +158,7 @@ async function buildDepTreeFromFiles(
156158
lockFilePath: string,
157159
includeDev = false,
158160
strictOutOfSync = true,
161+
honorAliases?: boolean,
159162
): Promise<PkgTree> {
160163
if (!root || !manifestFilePath || !lockFilePath) {
161164
throw new Error('Missing required parameters for buildDepTreeFromFiles()');
@@ -192,8 +195,12 @@ async function buildDepTreeFromFiles(
192195
}
193196

194197
return await buildDepTree(
195-
manifestFileContents,
196-
lockFileContents,
198+
honorAliases
199+
? rewriteAliasesPkgJson(manifestFileContents)
200+
: manifestFileContents,
201+
honorAliases
202+
? rewriteAliasesInNpmLockV1(lockFileContents)
203+
: lockFileContents,
197204
includeDev,
198205
lockFileType,
199206
strictOutOfSync,

test/jest/dep-graph-builders/aliases.test.ts

Lines changed: 71 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
import { join } from 'path';
22
import { readFileSync } from 'fs';
33
import {
4+
buildDepTreeFromFiles,
45
parseNpmLockV2Project,
56
parseYarnLockV1Project,
67
parseYarnLockV2Project,
78
} from '../../../lib/';
89

9-
describe('Testing aliases', () => {
10+
describe('Testing aliases for yarn', () => {
1011
it('match aliased package - yarn-lock-v1', async () => {
1112
const pkgJsonContent = readFileSync(
1213
join(__dirname, `./fixtures/aliases/yarn-lock-v1/package.json`),
@@ -57,37 +58,82 @@ describe('Testing aliases', () => {
5758
honorAliases: true,
5859
},
5960
);
60-
console.log(JSON.stringify(newDepGraph));
6161
expect(newDepGraph).toBeDefined;
6262

6363
expect(JSON.stringify(newDepGraph)).toContain('@yao-pkg/pkg');
6464
expect(JSON.stringify(newDepGraph)).not.toContain("'pkg@");
6565
});
66+
});
67+
describe('Testing aliases for npm', () => {
68+
it('match aliased package - npm-lock-v1', async () => {
69+
const rootPath = join(__dirname, './fixtures/aliases/npm-lock-v1');
6670

67-
// it('match aliased package - npm-lock-v2', async () => {
68-
// const pkgJsonContent = readFileSync(
69-
// join(__dirname, `./fixtures/aliases/package.json`),
70-
// 'utf8',
71-
// );
72-
// const pkgLockContent = readFileSync(
73-
// join(__dirname, `./fixtures/aliases/package-lock.json`),
74-
// 'utf8',
75-
// );
71+
const newDepGraph = await buildDepTreeFromFiles(
72+
rootPath,
73+
join(__dirname, `./fixtures/aliases/npm-lock-v1/package.json`),
74+
join(__dirname, `./fixtures/aliases/npm-lock-v1/package-lock.json`),
75+
true,
76+
true,
77+
true,
78+
);
7679

77-
// const newDepGraph = await parseNpmLockV2Project(
78-
// pkgJsonContent,
79-
// pkgLockContent,
80-
// {
81-
// includeDevDeps: false,
82-
// includeOptionalDeps: true,
83-
// pruneCycles: true,
84-
// strictOutOfSync: true,
85-
// },
86-
// );
80+
expect(newDepGraph).toBeDefined;
81+
expect(() => JSON.parse(JSON.stringify(newDepGraph))).not.toThrow();
82+
expect(JSON.stringify(newDepGraph)).toContain('@yao-pkg/pkg');
83+
expect(JSON.stringify(newDepGraph)).not.toContain('"pkg"');
84+
});
85+
it('match aliased package - npm-lock-v2', async () => {
86+
const pkgJsonContent = readFileSync(
87+
join(__dirname, `./fixtures/aliases/npm-lock-v2/package.json`),
88+
'utf8',
89+
);
90+
const pkgLockContent = readFileSync(
91+
join(__dirname, `./fixtures/aliases/npm-lock-v2/package-lock.json`),
92+
'utf8',
93+
);
8794

88-
// expect(newDepGraph).toBeDefined;
95+
const newDepGraph = await parseNpmLockV2Project(
96+
pkgJsonContent,
97+
pkgLockContent,
98+
{
99+
includeDevDeps: true,
100+
includeOptionalDeps: true,
101+
pruneCycles: true,
102+
strictOutOfSync: true,
103+
honorAliases: true,
104+
},
105+
);
89106

90-
// expect(JSON.stringify(newDepGraph)).toContain('@yao-pkg/pkg');
91-
// expect(JSON.stringify(newDepGraph)).not.toContain("'pkg'");
92-
// });
107+
expect(newDepGraph).toBeDefined;
108+
expect(() => JSON.parse(JSON.stringify(newDepGraph))).not.toThrow();
109+
expect(JSON.stringify(newDepGraph)).toContain('@yao-pkg/pkg');
110+
expect(JSON.stringify(newDepGraph)).not.toContain('"pkg"');
111+
});
112+
it('match aliased package - npm-lock-v3', async () => {
113+
const pkgJsonContent = readFileSync(
114+
join(__dirname, `./fixtures/aliases/npm-lock-v3/package.json`),
115+
'utf8',
116+
);
117+
const pkgLockContent = readFileSync(
118+
join(__dirname, `./fixtures/aliases/npm-lock-v3/package-lock.json`),
119+
'utf8',
120+
);
121+
122+
const newDepGraph = await parseNpmLockV2Project(
123+
pkgJsonContent,
124+
pkgLockContent,
125+
{
126+
includeDevDeps: true,
127+
includeOptionalDeps: true,
128+
pruneCycles: true,
129+
strictOutOfSync: true,
130+
honorAliases: true,
131+
},
132+
);
133+
134+
expect(newDepGraph).toBeDefined;
135+
expect(() => JSON.parse(JSON.stringify(newDepGraph))).not.toThrow();
136+
expect(JSON.stringify(newDepGraph)).toContain('@yao-pkg/pkg');
137+
expect(JSON.stringify(newDepGraph)).not.toContain('"pkg"');
138+
});
93139
});

0 commit comments

Comments
 (0)