2017-09-06 9 views
1

escodegen을 사용하여 다음과 같이 내 진술 문에 결말 코드를 추가합니다. leave 메서드에서는 문 끝에 .toArray() 호출을 추가합니다.escodegen 및 esprima가 내 소스 코드에서 괄호 래퍼를 생성하는 이유는 무엇입니까?

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... }입니다.

당신은 그것을 argumentscallee에 부착하여 ExpressionStatement을 수정하고 그 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()을 구문 분석 한 다음 코드를 생성하고 다시 구문 분석합니다.

또한 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();  
     } 
    }, 
}); 

난 당신이 유용 바랍니다.

+0

잘 작동합니다. 당신의 도움을 주셔서 감사합니다. –

+0

또 다른 질문은 :'this.break()'가 전체 프로세스를 멈추게 할 것인가 아니면 현재 명령문만을 멈추게 할 것인가? 프로세스에 필요한 다른 많은 코드가 실행되어야합니다. 거기에'this.break()'문을 써 넣으면 건너 뛰게되는지 궁금합니다. –

+0

아, 나는 그것이 순회를 종료한다고 생각합니다. 같은 순회에서 더 많은 일을하고 싶다면 그것을 사용해서는 안됩니다. – fonkap