private String genParamsRecordType ( TemplateNode node ) { Set < String > paramNames = new HashSet <> ( ) ; // Generate members for explicit params. Map < String , String > record = new LinkedHashMap <> ( ) ; for ( TemplateParam param : node . getParams ( ) ) { JsType jsType = getJsTypeForParamForDeclaration ( param . type ( ) ) ; record . put ( param . name ( ) , jsType . typeExprForRecordMember ( /* isOptional= */ ! param . isRequired ( ) ) ) ; for ( GoogRequire require : jsType . getGoogRequires ( ) ) { // TODO(lukes): switch these to requireTypes jsCodeBuilder . addGoogRequire ( require ) ; } paramNames . add ( param . name ( ) ) ; } // Do the same for indirect params, if we can find them. // If there's a conflict between the explicitly-declared type, and the type // inferred from the indirect params, then the explicit type wins. // Also note that indirect param types may not be inferrable if the target // is not in the current compilation file set. IndirectParamsInfo ipi = new IndirectParamsCalculator ( templateRegistry ) . calculateIndirectParams ( templateRegistry . getMetadata ( node ) ) ; // If there are any calls outside of the file set, then we can't know // the complete types of any indirect params. In such a case, we can simply // omit the indirect params from the function type signature, since record // types in JS allow additional undeclared fields to be present. if ( ! ipi . mayHaveIndirectParamsInExternalCalls && ! ipi . mayHaveIndirectParamsInExternalDelCalls ) { for ( String indirectParamName : ipi . indirectParamTypes . keySet ( ) ) { if ( paramNames . contains ( indirectParamName ) ) { continue ; } Collection < SoyType > paramTypes = ipi . indirectParamTypes . get ( indirectParamName ) ; SoyType combinedType = SoyTypes . computeLowestCommonType ( typeRegistry , paramTypes ) ; // Note that Union folds duplicate types and flattens unions, so if // the combinedType is already a union this will do the right thing. // TODO: detect cases where nullable is not needed (requires flow // analysis to determine if the template is always called.) SoyType indirectParamType = typeRegistry . getOrCreateUnionType ( combinedType , NullType . getInstance ( ) ) ; JsType jsType = getJsTypeForParamForDeclaration ( indirectParamType ) ; // NOTE: we do not add goog.requires for indirect types. This is because it might introduce // strict deps errors. This should be fine though since the transitive soy template that // actually has the param will add them. record . put ( indirectParamName , jsType . typeExprForRecordMember ( /* isOptional= */ true ) ) ; } } StringBuilder sb = new StringBuilder ( ) ; sb . append ( "{\n * " ) ; Joiner . on ( ",\n * " ) . withKeyValueSeparator ( ": " ) . appendTo ( sb , record ) ; // trailing comma in record is important in case the last record member is the // unknown type sb . append ( ",\n * }" ) ; return sb . toString ( ) ; }
Generate the JSDoc for the opt_data parameter .