@kravc/schema 2.7.6 → 2.8.0-alpha.0
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/README.md +19 -14
- package/dist/CredentialFactory.d.ts +345 -0
- package/dist/CredentialFactory.d.ts.map +1 -0
- package/dist/CredentialFactory.js +381 -0
- package/dist/CredentialFactory.js.map +1 -0
- package/dist/Schema.d.ts +448 -0
- package/dist/Schema.d.ts.map +1 -0
- package/dist/Schema.js +506 -0
- package/dist/Schema.js.map +1 -0
- package/dist/ValidationError.d.ts +70 -0
- package/dist/ValidationError.d.ts.map +1 -0
- package/dist/ValidationError.js +78 -0
- package/dist/ValidationError.js.map +1 -0
- package/dist/Validator.d.ts +483 -0
- package/dist/Validator.d.ts.map +1 -0
- package/dist/Validator.js +570 -0
- package/dist/Validator.js.map +1 -0
- package/dist/helpers/JsonSchema.d.ts +99 -0
- package/dist/helpers/JsonSchema.d.ts.map +1 -0
- package/dist/helpers/JsonSchema.js +3 -0
- package/dist/helpers/JsonSchema.js.map +1 -0
- package/dist/helpers/cleanupAttributes.d.ts +34 -0
- package/dist/helpers/cleanupAttributes.d.ts.map +1 -0
- package/dist/helpers/cleanupAttributes.js +113 -0
- package/dist/helpers/cleanupAttributes.js.map +1 -0
- package/dist/helpers/cleanupNulls.d.ts +27 -0
- package/dist/helpers/cleanupNulls.d.ts.map +1 -0
- package/dist/helpers/cleanupNulls.js +96 -0
- package/dist/helpers/cleanupNulls.js.map +1 -0
- package/dist/helpers/getReferenceIds.d.ts +169 -0
- package/dist/helpers/getReferenceIds.d.ts.map +1 -0
- package/dist/helpers/getReferenceIds.js +241 -0
- package/dist/helpers/getReferenceIds.js.map +1 -0
- package/dist/helpers/got.d.ts +60 -0
- package/dist/helpers/got.d.ts.map +1 -0
- package/dist/helpers/got.js +72 -0
- package/dist/helpers/got.js.map +1 -0
- package/dist/helpers/mapObjectProperties.d.ts +150 -0
- package/dist/helpers/mapObjectProperties.d.ts.map +1 -0
- package/dist/helpers/mapObjectProperties.js +229 -0
- package/dist/helpers/mapObjectProperties.js.map +1 -0
- package/dist/helpers/normalizeAttributes.d.ts +213 -0
- package/dist/helpers/normalizeAttributes.d.ts.map +1 -0
- package/dist/helpers/normalizeAttributes.js +243 -0
- package/dist/helpers/normalizeAttributes.js.map +1 -0
- package/dist/helpers/normalizeProperties.d.ts +168 -0
- package/dist/helpers/normalizeProperties.d.ts.map +1 -0
- package/dist/helpers/normalizeProperties.js +223 -0
- package/dist/helpers/normalizeProperties.js.map +1 -0
- package/dist/helpers/normalizeRequired.d.ts +159 -0
- package/dist/helpers/normalizeRequired.d.ts.map +1 -0
- package/dist/helpers/normalizeRequired.js +206 -0
- package/dist/helpers/normalizeRequired.js.map +1 -0
- package/dist/helpers/normalizeType.d.ts +81 -0
- package/dist/helpers/normalizeType.d.ts.map +1 -0
- package/dist/helpers/normalizeType.js +210 -0
- package/dist/helpers/normalizeType.js.map +1 -0
- package/dist/helpers/nullifyEmptyValues.d.ts +139 -0
- package/dist/helpers/nullifyEmptyValues.d.ts.map +1 -0
- package/dist/helpers/nullifyEmptyValues.js +191 -0
- package/dist/helpers/nullifyEmptyValues.js.map +1 -0
- package/dist/helpers/removeRequiredAndDefault.d.ts +106 -0
- package/dist/helpers/removeRequiredAndDefault.d.ts.map +1 -0
- package/dist/helpers/removeRequiredAndDefault.js +138 -0
- package/dist/helpers/removeRequiredAndDefault.js.map +1 -0
- package/dist/helpers/validateId.d.ts +39 -0
- package/dist/helpers/validateId.d.ts.map +1 -0
- package/dist/helpers/validateId.js +51 -0
- package/dist/helpers/validateId.js.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +17 -0
- package/dist/index.js.map +1 -0
- package/dist/ld/documentLoader.d.ts +8 -0
- package/dist/ld/documentLoader.d.ts.map +1 -0
- package/dist/ld/documentLoader.js +24 -0
- package/dist/ld/documentLoader.js.map +1 -0
- package/dist/ld/getLinkedDataAttributeType.d.ts +10 -0
- package/dist/ld/getLinkedDataAttributeType.d.ts.map +1 -0
- package/dist/ld/getLinkedDataAttributeType.js +32 -0
- package/dist/ld/getLinkedDataAttributeType.js.map +1 -0
- package/dist/ld/getLinkedDataContext.d.ts +19 -0
- package/dist/ld/getLinkedDataContext.d.ts.map +1 -0
- package/dist/ld/getLinkedDataContext.js +50 -0
- package/dist/ld/getLinkedDataContext.js.map +1 -0
- package/eslint.config.mjs +32 -52
- package/examples/credentials/createAccountCredential.ts +27 -0
- package/examples/credentials/createMineSweeperScoreCredential.ts +115 -0
- package/examples/index.ts +7 -0
- package/examples/schemas/FavoriteItemSchema.ts +27 -0
- package/examples/{Preferences.yaml → schemas/Preferences.yaml} +2 -0
- package/examples/schemas/PreferencesSchema.ts +29 -0
- package/examples/schemas/ProfileSchema.ts +91 -0
- package/examples/schemas/Status.yaml +3 -0
- package/examples/schemas/StatusSchema.ts +12 -0
- package/jest.config.mjs +5 -0
- package/package.json +27 -20
- package/src/CredentialFactory.ts +392 -0
- package/src/Schema.ts +583 -0
- package/src/ValidationError.ts +90 -0
- package/src/Validator.ts +603 -0
- package/src/__tests__/CredentialFactory.test.ts +588 -0
- package/src/__tests__/Schema.test.ts +371 -0
- package/src/__tests__/ValidationError.test.ts +235 -0
- package/src/__tests__/Validator.test.ts +787 -0
- package/src/helpers/JsonSchema.ts +119 -0
- package/src/helpers/__tests__/cleanupAttributes.test.ts +943 -0
- package/src/helpers/__tests__/cleanupNulls.test.ts +772 -0
- package/src/helpers/__tests__/getReferenceIds.test.ts +975 -0
- package/src/helpers/__tests__/got.test.ts +193 -0
- package/src/helpers/__tests__/mapObjectProperties.test.ts +1126 -0
- package/src/helpers/__tests__/normalizeAttributes.test.ts +1435 -0
- package/src/helpers/__tests__/normalizeProperties.test.ts +727 -0
- package/src/helpers/__tests__/normalizeRequired.test.ts +669 -0
- package/src/helpers/__tests__/normalizeType.test.ts +772 -0
- package/src/helpers/__tests__/nullifyEmptyValues.test.ts +735 -0
- package/src/helpers/__tests__/removeRequiredAndDefault.test.ts +734 -0
- package/src/helpers/__tests__/validateId.test.ts +118 -0
- package/src/helpers/cleanupAttributes.ts +151 -0
- package/src/helpers/cleanupNulls.ts +106 -0
- package/src/helpers/getReferenceIds.ts +273 -0
- package/src/helpers/got.ts +73 -0
- package/src/helpers/mapObjectProperties.ts +272 -0
- package/src/helpers/normalizeAttributes.ts +247 -0
- package/src/helpers/normalizeProperties.ts +249 -0
- package/src/helpers/normalizeRequired.ts +233 -0
- package/src/helpers/normalizeType.ts +235 -0
- package/src/helpers/nullifyEmptyValues.ts +207 -0
- package/src/helpers/removeRequiredAndDefault.ts +151 -0
- package/src/helpers/validateId.ts +53 -0
- package/src/index.ts +13 -0
- package/src/ld/__tests__/documentLoader.test.ts +57 -0
- package/src/ld/__tests__/getLinkedDataAttributeType.test.ts +212 -0
- package/src/ld/__tests__/getLinkedDataContext.test.ts +378 -0
- package/src/ld/documentLoader.ts +28 -0
- package/src/ld/getLinkedDataAttributeType.ts +46 -0
- package/src/ld/getLinkedDataContext.ts +80 -0
- package/tsconfig.json +27 -0
- package/types/credentials-context.d.ts +14 -0
- package/types/security-context.d.ts +6 -0
- package/examples/Status.yaml +0 -3
- package/examples/createAccountCredential.js +0 -27
- package/examples/createMineSweeperScoreCredential.js +0 -63
- package/examples/index.js +0 -9
- package/src/CredentialFactory.js +0 -67
- package/src/CredentialFactory.spec.js +0 -131
- package/src/Schema.js +0 -104
- package/src/Schema.spec.js +0 -172
- package/src/ValidationError.js +0 -31
- package/src/Validator.js +0 -128
- package/src/Validator.spec.js +0 -355
- package/src/helpers/cleanupAttributes.js +0 -71
- package/src/helpers/cleanupNulls.js +0 -42
- package/src/helpers/getReferenceIds.js +0 -71
- package/src/helpers/mapObject.js +0 -65
- package/src/helpers/normalizeAttributes.js +0 -28
- package/src/helpers/normalizeProperties.js +0 -61
- package/src/helpers/normalizeRequired.js +0 -37
- package/src/helpers/normalizeType.js +0 -41
- package/src/helpers/nullifyEmptyValues.js +0 -57
- package/src/helpers/removeRequiredAndDefault.js +0 -30
- package/src/helpers/validateId.js +0 -19
- package/src/index.d.ts +0 -25
- package/src/index.js +0 -8
- package/src/ld/documentLoader.js +0 -25
- package/src/ld/documentLoader.spec.js +0 -12
- package/src/ld/getLinkedDataContext.js +0 -63
- package/src/ld/getLinkedDataType.js +0 -38
- /package/examples/{FavoriteItem.yaml → schemas/FavoriteItem.yaml} +0 -0
- /package/examples/{Profile.yaml → schemas/Profile.yaml} +0 -0
|
@@ -0,0 +1,669 @@
|
|
|
1
|
+
import { get } from 'lodash';
|
|
2
|
+
import normalizeRequired from '../normalizeRequired';
|
|
3
|
+
import type {
|
|
4
|
+
EnumSchema,
|
|
5
|
+
ObjectSchema,
|
|
6
|
+
ObjectPropertySchema,
|
|
7
|
+
ArrayPropertySchema,
|
|
8
|
+
ReferencePropertySchema,
|
|
9
|
+
PropertySchema,
|
|
10
|
+
} from '../JsonSchema';
|
|
11
|
+
|
|
12
|
+
describe('normalizeRequired(schema)', () => {
|
|
13
|
+
describe('basic functionality', () => {
|
|
14
|
+
it('should add required fields to required array and set x-required flag', () => {
|
|
15
|
+
const schema: ObjectSchema = {
|
|
16
|
+
id: 'test-schema',
|
|
17
|
+
properties: {
|
|
18
|
+
requiredField: {
|
|
19
|
+
type: 'string',
|
|
20
|
+
required: true,
|
|
21
|
+
},
|
|
22
|
+
optionalField: {
|
|
23
|
+
type: 'string',
|
|
24
|
+
required: false,
|
|
25
|
+
},
|
|
26
|
+
},
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
normalizeRequired(schema);
|
|
30
|
+
|
|
31
|
+
expect(schema.required).toEqual(['requiredField']);
|
|
32
|
+
expect(schema.properties.requiredField['x-required']).toBe(true);
|
|
33
|
+
expect(schema.properties.requiredField.required).toBeUndefined();
|
|
34
|
+
expect(schema.properties.optionalField['x-required']).toBeUndefined();
|
|
35
|
+
expect(schema.properties.optionalField.required).toBeUndefined();
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
it('should handle multiple required fields', () => {
|
|
39
|
+
const schema: ObjectSchema = {
|
|
40
|
+
id: 'test-schema',
|
|
41
|
+
properties: {
|
|
42
|
+
field1: {
|
|
43
|
+
type: 'string',
|
|
44
|
+
required: true,
|
|
45
|
+
},
|
|
46
|
+
field2: {
|
|
47
|
+
type: 'number',
|
|
48
|
+
required: true,
|
|
49
|
+
},
|
|
50
|
+
field3: {
|
|
51
|
+
type: 'boolean',
|
|
52
|
+
required: true,
|
|
53
|
+
},
|
|
54
|
+
optionalField: {
|
|
55
|
+
type: 'string',
|
|
56
|
+
},
|
|
57
|
+
},
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
normalizeRequired(schema);
|
|
61
|
+
|
|
62
|
+
expect(schema.required).toEqual(['field1', 'field2', 'field3']);
|
|
63
|
+
expect(schema.properties.field1['x-required']).toBe(true);
|
|
64
|
+
expect(schema.properties.field2['x-required']).toBe(true);
|
|
65
|
+
expect(schema.properties.field3['x-required']).toBe(true);
|
|
66
|
+
expect(schema.properties.optionalField['x-required']).toBeUndefined();
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
it('should not set required array when no fields are required', () => {
|
|
70
|
+
const schema: ObjectSchema = {
|
|
71
|
+
id: 'test-schema',
|
|
72
|
+
properties: {
|
|
73
|
+
field1: {
|
|
74
|
+
type: 'string',
|
|
75
|
+
},
|
|
76
|
+
field2: {
|
|
77
|
+
type: 'number',
|
|
78
|
+
},
|
|
79
|
+
},
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
normalizeRequired(schema);
|
|
83
|
+
|
|
84
|
+
expect(schema.required).toBeUndefined();
|
|
85
|
+
expect(schema.properties.field1['x-required']).toBeUndefined();
|
|
86
|
+
expect(schema.properties.field2['x-required']).toBeUndefined();
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
it('should delete required property from all property schemas', () => {
|
|
90
|
+
const schema: ObjectSchema = {
|
|
91
|
+
id: 'test-schema',
|
|
92
|
+
properties: {
|
|
93
|
+
requiredField: {
|
|
94
|
+
type: 'string',
|
|
95
|
+
required: true,
|
|
96
|
+
},
|
|
97
|
+
optionalField: {
|
|
98
|
+
type: 'string',
|
|
99
|
+
required: false,
|
|
100
|
+
},
|
|
101
|
+
},
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
normalizeRequired(schema);
|
|
105
|
+
|
|
106
|
+
expect(schema.properties.requiredField.required).toBeUndefined();
|
|
107
|
+
expect(schema.properties.optionalField.required).toBeUndefined();
|
|
108
|
+
});
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
describe('nested object properties', () => {
|
|
112
|
+
it('should recursively normalize required fields in nested objects', () => {
|
|
113
|
+
const schema: ObjectSchema = {
|
|
114
|
+
id: 'test-schema',
|
|
115
|
+
properties: {
|
|
116
|
+
nestedObject: {
|
|
117
|
+
type: 'object',
|
|
118
|
+
required: true,
|
|
119
|
+
properties: {
|
|
120
|
+
nestedRequired: {
|
|
121
|
+
type: 'string',
|
|
122
|
+
required: true,
|
|
123
|
+
},
|
|
124
|
+
nestedOptional: {
|
|
125
|
+
type: 'string',
|
|
126
|
+
},
|
|
127
|
+
},
|
|
128
|
+
},
|
|
129
|
+
},
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
normalizeRequired(schema);
|
|
133
|
+
|
|
134
|
+
expect(schema.required).toEqual(['nestedObject']);
|
|
135
|
+
expect(schema.properties.nestedObject['x-required']).toBe(true);
|
|
136
|
+
|
|
137
|
+
const nested = schema.properties.nestedObject as ObjectPropertySchema;
|
|
138
|
+
// The function sets required on the nested object schema itself
|
|
139
|
+
expect(nested.required).toEqual(['nestedRequired']);
|
|
140
|
+
expect(nested.properties!.nestedRequired['x-required']).toBe(true);
|
|
141
|
+
expect(nested.properties!.nestedRequired.required).toBeUndefined();
|
|
142
|
+
expect(nested.properties!.nestedOptional['x-required']).toBeUndefined();
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
it('should handle deeply nested objects', () => {
|
|
146
|
+
const schema: ObjectSchema = {
|
|
147
|
+
id: 'test-schema',
|
|
148
|
+
properties: {
|
|
149
|
+
level1: {
|
|
150
|
+
type: 'object',
|
|
151
|
+
properties: {
|
|
152
|
+
level2: {
|
|
153
|
+
type: 'object',
|
|
154
|
+
required: true,
|
|
155
|
+
properties: {
|
|
156
|
+
level3: {
|
|
157
|
+
type: 'object',
|
|
158
|
+
required: true,
|
|
159
|
+
properties: {
|
|
160
|
+
deepField: {
|
|
161
|
+
type: 'string',
|
|
162
|
+
required: true,
|
|
163
|
+
},
|
|
164
|
+
},
|
|
165
|
+
},
|
|
166
|
+
},
|
|
167
|
+
},
|
|
168
|
+
},
|
|
169
|
+
},
|
|
170
|
+
},
|
|
171
|
+
};
|
|
172
|
+
|
|
173
|
+
normalizeRequired(schema);
|
|
174
|
+
|
|
175
|
+
const level1 = schema.properties.level1 as ObjectPropertySchema;
|
|
176
|
+
const level2 = level1.properties!.level2 as ObjectPropertySchema;
|
|
177
|
+
const level3 = level2.properties!.level3 as ObjectPropertySchema;
|
|
178
|
+
|
|
179
|
+
expect(level2.required).toEqual(['level3']);
|
|
180
|
+
expect(level2.properties!.level3['x-required']).toBe(true);
|
|
181
|
+
expect(level3.required).toEqual(['deepField']);
|
|
182
|
+
expect(level3.properties!.deepField['x-required']).toBe(true);
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
it('should handle nested object without required fields', () => {
|
|
186
|
+
const schema: ObjectSchema = {
|
|
187
|
+
id: 'test-schema',
|
|
188
|
+
properties: {
|
|
189
|
+
nestedObject: {
|
|
190
|
+
type: 'object',
|
|
191
|
+
properties: {
|
|
192
|
+
field1: {
|
|
193
|
+
type: 'string',
|
|
194
|
+
},
|
|
195
|
+
field2: {
|
|
196
|
+
type: 'number',
|
|
197
|
+
},
|
|
198
|
+
},
|
|
199
|
+
},
|
|
200
|
+
},
|
|
201
|
+
};
|
|
202
|
+
|
|
203
|
+
normalizeRequired(schema);
|
|
204
|
+
|
|
205
|
+
const nested = schema.properties.nestedObject as ObjectPropertySchema;
|
|
206
|
+
expect(nested.required).toBeUndefined();
|
|
207
|
+
expect(nested.properties!.field1['x-required']).toBeUndefined();
|
|
208
|
+
expect(nested.properties!.field2['x-required']).toBeUndefined();
|
|
209
|
+
});
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
describe('array properties', () => {
|
|
213
|
+
it('should recursively normalize required fields in array items', () => {
|
|
214
|
+
const schema: ObjectSchema = {
|
|
215
|
+
id: 'test-schema',
|
|
216
|
+
properties: {
|
|
217
|
+
arrayField: {
|
|
218
|
+
type: 'array',
|
|
219
|
+
required: true,
|
|
220
|
+
items: {
|
|
221
|
+
type: 'object',
|
|
222
|
+
properties: {
|
|
223
|
+
itemRequired: {
|
|
224
|
+
type: 'string',
|
|
225
|
+
required: true,
|
|
226
|
+
},
|
|
227
|
+
itemOptional: {
|
|
228
|
+
type: 'string',
|
|
229
|
+
},
|
|
230
|
+
},
|
|
231
|
+
},
|
|
232
|
+
},
|
|
233
|
+
},
|
|
234
|
+
};
|
|
235
|
+
|
|
236
|
+
normalizeRequired(schema);
|
|
237
|
+
|
|
238
|
+
expect(schema.required).toEqual(['arrayField']);
|
|
239
|
+
expect(schema.properties.arrayField['x-required']).toBe(true);
|
|
240
|
+
expect(schema.properties.arrayField.required).toBeUndefined();
|
|
241
|
+
|
|
242
|
+
const arrayField = schema.properties.arrayField as ArrayPropertySchema;
|
|
243
|
+
const items = arrayField.items as ObjectPropertySchema;
|
|
244
|
+
expect(items.required).toEqual(['itemRequired']);
|
|
245
|
+
expect(items.properties!.itemRequired['x-required']).toBe(true);
|
|
246
|
+
expect(items.properties!.itemRequired.required).toBeUndefined();
|
|
247
|
+
expect(items.properties!.itemOptional['x-required']).toBeUndefined();
|
|
248
|
+
});
|
|
249
|
+
|
|
250
|
+
it('should handle array items with reference schema', () => {
|
|
251
|
+
const schema: ObjectSchema = {
|
|
252
|
+
id: 'test-schema',
|
|
253
|
+
properties: {
|
|
254
|
+
arrayField: {
|
|
255
|
+
type: 'array',
|
|
256
|
+
items: {
|
|
257
|
+
$ref: '#/definitions/SomeSchema',
|
|
258
|
+
required: true,
|
|
259
|
+
} as ReferencePropertySchema,
|
|
260
|
+
},
|
|
261
|
+
},
|
|
262
|
+
};
|
|
263
|
+
|
|
264
|
+
normalizeRequired(schema);
|
|
265
|
+
|
|
266
|
+
const arrayField = schema.properties.arrayField as ArrayPropertySchema;
|
|
267
|
+
const items = arrayField.items as ReferencePropertySchema;
|
|
268
|
+
// ReferencePropertySchema without properties returns early, so required flag is not processed
|
|
269
|
+
// The function only processes schemas with properties
|
|
270
|
+
expect(items.required).toBe(true); // Still present since function returns early for refs without properties
|
|
271
|
+
});
|
|
272
|
+
|
|
273
|
+
it('should handle array property without items', () => {
|
|
274
|
+
const schema: ObjectSchema = {
|
|
275
|
+
id: 'test-schema',
|
|
276
|
+
properties: {
|
|
277
|
+
arrayField: {
|
|
278
|
+
type: 'array',
|
|
279
|
+
required: true,
|
|
280
|
+
} as ArrayPropertySchema,
|
|
281
|
+
},
|
|
282
|
+
};
|
|
283
|
+
|
|
284
|
+
normalizeRequired(schema);
|
|
285
|
+
|
|
286
|
+
expect(schema.required).toEqual(['arrayField']);
|
|
287
|
+
expect(schema.properties.arrayField['x-required']).toBe(true);
|
|
288
|
+
expect(schema.properties.arrayField.required).toBeUndefined();
|
|
289
|
+
});
|
|
290
|
+
|
|
291
|
+
it('should handle nested arrays', () => {
|
|
292
|
+
const schema: ObjectSchema = {
|
|
293
|
+
id: 'test-schema',
|
|
294
|
+
properties: {
|
|
295
|
+
outerArray: {
|
|
296
|
+
type: 'array',
|
|
297
|
+
items: {
|
|
298
|
+
type: 'array',
|
|
299
|
+
items: {
|
|
300
|
+
type: 'object',
|
|
301
|
+
properties: {
|
|
302
|
+
deepField: {
|
|
303
|
+
type: 'string',
|
|
304
|
+
required: true,
|
|
305
|
+
},
|
|
306
|
+
},
|
|
307
|
+
},
|
|
308
|
+
},
|
|
309
|
+
} as unknown as ArrayPropertySchema,
|
|
310
|
+
},
|
|
311
|
+
};
|
|
312
|
+
|
|
313
|
+
normalizeRequired(schema);
|
|
314
|
+
|
|
315
|
+
const outerArray = schema.properties.outerArray as ArrayPropertySchema;
|
|
316
|
+
const innerArray = outerArray.items as ArrayPropertySchema;
|
|
317
|
+
const items = innerArray.items as ObjectPropertySchema;
|
|
318
|
+
// When normalizeRequired is called on the inner ArrayPropertySchema (innerArray),
|
|
319
|
+
// it returns early because ArrayPropertySchema doesn't have properties.
|
|
320
|
+
// The function only processes ObjectSchema/ObjectPropertySchema with properties.
|
|
321
|
+
// So nested arrays are not fully processed - this is a limitation of the current implementation.
|
|
322
|
+
// The items of the inner array are not processed because normalizeRequired returns early
|
|
323
|
+
// when called on the innerArray (which is an ArrayPropertySchema without properties).
|
|
324
|
+
expect(items.required).toBeUndefined();
|
|
325
|
+
expect(items.properties!.deepField.required).toBe(true); // Still present, not processed
|
|
326
|
+
});
|
|
327
|
+
|
|
328
|
+
it('should handle array with object items containing nested arrays', () => {
|
|
329
|
+
const schema: ObjectSchema = {
|
|
330
|
+
id: 'test-schema',
|
|
331
|
+
properties: {
|
|
332
|
+
complexArray: {
|
|
333
|
+
type: 'array',
|
|
334
|
+
items: {
|
|
335
|
+
type: 'object',
|
|
336
|
+
properties: {
|
|
337
|
+
nestedArray: {
|
|
338
|
+
type: 'array',
|
|
339
|
+
required: true,
|
|
340
|
+
items: {
|
|
341
|
+
type: 'object',
|
|
342
|
+
properties: {
|
|
343
|
+
field: {
|
|
344
|
+
type: 'string',
|
|
345
|
+
required: true,
|
|
346
|
+
},
|
|
347
|
+
},
|
|
348
|
+
},
|
|
349
|
+
},
|
|
350
|
+
},
|
|
351
|
+
},
|
|
352
|
+
},
|
|
353
|
+
},
|
|
354
|
+
};
|
|
355
|
+
|
|
356
|
+
normalizeRequired(schema);
|
|
357
|
+
|
|
358
|
+
const complexArray = schema.properties.complexArray as ArrayPropertySchema;
|
|
359
|
+
const items = complexArray.items as ObjectPropertySchema;
|
|
360
|
+
expect(items.required).toEqual(['nestedArray']);
|
|
361
|
+
expect(items.properties!.nestedArray['x-required']).toBe(true);
|
|
362
|
+
|
|
363
|
+
const nestedArray = items.properties!.nestedArray as ArrayPropertySchema;
|
|
364
|
+
const nestedItems = nestedArray.items as ObjectPropertySchema;
|
|
365
|
+
expect(nestedItems.required).toEqual(['field']);
|
|
366
|
+
expect(nestedItems.properties!.field['x-required']).toBe(true);
|
|
367
|
+
});
|
|
368
|
+
});
|
|
369
|
+
|
|
370
|
+
describe('complex nested structures', () => {
|
|
371
|
+
it('should handle mix of objects, arrays, and primitives with required fields', () => {
|
|
372
|
+
const schema: ObjectSchema = {
|
|
373
|
+
id: 'test-schema',
|
|
374
|
+
properties: {
|
|
375
|
+
requiredString: {
|
|
376
|
+
type: 'string',
|
|
377
|
+
required: true,
|
|
378
|
+
},
|
|
379
|
+
nestedObject: {
|
|
380
|
+
type: 'object',
|
|
381
|
+
required: true,
|
|
382
|
+
properties: {
|
|
383
|
+
nestedRequired: {
|
|
384
|
+
type: 'number',
|
|
385
|
+
required: true,
|
|
386
|
+
},
|
|
387
|
+
nestedArray: {
|
|
388
|
+
type: 'array',
|
|
389
|
+
items: {
|
|
390
|
+
type: 'object',
|
|
391
|
+
properties: {
|
|
392
|
+
arrayItemRequired: {
|
|
393
|
+
type: 'boolean',
|
|
394
|
+
required: true,
|
|
395
|
+
},
|
|
396
|
+
},
|
|
397
|
+
},
|
|
398
|
+
},
|
|
399
|
+
},
|
|
400
|
+
},
|
|
401
|
+
arrayField: {
|
|
402
|
+
type: 'array',
|
|
403
|
+
items: {
|
|
404
|
+
type: 'object',
|
|
405
|
+
required: true,
|
|
406
|
+
properties: {
|
|
407
|
+
itemField: {
|
|
408
|
+
type: 'string',
|
|
409
|
+
required: true,
|
|
410
|
+
},
|
|
411
|
+
},
|
|
412
|
+
},
|
|
413
|
+
},
|
|
414
|
+
},
|
|
415
|
+
};
|
|
416
|
+
|
|
417
|
+
normalizeRequired(schema);
|
|
418
|
+
|
|
419
|
+
expect(schema.required).toEqual(['requiredString', 'nestedObject']);
|
|
420
|
+
|
|
421
|
+
const nestedObject = schema.properties.nestedObject as ObjectPropertySchema;
|
|
422
|
+
expect(nestedObject.required).toEqual(['nestedRequired']);
|
|
423
|
+
expect(nestedObject.properties!.nestedRequired['x-required']).toBe(true);
|
|
424
|
+
|
|
425
|
+
const nestedArray = nestedObject.properties!.nestedArray as ArrayPropertySchema;
|
|
426
|
+
const nestedArrayItems = nestedArray.items as ObjectPropertySchema;
|
|
427
|
+
expect(nestedArrayItems.required).toEqual(['arrayItemRequired']);
|
|
428
|
+
expect(nestedArrayItems.properties!.arrayItemRequired['x-required']).toBe(true);
|
|
429
|
+
|
|
430
|
+
const arrayField = schema.properties.arrayField as ArrayPropertySchema;
|
|
431
|
+
const arrayItems = arrayField.items as ObjectPropertySchema;
|
|
432
|
+
expect(arrayItems.required).toEqual(['itemField']);
|
|
433
|
+
expect(arrayItems.properties!.itemField['x-required']).toBe(true);
|
|
434
|
+
});
|
|
435
|
+
|
|
436
|
+
it('should handle object with array containing objects with nested objects', () => {
|
|
437
|
+
const schema: ObjectSchema = {
|
|
438
|
+
id: 'test-schema',
|
|
439
|
+
properties: {
|
|
440
|
+
users: {
|
|
441
|
+
type: 'array',
|
|
442
|
+
items: {
|
|
443
|
+
type: 'object',
|
|
444
|
+
properties: {
|
|
445
|
+
name: {
|
|
446
|
+
type: 'string',
|
|
447
|
+
required: true,
|
|
448
|
+
},
|
|
449
|
+
address: {
|
|
450
|
+
type: 'object',
|
|
451
|
+
required: true,
|
|
452
|
+
properties: {
|
|
453
|
+
street: {
|
|
454
|
+
type: 'string',
|
|
455
|
+
required: true,
|
|
456
|
+
},
|
|
457
|
+
city: {
|
|
458
|
+
type: 'string',
|
|
459
|
+
},
|
|
460
|
+
},
|
|
461
|
+
},
|
|
462
|
+
},
|
|
463
|
+
},
|
|
464
|
+
},
|
|
465
|
+
},
|
|
466
|
+
};
|
|
467
|
+
|
|
468
|
+
normalizeRequired(schema);
|
|
469
|
+
|
|
470
|
+
const users = schema.properties.users as ArrayPropertySchema;
|
|
471
|
+
const userItems = users.items as ObjectPropertySchema;
|
|
472
|
+
expect(userItems.required).toEqual(['name', 'address']);
|
|
473
|
+
expect(userItems.properties!.name['x-required']).toBe(true);
|
|
474
|
+
expect(userItems.properties!.address['x-required']).toBe(true);
|
|
475
|
+
|
|
476
|
+
const address = userItems.properties!.address as ObjectPropertySchema;
|
|
477
|
+
expect(address.required).toEqual(['street']);
|
|
478
|
+
expect(address.properties!.street['x-required']).toBe(true);
|
|
479
|
+
expect(address.properties!.city['x-required']).toBeUndefined();
|
|
480
|
+
});
|
|
481
|
+
});
|
|
482
|
+
|
|
483
|
+
describe('edge cases', () => {
|
|
484
|
+
it('should handle EnumSchema input', () => {
|
|
485
|
+
const schema: EnumSchema = {
|
|
486
|
+
enum: ['value1', 'value2', 'value3'],
|
|
487
|
+
type: 'string',
|
|
488
|
+
required: true,
|
|
489
|
+
};
|
|
490
|
+
|
|
491
|
+
normalizeRequired(schema);
|
|
492
|
+
|
|
493
|
+
// EnumSchema returns early, so no changes should be made
|
|
494
|
+
expect(schema.required).toBe(true);
|
|
495
|
+
expect(schema['x-required']).toBeUndefined();
|
|
496
|
+
});
|
|
497
|
+
|
|
498
|
+
it('should handle schema without properties', () => {
|
|
499
|
+
const schema: ObjectSchema = {
|
|
500
|
+
id: 'test-schema',
|
|
501
|
+
} as ObjectSchema;
|
|
502
|
+
|
|
503
|
+
normalizeRequired(schema);
|
|
504
|
+
|
|
505
|
+
expect(schema.required).toBeUndefined();
|
|
506
|
+
});
|
|
507
|
+
|
|
508
|
+
it('should handle schema with empty properties object', () => {
|
|
509
|
+
const schema: ObjectSchema = {
|
|
510
|
+
id: 'test-schema',
|
|
511
|
+
properties: {},
|
|
512
|
+
};
|
|
513
|
+
|
|
514
|
+
normalizeRequired(schema);
|
|
515
|
+
|
|
516
|
+
expect(schema.required).toBeUndefined();
|
|
517
|
+
});
|
|
518
|
+
|
|
519
|
+
it('should handle ObjectPropertySchema input', () => {
|
|
520
|
+
const schema: ObjectPropertySchema = {
|
|
521
|
+
type: 'object',
|
|
522
|
+
properties: {
|
|
523
|
+
field1: {
|
|
524
|
+
type: 'string',
|
|
525
|
+
required: true,
|
|
526
|
+
},
|
|
527
|
+
field2: {
|
|
528
|
+
type: 'number',
|
|
529
|
+
},
|
|
530
|
+
},
|
|
531
|
+
};
|
|
532
|
+
|
|
533
|
+
normalizeRequired(schema);
|
|
534
|
+
|
|
535
|
+
expect(schema.required).toEqual(['field1']);
|
|
536
|
+
expect(schema.properties!.field1['x-required']).toBe(true);
|
|
537
|
+
expect(schema.properties!.field2['x-required']).toBeUndefined();
|
|
538
|
+
});
|
|
539
|
+
|
|
540
|
+
it('should handle ReferencePropertySchema input', () => {
|
|
541
|
+
const schema: ReferencePropertySchema = {
|
|
542
|
+
$ref: '#/definitions/SomeSchema',
|
|
543
|
+
required: true,
|
|
544
|
+
};
|
|
545
|
+
|
|
546
|
+
normalizeRequired(schema);
|
|
547
|
+
|
|
548
|
+
// ReferencePropertySchema without properties returns early, so required flag is not processed
|
|
549
|
+
// The function only processes schemas with properties
|
|
550
|
+
expect(schema.required).toBe(true); // Still present since function returns early
|
|
551
|
+
expect(schema['x-required']).toBeUndefined();
|
|
552
|
+
});
|
|
553
|
+
|
|
554
|
+
it('should normalize required flag on reference properties', () => {
|
|
555
|
+
const schema: ObjectSchema = {
|
|
556
|
+
id: 'test-schema',
|
|
557
|
+
properties: {
|
|
558
|
+
refField: {
|
|
559
|
+
$ref: '#/definitions/SomeSchema',
|
|
560
|
+
required: true,
|
|
561
|
+
} as ReferencePropertySchema,
|
|
562
|
+
normalField: {
|
|
563
|
+
type: 'string',
|
|
564
|
+
required: true,
|
|
565
|
+
},
|
|
566
|
+
},
|
|
567
|
+
};
|
|
568
|
+
|
|
569
|
+
normalizeRequired(schema);
|
|
570
|
+
|
|
571
|
+
// Reference property required flag should be normalized (added to required array and removed from property)
|
|
572
|
+
expect(schema.required).toEqual(['refField', 'normalField']);
|
|
573
|
+
expect(schema.properties.refField.required).toBeUndefined(); // Removed after normalization
|
|
574
|
+
expect(schema.properties.refField['x-required']).toBe(true); // x-required flag set
|
|
575
|
+
|
|
576
|
+
// Normal field should be processed
|
|
577
|
+
expect(schema.properties.normalField['x-required']).toBe(true);
|
|
578
|
+
expect(schema.properties.normalField.required).toBeUndefined();
|
|
579
|
+
});
|
|
580
|
+
|
|
581
|
+
it('should handle property with required flag but no type', () => {
|
|
582
|
+
const schema: ObjectSchema = {
|
|
583
|
+
id: 'test-schema',
|
|
584
|
+
properties: {
|
|
585
|
+
field: {
|
|
586
|
+
required: true,
|
|
587
|
+
} as PropertySchema,
|
|
588
|
+
},
|
|
589
|
+
};
|
|
590
|
+
|
|
591
|
+
normalizeRequired(schema);
|
|
592
|
+
|
|
593
|
+
expect(schema.required).toEqual(['field']);
|
|
594
|
+
expect(schema.properties.field['x-required']).toBe(true);
|
|
595
|
+
expect(schema.properties.field.required).toBeUndefined();
|
|
596
|
+
});
|
|
597
|
+
|
|
598
|
+
it('should preserve other property attributes', () => {
|
|
599
|
+
const schema: ObjectSchema = {
|
|
600
|
+
id: 'test-schema',
|
|
601
|
+
properties: {
|
|
602
|
+
field: {
|
|
603
|
+
type: 'string',
|
|
604
|
+
required: true,
|
|
605
|
+
default: 'default-value',
|
|
606
|
+
description: 'Test field',
|
|
607
|
+
'x-title': 'Field Title',
|
|
608
|
+
},
|
|
609
|
+
},
|
|
610
|
+
};
|
|
611
|
+
|
|
612
|
+
normalizeRequired(schema);
|
|
613
|
+
|
|
614
|
+
expect(get(schema, 'properties.field.type')).toBe('string');
|
|
615
|
+
expect(schema.properties.field.default).toBe('default-value');
|
|
616
|
+
expect(schema.properties.field.description).toBe('Test field');
|
|
617
|
+
expect(schema.properties.field['x-title']).toBe('Field Title');
|
|
618
|
+
expect(schema.properties.field['x-required']).toBe(true);
|
|
619
|
+
expect(schema.properties.field.required).toBeUndefined();
|
|
620
|
+
});
|
|
621
|
+
|
|
622
|
+
it('should handle all fields as required', () => {
|
|
623
|
+
const schema: ObjectSchema = {
|
|
624
|
+
id: 'test-schema',
|
|
625
|
+
properties: {
|
|
626
|
+
field1: {
|
|
627
|
+
type: 'string',
|
|
628
|
+
required: true,
|
|
629
|
+
},
|
|
630
|
+
field2: {
|
|
631
|
+
type: 'number',
|
|
632
|
+
required: true,
|
|
633
|
+
},
|
|
634
|
+
field3: {
|
|
635
|
+
type: 'boolean',
|
|
636
|
+
required: true,
|
|
637
|
+
},
|
|
638
|
+
},
|
|
639
|
+
};
|
|
640
|
+
|
|
641
|
+
normalizeRequired(schema);
|
|
642
|
+
|
|
643
|
+
expect(schema.required).toEqual(['field1', 'field2', 'field3']);
|
|
644
|
+
expect(schema.properties.field1['x-required']).toBe(true);
|
|
645
|
+
expect(schema.properties.field2['x-required']).toBe(true);
|
|
646
|
+
expect(schema.properties.field3['x-required']).toBe(true);
|
|
647
|
+
});
|
|
648
|
+
|
|
649
|
+
it('should handle object with only optional fields', () => {
|
|
650
|
+
const schema: ObjectSchema = {
|
|
651
|
+
id: 'test-schema',
|
|
652
|
+
properties: {
|
|
653
|
+
field1: {
|
|
654
|
+
type: 'string',
|
|
655
|
+
},
|
|
656
|
+
field2: {
|
|
657
|
+
type: 'number',
|
|
658
|
+
},
|
|
659
|
+
},
|
|
660
|
+
};
|
|
661
|
+
|
|
662
|
+
normalizeRequired(schema);
|
|
663
|
+
|
|
664
|
+
expect(schema.required).toBeUndefined();
|
|
665
|
+
expect(schema.properties.field1['x-required']).toBeUndefined();
|
|
666
|
+
expect(schema.properties.field2['x-required']).toBeUndefined();
|
|
667
|
+
});
|
|
668
|
+
});
|
|
669
|
+
});
|