private parseIfCfnIntrinsic()

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}'`);
        }
    }
  }