total5 0.0.1 → 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/jsonschema.js ADDED
@@ -0,0 +1,699 @@
1
+ // Total.js JSONSchemas
2
+ // The MIT License
3
+ // Copyright 2021-2023 (c) Peter Širka <petersirka@gmail.com>
4
+
5
+ 'use strict';
6
+
7
+ require('./index');
8
+
9
+ const REG_NUMBER = /[\d,.]+/;
10
+ const REG_COLOR = /^#([A-F0-9]{3}|[A-F0-9]{6}|[A-F0-9]{8})$/i;
11
+ const REG_ICON = /^(ti|far|fab|fad|fal|fas|fa)?\s(fa|ti)-[a-z0-9-]+$/;
12
+ const REG_WSPACE = /\u00A0/g;
13
+
14
+ function Value() {}
15
+
16
+ function check_string(meta, error, value, errplus, path) {
17
+
18
+ var type = typeof(value);
19
+
20
+ if (type !== 'string')
21
+ value = value ? (value + '') : meta.nullable ? null : '';
22
+
23
+ if (errplus == null)
24
+ errplus = '';
25
+
26
+ if (value) {
27
+ switch (meta.subtype) {
28
+ case 'name':
29
+ value = value.toName();
30
+ break;
31
+ }
32
+ }
33
+
34
+ if (meta.$$REQUIRED && !value) {
35
+ error.push2(errplus + meta.$$ID, path);
36
+ return;
37
+ }
38
+
39
+ if (value == null)
40
+ return null;
41
+
42
+ var len = value.length;
43
+
44
+ if (meta.maxLength && len > meta.maxLength) {
45
+ error.push2(errplus + meta.$$ID, path);
46
+ return;
47
+ }
48
+
49
+ if (meta.minLength && len < meta.minLength) {
50
+ error.push2(errplus + meta.$$ID, path);
51
+ return;
52
+ }
53
+
54
+ if (value) {
55
+ value = value.replace(REG_WSPACE, ' ');
56
+ switch (meta.subtype) {
57
+ case 'text':
58
+ break;
59
+ case 'email':
60
+ value = value.replace(/\s/g, '').toLowerCase();
61
+ if (value && !value.isEmail()) {
62
+ error.push2(errplus + meta.$$ID, path);
63
+ return;
64
+ }
65
+ break;
66
+ case 'safestring':
67
+ value = value.trim();
68
+ if (value && (value.isXSS() || value.isSQLInjection())) {
69
+ error.push2(errplus + meta.$$ID, path);
70
+ return;
71
+ }
72
+ break;
73
+ case 'search':
74
+ value = value.trim().toSearch();
75
+ break;
76
+ case 'phone':
77
+ value = value.replace(/\s/g, '').toLowerCase();
78
+ if (value && !value.isPhone()) {
79
+ error.push2(errplus + meta.$$ID, path);
80
+ return;
81
+ }
82
+ break;
83
+ case 'url':
84
+ value = value.trim();
85
+ if (value && !value.isURL()) {
86
+ error.push2(errplus + meta.$$ID, path);
87
+ return;
88
+ }
89
+ break;
90
+ case 'zip':
91
+ value = value.trim();
92
+ if (value && !value.isZIP()) {
93
+ error.push2(errplus + meta.$$ID, path);
94
+ return;
95
+ }
96
+ break;
97
+ case 'guid':
98
+ value = value.trim();
99
+ if (value && !value.isGUID()) {
100
+ error.push2(errplus + meta.$$ID, path);
101
+ return;
102
+ } else if (!value)
103
+ value = null;
104
+ break;
105
+ case 'uid':
106
+ value = value.trim();
107
+ if (value && !value.isUID()) {
108
+ error.push2(errplus + meta.$$ID, path);
109
+ return;
110
+ } else if (!value)
111
+ value = null;
112
+ break;
113
+ case 'ipaddress':
114
+ case 'ip':
115
+ value = value.trim();
116
+ if (value && !F.Net.isIP(value)) {
117
+ error.push2(errplus + meta.$$ID, path);
118
+ return;
119
+ } else if (!value)
120
+ value = null;
121
+ break;
122
+ case 'json':
123
+ value = value.trim();
124
+ if (value && !value.isJSON()) {
125
+ error.push2(errplus + meta.$$ID, path);
126
+ return;
127
+ }
128
+ break;
129
+ case 'base64':
130
+ value = value.trim();
131
+ if (value && !value.isBase64()) {
132
+ error.push2(errplus + meta.$$ID, path);
133
+ return;
134
+ }
135
+ break;
136
+ case 'datauri':
137
+ value = value.trim();
138
+ if (value && !value.isBase64(true)) {
139
+ error.push2(errplus + meta.$$ID, path);
140
+ return;
141
+ }
142
+ value = value ? value.parseDataURI() : null;
143
+ break;
144
+ case 'color':
145
+ value = value.trim();
146
+ if (value && !REG_COLOR.test(value)) {
147
+ error.push2(errplus + meta.$$ID, path);
148
+ return;
149
+ }
150
+ break;
151
+ case 'icon':
152
+ value = value.trim();
153
+ if (value && !REG_ICON.test(value)) {
154
+ error.push2(errplus + meta.$$ID, path);
155
+ return;
156
+ }
157
+ break;
158
+ case 'lower':
159
+ case 'lowercase':
160
+ value = value.trim().toLowerCase();
161
+ break;
162
+ case 'upper':
163
+ case 'uppercase':
164
+ value = value.trim().toUpperCase();
165
+ break;
166
+ case 'capitalize':
167
+ value = value.trim().capitalize();
168
+ break;
169
+ case 'capitalize2':
170
+ value = value.trim().capitalize(true);
171
+ break;
172
+ default:
173
+ value = value.trim();
174
+ break;
175
+ }
176
+ }
177
+
178
+ if ((value || meta.$$REQUIRED) && meta.enum instanceof Array) {
179
+ if (!meta.enum.includes(value)) {
180
+ error.push2(errplus + meta.$$ID, path);
181
+ return;
182
+ }
183
+ }
184
+
185
+ return value;
186
+ }
187
+
188
+ function check_number(meta, error, value, errplus, path) {
189
+
190
+ var type = typeof(value);
191
+
192
+ if (errplus == null)
193
+ errplus = '';
194
+
195
+ if (type === 'string') {
196
+ if (REG_NUMBER.test(value))
197
+ value = value.parseFloat();
198
+ else
199
+ value = null;
200
+
201
+ } else if (type !== 'number')
202
+ value = null;
203
+
204
+ if (meta.$$REQUIRED) {
205
+ if (value == null) {
206
+ error.push2(errplus + meta.$$ID, path);
207
+ return;
208
+ }
209
+ }
210
+
211
+ if (value == null)
212
+ return;
213
+
214
+ if (meta.multipleOf) {
215
+ if (value % meta.multipleOf !== 0) {
216
+ error.push2(errplus + meta.$$ID, path);
217
+ return;
218
+ }
219
+ }
220
+
221
+ if (meta.maximum) {
222
+ if (value > meta.maximum) {
223
+ error.push2(errplus + meta.$$ID, path);
224
+ return;
225
+ }
226
+ }
227
+
228
+ if (meta.exclusiveMaximum) {
229
+ if (value >= meta.exclusiveMaximum) {
230
+ error.push2(errplus + meta.$$ID, path);
231
+ return;
232
+ }
233
+ }
234
+
235
+ if (meta.minimum) {
236
+ if (value < meta.minimum) {
237
+ error.push2(errplus + meta.$$ID, path);
238
+ return;
239
+ }
240
+ }
241
+
242
+ switch (meta.subtype) {
243
+ case 'smallint':
244
+ if (value < -32767 || value > 32767) {
245
+ error.push2(errplus + meta.$$ID, path);
246
+ return;
247
+ }
248
+ break;
249
+ case 'tinyint':
250
+ if (value < 0 || value > 255) {
251
+ error.push2(errplus + meta.$$ID, path);
252
+ return;
253
+ }
254
+ break;
255
+ }
256
+
257
+ if (meta.exclusiveMinimum) {
258
+ if (value <= meta.exclusiveMinimum) {
259
+ error.push2(errplus + meta.$$ID, path);
260
+ return;
261
+ }
262
+ }
263
+
264
+ return value;
265
+ }
266
+
267
+ function check_boolean(meta, error, value, errplus, path) {
268
+
269
+ var type = typeof(value);
270
+ if (type !== 'boolean')
271
+ value = value ? (value + '').parseBoolean() : null;
272
+
273
+ if (meta.$$REQUIRED) {
274
+
275
+ if (errplus == null)
276
+ errplus = '';
277
+
278
+ if (value == null) {
279
+ error.push2(errplus + meta.$$ID, path);
280
+ return;
281
+ }
282
+ }
283
+
284
+ if (value != null)
285
+ return value;
286
+ }
287
+
288
+ function check_date(meta, error, value, errplus, path) {
289
+
290
+ if (!(value instanceof Date))
291
+ value = value ? (value + '').parseDate() : null;
292
+
293
+ if (value && value instanceof Date && !(value.getTime()>0))
294
+ value = null;
295
+
296
+ if (meta.$$REQUIRED) {
297
+
298
+ if (errplus == null)
299
+ errplus = '';
300
+
301
+ if (value == null) {
302
+ error.push2(errplus + meta.$$ID, path);
303
+ return;
304
+ }
305
+ }
306
+
307
+ return value;
308
+ }
309
+
310
+ function readdef(ref, definitions) {
311
+
312
+ if (ref[0] === '#') {
313
+ var tmp = ref.substring(2).split('/');
314
+ var def = definitions[tmp[0]];
315
+ if (def) {
316
+ var schema = tmp[1];
317
+ var obj = def[schema];
318
+ if (obj) {
319
+ if (!obj.$$ID)
320
+ obj.$$ID = schema;
321
+ return obj;
322
+ }
323
+ }
324
+ } else
325
+ return F.jsonschemas[ref];
326
+ }
327
+
328
+ function check_array(meta, error, value, stop, definitions, path) {
329
+
330
+ if (!(value instanceof Array)) {
331
+ if (meta.$$REQUIRED) {
332
+ error.push2(meta.$$ID, path);
333
+ }
334
+ return;
335
+ }
336
+
337
+ if (!value.length) {
338
+ if (meta.$$REQUIRED) {
339
+ error.push2(meta.$$ID, path);
340
+ return;
341
+ }
342
+ return value;
343
+ }
344
+
345
+ var currentpath = path;
346
+ var response;
347
+ var tmp;
348
+
349
+ if (meta.items instanceof Array) {
350
+
351
+ for (var i = 0; i < value.length; i++) {
352
+ var val = value[i];
353
+ var type = meta.items[i];
354
+ if (type) {
355
+ switch (type) {
356
+ case '$ref':
357
+ break;
358
+ case 'number':
359
+ case 'integer':
360
+ case 'float':
361
+ case 'decimal':
362
+ tmp = check_number(type, error, val);
363
+ if (tmp != null) {
364
+ response.push(tmp);
365
+ break;
366
+ } else {
367
+ error.push2(meta.$$ID, currentpath);
368
+ return;
369
+ }
370
+ case 'boolean':
371
+ case 'bool':
372
+ tmp = check_boolean(type, error, val);
373
+ if (tmp != null) {
374
+ response.push(tmp);
375
+ break;
376
+ } else {
377
+ error.push2(meta.$$ID, currentpath);
378
+ return;
379
+ }
380
+ case 'date':
381
+ tmp = check_date(type, error, val);
382
+ if (tmp != null) {
383
+ response.push(tmp);
384
+ break;
385
+ } else {
386
+ error.push2(meta.$$ID, currentpath);
387
+ return;
388
+ }
389
+ case 'object':
390
+ tmp = check_object(type, error, val, null, stop, definitions);
391
+ if (tmp != null) {
392
+ response.push(tmp);
393
+ break;
394
+ } else {
395
+ error.push2(meta.$$ID, currentpath);
396
+ return;
397
+ }
398
+ case 'array':
399
+ tmp = check_array(type, error, value, null, definitions);
400
+ if (tmp != null && (!meta.uniqueItems || response.indexOf(tmp) === -1)) {
401
+ response.push(tmp);
402
+ break;
403
+ } else {
404
+ error.push2(meta.$$ID, currentpath);
405
+ return;
406
+ }
407
+ case 'string':
408
+ default:
409
+ tmp = check_string(type, error, val, null, currentpath);
410
+ if (tmp != null) {
411
+ if (!tmp && type.subtype === 'uid')
412
+ tmp = null;
413
+ response.push(tmp);
414
+ break;
415
+ } else {
416
+ error.push2(meta.$$ID, currentpath);
417
+ return;
418
+ }
419
+ }
420
+ } else if (!type && !meta.additionalItems) {
421
+ error.push2(meta.$$ID, currentpath, i);
422
+ return;
423
+ }
424
+ }
425
+ } else if (meta.items) {
426
+
427
+ response = [];
428
+
429
+ for (var i = 0; i < value.length; i++) {
430
+ var val = value[i];
431
+
432
+ if (meta.items.$ref) {
433
+ var ref = typeof(meta.items.$ref) === 'object' ? meta.items.$ref :readdef(meta.items.$ref, definitions);
434
+ if (ref) {
435
+ var newerror = new F.ErrorBuilder();
436
+ tmp = transform(ref, newerror, val, false, currentpath + '[' + i + ']');
437
+ if (newerror.items.length) {
438
+ for (var err of newerror.items) {
439
+ error.push2(err.name, err.path, i);
440
+ }
441
+ } else if (tmp != null && (!meta.uniqueItems || response.indexOf(tmp) === -1))
442
+ response.push(tmp);
443
+ continue;
444
+ } else
445
+ continue;
446
+ }
447
+
448
+
449
+ switch (meta.items.type) {
450
+ case 'number':
451
+ case 'integer':
452
+ tmp = check_number(meta.items, error, val, null, currentpath);
453
+ if (tmp != null && (!meta.uniqueItems || response.indexOf(tmp) === -1))
454
+ response.push(tmp);
455
+ break;
456
+ case 'boolean':
457
+ case 'bool':
458
+ tmp = check_boolean(meta.items, error, val, null, currentpath);
459
+ if (tmp != null && (!meta.uniqueItems || response.indexOf(tmp) === -1))
460
+ response.push(tmp);
461
+ break;
462
+ case 'date':
463
+ tmp = check_date(meta.items, error, val, null, currentpath);
464
+ if (tmp != null && (!meta.uniqueItems || response.indexOf(tmp) === -1))
465
+ response.push(tmp);
466
+ break;
467
+ case 'object':
468
+ var newerror = new ErrorBuilder();
469
+ tmp = check_object(meta.items, newerror, val, stop, definitions, currentpath);
470
+ if (newerror.length) {
471
+ for (var err of newerror.items)
472
+ error.push2(meta.$$ID + '.' + err.name, err.error, currentpath, i);
473
+ } else if (tmp != null && (!meta.uniqueItems || response.indexOf(tmp) === -1))
474
+ response.push(tmp);
475
+ break;
476
+ case 'array':
477
+ tmp = check_array(meta.items, error, value, stop, definitions, currentpath);
478
+ if (tmp != null && (!meta.uniqueItems || response.indexOf(tmp) === -1))
479
+ response.push(tmp);
480
+ break;
481
+ case 'string':
482
+ default:
483
+ tmp = check_string(meta.items, error, val, null, currentpath);
484
+ if (tmp != null && (!meta.uniqueItems || response.indexOf(tmp) === -1)) {
485
+ if (!tmp && meta.items.subtype === 'uid')
486
+ tmp = null;
487
+ response.push(tmp);
488
+ }
489
+ break;
490
+ }
491
+ }
492
+ } else
493
+ response = meta.uniqueItems ? [...new Set(value)] : value;
494
+
495
+ if (!response.length && meta.$$REQUIRED) {
496
+ error.push2(meta.$$ID, currentpath);
497
+ return;
498
+ }
499
+
500
+ if (meta.minItems && response.length < meta.minItems) {
501
+ error.push2(meta.$$ID, currentpath);
502
+ return;
503
+ }
504
+
505
+ if (meta.maxItems && response.length < meta.maxItems) {
506
+ error.push2(meta.$$ID, currentpath);
507
+ return;
508
+ }
509
+
510
+ return response;
511
+ }
512
+
513
+ function check_object(meta, error, value, response, stop, definitions, path) {
514
+
515
+ if (!value || typeof(value) !== 'object') {
516
+ if (meta.$$REQUIRED) {
517
+ error.push(meta.$$ID, path);
518
+ }
519
+ return;
520
+ }
521
+
522
+ if (stop && error.items.length)
523
+ return;
524
+
525
+ if (!meta.properties)
526
+ return value;
527
+
528
+ if (!response)
529
+ response = new Value();
530
+
531
+ var count = 0;
532
+ var tmp;
533
+
534
+ for (var key in meta.properties) {
535
+
536
+ var prop = meta.properties[key];
537
+
538
+ if (!prop.ID) {
539
+ prop.$$ID = key;
540
+ prop.$$REQUIRED = meta.required ? meta.required.indexOf(key) !== -1 : false;
541
+ }
542
+
543
+ if (stop && error.items.length)
544
+ return;
545
+
546
+ if (meta.maxProperties && count > meta.maxProperties) {
547
+ error.push(meta.$$ID, path);
548
+ return;
549
+ }
550
+
551
+ var currentpath = (path ? (path + '.') : '') + key;
552
+ var val = value[key];
553
+
554
+ switch (prop.type) {
555
+ case 'number':
556
+ case 'integer':
557
+ tmp = check_number(prop, error, val, null, currentpath);
558
+ if (tmp != null) {
559
+ response[key] = tmp;
560
+ count++;
561
+ }
562
+ break;
563
+ case 'boolean':
564
+ case 'bool':
565
+ tmp = check_boolean(prop, error, val, null, currentpath);
566
+ response[key] = tmp == true;
567
+ count++;
568
+ break;
569
+ case 'date':
570
+ tmp = check_date(prop, error, val, null, currentpath);
571
+ response[key] = tmp;
572
+ count++;
573
+ break;
574
+ case 'string':
575
+ tmp = check_string(prop, error, val, null, currentpath);
576
+ if (tmp == '' && prop.nullable)
577
+ tmp = null;
578
+ response[key] = tmp;
579
+ count++;
580
+ break;
581
+
582
+ case 'object':
583
+
584
+ if (prop.properties) {
585
+ tmp = check_object(prop, error, val, null, null, definitions, currentpath);
586
+ if (tmp != null) {
587
+ response[key] = tmp;
588
+ count++;
589
+ }
590
+ } else {
591
+
592
+ // check ref
593
+ if (prop.$ref) {
594
+ var ref = typeof(prop.$ref) === 'object' ? prop.$ref : readdef(prop.$ref, definitions);
595
+ if (ref) {
596
+ var newerror = new F.ErrorBuilder();
597
+ tmp = transform(ref, newerror, val, false, currentpath);
598
+ if (newerror.items.length) {
599
+ for (var err of newerror.items) {
600
+ error.push2(err.name, err.path);
601
+ }
602
+ } else
603
+ response[key] = tmp;
604
+ continue;
605
+ } else
606
+ continue;
607
+ }
608
+
609
+ response[key] = val;
610
+ count++;
611
+ }
612
+ break;
613
+ case 'array':
614
+ tmp = check_array(prop, error, val, null, definitions, currentpath);
615
+ if (tmp != null) {
616
+ response[key] = tmp;
617
+ count++;
618
+ }
619
+ break;
620
+ default:
621
+ if (prop.$ref) {
622
+ var ref = F.jsonschemas[prop.$ref];
623
+ if (ref) {
624
+ tmp = check_object(ref, error, val, null, null, definitions, currentpath);
625
+ if (tmp != null) {
626
+ response[key] = tmp;
627
+ count++;
628
+ } else if (prop.$$REQUIRED)
629
+ error.push2(prop.ID, currentpath);
630
+ } else
631
+ error.push2(prop.ID, currentpath);
632
+ } else {
633
+ // String
634
+ tmp = check_string(prop, error, val, null, currentpath);
635
+ if (tmp != null) {
636
+ if (!tmp && prop.subtype === 'uid')
637
+ value = null;
638
+ response[key] = tmp;
639
+ count++;
640
+ }
641
+ }
642
+ break;
643
+ }
644
+ }
645
+
646
+ if (meta.minProperties && count < meta.minProperties) {
647
+ error.push2(meta.$$ID, path);
648
+ return;
649
+ }
650
+
651
+ if (count)
652
+ return response;
653
+ }
654
+
655
+ function transform(meta, error, value, stop, path) {
656
+
657
+ var output;
658
+
659
+ switch (meta.type) {
660
+ case 'string':
661
+ output = check_string(meta, error, value, null, path);
662
+ break;
663
+ case 'number':
664
+ case 'integer':
665
+ case 'float':
666
+ case 'decimal':
667
+ output = check_number(meta, error, value, null, path);
668
+ break;
669
+ case 'boolean':
670
+ case 'bool':
671
+ output = check_boolean(meta, error, value, null, path);
672
+ break;
673
+ case 'date':
674
+ output = check_date(meta, error, value, null, path);
675
+ break;
676
+ case 'object':
677
+ output = check_object(meta, error, value, null, stop, meta, path);
678
+ break;
679
+ case 'array':
680
+ output = check_array(meta, error, value, stop, meta, path);
681
+ break;
682
+ default:
683
+ error.push2('.type', path);
684
+ return;
685
+ }
686
+
687
+ if (stop && error.length)
688
+ return;
689
+
690
+ return output || {};
691
+ }
692
+
693
+ function register(schema) {
694
+ if (schema.$id)
695
+ F.jsonschemas[schema.$id] = schema;
696
+ }
697
+
698
+ exports.register = register;
699
+ exports.transform = transform;