aws-cdk-lib
Version:
Version 2 of the AWS Cloud Development Kit library
2 lines (1 loc) • 20.1 kB
JavaScript
"use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.CfnParser=exports.CfnParsingContext=exports.FromCloudFormation=exports.FromCloudFormationPropertyObject=exports.FromCloudFormationResult=void 0;var cx_api_1=()=>{var tmp=require("../../../cx-api");return cx_api_1=()=>tmp,tmp},cfn_fn_1=()=>{var tmp=require("../cfn-fn");return cfn_fn_1=()=>tmp,tmp},cfn_pseudo_1=()=>{var tmp=require("../cfn-pseudo");return cfn_pseudo_1=()=>tmp,tmp},cfn_resource_policy_1=()=>{var tmp=require("../cfn-resource-policy");return cfn_resource_policy_1=()=>tmp,tmp},errors_1=()=>{var tmp=require("../errors");return errors_1=()=>tmp,tmp},feature_flags_1=()=>{var tmp=require("../feature-flags");return feature_flags_1=()=>tmp,tmp},lazy_1=()=>{var tmp=require("../lazy");return lazy_1=()=>tmp,tmp},cfn_reference_1=()=>{var tmp=require("../private/cfn-reference");return cfn_reference_1=()=>tmp,tmp},stack_1=()=>{var tmp=require("../stack");return stack_1=()=>tmp,tmp},token_1=()=>{var tmp=require("../token");return token_1=()=>tmp,tmp},util_1=()=>{var tmp=require("../util");return util_1=()=>tmp,tmp};class FromCloudFormationResult{constructor(value){this.value=value,this.extraProperties={}}appendExtraProperties(prefix,properties){for(const[key,val]of Object.entries(properties??{}))this.extraProperties[`${prefix}.${key}`]=val}}exports.FromCloudFormationResult=FromCloudFormationResult;class FromCloudFormationPropertyObject extends FromCloudFormationResult{constructor(){super({}),this.recognizedProperties=new Set}addPropertyResult(cdkPropName,cfnPropName,result){this.recognizedProperties.add(cfnPropName),result&&(this.value[cdkPropName]=result.value,this.appendExtraProperties(cfnPropName,result.extraProperties))}addUnrecognizedPropertiesAsExtra(properties){for(const[key,val]of Object.entries(properties))this.recognizedProperties.has(key)||(this.extraProperties[key]=val)}}exports.FromCloudFormationPropertyObject=FromCloudFormationPropertyObject;class FromCloudFormation{static getAny(value){return new FromCloudFormationResult(value)}static getBoolean(value){if(typeof value=="string")switch(value){case"true":return new FromCloudFormationResult(!0);case"false":return new FromCloudFormationResult(!1);default:throw new(errors_1()).UnscopedValidationError(`Expected 'true' or 'false' for boolean value, got: '${value}'`)}return new FromCloudFormationResult(value)}static getDate(value){return(0,token_1().isResolvableObject)(value)?new FromCloudFormationResult(value):typeof value=="string"?new FromCloudFormationResult(new Date(value)):new FromCloudFormationResult(value)}static getString(value){return(0,token_1().isResolvableObject)(value)?new FromCloudFormationResult(value.toString()):typeof value=="number"?new FromCloudFormationResult(value.toString()):typeof value=="boolean"?new FromCloudFormationResult(value.toString()):new FromCloudFormationResult(value)}static getNumber(value){if((0,token_1().isResolvableObject)(value))return new FromCloudFormationResult(token_1().Token.asNumber(value));if(typeof value=="string"){const parsedValue=parseFloat(value);if(!isNaN(parsedValue))return new FromCloudFormationResult(parsedValue)}return new FromCloudFormationResult(value)}static getStringArray(value){return(0,token_1().isResolvableObject)(value)?new FromCloudFormationResult(token_1().Token.asList(value)):FromCloudFormation.getArray(FromCloudFormation.getString)(value)}static getArray(mapper){return value=>{if(!Array.isArray(value))return new FromCloudFormationResult(value);const values=new Array,ret=new FromCloudFormationResult(values);for(let i=0;i<value.length;i++){const result=mapper(value[i]);values.push(result.value),ret.appendExtraProperties(`${i}`,result.extraProperties)}return ret}}static getMap(mapper){return value=>{if(typeof value!="object")return new FromCloudFormationResult(value);const values={},ret=new FromCloudFormationResult(values);for(const[key,val]of Object.entries(value)){const result=mapper(val);values[key]=result.value,ret.appendExtraProperties(key,result.extraProperties)}return ret}}static getCfnTag(tag){return(0,token_1().isResolvableObject)(tag)?new FromCloudFormationResult(tag):tag==null?new FromCloudFormationResult({}):new FromCloudFormationResult({key:tag.Key,value:tag.Value})}static getTypeUnion(validators,mappers){return value=>{for(let i=0;i<validators.length;i++){const candidate=mappers[i](value);if(validators[i](candidate.value).isSuccess)return candidate}return new FromCloudFormationResult(value)}}}exports.FromCloudFormation=FromCloudFormation;var CfnParsingContext;(function(CfnParsingContext2){CfnParsingContext2[CfnParsingContext2.CONDITIONS=0]="CONDITIONS",CfnParsingContext2[CfnParsingContext2.RULES=1]="RULES"})(CfnParsingContext||(exports.CfnParsingContext=CfnParsingContext={}));class CfnParser{constructor(options){this.options=options}handleAttributes(resource,resourceAttributes,logicalId){const cfnOptions=resource.cfnOptions;this.stack=stack_1().Stack.of(resource);const creationPolicy=this.parseCreationPolicy(resourceAttributes.CreationPolicy,logicalId),updatePolicy=this.parseUpdatePolicy(resourceAttributes.UpdatePolicy,logicalId);cfnOptions.creationPolicy=creationPolicy.value,cfnOptions.updatePolicy=updatePolicy.value,cfnOptions.deletionPolicy=this.parseDeletionPolicy(resourceAttributes.DeletionPolicy),cfnOptions.updateReplacePolicy=this.parseDeletionPolicy(resourceAttributes.UpdateReplacePolicy),cfnOptions.version=this.parseValue(resourceAttributes.Version),cfnOptions.description=this.parseValue(resourceAttributes.Description),cfnOptions.metadata=this.parseValue(resourceAttributes.Metadata);for(const[key,value]of Object.entries(creationPolicy.extraProperties))resource.addOverride(`CreationPolicy.${key}`,value);for(const[key,value]of Object.entries(updatePolicy.extraProperties))resource.addOverride(`UpdatePolicy.${key}`,value);if(resourceAttributes.Condition){const condition=this.finder.findCondition(resourceAttributes.Condition);if(!condition)throw new(errors_1()).UnscopedValidationError(`Resource '${logicalId}' uses Condition '${resourceAttributes.Condition}' that doesn't exist`);cfnOptions.condition=condition}resourceAttributes.DependsOn=resourceAttributes.DependsOn??[];const dependencies=Array.isArray(resourceAttributes.DependsOn)?resourceAttributes.DependsOn:[resourceAttributes.DependsOn];for(const dep of dependencies){const depResource=this.finder.findResource(dep);if(!depResource)throw new(errors_1()).UnscopedValidationError(`Resource '${logicalId}' depends on '${dep}' that doesn't exist`);resource.node.addDependency(depResource)}}parseCreationPolicy(policy,logicalId){if(typeof policy!="object")return new FromCloudFormationResult(void 0);this.throwIfIsIntrinsic(policy,logicalId);const self=this,creaPol=new ObjectParser(this.parseValue(policy));return creaPol.parseCase("autoScalingCreationPolicy",parseAutoScalingCreationPolicy),creaPol.parseCase("resourceSignal",parseResourceSignal),creaPol.toResult();function parseAutoScalingCreationPolicy(p){if(self.throwIfIsIntrinsic(p,logicalId),typeof p!="object")return new FromCloudFormationResult(void 0);const autoPol=new ObjectParser(p);return autoPol.parseCase("minSuccessfulInstancesPercent",FromCloudFormation.getNumber),autoPol.toResult()}function parseResourceSignal(p){if(typeof p!="object")return new FromCloudFormationResult(void 0);self.throwIfIsIntrinsic(p,logicalId);const sig=new ObjectParser(p);return sig.parseCase("count",FromCloudFormation.getNumber),sig.parseCase("timeout",FromCloudFormation.getString),sig.toResult()}}parseUpdatePolicy(policy,logicalId){if(typeof policy!="object")return new FromCloudFormationResult(void 0);this.throwIfIsIntrinsic(policy,logicalId);const self=this,uppol=new ObjectParser(this.parseValue(policy));return uppol.parseCase("autoScalingReplacingUpdate",parseAutoScalingReplacingUpdate),uppol.parseCase("autoScalingRollingUpdate",parseAutoScalingRollingUpdate),uppol.parseCase("autoScalingScheduledAction",parseAutoScalingScheduledAction),uppol.parseCase("codeDeployLambdaAliasUpdate",parseCodeDeployLambdaAliasUpdate),uppol.parseCase("enableVersionUpgrade",x=>FromCloudFormation.getBoolean(x)),uppol.parseCase("useOnlineResharding",x=>FromCloudFormation.getBoolean(x)),uppol.toResult();function parseAutoScalingReplacingUpdate(p){if(typeof p!="object")return new FromCloudFormationResult(void 0);self.throwIfIsIntrinsic(p,logicalId);const repUp=new ObjectParser(p);return repUp.parseCase("willReplace",x=>x),repUp.toResult()}function parseAutoScalingRollingUpdate(p){if(typeof p!="object")return new FromCloudFormationResult(void 0);self.throwIfIsIntrinsic(p,logicalId);const rollUp=new ObjectParser(p);return rollUp.parseCase("maxBatchSize",FromCloudFormation.getNumber),rollUp.parseCase("minInstancesInService",FromCloudFormation.getNumber),rollUp.parseCase("minSuccessfulInstancesPercent",FromCloudFormation.getNumber),rollUp.parseCase("minActiveInstancesPercent",FromCloudFormation.getNumber),rollUp.parseCase("pauseTime",FromCloudFormation.getString),rollUp.parseCase("suspendProcesses",FromCloudFormation.getStringArray),rollUp.parseCase("waitOnResourceSignals",FromCloudFormation.getBoolean),rollUp.toResult()}function parseCodeDeployLambdaAliasUpdate(p){if(typeof p!="object")return new FromCloudFormationResult(void 0);self.throwIfIsIntrinsic(p,logicalId);const cdUp=new ObjectParser(p);return cdUp.parseCase("beforeAllowTrafficHook",FromCloudFormation.getString),cdUp.parseCase("afterAllowTrafficHook",FromCloudFormation.getString),cdUp.parseCase("applicationName",FromCloudFormation.getString),cdUp.parseCase("deploymentGroupName",FromCloudFormation.getString),cdUp.toResult()}function parseAutoScalingScheduledAction(p){if(typeof p!="object")return new FromCloudFormationResult(void 0);self.throwIfIsIntrinsic(p,logicalId);const schedUp=new ObjectParser(p);return schedUp.parseCase("ignoreUnmodifiedGroupSizeProperties",FromCloudFormation.getBoolean),schedUp.toResult()}}parseDeletionPolicy(policy){if(policy==null)return;const isIntrinsic=this.looksLikeCfnIntrinsic(policy);switch(policy){case"Delete":return cfn_resource_policy_1().CfnDeletionPolicy.DELETE;case"Retain":return cfn_resource_policy_1().CfnDeletionPolicy.RETAIN;case"Snapshot":return cfn_resource_policy_1().CfnDeletionPolicy.SNAPSHOT;case"RetainExceptOnCreate":return cfn_resource_policy_1().CfnDeletionPolicy.RETAIN_EXCEPT_ON_CREATE;default:if(isIntrinsic)return policy=this.parseValue(policy),policy;throw new(errors_1()).UnscopedValidationError(`Unrecognized DeletionPolicy '${policy}'`)}}parseValue(cfnValue){if(cfnValue!=null){if((0,token_1().isResolvableObject)(cfnValue))return cfnValue;if(Array.isArray(cfnValue))return cfnValue.map(el=>this.parseValue(el));if(typeof cfnValue=="object"){const cfnIntrinsic=this.parseIfCfnIntrinsic(cfnValue);if(cfnIntrinsic!==void 0)return cfnIntrinsic;const ret={};for(const[key,val]of Object.entries(cfnValue))ret[key]=this.parseValue(val);return ret}return cfnValue}}get finder(){return this.options.finder}parseIfCfnIntrinsic(object){const key=this.looksLikeCfnIntrinsic(object);switch(key){case void 0:return;case"Ref":{const refTarget=object[key],specialRef=this.specialCaseRefs(refTarget);if(specialRef!==void 0)return specialRef;{const refElement=this.finder.findRefTarget(refTarget);if(!refElement)throw new(errors_1()).UnscopedValidationError(`Element used in Ref expression with logical ID: '${refTarget}' not found`);return cfn_reference_1().CfnReference.for(refElement,"Ref")}}case"Fn::GetAtt":{const value=object[key];let logicalId,attributeName,stringForm;if(typeof value=="string"){const dotIndex=value.indexOf(".");if(dotIndex===-1)throw new(errors_1()).UnscopedValidationError(`Short-form Fn::GetAtt must contain a '.' in its string argument, got: '${value}'`);logicalId=value.slice(0,dotIndex),attributeName=value.slice(dotIndex+1),stringForm=!0}else logicalId=value[0],attributeName=value[1],stringForm=!1;const target=this.finder.findResource(logicalId);if(!target)throw new(errors_1()).UnscopedValidationError(`Resource used in GetAtt expression with logical ID: '${logicalId}' not found`);return cfn_reference_1().CfnReference.for(target,attributeName,stringForm?cfn_reference_1().ReferenceRendering.GET_ATT_STRING:void 0)}case"Fn::Join":{const value=this.parseValue(object[key]);return cfn_fn_1().Fn.join(value[0],lazy_1().Lazy.list({produce:()=>value[1]}))}case"Fn::Cidr":{const value=this.parseValue(object[key]);return cfn_fn_1().Fn.cidr(value[0],value[1],value[2])}case"Fn::FindInMap":{const value=this.parseValue(object[key]);let mappingName;if(token_1().Token.isUnresolved(value[0]))mappingName=value[0];else{const mapping=this.finder.findMapping(value[0]);if(!mapping)throw new(errors_1()).UnscopedValidationError(`Mapping used in FindInMap expression with name '${value[0]}' was not found in the template`);mappingName=mapping.logicalId}return cfn_fn_1().Fn._findInMap(mappingName,value[1],value[2])}case"Fn::Select":{const value=this.parseValue(object[key]);return cfn_fn_1().Fn.select(value[0],value[1])}case"Fn::GetAZs":{const value=this.parseValue(object[key]);return cfn_fn_1().Fn.getAzs(value)}case"Fn::ImportValue":{const value=this.parseValue(object[key]);return cfn_fn_1().Fn.importValue(value)}case"Fn::Split":{const value=this.parseValue(object[key]);return cfn_fn_1().Fn.split(value[0],value[1])}case"Fn::Transform":{const value=this.parseValue(object[key]);return cfn_fn_1().Fn.transform(value.Name,value.Parameters)}case"Fn::Base64":{const value=this.parseValue(object[key]);return cfn_fn_1().Fn.base64(value)}case"Fn::If":{const value=this.parseValue(object[key]),condition=this.finder.findCondition(value[0]);if(!condition)throw new(errors_1()).UnscopedValidationError(`Condition '${value[0]}' used in an Fn::If expression does not exist in the template`);return cfn_fn_1().Fn.conditionIf(condition.logicalId,value[1],value[2])}case"Fn::Equals":{const value=this.parseValue(object[key]);return cfn_fn_1().Fn.conditionEquals(value[0],value[1])}case"Fn::And":{const value=this.parseValue(object[key]);return cfn_fn_1().Fn.conditionAnd(...value)}case"Fn::Not":{const value=this.parseValue(object[key]);return cfn_fn_1().Fn.conditionNot(value[0])}case"Fn::Or":{const value=this.parseValue(object[key]);return cfn_fn_1().Fn.conditionOr(...value)}case"Fn::Sub":{const value=this.parseValue(object[key]);let fnSubString,map;return typeof value=="string"?(fnSubString=value,map=void 0):(fnSubString=value[0],map=value[1]),this.parseFnSubString(fnSubString,map)}case"Condition":{const condition=this.finder.findCondition(object[key]);if(!condition)throw new(errors_1()).UnscopedValidationError(`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);throw new(errors_1()).UnscopedValidationError(`Unsupported CloudFormation function '${key}'`)}}throwIfIsIntrinsic(object,logicalId){if(!this.stack)throw new(errors_1()).UnscopedValidationError("cannot call this method before handleAttributes!");if(feature_flags_1().FeatureFlags.of(this.stack).isEnabled(cx_api_1().CFN_INCLUDE_REJECT_COMPLEX_RESOURCE_UPDATE_CREATE_POLICY_INTRINSICS)&&((0,token_1().isResolvableObject)(object??{})||this.looksLikeCfnIntrinsic(object??{})))throw new(errors_1()).UnscopedValidationError(`Cannot convert resource '${logicalId}' to CDK objects: it uses an intrinsic in a resource update or deletion policy to represent a non-primitive value. Specify '${logicalId}' in the 'dehydratedResources' prop to skip parsing this resource, while still including it in the output.`)}looksLikeCfnIntrinsic(object){const objectKeys=Object.keys(object);if(objectKeys.length!==1)return;const key=objectKeys[0];return key==="Ref"||key.startsWith("Fn::")||this.options.context===CfnParsingContext.CONDITIONS&&key==="Condition"?key:void 0}parseFnSubString(templateString,expressionMap){const map=expressionMap??{},self=this;return cfn_fn_1().Fn.sub(go(templateString),Object.keys(map).length===0?expressionMap:map);function go(value){const leftBrace=value.indexOf("${");if(leftBrace===-1)return value;const rightBrace=value.indexOf("}",leftBrace);if(rightBrace===-1)return value;const leftHalf=value.substring(0,leftBrace),rightHalf=value.substring(rightBrace+1),refTarget=value.substring(leftBrace+2,rightBrace).trim();if(refTarget[0]==="!")return value.substring(0,rightBrace+1)+go(rightHalf);if(refTarget in map)return leftHalf+"${"+refTarget+"}"+go(rightHalf);const specialRef=self.specialCaseSubRefs(refTarget);if(specialRef!==void 0)return token_1().Token.isUnresolved(specialRef)?(map[refTarget]=specialRef,leftHalf+"${"+refTarget+"}"+go(rightHalf)):leftHalf+specialRef+go(rightHalf);const dotIndex=refTarget.indexOf(".");if(dotIndex===-1){const refElement=self.finder.findRefTarget(refTarget);if(!refElement)throw new(errors_1()).UnscopedValidationError(`Element referenced in Fn::Sub expression with logical ID: '${refTarget}' was not found in the template`);return leftHalf+cfn_reference_1().CfnReference.for(refElement,"Ref",cfn_reference_1().ReferenceRendering.FN_SUB).toString()+go(rightHalf)}else{const targetId=refTarget.substring(0,dotIndex),refResource=self.finder.findResource(targetId);if(!refResource)throw new(errors_1()).UnscopedValidationError(`Resource referenced in Fn::Sub expression with logical ID: '${targetId}' was not found in the template`);const attribute=refTarget.substring(dotIndex+1);return leftHalf+cfn_reference_1().CfnReference.for(refResource,attribute,cfn_reference_1().ReferenceRendering.FN_SUB).toString()+go(rightHalf)}}}handleRulesIntrinsic(key,object){switch(key){case"Fn::ValueOf":{const value=this.parseValue(object[key]),parameterName=value[0];if(parameterName in this.parameters)throw new(errors_1()).UnscopedValidationError(`Cannot substitute parameter '${parameterName}' used in Fn::ValueOf expression with attribute '${value[1]}'`);const param=this.finder.findRefTarget(parameterName);if(!param)throw new(errors_1()).UnscopedValidationError(`Rule references parameter '${parameterName}' which was not found in the template`);return lazy_1().Lazy.any({produce:()=>({"Fn::ValueOf":[param.logicalId,value[1]]})})}default:return}}specialCaseRefs(value){if(value in this.parameters)return this.parameters[value];switch(value){case"AWS::AccountId":return cfn_pseudo_1().Aws.ACCOUNT_ID;case"AWS::Region":return cfn_pseudo_1().Aws.REGION;case"AWS::Partition":return cfn_pseudo_1().Aws.PARTITION;case"AWS::URLSuffix":return cfn_pseudo_1().Aws.URL_SUFFIX;case"AWS::NotificationARNs":return cfn_pseudo_1().Aws.NOTIFICATION_ARNS;case"AWS::StackId":return cfn_pseudo_1().Aws.STACK_ID;case"AWS::StackName":return cfn_pseudo_1().Aws.STACK_NAME;case"AWS::NoValue":return cfn_pseudo_1().Aws.NO_VALUE;default:return}}specialCaseSubRefs(value){return value in this.parameters?this.parameters[value]:value.indexOf("::")===-1?void 0:"${"+value+"}"}get parameters(){return this.options.parameters||{}}}exports.CfnParser=CfnParser;class ObjectParser{constructor(input){this.parsed={},this.unparsed={},this.unparsed={...input}}parseCase(targetKey,parser){const sourceKey=ucfirst(String(targetKey));this.parse(targetKey,sourceKey,parser)}parse(targetKey,sourceKey,parser){if(!(sourceKey in this.unparsed))return;const value=parser(this.unparsed[sourceKey]);if(delete this.unparsed[sourceKey],value instanceof FromCloudFormationResult){for(const[k,v]of Object.entries(value.extraProperties??{}))this.unparsed[`${sourceKey}.${k}`]=v;this.parsed[targetKey]=value.value}else this.parsed[targetKey]=value}toResult(){const ret=new FromCloudFormationResult((0,util_1().undefinedIfAllValuesAreEmpty)(this.parsed));for(const[k,v]of Object.entries(this.unparsedKeys))ret.extraProperties[k]=v;return ret}get unparsedKeys(){const unparsed={...this.unparsed};for(const[k,v]of Object.entries(this.unparsed))if(v instanceof FromCloudFormationResult)for(const[k2,v2]of Object.entries(v.extraProperties??{}))unparsed[`${k}.${k2}`]=v2;else unparsed[k]=v;return unparsed}}function ucfirst(x){return x.slice(0,1).toUpperCase()+x.slice(1)}