blog
blog copied to clipboard
写一个对象判空的babel插件
前言
上一篇写了通过写babel插件来入门ast, 在组内分享的时候,有同学说是不是可以写一个判空的插件呢?
把a.b => a && a.b呢?我觉得是的,这完全可以做呀!然后就尝试着在分享后写了一个。
在线示例:
https://astexplorer.net/#/gist/a54996b88a3fd57b65dbd9f2a14b4c91/fd5dbe0ea9ca616226980861f9d81e0984568753
转换前:
var change = babelCheckEmpty(a.b.c.d);
var notChange = d && d.e;
转换后
var change = a && (a.b && a.b.c && a.b.c.d);
var notChange = d && d.e;
我只会去转换带有babelCheckEmpty 包裹的方法,这样避免影响其他方法的调用, 代码我贴在下面
module.exports = function (babel) {
const {types: t} = babel;
let isEnter = false;
let objectName = '';
let stack = [];
function getTemplateAst(tpl, opts = {}) {
let ast = babel.template(tpl, opts)({});
if (Array.isArray(ast)) {
return ast;
} else {
return [ast];
}
}
function generateExpressionStack(stack = []) {
if (stack.length === 0) {
return [];
}
let result = [];
stack.reduce((sum, current) => {
const nowStr = sum.concat('.').concat(current);
result.push(nowStr);
return nowStr;
});
return result;
}
return {
name: "ast-transform", // not required
visitor: {
CallExpression: {
enter(path) {
if (path.node.callee.name !== 'babelCheckEmpty') {
return;
}
isEnter = true;
},
exit(path) {
if (path.node.callee.name !== 'babelCheckEmpty') {
return;
}
isEnter = false;
const resultArr = generateExpressionStack(stack);
const arr = getTemplateAst(resultArr.join('&&')) || [];
if (arr.length === 0 || stack.length === 0) {
return;
}
path.replaceWith(
t.logicalExpression('&&', t.identifier(stack[0]), arr[0].expression),
);
stack = [];
},
},
MemberExpression(path) {
if (!isEnter || !path.node) return;
objectName = path.node.object.name;
if (t.isIdentifier(path.node.property)) {
stack.unshift(path.node.property.name);
}
if (objectName) {
stack.unshift(objectName);
}
},
},
};
};
由于直接用逻辑运算自己去构造一个 a.b && a.b.c && a.b.c.d 的ast过于复杂,其实是我不知道到底要怎么去写,所以我就使用了一个上一篇内容没有讲到的一个方法,直接利用babel.template 的API 根据传入的内容直接生成ast
let ast = babel.template(tpl, opts)({});
放入工程里的截图

参考资料: 1.Babel 从入门到插件开发 https://juejin.im/entry/5912ba62a22b9d005819cff7 2.ast 入门(从写babel插件来深入了解ast https://github.com/AnnVoV/blog/issues/26