@composurecdk/cloudformation 0.8.2 → 0.8.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/commonjs/constraints/char-sets.d.ts +22 -0
- package/dist/commonjs/constraints/char-sets.d.ts.map +1 -0
- package/dist/commonjs/constraints/char-sets.js +30 -0
- package/dist/commonjs/constraints/char-sets.js.map +1 -0
- package/dist/commonjs/constraints/index.d.ts +4 -0
- package/dist/commonjs/constraints/index.d.ts.map +1 -0
- package/dist/commonjs/constraints/index.js +10 -0
- package/dist/commonjs/constraints/index.js.map +1 -0
- package/dist/commonjs/constraints/namespace.d.ts +17 -0
- package/dist/commonjs/constraints/namespace.d.ts.map +1 -0
- package/dist/commonjs/constraints/namespace.js +3 -0
- package/dist/commonjs/constraints/namespace.js.map +1 -0
- package/dist/commonjs/constraints/string-constraint.d.ts +73 -0
- package/dist/commonjs/constraints/string-constraint.d.ts.map +1 -0
- package/dist/commonjs/constraints/string-constraint.js +78 -0
- package/dist/commonjs/constraints/string-constraint.js.map +1 -0
- package/dist/commonjs/index.d.ts +1 -0
- package/dist/commonjs/index.d.ts.map +1 -1
- package/dist/commonjs/index.js +6 -1
- package/dist/commonjs/index.js.map +1 -1
- package/dist/commonjs/tag-validator.d.ts +5 -7
- package/dist/commonjs/tag-validator.d.ts.map +1 -1
- package/dist/commonjs/tag-validator.js +39 -32
- package/dist/commonjs/tag-validator.js.map +1 -1
- package/dist/esm/constraints/char-sets.d.ts +22 -0
- package/dist/esm/constraints/char-sets.d.ts.map +1 -0
- package/dist/esm/constraints/char-sets.js +27 -0
- package/dist/esm/constraints/char-sets.js.map +1 -0
- package/dist/esm/constraints/index.d.ts +4 -0
- package/dist/esm/constraints/index.d.ts.map +1 -0
- package/dist/esm/constraints/index.js +3 -0
- package/dist/esm/constraints/index.js.map +1 -0
- package/dist/esm/constraints/namespace.d.ts +17 -0
- package/dist/esm/constraints/namespace.d.ts.map +1 -0
- package/dist/esm/constraints/namespace.js +2 -0
- package/dist/esm/constraints/namespace.js.map +1 -0
- package/dist/esm/constraints/string-constraint.d.ts +73 -0
- package/dist/esm/constraints/string-constraint.d.ts.map +1 -0
- package/dist/esm/constraints/string-constraint.js +73 -0
- package/dist/esm/constraints/string-constraint.js.map +1 -0
- package/dist/esm/index.d.ts +1 -0
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.js +1 -0
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/tag-validator.d.ts +5 -7
- package/dist/esm/tag-validator.d.ts.map +1 -1
- package/dist/esm/tag-validator.js +39 -32
- package/dist/esm/tag-validator.js.map +1 -1
- package/package.json +2 -2
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Character-class fragments shared across multiple AWS-property constraints.
|
|
3
|
+
*
|
|
4
|
+
* Each value is pre-escaped and ordered for use *inside* a `[...]` character
|
|
5
|
+
* class (the `-` is escaped, so position is irrelevant). A constraint spreads
|
|
6
|
+
* these into its own class alongside any property-specific characters, so the
|
|
7
|
+
* common spine is declared once and the per-property tail stays local.
|
|
8
|
+
*
|
|
9
|
+
* They are grouped under a single {@link charSets} export to keep the package
|
|
10
|
+
* surface tidy. A fragment graduates here only once a *second* property needs
|
|
11
|
+
* it — promotion is a one-line move plus an import change in the owning
|
|
12
|
+
* packages. See ADR-0010.
|
|
13
|
+
*/
|
|
14
|
+
/**
|
|
15
|
+
* Shared character-class fragments. Spread one into a constraint's `charClass`:
|
|
16
|
+
* `` charClass: `${charSets.ALNUM}${charSets.AWS_NAME_PUNCT}...` ``.
|
|
17
|
+
*/
|
|
18
|
+
export declare const charSets: {
|
|
19
|
+
readonly ALNUM: "A-Za-z0-9";
|
|
20
|
+
readonly AWS_NAME_PUNCT: " _./:+=@#()\\-";
|
|
21
|
+
};
|
|
22
|
+
//# sourceMappingURL=char-sets.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"char-sets.d.ts","sourceRoot":"","sources":["../../../src/constraints/char-sets.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAYH;;;GAGG;AACH,eAAO,MAAM,QAAQ;;;CAAqC,CAAC"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Character-class fragments shared across multiple AWS-property constraints.
|
|
4
|
+
*
|
|
5
|
+
* Each value is pre-escaped and ordered for use *inside* a `[...]` character
|
|
6
|
+
* class (the `-` is escaped, so position is irrelevant). A constraint spreads
|
|
7
|
+
* these into its own class alongside any property-specific characters, so the
|
|
8
|
+
* common spine is declared once and the per-property tail stays local.
|
|
9
|
+
*
|
|
10
|
+
* They are grouped under a single {@link charSets} export to keep the package
|
|
11
|
+
* surface tidy. A fragment graduates here only once a *second* property needs
|
|
12
|
+
* it — promotion is a one-line move plus an import change in the owning
|
|
13
|
+
* packages. See ADR-0010.
|
|
14
|
+
*/
|
|
15
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
16
|
+
exports.charSets = void 0;
|
|
17
|
+
/** ASCII letters and digits — the base of nearly every AWS name/description. */
|
|
18
|
+
const ALNUM = "A-Za-z0-9";
|
|
19
|
+
/**
|
|
20
|
+
* The punctuation common to AlarmName, SecurityGroup descriptions, and tags
|
|
21
|
+
* (the measured intersection). Individual properties extend this with their
|
|
22
|
+
* own additional characters; they do not redefine the shared set.
|
|
23
|
+
*/
|
|
24
|
+
const AWS_NAME_PUNCT = " _./:+=@#()\\-";
|
|
25
|
+
/**
|
|
26
|
+
* Shared character-class fragments. Spread one into a constraint's `charClass`:
|
|
27
|
+
* `` charClass: `${charSets.ALNUM}${charSets.AWS_NAME_PUNCT}...` ``.
|
|
28
|
+
*/
|
|
29
|
+
exports.charSets = { ALNUM, AWS_NAME_PUNCT };
|
|
30
|
+
//# sourceMappingURL=char-sets.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"char-sets.js","sourceRoot":"","sources":["../../../src/constraints/char-sets.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;GAYG;;;AAEH,gFAAgF;AAChF,MAAM,KAAK,GAAG,WAAW,CAAC;AAE1B;;;;GAIG;AACH,MAAM,cAAc,GAAG,gBAAgB,CAAC;AAExC;;;GAGG;AACU,QAAA,QAAQ,GAAG,EAAE,KAAK,EAAE,cAAc,EAAW,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/constraints/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,gBAAgB,EACrB,gBAAgB,EAChB,cAAc,EACd,cAAc,GACf,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC1C,OAAO,EAAE,KAAK,mBAAmB,EAAE,MAAM,gBAAgB,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.charSets = exports.sanitizeString = exports.validateString = exports.stringConstraint = void 0;
|
|
4
|
+
var string_constraint_js_1 = require("./string-constraint.js");
|
|
5
|
+
Object.defineProperty(exports, "stringConstraint", { enumerable: true, get: function () { return string_constraint_js_1.stringConstraint; } });
|
|
6
|
+
Object.defineProperty(exports, "validateString", { enumerable: true, get: function () { return string_constraint_js_1.validateString; } });
|
|
7
|
+
Object.defineProperty(exports, "sanitizeString", { enumerable: true, get: function () { return string_constraint_js_1.sanitizeString; } });
|
|
8
|
+
var char_sets_js_1 = require("./char-sets.js");
|
|
9
|
+
Object.defineProperty(exports, "charSets", { enumerable: true, get: function () { return char_sets_js_1.charSets; } });
|
|
10
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/constraints/index.ts"],"names":[],"mappings":";;;AAAA,+DAKgC;AAH9B,wHAAA,gBAAgB,OAAA;AAChB,sHAAA,cAAc,OAAA;AACd,sHAAA,cAAc,OAAA;AAEhB,+CAA0C;AAAjC,wGAAA,QAAQ,OAAA"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The shape every package's `constraints` export conforms to.
|
|
3
|
+
*
|
|
4
|
+
* Discoverability is a convention, not a runtime aggregate: each builder
|
|
5
|
+
* package exposes its own `constraints` object of this shape, so the calling
|
|
6
|
+
* pattern (`constraints.validate.*` / `constraints.sanitize.*`) is identical
|
|
7
|
+
* everywhere and a consumer imports only the package they already use. The
|
|
8
|
+
* browsable index of the whole catalogue is a generated doc, not an import.
|
|
9
|
+
* See ADR-0010.
|
|
10
|
+
*/
|
|
11
|
+
export interface ConstraintNamespace {
|
|
12
|
+
/** Throwing validators for user-authored values the author can fix. */
|
|
13
|
+
readonly validate: Readonly<Record<string, (raw: string) => void>>;
|
|
14
|
+
/** Transforming sanitisers for derived values the author does not control. */
|
|
15
|
+
readonly sanitize: Readonly<Record<string, (raw: string) => string>>;
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=namespace.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"namespace.d.ts","sourceRoot":"","sources":["../../../src/constraints/namespace.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,MAAM,WAAW,mBAAmB;IAClC,uEAAuE;IACvE,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC,CAAC,CAAC;IACnE,8EAA8E;IAC9E,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,MAAM,CAAC,CAAC,CAAC;CACtE"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"namespace.js","sourceRoot":"","sources":["../../../src/constraints/namespace.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The shared mechanism behind the AWS-property constraint catalogue.
|
|
3
|
+
*
|
|
4
|
+
* AWS rejects malformed property strings (bad character sets, over-length
|
|
5
|
+
* values) at deploy time, after a successful `cdk synth`. A {@link StringConstraint}
|
|
6
|
+
* captures one AWS property's character-set and length rules as data, so a
|
|
7
|
+
* builder can fail at synth — at the authoring call site — instead.
|
|
8
|
+
*
|
|
9
|
+
* The catalogue is deliberately split: this mechanism lives here, while the
|
|
10
|
+
* per-resource constraint *data* lives in the package that owns the builder
|
|
11
|
+
* (e.g. `SECURITY_GROUP_DESCRIPTION` in `@composurecdk/ec2`). Cross-cutting
|
|
12
|
+
* constraints that apply to every resource (such as tags) live alongside this
|
|
13
|
+
* mechanism instead. See ADR-0010.
|
|
14
|
+
*/
|
|
15
|
+
/**
|
|
16
|
+
* A single AWS-property constraint, expressed as data. One entry per
|
|
17
|
+
* `(resource, property)` pair.
|
|
18
|
+
*
|
|
19
|
+
* Both regexes are compiled once. `validate*` helpers test {@link pattern};
|
|
20
|
+
* `sanitize*` helpers replace runs matched by {@link sanitizePattern}. Use
|
|
21
|
+
* {@link stringConstraint} to build one so the two stay in sync.
|
|
22
|
+
*/
|
|
23
|
+
export interface StringConstraint {
|
|
24
|
+
/** Human-readable property identifier, e.g. `"EC2 SecurityGroup GroupDescription"`. */
|
|
25
|
+
readonly name: string;
|
|
26
|
+
/** Anchored full-match pattern used by `validate*`. */
|
|
27
|
+
readonly pattern: RegExp;
|
|
28
|
+
/** Global negated-character-class pattern used by `sanitize*`; absent for pattern-only constraints. */
|
|
29
|
+
readonly sanitizePattern?: RegExp;
|
|
30
|
+
readonly minLength?: number;
|
|
31
|
+
readonly maxLength?: number;
|
|
32
|
+
/** Human-readable allowed-set, surfaced in validation error messages. */
|
|
33
|
+
readonly allowed: string;
|
|
34
|
+
/** AWS doc / CFN reference URL, surfaced in validation error messages. */
|
|
35
|
+
readonly source: string;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Builds a {@link StringConstraint} from a character class and bounds. The
|
|
39
|
+
* anchored validation pattern and the negated sanitisation pattern are both
|
|
40
|
+
* derived from `charClass` and compiled once here, so a single declaration
|
|
41
|
+
* drives both validation and sanitisation and the two cannot drift apart.
|
|
42
|
+
*
|
|
43
|
+
* @param spec - The constraint's character class, length bounds, and metadata.
|
|
44
|
+
* @returns A constraint ready for {@link validateString} / {@link sanitizeString}.
|
|
45
|
+
*/
|
|
46
|
+
export declare function stringConstraint(spec: {
|
|
47
|
+
name: string;
|
|
48
|
+
charClass: string;
|
|
49
|
+
minLength?: number;
|
|
50
|
+
maxLength?: number;
|
|
51
|
+
allowed: string;
|
|
52
|
+
source: string;
|
|
53
|
+
flags?: string;
|
|
54
|
+
}): StringConstraint;
|
|
55
|
+
/**
|
|
56
|
+
* Validates `value` against `constraint`, throwing synchronously on the first
|
|
57
|
+
* violation. Use for **user-authored** values the author can fix — the error
|
|
58
|
+
* fires at the call site, naming the allowed set and linking the AWS doc.
|
|
59
|
+
*
|
|
60
|
+
* @throws If `value` is shorter than `minLength`, longer than `maxLength`, or
|
|
61
|
+
* contains characters outside the constraint's pattern.
|
|
62
|
+
*/
|
|
63
|
+
export declare function validateString(value: string, constraint: StringConstraint): void;
|
|
64
|
+
/**
|
|
65
|
+
* Returns a copy of `value` made legal for `constraint` by replacing runs of
|
|
66
|
+
* disallowed characters with `replacement` and truncating to `maxLength`. Use
|
|
67
|
+
* for **derived** values the author does not control (e.g. a DNS name composed
|
|
68
|
+
* into a construct ID), where rewriting is the only sensible move.
|
|
69
|
+
*
|
|
70
|
+
* @throws If the constraint is pattern-only and declares no sanitisation pattern.
|
|
71
|
+
*/
|
|
72
|
+
export declare function sanitizeString(value: string, constraint: StringConstraint, replacement?: string): string;
|
|
73
|
+
//# sourceMappingURL=string-constraint.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"string-constraint.d.ts","sourceRoot":"","sources":["../../../src/constraints/string-constraint.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH;;;;;;;GAOG;AACH,MAAM,WAAW,gBAAgB;IAC/B,uFAAuF;IACvF,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,uDAAuD;IACvD,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,uGAAuG;IACvG,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,CAAC;IAClC,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,yEAAyE;IACzE,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,0EAA0E;IAC1E,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAED;;;;;;;;GAQG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE;IACrC,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,GAAG,gBAAgB,CAWnB;AAED;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,gBAAgB,GAAG,IAAI,CAgBhF;AAED;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAC5B,KAAK,EAAE,MAAM,EACb,UAAU,EAAE,gBAAgB,EAC5B,WAAW,SAAM,GAChB,MAAM,CAWR"}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* The shared mechanism behind the AWS-property constraint catalogue.
|
|
4
|
+
*
|
|
5
|
+
* AWS rejects malformed property strings (bad character sets, over-length
|
|
6
|
+
* values) at deploy time, after a successful `cdk synth`. A {@link StringConstraint}
|
|
7
|
+
* captures one AWS property's character-set and length rules as data, so a
|
|
8
|
+
* builder can fail at synth — at the authoring call site — instead.
|
|
9
|
+
*
|
|
10
|
+
* The catalogue is deliberately split: this mechanism lives here, while the
|
|
11
|
+
* per-resource constraint *data* lives in the package that owns the builder
|
|
12
|
+
* (e.g. `SECURITY_GROUP_DESCRIPTION` in `@composurecdk/ec2`). Cross-cutting
|
|
13
|
+
* constraints that apply to every resource (such as tags) live alongside this
|
|
14
|
+
* mechanism instead. See ADR-0010.
|
|
15
|
+
*/
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
exports.stringConstraint = stringConstraint;
|
|
18
|
+
exports.validateString = validateString;
|
|
19
|
+
exports.sanitizeString = sanitizeString;
|
|
20
|
+
/**
|
|
21
|
+
* Builds a {@link StringConstraint} from a character class and bounds. The
|
|
22
|
+
* anchored validation pattern and the negated sanitisation pattern are both
|
|
23
|
+
* derived from `charClass` and compiled once here, so a single declaration
|
|
24
|
+
* drives both validation and sanitisation and the two cannot drift apart.
|
|
25
|
+
*
|
|
26
|
+
* @param spec - The constraint's character class, length bounds, and metadata.
|
|
27
|
+
* @returns A constraint ready for {@link validateString} / {@link sanitizeString}.
|
|
28
|
+
*/
|
|
29
|
+
function stringConstraint(spec) {
|
|
30
|
+
const quantifier = `{${String(spec.minLength ?? 0)},${spec.maxLength === undefined ? "" : String(spec.maxLength)}}`;
|
|
31
|
+
return {
|
|
32
|
+
name: spec.name,
|
|
33
|
+
pattern: new RegExp(`^[${spec.charClass}]${quantifier}$`, spec.flags),
|
|
34
|
+
sanitizePattern: new RegExp(`[^${spec.charClass}]+`, spec.flags?.includes("u") ? "gu" : "g"),
|
|
35
|
+
minLength: spec.minLength,
|
|
36
|
+
maxLength: spec.maxLength,
|
|
37
|
+
allowed: spec.allowed,
|
|
38
|
+
source: spec.source,
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Validates `value` against `constraint`, throwing synchronously on the first
|
|
43
|
+
* violation. Use for **user-authored** values the author can fix — the error
|
|
44
|
+
* fires at the call site, naming the allowed set and linking the AWS doc.
|
|
45
|
+
*
|
|
46
|
+
* @throws If `value` is shorter than `minLength`, longer than `maxLength`, or
|
|
47
|
+
* contains characters outside the constraint's pattern.
|
|
48
|
+
*/
|
|
49
|
+
function validateString(value, constraint) {
|
|
50
|
+
if (constraint.minLength !== undefined && value.length < constraint.minLength) {
|
|
51
|
+
throw new Error(`${constraint.name} "${value}" is shorter than the ${String(constraint.minLength)}-character minimum. See ${constraint.source}.`);
|
|
52
|
+
}
|
|
53
|
+
if (constraint.maxLength !== undefined && value.length > constraint.maxLength) {
|
|
54
|
+
throw new Error(`${constraint.name} "${value}" exceeds the ${String(constraint.maxLength)}-character limit. See ${constraint.source}.`);
|
|
55
|
+
}
|
|
56
|
+
if (!constraint.pattern.test(value)) {
|
|
57
|
+
throw new Error(`${constraint.name} "${value}" is invalid. Allowed: ${constraint.allowed}. See ${constraint.source}.`);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Returns a copy of `value` made legal for `constraint` by replacing runs of
|
|
62
|
+
* disallowed characters with `replacement` and truncating to `maxLength`. Use
|
|
63
|
+
* for **derived** values the author does not control (e.g. a DNS name composed
|
|
64
|
+
* into a construct ID), where rewriting is the only sensible move.
|
|
65
|
+
*
|
|
66
|
+
* @throws If the constraint is pattern-only and declares no sanitisation pattern.
|
|
67
|
+
*/
|
|
68
|
+
function sanitizeString(value, constraint, replacement = "-") {
|
|
69
|
+
if (constraint.sanitizePattern === undefined) {
|
|
70
|
+
throw new Error(`${constraint.name} cannot be sanitised: the constraint has no character class.`);
|
|
71
|
+
}
|
|
72
|
+
let out = value.replace(constraint.sanitizePattern, replacement);
|
|
73
|
+
if (constraint.maxLength !== undefined && out.length > constraint.maxLength) {
|
|
74
|
+
out = out.slice(0, constraint.maxLength);
|
|
75
|
+
}
|
|
76
|
+
return out;
|
|
77
|
+
}
|
|
78
|
+
//# sourceMappingURL=string-constraint.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"string-constraint.js","sourceRoot":"","sources":["../../../src/constraints/string-constraint.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;GAaG;;AAkCH,4CAmBC;AAUD,wCAgBC;AAUD,wCAeC;AA/ED;;;;;;;;GAQG;AACH,SAAgB,gBAAgB,CAAC,IAQhC;IACC,MAAM,UAAU,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,SAAS,IAAI,CAAC,CAAC,IAAI,IAAI,CAAC,SAAS,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC;IACpH,OAAO;QACL,IAAI,EAAE,IAAI,CAAC,IAAI;QACf,OAAO,EAAE,IAAI,MAAM,CAAC,KAAK,IAAI,CAAC,SAAS,IAAI,UAAU,GAAG,EAAE,IAAI,CAAC,KAAK,CAAC;QACrE,eAAe,EAAE,IAAI,MAAM,CAAC,KAAK,IAAI,CAAC,SAAS,IAAI,EAAE,IAAI,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC;QAC5F,SAAS,EAAE,IAAI,CAAC,SAAS;QACzB,SAAS,EAAE,IAAI,CAAC,SAAS;QACzB,OAAO,EAAE,IAAI,CAAC,OAAO;QACrB,MAAM,EAAE,IAAI,CAAC,MAAM;KACpB,CAAC;AACJ,CAAC;AAED;;;;;;;GAOG;AACH,SAAgB,cAAc,CAAC,KAAa,EAAE,UAA4B;IACxE,IAAI,UAAU,CAAC,SAAS,KAAK,SAAS,IAAI,KAAK,CAAC,MAAM,GAAG,UAAU,CAAC,SAAS,EAAE,CAAC;QAC9E,MAAM,IAAI,KAAK,CACb,GAAG,UAAU,CAAC,IAAI,KAAK,KAAK,yBAAyB,MAAM,CAAC,UAAU,CAAC,SAAS,CAAC,2BAA2B,UAAU,CAAC,MAAM,GAAG,CACjI,CAAC;IACJ,CAAC;IACD,IAAI,UAAU,CAAC,SAAS,KAAK,SAAS,IAAI,KAAK,CAAC,MAAM,GAAG,UAAU,CAAC,SAAS,EAAE,CAAC;QAC9E,MAAM,IAAI,KAAK,CACb,GAAG,UAAU,CAAC,IAAI,KAAK,KAAK,iBAAiB,MAAM,CAAC,UAAU,CAAC,SAAS,CAAC,yBAAyB,UAAU,CAAC,MAAM,GAAG,CACvH,CAAC;IACJ,CAAC;IACD,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;QACpC,MAAM,IAAI,KAAK,CACb,GAAG,UAAU,CAAC,IAAI,KAAK,KAAK,0BAA0B,UAAU,CAAC,OAAO,SAAS,UAAU,CAAC,MAAM,GAAG,CACtG,CAAC;IACJ,CAAC;AACH,CAAC;AAED;;;;;;;GAOG;AACH,SAAgB,cAAc,CAC5B,KAAa,EACb,UAA4B,EAC5B,WAAW,GAAG,GAAG;IAEjB,IAAI,UAAU,CAAC,eAAe,KAAK,SAAS,EAAE,CAAC;QAC7C,MAAM,IAAI,KAAK,CACb,GAAG,UAAU,CAAC,IAAI,8DAA8D,CACjF,CAAC;IACJ,CAAC;IACD,IAAI,GAAG,GAAG,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC,eAAe,EAAE,WAAW,CAAC,CAAC;IACjE,IAAI,UAAU,CAAC,SAAS,KAAK,SAAS,IAAI,GAAG,CAAC,MAAM,GAAG,UAAU,CAAC,SAAS,EAAE,CAAC;QAC5E,GAAG,GAAG,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,UAAU,CAAC,SAAS,CAAC,CAAC;IAC3C,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC"}
|
package/dist/commonjs/index.d.ts
CHANGED
|
@@ -5,4 +5,5 @@ export { taggedBuilder, type ITaggedBuilder, TAG_OVERRIDE_WARNING_NAME } from ".
|
|
|
5
5
|
export { applyBuilderTags } from "./apply-builder-tags.js";
|
|
6
6
|
export { validateTag } from "./tag-validator.js";
|
|
7
7
|
export { tags, type TagDefinitions } from "./tags.js";
|
|
8
|
+
export { type StringConstraint, stringConstraint, validateString, sanitizeString, charSets, type ConstraintNamespace, } from "./constraints/index.js";
|
|
8
9
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,kBAAkB,EAClB,KAAK,aAAa,EAClB,KAAK,kBAAkB,GACxB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAC7D,OAAO,EAAE,OAAO,EAAE,KAAK,gBAAgB,EAAE,KAAK,iBAAiB,EAAE,MAAM,cAAc,CAAC;AACtF,OAAO,EAAE,aAAa,EAAE,KAAK,cAAc,EAAE,yBAAyB,EAAE,MAAM,qBAAqB,CAAC;AACpG,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,IAAI,EAAE,KAAK,cAAc,EAAE,MAAM,WAAW,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,kBAAkB,EAClB,KAAK,aAAa,EAClB,KAAK,kBAAkB,GACxB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAC7D,OAAO,EAAE,OAAO,EAAE,KAAK,gBAAgB,EAAE,KAAK,iBAAiB,EAAE,MAAM,cAAc,CAAC;AACtF,OAAO,EAAE,aAAa,EAAE,KAAK,cAAc,EAAE,yBAAyB,EAAE,MAAM,qBAAqB,CAAC;AACpG,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,IAAI,EAAE,KAAK,cAAc,EAAE,MAAM,WAAW,CAAC;AACtD,OAAO,EACL,KAAK,gBAAgB,EACrB,gBAAgB,EAChB,cAAc,EACd,cAAc,EACd,QAAQ,EACR,KAAK,mBAAmB,GACzB,MAAM,wBAAwB,CAAC"}
|
package/dist/commonjs/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.tags = exports.validateTag = exports.applyBuilderTags = exports.TAG_OVERRIDE_WARNING_NAME = exports.taggedBuilder = exports.outputs = exports.groupedStacks = exports.singleStack = exports.createStackBuilder = void 0;
|
|
3
|
+
exports.charSets = exports.sanitizeString = exports.validateString = exports.stringConstraint = exports.tags = exports.validateTag = exports.applyBuilderTags = exports.TAG_OVERRIDE_WARNING_NAME = exports.taggedBuilder = exports.outputs = exports.groupedStacks = exports.singleStack = exports.createStackBuilder = void 0;
|
|
4
4
|
var stack_builder_js_1 = require("./stack-builder.js");
|
|
5
5
|
Object.defineProperty(exports, "createStackBuilder", { enumerable: true, get: function () { return stack_builder_js_1.createStackBuilder; } });
|
|
6
6
|
var strategies_js_1 = require("./strategies.js");
|
|
@@ -17,4 +17,9 @@ var tag_validator_js_1 = require("./tag-validator.js");
|
|
|
17
17
|
Object.defineProperty(exports, "validateTag", { enumerable: true, get: function () { return tag_validator_js_1.validateTag; } });
|
|
18
18
|
var tags_js_1 = require("./tags.js");
|
|
19
19
|
Object.defineProperty(exports, "tags", { enumerable: true, get: function () { return tags_js_1.tags; } });
|
|
20
|
+
var index_js_1 = require("./constraints/index.js");
|
|
21
|
+
Object.defineProperty(exports, "stringConstraint", { enumerable: true, get: function () { return index_js_1.stringConstraint; } });
|
|
22
|
+
Object.defineProperty(exports, "validateString", { enumerable: true, get: function () { return index_js_1.validateString; } });
|
|
23
|
+
Object.defineProperty(exports, "sanitizeString", { enumerable: true, get: function () { return index_js_1.sanitizeString; } });
|
|
24
|
+
Object.defineProperty(exports, "charSets", { enumerable: true, get: function () { return index_js_1.charSets; } });
|
|
20
25
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":";;;AAAA,uDAI4B;AAH1B,sHAAA,kBAAkB,OAAA;AAIpB,iDAA6D;AAApD,4GAAA,WAAW,OAAA;AAAE,8GAAA,aAAa,OAAA;AACnC,2CAAsF;AAA7E,qGAAA,OAAO,OAAA;AAChB,yDAAoG;AAA3F,kHAAA,aAAa,OAAA;AAAuB,8HAAA,yBAAyB,OAAA;AACtE,iEAA2D;AAAlD,yHAAA,gBAAgB,OAAA;AACzB,uDAAiD;AAAxC,+GAAA,WAAW,OAAA;AACpB,qCAAsD;AAA7C,+FAAA,IAAI,OAAA"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":";;;AAAA,uDAI4B;AAH1B,sHAAA,kBAAkB,OAAA;AAIpB,iDAA6D;AAApD,4GAAA,WAAW,OAAA;AAAE,8GAAA,aAAa,OAAA;AACnC,2CAAsF;AAA7E,qGAAA,OAAO,OAAA;AAChB,yDAAoG;AAA3F,kHAAA,aAAa,OAAA;AAAuB,8HAAA,yBAAyB,OAAA;AACtE,iEAA2D;AAAlD,yHAAA,gBAAgB,OAAA;AACzB,uDAAiD;AAAxC,+GAAA,WAAW,OAAA;AACpB,qCAAsD;AAA7C,+FAAA,IAAI,OAAA;AACb,mDAOgC;AAL9B,4GAAA,gBAAgB,OAAA;AAChB,0GAAA,cAAc,OAAA;AACd,0GAAA,cAAc,OAAA;AACd,oGAAA,QAAQ,OAAA"}
|
|
@@ -4,14 +4,12 @@
|
|
|
4
4
|
* Throws synchronously at the call site so authors see the failure where the
|
|
5
5
|
* bad value was written, not at deploy time. Validates:
|
|
6
6
|
*
|
|
7
|
-
* - `key` is non-empty and
|
|
8
|
-
*
|
|
9
|
-
* - `value`
|
|
10
|
-
*
|
|
7
|
+
* - `key` is non-empty and does not start with the reserved `aws:` prefix
|
|
8
|
+
* (case-insensitive) — both tag-specific rules.
|
|
9
|
+
* - `key` and `value` length and character set, via the shared catalogue
|
|
10
|
+
* mechanism. Empty values are permitted; empty keys are not.
|
|
11
11
|
*
|
|
12
|
-
*
|
|
13
|
-
* documented punctuation set, so non-ASCII tags are accepted as AWS
|
|
14
|
-
* supports them.
|
|
12
|
+
* Non-ASCII letters, digits, and whitespace are accepted, matching AWS.
|
|
15
13
|
*/
|
|
16
14
|
export declare function validateTag(key: string, value: string): void;
|
|
17
15
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tag-validator.d.ts","sourceRoot":"","sources":["../../src/tag-validator.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"tag-validator.d.ts","sourceRoot":"","sources":["../../src/tag-validator.ts"],"names":[],"mappings":"AAyCA;;;;;;;;;;;;GAYG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAW5D;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI,CAItE"}
|
|
@@ -2,58 +2,65 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.validateTag = validateTag;
|
|
4
4
|
exports.validateTagRecord = validateTagRecord;
|
|
5
|
+
const index_js_1 = require("./constraints/index.js");
|
|
5
6
|
/**
|
|
6
7
|
* AWS allows letters, digits, whitespace, and the symbols `_ . : / = + - @`
|
|
7
8
|
* in tag keys and values, with non-ASCII letters/digits permitted via
|
|
8
|
-
* Unicode classes.
|
|
9
|
-
* empty `Key` is not. The character set is validated against this regex.
|
|
9
|
+
* Unicode classes.
|
|
10
10
|
*
|
|
11
|
-
* `\p{Z}` matches the full Unicode separator class — slightly more
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
|
|
16
|
-
|
|
11
|
+
* `\p{Z}` matches the full Unicode separator class — slightly more permissive
|
|
12
|
+
* than AWS's documented "white space," but errs on the side of accepting input
|
|
13
|
+
* the AWS API may yet reject at deploy time, where the failure is reported in
|
|
14
|
+
* the API response.
|
|
15
|
+
*/
|
|
16
|
+
const TAG_CHARS = "\\p{L}\\p{Z}\\p{N}_.:/=+@\\-";
|
|
17
|
+
const TAG_ALLOWED = "the AWS tag character set: letters, digits, whitespace, and _ . : / = + - @";
|
|
18
|
+
const TAG_SOURCE = "https://docs.aws.amazon.com/general/latest/gr/aws_tagging.html";
|
|
19
|
+
/**
|
|
20
|
+
* Tags are cross-cutting — they apply to every resource — so unlike per-resource
|
|
21
|
+
* constraints they live alongside the catalogue mechanism rather than in a
|
|
22
|
+
* service package. Both entries are module-private and reached only through
|
|
23
|
+
* {@link validateTag}, which layers the tag-specific empty-key and reserved-
|
|
24
|
+
* prefix rules on top of {@link validateString}. See ADR-0010.
|
|
17
25
|
*/
|
|
18
|
-
const
|
|
19
|
-
|
|
20
|
-
|
|
26
|
+
const TAG_KEY = (0, index_js_1.stringConstraint)({
|
|
27
|
+
name: "Tag key",
|
|
28
|
+
charClass: TAG_CHARS,
|
|
29
|
+
maxLength: 128,
|
|
30
|
+
allowed: TAG_ALLOWED,
|
|
31
|
+
source: TAG_SOURCE,
|
|
32
|
+
flags: "u",
|
|
33
|
+
});
|
|
34
|
+
const TAG_VALUE = (0, index_js_1.stringConstraint)({
|
|
35
|
+
name: "Tag value",
|
|
36
|
+
charClass: TAG_CHARS,
|
|
37
|
+
maxLength: 256,
|
|
38
|
+
allowed: TAG_ALLOWED,
|
|
39
|
+
source: TAG_SOURCE,
|
|
40
|
+
flags: "u",
|
|
41
|
+
});
|
|
21
42
|
/**
|
|
22
43
|
* Validates a single tag key/value pair against AWS tag constraints.
|
|
23
44
|
*
|
|
24
45
|
* Throws synchronously at the call site so authors see the failure where the
|
|
25
46
|
* bad value was written, not at deploy time. Validates:
|
|
26
47
|
*
|
|
27
|
-
* - `key` is non-empty and
|
|
28
|
-
*
|
|
29
|
-
* - `value`
|
|
30
|
-
*
|
|
48
|
+
* - `key` is non-empty and does not start with the reserved `aws:` prefix
|
|
49
|
+
* (case-insensitive) — both tag-specific rules.
|
|
50
|
+
* - `key` and `value` length and character set, via the shared catalogue
|
|
51
|
+
* mechanism. Empty values are permitted; empty keys are not.
|
|
31
52
|
*
|
|
32
|
-
*
|
|
33
|
-
* documented punctuation set, so non-ASCII tags are accepted as AWS
|
|
34
|
-
* supports them.
|
|
53
|
+
* Non-ASCII letters, digits, and whitespace are accepted, matching AWS.
|
|
35
54
|
*/
|
|
36
55
|
function validateTag(key, value) {
|
|
37
56
|
if (key.length === 0) {
|
|
38
57
|
throw new Error("Tag key must be non-empty.");
|
|
39
58
|
}
|
|
40
|
-
if (key.length > KEY_MAX) {
|
|
41
|
-
throw new Error(`Tag key "${key}" exceeds ${String(KEY_MAX)}-character limit.`);
|
|
42
|
-
}
|
|
43
59
|
if (key.toLowerCase().startsWith("aws:")) {
|
|
44
60
|
throw new Error(`Tag key "${key}" uses reserved "aws:" prefix; AWS rejects user tags with this prefix.`);
|
|
45
61
|
}
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
"(letters, digits, whitespace, and `_ . : / = + - @`).");
|
|
49
|
-
}
|
|
50
|
-
if (value.length > VALUE_MAX) {
|
|
51
|
-
throw new Error(`Tag value for key "${key}" exceeds ${String(VALUE_MAX)}-character limit.`);
|
|
52
|
-
}
|
|
53
|
-
if (!TAG_CHAR_RE.test(value)) {
|
|
54
|
-
throw new Error(`Tag value for key "${key}" contains characters outside the AWS tag character set ` +
|
|
55
|
-
"(letters, digits, whitespace, and `_ . : / = + - @`).");
|
|
56
|
-
}
|
|
62
|
+
(0, index_js_1.validateString)(key, TAG_KEY);
|
|
63
|
+
(0, index_js_1.validateString)(value, TAG_VALUE);
|
|
57
64
|
}
|
|
58
65
|
/**
|
|
59
66
|
* Validates every entry of a record via {@link validateTag}, throwing on the
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tag-validator.js","sourceRoot":"","sources":["../../src/tag-validator.ts"],"names":[],"mappings":";;
|
|
1
|
+
{"version":3,"file":"tag-validator.js","sourceRoot":"","sources":["../../src/tag-validator.ts"],"names":[],"mappings":";;AAsDA,kCAWC;AAMD,8CAIC;AA3ED,qDAA0E;AAE1E;;;;;;;;;GASG;AACH,MAAM,SAAS,GAAG,8BAA8B,CAAC;AACjD,MAAM,WAAW,GAAG,6EAA6E,CAAC;AAClG,MAAM,UAAU,GAAG,gEAAgE,CAAC;AAEpF;;;;;;GAMG;AACH,MAAM,OAAO,GAAG,IAAA,2BAAgB,EAAC;IAC/B,IAAI,EAAE,SAAS;IACf,SAAS,EAAE,SAAS;IACpB,SAAS,EAAE,GAAG;IACd,OAAO,EAAE,WAAW;IACpB,MAAM,EAAE,UAAU;IAClB,KAAK,EAAE,GAAG;CACX,CAAC,CAAC;AAEH,MAAM,SAAS,GAAG,IAAA,2BAAgB,EAAC;IACjC,IAAI,EAAE,WAAW;IACjB,SAAS,EAAE,SAAS;IACpB,SAAS,EAAE,GAAG;IACd,OAAO,EAAE,WAAW;IACpB,MAAM,EAAE,UAAU;IAClB,KAAK,EAAE,GAAG;CACX,CAAC,CAAC;AAEH;;;;;;;;;;;;GAYG;AACH,SAAgB,WAAW,CAAC,GAAW,EAAE,KAAa;IACpD,IAAI,GAAG,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACrB,MAAM,IAAI,KAAK,CAAC,4BAA4B,CAAC,CAAC;IAChD,CAAC;IACD,IAAI,GAAG,CAAC,WAAW,EAAE,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;QACzC,MAAM,IAAI,KAAK,CACb,YAAY,GAAG,wEAAwE,CACxF,CAAC;IACJ,CAAC;IACD,IAAA,yBAAc,EAAC,GAAG,EAAE,OAAO,CAAC,CAAC;IAC7B,IAAA,yBAAc,EAAC,KAAK,EAAE,SAAS,CAAC,CAAC;AACnC,CAAC;AAED;;;GAGG;AACH,SAAgB,iBAAiB,CAAC,MAA8B;IAC9D,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;QAClD,WAAW,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;IAC1B,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Character-class fragments shared across multiple AWS-property constraints.
|
|
3
|
+
*
|
|
4
|
+
* Each value is pre-escaped and ordered for use *inside* a `[...]` character
|
|
5
|
+
* class (the `-` is escaped, so position is irrelevant). A constraint spreads
|
|
6
|
+
* these into its own class alongside any property-specific characters, so the
|
|
7
|
+
* common spine is declared once and the per-property tail stays local.
|
|
8
|
+
*
|
|
9
|
+
* They are grouped under a single {@link charSets} export to keep the package
|
|
10
|
+
* surface tidy. A fragment graduates here only once a *second* property needs
|
|
11
|
+
* it — promotion is a one-line move plus an import change in the owning
|
|
12
|
+
* packages. See ADR-0010.
|
|
13
|
+
*/
|
|
14
|
+
/**
|
|
15
|
+
* Shared character-class fragments. Spread one into a constraint's `charClass`:
|
|
16
|
+
* `` charClass: `${charSets.ALNUM}${charSets.AWS_NAME_PUNCT}...` ``.
|
|
17
|
+
*/
|
|
18
|
+
export declare const charSets: {
|
|
19
|
+
readonly ALNUM: "A-Za-z0-9";
|
|
20
|
+
readonly AWS_NAME_PUNCT: " _./:+=@#()\\-";
|
|
21
|
+
};
|
|
22
|
+
//# sourceMappingURL=char-sets.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"char-sets.d.ts","sourceRoot":"","sources":["../../../src/constraints/char-sets.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAYH;;;GAGG;AACH,eAAO,MAAM,QAAQ;;;CAAqC,CAAC"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Character-class fragments shared across multiple AWS-property constraints.
|
|
3
|
+
*
|
|
4
|
+
* Each value is pre-escaped and ordered for use *inside* a `[...]` character
|
|
5
|
+
* class (the `-` is escaped, so position is irrelevant). A constraint spreads
|
|
6
|
+
* these into its own class alongside any property-specific characters, so the
|
|
7
|
+
* common spine is declared once and the per-property tail stays local.
|
|
8
|
+
*
|
|
9
|
+
* They are grouped under a single {@link charSets} export to keep the package
|
|
10
|
+
* surface tidy. A fragment graduates here only once a *second* property needs
|
|
11
|
+
* it — promotion is a one-line move plus an import change in the owning
|
|
12
|
+
* packages. See ADR-0010.
|
|
13
|
+
*/
|
|
14
|
+
/** ASCII letters and digits — the base of nearly every AWS name/description. */
|
|
15
|
+
const ALNUM = "A-Za-z0-9";
|
|
16
|
+
/**
|
|
17
|
+
* The punctuation common to AlarmName, SecurityGroup descriptions, and tags
|
|
18
|
+
* (the measured intersection). Individual properties extend this with their
|
|
19
|
+
* own additional characters; they do not redefine the shared set.
|
|
20
|
+
*/
|
|
21
|
+
const AWS_NAME_PUNCT = " _./:+=@#()\\-";
|
|
22
|
+
/**
|
|
23
|
+
* Shared character-class fragments. Spread one into a constraint's `charClass`:
|
|
24
|
+
* `` charClass: `${charSets.ALNUM}${charSets.AWS_NAME_PUNCT}...` ``.
|
|
25
|
+
*/
|
|
26
|
+
export const charSets = { ALNUM, AWS_NAME_PUNCT };
|
|
27
|
+
//# sourceMappingURL=char-sets.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"char-sets.js","sourceRoot":"","sources":["../../../src/constraints/char-sets.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,gFAAgF;AAChF,MAAM,KAAK,GAAG,WAAW,CAAC;AAE1B;;;;GAIG;AACH,MAAM,cAAc,GAAG,gBAAgB,CAAC;AAExC;;;GAGG;AACH,MAAM,CAAC,MAAM,QAAQ,GAAG,EAAE,KAAK,EAAE,cAAc,EAAW,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/constraints/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,gBAAgB,EACrB,gBAAgB,EAChB,cAAc,EACd,cAAc,GACf,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC1C,OAAO,EAAE,KAAK,mBAAmB,EAAE,MAAM,gBAAgB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/constraints/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,gBAAgB,EAChB,cAAc,EACd,cAAc,GACf,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The shape every package's `constraints` export conforms to.
|
|
3
|
+
*
|
|
4
|
+
* Discoverability is a convention, not a runtime aggregate: each builder
|
|
5
|
+
* package exposes its own `constraints` object of this shape, so the calling
|
|
6
|
+
* pattern (`constraints.validate.*` / `constraints.sanitize.*`) is identical
|
|
7
|
+
* everywhere and a consumer imports only the package they already use. The
|
|
8
|
+
* browsable index of the whole catalogue is a generated doc, not an import.
|
|
9
|
+
* See ADR-0010.
|
|
10
|
+
*/
|
|
11
|
+
export interface ConstraintNamespace {
|
|
12
|
+
/** Throwing validators for user-authored values the author can fix. */
|
|
13
|
+
readonly validate: Readonly<Record<string, (raw: string) => void>>;
|
|
14
|
+
/** Transforming sanitisers for derived values the author does not control. */
|
|
15
|
+
readonly sanitize: Readonly<Record<string, (raw: string) => string>>;
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=namespace.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"namespace.d.ts","sourceRoot":"","sources":["../../../src/constraints/namespace.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,MAAM,WAAW,mBAAmB;IAClC,uEAAuE;IACvE,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC,CAAC,CAAC;IACnE,8EAA8E;IAC9E,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,MAAM,CAAC,CAAC,CAAC;CACtE"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"namespace.js","sourceRoot":"","sources":["../../../src/constraints/namespace.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The shared mechanism behind the AWS-property constraint catalogue.
|
|
3
|
+
*
|
|
4
|
+
* AWS rejects malformed property strings (bad character sets, over-length
|
|
5
|
+
* values) at deploy time, after a successful `cdk synth`. A {@link StringConstraint}
|
|
6
|
+
* captures one AWS property's character-set and length rules as data, so a
|
|
7
|
+
* builder can fail at synth — at the authoring call site — instead.
|
|
8
|
+
*
|
|
9
|
+
* The catalogue is deliberately split: this mechanism lives here, while the
|
|
10
|
+
* per-resource constraint *data* lives in the package that owns the builder
|
|
11
|
+
* (e.g. `SECURITY_GROUP_DESCRIPTION` in `@composurecdk/ec2`). Cross-cutting
|
|
12
|
+
* constraints that apply to every resource (such as tags) live alongside this
|
|
13
|
+
* mechanism instead. See ADR-0010.
|
|
14
|
+
*/
|
|
15
|
+
/**
|
|
16
|
+
* A single AWS-property constraint, expressed as data. One entry per
|
|
17
|
+
* `(resource, property)` pair.
|
|
18
|
+
*
|
|
19
|
+
* Both regexes are compiled once. `validate*` helpers test {@link pattern};
|
|
20
|
+
* `sanitize*` helpers replace runs matched by {@link sanitizePattern}. Use
|
|
21
|
+
* {@link stringConstraint} to build one so the two stay in sync.
|
|
22
|
+
*/
|
|
23
|
+
export interface StringConstraint {
|
|
24
|
+
/** Human-readable property identifier, e.g. `"EC2 SecurityGroup GroupDescription"`. */
|
|
25
|
+
readonly name: string;
|
|
26
|
+
/** Anchored full-match pattern used by `validate*`. */
|
|
27
|
+
readonly pattern: RegExp;
|
|
28
|
+
/** Global negated-character-class pattern used by `sanitize*`; absent for pattern-only constraints. */
|
|
29
|
+
readonly sanitizePattern?: RegExp;
|
|
30
|
+
readonly minLength?: number;
|
|
31
|
+
readonly maxLength?: number;
|
|
32
|
+
/** Human-readable allowed-set, surfaced in validation error messages. */
|
|
33
|
+
readonly allowed: string;
|
|
34
|
+
/** AWS doc / CFN reference URL, surfaced in validation error messages. */
|
|
35
|
+
readonly source: string;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Builds a {@link StringConstraint} from a character class and bounds. The
|
|
39
|
+
* anchored validation pattern and the negated sanitisation pattern are both
|
|
40
|
+
* derived from `charClass` and compiled once here, so a single declaration
|
|
41
|
+
* drives both validation and sanitisation and the two cannot drift apart.
|
|
42
|
+
*
|
|
43
|
+
* @param spec - The constraint's character class, length bounds, and metadata.
|
|
44
|
+
* @returns A constraint ready for {@link validateString} / {@link sanitizeString}.
|
|
45
|
+
*/
|
|
46
|
+
export declare function stringConstraint(spec: {
|
|
47
|
+
name: string;
|
|
48
|
+
charClass: string;
|
|
49
|
+
minLength?: number;
|
|
50
|
+
maxLength?: number;
|
|
51
|
+
allowed: string;
|
|
52
|
+
source: string;
|
|
53
|
+
flags?: string;
|
|
54
|
+
}): StringConstraint;
|
|
55
|
+
/**
|
|
56
|
+
* Validates `value` against `constraint`, throwing synchronously on the first
|
|
57
|
+
* violation. Use for **user-authored** values the author can fix — the error
|
|
58
|
+
* fires at the call site, naming the allowed set and linking the AWS doc.
|
|
59
|
+
*
|
|
60
|
+
* @throws If `value` is shorter than `minLength`, longer than `maxLength`, or
|
|
61
|
+
* contains characters outside the constraint's pattern.
|
|
62
|
+
*/
|
|
63
|
+
export declare function validateString(value: string, constraint: StringConstraint): void;
|
|
64
|
+
/**
|
|
65
|
+
* Returns a copy of `value` made legal for `constraint` by replacing runs of
|
|
66
|
+
* disallowed characters with `replacement` and truncating to `maxLength`. Use
|
|
67
|
+
* for **derived** values the author does not control (e.g. a DNS name composed
|
|
68
|
+
* into a construct ID), where rewriting is the only sensible move.
|
|
69
|
+
*
|
|
70
|
+
* @throws If the constraint is pattern-only and declares no sanitisation pattern.
|
|
71
|
+
*/
|
|
72
|
+
export declare function sanitizeString(value: string, constraint: StringConstraint, replacement?: string): string;
|
|
73
|
+
//# sourceMappingURL=string-constraint.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"string-constraint.d.ts","sourceRoot":"","sources":["../../../src/constraints/string-constraint.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH;;;;;;;GAOG;AACH,MAAM,WAAW,gBAAgB;IAC/B,uFAAuF;IACvF,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,uDAAuD;IACvD,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,uGAAuG;IACvG,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,CAAC;IAClC,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,yEAAyE;IACzE,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,0EAA0E;IAC1E,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAED;;;;;;;;GAQG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE;IACrC,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,GAAG,gBAAgB,CAWnB;AAED;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,gBAAgB,GAAG,IAAI,CAgBhF;AAED;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAC5B,KAAK,EAAE,MAAM,EACb,UAAU,EAAE,gBAAgB,EAC5B,WAAW,SAAM,GAChB,MAAM,CAWR"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The shared mechanism behind the AWS-property constraint catalogue.
|
|
3
|
+
*
|
|
4
|
+
* AWS rejects malformed property strings (bad character sets, over-length
|
|
5
|
+
* values) at deploy time, after a successful `cdk synth`. A {@link StringConstraint}
|
|
6
|
+
* captures one AWS property's character-set and length rules as data, so a
|
|
7
|
+
* builder can fail at synth — at the authoring call site — instead.
|
|
8
|
+
*
|
|
9
|
+
* The catalogue is deliberately split: this mechanism lives here, while the
|
|
10
|
+
* per-resource constraint *data* lives in the package that owns the builder
|
|
11
|
+
* (e.g. `SECURITY_GROUP_DESCRIPTION` in `@composurecdk/ec2`). Cross-cutting
|
|
12
|
+
* constraints that apply to every resource (such as tags) live alongside this
|
|
13
|
+
* mechanism instead. See ADR-0010.
|
|
14
|
+
*/
|
|
15
|
+
/**
|
|
16
|
+
* Builds a {@link StringConstraint} from a character class and bounds. The
|
|
17
|
+
* anchored validation pattern and the negated sanitisation pattern are both
|
|
18
|
+
* derived from `charClass` and compiled once here, so a single declaration
|
|
19
|
+
* drives both validation and sanitisation and the two cannot drift apart.
|
|
20
|
+
*
|
|
21
|
+
* @param spec - The constraint's character class, length bounds, and metadata.
|
|
22
|
+
* @returns A constraint ready for {@link validateString} / {@link sanitizeString}.
|
|
23
|
+
*/
|
|
24
|
+
export function stringConstraint(spec) {
|
|
25
|
+
const quantifier = `{${String(spec.minLength ?? 0)},${spec.maxLength === undefined ? "" : String(spec.maxLength)}}`;
|
|
26
|
+
return {
|
|
27
|
+
name: spec.name,
|
|
28
|
+
pattern: new RegExp(`^[${spec.charClass}]${quantifier}$`, spec.flags),
|
|
29
|
+
sanitizePattern: new RegExp(`[^${spec.charClass}]+`, spec.flags?.includes("u") ? "gu" : "g"),
|
|
30
|
+
minLength: spec.minLength,
|
|
31
|
+
maxLength: spec.maxLength,
|
|
32
|
+
allowed: spec.allowed,
|
|
33
|
+
source: spec.source,
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Validates `value` against `constraint`, throwing synchronously on the first
|
|
38
|
+
* violation. Use for **user-authored** values the author can fix — the error
|
|
39
|
+
* fires at the call site, naming the allowed set and linking the AWS doc.
|
|
40
|
+
*
|
|
41
|
+
* @throws If `value` is shorter than `minLength`, longer than `maxLength`, or
|
|
42
|
+
* contains characters outside the constraint's pattern.
|
|
43
|
+
*/
|
|
44
|
+
export function validateString(value, constraint) {
|
|
45
|
+
if (constraint.minLength !== undefined && value.length < constraint.minLength) {
|
|
46
|
+
throw new Error(`${constraint.name} "${value}" is shorter than the ${String(constraint.minLength)}-character minimum. See ${constraint.source}.`);
|
|
47
|
+
}
|
|
48
|
+
if (constraint.maxLength !== undefined && value.length > constraint.maxLength) {
|
|
49
|
+
throw new Error(`${constraint.name} "${value}" exceeds the ${String(constraint.maxLength)}-character limit. See ${constraint.source}.`);
|
|
50
|
+
}
|
|
51
|
+
if (!constraint.pattern.test(value)) {
|
|
52
|
+
throw new Error(`${constraint.name} "${value}" is invalid. Allowed: ${constraint.allowed}. See ${constraint.source}.`);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Returns a copy of `value` made legal for `constraint` by replacing runs of
|
|
57
|
+
* disallowed characters with `replacement` and truncating to `maxLength`. Use
|
|
58
|
+
* for **derived** values the author does not control (e.g. a DNS name composed
|
|
59
|
+
* into a construct ID), where rewriting is the only sensible move.
|
|
60
|
+
*
|
|
61
|
+
* @throws If the constraint is pattern-only and declares no sanitisation pattern.
|
|
62
|
+
*/
|
|
63
|
+
export function sanitizeString(value, constraint, replacement = "-") {
|
|
64
|
+
if (constraint.sanitizePattern === undefined) {
|
|
65
|
+
throw new Error(`${constraint.name} cannot be sanitised: the constraint has no character class.`);
|
|
66
|
+
}
|
|
67
|
+
let out = value.replace(constraint.sanitizePattern, replacement);
|
|
68
|
+
if (constraint.maxLength !== undefined && out.length > constraint.maxLength) {
|
|
69
|
+
out = out.slice(0, constraint.maxLength);
|
|
70
|
+
}
|
|
71
|
+
return out;
|
|
72
|
+
}
|
|
73
|
+
//# sourceMappingURL=string-constraint.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"string-constraint.js","sourceRoot":"","sources":["../../../src/constraints/string-constraint.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAyBH;;;;;;;;GAQG;AACH,MAAM,UAAU,gBAAgB,CAAC,IAQhC;IACC,MAAM,UAAU,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,SAAS,IAAI,CAAC,CAAC,IAAI,IAAI,CAAC,SAAS,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC;IACpH,OAAO;QACL,IAAI,EAAE,IAAI,CAAC,IAAI;QACf,OAAO,EAAE,IAAI,MAAM,CAAC,KAAK,IAAI,CAAC,SAAS,IAAI,UAAU,GAAG,EAAE,IAAI,CAAC,KAAK,CAAC;QACrE,eAAe,EAAE,IAAI,MAAM,CAAC,KAAK,IAAI,CAAC,SAAS,IAAI,EAAE,IAAI,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC;QAC5F,SAAS,EAAE,IAAI,CAAC,SAAS;QACzB,SAAS,EAAE,IAAI,CAAC,SAAS;QACzB,OAAO,EAAE,IAAI,CAAC,OAAO;QACrB,MAAM,EAAE,IAAI,CAAC,MAAM;KACpB,CAAC;AACJ,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,cAAc,CAAC,KAAa,EAAE,UAA4B;IACxE,IAAI,UAAU,CAAC,SAAS,KAAK,SAAS,IAAI,KAAK,CAAC,MAAM,GAAG,UAAU,CAAC,SAAS,EAAE,CAAC;QAC9E,MAAM,IAAI,KAAK,CACb,GAAG,UAAU,CAAC,IAAI,KAAK,KAAK,yBAAyB,MAAM,CAAC,UAAU,CAAC,SAAS,CAAC,2BAA2B,UAAU,CAAC,MAAM,GAAG,CACjI,CAAC;IACJ,CAAC;IACD,IAAI,UAAU,CAAC,SAAS,KAAK,SAAS,IAAI,KAAK,CAAC,MAAM,GAAG,UAAU,CAAC,SAAS,EAAE,CAAC;QAC9E,MAAM,IAAI,KAAK,CACb,GAAG,UAAU,CAAC,IAAI,KAAK,KAAK,iBAAiB,MAAM,CAAC,UAAU,CAAC,SAAS,CAAC,yBAAyB,UAAU,CAAC,MAAM,GAAG,CACvH,CAAC;IACJ,CAAC;IACD,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;QACpC,MAAM,IAAI,KAAK,CACb,GAAG,UAAU,CAAC,IAAI,KAAK,KAAK,0BAA0B,UAAU,CAAC,OAAO,SAAS,UAAU,CAAC,MAAM,GAAG,CACtG,CAAC;IACJ,CAAC;AACH,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,cAAc,CAC5B,KAAa,EACb,UAA4B,EAC5B,WAAW,GAAG,GAAG;IAEjB,IAAI,UAAU,CAAC,eAAe,KAAK,SAAS,EAAE,CAAC;QAC7C,MAAM,IAAI,KAAK,CACb,GAAG,UAAU,CAAC,IAAI,8DAA8D,CACjF,CAAC;IACJ,CAAC;IACD,IAAI,GAAG,GAAG,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC,eAAe,EAAE,WAAW,CAAC,CAAC;IACjE,IAAI,UAAU,CAAC,SAAS,KAAK,SAAS,IAAI,GAAG,CAAC,MAAM,GAAG,UAAU,CAAC,SAAS,EAAE,CAAC;QAC5E,GAAG,GAAG,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,UAAU,CAAC,SAAS,CAAC,CAAC;IAC3C,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC"}
|
package/dist/esm/index.d.ts
CHANGED
|
@@ -5,4 +5,5 @@ export { taggedBuilder, type ITaggedBuilder, TAG_OVERRIDE_WARNING_NAME } from ".
|
|
|
5
5
|
export { applyBuilderTags } from "./apply-builder-tags.js";
|
|
6
6
|
export { validateTag } from "./tag-validator.js";
|
|
7
7
|
export { tags, type TagDefinitions } from "./tags.js";
|
|
8
|
+
export { type StringConstraint, stringConstraint, validateString, sanitizeString, charSets, type ConstraintNamespace, } from "./constraints/index.js";
|
|
8
9
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/esm/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,kBAAkB,EAClB,KAAK,aAAa,EAClB,KAAK,kBAAkB,GACxB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAC7D,OAAO,EAAE,OAAO,EAAE,KAAK,gBAAgB,EAAE,KAAK,iBAAiB,EAAE,MAAM,cAAc,CAAC;AACtF,OAAO,EAAE,aAAa,EAAE,KAAK,cAAc,EAAE,yBAAyB,EAAE,MAAM,qBAAqB,CAAC;AACpG,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,IAAI,EAAE,KAAK,cAAc,EAAE,MAAM,WAAW,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,kBAAkB,EAClB,KAAK,aAAa,EAClB,KAAK,kBAAkB,GACxB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAC7D,OAAO,EAAE,OAAO,EAAE,KAAK,gBAAgB,EAAE,KAAK,iBAAiB,EAAE,MAAM,cAAc,CAAC;AACtF,OAAO,EAAE,aAAa,EAAE,KAAK,cAAc,EAAE,yBAAyB,EAAE,MAAM,qBAAqB,CAAC;AACpG,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,IAAI,EAAE,KAAK,cAAc,EAAE,MAAM,WAAW,CAAC;AACtD,OAAO,EACL,KAAK,gBAAgB,EACrB,gBAAgB,EAChB,cAAc,EACd,cAAc,EACd,QAAQ,EACR,KAAK,mBAAmB,GACzB,MAAM,wBAAwB,CAAC"}
|
package/dist/esm/index.js
CHANGED
|
@@ -5,4 +5,5 @@ export { taggedBuilder, TAG_OVERRIDE_WARNING_NAME } from "./tagged-builder.js";
|
|
|
5
5
|
export { applyBuilderTags } from "./apply-builder-tags.js";
|
|
6
6
|
export { validateTag } from "./tag-validator.js";
|
|
7
7
|
export { tags } from "./tags.js";
|
|
8
|
+
export { stringConstraint, validateString, sanitizeString, charSets, } from "./constraints/index.js";
|
|
8
9
|
//# sourceMappingURL=index.js.map
|
package/dist/esm/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,kBAAkB,GAGnB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAC7D,OAAO,EAAE,OAAO,EAAiD,MAAM,cAAc,CAAC;AACtF,OAAO,EAAE,aAAa,EAAuB,yBAAyB,EAAE,MAAM,qBAAqB,CAAC;AACpG,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,IAAI,EAAuB,MAAM,WAAW,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,kBAAkB,GAGnB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAC7D,OAAO,EAAE,OAAO,EAAiD,MAAM,cAAc,CAAC;AACtF,OAAO,EAAE,aAAa,EAAuB,yBAAyB,EAAE,MAAM,qBAAqB,CAAC;AACpG,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,IAAI,EAAuB,MAAM,WAAW,CAAC;AACtD,OAAO,EAEL,gBAAgB,EAChB,cAAc,EACd,cAAc,EACd,QAAQ,GAET,MAAM,wBAAwB,CAAC"}
|
|
@@ -4,14 +4,12 @@
|
|
|
4
4
|
* Throws synchronously at the call site so authors see the failure where the
|
|
5
5
|
* bad value was written, not at deploy time. Validates:
|
|
6
6
|
*
|
|
7
|
-
* - `key` is non-empty and
|
|
8
|
-
*
|
|
9
|
-
* - `value`
|
|
10
|
-
*
|
|
7
|
+
* - `key` is non-empty and does not start with the reserved `aws:` prefix
|
|
8
|
+
* (case-insensitive) — both tag-specific rules.
|
|
9
|
+
* - `key` and `value` length and character set, via the shared catalogue
|
|
10
|
+
* mechanism. Empty values are permitted; empty keys are not.
|
|
11
11
|
*
|
|
12
|
-
*
|
|
13
|
-
* documented punctuation set, so non-ASCII tags are accepted as AWS
|
|
14
|
-
* supports them.
|
|
12
|
+
* Non-ASCII letters, digits, and whitespace are accepted, matching AWS.
|
|
15
13
|
*/
|
|
16
14
|
export declare function validateTag(key: string, value: string): void;
|
|
17
15
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tag-validator.d.ts","sourceRoot":"","sources":["../../src/tag-validator.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"tag-validator.d.ts","sourceRoot":"","sources":["../../src/tag-validator.ts"],"names":[],"mappings":"AAyCA;;;;;;;;;;;;GAYG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAW5D;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI,CAItE"}
|
|
@@ -1,55 +1,62 @@
|
|
|
1
|
+
import { stringConstraint, validateString } from "./constraints/index.js";
|
|
1
2
|
/**
|
|
2
3
|
* AWS allows letters, digits, whitespace, and the symbols `_ . : / = + - @`
|
|
3
4
|
* in tag keys and values, with non-ASCII letters/digits permitted via
|
|
4
|
-
* Unicode classes.
|
|
5
|
-
* empty `Key` is not. The character set is validated against this regex.
|
|
5
|
+
* Unicode classes.
|
|
6
6
|
*
|
|
7
|
-
* `\p{Z}` matches the full Unicode separator class — slightly more
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
|
|
12
|
-
|
|
7
|
+
* `\p{Z}` matches the full Unicode separator class — slightly more permissive
|
|
8
|
+
* than AWS's documented "white space," but errs on the side of accepting input
|
|
9
|
+
* the AWS API may yet reject at deploy time, where the failure is reported in
|
|
10
|
+
* the API response.
|
|
11
|
+
*/
|
|
12
|
+
const TAG_CHARS = "\\p{L}\\p{Z}\\p{N}_.:/=+@\\-";
|
|
13
|
+
const TAG_ALLOWED = "the AWS tag character set: letters, digits, whitespace, and _ . : / = + - @";
|
|
14
|
+
const TAG_SOURCE = "https://docs.aws.amazon.com/general/latest/gr/aws_tagging.html";
|
|
15
|
+
/**
|
|
16
|
+
* Tags are cross-cutting — they apply to every resource — so unlike per-resource
|
|
17
|
+
* constraints they live alongside the catalogue mechanism rather than in a
|
|
18
|
+
* service package. Both entries are module-private and reached only through
|
|
19
|
+
* {@link validateTag}, which layers the tag-specific empty-key and reserved-
|
|
20
|
+
* prefix rules on top of {@link validateString}. See ADR-0010.
|
|
13
21
|
*/
|
|
14
|
-
const
|
|
15
|
-
|
|
16
|
-
|
|
22
|
+
const TAG_KEY = stringConstraint({
|
|
23
|
+
name: "Tag key",
|
|
24
|
+
charClass: TAG_CHARS,
|
|
25
|
+
maxLength: 128,
|
|
26
|
+
allowed: TAG_ALLOWED,
|
|
27
|
+
source: TAG_SOURCE,
|
|
28
|
+
flags: "u",
|
|
29
|
+
});
|
|
30
|
+
const TAG_VALUE = stringConstraint({
|
|
31
|
+
name: "Tag value",
|
|
32
|
+
charClass: TAG_CHARS,
|
|
33
|
+
maxLength: 256,
|
|
34
|
+
allowed: TAG_ALLOWED,
|
|
35
|
+
source: TAG_SOURCE,
|
|
36
|
+
flags: "u",
|
|
37
|
+
});
|
|
17
38
|
/**
|
|
18
39
|
* Validates a single tag key/value pair against AWS tag constraints.
|
|
19
40
|
*
|
|
20
41
|
* Throws synchronously at the call site so authors see the failure where the
|
|
21
42
|
* bad value was written, not at deploy time. Validates:
|
|
22
43
|
*
|
|
23
|
-
* - `key` is non-empty and
|
|
24
|
-
*
|
|
25
|
-
* - `value`
|
|
26
|
-
*
|
|
44
|
+
* - `key` is non-empty and does not start with the reserved `aws:` prefix
|
|
45
|
+
* (case-insensitive) — both tag-specific rules.
|
|
46
|
+
* - `key` and `value` length and character set, via the shared catalogue
|
|
47
|
+
* mechanism. Empty values are permitted; empty keys are not.
|
|
27
48
|
*
|
|
28
|
-
*
|
|
29
|
-
* documented punctuation set, so non-ASCII tags are accepted as AWS
|
|
30
|
-
* supports them.
|
|
49
|
+
* Non-ASCII letters, digits, and whitespace are accepted, matching AWS.
|
|
31
50
|
*/
|
|
32
51
|
export function validateTag(key, value) {
|
|
33
52
|
if (key.length === 0) {
|
|
34
53
|
throw new Error("Tag key must be non-empty.");
|
|
35
54
|
}
|
|
36
|
-
if (key.length > KEY_MAX) {
|
|
37
|
-
throw new Error(`Tag key "${key}" exceeds ${String(KEY_MAX)}-character limit.`);
|
|
38
|
-
}
|
|
39
55
|
if (key.toLowerCase().startsWith("aws:")) {
|
|
40
56
|
throw new Error(`Tag key "${key}" uses reserved "aws:" prefix; AWS rejects user tags with this prefix.`);
|
|
41
57
|
}
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
"(letters, digits, whitespace, and `_ . : / = + - @`).");
|
|
45
|
-
}
|
|
46
|
-
if (value.length > VALUE_MAX) {
|
|
47
|
-
throw new Error(`Tag value for key "${key}" exceeds ${String(VALUE_MAX)}-character limit.`);
|
|
48
|
-
}
|
|
49
|
-
if (!TAG_CHAR_RE.test(value)) {
|
|
50
|
-
throw new Error(`Tag value for key "${key}" contains characters outside the AWS tag character set ` +
|
|
51
|
-
"(letters, digits, whitespace, and `_ . : / = + - @`).");
|
|
52
|
-
}
|
|
58
|
+
validateString(key, TAG_KEY);
|
|
59
|
+
validateString(value, TAG_VALUE);
|
|
53
60
|
}
|
|
54
61
|
/**
|
|
55
62
|
* Validates every entry of a record via {@link validateTag}, throwing on the
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tag-validator.js","sourceRoot":"","sources":["../../src/tag-validator.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"tag-validator.js","sourceRoot":"","sources":["../../src/tag-validator.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAE1E;;;;;;;;;GASG;AACH,MAAM,SAAS,GAAG,8BAA8B,CAAC;AACjD,MAAM,WAAW,GAAG,6EAA6E,CAAC;AAClG,MAAM,UAAU,GAAG,gEAAgE,CAAC;AAEpF;;;;;;GAMG;AACH,MAAM,OAAO,GAAG,gBAAgB,CAAC;IAC/B,IAAI,EAAE,SAAS;IACf,SAAS,EAAE,SAAS;IACpB,SAAS,EAAE,GAAG;IACd,OAAO,EAAE,WAAW;IACpB,MAAM,EAAE,UAAU;IAClB,KAAK,EAAE,GAAG;CACX,CAAC,CAAC;AAEH,MAAM,SAAS,GAAG,gBAAgB,CAAC;IACjC,IAAI,EAAE,WAAW;IACjB,SAAS,EAAE,SAAS;IACpB,SAAS,EAAE,GAAG;IACd,OAAO,EAAE,WAAW;IACpB,MAAM,EAAE,UAAU;IAClB,KAAK,EAAE,GAAG;CACX,CAAC,CAAC;AAEH;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,WAAW,CAAC,GAAW,EAAE,KAAa;IACpD,IAAI,GAAG,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACrB,MAAM,IAAI,KAAK,CAAC,4BAA4B,CAAC,CAAC;IAChD,CAAC;IACD,IAAI,GAAG,CAAC,WAAW,EAAE,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;QACzC,MAAM,IAAI,KAAK,CACb,YAAY,GAAG,wEAAwE,CACxF,CAAC;IACJ,CAAC;IACD,cAAc,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;IAC7B,cAAc,CAAC,KAAK,EAAE,SAAS,CAAC,CAAC;AACnC,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,iBAAiB,CAAC,MAA8B;IAC9D,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;QAClD,WAAW,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;IAC1B,CAAC;AACH,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@composurecdk/cloudformation",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.4",
|
|
4
4
|
"description": "Composable CloudFormation stack builder and stack assignment strategies",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
},
|
|
39
39
|
"peerDependencies": {
|
|
40
40
|
"@composurecdk/core": "^0.8.0",
|
|
41
|
-
"aws-cdk-lib": "^2.
|
|
41
|
+
"aws-cdk-lib": "^2.1.0",
|
|
42
42
|
"constructs": "^10.0.0"
|
|
43
43
|
},
|
|
44
44
|
"devDependencies": {
|