diff --git a/lib/util/entrypoints.js b/lib/util/entrypoints.js index b925d626..80d10d67 100644 --- a/lib/util/entrypoints.js +++ b/lib/util/entrypoints.js @@ -430,7 +430,24 @@ function targetMapping( return mappingTarget + remainingRequest; } assert(mappingTarget, false); - return mappingTarget.replace(/\*/g, remainingRequest.replace(/\$/g, "$$")); + const wildcardIndex = mappingTarget.indexOf("*"); + + if (wildcardIndex !== -1) { + const maybeCommonSuffix = mappingTarget.slice(wildcardIndex + 1); + if (remainingRequest.endsWith(maybeCommonSuffix)) { + return mappingTarget.replace( + new RegExp(`\\*${maybeCommonSuffix}`, "g"), + remainingRequest.replace(/\$/g, "$$") + ); + } else { + return mappingTarget.replace( + /\*/g, + remainingRequest.replace(/\$/g, "$$") + ); + } + } else { + return mappingTarget; + } } /** @@ -549,9 +566,10 @@ function walkPath(root, path, target) { node.folder = target; } else { const file = lastNonSlashIndex > 0 ? path.slice(lastNonSlashIndex) : path; - if (file.endsWith("*")) { + const wildcardsIndex = file.indexOf("*"); + if (wildcardsIndex !== -1) { if (node.wildcards === null) node.wildcards = new Map(); - node.wildcards.set(file.slice(0, -1), target); + node.wildcards.set(file.slice(0, wildcardsIndex), target); } else { node.files.set(file, target); } diff --git a/test/exportsField.js b/test/exportsField.js index d2f2d685..f7ee92af 100644 --- a/test/exportsField.js +++ b/test/exportsField.js @@ -1953,6 +1953,28 @@ describe("Process exports field", function exportsField() { "./a/b/d/c.js", [] ] + }, + { + name: "wildcard pattern with suffix #1", + expect: ["./A/b.js"], + suite: [ + { + "./a/*.js": "./A/*.js" + }, + "./a/b.js", + [] + ] + }, + { + name: "wildcard pattern with suffix #2", + expect: ["./A/b/c.js"], + suite: [ + { + "./a/*.js": "./A/*.js" + }, + "./a/b/c.js", + [] + ] } ]; @@ -2452,4 +2474,36 @@ describe("ExportsFieldPlugin", () => { } ); }); + + it("should resolve with wildcard pattern #1", done => { + const fixture = path.resolve( + __dirname, + "./fixtures/imports-exports-wildcard/" + ); + + resolver.resolve({}, fixture, "m/features/f.js", {}, (err, result) => { + if (err) return done(err); + if (!result) throw new Error("No result"); + result.should.equal( + path.resolve(fixture, "./node_modules/m/src/features/f.js") + ); + done(); + }); + }); + + it("should resolve with wildcard pattern #2", done => { + const fixture = path.resolve( + __dirname, + "./fixtures/imports-exports-wildcard/" + ); + + resolver.resolve({}, fixture, "m/features/y/y.js", {}, (err, result) => { + if (err) return done(err); + if (!result) throw new Error("No result"); + result.should.equal( + path.resolve(fixture, "./node_modules/m/src/features/y/y.js") + ); + done(); + }); + }); }); diff --git a/test/fixtures/imports-exports-wildcard/node_modules/m/package.json b/test/fixtures/imports-exports-wildcard/node_modules/m/package.json new file mode 100644 index 00000000..d610922b --- /dev/null +++ b/test/fixtures/imports-exports-wildcard/node_modules/m/package.json @@ -0,0 +1,9 @@ +{ + "name": "m", + "exports": { + "./features/*.js": "./src/features/*.js" + }, + "imports": { + "#internal/*.js": "./src/internal/*.js" + } +} diff --git a/test/fixtures/imports-exports-wildcard/node_modules/m/src/features/f.js b/test/fixtures/imports-exports-wildcard/node_modules/m/src/features/f.js new file mode 100644 index 00000000..e69de29b diff --git a/test/fixtures/imports-exports-wildcard/node_modules/m/src/features/y/y.js b/test/fixtures/imports-exports-wildcard/node_modules/m/src/features/y/y.js new file mode 100644 index 00000000..e69de29b diff --git a/test/fixtures/imports-exports-wildcard/node_modules/m/src/internal/i.js b/test/fixtures/imports-exports-wildcard/node_modules/m/src/internal/i.js new file mode 100644 index 00000000..e69de29b diff --git a/test/importsField.js b/test/importsField.js index 334cd87a..59eacba4 100644 --- a/test/importsField.js +++ b/test/importsField.js @@ -1357,4 +1357,17 @@ describe("ImportsFieldPlugin", () => { } ); }); + + it("should resolve with wildcard pattern", done => { + const fixture = path.resolve( + __dirname, + "./fixtures/imports-exports-wildcard/node_modules/m/" + ); + resolver.resolve({}, fixture, "#internal/i.js", {}, (err, result) => { + if (err) return done(err); + if (!result) throw new Error("No result"); + result.should.equal(path.resolve(fixture, "./src/internal/i.js")); + done(); + }); + }); });