之前看了别人写的async-catch-loader,于是乎自己尝试写着玩,想对所有Promise对象加入catch函数,但是发现在AST中根本判断不了变量是否是promise
(可能是自己太菜了尚且不知道如何在ast中判断~),于是只写了在显示Promise声明的情况下的场景。还有好多场景,没时间研究了(╥╯^╰╥)
直接上代码
const core = require('@babel/core')
const parser = require('@babel/parser')
const t = require('@babel/types')
const traverse = require('@babel/traverse').default
const DEFAULT_OPTIONS = {
catchCode: identifier => `console.error(${identifier})`,
identifier: 'e'
}
module.exports = function (source) {
let options = {
...DEFAULT_OPTIONS,
...this.getOptions()
}
let ast = parser.parse(source, {
sourceType: 'module' // 支持 es6 module
})
if (typeof options.catchCode === 'function') {
options.catchCode = options.catchCode(options.identifier)
}
let catchNode = parser.parse(options.catchCode).program.body
const promises = []
traverse(ast, {
NewExpression ({ node, parentPath }) {
const isPromise = node.callee.name === 'Promise'
if (isPromise) {
promises.push(parentPath.node.id.name)
}
},
CallExpression (path) {
const { node, parentPath } = path
const callee = node.callee
// !t.isMemberExpression(parentPath.node)这一层判断是替换父节点之后,防止p.then()表达式再次进入
if (!t.isMemberExpression(parentPath.node) && t.isMemberExpression(callee) && t.isIdentifier(callee.property) && t.isIdentifier(callee.object)) {
const isThenIdentifier = callee.property.name === 'then'
const isPromise = promises.includes(callee.object.name)
if (isThenIdentifier && isPromise) { // 说明是一个promise调用then表达
const params = t.arrowFunctionExpression([t.identifier(options.identifier)], t.blockStatement(catchNode))
const expressionStatement = t.expressionStatement(
t.callExpression(
t.memberExpression(
node,
t.identifier('catch')
),
[params]
)
)
parentPath.replaceWith(expressionStatement)
}
}
}
})
return core.transformFromAstSync(ast, null, {
configFile: false
}).code
}
const p = new Promise((resolve, reject) => {
resolve()
})
p.then(()=>{})
上面代码将转成
const p = new Promise((resolve, reject) => {
resolve();
});
p.then(()=>{}).catch(err => {
console.error(err);
});
网友评论