z-schema 7.1.0 → 7.2.0

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/README.md CHANGED
@@ -7,6 +7,7 @@
7
7
  ## Topics
8
8
 
9
9
  - [What](#what)
10
+ - [Versions](#versions)
10
11
  - [Usage](#usage)
11
12
  - [Features](#features)
12
13
  - [Options](#options)
@@ -17,6 +18,11 @@
17
18
 
18
19
  What is a JSON Schema? Find here: [https://json-schema.org/](https://json-schema.org/)
19
20
 
21
+ ## Versions
22
+
23
+ - v6 - old version which has been around a long time, supports JSON Schema draft-04
24
+ - v7 - modernized version (to ESM module with Typescript) which passes all tests from JSON Schema Test Suite for draft-04
25
+
20
26
  ## Usage
21
27
 
22
28
  Validator will try to perform sync validation when possible for speed, but supports async callbacks when they are necessary.
@@ -118,505 +124,13 @@ ZSchema.setSchemaReader(function (uri) {
118
124
 
119
125
  ## Features
120
126
 
121
- - [Validate against subschema](#validate-against-subschema)
122
- - [Compile arrays of schemas and use references between them](#compile-arrays-of-schemas-and-use-references-between-them)
123
- - [Register a custom format](#register-a-custom-format)
124
- - [Automatic downloading of remote schemas](#automatic-downloading-of-remote-schemas)
125
- - [Prefill default values to object using format](#prefill-default-values-to-object-using-format)
126
- - [Define a custom timeout for all async operations](#asynctimeout)
127
- - [Disallow validation of empty arrays as arrays](#noemptyarrays)
128
- - [Disallow validation of empty strings as strings](#noemptystrings)
129
- - [Disallow schemas that don't have a type specified](#notypeless)
130
- - [Disallow schemas that contain unrecognized keywords and are not validated by parent schemas](#noextrakeywords)
131
- - [Assume additionalItems/additionalProperties are defined in schemas as false](#assumeadditional)
132
- - [Force additionalItems/additionalProperties to be defined in schemas](#forceadditional)
133
- - [Force items to be defined in array type schemas](#forceitems)
134
- - [Force minItems to be defined in array type schemas](#forceminitems)
135
- - [Force maxItems to be defined in array type schemas](#forcemaxitems)
136
- - [Force minLength to be defined in string type schemas](#forceminlength)
137
- - [Force maxLength to be defined in string type schemas](#forcemaxlength)
138
- - [Force properties or patternProperties to be defined in object type schemas](#forceproperties)
139
- - [Ignore remote references to schemas that are not cached or resolvable](#ignoreunresolvablereferences)
140
- - [Ignore case mismatch when validating enum values](#enumCaseInsensitiveComparison)
141
- - [Only allow strictly absolute URIs to be used in schemas](#stricturis)
142
- - [Turn on z-schema strict mode](#strictmode)
143
- - [Set validator to collect as many errors as possible](#breakonfirsterror)
144
- - [Report paths in errors as arrays so they can be processed easier](#reportpathasarray)
145
- - [Unicode Property Escapes Support](#unicode-property-escapes-support)
146
-
147
- ### Validate against subschema
148
-
149
- In case you don't want to split your schema into multiple schemas using reference for any reason, you can use option schemaPath when validating:
150
-
151
- ```javascript
152
- var valid = validator.validate(cars, schema, { schemaPath: 'definitions.car.definitions.cars' });
153
- ```
154
-
155
- See more details in the [test](/test/spec/schemaPathSpec.js).
156
-
157
- ### Compile arrays of schemas and use references between them
158
-
159
- You can use validator to compile an array of schemas that have references between them and then validate against one of those schemas:
160
-
161
- ```javascript
162
- var schemas = [
163
- {
164
- id: 'personDetails',
165
- type: 'object',
166
- properties: {
167
- firstName: { type: 'string' },
168
- lastName: { type: 'string' },
169
- },
170
- required: ['firstName', 'lastName'],
171
- },
172
- {
173
- id: 'addressDetails',
174
- type: 'object',
175
- properties: {
176
- street: { type: 'string' },
177
- city: { type: 'string' },
178
- },
179
- required: ['street', 'city'],
180
- },
181
- {
182
- id: 'personWithAddress',
183
- allOf: [{ $ref: 'personDetails' }, { $ref: 'addressDetails' }],
184
- },
185
- ];
186
-
187
- var data = {
188
- firstName: 'Martin',
189
- lastName: 'Zagora',
190
- street: 'George St',
191
- city: 'Sydney',
192
- };
193
-
194
- var validator = new ZSchema();
195
-
196
- // compile & validate schemas first, z-schema will automatically handle array
197
- var allSchemasValid = validator.validateSchema(schemas);
198
- // allSchemasValid === true
199
-
200
- // now validate our data against the last schema
201
- var valid = validator.validate(data, schemas[2]);
202
- // valid === true
203
- ```
204
-
205
- ## Register a custom format
206
-
207
- You can register any format of your own. Your sync validator function should always respond with a boolean:
208
-
209
- ```javascript
210
- ZSchema.registerFormat('xstring', function (str) {
211
- return str === 'xxx';
212
- });
213
- ```
214
-
215
- Async format validators are also supported, they should accept two arguments, value and a callback to which they need to respond:
216
-
217
- ```javascript
218
- ZSchema.registerFormat('xstring', function (str, callback) {
219
- setTimeout(function () {
220
- callback(str === 'xxx');
221
- }, 1);
222
- });
223
- ```
224
-
225
- ### Helper method to check the formats that have been registered
226
-
227
- ```javascript
228
- var registeredFormats = ZSchema.getRegisteredFormats();
229
- //registeredFormats will now contain an array of all formats that have been registered with z-schema
230
- ```
231
-
232
- ### Automatic downloading of remote schemas
233
-
234
- Automatic downloading of remote schemas was removed from version `3.x` but is still possible with a bit of extra code,
235
- see [this test](test/spec/AutomaticSchemaLoadingSpec.js) for more information on this.
236
-
237
- ### Prefill default values to object using format
238
-
239
- Using format, you can pre-fill values of your choosing into the objects like this:
240
-
241
- ```javascript
242
- ZSchema.registerFormat('fillHello', function (obj) {
243
- obj.hello = 'world';
244
- return true;
245
- });
246
-
247
- var data = {};
248
-
249
- var schema = {
250
- type: 'object',
251
- format: 'fillHello',
252
- };
253
-
254
- validator.validate(data, schema);
255
- // data.hello === "world"
256
- ```
257
-
258
- ### Unicode Property Escapes Support
259
-
260
- Fully supports [Unicode property escapes](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_expressions/Unicode_property_escapes) in JSON Schema `pattern` values (e.g., `/\p{L}/u`). This allows you to write patterns that match Unicode character properties, such as letters, numbers, or scripts, provided your JavaScript environment supports them (Node.js ≥ 10, all modern browsers).
261
-
262
- **Example:**
263
-
264
- ```json
265
- {
266
- "type": "string",
267
- "pattern": "^\\p{L}+$" // matches only Unicode letters
268
- }
269
- ```
270
-
271
- z-schema will automatically use the `u` (Unicode) flag for all patterns containing Unicode property escapes, both in Node.js and browser environments. If your environment does not support Unicode property escapes, such patterns will be reported as invalid.
127
+ See [FEATURES.md](FEATURES.md) for a full list of features.
272
128
 
273
129
  ## Options
274
130
 
275
- ### asyncTimeout
276
-
277
- Defines a time limit, which should be used when waiting for async tasks like async format validators to perform their validation,
278
- before the validation fails with an `ASYNC_TIMEOUT` error.
279
-
280
- ```javascript
281
- var validator = new ZSchema({
282
- asyncTimeout: 2000,
283
- });
284
- ```
285
-
286
- ### noEmptyArrays
287
-
288
- When true, validator will assume that minimum count of items in any `array` is 1, except when `minItems: 0` is explicitly defined.
289
-
290
- ```javascript
291
- var validator = new ZSchema({
292
- noEmptyArrays: true,
293
- });
294
- ```
295
-
296
- ### noEmptyStrings
297
-
298
- When true, validator will assume that minimum length of any string to pass type `string` validation is 1, except when `minLength: 0` is explicitly defined.
299
-
300
- ```javascript
301
- var validator = new ZSchema({
302
- noEmptyStrings: true,
303
- });
304
- ```
305
-
306
- ### noTypeless
307
-
308
- When true, validator will fail validation for schemas that don't specify a `type` of object that they expect.
309
-
310
- ```javascript
311
- var validator = new ZSchema({
312
- noTypeless: true,
313
- });
314
- ```
315
-
316
- ### noExtraKeywords
317
-
318
- When true, validator will fail for schemas that use keywords not defined in JSON Schema specification and doesn't provide a parent schema in `$schema` property to validate the schema.
319
-
320
- ```javascript
321
- var validator = new ZSchema({
322
- noExtraKeywords: true,
323
- });
324
- ```
325
-
326
- ### assumeAdditional
131
+ See [OPTIONS.md](OPTIONS.md) for all available options and their descriptions.
327
132
 
328
- When true, validator assumes that additionalItems/additionalProperties are defined as false so you don't have to manually fix all your schemas.
329
-
330
- ```javascript
331
- var validator = new ZSchema({
332
- assumeAdditional: true,
333
- });
334
- ```
335
-
336
- When an array, validator assumes that additionalItems/additionalProperties are defined as false, but allows some properties to pass.
337
-
338
- ```javascript
339
- var validator = new ZSchema({
340
- assumeAdditional: ['$ref'],
341
- });
342
- ```
343
-
344
- ### forceAdditional
345
-
346
- When true, validator doesn't validate schemas where additionalItems/additionalProperties should be defined to either true or false.
347
-
348
- ```javascript
349
- var validator = new ZSchema({
350
- forceAdditional: true,
351
- });
352
- ```
353
-
354
- ### forceItems
355
-
356
- When true, validator doesn't validate schemas where `items` are not defined for `array` type schemas.
357
- This is to avoid passing anything through an array definition.
358
-
359
- ```javascript
360
- var validator = new ZSchema({
361
- forceItems: true,
362
- });
363
- ```
364
-
365
- ### forceMinItems
366
-
367
- When true, validator doesn't validate schemas where `minItems` is not defined for `array` type schemas.
368
- This is to avoid passing zero-length arrays which application doesn't expect to handle.
369
-
370
- ```javascript
371
- var validator = new ZSchema({
372
- forceMinItems: true,
373
- });
374
- ```
375
-
376
- ### forceMaxItems
377
-
378
- When true, validator doesn't validate schemas where `maxItems` is not defined for `array` type schemas.
379
- This is to avoid passing arrays with unlimited count of elements which application doesn't expect to handle.
380
-
381
- ```javascript
382
- var validator = new ZSchema({
383
- forceMaxItems: true,
384
- });
385
- ```
386
-
387
- ### forceMinLength
388
-
389
- When true, validator doesn't validate schemas where `minLength` is not defined for `string` type schemas.
390
- This is to avoid passing zero-length strings which application doesn't expect to handle.
391
-
392
- ```javascript
393
- var validator = new ZSchema({
394
- forceMinLength: true,
395
- });
396
- ```
397
-
398
- ### forceMaxLength
399
-
400
- When true, validator doesn't validate schemas where `maxLength` is not defined for `string` type schemas.
401
- This is to avoid passing extremly large strings which application doesn't expect to handle.
402
-
403
- ```javascript
404
- var validator = new ZSchema({
405
- forceMaxLength: true,
406
- });
407
- ```
408
-
409
- ### forceProperties
410
-
411
- When true, validator doesn't validate schemas where `properties` or `patternProperties` is not defined for `object` type schemas.
412
- This is to avoid having objects with unexpected properties in application.
413
-
414
- ```javascript
415
- var validator = new ZSchema({
416
- forceProperties: true,
417
- });
418
- ```
419
-
420
- ### ignoreUnresolvableReferences
421
-
422
- When true, validator doesn't end with error when a remote reference is unreachable. **This setting is not recommended in production outside of testing.**
423
-
424
- ```javascript
425
- var validator = new ZSchema({
426
- ignoreUnresolvableReferences: true,
427
- });
428
- ```
429
-
430
- ### enumCaseInsensitiveComparison
431
-
432
- When true, validator will return a `ENUM_CASE_MISMATCH` when the enum values mismatch only in case.
433
-
434
- ```javascript
435
- var validator = new ZSchema({
436
- enumCaseInsensitiveComparison: true,
437
- });
438
- ```
439
-
440
- ### strictUris
441
-
442
- When true, all strings of format `uri` must be an absolute URIs and not only URI references. See more details in [this issue](https://github.com/zaggino/z-schema/issues/18).
443
-
444
- ```javascript
445
- var validator = new ZSchema({
446
- strictUris: true,
447
- });
448
- ```
449
-
450
- ### strictMode
451
-
452
- Strict mode of z-schema is currently equal to the following:
453
-
454
- ```javascript
455
- if (this.options.strictMode === true) {
456
- this.options.forceAdditional = true;
457
- this.options.forceItems = true;
458
- this.options.forceMaxLength = true;
459
- this.options.forceProperties = true;
460
- this.options.noExtraKeywords = true;
461
- this.options.noTypeless = true;
462
- this.options.noEmptyStrings = true;
463
- this.options.noEmptyArrays = true;
464
- }
465
- ```
466
-
467
- ```javascript
468
- var validator = new ZSchema({
469
- strictMode: true,
470
- });
471
- ```
472
-
473
- ### breakOnFirstError
474
-
475
- default: `false`<br />
476
- When true, will stop validation after the first error is found:
477
-
478
- ```javascript
479
- var validator = new ZSchema({
480
- breakOnFirstError: true,
481
- });
482
- ```
483
-
484
- ### reportPathAsArray
485
-
486
- Report error paths as an array of path segments instead of a string:
487
-
488
- ```javascript
489
- var validator = new ZSchema({
490
- reportPathAsArray: true,
491
- });
492
- ```
493
-
494
- ### ignoreUnknownFormats
495
-
496
- By default, z-schema reports all unknown formats, formats not defined by JSON Schema and not registered using
497
- `ZSchema.registerFormat`, as an error. But the
498
- [JSON Schema specification](http://json-schema.org/latest/json-schema-validation.html#anchor106) says that validator
499
- implementations _"they SHOULD offer an option to disable validation"_ for `format`. That being said, setting this
500
- option to `true` will disable treating unknown formats as errlrs
501
-
502
- ```javascript
503
- var validator = new ZSchema({
504
- ignoreUnknownFormats: true,
505
- });
506
- ```
507
-
508
- ### includeErrors
509
-
510
- By default, z-schema reports all errors. If interested only in a subset of the errors, passing the option `includeErrors` to `validate` will perform validations only for those errors.
511
-
512
- ```javascript
513
- var validator = new ZSchema();
514
- // will only execute validation for "INVALID_TYPE" error.
515
- validator.validate(json, schema, { includeErrors: ['INVALID_TYPE'] });
516
- ```
517
-
518
- ### customValidator
519
-
520
- **Warning**: Use only if know what you are doing. Always consider using [custom format](#register-a-custom-format) before using this option.
521
-
522
- Register function to be called as part of validation process on every subshema encounter during validation.
523
-
524
- Let's make a real-life example with this feature.
525
- Imagine you have number of transactions:
526
-
527
- ```json
528
- {
529
- "fromId": 1034834329,
530
- "toId": 1034834543,
531
- "amount": 200
532
- }
533
- ```
534
-
535
- So you write the schema:
536
-
537
- ```json
538
- {
539
- "type": "object",
540
- "properties": {
541
- "fromId": {
542
- "type": "integer"
543
- },
544
- "toId": {
545
- "type": "integer"
546
- },
547
- "amount": {
548
- "type": "number"
549
- }
550
- }
551
- }
552
- ```
553
-
554
- But how to check that `fromId` and `toId` are never equal.
555
- In JSON Schema Draft4 there is no possibility to do this.
556
- Actually, it's easy to just write validation code for such simple payloads.
557
- But what if you have to do the same check for many objects in different places of JSON payload.
558
- One solution is to add custom keyword `uniqueProperties` with array of property names as a value. So in our schema we would need to add:
559
-
560
- ```json
561
- "uniqueProperties": [
562
- "fromId",
563
- "toId"
564
- ]
565
- ```
566
-
567
- To teach `z-schema` about this new keyword we need to write handler for it:
568
-
569
- ```javascript
570
- function customValidatorFn(report, schema, json) {
571
- // check if our custom property is present
572
- if (Array.isArray(schema.uniqueProperties)) {
573
- var seenValues = [];
574
- schema.uniqueProperties.forEach(function (prop) {
575
- var value = json[prop];
576
- if (typeof value !== 'undefined') {
577
- if (seenValues.indexOf(value) !== -1) {
578
- // report error back to z-schema core
579
- report.addCustomError(
580
- 'NON_UNIQUE_PROPERTY_VALUE',
581
- 'Property "{0}" has non-unique value: {1}',
582
- [prop, value],
583
- null,
584
- schema.description
585
- );
586
- }
587
- seenValues.push(value);
588
- }
589
- });
590
- }
591
- }
592
-
593
- var validator = new ZSchema({
594
- // register our custom validator inside z-schema
595
- customValidator: customValidatorFn,
596
- });
597
- ```
598
-
599
- Let's test it:
600
-
601
- ```javascript
602
- var data = {
603
- fromId: 1034834346,
604
- toId: 1034834346,
605
- amount: 50,
606
- };
607
-
608
- validator.validate(data, schema);
609
- console.log(validator.getLastErrors());
610
- //[ { code: 'NON_UNIQUE_PROPERTY_VALUE',
611
- // params: [ 'toId', 1034834346 ],
612
- // message: 'Property "toId" has non-unique value: 1034834346',
613
- // path: '#/',
614
- // schemaId: undefined } ]
615
- ```
616
-
617
- **Note:** before creating your own keywords you should consider all compatibility issues.
618
-
619
- ## Contributing:
133
+ ## Contributing
620
134
 
621
135
  These repository has several submodules and should be cloned as follows:
622
136
 
@@ -624,9 +138,233 @@ These repository has several submodules and should be cloned as follows:
624
138
 
625
139
  ## Contributors
626
140
 
627
- Thanks for contributing to:
628
-
629
- - [Jeremy Whitlock](https://github.com/whitlockjc)
630
- - [Oleksiy Krivoshey](https://github.com/oleksiyk)
141
+ Big thanks to:
142
+
143
+ <!-- readme: contributors -start -->
144
+ <table>
145
+ <tbody>
146
+ <tr>
147
+ <td align="center">
148
+ <a href="https://github.com/zaggino">
149
+ <img src="https://avatars.githubusercontent.com/u/1067319?v=4" width="100;" alt="zaggino"/>
150
+ <br />
151
+ <sub><b>Martin Zagora</b></sub>
152
+ </a>
153
+ </td>
154
+ <td align="center">
155
+ <a href="https://github.com/sergey-shandar">
156
+ <img src="https://avatars.githubusercontent.com/u/902339?v=4" width="100;" alt="sergey-shandar"/>
157
+ <br />
158
+ <sub><b>Sergey Shandar</b></sub>
159
+ </a>
160
+ </td>
161
+ <td align="center">
162
+ <a href="https://github.com/IvanGoncharov">
163
+ <img src="https://avatars.githubusercontent.com/u/8336157?v=4" width="100;" alt="IvanGoncharov"/>
164
+ <br />
165
+ <sub><b>Ivan Goncharov</b></sub>
166
+ </a>
167
+ </td>
168
+ <td align="center">
169
+ <a href="https://github.com/pgonzal">
170
+ <img src="https://avatars.githubusercontent.com/u/47177787?v=4" width="100;" alt="pgonzal"/>
171
+ <br />
172
+ <sub><b>Pete Gonzalez (OLD ALIAS)</b></sub>
173
+ </a>
174
+ </td>
175
+ <td align="center">
176
+ <a href="https://github.com/simon-p-r">
177
+ <img src="https://avatars.githubusercontent.com/u/4668724?v=4" width="100;" alt="simon-p-r"/>
178
+ <br />
179
+ <sub><b>Simon R</b></sub>
180
+ </a>
181
+ </td>
182
+ <td align="center">
183
+ <a href="https://github.com/TheToolbox">
184
+ <img src="https://avatars.githubusercontent.com/u/2837017?v=4" width="100;" alt="TheToolbox"/>
185
+ <br />
186
+ <sub><b>Jason Oettinger</b></sub>
187
+ </a>
188
+ </td>
189
+ </tr>
190
+ <tr>
191
+ <td align="center">
192
+ <a href="https://github.com/whitlockjc">
193
+ <img src="https://avatars.githubusercontent.com/u/98899?v=4" width="100;" alt="whitlockjc"/>
194
+ <br />
195
+ <sub><b>Jeremy Whitlock</b></sub>
196
+ </a>
197
+ </td>
198
+ <td align="center">
199
+ <a href="https://github.com/epoberezkin">
200
+ <img src="https://avatars.githubusercontent.com/u/2769109?v=4" width="100;" alt="epoberezkin"/>
201
+ <br />
202
+ <sub><b>Evgeny</b></sub>
203
+ </a>
204
+ </td>
205
+ <td align="center">
206
+ <a href="https://github.com/toofishes">
207
+ <img src="https://avatars.githubusercontent.com/u/265817?v=4" width="100;" alt="toofishes"/>
208
+ <br />
209
+ <sub><b>Dan McGee</b></sub>
210
+ </a>
211
+ </td>
212
+ <td align="center">
213
+ <a href="https://github.com/antialias">
214
+ <img src="https://avatars.githubusercontent.com/u/447517?v=4" width="100;" alt="antialias"/>
215
+ <br />
216
+ <sub><b>Thomas Hallock</b></sub>
217
+ </a>
218
+ </td>
219
+ <td align="center">
220
+ <a href="https://github.com/kallaspriit">
221
+ <img src="https://avatars.githubusercontent.com/u/277993?v=4" width="100;" alt="kallaspriit"/>
222
+ <br />
223
+ <sub><b>Priit Kallas</b></sub>
224
+ </a>
225
+ </td>
226
+ <td align="center">
227
+ <a href="https://github.com/santam85">
228
+ <img src="https://avatars.githubusercontent.com/u/2706307?v=4" width="100;" alt="santam85"/>
229
+ <br />
230
+ <sub><b>Marco Santarelli</b></sub>
231
+ </a>
232
+ </td>
233
+ </tr>
234
+ <tr>
235
+ <td align="center">
236
+ <a href="https://github.com/Hirse">
237
+ <img src="https://avatars.githubusercontent.com/u/2564094?v=4" width="100;" alt="Hirse"/>
238
+ <br />
239
+ <sub><b>Jan Pilzer</b></sub>
240
+ </a>
241
+ </td>
242
+ <td align="center">
243
+ <a href="https://github.com/geraintluff">
244
+ <img src="https://avatars.githubusercontent.com/u/1957191?v=4" width="100;" alt="geraintluff"/>
245
+ <br />
246
+ <sub><b>Geraint</b></sub>
247
+ </a>
248
+ </td>
249
+ <td align="center">
250
+ <a href="https://github.com/dgerber">
251
+ <img src="https://avatars.githubusercontent.com/u/393344?v=4" width="100;" alt="dgerber"/>
252
+ <br />
253
+ <sub><b>Daniel Gerber</b></sub>
254
+ </a>
255
+ </td>
256
+ <td align="center">
257
+ <a href="https://github.com/addaleax">
258
+ <img src="https://avatars.githubusercontent.com/u/899444?v=4" width="100;" alt="addaleax"/>
259
+ <br />
260
+ <sub><b>Anna Henningsen</b></sub>
261
+ </a>
262
+ </td>
263
+ <td align="center">
264
+ <a href="https://github.com/mctep">
265
+ <img src="https://avatars.githubusercontent.com/u/1949681?v=4" width="100;" alt="mctep"/>
266
+ <br />
267
+ <sub><b>Konstantin Vasilev</b></sub>
268
+ </a>
269
+ </td>
270
+ <td align="center">
271
+ <a href="https://github.com/barrtender">
272
+ <img src="https://avatars.githubusercontent.com/u/3101221?v=4" width="100;" alt="barrtender"/>
273
+ <br />
274
+ <sub><b>barrtender</b></sub>
275
+ </a>
276
+ </td>
277
+ </tr>
278
+ <tr>
279
+ <td align="center">
280
+ <a href="https://github.com/RomanHotsiy">
281
+ <img src="https://avatars.githubusercontent.com/u/3975738?v=4" width="100;" alt="RomanHotsiy"/>
282
+ <br />
283
+ <sub><b>Roman Hotsiy</b></sub>
284
+ </a>
285
+ </td>
286
+ <td align="center">
287
+ <a href="https://github.com/sauvainr">
288
+ <img src="https://avatars.githubusercontent.com/u/1715747?v=4" width="100;" alt="sauvainr"/>
289
+ <br />
290
+ <sub><b>RenaudS</b></sub>
291
+ </a>
292
+ </td>
293
+ <td align="center">
294
+ <a href="https://github.com/figadore">
295
+ <img src="https://avatars.githubusercontent.com/u/3253971?v=4" width="100;" alt="figadore"/>
296
+ <br />
297
+ <sub><b>Reese</b></sub>
298
+ </a>
299
+ </td>
300
+ <td align="center">
301
+ <a href="https://github.com/MattiSG">
302
+ <img src="https://avatars.githubusercontent.com/u/222463?v=4" width="100;" alt="MattiSG"/>
303
+ <br />
304
+ <sub><b>Matti Schneider</b></sub>
305
+ </a>
306
+ </td>
307
+ <td align="center">
308
+ <a href="https://github.com/sandersky">
309
+ <img src="https://avatars.githubusercontent.com/u/422902?v=4" width="100;" alt="sandersky"/>
310
+ <br />
311
+ <sub><b>Matthew Dahl</b></sub>
312
+ </a>
313
+ </td>
314
+ <td align="center">
315
+ <a href="https://github.com/jfromaniello">
316
+ <img src="https://avatars.githubusercontent.com/u/178512?v=4" width="100;" alt="jfromaniello"/>
317
+ <br />
318
+ <sub><b>José F. Romaniello</b></sub>
319
+ </a>
320
+ </td>
321
+ </tr>
322
+ <tr>
323
+ <td align="center">
324
+ <a href="https://github.com/KEIII">
325
+ <img src="https://avatars.githubusercontent.com/u/1167833?v=4" width="100;" alt="KEIII"/>
326
+ <br />
327
+ <sub><b>Ivan Kasenkov</b></sub>
328
+ </a>
329
+ </td>
330
+ <td align="center">
331
+ <a href="https://github.com/HanOterLin">
332
+ <img src="https://avatars.githubusercontent.com/u/21137108?v=4" width="100;" alt="HanOterLin"/>
333
+ <br />
334
+ <sub><b>Tony Lin</b></sub>
335
+ </a>
336
+ </td>
337
+ <td align="center">
338
+ <a href="https://github.com/domoritz">
339
+ <img src="https://avatars.githubusercontent.com/u/589034?v=4" width="100;" alt="domoritz"/>
340
+ <br />
341
+ <sub><b>Dominik Moritz</b></sub>
342
+ </a>
343
+ </td>
344
+ <td align="center">
345
+ <a href="https://github.com/Semigradsky">
346
+ <img src="https://avatars.githubusercontent.com/u/1198848?v=4" width="100;" alt="Semigradsky"/>
347
+ <br />
348
+ <sub><b>Dmitry Semigradsky</b></sub>
349
+ </a>
350
+ </td>
351
+ <td align="center">
352
+ <a href="https://github.com/countcain">
353
+ <img src="https://avatars.githubusercontent.com/u/1751150?v=4" width="100;" alt="countcain"/>
354
+ <br />
355
+ <sub><b>Tao Huang</b></sub>
356
+ </a>
357
+ </td>
358
+ <td align="center">
359
+ <a href="https://github.com/BuBuaBu">
360
+ <img src="https://avatars.githubusercontent.com/u/3825745?v=4" width="100;" alt="BuBuaBu"/>
361
+ <br />
362
+ <sub><b>BuBuaBu</b></sub>
363
+ </a>
364
+ </td>
365
+ </tr>
366
+ <tbody>
367
+ </table>
368
+ <!-- readme: contributors -end -->
631
369
 
632
370
  and to everyone submitting [issues](https://github.com/zaggino/z-schema/issues) on GitHub