@Override
  public void visit(NodeTraversal traversal, Node node, Node parent) {
    // SCRIPT node is special - it is the root of the AST for code from a file.
    // Append code to declare and initialize structures used in instrumentation.
    if (node.isScript()) {
      String fileName = getFileName(traversal);
      if (instrumentationData.get(fileName) != null) {
        if (node.hasChildren() && node.getFirstChild().isModuleBody()) {
          node = node.getFirstChild();
        }
        node.addChildrenToFront(newHeaderNode(traversal, node).removeChildren());
      }
      traversal.reportCodeChange();
      return;
    }

    // Don't instrument global statements
    if (reach == CoverageReach.CONDITIONAL
        && parent != null && parent.isScript()) {
      return;
    }

    // For arrow functions whose body is an expression instead of a block,
    // convert it to a block so that it can be instrumented.
    if (node.isFunction() && !NodeUtil.getFunctionBody(node).isBlock()) {
      Node returnValue = NodeUtil.getFunctionBody(node);
      Node body = IR.block(IR.returnNode(returnValue.detach()));
      body.useSourceInfoIfMissingFromForTree(returnValue);
      node.addChildToBack(body);
    }

    // Add instrumentation code just before a function block.
    // Similarly before other constructs: 'with', 'case', 'default', 'catch'
    if (node.isFunction()
        || node.isWith()
        || node.isCase()
        || node.isDefaultCase()
        || node.isCatch()) {
      Node codeBlock = node.getLastChild();
      codeBlock.addChildToFront(
          newInstrumentationNode(traversal, node));
      traversal.reportCodeChange();
      return;
    }

    // Add instrumentation code as the first child of a 'try' block.
    if (node.isTry()) {
      Node firstChild = node.getFirstChild();
      firstChild.addChildToFront(
          newInstrumentationNode(traversal, node));
      traversal.reportCodeChange();
      return;
    }

    // For any other statement, add instrumentation code just before it.
    if (parent != null && NodeUtil.isStatementBlock(parent) && !node.isModuleBody()) {
      parent.addChildBefore(
          newInstrumentationNode(traversal, node),
          node);
      traversal.reportCodeChange();
      return;
    }
  }
@ Override public void visit ( NodeTraversal traversal , Node node , Node parent ) { if ( node . isScript ( ) ) { String fileName = getFileName ( traversal ) ; if ( instrumentationData . get ( fileName ) != null ) { if ( node . hasChildren ( ) && node . getFirstChild ( ) . isModuleBody ( ) ) { node = node . getFirstChild ( ) ; } node . addChildrenToFront ( newHeaderNode ( traversal , node ) . removeChildren ( ) ) ; } traversal . reportCodeChange ( ) ; return ; } if ( reach == CoverageReach . CONDITIONAL && parent != null && parent . isScript ( ) ) { return ; } if ( node . isFunction ( ) && ! NodeUtil . getFunctionBody ( node ) . isBlock ( ) ) { Node returnValue = NodeUtil . getFunctionBody ( node ) ; Node body = IR . block ( IR . returnNode ( returnValue . detach ( ) ) ) ; body . useSourceInfoIfMissingFromForTree ( returnValue ) ; node . addChildToBack ( body ) ; } if ( node . isFunction ( ) || node . isWith ( ) || node . isCase ( ) || node . isDefaultCase ( ) || node . isCatch ( ) ) { Node codeBlock = node . getLastChild ( ) ; codeBlock . addChildToFront ( newInstrumentationNode ( traversal , node ) ) ; traversal . reportCodeChange ( ) ; return ; } if ( node . isTry ( ) ) { Node firstChild = node . getFirstChild ( ) ; firstChild . addChildToFront ( newInstrumentationNode ( traversal , node ) ) ; traversal . reportCodeChange ( ) ; return ; } if ( parent != null && NodeUtil . isStatementBlock ( parent ) && ! node . isModuleBody ( ) ) { parent . addChildBefore ( newInstrumentationNode ( traversal , node ) , node ) ; traversal . reportCodeChange ( ) ; return ; } }
Instruments the JS code by inserting appropriate nodes into the AST. The
instrumentation logic is tuned to collect "line coverage" data only.