Search in sources :

Example 6 with MemberDefinition

use of com.google.javascript.jscomp.PolymerPass.MemberDefinition in project closure-compiler by google.

the class PolymerClassRewriter method appendBehaviorPropertiesToBlock.

/**
 * Iterates through all the behaviors of this polymer call, and appends the properties of each
 * behavior to the given block.
 */
private void appendBehaviorPropertiesToBlock(PolymerClassDefinition cls, Node block, String basePath, boolean isExternsBlock) {
    if (cls.behaviors == null || cls.behaviors.isEmpty() || cls.behaviorProps == null) {
        return;
    }
    for (Map.Entry<MemberDefinition, BehaviorDefinition> itr : cls.behaviorProps.entrySet()) {
        BehaviorDefinition behavior = itr.getValue();
        MemberDefinition prop = itr.getKey();
        Node propertyNode = getPropertyNode(prop, basePath);
        if (propertyNode == null) {
            continue;
        }
        JSTypeExpression propType = PolymerPassStaticUtils.getTypeFromProperty(prop, compiler);
        if (propType == null) {
            continue;
        }
        JSDocInfo info = null;
        if (isExternsBlock) {
            info = replaceJSDocAndAddNewVars(prop, propType, block);
        } else {
            JSDocInfo.Builder infoBuilder = getJSDocInfoBuilderForBehavior(behavior, prop);
            infoBuilder.recordType(propType);
            info = infoBuilder.build();
        }
        propertyNode.getFirstChild().setJSDocInfo(info);
        block.addChildToBack(propertyNode);
    }
}
Also used : Node(com.google.javascript.rhino.Node) JSTypeExpression(com.google.javascript.rhino.JSTypeExpression) JSDocInfo(com.google.javascript.rhino.JSDocInfo) HashMap(java.util.HashMap) LinkedHashMap(java.util.LinkedHashMap) Map(java.util.Map) MemberDefinition(com.google.javascript.jscomp.PolymerPass.MemberDefinition) BehaviorDefinition(com.google.javascript.jscomp.PolymerBehaviorExtractor.BehaviorDefinition)

Example 7 with MemberDefinition

use of com.google.javascript.jscomp.PolymerPass.MemberDefinition in project closure-compiler by google.

the class PolymerClassDefinition method extractFromClassNode.

/**
 * Validates the class definition and if valid, extracts the class definition from the AST. As
 * opposed to the Polymer 1 extraction, this operation is non-destructive.
 */
@Nullable
static PolymerClassDefinition extractFromClassNode(Node classNode, AbstractCompiler compiler, GlobalNamespace globalNames) {
    checkState(classNode != null && classNode.isClass());
    // The supported case is for the config getter to return an object literal descriptor.
    Node propertiesDescriptor = null;
    Node propertiesGetter = NodeUtil.getFirstGetterMatchingKey(NodeUtil.getClassMembers(classNode), "properties");
    if (propertiesGetter != null) {
        if (!propertiesGetter.isStaticMember()) {
            // report bad class definition
            compiler.report(JSError.make(classNode, PolymerPassErrors.POLYMER_CLASS_PROPERTIES_NOT_STATIC));
        } else {
            for (Node child = NodeUtil.getFunctionBody(propertiesGetter.getFirstChild()).getFirstChild(); child != null; child = child.getNext()) {
                if (child.isReturn()) {
                    if (child.hasChildren() && child.getFirstChild().isObjectLit()) {
                        propertiesDescriptor = child.getFirstChild();
                        break;
                    } else {
                        compiler.report(JSError.make(propertiesGetter, PolymerPassErrors.POLYMER_CLASS_PROPERTIES_INVALID));
                    }
                }
            }
        }
    }
    Node target;
    if (NodeUtil.isNameDeclaration(classNode.getGrandparent())) {
        target = IR.name(classNode.getParent().getString());
    } else if (classNode.getParent().isAssign() && classNode.getParent().getFirstChild().isQualifiedName()) {
        target = classNode.getParent().getFirstChild();
    } else if (!classNode.getFirstChild().isEmpty()) {
        target = classNode.getFirstChild();
    } else {
        // issue error - no name found
        compiler.report(JSError.make(classNode, PolymerPassErrors.POLYMER_CLASS_UNNAMED));
        return null;
    }
    JSDocInfo classInfo = NodeUtil.getBestJSDocInfo(classNode);
    JSDocInfo ctorInfo = null;
    Node constructor = NodeUtil.getEs6ClassConstructorMemberFunctionDef(classNode);
    if (constructor != null) {
        ctorInfo = NodeUtil.getBestJSDocInfo(constructor);
    }
    List<MemberDefinition> properties = PolymerPassStaticUtils.extractProperties(propertiesDescriptor, DefinitionType.ES6Class, compiler, constructor);
    List<MemberDefinition> methods = new ArrayList<>();
    for (Node keyNode = NodeUtil.getClassMembers(classNode).getFirstChild(); keyNode != null; keyNode = keyNode.getNext()) {
        if (!keyNode.isMemberFunctionDef()) {
            continue;
        }
        methods.add(new MemberDefinition(NodeUtil.getBestJSDocInfo(keyNode), keyNode, keyNode.getFirstChild()));
    }
    return new PolymerClassDefinition(DefinitionType.ES6Class, classNode, target, /* hasGeneratedLhs= */
    false, propertiesDescriptor, classInfo, new MemberDefinition(ctorInfo, null, constructor), null, properties, null, methods, null, null);
}
Also used : Node(com.google.javascript.rhino.Node) ArrayList(java.util.ArrayList) JSDocInfo(com.google.javascript.rhino.JSDocInfo) MemberDefinition(com.google.javascript.jscomp.PolymerPass.MemberDefinition) Nullable(javax.annotation.Nullable)

Example 8 with MemberDefinition

use of com.google.javascript.jscomp.PolymerPass.MemberDefinition in project closure-compiler by google.

the class PolymerClassDefinition method extractFromCallNode.

/**
 * Validates the class definition and if valid, destructively extracts the class definition from
 * the AST.
 */
@Nullable
static PolymerClassDefinition extractFromCallNode(Node callNode, AbstractCompiler compiler, ModuleMetadata moduleMetadata, PolymerBehaviorExtractor behaviorExtractor) {
    Node descriptor = NodeUtil.getArgumentForCallOrNew(callNode, 0);
    if (descriptor == null || !descriptor.isObjectLit()) {
        // report bad class definition
        compiler.report(JSError.make(callNode, PolymerPassErrors.POLYMER_DESCRIPTOR_NOT_VALID));
        return null;
    }
    int paramCount = callNode.getChildCount() - 1;
    if (paramCount != 1) {
        compiler.report(JSError.make(callNode, PolymerPassErrors.POLYMER_UNEXPECTED_PARAMS));
        return null;
    }
    Node elName = NodeUtil.getFirstPropMatchingKey(descriptor, "is");
    if (elName == null) {
        compiler.report(JSError.make(callNode, PolymerPassErrors.POLYMER_MISSING_IS));
        return null;
    }
    boolean hasGeneratedLhs = false;
    Node target;
    if (NodeUtil.isNameDeclaration(callNode.getGrandparent())) {
        target = IR.name(callNode.getParent().getString());
    } else if (callNode.getParent().isAssign()) {
        if (isGoogModuleExports(callNode.getParent())) {
            // `exports = Polymer({` in a goog.module requires special handling, as adding a
            // duplicate assignment to exports just confuses the compiler. Create a dummy declaration
            // var exportsForPolymer$jscomp0 = Polymer({ // ...
            target = createDummyGoogModuleExportsTarget(compiler, callNode);
        } else {
            target = callNode.getParent().getFirstChild().cloneTree();
        }
    } else {
        String elNameStringBase = elName.isQualifiedName() ? elName.getQualifiedName().replace('.', '$') : elName.getString();
        String elNameString = CaseFormat.LOWER_HYPHEN.to(CaseFormat.UPPER_CAMEL, elNameStringBase);
        elNameString += "Element";
        target = IR.name(elNameString);
        hasGeneratedLhs = true;
    }
    JSDocInfo classInfo = NodeUtil.getBestJSDocInfo(target);
    JSDocInfo ctorInfo = null;
    Node constructor = NodeUtil.getFirstPropMatchingKey(descriptor, "factoryImpl");
    if (constructor == null) {
        constructor = NodeUtil.emptyFunction();
        compiler.reportChangeToChangeScope(constructor);
        constructor.srcrefTree(callNode);
    } else {
        ctorInfo = NodeUtil.getBestJSDocInfo(constructor);
    }
    Node baseClass = NodeUtil.getFirstPropMatchingKey(descriptor, "extends");
    String nativeBaseElement = baseClass == null ? null : baseClass.getString();
    Node behaviorArray = NodeUtil.getFirstPropMatchingKey(descriptor, "behaviors");
    ImmutableList<BehaviorDefinition> behaviors = behaviorExtractor.extractBehaviors(behaviorArray, moduleMetadata);
    List<MemberDefinition> properties = new ArrayList<>();
    Map<MemberDefinition, BehaviorDefinition> behaviorProps = new LinkedHashMap<>();
    for (BehaviorDefinition behavior : behaviors) {
        for (MemberDefinition prop : behavior.props) {
            behaviorProps.put(prop, behavior);
        }
    }
    overwriteMembersIfPresent(properties, PolymerPassStaticUtils.extractProperties(descriptor, DefinitionType.ObjectLiteral, compiler, /**
     * constructor=
     */
    null));
    // Behaviors might get included multiple times for the same element. See test case
    // testDuplicatedBehaviorsAreCopiedOnce
    // In those cases, behaviorProps will have repeated names. We must remove those duplicates.
    removeDuplicateBehaviorProps(behaviorProps);
    // Remove behavior properties which are already present in element properties
    removeBehaviorPropsOverlappingWithElementProps(behaviorProps, properties);
    FeatureSet newFeatures = null;
    if (!behaviors.isEmpty()) {
        newFeatures = behaviors.get(0).features;
        for (int i = 1; i < behaviors.size(); i++) {
            newFeatures = newFeatures.union(behaviors.get(i).features);
        }
    }
    List<MemberDefinition> methods = new ArrayList<>();
    for (Node keyNode = descriptor.getFirstChild(); keyNode != null; keyNode = keyNode.getNext()) {
        boolean isFunctionDefinition = keyNode.isMemberFunctionDef() || (keyNode.isStringKey() && keyNode.getFirstChild().isFunction());
        if (isFunctionDefinition) {
            methods.add(new MemberDefinition(NodeUtil.getBestJSDocInfo(keyNode), keyNode, keyNode.getFirstChild()));
        }
    }
    return new PolymerClassDefinition(DefinitionType.ObjectLiteral, callNode, target, hasGeneratedLhs, descriptor, classInfo, new MemberDefinition(ctorInfo, null, constructor), nativeBaseElement, properties, behaviorProps, methods, behaviors, newFeatures);
}
Also used : Node(com.google.javascript.rhino.Node) ArrayList(java.util.ArrayList) JSDocInfo(com.google.javascript.rhino.JSDocInfo) LinkedHashMap(java.util.LinkedHashMap) FeatureSet(com.google.javascript.jscomp.parsing.parser.FeatureSet) BehaviorDefinition(com.google.javascript.jscomp.PolymerBehaviorExtractor.BehaviorDefinition) MemberDefinition(com.google.javascript.jscomp.PolymerPass.MemberDefinition) Nullable(javax.annotation.Nullable)

Example 9 with MemberDefinition

use of com.google.javascript.jscomp.PolymerPass.MemberDefinition in project closure-compiler by google.

the class PolymerClassDefinition method removeDuplicateBehaviorProps.

/**
 * Removes duplicate properties from the given map, keeping only the first property
 *
 * <p>Duplicates occur when either the same behavior is transitively added multiple times to
 * Polymer element, or when two unique added behaviors share a property with the same name.
 */
private static void removeDuplicateBehaviorProps(Map<MemberDefinition, BehaviorDefinition> behaviorProps) {
    if (behaviorProps == null) {
        return;
    }
    Iterator<Map.Entry<MemberDefinition, BehaviorDefinition>> behaviorsItr = behaviorProps.entrySet().iterator();
    Set<String> seen = new HashSet<>();
    while (behaviorsItr.hasNext()) {
        MemberDefinition memberDefinition = behaviorsItr.next().getKey();
        String propertyName = memberDefinition.name.getString();
        if (!seen.add(propertyName)) {
            behaviorsItr.remove();
        }
    }
}
Also used : MemberDefinition(com.google.javascript.jscomp.PolymerPass.MemberDefinition) HashSet(java.util.HashSet)

Example 10 with MemberDefinition

use of com.google.javascript.jscomp.PolymerPass.MemberDefinition in project closure-compiler by google.

the class PolymerBehaviorExtractor method getBehaviorFunctionsToCopy.

/**
 * @return A list of functions from a behavior which should be copied to the element prototype.
 */
private static ImmutableList<MemberDefinition> getBehaviorFunctionsToCopy(Node behaviorObjLit) {
    checkState(behaviorObjLit.isObjectLit());
    ImmutableList.Builder<MemberDefinition> functionsToCopy = ImmutableList.builder();
    for (Node keyNode = behaviorObjLit.getFirstChild(); keyNode != null; keyNode = keyNode.getNext()) {
        boolean isFunctionDefinition = (keyNode.isStringKey() && keyNode.getFirstChild().isFunction()) || keyNode.isMemberFunctionDef();
        if (isFunctionDefinition && !BEHAVIOR_NAMES_NOT_TO_COPY.contains(keyNode.getString())) {
            functionsToCopy.add(new MemberDefinition(NodeUtil.getBestJSDocInfo(keyNode), keyNode, keyNode.getFirstChild()));
        }
    }
    return functionsToCopy.build();
}
Also used : ImmutableList(com.google.common.collect.ImmutableList) Node(com.google.javascript.rhino.Node) MemberDefinition(com.google.javascript.jscomp.PolymerPass.MemberDefinition)

Aggregations

MemberDefinition (com.google.javascript.jscomp.PolymerPass.MemberDefinition)22 Node (com.google.javascript.rhino.Node)21 JSDocInfo (com.google.javascript.rhino.JSDocInfo)13 JSTypeExpression (com.google.javascript.rhino.JSTypeExpression)9 BehaviorDefinition (com.google.javascript.jscomp.PolymerBehaviorExtractor.BehaviorDefinition)7 ArrayList (java.util.ArrayList)7 ImmutableList (com.google.common.collect.ImmutableList)6 LinkedHashMap (java.util.LinkedHashMap)6 FeatureSet (com.google.javascript.jscomp.parsing.parser.FeatureSet)5 JSDocInfoBuilder (com.google.javascript.rhino.JSDocInfoBuilder)4 HashMap (java.util.HashMap)4 Nullable (javax.annotation.Nullable)4 Map (java.util.Map)3 HashSet (java.util.HashSet)2 List (java.util.List)2 CaseFormat (com.google.common.base.CaseFormat)1 MoreObjects.toStringHelper (com.google.common.base.MoreObjects.toStringHelper)1 Preconditions.checkState (com.google.common.base.Preconditions.checkState)1 Supplier (com.google.common.base.Supplier)1 ModuleMetadata (com.google.javascript.jscomp.modules.ModuleMetadataMap.ModuleMetadata)1