@squiz/dx-json-schema-lib 1.79.0 → 1.80.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (56) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/jest.config.ts +13 -2
  3. package/lib/JsonSchemaService.d.ts +34 -0
  4. package/lib/JsonSchemaService.js +140 -0
  5. package/lib/JsonSchemaService.js.map +1 -0
  6. package/lib/JsonSchemaService.spec.d.ts +1 -0
  7. package/lib/JsonSchemaService.spec.js +1807 -0
  8. package/lib/JsonSchemaService.spec.js.map +1 -0
  9. package/lib/JsonValidationService.d.ts +11 -33
  10. package/lib/JsonValidationService.js +43 -194
  11. package/lib/JsonValidationService.js.map +1 -1
  12. package/lib/JsonValidationService.spec.js +19 -1800
  13. package/lib/JsonValidationService.spec.js.map +1 -1
  14. package/lib/index.d.ts +1 -0
  15. package/lib/index.js +1 -0
  16. package/lib/index.js.map +1 -1
  17. package/lib/jsonTypeResolution/TypeResolver.d.ts +0 -1
  18. package/lib/jsonTypeResolution/TypeResolver.js +0 -3
  19. package/lib/jsonTypeResolution/TypeResolver.js.map +1 -1
  20. package/lib/jsonTypeResolution/TypeResolver.spec.js +10 -0
  21. package/lib/jsonTypeResolution/TypeResolver.spec.js.map +1 -1
  22. package/lib/manifest/v1/DxComponentInputSchema.spec.js +18 -0
  23. package/lib/manifest/v1/DxComponentInputSchema.spec.js.map +1 -1
  24. package/lib/manifest/v1/DxContentMetaSchema.json +24 -32
  25. package/lib/manifest/v1/JobV1.d.ts +23 -18
  26. package/lib/manifest/v1/__test__/schemas/invalidUiMetadata.json +31 -0
  27. package/lib/manifest/v1/v1.d.ts +23 -18
  28. package/lib/manifest/v1/v1.spec.js +3 -66
  29. package/lib/manifest/v1/v1.spec.js.map +1 -1
  30. package/lib/processValidationResult.d.ts +2 -0
  31. package/lib/processValidationResult.js +24 -0
  32. package/lib/processValidationResult.js.map +1 -0
  33. package/lib/validators/customKeywordValidators.d.ts +2 -0
  34. package/lib/validators/customKeywordValidators.js +47 -0
  35. package/lib/validators/customKeywordValidators.js.map +1 -0
  36. package/lib/validators/customKeywordValidators.spec.d.ts +1 -0
  37. package/lib/validators/customKeywordValidators.spec.js +100 -0
  38. package/lib/validators/customKeywordValidators.spec.js.map +1 -0
  39. package/package.json +1 -1
  40. package/src/JsonSchemaService.spec.ts +2198 -0
  41. package/src/JsonSchemaService.ts +159 -0
  42. package/src/JsonValidationService.spec.ts +26 -2195
  43. package/src/JsonValidationService.ts +64 -226
  44. package/src/index.ts +1 -0
  45. package/src/jsonTypeResolution/TypeResolver.spec.ts +12 -0
  46. package/src/jsonTypeResolution/TypeResolver.ts +0 -4
  47. package/src/manifest/v1/DxComponentInputSchema.spec.ts +21 -0
  48. package/src/manifest/v1/DxContentMetaSchema.json +24 -32
  49. package/src/manifest/v1/JobV1.ts +23 -23
  50. package/src/manifest/v1/__test__/schemas/invalidUiMetadata.json +31 -0
  51. package/src/manifest/v1/v1.spec.ts +3 -73
  52. package/src/manifest/v1/v1.ts +23 -23
  53. package/src/processValidationResult.ts +20 -0
  54. package/src/validators/customKeywordValidators.spec.ts +171 -0
  55. package/src/validators/customKeywordValidators.ts +53 -0
  56. package/tsconfig.tsbuildinfo +1 -1
@@ -1,22 +1,10 @@
1
- import { ComponentInputMetaSchema, JSONSchemaService, JsonValidationService } from './JsonValidationService';
1
+ import { JsonValidationService } from './JsonValidationService';
2
2
  import { SchemaValidationError } from './errors/SchemaValidationError';
3
3
 
4
4
  import validManifest from './manifest/v1/__test__/schemas/validComponent.json';
5
5
  import validManifestJson from './manifest/v1/__test__/schemas/validComponentJson.json';
6
- import { FormattedText } from './formatted-text/v1/formattedText';
7
6
  import inputStringWithFormat from './manifest/v1/__test__/schemas/inputStringWithFormat.json';
8
- import { JSONSchema } from '@squiz/json-schema-library';
9
- import {
10
- AnyPrimitiveType,
11
- AnyResolvableType,
12
- PrimitiveType,
13
- ResolvableType,
14
- TypeResolver,
15
- } from './jsonTypeResolution/TypeResolver';
16
- import { FormattedTextType, SquizImageType, SquizLinkType } from './primitiveTypes';
17
- import { TypeResolverBuilder } from './jsonTypeResolution/TypeResolverBuilder';
18
- import { MatrixAssetUri } from './validators/utils/matrixAssetValidator';
19
- import { MatrixAssetLinkType, MatrixAssetType } from './resolvableTypes';
7
+ import invalidUiMetadata from './manifest/v1/__test__/schemas/invalidUiMetadata.json';
20
8
 
21
9
  function expectToThrowErrorMatchingTypeAndMessage(
22
10
  // eslint-disable-next-line @typescript-eslint/ban-types
@@ -126,6 +114,29 @@ describe('JsonValidationService', () => {
126
114
  },
127
115
  );
128
116
  });
117
+
118
+ it('should throw error for invalid ui:metadata options', () => {
119
+ expectToThrowErrorMatchingTypeAndMessage(
120
+ () => {
121
+ jsonValidationService.validateManifest(invalidUiMetadata, 'v1');
122
+ },
123
+ SchemaValidationError,
124
+ 'failed validation: ui:metadata property quickOption is only valid for enum based properties.',
125
+ {
126
+ '#/functions/0/input/properties/prop': [
127
+ {
128
+ data: {
129
+ expected: 'enum',
130
+ pointer: '#/functions/0/input/properties/prop',
131
+ received: 'object',
132
+ value: { type: 'string', 'ui:metadata': { quickOption: true } },
133
+ },
134
+ message: 'ui:metadata property quickOption is only valid for enum based properties.',
135
+ },
136
+ ],
137
+ },
138
+ );
139
+ });
129
140
  });
130
141
 
131
142
  describe('validateRenderInput', () => {
@@ -271,27 +282,7 @@ describe('JsonValidationService', () => {
271
282
  const value = {
272
283
  'my-input': [{ type: 'text', value: 'hello' }],
273
284
  };
274
- expectToThrowErrorMatchingTypeAndMessage(
275
- () => {
276
- jsonValidationService.validateRenderInput(schema, value);
277
- },
278
- SchemaValidationError,
279
- 'failed validation: Expected `Array [{"type":"text","value":"hello"}]` (array) in `#/my-input` to be of type `string`',
280
- {
281
- '#/my-input': [
282
- {
283
- message:
284
- 'Expected `Array [{"type":"text","value":"hello"}]` (array) in `#/my-input` to be of type `string`',
285
- data: {
286
- received: 'array',
287
- expected: 'string',
288
- value: [{ type: 'text', value: 'hello' }],
289
- pointer: '#/my-input',
290
- },
291
- },
292
- ],
293
- },
294
- );
285
+ expect(() => jsonValidationService.validateRenderInput(schema, value)).toThrowError(SchemaValidationError);
295
286
  });
296
287
 
297
288
  it('should validate a property with type FormattedText within an if/then/else as string', () => {
@@ -340,2163 +331,3 @@ describe('JsonValidationService', () => {
340
331
  });
341
332
  });
342
333
  });
343
-
344
- const defaultSchema: JSONSchema = {
345
- type: 'object',
346
- properties: {
347
- myProperty: {
348
- type: 'string',
349
- },
350
- },
351
- required: ['myProperty'],
352
- };
353
- function primitiveTypeFixture<T extends string>(title: T, schema: JSONSchema = defaultSchema) {
354
- return PrimitiveType({
355
- ...schema,
356
- title,
357
- });
358
- }
359
-
360
- function resolvableTypeFixture<T extends string>(title: T, schema: JSONSchema = defaultSchema) {
361
- return ResolvableType({
362
- ...schema,
363
- title,
364
- });
365
- }
366
-
367
- describe('JsonSchemaService', () => {
368
- let jsonSchemaService: JSONSchemaService<AnyPrimitiveType, AnyResolvableType>;
369
- beforeAll(() => {
370
- const typeResolver = new TypeResolver([FormattedTextType]);
371
- jsonSchemaService = new JSONSchemaService(typeResolver, ComponentInputMetaSchema);
372
- });
373
- describe('validateContentSchema', () => {
374
- it('should return true for a valid content schema', () => {
375
- const contentSchema = {
376
- type: 'object',
377
-
378
- properties: {
379
- 'my-input': { type: 'number' },
380
- },
381
-
382
- required: ['my-input'],
383
- };
384
- const result = jsonSchemaService.validateInput(contentSchema);
385
- expect(result).toBe(true);
386
- });
387
-
388
- it('should return false for an invalid content schema, where the required property is missed from a child object', () => {
389
- const contentSchema = {
390
- type: 'object',
391
-
392
- properties: {
393
- 'my-input': {
394
- type: 'object',
395
-
396
- properties: {
397
- 'my-deep-input': { type: 'object' },
398
- },
399
- },
400
- },
401
-
402
- required: ['my-input'],
403
- };
404
- expectToThrowErrorMatchingTypeAndMessage(
405
- () => {
406
- jsonSchemaService.validateInput(contentSchema);
407
- },
408
- SchemaValidationError,
409
- 'failed validation: The required property `required` is missing at `#/properties/my-input`',
410
- {
411
- '#/properties/my-input': [
412
- {
413
- data: { key: 'required', pointer: '#/properties/my-input' },
414
- message: 'The required property `required` is missing at `#/properties/my-input`',
415
- },
416
- ],
417
- },
418
- );
419
- });
420
-
421
- it('should throw a SchemaValidationError for an invalid content schema, top level type must be object', () => {
422
- const contentSchema = {
423
- type: 'array',
424
-
425
- items: {
426
- type: 'object',
427
- properties: {
428
- 'my-input': { type: 'number' },
429
- },
430
- required: ['my-input'],
431
- },
432
- };
433
- expectToThrowErrorMatchingTypeAndMessage(
434
- () => {
435
- jsonSchemaService.validateInput(contentSchema);
436
- },
437
- SchemaValidationError,
438
- `failed validation: Expected value at \`#/type\` to be \`object\`, but value given is \`array\``,
439
- {
440
- '#/type': [
441
- {
442
- data: { expected: 'object', pointer: '#/type', value: 'array' },
443
- message: 'Expected value at `#/type` to be `object`, but value given is `array`',
444
- },
445
- ],
446
- },
447
- );
448
- });
449
-
450
- it('should throw a SchemaValidationError for an invalid content schema missing the required property', () => {
451
- const contentSchema = {
452
- type: 'object',
453
-
454
- properties: {
455
- 'my-input': { type: 'number' },
456
- },
457
- };
458
- expectToThrowErrorMatchingTypeAndMessage(
459
- () => {
460
- jsonSchemaService.validateInput(contentSchema);
461
- },
462
- SchemaValidationError,
463
- 'failed validation: The required property `required` is missing at `#`',
464
- {
465
- '#': [
466
- { data: { key: 'required', pointer: '#' }, message: 'The required property `required` is missing at `#`' },
467
- ],
468
- },
469
- );
470
- });
471
- });
472
-
473
- describe('SquizImage input', () => {
474
- it('should validate a squizImage input', () => {
475
- const schema = {
476
- type: 'object',
477
- properties: {
478
- image: {
479
- type: 'SquizImage',
480
- },
481
- },
482
- };
483
-
484
- const value: SquizImageType['__shape__'] = {
485
- name: 'My Image',
486
- alt: 'My Image that did not load',
487
- caption: 'This above is a loaded image',
488
- imageVariations: {
489
- original: {
490
- url: 'https://picsum.photos/200/300',
491
- width: 100,
492
- height: 100,
493
- byteSize: 1000,
494
- mimeType: 'image/jpeg',
495
- aspectRatio: '1:1',
496
- sha1Hash: '1234567890abcdef1234567890abcdef12345678',
497
- },
498
- },
499
- };
500
- expect(jsonSchemaService.validateInput(value, schema)).toEqual(true);
501
- });
502
-
503
- it('should error if SquizImage type is missing required properties', async () => {
504
- const schema = {
505
- type: 'object',
506
- properties: {
507
- myProp: {
508
- type: 'SquizImage',
509
- },
510
- },
511
- };
512
-
513
- const value: { myProp: SquizImageType['__shape__'] } = {
514
- // @ts-expect-error - missing required properties
515
- myProp: {
516
- alt: 'alt',
517
- caption: 'caption',
518
- name: 'name',
519
- },
520
- };
521
- expectToThrowErrorMatchingTypeAndMessage(
522
- () => {
523
- jsonSchemaService.validateInput(value, schema);
524
- },
525
- SchemaValidationError,
526
- 'failed validation: Expected `Object {"alt":"alt","caption":"caption","name":"name"}` (object) in `#/myProp` to be of type `SquizImage`',
527
- {
528
- '#/myProp': [
529
- {
530
- data: {
531
- expected: 'SquizImage',
532
- pointer: '#/myProp',
533
- received: 'object',
534
- value: { alt: 'alt', caption: 'caption', name: 'name' },
535
- },
536
- message:
537
- 'Expected `Object {"alt":"alt","caption":"caption","name":"name"}` (object) in `#/myProp` to be of type `SquizImage`',
538
- },
539
- ],
540
- },
541
- );
542
- });
543
- });
544
-
545
- describe('FormattedText input', () => {
546
- it('should handle type as an array', () => {
547
- const functionInputSchema = {
548
- type: 'object',
549
-
550
- properties: {
551
- 'my-input': { type: ['number', 'string'] },
552
- },
553
-
554
- required: ['my-input'],
555
- };
556
-
557
- expect(
558
- jsonSchemaService.validateInput(
559
- {
560
- 'my-input': 'formattedText',
561
- },
562
- functionInputSchema,
563
- ),
564
- ).toEqual(true);
565
-
566
- expect(
567
- jsonSchemaService.validateInput(
568
- {
569
- 'my-input': 123,
570
- },
571
- functionInputSchema,
572
- ),
573
- ).toEqual(true);
574
- });
575
-
576
- it.failing('should handle type is an array of both string and FormattedText', () => {
577
- const formattedText: FormattedText = [
578
- {
579
- tag: 'p',
580
- type: 'tag',
581
- children: [
582
- { type: 'text', value: 'This is some ' },
583
- { type: 'text', value: 'Link to asset 12345' },
584
- { type: 'text', value: ' with an image ' },
585
- { type: 'text', value: '.' },
586
- ],
587
- },
588
- ];
589
- const functionInputSchema = {
590
- type: 'object',
591
-
592
- properties: {
593
- 'my-input': { type: ['FormattedText', 'string'] },
594
- },
595
-
596
- required: ['my-input'],
597
- };
598
-
599
- expect(
600
- jsonSchemaService.validateInput(
601
- {
602
- 'my-input': formattedText,
603
- },
604
- functionInputSchema,
605
- ),
606
- ).toEqual(true);
607
-
608
- expect(
609
- jsonSchemaService.validateInput(
610
- {
611
- 'my-input': 'hello',
612
- },
613
- functionInputSchema,
614
- ),
615
- ).toEqual(true);
616
- });
617
-
618
- it('should return true if input is formatted text', () => {
619
- const functionInputSchema = {
620
- type: 'object',
621
-
622
- properties: {
623
- 'my-input': { type: 'FormattedText' },
624
- },
625
-
626
- required: ['my-input'],
627
- };
628
-
629
- const formattedText: FormattedText = [
630
- {
631
- tag: 'p',
632
- type: 'tag',
633
- children: [
634
- { type: 'text', value: 'This is some ' },
635
- { type: 'text', value: 'Link to asset 12345' },
636
- { type: 'text', value: ' with an image ' },
637
- { type: 'text', value: '.' },
638
- ],
639
- },
640
- ];
641
- const inputValue = {
642
- 'my-input': formattedText,
643
- };
644
-
645
- expect(() => jsonSchemaService.validateInput(inputValue, functionInputSchema)).not.toThrow();
646
- });
647
-
648
- it('should throw an error if the FormattedText input is not formatted text', () => {
649
- const functionInputSchema = {
650
- type: 'object',
651
-
652
- properties: {
653
- 'my-input': { type: 'FormattedText' },
654
- },
655
-
656
- required: ['my-input'],
657
- };
658
- const inputValue = {
659
- 'my-input': 123,
660
- };
661
- expectToThrowErrorMatchingTypeAndMessage(
662
- () => {
663
- jsonSchemaService.validateInput(inputValue, functionInputSchema);
664
- },
665
- SchemaValidationError,
666
- 'failed validation: Value `123` in `#/my-input` does not match any given oneof schema',
667
- {
668
- '#/my-input': [
669
- {
670
- data: {
671
- errors: [
672
- {
673
- code: 'type-error',
674
- data: { expected: 'array', pointer: '#/my-input', received: 'number', value: 123 },
675
- message: 'Expected `123` (number) in `#/my-input` to be of type `array`',
676
- name: 'TypeError',
677
- type: 'error',
678
- },
679
- ],
680
- oneOf: [{ $ref: 'FormattedText.json' }],
681
- pointer: '#/my-input',
682
- value: '123',
683
- },
684
- message: 'Value `123` in `#/my-input` does not match any given oneof schema',
685
- },
686
- ],
687
- },
688
- );
689
- });
690
-
691
- it('should throw an error if the FormattedText input is invalid formatted text', () => {
692
- const functionInputSchema = {
693
- type: 'object',
694
-
695
- properties: {
696
- 'my-input': { type: 'FormattedText' },
697
- },
698
-
699
- required: ['my-input'],
700
- };
701
- const inputValue = {
702
- 'my-input': {
703
- something: 'aa',
704
- },
705
- };
706
- expectToThrowErrorMatchingTypeAndMessage(
707
- () => {
708
- jsonSchemaService.validateInput(inputValue, functionInputSchema);
709
- },
710
- SchemaValidationError,
711
- 'failed validation: Value `{"something":"aa"}` in `#/my-input` does not match any given oneof schema',
712
- {
713
- '#/my-input': [
714
- {
715
- data: {
716
- errors: [
717
- {
718
- code: 'type-error',
719
- data: { expected: 'array', pointer: '#/my-input', received: 'object', value: { something: 'aa' } },
720
- message: 'Expected `Object {"something":"aa"}` (object) in `#/my-input` to be of type `array`',
721
- name: 'TypeError',
722
- type: 'error',
723
- },
724
- ],
725
- oneOf: [{ $ref: 'FormattedText.json' }],
726
- pointer: '#/my-input',
727
- value: '{"something":"aa"}',
728
- },
729
- message: 'Value `{"something":"aa"}` in `#/my-input` does not match any given oneof schema',
730
- },
731
- ],
732
- },
733
- );
734
- });
735
-
736
- it('should throw an error if the FormattedText input is invalid formatted text (deeply nested)', () => {
737
- const functionInputSchema = {
738
- type: 'object',
739
-
740
- properties: {
741
- 'my-input': { type: 'FormattedText' },
742
- },
743
-
744
- required: ['my-input'],
745
- };
746
- const formattedText: FormattedText = [
747
- {
748
- tag: 'p',
749
- type: 'tag',
750
- children: [
751
- { type: 'text', value: 'This is some ' },
752
- { type: 'text', value: 'Link to asset 12345' },
753
- { type: 'text', value: ' with an image ' },
754
- { type: 'text', value: 123 as any }, // see here
755
- { type: 'text', value: '.' },
756
- ],
757
- },
758
- ];
759
-
760
- const inputValue = {
761
- 'my-input': formattedText,
762
- };
763
- expectToThrowErrorMatchingTypeAndMessage(
764
- () => {
765
- jsonSchemaService.validateInput(inputValue, functionInputSchema);
766
- },
767
- SchemaValidationError,
768
- 'failed validation: Value `[{"tag":"p","type":"tag","children":[{"type":"text","value":"This is some "},{"type":"text","value":"Link to asset 12345"},{"type":"text","value":" with an image "},{"type":"text","value":123},{"type":"text","value":"."}]}]` in `#/my-input` does not match any given oneof schema',
769
- {
770
- '#/my-input': [
771
- {
772
- data: {
773
- errors: [
774
- {
775
- code: 'any-of-error',
776
- data: {
777
- anyOf: [
778
- { $ref: '#/definitions/HigherOrderFormattedNodes' },
779
- { $ref: '#/definitions/BaseFormattedNodes' },
780
- ],
781
- pointer: '#/my-input/0',
782
- value: {
783
- children: [
784
- { type: 'text', value: 'This is some ' },
785
- { type: 'text', value: 'Link to asset 12345' },
786
- { type: 'text', value: ' with an image ' },
787
- { type: 'text', value: 123 },
788
- { type: 'text', value: '.' },
789
- ],
790
- tag: 'p',
791
- type: 'tag',
792
- },
793
- },
794
- message: 'Object at `#/my-input/0` does not match any schema',
795
- name: 'AnyOfError',
796
- type: 'error',
797
- },
798
- ],
799
- oneOf: [{ $ref: 'FormattedText.json' }],
800
- pointer: '#/my-input',
801
- value:
802
- '[{"tag":"p","type":"tag","children":[{"type":"text","value":"This is some "},{"type":"text","value":"Link to asset 12345"},{"type":"text","value":" with an image "},{"type":"text","value":123},{"type":"text","value":"."}]}]',
803
- },
804
- message:
805
- 'Value `[{"tag":"p","type":"tag","children":[{"type":"text","value":"This is some "},{"type":"text","value":"Link to asset 12345"},{"type":"text","value":" with an image "},{"type":"text","value":123},{"type":"text","value":"."}]}]` in `#/my-input` does not match any given oneof schema',
806
- },
807
- ],
808
- },
809
- );
810
- });
811
-
812
- it('should validate an array of formatted texts', () => {
813
- const formattedText: FormattedText = [
814
- {
815
- tag: 'p',
816
- type: 'tag',
817
- children: [{ type: 'text', value: 'hello' }],
818
- },
819
- ];
820
-
821
- const schema = {
822
- type: 'object',
823
- properties: {
824
- arr: {
825
- type: 'array',
826
- items: { type: 'FormattedText' },
827
- },
828
- },
829
- };
830
- const value = {
831
- arr: [formattedText],
832
- };
833
-
834
- expect(jsonSchemaService.validateInput(value, schema)).toEqual(true);
835
- });
836
-
837
- it('should throw an error if the FormattedText input is invalid formatted text (deeply, deeply nested)', () => {
838
- const formattedText: FormattedText = [
839
- {
840
- tag: 'p',
841
- type: 'tag',
842
- children: [{ type: 'text', value: 'hello' }],
843
- },
844
- ];
845
-
846
- const inputValue: any = {
847
- 'my-input': formattedText,
848
- deep: {
849
- arr: [
850
- {
851
- prop: formattedText,
852
- formattedTextArray: [formattedText, formattedText, { bad: 'data' }],
853
- },
854
- ],
855
- },
856
- };
857
-
858
- const functionInputSchema = {
859
- type: 'object',
860
-
861
- properties: {
862
- 'my-input': { type: 'FormattedText' },
863
- deep: {
864
- type: 'object',
865
- properties: {
866
- arr: {
867
- type: 'array',
868
- items: {
869
- type: 'object',
870
- required: ['prop', 'formattedTextArray'],
871
- properties: {
872
- prop: 'FormattedText',
873
- formattedTextArray: {
874
- type: 'array',
875
- items: {
876
- type: 'FormattedText',
877
- },
878
- },
879
- },
880
- },
881
- },
882
- },
883
- required: ['arr'],
884
- },
885
- },
886
-
887
- required: ['my-input', 'deep'],
888
- };
889
-
890
- expectToThrowErrorMatchingTypeAndMessage(
891
- () => {
892
- jsonSchemaService.validateInput(inputValue, functionInputSchema);
893
- },
894
- SchemaValidationError,
895
- 'failed validation: Value `{"bad":"data"}` in `#/deep/arr/0/formattedTextArray/2` does not match any given oneof schema',
896
- {
897
- '#/deep/arr/0/formattedTextArray/2': [
898
- {
899
- data: {
900
- errors: [
901
- {
902
- code: 'type-error',
903
- data: {
904
- expected: 'array',
905
- pointer: '#/deep/arr/0/formattedTextArray/2',
906
- received: 'object',
907
- value: { bad: 'data' },
908
- },
909
- message:
910
- 'Expected `Object {"bad":"data"}` (object) in `#/deep/arr/0/formattedTextArray/2` to be of type `array`',
911
- name: 'TypeError',
912
- type: 'error',
913
- },
914
- ],
915
- oneOf: [{ $ref: 'FormattedText.json' }],
916
- pointer: '#/deep/arr/0/formattedTextArray/2',
917
- value: '{"bad":"data"}',
918
- },
919
- message:
920
- 'Value `{"bad":"data"}` in `#/deep/arr/0/formattedTextArray/2` does not match any given oneof schema',
921
- },
922
- ],
923
- },
924
- );
925
- });
926
-
927
- it('should validate a FormattedText value when the schema is a $ref', async () => {
928
- const formattedText: FormattedText = [
929
- {
930
- tag: 'p',
931
- type: 'tag',
932
- children: [{ type: 'text', value: 'hello' }],
933
- },
934
- ];
935
-
936
- const schema = {
937
- type: 'object',
938
- properties: {
939
- 'my-input': { $ref: '#/definitions/FormattedText' },
940
- },
941
- definitions: {
942
- FormattedText: { type: 'FormattedText' },
943
- },
944
- required: ['my-input'],
945
- };
946
- const value = {
947
- 'my-input': formattedText,
948
- };
949
-
950
- expect(jsonSchemaService.validateInput(value, schema)).toEqual(true);
951
- });
952
-
953
- it('should error when a FormattedText value is invalid when the schema is a $ref', async () => {
954
- const schema = {
955
- type: 'object',
956
- properties: {
957
- 'my-input': { $ref: '#/definitions/FormattedText' },
958
- },
959
- definitions: {
960
- FormattedText: { type: 'FormattedText' },
961
- },
962
- required: ['my-input'],
963
- };
964
- const value = {
965
- 'my-input': { bad: 'data' },
966
- };
967
-
968
- expectToThrowErrorMatchingTypeAndMessage(
969
- () => {
970
- jsonSchemaService.validateInput(value, schema);
971
- },
972
- SchemaValidationError,
973
- 'failed validation: Value `{"bad":"data"}` in `#/my-input` does not match any given oneof schema',
974
- {
975
- '#/my-input': [
976
- {
977
- data: {
978
- errors: [
979
- {
980
- code: 'type-error',
981
- data: { expected: 'array', pointer: '#/my-input', received: 'object', value: { bad: 'data' } },
982
- message: 'Expected `Object {"bad":"data"}` (object) in `#/my-input` to be of type `array`',
983
- name: 'TypeError',
984
- type: 'error',
985
- },
986
- ],
987
- oneOf: [{ $ref: 'FormattedText.json' }],
988
- pointer: '#/my-input',
989
- value: '{"bad":"data"}',
990
- },
991
- message: 'Value `{"bad":"data"}` in `#/my-input` does not match any given oneof schema',
992
- },
993
- ],
994
- },
995
- );
996
- });
997
-
998
- it('should validate a FormattedText value when the schema is a $ref to a $ref', async () => {
999
- const formattedText: FormattedText = [
1000
- {
1001
- tag: 'p',
1002
- type: 'tag',
1003
- children: [{ type: 'text', value: 'hello' }],
1004
- },
1005
- ];
1006
-
1007
- const schema = {
1008
- type: 'object',
1009
- properties: {
1010
- 'my-input': { $ref: '#/definitions/FormattedText' },
1011
- },
1012
- definitions: {
1013
- FormattedText: { $ref: '#/definitions/FormattedText2' },
1014
- FormattedText2: { type: 'FormattedText' },
1015
- },
1016
- required: ['my-input'],
1017
- };
1018
- const value = {
1019
- 'my-input': formattedText,
1020
- };
1021
-
1022
- expect(jsonSchemaService.validateInput(value, schema)).toEqual(true);
1023
- });
1024
-
1025
- it('should validate a FormattedText value when the schema is in an if/then/else', async () => {
1026
- const formattedText: FormattedText = [
1027
- {
1028
- tag: 'p',
1029
- type: 'tag',
1030
- children: [{ type: 'text', value: 'hello' }],
1031
- },
1032
- ];
1033
-
1034
- const schema = {
1035
- type: 'object',
1036
- properties: {
1037
- 'my-input': {
1038
- if: { type: 'string' },
1039
- then: { type: 'string' },
1040
- else: { type: 'FormattedText' },
1041
- },
1042
- },
1043
- required: ['my-input'],
1044
- };
1045
- const value = {
1046
- 'my-input': formattedText,
1047
- };
1048
-
1049
- expect(jsonSchemaService.validateInput(value, schema)).toEqual(true);
1050
- });
1051
-
1052
- it('should allow an empty array', async () => {
1053
- const schema = {
1054
- type: 'object',
1055
- properties: {
1056
- 'my-input': { type: 'FormattedText' },
1057
- },
1058
- required: [],
1059
- };
1060
-
1061
- expect(jsonSchemaService.validateInput({ 'my-input': [] }, schema)).toEqual(true);
1062
- });
1063
-
1064
- it.each([
1065
- ['with attributes', { title: 'Link title' }],
1066
- ['without attributes', undefined],
1067
- ])('should validate link-to-matrix-asset - %s', (_: string, attributes?: Record<string, string>) => {
1068
- const formattedText: FormattedText = [
1069
- {
1070
- type: 'link-to-matrix-asset',
1071
- matrixIdentifier: 'matrix-identifier',
1072
- matrixDomain: 'https://matrix-api-url',
1073
- target: '_blank',
1074
- matrixAssetId: '12345',
1075
- children: [{ type: 'text', value: 'hello' }],
1076
- attributes,
1077
- },
1078
- ];
1079
- const schema = {
1080
- type: 'object',
1081
- properties: {
1082
- myInput: {
1083
- type: 'FormattedText',
1084
- },
1085
- },
1086
- };
1087
- const value = {
1088
- myInput: formattedText,
1089
- };
1090
-
1091
- expect(jsonSchemaService.validateInput(value, schema)).toBe(true);
1092
- });
1093
-
1094
- it('should throw if link-to-matrix-asset contains a reserved attribute', () => {
1095
- const formattedText: FormattedText = [
1096
- {
1097
- type: 'link-to-matrix-asset',
1098
- matrixIdentifier: 'matrix-identifier',
1099
- matrixDomain: 'https://matrix-api-url',
1100
- target: '_blank',
1101
- matrixAssetId: '12345',
1102
- children: [{ type: 'text', value: 'hello' }],
1103
- attributes: {
1104
- // href is reserved (resolved from the selected Matrix asset)
1105
- href: 'https://www.my-matrix.squiz.net',
1106
- } as any,
1107
- },
1108
- ];
1109
- const schema = {
1110
- type: 'object',
1111
- properties: {
1112
- myInput: {
1113
- type: 'FormattedText',
1114
- },
1115
- },
1116
- };
1117
- const value = {
1118
- myInput: formattedText,
1119
- };
1120
-
1121
- expect(() => jsonSchemaService.validateInput(value, schema)).toThrow(/does not match any given oneof schema/);
1122
- });
1123
-
1124
- it.each([
1125
- ['with attributes', { title: 'Link title' }],
1126
- ['without attributes', undefined],
1127
- ])('should validate matrix-image - %s', (_: string, attributes?: Record<string, string>) => {
1128
- const formattedText: FormattedText = [
1129
- {
1130
- type: 'matrix-image',
1131
- matrixIdentifier: 'matrix-identifier',
1132
- matrixDomain: 'https://matrix-api-url',
1133
- matrixAssetId: '12345',
1134
- attributes,
1135
- },
1136
- ];
1137
- const schema = {
1138
- type: 'object',
1139
- properties: {
1140
- myInput: {
1141
- type: 'FormattedText',
1142
- },
1143
- },
1144
- };
1145
- const value = {
1146
- myInput: formattedText,
1147
- };
1148
-
1149
- expect(jsonSchemaService.validateInput(value, schema)).toBe(true);
1150
- });
1151
-
1152
- it('should throw if matrix-image contains a reserved attribute', () => {
1153
- const formattedText: FormattedText = [
1154
- {
1155
- type: 'matrix-image',
1156
- matrixIdentifier: 'matrix-identifier',
1157
- matrixDomain: 'https://matrix-api-url',
1158
- matrixAssetId: '12345',
1159
- attributes: {
1160
- // src is reserved (resolved from the selected Matrix asset)
1161
- src: 'https://www.my-matrix.squiz.net/image.png',
1162
- } as any,
1163
- },
1164
- ];
1165
- const schema = {
1166
- type: 'object',
1167
- properties: {
1168
- myInput: {
1169
- type: 'FormattedText',
1170
- },
1171
- },
1172
- };
1173
- const value = {
1174
- myInput: formattedText,
1175
- };
1176
-
1177
- expect(() => jsonSchemaService.validateInput(value, schema)).toThrow(/does not match any given oneof schema/);
1178
- });
1179
-
1180
- it.each([
1181
- ['with attributes', { title: 'Link title' }],
1182
- ['without attributes', undefined],
1183
- ])('should validate dam-image - %s', (_: string, attributes?: Record<string, string>) => {
1184
- const formattedText: FormattedText = [
1185
- {
1186
- type: 'dam-image',
1187
- damSystemIdentifier: 'dam-identifier',
1188
- damObjectId: '12345',
1189
- damSystemType: 'bynder',
1190
- attributes,
1191
- },
1192
- ];
1193
- const schema = {
1194
- type: 'object',
1195
- properties: {
1196
- myInput: {
1197
- type: 'FormattedText',
1198
- },
1199
- },
1200
- };
1201
- const value = {
1202
- myInput: formattedText,
1203
- };
1204
-
1205
- expect(jsonSchemaService.validateInput(value, schema)).toBe(true);
1206
- });
1207
-
1208
- it('should throw if dam-image contains a reserved attribute', () => {
1209
- const formattedText: FormattedText = [
1210
- {
1211
- type: 'dam-image',
1212
- damSystemIdentifier: 'dam-identifier',
1213
- damObjectId: '12345',
1214
- damSystemType: 'bynder',
1215
- attributes: {
1216
- // src is reserved (resolved from the selected DAM asset)
1217
- src: 'https://www.my-matrix.squiz.net/image.png',
1218
- } as any,
1219
- },
1220
- ];
1221
- const schema = {
1222
- type: 'object',
1223
- properties: {
1224
- myInput: {
1225
- type: 'FormattedText',
1226
- },
1227
- },
1228
- };
1229
- const value = {
1230
- myInput: formattedText,
1231
- };
1232
-
1233
- expect(() => jsonSchemaService.validateInput(value, schema)).toThrow(/does not match any given oneof schema/);
1234
- });
1235
- });
1236
-
1237
- describe('standard inputs', () => {
1238
- const functionInputSchema = {
1239
- type: 'object',
1240
-
1241
- properties: {
1242
- 'my-input': { type: 'number' },
1243
- },
1244
-
1245
- required: ['my-input'],
1246
- };
1247
-
1248
- it('should return true for valid input values', () => {
1249
- const inputValue = {
1250
- 'my-input': 123,
1251
- };
1252
- const result = jsonSchemaService.validateInput(inputValue, functionInputSchema);
1253
- expect(result).toBe(true);
1254
- });
1255
-
1256
- it('should throw a SchemaValidationError for invalid input type', () => {
1257
- const inputValue = {
1258
- 'my-input': '123',
1259
- };
1260
- expectToThrowErrorMatchingTypeAndMessage(
1261
- () => {
1262
- jsonSchemaService.validateInput(inputValue, functionInputSchema);
1263
- },
1264
- SchemaValidationError,
1265
- `failed validation: Expected \`123\` (string) in \`#/my-input\` to be of type \`number\``,
1266
- {
1267
- '#/my-input': [
1268
- {
1269
- data: { expected: 'number', pointer: '#/my-input', received: 'string', value: '123' },
1270
- message: 'Expected `123` (string) in `#/my-input` to be of type `number`',
1271
- },
1272
- ],
1273
- },
1274
- );
1275
- });
1276
-
1277
- it('should throw a SchemaValidationError for invalid input missing properties', () => {
1278
- const inputValue = {};
1279
- expectToThrowErrorMatchingTypeAndMessage(
1280
- () => {
1281
- jsonSchemaService.validateInput(inputValue, functionInputSchema);
1282
- },
1283
- SchemaValidationError,
1284
- `failed validation: The required property \`my-input\` is missing at \`#\``,
1285
- {
1286
- '#': [
1287
- { data: { key: 'my-input', pointer: '#' }, message: 'The required property `my-input` is missing at `#`' },
1288
- ],
1289
- },
1290
- );
1291
- });
1292
-
1293
- it('should throw a SchemaValidationError with a truncated enum value list if there are more than 5 enum options', () => {
1294
- expectToThrowErrorMatchingTypeAndMessage(
1295
- () => {
1296
- jsonSchemaService.validateInput(
1297
- { enum: 'z' },
1298
- { type: 'object', properties: { enum: { type: 'string', enum: ['a', 'b', 'c', 'd', 'e', 'f', 'g'] } } },
1299
- );
1300
- },
1301
- SchemaValidationError,
1302
- 'failed validation: Expected given value `z` in #/enum` to be one of `[a, b, c, d, e, ... 2 more]`',
1303
- {
1304
- '#/enum': [
1305
- {
1306
- data: { pointer: '#/enum', value: 'z', values: ['a', 'b', 'c', 'd', 'e', 'f', 'g'] },
1307
- message: 'Expected given value `z` in #/enum` to be one of `[a, b, c, d, e, ... 2 more]`',
1308
- },
1309
- ],
1310
- },
1311
- );
1312
- });
1313
-
1314
- // TODO DEVX-658
1315
- it.skip('should throw a SchemaValidationError for invalid input additional properties', () => {
1316
- const inputValue = {
1317
- 'my-input': 123,
1318
- 'my-input-2': 123,
1319
- };
1320
- expect(() => {
1321
- jsonSchemaService.validateInput(inputValue, functionInputSchema);
1322
- }).toThrowErrorMatchingInlineSnapshot();
1323
- });
1324
- });
1325
-
1326
- describe('validateInput', () => {
1327
- it.each([String('123'), Number(123), [123]])(
1328
- 'should validate any primitive type with its resolvable type %s',
1329
- (propertyValue) => {
1330
- const primitiveSchema = primitiveTypeFixture('MyPrimitive', { type: 'string' });
1331
- const MyResolvableNumber = resolvableTypeFixture('MyResolvableNumber', { type: 'number' });
1332
- const MyResolvableArray = resolvableTypeFixture('MyResolvableArray', { type: 'array' });
1333
- const jsonSchemaService = new JSONSchemaService(
1334
- new TypeResolver([primitiveSchema], [MyResolvableNumber, MyResolvableArray], {
1335
- MyPrimitive: {
1336
- // @ts-expect-error - fixture is unknown but we know the actual shape
1337
- MyResolvableNumber: (value: number) => value.toString(),
1338
- // @ts-expect-error - fixture is unknown but we know the actual shape
1339
- MyResolvableArray: (value: any[]) => value.join(''),
1340
- },
1341
- }),
1342
- ComponentInputMetaSchema,
1343
- );
1344
-
1345
- expect(
1346
- jsonSchemaService.validateInput(
1347
- { myProperty: propertyValue },
1348
- { type: 'object', properties: { myProperty: { type: 'MyPrimitive' } } },
1349
- ),
1350
- ).toEqual(true);
1351
- },
1352
- );
1353
-
1354
- it('should error when a primitive type is provided a value that cannot be resolved by its resolvable types', () => {
1355
- const primitiveSchema = primitiveTypeFixture('MyPrimitive', { type: 'string' });
1356
- const MyResolvableNumber = resolvableTypeFixture('MyResolvableNumber', { type: 'number' });
1357
- const MyResolvableArray = resolvableTypeFixture('MyResolvableArray', { type: 'array' });
1358
- const jsonSchemaService = new JSONSchemaService(
1359
- new TypeResolver([primitiveSchema], [MyResolvableNumber, MyResolvableArray], {
1360
- MyPrimitive: {
1361
- // @ts-expect-error - fixture is unknown but we know the actual shape
1362
- MyResolvableNumber: (value: number) => value.toString(),
1363
- // @ts-expect-error - fixture is unknown but we know the actual shape
1364
- MyResolvableArray: (value: any[]) => value.join(''),
1365
- },
1366
- }),
1367
- ComponentInputMetaSchema,
1368
- );
1369
-
1370
- expect(() => {
1371
- jsonSchemaService.validateInput(
1372
- { myProperty: true },
1373
- { type: 'object', properties: { myProperty: { type: 'MyPrimitive' } } },
1374
- );
1375
- }).toThrowError();
1376
- });
1377
-
1378
- it.each([String('123'), Number(123), [123]])(
1379
- 'should validate a primitive type when defined as a ref with resolvable value %s',
1380
- (propertyValue) => {
1381
- const primitiveSchema = primitiveTypeFixture('MyPrimitive', { type: 'string' });
1382
- const MyResolvableNumber = resolvableTypeFixture('MyResolvableNumber', { type: 'number' });
1383
- const MyResolvableArray = resolvableTypeFixture('MyResolvableArray', { type: 'array' });
1384
- const jsonSchemaService = new JSONSchemaService(
1385
- new TypeResolver([primitiveSchema], [MyResolvableNumber, MyResolvableArray], {
1386
- MyPrimitive: {
1387
- // @ts-expect-error - fixture is unknown but we know the actual shape
1388
- MyResolvableNumber: (value: number) => value.toString(),
1389
- // @ts-expect-error - fixture is unknown but we know the actual shape
1390
- MyResolvableArray: (value: any[]) => value.join(''),
1391
- },
1392
- }),
1393
- ComponentInputMetaSchema,
1394
- );
1395
-
1396
- expect(
1397
- jsonSchemaService.validateInput(
1398
- { myProperty: propertyValue },
1399
- {
1400
- type: 'object',
1401
- properties: { myProperty: { $ref: '#/definitions/Ref' } },
1402
- definitions: { Ref: { type: 'MyPrimitive' } },
1403
- },
1404
- ),
1405
- ).toEqual(true);
1406
- },
1407
- );
1408
-
1409
- it('should not validate on a primitive type against a resolvable type when a resolver is not defined', () => {
1410
- const primitiveSchema = primitiveTypeFixture('MyPrimitive', { type: 'string' });
1411
- const MyResolvableNumber = resolvableTypeFixture('MyResolvableNumber', { type: 'number' });
1412
- const MyResolvableArray = resolvableTypeFixture('MyResolvableArray', { type: 'array' });
1413
- const jsonSchemaService = new JSONSchemaService(
1414
- new TypeResolver([primitiveSchema], [MyResolvableNumber, MyResolvableArray], {
1415
- MyPrimitive: {
1416
- // @ts-expect-error - fixture is unknown but we know the actual shape
1417
- MyResolvableNumber: (value: number) => value.toString(),
1418
- },
1419
- }),
1420
- ComponentInputMetaSchema,
1421
- );
1422
-
1423
- expect(() => {
1424
- jsonSchemaService.validateInput(
1425
- { myProperty: [123] },
1426
- { type: 'object', properties: { myProperty: { type: 'MyPrimitive' } } },
1427
- );
1428
- }).toThrowError();
1429
- });
1430
-
1431
- it('should validate a primitive type against similar but different resolvable types', () => {
1432
- const primitiveSchema = primitiveTypeFixture('MyPrimitive', { type: 'string' });
1433
- const jsonSchemaService = new JSONSchemaService(
1434
- new TypeResolver(
1435
- [primitiveSchema],
1436
- [
1437
- resolvableTypeFixture('MyResolvableSrcNumber', {
1438
- type: 'object',
1439
- properties: {
1440
- src: { type: 'number' },
1441
- },
1442
- }),
1443
- resolvableTypeFixture('MyResolvableSrcString', {
1444
- type: 'object',
1445
- properties: {
1446
- src: { type: 'string' },
1447
- },
1448
- }),
1449
- ],
1450
- {
1451
- MyPrimitive: {
1452
- // @ts-expect-error - fixture is unknown but we know the actual shape
1453
- MyResolvableSrcNumber: (value: { src: number }) => value.src.toString(),
1454
- // @ts-expect-error - fixture is unknown but we know the actual shape
1455
- MyResolvableSrcString: (value: { src: string }) => value.src,
1456
- },
1457
- },
1458
- ),
1459
- ComponentInputMetaSchema,
1460
- );
1461
-
1462
- expect(
1463
- jsonSchemaService.validateInput(
1464
- {
1465
- myProperty: {
1466
- src: 123,
1467
- },
1468
- },
1469
- { type: 'object', properties: { myProperty: { type: 'MyPrimitive' } } },
1470
- ),
1471
- ).toEqual(true);
1472
- expect(
1473
- jsonSchemaService.validateInput(
1474
- {
1475
- myProperty: {
1476
- src: '123',
1477
- },
1478
- },
1479
- { type: 'object', properties: { myProperty: { type: 'MyPrimitive' } } },
1480
- ),
1481
- ).toEqual(true);
1482
- });
1483
- });
1484
-
1485
- describe('resolveInput', () => {
1486
- it.each([String('123'), Number(123), [123]])(
1487
- 'should resolve a primitive type from its resolvable type %s',
1488
- async (resolvableValue) => {
1489
- const primitiveSchema = primitiveTypeFixture('MyPrimitive', { type: 'string' });
1490
- const jsonSchemaService = new JSONSchemaService(
1491
- new TypeResolver(
1492
- [primitiveSchema],
1493
- [
1494
- resolvableTypeFixture('MyResolvableNumber', { type: 'number' }),
1495
- resolvableTypeFixture('MyResolvableArray', { type: 'array' }),
1496
- ],
1497
- {
1498
- MyPrimitive: {
1499
- // @ts-expect-error - fixture is unknown but we know the actual shape
1500
- MyResolvableNumber: (value: number) => value.toString(),
1501
- // @ts-expect-error - fixture is unknown but we know the actual shape
1502
- MyResolvableArray: (value: any[]) => value.join(''),
1503
- },
1504
- },
1505
- ),
1506
- ComponentInputMetaSchema,
1507
- );
1508
-
1509
- await expect(
1510
- jsonSchemaService.resolveInput(
1511
- { myProperty: resolvableValue },
1512
- { type: 'object', properties: { myProperty: { type: 'MyPrimitive' } } },
1513
- ),
1514
- ).resolves.toEqual({ myProperty: '123' });
1515
- },
1516
- );
1517
-
1518
- it.each([
1519
- [{ src: 'MyString' }, 'MyString'],
1520
- [{ src: 1132 }, '1132'],
1521
- ])('should resolve a resolvable type %s against the correct resolver to %s', async (resolvableValue, output) => {
1522
- const primitiveSchema = primitiveTypeFixture('MyPrimitive', { type: 'string' });
1523
- const jsonSchemaService = new JSONSchemaService(
1524
- new TypeResolver(
1525
- [primitiveSchema],
1526
- [
1527
- resolvableTypeFixture('MyResolvableSrcString', {
1528
- type: 'object',
1529
- properties: { src: { type: 'string' } },
1530
- }),
1531
- resolvableTypeFixture('MyResolvableSrcNumber', {
1532
- type: 'object',
1533
- properties: { src: { type: 'number' } },
1534
- }),
1535
- ],
1536
- {
1537
- MyPrimitive: {
1538
- // @ts-expect-error - fixture is unknown but we know the actual shape
1539
- MyResolvableSrcNumber: (value: { src: number }) => value.src.toString(),
1540
- // @ts-expect-error - fixture is unknown but we know the actual shape
1541
- MyResolvableSrcString: (value: { src: string }) => value.src,
1542
- },
1543
- },
1544
- ),
1545
- ComponentInputMetaSchema,
1546
- );
1547
-
1548
- await expect(
1549
- jsonSchemaService.resolveInput(
1550
- { myProperty: resolvableValue },
1551
- { type: 'object', properties: { myProperty: { type: 'MyPrimitive' } } },
1552
- ),
1553
- ).resolves.toEqual({ myProperty: output });
1554
- });
1555
-
1556
- it('should resolve a primitive type from its resolvable type %s', async () => {
1557
- const primitiveSchema = primitiveTypeFixture('MyPrimitive', { type: 'string' });
1558
- const jsonSchemaService = new JSONSchemaService(
1559
- new TypeResolver([primitiveSchema], [resolvableTypeFixture('MyResolvableWithError', { type: 'number' })], {
1560
- MyPrimitive: {
1561
- // @ts-expect-error - fixture is unknown but we know the actual shape
1562
- MyResolvableWithError: (_value: number) => {
1563
- throw new Error('Failed resolving!!');
1564
- },
1565
- },
1566
- }),
1567
- ComponentInputMetaSchema,
1568
- );
1569
-
1570
- await expect(
1571
- jsonSchemaService.resolveInput(
1572
- { myProperty: 123, myProperty2: 234 },
1573
- { type: 'object', properties: { myProperty: { type: 'MyPrimitive' }, myProperty2: { type: 'MyPrimitive' } } },
1574
- ),
1575
- ).rejects.toThrowErrorMatchingInlineSnapshot(`
1576
- "Error(s) occurred when resolving JSON:
1577
- Error: Error resolving JSON at #/myProperty: Failed resolving!!
1578
- Error: Error resolving JSON at #/myProperty2: Failed resolving!!"
1579
- `);
1580
- });
1581
-
1582
- it('should resolve a FormattedText empty list', async () => {
1583
- const types = TypeResolverBuilder.new().addPrimitive(FormattedTextType).build();
1584
- const jsonSchemaService = new JSONSchemaService(types, ComponentInputMetaSchema);
1585
-
1586
- await expect(
1587
- jsonSchemaService.resolveInput(
1588
- { myProp: [] },
1589
- { type: 'object', properties: { myProp: { type: 'FormattedText' } }, required: [] },
1590
- ),
1591
- ).resolves.toEqual({ myProp: [] });
1592
- });
1593
- });
1594
- });
1595
-
1596
- describe('JSONSchemaService - validation', () => {
1597
- const typeResolver = TypeResolverBuilder.new()
1598
- .addPrimitive(SquizImageType)
1599
- .addPrimitive(SquizLinkType)
1600
- .addPrimitive(FormattedTextType)
1601
- .build();
1602
-
1603
- const jsonSchemaService = new JSONSchemaService(typeResolver, ComponentInputMetaSchema);
1604
-
1605
- it('should validate a schema with all the squiz primitive types', () => {
1606
- const schema = {
1607
- type: 'object',
1608
- properties: {
1609
- image: { type: 'SquizImage' },
1610
- link: { type: 'SquizLink' },
1611
- text: { type: 'FormattedText' },
1612
- },
1613
- required: ['image', 'link', 'text'],
1614
- };
1615
- const formattedText: FormattedText = [
1616
- {
1617
- tag: 'p',
1618
- type: 'tag',
1619
- children: [{ type: 'text', value: 'hello' }],
1620
- },
1621
- ];
1622
- const input: {
1623
- image: SquizImageType['__shape__'];
1624
- link: SquizLinkType['__shape__'];
1625
- text: FormattedText;
1626
- } = {
1627
- image: {
1628
- name: 'test-image.jpeg',
1629
- imageVariations: {
1630
- original: {
1631
- aspectRatio: '1:1',
1632
- height: 100,
1633
- width: 100,
1634
- url: 'https://www.squiz.net',
1635
- byteSize: 100,
1636
- mimeType: 'image/jpeg',
1637
- sha1Hash: '123',
1638
- },
1639
- },
1640
- },
1641
- link: {
1642
- text: 'test-link',
1643
- url: 'https://www.squiz.net',
1644
- target: '_blank',
1645
- },
1646
- text: formattedText,
1647
- };
1648
-
1649
- const result = jsonSchemaService.validateInput(input, schema);
1650
-
1651
- expect(result).toEqual(true);
1652
- });
1653
-
1654
- it('should validate a schema with all the squiz primitive types and matrix-asset-uri format', () => {
1655
- const schema = {
1656
- type: 'object',
1657
- properties: {
1658
- image: { type: 'SquizImage' },
1659
- link: { type: 'SquizLink' },
1660
- text: { type: 'FormattedText' },
1661
- asset: {
1662
- type: 'string',
1663
- format: 'matrix-asset-uri',
1664
- },
1665
- },
1666
- required: ['image', 'link', 'text', 'asset'],
1667
- };
1668
- const formattedText: FormattedText = [
1669
- {
1670
- tag: 'p',
1671
- type: 'tag',
1672
- children: [{ type: 'text', value: 'hello' }],
1673
- },
1674
- ];
1675
- const input: {
1676
- image: SquizImageType['__shape__'];
1677
- link: SquizLinkType['__shape__'];
1678
- text: FormattedText;
1679
- asset: MatrixAssetUri;
1680
- } = {
1681
- image: {
1682
- name: 'test-image.jpeg',
1683
- imageVariations: {
1684
- original: {
1685
- aspectRatio: '1:1',
1686
- height: 100,
1687
- width: 100,
1688
- url: 'https://www.squiz.net',
1689
- byteSize: 100,
1690
- mimeType: 'image/jpeg',
1691
- sha1Hash: '123',
1692
- },
1693
- },
1694
- },
1695
- link: {
1696
- text: 'test-link',
1697
- url: 'https://www.squiz.net',
1698
- target: '_blank',
1699
- },
1700
- text: formattedText,
1701
- asset: 'matrix-asset://identifier/123',
1702
- };
1703
-
1704
- const result = jsonSchemaService.validateInput(input, schema);
1705
-
1706
- expect(result).toEqual(true);
1707
- });
1708
-
1709
- it('should catch validation errors when there is a schema with all the squiz primitive types', () => {
1710
- const schema = {
1711
- type: 'object',
1712
- properties: {
1713
- image: { type: 'SquizImage' },
1714
- link: { type: 'SquizLink' },
1715
- text: { type: 'FormattedText' },
1716
- },
1717
- required: ['image', 'link', 'text'],
1718
- };
1719
- const formattedText: FormattedText = [
1720
- //@ts-expect-error - wrong type
1721
- {
1722
- children: [{ type: 'text', value: 'hello' }],
1723
- },
1724
- ];
1725
- const input: {
1726
- image: SquizImageType['__shape__'];
1727
- link: SquizLinkType['__shape__'];
1728
- text: FormattedText;
1729
- } = {
1730
- image: {
1731
- name: 'test-image.jpeg',
1732
- imageVariations: {
1733
- //@ts-expect-error - wrong type
1734
- original: {
1735
- width: 100,
1736
- url: 'https://www.squiz.net',
1737
- byteSize: 100,
1738
- mimeType: 'image/jpeg',
1739
- sha1Hash: '123',
1740
- },
1741
- },
1742
- },
1743
- //@ts-expect-error - wrong type
1744
- link: {
1745
- text: 'test-link',
1746
- target: '_blank',
1747
- },
1748
- text: formattedText,
1749
- };
1750
-
1751
- expectToThrowErrorMatchingTypeAndMessage(
1752
- () => jsonSchemaService.validateInput(input, schema),
1753
- SchemaValidationError,
1754
- 'failed validation: Value `{"name":"test-image.jpeg","imageVariations":{"original":{"width":100,"url":"https://www.squiz.net","byteSize":100,"mimeType":"image/jpeg","sha1Hash":"123"}}}` in `#/image` does not match any given oneof schema,\nValue `{"text":"test-link","target":"_blank"}` in `#/link` does not match any given oneof schema,\nValue `[{"children":[{"type":"text","value":"hello"}]}]` in `#/text` does not match any given oneof schema',
1755
- {
1756
- '#/image': [
1757
- {
1758
- data: {
1759
- errors: [
1760
- {
1761
- code: 'required-property-error',
1762
- data: { key: 'height', pointer: '#/image/imageVariations/original' },
1763
- message: 'The required property `height` is missing at `#/image/imageVariations/original`',
1764
- name: 'RequiredPropertyError',
1765
- type: 'error',
1766
- },
1767
- {
1768
- code: 'required-property-error',
1769
- data: { key: 'aspectRatio', pointer: '#/image/imageVariations/original' },
1770
- message: 'The required property `aspectRatio` is missing at `#/image/imageVariations/original`',
1771
- name: 'RequiredPropertyError',
1772
- type: 'error',
1773
- },
1774
- ],
1775
- oneOf: [{ $ref: 'SquizImage.json' }],
1776
- pointer: '#/image',
1777
- value:
1778
- '{"name":"test-image.jpeg","imageVariations":{"original":{"width":100,"url":"https://www.squiz.net","byteSize":100,"mimeType":"image/jpeg","sha1Hash":"123"}}}',
1779
- },
1780
- message:
1781
- 'Value `{"name":"test-image.jpeg","imageVariations":{"original":{"width":100,"url":"https://www.squiz.net","byteSize":100,"mimeType":"image/jpeg","sha1Hash":"123"}}}` in `#/image` does not match any given oneof schema',
1782
- },
1783
- ],
1784
- '#/link': [
1785
- {
1786
- data: {
1787
- errors: [
1788
- {
1789
- code: 'required-property-error',
1790
- data: { key: 'url', pointer: '#/link' },
1791
- message: 'The required property `url` is missing at `#/link`',
1792
- name: 'RequiredPropertyError',
1793
- type: 'error',
1794
- },
1795
- ],
1796
- oneOf: [{ $ref: 'SquizLink.json' }],
1797
- pointer: '#/link',
1798
- value: '{"text":"test-link","target":"_blank"}',
1799
- },
1800
- message: 'Value `{"text":"test-link","target":"_blank"}` in `#/link` does not match any given oneof schema',
1801
- },
1802
- ],
1803
- '#/text': [
1804
- {
1805
- data: {
1806
- errors: [
1807
- {
1808
- code: 'any-of-error',
1809
- data: {
1810
- anyOf: [
1811
- { $ref: '#/definitions/HigherOrderFormattedNodes' },
1812
- { $ref: '#/definitions/BaseFormattedNodes' },
1813
- ],
1814
- pointer: '#/text/0',
1815
- value: { children: [{ type: 'text', value: 'hello' }] },
1816
- },
1817
- message: 'Object at `#/text/0` does not match any schema',
1818
- name: 'AnyOfError',
1819
- type: 'error',
1820
- },
1821
- ],
1822
- oneOf: [{ $ref: 'FormattedText.json' }],
1823
- pointer: '#/text',
1824
- value: '[{"children":[{"type":"text","value":"hello"}]}]',
1825
- },
1826
- message:
1827
- 'Value `[{"children":[{"type":"text","value":"hello"}]}]` in `#/text` does not match any given oneof schema',
1828
- },
1829
- ],
1830
- },
1831
- );
1832
- });
1833
-
1834
- it('should catch validation errors when invalid matrix-asset-uri is provided with invalid other squiz primitive types ', () => {
1835
- const schema = {
1836
- type: 'object',
1837
- properties: {
1838
- image: { type: 'SquizImage' },
1839
- link: { type: 'SquizLink' },
1840
- text: { type: 'FormattedText' },
1841
- asset: {
1842
- type: 'string',
1843
- format: 'matrix-asset-uri',
1844
- },
1845
- },
1846
-
1847
- required: ['image', 'link', 'text', 'asset'],
1848
- };
1849
- const formattedText: FormattedText = [
1850
- //@ts-expect-error - wrong type
1851
- {
1852
- children: [{ type: 'text', value: 'hello' }],
1853
- },
1854
- ];
1855
- const input: {
1856
- image: SquizImageType['__shape__'];
1857
- link: SquizLinkType['__shape__'];
1858
- text: FormattedText;
1859
- asset: MatrixAssetUri;
1860
- } = {
1861
- image: {
1862
- name: 'test-image.jpeg',
1863
- imageVariations: {
1864
- //@ts-expect-error - wrong type
1865
- original: {
1866
- width: 100,
1867
- url: 'https://www.squiz.net',
1868
- byteSize: 100,
1869
- mimeType: 'image/jpeg',
1870
- sha1Hash: '123',
1871
- },
1872
- },
1873
- },
1874
- //@ts-expect-error - wrong type
1875
- link: {
1876
- text: 'test-link',
1877
- target: '_blank',
1878
- },
1879
- text: formattedText,
1880
- // @ts-expect-error - wrong type
1881
- asset: 'matrix://123',
1882
- };
1883
-
1884
- expectToThrowErrorMatchingTypeAndMessage(
1885
- () => jsonSchemaService.validateInput(input, schema),
1886
- SchemaValidationError,
1887
- 'failed validation: Value `{"name":"test-image.jpeg","imageVariations":{"original":{"width":100,"url":"https://www.squiz.net","byteSize":100,"mimeType":"image/jpeg","sha1Hash":"123"}}}` in `#/image` does not match any given oneof schema,\nValue `{"text":"test-link","target":"_blank"}` in `#/link` does not match any given oneof schema,\nValue `[{"children":[{"type":"text","value":"hello"}]}]` in `#/text` does not match any given oneof schema,\nValue matrix-asset-uri (matrix://123) in `#/asset` is not a valid matrix asset uri',
1888
- {
1889
- '#/asset': [
1890
- {
1891
- data: {
1892
- errors: {
1893
- assetId: {
1894
- data: { expected: /^\d+(?::.+)?$/, received: '' },
1895
- message: 'Matrix Asset Id has invalid format, must match /^d+(?::.+)?$/',
1896
- },
1897
- scheme: {
1898
- data: { expected: 'matrix-asset', received: 'matrix' },
1899
- message: 'Uri scheme is invalid, must match "matrix-asset"',
1900
- },
1901
- },
1902
- pointer: '#/asset',
1903
- value: 'matrix://123',
1904
- },
1905
- message: 'Value matrix-asset-uri (matrix://123) in `#/asset` is not a valid matrix asset uri',
1906
- },
1907
- ],
1908
- '#/image': [
1909
- {
1910
- data: {
1911
- errors: [
1912
- {
1913
- code: 'required-property-error',
1914
- data: { key: 'height', pointer: '#/image/imageVariations/original' },
1915
- message: 'The required property `height` is missing at `#/image/imageVariations/original`',
1916
- name: 'RequiredPropertyError',
1917
- type: 'error',
1918
- },
1919
- {
1920
- code: 'required-property-error',
1921
- data: { key: 'aspectRatio', pointer: '#/image/imageVariations/original' },
1922
- message: 'The required property `aspectRatio` is missing at `#/image/imageVariations/original`',
1923
- name: 'RequiredPropertyError',
1924
- type: 'error',
1925
- },
1926
- ],
1927
- oneOf: [{ $ref: 'SquizImage.json' }],
1928
- pointer: '#/image',
1929
- value:
1930
- '{"name":"test-image.jpeg","imageVariations":{"original":{"width":100,"url":"https://www.squiz.net","byteSize":100,"mimeType":"image/jpeg","sha1Hash":"123"}}}',
1931
- },
1932
- message:
1933
- 'Value `{"name":"test-image.jpeg","imageVariations":{"original":{"width":100,"url":"https://www.squiz.net","byteSize":100,"mimeType":"image/jpeg","sha1Hash":"123"}}}` in `#/image` does not match any given oneof schema',
1934
- },
1935
- ],
1936
- '#/link': [
1937
- {
1938
- data: {
1939
- errors: [
1940
- {
1941
- code: 'required-property-error',
1942
- data: { key: 'url', pointer: '#/link' },
1943
- message: 'The required property `url` is missing at `#/link`',
1944
- name: 'RequiredPropertyError',
1945
- type: 'error',
1946
- },
1947
- ],
1948
- oneOf: [{ $ref: 'SquizLink.json' }],
1949
- pointer: '#/link',
1950
- value: '{"text":"test-link","target":"_blank"}',
1951
- },
1952
- message: 'Value `{"text":"test-link","target":"_blank"}` in `#/link` does not match any given oneof schema',
1953
- },
1954
- ],
1955
- '#/text': [
1956
- {
1957
- data: {
1958
- errors: [
1959
- {
1960
- code: 'any-of-error',
1961
- data: {
1962
- anyOf: [
1963
- { $ref: '#/definitions/HigherOrderFormattedNodes' },
1964
- { $ref: '#/definitions/BaseFormattedNodes' },
1965
- ],
1966
- pointer: '#/text/0',
1967
- value: { children: [{ type: 'text', value: 'hello' }] },
1968
- },
1969
- message: 'Object at `#/text/0` does not match any schema',
1970
- name: 'AnyOfError',
1971
- type: 'error',
1972
- },
1973
- ],
1974
- oneOf: [{ $ref: 'FormattedText.json' }],
1975
- pointer: '#/text',
1976
- value: '[{"children":[{"type":"text","value":"hello"}]}]',
1977
- },
1978
- message:
1979
- 'Value `[{"children":[{"type":"text","value":"hello"}]}]` in `#/text` does not match any given oneof schema',
1980
- },
1981
- ],
1982
- },
1983
- );
1984
- });
1985
-
1986
- it('should validate when MatrixAssetType is being used for a squiz primitive type with resolver', () => {
1987
- const typeResolver = TypeResolverBuilder.new()
1988
- .addPrimitive(SquizImageType)
1989
- .addPrimitive(SquizLinkType)
1990
- .addPrimitive(FormattedTextType)
1991
- .addResolver(SquizImageType, MatrixAssetType, (): SquizImageType['__shape__'] => {
1992
- return {
1993
- name: '',
1994
- imageVariations: {
1995
- original: {
1996
- width: 0,
1997
- height: 0,
1998
- url: '',
1999
- mimeType: '',
2000
- byteSize: 0,
2001
- sha1Hash: '',
2002
- aspectRatio: '',
2003
- },
2004
- },
2005
- };
2006
- })
2007
- .build();
2008
-
2009
- const jsonSchemaService = new JSONSchemaService(typeResolver, ComponentInputMetaSchema);
2010
- const schema = {
2011
- type: 'object',
2012
- properties: {
2013
- image: { type: 'SquizImage' },
2014
- link: { type: 'SquizLink' },
2015
- text: { type: 'FormattedText' },
2016
- asset: {
2017
- type: 'string',
2018
- format: 'matrix-asset-uri',
2019
- },
2020
- },
2021
- required: ['image', 'link', 'text', 'asset'],
2022
- };
2023
- const formattedText: FormattedText = [
2024
- {
2025
- tag: 'p',
2026
- type: 'tag',
2027
- children: [{ type: 'text', value: 'hello' }],
2028
- },
2029
- ];
2030
- const input: {
2031
- image: MatrixAssetType['__shape__'];
2032
- link: SquizLinkType['__shape__'];
2033
- text: FormattedText;
2034
- asset: MatrixAssetUri;
2035
- } = {
2036
- image: {
2037
- matrixAssetId: '123',
2038
- matrixIdentifier: 'identifier',
2039
- matrixDomain: 'domain',
2040
- },
2041
- link: {
2042
- text: 'test-link',
2043
- url: 'https://www.squiz.net',
2044
- target: '_blank',
2045
- },
2046
- text: formattedText,
2047
- asset: 'matrix-asset://identifier/123',
2048
- };
2049
-
2050
- expect(jsonSchemaService.validateInput(input, schema)).toEqual(true);
2051
- });
2052
-
2053
- it('it should catch MatrixAssetType validation errors when being use for squiz primitive type with resolver', () => {
2054
- const typeResolver = TypeResolverBuilder.new()
2055
- .addPrimitive(SquizImageType)
2056
- .addPrimitive(SquizLinkType)
2057
- .addPrimitive(FormattedTextType)
2058
- .addResolver(SquizImageType, MatrixAssetType, (): SquizImageType['__shape__'] => {
2059
- return {
2060
- name: '',
2061
- imageVariations: {
2062
- original: {
2063
- width: 0,
2064
- height: 0,
2065
- url: '',
2066
- mimeType: '',
2067
- byteSize: 0,
2068
- sha1Hash: '',
2069
- aspectRatio: '',
2070
- },
2071
- },
2072
- };
2073
- })
2074
- .build();
2075
-
2076
- const jsonSchemaService = new JSONSchemaService(typeResolver, ComponentInputMetaSchema);
2077
- const schema = {
2078
- type: 'object',
2079
- properties: {
2080
- image: { type: 'SquizImage' },
2081
- },
2082
- required: ['image'],
2083
- };
2084
- const input: {
2085
- image: MatrixAssetType['__shape__'];
2086
- } = {
2087
- //@ts-expect-error - intentionally invalid input
2088
- image: {
2089
- matrixIdentifier: 'identifier',
2090
- },
2091
- };
2092
- expectToThrowErrorMatchingTypeAndMessage(
2093
- () => jsonSchemaService.validateInput(input, schema),
2094
- SchemaValidationError,
2095
- 'failed validation: Value `{"matrixIdentifier":"identifier"}` in `#/image` does not match any given oneof schema',
2096
- {
2097
- '#/image': [
2098
- {
2099
- data: {
2100
- errors: [
2101
- {
2102
- code: 'required-property-error',
2103
- data: { key: 'name', pointer: '#/image' },
2104
- message: 'The required property `name` is missing at `#/image`',
2105
- name: 'RequiredPropertyError',
2106
- type: 'error',
2107
- },
2108
- {
2109
- code: 'required-property-error',
2110
- data: { key: 'imageVariations', pointer: '#/image' },
2111
- message: 'The required property `imageVariations` is missing at `#/image`',
2112
- name: 'RequiredPropertyError',
2113
- type: 'error',
2114
- },
2115
- {
2116
- code: 'required-property-error',
2117
- data: { key: 'matrixAssetId', pointer: '#/image' },
2118
- message: 'The required property `matrixAssetId` is missing at `#/image`',
2119
- name: 'RequiredPropertyError',
2120
- type: 'error',
2121
- },
2122
- ],
2123
- oneOf: [{ $ref: 'SquizImage.json' }, { $ref: 'MatrixAsset.json' }],
2124
- pointer: '#/image',
2125
- value: '{"matrixIdentifier":"identifier"}',
2126
- },
2127
- message: 'Value `{"matrixIdentifier":"identifier"}` in `#/image` does not match any given oneof schema',
2128
- },
2129
- ],
2130
- },
2131
- );
2132
- });
2133
-
2134
- it('should only resolve an array of items containing resolvable types, other arrays are unaffected', async () => {
2135
- const typeResolver = TypeResolverBuilder.new()
2136
- .addPrimitive(SquizImageType)
2137
- .addPrimitive(SquizLinkType)
2138
- .addPrimitive(FormattedTextType)
2139
- .addResolver(SquizImageType, MatrixAssetType, (): SquizImageType['__shape__'] => {
2140
- return {
2141
- name: '',
2142
- imageVariations: {
2143
- original: {
2144
- width: 0,
2145
- height: 0,
2146
- url: '',
2147
- mimeType: '',
2148
- byteSize: 0,
2149
- sha1Hash: '',
2150
- aspectRatio: '',
2151
- },
2152
- },
2153
- };
2154
- })
2155
- .addResolver(SquizLinkType, MatrixAssetLinkType, (): SquizLinkType['__shape__'] => {
2156
- return {
2157
- text: 'link text',
2158
- url: 'www.test.com',
2159
- target: '_self',
2160
- };
2161
- })
2162
- .build();
2163
-
2164
- const jsonSchemaService = new JSONSchemaService(typeResolver, ComponentInputMetaSchema);
2165
-
2166
- const schema = {
2167
- type: 'object',
2168
- properties: {
2169
- images: {
2170
- description: 'Gallery images',
2171
- type: 'array',
2172
- items: {
2173
- type: 'SquizImage',
2174
- },
2175
- },
2176
- squizLink: {
2177
- title: 'Squiz link',
2178
- type: 'array',
2179
- items: {
2180
- type: 'SquizLink',
2181
- },
2182
- },
2183
- //custom format
2184
- multiLine: {
2185
- title: 'Multi-line (textarea)',
2186
- type: 'array',
2187
- items: {
2188
- type: 'string',
2189
- format: 'multi-line',
2190
- },
2191
- },
2192
- //string array
2193
- listOfStrings: {
2194
- type: 'array',
2195
- title: 'A list of strings',
2196
- items: {
2197
- type: 'string',
2198
- default: 'Holy smokes',
2199
- },
2200
- },
2201
- },
2202
- required: ['images', 'links'],
2203
- };
2204
-
2205
- const input: {
2206
- images: Array<MatrixAssetType['__shape__']>;
2207
- squizLink: Array<MatrixAssetLinkType['__shape__']>;
2208
- multiline: Array<string>;
2209
- listOfStrings: Array<string>;
2210
- } = {
2211
- images: [
2212
- {
2213
- matrixDomain: 'https://feaas-page-render-us.dev.matrix.squiz.cloud/59',
2214
- matrixAssetId: '160',
2215
- matrixIdentifier: 'feaas-matrix-us',
2216
- },
2217
- ],
2218
- squizLink: [
2219
- {
2220
- matrixDomain: 'https://feaas-page-render-us.dev.matrix.squiz.cloud/59',
2221
- matrixAssetId: '160',
2222
- matrixIdentifier: 'feaas-matrix-us',
2223
- target: '_self',
2224
- },
2225
- ],
2226
- multiline: ['wow', 'much', 'multiline'],
2227
- listOfStrings: ['very', 'string'],
2228
- };
2229
- const result = await jsonSchemaService.resolveInput(input, schema);
2230
- expect(result).toEqual({
2231
- images: [
2232
- {
2233
- imageVariations: {
2234
- original: { aspectRatio: '', byteSize: 0, height: 0, mimeType: '', sha1Hash: '', url: '', width: 0 },
2235
- },
2236
- name: '',
2237
- },
2238
- ],
2239
- squizLink: [
2240
- {
2241
- text: 'link text',
2242
- url: 'www.test.com',
2243
- target: '_self',
2244
- },
2245
- ],
2246
- multiline: ['wow', 'much', 'multiline'],
2247
- listOfStrings: ['very', 'string'],
2248
- });
2249
- });
2250
-
2251
- it('should resolve multiple primitive type array items in multi-level nested array structures', async () => {
2252
- const typeResolver = TypeResolverBuilder.new()
2253
- .addPrimitive(SquizLinkType)
2254
- .addResolver(
2255
- SquizLinkType,
2256
- MatrixAssetLinkType,
2257
- (input: MatrixAssetLinkType['__shape__']): SquizLinkType['__shape__'] => {
2258
- if ('matrixIdentifier' in input) {
2259
- return {
2260
- text: 'link text',
2261
- url: `www.test.com/asset/${input.matrixAssetId}`,
2262
- target: input.target,
2263
- };
2264
- }
2265
-
2266
- return input;
2267
- },
2268
- )
2269
- .build();
2270
-
2271
- const jsonSchemaService = new JSONSchemaService(typeResolver, ComponentInputMetaSchema);
2272
-
2273
- const schema = {
2274
- type: 'object',
2275
- properties: {
2276
- object1: {
2277
- type: 'object',
2278
- required: [],
2279
- properties: {
2280
- array1: {
2281
- type: 'array',
2282
- items: {
2283
- type: 'object',
2284
- properties: {
2285
- linksArray: {
2286
- type: 'array',
2287
- items: {
2288
- type: 'SquizLink',
2289
- },
2290
- },
2291
- },
2292
- },
2293
- },
2294
- },
2295
- },
2296
- },
2297
- };
2298
-
2299
- const input: {
2300
- object1: {
2301
- array1: Array<{
2302
- linksArray: Array<SquizLinkType['__shape__'] | MatrixAssetLinkType['__shape__']>;
2303
- }>;
2304
- };
2305
- } = {
2306
- object1: {
2307
- array1: [
2308
- {
2309
- linksArray: [
2310
- {
2311
- url: '#LineOne',
2312
- text: 'Link One',
2313
- target: '_blank',
2314
- },
2315
- {
2316
- url: '#LineTwo',
2317
- text: 'Link Two',
2318
- target: '_blank',
2319
- },
2320
- {
2321
- matrixAssetId: '100',
2322
- matrixDomain: 'my-matrix.squiz.net',
2323
- matrixIdentifier: 'my-matrix-identifier',
2324
- target: '_blank',
2325
- },
2326
- ],
2327
- },
2328
- ],
2329
- },
2330
- };
2331
- const result = await jsonSchemaService.resolveInput(input, schema);
2332
- expect(result).toEqual({
2333
- object1: {
2334
- array1: [
2335
- {
2336
- linksArray: [
2337
- {
2338
- url: '#LineOne',
2339
- text: 'Link One',
2340
- target: '_blank',
2341
- },
2342
- {
2343
- url: '#LineTwo',
2344
- text: 'Link Two',
2345
- target: '_blank',
2346
- },
2347
- {
2348
- url: 'www.test.com/asset/100',
2349
- text: 'link text',
2350
- target: '_blank',
2351
- },
2352
- ],
2353
- },
2354
- ],
2355
- },
2356
- });
2357
- });
2358
-
2359
- it('should not use the resolver for primitive items in a resolvable array', async () => {
2360
- const mockMatrixAssetResolver = jest.fn((input: MatrixAssetType['__shape__']) => {
2361
- return {
2362
- name: input.matrixAssetId,
2363
- imageVariations: {
2364
- original: {
2365
- width: 0,
2366
- height: 0,
2367
- url: '',
2368
- mimeType: '',
2369
- byteSize: 0,
2370
- sha1Hash: '',
2371
- aspectRatio: '',
2372
- },
2373
- },
2374
- };
2375
- });
2376
- const mockMatrixLinkResolver = jest.fn((input: MatrixAssetLinkType['__shape__']): SquizLinkType['__shape__'] => {
2377
- return {
2378
- text: input.matrixAssetId,
2379
- url: 'www.test.com',
2380
- target: '_self',
2381
- };
2382
- });
2383
- const typeResolver = TypeResolverBuilder.new()
2384
- .addPrimitive(SquizImageType)
2385
- .addPrimitive(SquizLinkType)
2386
- .addPrimitive(FormattedTextType)
2387
- .addResolver(SquizImageType, MatrixAssetType, mockMatrixAssetResolver)
2388
- .addResolver(SquizLinkType, MatrixAssetLinkType, mockMatrixLinkResolver)
2389
- .build();
2390
-
2391
- const jsonSchemaService = new JSONSchemaService(typeResolver, ComponentInputMetaSchema);
2392
-
2393
- const schema = {
2394
- type: 'object',
2395
- properties: {
2396
- images: {
2397
- description: 'Gallery images',
2398
- type: 'array',
2399
- items: {
2400
- type: 'SquizImage',
2401
- },
2402
- },
2403
- squizLink: {
2404
- title: 'Squiz link',
2405
- type: 'array',
2406
- items: {
2407
- type: 'SquizLink',
2408
- },
2409
- },
2410
- //custom format
2411
- multiLine: {
2412
- title: 'Multi-line (textarea)',
2413
- type: 'array',
2414
- items: {
2415
- type: 'string',
2416
- format: 'multi-line',
2417
- },
2418
- },
2419
- //string array
2420
- listOfStrings: {
2421
- type: 'array',
2422
- title: 'A list of strings',
2423
- items: {
2424
- type: 'string',
2425
- default: 'Holy smokes',
2426
- },
2427
- },
2428
- },
2429
- required: ['images', 'links'],
2430
- };
2431
-
2432
- const input: {
2433
- images: Array<MatrixAssetType['__shape__'] | SquizImageType['__shape__']>;
2434
- squizLink: Array<MatrixAssetLinkType['__shape__'] | SquizLinkType['__shape__']>;
2435
- multiline: Array<string>;
2436
- listOfStrings: Array<string>;
2437
- } = {
2438
- images: [
2439
- {
2440
- matrixDomain: 'https://feaas-page-render-us.dev.matrix.squiz.cloud/59',
2441
- matrixAssetId: '160',
2442
- matrixIdentifier: 'feaas-matrix-us',
2443
- },
2444
- {
2445
- imageVariations: {
2446
- original: { aspectRatio: '', byteSize: 0, height: 0, mimeType: '', sha1Hash: '', url: '', width: 0 },
2447
- },
2448
- name: '',
2449
- },
2450
- ],
2451
- squizLink: [
2452
- {
2453
- matrixDomain: 'https://feaas-page-render-us.dev.matrix.squiz.cloud/59',
2454
- matrixAssetId: '160',
2455
- matrixIdentifier: 'feaas-matrix-us',
2456
- target: '_self',
2457
- },
2458
- {
2459
- text: 'link text',
2460
- url: 'www.test.com',
2461
- target: '_self',
2462
- },
2463
- ],
2464
- multiline: ['wow', 'much', 'multiline'],
2465
- listOfStrings: ['very', 'string'],
2466
- };
2467
- const result = await jsonSchemaService.resolveInput(input, schema);
2468
- expect(result).toEqual({
2469
- images: [
2470
- {
2471
- imageVariations: {
2472
- original: { aspectRatio: '', byteSize: 0, height: 0, mimeType: '', sha1Hash: '', url: '', width: 0 },
2473
- },
2474
- name: (input.images[0] as MatrixAssetType['__shape__']).matrixAssetId,
2475
- },
2476
- {
2477
- imageVariations: {
2478
- original: { aspectRatio: '', byteSize: 0, height: 0, mimeType: '', sha1Hash: '', url: '', width: 0 },
2479
- },
2480
- name: '',
2481
- },
2482
- ],
2483
- squizLink: [
2484
- {
2485
- text: (input.squizLink[0] as MatrixAssetLinkType['__shape__']).matrixAssetId,
2486
- url: 'www.test.com',
2487
- target: '_self',
2488
- },
2489
- {
2490
- text: 'link text',
2491
- url: 'www.test.com',
2492
- target: '_self',
2493
- },
2494
- ],
2495
- multiline: ['wow', 'much', 'multiline'],
2496
- listOfStrings: ['very', 'string'],
2497
- });
2498
-
2499
- expect(mockMatrixAssetResolver).toHaveBeenCalledTimes(1);
2500
- expect(mockMatrixLinkResolver).toHaveBeenCalledTimes(1);
2501
- });
2502
- });