Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix wildcard pattern precedence in package.json exports/imports resolution #1458

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions packages/metro-resolver/src/__tests__/package-exports-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -510,16 +510,22 @@ describe('with package exports resolution enabled', () => {
'./features/bar/*.js': {
'react-native': null,
},
'./node/*': './lib/node/*.js',
'./*': './misc/*.js',
'./node/*/types': './types/*/types.d.ts',
'./assets/*': './assets/*',
},
}),
'/root/node_modules/test-pkg/lib/node/test.js': '',
'/root/node_modules/test-pkg/lib/node/foo/public.js': '',
'/root/node_modules/test-pkg/src/index.js': '',
'/root/node_modules/test-pkg/src/features/foo.js': '',
'/root/node_modules/test-pkg/src/features/foo.js.js': '',
'/root/node_modules/test-pkg/src/features/bar/Bar.js': '',
'/root/node_modules/test-pkg/src/features/baz.native.js': '',
'/root/node_modules/test-pkg/src/features/node_modules/foo/index.js':
'',
'/root/node_modules/test-pkg/types/foo/types.d.ts': '',
'/root/node_modules/test-pkg/assets/Logo.js': '',
}),
originModulePath: '/root/src/main.js',
Expand Down Expand Up @@ -577,6 +583,32 @@ describe('with package exports resolution enabled', () => {
`);
});

test('should resolve prefixed wildcard export, using the most specific export path', () => {
const context = baseContext;

expect(Resolver.resolve(context, 'test-pkg/node/test', null)).toEqual({
type: 'sourceFile',
filePath: '/root/node_modules/test-pkg/lib/node/test.js',
});
});

test('longer patterns have higher specificity if bases are equal', () => {
const context = baseContext;
expect(
Resolver.resolve(context, 'test-pkg/node/foo/public', null),
).toEqual({
type: 'sourceFile',
filePath: '/root/node_modules/test-pkg/lib/node/foo/public.js',
});

expect(
Resolver.resolve(context, 'test-pkg/node/foo/types', null),
).toEqual({
type: 'sourceFile',
filePath: '/root/node_modules/test-pkg/types/foo/types.d.ts',
});
});

describe('package encapsulation', () => {
test('[nonstrict] should fall back to "browser" spec resolution and log inaccessible import warning', () => {
const logWarning = jest.fn();
Expand Down
17 changes: 13 additions & 4 deletions packages/metro-resolver/src/utils/matchSubpathFromExportsLike.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,12 +55,21 @@ export function matchSubpathFromExportsLike(
// Attempt to match after expanding any subpath pattern keys
if (target == null) {
// Gather keys which are subpath patterns in descending order of specificity
// For ordering, see `PATTERN_KEY_COMPARE` in:
// https://nodejs.org/api/esm.html#resolution-algorithm-specification
const expansionKeys = [...exportsLikeMapAfterConditions.keys()]
.filter(key => key.includes('*'))
.sort(key => key.split('*')[0].length)
.reverse();
.map(key => ({key, baseLength: key.indexOf('*')}))
.filter(data => data.baseLength !== -1)
.sort((a, b) => {
if (a.baseLength === b.baseLength) {
// If wildcards are in equal positions, the longer key is more
// specific
return b.key.length - a.key.length;
}
return b.baseLength - a.baseLength;
});

for (const key of expansionKeys) {
for (const {key} of expansionKeys) {
const value = exportsLikeMapAfterConditions.get(key);

// Skip invalid values (must include a single '*' or be `null`)
Expand Down
Loading