All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.google.javascript.jscomp.ijs.ClassUtil Maven / Gradle / Ivy

/*
 * Copyright 2017 The Closure Compiler Authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.google.javascript.jscomp.ijs;

import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
import static com.google.common.base.Strings.isNullOrEmpty;

import com.google.javascript.jscomp.NodeUtil;
import com.google.javascript.rhino.JSDocInfo;
import com.google.javascript.rhino.Node;
import javax.annotation.Nullable;

/**
 * Static utility methods for dealing with classes.  The primary benefit is for papering over
 * the differences between ES6 class and goog.defineClass syntax.
 */
final class ClassUtil {
  private ClassUtil() {}

  static boolean isThisProp(Node getprop) {
    return getClassNameOfThisProp(getprop) != null;
  }

  static String getPrototypeNameOfThisProp(Node getprop) {
    String className = checkNotNull(getClassNameOfThisProp(getprop));
    return className + ".prototype." + getprop.getLastChild().getString();
  }

  @Nullable
  private static String getClassNameOfThisProp(Node getprop) {
    if (!getprop.isGetProp() || !getprop.getFirstChild().isThis()) {
      return null;
    }
    Node function = NodeUtil.getEnclosingFunction(getprop);
    if (function == null) {
      return null;
    }
    String className = getClassName(function);
    if (isNullOrEmpty(className)) {
      return null;
    }
    return className;
  }

  static String getFullyQualifiedNameOfMethod(Node function) {
    checkArgument(isClassMethod(function));
    String className = getClassName(function);
    checkState(className != null && !className.isEmpty());
    Node memberFunctionDef = function.getParent();
    String methodName = memberFunctionDef.getString();
    return memberFunctionDef.isStaticMember()
        ? className + "." + methodName
        : className + ".prototype." + methodName;
  }

  static boolean isClassMethod(Node functionNode) {
    checkArgument(functionNode.isFunction());
    Node parent = functionNode.getParent();
    if (parent.isMemberFunctionDef()
        && parent.getParent().isClassMembers()) {
      // ES6 class
      return true;
    }
    // goog.defineClass
    return parent.isStringKey()
        && parent.getParent().isObjectLit()
        && parent.getGrandparent().isCall()
        && parent.getGrandparent().getFirstChild().matchesQualifiedName("goog.defineClass");
  }

  /**
   * Checks whether the given constructor/member function belongs to a named class, as
   * opposed to an anonymous class.
   */
  static boolean hasNamedClass(Node functionNode) {
    checkArgument(functionNode.isFunction());
    return getClassName(functionNode) != null;
  }

  private static String getClassName(Node functionNode) {
    checkArgument(functionNode.isFunction());
    if (isClassMethod(functionNode)) {
      Node parent = functionNode.getParent();
      if (parent.isMemberFunctionDef()) {
        // ES6 class
        Node classNode = functionNode.getGrandparent().getParent();
        checkState(classNode.isClass());
        return NodeUtil.getName(classNode);
      }
      // goog.defineClass
      checkState(parent.isStringKey());
      Node defineClassCall = parent.getGrandparent();
      checkState(defineClassCall.isCall());
      return NodeUtil.getBestLValue(defineClassCall).getQualifiedName();
    }
    return NodeUtil.getName(functionNode);
  }

  static boolean isConstructor(Node functionNode) {
    if (isClassMethod(functionNode)) {
      return NodeUtil.isEs6Constructor(functionNode)
          ||
          // TODO(b/124020008): Delete this case when `goog.defineClass` is dropped.
          "constructor".equals(functionNode.getParent().getString());
    }
    JSDocInfo jsdoc = NodeUtil.getBestJSDocInfo(functionNode);
    return jsdoc != null && jsdoc.isConstructor();
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy