initial commit
This commit is contained in:
487
node_modules/mlly/README.md
generated
vendored
Normal file
487
node_modules/mlly/README.md
generated
vendored
Normal file
@@ -0,0 +1,487 @@
|
||||
# mlly
|
||||
|
||||
> 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 recommand.
|
||||
|
||||
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`
|
||||
|
||||
Resolve a module by respecting [ECMAScript Resolver algorithm](https://nodejs.org/dist/latest-v14.x/docs/api/esm.html#esm_resolver_algorithm)
|
||||
(based on experimental Node.js implementation extracted from [wooorm/import-meta-resolve](https://github.com/wooorm/import-meta-resolve)).
|
||||
|
||||
Additionally supports resolving without extension and `/index` similar to CommonJS.
|
||||
|
||||
```js
|
||||
import { resolve } 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`
|
||||
|
||||
Similar to `resolve` but returns a path instead of URL using `fileURLToPath`.
|
||||
|
||||
```js
|
||||
import { resolvePath } 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 resault 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 quikcly analyze ESM synax and extract static `import`/`export`
|
||||
- Super fast Regex based implementation
|
||||
- Handle most of 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 previusly 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('pathe'))
|
||||
```
|
||||
|
||||
## Evaluating Modules
|
||||
|
||||
Set of utilities to evaluate ESM modules using `data:` imports
|
||||
- Allow evaluating modules using
|
||||
- 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 { toDataURL } 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/'))
|
||||
```
|
||||
|
||||
### `normalizeid`
|
||||
|
||||
Ensures id has either of `node:`, `data:`, `http:`, `https:` or `file:` protocols.
|
||||
|
||||
```js
|
||||
import { ensureProtocol } 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))
|
||||
```
|
||||
|
||||
### `sanitizeURIComponent`
|
||||
|
||||
Replace reserved charachters 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'))
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
[MIT](./LICENSE) - Made with ❤️
|
||||
Reference in New Issue
Block a user