diff --git a/packages/esbuild-plugin-ast-vue/src/plugin.ts b/packages/esbuild-plugin-ast-vue/src/plugin.ts index 3d9ec2d..871e9c8 100644 --- a/packages/esbuild-plugin-ast-vue/src/plugin.ts +++ b/packages/esbuild-plugin-ast-vue/src/plugin.ts @@ -15,6 +15,8 @@ import { resolveStyle } from './style'; import { resolveTemplate } from './template'; import { resolvePath, validateDependency } from './utils'; +type ExtractNonArray = T extends Array ? never : T; + export interface AstParserVueOptions extends AstParserOptions { templateOptions?: Pick< SFCTemplateCompileOptions, @@ -33,7 +35,7 @@ export interface AstParserVueOptions extends AstParserOptions { | 'postcssOptions' | 'postcssPlugins' >; - templateVisitor: AstParserOptions['visitor']; + templateVisitor: ExtractNonArray; } validateDependency(); @@ -42,7 +44,7 @@ export function astParserVue({ templateOptions, scriptOptions, styleOptions, - visitor, + visitors, templateVisitor, }: AstParserVueOptions): Plugin { return { @@ -88,7 +90,7 @@ export function astParserVue({ }); return { - contents: parser(code, visitor), + contents: parser(code, visitors), errors: error, resolveDir: dirname, loader: isTs ? 'ts' : 'js', diff --git a/packages/esbuild-plugin-ast/src/__tests__/parser.spec.ts b/packages/esbuild-plugin-ast/src/__tests__/parser.spec.ts index ac41a7f..185804a 100644 --- a/packages/esbuild-plugin-ast/src/__tests__/parser.spec.ts +++ b/packages/esbuild-plugin-ast/src/__tests__/parser.spec.ts @@ -4,9 +4,8 @@ import { parser } from '../parser'; describe('parser', () => { const source = 'const value = 1;'; - it('should return the source if no valid visitor is provided', () => { - expect(parser(source, {})).toBe(source); + expect(parser(source, {})).toContain(source); }); it('should transform the source if visitor is a valid visitor object', () => { @@ -26,4 +25,36 @@ describe('parser', () => { expect(parser(source, visitor)).toMatch('const value = 2;'); }); + + it('should transform the source if multiple visitor are passed', () => { + const visitors: Visitor[] = [ + { + enter: (node) => { + if (node.type !== 'Literal') { + return node; + } + + return { + ...node, + value: 2, + raw: '2', + }; + }, + }, + { + enter: (node) => { + if (node.type !== 'Identifier') { + return node; + } + + return { + ...node, + name: 'expected', + }; + }, + }, + ]; + + expect(parser(source, visitors)).toMatch('const expected = 2;'); + }); }); diff --git a/packages/esbuild-plugin-ast/src/__tests__/plugin.spec.ts b/packages/esbuild-plugin-ast/src/__tests__/plugin.spec.ts index 49692c5..0dcfe17 100644 --- a/packages/esbuild-plugin-ast/src/__tests__/plugin.spec.ts +++ b/packages/esbuild-plugin-ast/src/__tests__/plugin.spec.ts @@ -12,7 +12,7 @@ describe('astParser', () => { const virtualPackage = 'ast-plugin'; const pluginOptions: AstParserOptions = { - visitor: { + visitors: { enter(node) { if ( node.type === 'CallExpression' && diff --git a/packages/esbuild-plugin-ast/src/parser.ts b/packages/esbuild-plugin-ast/src/parser.ts index 5590772..1c1f3ba 100644 --- a/packages/esbuild-plugin-ast/src/parser.ts +++ b/packages/esbuild-plugin-ast/src/parser.ts @@ -16,8 +16,8 @@ const isFunction = (v: unknown) => * Create an AST representation of the provided source and use the * visitor object to transform it if provided */ -export function parser(source: string, visitor: Visitor) { - if (!visitor) { +export function parser(source: string, visitors: Visitor | Visitor[]) { + if (!visitors) { /* eslint-disable-next-line no-console */ console.warn( '[esbuildPluginAst]: No visitor provided, the plugin will have no effect.', @@ -25,16 +25,20 @@ export function parser(source: string, visitor: Visitor) { return source; } - if (!isFunction(visitor.enter) && !isFunction(visitor.leave)) { - return source; - } + const visitorArray = Array.isArray(visitors) ? visitors : [visitors]; - const ast = Parser.parse(source, { + let ast = Parser.parse(source, { ecmaVersion: 'latest', sourceType: 'module', }) as Node; - const newAst = replace(ast, visitor); + for (const visitor of visitorArray) { + if (!isFunction(visitor.enter) && !isFunction(visitor.leave)) { + continue; + } + + ast = replace(ast, visitor); + } - return generate(newAst); + return generate(ast); } diff --git a/packages/esbuild-plugin-ast/src/plugin.ts b/packages/esbuild-plugin-ast/src/plugin.ts index 190e379..ca25500 100644 --- a/packages/esbuild-plugin-ast/src/plugin.ts +++ b/packages/esbuild-plugin-ast/src/plugin.ts @@ -9,10 +9,13 @@ import type { Plugin, OnResolveArgs } from 'esbuild'; export interface AstParserOptions { dependencies?: string[]; - visitor: Visitor; + visitors: Visitor | Visitor[]; } -export function astParser({ dependencies, visitor }: AstParserOptions): Plugin { +export function astParser({ + dependencies, + visitors, +}: AstParserOptions): Plugin { return { name: 'astParser', setup(build) { @@ -112,7 +115,7 @@ export function astParser({ dependencies, visitor }: AstParserOptions): Plugin { const source = await readFile(args.path, 'utf-8'); return { - contents: parser(source, visitor), + contents: parser(source, visitors), }; }); }, diff --git a/tsconfig.eslint.json b/tsconfig.eslint.json index a7aa0ef..ffb2afa 100644 --- a/tsconfig.eslint.json +++ b/tsconfig.eslint.json @@ -1,7 +1,8 @@ { "extends": "./tsconfig.base.json", "compilerOptions": { - "noEmit": true + "noEmit": true, + "types": ["@liip/esbuild-plugin-ast"] }, "include": ["."] }