@@ -73,7 +73,32 @@ def _convert_pnpm_v6_v9_version_peer_dep(version):
7373
7474######################### Lockfile v9 #########################
7575
76- def _convert_pnpm_v9_package_dependency_version (snapshots , name , version ):
76+ def _v9_snapshot_key_to_package_key (snapshot_key ):
77+ peer_meta_index = snapshot_key .find ("(" )
78+ package_key = snapshot_key [:peer_meta_index ] if peer_meta_index > 0 else snapshot_key
79+ return package_key
80+
81+ def _v9_resolve_link_version (packages , snapshot_key , name , link ):
82+ package_key = _v9_snapshot_key_to_package_key (snapshot_key )
83+ package = packages [package_key ]
84+ resolution = package ["resolution" ]
85+
86+ # :link dep from file:package will be relative to the file:package and not the workspace root
87+ if resolution .get ("type" , None ) == "directory" :
88+ # ... unless that link: dep is resolved from a peerDependency, then it is already resolved to workspace-relative
89+ if "peerDependencies" in package and name in package ["peerDependencies" ]:
90+ return link
91+
92+ return paths .normalize (paths .join (resolution ["directory" ], link ))
93+
94+ # in the standard case snapshot link: deps are already relative to the workspace root
95+ return link
96+
97+ def _convert_pnpm_v9_package_dependency_version (packages , snapshots , snapshot_key , name , version ):
98+ if version .startswith ("link:" ):
99+ # Resolve link: deps to be workspace root relative
100+ version = "link:" + _v9_resolve_link_version (packages , snapshot_key , name , version [5 :])
101+
77102 # Detect when an alias is just a direct reference to another snapshot
78103 is_alias = version in snapshots
79104
@@ -82,10 +107,10 @@ def _convert_pnpm_v9_package_dependency_version(snapshots, name, version):
82107
83108 return "npm:{}" .format (version ) if is_alias else version
84109
85- def _convert_pnpm_v9_package_dependency_map (snapshots , deps ):
110+ def _convert_pnpm_v9_package_dependency_map (packages , snapshots , snapshot_key , deps ):
86111 result = {}
87112 for name , version in deps .items ():
88- result [name ] = _convert_pnpm_v9_package_dependency_version (snapshots , name , version )
113+ result [name ] = _convert_pnpm_v9_package_dependency_version (packages , snapshots , snapshot_key , name , version )
89114 return result
90115
91116def _convert_pnpm_v9_importer_dependency_map (import_path , deps ):
@@ -156,9 +181,8 @@ def _convert_v9_packages(packages, snapshots):
156181 result = {}
157182
158183 # Snapshots contains the packages with the keys (which include peers) to return
159- for package_key , package_snapshot in snapshots .items ():
160- peer_meta_index = package_key .find ("(" )
161- static_key = package_key [:peer_meta_index ] if peer_meta_index > 0 else package_key
184+ for snapshot_key , package_snapshot in snapshots .items ():
185+ static_key = _v9_snapshot_key_to_package_key (snapshot_key )
162186 if not static_key in packages :
163187 msg = "package {} not found in pnpm 'packages'" .format (static_key )
164188 fail (msg )
@@ -173,7 +197,7 @@ def _convert_v9_packages(packages, snapshots):
173197 version_index = static_key .index ("@" , 1 )
174198 name = static_key [:version_index ]
175199
176- package_key = _convert_pnpm_v6_v9_version_peer_dep (package_key )
200+ package_key = _convert_pnpm_v6_v9_version_peer_dep (snapshot_key )
177201
178202 # Extract the version including peerDeps+patch from the key
179203 version = _convert_pnpm_v6_v9_version_peer_dep (package_key [package_key .index ("@" , 1 ) + 1 :])
@@ -185,8 +209,8 @@ def _convert_v9_packages(packages, snapshots):
185209 name = name ,
186210 version = version ,
187211 friendly_version = friendly_version ,
188- dependencies = _convert_pnpm_v9_package_dependency_map (snapshots , package_snapshot .get ("dependencies" , {})),
189- optional_dependencies = _convert_pnpm_v9_package_dependency_map (snapshots , package_snapshot .get ("optionalDependencies" , {})),
212+ dependencies = _convert_pnpm_v9_package_dependency_map (packages , snapshots , snapshot_key , package_snapshot .get ("dependencies" , {})),
213+ optional_dependencies = _convert_pnpm_v9_package_dependency_map (packages , snapshots , snapshot_key , package_snapshot .get ("optionalDependencies" , {})),
190214 has_bin = package_data .get ("hasBin" , False ),
191215 optional = package_snapshot .get ("optional" , False ),
192216 resolution = package_data ["resolution" ],
@@ -258,31 +282,38 @@ def _parse_lockfile(parsed, err):
258282
259283def _validate_lockfile_data (importers , packages ):
260284 for name , deps in importers .items ():
261- _validate_lockfile_deps (packages , "importer" , name , deps ["dependencies" ])
262- _validate_lockfile_deps (packages , "importer" , name , deps ["dev_dependencies" ])
263- _validate_lockfile_deps (packages , "importer" , name , deps ["optional_dependencies" ])
285+ _validate_lockfile_deps (importers , packages , "importer" , name , deps ["dependencies" ])
286+ _validate_lockfile_deps (importers , packages , "importer" , name , deps ["dev_dependencies" ])
287+ _validate_lockfile_deps (importers , packages , "importer" , name , deps ["optional_dependencies" ])
264288
265289 for name , info in packages .items ():
266- _validate_lockfile_deps (packages , "package" , name , info ["dependencies" ])
267- _validate_lockfile_deps (packages , "package" , name , info ["optional_dependencies" ])
290+ _validate_lockfile_deps (importers , packages , "package" , name , info ["dependencies" ])
291+ _validate_lockfile_deps (importers , packages , "package" , name , info ["optional_dependencies" ])
268292
269- def _validate_lockfile_deps (packages , importer_type , importer , deps ):
293+ def _validate_lockfile_deps (importers , packages , importer_type , importer , deps ):
270294 for dep , version in deps .items ():
271295 if version .startswith ("npm:" ):
272296 version = version [4 :]
273297
274- if version not in packages and not (version .startswith ("file:" ) or version .startswith ("link:" )) and not ("{}@{}" .format (dep , version ) in packages ):
298+ if version .startswith ("link:" ):
299+ if version [5 :] not in importers :
300+ msg = "ERROR: {} '{}' depends on package '{}' at link path '{}' which is not in the importers: {}" .format (
301+ importer_type ,
302+ importer ,
303+ dep ,
304+ version ,
305+ importers .keys (),
306+ )
307+ fail (msg )
308+ elif version not in packages and not ("{}@{}" .format (dep , version ) in packages ):
275309 msg = "ERROR: {} '{}' depends on package '{}' at version '{}' which is not in the packages: {}" .format (
276310 importer_type ,
277311 importer ,
278312 dep ,
279313 version ,
280314 packages .keys (),
281315 )
282-
283- # TODO(3.0): fail instead of print
284- # buildifier: disable=print
285- print (msg )
316+ fail (msg )
286317
287318def _assert_lockfile_version (version , testonly = False ):
288319 if type (version ) != type (1.0 ):
0 commit comments