- Uses the superb WASM-based
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
$ npm i parse-imports
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
// }
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 for details.
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
}
}
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.
Stars are always welcome!
For bugs and feature requests, please create an issue.