无法解析 Babel 插件中的 class 方法装饰器
Unable to parse class method decorator in a Babel plugin
我正在编写一个 Babel 插件来操作与特定装饰器相关的 AST 节点。我正在遍历 AST,但出于某种原因,我的插件未检测到方法装饰器 - 当访问者访问节点时,node.decorators
始终为 null。
这是插件:
import { ClassMethod, Decorator } from '@babel/types';
import { get } from 'lodash';
import { NodePath, PluginObj } from '@babel/core';
const providerArgumentsTransformer = (): PluginObj => ({
visitor: {
ClassMethod({ node, parent }: NodePath<ClassMethod>) {
const decorator = getProviderDecorator(node.decorators); // <- node.decorators is always null
if (getDecoratorName(decorator) === 'Provides') {
console.log('Success');
}
},
},
});
function getProviderDecorator(decorators: Array<Decorator> | undefined | null): Decorator | undefined {
return decorators?.find((decorator) => get(decorator, 'expression.callee.name') === 'Provides');
}
function getDecoratorName(decorator?: Decorator): string | undefined {
return get(decorator, 'expression.callee.name');
}
export default providerArgumentsTransformer;
我正在按如下方式测试装饰器:
import { PluginObj } from '@babel/core';
import * as babel from '@babel/core';
import providerArgumentsTransformer from './providerArgumentsTransformer';
const code = `class MainGraph {
Provides(clazz, propertyKey, descriptor) { }
@Provides()
someString(stringProvider) {
return stringProvider.theString;
}
}`;
describe('Provider Arguments Transformer', () => {
const uut: PluginObj = providerArgumentsTransformer();
it('Exposes transformer', () => {
babel.transformSync(code, {
plugins: [
['@babel/plugin-proposal-decorators', { legacy: true }],
['@babel/plugin-proposal-class-properties', { legacy: true }],
[uut, { legacy: true }],
],
configFile: false,
});
});
});
我想知道这个问题是否与 babel.transformSync
的使用方式有关,或者访问者配置不正确。
原来装饰器不见了,因为@babel/plugin-proposal-decorators clears the decorators 当它遍历 AST 时。
为了访问 @babel/plugin-proposal-decorators
之前的节点,我不得不稍微修改一下我的访问者。这种方法可能应该通过访问 ClassBody
或 ClassExpression
而不是 Program
.
来优化
const providerArgumentsTransformer: PluginObj = {
visitor: {
Program(path: NodePath<Program>) {
path.traverse(internalVisitor);
},
},
};
const internalVisitor = {
ClassMethod: {
enter({ node }: NodePath<ClassMethod>) {
// node.decorators are not null anymore
},
},
};
我正在编写一个 Babel 插件来操作与特定装饰器相关的 AST 节点。我正在遍历 AST,但出于某种原因,我的插件未检测到方法装饰器 - 当访问者访问节点时,node.decorators
始终为 null。
这是插件:
import { ClassMethod, Decorator } from '@babel/types';
import { get } from 'lodash';
import { NodePath, PluginObj } from '@babel/core';
const providerArgumentsTransformer = (): PluginObj => ({
visitor: {
ClassMethod({ node, parent }: NodePath<ClassMethod>) {
const decorator = getProviderDecorator(node.decorators); // <- node.decorators is always null
if (getDecoratorName(decorator) === 'Provides') {
console.log('Success');
}
},
},
});
function getProviderDecorator(decorators: Array<Decorator> | undefined | null): Decorator | undefined {
return decorators?.find((decorator) => get(decorator, 'expression.callee.name') === 'Provides');
}
function getDecoratorName(decorator?: Decorator): string | undefined {
return get(decorator, 'expression.callee.name');
}
export default providerArgumentsTransformer;
我正在按如下方式测试装饰器:
import { PluginObj } from '@babel/core';
import * as babel from '@babel/core';
import providerArgumentsTransformer from './providerArgumentsTransformer';
const code = `class MainGraph {
Provides(clazz, propertyKey, descriptor) { }
@Provides()
someString(stringProvider) {
return stringProvider.theString;
}
}`;
describe('Provider Arguments Transformer', () => {
const uut: PluginObj = providerArgumentsTransformer();
it('Exposes transformer', () => {
babel.transformSync(code, {
plugins: [
['@babel/plugin-proposal-decorators', { legacy: true }],
['@babel/plugin-proposal-class-properties', { legacy: true }],
[uut, { legacy: true }],
],
configFile: false,
});
});
});
我想知道这个问题是否与 babel.transformSync
的使用方式有关,或者访问者配置不正确。
原来装饰器不见了,因为@babel/plugin-proposal-decorators clears the decorators 当它遍历 AST 时。
为了访问 @babel/plugin-proposal-decorators
之前的节点,我不得不稍微修改一下我的访问者。这种方法可能应该通过访问 ClassBody
或 ClassExpression
而不是 Program
.
const providerArgumentsTransformer: PluginObj = {
visitor: {
Program(path: NodePath<Program>) {
path.traverse(internalVisitor);
},
},
};
const internalVisitor = {
ClassMethod: {
enter({ node }: NodePath<ClassMethod>) {
// node.decorators are not null anymore
},
},
};