@schmock/faker 2.3.0 → 2.3.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 (65) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +45 -0
  3. package/dist/constants.d.ts +82 -1
  4. package/dist/constants.d.ts.map +1 -1
  5. package/dist/field-name-matcher.d.ts +19 -0
  6. package/dist/field-name-matcher.d.ts.map +1 -1
  7. package/dist/index.d.ts +3 -0
  8. package/dist/index.d.ts.map +1 -1
  9. package/dist/index.js +4 -1
  10. package/dist/jsf-config.d.ts +19 -4
  11. package/dist/jsf-config.d.ts.map +1 -1
  12. package/dist/output-limits.d.ts +3 -0
  13. package/dist/output-limits.d.ts.map +1 -0
  14. package/dist/overrides.d.ts +2 -1
  15. package/dist/overrides.d.ts.map +1 -1
  16. package/dist/schema-children.d.ts +14 -0
  17. package/dist/schema-children.d.ts.map +1 -0
  18. package/dist/schema-enhancement.d.ts +1 -0
  19. package/dist/schema-enhancement.d.ts.map +1 -1
  20. package/dist/validation.d.ts +24 -5
  21. package/dist/validation.d.ts.map +1 -1
  22. package/package.json +17 -7
  23. package/dist/constants.js +0 -8
  24. package/dist/field-mappings.js +0 -1114
  25. package/dist/field-name-matcher.js +0 -148
  26. package/dist/jsf-config.js +0 -117
  27. package/dist/overrides.js +0 -137
  28. package/dist/schema-enhancement.js +0 -104
  29. package/dist/test-utils.d.ts +0 -57
  30. package/dist/test-utils.d.ts.map +0 -1
  31. package/dist/test-utils.js +0 -284
  32. package/dist/validation.js +0 -300
  33. package/src/advanced-features.test.ts +0 -912
  34. package/src/audit-faker-args.test.ts +0 -97
  35. package/src/constants.d.ts.map +0 -1
  36. package/src/constants.ts +0 -9
  37. package/src/data-quality.test.ts +0 -415
  38. package/src/error-handling.test.ts +0 -504
  39. package/src/field-mappings.test.ts +0 -351
  40. package/src/field-mappings.ts +0 -1148
  41. package/src/field-name-matcher.test.ts +0 -292
  42. package/src/field-name-matcher.ts +0 -187
  43. package/src/index.d.ts.map +0 -1
  44. package/src/index.test.ts +0 -1320
  45. package/src/index.ts +0 -185
  46. package/src/integration.test.ts +0 -634
  47. package/src/jsf-config.d.ts.map +0 -1
  48. package/src/jsf-config.test.ts +0 -65
  49. package/src/jsf-config.ts +0 -156
  50. package/src/overrides.d.ts.map +0 -1
  51. package/src/overrides.property.test.ts +0 -172
  52. package/src/overrides.test.ts +0 -38
  53. package/src/overrides.ts +0 -179
  54. package/src/performance.test.ts +0 -441
  55. package/src/plugin-integration.test.ts +0 -575
  56. package/src/post-process.test.ts +0 -177
  57. package/src/real-world.test.ts +0 -636
  58. package/src/schema-enhancement.d.ts.map +0 -1
  59. package/src/schema-enhancement.test.ts +0 -222
  60. package/src/schema-enhancement.ts +0 -144
  61. package/src/steps/deterministic-seeds.steps.ts +0 -112
  62. package/src/steps/faker-plugin.steps.ts +0 -301
  63. package/src/test-utils.ts +0 -385
  64. package/src/validation.d.ts.map +0 -1
  65. package/src/validation.ts +0 -417
@@ -1,634 +0,0 @@
1
- import { schmock } from "@schmock/core";
2
- import type { JSONSchema7 } from "json-schema";
3
- import { describe, expect, it } from "vitest";
4
- import { fakerPlugin, generateFromSchema } from "./index";
5
- import { generate, schemas, validators } from "./test-utils";
6
-
7
- describe("Schema Generator Integration Tests", () => {
8
- describe("End-to-End Scenarios", () => {
9
- it("generates complete mock API response with relationships", async () => {
10
- const schema: JSONSchema7 = {
11
- type: "object",
12
- properties: {
13
- user: {
14
- type: "object",
15
- properties: {
16
- id: { type: "string", format: "uuid" },
17
- username: { type: "string", pattern: "^[a-z0-9_]{3,20}$" },
18
- email: { type: "string", format: "email" },
19
- profile: {
20
- type: "object",
21
- properties: {
22
- firstName: { type: "string" },
23
- lastName: { type: "string" },
24
- avatar: { type: "string", format: "uri" },
25
- bio: { type: "string", maxLength: 500 },
26
- },
27
- },
28
- posts: {
29
- type: "array",
30
- items: {
31
- type: "object",
32
- properties: {
33
- id: { type: "string", format: "uuid" },
34
- title: { type: "string", minLength: 1, maxLength: 200 },
35
- content: { type: "string" },
36
- tags: {
37
- type: "array",
38
- items: { type: "string" },
39
- maxItems: 5,
40
- },
41
- publishedAt: { type: "string", format: "date-time" },
42
- comments: {
43
- type: "array",
44
- items: {
45
- type: "object",
46
- properties: {
47
- id: { type: "string", format: "uuid" },
48
- author: { type: "string" },
49
- text: { type: "string" },
50
- createdAt: { type: "string", format: "date-time" },
51
- },
52
- },
53
- },
54
- },
55
- },
56
- },
57
- },
58
- },
59
- },
60
- };
61
-
62
- const result = await generateFromSchema({ schema });
63
-
64
- // Verify complete structure
65
- expect(result.user).toBeDefined();
66
- expect(validators.appearsToBeFromCategory([result.user.id], "uuid")).toBe(
67
- true,
68
- );
69
- expect(result.user.username).toMatch(/^[a-z0-9_]{3,20}$/);
70
- expect(
71
- validators.appearsToBeFromCategory([result.user.email], "email"),
72
- ).toBe(true);
73
-
74
- expect(result.user.profile).toBeDefined();
75
- expect(typeof result.user.profile.firstName).toBe("string");
76
- expect(result.user.profile.firstName.length).toBeGreaterThan(0);
77
-
78
- if (result.user.posts && result.user.posts.length > 0) {
79
- const post = result.user.posts[0];
80
- expect(validators.appearsToBeFromCategory([post.id], "uuid")).toBe(
81
- true,
82
- );
83
- expect(post.title.length).toBeGreaterThan(0);
84
- expect(
85
- validators.appearsToBeFromCategory([post.publishedAt], "date"),
86
- ).toBe(true);
87
- }
88
- });
89
-
90
- it("generates consistent data across related fields", async () => {
91
- const plugin = fakerPlugin({
92
- schema: {
93
- type: "object",
94
- properties: {
95
- order: {
96
- type: "object",
97
- properties: {
98
- id: { type: "string", format: "uuid" },
99
- customerId: { type: "string", format: "uuid" },
100
- items: {
101
- type: "array",
102
- items: {
103
- type: "object",
104
- properties: {
105
- productId: { type: "string", format: "uuid" },
106
- quantity: { type: "integer", minimum: 1 },
107
- unitPrice: { type: "number", minimum: 0 },
108
- totalPrice: { type: "number", minimum: 0 },
109
- },
110
- },
111
- },
112
- subtotal: { type: "number", minimum: 0 },
113
- tax: { type: "number", minimum: 0 },
114
- total: { type: "number", minimum: 0 },
115
- createdAt: { type: "string", format: "date-time" },
116
- updatedAt: { type: "string", format: "date-time" },
117
- },
118
- },
119
- },
120
- },
121
- overrides: {
122
- "order.customerId": "{{params.customerId}}",
123
- "order.createdAt": "{{state.timestamp}}",
124
- "order.updatedAt": "{{state.timestamp}}",
125
- },
126
- });
127
-
128
- const context = {
129
- method: "GET",
130
- path: "/api/orders/123",
131
- params: { orderId: "123", customerId: "customer-456" },
132
- query: {},
133
- state: new Map(),
134
- routeState: { timestamp: "2024-01-01T10:00:00Z" },
135
- headers: {},
136
- body: null,
137
- route: {},
138
- };
139
-
140
- const result = await plugin.process(context);
141
-
142
- expect(result.response.order.customerId).toBe("customer-456");
143
- expect(result.response.order.createdAt).toBe("2024-01-01T10:00:00Z");
144
- expect(result.response.order.updatedAt).toBe("2024-01-01T10:00:00Z");
145
-
146
- // All IDs should be valid UUIDs
147
- expect(
148
- validators.appearsToBeFromCategory([result.response.order.id], "uuid"),
149
- ).toBe(true);
150
-
151
- if (
152
- result.response.order.items &&
153
- result.response.order.items.length > 0
154
- ) {
155
- result.response.order.items.forEach((item) => {
156
- expect(
157
- validators.appearsToBeFromCategory([item.productId], "uuid"),
158
- ).toBe(true);
159
- expect(item.quantity).toBeGreaterThanOrEqual(1);
160
- expect(item.unitPrice).toBeGreaterThanOrEqual(0);
161
- });
162
- }
163
- });
164
- });
165
-
166
- describe("Cross-Package Integration", () => {
167
- it("works with complex nested schemas from multiple sources", async () => {
168
- const addressSchema: JSONSchema7 = {
169
- type: "object",
170
- properties: {
171
- street: { type: "string" },
172
- city: { type: "string" },
173
- state: { type: "string", pattern: "^[A-Z]{2}$" },
174
- zipCode: { type: "string", pattern: "^\\d{5}(-\\d{4})?$" },
175
- country: { type: "string", enum: ["US", "CA", "MX"] },
176
- },
177
- required: ["street", "city", "state", "zipCode", "country"],
178
- };
179
-
180
- const customerSchema: JSONSchema7 = {
181
- type: "object",
182
- properties: {
183
- id: { type: "string", format: "uuid" },
184
- name: { type: "string" },
185
- email: { type: "string", format: "email" },
186
- phone: { type: "string" },
187
- billingAddress: addressSchema,
188
- shippingAddress: addressSchema,
189
- sameAsBilling: { type: "boolean" },
190
- },
191
- };
192
-
193
- const result = await generateFromSchema({ schema: customerSchema });
194
-
195
- // Both addresses should be valid structures
196
- expect(result.billingAddress.street).toBeDefined();
197
- expect(typeof result.billingAddress.street).toBe("string");
198
- expect(result.billingAddress.state).toMatch(/^[A-Z]{2}$/);
199
- expect(result.billingAddress.zipCode).toMatch(/^\d{5}(-\d{4})?$/);
200
-
201
- expect(result.shippingAddress.street).toBeDefined();
202
- expect(typeof result.shippingAddress.street).toBe("string");
203
- expect(["US", "CA", "MX"]).toContain(result.shippingAddress.country);
204
- });
205
-
206
- it("handles schema composition with allOf, anyOf, oneOf", async () => {
207
- const baseSchema: JSONSchema7 = {
208
- type: "object",
209
- properties: {
210
- id: { type: "string", format: "uuid" },
211
- createdAt: { type: "string", format: "date-time" },
212
- },
213
- required: ["id", "createdAt"],
214
- };
215
-
216
- const documentSchema: JSONSchema7 = {
217
- allOf: [
218
- baseSchema,
219
- {
220
- type: "object",
221
- properties: {
222
- title: { type: "string" },
223
- content: {
224
- anyOf: [
225
- { type: "string" },
226
- {
227
- type: "object",
228
- properties: {
229
- html: { type: "string" },
230
- markdown: { type: "string" },
231
- },
232
- },
233
- ],
234
- },
235
- status: {
236
- oneOf: [
237
- { const: "draft" },
238
- { const: "published" },
239
- { const: "archived" },
240
- ],
241
- },
242
- },
243
- required: ["title", "content", "status"],
244
- },
245
- ],
246
- };
247
-
248
- const results = await generate.samples<any>(documentSchema, 10);
249
-
250
- results.forEach((result) => {
251
- // Should have base properties
252
- expect(validators.appearsToBeFromCategory([result.id], "uuid")).toBe(
253
- true,
254
- );
255
- expect(
256
- validators.appearsToBeFromCategory([result.createdAt], "date"),
257
- ).toBe(true);
258
-
259
- // Should have document properties
260
- expect(result).toHaveProperty("title");
261
- expect(result).toHaveProperty("content");
262
- expect(["draft", "published", "archived"]).toContain(result.status);
263
- });
264
- });
265
- });
266
-
267
- describe("State Management Integration", () => {
268
- it("maintains state across multiple generations", async () => {
269
- const _callCount = 0;
270
- const plugin = fakerPlugin({
271
- schema: {
272
- type: "object",
273
- properties: {
274
- requestNumber: { type: "integer" },
275
- sessionId: { type: "string" },
276
- timestamp: { type: "string", format: "date-time" },
277
- },
278
- },
279
- overrides: {
280
- requestNumber: "{{state.requestCount}}",
281
- sessionId: "{{state.sessionId}}",
282
- },
283
- });
284
-
285
- const baseContext = {
286
- method: "GET",
287
- path: "/api/track",
288
- params: {},
289
- query: {},
290
- headers: {},
291
- body: null,
292
- route: {},
293
- };
294
-
295
- // Simulate multiple requests with evolving state
296
- const results: any[] = [];
297
- for (let i = 0; i < 5; i++) {
298
- const context = {
299
- ...baseContext,
300
- state: new Map(),
301
- routeState: {
302
- requestCount: i + 1,
303
- sessionId: "session-123",
304
- },
305
- };
306
- const r = await plugin.process(context);
307
- results.push(r.response);
308
- }
309
-
310
- // Request numbers should increment
311
- results.forEach((result, i) => {
312
- expect(result.requestNumber).toBe(i + 1);
313
- expect(result.sessionId).toBe("session-123");
314
- });
315
- });
316
-
317
- it("generates stateful mock data", async () => {
318
- const cartSchema: JSONSchema7 = {
319
- type: "object",
320
- properties: {
321
- id: { type: "string", format: "uuid" },
322
- userId: { type: "string", format: "uuid" },
323
- items: {
324
- type: "array",
325
- items: {
326
- type: "object",
327
- properties: {
328
- productId: { type: "string", format: "uuid" },
329
- quantity: { type: "integer", minimum: 1 },
330
- addedAt: { type: "string", format: "date-time" },
331
- },
332
- },
333
- },
334
- lastModified: { type: "string", format: "date-time" },
335
- },
336
- };
337
-
338
- // Generate initial cart
339
- const cart1 = await generateFromSchema({ schema: cartSchema });
340
-
341
- // Simulate adding items (would be done through state in real usage)
342
- const cart2 = await generateFromSchema({
343
- schema: cartSchema,
344
- overrides: {
345
- id: cart1.id, // Keep same cart ID
346
- userId: cart1.userId, // Keep same user
347
- lastModified: new Date().toISOString(),
348
- },
349
- });
350
-
351
- expect(cart2.id).toBe(cart1.id);
352
- expect(cart2.userId).toBe(cart1.userId);
353
- });
354
- });
355
-
356
- describe("Performance at Scale", () => {
357
- it("generates large datasets efficiently", async () => {
358
- const schema: JSONSchema7 = {
359
- type: "array",
360
- items: {
361
- type: "object",
362
- properties: {
363
- id: { type: "integer" },
364
- uuid: { type: "string", format: "uuid" },
365
- name: { type: "string" },
366
- email: { type: "string", format: "email" },
367
- active: { type: "boolean" },
368
- score: { type: "number", minimum: 0, maximum: 100 },
369
- tags: {
370
- type: "array",
371
- items: { type: "string" },
372
- maxItems: 3,
373
- },
374
- },
375
- },
376
- };
377
-
378
- const startTime = Date.now();
379
- const result = await generateFromSchema({ schema, count: 100 });
380
- const duration = Date.now() - startTime;
381
-
382
- expect(result).toHaveLength(100);
383
- expect(duration).toBeLessThan(1000); // Should complete in under 1 second
384
-
385
- // Verify data quality at scale
386
- const emails = result.map((item) => item.email);
387
- const uniqueEmails = new Set(emails);
388
- expect(uniqueEmails.size / emails.length).toBeGreaterThan(0.9); // High uniqueness
389
- });
390
-
391
- it("handles concurrent plugin processing", async () => {
392
- const plugin = fakerPlugin({
393
- schema: schemas.complex.user(),
394
- });
395
-
396
- const context = {
397
- method: "GET",
398
- path: "/api/user",
399
- params: {},
400
- query: {},
401
- state: {},
402
- headers: {},
403
- body: null,
404
- route: {},
405
- };
406
-
407
- // Simulate concurrent requests
408
- const promises = Array.from({ length: 20 }, () =>
409
- plugin.process(context),
410
- );
411
-
412
- const results = await Promise.all(promises);
413
-
414
- // All should complete successfully
415
- expect(results).toHaveLength(20);
416
-
417
- // Each should generate unique data
418
- const emails = results.map((r) => r.response.email);
419
- const uniqueEmails = new Set(emails);
420
- expect(uniqueEmails.size).toBeGreaterThan(15); // Most should be unique
421
- });
422
- });
423
-
424
- describe("Error Recovery and Resilience", () => {
425
- it("recovers from validation errors gracefully", async () => {
426
- // First, try invalid schema
427
- try {
428
- await generateFromSchema({
429
- schema: {
430
- type: "object",
431
- properties: {
432
- bad: { type: "invalid" as any },
433
- },
434
- },
435
- });
436
- } catch (_e) {
437
- // Expected
438
- }
439
-
440
- // Should still work with valid schema
441
- const result = await generateFromSchema({
442
- schema: schemas.simple.object({ id: schemas.simple.number() }),
443
- });
444
-
445
- expect(result).toHaveProperty("id");
446
- });
447
-
448
- it("handles partial template failures", async () => {
449
- const plugin = fakerPlugin({
450
- schema: {
451
- type: "object",
452
- properties: {
453
- field1: { type: "string" },
454
- field2: { type: "string" },
455
- field3: { type: "string" },
456
- field4: { type: "string" },
457
- },
458
- },
459
- overrides: {
460
- field1: "{{params.value1}}",
461
- field2: "{{state.missing.nested.value}}",
462
- field3: "static",
463
- field4: "{{query.value4}}",
464
- },
465
- });
466
-
467
- const result = await plugin.process({
468
- method: "GET",
469
- path: "/test",
470
- params: { value1: "success" },
471
- query: { value4: "works" },
472
- state: new Map(),
473
- routeState: {},
474
- headers: {},
475
- body: null,
476
- route: {},
477
- });
478
-
479
- // Successful templates should work
480
- expect(result.response.field1).toBe("success");
481
- expect(result.response.field3).toBe("static");
482
- expect(result.response.field4).toBe("works");
483
-
484
- // Failed template returns original
485
- expect(result.response.field2).toBe("{{state.missing.nested.value}}");
486
- });
487
- });
488
-
489
- describe("Advanced Integration Patterns", () => {
490
- it("supports pagination patterns", async () => {
491
- const paginatedSchema: JSONSchema7 = {
492
- type: "object",
493
- properties: {
494
- items: {
495
- type: "array",
496
- items: {
497
- type: "object",
498
- properties: {
499
- id: { type: "string", format: "uuid" },
500
- name: { type: "string" },
501
- },
502
- },
503
- },
504
- pagination: {
505
- type: "object",
506
- properties: {
507
- page: { type: "integer", minimum: 1 },
508
- pageSize: { type: "integer", minimum: 1, maximum: 100 },
509
- total: { type: "integer", minimum: 0 },
510
- hasNext: { type: "boolean" },
511
- hasPrev: { type: "boolean" },
512
- },
513
- },
514
- },
515
- };
516
-
517
- const plugin = fakerPlugin({
518
- schema: paginatedSchema,
519
- overrides: {
520
- "pagination.page": "{{query.page}}",
521
- "pagination.pageSize": "{{query.limit}}",
522
- "pagination.total": 150,
523
- "pagination.hasNext": "{{state.hasNext}}",
524
- "pagination.hasPrev": "{{state.hasPrev}}",
525
- },
526
- });
527
-
528
- const result = await plugin.process({
529
- method: "GET",
530
- path: "/api/items",
531
- params: {},
532
- query: { page: "2", limit: "20" },
533
- state: new Map(),
534
- routeState: { hasNext: true, hasPrev: true },
535
- headers: {},
536
- body: null,
537
- route: {},
538
- });
539
-
540
- expect(result.response.pagination.page).toBe("2");
541
- expect(result.response.pagination.pageSize).toBe("20");
542
- expect(result.response.pagination.total).toBe(150);
543
- expect(result.response.pagination.hasNext).toBe(true);
544
- });
545
-
546
- it("supports versioned API responses", async () => {
547
- const v1Schema: JSONSchema7 = {
548
- type: "object",
549
- properties: {
550
- version: { const: "1.0" },
551
- data: {
552
- type: "object",
553
- properties: {
554
- id: { type: "number" },
555
- name: { type: "string" },
556
- },
557
- },
558
- },
559
- };
560
-
561
- const v2Schema: JSONSchema7 = {
562
- type: "object",
563
- properties: {
564
- version: { const: "2.0" },
565
- data: {
566
- type: "object",
567
- properties: {
568
- id: { type: "string", format: "uuid" },
569
- name: { type: "string" },
570
- metadata: { type: "object" },
571
- },
572
- },
573
- },
574
- };
575
-
576
- const v1Result = await generateFromSchema({ schema: v1Schema });
577
- const v2Result = await generateFromSchema({ schema: v2Schema });
578
-
579
- expect(v1Result.version).toBe("1.0");
580
- expect(typeof v1Result.data.id).toBe("number");
581
-
582
- expect(v2Result.version).toBe("2.0");
583
- expect(
584
- validators.appearsToBeFromCategory([v2Result.data.id], "uuid"),
585
- ).toBe(true);
586
- expect(v2Result.data).toHaveProperty("metadata");
587
- });
588
- });
589
-
590
- describe("Schmock Handle Integration", () => {
591
- it("resolves state overrides when using schmock.handle() with global state", async () => {
592
- // This test verifies that state-driven template overrides work correctly
593
- // when the schema plugin is used through schmock.handle() with global state
594
- const userState = {
595
- currentUser: {
596
- id: "user-123",
597
- name: "Test User",
598
- },
599
- settings: {
600
- theme: "dark",
601
- },
602
- };
603
-
604
- const mock = schmock({ state: userState });
605
-
606
- const responseSchema: JSONSchema7 = {
607
- type: "object",
608
- properties: {
609
- userId: { type: "string" },
610
- userName: { type: "string" },
611
- theme: { type: "string" },
612
- timestamp: { type: "string" },
613
- },
614
- };
615
-
616
- mock("GET /profile", null).pipe(
617
- fakerPlugin({
618
- schema: responseSchema,
619
- overrides: {
620
- userId: "{{state.currentUser.id}}",
621
- userName: "{{state.currentUser.name}}",
622
- theme: "{{state.settings.theme}}",
623
- },
624
- }),
625
- );
626
-
627
- const response = await mock.handle("GET", "/profile");
628
-
629
- expect(response.body.userId).toBe("user-123");
630
- expect(response.body.userName).toBe("Test User");
631
- expect(response.body.theme).toBe("dark");
632
- });
633
- });
634
- });
@@ -1 +0,0 @@
1
- {"version":3,"file":"jsf-config.d.ts","sourceRoot":"","sources":["jsf-config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAM,KAAK,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,GAAG,MAAM,mBAAmB,CAAC;AAEpC;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,CAAC,EAAE,MAAM,SAMhD;AAoBD,wBAAgB,MAAM,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,OAAO,GAAG,CAuBhD"}
@@ -1,65 +0,0 @@
1
- import type { JSONSchema7 } from "json-schema";
2
- import { describe, expect, it } from "vitest";
3
- import { normalizeSchemaForJsf } from "./jsf-config.js";
4
-
5
- const tuple: JSONSchema7 = {
6
- type: "array",
7
- items: [{ type: "string" }, { type: "integer" }],
8
- minItems: 2,
9
- maxItems: 2,
10
- additionalItems: false,
11
- };
12
-
13
- function expectNormalizedTuple(value: unknown): void {
14
- expect(value).toMatchObject({
15
- type: "array",
16
- prefixItems: [{ type: "string" }, { type: "integer" }],
17
- items: false,
18
- });
19
- expect(value).not.toHaveProperty("additionalItems");
20
- }
21
-
22
- describe("normalizeSchemaForJsf", () => {
23
- it("recurses through Draft-7 schema-bearing keywords", () => {
24
- const normalized = normalizeSchemaForJsf({
25
- type: "object",
26
- definitions: { legacy: tuple },
27
- $defs: { modern: tuple },
28
- patternProperties: { "^tuple$": tuple },
29
- contains: tuple,
30
- not: tuple,
31
- if: tuple,
32
- // biome-ignore lint/suspicious/noThenProperty: JSON Schema's conditional keyword is named "then"
33
- then: tuple,
34
- else: tuple,
35
- });
36
-
37
- const record: Record<string, unknown> = normalized;
38
- const definitions = record.definitions;
39
- const defs = record.$defs;
40
- const patternProperties = record.patternProperties;
41
-
42
- expect(definitions).toBeTypeOf("object");
43
- expect(defs).toBeTypeOf("object");
44
- expect(patternProperties).toBeTypeOf("object");
45
- if (
46
- definitions === null ||
47
- typeof definitions !== "object" ||
48
- defs === null ||
49
- typeof defs !== "object" ||
50
- patternProperties === null ||
51
- typeof patternProperties !== "object"
52
- ) {
53
- throw new Error("Expected normalized schema maps");
54
- }
55
-
56
- expectNormalizedTuple(Reflect.get(definitions, "legacy"));
57
- expectNormalizedTuple(Reflect.get(defs, "modern"));
58
- expectNormalizedTuple(Reflect.get(patternProperties, "^tuple$"));
59
- expectNormalizedTuple(record.contains);
60
- expectNormalizedTuple(record.not);
61
- expectNormalizedTuple(record.if);
62
- expectNormalizedTuple(record.then);
63
- expectNormalizedTuple(record.else);
64
- });
65
- });