dev-api: add developer portal, OpenAPI spec, and Flatenbadet case study

- New /developers/ page with API docs, SDKs, pricing, use cases
- OpenAPI 3.0 spec for Orders, Missions, Photos, Analytics
- Case study: Glasskiosken i Flatenbadet — complete ROI analysis
- Updated /order/ with recurring missions and frequency dropdown
This commit is contained in:
Bernt
2026-07-14 15:27:33 +00:00
parent 3c522e39f0
commit 1a12fb870b
6296 changed files with 911440 additions and 55607 deletions
+21
View File
@@ -0,0 +1,21 @@
MIT License
Copyright (c) Pooya Parsa <pooya@pi0.io>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
+561
View File
@@ -0,0 +1,561 @@
# mlly
[![npm version][npm-version-src]][npm-version-href]
[![npm downloads][npm-downloads-src]][npm-downloads-href]
[![Codecov][codecov-src]][codecov-href]
> Missing [ECMAScript module](https://nodejs.org/api/esm.html) utils for Node.js
While ESM Modules are evolving in Node.js ecosystem, there are still
many required features that are still experimental or missing or needed to support ESM. This package tries to fill in the gap.
## Usage
Install npm package:
```sh
# using yarn
yarn add mlly
# using npm
npm install mlly
```
**Note:** Node.js 14+ is recommended.
Import utils:
```js
// ESM
import {} from "mlly";
// CommonJS
const {} = require("mlly");
```
## Resolving ESM modules
Several utilities to make ESM resolution easier:
- Respecting [ECMAScript Resolver algorithm](https://nodejs.org/dist/latest-v14.x/docs/api/esm.html#esm_resolver_algorithm)
- Exposed from Node.js implementation
- Windows paths normalized
- Supporting custom `extensions` and `/index` resolution
- Supporting custom `conditions`
- Support resolving from multiple paths or urls
### `resolve` / `resolveSync`
Resolve a module by respecting [ECMAScript Resolver algorithm](https://nodejs.org/dist/latest-v14.x/docs/api/esm.html#esm_resolver_algorithm)
(using [wooorm/import-meta-resolve](https://github.com/wooorm/import-meta-resolve)).
Additionally supports resolving without extension and `/index` similar to CommonJS.
```js
import { resolve, resolveSync } from "mlly";
// file:///home/user/project/module.mjs
console.log(await resolve("./module.mjs", { url: import.meta.url }));
```
**Resolve options:**
- `url`: URL or string to resolve from (default is `pwd()`)
- `conditions`: Array of conditions used for resolution algorithm (default is `['node', 'import']`)
- `extensions`: Array of additional extensions to check if import failed (default is `['.mjs', '.cjs', '.js', '.json']`)
### `resolvePath` / `resolvePathSync`
Similar to `resolve` but returns a path instead of URL using `fileURLToPath`.
```js
import { resolvePath, resolveSync } from "mlly";
// /home/user/project/module.mjs
console.log(await resolvePath("./module.mjs", { url: import.meta.url }));
```
### `createResolve`
Create a `resolve` function with defaults.
```js
import { createResolve } from "mlly";
const _resolve = createResolve({ url: import.meta.url });
// file:///home/user/project/module.mjs
console.log(await _resolve("./module.mjs"));
```
**Example:** Ponyfill [import.meta.resolve](https://nodejs.org/api/esm.html#esm_import_meta_resolve_specifier_parent):
```js
import { createResolve } from "mlly";
import.meta.resolve = createResolve({ url: import.meta.url });
```
### `resolveImports`
Resolve all static and dynamic imports with relative paths to full resolved path.
```js
import { resolveImports } from "mlly";
// import foo from 'file:///home/user/project/bar.mjs'
console.log(
await resolveImports(`import foo from './bar.mjs'`, { url: import.meta.url }),
);
```
## Syntax Analyzes
### `isValidNodeImport`
Using various syntax detection and heuristics, this method can determine if import is a valid import or not to be imported using dynamic `import()` before hitting an error!
When result is `false`, we usually need a to create a CommonJS require context or add specific rules to the bundler to transform dependency.
```js
import { isValidNodeImport } from "mlly";
// If returns true, we are safe to use `import('some-lib')`
await isValidNodeImport("some-lib", {});
```
**Algorithm:**
- Check import protocol - If is `data:` return `true` (✅ valid) - If is not `node:`, `file:` or `data:`, return `false` (
❌ invalid)
- Resolve full path of import using Node.js [Resolution algorithm](https://nodejs.org/api/esm.html#resolution-algorithm)
- Check full path extension
- If is `.mjs`, `.cjs`, `.node` or `.wasm`, return `true` (✅ valid)
- If is not `.js`, return `false` (❌ invalid)
- If is matching known mixed syntax (`.esm.js`, `.es.js`, etc) return `false` (
❌ invalid)
- Read closest `package.json` file to resolve path
- If `type: 'module'` field is set, return `true` (✅ valid)
- Read source code of resolved path
- Try to detect CommonJS syntax usage
- If yes, return `true` (✅ valid)
- Try to detect ESM syntax usage
- if yes, return `false` (
❌ invalid)
**Notes:**
- There might be still edge cases algorithm cannot cover. It is designed with best-efforts.
- This method also allows using dynamic import of CommonJS libraries considering
Node.js has [Interoperability with CommonJS](https://nodejs.org/api/esm.html#interoperability-with-commonjs).
### `hasESMSyntax`
Detect if code, has usage of ESM syntax (Static `import`, ESM `export` and `import.meta` usage)
```js
import { hasESMSyntax } from "mlly";
hasESMSyntax("export default foo = 123"); // true
```
### `hasCJSSyntax`
Detect if code, has usage of CommonJS syntax (`exports`, `module.exports`, `require` and `global` usage)
```js
import { hasCJSSyntax } from "mlly";
hasCJSSyntax("export default foo = 123"); // false
```
### `detectSyntax`
Tests code against both CJS and ESM.
`isMixed` indicates if both are detected! This is a common case with legacy packages exporting semi-compatible ESM syntax meant to be used by bundlers.
```js
import { detectSyntax } from "mlly";
// { hasESM: true, hasCJS: true, isMixed: true }
detectSyntax('export default require("lodash")');
```
## CommonJS Context
### `createCommonJS`
This utility creates a compatible CommonJS context that is missing in ECMAScript modules.
```js
import { createCommonJS } from "mlly";
const { __dirname, __filename, require } = createCommonJS(import.meta.url);
```
Note: `require` and `require.resolve` implementation are lazy functions. [`createRequire`](https://nodejs.org/api/module.html#module_module_createrequire_filename) will be called on first usage.
## Import/Export Analyzes
Tools to quickly analyze ESM syntax and extract static `import`/`export`
- Super fast Regex based implementation
- Handle most edge cases
- Find all static ESM imports
- Find all dynamic ESM imports
- Parse static import statement
- Find all named, declared and default exports
### `findStaticImports`
Find all static ESM imports.
Example:
```js
import { findStaticImports } from "mlly";
console.log(
findStaticImports(`
// Empty line
import foo, { bar /* foo */ } from 'baz'
`),
);
```
Outputs:
```js
[
{
type: "static",
imports: "foo, { bar /* foo */ } ",
specifier: "baz",
code: "import foo, { bar /* foo */ } from 'baz'",
start: 15,
end: 55,
},
];
```
### `parseStaticImport`
Parse a dynamic ESM import statement previously matched by `findStaticImports`.
Example:
```js
import { findStaticImports, parseStaticImport } from "mlly";
const [match0] = findStaticImports(`import baz, { x, y as z } from 'baz'`);
console.log(parseStaticImport(match0));
```
Outputs:
```js
{
type: 'static',
imports: 'baz, { x, y as z } ',
specifier: 'baz',
code: "import baz, { x, y as z } from 'baz'",
start: 0,
end: 36,
defaultImport: 'baz',
namespacedImport: undefined,
namedImports: { x: 'x', y: 'z' }
}
```
### `findDynamicImports`
Find all dynamic ESM imports.
Example:
```js
import { findDynamicImports } from "mlly";
console.log(
findDynamicImports(`
const foo = await import('bar')
`),
);
```
### `findExports`
```js
import { findExports } from "mlly";
console.log(
findExports(`
export const foo = 'bar'
export { bar, baz }
export default something
`),
);
```
Outputs:
```js
[
{
type: "declaration",
declaration: "const",
name: "foo",
code: "export const foo",
start: 1,
end: 17,
},
{
type: "named",
exports: " bar, baz ",
code: "export { bar, baz }",
start: 26,
end: 45,
names: ["bar", "baz"],
},
{ type: "default", code: "export default ", start: 46, end: 61 },
];
```
### `findExportNames`
Same as `findExports` but returns array of export names.
```js
import { findExportNames } from "mlly";
// [ "foo", "bar", "baz", "default" ]
console.log(
findExportNames(`
export const foo = 'bar'
export { bar, baz }
export default something
`),
);
```
## `resolveModuleExportNames`
Resolves module and reads its contents to extract possible export names using static analyzes.
```js
import { resolveModuleExportNames } from "mlly";
// ["basename", "dirname", ... ]
console.log(await resolveModuleExportNames("mlly"));
```
## Evaluating Modules
Set of utilities to evaluate ESM modules using `data:` imports
- Automatic import rewrite to resolved path using static analyzes
- Allow bypass ESM Cache
- Stack-trace support
- `.json` loader
### `evalModule`
Transform and evaluates module code using dynamic imports.
```js
import { evalModule } from "mlly";
await evalModule(`console.log("Hello World!")`);
await evalModule(
`
import { reverse } from './utils.mjs'
console.log(reverse('!emosewa si sj'))
`,
{ url: import.meta.url },
);
```
**Options:**
- all `resolve` options
- `url`: File URL
### `loadModule`
Dynamically loads a module by evaluating source code.
```js
import { loadModule } from "mlly";
await loadModule("./hello.mjs", { url: import.meta.url });
```
Options are same as `evalModule`.
### `transformModule`
- Resolves all relative imports will be resolved
- All usages of `import.meta.url` will be replaced with `url` or `from` option
```js
import { transformModule } from "mlly";
console.log(transformModule(`console.log(import.meta.url)`), {
url: "test.mjs",
});
```
Options are same as `evalModule`.
## Other Utils
### `fileURLToPath`
Similar to [url.fileURLToPath](https://nodejs.org/api/url.html#url_url_fileurltopath_url) but also converts windows backslash `\` to unix slash `/` and handles if input is already a path.
```js
import { fileURLToPath } from "mlly";
// /foo/bar.js
console.log(fileURLToPath("file:///foo/bar.js"));
// C:/path
console.log(fileURLToPath("file:///C:/path/"));
```
### `pathToFileURL`
Similar to [url.pathToFileURL](https://nodejs.org/api/url.html#urlpathtofileurlpath) but also handles `URL` input and returns a **string** with `file://` protocol.
```js
import { pathToFileURL } from "mlly";
// /foo/bar.js
console.log(pathToFileURL("foo/bar.js"));
// C:/path
console.log(pathToFileURL("C:\\path"));
```
### `normalizeid`
Ensures id has either of `node:`, `data:`, `http:`, `https:` or `file:` protocols.
```js
import { normalizeid } from "mlly";
// file:///foo/bar.js
console.log(normalizeid("/foo/bar.js"));
```
### `loadURL`
Read source contents of a URL. (currently only file protocol supported)
```js
import { resolve, loadURL } from "mlly";
const url = await resolve("./index.mjs", { url: import.meta.url });
console.log(await loadURL(url));
```
### `toDataURL`
Convert code to [`data:`](https://nodejs.org/api/esm.html#esm_data_imports) URL using base64 encoding.
```js
import { toDataURL } from "mlly";
console.log(
toDataURL(`
// This is an example
console.log('Hello world')
`),
);
```
### `interopDefault`
Return the default export of a module at the top-level, alongside any other named exports.
```js
// Assuming the shape { default: { foo: 'bar' }, baz: 'qux' }
import myModule from "my-module";
// Returns { foo: 'bar', baz: 'qux' }
console.log(interopDefault(myModule));
```
**Options:**
- `preferNamespace`: In case that `default` value exists but is not extendable (when is string for example), return input as-is (default is `false`, meaning `default`'s value is prefered even if cannot be extended)
### `sanitizeURIComponent`
Replace reserved characters from a segment of URI to make it compatible with [rfc2396](https://datatracker.ietf.org/doc/html/rfc2396).
```js
import { sanitizeURIComponent } from "mlly";
// foo_bar
console.log(sanitizeURIComponent(`foo:bar`));
```
### `sanitizeFilePath`
Sanitize each path of a file name or path with `sanitizeURIComponent` for URI compatibility.
```js
import { sanitizeFilePath } from "mlly";
// C:/te_st/_...slug_.jsx'
console.log(sanitizeFilePath("C:\\te#st\\[...slug].jsx"));
```
### `parseNodeModulePath`
Parses an absolute file path in `node_modules` to three segments:
- `dir`: Path to main directory of package
- `name`: Package name
- `subpath`: The optional package subpath
It returns an empty object (with partial keys) if parsing fails.
```js
import { parseNodeModulePath } from "mlly";
// dir: "/src/a/node_modules/"
// name: "lib"
// subpath: "./dist/index.mjs"
const { dir, name, subpath } = parseNodeModulePath(
"/src/a/node_modules/lib/dist/index.mjs",
);
```
### `lookupNodeModuleSubpath`
Parses an absolute file path in `node_modules` and tries to reverse lookup (or guess) the original package exports subpath for it.
```js
import { lookupNodeModuleSubpath } from "mlly";
// subpath: "./utils"
const subpath = lookupNodeModuleSubpath(
"/src/a/node_modules/lib/dist/utils.mjs",
);
```
## License
[MIT](./LICENSE) - Made with 💛
<!-- Badges -->
[npm-version-src]: https://img.shields.io/npm/v/mlly?style=flat&colorA=18181B&colorB=F0DB4F
[npm-version-href]: https://npmjs.com/package/mlly
[npm-downloads-src]: https://img.shields.io/npm/dm/mlly?style=flat&colorA=18181B&colorB=F0DB4F
[npm-downloads-href]: https://npmjs.com/package/mlly
[codecov-src]: https://img.shields.io/codecov/c/gh/unjs/mlly/main?style=flat&colorA=18181B&colorB=F0DB4F
[codecov-href]: https://codecov.io/gh/unjs/mlly
+2756
View File
@@ -0,0 +1,2756 @@
'use strict';
const acorn = require('acorn');
const node_module = require('node:module');
const fs = require('node:fs');
const ufo = require('ufo');
const pathe = require('pathe');
const pkgTypes = require('pkg-types');
const node_url = require('node:url');
const assert = require('node:assert');
const process$1 = require('node:process');
const path = require('node:path');
const v8 = require('node:v8');
const node_util = require('node:util');
function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e.default : e; }
const fs__default = /*#__PURE__*/_interopDefaultCompat(fs);
const assert__default = /*#__PURE__*/_interopDefaultCompat(assert);
const process__default = /*#__PURE__*/_interopDefaultCompat(process$1);
const path__default = /*#__PURE__*/_interopDefaultCompat(path);
const v8__default = /*#__PURE__*/_interopDefaultCompat(v8);
const BUILTIN_MODULES = new Set(node_module.builtinModules);
function normalizeSlash(path) {
return path.replace(/\\/g, "/");
}
function isObject(value) {
return value !== null && typeof value === "object";
}
function matchAll(regex, string, addition) {
const matches = [];
for (const match of string.matchAll(regex)) {
matches.push({
...addition,
...match.groups,
code: match[0],
start: match.index,
end: (match.index || 0) + match[0].length
});
}
return matches;
}
function clearImports(imports) {
return (imports || "").replace(/\/\/[^\n]*\n|\/\*.*\*\//g, "").replace(/\s+/g, " ");
}
function getImportNames(cleanedImports) {
const topLevelImports = cleanedImports.replace(/{[^}]*}/, "");
const namespacedImport = topLevelImports.match(/\* as \s*(\S*)/)?.[1];
const defaultImport = topLevelImports.split(",").find((index) => !/[*{}]/.test(index))?.trim() || void 0;
return {
namespacedImport,
defaultImport
};
}
/**
* @typedef ErrnoExceptionFields
* @property {number | undefined} [errnode]
* @property {string | undefined} [code]
* @property {string | undefined} [path]
* @property {string | undefined} [syscall]
* @property {string | undefined} [url]
*
* @typedef {Error & ErrnoExceptionFields} ErrnoException
*/
const own$1 = {}.hasOwnProperty;
const classRegExp = /^([A-Z][a-z\d]*)+$/;
// Sorted by a rough estimate on most frequently used entries.
const kTypes = new Set([
'string',
'function',
'number',
'object',
// Accept 'Function' and 'Object' as alternative to the lower cased version.
'Function',
'Object',
'boolean',
'bigint',
'symbol'
]);
const codes = {};
/**
* Create a list string in the form like 'A and B' or 'A, B, ..., and Z'.
* We cannot use Intl.ListFormat because it's not available in
* --without-intl builds.
*
* @param {Array<string>} array
* An array of strings.
* @param {string} [type]
* The list type to be inserted before the last element.
* @returns {string}
*/
function formatList(array, type = 'and') {
return array.length < 3
? array.join(` ${type} `)
: `${array.slice(0, -1).join(', ')}, ${type} ${array[array.length - 1]}`
}
/** @type {Map<string, MessageFunction | string>} */
const messages = new Map();
const nodeInternalPrefix = '__node_internal_';
/** @type {number} */
let userStackTraceLimit;
codes.ERR_INVALID_ARG_TYPE = createError(
'ERR_INVALID_ARG_TYPE',
/**
* @param {string} name
* @param {Array<string> | string} expected
* @param {unknown} actual
*/
(name, expected, actual) => {
assert__default.ok(typeof name === 'string', "'name' must be a string");
if (!Array.isArray(expected)) {
expected = [expected];
}
let message = 'The ';
if (name.endsWith(' argument')) {
// For cases like 'first argument'
message += `${name} `;
} else {
const type = name.includes('.') ? 'property' : 'argument';
message += `"${name}" ${type} `;
}
message += 'must be ';
/** @type {Array<string>} */
const types = [];
/** @type {Array<string>} */
const instances = [];
/** @type {Array<string>} */
const other = [];
for (const value of expected) {
assert__default.ok(
typeof value === 'string',
'All expected entries have to be of type string'
);
if (kTypes.has(value)) {
types.push(value.toLowerCase());
} else if (classRegExp.exec(value) === null) {
assert__default.ok(
value !== 'object',
'The value "object" should be written as "Object"'
);
other.push(value);
} else {
instances.push(value);
}
}
// Special handle `object` in case other instances are allowed to outline
// the differences between each other.
if (instances.length > 0) {
const pos = types.indexOf('object');
if (pos !== -1) {
types.slice(pos, 1);
instances.push('Object');
}
}
if (types.length > 0) {
message += `${types.length > 1 ? 'one of type' : 'of type'} ${formatList(
types,
'or'
)}`;
if (instances.length > 0 || other.length > 0) message += ' or ';
}
if (instances.length > 0) {
message += `an instance of ${formatList(instances, 'or')}`;
if (other.length > 0) message += ' or ';
}
if (other.length > 0) {
if (other.length > 1) {
message += `one of ${formatList(other, 'or')}`;
} else {
if (other[0].toLowerCase() !== other[0]) message += 'an ';
message += `${other[0]}`;
}
}
message += `. Received ${determineSpecificType(actual)}`;
return message
},
TypeError
);
codes.ERR_INVALID_MODULE_SPECIFIER = createError(
'ERR_INVALID_MODULE_SPECIFIER',
/**
* @param {string} request
* @param {string} reason
* @param {string} [base]
*/
(request, reason, base = undefined) => {
return `Invalid module "${request}" ${reason}${
base ? ` imported from ${base}` : ''
}`
},
TypeError
);
codes.ERR_INVALID_PACKAGE_CONFIG = createError(
'ERR_INVALID_PACKAGE_CONFIG',
/**
* @param {string} path
* @param {string} [base]
* @param {string} [message]
*/
(path, base, message) => {
return `Invalid package config ${path}${
base ? ` while importing ${base}` : ''
}${message ? `. ${message}` : ''}`
},
Error
);
codes.ERR_INVALID_PACKAGE_TARGET = createError(
'ERR_INVALID_PACKAGE_TARGET',
/**
* @param {string} packagePath
* @param {string} key
* @param {unknown} target
* @param {boolean} [isImport=false]
* @param {string} [base]
*/
(packagePath, key, target, isImport = false, base = undefined) => {
const relatedError =
typeof target === 'string' &&
!isImport &&
target.length > 0 &&
!target.startsWith('./');
if (key === '.') {
assert__default.ok(isImport === false);
return (
`Invalid "exports" main target ${JSON.stringify(target)} defined ` +
`in the package config ${packagePath}package.json${
base ? ` imported from ${base}` : ''
}${relatedError ? '; targets must start with "./"' : ''}`
)
}
return `Invalid "${
isImport ? 'imports' : 'exports'
}" target ${JSON.stringify(
target
)} defined for '${key}' in the package config ${packagePath}package.json${
base ? ` imported from ${base}` : ''
}${relatedError ? '; targets must start with "./"' : ''}`
},
Error
);
codes.ERR_MODULE_NOT_FOUND = createError(
'ERR_MODULE_NOT_FOUND',
/**
* @param {string} path
* @param {string} base
* @param {boolean} [exactUrl]
*/
(path, base, exactUrl = false) => {
return `Cannot find ${
exactUrl ? 'module' : 'package'
} '${path}' imported from ${base}`
},
Error
);
codes.ERR_NETWORK_IMPORT_DISALLOWED = createError(
'ERR_NETWORK_IMPORT_DISALLOWED',
"import of '%s' by %s is not supported: %s",
Error
);
codes.ERR_PACKAGE_IMPORT_NOT_DEFINED = createError(
'ERR_PACKAGE_IMPORT_NOT_DEFINED',
/**
* @param {string} specifier
* @param {string} packagePath
* @param {string} base
*/
(specifier, packagePath, base) => {
return `Package import specifier "${specifier}" is not defined${
packagePath ? ` in package ${packagePath}package.json` : ''
} imported from ${base}`
},
TypeError
);
codes.ERR_PACKAGE_PATH_NOT_EXPORTED = createError(
'ERR_PACKAGE_PATH_NOT_EXPORTED',
/**
* @param {string} packagePath
* @param {string} subpath
* @param {string} [base]
*/
(packagePath, subpath, base = undefined) => {
if (subpath === '.')
return `No "exports" main defined in ${packagePath}package.json${
base ? ` imported from ${base}` : ''
}`
return `Package subpath '${subpath}' is not defined by "exports" in ${packagePath}package.json${
base ? ` imported from ${base}` : ''
}`
},
Error
);
codes.ERR_UNSUPPORTED_DIR_IMPORT = createError(
'ERR_UNSUPPORTED_DIR_IMPORT',
"Directory import '%s' is not supported " +
'resolving ES modules imported from %s',
Error
);
codes.ERR_UNSUPPORTED_RESOLVE_REQUEST = createError(
'ERR_UNSUPPORTED_RESOLVE_REQUEST',
'Failed to resolve module specifier "%s" from "%s": Invalid relative URL or base scheme is not hierarchical.',
TypeError
);
codes.ERR_UNKNOWN_FILE_EXTENSION = createError(
'ERR_UNKNOWN_FILE_EXTENSION',
/**
* @param {string} extension
* @param {string} path
*/
(extension, path) => {
return `Unknown file extension "${extension}" for ${path}`
},
TypeError
);
codes.ERR_INVALID_ARG_VALUE = createError(
'ERR_INVALID_ARG_VALUE',
/**
* @param {string} name
* @param {unknown} value
* @param {string} [reason='is invalid']
*/
(name, value, reason = 'is invalid') => {
let inspected = node_util.inspect(value);
if (inspected.length > 128) {
inspected = `${inspected.slice(0, 128)}...`;
}
const type = name.includes('.') ? 'property' : 'argument';
return `The ${type} '${name}' ${reason}. Received ${inspected}`
},
TypeError
// Note: extra classes have been shaken out.
// , RangeError
);
/**
* Utility function for registering the error codes. Only used here. Exported
* *only* to allow for testing.
* @param {string} sym
* @param {MessageFunction | string} value
* @param {ErrorConstructor} constructor
* @returns {new (...parameters: Array<any>) => Error}
*/
function createError(sym, value, constructor) {
// Special case for SystemError that formats the error message differently
// The SystemErrors only have SystemError as their base classes.
messages.set(sym, value);
return makeNodeErrorWithCode(constructor, sym)
}
/**
* @param {ErrorConstructor} Base
* @param {string} key
* @returns {ErrorConstructor}
*/
function makeNodeErrorWithCode(Base, key) {
// @ts-expect-error Its a Node error.
return NodeError
/**
* @param {Array<unknown>} parameters
*/
function NodeError(...parameters) {
const limit = Error.stackTraceLimit;
if (isErrorStackTraceLimitWritable()) Error.stackTraceLimit = 0;
const error = new Base();
// Reset the limit and setting the name property.
if (isErrorStackTraceLimitWritable()) Error.stackTraceLimit = limit;
const message = getMessage(key, parameters, error);
Object.defineProperties(error, {
// Note: no need to implement `kIsNodeError` symbol, would be hard,
// probably.
message: {
value: message,
enumerable: false,
writable: true,
configurable: true
},
toString: {
/** @this {Error} */
value() {
return `${this.name} [${key}]: ${this.message}`
},
enumerable: false,
writable: true,
configurable: true
}
});
captureLargerStackTrace(error);
// @ts-expect-error Its a Node error.
error.code = key;
return error
}
}
/**
* @returns {boolean}
*/
function isErrorStackTraceLimitWritable() {
// Do no touch Error.stackTraceLimit as V8 would attempt to install
// it again during deserialization.
try {
if (v8__default.startupSnapshot.isBuildingSnapshot()) {
return false
}
} catch {}
const desc = Object.getOwnPropertyDescriptor(Error, 'stackTraceLimit');
if (desc === undefined) {
return Object.isExtensible(Error)
}
return own$1.call(desc, 'writable') && desc.writable !== undefined
? desc.writable
: desc.set !== undefined
}
/**
* This function removes unnecessary frames from Node.js core errors.
* @template {(...parameters: unknown[]) => unknown} T
* @param {T} wrappedFunction
* @returns {T}
*/
function hideStackFrames(wrappedFunction) {
// We rename the functions that will be hidden to cut off the stacktrace
// at the outermost one
const hidden = nodeInternalPrefix + wrappedFunction.name;
Object.defineProperty(wrappedFunction, 'name', {value: hidden});
return wrappedFunction
}
const captureLargerStackTrace = hideStackFrames(
/**
* @param {Error} error
* @returns {Error}
*/
// @ts-expect-error: fine
function (error) {
const stackTraceLimitIsWritable = isErrorStackTraceLimitWritable();
if (stackTraceLimitIsWritable) {
userStackTraceLimit = Error.stackTraceLimit;
Error.stackTraceLimit = Number.POSITIVE_INFINITY;
}
Error.captureStackTrace(error);
// Reset the limit
if (stackTraceLimitIsWritable) Error.stackTraceLimit = userStackTraceLimit;
return error
}
);
/**
* @param {string} key
* @param {Array<unknown>} parameters
* @param {Error} self
* @returns {string}
*/
function getMessage(key, parameters, self) {
const message = messages.get(key);
assert__default.ok(message !== undefined, 'expected `message` to be found');
if (typeof message === 'function') {
assert__default.ok(
message.length <= parameters.length, // Default options do not count.
`Code: ${key}; The provided arguments length (${parameters.length}) does not ` +
`match the required ones (${message.length}).`
);
return Reflect.apply(message, self, parameters)
}
const regex = /%[dfijoOs]/g;
let expectedLength = 0;
while (regex.exec(message) !== null) expectedLength++;
assert__default.ok(
expectedLength === parameters.length,
`Code: ${key}; The provided arguments length (${parameters.length}) does not ` +
`match the required ones (${expectedLength}).`
);
if (parameters.length === 0) return message
parameters.unshift(message);
return Reflect.apply(node_util.format, null, parameters)
}
/**
* Determine the specific type of a value for type-mismatch errors.
* @param {unknown} value
* @returns {string}
*/
function determineSpecificType(value) {
if (value === null || value === undefined) {
return String(value)
}
if (typeof value === 'function' && value.name) {
return `function ${value.name}`
}
if (typeof value === 'object') {
if (value.constructor && value.constructor.name) {
return `an instance of ${value.constructor.name}`
}
return `${node_util.inspect(value, {depth: -1})}`
}
let inspected = node_util.inspect(value, {colors: false});
if (inspected.length > 28) {
inspected = `${inspected.slice(0, 25)}...`;
}
return `type ${typeof value} (${inspected})`
}
// Manually “tree shaken” from:
// <https://github.com/nodejs/node/blob/7c3dce0/lib/internal/modules/package_json_reader.js>
// Last checked on: Apr 29, 2024.
// Removed the native dependency.
// Also: no need to cache, we do that in resolve already.
const hasOwnProperty$1 = {}.hasOwnProperty;
const {ERR_INVALID_PACKAGE_CONFIG: ERR_INVALID_PACKAGE_CONFIG$1} = codes;
/** @type {Map<string, PackageConfig>} */
const cache = new Map();
/**
* @param {string} jsonPath
* @param {{specifier: URL | string, base?: URL}} options
* @returns {PackageConfig}
*/
function read(jsonPath, {base, specifier}) {
const existing = cache.get(jsonPath);
if (existing) {
return existing
}
/** @type {string | undefined} */
let string;
try {
string = fs__default.readFileSync(path__default.toNamespacedPath(jsonPath), 'utf8');
} catch (error) {
const exception = /** @type {ErrnoException} */ (error);
if (exception.code !== 'ENOENT') {
throw exception
}
}
/** @type {PackageConfig} */
const result = {
exists: false,
pjsonPath: jsonPath,
main: undefined,
name: undefined,
type: 'none', // Ignore unknown types for forwards compatibility
exports: undefined,
imports: undefined
};
if (string !== undefined) {
/** @type {Record<string, unknown>} */
let parsed;
try {
parsed = JSON.parse(string);
} catch (error_) {
const cause = /** @type {ErrnoException} */ (error_);
const error = new ERR_INVALID_PACKAGE_CONFIG$1(
jsonPath,
(base ? `"${specifier}" from ` : '') + node_url.fileURLToPath(base || specifier),
cause.message
);
error.cause = cause;
throw error
}
result.exists = true;
if (
hasOwnProperty$1.call(parsed, 'name') &&
typeof parsed.name === 'string'
) {
result.name = parsed.name;
}
if (
hasOwnProperty$1.call(parsed, 'main') &&
typeof parsed.main === 'string'
) {
result.main = parsed.main;
}
if (hasOwnProperty$1.call(parsed, 'exports')) {
// @ts-expect-error: assume valid.
result.exports = parsed.exports;
}
if (hasOwnProperty$1.call(parsed, 'imports')) {
// @ts-expect-error: assume valid.
result.imports = parsed.imports;
}
// Ignore unknown types for forwards compatibility
if (
hasOwnProperty$1.call(parsed, 'type') &&
(parsed.type === 'commonjs' || parsed.type === 'module')
) {
result.type = parsed.type;
}
}
cache.set(jsonPath, result);
return result
}
/**
* @param {URL | string} resolved
* @returns {PackageConfig}
*/
function getPackageScopeConfig(resolved) {
// Note: in Node, this is now a native module.
let packageJSONUrl = new URL('package.json', resolved);
while (true) {
const packageJSONPath = packageJSONUrl.pathname;
if (packageJSONPath.endsWith('node_modules/package.json')) {
break
}
const packageConfig = read(node_url.fileURLToPath(packageJSONUrl), {
specifier: resolved
});
if (packageConfig.exists) {
return packageConfig
}
const lastPackageJSONUrl = packageJSONUrl;
packageJSONUrl = new URL('../package.json', packageJSONUrl);
// Terminates at root where ../package.json equals ../../package.json
// (can't just check "/package.json" for Windows support).
if (packageJSONUrl.pathname === lastPackageJSONUrl.pathname) {
break
}
}
const packageJSONPath = node_url.fileURLToPath(packageJSONUrl);
// ^^ Note: in Node, this is now a native module.
return {
pjsonPath: packageJSONPath,
exists: false,
type: 'none'
}
}
/**
* Returns the package type for a given URL.
* @param {URL} url - The URL to get the package type for.
* @returns {PackageType}
*/
function getPackageType(url) {
// To do @anonrig: Write a C++ function that returns only "type".
return getPackageScopeConfig(url).type
}
// Manually “tree shaken” from:
// <https://github.com/nodejs/node/blob/7c3dce0/lib/internal/modules/esm/get_format.js>
// Last checked on: Apr 29, 2024.
const {ERR_UNKNOWN_FILE_EXTENSION} = codes;
const hasOwnProperty = {}.hasOwnProperty;
/** @type {Record<string, string>} */
const extensionFormatMap = {
// @ts-expect-error: hush.
__proto__: null,
'.cjs': 'commonjs',
'.js': 'module',
'.json': 'json',
'.mjs': 'module'
};
/**
* @param {string | null} mime
* @returns {string | null}
*/
function mimeToFormat(mime) {
if (
mime &&
/\s*(text|application)\/javascript\s*(;\s*charset=utf-?8\s*)?/i.test(mime)
)
return 'module'
if (mime === 'application/json') return 'json'
return null
}
/**
* @callback ProtocolHandler
* @param {URL} parsed
* @param {{parentURL: string, source?: Buffer}} context
* @param {boolean} ignoreErrors
* @returns {string | null | void}
*/
/**
* @type {Record<string, ProtocolHandler>}
*/
const protocolHandlers = {
// @ts-expect-error: hush.
__proto__: null,
'data:': getDataProtocolModuleFormat,
'file:': getFileProtocolModuleFormat,
'http:': getHttpProtocolModuleFormat,
'https:': getHttpProtocolModuleFormat,
'node:'() {
return 'builtin'
}
};
/**
* @param {URL} parsed
*/
function getDataProtocolModuleFormat(parsed) {
const {1: mime} = /^([^/]+\/[^;,]+)[^,]*?(;base64)?,/.exec(
parsed.pathname
) || [null, null, null];
return mimeToFormat(mime)
}
/**
* Returns the file extension from a URL.
*
* Should give similar result to
* `require('node:path').extname(require('node:url').fileURLToPath(url))`
* when used with a `file:` URL.
*
* @param {URL} url
* @returns {string}
*/
function extname(url) {
const pathname = url.pathname;
let index = pathname.length;
while (index--) {
const code = pathname.codePointAt(index);
if (code === 47 /* `/` */) {
return ''
}
if (code === 46 /* `.` */) {
return pathname.codePointAt(index - 1) === 47 /* `/` */
? ''
: pathname.slice(index)
}
}
return ''
}
/**
* @type {ProtocolHandler}
*/
function getFileProtocolModuleFormat(url, _context, ignoreErrors) {
const value = extname(url);
if (value === '.js') {
const packageType = getPackageType(url);
if (packageType !== 'none') {
return packageType
}
return 'commonjs'
}
if (value === '') {
const packageType = getPackageType(url);
// Legacy behavior
if (packageType === 'none' || packageType === 'commonjs') {
return 'commonjs'
}
// Note: we dont implement WASM, so we dont need
// `getFormatOfExtensionlessFile` from `formats`.
return 'module'
}
const format = extensionFormatMap[value];
if (format) return format
// Explicit undefined return indicates load hook should rerun format check
if (ignoreErrors) {
return undefined
}
const filepath = node_url.fileURLToPath(url);
throw new ERR_UNKNOWN_FILE_EXTENSION(value, filepath)
}
function getHttpProtocolModuleFormat() {
// To do: HTTPS imports.
}
/**
* @param {URL} url
* @param {{parentURL: string}} context
* @returns {string | null}
*/
function defaultGetFormatWithoutErrors(url, context) {
const protocol = url.protocol;
if (!hasOwnProperty.call(protocolHandlers, protocol)) {
return null
}
return protocolHandlers[protocol](url, context, true) || null
}
// Manually “tree shaken” from:
// <https://github.com/nodejs/node/blob/81a9a97/lib/internal/modules/esm/utils.js>
// Last checked on: Apr 29, 2024.
// In Node itself these values are populated from CLI arguments, before any
// user code runs.
// Here we just define the defaults.
const DEFAULT_CONDITIONS = Object.freeze(['node', 'import']);
const DEFAULT_CONDITIONS_SET$1 = new Set(DEFAULT_CONDITIONS);
/**
* Returns the default conditions for ES module loading, as a Set.
*/
function getDefaultConditionsSet() {
return DEFAULT_CONDITIONS_SET$1
}
/**
* @param {Array<string>} [conditions]
* @returns {Set<string>}
*/
function getConditionsSet(conditions) {
return getDefaultConditionsSet()
}
// Manually “tree shaken” from:
// <https://github.com/nodejs/node/blob/81a9a97/lib/internal/modules/esm/resolve.js>
// Last checked on: Apr 29, 2024.
const RegExpPrototypeSymbolReplace = RegExp.prototype[Symbol.replace];
const {
ERR_INVALID_MODULE_SPECIFIER,
ERR_INVALID_PACKAGE_CONFIG,
ERR_INVALID_PACKAGE_TARGET,
ERR_MODULE_NOT_FOUND,
ERR_PACKAGE_IMPORT_NOT_DEFINED,
ERR_PACKAGE_PATH_NOT_EXPORTED,
ERR_UNSUPPORTED_DIR_IMPORT,
ERR_UNSUPPORTED_RESOLVE_REQUEST
} = codes;
const own = {}.hasOwnProperty;
const invalidSegmentRegEx =
/(^|\\|\/)((\.|%2e)(\.|%2e)?|(n|%6e|%4e)(o|%6f|%4f)(d|%64|%44)(e|%65|%45)(_|%5f)(m|%6d|%4d)(o|%6f|%4f)(d|%64|%44)(u|%75|%55)(l|%6c|%4c)(e|%65|%45)(s|%73|%53))?(\\|\/|$)/i;
const deprecatedInvalidSegmentRegEx =
/(^|\\|\/)((\.|%2e)(\.|%2e)?|(n|%6e|%4e)(o|%6f|%4f)(d|%64|%44)(e|%65|%45)(_|%5f)(m|%6d|%4d)(o|%6f|%4f)(d|%64|%44)(u|%75|%55)(l|%6c|%4c)(e|%65|%45)(s|%73|%53))(\\|\/|$)/i;
const invalidPackageNameRegEx = /^\.|%|\\/;
const patternRegEx = /\*/g;
const encodedSeparatorRegEx = /%2f|%5c/i;
/** @type {Set<string>} */
const emittedPackageWarnings = new Set();
const doubleSlashRegEx = /[/\\]{2}/;
/**
*
* @param {string} target
* @param {string} request
* @param {string} match
* @param {URL} packageJsonUrl
* @param {boolean} internal
* @param {URL} base
* @param {boolean} isTarget
*/
function emitInvalidSegmentDeprecation(
target,
request,
match,
packageJsonUrl,
internal,
base,
isTarget
) {
// @ts-expect-error: apparently it does exist, TS.
if (process__default.noDeprecation) {
return
}
const pjsonPath = node_url.fileURLToPath(packageJsonUrl);
const double = doubleSlashRegEx.exec(isTarget ? target : request) !== null;
process__default.emitWarning(
`Use of deprecated ${
double ? 'double slash' : 'leading or trailing slash matching'
} resolving "${target}" for module ` +
`request "${request}" ${
request === match ? '' : `matched to "${match}" `
}in the "${
internal ? 'imports' : 'exports'
}" field module resolution of the package at ${pjsonPath}${
base ? ` imported from ${node_url.fileURLToPath(base)}` : ''
}.`,
'DeprecationWarning',
'DEP0166'
);
}
/**
* @param {URL} url
* @param {URL} packageJsonUrl
* @param {URL} base
* @param {string} [main]
* @returns {void}
*/
function emitLegacyIndexDeprecation(url, packageJsonUrl, base, main) {
// @ts-expect-error: apparently it does exist, TS.
if (process__default.noDeprecation) {
return
}
const format = defaultGetFormatWithoutErrors(url, {parentURL: base.href});
if (format !== 'module') return
const urlPath = node_url.fileURLToPath(url.href);
const packagePath = node_url.fileURLToPath(new URL('.', packageJsonUrl));
const basePath = node_url.fileURLToPath(base);
if (!main) {
process__default.emitWarning(
`No "main" or "exports" field defined in the package.json for ${packagePath} resolving the main entry point "${urlPath.slice(
packagePath.length
)}", imported from ${basePath}.\nDefault "index" lookups for the main are deprecated for ES modules.`,
'DeprecationWarning',
'DEP0151'
);
} else if (path__default.resolve(packagePath, main) !== urlPath) {
process__default.emitWarning(
`Package ${packagePath} has a "main" field set to "${main}", ` +
`excluding the full filename and extension to the resolved file at "${urlPath.slice(
packagePath.length
)}", imported from ${basePath}.\n Automatic extension resolution of the "main" field is ` +
'deprecated for ES modules.',
'DeprecationWarning',
'DEP0151'
);
}
}
/**
* @param {string} path
* @returns {Stats | undefined}
*/
function tryStatSync(path) {
// Note: from Node 15 onwards we can use `throwIfNoEntry: false` instead.
try {
return fs.statSync(path)
} catch {
// Note: in Node code this returns `new Stats`,
// but in Node 22 thats marked as a deprecated internal API.
// Which, well, we kinda are, but still to prevent that warning,
// just yield `undefined`.
}
}
/**
* Legacy CommonJS main resolution:
* 1. let M = pkg_url + (json main field)
* 2. TRY(M, M.js, M.json, M.node)
* 3. TRY(M/index.js, M/index.json, M/index.node)
* 4. TRY(pkg_url/index.js, pkg_url/index.json, pkg_url/index.node)
* 5. NOT_FOUND
*
* @param {URL} url
* @returns {boolean}
*/
function fileExists(url) {
const stats = fs.statSync(url, {throwIfNoEntry: false});
const isFile = stats ? stats.isFile() : undefined;
return isFile === null || isFile === undefined ? false : isFile
}
/**
* @param {URL} packageJsonUrl
* @param {PackageConfig} packageConfig
* @param {URL} base
* @returns {URL}
*/
function legacyMainResolve(packageJsonUrl, packageConfig, base) {
/** @type {URL | undefined} */
let guess;
if (packageConfig.main !== undefined) {
guess = new URL(packageConfig.main, packageJsonUrl);
// Note: fs check redundances will be handled by Descriptor cache here.
if (fileExists(guess)) return guess
const tries = [
`./${packageConfig.main}.js`,
`./${packageConfig.main}.json`,
`./${packageConfig.main}.node`,
`./${packageConfig.main}/index.js`,
`./${packageConfig.main}/index.json`,
`./${packageConfig.main}/index.node`
];
let i = -1;
while (++i < tries.length) {
guess = new URL(tries[i], packageJsonUrl);
if (fileExists(guess)) break
guess = undefined;
}
if (guess) {
emitLegacyIndexDeprecation(
guess,
packageJsonUrl,
base,
packageConfig.main
);
return guess
}
// Fallthrough.
}
const tries = ['./index.js', './index.json', './index.node'];
let i = -1;
while (++i < tries.length) {
guess = new URL(tries[i], packageJsonUrl);
if (fileExists(guess)) break
guess = undefined;
}
if (guess) {
emitLegacyIndexDeprecation(guess, packageJsonUrl, base, packageConfig.main);
return guess
}
// Not found.
throw new ERR_MODULE_NOT_FOUND(
node_url.fileURLToPath(new URL('.', packageJsonUrl)),
node_url.fileURLToPath(base)
)
}
/**
* @param {URL} resolved
* @param {URL} base
* @param {boolean} [preserveSymlinks]
* @returns {URL}
*/
function finalizeResolution(resolved, base, preserveSymlinks) {
if (encodedSeparatorRegEx.exec(resolved.pathname) !== null) {
throw new ERR_INVALID_MODULE_SPECIFIER(
resolved.pathname,
'must not include encoded "/" or "\\" characters',
node_url.fileURLToPath(base)
)
}
/** @type {string} */
let filePath;
try {
filePath = node_url.fileURLToPath(resolved);
} catch (error) {
const cause = /** @type {ErrnoException} */ (error);
Object.defineProperty(cause, 'input', {value: String(resolved)});
Object.defineProperty(cause, 'module', {value: String(base)});
throw cause
}
const stats = tryStatSync(
filePath.endsWith('/') ? filePath.slice(-1) : filePath
);
if (stats && stats.isDirectory()) {
const error = new ERR_UNSUPPORTED_DIR_IMPORT(filePath, node_url.fileURLToPath(base));
// @ts-expect-error Add this for `import.meta.resolve`.
error.url = String(resolved);
throw error
}
if (!stats || !stats.isFile()) {
const error = new ERR_MODULE_NOT_FOUND(
filePath || resolved.pathname,
base && node_url.fileURLToPath(base),
true
);
// @ts-expect-error Add this for `import.meta.resolve`.
error.url = String(resolved);
throw error
}
{
const real = fs.realpathSync(filePath);
const {search, hash} = resolved;
resolved = node_url.pathToFileURL(real + (filePath.endsWith(path__default.sep) ? '/' : ''));
resolved.search = search;
resolved.hash = hash;
}
return resolved
}
/**
* @param {string} specifier
* @param {URL | undefined} packageJsonUrl
* @param {URL} base
* @returns {Error}
*/
function importNotDefined(specifier, packageJsonUrl, base) {
return new ERR_PACKAGE_IMPORT_NOT_DEFINED(
specifier,
packageJsonUrl && node_url.fileURLToPath(new URL('.', packageJsonUrl)),
node_url.fileURLToPath(base)
)
}
/**
* @param {string} subpath
* @param {URL} packageJsonUrl
* @param {URL} base
* @returns {Error}
*/
function exportsNotFound(subpath, packageJsonUrl, base) {
return new ERR_PACKAGE_PATH_NOT_EXPORTED(
node_url.fileURLToPath(new URL('.', packageJsonUrl)),
subpath,
base && node_url.fileURLToPath(base)
)
}
/**
* @param {string} request
* @param {string} match
* @param {URL} packageJsonUrl
* @param {boolean} internal
* @param {URL} [base]
* @returns {never}
*/
function throwInvalidSubpath(request, match, packageJsonUrl, internal, base) {
const reason = `request is not a valid match in pattern "${match}" for the "${
internal ? 'imports' : 'exports'
}" resolution of ${node_url.fileURLToPath(packageJsonUrl)}`;
throw new ERR_INVALID_MODULE_SPECIFIER(
request,
reason,
base && node_url.fileURLToPath(base)
)
}
/**
* @param {string} subpath
* @param {unknown} target
* @param {URL} packageJsonUrl
* @param {boolean} internal
* @param {URL} [base]
* @returns {Error}
*/
function invalidPackageTarget(subpath, target, packageJsonUrl, internal, base) {
target =
typeof target === 'object' && target !== null
? JSON.stringify(target, null, '')
: `${target}`;
return new ERR_INVALID_PACKAGE_TARGET(
node_url.fileURLToPath(new URL('.', packageJsonUrl)),
subpath,
target,
internal,
base && node_url.fileURLToPath(base)
)
}
/**
* @param {string} target
* @param {string} subpath
* @param {string} match
* @param {URL} packageJsonUrl
* @param {URL} base
* @param {boolean} pattern
* @param {boolean} internal
* @param {boolean} isPathMap
* @param {Set<string> | undefined} conditions
* @returns {URL}
*/
function resolvePackageTargetString(
target,
subpath,
match,
packageJsonUrl,
base,
pattern,
internal,
isPathMap,
conditions
) {
if (subpath !== '' && !pattern && target[target.length - 1] !== '/')
throw invalidPackageTarget(match, target, packageJsonUrl, internal, base)
if (!target.startsWith('./')) {
if (internal && !target.startsWith('../') && !target.startsWith('/')) {
let isURL = false;
try {
new URL(target);
isURL = true;
} catch {
// Continue regardless of error.
}
if (!isURL) {
const exportTarget = pattern
? RegExpPrototypeSymbolReplace.call(
patternRegEx,
target,
() => subpath
)
: target + subpath;
return packageResolve(exportTarget, packageJsonUrl, conditions)
}
}
throw invalidPackageTarget(match, target, packageJsonUrl, internal, base)
}
if (invalidSegmentRegEx.exec(target.slice(2)) !== null) {
if (deprecatedInvalidSegmentRegEx.exec(target.slice(2)) === null) {
if (!isPathMap) {
const request = pattern
? match.replace('*', () => subpath)
: match + subpath;
const resolvedTarget = pattern
? RegExpPrototypeSymbolReplace.call(
patternRegEx,
target,
() => subpath
)
: target;
emitInvalidSegmentDeprecation(
resolvedTarget,
request,
match,
packageJsonUrl,
internal,
base,
true
);
}
} else {
throw invalidPackageTarget(match, target, packageJsonUrl, internal, base)
}
}
const resolved = new URL(target, packageJsonUrl);
const resolvedPath = resolved.pathname;
const packagePath = new URL('.', packageJsonUrl).pathname;
if (!resolvedPath.startsWith(packagePath))
throw invalidPackageTarget(match, target, packageJsonUrl, internal, base)
if (subpath === '') return resolved
if (invalidSegmentRegEx.exec(subpath) !== null) {
const request = pattern
? match.replace('*', () => subpath)
: match + subpath;
if (deprecatedInvalidSegmentRegEx.exec(subpath) === null) {
if (!isPathMap) {
const resolvedTarget = pattern
? RegExpPrototypeSymbolReplace.call(
patternRegEx,
target,
() => subpath
)
: target;
emitInvalidSegmentDeprecation(
resolvedTarget,
request,
match,
packageJsonUrl,
internal,
base,
false
);
}
} else {
throwInvalidSubpath(request, match, packageJsonUrl, internal, base);
}
}
if (pattern) {
return new URL(
RegExpPrototypeSymbolReplace.call(
patternRegEx,
resolved.href,
() => subpath
)
)
}
return new URL(subpath, resolved)
}
/**
* @param {string} key
* @returns {boolean}
*/
function isArrayIndex(key) {
const keyNumber = Number(key);
if (`${keyNumber}` !== key) return false
return keyNumber >= 0 && keyNumber < 0xff_ff_ff_ff
}
/**
* @param {URL} packageJsonUrl
* @param {unknown} target
* @param {string} subpath
* @param {string} packageSubpath
* @param {URL} base
* @param {boolean} pattern
* @param {boolean} internal
* @param {boolean} isPathMap
* @param {Set<string> | undefined} conditions
* @returns {URL | null}
*/
function resolvePackageTarget(
packageJsonUrl,
target,
subpath,
packageSubpath,
base,
pattern,
internal,
isPathMap,
conditions
) {
if (typeof target === 'string') {
return resolvePackageTargetString(
target,
subpath,
packageSubpath,
packageJsonUrl,
base,
pattern,
internal,
isPathMap,
conditions
)
}
if (Array.isArray(target)) {
/** @type {Array<unknown>} */
const targetList = target;
if (targetList.length === 0) return null
/** @type {ErrnoException | null | undefined} */
let lastException;
let i = -1;
while (++i < targetList.length) {
const targetItem = targetList[i];
/** @type {URL | null} */
let resolveResult;
try {
resolveResult = resolvePackageTarget(
packageJsonUrl,
targetItem,
subpath,
packageSubpath,
base,
pattern,
internal,
isPathMap,
conditions
);
} catch (error) {
const exception = /** @type {ErrnoException} */ (error);
lastException = exception;
if (exception.code === 'ERR_INVALID_PACKAGE_TARGET') continue
throw error
}
if (resolveResult === undefined) continue
if (resolveResult === null) {
lastException = null;
continue
}
return resolveResult
}
if (lastException === undefined || lastException === null) {
return null
}
throw lastException
}
if (typeof target === 'object' && target !== null) {
const keys = Object.getOwnPropertyNames(target);
let i = -1;
while (++i < keys.length) {
const key = keys[i];
if (isArrayIndex(key)) {
throw new ERR_INVALID_PACKAGE_CONFIG(
node_url.fileURLToPath(packageJsonUrl),
base,
'"exports" cannot contain numeric property keys.'
)
}
}
i = -1;
while (++i < keys.length) {
const key = keys[i];
if (key === 'default' || (conditions && conditions.has(key))) {
// @ts-expect-error: indexable.
const conditionalTarget = /** @type {unknown} */ (target[key]);
const resolveResult = resolvePackageTarget(
packageJsonUrl,
conditionalTarget,
subpath,
packageSubpath,
base,
pattern,
internal,
isPathMap,
conditions
);
if (resolveResult === undefined) continue
return resolveResult
}
}
return null
}
if (target === null) {
return null
}
throw invalidPackageTarget(
packageSubpath,
target,
packageJsonUrl,
internal,
base
)
}
/**
* @param {unknown} exports
* @param {URL} packageJsonUrl
* @param {URL} base
* @returns {boolean}
*/
function isConditionalExportsMainSugar(exports$1, packageJsonUrl, base) {
if (typeof exports$1 === 'string' || Array.isArray(exports$1)) return true
if (typeof exports$1 !== 'object' || exports$1 === null) return false
const keys = Object.getOwnPropertyNames(exports$1);
let isConditionalSugar = false;
let i = 0;
let keyIndex = -1;
while (++keyIndex < keys.length) {
const key = keys[keyIndex];
const currentIsConditionalSugar = key === '' || key[0] !== '.';
if (i++ === 0) {
isConditionalSugar = currentIsConditionalSugar;
} else if (isConditionalSugar !== currentIsConditionalSugar) {
throw new ERR_INVALID_PACKAGE_CONFIG(
node_url.fileURLToPath(packageJsonUrl),
base,
'"exports" cannot contain some keys starting with \'.\' and some not.' +
' The exports object must either be an object of package subpath keys' +
' or an object of main entry condition name keys only.'
)
}
}
return isConditionalSugar
}
/**
* @param {string} match
* @param {URL} pjsonUrl
* @param {URL} base
*/
function emitTrailingSlashPatternDeprecation(match, pjsonUrl, base) {
// @ts-expect-error: apparently it does exist, TS.
if (process__default.noDeprecation) {
return
}
const pjsonPath = node_url.fileURLToPath(pjsonUrl);
if (emittedPackageWarnings.has(pjsonPath + '|' + match)) return
emittedPackageWarnings.add(pjsonPath + '|' + match);
process__default.emitWarning(
`Use of deprecated trailing slash pattern mapping "${match}" in the ` +
`"exports" field module resolution of the package at ${pjsonPath}${
base ? ` imported from ${node_url.fileURLToPath(base)}` : ''
}. Mapping specifiers ending in "/" is no longer supported.`,
'DeprecationWarning',
'DEP0155'
);
}
/**
* @param {URL} packageJsonUrl
* @param {string} packageSubpath
* @param {Record<string, unknown>} packageConfig
* @param {URL} base
* @param {Set<string> | undefined} conditions
* @returns {URL}
*/
function packageExportsResolve(
packageJsonUrl,
packageSubpath,
packageConfig,
base,
conditions
) {
let exports$1 = packageConfig.exports;
if (isConditionalExportsMainSugar(exports$1, packageJsonUrl, base)) {
exports$1 = {'.': exports$1};
}
if (
own.call(exports$1, packageSubpath) &&
!packageSubpath.includes('*') &&
!packageSubpath.endsWith('/')
) {
// @ts-expect-error: indexable.
const target = exports$1[packageSubpath];
const resolveResult = resolvePackageTarget(
packageJsonUrl,
target,
'',
packageSubpath,
base,
false,
false,
false,
conditions
);
if (resolveResult === null || resolveResult === undefined) {
throw exportsNotFound(packageSubpath, packageJsonUrl, base)
}
return resolveResult
}
let bestMatch = '';
let bestMatchSubpath = '';
const keys = Object.getOwnPropertyNames(exports$1);
let i = -1;
while (++i < keys.length) {
const key = keys[i];
const patternIndex = key.indexOf('*');
if (
patternIndex !== -1 &&
packageSubpath.startsWith(key.slice(0, patternIndex))
) {
// When this reaches EOL, this can throw at the top of the whole function:
//
// if (StringPrototypeEndsWith(packageSubpath, '/'))
// throwInvalidSubpath(packageSubpath)
//
// To match "imports" and the spec.
if (packageSubpath.endsWith('/')) {
emitTrailingSlashPatternDeprecation(
packageSubpath,
packageJsonUrl,
base
);
}
const patternTrailer = key.slice(patternIndex + 1);
if (
packageSubpath.length >= key.length &&
packageSubpath.endsWith(patternTrailer) &&
patternKeyCompare(bestMatch, key) === 1 &&
key.lastIndexOf('*') === patternIndex
) {
bestMatch = key;
bestMatchSubpath = packageSubpath.slice(
patternIndex,
packageSubpath.length - patternTrailer.length
);
}
}
}
if (bestMatch) {
// @ts-expect-error: indexable.
const target = /** @type {unknown} */ (exports$1[bestMatch]);
const resolveResult = resolvePackageTarget(
packageJsonUrl,
target,
bestMatchSubpath,
bestMatch,
base,
true,
false,
packageSubpath.endsWith('/'),
conditions
);
if (resolveResult === null || resolveResult === undefined) {
throw exportsNotFound(packageSubpath, packageJsonUrl, base)
}
return resolveResult
}
throw exportsNotFound(packageSubpath, packageJsonUrl, base)
}
/**
* @param {string} a
* @param {string} b
*/
function patternKeyCompare(a, b) {
const aPatternIndex = a.indexOf('*');
const bPatternIndex = b.indexOf('*');
const baseLengthA = aPatternIndex === -1 ? a.length : aPatternIndex + 1;
const baseLengthB = bPatternIndex === -1 ? b.length : bPatternIndex + 1;
if (baseLengthA > baseLengthB) return -1
if (baseLengthB > baseLengthA) return 1
if (aPatternIndex === -1) return 1
if (bPatternIndex === -1) return -1
if (a.length > b.length) return -1
if (b.length > a.length) return 1
return 0
}
/**
* @param {string} name
* @param {URL} base
* @param {Set<string>} [conditions]
* @returns {URL}
*/
function packageImportsResolve(name, base, conditions) {
if (name === '#' || name.startsWith('#/') || name.endsWith('/')) {
const reason = 'is not a valid internal imports specifier name';
throw new ERR_INVALID_MODULE_SPECIFIER(name, reason, node_url.fileURLToPath(base))
}
/** @type {URL | undefined} */
let packageJsonUrl;
const packageConfig = getPackageScopeConfig(base);
if (packageConfig.exists) {
packageJsonUrl = node_url.pathToFileURL(packageConfig.pjsonPath);
const imports = packageConfig.imports;
if (imports) {
if (own.call(imports, name) && !name.includes('*')) {
const resolveResult = resolvePackageTarget(
packageJsonUrl,
imports[name],
'',
name,
base,
false,
true,
false,
conditions
);
if (resolveResult !== null && resolveResult !== undefined) {
return resolveResult
}
} else {
let bestMatch = '';
let bestMatchSubpath = '';
const keys = Object.getOwnPropertyNames(imports);
let i = -1;
while (++i < keys.length) {
const key = keys[i];
const patternIndex = key.indexOf('*');
if (patternIndex !== -1 && name.startsWith(key.slice(0, -1))) {
const patternTrailer = key.slice(patternIndex + 1);
if (
name.length >= key.length &&
name.endsWith(patternTrailer) &&
patternKeyCompare(bestMatch, key) === 1 &&
key.lastIndexOf('*') === patternIndex
) {
bestMatch = key;
bestMatchSubpath = name.slice(
patternIndex,
name.length - patternTrailer.length
);
}
}
}
if (bestMatch) {
const target = imports[bestMatch];
const resolveResult = resolvePackageTarget(
packageJsonUrl,
target,
bestMatchSubpath,
bestMatch,
base,
true,
true,
false,
conditions
);
if (resolveResult !== null && resolveResult !== undefined) {
return resolveResult
}
}
}
}
}
throw importNotDefined(name, packageJsonUrl, base)
}
/**
* @param {string} specifier
* @param {URL} base
*/
function parsePackageName(specifier, base) {
let separatorIndex = specifier.indexOf('/');
let validPackageName = true;
let isScoped = false;
if (specifier[0] === '@') {
isScoped = true;
if (separatorIndex === -1 || specifier.length === 0) {
validPackageName = false;
} else {
separatorIndex = specifier.indexOf('/', separatorIndex + 1);
}
}
const packageName =
separatorIndex === -1 ? specifier : specifier.slice(0, separatorIndex);
// Package name cannot have leading . and cannot have percent-encoding or
// \\ separators.
if (invalidPackageNameRegEx.exec(packageName) !== null) {
validPackageName = false;
}
if (!validPackageName) {
throw new ERR_INVALID_MODULE_SPECIFIER(
specifier,
'is not a valid package name',
node_url.fileURLToPath(base)
)
}
const packageSubpath =
'.' + (separatorIndex === -1 ? '' : specifier.slice(separatorIndex));
return {packageName, packageSubpath, isScoped}
}
/**
* @param {string} specifier
* @param {URL} base
* @param {Set<string> | undefined} conditions
* @returns {URL}
*/
function packageResolve(specifier, base, conditions) {
if (node_module.builtinModules.includes(specifier)) {
return new URL('node:' + specifier)
}
const {packageName, packageSubpath, isScoped} = parsePackageName(
specifier,
base
);
// ResolveSelf
const packageConfig = getPackageScopeConfig(base);
// Cant test.
/* c8 ignore next 16 */
if (packageConfig.exists) {
const packageJsonUrl = node_url.pathToFileURL(packageConfig.pjsonPath);
if (
packageConfig.name === packageName &&
packageConfig.exports !== undefined &&
packageConfig.exports !== null
) {
return packageExportsResolve(
packageJsonUrl,
packageSubpath,
packageConfig,
base,
conditions
)
}
}
let packageJsonUrl = new URL(
'./node_modules/' + packageName + '/package.json',
base
);
let packageJsonPath = node_url.fileURLToPath(packageJsonUrl);
/** @type {string} */
let lastPath;
do {
const stat = tryStatSync(packageJsonPath.slice(0, -13));
if (!stat || !stat.isDirectory()) {
lastPath = packageJsonPath;
packageJsonUrl = new URL(
(isScoped ? '../../../../node_modules/' : '../../../node_modules/') +
packageName +
'/package.json',
packageJsonUrl
);
packageJsonPath = node_url.fileURLToPath(packageJsonUrl);
continue
}
// Package match.
const packageConfig = read(packageJsonPath, {base, specifier});
if (packageConfig.exports !== undefined && packageConfig.exports !== null) {
return packageExportsResolve(
packageJsonUrl,
packageSubpath,
packageConfig,
base,
conditions
)
}
if (packageSubpath === '.') {
return legacyMainResolve(packageJsonUrl, packageConfig, base)
}
return new URL(packageSubpath, packageJsonUrl)
// Cross-platform root check.
} while (packageJsonPath.length !== lastPath.length)
throw new ERR_MODULE_NOT_FOUND(packageName, node_url.fileURLToPath(base), false)
}
/**
* @param {string} specifier
* @returns {boolean}
*/
function isRelativeSpecifier(specifier) {
if (specifier[0] === '.') {
if (specifier.length === 1 || specifier[1] === '/') return true
if (
specifier[1] === '.' &&
(specifier.length === 2 || specifier[2] === '/')
) {
return true
}
}
return false
}
/**
* @param {string} specifier
* @returns {boolean}
*/
function shouldBeTreatedAsRelativeOrAbsolutePath(specifier) {
if (specifier === '') return false
if (specifier[0] === '/') return true
return isRelativeSpecifier(specifier)
}
/**
* The “Resolver Algorithm Specification” as detailed in the Node docs (which is
* sync and slightly lower-level than `resolve`).
*
* @param {string} specifier
* `/example.js`, `./example.js`, `../example.js`, `some-package`, `fs`, etc.
* @param {URL} base
* Full URL (to a file) that `specifier` is resolved relative from.
* @param {Set<string>} [conditions]
* Conditions.
* @param {boolean} [preserveSymlinks]
* Keep symlinks instead of resolving them.
* @returns {URL}
* A URL object to the found thing.
*/
function moduleResolve(specifier, base, conditions, preserveSymlinks) {
// Note: The Node code supports `base` as a string (in this internal API) too,
// we dont.
if (conditions === undefined) {
conditions = getConditionsSet();
}
const protocol = base.protocol;
const isData = protocol === 'data:';
const isRemote = isData || protocol === 'http:' || protocol === 'https:';
// Order swapped from spec for minor perf gain.
// Ok since relative URLs cannot parse as URLs.
/** @type {URL | undefined} */
let resolved;
if (shouldBeTreatedAsRelativeOrAbsolutePath(specifier)) {
try {
resolved = new URL(specifier, base);
} catch (error_) {
const error = new ERR_UNSUPPORTED_RESOLVE_REQUEST(specifier, base);
error.cause = error_;
throw error
}
} else if (protocol === 'file:' && specifier[0] === '#') {
resolved = packageImportsResolve(specifier, base, conditions);
} else {
try {
resolved = new URL(specifier);
} catch (error_) {
// Note: actual code uses `canBeRequiredWithoutScheme`.
if (isRemote && !node_module.builtinModules.includes(specifier)) {
const error = new ERR_UNSUPPORTED_RESOLVE_REQUEST(specifier, base);
error.cause = error_;
throw error
}
resolved = packageResolve(specifier, base, conditions);
}
}
assert__default.ok(resolved !== undefined, 'expected to be defined');
if (resolved.protocol !== 'file:') {
return resolved
}
return finalizeResolution(resolved, base)
}
function fileURLToPath(id) {
if (typeof id === "string" && !id.startsWith("file://")) {
return normalizeSlash(id);
}
return normalizeSlash(node_url.fileURLToPath(id));
}
function pathToFileURL(id) {
return node_url.pathToFileURL(fileURLToPath(id)).toString();
}
const INVALID_CHAR_RE = /[\u0000-\u001F"#$&*+,/:;<=>?@[\]^`{|}\u007F]+/g;
function sanitizeURIComponent(name = "", replacement = "_") {
return name.replace(INVALID_CHAR_RE, replacement).replace(/%../g, replacement);
}
function sanitizeFilePath(filePath = "") {
return filePath.replace(/\?.*$/, "").split(/[/\\]/g).map((p) => sanitizeURIComponent(p)).join("/").replace(/^([A-Za-z])_\//, "$1:/");
}
function normalizeid(id) {
if (typeof id !== "string") {
id = id.toString();
}
if (/(?:node|data|http|https|file):/.test(id)) {
return id;
}
if (BUILTIN_MODULES.has(id)) {
return "node:" + id;
}
return "file://" + encodeURI(normalizeSlash(id));
}
async function loadURL(url) {
const code = await fs.promises.readFile(fileURLToPath(url), "utf8");
return code;
}
function toDataURL(code) {
const base64 = Buffer.from(code).toString("base64");
return `data:text/javascript;base64,${base64}`;
}
function isNodeBuiltin(id = "") {
id = id.replace(/^node:/, "").split("/", 1)[0];
return BUILTIN_MODULES.has(id);
}
const ProtocolRegex = /^(?<proto>.{2,}?):.+$/;
function getProtocol(id) {
const proto = id.match(ProtocolRegex);
return proto ? proto.groups?.proto : void 0;
}
const DEFAULT_CONDITIONS_SET = /* @__PURE__ */ new Set(["node", "import"]);
const DEFAULT_EXTENSIONS = [".mjs", ".cjs", ".js", ".json"];
const NOT_FOUND_ERRORS = /* @__PURE__ */ new Set([
"ERR_MODULE_NOT_FOUND",
"ERR_UNSUPPORTED_DIR_IMPORT",
"MODULE_NOT_FOUND",
"ERR_PACKAGE_PATH_NOT_EXPORTED"
]);
function _tryModuleResolve(id, url, conditions) {
try {
return moduleResolve(id, url, conditions);
} catch (error) {
if (!NOT_FOUND_ERRORS.has(error?.code)) {
throw error;
}
}
}
function _resolve(id, options = {}) {
if (typeof id !== "string") {
if (id instanceof URL) {
id = fileURLToPath(id);
} else {
throw new TypeError("input must be a `string` or `URL`");
}
}
if (/(?:node|data|http|https):/.test(id)) {
return id;
}
if (BUILTIN_MODULES.has(id)) {
return "node:" + id;
}
if (id.startsWith("file://")) {
id = fileURLToPath(id);
}
if (pathe.isAbsolute(id)) {
try {
const stat = fs.statSync(id);
if (stat.isFile()) {
return pathToFileURL(id);
}
} catch (error) {
if (error?.code !== "ENOENT") {
throw error;
}
}
}
const conditionsSet = options.conditions ? new Set(options.conditions) : DEFAULT_CONDITIONS_SET;
const _urls = (Array.isArray(options.url) ? options.url : [options.url]).filter(Boolean).map((url) => new URL(normalizeid(url.toString())));
if (_urls.length === 0) {
_urls.push(new URL(pathToFileURL(process.cwd())));
}
const urls = [..._urls];
for (const url of _urls) {
if (url.protocol === "file:") {
urls.push(
new URL("./", url),
// If url is directory
new URL(ufo.joinURL(url.pathname, "_index.js"), url),
// TODO: Remove in next major version?
new URL("node_modules", url)
);
}
}
let resolved;
for (const url of urls) {
resolved = _tryModuleResolve(id, url, conditionsSet);
if (resolved) {
break;
}
for (const prefix of ["", "/index"]) {
for (const extension of options.extensions || DEFAULT_EXTENSIONS) {
resolved = _tryModuleResolve(
ufo.joinURL(id, prefix) + extension,
url,
conditionsSet
);
if (resolved) {
break;
}
}
if (resolved) {
break;
}
}
if (resolved) {
break;
}
}
if (!resolved) {
const error = new Error(
`Cannot find module ${id} imported from ${urls.join(", ")}`
);
error.code = "ERR_MODULE_NOT_FOUND";
throw error;
}
return pathToFileURL(resolved);
}
function resolveSync(id, options) {
return _resolve(id, options);
}
function resolve(id, options) {
try {
return Promise.resolve(resolveSync(id, options));
} catch (error) {
return Promise.reject(error);
}
}
function resolvePathSync(id, options) {
return fileURLToPath(resolveSync(id, options));
}
function resolvePath(id, options) {
try {
return Promise.resolve(resolvePathSync(id, options));
} catch (error) {
return Promise.reject(error);
}
}
function createResolve(defaults) {
return (id, url) => {
return resolve(id, { url, ...defaults });
};
}
const NODE_MODULES_RE = /^(.+\/node_modules\/)([^/@]+|@[^/]+\/[^/]+)(\/?.*?)?$/;
function parseNodeModulePath(path) {
if (!path) {
return {};
}
path = pathe.normalize(fileURLToPath(path));
const match = NODE_MODULES_RE.exec(path);
if (!match) {
return {};
}
const [, dir, name, subpath] = match;
return {
dir,
name,
subpath: subpath ? `.${subpath}` : void 0
};
}
async function lookupNodeModuleSubpath(path) {
path = pathe.normalize(fileURLToPath(path));
const { name, subpath } = parseNodeModulePath(path);
if (!name || !subpath) {
return subpath;
}
const { exports: exports$1 } = await pkgTypes.readPackageJSON(path).catch(() => {
}) || {};
if (exports$1) {
const resolvedSubpath = _findSubpath(subpath, exports$1);
if (resolvedSubpath) {
return resolvedSubpath;
}
}
return subpath;
}
function _findSubpath(subpath, exports$1) {
if (typeof exports$1 === "string") {
exports$1 = { ".": exports$1 };
}
if (!subpath.startsWith(".")) {
subpath = subpath.startsWith("/") ? `.${subpath}` : `./${subpath}`;
}
if (subpath in (exports$1 || {})) {
return subpath;
}
return _flattenExports(exports$1).find((p) => p.fsPath === subpath)?.subpath;
}
function _flattenExports(exports$1 = {}, parentSubpath = "./") {
return Object.entries(exports$1).flatMap(([key, value]) => {
const [subpath, condition] = key.startsWith(".") ? [key.slice(1), void 0] : ["", key];
const _subPath = ufo.joinURL(parentSubpath, subpath);
if (typeof value === "string") {
return [{ subpath: _subPath, fsPath: value, condition }];
} else {
return _flattenExports(value, _subPath);
}
});
}
const ESM_STATIC_IMPORT_RE = /(?<=\s|^|;|\})import\s*(?:[\s"']*(?<imports>[\p{L}\p{M}\w\t\n\r $*,/{}@.]+)from\s*)?["']\s*(?<specifier>(?<="\s*)[^"]*[^\s"](?=\s*")|(?<='\s*)[^']*[^\s'](?=\s*'))\s*["'][\s;]*/gmu;
const DYNAMIC_IMPORT_RE = /import\s*\((?<expression>(?:[^()]+|\((?:[^()]+|\([^()]*\))*\))*)\)/gm;
const IMPORT_NAMED_TYPE_RE = /(?<=\s|^|;|})import\s*type\s+(?:[\s"']*(?<imports>[\w\t\n\r $*,/{}]+)from\s*)?["']\s*(?<specifier>(?<="\s*)[^"]*[^\s"](?=\s*")|(?<='\s*)[^']*[^\s'](?=\s*'))\s*["'][\s;]*/gm;
const EXPORT_DECAL_RE = /\bexport\s+(?<declaration>(?:async function\s*\*?|function\s*\*?|let|const enum|const|enum|var|class))\s+\*?(?<name>[\w$]+)(?<extraNames>.*,\s*[\s\w:[\]{}]*[\w$\]}]+)*/g;
const EXPORT_DECAL_TYPE_RE = /\bexport\s+(?<declaration>(?:interface|type|declare (?:async function|function|let|const enum|const|enum|var|class)))\s+(?<name>[\w$]+)/g;
const EXPORT_NAMED_RE = /\bexport\s*{(?<exports>[^}]+?)[\s,]*}(?:\s*from\s*["']\s*(?<specifier>(?<="\s*)[^"]*[^\s"](?=\s*")|(?<='\s*)[^']*[^\s'](?=\s*'))\s*["'][^\n;]*)?/g;
const EXPORT_NAMED_TYPE_RE = /\bexport\s+type\s*{(?<exports>[^}]+?)[\s,]*}(?:\s*from\s*["']\s*(?<specifier>(?<="\s*)[^"]*[^\s"](?=\s*")|(?<='\s*)[^']*[^\s'](?=\s*'))\s*["'][^\n;]*)?/g;
const EXPORT_NAMED_DESTRUCT = /\bexport\s+(?:let|var|const)\s+(?:{(?<exports1>[^}]+?)[\s,]*}|\[(?<exports2>[^\]]+?)[\s,]*])\s+=/gm;
const EXPORT_STAR_RE = /\bexport\s*\*(?:\s*as\s+(?<name>[\w$]+)\s+)?\s*(?:\s*from\s*["']\s*(?<specifier>(?<="\s*)[^"]*[^\s"](?=\s*")|(?<='\s*)[^']*[^\s'](?=\s*'))\s*["'][^\n;]*)?/g;
const EXPORT_DEFAULT_RE = /\bexport\s+default\s+(async function|function|class|true|false|\W|\d)|\bexport\s+default\s+(?<defaultName>.*)/g;
const EXPORT_DEFAULT_CLASS_RE = /\bexport\s+default\s+(?<declaration>class)\s+(?<name>[\w$]+)/g;
const TYPE_RE = /^\s*?type\s/;
function findStaticImports(code) {
return _filterStatement(
_tryGetLocations(code, "import"),
matchAll(ESM_STATIC_IMPORT_RE, code, { type: "static" })
);
}
function findDynamicImports(code) {
return _filterStatement(
_tryGetLocations(code, "import"),
matchAll(DYNAMIC_IMPORT_RE, code, { type: "dynamic" })
);
}
function findTypeImports(code) {
return [
...matchAll(IMPORT_NAMED_TYPE_RE, code, { type: "type" }),
...matchAll(ESM_STATIC_IMPORT_RE, code, { type: "static" }).filter(
(match) => /[^A-Za-z]type\s/.test(match.imports)
)
];
}
function parseStaticImport(matched) {
const cleanedImports = clearImports(matched.imports);
const namedImports = {};
const _matches = cleanedImports.match(/{([^}]*)}/)?.[1]?.split(",") || [];
for (const namedImport of _matches) {
const _match = namedImport.match(/^\s*(\S*) as (\S*)\s*$/);
const source = _match?.[1] || namedImport.trim();
const importName = _match?.[2] || source;
if (source && !TYPE_RE.test(source)) {
namedImports[source] = importName;
}
}
const { namespacedImport, defaultImport } = getImportNames(cleanedImports);
return {
...matched,
defaultImport,
namespacedImport,
namedImports
};
}
function parseTypeImport(matched) {
if (matched.type === "type") {
return parseStaticImport(matched);
}
const cleanedImports = clearImports(matched.imports);
const namedImports = {};
const _matches = cleanedImports.match(/{([^}]*)}/)?.[1]?.split(",") || [];
for (const namedImport of _matches) {
const _match = /\s+as\s+/.test(namedImport) ? namedImport.match(/^\s*type\s+(\S*) as (\S*)\s*$/) : namedImport.match(/^\s*type\s+(\S*)\s*$/);
const source = _match?.[1] || namedImport.trim();
const importName = _match?.[2] || source;
if (source && TYPE_RE.test(namedImport)) {
namedImports[source] = importName;
}
}
const { namespacedImport, defaultImport } = getImportNames(cleanedImports);
return {
...matched,
defaultImport,
namespacedImport,
namedImports
};
}
function _extractExtraNames(extraNamesStr) {
const names = [];
let depth = 0;
let angleDepth = 0;
let inString = false;
let inTypeAnnotation = false;
for (let i = 0; i < extraNamesStr.length; i++) {
const char = extraNamesStr[i];
if (inString) {
if (char === inString) {
let backslashCount = 0;
for (let j = i - 1; j >= 0 && extraNamesStr[j] === "\\"; j--) {
backslashCount++;
}
if (backslashCount % 2 === 0) {
inString = false;
}
}
continue;
}
if (char === '"' || char === "'" || char === "`") {
inString = char;
continue;
}
if (char === ":" && depth === 0 && angleDepth === 0) {
inTypeAnnotation = true;
continue;
}
if (char === "=" && extraNamesStr[i + 1] !== ">" && depth === 0 && angleDepth === 0) {
inTypeAnnotation = false;
}
if (inTypeAnnotation && char === "<") {
angleDepth++;
continue;
}
if (!inTypeAnnotation && char === "<" && depth === 0 && i > 0 && _isIdentifierBeforeAngleBracket(extraNamesStr, i)) {
angleDepth++;
continue;
}
if (char === ">" && angleDepth > 0 && extraNamesStr[i - 1] !== "=") {
angleDepth--;
continue;
}
if (char === "(" || char === "[" || char === "{") {
depth++;
} else if (char === ")" || char === "]" || char === "}") {
depth--;
}
if (char === "," && depth === 0 && angleDepth === 0) {
const rest = extraNamesStr.slice(i + 1);
const match = rest.match(/^\s*([\w$]+)/);
if (match) {
names.push(match[1]);
}
}
}
return names;
}
function findExports(code) {
const declaredExports = matchAll(EXPORT_DECAL_RE, code, {
type: "declaration"
});
for (const declaredExport of declaredExports) {
if (/^export\s+(?:async\s+)?function/.test(declaredExport.code)) {
continue;
}
const extraNamesStr = declaredExport.extraNames;
if (extraNamesStr) {
const extraNames = _extractExtraNames(extraNamesStr);
if (extraNames.length > 0) {
declaredExport.names = [declaredExport.name, ...extraNames];
}
}
delete declaredExport.extraNames;
}
const namedExports = normalizeNamedExports(
matchAll(EXPORT_NAMED_RE, code, {
type: "named"
})
);
const destructuredExports = matchAll(
EXPORT_NAMED_DESTRUCT,
code,
{ type: "named" }
);
for (const namedExport of destructuredExports) {
namedExport.exports = namedExport.exports1 || namedExport.exports2;
namedExport.names = namedExport.exports.replace(/^\r?\n?/, "").split(/\s*,\s*/g).filter((name) => !TYPE_RE.test(name)).map(
(name) => name.replace(/^.*?\s*:\s*/, "").replace(/\s*=\s*.*$/, "").trim()
);
}
const defaultExport = matchAll(EXPORT_DEFAULT_RE, code, {
type: "default",
name: "default"
});
const defaultClassExports = matchAll(EXPORT_DEFAULT_CLASS_RE, code, {
type: "declaration"
});
const starExports = matchAll(EXPORT_STAR_RE, code, {
type: "star"
});
const exports$1 = normalizeExports([
...declaredExports,
...namedExports,
...destructuredExports,
...defaultExport,
...defaultClassExports,
...starExports
]);
if (exports$1.length === 0) {
return [];
}
const exportLocations = _tryGetLocations(code, "export");
if (exportLocations && exportLocations.length === 0) {
return [];
}
return (
// Filter false positive export matches
_filterStatement(exportLocations, exports$1).filter((exp, index, exports2) => {
const nextExport = exports2[index + 1];
return !nextExport || exp.type !== nextExport.type || !exp.name || exp.name !== nextExport.name;
})
);
}
function findTypeExports(code) {
const declaredExports = matchAll(
EXPORT_DECAL_TYPE_RE,
code,
{ type: "declaration" }
);
const namedExports = normalizeNamedExports(
matchAll(EXPORT_NAMED_TYPE_RE, code, {
type: "named"
})
);
const exports$1 = normalizeExports([
...declaredExports,
...namedExports
]);
if (exports$1.length === 0) {
return [];
}
const exportLocations = _tryGetLocations(code, "export");
if (exportLocations && exportLocations.length === 0) {
return [];
}
return (
// Filter false positive export matches
_filterStatement(exportLocations, exports$1).filter((exp, index, exports2) => {
const nextExport = exports2[index + 1];
return !nextExport || exp.type !== nextExport.type || !exp.name || exp.name !== nextExport.name;
})
);
}
function normalizeExports(exports$1) {
for (const exp of exports$1) {
if (!exp.name && exp.names && exp.names.length === 1) {
exp.name = exp.names[0];
}
if (exp.name === "default" && exp.type !== "default") {
exp._type = exp.type;
exp.type = "default";
}
if (!exp.names && exp.name) {
exp.names = [exp.name];
}
if (exp.type === "declaration" && exp.declaration) {
exp.declarationType = exp.declaration.replace(
/^declare\s*/,
""
);
}
}
return exports$1;
}
function normalizeNamedExports(namedExports) {
for (const namedExport of namedExports) {
namedExport.names = namedExport.exports.replace(/^\r?\n?/, "").split(/\s*,\s*/g).filter((name) => !TYPE_RE.test(name)).map((name) => name.replace(/^.*?\sas\s/, "").trim());
}
return namedExports;
}
function findExportNames(code) {
return findExports(code).flatMap((exp) => exp.names).filter(Boolean);
}
async function resolveModuleExportNames(id, options) {
const url = await resolvePath(id, options);
const code = await loadURL(url);
const exports$1 = findExports(code);
const exportNames = new Set(
exports$1.flatMap((exp) => exp.names).filter(Boolean)
);
for (const exp of exports$1) {
if (exp.type !== "star" || !exp.specifier) {
continue;
}
const subExports = await resolveModuleExportNames(exp.specifier, {
...options,
url
});
for (const subExport of subExports) {
exportNames.add(subExport);
}
}
return [...exportNames];
}
function _filterStatement(locations, statements) {
return statements.filter((exp) => {
return !locations || locations.some((location) => {
return exp.start <= location.start && exp.end >= location.end;
});
});
}
function _tryGetLocations(code, label) {
try {
return _getLocations(code, label);
} catch {
}
}
function _getLocations(code, label) {
const tokens = acorn.tokenizer(code, {
ecmaVersion: "latest",
sourceType: "module",
allowHashBang: true,
allowAwaitOutsideFunction: true,
allowImportExportEverywhere: true
});
const locations = [];
for (const token of tokens) {
if (token.type.label === label) {
locations.push({
start: token.start,
end: token.end
});
}
}
return locations;
}
function _isIdentifierBeforeAngleBracket(str, i) {
let j = i - 1;
while (j >= 0 && /[A-Za-z0-9_$]/.test(str[j])) {
j--;
}
const wordStart = j + 1;
return wordStart < i && /[A-Za-z_$]/.test(str[wordStart]);
}
function createCommonJS(url) {
const __filename = fileURLToPath(url);
const __dirname = path.dirname(__filename);
let _nativeRequire;
const getNativeRequire = () => {
if (!_nativeRequire) {
_nativeRequire = node_module.createRequire(url);
}
return _nativeRequire;
};
function require(id) {
return getNativeRequire()(id);
}
require.resolve = function requireResolve(id, options) {
return getNativeRequire().resolve(id, options);
};
return {
__filename,
__dirname,
require
};
}
function interopDefault(sourceModule, opts = {}) {
if (!isObject(sourceModule) || !("default" in sourceModule)) {
return sourceModule;
}
const defaultValue = sourceModule.default;
if (defaultValue === void 0 || defaultValue === null) {
return sourceModule;
}
const _defaultType = typeof defaultValue;
if (_defaultType !== "object" && !(_defaultType === "function" && !opts.preferNamespace)) {
return opts.preferNamespace ? sourceModule : defaultValue;
}
for (const key in sourceModule) {
try {
if (!(key in defaultValue)) {
Object.defineProperty(defaultValue, key, {
enumerable: key !== "default",
configurable: key !== "default",
get() {
return sourceModule[key];
}
});
}
} catch {
}
}
return defaultValue;
}
const EVAL_ESM_IMPORT_RE = /(?<=import .* from ["'])[^"']+(?=["'])|(?<=export .* from ["'])[^"']+(?=["'])|(?<=import\s*["'])[^"']+(?=["'])|(?<=import\s*\(["'])[^"']+(?=["']\))/g;
async function loadModule(id, options = {}) {
const url = await resolve(id, options);
const code = await loadURL(url);
return evalModule(code, { ...options, url });
}
async function evalModule(code, options = {}) {
const transformed = await transformModule(code, options);
const dataURL = toDataURL(transformed);
return import(dataURL).catch((error) => {
error.stack = error.stack.replace(
new RegExp(dataURL, "g"),
options.url || "_mlly_eval_"
);
throw error;
});
}
function transformModule(code, options = {}) {
if (options.url && options.url.endsWith(".json")) {
return Promise.resolve("export default " + code);
}
if (options.url) {
code = code.replace(/import\.meta\.url/g, `'${options.url}'`);
}
return Promise.resolve(code);
}
async function resolveImports(code, options) {
const imports = [...code.matchAll(EVAL_ESM_IMPORT_RE)].map((m) => m[0]);
if (imports.length === 0) {
return code;
}
const uniqueImports = [...new Set(imports)];
const resolved = /* @__PURE__ */ new Map();
await Promise.all(
uniqueImports.map(async (id) => {
let url = await resolve(id, options);
if (url.endsWith(".json")) {
const code2 = await loadURL(url);
url = toDataURL(await transformModule(code2, { url }));
}
resolved.set(id, url);
})
);
const re = new RegExp(
uniqueImports.map((index) => `(?:${index})`).join("|"),
"g"
);
return code.replace(re, (id) => resolved.get(id));
}
const ESM_RE = /(?:[\s;]|^)(?:import[\s\w*,{}]*from|import\s*["'*{]|export\b\s*(?:[*{]|default|class|type|function|const|var|let|async function)|import\.meta\b)/m;
const CJS_RE = /(?:[\s;]|^)(?:module\.exports\b|exports\.\w|require\s*\(|global\.\w)/m;
const COMMENT_RE = /\/\*.+?\*\/|\/\/.*(?=[nr])/g;
const BUILTIN_EXTENSIONS = /* @__PURE__ */ new Set([".mjs", ".cjs", ".node", ".wasm"]);
function hasESMSyntax(code, opts = {}) {
if (opts.stripComments) {
code = code.replace(COMMENT_RE, "");
}
return ESM_RE.test(code);
}
function hasCJSSyntax(code, opts = {}) {
if (opts.stripComments) {
code = code.replace(COMMENT_RE, "");
}
return CJS_RE.test(code);
}
function detectSyntax(code, opts = {}) {
if (opts.stripComments) {
code = code.replace(COMMENT_RE, "");
}
const hasESM = hasESMSyntax(code, {});
const hasCJS = hasCJSSyntax(code, {});
return {
hasESM,
hasCJS,
isMixed: hasESM && hasCJS
};
}
const validNodeImportDefaults = {
allowedProtocols: ["node", "file", "data"]
};
async function isValidNodeImport(id, _options = {}) {
if (isNodeBuiltin(id)) {
return true;
}
const options = { ...validNodeImportDefaults, ..._options };
const proto = getProtocol(id);
if (proto && !options.allowedProtocols?.includes(proto)) {
return false;
}
if (proto === "data") {
return true;
}
const resolvedPath = await resolvePath(id, options);
const extension = pathe.extname(resolvedPath);
if (BUILTIN_EXTENSIONS.has(extension)) {
return true;
}
if (extension !== ".js") {
return false;
}
const package_ = await pkgTypes.readPackageJSON(resolvedPath).catch(() => {
});
if (package_?.type === "module") {
return true;
}
if (/\.(?:\w+-)?esm?(?:-\w+)?\.js$|\/esm?\//.test(resolvedPath)) {
return false;
}
const code = options.code || await fs.promises.readFile(resolvedPath, "utf8").catch(() => {
}) || "";
return !hasESMSyntax(code, { stripComments: options.stripComments });
}
exports.DYNAMIC_IMPORT_RE = DYNAMIC_IMPORT_RE;
exports.ESM_STATIC_IMPORT_RE = ESM_STATIC_IMPORT_RE;
exports.EXPORT_DECAL_RE = EXPORT_DECAL_RE;
exports.EXPORT_DECAL_TYPE_RE = EXPORT_DECAL_TYPE_RE;
exports.createCommonJS = createCommonJS;
exports.createResolve = createResolve;
exports.detectSyntax = detectSyntax;
exports.evalModule = evalModule;
exports.fileURLToPath = fileURLToPath;
exports.findDynamicImports = findDynamicImports;
exports.findExportNames = findExportNames;
exports.findExports = findExports;
exports.findStaticImports = findStaticImports;
exports.findTypeExports = findTypeExports;
exports.findTypeImports = findTypeImports;
exports.getProtocol = getProtocol;
exports.hasCJSSyntax = hasCJSSyntax;
exports.hasESMSyntax = hasESMSyntax;
exports.interopDefault = interopDefault;
exports.isNodeBuiltin = isNodeBuiltin;
exports.isValidNodeImport = isValidNodeImport;
exports.loadModule = loadModule;
exports.loadURL = loadURL;
exports.lookupNodeModuleSubpath = lookupNodeModuleSubpath;
exports.normalizeid = normalizeid;
exports.parseNodeModulePath = parseNodeModulePath;
exports.parseStaticImport = parseStaticImport;
exports.parseTypeImport = parseTypeImport;
exports.pathToFileURL = pathToFileURL;
exports.resolve = resolve;
exports.resolveImports = resolveImports;
exports.resolveModuleExportNames = resolveModuleExportNames;
exports.resolvePath = resolvePath;
exports.resolvePathSync = resolvePathSync;
exports.resolveSync = resolveSync;
exports.sanitizeFilePath = sanitizeFilePath;
exports.sanitizeURIComponent = sanitizeURIComponent;
exports.toDataURL = toDataURL;
exports.transformModule = transformModule;
+564
View File
@@ -0,0 +1,564 @@
interface ResolveOptions {
/**
* A URL, path or array of URLs/paths to resolve against.
*/
url?: string | URL | (string | URL)[];
/**
* File extensions to consider when resolving modules.
*/
extensions?: string[];
/**
* Conditions to consider when resolving package exports.
*/
conditions?: string[];
}
/**
* Synchronously resolves a module path based on the options provided.
*
* @param {string} id - The identifier or path of the module to resolve.
* @param {ResolveOptions} [options] - Options to resolve the module. See {@link ResolveOptions}.
* @returns {string} The resolved URL as a string.
*/
declare function resolveSync(id: string, options?: ResolveOptions): string;
/**
* Asynchronously resolves a module path based on the given options.
*
* @param {string} id - The identifier or path of the module to resolve.
* @param {ResolveOptions} [options] - Options for resolving the module. See {@link ResolveOptions}.
* @returns {Promise<string>} A promise to resolve the URL as a string.
*/
declare function resolve(id: string, options?: ResolveOptions): Promise<string>;
/**
* Synchronously resolves a module path to a local file path based on the given options.
*
* @param {string} id - The identifier or path of the module to resolve.
* @param {ResolveOptions} [options] - Options to resolve the module. See {@link ResolveOptions}.
* @returns {string} The resolved file path.
*/
declare function resolvePathSync(id: string, options?: ResolveOptions): string;
/**
* Asynchronously resolves a module path to a local file path based on the options provided.
*
* @param {string} id - The identifier or path of the module to resolve.
* @param {ResolveOptions} [options] - Options for resolving the module. See {@link ResolveOptions}.
* @returns {Promise<string>} A promise to resolve to the file path.
*/
declare function resolvePath(id: string, options?: ResolveOptions): Promise<string>;
/**
* Creates a resolver function with default options that can be used to resolve module identifiers.
*
* @param {ResolveOptions} [defaults] - Default options to use for all resolutions. See {@link ResolveOptions}.
* @returns {Function} A resolver function that takes an identifier and an optional URL, and resolves the identifier using the default options and the given URL.
*/
declare function createResolve(defaults?: ResolveOptions): (id: string, url?: ResolveOptions["url"]) => Promise<string>;
/**
* Parses a node module path to extract the directory, name, and subpath.
*
* @param {string} path - The path to parse.
* @returns {Object} An object containing the directory, module name, and subpath of the node module.
*/
declare function parseNodeModulePath(path: string): {
dir?: undefined;
name?: undefined;
subpath?: undefined;
} | {
dir: string;
name: string;
subpath: string | undefined;
};
/**
* Attempts to reverse engineer a subpath export within a node module.
*
* @param {string} path - The path within the node module.
* @returns {Promise<string | undefined>} A promise that resolves to the detected subpath or undefined if not found.
*/
declare function lookupNodeModuleSubpath(path: string): Promise<string | undefined>;
/**
* Represents a general structure for ECMAScript module imports.
*/
interface ESMImport {
/**
* Specifies the type of import: "static" for static imports and "dynamic" for dynamic imports.
*/
type: "static" | "dynamic";
/**
* The full import declaration code snippet as a string.
*/
code: string;
/**
* The starting position (index) of the import declaration in the source code.
*/
start: number;
/**
* The end position (index) of the import declaration in the source code.
*/
end: number;
}
/**
* Represents a static import declaration in an ECMAScript module.
* Extends {@link ESMImport}.
*/
interface StaticImport extends ESMImport {
/**
* Indicates the type of import, specifically a static import.
*/
type: "static";
/**
* Contains the entire import statement as a string, excluding the module specifier.
*/
imports: string;
/**
* The module specifier from which imports are being brought in.
*/
specifier: string;
}
/**
* Represents a parsed static import declaration with detailed components of the import.
* Extends {@link StaticImport}.
*/
interface ParsedStaticImport extends StaticImport {
/**
* The default import name, if any.
* @optional
*/
defaultImport?: string;
/**
* The namespace import name, if any, using the `* as` syntax.
* @optional
*/
namespacedImport?: string;
/**
* An object representing named imports, with their local aliases if specified.
* Each property key is the original name and its value is the alias.
* @optional
*/
namedImports?: {
[name: string]: string;
};
}
/**
* Represents a dynamic import declaration that is loaded at runtime.
* Extends {@link ESMImport}.
*/
interface DynamicImport extends ESMImport {
/**
* Indicates that this is a dynamic import.
*/
type: "dynamic";
/**
* The expression or path to be dynamically imported, typically a module path or URL.
*/
expression: string;
}
/**
* Represents a type-specific import, primarily used for importing types in TypeScript.
* Extends {@link ESMImport} but omits the 'type' to redefine it specifically for type imports.
*/
interface TypeImport extends Omit<ESMImport, "type"> {
/**
* Specifies that this is a type import.
*/
type: "type";
/**
* Contains the entire type import statement as a string, excluding the module specifier.
*/
imports: string;
/**
* The module specifier from which to import types.
*/
specifier: string;
}
/**
* Represents a general structure for ECMAScript module exports.
*/
interface ESMExport {
/**
* Optional explicit type for complex scenarios, often used internally.
* @optional
*/
_type?: "declaration" | "named" | "default" | "star";
/**
* The type of export (declaration, named, default or star).
*/
type: "declaration" | "named" | "default" | "star";
/**
* The specific type of declaration being exported, if applicable.
* @optional
*/
declarationType?: "let" | "var" | "const" | "enum" | "const enum" | "class" | "function" | "async function";
/**
* The full code snippet of the export statement.
*/
code: string;
/**
* The starting position (index) of the export declaration in the source code.
*/
start: number;
/**
* The end position (index) of the export declaration in the source code.
*/
end: number;
/**
* The name of the variable, function or class being exported, if given explicitly.
* @optional
*/
name?: string;
/**
* The name used for default exports when a specific identifier isn't given.
* @optional
*/
defaultName?: string;
/**
* An array of names to export, applicable to named and destructured exports.
*/
names: string[];
/**
* The module specifier, if any, from which exports are being re-exported.
* @optional
*/
specifier?: string;
}
/**
* Represents a declaration export within an ECMAScript module.
* Extends {@link ESMExport}.
*/
interface DeclarationExport extends ESMExport {
/**
* Indicates that this export is a declaration export.
*/
type: "declaration";
/**
* The declaration string, such as 'let', 'const', 'class', etc., describing what is being exported.
*/
declaration: string;
/**
* The name of the declaration to be exported.
*/
name: string;
}
/**
* Represents a named export within an ECMAScript module.
* Extends {@link ESMExport}.
*/
interface NamedExport extends ESMExport {
/**
* Specifies that this export is a named export.
*/
type: "named";
/**
* The export string, containing all exported identifiers.
*/
exports: string;
/**
* An array of names to export.
*/
names: string[];
/**
* The module specifier, if any, from which exports are being re-exported.
* @optional
*/
specifier?: string;
}
/**
* Represents a standard export within an ECMAScript module.
* Extends {@link ESMExport}.
*/
interface DefaultExport extends ESMExport {
/**
* Specifies that this export is a standard export.
*/
type: "default";
}
/**
* Regular expression to match static import statements in JavaScript/TypeScript code.
* @example `import { foo, bar as baz } from 'module'`
*/
declare const ESM_STATIC_IMPORT_RE: RegExp;
/**
* Regular expression to match dynamic import statements in JavaScript/TypeScript code.
* @example `import('module')`
*/
declare const DYNAMIC_IMPORT_RE: RegExp;
/**
* Regular expression to match various types of export declarations including variables, functions, and classes.
* @example `export const num = 1, str = 'hello'; export class Example {}`
*/
declare const EXPORT_DECAL_RE: RegExp;
/**
* Regular expression to match export declarations specifically for types, interfaces, and type aliases in TypeScript.
* @example `export type Result = { success: boolean; }; export interface User { name: string; age: number; };`
*/
declare const EXPORT_DECAL_TYPE_RE: RegExp;
/**
* Finds all static import statements within the given code string.
* @param {string} code - The source code to search for static imports.
* @returns {StaticImport[]} An array of {@link StaticImport} objects representing each static import found.
*/
declare function findStaticImports(code: string): StaticImport[];
/**
* Searches for dynamic import statements in the given source code.
* @param {string} code - The source to search for dynamic imports in.
* @returns {DynamicImport[]} An array of {@link DynamicImport} objects representing each dynamic import found.
*/
declare function findDynamicImports(code: string): DynamicImport[];
/**
* Identifies and returns all type import statements in the given source code.
* This function is specifically targeted at type imports used in TypeScript.
* @param {string} code - The source code to search for type imports.
* @returns {TypeImport[]} An array of {@link TypeImport} objects representing each type import found.
*/
declare function findTypeImports(code: string): TypeImport[];
/**
* Parses a static import or type import to extract detailed import elements such as default, namespace and named imports.
* @param {StaticImport | TypeImport} matched - The matched import statement to parse. See {@link StaticImport} and {@link TypeImport}.
* @returns {ParsedStaticImport} A structured object representing the parsed static import. See {@link ParsedStaticImport}.
*/
declare function parseStaticImport(matched: StaticImport | TypeImport): ParsedStaticImport;
/**
* Parses a static import or type import to extract detailed import elements such as default, namespace and named imports.
* @param {StaticImport | TypeImport} matched - The matched import statement to parse. See {@link StaticImport} and {@link TypeImport}.
* @returns {ParsedStaticImport} A structured object representing the parsed static import. See {@link ParsedStaticImport}.
*/
declare function parseTypeImport(matched: TypeImport | StaticImport): ParsedStaticImport;
/**
* Identifies all export statements in the supplied source code and categorises them into different types such as declarations, named, default and star exports.
* This function processes the code to capture different forms of export statements and normalise their representation for further processing.
*
* @param {string} code - The source code containing the export statements to be analysed.
* @returns {ESMExport[]} An array of {@link ESMExport} objects representing each export found, properly categorised and structured.
*/
declare function findExports(code: string): ESMExport[];
/**
* Searches specifically for type-related exports in TypeScript code, such as exported interfaces, types, and declarations prefixed with 'declare'.
* This function uses specialised regular expressions to identify type exports and normalises them for consistency.
*
* @param {string} code - The TypeScript source code to search for type exports.
* @returns {ESMExport[]} An array of {@link ESMExport} objects representing each type export found.
*/
declare function findTypeExports(code: string): ESMExport[];
/**
* Extracts and returns a list of all export names from the given source.
* This function uses {@link findExports} to retrieve all types of exports and consolidates their names into a single array.
*
* @param {string} code - The source code to search for export names.
* @returns {string[]} An array containing the names of all exports found in the code.
*/
declare function findExportNames(code: string): string[];
/**
* Asynchronously resolves and returns all export names from a module specified by its module identifier.
* This function recursively resolves all explicitly named and asterisked (* as) exports to fully enumerate the exported identifiers.
*
* @param {string} id - The module identifier to resolve.
* @param {ResolveOptions} [options] - Optional settings for resolving the module path, such as the base URL.
* @returns {Promise<string[]>} A promise that resolves to an array of export names from the module.
*/
declare function resolveModuleExportNames(id: string, options?: ResolveOptions): Promise<string[]>;
/**
* Represents the context of a CommonJS environment, providing node-like module resolution capabilities within a module.
*/
interface CommonjsContext {
/**
* The absolute path to the current module file.
*/
__filename: string;
/**
* The directory name of the current module.
*/
__dirname: string;
/**
* A function to require modules as in CommonJS.
*/
require: NodeRequire;
}
/**
* Creates a CommonJS context for a given module URL, enabling `require`, `__filename` and `__dirname` support similar to Node.js.
* This function dynamically generates a `require` function that is context-aware and bound to the location of the given module URL.
*
* @param {string} url - The URL of the module file to create a context for.
* @returns {CommonjsContext} A context object containing `__filename`, `__dirname` and a custom `require` function. See {@link CommonjsContext}.
*/
declare function createCommonJS(url: string): CommonjsContext;
declare function interopDefault(sourceModule: any, opts?: {
preferNamespace?: boolean;
}): any;
/**
* Options for evaluating or transforming modules, extending resolution options with optional URL specifications.
*/
interface EvaluateOptions extends ResolveOptions {
/**
* The URL of the module, which can be specified to override the URL resolved from the module identifier.
* @optional
*/
url?: string;
}
/**
* Loads a module by resolving its identifier to a URL, fetching the module's code and evaluating it.
*
* @param {string} id - The identifier of the module to load.
* @param {EvaluateOptions} options - Optional parameters to resolve and load the module. See {@link EvaluateOptions}.
* @returns {Promise<any>} A promise to resolve to the evaluated module.
* });
*/
declare function loadModule(id: string, options?: EvaluateOptions): Promise<any>;
/**
* Evaluates JavaScript code as a module using a dynamic import from a data URL.
*
* @param {string} code - The code of the module to evaluate.
* @param {EvaluateOptions} options - Includes the original URL of the module for better error mapping. See {@link EvaluateOptions}.
* @returns {Promise<any>} A promise that resolves to the evaluated module or throws an error if the evaluation fails.
*/
declare function evalModule(code: string, options?: EvaluateOptions): Promise<any>;
/**
* Transform module code to handle specific scenarios, such as converting JSON to a module or rewriting import.meta.url.
*
* @param {string} code - The code of the module to transform.
* @param {EvaluateOptions} options - Options to control how the code is transformed. See {@link EvaluateOptions}.
* @returns {Promise<string>} A promise that resolves to the transformed code.
*/
declare function transformModule(code: string, options?: EvaluateOptions): Promise<string>;
/**
* Resolves all import URLs found within the provided code to their absolute URLs, based on the given options.
*
* @param {string} code - The code containing the import directives to resolve.
* @param {EvaluateOptions} [options] - Options to use for resolving imports. See {@link EvaluateOptions}.
* @returns {Promise<string>} A promise that resolves to the code, replacing import URLs with resolved URLs.
*/
declare function resolveImports(code: string, options?: EvaluateOptions): Promise<string>;
/**
* Options for detecting syntax within a code string.
*/
type DetectSyntaxOptions = {
/**
* Indicates whether comments should be stripped from the code before syntax checking.
* @default false
*/
stripComments?: boolean;
};
/**
* Determines if a given code string contains ECMAScript module syntax.
*
* @param {string} code - The source code to analyse.
* @param {DetectSyntaxOptions} opts - See {@link DetectSyntaxOptions}.
* @returns {boolean} `true` if the code contains ESM syntax, otherwise `false`.
*/
declare function hasESMSyntax(code: string, opts?: DetectSyntaxOptions): boolean;
/**
* Determines if a given string of code contains CommonJS syntax.
*
* @param {string} code - The source code to analyse.
* @param {DetectSyntaxOptions} opts - See {@link DetectSyntaxOptions}.
* @returns {boolean} `true` if the code contains CommonJS syntax, `false` otherwise.
*/
declare function hasCJSSyntax(code: string, opts?: DetectSyntaxOptions): boolean;
/**
* Analyses the supplied code to determine if it contains ECMAScript module syntax, CommonJS syntax, or both.
*
* @param {string} code - The source code to analyse.
* @param {DetectSyntaxOptions} opts - See {@link DetectSyntaxOptions}.
* @returns {object} An object indicating the presence of ESM syntax (`hasESM`), CJS syntax (`hasCJS`) and whether both syntaxes are present (`isMixed`).
*/
declare function detectSyntax(code: string, opts?: DetectSyntaxOptions): {
hasESM: boolean;
hasCJS: boolean;
isMixed: boolean;
};
interface ValidNodeImportOptions extends ResolveOptions {
/**
* The contents of the import, which may be analyzed to see if it contains
* CJS or ESM syntax as a last step in checking whether it is a valid import.
*/
code?: string;
/**
* Protocols that are allowed as valid node imports.
*
* @default ['node', 'file', 'data']
*
*/
allowedProtocols?: Array<string>;
/**
* Whether to strip comments from the code before checking for ESM syntax.
*
* @default false
*/
stripComments?: boolean;
}
/**
* Validates whether a given identifier represents a valid node import, based on its protocol, file extension, and optionally its contents.
*
* @param {string} id - The identifier or URL of the import to validate.
* @param {ValidNodeImportOptions} _options - Options for resolving and validating the import. See {@link ValidNodeImportOptions}.
* @returns {Promise<boolean>} A promise that resolves to `true` if the import is valid, otherwise `false`.
*/
declare function isValidNodeImport(id: string, _options?: ValidNodeImportOptions): Promise<boolean>;
/**
* Converts a file URL to a local file system path with normalized slashes.
*
* @param {string | URL} id - The file URL or local path to convert.
* @returns {string} A normalized file system path.
*/
declare function fileURLToPath(id: string | URL): string;
/**
* Converts a local file system path to a file URL.
*
* @param {string | URL} id - The file system path to convert.
* @returns {string} The resulting file URL as a string.
*/
declare function pathToFileURL(id: string | URL): string;
/**
* Sanitises a component of a URI by replacing invalid characters.
*
* @param {string} name - The URI component to sanitise.
* @param {string} [replacement="_"] - The string to replace invalid characters with.
* @returns {string} The sanitised URI component.
*/
declare function sanitizeURIComponent(name?: string, replacement?: string): string;
/**
* Cleans a file path string by sanitising each component of the path.
*
* @param {string} filePath - The file path to sanitise.
* @returns {string} The sanitised file path.
*/
declare function sanitizeFilePath(filePath?: string): string;
/**
* Normalises a module identifier to ensure it has a protocol if missing, handling built-in modules and file paths.
*
* @param {string} id - The identifier to normalise.
* @returns {string} The normalised identifier with the appropriate protocol.
*/
declare function normalizeid(id: string): string;
/**
* Loads the contents of a file from a URL into a string.
*
* @param {string} url - The URL of the file to load.
* @returns {Promise<string>} A promise that resolves to the content of the file.
*/
declare function loadURL(url: string): Promise<string>;
/**
* Converts a string of code into a data URL that can be used for dynamic imports.
*
* @param {string} code - The string of code to convert.
* @returns {string} The data URL containing the encoded code.
*/
declare function toDataURL(code: string): string;
/**
* Checks if a module identifier matches a Node.js built-in module.
*
* @param {string} id - The identifier to check.
* @returns {boolean} `true` if the identifier is a built-in module, otherwise `false`.
*/
declare function isNodeBuiltin(id?: string): boolean;
/**
* Extracts the protocol portion of a given identifier string.
*
* @param {string} id - The identifier from which to extract the log.
* @returns {string | undefined} The protocol part of the identifier, or undefined if no protocol is present.
*/
declare function getProtocol(id: string): string | undefined;
export { DYNAMIC_IMPORT_RE, ESM_STATIC_IMPORT_RE, EXPORT_DECAL_RE, EXPORT_DECAL_TYPE_RE, createCommonJS, createResolve, detectSyntax, evalModule, fileURLToPath, findDynamicImports, findExportNames, findExports, findStaticImports, findTypeExports, findTypeImports, getProtocol, hasCJSSyntax, hasESMSyntax, interopDefault, isNodeBuiltin, isValidNodeImport, loadModule, loadURL, lookupNodeModuleSubpath, normalizeid, parseNodeModulePath, parseStaticImport, parseTypeImport, pathToFileURL, resolve, resolveImports, resolveModuleExportNames, resolvePath, resolvePathSync, resolveSync, sanitizeFilePath, sanitizeURIComponent, toDataURL, transformModule };
export type { CommonjsContext, DeclarationExport, DefaultExport, DetectSyntaxOptions, DynamicImport, ESMExport, ESMImport, EvaluateOptions, NamedExport, ParsedStaticImport, ResolveOptions, StaticImport, TypeImport, ValidNodeImportOptions };
+564
View File
@@ -0,0 +1,564 @@
interface ResolveOptions {
/**
* A URL, path or array of URLs/paths to resolve against.
*/
url?: string | URL | (string | URL)[];
/**
* File extensions to consider when resolving modules.
*/
extensions?: string[];
/**
* Conditions to consider when resolving package exports.
*/
conditions?: string[];
}
/**
* Synchronously resolves a module path based on the options provided.
*
* @param {string} id - The identifier or path of the module to resolve.
* @param {ResolveOptions} [options] - Options to resolve the module. See {@link ResolveOptions}.
* @returns {string} The resolved URL as a string.
*/
declare function resolveSync(id: string, options?: ResolveOptions): string;
/**
* Asynchronously resolves a module path based on the given options.
*
* @param {string} id - The identifier or path of the module to resolve.
* @param {ResolveOptions} [options] - Options for resolving the module. See {@link ResolveOptions}.
* @returns {Promise<string>} A promise to resolve the URL as a string.
*/
declare function resolve(id: string, options?: ResolveOptions): Promise<string>;
/**
* Synchronously resolves a module path to a local file path based on the given options.
*
* @param {string} id - The identifier or path of the module to resolve.
* @param {ResolveOptions} [options] - Options to resolve the module. See {@link ResolveOptions}.
* @returns {string} The resolved file path.
*/
declare function resolvePathSync(id: string, options?: ResolveOptions): string;
/**
* Asynchronously resolves a module path to a local file path based on the options provided.
*
* @param {string} id - The identifier or path of the module to resolve.
* @param {ResolveOptions} [options] - Options for resolving the module. See {@link ResolveOptions}.
* @returns {Promise<string>} A promise to resolve to the file path.
*/
declare function resolvePath(id: string, options?: ResolveOptions): Promise<string>;
/**
* Creates a resolver function with default options that can be used to resolve module identifiers.
*
* @param {ResolveOptions} [defaults] - Default options to use for all resolutions. See {@link ResolveOptions}.
* @returns {Function} A resolver function that takes an identifier and an optional URL, and resolves the identifier using the default options and the given URL.
*/
declare function createResolve(defaults?: ResolveOptions): (id: string, url?: ResolveOptions["url"]) => Promise<string>;
/**
* Parses a node module path to extract the directory, name, and subpath.
*
* @param {string} path - The path to parse.
* @returns {Object} An object containing the directory, module name, and subpath of the node module.
*/
declare function parseNodeModulePath(path: string): {
dir?: undefined;
name?: undefined;
subpath?: undefined;
} | {
dir: string;
name: string;
subpath: string | undefined;
};
/**
* Attempts to reverse engineer a subpath export within a node module.
*
* @param {string} path - The path within the node module.
* @returns {Promise<string | undefined>} A promise that resolves to the detected subpath or undefined if not found.
*/
declare function lookupNodeModuleSubpath(path: string): Promise<string | undefined>;
/**
* Represents a general structure for ECMAScript module imports.
*/
interface ESMImport {
/**
* Specifies the type of import: "static" for static imports and "dynamic" for dynamic imports.
*/
type: "static" | "dynamic";
/**
* The full import declaration code snippet as a string.
*/
code: string;
/**
* The starting position (index) of the import declaration in the source code.
*/
start: number;
/**
* The end position (index) of the import declaration in the source code.
*/
end: number;
}
/**
* Represents a static import declaration in an ECMAScript module.
* Extends {@link ESMImport}.
*/
interface StaticImport extends ESMImport {
/**
* Indicates the type of import, specifically a static import.
*/
type: "static";
/**
* Contains the entire import statement as a string, excluding the module specifier.
*/
imports: string;
/**
* The module specifier from which imports are being brought in.
*/
specifier: string;
}
/**
* Represents a parsed static import declaration with detailed components of the import.
* Extends {@link StaticImport}.
*/
interface ParsedStaticImport extends StaticImport {
/**
* The default import name, if any.
* @optional
*/
defaultImport?: string;
/**
* The namespace import name, if any, using the `* as` syntax.
* @optional
*/
namespacedImport?: string;
/**
* An object representing named imports, with their local aliases if specified.
* Each property key is the original name and its value is the alias.
* @optional
*/
namedImports?: {
[name: string]: string;
};
}
/**
* Represents a dynamic import declaration that is loaded at runtime.
* Extends {@link ESMImport}.
*/
interface DynamicImport extends ESMImport {
/**
* Indicates that this is a dynamic import.
*/
type: "dynamic";
/**
* The expression or path to be dynamically imported, typically a module path or URL.
*/
expression: string;
}
/**
* Represents a type-specific import, primarily used for importing types in TypeScript.
* Extends {@link ESMImport} but omits the 'type' to redefine it specifically for type imports.
*/
interface TypeImport extends Omit<ESMImport, "type"> {
/**
* Specifies that this is a type import.
*/
type: "type";
/**
* Contains the entire type import statement as a string, excluding the module specifier.
*/
imports: string;
/**
* The module specifier from which to import types.
*/
specifier: string;
}
/**
* Represents a general structure for ECMAScript module exports.
*/
interface ESMExport {
/**
* Optional explicit type for complex scenarios, often used internally.
* @optional
*/
_type?: "declaration" | "named" | "default" | "star";
/**
* The type of export (declaration, named, default or star).
*/
type: "declaration" | "named" | "default" | "star";
/**
* The specific type of declaration being exported, if applicable.
* @optional
*/
declarationType?: "let" | "var" | "const" | "enum" | "const enum" | "class" | "function" | "async function";
/**
* The full code snippet of the export statement.
*/
code: string;
/**
* The starting position (index) of the export declaration in the source code.
*/
start: number;
/**
* The end position (index) of the export declaration in the source code.
*/
end: number;
/**
* The name of the variable, function or class being exported, if given explicitly.
* @optional
*/
name?: string;
/**
* The name used for default exports when a specific identifier isn't given.
* @optional
*/
defaultName?: string;
/**
* An array of names to export, applicable to named and destructured exports.
*/
names: string[];
/**
* The module specifier, if any, from which exports are being re-exported.
* @optional
*/
specifier?: string;
}
/**
* Represents a declaration export within an ECMAScript module.
* Extends {@link ESMExport}.
*/
interface DeclarationExport extends ESMExport {
/**
* Indicates that this export is a declaration export.
*/
type: "declaration";
/**
* The declaration string, such as 'let', 'const', 'class', etc., describing what is being exported.
*/
declaration: string;
/**
* The name of the declaration to be exported.
*/
name: string;
}
/**
* Represents a named export within an ECMAScript module.
* Extends {@link ESMExport}.
*/
interface NamedExport extends ESMExport {
/**
* Specifies that this export is a named export.
*/
type: "named";
/**
* The export string, containing all exported identifiers.
*/
exports: string;
/**
* An array of names to export.
*/
names: string[];
/**
* The module specifier, if any, from which exports are being re-exported.
* @optional
*/
specifier?: string;
}
/**
* Represents a standard export within an ECMAScript module.
* Extends {@link ESMExport}.
*/
interface DefaultExport extends ESMExport {
/**
* Specifies that this export is a standard export.
*/
type: "default";
}
/**
* Regular expression to match static import statements in JavaScript/TypeScript code.
* @example `import { foo, bar as baz } from 'module'`
*/
declare const ESM_STATIC_IMPORT_RE: RegExp;
/**
* Regular expression to match dynamic import statements in JavaScript/TypeScript code.
* @example `import('module')`
*/
declare const DYNAMIC_IMPORT_RE: RegExp;
/**
* Regular expression to match various types of export declarations including variables, functions, and classes.
* @example `export const num = 1, str = 'hello'; export class Example {}`
*/
declare const EXPORT_DECAL_RE: RegExp;
/**
* Regular expression to match export declarations specifically for types, interfaces, and type aliases in TypeScript.
* @example `export type Result = { success: boolean; }; export interface User { name: string; age: number; };`
*/
declare const EXPORT_DECAL_TYPE_RE: RegExp;
/**
* Finds all static import statements within the given code string.
* @param {string} code - The source code to search for static imports.
* @returns {StaticImport[]} An array of {@link StaticImport} objects representing each static import found.
*/
declare function findStaticImports(code: string): StaticImport[];
/**
* Searches for dynamic import statements in the given source code.
* @param {string} code - The source to search for dynamic imports in.
* @returns {DynamicImport[]} An array of {@link DynamicImport} objects representing each dynamic import found.
*/
declare function findDynamicImports(code: string): DynamicImport[];
/**
* Identifies and returns all type import statements in the given source code.
* This function is specifically targeted at type imports used in TypeScript.
* @param {string} code - The source code to search for type imports.
* @returns {TypeImport[]} An array of {@link TypeImport} objects representing each type import found.
*/
declare function findTypeImports(code: string): TypeImport[];
/**
* Parses a static import or type import to extract detailed import elements such as default, namespace and named imports.
* @param {StaticImport | TypeImport} matched - The matched import statement to parse. See {@link StaticImport} and {@link TypeImport}.
* @returns {ParsedStaticImport} A structured object representing the parsed static import. See {@link ParsedStaticImport}.
*/
declare function parseStaticImport(matched: StaticImport | TypeImport): ParsedStaticImport;
/**
* Parses a static import or type import to extract detailed import elements such as default, namespace and named imports.
* @param {StaticImport | TypeImport} matched - The matched import statement to parse. See {@link StaticImport} and {@link TypeImport}.
* @returns {ParsedStaticImport} A structured object representing the parsed static import. See {@link ParsedStaticImport}.
*/
declare function parseTypeImport(matched: TypeImport | StaticImport): ParsedStaticImport;
/**
* Identifies all export statements in the supplied source code and categorises them into different types such as declarations, named, default and star exports.
* This function processes the code to capture different forms of export statements and normalise their representation for further processing.
*
* @param {string} code - The source code containing the export statements to be analysed.
* @returns {ESMExport[]} An array of {@link ESMExport} objects representing each export found, properly categorised and structured.
*/
declare function findExports(code: string): ESMExport[];
/**
* Searches specifically for type-related exports in TypeScript code, such as exported interfaces, types, and declarations prefixed with 'declare'.
* This function uses specialised regular expressions to identify type exports and normalises them for consistency.
*
* @param {string} code - The TypeScript source code to search for type exports.
* @returns {ESMExport[]} An array of {@link ESMExport} objects representing each type export found.
*/
declare function findTypeExports(code: string): ESMExport[];
/**
* Extracts and returns a list of all export names from the given source.
* This function uses {@link findExports} to retrieve all types of exports and consolidates their names into a single array.
*
* @param {string} code - The source code to search for export names.
* @returns {string[]} An array containing the names of all exports found in the code.
*/
declare function findExportNames(code: string): string[];
/**
* Asynchronously resolves and returns all export names from a module specified by its module identifier.
* This function recursively resolves all explicitly named and asterisked (* as) exports to fully enumerate the exported identifiers.
*
* @param {string} id - The module identifier to resolve.
* @param {ResolveOptions} [options] - Optional settings for resolving the module path, such as the base URL.
* @returns {Promise<string[]>} A promise that resolves to an array of export names from the module.
*/
declare function resolveModuleExportNames(id: string, options?: ResolveOptions): Promise<string[]>;
/**
* Represents the context of a CommonJS environment, providing node-like module resolution capabilities within a module.
*/
interface CommonjsContext {
/**
* The absolute path to the current module file.
*/
__filename: string;
/**
* The directory name of the current module.
*/
__dirname: string;
/**
* A function to require modules as in CommonJS.
*/
require: NodeRequire;
}
/**
* Creates a CommonJS context for a given module URL, enabling `require`, `__filename` and `__dirname` support similar to Node.js.
* This function dynamically generates a `require` function that is context-aware and bound to the location of the given module URL.
*
* @param {string} url - The URL of the module file to create a context for.
* @returns {CommonjsContext} A context object containing `__filename`, `__dirname` and a custom `require` function. See {@link CommonjsContext}.
*/
declare function createCommonJS(url: string): CommonjsContext;
declare function interopDefault(sourceModule: any, opts?: {
preferNamespace?: boolean;
}): any;
/**
* Options for evaluating or transforming modules, extending resolution options with optional URL specifications.
*/
interface EvaluateOptions extends ResolveOptions {
/**
* The URL of the module, which can be specified to override the URL resolved from the module identifier.
* @optional
*/
url?: string;
}
/**
* Loads a module by resolving its identifier to a URL, fetching the module's code and evaluating it.
*
* @param {string} id - The identifier of the module to load.
* @param {EvaluateOptions} options - Optional parameters to resolve and load the module. See {@link EvaluateOptions}.
* @returns {Promise<any>} A promise to resolve to the evaluated module.
* });
*/
declare function loadModule(id: string, options?: EvaluateOptions): Promise<any>;
/**
* Evaluates JavaScript code as a module using a dynamic import from a data URL.
*
* @param {string} code - The code of the module to evaluate.
* @param {EvaluateOptions} options - Includes the original URL of the module for better error mapping. See {@link EvaluateOptions}.
* @returns {Promise<any>} A promise that resolves to the evaluated module or throws an error if the evaluation fails.
*/
declare function evalModule(code: string, options?: EvaluateOptions): Promise<any>;
/**
* Transform module code to handle specific scenarios, such as converting JSON to a module or rewriting import.meta.url.
*
* @param {string} code - The code of the module to transform.
* @param {EvaluateOptions} options - Options to control how the code is transformed. See {@link EvaluateOptions}.
* @returns {Promise<string>} A promise that resolves to the transformed code.
*/
declare function transformModule(code: string, options?: EvaluateOptions): Promise<string>;
/**
* Resolves all import URLs found within the provided code to their absolute URLs, based on the given options.
*
* @param {string} code - The code containing the import directives to resolve.
* @param {EvaluateOptions} [options] - Options to use for resolving imports. See {@link EvaluateOptions}.
* @returns {Promise<string>} A promise that resolves to the code, replacing import URLs with resolved URLs.
*/
declare function resolveImports(code: string, options?: EvaluateOptions): Promise<string>;
/**
* Options for detecting syntax within a code string.
*/
type DetectSyntaxOptions = {
/**
* Indicates whether comments should be stripped from the code before syntax checking.
* @default false
*/
stripComments?: boolean;
};
/**
* Determines if a given code string contains ECMAScript module syntax.
*
* @param {string} code - The source code to analyse.
* @param {DetectSyntaxOptions} opts - See {@link DetectSyntaxOptions}.
* @returns {boolean} `true` if the code contains ESM syntax, otherwise `false`.
*/
declare function hasESMSyntax(code: string, opts?: DetectSyntaxOptions): boolean;
/**
* Determines if a given string of code contains CommonJS syntax.
*
* @param {string} code - The source code to analyse.
* @param {DetectSyntaxOptions} opts - See {@link DetectSyntaxOptions}.
* @returns {boolean} `true` if the code contains CommonJS syntax, `false` otherwise.
*/
declare function hasCJSSyntax(code: string, opts?: DetectSyntaxOptions): boolean;
/**
* Analyses the supplied code to determine if it contains ECMAScript module syntax, CommonJS syntax, or both.
*
* @param {string} code - The source code to analyse.
* @param {DetectSyntaxOptions} opts - See {@link DetectSyntaxOptions}.
* @returns {object} An object indicating the presence of ESM syntax (`hasESM`), CJS syntax (`hasCJS`) and whether both syntaxes are present (`isMixed`).
*/
declare function detectSyntax(code: string, opts?: DetectSyntaxOptions): {
hasESM: boolean;
hasCJS: boolean;
isMixed: boolean;
};
interface ValidNodeImportOptions extends ResolveOptions {
/**
* The contents of the import, which may be analyzed to see if it contains
* CJS or ESM syntax as a last step in checking whether it is a valid import.
*/
code?: string;
/**
* Protocols that are allowed as valid node imports.
*
* @default ['node', 'file', 'data']
*
*/
allowedProtocols?: Array<string>;
/**
* Whether to strip comments from the code before checking for ESM syntax.
*
* @default false
*/
stripComments?: boolean;
}
/**
* Validates whether a given identifier represents a valid node import, based on its protocol, file extension, and optionally its contents.
*
* @param {string} id - The identifier or URL of the import to validate.
* @param {ValidNodeImportOptions} _options - Options for resolving and validating the import. See {@link ValidNodeImportOptions}.
* @returns {Promise<boolean>} A promise that resolves to `true` if the import is valid, otherwise `false`.
*/
declare function isValidNodeImport(id: string, _options?: ValidNodeImportOptions): Promise<boolean>;
/**
* Converts a file URL to a local file system path with normalized slashes.
*
* @param {string | URL} id - The file URL or local path to convert.
* @returns {string} A normalized file system path.
*/
declare function fileURLToPath(id: string | URL): string;
/**
* Converts a local file system path to a file URL.
*
* @param {string | URL} id - The file system path to convert.
* @returns {string} The resulting file URL as a string.
*/
declare function pathToFileURL(id: string | URL): string;
/**
* Sanitises a component of a URI by replacing invalid characters.
*
* @param {string} name - The URI component to sanitise.
* @param {string} [replacement="_"] - The string to replace invalid characters with.
* @returns {string} The sanitised URI component.
*/
declare function sanitizeURIComponent(name?: string, replacement?: string): string;
/**
* Cleans a file path string by sanitising each component of the path.
*
* @param {string} filePath - The file path to sanitise.
* @returns {string} The sanitised file path.
*/
declare function sanitizeFilePath(filePath?: string): string;
/**
* Normalises a module identifier to ensure it has a protocol if missing, handling built-in modules and file paths.
*
* @param {string} id - The identifier to normalise.
* @returns {string} The normalised identifier with the appropriate protocol.
*/
declare function normalizeid(id: string): string;
/**
* Loads the contents of a file from a URL into a string.
*
* @param {string} url - The URL of the file to load.
* @returns {Promise<string>} A promise that resolves to the content of the file.
*/
declare function loadURL(url: string): Promise<string>;
/**
* Converts a string of code into a data URL that can be used for dynamic imports.
*
* @param {string} code - The string of code to convert.
* @returns {string} The data URL containing the encoded code.
*/
declare function toDataURL(code: string): string;
/**
* Checks if a module identifier matches a Node.js built-in module.
*
* @param {string} id - The identifier to check.
* @returns {boolean} `true` if the identifier is a built-in module, otherwise `false`.
*/
declare function isNodeBuiltin(id?: string): boolean;
/**
* Extracts the protocol portion of a given identifier string.
*
* @param {string} id - The identifier from which to extract the log.
* @returns {string | undefined} The protocol part of the identifier, or undefined if no protocol is present.
*/
declare function getProtocol(id: string): string | undefined;
export { DYNAMIC_IMPORT_RE, ESM_STATIC_IMPORT_RE, EXPORT_DECAL_RE, EXPORT_DECAL_TYPE_RE, createCommonJS, createResolve, detectSyntax, evalModule, fileURLToPath, findDynamicImports, findExportNames, findExports, findStaticImports, findTypeExports, findTypeImports, getProtocol, hasCJSSyntax, hasESMSyntax, interopDefault, isNodeBuiltin, isValidNodeImport, loadModule, loadURL, lookupNodeModuleSubpath, normalizeid, parseNodeModulePath, parseStaticImport, parseTypeImport, pathToFileURL, resolve, resolveImports, resolveModuleExportNames, resolvePath, resolvePathSync, resolveSync, sanitizeFilePath, sanitizeURIComponent, toDataURL, transformModule };
export type { CommonjsContext, DeclarationExport, DefaultExport, DetectSyntaxOptions, DynamicImport, ESMExport, ESMImport, EvaluateOptions, NamedExport, ParsedStaticImport, ResolveOptions, StaticImport, TypeImport, ValidNodeImportOptions };
+564
View File
@@ -0,0 +1,564 @@
interface ResolveOptions {
/**
* A URL, path or array of URLs/paths to resolve against.
*/
url?: string | URL | (string | URL)[];
/**
* File extensions to consider when resolving modules.
*/
extensions?: string[];
/**
* Conditions to consider when resolving package exports.
*/
conditions?: string[];
}
/**
* Synchronously resolves a module path based on the options provided.
*
* @param {string} id - The identifier or path of the module to resolve.
* @param {ResolveOptions} [options] - Options to resolve the module. See {@link ResolveOptions}.
* @returns {string} The resolved URL as a string.
*/
declare function resolveSync(id: string, options?: ResolveOptions): string;
/**
* Asynchronously resolves a module path based on the given options.
*
* @param {string} id - The identifier or path of the module to resolve.
* @param {ResolveOptions} [options] - Options for resolving the module. See {@link ResolveOptions}.
* @returns {Promise<string>} A promise to resolve the URL as a string.
*/
declare function resolve(id: string, options?: ResolveOptions): Promise<string>;
/**
* Synchronously resolves a module path to a local file path based on the given options.
*
* @param {string} id - The identifier or path of the module to resolve.
* @param {ResolveOptions} [options] - Options to resolve the module. See {@link ResolveOptions}.
* @returns {string} The resolved file path.
*/
declare function resolvePathSync(id: string, options?: ResolveOptions): string;
/**
* Asynchronously resolves a module path to a local file path based on the options provided.
*
* @param {string} id - The identifier or path of the module to resolve.
* @param {ResolveOptions} [options] - Options for resolving the module. See {@link ResolveOptions}.
* @returns {Promise<string>} A promise to resolve to the file path.
*/
declare function resolvePath(id: string, options?: ResolveOptions): Promise<string>;
/**
* Creates a resolver function with default options that can be used to resolve module identifiers.
*
* @param {ResolveOptions} [defaults] - Default options to use for all resolutions. See {@link ResolveOptions}.
* @returns {Function} A resolver function that takes an identifier and an optional URL, and resolves the identifier using the default options and the given URL.
*/
declare function createResolve(defaults?: ResolveOptions): (id: string, url?: ResolveOptions["url"]) => Promise<string>;
/**
* Parses a node module path to extract the directory, name, and subpath.
*
* @param {string} path - The path to parse.
* @returns {Object} An object containing the directory, module name, and subpath of the node module.
*/
declare function parseNodeModulePath(path: string): {
dir?: undefined;
name?: undefined;
subpath?: undefined;
} | {
dir: string;
name: string;
subpath: string | undefined;
};
/**
* Attempts to reverse engineer a subpath export within a node module.
*
* @param {string} path - The path within the node module.
* @returns {Promise<string | undefined>} A promise that resolves to the detected subpath or undefined if not found.
*/
declare function lookupNodeModuleSubpath(path: string): Promise<string | undefined>;
/**
* Represents a general structure for ECMAScript module imports.
*/
interface ESMImport {
/**
* Specifies the type of import: "static" for static imports and "dynamic" for dynamic imports.
*/
type: "static" | "dynamic";
/**
* The full import declaration code snippet as a string.
*/
code: string;
/**
* The starting position (index) of the import declaration in the source code.
*/
start: number;
/**
* The end position (index) of the import declaration in the source code.
*/
end: number;
}
/**
* Represents a static import declaration in an ECMAScript module.
* Extends {@link ESMImport}.
*/
interface StaticImport extends ESMImport {
/**
* Indicates the type of import, specifically a static import.
*/
type: "static";
/**
* Contains the entire import statement as a string, excluding the module specifier.
*/
imports: string;
/**
* The module specifier from which imports are being brought in.
*/
specifier: string;
}
/**
* Represents a parsed static import declaration with detailed components of the import.
* Extends {@link StaticImport}.
*/
interface ParsedStaticImport extends StaticImport {
/**
* The default import name, if any.
* @optional
*/
defaultImport?: string;
/**
* The namespace import name, if any, using the `* as` syntax.
* @optional
*/
namespacedImport?: string;
/**
* An object representing named imports, with their local aliases if specified.
* Each property key is the original name and its value is the alias.
* @optional
*/
namedImports?: {
[name: string]: string;
};
}
/**
* Represents a dynamic import declaration that is loaded at runtime.
* Extends {@link ESMImport}.
*/
interface DynamicImport extends ESMImport {
/**
* Indicates that this is a dynamic import.
*/
type: "dynamic";
/**
* The expression or path to be dynamically imported, typically a module path or URL.
*/
expression: string;
}
/**
* Represents a type-specific import, primarily used for importing types in TypeScript.
* Extends {@link ESMImport} but omits the 'type' to redefine it specifically for type imports.
*/
interface TypeImport extends Omit<ESMImport, "type"> {
/**
* Specifies that this is a type import.
*/
type: "type";
/**
* Contains the entire type import statement as a string, excluding the module specifier.
*/
imports: string;
/**
* The module specifier from which to import types.
*/
specifier: string;
}
/**
* Represents a general structure for ECMAScript module exports.
*/
interface ESMExport {
/**
* Optional explicit type for complex scenarios, often used internally.
* @optional
*/
_type?: "declaration" | "named" | "default" | "star";
/**
* The type of export (declaration, named, default or star).
*/
type: "declaration" | "named" | "default" | "star";
/**
* The specific type of declaration being exported, if applicable.
* @optional
*/
declarationType?: "let" | "var" | "const" | "enum" | "const enum" | "class" | "function" | "async function";
/**
* The full code snippet of the export statement.
*/
code: string;
/**
* The starting position (index) of the export declaration in the source code.
*/
start: number;
/**
* The end position (index) of the export declaration in the source code.
*/
end: number;
/**
* The name of the variable, function or class being exported, if given explicitly.
* @optional
*/
name?: string;
/**
* The name used for default exports when a specific identifier isn't given.
* @optional
*/
defaultName?: string;
/**
* An array of names to export, applicable to named and destructured exports.
*/
names: string[];
/**
* The module specifier, if any, from which exports are being re-exported.
* @optional
*/
specifier?: string;
}
/**
* Represents a declaration export within an ECMAScript module.
* Extends {@link ESMExport}.
*/
interface DeclarationExport extends ESMExport {
/**
* Indicates that this export is a declaration export.
*/
type: "declaration";
/**
* The declaration string, such as 'let', 'const', 'class', etc., describing what is being exported.
*/
declaration: string;
/**
* The name of the declaration to be exported.
*/
name: string;
}
/**
* Represents a named export within an ECMAScript module.
* Extends {@link ESMExport}.
*/
interface NamedExport extends ESMExport {
/**
* Specifies that this export is a named export.
*/
type: "named";
/**
* The export string, containing all exported identifiers.
*/
exports: string;
/**
* An array of names to export.
*/
names: string[];
/**
* The module specifier, if any, from which exports are being re-exported.
* @optional
*/
specifier?: string;
}
/**
* Represents a standard export within an ECMAScript module.
* Extends {@link ESMExport}.
*/
interface DefaultExport extends ESMExport {
/**
* Specifies that this export is a standard export.
*/
type: "default";
}
/**
* Regular expression to match static import statements in JavaScript/TypeScript code.
* @example `import { foo, bar as baz } from 'module'`
*/
declare const ESM_STATIC_IMPORT_RE: RegExp;
/**
* Regular expression to match dynamic import statements in JavaScript/TypeScript code.
* @example `import('module')`
*/
declare const DYNAMIC_IMPORT_RE: RegExp;
/**
* Regular expression to match various types of export declarations including variables, functions, and classes.
* @example `export const num = 1, str = 'hello'; export class Example {}`
*/
declare const EXPORT_DECAL_RE: RegExp;
/**
* Regular expression to match export declarations specifically for types, interfaces, and type aliases in TypeScript.
* @example `export type Result = { success: boolean; }; export interface User { name: string; age: number; };`
*/
declare const EXPORT_DECAL_TYPE_RE: RegExp;
/**
* Finds all static import statements within the given code string.
* @param {string} code - The source code to search for static imports.
* @returns {StaticImport[]} An array of {@link StaticImport} objects representing each static import found.
*/
declare function findStaticImports(code: string): StaticImport[];
/**
* Searches for dynamic import statements in the given source code.
* @param {string} code - The source to search for dynamic imports in.
* @returns {DynamicImport[]} An array of {@link DynamicImport} objects representing each dynamic import found.
*/
declare function findDynamicImports(code: string): DynamicImport[];
/**
* Identifies and returns all type import statements in the given source code.
* This function is specifically targeted at type imports used in TypeScript.
* @param {string} code - The source code to search for type imports.
* @returns {TypeImport[]} An array of {@link TypeImport} objects representing each type import found.
*/
declare function findTypeImports(code: string): TypeImport[];
/**
* Parses a static import or type import to extract detailed import elements such as default, namespace and named imports.
* @param {StaticImport | TypeImport} matched - The matched import statement to parse. See {@link StaticImport} and {@link TypeImport}.
* @returns {ParsedStaticImport} A structured object representing the parsed static import. See {@link ParsedStaticImport}.
*/
declare function parseStaticImport(matched: StaticImport | TypeImport): ParsedStaticImport;
/**
* Parses a static import or type import to extract detailed import elements such as default, namespace and named imports.
* @param {StaticImport | TypeImport} matched - The matched import statement to parse. See {@link StaticImport} and {@link TypeImport}.
* @returns {ParsedStaticImport} A structured object representing the parsed static import. See {@link ParsedStaticImport}.
*/
declare function parseTypeImport(matched: TypeImport | StaticImport): ParsedStaticImport;
/**
* Identifies all export statements in the supplied source code and categorises them into different types such as declarations, named, default and star exports.
* This function processes the code to capture different forms of export statements and normalise their representation for further processing.
*
* @param {string} code - The source code containing the export statements to be analysed.
* @returns {ESMExport[]} An array of {@link ESMExport} objects representing each export found, properly categorised and structured.
*/
declare function findExports(code: string): ESMExport[];
/**
* Searches specifically for type-related exports in TypeScript code, such as exported interfaces, types, and declarations prefixed with 'declare'.
* This function uses specialised regular expressions to identify type exports and normalises them for consistency.
*
* @param {string} code - The TypeScript source code to search for type exports.
* @returns {ESMExport[]} An array of {@link ESMExport} objects representing each type export found.
*/
declare function findTypeExports(code: string): ESMExport[];
/**
* Extracts and returns a list of all export names from the given source.
* This function uses {@link findExports} to retrieve all types of exports and consolidates their names into a single array.
*
* @param {string} code - The source code to search for export names.
* @returns {string[]} An array containing the names of all exports found in the code.
*/
declare function findExportNames(code: string): string[];
/**
* Asynchronously resolves and returns all export names from a module specified by its module identifier.
* This function recursively resolves all explicitly named and asterisked (* as) exports to fully enumerate the exported identifiers.
*
* @param {string} id - The module identifier to resolve.
* @param {ResolveOptions} [options] - Optional settings for resolving the module path, such as the base URL.
* @returns {Promise<string[]>} A promise that resolves to an array of export names from the module.
*/
declare function resolveModuleExportNames(id: string, options?: ResolveOptions): Promise<string[]>;
/**
* Represents the context of a CommonJS environment, providing node-like module resolution capabilities within a module.
*/
interface CommonjsContext {
/**
* The absolute path to the current module file.
*/
__filename: string;
/**
* The directory name of the current module.
*/
__dirname: string;
/**
* A function to require modules as in CommonJS.
*/
require: NodeRequire;
}
/**
* Creates a CommonJS context for a given module URL, enabling `require`, `__filename` and `__dirname` support similar to Node.js.
* This function dynamically generates a `require` function that is context-aware and bound to the location of the given module URL.
*
* @param {string} url - The URL of the module file to create a context for.
* @returns {CommonjsContext} A context object containing `__filename`, `__dirname` and a custom `require` function. See {@link CommonjsContext}.
*/
declare function createCommonJS(url: string): CommonjsContext;
declare function interopDefault(sourceModule: any, opts?: {
preferNamespace?: boolean;
}): any;
/**
* Options for evaluating or transforming modules, extending resolution options with optional URL specifications.
*/
interface EvaluateOptions extends ResolveOptions {
/**
* The URL of the module, which can be specified to override the URL resolved from the module identifier.
* @optional
*/
url?: string;
}
/**
* Loads a module by resolving its identifier to a URL, fetching the module's code and evaluating it.
*
* @param {string} id - The identifier of the module to load.
* @param {EvaluateOptions} options - Optional parameters to resolve and load the module. See {@link EvaluateOptions}.
* @returns {Promise<any>} A promise to resolve to the evaluated module.
* });
*/
declare function loadModule(id: string, options?: EvaluateOptions): Promise<any>;
/**
* Evaluates JavaScript code as a module using a dynamic import from a data URL.
*
* @param {string} code - The code of the module to evaluate.
* @param {EvaluateOptions} options - Includes the original URL of the module for better error mapping. See {@link EvaluateOptions}.
* @returns {Promise<any>} A promise that resolves to the evaluated module or throws an error if the evaluation fails.
*/
declare function evalModule(code: string, options?: EvaluateOptions): Promise<any>;
/**
* Transform module code to handle specific scenarios, such as converting JSON to a module or rewriting import.meta.url.
*
* @param {string} code - The code of the module to transform.
* @param {EvaluateOptions} options - Options to control how the code is transformed. See {@link EvaluateOptions}.
* @returns {Promise<string>} A promise that resolves to the transformed code.
*/
declare function transformModule(code: string, options?: EvaluateOptions): Promise<string>;
/**
* Resolves all import URLs found within the provided code to their absolute URLs, based on the given options.
*
* @param {string} code - The code containing the import directives to resolve.
* @param {EvaluateOptions} [options] - Options to use for resolving imports. See {@link EvaluateOptions}.
* @returns {Promise<string>} A promise that resolves to the code, replacing import URLs with resolved URLs.
*/
declare function resolveImports(code: string, options?: EvaluateOptions): Promise<string>;
/**
* Options for detecting syntax within a code string.
*/
type DetectSyntaxOptions = {
/**
* Indicates whether comments should be stripped from the code before syntax checking.
* @default false
*/
stripComments?: boolean;
};
/**
* Determines if a given code string contains ECMAScript module syntax.
*
* @param {string} code - The source code to analyse.
* @param {DetectSyntaxOptions} opts - See {@link DetectSyntaxOptions}.
* @returns {boolean} `true` if the code contains ESM syntax, otherwise `false`.
*/
declare function hasESMSyntax(code: string, opts?: DetectSyntaxOptions): boolean;
/**
* Determines if a given string of code contains CommonJS syntax.
*
* @param {string} code - The source code to analyse.
* @param {DetectSyntaxOptions} opts - See {@link DetectSyntaxOptions}.
* @returns {boolean} `true` if the code contains CommonJS syntax, `false` otherwise.
*/
declare function hasCJSSyntax(code: string, opts?: DetectSyntaxOptions): boolean;
/**
* Analyses the supplied code to determine if it contains ECMAScript module syntax, CommonJS syntax, or both.
*
* @param {string} code - The source code to analyse.
* @param {DetectSyntaxOptions} opts - See {@link DetectSyntaxOptions}.
* @returns {object} An object indicating the presence of ESM syntax (`hasESM`), CJS syntax (`hasCJS`) and whether both syntaxes are present (`isMixed`).
*/
declare function detectSyntax(code: string, opts?: DetectSyntaxOptions): {
hasESM: boolean;
hasCJS: boolean;
isMixed: boolean;
};
interface ValidNodeImportOptions extends ResolveOptions {
/**
* The contents of the import, which may be analyzed to see if it contains
* CJS or ESM syntax as a last step in checking whether it is a valid import.
*/
code?: string;
/**
* Protocols that are allowed as valid node imports.
*
* @default ['node', 'file', 'data']
*
*/
allowedProtocols?: Array<string>;
/**
* Whether to strip comments from the code before checking for ESM syntax.
*
* @default false
*/
stripComments?: boolean;
}
/**
* Validates whether a given identifier represents a valid node import, based on its protocol, file extension, and optionally its contents.
*
* @param {string} id - The identifier or URL of the import to validate.
* @param {ValidNodeImportOptions} _options - Options for resolving and validating the import. See {@link ValidNodeImportOptions}.
* @returns {Promise<boolean>} A promise that resolves to `true` if the import is valid, otherwise `false`.
*/
declare function isValidNodeImport(id: string, _options?: ValidNodeImportOptions): Promise<boolean>;
/**
* Converts a file URL to a local file system path with normalized slashes.
*
* @param {string | URL} id - The file URL or local path to convert.
* @returns {string} A normalized file system path.
*/
declare function fileURLToPath(id: string | URL): string;
/**
* Converts a local file system path to a file URL.
*
* @param {string | URL} id - The file system path to convert.
* @returns {string} The resulting file URL as a string.
*/
declare function pathToFileURL(id: string | URL): string;
/**
* Sanitises a component of a URI by replacing invalid characters.
*
* @param {string} name - The URI component to sanitise.
* @param {string} [replacement="_"] - The string to replace invalid characters with.
* @returns {string} The sanitised URI component.
*/
declare function sanitizeURIComponent(name?: string, replacement?: string): string;
/**
* Cleans a file path string by sanitising each component of the path.
*
* @param {string} filePath - The file path to sanitise.
* @returns {string} The sanitised file path.
*/
declare function sanitizeFilePath(filePath?: string): string;
/**
* Normalises a module identifier to ensure it has a protocol if missing, handling built-in modules and file paths.
*
* @param {string} id - The identifier to normalise.
* @returns {string} The normalised identifier with the appropriate protocol.
*/
declare function normalizeid(id: string): string;
/**
* Loads the contents of a file from a URL into a string.
*
* @param {string} url - The URL of the file to load.
* @returns {Promise<string>} A promise that resolves to the content of the file.
*/
declare function loadURL(url: string): Promise<string>;
/**
* Converts a string of code into a data URL that can be used for dynamic imports.
*
* @param {string} code - The string of code to convert.
* @returns {string} The data URL containing the encoded code.
*/
declare function toDataURL(code: string): string;
/**
* Checks if a module identifier matches a Node.js built-in module.
*
* @param {string} id - The identifier to check.
* @returns {boolean} `true` if the identifier is a built-in module, otherwise `false`.
*/
declare function isNodeBuiltin(id?: string): boolean;
/**
* Extracts the protocol portion of a given identifier string.
*
* @param {string} id - The identifier from which to extract the log.
* @returns {string | undefined} The protocol part of the identifier, or undefined if no protocol is present.
*/
declare function getProtocol(id: string): string | undefined;
export { DYNAMIC_IMPORT_RE, ESM_STATIC_IMPORT_RE, EXPORT_DECAL_RE, EXPORT_DECAL_TYPE_RE, createCommonJS, createResolve, detectSyntax, evalModule, fileURLToPath, findDynamicImports, findExportNames, findExports, findStaticImports, findTypeExports, findTypeImports, getProtocol, hasCJSSyntax, hasESMSyntax, interopDefault, isNodeBuiltin, isValidNodeImport, loadModule, loadURL, lookupNodeModuleSubpath, normalizeid, parseNodeModulePath, parseStaticImport, parseTypeImport, pathToFileURL, resolve, resolveImports, resolveModuleExportNames, resolvePath, resolvePathSync, resolveSync, sanitizeFilePath, sanitizeURIComponent, toDataURL, transformModule };
export type { CommonjsContext, DeclarationExport, DefaultExport, DetectSyntaxOptions, DynamicImport, ESMExport, ESMImport, EvaluateOptions, NamedExport, ParsedStaticImport, ResolveOptions, StaticImport, TypeImport, ValidNodeImportOptions };
+2708
View File
@@ -0,0 +1,2708 @@
import { tokenizer } from 'acorn';
import { builtinModules, createRequire } from 'node:module';
import fs, { realpathSync, statSync, promises } from 'node:fs';
import { joinURL } from 'ufo';
import { normalize, isAbsolute, extname as extname$1 } from 'pathe';
import { readPackageJSON } from 'pkg-types';
import { fileURLToPath as fileURLToPath$1, pathToFileURL as pathToFileURL$1 } from 'node:url';
import assert from 'node:assert';
import process$1 from 'node:process';
import path, { dirname } from 'node:path';
import v8 from 'node:v8';
import { format, inspect } from 'node:util';
const BUILTIN_MODULES = new Set(builtinModules);
function normalizeSlash(path) {
return path.replace(/\\/g, "/");
}
function isObject(value) {
return value !== null && typeof value === "object";
}
function matchAll(regex, string, addition) {
const matches = [];
for (const match of string.matchAll(regex)) {
matches.push({
...addition,
...match.groups,
code: match[0],
start: match.index,
end: (match.index || 0) + match[0].length
});
}
return matches;
}
function clearImports(imports) {
return (imports || "").replace(/\/\/[^\n]*\n|\/\*.*\*\//g, "").replace(/\s+/g, " ");
}
function getImportNames(cleanedImports) {
const topLevelImports = cleanedImports.replace(/{[^}]*}/, "");
const namespacedImport = topLevelImports.match(/\* as \s*(\S*)/)?.[1];
const defaultImport = topLevelImports.split(",").find((index) => !/[*{}]/.test(index))?.trim() || void 0;
return {
namespacedImport,
defaultImport
};
}
/**
* @typedef ErrnoExceptionFields
* @property {number | undefined} [errnode]
* @property {string | undefined} [code]
* @property {string | undefined} [path]
* @property {string | undefined} [syscall]
* @property {string | undefined} [url]
*
* @typedef {Error & ErrnoExceptionFields} ErrnoException
*/
const own$1 = {}.hasOwnProperty;
const classRegExp = /^([A-Z][a-z\d]*)+$/;
// Sorted by a rough estimate on most frequently used entries.
const kTypes = new Set([
'string',
'function',
'number',
'object',
// Accept 'Function' and 'Object' as alternative to the lower cased version.
'Function',
'Object',
'boolean',
'bigint',
'symbol'
]);
const codes = {};
/**
* Create a list string in the form like 'A and B' or 'A, B, ..., and Z'.
* We cannot use Intl.ListFormat because it's not available in
* --without-intl builds.
*
* @param {Array<string>} array
* An array of strings.
* @param {string} [type]
* The list type to be inserted before the last element.
* @returns {string}
*/
function formatList(array, type = 'and') {
return array.length < 3
? array.join(` ${type} `)
: `${array.slice(0, -1).join(', ')}, ${type} ${array[array.length - 1]}`
}
/** @type {Map<string, MessageFunction | string>} */
const messages = new Map();
const nodeInternalPrefix = '__node_internal_';
/** @type {number} */
let userStackTraceLimit;
codes.ERR_INVALID_ARG_TYPE = createError(
'ERR_INVALID_ARG_TYPE',
/**
* @param {string} name
* @param {Array<string> | string} expected
* @param {unknown} actual
*/
(name, expected, actual) => {
assert.ok(typeof name === 'string', "'name' must be a string");
if (!Array.isArray(expected)) {
expected = [expected];
}
let message = 'The ';
if (name.endsWith(' argument')) {
// For cases like 'first argument'
message += `${name} `;
} else {
const type = name.includes('.') ? 'property' : 'argument';
message += `"${name}" ${type} `;
}
message += 'must be ';
/** @type {Array<string>} */
const types = [];
/** @type {Array<string>} */
const instances = [];
/** @type {Array<string>} */
const other = [];
for (const value of expected) {
assert.ok(
typeof value === 'string',
'All expected entries have to be of type string'
);
if (kTypes.has(value)) {
types.push(value.toLowerCase());
} else if (classRegExp.exec(value) === null) {
assert.ok(
value !== 'object',
'The value "object" should be written as "Object"'
);
other.push(value);
} else {
instances.push(value);
}
}
// Special handle `object` in case other instances are allowed to outline
// the differences between each other.
if (instances.length > 0) {
const pos = types.indexOf('object');
if (pos !== -1) {
types.slice(pos, 1);
instances.push('Object');
}
}
if (types.length > 0) {
message += `${types.length > 1 ? 'one of type' : 'of type'} ${formatList(
types,
'or'
)}`;
if (instances.length > 0 || other.length > 0) message += ' or ';
}
if (instances.length > 0) {
message += `an instance of ${formatList(instances, 'or')}`;
if (other.length > 0) message += ' or ';
}
if (other.length > 0) {
if (other.length > 1) {
message += `one of ${formatList(other, 'or')}`;
} else {
if (other[0].toLowerCase() !== other[0]) message += 'an ';
message += `${other[0]}`;
}
}
message += `. Received ${determineSpecificType(actual)}`;
return message
},
TypeError
);
codes.ERR_INVALID_MODULE_SPECIFIER = createError(
'ERR_INVALID_MODULE_SPECIFIER',
/**
* @param {string} request
* @param {string} reason
* @param {string} [base]
*/
(request, reason, base = undefined) => {
return `Invalid module "${request}" ${reason}${
base ? ` imported from ${base}` : ''
}`
},
TypeError
);
codes.ERR_INVALID_PACKAGE_CONFIG = createError(
'ERR_INVALID_PACKAGE_CONFIG',
/**
* @param {string} path
* @param {string} [base]
* @param {string} [message]
*/
(path, base, message) => {
return `Invalid package config ${path}${
base ? ` while importing ${base}` : ''
}${message ? `. ${message}` : ''}`
},
Error
);
codes.ERR_INVALID_PACKAGE_TARGET = createError(
'ERR_INVALID_PACKAGE_TARGET',
/**
* @param {string} packagePath
* @param {string} key
* @param {unknown} target
* @param {boolean} [isImport=false]
* @param {string} [base]
*/
(packagePath, key, target, isImport = false, base = undefined) => {
const relatedError =
typeof target === 'string' &&
!isImport &&
target.length > 0 &&
!target.startsWith('./');
if (key === '.') {
assert.ok(isImport === false);
return (
`Invalid "exports" main target ${JSON.stringify(target)} defined ` +
`in the package config ${packagePath}package.json${
base ? ` imported from ${base}` : ''
}${relatedError ? '; targets must start with "./"' : ''}`
)
}
return `Invalid "${
isImport ? 'imports' : 'exports'
}" target ${JSON.stringify(
target
)} defined for '${key}' in the package config ${packagePath}package.json${
base ? ` imported from ${base}` : ''
}${relatedError ? '; targets must start with "./"' : ''}`
},
Error
);
codes.ERR_MODULE_NOT_FOUND = createError(
'ERR_MODULE_NOT_FOUND',
/**
* @param {string} path
* @param {string} base
* @param {boolean} [exactUrl]
*/
(path, base, exactUrl = false) => {
return `Cannot find ${
exactUrl ? 'module' : 'package'
} '${path}' imported from ${base}`
},
Error
);
codes.ERR_NETWORK_IMPORT_DISALLOWED = createError(
'ERR_NETWORK_IMPORT_DISALLOWED',
"import of '%s' by %s is not supported: %s",
Error
);
codes.ERR_PACKAGE_IMPORT_NOT_DEFINED = createError(
'ERR_PACKAGE_IMPORT_NOT_DEFINED',
/**
* @param {string} specifier
* @param {string} packagePath
* @param {string} base
*/
(specifier, packagePath, base) => {
return `Package import specifier "${specifier}" is not defined${
packagePath ? ` in package ${packagePath}package.json` : ''
} imported from ${base}`
},
TypeError
);
codes.ERR_PACKAGE_PATH_NOT_EXPORTED = createError(
'ERR_PACKAGE_PATH_NOT_EXPORTED',
/**
* @param {string} packagePath
* @param {string} subpath
* @param {string} [base]
*/
(packagePath, subpath, base = undefined) => {
if (subpath === '.')
return `No "exports" main defined in ${packagePath}package.json${
base ? ` imported from ${base}` : ''
}`
return `Package subpath '${subpath}' is not defined by "exports" in ${packagePath}package.json${
base ? ` imported from ${base}` : ''
}`
},
Error
);
codes.ERR_UNSUPPORTED_DIR_IMPORT = createError(
'ERR_UNSUPPORTED_DIR_IMPORT',
"Directory import '%s' is not supported " +
'resolving ES modules imported from %s',
Error
);
codes.ERR_UNSUPPORTED_RESOLVE_REQUEST = createError(
'ERR_UNSUPPORTED_RESOLVE_REQUEST',
'Failed to resolve module specifier "%s" from "%s": Invalid relative URL or base scheme is not hierarchical.',
TypeError
);
codes.ERR_UNKNOWN_FILE_EXTENSION = createError(
'ERR_UNKNOWN_FILE_EXTENSION',
/**
* @param {string} extension
* @param {string} path
*/
(extension, path) => {
return `Unknown file extension "${extension}" for ${path}`
},
TypeError
);
codes.ERR_INVALID_ARG_VALUE = createError(
'ERR_INVALID_ARG_VALUE',
/**
* @param {string} name
* @param {unknown} value
* @param {string} [reason='is invalid']
*/
(name, value, reason = 'is invalid') => {
let inspected = inspect(value);
if (inspected.length > 128) {
inspected = `${inspected.slice(0, 128)}...`;
}
const type = name.includes('.') ? 'property' : 'argument';
return `The ${type} '${name}' ${reason}. Received ${inspected}`
},
TypeError
// Note: extra classes have been shaken out.
// , RangeError
);
/**
* Utility function for registering the error codes. Only used here. Exported
* *only* to allow for testing.
* @param {string} sym
* @param {MessageFunction | string} value
* @param {ErrorConstructor} constructor
* @returns {new (...parameters: Array<any>) => Error}
*/
function createError(sym, value, constructor) {
// Special case for SystemError that formats the error message differently
// The SystemErrors only have SystemError as their base classes.
messages.set(sym, value);
return makeNodeErrorWithCode(constructor, sym)
}
/**
* @param {ErrorConstructor} Base
* @param {string} key
* @returns {ErrorConstructor}
*/
function makeNodeErrorWithCode(Base, key) {
// @ts-expect-error Its a Node error.
return NodeError
/**
* @param {Array<unknown>} parameters
*/
function NodeError(...parameters) {
const limit = Error.stackTraceLimit;
if (isErrorStackTraceLimitWritable()) Error.stackTraceLimit = 0;
const error = new Base();
// Reset the limit and setting the name property.
if (isErrorStackTraceLimitWritable()) Error.stackTraceLimit = limit;
const message = getMessage(key, parameters, error);
Object.defineProperties(error, {
// Note: no need to implement `kIsNodeError` symbol, would be hard,
// probably.
message: {
value: message,
enumerable: false,
writable: true,
configurable: true
},
toString: {
/** @this {Error} */
value() {
return `${this.name} [${key}]: ${this.message}`
},
enumerable: false,
writable: true,
configurable: true
}
});
captureLargerStackTrace(error);
// @ts-expect-error Its a Node error.
error.code = key;
return error
}
}
/**
* @returns {boolean}
*/
function isErrorStackTraceLimitWritable() {
// Do no touch Error.stackTraceLimit as V8 would attempt to install
// it again during deserialization.
try {
if (v8.startupSnapshot.isBuildingSnapshot()) {
return false
}
} catch {}
const desc = Object.getOwnPropertyDescriptor(Error, 'stackTraceLimit');
if (desc === undefined) {
return Object.isExtensible(Error)
}
return own$1.call(desc, 'writable') && desc.writable !== undefined
? desc.writable
: desc.set !== undefined
}
/**
* This function removes unnecessary frames from Node.js core errors.
* @template {(...parameters: unknown[]) => unknown} T
* @param {T} wrappedFunction
* @returns {T}
*/
function hideStackFrames(wrappedFunction) {
// We rename the functions that will be hidden to cut off the stacktrace
// at the outermost one
const hidden = nodeInternalPrefix + wrappedFunction.name;
Object.defineProperty(wrappedFunction, 'name', {value: hidden});
return wrappedFunction
}
const captureLargerStackTrace = hideStackFrames(
/**
* @param {Error} error
* @returns {Error}
*/
// @ts-expect-error: fine
function (error) {
const stackTraceLimitIsWritable = isErrorStackTraceLimitWritable();
if (stackTraceLimitIsWritable) {
userStackTraceLimit = Error.stackTraceLimit;
Error.stackTraceLimit = Number.POSITIVE_INFINITY;
}
Error.captureStackTrace(error);
// Reset the limit
if (stackTraceLimitIsWritable) Error.stackTraceLimit = userStackTraceLimit;
return error
}
);
/**
* @param {string} key
* @param {Array<unknown>} parameters
* @param {Error} self
* @returns {string}
*/
function getMessage(key, parameters, self) {
const message = messages.get(key);
assert.ok(message !== undefined, 'expected `message` to be found');
if (typeof message === 'function') {
assert.ok(
message.length <= parameters.length, // Default options do not count.
`Code: ${key}; The provided arguments length (${parameters.length}) does not ` +
`match the required ones (${message.length}).`
);
return Reflect.apply(message, self, parameters)
}
const regex = /%[dfijoOs]/g;
let expectedLength = 0;
while (regex.exec(message) !== null) expectedLength++;
assert.ok(
expectedLength === parameters.length,
`Code: ${key}; The provided arguments length (${parameters.length}) does not ` +
`match the required ones (${expectedLength}).`
);
if (parameters.length === 0) return message
parameters.unshift(message);
return Reflect.apply(format, null, parameters)
}
/**
* Determine the specific type of a value for type-mismatch errors.
* @param {unknown} value
* @returns {string}
*/
function determineSpecificType(value) {
if (value === null || value === undefined) {
return String(value)
}
if (typeof value === 'function' && value.name) {
return `function ${value.name}`
}
if (typeof value === 'object') {
if (value.constructor && value.constructor.name) {
return `an instance of ${value.constructor.name}`
}
return `${inspect(value, {depth: -1})}`
}
let inspected = inspect(value, {colors: false});
if (inspected.length > 28) {
inspected = `${inspected.slice(0, 25)}...`;
}
return `type ${typeof value} (${inspected})`
}
// Manually “tree shaken” from:
// <https://github.com/nodejs/node/blob/7c3dce0/lib/internal/modules/package_json_reader.js>
// Last checked on: Apr 29, 2024.
// Removed the native dependency.
// Also: no need to cache, we do that in resolve already.
const hasOwnProperty$1 = {}.hasOwnProperty;
const {ERR_INVALID_PACKAGE_CONFIG: ERR_INVALID_PACKAGE_CONFIG$1} = codes;
/** @type {Map<string, PackageConfig>} */
const cache = new Map();
/**
* @param {string} jsonPath
* @param {{specifier: URL | string, base?: URL}} options
* @returns {PackageConfig}
*/
function read(jsonPath, {base, specifier}) {
const existing = cache.get(jsonPath);
if (existing) {
return existing
}
/** @type {string | undefined} */
let string;
try {
string = fs.readFileSync(path.toNamespacedPath(jsonPath), 'utf8');
} catch (error) {
const exception = /** @type {ErrnoException} */ (error);
if (exception.code !== 'ENOENT') {
throw exception
}
}
/** @type {PackageConfig} */
const result = {
exists: false,
pjsonPath: jsonPath,
main: undefined,
name: undefined,
type: 'none', // Ignore unknown types for forwards compatibility
exports: undefined,
imports: undefined
};
if (string !== undefined) {
/** @type {Record<string, unknown>} */
let parsed;
try {
parsed = JSON.parse(string);
} catch (error_) {
const cause = /** @type {ErrnoException} */ (error_);
const error = new ERR_INVALID_PACKAGE_CONFIG$1(
jsonPath,
(base ? `"${specifier}" from ` : '') + fileURLToPath$1(base || specifier),
cause.message
);
error.cause = cause;
throw error
}
result.exists = true;
if (
hasOwnProperty$1.call(parsed, 'name') &&
typeof parsed.name === 'string'
) {
result.name = parsed.name;
}
if (
hasOwnProperty$1.call(parsed, 'main') &&
typeof parsed.main === 'string'
) {
result.main = parsed.main;
}
if (hasOwnProperty$1.call(parsed, 'exports')) {
// @ts-expect-error: assume valid.
result.exports = parsed.exports;
}
if (hasOwnProperty$1.call(parsed, 'imports')) {
// @ts-expect-error: assume valid.
result.imports = parsed.imports;
}
// Ignore unknown types for forwards compatibility
if (
hasOwnProperty$1.call(parsed, 'type') &&
(parsed.type === 'commonjs' || parsed.type === 'module')
) {
result.type = parsed.type;
}
}
cache.set(jsonPath, result);
return result
}
/**
* @param {URL | string} resolved
* @returns {PackageConfig}
*/
function getPackageScopeConfig(resolved) {
// Note: in Node, this is now a native module.
let packageJSONUrl = new URL('package.json', resolved);
while (true) {
const packageJSONPath = packageJSONUrl.pathname;
if (packageJSONPath.endsWith('node_modules/package.json')) {
break
}
const packageConfig = read(fileURLToPath$1(packageJSONUrl), {
specifier: resolved
});
if (packageConfig.exists) {
return packageConfig
}
const lastPackageJSONUrl = packageJSONUrl;
packageJSONUrl = new URL('../package.json', packageJSONUrl);
// Terminates at root where ../package.json equals ../../package.json
// (can't just check "/package.json" for Windows support).
if (packageJSONUrl.pathname === lastPackageJSONUrl.pathname) {
break
}
}
const packageJSONPath = fileURLToPath$1(packageJSONUrl);
// ^^ Note: in Node, this is now a native module.
return {
pjsonPath: packageJSONPath,
exists: false,
type: 'none'
}
}
/**
* Returns the package type for a given URL.
* @param {URL} url - The URL to get the package type for.
* @returns {PackageType}
*/
function getPackageType(url) {
// To do @anonrig: Write a C++ function that returns only "type".
return getPackageScopeConfig(url).type
}
// Manually “tree shaken” from:
// <https://github.com/nodejs/node/blob/7c3dce0/lib/internal/modules/esm/get_format.js>
// Last checked on: Apr 29, 2024.
const {ERR_UNKNOWN_FILE_EXTENSION} = codes;
const hasOwnProperty = {}.hasOwnProperty;
/** @type {Record<string, string>} */
const extensionFormatMap = {
// @ts-expect-error: hush.
__proto__: null,
'.cjs': 'commonjs',
'.js': 'module',
'.json': 'json',
'.mjs': 'module'
};
/**
* @param {string | null} mime
* @returns {string | null}
*/
function mimeToFormat(mime) {
if (
mime &&
/\s*(text|application)\/javascript\s*(;\s*charset=utf-?8\s*)?/i.test(mime)
)
return 'module'
if (mime === 'application/json') return 'json'
return null
}
/**
* @callback ProtocolHandler
* @param {URL} parsed
* @param {{parentURL: string, source?: Buffer}} context
* @param {boolean} ignoreErrors
* @returns {string | null | void}
*/
/**
* @type {Record<string, ProtocolHandler>}
*/
const protocolHandlers = {
// @ts-expect-error: hush.
__proto__: null,
'data:': getDataProtocolModuleFormat,
'file:': getFileProtocolModuleFormat,
'http:': getHttpProtocolModuleFormat,
'https:': getHttpProtocolModuleFormat,
'node:'() {
return 'builtin'
}
};
/**
* @param {URL} parsed
*/
function getDataProtocolModuleFormat(parsed) {
const {1: mime} = /^([^/]+\/[^;,]+)[^,]*?(;base64)?,/.exec(
parsed.pathname
) || [null, null, null];
return mimeToFormat(mime)
}
/**
* Returns the file extension from a URL.
*
* Should give similar result to
* `require('node:path').extname(require('node:url').fileURLToPath(url))`
* when used with a `file:` URL.
*
* @param {URL} url
* @returns {string}
*/
function extname(url) {
const pathname = url.pathname;
let index = pathname.length;
while (index--) {
const code = pathname.codePointAt(index);
if (code === 47 /* `/` */) {
return ''
}
if (code === 46 /* `.` */) {
return pathname.codePointAt(index - 1) === 47 /* `/` */
? ''
: pathname.slice(index)
}
}
return ''
}
/**
* @type {ProtocolHandler}
*/
function getFileProtocolModuleFormat(url, _context, ignoreErrors) {
const value = extname(url);
if (value === '.js') {
const packageType = getPackageType(url);
if (packageType !== 'none') {
return packageType
}
return 'commonjs'
}
if (value === '') {
const packageType = getPackageType(url);
// Legacy behavior
if (packageType === 'none' || packageType === 'commonjs') {
return 'commonjs'
}
// Note: we dont implement WASM, so we dont need
// `getFormatOfExtensionlessFile` from `formats`.
return 'module'
}
const format = extensionFormatMap[value];
if (format) return format
// Explicit undefined return indicates load hook should rerun format check
if (ignoreErrors) {
return undefined
}
const filepath = fileURLToPath$1(url);
throw new ERR_UNKNOWN_FILE_EXTENSION(value, filepath)
}
function getHttpProtocolModuleFormat() {
// To do: HTTPS imports.
}
/**
* @param {URL} url
* @param {{parentURL: string}} context
* @returns {string | null}
*/
function defaultGetFormatWithoutErrors(url, context) {
const protocol = url.protocol;
if (!hasOwnProperty.call(protocolHandlers, protocol)) {
return null
}
return protocolHandlers[protocol](url, context, true) || null
}
// Manually “tree shaken” from:
// <https://github.com/nodejs/node/blob/81a9a97/lib/internal/modules/esm/utils.js>
// Last checked on: Apr 29, 2024.
// In Node itself these values are populated from CLI arguments, before any
// user code runs.
// Here we just define the defaults.
const DEFAULT_CONDITIONS = Object.freeze(['node', 'import']);
const DEFAULT_CONDITIONS_SET$1 = new Set(DEFAULT_CONDITIONS);
/**
* Returns the default conditions for ES module loading, as a Set.
*/
function getDefaultConditionsSet() {
return DEFAULT_CONDITIONS_SET$1
}
/**
* @param {Array<string>} [conditions]
* @returns {Set<string>}
*/
function getConditionsSet(conditions) {
return getDefaultConditionsSet()
}
// Manually “tree shaken” from:
// <https://github.com/nodejs/node/blob/81a9a97/lib/internal/modules/esm/resolve.js>
// Last checked on: Apr 29, 2024.
const RegExpPrototypeSymbolReplace = RegExp.prototype[Symbol.replace];
const {
ERR_INVALID_MODULE_SPECIFIER,
ERR_INVALID_PACKAGE_CONFIG,
ERR_INVALID_PACKAGE_TARGET,
ERR_MODULE_NOT_FOUND,
ERR_PACKAGE_IMPORT_NOT_DEFINED,
ERR_PACKAGE_PATH_NOT_EXPORTED,
ERR_UNSUPPORTED_DIR_IMPORT,
ERR_UNSUPPORTED_RESOLVE_REQUEST
} = codes;
const own = {}.hasOwnProperty;
const invalidSegmentRegEx =
/(^|\\|\/)((\.|%2e)(\.|%2e)?|(n|%6e|%4e)(o|%6f|%4f)(d|%64|%44)(e|%65|%45)(_|%5f)(m|%6d|%4d)(o|%6f|%4f)(d|%64|%44)(u|%75|%55)(l|%6c|%4c)(e|%65|%45)(s|%73|%53))?(\\|\/|$)/i;
const deprecatedInvalidSegmentRegEx =
/(^|\\|\/)((\.|%2e)(\.|%2e)?|(n|%6e|%4e)(o|%6f|%4f)(d|%64|%44)(e|%65|%45)(_|%5f)(m|%6d|%4d)(o|%6f|%4f)(d|%64|%44)(u|%75|%55)(l|%6c|%4c)(e|%65|%45)(s|%73|%53))(\\|\/|$)/i;
const invalidPackageNameRegEx = /^\.|%|\\/;
const patternRegEx = /\*/g;
const encodedSeparatorRegEx = /%2f|%5c/i;
/** @type {Set<string>} */
const emittedPackageWarnings = new Set();
const doubleSlashRegEx = /[/\\]{2}/;
/**
*
* @param {string} target
* @param {string} request
* @param {string} match
* @param {URL} packageJsonUrl
* @param {boolean} internal
* @param {URL} base
* @param {boolean} isTarget
*/
function emitInvalidSegmentDeprecation(
target,
request,
match,
packageJsonUrl,
internal,
base,
isTarget
) {
// @ts-expect-error: apparently it does exist, TS.
if (process$1.noDeprecation) {
return
}
const pjsonPath = fileURLToPath$1(packageJsonUrl);
const double = doubleSlashRegEx.exec(isTarget ? target : request) !== null;
process$1.emitWarning(
`Use of deprecated ${
double ? 'double slash' : 'leading or trailing slash matching'
} resolving "${target}" for module ` +
`request "${request}" ${
request === match ? '' : `matched to "${match}" `
}in the "${
internal ? 'imports' : 'exports'
}" field module resolution of the package at ${pjsonPath}${
base ? ` imported from ${fileURLToPath$1(base)}` : ''
}.`,
'DeprecationWarning',
'DEP0166'
);
}
/**
* @param {URL} url
* @param {URL} packageJsonUrl
* @param {URL} base
* @param {string} [main]
* @returns {void}
*/
function emitLegacyIndexDeprecation(url, packageJsonUrl, base, main) {
// @ts-expect-error: apparently it does exist, TS.
if (process$1.noDeprecation) {
return
}
const format = defaultGetFormatWithoutErrors(url, {parentURL: base.href});
if (format !== 'module') return
const urlPath = fileURLToPath$1(url.href);
const packagePath = fileURLToPath$1(new URL('.', packageJsonUrl));
const basePath = fileURLToPath$1(base);
if (!main) {
process$1.emitWarning(
`No "main" or "exports" field defined in the package.json for ${packagePath} resolving the main entry point "${urlPath.slice(
packagePath.length
)}", imported from ${basePath}.\nDefault "index" lookups for the main are deprecated for ES modules.`,
'DeprecationWarning',
'DEP0151'
);
} else if (path.resolve(packagePath, main) !== urlPath) {
process$1.emitWarning(
`Package ${packagePath} has a "main" field set to "${main}", ` +
`excluding the full filename and extension to the resolved file at "${urlPath.slice(
packagePath.length
)}", imported from ${basePath}.\n Automatic extension resolution of the "main" field is ` +
'deprecated for ES modules.',
'DeprecationWarning',
'DEP0151'
);
}
}
/**
* @param {string} path
* @returns {Stats | undefined}
*/
function tryStatSync(path) {
// Note: from Node 15 onwards we can use `throwIfNoEntry: false` instead.
try {
return statSync(path)
} catch {
// Note: in Node code this returns `new Stats`,
// but in Node 22 thats marked as a deprecated internal API.
// Which, well, we kinda are, but still to prevent that warning,
// just yield `undefined`.
}
}
/**
* Legacy CommonJS main resolution:
* 1. let M = pkg_url + (json main field)
* 2. TRY(M, M.js, M.json, M.node)
* 3. TRY(M/index.js, M/index.json, M/index.node)
* 4. TRY(pkg_url/index.js, pkg_url/index.json, pkg_url/index.node)
* 5. NOT_FOUND
*
* @param {URL} url
* @returns {boolean}
*/
function fileExists(url) {
const stats = statSync(url, {throwIfNoEntry: false});
const isFile = stats ? stats.isFile() : undefined;
return isFile === null || isFile === undefined ? false : isFile
}
/**
* @param {URL} packageJsonUrl
* @param {PackageConfig} packageConfig
* @param {URL} base
* @returns {URL}
*/
function legacyMainResolve(packageJsonUrl, packageConfig, base) {
/** @type {URL | undefined} */
let guess;
if (packageConfig.main !== undefined) {
guess = new URL(packageConfig.main, packageJsonUrl);
// Note: fs check redundances will be handled by Descriptor cache here.
if (fileExists(guess)) return guess
const tries = [
`./${packageConfig.main}.js`,
`./${packageConfig.main}.json`,
`./${packageConfig.main}.node`,
`./${packageConfig.main}/index.js`,
`./${packageConfig.main}/index.json`,
`./${packageConfig.main}/index.node`
];
let i = -1;
while (++i < tries.length) {
guess = new URL(tries[i], packageJsonUrl);
if (fileExists(guess)) break
guess = undefined;
}
if (guess) {
emitLegacyIndexDeprecation(
guess,
packageJsonUrl,
base,
packageConfig.main
);
return guess
}
// Fallthrough.
}
const tries = ['./index.js', './index.json', './index.node'];
let i = -1;
while (++i < tries.length) {
guess = new URL(tries[i], packageJsonUrl);
if (fileExists(guess)) break
guess = undefined;
}
if (guess) {
emitLegacyIndexDeprecation(guess, packageJsonUrl, base, packageConfig.main);
return guess
}
// Not found.
throw new ERR_MODULE_NOT_FOUND(
fileURLToPath$1(new URL('.', packageJsonUrl)),
fileURLToPath$1(base)
)
}
/**
* @param {URL} resolved
* @param {URL} base
* @param {boolean} [preserveSymlinks]
* @returns {URL}
*/
function finalizeResolution(resolved, base, preserveSymlinks) {
if (encodedSeparatorRegEx.exec(resolved.pathname) !== null) {
throw new ERR_INVALID_MODULE_SPECIFIER(
resolved.pathname,
'must not include encoded "/" or "\\" characters',
fileURLToPath$1(base)
)
}
/** @type {string} */
let filePath;
try {
filePath = fileURLToPath$1(resolved);
} catch (error) {
const cause = /** @type {ErrnoException} */ (error);
Object.defineProperty(cause, 'input', {value: String(resolved)});
Object.defineProperty(cause, 'module', {value: String(base)});
throw cause
}
const stats = tryStatSync(
filePath.endsWith('/') ? filePath.slice(-1) : filePath
);
if (stats && stats.isDirectory()) {
const error = new ERR_UNSUPPORTED_DIR_IMPORT(filePath, fileURLToPath$1(base));
// @ts-expect-error Add this for `import.meta.resolve`.
error.url = String(resolved);
throw error
}
if (!stats || !stats.isFile()) {
const error = new ERR_MODULE_NOT_FOUND(
filePath || resolved.pathname,
base && fileURLToPath$1(base),
true
);
// @ts-expect-error Add this for `import.meta.resolve`.
error.url = String(resolved);
throw error
}
{
const real = realpathSync(filePath);
const {search, hash} = resolved;
resolved = pathToFileURL$1(real + (filePath.endsWith(path.sep) ? '/' : ''));
resolved.search = search;
resolved.hash = hash;
}
return resolved
}
/**
* @param {string} specifier
* @param {URL | undefined} packageJsonUrl
* @param {URL} base
* @returns {Error}
*/
function importNotDefined(specifier, packageJsonUrl, base) {
return new ERR_PACKAGE_IMPORT_NOT_DEFINED(
specifier,
packageJsonUrl && fileURLToPath$1(new URL('.', packageJsonUrl)),
fileURLToPath$1(base)
)
}
/**
* @param {string} subpath
* @param {URL} packageJsonUrl
* @param {URL} base
* @returns {Error}
*/
function exportsNotFound(subpath, packageJsonUrl, base) {
return new ERR_PACKAGE_PATH_NOT_EXPORTED(
fileURLToPath$1(new URL('.', packageJsonUrl)),
subpath,
base && fileURLToPath$1(base)
)
}
/**
* @param {string} request
* @param {string} match
* @param {URL} packageJsonUrl
* @param {boolean} internal
* @param {URL} [base]
* @returns {never}
*/
function throwInvalidSubpath(request, match, packageJsonUrl, internal, base) {
const reason = `request is not a valid match in pattern "${match}" for the "${
internal ? 'imports' : 'exports'
}" resolution of ${fileURLToPath$1(packageJsonUrl)}`;
throw new ERR_INVALID_MODULE_SPECIFIER(
request,
reason,
base && fileURLToPath$1(base)
)
}
/**
* @param {string} subpath
* @param {unknown} target
* @param {URL} packageJsonUrl
* @param {boolean} internal
* @param {URL} [base]
* @returns {Error}
*/
function invalidPackageTarget(subpath, target, packageJsonUrl, internal, base) {
target =
typeof target === 'object' && target !== null
? JSON.stringify(target, null, '')
: `${target}`;
return new ERR_INVALID_PACKAGE_TARGET(
fileURLToPath$1(new URL('.', packageJsonUrl)),
subpath,
target,
internal,
base && fileURLToPath$1(base)
)
}
/**
* @param {string} target
* @param {string} subpath
* @param {string} match
* @param {URL} packageJsonUrl
* @param {URL} base
* @param {boolean} pattern
* @param {boolean} internal
* @param {boolean} isPathMap
* @param {Set<string> | undefined} conditions
* @returns {URL}
*/
function resolvePackageTargetString(
target,
subpath,
match,
packageJsonUrl,
base,
pattern,
internal,
isPathMap,
conditions
) {
if (subpath !== '' && !pattern && target[target.length - 1] !== '/')
throw invalidPackageTarget(match, target, packageJsonUrl, internal, base)
if (!target.startsWith('./')) {
if (internal && !target.startsWith('../') && !target.startsWith('/')) {
let isURL = false;
try {
new URL(target);
isURL = true;
} catch {
// Continue regardless of error.
}
if (!isURL) {
const exportTarget = pattern
? RegExpPrototypeSymbolReplace.call(
patternRegEx,
target,
() => subpath
)
: target + subpath;
return packageResolve(exportTarget, packageJsonUrl, conditions)
}
}
throw invalidPackageTarget(match, target, packageJsonUrl, internal, base)
}
if (invalidSegmentRegEx.exec(target.slice(2)) !== null) {
if (deprecatedInvalidSegmentRegEx.exec(target.slice(2)) === null) {
if (!isPathMap) {
const request = pattern
? match.replace('*', () => subpath)
: match + subpath;
const resolvedTarget = pattern
? RegExpPrototypeSymbolReplace.call(
patternRegEx,
target,
() => subpath
)
: target;
emitInvalidSegmentDeprecation(
resolvedTarget,
request,
match,
packageJsonUrl,
internal,
base,
true
);
}
} else {
throw invalidPackageTarget(match, target, packageJsonUrl, internal, base)
}
}
const resolved = new URL(target, packageJsonUrl);
const resolvedPath = resolved.pathname;
const packagePath = new URL('.', packageJsonUrl).pathname;
if (!resolvedPath.startsWith(packagePath))
throw invalidPackageTarget(match, target, packageJsonUrl, internal, base)
if (subpath === '') return resolved
if (invalidSegmentRegEx.exec(subpath) !== null) {
const request = pattern
? match.replace('*', () => subpath)
: match + subpath;
if (deprecatedInvalidSegmentRegEx.exec(subpath) === null) {
if (!isPathMap) {
const resolvedTarget = pattern
? RegExpPrototypeSymbolReplace.call(
patternRegEx,
target,
() => subpath
)
: target;
emitInvalidSegmentDeprecation(
resolvedTarget,
request,
match,
packageJsonUrl,
internal,
base,
false
);
}
} else {
throwInvalidSubpath(request, match, packageJsonUrl, internal, base);
}
}
if (pattern) {
return new URL(
RegExpPrototypeSymbolReplace.call(
patternRegEx,
resolved.href,
() => subpath
)
)
}
return new URL(subpath, resolved)
}
/**
* @param {string} key
* @returns {boolean}
*/
function isArrayIndex(key) {
const keyNumber = Number(key);
if (`${keyNumber}` !== key) return false
return keyNumber >= 0 && keyNumber < 0xff_ff_ff_ff
}
/**
* @param {URL} packageJsonUrl
* @param {unknown} target
* @param {string} subpath
* @param {string} packageSubpath
* @param {URL} base
* @param {boolean} pattern
* @param {boolean} internal
* @param {boolean} isPathMap
* @param {Set<string> | undefined} conditions
* @returns {URL | null}
*/
function resolvePackageTarget(
packageJsonUrl,
target,
subpath,
packageSubpath,
base,
pattern,
internal,
isPathMap,
conditions
) {
if (typeof target === 'string') {
return resolvePackageTargetString(
target,
subpath,
packageSubpath,
packageJsonUrl,
base,
pattern,
internal,
isPathMap,
conditions
)
}
if (Array.isArray(target)) {
/** @type {Array<unknown>} */
const targetList = target;
if (targetList.length === 0) return null
/** @type {ErrnoException | null | undefined} */
let lastException;
let i = -1;
while (++i < targetList.length) {
const targetItem = targetList[i];
/** @type {URL | null} */
let resolveResult;
try {
resolveResult = resolvePackageTarget(
packageJsonUrl,
targetItem,
subpath,
packageSubpath,
base,
pattern,
internal,
isPathMap,
conditions
);
} catch (error) {
const exception = /** @type {ErrnoException} */ (error);
lastException = exception;
if (exception.code === 'ERR_INVALID_PACKAGE_TARGET') continue
throw error
}
if (resolveResult === undefined) continue
if (resolveResult === null) {
lastException = null;
continue
}
return resolveResult
}
if (lastException === undefined || lastException === null) {
return null
}
throw lastException
}
if (typeof target === 'object' && target !== null) {
const keys = Object.getOwnPropertyNames(target);
let i = -1;
while (++i < keys.length) {
const key = keys[i];
if (isArrayIndex(key)) {
throw new ERR_INVALID_PACKAGE_CONFIG(
fileURLToPath$1(packageJsonUrl),
base,
'"exports" cannot contain numeric property keys.'
)
}
}
i = -1;
while (++i < keys.length) {
const key = keys[i];
if (key === 'default' || (conditions && conditions.has(key))) {
// @ts-expect-error: indexable.
const conditionalTarget = /** @type {unknown} */ (target[key]);
const resolveResult = resolvePackageTarget(
packageJsonUrl,
conditionalTarget,
subpath,
packageSubpath,
base,
pattern,
internal,
isPathMap,
conditions
);
if (resolveResult === undefined) continue
return resolveResult
}
}
return null
}
if (target === null) {
return null
}
throw invalidPackageTarget(
packageSubpath,
target,
packageJsonUrl,
internal,
base
)
}
/**
* @param {unknown} exports
* @param {URL} packageJsonUrl
* @param {URL} base
* @returns {boolean}
*/
function isConditionalExportsMainSugar(exports$1, packageJsonUrl, base) {
if (typeof exports$1 === 'string' || Array.isArray(exports$1)) return true
if (typeof exports$1 !== 'object' || exports$1 === null) return false
const keys = Object.getOwnPropertyNames(exports$1);
let isConditionalSugar = false;
let i = 0;
let keyIndex = -1;
while (++keyIndex < keys.length) {
const key = keys[keyIndex];
const currentIsConditionalSugar = key === '' || key[0] !== '.';
if (i++ === 0) {
isConditionalSugar = currentIsConditionalSugar;
} else if (isConditionalSugar !== currentIsConditionalSugar) {
throw new ERR_INVALID_PACKAGE_CONFIG(
fileURLToPath$1(packageJsonUrl),
base,
'"exports" cannot contain some keys starting with \'.\' and some not.' +
' The exports object must either be an object of package subpath keys' +
' or an object of main entry condition name keys only.'
)
}
}
return isConditionalSugar
}
/**
* @param {string} match
* @param {URL} pjsonUrl
* @param {URL} base
*/
function emitTrailingSlashPatternDeprecation(match, pjsonUrl, base) {
// @ts-expect-error: apparently it does exist, TS.
if (process$1.noDeprecation) {
return
}
const pjsonPath = fileURLToPath$1(pjsonUrl);
if (emittedPackageWarnings.has(pjsonPath + '|' + match)) return
emittedPackageWarnings.add(pjsonPath + '|' + match);
process$1.emitWarning(
`Use of deprecated trailing slash pattern mapping "${match}" in the ` +
`"exports" field module resolution of the package at ${pjsonPath}${
base ? ` imported from ${fileURLToPath$1(base)}` : ''
}. Mapping specifiers ending in "/" is no longer supported.`,
'DeprecationWarning',
'DEP0155'
);
}
/**
* @param {URL} packageJsonUrl
* @param {string} packageSubpath
* @param {Record<string, unknown>} packageConfig
* @param {URL} base
* @param {Set<string> | undefined} conditions
* @returns {URL}
*/
function packageExportsResolve(
packageJsonUrl,
packageSubpath,
packageConfig,
base,
conditions
) {
let exports$1 = packageConfig.exports;
if (isConditionalExportsMainSugar(exports$1, packageJsonUrl, base)) {
exports$1 = {'.': exports$1};
}
if (
own.call(exports$1, packageSubpath) &&
!packageSubpath.includes('*') &&
!packageSubpath.endsWith('/')
) {
// @ts-expect-error: indexable.
const target = exports$1[packageSubpath];
const resolveResult = resolvePackageTarget(
packageJsonUrl,
target,
'',
packageSubpath,
base,
false,
false,
false,
conditions
);
if (resolveResult === null || resolveResult === undefined) {
throw exportsNotFound(packageSubpath, packageJsonUrl, base)
}
return resolveResult
}
let bestMatch = '';
let bestMatchSubpath = '';
const keys = Object.getOwnPropertyNames(exports$1);
let i = -1;
while (++i < keys.length) {
const key = keys[i];
const patternIndex = key.indexOf('*');
if (
patternIndex !== -1 &&
packageSubpath.startsWith(key.slice(0, patternIndex))
) {
// When this reaches EOL, this can throw at the top of the whole function:
//
// if (StringPrototypeEndsWith(packageSubpath, '/'))
// throwInvalidSubpath(packageSubpath)
//
// To match "imports" and the spec.
if (packageSubpath.endsWith('/')) {
emitTrailingSlashPatternDeprecation(
packageSubpath,
packageJsonUrl,
base
);
}
const patternTrailer = key.slice(patternIndex + 1);
if (
packageSubpath.length >= key.length &&
packageSubpath.endsWith(patternTrailer) &&
patternKeyCompare(bestMatch, key) === 1 &&
key.lastIndexOf('*') === patternIndex
) {
bestMatch = key;
bestMatchSubpath = packageSubpath.slice(
patternIndex,
packageSubpath.length - patternTrailer.length
);
}
}
}
if (bestMatch) {
// @ts-expect-error: indexable.
const target = /** @type {unknown} */ (exports$1[bestMatch]);
const resolveResult = resolvePackageTarget(
packageJsonUrl,
target,
bestMatchSubpath,
bestMatch,
base,
true,
false,
packageSubpath.endsWith('/'),
conditions
);
if (resolveResult === null || resolveResult === undefined) {
throw exportsNotFound(packageSubpath, packageJsonUrl, base)
}
return resolveResult
}
throw exportsNotFound(packageSubpath, packageJsonUrl, base)
}
/**
* @param {string} a
* @param {string} b
*/
function patternKeyCompare(a, b) {
const aPatternIndex = a.indexOf('*');
const bPatternIndex = b.indexOf('*');
const baseLengthA = aPatternIndex === -1 ? a.length : aPatternIndex + 1;
const baseLengthB = bPatternIndex === -1 ? b.length : bPatternIndex + 1;
if (baseLengthA > baseLengthB) return -1
if (baseLengthB > baseLengthA) return 1
if (aPatternIndex === -1) return 1
if (bPatternIndex === -1) return -1
if (a.length > b.length) return -1
if (b.length > a.length) return 1
return 0
}
/**
* @param {string} name
* @param {URL} base
* @param {Set<string>} [conditions]
* @returns {URL}
*/
function packageImportsResolve(name, base, conditions) {
if (name === '#' || name.startsWith('#/') || name.endsWith('/')) {
const reason = 'is not a valid internal imports specifier name';
throw new ERR_INVALID_MODULE_SPECIFIER(name, reason, fileURLToPath$1(base))
}
/** @type {URL | undefined} */
let packageJsonUrl;
const packageConfig = getPackageScopeConfig(base);
if (packageConfig.exists) {
packageJsonUrl = pathToFileURL$1(packageConfig.pjsonPath);
const imports = packageConfig.imports;
if (imports) {
if (own.call(imports, name) && !name.includes('*')) {
const resolveResult = resolvePackageTarget(
packageJsonUrl,
imports[name],
'',
name,
base,
false,
true,
false,
conditions
);
if (resolveResult !== null && resolveResult !== undefined) {
return resolveResult
}
} else {
let bestMatch = '';
let bestMatchSubpath = '';
const keys = Object.getOwnPropertyNames(imports);
let i = -1;
while (++i < keys.length) {
const key = keys[i];
const patternIndex = key.indexOf('*');
if (patternIndex !== -1 && name.startsWith(key.slice(0, -1))) {
const patternTrailer = key.slice(patternIndex + 1);
if (
name.length >= key.length &&
name.endsWith(patternTrailer) &&
patternKeyCompare(bestMatch, key) === 1 &&
key.lastIndexOf('*') === patternIndex
) {
bestMatch = key;
bestMatchSubpath = name.slice(
patternIndex,
name.length - patternTrailer.length
);
}
}
}
if (bestMatch) {
const target = imports[bestMatch];
const resolveResult = resolvePackageTarget(
packageJsonUrl,
target,
bestMatchSubpath,
bestMatch,
base,
true,
true,
false,
conditions
);
if (resolveResult !== null && resolveResult !== undefined) {
return resolveResult
}
}
}
}
}
throw importNotDefined(name, packageJsonUrl, base)
}
/**
* @param {string} specifier
* @param {URL} base
*/
function parsePackageName(specifier, base) {
let separatorIndex = specifier.indexOf('/');
let validPackageName = true;
let isScoped = false;
if (specifier[0] === '@') {
isScoped = true;
if (separatorIndex === -1 || specifier.length === 0) {
validPackageName = false;
} else {
separatorIndex = specifier.indexOf('/', separatorIndex + 1);
}
}
const packageName =
separatorIndex === -1 ? specifier : specifier.slice(0, separatorIndex);
// Package name cannot have leading . and cannot have percent-encoding or
// \\ separators.
if (invalidPackageNameRegEx.exec(packageName) !== null) {
validPackageName = false;
}
if (!validPackageName) {
throw new ERR_INVALID_MODULE_SPECIFIER(
specifier,
'is not a valid package name',
fileURLToPath$1(base)
)
}
const packageSubpath =
'.' + (separatorIndex === -1 ? '' : specifier.slice(separatorIndex));
return {packageName, packageSubpath, isScoped}
}
/**
* @param {string} specifier
* @param {URL} base
* @param {Set<string> | undefined} conditions
* @returns {URL}
*/
function packageResolve(specifier, base, conditions) {
if (builtinModules.includes(specifier)) {
return new URL('node:' + specifier)
}
const {packageName, packageSubpath, isScoped} = parsePackageName(
specifier,
base
);
// ResolveSelf
const packageConfig = getPackageScopeConfig(base);
// Cant test.
/* c8 ignore next 16 */
if (packageConfig.exists) {
const packageJsonUrl = pathToFileURL$1(packageConfig.pjsonPath);
if (
packageConfig.name === packageName &&
packageConfig.exports !== undefined &&
packageConfig.exports !== null
) {
return packageExportsResolve(
packageJsonUrl,
packageSubpath,
packageConfig,
base,
conditions
)
}
}
let packageJsonUrl = new URL(
'./node_modules/' + packageName + '/package.json',
base
);
let packageJsonPath = fileURLToPath$1(packageJsonUrl);
/** @type {string} */
let lastPath;
do {
const stat = tryStatSync(packageJsonPath.slice(0, -13));
if (!stat || !stat.isDirectory()) {
lastPath = packageJsonPath;
packageJsonUrl = new URL(
(isScoped ? '../../../../node_modules/' : '../../../node_modules/') +
packageName +
'/package.json',
packageJsonUrl
);
packageJsonPath = fileURLToPath$1(packageJsonUrl);
continue
}
// Package match.
const packageConfig = read(packageJsonPath, {base, specifier});
if (packageConfig.exports !== undefined && packageConfig.exports !== null) {
return packageExportsResolve(
packageJsonUrl,
packageSubpath,
packageConfig,
base,
conditions
)
}
if (packageSubpath === '.') {
return legacyMainResolve(packageJsonUrl, packageConfig, base)
}
return new URL(packageSubpath, packageJsonUrl)
// Cross-platform root check.
} while (packageJsonPath.length !== lastPath.length)
throw new ERR_MODULE_NOT_FOUND(packageName, fileURLToPath$1(base), false)
}
/**
* @param {string} specifier
* @returns {boolean}
*/
function isRelativeSpecifier(specifier) {
if (specifier[0] === '.') {
if (specifier.length === 1 || specifier[1] === '/') return true
if (
specifier[1] === '.' &&
(specifier.length === 2 || specifier[2] === '/')
) {
return true
}
}
return false
}
/**
* @param {string} specifier
* @returns {boolean}
*/
function shouldBeTreatedAsRelativeOrAbsolutePath(specifier) {
if (specifier === '') return false
if (specifier[0] === '/') return true
return isRelativeSpecifier(specifier)
}
/**
* The “Resolver Algorithm Specification” as detailed in the Node docs (which is
* sync and slightly lower-level than `resolve`).
*
* @param {string} specifier
* `/example.js`, `./example.js`, `../example.js`, `some-package`, `fs`, etc.
* @param {URL} base
* Full URL (to a file) that `specifier` is resolved relative from.
* @param {Set<string>} [conditions]
* Conditions.
* @param {boolean} [preserveSymlinks]
* Keep symlinks instead of resolving them.
* @returns {URL}
* A URL object to the found thing.
*/
function moduleResolve(specifier, base, conditions, preserveSymlinks) {
// Note: The Node code supports `base` as a string (in this internal API) too,
// we dont.
if (conditions === undefined) {
conditions = getConditionsSet();
}
const protocol = base.protocol;
const isData = protocol === 'data:';
const isRemote = isData || protocol === 'http:' || protocol === 'https:';
// Order swapped from spec for minor perf gain.
// Ok since relative URLs cannot parse as URLs.
/** @type {URL | undefined} */
let resolved;
if (shouldBeTreatedAsRelativeOrAbsolutePath(specifier)) {
try {
resolved = new URL(specifier, base);
} catch (error_) {
const error = new ERR_UNSUPPORTED_RESOLVE_REQUEST(specifier, base);
error.cause = error_;
throw error
}
} else if (protocol === 'file:' && specifier[0] === '#') {
resolved = packageImportsResolve(specifier, base, conditions);
} else {
try {
resolved = new URL(specifier);
} catch (error_) {
// Note: actual code uses `canBeRequiredWithoutScheme`.
if (isRemote && !builtinModules.includes(specifier)) {
const error = new ERR_UNSUPPORTED_RESOLVE_REQUEST(specifier, base);
error.cause = error_;
throw error
}
resolved = packageResolve(specifier, base, conditions);
}
}
assert.ok(resolved !== undefined, 'expected to be defined');
if (resolved.protocol !== 'file:') {
return resolved
}
return finalizeResolution(resolved, base)
}
function fileURLToPath(id) {
if (typeof id === "string" && !id.startsWith("file://")) {
return normalizeSlash(id);
}
return normalizeSlash(fileURLToPath$1(id));
}
function pathToFileURL(id) {
return pathToFileURL$1(fileURLToPath(id)).toString();
}
const INVALID_CHAR_RE = /[\u0000-\u001F"#$&*+,/:;<=>?@[\]^`{|}\u007F]+/g;
function sanitizeURIComponent(name = "", replacement = "_") {
return name.replace(INVALID_CHAR_RE, replacement).replace(/%../g, replacement);
}
function sanitizeFilePath(filePath = "") {
return filePath.replace(/\?.*$/, "").split(/[/\\]/g).map((p) => sanitizeURIComponent(p)).join("/").replace(/^([A-Za-z])_\//, "$1:/");
}
function normalizeid(id) {
if (typeof id !== "string") {
id = id.toString();
}
if (/(?:node|data|http|https|file):/.test(id)) {
return id;
}
if (BUILTIN_MODULES.has(id)) {
return "node:" + id;
}
return "file://" + encodeURI(normalizeSlash(id));
}
async function loadURL(url) {
const code = await promises.readFile(fileURLToPath(url), "utf8");
return code;
}
function toDataURL(code) {
const base64 = Buffer.from(code).toString("base64");
return `data:text/javascript;base64,${base64}`;
}
function isNodeBuiltin(id = "") {
id = id.replace(/^node:/, "").split("/", 1)[0];
return BUILTIN_MODULES.has(id);
}
const ProtocolRegex = /^(?<proto>.{2,}?):.+$/;
function getProtocol(id) {
const proto = id.match(ProtocolRegex);
return proto ? proto.groups?.proto : void 0;
}
const DEFAULT_CONDITIONS_SET = /* @__PURE__ */ new Set(["node", "import"]);
const DEFAULT_EXTENSIONS = [".mjs", ".cjs", ".js", ".json"];
const NOT_FOUND_ERRORS = /* @__PURE__ */ new Set([
"ERR_MODULE_NOT_FOUND",
"ERR_UNSUPPORTED_DIR_IMPORT",
"MODULE_NOT_FOUND",
"ERR_PACKAGE_PATH_NOT_EXPORTED"
]);
function _tryModuleResolve(id, url, conditions) {
try {
return moduleResolve(id, url, conditions);
} catch (error) {
if (!NOT_FOUND_ERRORS.has(error?.code)) {
throw error;
}
}
}
function _resolve(id, options = {}) {
if (typeof id !== "string") {
if (id instanceof URL) {
id = fileURLToPath(id);
} else {
throw new TypeError("input must be a `string` or `URL`");
}
}
if (/(?:node|data|http|https):/.test(id)) {
return id;
}
if (BUILTIN_MODULES.has(id)) {
return "node:" + id;
}
if (id.startsWith("file://")) {
id = fileURLToPath(id);
}
if (isAbsolute(id)) {
try {
const stat = statSync(id);
if (stat.isFile()) {
return pathToFileURL(id);
}
} catch (error) {
if (error?.code !== "ENOENT") {
throw error;
}
}
}
const conditionsSet = options.conditions ? new Set(options.conditions) : DEFAULT_CONDITIONS_SET;
const _urls = (Array.isArray(options.url) ? options.url : [options.url]).filter(Boolean).map((url) => new URL(normalizeid(url.toString())));
if (_urls.length === 0) {
_urls.push(new URL(pathToFileURL(process.cwd())));
}
const urls = [..._urls];
for (const url of _urls) {
if (url.protocol === "file:") {
urls.push(
new URL("./", url),
// If url is directory
new URL(joinURL(url.pathname, "_index.js"), url),
// TODO: Remove in next major version?
new URL("node_modules", url)
);
}
}
let resolved;
for (const url of urls) {
resolved = _tryModuleResolve(id, url, conditionsSet);
if (resolved) {
break;
}
for (const prefix of ["", "/index"]) {
for (const extension of options.extensions || DEFAULT_EXTENSIONS) {
resolved = _tryModuleResolve(
joinURL(id, prefix) + extension,
url,
conditionsSet
);
if (resolved) {
break;
}
}
if (resolved) {
break;
}
}
if (resolved) {
break;
}
}
if (!resolved) {
const error = new Error(
`Cannot find module ${id} imported from ${urls.join(", ")}`
);
error.code = "ERR_MODULE_NOT_FOUND";
throw error;
}
return pathToFileURL(resolved);
}
function resolveSync(id, options) {
return _resolve(id, options);
}
function resolve(id, options) {
try {
return Promise.resolve(resolveSync(id, options));
} catch (error) {
return Promise.reject(error);
}
}
function resolvePathSync(id, options) {
return fileURLToPath(resolveSync(id, options));
}
function resolvePath(id, options) {
try {
return Promise.resolve(resolvePathSync(id, options));
} catch (error) {
return Promise.reject(error);
}
}
function createResolve(defaults) {
return (id, url) => {
return resolve(id, { url, ...defaults });
};
}
const NODE_MODULES_RE = /^(.+\/node_modules\/)([^/@]+|@[^/]+\/[^/]+)(\/?.*?)?$/;
function parseNodeModulePath(path) {
if (!path) {
return {};
}
path = normalize(fileURLToPath(path));
const match = NODE_MODULES_RE.exec(path);
if (!match) {
return {};
}
const [, dir, name, subpath] = match;
return {
dir,
name,
subpath: subpath ? `.${subpath}` : void 0
};
}
async function lookupNodeModuleSubpath(path) {
path = normalize(fileURLToPath(path));
const { name, subpath } = parseNodeModulePath(path);
if (!name || !subpath) {
return subpath;
}
const { exports: exports$1 } = await readPackageJSON(path).catch(() => {
}) || {};
if (exports$1) {
const resolvedSubpath = _findSubpath(subpath, exports$1);
if (resolvedSubpath) {
return resolvedSubpath;
}
}
return subpath;
}
function _findSubpath(subpath, exports$1) {
if (typeof exports$1 === "string") {
exports$1 = { ".": exports$1 };
}
if (!subpath.startsWith(".")) {
subpath = subpath.startsWith("/") ? `.${subpath}` : `./${subpath}`;
}
if (subpath in (exports$1 || {})) {
return subpath;
}
return _flattenExports(exports$1).find((p) => p.fsPath === subpath)?.subpath;
}
function _flattenExports(exports$1 = {}, parentSubpath = "./") {
return Object.entries(exports$1).flatMap(([key, value]) => {
const [subpath, condition] = key.startsWith(".") ? [key.slice(1), void 0] : ["", key];
const _subPath = joinURL(parentSubpath, subpath);
if (typeof value === "string") {
return [{ subpath: _subPath, fsPath: value, condition }];
} else {
return _flattenExports(value, _subPath);
}
});
}
const ESM_STATIC_IMPORT_RE = /(?<=\s|^|;|\})import\s*(?:[\s"']*(?<imports>[\p{L}\p{M}\w\t\n\r $*,/{}@.]+)from\s*)?["']\s*(?<specifier>(?<="\s*)[^"]*[^\s"](?=\s*")|(?<='\s*)[^']*[^\s'](?=\s*'))\s*["'][\s;]*/gmu;
const DYNAMIC_IMPORT_RE = /import\s*\((?<expression>(?:[^()]+|\((?:[^()]+|\([^()]*\))*\))*)\)/gm;
const IMPORT_NAMED_TYPE_RE = /(?<=\s|^|;|})import\s*type\s+(?:[\s"']*(?<imports>[\w\t\n\r $*,/{}]+)from\s*)?["']\s*(?<specifier>(?<="\s*)[^"]*[^\s"](?=\s*")|(?<='\s*)[^']*[^\s'](?=\s*'))\s*["'][\s;]*/gm;
const EXPORT_DECAL_RE = /\bexport\s+(?<declaration>(?:async function\s*\*?|function\s*\*?|let|const enum|const|enum|var|class))\s+\*?(?<name>[\w$]+)(?<extraNames>.*,\s*[\s\w:[\]{}]*[\w$\]}]+)*/g;
const EXPORT_DECAL_TYPE_RE = /\bexport\s+(?<declaration>(?:interface|type|declare (?:async function|function|let|const enum|const|enum|var|class)))\s+(?<name>[\w$]+)/g;
const EXPORT_NAMED_RE = /\bexport\s*{(?<exports>[^}]+?)[\s,]*}(?:\s*from\s*["']\s*(?<specifier>(?<="\s*)[^"]*[^\s"](?=\s*")|(?<='\s*)[^']*[^\s'](?=\s*'))\s*["'][^\n;]*)?/g;
const EXPORT_NAMED_TYPE_RE = /\bexport\s+type\s*{(?<exports>[^}]+?)[\s,]*}(?:\s*from\s*["']\s*(?<specifier>(?<="\s*)[^"]*[^\s"](?=\s*")|(?<='\s*)[^']*[^\s'](?=\s*'))\s*["'][^\n;]*)?/g;
const EXPORT_NAMED_DESTRUCT = /\bexport\s+(?:let|var|const)\s+(?:{(?<exports1>[^}]+?)[\s,]*}|\[(?<exports2>[^\]]+?)[\s,]*])\s+=/gm;
const EXPORT_STAR_RE = /\bexport\s*\*(?:\s*as\s+(?<name>[\w$]+)\s+)?\s*(?:\s*from\s*["']\s*(?<specifier>(?<="\s*)[^"]*[^\s"](?=\s*")|(?<='\s*)[^']*[^\s'](?=\s*'))\s*["'][^\n;]*)?/g;
const EXPORT_DEFAULT_RE = /\bexport\s+default\s+(async function|function|class|true|false|\W|\d)|\bexport\s+default\s+(?<defaultName>.*)/g;
const EXPORT_DEFAULT_CLASS_RE = /\bexport\s+default\s+(?<declaration>class)\s+(?<name>[\w$]+)/g;
const TYPE_RE = /^\s*?type\s/;
function findStaticImports(code) {
return _filterStatement(
_tryGetLocations(code, "import"),
matchAll(ESM_STATIC_IMPORT_RE, code, { type: "static" })
);
}
function findDynamicImports(code) {
return _filterStatement(
_tryGetLocations(code, "import"),
matchAll(DYNAMIC_IMPORT_RE, code, { type: "dynamic" })
);
}
function findTypeImports(code) {
return [
...matchAll(IMPORT_NAMED_TYPE_RE, code, { type: "type" }),
...matchAll(ESM_STATIC_IMPORT_RE, code, { type: "static" }).filter(
(match) => /[^A-Za-z]type\s/.test(match.imports)
)
];
}
function parseStaticImport(matched) {
const cleanedImports = clearImports(matched.imports);
const namedImports = {};
const _matches = cleanedImports.match(/{([^}]*)}/)?.[1]?.split(",") || [];
for (const namedImport of _matches) {
const _match = namedImport.match(/^\s*(\S*) as (\S*)\s*$/);
const source = _match?.[1] || namedImport.trim();
const importName = _match?.[2] || source;
if (source && !TYPE_RE.test(source)) {
namedImports[source] = importName;
}
}
const { namespacedImport, defaultImport } = getImportNames(cleanedImports);
return {
...matched,
defaultImport,
namespacedImport,
namedImports
};
}
function parseTypeImport(matched) {
if (matched.type === "type") {
return parseStaticImport(matched);
}
const cleanedImports = clearImports(matched.imports);
const namedImports = {};
const _matches = cleanedImports.match(/{([^}]*)}/)?.[1]?.split(",") || [];
for (const namedImport of _matches) {
const _match = /\s+as\s+/.test(namedImport) ? namedImport.match(/^\s*type\s+(\S*) as (\S*)\s*$/) : namedImport.match(/^\s*type\s+(\S*)\s*$/);
const source = _match?.[1] || namedImport.trim();
const importName = _match?.[2] || source;
if (source && TYPE_RE.test(namedImport)) {
namedImports[source] = importName;
}
}
const { namespacedImport, defaultImport } = getImportNames(cleanedImports);
return {
...matched,
defaultImport,
namespacedImport,
namedImports
};
}
function _extractExtraNames(extraNamesStr) {
const names = [];
let depth = 0;
let angleDepth = 0;
let inString = false;
let inTypeAnnotation = false;
for (let i = 0; i < extraNamesStr.length; i++) {
const char = extraNamesStr[i];
if (inString) {
if (char === inString) {
let backslashCount = 0;
for (let j = i - 1; j >= 0 && extraNamesStr[j] === "\\"; j--) {
backslashCount++;
}
if (backslashCount % 2 === 0) {
inString = false;
}
}
continue;
}
if (char === '"' || char === "'" || char === "`") {
inString = char;
continue;
}
if (char === ":" && depth === 0 && angleDepth === 0) {
inTypeAnnotation = true;
continue;
}
if (char === "=" && extraNamesStr[i + 1] !== ">" && depth === 0 && angleDepth === 0) {
inTypeAnnotation = false;
}
if (inTypeAnnotation && char === "<") {
angleDepth++;
continue;
}
if (!inTypeAnnotation && char === "<" && depth === 0 && i > 0 && _isIdentifierBeforeAngleBracket(extraNamesStr, i)) {
angleDepth++;
continue;
}
if (char === ">" && angleDepth > 0 && extraNamesStr[i - 1] !== "=") {
angleDepth--;
continue;
}
if (char === "(" || char === "[" || char === "{") {
depth++;
} else if (char === ")" || char === "]" || char === "}") {
depth--;
}
if (char === "," && depth === 0 && angleDepth === 0) {
const rest = extraNamesStr.slice(i + 1);
const match = rest.match(/^\s*([\w$]+)/);
if (match) {
names.push(match[1]);
}
}
}
return names;
}
function findExports(code) {
const declaredExports = matchAll(EXPORT_DECAL_RE, code, {
type: "declaration"
});
for (const declaredExport of declaredExports) {
if (/^export\s+(?:async\s+)?function/.test(declaredExport.code)) {
continue;
}
const extraNamesStr = declaredExport.extraNames;
if (extraNamesStr) {
const extraNames = _extractExtraNames(extraNamesStr);
if (extraNames.length > 0) {
declaredExport.names = [declaredExport.name, ...extraNames];
}
}
delete declaredExport.extraNames;
}
const namedExports = normalizeNamedExports(
matchAll(EXPORT_NAMED_RE, code, {
type: "named"
})
);
const destructuredExports = matchAll(
EXPORT_NAMED_DESTRUCT,
code,
{ type: "named" }
);
for (const namedExport of destructuredExports) {
namedExport.exports = namedExport.exports1 || namedExport.exports2;
namedExport.names = namedExport.exports.replace(/^\r?\n?/, "").split(/\s*,\s*/g).filter((name) => !TYPE_RE.test(name)).map(
(name) => name.replace(/^.*?\s*:\s*/, "").replace(/\s*=\s*.*$/, "").trim()
);
}
const defaultExport = matchAll(EXPORT_DEFAULT_RE, code, {
type: "default",
name: "default"
});
const defaultClassExports = matchAll(EXPORT_DEFAULT_CLASS_RE, code, {
type: "declaration"
});
const starExports = matchAll(EXPORT_STAR_RE, code, {
type: "star"
});
const exports$1 = normalizeExports([
...declaredExports,
...namedExports,
...destructuredExports,
...defaultExport,
...defaultClassExports,
...starExports
]);
if (exports$1.length === 0) {
return [];
}
const exportLocations = _tryGetLocations(code, "export");
if (exportLocations && exportLocations.length === 0) {
return [];
}
return (
// Filter false positive export matches
_filterStatement(exportLocations, exports$1).filter((exp, index, exports2) => {
const nextExport = exports2[index + 1];
return !nextExport || exp.type !== nextExport.type || !exp.name || exp.name !== nextExport.name;
})
);
}
function findTypeExports(code) {
const declaredExports = matchAll(
EXPORT_DECAL_TYPE_RE,
code,
{ type: "declaration" }
);
const namedExports = normalizeNamedExports(
matchAll(EXPORT_NAMED_TYPE_RE, code, {
type: "named"
})
);
const exports$1 = normalizeExports([
...declaredExports,
...namedExports
]);
if (exports$1.length === 0) {
return [];
}
const exportLocations = _tryGetLocations(code, "export");
if (exportLocations && exportLocations.length === 0) {
return [];
}
return (
// Filter false positive export matches
_filterStatement(exportLocations, exports$1).filter((exp, index, exports2) => {
const nextExport = exports2[index + 1];
return !nextExport || exp.type !== nextExport.type || !exp.name || exp.name !== nextExport.name;
})
);
}
function normalizeExports(exports$1) {
for (const exp of exports$1) {
if (!exp.name && exp.names && exp.names.length === 1) {
exp.name = exp.names[0];
}
if (exp.name === "default" && exp.type !== "default") {
exp._type = exp.type;
exp.type = "default";
}
if (!exp.names && exp.name) {
exp.names = [exp.name];
}
if (exp.type === "declaration" && exp.declaration) {
exp.declarationType = exp.declaration.replace(
/^declare\s*/,
""
);
}
}
return exports$1;
}
function normalizeNamedExports(namedExports) {
for (const namedExport of namedExports) {
namedExport.names = namedExport.exports.replace(/^\r?\n?/, "").split(/\s*,\s*/g).filter((name) => !TYPE_RE.test(name)).map((name) => name.replace(/^.*?\sas\s/, "").trim());
}
return namedExports;
}
function findExportNames(code) {
return findExports(code).flatMap((exp) => exp.names).filter(Boolean);
}
async function resolveModuleExportNames(id, options) {
const url = await resolvePath(id, options);
const code = await loadURL(url);
const exports$1 = findExports(code);
const exportNames = new Set(
exports$1.flatMap((exp) => exp.names).filter(Boolean)
);
for (const exp of exports$1) {
if (exp.type !== "star" || !exp.specifier) {
continue;
}
const subExports = await resolveModuleExportNames(exp.specifier, {
...options,
url
});
for (const subExport of subExports) {
exportNames.add(subExport);
}
}
return [...exportNames];
}
function _filterStatement(locations, statements) {
return statements.filter((exp) => {
return !locations || locations.some((location) => {
return exp.start <= location.start && exp.end >= location.end;
});
});
}
function _tryGetLocations(code, label) {
try {
return _getLocations(code, label);
} catch {
}
}
function _getLocations(code, label) {
const tokens = tokenizer(code, {
ecmaVersion: "latest",
sourceType: "module",
allowHashBang: true,
allowAwaitOutsideFunction: true,
allowImportExportEverywhere: true
});
const locations = [];
for (const token of tokens) {
if (token.type.label === label) {
locations.push({
start: token.start,
end: token.end
});
}
}
return locations;
}
function _isIdentifierBeforeAngleBracket(str, i) {
let j = i - 1;
while (j >= 0 && /[A-Za-z0-9_$]/.test(str[j])) {
j--;
}
const wordStart = j + 1;
return wordStart < i && /[A-Za-z_$]/.test(str[wordStart]);
}
function createCommonJS(url) {
const __filename = fileURLToPath(url);
const __dirname = dirname(__filename);
let _nativeRequire;
const getNativeRequire = () => {
if (!_nativeRequire) {
_nativeRequire = createRequire(url);
}
return _nativeRequire;
};
function require(id) {
return getNativeRequire()(id);
}
require.resolve = function requireResolve(id, options) {
return getNativeRequire().resolve(id, options);
};
return {
__filename,
__dirname,
require
};
}
function interopDefault(sourceModule, opts = {}) {
if (!isObject(sourceModule) || !("default" in sourceModule)) {
return sourceModule;
}
const defaultValue = sourceModule.default;
if (defaultValue === void 0 || defaultValue === null) {
return sourceModule;
}
const _defaultType = typeof defaultValue;
if (_defaultType !== "object" && !(_defaultType === "function" && !opts.preferNamespace)) {
return opts.preferNamespace ? sourceModule : defaultValue;
}
for (const key in sourceModule) {
try {
if (!(key in defaultValue)) {
Object.defineProperty(defaultValue, key, {
enumerable: key !== "default",
configurable: key !== "default",
get() {
return sourceModule[key];
}
});
}
} catch {
}
}
return defaultValue;
}
const EVAL_ESM_IMPORT_RE = /(?<=import .* from ["'])[^"']+(?=["'])|(?<=export .* from ["'])[^"']+(?=["'])|(?<=import\s*["'])[^"']+(?=["'])|(?<=import\s*\(["'])[^"']+(?=["']\))/g;
async function loadModule(id, options = {}) {
const url = await resolve(id, options);
const code = await loadURL(url);
return evalModule(code, { ...options, url });
}
async function evalModule(code, options = {}) {
const transformed = await transformModule(code, options);
const dataURL = toDataURL(transformed);
return import(dataURL).catch((error) => {
error.stack = error.stack.replace(
new RegExp(dataURL, "g"),
options.url || "_mlly_eval_"
);
throw error;
});
}
function transformModule(code, options = {}) {
if (options.url && options.url.endsWith(".json")) {
return Promise.resolve("export default " + code);
}
if (options.url) {
code = code.replace(/import\.meta\.url/g, `'${options.url}'`);
}
return Promise.resolve(code);
}
async function resolveImports(code, options) {
const imports = [...code.matchAll(EVAL_ESM_IMPORT_RE)].map((m) => m[0]);
if (imports.length === 0) {
return code;
}
const uniqueImports = [...new Set(imports)];
const resolved = /* @__PURE__ */ new Map();
await Promise.all(
uniqueImports.map(async (id) => {
let url = await resolve(id, options);
if (url.endsWith(".json")) {
const code2 = await loadURL(url);
url = toDataURL(await transformModule(code2, { url }));
}
resolved.set(id, url);
})
);
const re = new RegExp(
uniqueImports.map((index) => `(?:${index})`).join("|"),
"g"
);
return code.replace(re, (id) => resolved.get(id));
}
const ESM_RE = /(?:[\s;]|^)(?:import[\s\w*,{}]*from|import\s*["'*{]|export\b\s*(?:[*{]|default|class|type|function|const|var|let|async function)|import\.meta\b)/m;
const CJS_RE = /(?:[\s;]|^)(?:module\.exports\b|exports\.\w|require\s*\(|global\.\w)/m;
const COMMENT_RE = /\/\*.+?\*\/|\/\/.*(?=[nr])/g;
const BUILTIN_EXTENSIONS = /* @__PURE__ */ new Set([".mjs", ".cjs", ".node", ".wasm"]);
function hasESMSyntax(code, opts = {}) {
if (opts.stripComments) {
code = code.replace(COMMENT_RE, "");
}
return ESM_RE.test(code);
}
function hasCJSSyntax(code, opts = {}) {
if (opts.stripComments) {
code = code.replace(COMMENT_RE, "");
}
return CJS_RE.test(code);
}
function detectSyntax(code, opts = {}) {
if (opts.stripComments) {
code = code.replace(COMMENT_RE, "");
}
const hasESM = hasESMSyntax(code, {});
const hasCJS = hasCJSSyntax(code, {});
return {
hasESM,
hasCJS,
isMixed: hasESM && hasCJS
};
}
const validNodeImportDefaults = {
allowedProtocols: ["node", "file", "data"]
};
async function isValidNodeImport(id, _options = {}) {
if (isNodeBuiltin(id)) {
return true;
}
const options = { ...validNodeImportDefaults, ..._options };
const proto = getProtocol(id);
if (proto && !options.allowedProtocols?.includes(proto)) {
return false;
}
if (proto === "data") {
return true;
}
const resolvedPath = await resolvePath(id, options);
const extension = extname$1(resolvedPath);
if (BUILTIN_EXTENSIONS.has(extension)) {
return true;
}
if (extension !== ".js") {
return false;
}
const package_ = await readPackageJSON(resolvedPath).catch(() => {
});
if (package_?.type === "module") {
return true;
}
if (/\.(?:\w+-)?esm?(?:-\w+)?\.js$|\/esm?\//.test(resolvedPath)) {
return false;
}
const code = options.code || await promises.readFile(resolvedPath, "utf8").catch(() => {
}) || "";
return !hasESMSyntax(code, { stripComments: options.stripComments });
}
export { DYNAMIC_IMPORT_RE, ESM_STATIC_IMPORT_RE, EXPORT_DECAL_RE, EXPORT_DECAL_TYPE_RE, createCommonJS, createResolve, detectSyntax, evalModule, fileURLToPath, findDynamicImports, findExportNames, findExports, findStaticImports, findTypeExports, findTypeImports, getProtocol, hasCJSSyntax, hasESMSyntax, interopDefault, isNodeBuiltin, isValidNodeImport, loadModule, loadURL, lookupNodeModuleSubpath, normalizeid, parseNodeModulePath, parseStaticImport, parseTypeImport, pathToFileURL, resolve, resolveImports, resolveModuleExportNames, resolvePath, resolvePathSync, resolveSync, sanitizeFilePath, sanitizeURIComponent, toDataURL, transformModule };
+70
View File
@@ -0,0 +1,70 @@
MIT License
Copyright (c) Pooya Parsa <pooya@pi0.io> - Daniel Roe <daniel@roe.dev>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
---
Copyright Joyent, Inc. and other Node contributors.
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to permit
persons to whom the Software is furnished to do so, subject to the
following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
USE OR OTHER DEALINGS IN THE SOFTWARE.
---
Bundled zeptomatch (https://github.com/fabiospampinato/zeptomatch)
The MIT License (MIT)
Copyright (c) 2023-present Fabio Spampinato
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
+73
View File
@@ -0,0 +1,73 @@
# 🛣️ pathe
> Universal filesystem path utils
[![version][npm-v-src]][npm-v-href]
[![downloads][npm-d-src]][npm-d-href]
[![size][size-src]][size-href]
## ❓ Why
For [historical reasons](https://docs.microsoft.com/en-us/archive/blogs/larryosterman/why-is-the-dos-path-character), windows followed MS-DOS and used backslash for separating paths rather than slash used for macOS, Linux, and other Posix operating systems. Nowadays, [Windows](https://docs.microsoft.com/en-us/windows/win32/fileio/naming-a-file?redirectedfrom=MSDN) supports both Slash and Backslash for paths. [Node.js's built-in `path` module](https://nodejs.org/api/path.html) in the default operation of the path module varies based on the operating system on which a Node.js application is running. Specifically, when running on a Windows operating system, the path module will assume that Windows-style paths are being used. **This makes inconsistent code behavior between Windows and POSIX.**
Compared to popular [upath](https://github.com/anodynos/upath), pathe provides **identical exports** of Node.js with normalization on **all operations** and is written in modern **ESM/TypeScript** and has **no dependency on Node.js**!
This package is a drop-in replacement of the Node.js's [path module](https://nodejs.org/api/path.html) module and ensures paths are normalized with slash `/` and work in environments including Node.js.
## 💿 Usage
Install using npm or yarn:
```bash
# npm
npm i pathe
# yarn
yarn add pathe
# pnpm
pnpm i pathe
```
Import:
```js
// ESM / Typescript
import { resolve, matchesGlob } from "pathe";
// CommonJS
const { resolve, matchesGlob } = require("pathe");
```
Read more about path utils from [Node.js documentation](https://nodejs.org/api/path.html) and rest assured behavior is consistently like POSIX regardless of your input paths format and running platform (the only exception is `delimiter` constant export, it will be set to `;` on windows platform).
### Extra utilities
Pathe exports some extra utilities that do not exist in standard Node.js [path module](https://nodejs.org/api/path.html).
In order to use them, you can import from `pathe/utils` subpath:
```js
import {
filename,
normalizeAliases,
resolveAlias,
reverseResolveAlias,
} from "pathe/utils";
```
## License
Made with 💛 Published under the [MIT](./LICENSE) license.
Some code was used from the Node.js project. Glob supported is powered by [zeptomatch](https://github.com/fabiospampinato/zeptomatch).
<!-- Refs -->
[npm-v-src]: https://img.shields.io/npm/v/pathe?style=flat-square
[npm-v-href]: https://npmjs.com/package/pathe
[npm-d-src]: https://img.shields.io/npm/dm/pathe?style=flat-square
[npm-d-href]: https://npmjs.com/package/pathe
[github-actions-src]: https://img.shields.io/github/workflow/status/unjs/pathe/ci/main?style=flat-square
[github-actions-href]: https://github.com/unjs/pathe/actions?query=workflow%3Aci
[size-src]: https://packagephobia.now.sh/badge?p=pathe
[size-href]: https://packagephobia.now.sh/result?p=pathe
@@ -0,0 +1,39 @@
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
const _path = require('./shared/pathe.BSlhyZSM.cjs');
const delimiter = /* @__PURE__ */ (() => globalThis.process?.platform === "win32" ? ";" : ":")();
const _platforms = { posix: void 0, win32: void 0 };
const mix = (del = delimiter) => {
return new Proxy(_path._path, {
get(_, prop) {
if (prop === "delimiter") return del;
if (prop === "posix") return posix;
if (prop === "win32") return win32;
return _platforms[prop] || _path._path[prop];
}
});
};
const posix = /* @__PURE__ */ mix(":");
const win32 = /* @__PURE__ */ mix(";");
exports.basename = _path.basename;
exports.dirname = _path.dirname;
exports.extname = _path.extname;
exports.format = _path.format;
exports.isAbsolute = _path.isAbsolute;
exports.join = _path.join;
exports.matchesGlob = _path.matchesGlob;
exports.normalize = _path.normalize;
exports.normalizeString = _path.normalizeString;
exports.parse = _path.parse;
exports.relative = _path.relative;
exports.resolve = _path.resolve;
exports.sep = _path.sep;
exports.toNamespacedPath = _path.toNamespacedPath;
exports.default = posix;
exports.delimiter = delimiter;
exports.posix = posix;
exports.win32 = win32;
@@ -0,0 +1,47 @@
import * as path from 'node:path';
import path__default from 'node:path';
/**
* Constant for path separator.
*
* Always equals to `"/"`.
*/
declare const sep = "/";
declare const normalize: typeof path__default.normalize;
declare const join: typeof path__default.join;
declare const resolve: typeof path__default.resolve;
/**
* Resolves a string path, resolving '.' and '.' segments and allowing paths above the root.
*
* @param path - The path to normalise.
* @param allowAboveRoot - Whether to allow the resulting path to be above the root directory.
* @returns the normalised path string.
*/
declare function normalizeString(path: string, allowAboveRoot: boolean): string;
declare const isAbsolute: typeof path__default.isAbsolute;
declare const toNamespacedPath: typeof path__default.toNamespacedPath;
declare const extname: typeof path__default.extname;
declare const relative: typeof path__default.relative;
declare const dirname: typeof path__default.dirname;
declare const format: typeof path__default.format;
declare const basename: typeof path__default.basename;
declare const parse: typeof path__default.parse;
/**
* The `path.matchesGlob()` method determines if `path` matches the `pattern`.
* @param path The path to glob-match against.
* @param pattern The glob to check the path against.
*/
declare const matchesGlob: (path: string, pattern: string | string[]) => boolean;
type NodePath = typeof path;
/**
* The platform-specific file delimiter.
*
* Equals to `";"` in windows and `":"` in all other platforms.
*/
declare const delimiter: ";" | ":";
declare const posix: NodePath["posix"];
declare const win32: NodePath["win32"];
declare const _default: NodePath;
export { basename, _default as default, delimiter, dirname, extname, format, isAbsolute, join, matchesGlob, normalize, normalizeString, parse, posix, relative, resolve, sep, toNamespacedPath, win32 };
@@ -0,0 +1,47 @@
import * as path from 'node:path';
import path__default from 'node:path';
/**
* Constant for path separator.
*
* Always equals to `"/"`.
*/
declare const sep = "/";
declare const normalize: typeof path__default.normalize;
declare const join: typeof path__default.join;
declare const resolve: typeof path__default.resolve;
/**
* Resolves a string path, resolving '.' and '.' segments and allowing paths above the root.
*
* @param path - The path to normalise.
* @param allowAboveRoot - Whether to allow the resulting path to be above the root directory.
* @returns the normalised path string.
*/
declare function normalizeString(path: string, allowAboveRoot: boolean): string;
declare const isAbsolute: typeof path__default.isAbsolute;
declare const toNamespacedPath: typeof path__default.toNamespacedPath;
declare const extname: typeof path__default.extname;
declare const relative: typeof path__default.relative;
declare const dirname: typeof path__default.dirname;
declare const format: typeof path__default.format;
declare const basename: typeof path__default.basename;
declare const parse: typeof path__default.parse;
/**
* The `path.matchesGlob()` method determines if `path` matches the `pattern`.
* @param path The path to glob-match against.
* @param pattern The glob to check the path against.
*/
declare const matchesGlob: (path: string, pattern: string | string[]) => boolean;
type NodePath = typeof path;
/**
* The platform-specific file delimiter.
*
* Equals to `";"` in windows and `":"` in all other platforms.
*/
declare const delimiter: ";" | ":";
declare const posix: NodePath["posix"];
declare const win32: NodePath["win32"];
declare const _default: NodePath;
export { basename, _default as default, delimiter, dirname, extname, format, isAbsolute, join, matchesGlob, normalize, normalizeString, parse, posix, relative, resolve, sep, toNamespacedPath, win32 };
@@ -0,0 +1,47 @@
import * as path from 'node:path';
import path__default from 'node:path';
/**
* Constant for path separator.
*
* Always equals to `"/"`.
*/
declare const sep = "/";
declare const normalize: typeof path__default.normalize;
declare const join: typeof path__default.join;
declare const resolve: typeof path__default.resolve;
/**
* Resolves a string path, resolving '.' and '.' segments and allowing paths above the root.
*
* @param path - The path to normalise.
* @param allowAboveRoot - Whether to allow the resulting path to be above the root directory.
* @returns the normalised path string.
*/
declare function normalizeString(path: string, allowAboveRoot: boolean): string;
declare const isAbsolute: typeof path__default.isAbsolute;
declare const toNamespacedPath: typeof path__default.toNamespacedPath;
declare const extname: typeof path__default.extname;
declare const relative: typeof path__default.relative;
declare const dirname: typeof path__default.dirname;
declare const format: typeof path__default.format;
declare const basename: typeof path__default.basename;
declare const parse: typeof path__default.parse;
/**
* The `path.matchesGlob()` method determines if `path` matches the `pattern`.
* @param path The path to glob-match against.
* @param pattern The glob to check the path against.
*/
declare const matchesGlob: (path: string, pattern: string | string[]) => boolean;
type NodePath = typeof path;
/**
* The platform-specific file delimiter.
*
* Equals to `";"` in windows and `":"` in all other platforms.
*/
declare const delimiter: ";" | ":";
declare const posix: NodePath["posix"];
declare const win32: NodePath["win32"];
declare const _default: NodePath;
export { basename, _default as default, delimiter, dirname, extname, format, isAbsolute, join, matchesGlob, normalize, normalizeString, parse, posix, relative, resolve, sep, toNamespacedPath, win32 };
@@ -0,0 +1,19 @@
import { _ as _path } from './shared/pathe.M-eThtNZ.mjs';
export { c as basename, d as dirname, e as extname, f as format, i as isAbsolute, j as join, m as matchesGlob, n as normalize, a as normalizeString, p as parse, b as relative, r as resolve, s as sep, t as toNamespacedPath } from './shared/pathe.M-eThtNZ.mjs';
const delimiter = /* @__PURE__ */ (() => globalThis.process?.platform === "win32" ? ";" : ":")();
const _platforms = { posix: void 0, win32: void 0 };
const mix = (del = delimiter) => {
return new Proxy(_path, {
get(_, prop) {
if (prop === "delimiter") return del;
if (prop === "posix") return posix;
if (prop === "win32") return win32;
return _platforms[prop] || _path[prop];
}
});
};
const posix = /* @__PURE__ */ mix(":");
const win32 = /* @__PURE__ */ mix(";");
export { posix as default, delimiter, posix, win32 };
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,82 @@
'use strict';
const _path = require('./shared/pathe.BSlhyZSM.cjs');
const pathSeparators = /* @__PURE__ */ new Set(["/", "\\", void 0]);
const normalizedAliasSymbol = Symbol.for("pathe:normalizedAlias");
const SLASH_RE = /[/\\]/;
function normalizeAliases(_aliases) {
if (_aliases[normalizedAliasSymbol]) {
return _aliases;
}
const aliases = Object.fromEntries(
Object.entries(_aliases).sort(([a], [b]) => _compareAliases(a, b))
);
for (const key in aliases) {
for (const alias in aliases) {
if (alias === key || key.startsWith(alias)) {
continue;
}
if (aliases[key]?.startsWith(alias) && pathSeparators.has(aliases[key][alias.length])) {
aliases[key] = aliases[alias] + aliases[key].slice(alias.length);
}
}
}
Object.defineProperty(aliases, normalizedAliasSymbol, {
value: true,
enumerable: false
});
return aliases;
}
function resolveAlias(path, aliases) {
const _path$1 = _path.normalizeWindowsPath(path);
aliases = normalizeAliases(aliases);
for (const [alias, to] of Object.entries(aliases)) {
if (!_path$1.startsWith(alias)) {
continue;
}
const _alias = hasTrailingSlash(alias) ? alias.slice(0, -1) : alias;
if (hasTrailingSlash(_path$1[_alias.length])) {
return _path.join(to, _path$1.slice(alias.length));
}
}
return _path$1;
}
function reverseResolveAlias(path, aliases) {
const _path$1 = _path.normalizeWindowsPath(path);
aliases = normalizeAliases(aliases);
const matches = [];
for (const [to, alias] of Object.entries(aliases)) {
if (!_path$1.startsWith(alias)) {
continue;
}
const _alias = hasTrailingSlash(alias) ? alias.slice(0, -1) : alias;
if (hasTrailingSlash(_path$1[_alias.length])) {
matches.push(_path.join(to, _path$1.slice(alias.length)));
}
}
return matches.sort((a, b) => b.length - a.length);
}
function filename(path) {
const base = path.split(SLASH_RE).pop();
if (!base) {
return void 0;
}
const separatorIndex = base.lastIndexOf(".");
if (separatorIndex <= 0) {
return base;
}
return base.slice(0, separatorIndex);
}
function _compareAliases(a, b) {
return b.split("/").length - a.split("/").length;
}
function hasTrailingSlash(path = "/") {
const lastChar = path[path.length - 1];
return lastChar === "/" || lastChar === "\\";
}
exports.filename = filename;
exports.normalizeAliases = normalizeAliases;
exports.resolveAlias = resolveAlias;
exports.reverseResolveAlias = reverseResolveAlias;
@@ -0,0 +1,32 @@
/**
* Normalises alias mappings, ensuring that more specific aliases are resolved before less specific ones.
* This function also ensures that aliases do not resolve to themselves cyclically.
*
* @param _aliases - A set of alias mappings where each key is an alias and its value is the actual path it points to.
* @returns a set of normalised alias mappings.
*/
declare function normalizeAliases(_aliases: Record<string, string>): Record<string, string>;
/**
* Resolves a path string to its alias if applicable, otherwise returns the original path.
* This function normalises the path, resolves the alias and then joins it to the alias target if necessary.
*
* @param path - The path string to resolve.
* @param aliases - A set of alias mappings to use for resolution.
* @returns the resolved path as a string.
*/
declare function resolveAlias(path: string, aliases: Record<string, string>): string;
/**
* Resolves a path string to its possible alias.
*
* Returns an array of possible alias resolutions (could be empty), sorted by specificity (longest first).
*/
declare function reverseResolveAlias(path: string, aliases: Record<string, string>): string[];
/**
* Extracts the filename from a given path, excluding any directory paths and the file extension.
*
* @param path - The full path of the file from which to extract the filename.
* @returns the filename without the extension, or `undefined` if the filename cannot be extracted.
*/
declare function filename(path: string): string | undefined;
export { filename, normalizeAliases, resolveAlias, reverseResolveAlias };
@@ -0,0 +1,32 @@
/**
* Normalises alias mappings, ensuring that more specific aliases are resolved before less specific ones.
* This function also ensures that aliases do not resolve to themselves cyclically.
*
* @param _aliases - A set of alias mappings where each key is an alias and its value is the actual path it points to.
* @returns a set of normalised alias mappings.
*/
declare function normalizeAliases(_aliases: Record<string, string>): Record<string, string>;
/**
* Resolves a path string to its alias if applicable, otherwise returns the original path.
* This function normalises the path, resolves the alias and then joins it to the alias target if necessary.
*
* @param path - The path string to resolve.
* @param aliases - A set of alias mappings to use for resolution.
* @returns the resolved path as a string.
*/
declare function resolveAlias(path: string, aliases: Record<string, string>): string;
/**
* Resolves a path string to its possible alias.
*
* Returns an array of possible alias resolutions (could be empty), sorted by specificity (longest first).
*/
declare function reverseResolveAlias(path: string, aliases: Record<string, string>): string[];
/**
* Extracts the filename from a given path, excluding any directory paths and the file extension.
*
* @param path - The full path of the file from which to extract the filename.
* @returns the filename without the extension, or `undefined` if the filename cannot be extracted.
*/
declare function filename(path: string): string | undefined;
export { filename, normalizeAliases, resolveAlias, reverseResolveAlias };
@@ -0,0 +1,32 @@
/**
* Normalises alias mappings, ensuring that more specific aliases are resolved before less specific ones.
* This function also ensures that aliases do not resolve to themselves cyclically.
*
* @param _aliases - A set of alias mappings where each key is an alias and its value is the actual path it points to.
* @returns a set of normalised alias mappings.
*/
declare function normalizeAliases(_aliases: Record<string, string>): Record<string, string>;
/**
* Resolves a path string to its alias if applicable, otherwise returns the original path.
* This function normalises the path, resolves the alias and then joins it to the alias target if necessary.
*
* @param path - The path string to resolve.
* @param aliases - A set of alias mappings to use for resolution.
* @returns the resolved path as a string.
*/
declare function resolveAlias(path: string, aliases: Record<string, string>): string;
/**
* Resolves a path string to its possible alias.
*
* Returns an array of possible alias resolutions (could be empty), sorted by specificity (longest first).
*/
declare function reverseResolveAlias(path: string, aliases: Record<string, string>): string[];
/**
* Extracts the filename from a given path, excluding any directory paths and the file extension.
*
* @param path - The full path of the file from which to extract the filename.
* @returns the filename without the extension, or `undefined` if the filename cannot be extracted.
*/
declare function filename(path: string): string | undefined;
export { filename, normalizeAliases, resolveAlias, reverseResolveAlias };
@@ -0,0 +1,77 @@
import { g as normalizeWindowsPath, j as join } from './shared/pathe.M-eThtNZ.mjs';
const pathSeparators = /* @__PURE__ */ new Set(["/", "\\", void 0]);
const normalizedAliasSymbol = Symbol.for("pathe:normalizedAlias");
const SLASH_RE = /[/\\]/;
function normalizeAliases(_aliases) {
if (_aliases[normalizedAliasSymbol]) {
return _aliases;
}
const aliases = Object.fromEntries(
Object.entries(_aliases).sort(([a], [b]) => _compareAliases(a, b))
);
for (const key in aliases) {
for (const alias in aliases) {
if (alias === key || key.startsWith(alias)) {
continue;
}
if (aliases[key]?.startsWith(alias) && pathSeparators.has(aliases[key][alias.length])) {
aliases[key] = aliases[alias] + aliases[key].slice(alias.length);
}
}
}
Object.defineProperty(aliases, normalizedAliasSymbol, {
value: true,
enumerable: false
});
return aliases;
}
function resolveAlias(path, aliases) {
const _path = normalizeWindowsPath(path);
aliases = normalizeAliases(aliases);
for (const [alias, to] of Object.entries(aliases)) {
if (!_path.startsWith(alias)) {
continue;
}
const _alias = hasTrailingSlash(alias) ? alias.slice(0, -1) : alias;
if (hasTrailingSlash(_path[_alias.length])) {
return join(to, _path.slice(alias.length));
}
}
return _path;
}
function reverseResolveAlias(path, aliases) {
const _path = normalizeWindowsPath(path);
aliases = normalizeAliases(aliases);
const matches = [];
for (const [to, alias] of Object.entries(aliases)) {
if (!_path.startsWith(alias)) {
continue;
}
const _alias = hasTrailingSlash(alias) ? alias.slice(0, -1) : alias;
if (hasTrailingSlash(_path[_alias.length])) {
matches.push(join(to, _path.slice(alias.length)));
}
}
return matches.sort((a, b) => b.length - a.length);
}
function filename(path) {
const base = path.split(SLASH_RE).pop();
if (!base) {
return void 0;
}
const separatorIndex = base.lastIndexOf(".");
if (separatorIndex <= 0) {
return base;
}
return base.slice(0, separatorIndex);
}
function _compareAliases(a, b) {
return b.split("/").length - a.split("/").length;
}
function hasTrailingSlash(path = "/") {
const lastChar = path[path.length - 1];
return lastChar === "/" || lastChar === "\\";
}
export { filename, normalizeAliases, resolveAlias, reverseResolveAlias };
@@ -0,0 +1,61 @@
{
"name": "pathe",
"version": "2.0.3",
"description": "Universal filesystem path utils",
"repository": "unjs/pathe",
"license": "MIT",
"sideEffects": false,
"type": "module",
"exports": {
".": {
"import": {
"types": "./dist/index.d.mts",
"default": "./dist/index.mjs"
},
"require": {
"types": "./dist/index.d.cts",
"default": "./dist/index.cjs"
}
},
"./utils": {
"import": {
"types": "./dist/utils.d.mts",
"default": "./dist/utils.mjs"
},
"require": {
"types": "./dist/utils.d.cts",
"default": "./dist/utils.cjs"
}
}
},
"main": "./dist/index.cjs",
"module": "./dist/index.mjs",
"types": "./dist/index.d.ts",
"files": [
"dist",
"utils.d.ts"
],
"devDependencies": {
"@types/node": "^22.13.1",
"@vitest/coverage-v8": "^3.0.5",
"changelogen": "^0.5.7",
"esbuild": "^0.25.0",
"eslint": "^9.20.1",
"eslint-config-unjs": "^0.4.2",
"jiti": "^2.4.2",
"prettier": "^3.5.0",
"typescript": "^5.7.3",
"unbuild": "^3.3.1",
"vitest": "^3.0.5",
"zeptomatch": "^2.0.0"
},
"scripts": {
"build": "unbuild",
"dev": "vitest",
"lint": "eslint . && prettier -c src test",
"lint:fix": "eslint . --fix && prettier -w src test",
"release": "pnpm test && pnpm build && changelogen --release && pnpm publish && git push --follow-tags",
"test": "pnpm lint && vitest run --coverage",
"test:types": "tsc --noEmit"
}
}
@@ -0,0 +1 @@
export * from "./dist/utils";
+55
View File
@@ -0,0 +1,55 @@
{
"name": "mlly",
"version": "1.8.2",
"description": "Missing ECMAScript module utils for Node.js",
"repository": "unjs/mlly",
"license": "MIT",
"sideEffects": false,
"type": "module",
"exports": {
"types": "./dist/index.d.ts",
"import": "./dist/index.mjs",
"require": "./dist/index.cjs"
},
"main": "./dist/index.cjs",
"module": "./dist/index.mjs",
"types": "./dist/index.d.ts",
"files": [
"dist"
],
"scripts": {
"build": "unbuild",
"dev": "vitest",
"lint": "eslint src test && prettier -c src test",
"lint:fix": "eslint src test --fix && prettier -w src test",
"release": "pnpm test && pnpm build && changelogen --release && npm publish && git push --follow-tags",
"test": "pnpm lint && pnpm test:types && vitest run",
"test:types": "tsc --noEmit"
},
"dependencies": {
"acorn": "^8.16.0",
"pathe": "^2.0.3",
"pkg-types": "^1.3.1",
"ufo": "^1.6.3"
},
"devDependencies": {
"@types/node": "^25.5.0",
"@vitest/coverage-v8": "^4.1.0",
"changelogen": "^0.6.2",
"eslint": "^10.0.3",
"eslint-config-unjs": "^0.6.2",
"import-meta-resolve": "^4.2.0",
"jiti": "^2.6.1",
"prettier": "^3.8.1",
"std-env": "^4.0.0",
"typescript": "^5.9.3",
"unbuild": "^3.6.1",
"vitest": "^4.1.0"
},
"packageManager": "pnpm@10.20.0",
"pnpm": {
"onlyBuiltDependencies": [
"esbuild"
]
}
}