An open API service indexing awesome lists of open source software.

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

Awesome Lists containing this project

README

          

# \:gear: mlly

[![github release](https://img.shields.io/github/v/release/flex-development/mlly.svg?include_prereleases\&sort=semver)](https://github.com/flex-development/mlly/releases/latest)
[![npm](https://img.shields.io/npm/v/@flex-development/mlly.svg)](https://npmjs.com/package/@flex-development/mlly)
[![npm downloads](https://img.shields.io/npm/dm/@flex-development/mlly.svg)](https://www.npmcharts.com/compare/@flex-development/mlly?interval=30)
[![install size](https://packagephobia.now.sh/badge?p=@flex-development/mlly)](https://packagephobia.now.sh/result?p=@flex-development/mlly)
[![codecov](https://codecov.io/gh/flex-development/mlly/graph/badge.svg?token=36NUNRH6FW)](https://codecov.io/gh/flex-development/mlly)
[![module type: esm](https://img.shields.io/badge/module%20type-esm-brightgreen)](https://github.com/voxpelli/badges-cjs-esm)
[![license](https://img.shields.io/github/license/flex-development/mlly.svg)](LICENSE.md)
[![conventional commits](https://img.shields.io/badge/-conventional%20commits-fe5196?logo=conventional-commits\&logoColor=ffffff)](https://conventionalcommits.org)
[![typescript](https://img.shields.io/badge/-typescript-3178c6?logo=typescript\&logoColor=ffffff)](https://typescriptlang.org)
[![vitest](https://img.shields.io/badge/-vitest-6e9f18?style=flat\&logo=vitest\&logoColor=ffffff)](https://vitest.dev)
[![yarn](https://img.shields.io/badge/-yarn-2c8ebb?style=flat\&logo=yarn\&logoColor=ffffff)](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