diff --git a/lib/workspaces/pnpm-workspaces-parser.ts b/lib/workspaces/pnpm-workspaces-parser.ts index f3f9207..0031fc1 100644 --- a/lib/workspaces/pnpm-workspaces-parser.ts +++ b/lib/workspaces/pnpm-workspaces-parser.ts @@ -1,51 +1,12 @@ import * as debugModule from 'debug'; import * as pathUtil from 'path'; +import * as fs from 'fs'; const debug = debugModule('snyk-pnpm-workspaces'); import * as lockFileParser from 'snyk-nodejs-lockfile-parser'; import { MultiProjectResultCustom, ScannedProjectCustom } from '../types'; -import { getFileContents, isSubpath, normalizeFilePath } from '../utils'; -import { - getWorkspacesMap, - packageJsonBelongsToWorkspace, - sortTargetFiles, -} from './workspace-utils'; -import { DepGraph } from '@snyk/dep-graph'; - -const PNPM_ROOT_FILES = [ - 'pnpm-workspace.yaml', - 'package.json', - 'pnpm-lock.yaml', -]; - -// Compute project versions map -// This is needed because the lockfile doesn't present the version of -// a project that's part of a workspace, we need to retrieve it from -// its corresponding package.json -function computeProjectVersionMaps(root: string, targetFiles) { - const projectsVersionMap = {}; - for (const directory of Object.keys(targetFiles)) { - if (!isSubpath(directory, root)) { - continue; - } - const packageJsonFileName = pathUtil.join(directory, 'package.json'); - const packageJson = getFileContents(root, packageJsonFileName); - - try { - const parsedPkgJson = lockFileParser.parsePkgJson(packageJson.content); - const projectVersion = parsedPkgJson.version; - projectsVersionMap[ - normalizeFilePath(pathUtil.relative(root, directory)) - ] = projectVersion || 'undefined'; - } catch (err: any) { - debug( - `Error getting version for project: ${packageJsonFileName}. ERROR: ${err}`, - ); - continue; - } - } - return projectsVersionMap; -} +import { sortTargetFiles } from './workspace-utils'; +import { ScannedNodeProject } from 'snyk-nodejs-lockfile-parser/dist/dep-graph-builders/types'; export async function processPnpmWorkspaces( root: string, @@ -56,7 +17,7 @@ export async function processPnpmWorkspaces( }, targetFiles: string[], ): Promise { - const pnpmTargetFiles = sortTargetFiles(targetFiles, PNPM_ROOT_FILES); + const pnpmWorkspaceDirs = sortTargetFiles(targetFiles, ['pnpm-lock.yaml']); debug(`Processing potential Pnpm workspaces (${targetFiles.length})`); @@ -68,101 +29,32 @@ export async function processPnpmWorkspaces( scannedProjects: [], }; - let pnpmWorkspacesMap = {}; - const pnpmWorkspacesFilesMap = {}; - - let rootWorkspaceManifestContent = {}; - const projectsVersionMap = {}; - // the folders must be ordered highest first - for (const directory of Object.keys(pnpmTargetFiles)) { + for (const directory of Object.keys(pnpmWorkspaceDirs)) { debug(`Processing ${directory} as a potential Pnpm workspace`); - let isPnpmWorkspacePackage = false; - let isRootPackageJson = false; - const packageJsonFileName = pathUtil.join(directory, 'package.json'); - const packageJson = getFileContents(root, packageJsonFileName); - pnpmWorkspacesMap = { - ...pnpmWorkspacesMap, - ...getWorkspacesMap(root, directory, packageJson), - }; - - for (const workspaceRoot of Object.keys(pnpmWorkspacesMap)) { - const match = packageJsonBelongsToWorkspace( - packageJsonFileName, - pnpmWorkspacesMap, - workspaceRoot, - ); - if (match) { - debug(`${packageJsonFileName} matches an existing workspace pattern`); - pnpmWorkspacesFilesMap[packageJsonFileName] = { - root: workspaceRoot, - }; - isPnpmWorkspacePackage = true; - } - if (packageJsonFileName === workspaceRoot) { - isRootPackageJson = true; - const workspaceRootDir = pathUtil.dirname(workspaceRoot); - projectsVersionMap[workspaceRootDir] = computeProjectVersionMaps( - workspaceRootDir, - pnpmTargetFiles, - ); - rootWorkspaceManifestContent = JSON.parse(packageJson.content); - } - } - if (!(isPnpmWorkspacePackage || isRootPackageJson)) { + const pnpmWorkspacePath = pathUtil.join(directory, 'pnpm-workspace.yaml'); + if (!fs.existsSync(pnpmWorkspacePath)) { debug( - `${packageJsonFileName} is not part of any detected workspace, skipping`, + `Workspace file not found at ${directory}. Can't be a pnpm workspace root.`, ); continue; } - const rootDir = isPnpmWorkspacePackage - ? pathUtil.dirname(pnpmWorkspacesFilesMap[packageJsonFileName].root) - : pathUtil.dirname(packageJsonFileName); - - try { - const rootPnpmLockfileName = pathUtil.join(rootDir, 'pnpm-lock.yaml'); - const pnpmLock = getFileContents(root, rootPnpmLockfileName); - const lockfileVersion = lockFileParser.getPnpmLockfileVersion( - pnpmLock.content, - ); - const res: DepGraph = await lockFileParser.parsePnpmProject( - packageJson.content, - pnpmLock.content, - { - includeDevDeps: settings.dev || false, - includeOptionalDeps: settings.optional || true, - pruneWithinTopLevelDeps: true, - strictOutOfSync: - settings.strictOutOfSync === undefined - ? true - : settings.strictOutOfSync, - }, - lockfileVersion, - { - isWorkspacePkg: true, - workspacePath: normalizeFilePath( - pathUtil.relative(rootDir, directory), - ), - isRoot: isRootPackageJson, - projectsVersionMap: projectsVersionMap[rootDir], - rootOverrides: rootWorkspaceManifestContent?.['pnpm.overrides'] || {}, - }, - ); - const project: ScannedProjectCustom = { - packageManager: 'pnpm', - targetFile: pathUtil.relative(root, packageJson.fileName), - depGraph: res as any, - plugin: { - name: 'snyk-nodejs-lockfile-parser', - runtime: process.version, - }, - }; - result.scannedProjects.push(project); - } catch (e) { - debug(`Error process workspace: ${packageJsonFileName}. ERROR: ${e}`); - } + const scannedProjects: ScannedNodeProject[] = + await lockFileParser.parsePnpmWorkspace(root, directory, { + includeDevDeps: settings.dev || false, + includeOptionalDeps: settings.optional || true, + includePeerDeps: true, + pruneWithinTopLevelDeps: true, + strictOutOfSync: + settings.strictOutOfSync === undefined + ? true + : settings.strictOutOfSync, + }); + result.scannedProjects = result.scannedProjects.concat( + scannedProjects as ScannedProjectCustom[], + ); } if (!result.scannedProjects.length) { diff --git a/package.json b/package.json index db7ef3f..70cc517 100644 --- a/package.json +++ b/package.json @@ -42,7 +42,7 @@ "lodash.isempty": "^4.4.0", "lodash.sortby": "^4.7.0", "micromatch": "4.0.7", - "snyk-nodejs-lockfile-parser": "^1.56.1", + "snyk-nodejs-lockfile-parser": "1.58.5", "snyk-resolve-deps": "4.8.0" }, "devDependencies": {