Java Code Examples for com.google.javascript.rhino.Node#detach()

The following examples show how to use com.google.javascript.rhino.Node#detach() . You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example 1
Source File: TypeConversionPass.java    From clutz with MIT License 6 votes vote down vote up
private void stripFunctionDefaultParamsAndBody(Node member) {
  Node functionNode = member.getFirstChild();
  Node functionName = functionNode.getFirstChild();
  Node functionParams = functionNode.getSecondChild();
  // Remove defaults from parameters
  Node functionParamsNoDefaults = new Node(Token.PARAM_LIST);
  for (Node param : functionParams.children()) {
    Node paramNoDefault = param.isDefaultValue() ? param.getFirstChild() : param;
    functionParamsNoDefaults.addChildToBack(paramNoDefault.detach());
  }
  // Strip body from function definitions.
  Node newFunction =
      new Node(
          Token.FUNCTION,
          functionName.detach(),
          functionParamsNoDefaults,
          new Node(Token.EMPTY));
  newFunction.useSourceInfoFrom(functionNode);
  nodeComments.replaceWithComment(functionNode, newFunction);
}
 
Example 2
Source File: ModuleConversionPass.java    From clutz with MIT License 6 votes vote down vote up
/**
 * Takes an assignment statement (export or goog.provide one), removes it and instead finds the
 * matching declaration and adds an 'export' keyword.
 *
 * <p>Before: class C {} exports.C = C;
 *
 * <p>After: export class C {};
 */
private void moveExportStmtToADeclKeyword(Node assignmentNode, Node declarationNode) {
  // Rewrite the AST to export the symbol directly using information from the export
  // assignment.
  Node next = declarationNode.getNext();
  Node parent = declarationNode.getParent();
  declarationNode.detach();

  Node export = new Node(Token.EXPORT, declarationNode);
  export.useSourceInfoFrom(assignmentNode);

  nodeComments.moveComment(declarationNode, export);
  astComments.moveComment(declarationNode, export);
  parent.addChildBefore(export, next);
  compiler.reportChangeToEnclosingScope(parent);
}
 
Example 3
Source File: TypeScriptGenerator.java    From clutz with MIT License 5 votes vote down vote up
/** Removes the root nodes for all the library files from the source node. */
private static void stripNonCompiledNodes(Node n, Set<String> filesToCompile) {
  for (Node child : n.children()) {
    if (!filesToCompile.contains(child.getSourceFileName())) {
      child.detach();
    }
  }
}
 
Example 4
Source File: TypeConversionPass.java    From clutz with MIT License 5 votes vote down vote up
/** Converts goog.defineClass calls into class definitions. */
private void convertDefineClassToClass(Node n) {
  Preconditions.checkState(n.isCall());
  Node superClass = n.getSecondChild();
  if (superClass.isNull()) {
    superClass = IR.empty();
  } else {
    superClass.detach();
  }

  Node classMembers = new Node(Token.CLASS_MEMBERS);
  classMembers.useSourceInfoFrom(n);
  for (Node child : n.getLastChild().children()) {
    if (child.isStringKey() || child.isMemberFunctionDef()) {
      // Handle static methods
      if ("statics".equals(child.getString())) {
        for (Node child2 : child.getFirstChild().children()) {
          convertObjectLiteral(classMembers, child2, true);
        }
      } else { // prototype methods
        convertObjectLiteral(classMembers, child, false);
      }
    } else {
      // Add all other members, such as EMPTY comment nodes, as is.
      child.detach();
      classMembers.addChildToBack(child);
    }
  }
  Node classNode = new Node(Token.CLASS, IR.empty(), superClass, classMembers);
  classNode.useSourceInfoFrom(n);

  nodeComments.replaceWithComment(n, classNode);
}
 
Example 5
Source File: ModuleConversionPass.java    From clutz with MIT License 5 votes vote down vote up
/**
 * Converts a destructuring Closure goog.require call into a TypeScript import statement.
 *
 * <p>The resulting node is dependent on the exports by the module being imported:
 *
 * <pre>
 *   import {A as localName, B} from "./valueExports";
 * </pre>
 */
private void convertDestructuringRequireToImportStatements(Node n, ModuleImport moduleImport) {
  // The imported file is already in TS
  if (moduleImport.isAlreadyConverted()) {
    convertRequireForAlreadyConverted(moduleImport);
    return;
  }

  // The imported file is kept in JS
  if (moduleImport.module.shouldUseOldSyntax()) {
    convertRequireToImportsIfImportedIsKeptInJs(moduleImport);
    return;
  }
  // For the rest of the function, the imported and importing files are migrating together

  // import {localName} from "./file"
  Node importSpecs = createNamedImports(moduleImport);
  Node importNode =
      new Node(
          Token.IMPORT, IR.empty(), importSpecs, Node.newString(moduleImport.referencedFile));
  addImportNode(n, importNode);

  for (int i = 0; i < moduleImport.fullLocalNames.size(); i++) {
    registerLocalSymbol(
        n.getSourceFileName(),
        moduleImport.fullLocalNames.get(i),
        moduleImport.requiredNamespace,
        moduleImport.localNames.get(i));
  }

  compiler.reportChangeToEnclosingScope(n);
  n.detach();
}
 
Example 6
Source File: StyleFixPass.java    From clutz with MIT License 5 votes vote down vote up
/**
 * Attempts to lift class or functions declarations of the form 'var/let/const x = class/function
 * {...}' into 'class/function x {...}'
 */
private void liftClassOrFunctionDefinition(Node n) {
  Node rhs = n.getFirstFirstChild();
  Node oldName = rhs.getFirstChild();
  Node newName = n.getFirstChild();

  // Replace name node with declared name
  rhs.detach();
  newName.detach();
  nodeComments.replaceWithComment(oldName, newName);
  nodeComments.replaceWithComment(n, rhs);
}
 
Example 7
Source File: RemoveGoogScopePass.java    From clutz with MIT License 5 votes vote down vote up
private void rewriteGoogScope(Node n) {
  // Extract the goog.scope contents, and add them to module being constructed.
  Node blockOfScopeContents = n.getLastChild().getLastChild().getLastChild();
  blockOfScopeContents.detach();

  // Rewrite the AST, moving each node in the contents of the scope after the node.

  // Create a marker so that we know where to insert the goog.scope contents.
  Node insertAfterThisNode = n;

  @Nullable Node nodeToMove = blockOfScopeContents.getFirstChild();
  while (nodeToMove != null) {
    RewriteStatus rewriteStatus = maybeRewriteAlias(nodeToMove);
    // (1) nodeToMove is detached, alias to provided namespace is recorded, the next node is
    // returned. The next node should be 'maybeRewriteAlias()' checked before it can be moved out
    // of goog.scope
    if (rewriteStatus != stillAttached) {
      nodeToMove = rewriteStatus.nextNode;
      continue;
    }

    // (2) Alias is re-assigned with the provided namespace. In this case, node is not detached
    // and stillAttached sentinel is returned. nodeToMove needs to be moved out of goog.scope
    // Store the next node in a temp variable since detaching the node breaks the chain.
    Node nextNodeToMove = nodeToMove.getNext();
    nodeToMove.detach();

    n.getParent().addChildAfter(nodeToMove, insertAfterThisNode);

    insertAfterThisNode = nodeToMove;
    nodeToMove = nextNodeToMove;
  }

  compiler.reportChangeToEnclosingScope(n);
  n.detach();
}
 
Example 8
Source File: RemoveGoogScopePass.java    From clutz with MIT License 5 votes vote down vote up
private RewriteStatus maybeRecordAndRemoveAlias(Node assign) {
  Node lhs = assign;
  Node rhs = assign.getLastChild();
  if (rhs == null) { // var foo;
    return stillAttached;
  }
  if (isInProvidedNamespace(rhs)) {
    aliasToProvidedNamespace.put(lhs.getString(), rhs.getQualifiedName());
    Node next = assign.getParent().getNext();
    assign.detach();
    return new RewriteStatus(next);
  }
  return stillAttached;
}
 
Example 9
Source File: TypeConversionPass.java    From clutz with MIT License 4 votes vote down vote up
/**
 * Attempts to remove an inheritance statement. ex. goog.inherits(base, super)
 *
 * <p>This returns without any modification if the node is not an inheritance statement. This
 * fails by reporting an error when the node is an invalid inheritance statement.
 */
private void maybeRemoveInherits(Node exprNode) {
  Preconditions.checkState(exprNode.isExprResult());
  if (exprNode.getFirstChild().isCall()) {
    Node callNode = exprNode.getFirstChild();
    // Remove goog.inherits calls
    if (!callNode.getFirstChild().matchesQualifiedName("goog.inherits")) {
      return;
    }
    String className = callNode.getSecondChild().getQualifiedName();
    String superClassName = callNode.getLastChild().getQualifiedName();

    // Check that class exists
    if (!types.containsKey(className)) {
      compiler.report(
          JSError.make(
              exprNode,
              GentsErrorManager.GENTS_CLASS_PASS_ERROR,
              String.format("Class %s could not be found.", className)));
      return;
    }

    // Check that superclass is consistent
    Node classNode = types.get(className);
    String storedSuperClassName = classNode.getSecondChild().getQualifiedName();
    if (classNode.getSecondChild().isEmpty() || !storedSuperClassName.equals(superClassName)) {
      compiler.report(
          JSError.make(
              exprNode,
              GentsErrorManager.GENTS_CLASS_PASS_ERROR,
              String.format("Invalid superclass for %s", className)));
      return;
    }

    compiler.reportChangeToEnclosingScope(exprNode);
    exprNode.detach();
  } else if (exprNode.getFirstChild().isAssign()) {
    Node assignNode = exprNode.getFirstChild();
    // Report error if trying to assign to prototype directly
    Node lhs = assignNode.getFirstChild();
    if (lhs.isGetProp() && "prototype".equals(lhs.getLastChild().getString())) {
      compiler.report(
          JSError.make(
              exprNode,
              GentsErrorManager.GENTS_CLASS_PASS_ERROR,
              String.format(
                  "Cannot directly assign to prototype for %s",
                  lhs.getFirstChild().getQualifiedName())));
    }
  }
}
 
Example 10
Source File: TypeConversionPass.java    From clutz with MIT License 4 votes vote down vote up
/**
 * Attempts to convert a ES5 superclass call into a ES6 super() call.
 *
 * <p>Examples:
 *
 * <pre>
 * B.call(this, args) -> super(args);
 * B.prototype.foo.call(this, args) ->super.foo(args);
 * A.base(this, 'constructor', args) -> super(args);
 * A.base(this, 'foo', args) -> super.foo(args);
 * </pre>
 *
 * <p>This returns without any modification if the node is not an superclass call statement.
 */
private void maybeReplaceSuperCall(Node callNode) {
  Preconditions.checkState(callNode.isCall());
  String callName = callNode.getFirstChild().getQualifiedName();

  // First validate that we are inside a constructor call that extends another class
  Node classNode = NodeUtil.getEnclosingClass(callNode);
  if (callName == null || classNode == null) {
    return;
  }

  String className = NodeUtil.getName(classNode);

  // Translate super constructor or super method calls as follows:
  // A.base(this, 'constructor', args) -> super(args);
  // A.base(this, 'foo', args) -> super.foo(args);
  if (callName.equals(className + ".base") && callNode.getSecondChild().isThis()) {
    // Super calls for root classes are not converted
    if (classNode.getSecondChild().isEmpty()) {
      compiler.report(
          JSError.make(
              callNode,
              GentsErrorManager.GENTS_CLASS_PASS_ERROR,
              String.format("Cannot call superclass in root class %s", className)));
      return;
    }
    String methodName = callNode.getChildAtIndex(2).getString();

    if ("constructor".equals(methodName)) {
      nodeComments.replaceWithComment(callNode.getFirstChild(), IR.superNode());
    } else {
      nodeComments.replaceWithComment(
          callNode.getFirstChild(), NodeUtil.newQName(compiler, "super." + methodName));
    }

    // Remove twice to get rid of "this" and the method name
    callNode.removeChild(callNode.getSecondChild());
    callNode.removeChild(callNode.getSecondChild());
    compiler.reportChangeToEnclosingScope(callNode);
    return;
  }

  String superClassName = classNode.getSecondChild().getQualifiedName();
  // B.call(this, args) -> super(args);
  if (callName.equals(superClassName + ".call") && callNode.getSecondChild().isThis()) {
    nodeComments.replaceWithComment(callNode.getFirstChild(), IR.superNode());

    callNode.removeChild(callNode.getSecondChild());
    compiler.reportChangeToEnclosingScope(callNode);
    return;
  }

  // B.prototype.foo.call(this, args) -> super.foo(args);
  if (callName.startsWith(superClassName + ".prototype.") && callName.endsWith(".call")) {
    if (callNode.getSecondChild().isThis()) {
      // Determine name of method being called
      Node nameNode = callNode.getFirstFirstChild();
      Node n = nameNode;
      while (!n.getLastChild().getString().equals("prototype")) {
        n = n.getFirstChild();
      }
      nameNode.detach();

      nodeComments.replaceWithComment(n, IR.superNode());
      nodeComments.replaceWithComment(callNode.getFirstChild(), nameNode);
      callNode.removeChild(callNode.getSecondChild());
      compiler.reportChangeToEnclosingScope(callNode);
      return;
    }
  }
}