https://github.com/flex-development/mlly
ECMAScript module utilities
https://github.com/flex-development/mlly
ecmascript esm esmodules module typescript
Last synced: 12 days ago
JSON representation
ECMAScript module utilities
- Host: GitHub
- URL: https://github.com/flex-development/mlly
- Owner: flex-development
- License: bsd-3-clause
- Created: 2022-10-03T04:28:47.000Z (over 3 years ago)
- Default Branch: main
- Last Pushed: 2024-05-27T22:42:46.000Z (over 1 year ago)
- Last Synced: 2024-05-28T08:15:50.860Z (over 1 year ago)
- Topics: ecmascript, esm, esmodules, module, typescript
- Language: TypeScript
- Homepage: https://github.com/flex-development/mlly
- Size: 6.51 MB
- Stars: 3
- Watchers: 2
- Forks: 0
- Open Issues: 12
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- Contributing: CONTRIBUTING.md
- Funding: .github/funding.yml
- License: LICENSE.md
- Code of conduct: CODE_OF_CONDUCT.md
Awesome Lists containing this project
README
# \:gear: mlly
[](https://github.com/flex-development/mlly/releases/latest)
[](https://npmjs.com/package/@flex-development/mlly)
[](https://www.npmcharts.com/compare/@flex-development/mlly?interval=30)
[](https://packagephobia.now.sh/result?p=@flex-development/mlly)
[](https://codecov.io/gh/flex-development/mlly)
[](https://github.com/voxpelli/badges-cjs-esm)
[](LICENSE.md)
[](https://conventionalcommits.org)
[](https://typescriptlang.org)
[](https://vitest.dev)
[](https://yarnpkg.com)
[ECMAScript module][node-esm] utilities.
## Contents
- [What is this?](#what-is-this)
- [Install](#install)
- [Use](#use)
- [API](#api)
- [`canParseUrl(input[, base])`](#canparseurlinput-base)
- [`cwd()`](#cwd)
- [`defaultConditions`](#defaultconditions)
- [`defaultExtensions`](#defaultextensions)
- [`defaultMainFields`](#defaultmainfields)
- [`extensionFormatMap`](#extensionformatmap)
- [`formats`](#formats)
- [`getSource(id[, options])`](#getsourcetid-options)
- [`isAbsoluteSpecifier(value)`](#isabsolutespecifiervalue)
- [`isArrayIndex(value)`](#isarrayindexvalue)
- [`isBareSpecifier(value)`](#isbarespecifiervalue)
- [`isDirectory(id[, fs])`](#isdirectorytid-fs)
- [`isFile(id[, fs])`](#isfiletid-fs)
- [`isImportsSubpath(value)`](#isimportssubpathvalue)
- [`isModuleId(value)`](#ismoduleidvalue)
- [`isRelativeSpecifier(value)`](#isrelativespecifiervalue)
- [`legacyMainResolve(packageUrl[, manifest][, mainFields][, parent][, fs])`](#legacymainresolvetpackageurl-manifest-mainfields-parent-fs)
- [`lookupPackageScope(url[, end][, fs])`](#lookuppackagescopeturl-end-fs)
- [`moduleResolve(specifier, parent[, conditions][, mainFields][, preserveSymlinks][, fs])`](#moduleresolvetspecifier-parent-conditions-mainfields-preservesymlinks-fs)
- [`packageExportsResolve(packageUrl, subpath, exports[, conditions][, parent][, fs])`](#packageexportsresolvetpackageurl-subpath-exports-conditions-parent-fs)
- [`packageImportsExportsResolve(matchKey, matchObject, packageUrl[, isImports][, conditions][, mainFields][, parent][, fs])`](#packageimportsexportsresolvetmatchkey-matchobject-packageurl-isimports-conditions-mainfields-parent-fs)
- [`packageImportsResolve(specifier, parent[, conditions][, mainFields][, fs])`](#packageimportsresolvetspecifier-parent-conditions-mainfields-fs)
- [`packageResolve(specifier, parent[, conditions][, mainFields][, fs])`](#packageresolvetspecifier-parent-conditions-mainfields-fs)
- [`packageSelfResolve(name, subpath, parent[, conditions][, fs])`](#packageselfresolvetname-subpath-parent-conditions-fs)
- [`packageTargetResolve(packageUrl, target, subpath[, patternMatch][, isImports][, conditions][, mainFields][, parent][, fs])`](#packagetargetresolvetpackageurl-target-subpath-patternmatch-isimports-conditions-mainfields-parent-fs)
- [`patternKeyCompare(a, b)`](#patternkeycomparea-b)
- [`patternMatch(matchKey, matchObject)`](#patternmatchmatchkey-matchobject)
- [`readPackageJson(id[, specifier][, parent][, fs])`](#readpackagejsontid-specifier-parent-fs)
- [`resolveAlias(specifier[, options])`](#resolvealiasspecifier-options)
- [`resolveModule(specifier, parent[, options])`](#resolvemoduletspecifier-parent-options)
- [`resolver`](#resolver)
- [`root`](#root)
- [`toRelativeSpecifier(url, parent)`](#torelativespecifierurl-parent)
- [`toUrl(id[, parent])`](#tourlid-parent)
- [Types](#types)
- [`Aliases`](#aliases)
- [`Awaitable`](#awaitablet)
- [`ChangeExtFn<[Ext]>`](#changeextfnext)
- [`ConditionMap`](#conditionmap)
- [`Condition`](#condition)
- [`Dot`](#dot)
- [`EmptyArray`](#emptyarray)
- [`EmptyObject`](#emptyobject)
- [`EmptyString`](#emptystring)
- [`Ext`](#ext)
- [`FileSystem`](#filesystem)
- [`GetSourceContext`](#getsourcecontext)
- [`GetSourceHandler`](#getsourcehandler)
- [`GetSourceHandlers`](#getsourcehandlers)
- [`GetSourceOptions`](#getsourceoptions)
- [`IsDirectory`](#isdirectory)
- [`IsFile`](#isfile)
- [`List<[T]>`](#listt)
- [`MainFieldMap`](#mainfieldmap)
- [`MainField`](#mainfield)
- [`ModuleFormatMap`](#moduleformatmap)
- [`ModuleFormat`](#moduleformat)
- [`ModuleId`](#moduleid)
- [`Numeric`](#numeric)
- [`PatternKeyComparisonMap`](#patternkeycomparsionmap)
- [`PatternKeyComparison`](#patternkeycomparsion)
- [`PatternMatch`](#patternmatch)
- [`ProtocolMap`](#protocolmap)
- [`Protocol`](#protocol)
- [`ReadFile<[T]>`](#readfilet)
- [`Realpath<[T]>`](#realpatht)
- [`ResolveAliasOptions`](#resolvealiasoptions)
- [`ResolveModuleOptions`](#resolvemoduleoptions)
- [`Stat<[T]>`](#statt)
- [`Stats`](#stats)
- Additional Documentation
- [Resolution Algorithm](./docs/resolution-algorithm.md)
- [Contribute](#contribute)
## What is this?
`mlly` is a set of [ECMAScript module][node-esm] (ESM) utilities.\
It exposes several tools to bridge the gap between developer experience and the current state of ECMAScript modules.
## Install
This package is [ESM only][esm].
In Node.js (version 20+) with [yarn][]:
```sh
yarn add @flex-development/mlly
```
See Git - Protocols | Yarn
Β for details regarding installing from Git.
In Deno with [`esm.sh`][esmsh]:
```ts
import { resolveModule } from 'https://esm.sh/@flex-development/mlly'
```
In browsers with [`esm.sh`][esmsh]:
```html
import { resolveModule } from 'https://esm.sh/@flex-development/mlly'
```
## Use
```ts
import {
lookupPackageScope,
readPackageJson,
resolveModule,
type FileSystem
} from '@flex-development/mlly'
import pkg from '@flex-development/mlly/package.json' with { type: 'json' }
import type { PackageJson } from '@flex-development/pkg-types'
import nfs from 'node:fs'
/**
* A file system API with both asynchronous and synchronous methods.
*
* @const {FileSystem} fs
*/
const fs: FileSystem = {
readFile: nfs.promises.readFile,
realpath: nfs.promises.realpath,
stat: nfs.statSync
}
/**
* The URL of the package directory.
*
* @const {URL | null} scope
*/
const scope: URL | null = lookupPackageScope(import.meta.url, null, fs)
console.dir(scope) // file:///Users/lex/Projects/flex-development/mlly/
/**
* The package manifest.
*
* @const {PackageJson | null} manifest
*/
const manifest: PackageJson | null = await readPackageJson(
scope,
null,
import.meta.url,
fs
)
console.dir(manifest?.name === pkg.name) // true
console.dir(manifest) // `pkg`
/**
* A fully resolved URL.
*
* @const {URL} resolved
*/
const resolved = resolveModule(pkg.name, import.meta.url, {
conditions: new Set(['mlly']),
ext: null
})
console.dir(resolved) // file:///Users/lex/Projects/flex-development/mlly/src/
```
## API
`mlly` exports the identifiers listed below.
There is no default export.
### `canParseUrl(input[, base])`
Check if `input` can be parsed to a `URL`.
> π **Note**: If `input` is relative, `base` is required.
> If `input` is absolute, `base` is ignored.
#### Parameters
- `id` (`unknown`)
β the input url
- `base` (`unknown`)
β the base url to resolve against if `input` is not absolute
#### Returns
(`boolean`) `true` if `input` can be parsed to a `URL`, `false` otherwise
### `cwd()`
Get the URL of the current working directory.
#### Returns
(`URL`) The current working directory URL
### `defaultConditions`
[`Set`](#condition)
The default list of conditions.
### `defaultExtensions`
[`Set`](#ext)
The default list of resolvable file extensions.
### `defaultMainFields`
[`Set`](#mainfield)
The default list of main fields.
### `extensionFormatMap`
`Map`
Map, where each key is a [file extension](#ext) and each value is a default [module format](#formats).
### `formats`
Default module formats (`const enum`).
```ts
const enum formats {
builtin = 'builtin',
commonjs = 'commonjs',
cts = 'commonjs-typescript',
json = 'json',
module = 'module',
mts = 'module-typescript',
wasm = 'wasm'
}
```
### `getSource(id[, options])`
Get the source code for a module.
> π **Note**: Returns a promise if the [handler](#getsourcehandler) for `id` is async.
#### Type Parameters
- `T` ([`Awaitable`](#awaitablet))
β the module source code
#### Parameters
- `id` ([`ModuleId`](#moduleid) | `null` | `undefined`)
β the module id
- `options` ([`GetSourceOptions`](#getsourceoptions) | `null` | `undefined`)
β source code retrieval options
#### Returns
(`T`) The module source code
#### Throws
- [`ERR_UNSUPPORTED_ESM_URL_SCHEME`][err-unsupported-esm-url-scheme]
### `isAbsoluteSpecifier(value)`
Check if `value` is an *absolute specifier*.
> π **Note**: Only checks specifier syntax.\
> Does **not** guarantee the specifier references an existing module.
#### Parameters
- `value` (`unknown`)
β the value to check
#### Returns
(`boolean`) `true` if `value` is absolute specifier, `false` otherwise
### `isArrayIndex(value)`
Check if `value` is a valid array index.
#### Parameters
- `value` (`unknown`)
β the value to check
#### Returns
([`value is Numeric`](#numeric)) `true` if `value` is valid array index, `false` otherwise
### `isBareSpecifier(value)`
Check if `value` is a *bare specifier*.
> π **Note**: Only checks specifier syntax.\
> Does **not** guarantee the specifier references an existing module.
#### Parameters
- `value` (`unknown`)
β the value to check
#### Returns
(`boolean`) `true` if `value` is bare specifier, `false` otherwise
### `isDirectory(id[, fs])`
Check if a directory exists.
> π **Note**: Returns a promise if `fs.stat` is async.
#### Type Parameters
- `T` ([`Awaitable`](#awaitablet))
β the result of the check
#### Parameters
- `id` ([`ModuleId`](#moduleid))
β the module id to check
- `fs` ([`FileSystem`](#filesystem) | `null` | `undefined`)
β the file system api
#### Returns
(`T`) `true` if directory exists at `id`, `false` otherwise
### `isFile(id[, fs])`
Check if a file exists.
> π **Note**: Returns a promise if `fs.stat` is async.
#### Type Parameters
- `T` ([`Awaitable`](#awaitablet))
β the result of the check
#### Parameters
- `id` ([`ModuleId`](#moduleid))
β the module id to check
- `fs` ([`FileSystem`](#filesystem) | `null` | `undefined`)
β the file system api
#### Returns
(`T`) `true` if file exists at `id`, `false` otherwise
### `isImportsSubpath(value)`
Check if `value` is an [`imports`][subpath-imports] subpath.
> π **Note**: Only checks specifier syntax.\
> Does **not** guarantee the specifier references an existing module.
#### Parameters
- `value` (`unknown`)
β the value to check
#### Returns
([`value is ImportsSubpath`][pkg-imports-subpath]) `true` if `value` is `imports` subpath, `false` otherwise
### `isModuleId(value)`
Check if `value` is a module id.
#### Parameters
- `value` (`unknown`)
β the value to check
#### Returns
([`value is ModuleId`](#moduleid)) `true` if `value` is module id, `false` otherwise
### `isRelativeSpecifier(value)`
Check if `value` is a *relative specifier*.
> π **Note**: Only checks specifier syntax.\
> Does **not** guarantee the specifier references an existing module.
#### Parameters
- `value` (`unknown`)
β the value to check
#### Returns
(`boolean`) `true` if `value` is relative specifier, `false` otherwise
### `legacyMainResolve(packageUrl[, manifest][, mainFields][, parent][, fs])`
Resolve a [`main`][main]-like package entry point.
Implements the [`LEGACY_MAIN_RESOLVE`][algorithm-legacy-main-resolve] resolution algorithm.
> π **Note**: Returns a promise if `fs.stat` is async.
#### Type Parameters
- `T` ([`Awaitable`](#awaitablet))
β the resolved entry point url
#### Parameters
- `packageUrl` ([`ModuleId`](#moduleid))
β the url of the package directory, the `package.json` file, or a module in the same directory as a `package.json`
- `manifest` ([`PackageJson`][pkg-package-json] | `null` | `undefined`)
β the package manifest
- `mainFields` ([`List`](#mainfield) | `null` | `undefined`)
β the list of legacy main fields
- **default**: [`defaultMainFields`](#defaultmainfields)
- `parent` ([`ModuleId`](#moduleid) | `null` | `undefined`)
β the url of the parent module
- `fs` ([`FileSystem`](#filesystem) | `null` | `undefined`)
β the file system api
#### Returns
(`T`) The resolved entry point URL
#### Throws
- [`ERR_MODULE_NOT_FOUND`][err-module-not-found]
### `lookupPackageScope(url[, end][, fs])`
Get the package scope URL for a module `url`.
Implements the [`LOOKUP_PACKAGE_SCOPE`][algorithm-lookup-package-scope] algorithm.
> π **Note**: Returns a promise if `fs.stat` is async.
#### Overloads
```ts
function lookupPackageScope(
this: void,
url: EmptyString | null | undefined,
end?: ModuleId | null | undefined,
fs?: FileSystem | null | undefined
): null
```
```ts
function lookupPackageScope>(
this: void,
url: ModuleId | null | undefined,
end?: ModuleId | null | undefined,
fs?: FileSystem | null | undefined
): T
```
#### Type Parameters
- `T` ([`Awaitable`](#awaitablet))
β the resolved package scope url
#### Parameters
- `id` ([`ModuleId`](#moduleid) | `null` | `undefined`)
β the url of the module to scope
- `end` ([`ModuleId`](#moduleid) | `null` | `undefined`)
β the url of the directory to end search at
- **default**: [`root`](#root)
- `fs` ([`FileSystem`](#filesystem) | `null` | `undefined`)
β the file system api
#### Returns
(`T`) The URL of nearest directory containing a `package.json` file
### `moduleResolve(specifier, parent[, conditions][, mainFields][, preserveSymlinks][, fs])`
Resolve a module `specifier`.
Implements the [`ESM_RESOLVE`][algorithm-esm-resolve] algorithm.
> π **Note**: Returns a promise if `fs.realpath` or `fs.stat` is async, or one the following methods returns a promise:
> [`packageImportsResolve`](#packageimportsresolvetspecifier-parent-conditions-mainfields-fs),
> [`packageResolve`](#packageresolvetspecifier-parent-conditions-mainfields-fs).
#### Type Parameters
- `T` ([`Awaitable`](#awaitablet))
β the resolved url
#### Parameters
- `specifier` (`string`)
β the module specifier to resolve
- `parent` ([`ModuleId`](#moduleid))
β the url of the parent module
- `conditions` ([`List`](#condition) | `null` | `undefined`)
β the list of export/import conditions
- **default**: [`defaultConditions`](#defaultconditions)
- `mainFields` ([`List`](#mainfield) | `null` | `undefined`)
β the list of legacy main fields
- **default**: [`defaultMainFields`](#defaultmainfields)
- `preserveSymlinks` (`boolean` | `null` | `undefined`)
β whether to keep symlinks instead of resolving them
- `fs` ([`FileSystem`](#filesystem) | `null` | `undefined`)
β the file system api
#### Returns
(`T`) The resolved URL
### `packageExportsResolve(packageUrl, subpath, exports[, conditions][, parent][, fs])`
Resolve a package export.
Implements the [`PACKAGE_EXPORTS_RESOLVE`][algorithm-package-exports-resolve] algorithm.
> π **Note**: Never returns a promisee.
#### Type Parameters
- `T` ([`Awaitable`](#awaitablet))
β the resolved package export url
#### Parameters
- `packageUrl` ([`ModuleId`](#moduleid))
β the url of the package directory, the `package.json` file, or a module in the same directory as a `package.json`
- `subpath` (`string`)
β the package subpath
- `exports` ([`Exports`][pkg-exports] | `undefined`)
β the package exports
- `conditions` ([`List`](#condition) | `null` | `undefined`)
β the list of export/import conditions
- **default**: [`defaultConditions`](#defaultconditions)
- `parent` ([`ModuleId`](#moduleid) | `null` | `undefined`)
β the url of the parent module
- `fs` ([`FileSystem`](#filesystem) | `null` | `undefined`)
β the file system api
#### Returns
(`T`) The resolved package export URL
### `packageImportsExportsResolve(matchKey, matchObject, packageUrl[, isImports][, conditions][, mainFields][, parent][, fs])`
Resolve a package export or import.
Implements the [`PACKAGE_IMPORTS_EXPORTS_RESOLVE`][algorithm-package-imports-exports-resolve] algorithm.
> π **Note**: Returns a promise if
> [`packageTargetResolve`](#packagetargetresolvetpackageurl-target-subpath-patternmatch-isimports-conditions-mainfields-parent-fs),
> returns a promise.
#### Type Parameters
- `T` ([`Awaitable`](#awaitablet))
β the resolved package export or import url
#### Parameters
- `matchKey` (`string`)
β the package subpath extracted from a module specifier, or a dot character (`.`)
- `matchObject` ([`ExportsObject`][pkg-exports-object] | [`Imports`][pkg-imports] | `null` | `undefined`)
β the package exports or imports
- `packageUrl` ([`ModuleId`](#moduleid))
β the url of the directory containing the `package.json` file
- `isImports` (`boolean` | `null` | `undefined`)
β whether `matchObject` is internal to the package
- `conditions` ([`List`](#condition) | `null` | `undefined`)
β the list of export/import conditions
- **default**: [`defaultConditions`](#defaultconditions)
- `mainFields` ([`List`](#mainfield) | `null` | `undefined`)
β the list of legacy main fields
- **default**: [`defaultMainFields`](#defaultmainfields)
- `parent` ([`ModuleId`](#moduleid) | `null` | `undefined`)
β the url of the parent module
- `fs` ([`FileSystem`](#filesystem) | `null` | `undefined`)
β the file system api
#### Returns
(`T`) The resolved package export or import URL
### `packageImportsResolve(specifier, parent[, conditions][, mainFields][, fs])`
Resolve a package import.
Implements the [`PACKAGE_IMPORTS_RESOLVE`][algorithm-package-imports-resolve] algorithm.
> π **Note**: Returns a promise if [`lookupPackageScope`](#lookuppackagescopeturl-end-fs),
> [`packageImportsExportsResolve`](#packageimportsexportsresolvetmatchkey-matchobject-packageurl-isimports-conditions-mainfields-parent-fs),
> or [`readPackageJson`](#readpackagejsontid-specifier-parent-fs) returns a promise.
#### Type Parameters
- `T` ([`Awaitable`](#awaitablet))
β the resolved package import url
#### Parameters
- `specifier` (`string`)
β the import specifier to resolve
- `parent` ([`ModuleId`](#moduleid))
β the url of the parent module
- `conditions` ([`List`](#condition) | `null` | `undefined`)
β the list of export conditions
- **default**: [`defaultConditions`](#defaultconditions)
- `mainFields` ([`List`](#mainfield) | `null` | `undefined`)
β the list of legacy main fields
- **default**: [`defaultMainFields`](#defaultmainfields)
- `fs` ([`FileSystem`](#filesystem) | `null` | `undefined`)
β the file system api
#### Returns
(`T`) The resolved package import URL
#### Throws
- [`ERR_INVALID_MODULE_SPECIFIER`][err-invalid-module-specifier]
- [`ERR_PACKAGE_IMPORT_NOT_DEFINED`][err-package-import-not-defined]
### `packageResolve(specifier, parent[, conditions][, mainFields][, fs])`
Resolve a *bare specifier*.
Implements the [`PACKAGE_RESOLVE`][algorithm-package-resolve] algorithm.
> *Bare specifiers* like `'some-package'` or `'some-package/shuffle'` refer to the main entry point of a package by
> package name, or a specific feature module within a package prefixed by the package name.
> Including the file extension is only necessary for packages without an [`exports`][exports] field.
> π **Note**: Returns a promise if `fs.stat` is async or one of the following methods returns a promise:
> [`legacyMainResolve`](#legacymainresolvetpackageurl-manifest-mainfields-parent-fs),
> [`packageExportsResolve`](#packageexportsresolvetpackageurl-subpath-exports-conditions-parent-fs),
> [`packageSelfResolve`](#packageselfresolvetname-subpath-parent-conditions-fs), or
> [`readPackageJson`](#readpackagejsontid-specifier-parent-fs).
#### Type Parameters
- `T` ([`Awaitable`](#awaitablet))
β the resolved package url
#### Parameters
- `specifier` (`string`)
β the package specifier
- `parent` ([`ModuleId`](#moduleid))
β the url of the parent module
- `conditions` ([`List`](#condition) | `null` | `undefined`)
β the list of export conditions
- **default**: [`defaultConditions`](#defaultconditions)
- `mainFields` ([`List`](#mainfield) | `null` | `undefined`)
β the list of legacy main fields
- **default**: [`defaultMainFields`](#defaultmainfields)
- `fs` ([`FileSystem`](#filesystem) | `null` | `undefined`)
β the file system api
#### Returns
(`T`) The resolved package URL
#### Throws
- [`ERR_INVALID_MODULE_SPECIFIER`][err-invalid-module-specifier]
- [`ERR_MODULE_NOT_FOUND`][err-module-not-found]
### `packageSelfResolve(name, subpath, parent[, conditions][, fs])`
Resolve the self-import of a package.
Implements the [`PACKAGE_SELF_RESOLVE`][algorithm-package-self-resolve] algorithm.
> π **Note**: Returns a promise if [`lookupPackageScope`](#lookuppackagescopeturl-end-fs),
> [`packageExportsResolve`](#packageexportsresolvetpackageurl-subpath-exports-conditions-parent-fs),
> or [`readPackageJson`](#readpackagejsontid-specifier-parent-fs) returns a promise.
#### Type Parameters
- `T` ([`Awaitable`](#awaitablet))
β the resolved package url
#### Parameters
- `name` (`string`)
β the package name
- `subpath` (`string`)
β the package subpath
- `parent` ([`ModuleId`](#moduleid))
β the url of the parent module
- `conditions` ([`List`](#condition) | `null` | `undefined`)
β the list of export conditions
- **default**: [`defaultConditions`](#defaultconditions)
- `fs` ([`FileSystem`](#filesystem) | `null` | `undefined`)
β the file system api
#### Returns
(`T`) The resolved package URL
### `packageTargetResolve(packageUrl, target, subpath[, patternMatch][, isImports][, conditions][, mainFields][, parent][, fs])`
Resolve a package target.
Implements the [`PACKAGE_TARGET_RESOLVE`][algorithm-package-target-resolve] algorithm.
> π **Note**: Returns a promise if `target` is internal to the package and
> [`packageResolve`](#packageresolvetspecifier-parent-conditions-mainfields-fs) returns a promise.
#### Type Parameters
- `T` ([`Awaitable`](#awaitablet))
β the resolved package target url
#### Parameters
- `packageUrl` ([`ModuleId`](#moduleid))
β the url of the directory containing the `package.json` file
- `target` (`unknown`)
β the package target (i.e. a `exports`/`imports` value)
- `subpath` (`string`)
β the package subpath (i.e. a `exports`/`imports` key)
- `patternMatch` (`string` | `null` | `undefined`)
β the `subpath` pattern match
- `isImports` (`boolean` | `null` | `undefined`)
β whether `target` is internal to the package
- `conditions` ([`List`](#condition) | `null` | `undefined`)
β the list of export/import conditions
- **default**: [`defaultConditions`](#defaultconditions)
- `mainFields` ([`List`](#mainfield) | `null` | `undefined`)
β the list of legacy main fields
- **default**: [`defaultMainFields`](#defaultmainfields)
- `parent` ([`ModuleId`](#moduleid))
β the url of the parent module
- `fs` ([`FileSystem`](#filesystem) | `null` | `undefined`)
β the file system api
#### Returns
(`T`) The resolved package target URL
#### Throws
- [`ERR_INVALID_PACKAGE_CONFIG`][err-invalid-package-config]
- [`ERR_INVALID_PACKAGE_TARGET`][err-invalid-package-target]
### `patternKeyCompare(a, b)`
Compare two pattern keys and return a value indicating their order.
Implements the [`PATTERN_KEY_COMPARE`][algorithm-pattern-key-compare] algorithm.
#### Parameters
- `a` (`string`)
β the first key
- `b` (`string`)
β the key to compare against `a`
#### Returns
([`PatternKeyComparison`](#patternkeycomparsion)) The pattern key comparsion result
### `patternMatch(matchKey, matchObject)`
Get a subpath pattern match for `matchKey`.
#### Parameters
- `matchKey` (`string`)
β the key to expand
- `matchObject` (`unknown`)
β the match keys object
#### Returns
([`PatternMatch`](#patternmatch) | `null`) List, where the first item is the key of a package exports or imports target
object, and the last is a subpath pattern match
### `readPackageJson(id[, specifier][, parent][, fs])`
Read a `package.json` file.
Implements the [`READ_PACKAGE_JSON`][algorithm-read-package-json] algorithm.
> π **Note**: Returns a promise if `fs.readFile` or `fs.stat` is async.
#### Overloads
```ts
function readPackageJson(
this: void,
id: EmptyString | null | undefined,
specifier?: string | null | undefined,
parent?: ModuleId | null | undefined,
fs?: FileSystem | null | undefined
): null
```
```ts
function readPackageJson>(
this: void,
id: ModuleId | null | undefined,
specifier?: string | null | undefined,
parent?: ModuleId | null | undefined,
fs?: FileSystem | null | undefined
): T
```
#### Type Parameters
- `T` ([`Awaitable`][pkg-package-json])
β the parsed file contents
#### Parameters
- `id` ([`ModuleId`](#moduleid) | `null` | `undefined`)
β the url of the package directory, the `package.json` file, or a module in the same directory as a `package.json`
- `specifier` (`string` | `null` | `undefined`)
β the module specifier that initiated the reading of the `package.json` file
> π **note**: should be a `file:` url if `parent` is not a url
- `parent` ([`ModuleId`](#moduleid) | `null` | `undefined`)
β the url of the parent module
- `fs` ([`FileSystem`](#filesystem) | `null` | `undefined`)
β the file system api
#### Returns
(`T`) The parsed file contents
#### Throws
- [`ERR_INVALID_PACKAGE_CONFIG`][err-invalid-package-config]
### `resolveAlias(specifier[, options])`
Resolve an aliased `specifier`.
#### Parameters
- `specifier` (`string`)
β the specifier using an alias
- `options` ([`ResolveAliasOptions`](#resolvealiasoptions) | `null` | `undefined`)
β alias resolution options
#### Returns
(`string` | `null`) The specifier of the aliased module
### `resolveModule(specifier, parent[, options])`
Resolve a module `specifier`.
Implements the [`ESM_RESOLVE`][algorithm-esm-resolve] algorithm, mostly \:wink:.
Adds support for:
- Changing file extensions
- Directory index resolution
- Extensionless file resolution
- Path alias resolution
- Scopeless `@types/*` resolution (i.e. `unist` -> `@types/unist`)
> π **Note**: Returns a promise if
> [`moduleResolve`](#moduleresolvetspecifier-parent-conditions-mainfields-preservesymlinks-fs) returns a promise.
#### Type Parameters
- `T` ([`Awaitable`](#awaitablet))
β the resolved url
#### Parameters
- `specifier` (`string`)
β the module specifier to resolve
- `parent` ([`ModuleId`](#moduleid))
β the url of the parent module
- `options` ([`ResolveModuleOptions`](#resolvemoduleoptions))
β module resolution options
#### Returns
(`T`) The resolved URL
### `resolver`
An object containing resolution algorithm implementations.
- [`legacyMainResolve`](#legacymainresolvetpackageurl-manifest-mainfields-parent-fs)
- [`moduleResolve`](#moduleresolvetspecifier-parent-conditions-mainfields-preservesymlinks-fs)
- [`packageExportsResolve`](#packageexportsresolvetpackageurl-subpath-exports-conditions-parent-fs)
- [`packageImportsExportsResolve`](#packageimportsexportsresolvetmatchkey-matchobject-packageurl-isimports-conditions-mainfields-parent-fs)
- [`packageImportsResolve`](#packageimportsresolvetspecifier-parent-conditions-mainfields-fs)
- [`packageResolve`](#packageresolvetspecifier-parent-conditions-mainfields-fs)
- [`packageSelfResolve`](#packageselfresolvetname-subpath-parent-conditions-fs)
- [`packageTargetResolve`](#packagetargetresolvetpackageurl-target-subpath-patternmatch-isimports-conditions-mainfields-parent-fs)
### `root`
`URL`
The URL of the file system root.
### `toRelativeSpecifier(url, parent)`
Turn `url` into a *relative specifier*.
> π **Note**: The relative specifier will only have a file extension if `specifier` also has an extension.
#### Parameters
- `url` ([`ModuleId`](#moduleid))
β the `file:` url to convert
- `parent` ([`ModuleId`](#moduleid))
β the parent module id
#### Returns
(`string`) The relative specifier
### `toUrl(id[, parent])`
Convert `id` to a `URL`.
> π **Note**: If `id` cannot be parsed as a `URL` and is also not a [builtin module][builtin-module],
> it will be assumed to be a path and converted to a [`file:` URL][file-url].
#### Parameters
- `id` ([`ModuleId`](#moduleid))
β the module id to convert
- `parent` ([`ModuleId`](#moduleid) | `null` | `undefined`)
β the base url to resolve against if `id` is not absolute
#### Returns
(`URL`) The new URL
## Types
This package is fully typed with [TypeScript][].
### `Aliases`
Record, where each key is a path alias or pattern
and each value is a path mapping configuration (`interface`).
```ts
interface Aliases {
[alias: string]: (string | null | undefined)[] | string | null | undefined
}
```
When developing extensions that use additional aliases, augment `Aliases` to register custom aliases:
```ts
declare module '@flex-development/mlly' {
interface Aliases {
custom?: string[] | string | null
}
}
```
### `Awaitable`
Create a union of `T` and `T` as a promise-like object (`type`).
```ts
type Awaitable = PromiseLike | T
```
#### Type Parameters
- `T` (`any`)
- the value
### `ChangeExtFn<[Ext]>`
Get a new file extension for `url` (`type`).
Returning an empty string (`''`), `null`, or `undefined` will remove the current file extension.
```ts
type ChangeExtFn<
Ext extends string | null | undefined = string | null | undefined
> = (this: void, url: URL, specifier: string) => Ext
```
#### Type Parameters
- `Ext` (`string` | `null` | `undefined`, optional)
β the new file extension
#### Parameters
- `url` (`URL`)
β the resolved module URL
- `specifier` (`string`)
β the module specifier being resolved
#### Returns
(`Ext`) The new file extension
### `ConditionMap`
Registry of export/import conditions (`interface`).
When developing extensions that use additional conditions, augment `ConditionMap` to register custom conditions:
```ts
declare module '@flex-development/mlly' {
interface ConditionMap {
custom: 'custom'
}
}
```
### `Condition`
Union of values that can occur where a export/import condition is expected (`type`).
To register new conditions, augment [`ConditionMap`](#conditionmap).
They will be added to this union automatically.
```ts
type Condition = ConditionMap[keyof ConditionMap]
```
### `Dot`
A dot character (`'.'`) (`type`).
```ts
type Dot = '.'
```
### `EmptyArray`
An empty array (`type`).
```ts
type EmptyArray = []
```
### `EmptyObject`
An empty object (`type`).
```ts
type EmptyObject = { [tag]?: never }
```
### `EmptyString`
An empty string (`type`).
```ts
type EmptyString = ''
```
### `Ext`
A file extension (`type`).
```ts
type Ext = `${Dot}${string}`
```
### `FileSystem`
The file system API (`interface`).
#### Properties
- `readFile` ([`ReadFile`](#readfilet))
β read the entire contents of a file
- `realpath` ([`Realpath`](#realpatht))
β compute a canonical pathname by resolving `.`, `..`, and symbolic links
- `stat` ([`Stat`](#statt))
β get information about a directory or file
### `GetSourceContext`
Source code retrieval context (`interface`).
#### Extends
- [`GetSourceOptions`](#getsourceoptions)
#### Properties
- `fs` ([`FileSystem`](#filesystem))
β the file system api
- `handlers` ([`GetSourceHandlers`](#getsourcehandlers))
β record, where each key is a url protocol and each value is a source code handler
- `req` (`RequestInit`)
β request options for network based modules
- `schemes` (`Set`)
β the list of supported url schemes
### `GetSourceHandler`
Get the source code for a module (`type`).
```ts
type GetSourceHandler = (
this: GetSourceContext,
url: URL
) => Awaitable
```
#### Parameters
- **`this`** ([`GetSourceContext`](#getsourcecontext))
β the retrieval context
- `url` (`URL`)
β the module URL
#### Returns
([`Awaitable`](#awaitablet)) The source code
### `GetSourceHandlers`
Record, where key is a URL protocol and each value is a source code handler (`type`).
```ts
type GetSourceHandlers = {
[H in Protocol]?: GetSourceHandler | null | undefined
}
```
### `GetSourceOptions`
Options for retrieving source code (`interface`).
#### Properties
- `format?` ([`ModuleFormat`](#moduleformat) | `null` | `undefined`)
β the module format hint
- `fs?` ([`FileSystem`](#filesystem) | `null` | `undefined`)
β the file system api
- `handlers?` ([`GetSourceHandlers`](#getsourcehandlers) | `null` | `undefined`)
β record, where each key is a url protocol and each value is a source code handler
- `ignoreErrors?` (`boolean` | `null` | `undefined`)
β whether to ignore [`ERR_UNSUPPORTED_ESM_URL_SCHEME`][err-unsupported-esm-url-scheme] if thrown
- `req?` (`RequestInit` | `null` | `undefined`)
β request options for network based modules
- `schemes?` ([`List`](#listt) | `null` | `undefined`)
β the list of supported url schemes
- **default**: `['data', 'file', 'http', 'https', 'node']`
### `IsDirectory`
Check if a stats object describes a directory (`interface`).
#### Returns
(`boolean`) `true` if stats describes directory, `false` otherwise
### `IsFile`
Check if a stats object describes a file (`interface`).
#### Returns
(`boolean`) `true` if stats describes regular file, `false` otherwise
### `List<[T]>`
A list (`type`).
```ts
type List = ReadonlySet | readonly T[]
```
#### Type Parameters
- `T` (`any`, optional)
β list item type
### `MainFieldMap`
Registry of main fields (`interface`).
When developing extensions that use additional fields, augment `MainFieldMap` to register custom fields:
```ts
declare module '@flex-development/mlly' {
interface MainFieldMap {
unpkg: 'unpkg'
}
}
```
### `MainField`
Union of values that can occur where a main field is expected (`type`).
To register new main fields, augment [`MainFieldMap`](#mainfieldmap).
They will be added to this union automatically.
```ts
type MainField = MainFieldMap[keyof MainFieldMap]
```
### `ModuleFormatMap`
Registry of module formats (`interface`).
When developing extensions that use additional formats, augment `ModuleFormatMap` to register custom formats:
```ts
declare module '@flex-development/mlly' {
interface ModuleFormatMap {
custom: 'custom'
}
}
```
### `ModuleFormat`
Union of values that can occur where a module format is expected (`type`).
To register new main formats, augment [`ModuleFormatMap`](#moduleformatmap).
They will be added to this union automatically.
```ts
type ModuleFormat = ModuleFormatMap[keyof ModuleFormatMap]
```
### `ModuleId`
Union of values that can occur where a ECMAScript (ES) module identifier is expected (`type`).
```ts
type ModuleId = URL | string
```
### `Numeric`
A string that can be parsed to a valid number (`type`).
```ts
type Numeric = `${number}`
```
### `PatternKeyComparsionMap`
Registry of [`PATTERN_KEY_COMPARE`][algorithm-pattern-key-compare] algorithm results (`interface`).
When developing extensions that use additional results, augment `PatternKeyComparsionMap` to register custom results:
```ts
declare module '@flex-development/mlly' {
interface PatternKeyComparsionMap {
afterThree: 3
}
}
```
### `PatternKeyComparsion`
Union of values that can occur where a [`PATTERN_KEY_COMPARE`][algorithm-pattern-key-compare] algorithm result
is expected (`type`).
To register new results, augment [`PatternKeyComparisonMap`](#patternkeycomparsionmap).
They will be added to this union automatically.
```ts
type PatternKeyComparison =
PatternKeyComparisonMap[keyof PatternKeyComparisonMap]
```
### `PatternMatch`
List, where the first item is the key of a package `exports` or `imports` target object,
and the last is a subpath pattern match (`type`).
```ts
type PatternMatch = [expansionKey: string, patternMatch: string | null]
```
### `ProtocolMap`
Registry of URL protocols (`interface`).
When developing extensions that use additional protocols, augment `ProtocolMap` to register custom protocols:
```ts
declare module '@flex-development/mlly' {
interface ProtocolMap {
custom: 'custom:'
}
}
```
### `Protocol`
Union of values that can occur where a URL protocol is expected (`type`).
To register new results, augment [`ProtocolMap`](#protocolmap).
They will be added to this union automatically.
```ts
type Protocol = ProtocolMap[keyof ProtocolMap]
```
### `ReadFile<[T]>`
Read the entire contents of a file (`interface`).
#### Type Parameters
- `T` ([`Awaitable`](#awaitablet), optional)
β the file contents
#### Parameters
- `id` ([`ModuleId`](#moduleid))
β the module id
#### Returns
(`T`) The file contents
### `Realpath<[T]>`
Compute a canonical pathname by resolving `.`, `..`, and symbolic links (`interface`).
> π **Note**: A canonical pathname is not necessarily unique.
> Hard links and bind mounts can expose an entity through many pathnames.
#### Type Parameters
- `T` ([`Awaitable`](#awaitablet), optional)
β the canonical pathname
#### Parameters
- `id` ([`ModuleId`](#moduleid))
β the module id
#### Returns
(`T`) The canonical pathname
### `ResolveAliasOptions`
Options for path alias resolution (`interface`).
#### Properties
- `absolute?` (`boolean` | `null` | `undefined`)
β whether the resolved specifier should be absolute.\
if `true`, the resolved specifier will be a [`file:` URL][file-url]
- `aliases?` ([`Aliases`](#aliases) | `null` | `undefined`)
β the path mappings dictionary
> π **note**: paths should be relative to `cwd`
- `cwd?` ([`ModuleId`](#moduleid) | `null` | `undefined`)
β the url of the directory to resolve non-absolute modules from
- **default**: [`cwd()`](#cwd)
- `parent?` ([`ModuleId`](#moduleid) | `null` | `undefined`)
β the url of the parent module
### `ResolveModuleOptions`
Options for path alias resolution (`interface`).
#### Properties
- `aliases?` ([`Aliases`](#aliases) | `null` | `undefined`)
β the path mappings dictionary
> π **note**: paths should be relative to `cwd`
- `conditions?` ([`List`](#condition) | `null` | `undefined`)
β the list of export/import conditions
- **default**: [`defaultConditions`](#defaultconditions)
> π **note**: should be sorted by priority
- `cwd?` ([`ModuleId`](#moduleid) | `null` | `undefined`)
β the url of the directory to resolve path `aliases` from
- **default**: [`cwd()`](#cwd)
- `ext?` ([`ChangeExtFn`](#changeextfnext) | `string` | `null` | `undefined`)
β a replacement file extension or a function that returns a file extension.
> π **note**: an empty string (`''`) or `null` will remove a file extension
- `extensions?` ([`List`](#listt) | `null` | `undefined`)
β the module extensions to probe for
- **default**: [`defaultExtensions`](#defaultextensions)
> π **note**: should be sorted by priority
- `fs?` ([`FileSystem`](#filesystem) | `null` | `undefined`)
β the file system api
- `mainFields?` ([`List`](#mainfield) | `null` | `undefined`)
β the list of legacy `main` fields
- **default**: [`defaultMainFields`](#defaultmainfields)
> π **note**: should be sorted by priority
- `preserveSymlinks?` (`boolean` | `null` | `undefined`)
β whether to keep symlinks instead of resolving them
### `Stat<[T]>`
Get information about a directory or file (`interface`).
#### Type Parameters
- `T` ([`Awaitable`](#stats), optional)
β the info
#### Parameters
- `id` ([`ModuleId`](#moduleid))
β the module id
#### Returns
(`T`) The info
### `Stats`
An object describing a directory or file (`interface`).
#### Properties
- `isDirectory` ([`IsDirectory`](#isdirectory))
β check if the stats object describes a directory
- `isFile` ([`IsFile`](#isfile))
β check if the stats object describes a file
## Contribute
See [`CONTRIBUTING.md`](CONTRIBUTING.md).
This project has a [code of conduct](./CODE_OF_CONDUCT.md). By interacting with this repository, organization, or
community you agree to abide by its terms.
[algorithm-esm-resolve]: ./docs/resolution-algorithm.md#esm_resolvespecifier-parent-conditions-mainfields-preservesymlinks-extensionformatmap
[algorithm-legacy-main-resolve]: ./docs/resolution-algorithm.md#legacy_main_resolvepackageurl-manifest-mainfields
[algorithm-lookup-package-scope]: ./docs/resolution-algorithm.md#lookup_package_scopeurl-end
[algorithm-package-exports-resolve]: ./docs/resolution-algorithm.md#package_exports_resolvepackageurl-subpath-exports-conditions
[algorithm-package-imports-exports-resolve]: ./docs/resolution-algorithm.md#package_imports_exports_resolvematchkey-matchobject-packageurl-isimports-conditions-mainfields
[algorithm-package-imports-resolve]: ./docs/resolution-algorithm.md#package_imports_resolvespecifier-parent-conditions-mainfields
[algorithm-package-resolve]: ./docs/resolution-algorithm.md#package_resolvespecifier-parent-conditions-mainfields
[algorithm-package-self-resolve]: ./docs/resolution-algorithm.md#package_self_resolvename-subpath-parent-conditions
[algorithm-package-target-resolve]: ./docs/resolution-algorithm.md#package_target_resolvepackageurl-target-subpath-patternmatch-isimports-conditions-mainfields
[algorithm-pattern-key-compare]: ./docs/resolution-algorithm.md#pattern_key_comparea-b
[algorithm-read-package-json]: ./docs/resolution-algorithm.md#read_package_jsonid
[builtin-module]: https://nodejs.org/api/esm.html#builtin-modules
[err-invalid-module-specifier]: https://nodejs.org/api/errors.html#err_invalid_module_specifier
[err-invalid-package-config]: https://nodejs.org/api/errors.html#err_invalid_package_config
[err-invalid-package-target]: https://nodejs.org/api/errors.html#err_invalid_package_target
[err-module-not-found]: https://nodejs.org/api/errors.html#err_module_not_found
[err-package-import-not-defined]: https://nodejs.org/api/errors.html#err_package_import_not_defined
[err-unsupported-esm-url-scheme]: https://nodejs.org/api/errors.html#err_unsupported_esm_url_scheme
[esm]: https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c
[esmsh]: https://esm.sh
[exports]: https://nodejs.org/api/packages.html#exports
[file-url]: https://nodejs.org/api/esm.html#file-urls
[main]: https://github.com/nodejs/node/blob/v22.9.0/doc/api/packages.md#main
[node-esm]: https://nodejs.org/api/esm.html
[pkg-exports]: https://github.com/flex-development/pkg-types/blob/main/src/exports.ts
[pkg-exports-object]: https://github.com/flex-development/pkg-types/blob/main/src/exports-object.ts
[pkg-imports-subpath]: https://github.com/flex-development/pkg-types/blob/main/src/imports-subpath.ts
[pkg-imports]: https://github.com/flex-development/pkg-types/blob/main/src/imports.ts
[pkg-package-json]: https://github.com/flex-development/pkg-types/blob/main/src/package-json.ts
[subpath-imports]: https://nodejs.org/api/packages.html#subpath-imports
[typescript]: https://www.typescriptlang.org
[yarn]: https://yarnpkg.com