in src/documents/positionContexts/TemplatePositionContext.ts [113:253]
public getReferenceSiteInfo(considerDefinitionItself: boolean): IReferenceSite | undefined {
const tleInfo = this.tleInfo;
if (tleInfo) {
const scope = tleInfo.scope;
const tleCharacterIndex = tleInfo.tleCharacterIndex;
const definitionDocument = this.document;
const referenceDocument = this.document;
const tleFuncCall: TLE.FunctionCallValue | undefined = TLE.asFunctionCallValue(tleInfo.tleValue);
if (tleFuncCall) {
if (tleFuncCall.namespaceToken && tleFuncCall.namespaceToken.span.contains(tleCharacterIndex, ContainsBehavior.strict)) {
// Inside the namespace of a user-function reference
const ns = tleFuncCall.namespaceToken.stringValue;
const nsDefinition = scope.getFunctionNamespaceDefinition(ns);
if (nsDefinition) {
const unquotedReferenceSpan: Span = tleFuncCall.namespaceToken.span.translate(this.jsonTokenStartIndex);
return { referenceKind: ReferenceSiteKind.reference, referenceDocument, definition: nsDefinition, definitionScope: scope, unquotedReferenceSpan, definitionDocument };
}
} else if (tleFuncCall.nameToken) {
const unquotedReferenceSpan: Span = tleFuncCall.nameToken.span.translate(this.jsonTokenStartIndex);
const referenceKind = ReferenceSiteKind.reference;
if (tleFuncCall.nameToken.span.contains(tleCharacterIndex, ContainsBehavior.strict)) {
if (tleFuncCall.namespaceToken) {
// Inside the name of a user-function reference
const ns = tleFuncCall.namespaceToken.stringValue;
const name = tleFuncCall.nameToken.stringValue;
const nsDefinition = scope.getFunctionNamespaceDefinition(ns);
const userFunctiondefinition = scope.getUserFunctionDefinition(ns, name);
if (nsDefinition && userFunctiondefinition) {
return { referenceKind, referenceDocument, definition: userFunctiondefinition, definitionScope: scope, unquotedReferenceSpan, definitionDocument };
}
} else {
// Inside a reference to a built-in function
const builtInFuncName: string = tleFuncCall.nameToken.stringValue.toLowerCase();
// If it's inside a 'parameters' or 'variables' function call, get a reference to the referenced param/var instead of the parameters/variables built-infunction
if (tleFuncCall.argumentExpressions.length === 1) {
const arg = tleFuncCall.argumentExpressions[0];
if (arg instanceof TLE.StringValue) {
const argStringValue: string | undefined = tleFuncCall.argumentExpressions[0]?.asStringValue?.unquotedValue;
if (argStringValue) {
if (builtInFuncName === templateKeys.parameters) {
const ref = this.getParameterReference(referenceDocument, definitionDocument, scope, referenceKind, arg);
if (ref) {
return ref;
}
} else if (builtInFuncName === templateKeys.variables) {
const ref = this.getVariableReference(referenceDocument, definitionDocument, scope, referenceKind, arg);
if (ref) {
return ref;
}
}
}
}
}
const functionMetadata: BuiltinFunctionMetadata | undefined = AzureRMAssets.getFunctionMetadataFromName(tleFuncCall.nameToken.stringValue);
if (functionMetadata) {
return { referenceKind, referenceDocument, definition: functionMetadata, definitionScope: undefined, unquotedReferenceSpan, definitionDocument };
}
}
}
}
}
const tleStringValue: TLE.StringValue | undefined = TLE.asStringValue(tleInfo.tleValue);
if (tleStringValue) {
const referenceKind = ReferenceSiteKind.reference;
if (tleStringValue.isParametersArgument()) {
// Inside the 'xxx' of a parameters('xxx') reference
const ref = this.getParameterReference(referenceDocument, definitionDocument, scope, referenceKind, tleStringValue);
if (ref) {
return ref;
}
} else if (tleStringValue.isVariablesArgument()) {
const ref = this.getVariableReference(referenceDocument, definitionDocument, scope, referenceKind, tleStringValue);
if (ref) {
return ref;
}
}
}
// Is it a parameter value for a nested or linked template?
// Note that the scope of a parameter value doesn't (currently) match the scope
// of the template that the parameter is defined in, e.g.:
/*
"resources": [
{
"type": "Microsoft.Resources/deployments",
"properties": {
"parameters": { <<<<<<<< Parameter value definition
"nestedParameter1": {
"value": "[parameters('topLevelParameter2')]"
}
},
"template": {
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"nestedParameter1": { <<<<<<<< Parameter definition
"type": "string"
}
}
*/
// Note that the value of nestedParameter1 is inside the top-level scope (in order to interpret
// expressions correctly in that scope). So nestedParameter1 will have its definition inside
// the child deployment's scope, and we need to check there as well as the current scope.
for (const childScope of scope.childScopes) {
if (childScope.parameterValuesSource) {
const infoAsParamValue = getReferenceSiteInfoForParameterValue(
this.document,
childScope.parameterDefinitionsSource,
childScope,
childScope.parameterValuesSource,
this.documentCharacterIndex);
if (infoAsParamValue) {
return infoAsParamValue;
}
}
}
if (considerDefinitionItself) {
const definition = this.getDefinitionAtSite();
if (definition && definition.nameValue) {
return {
referenceKind: ReferenceSiteKind.definition,
definition: definition,
referenceDocument: this.document,
definitionDocument: this.document,
definitionScope: tleInfo.scope,
unquotedReferenceSpan: definition.nameValue?.unquotedSpan
};
}
}
return undefined;
}
}