Search in sources :

Example 1 with BehaviorDefinition

use of com.google.javascript.jscomp.PolymerBehaviorExtractor.BehaviorDefinition in project closure-compiler by google.

the class PolymerClassRewriter method parseReadOnlyProperties.

/**
 * Generates the _set* setters for readonly properties and appends them to the given block.
 *
 * @return A List of all readonly properties.
 */
private ImmutableList<MemberDefinition> parseReadOnlyProperties(final PolymerClassDefinition cls, Node block) {
    String qualifiedPath = cls.target.getQualifiedName() + ".prototype.";
    ImmutableList.Builder<MemberDefinition> readOnlyProps = ImmutableList.builder();
    for (MemberDefinition prop : cls.props) {
        // Generate the setter for readOnly properties.
        if (prop.value.isObjectLit()) {
            Node readOnlyValue = NodeUtil.getFirstPropMatchingKey(prop.value, "readOnly");
            if (readOnlyValue != null && readOnlyValue.isTrue()) {
                Node setter = makeReadOnlySetter(prop, qualifiedPath);
                setter.srcrefTreeIfMissing(prop.name);
                block.addChildToBack(setter);
                readOnlyProps.add(prop);
            }
        }
    }
    if (cls.behaviorProps != null) {
        for (Map.Entry<MemberDefinition, BehaviorDefinition> itr : cls.behaviorProps.entrySet()) {
            // Generate the setter for readOnly properties.
            MemberDefinition prop = itr.getKey();
            if (prop.value.isObjectLit()) {
                Node readOnlyValue = NodeUtil.getFirstPropMatchingKey(prop.value, "readOnly");
                if (readOnlyValue != null && readOnlyValue.isTrue()) {
                    Node setter = makeReadOnlySetter(prop, qualifiedPath);
                    setter.srcrefTreeIfMissing(prop.name);
                    block.addChildToBack(setter);
                    readOnlyProps.add(prop);
                }
            }
        }
    }
    return readOnlyProps.build();
}
Also used : ImmutableList(com.google.common.collect.ImmutableList) Node(com.google.javascript.rhino.Node) MemberDefinition(com.google.javascript.jscomp.PolymerPass.MemberDefinition) HashMap(java.util.HashMap) LinkedHashMap(java.util.LinkedHashMap) Map(java.util.Map) BehaviorDefinition(com.google.javascript.jscomp.PolymerBehaviorExtractor.BehaviorDefinition)

Example 2 with BehaviorDefinition

use of com.google.javascript.jscomp.PolymerBehaviorExtractor.BehaviorDefinition 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 3 with BehaviorDefinition

use of com.google.javascript.jscomp.PolymerBehaviorExtractor.BehaviorDefinition 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 4 with BehaviorDefinition

use of com.google.javascript.jscomp.PolymerBehaviorExtractor.BehaviorDefinition 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, GlobalNamespace globalNames) {
    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;
    }
    Node target;
    if (NodeUtil.isNameDeclaration(callNode.getGrandparent())) {
        target = IR.name(callNode.getParent().getString());
    } else if (callNode.getParent().isAssign()) {
        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);
    }
    JSDocInfo classInfo = NodeUtil.getBestJSDocInfo(target);
    JSDocInfo ctorInfo = null;
    Node constructor = NodeUtil.getFirstPropMatchingKey(descriptor, "factoryImpl");
    if (constructor == null) {
        constructor = NodeUtil.emptyFunction();
        compiler.reportChangeToChangeScope(constructor);
        constructor.useSourceInfoFromForTree(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");
    PolymerBehaviorExtractor behaviorExtractor = new PolymerBehaviorExtractor(compiler, globalNames);
    ImmutableList<BehaviorDefinition> behaviors = behaviorExtractor.extractBehaviors(behaviorArray);
    List<MemberDefinition> allProperties = new ArrayList<>();
    for (BehaviorDefinition behavior : behaviors) {
        overwriteMembersIfPresent(allProperties, behavior.props);
    }
    overwriteMembersIfPresent(allProperties, PolymerPassStaticUtils.extractProperties(descriptor, DefinitionType.ObjectLiteral, compiler));
    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);
        }
    }
    return new PolymerClassDefinition(DefinitionType.ObjectLiteral, callNode, target, descriptor, classInfo, new MemberDefinition(ctorInfo, null, constructor), nativeBaseElement, allProperties, behaviors, newFeatures);
}
Also used : Node(com.google.javascript.rhino.Node) ArrayList(java.util.ArrayList) FeatureSet(com.google.javascript.jscomp.parsing.parser.FeatureSet) JSDocInfo(com.google.javascript.rhino.JSDocInfo) BehaviorDefinition(com.google.javascript.jscomp.PolymerBehaviorExtractor.BehaviorDefinition) MemberDefinition(com.google.javascript.jscomp.PolymerPass.MemberDefinition) Nullable(javax.annotation.Nullable)

Example 5 with BehaviorDefinition

use of com.google.javascript.jscomp.PolymerBehaviorExtractor.BehaviorDefinition in project closure-compiler by google.

the class PolymerClassRewriter method appendBehaviorMembersToBlock.

/**
 * Appends all required behavior functions and non-property members to the given block.
 */
private void appendBehaviorMembersToBlock(final PolymerClassDefinition cls, Node block) {
    String qualifiedPath = cls.target.getQualifiedName() + ".prototype.";
    Map<String, Node> nameToExprResult = new HashMap<>();
    for (BehaviorDefinition behavior : cls.behaviors) {
        for (MemberDefinition behaviorFunction : behavior.functionsToCopy) {
            String fnName = behaviorFunction.name.getString();
            // Don't copy functions already defined by the element itself.
            if (NodeUtil.getFirstPropMatchingKey(cls.descriptor, fnName) != null) {
                continue;
            }
            // Avoid copying over the same function twice. The last definition always wins.
            if (nameToExprResult.containsKey(fnName)) {
                nameToExprResult.get(fnName).detach();
            }
            Node fnValue = behaviorFunction.value.cloneTree();
            NodeUtil.markNewScopesChanged(fnValue, compiler);
            Node exprResult = IR.exprResult(IR.assign(NodeUtil.newQName(compiler, qualifiedPath + fnName), fnValue));
            exprResult.srcrefTreeIfMissing(behaviorFunction.name);
            JSDocInfo.Builder info = getJSDocInfoBuilderForBehavior(behavior, behaviorFunction);
            // Uses of private members that come from behaviors are not recognized correctly,
            // so just suppress that warning.
            info.recordSuppression("unusedPrivateMembers");
            // making the type system understand that methods are "inherited" from behaviors.
            if (behaviorFunction.info != null && behaviorFunction.info.getVisibility() == Visibility.PROTECTED) {
                info.overwriteVisibility(Visibility.PUBLIC);
            }
            // symbols which do not exist in the element's scope. Only copy a function stub.
            if (!behavior.isGlobalDeclaration) {
                Node body = NodeUtil.getFunctionBody(fnValue);
                if (fnValue.isArrowFunction() && !NodeUtil.getFunctionBody(fnValue).isBlock()) {
                    // replace `() => <someExpr>` with `() => undefined`
                    body.replaceWith(NodeUtil.newUndefinedNode(body));
                } else {
                    body.removeChildren();
                }
                // Remove any non-named parameters, which may reference locals.
                int paramIndex = 0;
                for (Node param = NodeUtil.getFunctionParameters(fnValue).getFirstChild(); param != null; ) {
                    final Node next = param.getNext();
                    makeParamSafe(param, paramIndex++);
                    param = next;
                }
            }
            exprResult.getFirstChild().setJSDocInfo(info.build());
            block.addChildToBack(exprResult);
            nameToExprResult.put(fnName, exprResult);
        }
        // Copy other members.
        for (MemberDefinition behaviorProp : behavior.nonPropertyMembersToCopy) {
            String propName = behaviorProp.name.getString();
            if (nameToExprResult.containsKey(propName)) {
                nameToExprResult.get(propName).detach();
            }
            Node exprResult = IR.exprResult(NodeUtil.newQName(compiler, qualifiedPath + propName));
            exprResult.srcrefTree(behaviorProp.name);
            JSDocInfo.Builder info = getJSDocInfoBuilderForBehavior(behavior, behaviorProp);
            if (behaviorProp.name.isGetterDef()) {
                info = JSDocInfo.builder().parseDocumentation();
                if (behaviorProp.info != null && behaviorProp.info.getReturnType() != null) {
                    info.recordType(behaviorProp.info.getReturnType());
                }
            }
            exprResult.getFirstChild().setJSDocInfo(info.build());
            block.addChildToBack(exprResult);
            nameToExprResult.put(propName, exprResult);
        }
    }
}
Also used : HashMap(java.util.HashMap) LinkedHashMap(java.util.LinkedHashMap) Node(com.google.javascript.rhino.Node) JSDocInfo(com.google.javascript.rhino.JSDocInfo) BehaviorDefinition(com.google.javascript.jscomp.PolymerBehaviorExtractor.BehaviorDefinition) MemberDefinition(com.google.javascript.jscomp.PolymerPass.MemberDefinition)

Aggregations

BehaviorDefinition (com.google.javascript.jscomp.PolymerBehaviorExtractor.BehaviorDefinition)7 MemberDefinition (com.google.javascript.jscomp.PolymerPass.MemberDefinition)7 Node (com.google.javascript.rhino.Node)7 JSDocInfo (com.google.javascript.rhino.JSDocInfo)6 LinkedHashMap (java.util.LinkedHashMap)6 ArrayList (java.util.ArrayList)4 ImmutableList (com.google.common.collect.ImmutableList)3 FeatureSet (com.google.javascript.jscomp.parsing.parser.FeatureSet)3 HashMap (java.util.HashMap)3 Map (java.util.Map)3 Nullable (javax.annotation.Nullable)3 JSTypeExpression (com.google.javascript.rhino.JSTypeExpression)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 IR (com.google.javascript.rhino.IR)1 HashSet (java.util.HashSet)1