为什么 escodegen 和 esprima 会在我的源代码上生成括号包装器?
Why does escodegen and esprima generate a parenthesis wrapper on my source code?
我正在使用 escodegen
在我的语句中添加结束代码,如下所示。在 leave 方法中,我在语句末尾附加了一个 .toArray()
调用。
const esprima = require('esprima');
const estraverse = require('estraverse');
const escodegen = require('escodegen');
const ast = esprima.parse('db.find()');
let finished = false;
estraverse.traverse(ast, {
leave: (node, parent) => {
if (node.type === esprima.Syntax.ExpressionStatement && !finished) {
finished = true;
let statement = escodegen.generate(node);
statement = `${statement.substring(0, statement.lastIndexOf(';'))}.toArray()`;
const findAst = esprima.parse(statement);
node.arguments = findAst.body[0].expression.arguments;
node.callee = findAst.body[0].expression.callee;
node.type = findAst.body[0].expression.type;
}
},
});
const generated = escodegen.generate(ast);
console.log('generated code:', generated);
以上代码的输出是:generated code: (db.find().toArray())
。
我不明白为什么它会在我的源代码上加上括号。我的源代码有什么问题吗?
您生成的 AST 不正确。 ExpressionStatement
的形式为 {type: "ExpressionStatement", expression... }
。
您正在修改您的 ExpressionStatement
,将其附加到 arguments
和 callee
,并且您正在更改其 type
(更改为 CallExpression
)。这里:
node.arguments = findAst.body[0].expression.arguments;
node.callee = findAst.body[0].expression.callee;
node.type = findAst.body[0].expression.type;
产生了一个奇怪的 AST。
你可以简单地看到它:console.log('generated ast: %j', ast);
一个快速的解决方案是将提到的部分附加到它们所属的位置(expression
)。结果:
let finished = false;
estraverse.traverse(ast, {
leave: (node, parent) => {
if (node.type === esprima.Syntax.ExpressionStatement && !finished) {
finished = true;
let statement = escodegen.generate(node);
statement = `${statement.substring(0, statement.lastIndexOf(';'))}.toArray()`;
console.log(statement);
const findAst = esprima.parse(statement);
node.expression.arguments = findAst.body[0].expression.arguments;
node.expression.callee = findAst.body[0].expression.callee;
node.expression.type = findAst.body[0].expression.type;
}
},
});
它将生成正确的 AST,输出预期的 db.find().toArray();
。
但是我认为代码有点复杂并且做了太多工作,它解析 db.find()
然后生成代码并再次解析它。
此外,您可以 return this.break()
在 leave
中停止遍历。
以我的愚见,这很清楚:
var new_expr = {
type: "CallExpression",
callee: {
type: "MemberExpression",
computed: false,
object: null,
property: {
type: "Identifier",
name: "toArray"
}
},
arguments: []
};
const ast3 = esprima.parse('db.find()');
estraverse.traverse(ast3, {
leave: function(node, parent) {
if (node.type === esprima.Syntax.ExpressionStatement) {
new_expr.callee.object = node.expression;
node.expression = new_expr;
return this.break();
}
},
});
我希望你觉得这有用。
我正在使用 escodegen
在我的语句中添加结束代码,如下所示。在 leave 方法中,我在语句末尾附加了一个 .toArray()
调用。
const esprima = require('esprima');
const estraverse = require('estraverse');
const escodegen = require('escodegen');
const ast = esprima.parse('db.find()');
let finished = false;
estraverse.traverse(ast, {
leave: (node, parent) => {
if (node.type === esprima.Syntax.ExpressionStatement && !finished) {
finished = true;
let statement = escodegen.generate(node);
statement = `${statement.substring(0, statement.lastIndexOf(';'))}.toArray()`;
const findAst = esprima.parse(statement);
node.arguments = findAst.body[0].expression.arguments;
node.callee = findAst.body[0].expression.callee;
node.type = findAst.body[0].expression.type;
}
},
});
const generated = escodegen.generate(ast);
console.log('generated code:', generated);
以上代码的输出是:generated code: (db.find().toArray())
。
我不明白为什么它会在我的源代码上加上括号。我的源代码有什么问题吗?
您生成的 AST 不正确。 ExpressionStatement
的形式为 {type: "ExpressionStatement", expression... }
。
您正在修改您的 ExpressionStatement
,将其附加到 arguments
和 callee
,并且您正在更改其 type
(更改为 CallExpression
)。这里:
node.arguments = findAst.body[0].expression.arguments;
node.callee = findAst.body[0].expression.callee;
node.type = findAst.body[0].expression.type;
产生了一个奇怪的 AST。
你可以简单地看到它:console.log('generated ast: %j', ast);
一个快速的解决方案是将提到的部分附加到它们所属的位置(expression
)。结果:
let finished = false;
estraverse.traverse(ast, {
leave: (node, parent) => {
if (node.type === esprima.Syntax.ExpressionStatement && !finished) {
finished = true;
let statement = escodegen.generate(node);
statement = `${statement.substring(0, statement.lastIndexOf(';'))}.toArray()`;
console.log(statement);
const findAst = esprima.parse(statement);
node.expression.arguments = findAst.body[0].expression.arguments;
node.expression.callee = findAst.body[0].expression.callee;
node.expression.type = findAst.body[0].expression.type;
}
},
});
它将生成正确的 AST,输出预期的 db.find().toArray();
。
但是我认为代码有点复杂并且做了太多工作,它解析 db.find()
然后生成代码并再次解析它。
此外,您可以 return this.break()
在 leave
中停止遍历。
以我的愚见,这很清楚:
var new_expr = {
type: "CallExpression",
callee: {
type: "MemberExpression",
computed: false,
object: null,
property: {
type: "Identifier",
name: "toArray"
}
},
arguments: []
};
const ast3 = esprima.parse('db.find()');
estraverse.traverse(ast3, {
leave: function(node, parent) {
if (node.type === esprima.Syntax.ExpressionStatement) {
new_expr.callee.object = node.expression;
node.expression = new_expr;
return this.break();
}
},
});
我希望你觉得这有用。