Skip to content

Commit

Permalink
feat(findExports): support for exports destructuring (#133)
Browse files Browse the repository at this point in the history
  • Loading branch information
antfu authored Jan 5, 2023
1 parent 1523bbc commit 7e877b6
Show file tree
Hide file tree
Showing 3 changed files with 25 additions and 4 deletions.
17 changes: 17 additions & 0 deletions src/analyze.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ export const DYNAMIC_IMPORT_RE = /import\s*\((?<expression>(?:[^()]+|\((?:[^()]+

export const EXPORT_DECAL_RE = /\bexport\s+(?<declaration>(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_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+/g;
const TYPE_RE = /^\s*?type\s/;
Expand Down Expand Up @@ -110,6 +111,21 @@ export function findExports (code: string): ESMExport[] {
.map(name => name.replace(/^.*?\sas\s/, "").trim());
}

const destructuredExports: NamedExport[] = matchAll(EXPORT_NAMED_DESTRUCT, code, { type: "named" });
for (const namedExport of destructuredExports) {
// @ts-expect-error groups
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()
)
}

// Find export default
const defaultExport: DefaultExport[] = matchAll(EXPORT_DEFAULT_RE, code, { type: "default", name: "default" });

Expand All @@ -121,6 +137,7 @@ export function findExports (code: string): ESMExport[] {
const exports: ESMExport[] = [
...declaredExports,
...namedExports,
...destructuredExports,
...defaultExport,
...starExports
];
Expand Down
6 changes: 3 additions & 3 deletions src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,11 @@ export function fileURLToPath (id: string): string {
// eslint-disable-next-line no-control-regex
const INVALID_CHAR_RE = /[\u0000-\u001F"#$&*+,/:;<=>?@[\]^`{|}\u007F]+/g;

export function sanitizeURIComponent (name: string = "", replacement: string = "_"): string {
export function sanitizeURIComponent (name = "", replacement = "_"): string {
return name.replace(INVALID_CHAR_RE, replacement);
}

export function sanitizeFilePath (filePath: string = "") {
export function sanitizeFilePath (filePath = "") {
return filePath.split(/[/\\]/g).map(p => sanitizeURIComponent(p)).join("/")
.replace(/^([A-Za-z])_\//, "$1:/");
}
Expand Down Expand Up @@ -46,7 +46,7 @@ export function toDataURL (code: string): string {
return `data:text/javascript;base64,${base64}`;
}

export function isNodeBuiltin (id: string = "") {
export function isNodeBuiltin (id = "") {
// node:fs/promises => fs
id = id.replace(/^node:/, "").split("/")[0];
return BUILTIN_MODULES.has(id);
Expand Down
6 changes: 5 additions & 1 deletion test/exports.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,11 @@ describe("findExports", () => {
// eslint-disable-next-line no-template-curly-in-string
"const a = `<div${JSON.stringify({ class: 42 })}>`;\nexport default true;": { type: "default", name: "default", names: ["default"] },
"export const enum foo { a = 'xx' }": { type: "declaration", names: ["foo"] },
"export enum bar { a = 'xx' }": { type: "declaration", names: ["bar"] }
"export enum bar { a = 'xx' }": { type: "declaration", names: ["bar"] },
"export const { a, b } = foo": { type: "named", names: ["a", "b"] },
"export const [ a, b ] = foo": { type: "named", names: ["a", "b"] },
"export const [\na\n, b ] = foo": { type: "named", names: ["a", "b"] },
"export const [ a:b,\nc = 1] = foo": { type: "named", names: ["b", "c"] }
};

for (const [input, test] of Object.entries(tests)) {
Expand Down

0 comments on commit 7e877b6

Please sign in to comment.