11import * as debugModule from 'debug' ;
22import * as pathUtil from 'path' ;
3+ import * as fs from 'fs' ;
34
45const debug = debugModule ( 'snyk-pnpm-workspaces' ) ;
56import * as lockFileParser from 'snyk-nodejs-lockfile-parser' ;
67import { MultiProjectResultCustom , ScannedProjectCustom } from '../types' ;
7- import { getFileContents , isSubpath , normalizeFilePath } from '../utils' ;
8- import {
9- getWorkspacesMap ,
10- packageJsonBelongsToWorkspace ,
11- sortTargetFiles ,
12- } from './workspace-utils' ;
13- import { DepGraph } from '@snyk/dep-graph' ;
14-
15- const PNPM_ROOT_FILES = [
16- 'pnpm-workspace.yaml' ,
17- 'package.json' ,
18- 'pnpm-lock.yaml' ,
19- ] ;
20-
21- // Compute project versions map
22- // This is needed because the lockfile doesn't present the version of
23- // a project that's part of a workspace, we need to retrieve it from
24- // its corresponding package.json
25- function computeProjectVersionMaps ( root : string , targetFiles ) {
26- const projectsVersionMap = { } ;
27- for ( const directory of Object . keys ( targetFiles ) ) {
28- if ( ! isSubpath ( directory , root ) ) {
29- continue ;
30- }
31- const packageJsonFileName = pathUtil . join ( directory , 'package.json' ) ;
32- const packageJson = getFileContents ( root , packageJsonFileName ) ;
33-
34- try {
35- const parsedPkgJson = lockFileParser . parsePkgJson ( packageJson . content ) ;
36- const projectVersion = parsedPkgJson . version ;
37- projectsVersionMap [
38- normalizeFilePath ( pathUtil . relative ( root , directory ) )
39- ] = projectVersion || 'undefined' ;
40- } catch ( err : any ) {
41- debug (
42- `Error getting version for project: ${ packageJsonFileName } . ERROR: ${ err } ` ,
43- ) ;
44- continue ;
45- }
46- }
47- return projectsVersionMap ;
48- }
8+ import { sortTargetFiles } from './workspace-utils' ;
9+ import { ScannedNodeProject } from 'snyk-nodejs-lockfile-parser/dist/dep-graph-builders/types' ;
4910
5011export async function processPnpmWorkspaces (
5112 root : string ,
@@ -56,7 +17,7 @@ export async function processPnpmWorkspaces(
5617 } ,
5718 targetFiles : string [ ] ,
5819) : Promise < MultiProjectResultCustom > {
59- const pnpmTargetFiles = sortTargetFiles ( targetFiles , PNPM_ROOT_FILES ) ;
20+ const pnpmWorkspaceDirs = sortTargetFiles ( targetFiles , [ 'pnpm-lock.yaml' ] ) ;
6021
6122 debug ( `Processing potential Pnpm workspaces (${ targetFiles . length } )` ) ;
6223
@@ -68,101 +29,32 @@ export async function processPnpmWorkspaces(
6829 scannedProjects : [ ] ,
6930 } ;
7031
71- let pnpmWorkspacesMap = { } ;
72- const pnpmWorkspacesFilesMap = { } ;
73-
74- let rootWorkspaceManifestContent = { } ;
75- const projectsVersionMap = { } ;
76-
7732 // the folders must be ordered highest first
78- for ( const directory of Object . keys ( pnpmTargetFiles ) ) {
33+ for ( const directory of Object . keys ( pnpmWorkspaceDirs ) ) {
7934 debug ( `Processing ${ directory } as a potential Pnpm workspace` ) ;
80- let isPnpmWorkspacePackage = false ;
81- let isRootPackageJson = false ;
82- const packageJsonFileName = pathUtil . join ( directory , 'package.json' ) ;
83- const packageJson = getFileContents ( root , packageJsonFileName ) ;
84- pnpmWorkspacesMap = {
85- ...pnpmWorkspacesMap ,
86- ...getWorkspacesMap ( root , directory , packageJson ) ,
87- } ;
88-
89- for ( const workspaceRoot of Object . keys ( pnpmWorkspacesMap ) ) {
90- const match = packageJsonBelongsToWorkspace (
91- packageJsonFileName ,
92- pnpmWorkspacesMap ,
93- workspaceRoot ,
94- ) ;
95- if ( match ) {
96- debug ( `${ packageJsonFileName } matches an existing workspace pattern` ) ;
97- pnpmWorkspacesFilesMap [ packageJsonFileName ] = {
98- root : workspaceRoot ,
99- } ;
100- isPnpmWorkspacePackage = true ;
101- }
102- if ( packageJsonFileName === workspaceRoot ) {
103- isRootPackageJson = true ;
104- const workspaceRootDir = pathUtil . dirname ( workspaceRoot ) ;
105- projectsVersionMap [ workspaceRootDir ] = computeProjectVersionMaps (
106- workspaceRootDir ,
107- pnpmTargetFiles ,
108- ) ;
109- rootWorkspaceManifestContent = JSON . parse ( packageJson . content ) ;
110- }
111- }
11235
113- if ( ! ( isPnpmWorkspacePackage || isRootPackageJson ) ) {
36+ const pnpmWorkspacePath = pathUtil . join ( directory , 'pnpm-workspace.yaml' ) ;
37+ if ( ! fs . existsSync ( pnpmWorkspacePath ) ) {
11438 debug (
115- `${ packageJsonFileName } is not part of any detected workspace, skipping ` ,
39+ `Workspace file not found at ${ directory } . Can't be a pnpm workspace root. ` ,
11640 ) ;
11741 continue ;
11842 }
11943
120- const rootDir = isPnpmWorkspacePackage
121- ? pathUtil . dirname ( pnpmWorkspacesFilesMap [ packageJsonFileName ] . root )
122- : pathUtil . dirname ( packageJsonFileName ) ;
123-
124- try {
125- const rootPnpmLockfileName = pathUtil . join ( rootDir , 'pnpm-lock.yaml' ) ;
126- const pnpmLock = getFileContents ( root , rootPnpmLockfileName ) ;
127- const lockfileVersion = lockFileParser . getPnpmLockfileVersion (
128- pnpmLock . content ,
129- ) ;
130- const res : DepGraph = await lockFileParser . parsePnpmProject (
131- packageJson . content ,
132- pnpmLock . content ,
133- {
134- includeDevDeps : settings . dev || false ,
135- includeOptionalDeps : settings . optional || true ,
136- pruneWithinTopLevelDeps : true ,
137- strictOutOfSync :
138- settings . strictOutOfSync === undefined
139- ? true
140- : settings . strictOutOfSync ,
141- } ,
142- lockfileVersion ,
143- {
144- isWorkspacePkg : true ,
145- workspacePath : normalizeFilePath (
146- pathUtil . relative ( rootDir , directory ) ,
147- ) ,
148- isRoot : isRootPackageJson ,
149- projectsVersionMap : projectsVersionMap [ rootDir ] ,
150- rootOverrides : rootWorkspaceManifestContent ?. [ 'pnpm.overrides' ] || { } ,
151- } ,
152- ) ;
153- const project : ScannedProjectCustom = {
154- packageManager : 'pnpm' ,
155- targetFile : pathUtil . relative ( root , packageJson . fileName ) ,
156- depGraph : res as any ,
157- plugin : {
158- name : 'snyk-nodejs-lockfile-parser' ,
159- runtime : process . version ,
160- } ,
161- } ;
162- result . scannedProjects . push ( project ) ;
163- } catch ( e ) {
164- debug ( `Error process workspace: ${ packageJsonFileName } . ERROR: ${ e } ` ) ;
165- }
44+ const scannedProjects : ScannedNodeProject [ ] =
45+ await lockFileParser . parsePnpmWorkspace ( root , directory , {
46+ includeDevDeps : settings . dev || false ,
47+ includeOptionalDeps : settings . optional || true ,
48+ includePeerDeps : true ,
49+ pruneWithinTopLevelDeps : true ,
50+ strictOutOfSync :
51+ settings . strictOutOfSync === undefined
52+ ? true
53+ : settings . strictOutOfSync ,
54+ } ) ;
55+ result . scannedProjects = result . scannedProjects . concat (
56+ scannedProjects as ScannedProjectCustom [ ] ,
57+ ) ;
16658 }
16759
16860 if ( ! result . scannedProjects . length ) {
0 commit comments