import { callWithTelemetryAndErrorHandling , IActionContext } from 'vscode-azureextensionui' ; import { ProjectLanguage , TemplateFilter } from '../../constants' ; import { ext } from '../../extensionVariables' ; import { FuncVersion } from '../../FuncVersion' ; import { localize } from '../../localize' ; import { IBindingSetting , ValueType } from '../IBindingTemplate' ; import { IFunctionTemplate , TemplateCategory } from '../IFunctionTemplate' ; import { ITemplates } from '../ITemplates' ; /**
 * Describes a dotnet template before it has been parsed
 */ interface IRawTemplate { DefaultName : string ; Name : string ; Identity : string ; Parameters : { } [ ] ; } /**
 * Describes a dotnet template setting before it has been parsed
 */ interface IRawSetting { Documentation : string | undefined ; Name : string ; DefaultValue : string | undefined ; DataType : string | undefined ; Choices : { [ key ] : string ; } | undefined ; } function parseDotnetSetting ( rawSetting ) { let valueType ; switch ( rawSetting . DataType ?. toLowerCase ( ) ) { case 'choice' : valueType = ValueType . enum ; break ; case 'bool' : valueType = ValueType . boolean ; break ; default : valueType = ValueType . string ; } return { name : rawSetting . Name , resourceType : undefined , valueType , defaultValue : rawSetting . DefaultValue , required : true , label : rawSetting . Name , description : rawSetting . Documentation , enums : rawSetting . Choices ? Object . keys ( rawSetting . Choices ) . map ( ( key ) => { return { value : key , displayName : key } ; } ) : [ ] , validateSetting : ( ) : undefined => { return undefined ; } } ; } function parseDotnetTemplate ( rawTemplate ) { const userPromptedSettings = [ ] ; for ( const rawSetting of rawTemplate . Parameters ) { const setting = parseDotnetSetting ( < IRawSetting > rawSetting ) ; if ( ! /^(name|namespace|type|language)$/i . test ( setting . name ) ) { userPromptedSettings . push ( setting ) ; } } return { isHttpTrigger : /^http/i . test ( rawTemplate . Name ) || /webhook$/i . test ( rawTemplate . Name ) , isTimerTrigger : /^timer/i . test ( rawTemplate . Name ) , id : rawTemplate . Identity , name : rawTemplate . Name , defaultFunctionName : rawTemplate . DefaultName , language : /FSharp/i . test ( rawTemplate . Identity ) ? ProjectLanguage . FSharp : ProjectLanguage . CSharp , userPromptedSettings : userPromptedSettings , categories : [ TemplateCategory . Core ] } ; } /**
 * Parses templates used by the .NET CLI
 * This basically converts the 'raw' templates in the externally defined JSON format to a common and understood format (IFunctionTemplate) used by this extension
 */ export async function parseDotnetTemplates ( rawTemplates , version ) { const functionTemplates = [ ] ; for ( const rawTemplate of rawTemplates ) { try { functionTemplates . push ( parseDotnetTemplate ( < IRawTemplate > rawTemplate ) ) ; } catch ( error ) { } } await copyCSharpSettingsFromJS ( functionTemplates , version ) ; return { functionTemplates , bindingTemplates : [ ] } ; } /**
 * The dotnet templates do not provide the validation, resourceType, and display information that we desire
 * As a workaround, we can check for the exact same JavaScript template/setting and leverage that information
 */ async function copyCSharpSettingsFromJS ( csharpTemplates , version ) { await callWithTelemetryAndErrorHandling ( 'copyCSharpSettingsFromJS' , async ( jsContext ) => { jsContext . errorHandling . suppressDisplay = true ; jsContext . telemetry . properties . isActivationEvent = 'true' ; const templateProvider = ext . templateProvider . get ( jsContext ) ; const jsTemplates = await templateProvider . getFunctionTemplates ( jsContext , undefined , ProjectLanguage . JavaScript , version , TemplateFilter . All , undefined ) ; for ( const csharpTemplate of csharpTemplates ) { const normalizedDotnetId = normalizeDotnetId ( csharpTemplate . id ) ; const jsTemplate = jsTemplates . find ( ( t ) => normalizeScriptId ( t . id ) === normalizedDotnetId ) ; if ( jsTemplate ) { csharpTemplate . name = jsTemplate . name ; csharpTemplate . defaultFunctionName = jsTemplate . defaultFunctionName ; for ( const cSharpSetting of csharpTemplate . userPromptedSettings ) { const jsSetting = jsTemplate . userPromptedSettings . find ( ( t ) => normalizeName ( t . name ) === normalizeName ( cSharpSetting . name ) ) ; if ( jsSetting ) { cSharpSetting . resourceType = jsSetting . resourceType ; cSharpSetting . validateSetting = jsSetting . validateSetting ; } } } else { switch ( normalizedDotnetId ) { case 'httpwithopenapi' : csharpTemplate . name = localize ( 'httpWithOpenApiName' , 'HTTP trigger with OpenAPI' ) ; break ; case 'durablefunctionsorchestration' : csharpTemplate . name = localize ( 'durableFunctionsOrchestrationName' , 'Durable Functions Orchestration' ) ; break ; } } } } ) ; } /**
 * Converts ids like "Azure.Function.CSharp.QueueTrigger.2.x" to "queue"
 */ function normalizeDotnetId ( id ) { const match = id . match ( /^azure\.function\.(?:c|f)sharp\.(?:isolated\.|)([a-z]+)\./i ) ; return normalizeName ( match ? match [ 1 ] : id ) ; } /**
 * Converts ids like "QueueTrigger-JavaScript" to "queue"
 */ function normalizeScriptId ( id ) { const match = id . match ( /^([a-z]+)-/i ) ; return normalizeName ( match ? match [ 1 ] : id ) ; } function normalizeName ( name ) { return name . toLowerCase ( ) . replace ( /\s/g , '' ) . replace ( /trigger/i , '' ) ; }