json-schema-library 11.0.0 → 11.0.2

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.
@@ -2,1785 +2,1783 @@ import { compileSchema } from "../compileSchema";
2
2
  import { strict as assert } from "assert";
3
3
 
4
4
  describe("getData", () => {
5
- it("should not modify input schema", () => {
6
- const schema = {
7
- type: "object",
8
- properties: {
9
- title: { type: "string", default: "title" },
10
- list: {
11
- type: "array",
12
- items: { allOf: [{ type: "object" }, { properties: { index: { type: "number", default: 4 } } }] }
13
- },
14
- author: {
15
- anyOf: [
16
- { type: "string", default: "jane" },
17
- { type: "string", default: "john" }
18
- ]
19
- },
20
- source: { type: "string", enum: ["dpa", "getty"] }
21
- }
22
- };
23
- const originalSchema = JSON.stringify(schema);
24
- const node = compileSchema(schema);
25
- node.getData({});
26
- assert.deepEqual(JSON.stringify(schema), originalSchema);
27
- });
28
-
29
- describe("values", () => {
30
- it("should return default value missing input and type", () => {
31
- const data = compileSchema({ default: 123 }).getData();
32
- assert.deepEqual(data, 123);
33
- });
34
-
35
- it("should NOT override input value for missing type", () => {
36
- const data = compileSchema({ default: 123 }).getData("input");
37
- assert.deepEqual(data, "input");
38
- });
39
-
40
- // @attention, changing input data
41
- it("should alwayys return const value", () => {
42
- const data = compileSchema({ const: "const", default: 123 }).getData(123);
43
- assert.deepEqual(data, "const");
44
- });
45
-
46
- it("should prefer const over default", () => {
47
- const data = compileSchema({
48
- type: "string",
49
- const: "static",
50
- default: "should be overwritten"
51
- }).getData();
52
- assert.deepEqual(data, "static");
53
- });
54
-
55
- describe("string", () => {
56
- it("should return empty string for missing default value", () => {
57
- const data = compileSchema({ type: "string" }).getData();
58
- assert.deepEqual(data, "");
59
- });
60
-
61
- it("should return default value", () => {
62
- const data = compileSchema({
63
- type: "string",
64
- default: "default"
65
- }).getData();
66
- assert.deepEqual(data, "default");
67
- });
68
-
69
- it("should return string data", () => {
70
- const data = compileSchema({
71
- type: "string",
72
- default: "default"
73
- }).getData("input");
74
- assert.deepEqual(data, "input");
75
- });
76
- });
77
-
78
- describe("number", () => {
79
- it("should return 0 for missing default value", () => {
80
- const data = compileSchema({ type: "number" }).getData();
81
- assert.deepEqual(data, 0);
82
- });
83
-
84
- it("should return default value", () => {
85
- const data = compileSchema({ type: "number", default: 99 }).getData();
86
- assert.deepEqual(data, 99);
87
- });
88
-
89
- it("should return number data", () => {
90
- const data = compileSchema({ type: "number", default: 99 }).getData(123);
91
- assert.deepEqual(data, 123);
92
- });
93
- });
94
-
95
- describe("integer", () => {});
96
-
97
- describe("boolean", () => {
98
- it("should return `false` for missing default value", () => {
99
- const data = compileSchema({ type: "boolean", default: false }).getData();
100
- assert.deepEqual(data, false);
101
- });
102
-
103
- it("should return default value of boolean", () => {
104
- const data = compileSchema({ type: "boolean", default: false }).getData();
105
- assert.deepEqual(data, false);
106
- });
107
-
108
- it("should not override given boolean if it is `false`", () => {
109
- const data = compileSchema({ type: "boolean", default: true }).getData(false);
110
- assert.deepEqual(data, false);
111
- });
112
-
113
- it("should not override given boolean if it is `true`", () => {
114
- const data = compileSchema({ type: "boolean", default: false }).getData(true);
115
- assert.deepEqual(data, true);
116
- });
117
- });
118
-
119
- describe("null", () => {
120
- it("should return `null` for missing default value", () => {
121
- const data = compileSchema({ type: "null" }).getData();
122
- assert.deepEqual(data, null);
123
- });
124
-
125
- it("should return `null` when first type in type-array", () => {
126
- const node = compileSchema({ type: ["null", "string"] });
127
- const res = node.getData();
128
-
129
- assert.deepEqual(res, null);
130
- });
131
-
132
- it("should return default value of null", () => {
133
- const data = compileSchema({ type: "null", default: null }).getData();
134
- assert.deepEqual(data, null);
135
- });
136
-
137
- it("should return default value of null even for wrong typye", () => {
138
- const data = compileSchema({ type: "number", default: null }).getData();
139
- assert.deepEqual(data, null);
140
- });
141
-
142
- it("should support `null` type properties", () => {
143
- const data = compileSchema({
144
- type: "object",
145
- required: ["nullType"],
146
- properties: { nullType: { type: "null" } }
147
- }).getData();
148
- assert.deepEqual(data, { nullType: null });
149
- });
150
-
151
- it("should return `null` input for strings", () => {
152
- const data = compileSchema({ type: "string" }).getData(null);
153
- assert.deepEqual(data, null);
154
- });
155
-
156
- it("should return `null` input for value-property", () => {
157
- const data = compileSchema({
158
- type: "object",
159
- required: ["title"],
160
- properties: { title: { type: "number" } }
161
- }).getData({ title: null });
162
- assert.deepEqual(data, { title: null });
163
- });
164
- });
165
-
166
- describe("enum", () => {
167
- it("should set the first enum option for a missing default", () => {
168
- const data = compileSchema({ enum: ["first", "second"] }).getData();
169
- assert.deepEqual(data, "first");
170
- });
171
-
172
- it("should use default value in any case", () => {
173
- const data = compileSchema({ enum: ["first", "second"], default: "" }).getData();
174
- assert.deepEqual(data, "");
175
- });
176
- });
177
-
178
- describe("file", () => {
179
- it("should not modify file-instance", () => {
180
- const file = new File([], "testfile.pdf");
181
- const data = compileSchema({
182
- type: ["string", "object"],
183
- format: "file"
184
- }).getData(file);
185
- assert.deepEqual(data, file);
186
- });
187
-
188
- it("should not modify file-instance on object", () => {
189
- const file = new File([], "testfile.pdf");
190
- const data = compileSchema({
191
- type: "object",
192
- properties: { file: { type: ["string", "object"], format: "file" } }
193
- }).getData({ file });
194
- assert.deepEqual(data, { file });
195
- });
196
- });
197
-
198
- describe("oneOf", () => {
199
- it("should return first schema for mixed types", () => {
200
- const node = compileSchema({
201
- oneOf: [{ type: "string", default: "jane" }, { type: "number" }]
202
- });
203
- const res = node.getData();
204
-
205
- assert.deepEqual(res, "jane");
206
- });
207
- });
208
- });
209
-
210
- describe("object", () => {
211
- describe("behaviour", () => {
212
- it("should return {} for a missing default value", () => {
213
- const data = compileSchema({ type: "object" }).getData();
214
- assert.deepEqual(data, {});
215
- });
216
-
217
- it("should return default value of object", () => {
218
- const data = compileSchema({
219
- type: "object",
220
- default: { init: true }
221
- }).getData();
222
- assert.deepEqual(data, { init: true });
223
- });
224
-
225
- it("should return input data", () => {
226
- const data = compileSchema({ type: "object" }).getData({ init: false });
227
- assert.deepEqual(data, { init: false });
228
- });
229
-
230
- it("should override default by input data", () => {
231
- const data = compileSchema({
232
- type: "object",
233
- default: { init: true }
234
- }).getData({ init: false });
235
- assert.deepEqual(data, { init: false });
236
- });
237
- });
238
-
239
- describe("properties", () => {
240
- it("should return default object", () => {
241
- const data = compileSchema({
242
- type: "object",
243
- properties: { first: { type: "string" }, second: { type: "number" } },
244
- default: { first: "john", second: 4 }
245
- }).getData();
246
- assert.deepEqual(data, { first: "john", second: 4 });
247
- });
248
-
249
- it("should return only required object properties", () => {
250
- const data = compileSchema({
251
- type: "object",
252
- required: ["first"],
253
- properties: { first: { type: "string" }, second: { type: "number" } }
254
- }).getData();
255
- assert.deepEqual(data, { first: "" });
256
- });
257
-
258
- it("should not fail on falsy input data", () => {
259
- const data = compileSchema({
260
- type: "object",
261
- properties: {
262
- first: { type: "boolean", default: true },
263
- second: { type: "boolean", default: false }
264
- }
265
- }).getData({ first: false, second: true });
266
- assert.deepEqual(data, { first: false, second: true });
267
- });
268
-
269
- it("should return all object properties with `addOptionalProps=true`", () => {
270
- const data = compileSchema({
271
- type: "object",
272
- required: ["first", "second"],
273
- properties: { first: { type: "string" }, second: { type: "number" } }
274
- }).getData({}, { addOptionalProps: true });
275
- assert.deepEqual(data, { first: "", second: 0 });
276
- });
277
-
278
- it("should NOT override given default values by other default values", () => {
279
- const data = compileSchema({
280
- type: "object",
281
- properties: { first: { type: "string", default: "jane" }, second: { type: "number" } },
282
- default: { first: "john", second: 4 }
283
- }).getData();
284
- assert.deepEqual(data, { first: "john", second: 4 });
285
- });
286
-
287
- it("should extend given template data by property default values", () => {
288
- const data = compileSchema({
289
- type: "object",
290
- properties: { first: { type: "string", default: "jane" }, second: { type: "number" } },
291
- default: { first: "john", second: 4 }
292
- }).getData({ second: 8 });
293
- assert.deepEqual(data, { first: "john", second: 8 });
294
- });
295
- });
296
-
297
- describe("additionalProperties & option: removeInvalidData", () => {
298
- it("should NOT remove additional properties `additionalProperties=undefined`", () => {
299
- const data = compileSchema({
300
- type: "object",
301
- required: ["first", "second"],
302
- properties: { first: { type: "string" } }
303
- }).getData({ first: "first", second: 42 });
304
- assert.deepEqual(data, { first: "first", second: 42 });
305
- });
306
-
307
- it("should NOT remove additional properties `additionalProperties=true`", () => {
308
- const data = compileSchema({
309
- type: "object",
310
- required: ["first", "second"],
311
- properties: { first: { type: "string" } },
312
- additionalProperties: true
313
- }).getData({ first: "first", second: 42 });
314
- assert.deepEqual(data, { first: "first", second: 42 });
315
- });
316
-
317
- it("should NOT remove non matching properties with `additionalProperties={schema}`", () => {
318
- const data = compileSchema({
319
- type: "object",
320
- required: ["first", "second"],
321
- properties: { first: { type: "string" } },
322
- additionalProperties: { type: "string" }
323
- }).getData({ first: "first", second: 42 });
324
- assert.deepEqual(data, { first: "first", second: 42 });
325
- });
326
-
327
- it("should NOT remove additional properties with `additionalProperties=false`", () => {
328
- const data = compileSchema({
329
- type: "object",
330
- required: ["first", "second"],
331
- properties: { first: { type: "string" } },
332
- additionalProperties: false
333
- }).getData({ first: "first", second: 42 });
334
- assert.deepEqual(data, { first: "first", second: 42 });
335
- });
336
-
337
- it("should remove unmatched properties with option `removeInvalidData=true`", () => {
338
- const data = compileSchema({
339
- type: "object",
340
- required: ["first", "second"],
341
- properties: { first: { type: "string" } },
342
- additionalProperties: false
343
- }).getData({ first: "first", second: 42, thrid: "third" }, { removeInvalidData: true });
344
- assert.deepEqual(data, { first: "first" });
345
- });
346
-
347
- it("should remove invalid properties with option `removeInvalidData=true`", () => {
348
- const data = compileSchema({
349
- type: "object",
350
- required: ["first", "second"],
351
- properties: { first: { type: "string" } },
352
- additionalProperties: { type: "number" }
353
- }).getData({ first: "first", second: 42, third: "third", fourth: false }, { removeInvalidData: true });
354
- assert.deepEqual(data, { first: "first", second: 42 });
355
- });
356
- });
357
-
358
- // patternNames
359
- // patternProperties
360
- // dependentSchemas
361
- // dependentRequired
362
- // (unevaluatedPoperties)
363
-
364
- describe("allOf", () => {
365
- it("should create template for merged allOf schema", () => {
366
- const data = compileSchema({
367
- type: "object",
368
- allOf: [
369
- {
370
- required: ["name"],
371
- properties: { name: { type: "string", default: "jane" } }
372
- },
373
- {
374
- required: ["stage"],
375
- properties: { stage: { type: "string", default: "test" } }
376
- }
377
- ]
378
- }).getData({ name: "john" });
379
- assert.deepEqual(data, { name: "john", stage: "test" });
380
- });
381
- });
382
-
383
- describe("anyOf", () => {
384
- it("should create template for first anyOf schema", () => {
385
- const node = compileSchema({
386
- type: "object",
387
- anyOf: [
388
- {
389
- required: ["name", "stage"],
390
- properties: {
391
- name: { type: "string", default: "jane" },
392
- stage: { type: "string", default: "develop" }
393
- }
394
- },
395
- {
396
- required: ["stage"],
397
- properties: {
398
- stage: { type: "number", default: 0 }
399
- }
400
- }
401
- ]
402
- });
403
- const res = node.getData({ name: "john" });
404
-
405
- assert.deepEqual(res, { name: "john", stage: "develop" });
406
- });
407
- });
408
-
409
- describe("oneOf", () => {
410
- describe("oneOf", () => {
411
- it("should return template of first oneOf schema", () => {
412
- const node = compileSchema({
413
- type: "object",
414
- oneOf: [
415
- {
416
- type: "object",
417
- required: ["title"],
418
- properties: {
419
- title: { type: "string", default: "jane" }
420
- }
421
- },
422
- {
423
- type: "object",
424
- required: ["value"],
425
- properties: { value: { type: "number" } }
426
- }
427
- ]
428
- });
429
- const res = node.getData();
430
-
431
- assert.deepEqual(res, { title: "jane" });
432
- });
433
-
434
- it("should extend empty object with first oneOf schema", () => {
435
- const node = compileSchema({
436
- type: "object",
437
- oneOf: [
438
- {
439
- type: "object",
440
- required: ["title"],
441
- properties: {
442
- title: { type: "string", default: "jane" }
443
- }
444
- },
445
- {
446
- type: "object",
447
- required: ["value"],
448
- properties: { value: { type: "number" } }
449
- }
450
- ]
451
- });
452
- const res = node.getData({});
453
-
454
- assert.deepEqual(res, { title: "jane" });
455
- });
456
-
457
- it("should return template of matching oneOf schema", () => {
458
- const node = compileSchema({
459
- type: "object",
460
- oneOf: [
461
- {
462
- type: "object",
463
- required: ["value"],
464
- properties: {
465
- value: { type: "string", default: "jane" }
466
- }
467
- },
468
- {
469
- type: "object",
470
- required: ["value", "test"],
471
- properties: {
472
- value: { type: "number" },
473
- test: { type: "string", default: "test" }
474
- }
475
- }
476
- ]
477
- });
478
- const res = node.getData({ value: 111 });
479
-
480
- assert.deepEqual(res, { value: 111, test: "test" });
481
- });
482
-
483
- it("should return input value if no oneOf-schema matches ", () => {
484
- const node = compileSchema({
485
- type: "object",
486
- oneOf: [
487
- {
488
- type: "object",
489
- properties: {
490
- value: { type: "string", default: "jane" }
491
- }
492
- },
493
- {
494
- type: "object",
495
- properties: {
496
- value: { type: "number" },
497
- test: { type: "string", default: "test" }
498
- }
499
- }
500
- ]
501
- });
502
- const res = node.getData({ value: ["keep-me"] });
503
-
504
- assert.deepEqual(res, { value: ["keep-me"] });
505
- });
506
-
507
- it("should not require object type definition in oneOf schemas", () => {
508
- const node = compileSchema({
509
- type: "object",
510
- oneOf: [
511
- {
512
- required: ["type"],
513
- properties: {
514
- type: { const: "header" }
515
- }
516
- },
517
- {
518
- required: ["type"],
519
- properties: {
520
- type: { const: "paragraph" }
521
- }
522
- }
523
- ]
524
- });
525
-
526
- const res = node.getData({ type: "paragraph" });
527
- assert.deepEqual(res, { type: "paragraph" });
528
- });
529
-
530
- it("should return valid default data", () => {
531
- const node = compileSchema({
532
- type: "object",
533
- default: { value: 123 },
534
- oneOf: [
535
- {
536
- type: "object",
537
- required: ["title"],
538
- properties: { title: { type: "string", default: "jane" } }
539
- },
540
- { type: "object", required: ["value"], properties: { value: { type: "number" } } }
541
- ]
542
- });
543
- const res = node.getData();
544
-
545
- assert.deepEqual(res, { value: 123 });
546
- });
547
-
548
- it("should return invalid default data", () => {
549
- const node = compileSchema({
550
- type: "object",
551
- default: { value: "wrong type" },
552
- oneOf: [
553
- {
554
- type: "object",
555
- required: ["title"],
556
- properties: { title: { type: "string", default: "jane" } }
557
- },
558
- { type: "object", required: ["value"], properties: { value: { type: "number" } } }
559
- ]
560
- });
561
- const res = node.getData();
562
-
563
- assert.deepEqual(res, { value: "wrong type" });
564
- });
565
-
566
- it("should add correct optional properties from schema matching default data", () => {
567
- const node = compileSchema({
568
- type: "object",
569
- default: { value: 123 },
570
- oneOf: [
571
- {
572
- type: "object",
573
- required: ["title"],
574
- properties: { title: { type: "string", default: "jane" } }
575
- },
576
- {
577
- type: "object",
578
- required: ["value"],
579
- properties: { value: { type: "number" }, optional: { type: "string" } }
580
- }
581
- ]
582
- });
583
- const res = node.getData(undefined, { addOptionalProps: true });
584
-
585
- assert.deepEqual(res, { value: 123, optional: "" });
586
- });
587
- });
588
- });
589
- });
590
-
591
- describe("array", () => {
592
- describe("behaviour", () => {
593
- it("should return [] for a missing default value", () => {
594
- const data = compileSchema({ type: "array" }).getData();
595
- assert.deepEqual(data, []);
596
- });
597
-
598
- it("should return default value of object", () => {
599
- const data = compileSchema({ type: "array", default: [true] }).getData();
600
- assert.deepEqual(data, [true]);
601
- });
602
-
603
- it("should return input data", () => {
604
- const data = compileSchema({ type: "array" }).getData(["input"]);
605
- assert.deepEqual(data, ["input"]);
606
- });
607
-
608
- it("should override default by input data", () => {
609
- const data = compileSchema({
610
- type: "array",
611
- default: ["default"]
612
- }).getData(["input"]);
613
- assert.deepEqual(data, ["input"]);
614
- });
615
- });
616
-
617
- describe("items: {}", () => {
618
- it("should return empty array if minItems is undefined", () => {
619
- const data = compileSchema({ items: { type: "boolean" } }).getData();
620
- assert.deepEqual(data, []);
621
- });
622
-
623
- it("should return array with length of minItems", () => {
624
- const data = compileSchema({
625
- minItems: 3,
626
- items: { type: "boolean" }
627
- }).getData();
628
- assert(Array.isArray(data));
629
- assert.deepEqual(data.length, 3);
630
- assert.deepEqual(data, [false, false, false]);
631
- });
632
-
633
- it("should return default array even if minItems is not set", () => {
634
- const data = compileSchema({
635
- default: ["a", "b"],
636
- items: { type: "string" }
637
- }).getData();
638
- assert.deepEqual(data, ["a", "b"]);
639
- });
640
-
641
- it("should return default array if part of object", () => {
642
- const data = compileSchema({
643
- required: ["list"],
644
- properties: { list: { type: "array", default: ["a", "b"], items: { type: "string" } } }
645
- }).getData();
646
- assert.deepEqual(data, { list: ["a", "b"] });
647
- });
648
-
649
- it("should not override given default values", () => {
650
- const data = compileSchema({
651
- minItems: 2,
652
- default: ["abba", "doors"],
653
- items: { type: "string", default: "elvis" }
654
- }).getData();
655
- assert.deepEqual(data, ["abba", "doors"]);
656
- });
657
-
658
- it("should extend given template data by default values", () => {
659
- const data = compileSchema({
660
- minItems: 2,
661
- default: ["abba", "doors"],
662
- items: { type: "string" }
663
- }).getData(["elvis"]);
664
- assert.deepEqual(data, ["elvis", "doors"]);
665
- });
666
-
667
- it("should extend all input objects by missing properties", () => {
668
- const data = compileSchema({
669
- default: ["abba", "doors"],
670
- items: {
671
- type: "object",
672
- required: ["first", "second"],
673
- properties: {
674
- first: { type: "string", default: "first" },
675
- second: { type: "string", default: "second" }
676
- }
677
- }
678
- }).getData([{ first: "user input" }, {}]);
679
- assert.deepEqual(data, [
680
- { first: "user input", second: "second" },
681
- { first: "first", second: "second" }
682
- ]);
683
- });
684
-
685
- it("should resolve $ref in items-object", () => {
686
- const data = compileSchema({
687
- minItems: 1,
688
- items: { $ref: "/$defs/bool" },
689
- $defs: {
690
- bool: { type: "boolean", default: true }
691
- }
692
- }).getData();
693
- assert(Array.isArray(data));
694
- assert.deepEqual(data.length, 1);
695
- assert.deepEqual(data, [true]);
696
- });
697
- });
698
-
699
- describe("prefixItems: []", () => {
700
- // - Tuple validation is useful when the array is a collection of items where each has a different schema
701
- // and the ordinal index of each item is meaningful.
702
- // - It’s ok to not provide all of the items:
703
- // https://spacetelescope.github.io/understanding-json-schema/reference/array.html#tuple-validation
704
- it("should return array with minItems in given order", () => {
705
- const data = compileSchema({
706
- type: "array",
707
- minItems: 2,
708
- prefixItems: [{ type: "string" }, { type: "boolean" }]
709
- }).getData();
710
- assert.deepEqual(data, ["", false]);
711
- });
712
-
713
- it("should not override input items when complementing minItems", () => {
714
- const data = compileSchema({
715
- type: "array",
716
- minItems: 2,
717
- prefixItems: [{ type: "boolean", default: false }, { type: "string" }]
718
- }).getData([true]);
719
- assert.deepEqual(data, [true, ""]);
720
- });
721
-
722
- it("should not override wrong input items", () => {
723
- const data = compileSchema({
724
- type: "array",
725
- prefixItems: [
726
- { type: "boolean", default: false },
727
- { type: "string", default: "default" }
728
- ]
729
- }).getData([42, false]);
730
- assert.deepEqual(data, [42, "false"]);
731
- });
732
-
733
- it("should return default array", () => {
734
- const data = compileSchema({
735
- type: "array",
736
- minItems: 1,
737
- default: [true],
738
- items: {
739
- type: "boolean"
740
- }
741
- }).getData();
742
- assert.deepEqual(data, [true]);
743
- });
744
-
745
- it("should convert input data for strings", () => {
746
- const node = compileSchema({
747
- type: "array",
748
- minItems: 1,
749
- prefixItems: [{ type: "string" }]
750
- });
751
- const res = node.getData([43]);
752
-
753
- assert.deepEqual(res, ["43"]);
754
- });
755
-
756
- it("should convert input data for numbers", () => {
757
- const data = compileSchema({
758
- type: "array",
759
- minItems: 1,
760
- prefixItems: [{ type: "number" }]
761
- }).getData(["43"]);
762
- assert.deepEqual(data, [43]);
763
- });
764
-
765
- it("should convert input data for strings", () => {
766
- const data = compileSchema({
767
- type: "array",
768
- minItems: 1,
769
- prefixItems: [{ type: "string" }]
770
- }).getData([43]);
771
- assert.deepEqual(data, ["43"]);
772
- });
773
-
774
- it("should NOT convert invalid number if we would lose data", () => {
775
- const data = compileSchema({
776
- type: "array",
777
- minItems: 1,
778
- prefixItems: [{ type: "number" }]
779
- }).getData(["asd"]);
780
- assert.deepEqual(data, ["asd"]);
781
- });
782
-
783
- it("should convert input data for booleans", () => {
784
- const data = compileSchema({
785
- type: "array",
786
- minItems: 1,
787
- prefixItems: [{ type: "boolean" }]
788
- }).getData(["false"]);
789
- assert.deepEqual(data, [false]);
790
- });
791
-
792
- it("should NOT convert invalid boolean if we would lose data", () => {
793
- const data = compileSchema({
794
- type: "array",
795
- minItems: 1,
796
- prefixItems: [{ type: "boolean" }]
797
- }).getData(["43"]);
798
- assert.deepEqual(data, ["43"]);
799
- });
800
-
801
- it("should add defaults from `items`", () => {
802
- const data = compileSchema({
803
- type: "array",
804
- minItems: 2,
805
- items: {
806
- type: "number",
807
- default: 2
808
- }
809
- }).getData([43]);
810
- assert.deepEqual(data, [43, 2]);
811
- });
812
-
813
- it("should add defaults from `items` for items not in prefixItems", () => {
814
- const data = compileSchema({
815
- type: "array",
816
- minItems: 2,
817
- prefixItems: [{ type: "boolean" }],
818
- items: { type: "number", default: 2 }
819
- }).getData([43]);
820
- assert.deepEqual(data, [43, 2]);
821
- });
822
-
823
- it("should add prefixItems with `addOptionalProps: true`", () => {
824
- const data = compileSchema(
825
- {
826
- type: "array",
827
- prefixItems: [{ type: "boolean", default: true }],
828
- items: { type: "number", default: 2 }
829
- },
830
- {
831
- getDataDefaultOptions: { addOptionalProps: true }
832
- }
833
- ).getData();
834
- assert.deepEqual(data, [true]);
835
- });
836
-
837
- it("should resolve $ref in prefixItems", () => {
838
- const node = compileSchema({
839
- type: "array",
840
- minItems: 2,
841
- prefixItems: [{ $ref: "/$defs/bool" }, { $ref: "/$defs/string" }],
842
- $defs: {
843
- bool: { type: "boolean" },
844
- string: { type: "string" }
845
- }
846
- });
847
- const res = node.getData([]);
848
-
849
- assert.deepEqual(res, [false, ""]);
850
- });
851
- });
852
-
853
- describe("oneOf", () => {
854
- it("should return template of first oneOf schema", () => {
855
- const node = compileSchema({
856
- type: "array",
857
- minItems: 1,
858
- items: {
859
- oneOf: [
860
- { type: "string", default: "target" },
861
- { type: "number", default: 9 }
862
- ]
863
- }
864
- });
865
- const res = node.getData();
866
-
867
- assert(Array.isArray(res));
868
- assert.deepEqual(res.length, 1);
869
- assert.deepEqual(res, ["target"]);
870
- });
871
-
872
- it("should merge with input data", () => {
873
- const node = compileSchema({
874
- type: "array",
875
- minItems: 1,
876
- items: {
877
- oneOf: [
878
- {
879
- type: "object",
880
- required: ["notitle"],
881
- properties: {
882
- notitle: {
883
- type: "string",
884
- default: "nottitle"
885
- }
886
- }
887
- },
888
- {
889
- type: "object",
890
- required: ["title", "subtitle"],
891
- properties: {
892
- title: {
893
- type: "string",
894
- default: "Standardtitel"
895
- },
896
- subtitle: {
897
- type: "string",
898
- default: "do not replace with"
899
- }
900
- }
901
- },
902
- { type: "number", default: 9 }
903
- ]
904
- }
905
- });
906
-
907
- const res = node.getData([{ subtitle: "Subtitel" }]);
908
-
909
- assert(Array.isArray(res));
910
- assert.deepEqual(res.length, 1);
911
- assert.deepEqual(res, [{ title: "Standardtitel", subtitle: "Subtitel" }]);
912
- });
913
-
914
- it("should not remove invalid oneOf schema if 'removeInvalidData' is unset", () => {
915
- const node = compileSchema({
916
- type: "object",
917
- properties: {
918
- filter: {
919
- $ref: "#/definitions/filter"
920
- }
921
- },
922
- definitions: {
923
- filter: {
924
- type: "array",
925
- items: {
926
- oneOf: [
927
- {
928
- type: "object",
929
- properties: {
930
- op: {
931
- const: "in"
932
- },
933
- property: { type: "string", minLength: 1 }
934
- }
935
- }
936
- ]
937
- }
938
- }
939
- }
940
- });
941
- const res = node.getData({ filter: [{ op: "möp" }] });
942
- assert.deepEqual(res, { filter: [{ op: "möp" }] });
943
- });
944
- });
945
-
946
- describe("allOf", () => {
947
- it("should create template for merged allOf schema", () => {
948
- const node = compileSchema({
949
- type: "array",
950
- minItems: 2,
951
- items: {
952
- type: "object",
953
- allOf: [
954
- {
955
- required: ["title"],
956
- properties: {
957
- title: { type: "string", default: "title" }
958
- }
959
- },
960
- {
961
- required: ["caption"],
962
- properties: {
963
- caption: {
964
- type: "string",
965
- default: "caption"
966
- }
967
- }
968
- }
969
- ]
970
- }
971
- });
972
-
973
- const res = node.getData([{ title: "given-title" }]);
974
- assert.deepEqual(res, [
975
- { title: "given-title", caption: "caption" },
976
- { title: "title", caption: "caption" }
977
- ]);
978
- });
979
- });
980
-
981
- describe("anyOf", () => {
982
- it("should create template for first anyOf schema", () => {
983
- const node = compileSchema({
984
- type: "array",
985
- minItems: 2,
986
- items: {
987
- type: "object",
988
- anyOf: [
989
- {
990
- required: ["title"],
991
- properties: {
992
- title: { type: "string", default: "title" }
993
- }
994
- },
995
- {
996
- required: ["properties"],
997
- properties: {
998
- caption: {
999
- type: "string",
1000
- default: "caption"
1001
- }
1002
- }
1003
- }
1004
- ]
1005
- }
1006
- });
1007
-
1008
- const res = node.getData([{ title: "given-title" }]);
1009
- assert.deepEqual(res, [{ title: "given-title" }, { title: "title" }]);
1010
- });
1011
- });
1012
-
1013
- // draft07 (backwards compatible)
1014
- describe("dependencies", () => {
1015
- describe("option: `additionalProps: false`", () => {
1016
- const TEMPLATE_OPTIONS = { addOptionalProps: false };
1017
- describe("dependency required", () => {
1018
- it("should not add dependency if it is not required", () => {
1019
- const node = compileSchema({
1020
- type: "object",
1021
- properties: {
1022
- trigger: { type: "string" },
1023
- dependency: { type: "string", default: "default" }
1024
- },
1025
- dependencies: {
1026
- trigger: ["dependency"]
1027
- }
1028
- });
1029
-
1030
- const res = node.getData({}, TEMPLATE_OPTIONS);
1031
- assert.deepEqual(res, {});
1032
- });
1033
-
1034
- it("should add dependency if triggered as required", () => {
1035
- const node = compileSchema({
1036
- type: "object",
1037
- properties: {
1038
- trigger: { type: "string" },
1039
- dependency: { type: "string", default: "default" }
1040
- },
1041
- dependencies: {
1042
- trigger: ["dependency"]
1043
- }
1044
- });
1045
-
1046
- const res = node.getData({ trigger: "yes" }, TEMPLATE_OPTIONS);
1047
- assert.deepEqual(res, { trigger: "yes", dependency: "default" });
1048
- });
1049
-
1050
- it("should add dependency if initially triggered as required", () => {
1051
- const node = compileSchema({
1052
- type: "object",
1053
- required: ["trigger"],
1054
- properties: {
1055
- trigger: { type: "string" },
1056
- dependency: { type: "string", default: "default" }
1057
- },
1058
- dependencies: {
1059
- trigger: ["dependency"]
1060
- }
1061
- });
1062
-
1063
- const res = node.getData({}, TEMPLATE_OPTIONS);
1064
- assert.deepEqual(res, { trigger: "", dependency: "default" });
1065
- });
1066
- });
1067
-
1068
- describe("dependency schema", () => {
1069
- it("should not add dependency from schema if it is not required", () => {
1070
- const node = compileSchema({
1071
- type: "object",
1072
- properties: {
1073
- trigger: { type: "string" }
1074
- },
1075
- dependencies: {
1076
- trigger: {
1077
- properties: {
1078
- dependency: { type: "string", default: "default" }
1079
- }
1080
- }
1081
- }
1082
- });
1083
-
1084
- const res = node.getData({}, TEMPLATE_OPTIONS);
1085
- assert.deepEqual(res, {});
1086
- });
1087
-
1088
- it("should add dependency from schema if triggered as required", () => {
1089
- const node = compileSchema({
1090
- type: "object",
1091
- properties: {
1092
- trigger: { type: "string" }
1093
- },
1094
- dependencies: {
1095
- trigger: {
1096
- required: ["dependency"],
1097
- properties: {
1098
- dependency: { type: "string", default: "default" }
1099
- }
1100
- }
1101
- }
1102
- });
1103
-
1104
- const res = node.getData({ trigger: "yes" }, TEMPLATE_OPTIONS);
1105
- assert.deepEqual(res, { trigger: "yes", dependency: "default" });
1106
- });
1107
- });
1108
- });
1109
-
1110
- describe("option: `additionalProps: true`", () => {
1111
- it("should create template for valid dependency", () => {
1112
- const node = compileSchema({
1113
- type: "object",
1114
- properties: {
1115
- test: { type: "string", default: "tested value" }
1116
- },
1117
- dependencies: {
1118
- test: {
1119
- properties: {
1120
- additionalValue: { type: "string", default: "additional" }
1121
- }
1122
- }
1123
- }
1124
- });
1125
- const res = node.getData(undefined, {
1126
- addOptionalProps: true
1127
- });
1128
- assert.deepEqual(res, {
1129
- test: "tested value",
1130
- additionalValue: "additional"
1131
- });
1132
- });
1133
-
1134
- it("should not change passed value of dependency", () => {
1135
- const node = compileSchema({
1136
- type: "object",
1137
- properties: {
1138
- test: { type: "string", default: "tested value" }
1139
- },
1140
- dependencies: {
1141
- test: {
1142
- properties: {
1143
- additionalValue: { type: "string", default: "additional" }
1144
- }
1145
- }
1146
- }
1147
- });
1148
- const res = node.getData(
1149
- { additionalValue: "input value" },
1150
- {
1151
- addOptionalProps: true
1152
- }
1153
- );
1154
- assert.deepEqual(res, {
1155
- test: "tested value",
1156
- additionalValue: "input value"
1157
- });
1158
- });
1159
-
1160
- it("should not create data for non matching dependency", () => {
1161
- const node = compileSchema({
1162
- type: "object",
1163
- properties: {
1164
- test: { type: "string", default: "tested value" }
1165
- },
1166
- dependencies: {
1167
- unknown: {
1168
- properties: {
1169
- additionalValue: { type: "string", default: "additional" }
1170
- }
1171
- }
1172
- }
1173
- });
1174
- const res = node.getData(undefined, {
1175
- addOptionalProps: true
1176
- });
1177
- assert.deepEqual(res, { test: "tested value" });
1178
- });
1179
- });
1180
- });
1181
- });
1182
-
1183
- describe("$ref", () => {
1184
- it("should return default value of resolved ref", () => {
1185
- const data = compileSchema({
1186
- $ref: "#/$defs/once",
1187
- $defs: { once: { default: "once" } }
1188
- }).getData();
1189
- assert.deepEqual(data, "once");
1190
- });
1191
-
1192
- it("should follow all refs", () => {
1193
- const data = compileSchema({
1194
- $ref: "#/$defs/once",
1195
- $defs: { once: { $ref: "#/$defs/twice" }, twice: { default: "twice" } }
1196
- }).getData();
1197
- assert.deepEqual(data, "twice");
1198
- });
1199
-
1200
- it("should resolve $ref in object schema", () => {
1201
- const data = compileSchema({
1202
- type: "object",
1203
- required: ["first"],
1204
- properties: { first: { $ref: "#/definitions/first" } },
1205
- definitions: { first: { type: "string", default: "john" } }
1206
- }).getData();
1207
- assert.deepEqual(data, { first: "john" });
1208
- });
1209
-
1210
- it("should create template for all followed refs (draft 2019-09)", () => {
1211
- const data = compileSchema({
1212
- $ref: "#/$defs/once",
1213
- $defs: {
1214
- once: { required: ["once"], properties: { once: { type: "number" } }, $ref: "#/$defs/twice" },
1215
- twice: { required: ["twice"], properties: { twice: { type: "boolean", default: true } } }
1216
- }
1217
- }).getData();
1218
- assert.deepEqual(data, { once: 0, twice: true });
1219
- });
1220
-
1221
- it("should resolve $ref in items-array", () => {
1222
- const data = compileSchema({
1223
- type: "array",
1224
- prefixItems: [{ $ref: "#/definitions/first" }],
1225
- definitions: {
1226
- first: {
1227
- type: "object",
1228
- required: ["first"],
1229
- properties: { first: { type: "string", default: "john" } }
1230
- }
1231
- }
1232
- }).getData([{}, {}]);
1233
- assert.deepEqual(data, [{ first: "john" }, {}]);
1234
- });
1235
-
1236
- it("should follow $ref once", () => {
1237
- const data = compileSchema({
1238
- type: "object",
1239
- required: ["value", "nodes"],
1240
- properties: {
1241
- value: { type: "string", default: "node" },
1242
- nodes: { type: "array", minItems: 1, items: { $ref: "#" } }
1243
- }
1244
- }).getData({}, { recursionLimit: 1 });
1245
- assert.deepEqual(data, { value: "node", nodes: [{ value: "node", nodes: [] }] });
1246
- });
1247
-
1248
- it("should resolve all reoccuring refs ", () => {
1249
- const data = compileSchema({
1250
- minItems: 3,
1251
- items: {
1252
- $ref: "#/$defs/item"
1253
- },
1254
- $defs: {
1255
- item: {
1256
- required: ["type"],
1257
- properties: {
1258
- type: {
1259
- const: "node"
1260
- // $ref: "#"
1261
- }
1262
- }
1263
- }
1264
- }
1265
- }).getData([], { recursionLimit: 1 });
1266
- assert.deepEqual(data, [{ type: "node" }, { type: "node" }, { type: "node" }]);
1267
- });
1268
-
1269
- // iteration depth is 1, input-depth is 2 => still add template to depth 2
1270
- it("should respect depth of input data in $ref-resolution", () => {
1271
- const data = compileSchema({
1272
- type: "object",
1273
- required: ["value", "nodes"],
1274
- properties: {
1275
- value: { type: "string", default: "node" },
1276
- nodes: { type: "array", minItems: 1, items: { $ref: "#" } }
1277
- }
1278
- }).getData(
1279
- { nodes: [{ value: "input-node" }, { nodes: [{ nodes: [] }] }] },
1280
- {
1281
- recursionLimit: 1
1282
- }
1283
- );
1284
-
1285
- assert.deepEqual(data, {
1286
- value: "node",
1287
- nodes: [
1288
- {
1289
- value: "input-node",
1290
- nodes: []
1291
- },
1292
- {
1293
- value: "node",
1294
- nodes: [
1295
- {
1296
- value: "node",
1297
- nodes: []
1298
- }
1299
- ]
1300
- }
1301
- ]
1302
- });
1303
- });
1304
-
1305
- it("should create template of draft04", () => {
1306
- const schema = require("../../remotes/draft04.json");
1307
- const node = compileSchema({ ...schema, $schema: "draft-06" });
1308
- const res = node.getData({}, { addOptionalProps: true });
1309
- // console.log("RESULT\n", JSON.stringify(res, null, 2));
1310
- assert.deepEqual(Object.prototype.toString.call(res), "[object Object]");
1311
- });
1312
-
1313
- it("should create template of draft07", () => {
1314
- const data = compileSchema(require("../../remotes/draft07.json")).getData({}, { addOptionalProps: true });
1315
- // console.log("RESULT\n", JSON.stringify(data, null, 2));
1316
- assert.deepEqual(Object.prototype.toString.call(data), "[object Object]");
1317
- });
1318
- });
1319
-
1320
- describe("if-then-else", () => {
1321
- it("should return template of then-schema for valid if-schema", () => {
1322
- const data = compileSchema({
1323
- type: "object",
1324
- required: ["test"],
1325
- properties: { test: { type: "string", default: "with value" } },
1326
- if: { properties: { test: { type: "string", minLength: 4 } } },
1327
- then: { required: ["dynamic"], properties: { dynamic: { type: "string", default: "from then" } } }
1328
- }).getData();
1329
- assert.deepEqual(data, {
1330
- test: "with value",
1331
- dynamic: "from then"
1332
- });
1333
- });
1334
-
1335
- it("should NOT create data for then-schema if it is not required", () => {
1336
- const data = compileSchema({
1337
- type: "object",
1338
- required: ["test"],
1339
- properties: { test: { type: "string", default: "with value" } },
1340
- if: { properties: { test: { type: "string", minLength: 4 } } },
1341
- then: { properties: { dynamic: { type: "string", default: "from then" } } }
1342
- }).getData(undefined, { addOptionalProps: false });
1343
- assert.deepEqual(data, { test: "with value" });
1344
- });
1345
-
1346
- it("should NOT return template of then-schema for invalid if-schema", () => {
1347
- const data = compileSchema({
1348
- type: "object",
1349
- required: ["test"],
1350
- properties: { test: { type: "string", default: "too short" } },
1351
- if: { properties: { test: { type: "string", minLength: 40 } } },
1352
- then: { properties: { dynamic: { type: "string", default: "from then" } } }
1353
- }).getData();
1354
- assert.deepEqual(data, { test: "too short" });
1355
- });
1356
-
1357
- it("should return template of else-schema for invalid if-schema", () => {
1358
- const data = compileSchema({
1359
- type: "object",
1360
- required: ["test"],
1361
- properties: { test: { type: "string", default: "with test" } },
1362
- if: { properties: { test: { type: "string", minLength: 40 } } },
1363
- then: { required: ["dynamic"], properties: { dynamic: { type: "string", default: "from then" } } },
1364
- else: { required: ["dynamic"], properties: { dynamic: { type: "string", default: "from else" } } }
1365
- }).getData();
1366
- assert.deepEqual(data, { test: "with test", dynamic: "from else" });
1367
- });
1368
-
1369
- it("should incrementally resolve multiple 'then'-schema", () => {
1370
- const data = compileSchema({
1371
- type: "object",
1372
- required: ["trigger"],
1373
- properties: { trigger: { type: "boolean" } },
1374
- allOf: [
1375
- {
1376
- if: { properties: { trigger: { const: true } } },
1377
- then: {
1378
- required: ["additionalSchema"],
1379
- properties: { additionalSchema: { type: "string", default: "additional" } }
1380
- }
1381
- },
1382
- {
1383
- if: { required: ["additionalSchema"], properties: { additionalSchema: { minLength: 5 } } },
1384
- then: {
1385
- required: ["anotherSchema"],
1386
- properties: { anotherSchema: { type: "string", default: "another" } }
1387
- }
1388
- }
1389
- ]
1390
- }).getData({ trigger: true });
1391
- assert.deepEqual(data, { trigger: true, additionalSchema: "additional", anotherSchema: "another" });
1392
- });
1393
- });
1394
-
1395
- describe("type-array", () => {
1396
- it("should return first type of list for template", () => {
1397
- const node = compileSchema({
1398
- type: ["string", "object"]
1399
- });
1400
- const res = node.getData();
1401
-
1402
- assert.deepEqual(res, "");
1403
- });
1404
-
1405
- it("should return input data", () => {
1406
- const node = compileSchema({
1407
- type: ["string", "object"]
1408
- });
1409
- const res = node.getData("title");
1410
-
1411
- assert.deepEqual(res, "title");
1412
- });
1413
-
1414
- it("should return type of default value if data is not given", () => {
1415
- const node = compileSchema({
1416
- type: ["string", "array", "object"],
1417
- default: []
1418
- });
1419
- const res = node.getData();
1420
-
1421
- assert.deepEqual(res, []);
1422
- });
1423
- });
1424
-
1425
- describe("templateOptions", () => {
1426
- it("should remove invalid oneOf schema if 'removeInvalidData=true'", () => {
1427
- const node = compileSchema({
1428
- type: "object",
1429
- oneOf: [
1430
- {
1431
- type: "object",
1432
- properties: {
1433
- value: { type: "string", default: "jane" }
1434
- }
1435
- },
1436
- {
1437
- type: "object",
1438
- properties: {
1439
- value: { type: "number" },
1440
- test: { type: "string", default: "test" }
1441
- }
1442
- }
1443
- ]
1444
- });
1445
- const res = node.getData(
1446
- { value: ["remove-me"] },
1447
- {
1448
- removeInvalidData: true
1449
- }
1450
- );
1451
-
1452
- assert.deepEqual(res, {});
1453
- });
1454
-
1455
- it("should not add optional properties", () => {
1456
- const schema = {
1457
- type: "object",
1458
- required: ["list", "author"],
1459
- properties: {
1460
- title: { type: "string", default: "title" },
1461
- list: {
1462
- type: "array",
1463
- items: {
1464
- allOf: [
1465
- { type: "object" },
1466
- {
1467
- properties: {
1468
- index: { type: "number", default: 4 }
1469
- }
1470
- }
1471
- ]
1472
- }
1473
- },
1474
- author: {
1475
- anyOf: [
1476
- { type: "string", default: "jane" },
1477
- { type: "string", default: "john" }
1478
- ]
1479
- },
1480
- source: {
1481
- type: "string",
1482
- enum: ["dpa", "getty"]
1483
- }
1484
- }
1485
- };
1486
- const node = compileSchema(schema);
1487
-
1488
- const template = node.getData(
1489
- {},
1490
- {
1491
- addOptionalProps: false
1492
- }
1493
- );
1494
-
1495
- assert.deepEqual({ list: [], author: "jane" }, template);
1496
- });
1497
-
1498
- describe("extendDefaults", () => {
1499
- it("should keep array default-value with 'extendDefaults:false'", () => {
1500
- const node = compileSchema({
1501
- type: "array",
1502
- default: [],
1503
- items: {
1504
- type: "string",
1505
- enum: ["one", "two"]
1506
- },
1507
- minItems: 1 // usually adds an enty, but default states: []
1508
- });
1509
- const res = node.getData(undefined, {
1510
- extendDefaults: false
1511
- });
1512
-
1513
- assert.deepEqual(res, []);
1514
- });
1515
-
1516
- it("should add items to array with no default-value given and 'extendDefaults:false'", () => {
1517
- const node = compileSchema({
1518
- type: "array",
1519
- items: {
1520
- type: "string",
1521
- enum: ["one", "two"]
1522
- },
1523
- minItems: 1 // usually adds an enty, but default states: []
1524
- });
1525
- const res = node.getData(undefined, {
1526
- extendDefaults: false
1527
- });
1528
-
1529
- assert.deepEqual(res, ["one"]);
1530
- });
1531
-
1532
- it("should add items to default-array with 'extendDefaults:true'", () => {
1533
- const node = compileSchema({
1534
- type: "array",
1535
- default: [],
1536
- items: {
1537
- type: "string",
1538
- enum: ["one", "two"]
1539
- },
1540
- minItems: 1 // usually adds an enty, but default states: []
1541
- });
1542
- const res = node.getData(undefined, {
1543
- extendDefaults: true
1544
- });
1545
-
1546
- assert.deepEqual(res, ["one"]);
1547
- });
1548
-
1549
- it("should not add required items to object with default-value given and 'extendDefaults:false'", () => {
1550
- const node = compileSchema({
1551
- type: "object",
1552
- required: ["title"],
1553
- default: {},
1554
- properties: {
1555
- title: { type: "string" }
1556
- }
1557
- });
1558
- const res = node.getData(undefined, {
1559
- extendDefaults: false
1560
- });
1561
-
1562
- assert.deepEqual(res, {});
1563
- });
1564
-
1565
- it("should extend object by required property with no default-value given and 'extendDefaults:false'", () => {
1566
- const node = compileSchema({
1567
- type: "object",
1568
- required: ["title"],
1569
- properties: {
1570
- title: { type: "string" }
1571
- }
1572
- });
1573
- const res = node.getData(undefined, {
1574
- extendDefaults: false
1575
- });
1576
-
1577
- assert.deepEqual(res, { title: "" });
1578
- });
1579
- it("should extend default-object with 'extendDefaults:true'", () => {
1580
- const node = compileSchema({
1581
- type: "object",
1582
- required: ["title"],
1583
- default: {},
1584
- properties: {
1585
- title: { type: "string" }
1586
- }
1587
- });
1588
- const res = node.getData(undefined, {
1589
- extendDefaults: true
1590
- });
1591
-
1592
- assert.deepEqual(res, { title: "" });
1593
- });
1594
- });
1595
- });
1596
-
1597
- describe("defaultTemplateOptions.removeInvalidData", () => {
1598
- it("should NOT remove invalid data per default", () => {
1599
- const node = compileSchema({
1600
- type: "object",
1601
- properties: { valid: { type: "string" } },
1602
- additionalProperties: false
1603
- });
1604
- const res = node.getData({ valid: "stays", invalid: "not removed" });
1605
- assert.deepEqual(res, { valid: "stays", invalid: "not removed" });
1606
- });
1607
-
1608
- it("should remove invalid data with 'removeInvalidData=true'", () => {
1609
- const node = compileSchema({
1610
- type: "object",
1611
- properties: { valid: { type: "string" } },
1612
- additionalProperties: false
1613
- });
1614
- const res = node.getData({ valid: "stays", invalid: "removes" }, { removeInvalidData: true });
1615
- assert.deepEqual(res, { valid: "stays" });
1616
- });
1617
-
1618
- it("should NOT remove valid but unspecified data when 'removeInvalidData=true'", () => {
1619
- const node = compileSchema({
1620
- type: "object",
1621
- properties: { valid: { type: "string" } }
1622
- });
1623
- const res = node.getData({ valid: "stays", unspecified: "stays" }, { removeInvalidData: true });
1624
- assert.deepEqual(res, { valid: "stays", unspecified: "stays" });
1625
- });
1626
-
1627
- it("should remove invalid data with 'removeInvalidData=true' when set as defaultTemplateOptions", () => {
1628
- const node = compileSchema(
1629
- {
1630
- type: "object",
1631
- properties: { valid: { type: "string" } },
1632
- additionalProperties: false
1633
- },
1634
- {
1635
- getDataDefaultOptions: { removeInvalidData: true }
1636
- }
1637
- );
1638
- const res = node.getData({ valid: "stays", invalid: "removes" });
1639
- assert.deepEqual(res, { valid: "stays" });
1640
- });
1641
-
1642
- it("should NOT remove invalid data when set per default but overwritten on function", () => {
1643
- const node = compileSchema(
1644
- {
1645
- type: "object",
1646
- properties: { valid: { type: "string" } },
1647
- additionalProperties: false
1648
- },
1649
- {
1650
- getDataDefaultOptions: { removeInvalidData: true }
1651
- }
1652
- );
1653
- const res = node.getData({ valid: "stays", invalid: "not removed" }, { removeInvalidData: false });
1654
- assert.deepEqual(res, { valid: "stays", invalid: "not removed" });
1655
- });
1656
- });
1657
- describe("defaultTemplateOptions.useTypeDefaults", () => {
1658
- it("should return initial value for missing default-properties", () => {
1659
- const data = compileSchema({
1660
- required: ["valid"],
1661
- properties: { valid: { type: "string" } }
1662
- }).getData(null, { useTypeDefaults: true });
1663
-
1664
- assert.deepEqual(data, { valid: "" });
1665
- });
1666
-
1667
- it("should omit initial value for missing default-properties", () => {
1668
- const data = compileSchema({
1669
- required: ["valid"],
1670
- properties: { valid: { type: "string" } }
1671
- }).getData(null, { useTypeDefaults: false });
1672
-
1673
- assert.deepEqual(data, {});
1674
- });
1675
-
1676
- // @todo: reevaluate this behaviour
1677
- it("should return initial object-value for missing default-properties, even if useTypeDefaults: false", () => {
1678
- const data = compileSchema({
1679
- required: ["valid"],
1680
- properties: { valid: { type: "string" } }
1681
- }).getData(null, { useTypeDefaults: false });
1682
-
1683
- assert.deepEqual(data, {});
1684
- });
1685
-
1686
- // @todo: reevaluate this behaviour
1687
- it("should return initial array-value for missing default-properties", () => {
1688
- const data = compileSchema({
1689
- required: ["valid"],
1690
- properties: { valid: { type: "array", items: { type: "string" }, minItems: 1 } }
1691
- }).getData(null, { useTypeDefaults: false });
1692
-
1693
- assert.deepEqual(data, { valid: [undefined] });
1694
- });
1695
-
1696
- it("should omit properties without default values when 'useTypeDefaults:false' even if required", () => {
1697
- const node = compileSchema({
1698
- type: "object",
1699
- required: ["name", "age", "country"],
1700
- properties: {
1701
- name: { type: "string", default: "John Doe" },
1702
- age: { type: "number" },
1703
- country: { type: "string", default: "USA" }
1704
- }
1705
- });
1706
- const res = node.getData(undefined, {
1707
- extendDefaults: false,
1708
- useTypeDefaults: false
1709
- });
1710
-
1711
- assert.deepEqual(res, { name: "John Doe", country: "USA" });
1712
- });
1713
-
1714
- it("should omit properties without default values when 'useTypeDefaults:false' even if required in nested", () => {
1715
- const node = compileSchema({
1716
- type: "object",
1717
- properties: {
1718
- user: {
1719
- type: "object",
1720
- required: ["id", "username"],
1721
- properties: {
1722
- id: { type: "string" },
1723
- username: { type: "string", default: "guest" },
1724
- profile: {
1725
- type: "object",
1726
- properties: {
1727
- bio: { type: "string" },
1728
- theme: { type: "string", default: "light" }
1729
- }
1730
- }
1731
- }
1732
- },
1733
- active: { type: "boolean", default: true }
1734
- }
1735
- });
1736
- const res = node.getData({}, { addOptionalProps: true, useTypeDefaults: false });
1737
-
1738
- assert.deepEqual(
1739
- JSON.stringify(res),
1740
- JSON.stringify({
1741
- user: {
1742
- username: "guest",
1743
- profile: {
1744
- theme: "light"
1745
- }
1746
- },
1747
- active: true
1748
- })
1749
- );
1750
- });
1751
-
1752
- it("should handle type string with default value and 'useTypeDefaults:false'", () => {
1753
- const node = compileSchema({
1754
- type: "string",
1755
- default: "default value"
1756
- });
1757
- const res = node.getData(undefined, {
1758
- useTypeDefaults: false
1759
- });
1760
- assert.deepEqual(res, "default value");
1761
- });
1762
-
1763
- it("should handle type string without default value and 'useTypeDefaults:false'", () => {
1764
- const node = compileSchema({
1765
- type: "string"
1766
- });
1767
- const res = node.getData(undefined, { useTypeDefaults: false });
1768
- assert.deepEqual(res, undefined);
1769
- });
1770
-
1771
- it("should handle array without default value and 'useTypeDefaults:false'", () => {
1772
- const node = compileSchema({
1773
- type: "object",
1774
- required: ["title"],
1775
- properties: {
1776
- title: {
1777
- type: "array",
1778
- items: { type: "string" }
1779
- }
1780
- }
1781
- });
1782
- const res = node.getData(undefined, { useTypeDefaults: false });
1783
- assert.deepEqual(res, { title: [] });
1784
- });
1785
- });
5
+ it("should not modify input schema", () => {
6
+ const schema = {
7
+ type: "object",
8
+ properties: {
9
+ title: { type: "string", default: "title" },
10
+ list: {
11
+ type: "array",
12
+ items: { allOf: [{ type: "object" }, { properties: { index: { type: "number", default: 4 } } }] }
13
+ },
14
+ author: {
15
+ anyOf: [
16
+ { type: "string", default: "jane" },
17
+ { type: "string", default: "john" }
18
+ ]
19
+ },
20
+ source: { type: "string", enum: ["dpa", "getty"] }
21
+ }
22
+ };
23
+ const originalSchema = JSON.stringify(schema);
24
+ const node = compileSchema(schema);
25
+ node.getData({});
26
+ assert.deepEqual(JSON.stringify(schema), originalSchema);
27
+ });
28
+
29
+ describe("values", () => {
30
+ it("should return default value missing input and type", () => {
31
+ const data = compileSchema({ default: 123 }).getData();
32
+ assert.deepEqual(data, 123);
33
+ });
34
+
35
+ it("should NOT override input value for missing type", () => {
36
+ const data = compileSchema({ default: 123 }).getData("input");
37
+ assert.deepEqual(data, "input");
38
+ });
39
+
40
+ // @attention, changing input data
41
+ it("should alwayys return const value", () => {
42
+ const data = compileSchema({ const: "const", default: 123 }).getData(123);
43
+ assert.deepEqual(data, "const");
44
+ });
45
+
46
+ it("should prefer const over default", () => {
47
+ const data = compileSchema({
48
+ type: "string",
49
+ const: "static",
50
+ default: "should be overwritten"
51
+ }).getData();
52
+ assert.deepEqual(data, "static");
53
+ });
54
+
55
+ describe("string", () => {
56
+ it("should return empty string for missing default value", () => {
57
+ const data = compileSchema({ type: "string" }).getData();
58
+ assert.deepEqual(data, "");
59
+ });
60
+
61
+ it("should return default value", () => {
62
+ const data = compileSchema({
63
+ type: "string",
64
+ default: "default"
65
+ }).getData();
66
+ assert.deepEqual(data, "default");
67
+ });
68
+
69
+ it("should return string data", () => {
70
+ const data = compileSchema({
71
+ type: "string",
72
+ default: "default"
73
+ }).getData("input");
74
+ assert.deepEqual(data, "input");
75
+ });
76
+ });
77
+
78
+ describe("number", () => {
79
+ it("should return 0 for missing default value", () => {
80
+ const data = compileSchema({ type: "number" }).getData();
81
+ assert.deepEqual(data, 0);
82
+ });
83
+
84
+ it("should return default value", () => {
85
+ const data = compileSchema({ type: "number", default: 99 }).getData();
86
+ assert.deepEqual(data, 99);
87
+ });
88
+
89
+ it("should return number data", () => {
90
+ const data = compileSchema({ type: "number", default: 99 }).getData(123);
91
+ assert.deepEqual(data, 123);
92
+ });
93
+ });
94
+
95
+ describe("integer", () => {});
96
+
97
+ describe("boolean", () => {
98
+ it("should return `false` for missing default value", () => {
99
+ const data = compileSchema({ type: "boolean", default: false }).getData();
100
+ assert.deepEqual(data, false);
101
+ });
102
+
103
+ it("should return default value of boolean", () => {
104
+ const data = compileSchema({ type: "boolean", default: false }).getData();
105
+ assert.deepEqual(data, false);
106
+ });
107
+
108
+ it("should not override given boolean if it is `false`", () => {
109
+ const data = compileSchema({ type: "boolean", default: true }).getData(false);
110
+ assert.deepEqual(data, false);
111
+ });
112
+
113
+ it("should not override given boolean if it is `true`", () => {
114
+ const data = compileSchema({ type: "boolean", default: false }).getData(true);
115
+ assert.deepEqual(data, true);
116
+ });
117
+ });
118
+
119
+ describe("null", () => {
120
+ it("should return `null` for missing default value", () => {
121
+ const data = compileSchema({ type: "null" }).getData();
122
+ assert.deepEqual(data, null);
123
+ });
124
+
125
+ it("should return `null` when first type in type-array", () => {
126
+ const node = compileSchema({ type: ["null", "string"] });
127
+ const res = node.getData();
128
+
129
+ assert.deepEqual(res, null);
130
+ });
131
+
132
+ it("should return default value of null", () => {
133
+ const data = compileSchema({ type: "null", default: null }).getData();
134
+ assert.deepEqual(data, null);
135
+ });
136
+
137
+ it("should return default value of null even for wrong typye", () => {
138
+ const data = compileSchema({ type: "number", default: null }).getData();
139
+ assert.deepEqual(data, null);
140
+ });
141
+
142
+ it("should support `null` type properties", () => {
143
+ const data = compileSchema({
144
+ type: "object",
145
+ required: ["nullType"],
146
+ properties: { nullType: { type: "null" } }
147
+ }).getData();
148
+ assert.deepEqual(data, { nullType: null });
149
+ });
150
+
151
+ it("should return `null` input for strings", () => {
152
+ const data = compileSchema({ type: "string" }).getData(null);
153
+ assert.deepEqual(data, null);
154
+ });
155
+
156
+ it("should return `null` input for value-property", () => {
157
+ const data = compileSchema({
158
+ type: "object",
159
+ required: ["title"],
160
+ properties: { title: { type: "number" } }
161
+ }).getData({ title: null });
162
+ assert.deepEqual(data, { title: null });
163
+ });
164
+ });
165
+
166
+ describe("enum", () => {
167
+ it("should set the first enum option for a missing default", () => {
168
+ const data = compileSchema({ enum: ["first", "second"] }).getData();
169
+ assert.deepEqual(data, "first");
170
+ });
171
+
172
+ it("should use default value in any case", () => {
173
+ const data = compileSchema({ enum: ["first", "second"], default: "" }).getData();
174
+ assert.deepEqual(data, "");
175
+ });
176
+ });
177
+
178
+ describe("file", () => {
179
+ it("should not modify file-instance", () => {
180
+ const file = new File([], "testfile.pdf");
181
+ const data = compileSchema({
182
+ type: ["string", "object"],
183
+ format: "file"
184
+ }).getData(file);
185
+ assert.deepEqual(data, file);
186
+ });
187
+
188
+ it("should not modify file-instance on object", () => {
189
+ const file = new File([], "testfile.pdf");
190
+ const data = compileSchema({
191
+ type: "object",
192
+ properties: { file: { type: ["string", "object"], format: "file" } }
193
+ }).getData({ file });
194
+ assert.deepEqual(data, { file });
195
+ });
196
+ });
197
+
198
+ describe("oneOf", () => {
199
+ it("should return first schema for mixed types", () => {
200
+ const node = compileSchema({
201
+ oneOf: [{ type: "string", default: "jane" }, { type: "number" }]
202
+ });
203
+ const res = node.getData();
204
+
205
+ assert.deepEqual(res, "jane");
206
+ });
207
+ });
208
+ });
209
+
210
+ describe("object", () => {
211
+ describe("behaviour", () => {
212
+ it("should return {} for a missing default value", () => {
213
+ const data = compileSchema({ type: "object" }).getData();
214
+ assert.deepEqual(data, {});
215
+ });
216
+
217
+ it("should return default value of object", () => {
218
+ const data = compileSchema({
219
+ type: "object",
220
+ default: { init: true }
221
+ }).getData();
222
+ assert.deepEqual(data, { init: true });
223
+ });
224
+
225
+ it("should return input data", () => {
226
+ const data = compileSchema({ type: "object" }).getData({ init: false });
227
+ assert.deepEqual(data, { init: false });
228
+ });
229
+
230
+ it("should override default by input data", () => {
231
+ const data = compileSchema({
232
+ type: "object",
233
+ default: { init: true }
234
+ }).getData({ init: false });
235
+ assert.deepEqual(data, { init: false });
236
+ });
237
+ });
238
+
239
+ describe("properties", () => {
240
+ it("should return default object", () => {
241
+ const data = compileSchema({
242
+ type: "object",
243
+ properties: { first: { type: "string" }, second: { type: "number" } },
244
+ default: { first: "john", second: 4 }
245
+ }).getData();
246
+ assert.deepEqual(data, { first: "john", second: 4 });
247
+ });
248
+
249
+ it("should return only required object properties", () => {
250
+ const data = compileSchema({
251
+ type: "object",
252
+ required: ["first"],
253
+ properties: { first: { type: "string" }, second: { type: "number" } }
254
+ }).getData();
255
+ assert.deepEqual(data, { first: "" });
256
+ });
257
+
258
+ it("should not fail on falsy input data", () => {
259
+ const data = compileSchema({
260
+ type: "object",
261
+ properties: {
262
+ first: { type: "boolean", default: true },
263
+ second: { type: "boolean", default: false }
264
+ }
265
+ }).getData({ first: false, second: true });
266
+ assert.deepEqual(data, { first: false, second: true });
267
+ });
268
+
269
+ it("should return all object properties with `addOptionalProps=true`", () => {
270
+ const data = compileSchema({
271
+ type: "object",
272
+ required: ["first", "second"],
273
+ properties: { first: { type: "string" }, second: { type: "number" } }
274
+ }).getData({}, { addOptionalProps: true });
275
+ assert.deepEqual(data, { first: "", second: 0 });
276
+ });
277
+
278
+ it("should NOT override given default values by other default values", () => {
279
+ const data = compileSchema({
280
+ type: "object",
281
+ properties: { first: { type: "string", default: "jane" }, second: { type: "number" } },
282
+ default: { first: "john", second: 4 }
283
+ }).getData();
284
+ assert.deepEqual(data, { first: "john", second: 4 });
285
+ });
286
+
287
+ it("should extend given template data by property default values", () => {
288
+ const data = compileSchema({
289
+ type: "object",
290
+ properties: { first: { type: "string", default: "jane" }, second: { type: "number" } },
291
+ default: { first: "john", second: 4 }
292
+ }).getData({ second: 8 });
293
+ assert.deepEqual(data, { first: "john", second: 8 });
294
+ });
295
+ });
296
+
297
+ describe("additionalProperties & option: removeInvalidData", () => {
298
+ it("should NOT remove additional properties `additionalProperties=undefined`", () => {
299
+ const data = compileSchema({
300
+ type: "object",
301
+ required: ["first", "second"],
302
+ properties: { first: { type: "string" } }
303
+ }).getData({ first: "first", second: 42 });
304
+ assert.deepEqual(data, { first: "first", second: 42 });
305
+ });
306
+
307
+ it("should NOT remove additional properties `additionalProperties=true`", () => {
308
+ const data = compileSchema({
309
+ type: "object",
310
+ required: ["first", "second"],
311
+ properties: { first: { type: "string" } },
312
+ additionalProperties: true
313
+ }).getData({ first: "first", second: 42 });
314
+ assert.deepEqual(data, { first: "first", second: 42 });
315
+ });
316
+
317
+ it("should NOT remove non matching properties with `additionalProperties={schema}`", () => {
318
+ const data = compileSchema({
319
+ type: "object",
320
+ required: ["first", "second"],
321
+ properties: { first: { type: "string" } },
322
+ additionalProperties: { type: "string" }
323
+ }).getData({ first: "first", second: 42 });
324
+ assert.deepEqual(data, { first: "first", second: 42 });
325
+ });
326
+
327
+ it("should NOT remove additional properties with `additionalProperties=false`", () => {
328
+ const data = compileSchema({
329
+ type: "object",
330
+ required: ["first", "second"],
331
+ properties: { first: { type: "string" } },
332
+ additionalProperties: false
333
+ }).getData({ first: "first", second: 42 });
334
+ assert.deepEqual(data, { first: "first", second: 42 });
335
+ });
336
+
337
+ it("should remove unmatched properties with option `removeInvalidData=true`", () => {
338
+ const data = compileSchema({
339
+ type: "object",
340
+ required: ["first", "second"],
341
+ properties: { first: { type: "string" } },
342
+ additionalProperties: false
343
+ }).getData({ first: "first", second: 42, thrid: "third" }, { removeInvalidData: true });
344
+ assert.deepEqual(data, { first: "first" });
345
+ });
346
+
347
+ it("should remove invalid properties with option `removeInvalidData=true`", () => {
348
+ const data = compileSchema({
349
+ type: "object",
350
+ required: ["first", "second"],
351
+ properties: { first: { type: "string" } },
352
+ additionalProperties: { type: "number" }
353
+ }).getData({ first: "first", second: 42, third: "third", fourth: false }, { removeInvalidData: true });
354
+ assert.deepEqual(data, { first: "first", second: 42 });
355
+ });
356
+ });
357
+
358
+ // patternNames
359
+ // patternProperties
360
+ // dependentSchemas
361
+ // dependentRequired
362
+ // (unevaluatedPoperties)
363
+
364
+ describe("allOf", () => {
365
+ it("should create template for merged allOf schema", () => {
366
+ const data = compileSchema({
367
+ type: "object",
368
+ allOf: [
369
+ {
370
+ required: ["name"],
371
+ properties: { name: { type: "string", default: "jane" } }
372
+ },
373
+ {
374
+ required: ["stage"],
375
+ properties: { stage: { type: "string", default: "test" } }
376
+ }
377
+ ]
378
+ }).getData({ name: "john" });
379
+ assert.deepEqual(data, { name: "john", stage: "test" });
380
+ });
381
+ });
382
+
383
+ describe("anyOf", () => {
384
+ it("should create template for first anyOf schema", () => {
385
+ const node = compileSchema({
386
+ type: "object",
387
+ anyOf: [
388
+ {
389
+ required: ["name", "stage"],
390
+ properties: {
391
+ name: { type: "string", default: "jane" },
392
+ stage: { type: "string", default: "develop" }
393
+ }
394
+ },
395
+ {
396
+ required: ["stage"],
397
+ properties: {
398
+ stage: { type: "number", default: 0 }
399
+ }
400
+ }
401
+ ]
402
+ });
403
+ const res = node.getData({ name: "john" });
404
+
405
+ assert.deepEqual(res, { name: "john", stage: "develop" });
406
+ });
407
+ });
408
+
409
+ describe("oneOf", () => {
410
+ it("should return template of first oneOf schema", () => {
411
+ const node = compileSchema({
412
+ type: "object",
413
+ oneOf: [
414
+ {
415
+ type: "object",
416
+ required: ["title"],
417
+ properties: {
418
+ title: { type: "string", default: "jane" }
419
+ }
420
+ },
421
+ {
422
+ type: "object",
423
+ required: ["value"],
424
+ properties: { value: { type: "number" } }
425
+ }
426
+ ]
427
+ });
428
+ const res = node.getData();
429
+
430
+ assert.deepEqual(res, { title: "jane" });
431
+ });
432
+
433
+ it("should extend empty object with first oneOf schema", () => {
434
+ const node = compileSchema({
435
+ type: "object",
436
+ oneOf: [
437
+ {
438
+ type: "object",
439
+ required: ["title"],
440
+ properties: {
441
+ title: { type: "string", default: "jane" }
442
+ }
443
+ },
444
+ {
445
+ type: "object",
446
+ required: ["value"],
447
+ properties: { value: { type: "number" } }
448
+ }
449
+ ]
450
+ });
451
+ const res = node.getData({});
452
+
453
+ assert.deepEqual(res, { title: "jane" });
454
+ });
455
+
456
+ it("should return template of matching oneOf schema", () => {
457
+ const node = compileSchema({
458
+ type: "object",
459
+ oneOf: [
460
+ {
461
+ type: "object",
462
+ required: ["value"],
463
+ properties: {
464
+ value: { type: "string", default: "jane" }
465
+ }
466
+ },
467
+ {
468
+ type: "object",
469
+ required: ["value", "test"],
470
+ properties: {
471
+ value: { type: "number" },
472
+ test: { type: "string", default: "test" }
473
+ }
474
+ }
475
+ ]
476
+ });
477
+ const res = node.getData({ value: 111 });
478
+
479
+ assert.deepEqual(res, { value: 111, test: "test" });
480
+ });
481
+
482
+ it("should return input value if no oneOf-schema matches ", () => {
483
+ const node = compileSchema({
484
+ type: "object",
485
+ oneOf: [
486
+ {
487
+ type: "object",
488
+ properties: {
489
+ value: { type: "string", default: "jane" }
490
+ }
491
+ },
492
+ {
493
+ type: "object",
494
+ properties: {
495
+ value: { type: "number" },
496
+ test: { type: "string", default: "test" }
497
+ }
498
+ }
499
+ ]
500
+ });
501
+ const res = node.getData({ value: ["keep-me"] });
502
+
503
+ assert.deepEqual(res, { value: ["keep-me"] });
504
+ });
505
+
506
+ it("should not require object type definition in oneOf schemas", () => {
507
+ const node = compileSchema({
508
+ type: "object",
509
+ oneOf: [
510
+ {
511
+ required: ["type"],
512
+ properties: {
513
+ type: { const: "header" }
514
+ }
515
+ },
516
+ {
517
+ required: ["type"],
518
+ properties: {
519
+ type: { const: "paragraph" }
520
+ }
521
+ }
522
+ ]
523
+ });
524
+
525
+ const res = node.getData({ type: "paragraph" });
526
+ assert.deepEqual(res, { type: "paragraph" });
527
+ });
528
+
529
+ it("should return valid default data", () => {
530
+ const node = compileSchema({
531
+ type: "object",
532
+ default: { value: 123 },
533
+ oneOf: [
534
+ {
535
+ type: "object",
536
+ required: ["title"],
537
+ properties: { title: { type: "string", default: "jane" } }
538
+ },
539
+ { type: "object", required: ["value"], properties: { value: { type: "number" } } }
540
+ ]
541
+ });
542
+ const res = node.getData();
543
+
544
+ assert.deepEqual(res, { value: 123 });
545
+ });
546
+
547
+ it("should return invalid default data", () => {
548
+ const node = compileSchema({
549
+ type: "object",
550
+ default: { value: "wrong type" },
551
+ oneOf: [
552
+ {
553
+ type: "object",
554
+ required: ["title"],
555
+ properties: { title: { type: "string", default: "jane" } }
556
+ },
557
+ { type: "object", required: ["value"], properties: { value: { type: "number" } } }
558
+ ]
559
+ });
560
+ const res = node.getData();
561
+
562
+ assert.deepEqual(res, { value: "wrong type" });
563
+ });
564
+
565
+ it("should add correct optional properties from schema matching default data", () => {
566
+ const node = compileSchema({
567
+ type: "object",
568
+ default: { value: 123 },
569
+ oneOf: [
570
+ {
571
+ type: "object",
572
+ required: ["title"],
573
+ properties: { title: { type: "string", default: "jane" } }
574
+ },
575
+ {
576
+ type: "object",
577
+ required: ["value"],
578
+ properties: { value: { type: "number" }, optional: { type: "string" } }
579
+ }
580
+ ]
581
+ });
582
+ const res = node.getData(undefined, { addOptionalProps: true });
583
+
584
+ assert.deepEqual(res, { value: 123, optional: "" });
585
+ });
586
+ });
587
+ });
588
+
589
+ describe("array", () => {
590
+ describe("behaviour", () => {
591
+ it("should return [] for a missing default value", () => {
592
+ const data = compileSchema({ type: "array" }).getData();
593
+ assert.deepEqual(data, []);
594
+ });
595
+
596
+ it("should return default value of object", () => {
597
+ const data = compileSchema({ type: "array", default: [true] }).getData();
598
+ assert.deepEqual(data, [true]);
599
+ });
600
+
601
+ it("should return input data", () => {
602
+ const data = compileSchema({ type: "array" }).getData(["input"]);
603
+ assert.deepEqual(data, ["input"]);
604
+ });
605
+
606
+ it("should override default by input data", () => {
607
+ const data = compileSchema({
608
+ type: "array",
609
+ default: ["default"]
610
+ }).getData(["input"]);
611
+ assert.deepEqual(data, ["input"]);
612
+ });
613
+ });
614
+
615
+ describe("items: {}", () => {
616
+ it("should return empty array if minItems is undefined", () => {
617
+ const data = compileSchema({ items: { type: "boolean" } }).getData();
618
+ assert.deepEqual(data, []);
619
+ });
620
+
621
+ it("should return array with length of minItems", () => {
622
+ const data = compileSchema({
623
+ minItems: 3,
624
+ items: { type: "boolean" }
625
+ }).getData();
626
+ assert(Array.isArray(data));
627
+ assert.deepEqual(data.length, 3);
628
+ assert.deepEqual(data, [false, false, false]);
629
+ });
630
+
631
+ it("should return default array even if minItems is not set", () => {
632
+ const data = compileSchema({
633
+ default: ["a", "b"],
634
+ items: { type: "string" }
635
+ }).getData();
636
+ assert.deepEqual(data, ["a", "b"]);
637
+ });
638
+
639
+ it("should return default array if part of object", () => {
640
+ const data = compileSchema({
641
+ required: ["list"],
642
+ properties: { list: { type: "array", default: ["a", "b"], items: { type: "string" } } }
643
+ }).getData();
644
+ assert.deepEqual(data, { list: ["a", "b"] });
645
+ });
646
+
647
+ it("should not override given default values", () => {
648
+ const data = compileSchema({
649
+ minItems: 2,
650
+ default: ["abba", "doors"],
651
+ items: { type: "string", default: "elvis" }
652
+ }).getData();
653
+ assert.deepEqual(data, ["abba", "doors"]);
654
+ });
655
+
656
+ it("should extend given template data by default values", () => {
657
+ const data = compileSchema({
658
+ minItems: 2,
659
+ default: ["abba", "doors"],
660
+ items: { type: "string" }
661
+ }).getData(["elvis"]);
662
+ assert.deepEqual(data, ["elvis", "doors"]);
663
+ });
664
+
665
+ it("should extend all input objects by missing properties", () => {
666
+ const data = compileSchema({
667
+ default: ["abba", "doors"],
668
+ items: {
669
+ type: "object",
670
+ required: ["first", "second"],
671
+ properties: {
672
+ first: { type: "string", default: "first" },
673
+ second: { type: "string", default: "second" }
674
+ }
675
+ }
676
+ }).getData([{ first: "user input" }, {}]);
677
+ assert.deepEqual(data, [
678
+ { first: "user input", second: "second" },
679
+ { first: "first", second: "second" }
680
+ ]);
681
+ });
682
+
683
+ it("should resolve $ref in items-object", () => {
684
+ const data = compileSchema({
685
+ minItems: 1,
686
+ items: { $ref: "/$defs/bool" },
687
+ $defs: {
688
+ bool: { type: "boolean", default: true }
689
+ }
690
+ }).getData();
691
+ assert(Array.isArray(data));
692
+ assert.deepEqual(data.length, 1);
693
+ assert.deepEqual(data, [true]);
694
+ });
695
+ });
696
+
697
+ describe("prefixItems: []", () => {
698
+ // - Tuple validation is useful when the array is a collection of items where each has a different schema
699
+ // and the ordinal index of each item is meaningful.
700
+ // - It’s ok to not provide all of the items:
701
+ // https://spacetelescope.github.io/understanding-json-schema/reference/array.html#tuple-validation
702
+ it("should return array with minItems in given order", () => {
703
+ const data = compileSchema({
704
+ type: "array",
705
+ minItems: 2,
706
+ prefixItems: [{ type: "string" }, { type: "boolean" }]
707
+ }).getData();
708
+ assert.deepEqual(data, ["", false]);
709
+ });
710
+
711
+ it("should not override input items when complementing minItems", () => {
712
+ const data = compileSchema({
713
+ type: "array",
714
+ minItems: 2,
715
+ prefixItems: [{ type: "boolean", default: false }, { type: "string" }]
716
+ }).getData([true]);
717
+ assert.deepEqual(data, [true, ""]);
718
+ });
719
+
720
+ it("should not override wrong input items", () => {
721
+ const data = compileSchema({
722
+ type: "array",
723
+ prefixItems: [
724
+ { type: "boolean", default: false },
725
+ { type: "string", default: "default" }
726
+ ]
727
+ }).getData([42, false]);
728
+ assert.deepEqual(data, [42, "false"]);
729
+ });
730
+
731
+ it("should return default array", () => {
732
+ const data = compileSchema({
733
+ type: "array",
734
+ minItems: 1,
735
+ default: [true],
736
+ items: {
737
+ type: "boolean"
738
+ }
739
+ }).getData();
740
+ assert.deepEqual(data, [true]);
741
+ });
742
+
743
+ it("should convert input data for strings", () => {
744
+ const node = compileSchema({
745
+ type: "array",
746
+ minItems: 1,
747
+ prefixItems: [{ type: "string" }]
748
+ });
749
+ const res = node.getData([43]);
750
+
751
+ assert.deepEqual(res, ["43"]);
752
+ });
753
+
754
+ it("should convert input data for numbers", () => {
755
+ const data = compileSchema({
756
+ type: "array",
757
+ minItems: 1,
758
+ prefixItems: [{ type: "number" }]
759
+ }).getData(["43"]);
760
+ assert.deepEqual(data, [43]);
761
+ });
762
+
763
+ it("should convert input data for strings", () => {
764
+ const data = compileSchema({
765
+ type: "array",
766
+ minItems: 1,
767
+ prefixItems: [{ type: "string" }]
768
+ }).getData([43]);
769
+ assert.deepEqual(data, ["43"]);
770
+ });
771
+
772
+ it("should NOT convert invalid number if we would lose data", () => {
773
+ const data = compileSchema({
774
+ type: "array",
775
+ minItems: 1,
776
+ prefixItems: [{ type: "number" }]
777
+ }).getData(["asd"]);
778
+ assert.deepEqual(data, ["asd"]);
779
+ });
780
+
781
+ it("should convert input data for booleans", () => {
782
+ const data = compileSchema({
783
+ type: "array",
784
+ minItems: 1,
785
+ prefixItems: [{ type: "boolean" }]
786
+ }).getData(["false"]);
787
+ assert.deepEqual(data, [false]);
788
+ });
789
+
790
+ it("should NOT convert invalid boolean if we would lose data", () => {
791
+ const data = compileSchema({
792
+ type: "array",
793
+ minItems: 1,
794
+ prefixItems: [{ type: "boolean" }]
795
+ }).getData(["43"]);
796
+ assert.deepEqual(data, ["43"]);
797
+ });
798
+
799
+ it("should add defaults from `items`", () => {
800
+ const data = compileSchema({
801
+ type: "array",
802
+ minItems: 2,
803
+ items: {
804
+ type: "number",
805
+ default: 2
806
+ }
807
+ }).getData([43]);
808
+ assert.deepEqual(data, [43, 2]);
809
+ });
810
+
811
+ it("should add defaults from `items` for items not in prefixItems", () => {
812
+ const data = compileSchema({
813
+ type: "array",
814
+ minItems: 2,
815
+ prefixItems: [{ type: "boolean" }],
816
+ items: { type: "number", default: 2 }
817
+ }).getData([43]);
818
+ assert.deepEqual(data, [43, 2]);
819
+ });
820
+
821
+ it("should add prefixItems with `addOptionalProps: true`", () => {
822
+ const data = compileSchema(
823
+ {
824
+ type: "array",
825
+ prefixItems: [{ type: "boolean", default: true }],
826
+ items: { type: "number", default: 2 }
827
+ },
828
+ {
829
+ getDataDefaultOptions: { addOptionalProps: true }
830
+ }
831
+ ).getData();
832
+ assert.deepEqual(data, [true]);
833
+ });
834
+
835
+ it("should resolve $ref in prefixItems", () => {
836
+ const node = compileSchema({
837
+ type: "array",
838
+ minItems: 2,
839
+ prefixItems: [{ $ref: "/$defs/bool" }, { $ref: "/$defs/string" }],
840
+ $defs: {
841
+ bool: { type: "boolean" },
842
+ string: { type: "string" }
843
+ }
844
+ });
845
+ const res = node.getData([]);
846
+
847
+ assert.deepEqual(res, [false, ""]);
848
+ });
849
+ });
850
+
851
+ describe("oneOf", () => {
852
+ it("should return template of first oneOf schema", () => {
853
+ const node = compileSchema({
854
+ type: "array",
855
+ minItems: 1,
856
+ items: {
857
+ oneOf: [
858
+ { type: "string", default: "target" },
859
+ { type: "number", default: 9 }
860
+ ]
861
+ }
862
+ });
863
+ const res = node.getData();
864
+
865
+ assert(Array.isArray(res));
866
+ assert.deepEqual(res.length, 1);
867
+ assert.deepEqual(res, ["target"]);
868
+ });
869
+
870
+ it("should merge with input data", () => {
871
+ const node = compileSchema({
872
+ type: "array",
873
+ minItems: 1,
874
+ items: {
875
+ oneOf: [
876
+ {
877
+ type: "object",
878
+ required: ["notitle"],
879
+ properties: {
880
+ notitle: {
881
+ type: "string",
882
+ default: "nottitle"
883
+ }
884
+ }
885
+ },
886
+ {
887
+ type: "object",
888
+ required: ["title", "subtitle"],
889
+ properties: {
890
+ title: {
891
+ type: "string",
892
+ default: "Standardtitel"
893
+ },
894
+ subtitle: {
895
+ type: "string",
896
+ default: "do not replace with"
897
+ }
898
+ }
899
+ },
900
+ { type: "number", default: 9 }
901
+ ]
902
+ }
903
+ });
904
+
905
+ const res = node.getData([{ subtitle: "Subtitel" }]);
906
+
907
+ assert(Array.isArray(res));
908
+ assert.deepEqual(res.length, 1);
909
+ assert.deepEqual(res, [{ title: "Standardtitel", subtitle: "Subtitel" }]);
910
+ });
911
+
912
+ it("should not remove invalid oneOf schema if 'removeInvalidData' is unset", () => {
913
+ const node = compileSchema({
914
+ type: "object",
915
+ properties: {
916
+ filter: {
917
+ $ref: "#/definitions/filter"
918
+ }
919
+ },
920
+ definitions: {
921
+ filter: {
922
+ type: "array",
923
+ items: {
924
+ oneOf: [
925
+ {
926
+ type: "object",
927
+ properties: {
928
+ op: {
929
+ const: "in"
930
+ },
931
+ property: { type: "string", minLength: 1 }
932
+ }
933
+ }
934
+ ]
935
+ }
936
+ }
937
+ }
938
+ });
939
+ const res = node.getData({ filter: [{ op: "möp" }] });
940
+ assert.deepEqual(res, { filter: [{ op: "möp" }] });
941
+ });
942
+ });
943
+
944
+ describe("allOf", () => {
945
+ it("should create template for merged allOf schema", () => {
946
+ const node = compileSchema({
947
+ type: "array",
948
+ minItems: 2,
949
+ items: {
950
+ type: "object",
951
+ allOf: [
952
+ {
953
+ required: ["title"],
954
+ properties: {
955
+ title: { type: "string", default: "title" }
956
+ }
957
+ },
958
+ {
959
+ required: ["caption"],
960
+ properties: {
961
+ caption: {
962
+ type: "string",
963
+ default: "caption"
964
+ }
965
+ }
966
+ }
967
+ ]
968
+ }
969
+ });
970
+
971
+ const res = node.getData([{ title: "given-title" }]);
972
+ assert.deepEqual(res, [
973
+ { title: "given-title", caption: "caption" },
974
+ { title: "title", caption: "caption" }
975
+ ]);
976
+ });
977
+ });
978
+
979
+ describe("anyOf", () => {
980
+ it("should create template for first anyOf schema", () => {
981
+ const node = compileSchema({
982
+ type: "array",
983
+ minItems: 2,
984
+ items: {
985
+ type: "object",
986
+ anyOf: [
987
+ {
988
+ required: ["title"],
989
+ properties: {
990
+ title: { type: "string", default: "title" }
991
+ }
992
+ },
993
+ {
994
+ required: ["properties"],
995
+ properties: {
996
+ caption: {
997
+ type: "string",
998
+ default: "caption"
999
+ }
1000
+ }
1001
+ }
1002
+ ]
1003
+ }
1004
+ });
1005
+
1006
+ const res = node.getData([{ title: "given-title" }]);
1007
+ assert.deepEqual(res, [{ title: "given-title" }, { title: "title" }]);
1008
+ });
1009
+ });
1010
+
1011
+ // draft07 (backwards compatible)
1012
+ describe("dependencies", () => {
1013
+ describe("option: `additionalProps: false`", () => {
1014
+ const TEMPLATE_OPTIONS = { addOptionalProps: false };
1015
+ describe("dependency required", () => {
1016
+ it("should not add dependency if it is not required", () => {
1017
+ const node = compileSchema({
1018
+ type: "object",
1019
+ properties: {
1020
+ trigger: { type: "string" },
1021
+ dependency: { type: "string", default: "default" }
1022
+ },
1023
+ dependencies: {
1024
+ trigger: ["dependency"]
1025
+ }
1026
+ });
1027
+
1028
+ const res = node.getData({}, TEMPLATE_OPTIONS);
1029
+ assert.deepEqual(res, {});
1030
+ });
1031
+
1032
+ it("should add dependency if triggered as required", () => {
1033
+ const node = compileSchema({
1034
+ type: "object",
1035
+ properties: {
1036
+ trigger: { type: "string" },
1037
+ dependency: { type: "string", default: "default" }
1038
+ },
1039
+ dependencies: {
1040
+ trigger: ["dependency"]
1041
+ }
1042
+ });
1043
+
1044
+ const res = node.getData({ trigger: "yes" }, TEMPLATE_OPTIONS);
1045
+ assert.deepEqual(res, { trigger: "yes", dependency: "default" });
1046
+ });
1047
+
1048
+ it("should add dependency if initially triggered as required", () => {
1049
+ const node = compileSchema({
1050
+ type: "object",
1051
+ required: ["trigger"],
1052
+ properties: {
1053
+ trigger: { type: "string" },
1054
+ dependency: { type: "string", default: "default" }
1055
+ },
1056
+ dependencies: {
1057
+ trigger: ["dependency"]
1058
+ }
1059
+ });
1060
+
1061
+ const res = node.getData({}, TEMPLATE_OPTIONS);
1062
+ assert.deepEqual(res, { trigger: "", dependency: "default" });
1063
+ });
1064
+ });
1065
+
1066
+ describe("dependency schema", () => {
1067
+ it("should not add dependency from schema if it is not required", () => {
1068
+ const node = compileSchema({
1069
+ type: "object",
1070
+ properties: {
1071
+ trigger: { type: "string" }
1072
+ },
1073
+ dependencies: {
1074
+ trigger: {
1075
+ properties: {
1076
+ dependency: { type: "string", default: "default" }
1077
+ }
1078
+ }
1079
+ }
1080
+ });
1081
+
1082
+ const res = node.getData({}, TEMPLATE_OPTIONS);
1083
+ assert.deepEqual(res, {});
1084
+ });
1085
+
1086
+ it("should add dependency from schema if triggered as required", () => {
1087
+ const node = compileSchema({
1088
+ type: "object",
1089
+ properties: {
1090
+ trigger: { type: "string" }
1091
+ },
1092
+ dependencies: {
1093
+ trigger: {
1094
+ required: ["dependency"],
1095
+ properties: {
1096
+ dependency: { type: "string", default: "default" }
1097
+ }
1098
+ }
1099
+ }
1100
+ });
1101
+
1102
+ const res = node.getData({ trigger: "yes" }, TEMPLATE_OPTIONS);
1103
+ assert.deepEqual(res, { trigger: "yes", dependency: "default" });
1104
+ });
1105
+ });
1106
+ });
1107
+
1108
+ describe("option: `additionalProps: true`", () => {
1109
+ it("should create template for valid dependency", () => {
1110
+ const node = compileSchema({
1111
+ type: "object",
1112
+ properties: {
1113
+ test: { type: "string", default: "tested value" }
1114
+ },
1115
+ dependencies: {
1116
+ test: {
1117
+ properties: {
1118
+ additionalValue: { type: "string", default: "additional" }
1119
+ }
1120
+ }
1121
+ }
1122
+ });
1123
+ const res = node.getData(undefined, {
1124
+ addOptionalProps: true
1125
+ });
1126
+ assert.deepEqual(res, {
1127
+ test: "tested value",
1128
+ additionalValue: "additional"
1129
+ });
1130
+ });
1131
+
1132
+ it("should not change passed value of dependency", () => {
1133
+ const node = compileSchema({
1134
+ type: "object",
1135
+ properties: {
1136
+ test: { type: "string", default: "tested value" }
1137
+ },
1138
+ dependencies: {
1139
+ test: {
1140
+ properties: {
1141
+ additionalValue: { type: "string", default: "additional" }
1142
+ }
1143
+ }
1144
+ }
1145
+ });
1146
+ const res = node.getData(
1147
+ { additionalValue: "input value" },
1148
+ {
1149
+ addOptionalProps: true
1150
+ }
1151
+ );
1152
+ assert.deepEqual(res, {
1153
+ test: "tested value",
1154
+ additionalValue: "input value"
1155
+ });
1156
+ });
1157
+
1158
+ it("should not create data for non matching dependency", () => {
1159
+ const node = compileSchema({
1160
+ type: "object",
1161
+ properties: {
1162
+ test: { type: "string", default: "tested value" }
1163
+ },
1164
+ dependencies: {
1165
+ unknown: {
1166
+ properties: {
1167
+ additionalValue: { type: "string", default: "additional" }
1168
+ }
1169
+ }
1170
+ }
1171
+ });
1172
+ const res = node.getData(undefined, {
1173
+ addOptionalProps: true
1174
+ });
1175
+ assert.deepEqual(res, { test: "tested value" });
1176
+ });
1177
+ });
1178
+ });
1179
+ });
1180
+
1181
+ describe("$ref", () => {
1182
+ it("should return default value of resolved ref", () => {
1183
+ const data = compileSchema({
1184
+ $ref: "#/$defs/once",
1185
+ $defs: { once: { default: "once" } }
1186
+ }).getData();
1187
+ assert.deepEqual(data, "once");
1188
+ });
1189
+
1190
+ it("should follow all refs", () => {
1191
+ const data = compileSchema({
1192
+ $ref: "#/$defs/once",
1193
+ $defs: { once: { $ref: "#/$defs/twice" }, twice: { default: "twice" } }
1194
+ }).getData();
1195
+ assert.deepEqual(data, "twice");
1196
+ });
1197
+
1198
+ it("should resolve $ref in object schema", () => {
1199
+ const data = compileSchema({
1200
+ type: "object",
1201
+ required: ["first"],
1202
+ properties: { first: { $ref: "#/definitions/first" } },
1203
+ definitions: { first: { type: "string", default: "john" } }
1204
+ }).getData();
1205
+ assert.deepEqual(data, { first: "john" });
1206
+ });
1207
+
1208
+ it("should create template for all followed refs (draft 2019-09)", () => {
1209
+ const data = compileSchema({
1210
+ $ref: "#/$defs/once",
1211
+ $defs: {
1212
+ once: { required: ["once"], properties: { once: { type: "number" } }, $ref: "#/$defs/twice" },
1213
+ twice: { required: ["twice"], properties: { twice: { type: "boolean", default: true } } }
1214
+ }
1215
+ }).getData();
1216
+ assert.deepEqual(data, { once: 0, twice: true });
1217
+ });
1218
+
1219
+ it("should resolve $ref in items-array", () => {
1220
+ const data = compileSchema({
1221
+ type: "array",
1222
+ prefixItems: [{ $ref: "#/definitions/first" }],
1223
+ definitions: {
1224
+ first: {
1225
+ type: "object",
1226
+ required: ["first"],
1227
+ properties: { first: { type: "string", default: "john" } }
1228
+ }
1229
+ }
1230
+ }).getData([{}, {}]);
1231
+ assert.deepEqual(data, [{ first: "john" }, {}]);
1232
+ });
1233
+
1234
+ it("should follow $ref once", () => {
1235
+ const data = compileSchema({
1236
+ type: "object",
1237
+ required: ["value", "nodes"],
1238
+ properties: {
1239
+ value: { type: "string", default: "node" },
1240
+ nodes: { type: "array", minItems: 1, items: { $ref: "#" } }
1241
+ }
1242
+ }).getData({}, { recursionLimit: 1 });
1243
+ assert.deepEqual(data, { value: "node", nodes: [{ value: "node", nodes: [] }] });
1244
+ });
1245
+
1246
+ it("should resolve all reoccuring refs ", () => {
1247
+ const data = compileSchema({
1248
+ minItems: 3,
1249
+ items: {
1250
+ $ref: "#/$defs/item"
1251
+ },
1252
+ $defs: {
1253
+ item: {
1254
+ required: ["type"],
1255
+ properties: {
1256
+ type: {
1257
+ const: "node"
1258
+ // $ref: "#"
1259
+ }
1260
+ }
1261
+ }
1262
+ }
1263
+ }).getData([], { recursionLimit: 1 });
1264
+ assert.deepEqual(data, [{ type: "node" }, { type: "node" }, { type: "node" }]);
1265
+ });
1266
+
1267
+ // iteration depth is 1, input-depth is 2 => still add template to depth 2
1268
+ it("should respect depth of input data in $ref-resolution", () => {
1269
+ const data = compileSchema({
1270
+ type: "object",
1271
+ required: ["value", "nodes"],
1272
+ properties: {
1273
+ value: { type: "string", default: "node" },
1274
+ nodes: { type: "array", minItems: 1, items: { $ref: "#" } }
1275
+ }
1276
+ }).getData(
1277
+ { nodes: [{ value: "input-node" }, { nodes: [{ nodes: [] }] }] },
1278
+ {
1279
+ recursionLimit: 1
1280
+ }
1281
+ );
1282
+
1283
+ assert.deepEqual(data, {
1284
+ value: "node",
1285
+ nodes: [
1286
+ {
1287
+ value: "input-node",
1288
+ nodes: []
1289
+ },
1290
+ {
1291
+ value: "node",
1292
+ nodes: [
1293
+ {
1294
+ value: "node",
1295
+ nodes: []
1296
+ }
1297
+ ]
1298
+ }
1299
+ ]
1300
+ });
1301
+ });
1302
+
1303
+ it("should create template of draft04", () => {
1304
+ const schema = require("../../remotes/draft04.json");
1305
+ const node = compileSchema({ ...schema, $schema: "draft-06" });
1306
+ const res = node.getData({}, { addOptionalProps: true });
1307
+ // console.log("RESULT\n", JSON.stringify(res, null, 2));
1308
+ assert.deepEqual(Object.prototype.toString.call(res), "[object Object]");
1309
+ });
1310
+
1311
+ it("should create template of draft07", () => {
1312
+ const data = compileSchema(require("../../remotes/draft07.json")).getData({}, { addOptionalProps: true });
1313
+ // console.log("RESULT\n", JSON.stringify(data, null, 2));
1314
+ assert.deepEqual(Object.prototype.toString.call(data), "[object Object]");
1315
+ });
1316
+ });
1317
+
1318
+ describe("if-then-else", () => {
1319
+ it("should return template of then-schema for valid if-schema", () => {
1320
+ const data = compileSchema({
1321
+ type: "object",
1322
+ required: ["test"],
1323
+ properties: { test: { type: "string", default: "with value" } },
1324
+ if: { properties: { test: { type: "string", minLength: 4 } } },
1325
+ then: { required: ["dynamic"], properties: { dynamic: { type: "string", default: "from then" } } }
1326
+ }).getData();
1327
+ assert.deepEqual(data, {
1328
+ test: "with value",
1329
+ dynamic: "from then"
1330
+ });
1331
+ });
1332
+
1333
+ it("should NOT create data for then-schema if it is not required", () => {
1334
+ const data = compileSchema({
1335
+ type: "object",
1336
+ required: ["test"],
1337
+ properties: { test: { type: "string", default: "with value" } },
1338
+ if: { properties: { test: { type: "string", minLength: 4 } } },
1339
+ then: { properties: { dynamic: { type: "string", default: "from then" } } }
1340
+ }).getData(undefined, { addOptionalProps: false });
1341
+ assert.deepEqual(data, { test: "with value" });
1342
+ });
1343
+
1344
+ it("should NOT return template of then-schema for invalid if-schema", () => {
1345
+ const data = compileSchema({
1346
+ type: "object",
1347
+ required: ["test"],
1348
+ properties: { test: { type: "string", default: "too short" } },
1349
+ if: { properties: { test: { type: "string", minLength: 40 } } },
1350
+ then: { properties: { dynamic: { type: "string", default: "from then" } } }
1351
+ }).getData();
1352
+ assert.deepEqual(data, { test: "too short" });
1353
+ });
1354
+
1355
+ it("should return template of else-schema for invalid if-schema", () => {
1356
+ const data = compileSchema({
1357
+ type: "object",
1358
+ required: ["test"],
1359
+ properties: { test: { type: "string", default: "with test" } },
1360
+ if: { properties: { test: { type: "string", minLength: 40 } } },
1361
+ then: { required: ["dynamic"], properties: { dynamic: { type: "string", default: "from then" } } },
1362
+ else: { required: ["dynamic"], properties: { dynamic: { type: "string", default: "from else" } } }
1363
+ }).getData();
1364
+ assert.deepEqual(data, { test: "with test", dynamic: "from else" });
1365
+ });
1366
+
1367
+ it("should incrementally resolve multiple 'then'-schema", () => {
1368
+ const data = compileSchema({
1369
+ type: "object",
1370
+ required: ["trigger"],
1371
+ properties: { trigger: { type: "boolean" } },
1372
+ allOf: [
1373
+ {
1374
+ if: { properties: { trigger: { const: true } } },
1375
+ then: {
1376
+ required: ["additionalSchema"],
1377
+ properties: { additionalSchema: { type: "string", default: "additional" } }
1378
+ }
1379
+ },
1380
+ {
1381
+ if: { required: ["additionalSchema"], properties: { additionalSchema: { minLength: 5 } } },
1382
+ then: {
1383
+ required: ["anotherSchema"],
1384
+ properties: { anotherSchema: { type: "string", default: "another" } }
1385
+ }
1386
+ }
1387
+ ]
1388
+ }).getData({ trigger: true });
1389
+ assert.deepEqual(data, { trigger: true, additionalSchema: "additional", anotherSchema: "another" });
1390
+ });
1391
+ });
1392
+
1393
+ describe("type-array", () => {
1394
+ it("should return first type of list for template", () => {
1395
+ const node = compileSchema({
1396
+ type: ["string", "object"]
1397
+ });
1398
+ const res = node.getData();
1399
+
1400
+ assert.deepEqual(res, "");
1401
+ });
1402
+
1403
+ it("should return input data", () => {
1404
+ const node = compileSchema({
1405
+ type: ["string", "object"]
1406
+ });
1407
+ const res = node.getData("title");
1408
+
1409
+ assert.deepEqual(res, "title");
1410
+ });
1411
+
1412
+ it("should return type of default value if data is not given", () => {
1413
+ const node = compileSchema({
1414
+ type: ["string", "array", "object"],
1415
+ default: []
1416
+ });
1417
+ const res = node.getData();
1418
+
1419
+ assert.deepEqual(res, []);
1420
+ });
1421
+ });
1422
+
1423
+ describe("templateOptions", () => {
1424
+ it("should remove invalid oneOf schema if 'removeInvalidData=true'", () => {
1425
+ const node = compileSchema({
1426
+ type: "object",
1427
+ oneOf: [
1428
+ {
1429
+ type: "object",
1430
+ properties: {
1431
+ value: { type: "string", default: "jane" }
1432
+ }
1433
+ },
1434
+ {
1435
+ type: "object",
1436
+ properties: {
1437
+ value: { type: "number" },
1438
+ test: { type: "string", default: "test" }
1439
+ }
1440
+ }
1441
+ ]
1442
+ });
1443
+ const res = node.getData(
1444
+ { value: ["remove-me"] },
1445
+ {
1446
+ removeInvalidData: true
1447
+ }
1448
+ );
1449
+
1450
+ assert.deepEqual(res, {});
1451
+ });
1452
+
1453
+ it("should not add optional properties", () => {
1454
+ const schema = {
1455
+ type: "object",
1456
+ required: ["list", "author"],
1457
+ properties: {
1458
+ title: { type: "string", default: "title" },
1459
+ list: {
1460
+ type: "array",
1461
+ items: {
1462
+ allOf: [
1463
+ { type: "object" },
1464
+ {
1465
+ properties: {
1466
+ index: { type: "number", default: 4 }
1467
+ }
1468
+ }
1469
+ ]
1470
+ }
1471
+ },
1472
+ author: {
1473
+ anyOf: [
1474
+ { type: "string", default: "jane" },
1475
+ { type: "string", default: "john" }
1476
+ ]
1477
+ },
1478
+ source: {
1479
+ type: "string",
1480
+ enum: ["dpa", "getty"]
1481
+ }
1482
+ }
1483
+ };
1484
+ const node = compileSchema(schema);
1485
+
1486
+ const template = node.getData(
1487
+ {},
1488
+ {
1489
+ addOptionalProps: false
1490
+ }
1491
+ );
1492
+
1493
+ assert.deepEqual({ list: [], author: "jane" }, template);
1494
+ });
1495
+
1496
+ describe("extendDefaults", () => {
1497
+ it("should keep array default-value with 'extendDefaults:false'", () => {
1498
+ const node = compileSchema({
1499
+ type: "array",
1500
+ default: [],
1501
+ items: {
1502
+ type: "string",
1503
+ enum: ["one", "two"]
1504
+ },
1505
+ minItems: 1 // usually adds an enty, but default states: []
1506
+ });
1507
+ const res = node.getData(undefined, {
1508
+ extendDefaults: false
1509
+ });
1510
+
1511
+ assert.deepEqual(res, []);
1512
+ });
1513
+
1514
+ it("should add items to array with no default-value given and 'extendDefaults:false'", () => {
1515
+ const node = compileSchema({
1516
+ type: "array",
1517
+ items: {
1518
+ type: "string",
1519
+ enum: ["one", "two"]
1520
+ },
1521
+ minItems: 1 // usually adds an enty, but default states: []
1522
+ });
1523
+ const res = node.getData(undefined, {
1524
+ extendDefaults: false
1525
+ });
1526
+
1527
+ assert.deepEqual(res, ["one"]);
1528
+ });
1529
+
1530
+ it("should add items to default-array with 'extendDefaults:true'", () => {
1531
+ const node = compileSchema({
1532
+ type: "array",
1533
+ default: [],
1534
+ items: {
1535
+ type: "string",
1536
+ enum: ["one", "two"]
1537
+ },
1538
+ minItems: 1 // usually adds an enty, but default states: []
1539
+ });
1540
+ const res = node.getData(undefined, {
1541
+ extendDefaults: true
1542
+ });
1543
+
1544
+ assert.deepEqual(res, ["one"]);
1545
+ });
1546
+
1547
+ it("should not add required items to object with default-value given and 'extendDefaults:false'", () => {
1548
+ const node = compileSchema({
1549
+ type: "object",
1550
+ required: ["title"],
1551
+ default: {},
1552
+ properties: {
1553
+ title: { type: "string" }
1554
+ }
1555
+ });
1556
+ const res = node.getData(undefined, {
1557
+ extendDefaults: false
1558
+ });
1559
+
1560
+ assert.deepEqual(res, {});
1561
+ });
1562
+
1563
+ it("should extend object by required property with no default-value given and 'extendDefaults:false'", () => {
1564
+ const node = compileSchema({
1565
+ type: "object",
1566
+ required: ["title"],
1567
+ properties: {
1568
+ title: { type: "string" }
1569
+ }
1570
+ });
1571
+ const res = node.getData(undefined, {
1572
+ extendDefaults: false
1573
+ });
1574
+
1575
+ assert.deepEqual(res, { title: "" });
1576
+ });
1577
+ it("should extend default-object with 'extendDefaults:true'", () => {
1578
+ const node = compileSchema({
1579
+ type: "object",
1580
+ required: ["title"],
1581
+ default: {},
1582
+ properties: {
1583
+ title: { type: "string" }
1584
+ }
1585
+ });
1586
+ const res = node.getData(undefined, {
1587
+ extendDefaults: true
1588
+ });
1589
+
1590
+ assert.deepEqual(res, { title: "" });
1591
+ });
1592
+ });
1593
+ });
1594
+
1595
+ describe("defaultTemplateOptions.removeInvalidData", () => {
1596
+ it("should NOT remove invalid data per default", () => {
1597
+ const node = compileSchema({
1598
+ type: "object",
1599
+ properties: { valid: { type: "string" } },
1600
+ additionalProperties: false
1601
+ });
1602
+ const res = node.getData({ valid: "stays", invalid: "not removed" });
1603
+ assert.deepEqual(res, { valid: "stays", invalid: "not removed" });
1604
+ });
1605
+
1606
+ it("should remove invalid data with 'removeInvalidData=true'", () => {
1607
+ const node = compileSchema({
1608
+ type: "object",
1609
+ properties: { valid: { type: "string" } },
1610
+ additionalProperties: false
1611
+ });
1612
+ const res = node.getData({ valid: "stays", invalid: "removes" }, { removeInvalidData: true });
1613
+ assert.deepEqual(res, { valid: "stays" });
1614
+ });
1615
+
1616
+ it("should NOT remove valid but unspecified data when 'removeInvalidData=true'", () => {
1617
+ const node = compileSchema({
1618
+ type: "object",
1619
+ properties: { valid: { type: "string" } }
1620
+ });
1621
+ const res = node.getData({ valid: "stays", unspecified: "stays" }, { removeInvalidData: true });
1622
+ assert.deepEqual(res, { valid: "stays", unspecified: "stays" });
1623
+ });
1624
+
1625
+ it("should remove invalid data with 'removeInvalidData=true' when set as defaultTemplateOptions", () => {
1626
+ const node = compileSchema(
1627
+ {
1628
+ type: "object",
1629
+ properties: { valid: { type: "string" } },
1630
+ additionalProperties: false
1631
+ },
1632
+ {
1633
+ getDataDefaultOptions: { removeInvalidData: true }
1634
+ }
1635
+ );
1636
+ const res = node.getData({ valid: "stays", invalid: "removes" });
1637
+ assert.deepEqual(res, { valid: "stays" });
1638
+ });
1639
+
1640
+ it("should NOT remove invalid data when set per default but overwritten on function", () => {
1641
+ const node = compileSchema(
1642
+ {
1643
+ type: "object",
1644
+ properties: { valid: { type: "string" } },
1645
+ additionalProperties: false
1646
+ },
1647
+ {
1648
+ getDataDefaultOptions: { removeInvalidData: true }
1649
+ }
1650
+ );
1651
+ const res = node.getData({ valid: "stays", invalid: "not removed" }, { removeInvalidData: false });
1652
+ assert.deepEqual(res, { valid: "stays", invalid: "not removed" });
1653
+ });
1654
+ });
1655
+ describe("defaultTemplateOptions.useTypeDefaults", () => {
1656
+ it("should return initial value for missing default-properties", () => {
1657
+ const data = compileSchema({
1658
+ required: ["valid"],
1659
+ properties: { valid: { type: "string" } }
1660
+ }).getData(null, { useTypeDefaults: true });
1661
+
1662
+ assert.deepEqual(data, { valid: "" });
1663
+ });
1664
+
1665
+ it("should omit initial value for missing default-properties", () => {
1666
+ const data = compileSchema({
1667
+ required: ["valid"],
1668
+ properties: { valid: { type: "string" } }
1669
+ }).getData(null, { useTypeDefaults: false });
1670
+
1671
+ assert.deepEqual(data, {});
1672
+ });
1673
+
1674
+ // @todo: reevaluate this behaviour
1675
+ it("should return initial object-value for missing default-properties, even if useTypeDefaults: false", () => {
1676
+ const data = compileSchema({
1677
+ required: ["valid"],
1678
+ properties: { valid: { type: "string" } }
1679
+ }).getData(null, { useTypeDefaults: false });
1680
+
1681
+ assert.deepEqual(data, {});
1682
+ });
1683
+
1684
+ // @todo: reevaluate this behaviour
1685
+ it("should return initial array-value for missing default-properties", () => {
1686
+ const data = compileSchema({
1687
+ required: ["valid"],
1688
+ properties: { valid: { type: "array", items: { type: "string" }, minItems: 1 } }
1689
+ }).getData(null, { useTypeDefaults: false });
1690
+
1691
+ assert.deepEqual(data, { valid: [undefined] });
1692
+ });
1693
+
1694
+ it("should omit properties without default values when 'useTypeDefaults:false' even if required", () => {
1695
+ const node = compileSchema({
1696
+ type: "object",
1697
+ required: ["name", "age", "country"],
1698
+ properties: {
1699
+ name: { type: "string", default: "John Doe" },
1700
+ age: { type: "number" },
1701
+ country: { type: "string", default: "USA" }
1702
+ }
1703
+ });
1704
+ const res = node.getData(undefined, {
1705
+ extendDefaults: false,
1706
+ useTypeDefaults: false
1707
+ });
1708
+
1709
+ assert.deepEqual(res, { name: "John Doe", country: "USA" });
1710
+ });
1711
+
1712
+ it("should omit properties without default values when 'useTypeDefaults:false' even if required in nested", () => {
1713
+ const node = compileSchema({
1714
+ type: "object",
1715
+ properties: {
1716
+ user: {
1717
+ type: "object",
1718
+ required: ["id", "username"],
1719
+ properties: {
1720
+ id: { type: "string" },
1721
+ username: { type: "string", default: "guest" },
1722
+ profile: {
1723
+ type: "object",
1724
+ properties: {
1725
+ bio: { type: "string" },
1726
+ theme: { type: "string", default: "light" }
1727
+ }
1728
+ }
1729
+ }
1730
+ },
1731
+ active: { type: "boolean", default: true }
1732
+ }
1733
+ });
1734
+ const res = node.getData({}, { addOptionalProps: true, useTypeDefaults: false });
1735
+
1736
+ assert.deepEqual(
1737
+ JSON.stringify(res),
1738
+ JSON.stringify({
1739
+ user: {
1740
+ username: "guest",
1741
+ profile: {
1742
+ theme: "light"
1743
+ }
1744
+ },
1745
+ active: true
1746
+ })
1747
+ );
1748
+ });
1749
+
1750
+ it("should handle type string with default value and 'useTypeDefaults:false'", () => {
1751
+ const node = compileSchema({
1752
+ type: "string",
1753
+ default: "default value"
1754
+ });
1755
+ const res = node.getData(undefined, {
1756
+ useTypeDefaults: false
1757
+ });
1758
+ assert.deepEqual(res, "default value");
1759
+ });
1760
+
1761
+ it("should handle type string without default value and 'useTypeDefaults:false'", () => {
1762
+ const node = compileSchema({
1763
+ type: "string"
1764
+ });
1765
+ const res = node.getData(undefined, { useTypeDefaults: false });
1766
+ assert.deepEqual(res, undefined);
1767
+ });
1768
+
1769
+ it("should handle array without default value and 'useTypeDefaults:false'", () => {
1770
+ const node = compileSchema({
1771
+ type: "object",
1772
+ required: ["title"],
1773
+ properties: {
1774
+ title: {
1775
+ type: "array",
1776
+ items: { type: "string" }
1777
+ }
1778
+ }
1779
+ });
1780
+ const res = node.getData(undefined, { useTypeDefaults: false });
1781
+ assert.deepEqual(res, { title: [] });
1782
+ });
1783
+ });
1786
1784
  });