Skip to content

Commit 2ecf14a

Browse files
authored
feat(location): throw ValidationError instead of untyped errors (#34174)
### Issue # (if applicable) `aws-location-alpha` for #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 basically 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 d9c249f commit 2ecf14a

File tree

6 files changed

+63
-57
lines changed

6 files changed

+63
-57
lines changed

packages/@aws-cdk/aws-location-alpha/.eslintrc.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,12 @@ baseConfig.parserOptions.project = __dirname + '/tsconfig.json';
44
baseConfig.rules['import/no-extraneous-dependencies'] = ['error', { devDependencies: true, peerDependencies: true } ];
55
baseConfig.rules['import/order'] = 'off';
66
baseConfig.rules['@aws-cdk/invalid-cfn-imports'] = 'off';
7+
baseConfig.rules['@cdklabs/no-throw-default-error'] = ['error'];
8+
baseConfig.overrides.push({
9+
files: ["./test/**"],
10+
rules: {
11+
"@cdklabs/no-throw-default-error": "off",
12+
},
13+
});
714

815
module.exports = baseConfig;

packages/@aws-cdk/aws-location-alpha/lib/geofence-collection.ts

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import * as iam from 'aws-cdk-lib/aws-iam';
22
import * as kms from 'aws-cdk-lib/aws-kms';
3-
import { ArnFormat, IResource, Lazy, Resource, Stack, Token } from 'aws-cdk-lib/core';
3+
import { ArnFormat, IResource, Lazy, Resource, Stack, Token, UnscopedValidationError, ValidationError } from 'aws-cdk-lib/core';
44
import { Construct } from 'constructs';
55
import { CfnGeofenceCollection } from 'aws-cdk-lib/aws-location';
66
import { generateUniqueId } from './util';
@@ -81,7 +81,7 @@ export class GeofenceCollection extends Resource implements IGeofenceCollection
8181
const parsedArn = Stack.of(scope).splitArn(geofenceCollectionArn, ArnFormat.SLASH_RESOURCE_NAME);
8282

8383
if (!parsedArn.resourceName) {
84-
throw new Error(`Geofence Collection Arn ${geofenceCollectionArn} does not have a resource name.`);
84+
throw new UnscopedValidationError(`Geofence Collection Arn ${geofenceCollectionArn} does not have a resource name.`);
8585
}
8686

8787
class Import extends Resource implements IGeofenceCollection {
@@ -114,26 +114,25 @@ export class GeofenceCollection extends Resource implements IGeofenceCollection
114114
public readonly geofenceCollectionUpdateTime: string;
115115

116116
constructor(scope: Construct, id: string, props: GeofenceCollectionProps = {}) {
117+
super(scope, id, {
118+
physicalName: props.geofenceCollectionName ?? Lazy.string({ produce: () => generateUniqueId(this) }),
119+
});
120+
// Enhanced CDK Analytics Telemetry
121+
addConstructMetadata(this, props);
122+
117123
if (props.description && !Token.isUnresolved(props.description) && props.description.length > 1000) {
118-
throw new Error(`\`description\` must be between 0 and 1000 characters. Received: ${props.description.length} characters`);
124+
throw new ValidationError(`\`description\` must be between 0 and 1000 characters. Received: ${props.description.length} characters`, this);
119125
}
120126

121127
if (props.geofenceCollectionName !== undefined && !Token.isUnresolved(props.geofenceCollectionName)) {
122128
if (props.geofenceCollectionName.length < 1 || props.geofenceCollectionName.length > 100) {
123-
throw new Error(`\`geofenceCollectionName\` must be between 1 and 100 characters, got: ${props.geofenceCollectionName.length} characters.`);
129+
throw new ValidationError(`\`geofenceCollectionName\` must be between 1 and 100 characters, got: ${props.geofenceCollectionName.length} characters.`, this);
124130
}
125131

126132
if (!/^[-._\w]+$/.test(props.geofenceCollectionName)) {
127-
throw new Error(`\`geofenceCollectionName\` must contain only alphanumeric characters, hyphens, periods and underscores, got: ${props.geofenceCollectionName}.`);
133+
throw new ValidationError(`\`geofenceCollectionName\` must contain only alphanumeric characters, hyphens, periods and underscores, got: ${props.geofenceCollectionName}.`, this);
128134
}
129135
}
130-
131-
super(scope, id, {
132-
physicalName: props.geofenceCollectionName ?? Lazy.string({ produce: () => generateUniqueId(this) }),
133-
});
134-
// Enhanced CDK Analytics Telemetry
135-
addConstructMetadata(this, props);
136-
137136
const geofenceCollection = new CfnGeofenceCollection(this, 'Resource', {
138137
collectionName: this.physicalName,
139138
description: props.description,

packages/@aws-cdk/aws-location-alpha/lib/map.ts

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import * as iam from 'aws-cdk-lib/aws-iam';
2-
import { ArnFormat, IResource, Lazy, Resource, Stack, Token } from 'aws-cdk-lib/core';
2+
import { ArnFormat, IResource, Lazy, Resource, Stack, Token, UnscopedValidationError, ValidationError } from 'aws-cdk-lib/core';
33
import { Construct } from 'constructs';
44
import { CfnMap } from 'aws-cdk-lib/aws-location';
55
import { generateUniqueId } from './util';
@@ -241,7 +241,7 @@ export class Map extends Resource implements IMap {
241241
const parsedArn = Stack.of(scope).splitArn(mapArn, ArnFormat.SLASH_RESOURCE_NAME);
242242

243243
if (!parsedArn.resourceName) {
244-
throw new Error(`Map Arn ${mapArn} does not have a resource name.`);
244+
throw new UnscopedValidationError(`Map Arn ${mapArn} does not have a resource name.`);
245245
}
246246

247247
class Import extends Resource implements IMap {
@@ -274,26 +274,26 @@ export class Map extends Resource implements IMap {
274274
public readonly mapUpdateTime: string;
275275

276276
constructor(scope: Construct, id: string, props: MapProps) {
277+
super(scope, id, {
278+
physicalName: props.mapName ?? Lazy.string({ produce: () => generateUniqueId(this) }),
279+
});
280+
// Enhanced CDK Analytics Telemetry
281+
addConstructMetadata(this, props);
282+
277283
if (props.description && !Token.isUnresolved(props.description) && props.description.length > 1000) {
278-
throw new Error(`\`description\` must be between 0 and 1000 characters, got: ${props.description.length} characters.`);
284+
throw new ValidationError(`\`description\` must be between 0 and 1000 characters, got: ${props.description.length} characters.`, this);
279285
}
280286

281287
if (props.mapName !== undefined && !Token.isUnresolved(props.mapName)) {
282288
if (props.mapName.length < 1 || props.mapName.length > 100) {
283-
throw new Error(`\`mapName\` must be between 1 and 100 characters, got: ${props.mapName.length} characters.`);
289+
throw new ValidationError(`\`mapName\` must be between 1 and 100 characters, got: ${props.mapName.length} characters.`, this);
284290
}
285291

286292
if (!/^[-._\w]+$/.test(props.mapName)) {
287-
throw new Error(`\`mapName\` must contain only alphanumeric characters, hyphens, periods and underscores, got: ${props.mapName}.`);
293+
throw new ValidationError(`\`mapName\` must contain only alphanumeric characters, hyphens, periods and underscores, got: ${props.mapName}.`, this);
288294
}
289295
}
290296

291-
super(scope, id, {
292-
physicalName: props.mapName ?? Lazy.string({ produce: () => generateUniqueId(this) }),
293-
});
294-
// Enhanced CDK Analytics Telemetry
295-
addConstructMetadata(this, props);
296-
297297
const map = new CfnMap(this, 'Resource', {
298298
configuration: {
299299
style: props.style,

packages/@aws-cdk/aws-location-alpha/lib/place-index.ts

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import * as iam from 'aws-cdk-lib/aws-iam';
2-
import { ArnFormat, IResource, Lazy, Resource, Stack, Token } from 'aws-cdk-lib/core';
2+
import { ArnFormat, IResource, Lazy, Resource, Stack, Token, UnscopedValidationError, ValidationError } from 'aws-cdk-lib/core';
33
import { Construct } from 'constructs';
44
import { CfnPlaceIndex } from 'aws-cdk-lib/aws-location';
55
import { DataSource, generateUniqueId } from './util';
@@ -101,7 +101,7 @@ export class PlaceIndex extends Resource implements IPlaceIndex {
101101
const parsedArn = Stack.of(scope).splitArn(placeIndexArn, ArnFormat.SLASH_RESOURCE_NAME);
102102

103103
if (!parsedArn.resourceName) {
104-
throw new Error(`Place Index Arn ${placeIndexArn} does not have a resource name.`);
104+
throw new UnscopedValidationError(`Place Index Arn ${placeIndexArn} does not have a resource name.`);
105105
}
106106

107107
class Import extends Resource implements IPlaceIndex {
@@ -134,26 +134,26 @@ export class PlaceIndex extends Resource implements IPlaceIndex {
134134
public readonly placeIndexUpdateTime: string;
135135

136136
constructor(scope: Construct, id: string, props: PlaceIndexProps = {}) {
137+
super(scope, id, {
138+
physicalName: props.placeIndexName ?? Lazy.string({ produce: () => generateUniqueId(this) }),
139+
});
140+
// Enhanced CDK Analytics Telemetry
141+
addConstructMetadata(this, props);
142+
137143
if (props.description && !Token.isUnresolved(props.description) && props.description.length > 1000) {
138-
throw new Error(`\`description\` must be between 0 and 1000 characters. Received: ${props.description.length} characters`);
144+
throw new ValidationError(`\`description\` must be between 0 and 1000 characters. Received: ${props.description.length} characters`, this);
139145
}
140146

141147
if (props.placeIndexName !== undefined && !Token.isUnresolved(props.placeIndexName)) {
142148
if (props.placeIndexName.length < 1 || props.placeIndexName.length > 100) {
143-
throw new Error(`\`placeIndexName\` must be between 1 and 100 characters, got: ${props.placeIndexName.length} characters.`);
149+
throw new ValidationError(`\`placeIndexName\` must be between 1 and 100 characters, got: ${props.placeIndexName.length} characters.`, this);
144150
}
145151

146152
if (!/^[-._\w]+$/.test(props.placeIndexName)) {
147-
throw new Error(`\`placeIndexName\` must contain only alphanumeric characters, hyphens, periods and underscores, got: ${props.placeIndexName}.`);
153+
throw new ValidationError(`\`placeIndexName\` must contain only alphanumeric characters, hyphens, periods and underscores, got: ${props.placeIndexName}.`, this);
148154
}
149155
}
150156

151-
super(scope, id, {
152-
physicalName: props.placeIndexName ?? Lazy.string({ produce: () => generateUniqueId(this) }),
153-
});
154-
// Enhanced CDK Analytics Telemetry
155-
addConstructMetadata(this, props);
156-
157157
const placeIndex = new CfnPlaceIndex(this, 'Resource', {
158158
indexName: this.physicalName,
159159
dataSource: props.dataSource ?? DataSource.ESRI,

packages/@aws-cdk/aws-location-alpha/lib/route-calculator.ts

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import * as iam from 'aws-cdk-lib/aws-iam';
2-
import { ArnFormat, IResource, Lazy, Resource, Stack, Token } from 'aws-cdk-lib/core';
2+
import { ArnFormat, IResource, Lazy, Resource, Stack, Token, UnscopedValidationError, ValidationError } from 'aws-cdk-lib/core';
33
import { Construct } from 'constructs';
44
import { CfnRouteCalculator } from 'aws-cdk-lib/aws-location';
55
import { generateUniqueId, DataSource } from './util';
@@ -77,7 +77,7 @@ export class RouteCalculator extends Resource implements IRouteCalculator {
7777
const parsedArn = Stack.of(scope).splitArn(routeCalculatorArn, ArnFormat.SLASH_RESOURCE_NAME);
7878

7979
if (!parsedArn.resourceName) {
80-
throw new Error(`Route Calculator Arn ${routeCalculatorArn} does not have a resource name.`);
80+
throw new UnscopedValidationError(`Route Calculator Arn ${routeCalculatorArn} does not have a resource name.`);
8181
}
8282

8383
class Import extends Resource implements IRouteCalculator {
@@ -110,26 +110,26 @@ export class RouteCalculator extends Resource implements IRouteCalculator {
110110
public readonly routeCalculatorUpdateTime: string;
111111

112112
constructor(scope: Construct, id: string, props: RouteCalculatorProps) {
113+
super(scope, id, {
114+
physicalName: props.routeCalculatorName ?? Lazy.string({ produce: () => generateUniqueId(this) }),
115+
});
116+
// Enhanced CDK Analytics Telemetry
117+
addConstructMetadata(this, props);
118+
113119
if (props.description && !Token.isUnresolved(props.description) && props.description.length > 1000) {
114-
throw new Error(`\`description\` must be between 0 and 1000 characters. Received: ${props.description.length} characters`);
120+
throw new ValidationError(`\`description\` must be between 0 and 1000 characters. Received: ${props.description.length} characters`, this);
115121
}
116122

117123
if (props.routeCalculatorName !== undefined && !Token.isUnresolved(props.routeCalculatorName)) {
118124
if (props.routeCalculatorName.length < 1 || props.routeCalculatorName.length > 100) {
119-
throw new Error(`\`routeCalculatorName\` must be between 1 and 100 characters, got: ${props.routeCalculatorName.length} characters.`);
125+
throw new ValidationError(`\`routeCalculatorName\` must be between 1 and 100 characters, got: ${props.routeCalculatorName.length} characters.`, this);
120126
}
121127

122128
if (!/^[-._\w]+$/.test(props.routeCalculatorName)) {
123-
throw new Error(`\`routeCalculatorName\` must contain only alphanumeric characters, hyphens, periods and underscores, got: ${props.routeCalculatorName}.`);
129+
throw new ValidationError(`\`routeCalculatorName\` must contain only alphanumeric characters, hyphens, periods and underscores, got: ${props.routeCalculatorName}.`, this);
124130
}
125131
}
126132

127-
super(scope, id, {
128-
physicalName: props.routeCalculatorName ?? Lazy.string({ produce: () => generateUniqueId(this) }),
129-
});
130-
// Enhanced CDK Analytics Telemetry
131-
addConstructMetadata(this, props);
132-
133133
const routeCalculator = new CfnRouteCalculator(this, 'Resource', {
134134
calculatorName: this.physicalName,
135135
dataSource: props.dataSource ?? DataSource.ESRI,

packages/@aws-cdk/aws-location-alpha/lib/tracker.ts

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import * as iam from 'aws-cdk-lib/aws-iam';
22
import * as kms from 'aws-cdk-lib/aws-kms';
3-
import { ArnFormat, IResource, Lazy, Resource, Stack, Token } from 'aws-cdk-lib/core';
3+
import { ArnFormat, IResource, Lazy, Resource, Stack, Token, UnscopedValidationError, ValidationError } from 'aws-cdk-lib/core';
44
import { Construct } from 'constructs';
55
import { CfnTracker, CfnTrackerConsumer } from 'aws-cdk-lib/aws-location';
66
import { generateUniqueId } from './util';
@@ -140,7 +140,7 @@ export class Tracker extends Resource implements ITracker {
140140
const parsedArn = Stack.of(scope).splitArn(trackerArn, ArnFormat.SLASH_RESOURCE_NAME);
141141

142142
if (!parsedArn.resourceName) {
143-
throw new Error(`Tracker Arn ${trackerArn} does not have a resource name.`);
143+
throw new UnscopedValidationError(`Tracker Arn ${trackerArn} does not have a resource name.`);
144144
}
145145

146146
class Import extends Resource implements ITracker {
@@ -173,33 +173,33 @@ export class Tracker extends Resource implements ITracker {
173173
public readonly trackerUpdateTime: string;
174174

175175
constructor(scope: Construct, id: string, props: TrackerProps = {}) {
176+
super(scope, id, {
177+
physicalName: props.trackerName ?? Lazy.string({ produce: () => generateUniqueId(this) }),
178+
});
179+
// Enhanced CDK Analytics Telemetry
180+
addConstructMetadata(this, props);
181+
176182
if (props.description && !Token.isUnresolved(props.description) && props.description.length > 1000) {
177-
throw new Error(`\`description\` must be between 0 and 1000 characters. Received: ${props.description.length} characters`);
183+
throw new ValidationError(`\`description\` must be between 0 and 1000 characters. Received: ${props.description.length} characters`, this);
178184
}
179185

180186
if (props.trackerName !== undefined && !Token.isUnresolved(props.trackerName)) {
181187
if (props.trackerName.length < 1 || props.trackerName.length > 100) {
182-
throw new Error(`\`trackerName\` must be between 1 and 100 characters, got: ${props.trackerName.length} characters.`);
188+
throw new ValidationError(`\`trackerName\` must be between 1 and 100 characters, got: ${props.trackerName.length} characters.`, this);
183189
}
184190

185191
if (!/^[-._\w]+$/.test(props.trackerName)) {
186-
throw new Error(`\`trackerName\` must contain only alphanumeric characters, hyphens, periods and underscores, got: ${props.trackerName}.`);
192+
throw new ValidationError(`\`trackerName\` must contain only alphanumeric characters, hyphens, periods and underscores, got: ${props.trackerName}.`, this);
187193
}
188194
}
189195

190196
if (!Token.isUnresolved(props.kmsKey)
191197
&& !props.kmsKey
192198
&& props.kmsKeyEnableGeospatialQueries
193199
) {
194-
throw new Error('`kmsKeyEnableGeospatialQueries` can only be enabled that are configured to use an AWS KMS customer managed key');
200+
throw new ValidationError('`kmsKeyEnableGeospatialQueries` can only be enabled that are configured to use an AWS KMS customer managed key', this);
195201
}
196202

197-
super(scope, id, {
198-
physicalName: props.trackerName ?? Lazy.string({ produce: () => generateUniqueId(this) }),
199-
});
200-
// Enhanced CDK Analytics Telemetry
201-
addConstructMetadata(this, props);
202-
203203
const tracker = new CfnTracker(this, 'Resource', {
204204
trackerName: this.physicalName,
205205
description: props.description,

0 commit comments

Comments
 (0)