From 0d6c2cbafc53fee960e34e2c7ccc1494b9d1ba96 Mon Sep 17 00:00:00 2001 From: Guy Bedford Date: Wed, 8 Sep 2021 12:14:03 -0700 Subject: [PATCH] module: support pattern trailers for imports field --- lib/internal/modules/esm/resolve.js | 38 ++++++++++++------- test/es-module/test-esm-imports.mjs | 2 + .../es-modules/pkgimports/package.json | 1 + 3 files changed, 27 insertions(+), 14 deletions(-) diff --git a/lib/internal/modules/esm/resolve.js b/lib/internal/modules/esm/resolve.js index ca0e1b316fc5b6..0ea5630d7a9c34 100644 --- a/lib/internal/modules/esm/resolve.js +++ b/lib/internal/modules/esm/resolve.js @@ -22,7 +22,6 @@ const { StringPrototypeSlice, StringPrototypeSplit, StringPrototypeStartsWith, - StringPrototypeSubstr, } = primordials; const internalFS = require('internal/fs/utils'); const { NativeModule } = require('internal/bootstrap/loaders'); @@ -695,7 +694,9 @@ 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 ); @@ -703,30 +704,39 @@ function packageImportsResolve(name, base, conditions) { 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) { if (!pattern) emitFolderMapDeprecation(bestMatch, packageJSONUrl, false, base); diff --git a/test/es-module/test-esm-imports.mjs b/test/es-module/test-esm-imports.mjs index 694496a2ff2c93..577e33b60d08ec 100644 --- a/test/es-module/test-esm-imports.mjs +++ b/test/es-module/test-esm-imports.mjs @@ -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) { diff --git a/test/fixtures/es-modules/pkgimports/package.json b/test/fixtures/es-modules/pkgimports/package.json index a2224b39ddd2ac..299ce9c197b554 100644 --- a/test/fixtures/es-modules/pkgimports/package.json +++ b/test/fixtures/es-modules/pkgimports/package.json @@ -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",