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);
}
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;
}
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);
}
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);
}
}
}
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);
}
Aggregations