@@ -49,10 +49,18 @@ export function updateMappingsForPackageJson(
4949) : PackageJson {
5050 const newPackageJson = { ...packageJson } ;
5151
52- updateMappingForRecord ( newPackageJson . dependencies ?? { } , mappings ) ;
53- updateMappingForRecord ( newPackageJson . devDependencies ?? { } , mappings ) ;
54- updateMappingForRecord ( newPackageJson . optionalDependencies ?? { } , mappings ) ;
55- updateMappingForRecord ( newPackageJson . resolutions ?? { } , mappings ) ;
52+ updateMappingForRecord ( newPackageJson , 'dependencies' , mappings ) ;
53+ updateMappingForRecord ( newPackageJson , 'devDependencies' , mappings ) ;
54+ updateMappingForRecord ( newPackageJson , 'optionalDependencies' , mappings ) ;
55+ // The object for Yarn resolutions will not directly match with the mapping keys
56+ // specified here, as resolutions usually follow a format as followed:
57+ // 1. `**/<pkg-name>`
58+ // 2. `<other-pkg>/**/<pkg-name>`
59+ // 3. `<pkg-name>`
60+ // More details here: https://classic.yarnpkg.com/lang/en/docs/selective-version-resolutions/.
61+ // We pass a regular expression which matches the `<pkg-name>` so that the mappings can
62+ // be applied for resolutions as well.
63+ updateMappingForRecord ( newPackageJson , 'resolutions' , mappings , / ( [ ^ / ] + ) $ / ) ;
5664
5765 return newPackageJson ;
5866}
@@ -64,15 +72,31 @@ export function updateMappingsForPackageJson(
6472 * @throws An error if there is a dependency entry referring to a local file. Such
6573 * entries should not use `file:` but instead configure a mapping through Bazel.
6674 */
67- function updateMappingForRecord ( record : DependencyRecord , mappings : PackageMappings ) {
68- for ( const [ pkgName , value ] of Object . entries ( record ) ) {
75+ function updateMappingForRecord (
76+ pkgJson : PackageJson ,
77+ recordName : keyof PackageJson ,
78+ mappings : PackageMappings ,
79+ nameMatchRegex ?: RegExp ,
80+ ) {
81+ const record = pkgJson [ recordName ] ?? { } ;
82+
83+ for ( const [ entryKey , value ] of Object . entries ( record ) ) {
84+ const pkgName = getPackageNameFromDependencyEntry ( entryKey , nameMatchRegex ) ;
85+
86+ if ( pkgName === null ) {
87+ throw Error ( `Could not determine package name for "${ recordName } " entry: ${ entryKey } .` ) ;
88+ }
89+
90+ // Print the resolved package name to ease debugging when packages are not mapped properly.
91+ debug ( `updateMappingForRecord: Resolved "${ recordName } @${ entryKey } " to package: ${ pkgName } ` ) ;
92+
6993 const mappedAbsolutePath = mappings [ pkgName ] ;
7094
7195 // If the value of the dependency entry is referring to a local file, then we report
7296 // an error as this is likely a missing mapping that should be set up through Bazel.
7397 if ( mappedAbsolutePath === undefined && value . startsWith ( `file:` ) ) {
7498 throw Error (
75- `Unexpected dependency entry for: ${ pkgName } , pointing to: ${ value } .` +
99+ `Unexpected dependency entry for: ${ entryKey } , pointing to: ${ value } . ` +
76100 `Instead, configure the mapping through the integration test Bazel target.` ,
77101 ) ;
78102 }
@@ -82,6 +106,25 @@ function updateMappingForRecord(record: DependencyRecord, mappings: PackageMappi
82106 continue ;
83107 }
84108
85- record [ pkgName ] = mappedAbsolutePath ;
109+ record [ entryKey ] = mappedAbsolutePath ;
110+ }
111+ }
112+
113+ /**
114+ * Gets the package name from a dependency record entry.
115+ *
116+ * @param entryKey Key of the dependency record entry.
117+ * @param nameMatchRegex Optional regular expression that can be specified to match the package
118+ * name in a dependency entry. This is useful for e.g. Yarn resolutions using patterns.
119+ * The first capturing group is expected to return the matched package name.
120+ */
121+ function getPackageNameFromDependencyEntry (
122+ entryKey : string ,
123+ nameMatchRegex ?: RegExp ,
124+ ) : string | null {
125+ if ( nameMatchRegex ) {
126+ const matches = entryKey . match ( nameMatchRegex ) ;
127+ return matches === null ? null : matches [ 1 ] ;
86128 }
129+ return entryKey ;
87130}
0 commit comments