@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.
Files changed (170) hide show
  1. package/README.md +19 -14
  2. package/dist/CredentialFactory.d.ts +345 -0
  3. package/dist/CredentialFactory.d.ts.map +1 -0
  4. package/dist/CredentialFactory.js +381 -0
  5. package/dist/CredentialFactory.js.map +1 -0
  6. package/dist/Schema.d.ts +448 -0
  7. package/dist/Schema.d.ts.map +1 -0
  8. package/dist/Schema.js +506 -0
  9. package/dist/Schema.js.map +1 -0
  10. package/dist/ValidationError.d.ts +70 -0
  11. package/dist/ValidationError.d.ts.map +1 -0
  12. package/dist/ValidationError.js +78 -0
  13. package/dist/ValidationError.js.map +1 -0
  14. package/dist/Validator.d.ts +483 -0
  15. package/dist/Validator.d.ts.map +1 -0
  16. package/dist/Validator.js +570 -0
  17. package/dist/Validator.js.map +1 -0
  18. package/dist/helpers/JsonSchema.d.ts +99 -0
  19. package/dist/helpers/JsonSchema.d.ts.map +1 -0
  20. package/dist/helpers/JsonSchema.js +3 -0
  21. package/dist/helpers/JsonSchema.js.map +1 -0
  22. package/dist/helpers/cleanupAttributes.d.ts +34 -0
  23. package/dist/helpers/cleanupAttributes.d.ts.map +1 -0
  24. package/dist/helpers/cleanupAttributes.js +113 -0
  25. package/dist/helpers/cleanupAttributes.js.map +1 -0
  26. package/dist/helpers/cleanupNulls.d.ts +27 -0
  27. package/dist/helpers/cleanupNulls.d.ts.map +1 -0
  28. package/dist/helpers/cleanupNulls.js +96 -0
  29. package/dist/helpers/cleanupNulls.js.map +1 -0
  30. package/dist/helpers/getReferenceIds.d.ts +169 -0
  31. package/dist/helpers/getReferenceIds.d.ts.map +1 -0
  32. package/dist/helpers/getReferenceIds.js +241 -0
  33. package/dist/helpers/getReferenceIds.js.map +1 -0
  34. package/dist/helpers/got.d.ts +60 -0
  35. package/dist/helpers/got.d.ts.map +1 -0
  36. package/dist/helpers/got.js +72 -0
  37. package/dist/helpers/got.js.map +1 -0
  38. package/dist/helpers/mapObjectProperties.d.ts +150 -0
  39. package/dist/helpers/mapObjectProperties.d.ts.map +1 -0
  40. package/dist/helpers/mapObjectProperties.js +229 -0
  41. package/dist/helpers/mapObjectProperties.js.map +1 -0
  42. package/dist/helpers/normalizeAttributes.d.ts +213 -0
  43. package/dist/helpers/normalizeAttributes.d.ts.map +1 -0
  44. package/dist/helpers/normalizeAttributes.js +243 -0
  45. package/dist/helpers/normalizeAttributes.js.map +1 -0
  46. package/dist/helpers/normalizeProperties.d.ts +168 -0
  47. package/dist/helpers/normalizeProperties.d.ts.map +1 -0
  48. package/dist/helpers/normalizeProperties.js +223 -0
  49. package/dist/helpers/normalizeProperties.js.map +1 -0
  50. package/dist/helpers/normalizeRequired.d.ts +159 -0
  51. package/dist/helpers/normalizeRequired.d.ts.map +1 -0
  52. package/dist/helpers/normalizeRequired.js +206 -0
  53. package/dist/helpers/normalizeRequired.js.map +1 -0
  54. package/dist/helpers/normalizeType.d.ts +81 -0
  55. package/dist/helpers/normalizeType.d.ts.map +1 -0
  56. package/dist/helpers/normalizeType.js +210 -0
  57. package/dist/helpers/normalizeType.js.map +1 -0
  58. package/dist/helpers/nullifyEmptyValues.d.ts +139 -0
  59. package/dist/helpers/nullifyEmptyValues.d.ts.map +1 -0
  60. package/dist/helpers/nullifyEmptyValues.js +191 -0
  61. package/dist/helpers/nullifyEmptyValues.js.map +1 -0
  62. package/dist/helpers/removeRequiredAndDefault.d.ts +106 -0
  63. package/dist/helpers/removeRequiredAndDefault.d.ts.map +1 -0
  64. package/dist/helpers/removeRequiredAndDefault.js +138 -0
  65. package/dist/helpers/removeRequiredAndDefault.js.map +1 -0
  66. package/dist/helpers/validateId.d.ts +39 -0
  67. package/dist/helpers/validateId.d.ts.map +1 -0
  68. package/dist/helpers/validateId.js +51 -0
  69. package/dist/helpers/validateId.js.map +1 -0
  70. package/dist/index.d.ts +7 -0
  71. package/dist/index.d.ts.map +1 -0
  72. package/dist/index.js +17 -0
  73. package/dist/index.js.map +1 -0
  74. package/dist/ld/documentLoader.d.ts +8 -0
  75. package/dist/ld/documentLoader.d.ts.map +1 -0
  76. package/dist/ld/documentLoader.js +24 -0
  77. package/dist/ld/documentLoader.js.map +1 -0
  78. package/dist/ld/getLinkedDataAttributeType.d.ts +10 -0
  79. package/dist/ld/getLinkedDataAttributeType.d.ts.map +1 -0
  80. package/dist/ld/getLinkedDataAttributeType.js +32 -0
  81. package/dist/ld/getLinkedDataAttributeType.js.map +1 -0
  82. package/dist/ld/getLinkedDataContext.d.ts +19 -0
  83. package/dist/ld/getLinkedDataContext.d.ts.map +1 -0
  84. package/dist/ld/getLinkedDataContext.js +50 -0
  85. package/dist/ld/getLinkedDataContext.js.map +1 -0
  86. package/eslint.config.mjs +32 -52
  87. package/examples/credentials/createAccountCredential.ts +27 -0
  88. package/examples/credentials/createMineSweeperScoreCredential.ts +115 -0
  89. package/examples/index.ts +7 -0
  90. package/examples/schemas/FavoriteItemSchema.ts +27 -0
  91. package/examples/{Preferences.yaml → schemas/Preferences.yaml} +2 -0
  92. package/examples/schemas/PreferencesSchema.ts +29 -0
  93. package/examples/schemas/ProfileSchema.ts +91 -0
  94. package/examples/schemas/Status.yaml +3 -0
  95. package/examples/schemas/StatusSchema.ts +12 -0
  96. package/jest.config.mjs +5 -0
  97. package/package.json +27 -20
  98. package/src/CredentialFactory.ts +392 -0
  99. package/src/Schema.ts +583 -0
  100. package/src/ValidationError.ts +90 -0
  101. package/src/Validator.ts +603 -0
  102. package/src/__tests__/CredentialFactory.test.ts +588 -0
  103. package/src/__tests__/Schema.test.ts +371 -0
  104. package/src/__tests__/ValidationError.test.ts +235 -0
  105. package/src/__tests__/Validator.test.ts +787 -0
  106. package/src/helpers/JsonSchema.ts +119 -0
  107. package/src/helpers/__tests__/cleanupAttributes.test.ts +943 -0
  108. package/src/helpers/__tests__/cleanupNulls.test.ts +772 -0
  109. package/src/helpers/__tests__/getReferenceIds.test.ts +975 -0
  110. package/src/helpers/__tests__/got.test.ts +193 -0
  111. package/src/helpers/__tests__/mapObjectProperties.test.ts +1126 -0
  112. package/src/helpers/__tests__/normalizeAttributes.test.ts +1435 -0
  113. package/src/helpers/__tests__/normalizeProperties.test.ts +727 -0
  114. package/src/helpers/__tests__/normalizeRequired.test.ts +669 -0
  115. package/src/helpers/__tests__/normalizeType.test.ts +772 -0
  116. package/src/helpers/__tests__/nullifyEmptyValues.test.ts +735 -0
  117. package/src/helpers/__tests__/removeRequiredAndDefault.test.ts +734 -0
  118. package/src/helpers/__tests__/validateId.test.ts +118 -0
  119. package/src/helpers/cleanupAttributes.ts +151 -0
  120. package/src/helpers/cleanupNulls.ts +106 -0
  121. package/src/helpers/getReferenceIds.ts +273 -0
  122. package/src/helpers/got.ts +73 -0
  123. package/src/helpers/mapObjectProperties.ts +272 -0
  124. package/src/helpers/normalizeAttributes.ts +247 -0
  125. package/src/helpers/normalizeProperties.ts +249 -0
  126. package/src/helpers/normalizeRequired.ts +233 -0
  127. package/src/helpers/normalizeType.ts +235 -0
  128. package/src/helpers/nullifyEmptyValues.ts +207 -0
  129. package/src/helpers/removeRequiredAndDefault.ts +151 -0
  130. package/src/helpers/validateId.ts +53 -0
  131. package/src/index.ts +13 -0
  132. package/src/ld/__tests__/documentLoader.test.ts +57 -0
  133. package/src/ld/__tests__/getLinkedDataAttributeType.test.ts +212 -0
  134. package/src/ld/__tests__/getLinkedDataContext.test.ts +378 -0
  135. package/src/ld/documentLoader.ts +28 -0
  136. package/src/ld/getLinkedDataAttributeType.ts +46 -0
  137. package/src/ld/getLinkedDataContext.ts +80 -0
  138. package/tsconfig.json +27 -0
  139. package/types/credentials-context.d.ts +14 -0
  140. package/types/security-context.d.ts +6 -0
  141. package/examples/Status.yaml +0 -3
  142. package/examples/createAccountCredential.js +0 -27
  143. package/examples/createMineSweeperScoreCredential.js +0 -63
  144. package/examples/index.js +0 -9
  145. package/src/CredentialFactory.js +0 -67
  146. package/src/CredentialFactory.spec.js +0 -131
  147. package/src/Schema.js +0 -104
  148. package/src/Schema.spec.js +0 -172
  149. package/src/ValidationError.js +0 -31
  150. package/src/Validator.js +0 -128
  151. package/src/Validator.spec.js +0 -355
  152. package/src/helpers/cleanupAttributes.js +0 -71
  153. package/src/helpers/cleanupNulls.js +0 -42
  154. package/src/helpers/getReferenceIds.js +0 -71
  155. package/src/helpers/mapObject.js +0 -65
  156. package/src/helpers/normalizeAttributes.js +0 -28
  157. package/src/helpers/normalizeProperties.js +0 -61
  158. package/src/helpers/normalizeRequired.js +0 -37
  159. package/src/helpers/normalizeType.js +0 -41
  160. package/src/helpers/nullifyEmptyValues.js +0 -57
  161. package/src/helpers/removeRequiredAndDefault.js +0 -30
  162. package/src/helpers/validateId.js +0 -19
  163. package/src/index.d.ts +0 -25
  164. package/src/index.js +0 -8
  165. package/src/ld/documentLoader.js +0 -25
  166. package/src/ld/documentLoader.spec.js +0 -12
  167. package/src/ld/getLinkedDataContext.js +0 -63
  168. package/src/ld/getLinkedDataType.js +0 -38
  169. /package/examples/{FavoriteItem.yaml → schemas/FavoriteItem.yaml} +0 -0
  170. /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
+ });