@@ -444,7 +444,8 @@ def get_workspace_members(cls, workspaces, codebase, workspace_root_path):
444
444
# Case 3: This is a complex glob pattern, we are doing a full codebase walk
445
445
# and glob matching each resource
446
446
else :
447
- for resource in workspace_root_path :
447
+ workspace_root = codebase .get_resource (path = workspace_root_path )
448
+ for resource in workspace_root .walk (codebase ):
448
449
if NpmPackageJsonHandler .is_datafile (resource .location ) and fnmatch .fnmatch (
449
450
name = resource .location , pat = workspace_path ,
450
451
):
@@ -1155,6 +1156,10 @@ def parse(cls, location, package_only=False):
1155
1156
yield models .PackageData .from_data (package_data , package_only )
1156
1157
1157
1158
1159
+ class UnknownPnpmLockFormat (Exception ):
1160
+ pass
1161
+
1162
+
1158
1163
class BasePnpmLockHandler (BaseNpmHandler ):
1159
1164
1160
1165
@classmethod
@@ -1181,31 +1186,62 @@ def parse(cls, location, package_only=False):
1181
1186
}
1182
1187
major_v , minor_v = lockfile_version .split ("." )
1183
1188
1184
- resolved_packages = lock_data .get ("packages" , [])
1189
+ resolved_packages = lock_data .get ("packages" , {})
1190
+ dependency_relations = lock_data .get ("snapshots" , {})
1191
+ dependency_relations_by_purl = {}
1192
+ if dependency_relations :
1193
+ for purl_fields , relations in dependency_relations .items ():
1194
+ clean_purl_fields = purl_fields .split ("(" )[0 ]
1195
+ sections = clean_purl_fields .split ("/" )
1196
+ namespace = None
1197
+ if len (sections ) == 2 :
1198
+ namespace , name_version = sections
1199
+ elif len (sections ) == 1 :
1200
+ name_version , = sections
1201
+ name , version = name_version .split ("@" )
1202
+
1203
+ purl = PackageURL (
1204
+ type = cls .default_package_type ,
1205
+ name = name ,
1206
+ namespace = namespace ,
1207
+ version = version ,
1208
+ ).to_string ()
1209
+ dependency_relations_by_purl [purl ] = relations
1210
+
1185
1211
dependencies_by_purl = {}
1186
1212
1187
1213
for purl_fields , data in resolved_packages .items ():
1188
1214
if major_v == "6" :
1189
1215
clean_purl_fields = purl_fields .split ("(" )[0 ]
1190
1216
elif major_v == "5" or is_shrinkwrap :
1191
1217
clean_purl_fields = purl_fields .split ("_" )[0 ]
1192
- else :
1218
+ elif major_v == "9" :
1193
1219
clean_purl_fields = purl_fields
1194
- raise Exception (lockfile_version , purl_fields )
1220
+ else :
1221
+ message = f"Unknown pnpm lockfile format: { lockfile_version } "
1222
+ raise UnknownPnpmLockFormat (message , purl_fields )
1195
1223
1196
1224
sections = clean_purl_fields .split ("/" )
1197
- name_version = None
1225
+ name_version = None
1226
+ namespace = None
1198
1227
if major_v == "6" :
1199
1228
if len (sections ) == 2 :
1200
- namespace = None
1201
1229
_ , name_version = sections
1202
1230
elif len (sections ) == 3 :
1203
1231
_ , namespace , name_version = sections
1232
+ elif len (sections ) == 1 :
1233
+ name_version , = sections
1234
+
1235
+ name , version = name_version .split ("@" )
1236
+ elif major_v == "9" :
1237
+ if len (sections ) == 2 :
1238
+ namespace , name_version = sections
1239
+ elif len (sections ) == 1 :
1240
+ name_version , = sections
1204
1241
1205
1242
name , version = name_version .split ("@" )
1206
1243
elif major_v == "5" or is_shrinkwrap :
1207
1244
if len (sections ) == 3 :
1208
- namespace = None
1209
1245
_ , name , version = sections
1210
1246
elif len (sections ) == 4 :
1211
1247
_ , namespace , name , version = sections
@@ -1223,7 +1259,21 @@ def parse(cls, location, package_only=False):
1223
1259
1224
1260
dependencies = data .get ('dependencies' ) or {}
1225
1261
optional_dependencies = data .get ('optionalDependencies' ) or {}
1226
- transitive_peer_dependencies = data .get ('transitivePeerDependencies' ) or {}
1262
+ transitive_peer_dependencies = data .get ('transitivePeerDependencies' ) or []
1263
+
1264
+ if purl in dependency_relations_by_purl :
1265
+ dependency_relations = dependency_relations_by_purl .get (purl )
1266
+ if dependency_relations :
1267
+ deps = dependency_relations .get ('dependencies' )
1268
+ if deps :
1269
+ dependencies .update (deps )
1270
+ optional_deps = dependency_relations .get ('optionalDependencies' )
1271
+ if optional_deps :
1272
+ optional_dependencies .update (optional_deps )
1273
+ transitive_peer_deps = dependency_relations .get ('transitivePeerDependencies' )
1274
+ if transitive_peer_deps :
1275
+ transitive_peer_dependencies .extend (transitive_peer_deps )
1276
+
1227
1277
peer_dependencies = data .get ('peerDependencies' ) or {}
1228
1278
peer_dependencies_meta = data .get ('peerDependenciesMeta' ) or {}
1229
1279
0 commit comments