@tsed/schema 8.19.2 → 8.19.3
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/lib/esm/constants/OperationVerbs.js +35 -0
- package/lib/esm/constants/VendorKeys.js +29 -0
- package/lib/esm/constants/httpStatusMessages.js +59 -0
- package/lib/esm/constants/jsonSchemaProperties.js +55 -0
- package/lib/esm/decorators/class/children.js +93 -5
- package/lib/esm/decorators/class/discriminatorValue.js +124 -20
- package/lib/esm/decorators/collections/collectionContains.js +91 -10
- package/lib/esm/decorators/collections/maxItems.js +97 -27
- package/lib/esm/decorators/collections/maxProperties.js +96 -30
- package/lib/esm/decorators/collections/minItems.js +122 -27
- package/lib/esm/decorators/collections/minProperties.js +132 -31
- package/lib/esm/decorators/common/additionalProperties.js +59 -4
- package/lib/esm/decorators/common/allOf.js +61 -6
- package/lib/esm/decorators/common/allow.js +56 -12
- package/lib/esm/decorators/common/any.js +58 -18
- package/lib/esm/decorators/common/anyOf.js +65 -9
- package/lib/esm/decorators/common/const.js +72 -30
- package/lib/esm/decorators/common/customKey.js +132 -12
- package/lib/esm/decorators/common/default.js +85 -19
- package/lib/esm/decorators/common/discriminatorKey.js +123 -0
- package/lib/esm/decorators/common/errorMsg.js +48 -2
- package/lib/esm/decorators/common/example.js +68 -6
- package/lib/esm/decorators/common/examples.js +99 -6
- package/lib/esm/decorators/common/format.js +86 -52
- package/lib/esm/decorators/common/nullable.js +77 -11
- package/lib/esm/decorators/common/oneOf.js +93 -9
- package/lib/esm/decorators/common/optional.js +93 -4
- package/lib/esm/decorators/common/property.js +42 -6
- package/lib/esm/decorators/common/readOnly.js +106 -5
- package/lib/esm/decorators/common/required.js +57 -20
- package/lib/esm/decorators/common/writeOnly.js +117 -5
- package/lib/esm/domain/JsonClassStore.js +75 -0
- package/lib/esm/domain/JsonDiscriminator.js +57 -0
- package/lib/esm/domain/JsonEntityStore.js +46 -0
- package/lib/esm/domain/JsonFormatTypes.js +39 -0
- package/lib/esm/domain/JsonLazyRef.js +33 -0
- package/lib/esm/domain/JsonMap.js +32 -0
- package/lib/esm/domain/JsonMedia.js +28 -0
- package/lib/esm/domain/JsonMethodStore.js +56 -0
- package/lib/esm/domain/JsonOperation.js +43 -0
- package/lib/esm/domain/JsonOperationPathsMap.js +38 -0
- package/lib/esm/domain/JsonOperationRoute.js +54 -0
- package/lib/esm/domain/JsonParameter.js +35 -0
- package/lib/esm/domain/JsonParameterStore.js +71 -0
- package/lib/esm/domain/JsonParameterTypes.js +26 -0
- package/lib/esm/domain/JsonPropertyStore.js +44 -0
- package/lib/esm/domain/JsonRequestBody.js +26 -0
- package/lib/esm/domain/JsonResponse.js +29 -0
- package/lib/esm/domain/JsonSchema.js +365 -16
- package/lib/esm/domain/SpecTypes.js +26 -0
- package/lib/esm/fn/boolean.js +39 -3
- package/lib/esm/fn/number.js +45 -3
- package/lib/esm/fn/string.js +43 -3
- package/lib/types/constants/OperationVerbs.d.ts +35 -0
- package/lib/types/constants/VendorKeys.d.ts +29 -0
- package/lib/types/constants/httpStatusMessages.d.ts +59 -0
- package/lib/types/constants/jsonSchemaProperties.d.ts +55 -0
- package/lib/types/decorators/class/children.d.ts +93 -5
- package/lib/types/decorators/class/discriminatorValue.d.ts +124 -20
- package/lib/types/decorators/collections/collectionContains.d.ts +91 -10
- package/lib/types/decorators/collections/maxItems.d.ts +97 -27
- package/lib/types/decorators/collections/maxProperties.d.ts +96 -30
- package/lib/types/decorators/collections/minItems.d.ts +122 -27
- package/lib/types/decorators/collections/minProperties.d.ts +132 -31
- package/lib/types/decorators/common/additionalProperties.d.ts +59 -4
- package/lib/types/decorators/common/allOf.d.ts +61 -6
- package/lib/types/decorators/common/allow.d.ts +56 -12
- package/lib/types/decorators/common/any.d.ts +58 -18
- package/lib/types/decorators/common/anyOf.d.ts +65 -9
- package/lib/types/decorators/common/const.d.ts +72 -30
- package/lib/types/decorators/common/customKey.d.ts +132 -12
- package/lib/types/decorators/common/default.d.ts +85 -19
- package/lib/types/decorators/common/discriminatorKey.d.ts +123 -0
- package/lib/types/decorators/common/errorMsg.d.ts +48 -2
- package/lib/types/decorators/common/example.d.ts +68 -6
- package/lib/types/decorators/common/examples.d.ts +99 -6
- package/lib/types/decorators/common/format.d.ts +86 -52
- package/lib/types/decorators/common/nullable.d.ts +77 -11
- package/lib/types/decorators/common/oneOf.d.ts +93 -9
- package/lib/types/decorators/common/optional.d.ts +93 -4
- package/lib/types/decorators/common/property.d.ts +42 -6
- package/lib/types/decorators/common/readOnly.d.ts +106 -5
- package/lib/types/decorators/common/required.d.ts +57 -20
- package/lib/types/decorators/common/writeOnly.d.ts +117 -5
- package/lib/types/domain/JsonClassStore.d.ts +75 -0
- package/lib/types/domain/JsonDiscriminator.d.ts +57 -0
- package/lib/types/domain/JsonEntityStore.d.ts +51 -0
- package/lib/types/domain/JsonFormatTypes.d.ts +39 -0
- package/lib/types/domain/JsonLazyRef.d.ts +33 -0
- package/lib/types/domain/JsonMap.d.ts +32 -0
- package/lib/types/domain/JsonMedia.d.ts +28 -0
- package/lib/types/domain/JsonMethodStore.d.ts +66 -0
- package/lib/types/domain/JsonOperation.d.ts +51 -0
- package/lib/types/domain/JsonOperationPathsMap.d.ts +38 -0
- package/lib/types/domain/JsonOperationRoute.d.ts +54 -0
- package/lib/types/domain/JsonParameter.d.ts +35 -0
- package/lib/types/domain/JsonParameterStore.d.ts +97 -0
- package/lib/types/domain/JsonParameterTypes.d.ts +26 -0
- package/lib/types/domain/JsonPropertyStore.d.ts +44 -0
- package/lib/types/domain/JsonRequestBody.d.ts +31 -0
- package/lib/types/domain/JsonResponse.d.ts +34 -0
- package/lib/types/domain/JsonSchema.d.ts +422 -19
- package/lib/types/domain/SpecTypes.d.ts +26 -0
- package/lib/types/domain/types.d.ts +90 -0
- package/lib/types/fn/boolean.d.ts +39 -3
- package/lib/types/fn/number.d.ts +45 -3
- package/lib/types/fn/string.d.ts +43 -3
- package/lib/types/interfaces/IgnoreCallback.d.ts +24 -0
- package/lib/types/interfaces/JsonHookContext.d.ts +31 -0
- package/lib/types/interfaces/JsonOpenSpec.d.ts +33 -0
- package/lib/types/interfaces/JsonSchemaOptions.d.ts +26 -0
- package/package.json +7 -7
|
@@ -1,51 +1,121 @@
|
|
|
1
1
|
import { withErrorMsg } from "../../utils/withErrorMsg.js";
|
|
2
2
|
import { JsonEntityFn } from "../common/jsonEntityFn.js";
|
|
3
3
|
/**
|
|
4
|
-
*
|
|
4
|
+
* Sets the maximum number of items allowed in an array.
|
|
5
5
|
*
|
|
6
|
-
*
|
|
6
|
+
* The `@MaxItems()` decorator validates that an array has at most the specified number
|
|
7
|
+
* of elements. This is useful for enforcing size limits on collections to prevent
|
|
8
|
+
* excessive data, manage performance, or enforce business rules.
|
|
7
9
|
*
|
|
8
|
-
*
|
|
9
|
-
* The value `maxItems` MUST be a non-negative integer.
|
|
10
|
-
* :::
|
|
11
|
-
*
|
|
12
|
-
* :: warning
|
|
13
|
-
* This decorator will be removed in v7.
|
|
14
|
-
* For v6 user, use @@MaxItems@@ from @tsed/schema instead of @tsed/platform-http.
|
|
15
|
-
* :::
|
|
16
|
-
*
|
|
17
|
-
* ## Example
|
|
10
|
+
* ### Basic Usage
|
|
18
11
|
*
|
|
19
12
|
* ```typescript
|
|
20
|
-
* class
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
13
|
+
* class UserModel {
|
|
14
|
+
* @CollectionOf(String)
|
|
15
|
+
* @MaxItems(5)
|
|
16
|
+
* tags: string[];
|
|
17
|
+
* // Maximum 5 tags allowed
|
|
24
18
|
* }
|
|
25
19
|
* ```
|
|
26
20
|
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
21
|
+
* Generated schema:
|
|
29
22
|
* ```json
|
|
30
23
|
* {
|
|
31
24
|
* "type": "object",
|
|
32
25
|
* "properties": {
|
|
33
|
-
* "
|
|
34
|
-
* "type": "
|
|
35
|
-
* "maxItems":
|
|
26
|
+
* "tags": {
|
|
27
|
+
* "type": "array",
|
|
28
|
+
* "maxItems": 5,
|
|
29
|
+
* "items": {
|
|
30
|
+
* "type": "string"
|
|
31
|
+
* }
|
|
36
32
|
* }
|
|
37
33
|
* }
|
|
38
34
|
* }
|
|
39
35
|
* ```
|
|
40
36
|
*
|
|
41
|
-
*
|
|
37
|
+
* ### With MinItems - Range Validation
|
|
38
|
+
*
|
|
39
|
+
* ```typescript
|
|
40
|
+
* class TeamModel {
|
|
41
|
+
* @CollectionOf(String)
|
|
42
|
+
* @MinItems(1)
|
|
43
|
+
* @MaxItems(10)
|
|
44
|
+
* members: string[];
|
|
45
|
+
* // Must have between 1 and 10 members
|
|
46
|
+
* }
|
|
47
|
+
* ```
|
|
48
|
+
*
|
|
49
|
+
* ### API Rate Limiting
|
|
50
|
+
*
|
|
51
|
+
* ```typescript
|
|
52
|
+
* class BulkRequest {
|
|
53
|
+
* @CollectionOf(Number)
|
|
54
|
+
* @MaxItems(100)
|
|
55
|
+
* ids: number[];
|
|
56
|
+
* // Limit bulk operations to 100 items
|
|
57
|
+
* }
|
|
58
|
+
* ```
|
|
59
|
+
*
|
|
60
|
+
* ### File Uploads
|
|
61
|
+
*
|
|
62
|
+
* ```typescript
|
|
63
|
+
* class FileUpload {
|
|
64
|
+
* @CollectionOf(Object)
|
|
65
|
+
* @MaxItems(5)
|
|
66
|
+
* attachments: File[];
|
|
67
|
+
* // Maximum 5 file attachments
|
|
68
|
+
* }
|
|
69
|
+
* ```
|
|
70
|
+
*
|
|
71
|
+
* ### Validation Examples
|
|
72
|
+
*
|
|
73
|
+
* ```typescript
|
|
74
|
+
* @MaxItems(3)
|
|
75
|
+
* items: string[];
|
|
76
|
+
*
|
|
77
|
+
* // Valid:
|
|
78
|
+
* [] // 0 items (≤ 3)
|
|
79
|
+
* ["a"] // 1 item (≤ 3)
|
|
80
|
+
* ["a", "b", "c"] // 3 items (≤ 3)
|
|
81
|
+
*
|
|
82
|
+
* // Invalid:
|
|
83
|
+
* ["a", "b", "c", "d"] // 4 items (> 3)
|
|
84
|
+
* ```
|
|
85
|
+
*
|
|
86
|
+
* ### Use Cases
|
|
87
|
+
*
|
|
88
|
+
* - **Performance**: Limit collection sizes to prevent memory issues
|
|
89
|
+
* - **Business Rules**: Enforce maximum quantities (cart items, selections)
|
|
90
|
+
* - **API Protection**: Prevent abuse with excessive bulk requests
|
|
91
|
+
* - **UI Constraints**: Match front-end limitations (max selections)
|
|
92
|
+
* - **Data Quality**: Encourage focused, manageable data sets
|
|
93
|
+
*
|
|
94
|
+
* ### Combining with Other Validators
|
|
95
|
+
*
|
|
96
|
+
* ```typescript
|
|
97
|
+
* class SearchQuery {
|
|
98
|
+
* @CollectionOf(String)
|
|
99
|
+
* @MinItems(1)
|
|
100
|
+
* @MaxItems(10)
|
|
101
|
+
* @UniqueItems()
|
|
102
|
+
* keywords: string[];
|
|
103
|
+
* // 1-10 unique search keywords
|
|
104
|
+
* }
|
|
105
|
+
* ```
|
|
106
|
+
*
|
|
107
|
+
* ### Important Notes
|
|
108
|
+
*
|
|
109
|
+
* - The value must be a **non-negative integer** (0 or greater)
|
|
110
|
+
* - Throws an error if a negative value is provided
|
|
111
|
+
* - Empty arrays (length 0) always pass maxItems validation
|
|
112
|
+
* - Can be combined with custom error messages using ajv-errors
|
|
113
|
+
*
|
|
114
|
+
* @param maxItems - Maximum number of items allowed (must be non-negative)
|
|
115
|
+
*
|
|
42
116
|
* @decorator
|
|
43
117
|
* @validation
|
|
44
|
-
* @
|
|
45
|
-
* @schema
|
|
46
|
-
* @input
|
|
47
|
-
* @collections
|
|
48
|
-
* @ajv-errors
|
|
118
|
+
* @public
|
|
49
119
|
*/
|
|
50
120
|
export const MaxItems = withErrorMsg("maxItems", (maxItems) => {
|
|
51
121
|
if (maxItems < 0) {
|
|
@@ -1,50 +1,45 @@
|
|
|
1
1
|
import { withErrorMsg } from "../../utils/withErrorMsg.js";
|
|
2
2
|
import { JsonEntityFn } from "../common/jsonEntityFn.js";
|
|
3
3
|
/**
|
|
4
|
-
*
|
|
4
|
+
* Sets the maximum number of properties allowed on an object.
|
|
5
5
|
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
6
|
+
* The `@MaxProperties()` decorator validates that an object has at most the specified
|
|
7
|
+
* number of properties. This is useful for limiting dynamic object sizes, preventing
|
|
8
|
+
* excessive data structures, or enforcing schema constraints on flexible objects.
|
|
9
9
|
*
|
|
10
|
-
*
|
|
11
|
-
* This decorator will be removed in v7.
|
|
12
|
-
* For v6 user, use @@MaxProperties@@ from @tsed/schema instead of @tsed/platform-http.
|
|
13
|
-
* :::
|
|
10
|
+
* ### On Property
|
|
14
11
|
*
|
|
15
|
-
* ## Example
|
|
16
|
-
* ### On prop
|
|
17
12
|
* ```typescript
|
|
18
|
-
* class
|
|
19
|
-
*
|
|
20
|
-
*
|
|
13
|
+
* class ConfigModel {
|
|
14
|
+
* @MaxProperties(5)
|
|
15
|
+
* metadata: Record<string, any>;
|
|
16
|
+
* // Object can have at most 5 properties
|
|
21
17
|
* }
|
|
22
18
|
* ```
|
|
23
19
|
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
20
|
+
* Generated schema:
|
|
26
21
|
* ```json
|
|
27
22
|
* {
|
|
28
23
|
* "type": "object",
|
|
29
24
|
* "properties": {
|
|
30
|
-
* "
|
|
31
|
-
* "type": "
|
|
32
|
-
* "maxProperties":
|
|
25
|
+
* "metadata": {
|
|
26
|
+
* "type": "object",
|
|
27
|
+
* "maxProperties": 5
|
|
33
28
|
* }
|
|
34
29
|
* }
|
|
35
30
|
* }
|
|
36
31
|
* ```
|
|
37
32
|
*
|
|
38
|
-
* ### On
|
|
33
|
+
* ### On Class
|
|
39
34
|
*
|
|
40
35
|
* ```typescript
|
|
41
36
|
* @MaxProperties(10)
|
|
42
|
-
* class
|
|
37
|
+
* class DynamicModel {
|
|
38
|
+
* // Class instances can have at most 10 properties total
|
|
43
39
|
* }
|
|
44
40
|
* ```
|
|
45
41
|
*
|
|
46
|
-
*
|
|
47
|
-
*
|
|
42
|
+
* Generated schema:
|
|
48
43
|
* ```json
|
|
49
44
|
* {
|
|
50
45
|
* "type": "object",
|
|
@@ -55,20 +50,91 @@ import { JsonEntityFn } from "../common/jsonEntityFn.js";
|
|
|
55
50
|
* ### On Parameter
|
|
56
51
|
*
|
|
57
52
|
* ```typescript
|
|
53
|
+
* @Controller("/api")
|
|
54
|
+
* class ApiController {
|
|
55
|
+
* @Post("/config")
|
|
56
|
+
* updateConfig(
|
|
57
|
+
* @BodyParams() @MaxProperties(10) config: any
|
|
58
|
+
* ) {
|
|
59
|
+
* // Config object limited to 10 properties
|
|
60
|
+
* }
|
|
61
|
+
* }
|
|
62
|
+
* ```
|
|
63
|
+
*
|
|
64
|
+
* ### With MinProperties - Range Validation
|
|
65
|
+
*
|
|
66
|
+
* ```typescript
|
|
67
|
+
* class FilterModel {
|
|
68
|
+
* @MinProperties(1)
|
|
69
|
+
* @MaxProperties(5)
|
|
70
|
+
* filters: Record<string, string>;
|
|
71
|
+
* // Must have 1-5 filter properties
|
|
72
|
+
* }
|
|
73
|
+
* ```
|
|
74
|
+
*
|
|
75
|
+
* ### Dynamic Objects
|
|
76
|
+
*
|
|
77
|
+
* ```typescript
|
|
78
|
+
* class UserPreferences {
|
|
79
|
+
* @MaxProperties(20)
|
|
80
|
+
* @AdditionalProperties({ type: "string" })
|
|
81
|
+
* settings: Record<string, string>;
|
|
82
|
+
* // Up to 20 custom settings, all string values
|
|
83
|
+
* }
|
|
84
|
+
* ```
|
|
85
|
+
*
|
|
86
|
+
* ### Validation Examples
|
|
87
|
+
*
|
|
88
|
+
* ```typescript
|
|
89
|
+
* @MaxProperties(2)
|
|
90
|
+
* data: object;
|
|
91
|
+
*
|
|
92
|
+
* // Valid:
|
|
93
|
+
* {} // 0 properties (≤ 2)
|
|
94
|
+
* { a: 1 } // 1 property (≤ 2)
|
|
95
|
+
* { a: 1, b: 2 } // 2 properties (≤ 2)
|
|
96
|
+
*
|
|
97
|
+
* // Invalid:
|
|
98
|
+
* { a: 1, b: 2, c: 3 } // 3 properties (> 2)
|
|
99
|
+
* ```
|
|
100
|
+
*
|
|
101
|
+
* ### Use Cases
|
|
102
|
+
*
|
|
103
|
+
* - **API Rate Limiting**: Restrict filter/query parameter counts
|
|
104
|
+
* - **Performance**: Prevent overly complex objects
|
|
105
|
+
* - **Schema Constraints**: Limit dynamic data structures
|
|
106
|
+
* - **Configuration**: Cap number of custom settings
|
|
107
|
+
* - **Security**: Prevent payload bloat attacks
|
|
58
108
|
*
|
|
59
|
-
*
|
|
60
|
-
*
|
|
109
|
+
* ### Flexible Schemas
|
|
110
|
+
*
|
|
111
|
+
* ```typescript
|
|
112
|
+
* class ExtensibleModel {
|
|
113
|
+
* @Property()
|
|
114
|
+
* id: string;
|
|
115
|
+
*
|
|
116
|
+
* @Property()
|
|
117
|
+
* name: string;
|
|
118
|
+
*
|
|
119
|
+
* @MaxProperties(5)
|
|
120
|
+
* @AdditionalProperties(true)
|
|
121
|
+
* // 2 defined properties + up to 3 additional properties
|
|
61
122
|
* }
|
|
62
123
|
* ```
|
|
63
124
|
*
|
|
64
|
-
*
|
|
125
|
+
* ### Important Notes
|
|
126
|
+
*
|
|
127
|
+
* - The value must be a **non-negative integer** (0 or greater)
|
|
128
|
+
* - Throws an error if a negative value is provided
|
|
129
|
+
* - Empty objects (`{}`) always pass maxProperties validation
|
|
130
|
+
* - Counts all properties, including inherited and additional ones
|
|
131
|
+
* - Can be combined with custom error messages using ajv-errors
|
|
132
|
+
*
|
|
133
|
+
* @param maxProperties - Maximum number of properties allowed (must be non-negative)
|
|
134
|
+
*
|
|
65
135
|
* @decorator
|
|
66
136
|
* @validation
|
|
67
|
-
* @
|
|
68
|
-
* @schema
|
|
69
|
-
* @input
|
|
70
|
-
* @collections
|
|
71
|
-
* @ajv-errors
|
|
137
|
+
* @public
|
|
72
138
|
*/
|
|
73
139
|
export const MaxProperties = withErrorMsg("maxProperties", (maxProperties) => {
|
|
74
140
|
if (maxProperties < 0) {
|
|
@@ -1,39 +1,31 @@
|
|
|
1
1
|
import { withErrorMsg } from "../../utils/withErrorMsg.js";
|
|
2
2
|
import { JsonEntityFn } from "../common/jsonEntityFn.js";
|
|
3
3
|
/**
|
|
4
|
-
*
|
|
4
|
+
* Sets the minimum number of items required in an array.
|
|
5
5
|
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
6
|
+
* The `@MinItems()` decorator validates that an array has at least the specified number
|
|
7
|
+
* of elements. This is useful for ensuring required data is provided, enforcing business
|
|
8
|
+
* rules, or guaranteeing minimum quantities.
|
|
9
9
|
*
|
|
10
|
-
*
|
|
11
|
-
* Omitting this keyword has the same behavior as a value of 0.
|
|
12
|
-
* :::
|
|
13
|
-
*
|
|
14
|
-
* ::: warning
|
|
15
|
-
* For v6 user, use @@MinItems@@ from @tsed/schema instead of @tsed/platform-http.
|
|
16
|
-
* :::
|
|
17
|
-
*
|
|
18
|
-
* ## Example
|
|
10
|
+
* ### Basic Usage
|
|
19
11
|
*
|
|
20
12
|
* ```typescript
|
|
21
|
-
* class
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
13
|
+
* class OrderModel {
|
|
14
|
+
* @CollectionOf(String)
|
|
15
|
+
* @MinItems(1)
|
|
16
|
+
* items: string[];
|
|
17
|
+
* // Order must have at least 1 item
|
|
25
18
|
* }
|
|
26
19
|
* ```
|
|
27
20
|
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
21
|
+
* Generated schema:
|
|
30
22
|
* ```json
|
|
31
23
|
* {
|
|
32
24
|
* "type": "object",
|
|
33
25
|
* "properties": {
|
|
34
|
-
* "
|
|
26
|
+
* "items": {
|
|
35
27
|
* "type": "array",
|
|
36
|
-
* "minItems":
|
|
28
|
+
* "minItems": 1,
|
|
37
29
|
* "items": {
|
|
38
30
|
* "type": "string"
|
|
39
31
|
* }
|
|
@@ -42,14 +34,117 @@ import { JsonEntityFn } from "../common/jsonEntityFn.js";
|
|
|
42
34
|
* }
|
|
43
35
|
* ```
|
|
44
36
|
*
|
|
45
|
-
*
|
|
37
|
+
* ### With MaxItems - Range Validation
|
|
38
|
+
*
|
|
39
|
+
* ```typescript
|
|
40
|
+
* class VotingModel {
|
|
41
|
+
* @CollectionOf(String)
|
|
42
|
+
* @MinItems(3)
|
|
43
|
+
* @MaxItems(10)
|
|
44
|
+
* candidates: string[];
|
|
45
|
+
* // Must have between 3 and 10 candidates
|
|
46
|
+
* }
|
|
47
|
+
* ```
|
|
48
|
+
*
|
|
49
|
+
* ### Required Selections
|
|
50
|
+
*
|
|
51
|
+
* ```typescript
|
|
52
|
+
* class SurveyResponse {
|
|
53
|
+
* @CollectionOf(String)
|
|
54
|
+
* @MinItems(1)
|
|
55
|
+
* selectedOptions: string[];
|
|
56
|
+
* // User must select at least one option
|
|
57
|
+
* }
|
|
58
|
+
* ```
|
|
59
|
+
*
|
|
60
|
+
* ### Business Rules
|
|
61
|
+
*
|
|
62
|
+
* ```typescript
|
|
63
|
+
* class TeamCreation {
|
|
64
|
+
* @CollectionOf(String)
|
|
65
|
+
* @MinItems(2)
|
|
66
|
+
* memberIds: string[];
|
|
67
|
+
* // Team requires minimum 2 members
|
|
68
|
+
* }
|
|
69
|
+
* ```
|
|
70
|
+
*
|
|
71
|
+
* ### Validation Examples
|
|
72
|
+
*
|
|
73
|
+
* ```typescript
|
|
74
|
+
* @MinItems(2)
|
|
75
|
+
* items: string[];
|
|
76
|
+
*
|
|
77
|
+
* // Valid:
|
|
78
|
+
* ["a", "b"] // 2 items (≥ 2)
|
|
79
|
+
* ["a", "b", "c"] // 3 items (≥ 2)
|
|
80
|
+
*
|
|
81
|
+
* // Invalid:
|
|
82
|
+
* [] // 0 items (< 2)
|
|
83
|
+
* ["a"] // 1 item (< 2)
|
|
84
|
+
* ```
|
|
85
|
+
*
|
|
86
|
+
* ### Use Cases
|
|
87
|
+
*
|
|
88
|
+
* - **Required Data**: Ensure minimum data is provided
|
|
89
|
+
* - **Business Logic**: Enforce minimum quantities (team size, votes)
|
|
90
|
+
* - **Data Quality**: Prevent submission with insufficient information
|
|
91
|
+
* - **User Input**: Require multiple selections or answers
|
|
92
|
+
* - **Validation**: Ensure arrays are not empty when data is expected
|
|
93
|
+
*
|
|
94
|
+
* ### Non-Empty Arrays
|
|
95
|
+
*
|
|
96
|
+
* ```typescript
|
|
97
|
+
* class CommentModel {
|
|
98
|
+
* @CollectionOf(String)
|
|
99
|
+
* @MinItems(1)
|
|
100
|
+
* tags: string[];
|
|
101
|
+
* // Prevent empty tag arrays
|
|
102
|
+
* }
|
|
103
|
+
* ```
|
|
104
|
+
*
|
|
105
|
+
* ### Combining with Uniqueness
|
|
106
|
+
*
|
|
107
|
+
* ```typescript
|
|
108
|
+
* class CategoryModel {
|
|
109
|
+
* @CollectionOf(String)
|
|
110
|
+
* @MinItems(2)
|
|
111
|
+
* @UniqueItems()
|
|
112
|
+
* subcategories: string[];
|
|
113
|
+
* // Must have at least 2 unique subcategories
|
|
114
|
+
* }
|
|
115
|
+
* ```
|
|
116
|
+
*
|
|
117
|
+
* ### Important Notes
|
|
118
|
+
*
|
|
119
|
+
* - The value must be a **non-negative integer** (0 or greater)
|
|
120
|
+
* - Throws an error if a negative value is provided
|
|
121
|
+
* - Omitting `@MinItems()` is equivalent to `@MinItems(0)` (no minimum)
|
|
122
|
+
* - Can be combined with custom error messages using ajv-errors
|
|
123
|
+
* - Arrays with exactly minItems elements are valid (inclusive)
|
|
124
|
+
*
|
|
125
|
+
* ### Default Behavior
|
|
126
|
+
*
|
|
127
|
+
* Without `@MinItems()`, arrays can be empty:
|
|
128
|
+
* ```typescript
|
|
129
|
+
* @CollectionOf(String)
|
|
130
|
+
* tags: string[];
|
|
131
|
+
* // Valid: [], ["tag1"], ["tag1", "tag2"], etc.
|
|
132
|
+
* ```
|
|
133
|
+
*
|
|
134
|
+
* With `@MinItems(1)`, empty arrays are rejected:
|
|
135
|
+
* ```typescript
|
|
136
|
+
* @CollectionOf(String)
|
|
137
|
+
* @MinItems(1)
|
|
138
|
+
* tags: string[];
|
|
139
|
+
* // Invalid: []
|
|
140
|
+
* // Valid: ["tag1"], ["tag1", "tag2"], etc.
|
|
141
|
+
* ```
|
|
142
|
+
*
|
|
143
|
+
* @param minItems - Minimum number of items required (must be non-negative)
|
|
144
|
+
*
|
|
46
145
|
* @decorator
|
|
47
146
|
* @validation
|
|
48
|
-
* @
|
|
49
|
-
* @schema
|
|
50
|
-
* @input
|
|
51
|
-
* @collections
|
|
52
|
-
* @ajv-errors
|
|
147
|
+
* @public
|
|
53
148
|
*/
|
|
54
149
|
export const MinItems = withErrorMsg("minItems", (minItems) => {
|
|
55
150
|
if (minItems < 0) {
|
|
@@ -1,73 +1,174 @@
|
|
|
1
1
|
import { withErrorMsg } from "../../utils/withErrorMsg.js";
|
|
2
2
|
import { JsonEntityFn } from "../common/jsonEntityFn.js";
|
|
3
3
|
/**
|
|
4
|
-
*
|
|
4
|
+
* Sets the minimum number of properties required on an object.
|
|
5
5
|
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
6
|
+
* The `@MinProperties()` decorator validates that an object has at least the specified
|
|
7
|
+
* number of properties. This is useful for ensuring objects aren't empty, enforcing
|
|
8
|
+
* minimum data requirements, or validating that dynamic objects have sufficient content.
|
|
9
9
|
*
|
|
10
|
-
*
|
|
11
|
-
* For v6 user, use @@MinProperties@@ from @tsed/schema instead of @tsed/platform-http.
|
|
12
|
-
* :::
|
|
10
|
+
* ### On Property
|
|
13
11
|
*
|
|
14
|
-
* ## Example
|
|
15
|
-
* ### On prop
|
|
16
12
|
* ```typescript
|
|
17
|
-
* class
|
|
18
|
-
*
|
|
19
|
-
*
|
|
13
|
+
* class DataModel {
|
|
14
|
+
* @MinProperties(1)
|
|
15
|
+
* attributes: Record<string, any>;
|
|
16
|
+
* // Object must have at least 1 property
|
|
20
17
|
* }
|
|
21
18
|
* ```
|
|
22
19
|
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
20
|
+
* Generated schema:
|
|
25
21
|
* ```json
|
|
26
22
|
* {
|
|
27
23
|
* "type": "object",
|
|
28
24
|
* "properties": {
|
|
29
|
-
* "
|
|
30
|
-
* "type": "
|
|
31
|
-
* "minProperties":
|
|
25
|
+
* "attributes": {
|
|
26
|
+
* "type": "object",
|
|
27
|
+
* "minProperties": 1
|
|
32
28
|
* }
|
|
33
29
|
* }
|
|
34
30
|
* }
|
|
35
31
|
* ```
|
|
36
32
|
*
|
|
37
|
-
* ### On
|
|
33
|
+
* ### On Class
|
|
38
34
|
*
|
|
39
35
|
* ```typescript
|
|
40
|
-
* @MinProperties(
|
|
41
|
-
* class
|
|
36
|
+
* @MinProperties(2)
|
|
37
|
+
* class RequiredDataModel {
|
|
38
|
+
* // Class instances must have at least 2 properties
|
|
42
39
|
* }
|
|
43
40
|
* ```
|
|
44
41
|
*
|
|
45
|
-
*
|
|
46
|
-
*
|
|
42
|
+
* Generated schema:
|
|
47
43
|
* ```json
|
|
48
44
|
* {
|
|
49
45
|
* "type": "object",
|
|
50
|
-
* "minProperties":
|
|
46
|
+
* "minProperties": 2
|
|
51
47
|
* }
|
|
52
48
|
* ```
|
|
53
49
|
*
|
|
54
50
|
* ### On Parameter
|
|
55
51
|
*
|
|
56
52
|
* ```typescript
|
|
53
|
+
* @Controller("/api")
|
|
54
|
+
* class ApiController {
|
|
55
|
+
* @Post("/filters")
|
|
56
|
+
* search(
|
|
57
|
+
* @BodyParams() @MinProperties(1) filters: any
|
|
58
|
+
* ) {
|
|
59
|
+
* // Filters object must have at least 1 property
|
|
60
|
+
* }
|
|
61
|
+
* }
|
|
62
|
+
* ```
|
|
63
|
+
*
|
|
64
|
+
* ### With MaxProperties - Range Validation
|
|
65
|
+
*
|
|
66
|
+
* ```typescript
|
|
67
|
+
* class MetadataModel {
|
|
68
|
+
* @MinProperties(2)
|
|
69
|
+
* @MaxProperties(10)
|
|
70
|
+
* metadata: Record<string, string>;
|
|
71
|
+
* // Must have between 2 and 10 properties
|
|
72
|
+
* }
|
|
73
|
+
* ```
|
|
74
|
+
*
|
|
75
|
+
* ### Non-Empty Objects
|
|
76
|
+
*
|
|
77
|
+
* ```typescript
|
|
78
|
+
* class SearchCriteria {
|
|
79
|
+
* @MinProperties(1)
|
|
80
|
+
* criteria: Record<string, any>;
|
|
81
|
+
* // Prevent empty search criteria objects
|
|
82
|
+
* }
|
|
83
|
+
* ```
|
|
84
|
+
*
|
|
85
|
+
* ### Dynamic Configuration
|
|
86
|
+
*
|
|
87
|
+
* ```typescript
|
|
88
|
+
* class PluginConfig {
|
|
89
|
+
* @MinProperties(1)
|
|
90
|
+
* @AdditionalProperties({ type: "string" })
|
|
91
|
+
* options: Record<string, string>;
|
|
92
|
+
* // At least 1 configuration option required
|
|
93
|
+
* }
|
|
94
|
+
* ```
|
|
95
|
+
*
|
|
96
|
+
* ### Validation Examples
|
|
97
|
+
*
|
|
98
|
+
* ```typescript
|
|
99
|
+
* @MinProperties(2)
|
|
100
|
+
* data: object;
|
|
57
101
|
*
|
|
58
|
-
*
|
|
59
|
-
*
|
|
102
|
+
* // Valid:
|
|
103
|
+
* { a: 1, b: 2 } // 2 properties (≥ 2)
|
|
104
|
+
* { a: 1, b: 2, c: 3 } // 3 properties (≥ 2)
|
|
105
|
+
*
|
|
106
|
+
* // Invalid:
|
|
107
|
+
* {} // 0 properties (< 2)
|
|
108
|
+
* { a: 1 } // 1 property (< 2)
|
|
109
|
+
* ```
|
|
110
|
+
*
|
|
111
|
+
* ### Use Cases
|
|
112
|
+
*
|
|
113
|
+
* - **Required Data**: Ensure objects have minimum content
|
|
114
|
+
* - **Non-Empty Objects**: Prevent empty dynamic objects
|
|
115
|
+
* - **Business Rules**: Enforce minimum configuration requirements
|
|
116
|
+
* - **API Validation**: Require sufficient filter/search criteria
|
|
117
|
+
* - **Data Quality**: Ensure objects contain meaningful data
|
|
118
|
+
*
|
|
119
|
+
* ### Filter Validation
|
|
120
|
+
*
|
|
121
|
+
* ```typescript
|
|
122
|
+
* class QueryModel {
|
|
123
|
+
* @MinProperties(1)
|
|
124
|
+
* filters: Record<string, string>;
|
|
125
|
+
* // Must specify at least one filter
|
|
60
126
|
* }
|
|
61
127
|
* ```
|
|
62
128
|
*
|
|
63
|
-
*
|
|
129
|
+
* ### Combining with AdditionalProperties
|
|
130
|
+
*
|
|
131
|
+
* ```typescript
|
|
132
|
+
* class FlexibleModel {
|
|
133
|
+
* @Property()
|
|
134
|
+
* id: string;
|
|
135
|
+
*
|
|
136
|
+
* @MinProperties(3)
|
|
137
|
+
* @AdditionalProperties({ type: "string" })
|
|
138
|
+
* // 1 defined property + at least 2 additional properties = 3 minimum
|
|
139
|
+
* }
|
|
140
|
+
* ```
|
|
141
|
+
*
|
|
142
|
+
* ### Important Notes
|
|
143
|
+
*
|
|
144
|
+
* - The value must be a **non-negative integer** (0 or greater)
|
|
145
|
+
* - Throws an error if a negative value is provided
|
|
146
|
+
* - Omitting `@MinProperties()` is equivalent to `@MinProperties(0)` (no minimum)
|
|
147
|
+
* - Counts all properties, including defined and additional ones
|
|
148
|
+
* - Objects with exactly minProperties count are valid (inclusive)
|
|
149
|
+
* - Can be combined with custom error messages using ajv-errors
|
|
150
|
+
*
|
|
151
|
+
* ### Default Behavior
|
|
152
|
+
*
|
|
153
|
+
* Without `@MinProperties()`, empty objects are valid:
|
|
154
|
+
* ```typescript
|
|
155
|
+
* data: Record<string, any>;
|
|
156
|
+
* // Valid: {}, { a: 1 }, { a: 1, b: 2 }, etc.
|
|
157
|
+
* ```
|
|
158
|
+
*
|
|
159
|
+
* With `@MinProperties(1)`, empty objects are rejected:
|
|
160
|
+
* ```typescript
|
|
161
|
+
* @MinProperties(1)
|
|
162
|
+
* data: Record<string, any>;
|
|
163
|
+
* // Invalid: {}
|
|
164
|
+
* // Valid: { a: 1 }, { a: 1, b: 2 }, etc.
|
|
165
|
+
* ```
|
|
166
|
+
*
|
|
167
|
+
* @param minProperties - Minimum number of properties required (must be non-negative)
|
|
168
|
+
*
|
|
64
169
|
* @decorator
|
|
65
170
|
* @validation
|
|
66
|
-
* @
|
|
67
|
-
* @schema
|
|
68
|
-
* @input
|
|
69
|
-
* @collections
|
|
70
|
-
* @ajv-errors
|
|
171
|
+
* @public
|
|
71
172
|
*/
|
|
72
173
|
export const MinProperties = withErrorMsg("minProperties", (minProperties) => {
|
|
73
174
|
if (minProperties < 0) {
|