private void visitClassNode(NodeTraversal t, Node classNode) { String name = NodeUtil.getName(classNode); if (name != null) { providedNames.add(name); } Node extendClass = classNode.getSecondChild(); // If the superclass is something other than a qualified name, ignore it. if (!extendClass.isQualifiedName()) { return; } // Single names are likely external, but if this is running in single-file mode, they // will not be in the externs, so add a weak usage. if (mode == Mode.SINGLE_FILE && extendClass.isName()) { weakUsages.put(extendClass.getString(), extendClass); return; } Node root = NodeUtil.getRootOfQualifiedName(extendClass); // It should always be a name. Extending this.something or // super.something is unlikely. // We only consider programmer-defined superclasses that are // global variables, or are defined on global variables. if (root.isName()) { String rootName = root.getString(); Var var = t.getScope().getVar(rootName); if (var != null && (var.isLocal() || var.isExtern())) { // "require" not needed for these } else { usages.put(extendClass.getQualifiedName(), extendClass); } } }
@Override public void visit(NodeTraversal t, Node n, Node parent) { JSDocInfo docInfo = n.getJSDocInfo(); if (docInfo != null && docInfo.isExport()) { if (parent.isAssign() && (n.isFunction() || n.isClass())) { JSDocInfo parentInfo = parent.getJSDocInfo(); if (parentInfo != null && parentInfo.isExport()) { // ScopedAliases produces export annotations on both the function/class // node and assign node, we only want to visit the assign node. return; } } String export = null; GenerateNodeContext context = null; switch (n.getType()) { case Token.FUNCTION: case Token.CLASS: if (parent.isScript()) { export = NodeUtil.getName(n); context = new GenerateNodeContext(n, Mode.EXPORT); } break; case Token.MEMBER_FUNCTION_DEF: export = n.getString(); context = new GenerateNodeContext(n, Mode.EXPORT); break; case Token.ASSIGN: Node grandparent = parent.getParent(); if (parent.isExprResult() && !n.getLastChild().isAssign()) { if (grandparent != null && grandparent.isScript() && n.getFirstChild().isQualifiedName()) { export = n.getFirstChild().getQualifiedName(); context = new GenerateNodeContext(n, Mode.EXPORT); } else if (allowLocalExports && n.getFirstChild().isGetProp()) { Node target = n.getFirstChild(); export = target.getLastChild().getString(); context = new GenerateNodeContext(n, Mode.EXTERN); } } break; case Token.VAR: case Token.LET: case Token.CONST: if (parent.isScript()) { if (n.getFirstChild().hasChildren() && !n.getFirstChild().getFirstChild().isAssign()) { export = n.getFirstChild().getString(); context = new GenerateNodeContext(n, Mode.EXPORT); } } break; case Token.GETPROP: if (allowLocalExports && parent.isExprResult()) { export = n.getLastChild().getString(); context = new GenerateNodeContext(n, Mode.EXTERN); } break; case Token.STRING_KEY: case Token.GETTER_DEF: case Token.SETTER_DEF: if (allowLocalExports) { export = n.getString(); context = new GenerateNodeContext(n, Mode.EXTERN); } break; } if (export != null) { exports.put(export, context); } else { // Don't produce extra warnings for functions values of object literals if (!n.isFunction() || !NodeUtil.isObjectLitKey(parent)) { if (allowLocalExports) { compiler.report(t.makeError(n, EXPORT_ANNOTATION_NOT_ALLOWED)); } else { compiler.report(t.makeError(n, NON_GLOBAL_ERROR)); } } } } }