@aws-cdk/core
Version:
AWS Cloud Development Kit Core Library
698 lines • 103 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.CfnParser = exports.CfnParsingContext = exports.FromCloudFormation = exports.FromCloudFormationPropertyObject = exports.FromCloudFormationResult = void 0;
const cfn_fn_1 = require("../cfn-fn");
const cfn_pseudo_1 = require("../cfn-pseudo");
const cfn_resource_policy_1 = require("../cfn-resource-policy");
const lazy_1 = require("../lazy");
const cfn_reference_1 = require("../private/cfn-reference");
const token_1 = require("../token");
const util_1 = require("../util");
/**
* The class used as the intermediate result from the generated L1 methods
* that convert from CloudFormation's UpperCase to CDK's lowerCase property names.
* Saves any extra properties that were present in the argument object,
* but that were not found in the CFN schema,
* so that they're not lost from the final CDK-rendered template.
*/
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;
/**
* A property object we will accumulate properties into
*/
class FromCloudFormationPropertyObject extends FromCloudFormationResult {
constructor() {
super({}); // We're still accumulating
this.recognizedProperties = new Set();
}
/**
* Add a parse result under a given key
*/
addPropertyResult(cdkPropName, cfnPropName, result) {
this.recognizedProperties.add(cfnPropName);
if (!result) {
return;
}
this.value[cdkPropName] = result.value;
this.appendExtraProperties(cfnPropName, result.extraProperties);
}
addUnrecognizedPropertiesAsExtra(properties) {
for (const [key, val] of Object.entries(properties)) {
if (!this.recognizedProperties.has(key)) {
this.extraProperties[key] = val;
}
}
}
}
exports.FromCloudFormationPropertyObject = FromCloudFormationPropertyObject;
/**
* This class contains static methods called when going from
* translated values received from {@link CfnParser.parseValue}
* to the actual L1 properties -
* things like changing IResolvable to the appropriate type
* (string, string array, or number), etc.
*
* While this file not exported from the module
* (to not make it part of the public API),
* it is directly referenced in the generated L1 code.
*
*/
class FromCloudFormation {
// nothing to for any but return it
static getAny(value) {
return new FromCloudFormationResult(value);
}
static getBoolean(value) {
if (typeof value === 'string') {
// CloudFormation allows passing strings as boolean
switch (value) {
case 'true': return new FromCloudFormationResult(true);
case 'false': return new FromCloudFormationResult(false);
default: throw new Error(`Expected 'true' or 'false' for boolean value, got: '${value}'`);
}
}
// in all other cases, just return the value,
// and let a validator handle if it's not a boolean
return new FromCloudFormationResult(value);
}
static getDate(value) {
// if the date is a deploy-time value, just return it
if (token_1.isResolvableObject(value)) {
return new FromCloudFormationResult(value);
}
// if the date has been given as a string, convert it
if (typeof value === 'string') {
return new FromCloudFormationResult(new Date(value));
}
// all other cases - just return the value,
// if it's not a Date, a validator should catch it
return new FromCloudFormationResult(value);
}
// won't always return a string; if the input can't be resolved to a string,
// the input will be returned.
static getString(value) {
// if the string is a deploy-time value, serialize it to a Token
if (token_1.isResolvableObject(value)) {
return new FromCloudFormationResult(value.toString());
}
// CloudFormation treats numbers and strings interchangeably;
// so, if we get a number here, convert it to a string
if (typeof value === 'number') {
return new FromCloudFormationResult(value.toString());
}
// CloudFormation treats booleans and strings interchangeably;
// so, if we get a boolean here, convert it to a string
if (typeof value === 'boolean') {
return new FromCloudFormationResult(value.toString());
}
// in all other cases, just return the input,
// and let a validator handle it if it's not a string
return new FromCloudFormationResult(value);
}
// won't always return a number; if the input can't be parsed to a number,
// the input will be returned.
static getNumber(value) {
// if the string is a deploy-time value, serialize it to a Token
if (token_1.isResolvableObject(value)) {
return new FromCloudFormationResult(token_1.Token.asNumber(value));
}
// return a number, if the input can be parsed as one
if (typeof value === 'string') {
const parsedValue = parseFloat(value);
if (!isNaN(parsedValue)) {
return new FromCloudFormationResult(parsedValue);
}
}
// otherwise return the input,
// and let a validator handle it if it's not a number
return new FromCloudFormationResult(value);
}
static getStringArray(value) {
// if the array is a deploy-time value, serialize it to a Token
if (token_1.isResolvableObject(value)) {
return new FromCloudFormationResult(token_1.Token.asList(value));
}
// in all other cases, delegate to the standard mapping logic
return this.getArray(this.getString)(value);
}
static getArray(mapper) {
return (value) => {
if (!Array.isArray(value)) {
// break the type system, and just return the given value,
// which hopefully will be reported as invalid by the validator
// of the property we're transforming
// (unless it's a deploy-time value,
// which we can't map over at build time anyway)
return new FromCloudFormationResult(value);
}
const values = new Array();
const 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') {
// if the input is not a map (= object in JS land),
// just return it, and let the validator of this property handle it
// (unless it's a deploy-time value,
// which we can't map over at build time anyway)
return new FromCloudFormationResult(value);
}
const values = {};
const 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 tag == null
? new FromCloudFormationResult({}) // break the type system - this should be detected at runtime by a tag validator
: new FromCloudFormationResult({
key: tag.Key,
value: tag.Value,
});
}
/**
* Return a function that, when applied to a value, will return the first validly deserialized one
*/
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;
}
}
// if nothing matches, just return the input unchanged, and let validators catch it
return new FromCloudFormationResult(value);
};
}
}
exports.FromCloudFormation = FromCloudFormation;
/**
* The context in which the parsing is taking place.
*
* Some fragments of CloudFormation templates behave differently than others
* (for example, the 'Conditions' sections treats { "Condition": "NameOfCond" }
* differently than the 'Resources' section).
* This enum can be used to change the created {@link CfnParser} behavior,
* based on the template context.
*/
var CfnParsingContext;
(function (CfnParsingContext) {
/** We're currently parsing the 'Conditions' section. */
CfnParsingContext[CfnParsingContext["CONDITIONS"] = 0] = "CONDITIONS";
/** We're currently parsing the 'Rules' section. */
CfnParsingContext[CfnParsingContext["RULES"] = 1] = "RULES";
})(CfnParsingContext = exports.CfnParsingContext || (exports.CfnParsingContext = {}));
/**
* This class contains methods for translating from a pure CFN value
* (like a JS object { "Ref": "Bucket" })
* to a form CDK understands
* (like Fn.ref('Bucket')).
*
* While this file not exported from the module
* (to not make it part of the public API),
* it is directly referenced in the generated L1 code,
* so any renames of it need to be reflected in cfn2ts/codegen.ts as well.
*
*/
class CfnParser {
constructor(options) {
this.options = options;
}
handleAttributes(resource, resourceAttributes, logicalId) {
const cfnOptions = resource.cfnOptions;
cfnOptions.creationPolicy = this.parseCreationPolicy(resourceAttributes.CreationPolicy);
cfnOptions.updatePolicy = this.parseUpdatePolicy(resourceAttributes.UpdatePolicy);
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);
// handle Condition
if (resourceAttributes.Condition) {
const condition = this.finder.findCondition(resourceAttributes.Condition);
if (!condition) {
throw new Error(`Resource '${logicalId}' uses Condition '${resourceAttributes.Condition}' that doesn't exist`);
}
cfnOptions.condition = condition;
}
// handle DependsOn
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 Error(`Resource '${logicalId}' depends on '${dep}' that doesn't exist`);
}
resource.node.addDependency(depResource);
}
}
parseCreationPolicy(policy) {
if (typeof policy !== 'object') {
return undefined;
}
// change simple JS values to their CDK equivalents
policy = this.parseValue(policy);
return util_1.undefinedIfAllValuesAreEmpty({
autoScalingCreationPolicy: parseAutoScalingCreationPolicy(policy.AutoScalingCreationPolicy),
resourceSignal: parseResourceSignal(policy.ResourceSignal),
});
function parseAutoScalingCreationPolicy(p) {
if (typeof p !== 'object') {
return undefined;
}
return util_1.undefinedIfAllValuesAreEmpty({
minSuccessfulInstancesPercent: FromCloudFormation.getNumber(p.MinSuccessfulInstancesPercent).value,
});
}
function parseResourceSignal(p) {
if (typeof p !== 'object') {
return undefined;
}
return util_1.undefinedIfAllValuesAreEmpty({
count: FromCloudFormation.getNumber(p.Count).value,
timeout: FromCloudFormation.getString(p.Timeout).value,
});
}
}
parseUpdatePolicy(policy) {
if (typeof policy !== 'object') {
return undefined;
}
// change simple JS values to their CDK equivalents
policy = this.parseValue(policy);
return util_1.undefinedIfAllValuesAreEmpty({
autoScalingReplacingUpdate: parseAutoScalingReplacingUpdate(policy.AutoScalingReplacingUpdate),
autoScalingRollingUpdate: parseAutoScalingRollingUpdate(policy.AutoScalingRollingUpdate),
autoScalingScheduledAction: parseAutoScalingScheduledAction(policy.AutoScalingScheduledAction),
codeDeployLambdaAliasUpdate: parseCodeDeployLambdaAliasUpdate(policy.CodeDeployLambdaAliasUpdate),
enableVersionUpgrade: FromCloudFormation.getBoolean(policy.EnableVersionUpgrade).value,
useOnlineResharding: FromCloudFormation.getBoolean(policy.UseOnlineResharding).value,
});
function parseAutoScalingReplacingUpdate(p) {
if (typeof p !== 'object') {
return undefined;
}
return util_1.undefinedIfAllValuesAreEmpty({
willReplace: p.WillReplace,
});
}
function parseAutoScalingRollingUpdate(p) {
if (typeof p !== 'object') {
return undefined;
}
return util_1.undefinedIfAllValuesAreEmpty({
maxBatchSize: FromCloudFormation.getNumber(p.MaxBatchSize).value,
minInstancesInService: FromCloudFormation.getNumber(p.MinInstancesInService).value,
minSuccessfulInstancesPercent: FromCloudFormation.getNumber(p.MinSuccessfulInstancesPercent).value,
pauseTime: FromCloudFormation.getString(p.PauseTime).value,
suspendProcesses: FromCloudFormation.getStringArray(p.SuspendProcesses).value,
waitOnResourceSignals: FromCloudFormation.getBoolean(p.WaitOnResourceSignals).value,
});
}
function parseCodeDeployLambdaAliasUpdate(p) {
if (typeof p !== 'object') {
return undefined;
}
return {
beforeAllowTrafficHook: FromCloudFormation.getString(p.BeforeAllowTrafficHook).value,
afterAllowTrafficHook: FromCloudFormation.getString(p.AfterAllowTrafficHook).value,
applicationName: FromCloudFormation.getString(p.ApplicationName).value,
deploymentGroupName: FromCloudFormation.getString(p.DeploymentGroupName).value,
};
}
function parseAutoScalingScheduledAction(p) {
if (typeof p !== 'object') {
return undefined;
}
return util_1.undefinedIfAllValuesAreEmpty({
ignoreUnmodifiedGroupSizeProperties: FromCloudFormation.getBoolean(p.IgnoreUnmodifiedGroupSizeProperties).value,
});
}
}
parseDeletionPolicy(policy) {
switch (policy) {
case null: return undefined;
case undefined: return undefined;
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;
default: throw new Error(`Unrecognized DeletionPolicy '${policy}'`);
}
}
parseValue(cfnValue) {
// == null captures undefined as well
if (cfnValue == null) {
return undefined;
}
// if we have any late-bound values,
// just return them
if (token_1.isResolvableObject(cfnValue)) {
return cfnValue;
}
if (Array.isArray(cfnValue)) {
return cfnValue.map(el => this.parseValue(el));
}
if (typeof cfnValue === 'object') {
// an object can be either a CFN intrinsic, or an actual object
const cfnIntrinsic = this.parseIfCfnIntrinsic(cfnValue);
if (cfnIntrinsic !== undefined) {
return cfnIntrinsic;
}
const ret = {};
for (const [key, val] of Object.entries(cfnValue)) {
ret[key] = this.parseValue(val);
}
return ret;
}
// in all other cases, just return the input
return cfnValue;
}
get finder() {
return this.options.finder;
}
parseIfCfnIntrinsic(object) {
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 cfn_reference_1.CfnReference.for(refElement, 'Ref');
}
}
case 'Fn::GetAtt': {
const value = object[key];
let logicalId, attributeName, stringForm;
// 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 cfn_reference_1.CfnReference.for(target, attributeName, stringForm ? cfn_reference_1.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 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]);
// the first argument to FindInMap is the mapping name
let mappingName;
if (token_1.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 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': {
// 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 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;
let map;
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}'`);
}
}
}
looksLikeCfnIntrinsic(object) {
const objectKeys = Object.keys(object);
// a CFN intrinsic is always an object with a single key
if (objectKeys.length !== 1) {
return undefined;
}
const key = objectKeys[0];
return key === 'Ref' || key.startsWith('Fn::') ||
// special intrinsic only available in the 'Conditions' section
(this.options.context === CfnParsingContext.CONDITIONS && key === 'Condition')
? key
: undefined;
}
parseFnSubString(templateString, expressionMap) {
const map = expressionMap ?? {};
const 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;
}
// search for the closing brace to the right of the opening '${'
// (in theory, there could be other braces in the string,
// for example if it represents a JSON object)
const rightBrace = value.indexOf('}', leftBrace);
if (rightBrace === -1) {
return value;
}
const leftHalf = value.substring(0, leftBrace);
const rightHalf = value.substring(rightBrace + 1);
// don't include left and right braces when searching for the target of the reference
const refTarget = value.substring(leftBrace + 2, rightBrace).trim();
if (refTarget[0] === '!') {
return value.substring(0, rightBrace + 1) + go(rightHalf);
}
// lookup in map
if (refTarget in map) {
return leftHalf + '${' + refTarget + '}' + go(rightHalf);
}
// since it's not in the map, check if it's a pseudo-parameter
// (or a value to be substituted for a Parameter, provided by the customer)
const specialRef = self.specialCaseSubRefs(refTarget);
if (specialRef !== undefined) {
if (token_1.Token.isUnresolved(specialRef)) {
// specialRef can only be a Token if the value passed by the customer
// for substituting a Parameter was a Token.
// This is actually bad here,
// because the Token can potentially be something that doesn't render
// well inside an Fn::Sub template string, like a { Ref } object.
// To handle this case,
// instead of substituting the Parameter directly with the token in the template string,
// add a new entry to the Fn::Sub map,
// with key refTarget, and the token as the value.
// This is safe, because this sort of shadowing is legal in CloudFormation,
// and also because we're certain the Fn::Sub map doesn't contain an entry for refTarget
// (as we check that condition in the code right above this).
map[refTarget] = specialRef;
return leftHalf + '${' + refTarget + '}' + go(rightHalf);
}
else {
return leftHalf + specialRef + go(rightHalf);
}
}
const dotIndex = refTarget.indexOf('.');
const isRef = dotIndex === -1;
if (isRef) {
const refElement = self.finder.findRefTarget(refTarget);
if (!refElement) {
throw new Error(`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);
const refResource = self.finder.findResource(targetId);
if (!refResource) {
throw new Error(`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) {
// Rules have their own set of intrinsics:
// https://docs.aws.amazon.com/servicecatalog/latest/adminguide/intrinsic-function-reference-rules.html
switch (key) {
case 'Fn::ValueOf': {
// ValueOf is special,
// as it takes the name of a Parameter as its first argument
const value = this.parseValue(object[key]);
const parameterName = value[0];
if (parameterName in this.parameters) {
// since ValueOf returns the value of a specific attribute,
// fail here - this substitution is not allowed
throw new Error(`Cannot substitute parameter '${parameterName}' used in Fn::ValueOf expression with attribute '${value[1]}'`);
}
const param = this.finder.findRefTarget(parameterName);
if (!param) {
throw new Error(`Rule references parameter '${parameterName}' which was not found in the template`);
}
// create an explicit IResolvable,
// as Fn.valueOf() returns a string,
// which is incorrect
// (Fn::ValueOf can also return an array)
return lazy_1.Lazy.any({ produce: () => ({ 'Fn::ValueOf': [param.logicalId, value[1]] }) });
}
default:
// I don't want to hard-code the list of supported Rules-specific intrinsics in this function;
// so, just return undefined here,
// and they will be treated as a regular JSON object
return undefined;
}
}
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 undefined;
}
}
specialCaseSubRefs(value) {
if (value in this.parameters) {
return this.parameters[value];
}
return value.indexOf('::') === -1 ? undefined : '${' + value + '}';
}
get parameters() {
return this.options.parameters || {};
}
}
exports.CfnParser = CfnParser;
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2ZuLXBhcnNlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiY2ZuLXBhcnNlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQUVBLHNDQUErQjtBQUUvQiw4Q0FBb0M7QUFFcEMsZ0VBR2dDO0FBRWhDLGtDQUErQjtBQUMvQiw0REFBNEU7QUFHNUUsb0NBQXFEO0FBQ3JELGtDQUF1RDtBQUV2RDs7Ozs7O0dBTUc7QUFDSCxNQUFhLHdCQUF3QjtJQUluQyxZQUFtQixLQUFRO1FBQ3pCLElBQUksQ0FBQyxLQUFLLEdBQUcsS0FBSyxDQUFDO1FBQ25CLElBQUksQ0FBQyxlQUFlLEdBQUcsRUFBRSxDQUFDO0tBQzNCO0lBRU0scUJBQXFCLENBQUMsTUFBYyxFQUFFLFVBQThDO1FBQ3pGLEtBQUssTUFBTSxDQUFDLEdBQUcsRUFBRSxHQUFHLENBQUMsSUFBSSxNQUFNLENBQUMsT0FBTyxDQUFDLFVBQVUsSUFBSSxFQUFFLENBQUMsRUFBRTtZQUN6RCxJQUFJLENBQUMsZUFBZSxDQUFDLEdBQUcsTUFBTSxJQUFJLEdBQUcsRUFBRSxDQUFDLEdBQUcsR0FBRyxDQUFDO1NBQ2hEO0tBQ0Y7Q0FDRjtBQWRELDREQWNDO0FBRUQ7O0dBRUc7QUFDSCxNQUFhLGdDQUFnRSxTQUFRLHdCQUEyQjtJQUc5RztRQUNFLEtBQUssQ0FBQyxFQUFTLENBQUMsQ0FBQyxDQUFDLDJCQUEyQjtRQUg5Qix5QkFBb0IsR0FBRyxJQUFJLEdBQUcsRUFBVSxDQUFDO0tBSXpEO0lBRUQ7O09BRUc7SUFDSSxpQkFBaUIsQ0FBQyxXQUFvQixFQUFFLFdBQW1CLEVBQUUsTUFBc0M7UUFDeEcsSUFBSSxDQUFDLG9CQUFvQixDQUFDLEdBQUcsQ0FBQyxXQUFXLENBQUMsQ0FBQztRQUMzQyxJQUFJLENBQUMsTUFBTSxFQUFFO1lBQUUsT0FBTztTQUFFO1FBQ3hCLElBQUksQ0FBQyxLQUFLLENBQUMsV0FBVyxDQUFDLEdBQUcsTUFBTSxDQUFDLEtBQUssQ0FBQztRQUN2QyxJQUFJLENB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