import * as fse from 'fs-extra' ; import * as path from 'path' ; import { QuickPickItem , Uri , window } from "vscode" ; import { IActionContext , UserCancelledError } from 'vscode-azureextensionui' ; import { ext } from '../../extensionVariables' ; import { isTleExpression } from "../../language/expressions/isTleExpression" ; import * as Json from "../../language/json/JSON" ; import { assertNever } from '../../util/assertNever' ; import { CaseInsensitiveMap } from '../../util/CaseInsensitiveMap' ; import { indentMultilineString , unindentMultilineString } from '../../util/multilineStrings' ; import { ExpressionType } from '../templates/ExpressionType' ; import { TemplateScope } from '../templates/scopes/TemplateScope' ; import { IParameterDefinition } from './IParameterDefinition' ; import { IParameterDefinitionsSource } from './IParameterDefinitionsSource' ; export const defaultTabSize = 4 ; export async function queryCreateParameterFile ( actionContext , scope , tabSize = defaultTabSize ) { const all = < QuickPickItem > { label : "All parameters" } ; const required = < QuickPickItem > { label : "Only required parameters" , description : "Uses only parameters that have no default value in the template file" } ; const templateUri = scope . document . documentUri ; const whichParams = await ext . ui . showQuickPick ( [ all , required ] , { placeHolder : `Include which parameters from ${ path . basename ( templateUri . fsPath ) }?` } ) ; const onlyRequiredParams = whichParams === required ; actionContext . telemetry . properties . onlyRequiredParams = String ( onlyRequiredParams ) ; const fileNameWithoutJsonC = path . basename ( templateUri . fsPath ) . replace ( /\.[Jj][Ss][Oo][Nn][Cc]?$/ , '' ) ; const defaultParamPath = path . join ( path . dirname ( templateUri . fsPath ) , `${ fileNameWithoutJsonC }.parameters.json` ) ; let newUri = await window . showSaveDialog ( { defaultUri : Uri . file ( defaultParamPath ) , filters : { JSON : [ 'json' , 'jsonc' ] } } ) ; if ( ! newUri ) { throw new UserCancelledError ( ) ; } let paramsObj = createParameterFileContents ( scope , tabSize , onlyRequiredParams ) ; await fse . writeFile ( newUri . fsPath , paramsObj , { encoding : 'utf8' } ) ; return newUri ; } export function createParameterFileContents ( scope , tabSize , onlyRequiredParameters ) { const tab = makeIndent ( tabSize ) ; const params = createParameters ( scope , tabSize , onlyRequiredParameters ) ; const paramsContent = params . map ( ( key , value ) => value ) . join ( `,${ ext . EOL }` ) ; let contents = `{` + ext . EOL + `${ tab }"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#",` + ext . EOL + `${ tab }"contentVersion": "1.0.0.0",` + ext . EOL + `${ tab }"parameters": {` + ext . EOL ; if ( params . size > 0 ) { contents += indentMultilineString ( paramsContent , tabSize * 2 ) + ext . EOL ; } contents += `${ tab }}` + ext . EOL + `}` ; return contents ; } param tabSize export function createParameterFromTemplateParameter ( parameterDefinitionsSource , parameter , parentParameterDefinitions , tabSize ) { let value ; const parameterNameLC = parameter . nameValue . unquotedValue . toLowerCase ( ) ; const matchingParentParameter = parentParameterDefinitions ?. parameterDefinitions . find ( def => def . nameValue . unquotedValue . toLowerCase ( ) === parameterNameLC ) ; if ( matchingParentParameter ) { value = `"[parameters('${ matchingParentParameter . nameValue . unquotedValue }')]"` ; } else if ( parameter . defaultValue ) { const isExpression = parameter . defaultValue instanceof Json . StringValue && isTleExpression ( parameter . defaultValue . unquotedValue ) ; if ( ! isExpression ) { const defValueSpan = parameter . defaultValue . span ; const defValue = parameter . document . documentText . slice ( defValueSpan . startIndex , defValueSpan . afterEndIndex ) ; value = unindentMultilineString ( defValue , true ) ; } } if ( value === undefined ) { value = getDefaultValueFromType ( parameter . validType , tabSize ) ; } const valueIndentedAfterFirstLine = indentMultilineString ( value . trimLeft ( ) , tabSize ) . trimLeft ( ) ; return `"${ parameter . nameValue . unquotedValue }": {` + ext . EOL + `${ makeIndent ( tabSize ) }"value": ${ valueIndentedAfterFirstLine }` + ext . EOL + `}` ; } function getDefaultValueFromType ( propType , indent ) { const comment = "// TODO: Fill in parameter value" ; const tab = ' ' . repeat ( indent ) ; switch ( propType ) { case "array" : return `[${ ext . EOL }${ tab }${ comment }${ ext . EOL }]` ; case "bool" : return `false ${ comment }` ; case "int" : return `0 ${ comment }` ; case "object" : case "secureobject" : return `{${ ext . EOL }${ tab }${ comment }${ ext . EOL }}` ; case "securestring" : case "string" : case undefined : return `"" ${ comment }` ; default : assertNever ( propType ) ; } } function createParameters ( scope , tabSize , onlyRequiredParameters ) { let params = new CaseInsensitiveMap < string , string > ( ) ; for ( let paramDef of scope . parameterDefinitionsSource . parameterDefinitions ) { if ( ! onlyRequiredParameters || ! paramDef . defaultValue ) { params . set ( paramDef . nameValue . unquotedValue , createParameterFromTemplateParameter ( scope . parameterDefinitionsSource , paramDef , undefined , tabSize ) ) ; } } return params ; } function makeIndent ( tabSize ) { return ' ' . repeat ( tabSize ) ; }