import { templateKeys } from '../../../../common' ; import { Json , strings } from '../../../../extension.bundle' ; import { assert } from '../../../fixed_assert' ; import * as TLE from "../../../language/expressions/TLE" ; import { CachedValue } from '../../../util/CachedValue' ; import { IParameterDefinition } from '../../parameters/IParameterDefinition' ; import { IParameterDefinitionsSource } from '../../parameters/IParameterDefinitionsSource' ; import { IParameterDefinitionsSourceProvider } from "../../parameters/IParameterDefinitionsSourceProvider" ; import { IParameterValuesSource } from '../../parameters/IParameterValuesSource' ; import { IJsonDocument } from '../IJsonDocument' ; import { IResource } from '../IResource' ; import { UserFunctionDefinition } from '../UserFunctionDefinition' ; import { UserFunctionNamespaceDefinition } from "../UserFunctionNamespaceDefinition" ; import { IVariableDefinition } from '../VariableDefinition' ; import { IDeploymentSchemaReference } from './IDeploymentSchemaReference' ; export enum TemplateScopeKind { Empty = "Empty" , TopLevel = "TopLevel" , ParameterDefaultValue = "ParameterDefaultValue" , UserFunction = "UserFunction" , NestedDeploymentWithInnerScope = "NestedDeploymentWithInnerScope" , NestedDeploymentWithOuterScope = "NestedDeploymentWithOuterScope" , LinkedDeployment = "LinkedDeployment" } /**
 * Represents the scoped access of parameters/variables/functions at a particular point in the template tree.
 */ export abstract class TemplateScope implements IParameterDefinitionsSourceProvider { private _variableDefinitions : CachedValue < IVariableDefinition [ ] | undefined > = new CachedValue < IVariableDefinition [ ] | undefined > ( ) ; private _functionDefinitions : CachedValue < UserFunctionNamespaceDefinition [ ] | undefined > = new CachedValue < UserFunctionNamespaceDefinition [ ] | undefined > ( ) ; private _resources : CachedValue < IResource [ ] | undefined > = new CachedValue < IResource [ ] | undefined > ( ) ; constructor ( public readonly parent , public readonly document , /** The object that the scope applies to (expressions inside this object will use this scope for evaluation) */ public readonly rootObject , /**
     * The scope of the deployment if this represents a deployment (RG, subscription, MG, tenant)
     * Undefined if this scope is not a deployment (e.g. it's a user function scope).
     * If it is a deployment scope but the schema is invalid, deploymentScope will be undefined and
     *  contains kind=unknown
     */ public readonly deploymentSchema , public readonly __debugDisplay ) { } public readonly abstract scopeKind : TemplateScopeKind ; /**
     * Indicates whether this scope's params, vars and namespaces are unique.
     * False if it shares its members with its parents.
     * Note that resources are always unique to a scope.
     */ public readonly hasUniqueParamsVarsAndFunctions : boolean = true ; /**
     * True if this scope is external to the hosting template file (i.e., it's a linked deployment template)
     */ public readonly isExternal : boolean = false ; /**
     * The root object that owns the parameters, variables and user functions that are used by
     * this scope (will be the scope's root object itself if hasUniqueParamsVarsAndFunctions = true)
     */ public get memberOwningRootObject ( ) : Json . ObjectValue | undefined { return this . getMemberOwningRootObject ( ) ; } protected getMemberOwningRootObject ( ) { return this . rootObject ; } protected getVariableDefinitions ( ) { return undefined ; } protected getNamespaceDefinitions ( ) { return undefined ; } protected getResources ( ) { return undefined ; } protected getParameterValuesSource ( ) { return undefined ; } protected abstract getParameterDefinitionsSource ( ) ; public get parameterDefinitions ( ) : IParameterDefinition [ ] { return this . getParameterDefinitionsSource ( ) . parameterDefinitions ; } public get variableDefinitions ( ) : IVariableDefinition [ ] { return this . _variableDefinitions . getOrCacheValue ( ( ) => this . getVariableDefinitions ( ) ) ?? [ ] ; } public get namespaceDefinitions ( ) : UserFunctionNamespaceDefinition [ ] { return this . _functionDefinitions . getOrCacheValue ( ( ) => this . getNamespaceDefinitions ( ) ) ?? [ ] ; } public get resources ( ) : IResource [ ] { return this . _resources . getOrCacheValue ( ( ) => this . getResources ( ) ) ?? [ ] ; } public get parameterValuesSource ( ) : IParameterValuesSource | undefined { return this . getParameterValuesSource ( ) ; } public get parameterDefinitionsSource ( ) : IParameterDefinitionsSource { return this . getParameterDefinitionsSource ( ) ; } public get childScopes ( ) : TemplateScope [ ] { const scopes = [ ] ; for ( let resource of this . resources ?? [ ] ) { if ( resource . childDeployment ) { scopes . push ( resource . childDeployment ) ; } } if ( this . hasUniqueParamsVarsAndFunctions ) { for ( let namespace of this . namespaceDefinitions ) { for ( let member of namespace . members ) { scopes . push ( member . scope ) ; } } } return scopes ; } public getParameterDefinition ( parameterName ) { const unquotedParameterName = strings . unquote ( parameterName ) ; if ( unquotedParameterName ) { let parameterNameLC = unquotedParameterName . toLowerCase ( ) ; for ( let i = this . parameterDefinitionsSource . parameterDefinitions . length - 1 ; i >= 0 ; -- i ) { let pd = this . parameterDefinitionsSource . parameterDefinitions [ i ] ; if ( pd . nameValue . toString ( ) . toLowerCase ( ) === parameterNameLC ) { return pd ; } } } return undefined ; } public getFunctionNamespaceDefinition ( namespaceName ) { if ( ! namespaceName ) { return undefined ; } let namespaceNameLC = namespaceName . toLowerCase ( ) ; return this . namespaceDefinitions . find ( ( nd ) => nd . nameValue . toString ( ) . toLowerCase ( ) === namespaceNameLC ) ; } public getUserFunctionDefinition ( namespace , functionName ) { if ( ! functionName ) { return undefined ; } let nd = typeof namespace === 'string' ? this . getFunctionNamespaceDefinition ( namespace ) : namespace ; if ( nd ) { let result = nd . getMemberDefinition ( functionName ) ; return result ? result : undefined ; } return undefined ; } public getVariableDefinition ( variableName ) { const unquotedVariableName = strings . unquote ( variableName ) ; if ( unquotedVariableName ) { const variableNameLC = unquotedVariableName . toLowerCase ( ) ; for ( let i = this . variableDefinitions . length - 1 ; i >= 0 ; -- i ) { let vd = this . variableDefinitions [ i ] ; if ( vd . nameValue . toString ( ) . toLowerCase ( ) === variableNameLC ) { return vd ; } } } return undefined ; } /**
     * If the function call is a variables() reference, return the related variable definition
     */ public getVariableDefinitionFromFunctionCall ( tleFunction ) { let result ; if ( tleFunction . isCallToBuiltinWithName ( templateKeys . variables ) ) { const variableName = TLE . asStringValue ( tleFunction . argumentExpressions [ 0 ] ) ; if ( variableName ) { result = this . getVariableDefinition ( variableName . toString ( ) ) ; } } return result ; } /**
     * If the function call is a parameters() reference, return the related parameter definition
     */ public getParameterDefinitionFromFunctionCall ( tleFunction ) { assert ( tleFunction ) ; let result ; if ( tleFunction . isCallToBuiltinWithName ( templateKeys . parameters ) ) { const propertyName = TLE . asStringValue ( tleFunction . argumentExpressions [ 0 ] ) ; if ( propertyName ) { result = this . getParameterDefinition ( propertyName . toString ( ) ) ; } } return result ; } public get isInUserFunction ( ) : boolean { return this . scopeKind === TemplateScopeKind . UserFunction ; } public get parentWithUniqueParamsVarsAndFunctions ( ) : TemplateScope { let parent = this . parent ; while ( ! parent ?. hasUniqueParamsVarsAndFunctions ) { parent = parent ?. parent ; } assert ( parent , "Should have found parent with unique params/vars/functions (top-level should be unique)" ) ; return parent ; } }