in packages/aws-cdk-lib/core/lib/helpers-internal/cfn-parse.ts [541:695]
private parseIfCfnIntrinsic(object: any): any {
const key = this.looksLikeCfnIntrinsic(object);
switch (key) {
case undefined:
return undefined;
case 'Ref': {
const refTarget = object[key];
const specialRef = this.specialCaseRefs(refTarget);
if (specialRef !== undefined) {
return specialRef;
} else {
const refElement = this.finder.findRefTarget(refTarget);
if (!refElement) {
throw new Error(`Element used in Ref expression with logical ID: '${refTarget}' not found`);
}
return CfnReference.for(refElement, 'Ref');
}
}
case 'Fn::GetAtt': {
const value = object[key];
let logicalId: string, attributeName: string, stringForm: boolean;
// Fn::GetAtt takes as arguments either a string...
if (typeof value === 'string') {
// ...in which case the logical ID and the attribute name are separated with '.'
const dotIndex = value.indexOf('.');
if (dotIndex === -1) {
throw new Error(`Short-form Fn::GetAtt must contain a '.' in its string argument, got: '${value}'`);
}
logicalId = value.slice(0, dotIndex);
attributeName = value.slice(dotIndex + 1); // the +1 is to skip the actual '.'
stringForm = true;
} else {
// ...or a 2-element list
logicalId = value[0];
attributeName = value[1];
stringForm = false;
}
const target = this.finder.findResource(logicalId);
if (!target) {
throw new Error(`Resource used in GetAtt expression with logical ID: '${logicalId}' not found`);
}
return CfnReference.for(target, attributeName, stringForm ? ReferenceRendering.GET_ATT_STRING : undefined);
}
case 'Fn::Join': {
// Fn::Join takes a 2-element list as its argument,
// where the first element is the delimiter,
// and the second is the list of elements to join
const value = this.parseValue(object[key]);
// wrap the array as a Token,
// as otherwise Fn.join() will try to concatenate
// the non-token parts,
// causing a diff with the original template
return Fn.join(value[0], Lazy.list({ produce: () => value[1] }));
}
case 'Fn::Cidr': {
const value = this.parseValue(object[key]);
return Fn.cidr(value[0], value[1], value[2]);
}
case 'Fn::FindInMap': {
const value = this.parseValue(object[key]);
// the first argument to FindInMap is the mapping name
let mappingName: string;
if (Token.isUnresolved(value[0])) {
// the first argument can be a dynamic expression like Ref: Param;
// if it is, we can't find the mapping in advance
mappingName = value[0];
} else {
const mapping = this.finder.findMapping(value[0]);
if (!mapping) {
throw new Error(`Mapping used in FindInMap expression with name '${value[0]}' was not found in the template`);
}
mappingName = mapping.logicalId;
}
return Fn._findInMap(mappingName, value[1], value[2]);
}
case 'Fn::Select': {
const value = this.parseValue(object[key]);
return Fn.select(value[0], value[1]);
}
case 'Fn::GetAZs': {
const value = this.parseValue(object[key]);
return Fn.getAzs(value);
}
case 'Fn::ImportValue': {
const value = this.parseValue(object[key]);
return Fn.importValue(value);
}
case 'Fn::Split': {
const value = this.parseValue(object[key]);
return Fn.split(value[0], value[1]);
}
case 'Fn::Transform': {
const value = this.parseValue(object[key]);
return Fn.transform(value.Name, value.Parameters);
}
case 'Fn::Base64': {
const value = this.parseValue(object[key]);
return Fn.base64(value);
}
case 'Fn::If': {
// Fn::If takes a 3-element list as its argument,
// where the first element is the name of a Condition
const value = this.parseValue(object[key]);
const condition = this.finder.findCondition(value[0]);
if (!condition) {
throw new Error(`Condition '${value[0]}' used in an Fn::If expression does not exist in the template`);
}
return Fn.conditionIf(condition.logicalId, value[1], value[2]);
}
case 'Fn::Equals': {
const value = this.parseValue(object[key]);
return Fn.conditionEquals(value[0], value[1]);
}
case 'Fn::And': {
const value = this.parseValue(object[key]);
return Fn.conditionAnd(...value);
}
case 'Fn::Not': {
const value = this.parseValue(object[key]);
return Fn.conditionNot(value[0]);
}
case 'Fn::Or': {
const value = this.parseValue(object[key]);
return Fn.conditionOr(...value);
}
case 'Fn::Sub': {
const value = this.parseValue(object[key]);
let fnSubString: string;
let map: { [key: string]: any } | undefined;
if (typeof value === 'string') {
fnSubString = value;
map = undefined;
} else {
fnSubString = value[0];
map = value[1];
}
return this.parseFnSubString(fnSubString, map);
}
case 'Condition': {
// a reference to a Condition from another Condition
const condition = this.finder.findCondition(object[key]);
if (!condition) {
throw new Error(`Referenced Condition with name '${object[key]}' was not found in the template`);
}
return { Condition: condition.logicalId };
}
default:
if (this.options.context === CfnParsingContext.RULES) {
return this.handleRulesIntrinsic(key, object);
} else {
throw new Error(`Unsupported CloudFormation function '${key}'`);
}
}
}