forked from public/fvtt-cthulhu-eternal
279 lines
7.0 KiB
Markdown
279 lines
7.0 KiB
Markdown
|
<h1 align="center">
|
||
|
parse-imports
|
||
|
</h1>
|
||
|
|
||
|
<div align="center">
|
||
|
<a href="https://npmjs.org/package/parse-imports">
|
||
|
<img src="https://badgen.now.sh/npm/v/parse-imports" alt="version" />
|
||
|
</a>
|
||
|
<a href="https://github.com/TomerAberbach/parse-imports/actions">
|
||
|
<img src="https://github.com/TomerAberbach/parse-imports/workflows/CI/badge.svg" alt="CI" />
|
||
|
</a>
|
||
|
<a href="https://github.com/sponsors/TomerAberbach">
|
||
|
<img src="https://img.shields.io/static/v1?label=Sponsor&message=%E2%9D%A4&logo=GitHub&color=%23fe8e86" alt="Sponsor">
|
||
|
</a>
|
||
|
</div>
|
||
|
|
||
|
<div align="center">
|
||
|
A blazing fast ES module imports parser.
|
||
|
</div>
|
||
|
|
||
|
## Features
|
||
|
|
||
|
- Uses the superb WASM-based
|
||
|
[`es-module-lexer`](https://github.com/guybedford/es-module-lexer) under the
|
||
|
hood
|
||
|
- Identifies module specifier types (e.g. relative file import, package import,
|
||
|
builtin import, etc.)
|
||
|
- Unescapes module specifier escape sequences
|
||
|
- Collects default, named, and namespace imports
|
||
|
- Works with dynamic imports
|
||
|
- Resolves module specifier paths via `require.resolve`
|
||
|
|
||
|
## Install
|
||
|
|
||
|
```sh
|
||
|
$ npm i parse-imports
|
||
|
```
|
||
|
|
||
|
## Usage
|
||
|
|
||
|
```js
|
||
|
import { parseImports } from 'parse-imports'
|
||
|
|
||
|
const code = `
|
||
|
import a from 'b'
|
||
|
import * as c from './d'
|
||
|
import { e as f, g as h, i } from '/j'
|
||
|
import k, { l as m } from 'n'
|
||
|
import o, * as p from "./q"
|
||
|
import r, { s as t, u } from "/v"
|
||
|
import fs from 'fs'
|
||
|
|
||
|
;(async () => {
|
||
|
await import("w")
|
||
|
await import("x" + "y")
|
||
|
})()
|
||
|
`
|
||
|
|
||
|
// Lazily iterate over iterable of imports
|
||
|
for (const $import of await parseImports(code)) {
|
||
|
console.log($import)
|
||
|
}
|
||
|
|
||
|
// Or get as an array of imports
|
||
|
const imports = [...(await parseImports(code))]
|
||
|
|
||
|
console.log(imports[0])
|
||
|
//=>
|
||
|
// {
|
||
|
// startIndex: 3,
|
||
|
// endIndex: 20,
|
||
|
// isDynamicImport: false,
|
||
|
// moduleSpecifier: {
|
||
|
// type: 'package',
|
||
|
// startIndex: 17,
|
||
|
// endIndex: 20,
|
||
|
// isConstant: true,
|
||
|
// code: `'b'`,
|
||
|
// value: 'b',
|
||
|
// resolved: undefined
|
||
|
// },
|
||
|
// importClause: {
|
||
|
// default: 'a',
|
||
|
// named: [],
|
||
|
// namespace: undefined
|
||
|
// }
|
||
|
// }
|
||
|
|
||
|
console.log(imports[1])
|
||
|
//=>
|
||
|
// {
|
||
|
// startIndex: 23,
|
||
|
// endIndex: 47,
|
||
|
// isDynamicImport: false,
|
||
|
// moduleSpecifier: {
|
||
|
// type: 'relative',
|
||
|
// startIndex: 42,
|
||
|
// endIndex: 47,
|
||
|
// isConstant: true,
|
||
|
// code: `'./d'`,
|
||
|
// value: './d',
|
||
|
// resolved: undefined
|
||
|
// },
|
||
|
// importClause: {
|
||
|
// default: undefined,
|
||
|
// named: [],
|
||
|
// namespace: 'c'
|
||
|
// }
|
||
|
// }
|
||
|
|
||
|
console.log(imports[5])
|
||
|
//=>
|
||
|
// {
|
||
|
// startIndex: 153,
|
||
|
// endIndex: 186,
|
||
|
// isDynamicImport: false,
|
||
|
// moduleSpecifier: {
|
||
|
// type: 'absolute',
|
||
|
// startIndex: 182,
|
||
|
// endIndex: 186,
|
||
|
// isConstant: true,
|
||
|
// code: '"/v"',
|
||
|
// value: '/v',
|
||
|
// resolved: undefined
|
||
|
// },
|
||
|
// importClause: {
|
||
|
// default: 'r',
|
||
|
// named: [
|
||
|
// { specifier: 's', binding: 't' },
|
||
|
// { specifier: 'u', binding: 'u' }
|
||
|
// ],
|
||
|
// namespace: undefined
|
||
|
// }
|
||
|
// }
|
||
|
|
||
|
console.log(imports[7])
|
||
|
//=>
|
||
|
// {
|
||
|
// startIndex: 238,
|
||
|
// endIndex: 249,
|
||
|
// isDynamicImport: true,
|
||
|
// moduleSpecifier: {
|
||
|
// type: 'package',
|
||
|
// startIndex: 245,
|
||
|
// endIndex: 248,
|
||
|
// isConstant: true,
|
||
|
// code: '"w"',
|
||
|
// value: 'w',
|
||
|
// resolved: undefined
|
||
|
// },
|
||
|
// importClause: undefined
|
||
|
// }
|
||
|
|
||
|
console.log(imports[8])
|
||
|
//=>
|
||
|
// {
|
||
|
// startIndex: 260,
|
||
|
// endIndex: 277,
|
||
|
// isDynamicImport: true,
|
||
|
// moduleSpecifier: {
|
||
|
// type: 'unknown',
|
||
|
// startIndex: 267,
|
||
|
// endIndex: 276,
|
||
|
// isConstant: false,
|
||
|
// code: '"x" + "y"',
|
||
|
// value: undefined,
|
||
|
// resolved: undefined
|
||
|
// },
|
||
|
// importClause: undefined
|
||
|
// }
|
||
|
```
|
||
|
|
||
|
## API
|
||
|
|
||
|
Use `parseImports` when you're able to await a `Promise` result and
|
||
|
`parseImportsSync` otherwise.
|
||
|
|
||
|
> [!IMPORTANT]
|
||
|
>
|
||
|
> You can only call `parseImportsSync` once the WASM has loaded. You can be sure
|
||
|
> this has happened by awaiting the exported `wasmLoadPromise`.
|
||
|
|
||
|
See the [type definitions](./src/index.d.ts) for details.
|
||
|
|
||
|
### Types
|
||
|
|
||
|
<!-- eslint-skip -->
|
||
|
|
||
|
```ts
|
||
|
type ModuleSpecifierType =
|
||
|
| 'invalid'
|
||
|
| 'absolute'
|
||
|
| 'relative'
|
||
|
| 'builtin'
|
||
|
| 'package'
|
||
|
| 'unknown'
|
||
|
|
||
|
type Import = {
|
||
|
startIndex: number
|
||
|
endIndex: number
|
||
|
isDynamicImport: boolean
|
||
|
moduleSpecifier: {
|
||
|
type: ModuleSpecifierType
|
||
|
startIndex: number
|
||
|
endIndex: number
|
||
|
isConstant: boolean
|
||
|
code: string
|
||
|
value?: string
|
||
|
resolved?: string
|
||
|
}
|
||
|
importClause?: {
|
||
|
default?: string
|
||
|
named: string[]
|
||
|
namespace?: string
|
||
|
}
|
||
|
}
|
||
|
```
|
||
|
|
||
|
#### `Import`
|
||
|
|
||
|
`code.substring(startIndex, endIndex)` returns the full import statement or
|
||
|
expression.
|
||
|
`code.substring(moduleSpecifier.startIndex, moduleSpecifier.endIndex)` returns
|
||
|
the module specifier including quotes.
|
||
|
|
||
|
`moduleSpecifier.isConstant` is `true` when the import is not a dynamic import
|
||
|
(`isDynamicImport` is `false`), or when the import is a dynamic import where the
|
||
|
specifier is a simple string literal (e.g. `import('fs')`, `import("fs")`,
|
||
|
``import(`fs`)``).
|
||
|
|
||
|
If `moduleSpecifier.isConstant` is `false`, then `moduleSpecifier.type` is
|
||
|
`'unknown'`. Otherwise, it is set according to the following rules:
|
||
|
|
||
|
- `'invalid'` if the module specifier is the empty string
|
||
|
- `'absolute'` if the module specifier is an absolute file path
|
||
|
- `'relative'` if the module specifier is a relative file path
|
||
|
- `'builtin'` if the module specifier is the name of a builtin Node.js package
|
||
|
- `'package'` otherwise
|
||
|
|
||
|
`moduleSpecifier.code` is the module specifier as it was written in the code.
|
||
|
For non-constant dynamic imports it could be a complex expression.
|
||
|
|
||
|
`moduleSpecifier.value` is `moduleSpecifier.code` without string literal quotes
|
||
|
and unescaped if `moduleSpecifier.isConstant` is `true`. Otherwise, it is
|
||
|
`undefined`.
|
||
|
|
||
|
`moduleSpecifier.resolved` is set if the `resolveFrom` option is set and
|
||
|
`moduleSpecifier.value` is not `undefined`.
|
||
|
|
||
|
`importClause` is only `undefined` if `isDynamicImport` is `true`.
|
||
|
|
||
|
`importClause.default` is the default import identifier or `undefined` if the
|
||
|
import statement does not have a default import.
|
||
|
|
||
|
`importClause.named` is the array of objects representing the named imports of
|
||
|
the import statement. It is empty if the import statement does not have any
|
||
|
named imports. Each object in the array has a `specifier` field set to the
|
||
|
imported identifier and a `binding` field set to the identifier for accessing
|
||
|
the imported value. For example, `import { a, x as y } from 'something'` would
|
||
|
have the following array for `importClause.named`:
|
||
|
`[{ specifier: 'a', binding: 'a' }, { specifier: 'x', binding: 'y' }]`.
|
||
|
|
||
|
`importClause.namespace` is the namespace import identifier or `undefined` if
|
||
|
the import statement does not have a namespace import.
|
||
|
|
||
|
## Contributing
|
||
|
|
||
|
Stars are always welcome!
|
||
|
|
||
|
For bugs and feature requests,
|
||
|
[please create an issue](https://github.com/TomerAberbach/parse-imports/issues/new).
|
||
|
|
||
|
## License
|
||
|
|
||
|
[MIT](https://github.com/TomerAberbach/parse-imports/blob/main/license) ©
|
||
|
[Tomer Aberbach](https://github.com/TomerAberbach) \
|
||
|
[Apache 2.0](https://github.com/TomerAberbach/parse-imports/blob/main/license-apache) ©
|
||
|
[Google](https://github.com/TomerAberbach/parse-imports/blob/main/notice-apache)
|