@squiz/dx-json-schema-lib 1.33.1-alpha.4 → 1.33.1-alpha.5
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.
- package/.npm/_logs/{2023-05-12T02_45_11_782Z-debug-0.log → 2023-05-12T05_00_21_808Z-debug-0.log} +11 -11
- package/lib/JsonValidationService.d.ts +0 -2
- package/lib/JsonValidationService.js +40 -29
- package/lib/JsonValidationService.js.map +1 -1
- package/lib/JsonValidationService.spec.js +262 -16
- package/lib/JsonValidationService.spec.js.map +1 -1
- package/lib/validators/customFormatValidators.js +5 -1
- package/lib/validators/customFormatValidators.js.map +1 -1
- package/lib/validators/utils/getValidationDataForMatrixUri.d.ts +8 -0
- package/lib/validators/utils/getValidationDataForMatrixUri.js +51 -0
- package/lib/validators/utils/getValidationDataForMatrixUri.js.map +1 -0
- package/lib/validators/utils/getValidationDataForMatrixUri.spec.d.ts +1 -0
- package/lib/validators/utils/getValidationDataForMatrixUri.spec.js +91 -0
- package/lib/validators/utils/getValidationDataForMatrixUri.spec.js.map +1 -0
- package/package.json +2 -2
- package/src/JsonValidationService.spec.ts +280 -7
- package/src/JsonValidationService.ts +43 -29
- package/src/validators/customFormatValidators.ts +8 -1
- package/src/validators/utils/getValidationDataForMatrixUri.spec.ts +92 -0
- package/src/validators/utils/getValidationDataForMatrixUri.ts +55 -0
- package/tsconfig.tsbuildinfo +1 -1
@@ -13,7 +13,7 @@ import {
|
|
13
13
|
ResolvableType,
|
14
14
|
TypeResolver,
|
15
15
|
} from './jsonTypeResolution/TypeResolver';
|
16
|
-
import { FormattedTextType } from './primitiveTypes';
|
16
|
+
import { FormattedTextType, SquizImageType } from './primitiveTypes';
|
17
17
|
|
18
18
|
function expectToThrowErrorMatchingTypeAndMessage(
|
19
19
|
// eslint-disable-next-line @typescript-eslint/ban-types
|
@@ -145,7 +145,7 @@ describe('JsonValidationService', () => {
|
|
145
145
|
).toEqual(true);
|
146
146
|
});
|
147
147
|
it('should throw error for invalid matrix-asset-uri format', () => {
|
148
|
-
const invalidMatrixAssetUri = 'not-valid://canary
|
148
|
+
const invalidMatrixAssetUri = 'not-valid://canary uat matrix.squiz.cloud//abc123';
|
149
149
|
expectToThrowErrorMatchingTypeAndMessage(
|
150
150
|
() => {
|
151
151
|
jsonValidationService.validateRenderInput(functionInputSchema, {
|
@@ -153,8 +153,21 @@ describe('JsonValidationService', () => {
|
|
153
153
|
});
|
154
154
|
},
|
155
155
|
SchemaValidationError,
|
156
|
-
`failed validation:
|
157
|
-
|
156
|
+
`failed validation: matrix asset uri "not-valid://canary uat matrix.squiz.cloud//abc123" isn't a valid matrix asset uri`,
|
157
|
+
{
|
158
|
+
assetId: {
|
159
|
+
data: { expected: /^\d+(?::.+)?$/, received: '/abc123' },
|
160
|
+
message: 'Matrix Asset Id has invalid format, must match /^d+(?::.+)?$/',
|
161
|
+
},
|
162
|
+
identifier: {
|
163
|
+
data: { expected: /^[a-zA-Z0-9.-]+$/, received: 'canary uat matrix.squiz.cloud' },
|
164
|
+
message: 'Matrix Identifier has invalid format, must match /^[a-zA-Z0-9.-]+$/',
|
165
|
+
},
|
166
|
+
scheme: {
|
167
|
+
data: { expected: 'matrix-asset', received: 'not-valid' },
|
168
|
+
message: 'Uri scheme is invalid, must match "matrix-asset"',
|
169
|
+
},
|
170
|
+
},
|
158
171
|
);
|
159
172
|
});
|
160
173
|
it('should throw error for invalid matrix-asset-uri type number', () => {
|
@@ -186,7 +199,21 @@ describe('JsonValidationService', () => {
|
|
186
199
|
});
|
187
200
|
},
|
188
201
|
SchemaValidationError,
|
189
|
-
`failed validation:
|
202
|
+
`failed validation: matrix asset uri "matrix://" isn't a valid matrix asset uri`,
|
203
|
+
{
|
204
|
+
assetId: {
|
205
|
+
data: { expected: /^\d+(?::.+)?$/, received: '' },
|
206
|
+
message: 'Matrix Asset Id has invalid format, must match /^d+(?::.+)?$/',
|
207
|
+
},
|
208
|
+
identifier: {
|
209
|
+
data: { expected: /^[a-zA-Z0-9.-]+$/, received: '' },
|
210
|
+
message: 'Matrix Identifier has invalid format, must match /^[a-zA-Z0-9.-]+$/',
|
211
|
+
},
|
212
|
+
scheme: {
|
213
|
+
data: { expected: 'matrix-asset', received: 'matrix' },
|
214
|
+
message: 'Uri scheme is invalid, must match "matrix-asset"',
|
215
|
+
},
|
216
|
+
},
|
190
217
|
);
|
191
218
|
});
|
192
219
|
});
|
@@ -223,11 +250,12 @@ describe('JsonValidationService', () => {
|
|
223
250
|
jsonValidationService.validateRenderInput(schema, value);
|
224
251
|
},
|
225
252
|
SchemaValidationError,
|
226
|
-
'failed validation: Expected `[
|
253
|
+
'failed validation: Expected `Array [{"type":"text","value":"hello"}]` (array) in `#/my-input` to be of type `string`',
|
227
254
|
{
|
228
255
|
'#/my-input': [
|
229
256
|
{
|
230
|
-
message:
|
257
|
+
message:
|
258
|
+
'Expected `Array [{"type":"text","value":"hello"}]` (array) in `#/my-input` to be of type `string`',
|
231
259
|
data: {
|
232
260
|
received: 'array',
|
233
261
|
expected: 'string',
|
@@ -353,6 +381,14 @@ describe('JsonSchemaService', () => {
|
|
353
381
|
},
|
354
382
|
SchemaValidationError,
|
355
383
|
'failed validation: The required property `required` is missing at `#/properties/my-input`',
|
384
|
+
{
|
385
|
+
'#/properties/my-input': [
|
386
|
+
{
|
387
|
+
data: { key: 'required', pointer: '#/properties/my-input' },
|
388
|
+
message: 'The required property `required` is missing at `#/properties/my-input`',
|
389
|
+
},
|
390
|
+
],
|
391
|
+
},
|
356
392
|
);
|
357
393
|
});
|
358
394
|
|
@@ -374,6 +410,14 @@ describe('JsonSchemaService', () => {
|
|
374
410
|
},
|
375
411
|
SchemaValidationError,
|
376
412
|
`failed validation: Expected value at \`#/type\` to be \`object\`, but value given is \`array\``,
|
413
|
+
{
|
414
|
+
'#/type': [
|
415
|
+
{
|
416
|
+
data: { expected: 'object', pointer: '#/type', value: 'array' },
|
417
|
+
message: 'Expected value at `#/type` to be `object`, but value given is `array`',
|
418
|
+
},
|
419
|
+
],
|
420
|
+
},
|
377
421
|
);
|
378
422
|
});
|
379
423
|
|
@@ -391,6 +435,83 @@ describe('JsonSchemaService', () => {
|
|
391
435
|
},
|
392
436
|
SchemaValidationError,
|
393
437
|
'failed validation: The required property `required` is missing at `#`',
|
438
|
+
{
|
439
|
+
'#': [
|
440
|
+
{ data: { key: 'required', pointer: '#' }, message: 'The required property `required` is missing at `#`' },
|
441
|
+
],
|
442
|
+
},
|
443
|
+
);
|
444
|
+
});
|
445
|
+
});
|
446
|
+
|
447
|
+
describe('SquizImage input', () => {
|
448
|
+
it('should validate a squizImage input', () => {
|
449
|
+
const schema = {
|
450
|
+
type: 'object',
|
451
|
+
properties: {
|
452
|
+
image: {
|
453
|
+
type: 'SquizImage',
|
454
|
+
},
|
455
|
+
},
|
456
|
+
};
|
457
|
+
|
458
|
+
const value: SquizImageType['__shape__'] = {
|
459
|
+
name: 'My Image',
|
460
|
+
alt: 'My Image that did not load',
|
461
|
+
caption: 'This above is a loaded image',
|
462
|
+
imageVariations: {
|
463
|
+
original: {
|
464
|
+
url: 'https://picsum.photos/200/300',
|
465
|
+
width: 100,
|
466
|
+
height: 100,
|
467
|
+
byteSize: 1000,
|
468
|
+
mimeType: 'image/jpeg',
|
469
|
+
aspectRatio: '1:1',
|
470
|
+
sha1Hash: '1234567890abcdef1234567890abcdef12345678',
|
471
|
+
},
|
472
|
+
},
|
473
|
+
};
|
474
|
+
expect(jsonSchemaService.validateInput(value, schema)).toEqual(true);
|
475
|
+
});
|
476
|
+
|
477
|
+
it('should error if SquizImage type is missing required properties', async () => {
|
478
|
+
const schema = {
|
479
|
+
type: 'object',
|
480
|
+
properties: {
|
481
|
+
myProp: {
|
482
|
+
type: 'SquizImage',
|
483
|
+
},
|
484
|
+
},
|
485
|
+
};
|
486
|
+
|
487
|
+
const value: { myProp: SquizImageType['__shape__'] } = {
|
488
|
+
// @ts-expect-error - missing required properties
|
489
|
+
myProp: {
|
490
|
+
alt: 'alt',
|
491
|
+
caption: 'caption',
|
492
|
+
name: 'name',
|
493
|
+
},
|
494
|
+
};
|
495
|
+
expectToThrowErrorMatchingTypeAndMessage(
|
496
|
+
() => {
|
497
|
+
jsonSchemaService.validateInput(value, schema);
|
498
|
+
},
|
499
|
+
SchemaValidationError,
|
500
|
+
'failed validation: Expected `Object {"alt":"alt","caption":"caption","name":"name"}` (object) in `#/myProp` to be of type `SquizImage`',
|
501
|
+
{
|
502
|
+
'#/myProp': [
|
503
|
+
{
|
504
|
+
data: {
|
505
|
+
expected: 'SquizImage',
|
506
|
+
pointer: '#/myProp',
|
507
|
+
received: 'object',
|
508
|
+
value: { alt: 'alt', caption: 'caption', name: 'name' },
|
509
|
+
},
|
510
|
+
message:
|
511
|
+
'Expected `Object {"alt":"alt","caption":"caption","name":"name"}` (object) in `#/myProp` to be of type `SquizImage`',
|
512
|
+
},
|
513
|
+
],
|
514
|
+
},
|
394
515
|
);
|
395
516
|
});
|
396
517
|
});
|
@@ -517,6 +638,27 @@ describe('JsonSchemaService', () => {
|
|
517
638
|
},
|
518
639
|
SchemaValidationError,
|
519
640
|
'failed validation: Value `123` in `#/my-input` does not match any given oneof schema',
|
641
|
+
{
|
642
|
+
'#/my-input': [
|
643
|
+
{
|
644
|
+
data: {
|
645
|
+
errors: [
|
646
|
+
{
|
647
|
+
code: 'type-error',
|
648
|
+
data: { expected: 'array', pointer: '#/my-input', received: 'number', value: 123 },
|
649
|
+
message: 'Expected `123` (number) in `#/my-input` to be of type `array`',
|
650
|
+
name: 'TypeError',
|
651
|
+
type: 'error',
|
652
|
+
},
|
653
|
+
],
|
654
|
+
oneOf: [{ $ref: 'FormattedText.json' }],
|
655
|
+
pointer: '#/my-input',
|
656
|
+
value: '123',
|
657
|
+
},
|
658
|
+
message: 'Value `123` in `#/my-input` does not match any given oneof schema',
|
659
|
+
},
|
660
|
+
],
|
661
|
+
},
|
520
662
|
);
|
521
663
|
});
|
522
664
|
|
@@ -541,6 +683,27 @@ describe('JsonSchemaService', () => {
|
|
541
683
|
},
|
542
684
|
SchemaValidationError,
|
543
685
|
'failed validation: Value `{"something":"aa"}` in `#/my-input` does not match any given oneof schema',
|
686
|
+
{
|
687
|
+
'#/my-input': [
|
688
|
+
{
|
689
|
+
data: {
|
690
|
+
errors: [
|
691
|
+
{
|
692
|
+
code: 'type-error',
|
693
|
+
data: { expected: 'array', pointer: '#/my-input', received: 'object', value: { something: 'aa' } },
|
694
|
+
message: 'Expected `Object {"something":"aa"}` (object) in `#/my-input` to be of type `array`',
|
695
|
+
name: 'TypeError',
|
696
|
+
type: 'error',
|
697
|
+
},
|
698
|
+
],
|
699
|
+
oneOf: [{ $ref: 'FormattedText.json' }],
|
700
|
+
pointer: '#/my-input',
|
701
|
+
value: '{"something":"aa"}',
|
702
|
+
},
|
703
|
+
message: 'Value `{"something":"aa"}` in `#/my-input` does not match any given oneof schema',
|
704
|
+
},
|
705
|
+
],
|
706
|
+
},
|
544
707
|
);
|
545
708
|
});
|
546
709
|
|
@@ -577,6 +740,46 @@ describe('JsonSchemaService', () => {
|
|
577
740
|
},
|
578
741
|
SchemaValidationError,
|
579
742
|
'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',
|
743
|
+
{
|
744
|
+
'#/my-input': [
|
745
|
+
{
|
746
|
+
data: {
|
747
|
+
errors: [
|
748
|
+
{
|
749
|
+
code: 'any-of-error',
|
750
|
+
data: {
|
751
|
+
anyOf: [
|
752
|
+
{ $ref: '#/definitions/HigherOrderFormattedNodes' },
|
753
|
+
{ $ref: '#/definitions/BaseFormattedNodes' },
|
754
|
+
],
|
755
|
+
pointer: '#/my-input/0',
|
756
|
+
value: {
|
757
|
+
children: [
|
758
|
+
{ type: 'text', value: 'This is some ' },
|
759
|
+
{ type: 'text', value: 'Link to asset 12345' },
|
760
|
+
{ type: 'text', value: ' with an image ' },
|
761
|
+
{ type: 'text', value: 123 },
|
762
|
+
{ type: 'text', value: '.' },
|
763
|
+
],
|
764
|
+
tag: 'p',
|
765
|
+
type: 'tag',
|
766
|
+
},
|
767
|
+
},
|
768
|
+
message: 'Object at `#/my-input/0` does not match any schema',
|
769
|
+
name: 'AnyOfError',
|
770
|
+
type: 'error',
|
771
|
+
},
|
772
|
+
],
|
773
|
+
oneOf: [{ $ref: 'FormattedText.json' }],
|
774
|
+
pointer: '#/my-input',
|
775
|
+
value:
|
776
|
+
'[{"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":"."}]}]',
|
777
|
+
},
|
778
|
+
message:
|
779
|
+
'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',
|
780
|
+
},
|
781
|
+
],
|
782
|
+
},
|
580
783
|
);
|
581
784
|
});
|
582
785
|
|
@@ -664,6 +867,34 @@ describe('JsonSchemaService', () => {
|
|
664
867
|
},
|
665
868
|
SchemaValidationError,
|
666
869
|
'failed validation: Value `{"bad":"data"}` in `#/deep/arr/0/formattedTextArray/2` does not match any given oneof schema',
|
870
|
+
{
|
871
|
+
'#/deep/arr/0/formattedTextArray/2': [
|
872
|
+
{
|
873
|
+
data: {
|
874
|
+
errors: [
|
875
|
+
{
|
876
|
+
code: 'type-error',
|
877
|
+
data: {
|
878
|
+
expected: 'array',
|
879
|
+
pointer: '#/deep/arr/0/formattedTextArray/2',
|
880
|
+
received: 'object',
|
881
|
+
value: { bad: 'data' },
|
882
|
+
},
|
883
|
+
message:
|
884
|
+
'Expected `Object {"bad":"data"}` (object) in `#/deep/arr/0/formattedTextArray/2` to be of type `array`',
|
885
|
+
name: 'TypeError',
|
886
|
+
type: 'error',
|
887
|
+
},
|
888
|
+
],
|
889
|
+
oneOf: [{ $ref: 'FormattedText.json' }],
|
890
|
+
pointer: '#/deep/arr/0/formattedTextArray/2',
|
891
|
+
value: '{"bad":"data"}',
|
892
|
+
},
|
893
|
+
message:
|
894
|
+
'Value `{"bad":"data"}` in `#/deep/arr/0/formattedTextArray/2` does not match any given oneof schema',
|
895
|
+
},
|
896
|
+
],
|
897
|
+
},
|
667
898
|
);
|
668
899
|
});
|
669
900
|
|
@@ -714,6 +945,27 @@ describe('JsonSchemaService', () => {
|
|
714
945
|
},
|
715
946
|
SchemaValidationError,
|
716
947
|
'failed validation: Value `{"bad":"data"}` in `#/my-input` does not match any given oneof schema',
|
948
|
+
{
|
949
|
+
'#/my-input': [
|
950
|
+
{
|
951
|
+
data: {
|
952
|
+
errors: [
|
953
|
+
{
|
954
|
+
code: 'type-error',
|
955
|
+
data: { expected: 'array', pointer: '#/my-input', received: 'object', value: { bad: 'data' } },
|
956
|
+
message: 'Expected `Object {"bad":"data"}` (object) in `#/my-input` to be of type `array`',
|
957
|
+
name: 'TypeError',
|
958
|
+
type: 'error',
|
959
|
+
},
|
960
|
+
],
|
961
|
+
oneOf: [{ $ref: 'FormattedText.json' }],
|
962
|
+
pointer: '#/my-input',
|
963
|
+
value: '{"bad":"data"}',
|
964
|
+
},
|
965
|
+
message: 'Value `{"bad":"data"}` in `#/my-input` does not match any given oneof schema',
|
966
|
+
},
|
967
|
+
],
|
968
|
+
},
|
717
969
|
);
|
718
970
|
});
|
719
971
|
|
@@ -801,6 +1053,14 @@ describe('JsonSchemaService', () => {
|
|
801
1053
|
},
|
802
1054
|
SchemaValidationError,
|
803
1055
|
`failed validation: Expected \`123\` (string) in \`#/my-input\` to be of type \`number\``,
|
1056
|
+
{
|
1057
|
+
'#/my-input': [
|
1058
|
+
{
|
1059
|
+
data: { expected: 'number', pointer: '#/my-input', received: 'string', value: '123' },
|
1060
|
+
message: 'Expected `123` (string) in `#/my-input` to be of type `number`',
|
1061
|
+
},
|
1062
|
+
],
|
1063
|
+
},
|
804
1064
|
);
|
805
1065
|
});
|
806
1066
|
|
@@ -812,6 +1072,11 @@ describe('JsonSchemaService', () => {
|
|
812
1072
|
},
|
813
1073
|
SchemaValidationError,
|
814
1074
|
`failed validation: The required property \`my-input\` is missing at \`#\``,
|
1075
|
+
{
|
1076
|
+
'#': [
|
1077
|
+
{ data: { key: 'my-input', pointer: '#' }, message: 'The required property `my-input` is missing at `#`' },
|
1078
|
+
],
|
1079
|
+
},
|
815
1080
|
);
|
816
1081
|
});
|
817
1082
|
|
@@ -825,6 +1090,14 @@ describe('JsonSchemaService', () => {
|
|
825
1090
|
},
|
826
1091
|
SchemaValidationError,
|
827
1092
|
'failed validation: Expected given value `z` in #/enum` to be one of `[a, b, c, d, e, ... 2 more]`',
|
1093
|
+
{
|
1094
|
+
'#/enum': [
|
1095
|
+
{
|
1096
|
+
data: { pointer: '#/enum', value: 'z', values: ['a', 'b', 'c', 'd', 'e', 'f', 'g'] },
|
1097
|
+
message: 'Expected given value `z` in #/enum` to be one of `[a, b, c, d, e, ... 2 more]`',
|
1098
|
+
},
|
1099
|
+
],
|
1100
|
+
},
|
828
1101
|
);
|
829
1102
|
});
|
830
1103
|
|
@@ -67,6 +67,28 @@ const defaultConfig: DraftConfig = {
|
|
67
67
|
data,
|
68
68
|
};
|
69
69
|
},
|
70
|
+
|
71
|
+
typeError(data) {
|
72
|
+
let value = `${data.value}`;
|
73
|
+
|
74
|
+
if (data.received == 'object') {
|
75
|
+
value = `Object ${JSON.stringify(data.value)}`;
|
76
|
+
}
|
77
|
+
|
78
|
+
if (data.received == 'array') {
|
79
|
+
value = `Array ${JSON.stringify(data.value)}`;
|
80
|
+
}
|
81
|
+
|
82
|
+
const expected = JSON.stringify(data.expected).replace(/"/g, '`');
|
83
|
+
|
84
|
+
return {
|
85
|
+
type: 'error',
|
86
|
+
name: 'TypeError',
|
87
|
+
code: 'type-error',
|
88
|
+
message: `Expected \`${value}\` (${data.received}) in \`${data.pointer}\` to be of type ${expected}`,
|
89
|
+
data,
|
90
|
+
};
|
91
|
+
},
|
70
92
|
},
|
71
93
|
};
|
72
94
|
|
@@ -204,15 +226,7 @@ export class JSONSchemaService<P extends AnyPrimitiveType, R extends AnyResolvab
|
|
204
226
|
public validateInput(input: unknown, inputSchema: JSONSchema = this.schema.rootSchema): true | never {
|
205
227
|
inputSchema = this.schema.compileSchema(inputSchema);
|
206
228
|
const errors = this.schema.validate(input, inputSchema);
|
207
|
-
return
|
208
|
-
}
|
209
|
-
|
210
|
-
private processValidationResult(errors: JSONError[]): true {
|
211
|
-
if (errors.length > 0) {
|
212
|
-
throw new SchemaValidationError(errors.map((a) => a.message).join(',\n'));
|
213
|
-
}
|
214
|
-
|
215
|
-
return true;
|
229
|
+
return processValidationResult(errors);
|
216
230
|
}
|
217
231
|
|
218
232
|
/**
|
@@ -269,7 +283,7 @@ export class JsonValidationService {
|
|
269
283
|
switch (version) {
|
270
284
|
case 'v1': {
|
271
285
|
const validationResult = v1Schema.validate(manifest);
|
272
|
-
return
|
286
|
+
return processValidationResult(validationResult);
|
273
287
|
}
|
274
288
|
|
275
289
|
default:
|
@@ -277,37 +291,37 @@ export class JsonValidationService {
|
|
277
291
|
}
|
278
292
|
}
|
279
293
|
validateContentSchema(contentSchema: JSONSchema) {
|
280
|
-
return
|
294
|
+
return processValidationResult(ComponentInputSchema.validate(contentSchema));
|
281
295
|
}
|
282
296
|
|
283
297
|
validateComponentInput(functionInputSchema: JSONSchema, inputValue: unknown) {
|
284
298
|
const inputSchema = ComponentInputSchema.compileSchema(functionInputSchema);
|
285
299
|
const errors = ComponentInputSchema.validate(inputValue, inputSchema);
|
286
|
-
return
|
300
|
+
return processValidationResult(errors);
|
287
301
|
}
|
288
302
|
|
289
303
|
validateRenderInput(functionInputSchema: JSONSchema, inputValue: unknown) {
|
290
304
|
const inputSchema = RenderInputSchema.compileSchema(functionInputSchema);
|
291
305
|
const errors = RenderInputSchema.validate(inputValue, inputSchema);
|
292
306
|
|
293
|
-
return
|
307
|
+
return processValidationResult(errors);
|
294
308
|
}
|
309
|
+
}
|
295
310
|
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
}
|
311
|
-
return true;
|
311
|
+
function processValidationResult(errors: JSONError[]): true {
|
312
|
+
if (errors.length > 0) {
|
313
|
+
const ValidationDataMap: ValidationDataMap = errors.reduce((acc: ValidationDataMap, error: JSONError) => {
|
314
|
+
const pointer = error?.data?.pointer;
|
315
|
+
const validationData: ValidationData = {
|
316
|
+
message: error.message,
|
317
|
+
data: error.data,
|
318
|
+
};
|
319
|
+
Object.keys(acc).includes(pointer) && Array.isArray(acc[pointer])
|
320
|
+
? acc[pointer].push(validationData)
|
321
|
+
: (acc[pointer] = [validationData]);
|
322
|
+
return acc;
|
323
|
+
}, {});
|
324
|
+
throw new SchemaValidationError(errors.map((a) => a.message).join(',\n'), undefined, ValidationDataMap);
|
312
325
|
}
|
326
|
+
return true;
|
313
327
|
}
|
@@ -1,6 +1,7 @@
|
|
1
1
|
import { Draft, JSONError, JSONSchema } from '@squiz/json-schema-library';
|
2
2
|
import { SchemaValidationError } from '../errors/SchemaValidationError';
|
3
3
|
import { isMatrixAssetUri } from './utils/matrixAssetValidator';
|
4
|
+
import { getValidationDataForMatrixUri } from './utils/getValidationDataForMatrixUri';
|
4
5
|
|
5
6
|
export const customFormatValidators: Record<
|
6
7
|
string,
|
@@ -8,7 +9,13 @@ export const customFormatValidators: Record<
|
|
8
9
|
> = {
|
9
10
|
'matrix-asset-uri': (core, schema, value): undefined => {
|
10
11
|
if (isMatrixAssetUri(value) === false) {
|
11
|
-
throw new SchemaValidationError(`
|
12
|
+
if (typeof value !== 'string') throw new SchemaValidationError(`matrix asset uri "${value}" isn't a string`);
|
13
|
+
const validationData = getValidationDataForMatrixUri(value);
|
14
|
+
throw new SchemaValidationError(
|
15
|
+
`matrix asset uri "${value}" isn't a valid matrix asset uri`,
|
16
|
+
undefined,
|
17
|
+
validationData,
|
18
|
+
);
|
12
19
|
}
|
13
20
|
return;
|
14
21
|
},
|
@@ -0,0 +1,92 @@
|
|
1
|
+
import { getValidationDataForMatrixUri } from './getValidationDataForMatrixUri';
|
2
|
+
|
3
|
+
describe('getInvalidPartFromMatrixUri', () => {
|
4
|
+
it('should return invalid part of matrix asset uri - invalid scheme', () => {
|
5
|
+
const part = getValidationDataForMatrixUri('matrix-link://dx-data.asset.com/123');
|
6
|
+
expect(part).toEqual({
|
7
|
+
scheme: {
|
8
|
+
message: 'Uri scheme is invalid, must match "matrix-asset"',
|
9
|
+
data: {
|
10
|
+
expected: 'matrix-asset',
|
11
|
+
received: 'matrix-link',
|
12
|
+
},
|
13
|
+
},
|
14
|
+
});
|
15
|
+
});
|
16
|
+
it('should return invalid part of matrix asset uri - invalid identifier', () => {
|
17
|
+
const part = getValidationDataForMatrixUri('matrix-asset://dx team id/123');
|
18
|
+
expect(part).toEqual({
|
19
|
+
identifier: {
|
20
|
+
message: 'Matrix Identifier has invalid format, must match /^[a-zA-Z0-9.-]+$/',
|
21
|
+
data: {
|
22
|
+
expected: /^[a-zA-Z0-9.-]+$/,
|
23
|
+
received: 'dx team id',
|
24
|
+
},
|
25
|
+
},
|
26
|
+
});
|
27
|
+
});
|
28
|
+
it('should return invalid part of matrix asset uri - invalid asset id', () => {
|
29
|
+
const part = getValidationDataForMatrixUri('matrix-asset://dx-data.asset.com/asset/1234');
|
30
|
+
expect(part).toEqual({
|
31
|
+
assetId: {
|
32
|
+
message: 'Matrix Asset Id has invalid format, must match /^d+(?::.+)?$/',
|
33
|
+
data: {
|
34
|
+
expected: /^\d+(?::.+)?$/,
|
35
|
+
received: 'asset/1234',
|
36
|
+
},
|
37
|
+
},
|
38
|
+
});
|
39
|
+
});
|
40
|
+
|
41
|
+
it('should return invalid part of matrix asset uri - invalid identifier and asset id', () => {
|
42
|
+
const part = getValidationDataForMatrixUri('matrix-asset://dx team id/asset/1234');
|
43
|
+
expect(part).toEqual({
|
44
|
+
identifier: {
|
45
|
+
message: 'Matrix Identifier has invalid format, must match /^[a-zA-Z0-9.-]+$/',
|
46
|
+
data: {
|
47
|
+
expected: /^[a-zA-Z0-9.-]+$/,
|
48
|
+
received: 'dx team id',
|
49
|
+
},
|
50
|
+
},
|
51
|
+
assetId: {
|
52
|
+
message: 'Matrix Asset Id has invalid format, must match /^d+(?::.+)?$/',
|
53
|
+
data: {
|
54
|
+
expected: /^\d+(?::.+)?$/,
|
55
|
+
received: 'asset/1234',
|
56
|
+
},
|
57
|
+
},
|
58
|
+
});
|
59
|
+
});
|
60
|
+
|
61
|
+
it('should return invalid part of matrix asset uri - invalid scheme, identifier and asset id', () => {
|
62
|
+
const part = getValidationDataForMatrixUri('matrix-link://dx team id/asset/1234');
|
63
|
+
expect(part).toEqual({
|
64
|
+
scheme: {
|
65
|
+
message: 'Uri scheme is invalid, must match "matrix-asset"',
|
66
|
+
data: {
|
67
|
+
expected: 'matrix-asset',
|
68
|
+
received: 'matrix-link',
|
69
|
+
},
|
70
|
+
},
|
71
|
+
identifier: {
|
72
|
+
message: 'Matrix Identifier has invalid format, must match /^[a-zA-Z0-9.-]+$/',
|
73
|
+
data: {
|
74
|
+
expected: /^[a-zA-Z0-9.-]+$/,
|
75
|
+
received: 'dx team id',
|
76
|
+
},
|
77
|
+
},
|
78
|
+
assetId: {
|
79
|
+
message: 'Matrix Asset Id has invalid format, must match /^d+(?::.+)?$/',
|
80
|
+
data: {
|
81
|
+
expected: /^\d+(?::.+)?$/,
|
82
|
+
received: 'asset/1234',
|
83
|
+
},
|
84
|
+
},
|
85
|
+
});
|
86
|
+
});
|
87
|
+
|
88
|
+
it('should return undefined if matrix asset uri is valid', () => {
|
89
|
+
const part = getValidationDataForMatrixUri('matrix-asset://dx-data.asset.com/123');
|
90
|
+
expect(part).toEqual(undefined);
|
91
|
+
});
|
92
|
+
});
|
@@ -0,0 +1,55 @@
|
|
1
|
+
type matrixAssetUriValidationData = { message: string; data: any };
|
2
|
+
type uriParts = 'scheme' | 'identifier' | 'assetId';
|
3
|
+
type matrixAssetUriValidationDataMap = Record<uriParts, matrixAssetUriValidationData> | object;
|
4
|
+
|
5
|
+
export function getValidationDataForMatrixUri(uri: string): matrixAssetUriValidationDataMap | undefined {
|
6
|
+
let validationDataMap: matrixAssetUriValidationDataMap = {};
|
7
|
+
const [scheme, path] = uri.split('://');
|
8
|
+
|
9
|
+
if (scheme !== 'matrix-asset') {
|
10
|
+
const validationData: matrixAssetUriValidationData = {
|
11
|
+
message: 'Uri scheme is invalid, must match "matrix-asset"',
|
12
|
+
data: {
|
13
|
+
expected: 'matrix-asset',
|
14
|
+
received: scheme,
|
15
|
+
},
|
16
|
+
};
|
17
|
+
validationDataMap = {
|
18
|
+
...validationDataMap,
|
19
|
+
scheme: validationData,
|
20
|
+
};
|
21
|
+
}
|
22
|
+
|
23
|
+
const [identifier, ...assetIdArray] = path.split('/');
|
24
|
+
const assetId = assetIdArray.join('/');
|
25
|
+
|
26
|
+
const identifierRegex = /^[a-zA-Z0-9.-]+$/;
|
27
|
+
if (identifierRegex.test(identifier) === false) {
|
28
|
+
validationDataMap = {
|
29
|
+
...validationDataMap,
|
30
|
+
identifier: {
|
31
|
+
message: 'Matrix Identifier has invalid format, must match /^[a-zA-Z0-9.-]+$/',
|
32
|
+
data: {
|
33
|
+
expected: /^[a-zA-Z0-9.-]+$/,
|
34
|
+
received: identifier,
|
35
|
+
},
|
36
|
+
},
|
37
|
+
};
|
38
|
+
}
|
39
|
+
|
40
|
+
const assetIdRegex = /^\d+(?::.+)?$/;
|
41
|
+
if (assetIdRegex.test(assetId) === false) {
|
42
|
+
validationDataMap = {
|
43
|
+
...validationDataMap,
|
44
|
+
assetId: {
|
45
|
+
message: 'Matrix Asset Id has invalid format, must match /^d+(?::.+)?$/',
|
46
|
+
data: {
|
47
|
+
expected: /^\d+(?::.+)?$/,
|
48
|
+
received: assetId,
|
49
|
+
},
|
50
|
+
},
|
51
|
+
};
|
52
|
+
}
|
53
|
+
|
54
|
+
return Object.keys(validationDataMap).length > 0 ? validationDataMap : undefined;
|
55
|
+
}
|