Skip to content

Commit

Permalink
feat: directory/subpath mapping;
Browse files Browse the repository at this point in the history
- support deprecated syntax ("./", "./foo/")
- support new wildcard syntax ("./*" -> "./hello/*.js")
  • Loading branch information
lukeed committed Jan 8, 2021
1 parent 9daed2a commit 9e66106
Show file tree
Hide file tree
Showing 3 changed files with 85 additions and 24 deletions.
4 changes: 2 additions & 2 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@
- [x] exports object (multi entry)
- [x] nested conditions
- [ ] exports arrayable
- [ ] directory mapping (`./foobar/` => `/foobar/`)
- [ ] directory mapping (`./foobar/*` => `./other/*.js`)
- [x] directory mapping (`./foobar/` => `/foobar/`)
- [x] directory mapping (`./foobar/*` => `./other/*.js`)
- [ ] `options.file` => absolute filepath
- [ ] legacy fields

Expand Down
34 changes: 20 additions & 14 deletions src/index.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import { join } from 'path';

/**
* @todo arrayable
* @param {object} exports
Expand Down Expand Up @@ -60,12 +58,9 @@ export function resolve(pkg, entry='.', options={}) {
if (requires) allows.add('require');
allows.add(browser ? 'browser' : 'node');

// TODO: "./*"
const isLoose = exports['./'];
let key, isSingle = !isLoose;
let key, tmp, isSingle=false;

// might just not have "./" key
if (isSingle) for (key in exports) {
for (key in exports) {
isSingle = key.charAt(0) !== '.';
break;
}
Expand All @@ -74,13 +69,24 @@ export function resolve(pkg, entry='.', options={}) {
return isSelf && loop(exports, allows) || bail(name, target);
}

let item = exports[target];
// TODO: no known keys error
if (item) return loop(item, allows);
if (tmp = exports[target]) {
if (tmp = loop(tmp, allows)) return tmp;
throw new Error(`No valid keys for "${target}" entry in "${name}" package`);
}

for (key in exports) {
tmp = key.charAt(key.length - 1);
if (tmp === '/' && target.startsWith(key)) {
return exports[key] + target.substring(key.length);
}
if (tmp === '*' && target.startsWith(key.slice(0, -1))) {
// do not trigger if no *content* to inject
if (tmp = target.substring(key.length - 1)) {
return exports[key].replace('*', tmp);
}
}
}

// NOTE: is only "./", may be other directory mappings
// TODO: can now also have "./*"
// @see https://nodejs.org/api/packages.html#packages_subpath_folder_mappings
return isLoose ? join(isLoose, target) : bail(name, target);
return bail(name, target);
}
}
71 changes: 63 additions & 8 deletions test/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -130,8 +130,6 @@ resolve('exports["./foo"] = object', () => {
fail(pkg, './other', 'foobar/other');
});

// TODO: folder mappings -- https://nodejs.org/api/packages.html#packages_subpath_folder_mappings

// https://nodejs.org/api/packages.html#packages_nested_conditions
resolve('nested conditions', () => {
let pkg = {
Expand All @@ -157,9 +155,6 @@ resolve('nested conditions', () => {
fail(pkg, './other', 'other');
});

// TODO: incomplete
// TODO? do require.resolve on directory?
// https://nodejs.org/api/packages.html#packages_subpath_folder_mappings
resolve('exports["./"]', () => {
let pkg = {
"name": "foobar",
Expand All @@ -182,9 +177,69 @@ resolve('exports["./"]', () => {
pass(pkg, './package.json', './package.json');

// "loose" / everything exposed
// pass(pkg, './hello.js', 'hello.js');
// pass(pkg, './hello.js', 'foobar/hello.js');
// pass(pkg, './hello/world.js', './hello/world.js');
pass(pkg, './hello.js', 'hello.js');
pass(pkg, './hello.js', 'foobar/hello.js');
pass(pkg, './hello/world.js', './hello/world.js');
});

// https://nodejs.org/api/packages.html#packages_subpath_folder_mappings
resolve('exports["./features/"]', () => {
let pkg = {
"name": "foobar",
"exports": {
"./features/": "./features/",
"./package.json": "./package.json",
"./": "./"
}
};

pass(pkg, './features', 'features'); // via "./"
pass(pkg, './features', 'foobar/features'); // via "./"

pass(pkg, './features/', 'features/'); // via "./features/"
pass(pkg, './features/', 'foobar/features/'); // via "./features/"

pass(pkg, './features/hello.js', 'foobar/features/hello.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/api/packages.html#packages_subpath_folder_mappings
resolve('exports["./features/*"]', () => {
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/world.js', 'foobar/features/world');

// incorrect, but matches Node. evaluate as defined
pass(pkg, './features/hello.js.js', 'foobar/features/hello.js');
pass(pkg, './features/world.js.js', 'foobar/features/world.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');
});

resolve.run();

0 comments on commit 9e66106

Please sign in to comment.