Search in sources :

Example 1 with FeatureSet

use of com.google.javascript.jscomp.parsing.parser.FeatureSet in project closure-compiler by google.

the class SyncCompilerFeatures method process.

@Override
public void process(Node externs, Node root) {
    FeatureSet featureSet = FeatureSet.BARE_MINIMUM;
    for (Node rootNode : ImmutableList.of(externs, root)) {
        for (Node childNode = rootNode.getFirstChild(); childNode != null; childNode = childNode.getNext()) {
            checkState(childNode.isScript());
            FeatureSet featuresInScript = NodeUtil.getFeatureSetOfScript(childNode);
            if (featuresInScript != null) {
                featureSet = featureSet.with(featuresInScript);
            }
        }
    }
    compiler.setFeatureSet(featureSet);
}
Also used : Node(com.google.javascript.rhino.Node) FeatureSet(com.google.javascript.jscomp.parsing.parser.FeatureSet)

Example 2 with FeatureSet

use of com.google.javascript.jscomp.parsing.parser.FeatureSet in project closure-compiler by google.

the class RewritePolyfills method getPolyfillSupportedFeatureSet.

/**
 * If the given `Node` is a polyfill definition, return the `FeatureSet` which should be
 * considered to already include that polyfill (making it unnecessary).
 *
 * <p>Otherwise, return `null`.
 */
@Nullable
private FeatureSet getPolyfillSupportedFeatureSet(Node maybePolyfill) {
    FeatureSet polyfillSupportFeatureSet = null;
    if (NodeUtil.isExprCall(maybePolyfill)) {
        Node call = maybePolyfill.getFirstChild();
        Node name = call.getFirstChild();
        if (name.matchesQualifiedName("$jscomp.polyfill")) {
            final String nativeVersionStr = name.getNext().getNext().getNext().getString();
            polyfillSupportFeatureSet = FeatureSet.valueOf(nativeVersionStr);
            // Safari has been really slow to implement these regex features, even though it has
            // kept on top of the features we polyfill, so we want to ignore the regex features
            // when deciding whether the polyfill should be considered "already supported" in the
            // target environment.
            // NOTE: This special case seems reasonable for now, but if further divergence occurs
            // we should consider doing a more direct solution by having the polyfill definitions
            // report names of `FeatureSet` values representing browser `FeatureSet` year instead of
            // spec release year.
            polyfillSupportFeatureSet = polyfillSupportFeatureSet.without(Feature.REGEXP_FLAG_S, Feature.REGEXP_LOOKBEHIND, Feature.REGEXP_NAMED_GROUPS, Feature.REGEXP_UNICODE_PROPERTY_ESCAPE);
        }
    }
    return polyfillSupportFeatureSet;
}
Also used : Node(com.google.javascript.rhino.Node) FeatureSet(com.google.javascript.jscomp.parsing.parser.FeatureSet) Nullable(javax.annotation.Nullable)

Example 3 with FeatureSet

use of com.google.javascript.jscomp.parsing.parser.FeatureSet in project closure-compiler by google.

the class AstValidatorTest method testFeatureValidation.

/**
 * Tests that AstValidator checks for the given feature in the AST
 *
 * <p>This will raise an error if a) the AST parsed from {@code code} lacks {@code feature}, or b)
 * AstValidator does not validate {@code feature}'s presence in the AST.
 */
private void testFeatureValidation(String code, Feature feature) {
    valid(code);
    Node script = getLastCompiler().getJsRoot().getFirstChild();
    // Remove `feature` from the SCRIPT node's feature set, checking that it was originally present,
    // and then validate that AstValidator errors because it expects `feature` to be present.
    FeatureSet currentFeatures = NodeUtil.getFeatureSetOfScript(script);
    assertThat(currentFeatures.contains(feature)).isTrue();
    script.putProp(Node.FEATURE_SET, currentFeatures.without(feature));
    expectInvalid(script, Check.SCRIPT);
}
Also used : Node(com.google.javascript.rhino.Node) FeatureSet(com.google.javascript.jscomp.parsing.parser.FeatureSet)

Example 4 with FeatureSet

use of com.google.javascript.jscomp.parsing.parser.FeatureSet in project closure-compiler by google.

the class PolymerClassRewriter method rewritePolymerCall.

/**
 * Rewrites a given call to Polymer({}) to a set of declarations and assignments which can be
 * understood by the compiler.
 *
 * @param cls The extracted {@link PolymerClassDefinition} for the Polymer element created by this
 *     call.
 * @param traversal Nodetraversal used here to identify the scope in which Polymer exists
 */
void rewritePolymerCall(final PolymerClassDefinition cls, NodeTraversal traversal) {
    Node callParent = cls.definition.getParent();
    // Determine whether we are in a Polymer({}) call at the top level versus in an assignment.
    Node exprRoot = callParent.isExprResult() ? callParent : callParent.getParent();
    checkState(NodeUtil.isStatementParent(exprRoot.getParent()), exprRoot.getParent());
    Node objLit = checkNotNull(cls.descriptor);
    // Add {@code @lends} to the object literal.
    JSDocInfo.Builder objLitDoc = JSDocInfo.builder().parseDocumentation();
    JSTypeExpression jsTypeExpression = new JSTypeExpression(IR.string(cls.target.getQualifiedName() + ".prototype").srcref(exprRoot), exprRoot.getSourceFileName());
    objLitDoc.recordLends(jsTypeExpression);
    objLit.setJSDocInfo(objLitDoc.build());
    addTypesToFunctions(objLit, cls.target.getQualifiedName(), cls.defType);
    PolymerPassStaticUtils.switchDollarSignPropsToBrackets(objLit, compiler);
    PolymerPassStaticUtils.quoteListenerAndHostAttributeKeys(objLit, compiler);
    for (MemberDefinition prop : cls.props) {
        if (prop.value.isObjectLit()) {
            PolymerPassStaticUtils.switchDollarSignPropsToBrackets(prop.value, compiler);
        }
    }
    // The propsAndBehaviorBlock holds code generated for the  Polymer's properties and behaviors
    Node propsAndBehaviorBlock = IR.block();
    JSDocInfo.Builder constructorDoc = this.getConstructorDoc(cls);
    // Remove the original constructor JS docs from the objlit.
    Node ctorKey = cls.constructor.value.getParent();
    if (ctorKey != null) {
        ctorKey.setJSDocInfo(null);
    }
    // Check for a conflicting definition of PolymerElement
    if (!traversal.inGlobalScope()) {
        Var polymerElement = traversal.getScope().getVar("PolymerElement");
        if (polymerElement != null && !polymerElement.getScope().isGlobal()) {
            Node nameNode = polymerElement.getNameNode();
            compiler.report(JSError.make(cls.constructor.value, POLYMER_ELEMENT_CONFLICT, nameNode.getSourceFileName(), Integer.toString(nameNode.getLineno()), Integer.toString(nameNode.getCharno())));
        }
    }
    Node declarationCode = generateDeclarationCode(exprRoot, cls, constructorDoc, traversal);
    String basePath = cls.target.getQualifiedName() + ".prototype.";
    appendBehaviorPropertiesToBlock(cls, propsAndBehaviorBlock, basePath, /*isExternsBlock*/
    false);
    appendPropertiesToBlock(cls.props, propsAndBehaviorBlock, basePath, /* isExternsBlock= */
    false);
    appendBehaviorMembersToBlock(cls, propsAndBehaviorBlock);
    ImmutableList<MemberDefinition> readOnlyPropsAll = parseReadOnlyProperties(cls, propsAndBehaviorBlock);
    ImmutableList<MemberDefinition> attributeReflectedPropsAll = parseAttributeReflectedProperties(cls);
    createExportsAndExterns(cls, readOnlyPropsAll, attributeReflectedPropsAll);
    removePropertyDocs(objLit, cls.defType);
    Node propsAndBehaviorCode = propsAndBehaviorBlock.removeChildren();
    Node parent = exprRoot.getParent();
    // exported.
    if (!traversal.inGlobalScope() && cls.hasGeneratedLhs && !cls.target.isGetProp()) {
        Node enclosingNode = NodeUtil.getEnclosingNode(parent, node -> node.isScript() || node.isModuleBody() || isIIFE(node) || isFunctionArgInGoogLoadModule(node));
        // For module, IIFE and goog.LoadModule enclosed Polymer calls, the declaration code and the
        // code generated from properties and behavior have to be hoisted in different places within
        // the AST. We want to insert the generated declarations to global scope, and insert the
        // propsAndbehaviorCode in the same scope. Hence, dealing with them separately.
        insertGeneratedDeclarationCodeToGlobalScope(enclosingNode, declarationCode);
        if (propsAndBehaviorCode != null) {
            insertGeneratedPropsAndBehaviorCode(enclosingNode, propsAndBehaviorCode);
        }
    } else {
        Node beforeRoot = exprRoot.getPrevious();
        if (beforeRoot == null) {
            if (propsAndBehaviorCode != null) {
                parent.addChildrenToFront(propsAndBehaviorCode);
            }
            parent.addChildToFront(declarationCode);
        } else {
            if (propsAndBehaviorCode != null) {
                parent.addChildrenAfter(propsAndBehaviorCode, beforeRoot);
            }
            declarationCode.insertAfter(beforeRoot);
        }
        compiler.reportChangeToEnclosingScope(parent);
    }
    if (propsAndBehaviorCode != null) {
        compiler.reportChangeToEnclosingScope(propsAndBehaviorCode);
    }
    // we might need to update the FeatureSet.
    if (cls.features != null) {
        Node scriptNode = NodeUtil.getEnclosingScript(parent);
        FeatureSet oldFeatures = (FeatureSet) scriptNode.getProp(Node.FEATURE_SET);
        FeatureSet newFeatures = oldFeatures.union(cls.features);
        if (!newFeatures.equals(oldFeatures)) {
            scriptNode.putProp(Node.FEATURE_SET, newFeatures);
            compiler.reportChangeToChangeScope(scriptNode);
        }
    }
    if (NodeUtil.isNameDeclaration(exprRoot)) {
        Node assignExpr = varToAssign(exprRoot);
        exprRoot.replaceWith(assignExpr);
        compiler.reportChangeToEnclosingScope(assignExpr);
    }
    // with the class members.
    if (polymerVersion > 1 && propertyRenamingEnabled && cls.descriptor != null) {
        Node props = NodeUtil.getFirstPropMatchingKey(cls.descriptor, "properties");
        if (props != null && props.isObjectLit()) {
            addPropertiesConfigObjectReflection(cls, props);
        }
    }
}
Also used : Node(com.google.javascript.rhino.Node) JSTypeExpression(com.google.javascript.rhino.JSTypeExpression) FeatureSet(com.google.javascript.jscomp.parsing.parser.FeatureSet) JSDocInfo(com.google.javascript.rhino.JSDocInfo) MemberDefinition(com.google.javascript.jscomp.PolymerPass.MemberDefinition)

Example 5 with FeatureSet

use of com.google.javascript.jscomp.parsing.parser.FeatureSet 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)

Aggregations

FeatureSet (com.google.javascript.jscomp.parsing.parser.FeatureSet)17 Node (com.google.javascript.rhino.Node)14 MemberDefinition (com.google.javascript.jscomp.PolymerPass.MemberDefinition)4 JSDocInfo (com.google.javascript.rhino.JSDocInfo)4 Nullable (javax.annotation.Nullable)3 ImmutableList (com.google.common.collect.ImmutableList)2 BehaviorDefinition (com.google.javascript.jscomp.PolymerBehaviorExtractor.BehaviorDefinition)2 ArrayList (java.util.ArrayList)2 Name (com.google.javascript.jscomp.GlobalNamespace.Name)1 Ref (com.google.javascript.jscomp.GlobalNamespace.Ref)1 Polyfill (com.google.javascript.jscomp.PolyfillUsageFinder.Polyfill)1 Parser (com.google.javascript.jscomp.parsing.parser.Parser)1 SourceFile (com.google.javascript.jscomp.parsing.parser.SourceFile)1 Comment (com.google.javascript.jscomp.parsing.parser.trees.Comment)1 ProgramTree (com.google.javascript.jscomp.parsing.parser.trees.ProgramTree)1 JSDocInfoBuilder (com.google.javascript.rhino.JSDocInfoBuilder)1 JSTypeExpression (com.google.javascript.rhino.JSTypeExpression)1 StaticSourceFile (com.google.javascript.rhino.StaticSourceFile)1 LinkedHashMap (java.util.LinkedHashMap)1 TreeMap (java.util.TreeMap)1