Skip to content

Commit

Permalink
Merge pull request #223 from snyk/feat/pnpm-lockfile-v9
Browse files Browse the repository at this point in the history
feat: added support for pnpm lockfiles v9
  • Loading branch information
gemaxim committed May 10, 2024
2 parents e57ddda + da40be3 commit e81f206
Show file tree
Hide file tree
Showing 70 changed files with 104,409 additions and 44 deletions.
2 changes: 1 addition & 1 deletion README.md
Expand Up @@ -14,7 +14,7 @@ Dep graph generation supported for:

- `package-lock.json` (at Versions 2 and 3)
- `yarn.lock`
- `pnpm-lock.yaml` (lockfileVersion 5.x or 6.x)
- `pnpm-lock.yaml` (lockfileVersion 5.x, 6.x and 9.x)

Legacy dep tree supported for:

Expand Down
2 changes: 2 additions & 0 deletions lib/dep-graph-builders/pnpm/build-dep-graph-pnpm.ts
Expand Up @@ -29,6 +29,8 @@ export const buildDepGraphPnpm = async (
{ name: pkgJson.name, version: pkgJson.version },
);

lockFileParser.extractedPackages = lockFileParser.extractPackages();

const extractedPnpmPkgs: NormalisedPnpmPkgs =
lockFileParser.extractedPackages;

Expand Down
8 changes: 8 additions & 0 deletions lib/dep-graph-builders/pnpm/lockfile-parser/index.ts
Expand Up @@ -2,6 +2,7 @@ import { load, FAILSAFE_SCHEMA } from 'js-yaml';
import { PnpmLockfileParser } from './lockfile-parser';
import { LockfileV6Parser } from './lockfile-v6';
import { LockfileV5Parser } from './lockfile-v5';
import { LockfileV9Parser } from './lockfile-v9';
import { PnpmWorkspaceArgs } from '../../types';
import { OpenSourceEcosystems } from '@snyk/error-catalog-nodejs-public';
import { NodeLockfileVersion } from '../../../utils';
Expand Down Expand Up @@ -31,6 +32,13 @@ export function getPnpmLockfileParser(
return new LockfileV6Parser(rawPnpmLock, workspaceArgs);
}

if (
lockfileVersion === NodeLockfileVersion.PnpmLockV9 ||
version.startsWith('9')
) {
return new LockfileV9Parser(rawPnpmLock, workspaceArgs);
}

throw new OpenSourceEcosystems.PnpmUnsupportedLockfileVersionError(
`The pnpm-lock.yaml lockfile version ${lockfileVersion} is not supported`,
);
Expand Down
27 changes: 16 additions & 11 deletions lib/dep-graph-builders/pnpm/lockfile-parser/lockfile-parser.ts
Expand Up @@ -33,7 +33,7 @@ export abstract class PnpmLockfileParser {
this.devDependencies = depsRoot.devDependencies || {};
this.optionalDependencies = depsRoot.optionalDependencies || {};
this.peerDependencies = depsRoot.peerDependencies || {};
this.extractedPackages = this.extractPackages();
this.extractedPackages = {};
this.importers = this.normaliseImporters(rawPnpmLock);
}

Expand All @@ -55,23 +55,25 @@ export abstract class PnpmLockfileParser {
return depsRoot;
}

public extractPackages(): NormalisedPnpmPkgs {
public extractPackages() {
const packages: NormalisedPnpmPkgs = {};
Object.entries(this.packages).forEach(
([depPath, versionData]: [string, any]) => {
// name and version are optional in version data - if they don't show up in version data, they can be deducted from the dependency path
let { name, version } = versionData;
if (!(name && version)) {
({ name, version } = this.parseDepPath(depPath));
const { name, version } = versionData;
let parsedPath: ParsedDepPath = {};
if (!(version && name)) {
parsedPath = this.parseDepPath(depPath);
}

const pkg: NormalisedPnpmPkg = {
id: depPath,
name,
version,
name: name || parsedPath.name,
version: version || parsedPath.version || depPath,
isDev: versionData.dev == 'true',
dependencies: versionData.dependencies,
devDependencies: versionData.devDependencies,
optionalDependencies: versionData.optionalDependencies,
dependencies: versionData.dependencies || {},
devDependencies: versionData.devDependencies || {},
optionalDependencies: versionData.optionalDependencies || {},
};
packages[`${pkg.name}@${pkg.version}`] = pkg;
},
Expand Down Expand Up @@ -115,7 +117,10 @@ export abstract class PnpmLockfileParser {
// they show up in packages with keys equal to the version in top level deps
// e.g. body-parser with version github.com/expressjs/body-parser/263f602e6ae34add6332c1eb4caa808893b0b711
if (this.packages[version]) {
return this.packages[version].version!;
return this.packages[version].version || version;
}
if (this.packages[`${name}@${version}`]) {
return this.packages[`${name}@${version}`].version || version;
}
}
}
Expand Down
32 changes: 32 additions & 0 deletions lib/dep-graph-builders/pnpm/lockfile-parser/lockfile-v9.ts
@@ -0,0 +1,32 @@
import { PnpmWorkspaceArgs } from '../../types';
import { LockfileV6Parser } from './lockfile-v6';

const DEFAULT_WORKSPACE_ARGS: PnpmWorkspaceArgs = {
isWorkspacePkg: true,
isRoot: true,
workspacePath: '.',
projectsVersionMap: {},
rootOverrides: {},
};
export class LockfileV9Parser extends LockfileV6Parser {
public settings;
public snapshots;

public constructor(
rawPnpmLock: any,
workspaceArgs: PnpmWorkspaceArgs = DEFAULT_WORKSPACE_ARGS,
) {
super(rawPnpmLock, workspaceArgs);
this.settings = rawPnpmLock.settings;
this.packages = {};
Object.entries(rawPnpmLock.snapshots).forEach(
([depPath, versionData]: [string, any]) => {
const normalizedDepPath = this.excludeTransPeerDepsVersions(depPath);
this.packages[normalizedDepPath] = {
...rawPnpmLock.packages[normalizedDepPath],
...versionData,
};
},
);
}
}
8 changes: 7 additions & 1 deletion lib/utils.ts
Expand Up @@ -11,6 +11,7 @@ export enum NodeLockfileVersion {
YarnLockV2 = 'YARN_LOCK_V2',
PnpmLockV5 = 'PNPM_LOCK_V5',
PnpmLockV6 = 'PNPM_LOCK_V6',
PnpmLockV9 = 'PNPM_LOCK_V9',
}

export const getLockfileVersionFromFile = (
Expand All @@ -33,7 +34,10 @@ export const getLockfileVersionFromFile = (

export function getPnpmLockfileVersion(
lockFileContents: string,
): NodeLockfileVersion.PnpmLockV5 | NodeLockfileVersion.PnpmLockV6 {
):
| NodeLockfileVersion.PnpmLockV5
| NodeLockfileVersion.PnpmLockV6
| NodeLockfileVersion.PnpmLockV9 {
const rawPnpmLock = load(lockFileContents, {
json: true,
schema: FAILSAFE_SCHEMA,
Expand All @@ -43,6 +47,8 @@ export function getPnpmLockfileVersion(
return NodeLockfileVersion.PnpmLockV5;
} else if (lockfileVersion.startsWith('6')) {
return NodeLockfileVersion.PnpmLockV6;
} else if (lockfileVersion.startsWith('9')) {
return NodeLockfileVersion.PnpmLockV9;
} else {
throw new OpenSourceEcosystems.PnpmUnsupportedLockfileVersionError(
`The pnpm-lock.yaml lockfile version ${lockfileVersion} is not supported`,
Expand Down

0 comments on commit e81f206

Please sign in to comment.