@kravc/schema 2.7.6 → 2.8.0-alpha.1

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 (176) 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/createSchemasMap.d.ts +67 -0
  31. package/dist/helpers/createSchemasMap.d.ts.map +1 -0
  32. package/dist/helpers/createSchemasMap.js +200 -0
  33. package/dist/helpers/createSchemasMap.js.map +1 -0
  34. package/dist/helpers/getReferenceIds.d.ts +169 -0
  35. package/dist/helpers/getReferenceIds.d.ts.map +1 -0
  36. package/dist/helpers/getReferenceIds.js +241 -0
  37. package/dist/helpers/getReferenceIds.js.map +1 -0
  38. package/dist/helpers/got.d.ts +60 -0
  39. package/dist/helpers/got.d.ts.map +1 -0
  40. package/dist/helpers/got.js +72 -0
  41. package/dist/helpers/got.js.map +1 -0
  42. package/dist/helpers/mapObjectProperties.d.ts +150 -0
  43. package/dist/helpers/mapObjectProperties.d.ts.map +1 -0
  44. package/dist/helpers/mapObjectProperties.js +229 -0
  45. package/dist/helpers/mapObjectProperties.js.map +1 -0
  46. package/dist/helpers/normalizeAttributes.d.ts +213 -0
  47. package/dist/helpers/normalizeAttributes.d.ts.map +1 -0
  48. package/dist/helpers/normalizeAttributes.js +243 -0
  49. package/dist/helpers/normalizeAttributes.js.map +1 -0
  50. package/dist/helpers/normalizeProperties.d.ts +168 -0
  51. package/dist/helpers/normalizeProperties.d.ts.map +1 -0
  52. package/dist/helpers/normalizeProperties.js +223 -0
  53. package/dist/helpers/normalizeProperties.js.map +1 -0
  54. package/dist/helpers/normalizeRequired.d.ts +159 -0
  55. package/dist/helpers/normalizeRequired.d.ts.map +1 -0
  56. package/dist/helpers/normalizeRequired.js +206 -0
  57. package/dist/helpers/normalizeRequired.js.map +1 -0
  58. package/dist/helpers/normalizeType.d.ts +81 -0
  59. package/dist/helpers/normalizeType.d.ts.map +1 -0
  60. package/dist/helpers/normalizeType.js +210 -0
  61. package/dist/helpers/normalizeType.js.map +1 -0
  62. package/dist/helpers/nullifyEmptyValues.d.ts +139 -0
  63. package/dist/helpers/nullifyEmptyValues.d.ts.map +1 -0
  64. package/dist/helpers/nullifyEmptyValues.js +191 -0
  65. package/dist/helpers/nullifyEmptyValues.js.map +1 -0
  66. package/dist/helpers/removeRequiredAndDefault.d.ts +106 -0
  67. package/dist/helpers/removeRequiredAndDefault.d.ts.map +1 -0
  68. package/dist/helpers/removeRequiredAndDefault.js +138 -0
  69. package/dist/helpers/removeRequiredAndDefault.js.map +1 -0
  70. package/dist/helpers/validateId.d.ts +39 -0
  71. package/dist/helpers/validateId.d.ts.map +1 -0
  72. package/dist/helpers/validateId.js +51 -0
  73. package/dist/helpers/validateId.js.map +1 -0
  74. package/dist/index.d.ts +9 -0
  75. package/dist/index.d.ts.map +1 -0
  76. package/dist/index.js +21 -0
  77. package/dist/index.js.map +1 -0
  78. package/dist/ld/documentLoader.d.ts +8 -0
  79. package/dist/ld/documentLoader.d.ts.map +1 -0
  80. package/dist/ld/documentLoader.js +24 -0
  81. package/dist/ld/documentLoader.js.map +1 -0
  82. package/dist/ld/getLinkedDataAttributeType.d.ts +10 -0
  83. package/dist/ld/getLinkedDataAttributeType.d.ts.map +1 -0
  84. package/dist/ld/getLinkedDataAttributeType.js +32 -0
  85. package/dist/ld/getLinkedDataAttributeType.js.map +1 -0
  86. package/dist/ld/getLinkedDataContext.d.ts +19 -0
  87. package/dist/ld/getLinkedDataContext.d.ts.map +1 -0
  88. package/dist/ld/getLinkedDataContext.js +50 -0
  89. package/dist/ld/getLinkedDataContext.js.map +1 -0
  90. package/eslint.config.mjs +32 -52
  91. package/examples/credentials/createAccountCredential.ts +27 -0
  92. package/examples/credentials/createMineSweeperScoreCredential.ts +115 -0
  93. package/examples/index.ts +7 -0
  94. package/examples/schemas/FavoriteItemSchema.ts +27 -0
  95. package/examples/{Preferences.yaml → schemas/Preferences.yaml} +2 -0
  96. package/examples/schemas/PreferencesSchema.ts +29 -0
  97. package/examples/schemas/ProfileSchema.ts +91 -0
  98. package/examples/schemas/Status.yaml +3 -0
  99. package/examples/schemas/StatusSchema.ts +12 -0
  100. package/jest.config.mjs +5 -0
  101. package/package.json +27 -20
  102. package/src/CredentialFactory.ts +392 -0
  103. package/src/Schema.ts +583 -0
  104. package/src/ValidationError.ts +90 -0
  105. package/src/Validator.ts +603 -0
  106. package/src/__tests__/CredentialFactory.test.ts +588 -0
  107. package/src/__tests__/Schema.test.ts +371 -0
  108. package/src/__tests__/ValidationError.test.ts +235 -0
  109. package/src/__tests__/Validator.test.ts +787 -0
  110. package/src/helpers/JsonSchema.ts +119 -0
  111. package/src/helpers/__tests__/cleanupAttributes.test.ts +943 -0
  112. package/src/helpers/__tests__/cleanupNulls.test.ts +772 -0
  113. package/src/helpers/__tests__/createSchemasMap.test.ts +238 -0
  114. package/src/helpers/__tests__/getReferenceIds.test.ts +975 -0
  115. package/src/helpers/__tests__/got.test.ts +193 -0
  116. package/src/helpers/__tests__/mapObjectProperties.test.ts +1126 -0
  117. package/src/helpers/__tests__/normalizeAttributes.test.ts +1435 -0
  118. package/src/helpers/__tests__/normalizeProperties.test.ts +727 -0
  119. package/src/helpers/__tests__/normalizeRequired.test.ts +669 -0
  120. package/src/helpers/__tests__/normalizeType.test.ts +772 -0
  121. package/src/helpers/__tests__/nullifyEmptyValues.test.ts +735 -0
  122. package/src/helpers/__tests__/removeRequiredAndDefault.test.ts +734 -0
  123. package/src/helpers/__tests__/validateId.test.ts +118 -0
  124. package/src/helpers/cleanupAttributes.ts +151 -0
  125. package/src/helpers/cleanupNulls.ts +106 -0
  126. package/src/helpers/createSchemasMap.ts +212 -0
  127. package/src/helpers/getReferenceIds.ts +273 -0
  128. package/src/helpers/got.ts +73 -0
  129. package/src/helpers/mapObjectProperties.ts +272 -0
  130. package/src/helpers/normalizeAttributes.ts +247 -0
  131. package/src/helpers/normalizeProperties.ts +249 -0
  132. package/src/helpers/normalizeRequired.ts +233 -0
  133. package/src/helpers/normalizeType.ts +235 -0
  134. package/src/helpers/nullifyEmptyValues.ts +207 -0
  135. package/src/helpers/removeRequiredAndDefault.ts +151 -0
  136. package/src/helpers/validateId.ts +53 -0
  137. package/src/index.ts +17 -0
  138. package/src/ld/__tests__/documentLoader.test.ts +57 -0
  139. package/src/ld/__tests__/getLinkedDataAttributeType.test.ts +212 -0
  140. package/src/ld/__tests__/getLinkedDataContext.test.ts +378 -0
  141. package/src/ld/documentLoader.ts +28 -0
  142. package/src/ld/getLinkedDataAttributeType.ts +46 -0
  143. package/src/ld/getLinkedDataContext.ts +80 -0
  144. package/tsconfig.json +27 -0
  145. package/types/credentials-context.d.ts +14 -0
  146. package/types/security-context.d.ts +6 -0
  147. package/examples/Status.yaml +0 -3
  148. package/examples/createAccountCredential.js +0 -27
  149. package/examples/createMineSweeperScoreCredential.js +0 -63
  150. package/examples/index.js +0 -9
  151. package/src/CredentialFactory.js +0 -67
  152. package/src/CredentialFactory.spec.js +0 -131
  153. package/src/Schema.js +0 -104
  154. package/src/Schema.spec.js +0 -172
  155. package/src/ValidationError.js +0 -31
  156. package/src/Validator.js +0 -128
  157. package/src/Validator.spec.js +0 -355
  158. package/src/helpers/cleanupAttributes.js +0 -71
  159. package/src/helpers/cleanupNulls.js +0 -42
  160. package/src/helpers/getReferenceIds.js +0 -71
  161. package/src/helpers/mapObject.js +0 -65
  162. package/src/helpers/normalizeAttributes.js +0 -28
  163. package/src/helpers/normalizeProperties.js +0 -61
  164. package/src/helpers/normalizeRequired.js +0 -37
  165. package/src/helpers/normalizeType.js +0 -41
  166. package/src/helpers/nullifyEmptyValues.js +0 -57
  167. package/src/helpers/removeRequiredAndDefault.js +0 -30
  168. package/src/helpers/validateId.js +0 -19
  169. package/src/index.d.ts +0 -25
  170. package/src/index.js +0 -8
  171. package/src/ld/documentLoader.js +0 -25
  172. package/src/ld/documentLoader.spec.js +0 -12
  173. package/src/ld/getLinkedDataContext.js +0 -63
  174. package/src/ld/getLinkedDataType.js +0 -38
  175. /package/examples/{FavoriteItem.yaml → schemas/FavoriteItem.yaml} +0 -0
  176. /package/examples/{Profile.yaml → schemas/Profile.yaml} +0 -0
@@ -0,0 +1,975 @@
1
+ import Schema from '../../Schema';
2
+ import getReferenceIds from '../getReferenceIds';
3
+
4
+ describe('getReferenceIds(schema, schemasMap)', () => {
5
+ describe('enum schema', () => {
6
+ it('should return empty array for enum schema', () => {
7
+ const enumSchema = new Schema({ enum: ['value1', 'value2', 'value3'] }, 'enum-schema');
8
+ const schemasMap = {};
9
+
10
+ const result = getReferenceIds(enumSchema, schemasMap);
11
+
12
+ expect(result).toEqual([]);
13
+ });
14
+ });
15
+
16
+ describe('object schema with no properties', () => {
17
+ it('should return empty array for schema with no properties', () => {
18
+ const schema = new Schema({}, 'empty-schema');
19
+ const schemasMap = {};
20
+
21
+ const result = getReferenceIds(schema, schemasMap);
22
+
23
+ expect(result).toEqual([]);
24
+ });
25
+ });
26
+
27
+ describe('reference properties ($ref)', () => {
28
+ it('should return reference ID for schema with single reference property', () => {
29
+ const schema = new Schema(
30
+ {
31
+ refField: { $ref: 'referenced-schema' }
32
+ },
33
+ 'test-schema'
34
+ );
35
+ const referencedSchema = new Schema(
36
+ {
37
+ field: { type: 'string' }
38
+ },
39
+ 'referenced-schema'
40
+ );
41
+ const schemasMap = {
42
+ 'referenced-schema': referencedSchema
43
+ };
44
+
45
+ const result = getReferenceIds(schema, schemasMap);
46
+
47
+ expect(result).toEqual(['referenced-schema']);
48
+ });
49
+
50
+ it('should return all reference IDs for schema with multiple reference properties', () => {
51
+ const schema = new Schema(
52
+ {
53
+ refField1: { $ref: 'schema1' },
54
+ refField2: { $ref: 'schema2' },
55
+ refField3: { $ref: 'schema3' }
56
+ },
57
+ 'test-schema'
58
+ );
59
+ const schema1 = new Schema({ field1: { type: 'string' } }, 'schema1');
60
+ const schema2 = new Schema({ field2: { type: 'string' } }, 'schema2');
61
+ const schema3 = new Schema({ field3: { type: 'string' } }, 'schema3');
62
+ const schemasMap = {
63
+ 'schema1': schema1,
64
+ 'schema2': schema2,
65
+ 'schema3': schema3
66
+ };
67
+
68
+ const result = getReferenceIds(schema, schemasMap);
69
+
70
+ expect(result).toEqual(expect.arrayContaining(['schema1', 'schema2', 'schema3']));
71
+ expect(result).toHaveLength(3);
72
+ });
73
+
74
+ it('should return nested reference IDs recursively', () => {
75
+ const schema = new Schema(
76
+ {
77
+ refField: { $ref: 'level1-schema' }
78
+ },
79
+ 'test-schema'
80
+ );
81
+ const level1Schema = new Schema(
82
+ {
83
+ nestedRef: { $ref: 'level2-schema' }
84
+ },
85
+ 'level1-schema'
86
+ );
87
+ const level2Schema = new Schema(
88
+ {
89
+ field: { type: 'string' }
90
+ },
91
+ 'level2-schema'
92
+ );
93
+ const schemasMap = {
94
+ 'level1-schema': level1Schema,
95
+ 'level2-schema': level2Schema
96
+ };
97
+
98
+ const result = getReferenceIds(schema, schemasMap);
99
+
100
+ expect(result).toEqual(expect.arrayContaining(['level1-schema', 'level2-schema']));
101
+ expect(result).toHaveLength(2);
102
+ });
103
+
104
+ it('should handle deeply nested references', () => {
105
+ const schema = new Schema(
106
+ {
107
+ refField: { $ref: 'level1' }
108
+ },
109
+ 'test-schema'
110
+ );
111
+ const level1 = new Schema({ ref: { $ref: 'level2' } }, 'level1');
112
+ const level2 = new Schema({ ref: { $ref: 'level3' } }, 'level2');
113
+ const level3 = new Schema({ field: { type: 'string' } }, 'level3');
114
+ const schemasMap = {
115
+ 'level1': level1,
116
+ 'level2': level2,
117
+ 'level3': level3
118
+ };
119
+
120
+ const result = getReferenceIds(schema, schemasMap);
121
+
122
+ expect(result).toEqual(expect.arrayContaining(['level1', 'level2', 'level3']));
123
+ expect(result).toHaveLength(3);
124
+ });
125
+
126
+ it('should return unique reference IDs when duplicates exist', () => {
127
+ const schema = new Schema(
128
+ {
129
+ refField1: { $ref: 'shared-schema' },
130
+ refField2: { $ref: 'shared-schema' }
131
+ },
132
+ 'test-schema'
133
+ );
134
+ const sharedSchema = new Schema({ field: { type: 'string' } }, 'shared-schema');
135
+ const schemasMap = {
136
+ 'shared-schema': sharedSchema
137
+ };
138
+
139
+ const result = getReferenceIds(schema, schemasMap);
140
+
141
+ expect(result).toEqual(['shared-schema']);
142
+ });
143
+
144
+ it('should throw error when referenced schema is not found in schemasMap', () => {
145
+ const schema = new Schema(
146
+ {
147
+ refField: { $ref: 'non-existent-schema' }
148
+ },
149
+ 'test-schema'
150
+ );
151
+ const schemasMap = {};
152
+
153
+ expect(() => {
154
+ getReferenceIds(schema, schemasMap);
155
+ }).toThrow();
156
+ });
157
+ });
158
+
159
+ describe('object properties', () => {
160
+ it('should return empty array for nested object with no references', () => {
161
+ const schema = new Schema(
162
+ {
163
+ nestedObject: {
164
+ type: 'object',
165
+ properties: {
166
+ field: { type: 'string' }
167
+ }
168
+ }
169
+ },
170
+ 'test-schema'
171
+ );
172
+ const schemasMap = {};
173
+
174
+ const result = getReferenceIds(schema, schemasMap);
175
+
176
+ expect(result).toEqual([]);
177
+ });
178
+
179
+ it('should return reference IDs from nested object properties', () => {
180
+ const schema = new Schema(
181
+ {
182
+ nestedObject: {
183
+ type: 'object',
184
+ properties: {
185
+ refField: { $ref: 'nested-ref-schema' }
186
+ }
187
+ }
188
+ },
189
+ 'test-schema'
190
+ );
191
+ const nestedRefSchema = new Schema({ field: { type: 'string' } }, 'nested-ref-schema');
192
+ const schemasMap = {
193
+ 'nested-ref-schema': nestedRefSchema
194
+ };
195
+
196
+ const result = getReferenceIds(schema, schemasMap);
197
+
198
+ expect(result).toEqual(['nested-ref-schema']);
199
+ });
200
+
201
+ it('should handle deeply nested object properties', () => {
202
+ const schema = new Schema(
203
+ {
204
+ level1: {
205
+ type: 'object',
206
+ properties: {
207
+ level2: {
208
+ type: 'object',
209
+ properties: {
210
+ refField: { $ref: 'deep-schema' }
211
+ }
212
+ }
213
+ }
214
+ }
215
+ },
216
+ 'test-schema'
217
+ );
218
+ const deepSchema = new Schema({ field: { type: 'string' } }, 'deep-schema');
219
+ const schemasMap = {
220
+ 'deep-schema': deepSchema
221
+ };
222
+
223
+ const result = getReferenceIds(schema, schemasMap);
224
+
225
+ expect(result).toEqual(['deep-schema']);
226
+ });
227
+ });
228
+
229
+ describe('array properties', () => {
230
+ it('should return reference ID for array with reference items', () => {
231
+ const schema = new Schema(
232
+ {
233
+ arrayField: {
234
+ type: 'array',
235
+ items: { $ref: 'item-schema' }
236
+ }
237
+ },
238
+ 'test-schema'
239
+ );
240
+ const itemSchema = new Schema({ field: { type: 'string' } }, 'item-schema');
241
+ const schemasMap = {
242
+ 'item-schema': itemSchema
243
+ };
244
+
245
+ const result = getReferenceIds(schema, schemasMap);
246
+
247
+ expect(result).toEqual(['item-schema']);
248
+ });
249
+
250
+ it('should return nested reference IDs from array items with references', () => {
251
+ const schema = new Schema(
252
+ {
253
+ arrayField: {
254
+ type: 'array',
255
+ items: { $ref: 'item-schema' }
256
+ }
257
+ },
258
+ 'test-schema'
259
+ );
260
+ const itemSchema = new Schema(
261
+ {
262
+ refField: { $ref: 'nested-item-schema' }
263
+ },
264
+ 'item-schema'
265
+ );
266
+ const nestedItemSchema = new Schema({ field: { type: 'string' } }, 'nested-item-schema');
267
+ const schemasMap = {
268
+ 'item-schema': itemSchema,
269
+ 'nested-item-schema': nestedItemSchema
270
+ };
271
+
272
+ const result = getReferenceIds(schema, schemasMap);
273
+
274
+ expect(result).toEqual(expect.arrayContaining(['item-schema', 'nested-item-schema']));
275
+ expect(result).toHaveLength(2);
276
+ });
277
+
278
+ it('should return empty array for array with object items that have no references', () => {
279
+ const schema = new Schema(
280
+ {
281
+ arrayField: {
282
+ type: 'array',
283
+ items: {
284
+ type: 'object',
285
+ properties: {
286
+ field: { type: 'string' }
287
+ }
288
+ }
289
+ }
290
+ },
291
+ 'test-schema'
292
+ );
293
+ const schemasMap = {};
294
+
295
+ const result = getReferenceIds(schema, schemasMap);
296
+
297
+ expect(result).toEqual([]);
298
+ });
299
+
300
+ it('should return reference IDs from array items with object properties', () => {
301
+ const schema = new Schema(
302
+ {
303
+ arrayField: {
304
+ type: 'array',
305
+ items: {
306
+ type: 'object',
307
+ properties: {
308
+ refField: { $ref: 'item-ref-schema' }
309
+ }
310
+ }
311
+ }
312
+ },
313
+ 'test-schema'
314
+ );
315
+ const itemRefSchema = new Schema({ field: { type: 'string' } }, 'item-ref-schema');
316
+ const schemasMap = {
317
+ 'item-ref-schema': itemRefSchema
318
+ };
319
+
320
+ const result = getReferenceIds(schema, schemasMap);
321
+
322
+ expect(result).toEqual(['item-ref-schema']);
323
+ });
324
+
325
+ it('should handle nested references in array items with object properties', () => {
326
+ const schema = new Schema(
327
+ {
328
+ arrayField: {
329
+ type: 'array',
330
+ items: {
331
+ type: 'object',
332
+ properties: {
333
+ nestedObject: {
334
+ type: 'object',
335
+ properties: {
336
+ refField: { $ref: 'deep-array-ref-schema' }
337
+ }
338
+ }
339
+ }
340
+ }
341
+ }
342
+ },
343
+ 'test-schema'
344
+ );
345
+ const deepArrayRefSchema = new Schema({ field: { type: 'string' } }, 'deep-array-ref-schema');
346
+ const schemasMap = {
347
+ 'deep-array-ref-schema': deepArrayRefSchema
348
+ };
349
+
350
+ const result = getReferenceIds(schema, schemasMap);
351
+
352
+ expect(result).toEqual(['deep-array-ref-schema']);
353
+ });
354
+ });
355
+
356
+ describe('complex nested scenarios', () => {
357
+ it('should return all reference IDs from schema with mix of reference, object, and array properties', () => {
358
+ const schema = new Schema(
359
+ {
360
+ refField: { $ref: 'ref-schema' },
361
+ nestedObject: {
362
+ type: 'object',
363
+ properties: {
364
+ nestedRef: { $ref: 'nested-ref-schema' }
365
+ }
366
+ },
367
+ arrayField: {
368
+ type: 'array',
369
+ items: { $ref: 'array-item-schema' }
370
+ }
371
+ },
372
+ 'test-schema'
373
+ );
374
+ const refSchema = new Schema({ field: { type: 'string' } }, 'ref-schema');
375
+ const nestedRefSchema = new Schema({ field: { type: 'string' } }, 'nested-ref-schema');
376
+ const arrayItemSchema = new Schema({ field: { type: 'string' } }, 'array-item-schema');
377
+ const schemasMap = {
378
+ 'ref-schema': refSchema,
379
+ 'nested-ref-schema': nestedRefSchema,
380
+ 'array-item-schema': arrayItemSchema
381
+ };
382
+
383
+ const result = getReferenceIds(schema, schemasMap);
384
+
385
+ expect(result).toEqual(expect.arrayContaining(['ref-schema', 'nested-ref-schema', 'array-item-schema']));
386
+ expect(result).toHaveLength(3);
387
+ });
388
+
389
+ it('should handle array of objects with nested references', () => {
390
+ const schema = new Schema(
391
+ {
392
+ arrayField: {
393
+ type: 'array',
394
+ items: {
395
+ type: 'object',
396
+ properties: {
397
+ refField: { $ref: 'array-nested-ref-schema' }
398
+ }
399
+ }
400
+ }
401
+ },
402
+ 'test-schema'
403
+ );
404
+ const arrayNestedRefSchema = new Schema(
405
+ {
406
+ nestedRef: { $ref: 'deep-nested-schema' }
407
+ },
408
+ 'array-nested-ref-schema'
409
+ );
410
+ const deepNestedSchema = new Schema({ field: { type: 'string' } }, 'deep-nested-schema');
411
+ const schemasMap = {
412
+ 'array-nested-ref-schema': arrayNestedRefSchema,
413
+ 'deep-nested-schema': deepNestedSchema
414
+ };
415
+
416
+ const result = getReferenceIds(schema, schemasMap);
417
+
418
+ expect(result).toEqual(expect.arrayContaining(['array-nested-ref-schema', 'deep-nested-schema']));
419
+ expect(result).toHaveLength(2);
420
+ });
421
+
422
+ it('should handle circular references (causes infinite recursion - limitation)', () => {
423
+ // Note: This test demonstrates that circular references cause infinite recursion.
424
+ // The current implementation does not handle circular references.
425
+ // This would need cycle detection to be properly handled.
426
+ const schema = new Schema(
427
+ {
428
+ refField: { $ref: 'circular-schema' }
429
+ },
430
+ 'test-schema'
431
+ );
432
+ const circularSchema = new Schema(
433
+ {
434
+ selfRef: { $ref: 'circular-schema' }
435
+ },
436
+ 'circular-schema'
437
+ );
438
+ const schemasMap = {
439
+ 'circular-schema': circularSchema
440
+ };
441
+
442
+ // The function will recurse infinitely with circular references
443
+ expect(() => {
444
+ getReferenceIds(schema, schemasMap);
445
+ }).toThrow();
446
+ });
447
+
448
+ it('should handle multiple properties with same nested reference', () => {
449
+ const schema = new Schema(
450
+ {
451
+ refField1: { $ref: 'shared-nested-schema' },
452
+ refField2: { $ref: 'shared-nested-schema' },
453
+ nestedObject: {
454
+ type: 'object',
455
+ properties: {
456
+ refField: { $ref: 'shared-nested-schema' }
457
+ }
458
+ }
459
+ },
460
+ 'test-schema'
461
+ );
462
+ const sharedNestedSchema = new Schema(
463
+ {
464
+ nestedRef: { $ref: 'deep-shared-schema' }
465
+ },
466
+ 'shared-nested-schema'
467
+ );
468
+ const deepSharedSchema = new Schema({ field: { type: 'string' } }, 'deep-shared-schema');
469
+ const schemasMap = {
470
+ 'shared-nested-schema': sharedNestedSchema,
471
+ 'deep-shared-schema': deepSharedSchema
472
+ };
473
+
474
+ const result = getReferenceIds(schema, schemasMap);
475
+
476
+ expect(result).toEqual(expect.arrayContaining(['shared-nested-schema', 'deep-shared-schema']));
477
+ expect(result).toHaveLength(2);
478
+ });
479
+ });
480
+
481
+ describe('edge cases', () => {
482
+ it('should handle schema with only non-reference properties', () => {
483
+ const schema = new Schema(
484
+ {
485
+ stringField: { type: 'string' },
486
+ numberField: { type: 'number' },
487
+ booleanField: { type: 'boolean' }
488
+ },
489
+ 'test-schema'
490
+ );
491
+ const schemasMap = {};
492
+
493
+ const result = getReferenceIds(schema, schemasMap);
494
+
495
+ expect(result).toEqual([]);
496
+ });
497
+
498
+ it('should handle schema with empty object properties', () => {
499
+ const schema = new Schema(
500
+ {
501
+ emptyObject: {
502
+ type: 'object',
503
+ properties: {}
504
+ }
505
+ },
506
+ 'test-schema'
507
+ );
508
+ const schemasMap = {};
509
+
510
+ const result = getReferenceIds(schema, schemasMap);
511
+
512
+ expect(result).toEqual([]);
513
+ });
514
+
515
+
516
+ it('should handle array with items that have no properties', () => {
517
+ const schema = new Schema(
518
+ {
519
+ arrayField: {
520
+ type: 'array',
521
+ items: {
522
+ type: 'object'
523
+ }
524
+ }
525
+ },
526
+ 'test-schema'
527
+ );
528
+ const schemasMap = {};
529
+
530
+ const result = getReferenceIds(schema, schemasMap);
531
+
532
+ expect(result).toEqual([]);
533
+ });
534
+ });
535
+
536
+ describe('complex nested combinations', () => {
537
+ it('should handle object containing array with references', () => {
538
+ const schema = new Schema(
539
+ {
540
+ container: {
541
+ type: 'object',
542
+ properties: {
543
+ items: {
544
+ type: 'array',
545
+ items: { $ref: 'ItemSchema' }
546
+ }
547
+ }
548
+ }
549
+ },
550
+ 'test-schema'
551
+ );
552
+ const itemSchema = new Schema({ field: { type: 'string' } }, 'ItemSchema');
553
+ const schemasMap = {
554
+ 'ItemSchema': itemSchema
555
+ };
556
+
557
+ const result = getReferenceIds(schema, schemasMap);
558
+
559
+ expect(result).toEqual(['ItemSchema']);
560
+ });
561
+
562
+ it('should handle reference -> object -> array -> reference (transitive through all types)', () => {
563
+ const schema = new Schema(
564
+ {
565
+ refField: { $ref: 'Level1' }
566
+ },
567
+ 'test-schema'
568
+ );
569
+ const level1Schema = new Schema(
570
+ {
571
+ nestedObject: {
572
+ type: 'object',
573
+ properties: {
574
+ items: {
575
+ type: 'array',
576
+ items: { $ref: 'Level2' }
577
+ }
578
+ }
579
+ }
580
+ },
581
+ 'Level1'
582
+ );
583
+ const level2Schema = new Schema({ field: { type: 'string' } }, 'Level2');
584
+ const schemasMap = {
585
+ 'Level1': level1Schema,
586
+ 'Level2': level2Schema
587
+ };
588
+
589
+ const result = getReferenceIds(schema, schemasMap);
590
+
591
+ expect(result).toEqual(expect.arrayContaining(['Level1', 'Level2']));
592
+ expect(result).toHaveLength(2);
593
+ });
594
+
595
+ it('should handle reference -> array -> object -> reference (transitive through array and object)', () => {
596
+ const schema = new Schema(
597
+ {
598
+ refField: { $ref: 'Level1' }
599
+ },
600
+ 'test-schema'
601
+ );
602
+ const level1Schema = new Schema(
603
+ {
604
+ items: {
605
+ type: 'array',
606
+ items: {
607
+ type: 'object',
608
+ properties: {
609
+ nestedRef: { $ref: 'Level2' }
610
+ }
611
+ }
612
+ }
613
+ },
614
+ 'Level1'
615
+ );
616
+ const level2Schema = new Schema({ field: { type: 'string' } }, 'Level2');
617
+ const schemasMap = {
618
+ 'Level1': level1Schema,
619
+ 'Level2': level2Schema
620
+ };
621
+
622
+ const result = getReferenceIds(schema, schemasMap);
623
+
624
+ expect(result).toEqual(expect.arrayContaining(['Level1', 'Level2']));
625
+ expect(result).toHaveLength(2);
626
+ });
627
+
628
+ it('should handle array items that are objects containing arrays with references', () => {
629
+ const schema = new Schema(
630
+ {
631
+ outerArray: {
632
+ type: 'array',
633
+ items: {
634
+ type: 'object',
635
+ properties: {
636
+ innerArray: {
637
+ type: 'array',
638
+ items: { $ref: 'InnerItem' }
639
+ }
640
+ }
641
+ }
642
+ }
643
+ },
644
+ 'test-schema'
645
+ );
646
+ const innerItemSchema = new Schema({ field: { type: 'string' } }, 'InnerItem');
647
+ const schemasMap = {
648
+ 'InnerItem': innerItemSchema
649
+ };
650
+
651
+ const result = getReferenceIds(schema, schemasMap);
652
+
653
+ expect(result).toEqual(['InnerItem']);
654
+ });
655
+
656
+ it('should handle object -> array -> object -> array -> reference (maximum depth nesting)', () => {
657
+ const schema = new Schema(
658
+ {
659
+ level1: {
660
+ type: 'object',
661
+ properties: {
662
+ level2: {
663
+ type: 'array',
664
+ items: {
665
+ type: 'object',
666
+ properties: {
667
+ level3: {
668
+ type: 'array',
669
+ items: { $ref: 'DeepSchema' }
670
+ }
671
+ }
672
+ }
673
+ }
674
+ }
675
+ }
676
+ },
677
+ 'test-schema'
678
+ );
679
+ const deepSchema = new Schema({ field: { type: 'string' } }, 'DeepSchema');
680
+ const schemasMap = {
681
+ 'DeepSchema': deepSchema
682
+ };
683
+
684
+ const result = getReferenceIds(schema, schemasMap);
685
+
686
+ expect(result).toEqual(['DeepSchema']);
687
+ });
688
+
689
+ it('should handle reference that points to schema with object containing array with reference', () => {
690
+ const schema = new Schema(
691
+ {
692
+ refField: { $ref: 'ContainerSchema' }
693
+ },
694
+ 'test-schema'
695
+ );
696
+ const containerSchema = new Schema(
697
+ {
698
+ wrapper: {
699
+ type: 'object',
700
+ properties: {
701
+ items: {
702
+ type: 'array',
703
+ items: { $ref: 'ItemSchema' }
704
+ }
705
+ }
706
+ }
707
+ },
708
+ 'ContainerSchema'
709
+ );
710
+ const itemSchema = new Schema({ field: { type: 'string' } }, 'ItemSchema');
711
+ const schemasMap = {
712
+ 'ContainerSchema': containerSchema,
713
+ 'ItemSchema': itemSchema
714
+ };
715
+
716
+ const result = getReferenceIds(schema, schemasMap);
717
+
718
+ expect(result).toEqual(expect.arrayContaining(['ContainerSchema', 'ItemSchema']));
719
+ expect(result).toHaveLength(2);
720
+ });
721
+
722
+ it('should handle multiple references with mixed transitive patterns (array vs object)', () => {
723
+ const schema = new Schema(
724
+ {
725
+ ref1: { $ref: 'SchemaWithArray' },
726
+ ref2: { $ref: 'SchemaWithObject' }
727
+ },
728
+ 'test-schema'
729
+ );
730
+ const schemaWithArray = new Schema(
731
+ {
732
+ items: {
733
+ type: 'array',
734
+ items: { $ref: 'ArrayItem' }
735
+ }
736
+ },
737
+ 'SchemaWithArray'
738
+ );
739
+ const schemaWithObject = new Schema(
740
+ {
741
+ nested: {
742
+ type: 'object',
743
+ properties: {
744
+ ref: { $ref: 'ObjectItem' }
745
+ }
746
+ }
747
+ },
748
+ 'SchemaWithObject'
749
+ );
750
+ const arrayItemSchema = new Schema({ field: { type: 'string' } }, 'ArrayItem');
751
+ const objectItemSchema = new Schema({ field: { type: 'string' } }, 'ObjectItem');
752
+ const schemasMap = {
753
+ 'SchemaWithArray': schemaWithArray,
754
+ 'SchemaWithObject': schemaWithObject,
755
+ 'ArrayItem': arrayItemSchema,
756
+ 'ObjectItem': objectItemSchema
757
+ };
758
+
759
+ const result = getReferenceIds(schema, schemasMap);
760
+
761
+ expect(result).toEqual(expect.arrayContaining(['SchemaWithArray', 'SchemaWithObject', 'ArrayItem', 'ObjectItem']));
762
+ expect(result).toHaveLength(4);
763
+ });
764
+
765
+ it('should handle array items that are references containing arrays with references', () => {
766
+ const schema = new Schema(
767
+ {
768
+ outerArray: {
769
+ type: 'array',
770
+ items: { $ref: 'MiddleSchema' }
771
+ }
772
+ },
773
+ 'test-schema'
774
+ );
775
+ const middleSchema = new Schema(
776
+ {
777
+ innerArray: {
778
+ type: 'array',
779
+ items: { $ref: 'InnerSchema' }
780
+ }
781
+ },
782
+ 'MiddleSchema'
783
+ );
784
+ const innerSchema = new Schema({ field: { type: 'string' } }, 'InnerSchema');
785
+ const schemasMap = {
786
+ 'MiddleSchema': middleSchema,
787
+ 'InnerSchema': innerSchema
788
+ };
789
+
790
+ const result = getReferenceIds(schema, schemasMap);
791
+
792
+ expect(result).toEqual(expect.arrayContaining(['MiddleSchema', 'InnerSchema']));
793
+ expect(result).toHaveLength(2);
794
+ });
795
+
796
+ it('should handle object properties that are references containing nested objects with references', () => {
797
+ const schema = new Schema(
798
+ {
799
+ refField: { $ref: 'OuterSchema' }
800
+ },
801
+ 'test-schema'
802
+ );
803
+ const outerSchema = new Schema(
804
+ {
805
+ nested: {
806
+ type: 'object',
807
+ properties: {
808
+ deepRef: { $ref: 'DeepSchema' }
809
+ }
810
+ }
811
+ },
812
+ 'OuterSchema'
813
+ );
814
+ const deepSchema = new Schema({ field: { type: 'string' } }, 'DeepSchema');
815
+ const schemasMap = {
816
+ 'OuterSchema': outerSchema,
817
+ 'DeepSchema': deepSchema
818
+ };
819
+
820
+ const result = getReferenceIds(schema, schemasMap);
821
+
822
+ expect(result).toEqual(expect.arrayContaining(['OuterSchema', 'DeepSchema']));
823
+ expect(result).toHaveLength(2);
824
+ });
825
+
826
+ it('should handle complex mixed structure: reference -> object -> array -> object -> reference', () => {
827
+ const schema = new Schema(
828
+ {
829
+ rootRef: { $ref: 'RootSchema' }
830
+ },
831
+ 'test-schema'
832
+ );
833
+ const rootSchema = new Schema(
834
+ {
835
+ level1: {
836
+ type: 'object',
837
+ properties: {
838
+ level2: {
839
+ type: 'array',
840
+ items: {
841
+ type: 'object',
842
+ properties: {
843
+ level3: { $ref: 'FinalSchema' }
844
+ }
845
+ }
846
+ }
847
+ }
848
+ }
849
+ },
850
+ 'RootSchema'
851
+ );
852
+ const finalSchema = new Schema({ field: { type: 'string' } }, 'FinalSchema');
853
+ const schemasMap = {
854
+ 'RootSchema': rootSchema,
855
+ 'FinalSchema': finalSchema
856
+ };
857
+
858
+ const result = getReferenceIds(schema, schemasMap);
859
+
860
+ expect(result).toEqual(expect.arrayContaining(['RootSchema', 'FinalSchema']));
861
+ expect(result).toHaveLength(2);
862
+ });
863
+
864
+ it('should handle multiple nested arrays with references at different levels', () => {
865
+ const schema = new Schema(
866
+ {
867
+ array1: {
868
+ type: 'array',
869
+ items: {
870
+ type: 'object',
871
+ properties: {
872
+ array2: {
873
+ type: 'array',
874
+ items: { $ref: 'NestedItem' }
875
+ }
876
+ }
877
+ }
878
+ }
879
+ },
880
+ 'test-schema'
881
+ );
882
+ const nestedItemSchema = new Schema({ field: { type: 'string' } }, 'NestedItem');
883
+ const schemasMap = {
884
+ 'NestedItem': nestedItemSchema
885
+ };
886
+
887
+ const result = getReferenceIds(schema, schemasMap);
888
+
889
+ expect(result).toEqual(['NestedItem']);
890
+ });
891
+
892
+ it('should handle reference -> array -> reference -> object -> reference (complex transitive chain)', () => {
893
+ const schema = new Schema(
894
+ {
895
+ ref1: { $ref: 'Chain1' }
896
+ },
897
+ 'test-schema'
898
+ );
899
+ const chain1Schema = new Schema(
900
+ {
901
+ items: {
902
+ type: 'array',
903
+ items: { $ref: 'Chain2' }
904
+ }
905
+ },
906
+ 'Chain1'
907
+ );
908
+ const chain2Schema = new Schema(
909
+ {
910
+ nested: {
911
+ type: 'object',
912
+ properties: {
913
+ ref: { $ref: 'Chain3' }
914
+ }
915
+ }
916
+ },
917
+ 'Chain2'
918
+ );
919
+ const chain3Schema = new Schema({ field: { type: 'string' } }, 'Chain3');
920
+ const schemasMap = {
921
+ 'Chain1': chain1Schema,
922
+ 'Chain2': chain2Schema,
923
+ 'Chain3': chain3Schema
924
+ };
925
+
926
+ const result = getReferenceIds(schema, schemasMap);
927
+
928
+ expect(result).toEqual(expect.arrayContaining(['Chain1', 'Chain2', 'Chain3']));
929
+ expect(result).toHaveLength(3);
930
+ });
931
+
932
+ it('should handle object with multiple arrays containing different references', () => {
933
+ const schema = new Schema(
934
+ {
935
+ container: {
936
+ type: 'object',
937
+ properties: {
938
+ array1: {
939
+ type: 'array',
940
+ items: { $ref: 'Schema1' }
941
+ },
942
+ array2: {
943
+ type: 'array',
944
+ items: { $ref: 'Schema2' }
945
+ },
946
+ array3: {
947
+ type: 'array',
948
+ items: {
949
+ type: 'object',
950
+ properties: {
951
+ ref: { $ref: 'Schema3' }
952
+ }
953
+ }
954
+ }
955
+ }
956
+ }
957
+ },
958
+ 'test-schema'
959
+ );
960
+ const schema1 = new Schema({ field: { type: 'string' } }, 'Schema1');
961
+ const schema2 = new Schema({ field: { type: 'string' } }, 'Schema2');
962
+ const schema3 = new Schema({ field: { type: 'string' } }, 'Schema3');
963
+ const schemasMap = {
964
+ 'Schema1': schema1,
965
+ 'Schema2': schema2,
966
+ 'Schema3': schema3
967
+ };
968
+
969
+ const result = getReferenceIds(schema, schemasMap);
970
+
971
+ expect(result).toEqual(expect.arrayContaining(['Schema1', 'Schema2', 'Schema3']));
972
+ expect(result).toHaveLength(3);
973
+ });
974
+ });
975
+ });