# import-meta-resolve

[![Build][build-badge]][build]
[![Coverage][coverage-badge]][coverage]
[![Downloads][downloads-badge]][downloads]

Resolve things like Node.js.

## Contents

*   [What is this?](#what-is-this)
*   [When to use this?](#when-to-use-this)
*   [Install](#install)
*   [Use](#use)
*   [API](#api)
    *   [`resolve(specifier, parent)`](#resolvespecifier-parent)
    *   [`moduleResolve(specifier, parent, conditions, preserveSymlinks)`](#moduleresolvespecifier-parent-conditions-preservesymlinks)
    *   [`ErrnoException`](#errnoexception)
*   [Algorithm](#algorithm)
*   [Differences to Node](#differences-to-node)
*   [Types](#types)
*   [Compatibility](#compatibility)
*   [Contribute](#contribute)
*   [License](#license)

## What is this?

This package is a ponyfill for [`import.meta.resolve`][native-resolve].
It supports everything you need to resolve files just like modern Node does:
import maps, export maps, loading CJS and ESM projects, all of that!

## When to use this?

As of Node.js 20.0, `import.meta.resolve` is still behind an experimental flag.
This package can be used to do what it does in Node 16–20.

## Install

This package is [ESM only][esm].
In Node.js (version 16+), install with [npm][]:

```sh
npm install import-meta-resolve
```

## Use

```js
import {resolve} from 'import-meta-resolve'

// A file:
console.log(resolve('./index.js', import.meta.url))
//=> file:///Users/tilde/Projects/oss/import-meta-resolve/index.js

// A CJS package:
console.log(resolve('builtins', import.meta.url))
//=> file:///Users/tilde/Projects/oss/import-meta-resolve/node_modules/builtins/index.js

// A scoped CJS package:
console.log(resolve('@eslint/eslintrc', import.meta.url))
//=> file:///Users/tilde/Projects/oss/import-meta-resolve/node_modules/@eslint/eslintrc/lib/index.js

// A package with an export map:
console.log(resolve('micromark/lib/parse', import.meta.url))
//=> file:///Users/tilde/Projects/oss/import-meta-resolve/node_modules/micromark/lib/parse.js

// A node builtin:
console.log(resolve('fs', import.meta.url))
//=> node:fs
```

## API

This package exports the identifiers [`moduleResolve`][moduleresolve] and
[`resolve`][resolve].
There is no default export.

### `resolve(specifier, parent)`

Match `import.meta.resolve` except that `parent` is required (you can pass
`import.meta.url`).

###### Parameters

*   `specifier` (`string`)
    — the module specifier to resolve relative to parent
    (`/example.js`, `./example.js`, `../example.js`, `some-package`, `fs`, etc)
*   `parent` (`string`, example: `import.meta.url`)
    — the absolute parent module URL to resolve from; you must pass
    `import.meta.url` or something else

###### Returns

Full `file:`, `data:`, or `node:` URL (`string`) to the found thing

###### Throws

Throws an [`ErrnoException`][errnoexception].

### `moduleResolve(specifier, parent, conditions, preserveSymlinks)`

The [“Resolver Algorithm Specification”][algo] as detailed in the Node docs
(which is slightly lower-level than `resolve`).

###### Parameters

*   `specifier` (`string`)
    — `/example.js`, `./example.js`, `../example.js`, `some-package`, `fs`, etc
*   `parent` (`URL`, example: `import.meta.url`)
    — full URL (to a file) that `specifier` is resolved relative from
*   `conditions` (`Set<string>`, default: `new Set(['node', 'import'])`)
    — conditions
*   `preserveSymlinks` (`boolean`, default: `false`)
    — keep symlinks instead of resolving them

###### Returns

A URL object (`URL`) to the found thing.

###### Throws

Throws an [`ErrnoException`][errnoexception].

### `ErrnoException`

One of many different errors that occur when resolving (TypeScript type).

###### Type

```ts
type ErrnoExceptionFields = Error & {
  errnode?: number | undefined
  code?: string | undefined
  path?: string | undefined
  syscall?: string | undefined
  url?: string | undefined
}
```

The `code` field on errors is one of the following strings:

*   `'ERR_INVALID_MODULE_SPECIFIER'`
    — when `specifier` is invalid (example: `'#'`)
*   `'ERR_INVALID_PACKAGE_CONFIG'`
    — when a `package.json` is invalid (example: invalid JSON)
*   `'ERR_INVALID_PACKAGE_TARGET'`
    — when a `package.json` `exports` or `imports` is invalid (example: when it
    does not start with `'./'`)
*   `'ERR_MODULE_NOT_FOUND'`
    — when `specifier` cannot be found in `parent` (example: `'some-missing-package'`)
*   `'ERR_NETWORK_IMPORT_DISALLOWED'`
    — thrown when trying to resolve a local file or builtin from a remote file
    (`node:fs` relative to `'https://example.com'`)
*   `'ERR_PACKAGE_IMPORT_NOT_DEFINED'`
    — when a local import is not defined in an import map (example: `'#local'`
    when not defined)
*   `'ERR_PACKAGE_PATH_NOT_EXPORTED'`
    — when an export is not defined in an export map (example: `'tape/index.js'`,
    which is not in its export map)
*   `'ERR_UNSUPPORTED_DIR_IMPORT'`
    — when attempting to import a directory (example: `'./lib/'`)
*   `'ERR_UNKNOWN_FILE_EXTENSION'`
    — when somehow reading a file that has an unexpected extensions (`'./readme.md'`)
*   `'ERR_INVALID_ARG_VALUE'`
    — when `conditions` is incorrect

## Algorithm

The algorithm for `resolve` matches how Node handles `import.meta.resolve`, with
a couple of differences.

The algorithm for `moduleResolve` matches the [Resolver Algorithm
Specification][algo] as detailed in the Node docs (which is sync and slightly
lower-level than `resolve`).

## Differences to Node

*   `parent` defaulting to `import.meta.url` cannot be ponyfilled: you have to
    explicitly pass it
*   no support for loaders (that would mean implementing all of loaders)
*   no support for CLI flags:
    `--conditions`,
    `--experimental-default-type`,
    `--experimental-json-modules`,
    `--experimental-network-imports`,
    `--experimental-policy`,
    `--experimental-wasm-modules`,
    `--input-type`,
    `--no-addons`,
    `--preserve-symlinks`, nor
    `--preserve-symlinks-main`
    work
*   no support for `WATCH_REPORT_DEPENDENCIES` env variable
*   no attempt is made to add a suggestion based on how things used to work in
    CJS before to not-found errors
*   prototypal methods are not guarded: Node protects for example `String#slice`
    or so from being tampered with, whereas this doesn’t

## Types

This package is fully typed with [TypeScript][].
It exports the additional type [`ErrnoException`][errnoexception].

## Compatibility

This package is at least compatible with all maintained versions of Node.js.
As of now, that is Node.js 16 and later.

## Contribute

Yes please!
See [How to Contribute to Open Source][contribute].

## License

[MIT][license] © [Titus Wormer][author] and Node.js contributors

<!-- Definitions -->

[build-badge]: https://github.com/wooorm/import-meta-resolve/workflows/main/badge.svg

[build]: https://github.com/wooorm/import-meta-resolve/actions

[coverage-badge]: https://img.shields.io/codecov/c/github/wooorm/import-meta-resolve.svg

[coverage]: https://codecov.io/github/wooorm/import-meta-resolve

[downloads-badge]: https://img.shields.io/npm/dm/import-meta-resolve.svg

[downloads]: https://www.npmjs.com/package/import-meta-resolve

[npm]: https://docs.npmjs.com/cli/install

[license]: license

[author]: https://wooorm.com

[esm]: https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c

[typescript]: https://www.typescriptlang.org

[contribute]: https://opensource.guide/how-to-contribute/

[algo]: https://nodejs.org/dist/latest-v14.x/docs/api/esm.html#esm_resolver_algorithm

[native-resolve]: https://nodejs.org/api/esm.html#esm_import_meta_resolve_specifier_parent

[resolve]: #resolvespecifier-parent

[moduleresolve]: #moduleResolvespecifier-parent-conditions-preserveSymlinks

[errnoexception]: #errnoexception
