Fast and easy parser for declarations of import and export from the ECMAScript standard, with TypeScript syntax support.
parse-imports-exports works for syntactically correct, well-formatted code (for example, by prettier). Single-line and multi-line ECMAScript comments in import/export statements are supported.
Imagine a module with the following content:
/** * Imports. */ // {Qux: [{start: 17, end: 58, names: {baz: {by: 'foo'}}, types: {Bar: {}}}]} import {foo as baz, type Bar} from 'Qux'; // {Qux: [{start: 80, end: 112, namespace: 'foo', default: 'Foo'}]} import Foo, * as foo from 'Qux'; // {Qux: [{start: 114, end: 127}]} const foo = await import('Qux'); // {Qux: [{start: 128, end, 134}]} const foo = require('Qux'); // {Qux: [{start: 142, end: 175, names: {Baz: {by: 'Foo'}, Bar: {}}}]} import type {Foo as Baz, Bar} from 'Qux'; // {Qux: [{start: 201, end: 233, namespace: 'Foo'}]} import type * as Foo from 'Qux'; // {Qux: [{start: 137, end: 141}]} type Foo = typeof import('Qux'); /** * Reexports. */ // {Qux: [{start: 254, end: 295, names: {baz: {by: 'foo'}}, types: {Bar: {}}}]} export {foo as baz, type Bar} from 'Qux'; // {Qux: [{start: 319, end: 346, namespace: 'foo'}]} export * as foo from 'Qux'; // {Qux: [{start: 365, end: 385}]} export * from 'Qux'; // {Qux: [{start: 409, end: 450, names: {Baz: {by: 'Foo'}, Bar: {}}}]} export type {Foo as Baz, Bar} from 'Qux'; // {Qux: [{start: 478, end: 510, namespace: 'Foo'}]} export type * as Foo from 'Qux'; // {Qux: [{start: 533, end: 558}]} export type * from 'Qux'; /** * Exports. */ // {start: 578, end: 596} export default 42; // [{start: 614, end: 644, names: {baz: {by: 'foo'}}, types: {Bar: {}}}] export {foo as baz, type Bar}; // {foo: {start: 668, end: 689, kind: 'const'}} export const foo = 2; // [{start: 711, end: 741, names: {Baz: {by: 'Foo'}, Bar: {}}}] export type {Foo as Baz, Bar}; // {T: {start: 758, end: 781}} export type T = number; // {I: [{start: 803, end: 836}]} export interface I { foo: number; } // {N: [{start: 858, end: 891}]} export namespace N { foo: number; } // {start: 901, end: 915} module.exports = 42; // {foo: {start: 917, end: 931, startsWithModule: true}} module.exports.foo = 2;
Let its content be stored as a string in the variable source. Then it can be parsed like this:
import {parseImportsExports} from 'parse-imports-exports'; const importsExports = parseImportsExports(source); // Now `importsExports` has the following shape (the `start` and `end` indices, which indicate // the beginning and end of the corresponding statement in the source, may differ): const importsExportsShape = { /** * Imports. */ // import {foo as baz, type Bar} from 'Qux'; namedImports: {Qux: [{start: 17, end: 58, names: {baz: {by: 'foo'}}, types: {Bar: {}}}]}, // import Foo, * as foo from 'Qux'; namespaceImports: {Qux: [{start: 80, end: 112, namespace: 'foo', default: 'Foo'}]}, // const foo = await import('Qux'); dynamicImports: {Qux: [{start: 114, end: 127}]}, // const foo = require('Qux'); requires: {Qux: [{start: 128, end: 134}]}, // import type {Foo as Baz, Bar} from 'Qux'; typeNamedImports: {Qux: [{start: 142, end: 175, names: {Baz: {by: 'Foo'}, Bar: {}}}]}, // import type * as Foo from 'Qux'; typeNamespaceImports: {Qux: [{start: 201, end: 233, namespace: 'Foo'}]}, // type Foo = typeof import('Qux'); typeDynamicImports: {Qux: [{start: 137, end: 141}]}, /** * Reexports. */ // export {foo as baz, type Bar} from 'Qux'; namedReexports: {Qux: [{start: 254, end: 295, names: {baz: {by: 'foo'}}, types: {Bar: {}}}]}, // export * as foo from 'Qux'; namespaceReexports: {Qux: [{start: 319, end: 346, namespace: 'foo'}]}, // export * from 'Qux'; starReexports: {Qux: [{start: 365, end: 385}]}, // export type {Foo as Baz, Bar} from 'Qux'; typeNamedReexports: {Qux: [{start: 409, end: 450, names: {Baz: {by: 'Foo'}, Bar: {}}}]}, // export type * as Foo from 'Qux'; typeNamespaceReexports: {Qux: [{start: 478, end: 510, namespace: 'Foo'}]}, // export type * from 'Qux'; typeStarReexports: {Qux: [{start: 533, end: 558}]}, /** * Exports. */ // export default 42; defaultExport: {start: 578, end: 596}, // export {foo as baz, type Bar}; namedExports: [{start: 614, end: 644, names: {baz: {by: 'foo'}}, types: {Bar: {}}}], // export const foo = 2; declarationExports: {foo: {start: 668, end: 689, kind: 'const'}}, // export type {Foo as Baz, Bar}; typeNamedExports: [{start: 711, end: 741, names: {Baz: {by: 'Foo'}, Bar: {}}}], // export type T = number; typeExports: {T: {start: 758, end: 781}}, // export interface I {foo: number}; interfaceExports: {I: [{start: 803, end: 836}]}, // export namespace N {foo: number}; namespaceExports: {N: [{start: 858, end: 891}]}, // module.exports = 42; commonJsNamespaceExport: {start, end}, // module.exports.foo = 2; commonJsExports: {foo: {start, end, startsWithModule: true}}, };
Requires node version 10 or higher:
npm install parse-imports-exports
parse-imports-exports works in any environment that supports ES2018 (because package uses RegExp Named Capture Groups).
parse-imports-exports exports one runtime value — the parseImportsExports function:
import {parseImportsExports} from 'parse-imports-exports'; import type {ImportsExports, Options} from 'parse-imports-exports'; const importsExports: ImportsExports = parseImportsExports('some source code (as string)'); // or with optional options: const importsExports = parseImportsExports('some source code (as string)', options); // all option fields are optional boolean with default `false` value const options: Options = { /** * If `true`, then we ignore `module.exports = ...`/`(module.)exports.foo = ...` expressions * during parsing (maybe a little faster). * By default (if `false` or skipped option), `module.exports = ...`/`(module.)exports.foo = ...` * expressions are parsed. */ ignoreCommonJsExports: false; /** * If `true`, then we ignore `import(...)` expressions during parsing (maybe a little faster). * By default (if `false` or skipped option), `import(...)` expressions are parsed. */ ignoreDynamicImports: false; /** * If `true`, then we ignore regular expression literals (`/.../`) * during parsing (maybe a little faster). * By default (if `false` or skipped option), regular expression literals are parsed. */ ignoreRegexpLiterals: false; /** * If `true`, then we ignore `require(...)` expressions during parsing (maybe a little faster). * By default (if `false` or skipped option), `require(...)` expressions are parsed. */ ignoreRequires: false; /** * If `true`, then we ignore string literals during parsing (maybe a little faster). * By default (if `false` or skipped option), string literals are parsed, that is, * the text inside them cannot be interpreted as another expression. */ ignoreStringLiterals: false; };
parse-imports-exports also exports types included in the API:
export type { /** * Parsed JSON presentation of imports, exports and reexports of ECMAScript/TypeScript module. */ ImportsExports, /** * Kind of exported declaration. */ Kind, /** * Options of `parseImportsExports` function. */ Options, };