AK-21/Graphite-Industrial-Intelligence
0
1# resolve-pkg-maps2 3Utils to resolve `package.json` subpath & conditional [`exports`](https://nodejs.org/api/packages.html#exports)/[`imports`](https://nodejs.org/api/packages.html#imports) in resolvers.4 5Implements the [ESM resolution algorithm](https://nodejs.org/api/esm.html#resolver-algorithm-specification). Tested [against Node.js](/tests/) for accuracy.6 7<sub>Support this project by ⭐️ starring and sharing it. [Follow me](https://github.com/privatenumber) to see what other cool projects I'm working on! ❤️</sub>8 9## Usage10 11### Resolving `exports`12 13_utils/package.json_14```json515{16 // ...17 "exports": {18 "./reverse": {19 "require": "./file.cjs",20 "default": "./file.mjs"21 }22 },23 // ...24}25```26 27```ts28import { resolveExports } from 'resolve-pkg-maps'29 30const [packageName, packageSubpath] = parseRequest('utils/reverse')31 32const resolvedPaths: string[] = resolveExports(33 getPackageJson(packageName).exports,34 packageSubpath,35 ['import', ...otherConditions]36)37// => ['./file.mjs']38```39 40### Resolving `imports`41 42_package.json_43```json544{45 // ...46 "imports": {47 "#supports-color": {48 "node": "./index.js",49 "default": "./browser.js"50 }51 },52 // ...53}54```55 56```ts57import { resolveImports } from 'resolve-pkg-maps'58 59const resolvedPaths: string[] = resolveImports(60 getPackageJson('.').imports,61 '#supports-color',62 ['node', ...otherConditions]63)64// => ['./index.js']65```66 67## API68 69### resolveExports(exports, request, conditions)70 71Returns: `string[]`72 73Resolves the `request` based on `exports` and `conditions`. Returns an array of paths (e.g. in case a fallback array is matched).74 75#### exports76 77Type:78```ts79type Exports = PathOrMap | readonly PathOrMap[]80 81type PathOrMap = string | PathConditionsMap82 83type PathConditionsMap = {84 [condition: string]: PathConditions | null85}86```87 88The [`exports` property](https://nodejs.org/api/packages.html#exports) value in `package.json`.89 90#### request91 92Type: `string`93 94The package subpath to resolve. Assumes a normalized path is passed in (eg. [repeating slashes `//`](https://github.com/nodejs/node/issues/44316)).95 96It _should not_ start with `/` or `./`.97 98Example: if the full import path is `some-package/subpath/file`, the request is `subpath/file`.99 100 101#### conditions102 103Type: `readonly string[]`104 105An array of conditions to use when resolving the request. For reference, Node.js's default conditions are [`['node', 'import']`](https://nodejs.org/api/esm.html#:~:text=defaultConditions%20is%20the%20conditional%20environment%20name%20array%2C%20%5B%22node%22%2C%20%22import%22%5D.).106 107The order of this array does not matter; the order of condition keys in the export map is what matters instead.108 109Not all conditions in the array need to be met to resolve the request. It just needs enough to resolve to a path.110 111---112 113### resolveImports(imports, request, conditions)114 115Returns: `string[]`116 117Resolves the `request` based on `imports` and `conditions`. Returns an array of paths (e.g. in case a fallback array is matched).118 119#### imports120 121Type:122```ts123type Imports = {124 [condition: string]: PathOrMap | readonly PathOrMap[] | null125}126 127type PathOrMap = string | Imports128```129 130The [`imports` property](https://nodejs.org/api/packages.html#imports) value in `package.json`.131 132 133#### request134 135Type: `string`136 137The request resolve. Assumes a normalized path is passed in (eg. [repeating slashes `//`](https://github.com/nodejs/node/issues/44316)).138 139> **Note:** In Node.js, imports resolutions are limited to requests prefixed with `#`. However, this package does not enforce that requirement in case you want to add custom support for non-prefixed entries.140 141#### conditions142 143Type: `readonly string[]`144 145An array of conditions to use when resolving the request. For reference, Node.js's default conditions are [`['node', 'import']`](https://nodejs.org/api/esm.html#:~:text=defaultConditions%20is%20the%20conditional%20environment%20name%20array%2C%20%5B%22node%22%2C%20%22import%22%5D.).146 147The order of this array does not matter; the order of condition keys in the import map is what matters instead.148 149Not all conditions in the array need to be met to resolve the request. It just needs enough to resolve to a path.150 151---152 153### Errors154 155#### `ERR_PACKAGE_PATH_NOT_EXPORTED`156 - If the request is not exported by the export map157 158#### `ERR_PACKAGE_IMPORT_NOT_DEFINED`159 - If the request is not defined by the import map160 161#### `ERR_INVALID_PACKAGE_CONFIG`162 163 - If an object contains properties that are both paths and conditions (e.g. start with and without `.`)164 - If an object contains numeric properties 165 166#### `ERR_INVALID_PACKAGE_TARGET`167 - If a resolved exports path is not a valid path (e.g. not relative or has protocol)168 - If a resolved path includes `..` or `node_modules`169 - If a resolved path is a type that cannot be parsed170 171## FAQ172 173### Why do the APIs return an array of paths?174 175`exports`/`imports` supports passing in a [fallback array](https://github.com/jkrems/proposal-pkg-exports/#:~:text=Whenever%20there%20is,to%20new%20cases.) to provide fallback paths if the previous one is invalid:176 177```json5178{179 "exports": {180 "./feature": [181 "./file.js",182 "./fallback.js"183 ]184 }185}186```187 188Node.js's implementation [picks the first valid path (without attempting to resolve it)](https://github.com/nodejs/node/issues/44282#issuecomment-1220151715) and throws an error if it can't be resolved. Node.js's fallback array is designed for [forward compatibility with features](https://github.com/jkrems/proposal-pkg-exports/#:~:text=providing%20forwards%20compatiblitiy%20for%20new%20features) (e.g. protocols) that can be immediately/inexpensively validated:189 190```json5191{192 "exports": {193 "./core-polyfill": ["std:core-module", "./core-polyfill.js"]194 }195}196```197 198However, [Webpack](https://webpack.js.org/guides/package-exports/#alternatives) and [TypeScript](https://github.com/microsoft/TypeScript/blob/71e852922888337ef51a0e48416034a94a6c34d9/src/compiler/moduleSpecifiers.ts#L695) have deviated from this behavior and attempts to resolve the next path if a path cannot be resolved.199 200By returning an array of matched paths instead of just the first one, the user can decide which behavior to adopt.201 202### How is it different from [`resolve.exports`](https://github.com/lukeed/resolve.exports)?203 204`resolve.exports` only resolves `exports`, whereas this package resolves both `exports` & `imports`. This comparison will only cover resolving `exports`.205 206- Despite it's name, `resolve.exports` handles more than just `exports`. It takes in the entire `package.json` object to handle resolving `.` and [self-references](https://nodejs.org/api/packages.html#self-referencing-a-package-using-its-name). This package only accepts `exports`/`imports` maps from `package.json` and is scoped to only resolving what's defined in the maps.207 208- `resolve.exports` accepts the full request (e.g. `foo/bar`), whereas this package only accepts the requested subpath (e.g. `bar`).209 210- `resolve.exports` only returns the first result in a fallback array. This package returns an array of results for the user to decide how to handle it.211 212- `resolve.exports` supports [subpath folder mapping](https://nodejs.org/docs/latest-v16.x/api/packages.html#subpath-folder-mappings) (deprecated in Node.js v16 & removed in v17) but seems to [have a bug](https://github.com/lukeed/resolve.exports/issues/7). This package does not support subpath folder mapping because Node.js has removed it in favor of using subpath patterns.213 214- Neither resolvers rely on a file-system215 216This package also addresses many of the bugs in `resolve.exports`, demonstrated in [this test](/tests/exports/compare-resolve.exports.ts).217 