private void declareVariablesForObjLitValues ( Name objlitName , String alias , Node objlit , Node varNode , Node nameToAddAfter , Node varParent ) { int arbitraryNameCounter = 0 ; boolean discardKeys = ! objlitName . shouldKeepKeys ( ) ; for ( Node key = objlit . getFirstChild ( ) , nextKey ; key != null ; key = nextKey ) { Node value = key . getFirstChild ( ) ; nextKey = key . getNext ( ) ; // A computed property, or a get or a set can not be rewritten as a VAR. We don't know what // properties will be generated by a spread. switch ( key . getToken ( ) ) { case GETTER_DEF : case SETTER_DEF : case COMPUTED_PROP : case SPREAD : continue ; case STRING_KEY : case MEMBER_FUNCTION_DEF : break ; default : throw new IllegalStateException ( "Unexpected child of OBJECTLIT: " + key . toStringTree ( ) ) ; } // We generate arbitrary names for keys that aren't valid JavaScript // identifiers, since those keys are never referenced. (If they were, // this object literal's child names wouldn't be collapsible.) The only // reason that we don't eliminate them entirely is the off chance that // their values are expressions that have side effects. boolean isJsIdentifier = ! key . isNumber ( ) && TokenStream . isJSIdentifier ( key . getString ( ) ) ; String propName = isJsIdentifier ? key . getString ( ) : String . valueOf ( ++ arbitraryNameCounter ) ; // If the name cannot be collapsed, skip it. String qName = objlitName . getFullName ( ) + ' ' + propName ; Name p = nameMap . get ( qName ) ; if ( p != null && ! canCollapse ( p ) ) { continue ; } String propAlias = appendPropForAlias ( alias , propName ) ; Node refNode = null ; if ( discardKeys ) { objlit . removeChild ( key ) ; value . detach ( ) ; // Don't report a change here because the objlit has already been removed from the tree. } else { // Substitute a reference for the value. refNode = IR . name ( propAlias ) ; if ( key . getBooleanProp ( Node . IS_CONSTANT_NAME ) ) { refNode . putBooleanProp ( Node . IS_CONSTANT_NAME , true ) ; } key . replaceChild ( value , refNode ) ; compiler . reportChangeToEnclosingScope ( refNode ) ; } // Declare the collapsed name as a variable with the original value. Node nameNode = IR . name ( propAlias ) ; nameNode . addChildToFront ( value ) ; if ( key . getBooleanProp ( Node . IS_CONSTANT_NAME ) ) { nameNode . putBooleanProp ( Node . IS_CONSTANT_NAME , true ) ; } Node newVar = IR . var ( nameNode ) . useSourceInfoIfMissingFromForTree ( key ) ; if ( nameToAddAfter != null ) { varParent . addChildAfter ( newVar , nameToAddAfter ) ; } else { varParent . addChildBefore ( newVar , varNode ) ; } compiler . reportChangeToEnclosingScope ( newVar ) ; nameToAddAfter = newVar ; // Update the global name's node ancestry if it hasn't already been // done. (Duplicate keys in an object literal can bring us here twice // for the same global name.) if ( isJsIdentifier && p != null ) { if ( ! discardKeys ) { p . addAliasingGetClonedFromDeclaration ( refNode ) ; } p . updateRefNode ( p . getDeclaration ( ) , nameNode ) ; if ( value . isFunction ( ) ) { checkForHosedThisReferences ( value , key . getJSDocInfo ( ) , p ) ; } } } }
Declares global variables to serve as aliases for the values in an object literal optionally removing all of the object literal s keys and values .