Почему escodegen и esprima генерируют упаковку скобок в моем исходном коде?
Я использую escodegen
добавить конечный код в моем заявлении, как показано ниже. В методе отпуска я добавляю .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())
, Я не понимаю, почему это заключает в скобки мой исходный код. Что-то не так в моем исходном коде?
1 ответ
Вы генерируете неправильный 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;
В результате странный АСТ.
Вы можете увидеть это просто с помощью: 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()
затем он генерирует код и анализирует его снова.
Дополнительно вы можете вернуться 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();
}
},
});
Я надеюсь, что вы найдете это полезным.