Skip to content

Commit

Permalink
module: support pattern trailers for imports field
Browse files Browse the repository at this point in the history
PR-URL: nodejs#40041
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Geoffrey Booth <webmaster@geoffreybooth.com>
  • Loading branch information
guybedford committed Sep 15, 2021
1 parent abd2ab9 commit f5c3d1e
Show file tree
Hide file tree
Showing 3 changed files with 27 additions and 14 deletions.
38 changes: 24 additions & 14 deletions lib/internal/modules/esm/resolve.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ const {
StringPrototypeSlice,
StringPrototypeSplit,
StringPrototypeStartsWith,
StringPrototypeSubstr,
} = primordials;
const internalFS = require('internal/fs/utils');
const { NativeModule } = require('internal/bootstrap/loaders');
Expand Down Expand Up @@ -582,38 +581,49 @@ function packageImportsResolve(name, base, conditions) {
packageJSONUrl = pathToFileURL(packageConfig.pjsonPath);
const imports = packageConfig.imports;
if (imports) {
if (ObjectPrototypeHasOwnProperty(imports, name)) {
if (ObjectPrototypeHasOwnProperty(imports, name) &&
!StringPrototypeIncludes(name, '*') &&
!StringPrototypeEndsWith(name, '/')) {
const resolved = resolvePackageTarget(
packageJSONUrl, imports[name], '', name, base, false, true, conditions
);
if (resolved !== null)
return { resolved, exact: true };
} else {
let bestMatch = '';
let bestMatchSubpath;
const keys = ObjectGetOwnPropertyNames(imports);
for (let i = 0; i < keys.length; i++) {
const key = keys[i];
if (key[key.length - 1] === '*' &&
const patternIndex = StringPrototypeIndexOf(key, '*');
if (patternIndex !== -1 &&
StringPrototypeStartsWith(name,
StringPrototypeSlice(key, 0, -1)) &&
name.length >= key.length &&
key.length > bestMatch.length) {
bestMatch = key;
StringPrototypeSlice(key, 0,
patternIndex))) {
const patternTrailer = StringPrototypeSlice(key, patternIndex + 1);
if (name.length >= key.length &&
StringPrototypeEndsWith(name, patternTrailer) &&
patternKeyCompare(bestMatch, key) === 1 &&
StringPrototypeLastIndexOf(key, '*') === patternIndex) {
bestMatch = key;
bestMatchSubpath = StringPrototypeSlice(
name, patternIndex, name.length - patternTrailer.length);
}
} else if (key[key.length - 1] === '/' &&
StringPrototypeStartsWith(name, key) &&
key.length > bestMatch.length) {
patternKeyCompare(bestMatch, key) === 1) {
bestMatch = key;
bestMatchSubpath = StringPrototypeSlice(name, key.length);
}
}

if (bestMatch) {
const target = imports[bestMatch];
const pattern = bestMatch[bestMatch.length - 1] === '*';
const subpath = StringPrototypeSubstr(name, bestMatch.length -
(pattern ? 1 : 0));
const resolved = resolvePackageTarget(
packageJSONUrl, target, subpath, bestMatch, base, pattern, true,
conditions);
const pattern = StringPrototypeIncludes(bestMatch, '*');
const resolved = resolvePackageTarget(packageJSONUrl, target,
bestMatchSubpath, bestMatch,
base, pattern, true,
conditions);
if (resolved !== null)
return { resolved, exact: pattern };
}
Expand Down
2 changes: 2 additions & 0 deletions test/es-module/test-esm-imports.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ const { requireImport, importImport } = importer;
['#external', { default: 'asdf' }],
// External subpath imports
['#external/subpath/asdf.js', { default: 'asdf' }],
// Trailing pattern imports
['#subpath/asdf.asdf', { default: 'test' }],
]);

for (const [validSpecifier, expected] of internalImports) {
Expand Down
1 change: 1 addition & 0 deletions test/fixtures/es-modules/pkgimports/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
"require": "./requirebranch.js"
},
"#subpath/*": "./sub/*",
"#subpath/*.asdf": "./test.js",
"#external": "pkgexports/valid-cjs",
"#external/subpath/*": "pkgexports/sub/*",
"#external/invalidsubpath/": "pkgexports/sub",
Expand Down

0 comments on commit f5c3d1e

Please sign in to comment.