Skip to content

Commit

Permalink
fix: support "./foo/*.js" subpath patterns;
Browse files Browse the repository at this point in the history
- also keep longest subpath/key match
- Closes #22
- Closes #7, #8
  • Loading branch information
lukeed committed Jan 11, 2023
1 parent af93bda commit 7e41d63
Show file tree
Hide file tree
Showing 2 changed files with 93 additions and 14 deletions.
44 changes: 30 additions & 14 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ export function resolve(pkg, entry='.', options={}) {
unsafe || allows.add(require ? 'require' : 'import');
unsafe || allows.add(browser ? 'browser' : 'node');

let key, tmp, isSingle=false;
let key, m, k, kv, tmp, isSingle=false;

for (key in exports) {
isSingle = key[0] !== '.';
Expand All @@ -91,21 +91,37 @@ export function resolve(pkg, entry='.', options={}) {
return loop(tmp, allows) || bail(name, target, 1);
}

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 (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(/[*]/g, target.substring(key.length - 1))
: bail(name, target, 1);
if (target !== '.') {
for (key in exports) {
if (k && key.length < k.length) {
// do not allow "./" to match if already matched "./foo*" key
} else if (key[key.length - 1] === '/' && target.startsWith(key)) {
kv = target.substring(key.length);
k = key;
} else {
tmp = key.indexOf('*', 2);
if (!!~tmp) {
m = RegExp(
'^\.\/' + key.substring(2, tmp) + '(.*)' + key.substring(1+tmp)
).exec(target);

if (m && m[1]) {
kv = m[1];
k = key;
}
}
}
}

if (k && kv) {
// must have value
tmp = loop(exports[k], allows);
if (!tmp) return bail(name, target, 1);

return tmp.includes('*')
? tmp.replace(/[*]/g, kv)
: tmp + kv;
}
}

return bail(name, target);
Expand Down
63 changes: 63 additions & 0 deletions test/resolve.js
Original file line number Diff line number Diff line change
Expand Up @@ -485,6 +485,69 @@ resolve('exports["./features/*"] :: with "./" key', () => {
fail(pkg, '.', 'foobar');
});

// https://github.com/lukeed/resolve.exports/issues/7
resolve('exports["./features/*"] :: with "./" key first', () => {
let pkg = {
"name": "foobar",
"exports": {
"./": "./",
"./features/*": "./features/*.js"
}
};

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');
pass(pkg, './features/foo/bar.js', 'foobar/features/foo/bar');

// Valid: Pattern trailers allow any exact substrings to be matched
pass(pkg, './features/hello.js.js', 'foobar/features/hello.js');
pass(pkg, './features/foo/bar.js.js', 'foobar/features/foo/bar.js');

pass(pkg, './package.json', 'package.json');
pass(pkg, './package.json', 'foobar/package.json');
pass(pkg, './package.json', './package.json');

// Does NOT hit "./" (match Node)
fail(pkg, '.', '.');
fail(pkg, '.', 'foobar');
});

// https://nodejs.org/docs/latest-v18.x/api/packages.html#package-entry-points
resolve('exports["./features/*"] :: with "./features/*.js" key', () => {
let pkg = {
"name": "foobar",
"exports": {
"./features/*": "./features/*.js",
"./features/*.js": "./features/*.js",
}
};

fail(pkg, './features', 'features');
fail(pkg, './features', 'foobar/features');

fail(pkg, './features/', 'features/');
fail(pkg, './features/', 'foobar/features/');

pass(pkg, './features/a.js', 'foobar/features/a');
pass(pkg, './features/ab.js', 'foobar/features/ab');
pass(pkg, './features/abc.js', 'foobar/features/abc');

pass(pkg, './features/hello.js', 'foobar/features/hello');
pass(pkg, './features/hello.js', 'foobar/features/hello.js');

pass(pkg, './features/foo/bar.js', 'foobar/features/foo/bar');
pass(pkg, './features/foo/bar.js', 'foobar/features/foo/bar.js');

fail(pkg, './package.json', 'package.json');
fail(pkg, './package.json', 'foobar/package.json');
fail(pkg, './package.json', './package.json');
});

resolve('exports["./features/*"] :: conditions', () => {
let pkg = {
"name": "foobar",
Expand Down

0 comments on commit 7e41d63

Please sign in to comment.