1
1
import * as debugModule from 'debug' ;
2
2
import * as pathUtil from 'path' ;
3
+ import * as fs from 'fs' ;
3
4
4
5
const debug = debugModule ( 'snyk-pnpm-workspaces' ) ;
5
6
import * as lockFileParser from 'snyk-nodejs-lockfile-parser' ;
6
7
import { 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' ;
49
10
50
11
export async function processPnpmWorkspaces (
51
12
root : string ,
@@ -56,7 +17,7 @@ export async function processPnpmWorkspaces(
56
17
} ,
57
18
targetFiles : string [ ] ,
58
19
) : Promise < MultiProjectResultCustom > {
59
- const pnpmTargetFiles = sortTargetFiles ( targetFiles , PNPM_ROOT_FILES ) ;
20
+ const pnpmWorkspaceDirs = sortTargetFiles ( targetFiles , [ 'pnpm-lock.yaml' ] ) ;
60
21
61
22
debug ( `Processing potential Pnpm workspaces (${ targetFiles . length } )` ) ;
62
23
@@ -68,101 +29,32 @@ export async function processPnpmWorkspaces(
68
29
scannedProjects : [ ] ,
69
30
} ;
70
31
71
- let pnpmWorkspacesMap = { } ;
72
- const pnpmWorkspacesFilesMap = { } ;
73
-
74
- let rootWorkspaceManifestContent = { } ;
75
- const projectsVersionMap = { } ;
76
-
77
32
// the folders must be ordered highest first
78
- for ( const directory of Object . keys ( pnpmTargetFiles ) ) {
33
+ for ( const directory of Object . keys ( pnpmWorkspaceDirs ) ) {
79
34
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
- }
112
35
113
- if ( ! ( isPnpmWorkspacePackage || isRootPackageJson ) ) {
36
+ const pnpmWorkspacePath = pathUtil . join ( directory , 'pnpm-workspace.yaml' ) ;
37
+ if ( ! fs . existsSync ( pnpmWorkspacePath ) ) {
114
38
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. ` ,
116
40
) ;
117
41
continue ;
118
42
}
119
43
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
+ ) ;
166
58
}
167
59
168
60
if ( ! result . scannedProjects . length ) {
0 commit comments