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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. package/CHANGELOG.md +12 -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 +4 -2
  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/primitiveTypes/SquizImage.d.ts +2 -1
  31. package/lib/primitiveTypes/SquizImage.js.map +1 -1
  32. package/lib/processValidationResult.d.ts +2 -0
  33. package/lib/processValidationResult.js +24 -0
  34. package/lib/processValidationResult.js.map +1 -0
  35. package/lib/validators/customKeywordValidators.d.ts +2 -0
  36. package/lib/validators/customKeywordValidators.js +47 -0
  37. package/lib/validators/customKeywordValidators.js.map +1 -0
  38. package/lib/validators/customKeywordValidators.spec.d.ts +1 -0
  39. package/lib/validators/customKeywordValidators.spec.js +100 -0
  40. package/lib/validators/customKeywordValidators.spec.js.map +1 -0
  41. package/package.json +2 -5
  42. package/src/JsonSchemaService.spec.ts +2198 -0
  43. package/src/JsonSchemaService.ts +159 -0
  44. package/src/JsonValidationService.spec.ts +26 -2195
  45. package/src/JsonValidationService.ts +64 -226
  46. package/src/index.ts +1 -0
  47. package/src/jsonTypeResolution/TypeResolver.spec.ts +12 -0
  48. package/src/jsonTypeResolution/TypeResolver.ts +5 -5
  49. package/src/manifest/v1/DxComponentInputSchema.spec.ts +21 -0
  50. package/src/manifest/v1/DxContentMetaSchema.json +24 -32
  51. package/src/manifest/v1/JobV1.ts +23 -23
  52. package/src/manifest/v1/__test__/schemas/invalidUiMetadata.json +31 -0
  53. package/src/manifest/v1/v1.spec.ts +3 -73
  54. package/src/manifest/v1/v1.ts +23 -23
  55. package/src/primitiveTypes/SquizImage.ts +2 -1
  56. package/src/processValidationResult.ts +20 -0
  57. package/src/validators/customKeywordValidators.spec.ts +171 -0
  58. package/src/validators/customKeywordValidators.ts +53 -0
  59. 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
- });