diff options
Diffstat (limited to 'node_modules/resolve.exports')
| -rw-r--r-- | node_modules/resolve.exports/dist/index.js | 149 | ||||
| -rw-r--r-- | node_modules/resolve.exports/dist/index.mjs | 146 | ||||
| -rw-r--r-- | node_modules/resolve.exports/index.d.ts | 21 | ||||
| -rw-r--r-- | node_modules/resolve.exports/license | 21 | ||||
| -rw-r--r-- | node_modules/resolve.exports/package.json | 47 | ||||
| -rw-r--r-- | node_modules/resolve.exports/readme.md | 320 | 
6 files changed, 704 insertions, 0 deletions
diff --git a/node_modules/resolve.exports/dist/index.js b/node_modules/resolve.exports/dist/index.js new file mode 100644 index 0000000..0f6e0ad --- /dev/null +++ b/node_modules/resolve.exports/dist/index.js @@ -0,0 +1,149 @@ +/** + * @param {object} exports + * @param {Set<string>} keys + */ +function loop(exports, keys) { +	if (typeof exports === 'string') { +		return exports; +	} + +	if (exports) { +		let idx, tmp; +		if (Array.isArray(exports)) { +			for (idx=0; idx < exports.length; idx++) { +				if (tmp = loop(exports[idx], keys)) return tmp; +			} +		} else { +			for (idx in exports) { +				if (keys.has(idx)) { +					return loop(exports[idx], keys); +				} +			} +		} +	} +} + +/** + * @param {string} name The package name + * @param {string} entry The target entry, eg "." + * @param {number} [condition] Unmatched condition? + */ +function bail(name, entry, condition) { +	throw new Error( +		condition +		? `No known conditions for "${entry}" entry in "${name}" package` +		: `Missing "${entry}" export in "${name}" package` +	); +} + +/** + * @param {string} name the package name + * @param {string} entry the target path/import + */ +function toName(name, entry) { +	return entry === name ? '.' +		: entry[0] === '.' ? entry +		: entry.replace(new RegExp('^' + name + '\/'), './'); +} + +/** + * @param {object} pkg package.json contents + * @param {string} [entry] entry name or import path + * @param {object} [options] + * @param {boolean} [options.browser] + * @param {boolean} [options.require] + * @param {string[]} [options.conditions] + * @param {boolean} [options.unsafe] + */ +function resolve(pkg, entry='.', options={}) { +	let { name, exports } = pkg; + +	if (exports) { +		let { browser, require, unsafe, conditions=[] } = options; + +		let target = toName(name, entry); +		if (target[0] !== '.') target = './' + target; + +		if (typeof exports === 'string') { +			return target === '.' ? exports : bail(name, target); +		} + +		let allows = new Set(['default', ...conditions]); +		unsafe || allows.add(require ? 'require' : 'import'); +		unsafe || allows.add(browser ? 'browser' : 'node'); + +		let key, tmp, isSingle=false; + +		for (key in exports) { +			isSingle = key[0] !== '.'; +			break; +		} + +		if (isSingle) { +			return target === '.' +				? loop(exports, allows) || bail(name, target, 1) +				: bail(name, target); +		} + +		if (tmp = exports[target]) { +			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('*', target.substring(key.length - 1)) +						: bail(name, target, 1); +				} +			} +		} + +		return bail(name, target); +	} +} + +/** + * @param {object} pkg + * @param {object} [options] + * @param {string|boolean} [options.browser] + * @param {string[]} [options.fields] + */ +function legacy(pkg, options={}) { +	let i=0, value, +		browser = options.browser, +		fields = options.fields || ['module', 'main']; + +	if (browser && !fields.includes('browser')) { +		fields.unshift('browser'); +	} + +	for (; i < fields.length; i++) { +		if (value = pkg[fields[i]]) { +			if (typeof value == 'string') { +				// +			} else if (typeof value == 'object' && fields[i] == 'browser') { +				if (typeof browser == 'string') { +					value = value[browser=toName(pkg.name, browser)]; +					if (value == null) return browser; +				} +			} else { +				continue; +			} + +			return typeof value == 'string' +				? ('./' + value.replace(/^\.?\//, '')) +				: value; +		} +	} +} + +exports.legacy = legacy; +exports.resolve = resolve;
\ No newline at end of file diff --git a/node_modules/resolve.exports/dist/index.mjs b/node_modules/resolve.exports/dist/index.mjs new file mode 100644 index 0000000..6be642c --- /dev/null +++ b/node_modules/resolve.exports/dist/index.mjs @@ -0,0 +1,146 @@ +/** + * @param {object} exports + * @param {Set<string>} keys + */ +function loop(exports, keys) { +	if (typeof exports === 'string') { +		return exports; +	} + +	if (exports) { +		let idx, tmp; +		if (Array.isArray(exports)) { +			for (idx=0; idx < exports.length; idx++) { +				if (tmp = loop(exports[idx], keys)) return tmp; +			} +		} else { +			for (idx in exports) { +				if (keys.has(idx)) { +					return loop(exports[idx], keys); +				} +			} +		} +	} +} + +/** + * @param {string} name The package name + * @param {string} entry The target entry, eg "." + * @param {number} [condition] Unmatched condition? + */ +function bail(name, entry, condition) { +	throw new Error( +		condition +		? `No known conditions for "${entry}" entry in "${name}" package` +		: `Missing "${entry}" export in "${name}" package` +	); +} + +/** + * @param {string} name the package name + * @param {string} entry the target path/import + */ +function toName(name, entry) { +	return entry === name ? '.' +		: entry[0] === '.' ? entry +		: entry.replace(new RegExp('^' + name + '\/'), './'); +} + +/** + * @param {object} pkg package.json contents + * @param {string} [entry] entry name or import path + * @param {object} [options] + * @param {boolean} [options.browser] + * @param {boolean} [options.require] + * @param {string[]} [options.conditions] + * @param {boolean} [options.unsafe] + */ +export function resolve(pkg, entry='.', options={}) { +	let { name, exports } = pkg; + +	if (exports) { +		let { browser, require, unsafe, conditions=[] } = options; + +		let target = toName(name, entry); +		if (target[0] !== '.') target = './' + target; + +		if (typeof exports === 'string') { +			return target === '.' ? exports : bail(name, target); +		} + +		let allows = new Set(['default', ...conditions]); +		unsafe || allows.add(require ? 'require' : 'import'); +		unsafe || allows.add(browser ? 'browser' : 'node'); + +		let key, tmp, isSingle=false; + +		for (key in exports) { +			isSingle = key[0] !== '.'; +			break; +		} + +		if (isSingle) { +			return target === '.' +				? loop(exports, allows) || bail(name, target, 1) +				: bail(name, target); +		} + +		if (tmp = exports[target]) { +			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('*', target.substring(key.length - 1)) +						: bail(name, target, 1); +				} +			} +		} + +		return bail(name, target); +	} +} + +/** + * @param {object} pkg + * @param {object} [options] + * @param {string|boolean} [options.browser] + * @param {string[]} [options.fields] + */ +export function legacy(pkg, options={}) { +	let i=0, value, +		browser = options.browser, +		fields = options.fields || ['module', 'main']; + +	if (browser && !fields.includes('browser')) { +		fields.unshift('browser'); +	} + +	for (; i < fields.length; i++) { +		if (value = pkg[fields[i]]) { +			if (typeof value == 'string') { +				// +			} else if (typeof value == 'object' && fields[i] == 'browser') { +				if (typeof browser == 'string') { +					value = value[browser=toName(pkg.name, browser)]; +					if (value == null) return browser; +				} +			} else { +				continue; +			} + +			return typeof value == 'string' +				? ('./' + value.replace(/^\.?\//, '')) +				: value; +		} +	} +} diff --git a/node_modules/resolve.exports/index.d.ts b/node_modules/resolve.exports/index.d.ts new file mode 100644 index 0000000..94217c7 --- /dev/null +++ b/node_modules/resolve.exports/index.d.ts @@ -0,0 +1,21 @@ +export type Options = { +	browser?: boolean; +	conditions?: string[]; +	require?: boolean; +	unsafe?: false; +} | { +	conditions?: string[]; +	unsafe?: true; +} + +export function resolve<T=any>(pkg: T, entry: string, options?: Options): string | void; + +export type BrowserFiles = Record<string, string | false>; + +export function legacy<T=any>(pkg: T, options: { browser: true, fields?: string[] }): BrowserFiles | string | void; +export function legacy<T=any>(pkg: T, options: { browser: string, fields?: string[] }): string | false | void; +export function legacy<T=any>(pkg: T, options: { browser: false, fields?: string[] }): string | void; +export function legacy<T=any>(pkg: T, options?: { +	browser?: boolean | string; +	fields?: string[]; +}): BrowserFiles | string | false | void; diff --git a/node_modules/resolve.exports/license b/node_modules/resolve.exports/license new file mode 100644 index 0000000..a3f96f8 --- /dev/null +++ b/node_modules/resolve.exports/license @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) Luke Edwards <luke.edwards05@gmail.com> (lukeed.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/node_modules/resolve.exports/package.json b/node_modules/resolve.exports/package.json new file mode 100644 index 0000000..5a5a7fb --- /dev/null +++ b/node_modules/resolve.exports/package.json @@ -0,0 +1,47 @@ +{ +  "version": "1.1.0", +  "name": "resolve.exports", +  "repository": "lukeed/resolve.exports", +  "description": "A tiny (737b), correct, general-purpose, and configurable \"exports\" resolver without file-system reliance", +  "module": "dist/index.mjs", +  "main": "dist/index.js", +  "types": "index.d.ts", +  "license": "MIT", +  "author": { +    "name": "Luke Edwards", +    "email": "luke.edwards05@gmail.com", +    "url": "https://lukeed.com" +  }, +  "engines": { +    "node": ">=10" +  }, +  "scripts": { +    "build": "bundt", +    "test": "uvu -r esm test" +  }, +  "files": [ +    "*.d.ts", +    "dist" +  ], +  "exports": { +    ".": { +      "import": "./dist/index.mjs", +      "require": "./dist/index.js" +    }, +    "./package.json": "./package.json" +  }, +  "keywords": [ +    "esm", +    "exports", +    "esmodules", +    "fields", +    "modules", +    "resolution", +    "resolve" +  ], +  "devDependencies": { +    "bundt": "1.1.2", +    "esm": "3.2.25", +    "uvu": "0.5.1" +  } +} diff --git a/node_modules/resolve.exports/readme.md b/node_modules/resolve.exports/readme.md new file mode 100644 index 0000000..f265c46 --- /dev/null +++ b/node_modules/resolve.exports/readme.md @@ -0,0 +1,320 @@ +# resolve.exports [](https://github.com/lukeed/resolve.exports/actions) [](https://codecov.io/gh/lukeed/resolve.exports) + +> A tiny (737b), correct, general-purpose, and configurable `"exports"` resolver without file-system reliance + +***Why?*** + +Hopefully, this module may serve as a reference point (and/or be used directly) so that the varying tools and bundlers within the ecosystem can share a common approach with one another **as well as** with the native Node.js implementation. + +With the push for ESM, we must be _very_ careful and avoid fragmentation. If we, as a community, begin propagating different _dialects_ of `"exports"` resolution, then we're headed for deep trouble. It will make supporting (and using) `"exports"` nearly impossible, which may force its abandonment and along with it, its benefits. + +Let's have nice things. + +***TODO*** + +- [x] exports string +- [x] exports object (single entry) +- [x] exports object (multi entry) +- [x] nested / recursive conditions +- [x] exports arrayable +- [x] directory mapping (`./foobar/` => `/foobar/`) +- [x] directory mapping (`./foobar/*` => `./other/*.js`) +- [x] directory mapping w/ conditions +- [x] directory mapping w/ nested conditions +- [x] legacy fields (`main` vs `module` vs ...) +- [x] legacy "browser" files object + +## Install + +```sh +$ npm install resolve.exports +``` + +## Usage + +> Please see [`/test/`](/test) for examples. + +```js +import { resolve, legacy } from 'resolve.exports'; + +const contents = { +  "name": "foobar", +  "module": "dist/module.mjs", +  "main": "dist/require.js", +  "exports": { +    ".": { +      "import": "./dist/module.mjs", +      "require": "./dist/require.js" +    }, +    "./lite": { +      "worker": { +        "browser": "./lite/worker.brower.js", +        "node": "./lite/worker.node.js" +      }, +      "import": "./lite/module.mjs", +      "require": "./lite/require.js" +    } +  } +}; + +// Assumes `.` as default entry +// Assumes `import` as default condition +resolve(contents); //=> "./dist/module.mjs" + +// entry: nullish === "foobar" === "." +resolve(contents, 'foobar'); //=> "./dist/module.mjs" +resolve(contents, '.'); //=> "./dist/module.mjs" + +// entry: "foobar/lite" === "./lite" +resolve(contents, 'foobar/lite'); //=> "./lite/module.mjs" +resolve(contents, './lite'); //=> "./lite/module.mjs" + +// Assume `require` usage +resolve(contents, 'foobar', { require: true }); //=> "./dist/require.js" +resolve(contents, './lite', { require: true }); //=> "./lite/require.js" + +// Throws "Missing <entry> export in <name> package" Error +resolve(contents, 'foobar/hello'); +resolve(contents, './hello/world'); + +// Add custom condition(s) +resolve(contents, 'foobar/lite', { +  conditions: ['worker'] +}); // => "./lite/worker.node.js" + +// Toggle "browser" condition +resolve(contents, 'foobar/lite', { +  conditions: ['worker'], +  browser: true +}); // => "./lite/worker.browser.js" + +// --- +// Legacy +// --- + +// prefer "module" > "main" (default) +legacy(contents); //=> "dist/module.mjs" + +// customize fields order +legacy(contents, { +  fields: ['main', 'module'] +}); //=> "dist/require.js" +``` + +## API + +### resolve(pkg, entry?, options?) +Returns: `string` or `undefined` + +Traverse the `"exports"` within the contents of a `package.json` file. <br> +If the contents _does not_ contain an `"exports"` map, then `undefined` will be returned. + +Successful resolutions will always result in a string value. This will be the value of the resolved mapping itself – which means that the output is a relative file path. + +This function may throw an Error if: + +* the requested `entry` cannot be resolved (aka, not defined in the `"exports"` map) +* an `entry` _was_ resolved but no known conditions were found (see [`options.conditions`](#optionsconditions)) + +#### pkg +Type: `object` <br> +Required: `true` + +The `package.json` contents. + +#### entry +Type: `string` <br> +Required: `false` <br> +Default: `.` (aka, root) + +The desired target entry, or the original `import` path. + +When `entry` _is not_ a relative path (aka, does not start with `'.'`), then `entry` is given the `'./'` prefix. + +When `entry` begins with the package name (determined via the `pkg.name` value), then `entry` is truncated and made relative. + +When `entry` is already relative, it is accepted as is. + +***Examples*** + +Assume we have a module named "foobar" and whose `pkg` contains `"name": "foobar"`. + +| `entry` value | treated as | reason | +|-|-|-| +| `null` / `undefined` | `'.'` | default | +| `'.'` | `'.'` | value was relative | +| `'foobar'` | `'.'` | value was `pkg.name` | +| `'foobar/lite'` | `'./lite'` | value had `pkg.name` prefix | +| `'./lite'` | `'./lite'` | value was relative | +| `'lite'` | `'./lite'` | value was not relative & did not have `pkg.name` prefix | + + +#### options.require +Type: `boolean` <br> +Default: `false` + +When truthy, the `"require"` field is added to the list of allowed/known conditions. + +When falsey, the `"import"` field is added to the list of allowed/known conditions instead. + +#### options.browser +Type: `boolean` <br> +Default: `false` + +When truthy, the `"browser"` field is added to the list of allowed/known conditions. + +#### options.conditions +Type: `string[]` <br> +Default: `[]` + +Provide a list of additional/custom conditions that should be accepted when seen. + +> **Important:** The order specified within `options.conditions` does not matter. <br>The matching order/priority is **always** determined by the `"exports"` map's key order. + +For example, you may choose to accept a `"production"` condition in certain environments. Given the following `pkg` content: + +```js +const contents = { +  // ... +  "exports": { +    "worker": "./index.worker.js", +    "require": "./index.require.js", +    "production": "./index.prod.js", +    "import": "./index.import.mjs", +  } +}; + +resolve(contents, '.'); +//=> "./index.import.mjs" + +resolve(contents, '.', { +  conditions: ['production'] +}); //=> "./index.prod.js" + +resolve(contents, '.', { +  conditions: ['production'], +  require: true, +}); //=> "./index.require.js" + +resolve(contents, '.', { +  conditions: ['production', 'worker'], +  require: true, +}); //=> "./index.worker.js" + +resolve(contents, '.', { +  conditions: ['production', 'worker'] +}); //=> "./index.worker.js" +``` + +#### options.unsafe +Type: `boolean` <br> +Default: `false` + +> **Important:** You probably do not want this option! <br>It will break out of Node's default resolution conditions. + +When enabled, this option will ignore **all other options** except [`options.conditions`](#optionsconditions). This is because, when enabled, `options.unsafe` **does not** assume or provide any default conditions except the `"default"` condition. + +```js +resolve(contents); +//=> Conditions: ["default", "import", "node"] + +resolve(contents, { unsafe: true }); +//=> Conditions: ["default"] + +resolve(contents, { unsafe: true, require: true, browser: true }); +//=> Conditions: ["default"] +``` + +In other words, this means that trying to use `options.require` or `options.browser` alongside `options.unsafe` will have no effect. In order to enable these conditions, you must provide them manually into the `options.conditions` list: + +```js +resolve(contents, { +  unsafe: true, +  conditions: ["require"] +}); +//=> Conditions: ["default", "require"] + +resolve(contents, { +  unsafe: true, +  conditions: ["browser", "require", "custom123"] +}); +//=> Conditions: ["default", "browser", "require", "custom123"] +``` + + +### legacy(pkg, options?) +Returns: `string` or `undefined` + +Also included is a "legacy" method for resolving non-`"exports"` package fields. This may be used as a fallback method when for when no `"exports"` mapping is defined. In other words, it's completely optional (and tree-shakeable). + +You may customize the field priority via [`options.fields`](#optionsfields). + +When a field is found, its value is returned _as written_. <br> +When no fields were found, `undefined` is returned. If you wish to mimic Node.js behavior, you can assume this means `'index.js'` – but this module does not make that assumption for you. + +#### options.browser +Type: `boolean` or `string` <br> +Default: `false` + +When truthy, ensures that the `'browser'` field is part of the acceptable `fields` list. + +> **Important:** If your custom [`options.fields`](#optionsfields) value includes `'browser'`, then _your_ order is respected. <br>Otherwise, when truthy, `options.browser` will move `'browser'` to the front of the list, making it the top priority. + +When `true` and `"browser"` is an object, then `legacy()` will return the the entire `"browser"` object. + +You may also pass a string value, which will be treated as an import/file path. When this is the case and `"browser"` is an object, then `legacy()` may return: + +* `false` – if the package author decided a file should be ignored; or +* your `options.browser` string value – but made relative, if not already + +> See the [`"browser" field specification](https://github.com/defunctzombie/package-browser-field-spec) for more information. + +#### options.fields +Type: `string[]` <br> +Default: `['module', 'main']` + +A list of fields to accept. The order of the array determines the priority/importance of each field, with the most important fields at the beginning of the list. + +By default, the `legacy()` method will accept any `"module"` and/or "main" fields if they are defined. However, if both fields are defined, then "module" will be returned. + +```js +const contents = { +  "name": "...", +  "worker": "worker.js", +  "module": "module.mjs", +  "browser": "browser.js", +  "main": "main.js", +} + +legacy(contents); +// fields = [module, main] +//=> "module.mjs" + +legacy(contents, { browser: true }); +// fields = [browser, module, main] +//=> "browser.mjs" + +legacy(contents, { +  fields: ['missing', 'worker', 'module', 'main'] +}); +// fields = [missing, worker, module, main] +//=> "worker.js" + +legacy(contents, { +  fields: ['missing', 'worker', 'module', 'main'], +  browser: true, +}); +// fields = [browser, missing, worker, module, main] +//=> "browser.js" + +legacy(contents, { +  fields: ['module', 'browser', 'main'], +  browser: true, +}); +// fields = [module, browser, main] +//=> "module.mjs" +``` + +## License + +MIT © [Luke Edwards](https://lukeed.com)  | 
