@@ -240,6 +240,9 @@ def manifest_dependencies
240240 next if requirement . start_with? ( "workspace:" , "catalog:" )
241241
242242 requirement = "*" if requirement == ""
243+
244+ name , requirement = dealias_package ( name , requirement ) if dealias_packages?
245+
243246 dep = build_dependency (
244247 file : file , type : type , name : name , requirement : requirement
245248 )
@@ -388,6 +391,64 @@ def aliased_package_name?(name)
388391 name . include? ( "@#{ NpmPackageManager ::NAME } :" )
389392 end
390393
394+ sig { returns ( T ::Boolean ) }
395+ def dealias_packages?
396+ options . fetch ( :dealias_packages , false ) == true
397+ end
398+
399+ # Resolves an aliased manifest entry to its real package name and requirement.
400+ # Yarn-style: "my-fetch-factory@npm:fetch-factory": "0.0.2"
401+ # npm-style: "my-fetch-factory": "npm:fetch-factory@0.0.2"
402+ sig { params ( name : String , requirement : String ) . returns ( [ String , String ] ) }
403+ def dealias_package ( name , requirement )
404+ if aliased_package_name? ( name )
405+ real_name = extract_real_name_from_alias_key ( name )
406+ name = real_name if real_name
407+ elsif alias_package? ( requirement )
408+ parsed = parse_alias_package_requirement ( requirement )
409+ if parsed
410+ name = T . must ( parsed [ :name ] )
411+ requirement = T . must ( parsed [ :requirement ] )
412+ end
413+ end
414+
415+ [ name , requirement ]
416+ end
417+
418+ # npm-style: "npm:fetch-factory@0.0.2" → { name: "fetch-factory", requirement: "0.0.2" }
419+ # npm-style: "npm:@scope/pkg@^1.0.0" → { name: "@scope/pkg", requirement: "^1.0.0" }
420+ sig { params ( requirement : String ) . returns ( T . nilable ( T ::Hash [ Symbol , String ] ) ) }
421+ def parse_alias_package_requirement ( requirement )
422+ return nil unless requirement . start_with? ( "#{ NpmPackageManager ::NAME } :" )
423+
424+ rest = requirement . delete_prefix ( "#{ NpmPackageManager ::NAME } :" )
425+
426+ if rest . start_with? ( "@" )
427+ second_at = rest . index ( "@" , 1 )
428+ if second_at
429+ { name : rest [ 0 ...second_at ] , requirement : rest [ ( second_at + 1 ) ..] }
430+ else
431+ { name : rest , requirement : "*" }
432+ end
433+ else
434+ at_index = rest . index ( "@" )
435+ if at_index
436+ { name : rest [ 0 ...at_index ] , requirement : rest [ ( at_index + 1 ) ..] }
437+ else
438+ { name : rest , requirement : "*" }
439+ end
440+ end
441+ end
442+
443+ # Yarn-style: "my-fetch-factory@npm:fetch-factory" → "fetch-factory"
444+ sig { params ( name : String ) . returns ( T . nilable ( String ) ) }
445+ def extract_real_name_from_alias_key ( name )
446+ match = name . match ( /@#{ NpmPackageManager ::NAME } :(.+)$/o )
447+ return nil unless match
448+
449+ match [ 1 ]
450+ end
451+
391452 sig { returns ( T ::Array [ String ] ) }
392453 def workspace_package_names
393454 @workspace_package_names ||= T . let (
0 commit comments