@jetio/validator 1.0.2 → 1.0.3

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
@@ -363,28 +363,14 @@ For transparency, here are the keywords jet-validator intentionally does not sup
363
363
 
364
364
  ### Summary
365
365
 
366
- - **Compilation:** 10-27x faster than AJV (1.33ms vs 13.20ms average)
367
- - **Valid data validation:** 7% faster overall (2.44M vs 2.28M ops/sec)
368
- - **Invalid data validation:** 24% faster overall (4.15M vs 3.36M ops/sec)
369
- - **Win rate:** 49.2% on valid data, 66.2% on invalid data
370
- - **Overall winner:** 71.8% of all benchmarks
366
+ 🚀 **Compilation:** 19x faster (1.47ms vs 28.29ms)
367
+ **Valid Data:** 58% win rate (36/62)
368
+ 🛡️ **Invalid Data:** 73% win rate (45/62)
369
+ 🏆 **Overall:** 72% win rate (89/124)
371
370
 
372
- **Key Wins:**
371
+ [📊 Full Benchmark Report](https://github.com/official-jetio/validator/blob/main/benchmarks/results/COMPARISON.md) | [📈 Detailed Results](https://github.com/official-jetio/validator/tree/main/benchmarks/results/)
373
372
 
374
- - Composition operations: 240-284% faster
375
- - Pattern matching: Up to 88% faster
376
- - Integer validation: 48-120% faster
377
- - Object validation at scale: 28-51% faster
378
-
379
- **Where AJV leads:**
380
-
381
- - Deeply chained $refs: 88% faster
382
- - Deep allOf chains: 68% faster
383
- - Complex conditionals: 36% faster
384
-
385
- [📊 Full Benchmark Report](https://github.com/official-jetio/validator/blob/main/benchmark/results/COMPARISON.md) | [📈 Detailed Results](https://github.com/official-jetio/validator/tree/main/benchmark/results/)
386
-
387
- _Tested against AJV v8.17.1 using official benchmarks with 65 schemas, 1000 warmups, 10000 iterations, 5 runs per test_
373
+ _Tested against AJV v8.17.1 using official benchmarks with 65 schemas, 1000 warmups, 10000 iterations, 30 runs per test_
388
374
 
389
375
  ---
390
376
 
@@ -888,7 +874,6 @@ len_of("café"); // 4
888
874
 
889
875
  **Use case:** Validating `minLength`/`maxLength` for strings with emoji or special Unicode characters.
890
876
 
891
- **→ [See Full Utilities API Reference](https://github.com/official-jetio/validator/blob/main/DOCUMENTATION.md#utilities-api)**
892
877
 
893
878
  ---
894
879
 
@@ -910,18 +895,16 @@ const validate = jetValidator.compile(schema);
910
895
 
911
896
  **Benefits of switching:**
912
897
 
913
- - ⚡ 10-27x faster compilation
898
+ - ⚡ 19x faster compilation
914
899
  - 📦 Smaller bundle size
915
- - 🎯 Built-in formats (no separate packages)
900
+ - 🎯 Built-in formats and error messages (no separate packages)
916
901
  - ✨ Enhanced features (`elseIf`, better `$data`)
917
902
 
918
903
  **What's different:**
919
904
 
920
- - Error object structure (but more detailed)
921
- - Custom keywords use different API (more powerful)
922
- - Meta-schema setup is easier
923
-
924
- **→ [See Migration Guide](https://github.com/official-jetio/validator/blob/main/DOCUMENTATION.md#migration-from-ajv)**
905
+ - Error object structure
906
+ - Custom keywords use different API
907
+ - Meta-schema setup with cli
925
908
 
926
909
  ---
927
910
 
@@ -939,7 +922,7 @@ const validate = jetValidator.compile(schema);
939
922
  ### Consider Alternatives If:
940
923
 
941
924
  ⚠️ You need 100% JSON Schema spec compliance (we're at 99.5%)
942
- ⚠️ You're already heavily invested in AJV ecosystem with custom plugins (we offer the same custom keywords but contexts are simpler and different, although much more easy to use and better)
925
+ ⚠️ You're already heavily invested in AJV ecosystem with custom plugins (we offer the same custom keywords but contexts are simpler and different, although much more easy to use)
943
926
  ⚠️ You need streaming validation for extremely large documents
944
927
 
945
928
  ---
@@ -951,7 +934,7 @@ const validate = jetValidator.compile(schema);
951
934
  jet-validator eliminates infinite recursion through a unique resolution approach. Unlike other validators that resolve references during traversal (causing stack overflow), jet-validator:
952
935
 
953
936
  1. **Collects** all references and identifiers
954
- 2. **Assigns** unique function names to each location
937
+ 2. **Assigns** unique function names to each location when inlining is impossible
955
938
  3. **Resolves** references by replacing them with function calls
956
939
 
957
940
  This architecture enables both lightning-fast compilation and bulletproof circular reference handling.
@@ -965,14 +948,14 @@ This architecture enables both lightning-fast compilation and bulletproof circul
965
948
  Traditional validators:
966
949
 
967
950
  ```typescript
968
- // Slow: 20ms per compilation
951
+ // Slow: 10-20ms per compilation
969
952
  const validate = ajv.compile(schema); // Must cache!
970
953
  ```
971
954
 
972
955
  jet-validator:
973
956
 
974
957
  ```typescript
975
- // Fast: 1-2ms per compilation
958
+ // Fast: 0.7ms per compilation
976
959
  const validate = jetValidator.compile(schema); // Can recompile!
977
960
  ```
978
961
 
@@ -1141,7 +1124,7 @@ We welcome contributions! jet-validator is a community project and we appreciate
1141
1124
  ```bash
1142
1125
  # Clone the repo
1143
1126
  git clone https://github.com/official-jetio/validator
1144
- cd jet-validator
1127
+ cd validator
1145
1128
 
1146
1129
  # Install dependencies
1147
1130
  npm install
@@ -1159,8 +1142,7 @@ npm run test:draft6
1159
1142
  npm run test
1160
1143
 
1161
1144
  # Run benchmarks
1162
- npm run benchmark
1163
- npm run benchmark:compare
1145
+ node --expose-gc --max-old-space-size=4096 --max-semi-space-size=64 benchmarks/jet-validator-benchmark.js
1164
1146
  ```
1165
1147
 
1166
1148
  ### Testing Philosophy
@@ -1174,7 +1156,7 @@ jet-validator uses the official [JSON Schema Test Suite](https://github.com/json
1174
1156
  3. Run the official test suite: `npm run test:draft2020-12` (or appropriate draft)
1175
1157
  4. Check compliance rate - aim to maintain or improve current 99.5%+ compliance
1176
1158
 
1177
- **The test runner** (`tests/test-runner.ts`) validates against:
1159
+ **The test runner** (`tests/test.ts`) validates against:
1178
1160
 
1179
1161
  - 1,261+ tests for Draft 2020-12
1180
1162
  - 1,227+ tests for Draft 2019-09
@@ -1294,23 +1276,10 @@ We track bugs and feature requests using GitHub Issues.
1294
1276
  ---
1295
1277
 
1296
1278
  ## ⚠️ Benchmark Methodology & Hardware Notes
1297
-
1298
- The benchmarks took hours to run due to laptop hardware and the billions of operations performed. The `array100KItems` benchmark alone—validating 100K array items with 1,000 warmups, 10,000 iterations, and 5 runs—was particularly intensive.
1299
-
1300
1279
  **Performance on Better Hardware:**
1301
1280
 
1302
1281
  Results will vary significantly on better hardware. While absolute numbers will improve across the board, jet-validator is expected to maintain its performance advantages, especially in compilation speed.
1303
1282
 
1304
- **Implementation Differences:**
1305
-
1306
- Unlike AJV, jet-validator doesn't inline `$ref`s by default. This design choice:
1307
-
1308
- - Reduces code bloat
1309
- - Enables proper tracing for `unevaluatedItems`/`unevaluatedProperties`
1310
- - Maintains cleaner stack traces for debugging
1311
-
1312
- Optional inlining is a feature we plan to add in the future for users who prefer maximum runtime performance over bundle size.
1313
-
1314
1283
  ---
1315
1284
 
1316
1285
  ## 🏆 Conclusion
@@ -1318,11 +1287,10 @@ Optional inlining is a feature we plan to add in the future for users who prefer
1318
1287
  jet-validator has proven itself as a strong contender for JSON Schema validation in the Node.js ecosystem, offering:
1319
1288
 
1320
1289
  ✅ **99.5% JSON Schema compliance** - More spec-compliant than AJV in many areas
1321
- **10-27x faster compilation** - Game-changer for serverless
1322
- ✅ **7% faster valid data** - Better average throughput
1323
- **24% faster invalid data** - Better security posture
1324
- **49% valid win rate** - More common-case wins
1325
- ✅ **66% invalid win rate** - Dominant error detection
1290
+ 🚀 **Compilation:** 19x faster (1.47ms vs 28.29ms) on average - Game-changer for serverless
1291
+ ✅ **Valid Data:** 58% win rate (36/62)
1292
+ 🛡️ **Invalid Data:** 73% win rate (45/62)
1293
+ 🏆 **Overall:** 72% win rate (89/124)
1326
1294
 
1327
1295
  **jet-validator is the clear choice for:**
1328
1296
 
@@ -1331,12 +1299,10 @@ jet-validator has proven itself as a strong contender for JSON Schema validation
1331
1299
  - Real-world schema validation
1332
1300
  - Applications requiring fast compilation
1333
1301
  - Security-focused applications (invalid data detection)
1334
-
1335
- **Consider AJV for:**
1336
-
1337
- - Extremely deep composition chains (>10 levels)
1338
1302
  - Heavy reliance on complex $ref graphs
1339
1303
  - Schemas with complex conditional logic
1304
+ - Extremely deep composition chains (>10 levels)
1305
+
1340
1306
 
1341
1307
  ---
1342
1308
 
@@ -1355,7 +1321,7 @@ MIT © [Great Venerable](https://github.com/greatvenerable)
1355
1321
  - **[npm Package](https://www.npmjs.com/package/@jetio/validator)**
1356
1322
  - **[GitHub Repository](https://github.com/@jetio/validator)**
1357
1323
  - **[Complete Documentation (20k+ lines)](https://github.com/official-jetio/validator/blob/main/DOCUMENTATION.md)**
1358
- - **[Benchmark Results](https://github.com/official-jetio/validator/blob/main/benchmark/results/COMPARISON.md)**
1324
+ - **[Benchmark Results](https://github.com/official-jetio/validator/blob/main/benchmarks/results/COMPARISON.md)**
1359
1325
  - **[Issue Tracker](https://github.com/official-jetio/validator/issues)**
1360
1326
  - **[GitHub Discussions](https://github.com/official-jetio/validator/discussions)**
1361
1327
 
@@ -66,7 +66,6 @@ export declare class Compiler {
66
66
  private jetValidator;
67
67
  private notLogic;
68
68
  private noreturn;
69
- private neutralError;
70
69
  private compileContext;
71
70
  private standAlone;
72
71
  private hasCompileKeyword;
@@ -113,7 +113,6 @@ class Compiler {
113
113
  this.validateKeywords = new Set();
114
114
  this.notLogic = false;
115
115
  this.noreturn = false;
116
- this.neutralError = false;
117
116
  this.standAlone = false;
118
117
  this.hasCompileKeyword = false;
119
118
  this.needslen_of = false;
@@ -306,11 +305,10 @@ class Compiler {
306
305
  return src.join("");
307
306
  }
308
307
  const schema = rootSchema;
309
- const varName = (schema.default === undefined || !this.options.useDefaults) &&
310
- !this.options.removeAdditional &&
311
- !this.options.coerceTypes
308
+ const varName = accessPattern === "rootData" ||
309
+ (inlined && (schema.default === undefined || !this.options.useDefaults))
312
310
  ? accessPattern
313
- : "var" + counter++;
311
+ : "jv" + counter++;
314
312
  this.initializeDefault(src, schema, varName, accessPattern, inlined);
315
313
  let shouldTrackProps;
316
314
  let shouldTrackItems;
@@ -354,11 +352,16 @@ class Compiler {
354
352
  return src.join("");
355
353
  }
356
354
  initializeDefault(src, schema, varName, accessPattern, inlined) {
357
- if (schema.default !== undefined && this.options.useDefaults) {
358
- src.push(`let ${varName} = ${accessPattern};`, `if (${varName} === undefined || ${varName} === null) {`, `${varName} = ${JSON.stringify(schema.default)};`, "}");
359
- }
360
- else if (this.options.removeAdditional || this.options.coerceTypes) {
361
- src.push(`let ${varName} = ${accessPattern};`);
355
+ if (accessPattern !== "rootData") {
356
+ if (schema.default !== undefined && this.options.useDefaults) {
357
+ src.push(`let ${varName} = ${accessPattern};`, `if (${varName} === undefined || ${varName} === null) {`, `${varName} = ${JSON.stringify(schema.default)};`, "}");
358
+ }
359
+ else if (!inlined) {
360
+ const keyword = this.options.removeAdditional || this.options.coerceTypes
361
+ ? "let"
362
+ : "const";
363
+ src.push(`${keyword} ${varName} = ${accessPattern};`);
364
+ }
362
365
  }
363
366
  if (this.options.coerceTypes) {
364
367
  if (schema.type === "number" || schema.type === "integer") {
@@ -474,10 +477,20 @@ class Compiler {
474
477
  src.push(`if(${extra.before} true){`);
475
478
  src.push(`const ${funcValidator}Result = ${awaitPrefix}${schema.__functionName}${callArgs};`);
476
479
  if (this.options.allErrors) {
477
- src.push(`if (!${funcValidator}Result) {${this.errorVariable} = ${this.errorVariable}.concat(${schema.__functionName}.errors);${extra.refAfter || extra.after}}`);
480
+ src.push(`if (!${funcValidator}Result){${extra.after}${this.notLogic ? "" : `${this.errorVariable} = ${this.errorVariable}.concat(${schema.__functionName}.errors);`}}`);
478
481
  }
479
482
  else {
480
- src.push(`if (!${funcValidator}Result){${this.mainFunctionName}.errors = ${schema.__functionName}.errors;${extra.refAfter ?? extra.after}${this.noreturn ? "" : "return false;"}}`);
483
+ if (this.noreturn) {
484
+ src.push(`if (!${funcValidator}Result){${extra.after}${this.notLogic ? "" : `${schema.__functionName}.errors.length > 1 ? (${this.errorVariable} = ${this.errorVariable}.concat(${schema.__functionName}.errors)) : ${this.errorVariable}.push(${schema.__functionName}.errors[0]);`}}`);
485
+ }
486
+ else {
487
+ if (this.mainFunctionName === schema.__functionName) {
488
+ src.push(`if (!${funcValidator}Result){${this.notLogic ? extra.after : `return false;`}}`);
489
+ }
490
+ else {
491
+ src.push(`if (!${funcValidator}Result){${this.notLogic ? extra.after : `${this.mainFunctionName}.errors = ${schema.__functionName}.errors;return false;`}}`);
492
+ }
493
+ }
481
494
  }
482
495
  if (extra.before != "")
483
496
  src.push(`}`);
@@ -503,10 +516,20 @@ class Compiler {
503
516
  src.push(`if(${extra.before} true){`);
504
517
  src.push(`const ${refValidator}Result = ${awaitPrefix}${functionName}${callArgs};`);
505
518
  if (this.options.allErrors) {
506
- src.push(`if (!${refValidator}Result) {${this.errorVariable} = ${this.errorVariable}.concat(${functionName}.errors);${extra.refAfter || extra.after}}`);
519
+ src.push(`if (!${refValidator}Result){${extra.after}${this.notLogic ? "" : `${this.errorVariable} = ${this.errorVariable}.concat(${functionName}.errors);`}}`);
507
520
  }
508
521
  else {
509
- src.push(`if (!${refValidator}Result){${this.mainFunctionName}.errors = ${functionName}.errors;${extra.refAfter ?? extra.after}${this.noreturn ? "" : "return false;"}}`);
522
+ if (this.noreturn) {
523
+ src.push(`if (!${refValidator}Result){${extra.after}${this.notLogic ? "" : `${functionName}.errors.length > 1 ? (${this.errorVariable} = ${this.errorVariable}.concat(${functionName}.errors)) : ${this.errorVariable}.push(${functionName}.errors[0]);`}}`);
524
+ }
525
+ else {
526
+ if (this.mainFunctionName === functionName) {
527
+ src.push(`if (!${refValidator}Result){${this.notLogic ? extra.after : `return false;`}}`);
528
+ }
529
+ else {
530
+ src.push(`if (!${refValidator}Result){${this.notLogic ? extra.after : `${this.mainFunctionName}.errors = ${functionName}.errors;return false;`}}`);
531
+ }
532
+ }
510
533
  }
511
534
  if (extra.before != "")
512
535
  src.push(`}`);
@@ -525,12 +548,12 @@ class Compiler {
525
548
  return `(${args.join(", ")})`;
526
549
  }
527
550
  handleLogicalOperators(src, schema, varName, pathContext, trackingState, extra) {
551
+ if (schema.allOf)
552
+ this.handleAllOfOperator(src, schema, varName, pathContext, trackingState, extra);
528
553
  if (schema.not)
529
554
  this.handleNotOperator(src, schema, varName, pathContext, extra);
530
555
  if (schema.anyOf)
531
556
  this.handleAnyOfOperator(src, schema, varName, pathContext, trackingState, extra);
532
- if (schema.allOf)
533
- this.handleAllOfOperator(src, schema, varName, pathContext, trackingState, extra);
534
557
  if (schema.oneOf)
535
558
  this.handleOneOfOperator(src, schema, varName, pathContext, trackingState, extra);
536
559
  }
@@ -564,9 +587,12 @@ class Compiler {
564
587
  let firstLength = "";
565
588
  const anyOfValid = "anyOfValid" + counter++;
566
589
  src.push(`let ${anyOfValid} = false;`);
567
- const anyOfError = "anyOfErr" + counter++;
568
- if (!this.options.allErrors && !this.notLogic)
590
+ const anyOfError = this.noreturn
591
+ ? this.errorVariable
592
+ : "anyOfErr" + counter++;
593
+ if (!this.options.allErrors && !this.noreturn)
569
594
  src.push(`let ${anyOfError} = [];`);
595
+ const error = this.errorVariable;
570
596
  schema.anyOf.forEach((subSchema, index) => {
571
597
  const branch = `branch${counter++}Valid`;
572
598
  if (!this.options.allErrors)
@@ -577,24 +603,27 @@ class Compiler {
577
603
  const configs = this.createSubschemaOptions(trackingState, pathContext, `anyOf/${index}`, schema);
578
604
  configs.pathContext.alt = `${pathContext.schema}/anyOf/${index}`;
579
605
  configs.pathContext.alt2 = `${pathContext.schema}/anyOf`;
606
+ let errorCountVar = "anyErrCnt" + counter++;
580
607
  if (this.options.allErrors) {
581
608
  validatorFn = this.compileSchema(subSchema, configs.pathContext, configs.trackingState, varName, extra, true);
582
609
  }
583
610
  else {
611
+ this.errorVariable = anyOfError;
584
612
  validatorFn = this.compileSchema(subSchema, configs.pathContext, configs.trackingState, varName, {
585
613
  before: `${branch} && `,
586
- after: `${branch} = false;${this.notLogic ? "" : `${anyOfError}.push(${this.mainFunctionName}.errors[0]);`}`,
587
- refAfter: `${branch} = false;${this.notLogic ? "" : `${anyOfError} = ${anyOfError}.concat(${this.mainFunctionName}.errors);`}`,
614
+ after: `${branch} = false;`,
588
615
  }, true);
589
616
  }
590
- this.noreturn = noreturn;
591
- let errorCountVar;
592
617
  if (this.options.allErrors) {
593
- errorCountVar = "anyErrCnt" + counter++;
594
618
  src.push(`const ${errorCountVar} = ${this.errorVariable}.length;`);
595
619
  if (index === 0)
596
620
  firstLength = errorCountVar;
597
621
  }
622
+ else if (index === 0) {
623
+ src.push(`const ${errorCountVar} = ${this.errorVariable}.length;`);
624
+ firstLength = errorCountVar;
625
+ }
626
+ this.noreturn = noreturn;
598
627
  if (index > 0 &&
599
628
  !trackingState.shouldTrackEvaluatedProperties &&
600
629
  !trackingState.shouldTrackEvaluatedItems) {
@@ -629,27 +658,36 @@ class Compiler {
629
658
  }
630
659
  });
631
660
  if (this.options.allErrors) {
632
- src.push(`if (${anyOfValid}) {${this.errorVariable}.length = ${firstLength};}${extra.after != "" ? `else{${extra.after}}` : ""}`);
661
+ src.push(`if (${anyOfValid} && ${this.errorVariable}.length != ${firstLength}) {${this.errorVariable}.length = ${firstLength};}${extra.after != "" ? `else if(!${anyOfValid}){${extra.after}}` : ""}`);
633
662
  }
634
663
  else {
635
- src.push(`if (${anyOfValid}){${this.mainFunctionName}.errors = undefined}else {${this.notLogic ? "" : `${this.mainFunctionName}.errors = ${anyOfError};`}${extra.refAfter ?? extra.after}${this.noreturn ? "" : "return false;"}}`);
664
+ if (this.noreturn) {
665
+ src.push(`if (${anyOfValid} && ${this.errorVariable}.length != ${firstLength}){${this.errorVariable}.length = ${firstLength};}else if(!${anyOfValid}){${extra.after}}`);
666
+ }
667
+ else {
668
+ src.push(`if (${anyOfValid} && ${this.errorVariable}.length != ${firstLength}){${this.errorVariable}.length = ${firstLength};}else if(!${anyOfValid}){${this.notLogic ? extra.after : `${this.mainFunctionName}.errors = ${this.errorVariable};return false;`}}`);
669
+ }
670
+ this.errorVariable = error;
636
671
  }
637
672
  }
638
673
  handleOneOfOperator(src, schema, varName, pathContext, trackingState, extra) {
639
674
  if (!schema.oneOf)
640
675
  return;
641
676
  let firstLength = "";
642
- const oneOfErrors = `oneOfErrors${counter++}`;
677
+ const oneOfErrors = this.noreturn
678
+ ? this.errorVariable
679
+ : `oneOfErrors${counter++}`;
643
680
  const validSchemaCount = "validSchemaCount" + counter++;
644
681
  src.push(`let ${validSchemaCount} = 0;`);
645
- if (!this.options.allErrors)
682
+ if (!this.options.allErrors && !this.noreturn)
646
683
  src.push(`let ${oneOfErrors} = [];`);
684
+ const noreturn = this.noreturn;
685
+ const error = this.errorVariable;
647
686
  schema.oneOf.forEach((subSchema, index) => {
648
687
  const branch = `branch${counter++}Valid`;
649
- if (!this.options.allErrors && !this.notLogic)
688
+ if (!this.options.allErrors)
650
689
  src.push(`let ${branch} = true;`);
651
690
  let validatorFn;
652
- const noreturn = this.noreturn;
653
691
  this.noreturn = true;
654
692
  const configs = this.createSubschemaOptions(trackingState, pathContext, `oneOf/${index}`, schema);
655
693
  configs.pathContext.alt = `${pathContext.schema}/oneOf/${index}`;
@@ -658,20 +696,22 @@ class Compiler {
658
696
  validatorFn = this.compileSchema(subSchema, configs.pathContext, configs.trackingState, varName, extra, true);
659
697
  }
660
698
  else {
699
+ this.errorVariable = oneOfErrors;
661
700
  validatorFn = this.compileSchema(subSchema, configs.pathContext, configs.trackingState, varName, {
662
701
  before: `${branch} && `,
663
- after: `${branch} = false;${this.notLogic ? "" : `${oneOfErrors}.push(${this.mainFunctionName}.errors[0]);`}`,
664
- refAfter: `${branch} = false;${this.notLogic ? "" : `${oneOfErrors} = ${oneOfErrors}.concat(${this.mainFunctionName}.errors);`}`,
702
+ after: `${branch} = false;`,
665
703
  }, true);
666
704
  }
667
- this.noreturn = noreturn;
668
- let errorCountVar;
705
+ let errorCountVar = "oneErrCnt" + counter++;
669
706
  if (this.options.allErrors) {
670
- errorCountVar = "oneErrCnt" + counter;
671
707
  src.push(`const ${errorCountVar} = ${this.errorVariable}.length;`);
672
708
  if (index === 0)
673
709
  firstLength = errorCountVar;
674
710
  }
711
+ else if (index === 0) {
712
+ src.push(`const ${errorCountVar} = ${this.errorVariable}.length;`);
713
+ firstLength = errorCountVar;
714
+ }
675
715
  if (index > 0 &&
676
716
  !trackingState.shouldTrackEvaluatedProperties &&
677
717
  !trackingState.shouldTrackEvaluatedItems) {
@@ -706,7 +746,7 @@ class Compiler {
706
746
  }
707
747
  });
708
748
  if (this.options.allErrors) {
709
- src.push(`if (${validSchemaCount} == 1) {${this.errorVariable}.length = ${firstLength};} else{${this.buildErrorReturn(pathContext, {
749
+ src.push(`if (${validSchemaCount} == 1 && ${this.errorVariable}.length != ${firstLength}) {${this.errorVariable}.length = ${firstLength};}else if(${validSchemaCount} != 1){${this.buildErrorReturn(pathContext, {
710
750
  keyword: "oneOf",
711
751
  value: varName,
712
752
  message: `"Data must validate against exactly one schema, but matched "+ ${validSchemaCount}`,
@@ -714,14 +754,23 @@ class Compiler {
714
754
  })}${extra.after}}`);
715
755
  }
716
756
  else {
717
- const noreturn = this.noreturn;
718
- this.noreturn = true;
719
- src.push(`if (${validSchemaCount} == 1){${this.mainFunctionName}.errors = undefined}else {${this.buildErrorReturn(pathContext, {
720
- keyword: "oneOf",
721
- value: varName,
722
- message: `"Data must validate against exactly one schema, but matched "+ ${validSchemaCount}`,
723
- expected: '"exactly one schema"',
724
- })}${this.notLogic ? "" : `${oneOfErrors}.push(${this.mainFunctionName}.errors[0]);${this.mainFunctionName}.errors = ${oneOfErrors};`}${extra.refAfter ?? extra.after}${noreturn ? "" : "return false;"}}`);
757
+ if (noreturn) {
758
+ src.push(`if (${validSchemaCount} == 1 && ${this.errorVariable}.length != ${firstLength}){${this.errorVariable}.length = ${firstLength};}else if(${validSchemaCount} != 1){${this.buildErrorReturn(pathContext, {
759
+ keyword: "oneOf",
760
+ value: varName,
761
+ message: `"Data must validate against exactly one schema, but matched "+ ${validSchemaCount}`,
762
+ expected: '"exactly one schema"',
763
+ })}${extra.after}}`);
764
+ }
765
+ else {
766
+ src.push(`if (${validSchemaCount} == 1 && ${this.errorVariable}.length != ${firstLength}){${this.errorVariable}.length = ${firstLength};}else if(${validSchemaCount} != 1){${this.buildErrorReturn(pathContext, {
767
+ keyword: "oneOf",
768
+ value: varName,
769
+ message: `"Data must validate against exactly one schema, but matched "+ ${validSchemaCount}`,
770
+ expected: '"exactly one schema"',
771
+ })}${this.notLogic ? extra.after : `${this.mainFunctionName}.errors = ${this.errorVariable};return false;`}}`);
772
+ }
773
+ this.errorVariable = error;
725
774
  this.noreturn = noreturn;
726
775
  }
727
776
  }
@@ -1309,7 +1358,7 @@ class Compiler {
1309
1358
  else {
1310
1359
  const data = this.jetValidator.getFormat(schema.format);
1311
1360
  if (!data) {
1312
- throw new Error(`Format '${schema.format}' not found`);
1361
+ console.warn(`Format '${schema.format}' not found will be ignored`);
1313
1362
  }
1314
1363
  const format = typeof data === "object" && "validate" in data ? data.validate : data;
1315
1364
  const formatType = typeof data === "object" &&
@@ -1431,24 +1480,39 @@ class Compiler {
1431
1480
  if (Array.isArray(schema.required)) {
1432
1481
  if (this.options.allErrors ||
1433
1482
  schema.required.length > this.options.loopRequired) {
1434
- const arr = JSON.stringify(schema.required);
1435
- const arrVar = `arr${src.length}${counter++}`;
1436
- const iVar = `i${src.length}${counter++}`;
1437
- src.push(`const ${arrVar} = ${arr};`);
1438
1483
  if (extra.before != "")
1439
1484
  src.push(`if(${extra.before} true){`);
1440
- src.push(`for (let ${iVar} = 0; ${iVar} < ${arrVar}.length; ${iVar}++) {`);
1441
- const prop = "prop" + counter++;
1442
- src.push(`const ${prop} = ${arrVar}[${iVar}];`);
1443
- addEvaluatedProperty(src, prop, trackingState);
1444
- src.push(`if (${extra.before}${varName}[${prop}] === undefined) {${this.buildErrorReturn(pathContext, {
1445
- keyword: "required",
1446
- value: varName,
1447
- message: `"Missing required field: " + ${prop} + " in data."`,
1448
- expected: `${prop}`,
1449
- schemaPath: `${pathContext.schema}`,
1450
- })}${extra.after}}`);
1451
- src.push(`}`);
1485
+ if (schema.required.length > this.options.loopRequired) {
1486
+ const arr = JSON.stringify(schema.required);
1487
+ const arrVar = `arr${src.length}${counter++}`;
1488
+ const iVar = `i${src.length}${counter++}`;
1489
+ src.push(`const ${arrVar} = ${arr};`);
1490
+ src.push(`for (let ${iVar} = 0; ${iVar} < ${arrVar}.length; ${iVar}++) {`);
1491
+ const prop = "prop" + counter++;
1492
+ src.push(`const ${prop} = ${arrVar}[${iVar}];`);
1493
+ addEvaluatedProperty(src, prop, trackingState);
1494
+ src.push(`if (${extra.before}${varName}[${prop}] === undefined) {${this.buildErrorReturn(pathContext, {
1495
+ keyword: "required",
1496
+ value: varName,
1497
+ message: `"Missing required field: " + ${prop} + " in data."`,
1498
+ expected: `${prop}`,
1499
+ schemaPath: `${pathContext.schema}`,
1500
+ })}${extra.after}}`);
1501
+ src.push(`}`);
1502
+ }
1503
+ else {
1504
+ for (const prop of schema.required) {
1505
+ const errorMessage = JSON.stringify(`Missing required field: ${prop} in data.`);
1506
+ const pstring = JSON.stringify(prop);
1507
+ src.push(`if (${extra.before}${varName}[${pstring}] === undefined) {${this.buildErrorReturn(pathContext, {
1508
+ keyword: "required",
1509
+ value: varName,
1510
+ message: errorMessage,
1511
+ expected: `${pstring}`,
1512
+ schemaPath: `${pathContext.schema}`,
1513
+ })}${extra.after}}`);
1514
+ }
1515
+ }
1452
1516
  if (extra.before != "")
1453
1517
  src.push(`}`);
1454
1518
  }
@@ -2116,9 +2180,7 @@ class Compiler {
2116
2180
  buildErrorReturn(pathContext, error, spreads) {
2117
2181
  if (this.notLogic)
2118
2182
  return "";
2119
- if (this.neutralError)
2120
- return "return false;";
2121
- let result = this.options.allErrors
2183
+ let result = this.options.allErrors || this.noreturn
2122
2184
  ? `${this.errorVariable}.push({`
2123
2185
  : `${this.mainFunctionName}.errors = [{`;
2124
2186
  const escapedDataPath = (0, utilities_1.escapeTemplateString)(error.dataPath || pathContext.data || "/");
@@ -2199,7 +2261,7 @@ class Compiler {
2199
2261
  result += `,${spreads}`;
2200
2262
  }
2201
2263
  result += "}";
2202
- if (this.options.allErrors) {
2264
+ if (this.options.allErrors || this.noreturn) {
2203
2265
  result += ");";
2204
2266
  }
2205
2267
  else {