UNPKG

unplugin-ast

Version:

Manipulate the AST to transform your code.

107 lines (106 loc) 3.25 kB
import { t as toArray } from "./dist-DYox6mU4.js"; import { babelParse, babelParseFile, getBabelParserOptions, getLang, walkASTAsync } from "ast-kit"; import { createUnplugin } from "unplugin"; import { MagicStringAST, generateTransform } from "magic-string-ast"; //#region src/core/options.ts function resolveOptions(options) { return { include: options.include || [/\.[jt]sx?$/], exclude: options.exclude || void 0, enforce: options.enforce || void 0, parserOptions: options.parserOptions || {}, transformer: options.transformer ? toArray(options.transformer) : [] }; } //#endregion //#region src/core/utils.ts function useNodeRef() { const nodeRefs = /* @__PURE__ */ new Map(); function getNodeRef(node) { if (nodeRefs.has(node)) return nodeRefs.get(node); const ref = { value: node, set(node) { this.value = node; } }; nodeRefs.set(node, ref); return ref; } return { nodeRefs, getNodeRef }; } //#endregion //#region src/core/transform.ts async function getTransformersByFile(transformer, id) { return (await Promise.all(transformer.map(async (t) => { if (t.transformInclude && !await t.transformInclude(id)) return void 0; return { transformer: t, nodes: [] }; }))).filter((t) => !!t); } async function transform(code, id, options) { const { getNodeRef } = useNodeRef(); const transformers = await getTransformersByFile(options.transformer, id); if (transformers.length === 0) return; await walkASTAsync(babelParseFile(code, getBabelParserOptions(getLang(id), options.parserOptions)), { async enter(node, parent, key, index) { for (const { transformer, nodes } of transformers) { if (transformer.onNode) { if (!await transformer.onNode?.(node, parent, index)) continue; } nodes.push(getNodeRef(node)); } } }); const s = new MagicStringAST(code); for (const { transformer, nodes } of transformers) for (const node of nodes) { const value = node.value; if (!value) continue; const result = await transformer.transform(value, code, { id }); if (result) { let newAST; if (typeof result === "string") { s.overwriteNode(value, result); newAST = babelParse(`{${result}}`, getLang(id), options.parserOptions).body[0].body[0]; if (newAST.type === "ExpressionStatement") newAST = newAST.expression; newAST.start = value.start; newAST.end = value.end; } else { const { generate } = await import("@babel/generator"); let code = generate(result).code; if (result.type.endsWith("Expression")) code = `(${code})`; s.overwriteNode(value, code); newAST = result; } node.set(newAST); } else if (result === false) { node.set(void 0); s.removeNode(value); } } for (const { transformer } of transformers) await transformer.finalize?.(s); return generateTransform(s, id); } //#endregion //#region src/index.ts const AST = createUnplugin((userOptions = {}) => { const { include, exclude, enforce, ...options } = resolveOptions(userOptions); return { name: "unplugin-ast", enforce, transform: { filter: { id: { include, exclude } }, handler(code, id) { return transform(code, id, options); } } }; }); //#endregion export { transform as n, resolveOptions as r, AST as t };