Repository: json-schema-faker/json-schema-faker
Pull request #817 (2024-08-31 02:47:12)

sync dev


Patch:
diff --git a/README.md b/README.md
index c4b6a13..252ea9b 100644
--- a/README.md
+++ b/README.md
@@ -2,13 +2,15 @@
 
 [![Donate](https://img.shields.io/badge/Donate-PayPal-green.svg)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=8MXLRJ7QQXGYY)
 [![OpenCollective](https://badgen.net/opencollective/backers/json-schema-faker)](https://opencollective.com/json-schema-faker)
-[![Build status](https://github.com/json-schema-faker/json-schema-faker/actions/workflows/testing.yml/badge.svg)](https://github.com/json-schema-faker/json-schema-faker/actions)
+[![Build status](https://github.com/json-schema-faker/json-schema-faker/workflows/ci/badge.svg)](https://github.com/json-schema-faker/json-schema-faker/actions)
 [![NPM version](https://badge.fury.io/js/json-schema-faker.svg)](http://badge.fury.io/js/json-schema-faker)
 [![Coverage Status](https://codecov.io/github/json-schema-faker/json-schema-faker/coverage.svg?branch=master)](https://codecov.io/github/json-schema-faker/json-schema-faker?branch=master)
 
 [![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/json-schema-faker/Lobby)
+[![Dependency Status](https://david-dm.org/json-schema-faker/json-schema-faker/status.svg)](https://david-dm.org/json-schema-faker/json-schema-faker)
+[![devDependency Status](https://david-dm.org/json-schema-faker/json-schema-faker/dev-status.svg)](https://david-dm.org/json-schema-faker/json-schema-faker#info=devDependencies)
 
-[![Inline docs](https://inch-ci.org/github/json-schema-faker/json-schema-faker.svg?branch=master)](https://inch-ci.org/github/json-schema-faker/json-schema-faker)
+[![Inline docs](http://inch-ci.org/github/json-schema-faker/json-schema-faker.svg?branch=master)](http://inch-ci.org/github/json-schema-faker/json-schema-faker)
 [![Typedoc](https://img.shields.io/badge/typedoc-provided-blue.svg)](http://json-schema-faker.github.io/json-schema-faker/)
 [![Known Vulnerabilities](https://snyk.io/test/github/json-schema-faker/json-schema-faker/badge.svg)](https://snyk.io/test/github/json-schema-faker/json-schema-faker)
 
diff --git a/docs/README.md b/docs/README.md
index 2045a32..9841be1 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -133,6 +133,7 @@ jsf.locate('faker');
 - `omitNulls` &mdash; Remove any generated `null` value from the resulting value (default: `false`)
 - `minDateTime` &mdash; When generating a string with format `date-time`, set the minimum date that will get selected. If it's a number it will be the offset from `now` in milliseconds (default: `-2524608000000`)
 - `maxDateTime` &mdash; When generating a string with format `date-time`, set the maximum date that will get selected. If it's a number it will be the offset from `now` in milliseconds (default: `1000`)
+- `maxRegexRetry` &mdash; When generating a string with a `pattern` and a `maxLength`, if the `maxLength` is smaller than the generated value, the value will be cropped. If the new value is not matching the pattern, it will try to keep cropping the value until it's valid or it reaches either the minimum allowed length or the maximum number of iterations set by this option (default: `100`)
 
 ## Building
 
diff --git a/docs/USAGE.md b/docs/USAGE.md
index 73c5d04..aeb404e 100644
--- a/docs/USAGE.md
+++ b/docs/USAGE.md
@@ -192,7 +192,7 @@ JSONSchemaFaker.resolve(schema, refs).then((sample) => {
 
 ## Faking values
 
-`JSONSchemaFaker` has built-in generators for core-formats, [Faker.js](https://github.com/marak/Faker.js/) and [Chance.js](http://chancejs.com/) (and others) are also supported but they require setup:
+`JSONSchemaFaker` has built-in generators for core-formats, [Faker.js](https://github.com/faker-js/faker/) and [Chance.js](http://chancejs.com/) (and others) are also supported but they require setup:
 
 ```js
 JSONSchemaFaker.extend("faker", () => require("@faker-js/faker"));
@@ -207,7 +207,7 @@ JSONSchemaFaker.extend("faker", () => require("@faker-js/faker"));
 
 ([demo »](http://json-schema-faker.js.org/#gist/89659ebf28be89d3f860c3f80cbffe4b))
 
-The above schema will invoke [`faker.internet.email()`](https://github.com/Marak/faker.js/blob/1f47f09e25ad43db41ea4187c3cd3f7e113d4cb4/lib/internet.js#L32).
+The above schema will invoke [`faker.internet.email()`](https://github.com/faker-js/faker/blob/1f47f09e25ad43db41ea4187c3cd3f7e113d4cb4/lib/internet.js#L32).
 
 Note that both generators has higher precedence than **format**.
 
@@ -253,7 +253,7 @@ E.g. using `chance` to faking values while passing arguments to the generator:
 This example works for single-parameter generator function.
 
 However, if you pass multiple arguments to the generator function, just pass them wrapped in an array.
-In the example below we use the [`faker.finance.amount(min, max, dec, symbol)`](https://github.com/Marak/faker.js/blob/1f47f09e25ad43db41ea4187c3cd3f7e113d4cb4/lib/finance.js#L85)
+In the example below we use the [`faker.finance.amount(min, max, dec, symbol)`](https://github.com/faker-js/faker/blob/1f47f09e25ad43db41ea4187c3cd3f7e113d4cb4/lib/finance.js#L85)
 generator which has 4 parameters. We just wrap them with an array and it's equivalent to `faker.finance.amount(100, 10000, 2, "$")`:
 
 ```json
@@ -346,7 +346,7 @@ JSONSchemaFaker.option("alwaysFakeOptionals", true);
 
 ## Extending dependencies
 
-You may extend [Faker.js](https://github.com/Marak/faker.js):
+You may extend [Faker.js](https://github.com/faker-js/faker):
 
 ```javascript
 import { JSONSchemaFaker } from 'json-schema-faker';
@@ -373,7 +373,7 @@ const schema = {
 JSONSchemaFaker.resolve(schema).then(...);
 ```
 
-...or if you want to use [faker's _individual localization packages_](https://github.com/Marak/faker.js#individual-localization-packages), simply do the following:
+...or if you want to use [faker's _individual localization packages_](https://github.com/faker-js/faker#individual-localization-packages), simply do the following:
 
 ```js
 JSONSchemaFaker.extend("faker", () => {
diff --git a/index.d.cts b/index.d.cts
index fc29bcc..24ba546 100644
--- a/index.d.cts
+++ b/index.d.cts
@@ -35,6 +35,7 @@ export interface JSONSchemaFakerOptions {
   renderComment?: boolean;
   refDepthMax?: number;
   refDepthMin?: number;
+  maxRegexRetry?: number;
 }
 
 export type JSONSchemaFakerRefs = Schema[] | { [k: string]: Schema };
diff --git a/index.d.ts b/index.d.ts
index fc29bcc..7717629 100644
--- a/index.d.ts
+++ b/index.d.ts
@@ -35,6 +35,7 @@ export interface JSONSchemaFakerOptions {
   renderComment?: boolean;
   refDepthMax?: number;
   refDepthMin?: number;
+  maxRegexRetry?: number;
 }
 
 export type JSONSchemaFakerRefs = Schema[] | { [k: string]: Schema };
@@ -49,7 +50,7 @@ export interface JSONSchemaFakerFormat {
 }
 
 declare function JSONSchemaFakerOption(opts: JSONSchemaFakerOptions): void;
-declare function JSONSchemaFakerOption(name: keyof JSONSchemaFakerOptions, value: any): void;
+declare function JSONSchemaFakerOption<K extends keyof JSONSchemaFakerOptions>(name: K, value: JSONSchemaFakerOptions[K]): void;
 declare namespace JSONSchemaFakerOption {
   var getDefaults: () => JSONSchemaFakerOptions;
 }
diff --git a/package.json b/package.json
index 97519a9..9ed6917 100644
--- a/package.json
+++ b/package.json
@@ -100,7 +100,7 @@
   ],
   "dependencies": {
     "json-schema-ref-parser": "^6.1.0",
-    "jsonpath-plus": "^7.2.0"
+    "jsonpath-plus": "^10.1.0"
   },
   "devDependencies": {
     "@faker-js/faker": "^7.6.0",
diff --git a/public/v1/index.html b/public/v1/index.html
index 9852ff0..236cee0 100644
--- a/public/v1/index.html
+++ b/public/v1/index.html
@@ -9,6 +9,7 @@
         <link href="http://netdna.bootstrapcdn.com/font-awesome/3.0.2/css/font-awesome.css" rel="stylesheet">
         <script src="https://cdnjs.cloudflare.com/ajax/libs/json-schema-faker/0.3.6/json-schema-faker.js" type="text/javascript" charset="utf-8"></script>
         <script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.2.3/ace.js" type="text/javascript" charset="utf-8"></script>
+        <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/github-fork-ribbon-css/0.2.3/gh-fork-ribbon.min.css" integrity="sha512-TktJbycEG5Van9KvrSHFUcYOKBroD7QCYkEe73HAutODCw9QTFcvF6fuxioYM1h6THNudK1GjVidazj6EslK4A==" crossorigin="anonymous" referrerpolicy="no-referrer" />
         <script src="vendor.js"></script>
         <script src="bundle.js"></script>
         <!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries -->
@@ -75,7 +76,7 @@
                         </li>
                     </ul>
                     <ul class="nav navbar-nav navbar-right">
-                        <li><a href="https://github.com/marak/Faker.js/">faker.js</a></li>
+                        <li><a href="https://github.com/faker-js/faker/">faker.js</a></li>
                         <li><a href="http://chancejs.com/">chance.js</a></li>
                         <li><a href="http://fent.github.io/randexp.js/">randexp.js</a></li>
                     </ul>
@@ -127,9 +128,7 @@
             </div>
         </div>
 
-        <a class="github-ribbon" href="https://github.com/json-schema-faker/json-schema-faker">
-            <img src="https://camo.githubusercontent.com/a6677b08c955af8400f44c6298f40e7d19cc5b2d/68747470733a2f2f73332e616d617a6f6e6177732e636f6d2f6769746875622f726962626f6e732f666f726b6d655f72696768745f677261795f3664366436642e706e67" alt="Fork me on GitHub" data-canonical-src="https://s3.amazonaws.com/github/ribbons/forkme_right_gray_6d6d6d.png">
-        </a>
+        <a class="github-fork-ribbon" href="https://github.com/json-schema-faker/json-schema-faker" data-ribbon="Fork me on GitHub" title="Fork me on GitHub">Fork me on GitHub</a>
 
         <script>
           (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
diff --git a/src/lib/api/defaults.mjs b/src/lib/api/defaults.mjs
index 827fe4c..30346e8 100644
--- a/src/lib/api/defaults.mjs
+++ b/src/lib/api/defaults.mjs
@@ -4,6 +4,7 @@ export default defaults;
 
 defaults.defaultInvalidTypeProduct = undefined;
 defaults.defaultRandExpMax = 10;
+defaults.maxRegexRetry = 100;
 
 defaults.pruneProperties = [];
 defaults.ignoreProperties = [];
diff --git a/src/lib/core/utils.mjs b/src/lib/core/utils.mjs
index b21cf70..c79c266 100644
--- a/src/lib/core/utils.mjs
+++ b/src/lib/core/utils.mjs
@@ -238,6 +238,18 @@ function typecast(type, schema, callback) {
 
       if (value.length > max) {
         value = value.substr(0, max);
+        const pattern = schema.pattern ? new RegExp(schema.pattern) : null;
+        if (pattern && !pattern.test(value)) {
+          let temp = value;
+          const maxRetries = optionAPI('maxRegexRetry');
+          const minLength = Math.max(value.length - maxRetries, min);
+          while (temp.length > minLength && !pattern.test(temp)) {
+            temp = temp.slice(0, -1);
+            if (pattern.test(temp)) {
+              value = temp;
+            }
+          }
+        }
       }
 
       switch (schema.format) {
@@ -499,7 +511,7 @@ function clean(obj, schema, isArray = false) {
 
   if (Array.isArray(obj)) {
     return obj
-      .map(value => clean(value, schema, true))
+      .map(value => clean(value, schema?.items, true))
       .filter(value => typeof value !== 'undefined');
   }
 
diff --git a/src/lib/types/array.mjs b/src/lib/types/array.mjs
index c783c50..c274292 100644
--- a/src/lib/types/array.mjs
+++ b/src/lib/types/array.mjs
@@ -92,7 +92,7 @@ function arrayType(value, path, resolve, traverseCallback) {
   const optionalsProbability = optionAPI('alwaysFakeOptionals') === true ? 1.0 : optionAPI('optionalsProbability');
   const fixedProbabilities = optionAPI('alwaysFakeOptionals') || optionAPI('fixedProbabilities') || false;
 
-  let length = random.number(minItems, maxItems, 1, 5);
+  let length = random.number(minItems, maxItems, 0, 5);
 
   if (optionalsProbability !== null) {
     length = Math.max(fixedProbabilities


Test patch:
diff --git a/docs/TESTING.md b/docs/TESTING.md
index e092eae..70c10cf 100644
--- a/docs/TESTING.md
+++ b/docs/TESTING.md
@@ -6,7 +6,7 @@
 ### Unit tests
 
 - They just validate the building blocks from the entire library
-- We're using `mocha` and `chai` so the worflow would be very familiar
+- We're using `mocha` and `chai` so the workflow would be very familiar
 
 > Much stuff from the internals are not covered by unit-tests yet, PRs for increasing that are very welcome!
 
diff --git a/tests/schema/core/issues/issue-494.json b/tests/schema/core/issues/issue-494.json
index 489bf02..aad4bcf 100644
--- a/tests/schema/core/issues/issue-494.json
+++ b/tests/schema/core/issues/issue-494.json
@@ -13,13 +13,15 @@
                 "type": "array",
                 "items": {
                   "$ref": "#/definitions/current-account"
-                }
+                },
+                "minItems": 1
               },
               "escrow": {
                 "type": "array",
                 "items": {
                   "$ref": "#/definitions/current-account"
-                }
+                },
+                "minItems": 1
               }
             },
             "required": [
diff --git a/tests/schema/core/issues/issue-747.json b/tests/schema/core/issues/issue-747.json
index 476282d..5a713d4 100644
--- a/tests/schema/core/issues/issue-747.json
+++ b/tests/schema/core/issues/issue-747.json
@@ -32,6 +32,7 @@
                 ],
                 "type": "object"
               },
+              "minItems": 1,
               "type": "array"
             }
           },
diff --git a/tests/schema/core/types/string.json b/tests/schema/core/types/string.json
index c5ca4c9..950603a 100644
--- a/tests/schema/core/types/string.json
+++ b/tests/schema/core/types/string.json
@@ -27,6 +27,15 @@
         },
         "valid": true
       },
+      {
+        "description": "should handle pattern with maxLength",
+        "schema": {
+          "type": "string",
+          "pattern": "^[a-z]{2}( [a-z])?$",
+          "maxLength": 3
+        },
+        "valid": true
+      },
       {
         "description": "should handle format (core)",
         "schema": {
diff --git a/tests/schema/main.spec.mjs b/tests/schema/main.spec.mjs
index 34ef94c..1a90651 100644
--- a/tests/schema/main.spec.mjs
+++ b/tests/schema/main.spec.mjs
@@ -55,6 +55,10 @@ function seed() {
           ? pick(suite, test.schema)
           : test.schema;
 
+        if (!schema) {
+          throw new Error(`Missing schema to test, given '${JSON.stringify(test)}'`);
+        }
+
         const refs = (test.refs || []).map(ref => {
           return typeof ref === 'string'
             ? pick(suite, ref)
diff --git a/tests/unit/core/traverse.spec.mjs b/tests/unit/core/traverse.spec.mjs
index c866800..0488ed4 100644
--- a/tests/unit/core/traverse.spec.mjs
+++ b/tests/unit/core/traverse.spec.mjs
@@ -49,6 +49,7 @@ describe('Traverse', () => {
         type: 'string',
         generate: () => 'foo',
       },
+      minItems: 1,
       maxItems: 1,
     };
 
diff --git a/tests/unit/core/utils.spec.mjs b/tests/unit/core/utils.spec.mjs
index 22af3eb..d71dc17 100644
--- a/tests/unit/core/utils.spec.mjs
+++ b/tests/unit/core/utils.spec.mjs
@@ -523,5 +523,11 @@ describe('Utils', () => {
       const cleaned = utils.clean(a, { required: ['b'] });
       expect(cleaned).to.eql({ b: {}, c: { d: 'string value' } });
     });
+
+    it('should respect nested required keys', () => {
+      const a = [[{ b: {} }]];
+      const cleaned = utils.clean(a, { items: { items: { properties: { price: {} }, required: ['b'] } } });
+      expect(cleaned).to.eql([[{ b: {} }]]);
+    });
   });
 });