Skip to content

Commit 92a9a73

Browse files
authored
feat(cloudformation-include): throw ValidationError instead of untyped Errors (#33391)
### Issue Relates to #32569 ### Description of changes `ValidationErrors` everywhere ### Describe any new or updated permissions being added n/a ### Description of how you validated changes Existing tests. Exemptions granted as this is a refactor of existing code. ### Checklist - [x] My code adheres to the [CONTRIBUTING GUIDE](https://github.com/aws/aws-cdk/blob/main/CONTRIBUTING.md) and [DESIGN GUIDELINES](https://github.com/aws/aws-cdk/blob/main/docs/DESIGN_GUIDELINES.md) ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
1 parent ae95d95 commit 92a9a73

File tree

2 files changed

+37
-34
lines changed

2 files changed

+37
-34
lines changed

packages/aws-cdk-lib/.eslintrc.js

+1
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ const enableNoThrowDefaultErrorIn = [
4646
'aws-ssmincidents',
4747
'aws-ssmquicksetup',
4848
'aws-synthetics',
49+
'cloudformation-include',
4950
'aws-route53',
5051
'aws-route53-patterns',
5152
'aws-route53-targets',

packages/aws-cdk-lib/cloudformation-include/lib/cfn-include.ts

+36-34
Original file line numberDiff line numberDiff line change
@@ -140,14 +140,14 @@ export class CfnInclude extends core.CfnElement {
140140

141141
for (const logicalId of this.dehydratedResources) {
142142
if (!Object.keys(this.template.Resources).includes(logicalId)) {
143-
throw new Error(`Logical ID '${logicalId}' was specified in 'dehydratedResources', but does not belong to a resource in the template.`);
143+
throw new core.ValidationError(`Logical ID '${logicalId}' was specified in 'dehydratedResources', but does not belong to a resource in the template.`, this);
144144
}
145145
}
146146

147147
// check if all user specified parameter values exist in the template
148148
for (const logicalId of Object.keys(this.parametersToReplace)) {
149149
if (!(logicalId in (this.template.Parameters || {}))) {
150-
throw new Error(`Parameter with logical ID '${logicalId}' was not found in the template`);
150+
throw new core.ValidationError(`Parameter with logical ID '${logicalId}' was not found in the template`, this);
151151
}
152152
}
153153

@@ -182,7 +182,7 @@ export class CfnInclude extends core.CfnElement {
182182
// verify that all nestedStacks have been instantiated
183183
for (const nestedStackId of Object.keys(props.loadNestedStacks || {})) {
184184
if (!(nestedStackId in this.resources)) {
185-
throw new Error(`Nested Stack with logical ID '${nestedStackId}' was not found in the template`);
185+
throw new core.ValidationError(`Nested Stack with logical ID '${nestedStackId}' was not found in the template`, this);
186186
}
187187
}
188188

@@ -217,7 +217,7 @@ export class CfnInclude extends core.CfnElement {
217217
public getResource(logicalId: string): core.CfnResource {
218218
const ret = this.resources[logicalId];
219219
if (!ret) {
220-
throw new Error(`Resource with logical ID '${logicalId}' was not found in the template`);
220+
throw new core.ValidationError(`Resource with logical ID '${logicalId}' was not found in the template`, this);
221221
}
222222
return ret;
223223
}
@@ -235,7 +235,7 @@ export class CfnInclude extends core.CfnElement {
235235
public getCondition(conditionName: string): core.CfnCondition {
236236
const ret = this.conditions[conditionName];
237237
if (!ret) {
238-
throw new Error(`Condition with name '${conditionName}' was not found in the template`);
238+
throw new core.ValidationError(`Condition with name '${conditionName}' was not found in the template`, this);
239239
}
240240
return ret;
241241
}
@@ -253,7 +253,7 @@ export class CfnInclude extends core.CfnElement {
253253
public getParameter(parameterName: string): core.CfnParameter {
254254
const ret = this.parameters[parameterName];
255255
if (!ret) {
256-
throw new Error(`Parameter with name '${parameterName}' was not found in the template`);
256+
throw new core.ValidationError(`Parameter with name '${parameterName}' was not found in the template`, this);
257257
}
258258
return ret;
259259
}
@@ -270,7 +270,7 @@ export class CfnInclude extends core.CfnElement {
270270
public getMapping(mappingName: string): core.CfnMapping {
271271
const ret = this.mappings[mappingName];
272272
if (!ret) {
273-
throw new Error(`Mapping with name '${mappingName}' was not found in the template`);
273+
throw new core.ValidationError(`Mapping with name '${mappingName}' was not found in the template`, this);
274274
}
275275
return ret;
276276
}
@@ -288,7 +288,7 @@ export class CfnInclude extends core.CfnElement {
288288
public getOutput(logicalId: string): core.CfnOutput {
289289
const ret = this.outputs[logicalId];
290290
if (!ret) {
291-
throw new Error(`Output with logical ID '${logicalId}' was not found in the template`);
291+
throw new core.ValidationError(`Output with logical ID '${logicalId}' was not found in the template`, this);
292292
}
293293
return ret;
294294
}
@@ -306,7 +306,7 @@ export class CfnInclude extends core.CfnElement {
306306
public getRule(ruleName: string): core.CfnRule {
307307
const ret = this.rules[ruleName];
308308
if (!ret) {
309-
throw new Error(`Rule with name '${ruleName}' was not found in the template`);
309+
throw new core.ValidationError(`Rule with name '${ruleName}' was not found in the template`, this);
310310
}
311311
return ret;
312312
}
@@ -324,7 +324,7 @@ export class CfnInclude extends core.CfnElement {
324324
public getHook(hookLogicalId: string): core.CfnHook {
325325
const ret = this.hooks[hookLogicalId];
326326
if (!ret) {
327-
throw new Error(`Hook with logical ID '${hookLogicalId}' was not found in the template`);
327+
throw new core.ValidationError(`Hook with logical ID '${hookLogicalId}' was not found in the template`, this);
328328
}
329329
return ret;
330330
}
@@ -340,12 +340,12 @@ export class CfnInclude extends core.CfnElement {
340340
public getNestedStack(logicalId: string): IncludedNestedStack {
341341
if (!this.nestedStacks[logicalId]) {
342342
if (!this.template.Resources[logicalId]) {
343-
throw new Error(`Nested Stack with logical ID '${logicalId}' was not found in the template`);
343+
throw new core.ValidationError(`Nested Stack with logical ID '${logicalId}' was not found in the template`, this);
344344
} else if (this.template.Resources[logicalId].Type !== 'AWS::CloudFormation::Stack') {
345-
throw new Error(`Resource with logical ID '${logicalId}' is not a CloudFormation Stack`);
345+
throw new core.ValidationError(`Resource with logical ID '${logicalId}' is not a CloudFormation Stack`, this);
346346
} else {
347-
throw new Error(`Nested Stack '${logicalId}' was not included in the parent template. ` +
348-
'To retrieve an included nested stack, it must be specified either in the `loadNestedStacks` property, or through the `loadNestedStack` method');
347+
throw new core.ValidationError(`Nested Stack '${logicalId}' was not included in the parent template. ` +
348+
'To retrieve an included nested stack, it must be specified either in the `loadNestedStacks` property, or through the `loadNestedStack` method', this);
349349
}
350350
}
351351
return this.nestedStacks[logicalId];
@@ -364,11 +364,11 @@ export class CfnInclude extends core.CfnElement {
364364
*/
365365
public loadNestedStack(logicalId: string, nestedStackProps: CfnIncludeProps): IncludedNestedStack {
366366
if (logicalId in this.nestedStacks) {
367-
throw new Error(`Nested Stack '${logicalId}' was already included in its parent template`);
367+
throw new core.ValidationError(`Nested Stack '${logicalId}' was already included in its parent template`, this);
368368
}
369369
const cfnStack = this.resources[logicalId];
370370
if (!cfnStack) {
371-
throw new Error(`Nested Stack with logical ID '${logicalId}' was not found in the template`);
371+
throw new core.ValidationError(`Nested Stack with logical ID '${logicalId}' was not found in the template`, this);
372372
}
373373
if (cfnStack instanceof core.CfnStack) {
374374
// delete the old CfnStack child - one will be created by the NestedStack object
@@ -381,7 +381,7 @@ export class CfnInclude extends core.CfnElement {
381381
this.getOrCreateResource(logicalId);
382382
return this.nestedStacks[logicalId];
383383
} else {
384-
throw new Error(`Nested Stack with logical ID '${logicalId}' is not an AWS::CloudFormation::Stack resource`);
384+
throw new core.ValidationError(`Nested Stack with logical ID '${logicalId}' is not an AWS::CloudFormation::Stack resource`, this);
385385
}
386386
}
387387

@@ -429,12 +429,13 @@ export class CfnInclude extends core.CfnElement {
429429
}
430430

431431
private createMapping(mappingName: string): void {
432+
const self = this;
432433
const cfnParser = new cfn_parse.CfnParser({
433434
finder: {
434-
findCondition() { throw new Error('Referring to Conditions in Mapping definitions is not allowed'); },
435-
findMapping() { throw new Error('Referring to other Mappings in Mapping definitions is not allowed'); },
436-
findRefTarget() { throw new Error('Using Ref expressions in Mapping definitions is not allowed'); },
437-
findResource() { throw new Error('Using GetAtt expressions in Mapping definitions is not allowed'); },
435+
findCondition() { throw new core.ValidationError('Referring to Conditions in Mapping definitions is not allowed', self); },
436+
findMapping() { throw new core.ValidationError('Referring to other Mappings in Mapping definitions is not allowed', self); },
437+
findRefTarget() { throw new core.ValidationError('Using Ref expressions in Mapping definitions is not allowed', self); },
438+
findResource() { throw new core.ValidationError('Using GetAtt expressions in Mapping definitions is not allowed', self); },
438439
},
439440
parameters: {},
440441
});
@@ -450,12 +451,13 @@ export class CfnInclude extends core.CfnElement {
450451
return;
451452
}
452453

454+
const self = this;
453455
const expression = new cfn_parse.CfnParser({
454456
finder: {
455-
findResource() { throw new Error('Using GetAtt expressions in Parameter definitions is not allowed'); },
456-
findRefTarget() { throw new Error('Using Ref expressions in Parameter definitions is not allowed'); },
457-
findCondition() { throw new Error('Referring to Conditions in Parameter definitions is not allowed'); },
458-
findMapping() { throw new Error('Referring to Mappings in Parameter definitions is not allowed'); },
457+
findResource() { throw new core.ValidationError('Using GetAtt expressions in Parameter definitions is not allowed', self); },
458+
findRefTarget() { throw new core.ValidationError('Using Ref expressions in Parameter definitions is not allowed', self); },
459+
findCondition() { throw new core.ValidationError('Referring to Conditions in Parameter definitions is not allowed', self); },
460+
findMapping() { throw new core.ValidationError('Referring to Mappings in Parameter definitions is not allowed', self); },
459461
},
460462
parameters: {},
461463
}).parseValue(this.template.Parameters[logicalId]);
@@ -485,7 +487,7 @@ export class CfnInclude extends core.CfnElement {
485487
// only parameters can be referenced in Rules
486488
return self.parameters[refTarget];
487489
},
488-
findResource() { throw new Error('Using GetAtt expressions in Rule definitions is not allowed'); },
490+
findResource() { throw new core.ValidationError('Using GetAtt expressions in Rule definitions is not allowed', self); },
489491
findCondition(conditionName: string): core.CfnCondition | undefined {
490492
return self.conditions[conditionName];
491493
},
@@ -575,8 +577,8 @@ export class CfnInclude extends core.CfnElement {
575577
return self.getCondition(outputAttributes.Condition);
576578
}
577579

578-
throw new Error(`Output with name '${logicalId}' refers to a Condition with name ` +
579-
`'${outputAttributes.Condition}' which was not found in this template`);
580+
throw new core.ValidationError(`Output with name '${logicalId}' refers to a Condition with name ` +
581+
`'${outputAttributes.Condition}' which was not found in this template`, this);
580582
})(),
581583
});
582584

@@ -592,7 +594,7 @@ export class CfnInclude extends core.CfnElement {
592594
const self = this;
593595
const cfnParser = new cfn_parse.CfnParser({
594596
finder: {
595-
findResource() { throw new Error('Using GetAtt in Condition definitions is not allowed'); },
597+
findResource() { throw new core.ValidationError('Using GetAtt in Condition definitions is not allowed', self); },
596598
findRefTarget(elementName: string): core.CfnElement | undefined {
597599
// only Parameters can be referenced in the 'Conditions' section
598600
return self.parameters[elementName];
@@ -626,7 +628,7 @@ export class CfnInclude extends core.CfnElement {
626628
cycleChain = cycleChain.concat([logicalId]);
627629
if (cycleChain.length !== new Set(cycleChain).size) {
628630
if (!this.allowCyclicalReferences) {
629-
throw new Error(`Found a cycle between resources in the template: ${cycleChain.join(' depends on ')}`);
631+
throw new core.ValidationError(`Found a cycle between resources in the template: ${cycleChain.join(' depends on ')}`, this);
630632
}
631633
// only allow one placeholder per logical id
632634
if (this.logicalIdToPlaceholderMap.get(logicalId)) {
@@ -683,7 +685,7 @@ export class CfnInclude extends core.CfnElement {
683685
const resourceAttributes: any = this.template.Resources[logicalId];
684686
let l1Instance: core.CfnResource;
685687
if (this.nestedStacksToInclude[logicalId] && this.dehydratedResources.includes(logicalId)) {
686-
throw new Error(`nested stack '${logicalId}' was marked as dehydrated - nested stacks cannot be dehydrated`);
688+
throw new core.ValidationError(`nested stack '${logicalId}' was marked as dehydrated - nested stacks cannot be dehydrated`, this);
687689
} else if (this.nestedStacksToInclude[logicalId]) {
688690
l1Instance = this.createNestedStack(logicalId, cfnParser);
689691
} else if (this.dehydratedResources.includes(logicalId)) {
@@ -758,13 +760,13 @@ export class CfnInclude extends core.CfnElement {
758760
const nestedStackAttributes = templateResources[nestedStackId] || {};
759761

760762
if (nestedStackAttributes.Type !== 'AWS::CloudFormation::Stack') {
761-
throw new Error(`Nested Stack with logical ID '${nestedStackId}' is not an AWS::CloudFormation::Stack resource`);
763+
throw new core.ValidationError(`Nested Stack with logical ID '${nestedStackId}' is not an AWS::CloudFormation::Stack resource`, this);
762764
}
763765
if (nestedStackAttributes.CreationPolicy) {
764-
throw new Error('CreationPolicy is not supported by the AWS::CloudFormation::Stack resource');
766+
throw new core.ValidationError('CreationPolicy is not supported by the AWS::CloudFormation::Stack resource', this);
765767
}
766768
if (nestedStackAttributes.UpdatePolicy) {
767-
throw new Error('UpdatePolicy is not supported by the AWS::CloudFormation::Stack resource');
769+
throw new core.ValidationError('UpdatePolicy is not supported by the AWS::CloudFormation::Stack resource', this);
768770
}
769771

770772
const nestedStackProps = cfnParser.parseValue(nestedStackAttributes.Properties);

0 commit comments

Comments
 (0)