public async evaluateCfnExpression()

in packages/@aws-cdk/toolkit-lib/lib/api/cloudformation/evaluate-cloudformation-template.ts [210:317]


  public async evaluateCfnExpression(cfnExpression: any): Promise<any> {
    const self = this;
    /**
     * Evaluates CloudFormation intrinsic functions
     *
     * Note that supported intrinsic functions are documented in README.md -- please update
     * list of supported functions when adding new evaluations
     *
     * See: https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference.html
     */
    class CfnIntrinsics {
      public evaluateIntrinsic(intrinsic: Intrinsic): any {
        const intrinsicFunc = (this as any)[intrinsic.name];
        if (!intrinsicFunc) {
          throw new CfnEvaluationException(`CloudFormation function ${intrinsic.name} is not supported`);
        }

        const argsAsArray = Array.isArray(intrinsic.args) ? intrinsic.args : [intrinsic.args];

        return intrinsicFunc.apply(this, argsAsArray);
      }

      async 'Fn::Join'(separator: string, args: any[]): Promise<string> {
        const evaluatedArgs = await self.evaluateCfnExpression(args);
        return evaluatedArgs.join(separator);
      }

      async 'Fn::Split'(separator: string, args: any): Promise<string> {
        const evaluatedArgs = await self.evaluateCfnExpression(args);
        return evaluatedArgs.split(separator);
      }

      async 'Fn::Select'(index: number, args: any[]): Promise<string> {
        const evaluatedArgs = await self.evaluateCfnExpression(args);
        return evaluatedArgs[index];
      }

      async Ref(logicalId: string): Promise<string> {
        const refTarget = await self.findRefTarget(logicalId);
        if (refTarget) {
          return refTarget;
        } else {
          throw new CfnEvaluationException(`Parameter or resource '${logicalId}' could not be found for evaluation`);
        }
      }

      async 'Fn::GetAtt'(logicalId: string, attributeName: string): Promise<string> {
        // ToDo handle the 'logicalId.attributeName' form of Fn::GetAtt
        const attrValue = await self.findGetAttTarget(logicalId, attributeName);
        if (attrValue) {
          return attrValue;
        } else {
          throw new CfnEvaluationException(
            `Attribute '${attributeName}' of resource '${logicalId}' could not be found for evaluation`,
          );
        }
      }

      async 'Fn::Sub'(template: string, explicitPlaceholders?: { [variable: string]: string }): Promise<string> {
        const placeholders = explicitPlaceholders ? await self.evaluateCfnExpression(explicitPlaceholders) : {};

        return asyncGlobalReplace(template, /\${([^}]*)}/g, (key) => {
          if (key in placeholders) {
            return placeholders[key];
          } else {
            const splitKey = key.split('.');
            return splitKey.length === 1 ? this.Ref(key) : this['Fn::GetAtt'](splitKey[0], splitKey.slice(1).join('.'));
          }
        });
      }

      async 'Fn::ImportValue'(name: string): Promise<string> {
        const exported = await self.lookupExport.lookupExport(name);
        if (!exported) {
          throw new CfnEvaluationException(`Export '${name}' could not be found for evaluation`);
        }
        if (!exported.Value) {
          throw new CfnEvaluationException(`Export '${name}' exists without a value`);
        }
        return exported.Value;
      }
    }

    if (cfnExpression == null) {
      return cfnExpression;
    }

    if (Array.isArray(cfnExpression)) {
      // Small arrays in practice
      // eslint-disable-next-line @cdklabs/promiseall-no-unbounded-parallelism
      return Promise.all(cfnExpression.map((expr) => this.evaluateCfnExpression(expr)));
    }

    if (typeof cfnExpression === 'object') {
      const intrinsic = this.parseIntrinsic(cfnExpression);
      if (intrinsic) {
        return new CfnIntrinsics().evaluateIntrinsic(intrinsic);
      } else {
        const ret: { [key: string]: any } = {};
        for (const [key, val] of Object.entries(cfnExpression)) {
          ret[key] = await this.evaluateCfnExpression(val);
        }
        return ret;
      }
    }

    return cfnExpression;
  }