Ошибка генерации кода с помощью escodegen после удаления узла
Сначала я создал esprima
AST, то я хочу удалить узел, используя estraverse
и, наконец, восстановить код с escodegen
, Но я получаю ошибку.
Код, который я пытаюсь это:
var esprima = require('esprima');
var estraverse = require('estraverse');
var escodegen = require('escodegen');
(function () {
//build an ast with 2 lines of code
var ast = esprima.parse("console.log('1');\n console.log('2');")
console.log("original code:\n" + escodegen.generate(ast));
console.log();
//change one of the lines, works
ast = estraverse.replace(ast, {
enter: function (node) {
},
leave: function (node) {
if (node.type === esprima.Syntax.CallExpression) {
this.break();
return esprima.parse("console.log('patch');").body[0].expression;
}
}
});
console.log("patched code:\n" + escodegen.generate(ast));
console.log();
//remove one of the lines, error
ast = estraverse.replace(ast, {
enter: function (node) {
},
leave: function (node) {
if (node.type === esprima.Syntax.CallExpression) {
this.break();
return this.remove();
}
}
});
console.log("removed node:\n" + escodegen.generate(ast));
})()
Трассировка ошибки:
C:\temp\node_modules\escodegen\escodegen.js:2450
type = expr.type || Syntax.Property;
^
TypeError: Cannot read property 'type' of null
at CodeGenerator.generateExpression (C:\temp\node_modules\escodegen\escodegen.js:2450:20)
at CodeGenerator.ExpressionStatement (C:\temp\node_modules\escodegen\escodegen.js:1335:28)
at CodeGenerator.generateStatement (C:\temp\node_modules\escodegen\escodegen.js:2469:33)
at CodeGenerator.Program (C:\temp\node_modules\escodegen\escodegen.js:1717:43)
at CodeGenerator.generateStatement (C:\temp\node_modules\escodegen\escodegen.js:2469:33)
at generateInternal (C:\temp\node_modules\escodegen\escodegen.js:2490:28)
at Object.generate (C:\temp\node_modules\escodegen\escodegen.js:2558:18)
at C:\temp\bug1.js:35:45
at Object.<anonymous> (C:\temp\bug1.js:38:3)
at Module._compile (module.js:570:32)
Я делаю что-то неправильно? Это ошибка в escodegen
или может быть в estraverse
?
Заранее спасибо.
2 ответа
Я поставил вопрос на GitHub, и я получил ответ, я делаю недействительным AST.
Удаление CallExpression оставляло его родительский ExpressionStatement пустым и поэтому недействительным. Решением является просто удаление ExpressionStatement.
Этот код работает как ожидалось:
var esprima = require('esprima');
var estraverse = require('estraverse');
var escodegen = require('escodegen');
(function () {
//build an ast with 2 lines of code
var ast = esprima.parse("console.log('1');\n console.log('2');")
console.log("original code:\n" + escodegen.generate(ast));
console.log();
//remove one of the lines, works!
var done = false;
ast = estraverse.replace(ast, {
enter: function (node) {
if (done)
return this.break();
if (node.type === esprima.Syntax.ExpressionStatement) {
done = true;
this.remove();
}
},
leave: function (node) {
if (done)
return this.break();
}
});
console.log("removed node:\n" + escodegen.generate(ast));
})()
Выход:
original code:
console.log('1');
console.log('2');
removed node:
console.log('2');
Похоже, что одной из причин этого может быть удаление кода, оставляющего пустое тело стрелочной функции. Например, исходный код:
() => console.log(1);
В результате чего:
() =>
С одним решением:
() => { console.log(1); }
Возможно, в этом случае родитель тоже должен быть удален, просто может быть немного сложно, если на практике это было что-то вроде
useEffect(() => console.log(1))