use of com.google.javascript.jscomp.PolymerPass.MemberDefinition in project closure-compiler by google.
the class PolymerClassRewriter method appendPropertiesToBlock.
/**
* Appends all properties in the ClassDefinition to the prototype of the custom element.
*/
private void appendPropertiesToBlock(final PolymerClassDefinition cls, Node block, String basePath) {
for (MemberDefinition prop : cls.props) {
Node propertyNode = IR.exprResult(NodeUtil.newQName(compiler, basePath + prop.name.getString()));
// If a property string is quoted, make sure the added prototype properties are also quoted
if (prop.name.isQuotedString()) {
continue;
}
propertyNode.useSourceInfoIfMissingFromForTree(prop.name);
JSDocInfoBuilder info = JSDocInfoBuilder.maybeCopyFrom(prop.info);
JSTypeExpression propType = PolymerPassStaticUtils.getTypeFromProperty(prop, compiler);
if (propType == null) {
return;
}
info.recordType(propType);
propertyNode.getFirstChild().setJSDocInfo(info.build());
block.addChildToBack(propertyNode);
}
}
use of com.google.javascript.jscomp.PolymerPass.MemberDefinition in project closure-compiler by google.
the class PolymerClassRewriter method addTypesToFunctions.
/**
* Adds an @this annotation to all functions in the objLit.
*/
private void addTypesToFunctions(Node objLit, String thisType, PolymerClassDefinition.DefinitionType defType) {
checkState(objLit.isObjectLit());
for (Node keyNode = objLit.getFirstChild(); keyNode != null; keyNode = keyNode.getNext()) {
Node value = keyNode.getLastChild();
if (value != null && value.isFunction()) {
JSDocInfo.Builder fnDoc = JSDocInfo.Builder.maybeCopyFrom(keyNode.getJSDocInfo());
fnDoc.recordThisType(new JSTypeExpression(new Node(Token.BANG, IR.string(thisType)).srcrefTree(keyNode), VIRTUAL_FILE));
keyNode.setJSDocInfo(fnDoc.build());
}
}
// Add @this and @return to default property values.
for (MemberDefinition property : PolymerPassStaticUtils.extractProperties(objLit, defType, compiler, /**
* constructor=
*/
null)) {
if (!property.value.isObjectLit()) {
continue;
}
Node defaultValue = NodeUtil.getFirstPropMatchingKey(property.value, "value");
if (defaultValue == null || !defaultValue.isFunction()) {
continue;
}
Node defaultValueKey = defaultValue.getParent();
JSDocInfo.Builder fnDoc = JSDocInfo.Builder.maybeCopyFrom(defaultValueKey.getJSDocInfo());
fnDoc.recordThisType(new JSTypeExpression(new Node(Token.BANG, IR.string(thisType)).srcrefTree(defaultValueKey), VIRTUAL_FILE));
fnDoc.recordReturnType(PolymerPassStaticUtils.getTypeFromProperty(property, compiler));
defaultValueKey.setJSDocInfo(fnDoc.build());
}
}
use of com.google.javascript.jscomp.PolymerPass.MemberDefinition in project closure-compiler by google.
the class PolymerClassRewriter method convertSimpleObserverStringsToReferences.
/**
* Converts property observer strings to direct function references.
*
* <p>From: <code>observer: '_observerName'</code> To: <code>
* observer: ClassName.prototype._observerName</code>
*/
private void convertSimpleObserverStringsToReferences(final PolymerClassDefinition cls) {
for (MemberDefinition prop : cls.props) {
if (prop.value.isObjectLit()) {
Node observer = NodeUtil.getFirstPropMatchingKey(prop.value, "observer");
if (observer != null && observer.isStringLit()) {
Node observerDirectReference = IR.getprop(cls.target.cloneTree(), "prototype", observer.getString()).srcref(observer);
observer.replaceWith(observerDirectReference);
compiler.reportChangeToEnclosingScope(observerDirectReference);
}
}
}
}
use of com.google.javascript.jscomp.PolymerPass.MemberDefinition 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.PolymerPass.MemberDefinition 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();
}
Aggregations