diff --git a/src/index.js b/src/index.js index 84e9b7a..d7d6e3c 100644 --- a/src/index.js +++ b/src/index.js @@ -71,7 +71,7 @@ export function resolve(pkg, entry='.', options={}) { allows.add(require ? 'require' : 'import'); allows.add(browser ? 'browser' : 'node'); - let key, tmp, isSingle=false; + let key, tmp, isSingle=false, longestMatch=''; for (key in exports) { isSingle = key[0] !== '.'; @@ -90,18 +90,21 @@ export function resolve(pkg, entry='.', options={}) { for (key in exports) { tmp = key[key.length - 1]; - if (tmp === '/' && target.startsWith(key)) { - return (tmp = loop(exports[key], allows)) - ? (tmp + target.substring(key.length)) - : bail(name, target, 1); + if (key.length <= target.length && key.length > longestMatch.length && ( + tmp === '/' && target.startsWith(key) || + tmp === '*' && target.startsWith(key.slice(0, -1)) + )) { + longestMatch = key; } - if (tmp === '*' && target.startsWith(key.slice(0, -1))) { - // do not trigger if no *content* to inject - if (target.substring(key.length - 1).length > 0) { - return (tmp = loop(exports[key], allows)) - ? tmp.replace('*', target.substring(key.length - 1)) - : bail(name, target, 1); - } + } + + if (longestMatch) { + if (tmp = loop(exports[longestMatch], allows)) { + return (longestMatch[longestMatch.length - 1] === '/') + ? (tmp + target.slice(longestMatch.length)) + : tmp.replace('*', target.slice(longestMatch.length - 1)); + } else { + return bail(name, target, 1); } } diff --git a/test/resolve.js b/test/resolve.js index dd5dc39..63f7d69 100644 --- a/test/resolve.js +++ b/test/resolve.js @@ -425,6 +425,33 @@ resolve('exports["./features/*"] :: with "./" key', () => { fail(pkg, '.', 'foobar'); }); +resolve('exports["./features/*"] :: with unsorted keys', () => { + let pkg = { + "name": "foobar", + "exports": { + "./features/*": "./features/*.js", + "./": "./", + "./features/data/*": "./features/data/*.json" + } + }; + + pass(pkg, './features', 'features'); // via "./" + pass(pkg, './features', 'foobar/features'); // via "./" + + pass(pkg, './features/', 'features/'); // via "./" + pass(pkg, './features/', 'foobar/features/'); // via "./" + + pass(pkg, './features/hello.js', 'foobar/features/hello'); // via "./features/*" + pass(pkg, './features/world.js', 'foobar/features/world'); // via "./features/*"" + + pass(pkg, './features/data/hello.json', 'foobar/features/data/hello'); // via "./features/data/*" + pass(pkg, './features/data/world.json', 'foobar/features/data/world'); // via "./features/data/*" + + pass(pkg, './package.json', 'package.json'); // via "./" + pass(pkg, './package.json', 'foobar/package.json'); // via "./" + pass(pkg, './package.json', './package.json'); // via "./" +}); + resolve('exports["./features/*"] :: conditions', () => { let pkg = { "name": "foobar",