import { isString } from 'util' ; import { ProjectLanguage } from '../../constants' ; import { IFunctionBinding , ParsedFunctionJson } from '../../funcConfig/function' ; import { localize } from '../../localize' ; import { IBindingSetting , IBindingTemplate , IEnumValue , ResourceType , ValueType } from '../IBindingTemplate' ; import { IFunctionTemplate , TemplateCategory } from '../IFunctionTemplate' ; import { ITemplates } from '../ITemplates' ; /**
 * Describes a script template before it has been parsed
 */ export interface IRawTemplate { id ? : string ; function ? : { } ; metadata ? : { defaultFunctionName : string ; name : string ; language : ProjectLanguage ; userPrompt ? : string [ ] ; category ? : TemplateCategory [ ] ; } ; files ? : { [ filename ] : string ; } ; } /**
 * Describes a script template setting before it has been parsed
 */ interface IRawSetting { name : string ; value : ValueType ; label : string ; help ? : string ; defaultValue ? : string ; required ? : boolean ; resource ? : ResourceType ; validators ? : { expression : string ; errorText : string ; } [ ] ; enum ? : { value : string ; display : string ; } [ ] ; } interface IRawBinding { type ? : string ; documentation : string ; displayName : string ; direction : string ; settings ? : IRawSetting [ ] ; } /**
 * Describes script template config to be used for parsing
 */ export interface IConfig { variables : IVariables ; bindings ? : IRawBinding [ ] ; } /**
 * Describes script template variables to be used for parsing
 */ interface IVariables { [ name ] : string ; } /**
 * Describes script template resources to be used for parsing
 */ export interface IResources { lang ? : { [ key ] : string | undefined ; } ; en : { [ key ] : string | undefined ; } ; } function getVariableValue ( resources , variables , data ) { if ( ! isString ( data ) ) { return data ; } const matches = data . match ( /\[variables\(\'(.*)\'\)\]/ ) ; data = matches !== null ? variables [ matches [ 1 ] ] : data ; return getResourceValue ( resources , data ) ; } export function getResourceValue ( resources , data ) { const matches = data . match ( /\$(.*)/ ) ; if ( matches === null ) { return data ; } else { const key = matches [ 1 ] ; const result = resources . lang && resources . lang [ key ] ? resources . lang [ key ] : resources . en [ key ] ; if ( result === undefined ) { throw new Error ( localize ( 'resourceNotFound' , 'Resource "{0}" not found.' , data ) ) ; } else { return result ; } } } function parseScriptSetting ( data , resources , variables ) { const rawSetting = < IRawSetting > data ; const enums = [ ] ; if ( rawSetting . enum ) { for ( const ev of rawSetting . enum ) { enums . push ( { value : getVariableValue ( resources , variables , ev . value ) , displayName : getVariableValue ( resources , variables , ev . display ) } ) ; } } return { name : getVariableValue ( resources , variables , rawSetting . name ) , resourceType : rawSetting . resource , valueType : rawSetting . value , description : rawSetting . help ? replaceHtmlLinkWithMarkdown ( getResourceValue ( resources , rawSetting . help ) ) : undefined , defaultValue : rawSetting . defaultValue , label : getVariableValue ( resources , variables , rawSetting . label ) , enums : enums , required : rawSetting . required , validateSetting : ( value ) : string | undefined => { if ( rawSetting . validators ) { for ( const validator of rawSetting . validators ) { if ( ! value || value . match ( validator . expression ) === null ) { return replaceHtmlLinkWithMarkdown ( getVariableValue ( resources , variables , validator . errorText ) ) ; } } } return undefined ; } } ; } function replaceHtmlLinkWithMarkdown ( text ) { const match = text . match ( /<a[^>]*href=['"]([^'"]*)['"][^>]*>([^<]*)<\/a>/i ) ; if ( match ) { return text . replace ( match [ 0 ] , `[${ match [ 2 ] }](${ match [ 1 ] })` ) ; } else { return text ; } } export function parseScriptBindings ( config , resources ) { const result = [ ] ; if ( config . bindings ) { for ( const rawBinding of config . bindings ) { try { if ( rawBinding . type ) { const settings = ( rawBinding . settings || [ ] ) . map ( ( setting ) => parseScriptSetting ( setting , resources , config . variables ) ) ; result . push ( { direction : rawBinding . direction , displayName : getResourceValue ( resources , rawBinding . displayName ) , isHttpTrigger : /^http/i . test ( rawBinding . type ) , isTimerTrigger : /^timer/i . test ( rawBinding . type ) , settings , type : rawBinding . type } ) ; } } catch { } } } return result ; } export function parseScriptTemplate ( rawTemplate , resources , bindingTemplates ) { if ( ! rawTemplate . id || ! rawTemplate . metadata ) { return undefined ; } const functionJson = new ParsedFunctionJson ( rawTemplate . function ) ; let language = rawTemplate . metadata . language ; switch ( language ) { case ProjectLanguage . CSharp : language = ProjectLanguage . CSharpScript ; break ; case ProjectLanguage . FSharp : language = ProjectLanguage . FSharpScript ; break ; case ProjectLanguage . Java : language = ProjectLanguage . Java ; break ; default : } const userPromptedSettings = [ ] ; if ( rawTemplate . metadata . userPrompt ) { for ( const settingName of rawTemplate . metadata . userPrompt ) { if ( functionJson . triggerBinding ) { const triggerBinding = functionJson . triggerBinding ; const bindingTemplate = bindingTemplates . find ( b => b . type . toLowerCase ( ) === triggerBinding . type ?. toLowerCase ( ) ) ; if ( bindingTemplate ) { const setting = bindingTemplate . settings . find ( ( bs ) => bs . name === settingName ) ; if ( setting ) { const functionSpecificDefaultValue = triggerBinding [ setting . name ] ; if ( functionSpecificDefaultValue ) { setting . defaultValue = functionSpecificDefaultValue ; } userPromptedSettings . push ( setting ) ; } } } } } return { functionJson , isHttpTrigger : functionJson . isHttpTrigger , isTimerTrigger : functionJson . isTimerTrigger , id : rawTemplate . id , name : getResourceValue ( resources , rawTemplate . metadata . name ) , defaultFunctionName : rawTemplate . metadata . defaultFunctionName , language , userPromptedSettings , templateFiles : rawTemplate . files || { } , categories : rawTemplate . metadata . category || [ ] } ; } export interface IScriptFunctionTemplate extends IFunctionTemplate { templateFiles : { [ filename ] : string ; } ; functionJson : ParsedFunctionJson ; } /**
 * Parses templates contained in the templateApiZip of the functions cli feed. This contains all 'script' templates, including JavaScript, C#Script, Python, etc.
 * This basically converts the 'raw' templates in the externally defined JSON format to a common and understood format (IFunctionTemplate) used by this extension
 */ export function parseScriptTemplates ( rawResources , rawTemplates , rawConfig ) { const bindingTemplates = parseScriptBindings ( < IConfig > rawConfig , < IResources > rawResources ) ; const functionTemplates = [ ] ; for ( const rawTemplate of rawTemplates ) { try { const parsed = parseScriptTemplate ( < IRawTemplate > rawTemplate , < IResources > rawResources , bindingTemplates ) ; if ( parsed ) { functionTemplates . push ( parsed ) ; } } catch { } } return { functionTemplates , bindingTemplates } ; }