I am using escodegen
to add an ending code on my statement as below. In the leave method, I append a .toArray()
call on the end of the statement.
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);
The output from above code is: generated code: (db.find().toArray())
.
I don't understand why it wraps a parenthesis on my source code. Is there anything wrong in my source code?
You are generating an incorrect AST. An
ExpressionStatement
has the form{type: "ExpressionStatement", expression... }
.You are modifying your
ExpressionStatement
, attaching to itarguments
andcallee
and you are changing itstype
(toCallExpression
). Here:Resulting a weird AST.
You can see it simply with :
console.log('generated ast: %j', ast);
A quick solution is attach mentioned parts where them belong (to
expression
). Resulting:It will generate a correct AST, that will output the expected
db.find().toArray();
. But I think the code is a bit complicated and does too much work, it parsesdb.find()
then it generates code and parses it again.Additionally you can return
this.break()
inleave
to stop the traverse.In my humble opinion it would be much clear:
I hope you find this useful.