From d514df2b41eab466f726af5b32381f73c59fa101 Mon Sep 17 00:00:00 2001 From: Nikita Skovoroda Date: Fri, 7 Oct 2022 01:32:30 +0400 Subject: [PATCH] draft: add all supported drafts (and next) to samples --- README.md | 2 +- doc/samples/draft-next/README.md | 84 + .../draft-next/additionalProperties.md | 204 ++ doc/samples/draft-next/allOf.md | 328 +++ doc/samples/draft-next/anchor.md | 660 ++++++ doc/samples/draft-next/anyOf.md | 233 ++ doc/samples/draft-next/boolean_schema.md | 44 + doc/samples/draft-next/const.md | 324 +++ doc/samples/draft-next/contains.md | 297 +++ doc/samples/draft-next/content.md | 100 + doc/samples/draft-next/default.md | 98 + doc/samples/draft-next/defs.md | 436 ++++ doc/samples/draft-next/dependentRequired.md | 106 + doc/samples/draft-next/dependentSchemas.md | 114 + doc/samples/draft-next/dynamicRef.md | 701 ++++++ doc/samples/draft-next/enum.md | 216 ++ doc/samples/draft-next/exclusiveMaximum.md | 27 + doc/samples/draft-next/exclusiveMinimum.md | 27 + doc/samples/draft-next/format.md | 580 +++++ doc/samples/draft-next/id.md | 1414 ++++++++++++ doc/samples/draft-next/if-then-else.md | 305 +++ .../draft-next/infinite-loop-detection.md | 45 + doc/samples/draft-next/items.md | 332 +++ doc/samples/draft-next/maxContains.md | 146 ++ doc/samples/draft-next/maxItems.md | 53 + doc/samples/draft-next/maxLength.md | 57 + doc/samples/draft-next/maxProperties.md | 79 + doc/samples/draft-next/maximum.md | 53 + doc/samples/draft-next/minContains.md | 286 +++ doc/samples/draft-next/minItems.md | 53 + doc/samples/draft-next/minLength.md | 57 + doc/samples/draft-next/minProperties.md | 53 + doc/samples/draft-next/minimum.md | 53 + doc/samples/draft-next/multipleOf.md | 116 + doc/samples/draft-next/not.md | 163 ++ doc/samples/draft-next/oneOf.md | 371 ++++ doc/samples/draft-next/optional-bignum.md | 169 ++ .../optional-dependencies-compatibility.md | 219 ++ .../draft-next/optional-ecmascript-regex.md | 950 ++++++++ .../draft-next/optional-float-overflow.md | 22 + .../draft-next/optional-format-assertion.md | 43 + .../draft-next/optional-non-bmp-regex.md | 59 + .../optional-refOfUnknownKeyword.md | 75 + doc/samples/draft-next/pattern.md | 54 + doc/samples/draft-next/patternProperties.md | 168 ++ doc/samples/draft-next/prefixItems.md | 118 + doc/samples/draft-next/properties.md | 240 ++ .../draft-next/propertyDependencies.md | 83 + doc/samples/draft-next/propertyNames.md | 80 + doc/samples/draft-next/ref.md | 1939 +++++++++++++++++ doc/samples/draft-next/refRemote.md | 494 +++++ doc/samples/draft-next/required.md | 144 ++ doc/samples/draft-next/type.md | 249 +++ doc/samples/draft-next/unevaluatedItems.md | 1020 +++++++++ .../draft-next/unevaluatedProperties.md | 1637 ++++++++++++++ doc/samples/draft-next/uniqueItems.md | 322 +++ doc/samples/draft-next/unknownKeyword.md | 93 + doc/samples/draft-next/vocabulary.md | 22 + doc/samples/draft4/README.md | 64 + doc/samples/draft4/additionalItems.md | 268 +++ doc/samples/draft4/additionalProperties.md | 204 ++ doc/samples/draft4/allOf.md | 260 +++ doc/samples/draft4/anyOf.md | 167 ++ doc/samples/draft4/default.md | 98 + doc/samples/draft4/definitions.md | 288 +++ doc/samples/draft4/dependencies.md | 145 ++ doc/samples/draft4/enum.md | 216 ++ doc/samples/draft4/format.md | 233 ++ doc/samples/draft4/id.md | 66 + doc/samples/draft4/infinite-loop-detection.md | 45 + doc/samples/draft4/items.md | 244 +++ doc/samples/draft4/maxItems.md | 27 + doc/samples/draft4/maxLength.md | 29 + doc/samples/draft4/maxProperties.md | 53 + doc/samples/draft4/maximum.md | 105 + doc/samples/draft4/minItems.md | 27 + doc/samples/draft4/minLength.md | 29 + doc/samples/draft4/minProperties.md | 27 + doc/samples/draft4/minimum.md | 105 + doc/samples/draft4/multipleOf.md | 116 + doc/samples/draft4/not.md | 116 + doc/samples/draft4/oneOf.md | 261 +++ doc/samples/draft4/optional-bignum.md | 169 ++ .../draft4/optional-ecmascript-regex.md | 515 +++++ doc/samples/draft4/optional-float-overflow.md | 22 + doc/samples/draft4/optional-non-bmp-regex.md | 59 + .../draft4/optional-zeroTerminatedFloats.md | 25 + doc/samples/draft4/pattern.md | 54 + doc/samples/draft4/patternProperties.md | 140 ++ doc/samples/draft4/properties.md | 213 ++ doc/samples/draft4/ref.md | 860 ++++++++ doc/samples/draft4/refRemote.md | 318 +++ doc/samples/draft4/required.md | 121 + doc/samples/draft4/type.md | 249 +++ doc/samples/draft4/uniqueItems.md | 319 +++ doc/samples/draft6/README.md | 70 + doc/samples/draft6/additionalItems.md | 268 +++ doc/samples/draft6/additionalProperties.md | 204 ++ doc/samples/draft6/allOf.md | 328 +++ doc/samples/draft6/anyOf.md | 233 ++ doc/samples/draft6/boolean_schema.md | 44 + doc/samples/draft6/const.md | 324 +++ doc/samples/draft6/contains.md | 228 ++ doc/samples/draft6/default.md | 98 + doc/samples/draft6/definitions.md | 284 +++ doc/samples/draft6/dependencies.md | 195 ++ doc/samples/draft6/enum.md | 216 ++ doc/samples/draft6/exclusiveMaximum.md | 27 + doc/samples/draft6/exclusiveMinimum.md | 27 + doc/samples/draft6/format.md | 314 +++ doc/samples/draft6/id.md | 175 ++ doc/samples/draft6/infinite-loop-detection.md | 45 + doc/samples/draft6/items.md | 323 +++ doc/samples/draft6/maxItems.md | 53 + doc/samples/draft6/maxLength.md | 57 + doc/samples/draft6/maxProperties.md | 79 + doc/samples/draft6/maximum.md | 53 + doc/samples/draft6/minItems.md | 53 + doc/samples/draft6/minLength.md | 57 + doc/samples/draft6/minProperties.md | 53 + doc/samples/draft6/minimum.md | 53 + doc/samples/draft6/multipleOf.md | 116 + doc/samples/draft6/not.md | 163 ++ doc/samples/draft6/oneOf.md | 371 ++++ doc/samples/draft6/optional-bignum.md | 169 ++ .../draft6/optional-ecmascript-regex.md | 515 +++++ doc/samples/draft6/optional-float-overflow.md | 22 + doc/samples/draft6/optional-non-bmp-regex.md | 59 + doc/samples/draft6/pattern.md | 54 + doc/samples/draft6/patternProperties.md | 168 ++ doc/samples/draft6/properties.md | 240 ++ doc/samples/draft6/propertyNames.md | 109 + doc/samples/draft6/ref.md | 1256 +++++++++++ doc/samples/draft6/refRemote.md | 404 ++++ doc/samples/draft6/required.md | 144 ++ doc/samples/draft6/type.md | 249 +++ doc/samples/draft6/uniqueItems.md | 319 +++ doc/samples/draft6/unknownKeyword.md | 91 + doc/samples/draft7/README.md | 73 + doc/samples/draft7/additionalItems.md | 268 +++ doc/samples/draft7/additionalProperties.md | 204 ++ doc/samples/draft7/allOf.md | 328 +++ doc/samples/draft7/anyOf.md | 233 ++ doc/samples/draft7/boolean_schema.md | 44 + doc/samples/draft7/const.md | 324 +++ doc/samples/draft7/contains.md | 262 +++ doc/samples/draft7/default.md | 98 + doc/samples/draft7/definitions.md | 311 +++ doc/samples/draft7/dependencies.md | 195 ++ doc/samples/draft7/enum.md | 216 ++ doc/samples/draft7/exclusiveMaximum.md | 27 + doc/samples/draft7/exclusiveMinimum.md | 27 + doc/samples/draft7/format.md | 521 +++++ doc/samples/draft7/id.md | 151 ++ doc/samples/draft7/if-then-else.md | 305 +++ doc/samples/draft7/infinite-loop-detection.md | 45 + doc/samples/draft7/items.md | 323 +++ doc/samples/draft7/maxItems.md | 53 + doc/samples/draft7/maxLength.md | 57 + doc/samples/draft7/maxProperties.md | 79 + doc/samples/draft7/maximum.md | 53 + doc/samples/draft7/minItems.md | 53 + doc/samples/draft7/minLength.md | 57 + doc/samples/draft7/minProperties.md | 53 + doc/samples/draft7/minimum.md | 53 + doc/samples/draft7/multipleOf.md | 116 + doc/samples/draft7/not.md | 163 ++ doc/samples/draft7/oneOf.md | 371 ++++ doc/samples/draft7/optional-bignum.md | 169 ++ doc/samples/draft7/optional-content.md | 102 + doc/samples/draft7/optional-cross-draft.md | 39 + .../draft7/optional-ecmascript-regex.md | 515 +++++ doc/samples/draft7/optional-float-overflow.md | 22 + doc/samples/draft7/optional-non-bmp-regex.md | 59 + doc/samples/draft7/pattern.md | 54 + doc/samples/draft7/patternProperties.md | 168 ++ doc/samples/draft7/properties.md | 240 ++ doc/samples/draft7/propertyNames.md | 109 + doc/samples/draft7/ref.md | 1316 +++++++++++ doc/samples/draft7/refRemote.md | 404 ++++ doc/samples/draft7/required.md | 144 ++ doc/samples/draft7/type.md | 249 +++ doc/samples/draft7/uniqueItems.md | 319 +++ doc/samples/draft7/unknownKeyword.md | 91 + doc/samples/util/generate.js | 9 +- 185 files changed, 40053 insertions(+), 3 deletions(-) create mode 100644 doc/samples/draft-next/README.md create mode 100644 doc/samples/draft-next/additionalProperties.md create mode 100644 doc/samples/draft-next/allOf.md create mode 100644 doc/samples/draft-next/anchor.md create mode 100644 doc/samples/draft-next/anyOf.md create mode 100644 doc/samples/draft-next/boolean_schema.md create mode 100644 doc/samples/draft-next/const.md create mode 100644 doc/samples/draft-next/contains.md create mode 100644 doc/samples/draft-next/content.md create mode 100644 doc/samples/draft-next/default.md create mode 100644 doc/samples/draft-next/defs.md create mode 100644 doc/samples/draft-next/dependentRequired.md create mode 100644 doc/samples/draft-next/dependentSchemas.md create mode 100644 doc/samples/draft-next/dynamicRef.md create mode 100644 doc/samples/draft-next/enum.md create mode 100644 doc/samples/draft-next/exclusiveMaximum.md create mode 100644 doc/samples/draft-next/exclusiveMinimum.md create mode 100644 doc/samples/draft-next/format.md create mode 100644 doc/samples/draft-next/id.md create mode 100644 doc/samples/draft-next/if-then-else.md create mode 100644 doc/samples/draft-next/infinite-loop-detection.md create mode 100644 doc/samples/draft-next/items.md create mode 100644 doc/samples/draft-next/maxContains.md create mode 100644 doc/samples/draft-next/maxItems.md create mode 100644 doc/samples/draft-next/maxLength.md create mode 100644 doc/samples/draft-next/maxProperties.md create mode 100644 doc/samples/draft-next/maximum.md create mode 100644 doc/samples/draft-next/minContains.md create mode 100644 doc/samples/draft-next/minItems.md create mode 100644 doc/samples/draft-next/minLength.md create mode 100644 doc/samples/draft-next/minProperties.md create mode 100644 doc/samples/draft-next/minimum.md create mode 100644 doc/samples/draft-next/multipleOf.md create mode 100644 doc/samples/draft-next/not.md create mode 100644 doc/samples/draft-next/oneOf.md create mode 100644 doc/samples/draft-next/optional-bignum.md create mode 100644 doc/samples/draft-next/optional-dependencies-compatibility.md create mode 100644 doc/samples/draft-next/optional-ecmascript-regex.md create mode 100644 doc/samples/draft-next/optional-float-overflow.md create mode 100644 doc/samples/draft-next/optional-format-assertion.md create mode 100644 doc/samples/draft-next/optional-non-bmp-regex.md create mode 100644 doc/samples/draft-next/optional-refOfUnknownKeyword.md create mode 100644 doc/samples/draft-next/pattern.md create mode 100644 doc/samples/draft-next/patternProperties.md create mode 100644 doc/samples/draft-next/prefixItems.md create mode 100644 doc/samples/draft-next/properties.md create mode 100644 doc/samples/draft-next/propertyDependencies.md create mode 100644 doc/samples/draft-next/propertyNames.md create mode 100644 doc/samples/draft-next/ref.md create mode 100644 doc/samples/draft-next/refRemote.md create mode 100644 doc/samples/draft-next/required.md create mode 100644 doc/samples/draft-next/type.md create mode 100644 doc/samples/draft-next/unevaluatedItems.md create mode 100644 doc/samples/draft-next/unevaluatedProperties.md create mode 100644 doc/samples/draft-next/uniqueItems.md create mode 100644 doc/samples/draft-next/unknownKeyword.md create mode 100644 doc/samples/draft-next/vocabulary.md create mode 100644 doc/samples/draft4/README.md create mode 100644 doc/samples/draft4/additionalItems.md create mode 100644 doc/samples/draft4/additionalProperties.md create mode 100644 doc/samples/draft4/allOf.md create mode 100644 doc/samples/draft4/anyOf.md create mode 100644 doc/samples/draft4/default.md create mode 100644 doc/samples/draft4/definitions.md create mode 100644 doc/samples/draft4/dependencies.md create mode 100644 doc/samples/draft4/enum.md create mode 100644 doc/samples/draft4/format.md create mode 100644 doc/samples/draft4/id.md create mode 100644 doc/samples/draft4/infinite-loop-detection.md create mode 100644 doc/samples/draft4/items.md create mode 100644 doc/samples/draft4/maxItems.md create mode 100644 doc/samples/draft4/maxLength.md create mode 100644 doc/samples/draft4/maxProperties.md create mode 100644 doc/samples/draft4/maximum.md create mode 100644 doc/samples/draft4/minItems.md create mode 100644 doc/samples/draft4/minLength.md create mode 100644 doc/samples/draft4/minProperties.md create mode 100644 doc/samples/draft4/minimum.md create mode 100644 doc/samples/draft4/multipleOf.md create mode 100644 doc/samples/draft4/not.md create mode 100644 doc/samples/draft4/oneOf.md create mode 100644 doc/samples/draft4/optional-bignum.md create mode 100644 doc/samples/draft4/optional-ecmascript-regex.md create mode 100644 doc/samples/draft4/optional-float-overflow.md create mode 100644 doc/samples/draft4/optional-non-bmp-regex.md create mode 100644 doc/samples/draft4/optional-zeroTerminatedFloats.md create mode 100644 doc/samples/draft4/pattern.md create mode 100644 doc/samples/draft4/patternProperties.md create mode 100644 doc/samples/draft4/properties.md create mode 100644 doc/samples/draft4/ref.md create mode 100644 doc/samples/draft4/refRemote.md create mode 100644 doc/samples/draft4/required.md create mode 100644 doc/samples/draft4/type.md create mode 100644 doc/samples/draft4/uniqueItems.md create mode 100644 doc/samples/draft6/README.md create mode 100644 doc/samples/draft6/additionalItems.md create mode 100644 doc/samples/draft6/additionalProperties.md create mode 100644 doc/samples/draft6/allOf.md create mode 100644 doc/samples/draft6/anyOf.md create mode 100644 doc/samples/draft6/boolean_schema.md create mode 100644 doc/samples/draft6/const.md create mode 100644 doc/samples/draft6/contains.md create mode 100644 doc/samples/draft6/default.md create mode 100644 doc/samples/draft6/definitions.md create mode 100644 doc/samples/draft6/dependencies.md create mode 100644 doc/samples/draft6/enum.md create mode 100644 doc/samples/draft6/exclusiveMaximum.md create mode 100644 doc/samples/draft6/exclusiveMinimum.md create mode 100644 doc/samples/draft6/format.md create mode 100644 doc/samples/draft6/id.md create mode 100644 doc/samples/draft6/infinite-loop-detection.md create mode 100644 doc/samples/draft6/items.md create mode 100644 doc/samples/draft6/maxItems.md create mode 100644 doc/samples/draft6/maxLength.md create mode 100644 doc/samples/draft6/maxProperties.md create mode 100644 doc/samples/draft6/maximum.md create mode 100644 doc/samples/draft6/minItems.md create mode 100644 doc/samples/draft6/minLength.md create mode 100644 doc/samples/draft6/minProperties.md create mode 100644 doc/samples/draft6/minimum.md create mode 100644 doc/samples/draft6/multipleOf.md create mode 100644 doc/samples/draft6/not.md create mode 100644 doc/samples/draft6/oneOf.md create mode 100644 doc/samples/draft6/optional-bignum.md create mode 100644 doc/samples/draft6/optional-ecmascript-regex.md create mode 100644 doc/samples/draft6/optional-float-overflow.md create mode 100644 doc/samples/draft6/optional-non-bmp-regex.md create mode 100644 doc/samples/draft6/pattern.md create mode 100644 doc/samples/draft6/patternProperties.md create mode 100644 doc/samples/draft6/properties.md create mode 100644 doc/samples/draft6/propertyNames.md create mode 100644 doc/samples/draft6/ref.md create mode 100644 doc/samples/draft6/refRemote.md create mode 100644 doc/samples/draft6/required.md create mode 100644 doc/samples/draft6/type.md create mode 100644 doc/samples/draft6/uniqueItems.md create mode 100644 doc/samples/draft6/unknownKeyword.md create mode 100644 doc/samples/draft7/README.md create mode 100644 doc/samples/draft7/additionalItems.md create mode 100644 doc/samples/draft7/additionalProperties.md create mode 100644 doc/samples/draft7/allOf.md create mode 100644 doc/samples/draft7/anyOf.md create mode 100644 doc/samples/draft7/boolean_schema.md create mode 100644 doc/samples/draft7/const.md create mode 100644 doc/samples/draft7/contains.md create mode 100644 doc/samples/draft7/default.md create mode 100644 doc/samples/draft7/definitions.md create mode 100644 doc/samples/draft7/dependencies.md create mode 100644 doc/samples/draft7/enum.md create mode 100644 doc/samples/draft7/exclusiveMaximum.md create mode 100644 doc/samples/draft7/exclusiveMinimum.md create mode 100644 doc/samples/draft7/format.md create mode 100644 doc/samples/draft7/id.md create mode 100644 doc/samples/draft7/if-then-else.md create mode 100644 doc/samples/draft7/infinite-loop-detection.md create mode 100644 doc/samples/draft7/items.md create mode 100644 doc/samples/draft7/maxItems.md create mode 100644 doc/samples/draft7/maxLength.md create mode 100644 doc/samples/draft7/maxProperties.md create mode 100644 doc/samples/draft7/maximum.md create mode 100644 doc/samples/draft7/minItems.md create mode 100644 doc/samples/draft7/minLength.md create mode 100644 doc/samples/draft7/minProperties.md create mode 100644 doc/samples/draft7/minimum.md create mode 100644 doc/samples/draft7/multipleOf.md create mode 100644 doc/samples/draft7/not.md create mode 100644 doc/samples/draft7/oneOf.md create mode 100644 doc/samples/draft7/optional-bignum.md create mode 100644 doc/samples/draft7/optional-content.md create mode 100644 doc/samples/draft7/optional-cross-draft.md create mode 100644 doc/samples/draft7/optional-ecmascript-regex.md create mode 100644 doc/samples/draft7/optional-float-overflow.md create mode 100644 doc/samples/draft7/optional-non-bmp-regex.md create mode 100644 doc/samples/draft7/pattern.md create mode 100644 doc/samples/draft7/patternProperties.md create mode 100644 doc/samples/draft7/properties.md create mode 100644 doc/samples/draft7/propertyNames.md create mode 100644 doc/samples/draft7/ref.md create mode 100644 doc/samples/draft7/refRemote.md create mode 100644 doc/samples/draft7/required.md create mode 100644 doc/samples/draft7/type.md create mode 100644 doc/samples/draft7/uniqueItems.md create mode 100644 doc/samples/draft7/unknownKeyword.md diff --git a/README.md b/README.md index 5ff9cc2..92a296d 100644 --- a/README.md +++ b/README.md @@ -198,7 +198,7 @@ See [Error handling](./doc/Error-handling.md) for more information. ## Generate Modules See the [doc/samples](./doc/samples/) directory to see how `@exodus/schemasafe` compiles -`draft/2019-09` and `draft/2020-12` test suites. +supported test suites. To compile a validator function to an IIFE, call `validate.toModule()`: diff --git a/doc/samples/draft-next/README.md b/doc/samples/draft-next/README.md new file mode 100644 index 0000000..e010f57 --- /dev/null +++ b/doc/samples/draft-next/README.md @@ -0,0 +1,84 @@ +# Samples + +Based on JSON Schema Test Suite for `draft-next`. + + +### Disambiguation + + * **Failed to compile** — schemas that did not compile in any mode. + + * **Warnings** — schemas that did not compile in the `default` mode, but compiled in `lax` + mode. + + JSON Schema spec allows usage of ineffective or unknown keywords, which is considered a mistake + by `@exodus/schemasafe` by default. `lax` mode lifts that coherence check. + + * **Misclassified** — schemas that classified at least one test value incorrectly, i.e. gave + `true` where testsuite expected `false` or vice versa. + +## Results + +| Name | Total | Failed to compile | Warnings | Misclassified | +|---------------------------------------------------------------------------------|-------|-------------------|----------|---------------| +| [additionalProperties](./additionalProperties.md) | 7 | - | - | - | +| [allOf](./allOf.md) | 12 | - | - | - | +| [anchor](./anchor.md) | 7 | - | - | - | +| [anyOf](./anyOf.md) | 8 | - | 3 | - | +| [boolean_schema](./boolean_schema.md) | 2 | - | - | - | +| [const](./const.md) | 15 | - | - | - | +| [contains](./contains.md) | 7 | - | - | 6 | +| [content](./content.md) | 4 | - | 4 | - | +| [default](./default.md) | 3 | - | - | - | +| [defs](./defs.md) | 1 | - | - | - | +| [dependentRequired](./dependentRequired.md) | 4 | - | - | - | +| [dependentSchemas](./dependentSchemas.md) | 3 | - | - | - | +| [dynamicRef](./dynamicRef.md) | 12 | 2 | - | - | +| [enum](./enum.md) | 10 | - | - | - | +| [exclusiveMaximum](./exclusiveMaximum.md) | 1 | - | - | - | +| [exclusiveMinimum](./exclusiveMinimum.md) | 1 | - | - | - | +| [format](./format.md) | 19 | 4 | - | - | +| [id](./id.md) | 5 | - | - | - | +| [if-then-else](./if-then-else.md) | 10 | - | 6 | - | +| [infinite-loop-detection](./infinite-loop-detection.md) | 1 | - | - | - | +| [items](./items.md) | 9 | - | - | - | +| [maxContains](./maxContains.md) | 4 | - | 1 | 2 | +| [maxItems](./maxItems.md) | 2 | - | - | - | +| [maxLength](./maxLength.md) | 2 | - | - | - | +| [maxProperties](./maxProperties.md) | 3 | - | - | - | +| [maximum](./maximum.md) | 2 | - | - | - | +| [minContains](./minContains.md) | 8 | - | 2 | - | +| [minItems](./minItems.md) | 2 | - | - | - | +| [minLength](./minLength.md) | 2 | - | - | - | +| [minProperties](./minProperties.md) | 2 | - | - | - | +| [minimum](./minimum.md) | 2 | - | - | - | +| [multipleOf](./multipleOf.md) | 4 | - | - | - | +| [not](./not.md) | 6 | - | 1 | - | +| [oneOf](./oneOf.md) | 11 | - | 3 | - | +| [pattern](./pattern.md) | 2 | - | - | - | +| [patternProperties](./patternProperties.md) | 5 | - | - | - | +| [prefixItems](./prefixItems.md) | 4 | - | - | - | +| [properties](./properties.md) | 6 | - | - | - | +| [propertyDependencies](./propertyDependencies.md) | 3 | - | 3 | 1 | +| [propertyNames](./propertyNames.md) | 3 | - | - | - | +| [ref](./ref.md) | 29 | - | - | - | +| [refRemote](./refRemote.md) | 13 | - | - | - | +| [required](./required.md) | 5 | - | - | - | +| [type](./type.md) | 11 | - | - | - | +| [unevaluatedItems](./unevaluatedItems.md) | 23 | - | 2 | - | +| [unevaluatedProperties](./unevaluatedProperties.md) | 36 | - | 3 | 2 | +| [uniqueItems](./uniqueItems.md) | 6 | - | - | - | +| [unknownKeyword](./unknownKeyword.md) | 1 | - | 1 | - | +| [vocabulary](./vocabulary.md) | 1 | 1 | - | - | +| [optional/bignum](./optional-bignum.md) | 7 | - | - | - | +| [optional/dependencies-compatibility](./optional-dependencies-compatibility.md) | 7 | - | - | - | +| [optional/ecmascript-regex](./optional-ecmascript-regex.md) | 21 | - | - | - | +| [optional/float-overflow](./optional-float-overflow.md) | 1 | - | - | - | +| [optional/format-assertion](./optional-format-assertion.md) | 2 | 2 | - | - | +| [optional/non-bmp-regex](./optional-non-bmp-regex.md) | 2 | - | - | - | +| [optional/refOfUnknownKeyword](./optional-refOfUnknownKeyword.md) | 2 | - | 2 | - | + +### Notes + +`{ isJSON: true }` option is used for better clarity, and that also corresponds to the main +expected usage pattern of this module. Without it, there would be additional checks for +`!== undefined`, which can be fast-tracked if we know that the input came from `JSON.parse()`. diff --git a/doc/samples/draft-next/additionalProperties.md b/doc/samples/draft-next/additionalProperties.md new file mode 100644 index 0000000..33da910 --- /dev/null +++ b/doc/samples/draft-next/additionalProperties.md @@ -0,0 +1,204 @@ +# additionalProperties + +## additionalProperties being false does not allow other properties + +### Schema + +```json +{ + "properties": { "foo": {}, "bar": {} }, + "patternProperties": { "^v": {} }, + "additionalProperties": false +} +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + for (const key1 of Object.keys(data)) { + if (key1 !== "foo" && key1 !== "bar" && !(key1.startsWith("v"))) return false + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] empty rules node is not allowed at #/properties/foo` + + +## non-ASCII pattern with additionalProperties + +### Schema + +```json +{ "patternProperties": { "^á": {} }, "additionalProperties": false } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + for (const key1 of Object.keys(data)) { + if (!(key1.startsWith("á"))) return false + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `Should start with ^ and end with $: "^á" at #` + + +## additionalProperties with schema + +### Schema + +```json +{ + "properties": { "foo": {}, "bar": {} }, + "additionalProperties": { "type": "boolean" } +} +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + for (const key0 of Object.keys(data)) { + if (key0 !== "foo" && key0 !== "bar") { + if (!(typeof data[key0] === "boolean")) return false + } + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] empty rules node is not allowed at #/properties/foo` + + +## additionalProperties can exist by itself + +### Schema + +```json +{ "additionalProperties": { "type": "boolean" } } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + for (const key0 of Object.keys(data)) { + if (!(typeof data[key0] === "boolean")) return false + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## additionalProperties are allowed by default + +### Schema + +```json +{ "properties": { "foo": {}, "bar": {} } } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] empty rules node is not allowed at #/properties/foo` + + +## additionalProperties does not look in applicators + +### Schema + +```json +{ + "allOf": [{ "properties": { "foo": {} } }], + "additionalProperties": { "type": "boolean" } +} +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + for (const key0 of Object.keys(data)) { + if (!(typeof data[key0] === "boolean")) return false + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] empty rules node is not allowed at #/allOf/0/properties/foo` + + +## additionalProperties with null valued instance properties + +### Schema + +```json +{ "additionalProperties": { "type": "null" } } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + for (const key0 of Object.keys(data)) { + if (!(data[key0] === null)) return false + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + diff --git a/doc/samples/draft-next/allOf.md b/doc/samples/draft-next/allOf.md new file mode 100644 index 0000000..9e2130e --- /dev/null +++ b/doc/samples/draft-next/allOf.md @@ -0,0 +1,328 @@ +# allOf + +## allOf + +### Schema + +```json +{ + "allOf": [ + { "properties": { "bar": { "type": "integer" } }, "required": ["bar"] }, + { "properties": { "foo": { "type": "string" } }, "required": ["foo"] } + ] +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (!(data.bar !== undefined && hasOwn(data, "bar"))) return false + if (!Number.isInteger(data.bar)) return false + } + if (typeof data === "object" && data && !Array.isArray(data)) { + if (!(data.foo !== undefined && hasOwn(data, "foo"))) return false + if (!(typeof data.foo === "string")) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireStringValidation] pattern, format or contentSchema should be specified for strings, use pattern: ^[\s\S]*$ to opt-out at #/allOf/1/properties/foo` + + +## allOf with base schema + +### Schema + +```json +{ + "properties": { "bar": { "type": "integer" } }, + "required": ["bar"], + "allOf": [ + { "properties": { "foo": { "type": "string" } }, "required": ["foo"] }, + { "properties": { "baz": { "type": "null" } }, "required": ["baz"] } + ] +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (!(data.bar !== undefined && hasOwn(data, "bar"))) return false + if (!Number.isInteger(data.bar)) return false + } + if (typeof data === "object" && data && !Array.isArray(data)) { + if (!(data.foo !== undefined && hasOwn(data, "foo"))) return false + if (!(typeof data.foo === "string")) return false + } + if (typeof data === "object" && data && !Array.isArray(data)) { + if (!(data.baz !== undefined && hasOwn(data, "baz"))) return false + if (!(data.baz === null)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireStringValidation] pattern, format or contentSchema should be specified for strings, use pattern: ^[\s\S]*$ to opt-out at #/allOf/0/properties/foo` + + +## allOf simple types + +### Schema + +```json +{ "allOf": [{ "maximum": 30 }, { "minimum": 20 }] } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (typeof data === "number") { + if (!(30 >= data)) return false + } + if (typeof data === "number") { + if (!(20 <= data)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## allOf with boolean schemas, all true + +### Schema + +```json +{ "allOf": [true, true] } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] schema = true is not allowed at #/allOf/0` + + +## allOf with boolean schemas, some false + +### Schema + +```json +{ "allOf": [true, false] } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + return false + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] schema = true is not allowed at #/allOf/0` + + +## allOf with boolean schemas, all false + +### Schema + +```json +{ "allOf": [false, false] } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + return false + return false + return true +}; +return ref0 +``` + + +## allOf with one empty schema + +### Schema + +```json +{ "allOf": [{}] } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] empty rules node is not allowed at #/allOf/0` + + +## allOf with two empty schemas + +### Schema + +```json +{ "allOf": [{}, {}] } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] empty rules node is not allowed at #/allOf/0` + + +## allOf with the first empty schema + +### Schema + +```json +{ "allOf": [{}, { "type": "number" }] } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (!(typeof data === "number")) return false + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] empty rules node is not allowed at #/allOf/0` + + +## allOf with the last empty schema + +### Schema + +```json +{ "allOf": [{ "type": "number" }, {}] } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (!(typeof data === "number")) return false + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] empty rules node is not allowed at #/allOf/1` + + +## nested allOf, to check validation semantics + +### Schema + +```json +{ "allOf": [{ "allOf": [{ "type": "null" }] }] } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (!(data === null)) return false + return true +}; +return ref0 +``` + + +## allOf combined with anyOf, oneOf + +### Schema + +```json +{ + "allOf": [{ "multipleOf": 2 }], + "anyOf": [{ "multipleOf": 3 }], + "oneOf": [{ "multipleOf": 5 }] +} +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (typeof data === "number") { + if (data % 2 !== 0) return false + } + if (typeof data === "number") { + if (data % 3 !== 0) return false + } + if (typeof data === "number") { + if (data % 5 !== 0) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + diff --git a/doc/samples/draft-next/anchor.md b/doc/samples/draft-next/anchor.md new file mode 100644 index 0000000..dc3354f --- /dev/null +++ b/doc/samples/draft-next/anchor.md @@ -0,0 +1,660 @@ +# anchor + +## Location-independent identifier + +### Schema + +```json +{ "$ref": "#foo", "$defs": { "A": { "$anchor": "foo", "type": "integer" } } } +``` + +### Code + +```js +'use strict' +const ref1 = function validate(data) { + if (!Number.isInteger(data)) return false + return true +}; +const ref0 = function validate(data) { + if (!ref1(data)) return false + return true +}; +return ref0 +``` + + +## Location-independent identifier with absolute URI + +### Schema + +```json +{ + "$ref": "http://localhost:1234/draft-next/bar#foo", + "$defs": { + "A": { + "$id": "http://localhost:1234/draft-next/bar", + "$anchor": "foo", + "type": "integer" + } + } +} +``` + +### Code + +```js +'use strict' +const ref1 = function validate(data) { + if (!Number.isInteger(data)) return false + return true +}; +const ref0 = function validate(data) { + if (!ref1(data)) return false + return true +}; +return ref0 +``` + + +## Location-independent identifier with base URI change in subschema + +### Schema + +```json +{ + "$id": "http://localhost:1234/draft-next/root", + "$ref": "http://localhost:1234/draft-next/nested.json#foo", + "$defs": { + "A": { + "$id": "nested.json", + "$defs": { "B": { "$anchor": "foo", "type": "integer" } } + } + } +} +``` + +### Code + +```js +'use strict' +const ref1 = function validate(data) { + if (!Number.isInteger(data)) return false + return true +}; +const ref0 = function validate(data) { + if (!ref1(data)) return false + return true +}; +return ref0 +``` + + +## $anchor inside an enum is not a real identifier + +### Schema + +```json +{ + "$defs": { + "anchor_in_enum": { "enum": [{ "$anchor": "my_anchor", "type": "null" }] }, + "real_identifier_in_schema": { "$anchor": "my_anchor", "type": "string" }, + "zzz_anchor_in_const": { + "const": { "$anchor": "my_anchor", "type": "null" } + } + }, + "anyOf": [{ "$ref": "#/$defs/anchor_in_enum" }, { "$ref": "#my_anchor" }] +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref1 = function validate(data) { + if (!(typeof data === "object" && data && !Array.isArray(data) && Object.keys(data).length === 2 && hasOwn(data, "$anchor") && hasOwn(data, "type") && data["$anchor"] === "my_anchor" && data["type"] === "null")) return false + return true +}; +const ref2 = function validate(data) { + if (!(typeof data === "string")) return false + return true +}; +const ref0 = function validate(data) { + const sub0 = (() => { + if (!ref1(data)) return false + return true + })() + if (!sub0) { + const sub1 = (() => { + if (!ref2(data)) return false + return true + })() + if (!sub1) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireStringValidation] pattern, format or contentSchema should be specified for strings, use pattern: ^[\s\S]*$ to opt-out at #` + + +## same $anchor with different base uri + +### Schema + +```json +{ + "$id": "http://localhost:1234/draft-next/foobar", + "$defs": { + "A": { + "$id": "child1", + "allOf": [ + { "$id": "child2", "$anchor": "my_anchor", "type": "number" }, + { "$anchor": "my_anchor", "type": "string" } + ] + } + }, + "$ref": "child1#my_anchor" +} +``` + +### Code + +```js +'use strict' +const ref1 = function validate(data) { + if (!(typeof data === "string")) return false + return true +}; +const ref0 = function validate(data) { + if (!ref1(data)) return false + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireStringValidation] pattern, format or contentSchema should be specified for strings, use pattern: ^[\s\S]*$ to opt-out at http://localhost:1234/draft-next/child1#` + + +## non-schema object containing an $anchor property + +### Schema + +```json +{ + "$defs": { + "const_not_anchor": { "const": { "$anchor": "not_a_real_anchor" } } + }, + "if": { "const": "skip not_a_real_anchor" }, + "then": true, + "else": { "$ref": "#/$defs/const_not_anchor" } +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref1 = function validate(data) { + if (!(typeof data === "object" && data && !Array.isArray(data) && Object.keys(data).length === 1 && hasOwn(data, "$anchor") && data["$anchor"] === "not_a_real_anchor")) return false + return true +}; +const ref0 = function validate(data) { + const sub0 = (() => { + if (!(data === "skip not_a_real_anchor")) return false + return true + })() + if (!sub0) { + if (!ref1(data)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] schema = true is not allowed at #/then` + + +## invalid anchors + +### Schema + +```json +{ "$ref": "https://json-schema.org/draft/next/schema" } +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const dynamicResolve = (anchors, id) => (anchors.filter((x) => x[id])[0] || {})[id]; +const unique = (array) => { + if (array.length < 2) return true + if (array.length === 2) return !deepEqual(array[0], array[1]) + const objects = [] + const primitives = array.length > 20 ? new Set() : null + let primitivesCount = 0 + let pos = 0 + for (const item of array) { + if (typeof item === 'object') { + objects.push(item) + } else if (primitives) { + primitives.add(item) + if (primitives.size !== ++primitivesCount) return false + } else { + if (array.indexOf(item, pos + 1) !== -1) return false + } + pos++ + } + for (let i = 1; i < objects.length; i++) + for (let j = 0; j < i; j++) if (deepEqual(objects[i], objects[j])) return false + return true +}; +const deepEqual = (obj, obj2) => { + if (obj === obj2) return true + if (!obj || !obj2 || typeof obj !== typeof obj2) return false + if (obj !== obj2 && typeof obj !== 'object') return false + + const proto = Object.getPrototypeOf(obj) + if (proto !== Object.getPrototypeOf(obj2)) return false + + if (proto === Array.prototype) { + if (!Array.isArray(obj) || !Array.isArray(obj2)) return false + if (obj.length !== obj2.length) return false + return obj.every((x, i) => deepEqual(x, obj2[i])) + } else if (proto === Object.prototype) { + const [keys, keys2] = [Object.keys(obj), Object.keys(obj2)] + if (keys.length !== keys2.length) return false + const keyset2 = new Set([...keys, ...keys2]) + return keyset2.size === keys.length && keys.every((key) => deepEqual(obj[key], obj2[key])) + } + return false +}; +const ref2 = function validate(data, dynAnchors) { + if (!Array.isArray(data)) return false + for (let i = 0; i < data.length; i++) { + if (data[i] !== undefined && hasOwn(data, i)) { + if (!(typeof data[i] === "string")) return false + } + } + if (!unique(data)) return false + return true +}; +const pattern0 = new RegExp("^[A-Za-z_][-A-Za-z0-9._]*$", "u"); +const ref3 = function validate(data, dynAnchors) { + if (!(typeof data === "string")) return false + if (!pattern0.test(data)) return false + return true +}; +const format0 = new RegExp("^(?:[a-z][a-z0-9+\\-.]*:)?(?:\\/?\\/(?:(?:[a-z0-9\\-._~!$&'()*+,;=:]|%[0-9a-f]{2})*@)?(?:\\[(?:(?:(?:(?:[0-9a-f]{1,4}:){6}|::(?:[0-9a-f]{1,4}:){5}|(?:[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){4}|(?:(?:[0-9a-f]{1,4}:){0,1}[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){3}|(?:(?:[0-9a-f]{1,4}:){0,2}[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){2}|(?:(?:[0-9a-f]{1,4}:){0,3}[0-9a-f]{1,4})?::[0-9a-f]{1,4}:|(?:(?:[0-9a-f]{1,4}:){0,4}[0-9a-f]{1,4})?::)(?:[0-9a-f]{1,4}:[0-9a-f]{1,4}|(?:(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d\\d?)\\.){3}(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d\\d?))|(?:(?:[0-9a-f]{1,4}:){0,5}[0-9a-f]{1,4})?::[0-9a-f]{1,4}|(?:(?:[0-9a-f]{1,4}:){0,6}[0-9a-f]{1,4})?::)|v[0-9a-f]+\\.[a-z0-9\\-._~!$&'()*+,;=:]+)\\]|(?:(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d\\d?)\\.){3}(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d\\d?)|(?:[a-z0-9\\-._~!$&'()*+,;=]|%[0-9a-f]{2})*)(?::\\d*)?(?:\\/(?:[a-z0-9\\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})*)*|\\/?(?:(?:[a-z0-9\\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})+(?:\\/(?:[a-z0-9\\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})*)*)?)?(?:\\?(?:[a-z0-9\\-._~!$&'()*+,;=:@/?]|%[0-9a-f]{2})*)?(?:#(?:[a-z0-9\\-._~!$&'()*+,;=:@/?]|%[0-9a-f]{2})*)?$", "i"); +const ref4 = function validate(data, dynAnchors) { + if (!(typeof data === "string")) return false + if (!format0.test(data)) return false + return true +}; +const pattern1 = new RegExp("^[^#]*#?$", "u"); +const format1 = new RegExp("^[a-z][a-z0-9+\\-.]*:(?:\\/?\\/(?:(?:[a-z0-9\\-._~!$&'()*+,;=:]|%[0-9a-f]{2})*@)?(?:\\[(?:(?:(?:(?:[0-9a-f]{1,4}:){6}|::(?:[0-9a-f]{1,4}:){5}|(?:[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){4}|(?:(?:[0-9a-f]{1,4}:){0,1}[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){3}|(?:(?:[0-9a-f]{1,4}:){0,2}[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){2}|(?:(?:[0-9a-f]{1,4}:){0,3}[0-9a-f]{1,4})?::[0-9a-f]{1,4}:|(?:(?:[0-9a-f]{1,4}:){0,4}[0-9a-f]{1,4})?::)(?:[0-9a-f]{1,4}:[0-9a-f]{1,4}|(?:(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d\\d?)\\.){3}(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d\\d?))|(?:(?:[0-9a-f]{1,4}:){0,5}[0-9a-f]{1,4})?::[0-9a-f]{1,4}|(?:(?:[0-9a-f]{1,4}:){0,6}[0-9a-f]{1,4})?::)|v[0-9a-f]+\\.[a-z0-9\\-._~!$&'()*+,;=:]+)\\]|(?:(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d\\d?)\\.){3}(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d\\d?)|(?:[a-z0-9\\-._~!$&'()*+,;=]|%[0-9a-f]{2})*)(?::\\d*)?(?:\\/(?:[a-z0-9\\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})*)*|\\/?(?:(?:[a-z0-9\\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})+(?:\\/(?:[a-z0-9\\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})*)*)?)(?:\\?(?:[a-z0-9\\-._~!$&'()*+,;=:@/?]|%[0-9a-f]{2})*)?(?:#(?:[a-z0-9\\-._~!$&'()*+,;=:@/?]|%[0-9a-f]{2})*)?$", "i"); +const ref6 = function validate(data, dynAnchors) { + if (!(typeof data === "string")) return false + if (!format1.test(data)) return false + return true +}; +const ref5 = function validate(data, dynAnchors = []) { + const dynLocal = [{}] + dynLocal[0]["#meta"] = validate + if (!(typeof data === "object" && data && !Array.isArray(data) || typeof data === "boolean")) return false + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data["$id"] !== undefined && hasOwn(data, "$id")) { + if (!ref4(data["$id"], [...dynAnchors, dynLocal[0] || []])) return false + if (!(pattern1.test(data["$id"]))) return false + } + if (data["$schema"] !== undefined && hasOwn(data, "$schema")) { + if (!ref6(data["$schema"], [...dynAnchors, dynLocal[0] || []])) return false + } + if (data["$ref"] !== undefined && hasOwn(data, "$ref")) { + if (!ref4(data["$ref"], [...dynAnchors, dynLocal[0] || []])) return false + } + if (data["$anchor"] !== undefined && hasOwn(data, "$anchor")) { + if (!ref3(data["$anchor"], [...dynAnchors, dynLocal[0] || []])) return false + } + if (data["$dynamicRef"] !== undefined && hasOwn(data, "$dynamicRef")) { + if (!ref4(data["$dynamicRef"], [...dynAnchors, dynLocal[0] || []])) return false + } + if (data["$dynamicAnchor"] !== undefined && hasOwn(data, "$dynamicAnchor")) { + if (!ref3(data["$dynamicAnchor"], [...dynAnchors, dynLocal[0] || []])) return false + } + if (data["$vocabulary"] !== undefined && hasOwn(data, "$vocabulary")) { + if (!(typeof data["$vocabulary"] === "object" && data["$vocabulary"] && !Array.isArray(data["$vocabulary"]))) return false + for (const key2 of Object.keys(data["$vocabulary"])) { + if (!ref6(key2, [...dynAnchors, dynLocal[0] || []])) return false + } + for (const key3 of Object.keys(data["$vocabulary"])) { + if (!(typeof data["$vocabulary"][key3] === "boolean")) return false + } + } + if (data["$comment"] !== undefined && hasOwn(data, "$comment")) { + if (!(typeof data["$comment"] === "string")) return false + } + if (data["$defs"] !== undefined && hasOwn(data, "$defs")) { + if (!(typeof data["$defs"] === "object" && data["$defs"] && !Array.isArray(data["$defs"]))) return false + for (const key4 of Object.keys(data["$defs"])) { + if (!(dynamicResolve(dynAnchors || [], "#meta") || validate)(data["$defs"][key4], [...dynAnchors, dynLocal[0] || []])) return false + } + } + } + return true +}; +const ref8 = function validate(data, dynAnchors) { + if (!Array.isArray(data)) return false + if (data.length < 1) return false + for (let j = 0; j < data.length; j++) { + if (data[j] !== undefined && hasOwn(data, j)) { + if (!(dynamicResolve(dynAnchors || [], "#meta") || ref7)(data[j], dynAnchors)) return false + } + } + return true +}; +const format2 = (str) => { + if (str.length > 1e5) return false + const Z_ANCHOR = /[^\\]\\Z/ + if (Z_ANCHOR.test(str)) return false + try { + new RegExp(str, 'u') + return true + } catch (e) { + return false + } + }; +const ref7 = function validate(data, dynAnchors = []) { + const dynLocal = [{}] + dynLocal[0]["#meta"] = validate + if (!(typeof data === "object" && data && !Array.isArray(data) || typeof data === "boolean")) return false + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.prefixItems !== undefined && hasOwn(data, "prefixItems")) { + if (!ref8(data.prefixItems, [...dynAnchors, dynLocal[0] || []])) return false + } + if (data.items !== undefined && hasOwn(data, "items")) { + if (!(dynamicResolve(dynAnchors || [], "#meta") || validate)(data.items, [...dynAnchors, dynLocal[0] || []])) return false + } + if (data.contains !== undefined && hasOwn(data, "contains")) { + if (!(dynamicResolve(dynAnchors || [], "#meta") || validate)(data.contains, [...dynAnchors, dynLocal[0] || []])) return false + } + if (data.additionalProperties !== undefined && hasOwn(data, "additionalProperties")) { + if (!(dynamicResolve(dynAnchors || [], "#meta") || validate)(data.additionalProperties, [...dynAnchors, dynLocal[0] || []])) return false + } + if (data.properties !== undefined && hasOwn(data, "properties")) { + if (!(typeof data.properties === "object" && data.properties && !Array.isArray(data.properties))) return false + for (const key5 of Object.keys(data.properties)) { + if (!(dynamicResolve(dynAnchors || [], "#meta") || validate)(data.properties[key5], [...dynAnchors, dynLocal[0] || []])) return false + } + } + if (data.patternProperties !== undefined && hasOwn(data, "patternProperties")) { + if (!(typeof data.patternProperties === "object" && data.patternProperties && !Array.isArray(data.patternProperties))) return false + for (const key6 of Object.keys(data.patternProperties)) { + if (!format2(key6)) return false + } + for (const key7 of Object.keys(data.patternProperties)) { + if (!(dynamicResolve(dynAnchors || [], "#meta") || validate)(data.patternProperties[key7], [...dynAnchors, dynLocal[0] || []])) return false + } + } + if (data.dependentSchemas !== undefined && hasOwn(data, "dependentSchemas")) { + if (!(typeof data.dependentSchemas === "object" && data.dependentSchemas && !Array.isArray(data.dependentSchemas))) return false + for (const key8 of Object.keys(data.dependentSchemas)) { + if (!(dynamicResolve(dynAnchors || [], "#meta") || validate)(data.dependentSchemas[key8], [...dynAnchors, dynLocal[0] || []])) return false + } + } + if (data.propertyNames !== undefined && hasOwn(data, "propertyNames")) { + if (!(dynamicResolve(dynAnchors || [], "#meta") || validate)(data.propertyNames, [...dynAnchors, dynLocal[0] || []])) return false + } + if (data.if !== undefined && hasOwn(data, "if")) { + if (!(dynamicResolve(dynAnchors || [], "#meta") || validate)(data.if, [...dynAnchors, dynLocal[0] || []])) return false + } + if (data.then !== undefined && hasOwn(data, "then")) { + if (!(dynamicResolve(dynAnchors || [], "#meta") || validate)(data.then, [...dynAnchors, dynLocal[0] || []])) return false + } + if (data.else !== undefined && hasOwn(data, "else")) { + if (!(dynamicResolve(dynAnchors || [], "#meta") || validate)(data.else, [...dynAnchors, dynLocal[0] || []])) return false + } + if (data.allOf !== undefined && hasOwn(data, "allOf")) { + if (!ref8(data.allOf, [...dynAnchors, dynLocal[0] || []])) return false + } + if (data.anyOf !== undefined && hasOwn(data, "anyOf")) { + if (!ref8(data.anyOf, [...dynAnchors, dynLocal[0] || []])) return false + } + if (data.oneOf !== undefined && hasOwn(data, "oneOf")) { + if (!ref8(data.oneOf, [...dynAnchors, dynLocal[0] || []])) return false + } + if (data.not !== undefined && hasOwn(data, "not")) { + if (!(dynamicResolve(dynAnchors || [], "#meta") || validate)(data.not, [...dynAnchors, dynLocal[0] || []])) return false + } + } + return true +}; +const ref9 = function validate(data, dynAnchors = []) { + const dynLocal = [{}] + dynLocal[0]["#meta"] = validate + if (!(typeof data === "object" && data && !Array.isArray(data) || typeof data === "boolean")) return false + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.unevaluatedItems !== undefined && hasOwn(data, "unevaluatedItems")) { + if (!(dynamicResolve(dynAnchors || [], "#meta") || validate)(data.unevaluatedItems, [...dynAnchors, dynLocal[0] || []])) return false + } + if (data.unevaluatedProperties !== undefined && hasOwn(data, "unevaluatedProperties")) { + if (!(dynamicResolve(dynAnchors || [], "#meta") || validate)(data.unevaluatedProperties, [...dynAnchors, dynLocal[0] || []])) return false + } + } + return true +}; +const ref11 = function validate(data, dynAnchors) { + if (!(data === "array" || data === "boolean" || data === "integer" || data === "null" || data === "number" || data === "object" || data === "string")) return false + return true +}; +const ref12 = function validate(data, dynAnchors) { + if (!Number.isInteger(data)) return false + if (!(0 <= data)) return false + return true +}; +const ref13 = function validate(data, dynAnchors) { + if (!ref12(data, dynAnchors)) return false + return true +}; +const ref10 = function validate(data, dynAnchors = []) { + const dynLocal = [{}] + dynLocal[0]["#meta"] = validate + if (!(typeof data === "object" && data && !Array.isArray(data) || typeof data === "boolean")) return false + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.type !== undefined && hasOwn(data, "type")) { + const sub2 = (() => { + if (!ref11(data.type, [...dynAnchors, dynLocal[0] || []])) return false + return true + })() + if (!sub2) { + const sub3 = (() => { + if (!Array.isArray(data.type)) return false + if (data.type.length < 1) return false + for (let k = 0; k < data.type.length; k++) { + if (data.type[k] !== undefined && hasOwn(data.type, k)) { + if (!ref11(data.type[k], [...dynAnchors, dynLocal[0] || []])) return false + } + } + if (!unique(data.type)) return false + return true + })() + if (!sub3) return false + } + } + if (data.enum !== undefined && hasOwn(data, "enum")) { + if (!Array.isArray(data.enum)) return false + } + if (data.multipleOf !== undefined && hasOwn(data, "multipleOf")) { + if (!(typeof data.multipleOf === "number")) return false + if (!(0 < data.multipleOf)) return false + } + if (data.maximum !== undefined && hasOwn(data, "maximum")) { + if (!(typeof data.maximum === "number")) return false + } + if (data.exclusiveMaximum !== undefined && hasOwn(data, "exclusiveMaximum")) { + if (!(typeof data.exclusiveMaximum === "number")) return false + } + if (data.minimum !== undefined && hasOwn(data, "minimum")) { + if (!(typeof data.minimum === "number")) return false + } + if (data.exclusiveMinimum !== undefined && hasOwn(data, "exclusiveMinimum")) { + if (!(typeof data.exclusiveMinimum === "number")) return false + } + if (data.maxLength !== undefined && hasOwn(data, "maxLength")) { + if (!ref12(data.maxLength, [...dynAnchors, dynLocal[0] || []])) return false + } + if (data.minLength !== undefined && hasOwn(data, "minLength")) { + if (!ref13(data.minLength, [...dynAnchors, dynLocal[0] || []])) return false + } + if (data.pattern !== undefined && hasOwn(data, "pattern")) { + if (!(typeof data.pattern === "string")) return false + if (!format2(data.pattern)) return false + } + if (data.maxItems !== undefined && hasOwn(data, "maxItems")) { + if (!ref12(data.maxItems, [...dynAnchors, dynLocal[0] || []])) return false + } + if (data.minItems !== undefined && hasOwn(data, "minItems")) { + if (!ref13(data.minItems, [...dynAnchors, dynLocal[0] || []])) return false + } + if (data.uniqueItems !== undefined && hasOwn(data, "uniqueItems")) { + if (!(typeof data.uniqueItems === "boolean")) return false + } + if (data.maxContains !== undefined && hasOwn(data, "maxContains")) { + if (!ref12(data.maxContains, [...dynAnchors, dynLocal[0] || []])) return false + } + if (data.minContains !== undefined && hasOwn(data, "minContains")) { + if (!ref12(data.minContains, [...dynAnchors, dynLocal[0] || []])) return false + } + if (data.maxProperties !== undefined && hasOwn(data, "maxProperties")) { + if (!ref12(data.maxProperties, [...dynAnchors, dynLocal[0] || []])) return false + } + if (data.minProperties !== undefined && hasOwn(data, "minProperties")) { + if (!ref13(data.minProperties, [...dynAnchors, dynLocal[0] || []])) return false + } + if (data.required !== undefined && hasOwn(data, "required")) { + if (!ref2(data.required, [...dynAnchors, dynLocal[0] || []])) return false + } + if (data.dependentRequired !== undefined && hasOwn(data, "dependentRequired")) { + if (!(typeof data.dependentRequired === "object" && data.dependentRequired && !Array.isArray(data.dependentRequired))) return false + for (const key9 of Object.keys(data.dependentRequired)) { + if (!ref2(data.dependentRequired[key9], [...dynAnchors, dynLocal[0] || []])) return false + } + } + } + return true +}; +const ref14 = function validate(data, dynAnchors) { + if (!(typeof data === "object" && data && !Array.isArray(data) || typeof data === "boolean")) return false + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.title !== undefined && hasOwn(data, "title")) { + if (!(typeof data.title === "string")) return false + } + if (data.description !== undefined && hasOwn(data, "description")) { + if (!(typeof data.description === "string")) return false + } + if (data.deprecated !== undefined && hasOwn(data, "deprecated")) { + if (!(typeof data.deprecated === "boolean")) return false + } + if (data.readOnly !== undefined && hasOwn(data, "readOnly")) { + if (!(typeof data.readOnly === "boolean")) return false + } + if (data.writeOnly !== undefined && hasOwn(data, "writeOnly")) { + if (!(typeof data.writeOnly === "boolean")) return false + } + if (data.examples !== undefined && hasOwn(data, "examples")) { + if (!Array.isArray(data.examples)) return false + } + } + return true +}; +const ref15 = function validate(data, dynAnchors) { + if (!(typeof data === "object" && data && !Array.isArray(data) || typeof data === "boolean")) return false + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.format !== undefined && hasOwn(data, "format")) { + if (!(typeof data.format === "string")) return false + } + } + return true +}; +const ref16 = function validate(data, dynAnchors = []) { + const dynLocal = [{}] + dynLocal[0]["#meta"] = validate + if (!(typeof data === "object" && data && !Array.isArray(data) || typeof data === "boolean")) return false + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.contentEncoding !== undefined && hasOwn(data, "contentEncoding")) { + if (!(typeof data.contentEncoding === "string")) return false + } + if (data.contentMediaType !== undefined && hasOwn(data, "contentMediaType")) { + if (!(typeof data.contentMediaType === "string")) return false + } + if (data.contentSchema !== undefined && hasOwn(data, "contentSchema")) { + if (!(dynamicResolve(dynAnchors || [], "#meta") || validate)(data.contentSchema, [...dynAnchors, dynLocal[0] || []])) return false + } + } + return true +}; +const ref1 = function validate(data, dynAnchors = []) { + const dynLocal = [{}] + dynLocal[0]["#meta"] = validate + if (!(typeof data === "object" && data && !Array.isArray(data) || typeof data === "boolean")) return false + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.definitions !== undefined && hasOwn(data, "definitions")) { + if (!(typeof data.definitions === "object" && data.definitions && !Array.isArray(data.definitions))) return false + for (const key0 of Object.keys(data.definitions)) { + if (!(dynamicResolve(dynAnchors || [], "#meta") || validate)(data.definitions[key0], [...dynAnchors, dynLocal[0] || []])) return false + } + } + if (data.dependencies !== undefined && hasOwn(data, "dependencies")) { + if (!(typeof data.dependencies === "object" && data.dependencies && !Array.isArray(data.dependencies))) return false + for (const key1 of Object.keys(data.dependencies)) { + const sub0 = (() => { + if (!(dynamicResolve(dynAnchors || [], "#meta") || validate)(data.dependencies[key1], [...dynAnchors, dynLocal[0] || []])) return false + return true + })() + if (!sub0) { + const sub1 = (() => { + if (!ref2(data.dependencies[key1], [...dynAnchors, dynLocal[0] || []])) return false + return true + })() + if (!sub1) return false + } + } + } + if (data["$recursiveAnchor"] !== undefined && hasOwn(data, "$recursiveAnchor")) { + if (!ref3(data["$recursiveAnchor"], [...dynAnchors, dynLocal[0] || []])) return false + } + if (data["$recursiveRef"] !== undefined && hasOwn(data, "$recursiveRef")) { + if (!ref4(data["$recursiveRef"], [...dynAnchors, dynLocal[0] || []])) return false + } + } + if (!ref5(data, [...dynAnchors, dynLocal[0] || []])) return false + if (!ref7(data, [...dynAnchors, dynLocal[0] || []])) return false + if (!ref9(data, [...dynAnchors, dynLocal[0] || []])) return false + if (!ref10(data, [...dynAnchors, dynLocal[0] || []])) return false + if (!ref14(data, [...dynAnchors, dynLocal[0] || []])) return false + if (!ref15(data, [...dynAnchors, dynLocal[0] || []])) return false + if (!ref16(data, [...dynAnchors, dynLocal[0] || []])) return false + return true +}; +const ref0 = function validate(data, dynAnchors) { + if (!ref1(data, dynAnchors)) return false + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at https://json-schema.org/draft/next/schema#/properties/definitions/additionalProperties` + diff --git a/doc/samples/draft-next/anyOf.md b/doc/samples/draft-next/anyOf.md new file mode 100644 index 0000000..3fcf9b7 --- /dev/null +++ b/doc/samples/draft-next/anyOf.md @@ -0,0 +1,233 @@ +# anyOf + +## anyOf + +### Schema + +```json +{ "anyOf": [{ "type": "integer" }, { "minimum": 2 }] } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + const sub0 = (() => { + if (!Number.isInteger(data)) return false + return true + })() + if (!sub0) { + const sub1 = (() => { + if (typeof data === "number") { + if (!(2 <= data)) return false + } + return true + })() + if (!sub1) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## anyOf with base schema + +### Schema + +```json +{ "type": "string", "anyOf": [{ "maxLength": 2 }, { "minLength": 4 }] } +``` + +### Code + +```js +'use strict' +const stringLength = (string) => + /[\uD800-\uDFFF]/.test(string) ? [...string].length : string.length; +const ref0 = function validate(data) { + if (!(typeof data === "string")) return false + const sub0 = (() => { + if (data.length > 2 && stringLength(data) > 2) return false + return true + })() + if (!sub0) { + const sub1 = (() => { + if (data.length < 4 || stringLength(data) < 4) return false + return true + })() + if (!sub1) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireStringValidation] pattern, format or contentSchema should be specified for strings, use pattern: ^[\s\S]*$ to opt-out at #` + + +## anyOf with boolean schemas, all true + +### Schema + +```json +{ "anyOf": [true, true] } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + return true +}; +return ref0 +``` + +### Warnings + + * `some checks are never reachable at #` + + +## anyOf with boolean schemas, some true + +### Schema + +```json +{ "anyOf": [true, false] } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + return true +}; +return ref0 +``` + +### Warnings + + * `some checks are never reachable at #` + + +## anyOf with boolean schemas, all false + +### Schema + +```json +{ "anyOf": [false, false] } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + return false + return true +}; +return ref0 +``` + + +## anyOf complex types + +### Schema + +```json +{ + "anyOf": [ + { "properties": { "bar": { "type": "integer" } }, "required": ["bar"] }, + { "properties": { "foo": { "type": "string" } }, "required": ["foo"] } + ] +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + const sub0 = (() => { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (!(data.bar !== undefined && hasOwn(data, "bar"))) return false + if (!Number.isInteger(data.bar)) return false + } + return true + })() + if (!sub0) { + const sub1 = (() => { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (!(data.foo !== undefined && hasOwn(data, "foo"))) return false + if (!(typeof data.foo === "string")) return false + } + return true + })() + if (!sub1) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireStringValidation] pattern, format or contentSchema should be specified for strings, use pattern: ^[\s\S]*$ to opt-out at #/anyOf/1/properties/foo` + + +## anyOf with one empty schema + +### Schema + +```json +{ "anyOf": [{ "type": "number" }, {}] } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + const sub0 = (() => { + if (!(typeof data === "number")) return false + return true + })() + return true +}; +return ref0 +``` + +### Warnings + + * `some checks are never reachable at #` + + +## nested anyOf, to check validation semantics + +### Schema + +```json +{ "anyOf": [{ "anyOf": [{ "type": "null" }] }] } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (!(data === null)) return false + return true +}; +return ref0 +``` + diff --git a/doc/samples/draft-next/boolean_schema.md b/doc/samples/draft-next/boolean_schema.md new file mode 100644 index 0000000..406f7d6 --- /dev/null +++ b/doc/samples/draft-next/boolean_schema.md @@ -0,0 +1,44 @@ +# boolean_schema + +## boolean schema 'true' + +### Schema + +```json +true +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] schema = true is not allowed at #` + + +## boolean schema 'false' + +### Schema + +```json +false +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + return false + return true +}; +return ref0 +``` + diff --git a/doc/samples/draft-next/const.md b/doc/samples/draft-next/const.md new file mode 100644 index 0000000..a918cab --- /dev/null +++ b/doc/samples/draft-next/const.md @@ -0,0 +1,324 @@ +# const + +## const validation + +### Schema + +```json +{ "const": 2 } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (!(data === 2)) return false + return true +}; +return ref0 +``` + + +## const with object + +### Schema + +```json +{ "const": { "foo": "bar", "baz": "bax" } } +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (!(typeof data === "object" && data && !Array.isArray(data) && Object.keys(data).length === 2 && hasOwn(data, "foo") && hasOwn(data, "baz") && data["foo"] === "bar" && data["baz"] === "bax")) return false + return true +}; +return ref0 +``` + + +## const with array + +### Schema + +```json +{ "const": [{ "foo": "bar" }] } +``` + +### Code + +```js +'use strict' +const deepEqual = (obj, obj2) => { + if (obj === obj2) return true + if (!obj || !obj2 || typeof obj !== typeof obj2) return false + if (obj !== obj2 && typeof obj !== 'object') return false + + const proto = Object.getPrototypeOf(obj) + if (proto !== Object.getPrototypeOf(obj2)) return false + + if (proto === Array.prototype) { + if (!Array.isArray(obj) || !Array.isArray(obj2)) return false + if (obj.length !== obj2.length) return false + return obj.every((x, i) => deepEqual(x, obj2[i])) + } else if (proto === Object.prototype) { + const [keys, keys2] = [Object.keys(obj), Object.keys(obj2)] + if (keys.length !== keys2.length) return false + const keyset2 = new Set([...keys, ...keys2]) + return keyset2.size === keys.length && keys.every((key) => deepEqual(obj[key], obj2[key])) + } + return false +}; +const ref0 = function validate(data) { + if (!(Array.isArray(data) && deepEqual(data, [{"foo":"bar"}]))) return false + return true +}; +return ref0 +``` + + +## const with null + +### Schema + +```json +{ "const": null } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (!(data === null)) return false + return true +}; +return ref0 +``` + + +## const with false does not match 0 + +### Schema + +```json +{ "const": false } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (!(data === false)) return false + return true +}; +return ref0 +``` + + +## const with true does not match 1 + +### Schema + +```json +{ "const": true } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (!(data === true)) return false + return true +}; +return ref0 +``` + + +## const with [false] does not match [0] + +### Schema + +```json +{ "const": [false] } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (!(Array.isArray(data) && data.length === 1 && data[0] === false)) return false + return true +}; +return ref0 +``` + + +## const with [true] does not match [1] + +### Schema + +```json +{ "const": [true] } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (!(Array.isArray(data) && data.length === 1 && data[0] === true)) return false + return true +}; +return ref0 +``` + + +## const with {"a": false} does not match {"a": 0} + +### Schema + +```json +{ "const": { "a": false } } +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (!(typeof data === "object" && data && !Array.isArray(data) && Object.keys(data).length === 1 && hasOwn(data, "a") && data["a"] === false)) return false + return true +}; +return ref0 +``` + + +## const with {"a": true} does not match {"a": 1} + +### Schema + +```json +{ "const": { "a": true } } +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (!(typeof data === "object" && data && !Array.isArray(data) && Object.keys(data).length === 1 && hasOwn(data, "a") && data["a"] === true)) return false + return true +}; +return ref0 +``` + + +## const with 0 does not match other zero-like types + +### Schema + +```json +{ "const": 0 } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (!(data === 0)) return false + return true +}; +return ref0 +``` + + +## const with 1 does not match true + +### Schema + +```json +{ "const": 1 } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (!(data === 1)) return false + return true +}; +return ref0 +``` + + +## const with -2.0 matches integer and float types + +### Schema + +```json +{ "const": -2 } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (!(data === -2)) return false + return true +}; +return ref0 +``` + + +## float and integers are equal up to 64-bit representation limits + +### Schema + +```json +{ "const": 9007199254740992 } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (!(data === 9007199254740992)) return false + return true +}; +return ref0 +``` + + +## nul characters in strings + +### Schema + +```json +{ "const": "hello\u0000there" } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (!(data === "hello\u0000there")) return false + return true +}; +return ref0 +``` + diff --git a/doc/samples/draft-next/contains.md b/doc/samples/draft-next/contains.md new file mode 100644 index 0000000..eeb9396 --- /dev/null +++ b/doc/samples/draft-next/contains.md @@ -0,0 +1,297 @@ +# contains + +## contains keyword validation + +### Schema + +```json +{ "contains": { "minimum": 5 } } +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (Array.isArray(data)) { + let passes0 = 0 + for (let i = 0; i < data.length; i++) { + const sub0 = (() => { + if (data[i] !== undefined && hasOwn(data, i)) { + if (typeof data[i] === "number") { + if (!(5 <= data[i])) return false + } + } + return true + })() + if (sub0) passes0++ + } + if (passes0 < 1) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #/contains` + +### Misclassified! + +**This schema caused 2 misclassifications!** + + +## contains keyword with const keyword + +### Schema + +```json +{ "contains": { "const": 5 } } +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (Array.isArray(data)) { + let passes0 = 0 + for (let i = 0; i < data.length; i++) { + const sub0 = (() => { + if (data[i] !== undefined && hasOwn(data, i)) { + if (!(data[i] === 5)) return false + } + return true + })() + if (sub0) passes0++ + } + if (passes0 < 1) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + +### Misclassified! + +**This schema caused 1 misclassifications!** + + +## contains keyword with boolean schema true + +### Schema + +```json +{ "contains": true } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (Array.isArray(data)) { + let passes0 = 0 + for (let i = 0; i < data.length; i++) { + const sub0 = (() => { + return true + })() + if (sub0) passes0++ + } + if (passes0 < 1) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] schema = true is not allowed at #/contains` + +### Misclassified! + +**This schema caused 1 misclassifications!** + + +## contains keyword with boolean schema false + +### Schema + +```json +{ "contains": false } +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (Array.isArray(data)) { + let passes0 = 0 + for (let i = 0; i < data.length; i++) { + const sub0 = (() => { + if (data[i] !== undefined && hasOwn(data, i)) return false + return true + })() + if (sub0) passes0++ + } + if (passes0 < 1) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + +### Misclassified! + +**This schema caused 1 misclassifications!** + + +## items + contains + +### Schema + +```json +{ + "additionalProperties": { "multipleOf": 2 }, + "items": { "multipleOf": 2 }, + "contains": { "multipleOf": 3 } +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (Array.isArray(data)) { + for (let i = 0; i < data.length; i++) { + if (data[i] !== undefined && hasOwn(data, i)) { + if (typeof data[i] === "number") { + if (data[i] % 2 !== 0) return false + } + } + } + let passes0 = 0 + for (let j = 0; j < data.length; j++) { + const sub0 = (() => { + if (data[j] !== undefined && hasOwn(data, j)) { + if (typeof data[j] === "number") { + if (data[j] % 3 !== 0) return false + } + } + return true + })() + if (sub0) passes0++ + } + if (passes0 < 1) return false + } + if (typeof data === "object" && data && !Array.isArray(data)) { + for (const key0 of Object.keys(data)) { + if (typeof data[key0] === "number") { + if (data[key0] % 2 !== 0) return false + } + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #/items` + +### Misclassified! + +**This schema caused 1 misclassifications!** + + +## contains with false if subschema + +### Schema + +```json +{ "contains": { "if": false, "else": true } } +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (Array.isArray(data)) { + let passes0 = 0 + for (let i = 0; i < data.length; i++) { + const sub0 = (() => { + return true + })() + if (sub0) passes0++ + } + if (passes0 < 1) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] schema = true is not allowed at #/contains/else` + +### Misclassified! + +**This schema caused 1 misclassifications!** + + +## contains with null instance elements + +### Schema + +```json +{ "contains": { "type": "null" } } +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (Array.isArray(data)) { + let passes0 = 0 + for (let i = 0; i < data.length; i++) { + const sub0 = (() => { + if (data[i] !== undefined && hasOwn(data, i)) { + if (!(data[i] === null)) return false + } + return true + })() + if (sub0) passes0++ + } + if (passes0 < 1) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + diff --git a/doc/samples/draft-next/content.md b/doc/samples/draft-next/content.md new file mode 100644 index 0000000..b5caf2d --- /dev/null +++ b/doc/samples/draft-next/content.md @@ -0,0 +1,100 @@ +# content + +## validation of string-encoded content based on media type + +### Schema + +```json +{ "contentMediaType": "application/json" } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + return true +}; +return ref0 +``` + +### Warnings + + * `"content*" keywords are disabled by default per spec, enable with { contentValidation = true } option (see doc/Options.md for more info) at #` + + +## validation of binary string-encoding + +### Schema + +```json +{ "contentEncoding": "base64" } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + return true +}; +return ref0 +``` + +### Warnings + + * `"content*" keywords are disabled by default per spec, enable with { contentValidation = true } option (see doc/Options.md for more info) at #` + + +## validation of binary-encoded media type documents + +### Schema + +```json +{ "contentMediaType": "application/json", "contentEncoding": "base64" } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + return true +}; +return ref0 +``` + +### Warnings + + * `"content*" keywords are disabled by default per spec, enable with { contentValidation = true } option (see doc/Options.md for more info) at #` + + +## validation of binary-encoded media type documents with schema + +### Schema + +```json +{ + "contentMediaType": "application/json", + "contentEncoding": "base64", + "contentSchema": { + "required": ["foo"], + "properties": { "foo": { "type": "string" } } + } +} +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + return true +}; +return ref0 +``` + +### Warnings + + * `"content*" keywords are disabled by default per spec, enable with { contentValidation = true } option (see doc/Options.md for more info) at #` + diff --git a/doc/samples/draft-next/default.md b/doc/samples/draft-next/default.md new file mode 100644 index 0000000..9e6b1e6 --- /dev/null +++ b/doc/samples/draft-next/default.md @@ -0,0 +1,98 @@ +# default + +## invalid type for default + +### Schema + +```json +{ "properties": { "foo": { "type": "integer", "default": [] } } } +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.foo !== undefined && hasOwn(data, "foo")) { + if (!Number.isInteger(data.foo)) return false + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## invalid string value for default + +### Schema + +```json +{ + "properties": { + "bar": { "type": "string", "minLength": 4, "default": "bad" } + } +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const stringLength = (string) => + /[\uD800-\uDFFF]/.test(string) ? [...string].length : string.length; +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.bar !== undefined && hasOwn(data, "bar")) { + if (!(typeof data.bar === "string")) return false + if (data.bar.length < 4 || stringLength(data.bar) < 4) return false + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireStringValidation] pattern, format or contentSchema should be specified for strings, use pattern: ^[\s\S]*$ to opt-out at #/properties/bar` + + +## the default keyword does not do anything if the property is missing + +### Schema + +```json +{ + "type": "object", + "properties": { "alpha": { "type": "number", "maximum": 3, "default": 5 } } +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (!(typeof data === "object" && data && !Array.isArray(data))) return false + if (data.alpha !== undefined && hasOwn(data, "alpha")) { + if (!(typeof data.alpha === "number")) return false + if (!(3 >= data.alpha)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] additionalProperties or unevaluatedProperties should be specified at #` + diff --git a/doc/samples/draft-next/defs.md b/doc/samples/draft-next/defs.md new file mode 100644 index 0000000..ea6b05a --- /dev/null +++ b/doc/samples/draft-next/defs.md @@ -0,0 +1,436 @@ +# defs + +## validate definition against metaschema + +### Schema + +```json +{ "$ref": "https://json-schema.org/draft/next/schema" } +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const dynamicResolve = (anchors, id) => (anchors.filter((x) => x[id])[0] || {})[id]; +const unique = (array) => { + if (array.length < 2) return true + if (array.length === 2) return !deepEqual(array[0], array[1]) + const objects = [] + const primitives = array.length > 20 ? new Set() : null + let primitivesCount = 0 + let pos = 0 + for (const item of array) { + if (typeof item === 'object') { + objects.push(item) + } else if (primitives) { + primitives.add(item) + if (primitives.size !== ++primitivesCount) return false + } else { + if (array.indexOf(item, pos + 1) !== -1) return false + } + pos++ + } + for (let i = 1; i < objects.length; i++) + for (let j = 0; j < i; j++) if (deepEqual(objects[i], objects[j])) return false + return true +}; +const deepEqual = (obj, obj2) => { + if (obj === obj2) return true + if (!obj || !obj2 || typeof obj !== typeof obj2) return false + if (obj !== obj2 && typeof obj !== 'object') return false + + const proto = Object.getPrototypeOf(obj) + if (proto !== Object.getPrototypeOf(obj2)) return false + + if (proto === Array.prototype) { + if (!Array.isArray(obj) || !Array.isArray(obj2)) return false + if (obj.length !== obj2.length) return false + return obj.every((x, i) => deepEqual(x, obj2[i])) + } else if (proto === Object.prototype) { + const [keys, keys2] = [Object.keys(obj), Object.keys(obj2)] + if (keys.length !== keys2.length) return false + const keyset2 = new Set([...keys, ...keys2]) + return keyset2.size === keys.length && keys.every((key) => deepEqual(obj[key], obj2[key])) + } + return false +}; +const ref2 = function validate(data, dynAnchors) { + if (!Array.isArray(data)) return false + for (let i = 0; i < data.length; i++) { + if (data[i] !== undefined && hasOwn(data, i)) { + if (!(typeof data[i] === "string")) return false + } + } + if (!unique(data)) return false + return true +}; +const pattern0 = new RegExp("^[A-Za-z_][-A-Za-z0-9._]*$", "u"); +const ref3 = function validate(data, dynAnchors) { + if (!(typeof data === "string")) return false + if (!pattern0.test(data)) return false + return true +}; +const format0 = new RegExp("^(?:[a-z][a-z0-9+\\-.]*:)?(?:\\/?\\/(?:(?:[a-z0-9\\-._~!$&'()*+,;=:]|%[0-9a-f]{2})*@)?(?:\\[(?:(?:(?:(?:[0-9a-f]{1,4}:){6}|::(?:[0-9a-f]{1,4}:){5}|(?:[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){4}|(?:(?:[0-9a-f]{1,4}:){0,1}[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){3}|(?:(?:[0-9a-f]{1,4}:){0,2}[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){2}|(?:(?:[0-9a-f]{1,4}:){0,3}[0-9a-f]{1,4})?::[0-9a-f]{1,4}:|(?:(?:[0-9a-f]{1,4}:){0,4}[0-9a-f]{1,4})?::)(?:[0-9a-f]{1,4}:[0-9a-f]{1,4}|(?:(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d\\d?)\\.){3}(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d\\d?))|(?:(?:[0-9a-f]{1,4}:){0,5}[0-9a-f]{1,4})?::[0-9a-f]{1,4}|(?:(?:[0-9a-f]{1,4}:){0,6}[0-9a-f]{1,4})?::)|v[0-9a-f]+\\.[a-z0-9\\-._~!$&'()*+,;=:]+)\\]|(?:(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d\\d?)\\.){3}(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d\\d?)|(?:[a-z0-9\\-._~!$&'()*+,;=]|%[0-9a-f]{2})*)(?::\\d*)?(?:\\/(?:[a-z0-9\\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})*)*|\\/?(?:(?:[a-z0-9\\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})+(?:\\/(?:[a-z0-9\\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})*)*)?)?(?:\\?(?:[a-z0-9\\-._~!$&'()*+,;=:@/?]|%[0-9a-f]{2})*)?(?:#(?:[a-z0-9\\-._~!$&'()*+,;=:@/?]|%[0-9a-f]{2})*)?$", "i"); +const ref4 = function validate(data, dynAnchors) { + if (!(typeof data === "string")) return false + if (!format0.test(data)) return false + return true +}; +const pattern1 = new RegExp("^[^#]*#?$", "u"); +const format1 = new RegExp("^[a-z][a-z0-9+\\-.]*:(?:\\/?\\/(?:(?:[a-z0-9\\-._~!$&'()*+,;=:]|%[0-9a-f]{2})*@)?(?:\\[(?:(?:(?:(?:[0-9a-f]{1,4}:){6}|::(?:[0-9a-f]{1,4}:){5}|(?:[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){4}|(?:(?:[0-9a-f]{1,4}:){0,1}[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){3}|(?:(?:[0-9a-f]{1,4}:){0,2}[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){2}|(?:(?:[0-9a-f]{1,4}:){0,3}[0-9a-f]{1,4})?::[0-9a-f]{1,4}:|(?:(?:[0-9a-f]{1,4}:){0,4}[0-9a-f]{1,4})?::)(?:[0-9a-f]{1,4}:[0-9a-f]{1,4}|(?:(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d\\d?)\\.){3}(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d\\d?))|(?:(?:[0-9a-f]{1,4}:){0,5}[0-9a-f]{1,4})?::[0-9a-f]{1,4}|(?:(?:[0-9a-f]{1,4}:){0,6}[0-9a-f]{1,4})?::)|v[0-9a-f]+\\.[a-z0-9\\-._~!$&'()*+,;=:]+)\\]|(?:(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d\\d?)\\.){3}(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d\\d?)|(?:[a-z0-9\\-._~!$&'()*+,;=]|%[0-9a-f]{2})*)(?::\\d*)?(?:\\/(?:[a-z0-9\\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})*)*|\\/?(?:(?:[a-z0-9\\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})+(?:\\/(?:[a-z0-9\\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})*)*)?)(?:\\?(?:[a-z0-9\\-._~!$&'()*+,;=:@/?]|%[0-9a-f]{2})*)?(?:#(?:[a-z0-9\\-._~!$&'()*+,;=:@/?]|%[0-9a-f]{2})*)?$", "i"); +const ref6 = function validate(data, dynAnchors) { + if (!(typeof data === "string")) return false + if (!format1.test(data)) return false + return true +}; +const ref5 = function validate(data, dynAnchors = []) { + const dynLocal = [{}] + dynLocal[0]["#meta"] = validate + if (!(typeof data === "object" && data && !Array.isArray(data) || typeof data === "boolean")) return false + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data["$id"] !== undefined && hasOwn(data, "$id")) { + if (!ref4(data["$id"], [...dynAnchors, dynLocal[0] || []])) return false + if (!(pattern1.test(data["$id"]))) return false + } + if (data["$schema"] !== undefined && hasOwn(data, "$schema")) { + if (!ref6(data["$schema"], [...dynAnchors, dynLocal[0] || []])) return false + } + if (data["$ref"] !== undefined && hasOwn(data, "$ref")) { + if (!ref4(data["$ref"], [...dynAnchors, dynLocal[0] || []])) return false + } + if (data["$anchor"] !== undefined && hasOwn(data, "$anchor")) { + if (!ref3(data["$anchor"], [...dynAnchors, dynLocal[0] || []])) return false + } + if (data["$dynamicRef"] !== undefined && hasOwn(data, "$dynamicRef")) { + if (!ref4(data["$dynamicRef"], [...dynAnchors, dynLocal[0] || []])) return false + } + if (data["$dynamicAnchor"] !== undefined && hasOwn(data, "$dynamicAnchor")) { + if (!ref3(data["$dynamicAnchor"], [...dynAnchors, dynLocal[0] || []])) return false + } + if (data["$vocabulary"] !== undefined && hasOwn(data, "$vocabulary")) { + if (!(typeof data["$vocabulary"] === "object" && data["$vocabulary"] && !Array.isArray(data["$vocabulary"]))) return false + for (const key2 of Object.keys(data["$vocabulary"])) { + if (!ref6(key2, [...dynAnchors, dynLocal[0] || []])) return false + } + for (const key3 of Object.keys(data["$vocabulary"])) { + if (!(typeof data["$vocabulary"][key3] === "boolean")) return false + } + } + if (data["$comment"] !== undefined && hasOwn(data, "$comment")) { + if (!(typeof data["$comment"] === "string")) return false + } + if (data["$defs"] !== undefined && hasOwn(data, "$defs")) { + if (!(typeof data["$defs"] === "object" && data["$defs"] && !Array.isArray(data["$defs"]))) return false + for (const key4 of Object.keys(data["$defs"])) { + if (!(dynamicResolve(dynAnchors || [], "#meta") || validate)(data["$defs"][key4], [...dynAnchors, dynLocal[0] || []])) return false + } + } + } + return true +}; +const ref8 = function validate(data, dynAnchors) { + if (!Array.isArray(data)) return false + if (data.length < 1) return false + for (let j = 0; j < data.length; j++) { + if (data[j] !== undefined && hasOwn(data, j)) { + if (!(dynamicResolve(dynAnchors || [], "#meta") || ref7)(data[j], dynAnchors)) return false + } + } + return true +}; +const format2 = (str) => { + if (str.length > 1e5) return false + const Z_ANCHOR = /[^\\]\\Z/ + if (Z_ANCHOR.test(str)) return false + try { + new RegExp(str, 'u') + return true + } catch (e) { + return false + } + }; +const ref7 = function validate(data, dynAnchors = []) { + const dynLocal = [{}] + dynLocal[0]["#meta"] = validate + if (!(typeof data === "object" && data && !Array.isArray(data) || typeof data === "boolean")) return false + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.prefixItems !== undefined && hasOwn(data, "prefixItems")) { + if (!ref8(data.prefixItems, [...dynAnchors, dynLocal[0] || []])) return false + } + if (data.items !== undefined && hasOwn(data, "items")) { + if (!(dynamicResolve(dynAnchors || [], "#meta") || validate)(data.items, [...dynAnchors, dynLocal[0] || []])) return false + } + if (data.contains !== undefined && hasOwn(data, "contains")) { + if (!(dynamicResolve(dynAnchors || [], "#meta") || validate)(data.contains, [...dynAnchors, dynLocal[0] || []])) return false + } + if (data.additionalProperties !== undefined && hasOwn(data, "additionalProperties")) { + if (!(dynamicResolve(dynAnchors || [], "#meta") || validate)(data.additionalProperties, [...dynAnchors, dynLocal[0] || []])) return false + } + if (data.properties !== undefined && hasOwn(data, "properties")) { + if (!(typeof data.properties === "object" && data.properties && !Array.isArray(data.properties))) return false + for (const key5 of Object.keys(data.properties)) { + if (!(dynamicResolve(dynAnchors || [], "#meta") || validate)(data.properties[key5], [...dynAnchors, dynLocal[0] || []])) return false + } + } + if (data.patternProperties !== undefined && hasOwn(data, "patternProperties")) { + if (!(typeof data.patternProperties === "object" && data.patternProperties && !Array.isArray(data.patternProperties))) return false + for (const key6 of Object.keys(data.patternProperties)) { + if (!format2(key6)) return false + } + for (const key7 of Object.keys(data.patternProperties)) { + if (!(dynamicResolve(dynAnchors || [], "#meta") || validate)(data.patternProperties[key7], [...dynAnchors, dynLocal[0] || []])) return false + } + } + if (data.dependentSchemas !== undefined && hasOwn(data, "dependentSchemas")) { + if (!(typeof data.dependentSchemas === "object" && data.dependentSchemas && !Array.isArray(data.dependentSchemas))) return false + for (const key8 of Object.keys(data.dependentSchemas)) { + if (!(dynamicResolve(dynAnchors || [], "#meta") || validate)(data.dependentSchemas[key8], [...dynAnchors, dynLocal[0] || []])) return false + } + } + if (data.propertyNames !== undefined && hasOwn(data, "propertyNames")) { + if (!(dynamicResolve(dynAnchors || [], "#meta") || validate)(data.propertyNames, [...dynAnchors, dynLocal[0] || []])) return false + } + if (data.if !== undefined && hasOwn(data, "if")) { + if (!(dynamicResolve(dynAnchors || [], "#meta") || validate)(data.if, [...dynAnchors, dynLocal[0] || []])) return false + } + if (data.then !== undefined && hasOwn(data, "then")) { + if (!(dynamicResolve(dynAnchors || [], "#meta") || validate)(data.then, [...dynAnchors, dynLocal[0] || []])) return false + } + if (data.else !== undefined && hasOwn(data, "else")) { + if (!(dynamicResolve(dynAnchors || [], "#meta") || validate)(data.else, [...dynAnchors, dynLocal[0] || []])) return false + } + if (data.allOf !== undefined && hasOwn(data, "allOf")) { + if (!ref8(data.allOf, [...dynAnchors, dynLocal[0] || []])) return false + } + if (data.anyOf !== undefined && hasOwn(data, "anyOf")) { + if (!ref8(data.anyOf, [...dynAnchors, dynLocal[0] || []])) return false + } + if (data.oneOf !== undefined && hasOwn(data, "oneOf")) { + if (!ref8(data.oneOf, [...dynAnchors, dynLocal[0] || []])) return false + } + if (data.not !== undefined && hasOwn(data, "not")) { + if (!(dynamicResolve(dynAnchors || [], "#meta") || validate)(data.not, [...dynAnchors, dynLocal[0] || []])) return false + } + } + return true +}; +const ref9 = function validate(data, dynAnchors = []) { + const dynLocal = [{}] + dynLocal[0]["#meta"] = validate + if (!(typeof data === "object" && data && !Array.isArray(data) || typeof data === "boolean")) return false + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.unevaluatedItems !== undefined && hasOwn(data, "unevaluatedItems")) { + if (!(dynamicResolve(dynAnchors || [], "#meta") || validate)(data.unevaluatedItems, [...dynAnchors, dynLocal[0] || []])) return false + } + if (data.unevaluatedProperties !== undefined && hasOwn(data, "unevaluatedProperties")) { + if (!(dynamicResolve(dynAnchors || [], "#meta") || validate)(data.unevaluatedProperties, [...dynAnchors, dynLocal[0] || []])) return false + } + } + return true +}; +const ref11 = function validate(data, dynAnchors) { + if (!(data === "array" || data === "boolean" || data === "integer" || data === "null" || data === "number" || data === "object" || data === "string")) return false + return true +}; +const ref12 = function validate(data, dynAnchors) { + if (!Number.isInteger(data)) return false + if (!(0 <= data)) return false + return true +}; +const ref13 = function validate(data, dynAnchors) { + if (!ref12(data, dynAnchors)) return false + return true +}; +const ref10 = function validate(data, dynAnchors = []) { + const dynLocal = [{}] + dynLocal[0]["#meta"] = validate + if (!(typeof data === "object" && data && !Array.isArray(data) || typeof data === "boolean")) return false + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.type !== undefined && hasOwn(data, "type")) { + const sub2 = (() => { + if (!ref11(data.type, [...dynAnchors, dynLocal[0] || []])) return false + return true + })() + if (!sub2) { + const sub3 = (() => { + if (!Array.isArray(data.type)) return false + if (data.type.length < 1) return false + for (let k = 0; k < data.type.length; k++) { + if (data.type[k] !== undefined && hasOwn(data.type, k)) { + if (!ref11(data.type[k], [...dynAnchors, dynLocal[0] || []])) return false + } + } + if (!unique(data.type)) return false + return true + })() + if (!sub3) return false + } + } + if (data.enum !== undefined && hasOwn(data, "enum")) { + if (!Array.isArray(data.enum)) return false + } + if (data.multipleOf !== undefined && hasOwn(data, "multipleOf")) { + if (!(typeof data.multipleOf === "number")) return false + if (!(0 < data.multipleOf)) return false + } + if (data.maximum !== undefined && hasOwn(data, "maximum")) { + if (!(typeof data.maximum === "number")) return false + } + if (data.exclusiveMaximum !== undefined && hasOwn(data, "exclusiveMaximum")) { + if (!(typeof data.exclusiveMaximum === "number")) return false + } + if (data.minimum !== undefined && hasOwn(data, "minimum")) { + if (!(typeof data.minimum === "number")) return false + } + if (data.exclusiveMinimum !== undefined && hasOwn(data, "exclusiveMinimum")) { + if (!(typeof data.exclusiveMinimum === "number")) return false + } + if (data.maxLength !== undefined && hasOwn(data, "maxLength")) { + if (!ref12(data.maxLength, [...dynAnchors, dynLocal[0] || []])) return false + } + if (data.minLength !== undefined && hasOwn(data, "minLength")) { + if (!ref13(data.minLength, [...dynAnchors, dynLocal[0] || []])) return false + } + if (data.pattern !== undefined && hasOwn(data, "pattern")) { + if (!(typeof data.pattern === "string")) return false + if (!format2(data.pattern)) return false + } + if (data.maxItems !== undefined && hasOwn(data, "maxItems")) { + if (!ref12(data.maxItems, [...dynAnchors, dynLocal[0] || []])) return false + } + if (data.minItems !== undefined && hasOwn(data, "minItems")) { + if (!ref13(data.minItems, [...dynAnchors, dynLocal[0] || []])) return false + } + if (data.uniqueItems !== undefined && hasOwn(data, "uniqueItems")) { + if (!(typeof data.uniqueItems === "boolean")) return false + } + if (data.maxContains !== undefined && hasOwn(data, "maxContains")) { + if (!ref12(data.maxContains, [...dynAnchors, dynLocal[0] || []])) return false + } + if (data.minContains !== undefined && hasOwn(data, "minContains")) { + if (!ref12(data.minContains, [...dynAnchors, dynLocal[0] || []])) return false + } + if (data.maxProperties !== undefined && hasOwn(data, "maxProperties")) { + if (!ref12(data.maxProperties, [...dynAnchors, dynLocal[0] || []])) return false + } + if (data.minProperties !== undefined && hasOwn(data, "minProperties")) { + if (!ref13(data.minProperties, [...dynAnchors, dynLocal[0] || []])) return false + } + if (data.required !== undefined && hasOwn(data, "required")) { + if (!ref2(data.required, [...dynAnchors, dynLocal[0] || []])) return false + } + if (data.dependentRequired !== undefined && hasOwn(data, "dependentRequired")) { + if (!(typeof data.dependentRequired === "object" && data.dependentRequired && !Array.isArray(data.dependentRequired))) return false + for (const key9 of Object.keys(data.dependentRequired)) { + if (!ref2(data.dependentRequired[key9], [...dynAnchors, dynLocal[0] || []])) return false + } + } + } + return true +}; +const ref14 = function validate(data, dynAnchors) { + if (!(typeof data === "object" && data && !Array.isArray(data) || typeof data === "boolean")) return false + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.title !== undefined && hasOwn(data, "title")) { + if (!(typeof data.title === "string")) return false + } + if (data.description !== undefined && hasOwn(data, "description")) { + if (!(typeof data.description === "string")) return false + } + if (data.deprecated !== undefined && hasOwn(data, "deprecated")) { + if (!(typeof data.deprecated === "boolean")) return false + } + if (data.readOnly !== undefined && hasOwn(data, "readOnly")) { + if (!(typeof data.readOnly === "boolean")) return false + } + if (data.writeOnly !== undefined && hasOwn(data, "writeOnly")) { + if (!(typeof data.writeOnly === "boolean")) return false + } + if (data.examples !== undefined && hasOwn(data, "examples")) { + if (!Array.isArray(data.examples)) return false + } + } + return true +}; +const ref15 = function validate(data, dynAnchors) { + if (!(typeof data === "object" && data && !Array.isArray(data) || typeof data === "boolean")) return false + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.format !== undefined && hasOwn(data, "format")) { + if (!(typeof data.format === "string")) return false + } + } + return true +}; +const ref16 = function validate(data, dynAnchors = []) { + const dynLocal = [{}] + dynLocal[0]["#meta"] = validate + if (!(typeof data === "object" && data && !Array.isArray(data) || typeof data === "boolean")) return false + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.contentEncoding !== undefined && hasOwn(data, "contentEncoding")) { + if (!(typeof data.contentEncoding === "string")) return false + } + if (data.contentMediaType !== undefined && hasOwn(data, "contentMediaType")) { + if (!(typeof data.contentMediaType === "string")) return false + } + if (data.contentSchema !== undefined && hasOwn(data, "contentSchema")) { + if (!(dynamicResolve(dynAnchors || [], "#meta") || validate)(data.contentSchema, [...dynAnchors, dynLocal[0] || []])) return false + } + } + return true +}; +const ref1 = function validate(data, dynAnchors = []) { + const dynLocal = [{}] + dynLocal[0]["#meta"] = validate + if (!(typeof data === "object" && data && !Array.isArray(data) || typeof data === "boolean")) return false + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.definitions !== undefined && hasOwn(data, "definitions")) { + if (!(typeof data.definitions === "object" && data.definitions && !Array.isArray(data.definitions))) return false + for (const key0 of Object.keys(data.definitions)) { + if (!(dynamicResolve(dynAnchors || [], "#meta") || validate)(data.definitions[key0], [...dynAnchors, dynLocal[0] || []])) return false + } + } + if (data.dependencies !== undefined && hasOwn(data, "dependencies")) { + if (!(typeof data.dependencies === "object" && data.dependencies && !Array.isArray(data.dependencies))) return false + for (const key1 of Object.keys(data.dependencies)) { + const sub0 = (() => { + if (!(dynamicResolve(dynAnchors || [], "#meta") || validate)(data.dependencies[key1], [...dynAnchors, dynLocal[0] || []])) return false + return true + })() + if (!sub0) { + const sub1 = (() => { + if (!ref2(data.dependencies[key1], [...dynAnchors, dynLocal[0] || []])) return false + return true + })() + if (!sub1) return false + } + } + } + if (data["$recursiveAnchor"] !== undefined && hasOwn(data, "$recursiveAnchor")) { + if (!ref3(data["$recursiveAnchor"], [...dynAnchors, dynLocal[0] || []])) return false + } + if (data["$recursiveRef"] !== undefined && hasOwn(data, "$recursiveRef")) { + if (!ref4(data["$recursiveRef"], [...dynAnchors, dynLocal[0] || []])) return false + } + } + if (!ref5(data, [...dynAnchors, dynLocal[0] || []])) return false + if (!ref7(data, [...dynAnchors, dynLocal[0] || []])) return false + if (!ref9(data, [...dynAnchors, dynLocal[0] || []])) return false + if (!ref10(data, [...dynAnchors, dynLocal[0] || []])) return false + if (!ref14(data, [...dynAnchors, dynLocal[0] || []])) return false + if (!ref15(data, [...dynAnchors, dynLocal[0] || []])) return false + if (!ref16(data, [...dynAnchors, dynLocal[0] || []])) return false + return true +}; +const ref0 = function validate(data, dynAnchors) { + if (!ref1(data, dynAnchors)) return false + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at https://json-schema.org/draft/next/schema#/properties/definitions/additionalProperties` + diff --git a/doc/samples/draft-next/dependentRequired.md b/doc/samples/draft-next/dependentRequired.md new file mode 100644 index 0000000..d720a34 --- /dev/null +++ b/doc/samples/draft-next/dependentRequired.md @@ -0,0 +1,106 @@ +# dependentRequired + +## single dependency + +### Schema + +```json +{ "dependentRequired": { "bar": ["foo"] } } +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.bar !== undefined && hasOwn(data, "bar") && !(data.foo !== undefined && hasOwn(data, "foo"))) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## empty dependents + +### Schema + +```json +{ "dependentRequired": { "bar": [] } } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## multiple dependents required + +### Schema + +```json +{ "dependentRequired": { "quux": ["foo", "bar"] } } +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.quux !== undefined && hasOwn(data, "quux") && !(data.foo !== undefined && hasOwn(data, "foo") && data.bar !== undefined && hasOwn(data, "bar"))) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## dependencies with escaped characters + +### Schema + +```json +{ "dependentRequired": { "foo\nbar": ["foo\rbar"], "foo\"bar": ["foo'bar"] } } +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data["foo\nbar"] !== undefined && hasOwn(data, "foo\nbar") && !(data["foo\rbar"] !== undefined && hasOwn(data, "foo\rbar"))) return false + if (data["foo\"bar"] !== undefined && hasOwn(data, "foo\"bar") && !(data["foo'bar"] !== undefined && hasOwn(data, "foo'bar"))) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + diff --git a/doc/samples/draft-next/dependentSchemas.md b/doc/samples/draft-next/dependentSchemas.md new file mode 100644 index 0000000..010d941 --- /dev/null +++ b/doc/samples/draft-next/dependentSchemas.md @@ -0,0 +1,114 @@ +# dependentSchemas + +## single dependency + +### Schema + +```json +{ + "dependentSchemas": { + "bar": { + "properties": { + "foo": { "type": "integer" }, + "bar": { "type": "integer" } + } + } + } +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.bar !== undefined && hasOwn(data, "bar")) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.foo !== undefined && hasOwn(data, "foo")) { + if (!Number.isInteger(data.foo)) return false + } + if (data.bar !== undefined && hasOwn(data, "bar")) { + if (!Number.isInteger(data.bar)) return false + } + } + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] if properties is used, required should be specified at #/dependentSchemas/bar` + + +## boolean subschemas + +### Schema + +```json +{ "dependentSchemas": { "foo": true, "bar": false } } +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.bar !== undefined && hasOwn(data, "bar")) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] schema = true is not allowed at #/dependentSchemas/foo` + + +## dependencies with escaped characters + +### Schema + +```json +{ + "dependentSchemas": { + "foo\tbar": { "minProperties": 4 }, + "foo'bar": { "required": ["foo\"bar"] } + } +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data["foo\tbar"] !== undefined && hasOwn(data, "foo\tbar")) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (Object.keys(data).length < 4) return false + } + } + if (data["foo'bar"] !== undefined && hasOwn(data, "foo'bar")) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (!(data["foo\"bar"] !== undefined && hasOwn(data, "foo\"bar"))) return false + } + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + diff --git a/doc/samples/draft-next/dynamicRef.md b/doc/samples/draft-next/dynamicRef.md new file mode 100644 index 0000000..4750ebc --- /dev/null +++ b/doc/samples/draft-next/dynamicRef.md @@ -0,0 +1,701 @@ +# dynamicRef + +## A $dynamicRef to a $dynamicAnchor in the same schema resource behaves like a normal $ref to an $anchor + +### Schema + +```json +{ + "$id": "https://test.json-schema.org/dynamicRef-dynamicAnchor-same-schema/root", + "type": "array", + "items": { "$dynamicRef": "#items" }, + "$defs": { "foo": { "$dynamicAnchor": "items", "type": "string" } } +} +``` + +### Code + +```js +'use strict' +const ref1 = function validate(data, dynAnchors) { + if (!(typeof data === "string")) return false + return true +}; +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const dynamicResolve = (anchors, id) => (anchors.filter((x) => x[id])[0] || {})[id]; +const ref0 = function validate(data, dynAnchors = []) { + const dynLocal = [{}] + dynLocal[0]["#items"] = ref1 + if (!Array.isArray(data)) return false + for (let i = 0; i < data.length; i++) { + if (data[i] !== undefined && hasOwn(data, i)) { + if (!(dynamicResolve(dynAnchors || [], "#items") || ref1)(data[i], [...dynAnchors, dynLocal[0] || []])) return false + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireStringValidation] pattern, format or contentSchema should be specified for strings, use pattern: ^[\s\S]*$ to opt-out at https://test.json-schema.org/dynamicRef-dynamicAnchor-same-schema/root#` + + +## A $ref to a $dynamicAnchor in the same schema resource behaves like a normal $ref to an $anchor + +### Schema + +```json +{ + "$id": "https://test.json-schema.org/ref-dynamicAnchor-same-schema/root", + "type": "array", + "items": { "$ref": "#items" }, + "$defs": { "foo": { "$dynamicAnchor": "items", "type": "string" } } +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref1 = function validate(data) { + if (!(typeof data === "string")) return false + return true +}; +const ref0 = function validate(data) { + if (!Array.isArray(data)) return false + for (let i = 0; i < data.length; i++) { + if (data[i] !== undefined && hasOwn(data, i)) { + if (!ref1(data[i])) return false + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireStringValidation] pattern, format or contentSchema should be specified for strings, use pattern: ^[\s\S]*$ to opt-out at https://test.json-schema.org/ref-dynamicAnchor-same-schema/root#` + + +## A $dynamicRef resolves to the first $dynamicAnchor still in scope that is encountered when the schema is evaluated + +### Schema + +```json +{ + "$id": "https://test.json-schema.org/typical-dynamic-resolution/root", + "$ref": "list", + "$defs": { + "foo": { "$dynamicAnchor": "items", "type": "string" }, + "list": { + "$id": "list", + "type": "array", + "items": { "$dynamicRef": "#items" } + } + } +} +``` + +### Code + +**FAILED TO COMPILE** + +### Errors + + * `$dynamicRef bookending resolution failed "#items" at https://test.json-schema.org/typical-dynamic-resolution/root#/items` + + +## A $dynamicRef with intermediate scopes that don't include a matching $dynamicAnchor does not affect dynamic scope resolution + +### Schema + +```json +{ + "$id": "https://test.json-schema.org/dynamic-resolution-with-intermediate-scopes/root", + "$ref": "intermediate-scope", + "$defs": { + "foo": { "$dynamicAnchor": "items", "type": "string" }, + "intermediate-scope": { "$id": "intermediate-scope", "$ref": "list" }, + "list": { + "$id": "list", + "type": "array", + "items": { "$dynamicRef": "#items" } + } + } +} +``` + +### Code + +**FAILED TO COMPILE** + +### Errors + + * `$dynamicRef bookending resolution failed "#items" at https://test.json-schema.org/dynamic-resolution-with-intermediate-scopes/root#/items` + + +## An $anchor with the same name as a $dynamicAnchor is not used for dynamic scope resolution + +### Schema + +```json +{ + "$id": "https://test.json-schema.org/dynamic-resolution-ignores-anchors/root", + "$ref": "list", + "$defs": { + "foo": { "$anchor": "items", "type": "string" }, + "list": { + "$id": "list", + "type": "array", + "items": { "$dynamicRef": "#items" }, + "$defs": { "items": { "$dynamicAnchor": "items" } } + } + } +} +``` + +### Code + +```js +'use strict' +const ref2 = function validate(data, dynAnchors) { + return true +}; +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const dynamicResolve = (anchors, id) => (anchors.filter((x) => x[id])[0] || {})[id]; +const ref1 = function validate(data, dynAnchors = []) { + const dynLocal = [{}] + dynLocal[0]["#items"] = ref2 + if (!Array.isArray(data)) return false + for (let i = 0; i < data.length; i++) { + if (data[i] !== undefined && hasOwn(data, i)) { + if (!(dynamicResolve(dynAnchors || [], "#items") || ref2)(data[i], [...dynAnchors, dynLocal[0] || []])) return false + } + } + return true +}; +const ref0 = function validate(data, dynAnchors = []) { + const dynLocal = [{}] + if (!ref1(data, [...dynAnchors, dynLocal[0] || []])) return false + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at https://test.json-schema.org/dynamic-resolution-ignores-anchors/list#` + + +## A $dynamicRef that initially resolves to a schema with a matching $dynamicAnchor resolves to the first $dynamicAnchor in the dynamic scope + +### Schema + +```json +{ + "$id": "https://test.json-schema.org/relative-dynamic-reference/root", + "$dynamicAnchor": "meta", + "type": "object", + "properties": { "foo": { "const": "pass" } }, + "$ref": "extended", + "$defs": { + "extended": { + "$id": "extended", + "$dynamicAnchor": "meta", + "type": "object", + "properties": { "bar": { "$ref": "bar" } } + }, + "bar": { + "$id": "bar", + "type": "object", + "properties": { "baz": { "$dynamicRef": "extended#meta" } } + } + } +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const dynamicResolve = (anchors, id) => (anchors.filter((x) => x[id])[0] || {})[id]; +const ref2 = function validate(data, dynAnchors) { + if (!(typeof data === "object" && data && !Array.isArray(data))) return false + if (data.baz !== undefined && hasOwn(data, "baz")) { + if (!(dynamicResolve(dynAnchors || [], "#meta") || ref1)(data.baz, dynAnchors)) return false + } + return true +}; +const ref1 = function validate(data, dynAnchors = []) { + const dynLocal = [{}] + dynLocal[0]["#meta"] = validate + if (!(typeof data === "object" && data && !Array.isArray(data))) return false + if (data.bar !== undefined && hasOwn(data, "bar")) { + if (!ref2(data.bar, [...dynAnchors, dynLocal[0] || []])) return false + } + return true +}; +const ref0 = function validate(data, dynAnchors = []) { + const dynLocal = [{}] + dynLocal[0]["#meta"] = validate + if (!ref1(data, [...dynAnchors, dynLocal[0] || []])) return false + if (!(typeof data === "object" && data && !Array.isArray(data))) return false + if (data.foo !== undefined && hasOwn(data, "foo")) { + if (!(data.foo === "pass")) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at https://test.json-schema.org/relative-dynamic-reference/root#/properties/baz` + + +## multiple dynamic paths to the $dynamicRef keyword + +### Schema + +```json +{ + "$id": "https://test.json-schema.org/dynamic-ref-with-multiple-paths/main", + "$defs": { + "inner": { + "$id": "inner", + "$dynamicAnchor": "foo", + "title": "inner", + "additionalProperties": { "$dynamicRef": "#foo" } + } + }, + "if": { "propertyNames": { "pattern": "^[a-m]" } }, + "then": { + "title": "any type of node", + "$id": "anyLeafNode", + "$dynamicAnchor": "foo", + "$ref": "inner" + }, + "else": { + "title": "integer node", + "$id": "integerNode", + "$dynamicAnchor": "foo", + "type": ["object", "integer"], + "$ref": "inner" + } +} +``` + +### Code + +```js +'use strict' +const pattern0 = new RegExp("^[a-m]", "u"); +const dynamicResolve = (anchors, id) => (anchors.filter((x) => x[id])[0] || {})[id]; +const ref2 = function validate(data, dynAnchors = []) { + const dynLocal = [{}] + dynLocal[0]["#foo"] = validate + if (typeof data === "object" && data && !Array.isArray(data)) { + for (const key1 of Object.keys(data)) { + if (!(dynamicResolve(dynAnchors || [], "#foo") || validate)(data[key1], [...dynAnchors, dynLocal[0] || []])) return false + } + } + return true +}; +const ref1 = function validate(data, dynAnchors = []) { + const dynLocal = [{}] + dynLocal[0]["#foo"] = validate + if (!ref2(data, [...dynAnchors, dynLocal[0] || []])) return false + return true +}; +const ref3 = function validate(data, dynAnchors = []) { + const dynLocal = [{}] + dynLocal[0]["#foo"] = validate + if (!ref2(data, [...dynAnchors, dynLocal[0] || []])) return false + if (!(typeof data === "object" && data && !Array.isArray(data) || Number.isInteger(data))) return false + return true +}; +const ref0 = function validate(data, dynAnchors = []) { + const dynLocal = [{}] + const sub0 = (() => { + if (typeof data === "object" && data && !Array.isArray(data)) { + for (const key0 of Object.keys(data)) { + if (!pattern0.test(key0)) return false + } + } + return true + })() + if (sub0) { + dynLocal.unshift({}) + dynLocal[0]["#foo"] = ref1 + if (!ref2(data, [...dynAnchors, dynLocal[0] || []])) return false + dynLocal.shift() + } + else { + dynLocal.unshift({}) + dynLocal[0]["#foo"] = ref3 + if (!ref2(data, [...dynAnchors, dynLocal[0] || []])) return false + if (!(typeof data === "object" && data && !Array.isArray(data) || Number.isInteger(data))) return false + dynLocal.shift() + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `Should start with ^ and end with $: "^[a-m]" at #/if/propertyNames` + + +## after leaving a dynamic scope, it is not used by a $dynamicRef + +### Schema + +```json +{ + "$id": "https://test.json-schema.org/dynamic-ref-leaving-dynamic-scope/main", + "if": { + "$id": "first_scope", + "$defs": { + "thingy": { + "$comment": "this is first_scope#thingy", + "$dynamicAnchor": "thingy", + "type": "number" + } + } + }, + "then": { + "$id": "second_scope", + "$ref": "start", + "$defs": { + "thingy": { + "$comment": "this is second_scope#thingy, the final destination of the $dynamicRef", + "$dynamicAnchor": "thingy", + "type": "null" + } + } + }, + "$defs": { + "start": { + "$comment": "this is the landing spot from $ref", + "$id": "start", + "$dynamicRef": "inner_scope#thingy" + }, + "thingy": { + "$comment": "this is the first stop for the $dynamicRef", + "$id": "inner_scope", + "$dynamicAnchor": "thingy", + "type": "string" + } + } +} +``` + +### Code + +```js +'use strict' +const ref1 = function validate(data, dynAnchors) { + if (!(typeof data === "number")) return false + return true +}; +const ref2 = function validate(data, dynAnchors) { + if (!(data === null)) return false + return true +}; +const ref4 = function validate(data, dynAnchors) { + if (!(typeof data === "string")) return false + return true +}; +const dynamicResolve = (anchors, id) => (anchors.filter((x) => x[id])[0] || {})[id]; +const ref3 = function validate(data, dynAnchors) { + if (!(dynamicResolve(dynAnchors || [], "#thingy") || ref4)(data, dynAnchors)) return false + return true +}; +const ref0 = function validate(data, dynAnchors = []) { + const dynLocal = [{}] + const sub0 = (() => { + dynLocal.unshift({}) + dynLocal[0]["#thingy"] = ref1 + dynLocal.shift() + return true + })() + if (sub0) { + dynLocal.unshift({}) + dynLocal[0]["#thingy"] = ref2 + if (!ref3(data, [...dynAnchors, dynLocal[0] || []])) return false + dynLocal.shift() + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireStringValidation] pattern, format or contentSchema should be specified for strings, use pattern: ^[\s\S]*$ to opt-out at https://test.json-schema.org/dynamic-ref-leaving-dynamic-scope/main#` + + +## strict-tree schema, guards against misspelled properties + +### Schema + +```json +{ + "$id": "http://localhost:1234/draft-next/strict-tree.json", + "$dynamicAnchor": "node", + "$ref": "tree.json", + "unevaluatedProperties": false +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const dynamicResolve = (anchors, id) => (anchors.filter((x) => x[id])[0] || {})[id]; +const ref1 = function validate(data, dynAnchors = []) { + const dynLocal = [{}] + dynLocal[0]["#node"] = validate + if (!(typeof data === "object" && data && !Array.isArray(data))) return false + if (data.children !== undefined && hasOwn(data, "children")) { + if (!Array.isArray(data.children)) return false + for (let i = 0; i < data.children.length; i++) { + if (data.children[i] !== undefined && hasOwn(data.children, i)) { + if (!(dynamicResolve(dynAnchors || [], "#node") || validate)(data.children[i], [...dynAnchors, dynLocal[0] || []])) return false + } + } + } + return true +}; +const ref0 = function validate(data, dynAnchors = []) { + const dynLocal = [{}] + dynLocal[0]["#node"] = validate + if (!ref1(data, [...dynAnchors, dynLocal[0] || []])) return false + for (const key0 of Object.keys(data)) { + if (key0 !== "children" && key0 !== "data") return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] schema = true is not allowed at http://localhost:1234/draft-next/tree.json#/properties/data` + + +## tests for implementation dynamic anchor and reference link + +### Schema + +```json +{ + "$id": "http://localhost:1234/draft-next/strict-extendible.json", + "$ref": "extendible-dynamic-ref.json", + "$defs": { + "elements": { + "$dynamicAnchor": "elements", + "properties": { "a": true }, + "required": ["a"], + "additionalProperties": false + } + } +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref1 = function validate(data, dynAnchors) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (!(data.a !== undefined && hasOwn(data, "a"))) return false + for (const key0 of Object.keys(data)) { + if (key0 !== "a") return false + } + } + return true +}; +const ref3 = function validate(data, dynAnchors) { + return true +}; +const dynamicResolve = (anchors, id) => (anchors.filter((x) => x[id])[0] || {})[id]; +const ref2 = function validate(data, dynAnchors = []) { + const dynLocal = [{}] + dynLocal[0]["#elements"] = ref3 + if (!(typeof data === "object" && data && !Array.isArray(data))) return false + if (!(data.elements !== undefined && hasOwn(data, "elements"))) return false + if (!Array.isArray(data.elements)) return false + for (let i = 0; i < data.elements.length; i++) { + if (data.elements[i] !== undefined && hasOwn(data.elements, i)) { + if (!(dynamicResolve(dynAnchors || [], "#elements") || ref3)(data.elements[i], [...dynAnchors, dynLocal[0] || []])) return false + } + } + for (const key1 of Object.keys(data)) { + if (key1 !== "elements") return false + } + return true +}; +const ref0 = function validate(data, dynAnchors = []) { + const dynLocal = [{}] + dynLocal[0]["#elements"] = ref1 + if (!ref2(data, [...dynAnchors, dynLocal[0] || []])) return false + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] schema = true is not allowed at http://localhost:1234/draft-next/strict-extendible.json#/properties/a` + + +## $ref and $dynamicAnchor are independent of order - $defs first + +### Schema + +```json +{ + "$id": "http://localhost:1234/draft-next/strict-extendible-allof-defs-first.json", + "allOf": [ + { "$ref": "extendible-dynamic-ref.json" }, + { + "$defs": { + "elements": { + "$dynamicAnchor": "elements", + "properties": { "a": true }, + "required": ["a"], + "additionalProperties": false + } + } + } + ] +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref1 = function validate(data, dynAnchors) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (!(data.a !== undefined && hasOwn(data, "a"))) return false + for (const key0 of Object.keys(data)) { + if (key0 !== "a") return false + } + } + return true +}; +const ref3 = function validate(data, dynAnchors) { + return true +}; +const dynamicResolve = (anchors, id) => (anchors.filter((x) => x[id])[0] || {})[id]; +const ref2 = function validate(data, dynAnchors = []) { + const dynLocal = [{}] + dynLocal[0]["#elements"] = ref3 + if (!(typeof data === "object" && data && !Array.isArray(data))) return false + if (!(data.elements !== undefined && hasOwn(data, "elements"))) return false + if (!Array.isArray(data.elements)) return false + for (let i = 0; i < data.elements.length; i++) { + if (data.elements[i] !== undefined && hasOwn(data.elements, i)) { + if (!(dynamicResolve(dynAnchors || [], "#elements") || ref3)(data.elements[i], [...dynAnchors, dynLocal[0] || []])) return false + } + } + for (const key1 of Object.keys(data)) { + if (key1 !== "elements") return false + } + return true +}; +const ref0 = function validate(data, dynAnchors = []) { + const dynLocal = [{}] + dynLocal[0]["#elements"] = ref1 + if (!ref2(data, [...dynAnchors, dynLocal[0] || []])) return false + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] schema = true is not allowed at http://localhost:1234/draft-next/strict-extendible-allof-defs-first.json#/properties/a` + + +## $ref and $dynamicAnchor are independent of order - $ref first + +### Schema + +```json +{ + "$id": "http://localhost:1234/draft-next/strict-extendible-allof-ref-first.json", + "allOf": [ + { + "$defs": { + "elements": { + "$dynamicAnchor": "elements", + "properties": { "a": true }, + "required": ["a"], + "additionalProperties": false + } + } + }, + { "$ref": "extendible-dynamic-ref.json" } + ] +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref1 = function validate(data, dynAnchors) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (!(data.a !== undefined && hasOwn(data, "a"))) return false + for (const key0 of Object.keys(data)) { + if (key0 !== "a") return false + } + } + return true +}; +const ref3 = function validate(data, dynAnchors) { + return true +}; +const dynamicResolve = (anchors, id) => (anchors.filter((x) => x[id])[0] || {})[id]; +const ref2 = function validate(data, dynAnchors = []) { + const dynLocal = [{}] + dynLocal[0]["#elements"] = ref3 + if (!(typeof data === "object" && data && !Array.isArray(data))) return false + if (!(data.elements !== undefined && hasOwn(data, "elements"))) return false + if (!Array.isArray(data.elements)) return false + for (let i = 0; i < data.elements.length; i++) { + if (data.elements[i] !== undefined && hasOwn(data.elements, i)) { + if (!(dynamicResolve(dynAnchors || [], "#elements") || ref3)(data.elements[i], [...dynAnchors, dynLocal[0] || []])) return false + } + } + for (const key1 of Object.keys(data)) { + if (key1 !== "elements") return false + } + return true +}; +const ref0 = function validate(data, dynAnchors = []) { + const dynLocal = [{}] + dynLocal[0]["#elements"] = ref1 + if (!ref2(data, [...dynAnchors, dynLocal[0] || []])) return false + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] schema = true is not allowed at http://localhost:1234/draft-next/strict-extendible-allof-ref-first.json#/properties/a` + diff --git a/doc/samples/draft-next/enum.md b/doc/samples/draft-next/enum.md new file mode 100644 index 0000000..f72f0da --- /dev/null +++ b/doc/samples/draft-next/enum.md @@ -0,0 +1,216 @@ +# enum + +## simple enum validation + +### Schema + +```json +{ "enum": [1, 2, 3] } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (!(data === 1 || data === 2 || data === 3)) return false + return true +}; +return ref0 +``` + + +## heterogeneous enum validation + +### Schema + +```json +{ "enum": [6, "foo", [], true, { "foo": 12 }] } +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (!(data === 6 || data === "foo" || data === true || Array.isArray(data) && data.length === 0 || typeof data === "object" && data && !Array.isArray(data) && Object.keys(data).length === 1 && hasOwn(data, "foo") && data["foo"] === 12)) return false + return true +}; +return ref0 +``` + + +## heterogeneous enum-with-null validation + +### Schema + +```json +{ "enum": [6, null] } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (!(data === 6 || data === null)) return false + return true +}; +return ref0 +``` + + +## enums in properties + +### Schema + +```json +{ + "type": "object", + "properties": { "foo": { "enum": ["foo"] }, "bar": { "enum": ["bar"] } }, + "required": ["bar"] +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (!(typeof data === "object" && data && !Array.isArray(data))) return false + if (!(data.bar !== undefined && hasOwn(data, "bar"))) return false + if (data.foo !== undefined && hasOwn(data, "foo")) { + if (!(data.foo === "foo")) return false + } + if (!(data.bar === "bar")) return false + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] additionalProperties or unevaluatedProperties should be specified at #` + + +## enum with escaped characters + +### Schema + +```json +{ "enum": ["foo\nbar", "foo\rbar"] } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (!(data === "foo\nbar" || data === "foo\rbar")) return false + return true +}; +return ref0 +``` + + +## enum with false does not match 0 + +### Schema + +```json +{ "enum": [false] } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (!(data === false)) return false + return true +}; +return ref0 +``` + + +## enum with true does not match 1 + +### Schema + +```json +{ "enum": [true] } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (!(data === true)) return false + return true +}; +return ref0 +``` + + +## enum with 0 does not match false + +### Schema + +```json +{ "enum": [0] } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (!(data === 0)) return false + return true +}; +return ref0 +``` + + +## enum with 1 does not match true + +### Schema + +```json +{ "enum": [1] } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (!(data === 1)) return false + return true +}; +return ref0 +``` + + +## nul characters in strings + +### Schema + +```json +{ "enum": ["hello\u0000there"] } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (!(data === "hello\u0000there")) return false + return true +}; +return ref0 +``` + diff --git a/doc/samples/draft-next/exclusiveMaximum.md b/doc/samples/draft-next/exclusiveMaximum.md new file mode 100644 index 0000000..fa89b08 --- /dev/null +++ b/doc/samples/draft-next/exclusiveMaximum.md @@ -0,0 +1,27 @@ +# exclusiveMaximum + +## exclusiveMaximum validation + +### Schema + +```json +{ "exclusiveMaximum": 3 } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (typeof data === "number") { + if (!(3 > data)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + diff --git a/doc/samples/draft-next/exclusiveMinimum.md b/doc/samples/draft-next/exclusiveMinimum.md new file mode 100644 index 0000000..4a605e7 --- /dev/null +++ b/doc/samples/draft-next/exclusiveMinimum.md @@ -0,0 +1,27 @@ +# exclusiveMinimum + +## exclusiveMinimum validation + +### Schema + +```json +{ "exclusiveMinimum": 1.1 } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (typeof data === "number") { + if (!(1.1 < data)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + diff --git a/doc/samples/draft-next/format.md b/doc/samples/draft-next/format.md new file mode 100644 index 0000000..a6215d2 --- /dev/null +++ b/doc/samples/draft-next/format.md @@ -0,0 +1,580 @@ +# format + +## email format + +### Schema + +```json +{ "format": "email" } +``` + +### Code + +```js +'use strict' +const format0 = (input) => { + if (input.length > 318) return false + const fast = /^[a-z0-9!#$%&'*+/=?^_`{|}~-]{1,20}(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]{1,21}){0,2}@[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?(?:\.[a-z0-9](?:[a-z0-9-]{0,60}[a-z0-9])?){0,3}$/i + if (fast.test(input)) return true + if (!input.includes('@') || /(^\.|^"|\.@|\.\.)/.test(input)) return false + const [name, host, ...rest] = input.split('@') + if (!name || !host || rest.length !== 0 || name.length > 64 || host.length > 253) return false + if (!/^[a-z0-9.-]+$/i.test(host) || !/^[a-z0-9.!#$%&'*+/=?^_`{|}~-]+$/i.test(name)) return false + return host.split('.').every((part) => /^[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?$/i.test(part)) + }; +const ref0 = function validate(data) { + if (typeof data === "string") { + if (!format0(data)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## idn-email format + +### Schema + +```json +{ "format": "idn-email" } +``` + +### Code + +**FAILED TO COMPILE** + +### Errors + + * `Unrecognized format used: "idn-email" at #` + + +## regex format + +### Schema + +```json +{ "format": "regex" } +``` + +### Code + +```js +'use strict' +const format0 = (str) => { + if (str.length > 1e5) return false + const Z_ANCHOR = /[^\\]\\Z/ + if (Z_ANCHOR.test(str)) return false + try { + new RegExp(str, 'u') + return true + } catch (e) { + return false + } + }; +const ref0 = function validate(data) { + if (typeof data === "string") { + if (!format0(data)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `Unrecognized format used: "regex" at #` + + +## ipv4 format + +### Schema + +```json +{ "format": "ipv4" } +``` + +### Code + +```js +'use strict' +const format0 = (ip) => + ip.length <= 15 && + /^(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)\.){3}(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d\d?)$/.test(ip); +const ref0 = function validate(data) { + if (typeof data === "string") { + if (!format0(data)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## ipv6 format + +### Schema + +```json +{ "format": "ipv6" } +``` + +### Code + +```js +'use strict' +const format0 = (input) => { + if (input.length > 45 || input.length < 2) return false + let s0 = 0, s1 = 0, hex = 0, short = false, letters = false, last = 0, start = true + for (let i = 0; i < input.length; i++) { + const c = input.charCodeAt(i) + if (i === 1 && last === 58 && c !== 58) return false + if (c >= 48 && c <= 57) { + if (++hex > 4) return false + } else if (c === 46) { + if (s0 > 6 || s1 >= 3 || hex === 0 || letters) return false + s1++ + hex = 0 + } else if (c === 58) { + if (s1 > 0 || s0 >= 7) return false + if (last === 58) { + if (short) return false + short = true + } else if (i === 0) start = false + s0++ + hex = 0 + letters = false + } else if ((c >= 97 && c <= 102) || (c >= 65 && c <= 70)) { + if (s1 > 0) return false + if (++hex > 4) return false + letters = true + } else return false + last = c + } + if (s0 < 2 || (s1 > 0 && (s1 !== 3 || hex === 0))) return false + if (short && input.length === 2) return true + if (s1 > 0 && !/(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}$/.test(input)) return false + const spaces = s1 > 0 ? 6 : 7 + if (!short) return s0 === spaces && start && hex > 0 + return (start || hex > 0) && s0 < spaces + }; +const ref0 = function validate(data) { + if (typeof data === "string") { + if (!format0(data)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## idn-hostname format + +### Schema + +```json +{ "format": "idn-hostname" } +``` + +### Code + +**FAILED TO COMPILE** + +### Errors + + * `Unrecognized format used: "idn-hostname" at #` + + +## hostname format + +### Schema + +```json +{ "format": "hostname" } +``` + +### Code + +```js +'use strict' +const format0 = (input) => { + if (input.length > (input.endsWith('.') ? 254 : 253)) return false + const hostname = /^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?(?:\.[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?)*\.?$/i + return hostname.test(input) + }; +const ref0 = function validate(data) { + if (typeof data === "string") { + if (!format0(data)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## date format + +### Schema + +```json +{ "format": "date" } +``` + +### Code + +```js +'use strict' +const format0 = (input) => { + if (input.length !== 10) return false + if (input[5] === '0' && input[6] === '2') { + if (/^\d\d\d\d-02-(?:[012][1-8]|[12]0|[01]9)$/.test(input)) return true + const matches = input.match(/^(\d\d\d\d)-02-29$/) + if (!matches) return false + const year = matches[1] | 0 + return year % 16 === 0 || (year % 4 === 0 && year % 25 !== 0) + } + if (input.endsWith('31')) return /^\d\d\d\d-(?:0[13578]|1[02])-31$/.test(input) + return /^\d\d\d\d-(?:0[13-9]|1[012])-(?:[012][1-9]|[123]0)$/.test(input) + }; +const ref0 = function validate(data) { + if (typeof data === "string") { + if (!format0(data)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## date-time format + +### Schema + +```json +{ "format": "date-time" } +``` + +### Code + +```js +'use strict' +const format0 = (input) => { + if (input.length > 10 + 1 + 9 + 12 + 6) return false + const full = /^\d\d\d\d-(?:0[1-9]|1[0-2])-(?:[0-2]\d|3[01])[t\s](?:2[0-3]|[0-1]\d):[0-5]\d:(?:[0-5]\d|60)(?:\.\d+)?(?:z|[+-](?:2[0-3]|[0-1]\d)(?::?[0-5]\d)?)$/i + const feb = input[5] === '0' && input[6] === '2' + if ((feb && input[8] === '3') || !full.test(input)) return false + if (input[17] === '6') { + const p = input.slice(11).match(/([0-9.]+|[^0-9.])/g) + let hm = Number(p[0]) * 60 + Number(p[2]) + if (p[5] === '+') hm += 24 * 60 - Number(p[6] || 0) * 60 - Number(p[8] || 0) + else if (p[5] === '-') hm += Number(p[6] || 0) * 60 + Number(p[8] || 0) + if (hm % (24 * 60) !== 23 * 60 + 59) return false + } + if (feb) { + if (/^\d\d\d\d-02-(?:[012][1-8]|[12]0|[01]9)/.test(input)) return true + const matches = input.match(/^(\d\d\d\d)-02-29/) + if (!matches) return false + const year = matches[1] | 0 + return year % 16 === 0 || (year % 4 === 0 && year % 25 !== 0) + } + if (input[8] === '3' && input[9] === '1') return /^\d\d\d\d-(?:0[13578]|1[02])-31/.test(input) + return /^\d\d\d\d-(?:0[13-9]|1[012])-(?:[012][1-9]|[123]0)/.test(input) + }; +const ref0 = function validate(data) { + if (typeof data === "string") { + if (!format0(data)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## time format + +### Schema + +```json +{ "format": "time" } +``` + +### Code + +```js +'use strict' +const format0 = (input) => { + if (input.length > 9 + 12 + 6) return false + const time = /^(?:2[0-3]|[0-1]\d):[0-5]\d:(?:[0-5]\d|60)(?:\.\d+)?(?:z|[+-](?:2[0-3]|[0-1]\d)(?::?[0-5]\d)?)?$/i + if (!time.test(input)) return false + if (!/:60/.test(input)) return true + const p = input.match(/([0-9.]+|[^0-9.])/g) + let hm = Number(p[0]) * 60 + Number(p[2]) + if (p[5] === '+') hm += 24 * 60 - Number(p[6] || 0) * 60 - Number(p[8] || 0) + else if (p[5] === '-') hm += Number(p[6] || 0) * 60 + Number(p[8] || 0) + return hm % (24 * 60) === 23 * 60 + 59 + }; +const ref0 = function validate(data) { + if (typeof data === "string") { + if (!format0(data)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## json-pointer format + +### Schema + +```json +{ "format": "json-pointer" } +``` + +### Code + +```js +'use strict' +const format0 = new RegExp("^(?:|\\/(?:[^~]|~0|~1)*)$", ""); +const ref0 = function validate(data) { + if (typeof data === "string") { + if (!format0.test(data)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## relative-json-pointer format + +### Schema + +```json +{ "format": "relative-json-pointer" } +``` + +### Code + +```js +'use strict' +const format0 = new RegExp("^(?:0|[1-9][0-9]*)(?:|#|\\/(?:[^~]|~0|~1)*)$", ""); +const ref0 = function validate(data) { + if (typeof data === "string") { + if (!format0.test(data)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## iri format + +### Schema + +```json +{ "format": "iri" } +``` + +### Code + +**FAILED TO COMPILE** + +### Errors + + * `Unrecognized format used: "iri" at #` + + +## iri-reference format + +### Schema + +```json +{ "format": "iri-reference" } +``` + +### Code + +**FAILED TO COMPILE** + +### Errors + + * `Unrecognized format used: "iri-reference" at #` + + +## uri format + +### Schema + +```json +{ "format": "uri" } +``` + +### Code + +```js +'use strict' +const format0 = new RegExp("^[a-z][a-z0-9+\\-.]*:(?:\\/?\\/(?:(?:[a-z0-9\\-._~!$&'()*+,;=:]|%[0-9a-f]{2})*@)?(?:\\[(?:(?:(?:(?:[0-9a-f]{1,4}:){6}|::(?:[0-9a-f]{1,4}:){5}|(?:[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){4}|(?:(?:[0-9a-f]{1,4}:){0,1}[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){3}|(?:(?:[0-9a-f]{1,4}:){0,2}[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){2}|(?:(?:[0-9a-f]{1,4}:){0,3}[0-9a-f]{1,4})?::[0-9a-f]{1,4}:|(?:(?:[0-9a-f]{1,4}:){0,4}[0-9a-f]{1,4})?::)(?:[0-9a-f]{1,4}:[0-9a-f]{1,4}|(?:(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d\\d?)\\.){3}(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d\\d?))|(?:(?:[0-9a-f]{1,4}:){0,5}[0-9a-f]{1,4})?::[0-9a-f]{1,4}|(?:(?:[0-9a-f]{1,4}:){0,6}[0-9a-f]{1,4})?::)|v[0-9a-f]+\\.[a-z0-9\\-._~!$&'()*+,;=:]+)\\]|(?:(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d\\d?)\\.){3}(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d\\d?)|(?:[a-z0-9\\-._~!$&'()*+,;=]|%[0-9a-f]{2})*)(?::\\d*)?(?:\\/(?:[a-z0-9\\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})*)*|\\/?(?:(?:[a-z0-9\\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})+(?:\\/(?:[a-z0-9\\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})*)*)?)(?:\\?(?:[a-z0-9\\-._~!$&'()*+,;=:@/?]|%[0-9a-f]{2})*)?(?:#(?:[a-z0-9\\-._~!$&'()*+,;=:@/?]|%[0-9a-f]{2})*)?$", "i"); +const ref0 = function validate(data) { + if (typeof data === "string") { + if (!format0.test(data)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## uri-reference format + +### Schema + +```json +{ "format": "uri-reference" } +``` + +### Code + +```js +'use strict' +const format0 = new RegExp("^(?:[a-z][a-z0-9+\\-.]*:)?(?:\\/?\\/(?:(?:[a-z0-9\\-._~!$&'()*+,;=:]|%[0-9a-f]{2})*@)?(?:\\[(?:(?:(?:(?:[0-9a-f]{1,4}:){6}|::(?:[0-9a-f]{1,4}:){5}|(?:[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){4}|(?:(?:[0-9a-f]{1,4}:){0,1}[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){3}|(?:(?:[0-9a-f]{1,4}:){0,2}[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){2}|(?:(?:[0-9a-f]{1,4}:){0,3}[0-9a-f]{1,4})?::[0-9a-f]{1,4}:|(?:(?:[0-9a-f]{1,4}:){0,4}[0-9a-f]{1,4})?::)(?:[0-9a-f]{1,4}:[0-9a-f]{1,4}|(?:(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d\\d?)\\.){3}(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d\\d?))|(?:(?:[0-9a-f]{1,4}:){0,5}[0-9a-f]{1,4})?::[0-9a-f]{1,4}|(?:(?:[0-9a-f]{1,4}:){0,6}[0-9a-f]{1,4})?::)|v[0-9a-f]+\\.[a-z0-9\\-._~!$&'()*+,;=:]+)\\]|(?:(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d\\d?)\\.){3}(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d\\d?)|(?:[a-z0-9\\-._~!$&'()*+,;=]|%[0-9a-f]{2})*)(?::\\d*)?(?:\\/(?:[a-z0-9\\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})*)*|\\/?(?:(?:[a-z0-9\\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})+(?:\\/(?:[a-z0-9\\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})*)*)?)?(?:\\?(?:[a-z0-9\\-._~!$&'()*+,;=:@/?]|%[0-9a-f]{2})*)?(?:#(?:[a-z0-9\\-._~!$&'()*+,;=:@/?]|%[0-9a-f]{2})*)?$", "i"); +const ref0 = function validate(data) { + if (typeof data === "string") { + if (!format0.test(data)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## uri-template format + +### Schema + +```json +{ "format": "uri-template" } +``` + +### Code + +```js +'use strict' +const format0 = new RegExp("^(?:[^\\x00-\\x20\"'<>%\\\\^`{|}]|%[0-9a-f]{2}|\\{[+#./;?&=,!@|]?(?:[a-z0-9_]|%[0-9a-f]{2})+(?::[1-9][0-9]{0,3}|\\*)?(?:,(?:[a-z0-9_]|%[0-9a-f]{2})+(?::[1-9][0-9]{0,3}|\\*)?)*\\})*$", "i"); +const ref0 = function validate(data) { + if (typeof data === "string") { + if (!format0.test(data)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## uuid format + +### Schema + +```json +{ "format": "uuid" } +``` + +### Code + +```js +'use strict' +const format0 = new RegExp("^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$", "i"); +const ref0 = function validate(data) { + if (typeof data === "string") { + if (!format0.test(data)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## duration format + +### Schema + +```json +{ "format": "duration" } +``` + +### Code + +```js +'use strict' +const format0 = (input) => + input.length > 1 && + input.length < 80 && + (/^P\d+([.,]\d+)?W$/.test(input) || + (/^P[\dYMDTHS]*(\d[.,]\d+)?[YMDHS]$/.test(input) && + /^P([.,\d]+Y)?([.,\d]+M)?([.,\d]+D)?(T([.,\d]+H)?([.,\d]+M)?([.,\d]+S)?)?$/.test(input))); +const ref0 = function validate(data) { + if (typeof data === "string") { + if (!format0(data)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + diff --git a/doc/samples/draft-next/id.md b/doc/samples/draft-next/id.md new file mode 100644 index 0000000..4391f26 --- /dev/null +++ b/doc/samples/draft-next/id.md @@ -0,0 +1,1414 @@ +# id + +## Invalid use of fragments in location-independent $id + +### Schema + +```json +{ "$ref": "https://json-schema.org/draft/next/schema" } +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const dynamicResolve = (anchors, id) => (anchors.filter((x) => x[id])[0] || {})[id]; +const unique = (array) => { + if (array.length < 2) return true + if (array.length === 2) return !deepEqual(array[0], array[1]) + const objects = [] + const primitives = array.length > 20 ? new Set() : null + let primitivesCount = 0 + let pos = 0 + for (const item of array) { + if (typeof item === 'object') { + objects.push(item) + } else if (primitives) { + primitives.add(item) + if (primitives.size !== ++primitivesCount) return false + } else { + if (array.indexOf(item, pos + 1) !== -1) return false + } + pos++ + } + for (let i = 1; i < objects.length; i++) + for (let j = 0; j < i; j++) if (deepEqual(objects[i], objects[j])) return false + return true +}; +const deepEqual = (obj, obj2) => { + if (obj === obj2) return true + if (!obj || !obj2 || typeof obj !== typeof obj2) return false + if (obj !== obj2 && typeof obj !== 'object') return false + + const proto = Object.getPrototypeOf(obj) + if (proto !== Object.getPrototypeOf(obj2)) return false + + if (proto === Array.prototype) { + if (!Array.isArray(obj) || !Array.isArray(obj2)) return false + if (obj.length !== obj2.length) return false + return obj.every((x, i) => deepEqual(x, obj2[i])) + } else if (proto === Object.prototype) { + const [keys, keys2] = [Object.keys(obj), Object.keys(obj2)] + if (keys.length !== keys2.length) return false + const keyset2 = new Set([...keys, ...keys2]) + return keyset2.size === keys.length && keys.every((key) => deepEqual(obj[key], obj2[key])) + } + return false +}; +const ref2 = function validate(data, dynAnchors) { + if (!Array.isArray(data)) return false + for (let i = 0; i < data.length; i++) { + if (data[i] !== undefined && hasOwn(data, i)) { + if (!(typeof data[i] === "string")) return false + } + } + if (!unique(data)) return false + return true +}; +const pattern0 = new RegExp("^[A-Za-z_][-A-Za-z0-9._]*$", "u"); +const ref3 = function validate(data, dynAnchors) { + if (!(typeof data === "string")) return false + if (!pattern0.test(data)) return false + return true +}; +const format0 = new RegExp("^(?:[a-z][a-z0-9+\\-.]*:)?(?:\\/?\\/(?:(?:[a-z0-9\\-._~!$&'()*+,;=:]|%[0-9a-f]{2})*@)?(?:\\[(?:(?:(?:(?:[0-9a-f]{1,4}:){6}|::(?:[0-9a-f]{1,4}:){5}|(?:[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){4}|(?:(?:[0-9a-f]{1,4}:){0,1}[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){3}|(?:(?:[0-9a-f]{1,4}:){0,2}[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){2}|(?:(?:[0-9a-f]{1,4}:){0,3}[0-9a-f]{1,4})?::[0-9a-f]{1,4}:|(?:(?:[0-9a-f]{1,4}:){0,4}[0-9a-f]{1,4})?::)(?:[0-9a-f]{1,4}:[0-9a-f]{1,4}|(?:(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d\\d?)\\.){3}(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d\\d?))|(?:(?:[0-9a-f]{1,4}:){0,5}[0-9a-f]{1,4})?::[0-9a-f]{1,4}|(?:(?:[0-9a-f]{1,4}:){0,6}[0-9a-f]{1,4})?::)|v[0-9a-f]+\\.[a-z0-9\\-._~!$&'()*+,;=:]+)\\]|(?:(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d\\d?)\\.){3}(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d\\d?)|(?:[a-z0-9\\-._~!$&'()*+,;=]|%[0-9a-f]{2})*)(?::\\d*)?(?:\\/(?:[a-z0-9\\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})*)*|\\/?(?:(?:[a-z0-9\\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})+(?:\\/(?:[a-z0-9\\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})*)*)?)?(?:\\?(?:[a-z0-9\\-._~!$&'()*+,;=:@/?]|%[0-9a-f]{2})*)?(?:#(?:[a-z0-9\\-._~!$&'()*+,;=:@/?]|%[0-9a-f]{2})*)?$", "i"); +const ref4 = function validate(data, dynAnchors) { + if (!(typeof data === "string")) return false + if (!format0.test(data)) return false + return true +}; +const pattern1 = new RegExp("^[^#]*#?$", "u"); +const format1 = new RegExp("^[a-z][a-z0-9+\\-.]*:(?:\\/?\\/(?:(?:[a-z0-9\\-._~!$&'()*+,;=:]|%[0-9a-f]{2})*@)?(?:\\[(?:(?:(?:(?:[0-9a-f]{1,4}:){6}|::(?:[0-9a-f]{1,4}:){5}|(?:[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){4}|(?:(?:[0-9a-f]{1,4}:){0,1}[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){3}|(?:(?:[0-9a-f]{1,4}:){0,2}[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){2}|(?:(?:[0-9a-f]{1,4}:){0,3}[0-9a-f]{1,4})?::[0-9a-f]{1,4}:|(?:(?:[0-9a-f]{1,4}:){0,4}[0-9a-f]{1,4})?::)(?:[0-9a-f]{1,4}:[0-9a-f]{1,4}|(?:(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d\\d?)\\.){3}(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d\\d?))|(?:(?:[0-9a-f]{1,4}:){0,5}[0-9a-f]{1,4})?::[0-9a-f]{1,4}|(?:(?:[0-9a-f]{1,4}:){0,6}[0-9a-f]{1,4})?::)|v[0-9a-f]+\\.[a-z0-9\\-._~!$&'()*+,;=:]+)\\]|(?:(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d\\d?)\\.){3}(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d\\d?)|(?:[a-z0-9\\-._~!$&'()*+,;=]|%[0-9a-f]{2})*)(?::\\d*)?(?:\\/(?:[a-z0-9\\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})*)*|\\/?(?:(?:[a-z0-9\\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})+(?:\\/(?:[a-z0-9\\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})*)*)?)(?:\\?(?:[a-z0-9\\-._~!$&'()*+,;=:@/?]|%[0-9a-f]{2})*)?(?:#(?:[a-z0-9\\-._~!$&'()*+,;=:@/?]|%[0-9a-f]{2})*)?$", "i"); +const ref6 = function validate(data, dynAnchors) { + if (!(typeof data === "string")) return false + if (!format1.test(data)) return false + return true +}; +const ref5 = function validate(data, dynAnchors = []) { + const dynLocal = [{}] + dynLocal[0]["#meta"] = validate + if (!(typeof data === "object" && data && !Array.isArray(data) || typeof data === "boolean")) return false + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data["$id"] !== undefined && hasOwn(data, "$id")) { + if (!ref4(data["$id"], [...dynAnchors, dynLocal[0] || []])) return false + if (!(pattern1.test(data["$id"]))) return false + } + if (data["$schema"] !== undefined && hasOwn(data, "$schema")) { + if (!ref6(data["$schema"], [...dynAnchors, dynLocal[0] || []])) return false + } + if (data["$ref"] !== undefined && hasOwn(data, "$ref")) { + if (!ref4(data["$ref"], [...dynAnchors, dynLocal[0] || []])) return false + } + if (data["$anchor"] !== undefined && hasOwn(data, "$anchor")) { + if (!ref3(data["$anchor"], [...dynAnchors, dynLocal[0] || []])) return false + } + if (data["$dynamicRef"] !== undefined && hasOwn(data, "$dynamicRef")) { + if (!ref4(data["$dynamicRef"], [...dynAnchors, dynLocal[0] || []])) return false + } + if (data["$dynamicAnchor"] !== undefined && hasOwn(data, "$dynamicAnchor")) { + if (!ref3(data["$dynamicAnchor"], [...dynAnchors, dynLocal[0] || []])) return false + } + if (data["$vocabulary"] !== undefined && hasOwn(data, "$vocabulary")) { + if (!(typeof data["$vocabulary"] === "object" && data["$vocabulary"] && !Array.isArray(data["$vocabulary"]))) return false + for (const key2 of Object.keys(data["$vocabulary"])) { + if (!ref6(key2, [...dynAnchors, dynLocal[0] || []])) return false + } + for (const key3 of Object.keys(data["$vocabulary"])) { + if (!(typeof data["$vocabulary"][key3] === "boolean")) return false + } + } + if (data["$comment"] !== undefined && hasOwn(data, "$comment")) { + if (!(typeof data["$comment"] === "string")) return false + } + if (data["$defs"] !== undefined && hasOwn(data, "$defs")) { + if (!(typeof data["$defs"] === "object" && data["$defs"] && !Array.isArray(data["$defs"]))) return false + for (const key4 of Object.keys(data["$defs"])) { + if (!(dynamicResolve(dynAnchors || [], "#meta") || validate)(data["$defs"][key4], [...dynAnchors, dynLocal[0] || []])) return false + } + } + } + return true +}; +const ref8 = function validate(data, dynAnchors) { + if (!Array.isArray(data)) return false + if (data.length < 1) return false + for (let j = 0; j < data.length; j++) { + if (data[j] !== undefined && hasOwn(data, j)) { + if (!(dynamicResolve(dynAnchors || [], "#meta") || ref7)(data[j], dynAnchors)) return false + } + } + return true +}; +const format2 = (str) => { + if (str.length > 1e5) return false + const Z_ANCHOR = /[^\\]\\Z/ + if (Z_ANCHOR.test(str)) return false + try { + new RegExp(str, 'u') + return true + } catch (e) { + return false + } + }; +const ref7 = function validate(data, dynAnchors = []) { + const dynLocal = [{}] + dynLocal[0]["#meta"] = validate + if (!(typeof data === "object" && data && !Array.isArray(data) || typeof data === "boolean")) return false + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.prefixItems !== undefined && hasOwn(data, "prefixItems")) { + if (!ref8(data.prefixItems, [...dynAnchors, dynLocal[0] || []])) return false + } + if (data.items !== undefined && hasOwn(data, "items")) { + if (!(dynamicResolve(dynAnchors || [], "#meta") || validate)(data.items, [...dynAnchors, dynLocal[0] || []])) return false + } + if (data.contains !== undefined && hasOwn(data, "contains")) { + if (!(dynamicResolve(dynAnchors || [], "#meta") || validate)(data.contains, [...dynAnchors, dynLocal[0] || []])) return false + } + if (data.additionalProperties !== undefined && hasOwn(data, "additionalProperties")) { + if (!(dynamicResolve(dynAnchors || [], "#meta") || validate)(data.additionalProperties, [...dynAnchors, dynLocal[0] || []])) return false + } + if (data.properties !== undefined && hasOwn(data, "properties")) { + if (!(typeof data.properties === "object" && data.properties && !Array.isArray(data.properties))) return false + for (const key5 of Object.keys(data.properties)) { + if (!(dynamicResolve(dynAnchors || [], "#meta") || validate)(data.properties[key5], [...dynAnchors, dynLocal[0] || []])) return false + } + } + if (data.patternProperties !== undefined && hasOwn(data, "patternProperties")) { + if (!(typeof data.patternProperties === "object" && data.patternProperties && !Array.isArray(data.patternProperties))) return false + for (const key6 of Object.keys(data.patternProperties)) { + if (!format2(key6)) return false + } + for (const key7 of Object.keys(data.patternProperties)) { + if (!(dynamicResolve(dynAnchors || [], "#meta") || validate)(data.patternProperties[key7], [...dynAnchors, dynLocal[0] || []])) return false + } + } + if (data.dependentSchemas !== undefined && hasOwn(data, "dependentSchemas")) { + if (!(typeof data.dependentSchemas === "object" && data.dependentSchemas && !Array.isArray(data.dependentSchemas))) return false + for (const key8 of Object.keys(data.dependentSchemas)) { + if (!(dynamicResolve(dynAnchors || [], "#meta") || validate)(data.dependentSchemas[key8], [...dynAnchors, dynLocal[0] || []])) return false + } + } + if (data.propertyNames !== undefined && hasOwn(data, "propertyNames")) { + if (!(dynamicResolve(dynAnchors || [], "#meta") || validate)(data.propertyNames, [...dynAnchors, dynLocal[0] || []])) return false + } + if (data.if !== undefined && hasOwn(data, "if")) { + if (!(dynamicResolve(dynAnchors || [], "#meta") || validate)(data.if, [...dynAnchors, dynLocal[0] || []])) return false + } + if (data.then !== undefined && hasOwn(data, "then")) { + if (!(dynamicResolve(dynAnchors || [], "#meta") || validate)(data.then, [...dynAnchors, dynLocal[0] || []])) return false + } + if (data.else !== undefined && hasOwn(data, "else")) { + if (!(dynamicResolve(dynAnchors || [], "#meta") || validate)(data.else, [...dynAnchors, dynLocal[0] || []])) return false + } + if (data.allOf !== undefined && hasOwn(data, "allOf")) { + if (!ref8(data.allOf, [...dynAnchors, dynLocal[0] || []])) return false + } + if (data.anyOf !== undefined && hasOwn(data, "anyOf")) { + if (!ref8(data.anyOf, [...dynAnchors, dynLocal[0] || []])) return false + } + if (data.oneOf !== undefined && hasOwn(data, "oneOf")) { + if (!ref8(data.oneOf, [...dynAnchors, dynLocal[0] || []])) return false + } + if (data.not !== undefined && hasOwn(data, "not")) { + if (!(dynamicResolve(dynAnchors || [], "#meta") || validate)(data.not, [...dynAnchors, dynLocal[0] || []])) return false + } + } + return true +}; +const ref9 = function validate(data, dynAnchors = []) { + const dynLocal = [{}] + dynLocal[0]["#meta"] = validate + if (!(typeof data === "object" && data && !Array.isArray(data) || typeof data === "boolean")) return false + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.unevaluatedItems !== undefined && hasOwn(data, "unevaluatedItems")) { + if (!(dynamicResolve(dynAnchors || [], "#meta") || validate)(data.unevaluatedItems, [...dynAnchors, dynLocal[0] || []])) return false + } + if (data.unevaluatedProperties !== undefined && hasOwn(data, "unevaluatedProperties")) { + if (!(dynamicResolve(dynAnchors || [], "#meta") || validate)(data.unevaluatedProperties, [...dynAnchors, dynLocal[0] || []])) return false + } + } + return true +}; +const ref11 = function validate(data, dynAnchors) { + if (!(data === "array" || data === "boolean" || data === "integer" || data === "null" || data === "number" || data === "object" || data === "string")) return false + return true +}; +const ref12 = function validate(data, dynAnchors) { + if (!Number.isInteger(data)) return false + if (!(0 <= data)) return false + return true +}; +const ref13 = function validate(data, dynAnchors) { + if (!ref12(data, dynAnchors)) return false + return true +}; +const ref10 = function validate(data, dynAnchors = []) { + const dynLocal = [{}] + dynLocal[0]["#meta"] = validate + if (!(typeof data === "object" && data && !Array.isArray(data) || typeof data === "boolean")) return false + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.type !== undefined && hasOwn(data, "type")) { + const sub2 = (() => { + if (!ref11(data.type, [...dynAnchors, dynLocal[0] || []])) return false + return true + })() + if (!sub2) { + const sub3 = (() => { + if (!Array.isArray(data.type)) return false + if (data.type.length < 1) return false + for (let k = 0; k < data.type.length; k++) { + if (data.type[k] !== undefined && hasOwn(data.type, k)) { + if (!ref11(data.type[k], [...dynAnchors, dynLocal[0] || []])) return false + } + } + if (!unique(data.type)) return false + return true + })() + if (!sub3) return false + } + } + if (data.enum !== undefined && hasOwn(data, "enum")) { + if (!Array.isArray(data.enum)) return false + } + if (data.multipleOf !== undefined && hasOwn(data, "multipleOf")) { + if (!(typeof data.multipleOf === "number")) return false + if (!(0 < data.multipleOf)) return false + } + if (data.maximum !== undefined && hasOwn(data, "maximum")) { + if (!(typeof data.maximum === "number")) return false + } + if (data.exclusiveMaximum !== undefined && hasOwn(data, "exclusiveMaximum")) { + if (!(typeof data.exclusiveMaximum === "number")) return false + } + if (data.minimum !== undefined && hasOwn(data, "minimum")) { + if (!(typeof data.minimum === "number")) return false + } + if (data.exclusiveMinimum !== undefined && hasOwn(data, "exclusiveMinimum")) { + if (!(typeof data.exclusiveMinimum === "number")) return false + } + if (data.maxLength !== undefined && hasOwn(data, "maxLength")) { + if (!ref12(data.maxLength, [...dynAnchors, dynLocal[0] || []])) return false + } + if (data.minLength !== undefined && hasOwn(data, "minLength")) { + if (!ref13(data.minLength, [...dynAnchors, dynLocal[0] || []])) return false + } + if (data.pattern !== undefined && hasOwn(data, "pattern")) { + if (!(typeof data.pattern === "string")) return false + if (!format2(data.pattern)) return false + } + if (data.maxItems !== undefined && hasOwn(data, "maxItems")) { + if (!ref12(data.maxItems, [...dynAnchors, dynLocal[0] || []])) return false + } + if (data.minItems !== undefined && hasOwn(data, "minItems")) { + if (!ref13(data.minItems, [...dynAnchors, dynLocal[0] || []])) return false + } + if (data.uniqueItems !== undefined && hasOwn(data, "uniqueItems")) { + if (!(typeof data.uniqueItems === "boolean")) return false + } + if (data.maxContains !== undefined && hasOwn(data, "maxContains")) { + if (!ref12(data.maxContains, [...dynAnchors, dynLocal[0] || []])) return false + } + if (data.minContains !== undefined && hasOwn(data, "minContains")) { + if (!ref12(data.minContains, [...dynAnchors, dynLocal[0] || []])) return false + } + if (data.maxProperties !== undefined && hasOwn(data, "maxProperties")) { + if (!ref12(data.maxProperties, [...dynAnchors, dynLocal[0] || []])) return false + } + if (data.minProperties !== undefined && hasOwn(data, "minProperties")) { + if (!ref13(data.minProperties, [...dynAnchors, dynLocal[0] || []])) return false + } + if (data.required !== undefined && hasOwn(data, "required")) { + if (!ref2(data.required, [...dynAnchors, dynLocal[0] || []])) return false + } + if (data.dependentRequired !== undefined && hasOwn(data, "dependentRequired")) { + if (!(typeof data.dependentRequired === "object" && data.dependentRequired && !Array.isArray(data.dependentRequired))) return false + for (const key9 of Object.keys(data.dependentRequired)) { + if (!ref2(data.dependentRequired[key9], [...dynAnchors, dynLocal[0] || []])) return false + } + } + } + return true +}; +const ref14 = function validate(data, dynAnchors) { + if (!(typeof data === "object" && data && !Array.isArray(data) || typeof data === "boolean")) return false + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.title !== undefined && hasOwn(data, "title")) { + if (!(typeof data.title === "string")) return false + } + if (data.description !== undefined && hasOwn(data, "description")) { + if (!(typeof data.description === "string")) return false + } + if (data.deprecated !== undefined && hasOwn(data, "deprecated")) { + if (!(typeof data.deprecated === "boolean")) return false + } + if (data.readOnly !== undefined && hasOwn(data, "readOnly")) { + if (!(typeof data.readOnly === "boolean")) return false + } + if (data.writeOnly !== undefined && hasOwn(data, "writeOnly")) { + if (!(typeof data.writeOnly === "boolean")) return false + } + if (data.examples !== undefined && hasOwn(data, "examples")) { + if (!Array.isArray(data.examples)) return false + } + } + return true +}; +const ref15 = function validate(data, dynAnchors) { + if (!(typeof data === "object" && data && !Array.isArray(data) || typeof data === "boolean")) return false + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.format !== undefined && hasOwn(data, "format")) { + if (!(typeof data.format === "string")) return false + } + } + return true +}; +const ref16 = function validate(data, dynAnchors = []) { + const dynLocal = [{}] + dynLocal[0]["#meta"] = validate + if (!(typeof data === "object" && data && !Array.isArray(data) || typeof data === "boolean")) return false + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.contentEncoding !== undefined && hasOwn(data, "contentEncoding")) { + if (!(typeof data.contentEncoding === "string")) return false + } + if (data.contentMediaType !== undefined && hasOwn(data, "contentMediaType")) { + if (!(typeof data.contentMediaType === "string")) return false + } + if (data.contentSchema !== undefined && hasOwn(data, "contentSchema")) { + if (!(dynamicResolve(dynAnchors || [], "#meta") || validate)(data.contentSchema, [...dynAnchors, dynLocal[0] || []])) return false + } + } + return true +}; +const ref1 = function validate(data, dynAnchors = []) { + const dynLocal = [{}] + dynLocal[0]["#meta"] = validate + if (!(typeof data === "object" && data && !Array.isArray(data) || typeof data === "boolean")) return false + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.definitions !== undefined && hasOwn(data, "definitions")) { + if (!(typeof data.definitions === "object" && data.definitions && !Array.isArray(data.definitions))) return false + for (const key0 of Object.keys(data.definitions)) { + if (!(dynamicResolve(dynAnchors || [], "#meta") || validate)(data.definitions[key0], [...dynAnchors, dynLocal[0] || []])) return false + } + } + if (data.dependencies !== undefined && hasOwn(data, "dependencies")) { + if (!(typeof data.dependencies === "object" && data.dependencies && !Array.isArray(data.dependencies))) return false + for (const key1 of Object.keys(data.dependencies)) { + const sub0 = (() => { + if (!(dynamicResolve(dynAnchors || [], "#meta") || validate)(data.dependencies[key1], [...dynAnchors, dynLocal[0] || []])) return false + return true + })() + if (!sub0) { + const sub1 = (() => { + if (!ref2(data.dependencies[key1], [...dynAnchors, dynLocal[0] || []])) return false + return true + })() + if (!sub1) return false + } + } + } + if (data["$recursiveAnchor"] !== undefined && hasOwn(data, "$recursiveAnchor")) { + if (!ref3(data["$recursiveAnchor"], [...dynAnchors, dynLocal[0] || []])) return false + } + if (data["$recursiveRef"] !== undefined && hasOwn(data, "$recursiveRef")) { + if (!ref4(data["$recursiveRef"], [...dynAnchors, dynLocal[0] || []])) return false + } + } + if (!ref5(data, [...dynAnchors, dynLocal[0] || []])) return false + if (!ref7(data, [...dynAnchors, dynLocal[0] || []])) return false + if (!ref9(data, [...dynAnchors, dynLocal[0] || []])) return false + if (!ref10(data, [...dynAnchors, dynLocal[0] || []])) return false + if (!ref14(data, [...dynAnchors, dynLocal[0] || []])) return false + if (!ref15(data, [...dynAnchors, dynLocal[0] || []])) return false + if (!ref16(data, [...dynAnchors, dynLocal[0] || []])) return false + return true +}; +const ref0 = function validate(data, dynAnchors) { + if (!ref1(data, dynAnchors)) return false + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at https://json-schema.org/draft/next/schema#/properties/definitions/additionalProperties` + + +## Valid use of empty fragments in location-independent $id + +### Schema + +```json +{ "$ref": "https://json-schema.org/draft/next/schema" } +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const dynamicResolve = (anchors, id) => (anchors.filter((x) => x[id])[0] || {})[id]; +const unique = (array) => { + if (array.length < 2) return true + if (array.length === 2) return !deepEqual(array[0], array[1]) + const objects = [] + const primitives = array.length > 20 ? new Set() : null + let primitivesCount = 0 + let pos = 0 + for (const item of array) { + if (typeof item === 'object') { + objects.push(item) + } else if (primitives) { + primitives.add(item) + if (primitives.size !== ++primitivesCount) return false + } else { + if (array.indexOf(item, pos + 1) !== -1) return false + } + pos++ + } + for (let i = 1; i < objects.length; i++) + for (let j = 0; j < i; j++) if (deepEqual(objects[i], objects[j])) return false + return true +}; +const deepEqual = (obj, obj2) => { + if (obj === obj2) return true + if (!obj || !obj2 || typeof obj !== typeof obj2) return false + if (obj !== obj2 && typeof obj !== 'object') return false + + const proto = Object.getPrototypeOf(obj) + if (proto !== Object.getPrototypeOf(obj2)) return false + + if (proto === Array.prototype) { + if (!Array.isArray(obj) || !Array.isArray(obj2)) return false + if (obj.length !== obj2.length) return false + return obj.every((x, i) => deepEqual(x, obj2[i])) + } else if (proto === Object.prototype) { + const [keys, keys2] = [Object.keys(obj), Object.keys(obj2)] + if (keys.length !== keys2.length) return false + const keyset2 = new Set([...keys, ...keys2]) + return keyset2.size === keys.length && keys.every((key) => deepEqual(obj[key], obj2[key])) + } + return false +}; +const ref2 = function validate(data, dynAnchors) { + if (!Array.isArray(data)) return false + for (let i = 0; i < data.length; i++) { + if (data[i] !== undefined && hasOwn(data, i)) { + if (!(typeof data[i] === "string")) return false + } + } + if (!unique(data)) return false + return true +}; +const pattern0 = new RegExp("^[A-Za-z_][-A-Za-z0-9._]*$", "u"); +const ref3 = function validate(data, dynAnchors) { + if (!(typeof data === "string")) return false + if (!pattern0.test(data)) return false + return true +}; +const format0 = new RegExp("^(?:[a-z][a-z0-9+\\-.]*:)?(?:\\/?\\/(?:(?:[a-z0-9\\-._~!$&'()*+,;=:]|%[0-9a-f]{2})*@)?(?:\\[(?:(?:(?:(?:[0-9a-f]{1,4}:){6}|::(?:[0-9a-f]{1,4}:){5}|(?:[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){4}|(?:(?:[0-9a-f]{1,4}:){0,1}[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){3}|(?:(?:[0-9a-f]{1,4}:){0,2}[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){2}|(?:(?:[0-9a-f]{1,4}:){0,3}[0-9a-f]{1,4})?::[0-9a-f]{1,4}:|(?:(?:[0-9a-f]{1,4}:){0,4}[0-9a-f]{1,4})?::)(?:[0-9a-f]{1,4}:[0-9a-f]{1,4}|(?:(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d\\d?)\\.){3}(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d\\d?))|(?:(?:[0-9a-f]{1,4}:){0,5}[0-9a-f]{1,4})?::[0-9a-f]{1,4}|(?:(?:[0-9a-f]{1,4}:){0,6}[0-9a-f]{1,4})?::)|v[0-9a-f]+\\.[a-z0-9\\-._~!$&'()*+,;=:]+)\\]|(?:(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d\\d?)\\.){3}(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d\\d?)|(?:[a-z0-9\\-._~!$&'()*+,;=]|%[0-9a-f]{2})*)(?::\\d*)?(?:\\/(?:[a-z0-9\\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})*)*|\\/?(?:(?:[a-z0-9\\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})+(?:\\/(?:[a-z0-9\\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})*)*)?)?(?:\\?(?:[a-z0-9\\-._~!$&'()*+,;=:@/?]|%[0-9a-f]{2})*)?(?:#(?:[a-z0-9\\-._~!$&'()*+,;=:@/?]|%[0-9a-f]{2})*)?$", "i"); +const ref4 = function validate(data, dynAnchors) { + if (!(typeof data === "string")) return false + if (!format0.test(data)) return false + return true +}; +const pattern1 = new RegExp("^[^#]*#?$", "u"); +const format1 = new RegExp("^[a-z][a-z0-9+\\-.]*:(?:\\/?\\/(?:(?:[a-z0-9\\-._~!$&'()*+,;=:]|%[0-9a-f]{2})*@)?(?:\\[(?:(?:(?:(?:[0-9a-f]{1,4}:){6}|::(?:[0-9a-f]{1,4}:){5}|(?:[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){4}|(?:(?:[0-9a-f]{1,4}:){0,1}[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){3}|(?:(?:[0-9a-f]{1,4}:){0,2}[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){2}|(?:(?:[0-9a-f]{1,4}:){0,3}[0-9a-f]{1,4})?::[0-9a-f]{1,4}:|(?:(?:[0-9a-f]{1,4}:){0,4}[0-9a-f]{1,4})?::)(?:[0-9a-f]{1,4}:[0-9a-f]{1,4}|(?:(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d\\d?)\\.){3}(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d\\d?))|(?:(?:[0-9a-f]{1,4}:){0,5}[0-9a-f]{1,4})?::[0-9a-f]{1,4}|(?:(?:[0-9a-f]{1,4}:){0,6}[0-9a-f]{1,4})?::)|v[0-9a-f]+\\.[a-z0-9\\-._~!$&'()*+,;=:]+)\\]|(?:(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d\\d?)\\.){3}(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d\\d?)|(?:[a-z0-9\\-._~!$&'()*+,;=]|%[0-9a-f]{2})*)(?::\\d*)?(?:\\/(?:[a-z0-9\\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})*)*|\\/?(?:(?:[a-z0-9\\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})+(?:\\/(?:[a-z0-9\\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})*)*)?)(?:\\?(?:[a-z0-9\\-._~!$&'()*+,;=:@/?]|%[0-9a-f]{2})*)?(?:#(?:[a-z0-9\\-._~!$&'()*+,;=:@/?]|%[0-9a-f]{2})*)?$", "i"); +const ref6 = function validate(data, dynAnchors) { + if (!(typeof data === "string")) return false + if (!format1.test(data)) return false + return true +}; +const ref5 = function validate(data, dynAnchors = []) { + const dynLocal = [{}] + dynLocal[0]["#meta"] = validate + if (!(typeof data === "object" && data && !Array.isArray(data) || typeof data === "boolean")) return false + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data["$id"] !== undefined && hasOwn(data, "$id")) { + if (!ref4(data["$id"], [...dynAnchors, dynLocal[0] || []])) return false + if (!(pattern1.test(data["$id"]))) return false + } + if (data["$schema"] !== undefined && hasOwn(data, "$schema")) { + if (!ref6(data["$schema"], [...dynAnchors, dynLocal[0] || []])) return false + } + if (data["$ref"] !== undefined && hasOwn(data, "$ref")) { + if (!ref4(data["$ref"], [...dynAnchors, dynLocal[0] || []])) return false + } + if (data["$anchor"] !== undefined && hasOwn(data, "$anchor")) { + if (!ref3(data["$anchor"], [...dynAnchors, dynLocal[0] || []])) return false + } + if (data["$dynamicRef"] !== undefined && hasOwn(data, "$dynamicRef")) { + if (!ref4(data["$dynamicRef"], [...dynAnchors, dynLocal[0] || []])) return false + } + if (data["$dynamicAnchor"] !== undefined && hasOwn(data, "$dynamicAnchor")) { + if (!ref3(data["$dynamicAnchor"], [...dynAnchors, dynLocal[0] || []])) return false + } + if (data["$vocabulary"] !== undefined && hasOwn(data, "$vocabulary")) { + if (!(typeof data["$vocabulary"] === "object" && data["$vocabulary"] && !Array.isArray(data["$vocabulary"]))) return false + for (const key2 of Object.keys(data["$vocabulary"])) { + if (!ref6(key2, [...dynAnchors, dynLocal[0] || []])) return false + } + for (const key3 of Object.keys(data["$vocabulary"])) { + if (!(typeof data["$vocabulary"][key3] === "boolean")) return false + } + } + if (data["$comment"] !== undefined && hasOwn(data, "$comment")) { + if (!(typeof data["$comment"] === "string")) return false + } + if (data["$defs"] !== undefined && hasOwn(data, "$defs")) { + if (!(typeof data["$defs"] === "object" && data["$defs"] && !Array.isArray(data["$defs"]))) return false + for (const key4 of Object.keys(data["$defs"])) { + if (!(dynamicResolve(dynAnchors || [], "#meta") || validate)(data["$defs"][key4], [...dynAnchors, dynLocal[0] || []])) return false + } + } + } + return true +}; +const ref8 = function validate(data, dynAnchors) { + if (!Array.isArray(data)) return false + if (data.length < 1) return false + for (let j = 0; j < data.length; j++) { + if (data[j] !== undefined && hasOwn(data, j)) { + if (!(dynamicResolve(dynAnchors || [], "#meta") || ref7)(data[j], dynAnchors)) return false + } + } + return true +}; +const format2 = (str) => { + if (str.length > 1e5) return false + const Z_ANCHOR = /[^\\]\\Z/ + if (Z_ANCHOR.test(str)) return false + try { + new RegExp(str, 'u') + return true + } catch (e) { + return false + } + }; +const ref7 = function validate(data, dynAnchors = []) { + const dynLocal = [{}] + dynLocal[0]["#meta"] = validate + if (!(typeof data === "object" && data && !Array.isArray(data) || typeof data === "boolean")) return false + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.prefixItems !== undefined && hasOwn(data, "prefixItems")) { + if (!ref8(data.prefixItems, [...dynAnchors, dynLocal[0] || []])) return false + } + if (data.items !== undefined && hasOwn(data, "items")) { + if (!(dynamicResolve(dynAnchors || [], "#meta") || validate)(data.items, [...dynAnchors, dynLocal[0] || []])) return false + } + if (data.contains !== undefined && hasOwn(data, "contains")) { + if (!(dynamicResolve(dynAnchors || [], "#meta") || validate)(data.contains, [...dynAnchors, dynLocal[0] || []])) return false + } + if (data.additionalProperties !== undefined && hasOwn(data, "additionalProperties")) { + if (!(dynamicResolve(dynAnchors || [], "#meta") || validate)(data.additionalProperties, [...dynAnchors, dynLocal[0] || []])) return false + } + if (data.properties !== undefined && hasOwn(data, "properties")) { + if (!(typeof data.properties === "object" && data.properties && !Array.isArray(data.properties))) return false + for (const key5 of Object.keys(data.properties)) { + if (!(dynamicResolve(dynAnchors || [], "#meta") || validate)(data.properties[key5], [...dynAnchors, dynLocal[0] || []])) return false + } + } + if (data.patternProperties !== undefined && hasOwn(data, "patternProperties")) { + if (!(typeof data.patternProperties === "object" && data.patternProperties && !Array.isArray(data.patternProperties))) return false + for (const key6 of Object.keys(data.patternProperties)) { + if (!format2(key6)) return false + } + for (const key7 of Object.keys(data.patternProperties)) { + if (!(dynamicResolve(dynAnchors || [], "#meta") || validate)(data.patternProperties[key7], [...dynAnchors, dynLocal[0] || []])) return false + } + } + if (data.dependentSchemas !== undefined && hasOwn(data, "dependentSchemas")) { + if (!(typeof data.dependentSchemas === "object" && data.dependentSchemas && !Array.isArray(data.dependentSchemas))) return false + for (const key8 of Object.keys(data.dependentSchemas)) { + if (!(dynamicResolve(dynAnchors || [], "#meta") || validate)(data.dependentSchemas[key8], [...dynAnchors, dynLocal[0] || []])) return false + } + } + if (data.propertyNames !== undefined && hasOwn(data, "propertyNames")) { + if (!(dynamicResolve(dynAnchors || [], "#meta") || validate)(data.propertyNames, [...dynAnchors, dynLocal[0] || []])) return false + } + if (data.if !== undefined && hasOwn(data, "if")) { + if (!(dynamicResolve(dynAnchors || [], "#meta") || validate)(data.if, [...dynAnchors, dynLocal[0] || []])) return false + } + if (data.then !== undefined && hasOwn(data, "then")) { + if (!(dynamicResolve(dynAnchors || [], "#meta") || validate)(data.then, [...dynAnchors, dynLocal[0] || []])) return false + } + if (data.else !== undefined && hasOwn(data, "else")) { + if (!(dynamicResolve(dynAnchors || [], "#meta") || validate)(data.else, [...dynAnchors, dynLocal[0] || []])) return false + } + if (data.allOf !== undefined && hasOwn(data, "allOf")) { + if (!ref8(data.allOf, [...dynAnchors, dynLocal[0] || []])) return false + } + if (data.anyOf !== undefined && hasOwn(data, "anyOf")) { + if (!ref8(data.anyOf, [...dynAnchors, dynLocal[0] || []])) return false + } + if (data.oneOf !== undefined && hasOwn(data, "oneOf")) { + if (!ref8(data.oneOf, [...dynAnchors, dynLocal[0] || []])) return false + } + if (data.not !== undefined && hasOwn(data, "not")) { + if (!(dynamicResolve(dynAnchors || [], "#meta") || validate)(data.not, [...dynAnchors, dynLocal[0] || []])) return false + } + } + return true +}; +const ref9 = function validate(data, dynAnchors = []) { + const dynLocal = [{}] + dynLocal[0]["#meta"] = validate + if (!(typeof data === "object" && data && !Array.isArray(data) || typeof data === "boolean")) return false + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.unevaluatedItems !== undefined && hasOwn(data, "unevaluatedItems")) { + if (!(dynamicResolve(dynAnchors || [], "#meta") || validate)(data.unevaluatedItems, [...dynAnchors, dynLocal[0] || []])) return false + } + if (data.unevaluatedProperties !== undefined && hasOwn(data, "unevaluatedProperties")) { + if (!(dynamicResolve(dynAnchors || [], "#meta") || validate)(data.unevaluatedProperties, [...dynAnchors, dynLocal[0] || []])) return false + } + } + return true +}; +const ref11 = function validate(data, dynAnchors) { + if (!(data === "array" || data === "boolean" || data === "integer" || data === "null" || data === "number" || data === "object" || data === "string")) return false + return true +}; +const ref12 = function validate(data, dynAnchors) { + if (!Number.isInteger(data)) return false + if (!(0 <= data)) return false + return true +}; +const ref13 = function validate(data, dynAnchors) { + if (!ref12(data, dynAnchors)) return false + return true +}; +const ref10 = function validate(data, dynAnchors = []) { + const dynLocal = [{}] + dynLocal[0]["#meta"] = validate + if (!(typeof data === "object" && data && !Array.isArray(data) || typeof data === "boolean")) return false + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.type !== undefined && hasOwn(data, "type")) { + const sub2 = (() => { + if (!ref11(data.type, [...dynAnchors, dynLocal[0] || []])) return false + return true + })() + if (!sub2) { + const sub3 = (() => { + if (!Array.isArray(data.type)) return false + if (data.type.length < 1) return false + for (let k = 0; k < data.type.length; k++) { + if (data.type[k] !== undefined && hasOwn(data.type, k)) { + if (!ref11(data.type[k], [...dynAnchors, dynLocal[0] || []])) return false + } + } + if (!unique(data.type)) return false + return true + })() + if (!sub3) return false + } + } + if (data.enum !== undefined && hasOwn(data, "enum")) { + if (!Array.isArray(data.enum)) return false + } + if (data.multipleOf !== undefined && hasOwn(data, "multipleOf")) { + if (!(typeof data.multipleOf === "number")) return false + if (!(0 < data.multipleOf)) return false + } + if (data.maximum !== undefined && hasOwn(data, "maximum")) { + if (!(typeof data.maximum === "number")) return false + } + if (data.exclusiveMaximum !== undefined && hasOwn(data, "exclusiveMaximum")) { + if (!(typeof data.exclusiveMaximum === "number")) return false + } + if (data.minimum !== undefined && hasOwn(data, "minimum")) { + if (!(typeof data.minimum === "number")) return false + } + if (data.exclusiveMinimum !== undefined && hasOwn(data, "exclusiveMinimum")) { + if (!(typeof data.exclusiveMinimum === "number")) return false + } + if (data.maxLength !== undefined && hasOwn(data, "maxLength")) { + if (!ref12(data.maxLength, [...dynAnchors, dynLocal[0] || []])) return false + } + if (data.minLength !== undefined && hasOwn(data, "minLength")) { + if (!ref13(data.minLength, [...dynAnchors, dynLocal[0] || []])) return false + } + if (data.pattern !== undefined && hasOwn(data, "pattern")) { + if (!(typeof data.pattern === "string")) return false + if (!format2(data.pattern)) return false + } + if (data.maxItems !== undefined && hasOwn(data, "maxItems")) { + if (!ref12(data.maxItems, [...dynAnchors, dynLocal[0] || []])) return false + } + if (data.minItems !== undefined && hasOwn(data, "minItems")) { + if (!ref13(data.minItems, [...dynAnchors, dynLocal[0] || []])) return false + } + if (data.uniqueItems !== undefined && hasOwn(data, "uniqueItems")) { + if (!(typeof data.uniqueItems === "boolean")) return false + } + if (data.maxContains !== undefined && hasOwn(data, "maxContains")) { + if (!ref12(data.maxContains, [...dynAnchors, dynLocal[0] || []])) return false + } + if (data.minContains !== undefined && hasOwn(data, "minContains")) { + if (!ref12(data.minContains, [...dynAnchors, dynLocal[0] || []])) return false + } + if (data.maxProperties !== undefined && hasOwn(data, "maxProperties")) { + if (!ref12(data.maxProperties, [...dynAnchors, dynLocal[0] || []])) return false + } + if (data.minProperties !== undefined && hasOwn(data, "minProperties")) { + if (!ref13(data.minProperties, [...dynAnchors, dynLocal[0] || []])) return false + } + if (data.required !== undefined && hasOwn(data, "required")) { + if (!ref2(data.required, [...dynAnchors, dynLocal[0] || []])) return false + } + if (data.dependentRequired !== undefined && hasOwn(data, "dependentRequired")) { + if (!(typeof data.dependentRequired === "object" && data.dependentRequired && !Array.isArray(data.dependentRequired))) return false + for (const key9 of Object.keys(data.dependentRequired)) { + if (!ref2(data.dependentRequired[key9], [...dynAnchors, dynLocal[0] || []])) return false + } + } + } + return true +}; +const ref14 = function validate(data, dynAnchors) { + if (!(typeof data === "object" && data && !Array.isArray(data) || typeof data === "boolean")) return false + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.title !== undefined && hasOwn(data, "title")) { + if (!(typeof data.title === "string")) return false + } + if (data.description !== undefined && hasOwn(data, "description")) { + if (!(typeof data.description === "string")) return false + } + if (data.deprecated !== undefined && hasOwn(data, "deprecated")) { + if (!(typeof data.deprecated === "boolean")) return false + } + if (data.readOnly !== undefined && hasOwn(data, "readOnly")) { + if (!(typeof data.readOnly === "boolean")) return false + } + if (data.writeOnly !== undefined && hasOwn(data, "writeOnly")) { + if (!(typeof data.writeOnly === "boolean")) return false + } + if (data.examples !== undefined && hasOwn(data, "examples")) { + if (!Array.isArray(data.examples)) return false + } + } + return true +}; +const ref15 = function validate(data, dynAnchors) { + if (!(typeof data === "object" && data && !Array.isArray(data) || typeof data === "boolean")) return false + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.format !== undefined && hasOwn(data, "format")) { + if (!(typeof data.format === "string")) return false + } + } + return true +}; +const ref16 = function validate(data, dynAnchors = []) { + const dynLocal = [{}] + dynLocal[0]["#meta"] = validate + if (!(typeof data === "object" && data && !Array.isArray(data) || typeof data === "boolean")) return false + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.contentEncoding !== undefined && hasOwn(data, "contentEncoding")) { + if (!(typeof data.contentEncoding === "string")) return false + } + if (data.contentMediaType !== undefined && hasOwn(data, "contentMediaType")) { + if (!(typeof data.contentMediaType === "string")) return false + } + if (data.contentSchema !== undefined && hasOwn(data, "contentSchema")) { + if (!(dynamicResolve(dynAnchors || [], "#meta") || validate)(data.contentSchema, [...dynAnchors, dynLocal[0] || []])) return false + } + } + return true +}; +const ref1 = function validate(data, dynAnchors = []) { + const dynLocal = [{}] + dynLocal[0]["#meta"] = validate + if (!(typeof data === "object" && data && !Array.isArray(data) || typeof data === "boolean")) return false + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.definitions !== undefined && hasOwn(data, "definitions")) { + if (!(typeof data.definitions === "object" && data.definitions && !Array.isArray(data.definitions))) return false + for (const key0 of Object.keys(data.definitions)) { + if (!(dynamicResolve(dynAnchors || [], "#meta") || validate)(data.definitions[key0], [...dynAnchors, dynLocal[0] || []])) return false + } + } + if (data.dependencies !== undefined && hasOwn(data, "dependencies")) { + if (!(typeof data.dependencies === "object" && data.dependencies && !Array.isArray(data.dependencies))) return false + for (const key1 of Object.keys(data.dependencies)) { + const sub0 = (() => { + if (!(dynamicResolve(dynAnchors || [], "#meta") || validate)(data.dependencies[key1], [...dynAnchors, dynLocal[0] || []])) return false + return true + })() + if (!sub0) { + const sub1 = (() => { + if (!ref2(data.dependencies[key1], [...dynAnchors, dynLocal[0] || []])) return false + return true + })() + if (!sub1) return false + } + } + } + if (data["$recursiveAnchor"] !== undefined && hasOwn(data, "$recursiveAnchor")) { + if (!ref3(data["$recursiveAnchor"], [...dynAnchors, dynLocal[0] || []])) return false + } + if (data["$recursiveRef"] !== undefined && hasOwn(data, "$recursiveRef")) { + if (!ref4(data["$recursiveRef"], [...dynAnchors, dynLocal[0] || []])) return false + } + } + if (!ref5(data, [...dynAnchors, dynLocal[0] || []])) return false + if (!ref7(data, [...dynAnchors, dynLocal[0] || []])) return false + if (!ref9(data, [...dynAnchors, dynLocal[0] || []])) return false + if (!ref10(data, [...dynAnchors, dynLocal[0] || []])) return false + if (!ref14(data, [...dynAnchors, dynLocal[0] || []])) return false + if (!ref15(data, [...dynAnchors, dynLocal[0] || []])) return false + if (!ref16(data, [...dynAnchors, dynLocal[0] || []])) return false + return true +}; +const ref0 = function validate(data, dynAnchors) { + if (!ref1(data, dynAnchors)) return false + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at https://json-schema.org/draft/next/schema#/properties/definitions/additionalProperties` + + +## Unnormalized $ids are allowed but discouraged + +### Schema + +```json +{ "$ref": "https://json-schema.org/draft/next/schema" } +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const dynamicResolve = (anchors, id) => (anchors.filter((x) => x[id])[0] || {})[id]; +const unique = (array) => { + if (array.length < 2) return true + if (array.length === 2) return !deepEqual(array[0], array[1]) + const objects = [] + const primitives = array.length > 20 ? new Set() : null + let primitivesCount = 0 + let pos = 0 + for (const item of array) { + if (typeof item === 'object') { + objects.push(item) + } else if (primitives) { + primitives.add(item) + if (primitives.size !== ++primitivesCount) return false + } else { + if (array.indexOf(item, pos + 1) !== -1) return false + } + pos++ + } + for (let i = 1; i < objects.length; i++) + for (let j = 0; j < i; j++) if (deepEqual(objects[i], objects[j])) return false + return true +}; +const deepEqual = (obj, obj2) => { + if (obj === obj2) return true + if (!obj || !obj2 || typeof obj !== typeof obj2) return false + if (obj !== obj2 && typeof obj !== 'object') return false + + const proto = Object.getPrototypeOf(obj) + if (proto !== Object.getPrototypeOf(obj2)) return false + + if (proto === Array.prototype) { + if (!Array.isArray(obj) || !Array.isArray(obj2)) return false + if (obj.length !== obj2.length) return false + return obj.every((x, i) => deepEqual(x, obj2[i])) + } else if (proto === Object.prototype) { + const [keys, keys2] = [Object.keys(obj), Object.keys(obj2)] + if (keys.length !== keys2.length) return false + const keyset2 = new Set([...keys, ...keys2]) + return keyset2.size === keys.length && keys.every((key) => deepEqual(obj[key], obj2[key])) + } + return false +}; +const ref2 = function validate(data, dynAnchors) { + if (!Array.isArray(data)) return false + for (let i = 0; i < data.length; i++) { + if (data[i] !== undefined && hasOwn(data, i)) { + if (!(typeof data[i] === "string")) return false + } + } + if (!unique(data)) return false + return true +}; +const pattern0 = new RegExp("^[A-Za-z_][-A-Za-z0-9._]*$", "u"); +const ref3 = function validate(data, dynAnchors) { + if (!(typeof data === "string")) return false + if (!pattern0.test(data)) return false + return true +}; +const format0 = new RegExp("^(?:[a-z][a-z0-9+\\-.]*:)?(?:\\/?\\/(?:(?:[a-z0-9\\-._~!$&'()*+,;=:]|%[0-9a-f]{2})*@)?(?:\\[(?:(?:(?:(?:[0-9a-f]{1,4}:){6}|::(?:[0-9a-f]{1,4}:){5}|(?:[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){4}|(?:(?:[0-9a-f]{1,4}:){0,1}[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){3}|(?:(?:[0-9a-f]{1,4}:){0,2}[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){2}|(?:(?:[0-9a-f]{1,4}:){0,3}[0-9a-f]{1,4})?::[0-9a-f]{1,4}:|(?:(?:[0-9a-f]{1,4}:){0,4}[0-9a-f]{1,4})?::)(?:[0-9a-f]{1,4}:[0-9a-f]{1,4}|(?:(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d\\d?)\\.){3}(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d\\d?))|(?:(?:[0-9a-f]{1,4}:){0,5}[0-9a-f]{1,4})?::[0-9a-f]{1,4}|(?:(?:[0-9a-f]{1,4}:){0,6}[0-9a-f]{1,4})?::)|v[0-9a-f]+\\.[a-z0-9\\-._~!$&'()*+,;=:]+)\\]|(?:(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d\\d?)\\.){3}(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d\\d?)|(?:[a-z0-9\\-._~!$&'()*+,;=]|%[0-9a-f]{2})*)(?::\\d*)?(?:\\/(?:[a-z0-9\\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})*)*|\\/?(?:(?:[a-z0-9\\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})+(?:\\/(?:[a-z0-9\\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})*)*)?)?(?:\\?(?:[a-z0-9\\-._~!$&'()*+,;=:@/?]|%[0-9a-f]{2})*)?(?:#(?:[a-z0-9\\-._~!$&'()*+,;=:@/?]|%[0-9a-f]{2})*)?$", "i"); +const ref4 = function validate(data, dynAnchors) { + if (!(typeof data === "string")) return false + if (!format0.test(data)) return false + return true +}; +const pattern1 = new RegExp("^[^#]*#?$", "u"); +const format1 = new RegExp("^[a-z][a-z0-9+\\-.]*:(?:\\/?\\/(?:(?:[a-z0-9\\-._~!$&'()*+,;=:]|%[0-9a-f]{2})*@)?(?:\\[(?:(?:(?:(?:[0-9a-f]{1,4}:){6}|::(?:[0-9a-f]{1,4}:){5}|(?:[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){4}|(?:(?:[0-9a-f]{1,4}:){0,1}[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){3}|(?:(?:[0-9a-f]{1,4}:){0,2}[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){2}|(?:(?:[0-9a-f]{1,4}:){0,3}[0-9a-f]{1,4})?::[0-9a-f]{1,4}:|(?:(?:[0-9a-f]{1,4}:){0,4}[0-9a-f]{1,4})?::)(?:[0-9a-f]{1,4}:[0-9a-f]{1,4}|(?:(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d\\d?)\\.){3}(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d\\d?))|(?:(?:[0-9a-f]{1,4}:){0,5}[0-9a-f]{1,4})?::[0-9a-f]{1,4}|(?:(?:[0-9a-f]{1,4}:){0,6}[0-9a-f]{1,4})?::)|v[0-9a-f]+\\.[a-z0-9\\-._~!$&'()*+,;=:]+)\\]|(?:(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d\\d?)\\.){3}(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d\\d?)|(?:[a-z0-9\\-._~!$&'()*+,;=]|%[0-9a-f]{2})*)(?::\\d*)?(?:\\/(?:[a-z0-9\\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})*)*|\\/?(?:(?:[a-z0-9\\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})+(?:\\/(?:[a-z0-9\\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})*)*)?)(?:\\?(?:[a-z0-9\\-._~!$&'()*+,;=:@/?]|%[0-9a-f]{2})*)?(?:#(?:[a-z0-9\\-._~!$&'()*+,;=:@/?]|%[0-9a-f]{2})*)?$", "i"); +const ref6 = function validate(data, dynAnchors) { + if (!(typeof data === "string")) return false + if (!format1.test(data)) return false + return true +}; +const ref5 = function validate(data, dynAnchors = []) { + const dynLocal = [{}] + dynLocal[0]["#meta"] = validate + if (!(typeof data === "object" && data && !Array.isArray(data) || typeof data === "boolean")) return false + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data["$id"] !== undefined && hasOwn(data, "$id")) { + if (!ref4(data["$id"], [...dynAnchors, dynLocal[0] || []])) return false + if (!(pattern1.test(data["$id"]))) return false + } + if (data["$schema"] !== undefined && hasOwn(data, "$schema")) { + if (!ref6(data["$schema"], [...dynAnchors, dynLocal[0] || []])) return false + } + if (data["$ref"] !== undefined && hasOwn(data, "$ref")) { + if (!ref4(data["$ref"], [...dynAnchors, dynLocal[0] || []])) return false + } + if (data["$anchor"] !== undefined && hasOwn(data, "$anchor")) { + if (!ref3(data["$anchor"], [...dynAnchors, dynLocal[0] || []])) return false + } + if (data["$dynamicRef"] !== undefined && hasOwn(data, "$dynamicRef")) { + if (!ref4(data["$dynamicRef"], [...dynAnchors, dynLocal[0] || []])) return false + } + if (data["$dynamicAnchor"] !== undefined && hasOwn(data, "$dynamicAnchor")) { + if (!ref3(data["$dynamicAnchor"], [...dynAnchors, dynLocal[0] || []])) return false + } + if (data["$vocabulary"] !== undefined && hasOwn(data, "$vocabulary")) { + if (!(typeof data["$vocabulary"] === "object" && data["$vocabulary"] && !Array.isArray(data["$vocabulary"]))) return false + for (const key2 of Object.keys(data["$vocabulary"])) { + if (!ref6(key2, [...dynAnchors, dynLocal[0] || []])) return false + } + for (const key3 of Object.keys(data["$vocabulary"])) { + if (!(typeof data["$vocabulary"][key3] === "boolean")) return false + } + } + if (data["$comment"] !== undefined && hasOwn(data, "$comment")) { + if (!(typeof data["$comment"] === "string")) return false + } + if (data["$defs"] !== undefined && hasOwn(data, "$defs")) { + if (!(typeof data["$defs"] === "object" && data["$defs"] && !Array.isArray(data["$defs"]))) return false + for (const key4 of Object.keys(data["$defs"])) { + if (!(dynamicResolve(dynAnchors || [], "#meta") || validate)(data["$defs"][key4], [...dynAnchors, dynLocal[0] || []])) return false + } + } + } + return true +}; +const ref8 = function validate(data, dynAnchors) { + if (!Array.isArray(data)) return false + if (data.length < 1) return false + for (let j = 0; j < data.length; j++) { + if (data[j] !== undefined && hasOwn(data, j)) { + if (!(dynamicResolve(dynAnchors || [], "#meta") || ref7)(data[j], dynAnchors)) return false + } + } + return true +}; +const format2 = (str) => { + if (str.length > 1e5) return false + const Z_ANCHOR = /[^\\]\\Z/ + if (Z_ANCHOR.test(str)) return false + try { + new RegExp(str, 'u') + return true + } catch (e) { + return false + } + }; +const ref7 = function validate(data, dynAnchors = []) { + const dynLocal = [{}] + dynLocal[0]["#meta"] = validate + if (!(typeof data === "object" && data && !Array.isArray(data) || typeof data === "boolean")) return false + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.prefixItems !== undefined && hasOwn(data, "prefixItems")) { + if (!ref8(data.prefixItems, [...dynAnchors, dynLocal[0] || []])) return false + } + if (data.items !== undefined && hasOwn(data, "items")) { + if (!(dynamicResolve(dynAnchors || [], "#meta") || validate)(data.items, [...dynAnchors, dynLocal[0] || []])) return false + } + if (data.contains !== undefined && hasOwn(data, "contains")) { + if (!(dynamicResolve(dynAnchors || [], "#meta") || validate)(data.contains, [...dynAnchors, dynLocal[0] || []])) return false + } + if (data.additionalProperties !== undefined && hasOwn(data, "additionalProperties")) { + if (!(dynamicResolve(dynAnchors || [], "#meta") || validate)(data.additionalProperties, [...dynAnchors, dynLocal[0] || []])) return false + } + if (data.properties !== undefined && hasOwn(data, "properties")) { + if (!(typeof data.properties === "object" && data.properties && !Array.isArray(data.properties))) return false + for (const key5 of Object.keys(data.properties)) { + if (!(dynamicResolve(dynAnchors || [], "#meta") || validate)(data.properties[key5], [...dynAnchors, dynLocal[0] || []])) return false + } + } + if (data.patternProperties !== undefined && hasOwn(data, "patternProperties")) { + if (!(typeof data.patternProperties === "object" && data.patternProperties && !Array.isArray(data.patternProperties))) return false + for (const key6 of Object.keys(data.patternProperties)) { + if (!format2(key6)) return false + } + for (const key7 of Object.keys(data.patternProperties)) { + if (!(dynamicResolve(dynAnchors || [], "#meta") || validate)(data.patternProperties[key7], [...dynAnchors, dynLocal[0] || []])) return false + } + } + if (data.dependentSchemas !== undefined && hasOwn(data, "dependentSchemas")) { + if (!(typeof data.dependentSchemas === "object" && data.dependentSchemas && !Array.isArray(data.dependentSchemas))) return false + for (const key8 of Object.keys(data.dependentSchemas)) { + if (!(dynamicResolve(dynAnchors || [], "#meta") || validate)(data.dependentSchemas[key8], [...dynAnchors, dynLocal[0] || []])) return false + } + } + if (data.propertyNames !== undefined && hasOwn(data, "propertyNames")) { + if (!(dynamicResolve(dynAnchors || [], "#meta") || validate)(data.propertyNames, [...dynAnchors, dynLocal[0] || []])) return false + } + if (data.if !== undefined && hasOwn(data, "if")) { + if (!(dynamicResolve(dynAnchors || [], "#meta") || validate)(data.if, [...dynAnchors, dynLocal[0] || []])) return false + } + if (data.then !== undefined && hasOwn(data, "then")) { + if (!(dynamicResolve(dynAnchors || [], "#meta") || validate)(data.then, [...dynAnchors, dynLocal[0] || []])) return false + } + if (data.else !== undefined && hasOwn(data, "else")) { + if (!(dynamicResolve(dynAnchors || [], "#meta") || validate)(data.else, [...dynAnchors, dynLocal[0] || []])) return false + } + if (data.allOf !== undefined && hasOwn(data, "allOf")) { + if (!ref8(data.allOf, [...dynAnchors, dynLocal[0] || []])) return false + } + if (data.anyOf !== undefined && hasOwn(data, "anyOf")) { + if (!ref8(data.anyOf, [...dynAnchors, dynLocal[0] || []])) return false + } + if (data.oneOf !== undefined && hasOwn(data, "oneOf")) { + if (!ref8(data.oneOf, [...dynAnchors, dynLocal[0] || []])) return false + } + if (data.not !== undefined && hasOwn(data, "not")) { + if (!(dynamicResolve(dynAnchors || [], "#meta") || validate)(data.not, [...dynAnchors, dynLocal[0] || []])) return false + } + } + return true +}; +const ref9 = function validate(data, dynAnchors = []) { + const dynLocal = [{}] + dynLocal[0]["#meta"] = validate + if (!(typeof data === "object" && data && !Array.isArray(data) || typeof data === "boolean")) return false + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.unevaluatedItems !== undefined && hasOwn(data, "unevaluatedItems")) { + if (!(dynamicResolve(dynAnchors || [], "#meta") || validate)(data.unevaluatedItems, [...dynAnchors, dynLocal[0] || []])) return false + } + if (data.unevaluatedProperties !== undefined && hasOwn(data, "unevaluatedProperties")) { + if (!(dynamicResolve(dynAnchors || [], "#meta") || validate)(data.unevaluatedProperties, [...dynAnchors, dynLocal[0] || []])) return false + } + } + return true +}; +const ref11 = function validate(data, dynAnchors) { + if (!(data === "array" || data === "boolean" || data === "integer" || data === "null" || data === "number" || data === "object" || data === "string")) return false + return true +}; +const ref12 = function validate(data, dynAnchors) { + if (!Number.isInteger(data)) return false + if (!(0 <= data)) return false + return true +}; +const ref13 = function validate(data, dynAnchors) { + if (!ref12(data, dynAnchors)) return false + return true +}; +const ref10 = function validate(data, dynAnchors = []) { + const dynLocal = [{}] + dynLocal[0]["#meta"] = validate + if (!(typeof data === "object" && data && !Array.isArray(data) || typeof data === "boolean")) return false + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.type !== undefined && hasOwn(data, "type")) { + const sub2 = (() => { + if (!ref11(data.type, [...dynAnchors, dynLocal[0] || []])) return false + return true + })() + if (!sub2) { + const sub3 = (() => { + if (!Array.isArray(data.type)) return false + if (data.type.length < 1) return false + for (let k = 0; k < data.type.length; k++) { + if (data.type[k] !== undefined && hasOwn(data.type, k)) { + if (!ref11(data.type[k], [...dynAnchors, dynLocal[0] || []])) return false + } + } + if (!unique(data.type)) return false + return true + })() + if (!sub3) return false + } + } + if (data.enum !== undefined && hasOwn(data, "enum")) { + if (!Array.isArray(data.enum)) return false + } + if (data.multipleOf !== undefined && hasOwn(data, "multipleOf")) { + if (!(typeof data.multipleOf === "number")) return false + if (!(0 < data.multipleOf)) return false + } + if (data.maximum !== undefined && hasOwn(data, "maximum")) { + if (!(typeof data.maximum === "number")) return false + } + if (data.exclusiveMaximum !== undefined && hasOwn(data, "exclusiveMaximum")) { + if (!(typeof data.exclusiveMaximum === "number")) return false + } + if (data.minimum !== undefined && hasOwn(data, "minimum")) { + if (!(typeof data.minimum === "number")) return false + } + if (data.exclusiveMinimum !== undefined && hasOwn(data, "exclusiveMinimum")) { + if (!(typeof data.exclusiveMinimum === "number")) return false + } + if (data.maxLength !== undefined && hasOwn(data, "maxLength")) { + if (!ref12(data.maxLength, [...dynAnchors, dynLocal[0] || []])) return false + } + if (data.minLength !== undefined && hasOwn(data, "minLength")) { + if (!ref13(data.minLength, [...dynAnchors, dynLocal[0] || []])) return false + } + if (data.pattern !== undefined && hasOwn(data, "pattern")) { + if (!(typeof data.pattern === "string")) return false + if (!format2(data.pattern)) return false + } + if (data.maxItems !== undefined && hasOwn(data, "maxItems")) { + if (!ref12(data.maxItems, [...dynAnchors, dynLocal[0] || []])) return false + } + if (data.minItems !== undefined && hasOwn(data, "minItems")) { + if (!ref13(data.minItems, [...dynAnchors, dynLocal[0] || []])) return false + } + if (data.uniqueItems !== undefined && hasOwn(data, "uniqueItems")) { + if (!(typeof data.uniqueItems === "boolean")) return false + } + if (data.maxContains !== undefined && hasOwn(data, "maxContains")) { + if (!ref12(data.maxContains, [...dynAnchors, dynLocal[0] || []])) return false + } + if (data.minContains !== undefined && hasOwn(data, "minContains")) { + if (!ref12(data.minContains, [...dynAnchors, dynLocal[0] || []])) return false + } + if (data.maxProperties !== undefined && hasOwn(data, "maxProperties")) { + if (!ref12(data.maxProperties, [...dynAnchors, dynLocal[0] || []])) return false + } + if (data.minProperties !== undefined && hasOwn(data, "minProperties")) { + if (!ref13(data.minProperties, [...dynAnchors, dynLocal[0] || []])) return false + } + if (data.required !== undefined && hasOwn(data, "required")) { + if (!ref2(data.required, [...dynAnchors, dynLocal[0] || []])) return false + } + if (data.dependentRequired !== undefined && hasOwn(data, "dependentRequired")) { + if (!(typeof data.dependentRequired === "object" && data.dependentRequired && !Array.isArray(data.dependentRequired))) return false + for (const key9 of Object.keys(data.dependentRequired)) { + if (!ref2(data.dependentRequired[key9], [...dynAnchors, dynLocal[0] || []])) return false + } + } + } + return true +}; +const ref14 = function validate(data, dynAnchors) { + if (!(typeof data === "object" && data && !Array.isArray(data) || typeof data === "boolean")) return false + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.title !== undefined && hasOwn(data, "title")) { + if (!(typeof data.title === "string")) return false + } + if (data.description !== undefined && hasOwn(data, "description")) { + if (!(typeof data.description === "string")) return false + } + if (data.deprecated !== undefined && hasOwn(data, "deprecated")) { + if (!(typeof data.deprecated === "boolean")) return false + } + if (data.readOnly !== undefined && hasOwn(data, "readOnly")) { + if (!(typeof data.readOnly === "boolean")) return false + } + if (data.writeOnly !== undefined && hasOwn(data, "writeOnly")) { + if (!(typeof data.writeOnly === "boolean")) return false + } + if (data.examples !== undefined && hasOwn(data, "examples")) { + if (!Array.isArray(data.examples)) return false + } + } + return true +}; +const ref15 = function validate(data, dynAnchors) { + if (!(typeof data === "object" && data && !Array.isArray(data) || typeof data === "boolean")) return false + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.format !== undefined && hasOwn(data, "format")) { + if (!(typeof data.format === "string")) return false + } + } + return true +}; +const ref16 = function validate(data, dynAnchors = []) { + const dynLocal = [{}] + dynLocal[0]["#meta"] = validate + if (!(typeof data === "object" && data && !Array.isArray(data) || typeof data === "boolean")) return false + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.contentEncoding !== undefined && hasOwn(data, "contentEncoding")) { + if (!(typeof data.contentEncoding === "string")) return false + } + if (data.contentMediaType !== undefined && hasOwn(data, "contentMediaType")) { + if (!(typeof data.contentMediaType === "string")) return false + } + if (data.contentSchema !== undefined && hasOwn(data, "contentSchema")) { + if (!(dynamicResolve(dynAnchors || [], "#meta") || validate)(data.contentSchema, [...dynAnchors, dynLocal[0] || []])) return false + } + } + return true +}; +const ref1 = function validate(data, dynAnchors = []) { + const dynLocal = [{}] + dynLocal[0]["#meta"] = validate + if (!(typeof data === "object" && data && !Array.isArray(data) || typeof data === "boolean")) return false + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.definitions !== undefined && hasOwn(data, "definitions")) { + if (!(typeof data.definitions === "object" && data.definitions && !Array.isArray(data.definitions))) return false + for (const key0 of Object.keys(data.definitions)) { + if (!(dynamicResolve(dynAnchors || [], "#meta") || validate)(data.definitions[key0], [...dynAnchors, dynLocal[0] || []])) return false + } + } + if (data.dependencies !== undefined && hasOwn(data, "dependencies")) { + if (!(typeof data.dependencies === "object" && data.dependencies && !Array.isArray(data.dependencies))) return false + for (const key1 of Object.keys(data.dependencies)) { + const sub0 = (() => { + if (!(dynamicResolve(dynAnchors || [], "#meta") || validate)(data.dependencies[key1], [...dynAnchors, dynLocal[0] || []])) return false + return true + })() + if (!sub0) { + const sub1 = (() => { + if (!ref2(data.dependencies[key1], [...dynAnchors, dynLocal[0] || []])) return false + return true + })() + if (!sub1) return false + } + } + } + if (data["$recursiveAnchor"] !== undefined && hasOwn(data, "$recursiveAnchor")) { + if (!ref3(data["$recursiveAnchor"], [...dynAnchors, dynLocal[0] || []])) return false + } + if (data["$recursiveRef"] !== undefined && hasOwn(data, "$recursiveRef")) { + if (!ref4(data["$recursiveRef"], [...dynAnchors, dynLocal[0] || []])) return false + } + } + if (!ref5(data, [...dynAnchors, dynLocal[0] || []])) return false + if (!ref7(data, [...dynAnchors, dynLocal[0] || []])) return false + if (!ref9(data, [...dynAnchors, dynLocal[0] || []])) return false + if (!ref10(data, [...dynAnchors, dynLocal[0] || []])) return false + if (!ref14(data, [...dynAnchors, dynLocal[0] || []])) return false + if (!ref15(data, [...dynAnchors, dynLocal[0] || []])) return false + if (!ref16(data, [...dynAnchors, dynLocal[0] || []])) return false + return true +}; +const ref0 = function validate(data, dynAnchors) { + if (!ref1(data, dynAnchors)) return false + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at https://json-schema.org/draft/next/schema#/properties/definitions/additionalProperties` + + +## $id inside an enum is not a real identifier + +### Schema + +```json +{ + "$defs": { + "id_in_enum": { + "enum": [ + { + "$id": "https://localhost:1234/draft-next/id/my_identifier.json", + "type": "null" + } + ] + }, + "real_id_in_schema": { + "$id": "https://localhost:1234/draft-next/id/my_identifier.json", + "type": "string" + }, + "zzz_id_in_const": { + "const": { + "$id": "https://localhost:1234/draft-next/id/my_identifier.json", + "type": "null" + } + } + }, + "anyOf": [ + { "$ref": "#/$defs/id_in_enum" }, + { "$ref": "https://localhost:1234/draft-next/id/my_identifier.json" } + ] +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref1 = function validate(data) { + if (!(typeof data === "object" && data && !Array.isArray(data) && Object.keys(data).length === 2 && hasOwn(data, "$id") && hasOwn(data, "type") && data["$id"] === "https://localhost:1234/draft-next/id/my_identifier.json" && data["type"] === "null")) return false + return true +}; +const ref2 = function validate(data) { + if (!(typeof data === "string")) return false + return true +}; +const ref0 = function validate(data) { + const sub0 = (() => { + if (!ref1(data)) return false + return true + })() + if (!sub0) { + const sub1 = (() => { + if (!ref2(data)) return false + return true + })() + if (!sub1) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireStringValidation] pattern, format or contentSchema should be specified for strings, use pattern: ^[\s\S]*$ to opt-out at #` + + +## non-schema object containing an $id property + +### Schema + +```json +{ + "$defs": { "const_not_id": { "const": { "$id": "not_a_real_id" } } }, + "if": { "const": "skip not_a_real_id" }, + "then": true, + "else": { "$ref": "#/$defs/const_not_id" } +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref1 = function validate(data) { + if (!(typeof data === "object" && data && !Array.isArray(data) && Object.keys(data).length === 1 && hasOwn(data, "$id") && data["$id"] === "not_a_real_id")) return false + return true +}; +const ref0 = function validate(data) { + const sub0 = (() => { + if (!(data === "skip not_a_real_id")) return false + return true + })() + if (!sub0) { + if (!ref1(data)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] schema = true is not allowed at #/then` + diff --git a/doc/samples/draft-next/if-then-else.md b/doc/samples/draft-next/if-then-else.md new file mode 100644 index 0000000..836d8cb --- /dev/null +++ b/doc/samples/draft-next/if-then-else.md @@ -0,0 +1,305 @@ +# if-then-else + +## ignore if without then or else + +### Schema + +```json +{ "if": { "const": 0 } } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + const sub0 = (() => { + if (!(data === 0)) return false + return true + })() + return true +}; +return ref0 +``` + +### Warnings + + * `Unprocessed keywords: ["if"] at #` + + +## ignore then without if + +### Schema + +```json +{ "then": { "const": 0 } } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + return true +}; +return ref0 +``` + +### Warnings + + * `Unprocessed keywords: ["then"] at #` + + +## ignore else without if + +### Schema + +```json +{ "else": { "const": 0 } } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + return true +}; +return ref0 +``` + +### Warnings + + * `Unprocessed keywords: ["else"] at #` + + +## if and then without else + +### Schema + +```json +{ "if": { "exclusiveMaximum": 0 }, "then": { "minimum": -10 } } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + const sub0 = (() => { + if (typeof data === "number") { + if (!(0 > data)) return false + } + return true + })() + if (sub0) { + if (typeof data === "number") { + if (!(-10 <= data)) return false + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## if and else without then + +### Schema + +```json +{ "if": { "exclusiveMaximum": 0 }, "else": { "multipleOf": 2 } } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + const sub0 = (() => { + if (typeof data === "number") { + if (!(0 > data)) return false + } + return true + })() + if (!sub0) { + if (typeof data === "number") { + if (data % 2 !== 0) return false + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## validate against correct branch, then vs else + +### Schema + +```json +{ + "if": { "exclusiveMaximum": 0 }, + "then": { "minimum": -10 }, + "else": { "multipleOf": 2 } +} +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + const sub0 = (() => { + if (typeof data === "number") { + if (!(0 > data)) return false + } + return true + })() + if (sub0) { + if (typeof data === "number") { + if (!(-10 <= data)) return false + } + } + else { + if (typeof data === "number") { + if (data % 2 !== 0) return false + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## non-interference across combined schemas + +### Schema + +```json +{ + "allOf": [ + { "if": { "exclusiveMaximum": 0 } }, + { "then": { "minimum": -10 } }, + { "else": { "multipleOf": 2 } } + ] +} +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + const sub0 = (() => { + if (typeof data === "number") { + if (!(0 > data)) return false + } + return true + })() + return true +}; +return ref0 +``` + +### Warnings + + * `Unprocessed keywords: ["if"] at #/allOf/0` + + +## if with boolean schema true + +### Schema + +```json +{ "if": true, "then": { "const": "then" }, "else": { "const": "else" } } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (!(data === "then")) return false + return true +}; +return ref0 +``` + +### Warnings + + * `some checks are never reachable at #` + + +## if with boolean schema false + +### Schema + +```json +{ "if": false, "then": { "const": "then" }, "else": { "const": "else" } } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (!(data === "else")) return false + return true +}; +return ref0 +``` + +### Warnings + + * `some checks are never reachable at #` + + +## if appears at the end when serialized (keyword processing sequence) + +### Schema + +```json +{ + "then": { "const": "yes" }, + "else": { "const": "other" }, + "if": { "maxLength": 4 } +} +``` + +### Code + +```js +'use strict' +const stringLength = (string) => + /[\uD800-\uDFFF]/.test(string) ? [...string].length : string.length; +const ref0 = function validate(data) { + const sub0 = (() => { + if (typeof data === "string") { + if (data.length > 4 && stringLength(data) > 4) return false + } + return true + })() + if (sub0) { + if (!(data === "yes")) return false + } + else { + if (!(data === "other")) return false + } + return true +}; +return ref0 +``` + diff --git a/doc/samples/draft-next/infinite-loop-detection.md b/doc/samples/draft-next/infinite-loop-detection.md new file mode 100644 index 0000000..df67854 --- /dev/null +++ b/doc/samples/draft-next/infinite-loop-detection.md @@ -0,0 +1,45 @@ +# infinite-loop-detection + +## evaluating the same schema location against the same data location twice is not a sign of an infinite loop + +### Schema + +```json +{ + "$defs": { "int": { "type": "integer" } }, + "allOf": [ + { "properties": { "foo": { "$ref": "#/$defs/int" } } }, + { "additionalProperties": { "$ref": "#/$defs/int" } } + ] +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref1 = function validate(data) { + if (!Number.isInteger(data)) return false + return true +}; +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.foo !== undefined && hasOwn(data, "foo")) { + if (!ref1(data.foo)) return false + } + } + if (typeof data === "object" && data && !Array.isArray(data)) { + for (const key0 of Object.keys(data)) { + if (!ref1(data[key0])) return false + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] if properties is used, required should be specified at #/allOf/0` + diff --git a/doc/samples/draft-next/items.md b/doc/samples/draft-next/items.md new file mode 100644 index 0000000..129cff0 --- /dev/null +++ b/doc/samples/draft-next/items.md @@ -0,0 +1,332 @@ +# items + +## a schema given for items + +### Schema + +```json +{ "items": { "type": "integer" } } +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (Array.isArray(data)) { + for (let i = 0; i < data.length; i++) { + if (data[i] !== undefined && hasOwn(data, i)) { + if (!(Number.isInteger(data[i]))) return false + } + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## items with boolean schema (true) + +### Schema + +```json +{ "items": true } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] schema = true is not allowed at #/items` + + +## items with boolean schema (false) + +### Schema + +```json +{ "items": false } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (Array.isArray(data)) { + if (data.length > 0) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## items and subitems + +### Schema + +```json +{ + "$defs": { + "item": { + "type": "array", + "items": false, + "prefixItems": [ + { "$ref": "#/$defs/sub-item" }, + { "$ref": "#/$defs/sub-item" } + ] + }, + "sub-item": { "type": "object", "required": ["foo"] } + }, + "type": "array", + "items": false, + "prefixItems": [ + { "$ref": "#/$defs/item" }, + { "$ref": "#/$defs/item" }, + { "$ref": "#/$defs/item" } + ] +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref2 = function validate(data) { + if (!(typeof data === "object" && data && !Array.isArray(data))) return false + if (!(data.foo !== undefined && hasOwn(data, "foo"))) return false + return true +}; +const ref1 = function validate(data) { + if (!Array.isArray(data)) return false + if (data[0] !== undefined && hasOwn(data, 0)) { + if (!ref2(data[0])) return false + } + if (data[1] !== undefined && hasOwn(data, 1)) { + if (!ref2(data[1])) return false + } + if (data.length > 2) return false + return true +}; +const ref0 = function validate(data) { + if (!Array.isArray(data)) return false + if (data[0] !== undefined && hasOwn(data, 0)) { + if (!ref1(data[0])) return false + } + if (data[1] !== undefined && hasOwn(data, 1)) { + if (!ref1(data[1])) return false + } + if (data[2] !== undefined && hasOwn(data, 2)) { + if (!ref1(data[2])) return false + } + if (data.length > 3) return false + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] additionalProperties or unevaluatedProperties should be specified at #` + + +## nested items + +### Schema + +```json +{ + "type": "array", + "items": { + "type": "array", + "items": { + "type": "array", + "items": { "type": "array", "items": { "type": "number" } } + } + } +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (!Array.isArray(data)) return false + for (let i = 0; i < data.length; i++) { + if (data[i] !== undefined && hasOwn(data, i)) { + if (!(Array.isArray(data[i]))) return false + for (let j = 0; j < data[i].length; j++) { + if (data[i][j] !== undefined && hasOwn(data[i], j)) { + if (!(Array.isArray(data[i][j]))) return false + for (let k = 0; k < data[i][j].length; k++) { + if (data[i][j][k] !== undefined && hasOwn(data[i][j], k)) { + if (!(Array.isArray(data[i][j][k]))) return false + for (let l = 0; l < data[i][j][k].length; l++) { + if (data[i][j][k][l] !== undefined && hasOwn(data[i][j][k], l)) { + if (!(typeof data[i][j][k][l] === "number")) return false + } + } + } + } + } + } + } + } + return true +}; +return ref0 +``` + + +## prefixItems with no additional items allowed + +### Schema + +```json +{ "prefixItems": [{}, {}, {}], "items": false } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (Array.isArray(data)) { + if (data.length > 3) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] empty rules node is not allowed at #/0` + + +## items does not look in applicators, valid case + +### Schema + +```json +{ "allOf": [{ "prefixItems": [{ "minimum": 3 }] }], "items": { "minimum": 5 } } +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (Array.isArray(data)) { + for (let i = 0; i < data.length; i++) { + if (data[i] !== undefined && hasOwn(data, i)) { + if (typeof data[i] === "number") { + if (!(5 <= data[i])) return false + } + } + } + } + if (Array.isArray(data)) { + if (data[0] !== undefined && hasOwn(data, 0)) { + if (typeof data[0] === "number") { + if (!(3 <= data[0])) return false + } + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #/items` + + +## prefixItems validation adjusts the starting index for items + +### Schema + +```json +{ "prefixItems": [{ "type": "string" }], "items": { "type": "integer" } } +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (Array.isArray(data)) { + if (data[0] !== undefined && hasOwn(data, 0)) { + if (!(typeof data[0] === "string")) return false + } + for (let i = 1; i < data.length; i++) { + if (data[i] !== undefined && hasOwn(data, i)) { + if (!(Number.isInteger(data[i]))) return false + } + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireStringValidation] pattern, format or contentSchema should be specified for strings, use pattern: ^[\s\S]*$ to opt-out at #/0` + + +## items with null instance elements + +### Schema + +```json +{ "items": { "type": "null" } } +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (Array.isArray(data)) { + for (let i = 0; i < data.length; i++) { + if (data[i] !== undefined && hasOwn(data, i)) { + if (!(data[i] === null)) return false + } + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + diff --git a/doc/samples/draft-next/maxContains.md b/doc/samples/draft-next/maxContains.md new file mode 100644 index 0000000..80215df --- /dev/null +++ b/doc/samples/draft-next/maxContains.md @@ -0,0 +1,146 @@ +# maxContains + +## maxContains without contains is ignored + +### Schema + +```json +{ "maxContains": 1 } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + return true +}; +return ref0 +``` + +### Warnings + + * `Unprocessed keywords: ["maxContains"] at #` + + +## maxContains with contains + +### Schema + +```json +{ "contains": { "const": 1 }, "maxContains": 1 } +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (Array.isArray(data)) { + let passes0 = 0 + for (let i = 0; i < data.length; i++) { + const sub0 = (() => { + if (data[i] !== undefined && hasOwn(data, i)) { + if (!(data[i] === 1)) return false + } + return true + })() + if (sub0) passes0++ + } + if (passes0 < 1) return false + if (passes0 > 1) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + +### Misclassified! + +**This schema caused 3 misclassifications!** + + +## maxContains with contains, value with a decimal + +### Schema + +```json +{ "contains": { "const": 1 }, "maxContains": 1 } +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (Array.isArray(data)) { + let passes0 = 0 + for (let i = 0; i < data.length; i++) { + const sub0 = (() => { + if (data[i] !== undefined && hasOwn(data, i)) { + if (!(data[i] === 1)) return false + } + return true + })() + if (sub0) passes0++ + } + if (passes0 < 1) return false + if (passes0 > 1) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## minContains < maxContains + +### Schema + +```json +{ "contains": { "const": 1 }, "minContains": 1, "maxContains": 3 } +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (Array.isArray(data)) { + let passes0 = 0 + for (let i = 0; i < data.length; i++) { + const sub0 = (() => { + if (data[i] !== undefined && hasOwn(data, i)) { + if (!(data[i] === 1)) return false + } + return true + })() + if (sub0) passes0++ + } + if (passes0 < 1) return false + if (passes0 > 3) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + +### Misclassified! + +**This schema caused 2 misclassifications!** + diff --git a/doc/samples/draft-next/maxItems.md b/doc/samples/draft-next/maxItems.md new file mode 100644 index 0000000..42c80fd --- /dev/null +++ b/doc/samples/draft-next/maxItems.md @@ -0,0 +1,53 @@ +# maxItems + +## maxItems validation + +### Schema + +```json +{ "maxItems": 2 } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (Array.isArray(data)) { + if (data.length > 2) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## maxItems validation with a decimal + +### Schema + +```json +{ "maxItems": 2 } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (Array.isArray(data)) { + if (data.length > 2) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + diff --git a/doc/samples/draft-next/maxLength.md b/doc/samples/draft-next/maxLength.md new file mode 100644 index 0000000..6f2f147 --- /dev/null +++ b/doc/samples/draft-next/maxLength.md @@ -0,0 +1,57 @@ +# maxLength + +## maxLength validation + +### Schema + +```json +{ "maxLength": 2 } +``` + +### Code + +```js +'use strict' +const stringLength = (string) => + /[\uD800-\uDFFF]/.test(string) ? [...string].length : string.length; +const ref0 = function validate(data) { + if (typeof data === "string") { + if (data.length > 2 && stringLength(data) > 2) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## maxLength validation with a decimal + +### Schema + +```json +{ "maxLength": 2 } +``` + +### Code + +```js +'use strict' +const stringLength = (string) => + /[\uD800-\uDFFF]/.test(string) ? [...string].length : string.length; +const ref0 = function validate(data) { + if (typeof data === "string") { + if (data.length > 2 && stringLength(data) > 2) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + diff --git a/doc/samples/draft-next/maxProperties.md b/doc/samples/draft-next/maxProperties.md new file mode 100644 index 0000000..d085599 --- /dev/null +++ b/doc/samples/draft-next/maxProperties.md @@ -0,0 +1,79 @@ +# maxProperties + +## maxProperties validation + +### Schema + +```json +{ "maxProperties": 2 } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (Object.keys(data).length > 2) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## maxProperties validation with a decimal + +### Schema + +```json +{ "maxProperties": 2 } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (Object.keys(data).length > 2) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## maxProperties = 0 means the object is empty + +### Schema + +```json +{ "maxProperties": 0 } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (Object.keys(data).length > 0) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + diff --git a/doc/samples/draft-next/maximum.md b/doc/samples/draft-next/maximum.md new file mode 100644 index 0000000..47de30e --- /dev/null +++ b/doc/samples/draft-next/maximum.md @@ -0,0 +1,53 @@ +# maximum + +## maximum validation + +### Schema + +```json +{ "maximum": 3 } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (typeof data === "number") { + if (!(3 >= data)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## maximum validation with unsigned integer + +### Schema + +```json +{ "maximum": 300 } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (typeof data === "number") { + if (!(300 >= data)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + diff --git a/doc/samples/draft-next/minContains.md b/doc/samples/draft-next/minContains.md new file mode 100644 index 0000000..f1548c9 --- /dev/null +++ b/doc/samples/draft-next/minContains.md @@ -0,0 +1,286 @@ +# minContains + +## minContains without contains is ignored + +### Schema + +```json +{ "minContains": 1 } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + return true +}; +return ref0 +``` + +### Warnings + + * `Unprocessed keywords: ["minContains"] at #` + + +## minContains=1 with contains + +### Schema + +```json +{ "contains": { "const": 1 }, "minContains": 1 } +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (Array.isArray(data)) { + let passes0 = 0 + for (let i = 0; i < data.length; i++) { + const sub0 = (() => { + if (data[i] !== undefined && hasOwn(data, i)) { + if (!(data[i] === 1)) return false + } + return true + })() + if (sub0) passes0++ + } + if (passes0 < 1) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## minContains=2 with contains + +### Schema + +```json +{ "contains": { "const": 1 }, "minContains": 2 } +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (Array.isArray(data)) { + let passes0 = 0 + for (let i = 0; i < data.length; i++) { + const sub0 = (() => { + if (data[i] !== undefined && hasOwn(data, i)) { + if (!(data[i] === 1)) return false + } + return true + })() + if (sub0) passes0++ + } + if (passes0 < 2) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## minContains=2 with contains with a decimal value + +### Schema + +```json +{ "contains": { "const": 1 }, "minContains": 2 } +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (Array.isArray(data)) { + let passes0 = 0 + for (let i = 0; i < data.length; i++) { + const sub0 = (() => { + if (data[i] !== undefined && hasOwn(data, i)) { + if (!(data[i] === 1)) return false + } + return true + })() + if (sub0) passes0++ + } + if (passes0 < 2) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## maxContains = minContains + +### Schema + +```json +{ "contains": { "const": 1 }, "maxContains": 2, "minContains": 2 } +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (Array.isArray(data)) { + let passes0 = 0 + for (let i = 0; i < data.length; i++) { + const sub0 = (() => { + if (data[i] !== undefined && hasOwn(data, i)) { + if (!(data[i] === 1)) return false + } + return true + })() + if (sub0) passes0++ + } + if (passes0 < 2) return false + if (passes0 > 2) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## maxContains < minContains + +### Schema + +```json +{ "contains": { "const": 1 }, "maxContains": 1, "minContains": 3 } +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (Array.isArray(data)) { + let passes0 = 0 + for (let i = 0; i < data.length; i++) { + const sub0 = (() => { + if (data[i] !== undefined && hasOwn(data, i)) { + if (!(data[i] === 1)) return false + } + return true + })() + if (sub0) passes0++ + } + if (passes0 < 3) return false + if (passes0 > 1) return false + } + return true +}; +return ref0 +``` + +### Warnings + + * `Invalid minContains / maxContains combination at #` + + +## minContains = 0 + +### Schema + +```json +{ "contains": { "const": 1 }, "minContains": 0 } +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (Array.isArray(data)) { + let passes0 = 0 + for (let i = 0; i < data.length; i++) { + const sub0 = (() => { + if (data[i] !== undefined && hasOwn(data, i)) { + if (!(data[i] === 1)) return false + } + return true + })() + if (sub0) passes0++ + } + if (passes0 < 0) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## minContains = 0 with maxContains + +### Schema + +```json +{ "contains": { "const": 1 }, "minContains": 0, "maxContains": 1 } +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (Array.isArray(data)) { + let passes0 = 0 + for (let i = 0; i < data.length; i++) { + const sub0 = (() => { + if (data[i] !== undefined && hasOwn(data, i)) { + if (!(data[i] === 1)) return false + } + return true + })() + if (sub0) passes0++ + } + if (passes0 < 0) return false + if (passes0 > 1) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + diff --git a/doc/samples/draft-next/minItems.md b/doc/samples/draft-next/minItems.md new file mode 100644 index 0000000..faaa676 --- /dev/null +++ b/doc/samples/draft-next/minItems.md @@ -0,0 +1,53 @@ +# minItems + +## minItems validation + +### Schema + +```json +{ "minItems": 1 } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (Array.isArray(data)) { + if (data.length < 1) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## minItems validation with a decimal + +### Schema + +```json +{ "minItems": 1 } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (Array.isArray(data)) { + if (data.length < 1) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + diff --git a/doc/samples/draft-next/minLength.md b/doc/samples/draft-next/minLength.md new file mode 100644 index 0000000..9e7f30c --- /dev/null +++ b/doc/samples/draft-next/minLength.md @@ -0,0 +1,57 @@ +# minLength + +## minLength validation + +### Schema + +```json +{ "minLength": 2 } +``` + +### Code + +```js +'use strict' +const stringLength = (string) => + /[\uD800-\uDFFF]/.test(string) ? [...string].length : string.length; +const ref0 = function validate(data) { + if (typeof data === "string") { + if (data.length < 2 || stringLength(data) < 2) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## minLength validation with a decimal + +### Schema + +```json +{ "minLength": 2 } +``` + +### Code + +```js +'use strict' +const stringLength = (string) => + /[\uD800-\uDFFF]/.test(string) ? [...string].length : string.length; +const ref0 = function validate(data) { + if (typeof data === "string") { + if (data.length < 2 || stringLength(data) < 2) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + diff --git a/doc/samples/draft-next/minProperties.md b/doc/samples/draft-next/minProperties.md new file mode 100644 index 0000000..072a920 --- /dev/null +++ b/doc/samples/draft-next/minProperties.md @@ -0,0 +1,53 @@ +# minProperties + +## minProperties validation + +### Schema + +```json +{ "minProperties": 1 } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (Object.keys(data).length < 1) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## minProperties validation with a decimal + +### Schema + +```json +{ "minProperties": 1 } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (Object.keys(data).length < 1) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + diff --git a/doc/samples/draft-next/minimum.md b/doc/samples/draft-next/minimum.md new file mode 100644 index 0000000..7adc25c --- /dev/null +++ b/doc/samples/draft-next/minimum.md @@ -0,0 +1,53 @@ +# minimum + +## minimum validation + +### Schema + +```json +{ "minimum": 1.1 } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (typeof data === "number") { + if (!(1.1 <= data)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## minimum validation with signed integer + +### Schema + +```json +{ "minimum": -2 } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (typeof data === "number") { + if (!(-2 <= data)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + diff --git a/doc/samples/draft-next/multipleOf.md b/doc/samples/draft-next/multipleOf.md new file mode 100644 index 0000000..f56f9b8 --- /dev/null +++ b/doc/samples/draft-next/multipleOf.md @@ -0,0 +1,116 @@ +# multipleOf + +## by int + +### Schema + +```json +{ "multipleOf": 2 } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (typeof data === "number") { + if (data % 2 !== 0) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## by number + +### Schema + +```json +{ "multipleOf": 1.5 } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (typeof data === "number") { + if (data % 1.5 !== 0) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## by small number + +### Schema + +```json +{ "multipleOf": 0.0001 } +``` + +### Code + +```js +'use strict' +const isMultipleOf = (value, divisor, factor, factorMultiple) => { + if (value % divisor === 0) return true + let multiple = value * factor + if (multiple === Infinity || multiple === -Infinity) multiple = value + if (multiple % factorMultiple === 0) return true + const normal = Math.floor(multiple + 0.5) + return normal / factor === value && normal % factorMultiple === 0 +}; +const ref0 = function validate(data) { + if (typeof data === "number") { + if (!isMultipleOf(data, 0.0001, 1e4, 1)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## float division = inf + +### Schema + +```json +{ "type": "integer", "multipleOf": 0.123456789 } +``` + +### Code + +```js +'use strict' +const isMultipleOf = (value, divisor, factor, factorMultiple) => { + if (value % divisor === 0) return true + let multiple = value * factor + if (multiple === Infinity || multiple === -Infinity) multiple = value + if (multiple % factorMultiple === 0) return true + const normal = Math.floor(multiple + 0.5) + return normal / factor === value && normal % factorMultiple === 0 +}; +const ref0 = function validate(data) { + if (!Number.isInteger(data)) return false + if (!isMultipleOf(data, 0.123456789, 1e9, 123456789)) return false + return true +}; +return ref0 +``` + diff --git a/doc/samples/draft-next/not.md b/doc/samples/draft-next/not.md new file mode 100644 index 0000000..ba5ee57 --- /dev/null +++ b/doc/samples/draft-next/not.md @@ -0,0 +1,163 @@ +# not + +## not + +### Schema + +```json +{ "not": { "type": "integer" } } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + const sub0 = (() => { + if (!Number.isInteger(data)) return false + return true + })() + if (sub0) return false + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## not multiple types + +### Schema + +```json +{ "not": { "type": ["integer", "boolean"] } } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + const sub0 = (() => { + if (!(Number.isInteger(data) || typeof data === "boolean")) return false + return true + })() + if (sub0) return false + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## not more complex schema + +### Schema + +```json +{ "not": { "type": "object", "properties": { "foo": { "type": "string" } } } } +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + const sub0 = (() => { + if (!(typeof data === "object" && data && !Array.isArray(data))) return false + if (data.foo !== undefined && hasOwn(data, "foo")) { + if (!(typeof data.foo === "string")) return false + } + return true + })() + if (sub0) return false + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] if properties is used, required should be specified at #/not` + + +## forbidden property + +### Schema + +```json +{ "properties": { "foo": { "not": {} } } } +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.foo !== undefined && hasOwn(data, "foo")) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #/properties/foo` + + +## not with boolean schema true + +### Schema + +```json +{ "not": true } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + return false + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## not with boolean schema false + +### Schema + +```json +{ "not": false } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + return true +}; +return ref0 +``` + +### Warnings + + * `some checks are never reachable at #` + diff --git a/doc/samples/draft-next/oneOf.md b/doc/samples/draft-next/oneOf.md new file mode 100644 index 0000000..4d80f08 --- /dev/null +++ b/doc/samples/draft-next/oneOf.md @@ -0,0 +1,371 @@ +# oneOf + +## oneOf + +### Schema + +```json +{ "oneOf": [{ "type": "integer" }, { "minimum": 2 }] } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + let passes0 = 0 + const sub0 = (() => { + if (!Number.isInteger(data)) return false + return true + })() + if (sub0) passes0++ + const sub1 = (() => { + if (typeof data === "number") { + if (!(2 <= data)) return false + } + return true + })() + if (sub1) passes0++ + if (passes0 !== 1) return false + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## oneOf with base schema + +### Schema + +```json +{ "type": "string", "oneOf": [{ "minLength": 2 }, { "maxLength": 4 }] } +``` + +### Code + +```js +'use strict' +const stringLength = (string) => + /[\uD800-\uDFFF]/.test(string) ? [...string].length : string.length; +const ref0 = function validate(data) { + if (!(typeof data === "string")) return false + let passes0 = 0 + const sub0 = (() => { + if (data.length < 2 || stringLength(data) < 2) return false + return true + })() + if (sub0) passes0++ + const sub1 = (() => { + if (data.length > 4 && stringLength(data) > 4) return false + return true + })() + if (sub1) passes0++ + if (passes0 !== 1) return false + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireStringValidation] pattern, format or contentSchema should be specified for strings, use pattern: ^[\s\S]*$ to opt-out at #` + + +## oneOf with boolean schemas, all true + +### Schema + +```json +{ "oneOf": [true, true, true] } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + let passes0 = 0 + passes0++ + passes0++ + if (passes0 > 1) return false + passes0++ + if (passes0 !== 1) return false + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## oneOf with boolean schemas, one true + +### Schema + +```json +{ "oneOf": [true, false, false] } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + let passes0 = 0 + passes0++ + if (passes0 > 1) return false + if (passes0 !== 1) return false + return true +}; +return ref0 +``` + +### Warnings + + * `some checks are never reachable at #` + + +## oneOf with boolean schemas, more than one true + +### Schema + +```json +{ "oneOf": [true, true, false] } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + let passes0 = 0 + passes0++ + passes0++ + if (passes0 > 1) return false + if (passes0 !== 1) return false + return true +}; +return ref0 +``` + +### Warnings + + * `some checks are never reachable at #` + + +## oneOf with boolean schemas, all false + +### Schema + +```json +{ "oneOf": [false, false, false] } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + let passes0 = 0 + if (passes0 > 1) return false + if (passes0 !== 1) return false + return true +}; +return ref0 +``` + +### Warnings + + * `some checks are never reachable at #` + + +## oneOf complex types + +### Schema + +```json +{ + "oneOf": [ + { "properties": { "bar": { "type": "integer" } }, "required": ["bar"] }, + { "properties": { "foo": { "type": "string" } }, "required": ["foo"] } + ] +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + let passes0 = 0 + const sub0 = (() => { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (!(data.bar !== undefined && hasOwn(data, "bar"))) return false + if (!Number.isInteger(data.bar)) return false + } + return true + })() + if (sub0) passes0++ + const sub1 = (() => { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (!(data.foo !== undefined && hasOwn(data, "foo"))) return false + if (!(typeof data.foo === "string")) return false + } + return true + })() + if (sub1) passes0++ + if (passes0 !== 1) return false + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireStringValidation] pattern, format or contentSchema should be specified for strings, use pattern: ^[\s\S]*$ to opt-out at #/oneOf/1/properties/foo` + + +## oneOf with empty schema + +### Schema + +```json +{ "oneOf": [{ "type": "number" }, {}] } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + let passes0 = 0 + const sub0 = (() => { + if (!(typeof data === "number")) return false + return true + })() + if (sub0) passes0++ + passes0++ + if (passes0 !== 1) return false + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## oneOf with required + +### Schema + +```json +{ + "type": "object", + "oneOf": [{ "required": ["foo", "bar"] }, { "required": ["foo", "baz"] }] +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (!(typeof data === "object" && data && !Array.isArray(data))) return false + let passes0 = 0 + const sub0 = (() => { + if (!(data.foo !== undefined && hasOwn(data, "foo"))) return false + if (!(data.bar !== undefined && hasOwn(data, "bar"))) return false + return true + })() + if (sub0) passes0++ + const sub1 = (() => { + if (!(data.foo !== undefined && hasOwn(data, "foo"))) return false + if (!(data.baz !== undefined && hasOwn(data, "baz"))) return false + return true + })() + if (sub1) passes0++ + if (passes0 !== 1) return false + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] additionalProperties or unevaluatedProperties should be specified at #` + + +## oneOf with missing optional property + +### Schema + +```json +{ + "oneOf": [ + { "properties": { "bar": true, "baz": true }, "required": ["bar"] }, + { "properties": { "foo": true }, "required": ["foo"] } + ] +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + let passes0 = 0 + const sub0 = (() => { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (!(data.bar !== undefined && hasOwn(data, "bar"))) return false + } + return true + })() + if (sub0) passes0++ + const sub1 = (() => { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (!(data.foo !== undefined && hasOwn(data, "foo"))) return false + } + return true + })() + if (sub1) passes0++ + if (passes0 !== 1) return false + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] schema = true is not allowed at #/oneOf/0/properties/bar` + + +## nested oneOf, to check validation semantics + +### Schema + +```json +{ "oneOf": [{ "oneOf": [{ "type": "null" }] }] } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (!(data === null)) return false + return true +}; +return ref0 +``` + diff --git a/doc/samples/draft-next/optional-bignum.md b/doc/samples/draft-next/optional-bignum.md new file mode 100644 index 0000000..a9a7ca7 --- /dev/null +++ b/doc/samples/draft-next/optional-bignum.md @@ -0,0 +1,169 @@ +# optional/bignum + +## integer + +### Schema + +```json +{ "type": "integer" } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (!Number.isInteger(data)) return false + return true +}; +return ref0 +``` + + +## number + +### Schema + +```json +{ "type": "number" } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (!(typeof data === "number")) return false + return true +}; +return ref0 +``` + + +## string + +### Schema + +```json +{ "type": "string" } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (!(typeof data === "string")) return false + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireStringValidation] pattern, format or contentSchema should be specified for strings, use pattern: ^[\s\S]*$ to opt-out at #` + + +## maximum integer comparison + +### Schema + +```json +{ "maximum": 18446744073709552000 } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (typeof data === "number") { + if (!(18446744073709552000 >= data)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## float comparison with high precision + +### Schema + +```json +{ "exclusiveMaximum": 9.727837981879871e26 } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (typeof data === "number") { + if (!(9.727837981879871e+26 > data)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## minimum integer comparison + +### Schema + +```json +{ "minimum": -18446744073709552000 } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (typeof data === "number") { + if (!(-18446744073709552000 <= data)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## float comparison with high precision on negative numbers + +### Schema + +```json +{ "exclusiveMinimum": -9.727837981879871e26 } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (typeof data === "number") { + if (!(-9.727837981879871e+26 < data)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + diff --git a/doc/samples/draft-next/optional-dependencies-compatibility.md b/doc/samples/draft-next/optional-dependencies-compatibility.md new file mode 100644 index 0000000..f4d5b5b --- /dev/null +++ b/doc/samples/draft-next/optional-dependencies-compatibility.md @@ -0,0 +1,219 @@ +# optional/dependencies-compatibility + +## single dependency + +### Schema + +```json +{ "dependencies": { "bar": ["foo"] } } +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.bar !== undefined && hasOwn(data, "bar") && !(data.foo !== undefined && hasOwn(data, "foo"))) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## empty dependents + +### Schema + +```json +{ "dependencies": { "bar": [] } } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## multiple dependents required + +### Schema + +```json +{ "dependencies": { "quux": ["foo", "bar"] } } +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.quux !== undefined && hasOwn(data, "quux") && !(data.foo !== undefined && hasOwn(data, "foo") && data.bar !== undefined && hasOwn(data, "bar"))) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## dependencies with escaped characters + +### Schema + +```json +{ "dependencies": { "foo\nbar": ["foo\rbar"], "foo\"bar": ["foo'bar"] } } +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data["foo\nbar"] !== undefined && hasOwn(data, "foo\nbar") && !(data["foo\rbar"] !== undefined && hasOwn(data, "foo\rbar"))) return false + if (data["foo\"bar"] !== undefined && hasOwn(data, "foo\"bar") && !(data["foo'bar"] !== undefined && hasOwn(data, "foo'bar"))) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## single schema dependency + +### Schema + +```json +{ + "dependencies": { + "bar": { + "properties": { + "foo": { "type": "integer" }, + "bar": { "type": "integer" } + } + } + } +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.bar !== undefined && hasOwn(data, "bar")) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.foo !== undefined && hasOwn(data, "foo")) { + if (!Number.isInteger(data.foo)) return false + } + if (data.bar !== undefined && hasOwn(data, "bar")) { + if (!Number.isInteger(data.bar)) return false + } + } + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] if properties is used, required should be specified at #/dependencies/bar` + + +## boolean subschemas + +### Schema + +```json +{ "dependencies": { "foo": true, "bar": false } } +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.bar !== undefined && hasOwn(data, "bar")) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] schema = true is not allowed at #/dependencies/foo` + + +## schema dependencies with escaped characters + +### Schema + +```json +{ + "dependencies": { + "foo\tbar": { "minProperties": 4 }, + "foo'bar": { "required": ["foo\"bar"] } + } +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data["foo\tbar"] !== undefined && hasOwn(data, "foo\tbar")) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (Object.keys(data).length < 4) return false + } + } + if (data["foo'bar"] !== undefined && hasOwn(data, "foo'bar")) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (!(data["foo\"bar"] !== undefined && hasOwn(data, "foo\"bar"))) return false + } + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + diff --git a/doc/samples/draft-next/optional-ecmascript-regex.md b/doc/samples/draft-next/optional-ecmascript-regex.md new file mode 100644 index 0000000..3f79875 --- /dev/null +++ b/doc/samples/draft-next/optional-ecmascript-regex.md @@ -0,0 +1,950 @@ +# optional/ecmascript-regex + +## ECMA 262 regex $ does not match trailing newline + +### Schema + +```json +{ "type": "string", "pattern": "^abc$" } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (!(typeof data === "string")) return false + if (!(data === "abc")) return false + return true +}; +return ref0 +``` + + +## ECMA 262 regex converts \t to horizontal tab + +### Schema + +```json +{ "type": "string", "pattern": "^\\t$" } +``` + +### Code + +```js +'use strict' +const pattern0 = new RegExp("^\\t$", "u"); +const ref0 = function validate(data) { + if (!(typeof data === "string")) return false + if (!pattern0.test(data)) return false + return true +}; +return ref0 +``` + + +## ECMA 262 regex escapes control codes with \c and upper letter + +### Schema + +```json +{ "type": "string", "pattern": "^\\cC$" } +``` + +### Code + +```js +'use strict' +const pattern0 = new RegExp("^\\cC$", "u"); +const ref0 = function validate(data) { + if (!(typeof data === "string")) return false + if (!pattern0.test(data)) return false + return true +}; +return ref0 +``` + + +## ECMA 262 regex escapes control codes with \c and lower letter + +### Schema + +```json +{ "type": "string", "pattern": "^\\cc$" } +``` + +### Code + +```js +'use strict' +const pattern0 = new RegExp("^\\cc$", "u"); +const ref0 = function validate(data) { + if (!(typeof data === "string")) return false + if (!pattern0.test(data)) return false + return true +}; +return ref0 +``` + + +## ECMA 262 \d matches ascii digits only + +### Schema + +```json +{ "type": "string", "pattern": "^\\d$" } +``` + +### Code + +```js +'use strict' +const pattern0 = new RegExp("^\\d$", "u"); +const ref0 = function validate(data) { + if (!(typeof data === "string")) return false + if (!pattern0.test(data)) return false + return true +}; +return ref0 +``` + + +## ECMA 262 \D matches everything but ascii digits + +### Schema + +```json +{ "type": "string", "pattern": "^\\D$" } +``` + +### Code + +```js +'use strict' +const pattern0 = new RegExp("^\\D$", "u"); +const ref0 = function validate(data) { + if (!(typeof data === "string")) return false + if (!pattern0.test(data)) return false + return true +}; +return ref0 +``` + + +## ECMA 262 \w matches ascii letters only + +### Schema + +```json +{ "type": "string", "pattern": "^\\w$" } +``` + +### Code + +```js +'use strict' +const pattern0 = new RegExp("^\\w$", "u"); +const ref0 = function validate(data) { + if (!(typeof data === "string")) return false + if (!pattern0.test(data)) return false + return true +}; +return ref0 +``` + + +## ECMA 262 \W matches everything but ascii letters + +### Schema + +```json +{ "type": "string", "pattern": "^\\W$" } +``` + +### Code + +```js +'use strict' +const pattern0 = new RegExp("^\\W$", "u"); +const ref0 = function validate(data) { + if (!(typeof data === "string")) return false + if (!pattern0.test(data)) return false + return true +}; +return ref0 +``` + + +## ECMA 262 \s matches whitespace + +### Schema + +```json +{ "type": "string", "pattern": "^\\s$" } +``` + +### Code + +```js +'use strict' +const pattern0 = new RegExp("^\\s$", "u"); +const ref0 = function validate(data) { + if (!(typeof data === "string")) return false + if (!pattern0.test(data)) return false + return true +}; +return ref0 +``` + + +## ECMA 262 \S matches everything but whitespace + +### Schema + +```json +{ "type": "string", "pattern": "^\\S$" } +``` + +### Code + +```js +'use strict' +const pattern0 = new RegExp("^\\S$", "u"); +const ref0 = function validate(data) { + if (!(typeof data === "string")) return false + if (!pattern0.test(data)) return false + return true +}; +return ref0 +``` + + +## patterns always use unicode semantics with pattern + +### Schema + +```json +{ "pattern": "\\p{Letter}cole" } +``` + +### Code + +```js +'use strict' +const pattern0 = new RegExp("\\p{Letter}cole", "u"); +const ref0 = function validate(data) { + if (typeof data === "string") { + if (!pattern0.test(data)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `Should start with ^ and end with $: "\\p{Letter}cole" at #` + + +## \w in patterns matches [A-Za-z0-9_], not unicode letters + +### Schema + +```json +{ "pattern": "\\wcole" } +``` + +### Code + +```js +'use strict' +const pattern0 = new RegExp("\\wcole", "u"); +const ref0 = function validate(data) { + if (typeof data === "string") { + if (!pattern0.test(data)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `Should start with ^ and end with $: "\\wcole" at #` + + +## pattern with ASCII ranges + +### Schema + +```json +{ "pattern": "[a-z]cole" } +``` + +### Code + +```js +'use strict' +const pattern0 = new RegExp("[a-z]cole", "u"); +const ref0 = function validate(data) { + if (typeof data === "string") { + if (!pattern0.test(data)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `Should start with ^ and end with $: "[a-z]cole" at #` + + +## \d in pattern matches [0-9], not unicode digits + +### Schema + +```json +{ "pattern": "^\\d+$" } +``` + +### Code + +```js +'use strict' +const pattern0 = new RegExp("^\\d+$", "u"); +const ref0 = function validate(data) { + if (typeof data === "string") { + if (!pattern0.test(data)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## \a is not an ECMA 262 control escape + +### Schema + +```json +{ "$ref": "https://json-schema.org/draft/next/schema" } +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const dynamicResolve = (anchors, id) => (anchors.filter((x) => x[id])[0] || {})[id]; +const unique = (array) => { + if (array.length < 2) return true + if (array.length === 2) return !deepEqual(array[0], array[1]) + const objects = [] + const primitives = array.length > 20 ? new Set() : null + let primitivesCount = 0 + let pos = 0 + for (const item of array) { + if (typeof item === 'object') { + objects.push(item) + } else if (primitives) { + primitives.add(item) + if (primitives.size !== ++primitivesCount) return false + } else { + if (array.indexOf(item, pos + 1) !== -1) return false + } + pos++ + } + for (let i = 1; i < objects.length; i++) + for (let j = 0; j < i; j++) if (deepEqual(objects[i], objects[j])) return false + return true +}; +const deepEqual = (obj, obj2) => { + if (obj === obj2) return true + if (!obj || !obj2 || typeof obj !== typeof obj2) return false + if (obj !== obj2 && typeof obj !== 'object') return false + + const proto = Object.getPrototypeOf(obj) + if (proto !== Object.getPrototypeOf(obj2)) return false + + if (proto === Array.prototype) { + if (!Array.isArray(obj) || !Array.isArray(obj2)) return false + if (obj.length !== obj2.length) return false + return obj.every((x, i) => deepEqual(x, obj2[i])) + } else if (proto === Object.prototype) { + const [keys, keys2] = [Object.keys(obj), Object.keys(obj2)] + if (keys.length !== keys2.length) return false + const keyset2 = new Set([...keys, ...keys2]) + return keyset2.size === keys.length && keys.every((key) => deepEqual(obj[key], obj2[key])) + } + return false +}; +const ref2 = function validate(data, dynAnchors) { + if (!Array.isArray(data)) return false + for (let i = 0; i < data.length; i++) { + if (data[i] !== undefined && hasOwn(data, i)) { + if (!(typeof data[i] === "string")) return false + } + } + if (!unique(data)) return false + return true +}; +const pattern0 = new RegExp("^[A-Za-z_][-A-Za-z0-9._]*$", "u"); +const ref3 = function validate(data, dynAnchors) { + if (!(typeof data === "string")) return false + if (!pattern0.test(data)) return false + return true +}; +const format0 = new RegExp("^(?:[a-z][a-z0-9+\\-.]*:)?(?:\\/?\\/(?:(?:[a-z0-9\\-._~!$&'()*+,;=:]|%[0-9a-f]{2})*@)?(?:\\[(?:(?:(?:(?:[0-9a-f]{1,4}:){6}|::(?:[0-9a-f]{1,4}:){5}|(?:[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){4}|(?:(?:[0-9a-f]{1,4}:){0,1}[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){3}|(?:(?:[0-9a-f]{1,4}:){0,2}[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){2}|(?:(?:[0-9a-f]{1,4}:){0,3}[0-9a-f]{1,4})?::[0-9a-f]{1,4}:|(?:(?:[0-9a-f]{1,4}:){0,4}[0-9a-f]{1,4})?::)(?:[0-9a-f]{1,4}:[0-9a-f]{1,4}|(?:(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d\\d?)\\.){3}(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d\\d?))|(?:(?:[0-9a-f]{1,4}:){0,5}[0-9a-f]{1,4})?::[0-9a-f]{1,4}|(?:(?:[0-9a-f]{1,4}:){0,6}[0-9a-f]{1,4})?::)|v[0-9a-f]+\\.[a-z0-9\\-._~!$&'()*+,;=:]+)\\]|(?:(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d\\d?)\\.){3}(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d\\d?)|(?:[a-z0-9\\-._~!$&'()*+,;=]|%[0-9a-f]{2})*)(?::\\d*)?(?:\\/(?:[a-z0-9\\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})*)*|\\/?(?:(?:[a-z0-9\\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})+(?:\\/(?:[a-z0-9\\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})*)*)?)?(?:\\?(?:[a-z0-9\\-._~!$&'()*+,;=:@/?]|%[0-9a-f]{2})*)?(?:#(?:[a-z0-9\\-._~!$&'()*+,;=:@/?]|%[0-9a-f]{2})*)?$", "i"); +const ref4 = function validate(data, dynAnchors) { + if (!(typeof data === "string")) return false + if (!format0.test(data)) return false + return true +}; +const pattern1 = new RegExp("^[^#]*#?$", "u"); +const format1 = new RegExp("^[a-z][a-z0-9+\\-.]*:(?:\\/?\\/(?:(?:[a-z0-9\\-._~!$&'()*+,;=:]|%[0-9a-f]{2})*@)?(?:\\[(?:(?:(?:(?:[0-9a-f]{1,4}:){6}|::(?:[0-9a-f]{1,4}:){5}|(?:[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){4}|(?:(?:[0-9a-f]{1,4}:){0,1}[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){3}|(?:(?:[0-9a-f]{1,4}:){0,2}[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){2}|(?:(?:[0-9a-f]{1,4}:){0,3}[0-9a-f]{1,4})?::[0-9a-f]{1,4}:|(?:(?:[0-9a-f]{1,4}:){0,4}[0-9a-f]{1,4})?::)(?:[0-9a-f]{1,4}:[0-9a-f]{1,4}|(?:(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d\\d?)\\.){3}(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d\\d?))|(?:(?:[0-9a-f]{1,4}:){0,5}[0-9a-f]{1,4})?::[0-9a-f]{1,4}|(?:(?:[0-9a-f]{1,4}:){0,6}[0-9a-f]{1,4})?::)|v[0-9a-f]+\\.[a-z0-9\\-._~!$&'()*+,;=:]+)\\]|(?:(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d\\d?)\\.){3}(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d\\d?)|(?:[a-z0-9\\-._~!$&'()*+,;=]|%[0-9a-f]{2})*)(?::\\d*)?(?:\\/(?:[a-z0-9\\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})*)*|\\/?(?:(?:[a-z0-9\\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})+(?:\\/(?:[a-z0-9\\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})*)*)?)(?:\\?(?:[a-z0-9\\-._~!$&'()*+,;=:@/?]|%[0-9a-f]{2})*)?(?:#(?:[a-z0-9\\-._~!$&'()*+,;=:@/?]|%[0-9a-f]{2})*)?$", "i"); +const ref6 = function validate(data, dynAnchors) { + if (!(typeof data === "string")) return false + if (!format1.test(data)) return false + return true +}; +const ref5 = function validate(data, dynAnchors = []) { + const dynLocal = [{}] + dynLocal[0]["#meta"] = validate + if (!(typeof data === "object" && data && !Array.isArray(data) || typeof data === "boolean")) return false + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data["$id"] !== undefined && hasOwn(data, "$id")) { + if (!ref4(data["$id"], [...dynAnchors, dynLocal[0] || []])) return false + if (!(pattern1.test(data["$id"]))) return false + } + if (data["$schema"] !== undefined && hasOwn(data, "$schema")) { + if (!ref6(data["$schema"], [...dynAnchors, dynLocal[0] || []])) return false + } + if (data["$ref"] !== undefined && hasOwn(data, "$ref")) { + if (!ref4(data["$ref"], [...dynAnchors, dynLocal[0] || []])) return false + } + if (data["$anchor"] !== undefined && hasOwn(data, "$anchor")) { + if (!ref3(data["$anchor"], [...dynAnchors, dynLocal[0] || []])) return false + } + if (data["$dynamicRef"] !== undefined && hasOwn(data, "$dynamicRef")) { + if (!ref4(data["$dynamicRef"], [...dynAnchors, dynLocal[0] || []])) return false + } + if (data["$dynamicAnchor"] !== undefined && hasOwn(data, "$dynamicAnchor")) { + if (!ref3(data["$dynamicAnchor"], [...dynAnchors, dynLocal[0] || []])) return false + } + if (data["$vocabulary"] !== undefined && hasOwn(data, "$vocabulary")) { + if (!(typeof data["$vocabulary"] === "object" && data["$vocabulary"] && !Array.isArray(data["$vocabulary"]))) return false + for (const key2 of Object.keys(data["$vocabulary"])) { + if (!ref6(key2, [...dynAnchors, dynLocal[0] || []])) return false + } + for (const key3 of Object.keys(data["$vocabulary"])) { + if (!(typeof data["$vocabulary"][key3] === "boolean")) return false + } + } + if (data["$comment"] !== undefined && hasOwn(data, "$comment")) { + if (!(typeof data["$comment"] === "string")) return false + } + if (data["$defs"] !== undefined && hasOwn(data, "$defs")) { + if (!(typeof data["$defs"] === "object" && data["$defs"] && !Array.isArray(data["$defs"]))) return false + for (const key4 of Object.keys(data["$defs"])) { + if (!(dynamicResolve(dynAnchors || [], "#meta") || validate)(data["$defs"][key4], [...dynAnchors, dynLocal[0] || []])) return false + } + } + } + return true +}; +const ref8 = function validate(data, dynAnchors) { + if (!Array.isArray(data)) return false + if (data.length < 1) return false + for (let j = 0; j < data.length; j++) { + if (data[j] !== undefined && hasOwn(data, j)) { + if (!(dynamicResolve(dynAnchors || [], "#meta") || ref7)(data[j], dynAnchors)) return false + } + } + return true +}; +const format2 = (str) => { + if (str.length > 1e5) return false + const Z_ANCHOR = /[^\\]\\Z/ + if (Z_ANCHOR.test(str)) return false + try { + new RegExp(str, 'u') + return true + } catch (e) { + return false + } + }; +const ref7 = function validate(data, dynAnchors = []) { + const dynLocal = [{}] + dynLocal[0]["#meta"] = validate + if (!(typeof data === "object" && data && !Array.isArray(data) || typeof data === "boolean")) return false + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.prefixItems !== undefined && hasOwn(data, "prefixItems")) { + if (!ref8(data.prefixItems, [...dynAnchors, dynLocal[0] || []])) return false + } + if (data.items !== undefined && hasOwn(data, "items")) { + if (!(dynamicResolve(dynAnchors || [], "#meta") || validate)(data.items, [...dynAnchors, dynLocal[0] || []])) return false + } + if (data.contains !== undefined && hasOwn(data, "contains")) { + if (!(dynamicResolve(dynAnchors || [], "#meta") || validate)(data.contains, [...dynAnchors, dynLocal[0] || []])) return false + } + if (data.additionalProperties !== undefined && hasOwn(data, "additionalProperties")) { + if (!(dynamicResolve(dynAnchors || [], "#meta") || validate)(data.additionalProperties, [...dynAnchors, dynLocal[0] || []])) return false + } + if (data.properties !== undefined && hasOwn(data, "properties")) { + if (!(typeof data.properties === "object" && data.properties && !Array.isArray(data.properties))) return false + for (const key5 of Object.keys(data.properties)) { + if (!(dynamicResolve(dynAnchors || [], "#meta") || validate)(data.properties[key5], [...dynAnchors, dynLocal[0] || []])) return false + } + } + if (data.patternProperties !== undefined && hasOwn(data, "patternProperties")) { + if (!(typeof data.patternProperties === "object" && data.patternProperties && !Array.isArray(data.patternProperties))) return false + for (const key6 of Object.keys(data.patternProperties)) { + if (!format2(key6)) return false + } + for (const key7 of Object.keys(data.patternProperties)) { + if (!(dynamicResolve(dynAnchors || [], "#meta") || validate)(data.patternProperties[key7], [...dynAnchors, dynLocal[0] || []])) return false + } + } + if (data.dependentSchemas !== undefined && hasOwn(data, "dependentSchemas")) { + if (!(typeof data.dependentSchemas === "object" && data.dependentSchemas && !Array.isArray(data.dependentSchemas))) return false + for (const key8 of Object.keys(data.dependentSchemas)) { + if (!(dynamicResolve(dynAnchors || [], "#meta") || validate)(data.dependentSchemas[key8], [...dynAnchors, dynLocal[0] || []])) return false + } + } + if (data.propertyNames !== undefined && hasOwn(data, "propertyNames")) { + if (!(dynamicResolve(dynAnchors || [], "#meta") || validate)(data.propertyNames, [...dynAnchors, dynLocal[0] || []])) return false + } + if (data.if !== undefined && hasOwn(data, "if")) { + if (!(dynamicResolve(dynAnchors || [], "#meta") || validate)(data.if, [...dynAnchors, dynLocal[0] || []])) return false + } + if (data.then !== undefined && hasOwn(data, "then")) { + if (!(dynamicResolve(dynAnchors || [], "#meta") || validate)(data.then, [...dynAnchors, dynLocal[0] || []])) return false + } + if (data.else !== undefined && hasOwn(data, "else")) { + if (!(dynamicResolve(dynAnchors || [], "#meta") || validate)(data.else, [...dynAnchors, dynLocal[0] || []])) return false + } + if (data.allOf !== undefined && hasOwn(data, "allOf")) { + if (!ref8(data.allOf, [...dynAnchors, dynLocal[0] || []])) return false + } + if (data.anyOf !== undefined && hasOwn(data, "anyOf")) { + if (!ref8(data.anyOf, [...dynAnchors, dynLocal[0] || []])) return false + } + if (data.oneOf !== undefined && hasOwn(data, "oneOf")) { + if (!ref8(data.oneOf, [...dynAnchors, dynLocal[0] || []])) return false + } + if (data.not !== undefined && hasOwn(data, "not")) { + if (!(dynamicResolve(dynAnchors || [], "#meta") || validate)(data.not, [...dynAnchors, dynLocal[0] || []])) return false + } + } + return true +}; +const ref9 = function validate(data, dynAnchors = []) { + const dynLocal = [{}] + dynLocal[0]["#meta"] = validate + if (!(typeof data === "object" && data && !Array.isArray(data) || typeof data === "boolean")) return false + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.unevaluatedItems !== undefined && hasOwn(data, "unevaluatedItems")) { + if (!(dynamicResolve(dynAnchors || [], "#meta") || validate)(data.unevaluatedItems, [...dynAnchors, dynLocal[0] || []])) return false + } + if (data.unevaluatedProperties !== undefined && hasOwn(data, "unevaluatedProperties")) { + if (!(dynamicResolve(dynAnchors || [], "#meta") || validate)(data.unevaluatedProperties, [...dynAnchors, dynLocal[0] || []])) return false + } + } + return true +}; +const ref11 = function validate(data, dynAnchors) { + if (!(data === "array" || data === "boolean" || data === "integer" || data === "null" || data === "number" || data === "object" || data === "string")) return false + return true +}; +const ref12 = function validate(data, dynAnchors) { + if (!Number.isInteger(data)) return false + if (!(0 <= data)) return false + return true +}; +const ref13 = function validate(data, dynAnchors) { + if (!ref12(data, dynAnchors)) return false + return true +}; +const ref10 = function validate(data, dynAnchors = []) { + const dynLocal = [{}] + dynLocal[0]["#meta"] = validate + if (!(typeof data === "object" && data && !Array.isArray(data) || typeof data === "boolean")) return false + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.type !== undefined && hasOwn(data, "type")) { + const sub2 = (() => { + if (!ref11(data.type, [...dynAnchors, dynLocal[0] || []])) return false + return true + })() + if (!sub2) { + const sub3 = (() => { + if (!Array.isArray(data.type)) return false + if (data.type.length < 1) return false + for (let k = 0; k < data.type.length; k++) { + if (data.type[k] !== undefined && hasOwn(data.type, k)) { + if (!ref11(data.type[k], [...dynAnchors, dynLocal[0] || []])) return false + } + } + if (!unique(data.type)) return false + return true + })() + if (!sub3) return false + } + } + if (data.enum !== undefined && hasOwn(data, "enum")) { + if (!Array.isArray(data.enum)) return false + } + if (data.multipleOf !== undefined && hasOwn(data, "multipleOf")) { + if (!(typeof data.multipleOf === "number")) return false + if (!(0 < data.multipleOf)) return false + } + if (data.maximum !== undefined && hasOwn(data, "maximum")) { + if (!(typeof data.maximum === "number")) return false + } + if (data.exclusiveMaximum !== undefined && hasOwn(data, "exclusiveMaximum")) { + if (!(typeof data.exclusiveMaximum === "number")) return false + } + if (data.minimum !== undefined && hasOwn(data, "minimum")) { + if (!(typeof data.minimum === "number")) return false + } + if (data.exclusiveMinimum !== undefined && hasOwn(data, "exclusiveMinimum")) { + if (!(typeof data.exclusiveMinimum === "number")) return false + } + if (data.maxLength !== undefined && hasOwn(data, "maxLength")) { + if (!ref12(data.maxLength, [...dynAnchors, dynLocal[0] || []])) return false + } + if (data.minLength !== undefined && hasOwn(data, "minLength")) { + if (!ref13(data.minLength, [...dynAnchors, dynLocal[0] || []])) return false + } + if (data.pattern !== undefined && hasOwn(data, "pattern")) { + if (!(typeof data.pattern === "string")) return false + if (!format2(data.pattern)) return false + } + if (data.maxItems !== undefined && hasOwn(data, "maxItems")) { + if (!ref12(data.maxItems, [...dynAnchors, dynLocal[0] || []])) return false + } + if (data.minItems !== undefined && hasOwn(data, "minItems")) { + if (!ref13(data.minItems, [...dynAnchors, dynLocal[0] || []])) return false + } + if (data.uniqueItems !== undefined && hasOwn(data, "uniqueItems")) { + if (!(typeof data.uniqueItems === "boolean")) return false + } + if (data.maxContains !== undefined && hasOwn(data, "maxContains")) { + if (!ref12(data.maxContains, [...dynAnchors, dynLocal[0] || []])) return false + } + if (data.minContains !== undefined && hasOwn(data, "minContains")) { + if (!ref12(data.minContains, [...dynAnchors, dynLocal[0] || []])) return false + } + if (data.maxProperties !== undefined && hasOwn(data, "maxProperties")) { + if (!ref12(data.maxProperties, [...dynAnchors, dynLocal[0] || []])) return false + } + if (data.minProperties !== undefined && hasOwn(data, "minProperties")) { + if (!ref13(data.minProperties, [...dynAnchors, dynLocal[0] || []])) return false + } + if (data.required !== undefined && hasOwn(data, "required")) { + if (!ref2(data.required, [...dynAnchors, dynLocal[0] || []])) return false + } + if (data.dependentRequired !== undefined && hasOwn(data, "dependentRequired")) { + if (!(typeof data.dependentRequired === "object" && data.dependentRequired && !Array.isArray(data.dependentRequired))) return false + for (const key9 of Object.keys(data.dependentRequired)) { + if (!ref2(data.dependentRequired[key9], [...dynAnchors, dynLocal[0] || []])) return false + } + } + } + return true +}; +const ref14 = function validate(data, dynAnchors) { + if (!(typeof data === "object" && data && !Array.isArray(data) || typeof data === "boolean")) return false + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.title !== undefined && hasOwn(data, "title")) { + if (!(typeof data.title === "string")) return false + } + if (data.description !== undefined && hasOwn(data, "description")) { + if (!(typeof data.description === "string")) return false + } + if (data.deprecated !== undefined && hasOwn(data, "deprecated")) { + if (!(typeof data.deprecated === "boolean")) return false + } + if (data.readOnly !== undefined && hasOwn(data, "readOnly")) { + if (!(typeof data.readOnly === "boolean")) return false + } + if (data.writeOnly !== undefined && hasOwn(data, "writeOnly")) { + if (!(typeof data.writeOnly === "boolean")) return false + } + if (data.examples !== undefined && hasOwn(data, "examples")) { + if (!Array.isArray(data.examples)) return false + } + } + return true +}; +const ref15 = function validate(data, dynAnchors) { + if (!(typeof data === "object" && data && !Array.isArray(data) || typeof data === "boolean")) return false + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.format !== undefined && hasOwn(data, "format")) { + if (!(typeof data.format === "string")) return false + } + } + return true +}; +const ref16 = function validate(data, dynAnchors = []) { + const dynLocal = [{}] + dynLocal[0]["#meta"] = validate + if (!(typeof data === "object" && data && !Array.isArray(data) || typeof data === "boolean")) return false + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.contentEncoding !== undefined && hasOwn(data, "contentEncoding")) { + if (!(typeof data.contentEncoding === "string")) return false + } + if (data.contentMediaType !== undefined && hasOwn(data, "contentMediaType")) { + if (!(typeof data.contentMediaType === "string")) return false + } + if (data.contentSchema !== undefined && hasOwn(data, "contentSchema")) { + if (!(dynamicResolve(dynAnchors || [], "#meta") || validate)(data.contentSchema, [...dynAnchors, dynLocal[0] || []])) return false + } + } + return true +}; +const ref1 = function validate(data, dynAnchors = []) { + const dynLocal = [{}] + dynLocal[0]["#meta"] = validate + if (!(typeof data === "object" && data && !Array.isArray(data) || typeof data === "boolean")) return false + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.definitions !== undefined && hasOwn(data, "definitions")) { + if (!(typeof data.definitions === "object" && data.definitions && !Array.isArray(data.definitions))) return false + for (const key0 of Object.keys(data.definitions)) { + if (!(dynamicResolve(dynAnchors || [], "#meta") || validate)(data.definitions[key0], [...dynAnchors, dynLocal[0] || []])) return false + } + } + if (data.dependencies !== undefined && hasOwn(data, "dependencies")) { + if (!(typeof data.dependencies === "object" && data.dependencies && !Array.isArray(data.dependencies))) return false + for (const key1 of Object.keys(data.dependencies)) { + const sub0 = (() => { + if (!(dynamicResolve(dynAnchors || [], "#meta") || validate)(data.dependencies[key1], [...dynAnchors, dynLocal[0] || []])) return false + return true + })() + if (!sub0) { + const sub1 = (() => { + if (!ref2(data.dependencies[key1], [...dynAnchors, dynLocal[0] || []])) return false + return true + })() + if (!sub1) return false + } + } + } + if (data["$recursiveAnchor"] !== undefined && hasOwn(data, "$recursiveAnchor")) { + if (!ref3(data["$recursiveAnchor"], [...dynAnchors, dynLocal[0] || []])) return false + } + if (data["$recursiveRef"] !== undefined && hasOwn(data, "$recursiveRef")) { + if (!ref4(data["$recursiveRef"], [...dynAnchors, dynLocal[0] || []])) return false + } + } + if (!ref5(data, [...dynAnchors, dynLocal[0] || []])) return false + if (!ref7(data, [...dynAnchors, dynLocal[0] || []])) return false + if (!ref9(data, [...dynAnchors, dynLocal[0] || []])) return false + if (!ref10(data, [...dynAnchors, dynLocal[0] || []])) return false + if (!ref14(data, [...dynAnchors, dynLocal[0] || []])) return false + if (!ref15(data, [...dynAnchors, dynLocal[0] || []])) return false + if (!ref16(data, [...dynAnchors, dynLocal[0] || []])) return false + return true +}; +const ref0 = function validate(data, dynAnchors) { + if (!ref1(data, dynAnchors)) return false + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at https://json-schema.org/draft/next/schema#/properties/definitions/additionalProperties` + + +## pattern with non-ASCII digits + +### Schema + +```json +{ "pattern": "^\\p{digit}+$" } +``` + +### Code + +```js +'use strict' +const pattern0 = new RegExp("^\\p{digit}+$", "u"); +const ref0 = function validate(data) { + if (typeof data === "string") { + if (!pattern0.test(data)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[complexityChecks] maxLength should be specified for pattern: "^\\p{digit}+$" at #` + + +## patterns always use unicode semantics with patternProperties + +### Schema + +```json +{ + "type": "object", + "patternProperties": { "\\p{Letter}cole": true }, + "additionalProperties": false +} +``` + +### Code + +```js +'use strict' +const pattern0 = new RegExp("\\p{Letter}cole", "u"); +const ref0 = function validate(data) { + if (!(typeof data === "object" && data && !Array.isArray(data))) return false + for (const key1 of Object.keys(data)) { + if (!pattern0.test(key1)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `Should start with ^ and end with $: "\\p{Letter}cole" at #` + + +## \w in patternProperties matches [A-Za-z0-9_], not unicode letters + +### Schema + +```json +{ + "type": "object", + "patternProperties": { "\\wcole": true }, + "additionalProperties": false +} +``` + +### Code + +```js +'use strict' +const pattern0 = new RegExp("\\wcole", "u"); +const ref0 = function validate(data) { + if (!(typeof data === "object" && data && !Array.isArray(data))) return false + for (const key1 of Object.keys(data)) { + if (!pattern0.test(key1)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `Should start with ^ and end with $: "\\wcole" at #` + + +## patternProperties with ASCII ranges + +### Schema + +```json +{ + "type": "object", + "patternProperties": { "[a-z]cole": true }, + "additionalProperties": false +} +``` + +### Code + +```js +'use strict' +const pattern0 = new RegExp("[a-z]cole", "u"); +const ref0 = function validate(data) { + if (!(typeof data === "object" && data && !Array.isArray(data))) return false + for (const key1 of Object.keys(data)) { + if (!pattern0.test(key1)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `Should start with ^ and end with $: "[a-z]cole" at #` + + +## \d in patternProperties matches [0-9], not unicode digits + +### Schema + +```json +{ + "type": "object", + "patternProperties": { "^\\d+$": true }, + "additionalProperties": false +} +``` + +### Code + +```js +'use strict' +const pattern0 = new RegExp("^\\d+$", "u"); +const ref0 = function validate(data) { + if (!(typeof data === "object" && data && !Array.isArray(data))) return false + for (const key1 of Object.keys(data)) { + if (!pattern0.test(key1)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] schema = true is not allowed at #/patternProperties/^\d+$` + + +## patternProperties with non-ASCII digits + +### Schema + +```json +{ + "type": "object", + "patternProperties": { "^\\p{digit}+$": true }, + "additionalProperties": false +} +``` + +### Code + +```js +'use strict' +const pattern0 = new RegExp("^\\p{digit}+$", "u"); +const ref0 = function validate(data) { + if (!(typeof data === "object" && data && !Array.isArray(data))) return false + for (const key1 of Object.keys(data)) { + if (!pattern0.test(key1)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[complexityChecks] maxLength should be specified for pattern: "^\\p{digit}+$" at #` + diff --git a/doc/samples/draft-next/optional-float-overflow.md b/doc/samples/draft-next/optional-float-overflow.md new file mode 100644 index 0000000..313af9c --- /dev/null +++ b/doc/samples/draft-next/optional-float-overflow.md @@ -0,0 +1,22 @@ +# optional/float-overflow + +## all integers are multiples of 0.5, if overflow is handled + +### Schema + +```json +{ "type": "integer", "multipleOf": 0.5 } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (!Number.isInteger(data)) return false + if (data % 0.5 !== 0) return false + return true +}; +return ref0 +``` + diff --git a/doc/samples/draft-next/optional-format-assertion.md b/doc/samples/draft-next/optional-format-assertion.md new file mode 100644 index 0000000..9d8b856 --- /dev/null +++ b/doc/samples/draft-next/optional-format-assertion.md @@ -0,0 +1,43 @@ +# optional/format-assertion + +## schema that uses custom metaschema with format-assertion: false + +### Schema + +```json +{ + "$id": "https://schema/using/format-assertion/false", + "$schema": "http://localhost:1234/draft-next/format-assertion-false.json", + "format": "ipv4" +} +``` + +### Code + +**FAILED TO COMPILE** + +### Errors + + * `Unexpected schema version: "https://localhost:1234/draft-next/format-assertion-false.json" at #` + + +## schema that uses custom metaschema with format-assertion: true + +### Schema + +```json +{ + "$id": "https://schema/using/format-assertion/true", + "$schema": "http://localhost:1234/draft-next/format-assertion-true.json", + "format": "ipv4" +} +``` + +### Code + +**FAILED TO COMPILE** + +### Errors + + * `Unexpected schema version: "https://localhost:1234/draft-next/format-assertion-true.json" at #` + diff --git a/doc/samples/draft-next/optional-non-bmp-regex.md b/doc/samples/draft-next/optional-non-bmp-regex.md new file mode 100644 index 0000000..8d300cd --- /dev/null +++ b/doc/samples/draft-next/optional-non-bmp-regex.md @@ -0,0 +1,59 @@ +# optional/non-bmp-regex + +## Proper UTF-16 surrogate pair handling: pattern + +### Schema + +```json +{ "pattern": "^🐲*$" } +``` + +### Code + +```js +'use strict' +const pattern0 = new RegExp("^🐲*$", "u"); +const ref0 = function validate(data) { + if (typeof data === "string") { + if (!pattern0.test(data)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## Proper UTF-16 surrogate pair handling: patternProperties + +### Schema + +```json +{ "patternProperties": { "^🐲*$": { "type": "integer" } } } +``` + +### Code + +```js +'use strict' +const pattern0 = new RegExp("^🐲*$", "u"); +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + for (const key0 of Object.keys(data)) { + if (pattern0.test(key0)) { + if (!(Number.isInteger(data[key0]))) return false + } + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + diff --git a/doc/samples/draft-next/optional-refOfUnknownKeyword.md b/doc/samples/draft-next/optional-refOfUnknownKeyword.md new file mode 100644 index 0000000..edf3558 --- /dev/null +++ b/doc/samples/draft-next/optional-refOfUnknownKeyword.md @@ -0,0 +1,75 @@ +# optional/refOfUnknownKeyword + +## reference of a root arbitrary keyword + +### Schema + +```json +{ + "unknown-keyword": { "type": "integer" }, + "properties": { "bar": { "$ref": "#/unknown-keyword" } } +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref1 = function validate(data) { + if (!Number.isInteger(data)) return false + return true +}; +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.bar !== undefined && hasOwn(data, "bar")) { + if (!ref1(data.bar)) return false + } + } + return true +}; +return ref0 +``` + +### Warnings + + * `Keyword not supported: "unknown-keyword" at #` + + +## reference of an arbitrary keyword of a sub-schema + +### Schema + +```json +{ + "properties": { + "foo": { "unknown-keyword": { "type": "integer" } }, + "bar": { "$ref": "#/properties/foo/unknown-keyword" } + } +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref1 = function validate(data) { + if (!Number.isInteger(data)) return false + return true +}; +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.bar !== undefined && hasOwn(data, "bar")) { + if (!ref1(data.bar)) return false + } + } + return true +}; +return ref0 +``` + +### Warnings + + * `Keyword not supported: "unknown-keyword" at #/properties/foo` + diff --git a/doc/samples/draft-next/pattern.md b/doc/samples/draft-next/pattern.md new file mode 100644 index 0000000..07714d8 --- /dev/null +++ b/doc/samples/draft-next/pattern.md @@ -0,0 +1,54 @@ +# pattern + +## pattern validation + +### Schema + +```json +{ "pattern": "^a*$" } +``` + +### Code + +```js +'use strict' +const pattern0 = new RegExp("^a*$", "u"); +const ref0 = function validate(data) { + if (typeof data === "string") { + if (!pattern0.test(data)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## pattern is not anchored + +### Schema + +```json +{ "pattern": "a+" } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (typeof data === "string") { + if (!(data.includes("a"))) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `Should start with ^ and end with $: "a+" at #` + diff --git a/doc/samples/draft-next/patternProperties.md b/doc/samples/draft-next/patternProperties.md new file mode 100644 index 0000000..ebc285b --- /dev/null +++ b/doc/samples/draft-next/patternProperties.md @@ -0,0 +1,168 @@ +# patternProperties + +## patternProperties validates properties matching a regex + +### Schema + +```json +{ "patternProperties": { "f.*o": { "type": "integer" } } } +``` + +### Code + +```js +'use strict' +const pattern0 = new RegExp("f.*o", "u"); +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + for (const key0 of Object.keys(data)) { + if (pattern0.test(key0)) { + if (!(Number.isInteger(data[key0]))) return false + } + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `Should start with ^ and end with $: "f.*o" at #` + + +## multiple simultaneous patternProperties are validated + +### Schema + +```json +{ + "patternProperties": { + "a*": { "type": "integer" }, + "aaa*": { "maximum": 20 } + } +} +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + for (const key0 of Object.keys(data)) { + if (!(Number.isInteger(data[key0]))) return false + if (key0.includes("aa")) { + if (typeof data[key0] === "number") { + if (!(20 >= data[key0])) return false + } + } + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `Should start with ^ and end with $: "a*" at #` + + +## regexes are not anchored by default and are case sensitive + +### Schema + +```json +{ + "patternProperties": { + "[0-9]{2,}": { "type": "boolean" }, + "X_": { "type": "string" } + } +} +``` + +### Code + +```js +'use strict' +const pattern0 = new RegExp("[0-9]{2,}", "u"); +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + for (const key0 of Object.keys(data)) { + if (pattern0.test(key0)) { + if (!(typeof data[key0] === "boolean")) return false + } + if (key0.includes("X_")) { + if (!(typeof data[key0] === "string")) return false + } + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `Should start with ^ and end with $: "[0-9]{2,}" at #` + + +## patternProperties with boolean schemas + +### Schema + +```json +{ "patternProperties": { "f.*": true, "b.*": false } } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + for (const key0 of Object.keys(data)) { + if (key0.includes("b")) return false + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `Should start with ^ and end with $: "f.*" at #` + + +## patternProperties with null valued instance properties + +### Schema + +```json +{ "patternProperties": { "^.*bar$": { "type": "null" } } } +``` + +### Code + +```js +'use strict' +const pattern0 = new RegExp("^.*bar$", "u"); +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + for (const key0 of Object.keys(data)) { + if (pattern0.test(key0)) { + if (!(data[key0] === null)) return false + } + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + diff --git a/doc/samples/draft-next/prefixItems.md b/doc/samples/draft-next/prefixItems.md new file mode 100644 index 0000000..cb4b4c7 --- /dev/null +++ b/doc/samples/draft-next/prefixItems.md @@ -0,0 +1,118 @@ +# prefixItems + +## a schema given for prefixItems + +### Schema + +```json +{ "prefixItems": [{ "type": "integer" }, { "type": "string" }] } +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (Array.isArray(data)) { + if (data[0] !== undefined && hasOwn(data, 0)) { + if (!(Number.isInteger(data[0]))) return false + } + if (data[1] !== undefined && hasOwn(data, 1)) { + if (!(typeof data[1] === "string")) return false + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireStringValidation] pattern, format or contentSchema should be specified for strings, use pattern: ^[\s\S]*$ to opt-out at #/1` + + +## prefixItems with boolean schemas + +### Schema + +```json +{ "prefixItems": [true, false] } +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (Array.isArray(data)) { + if (data[1] !== undefined && hasOwn(data, 1)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] schema = true is not allowed at #/0` + + +## additional items are allowed by default + +### Schema + +```json +{ "prefixItems": [{ "type": "integer" }] } +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (Array.isArray(data)) { + if (data[0] !== undefined && hasOwn(data, 0)) { + if (!(Number.isInteger(data[0]))) return false + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## prefixItems with null instance elements + +### Schema + +```json +{ "prefixItems": [{ "type": "null" }] } +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (Array.isArray(data)) { + if (data[0] !== undefined && hasOwn(data, 0)) { + if (!(data[0] === null)) return false + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + diff --git a/doc/samples/draft-next/properties.md b/doc/samples/draft-next/properties.md new file mode 100644 index 0000000..3100ea9 --- /dev/null +++ b/doc/samples/draft-next/properties.md @@ -0,0 +1,240 @@ +# properties + +## object properties validation + +### Schema + +```json +{ "properties": { "foo": { "type": "integer" }, "bar": { "type": "string" } } } +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.foo !== undefined && hasOwn(data, "foo")) { + if (!Number.isInteger(data.foo)) return false + } + if (data.bar !== undefined && hasOwn(data, "bar")) { + if (!(typeof data.bar === "string")) return false + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireStringValidation] pattern, format or contentSchema should be specified for strings, use pattern: ^[\s\S]*$ to opt-out at #/properties/bar` + + +## properties, patternProperties, additionalProperties interaction + +### Schema + +```json +{ + "properties": { + "foo": { "type": "array", "maxItems": 3 }, + "bar": { "type": "array" } + }, + "patternProperties": { "f.o": { "minItems": 2 } }, + "additionalProperties": { "type": "integer" } +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const pattern0 = new RegExp("f.o", "u"); +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.foo !== undefined && hasOwn(data, "foo")) { + if (!Array.isArray(data.foo)) return false + if (data.foo.length > 3) return false + } + if (data.bar !== undefined && hasOwn(data, "bar")) { + if (!Array.isArray(data.bar)) return false + } + for (const key0 of Object.keys(data)) { + if (pattern0.test(key0)) { + if (Array.isArray(data[key0])) { + if (data[key0].length < 2) return false + } + } + } + for (const key1 of Object.keys(data)) { + if (key1 !== "foo" && key1 !== "bar" && !pattern0.test(key1)) { + if (!(Number.isInteger(data[key1]))) return false + } + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] items rule should be specified at #/properties/foo` + + +## properties with boolean schema + +### Schema + +```json +{ "properties": { "foo": true, "bar": false } } +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.bar !== undefined && hasOwn(data, "bar")) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] schema = true is not allowed at #/properties/foo` + + +## properties with escaped characters + +### Schema + +```json +{ + "properties": { + "foo\nbar": { "type": "number" }, + "foo\"bar": { "type": "number" }, + "foo\\bar": { "type": "number" }, + "foo\rbar": { "type": "number" }, + "foo\tbar": { "type": "number" }, + "foo\fbar": { "type": "number" } + } +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data["foo\nbar"] !== undefined && hasOwn(data, "foo\nbar")) { + if (!(typeof data["foo\nbar"] === "number")) return false + } + if (data["foo\"bar"] !== undefined && hasOwn(data, "foo\"bar")) { + if (!(typeof data["foo\"bar"] === "number")) return false + } + if (data["foo\\bar"] !== undefined && hasOwn(data, "foo\\bar")) { + if (!(typeof data["foo\\bar"] === "number")) return false + } + if (data["foo\rbar"] !== undefined && hasOwn(data, "foo\rbar")) { + if (!(typeof data["foo\rbar"] === "number")) return false + } + if (data["foo\tbar"] !== undefined && hasOwn(data, "foo\tbar")) { + if (!(typeof data["foo\tbar"] === "number")) return false + } + if (data["foo\fbar"] !== undefined && hasOwn(data, "foo\fbar")) { + if (!(typeof data["foo\fbar"] === "number")) return false + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## properties with null valued instance properties + +### Schema + +```json +{ "properties": { "foo": { "type": "null" } } } +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.foo !== undefined && hasOwn(data, "foo")) { + if (!(data.foo === null)) return false + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## properties whose names are Javascript object property names + +### Schema + +```json +{ + "properties": { + "__proto__": { "type": "number" }, + "toString": { "properties": { "length": { "type": "string" } } }, + "constructor": { "type": "number" } + } +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data["__proto__"] !== undefined && hasOwn(data, "__proto__")) { + if (!(typeof data["__proto__"] === "number")) return false + } + if (data.toString !== undefined && hasOwn(data, "toString")) { + if (typeof data.toString === "object" && data.toString && !Array.isArray(data.toString)) { + if (data.toString.length !== undefined && hasOwn(data.toString, "length")) { + if (!(typeof data.toString.length === "string")) return false + } + } + } + if (data.constructor !== undefined && hasOwn(data, "constructor")) { + if (!(typeof data.constructor === "number")) return false + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireStringValidation] pattern, format or contentSchema should be specified for strings, use pattern: ^[\s\S]*$ to opt-out at #/properties/toString/properties/length` + diff --git a/doc/samples/draft-next/propertyDependencies.md b/doc/samples/draft-next/propertyDependencies.md new file mode 100644 index 0000000..4eb93a3 --- /dev/null +++ b/doc/samples/draft-next/propertyDependencies.md @@ -0,0 +1,83 @@ +# propertyDependencies + +## propertyDependencies doesn't act on non-objects + +### Schema + +```json +{ "propertyDependencies": { "foo": { "bar": false } } } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + return true +}; +return ref0 +``` + +### Warnings + + * `Keyword not supported: "propertyDependencies" at #` + + +## propertyDependencies doesn't act on non-string property values + +### Schema + +```json +{ "propertyDependencies": { "foo": { "bar": false } } } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + return true +}; +return ref0 +``` + +### Warnings + + * `Keyword not supported: "propertyDependencies" at #` + + +## multiple options selects the right one + +### Schema + +```json +{ + "propertyDependencies": { + "foo": { + "bar": { "minProperties": 2, "maxProperties": 2 }, + "baz": { "maxProperties": 1 }, + "qux": true, + "quux": false + } + } +} +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + return true +}; +return ref0 +``` + +### Warnings + + * `Keyword not supported: "propertyDependencies" at #` + +### Misclassified! + +**This schema caused 4 misclassifications!** + diff --git a/doc/samples/draft-next/propertyNames.md b/doc/samples/draft-next/propertyNames.md new file mode 100644 index 0000000..93f35a2 --- /dev/null +++ b/doc/samples/draft-next/propertyNames.md @@ -0,0 +1,80 @@ +# propertyNames + +## propertyNames validation + +### Schema + +```json +{ "propertyNames": { "maxLength": 3 } } +``` + +### Code + +```js +'use strict' +const stringLength = (string) => + /[\uD800-\uDFFF]/.test(string) ? [...string].length : string.length; +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + for (const key0 of Object.keys(data)) { + if (key0.length > 3 && stringLength(key0) > 3) return false + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireStringValidation] pattern, format or contentSchema should be specified for strings, use pattern: ^[\s\S]*$ to opt-out at #/propertyNames` + + +## propertyNames with boolean schema true + +### Schema + +```json +{ "propertyNames": true } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] schema = true is not allowed at #/propertyNames` + + +## propertyNames with boolean schema false + +### Schema + +```json +{ "propertyNames": false } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + for (const key0 of Object.keys(data)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + diff --git a/doc/samples/draft-next/ref.md b/doc/samples/draft-next/ref.md new file mode 100644 index 0000000..f040fe3 --- /dev/null +++ b/doc/samples/draft-next/ref.md @@ -0,0 +1,1939 @@ +# ref + +## root pointer ref + +### Schema + +```json +{ "properties": { "foo": { "$ref": "#" } }, "additionalProperties": false } +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.foo !== undefined && hasOwn(data, "foo")) { + if (!validate(data.foo)) return false + } + for (const key0 of Object.keys(data)) { + if (key0 !== "foo") return false + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #/properties/foo` + + +## relative pointer ref to object + +### Schema + +```json +{ + "properties": { + "foo": { "type": "integer" }, + "bar": { "$ref": "#/properties/foo" } + } +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref1 = function validate(data) { + if (!Number.isInteger(data)) return false + return true +}; +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.foo !== undefined && hasOwn(data, "foo")) { + if (!Number.isInteger(data.foo)) return false + } + if (data.bar !== undefined && hasOwn(data, "bar")) { + if (!ref1(data.bar)) return false + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## relative pointer ref to array + +### Schema + +```json +{ "prefixItems": [{ "type": "integer" }, { "$ref": "#/prefixItems/0" }] } +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref1 = function validate(data) { + if (!Number.isInteger(data)) return false + return true +}; +const ref0 = function validate(data) { + if (Array.isArray(data)) { + if (data[0] !== undefined && hasOwn(data, 0)) { + if (!(Number.isInteger(data[0]))) return false + } + if (data[1] !== undefined && hasOwn(data, 1)) { + if (!ref1(data[1])) return false + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## escaped pointer ref + +### Schema + +```json +{ + "$defs": { + "tilde~field": { "type": "integer" }, + "slash/field": { "type": "integer" }, + "percent%field": { "type": "integer" } + }, + "properties": { + "tilde": { "$ref": "#/$defs/tilde~0field" }, + "slash": { "$ref": "#/$defs/slash~1field" }, + "percent": { "$ref": "#/$defs/percent%25field" } + } +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref1 = function validate(data) { + if (!Number.isInteger(data)) return false + return true +}; +const ref2 = function validate(data) { + if (!Number.isInteger(data)) return false + return true +}; +const ref3 = function validate(data) { + if (!Number.isInteger(data)) return false + return true +}; +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.tilde !== undefined && hasOwn(data, "tilde")) { + if (!ref1(data.tilde)) return false + } + if (data.slash !== undefined && hasOwn(data, "slash")) { + if (!ref2(data.slash)) return false + } + if (data.percent !== undefined && hasOwn(data, "percent")) { + if (!ref3(data.percent)) return false + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## nested refs + +### Schema + +```json +{ + "$defs": { + "a": { "type": "integer" }, + "b": { "$ref": "#/$defs/a" }, + "c": { "$ref": "#/$defs/b" } + }, + "$ref": "#/$defs/c" +} +``` + +### Code + +```js +'use strict' +const ref3 = function validate(data) { + if (!Number.isInteger(data)) return false + return true +}; +const ref2 = function validate(data) { + if (!ref3(data)) return false + return true +}; +const ref1 = function validate(data) { + if (!ref2(data)) return false + return true +}; +const ref0 = function validate(data) { + if (!ref1(data)) return false + return true +}; +return ref0 +``` + + +## ref applies alongside sibling keywords + +### Schema + +```json +{ + "$defs": { "reffed": { "type": "array" } }, + "properties": { "foo": { "$ref": "#/$defs/reffed", "maxItems": 2 } } +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref1 = function validate(data) { + if (!Array.isArray(data)) return false + return true +}; +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.foo !== undefined && hasOwn(data, "foo")) { + if (!ref1(data.foo)) return false + if (data.foo.length > 2) return false + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] items rule should be specified at #` + + +## remote ref, containing refs itself + +### Schema + +```json +{ "$ref": "https://json-schema.org/draft/next/schema" } +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const dynamicResolve = (anchors, id) => (anchors.filter((x) => x[id])[0] || {})[id]; +const unique = (array) => { + if (array.length < 2) return true + if (array.length === 2) return !deepEqual(array[0], array[1]) + const objects = [] + const primitives = array.length > 20 ? new Set() : null + let primitivesCount = 0 + let pos = 0 + for (const item of array) { + if (typeof item === 'object') { + objects.push(item) + } else if (primitives) { + primitives.add(item) + if (primitives.size !== ++primitivesCount) return false + } else { + if (array.indexOf(item, pos + 1) !== -1) return false + } + pos++ + } + for (let i = 1; i < objects.length; i++) + for (let j = 0; j < i; j++) if (deepEqual(objects[i], objects[j])) return false + return true +}; +const deepEqual = (obj, obj2) => { + if (obj === obj2) return true + if (!obj || !obj2 || typeof obj !== typeof obj2) return false + if (obj !== obj2 && typeof obj !== 'object') return false + + const proto = Object.getPrototypeOf(obj) + if (proto !== Object.getPrototypeOf(obj2)) return false + + if (proto === Array.prototype) { + if (!Array.isArray(obj) || !Array.isArray(obj2)) return false + if (obj.length !== obj2.length) return false + return obj.every((x, i) => deepEqual(x, obj2[i])) + } else if (proto === Object.prototype) { + const [keys, keys2] = [Object.keys(obj), Object.keys(obj2)] + if (keys.length !== keys2.length) return false + const keyset2 = new Set([...keys, ...keys2]) + return keyset2.size === keys.length && keys.every((key) => deepEqual(obj[key], obj2[key])) + } + return false +}; +const ref2 = function validate(data, dynAnchors) { + if (!Array.isArray(data)) return false + for (let i = 0; i < data.length; i++) { + if (data[i] !== undefined && hasOwn(data, i)) { + if (!(typeof data[i] === "string")) return false + } + } + if (!unique(data)) return false + return true +}; +const pattern0 = new RegExp("^[A-Za-z_][-A-Za-z0-9._]*$", "u"); +const ref3 = function validate(data, dynAnchors) { + if (!(typeof data === "string")) return false + if (!pattern0.test(data)) return false + return true +}; +const format0 = new RegExp("^(?:[a-z][a-z0-9+\\-.]*:)?(?:\\/?\\/(?:(?:[a-z0-9\\-._~!$&'()*+,;=:]|%[0-9a-f]{2})*@)?(?:\\[(?:(?:(?:(?:[0-9a-f]{1,4}:){6}|::(?:[0-9a-f]{1,4}:){5}|(?:[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){4}|(?:(?:[0-9a-f]{1,4}:){0,1}[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){3}|(?:(?:[0-9a-f]{1,4}:){0,2}[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){2}|(?:(?:[0-9a-f]{1,4}:){0,3}[0-9a-f]{1,4})?::[0-9a-f]{1,4}:|(?:(?:[0-9a-f]{1,4}:){0,4}[0-9a-f]{1,4})?::)(?:[0-9a-f]{1,4}:[0-9a-f]{1,4}|(?:(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d\\d?)\\.){3}(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d\\d?))|(?:(?:[0-9a-f]{1,4}:){0,5}[0-9a-f]{1,4})?::[0-9a-f]{1,4}|(?:(?:[0-9a-f]{1,4}:){0,6}[0-9a-f]{1,4})?::)|v[0-9a-f]+\\.[a-z0-9\\-._~!$&'()*+,;=:]+)\\]|(?:(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d\\d?)\\.){3}(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d\\d?)|(?:[a-z0-9\\-._~!$&'()*+,;=]|%[0-9a-f]{2})*)(?::\\d*)?(?:\\/(?:[a-z0-9\\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})*)*|\\/?(?:(?:[a-z0-9\\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})+(?:\\/(?:[a-z0-9\\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})*)*)?)?(?:\\?(?:[a-z0-9\\-._~!$&'()*+,;=:@/?]|%[0-9a-f]{2})*)?(?:#(?:[a-z0-9\\-._~!$&'()*+,;=:@/?]|%[0-9a-f]{2})*)?$", "i"); +const ref4 = function validate(data, dynAnchors) { + if (!(typeof data === "string")) return false + if (!format0.test(data)) return false + return true +}; +const pattern1 = new RegExp("^[^#]*#?$", "u"); +const format1 = new RegExp("^[a-z][a-z0-9+\\-.]*:(?:\\/?\\/(?:(?:[a-z0-9\\-._~!$&'()*+,;=:]|%[0-9a-f]{2})*@)?(?:\\[(?:(?:(?:(?:[0-9a-f]{1,4}:){6}|::(?:[0-9a-f]{1,4}:){5}|(?:[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){4}|(?:(?:[0-9a-f]{1,4}:){0,1}[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){3}|(?:(?:[0-9a-f]{1,4}:){0,2}[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){2}|(?:(?:[0-9a-f]{1,4}:){0,3}[0-9a-f]{1,4})?::[0-9a-f]{1,4}:|(?:(?:[0-9a-f]{1,4}:){0,4}[0-9a-f]{1,4})?::)(?:[0-9a-f]{1,4}:[0-9a-f]{1,4}|(?:(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d\\d?)\\.){3}(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d\\d?))|(?:(?:[0-9a-f]{1,4}:){0,5}[0-9a-f]{1,4})?::[0-9a-f]{1,4}|(?:(?:[0-9a-f]{1,4}:){0,6}[0-9a-f]{1,4})?::)|v[0-9a-f]+\\.[a-z0-9\\-._~!$&'()*+,;=:]+)\\]|(?:(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d\\d?)\\.){3}(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d\\d?)|(?:[a-z0-9\\-._~!$&'()*+,;=]|%[0-9a-f]{2})*)(?::\\d*)?(?:\\/(?:[a-z0-9\\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})*)*|\\/?(?:(?:[a-z0-9\\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})+(?:\\/(?:[a-z0-9\\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})*)*)?)(?:\\?(?:[a-z0-9\\-._~!$&'()*+,;=:@/?]|%[0-9a-f]{2})*)?(?:#(?:[a-z0-9\\-._~!$&'()*+,;=:@/?]|%[0-9a-f]{2})*)?$", "i"); +const ref6 = function validate(data, dynAnchors) { + if (!(typeof data === "string")) return false + if (!format1.test(data)) return false + return true +}; +const ref5 = function validate(data, dynAnchors = []) { + const dynLocal = [{}] + dynLocal[0]["#meta"] = validate + if (!(typeof data === "object" && data && !Array.isArray(data) || typeof data === "boolean")) return false + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data["$id"] !== undefined && hasOwn(data, "$id")) { + if (!ref4(data["$id"], [...dynAnchors, dynLocal[0] || []])) return false + if (!(pattern1.test(data["$id"]))) return false + } + if (data["$schema"] !== undefined && hasOwn(data, "$schema")) { + if (!ref6(data["$schema"], [...dynAnchors, dynLocal[0] || []])) return false + } + if (data["$ref"] !== undefined && hasOwn(data, "$ref")) { + if (!ref4(data["$ref"], [...dynAnchors, dynLocal[0] || []])) return false + } + if (data["$anchor"] !== undefined && hasOwn(data, "$anchor")) { + if (!ref3(data["$anchor"], [...dynAnchors, dynLocal[0] || []])) return false + } + if (data["$dynamicRef"] !== undefined && hasOwn(data, "$dynamicRef")) { + if (!ref4(data["$dynamicRef"], [...dynAnchors, dynLocal[0] || []])) return false + } + if (data["$dynamicAnchor"] !== undefined && hasOwn(data, "$dynamicAnchor")) { + if (!ref3(data["$dynamicAnchor"], [...dynAnchors, dynLocal[0] || []])) return false + } + if (data["$vocabulary"] !== undefined && hasOwn(data, "$vocabulary")) { + if (!(typeof data["$vocabulary"] === "object" && data["$vocabulary"] && !Array.isArray(data["$vocabulary"]))) return false + for (const key2 of Object.keys(data["$vocabulary"])) { + if (!ref6(key2, [...dynAnchors, dynLocal[0] || []])) return false + } + for (const key3 of Object.keys(data["$vocabulary"])) { + if (!(typeof data["$vocabulary"][key3] === "boolean")) return false + } + } + if (data["$comment"] !== undefined && hasOwn(data, "$comment")) { + if (!(typeof data["$comment"] === "string")) return false + } + if (data["$defs"] !== undefined && hasOwn(data, "$defs")) { + if (!(typeof data["$defs"] === "object" && data["$defs"] && !Array.isArray(data["$defs"]))) return false + for (const key4 of Object.keys(data["$defs"])) { + if (!(dynamicResolve(dynAnchors || [], "#meta") || validate)(data["$defs"][key4], [...dynAnchors, dynLocal[0] || []])) return false + } + } + } + return true +}; +const ref8 = function validate(data, dynAnchors) { + if (!Array.isArray(data)) return false + if (data.length < 1) return false + for (let j = 0; j < data.length; j++) { + if (data[j] !== undefined && hasOwn(data, j)) { + if (!(dynamicResolve(dynAnchors || [], "#meta") || ref7)(data[j], dynAnchors)) return false + } + } + return true +}; +const format2 = (str) => { + if (str.length > 1e5) return false + const Z_ANCHOR = /[^\\]\\Z/ + if (Z_ANCHOR.test(str)) return false + try { + new RegExp(str, 'u') + return true + } catch (e) { + return false + } + }; +const ref7 = function validate(data, dynAnchors = []) { + const dynLocal = [{}] + dynLocal[0]["#meta"] = validate + if (!(typeof data === "object" && data && !Array.isArray(data) || typeof data === "boolean")) return false + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.prefixItems !== undefined && hasOwn(data, "prefixItems")) { + if (!ref8(data.prefixItems, [...dynAnchors, dynLocal[0] || []])) return false + } + if (data.items !== undefined && hasOwn(data, "items")) { + if (!(dynamicResolve(dynAnchors || [], "#meta") || validate)(data.items, [...dynAnchors, dynLocal[0] || []])) return false + } + if (data.contains !== undefined && hasOwn(data, "contains")) { + if (!(dynamicResolve(dynAnchors || [], "#meta") || validate)(data.contains, [...dynAnchors, dynLocal[0] || []])) return false + } + if (data.additionalProperties !== undefined && hasOwn(data, "additionalProperties")) { + if (!(dynamicResolve(dynAnchors || [], "#meta") || validate)(data.additionalProperties, [...dynAnchors, dynLocal[0] || []])) return false + } + if (data.properties !== undefined && hasOwn(data, "properties")) { + if (!(typeof data.properties === "object" && data.properties && !Array.isArray(data.properties))) return false + for (const key5 of Object.keys(data.properties)) { + if (!(dynamicResolve(dynAnchors || [], "#meta") || validate)(data.properties[key5], [...dynAnchors, dynLocal[0] || []])) return false + } + } + if (data.patternProperties !== undefined && hasOwn(data, "patternProperties")) { + if (!(typeof data.patternProperties === "object" && data.patternProperties && !Array.isArray(data.patternProperties))) return false + for (const key6 of Object.keys(data.patternProperties)) { + if (!format2(key6)) return false + } + for (const key7 of Object.keys(data.patternProperties)) { + if (!(dynamicResolve(dynAnchors || [], "#meta") || validate)(data.patternProperties[key7], [...dynAnchors, dynLocal[0] || []])) return false + } + } + if (data.dependentSchemas !== undefined && hasOwn(data, "dependentSchemas")) { + if (!(typeof data.dependentSchemas === "object" && data.dependentSchemas && !Array.isArray(data.dependentSchemas))) return false + for (const key8 of Object.keys(data.dependentSchemas)) { + if (!(dynamicResolve(dynAnchors || [], "#meta") || validate)(data.dependentSchemas[key8], [...dynAnchors, dynLocal[0] || []])) return false + } + } + if (data.propertyNames !== undefined && hasOwn(data, "propertyNames")) { + if (!(dynamicResolve(dynAnchors || [], "#meta") || validate)(data.propertyNames, [...dynAnchors, dynLocal[0] || []])) return false + } + if (data.if !== undefined && hasOwn(data, "if")) { + if (!(dynamicResolve(dynAnchors || [], "#meta") || validate)(data.if, [...dynAnchors, dynLocal[0] || []])) return false + } + if (data.then !== undefined && hasOwn(data, "then")) { + if (!(dynamicResolve(dynAnchors || [], "#meta") || validate)(data.then, [...dynAnchors, dynLocal[0] || []])) return false + } + if (data.else !== undefined && hasOwn(data, "else")) { + if (!(dynamicResolve(dynAnchors || [], "#meta") || validate)(data.else, [...dynAnchors, dynLocal[0] || []])) return false + } + if (data.allOf !== undefined && hasOwn(data, "allOf")) { + if (!ref8(data.allOf, [...dynAnchors, dynLocal[0] || []])) return false + } + if (data.anyOf !== undefined && hasOwn(data, "anyOf")) { + if (!ref8(data.anyOf, [...dynAnchors, dynLocal[0] || []])) return false + } + if (data.oneOf !== undefined && hasOwn(data, "oneOf")) { + if (!ref8(data.oneOf, [...dynAnchors, dynLocal[0] || []])) return false + } + if (data.not !== undefined && hasOwn(data, "not")) { + if (!(dynamicResolve(dynAnchors || [], "#meta") || validate)(data.not, [...dynAnchors, dynLocal[0] || []])) return false + } + } + return true +}; +const ref9 = function validate(data, dynAnchors = []) { + const dynLocal = [{}] + dynLocal[0]["#meta"] = validate + if (!(typeof data === "object" && data && !Array.isArray(data) || typeof data === "boolean")) return false + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.unevaluatedItems !== undefined && hasOwn(data, "unevaluatedItems")) { + if (!(dynamicResolve(dynAnchors || [], "#meta") || validate)(data.unevaluatedItems, [...dynAnchors, dynLocal[0] || []])) return false + } + if (data.unevaluatedProperties !== undefined && hasOwn(data, "unevaluatedProperties")) { + if (!(dynamicResolve(dynAnchors || [], "#meta") || validate)(data.unevaluatedProperties, [...dynAnchors, dynLocal[0] || []])) return false + } + } + return true +}; +const ref11 = function validate(data, dynAnchors) { + if (!(data === "array" || data === "boolean" || data === "integer" || data === "null" || data === "number" || data === "object" || data === "string")) return false + return true +}; +const ref12 = function validate(data, dynAnchors) { + if (!Number.isInteger(data)) return false + if (!(0 <= data)) return false + return true +}; +const ref13 = function validate(data, dynAnchors) { + if (!ref12(data, dynAnchors)) return false + return true +}; +const ref10 = function validate(data, dynAnchors = []) { + const dynLocal = [{}] + dynLocal[0]["#meta"] = validate + if (!(typeof data === "object" && data && !Array.isArray(data) || typeof data === "boolean")) return false + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.type !== undefined && hasOwn(data, "type")) { + const sub2 = (() => { + if (!ref11(data.type, [...dynAnchors, dynLocal[0] || []])) return false + return true + })() + if (!sub2) { + const sub3 = (() => { + if (!Array.isArray(data.type)) return false + if (data.type.length < 1) return false + for (let k = 0; k < data.type.length; k++) { + if (data.type[k] !== undefined && hasOwn(data.type, k)) { + if (!ref11(data.type[k], [...dynAnchors, dynLocal[0] || []])) return false + } + } + if (!unique(data.type)) return false + return true + })() + if (!sub3) return false + } + } + if (data.enum !== undefined && hasOwn(data, "enum")) { + if (!Array.isArray(data.enum)) return false + } + if (data.multipleOf !== undefined && hasOwn(data, "multipleOf")) { + if (!(typeof data.multipleOf === "number")) return false + if (!(0 < data.multipleOf)) return false + } + if (data.maximum !== undefined && hasOwn(data, "maximum")) { + if (!(typeof data.maximum === "number")) return false + } + if (data.exclusiveMaximum !== undefined && hasOwn(data, "exclusiveMaximum")) { + if (!(typeof data.exclusiveMaximum === "number")) return false + } + if (data.minimum !== undefined && hasOwn(data, "minimum")) { + if (!(typeof data.minimum === "number")) return false + } + if (data.exclusiveMinimum !== undefined && hasOwn(data, "exclusiveMinimum")) { + if (!(typeof data.exclusiveMinimum === "number")) return false + } + if (data.maxLength !== undefined && hasOwn(data, "maxLength")) { + if (!ref12(data.maxLength, [...dynAnchors, dynLocal[0] || []])) return false + } + if (data.minLength !== undefined && hasOwn(data, "minLength")) { + if (!ref13(data.minLength, [...dynAnchors, dynLocal[0] || []])) return false + } + if (data.pattern !== undefined && hasOwn(data, "pattern")) { + if (!(typeof data.pattern === "string")) return false + if (!format2(data.pattern)) return false + } + if (data.maxItems !== undefined && hasOwn(data, "maxItems")) { + if (!ref12(data.maxItems, [...dynAnchors, dynLocal[0] || []])) return false + } + if (data.minItems !== undefined && hasOwn(data, "minItems")) { + if (!ref13(data.minItems, [...dynAnchors, dynLocal[0] || []])) return false + } + if (data.uniqueItems !== undefined && hasOwn(data, "uniqueItems")) { + if (!(typeof data.uniqueItems === "boolean")) return false + } + if (data.maxContains !== undefined && hasOwn(data, "maxContains")) { + if (!ref12(data.maxContains, [...dynAnchors, dynLocal[0] || []])) return false + } + if (data.minContains !== undefined && hasOwn(data, "minContains")) { + if (!ref12(data.minContains, [...dynAnchors, dynLocal[0] || []])) return false + } + if (data.maxProperties !== undefined && hasOwn(data, "maxProperties")) { + if (!ref12(data.maxProperties, [...dynAnchors, dynLocal[0] || []])) return false + } + if (data.minProperties !== undefined && hasOwn(data, "minProperties")) { + if (!ref13(data.minProperties, [...dynAnchors, dynLocal[0] || []])) return false + } + if (data.required !== undefined && hasOwn(data, "required")) { + if (!ref2(data.required, [...dynAnchors, dynLocal[0] || []])) return false + } + if (data.dependentRequired !== undefined && hasOwn(data, "dependentRequired")) { + if (!(typeof data.dependentRequired === "object" && data.dependentRequired && !Array.isArray(data.dependentRequired))) return false + for (const key9 of Object.keys(data.dependentRequired)) { + if (!ref2(data.dependentRequired[key9], [...dynAnchors, dynLocal[0] || []])) return false + } + } + } + return true +}; +const ref14 = function validate(data, dynAnchors) { + if (!(typeof data === "object" && data && !Array.isArray(data) || typeof data === "boolean")) return false + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.title !== undefined && hasOwn(data, "title")) { + if (!(typeof data.title === "string")) return false + } + if (data.description !== undefined && hasOwn(data, "description")) { + if (!(typeof data.description === "string")) return false + } + if (data.deprecated !== undefined && hasOwn(data, "deprecated")) { + if (!(typeof data.deprecated === "boolean")) return false + } + if (data.readOnly !== undefined && hasOwn(data, "readOnly")) { + if (!(typeof data.readOnly === "boolean")) return false + } + if (data.writeOnly !== undefined && hasOwn(data, "writeOnly")) { + if (!(typeof data.writeOnly === "boolean")) return false + } + if (data.examples !== undefined && hasOwn(data, "examples")) { + if (!Array.isArray(data.examples)) return false + } + } + return true +}; +const ref15 = function validate(data, dynAnchors) { + if (!(typeof data === "object" && data && !Array.isArray(data) || typeof data === "boolean")) return false + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.format !== undefined && hasOwn(data, "format")) { + if (!(typeof data.format === "string")) return false + } + } + return true +}; +const ref16 = function validate(data, dynAnchors = []) { + const dynLocal = [{}] + dynLocal[0]["#meta"] = validate + if (!(typeof data === "object" && data && !Array.isArray(data) || typeof data === "boolean")) return false + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.contentEncoding !== undefined && hasOwn(data, "contentEncoding")) { + if (!(typeof data.contentEncoding === "string")) return false + } + if (data.contentMediaType !== undefined && hasOwn(data, "contentMediaType")) { + if (!(typeof data.contentMediaType === "string")) return false + } + if (data.contentSchema !== undefined && hasOwn(data, "contentSchema")) { + if (!(dynamicResolve(dynAnchors || [], "#meta") || validate)(data.contentSchema, [...dynAnchors, dynLocal[0] || []])) return false + } + } + return true +}; +const ref1 = function validate(data, dynAnchors = []) { + const dynLocal = [{}] + dynLocal[0]["#meta"] = validate + if (!(typeof data === "object" && data && !Array.isArray(data) || typeof data === "boolean")) return false + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.definitions !== undefined && hasOwn(data, "definitions")) { + if (!(typeof data.definitions === "object" && data.definitions && !Array.isArray(data.definitions))) return false + for (const key0 of Object.keys(data.definitions)) { + if (!(dynamicResolve(dynAnchors || [], "#meta") || validate)(data.definitions[key0], [...dynAnchors, dynLocal[0] || []])) return false + } + } + if (data.dependencies !== undefined && hasOwn(data, "dependencies")) { + if (!(typeof data.dependencies === "object" && data.dependencies && !Array.isArray(data.dependencies))) return false + for (const key1 of Object.keys(data.dependencies)) { + const sub0 = (() => { + if (!(dynamicResolve(dynAnchors || [], "#meta") || validate)(data.dependencies[key1], [...dynAnchors, dynLocal[0] || []])) return false + return true + })() + if (!sub0) { + const sub1 = (() => { + if (!ref2(data.dependencies[key1], [...dynAnchors, dynLocal[0] || []])) return false + return true + })() + if (!sub1) return false + } + } + } + if (data["$recursiveAnchor"] !== undefined && hasOwn(data, "$recursiveAnchor")) { + if (!ref3(data["$recursiveAnchor"], [...dynAnchors, dynLocal[0] || []])) return false + } + if (data["$recursiveRef"] !== undefined && hasOwn(data, "$recursiveRef")) { + if (!ref4(data["$recursiveRef"], [...dynAnchors, dynLocal[0] || []])) return false + } + } + if (!ref5(data, [...dynAnchors, dynLocal[0] || []])) return false + if (!ref7(data, [...dynAnchors, dynLocal[0] || []])) return false + if (!ref9(data, [...dynAnchors, dynLocal[0] || []])) return false + if (!ref10(data, [...dynAnchors, dynLocal[0] || []])) return false + if (!ref14(data, [...dynAnchors, dynLocal[0] || []])) return false + if (!ref15(data, [...dynAnchors, dynLocal[0] || []])) return false + if (!ref16(data, [...dynAnchors, dynLocal[0] || []])) return false + return true +}; +const ref0 = function validate(data, dynAnchors) { + if (!ref1(data, dynAnchors)) return false + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at https://json-schema.org/draft/next/schema#/properties/definitions/additionalProperties` + + +## property named $ref that is not a reference + +### Schema + +```json +{ "properties": { "$ref": { "type": "string" } } } +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data["$ref"] !== undefined && hasOwn(data, "$ref")) { + if (!(typeof data["$ref"] === "string")) return false + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireStringValidation] pattern, format or contentSchema should be specified for strings, use pattern: ^[\s\S]*$ to opt-out at #/properties/$ref` + + +## property named $ref, containing an actual $ref + +### Schema + +```json +{ + "properties": { "$ref": { "$ref": "#/$defs/is-string" } }, + "$defs": { "is-string": { "type": "string" } } +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref1 = function validate(data) { + if (!(typeof data === "string")) return false + return true +}; +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data["$ref"] !== undefined && hasOwn(data, "$ref")) { + if (!ref1(data["$ref"])) return false + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireStringValidation] pattern, format or contentSchema should be specified for strings, use pattern: ^[\s\S]*$ to opt-out at #` + + +## $ref to boolean schema true + +### Schema + +```json +{ "$ref": "#/$defs/bool", "$defs": { "bool": true } } +``` + +### Code + +```js +'use strict' +const ref1 = function validate(data) { + return true +}; +const ref0 = function validate(data) { + if (!ref1(data)) return false + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] schema = true is not allowed at #` + + +## $ref to boolean schema false + +### Schema + +```json +{ "$ref": "#/$defs/bool", "$defs": { "bool": false } } +``` + +### Code + +```js +'use strict' +const ref1 = function validate(data) { + return false + return true +}; +const ref0 = function validate(data) { + if (!ref1(data)) return false + return true +}; +return ref0 +``` + + +## Recursive references between schemas + +### Schema + +```json +{ + "$id": "http://localhost:1234/draft-next/tree", + "description": "tree of nodes", + "type": "object", + "properties": { + "meta": { "type": "string" }, + "nodes": { "type": "array", "items": { "$ref": "node" } } + }, + "required": ["meta", "nodes"], + "$defs": { + "node": { + "$id": "http://localhost:1234/draft-next/node", + "description": "node", + "type": "object", + "properties": { + "value": { "type": "number" }, + "subtree": { "$ref": "tree" } + }, + "required": ["value"] + } + } +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref1 = function validate(data) { + if (!(typeof data === "object" && data && !Array.isArray(data))) return false + if (!(data.value !== undefined && hasOwn(data, "value"))) return false + if (!(typeof data.value === "number")) return false + if (data.subtree !== undefined && hasOwn(data, "subtree")) { + if (!ref0(data.subtree)) return false + } + return true +}; +const ref0 = function validate(data) { + if (!(typeof data === "object" && data && !Array.isArray(data))) return false + if (!(data.meta !== undefined && hasOwn(data, "meta"))) return false + if (!(data.nodes !== undefined && hasOwn(data, "nodes"))) return false + if (!(typeof data.meta === "string")) return false + if (!Array.isArray(data.nodes)) return false + for (let i = 0; i < data.nodes.length; i++) { + if (data.nodes[i] !== undefined && hasOwn(data.nodes, i)) { + if (!ref1(data.nodes[i])) return false + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireStringValidation] pattern, format or contentSchema should be specified for strings, use pattern: ^[\s\S]*$ to opt-out at #/properties/meta` + + +## refs with quote + +### Schema + +```json +{ + "properties": { "foo\"bar": { "$ref": "#/$defs/foo%22bar" } }, + "$defs": { "foo\"bar": { "type": "number" } } +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref1 = function validate(data) { + if (!(typeof data === "number")) return false + return true +}; +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data["foo\"bar"] !== undefined && hasOwn(data, "foo\"bar")) { + if (!ref1(data["foo\"bar"])) return false + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## ref creates new scope when adjacent to keywords + +### Schema + +```json +{ + "$defs": { "A": { "unevaluatedProperties": false } }, + "properties": { "prop1": { "type": "string" } }, + "$ref": "#/$defs/A" +} +``` + +### Code + +```js +'use strict' +const ref1 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + for (const key0 of Object.keys(data)) return false + } + return true +}; +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (!ref1(data)) return false + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.prop1 !== undefined && hasOwn(data, "prop1")) { + if (!(typeof data.prop1 === "string")) return false + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## naive replacement of $ref with its destination is not correct + +### Schema + +```json +{ + "$defs": { "a_string": { "type": "string" } }, + "enum": [{ "$ref": "#/$defs/a_string" }] +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (!(typeof data === "object" && data && !Array.isArray(data) && Object.keys(data).length === 1 && hasOwn(data, "$ref") && data["$ref"] === "#/$defs/a_string")) return false + return true +}; +return ref0 +``` + + +## refs with relative uris and defs + +### Schema + +```json +{ + "$id": "http://example.com/schema-relative-uri-defs1.json", + "properties": { + "foo": { + "$id": "schema-relative-uri-defs2.json", + "$defs": { "inner": { "properties": { "bar": { "type": "string" } } } }, + "$ref": "#/$defs/inner" + } + }, + "$ref": "schema-relative-uri-defs2.json" +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref2 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.bar !== undefined && hasOwn(data, "bar")) { + if (!(typeof data.bar === "string")) return false + } + } + return true +}; +const ref1 = function validate(data) { + if (!ref2(data)) return false + return true +}; +const ref0 = function validate(data) { + if (!ref1(data)) return false + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.foo !== undefined && hasOwn(data, "foo")) { + if (!ref2(data.foo)) return false + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireStringValidation] pattern, format or contentSchema should be specified for strings, use pattern: ^[\s\S]*$ to opt-out at http://example.com/schema-relative-uri-defs2.json#/properties/bar` + + +## relative refs with absolute uris and defs + +### Schema + +```json +{ + "$id": "http://example.com/schema-refs-absolute-uris-defs1.json", + "properties": { + "foo": { + "$id": "http://example.com/schema-refs-absolute-uris-defs2.json", + "$defs": { "inner": { "properties": { "bar": { "type": "string" } } } }, + "$ref": "#/$defs/inner" + } + }, + "$ref": "schema-refs-absolute-uris-defs2.json" +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref2 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.bar !== undefined && hasOwn(data, "bar")) { + if (!(typeof data.bar === "string")) return false + } + } + return true +}; +const ref1 = function validate(data) { + if (!ref2(data)) return false + return true +}; +const ref0 = function validate(data) { + if (!ref1(data)) return false + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.foo !== undefined && hasOwn(data, "foo")) { + if (!ref2(data.foo)) return false + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireStringValidation] pattern, format or contentSchema should be specified for strings, use pattern: ^[\s\S]*$ to opt-out at http://example.com/schema-refs-absolute-uris-defs2.json#/properties/bar` + + +## $id must be resolved against nearest parent, not just immediate parent + +### Schema + +```json +{ + "$id": "http://example.com/a.json", + "$defs": { + "x": { + "$id": "http://example.com/b/c.json", + "not": { "$defs": { "y": { "$id": "d.json", "type": "number" } } } + } + }, + "allOf": [{ "$ref": "http://example.com/b/d.json" }] +} +``` + +### Code + +```js +'use strict' +const ref1 = function validate(data) { + if (!(typeof data === "number")) return false + return true +}; +const ref0 = function validate(data) { + if (!ref1(data)) return false + return true +}; +return ref0 +``` + + +## order of evaluation: $id and $ref + +### Schema + +```json +{ + "$comment": "$id must be evaluated before $ref to get the proper $ref destination", + "$id": "/draft/next/ref-and-id1/base.json", + "$ref": "int.json", + "$defs": { + "bigint": { + "$comment": "canonical uri: /ref-and-id1/int.json", + "$id": "int.json", + "maximum": 10 + }, + "smallint": { + "$comment": "canonical uri: /ref-and-id1-int.json", + "$id": "/draft/next/ref-and-id1-int.json", + "maximum": 2 + } + } +} +``` + +### Code + +```js +'use strict' +const ref1 = function validate(data) { + if (typeof data === "number") { + if (!(10 >= data)) return false + } + return true +}; +const ref0 = function validate(data) { + if (!ref1(data)) return false + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at /draft/next/ref-and-id1/base.json#` + + +## order of evaluation: $id and $anchor and $ref + +### Schema + +```json +{ + "$comment": "$id must be evaluated before $ref to get the proper $ref destination", + "$id": "/draft/next/ref-and-id2/base.json", + "$ref": "#bigint", + "$defs": { + "bigint": { + "$comment": "canonical uri: /ref-and-id2/base.json/$defs/bigint; another valid uri for this location: /ref-and-id2/base.json#bigint", + "$anchor": "bigint", + "maximum": 10 + }, + "smallint": { + "$comment": "canonical uri: /ref-and-id2#/$defs/smallint; another valid uri for this location: /ref-and-id2/#bigint", + "$id": "/draft/next/ref-and-id2/", + "$anchor": "bigint", + "maximum": 2 + } + } +} +``` + +### Code + +```js +'use strict' +const ref1 = function validate(data) { + if (typeof data === "number") { + if (!(10 >= data)) return false + } + return true +}; +const ref0 = function validate(data) { + if (!ref1(data)) return false + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at /draft/next/ref-and-id2/base.json#` + + +## simple URN base URI with $ref via the URN + +### Schema + +```json +{ + "$comment": "URIs do not have to have HTTP(s) schemes", + "$id": "urn:uuid:deadbeef-1234-ffff-ffff-4321feebdaed", + "minimum": 30, + "properties": { + "foo": { "$ref": "urn:uuid:deadbeef-1234-ffff-ffff-4321feebdaed" } + } +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (typeof data === "number") { + if (!(30 <= data)) return false + } + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.foo !== undefined && hasOwn(data, "foo")) { + if (!validate(data.foo)) return false + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #/properties/foo` + + +## simple URN base URI with JSON pointer + +### Schema + +```json +{ + "$comment": "URIs do not have to have HTTP(s) schemes", + "$id": "urn:uuid:deadbeef-1234-00ff-ff00-4321feebdaed", + "properties": { "foo": { "$ref": "#/$defs/bar" } }, + "$defs": { "bar": { "type": "string" } } +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref1 = function validate(data) { + if (!(typeof data === "string")) return false + return true +}; +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.foo !== undefined && hasOwn(data, "foo")) { + if (!ref1(data.foo)) return false + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireStringValidation] pattern, format or contentSchema should be specified for strings, use pattern: ^[\s\S]*$ to opt-out at urn:uuid:deadbeef-1234-00ff-ff00-4321feebdaed#` + + +## URN base URI with NSS + +### Schema + +```json +{ + "$comment": "RFC 8141 §2.2", + "$id": "urn:example:1/406/47452/2", + "properties": { "foo": { "$ref": "#/$defs/bar" } }, + "$defs": { "bar": { "type": "string" } } +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref1 = function validate(data) { + if (!(typeof data === "string")) return false + return true +}; +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.foo !== undefined && hasOwn(data, "foo")) { + if (!ref1(data.foo)) return false + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireStringValidation] pattern, format or contentSchema should be specified for strings, use pattern: ^[\s\S]*$ to opt-out at urn:example:1/406/47452/2#` + + +## URN base URI with r-component + +### Schema + +```json +{ + "$comment": "RFC 8141 §2.3.1", + "$id": "urn:example:foo-bar-baz-qux?+CCResolve:cc=uk", + "properties": { "foo": { "$ref": "#/$defs/bar" } }, + "$defs": { "bar": { "type": "string" } } +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref1 = function validate(data) { + if (!(typeof data === "string")) return false + return true +}; +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.foo !== undefined && hasOwn(data, "foo")) { + if (!ref1(data.foo)) return false + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireStringValidation] pattern, format or contentSchema should be specified for strings, use pattern: ^[\s\S]*$ to opt-out at urn:example:foo-bar-baz-qux?+CCResolve:cc=uk#` + + +## URN base URI with q-component + +### Schema + +```json +{ + "$comment": "RFC 8141 §2.3.2", + "$id": "urn:example:weather?=op=map&lat=39.56&lon=-104.85&datetime=1969-07-21T02:56:15Z", + "properties": { "foo": { "$ref": "#/$defs/bar" } }, + "$defs": { "bar": { "type": "string" } } +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref1 = function validate(data) { + if (!(typeof data === "string")) return false + return true +}; +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.foo !== undefined && hasOwn(data, "foo")) { + if (!ref1(data.foo)) return false + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireStringValidation] pattern, format or contentSchema should be specified for strings, use pattern: ^[\s\S]*$ to opt-out at urn:example:weather?=op=map&lat=39.56&lon=-104.85&datetime=1969-07-21T02:56:15Z#` + + +## URN base URI with f-component + +### Schema + +```json +{ + "$comment": "RFC 8141 §2.3.3, but we don't allow fragments", + "$ref": "https://json-schema.org/draft/next/schema" +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const dynamicResolve = (anchors, id) => (anchors.filter((x) => x[id])[0] || {})[id]; +const unique = (array) => { + if (array.length < 2) return true + if (array.length === 2) return !deepEqual(array[0], array[1]) + const objects = [] + const primitives = array.length > 20 ? new Set() : null + let primitivesCount = 0 + let pos = 0 + for (const item of array) { + if (typeof item === 'object') { + objects.push(item) + } else if (primitives) { + primitives.add(item) + if (primitives.size !== ++primitivesCount) return false + } else { + if (array.indexOf(item, pos + 1) !== -1) return false + } + pos++ + } + for (let i = 1; i < objects.length; i++) + for (let j = 0; j < i; j++) if (deepEqual(objects[i], objects[j])) return false + return true +}; +const deepEqual = (obj, obj2) => { + if (obj === obj2) return true + if (!obj || !obj2 || typeof obj !== typeof obj2) return false + if (obj !== obj2 && typeof obj !== 'object') return false + + const proto = Object.getPrototypeOf(obj) + if (proto !== Object.getPrototypeOf(obj2)) return false + + if (proto === Array.prototype) { + if (!Array.isArray(obj) || !Array.isArray(obj2)) return false + if (obj.length !== obj2.length) return false + return obj.every((x, i) => deepEqual(x, obj2[i])) + } else if (proto === Object.prototype) { + const [keys, keys2] = [Object.keys(obj), Object.keys(obj2)] + if (keys.length !== keys2.length) return false + const keyset2 = new Set([...keys, ...keys2]) + return keyset2.size === keys.length && keys.every((key) => deepEqual(obj[key], obj2[key])) + } + return false +}; +const ref2 = function validate(data, dynAnchors) { + if (!Array.isArray(data)) return false + for (let i = 0; i < data.length; i++) { + if (data[i] !== undefined && hasOwn(data, i)) { + if (!(typeof data[i] === "string")) return false + } + } + if (!unique(data)) return false + return true +}; +const pattern0 = new RegExp("^[A-Za-z_][-A-Za-z0-9._]*$", "u"); +const ref3 = function validate(data, dynAnchors) { + if (!(typeof data === "string")) return false + if (!pattern0.test(data)) return false + return true +}; +const format0 = new RegExp("^(?:[a-z][a-z0-9+\\-.]*:)?(?:\\/?\\/(?:(?:[a-z0-9\\-._~!$&'()*+,;=:]|%[0-9a-f]{2})*@)?(?:\\[(?:(?:(?:(?:[0-9a-f]{1,4}:){6}|::(?:[0-9a-f]{1,4}:){5}|(?:[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){4}|(?:(?:[0-9a-f]{1,4}:){0,1}[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){3}|(?:(?:[0-9a-f]{1,4}:){0,2}[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){2}|(?:(?:[0-9a-f]{1,4}:){0,3}[0-9a-f]{1,4})?::[0-9a-f]{1,4}:|(?:(?:[0-9a-f]{1,4}:){0,4}[0-9a-f]{1,4})?::)(?:[0-9a-f]{1,4}:[0-9a-f]{1,4}|(?:(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d\\d?)\\.){3}(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d\\d?))|(?:(?:[0-9a-f]{1,4}:){0,5}[0-9a-f]{1,4})?::[0-9a-f]{1,4}|(?:(?:[0-9a-f]{1,4}:){0,6}[0-9a-f]{1,4})?::)|v[0-9a-f]+\\.[a-z0-9\\-._~!$&'()*+,;=:]+)\\]|(?:(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d\\d?)\\.){3}(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d\\d?)|(?:[a-z0-9\\-._~!$&'()*+,;=]|%[0-9a-f]{2})*)(?::\\d*)?(?:\\/(?:[a-z0-9\\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})*)*|\\/?(?:(?:[a-z0-9\\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})+(?:\\/(?:[a-z0-9\\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})*)*)?)?(?:\\?(?:[a-z0-9\\-._~!$&'()*+,;=:@/?]|%[0-9a-f]{2})*)?(?:#(?:[a-z0-9\\-._~!$&'()*+,;=:@/?]|%[0-9a-f]{2})*)?$", "i"); +const ref4 = function validate(data, dynAnchors) { + if (!(typeof data === "string")) return false + if (!format0.test(data)) return false + return true +}; +const pattern1 = new RegExp("^[^#]*#?$", "u"); +const format1 = new RegExp("^[a-z][a-z0-9+\\-.]*:(?:\\/?\\/(?:(?:[a-z0-9\\-._~!$&'()*+,;=:]|%[0-9a-f]{2})*@)?(?:\\[(?:(?:(?:(?:[0-9a-f]{1,4}:){6}|::(?:[0-9a-f]{1,4}:){5}|(?:[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){4}|(?:(?:[0-9a-f]{1,4}:){0,1}[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){3}|(?:(?:[0-9a-f]{1,4}:){0,2}[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){2}|(?:(?:[0-9a-f]{1,4}:){0,3}[0-9a-f]{1,4})?::[0-9a-f]{1,4}:|(?:(?:[0-9a-f]{1,4}:){0,4}[0-9a-f]{1,4})?::)(?:[0-9a-f]{1,4}:[0-9a-f]{1,4}|(?:(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d\\d?)\\.){3}(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d\\d?))|(?:(?:[0-9a-f]{1,4}:){0,5}[0-9a-f]{1,4})?::[0-9a-f]{1,4}|(?:(?:[0-9a-f]{1,4}:){0,6}[0-9a-f]{1,4})?::)|v[0-9a-f]+\\.[a-z0-9\\-._~!$&'()*+,;=:]+)\\]|(?:(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d\\d?)\\.){3}(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d\\d?)|(?:[a-z0-9\\-._~!$&'()*+,;=]|%[0-9a-f]{2})*)(?::\\d*)?(?:\\/(?:[a-z0-9\\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})*)*|\\/?(?:(?:[a-z0-9\\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})+(?:\\/(?:[a-z0-9\\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})*)*)?)(?:\\?(?:[a-z0-9\\-._~!$&'()*+,;=:@/?]|%[0-9a-f]{2})*)?(?:#(?:[a-z0-9\\-._~!$&'()*+,;=:@/?]|%[0-9a-f]{2})*)?$", "i"); +const ref6 = function validate(data, dynAnchors) { + if (!(typeof data === "string")) return false + if (!format1.test(data)) return false + return true +}; +const ref5 = function validate(data, dynAnchors = []) { + const dynLocal = [{}] + dynLocal[0]["#meta"] = validate + if (!(typeof data === "object" && data && !Array.isArray(data) || typeof data === "boolean")) return false + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data["$id"] !== undefined && hasOwn(data, "$id")) { + if (!ref4(data["$id"], [...dynAnchors, dynLocal[0] || []])) return false + if (!(pattern1.test(data["$id"]))) return false + } + if (data["$schema"] !== undefined && hasOwn(data, "$schema")) { + if (!ref6(data["$schema"], [...dynAnchors, dynLocal[0] || []])) return false + } + if (data["$ref"] !== undefined && hasOwn(data, "$ref")) { + if (!ref4(data["$ref"], [...dynAnchors, dynLocal[0] || []])) return false + } + if (data["$anchor"] !== undefined && hasOwn(data, "$anchor")) { + if (!ref3(data["$anchor"], [...dynAnchors, dynLocal[0] || []])) return false + } + if (data["$dynamicRef"] !== undefined && hasOwn(data, "$dynamicRef")) { + if (!ref4(data["$dynamicRef"], [...dynAnchors, dynLocal[0] || []])) return false + } + if (data["$dynamicAnchor"] !== undefined && hasOwn(data, "$dynamicAnchor")) { + if (!ref3(data["$dynamicAnchor"], [...dynAnchors, dynLocal[0] || []])) return false + } + if (data["$vocabulary"] !== undefined && hasOwn(data, "$vocabulary")) { + if (!(typeof data["$vocabulary"] === "object" && data["$vocabulary"] && !Array.isArray(data["$vocabulary"]))) return false + for (const key2 of Object.keys(data["$vocabulary"])) { + if (!ref6(key2, [...dynAnchors, dynLocal[0] || []])) return false + } + for (const key3 of Object.keys(data["$vocabulary"])) { + if (!(typeof data["$vocabulary"][key3] === "boolean")) return false + } + } + if (data["$comment"] !== undefined && hasOwn(data, "$comment")) { + if (!(typeof data["$comment"] === "string")) return false + } + if (data["$defs"] !== undefined && hasOwn(data, "$defs")) { + if (!(typeof data["$defs"] === "object" && data["$defs"] && !Array.isArray(data["$defs"]))) return false + for (const key4 of Object.keys(data["$defs"])) { + if (!(dynamicResolve(dynAnchors || [], "#meta") || validate)(data["$defs"][key4], [...dynAnchors, dynLocal[0] || []])) return false + } + } + } + return true +}; +const ref8 = function validate(data, dynAnchors) { + if (!Array.isArray(data)) return false + if (data.length < 1) return false + for (let j = 0; j < data.length; j++) { + if (data[j] !== undefined && hasOwn(data, j)) { + if (!(dynamicResolve(dynAnchors || [], "#meta") || ref7)(data[j], dynAnchors)) return false + } + } + return true +}; +const format2 = (str) => { + if (str.length > 1e5) return false + const Z_ANCHOR = /[^\\]\\Z/ + if (Z_ANCHOR.test(str)) return false + try { + new RegExp(str, 'u') + return true + } catch (e) { + return false + } + }; +const ref7 = function validate(data, dynAnchors = []) { + const dynLocal = [{}] + dynLocal[0]["#meta"] = validate + if (!(typeof data === "object" && data && !Array.isArray(data) || typeof data === "boolean")) return false + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.prefixItems !== undefined && hasOwn(data, "prefixItems")) { + if (!ref8(data.prefixItems, [...dynAnchors, dynLocal[0] || []])) return false + } + if (data.items !== undefined && hasOwn(data, "items")) { + if (!(dynamicResolve(dynAnchors || [], "#meta") || validate)(data.items, [...dynAnchors, dynLocal[0] || []])) return false + } + if (data.contains !== undefined && hasOwn(data, "contains")) { + if (!(dynamicResolve(dynAnchors || [], "#meta") || validate)(data.contains, [...dynAnchors, dynLocal[0] || []])) return false + } + if (data.additionalProperties !== undefined && hasOwn(data, "additionalProperties")) { + if (!(dynamicResolve(dynAnchors || [], "#meta") || validate)(data.additionalProperties, [...dynAnchors, dynLocal[0] || []])) return false + } + if (data.properties !== undefined && hasOwn(data, "properties")) { + if (!(typeof data.properties === "object" && data.properties && !Array.isArray(data.properties))) return false + for (const key5 of Object.keys(data.properties)) { + if (!(dynamicResolve(dynAnchors || [], "#meta") || validate)(data.properties[key5], [...dynAnchors, dynLocal[0] || []])) return false + } + } + if (data.patternProperties !== undefined && hasOwn(data, "patternProperties")) { + if (!(typeof data.patternProperties === "object" && data.patternProperties && !Array.isArray(data.patternProperties))) return false + for (const key6 of Object.keys(data.patternProperties)) { + if (!format2(key6)) return false + } + for (const key7 of Object.keys(data.patternProperties)) { + if (!(dynamicResolve(dynAnchors || [], "#meta") || validate)(data.patternProperties[key7], [...dynAnchors, dynLocal[0] || []])) return false + } + } + if (data.dependentSchemas !== undefined && hasOwn(data, "dependentSchemas")) { + if (!(typeof data.dependentSchemas === "object" && data.dependentSchemas && !Array.isArray(data.dependentSchemas))) return false + for (const key8 of Object.keys(data.dependentSchemas)) { + if (!(dynamicResolve(dynAnchors || [], "#meta") || validate)(data.dependentSchemas[key8], [...dynAnchors, dynLocal[0] || []])) return false + } + } + if (data.propertyNames !== undefined && hasOwn(data, "propertyNames")) { + if (!(dynamicResolve(dynAnchors || [], "#meta") || validate)(data.propertyNames, [...dynAnchors, dynLocal[0] || []])) return false + } + if (data.if !== undefined && hasOwn(data, "if")) { + if (!(dynamicResolve(dynAnchors || [], "#meta") || validate)(data.if, [...dynAnchors, dynLocal[0] || []])) return false + } + if (data.then !== undefined && hasOwn(data, "then")) { + if (!(dynamicResolve(dynAnchors || [], "#meta") || validate)(data.then, [...dynAnchors, dynLocal[0] || []])) return false + } + if (data.else !== undefined && hasOwn(data, "else")) { + if (!(dynamicResolve(dynAnchors || [], "#meta") || validate)(data.else, [...dynAnchors, dynLocal[0] || []])) return false + } + if (data.allOf !== undefined && hasOwn(data, "allOf")) { + if (!ref8(data.allOf, [...dynAnchors, dynLocal[0] || []])) return false + } + if (data.anyOf !== undefined && hasOwn(data, "anyOf")) { + if (!ref8(data.anyOf, [...dynAnchors, dynLocal[0] || []])) return false + } + if (data.oneOf !== undefined && hasOwn(data, "oneOf")) { + if (!ref8(data.oneOf, [...dynAnchors, dynLocal[0] || []])) return false + } + if (data.not !== undefined && hasOwn(data, "not")) { + if (!(dynamicResolve(dynAnchors || [], "#meta") || validate)(data.not, [...dynAnchors, dynLocal[0] || []])) return false + } + } + return true +}; +const ref9 = function validate(data, dynAnchors = []) { + const dynLocal = [{}] + dynLocal[0]["#meta"] = validate + if (!(typeof data === "object" && data && !Array.isArray(data) || typeof data === "boolean")) return false + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.unevaluatedItems !== undefined && hasOwn(data, "unevaluatedItems")) { + if (!(dynamicResolve(dynAnchors || [], "#meta") || validate)(data.unevaluatedItems, [...dynAnchors, dynLocal[0] || []])) return false + } + if (data.unevaluatedProperties !== undefined && hasOwn(data, "unevaluatedProperties")) { + if (!(dynamicResolve(dynAnchors || [], "#meta") || validate)(data.unevaluatedProperties, [...dynAnchors, dynLocal[0] || []])) return false + } + } + return true +}; +const ref11 = function validate(data, dynAnchors) { + if (!(data === "array" || data === "boolean" || data === "integer" || data === "null" || data === "number" || data === "object" || data === "string")) return false + return true +}; +const ref12 = function validate(data, dynAnchors) { + if (!Number.isInteger(data)) return false + if (!(0 <= data)) return false + return true +}; +const ref13 = function validate(data, dynAnchors) { + if (!ref12(data, dynAnchors)) return false + return true +}; +const ref10 = function validate(data, dynAnchors = []) { + const dynLocal = [{}] + dynLocal[0]["#meta"] = validate + if (!(typeof data === "object" && data && !Array.isArray(data) || typeof data === "boolean")) return false + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.type !== undefined && hasOwn(data, "type")) { + const sub2 = (() => { + if (!ref11(data.type, [...dynAnchors, dynLocal[0] || []])) return false + return true + })() + if (!sub2) { + const sub3 = (() => { + if (!Array.isArray(data.type)) return false + if (data.type.length < 1) return false + for (let k = 0; k < data.type.length; k++) { + if (data.type[k] !== undefined && hasOwn(data.type, k)) { + if (!ref11(data.type[k], [...dynAnchors, dynLocal[0] || []])) return false + } + } + if (!unique(data.type)) return false + return true + })() + if (!sub3) return false + } + } + if (data.enum !== undefined && hasOwn(data, "enum")) { + if (!Array.isArray(data.enum)) return false + } + if (data.multipleOf !== undefined && hasOwn(data, "multipleOf")) { + if (!(typeof data.multipleOf === "number")) return false + if (!(0 < data.multipleOf)) return false + } + if (data.maximum !== undefined && hasOwn(data, "maximum")) { + if (!(typeof data.maximum === "number")) return false + } + if (data.exclusiveMaximum !== undefined && hasOwn(data, "exclusiveMaximum")) { + if (!(typeof data.exclusiveMaximum === "number")) return false + } + if (data.minimum !== undefined && hasOwn(data, "minimum")) { + if (!(typeof data.minimum === "number")) return false + } + if (data.exclusiveMinimum !== undefined && hasOwn(data, "exclusiveMinimum")) { + if (!(typeof data.exclusiveMinimum === "number")) return false + } + if (data.maxLength !== undefined && hasOwn(data, "maxLength")) { + if (!ref12(data.maxLength, [...dynAnchors, dynLocal[0] || []])) return false + } + if (data.minLength !== undefined && hasOwn(data, "minLength")) { + if (!ref13(data.minLength, [...dynAnchors, dynLocal[0] || []])) return false + } + if (data.pattern !== undefined && hasOwn(data, "pattern")) { + if (!(typeof data.pattern === "string")) return false + if (!format2(data.pattern)) return false + } + if (data.maxItems !== undefined && hasOwn(data, "maxItems")) { + if (!ref12(data.maxItems, [...dynAnchors, dynLocal[0] || []])) return false + } + if (data.minItems !== undefined && hasOwn(data, "minItems")) { + if (!ref13(data.minItems, [...dynAnchors, dynLocal[0] || []])) return false + } + if (data.uniqueItems !== undefined && hasOwn(data, "uniqueItems")) { + if (!(typeof data.uniqueItems === "boolean")) return false + } + if (data.maxContains !== undefined && hasOwn(data, "maxContains")) { + if (!ref12(data.maxContains, [...dynAnchors, dynLocal[0] || []])) return false + } + if (data.minContains !== undefined && hasOwn(data, "minContains")) { + if (!ref12(data.minContains, [...dynAnchors, dynLocal[0] || []])) return false + } + if (data.maxProperties !== undefined && hasOwn(data, "maxProperties")) { + if (!ref12(data.maxProperties, [...dynAnchors, dynLocal[0] || []])) return false + } + if (data.minProperties !== undefined && hasOwn(data, "minProperties")) { + if (!ref13(data.minProperties, [...dynAnchors, dynLocal[0] || []])) return false + } + if (data.required !== undefined && hasOwn(data, "required")) { + if (!ref2(data.required, [...dynAnchors, dynLocal[0] || []])) return false + } + if (data.dependentRequired !== undefined && hasOwn(data, "dependentRequired")) { + if (!(typeof data.dependentRequired === "object" && data.dependentRequired && !Array.isArray(data.dependentRequired))) return false + for (const key9 of Object.keys(data.dependentRequired)) { + if (!ref2(data.dependentRequired[key9], [...dynAnchors, dynLocal[0] || []])) return false + } + } + } + return true +}; +const ref14 = function validate(data, dynAnchors) { + if (!(typeof data === "object" && data && !Array.isArray(data) || typeof data === "boolean")) return false + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.title !== undefined && hasOwn(data, "title")) { + if (!(typeof data.title === "string")) return false + } + if (data.description !== undefined && hasOwn(data, "description")) { + if (!(typeof data.description === "string")) return false + } + if (data.deprecated !== undefined && hasOwn(data, "deprecated")) { + if (!(typeof data.deprecated === "boolean")) return false + } + if (data.readOnly !== undefined && hasOwn(data, "readOnly")) { + if (!(typeof data.readOnly === "boolean")) return false + } + if (data.writeOnly !== undefined && hasOwn(data, "writeOnly")) { + if (!(typeof data.writeOnly === "boolean")) return false + } + if (data.examples !== undefined && hasOwn(data, "examples")) { + if (!Array.isArray(data.examples)) return false + } + } + return true +}; +const ref15 = function validate(data, dynAnchors) { + if (!(typeof data === "object" && data && !Array.isArray(data) || typeof data === "boolean")) return false + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.format !== undefined && hasOwn(data, "format")) { + if (!(typeof data.format === "string")) return false + } + } + return true +}; +const ref16 = function validate(data, dynAnchors = []) { + const dynLocal = [{}] + dynLocal[0]["#meta"] = validate + if (!(typeof data === "object" && data && !Array.isArray(data) || typeof data === "boolean")) return false + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.contentEncoding !== undefined && hasOwn(data, "contentEncoding")) { + if (!(typeof data.contentEncoding === "string")) return false + } + if (data.contentMediaType !== undefined && hasOwn(data, "contentMediaType")) { + if (!(typeof data.contentMediaType === "string")) return false + } + if (data.contentSchema !== undefined && hasOwn(data, "contentSchema")) { + if (!(dynamicResolve(dynAnchors || [], "#meta") || validate)(data.contentSchema, [...dynAnchors, dynLocal[0] || []])) return false + } + } + return true +}; +const ref1 = function validate(data, dynAnchors = []) { + const dynLocal = [{}] + dynLocal[0]["#meta"] = validate + if (!(typeof data === "object" && data && !Array.isArray(data) || typeof data === "boolean")) return false + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.definitions !== undefined && hasOwn(data, "definitions")) { + if (!(typeof data.definitions === "object" && data.definitions && !Array.isArray(data.definitions))) return false + for (const key0 of Object.keys(data.definitions)) { + if (!(dynamicResolve(dynAnchors || [], "#meta") || validate)(data.definitions[key0], [...dynAnchors, dynLocal[0] || []])) return false + } + } + if (data.dependencies !== undefined && hasOwn(data, "dependencies")) { + if (!(typeof data.dependencies === "object" && data.dependencies && !Array.isArray(data.dependencies))) return false + for (const key1 of Object.keys(data.dependencies)) { + const sub0 = (() => { + if (!(dynamicResolve(dynAnchors || [], "#meta") || validate)(data.dependencies[key1], [...dynAnchors, dynLocal[0] || []])) return false + return true + })() + if (!sub0) { + const sub1 = (() => { + if (!ref2(data.dependencies[key1], [...dynAnchors, dynLocal[0] || []])) return false + return true + })() + if (!sub1) return false + } + } + } + if (data["$recursiveAnchor"] !== undefined && hasOwn(data, "$recursiveAnchor")) { + if (!ref3(data["$recursiveAnchor"], [...dynAnchors, dynLocal[0] || []])) return false + } + if (data["$recursiveRef"] !== undefined && hasOwn(data, "$recursiveRef")) { + if (!ref4(data["$recursiveRef"], [...dynAnchors, dynLocal[0] || []])) return false + } + } + if (!ref5(data, [...dynAnchors, dynLocal[0] || []])) return false + if (!ref7(data, [...dynAnchors, dynLocal[0] || []])) return false + if (!ref9(data, [...dynAnchors, dynLocal[0] || []])) return false + if (!ref10(data, [...dynAnchors, dynLocal[0] || []])) return false + if (!ref14(data, [...dynAnchors, dynLocal[0] || []])) return false + if (!ref15(data, [...dynAnchors, dynLocal[0] || []])) return false + if (!ref16(data, [...dynAnchors, dynLocal[0] || []])) return false + return true +}; +const ref0 = function validate(data, dynAnchors) { + if (!ref1(data, dynAnchors)) return false + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at https://json-schema.org/draft/next/schema#/properties/definitions/additionalProperties` + + +## URN base URI with URN and JSON pointer ref + +### Schema + +```json +{ + "$id": "urn:uuid:deadbeef-1234-0000-0000-4321feebdaed", + "properties": { + "foo": { + "$ref": "urn:uuid:deadbeef-1234-0000-0000-4321feebdaed#/$defs/bar" + } + }, + "$defs": { "bar": { "type": "string" } } +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref1 = function validate(data) { + if (!(typeof data === "string")) return false + return true +}; +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.foo !== undefined && hasOwn(data, "foo")) { + if (!ref1(data.foo)) return false + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireStringValidation] pattern, format or contentSchema should be specified for strings, use pattern: ^[\s\S]*$ to opt-out at urn:uuid:deadbeef-1234-0000-0000-4321feebdaed#` + + +## URN base URI with URN and anchor ref + +### Schema + +```json +{ + "$id": "urn:uuid:deadbeef-1234-ff00-00ff-4321feebdaed", + "properties": { + "foo": { "$ref": "urn:uuid:deadbeef-1234-ff00-00ff-4321feebdaed#something" } + }, + "$defs": { "bar": { "$anchor": "something", "type": "string" } } +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref1 = function validate(data) { + if (!(typeof data === "string")) return false + return true +}; +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.foo !== undefined && hasOwn(data, "foo")) { + if (!ref1(data.foo)) return false + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireStringValidation] pattern, format or contentSchema should be specified for strings, use pattern: ^[\s\S]*$ to opt-out at urn:uuid:deadbeef-1234-ff00-00ff-4321feebdaed#` + + +## URN ref with nested pointer ref + +### Schema + +```json +{ + "$ref": "urn:uuid:deadbeef-4321-ffff-ffff-1234feebdaed", + "$defs": { + "foo": { + "$id": "urn:uuid:deadbeef-4321-ffff-ffff-1234feebdaed", + "$defs": { "bar": { "type": "string" } }, + "$ref": "#/$defs/bar" + } + } +} +``` + +### Code + +```js +'use strict' +const ref2 = function validate(data) { + if (!(typeof data === "string")) return false + return true +}; +const ref1 = function validate(data) { + if (!ref2(data)) return false + return true +}; +const ref0 = function validate(data) { + if (!ref1(data)) return false + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireStringValidation] pattern, format or contentSchema should be specified for strings, use pattern: ^[\s\S]*$ to opt-out at urn:uuid:deadbeef-4321-ffff-ffff-1234feebdaed#` + diff --git a/doc/samples/draft-next/refRemote.md b/doc/samples/draft-next/refRemote.md new file mode 100644 index 0000000..d8638ae --- /dev/null +++ b/doc/samples/draft-next/refRemote.md @@ -0,0 +1,494 @@ +# refRemote + +## remote ref + +### Schema + +```json +{ "$ref": "http://localhost:1234/draft-next/integer.json" } +``` + +### Code + +```js +'use strict' +const ref1 = function validate(data) { + if (!Number.isInteger(data)) return false + return true +}; +const ref0 = function validate(data) { + if (!ref1(data)) return false + return true +}; +return ref0 +``` + + +## fragment within remote ref + +### Schema + +```json +{ + "$ref": "http://localhost:1234/draft-next/subSchemas-defs.json#/$defs/integer" +} +``` + +### Code + +```js +'use strict' +const ref1 = function validate(data) { + if (!Number.isInteger(data)) return false + return true +}; +const ref0 = function validate(data) { + if (!ref1(data)) return false + return true +}; +return ref0 +``` + + +## ref within remote ref + +### Schema + +```json +{ + "$ref": "http://localhost:1234/draft-next/subSchemas-defs.json#/$defs/refToInteger" +} +``` + +### Code + +```js +'use strict' +const ref2 = function validate(data) { + if (!Number.isInteger(data)) return false + return true +}; +const ref1 = function validate(data) { + if (!ref2(data)) return false + return true +}; +const ref0 = function validate(data) { + if (!ref1(data)) return false + return true +}; +return ref0 +``` + + +## base URI change + +### Schema + +```json +{ + "$id": "http://localhost:1234/draft-next/", + "items": { + "$id": "baseUriChange/", + "items": { "$ref": "folderInteger.json" } + } +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref1 = function validate(data) { + if (!Number.isInteger(data)) return false + return true +}; +const ref0 = function validate(data) { + if (Array.isArray(data)) { + for (let i = 0; i < data.length; i++) { + if (data[i] !== undefined && hasOwn(data, i)) { + if (Array.isArray(data[i])) { + for (let j = 0; j < data[i].length; j++) { + if (data[i][j] !== undefined && hasOwn(data[i], j)) { + if (!ref1(data[i][j])) return false + } + } + } + } + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #/items` + + +## base URI change - change folder + +### Schema + +```json +{ + "$id": "http://localhost:1234/draft-next/scope_change_defs1.json", + "type": "object", + "properties": { "list": { "$ref": "baseUriChangeFolder/" } }, + "$defs": { + "baz": { + "$id": "baseUriChangeFolder/", + "type": "array", + "items": { "$ref": "folderInteger.json" } + } + } +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref2 = function validate(data) { + if (!Number.isInteger(data)) return false + return true +}; +const ref1 = function validate(data) { + if (!Array.isArray(data)) return false + for (let i = 0; i < data.length; i++) { + if (data[i] !== undefined && hasOwn(data, i)) { + if (!ref2(data[i])) return false + } + } + return true +}; +const ref0 = function validate(data) { + if (!(typeof data === "object" && data && !Array.isArray(data))) return false + if (data.list !== undefined && hasOwn(data, "list")) { + if (!ref1(data.list)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] additionalProperties or unevaluatedProperties should be specified at #` + + +## base URI change - change folder in subschema + +### Schema + +```json +{ + "$id": "http://localhost:1234/draft-next/scope_change_defs2.json", + "type": "object", + "properties": { + "list": { "$ref": "baseUriChangeFolderInSubschema/#/$defs/bar" } + }, + "$defs": { + "baz": { + "$id": "baseUriChangeFolderInSubschema/", + "$defs": { + "bar": { "type": "array", "items": { "$ref": "folderInteger.json" } } + } + } + } +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref2 = function validate(data) { + if (!Number.isInteger(data)) return false + return true +}; +const ref1 = function validate(data) { + if (!Array.isArray(data)) return false + for (let i = 0; i < data.length; i++) { + if (data[i] !== undefined && hasOwn(data, i)) { + if (!ref2(data[i])) return false + } + } + return true +}; +const ref0 = function validate(data) { + if (!(typeof data === "object" && data && !Array.isArray(data))) return false + if (data.list !== undefined && hasOwn(data, "list")) { + if (!ref1(data.list)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] additionalProperties or unevaluatedProperties should be specified at #` + + +## root ref in remote ref + +### Schema + +```json +{ + "$id": "http://localhost:1234/draft-next/object", + "type": "object", + "properties": { "name": { "$ref": "name-defs.json#/$defs/orNull" } } +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref2 = function validate(data) { + if (!(typeof data === "string")) return false + return true +}; +const ref1 = function validate(data) { + const sub0 = (() => { + if (!(data === null)) return false + return true + })() + if (!sub0) { + const sub1 = (() => { + if (!ref2(data)) return false + return true + })() + if (!sub1) return false + } + return true +}; +const ref0 = function validate(data) { + if (!(typeof data === "object" && data && !Array.isArray(data))) return false + if (data.name !== undefined && hasOwn(data, "name")) { + if (!ref1(data.name)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireStringValidation] pattern, format or contentSchema should be specified for strings, use pattern: ^[\s\S]*$ to opt-out at #` + + +## remote ref with ref to defs + +### Schema + +```json +{ + "$id": "http://localhost:1234/draft-next/schema-remote-ref-ref-defs1.json", + "$ref": "ref-and-defs.json" +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref2 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.bar !== undefined && hasOwn(data, "bar")) { + if (!(typeof data.bar === "string")) return false + } + } + return true +}; +const ref1 = function validate(data) { + if (!ref2(data)) return false + return true +}; +const ref0 = function validate(data) { + if (!ref1(data)) return false + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireStringValidation] pattern, format or contentSchema should be specified for strings, use pattern: ^[\s\S]*$ to opt-out at http://localhost:1234/draft-next/ref-and-defs.json#/properties/bar` + + +## Location-independent identifier in remote ref + +### Schema + +```json +{ + "$ref": "http://localhost:1234/draft-next/locationIndependentIdentifier.json#/$defs/refToInteger" +} +``` + +### Code + +```js +'use strict' +const ref2 = function validate(data) { + if (!Number.isInteger(data)) return false + return true +}; +const ref1 = function validate(data) { + if (!ref2(data)) return false + return true +}; +const ref0 = function validate(data) { + if (!ref1(data)) return false + return true +}; +return ref0 +``` + + +## retrieved nested refs resolve relative to their URI not $id + +### Schema + +```json +{ + "$id": "http://localhost:1234/draft-next/some-id", + "properties": { "name": { "$ref": "nested/foo-ref-string.json" } } +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref2 = function validate(data) { + if (!(typeof data === "string")) return false + return true +}; +const ref1 = function validate(data) { + if (!(typeof data === "object" && data && !Array.isArray(data))) return false + if (data.foo !== undefined && hasOwn(data, "foo")) { + if (!ref2(data.foo)) return false + } + return true +}; +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.name !== undefined && hasOwn(data, "name")) { + if (!ref1(data.name)) return false + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireStringValidation] pattern, format or contentSchema should be specified for strings, use pattern: ^[\s\S]*$ to opt-out at http://localhost:1234/draft-next/nested/string.json#` + + +## remote HTTP ref with different $id + +### Schema + +```json +{ "$ref": "http://localhost:1234/different-id-ref-string.json" } +``` + +### Code + +```js +'use strict' +const ref2 = function validate(data) { + if (!(typeof data === "string")) return false + return true +}; +const ref1 = function validate(data) { + if (!ref2(data)) return false + return true +}; +const ref0 = function validate(data) { + if (!ref1(data)) return false + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireSchema] $schema is required at http://localhost:1234/different-id-ref-string.json#` + + +## remote HTTP ref with different URN $id + +### Schema + +```json +{ "$ref": "http://localhost:1234/urn-ref-string.json" } +``` + +### Code + +```js +'use strict' +const ref2 = function validate(data) { + if (!(typeof data === "string")) return false + return true +}; +const ref1 = function validate(data) { + if (!ref2(data)) return false + return true +}; +const ref0 = function validate(data) { + if (!ref1(data)) return false + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireSchema] $schema is required at http://localhost:1234/urn-ref-string.json#` + + +## remote HTTP ref with nested absolute ref + +### Schema + +```json +{ "$ref": "http://localhost:1234/nested-absolute-ref-to-string.json" } +``` + +### Code + +```js +'use strict' +const ref2 = function validate(data) { + if (!(typeof data === "string")) return false + return true +}; +const ref1 = function validate(data) { + if (!ref2(data)) return false + return true +}; +const ref0 = function validate(data) { + if (!ref1(data)) return false + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireSchema] $schema is required at http://localhost:1234/nested-absolute-ref-to-string.json#` + diff --git a/doc/samples/draft-next/required.md b/doc/samples/draft-next/required.md new file mode 100644 index 0000000..8888dab --- /dev/null +++ b/doc/samples/draft-next/required.md @@ -0,0 +1,144 @@ +# required + +## required validation + +### Schema + +```json +{ "properties": { "foo": {}, "bar": {} }, "required": ["foo"] } +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (!(data.foo !== undefined && hasOwn(data, "foo"))) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] empty rules node is not allowed at #/properties/foo` + + +## required default validation + +### Schema + +```json +{ "properties": { "foo": {} } } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] empty rules node is not allowed at #/properties/foo` + + +## required with empty array + +### Schema + +```json +{ "properties": { "foo": {} }, "required": [] } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] empty rules node is not allowed at #/properties/foo` + + +## required with escaped characters + +### Schema + +```json +{ + "required": [ + "foo\nbar", + "foo\"bar", + "foo\\bar", + "foo\rbar", + "foo\tbar", + "foo\fbar" + ] +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (!(data["foo\nbar"] !== undefined && hasOwn(data, "foo\nbar"))) return false + if (!(data["foo\"bar"] !== undefined && hasOwn(data, "foo\"bar"))) return false + if (!(data["foo\\bar"] !== undefined && hasOwn(data, "foo\\bar"))) return false + if (!(data["foo\rbar"] !== undefined && hasOwn(data, "foo\rbar"))) return false + if (!(data["foo\tbar"] !== undefined && hasOwn(data, "foo\tbar"))) return false + if (!(data["foo\fbar"] !== undefined && hasOwn(data, "foo\fbar"))) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## required properties whose names are Javascript object property names + +### Schema + +```json +{ "required": ["__proto__", "toString", "constructor"] } +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (!(data["__proto__"] !== undefined && hasOwn(data, "__proto__"))) return false + if (!(data.toString !== undefined && hasOwn(data, "toString"))) return false + if (!(data.constructor !== undefined && hasOwn(data, "constructor"))) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + diff --git a/doc/samples/draft-next/type.md b/doc/samples/draft-next/type.md new file mode 100644 index 0000000..ed839b2 --- /dev/null +++ b/doc/samples/draft-next/type.md @@ -0,0 +1,249 @@ +# type + +## integer type matches integers + +### Schema + +```json +{ "type": "integer" } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (!Number.isInteger(data)) return false + return true +}; +return ref0 +``` + + +## number type matches numbers + +### Schema + +```json +{ "type": "number" } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (!(typeof data === "number")) return false + return true +}; +return ref0 +``` + + +## string type matches strings + +### Schema + +```json +{ "type": "string" } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (!(typeof data === "string")) return false + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireStringValidation] pattern, format or contentSchema should be specified for strings, use pattern: ^[\s\S]*$ to opt-out at #` + + +## object type matches objects + +### Schema + +```json +{ "type": "object" } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (!(typeof data === "object" && data && !Array.isArray(data))) return false + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] additionalProperties or unevaluatedProperties should be specified at #` + + +## array type matches arrays + +### Schema + +```json +{ "type": "array" } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (!Array.isArray(data)) return false + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] items rule should be specified at #` + + +## boolean type matches booleans + +### Schema + +```json +{ "type": "boolean" } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (!(typeof data === "boolean")) return false + return true +}; +return ref0 +``` + + +## null type matches only the null object + +### Schema + +```json +{ "type": "null" } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (!(data === null)) return false + return true +}; +return ref0 +``` + + +## multiple types can be specified in an array + +### Schema + +```json +{ "type": ["integer", "string"] } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (!(Number.isInteger(data) || typeof data === "string")) return false + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireStringValidation] pattern, format or contentSchema should be specified for strings, use pattern: ^[\s\S]*$ to opt-out at #` + + +## type as array with one item + +### Schema + +```json +{ "type": ["string"] } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (!(typeof data === "string")) return false + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireStringValidation] pattern, format or contentSchema should be specified for strings, use pattern: ^[\s\S]*$ to opt-out at #` + + +## type: array or object + +### Schema + +```json +{ "type": ["array", "object"] } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (!(Array.isArray(data) || typeof data === "object" && data && !Array.isArray(data))) return false + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] items rule should be specified at #` + + +## type: array, object or null + +### Schema + +```json +{ "type": ["array", "object", "null"] } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (!(Array.isArray(data) || typeof data === "object" && data && !Array.isArray(data) || data === null)) return false + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] items rule should be specified at #` + diff --git a/doc/samples/draft-next/unevaluatedItems.md b/doc/samples/draft-next/unevaluatedItems.md new file mode 100644 index 0000000..5b4c728 --- /dev/null +++ b/doc/samples/draft-next/unevaluatedItems.md @@ -0,0 +1,1020 @@ +# unevaluatedItems + +## unevaluatedItems true + +### Schema + +```json +{ "unevaluatedItems": true } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] schema = true is not allowed at #/unevaluatedItems` + + +## unevaluatedItems false + +### Schema + +```json +{ "unevaluatedItems": false } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (Array.isArray(data)) { + if (data.length > 0) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## unevaluatedItems as schema + +### Schema + +```json +{ "unevaluatedItems": { "type": "string" } } +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (Array.isArray(data)) { + for (let i = 0; i < data.length; i++) { + if (data[i] !== undefined && hasOwn(data, i)) { + if (!(typeof data[i] === "string")) return false + } + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireStringValidation] pattern, format or contentSchema should be specified for strings, use pattern: ^[\s\S]*$ to opt-out at #/unevaluatedItems` + + +## unevaluatedItems with uniform items + +### Schema + +```json +{ "items": { "type": "string" }, "unevaluatedItems": false } +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (Array.isArray(data)) { + for (let i = 0; i < data.length; i++) { + if (data[i] !== undefined && hasOwn(data, i)) { + if (!(typeof data[i] === "string")) return false + } + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireStringValidation] pattern, format or contentSchema should be specified for strings, use pattern: ^[\s\S]*$ to opt-out at #/items` + + +## unevaluatedItems with tuple + +### Schema + +```json +{ "prefixItems": [{ "type": "string" }], "unevaluatedItems": false } +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (Array.isArray(data)) { + if (data[0] !== undefined && hasOwn(data, 0)) { + if (!(typeof data[0] === "string")) return false + } + } + if (Array.isArray(data)) { + if (data.length > 1) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireStringValidation] pattern, format or contentSchema should be specified for strings, use pattern: ^[\s\S]*$ to opt-out at #/0` + + +## unevaluatedItems with items + +### Schema + +```json +{ + "prefixItems": [{ "type": "string" }], + "items": true, + "unevaluatedItems": false +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (Array.isArray(data)) { + if (data[0] !== undefined && hasOwn(data, 0)) { + if (!(typeof data[0] === "string")) return false + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireStringValidation] pattern, format or contentSchema should be specified for strings, use pattern: ^[\s\S]*$ to opt-out at #/0` + + +## unevaluatedItems with nested tuple + +### Schema + +```json +{ + "prefixItems": [{ "type": "string" }], + "allOf": [{ "prefixItems": [true, { "type": "number" }] }], + "unevaluatedItems": false +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (Array.isArray(data)) { + if (data[0] !== undefined && hasOwn(data, 0)) { + if (!(typeof data[0] === "string")) return false + } + } + if (Array.isArray(data)) { + if (data[1] !== undefined && hasOwn(data, 1)) { + if (!(typeof data[1] === "number")) return false + } + } + if (Array.isArray(data)) { + if (data.length > 2) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireStringValidation] pattern, format or contentSchema should be specified for strings, use pattern: ^[\s\S]*$ to opt-out at #/0` + + +## unevaluatedItems with nested items + +### Schema + +```json +{ + "unevaluatedItems": { "type": "boolean" }, + "anyOf": [{ "items": { "type": "string" } }, true] +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + validate.evaluatedDynamic = null + const evaluatedItem0 = [] + const evaluatedItems0 = [0] + const evaluatedProps0 = [[], []] + const sub0 = (() => { + if (Array.isArray(data)) { + for (let i = 0; i < data.length; i++) { + if (data[i] !== undefined && hasOwn(data, i)) { + if (!(typeof data[i] === "string")) return false + } + } + } + return true + })() + if (sub0) evaluatedItems0.push(Infinity) + if (Array.isArray(data)) { + for (let j = Math.max(0, ...evaluatedItems0); j < data.length; j++) { + if (evaluatedItem0.includes(j)) continue + if (data[j] !== undefined && hasOwn(data, j)) { + if (!(typeof data[j] === "boolean")) return false + } + } + } + return true +}; +return ref0 +``` + +### Warnings + + * `some checks are never reachable at #/unevaluatedItems` + + +## unevaluatedItems with nested prefixItems and items + +### Schema + +```json +{ + "allOf": [{ "prefixItems": [{ "type": "string" }], "items": true }], + "unevaluatedItems": false +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (Array.isArray(data)) { + if (data[0] !== undefined && hasOwn(data, 0)) { + if (!(typeof data[0] === "string")) return false + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireStringValidation] pattern, format or contentSchema should be specified for strings, use pattern: ^[\s\S]*$ to opt-out at #/allOf/0/0` + + +## unevaluatedItems with nested unevaluatedItems + +### Schema + +```json +{ + "allOf": [ + { "prefixItems": [{ "type": "string" }] }, + { "unevaluatedItems": true } + ], + "unevaluatedItems": false +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (Array.isArray(data)) { + if (data[0] !== undefined && hasOwn(data, 0)) { + if (!(typeof data[0] === "string")) return false + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireStringValidation] pattern, format or contentSchema should be specified for strings, use pattern: ^[\s\S]*$ to opt-out at #/allOf/0/0` + + +## unevaluatedItems with anyOf + +### Schema + +```json +{ + "prefixItems": [{ "const": "foo" }], + "anyOf": [ + { "prefixItems": [true, { "const": "bar" }] }, + { "prefixItems": [true, true, { "const": "baz" }] } + ], + "unevaluatedItems": false +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + validate.evaluatedDynamic = null + const evaluatedItem0 = [] + const evaluatedItems0 = [0] + const evaluatedProps0 = [[], []] + if (Array.isArray(data)) { + if (data[0] !== undefined && hasOwn(data, 0)) { + if (!(data[0] === "foo")) return false + } + } + const sub0 = (() => { + if (Array.isArray(data)) { + if (data[1] !== undefined && hasOwn(data, 1)) { + if (!(data[1] === "bar")) return false + } + } + return true + })() + const sub1 = (() => { + if (Array.isArray(data)) { + if (data[2] !== undefined && hasOwn(data, 2)) { + if (!(data[2] === "baz")) return false + } + } + return true + })() + if (!(sub0 || sub1)) return false + if (sub0) evaluatedItems0.push(2) + if (sub1) evaluatedItems0.push(3) + if (Array.isArray(data)) { + for (let i = Math.max(1, ...evaluatedItems0); i < data.length; i++) { + if (evaluatedItem0.includes(i)) continue + if (data[i] !== undefined && hasOwn(data, i)) return false + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] schema = true is not allowed at #/anyOf/0/0` + + +## unevaluatedItems with oneOf + +### Schema + +```json +{ + "prefixItems": [{ "const": "foo" }], + "oneOf": [ + { "prefixItems": [true, { "const": "bar" }] }, + { "prefixItems": [true, { "const": "baz" }] } + ], + "unevaluatedItems": false +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (Array.isArray(data)) { + if (data[0] !== undefined && hasOwn(data, 0)) { + if (!(data[0] === "foo")) return false + } + } + let passes0 = 0 + const sub0 = (() => { + if (Array.isArray(data)) { + if (data[1] !== undefined && hasOwn(data, 1)) { + if (!(data[1] === "bar")) return false + } + } + return true + })() + if (sub0) passes0++ + const sub1 = (() => { + if (Array.isArray(data)) { + if (data[1] !== undefined && hasOwn(data, 1)) { + if (!(data[1] === "baz")) return false + } + } + return true + })() + if (sub1) passes0++ + if (passes0 !== 1) return false + if (Array.isArray(data)) { + if (data.length > 2) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] schema = true is not allowed at #/oneOf/0/0` + + +## unevaluatedItems with not + +### Schema + +```json +{ + "prefixItems": [{ "const": "foo" }], + "not": { "not": { "prefixItems": [true, { "const": "bar" }] } }, + "unevaluatedItems": false +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (Array.isArray(data)) { + if (data[0] !== undefined && hasOwn(data, 0)) { + if (!(data[0] === "foo")) return false + } + } + const sub0 = (() => { + const sub1 = (() => { + if (Array.isArray(data)) { + if (data[1] !== undefined && hasOwn(data, 1)) { + if (!(data[1] === "bar")) return false + } + } + return true + })() + if (sub1) return false + return true + })() + if (sub0) return false + if (Array.isArray(data)) { + if (data.length > 1) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] schema = true is not allowed at #/not/not/0` + + +## unevaluatedItems with if/then/else + +### Schema + +```json +{ + "prefixItems": [{ "const": "foo" }], + "if": { "prefixItems": [true, { "const": "bar" }] }, + "then": { "prefixItems": [true, true, { "const": "then" }] }, + "else": { "prefixItems": [true, true, true, { "const": "else" }] }, + "unevaluatedItems": false +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + validate.evaluatedDynamic = null + const evaluatedItem0 = [] + const evaluatedItems0 = [0] + const evaluatedProps0 = [[], []] + if (Array.isArray(data)) { + if (data[0] !== undefined && hasOwn(data, 0)) { + if (!(data[0] === "foo")) return false + } + } + const sub0 = (() => { + if (Array.isArray(data)) { + if (data[1] !== undefined && hasOwn(data, 1)) { + if (!(data[1] === "bar")) return false + } + } + return true + })() + if (sub0) { + if (Array.isArray(data)) { + if (data[2] !== undefined && hasOwn(data, 2)) { + if (!(data[2] === "then")) return false + } + } + evaluatedItems0.push(3) + } + else { + if (Array.isArray(data)) { + if (data[3] !== undefined && hasOwn(data, 3)) { + if (!(data[3] === "else")) return false + } + } + evaluatedItems0.push(4) + } + if (Array.isArray(data)) { + for (let i = Math.max(3, ...evaluatedItems0); i < data.length; i++) { + if (evaluatedItem0.includes(i)) continue + if (data[i] !== undefined && hasOwn(data, i)) return false + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] schema = true is not allowed at #/if/0` + + +## unevaluatedItems with boolean schemas + +### Schema + +```json +{ "allOf": [true], "unevaluatedItems": false } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (Array.isArray(data)) { + if (data.length > 0) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] schema = true is not allowed at #/allOf/0` + + +## unevaluatedItems with $ref + +### Schema + +```json +{ + "$ref": "#/$defs/bar", + "prefixItems": [{ "type": "string" }], + "unevaluatedItems": false, + "$defs": { "bar": { "prefixItems": [true, { "type": "string" }] } } +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref1 = function validate(data) { + if (Array.isArray(data)) { + if (data[1] !== undefined && hasOwn(data, 1)) { + if (!(typeof data[1] === "string")) return false + } + } + return true +}; +const ref0 = function validate(data) { + if (!ref1(data)) return false + if (Array.isArray(data)) { + if (data[0] !== undefined && hasOwn(data, 0)) { + if (!(typeof data[0] === "string")) return false + } + } + if (Array.isArray(data)) { + if (data.length > 2) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] schema = true is not allowed at #/0` + + +## unevaluatedItems can't see inside cousins + +### Schema + +```json +{ "allOf": [{ "prefixItems": [true] }, { "unevaluatedItems": false }] } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (Array.isArray(data)) { + if (data.length > 0) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] schema = true is not allowed at #/allOf/0/0` + + +## item is evaluated in an uncle schema to unevaluatedItems + +### Schema + +```json +{ + "properties": { + "foo": { "prefixItems": [{ "type": "string" }], "unevaluatedItems": false } + }, + "anyOf": [ + { "properties": { "foo": { "prefixItems": [true, { "type": "string" }] } } } + ] +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.foo !== undefined && hasOwn(data, "foo")) { + if (Array.isArray(data.foo)) { + if (data.foo[0] !== undefined && hasOwn(data.foo, 0)) { + if (!(typeof data.foo[0] === "string")) return false + } + } + if (Array.isArray(data.foo)) { + if (data.foo.length > 1) return false + } + } + } + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.foo !== undefined && hasOwn(data, "foo")) { + if (Array.isArray(data.foo)) { + if (data.foo[1] !== undefined && hasOwn(data.foo, 1)) { + if (!(typeof data.foo[1] === "string")) return false + } + } + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireStringValidation] pattern, format or contentSchema should be specified for strings, use pattern: ^[\s\S]*$ to opt-out at #/properties/foo/0` + + +## unevaluatedItems depends on adjacent contains + +### Schema + +```json +{ + "prefixItems": [true], + "contains": { "type": "string" }, + "unevaluatedItems": false +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + validate.evaluatedDynamic = null + const evaluatedItem0 = [] + const evaluatedItems0 = [0] + const evaluatedProps0 = [[], []] + if (Array.isArray(data)) { + let passes0 = 0 + for (let i = 0; i < data.length; i++) { + const sub0 = (() => { + if (data[i] !== undefined && hasOwn(data, i)) { + if (!(typeof data[i] === "string")) return false + } + return true + })() + if (sub0) { + passes0++ + evaluatedItem0.push(i) + } + } + if (passes0 < 1) return false + } + if (Array.isArray(data)) { + for (let j = Math.max(1, ...evaluatedItems0); j < data.length; j++) { + if (evaluatedItem0.includes(j)) continue + if (data[j] !== undefined && hasOwn(data, j)) return false + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] schema = true is not allowed at #/0` + + +## unevaluatedItems depends on multiple nested contains + +### Schema + +```json +{ + "allOf": [ + { "contains": { "multipleOf": 2 } }, + { "contains": { "multipleOf": 3 } } + ], + "unevaluatedItems": { "multipleOf": 5 } +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + validate.evaluatedDynamic = null + const evaluatedItem0 = [] + const evaluatedItems0 = [0] + const evaluatedProps0 = [[], []] + if (Array.isArray(data)) { + let passes0 = 0 + for (let i = 0; i < data.length; i++) { + const sub0 = (() => { + if (data[i] !== undefined && hasOwn(data, i)) { + if (typeof data[i] === "number") { + if (data[i] % 2 !== 0) return false + } + } + return true + })() + if (sub0) { + passes0++ + evaluatedItem0.push(i) + } + } + if (passes0 < 1) return false + } + if (Array.isArray(data)) { + let passes1 = 0 + for (let j = 0; j < data.length; j++) { + const sub1 = (() => { + if (data[j] !== undefined && hasOwn(data, j)) { + if (typeof data[j] === "number") { + if (data[j] % 3 !== 0) return false + } + } + return true + })() + if (sub1) { + passes1++ + evaluatedItem0.push(j) + } + } + if (passes1 < 1) return false + } + if (Array.isArray(data)) { + for (let k = Math.max(0, ...evaluatedItems0); k < data.length; k++) { + if (evaluatedItem0.includes(k)) continue + if (data[k] !== undefined && hasOwn(data, k)) { + if (typeof data[k] === "number") { + if (data[k] % 5 !== 0) return false + } + } + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #/allOf/0/contains` + + +## unevaluatedItems and contains interact to control item dependency relationship + +### Schema + +```json +{ + "if": { "contains": { "const": "a" } }, + "then": { + "if": { "contains": { "const": "b" } }, + "then": { "if": { "contains": { "const": "c" } } } + }, + "unevaluatedItems": false +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + validate.evaluatedDynamic = null + const evaluatedItem0 = [] + const evaluatedItems0 = [0] + const evaluatedProps0 = [[], []] + const sub0 = (() => { + if (Array.isArray(data)) { + let passes0 = 0 + for (let i = 0; i < data.length; i++) { + const sub1 = (() => { + if (data[i] !== undefined && hasOwn(data, i)) { + if (!(data[i] === "a")) return false + } + return true + })() + if (sub1) { + passes0++ + evaluatedItem0.push(i) + } + } + if (passes0 < 1) return false + } + return true + })() + if (sub0) { + const sub2 = (() => { + if (Array.isArray(data)) { + let passes1 = 0 + for (let j = 0; j < data.length; j++) { + const sub3 = (() => { + if (data[j] !== undefined && hasOwn(data, j)) { + if (!(data[j] === "b")) return false + } + return true + })() + if (sub3) { + passes1++ + evaluatedItem0.push(j) + } + } + if (passes1 < 1) return false + } + return true + })() + if (sub2) { + const sub4 = (() => { + if (Array.isArray(data)) { + let passes2 = 0 + for (let k = 0; k < data.length; k++) { + const sub5 = (() => { + if (data[k] !== undefined && hasOwn(data, k)) { + if (!(data[k] === "c")) return false + } + return true + })() + if (sub5) { + passes2++ + evaluatedItem0.push(k) + } + } + if (passes2 < 1) return false + } + return true + })() + } + } + if (Array.isArray(data)) { + for (let l = Math.max(0, ...evaluatedItems0); l < data.length; l++) { + if (evaluatedItem0.includes(l)) continue + if (data[l] !== undefined && hasOwn(data, l)) return false + } + } + return true +}; +return ref0 +``` + +### Warnings + + * `Unprocessed keywords: ["if"] at #/then/then` + + +## non-array instances are valid + +### Schema + +```json +{ "unevaluatedItems": false } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (Array.isArray(data)) { + if (data.length > 0) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## unevaluatedItems with null instance elements + +### Schema + +```json +{ "unevaluatedItems": { "type": "null" } } +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (Array.isArray(data)) { + for (let i = 0; i < data.length; i++) { + if (data[i] !== undefined && hasOwn(data, i)) { + if (!(data[i] === null)) return false + } + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + diff --git a/doc/samples/draft-next/unevaluatedProperties.md b/doc/samples/draft-next/unevaluatedProperties.md new file mode 100644 index 0000000..def9b3a --- /dev/null +++ b/doc/samples/draft-next/unevaluatedProperties.md @@ -0,0 +1,1637 @@ +# unevaluatedProperties + +## unevaluatedProperties true + +### Schema + +```json +{ "type": "object", "unevaluatedProperties": true } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (!(typeof data === "object" && data && !Array.isArray(data))) return false + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] schema = true is not allowed at #/unevaluatedProperties` + + +## unevaluatedProperties schema + +### Schema + +```json +{ + "type": "object", + "unevaluatedProperties": { "type": "string", "minLength": 3 } +} +``` + +### Code + +```js +'use strict' +const stringLength = (string) => + /[\uD800-\uDFFF]/.test(string) ? [...string].length : string.length; +const ref0 = function validate(data) { + if (!(typeof data === "object" && data && !Array.isArray(data))) return false + for (const key0 of Object.keys(data)) { + if (!(typeof data[key0] === "string")) return false + if (data[key0].length < 3 || stringLength(data[key0]) < 3) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireStringValidation] pattern, format or contentSchema should be specified for strings, use pattern: ^[\s\S]*$ to opt-out at #/unevaluatedProperties` + + +## unevaluatedProperties false + +### Schema + +```json +{ "type": "object", "unevaluatedProperties": false } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (!(typeof data === "object" && data && !Array.isArray(data))) return false + for (const key0 of Object.keys(data)) return false + return true +}; +return ref0 +``` + + +## unevaluatedProperties with adjacent properties + +### Schema + +```json +{ + "type": "object", + "properties": { "foo": { "type": "string" } }, + "unevaluatedProperties": false +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (!(typeof data === "object" && data && !Array.isArray(data))) return false + if (data.foo !== undefined && hasOwn(data, "foo")) { + if (!(typeof data.foo === "string")) return false + } + for (const key0 of Object.keys(data)) { + if (key0 !== "foo") return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireStringValidation] pattern, format or contentSchema should be specified for strings, use pattern: ^[\s\S]*$ to opt-out at #/properties/foo` + + +## unevaluatedProperties with adjacent patternProperties + +### Schema + +```json +{ + "type": "object", + "patternProperties": { "^foo": { "type": "string" } }, + "unevaluatedProperties": false +} +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (!(typeof data === "object" && data && !Array.isArray(data))) return false + for (const key0 of Object.keys(data)) { + if (key0.startsWith("foo")) { + if (!(typeof data[key0] === "string")) return false + } + } + for (const key1 of Object.keys(data)) { + if (!(key1.startsWith("foo"))) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `Should start with ^ and end with $: "^foo" at #` + + +## unevaluatedProperties with adjacent additionalProperties + +### Schema + +```json +{ + "type": "object", + "properties": { "foo": { "type": "string" } }, + "additionalProperties": true, + "unevaluatedProperties": false +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (!(typeof data === "object" && data && !Array.isArray(data))) return false + if (data.foo !== undefined && hasOwn(data, "foo")) { + if (!(typeof data.foo === "string")) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireStringValidation] pattern, format or contentSchema should be specified for strings, use pattern: ^[\s\S]*$ to opt-out at #/properties/foo` + + +## unevaluatedProperties with nested properties + +### Schema + +```json +{ + "type": "object", + "properties": { "foo": { "type": "string" } }, + "allOf": [{ "properties": { "bar": { "type": "string" } } }], + "unevaluatedProperties": false +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (!(typeof data === "object" && data && !Array.isArray(data))) return false + if (data.foo !== undefined && hasOwn(data, "foo")) { + if (!(typeof data.foo === "string")) return false + } + if (data.bar !== undefined && hasOwn(data, "bar")) { + if (!(typeof data.bar === "string")) return false + } + for (const key0 of Object.keys(data)) { + if (key0 !== "bar" && key0 !== "foo") return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireStringValidation] pattern, format or contentSchema should be specified for strings, use pattern: ^[\s\S]*$ to opt-out at #/properties/foo` + + +## unevaluatedProperties with nested patternProperties + +### Schema + +```json +{ + "type": "object", + "properties": { "foo": { "type": "string" } }, + "allOf": [{ "patternProperties": { "^bar": { "type": "string" } } }], + "unevaluatedProperties": false +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (!(typeof data === "object" && data && !Array.isArray(data))) return false + if (data.foo !== undefined && hasOwn(data, "foo")) { + if (!(typeof data.foo === "string")) return false + } + for (const key0 of Object.keys(data)) { + if (key0.startsWith("bar")) { + if (!(typeof data[key0] === "string")) return false + } + } + for (const key1 of Object.keys(data)) { + if (key1 !== "foo" && !(key1.startsWith("bar"))) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireStringValidation] pattern, format or contentSchema should be specified for strings, use pattern: ^[\s\S]*$ to opt-out at #/properties/foo` + + +## unevaluatedProperties with nested additionalProperties + +### Schema + +```json +{ + "type": "object", + "properties": { "foo": { "type": "string" } }, + "allOf": [{ "additionalProperties": true }], + "unevaluatedProperties": false +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (!(typeof data === "object" && data && !Array.isArray(data))) return false + if (data.foo !== undefined && hasOwn(data, "foo")) { + if (!(typeof data.foo === "string")) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireStringValidation] pattern, format or contentSchema should be specified for strings, use pattern: ^[\s\S]*$ to opt-out at #/properties/foo` + + +## unevaluatedProperties with nested unevaluatedProperties + +### Schema + +```json +{ + "type": "object", + "properties": { "foo": { "type": "string" } }, + "allOf": [{ "unevaluatedProperties": true }], + "unevaluatedProperties": { "type": "string", "maxLength": 2 } +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (!(typeof data === "object" && data && !Array.isArray(data))) return false + if (data.foo !== undefined && hasOwn(data, "foo")) { + if (!(typeof data.foo === "string")) return false + } + return true +}; +return ref0 +``` + +### Warnings + + * `Unprocessed keywords: ["unevaluatedProperties"] at #` + + +## unevaluatedProperties with anyOf + +### Schema + +```json +{ + "type": "object", + "properties": { "foo": { "type": "string" } }, + "anyOf": [ + { "properties": { "bar": { "const": "bar" } }, "required": ["bar"] }, + { "properties": { "baz": { "const": "baz" } }, "required": ["baz"] }, + { "properties": { "quux": { "const": "quux" } }, "required": ["quux"] } + ], + "unevaluatedProperties": false +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const propertyIn = (key, [properties, patterns]) => + properties.includes(true) || + properties.some((prop) => prop === key) || + patterns.some((pattern) => new RegExp(pattern, 'u').test(key)); +const ref0 = function validate(data) { + validate.evaluatedDynamic = null + const evaluatedItem0 = [] + const evaluatedItems0 = [0] + const evaluatedProps0 = [[], []] + if (!(typeof data === "object" && data && !Array.isArray(data))) return false + if (data.foo !== undefined && hasOwn(data, "foo")) { + if (!(typeof data.foo === "string")) return false + } + const sub0 = (() => { + if (!(data.bar !== undefined && hasOwn(data, "bar"))) return false + if (!(data.bar === "bar")) return false + return true + })() + const sub1 = (() => { + if (!(data.baz !== undefined && hasOwn(data, "baz"))) return false + if (!(data.baz === "baz")) return false + return true + })() + const sub2 = (() => { + if (!(data.quux !== undefined && hasOwn(data, "quux"))) return false + if (!(data.quux === "quux")) return false + return true + })() + if (!(sub0 || sub1 || sub2)) return false + if (sub0) evaluatedProps0[0].push(...["bar"]) + if (sub1) evaluatedProps0[0].push(...["baz"]) + if (sub2) evaluatedProps0[0].push(...["quux"]) + for (const key0 of Object.keys(data)) { + if (key0 !== "foo" && !propertyIn(key0, evaluatedProps0)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireStringValidation] pattern, format or contentSchema should be specified for strings, use pattern: ^[\s\S]*$ to opt-out at #/properties/foo` + + +## unevaluatedProperties with oneOf + +### Schema + +```json +{ + "type": "object", + "properties": { "foo": { "type": "string" } }, + "oneOf": [ + { "properties": { "bar": { "const": "bar" } }, "required": ["bar"] }, + { "properties": { "baz": { "const": "baz" } }, "required": ["baz"] } + ], + "unevaluatedProperties": false +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const propertyIn = (key, [properties, patterns]) => + properties.includes(true) || + properties.some((prop) => prop === key) || + patterns.some((pattern) => new RegExp(pattern, 'u').test(key)); +const ref0 = function validate(data) { + validate.evaluatedDynamic = null + const evaluatedItem0 = [] + const evaluatedItems0 = [0] + const evaluatedProps0 = [[], []] + if (!(typeof data === "object" && data && !Array.isArray(data))) return false + if (data.foo !== undefined && hasOwn(data, "foo")) { + if (!(typeof data.foo === "string")) return false + } + let passes0 = 0 + const sub0 = (() => { + if (!(data.bar !== undefined && hasOwn(data, "bar"))) return false + if (!(data.bar === "bar")) return false + return true + })() + if (sub0) passes0++ + const sub1 = (() => { + if (!(data.baz !== undefined && hasOwn(data, "baz"))) return false + if (!(data.baz === "baz")) return false + return true + })() + if (sub1) passes0++ + if (passes0 !== 1) return false + if (sub0) evaluatedProps0[0].push(...["bar"]) + if (sub1) evaluatedProps0[0].push(...["baz"]) + for (const key0 of Object.keys(data)) { + if (key0 !== "foo" && !propertyIn(key0, evaluatedProps0)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireStringValidation] pattern, format or contentSchema should be specified for strings, use pattern: ^[\s\S]*$ to opt-out at #/properties/foo` + + +## unevaluatedProperties with not + +### Schema + +```json +{ + "type": "object", + "properties": { "foo": { "type": "string" } }, + "not": { + "not": { "properties": { "bar": { "const": "bar" } }, "required": ["bar"] } + }, + "unevaluatedProperties": false +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (!(typeof data === "object" && data && !Array.isArray(data))) return false + if (data.foo !== undefined && hasOwn(data, "foo")) { + if (!(typeof data.foo === "string")) return false + } + const sub0 = (() => { + const sub1 = (() => { + if (!(data.bar !== undefined && hasOwn(data, "bar"))) return false + if (!(data.bar === "bar")) return false + return true + })() + if (sub1) return false + return true + })() + if (sub0) return false + for (const key0 of Object.keys(data)) { + if (key0 !== "foo") return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireStringValidation] pattern, format or contentSchema should be specified for strings, use pattern: ^[\s\S]*$ to opt-out at #/properties/foo` + + +## unevaluatedProperties with if/then/else + +### Schema + +```json +{ + "type": "object", + "if": { "properties": { "foo": { "const": "then" } }, "required": ["foo"] }, + "then": { + "properties": { "bar": { "type": "string" } }, + "required": ["bar"] + }, + "else": { + "properties": { "baz": { "type": "string" } }, + "required": ["baz"] + }, + "unevaluatedProperties": false +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const propertyIn = (key, [properties, patterns]) => + properties.includes(true) || + properties.some((prop) => prop === key) || + patterns.some((pattern) => new RegExp(pattern, 'u').test(key)); +const ref0 = function validate(data) { + validate.evaluatedDynamic = null + const evaluatedItem0 = [] + const evaluatedItems0 = [0] + const evaluatedProps0 = [[], []] + if (!(typeof data === "object" && data && !Array.isArray(data))) return false + const sub0 = (() => { + if (!(data.foo !== undefined && hasOwn(data, "foo"))) return false + if (!(data.foo === "then")) return false + return true + })() + if (sub0) { + if (!(data.bar !== undefined && hasOwn(data, "bar"))) return false + if (!(typeof data.bar === "string")) return false + evaluatedProps0[0].push(...["bar","foo"]) + } + else { + if (!(data.baz !== undefined && hasOwn(data, "baz"))) return false + if (!(typeof data.baz === "string")) return false + evaluatedProps0[0].push(...["baz"]) + } + for (const key0 of Object.keys(data)) { + if (true && !propertyIn(key0, evaluatedProps0)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireStringValidation] pattern, format or contentSchema should be specified for strings, use pattern: ^[\s\S]*$ to opt-out at #/then/properties/bar` + + +## unevaluatedProperties with if/then/else, then not defined + +### Schema + +```json +{ + "type": "object", + "if": { "properties": { "foo": { "const": "then" } }, "required": ["foo"] }, + "else": { + "properties": { "baz": { "type": "string" } }, + "required": ["baz"] + }, + "unevaluatedProperties": false +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const propertyIn = (key, [properties, patterns]) => + properties.includes(true) || + properties.some((prop) => prop === key) || + patterns.some((pattern) => new RegExp(pattern, 'u').test(key)); +const ref0 = function validate(data) { + validate.evaluatedDynamic = null + const evaluatedItem0 = [] + const evaluatedItems0 = [0] + const evaluatedProps0 = [[], []] + if (!(typeof data === "object" && data && !Array.isArray(data))) return false + const sub0 = (() => { + if (!(data.foo !== undefined && hasOwn(data, "foo"))) return false + if (!(data.foo === "then")) return false + return true + })() + if (!sub0) { + if (!(data.baz !== undefined && hasOwn(data, "baz"))) return false + if (!(typeof data.baz === "string")) return false + evaluatedProps0[0].push(...["baz"]) + } + for (const key0 of Object.keys(data)) { + if (true && !propertyIn(key0, evaluatedProps0)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireStringValidation] pattern, format or contentSchema should be specified for strings, use pattern: ^[\s\S]*$ to opt-out at #/else/properties/baz` + + +## unevaluatedProperties with if/then/else, else not defined + +### Schema + +```json +{ + "type": "object", + "if": { "properties": { "foo": { "const": "then" } }, "required": ["foo"] }, + "then": { + "properties": { "bar": { "type": "string" } }, + "required": ["bar"] + }, + "unevaluatedProperties": false +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const propertyIn = (key, [properties, patterns]) => + properties.includes(true) || + properties.some((prop) => prop === key) || + patterns.some((pattern) => new RegExp(pattern, 'u').test(key)); +const ref0 = function validate(data) { + validate.evaluatedDynamic = null + const evaluatedItem0 = [] + const evaluatedItems0 = [0] + const evaluatedProps0 = [[], []] + if (!(typeof data === "object" && data && !Array.isArray(data))) return false + const sub0 = (() => { + if (!(data.foo !== undefined && hasOwn(data, "foo"))) return false + if (!(data.foo === "then")) return false + return true + })() + if (sub0) { + if (!(data.bar !== undefined && hasOwn(data, "bar"))) return false + if (!(typeof data.bar === "string")) return false + evaluatedProps0[0].push(...["bar","foo"]) + } + for (const key0 of Object.keys(data)) { + if (true && !propertyIn(key0, evaluatedProps0)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireStringValidation] pattern, format or contentSchema should be specified for strings, use pattern: ^[\s\S]*$ to opt-out at #/then/properties/bar` + + +## unevaluatedProperties with dependentSchemas + +### Schema + +```json +{ + "type": "object", + "properties": { "foo": { "type": "string" } }, + "dependentSchemas": { + "foo": { "properties": { "bar": { "const": "bar" } }, "required": ["bar"] } + }, + "unevaluatedProperties": false +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const propertyIn = (key, [properties, patterns]) => + properties.includes(true) || + properties.some((prop) => prop === key) || + patterns.some((pattern) => new RegExp(pattern, 'u').test(key)); +const ref0 = function validate(data) { + validate.evaluatedDynamic = null + const evaluatedItem0 = [] + const evaluatedItems0 = [0] + const evaluatedProps0 = [[], []] + if (!(typeof data === "object" && data && !Array.isArray(data))) return false + if (data.foo !== undefined && hasOwn(data, "foo")) { + if (!(data.bar !== undefined && hasOwn(data, "bar"))) return false + if (!(data.bar === "bar")) return false + evaluatedProps0[0].push(...["bar"]) + } + if (data.foo !== undefined && hasOwn(data, "foo")) { + if (!(typeof data.foo === "string")) return false + } + for (const key0 of Object.keys(data)) { + if (key0 !== "foo" && !propertyIn(key0, evaluatedProps0)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireStringValidation] pattern, format or contentSchema should be specified for strings, use pattern: ^[\s\S]*$ to opt-out at #/properties/foo` + + +## unevaluatedProperties with boolean schemas + +### Schema + +```json +{ + "type": "object", + "properties": { "foo": { "type": "string" } }, + "allOf": [true], + "unevaluatedProperties": false +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (!(typeof data === "object" && data && !Array.isArray(data))) return false + if (data.foo !== undefined && hasOwn(data, "foo")) { + if (!(typeof data.foo === "string")) return false + } + for (const key0 of Object.keys(data)) { + if (key0 !== "foo") return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireStringValidation] pattern, format or contentSchema should be specified for strings, use pattern: ^[\s\S]*$ to opt-out at #/properties/foo` + + +## unevaluatedProperties with $ref + +### Schema + +```json +{ + "type": "object", + "$ref": "#/$defs/bar", + "properties": { "foo": { "type": "string" } }, + "unevaluatedProperties": false, + "$defs": { "bar": { "properties": { "bar": { "type": "string" } } } } +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref1 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.bar !== undefined && hasOwn(data, "bar")) { + if (!(typeof data.bar === "string")) return false + } + } + return true +}; +const ref0 = function validate(data) { + if (!ref1(data)) return false + if (!(typeof data === "object" && data && !Array.isArray(data))) return false + if (data.foo !== undefined && hasOwn(data, "foo")) { + if (!(typeof data.foo === "string")) return false + } + for (const key0 of Object.keys(data)) { + if (key0 !== "bar" && key0 !== "foo") return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireStringValidation] pattern, format or contentSchema should be specified for strings, use pattern: ^[\s\S]*$ to opt-out at #/properties/bar` + + +## unevaluatedProperties can't see inside cousins + +### Schema + +```json +{ + "allOf": [ + { "properties": { "foo": true } }, + { "unevaluatedProperties": false } + ] +} +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + for (const key0 of Object.keys(data)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] schema = true is not allowed at #/allOf/0/properties/foo` + + +## nested unevaluatedProperties, outer false, inner true, properties outside + +### Schema + +```json +{ + "type": "object", + "properties": { "foo": { "type": "string" } }, + "allOf": [{ "unevaluatedProperties": true }], + "unevaluatedProperties": false +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (!(typeof data === "object" && data && !Array.isArray(data))) return false + if (data.foo !== undefined && hasOwn(data, "foo")) { + if (!(typeof data.foo === "string")) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireStringValidation] pattern, format or contentSchema should be specified for strings, use pattern: ^[\s\S]*$ to opt-out at #/properties/foo` + + +## nested unevaluatedProperties, outer false, inner true, properties inside + +### Schema + +```json +{ + "type": "object", + "allOf": [ + { + "properties": { "foo": { "type": "string" } }, + "unevaluatedProperties": true + } + ], + "unevaluatedProperties": false +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (!(typeof data === "object" && data && !Array.isArray(data))) return false + if (data.foo !== undefined && hasOwn(data, "foo")) { + if (!(typeof data.foo === "string")) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireStringValidation] pattern, format or contentSchema should be specified for strings, use pattern: ^[\s\S]*$ to opt-out at #/allOf/0/properties/foo` + + +## nested unevaluatedProperties, outer true, inner false, properties outside + +### Schema + +```json +{ + "type": "object", + "properties": { "foo": { "type": "string" } }, + "allOf": [{ "unevaluatedProperties": false }], + "unevaluatedProperties": true +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (!(typeof data === "object" && data && !Array.isArray(data))) return false + if (data.foo !== undefined && hasOwn(data, "foo")) { + if (!(typeof data.foo === "string")) return false + } + for (const key0 of Object.keys(data)) return false + return true +}; +return ref0 +``` + +### Warnings + + * `Unprocessed keywords: ["unevaluatedProperties"] at #` + + +## nested unevaluatedProperties, outer true, inner false, properties inside + +### Schema + +```json +{ + "type": "object", + "allOf": [ + { + "properties": { "foo": { "type": "string" } }, + "unevaluatedProperties": false + } + ], + "unevaluatedProperties": true +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (!(typeof data === "object" && data && !Array.isArray(data))) return false + if (data.foo !== undefined && hasOwn(data, "foo")) { + if (!(typeof data.foo === "string")) return false + } + for (const key0 of Object.keys(data)) { + if (key0 !== "foo") return false + } + return true +}; +return ref0 +``` + +### Warnings + + * `Unprocessed keywords: ["unevaluatedProperties"] at #` + + +## cousin unevaluatedProperties, true and false, true with properties + +### Schema + +```json +{ + "type": "object", + "allOf": [ + { + "properties": { "foo": { "type": "string" } }, + "unevaluatedProperties": true + }, + { "unevaluatedProperties": false } + ] +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (!(typeof data === "object" && data && !Array.isArray(data))) return false + if (data.foo !== undefined && hasOwn(data, "foo")) { + if (!(typeof data.foo === "string")) return false + } + for (const key1 of Object.keys(data)) return false + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireStringValidation] pattern, format or contentSchema should be specified for strings, use pattern: ^[\s\S]*$ to opt-out at #/allOf/0/properties/foo` + + +## cousin unevaluatedProperties, true and false, false with properties + +### Schema + +```json +{ + "type": "object", + "allOf": [ + { "unevaluatedProperties": true }, + { + "properties": { "foo": { "type": "string" } }, + "unevaluatedProperties": false + } + ] +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (!(typeof data === "object" && data && !Array.isArray(data))) return false + if (data.foo !== undefined && hasOwn(data, "foo")) { + if (!(typeof data.foo === "string")) return false + } + for (const key1 of Object.keys(data)) { + if (key1 !== "foo") return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] schema = true is not allowed at #/allOf/0/unevaluatedProperties` + + +## property is evaluated in an uncle schema to unevaluatedProperties + +### Schema + +```json +{ + "type": "object", + "properties": { + "foo": { + "type": "object", + "properties": { "bar": { "type": "string" } }, + "unevaluatedProperties": false + } + }, + "anyOf": [ + { + "properties": { "foo": { "properties": { "faz": { "type": "string" } } } } + } + ] +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (!(typeof data === "object" && data && !Array.isArray(data))) return false + if (data.foo !== undefined && hasOwn(data, "foo")) { + if (!(typeof data.foo === "object" && data.foo && !Array.isArray(data.foo))) return false + if (data.foo.bar !== undefined && hasOwn(data.foo, "bar")) { + if (!(typeof data.foo.bar === "string")) return false + } + for (const key0 of Object.keys(data.foo)) { + if (key0 !== "bar") return false + } + } + if (data.foo !== undefined && hasOwn(data, "foo")) { + if (typeof data.foo === "object" && data.foo && !Array.isArray(data.foo)) { + if (data.foo.faz !== undefined && hasOwn(data.foo, "faz")) { + if (!(typeof data.foo.faz === "string")) return false + } + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireStringValidation] pattern, format or contentSchema should be specified for strings, use pattern: ^[\s\S]*$ to opt-out at #/properties/foo/properties/bar` + + +## in-place applicator siblings, allOf has unevaluated + +### Schema + +```json +{ + "type": "object", + "allOf": [{ "properties": { "foo": true }, "unevaluatedProperties": false }], + "anyOf": [{ "properties": { "bar": true } }] +} +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (!(typeof data === "object" && data && !Array.isArray(data))) return false + for (const key0 of Object.keys(data)) { + if (key0 !== "foo") return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] schema = true is not allowed at #/allOf/0/properties/foo` + + +## in-place applicator siblings, anyOf has unevaluated + +### Schema + +```json +{ + "type": "object", + "allOf": [{ "properties": { "foo": true } }], + "anyOf": [{ "properties": { "bar": true }, "unevaluatedProperties": false }] +} +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (!(typeof data === "object" && data && !Array.isArray(data))) return false + for (const key0 of Object.keys(data)) { + if (key0 !== "bar") return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] schema = true is not allowed at #/allOf/0/properties/foo` + + +## unevaluatedProperties + single cyclic ref + +### Schema + +```json +{ + "type": "object", + "properties": { "x": { "$ref": "#" } }, + "unevaluatedProperties": false +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (!(typeof data === "object" && data && !Array.isArray(data))) return false + if (data.x !== undefined && hasOwn(data, "x")) { + if (!validate(data.x)) return false + } + for (const key0 of Object.keys(data)) { + if (key0 !== "x") return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] if properties is used, required should be specified at #` + + +## unevaluatedProperties + ref inside allOf / oneOf + +### Schema + +```json +{ + "$defs": { + "one": { "properties": { "a": true } }, + "two": { "required": ["x"], "properties": { "x": true } } + }, + "allOf": [ + { "$ref": "#/$defs/one" }, + { "properties": { "b": true } }, + { + "oneOf": [ + { "$ref": "#/$defs/two" }, + { "required": ["y"], "properties": { "y": true } } + ] + } + ], + "unevaluatedProperties": false +} +``` + +### Code + +```js +'use strict' +const ref1 = function validate(data) { + validate.evaluatedDynamic = null + const evaluatedItem1 = [] + const evaluatedItems1 = [0] + const evaluatedProps1 = [[], []] + return true +}; +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref2 = function validate(data) { + validate.evaluatedDynamic = null + const evaluatedItem2 = [] + const evaluatedItems2 = [0] + const evaluatedProps2 = [[], []] + if (typeof data === "object" && data && !Array.isArray(data)) { + if (!(data.x !== undefined && hasOwn(data, "x"))) return false + } + return true +}; +const propertyIn = (key, [properties, patterns]) => + properties.includes(true) || + properties.some((prop) => prop === key) || + patterns.some((pattern) => new RegExp(pattern, 'u').test(key)); +const ref0 = function validate(data) { + validate.evaluatedDynamic = null + const evaluatedItem0 = [] + const evaluatedItems0 = [0] + const evaluatedProps0 = [[], []] + const res0 = ref1(data) + if (!res0) return false + let passes0 = 0 + const sub0 = (() => { + const res1 = ref2(data) + if (!res1) return false + return true + })() + if (sub0) passes0++ + const sub1 = (() => { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (!(data.y !== undefined && hasOwn(data, "y"))) return false + } + return true + })() + if (sub1) passes0++ + if (passes0 !== 1) return false + if (sub0) evaluatedProps0[0].push(...["x"]) + if (sub1) evaluatedProps0[0].push(...["y"]) + if (typeof data === "object" && data && !Array.isArray(data)) { + for (const key0 of Object.keys(data)) { + if (key0 !== "a" && key0 !== "b" && !propertyIn(key0, evaluatedProps0)) return false + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] schema = true is not allowed at #/properties/a` + + +## dynamic evalation inside nested refs + +### Schema + +```json +{ + "$defs": { + "one": { + "oneOf": [ + { "$ref": "#/$defs/two" }, + { "required": ["b"], "properties": { "b": true } }, + { "required": ["xx"], "patternProperties": { "x": true } }, + { "required": ["all"], "unevaluatedProperties": true } + ] + }, + "two": { + "oneOf": [ + { "required": ["c"], "properties": { "c": true } }, + { "required": ["d"], "properties": { "d": true } } + ] + } + }, + "oneOf": [ + { "$ref": "#/$defs/one" }, + { "required": ["a"], "properties": { "a": true } } + ], + "unevaluatedProperties": false +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref2 = function validate(data) { + validate.evaluatedDynamic = null + const evaluatedItem2 = [] + const evaluatedItems2 = [0] + const evaluatedProps2 = [[], []] + let passes2 = 0 + const sub2 = (() => { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (!(data.c !== undefined && hasOwn(data, "c"))) return false + } + return true + })() + if (sub2) passes2++ + const sub3 = (() => { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (!(data.d !== undefined && hasOwn(data, "d"))) return false + } + return true + })() + if (sub3) passes2++ + if (passes2 !== 1) return false + if (sub2) evaluatedProps2[0].push(...["c"]) + if (sub3) evaluatedProps2[0].push(...["d"]) + validate.evaluatedDynamic = [evaluatedItem2, evaluatedItems2, evaluatedProps2] + return true +}; +const ref1 = function validate(data) { + validate.evaluatedDynamic = null + const evaluatedItem1 = [] + const evaluatedItems1 = [0] + const evaluatedProps1 = [[], []] + let passes1 = 0 + const sub1 = (() => { + const res0 = ref2(data) + if (!res0) return false + if (res0) { + evaluatedProps1[0].push(...ref2.evaluatedDynamic[2][0]) + evaluatedProps1[1].push(...ref2.evaluatedDynamic[2][1]) + } + return true + })() + if (sub1) passes1++ + const sub4 = (() => { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (!(data.b !== undefined && hasOwn(data, "b"))) return false + } + return true + })() + if (sub4) passes1++ + if (passes1 > 1) return false + const sub5 = (() => { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (!(data.xx !== undefined && hasOwn(data, "xx"))) return false + } + return true + })() + if (sub5) passes1++ + if (passes1 > 1) return false + const sub6 = (() => { + const evaluatedProps3 = [[], []] + if (typeof data === "object" && data && !Array.isArray(data)) { + if (!(data.all !== undefined && hasOwn(data, "all"))) return false + } + return true + })() + if (sub6) passes1++ + if (passes1 !== 1) return false + if (sub4) evaluatedProps1[0].push(...["b"]) + if (sub5) evaluatedProps1[1].push(...["x"]) + if (sub6) evaluatedProps1[0].push(true) + validate.evaluatedDynamic = [evaluatedItem1, evaluatedItems1, evaluatedProps1] + return true +}; +const propertyIn = (key, [properties, patterns]) => + properties.includes(true) || + properties.some((prop) => prop === key) || + patterns.some((pattern) => new RegExp(pattern, 'u').test(key)); +const ref0 = function validate(data) { + validate.evaluatedDynamic = null + const evaluatedItem0 = [] + const evaluatedItems0 = [0] + const evaluatedProps0 = [[], []] + let passes0 = 0 + const sub0 = (() => { + const res1 = ref1(data) + if (!res1) return false + if (res1) { + evaluatedProps0[0].push(...ref1.evaluatedDynamic[2][0]) + evaluatedProps0[1].push(...ref1.evaluatedDynamic[2][1]) + } + return true + })() + if (sub0) passes0++ + const sub7 = (() => { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (!(data.a !== undefined && hasOwn(data, "a"))) return false + } + return true + })() + if (sub7) passes0++ + if (passes0 !== 1) return false + if (sub7) evaluatedProps0[0].push(...["a"]) + if (typeof data === "object" && data && !Array.isArray(data)) { + for (const key2 of Object.keys(data)) { + if (true && !propertyIn(key2, evaluatedProps0)) return false + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] schema = true is not allowed at #/oneOf/0/properties/c` + + +## unevaluatedProperties depends on adjacent contains + +### Schema + +```json +{ + "properties": { "foo": { "type": "number" } }, + "contains": { "type": "string" }, + "unevaluatedProperties": false +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (Array.isArray(data)) { + let passes0 = 0 + for (let i = 0; i < data.length; i++) { + const sub0 = (() => { + if (data[i] !== undefined && hasOwn(data, i)) { + if (!(typeof data[i] === "string")) return false + } + return true + })() + if (sub0) passes0++ + } + if (passes0 < 1) return false + } + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.foo !== undefined && hasOwn(data, "foo")) { + if (!(typeof data.foo === "number")) return false + } + } + if (typeof data === "object" && data && !Array.isArray(data)) { + for (const key0 of Object.keys(data)) { + if (key0 !== "foo") return false + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireStringValidation] pattern, format or contentSchema should be specified for strings, use pattern: ^[\s\S]*$ to opt-out at #/contains` + +### Misclassified! + +**This schema caused 1 misclassifications!** + + +## unevaluatedProperties depends on multiple nested contains + +### Schema + +```json +{ + "allOf": [ + { "contains": { "multipleOf": 2 } }, + { "contains": { "multipleOf": 3 } } + ], + "unevaluatedProperties": { "multipleOf": 5 } +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (Array.isArray(data)) { + let passes0 = 0 + for (let i = 0; i < data.length; i++) { + const sub0 = (() => { + if (data[i] !== undefined && hasOwn(data, i)) { + if (typeof data[i] === "number") { + if (data[i] % 2 !== 0) return false + } + } + return true + })() + if (sub0) passes0++ + } + if (passes0 < 1) return false + } + if (Array.isArray(data)) { + let passes1 = 0 + for (let j = 0; j < data.length; j++) { + const sub1 = (() => { + if (data[j] !== undefined && hasOwn(data, j)) { + if (typeof data[j] === "number") { + if (data[j] % 3 !== 0) return false + } + } + return true + })() + if (sub1) passes1++ + } + if (passes1 < 1) return false + } + if (typeof data === "object" && data && !Array.isArray(data)) { + for (const key0 of Object.keys(data)) { + if (typeof data[key0] === "number") { + if (data[key0] % 5 !== 0) return false + } + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #/allOf/0/contains` + +### Misclassified! + +**This schema caused 1 misclassifications!** + + +## non-object instances are valid + +### Schema + +```json +{ "unevaluatedProperties": false } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + for (const key0 of Object.keys(data)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## unevaluatedProperties with null valued instance properties + +### Schema + +```json +{ "unevaluatedProperties": { "type": "null" } } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + for (const key0 of Object.keys(data)) { + if (!(data[key0] === null)) return false + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + diff --git a/doc/samples/draft-next/uniqueItems.md b/doc/samples/draft-next/uniqueItems.md new file mode 100644 index 0000000..d590ed3 --- /dev/null +++ b/doc/samples/draft-next/uniqueItems.md @@ -0,0 +1,322 @@ +# uniqueItems + +## uniqueItems validation + +### Schema + +```json +{ "uniqueItems": true } +``` + +### Code + +```js +'use strict' +const unique = (array) => { + if (array.length < 2) return true + if (array.length === 2) return !deepEqual(array[0], array[1]) + const objects = [] + const primitives = array.length > 20 ? new Set() : null + let primitivesCount = 0 + let pos = 0 + for (const item of array) { + if (typeof item === 'object') { + objects.push(item) + } else if (primitives) { + primitives.add(item) + if (primitives.size !== ++primitivesCount) return false + } else { + if (array.indexOf(item, pos + 1) !== -1) return false + } + pos++ + } + for (let i = 1; i < objects.length; i++) + for (let j = 0; j < i; j++) if (deepEqual(objects[i], objects[j])) return false + return true +}; +const deepEqual = (obj, obj2) => { + if (obj === obj2) return true + if (!obj || !obj2 || typeof obj !== typeof obj2) return false + if (obj !== obj2 && typeof obj !== 'object') return false + + const proto = Object.getPrototypeOf(obj) + if (proto !== Object.getPrototypeOf(obj2)) return false + + if (proto === Array.prototype) { + if (!Array.isArray(obj) || !Array.isArray(obj2)) return false + if (obj.length !== obj2.length) return false + return obj.every((x, i) => deepEqual(x, obj2[i])) + } else if (proto === Object.prototype) { + const [keys, keys2] = [Object.keys(obj), Object.keys(obj2)] + if (keys.length !== keys2.length) return false + const keyset2 = new Set([...keys, ...keys2]) + return keyset2.size === keys.length && keys.every((key) => deepEqual(obj[key], obj2[key])) + } + return false +}; +const ref0 = function validate(data) { + if (Array.isArray(data)) { + if (!unique(data)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[complexityChecks] maxItems should be specified for non-primitive uniqueItems at #` + + +## uniqueItems with an array of items + +### Schema + +```json +{ + "prefixItems": [{ "type": "boolean" }, { "type": "boolean" }], + "uniqueItems": true +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const unique = (array) => { + if (array.length < 2) return true + if (array.length === 2) return !deepEqual(array[0], array[1]) + const objects = [] + const primitives = array.length > 20 ? new Set() : null + let primitivesCount = 0 + let pos = 0 + for (const item of array) { + if (typeof item === 'object') { + objects.push(item) + } else if (primitives) { + primitives.add(item) + if (primitives.size !== ++primitivesCount) return false + } else { + if (array.indexOf(item, pos + 1) !== -1) return false + } + pos++ + } + for (let i = 1; i < objects.length; i++) + for (let j = 0; j < i; j++) if (deepEqual(objects[i], objects[j])) return false + return true +}; +const deepEqual = (obj, obj2) => { + if (obj === obj2) return true + if (!obj || !obj2 || typeof obj !== typeof obj2) return false + if (obj !== obj2 && typeof obj !== 'object') return false + + const proto = Object.getPrototypeOf(obj) + if (proto !== Object.getPrototypeOf(obj2)) return false + + if (proto === Array.prototype) { + if (!Array.isArray(obj) || !Array.isArray(obj2)) return false + if (obj.length !== obj2.length) return false + return obj.every((x, i) => deepEqual(x, obj2[i])) + } else if (proto === Object.prototype) { + const [keys, keys2] = [Object.keys(obj), Object.keys(obj2)] + if (keys.length !== keys2.length) return false + const keyset2 = new Set([...keys, ...keys2]) + return keyset2.size === keys.length && keys.every((key) => deepEqual(obj[key], obj2[key])) + } + return false +}; +const ref0 = function validate(data) { + if (Array.isArray(data)) { + if (data[0] !== undefined && hasOwn(data, 0)) { + if (!(typeof data[0] === "boolean")) return false + } + if (data[1] !== undefined && hasOwn(data, 1)) { + if (!(typeof data[1] === "boolean")) return false + } + if (!unique(data)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[complexityChecks] maxItems should be specified for non-primitive uniqueItems at #` + + +## uniqueItems with an array of items and additionalItems=false + +### Schema + +```json +{ + "prefixItems": [{ "type": "boolean" }, { "type": "boolean" }], + "uniqueItems": true, + "items": false +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const unique = (array) => { + if (array.length < 2) return true + if (array.length === 2) return !deepEqual(array[0], array[1]) + const objects = [] + const primitives = array.length > 20 ? new Set() : null + let primitivesCount = 0 + let pos = 0 + for (const item of array) { + if (typeof item === 'object') { + objects.push(item) + } else if (primitives) { + primitives.add(item) + if (primitives.size !== ++primitivesCount) return false + } else { + if (array.indexOf(item, pos + 1) !== -1) return false + } + pos++ + } + for (let i = 1; i < objects.length; i++) + for (let j = 0; j < i; j++) if (deepEqual(objects[i], objects[j])) return false + return true +}; +const deepEqual = (obj, obj2) => { + if (obj === obj2) return true + if (!obj || !obj2 || typeof obj !== typeof obj2) return false + if (obj !== obj2 && typeof obj !== 'object') return false + + const proto = Object.getPrototypeOf(obj) + if (proto !== Object.getPrototypeOf(obj2)) return false + + if (proto === Array.prototype) { + if (!Array.isArray(obj) || !Array.isArray(obj2)) return false + if (obj.length !== obj2.length) return false + return obj.every((x, i) => deepEqual(x, obj2[i])) + } else if (proto === Object.prototype) { + const [keys, keys2] = [Object.keys(obj), Object.keys(obj2)] + if (keys.length !== keys2.length) return false + const keyset2 = new Set([...keys, ...keys2]) + return keyset2.size === keys.length && keys.every((key) => deepEqual(obj[key], obj2[key])) + } + return false +}; +const ref0 = function validate(data) { + if (Array.isArray(data)) { + if (data[0] !== undefined && hasOwn(data, 0)) { + if (!(typeof data[0] === "boolean")) return false + } + if (data[1] !== undefined && hasOwn(data, 1)) { + if (!(typeof data[1] === "boolean")) return false + } + if (data.length > 2) return false + if (!unique(data)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## uniqueItems=false validation + +### Schema + +```json +{ "uniqueItems": false } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## uniqueItems=false with an array of items + +### Schema + +```json +{ + "prefixItems": [{ "type": "boolean" }, { "type": "boolean" }], + "uniqueItems": false +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (Array.isArray(data)) { + if (data[0] !== undefined && hasOwn(data, 0)) { + if (!(typeof data[0] === "boolean")) return false + } + if (data[1] !== undefined && hasOwn(data, 1)) { + if (!(typeof data[1] === "boolean")) return false + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## uniqueItems=false with an array of items and additionalItems=false + +### Schema + +```json +{ + "prefixItems": [{ "type": "boolean" }, { "type": "boolean" }], + "uniqueItems": false, + "items": false +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (Array.isArray(data)) { + if (data[0] !== undefined && hasOwn(data, 0)) { + if (!(typeof data[0] === "boolean")) return false + } + if (data[1] !== undefined && hasOwn(data, 1)) { + if (!(typeof data[1] === "boolean")) return false + } + if (data.length > 2) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + diff --git a/doc/samples/draft-next/unknownKeyword.md b/doc/samples/draft-next/unknownKeyword.md new file mode 100644 index 0000000..89aac99 --- /dev/null +++ b/doc/samples/draft-next/unknownKeyword.md @@ -0,0 +1,93 @@ +# unknownKeyword + +## $id inside an unknown keyword is not a real identifier + +### Schema + +```json +{ + "$defs": { + "id_in_unknown0": { + "not": { + "array_of_schemas": [ + { + "$id": "https://localhost:1234/draft-next/unknownKeyword/my_identifier.json", + "type": "null" + } + ] + } + }, + "real_id_in_schema": { + "$id": "https://localhost:1234/draft-next/unknownKeyword/my_identifier.json", + "type": "string" + }, + "id_in_unknown1": { + "not": { + "object_of_schemas": { + "foo": { + "$id": "https://localhost:1234/draft-next/unknownKeyword/my_identifier.json", + "type": "integer" + } + } + } + } + }, + "anyOf": [ + { "$ref": "#/$defs/id_in_unknown0" }, + { "$ref": "#/$defs/id_in_unknown1" }, + { + "$ref": "https://localhost:1234/draft-next/unknownKeyword/my_identifier.json" + } + ] +} +``` + +### Code + +```js +'use strict' +const ref1 = function validate(data) { + const sub1 = (() => { + return true + })() + if (sub1) return false + return true +}; +const ref2 = function validate(data) { + const sub3 = (() => { + return true + })() + if (sub3) return false + return true +}; +const ref3 = function validate(data) { + if (!(typeof data === "string")) return false + return true +}; +const ref0 = function validate(data) { + const sub0 = (() => { + if (!ref1(data)) return false + return true + })() + if (!sub0) { + const sub2 = (() => { + if (!ref2(data)) return false + return true + })() + if (!sub2) { + const sub4 = (() => { + if (!ref3(data)) return false + return true + })() + if (!sub4) return false + } + } + return true +}; +return ref0 +``` + +### Warnings + + * `Keyword not supported: "array_of_schemas" at #/not` + diff --git a/doc/samples/draft-next/vocabulary.md b/doc/samples/draft-next/vocabulary.md new file mode 100644 index 0000000..52fc577 --- /dev/null +++ b/doc/samples/draft-next/vocabulary.md @@ -0,0 +1,22 @@ +# vocabulary + +## schema that uses custom metaschema with with no validation vocabulary + +### Schema + +```json +{ + "$id": "https://schema/using/no/validation", + "$schema": "http://localhost:1234/draft-next/metaschema-no-validation.json", + "properties": { "badProperty": false, "numberProperty": { "minimum": 10 } } +} +``` + +### Code + +**FAILED TO COMPILE** + +### Errors + + * `Unexpected schema version: "https://localhost:1234/draft-next/metaschema-no-validation.json" at #` + diff --git a/doc/samples/draft4/README.md b/doc/samples/draft4/README.md new file mode 100644 index 0000000..55ac485 --- /dev/null +++ b/doc/samples/draft4/README.md @@ -0,0 +1,64 @@ +# Samples + +Based on JSON Schema Test Suite for `draft4`. + + +### Disambiguation + + * **Failed to compile** — schemas that did not compile in any mode. + + * **Warnings** — schemas that did not compile in the `default` mode, but compiled in `lax` + mode. + + JSON Schema spec allows usage of ineffective or unknown keywords, which is considered a mistake + by `@exodus/schemasafe` by default. `lax` mode lifts that coherence check. + + * **Misclassified** — schemas that classified at least one test value incorrectly, i.e. gave + `true` where testsuite expected `false` or vice versa. + +## Results + +| Name | Total | Failed to compile | Warnings | Misclassified | +|---------------------------------------------------------------------|-------|-------------------|----------|---------------| +| [additionalItems](./additionalItems.md) | 9 | - | 4 | - | +| [additionalProperties](./additionalProperties.md) | 7 | - | - | - | +| [allOf](./allOf.md) | 9 | - | - | - | +| [anyOf](./anyOf.md) | 5 | - | 1 | - | +| [default](./default.md) | 3 | - | - | - | +| [definitions](./definitions.md) | 1 | - | - | - | +| [dependencies](./dependencies.md) | 4 | - | - | - | +| [enum](./enum.md) | 10 | - | - | - | +| [format](./format.md) | 6 | - | - | - | +| [id](./id.md) | 1 | - | - | - | +| [infinite-loop-detection](./infinite-loop-detection.md) | 1 | - | - | - | +| [items](./items.md) | 6 | - | - | - | +| [maxItems](./maxItems.md) | 1 | - | - | - | +| [maxLength](./maxLength.md) | 1 | - | - | - | +| [maxProperties](./maxProperties.md) | 2 | - | - | - | +| [maximum](./maximum.md) | 4 | - | - | - | +| [minItems](./minItems.md) | 1 | - | - | - | +| [minLength](./minLength.md) | 1 | - | - | - | +| [minProperties](./minProperties.md) | 1 | - | - | - | +| [minimum](./minimum.md) | 4 | - | - | - | +| [multipleOf](./multipleOf.md) | 4 | - | - | - | +| [not](./not.md) | 4 | - | - | - | +| [oneOf](./oneOf.md) | 7 | - | - | - | +| [pattern](./pattern.md) | 2 | - | - | - | +| [patternProperties](./patternProperties.md) | 4 | - | - | - | +| [properties](./properties.md) | 5 | - | - | - | +| [ref](./ref.md) | 16 | - | 2 | - | +| [refRemote](./refRemote.md) | 8 | - | - | - | +| [required](./required.md) | 4 | - | - | - | +| [type](./type.md) | 11 | - | - | - | +| [uniqueItems](./uniqueItems.md) | 6 | - | - | - | +| [optional/bignum](./optional-bignum.md) | 7 | - | - | - | +| [optional/ecmascript-regex](./optional-ecmascript-regex.md) | 20 | - | - | - | +| [optional/float-overflow](./optional-float-overflow.md) | 1 | - | - | - | +| [optional/non-bmp-regex](./optional-non-bmp-regex.md) | 2 | - | - | - | +| [optional/zeroTerminatedFloats](./optional-zeroTerminatedFloats.md) | 1 | - | - | 1 | + +### Notes + +`{ isJSON: true }` option is used for better clarity, and that also corresponds to the main +expected usage pattern of this module. Without it, there would be additional checks for +`!== undefined`, which can be fast-tracked if we know that the input came from `JSON.parse()`. diff --git a/doc/samples/draft4/additionalItems.md b/doc/samples/draft4/additionalItems.md new file mode 100644 index 0000000..3da2bba --- /dev/null +++ b/doc/samples/draft4/additionalItems.md @@ -0,0 +1,268 @@ +# additionalItems + +## additionalItems as schema + +### Schema + +```json +{ "items": [{}], "additionalItems": { "type": "integer" } } +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (Array.isArray(data)) { + for (let i = 1; i < data.length; i++) { + if (data[i] !== undefined && hasOwn(data, i)) { + if (!(Number.isInteger(data[i]))) return false + } + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] empty rules node is not allowed at #/0` + + +## when items is schema, additionalItems does nothing + +### Schema + +```json +{ "items": {}, "additionalItems": false } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + return true +}; +return ref0 +``` + +### Warnings + + * `Unprocessed keywords: ["additionalItems"] at #` + + +## array of items with no additionalItems permitted + +### Schema + +```json +{ "items": [{}, {}, {}], "additionalItems": false } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (Array.isArray(data)) { + if (data.length > 3) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] empty rules node is not allowed at #/0` + + +## additionalItems as false without items + +### Schema + +```json +{ "additionalItems": false } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + return true +}; +return ref0 +``` + +### Warnings + + * `Unprocessed keywords: ["additionalItems"] at #` + + +## additionalItems are allowed by default + +### Schema + +```json +{ "items": [{ "type": "integer" }] } +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (Array.isArray(data)) { + if (data[0] !== undefined && hasOwn(data, 0)) { + if (!(Number.isInteger(data[0]))) return false + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## additionalItems does not look in applicators, valid case + +### Schema + +```json +{ + "allOf": [{ "items": [{ "type": "integer" }] }], + "additionalItems": { "type": "boolean" } +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (Array.isArray(data)) { + if (data[0] !== undefined && hasOwn(data, 0)) { + if (!(Number.isInteger(data[0]))) return false + } + } + return true +}; +return ref0 +``` + +### Warnings + + * `Unprocessed keywords: ["additionalItems"] at #` + + +## additionalItems does not look in applicators, invalid case + +### Schema + +```json +{ + "allOf": [{ "items": [{ "type": "integer" }, { "type": "string" }] }], + "items": [{ "type": "integer" }], + "additionalItems": { "type": "boolean" } +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (Array.isArray(data)) { + if (data[0] !== undefined && hasOwn(data, 0)) { + if (!(Number.isInteger(data[0]))) return false + } + for (let i = 1; i < data.length; i++) { + if (data[i] !== undefined && hasOwn(data, i)) { + if (!(typeof data[i] === "boolean")) return false + } + } + } + if (Array.isArray(data)) { + if (data[0] !== undefined && hasOwn(data, 0)) { + if (!(Number.isInteger(data[0]))) return false + } + if (data[1] !== undefined && hasOwn(data, 1)) { + if (!(typeof data[1] === "string")) return false + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireStringValidation] pattern, format or contentSchema should be specified for strings, use pattern: ^[\s\S]*$ to opt-out at #/allOf/0/1` + + +## items validation adjusts the starting index for additionalItems + +### Schema + +```json +{ "items": [{ "type": "string" }], "additionalItems": { "type": "integer" } } +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (Array.isArray(data)) { + if (data[0] !== undefined && hasOwn(data, 0)) { + if (!(typeof data[0] === "string")) return false + } + for (let i = 1; i < data.length; i++) { + if (data[i] !== undefined && hasOwn(data, i)) { + if (!(Number.isInteger(data[i]))) return false + } + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireStringValidation] pattern, format or contentSchema should be specified for strings, use pattern: ^[\s\S]*$ to opt-out at #/0` + + +## additionalItems with null instance elements + +### Schema + +```json +{ "additionalItems": { "type": "null" } } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + return true +}; +return ref0 +``` + +### Warnings + + * `Unprocessed keywords: ["additionalItems"] at #` + diff --git a/doc/samples/draft4/additionalProperties.md b/doc/samples/draft4/additionalProperties.md new file mode 100644 index 0000000..33da910 --- /dev/null +++ b/doc/samples/draft4/additionalProperties.md @@ -0,0 +1,204 @@ +# additionalProperties + +## additionalProperties being false does not allow other properties + +### Schema + +```json +{ + "properties": { "foo": {}, "bar": {} }, + "patternProperties": { "^v": {} }, + "additionalProperties": false +} +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + for (const key1 of Object.keys(data)) { + if (key1 !== "foo" && key1 !== "bar" && !(key1.startsWith("v"))) return false + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] empty rules node is not allowed at #/properties/foo` + + +## non-ASCII pattern with additionalProperties + +### Schema + +```json +{ "patternProperties": { "^á": {} }, "additionalProperties": false } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + for (const key1 of Object.keys(data)) { + if (!(key1.startsWith("á"))) return false + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `Should start with ^ and end with $: "^á" at #` + + +## additionalProperties with schema + +### Schema + +```json +{ + "properties": { "foo": {}, "bar": {} }, + "additionalProperties": { "type": "boolean" } +} +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + for (const key0 of Object.keys(data)) { + if (key0 !== "foo" && key0 !== "bar") { + if (!(typeof data[key0] === "boolean")) return false + } + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] empty rules node is not allowed at #/properties/foo` + + +## additionalProperties can exist by itself + +### Schema + +```json +{ "additionalProperties": { "type": "boolean" } } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + for (const key0 of Object.keys(data)) { + if (!(typeof data[key0] === "boolean")) return false + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## additionalProperties are allowed by default + +### Schema + +```json +{ "properties": { "foo": {}, "bar": {} } } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] empty rules node is not allowed at #/properties/foo` + + +## additionalProperties does not look in applicators + +### Schema + +```json +{ + "allOf": [{ "properties": { "foo": {} } }], + "additionalProperties": { "type": "boolean" } +} +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + for (const key0 of Object.keys(data)) { + if (!(typeof data[key0] === "boolean")) return false + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] empty rules node is not allowed at #/allOf/0/properties/foo` + + +## additionalProperties with null valued instance properties + +### Schema + +```json +{ "additionalProperties": { "type": "null" } } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + for (const key0 of Object.keys(data)) { + if (!(data[key0] === null)) return false + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + diff --git a/doc/samples/draft4/allOf.md b/doc/samples/draft4/allOf.md new file mode 100644 index 0000000..de72f01 --- /dev/null +++ b/doc/samples/draft4/allOf.md @@ -0,0 +1,260 @@ +# allOf + +## allOf + +### Schema + +```json +{ + "allOf": [ + { "properties": { "bar": { "type": "integer" } }, "required": ["bar"] }, + { "properties": { "foo": { "type": "string" } }, "required": ["foo"] } + ] +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (!(data.bar !== undefined && hasOwn(data, "bar"))) return false + if (!Number.isInteger(data.bar)) return false + } + if (typeof data === "object" && data && !Array.isArray(data)) { + if (!(data.foo !== undefined && hasOwn(data, "foo"))) return false + if (!(typeof data.foo === "string")) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireStringValidation] pattern, format or contentSchema should be specified for strings, use pattern: ^[\s\S]*$ to opt-out at #/allOf/1/properties/foo` + + +## allOf with base schema + +### Schema + +```json +{ + "properties": { "bar": { "type": "integer" } }, + "required": ["bar"], + "allOf": [ + { "properties": { "foo": { "type": "string" } }, "required": ["foo"] }, + { "properties": { "baz": { "type": "null" } }, "required": ["baz"] } + ] +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (!(data.bar !== undefined && hasOwn(data, "bar"))) return false + if (!Number.isInteger(data.bar)) return false + } + if (typeof data === "object" && data && !Array.isArray(data)) { + if (!(data.foo !== undefined && hasOwn(data, "foo"))) return false + if (!(typeof data.foo === "string")) return false + } + if (typeof data === "object" && data && !Array.isArray(data)) { + if (!(data.baz !== undefined && hasOwn(data, "baz"))) return false + if (!(data.baz === null)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireStringValidation] pattern, format or contentSchema should be specified for strings, use pattern: ^[\s\S]*$ to opt-out at #/allOf/0/properties/foo` + + +## allOf simple types + +### Schema + +```json +{ "allOf": [{ "maximum": 30 }, { "minimum": 20 }] } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (typeof data === "number") { + if (!(30 >= data)) return false + } + if (typeof data === "number") { + if (!(20 <= data)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## allOf with one empty schema + +### Schema + +```json +{ "allOf": [{}] } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] empty rules node is not allowed at #/allOf/0` + + +## allOf with two empty schemas + +### Schema + +```json +{ "allOf": [{}, {}] } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] empty rules node is not allowed at #/allOf/0` + + +## allOf with the first empty schema + +### Schema + +```json +{ "allOf": [{}, { "type": "number" }] } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (!(typeof data === "number")) return false + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] empty rules node is not allowed at #/allOf/0` + + +## allOf with the last empty schema + +### Schema + +```json +{ "allOf": [{ "type": "number" }, {}] } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (!(typeof data === "number")) return false + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] empty rules node is not allowed at #/allOf/1` + + +## nested allOf, to check validation semantics + +### Schema + +```json +{ "allOf": [{ "allOf": [{ "type": "null" }] }] } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (!(data === null)) return false + return true +}; +return ref0 +``` + + +## allOf combined with anyOf, oneOf + +### Schema + +```json +{ + "allOf": [{ "multipleOf": 2 }], + "anyOf": [{ "multipleOf": 3 }], + "oneOf": [{ "multipleOf": 5 }] +} +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (typeof data === "number") { + if (data % 2 !== 0) return false + } + if (typeof data === "number") { + if (data % 3 !== 0) return false + } + if (typeof data === "number") { + if (data % 5 !== 0) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + diff --git a/doc/samples/draft4/anyOf.md b/doc/samples/draft4/anyOf.md new file mode 100644 index 0000000..9472ae3 --- /dev/null +++ b/doc/samples/draft4/anyOf.md @@ -0,0 +1,167 @@ +# anyOf + +## anyOf + +### Schema + +```json +{ "anyOf": [{ "type": "integer" }, { "minimum": 2 }] } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + const sub0 = (() => { + if (!Number.isInteger(data)) return false + return true + })() + if (!sub0) { + const sub1 = (() => { + if (typeof data === "number") { + if (!(2 <= data)) return false + } + return true + })() + if (!sub1) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## anyOf with base schema + +### Schema + +```json +{ "type": "string", "anyOf": [{ "maxLength": 2 }, { "minLength": 4 }] } +``` + +### Code + +```js +'use strict' +const stringLength = (string) => + /[\uD800-\uDFFF]/.test(string) ? [...string].length : string.length; +const ref0 = function validate(data) { + if (!(typeof data === "string")) return false + const sub0 = (() => { + if (data.length > 2 && stringLength(data) > 2) return false + return true + })() + if (!sub0) { + const sub1 = (() => { + if (data.length < 4 || stringLength(data) < 4) return false + return true + })() + if (!sub1) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireStringValidation] pattern, format or contentSchema should be specified for strings, use pattern: ^[\s\S]*$ to opt-out at #` + + +## anyOf complex types + +### Schema + +```json +{ + "anyOf": [ + { "properties": { "bar": { "type": "integer" } }, "required": ["bar"] }, + { "properties": { "foo": { "type": "string" } }, "required": ["foo"] } + ] +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + const sub0 = (() => { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (!(data.bar !== undefined && hasOwn(data, "bar"))) return false + if (!Number.isInteger(data.bar)) return false + } + return true + })() + if (!sub0) { + const sub1 = (() => { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (!(data.foo !== undefined && hasOwn(data, "foo"))) return false + if (!(typeof data.foo === "string")) return false + } + return true + })() + if (!sub1) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireStringValidation] pattern, format or contentSchema should be specified for strings, use pattern: ^[\s\S]*$ to opt-out at #/anyOf/1/properties/foo` + + +## anyOf with one empty schema + +### Schema + +```json +{ "anyOf": [{ "type": "number" }, {}] } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + const sub0 = (() => { + if (!(typeof data === "number")) return false + return true + })() + return true +}; +return ref0 +``` + +### Warnings + + * `some checks are never reachable at #` + + +## nested anyOf, to check validation semantics + +### Schema + +```json +{ "anyOf": [{ "anyOf": [{ "type": "null" }] }] } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (!(data === null)) return false + return true +}; +return ref0 +``` + diff --git a/doc/samples/draft4/default.md b/doc/samples/draft4/default.md new file mode 100644 index 0000000..9e6b1e6 --- /dev/null +++ b/doc/samples/draft4/default.md @@ -0,0 +1,98 @@ +# default + +## invalid type for default + +### Schema + +```json +{ "properties": { "foo": { "type": "integer", "default": [] } } } +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.foo !== undefined && hasOwn(data, "foo")) { + if (!Number.isInteger(data.foo)) return false + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## invalid string value for default + +### Schema + +```json +{ + "properties": { + "bar": { "type": "string", "minLength": 4, "default": "bad" } + } +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const stringLength = (string) => + /[\uD800-\uDFFF]/.test(string) ? [...string].length : string.length; +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.bar !== undefined && hasOwn(data, "bar")) { + if (!(typeof data.bar === "string")) return false + if (data.bar.length < 4 || stringLength(data.bar) < 4) return false + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireStringValidation] pattern, format or contentSchema should be specified for strings, use pattern: ^[\s\S]*$ to opt-out at #/properties/bar` + + +## the default keyword does not do anything if the property is missing + +### Schema + +```json +{ + "type": "object", + "properties": { "alpha": { "type": "number", "maximum": 3, "default": 5 } } +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (!(typeof data === "object" && data && !Array.isArray(data))) return false + if (data.alpha !== undefined && hasOwn(data, "alpha")) { + if (!(typeof data.alpha === "number")) return false + if (!(3 >= data.alpha)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] additionalProperties or unevaluatedProperties should be specified at #` + diff --git a/doc/samples/draft4/definitions.md b/doc/samples/draft4/definitions.md new file mode 100644 index 0000000..a43c581 --- /dev/null +++ b/doc/samples/draft4/definitions.md @@ -0,0 +1,288 @@ +# definitions + +## validate definition against metaschema + +### Schema + +```json +{ "$ref": "http://json-schema.org/draft-04/schema#" } +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref2 = function validate(data) { + if (!Number.isInteger(data)) return false + if (!(0 <= data)) return false + return true +}; +const ref3 = function validate(data) { + if (!ref2(data)) return false + return true +}; +const format0 = (str) => { + if (str.length > 1e5) return false + const Z_ANCHOR = /[^\\]\\Z/ + if (Z_ANCHOR.test(str)) return false + try { + new RegExp(str, 'u') + return true + } catch (e) { + return false + } + }; +const ref4 = function validate(data) { + if (!Array.isArray(data)) return false + if (data.length < 1) return false + for (let i = 0; i < data.length; i++) { + if (data[i] !== undefined && hasOwn(data, i)) { + if (!ref1(data[i])) return false + } + } + return true +}; +const unique = (array) => { + if (array.length < 2) return true + if (array.length === 2) return !deepEqual(array[0], array[1]) + const objects = [] + const primitives = array.length > 20 ? new Set() : null + let primitivesCount = 0 + let pos = 0 + for (const item of array) { + if (typeof item === 'object') { + objects.push(item) + } else if (primitives) { + primitives.add(item) + if (primitives.size !== ++primitivesCount) return false + } else { + if (array.indexOf(item, pos + 1) !== -1) return false + } + pos++ + } + for (let i = 1; i < objects.length; i++) + for (let j = 0; j < i; j++) if (deepEqual(objects[i], objects[j])) return false + return true +}; +const deepEqual = (obj, obj2) => { + if (obj === obj2) return true + if (!obj || !obj2 || typeof obj !== typeof obj2) return false + if (obj !== obj2 && typeof obj !== 'object') return false + + const proto = Object.getPrototypeOf(obj) + if (proto !== Object.getPrototypeOf(obj2)) return false + + if (proto === Array.prototype) { + if (!Array.isArray(obj) || !Array.isArray(obj2)) return false + if (obj.length !== obj2.length) return false + return obj.every((x, i) => deepEqual(x, obj2[i])) + } else if (proto === Object.prototype) { + const [keys, keys2] = [Object.keys(obj), Object.keys(obj2)] + if (keys.length !== keys2.length) return false + const keyset2 = new Set([...keys, ...keys2]) + return keyset2.size === keys.length && keys.every((key) => deepEqual(obj[key], obj2[key])) + } + return false +}; +const ref5 = function validate(data) { + if (!Array.isArray(data)) return false + if (data.length < 1) return false + for (let j = 0; j < data.length; j++) { + if (data[j] !== undefined && hasOwn(data, j)) { + if (!(typeof data[j] === "string")) return false + } + } + if (!unique(data)) return false + return true +}; +const ref6 = function validate(data) { + if (!(data === "array" || data === "boolean" || data === "integer" || data === "null" || data === "number" || data === "object" || data === "string")) return false + return true +}; +const ref1 = function validate(data) { + if (!(typeof data === "object" && data && !Array.isArray(data))) return false + if (data.exclusiveMaximum !== undefined && hasOwn(data, "exclusiveMaximum") && !(data.maximum !== undefined && hasOwn(data, "maximum"))) return false + if (data.exclusiveMinimum !== undefined && hasOwn(data, "exclusiveMinimum") && !(data.minimum !== undefined && hasOwn(data, "minimum"))) return false + if (data.id !== undefined && hasOwn(data, "id")) { + if (!(typeof data.id === "string")) return false + } + if (data["$schema"] !== undefined && hasOwn(data, "$schema")) { + if (!(typeof data["$schema"] === "string")) return false + } + if (data.title !== undefined && hasOwn(data, "title")) { + if (!(typeof data.title === "string")) return false + } + if (data.description !== undefined && hasOwn(data, "description")) { + if (!(typeof data.description === "string")) return false + } + if (data.multipleOf !== undefined && hasOwn(data, "multipleOf")) { + if (!(typeof data.multipleOf === "number")) return false + if (!(0 < data.multipleOf)) return false + } + if (data.maximum !== undefined && hasOwn(data, "maximum")) { + if (!(typeof data.maximum === "number")) return false + } + if (data.exclusiveMaximum !== undefined && hasOwn(data, "exclusiveMaximum")) { + if (!(typeof data.exclusiveMaximum === "boolean")) return false + } + if (data.minimum !== undefined && hasOwn(data, "minimum")) { + if (!(typeof data.minimum === "number")) return false + } + if (data.exclusiveMinimum !== undefined && hasOwn(data, "exclusiveMinimum")) { + if (!(typeof data.exclusiveMinimum === "boolean")) return false + } + if (data.maxLength !== undefined && hasOwn(data, "maxLength")) { + if (!ref2(data.maxLength)) return false + } + if (data.minLength !== undefined && hasOwn(data, "minLength")) { + if (!ref3(data.minLength)) return false + } + if (data.pattern !== undefined && hasOwn(data, "pattern")) { + if (!(typeof data.pattern === "string")) return false + if (!format0(data.pattern)) return false + } + if (data.additionalItems !== undefined && hasOwn(data, "additionalItems")) { + const sub0 = (() => { + if (!(typeof data.additionalItems === "boolean")) return false + return true + })() + if (!sub0) { + const sub1 = (() => { + if (!validate(data.additionalItems)) return false + return true + })() + if (!sub1) return false + } + } + if (data.items !== undefined && hasOwn(data, "items")) { + const sub2 = (() => { + if (!validate(data.items)) return false + return true + })() + if (!sub2) { + const sub3 = (() => { + if (!ref4(data.items)) return false + return true + })() + if (!sub3) return false + } + } + if (data.maxItems !== undefined && hasOwn(data, "maxItems")) { + if (!ref2(data.maxItems)) return false + } + if (data.minItems !== undefined && hasOwn(data, "minItems")) { + if (!ref3(data.minItems)) return false + } + if (data.uniqueItems !== undefined && hasOwn(data, "uniqueItems")) { + if (!(typeof data.uniqueItems === "boolean")) return false + } + if (data.maxProperties !== undefined && hasOwn(data, "maxProperties")) { + if (!ref2(data.maxProperties)) return false + } + if (data.minProperties !== undefined && hasOwn(data, "minProperties")) { + if (!ref3(data.minProperties)) return false + } + if (data.required !== undefined && hasOwn(data, "required")) { + if (!ref5(data.required)) return false + } + if (data.additionalProperties !== undefined && hasOwn(data, "additionalProperties")) { + const sub4 = (() => { + if (!(typeof data.additionalProperties === "boolean")) return false + return true + })() + if (!sub4) { + const sub5 = (() => { + if (!validate(data.additionalProperties)) return false + return true + })() + if (!sub5) return false + } + } + if (data.definitions !== undefined && hasOwn(data, "definitions")) { + if (!(typeof data.definitions === "object" && data.definitions && !Array.isArray(data.definitions))) return false + for (const key0 of Object.keys(data.definitions)) { + if (!validate(data.definitions[key0])) return false + } + } + if (data.properties !== undefined && hasOwn(data, "properties")) { + if (!(typeof data.properties === "object" && data.properties && !Array.isArray(data.properties))) return false + for (const key1 of Object.keys(data.properties)) { + if (!validate(data.properties[key1])) return false + } + } + if (data.patternProperties !== undefined && hasOwn(data, "patternProperties")) { + if (!(typeof data.patternProperties === "object" && data.patternProperties && !Array.isArray(data.patternProperties))) return false + for (const key2 of Object.keys(data.patternProperties)) { + if (!validate(data.patternProperties[key2])) return false + } + } + if (data.dependencies !== undefined && hasOwn(data, "dependencies")) { + if (!(typeof data.dependencies === "object" && data.dependencies && !Array.isArray(data.dependencies))) return false + for (const key3 of Object.keys(data.dependencies)) { + const sub6 = (() => { + if (!validate(data.dependencies[key3])) return false + return true + })() + if (!sub6) { + const sub7 = (() => { + if (!ref5(data.dependencies[key3])) return false + return true + })() + if (!sub7) return false + } + } + } + if (data.enum !== undefined && hasOwn(data, "enum")) { + if (!Array.isArray(data.enum)) return false + if (data.enum.length < 1) return false + if (!unique(data.enum)) return false + } + if (data.type !== undefined && hasOwn(data, "type")) { + const sub8 = (() => { + if (!ref6(data.type)) return false + return true + })() + if (!sub8) { + const sub9 = (() => { + if (!Array.isArray(data.type)) return false + if (data.type.length < 1) return false + for (let k = 0; k < data.type.length; k++) { + if (data.type[k] !== undefined && hasOwn(data.type, k)) { + if (!ref6(data.type[k])) return false + } + } + if (!unique(data.type)) return false + return true + })() + if (!sub9) return false + } + } + if (data.format !== undefined && hasOwn(data, "format")) { + if (!(typeof data.format === "string")) return false + } + if (data.allOf !== undefined && hasOwn(data, "allOf")) { + if (!ref4(data.allOf)) return false + } + if (data.anyOf !== undefined && hasOwn(data, "anyOf")) { + if (!ref4(data.anyOf)) return false + } + if (data.oneOf !== undefined && hasOwn(data, "oneOf")) { + if (!ref4(data.oneOf)) return false + } + if (data.not !== undefined && hasOwn(data, "not")) { + if (!validate(data.not)) return false + } + return true +}; +const ref0 = function validate(data) { + if (!ref1(data)) return false + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireStringValidation] pattern, format or contentSchema should be specified for strings, use pattern: ^[\s\S]*$ to opt-out at http://json-schema.org/draft-04/schema#/properties/id` + diff --git a/doc/samples/draft4/dependencies.md b/doc/samples/draft4/dependencies.md new file mode 100644 index 0000000..86719c3 --- /dev/null +++ b/doc/samples/draft4/dependencies.md @@ -0,0 +1,145 @@ +# dependencies + +## dependencies + +### Schema + +```json +{ "dependencies": { "bar": ["foo"] } } +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.bar !== undefined && hasOwn(data, "bar") && !(data.foo !== undefined && hasOwn(data, "foo"))) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## multiple dependencies + +### Schema + +```json +{ "dependencies": { "quux": ["foo", "bar"] } } +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.quux !== undefined && hasOwn(data, "quux") && !(data.foo !== undefined && hasOwn(data, "foo") && data.bar !== undefined && hasOwn(data, "bar"))) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## multiple dependencies subschema + +### Schema + +```json +{ + "dependencies": { + "bar": { + "properties": { + "foo": { "type": "integer" }, + "bar": { "type": "integer" } + } + } + } +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.bar !== undefined && hasOwn(data, "bar")) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.foo !== undefined && hasOwn(data, "foo")) { + if (!Number.isInteger(data.foo)) return false + } + if (data.bar !== undefined && hasOwn(data, "bar")) { + if (!Number.isInteger(data.bar)) return false + } + } + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] if properties is used, required should be specified at #/dependencies/bar` + + +## dependencies with escaped characters + +### Schema + +```json +{ + "dependencies": { + "foo\nbar": ["foo\rbar"], + "foo\tbar": { "minProperties": 4 }, + "foo'bar": { "required": ["foo\"bar"] }, + "foo\"bar": ["foo'bar"] + } +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data["foo\nbar"] !== undefined && hasOwn(data, "foo\nbar") && !(data["foo\rbar"] !== undefined && hasOwn(data, "foo\rbar"))) return false + if (data["foo\tbar"] !== undefined && hasOwn(data, "foo\tbar")) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (Object.keys(data).length < 4) return false + } + } + if (data["foo'bar"] !== undefined && hasOwn(data, "foo'bar")) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (!(data["foo\"bar"] !== undefined && hasOwn(data, "foo\"bar"))) return false + } + } + if (data["foo\"bar"] !== undefined && hasOwn(data, "foo\"bar") && !(data["foo'bar"] !== undefined && hasOwn(data, "foo'bar"))) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + diff --git a/doc/samples/draft4/enum.md b/doc/samples/draft4/enum.md new file mode 100644 index 0000000..f72f0da --- /dev/null +++ b/doc/samples/draft4/enum.md @@ -0,0 +1,216 @@ +# enum + +## simple enum validation + +### Schema + +```json +{ "enum": [1, 2, 3] } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (!(data === 1 || data === 2 || data === 3)) return false + return true +}; +return ref0 +``` + + +## heterogeneous enum validation + +### Schema + +```json +{ "enum": [6, "foo", [], true, { "foo": 12 }] } +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (!(data === 6 || data === "foo" || data === true || Array.isArray(data) && data.length === 0 || typeof data === "object" && data && !Array.isArray(data) && Object.keys(data).length === 1 && hasOwn(data, "foo") && data["foo"] === 12)) return false + return true +}; +return ref0 +``` + + +## heterogeneous enum-with-null validation + +### Schema + +```json +{ "enum": [6, null] } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (!(data === 6 || data === null)) return false + return true +}; +return ref0 +``` + + +## enums in properties + +### Schema + +```json +{ + "type": "object", + "properties": { "foo": { "enum": ["foo"] }, "bar": { "enum": ["bar"] } }, + "required": ["bar"] +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (!(typeof data === "object" && data && !Array.isArray(data))) return false + if (!(data.bar !== undefined && hasOwn(data, "bar"))) return false + if (data.foo !== undefined && hasOwn(data, "foo")) { + if (!(data.foo === "foo")) return false + } + if (!(data.bar === "bar")) return false + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] additionalProperties or unevaluatedProperties should be specified at #` + + +## enum with escaped characters + +### Schema + +```json +{ "enum": ["foo\nbar", "foo\rbar"] } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (!(data === "foo\nbar" || data === "foo\rbar")) return false + return true +}; +return ref0 +``` + + +## enum with false does not match 0 + +### Schema + +```json +{ "enum": [false] } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (!(data === false)) return false + return true +}; +return ref0 +``` + + +## enum with true does not match 1 + +### Schema + +```json +{ "enum": [true] } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (!(data === true)) return false + return true +}; +return ref0 +``` + + +## enum with 0 does not match false + +### Schema + +```json +{ "enum": [0] } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (!(data === 0)) return false + return true +}; +return ref0 +``` + + +## enum with 1 does not match true + +### Schema + +```json +{ "enum": [1] } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (!(data === 1)) return false + return true +}; +return ref0 +``` + + +## nul characters in strings + +### Schema + +```json +{ "enum": ["hello\u0000there"] } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (!(data === "hello\u0000there")) return false + return true +}; +return ref0 +``` + diff --git a/doc/samples/draft4/format.md b/doc/samples/draft4/format.md new file mode 100644 index 0000000..b4e7eb7 --- /dev/null +++ b/doc/samples/draft4/format.md @@ -0,0 +1,233 @@ +# format + +## email format + +### Schema + +```json +{ "format": "email" } +``` + +### Code + +```js +'use strict' +const format0 = (input) => { + if (input.length > 318) return false + const fast = /^[a-z0-9!#$%&'*+/=?^_`{|}~-]{1,20}(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]{1,21}){0,2}@[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?(?:\.[a-z0-9](?:[a-z0-9-]{0,60}[a-z0-9])?){0,3}$/i + if (fast.test(input)) return true + if (!input.includes('@') || /(^\.|^"|\.@|\.\.)/.test(input)) return false + const [name, host, ...rest] = input.split('@') + if (!name || !host || rest.length !== 0 || name.length > 64 || host.length > 253) return false + if (!/^[a-z0-9.-]+$/i.test(host) || !/^[a-z0-9.!#$%&'*+/=?^_`{|}~-]+$/i.test(name)) return false + return host.split('.').every((part) => /^[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?$/i.test(part)) + }; +const ref0 = function validate(data) { + if (typeof data === "string") { + if (!format0(data)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## ipv4 format + +### Schema + +```json +{ "format": "ipv4" } +``` + +### Code + +```js +'use strict' +const format0 = (ip) => + ip.length <= 15 && + /^(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)\.){3}(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d\d?)$/.test(ip); +const ref0 = function validate(data) { + if (typeof data === "string") { + if (!format0(data)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## ipv6 format + +### Schema + +```json +{ "format": "ipv6" } +``` + +### Code + +```js +'use strict' +const format0 = (input) => { + if (input.length > 45 || input.length < 2) return false + let s0 = 0, s1 = 0, hex = 0, short = false, letters = false, last = 0, start = true + for (let i = 0; i < input.length; i++) { + const c = input.charCodeAt(i) + if (i === 1 && last === 58 && c !== 58) return false + if (c >= 48 && c <= 57) { + if (++hex > 4) return false + } else if (c === 46) { + if (s0 > 6 || s1 >= 3 || hex === 0 || letters) return false + s1++ + hex = 0 + } else if (c === 58) { + if (s1 > 0 || s0 >= 7) return false + if (last === 58) { + if (short) return false + short = true + } else if (i === 0) start = false + s0++ + hex = 0 + letters = false + } else if ((c >= 97 && c <= 102) || (c >= 65 && c <= 70)) { + if (s1 > 0) return false + if (++hex > 4) return false + letters = true + } else return false + last = c + } + if (s0 < 2 || (s1 > 0 && (s1 !== 3 || hex === 0))) return false + if (short && input.length === 2) return true + if (s1 > 0 && !/(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}$/.test(input)) return false + const spaces = s1 > 0 ? 6 : 7 + if (!short) return s0 === spaces && start && hex > 0 + return (start || hex > 0) && s0 < spaces + }; +const ref0 = function validate(data) { + if (typeof data === "string") { + if (!format0(data)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## hostname format + +### Schema + +```json +{ "format": "hostname" } +``` + +### Code + +```js +'use strict' +const format0 = (input) => { + if (input.length > (input.endsWith('.') ? 254 : 253)) return false + const hostname = /^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?(?:\.[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?)*\.?$/i + return hostname.test(input) + }; +const ref0 = function validate(data) { + if (typeof data === "string") { + if (!format0(data)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## date-time format + +### Schema + +```json +{ "format": "date-time" } +``` + +### Code + +```js +'use strict' +const format0 = (input) => { + if (input.length > 10 + 1 + 9 + 12 + 6) return false + const full = /^\d\d\d\d-(?:0[1-9]|1[0-2])-(?:[0-2]\d|3[01])[t\s](?:2[0-3]|[0-1]\d):[0-5]\d:(?:[0-5]\d|60)(?:\.\d+)?(?:z|[+-](?:2[0-3]|[0-1]\d)(?::?[0-5]\d)?)$/i + const feb = input[5] === '0' && input[6] === '2' + if ((feb && input[8] === '3') || !full.test(input)) return false + if (input[17] === '6') { + const p = input.slice(11).match(/([0-9.]+|[^0-9.])/g) + let hm = Number(p[0]) * 60 + Number(p[2]) + if (p[5] === '+') hm += 24 * 60 - Number(p[6] || 0) * 60 - Number(p[8] || 0) + else if (p[5] === '-') hm += Number(p[6] || 0) * 60 + Number(p[8] || 0) + if (hm % (24 * 60) !== 23 * 60 + 59) return false + } + if (feb) { + if (/^\d\d\d\d-02-(?:[012][1-8]|[12]0|[01]9)/.test(input)) return true + const matches = input.match(/^(\d\d\d\d)-02-29/) + if (!matches) return false + const year = matches[1] | 0 + return year % 16 === 0 || (year % 4 === 0 && year % 25 !== 0) + } + if (input[8] === '3' && input[9] === '1') return /^\d\d\d\d-(?:0[13578]|1[02])-31/.test(input) + return /^\d\d\d\d-(?:0[13-9]|1[012])-(?:[012][1-9]|[123]0)/.test(input) + }; +const ref0 = function validate(data) { + if (typeof data === "string") { + if (!format0(data)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## uri format + +### Schema + +```json +{ "format": "uri" } +``` + +### Code + +```js +'use strict' +const format0 = new RegExp("^[a-z][a-z0-9+\\-.]*:(?:\\/?\\/(?:(?:[a-z0-9\\-._~!$&'()*+,;=:]|%[0-9a-f]{2})*@)?(?:\\[(?:(?:(?:(?:[0-9a-f]{1,4}:){6}|::(?:[0-9a-f]{1,4}:){5}|(?:[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){4}|(?:(?:[0-9a-f]{1,4}:){0,1}[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){3}|(?:(?:[0-9a-f]{1,4}:){0,2}[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){2}|(?:(?:[0-9a-f]{1,4}:){0,3}[0-9a-f]{1,4})?::[0-9a-f]{1,4}:|(?:(?:[0-9a-f]{1,4}:){0,4}[0-9a-f]{1,4})?::)(?:[0-9a-f]{1,4}:[0-9a-f]{1,4}|(?:(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d\\d?)\\.){3}(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d\\d?))|(?:(?:[0-9a-f]{1,4}:){0,5}[0-9a-f]{1,4})?::[0-9a-f]{1,4}|(?:(?:[0-9a-f]{1,4}:){0,6}[0-9a-f]{1,4})?::)|v[0-9a-f]+\\.[a-z0-9\\-._~!$&'()*+,;=:]+)\\]|(?:(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d\\d?)\\.){3}(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d\\d?)|(?:[a-z0-9\\-._~!$&'()*+,;=]|%[0-9a-f]{2})*)(?::\\d*)?(?:\\/(?:[a-z0-9\\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})*)*|\\/?(?:(?:[a-z0-9\\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})+(?:\\/(?:[a-z0-9\\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})*)*)?)(?:\\?(?:[a-z0-9\\-._~!$&'()*+,;=:@/?]|%[0-9a-f]{2})*)?(?:#(?:[a-z0-9\\-._~!$&'()*+,;=:@/?]|%[0-9a-f]{2})*)?$", "i"); +const ref0 = function validate(data) { + if (typeof data === "string") { + if (!format0.test(data)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + diff --git a/doc/samples/draft4/id.md b/doc/samples/draft4/id.md new file mode 100644 index 0000000..c44fd6e --- /dev/null +++ b/doc/samples/draft4/id.md @@ -0,0 +1,66 @@ +# id + +## id inside an enum is not a real identifier + +### Schema + +```json +{ + "definitions": { + "id_in_enum": { + "enum": [ + { "id": "https://localhost:1234/my_identifier.json", "type": "null" } + ] + }, + "real_id_in_schema": { + "id": "https://localhost:1234/my_identifier.json", + "type": "string" + }, + "zzz_id_in_const": { + "const": { + "id": "https://localhost:1234/my_identifier.json", + "type": "null" + } + } + }, + "anyOf": [ + { "$ref": "#/definitions/id_in_enum" }, + { "$ref": "https://localhost:1234/my_identifier.json" } + ] +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref1 = function validate(data) { + if (!(typeof data === "object" && data && !Array.isArray(data) && Object.keys(data).length === 2 && hasOwn(data, "id") && hasOwn(data, "type") && data["id"] === "https://localhost:1234/my_identifier.json" && data["type"] === "null")) return false + return true +}; +const ref2 = function validate(data) { + if (!(typeof data === "string")) return false + return true +}; +const ref0 = function validate(data) { + const sub0 = (() => { + if (!ref1(data)) return false + return true + })() + if (!sub0) { + const sub1 = (() => { + if (!ref2(data)) return false + return true + })() + if (!sub1) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireStringValidation] pattern, format or contentSchema should be specified for strings, use pattern: ^[\s\S]*$ to opt-out at #` + diff --git a/doc/samples/draft4/infinite-loop-detection.md b/doc/samples/draft4/infinite-loop-detection.md new file mode 100644 index 0000000..429be5c --- /dev/null +++ b/doc/samples/draft4/infinite-loop-detection.md @@ -0,0 +1,45 @@ +# infinite-loop-detection + +## evaluating the same schema location against the same data location twice is not a sign of an infinite loop + +### Schema + +```json +{ + "definitions": { "int": { "type": "integer" } }, + "allOf": [ + { "properties": { "foo": { "$ref": "#/definitions/int" } } }, + { "additionalProperties": { "$ref": "#/definitions/int" } } + ] +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref1 = function validate(data) { + if (!Number.isInteger(data)) return false + return true +}; +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.foo !== undefined && hasOwn(data, "foo")) { + if (!ref1(data.foo)) return false + } + } + if (typeof data === "object" && data && !Array.isArray(data)) { + for (const key0 of Object.keys(data)) { + if (!ref1(data[key0])) return false + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] if properties is used, required should be specified at #/allOf/0` + diff --git a/doc/samples/draft4/items.md b/doc/samples/draft4/items.md new file mode 100644 index 0000000..dfbd428 --- /dev/null +++ b/doc/samples/draft4/items.md @@ -0,0 +1,244 @@ +# items + +## a schema given for items + +### Schema + +```json +{ "items": { "type": "integer" } } +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (Array.isArray(data)) { + for (let i = 0; i < data.length; i++) { + if (data[i] !== undefined && hasOwn(data, i)) { + if (!(Number.isInteger(data[i]))) return false + } + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## an array of schemas for items + +### Schema + +```json +{ "items": [{ "type": "integer" }, { "type": "string" }] } +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (Array.isArray(data)) { + if (data[0] !== undefined && hasOwn(data, 0)) { + if (!(Number.isInteger(data[0]))) return false + } + if (data[1] !== undefined && hasOwn(data, 1)) { + if (!(typeof data[1] === "string")) return false + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireStringValidation] pattern, format or contentSchema should be specified for strings, use pattern: ^[\s\S]*$ to opt-out at #/1` + + +## items and subitems + +### Schema + +```json +{ + "definitions": { + "item": { + "type": "array", + "additionalItems": false, + "items": [ + { "$ref": "#/definitions/sub-item" }, + { "$ref": "#/definitions/sub-item" } + ] + }, + "sub-item": { "type": "object", "required": ["foo"] } + }, + "type": "array", + "additionalItems": false, + "items": [ + { "$ref": "#/definitions/item" }, + { "$ref": "#/definitions/item" }, + { "$ref": "#/definitions/item" } + ] +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref2 = function validate(data) { + if (!(typeof data === "object" && data && !Array.isArray(data))) return false + if (!(data.foo !== undefined && hasOwn(data, "foo"))) return false + return true +}; +const ref1 = function validate(data) { + if (!Array.isArray(data)) return false + if (data[0] !== undefined && hasOwn(data, 0)) { + if (!ref2(data[0])) return false + } + if (data[1] !== undefined && hasOwn(data, 1)) { + if (!ref2(data[1])) return false + } + if (data.length > 2) return false + return true +}; +const ref0 = function validate(data) { + if (!Array.isArray(data)) return false + if (data[0] !== undefined && hasOwn(data, 0)) { + if (!ref1(data[0])) return false + } + if (data[1] !== undefined && hasOwn(data, 1)) { + if (!ref1(data[1])) return false + } + if (data[2] !== undefined && hasOwn(data, 2)) { + if (!ref1(data[2])) return false + } + if (data.length > 3) return false + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] additionalProperties or unevaluatedProperties should be specified at #` + + +## nested items + +### Schema + +```json +{ + "type": "array", + "items": { + "type": "array", + "items": { + "type": "array", + "items": { "type": "array", "items": { "type": "number" } } + } + } +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (!Array.isArray(data)) return false + for (let i = 0; i < data.length; i++) { + if (data[i] !== undefined && hasOwn(data, i)) { + if (!(Array.isArray(data[i]))) return false + for (let j = 0; j < data[i].length; j++) { + if (data[i][j] !== undefined && hasOwn(data[i], j)) { + if (!(Array.isArray(data[i][j]))) return false + for (let k = 0; k < data[i][j].length; k++) { + if (data[i][j][k] !== undefined && hasOwn(data[i][j], k)) { + if (!(Array.isArray(data[i][j][k]))) return false + for (let l = 0; l < data[i][j][k].length; l++) { + if (data[i][j][k][l] !== undefined && hasOwn(data[i][j][k], l)) { + if (!(typeof data[i][j][k][l] === "number")) return false + } + } + } + } + } + } + } + } + return true +}; +return ref0 +``` + + +## items with null instance elements + +### Schema + +```json +{ "items": { "type": "null" } } +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (Array.isArray(data)) { + for (let i = 0; i < data.length; i++) { + if (data[i] !== undefined && hasOwn(data, i)) { + if (!(data[i] === null)) return false + } + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## array-form items with null instance elements + +### Schema + +```json +{ "items": [{ "type": "null" }] } +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (Array.isArray(data)) { + if (data[0] !== undefined && hasOwn(data, 0)) { + if (!(data[0] === null)) return false + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + diff --git a/doc/samples/draft4/maxItems.md b/doc/samples/draft4/maxItems.md new file mode 100644 index 0000000..2d5a0ab --- /dev/null +++ b/doc/samples/draft4/maxItems.md @@ -0,0 +1,27 @@ +# maxItems + +## maxItems validation + +### Schema + +```json +{ "maxItems": 2 } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (Array.isArray(data)) { + if (data.length > 2) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + diff --git a/doc/samples/draft4/maxLength.md b/doc/samples/draft4/maxLength.md new file mode 100644 index 0000000..b2e7e23 --- /dev/null +++ b/doc/samples/draft4/maxLength.md @@ -0,0 +1,29 @@ +# maxLength + +## maxLength validation + +### Schema + +```json +{ "maxLength": 2 } +``` + +### Code + +```js +'use strict' +const stringLength = (string) => + /[\uD800-\uDFFF]/.test(string) ? [...string].length : string.length; +const ref0 = function validate(data) { + if (typeof data === "string") { + if (data.length > 2 && stringLength(data) > 2) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + diff --git a/doc/samples/draft4/maxProperties.md b/doc/samples/draft4/maxProperties.md new file mode 100644 index 0000000..e901508 --- /dev/null +++ b/doc/samples/draft4/maxProperties.md @@ -0,0 +1,53 @@ +# maxProperties + +## maxProperties validation + +### Schema + +```json +{ "maxProperties": 2 } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (Object.keys(data).length > 2) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## maxProperties = 0 means the object is empty + +### Schema + +```json +{ "maxProperties": 0 } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (Object.keys(data).length > 0) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + diff --git a/doc/samples/draft4/maximum.md b/doc/samples/draft4/maximum.md new file mode 100644 index 0000000..961d3ef --- /dev/null +++ b/doc/samples/draft4/maximum.md @@ -0,0 +1,105 @@ +# maximum + +## maximum validation + +### Schema + +```json +{ "maximum": 3 } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (typeof data === "number") { + if (!(3 >= data)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## maximum validation with unsigned integer + +### Schema + +```json +{ "maximum": 300 } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (typeof data === "number") { + if (!(300 >= data)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## maximum validation (explicit false exclusivity) + +### Schema + +```json +{ "maximum": 3, "exclusiveMaximum": false } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (typeof data === "number") { + if (!(3 >= data)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## exclusiveMaximum validation + +### Schema + +```json +{ "maximum": 3, "exclusiveMaximum": true } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (typeof data === "number") { + if (!(3 > data)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + diff --git a/doc/samples/draft4/minItems.md b/doc/samples/draft4/minItems.md new file mode 100644 index 0000000..e60abd6 --- /dev/null +++ b/doc/samples/draft4/minItems.md @@ -0,0 +1,27 @@ +# minItems + +## minItems validation + +### Schema + +```json +{ "minItems": 1 } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (Array.isArray(data)) { + if (data.length < 1) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + diff --git a/doc/samples/draft4/minLength.md b/doc/samples/draft4/minLength.md new file mode 100644 index 0000000..4753aa7 --- /dev/null +++ b/doc/samples/draft4/minLength.md @@ -0,0 +1,29 @@ +# minLength + +## minLength validation + +### Schema + +```json +{ "minLength": 2 } +``` + +### Code + +```js +'use strict' +const stringLength = (string) => + /[\uD800-\uDFFF]/.test(string) ? [...string].length : string.length; +const ref0 = function validate(data) { + if (typeof data === "string") { + if (data.length < 2 || stringLength(data) < 2) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + diff --git a/doc/samples/draft4/minProperties.md b/doc/samples/draft4/minProperties.md new file mode 100644 index 0000000..ad22c21 --- /dev/null +++ b/doc/samples/draft4/minProperties.md @@ -0,0 +1,27 @@ +# minProperties + +## minProperties validation + +### Schema + +```json +{ "minProperties": 1 } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (Object.keys(data).length < 1) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + diff --git a/doc/samples/draft4/minimum.md b/doc/samples/draft4/minimum.md new file mode 100644 index 0000000..f021f69 --- /dev/null +++ b/doc/samples/draft4/minimum.md @@ -0,0 +1,105 @@ +# minimum + +## minimum validation + +### Schema + +```json +{ "minimum": 1.1 } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (typeof data === "number") { + if (!(1.1 <= data)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## minimum validation (explicit false exclusivity) + +### Schema + +```json +{ "minimum": 1.1, "exclusiveMinimum": false } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (typeof data === "number") { + if (!(1.1 <= data)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## exclusiveMinimum validation + +### Schema + +```json +{ "minimum": 1.1, "exclusiveMinimum": true } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (typeof data === "number") { + if (!(1.1 < data)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## minimum validation with signed integer + +### Schema + +```json +{ "minimum": -2 } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (typeof data === "number") { + if (!(-2 <= data)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + diff --git a/doc/samples/draft4/multipleOf.md b/doc/samples/draft4/multipleOf.md new file mode 100644 index 0000000..f56f9b8 --- /dev/null +++ b/doc/samples/draft4/multipleOf.md @@ -0,0 +1,116 @@ +# multipleOf + +## by int + +### Schema + +```json +{ "multipleOf": 2 } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (typeof data === "number") { + if (data % 2 !== 0) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## by number + +### Schema + +```json +{ "multipleOf": 1.5 } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (typeof data === "number") { + if (data % 1.5 !== 0) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## by small number + +### Schema + +```json +{ "multipleOf": 0.0001 } +``` + +### Code + +```js +'use strict' +const isMultipleOf = (value, divisor, factor, factorMultiple) => { + if (value % divisor === 0) return true + let multiple = value * factor + if (multiple === Infinity || multiple === -Infinity) multiple = value + if (multiple % factorMultiple === 0) return true + const normal = Math.floor(multiple + 0.5) + return normal / factor === value && normal % factorMultiple === 0 +}; +const ref0 = function validate(data) { + if (typeof data === "number") { + if (!isMultipleOf(data, 0.0001, 1e4, 1)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## float division = inf + +### Schema + +```json +{ "type": "integer", "multipleOf": 0.123456789 } +``` + +### Code + +```js +'use strict' +const isMultipleOf = (value, divisor, factor, factorMultiple) => { + if (value % divisor === 0) return true + let multiple = value * factor + if (multiple === Infinity || multiple === -Infinity) multiple = value + if (multiple % factorMultiple === 0) return true + const normal = Math.floor(multiple + 0.5) + return normal / factor === value && normal % factorMultiple === 0 +}; +const ref0 = function validate(data) { + if (!Number.isInteger(data)) return false + if (!isMultipleOf(data, 0.123456789, 1e9, 123456789)) return false + return true +}; +return ref0 +``` + diff --git a/doc/samples/draft4/not.md b/doc/samples/draft4/not.md new file mode 100644 index 0000000..8b4c57c --- /dev/null +++ b/doc/samples/draft4/not.md @@ -0,0 +1,116 @@ +# not + +## not + +### Schema + +```json +{ "not": { "type": "integer" } } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + const sub0 = (() => { + if (!Number.isInteger(data)) return false + return true + })() + if (sub0) return false + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## not multiple types + +### Schema + +```json +{ "not": { "type": ["integer", "boolean"] } } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + const sub0 = (() => { + if (!(Number.isInteger(data) || typeof data === "boolean")) return false + return true + })() + if (sub0) return false + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## not more complex schema + +### Schema + +```json +{ "not": { "type": "object", "properties": { "foo": { "type": "string" } } } } +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + const sub0 = (() => { + if (!(typeof data === "object" && data && !Array.isArray(data))) return false + if (data.foo !== undefined && hasOwn(data, "foo")) { + if (!(typeof data.foo === "string")) return false + } + return true + })() + if (sub0) return false + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] if properties is used, required should be specified at #/not` + + +## forbidden property + +### Schema + +```json +{ "properties": { "foo": { "not": {} } } } +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.foo !== undefined && hasOwn(data, "foo")) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #/properties/foo` + diff --git a/doc/samples/draft4/oneOf.md b/doc/samples/draft4/oneOf.md new file mode 100644 index 0000000..5d6c891 --- /dev/null +++ b/doc/samples/draft4/oneOf.md @@ -0,0 +1,261 @@ +# oneOf + +## oneOf + +### Schema + +```json +{ "oneOf": [{ "type": "integer" }, { "minimum": 2 }] } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + let passes0 = 0 + const sub0 = (() => { + if (!Number.isInteger(data)) return false + return true + })() + if (sub0) passes0++ + const sub1 = (() => { + if (typeof data === "number") { + if (!(2 <= data)) return false + } + return true + })() + if (sub1) passes0++ + if (passes0 !== 1) return false + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## oneOf with base schema + +### Schema + +```json +{ "type": "string", "oneOf": [{ "minLength": 2 }, { "maxLength": 4 }] } +``` + +### Code + +```js +'use strict' +const stringLength = (string) => + /[\uD800-\uDFFF]/.test(string) ? [...string].length : string.length; +const ref0 = function validate(data) { + if (!(typeof data === "string")) return false + let passes0 = 0 + const sub0 = (() => { + if (data.length < 2 || stringLength(data) < 2) return false + return true + })() + if (sub0) passes0++ + const sub1 = (() => { + if (data.length > 4 && stringLength(data) > 4) return false + return true + })() + if (sub1) passes0++ + if (passes0 !== 1) return false + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireStringValidation] pattern, format or contentSchema should be specified for strings, use pattern: ^[\s\S]*$ to opt-out at #` + + +## oneOf complex types + +### Schema + +```json +{ + "oneOf": [ + { "properties": { "bar": { "type": "integer" } }, "required": ["bar"] }, + { "properties": { "foo": { "type": "string" } }, "required": ["foo"] } + ] +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + let passes0 = 0 + const sub0 = (() => { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (!(data.bar !== undefined && hasOwn(data, "bar"))) return false + if (!Number.isInteger(data.bar)) return false + } + return true + })() + if (sub0) passes0++ + const sub1 = (() => { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (!(data.foo !== undefined && hasOwn(data, "foo"))) return false + if (!(typeof data.foo === "string")) return false + } + return true + })() + if (sub1) passes0++ + if (passes0 !== 1) return false + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireStringValidation] pattern, format or contentSchema should be specified for strings, use pattern: ^[\s\S]*$ to opt-out at #/oneOf/1/properties/foo` + + +## oneOf with empty schema + +### Schema + +```json +{ "oneOf": [{ "type": "number" }, {}] } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + let passes0 = 0 + const sub0 = (() => { + if (!(typeof data === "number")) return false + return true + })() + if (sub0) passes0++ + passes0++ + if (passes0 !== 1) return false + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## oneOf with required + +### Schema + +```json +{ + "type": "object", + "oneOf": [{ "required": ["foo", "bar"] }, { "required": ["foo", "baz"] }] +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (!(typeof data === "object" && data && !Array.isArray(data))) return false + let passes0 = 0 + const sub0 = (() => { + if (!(data.foo !== undefined && hasOwn(data, "foo"))) return false + if (!(data.bar !== undefined && hasOwn(data, "bar"))) return false + return true + })() + if (sub0) passes0++ + const sub1 = (() => { + if (!(data.foo !== undefined && hasOwn(data, "foo"))) return false + if (!(data.baz !== undefined && hasOwn(data, "baz"))) return false + return true + })() + if (sub1) passes0++ + if (passes0 !== 1) return false + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] additionalProperties or unevaluatedProperties should be specified at #` + + +## oneOf with missing optional property + +### Schema + +```json +{ + "oneOf": [ + { "properties": { "bar": {}, "baz": {} }, "required": ["bar"] }, + { "properties": { "foo": {} }, "required": ["foo"] } + ] +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + let passes0 = 0 + const sub0 = (() => { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (!(data.bar !== undefined && hasOwn(data, "bar"))) return false + } + return true + })() + if (sub0) passes0++ + const sub1 = (() => { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (!(data.foo !== undefined && hasOwn(data, "foo"))) return false + } + return true + })() + if (sub1) passes0++ + if (passes0 !== 1) return false + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] empty rules node is not allowed at #/oneOf/0/properties/bar` + + +## nested oneOf, to check validation semantics + +### Schema + +```json +{ "oneOf": [{ "oneOf": [{ "type": "null" }] }] } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (!(data === null)) return false + return true +}; +return ref0 +``` + diff --git a/doc/samples/draft4/optional-bignum.md b/doc/samples/draft4/optional-bignum.md new file mode 100644 index 0000000..44a1949 --- /dev/null +++ b/doc/samples/draft4/optional-bignum.md @@ -0,0 +1,169 @@ +# optional/bignum + +## integer + +### Schema + +```json +{ "type": "integer" } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (!Number.isInteger(data)) return false + return true +}; +return ref0 +``` + + +## number + +### Schema + +```json +{ "type": "number" } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (!(typeof data === "number")) return false + return true +}; +return ref0 +``` + + +## string + +### Schema + +```json +{ "type": "string" } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (!(typeof data === "string")) return false + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireStringValidation] pattern, format or contentSchema should be specified for strings, use pattern: ^[\s\S]*$ to opt-out at #` + + +## maximum integer comparison + +### Schema + +```json +{ "maximum": 18446744073709552000 } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (typeof data === "number") { + if (!(18446744073709552000 >= data)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## float comparison with high precision + +### Schema + +```json +{ "maximum": 9.727837981879871e26, "exclusiveMaximum": true } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (typeof data === "number") { + if (!(9.727837981879871e+26 > data)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## minimum integer comparison + +### Schema + +```json +{ "minimum": -18446744073709552000 } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (typeof data === "number") { + if (!(-18446744073709552000 <= data)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## float comparison with high precision on negative numbers + +### Schema + +```json +{ "minimum": -9.727837981879871e26, "exclusiveMinimum": true } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (typeof data === "number") { + if (!(-9.727837981879871e+26 < data)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + diff --git a/doc/samples/draft4/optional-ecmascript-regex.md b/doc/samples/draft4/optional-ecmascript-regex.md new file mode 100644 index 0000000..fca237c --- /dev/null +++ b/doc/samples/draft4/optional-ecmascript-regex.md @@ -0,0 +1,515 @@ +# optional/ecmascript-regex + +## ECMA 262 regex $ does not match trailing newline + +### Schema + +```json +{ "type": "string", "pattern": "^abc$" } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (!(typeof data === "string")) return false + if (!(data === "abc")) return false + return true +}; +return ref0 +``` + + +## ECMA 262 regex converts \t to horizontal tab + +### Schema + +```json +{ "type": "string", "pattern": "^\\t$" } +``` + +### Code + +```js +'use strict' +const pattern0 = new RegExp("^\\t$", "u"); +const ref0 = function validate(data) { + if (!(typeof data === "string")) return false + if (!pattern0.test(data)) return false + return true +}; +return ref0 +``` + + +## ECMA 262 regex escapes control codes with \c and upper letter + +### Schema + +```json +{ "type": "string", "pattern": "^\\cC$" } +``` + +### Code + +```js +'use strict' +const pattern0 = new RegExp("^\\cC$", "u"); +const ref0 = function validate(data) { + if (!(typeof data === "string")) return false + if (!pattern0.test(data)) return false + return true +}; +return ref0 +``` + + +## ECMA 262 regex escapes control codes with \c and lower letter + +### Schema + +```json +{ "type": "string", "pattern": "^\\cc$" } +``` + +### Code + +```js +'use strict' +const pattern0 = new RegExp("^\\cc$", "u"); +const ref0 = function validate(data) { + if (!(typeof data === "string")) return false + if (!pattern0.test(data)) return false + return true +}; +return ref0 +``` + + +## ECMA 262 \d matches ascii digits only + +### Schema + +```json +{ "type": "string", "pattern": "^\\d$" } +``` + +### Code + +```js +'use strict' +const pattern0 = new RegExp("^\\d$", "u"); +const ref0 = function validate(data) { + if (!(typeof data === "string")) return false + if (!pattern0.test(data)) return false + return true +}; +return ref0 +``` + + +## ECMA 262 \D matches everything but ascii digits + +### Schema + +```json +{ "type": "string", "pattern": "^\\D$" } +``` + +### Code + +```js +'use strict' +const pattern0 = new RegExp("^\\D$", "u"); +const ref0 = function validate(data) { + if (!(typeof data === "string")) return false + if (!pattern0.test(data)) return false + return true +}; +return ref0 +``` + + +## ECMA 262 \w matches ascii letters only + +### Schema + +```json +{ "type": "string", "pattern": "^\\w$" } +``` + +### Code + +```js +'use strict' +const pattern0 = new RegExp("^\\w$", "u"); +const ref0 = function validate(data) { + if (!(typeof data === "string")) return false + if (!pattern0.test(data)) return false + return true +}; +return ref0 +``` + + +## ECMA 262 \W matches everything but ascii letters + +### Schema + +```json +{ "type": "string", "pattern": "^\\W$" } +``` + +### Code + +```js +'use strict' +const pattern0 = new RegExp("^\\W$", "u"); +const ref0 = function validate(data) { + if (!(typeof data === "string")) return false + if (!pattern0.test(data)) return false + return true +}; +return ref0 +``` + + +## ECMA 262 \s matches whitespace + +### Schema + +```json +{ "type": "string", "pattern": "^\\s$" } +``` + +### Code + +```js +'use strict' +const pattern0 = new RegExp("^\\s$", "u"); +const ref0 = function validate(data) { + if (!(typeof data === "string")) return false + if (!pattern0.test(data)) return false + return true +}; +return ref0 +``` + + +## ECMA 262 \S matches everything but whitespace + +### Schema + +```json +{ "type": "string", "pattern": "^\\S$" } +``` + +### Code + +```js +'use strict' +const pattern0 = new RegExp("^\\S$", "u"); +const ref0 = function validate(data) { + if (!(typeof data === "string")) return false + if (!pattern0.test(data)) return false + return true +}; +return ref0 +``` + + +## patterns always use unicode semantics with pattern + +### Schema + +```json +{ "pattern": "\\p{Letter}cole" } +``` + +### Code + +```js +'use strict' +const pattern0 = new RegExp("\\p{Letter}cole", "u"); +const ref0 = function validate(data) { + if (typeof data === "string") { + if (!pattern0.test(data)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `Should start with ^ and end with $: "\\p{Letter}cole" at #` + + +## \w in patterns matches [A-Za-z0-9_], not unicode letters + +### Schema + +```json +{ "pattern": "\\wcole" } +``` + +### Code + +```js +'use strict' +const pattern0 = new RegExp("\\wcole", "u"); +const ref0 = function validate(data) { + if (typeof data === "string") { + if (!pattern0.test(data)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `Should start with ^ and end with $: "\\wcole" at #` + + +## pattern with ASCII ranges + +### Schema + +```json +{ "pattern": "[a-z]cole" } +``` + +### Code + +```js +'use strict' +const pattern0 = new RegExp("[a-z]cole", "u"); +const ref0 = function validate(data) { + if (typeof data === "string") { + if (!pattern0.test(data)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `Should start with ^ and end with $: "[a-z]cole" at #` + + +## \d in pattern matches [0-9], not unicode digits + +### Schema + +```json +{ "pattern": "^\\d+$" } +``` + +### Code + +```js +'use strict' +const pattern0 = new RegExp("^\\d+$", "u"); +const ref0 = function validate(data) { + if (typeof data === "string") { + if (!pattern0.test(data)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## pattern with non-ASCII digits + +### Schema + +```json +{ "pattern": "^\\p{digit}+$" } +``` + +### Code + +```js +'use strict' +const pattern0 = new RegExp("^\\p{digit}+$", "u"); +const ref0 = function validate(data) { + if (typeof data === "string") { + if (!pattern0.test(data)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[complexityChecks] maxLength should be specified for pattern: "^\\p{digit}+$" at #` + + +## patterns always use unicode semantics with patternProperties + +### Schema + +```json +{ + "type": "object", + "patternProperties": { "\\p{Letter}cole": {} }, + "additionalProperties": false +} +``` + +### Code + +```js +'use strict' +const pattern0 = new RegExp("\\p{Letter}cole", "u"); +const ref0 = function validate(data) { + if (!(typeof data === "object" && data && !Array.isArray(data))) return false + for (const key1 of Object.keys(data)) { + if (!pattern0.test(key1)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `Should start with ^ and end with $: "\\p{Letter}cole" at #` + + +## \w in patternProperties matches [A-Za-z0-9_], not unicode letters + +### Schema + +```json +{ + "type": "object", + "patternProperties": { "\\wcole": {} }, + "additionalProperties": false +} +``` + +### Code + +```js +'use strict' +const pattern0 = new RegExp("\\wcole", "u"); +const ref0 = function validate(data) { + if (!(typeof data === "object" && data && !Array.isArray(data))) return false + for (const key1 of Object.keys(data)) { + if (!pattern0.test(key1)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `Should start with ^ and end with $: "\\wcole" at #` + + +## patternProperties with ASCII ranges + +### Schema + +```json +{ + "type": "object", + "patternProperties": { "[a-z]cole": {} }, + "additionalProperties": false +} +``` + +### Code + +```js +'use strict' +const pattern0 = new RegExp("[a-z]cole", "u"); +const ref0 = function validate(data) { + if (!(typeof data === "object" && data && !Array.isArray(data))) return false + for (const key1 of Object.keys(data)) { + if (!pattern0.test(key1)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `Should start with ^ and end with $: "[a-z]cole" at #` + + +## \d in patternProperties matches [0-9], not unicode digits + +### Schema + +```json +{ + "type": "object", + "patternProperties": { "^\\d+$": {} }, + "additionalProperties": false +} +``` + +### Code + +```js +'use strict' +const pattern0 = new RegExp("^\\d+$", "u"); +const ref0 = function validate(data) { + if (!(typeof data === "object" && data && !Array.isArray(data))) return false + for (const key1 of Object.keys(data)) { + if (!pattern0.test(key1)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] empty rules node is not allowed at #/patternProperties/^\d+$` + + +## patternProperties with non-ASCII digits + +### Schema + +```json +{ + "type": "object", + "patternProperties": { "^\\p{digit}+$": {} }, + "additionalProperties": false +} +``` + +### Code + +```js +'use strict' +const pattern0 = new RegExp("^\\p{digit}+$", "u"); +const ref0 = function validate(data) { + if (!(typeof data === "object" && data && !Array.isArray(data))) return false + for (const key1 of Object.keys(data)) { + if (!pattern0.test(key1)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[complexityChecks] maxLength should be specified for pattern: "^\\p{digit}+$" at #` + diff --git a/doc/samples/draft4/optional-float-overflow.md b/doc/samples/draft4/optional-float-overflow.md new file mode 100644 index 0000000..4bd80d7 --- /dev/null +++ b/doc/samples/draft4/optional-float-overflow.md @@ -0,0 +1,22 @@ +# optional/float-overflow + +## all integers are multiples of 0.5, if overflow is handled + +### Schema + +```json +{ "type": "number", "multipleOf": 0.5 } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (!(typeof data === "number")) return false + if (data % 0.5 !== 0) return false + return true +}; +return ref0 +``` + diff --git a/doc/samples/draft4/optional-non-bmp-regex.md b/doc/samples/draft4/optional-non-bmp-regex.md new file mode 100644 index 0000000..8d300cd --- /dev/null +++ b/doc/samples/draft4/optional-non-bmp-regex.md @@ -0,0 +1,59 @@ +# optional/non-bmp-regex + +## Proper UTF-16 surrogate pair handling: pattern + +### Schema + +```json +{ "pattern": "^🐲*$" } +``` + +### Code + +```js +'use strict' +const pattern0 = new RegExp("^🐲*$", "u"); +const ref0 = function validate(data) { + if (typeof data === "string") { + if (!pattern0.test(data)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## Proper UTF-16 surrogate pair handling: patternProperties + +### Schema + +```json +{ "patternProperties": { "^🐲*$": { "type": "integer" } } } +``` + +### Code + +```js +'use strict' +const pattern0 = new RegExp("^🐲*$", "u"); +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + for (const key0 of Object.keys(data)) { + if (pattern0.test(key0)) { + if (!(Number.isInteger(data[key0]))) return false + } + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + diff --git a/doc/samples/draft4/optional-zeroTerminatedFloats.md b/doc/samples/draft4/optional-zeroTerminatedFloats.md new file mode 100644 index 0000000..ce3a30c --- /dev/null +++ b/doc/samples/draft4/optional-zeroTerminatedFloats.md @@ -0,0 +1,25 @@ +# optional/zeroTerminatedFloats + +## some languages do not distinguish between different types of numeric value + +### Schema + +```json +{ "type": "integer" } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (!Number.isInteger(data)) return false + return true +}; +return ref0 +``` + +### Misclassified! + +**This schema caused 1 misclassifications!** + diff --git a/doc/samples/draft4/pattern.md b/doc/samples/draft4/pattern.md new file mode 100644 index 0000000..07714d8 --- /dev/null +++ b/doc/samples/draft4/pattern.md @@ -0,0 +1,54 @@ +# pattern + +## pattern validation + +### Schema + +```json +{ "pattern": "^a*$" } +``` + +### Code + +```js +'use strict' +const pattern0 = new RegExp("^a*$", "u"); +const ref0 = function validate(data) { + if (typeof data === "string") { + if (!pattern0.test(data)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## pattern is not anchored + +### Schema + +```json +{ "pattern": "a+" } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (typeof data === "string") { + if (!(data.includes("a"))) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `Should start with ^ and end with $: "a+" at #` + diff --git a/doc/samples/draft4/patternProperties.md b/doc/samples/draft4/patternProperties.md new file mode 100644 index 0000000..7c34132 --- /dev/null +++ b/doc/samples/draft4/patternProperties.md @@ -0,0 +1,140 @@ +# patternProperties + +## patternProperties validates properties matching a regex + +### Schema + +```json +{ "patternProperties": { "f.*o": { "type": "integer" } } } +``` + +### Code + +```js +'use strict' +const pattern0 = new RegExp("f.*o", "u"); +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + for (const key0 of Object.keys(data)) { + if (pattern0.test(key0)) { + if (!(Number.isInteger(data[key0]))) return false + } + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `Should start with ^ and end with $: "f.*o" at #` + + +## multiple simultaneous patternProperties are validated + +### Schema + +```json +{ + "patternProperties": { + "a*": { "type": "integer" }, + "aaa*": { "maximum": 20 } + } +} +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + for (const key0 of Object.keys(data)) { + if (!(Number.isInteger(data[key0]))) return false + if (key0.includes("aa")) { + if (typeof data[key0] === "number") { + if (!(20 >= data[key0])) return false + } + } + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `Should start with ^ and end with $: "a*" at #` + + +## regexes are not anchored by default and are case sensitive + +### Schema + +```json +{ + "patternProperties": { + "[0-9]{2,}": { "type": "boolean" }, + "X_": { "type": "string" } + } +} +``` + +### Code + +```js +'use strict' +const pattern0 = new RegExp("[0-9]{2,}", "u"); +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + for (const key0 of Object.keys(data)) { + if (pattern0.test(key0)) { + if (!(typeof data[key0] === "boolean")) return false + } + if (key0.includes("X_")) { + if (!(typeof data[key0] === "string")) return false + } + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `Should start with ^ and end with $: "[0-9]{2,}" at #` + + +## patternProperties with null valued instance properties + +### Schema + +```json +{ "patternProperties": { "^.*bar$": { "type": "null" } } } +``` + +### Code + +```js +'use strict' +const pattern0 = new RegExp("^.*bar$", "u"); +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + for (const key0 of Object.keys(data)) { + if (pattern0.test(key0)) { + if (!(data[key0] === null)) return false + } + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + diff --git a/doc/samples/draft4/properties.md b/doc/samples/draft4/properties.md new file mode 100644 index 0000000..9ca071e --- /dev/null +++ b/doc/samples/draft4/properties.md @@ -0,0 +1,213 @@ +# properties + +## object properties validation + +### Schema + +```json +{ "properties": { "foo": { "type": "integer" }, "bar": { "type": "string" } } } +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.foo !== undefined && hasOwn(data, "foo")) { + if (!Number.isInteger(data.foo)) return false + } + if (data.bar !== undefined && hasOwn(data, "bar")) { + if (!(typeof data.bar === "string")) return false + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireStringValidation] pattern, format or contentSchema should be specified for strings, use pattern: ^[\s\S]*$ to opt-out at #/properties/bar` + + +## properties, patternProperties, additionalProperties interaction + +### Schema + +```json +{ + "properties": { + "foo": { "type": "array", "maxItems": 3 }, + "bar": { "type": "array" } + }, + "patternProperties": { "f.o": { "minItems": 2 } }, + "additionalProperties": { "type": "integer" } +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const pattern0 = new RegExp("f.o", "u"); +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.foo !== undefined && hasOwn(data, "foo")) { + if (!Array.isArray(data.foo)) return false + if (data.foo.length > 3) return false + } + if (data.bar !== undefined && hasOwn(data, "bar")) { + if (!Array.isArray(data.bar)) return false + } + for (const key0 of Object.keys(data)) { + if (pattern0.test(key0)) { + if (Array.isArray(data[key0])) { + if (data[key0].length < 2) return false + } + } + } + for (const key1 of Object.keys(data)) { + if (key1 !== "foo" && key1 !== "bar" && !pattern0.test(key1)) { + if (!(Number.isInteger(data[key1]))) return false + } + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] items rule should be specified at #/properties/foo` + + +## properties with escaped characters + +### Schema + +```json +{ + "properties": { + "foo\nbar": { "type": "number" }, + "foo\"bar": { "type": "number" }, + "foo\\bar": { "type": "number" }, + "foo\rbar": { "type": "number" }, + "foo\tbar": { "type": "number" }, + "foo\fbar": { "type": "number" } + } +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data["foo\nbar"] !== undefined && hasOwn(data, "foo\nbar")) { + if (!(typeof data["foo\nbar"] === "number")) return false + } + if (data["foo\"bar"] !== undefined && hasOwn(data, "foo\"bar")) { + if (!(typeof data["foo\"bar"] === "number")) return false + } + if (data["foo\\bar"] !== undefined && hasOwn(data, "foo\\bar")) { + if (!(typeof data["foo\\bar"] === "number")) return false + } + if (data["foo\rbar"] !== undefined && hasOwn(data, "foo\rbar")) { + if (!(typeof data["foo\rbar"] === "number")) return false + } + if (data["foo\tbar"] !== undefined && hasOwn(data, "foo\tbar")) { + if (!(typeof data["foo\tbar"] === "number")) return false + } + if (data["foo\fbar"] !== undefined && hasOwn(data, "foo\fbar")) { + if (!(typeof data["foo\fbar"] === "number")) return false + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## properties with null valued instance properties + +### Schema + +```json +{ "properties": { "foo": { "type": "null" } } } +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.foo !== undefined && hasOwn(data, "foo")) { + if (!(data.foo === null)) return false + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## properties whose names are Javascript object property names + +### Schema + +```json +{ + "properties": { + "__proto__": { "type": "number" }, + "toString": { "properties": { "length": { "type": "string" } } }, + "constructor": { "type": "number" } + } +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data["__proto__"] !== undefined && hasOwn(data, "__proto__")) { + if (!(typeof data["__proto__"] === "number")) return false + } + if (data.toString !== undefined && hasOwn(data, "toString")) { + if (typeof data.toString === "object" && data.toString && !Array.isArray(data.toString)) { + if (data.toString.length !== undefined && hasOwn(data.toString, "length")) { + if (!(typeof data.toString.length === "string")) return false + } + } + } + if (data.constructor !== undefined && hasOwn(data, "constructor")) { + if (!(typeof data.constructor === "number")) return false + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireStringValidation] pattern, format or contentSchema should be specified for strings, use pattern: ^[\s\S]*$ to opt-out at #/properties/toString/properties/length` + diff --git a/doc/samples/draft4/ref.md b/doc/samples/draft4/ref.md new file mode 100644 index 0000000..19d328e --- /dev/null +++ b/doc/samples/draft4/ref.md @@ -0,0 +1,860 @@ +# ref + +## root pointer ref + +### Schema + +```json +{ "properties": { "foo": { "$ref": "#" } }, "additionalProperties": false } +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.foo !== undefined && hasOwn(data, "foo")) { + if (!validate(data.foo)) return false + } + for (const key0 of Object.keys(data)) { + if (key0 !== "foo") return false + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #/properties/foo` + + +## relative pointer ref to object + +### Schema + +```json +{ + "properties": { + "foo": { "type": "integer" }, + "bar": { "$ref": "#/properties/foo" } + } +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref1 = function validate(data) { + if (!Number.isInteger(data)) return false + return true +}; +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.foo !== undefined && hasOwn(data, "foo")) { + if (!Number.isInteger(data.foo)) return false + } + if (data.bar !== undefined && hasOwn(data, "bar")) { + if (!ref1(data.bar)) return false + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## relative pointer ref to array + +### Schema + +```json +{ "items": [{ "type": "integer" }, { "$ref": "#/items/0" }] } +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref1 = function validate(data) { + if (!Number.isInteger(data)) return false + return true +}; +const ref0 = function validate(data) { + if (Array.isArray(data)) { + if (data[0] !== undefined && hasOwn(data, 0)) { + if (!(Number.isInteger(data[0]))) return false + } + if (data[1] !== undefined && hasOwn(data, 1)) { + if (!ref1(data[1])) return false + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## escaped pointer ref + +### Schema + +```json +{ + "definitions": { + "tilde~field": { "type": "integer" }, + "slash/field": { "type": "integer" }, + "percent%field": { "type": "integer" } + }, + "properties": { + "tilde": { "$ref": "#/definitions/tilde~0field" }, + "slash": { "$ref": "#/definitions/slash~1field" }, + "percent": { "$ref": "#/definitions/percent%25field" } + } +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref1 = function validate(data) { + if (!Number.isInteger(data)) return false + return true +}; +const ref2 = function validate(data) { + if (!Number.isInteger(data)) return false + return true +}; +const ref3 = function validate(data) { + if (!Number.isInteger(data)) return false + return true +}; +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.tilde !== undefined && hasOwn(data, "tilde")) { + if (!ref1(data.tilde)) return false + } + if (data.slash !== undefined && hasOwn(data, "slash")) { + if (!ref2(data.slash)) return false + } + if (data.percent !== undefined && hasOwn(data, "percent")) { + if (!ref3(data.percent)) return false + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## nested refs + +### Schema + +```json +{ + "definitions": { + "a": { "type": "integer" }, + "b": { "$ref": "#/definitions/a" }, + "c": { "$ref": "#/definitions/b" } + }, + "allOf": [{ "$ref": "#/definitions/c" }] +} +``` + +### Code + +```js +'use strict' +const ref3 = function validate(data) { + if (!Number.isInteger(data)) return false + return true +}; +const ref2 = function validate(data) { + if (!ref3(data)) return false + return true +}; +const ref1 = function validate(data) { + if (!ref2(data)) return false + return true +}; +const ref0 = function validate(data) { + if (!ref1(data)) return false + return true +}; +return ref0 +``` + + +## ref overrides any sibling keywords + +### Schema + +```json +{ + "definitions": { "reffed": { "type": "array" } }, + "properties": { "foo": { "$ref": "#/definitions/reffed", "maxItems": 2 } } +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref1 = function validate(data) { + if (!Array.isArray(data)) return false + return true +}; +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.foo !== undefined && hasOwn(data, "foo")) { + if (!ref1(data.foo)) return false + } + } + return true +}; +return ref0 +``` + +### Warnings + + * `Unprocessed keywords: ["maxItems"] at #/properties/foo` + + +## $ref prevents a sibling id from changing the base uri + +### Schema + +```json +{ + "id": "http://localhost:1234/sibling_id/base/", + "definitions": { + "foo": { + "id": "http://localhost:1234/sibling_id/foo.json", + "type": "string" + }, + "base_foo": { + "$comment": "this canonical uri is http://localhost:1234/sibling_id/base/foo.json", + "id": "foo.json", + "type": "number" + } + }, + "allOf": [ + { + "$comment": "$ref resolves to http://localhost:1234/sibling_id/base/foo.json, not http://localhost:1234/sibling_id/foo.json", + "id": "http://localhost:1234/sibling_id/", + "$ref": "foo.json" + } + ] +} +``` + +### Code + +```js +'use strict' +const ref1 = function validate(data) { + if (!(typeof data === "number")) return false + return true +}; +const ref0 = function validate(data) { + if (!ref1(data)) return false + return true +}; +return ref0 +``` + +### Warnings + + * `Unprocessed keywords: ["id"] at #/allOf/0` + + +## remote ref, containing refs itself + +### Schema + +```json +{ "$ref": "http://json-schema.org/draft-04/schema#" } +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref2 = function validate(data) { + if (!Number.isInteger(data)) return false + if (!(0 <= data)) return false + return true +}; +const ref3 = function validate(data) { + if (!ref2(data)) return false + return true +}; +const format0 = (str) => { + if (str.length > 1e5) return false + const Z_ANCHOR = /[^\\]\\Z/ + if (Z_ANCHOR.test(str)) return false + try { + new RegExp(str, 'u') + return true + } catch (e) { + return false + } + }; +const ref4 = function validate(data) { + if (!Array.isArray(data)) return false + if (data.length < 1) return false + for (let i = 0; i < data.length; i++) { + if (data[i] !== undefined && hasOwn(data, i)) { + if (!ref1(data[i])) return false + } + } + return true +}; +const unique = (array) => { + if (array.length < 2) return true + if (array.length === 2) return !deepEqual(array[0], array[1]) + const objects = [] + const primitives = array.length > 20 ? new Set() : null + let primitivesCount = 0 + let pos = 0 + for (const item of array) { + if (typeof item === 'object') { + objects.push(item) + } else if (primitives) { + primitives.add(item) + if (primitives.size !== ++primitivesCount) return false + } else { + if (array.indexOf(item, pos + 1) !== -1) return false + } + pos++ + } + for (let i = 1; i < objects.length; i++) + for (let j = 0; j < i; j++) if (deepEqual(objects[i], objects[j])) return false + return true +}; +const deepEqual = (obj, obj2) => { + if (obj === obj2) return true + if (!obj || !obj2 || typeof obj !== typeof obj2) return false + if (obj !== obj2 && typeof obj !== 'object') return false + + const proto = Object.getPrototypeOf(obj) + if (proto !== Object.getPrototypeOf(obj2)) return false + + if (proto === Array.prototype) { + if (!Array.isArray(obj) || !Array.isArray(obj2)) return false + if (obj.length !== obj2.length) return false + return obj.every((x, i) => deepEqual(x, obj2[i])) + } else if (proto === Object.prototype) { + const [keys, keys2] = [Object.keys(obj), Object.keys(obj2)] + if (keys.length !== keys2.length) return false + const keyset2 = new Set([...keys, ...keys2]) + return keyset2.size === keys.length && keys.every((key) => deepEqual(obj[key], obj2[key])) + } + return false +}; +const ref5 = function validate(data) { + if (!Array.isArray(data)) return false + if (data.length < 1) return false + for (let j = 0; j < data.length; j++) { + if (data[j] !== undefined && hasOwn(data, j)) { + if (!(typeof data[j] === "string")) return false + } + } + if (!unique(data)) return false + return true +}; +const ref6 = function validate(data) { + if (!(data === "array" || data === "boolean" || data === "integer" || data === "null" || data === "number" || data === "object" || data === "string")) return false + return true +}; +const ref1 = function validate(data) { + if (!(typeof data === "object" && data && !Array.isArray(data))) return false + if (data.exclusiveMaximum !== undefined && hasOwn(data, "exclusiveMaximum") && !(data.maximum !== undefined && hasOwn(data, "maximum"))) return false + if (data.exclusiveMinimum !== undefined && hasOwn(data, "exclusiveMinimum") && !(data.minimum !== undefined && hasOwn(data, "minimum"))) return false + if (data.id !== undefined && hasOwn(data, "id")) { + if (!(typeof data.id === "string")) return false + } + if (data["$schema"] !== undefined && hasOwn(data, "$schema")) { + if (!(typeof data["$schema"] === "string")) return false + } + if (data.title !== undefined && hasOwn(data, "title")) { + if (!(typeof data.title === "string")) return false + } + if (data.description !== undefined && hasOwn(data, "description")) { + if (!(typeof data.description === "string")) return false + } + if (data.multipleOf !== undefined && hasOwn(data, "multipleOf")) { + if (!(typeof data.multipleOf === "number")) return false + if (!(0 < data.multipleOf)) return false + } + if (data.maximum !== undefined && hasOwn(data, "maximum")) { + if (!(typeof data.maximum === "number")) return false + } + if (data.exclusiveMaximum !== undefined && hasOwn(data, "exclusiveMaximum")) { + if (!(typeof data.exclusiveMaximum === "boolean")) return false + } + if (data.minimum !== undefined && hasOwn(data, "minimum")) { + if (!(typeof data.minimum === "number")) return false + } + if (data.exclusiveMinimum !== undefined && hasOwn(data, "exclusiveMinimum")) { + if (!(typeof data.exclusiveMinimum === "boolean")) return false + } + if (data.maxLength !== undefined && hasOwn(data, "maxLength")) { + if (!ref2(data.maxLength)) return false + } + if (data.minLength !== undefined && hasOwn(data, "minLength")) { + if (!ref3(data.minLength)) return false + } + if (data.pattern !== undefined && hasOwn(data, "pattern")) { + if (!(typeof data.pattern === "string")) return false + if (!format0(data.pattern)) return false + } + if (data.additionalItems !== undefined && hasOwn(data, "additionalItems")) { + const sub0 = (() => { + if (!(typeof data.additionalItems === "boolean")) return false + return true + })() + if (!sub0) { + const sub1 = (() => { + if (!validate(data.additionalItems)) return false + return true + })() + if (!sub1) return false + } + } + if (data.items !== undefined && hasOwn(data, "items")) { + const sub2 = (() => { + if (!validate(data.items)) return false + return true + })() + if (!sub2) { + const sub3 = (() => { + if (!ref4(data.items)) return false + return true + })() + if (!sub3) return false + } + } + if (data.maxItems !== undefined && hasOwn(data, "maxItems")) { + if (!ref2(data.maxItems)) return false + } + if (data.minItems !== undefined && hasOwn(data, "minItems")) { + if (!ref3(data.minItems)) return false + } + if (data.uniqueItems !== undefined && hasOwn(data, "uniqueItems")) { + if (!(typeof data.uniqueItems === "boolean")) return false + } + if (data.maxProperties !== undefined && hasOwn(data, "maxProperties")) { + if (!ref2(data.maxProperties)) return false + } + if (data.minProperties !== undefined && hasOwn(data, "minProperties")) { + if (!ref3(data.minProperties)) return false + } + if (data.required !== undefined && hasOwn(data, "required")) { + if (!ref5(data.required)) return false + } + if (data.additionalProperties !== undefined && hasOwn(data, "additionalProperties")) { + const sub4 = (() => { + if (!(typeof data.additionalProperties === "boolean")) return false + return true + })() + if (!sub4) { + const sub5 = (() => { + if (!validate(data.additionalProperties)) return false + return true + })() + if (!sub5) return false + } + } + if (data.definitions !== undefined && hasOwn(data, "definitions")) { + if (!(typeof data.definitions === "object" && data.definitions && !Array.isArray(data.definitions))) return false + for (const key0 of Object.keys(data.definitions)) { + if (!validate(data.definitions[key0])) return false + } + } + if (data.properties !== undefined && hasOwn(data, "properties")) { + if (!(typeof data.properties === "object" && data.properties && !Array.isArray(data.properties))) return false + for (const key1 of Object.keys(data.properties)) { + if (!validate(data.properties[key1])) return false + } + } + if (data.patternProperties !== undefined && hasOwn(data, "patternProperties")) { + if (!(typeof data.patternProperties === "object" && data.patternProperties && !Array.isArray(data.patternProperties))) return false + for (const key2 of Object.keys(data.patternProperties)) { + if (!validate(data.patternProperties[key2])) return false + } + } + if (data.dependencies !== undefined && hasOwn(data, "dependencies")) { + if (!(typeof data.dependencies === "object" && data.dependencies && !Array.isArray(data.dependencies))) return false + for (const key3 of Object.keys(data.dependencies)) { + const sub6 = (() => { + if (!validate(data.dependencies[key3])) return false + return true + })() + if (!sub6) { + const sub7 = (() => { + if (!ref5(data.dependencies[key3])) return false + return true + })() + if (!sub7) return false + } + } + } + if (data.enum !== undefined && hasOwn(data, "enum")) { + if (!Array.isArray(data.enum)) return false + if (data.enum.length < 1) return false + if (!unique(data.enum)) return false + } + if (data.type !== undefined && hasOwn(data, "type")) { + const sub8 = (() => { + if (!ref6(data.type)) return false + return true + })() + if (!sub8) { + const sub9 = (() => { + if (!Array.isArray(data.type)) return false + if (data.type.length < 1) return false + for (let k = 0; k < data.type.length; k++) { + if (data.type[k] !== undefined && hasOwn(data.type, k)) { + if (!ref6(data.type[k])) return false + } + } + if (!unique(data.type)) return false + return true + })() + if (!sub9) return false + } + } + if (data.format !== undefined && hasOwn(data, "format")) { + if (!(typeof data.format === "string")) return false + } + if (data.allOf !== undefined && hasOwn(data, "allOf")) { + if (!ref4(data.allOf)) return false + } + if (data.anyOf !== undefined && hasOwn(data, "anyOf")) { + if (!ref4(data.anyOf)) return false + } + if (data.oneOf !== undefined && hasOwn(data, "oneOf")) { + if (!ref4(data.oneOf)) return false + } + if (data.not !== undefined && hasOwn(data, "not")) { + if (!validate(data.not)) return false + } + return true +}; +const ref0 = function validate(data) { + if (!ref1(data)) return false + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireStringValidation] pattern, format or contentSchema should be specified for strings, use pattern: ^[\s\S]*$ to opt-out at http://json-schema.org/draft-04/schema#/properties/id` + + +## property named $ref that is not a reference + +### Schema + +```json +{ "properties": { "$ref": { "type": "string" } } } +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data["$ref"] !== undefined && hasOwn(data, "$ref")) { + if (!(typeof data["$ref"] === "string")) return false + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireStringValidation] pattern, format or contentSchema should be specified for strings, use pattern: ^[\s\S]*$ to opt-out at #/properties/$ref` + + +## property named $ref, containing an actual $ref + +### Schema + +```json +{ + "properties": { "$ref": { "$ref": "#/definitions/is-string" } }, + "definitions": { "is-string": { "type": "string" } } +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref1 = function validate(data) { + if (!(typeof data === "string")) return false + return true +}; +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data["$ref"] !== undefined && hasOwn(data, "$ref")) { + if (!ref1(data["$ref"])) return false + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireStringValidation] pattern, format or contentSchema should be specified for strings, use pattern: ^[\s\S]*$ to opt-out at #` + + +## Recursive references between schemas + +### Schema + +```json +{ + "id": "http://localhost:1234/tree", + "description": "tree of nodes", + "type": "object", + "properties": { + "meta": { "type": "string" }, + "nodes": { "type": "array", "items": { "$ref": "node" } } + }, + "required": ["meta", "nodes"], + "definitions": { + "node": { + "id": "http://localhost:1234/node", + "description": "node", + "type": "object", + "properties": { + "value": { "type": "number" }, + "subtree": { "$ref": "tree" } + }, + "required": ["value"] + } + } +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref1 = function validate(data) { + if (!(typeof data === "object" && data && !Array.isArray(data))) return false + if (!(data.value !== undefined && hasOwn(data, "value"))) return false + if (!(typeof data.value === "number")) return false + if (data.subtree !== undefined && hasOwn(data, "subtree")) { + if (!ref0(data.subtree)) return false + } + return true +}; +const ref0 = function validate(data) { + if (!(typeof data === "object" && data && !Array.isArray(data))) return false + if (!(data.meta !== undefined && hasOwn(data, "meta"))) return false + if (!(data.nodes !== undefined && hasOwn(data, "nodes"))) return false + if (!(typeof data.meta === "string")) return false + if (!Array.isArray(data.nodes)) return false + for (let i = 0; i < data.nodes.length; i++) { + if (data.nodes[i] !== undefined && hasOwn(data.nodes, i)) { + if (!ref1(data.nodes[i])) return false + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireStringValidation] pattern, format or contentSchema should be specified for strings, use pattern: ^[\s\S]*$ to opt-out at #/properties/meta` + + +## refs with quote + +### Schema + +```json +{ + "properties": { "foo\"bar": { "$ref": "#/definitions/foo%22bar" } }, + "definitions": { "foo\"bar": { "type": "number" } } +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref1 = function validate(data) { + if (!(typeof data === "number")) return false + return true +}; +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data["foo\"bar"] !== undefined && hasOwn(data, "foo\"bar")) { + if (!ref1(data["foo\"bar"])) return false + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## Location-independent identifier + +### Schema + +```json +{ + "allOf": [{ "$ref": "#foo" }], + "definitions": { "A": { "id": "#foo", "type": "integer" } } +} +``` + +### Code + +```js +'use strict' +const ref1 = function validate(data) { + if (!Number.isInteger(data)) return false + return true +}; +const ref0 = function validate(data) { + if (!ref1(data)) return false + return true +}; +return ref0 +``` + + +## Location-independent identifier with base URI change in subschema + +### Schema + +```json +{ + "id": "http://localhost:1234/root", + "allOf": [{ "$ref": "http://localhost:1234/nested.json#foo" }], + "definitions": { + "A": { + "id": "nested.json", + "definitions": { "B": { "id": "#foo", "type": "integer" } } + } + } +} +``` + +### Code + +```js +'use strict' +const ref1 = function validate(data) { + if (!Number.isInteger(data)) return false + return true +}; +const ref0 = function validate(data) { + if (!ref1(data)) return false + return true +}; +return ref0 +``` + + +## naive replacement of $ref with its destination is not correct + +### Schema + +```json +{ + "definitions": { "a_string": { "type": "string" } }, + "enum": [{ "$ref": "#/definitions/a_string" }] +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (!(typeof data === "object" && data && !Array.isArray(data) && Object.keys(data).length === 1 && hasOwn(data, "$ref") && data["$ref"] === "#/definitions/a_string")) return false + return true +}; +return ref0 +``` + + +## id must be resolved against nearest parent, not just immediate parent + +### Schema + +```json +{ + "id": "http://example.com/a.json", + "definitions": { + "x": { + "id": "http://example.com/b/c.json", + "not": { "definitions": { "y": { "id": "d.json", "type": "number" } } } + } + }, + "allOf": [{ "$ref": "http://example.com/b/d.json" }] +} +``` + +### Code + +```js +'use strict' +const ref1 = function validate(data) { + if (!(typeof data === "number")) return false + return true +}; +const ref0 = function validate(data) { + if (!ref1(data)) return false + return true +}; +return ref0 +``` + diff --git a/doc/samples/draft4/refRemote.md b/doc/samples/draft4/refRemote.md new file mode 100644 index 0000000..cd21cd5 --- /dev/null +++ b/doc/samples/draft4/refRemote.md @@ -0,0 +1,318 @@ +# refRemote + +## remote ref + +### Schema + +```json +{ "$ref": "http://localhost:1234/integer.json" } +``` + +### Code + +```js +'use strict' +const ref1 = function validate(data) { + if (!Number.isInteger(data)) return false + return true +}; +const ref0 = function validate(data) { + if (!ref1(data)) return false + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireSchema] $schema is required at http://localhost:1234/integer.json#` + + +## fragment within remote ref + +### Schema + +```json +{ "$ref": "http://localhost:1234/subSchemas.json#/integer" } +``` + +### Code + +```js +'use strict' +const ref1 = function validate(data) { + if (!Number.isInteger(data)) return false + return true +}; +const ref0 = function validate(data) { + if (!ref1(data)) return false + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireSchema] $schema is required at http://localhost:1234/subSchemas.json#` + + +## ref within remote ref + +### Schema + +```json +{ "$ref": "http://localhost:1234/subSchemas.json#/refToInteger" } +``` + +### Code + +```js +'use strict' +const ref2 = function validate(data) { + if (!Number.isInteger(data)) return false + return true +}; +const ref1 = function validate(data) { + if (!ref2(data)) return false + return true +}; +const ref0 = function validate(data) { + if (!ref1(data)) return false + return true +}; +return ref0 +``` + + +## base URI change + +### Schema + +```json +{ + "id": "http://localhost:1234/", + "items": { "id": "baseUriChange/", "items": { "$ref": "folderInteger.json" } } +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref1 = function validate(data) { + if (!Number.isInteger(data)) return false + return true +}; +const ref0 = function validate(data) { + if (Array.isArray(data)) { + for (let i = 0; i < data.length; i++) { + if (data[i] !== undefined && hasOwn(data, i)) { + if (Array.isArray(data[i])) { + for (let j = 0; j < data[i].length; j++) { + if (data[i][j] !== undefined && hasOwn(data[i], j)) { + if (!ref1(data[i][j])) return false + } + } + } + } + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireSchema] $schema is required at http://localhost:1234/baseUriChange/folderInteger.json#` + + +## base URI change - change folder + +### Schema + +```json +{ + "id": "http://localhost:1234/scope_change_defs1.json", + "type": "object", + "properties": { "list": { "$ref": "#/definitions/baz" } }, + "definitions": { + "baz": { + "id": "baseUriChangeFolder/", + "type": "array", + "items": { "$ref": "folderInteger.json" } + } + } +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref2 = function validate(data) { + if (!Number.isInteger(data)) return false + return true +}; +const ref1 = function validate(data) { + if (!Array.isArray(data)) return false + for (let i = 0; i < data.length; i++) { + if (data[i] !== undefined && hasOwn(data, i)) { + if (!ref2(data[i])) return false + } + } + return true +}; +const ref0 = function validate(data) { + if (!(typeof data === "object" && data && !Array.isArray(data))) return false + if (data.list !== undefined && hasOwn(data, "list")) { + if (!ref1(data.list)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireSchema] $schema is required at http://localhost:1234/baseUriChangeFolder/folderInteger.json#` + + +## base URI change - change folder in subschema + +### Schema + +```json +{ + "id": "http://localhost:1234/scope_change_defs2.json", + "type": "object", + "properties": { "list": { "$ref": "#/definitions/baz/definitions/bar" } }, + "definitions": { + "baz": { + "id": "baseUriChangeFolderInSubschema/", + "definitions": { + "bar": { "type": "array", "items": { "$ref": "folderInteger.json" } } + } + } + } +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref2 = function validate(data) { + if (!Number.isInteger(data)) return false + return true +}; +const ref1 = function validate(data) { + if (!Array.isArray(data)) return false + for (let i = 0; i < data.length; i++) { + if (data[i] !== undefined && hasOwn(data, i)) { + if (!ref2(data[i])) return false + } + } + return true +}; +const ref0 = function validate(data) { + if (!(typeof data === "object" && data && !Array.isArray(data))) return false + if (data.list !== undefined && hasOwn(data, "list")) { + if (!ref1(data.list)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireSchema] $schema is required at http://localhost:1234/baseUriChangeFolderInSubschema/folderInteger.json#` + + +## root ref in remote ref + +### Schema + +```json +{ + "id": "http://localhost:1234/object", + "type": "object", + "properties": { "name": { "$ref": "name.json#/definitions/orNull" } } +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref2 = function validate(data) { + if (!(typeof data === "string")) return false + return true +}; +const ref1 = function validate(data) { + const sub0 = (() => { + if (!(data === null)) return false + return true + })() + if (!sub0) { + const sub1 = (() => { + if (!ref2(data)) return false + return true + })() + if (!sub1) return false + } + return true +}; +const ref0 = function validate(data) { + if (!(typeof data === "object" && data && !Array.isArray(data))) return false + if (data.name !== undefined && hasOwn(data, "name")) { + if (!ref1(data.name)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireSchema] $schema is required at http://localhost:1234/name.json#` + + +## Location-independent identifier in remote ref + +### Schema + +```json +{ + "$ref": "http://localhost:1234/locationIndependentIdentifierDraft4.json#/definitions/refToInteger" +} +``` + +### Code + +```js +'use strict' +const ref2 = function validate(data) { + if (!Number.isInteger(data)) return false + return true +}; +const ref1 = function validate(data) { + if (!ref2(data)) return false + return true +}; +const ref0 = function validate(data) { + if (!ref1(data)) return false + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireSchema] $schema is required at http://localhost:1234/locationIndependentIdentifierDraft4.json#` + diff --git a/doc/samples/draft4/required.md b/doc/samples/draft4/required.md new file mode 100644 index 0000000..e769611 --- /dev/null +++ b/doc/samples/draft4/required.md @@ -0,0 +1,121 @@ +# required + +## required validation + +### Schema + +```json +{ "properties": { "foo": {}, "bar": {} }, "required": ["foo"] } +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (!(data.foo !== undefined && hasOwn(data, "foo"))) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] empty rules node is not allowed at #/properties/foo` + + +## required default validation + +### Schema + +```json +{ "properties": { "foo": {} } } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] empty rules node is not allowed at #/properties/foo` + + +## required with escaped characters + +### Schema + +```json +{ + "required": [ + "foo\nbar", + "foo\"bar", + "foo\\bar", + "foo\rbar", + "foo\tbar", + "foo\fbar" + ] +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (!(data["foo\nbar"] !== undefined && hasOwn(data, "foo\nbar"))) return false + if (!(data["foo\"bar"] !== undefined && hasOwn(data, "foo\"bar"))) return false + if (!(data["foo\\bar"] !== undefined && hasOwn(data, "foo\\bar"))) return false + if (!(data["foo\rbar"] !== undefined && hasOwn(data, "foo\rbar"))) return false + if (!(data["foo\tbar"] !== undefined && hasOwn(data, "foo\tbar"))) return false + if (!(data["foo\fbar"] !== undefined && hasOwn(data, "foo\fbar"))) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## required properties whose names are Javascript object property names + +### Schema + +```json +{ "required": ["__proto__", "toString", "constructor"] } +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (!(data["__proto__"] !== undefined && hasOwn(data, "__proto__"))) return false + if (!(data.toString !== undefined && hasOwn(data, "toString"))) return false + if (!(data.constructor !== undefined && hasOwn(data, "constructor"))) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + diff --git a/doc/samples/draft4/type.md b/doc/samples/draft4/type.md new file mode 100644 index 0000000..ed839b2 --- /dev/null +++ b/doc/samples/draft4/type.md @@ -0,0 +1,249 @@ +# type + +## integer type matches integers + +### Schema + +```json +{ "type": "integer" } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (!Number.isInteger(data)) return false + return true +}; +return ref0 +``` + + +## number type matches numbers + +### Schema + +```json +{ "type": "number" } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (!(typeof data === "number")) return false + return true +}; +return ref0 +``` + + +## string type matches strings + +### Schema + +```json +{ "type": "string" } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (!(typeof data === "string")) return false + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireStringValidation] pattern, format or contentSchema should be specified for strings, use pattern: ^[\s\S]*$ to opt-out at #` + + +## object type matches objects + +### Schema + +```json +{ "type": "object" } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (!(typeof data === "object" && data && !Array.isArray(data))) return false + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] additionalProperties or unevaluatedProperties should be specified at #` + + +## array type matches arrays + +### Schema + +```json +{ "type": "array" } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (!Array.isArray(data)) return false + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] items rule should be specified at #` + + +## boolean type matches booleans + +### Schema + +```json +{ "type": "boolean" } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (!(typeof data === "boolean")) return false + return true +}; +return ref0 +``` + + +## null type matches only the null object + +### Schema + +```json +{ "type": "null" } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (!(data === null)) return false + return true +}; +return ref0 +``` + + +## multiple types can be specified in an array + +### Schema + +```json +{ "type": ["integer", "string"] } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (!(Number.isInteger(data) || typeof data === "string")) return false + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireStringValidation] pattern, format or contentSchema should be specified for strings, use pattern: ^[\s\S]*$ to opt-out at #` + + +## type as array with one item + +### Schema + +```json +{ "type": ["string"] } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (!(typeof data === "string")) return false + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireStringValidation] pattern, format or contentSchema should be specified for strings, use pattern: ^[\s\S]*$ to opt-out at #` + + +## type: array or object + +### Schema + +```json +{ "type": ["array", "object"] } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (!(Array.isArray(data) || typeof data === "object" && data && !Array.isArray(data))) return false + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] items rule should be specified at #` + + +## type: array, object or null + +### Schema + +```json +{ "type": ["array", "object", "null"] } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (!(Array.isArray(data) || typeof data === "object" && data && !Array.isArray(data) || data === null)) return false + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] items rule should be specified at #` + diff --git a/doc/samples/draft4/uniqueItems.md b/doc/samples/draft4/uniqueItems.md new file mode 100644 index 0000000..bd67a27 --- /dev/null +++ b/doc/samples/draft4/uniqueItems.md @@ -0,0 +1,319 @@ +# uniqueItems + +## uniqueItems validation + +### Schema + +```json +{ "uniqueItems": true } +``` + +### Code + +```js +'use strict' +const unique = (array) => { + if (array.length < 2) return true + if (array.length === 2) return !deepEqual(array[0], array[1]) + const objects = [] + const primitives = array.length > 20 ? new Set() : null + let primitivesCount = 0 + let pos = 0 + for (const item of array) { + if (typeof item === 'object') { + objects.push(item) + } else if (primitives) { + primitives.add(item) + if (primitives.size !== ++primitivesCount) return false + } else { + if (array.indexOf(item, pos + 1) !== -1) return false + } + pos++ + } + for (let i = 1; i < objects.length; i++) + for (let j = 0; j < i; j++) if (deepEqual(objects[i], objects[j])) return false + return true +}; +const deepEqual = (obj, obj2) => { + if (obj === obj2) return true + if (!obj || !obj2 || typeof obj !== typeof obj2) return false + if (obj !== obj2 && typeof obj !== 'object') return false + + const proto = Object.getPrototypeOf(obj) + if (proto !== Object.getPrototypeOf(obj2)) return false + + if (proto === Array.prototype) { + if (!Array.isArray(obj) || !Array.isArray(obj2)) return false + if (obj.length !== obj2.length) return false + return obj.every((x, i) => deepEqual(x, obj2[i])) + } else if (proto === Object.prototype) { + const [keys, keys2] = [Object.keys(obj), Object.keys(obj2)] + if (keys.length !== keys2.length) return false + const keyset2 = new Set([...keys, ...keys2]) + return keyset2.size === keys.length && keys.every((key) => deepEqual(obj[key], obj2[key])) + } + return false +}; +const ref0 = function validate(data) { + if (Array.isArray(data)) { + if (!unique(data)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[complexityChecks] maxItems should be specified for non-primitive uniqueItems at #` + + +## uniqueItems with an array of items + +### Schema + +```json +{ "items": [{ "type": "boolean" }, { "type": "boolean" }], "uniqueItems": true } +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const unique = (array) => { + if (array.length < 2) return true + if (array.length === 2) return !deepEqual(array[0], array[1]) + const objects = [] + const primitives = array.length > 20 ? new Set() : null + let primitivesCount = 0 + let pos = 0 + for (const item of array) { + if (typeof item === 'object') { + objects.push(item) + } else if (primitives) { + primitives.add(item) + if (primitives.size !== ++primitivesCount) return false + } else { + if (array.indexOf(item, pos + 1) !== -1) return false + } + pos++ + } + for (let i = 1; i < objects.length; i++) + for (let j = 0; j < i; j++) if (deepEqual(objects[i], objects[j])) return false + return true +}; +const deepEqual = (obj, obj2) => { + if (obj === obj2) return true + if (!obj || !obj2 || typeof obj !== typeof obj2) return false + if (obj !== obj2 && typeof obj !== 'object') return false + + const proto = Object.getPrototypeOf(obj) + if (proto !== Object.getPrototypeOf(obj2)) return false + + if (proto === Array.prototype) { + if (!Array.isArray(obj) || !Array.isArray(obj2)) return false + if (obj.length !== obj2.length) return false + return obj.every((x, i) => deepEqual(x, obj2[i])) + } else if (proto === Object.prototype) { + const [keys, keys2] = [Object.keys(obj), Object.keys(obj2)] + if (keys.length !== keys2.length) return false + const keyset2 = new Set([...keys, ...keys2]) + return keyset2.size === keys.length && keys.every((key) => deepEqual(obj[key], obj2[key])) + } + return false +}; +const ref0 = function validate(data) { + if (Array.isArray(data)) { + if (data[0] !== undefined && hasOwn(data, 0)) { + if (!(typeof data[0] === "boolean")) return false + } + if (data[1] !== undefined && hasOwn(data, 1)) { + if (!(typeof data[1] === "boolean")) return false + } + if (!unique(data)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[complexityChecks] maxItems should be specified for non-primitive uniqueItems at #` + + +## uniqueItems with an array of items and additionalItems=false + +### Schema + +```json +{ + "items": [{ "type": "boolean" }, { "type": "boolean" }], + "uniqueItems": true, + "additionalItems": false +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const unique = (array) => { + if (array.length < 2) return true + if (array.length === 2) return !deepEqual(array[0], array[1]) + const objects = [] + const primitives = array.length > 20 ? new Set() : null + let primitivesCount = 0 + let pos = 0 + for (const item of array) { + if (typeof item === 'object') { + objects.push(item) + } else if (primitives) { + primitives.add(item) + if (primitives.size !== ++primitivesCount) return false + } else { + if (array.indexOf(item, pos + 1) !== -1) return false + } + pos++ + } + for (let i = 1; i < objects.length; i++) + for (let j = 0; j < i; j++) if (deepEqual(objects[i], objects[j])) return false + return true +}; +const deepEqual = (obj, obj2) => { + if (obj === obj2) return true + if (!obj || !obj2 || typeof obj !== typeof obj2) return false + if (obj !== obj2 && typeof obj !== 'object') return false + + const proto = Object.getPrototypeOf(obj) + if (proto !== Object.getPrototypeOf(obj2)) return false + + if (proto === Array.prototype) { + if (!Array.isArray(obj) || !Array.isArray(obj2)) return false + if (obj.length !== obj2.length) return false + return obj.every((x, i) => deepEqual(x, obj2[i])) + } else if (proto === Object.prototype) { + const [keys, keys2] = [Object.keys(obj), Object.keys(obj2)] + if (keys.length !== keys2.length) return false + const keyset2 = new Set([...keys, ...keys2]) + return keyset2.size === keys.length && keys.every((key) => deepEqual(obj[key], obj2[key])) + } + return false +}; +const ref0 = function validate(data) { + if (Array.isArray(data)) { + if (data[0] !== undefined && hasOwn(data, 0)) { + if (!(typeof data[0] === "boolean")) return false + } + if (data[1] !== undefined && hasOwn(data, 1)) { + if (!(typeof data[1] === "boolean")) return false + } + if (data.length > 2) return false + if (!unique(data)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## uniqueItems=false validation + +### Schema + +```json +{ "uniqueItems": false } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## uniqueItems=false with an array of items + +### Schema + +```json +{ + "items": [{ "type": "boolean" }, { "type": "boolean" }], + "uniqueItems": false +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (Array.isArray(data)) { + if (data[0] !== undefined && hasOwn(data, 0)) { + if (!(typeof data[0] === "boolean")) return false + } + if (data[1] !== undefined && hasOwn(data, 1)) { + if (!(typeof data[1] === "boolean")) return false + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## uniqueItems=false with an array of items and additionalItems=false + +### Schema + +```json +{ + "items": [{ "type": "boolean" }, { "type": "boolean" }], + "uniqueItems": false, + "additionalItems": false +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (Array.isArray(data)) { + if (data[0] !== undefined && hasOwn(data, 0)) { + if (!(typeof data[0] === "boolean")) return false + } + if (data[1] !== undefined && hasOwn(data, 1)) { + if (!(typeof data[1] === "boolean")) return false + } + if (data.length > 2) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + diff --git a/doc/samples/draft6/README.md b/doc/samples/draft6/README.md new file mode 100644 index 0000000..634b77a --- /dev/null +++ b/doc/samples/draft6/README.md @@ -0,0 +1,70 @@ +# Samples + +Based on JSON Schema Test Suite for `draft6`. + + +### Disambiguation + + * **Failed to compile** — schemas that did not compile in any mode. + + * **Warnings** — schemas that did not compile in the `default` mode, but compiled in `lax` + mode. + + JSON Schema spec allows usage of ineffective or unknown keywords, which is considered a mistake + by `@exodus/schemasafe` by default. `lax` mode lifts that coherence check. + + * **Misclassified** — schemas that classified at least one test value incorrectly, i.e. gave + `true` where testsuite expected `false` or vice versa. + +## Results + +| Name | Total | Failed to compile | Warnings | Misclassified | +|-------------------------------------------------------------|-------|-------------------|----------|---------------| +| [additionalItems](./additionalItems.md) | 9 | - | 4 | - | +| [additionalProperties](./additionalProperties.md) | 7 | - | - | - | +| [allOf](./allOf.md) | 12 | - | - | - | +| [anyOf](./anyOf.md) | 8 | - | 3 | - | +| [boolean_schema](./boolean_schema.md) | 2 | - | - | - | +| [const](./const.md) | 15 | - | - | - | +| [contains](./contains.md) | 6 | - | - | - | +| [default](./default.md) | 3 | - | - | - | +| [definitions](./definitions.md) | 1 | - | - | - | +| [dependencies](./dependencies.md) | 6 | - | - | - | +| [enum](./enum.md) | 10 | - | - | - | +| [exclusiveMaximum](./exclusiveMaximum.md) | 1 | - | - | - | +| [exclusiveMinimum](./exclusiveMinimum.md) | 1 | - | - | - | +| [format](./format.md) | 9 | - | - | - | +| [id](./id.md) | 3 | - | - | - | +| [infinite-loop-detection](./infinite-loop-detection.md) | 1 | - | - | - | +| [items](./items.md) | 9 | - | - | - | +| [maxItems](./maxItems.md) | 2 | - | - | - | +| [maxLength](./maxLength.md) | 2 | - | - | - | +| [maxProperties](./maxProperties.md) | 3 | - | - | - | +| [maximum](./maximum.md) | 2 | - | - | - | +| [minItems](./minItems.md) | 2 | - | - | - | +| [minLength](./minLength.md) | 2 | - | - | - | +| [minProperties](./minProperties.md) | 2 | - | - | - | +| [minimum](./minimum.md) | 2 | - | - | - | +| [multipleOf](./multipleOf.md) | 4 | - | - | - | +| [not](./not.md) | 6 | - | 1 | - | +| [oneOf](./oneOf.md) | 11 | - | 3 | - | +| [pattern](./pattern.md) | 2 | - | - | - | +| [patternProperties](./patternProperties.md) | 5 | - | - | - | +| [properties](./properties.md) | 6 | - | - | - | +| [propertyNames](./propertyNames.md) | 4 | - | - | - | +| [ref](./ref.md) | 26 | - | 2 | - | +| [refRemote](./refRemote.md) | 10 | - | - | - | +| [required](./required.md) | 5 | - | - | - | +| [type](./type.md) | 11 | - | - | - | +| [uniqueItems](./uniqueItems.md) | 6 | - | - | - | +| [unknownKeyword](./unknownKeyword.md) | 1 | - | 1 | - | +| [optional/bignum](./optional-bignum.md) | 7 | - | - | - | +| [optional/ecmascript-regex](./optional-ecmascript-regex.md) | 20 | - | - | - | +| [optional/float-overflow](./optional-float-overflow.md) | 1 | - | - | - | +| [optional/non-bmp-regex](./optional-non-bmp-regex.md) | 2 | - | - | - | + +### Notes + +`{ isJSON: true }` option is used for better clarity, and that also corresponds to the main +expected usage pattern of this module. Without it, there would be additional checks for +`!== undefined`, which can be fast-tracked if we know that the input came from `JSON.parse()`. diff --git a/doc/samples/draft6/additionalItems.md b/doc/samples/draft6/additionalItems.md new file mode 100644 index 0000000..3da2bba --- /dev/null +++ b/doc/samples/draft6/additionalItems.md @@ -0,0 +1,268 @@ +# additionalItems + +## additionalItems as schema + +### Schema + +```json +{ "items": [{}], "additionalItems": { "type": "integer" } } +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (Array.isArray(data)) { + for (let i = 1; i < data.length; i++) { + if (data[i] !== undefined && hasOwn(data, i)) { + if (!(Number.isInteger(data[i]))) return false + } + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] empty rules node is not allowed at #/0` + + +## when items is schema, additionalItems does nothing + +### Schema + +```json +{ "items": {}, "additionalItems": false } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + return true +}; +return ref0 +``` + +### Warnings + + * `Unprocessed keywords: ["additionalItems"] at #` + + +## array of items with no additionalItems permitted + +### Schema + +```json +{ "items": [{}, {}, {}], "additionalItems": false } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (Array.isArray(data)) { + if (data.length > 3) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] empty rules node is not allowed at #/0` + + +## additionalItems as false without items + +### Schema + +```json +{ "additionalItems": false } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + return true +}; +return ref0 +``` + +### Warnings + + * `Unprocessed keywords: ["additionalItems"] at #` + + +## additionalItems are allowed by default + +### Schema + +```json +{ "items": [{ "type": "integer" }] } +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (Array.isArray(data)) { + if (data[0] !== undefined && hasOwn(data, 0)) { + if (!(Number.isInteger(data[0]))) return false + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## additionalItems does not look in applicators, valid case + +### Schema + +```json +{ + "allOf": [{ "items": [{ "type": "integer" }] }], + "additionalItems": { "type": "boolean" } +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (Array.isArray(data)) { + if (data[0] !== undefined && hasOwn(data, 0)) { + if (!(Number.isInteger(data[0]))) return false + } + } + return true +}; +return ref0 +``` + +### Warnings + + * `Unprocessed keywords: ["additionalItems"] at #` + + +## additionalItems does not look in applicators, invalid case + +### Schema + +```json +{ + "allOf": [{ "items": [{ "type": "integer" }, { "type": "string" }] }], + "items": [{ "type": "integer" }], + "additionalItems": { "type": "boolean" } +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (Array.isArray(data)) { + if (data[0] !== undefined && hasOwn(data, 0)) { + if (!(Number.isInteger(data[0]))) return false + } + for (let i = 1; i < data.length; i++) { + if (data[i] !== undefined && hasOwn(data, i)) { + if (!(typeof data[i] === "boolean")) return false + } + } + } + if (Array.isArray(data)) { + if (data[0] !== undefined && hasOwn(data, 0)) { + if (!(Number.isInteger(data[0]))) return false + } + if (data[1] !== undefined && hasOwn(data, 1)) { + if (!(typeof data[1] === "string")) return false + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireStringValidation] pattern, format or contentSchema should be specified for strings, use pattern: ^[\s\S]*$ to opt-out at #/allOf/0/1` + + +## items validation adjusts the starting index for additionalItems + +### Schema + +```json +{ "items": [{ "type": "string" }], "additionalItems": { "type": "integer" } } +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (Array.isArray(data)) { + if (data[0] !== undefined && hasOwn(data, 0)) { + if (!(typeof data[0] === "string")) return false + } + for (let i = 1; i < data.length; i++) { + if (data[i] !== undefined && hasOwn(data, i)) { + if (!(Number.isInteger(data[i]))) return false + } + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireStringValidation] pattern, format or contentSchema should be specified for strings, use pattern: ^[\s\S]*$ to opt-out at #/0` + + +## additionalItems with null instance elements + +### Schema + +```json +{ "additionalItems": { "type": "null" } } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + return true +}; +return ref0 +``` + +### Warnings + + * `Unprocessed keywords: ["additionalItems"] at #` + diff --git a/doc/samples/draft6/additionalProperties.md b/doc/samples/draft6/additionalProperties.md new file mode 100644 index 0000000..33da910 --- /dev/null +++ b/doc/samples/draft6/additionalProperties.md @@ -0,0 +1,204 @@ +# additionalProperties + +## additionalProperties being false does not allow other properties + +### Schema + +```json +{ + "properties": { "foo": {}, "bar": {} }, + "patternProperties": { "^v": {} }, + "additionalProperties": false +} +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + for (const key1 of Object.keys(data)) { + if (key1 !== "foo" && key1 !== "bar" && !(key1.startsWith("v"))) return false + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] empty rules node is not allowed at #/properties/foo` + + +## non-ASCII pattern with additionalProperties + +### Schema + +```json +{ "patternProperties": { "^á": {} }, "additionalProperties": false } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + for (const key1 of Object.keys(data)) { + if (!(key1.startsWith("á"))) return false + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `Should start with ^ and end with $: "^á" at #` + + +## additionalProperties with schema + +### Schema + +```json +{ + "properties": { "foo": {}, "bar": {} }, + "additionalProperties": { "type": "boolean" } +} +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + for (const key0 of Object.keys(data)) { + if (key0 !== "foo" && key0 !== "bar") { + if (!(typeof data[key0] === "boolean")) return false + } + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] empty rules node is not allowed at #/properties/foo` + + +## additionalProperties can exist by itself + +### Schema + +```json +{ "additionalProperties": { "type": "boolean" } } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + for (const key0 of Object.keys(data)) { + if (!(typeof data[key0] === "boolean")) return false + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## additionalProperties are allowed by default + +### Schema + +```json +{ "properties": { "foo": {}, "bar": {} } } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] empty rules node is not allowed at #/properties/foo` + + +## additionalProperties does not look in applicators + +### Schema + +```json +{ + "allOf": [{ "properties": { "foo": {} } }], + "additionalProperties": { "type": "boolean" } +} +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + for (const key0 of Object.keys(data)) { + if (!(typeof data[key0] === "boolean")) return false + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] empty rules node is not allowed at #/allOf/0/properties/foo` + + +## additionalProperties with null valued instance properties + +### Schema + +```json +{ "additionalProperties": { "type": "null" } } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + for (const key0 of Object.keys(data)) { + if (!(data[key0] === null)) return false + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + diff --git a/doc/samples/draft6/allOf.md b/doc/samples/draft6/allOf.md new file mode 100644 index 0000000..9e2130e --- /dev/null +++ b/doc/samples/draft6/allOf.md @@ -0,0 +1,328 @@ +# allOf + +## allOf + +### Schema + +```json +{ + "allOf": [ + { "properties": { "bar": { "type": "integer" } }, "required": ["bar"] }, + { "properties": { "foo": { "type": "string" } }, "required": ["foo"] } + ] +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (!(data.bar !== undefined && hasOwn(data, "bar"))) return false + if (!Number.isInteger(data.bar)) return false + } + if (typeof data === "object" && data && !Array.isArray(data)) { + if (!(data.foo !== undefined && hasOwn(data, "foo"))) return false + if (!(typeof data.foo === "string")) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireStringValidation] pattern, format or contentSchema should be specified for strings, use pattern: ^[\s\S]*$ to opt-out at #/allOf/1/properties/foo` + + +## allOf with base schema + +### Schema + +```json +{ + "properties": { "bar": { "type": "integer" } }, + "required": ["bar"], + "allOf": [ + { "properties": { "foo": { "type": "string" } }, "required": ["foo"] }, + { "properties": { "baz": { "type": "null" } }, "required": ["baz"] } + ] +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (!(data.bar !== undefined && hasOwn(data, "bar"))) return false + if (!Number.isInteger(data.bar)) return false + } + if (typeof data === "object" && data && !Array.isArray(data)) { + if (!(data.foo !== undefined && hasOwn(data, "foo"))) return false + if (!(typeof data.foo === "string")) return false + } + if (typeof data === "object" && data && !Array.isArray(data)) { + if (!(data.baz !== undefined && hasOwn(data, "baz"))) return false + if (!(data.baz === null)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireStringValidation] pattern, format or contentSchema should be specified for strings, use pattern: ^[\s\S]*$ to opt-out at #/allOf/0/properties/foo` + + +## allOf simple types + +### Schema + +```json +{ "allOf": [{ "maximum": 30 }, { "minimum": 20 }] } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (typeof data === "number") { + if (!(30 >= data)) return false + } + if (typeof data === "number") { + if (!(20 <= data)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## allOf with boolean schemas, all true + +### Schema + +```json +{ "allOf": [true, true] } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] schema = true is not allowed at #/allOf/0` + + +## allOf with boolean schemas, some false + +### Schema + +```json +{ "allOf": [true, false] } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + return false + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] schema = true is not allowed at #/allOf/0` + + +## allOf with boolean schemas, all false + +### Schema + +```json +{ "allOf": [false, false] } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + return false + return false + return true +}; +return ref0 +``` + + +## allOf with one empty schema + +### Schema + +```json +{ "allOf": [{}] } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] empty rules node is not allowed at #/allOf/0` + + +## allOf with two empty schemas + +### Schema + +```json +{ "allOf": [{}, {}] } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] empty rules node is not allowed at #/allOf/0` + + +## allOf with the first empty schema + +### Schema + +```json +{ "allOf": [{}, { "type": "number" }] } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (!(typeof data === "number")) return false + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] empty rules node is not allowed at #/allOf/0` + + +## allOf with the last empty schema + +### Schema + +```json +{ "allOf": [{ "type": "number" }, {}] } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (!(typeof data === "number")) return false + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] empty rules node is not allowed at #/allOf/1` + + +## nested allOf, to check validation semantics + +### Schema + +```json +{ "allOf": [{ "allOf": [{ "type": "null" }] }] } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (!(data === null)) return false + return true +}; +return ref0 +``` + + +## allOf combined with anyOf, oneOf + +### Schema + +```json +{ + "allOf": [{ "multipleOf": 2 }], + "anyOf": [{ "multipleOf": 3 }], + "oneOf": [{ "multipleOf": 5 }] +} +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (typeof data === "number") { + if (data % 2 !== 0) return false + } + if (typeof data === "number") { + if (data % 3 !== 0) return false + } + if (typeof data === "number") { + if (data % 5 !== 0) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + diff --git a/doc/samples/draft6/anyOf.md b/doc/samples/draft6/anyOf.md new file mode 100644 index 0000000..3fcf9b7 --- /dev/null +++ b/doc/samples/draft6/anyOf.md @@ -0,0 +1,233 @@ +# anyOf + +## anyOf + +### Schema + +```json +{ "anyOf": [{ "type": "integer" }, { "minimum": 2 }] } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + const sub0 = (() => { + if (!Number.isInteger(data)) return false + return true + })() + if (!sub0) { + const sub1 = (() => { + if (typeof data === "number") { + if (!(2 <= data)) return false + } + return true + })() + if (!sub1) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## anyOf with base schema + +### Schema + +```json +{ "type": "string", "anyOf": [{ "maxLength": 2 }, { "minLength": 4 }] } +``` + +### Code + +```js +'use strict' +const stringLength = (string) => + /[\uD800-\uDFFF]/.test(string) ? [...string].length : string.length; +const ref0 = function validate(data) { + if (!(typeof data === "string")) return false + const sub0 = (() => { + if (data.length > 2 && stringLength(data) > 2) return false + return true + })() + if (!sub0) { + const sub1 = (() => { + if (data.length < 4 || stringLength(data) < 4) return false + return true + })() + if (!sub1) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireStringValidation] pattern, format or contentSchema should be specified for strings, use pattern: ^[\s\S]*$ to opt-out at #` + + +## anyOf with boolean schemas, all true + +### Schema + +```json +{ "anyOf": [true, true] } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + return true +}; +return ref0 +``` + +### Warnings + + * `some checks are never reachable at #` + + +## anyOf with boolean schemas, some true + +### Schema + +```json +{ "anyOf": [true, false] } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + return true +}; +return ref0 +``` + +### Warnings + + * `some checks are never reachable at #` + + +## anyOf with boolean schemas, all false + +### Schema + +```json +{ "anyOf": [false, false] } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + return false + return true +}; +return ref0 +``` + + +## anyOf complex types + +### Schema + +```json +{ + "anyOf": [ + { "properties": { "bar": { "type": "integer" } }, "required": ["bar"] }, + { "properties": { "foo": { "type": "string" } }, "required": ["foo"] } + ] +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + const sub0 = (() => { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (!(data.bar !== undefined && hasOwn(data, "bar"))) return false + if (!Number.isInteger(data.bar)) return false + } + return true + })() + if (!sub0) { + const sub1 = (() => { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (!(data.foo !== undefined && hasOwn(data, "foo"))) return false + if (!(typeof data.foo === "string")) return false + } + return true + })() + if (!sub1) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireStringValidation] pattern, format or contentSchema should be specified for strings, use pattern: ^[\s\S]*$ to opt-out at #/anyOf/1/properties/foo` + + +## anyOf with one empty schema + +### Schema + +```json +{ "anyOf": [{ "type": "number" }, {}] } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + const sub0 = (() => { + if (!(typeof data === "number")) return false + return true + })() + return true +}; +return ref0 +``` + +### Warnings + + * `some checks are never reachable at #` + + +## nested anyOf, to check validation semantics + +### Schema + +```json +{ "anyOf": [{ "anyOf": [{ "type": "null" }] }] } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (!(data === null)) return false + return true +}; +return ref0 +``` + diff --git a/doc/samples/draft6/boolean_schema.md b/doc/samples/draft6/boolean_schema.md new file mode 100644 index 0000000..406f7d6 --- /dev/null +++ b/doc/samples/draft6/boolean_schema.md @@ -0,0 +1,44 @@ +# boolean_schema + +## boolean schema 'true' + +### Schema + +```json +true +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] schema = true is not allowed at #` + + +## boolean schema 'false' + +### Schema + +```json +false +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + return false + return true +}; +return ref0 +``` + diff --git a/doc/samples/draft6/const.md b/doc/samples/draft6/const.md new file mode 100644 index 0000000..a918cab --- /dev/null +++ b/doc/samples/draft6/const.md @@ -0,0 +1,324 @@ +# const + +## const validation + +### Schema + +```json +{ "const": 2 } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (!(data === 2)) return false + return true +}; +return ref0 +``` + + +## const with object + +### Schema + +```json +{ "const": { "foo": "bar", "baz": "bax" } } +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (!(typeof data === "object" && data && !Array.isArray(data) && Object.keys(data).length === 2 && hasOwn(data, "foo") && hasOwn(data, "baz") && data["foo"] === "bar" && data["baz"] === "bax")) return false + return true +}; +return ref0 +``` + + +## const with array + +### Schema + +```json +{ "const": [{ "foo": "bar" }] } +``` + +### Code + +```js +'use strict' +const deepEqual = (obj, obj2) => { + if (obj === obj2) return true + if (!obj || !obj2 || typeof obj !== typeof obj2) return false + if (obj !== obj2 && typeof obj !== 'object') return false + + const proto = Object.getPrototypeOf(obj) + if (proto !== Object.getPrototypeOf(obj2)) return false + + if (proto === Array.prototype) { + if (!Array.isArray(obj) || !Array.isArray(obj2)) return false + if (obj.length !== obj2.length) return false + return obj.every((x, i) => deepEqual(x, obj2[i])) + } else if (proto === Object.prototype) { + const [keys, keys2] = [Object.keys(obj), Object.keys(obj2)] + if (keys.length !== keys2.length) return false + const keyset2 = new Set([...keys, ...keys2]) + return keyset2.size === keys.length && keys.every((key) => deepEqual(obj[key], obj2[key])) + } + return false +}; +const ref0 = function validate(data) { + if (!(Array.isArray(data) && deepEqual(data, [{"foo":"bar"}]))) return false + return true +}; +return ref0 +``` + + +## const with null + +### Schema + +```json +{ "const": null } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (!(data === null)) return false + return true +}; +return ref0 +``` + + +## const with false does not match 0 + +### Schema + +```json +{ "const": false } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (!(data === false)) return false + return true +}; +return ref0 +``` + + +## const with true does not match 1 + +### Schema + +```json +{ "const": true } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (!(data === true)) return false + return true +}; +return ref0 +``` + + +## const with [false] does not match [0] + +### Schema + +```json +{ "const": [false] } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (!(Array.isArray(data) && data.length === 1 && data[0] === false)) return false + return true +}; +return ref0 +``` + + +## const with [true] does not match [1] + +### Schema + +```json +{ "const": [true] } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (!(Array.isArray(data) && data.length === 1 && data[0] === true)) return false + return true +}; +return ref0 +``` + + +## const with {"a": false} does not match {"a": 0} + +### Schema + +```json +{ "const": { "a": false } } +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (!(typeof data === "object" && data && !Array.isArray(data) && Object.keys(data).length === 1 && hasOwn(data, "a") && data["a"] === false)) return false + return true +}; +return ref0 +``` + + +## const with {"a": true} does not match {"a": 1} + +### Schema + +```json +{ "const": { "a": true } } +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (!(typeof data === "object" && data && !Array.isArray(data) && Object.keys(data).length === 1 && hasOwn(data, "a") && data["a"] === true)) return false + return true +}; +return ref0 +``` + + +## const with 0 does not match other zero-like types + +### Schema + +```json +{ "const": 0 } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (!(data === 0)) return false + return true +}; +return ref0 +``` + + +## const with 1 does not match true + +### Schema + +```json +{ "const": 1 } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (!(data === 1)) return false + return true +}; +return ref0 +``` + + +## const with -2.0 matches integer and float types + +### Schema + +```json +{ "const": -2 } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (!(data === -2)) return false + return true +}; +return ref0 +``` + + +## float and integers are equal up to 64-bit representation limits + +### Schema + +```json +{ "const": 9007199254740992 } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (!(data === 9007199254740992)) return false + return true +}; +return ref0 +``` + + +## nul characters in strings + +### Schema + +```json +{ "const": "hello\u0000there" } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (!(data === "hello\u0000there")) return false + return true +}; +return ref0 +``` + diff --git a/doc/samples/draft6/contains.md b/doc/samples/draft6/contains.md new file mode 100644 index 0000000..7695ac7 --- /dev/null +++ b/doc/samples/draft6/contains.md @@ -0,0 +1,228 @@ +# contains + +## contains keyword validation + +### Schema + +```json +{ "contains": { "minimum": 5 } } +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (Array.isArray(data)) { + let passes0 = 0 + for (let i = 0; i < data.length; i++) { + const sub0 = (() => { + if (data[i] !== undefined && hasOwn(data, i)) { + if (typeof data[i] === "number") { + if (!(5 <= data[i])) return false + } + } + return true + })() + if (sub0) passes0++ + } + if (passes0 < 1) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #/contains` + + +## contains keyword with const keyword + +### Schema + +```json +{ "contains": { "const": 5 } } +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (Array.isArray(data)) { + let passes0 = 0 + for (let i = 0; i < data.length; i++) { + const sub0 = (() => { + if (data[i] !== undefined && hasOwn(data, i)) { + if (!(data[i] === 5)) return false + } + return true + })() + if (sub0) passes0++ + } + if (passes0 < 1) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## contains keyword with boolean schema true + +### Schema + +```json +{ "contains": true } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (Array.isArray(data)) { + let passes0 = 0 + for (let i = 0; i < data.length; i++) { + const sub0 = (() => { + return true + })() + if (sub0) passes0++ + } + if (passes0 < 1) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] schema = true is not allowed at #/contains` + + +## contains keyword with boolean schema false + +### Schema + +```json +{ "contains": false } +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (Array.isArray(data)) { + let passes0 = 0 + for (let i = 0; i < data.length; i++) { + const sub0 = (() => { + if (data[i] !== undefined && hasOwn(data, i)) return false + return true + })() + if (sub0) passes0++ + } + if (passes0 < 1) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## items + contains + +### Schema + +```json +{ "items": { "multipleOf": 2 }, "contains": { "multipleOf": 3 } } +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (Array.isArray(data)) { + for (let i = 0; i < data.length; i++) { + if (data[i] !== undefined && hasOwn(data, i)) { + if (typeof data[i] === "number") { + if (data[i] % 2 !== 0) return false + } + } + } + let passes0 = 0 + for (let j = 0; j < data.length; j++) { + const sub0 = (() => { + if (data[j] !== undefined && hasOwn(data, j)) { + if (typeof data[j] === "number") { + if (data[j] % 3 !== 0) return false + } + } + return true + })() + if (sub0) passes0++ + } + if (passes0 < 1) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #/items` + + +## contains with null instance elements + +### Schema + +```json +{ "contains": { "type": "null" } } +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (Array.isArray(data)) { + let passes0 = 0 + for (let i = 0; i < data.length; i++) { + const sub0 = (() => { + if (data[i] !== undefined && hasOwn(data, i)) { + if (!(data[i] === null)) return false + } + return true + })() + if (sub0) passes0++ + } + if (passes0 < 1) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + diff --git a/doc/samples/draft6/default.md b/doc/samples/draft6/default.md new file mode 100644 index 0000000..9e6b1e6 --- /dev/null +++ b/doc/samples/draft6/default.md @@ -0,0 +1,98 @@ +# default + +## invalid type for default + +### Schema + +```json +{ "properties": { "foo": { "type": "integer", "default": [] } } } +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.foo !== undefined && hasOwn(data, "foo")) { + if (!Number.isInteger(data.foo)) return false + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## invalid string value for default + +### Schema + +```json +{ + "properties": { + "bar": { "type": "string", "minLength": 4, "default": "bad" } + } +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const stringLength = (string) => + /[\uD800-\uDFFF]/.test(string) ? [...string].length : string.length; +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.bar !== undefined && hasOwn(data, "bar")) { + if (!(typeof data.bar === "string")) return false + if (data.bar.length < 4 || stringLength(data.bar) < 4) return false + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireStringValidation] pattern, format or contentSchema should be specified for strings, use pattern: ^[\s\S]*$ to opt-out at #/properties/bar` + + +## the default keyword does not do anything if the property is missing + +### Schema + +```json +{ + "type": "object", + "properties": { "alpha": { "type": "number", "maximum": 3, "default": 5 } } +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (!(typeof data === "object" && data && !Array.isArray(data))) return false + if (data.alpha !== undefined && hasOwn(data, "alpha")) { + if (!(typeof data.alpha === "number")) return false + if (!(3 >= data.alpha)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] additionalProperties or unevaluatedProperties should be specified at #` + diff --git a/doc/samples/draft6/definitions.md b/doc/samples/draft6/definitions.md new file mode 100644 index 0000000..117d12a --- /dev/null +++ b/doc/samples/draft6/definitions.md @@ -0,0 +1,284 @@ +# definitions + +## validate definition against metaschema + +### Schema + +```json +{ "$ref": "http://json-schema.org/draft-06/schema#" } +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const format0 = new RegExp("^(?:[a-z][a-z0-9+\\-.]*:)?(?:\\/?\\/(?:(?:[a-z0-9\\-._~!$&'()*+,;=:]|%[0-9a-f]{2})*@)?(?:\\[(?:(?:(?:(?:[0-9a-f]{1,4}:){6}|::(?:[0-9a-f]{1,4}:){5}|(?:[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){4}|(?:(?:[0-9a-f]{1,4}:){0,1}[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){3}|(?:(?:[0-9a-f]{1,4}:){0,2}[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){2}|(?:(?:[0-9a-f]{1,4}:){0,3}[0-9a-f]{1,4})?::[0-9a-f]{1,4}:|(?:(?:[0-9a-f]{1,4}:){0,4}[0-9a-f]{1,4})?::)(?:[0-9a-f]{1,4}:[0-9a-f]{1,4}|(?:(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d\\d?)\\.){3}(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d\\d?))|(?:(?:[0-9a-f]{1,4}:){0,5}[0-9a-f]{1,4})?::[0-9a-f]{1,4}|(?:(?:[0-9a-f]{1,4}:){0,6}[0-9a-f]{1,4})?::)|v[0-9a-f]+\\.[a-z0-9\\-._~!$&'()*+,;=:]+)\\]|(?:(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d\\d?)\\.){3}(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d\\d?)|(?:[a-z0-9\\-._~!$&'()*+,;=]|%[0-9a-f]{2})*)(?::\\d*)?(?:\\/(?:[a-z0-9\\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})*)*|\\/?(?:(?:[a-z0-9\\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})+(?:\\/(?:[a-z0-9\\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})*)*)?)?(?:\\?(?:[a-z0-9\\-._~!$&'()*+,;=:@/?]|%[0-9a-f]{2})*)?(?:#(?:[a-z0-9\\-._~!$&'()*+,;=:@/?]|%[0-9a-f]{2})*)?$", "i"); +const format1 = new RegExp("^[a-z][a-z0-9+\\-.]*:(?:\\/?\\/(?:(?:[a-z0-9\\-._~!$&'()*+,;=:]|%[0-9a-f]{2})*@)?(?:\\[(?:(?:(?:(?:[0-9a-f]{1,4}:){6}|::(?:[0-9a-f]{1,4}:){5}|(?:[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){4}|(?:(?:[0-9a-f]{1,4}:){0,1}[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){3}|(?:(?:[0-9a-f]{1,4}:){0,2}[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){2}|(?:(?:[0-9a-f]{1,4}:){0,3}[0-9a-f]{1,4})?::[0-9a-f]{1,4}:|(?:(?:[0-9a-f]{1,4}:){0,4}[0-9a-f]{1,4})?::)(?:[0-9a-f]{1,4}:[0-9a-f]{1,4}|(?:(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d\\d?)\\.){3}(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d\\d?))|(?:(?:[0-9a-f]{1,4}:){0,5}[0-9a-f]{1,4})?::[0-9a-f]{1,4}|(?:(?:[0-9a-f]{1,4}:){0,6}[0-9a-f]{1,4})?::)|v[0-9a-f]+\\.[a-z0-9\\-._~!$&'()*+,;=:]+)\\]|(?:(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d\\d?)\\.){3}(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d\\d?)|(?:[a-z0-9\\-._~!$&'()*+,;=]|%[0-9a-f]{2})*)(?::\\d*)?(?:\\/(?:[a-z0-9\\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})*)*|\\/?(?:(?:[a-z0-9\\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})+(?:\\/(?:[a-z0-9\\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})*)*)?)(?:\\?(?:[a-z0-9\\-._~!$&'()*+,;=:@/?]|%[0-9a-f]{2})*)?(?:#(?:[a-z0-9\\-._~!$&'()*+,;=:@/?]|%[0-9a-f]{2})*)?$", "i"); +const ref2 = function validate(data) { + if (!Number.isInteger(data)) return false + if (!(0 <= data)) return false + return true +}; +const ref3 = function validate(data) { + if (!ref2(data)) return false + return true +}; +const format2 = (str) => { + if (str.length > 1e5) return false + const Z_ANCHOR = /[^\\]\\Z/ + if (Z_ANCHOR.test(str)) return false + try { + new RegExp(str, 'u') + return true + } catch (e) { + return false + } + }; +const ref4 = function validate(data) { + if (!Array.isArray(data)) return false + if (data.length < 1) return false + for (let j = 0; j < data.length; j++) { + if (data[j] !== undefined && hasOwn(data, j)) { + if (!ref1(data[j])) return false + } + } + return true +}; +const unique = (array) => { + if (array.length < 2) return true + if (array.length === 2) return !deepEqual(array[0], array[1]) + const objects = [] + const primitives = array.length > 20 ? new Set() : null + let primitivesCount = 0 + let pos = 0 + for (const item of array) { + if (typeof item === 'object') { + objects.push(item) + } else if (primitives) { + primitives.add(item) + if (primitives.size !== ++primitivesCount) return false + } else { + if (array.indexOf(item, pos + 1) !== -1) return false + } + pos++ + } + for (let i = 1; i < objects.length; i++) + for (let j = 0; j < i; j++) if (deepEqual(objects[i], objects[j])) return false + return true +}; +const deepEqual = (obj, obj2) => { + if (obj === obj2) return true + if (!obj || !obj2 || typeof obj !== typeof obj2) return false + if (obj !== obj2 && typeof obj !== 'object') return false + + const proto = Object.getPrototypeOf(obj) + if (proto !== Object.getPrototypeOf(obj2)) return false + + if (proto === Array.prototype) { + if (!Array.isArray(obj) || !Array.isArray(obj2)) return false + if (obj.length !== obj2.length) return false + return obj.every((x, i) => deepEqual(x, obj2[i])) + } else if (proto === Object.prototype) { + const [keys, keys2] = [Object.keys(obj), Object.keys(obj2)] + if (keys.length !== keys2.length) return false + const keyset2 = new Set([...keys, ...keys2]) + return keyset2.size === keys.length && keys.every((key) => deepEqual(obj[key], obj2[key])) + } + return false +}; +const ref5 = function validate(data) { + if (!Array.isArray(data)) return false + for (let k = 0; k < data.length; k++) { + if (data[k] !== undefined && hasOwn(data, k)) { + if (!(typeof data[k] === "string")) return false + } + } + if (!unique(data)) return false + return true +}; +const ref6 = function validate(data) { + if (!(data === "array" || data === "boolean" || data === "integer" || data === "null" || data === "number" || data === "object" || data === "string")) return false + return true +}; +const ref1 = function validate(data) { + if (!(typeof data === "object" && data && !Array.isArray(data) || typeof data === "boolean")) return false + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data["$id"] !== undefined && hasOwn(data, "$id")) { + if (!(typeof data["$id"] === "string")) return false + if (!format0.test(data["$id"])) return false + } + if (data["$schema"] !== undefined && hasOwn(data, "$schema")) { + if (!(typeof data["$schema"] === "string")) return false + if (!format1.test(data["$schema"])) return false + } + if (data["$ref"] !== undefined && hasOwn(data, "$ref")) { + if (!(typeof data["$ref"] === "string")) return false + if (!format0.test(data["$ref"])) return false + } + if (data.title !== undefined && hasOwn(data, "title")) { + if (!(typeof data.title === "string")) return false + } + if (data.description !== undefined && hasOwn(data, "description")) { + if (!(typeof data.description === "string")) return false + } + if (data.examples !== undefined && hasOwn(data, "examples")) { + if (!Array.isArray(data.examples)) return false + } + if (data.multipleOf !== undefined && hasOwn(data, "multipleOf")) { + if (!(typeof data.multipleOf === "number")) return false + if (!(0 < data.multipleOf)) return false + } + if (data.maximum !== undefined && hasOwn(data, "maximum")) { + if (!(typeof data.maximum === "number")) return false + } + if (data.exclusiveMaximum !== undefined && hasOwn(data, "exclusiveMaximum")) { + if (!(typeof data.exclusiveMaximum === "number")) return false + } + if (data.minimum !== undefined && hasOwn(data, "minimum")) { + if (!(typeof data.minimum === "number")) return false + } + if (data.exclusiveMinimum !== undefined && hasOwn(data, "exclusiveMinimum")) { + if (!(typeof data.exclusiveMinimum === "number")) return false + } + if (data.maxLength !== undefined && hasOwn(data, "maxLength")) { + if (!ref2(data.maxLength)) return false + } + if (data.minLength !== undefined && hasOwn(data, "minLength")) { + if (!ref3(data.minLength)) return false + } + if (data.pattern !== undefined && hasOwn(data, "pattern")) { + if (!(typeof data.pattern === "string")) return false + if (!format2(data.pattern)) return false + } + if (data.additionalItems !== undefined && hasOwn(data, "additionalItems")) { + if (!validate(data.additionalItems)) return false + } + if (data.items !== undefined && hasOwn(data, "items")) { + const sub0 = (() => { + if (!validate(data.items)) return false + return true + })() + if (!sub0) { + const sub1 = (() => { + if (!ref4(data.items)) return false + return true + })() + if (!sub1) return false + } + } + if (data.maxItems !== undefined && hasOwn(data, "maxItems")) { + if (!ref2(data.maxItems)) return false + } + if (data.minItems !== undefined && hasOwn(data, "minItems")) { + if (!ref3(data.minItems)) return false + } + if (data.uniqueItems !== undefined && hasOwn(data, "uniqueItems")) { + if (!(typeof data.uniqueItems === "boolean")) return false + } + if (data.contains !== undefined && hasOwn(data, "contains")) { + if (!validate(data.contains)) return false + } + if (data.maxProperties !== undefined && hasOwn(data, "maxProperties")) { + if (!ref2(data.maxProperties)) return false + } + if (data.minProperties !== undefined && hasOwn(data, "minProperties")) { + if (!ref3(data.minProperties)) return false + } + if (data.required !== undefined && hasOwn(data, "required")) { + if (!ref5(data.required)) return false + } + if (data.additionalProperties !== undefined && hasOwn(data, "additionalProperties")) { + if (!validate(data.additionalProperties)) return false + } + if (data.definitions !== undefined && hasOwn(data, "definitions")) { + if (!(typeof data.definitions === "object" && data.definitions && !Array.isArray(data.definitions))) return false + for (const key0 of Object.keys(data.definitions)) { + if (!validate(data.definitions[key0])) return false + } + } + if (data.properties !== undefined && hasOwn(data, "properties")) { + if (!(typeof data.properties === "object" && data.properties && !Array.isArray(data.properties))) return false + for (const key1 of Object.keys(data.properties)) { + if (!validate(data.properties[key1])) return false + } + } + if (data.patternProperties !== undefined && hasOwn(data, "patternProperties")) { + if (!(typeof data.patternProperties === "object" && data.patternProperties && !Array.isArray(data.patternProperties))) return false + for (const key2 of Object.keys(data.patternProperties)) { + if (!validate(data.patternProperties[key2])) return false + } + } + if (data.dependencies !== undefined && hasOwn(data, "dependencies")) { + if (!(typeof data.dependencies === "object" && data.dependencies && !Array.isArray(data.dependencies))) return false + for (const key3 of Object.keys(data.dependencies)) { + const sub2 = (() => { + if (!validate(data.dependencies[key3])) return false + return true + })() + if (!sub2) { + const sub3 = (() => { + if (!ref5(data.dependencies[key3])) return false + return true + })() + if (!sub3) return false + } + } + } + if (data.propertyNames !== undefined && hasOwn(data, "propertyNames")) { + if (!validate(data.propertyNames)) return false + } + if (data.enum !== undefined && hasOwn(data, "enum")) { + if (!Array.isArray(data.enum)) return false + if (data.enum.length < 1) return false + if (!unique(data.enum)) return false + } + if (data.type !== undefined && hasOwn(data, "type")) { + const sub4 = (() => { + if (!ref6(data.type)) return false + return true + })() + if (!sub4) { + const sub5 = (() => { + if (!Array.isArray(data.type)) return false + if (data.type.length < 1) return false + for (let l = 0; l < data.type.length; l++) { + if (data.type[l] !== undefined && hasOwn(data.type, l)) { + if (!ref6(data.type[l])) return false + } + } + if (!unique(data.type)) return false + return true + })() + if (!sub5) return false + } + } + if (data.format !== undefined && hasOwn(data, "format")) { + if (!(typeof data.format === "string")) return false + } + if (data.allOf !== undefined && hasOwn(data, "allOf")) { + if (!ref4(data.allOf)) return false + } + if (data.anyOf !== undefined && hasOwn(data, "anyOf")) { + if (!ref4(data.anyOf)) return false + } + if (data.oneOf !== undefined && hasOwn(data, "oneOf")) { + if (!ref4(data.oneOf)) return false + } + if (data.not !== undefined && hasOwn(data, "not")) { + if (!validate(data.not)) return false + } + } + return true +}; +const ref0 = function validate(data) { + if (!ref1(data)) return false + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireStringValidation] pattern, format or contentSchema should be specified for strings, use pattern: ^[\s\S]*$ to opt-out at http://json-schema.org/draft-06/schema#/properties/title` + diff --git a/doc/samples/draft6/dependencies.md b/doc/samples/draft6/dependencies.md new file mode 100644 index 0000000..a13ce57 --- /dev/null +++ b/doc/samples/draft6/dependencies.md @@ -0,0 +1,195 @@ +# dependencies + +## dependencies + +### Schema + +```json +{ "dependencies": { "bar": ["foo"] } } +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.bar !== undefined && hasOwn(data, "bar") && !(data.foo !== undefined && hasOwn(data, "foo"))) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## dependencies with empty array + +### Schema + +```json +{ "dependencies": { "bar": [] } } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## multiple dependencies + +### Schema + +```json +{ "dependencies": { "quux": ["foo", "bar"] } } +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.quux !== undefined && hasOwn(data, "quux") && !(data.foo !== undefined && hasOwn(data, "foo") && data.bar !== undefined && hasOwn(data, "bar"))) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## multiple dependencies subschema + +### Schema + +```json +{ + "dependencies": { + "bar": { + "properties": { + "foo": { "type": "integer" }, + "bar": { "type": "integer" } + } + } + } +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.bar !== undefined && hasOwn(data, "bar")) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.foo !== undefined && hasOwn(data, "foo")) { + if (!Number.isInteger(data.foo)) return false + } + if (data.bar !== undefined && hasOwn(data, "bar")) { + if (!Number.isInteger(data.bar)) return false + } + } + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] if properties is used, required should be specified at #/dependencies/bar` + + +## dependencies with boolean subschemas + +### Schema + +```json +{ "dependencies": { "foo": true, "bar": false } } +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.bar !== undefined && hasOwn(data, "bar")) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] schema = true is not allowed at #/dependencies/foo` + + +## dependencies with escaped characters + +### Schema + +```json +{ + "dependencies": { + "foo\nbar": ["foo\rbar"], + "foo\tbar": { "minProperties": 4 }, + "foo'bar": { "required": ["foo\"bar"] }, + "foo\"bar": ["foo'bar"] + } +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data["foo\nbar"] !== undefined && hasOwn(data, "foo\nbar") && !(data["foo\rbar"] !== undefined && hasOwn(data, "foo\rbar"))) return false + if (data["foo\tbar"] !== undefined && hasOwn(data, "foo\tbar")) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (Object.keys(data).length < 4) return false + } + } + if (data["foo'bar"] !== undefined && hasOwn(data, "foo'bar")) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (!(data["foo\"bar"] !== undefined && hasOwn(data, "foo\"bar"))) return false + } + } + if (data["foo\"bar"] !== undefined && hasOwn(data, "foo\"bar") && !(data["foo'bar"] !== undefined && hasOwn(data, "foo'bar"))) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + diff --git a/doc/samples/draft6/enum.md b/doc/samples/draft6/enum.md new file mode 100644 index 0000000..f72f0da --- /dev/null +++ b/doc/samples/draft6/enum.md @@ -0,0 +1,216 @@ +# enum + +## simple enum validation + +### Schema + +```json +{ "enum": [1, 2, 3] } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (!(data === 1 || data === 2 || data === 3)) return false + return true +}; +return ref0 +``` + + +## heterogeneous enum validation + +### Schema + +```json +{ "enum": [6, "foo", [], true, { "foo": 12 }] } +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (!(data === 6 || data === "foo" || data === true || Array.isArray(data) && data.length === 0 || typeof data === "object" && data && !Array.isArray(data) && Object.keys(data).length === 1 && hasOwn(data, "foo") && data["foo"] === 12)) return false + return true +}; +return ref0 +``` + + +## heterogeneous enum-with-null validation + +### Schema + +```json +{ "enum": [6, null] } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (!(data === 6 || data === null)) return false + return true +}; +return ref0 +``` + + +## enums in properties + +### Schema + +```json +{ + "type": "object", + "properties": { "foo": { "enum": ["foo"] }, "bar": { "enum": ["bar"] } }, + "required": ["bar"] +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (!(typeof data === "object" && data && !Array.isArray(data))) return false + if (!(data.bar !== undefined && hasOwn(data, "bar"))) return false + if (data.foo !== undefined && hasOwn(data, "foo")) { + if (!(data.foo === "foo")) return false + } + if (!(data.bar === "bar")) return false + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] additionalProperties or unevaluatedProperties should be specified at #` + + +## enum with escaped characters + +### Schema + +```json +{ "enum": ["foo\nbar", "foo\rbar"] } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (!(data === "foo\nbar" || data === "foo\rbar")) return false + return true +}; +return ref0 +``` + + +## enum with false does not match 0 + +### Schema + +```json +{ "enum": [false] } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (!(data === false)) return false + return true +}; +return ref0 +``` + + +## enum with true does not match 1 + +### Schema + +```json +{ "enum": [true] } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (!(data === true)) return false + return true +}; +return ref0 +``` + + +## enum with 0 does not match false + +### Schema + +```json +{ "enum": [0] } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (!(data === 0)) return false + return true +}; +return ref0 +``` + + +## enum with 1 does not match true + +### Schema + +```json +{ "enum": [1] } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (!(data === 1)) return false + return true +}; +return ref0 +``` + + +## nul characters in strings + +### Schema + +```json +{ "enum": ["hello\u0000there"] } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (!(data === "hello\u0000there")) return false + return true +}; +return ref0 +``` + diff --git a/doc/samples/draft6/exclusiveMaximum.md b/doc/samples/draft6/exclusiveMaximum.md new file mode 100644 index 0000000..fa89b08 --- /dev/null +++ b/doc/samples/draft6/exclusiveMaximum.md @@ -0,0 +1,27 @@ +# exclusiveMaximum + +## exclusiveMaximum validation + +### Schema + +```json +{ "exclusiveMaximum": 3 } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (typeof data === "number") { + if (!(3 > data)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + diff --git a/doc/samples/draft6/exclusiveMinimum.md b/doc/samples/draft6/exclusiveMinimum.md new file mode 100644 index 0000000..4a605e7 --- /dev/null +++ b/doc/samples/draft6/exclusiveMinimum.md @@ -0,0 +1,27 @@ +# exclusiveMinimum + +## exclusiveMinimum validation + +### Schema + +```json +{ "exclusiveMinimum": 1.1 } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (typeof data === "number") { + if (!(1.1 < data)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + diff --git a/doc/samples/draft6/format.md b/doc/samples/draft6/format.md new file mode 100644 index 0000000..c75bc68 --- /dev/null +++ b/doc/samples/draft6/format.md @@ -0,0 +1,314 @@ +# format + +## email format + +### Schema + +```json +{ "format": "email" } +``` + +### Code + +```js +'use strict' +const format0 = (input) => { + if (input.length > 318) return false + const fast = /^[a-z0-9!#$%&'*+/=?^_`{|}~-]{1,20}(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]{1,21}){0,2}@[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?(?:\.[a-z0-9](?:[a-z0-9-]{0,60}[a-z0-9])?){0,3}$/i + if (fast.test(input)) return true + if (!input.includes('@') || /(^\.|^"|\.@|\.\.)/.test(input)) return false + const [name, host, ...rest] = input.split('@') + if (!name || !host || rest.length !== 0 || name.length > 64 || host.length > 253) return false + if (!/^[a-z0-9.-]+$/i.test(host) || !/^[a-z0-9.!#$%&'*+/=?^_`{|}~-]+$/i.test(name)) return false + return host.split('.').every((part) => /^[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?$/i.test(part)) + }; +const ref0 = function validate(data) { + if (typeof data === "string") { + if (!format0(data)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## ipv4 format + +### Schema + +```json +{ "format": "ipv4" } +``` + +### Code + +```js +'use strict' +const format0 = (ip) => + ip.length <= 15 && + /^(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)\.){3}(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d\d?)$/.test(ip); +const ref0 = function validate(data) { + if (typeof data === "string") { + if (!format0(data)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## ipv6 format + +### Schema + +```json +{ "format": "ipv6" } +``` + +### Code + +```js +'use strict' +const format0 = (input) => { + if (input.length > 45 || input.length < 2) return false + let s0 = 0, s1 = 0, hex = 0, short = false, letters = false, last = 0, start = true + for (let i = 0; i < input.length; i++) { + const c = input.charCodeAt(i) + if (i === 1 && last === 58 && c !== 58) return false + if (c >= 48 && c <= 57) { + if (++hex > 4) return false + } else if (c === 46) { + if (s0 > 6 || s1 >= 3 || hex === 0 || letters) return false + s1++ + hex = 0 + } else if (c === 58) { + if (s1 > 0 || s0 >= 7) return false + if (last === 58) { + if (short) return false + short = true + } else if (i === 0) start = false + s0++ + hex = 0 + letters = false + } else if ((c >= 97 && c <= 102) || (c >= 65 && c <= 70)) { + if (s1 > 0) return false + if (++hex > 4) return false + letters = true + } else return false + last = c + } + if (s0 < 2 || (s1 > 0 && (s1 !== 3 || hex === 0))) return false + if (short && input.length === 2) return true + if (s1 > 0 && !/(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}$/.test(input)) return false + const spaces = s1 > 0 ? 6 : 7 + if (!short) return s0 === spaces && start && hex > 0 + return (start || hex > 0) && s0 < spaces + }; +const ref0 = function validate(data) { + if (typeof data === "string") { + if (!format0(data)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## hostname format + +### Schema + +```json +{ "format": "hostname" } +``` + +### Code + +```js +'use strict' +const format0 = (input) => { + if (input.length > (input.endsWith('.') ? 254 : 253)) return false + const hostname = /^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?(?:\.[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?)*\.?$/i + return hostname.test(input) + }; +const ref0 = function validate(data) { + if (typeof data === "string") { + if (!format0(data)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## date-time format + +### Schema + +```json +{ "format": "date-time" } +``` + +### Code + +```js +'use strict' +const format0 = (input) => { + if (input.length > 10 + 1 + 9 + 12 + 6) return false + const full = /^\d\d\d\d-(?:0[1-9]|1[0-2])-(?:[0-2]\d|3[01])[t\s](?:2[0-3]|[0-1]\d):[0-5]\d:(?:[0-5]\d|60)(?:\.\d+)?(?:z|[+-](?:2[0-3]|[0-1]\d)(?::?[0-5]\d)?)$/i + const feb = input[5] === '0' && input[6] === '2' + if ((feb && input[8] === '3') || !full.test(input)) return false + if (input[17] === '6') { + const p = input.slice(11).match(/([0-9.]+|[^0-9.])/g) + let hm = Number(p[0]) * 60 + Number(p[2]) + if (p[5] === '+') hm += 24 * 60 - Number(p[6] || 0) * 60 - Number(p[8] || 0) + else if (p[5] === '-') hm += Number(p[6] || 0) * 60 + Number(p[8] || 0) + if (hm % (24 * 60) !== 23 * 60 + 59) return false + } + if (feb) { + if (/^\d\d\d\d-02-(?:[012][1-8]|[12]0|[01]9)/.test(input)) return true + const matches = input.match(/^(\d\d\d\d)-02-29/) + if (!matches) return false + const year = matches[1] | 0 + return year % 16 === 0 || (year % 4 === 0 && year % 25 !== 0) + } + if (input[8] === '3' && input[9] === '1') return /^\d\d\d\d-(?:0[13578]|1[02])-31/.test(input) + return /^\d\d\d\d-(?:0[13-9]|1[012])-(?:[012][1-9]|[123]0)/.test(input) + }; +const ref0 = function validate(data) { + if (typeof data === "string") { + if (!format0(data)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## json-pointer format + +### Schema + +```json +{ "format": "json-pointer" } +``` + +### Code + +```js +'use strict' +const format0 = new RegExp("^(?:|\\/(?:[^~]|~0|~1)*)$", ""); +const ref0 = function validate(data) { + if (typeof data === "string") { + if (!format0.test(data)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## uri format + +### Schema + +```json +{ "format": "uri" } +``` + +### Code + +```js +'use strict' +const format0 = new RegExp("^[a-z][a-z0-9+\\-.]*:(?:\\/?\\/(?:(?:[a-z0-9\\-._~!$&'()*+,;=:]|%[0-9a-f]{2})*@)?(?:\\[(?:(?:(?:(?:[0-9a-f]{1,4}:){6}|::(?:[0-9a-f]{1,4}:){5}|(?:[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){4}|(?:(?:[0-9a-f]{1,4}:){0,1}[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){3}|(?:(?:[0-9a-f]{1,4}:){0,2}[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){2}|(?:(?:[0-9a-f]{1,4}:){0,3}[0-9a-f]{1,4})?::[0-9a-f]{1,4}:|(?:(?:[0-9a-f]{1,4}:){0,4}[0-9a-f]{1,4})?::)(?:[0-9a-f]{1,4}:[0-9a-f]{1,4}|(?:(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d\\d?)\\.){3}(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d\\d?))|(?:(?:[0-9a-f]{1,4}:){0,5}[0-9a-f]{1,4})?::[0-9a-f]{1,4}|(?:(?:[0-9a-f]{1,4}:){0,6}[0-9a-f]{1,4})?::)|v[0-9a-f]+\\.[a-z0-9\\-._~!$&'()*+,;=:]+)\\]|(?:(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d\\d?)\\.){3}(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d\\d?)|(?:[a-z0-9\\-._~!$&'()*+,;=]|%[0-9a-f]{2})*)(?::\\d*)?(?:\\/(?:[a-z0-9\\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})*)*|\\/?(?:(?:[a-z0-9\\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})+(?:\\/(?:[a-z0-9\\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})*)*)?)(?:\\?(?:[a-z0-9\\-._~!$&'()*+,;=:@/?]|%[0-9a-f]{2})*)?(?:#(?:[a-z0-9\\-._~!$&'()*+,;=:@/?]|%[0-9a-f]{2})*)?$", "i"); +const ref0 = function validate(data) { + if (typeof data === "string") { + if (!format0.test(data)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## uri-reference format + +### Schema + +```json +{ "format": "uri-reference" } +``` + +### Code + +```js +'use strict' +const format0 = new RegExp("^(?:[a-z][a-z0-9+\\-.]*:)?(?:\\/?\\/(?:(?:[a-z0-9\\-._~!$&'()*+,;=:]|%[0-9a-f]{2})*@)?(?:\\[(?:(?:(?:(?:[0-9a-f]{1,4}:){6}|::(?:[0-9a-f]{1,4}:){5}|(?:[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){4}|(?:(?:[0-9a-f]{1,4}:){0,1}[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){3}|(?:(?:[0-9a-f]{1,4}:){0,2}[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){2}|(?:(?:[0-9a-f]{1,4}:){0,3}[0-9a-f]{1,4})?::[0-9a-f]{1,4}:|(?:(?:[0-9a-f]{1,4}:){0,4}[0-9a-f]{1,4})?::)(?:[0-9a-f]{1,4}:[0-9a-f]{1,4}|(?:(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d\\d?)\\.){3}(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d\\d?))|(?:(?:[0-9a-f]{1,4}:){0,5}[0-9a-f]{1,4})?::[0-9a-f]{1,4}|(?:(?:[0-9a-f]{1,4}:){0,6}[0-9a-f]{1,4})?::)|v[0-9a-f]+\\.[a-z0-9\\-._~!$&'()*+,;=:]+)\\]|(?:(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d\\d?)\\.){3}(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d\\d?)|(?:[a-z0-9\\-._~!$&'()*+,;=]|%[0-9a-f]{2})*)(?::\\d*)?(?:\\/(?:[a-z0-9\\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})*)*|\\/?(?:(?:[a-z0-9\\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})+(?:\\/(?:[a-z0-9\\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})*)*)?)?(?:\\?(?:[a-z0-9\\-._~!$&'()*+,;=:@/?]|%[0-9a-f]{2})*)?(?:#(?:[a-z0-9\\-._~!$&'()*+,;=:@/?]|%[0-9a-f]{2})*)?$", "i"); +const ref0 = function validate(data) { + if (typeof data === "string") { + if (!format0.test(data)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## uri-template format + +### Schema + +```json +{ "format": "uri-template" } +``` + +### Code + +```js +'use strict' +const format0 = new RegExp("^(?:[^\\x00-\\x20\"'<>%\\\\^`{|}]|%[0-9a-f]{2}|\\{[+#./;?&=,!@|]?(?:[a-z0-9_]|%[0-9a-f]{2})+(?::[1-9][0-9]{0,3}|\\*)?(?:,(?:[a-z0-9_]|%[0-9a-f]{2})+(?::[1-9][0-9]{0,3}|\\*)?)*\\})*$", "i"); +const ref0 = function validate(data) { + if (typeof data === "string") { + if (!format0.test(data)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + diff --git a/doc/samples/draft6/id.md b/doc/samples/draft6/id.md new file mode 100644 index 0000000..d7e2030 --- /dev/null +++ b/doc/samples/draft6/id.md @@ -0,0 +1,175 @@ +# id + +## id inside an enum is not a real identifier + +### Schema + +```json +{ + "definitions": { + "id_in_enum": { + "enum": [ + { + "$id": "https://localhost:1234/id/my_identifier.json", + "type": "null" + } + ] + }, + "real_id_in_schema": { + "$id": "https://localhost:1234/id/my_identifier.json", + "type": "string" + }, + "zzz_id_in_const": { + "const": { + "$id": "https://localhost:1234/id/my_identifier.json", + "type": "null" + } + } + }, + "anyOf": [ + { "$ref": "#/definitions/id_in_enum" }, + { "$ref": "https://localhost:1234/id/my_identifier.json" } + ] +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref1 = function validate(data) { + if (!(typeof data === "object" && data && !Array.isArray(data) && Object.keys(data).length === 2 && hasOwn(data, "$id") && hasOwn(data, "type") && data["$id"] === "https://localhost:1234/id/my_identifier.json" && data["type"] === "null")) return false + return true +}; +const ref2 = function validate(data) { + if (!(typeof data === "string")) return false + return true +}; +const ref0 = function validate(data) { + const sub0 = (() => { + if (!ref1(data)) return false + return true + })() + if (!sub0) { + const sub1 = (() => { + if (!ref2(data)) return false + return true + })() + if (!sub1) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireStringValidation] pattern, format or contentSchema should be specified for strings, use pattern: ^[\s\S]*$ to opt-out at #` + + +## non-schema object containing a plain-name $id property + +### Schema + +```json +{ + "definitions": { + "const_not_anchor": { "const": { "$id": "#not_a_real_anchor" } } + }, + "oneOf": [ + { "const": "skip not_a_real_anchor" }, + { + "allOf": [ + { "not": { "const": "skip not_a_real_anchor" } }, + { "$ref": "#/definitions/const_not_anchor" } + ] + } + ] +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref1 = function validate(data) { + if (!(typeof data === "object" && data && !Array.isArray(data) && Object.keys(data).length === 1 && hasOwn(data, "$id") && data["$id"] === "#not_a_real_anchor")) return false + return true +}; +const ref0 = function validate(data) { + let passes0 = 0 + const sub0 = (() => { + if (!(data === "skip not_a_real_anchor")) return false + return true + })() + if (sub0) passes0++ + const sub1 = (() => { + const sub2 = (() => { + if (!(data === "skip not_a_real_anchor")) return false + return true + })() + if (sub2) return false + if (!ref1(data)) return false + return true + })() + if (sub1) passes0++ + if (passes0 !== 1) return false + return true +}; +return ref0 +``` + + +## non-schema object containing an $id property + +### Schema + +```json +{ + "definitions": { "const_not_id": { "const": { "$id": "not_a_real_id" } } }, + "oneOf": [ + { "const": "skip not_a_real_id" }, + { + "allOf": [ + { "not": { "const": "skip not_a_real_id" } }, + { "$ref": "#/definitions/const_not_id" } + ] + } + ] +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref1 = function validate(data) { + if (!(typeof data === "object" && data && !Array.isArray(data) && Object.keys(data).length === 1 && hasOwn(data, "$id") && data["$id"] === "not_a_real_id")) return false + return true +}; +const ref0 = function validate(data) { + let passes0 = 0 + const sub0 = (() => { + if (!(data === "skip not_a_real_id")) return false + return true + })() + if (sub0) passes0++ + const sub1 = (() => { + const sub2 = (() => { + if (!(data === "skip not_a_real_id")) return false + return true + })() + if (sub2) return false + if (!ref1(data)) return false + return true + })() + if (sub1) passes0++ + if (passes0 !== 1) return false + return true +}; +return ref0 +``` + diff --git a/doc/samples/draft6/infinite-loop-detection.md b/doc/samples/draft6/infinite-loop-detection.md new file mode 100644 index 0000000..429be5c --- /dev/null +++ b/doc/samples/draft6/infinite-loop-detection.md @@ -0,0 +1,45 @@ +# infinite-loop-detection + +## evaluating the same schema location against the same data location twice is not a sign of an infinite loop + +### Schema + +```json +{ + "definitions": { "int": { "type": "integer" } }, + "allOf": [ + { "properties": { "foo": { "$ref": "#/definitions/int" } } }, + { "additionalProperties": { "$ref": "#/definitions/int" } } + ] +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref1 = function validate(data) { + if (!Number.isInteger(data)) return false + return true +}; +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.foo !== undefined && hasOwn(data, "foo")) { + if (!ref1(data.foo)) return false + } + } + if (typeof data === "object" && data && !Array.isArray(data)) { + for (const key0 of Object.keys(data)) { + if (!ref1(data[key0])) return false + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] if properties is used, required should be specified at #/allOf/0` + diff --git a/doc/samples/draft6/items.md b/doc/samples/draft6/items.md new file mode 100644 index 0000000..4002db9 --- /dev/null +++ b/doc/samples/draft6/items.md @@ -0,0 +1,323 @@ +# items + +## a schema given for items + +### Schema + +```json +{ "items": { "type": "integer" } } +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (Array.isArray(data)) { + for (let i = 0; i < data.length; i++) { + if (data[i] !== undefined && hasOwn(data, i)) { + if (!(Number.isInteger(data[i]))) return false + } + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## an array of schemas for items + +### Schema + +```json +{ "items": [{ "type": "integer" }, { "type": "string" }] } +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (Array.isArray(data)) { + if (data[0] !== undefined && hasOwn(data, 0)) { + if (!(Number.isInteger(data[0]))) return false + } + if (data[1] !== undefined && hasOwn(data, 1)) { + if (!(typeof data[1] === "string")) return false + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireStringValidation] pattern, format or contentSchema should be specified for strings, use pattern: ^[\s\S]*$ to opt-out at #/1` + + +## items with boolean schema (true) + +### Schema + +```json +{ "items": true } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] schema = true is not allowed at #/items` + + +## items with boolean schema (false) + +### Schema + +```json +{ "items": false } +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (Array.isArray(data)) { + for (let i = 0; i < data.length; i++) { + if (data[i] !== undefined && hasOwn(data, i)) return false + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## items with boolean schemas + +### Schema + +```json +{ "items": [true, false] } +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (Array.isArray(data)) { + if (data[1] !== undefined && hasOwn(data, 1)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] schema = true is not allowed at #/0` + + +## items and subitems + +### Schema + +```json +{ + "definitions": { + "item": { + "type": "array", + "additionalItems": false, + "items": [ + { "$ref": "#/definitions/sub-item" }, + { "$ref": "#/definitions/sub-item" } + ] + }, + "sub-item": { "type": "object", "required": ["foo"] } + }, + "type": "array", + "additionalItems": false, + "items": [ + { "$ref": "#/definitions/item" }, + { "$ref": "#/definitions/item" }, + { "$ref": "#/definitions/item" } + ] +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref2 = function validate(data) { + if (!(typeof data === "object" && data && !Array.isArray(data))) return false + if (!(data.foo !== undefined && hasOwn(data, "foo"))) return false + return true +}; +const ref1 = function validate(data) { + if (!Array.isArray(data)) return false + if (data[0] !== undefined && hasOwn(data, 0)) { + if (!ref2(data[0])) return false + } + if (data[1] !== undefined && hasOwn(data, 1)) { + if (!ref2(data[1])) return false + } + if (data.length > 2) return false + return true +}; +const ref0 = function validate(data) { + if (!Array.isArray(data)) return false + if (data[0] !== undefined && hasOwn(data, 0)) { + if (!ref1(data[0])) return false + } + if (data[1] !== undefined && hasOwn(data, 1)) { + if (!ref1(data[1])) return false + } + if (data[2] !== undefined && hasOwn(data, 2)) { + if (!ref1(data[2])) return false + } + if (data.length > 3) return false + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] additionalProperties or unevaluatedProperties should be specified at #` + + +## nested items + +### Schema + +```json +{ + "type": "array", + "items": { + "type": "array", + "items": { + "type": "array", + "items": { "type": "array", "items": { "type": "number" } } + } + } +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (!Array.isArray(data)) return false + for (let i = 0; i < data.length; i++) { + if (data[i] !== undefined && hasOwn(data, i)) { + if (!(Array.isArray(data[i]))) return false + for (let j = 0; j < data[i].length; j++) { + if (data[i][j] !== undefined && hasOwn(data[i], j)) { + if (!(Array.isArray(data[i][j]))) return false + for (let k = 0; k < data[i][j].length; k++) { + if (data[i][j][k] !== undefined && hasOwn(data[i][j], k)) { + if (!(Array.isArray(data[i][j][k]))) return false + for (let l = 0; l < data[i][j][k].length; l++) { + if (data[i][j][k][l] !== undefined && hasOwn(data[i][j][k], l)) { + if (!(typeof data[i][j][k][l] === "number")) return false + } + } + } + } + } + } + } + } + return true +}; +return ref0 +``` + + +## single-form items with null instance elements + +### Schema + +```json +{ "items": { "type": "null" } } +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (Array.isArray(data)) { + for (let i = 0; i < data.length; i++) { + if (data[i] !== undefined && hasOwn(data, i)) { + if (!(data[i] === null)) return false + } + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## array-form items with null instance elements + +### Schema + +```json +{ "items": [{ "type": "null" }] } +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (Array.isArray(data)) { + if (data[0] !== undefined && hasOwn(data, 0)) { + if (!(data[0] === null)) return false + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + diff --git a/doc/samples/draft6/maxItems.md b/doc/samples/draft6/maxItems.md new file mode 100644 index 0000000..42c80fd --- /dev/null +++ b/doc/samples/draft6/maxItems.md @@ -0,0 +1,53 @@ +# maxItems + +## maxItems validation + +### Schema + +```json +{ "maxItems": 2 } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (Array.isArray(data)) { + if (data.length > 2) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## maxItems validation with a decimal + +### Schema + +```json +{ "maxItems": 2 } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (Array.isArray(data)) { + if (data.length > 2) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + diff --git a/doc/samples/draft6/maxLength.md b/doc/samples/draft6/maxLength.md new file mode 100644 index 0000000..6f2f147 --- /dev/null +++ b/doc/samples/draft6/maxLength.md @@ -0,0 +1,57 @@ +# maxLength + +## maxLength validation + +### Schema + +```json +{ "maxLength": 2 } +``` + +### Code + +```js +'use strict' +const stringLength = (string) => + /[\uD800-\uDFFF]/.test(string) ? [...string].length : string.length; +const ref0 = function validate(data) { + if (typeof data === "string") { + if (data.length > 2 && stringLength(data) > 2) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## maxLength validation with a decimal + +### Schema + +```json +{ "maxLength": 2 } +``` + +### Code + +```js +'use strict' +const stringLength = (string) => + /[\uD800-\uDFFF]/.test(string) ? [...string].length : string.length; +const ref0 = function validate(data) { + if (typeof data === "string") { + if (data.length > 2 && stringLength(data) > 2) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + diff --git a/doc/samples/draft6/maxProperties.md b/doc/samples/draft6/maxProperties.md new file mode 100644 index 0000000..d085599 --- /dev/null +++ b/doc/samples/draft6/maxProperties.md @@ -0,0 +1,79 @@ +# maxProperties + +## maxProperties validation + +### Schema + +```json +{ "maxProperties": 2 } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (Object.keys(data).length > 2) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## maxProperties validation with a decimal + +### Schema + +```json +{ "maxProperties": 2 } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (Object.keys(data).length > 2) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## maxProperties = 0 means the object is empty + +### Schema + +```json +{ "maxProperties": 0 } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (Object.keys(data).length > 0) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + diff --git a/doc/samples/draft6/maximum.md b/doc/samples/draft6/maximum.md new file mode 100644 index 0000000..47de30e --- /dev/null +++ b/doc/samples/draft6/maximum.md @@ -0,0 +1,53 @@ +# maximum + +## maximum validation + +### Schema + +```json +{ "maximum": 3 } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (typeof data === "number") { + if (!(3 >= data)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## maximum validation with unsigned integer + +### Schema + +```json +{ "maximum": 300 } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (typeof data === "number") { + if (!(300 >= data)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + diff --git a/doc/samples/draft6/minItems.md b/doc/samples/draft6/minItems.md new file mode 100644 index 0000000..faaa676 --- /dev/null +++ b/doc/samples/draft6/minItems.md @@ -0,0 +1,53 @@ +# minItems + +## minItems validation + +### Schema + +```json +{ "minItems": 1 } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (Array.isArray(data)) { + if (data.length < 1) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## minItems validation with a decimal + +### Schema + +```json +{ "minItems": 1 } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (Array.isArray(data)) { + if (data.length < 1) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + diff --git a/doc/samples/draft6/minLength.md b/doc/samples/draft6/minLength.md new file mode 100644 index 0000000..9e7f30c --- /dev/null +++ b/doc/samples/draft6/minLength.md @@ -0,0 +1,57 @@ +# minLength + +## minLength validation + +### Schema + +```json +{ "minLength": 2 } +``` + +### Code + +```js +'use strict' +const stringLength = (string) => + /[\uD800-\uDFFF]/.test(string) ? [...string].length : string.length; +const ref0 = function validate(data) { + if (typeof data === "string") { + if (data.length < 2 || stringLength(data) < 2) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## minLength validation with a decimal + +### Schema + +```json +{ "minLength": 2 } +``` + +### Code + +```js +'use strict' +const stringLength = (string) => + /[\uD800-\uDFFF]/.test(string) ? [...string].length : string.length; +const ref0 = function validate(data) { + if (typeof data === "string") { + if (data.length < 2 || stringLength(data) < 2) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + diff --git a/doc/samples/draft6/minProperties.md b/doc/samples/draft6/minProperties.md new file mode 100644 index 0000000..072a920 --- /dev/null +++ b/doc/samples/draft6/minProperties.md @@ -0,0 +1,53 @@ +# minProperties + +## minProperties validation + +### Schema + +```json +{ "minProperties": 1 } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (Object.keys(data).length < 1) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## minProperties validation with a decimal + +### Schema + +```json +{ "minProperties": 1 } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (Object.keys(data).length < 1) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + diff --git a/doc/samples/draft6/minimum.md b/doc/samples/draft6/minimum.md new file mode 100644 index 0000000..7adc25c --- /dev/null +++ b/doc/samples/draft6/minimum.md @@ -0,0 +1,53 @@ +# minimum + +## minimum validation + +### Schema + +```json +{ "minimum": 1.1 } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (typeof data === "number") { + if (!(1.1 <= data)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## minimum validation with signed integer + +### Schema + +```json +{ "minimum": -2 } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (typeof data === "number") { + if (!(-2 <= data)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + diff --git a/doc/samples/draft6/multipleOf.md b/doc/samples/draft6/multipleOf.md new file mode 100644 index 0000000..f56f9b8 --- /dev/null +++ b/doc/samples/draft6/multipleOf.md @@ -0,0 +1,116 @@ +# multipleOf + +## by int + +### Schema + +```json +{ "multipleOf": 2 } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (typeof data === "number") { + if (data % 2 !== 0) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## by number + +### Schema + +```json +{ "multipleOf": 1.5 } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (typeof data === "number") { + if (data % 1.5 !== 0) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## by small number + +### Schema + +```json +{ "multipleOf": 0.0001 } +``` + +### Code + +```js +'use strict' +const isMultipleOf = (value, divisor, factor, factorMultiple) => { + if (value % divisor === 0) return true + let multiple = value * factor + if (multiple === Infinity || multiple === -Infinity) multiple = value + if (multiple % factorMultiple === 0) return true + const normal = Math.floor(multiple + 0.5) + return normal / factor === value && normal % factorMultiple === 0 +}; +const ref0 = function validate(data) { + if (typeof data === "number") { + if (!isMultipleOf(data, 0.0001, 1e4, 1)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## float division = inf + +### Schema + +```json +{ "type": "integer", "multipleOf": 0.123456789 } +``` + +### Code + +```js +'use strict' +const isMultipleOf = (value, divisor, factor, factorMultiple) => { + if (value % divisor === 0) return true + let multiple = value * factor + if (multiple === Infinity || multiple === -Infinity) multiple = value + if (multiple % factorMultiple === 0) return true + const normal = Math.floor(multiple + 0.5) + return normal / factor === value && normal % factorMultiple === 0 +}; +const ref0 = function validate(data) { + if (!Number.isInteger(data)) return false + if (!isMultipleOf(data, 0.123456789, 1e9, 123456789)) return false + return true +}; +return ref0 +``` + diff --git a/doc/samples/draft6/not.md b/doc/samples/draft6/not.md new file mode 100644 index 0000000..ba5ee57 --- /dev/null +++ b/doc/samples/draft6/not.md @@ -0,0 +1,163 @@ +# not + +## not + +### Schema + +```json +{ "not": { "type": "integer" } } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + const sub0 = (() => { + if (!Number.isInteger(data)) return false + return true + })() + if (sub0) return false + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## not multiple types + +### Schema + +```json +{ "not": { "type": ["integer", "boolean"] } } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + const sub0 = (() => { + if (!(Number.isInteger(data) || typeof data === "boolean")) return false + return true + })() + if (sub0) return false + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## not more complex schema + +### Schema + +```json +{ "not": { "type": "object", "properties": { "foo": { "type": "string" } } } } +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + const sub0 = (() => { + if (!(typeof data === "object" && data && !Array.isArray(data))) return false + if (data.foo !== undefined && hasOwn(data, "foo")) { + if (!(typeof data.foo === "string")) return false + } + return true + })() + if (sub0) return false + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] if properties is used, required should be specified at #/not` + + +## forbidden property + +### Schema + +```json +{ "properties": { "foo": { "not": {} } } } +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.foo !== undefined && hasOwn(data, "foo")) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #/properties/foo` + + +## not with boolean schema true + +### Schema + +```json +{ "not": true } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + return false + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## not with boolean schema false + +### Schema + +```json +{ "not": false } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + return true +}; +return ref0 +``` + +### Warnings + + * `some checks are never reachable at #` + diff --git a/doc/samples/draft6/oneOf.md b/doc/samples/draft6/oneOf.md new file mode 100644 index 0000000..4d80f08 --- /dev/null +++ b/doc/samples/draft6/oneOf.md @@ -0,0 +1,371 @@ +# oneOf + +## oneOf + +### Schema + +```json +{ "oneOf": [{ "type": "integer" }, { "minimum": 2 }] } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + let passes0 = 0 + const sub0 = (() => { + if (!Number.isInteger(data)) return false + return true + })() + if (sub0) passes0++ + const sub1 = (() => { + if (typeof data === "number") { + if (!(2 <= data)) return false + } + return true + })() + if (sub1) passes0++ + if (passes0 !== 1) return false + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## oneOf with base schema + +### Schema + +```json +{ "type": "string", "oneOf": [{ "minLength": 2 }, { "maxLength": 4 }] } +``` + +### Code + +```js +'use strict' +const stringLength = (string) => + /[\uD800-\uDFFF]/.test(string) ? [...string].length : string.length; +const ref0 = function validate(data) { + if (!(typeof data === "string")) return false + let passes0 = 0 + const sub0 = (() => { + if (data.length < 2 || stringLength(data) < 2) return false + return true + })() + if (sub0) passes0++ + const sub1 = (() => { + if (data.length > 4 && stringLength(data) > 4) return false + return true + })() + if (sub1) passes0++ + if (passes0 !== 1) return false + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireStringValidation] pattern, format or contentSchema should be specified for strings, use pattern: ^[\s\S]*$ to opt-out at #` + + +## oneOf with boolean schemas, all true + +### Schema + +```json +{ "oneOf": [true, true, true] } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + let passes0 = 0 + passes0++ + passes0++ + if (passes0 > 1) return false + passes0++ + if (passes0 !== 1) return false + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## oneOf with boolean schemas, one true + +### Schema + +```json +{ "oneOf": [true, false, false] } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + let passes0 = 0 + passes0++ + if (passes0 > 1) return false + if (passes0 !== 1) return false + return true +}; +return ref0 +``` + +### Warnings + + * `some checks are never reachable at #` + + +## oneOf with boolean schemas, more than one true + +### Schema + +```json +{ "oneOf": [true, true, false] } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + let passes0 = 0 + passes0++ + passes0++ + if (passes0 > 1) return false + if (passes0 !== 1) return false + return true +}; +return ref0 +``` + +### Warnings + + * `some checks are never reachable at #` + + +## oneOf with boolean schemas, all false + +### Schema + +```json +{ "oneOf": [false, false, false] } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + let passes0 = 0 + if (passes0 > 1) return false + if (passes0 !== 1) return false + return true +}; +return ref0 +``` + +### Warnings + + * `some checks are never reachable at #` + + +## oneOf complex types + +### Schema + +```json +{ + "oneOf": [ + { "properties": { "bar": { "type": "integer" } }, "required": ["bar"] }, + { "properties": { "foo": { "type": "string" } }, "required": ["foo"] } + ] +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + let passes0 = 0 + const sub0 = (() => { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (!(data.bar !== undefined && hasOwn(data, "bar"))) return false + if (!Number.isInteger(data.bar)) return false + } + return true + })() + if (sub0) passes0++ + const sub1 = (() => { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (!(data.foo !== undefined && hasOwn(data, "foo"))) return false + if (!(typeof data.foo === "string")) return false + } + return true + })() + if (sub1) passes0++ + if (passes0 !== 1) return false + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireStringValidation] pattern, format or contentSchema should be specified for strings, use pattern: ^[\s\S]*$ to opt-out at #/oneOf/1/properties/foo` + + +## oneOf with empty schema + +### Schema + +```json +{ "oneOf": [{ "type": "number" }, {}] } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + let passes0 = 0 + const sub0 = (() => { + if (!(typeof data === "number")) return false + return true + })() + if (sub0) passes0++ + passes0++ + if (passes0 !== 1) return false + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## oneOf with required + +### Schema + +```json +{ + "type": "object", + "oneOf": [{ "required": ["foo", "bar"] }, { "required": ["foo", "baz"] }] +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (!(typeof data === "object" && data && !Array.isArray(data))) return false + let passes0 = 0 + const sub0 = (() => { + if (!(data.foo !== undefined && hasOwn(data, "foo"))) return false + if (!(data.bar !== undefined && hasOwn(data, "bar"))) return false + return true + })() + if (sub0) passes0++ + const sub1 = (() => { + if (!(data.foo !== undefined && hasOwn(data, "foo"))) return false + if (!(data.baz !== undefined && hasOwn(data, "baz"))) return false + return true + })() + if (sub1) passes0++ + if (passes0 !== 1) return false + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] additionalProperties or unevaluatedProperties should be specified at #` + + +## oneOf with missing optional property + +### Schema + +```json +{ + "oneOf": [ + { "properties": { "bar": true, "baz": true }, "required": ["bar"] }, + { "properties": { "foo": true }, "required": ["foo"] } + ] +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + let passes0 = 0 + const sub0 = (() => { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (!(data.bar !== undefined && hasOwn(data, "bar"))) return false + } + return true + })() + if (sub0) passes0++ + const sub1 = (() => { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (!(data.foo !== undefined && hasOwn(data, "foo"))) return false + } + return true + })() + if (sub1) passes0++ + if (passes0 !== 1) return false + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] schema = true is not allowed at #/oneOf/0/properties/bar` + + +## nested oneOf, to check validation semantics + +### Schema + +```json +{ "oneOf": [{ "oneOf": [{ "type": "null" }] }] } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (!(data === null)) return false + return true +}; +return ref0 +``` + diff --git a/doc/samples/draft6/optional-bignum.md b/doc/samples/draft6/optional-bignum.md new file mode 100644 index 0000000..a9a7ca7 --- /dev/null +++ b/doc/samples/draft6/optional-bignum.md @@ -0,0 +1,169 @@ +# optional/bignum + +## integer + +### Schema + +```json +{ "type": "integer" } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (!Number.isInteger(data)) return false + return true +}; +return ref0 +``` + + +## number + +### Schema + +```json +{ "type": "number" } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (!(typeof data === "number")) return false + return true +}; +return ref0 +``` + + +## string + +### Schema + +```json +{ "type": "string" } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (!(typeof data === "string")) return false + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireStringValidation] pattern, format or contentSchema should be specified for strings, use pattern: ^[\s\S]*$ to opt-out at #` + + +## maximum integer comparison + +### Schema + +```json +{ "maximum": 18446744073709552000 } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (typeof data === "number") { + if (!(18446744073709552000 >= data)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## float comparison with high precision + +### Schema + +```json +{ "exclusiveMaximum": 9.727837981879871e26 } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (typeof data === "number") { + if (!(9.727837981879871e+26 > data)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## minimum integer comparison + +### Schema + +```json +{ "minimum": -18446744073709552000 } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (typeof data === "number") { + if (!(-18446744073709552000 <= data)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## float comparison with high precision on negative numbers + +### Schema + +```json +{ "exclusiveMinimum": -9.727837981879871e26 } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (typeof data === "number") { + if (!(-9.727837981879871e+26 < data)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + diff --git a/doc/samples/draft6/optional-ecmascript-regex.md b/doc/samples/draft6/optional-ecmascript-regex.md new file mode 100644 index 0000000..f67da04 --- /dev/null +++ b/doc/samples/draft6/optional-ecmascript-regex.md @@ -0,0 +1,515 @@ +# optional/ecmascript-regex + +## ECMA 262 regex $ does not match trailing newline + +### Schema + +```json +{ "type": "string", "pattern": "^abc$" } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (!(typeof data === "string")) return false + if (!(data === "abc")) return false + return true +}; +return ref0 +``` + + +## ECMA 262 regex converts \t to horizontal tab + +### Schema + +```json +{ "type": "string", "pattern": "^\\t$" } +``` + +### Code + +```js +'use strict' +const pattern0 = new RegExp("^\\t$", "u"); +const ref0 = function validate(data) { + if (!(typeof data === "string")) return false + if (!pattern0.test(data)) return false + return true +}; +return ref0 +``` + + +## ECMA 262 regex escapes control codes with \c and upper letter + +### Schema + +```json +{ "type": "string", "pattern": "^\\cC$" } +``` + +### Code + +```js +'use strict' +const pattern0 = new RegExp("^\\cC$", "u"); +const ref0 = function validate(data) { + if (!(typeof data === "string")) return false + if (!pattern0.test(data)) return false + return true +}; +return ref0 +``` + + +## ECMA 262 regex escapes control codes with \c and lower letter + +### Schema + +```json +{ "type": "string", "pattern": "^\\cc$" } +``` + +### Code + +```js +'use strict' +const pattern0 = new RegExp("^\\cc$", "u"); +const ref0 = function validate(data) { + if (!(typeof data === "string")) return false + if (!pattern0.test(data)) return false + return true +}; +return ref0 +``` + + +## ECMA 262 \d matches ascii digits only + +### Schema + +```json +{ "type": "string", "pattern": "^\\d$" } +``` + +### Code + +```js +'use strict' +const pattern0 = new RegExp("^\\d$", "u"); +const ref0 = function validate(data) { + if (!(typeof data === "string")) return false + if (!pattern0.test(data)) return false + return true +}; +return ref0 +``` + + +## ECMA 262 \D matches everything but ascii digits + +### Schema + +```json +{ "type": "string", "pattern": "^\\D$" } +``` + +### Code + +```js +'use strict' +const pattern0 = new RegExp("^\\D$", "u"); +const ref0 = function validate(data) { + if (!(typeof data === "string")) return false + if (!pattern0.test(data)) return false + return true +}; +return ref0 +``` + + +## ECMA 262 \w matches ascii letters only + +### Schema + +```json +{ "type": "string", "pattern": "^\\w$" } +``` + +### Code + +```js +'use strict' +const pattern0 = new RegExp("^\\w$", "u"); +const ref0 = function validate(data) { + if (!(typeof data === "string")) return false + if (!pattern0.test(data)) return false + return true +}; +return ref0 +``` + + +## ECMA 262 \W matches everything but ascii letters + +### Schema + +```json +{ "type": "string", "pattern": "^\\W$" } +``` + +### Code + +```js +'use strict' +const pattern0 = new RegExp("^\\W$", "u"); +const ref0 = function validate(data) { + if (!(typeof data === "string")) return false + if (!pattern0.test(data)) return false + return true +}; +return ref0 +``` + + +## ECMA 262 \s matches whitespace + +### Schema + +```json +{ "type": "string", "pattern": "^\\s$" } +``` + +### Code + +```js +'use strict' +const pattern0 = new RegExp("^\\s$", "u"); +const ref0 = function validate(data) { + if (!(typeof data === "string")) return false + if (!pattern0.test(data)) return false + return true +}; +return ref0 +``` + + +## ECMA 262 \S matches everything but whitespace + +### Schema + +```json +{ "type": "string", "pattern": "^\\S$" } +``` + +### Code + +```js +'use strict' +const pattern0 = new RegExp("^\\S$", "u"); +const ref0 = function validate(data) { + if (!(typeof data === "string")) return false + if (!pattern0.test(data)) return false + return true +}; +return ref0 +``` + + +## patterns always use unicode semantics with pattern + +### Schema + +```json +{ "pattern": "\\p{Letter}cole" } +``` + +### Code + +```js +'use strict' +const pattern0 = new RegExp("\\p{Letter}cole", "u"); +const ref0 = function validate(data) { + if (typeof data === "string") { + if (!pattern0.test(data)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `Should start with ^ and end with $: "\\p{Letter}cole" at #` + + +## \w in patterns matches [A-Za-z0-9_], not unicode letters + +### Schema + +```json +{ "pattern": "\\wcole" } +``` + +### Code + +```js +'use strict' +const pattern0 = new RegExp("\\wcole", "u"); +const ref0 = function validate(data) { + if (typeof data === "string") { + if (!pattern0.test(data)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `Should start with ^ and end with $: "\\wcole" at #` + + +## pattern with ASCII ranges + +### Schema + +```json +{ "pattern": "[a-z]cole" } +``` + +### Code + +```js +'use strict' +const pattern0 = new RegExp("[a-z]cole", "u"); +const ref0 = function validate(data) { + if (typeof data === "string") { + if (!pattern0.test(data)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `Should start with ^ and end with $: "[a-z]cole" at #` + + +## \d in pattern matches [0-9], not unicode digits + +### Schema + +```json +{ "pattern": "^\\d+$" } +``` + +### Code + +```js +'use strict' +const pattern0 = new RegExp("^\\d+$", "u"); +const ref0 = function validate(data) { + if (typeof data === "string") { + if (!pattern0.test(data)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## pattern with non-ASCII digits + +### Schema + +```json +{ "pattern": "^\\p{digit}+$" } +``` + +### Code + +```js +'use strict' +const pattern0 = new RegExp("^\\p{digit}+$", "u"); +const ref0 = function validate(data) { + if (typeof data === "string") { + if (!pattern0.test(data)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[complexityChecks] maxLength should be specified for pattern: "^\\p{digit}+$" at #` + + +## patterns always use unicode semantics with patternProperties + +### Schema + +```json +{ + "type": "object", + "patternProperties": { "\\p{Letter}cole": true }, + "additionalProperties": false +} +``` + +### Code + +```js +'use strict' +const pattern0 = new RegExp("\\p{Letter}cole", "u"); +const ref0 = function validate(data) { + if (!(typeof data === "object" && data && !Array.isArray(data))) return false + for (const key1 of Object.keys(data)) { + if (!pattern0.test(key1)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `Should start with ^ and end with $: "\\p{Letter}cole" at #` + + +## \w in patternProperties matches [A-Za-z0-9_], not unicode letters + +### Schema + +```json +{ + "type": "object", + "patternProperties": { "\\wcole": true }, + "additionalProperties": false +} +``` + +### Code + +```js +'use strict' +const pattern0 = new RegExp("\\wcole", "u"); +const ref0 = function validate(data) { + if (!(typeof data === "object" && data && !Array.isArray(data))) return false + for (const key1 of Object.keys(data)) { + if (!pattern0.test(key1)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `Should start with ^ and end with $: "\\wcole" at #` + + +## patternProperties with ASCII ranges + +### Schema + +```json +{ + "type": "object", + "patternProperties": { "[a-z]cole": true }, + "additionalProperties": false +} +``` + +### Code + +```js +'use strict' +const pattern0 = new RegExp("[a-z]cole", "u"); +const ref0 = function validate(data) { + if (!(typeof data === "object" && data && !Array.isArray(data))) return false + for (const key1 of Object.keys(data)) { + if (!pattern0.test(key1)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `Should start with ^ and end with $: "[a-z]cole" at #` + + +## \d in patternProperties matches [0-9], not unicode digits + +### Schema + +```json +{ + "type": "object", + "patternProperties": { "^\\d+$": true }, + "additionalProperties": false +} +``` + +### Code + +```js +'use strict' +const pattern0 = new RegExp("^\\d+$", "u"); +const ref0 = function validate(data) { + if (!(typeof data === "object" && data && !Array.isArray(data))) return false + for (const key1 of Object.keys(data)) { + if (!pattern0.test(key1)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] schema = true is not allowed at #/patternProperties/^\d+$` + + +## patternProperties with non-ASCII digits + +### Schema + +```json +{ + "type": "object", + "patternProperties": { "^\\p{digit}+$": true }, + "additionalProperties": false +} +``` + +### Code + +```js +'use strict' +const pattern0 = new RegExp("^\\p{digit}+$", "u"); +const ref0 = function validate(data) { + if (!(typeof data === "object" && data && !Array.isArray(data))) return false + for (const key1 of Object.keys(data)) { + if (!pattern0.test(key1)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[complexityChecks] maxLength should be specified for pattern: "^\\p{digit}+$" at #` + diff --git a/doc/samples/draft6/optional-float-overflow.md b/doc/samples/draft6/optional-float-overflow.md new file mode 100644 index 0000000..313af9c --- /dev/null +++ b/doc/samples/draft6/optional-float-overflow.md @@ -0,0 +1,22 @@ +# optional/float-overflow + +## all integers are multiples of 0.5, if overflow is handled + +### Schema + +```json +{ "type": "integer", "multipleOf": 0.5 } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (!Number.isInteger(data)) return false + if (data % 0.5 !== 0) return false + return true +}; +return ref0 +``` + diff --git a/doc/samples/draft6/optional-non-bmp-regex.md b/doc/samples/draft6/optional-non-bmp-regex.md new file mode 100644 index 0000000..8d300cd --- /dev/null +++ b/doc/samples/draft6/optional-non-bmp-regex.md @@ -0,0 +1,59 @@ +# optional/non-bmp-regex + +## Proper UTF-16 surrogate pair handling: pattern + +### Schema + +```json +{ "pattern": "^🐲*$" } +``` + +### Code + +```js +'use strict' +const pattern0 = new RegExp("^🐲*$", "u"); +const ref0 = function validate(data) { + if (typeof data === "string") { + if (!pattern0.test(data)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## Proper UTF-16 surrogate pair handling: patternProperties + +### Schema + +```json +{ "patternProperties": { "^🐲*$": { "type": "integer" } } } +``` + +### Code + +```js +'use strict' +const pattern0 = new RegExp("^🐲*$", "u"); +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + for (const key0 of Object.keys(data)) { + if (pattern0.test(key0)) { + if (!(Number.isInteger(data[key0]))) return false + } + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + diff --git a/doc/samples/draft6/pattern.md b/doc/samples/draft6/pattern.md new file mode 100644 index 0000000..07714d8 --- /dev/null +++ b/doc/samples/draft6/pattern.md @@ -0,0 +1,54 @@ +# pattern + +## pattern validation + +### Schema + +```json +{ "pattern": "^a*$" } +``` + +### Code + +```js +'use strict' +const pattern0 = new RegExp("^a*$", "u"); +const ref0 = function validate(data) { + if (typeof data === "string") { + if (!pattern0.test(data)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## pattern is not anchored + +### Schema + +```json +{ "pattern": "a+" } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (typeof data === "string") { + if (!(data.includes("a"))) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `Should start with ^ and end with $: "a+" at #` + diff --git a/doc/samples/draft6/patternProperties.md b/doc/samples/draft6/patternProperties.md new file mode 100644 index 0000000..ebc285b --- /dev/null +++ b/doc/samples/draft6/patternProperties.md @@ -0,0 +1,168 @@ +# patternProperties + +## patternProperties validates properties matching a regex + +### Schema + +```json +{ "patternProperties": { "f.*o": { "type": "integer" } } } +``` + +### Code + +```js +'use strict' +const pattern0 = new RegExp("f.*o", "u"); +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + for (const key0 of Object.keys(data)) { + if (pattern0.test(key0)) { + if (!(Number.isInteger(data[key0]))) return false + } + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `Should start with ^ and end with $: "f.*o" at #` + + +## multiple simultaneous patternProperties are validated + +### Schema + +```json +{ + "patternProperties": { + "a*": { "type": "integer" }, + "aaa*": { "maximum": 20 } + } +} +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + for (const key0 of Object.keys(data)) { + if (!(Number.isInteger(data[key0]))) return false + if (key0.includes("aa")) { + if (typeof data[key0] === "number") { + if (!(20 >= data[key0])) return false + } + } + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `Should start with ^ and end with $: "a*" at #` + + +## regexes are not anchored by default and are case sensitive + +### Schema + +```json +{ + "patternProperties": { + "[0-9]{2,}": { "type": "boolean" }, + "X_": { "type": "string" } + } +} +``` + +### Code + +```js +'use strict' +const pattern0 = new RegExp("[0-9]{2,}", "u"); +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + for (const key0 of Object.keys(data)) { + if (pattern0.test(key0)) { + if (!(typeof data[key0] === "boolean")) return false + } + if (key0.includes("X_")) { + if (!(typeof data[key0] === "string")) return false + } + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `Should start with ^ and end with $: "[0-9]{2,}" at #` + + +## patternProperties with boolean schemas + +### Schema + +```json +{ "patternProperties": { "f.*": true, "b.*": false } } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + for (const key0 of Object.keys(data)) { + if (key0.includes("b")) return false + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `Should start with ^ and end with $: "f.*" at #` + + +## patternProperties with null valued instance properties + +### Schema + +```json +{ "patternProperties": { "^.*bar$": { "type": "null" } } } +``` + +### Code + +```js +'use strict' +const pattern0 = new RegExp("^.*bar$", "u"); +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + for (const key0 of Object.keys(data)) { + if (pattern0.test(key0)) { + if (!(data[key0] === null)) return false + } + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + diff --git a/doc/samples/draft6/properties.md b/doc/samples/draft6/properties.md new file mode 100644 index 0000000..3100ea9 --- /dev/null +++ b/doc/samples/draft6/properties.md @@ -0,0 +1,240 @@ +# properties + +## object properties validation + +### Schema + +```json +{ "properties": { "foo": { "type": "integer" }, "bar": { "type": "string" } } } +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.foo !== undefined && hasOwn(data, "foo")) { + if (!Number.isInteger(data.foo)) return false + } + if (data.bar !== undefined && hasOwn(data, "bar")) { + if (!(typeof data.bar === "string")) return false + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireStringValidation] pattern, format or contentSchema should be specified for strings, use pattern: ^[\s\S]*$ to opt-out at #/properties/bar` + + +## properties, patternProperties, additionalProperties interaction + +### Schema + +```json +{ + "properties": { + "foo": { "type": "array", "maxItems": 3 }, + "bar": { "type": "array" } + }, + "patternProperties": { "f.o": { "minItems": 2 } }, + "additionalProperties": { "type": "integer" } +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const pattern0 = new RegExp("f.o", "u"); +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.foo !== undefined && hasOwn(data, "foo")) { + if (!Array.isArray(data.foo)) return false + if (data.foo.length > 3) return false + } + if (data.bar !== undefined && hasOwn(data, "bar")) { + if (!Array.isArray(data.bar)) return false + } + for (const key0 of Object.keys(data)) { + if (pattern0.test(key0)) { + if (Array.isArray(data[key0])) { + if (data[key0].length < 2) return false + } + } + } + for (const key1 of Object.keys(data)) { + if (key1 !== "foo" && key1 !== "bar" && !pattern0.test(key1)) { + if (!(Number.isInteger(data[key1]))) return false + } + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] items rule should be specified at #/properties/foo` + + +## properties with boolean schema + +### Schema + +```json +{ "properties": { "foo": true, "bar": false } } +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.bar !== undefined && hasOwn(data, "bar")) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] schema = true is not allowed at #/properties/foo` + + +## properties with escaped characters + +### Schema + +```json +{ + "properties": { + "foo\nbar": { "type": "number" }, + "foo\"bar": { "type": "number" }, + "foo\\bar": { "type": "number" }, + "foo\rbar": { "type": "number" }, + "foo\tbar": { "type": "number" }, + "foo\fbar": { "type": "number" } + } +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data["foo\nbar"] !== undefined && hasOwn(data, "foo\nbar")) { + if (!(typeof data["foo\nbar"] === "number")) return false + } + if (data["foo\"bar"] !== undefined && hasOwn(data, "foo\"bar")) { + if (!(typeof data["foo\"bar"] === "number")) return false + } + if (data["foo\\bar"] !== undefined && hasOwn(data, "foo\\bar")) { + if (!(typeof data["foo\\bar"] === "number")) return false + } + if (data["foo\rbar"] !== undefined && hasOwn(data, "foo\rbar")) { + if (!(typeof data["foo\rbar"] === "number")) return false + } + if (data["foo\tbar"] !== undefined && hasOwn(data, "foo\tbar")) { + if (!(typeof data["foo\tbar"] === "number")) return false + } + if (data["foo\fbar"] !== undefined && hasOwn(data, "foo\fbar")) { + if (!(typeof data["foo\fbar"] === "number")) return false + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## properties with null valued instance properties + +### Schema + +```json +{ "properties": { "foo": { "type": "null" } } } +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.foo !== undefined && hasOwn(data, "foo")) { + if (!(data.foo === null)) return false + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## properties whose names are Javascript object property names + +### Schema + +```json +{ + "properties": { + "__proto__": { "type": "number" }, + "toString": { "properties": { "length": { "type": "string" } } }, + "constructor": { "type": "number" } + } +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data["__proto__"] !== undefined && hasOwn(data, "__proto__")) { + if (!(typeof data["__proto__"] === "number")) return false + } + if (data.toString !== undefined && hasOwn(data, "toString")) { + if (typeof data.toString === "object" && data.toString && !Array.isArray(data.toString)) { + if (data.toString.length !== undefined && hasOwn(data.toString, "length")) { + if (!(typeof data.toString.length === "string")) return false + } + } + } + if (data.constructor !== undefined && hasOwn(data, "constructor")) { + if (!(typeof data.constructor === "number")) return false + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireStringValidation] pattern, format or contentSchema should be specified for strings, use pattern: ^[\s\S]*$ to opt-out at #/properties/toString/properties/length` + diff --git a/doc/samples/draft6/propertyNames.md b/doc/samples/draft6/propertyNames.md new file mode 100644 index 0000000..48fec27 --- /dev/null +++ b/doc/samples/draft6/propertyNames.md @@ -0,0 +1,109 @@ +# propertyNames + +## propertyNames validation + +### Schema + +```json +{ "propertyNames": { "maxLength": 3 } } +``` + +### Code + +```js +'use strict' +const stringLength = (string) => + /[\uD800-\uDFFF]/.test(string) ? [...string].length : string.length; +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + for (const key0 of Object.keys(data)) { + if (key0.length > 3 && stringLength(key0) > 3) return false + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireStringValidation] pattern, format or contentSchema should be specified for strings, use pattern: ^[\s\S]*$ to opt-out at #/propertyNames` + + +## propertyNames validation with pattern + +### Schema + +```json +{ "propertyNames": { "pattern": "^a+$" } } +``` + +### Code + +```js +'use strict' +const pattern0 = new RegExp("^a+$", "u"); +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + for (const key0 of Object.keys(data)) { + if (!pattern0.test(key0)) return false + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## propertyNames with boolean schema true + +### Schema + +```json +{ "propertyNames": true } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] schema = true is not allowed at #/propertyNames` + + +## propertyNames with boolean schema false + +### Schema + +```json +{ "propertyNames": false } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + for (const key0 of Object.keys(data)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + diff --git a/doc/samples/draft6/ref.md b/doc/samples/draft6/ref.md new file mode 100644 index 0000000..2587076 --- /dev/null +++ b/doc/samples/draft6/ref.md @@ -0,0 +1,1256 @@ +# ref + +## root pointer ref + +### Schema + +```json +{ "properties": { "foo": { "$ref": "#" } }, "additionalProperties": false } +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.foo !== undefined && hasOwn(data, "foo")) { + if (!validate(data.foo)) return false + } + for (const key0 of Object.keys(data)) { + if (key0 !== "foo") return false + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #/properties/foo` + + +## relative pointer ref to object + +### Schema + +```json +{ + "properties": { + "foo": { "type": "integer" }, + "bar": { "$ref": "#/properties/foo" } + } +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref1 = function validate(data) { + if (!Number.isInteger(data)) return false + return true +}; +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.foo !== undefined && hasOwn(data, "foo")) { + if (!Number.isInteger(data.foo)) return false + } + if (data.bar !== undefined && hasOwn(data, "bar")) { + if (!ref1(data.bar)) return false + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## relative pointer ref to array + +### Schema + +```json +{ "items": [{ "type": "integer" }, { "$ref": "#/items/0" }] } +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref1 = function validate(data) { + if (!Number.isInteger(data)) return false + return true +}; +const ref0 = function validate(data) { + if (Array.isArray(data)) { + if (data[0] !== undefined && hasOwn(data, 0)) { + if (!(Number.isInteger(data[0]))) return false + } + if (data[1] !== undefined && hasOwn(data, 1)) { + if (!ref1(data[1])) return false + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## escaped pointer ref + +### Schema + +```json +{ + "definitions": { + "tilde~field": { "type": "integer" }, + "slash/field": { "type": "integer" }, + "percent%field": { "type": "integer" } + }, + "properties": { + "tilde": { "$ref": "#/definitions/tilde~0field" }, + "slash": { "$ref": "#/definitions/slash~1field" }, + "percent": { "$ref": "#/definitions/percent%25field" } + } +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref1 = function validate(data) { + if (!Number.isInteger(data)) return false + return true +}; +const ref2 = function validate(data) { + if (!Number.isInteger(data)) return false + return true +}; +const ref3 = function validate(data) { + if (!Number.isInteger(data)) return false + return true +}; +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.tilde !== undefined && hasOwn(data, "tilde")) { + if (!ref1(data.tilde)) return false + } + if (data.slash !== undefined && hasOwn(data, "slash")) { + if (!ref2(data.slash)) return false + } + if (data.percent !== undefined && hasOwn(data, "percent")) { + if (!ref3(data.percent)) return false + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## nested refs + +### Schema + +```json +{ + "definitions": { + "a": { "type": "integer" }, + "b": { "$ref": "#/definitions/a" }, + "c": { "$ref": "#/definitions/b" } + }, + "allOf": [{ "$ref": "#/definitions/c" }] +} +``` + +### Code + +```js +'use strict' +const ref3 = function validate(data) { + if (!Number.isInteger(data)) return false + return true +}; +const ref2 = function validate(data) { + if (!ref3(data)) return false + return true +}; +const ref1 = function validate(data) { + if (!ref2(data)) return false + return true +}; +const ref0 = function validate(data) { + if (!ref1(data)) return false + return true +}; +return ref0 +``` + + +## ref overrides any sibling keywords + +### Schema + +```json +{ + "definitions": { "reffed": { "type": "array" } }, + "properties": { "foo": { "$ref": "#/definitions/reffed", "maxItems": 2 } } +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref1 = function validate(data) { + if (!Array.isArray(data)) return false + return true +}; +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.foo !== undefined && hasOwn(data, "foo")) { + if (!ref1(data.foo)) return false + } + } + return true +}; +return ref0 +``` + +### Warnings + + * `Unprocessed keywords: ["maxItems"] at #/properties/foo` + + +## $ref prevents a sibling $id from changing the base uri + +### Schema + +```json +{ + "$id": "http://localhost:1234/sibling_id/base/", + "definitions": { + "foo": { + "$id": "http://localhost:1234/sibling_id/foo.json", + "type": "string" + }, + "base_foo": { + "$comment": "this canonical uri is http://localhost:1234/sibling_id/base/foo.json", + "$id": "foo.json", + "type": "number" + } + }, + "allOf": [ + { + "$comment": "$ref resolves to http://localhost:1234/sibling_id/base/foo.json, not http://localhost:1234/sibling_id/foo.json", + "$id": "http://localhost:1234/sibling_id/", + "$ref": "foo.json" + } + ] +} +``` + +### Code + +```js +'use strict' +const ref1 = function validate(data) { + if (!(typeof data === "number")) return false + return true +}; +const ref0 = function validate(data) { + if (!ref1(data)) return false + return true +}; +return ref0 +``` + +### Warnings + + * `Unprocessed keywords: ["$id"] at #/allOf/0` + + +## remote ref, containing refs itself + +### Schema + +```json +{ "$ref": "http://json-schema.org/draft-06/schema#" } +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const format0 = new RegExp("^(?:[a-z][a-z0-9+\\-.]*:)?(?:\\/?\\/(?:(?:[a-z0-9\\-._~!$&'()*+,;=:]|%[0-9a-f]{2})*@)?(?:\\[(?:(?:(?:(?:[0-9a-f]{1,4}:){6}|::(?:[0-9a-f]{1,4}:){5}|(?:[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){4}|(?:(?:[0-9a-f]{1,4}:){0,1}[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){3}|(?:(?:[0-9a-f]{1,4}:){0,2}[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){2}|(?:(?:[0-9a-f]{1,4}:){0,3}[0-9a-f]{1,4})?::[0-9a-f]{1,4}:|(?:(?:[0-9a-f]{1,4}:){0,4}[0-9a-f]{1,4})?::)(?:[0-9a-f]{1,4}:[0-9a-f]{1,4}|(?:(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d\\d?)\\.){3}(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d\\d?))|(?:(?:[0-9a-f]{1,4}:){0,5}[0-9a-f]{1,4})?::[0-9a-f]{1,4}|(?:(?:[0-9a-f]{1,4}:){0,6}[0-9a-f]{1,4})?::)|v[0-9a-f]+\\.[a-z0-9\\-._~!$&'()*+,;=:]+)\\]|(?:(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d\\d?)\\.){3}(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d\\d?)|(?:[a-z0-9\\-._~!$&'()*+,;=]|%[0-9a-f]{2})*)(?::\\d*)?(?:\\/(?:[a-z0-9\\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})*)*|\\/?(?:(?:[a-z0-9\\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})+(?:\\/(?:[a-z0-9\\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})*)*)?)?(?:\\?(?:[a-z0-9\\-._~!$&'()*+,;=:@/?]|%[0-9a-f]{2})*)?(?:#(?:[a-z0-9\\-._~!$&'()*+,;=:@/?]|%[0-9a-f]{2})*)?$", "i"); +const format1 = new RegExp("^[a-z][a-z0-9+\\-.]*:(?:\\/?\\/(?:(?:[a-z0-9\\-._~!$&'()*+,;=:]|%[0-9a-f]{2})*@)?(?:\\[(?:(?:(?:(?:[0-9a-f]{1,4}:){6}|::(?:[0-9a-f]{1,4}:){5}|(?:[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){4}|(?:(?:[0-9a-f]{1,4}:){0,1}[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){3}|(?:(?:[0-9a-f]{1,4}:){0,2}[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){2}|(?:(?:[0-9a-f]{1,4}:){0,3}[0-9a-f]{1,4})?::[0-9a-f]{1,4}:|(?:(?:[0-9a-f]{1,4}:){0,4}[0-9a-f]{1,4})?::)(?:[0-9a-f]{1,4}:[0-9a-f]{1,4}|(?:(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d\\d?)\\.){3}(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d\\d?))|(?:(?:[0-9a-f]{1,4}:){0,5}[0-9a-f]{1,4})?::[0-9a-f]{1,4}|(?:(?:[0-9a-f]{1,4}:){0,6}[0-9a-f]{1,4})?::)|v[0-9a-f]+\\.[a-z0-9\\-._~!$&'()*+,;=:]+)\\]|(?:(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d\\d?)\\.){3}(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d\\d?)|(?:[a-z0-9\\-._~!$&'()*+,;=]|%[0-9a-f]{2})*)(?::\\d*)?(?:\\/(?:[a-z0-9\\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})*)*|\\/?(?:(?:[a-z0-9\\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})+(?:\\/(?:[a-z0-9\\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})*)*)?)(?:\\?(?:[a-z0-9\\-._~!$&'()*+,;=:@/?]|%[0-9a-f]{2})*)?(?:#(?:[a-z0-9\\-._~!$&'()*+,;=:@/?]|%[0-9a-f]{2})*)?$", "i"); +const ref2 = function validate(data) { + if (!Number.isInteger(data)) return false + if (!(0 <= data)) return false + return true +}; +const ref3 = function validate(data) { + if (!ref2(data)) return false + return true +}; +const format2 = (str) => { + if (str.length > 1e5) return false + const Z_ANCHOR = /[^\\]\\Z/ + if (Z_ANCHOR.test(str)) return false + try { + new RegExp(str, 'u') + return true + } catch (e) { + return false + } + }; +const ref4 = function validate(data) { + if (!Array.isArray(data)) return false + if (data.length < 1) return false + for (let j = 0; j < data.length; j++) { + if (data[j] !== undefined && hasOwn(data, j)) { + if (!ref1(data[j])) return false + } + } + return true +}; +const unique = (array) => { + if (array.length < 2) return true + if (array.length === 2) return !deepEqual(array[0], array[1]) + const objects = [] + const primitives = array.length > 20 ? new Set() : null + let primitivesCount = 0 + let pos = 0 + for (const item of array) { + if (typeof item === 'object') { + objects.push(item) + } else if (primitives) { + primitives.add(item) + if (primitives.size !== ++primitivesCount) return false + } else { + if (array.indexOf(item, pos + 1) !== -1) return false + } + pos++ + } + for (let i = 1; i < objects.length; i++) + for (let j = 0; j < i; j++) if (deepEqual(objects[i], objects[j])) return false + return true +}; +const deepEqual = (obj, obj2) => { + if (obj === obj2) return true + if (!obj || !obj2 || typeof obj !== typeof obj2) return false + if (obj !== obj2 && typeof obj !== 'object') return false + + const proto = Object.getPrototypeOf(obj) + if (proto !== Object.getPrototypeOf(obj2)) return false + + if (proto === Array.prototype) { + if (!Array.isArray(obj) || !Array.isArray(obj2)) return false + if (obj.length !== obj2.length) return false + return obj.every((x, i) => deepEqual(x, obj2[i])) + } else if (proto === Object.prototype) { + const [keys, keys2] = [Object.keys(obj), Object.keys(obj2)] + if (keys.length !== keys2.length) return false + const keyset2 = new Set([...keys, ...keys2]) + return keyset2.size === keys.length && keys.every((key) => deepEqual(obj[key], obj2[key])) + } + return false +}; +const ref5 = function validate(data) { + if (!Array.isArray(data)) return false + for (let k = 0; k < data.length; k++) { + if (data[k] !== undefined && hasOwn(data, k)) { + if (!(typeof data[k] === "string")) return false + } + } + if (!unique(data)) return false + return true +}; +const ref6 = function validate(data) { + if (!(data === "array" || data === "boolean" || data === "integer" || data === "null" || data === "number" || data === "object" || data === "string")) return false + return true +}; +const ref1 = function validate(data) { + if (!(typeof data === "object" && data && !Array.isArray(data) || typeof data === "boolean")) return false + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data["$id"] !== undefined && hasOwn(data, "$id")) { + if (!(typeof data["$id"] === "string")) return false + if (!format0.test(data["$id"])) return false + } + if (data["$schema"] !== undefined && hasOwn(data, "$schema")) { + if (!(typeof data["$schema"] === "string")) return false + if (!format1.test(data["$schema"])) return false + } + if (data["$ref"] !== undefined && hasOwn(data, "$ref")) { + if (!(typeof data["$ref"] === "string")) return false + if (!format0.test(data["$ref"])) return false + } + if (data.title !== undefined && hasOwn(data, "title")) { + if (!(typeof data.title === "string")) return false + } + if (data.description !== undefined && hasOwn(data, "description")) { + if (!(typeof data.description === "string")) return false + } + if (data.examples !== undefined && hasOwn(data, "examples")) { + if (!Array.isArray(data.examples)) return false + } + if (data.multipleOf !== undefined && hasOwn(data, "multipleOf")) { + if (!(typeof data.multipleOf === "number")) return false + if (!(0 < data.multipleOf)) return false + } + if (data.maximum !== undefined && hasOwn(data, "maximum")) { + if (!(typeof data.maximum === "number")) return false + } + if (data.exclusiveMaximum !== undefined && hasOwn(data, "exclusiveMaximum")) { + if (!(typeof data.exclusiveMaximum === "number")) return false + } + if (data.minimum !== undefined && hasOwn(data, "minimum")) { + if (!(typeof data.minimum === "number")) return false + } + if (data.exclusiveMinimum !== undefined && hasOwn(data, "exclusiveMinimum")) { + if (!(typeof data.exclusiveMinimum === "number")) return false + } + if (data.maxLength !== undefined && hasOwn(data, "maxLength")) { + if (!ref2(data.maxLength)) return false + } + if (data.minLength !== undefined && hasOwn(data, "minLength")) { + if (!ref3(data.minLength)) return false + } + if (data.pattern !== undefined && hasOwn(data, "pattern")) { + if (!(typeof data.pattern === "string")) return false + if (!format2(data.pattern)) return false + } + if (data.additionalItems !== undefined && hasOwn(data, "additionalItems")) { + if (!validate(data.additionalItems)) return false + } + if (data.items !== undefined && hasOwn(data, "items")) { + const sub0 = (() => { + if (!validate(data.items)) return false + return true + })() + if (!sub0) { + const sub1 = (() => { + if (!ref4(data.items)) return false + return true + })() + if (!sub1) return false + } + } + if (data.maxItems !== undefined && hasOwn(data, "maxItems")) { + if (!ref2(data.maxItems)) return false + } + if (data.minItems !== undefined && hasOwn(data, "minItems")) { + if (!ref3(data.minItems)) return false + } + if (data.uniqueItems !== undefined && hasOwn(data, "uniqueItems")) { + if (!(typeof data.uniqueItems === "boolean")) return false + } + if (data.contains !== undefined && hasOwn(data, "contains")) { + if (!validate(data.contains)) return false + } + if (data.maxProperties !== undefined && hasOwn(data, "maxProperties")) { + if (!ref2(data.maxProperties)) return false + } + if (data.minProperties !== undefined && hasOwn(data, "minProperties")) { + if (!ref3(data.minProperties)) return false + } + if (data.required !== undefined && hasOwn(data, "required")) { + if (!ref5(data.required)) return false + } + if (data.additionalProperties !== undefined && hasOwn(data, "additionalProperties")) { + if (!validate(data.additionalProperties)) return false + } + if (data.definitions !== undefined && hasOwn(data, "definitions")) { + if (!(typeof data.definitions === "object" && data.definitions && !Array.isArray(data.definitions))) return false + for (const key0 of Object.keys(data.definitions)) { + if (!validate(data.definitions[key0])) return false + } + } + if (data.properties !== undefined && hasOwn(data, "properties")) { + if (!(typeof data.properties === "object" && data.properties && !Array.isArray(data.properties))) return false + for (const key1 of Object.keys(data.properties)) { + if (!validate(data.properties[key1])) return false + } + } + if (data.patternProperties !== undefined && hasOwn(data, "patternProperties")) { + if (!(typeof data.patternProperties === "object" && data.patternProperties && !Array.isArray(data.patternProperties))) return false + for (const key2 of Object.keys(data.patternProperties)) { + if (!validate(data.patternProperties[key2])) return false + } + } + if (data.dependencies !== undefined && hasOwn(data, "dependencies")) { + if (!(typeof data.dependencies === "object" && data.dependencies && !Array.isArray(data.dependencies))) return false + for (const key3 of Object.keys(data.dependencies)) { + const sub2 = (() => { + if (!validate(data.dependencies[key3])) return false + return true + })() + if (!sub2) { + const sub3 = (() => { + if (!ref5(data.dependencies[key3])) return false + return true + })() + if (!sub3) return false + } + } + } + if (data.propertyNames !== undefined && hasOwn(data, "propertyNames")) { + if (!validate(data.propertyNames)) return false + } + if (data.enum !== undefined && hasOwn(data, "enum")) { + if (!Array.isArray(data.enum)) return false + if (data.enum.length < 1) return false + if (!unique(data.enum)) return false + } + if (data.type !== undefined && hasOwn(data, "type")) { + const sub4 = (() => { + if (!ref6(data.type)) return false + return true + })() + if (!sub4) { + const sub5 = (() => { + if (!Array.isArray(data.type)) return false + if (data.type.length < 1) return false + for (let l = 0; l < data.type.length; l++) { + if (data.type[l] !== undefined && hasOwn(data.type, l)) { + if (!ref6(data.type[l])) return false + } + } + if (!unique(data.type)) return false + return true + })() + if (!sub5) return false + } + } + if (data.format !== undefined && hasOwn(data, "format")) { + if (!(typeof data.format === "string")) return false + } + if (data.allOf !== undefined && hasOwn(data, "allOf")) { + if (!ref4(data.allOf)) return false + } + if (data.anyOf !== undefined && hasOwn(data, "anyOf")) { + if (!ref4(data.anyOf)) return false + } + if (data.oneOf !== undefined && hasOwn(data, "oneOf")) { + if (!ref4(data.oneOf)) return false + } + if (data.not !== undefined && hasOwn(data, "not")) { + if (!validate(data.not)) return false + } + } + return true +}; +const ref0 = function validate(data) { + if (!ref1(data)) return false + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireStringValidation] pattern, format or contentSchema should be specified for strings, use pattern: ^[\s\S]*$ to opt-out at http://json-schema.org/draft-06/schema#/properties/title` + + +## property named $ref that is not a reference + +### Schema + +```json +{ "properties": { "$ref": { "type": "string" } } } +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data["$ref"] !== undefined && hasOwn(data, "$ref")) { + if (!(typeof data["$ref"] === "string")) return false + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireStringValidation] pattern, format or contentSchema should be specified for strings, use pattern: ^[\s\S]*$ to opt-out at #/properties/$ref` + + +## property named $ref, containing an actual $ref + +### Schema + +```json +{ + "properties": { "$ref": { "$ref": "#/definitions/is-string" } }, + "definitions": { "is-string": { "type": "string" } } +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref1 = function validate(data) { + if (!(typeof data === "string")) return false + return true +}; +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data["$ref"] !== undefined && hasOwn(data, "$ref")) { + if (!ref1(data["$ref"])) return false + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireStringValidation] pattern, format or contentSchema should be specified for strings, use pattern: ^[\s\S]*$ to opt-out at #` + + +## $ref to boolean schema true + +### Schema + +```json +{ "allOf": [{ "$ref": "#/definitions/bool" }], "definitions": { "bool": true } } +``` + +### Code + +```js +'use strict' +const ref1 = function validate(data) { + return true +}; +const ref0 = function validate(data) { + if (!ref1(data)) return false + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] schema = true is not allowed at #` + + +## $ref to boolean schema false + +### Schema + +```json +{ + "allOf": [{ "$ref": "#/definitions/bool" }], + "definitions": { "bool": false } +} +``` + +### Code + +```js +'use strict' +const ref1 = function validate(data) { + return false + return true +}; +const ref0 = function validate(data) { + if (!ref1(data)) return false + return true +}; +return ref0 +``` + + +## Recursive references between schemas + +### Schema + +```json +{ + "$id": "http://localhost:1234/tree", + "description": "tree of nodes", + "type": "object", + "properties": { + "meta": { "type": "string" }, + "nodes": { "type": "array", "items": { "$ref": "node" } } + }, + "required": ["meta", "nodes"], + "definitions": { + "node": { + "$id": "http://localhost:1234/node", + "description": "node", + "type": "object", + "properties": { + "value": { "type": "number" }, + "subtree": { "$ref": "tree" } + }, + "required": ["value"] + } + } +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref1 = function validate(data) { + if (!(typeof data === "object" && data && !Array.isArray(data))) return false + if (!(data.value !== undefined && hasOwn(data, "value"))) return false + if (!(typeof data.value === "number")) return false + if (data.subtree !== undefined && hasOwn(data, "subtree")) { + if (!ref0(data.subtree)) return false + } + return true +}; +const ref0 = function validate(data) { + if (!(typeof data === "object" && data && !Array.isArray(data))) return false + if (!(data.meta !== undefined && hasOwn(data, "meta"))) return false + if (!(data.nodes !== undefined && hasOwn(data, "nodes"))) return false + if (!(typeof data.meta === "string")) return false + if (!Array.isArray(data.nodes)) return false + for (let i = 0; i < data.nodes.length; i++) { + if (data.nodes[i] !== undefined && hasOwn(data.nodes, i)) { + if (!ref1(data.nodes[i])) return false + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireStringValidation] pattern, format or contentSchema should be specified for strings, use pattern: ^[\s\S]*$ to opt-out at #/properties/meta` + + +## refs with quote + +### Schema + +```json +{ + "properties": { "foo\"bar": { "$ref": "#/definitions/foo%22bar" } }, + "definitions": { "foo\"bar": { "type": "number" } } +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref1 = function validate(data) { + if (!(typeof data === "number")) return false + return true +}; +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data["foo\"bar"] !== undefined && hasOwn(data, "foo\"bar")) { + if (!ref1(data["foo\"bar"])) return false + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## Location-independent identifier + +### Schema + +```json +{ + "allOf": [{ "$ref": "#foo" }], + "definitions": { "A": { "$id": "#foo", "type": "integer" } } +} +``` + +### Code + +```js +'use strict' +const ref1 = function validate(data) { + if (!Number.isInteger(data)) return false + return true +}; +const ref0 = function validate(data) { + if (!ref1(data)) return false + return true +}; +return ref0 +``` + + +## Location-independent identifier with base URI change in subschema + +### Schema + +```json +{ + "$id": "http://localhost:1234/root", + "allOf": [{ "$ref": "http://localhost:1234/nested.json#foo" }], + "definitions": { + "A": { + "$id": "nested.json", + "definitions": { "B": { "$id": "#foo", "type": "integer" } } + } + } +} +``` + +### Code + +```js +'use strict' +const ref1 = function validate(data) { + if (!Number.isInteger(data)) return false + return true +}; +const ref0 = function validate(data) { + if (!ref1(data)) return false + return true +}; +return ref0 +``` + + +## naive replacement of $ref with its destination is not correct + +### Schema + +```json +{ + "definitions": { "a_string": { "type": "string" } }, + "enum": [{ "$ref": "#/definitions/a_string" }] +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (!(typeof data === "object" && data && !Array.isArray(data) && Object.keys(data).length === 1 && hasOwn(data, "$ref") && data["$ref"] === "#/definitions/a_string")) return false + return true +}; +return ref0 +``` + + +## refs with relative uris and defs + +### Schema + +```json +{ + "$id": "http://example.com/schema-relative-uri-defs1.json", + "properties": { + "foo": { + "$id": "schema-relative-uri-defs2.json", + "definitions": { + "inner": { "properties": { "bar": { "type": "string" } } } + }, + "allOf": [{ "$ref": "#/definitions/inner" }] + } + }, + "allOf": [{ "$ref": "schema-relative-uri-defs2.json" }] +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref1 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.bar !== undefined && hasOwn(data, "bar")) { + if (!(typeof data.bar === "string")) return false + } + } + return true +}; +const ref2 = function validate(data) { + if (!ref1(data)) return false + return true +}; +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.foo !== undefined && hasOwn(data, "foo")) { + if (!ref1(data.foo)) return false + } + } + if (!ref2(data)) return false + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireStringValidation] pattern, format or contentSchema should be specified for strings, use pattern: ^[\s\S]*$ to opt-out at http://example.com/schema-relative-uri-defs2.json#/properties/bar` + + +## relative refs with absolute uris and defs + +### Schema + +```json +{ + "$id": "http://example.com/schema-refs-absolute-uris-defs1.json", + "properties": { + "foo": { + "$id": "http://example.com/schema-refs-absolute-uris-defs2.json", + "definitions": { + "inner": { "properties": { "bar": { "type": "string" } } } + }, + "allOf": [{ "$ref": "#/definitions/inner" }] + } + }, + "allOf": [{ "$ref": "schema-refs-absolute-uris-defs2.json" }] +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref1 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.bar !== undefined && hasOwn(data, "bar")) { + if (!(typeof data.bar === "string")) return false + } + } + return true +}; +const ref2 = function validate(data) { + if (!ref1(data)) return false + return true +}; +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.foo !== undefined && hasOwn(data, "foo")) { + if (!ref1(data.foo)) return false + } + } + if (!ref2(data)) return false + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireStringValidation] pattern, format or contentSchema should be specified for strings, use pattern: ^[\s\S]*$ to opt-out at http://example.com/schema-refs-absolute-uris-defs2.json#/properties/bar` + + +## simple URN base URI with $ref via the URN + +### Schema + +```json +{ + "$comment": "URIs do not have to have HTTP(s) schemes", + "$id": "urn:uuid:deadbeef-1234-ffff-ffff-4321feebdaed", + "minimum": 30, + "properties": { + "foo": { "$ref": "urn:uuid:deadbeef-1234-ffff-ffff-4321feebdaed" } + } +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (typeof data === "number") { + if (!(30 <= data)) return false + } + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.foo !== undefined && hasOwn(data, "foo")) { + if (!validate(data.foo)) return false + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #/properties/foo` + + +## simple URN base URI with JSON pointer + +### Schema + +```json +{ + "$comment": "URIs do not have to have HTTP(s) schemes", + "$id": "urn:uuid:deadbeef-1234-00ff-ff00-4321feebdaed", + "properties": { "foo": { "$ref": "#/definitions/bar" } }, + "definitions": { "bar": { "type": "string" } } +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref1 = function validate(data) { + if (!(typeof data === "string")) return false + return true +}; +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.foo !== undefined && hasOwn(data, "foo")) { + if (!ref1(data.foo)) return false + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireStringValidation] pattern, format or contentSchema should be specified for strings, use pattern: ^[\s\S]*$ to opt-out at urn:uuid:deadbeef-1234-00ff-ff00-4321feebdaed#` + + +## URN base URI with NSS + +### Schema + +```json +{ + "$comment": "RFC 8141 §2.2", + "$id": "urn:example:1/406/47452/2", + "properties": { "foo": { "$ref": "#/definitions/bar" } }, + "definitions": { "bar": { "type": "string" } } +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref1 = function validate(data) { + if (!(typeof data === "string")) return false + return true +}; +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.foo !== undefined && hasOwn(data, "foo")) { + if (!ref1(data.foo)) return false + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireStringValidation] pattern, format or contentSchema should be specified for strings, use pattern: ^[\s\S]*$ to opt-out at urn:example:1/406/47452/2#` + + +## URN base URI with r-component + +### Schema + +```json +{ + "$comment": "RFC 8141 §2.3.1", + "$id": "urn:example:foo-bar-baz-qux?+CCResolve:cc=uk", + "properties": { "foo": { "$ref": "#/definitions/bar" } }, + "definitions": { "bar": { "type": "string" } } +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref1 = function validate(data) { + if (!(typeof data === "string")) return false + return true +}; +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.foo !== undefined && hasOwn(data, "foo")) { + if (!ref1(data.foo)) return false + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireStringValidation] pattern, format or contentSchema should be specified for strings, use pattern: ^[\s\S]*$ to opt-out at urn:example:foo-bar-baz-qux?+CCResolve:cc=uk#` + + +## URN base URI with q-component + +### Schema + +```json +{ + "$comment": "RFC 8141 §2.3.2", + "$id": "urn:example:weather?=op=map&lat=39.56&lon=-104.85&datetime=1969-07-21T02:56:15Z", + "properties": { "foo": { "$ref": "#/definitions/bar" } }, + "definitions": { "bar": { "type": "string" } } +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref1 = function validate(data) { + if (!(typeof data === "string")) return false + return true +}; +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.foo !== undefined && hasOwn(data, "foo")) { + if (!ref1(data.foo)) return false + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireStringValidation] pattern, format or contentSchema should be specified for strings, use pattern: ^[\s\S]*$ to opt-out at urn:example:weather?=op=map&lat=39.56&lon=-104.85&datetime=1969-07-21T02:56:15Z#` + + +## URN base URI with URN and JSON pointer ref + +### Schema + +```json +{ + "$id": "urn:uuid:deadbeef-1234-0000-0000-4321feebdaed", + "properties": { + "foo": { + "$ref": "urn:uuid:deadbeef-1234-0000-0000-4321feebdaed#/definitions/bar" + } + }, + "definitions": { "bar": { "type": "string" } } +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref1 = function validate(data) { + if (!(typeof data === "string")) return false + return true +}; +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.foo !== undefined && hasOwn(data, "foo")) { + if (!ref1(data.foo)) return false + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireStringValidation] pattern, format or contentSchema should be specified for strings, use pattern: ^[\s\S]*$ to opt-out at urn:uuid:deadbeef-1234-0000-0000-4321feebdaed#` + + +## URN base URI with URN and anchor ref + +### Schema + +```json +{ + "$id": "urn:uuid:deadbeef-1234-ff00-00ff-4321feebdaed", + "properties": { + "foo": { "$ref": "urn:uuid:deadbeef-1234-ff00-00ff-4321feebdaed#something" } + }, + "definitions": { "bar": { "$id": "#something", "type": "string" } } +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref1 = function validate(data) { + if (!(typeof data === "string")) return false + return true +}; +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.foo !== undefined && hasOwn(data, "foo")) { + if (!ref1(data.foo)) return false + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireStringValidation] pattern, format or contentSchema should be specified for strings, use pattern: ^[\s\S]*$ to opt-out at urn:uuid:deadbeef-1234-ff00-00ff-4321feebdaed#` + diff --git a/doc/samples/draft6/refRemote.md b/doc/samples/draft6/refRemote.md new file mode 100644 index 0000000..9cda6e5 --- /dev/null +++ b/doc/samples/draft6/refRemote.md @@ -0,0 +1,404 @@ +# refRemote + +## remote ref + +### Schema + +```json +{ "$ref": "http://localhost:1234/integer.json" } +``` + +### Code + +```js +'use strict' +const ref1 = function validate(data) { + if (!Number.isInteger(data)) return false + return true +}; +const ref0 = function validate(data) { + if (!ref1(data)) return false + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireSchema] $schema is required at http://localhost:1234/integer.json#` + + +## fragment within remote ref + +### Schema + +```json +{ "$ref": "http://localhost:1234/subSchemas.json#/integer" } +``` + +### Code + +```js +'use strict' +const ref1 = function validate(data) { + if (!Number.isInteger(data)) return false + return true +}; +const ref0 = function validate(data) { + if (!ref1(data)) return false + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireSchema] $schema is required at http://localhost:1234/subSchemas.json#` + + +## ref within remote ref + +### Schema + +```json +{ "$ref": "http://localhost:1234/subSchemas.json#/refToInteger" } +``` + +### Code + +```js +'use strict' +const ref2 = function validate(data) { + if (!Number.isInteger(data)) return false + return true +}; +const ref1 = function validate(data) { + if (!ref2(data)) return false + return true +}; +const ref0 = function validate(data) { + if (!ref1(data)) return false + return true +}; +return ref0 +``` + + +## base URI change + +### Schema + +```json +{ + "$id": "http://localhost:1234/", + "items": { + "$id": "baseUriChange/", + "items": { "$ref": "folderInteger.json" } + } +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref1 = function validate(data) { + if (!Number.isInteger(data)) return false + return true +}; +const ref0 = function validate(data) { + if (Array.isArray(data)) { + for (let i = 0; i < data.length; i++) { + if (data[i] !== undefined && hasOwn(data, i)) { + if (Array.isArray(data[i])) { + for (let j = 0; j < data[i].length; j++) { + if (data[i][j] !== undefined && hasOwn(data[i], j)) { + if (!ref1(data[i][j])) return false + } + } + } + } + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireSchema] $schema is required at http://localhost:1234/baseUriChange/folderInteger.json#` + + +## base URI change - change folder + +### Schema + +```json +{ + "$id": "http://localhost:1234/scope_change_defs1.json", + "type": "object", + "properties": { "list": { "$ref": "#/definitions/baz" } }, + "definitions": { + "baz": { + "$id": "baseUriChangeFolder/", + "type": "array", + "items": { "$ref": "folderInteger.json" } + } + } +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref2 = function validate(data) { + if (!Number.isInteger(data)) return false + return true +}; +const ref1 = function validate(data) { + if (!Array.isArray(data)) return false + for (let i = 0; i < data.length; i++) { + if (data[i] !== undefined && hasOwn(data, i)) { + if (!ref2(data[i])) return false + } + } + return true +}; +const ref0 = function validate(data) { + if (!(typeof data === "object" && data && !Array.isArray(data))) return false + if (data.list !== undefined && hasOwn(data, "list")) { + if (!ref1(data.list)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireSchema] $schema is required at http://localhost:1234/baseUriChangeFolder/folderInteger.json#` + + +## base URI change - change folder in subschema + +### Schema + +```json +{ + "$id": "http://localhost:1234/scope_change_defs2.json", + "type": "object", + "properties": { "list": { "$ref": "#/definitions/baz/definitions/bar" } }, + "definitions": { + "baz": { + "$id": "baseUriChangeFolderInSubschema/", + "definitions": { + "bar": { "type": "array", "items": { "$ref": "folderInteger.json" } } + } + } + } +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref2 = function validate(data) { + if (!Number.isInteger(data)) return false + return true +}; +const ref1 = function validate(data) { + if (!Array.isArray(data)) return false + for (let i = 0; i < data.length; i++) { + if (data[i] !== undefined && hasOwn(data, i)) { + if (!ref2(data[i])) return false + } + } + return true +}; +const ref0 = function validate(data) { + if (!(typeof data === "object" && data && !Array.isArray(data))) return false + if (data.list !== undefined && hasOwn(data, "list")) { + if (!ref1(data.list)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireSchema] $schema is required at http://localhost:1234/baseUriChangeFolderInSubschema/folderInteger.json#` + + +## root ref in remote ref + +### Schema + +```json +{ + "$id": "http://localhost:1234/object", + "type": "object", + "properties": { "name": { "$ref": "name.json#/definitions/orNull" } } +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref2 = function validate(data) { + if (!(typeof data === "string")) return false + return true +}; +const ref1 = function validate(data) { + const sub0 = (() => { + if (!(data === null)) return false + return true + })() + if (!sub0) { + const sub1 = (() => { + if (!ref2(data)) return false + return true + })() + if (!sub1) return false + } + return true +}; +const ref0 = function validate(data) { + if (!(typeof data === "object" && data && !Array.isArray(data))) return false + if (data.name !== undefined && hasOwn(data, "name")) { + if (!ref1(data.name)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireSchema] $schema is required at http://localhost:1234/name.json#` + + +## remote ref with ref to definitions + +### Schema + +```json +{ + "$id": "http://localhost:1234/schema-remote-ref-ref-defs1.json", + "allOf": [{ "$ref": "ref-and-definitions.json" }] +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref2 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.bar !== undefined && hasOwn(data, "bar")) { + if (!(typeof data.bar === "string")) return false + } + } + return true +}; +const ref1 = function validate(data) { + if (!ref2(data)) return false + return true +}; +const ref0 = function validate(data) { + if (!ref1(data)) return false + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireSchema] $schema is required at http://localhost:1234/ref-and-definitions.json#` + + +## Location-independent identifier in remote ref + +### Schema + +```json +{ + "$ref": "http://localhost:1234/locationIndependentIdentifierPre2019.json#/definitions/refToInteger" +} +``` + +### Code + +```js +'use strict' +const ref2 = function validate(data) { + if (!Number.isInteger(data)) return false + return true +}; +const ref1 = function validate(data) { + if (!ref2(data)) return false + return true +}; +const ref0 = function validate(data) { + if (!ref1(data)) return false + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireSchema] $schema is required at http://localhost:1234/locationIndependentIdentifierPre2019.json#` + + +## retrieved nested refs resolve relative to their URI not $id + +### Schema + +```json +{ + "$id": "http://localhost:1234/some-id", + "properties": { "name": { "$ref": "nested/foo-ref-string.json" } } +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref2 = function validate(data) { + if (!(typeof data === "string")) return false + return true +}; +const ref1 = function validate(data) { + if (!(typeof data === "object" && data && !Array.isArray(data))) return false + if (data.foo !== undefined && hasOwn(data, "foo")) { + if (!ref2(data.foo)) return false + } + return true +}; +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.name !== undefined && hasOwn(data, "name")) { + if (!ref1(data.name)) return false + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireSchema] $schema is required at http://localhost:1234/nested/foo-ref-string.json#` + diff --git a/doc/samples/draft6/required.md b/doc/samples/draft6/required.md new file mode 100644 index 0000000..8888dab --- /dev/null +++ b/doc/samples/draft6/required.md @@ -0,0 +1,144 @@ +# required + +## required validation + +### Schema + +```json +{ "properties": { "foo": {}, "bar": {} }, "required": ["foo"] } +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (!(data.foo !== undefined && hasOwn(data, "foo"))) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] empty rules node is not allowed at #/properties/foo` + + +## required default validation + +### Schema + +```json +{ "properties": { "foo": {} } } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] empty rules node is not allowed at #/properties/foo` + + +## required with empty array + +### Schema + +```json +{ "properties": { "foo": {} }, "required": [] } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] empty rules node is not allowed at #/properties/foo` + + +## required with escaped characters + +### Schema + +```json +{ + "required": [ + "foo\nbar", + "foo\"bar", + "foo\\bar", + "foo\rbar", + "foo\tbar", + "foo\fbar" + ] +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (!(data["foo\nbar"] !== undefined && hasOwn(data, "foo\nbar"))) return false + if (!(data["foo\"bar"] !== undefined && hasOwn(data, "foo\"bar"))) return false + if (!(data["foo\\bar"] !== undefined && hasOwn(data, "foo\\bar"))) return false + if (!(data["foo\rbar"] !== undefined && hasOwn(data, "foo\rbar"))) return false + if (!(data["foo\tbar"] !== undefined && hasOwn(data, "foo\tbar"))) return false + if (!(data["foo\fbar"] !== undefined && hasOwn(data, "foo\fbar"))) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## required properties whose names are Javascript object property names + +### Schema + +```json +{ "required": ["__proto__", "toString", "constructor"] } +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (!(data["__proto__"] !== undefined && hasOwn(data, "__proto__"))) return false + if (!(data.toString !== undefined && hasOwn(data, "toString"))) return false + if (!(data.constructor !== undefined && hasOwn(data, "constructor"))) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + diff --git a/doc/samples/draft6/type.md b/doc/samples/draft6/type.md new file mode 100644 index 0000000..ed839b2 --- /dev/null +++ b/doc/samples/draft6/type.md @@ -0,0 +1,249 @@ +# type + +## integer type matches integers + +### Schema + +```json +{ "type": "integer" } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (!Number.isInteger(data)) return false + return true +}; +return ref0 +``` + + +## number type matches numbers + +### Schema + +```json +{ "type": "number" } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (!(typeof data === "number")) return false + return true +}; +return ref0 +``` + + +## string type matches strings + +### Schema + +```json +{ "type": "string" } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (!(typeof data === "string")) return false + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireStringValidation] pattern, format or contentSchema should be specified for strings, use pattern: ^[\s\S]*$ to opt-out at #` + + +## object type matches objects + +### Schema + +```json +{ "type": "object" } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (!(typeof data === "object" && data && !Array.isArray(data))) return false + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] additionalProperties or unevaluatedProperties should be specified at #` + + +## array type matches arrays + +### Schema + +```json +{ "type": "array" } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (!Array.isArray(data)) return false + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] items rule should be specified at #` + + +## boolean type matches booleans + +### Schema + +```json +{ "type": "boolean" } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (!(typeof data === "boolean")) return false + return true +}; +return ref0 +``` + + +## null type matches only the null object + +### Schema + +```json +{ "type": "null" } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (!(data === null)) return false + return true +}; +return ref0 +``` + + +## multiple types can be specified in an array + +### Schema + +```json +{ "type": ["integer", "string"] } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (!(Number.isInteger(data) || typeof data === "string")) return false + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireStringValidation] pattern, format or contentSchema should be specified for strings, use pattern: ^[\s\S]*$ to opt-out at #` + + +## type as array with one item + +### Schema + +```json +{ "type": ["string"] } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (!(typeof data === "string")) return false + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireStringValidation] pattern, format or contentSchema should be specified for strings, use pattern: ^[\s\S]*$ to opt-out at #` + + +## type: array or object + +### Schema + +```json +{ "type": ["array", "object"] } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (!(Array.isArray(data) || typeof data === "object" && data && !Array.isArray(data))) return false + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] items rule should be specified at #` + + +## type: array, object or null + +### Schema + +```json +{ "type": ["array", "object", "null"] } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (!(Array.isArray(data) || typeof data === "object" && data && !Array.isArray(data) || data === null)) return false + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] items rule should be specified at #` + diff --git a/doc/samples/draft6/uniqueItems.md b/doc/samples/draft6/uniqueItems.md new file mode 100644 index 0000000..bd67a27 --- /dev/null +++ b/doc/samples/draft6/uniqueItems.md @@ -0,0 +1,319 @@ +# uniqueItems + +## uniqueItems validation + +### Schema + +```json +{ "uniqueItems": true } +``` + +### Code + +```js +'use strict' +const unique = (array) => { + if (array.length < 2) return true + if (array.length === 2) return !deepEqual(array[0], array[1]) + const objects = [] + const primitives = array.length > 20 ? new Set() : null + let primitivesCount = 0 + let pos = 0 + for (const item of array) { + if (typeof item === 'object') { + objects.push(item) + } else if (primitives) { + primitives.add(item) + if (primitives.size !== ++primitivesCount) return false + } else { + if (array.indexOf(item, pos + 1) !== -1) return false + } + pos++ + } + for (let i = 1; i < objects.length; i++) + for (let j = 0; j < i; j++) if (deepEqual(objects[i], objects[j])) return false + return true +}; +const deepEqual = (obj, obj2) => { + if (obj === obj2) return true + if (!obj || !obj2 || typeof obj !== typeof obj2) return false + if (obj !== obj2 && typeof obj !== 'object') return false + + const proto = Object.getPrototypeOf(obj) + if (proto !== Object.getPrototypeOf(obj2)) return false + + if (proto === Array.prototype) { + if (!Array.isArray(obj) || !Array.isArray(obj2)) return false + if (obj.length !== obj2.length) return false + return obj.every((x, i) => deepEqual(x, obj2[i])) + } else if (proto === Object.prototype) { + const [keys, keys2] = [Object.keys(obj), Object.keys(obj2)] + if (keys.length !== keys2.length) return false + const keyset2 = new Set([...keys, ...keys2]) + return keyset2.size === keys.length && keys.every((key) => deepEqual(obj[key], obj2[key])) + } + return false +}; +const ref0 = function validate(data) { + if (Array.isArray(data)) { + if (!unique(data)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[complexityChecks] maxItems should be specified for non-primitive uniqueItems at #` + + +## uniqueItems with an array of items + +### Schema + +```json +{ "items": [{ "type": "boolean" }, { "type": "boolean" }], "uniqueItems": true } +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const unique = (array) => { + if (array.length < 2) return true + if (array.length === 2) return !deepEqual(array[0], array[1]) + const objects = [] + const primitives = array.length > 20 ? new Set() : null + let primitivesCount = 0 + let pos = 0 + for (const item of array) { + if (typeof item === 'object') { + objects.push(item) + } else if (primitives) { + primitives.add(item) + if (primitives.size !== ++primitivesCount) return false + } else { + if (array.indexOf(item, pos + 1) !== -1) return false + } + pos++ + } + for (let i = 1; i < objects.length; i++) + for (let j = 0; j < i; j++) if (deepEqual(objects[i], objects[j])) return false + return true +}; +const deepEqual = (obj, obj2) => { + if (obj === obj2) return true + if (!obj || !obj2 || typeof obj !== typeof obj2) return false + if (obj !== obj2 && typeof obj !== 'object') return false + + const proto = Object.getPrototypeOf(obj) + if (proto !== Object.getPrototypeOf(obj2)) return false + + if (proto === Array.prototype) { + if (!Array.isArray(obj) || !Array.isArray(obj2)) return false + if (obj.length !== obj2.length) return false + return obj.every((x, i) => deepEqual(x, obj2[i])) + } else if (proto === Object.prototype) { + const [keys, keys2] = [Object.keys(obj), Object.keys(obj2)] + if (keys.length !== keys2.length) return false + const keyset2 = new Set([...keys, ...keys2]) + return keyset2.size === keys.length && keys.every((key) => deepEqual(obj[key], obj2[key])) + } + return false +}; +const ref0 = function validate(data) { + if (Array.isArray(data)) { + if (data[0] !== undefined && hasOwn(data, 0)) { + if (!(typeof data[0] === "boolean")) return false + } + if (data[1] !== undefined && hasOwn(data, 1)) { + if (!(typeof data[1] === "boolean")) return false + } + if (!unique(data)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[complexityChecks] maxItems should be specified for non-primitive uniqueItems at #` + + +## uniqueItems with an array of items and additionalItems=false + +### Schema + +```json +{ + "items": [{ "type": "boolean" }, { "type": "boolean" }], + "uniqueItems": true, + "additionalItems": false +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const unique = (array) => { + if (array.length < 2) return true + if (array.length === 2) return !deepEqual(array[0], array[1]) + const objects = [] + const primitives = array.length > 20 ? new Set() : null + let primitivesCount = 0 + let pos = 0 + for (const item of array) { + if (typeof item === 'object') { + objects.push(item) + } else if (primitives) { + primitives.add(item) + if (primitives.size !== ++primitivesCount) return false + } else { + if (array.indexOf(item, pos + 1) !== -1) return false + } + pos++ + } + for (let i = 1; i < objects.length; i++) + for (let j = 0; j < i; j++) if (deepEqual(objects[i], objects[j])) return false + return true +}; +const deepEqual = (obj, obj2) => { + if (obj === obj2) return true + if (!obj || !obj2 || typeof obj !== typeof obj2) return false + if (obj !== obj2 && typeof obj !== 'object') return false + + const proto = Object.getPrototypeOf(obj) + if (proto !== Object.getPrototypeOf(obj2)) return false + + if (proto === Array.prototype) { + if (!Array.isArray(obj) || !Array.isArray(obj2)) return false + if (obj.length !== obj2.length) return false + return obj.every((x, i) => deepEqual(x, obj2[i])) + } else if (proto === Object.prototype) { + const [keys, keys2] = [Object.keys(obj), Object.keys(obj2)] + if (keys.length !== keys2.length) return false + const keyset2 = new Set([...keys, ...keys2]) + return keyset2.size === keys.length && keys.every((key) => deepEqual(obj[key], obj2[key])) + } + return false +}; +const ref0 = function validate(data) { + if (Array.isArray(data)) { + if (data[0] !== undefined && hasOwn(data, 0)) { + if (!(typeof data[0] === "boolean")) return false + } + if (data[1] !== undefined && hasOwn(data, 1)) { + if (!(typeof data[1] === "boolean")) return false + } + if (data.length > 2) return false + if (!unique(data)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## uniqueItems=false validation + +### Schema + +```json +{ "uniqueItems": false } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## uniqueItems=false with an array of items + +### Schema + +```json +{ + "items": [{ "type": "boolean" }, { "type": "boolean" }], + "uniqueItems": false +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (Array.isArray(data)) { + if (data[0] !== undefined && hasOwn(data, 0)) { + if (!(typeof data[0] === "boolean")) return false + } + if (data[1] !== undefined && hasOwn(data, 1)) { + if (!(typeof data[1] === "boolean")) return false + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## uniqueItems=false with an array of items and additionalItems=false + +### Schema + +```json +{ + "items": [{ "type": "boolean" }, { "type": "boolean" }], + "uniqueItems": false, + "additionalItems": false +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (Array.isArray(data)) { + if (data[0] !== undefined && hasOwn(data, 0)) { + if (!(typeof data[0] === "boolean")) return false + } + if (data[1] !== undefined && hasOwn(data, 1)) { + if (!(typeof data[1] === "boolean")) return false + } + if (data.length > 2) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + diff --git a/doc/samples/draft6/unknownKeyword.md b/doc/samples/draft6/unknownKeyword.md new file mode 100644 index 0000000..f0ef772 --- /dev/null +++ b/doc/samples/draft6/unknownKeyword.md @@ -0,0 +1,91 @@ +# unknownKeyword + +## $id inside an unknown keyword is not a real identifier + +### Schema + +```json +{ + "definitions": { + "id_in_unknown0": { + "not": { + "array_of_schemas": [ + { + "$id": "https://localhost:1234/unknownKeyword/my_identifier.json", + "type": "null" + } + ] + } + }, + "real_id_in_schema": { + "$id": "https://localhost:1234/unknownKeyword/my_identifier.json", + "type": "string" + }, + "id_in_unknown1": { + "not": { + "object_of_schemas": { + "foo": { + "$id": "https://localhost:1234/unknownKeyword/my_identifier.json", + "type": "integer" + } + } + } + } + }, + "anyOf": [ + { "$ref": "#/definitions/id_in_unknown0" }, + { "$ref": "#/definitions/id_in_unknown1" }, + { "$ref": "https://localhost:1234/unknownKeyword/my_identifier.json" } + ] +} +``` + +### Code + +```js +'use strict' +const ref1 = function validate(data) { + const sub1 = (() => { + return true + })() + if (sub1) return false + return true +}; +const ref2 = function validate(data) { + const sub3 = (() => { + return true + })() + if (sub3) return false + return true +}; +const ref3 = function validate(data) { + if (!(typeof data === "string")) return false + return true +}; +const ref0 = function validate(data) { + const sub0 = (() => { + if (!ref1(data)) return false + return true + })() + if (!sub0) { + const sub2 = (() => { + if (!ref2(data)) return false + return true + })() + if (!sub2) { + const sub4 = (() => { + if (!ref3(data)) return false + return true + })() + if (!sub4) return false + } + } + return true +}; +return ref0 +``` + +### Warnings + + * `Keyword not supported: "array_of_schemas" at #/not` + diff --git a/doc/samples/draft7/README.md b/doc/samples/draft7/README.md new file mode 100644 index 0000000..943c595 --- /dev/null +++ b/doc/samples/draft7/README.md @@ -0,0 +1,73 @@ +# Samples + +Based on JSON Schema Test Suite for `draft7`. + + +### Disambiguation + + * **Failed to compile** — schemas that did not compile in any mode. + + * **Warnings** — schemas that did not compile in the `default` mode, but compiled in `lax` + mode. + + JSON Schema spec allows usage of ineffective or unknown keywords, which is considered a mistake + by `@exodus/schemasafe` by default. `lax` mode lifts that coherence check. + + * **Misclassified** — schemas that classified at least one test value incorrectly, i.e. gave + `true` where testsuite expected `false` or vice versa. + +## Results + +| Name | Total | Failed to compile | Warnings | Misclassified | +|-------------------------------------------------------------|-------|-------------------|----------|---------------| +| [additionalItems](./additionalItems.md) | 9 | - | 4 | - | +| [additionalProperties](./additionalProperties.md) | 7 | - | - | - | +| [allOf](./allOf.md) | 12 | - | - | - | +| [anyOf](./anyOf.md) | 8 | - | 3 | - | +| [boolean_schema](./boolean_schema.md) | 2 | - | - | - | +| [const](./const.md) | 15 | - | - | - | +| [contains](./contains.md) | 7 | - | - | - | +| [default](./default.md) | 3 | - | - | - | +| [definitions](./definitions.md) | 1 | - | - | - | +| [dependencies](./dependencies.md) | 6 | - | - | - | +| [enum](./enum.md) | 10 | - | - | - | +| [exclusiveMaximum](./exclusiveMaximum.md) | 1 | - | - | - | +| [exclusiveMinimum](./exclusiveMinimum.md) | 1 | - | - | - | +| [format](./format.md) | 17 | 4 | - | - | +| [id](./id.md) | 3 | - | - | - | +| [if-then-else](./if-then-else.md) | 10 | - | 6 | - | +| [infinite-loop-detection](./infinite-loop-detection.md) | 1 | - | - | - | +| [items](./items.md) | 9 | - | - | - | +| [maxItems](./maxItems.md) | 2 | - | - | - | +| [maxLength](./maxLength.md) | 2 | - | - | - | +| [maxProperties](./maxProperties.md) | 3 | - | - | - | +| [maximum](./maximum.md) | 2 | - | - | - | +| [minItems](./minItems.md) | 2 | - | - | - | +| [minLength](./minLength.md) | 2 | - | - | - | +| [minProperties](./minProperties.md) | 2 | - | - | - | +| [minimum](./minimum.md) | 2 | - | - | - | +| [multipleOf](./multipleOf.md) | 4 | - | - | - | +| [not](./not.md) | 6 | - | 1 | - | +| [oneOf](./oneOf.md) | 11 | - | 3 | - | +| [pattern](./pattern.md) | 2 | - | - | - | +| [patternProperties](./patternProperties.md) | 5 | - | - | - | +| [properties](./properties.md) | 6 | - | - | - | +| [propertyNames](./propertyNames.md) | 4 | - | - | - | +| [ref](./ref.md) | 27 | - | 2 | - | +| [refRemote](./refRemote.md) | 10 | - | - | - | +| [required](./required.md) | 5 | - | - | - | +| [type](./type.md) | 11 | - | - | - | +| [uniqueItems](./uniqueItems.md) | 6 | - | - | - | +| [unknownKeyword](./unknownKeyword.md) | 1 | - | 1 | - | +| [optional/bignum](./optional-bignum.md) | 7 | - | - | - | +| [optional/content](./optional-content.md) | 3 | - | - | - | +| [optional/cross-draft](./optional-cross-draft.md) | 1 | - | - | - | +| [optional/ecmascript-regex](./optional-ecmascript-regex.md) | 20 | - | - | - | +| [optional/float-overflow](./optional-float-overflow.md) | 1 | - | - | - | +| [optional/non-bmp-regex](./optional-non-bmp-regex.md) | 2 | - | - | - | + +### Notes + +`{ isJSON: true }` option is used for better clarity, and that also corresponds to the main +expected usage pattern of this module. Without it, there would be additional checks for +`!== undefined`, which can be fast-tracked if we know that the input came from `JSON.parse()`. diff --git a/doc/samples/draft7/additionalItems.md b/doc/samples/draft7/additionalItems.md new file mode 100644 index 0000000..3da2bba --- /dev/null +++ b/doc/samples/draft7/additionalItems.md @@ -0,0 +1,268 @@ +# additionalItems + +## additionalItems as schema + +### Schema + +```json +{ "items": [{}], "additionalItems": { "type": "integer" } } +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (Array.isArray(data)) { + for (let i = 1; i < data.length; i++) { + if (data[i] !== undefined && hasOwn(data, i)) { + if (!(Number.isInteger(data[i]))) return false + } + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] empty rules node is not allowed at #/0` + + +## when items is schema, additionalItems does nothing + +### Schema + +```json +{ "items": {}, "additionalItems": false } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + return true +}; +return ref0 +``` + +### Warnings + + * `Unprocessed keywords: ["additionalItems"] at #` + + +## array of items with no additionalItems permitted + +### Schema + +```json +{ "items": [{}, {}, {}], "additionalItems": false } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (Array.isArray(data)) { + if (data.length > 3) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] empty rules node is not allowed at #/0` + + +## additionalItems as false without items + +### Schema + +```json +{ "additionalItems": false } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + return true +}; +return ref0 +``` + +### Warnings + + * `Unprocessed keywords: ["additionalItems"] at #` + + +## additionalItems are allowed by default + +### Schema + +```json +{ "items": [{ "type": "integer" }] } +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (Array.isArray(data)) { + if (data[0] !== undefined && hasOwn(data, 0)) { + if (!(Number.isInteger(data[0]))) return false + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## additionalItems does not look in applicators, valid case + +### Schema + +```json +{ + "allOf": [{ "items": [{ "type": "integer" }] }], + "additionalItems": { "type": "boolean" } +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (Array.isArray(data)) { + if (data[0] !== undefined && hasOwn(data, 0)) { + if (!(Number.isInteger(data[0]))) return false + } + } + return true +}; +return ref0 +``` + +### Warnings + + * `Unprocessed keywords: ["additionalItems"] at #` + + +## additionalItems does not look in applicators, invalid case + +### Schema + +```json +{ + "allOf": [{ "items": [{ "type": "integer" }, { "type": "string" }] }], + "items": [{ "type": "integer" }], + "additionalItems": { "type": "boolean" } +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (Array.isArray(data)) { + if (data[0] !== undefined && hasOwn(data, 0)) { + if (!(Number.isInteger(data[0]))) return false + } + for (let i = 1; i < data.length; i++) { + if (data[i] !== undefined && hasOwn(data, i)) { + if (!(typeof data[i] === "boolean")) return false + } + } + } + if (Array.isArray(data)) { + if (data[0] !== undefined && hasOwn(data, 0)) { + if (!(Number.isInteger(data[0]))) return false + } + if (data[1] !== undefined && hasOwn(data, 1)) { + if (!(typeof data[1] === "string")) return false + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireStringValidation] pattern, format or contentSchema should be specified for strings, use pattern: ^[\s\S]*$ to opt-out at #/allOf/0/1` + + +## items validation adjusts the starting index for additionalItems + +### Schema + +```json +{ "items": [{ "type": "string" }], "additionalItems": { "type": "integer" } } +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (Array.isArray(data)) { + if (data[0] !== undefined && hasOwn(data, 0)) { + if (!(typeof data[0] === "string")) return false + } + for (let i = 1; i < data.length; i++) { + if (data[i] !== undefined && hasOwn(data, i)) { + if (!(Number.isInteger(data[i]))) return false + } + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireStringValidation] pattern, format or contentSchema should be specified for strings, use pattern: ^[\s\S]*$ to opt-out at #/0` + + +## additionalItems with null instance elements + +### Schema + +```json +{ "additionalItems": { "type": "null" } } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + return true +}; +return ref0 +``` + +### Warnings + + * `Unprocessed keywords: ["additionalItems"] at #` + diff --git a/doc/samples/draft7/additionalProperties.md b/doc/samples/draft7/additionalProperties.md new file mode 100644 index 0000000..33da910 --- /dev/null +++ b/doc/samples/draft7/additionalProperties.md @@ -0,0 +1,204 @@ +# additionalProperties + +## additionalProperties being false does not allow other properties + +### Schema + +```json +{ + "properties": { "foo": {}, "bar": {} }, + "patternProperties": { "^v": {} }, + "additionalProperties": false +} +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + for (const key1 of Object.keys(data)) { + if (key1 !== "foo" && key1 !== "bar" && !(key1.startsWith("v"))) return false + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] empty rules node is not allowed at #/properties/foo` + + +## non-ASCII pattern with additionalProperties + +### Schema + +```json +{ "patternProperties": { "^á": {} }, "additionalProperties": false } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + for (const key1 of Object.keys(data)) { + if (!(key1.startsWith("á"))) return false + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `Should start with ^ and end with $: "^á" at #` + + +## additionalProperties with schema + +### Schema + +```json +{ + "properties": { "foo": {}, "bar": {} }, + "additionalProperties": { "type": "boolean" } +} +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + for (const key0 of Object.keys(data)) { + if (key0 !== "foo" && key0 !== "bar") { + if (!(typeof data[key0] === "boolean")) return false + } + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] empty rules node is not allowed at #/properties/foo` + + +## additionalProperties can exist by itself + +### Schema + +```json +{ "additionalProperties": { "type": "boolean" } } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + for (const key0 of Object.keys(data)) { + if (!(typeof data[key0] === "boolean")) return false + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## additionalProperties are allowed by default + +### Schema + +```json +{ "properties": { "foo": {}, "bar": {} } } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] empty rules node is not allowed at #/properties/foo` + + +## additionalProperties does not look in applicators + +### Schema + +```json +{ + "allOf": [{ "properties": { "foo": {} } }], + "additionalProperties": { "type": "boolean" } +} +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + for (const key0 of Object.keys(data)) { + if (!(typeof data[key0] === "boolean")) return false + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] empty rules node is not allowed at #/allOf/0/properties/foo` + + +## additionalProperties with null valued instance properties + +### Schema + +```json +{ "additionalProperties": { "type": "null" } } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + for (const key0 of Object.keys(data)) { + if (!(data[key0] === null)) return false + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + diff --git a/doc/samples/draft7/allOf.md b/doc/samples/draft7/allOf.md new file mode 100644 index 0000000..9e2130e --- /dev/null +++ b/doc/samples/draft7/allOf.md @@ -0,0 +1,328 @@ +# allOf + +## allOf + +### Schema + +```json +{ + "allOf": [ + { "properties": { "bar": { "type": "integer" } }, "required": ["bar"] }, + { "properties": { "foo": { "type": "string" } }, "required": ["foo"] } + ] +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (!(data.bar !== undefined && hasOwn(data, "bar"))) return false + if (!Number.isInteger(data.bar)) return false + } + if (typeof data === "object" && data && !Array.isArray(data)) { + if (!(data.foo !== undefined && hasOwn(data, "foo"))) return false + if (!(typeof data.foo === "string")) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireStringValidation] pattern, format or contentSchema should be specified for strings, use pattern: ^[\s\S]*$ to opt-out at #/allOf/1/properties/foo` + + +## allOf with base schema + +### Schema + +```json +{ + "properties": { "bar": { "type": "integer" } }, + "required": ["bar"], + "allOf": [ + { "properties": { "foo": { "type": "string" } }, "required": ["foo"] }, + { "properties": { "baz": { "type": "null" } }, "required": ["baz"] } + ] +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (!(data.bar !== undefined && hasOwn(data, "bar"))) return false + if (!Number.isInteger(data.bar)) return false + } + if (typeof data === "object" && data && !Array.isArray(data)) { + if (!(data.foo !== undefined && hasOwn(data, "foo"))) return false + if (!(typeof data.foo === "string")) return false + } + if (typeof data === "object" && data && !Array.isArray(data)) { + if (!(data.baz !== undefined && hasOwn(data, "baz"))) return false + if (!(data.baz === null)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireStringValidation] pattern, format or contentSchema should be specified for strings, use pattern: ^[\s\S]*$ to opt-out at #/allOf/0/properties/foo` + + +## allOf simple types + +### Schema + +```json +{ "allOf": [{ "maximum": 30 }, { "minimum": 20 }] } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (typeof data === "number") { + if (!(30 >= data)) return false + } + if (typeof data === "number") { + if (!(20 <= data)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## allOf with boolean schemas, all true + +### Schema + +```json +{ "allOf": [true, true] } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] schema = true is not allowed at #/allOf/0` + + +## allOf with boolean schemas, some false + +### Schema + +```json +{ "allOf": [true, false] } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + return false + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] schema = true is not allowed at #/allOf/0` + + +## allOf with boolean schemas, all false + +### Schema + +```json +{ "allOf": [false, false] } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + return false + return false + return true +}; +return ref0 +``` + + +## allOf with one empty schema + +### Schema + +```json +{ "allOf": [{}] } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] empty rules node is not allowed at #/allOf/0` + + +## allOf with two empty schemas + +### Schema + +```json +{ "allOf": [{}, {}] } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] empty rules node is not allowed at #/allOf/0` + + +## allOf with the first empty schema + +### Schema + +```json +{ "allOf": [{}, { "type": "number" }] } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (!(typeof data === "number")) return false + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] empty rules node is not allowed at #/allOf/0` + + +## allOf with the last empty schema + +### Schema + +```json +{ "allOf": [{ "type": "number" }, {}] } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (!(typeof data === "number")) return false + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] empty rules node is not allowed at #/allOf/1` + + +## nested allOf, to check validation semantics + +### Schema + +```json +{ "allOf": [{ "allOf": [{ "type": "null" }] }] } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (!(data === null)) return false + return true +}; +return ref0 +``` + + +## allOf combined with anyOf, oneOf + +### Schema + +```json +{ + "allOf": [{ "multipleOf": 2 }], + "anyOf": [{ "multipleOf": 3 }], + "oneOf": [{ "multipleOf": 5 }] +} +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (typeof data === "number") { + if (data % 2 !== 0) return false + } + if (typeof data === "number") { + if (data % 3 !== 0) return false + } + if (typeof data === "number") { + if (data % 5 !== 0) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + diff --git a/doc/samples/draft7/anyOf.md b/doc/samples/draft7/anyOf.md new file mode 100644 index 0000000..3fcf9b7 --- /dev/null +++ b/doc/samples/draft7/anyOf.md @@ -0,0 +1,233 @@ +# anyOf + +## anyOf + +### Schema + +```json +{ "anyOf": [{ "type": "integer" }, { "minimum": 2 }] } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + const sub0 = (() => { + if (!Number.isInteger(data)) return false + return true + })() + if (!sub0) { + const sub1 = (() => { + if (typeof data === "number") { + if (!(2 <= data)) return false + } + return true + })() + if (!sub1) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## anyOf with base schema + +### Schema + +```json +{ "type": "string", "anyOf": [{ "maxLength": 2 }, { "minLength": 4 }] } +``` + +### Code + +```js +'use strict' +const stringLength = (string) => + /[\uD800-\uDFFF]/.test(string) ? [...string].length : string.length; +const ref0 = function validate(data) { + if (!(typeof data === "string")) return false + const sub0 = (() => { + if (data.length > 2 && stringLength(data) > 2) return false + return true + })() + if (!sub0) { + const sub1 = (() => { + if (data.length < 4 || stringLength(data) < 4) return false + return true + })() + if (!sub1) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireStringValidation] pattern, format or contentSchema should be specified for strings, use pattern: ^[\s\S]*$ to opt-out at #` + + +## anyOf with boolean schemas, all true + +### Schema + +```json +{ "anyOf": [true, true] } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + return true +}; +return ref0 +``` + +### Warnings + + * `some checks are never reachable at #` + + +## anyOf with boolean schemas, some true + +### Schema + +```json +{ "anyOf": [true, false] } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + return true +}; +return ref0 +``` + +### Warnings + + * `some checks are never reachable at #` + + +## anyOf with boolean schemas, all false + +### Schema + +```json +{ "anyOf": [false, false] } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + return false + return true +}; +return ref0 +``` + + +## anyOf complex types + +### Schema + +```json +{ + "anyOf": [ + { "properties": { "bar": { "type": "integer" } }, "required": ["bar"] }, + { "properties": { "foo": { "type": "string" } }, "required": ["foo"] } + ] +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + const sub0 = (() => { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (!(data.bar !== undefined && hasOwn(data, "bar"))) return false + if (!Number.isInteger(data.bar)) return false + } + return true + })() + if (!sub0) { + const sub1 = (() => { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (!(data.foo !== undefined && hasOwn(data, "foo"))) return false + if (!(typeof data.foo === "string")) return false + } + return true + })() + if (!sub1) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireStringValidation] pattern, format or contentSchema should be specified for strings, use pattern: ^[\s\S]*$ to opt-out at #/anyOf/1/properties/foo` + + +## anyOf with one empty schema + +### Schema + +```json +{ "anyOf": [{ "type": "number" }, {}] } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + const sub0 = (() => { + if (!(typeof data === "number")) return false + return true + })() + return true +}; +return ref0 +``` + +### Warnings + + * `some checks are never reachable at #` + + +## nested anyOf, to check validation semantics + +### Schema + +```json +{ "anyOf": [{ "anyOf": [{ "type": "null" }] }] } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (!(data === null)) return false + return true +}; +return ref0 +``` + diff --git a/doc/samples/draft7/boolean_schema.md b/doc/samples/draft7/boolean_schema.md new file mode 100644 index 0000000..406f7d6 --- /dev/null +++ b/doc/samples/draft7/boolean_schema.md @@ -0,0 +1,44 @@ +# boolean_schema + +## boolean schema 'true' + +### Schema + +```json +true +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] schema = true is not allowed at #` + + +## boolean schema 'false' + +### Schema + +```json +false +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + return false + return true +}; +return ref0 +``` + diff --git a/doc/samples/draft7/const.md b/doc/samples/draft7/const.md new file mode 100644 index 0000000..a918cab --- /dev/null +++ b/doc/samples/draft7/const.md @@ -0,0 +1,324 @@ +# const + +## const validation + +### Schema + +```json +{ "const": 2 } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (!(data === 2)) return false + return true +}; +return ref0 +``` + + +## const with object + +### Schema + +```json +{ "const": { "foo": "bar", "baz": "bax" } } +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (!(typeof data === "object" && data && !Array.isArray(data) && Object.keys(data).length === 2 && hasOwn(data, "foo") && hasOwn(data, "baz") && data["foo"] === "bar" && data["baz"] === "bax")) return false + return true +}; +return ref0 +``` + + +## const with array + +### Schema + +```json +{ "const": [{ "foo": "bar" }] } +``` + +### Code + +```js +'use strict' +const deepEqual = (obj, obj2) => { + if (obj === obj2) return true + if (!obj || !obj2 || typeof obj !== typeof obj2) return false + if (obj !== obj2 && typeof obj !== 'object') return false + + const proto = Object.getPrototypeOf(obj) + if (proto !== Object.getPrototypeOf(obj2)) return false + + if (proto === Array.prototype) { + if (!Array.isArray(obj) || !Array.isArray(obj2)) return false + if (obj.length !== obj2.length) return false + return obj.every((x, i) => deepEqual(x, obj2[i])) + } else if (proto === Object.prototype) { + const [keys, keys2] = [Object.keys(obj), Object.keys(obj2)] + if (keys.length !== keys2.length) return false + const keyset2 = new Set([...keys, ...keys2]) + return keyset2.size === keys.length && keys.every((key) => deepEqual(obj[key], obj2[key])) + } + return false +}; +const ref0 = function validate(data) { + if (!(Array.isArray(data) && deepEqual(data, [{"foo":"bar"}]))) return false + return true +}; +return ref0 +``` + + +## const with null + +### Schema + +```json +{ "const": null } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (!(data === null)) return false + return true +}; +return ref0 +``` + + +## const with false does not match 0 + +### Schema + +```json +{ "const": false } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (!(data === false)) return false + return true +}; +return ref0 +``` + + +## const with true does not match 1 + +### Schema + +```json +{ "const": true } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (!(data === true)) return false + return true +}; +return ref0 +``` + + +## const with [false] does not match [0] + +### Schema + +```json +{ "const": [false] } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (!(Array.isArray(data) && data.length === 1 && data[0] === false)) return false + return true +}; +return ref0 +``` + + +## const with [true] does not match [1] + +### Schema + +```json +{ "const": [true] } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (!(Array.isArray(data) && data.length === 1 && data[0] === true)) return false + return true +}; +return ref0 +``` + + +## const with {"a": false} does not match {"a": 0} + +### Schema + +```json +{ "const": { "a": false } } +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (!(typeof data === "object" && data && !Array.isArray(data) && Object.keys(data).length === 1 && hasOwn(data, "a") && data["a"] === false)) return false + return true +}; +return ref0 +``` + + +## const with {"a": true} does not match {"a": 1} + +### Schema + +```json +{ "const": { "a": true } } +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (!(typeof data === "object" && data && !Array.isArray(data) && Object.keys(data).length === 1 && hasOwn(data, "a") && data["a"] === true)) return false + return true +}; +return ref0 +``` + + +## const with 0 does not match other zero-like types + +### Schema + +```json +{ "const": 0 } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (!(data === 0)) return false + return true +}; +return ref0 +``` + + +## const with 1 does not match true + +### Schema + +```json +{ "const": 1 } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (!(data === 1)) return false + return true +}; +return ref0 +``` + + +## const with -2.0 matches integer and float types + +### Schema + +```json +{ "const": -2 } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (!(data === -2)) return false + return true +}; +return ref0 +``` + + +## float and integers are equal up to 64-bit representation limits + +### Schema + +```json +{ "const": 9007199254740992 } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (!(data === 9007199254740992)) return false + return true +}; +return ref0 +``` + + +## nul characters in strings + +### Schema + +```json +{ "const": "hello\u0000there" } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (!(data === "hello\u0000there")) return false + return true +}; +return ref0 +``` + diff --git a/doc/samples/draft7/contains.md b/doc/samples/draft7/contains.md new file mode 100644 index 0000000..a65f895 --- /dev/null +++ b/doc/samples/draft7/contains.md @@ -0,0 +1,262 @@ +# contains + +## contains keyword validation + +### Schema + +```json +{ "contains": { "minimum": 5 } } +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (Array.isArray(data)) { + let passes0 = 0 + for (let i = 0; i < data.length; i++) { + const sub0 = (() => { + if (data[i] !== undefined && hasOwn(data, i)) { + if (typeof data[i] === "number") { + if (!(5 <= data[i])) return false + } + } + return true + })() + if (sub0) passes0++ + } + if (passes0 < 1) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #/contains` + + +## contains keyword with const keyword + +### Schema + +```json +{ "contains": { "const": 5 } } +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (Array.isArray(data)) { + let passes0 = 0 + for (let i = 0; i < data.length; i++) { + const sub0 = (() => { + if (data[i] !== undefined && hasOwn(data, i)) { + if (!(data[i] === 5)) return false + } + return true + })() + if (sub0) passes0++ + } + if (passes0 < 1) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## contains keyword with boolean schema true + +### Schema + +```json +{ "contains": true } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (Array.isArray(data)) { + let passes0 = 0 + for (let i = 0; i < data.length; i++) { + const sub0 = (() => { + return true + })() + if (sub0) passes0++ + } + if (passes0 < 1) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] schema = true is not allowed at #/contains` + + +## contains keyword with boolean schema false + +### Schema + +```json +{ "contains": false } +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (Array.isArray(data)) { + let passes0 = 0 + for (let i = 0; i < data.length; i++) { + const sub0 = (() => { + if (data[i] !== undefined && hasOwn(data, i)) return false + return true + })() + if (sub0) passes0++ + } + if (passes0 < 1) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## items + contains + +### Schema + +```json +{ "items": { "multipleOf": 2 }, "contains": { "multipleOf": 3 } } +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (Array.isArray(data)) { + for (let i = 0; i < data.length; i++) { + if (data[i] !== undefined && hasOwn(data, i)) { + if (typeof data[i] === "number") { + if (data[i] % 2 !== 0) return false + } + } + } + let passes0 = 0 + for (let j = 0; j < data.length; j++) { + const sub0 = (() => { + if (data[j] !== undefined && hasOwn(data, j)) { + if (typeof data[j] === "number") { + if (data[j] % 3 !== 0) return false + } + } + return true + })() + if (sub0) passes0++ + } + if (passes0 < 1) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #/items` + + +## contains with false if subschema + +### Schema + +```json +{ "contains": { "if": false, "else": true } } +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (Array.isArray(data)) { + let passes0 = 0 + for (let i = 0; i < data.length; i++) { + const sub0 = (() => { + return true + })() + if (sub0) passes0++ + } + if (passes0 < 1) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] schema = true is not allowed at #/contains/else` + + +## contains with null instance elements + +### Schema + +```json +{ "contains": { "type": "null" } } +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (Array.isArray(data)) { + let passes0 = 0 + for (let i = 0; i < data.length; i++) { + const sub0 = (() => { + if (data[i] !== undefined && hasOwn(data, i)) { + if (!(data[i] === null)) return false + } + return true + })() + if (sub0) passes0++ + } + if (passes0 < 1) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + diff --git a/doc/samples/draft7/default.md b/doc/samples/draft7/default.md new file mode 100644 index 0000000..9e6b1e6 --- /dev/null +++ b/doc/samples/draft7/default.md @@ -0,0 +1,98 @@ +# default + +## invalid type for default + +### Schema + +```json +{ "properties": { "foo": { "type": "integer", "default": [] } } } +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.foo !== undefined && hasOwn(data, "foo")) { + if (!Number.isInteger(data.foo)) return false + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## invalid string value for default + +### Schema + +```json +{ + "properties": { + "bar": { "type": "string", "minLength": 4, "default": "bad" } + } +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const stringLength = (string) => + /[\uD800-\uDFFF]/.test(string) ? [...string].length : string.length; +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.bar !== undefined && hasOwn(data, "bar")) { + if (!(typeof data.bar === "string")) return false + if (data.bar.length < 4 || stringLength(data.bar) < 4) return false + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireStringValidation] pattern, format or contentSchema should be specified for strings, use pattern: ^[\s\S]*$ to opt-out at #/properties/bar` + + +## the default keyword does not do anything if the property is missing + +### Schema + +```json +{ + "type": "object", + "properties": { "alpha": { "type": "number", "maximum": 3, "default": 5 } } +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (!(typeof data === "object" && data && !Array.isArray(data))) return false + if (data.alpha !== undefined && hasOwn(data, "alpha")) { + if (!(typeof data.alpha === "number")) return false + if (!(3 >= data.alpha)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] additionalProperties or unevaluatedProperties should be specified at #` + diff --git a/doc/samples/draft7/definitions.md b/doc/samples/draft7/definitions.md new file mode 100644 index 0000000..57b7f60 --- /dev/null +++ b/doc/samples/draft7/definitions.md @@ -0,0 +1,311 @@ +# definitions + +## validate definition against metaschema + +### Schema + +```json +{ "$ref": "http://json-schema.org/draft-07/schema#" } +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const format0 = new RegExp("^(?:[a-z][a-z0-9+\\-.]*:)?(?:\\/?\\/(?:(?:[a-z0-9\\-._~!$&'()*+,;=:]|%[0-9a-f]{2})*@)?(?:\\[(?:(?:(?:(?:[0-9a-f]{1,4}:){6}|::(?:[0-9a-f]{1,4}:){5}|(?:[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){4}|(?:(?:[0-9a-f]{1,4}:){0,1}[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){3}|(?:(?:[0-9a-f]{1,4}:){0,2}[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){2}|(?:(?:[0-9a-f]{1,4}:){0,3}[0-9a-f]{1,4})?::[0-9a-f]{1,4}:|(?:(?:[0-9a-f]{1,4}:){0,4}[0-9a-f]{1,4})?::)(?:[0-9a-f]{1,4}:[0-9a-f]{1,4}|(?:(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d\\d?)\\.){3}(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d\\d?))|(?:(?:[0-9a-f]{1,4}:){0,5}[0-9a-f]{1,4})?::[0-9a-f]{1,4}|(?:(?:[0-9a-f]{1,4}:){0,6}[0-9a-f]{1,4})?::)|v[0-9a-f]+\\.[a-z0-9\\-._~!$&'()*+,;=:]+)\\]|(?:(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d\\d?)\\.){3}(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d\\d?)|(?:[a-z0-9\\-._~!$&'()*+,;=]|%[0-9a-f]{2})*)(?::\\d*)?(?:\\/(?:[a-z0-9\\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})*)*|\\/?(?:(?:[a-z0-9\\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})+(?:\\/(?:[a-z0-9\\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})*)*)?)?(?:\\?(?:[a-z0-9\\-._~!$&'()*+,;=:@/?]|%[0-9a-f]{2})*)?(?:#(?:[a-z0-9\\-._~!$&'()*+,;=:@/?]|%[0-9a-f]{2})*)?$", "i"); +const format1 = new RegExp("^[a-z][a-z0-9+\\-.]*:(?:\\/?\\/(?:(?:[a-z0-9\\-._~!$&'()*+,;=:]|%[0-9a-f]{2})*@)?(?:\\[(?:(?:(?:(?:[0-9a-f]{1,4}:){6}|::(?:[0-9a-f]{1,4}:){5}|(?:[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){4}|(?:(?:[0-9a-f]{1,4}:){0,1}[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){3}|(?:(?:[0-9a-f]{1,4}:){0,2}[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){2}|(?:(?:[0-9a-f]{1,4}:){0,3}[0-9a-f]{1,4})?::[0-9a-f]{1,4}:|(?:(?:[0-9a-f]{1,4}:){0,4}[0-9a-f]{1,4})?::)(?:[0-9a-f]{1,4}:[0-9a-f]{1,4}|(?:(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d\\d?)\\.){3}(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d\\d?))|(?:(?:[0-9a-f]{1,4}:){0,5}[0-9a-f]{1,4})?::[0-9a-f]{1,4}|(?:(?:[0-9a-f]{1,4}:){0,6}[0-9a-f]{1,4})?::)|v[0-9a-f]+\\.[a-z0-9\\-._~!$&'()*+,;=:]+)\\]|(?:(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d\\d?)\\.){3}(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d\\d?)|(?:[a-z0-9\\-._~!$&'()*+,;=]|%[0-9a-f]{2})*)(?::\\d*)?(?:\\/(?:[a-z0-9\\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})*)*|\\/?(?:(?:[a-z0-9\\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})+(?:\\/(?:[a-z0-9\\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})*)*)?)(?:\\?(?:[a-z0-9\\-._~!$&'()*+,;=:@/?]|%[0-9a-f]{2})*)?(?:#(?:[a-z0-9\\-._~!$&'()*+,;=:@/?]|%[0-9a-f]{2})*)?$", "i"); +const ref2 = function validate(data) { + if (!Number.isInteger(data)) return false + if (!(0 <= data)) return false + return true +}; +const ref3 = function validate(data) { + if (!ref2(data)) return false + return true +}; +const format2 = (str) => { + if (str.length > 1e5) return false + const Z_ANCHOR = /[^\\]\\Z/ + if (Z_ANCHOR.test(str)) return false + try { + new RegExp(str, 'u') + return true + } catch (e) { + return false + } + }; +const ref4 = function validate(data) { + if (!Array.isArray(data)) return false + if (data.length < 1) return false + for (let j = 0; j < data.length; j++) { + if (data[j] !== undefined && hasOwn(data, j)) { + if (!ref1(data[j])) return false + } + } + return true +}; +const unique = (array) => { + if (array.length < 2) return true + if (array.length === 2) return !deepEqual(array[0], array[1]) + const objects = [] + const primitives = array.length > 20 ? new Set() : null + let primitivesCount = 0 + let pos = 0 + for (const item of array) { + if (typeof item === 'object') { + objects.push(item) + } else if (primitives) { + primitives.add(item) + if (primitives.size !== ++primitivesCount) return false + } else { + if (array.indexOf(item, pos + 1) !== -1) return false + } + pos++ + } + for (let i = 1; i < objects.length; i++) + for (let j = 0; j < i; j++) if (deepEqual(objects[i], objects[j])) return false + return true +}; +const deepEqual = (obj, obj2) => { + if (obj === obj2) return true + if (!obj || !obj2 || typeof obj !== typeof obj2) return false + if (obj !== obj2 && typeof obj !== 'object') return false + + const proto = Object.getPrototypeOf(obj) + if (proto !== Object.getPrototypeOf(obj2)) return false + + if (proto === Array.prototype) { + if (!Array.isArray(obj) || !Array.isArray(obj2)) return false + if (obj.length !== obj2.length) return false + return obj.every((x, i) => deepEqual(x, obj2[i])) + } else if (proto === Object.prototype) { + const [keys, keys2] = [Object.keys(obj), Object.keys(obj2)] + if (keys.length !== keys2.length) return false + const keyset2 = new Set([...keys, ...keys2]) + return keyset2.size === keys.length && keys.every((key) => deepEqual(obj[key], obj2[key])) + } + return false +}; +const ref5 = function validate(data) { + if (!Array.isArray(data)) return false + for (let k = 0; k < data.length; k++) { + if (data[k] !== undefined && hasOwn(data, k)) { + if (!(typeof data[k] === "string")) return false + } + } + if (!unique(data)) return false + return true +}; +const ref6 = function validate(data) { + if (!(data === "array" || data === "boolean" || data === "integer" || data === "null" || data === "number" || data === "object" || data === "string")) return false + return true +}; +const ref1 = function validate(data) { + if (!(typeof data === "object" && data && !Array.isArray(data) || typeof data === "boolean")) return false + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data["$id"] !== undefined && hasOwn(data, "$id")) { + if (!(typeof data["$id"] === "string")) return false + if (!format0.test(data["$id"])) return false + } + if (data["$schema"] !== undefined && hasOwn(data, "$schema")) { + if (!(typeof data["$schema"] === "string")) return false + if (!format1.test(data["$schema"])) return false + } + if (data["$ref"] !== undefined && hasOwn(data, "$ref")) { + if (!(typeof data["$ref"] === "string")) return false + if (!format0.test(data["$ref"])) return false + } + if (data["$comment"] !== undefined && hasOwn(data, "$comment")) { + if (!(typeof data["$comment"] === "string")) return false + } + if (data.title !== undefined && hasOwn(data, "title")) { + if (!(typeof data.title === "string")) return false + } + if (data.description !== undefined && hasOwn(data, "description")) { + if (!(typeof data.description === "string")) return false + } + if (data.readOnly !== undefined && hasOwn(data, "readOnly")) { + if (!(typeof data.readOnly === "boolean")) return false + } + if (data.writeOnly !== undefined && hasOwn(data, "writeOnly")) { + if (!(typeof data.writeOnly === "boolean")) return false + } + if (data.examples !== undefined && hasOwn(data, "examples")) { + if (!Array.isArray(data.examples)) return false + } + if (data.multipleOf !== undefined && hasOwn(data, "multipleOf")) { + if (!(typeof data.multipleOf === "number")) return false + if (!(0 < data.multipleOf)) return false + } + if (data.maximum !== undefined && hasOwn(data, "maximum")) { + if (!(typeof data.maximum === "number")) return false + } + if (data.exclusiveMaximum !== undefined && hasOwn(data, "exclusiveMaximum")) { + if (!(typeof data.exclusiveMaximum === "number")) return false + } + if (data.minimum !== undefined && hasOwn(data, "minimum")) { + if (!(typeof data.minimum === "number")) return false + } + if (data.exclusiveMinimum !== undefined && hasOwn(data, "exclusiveMinimum")) { + if (!(typeof data.exclusiveMinimum === "number")) return false + } + if (data.maxLength !== undefined && hasOwn(data, "maxLength")) { + if (!ref2(data.maxLength)) return false + } + if (data.minLength !== undefined && hasOwn(data, "minLength")) { + if (!ref3(data.minLength)) return false + } + if (data.pattern !== undefined && hasOwn(data, "pattern")) { + if (!(typeof data.pattern === "string")) return false + if (!format2(data.pattern)) return false + } + if (data.additionalItems !== undefined && hasOwn(data, "additionalItems")) { + if (!validate(data.additionalItems)) return false + } + if (data.items !== undefined && hasOwn(data, "items")) { + const sub0 = (() => { + if (!validate(data.items)) return false + return true + })() + if (!sub0) { + const sub1 = (() => { + if (!ref4(data.items)) return false + return true + })() + if (!sub1) return false + } + } + if (data.maxItems !== undefined && hasOwn(data, "maxItems")) { + if (!ref2(data.maxItems)) return false + } + if (data.minItems !== undefined && hasOwn(data, "minItems")) { + if (!ref3(data.minItems)) return false + } + if (data.uniqueItems !== undefined && hasOwn(data, "uniqueItems")) { + if (!(typeof data.uniqueItems === "boolean")) return false + } + if (data.contains !== undefined && hasOwn(data, "contains")) { + if (!validate(data.contains)) return false + } + if (data.maxProperties !== undefined && hasOwn(data, "maxProperties")) { + if (!ref2(data.maxProperties)) return false + } + if (data.minProperties !== undefined && hasOwn(data, "minProperties")) { + if (!ref3(data.minProperties)) return false + } + if (data.required !== undefined && hasOwn(data, "required")) { + if (!ref5(data.required)) return false + } + if (data.additionalProperties !== undefined && hasOwn(data, "additionalProperties")) { + if (!validate(data.additionalProperties)) return false + } + if (data.definitions !== undefined && hasOwn(data, "definitions")) { + if (!(typeof data.definitions === "object" && data.definitions && !Array.isArray(data.definitions))) return false + for (const key0 of Object.keys(data.definitions)) { + if (!validate(data.definitions[key0])) return false + } + } + if (data.properties !== undefined && hasOwn(data, "properties")) { + if (!(typeof data.properties === "object" && data.properties && !Array.isArray(data.properties))) return false + for (const key1 of Object.keys(data.properties)) { + if (!validate(data.properties[key1])) return false + } + } + if (data.patternProperties !== undefined && hasOwn(data, "patternProperties")) { + if (!(typeof data.patternProperties === "object" && data.patternProperties && !Array.isArray(data.patternProperties))) return false + for (const key2 of Object.keys(data.patternProperties)) { + if (!format2(key2)) return false + } + for (const key3 of Object.keys(data.patternProperties)) { + if (!validate(data.patternProperties[key3])) return false + } + } + if (data.dependencies !== undefined && hasOwn(data, "dependencies")) { + if (!(typeof data.dependencies === "object" && data.dependencies && !Array.isArray(data.dependencies))) return false + for (const key4 of Object.keys(data.dependencies)) { + const sub2 = (() => { + if (!validate(data.dependencies[key4])) return false + return true + })() + if (!sub2) { + const sub3 = (() => { + if (!ref5(data.dependencies[key4])) return false + return true + })() + if (!sub3) return false + } + } + } + if (data.propertyNames !== undefined && hasOwn(data, "propertyNames")) { + if (!validate(data.propertyNames)) return false + } + if (data.enum !== undefined && hasOwn(data, "enum")) { + if (!Array.isArray(data.enum)) return false + if (data.enum.length < 1) return false + if (!unique(data.enum)) return false + } + if (data.type !== undefined && hasOwn(data, "type")) { + const sub4 = (() => { + if (!ref6(data.type)) return false + return true + })() + if (!sub4) { + const sub5 = (() => { + if (!Array.isArray(data.type)) return false + if (data.type.length < 1) return false + for (let m = 0; m < data.type.length; m++) { + if (data.type[m] !== undefined && hasOwn(data.type, m)) { + if (!ref6(data.type[m])) return false + } + } + if (!unique(data.type)) return false + return true + })() + if (!sub5) return false + } + } + if (data.format !== undefined && hasOwn(data, "format")) { + if (!(typeof data.format === "string")) return false + } + if (data.contentMediaType !== undefined && hasOwn(data, "contentMediaType")) { + if (!(typeof data.contentMediaType === "string")) return false + } + if (data.contentEncoding !== undefined && hasOwn(data, "contentEncoding")) { + if (!(typeof data.contentEncoding === "string")) return false + } + if (data.if !== undefined && hasOwn(data, "if")) { + if (!validate(data.if)) return false + } + if (data.then !== undefined && hasOwn(data, "then")) { + if (!validate(data.then)) return false + } + if (data.else !== undefined && hasOwn(data, "else")) { + if (!validate(data.else)) return false + } + if (data.allOf !== undefined && hasOwn(data, "allOf")) { + if (!ref4(data.allOf)) return false + } + if (data.anyOf !== undefined && hasOwn(data, "anyOf")) { + if (!ref4(data.anyOf)) return false + } + if (data.oneOf !== undefined && hasOwn(data, "oneOf")) { + if (!ref4(data.oneOf)) return false + } + if (data.not !== undefined && hasOwn(data, "not")) { + if (!validate(data.not)) return false + } + } + return true +}; +const ref0 = function validate(data) { + if (!ref1(data)) return false + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireStringValidation] pattern, format or contentSchema should be specified for strings, use pattern: ^[\s\S]*$ to opt-out at http://json-schema.org/draft-07/schema#/properties/$comment` + diff --git a/doc/samples/draft7/dependencies.md b/doc/samples/draft7/dependencies.md new file mode 100644 index 0000000..a13ce57 --- /dev/null +++ b/doc/samples/draft7/dependencies.md @@ -0,0 +1,195 @@ +# dependencies + +## dependencies + +### Schema + +```json +{ "dependencies": { "bar": ["foo"] } } +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.bar !== undefined && hasOwn(data, "bar") && !(data.foo !== undefined && hasOwn(data, "foo"))) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## dependencies with empty array + +### Schema + +```json +{ "dependencies": { "bar": [] } } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## multiple dependencies + +### Schema + +```json +{ "dependencies": { "quux": ["foo", "bar"] } } +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.quux !== undefined && hasOwn(data, "quux") && !(data.foo !== undefined && hasOwn(data, "foo") && data.bar !== undefined && hasOwn(data, "bar"))) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## multiple dependencies subschema + +### Schema + +```json +{ + "dependencies": { + "bar": { + "properties": { + "foo": { "type": "integer" }, + "bar": { "type": "integer" } + } + } + } +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.bar !== undefined && hasOwn(data, "bar")) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.foo !== undefined && hasOwn(data, "foo")) { + if (!Number.isInteger(data.foo)) return false + } + if (data.bar !== undefined && hasOwn(data, "bar")) { + if (!Number.isInteger(data.bar)) return false + } + } + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] if properties is used, required should be specified at #/dependencies/bar` + + +## dependencies with boolean subschemas + +### Schema + +```json +{ "dependencies": { "foo": true, "bar": false } } +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.bar !== undefined && hasOwn(data, "bar")) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] schema = true is not allowed at #/dependencies/foo` + + +## dependencies with escaped characters + +### Schema + +```json +{ + "dependencies": { + "foo\nbar": ["foo\rbar"], + "foo\tbar": { "minProperties": 4 }, + "foo'bar": { "required": ["foo\"bar"] }, + "foo\"bar": ["foo'bar"] + } +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data["foo\nbar"] !== undefined && hasOwn(data, "foo\nbar") && !(data["foo\rbar"] !== undefined && hasOwn(data, "foo\rbar"))) return false + if (data["foo\tbar"] !== undefined && hasOwn(data, "foo\tbar")) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (Object.keys(data).length < 4) return false + } + } + if (data["foo'bar"] !== undefined && hasOwn(data, "foo'bar")) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (!(data["foo\"bar"] !== undefined && hasOwn(data, "foo\"bar"))) return false + } + } + if (data["foo\"bar"] !== undefined && hasOwn(data, "foo\"bar") && !(data["foo'bar"] !== undefined && hasOwn(data, "foo'bar"))) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + diff --git a/doc/samples/draft7/enum.md b/doc/samples/draft7/enum.md new file mode 100644 index 0000000..f72f0da --- /dev/null +++ b/doc/samples/draft7/enum.md @@ -0,0 +1,216 @@ +# enum + +## simple enum validation + +### Schema + +```json +{ "enum": [1, 2, 3] } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (!(data === 1 || data === 2 || data === 3)) return false + return true +}; +return ref0 +``` + + +## heterogeneous enum validation + +### Schema + +```json +{ "enum": [6, "foo", [], true, { "foo": 12 }] } +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (!(data === 6 || data === "foo" || data === true || Array.isArray(data) && data.length === 0 || typeof data === "object" && data && !Array.isArray(data) && Object.keys(data).length === 1 && hasOwn(data, "foo") && data["foo"] === 12)) return false + return true +}; +return ref0 +``` + + +## heterogeneous enum-with-null validation + +### Schema + +```json +{ "enum": [6, null] } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (!(data === 6 || data === null)) return false + return true +}; +return ref0 +``` + + +## enums in properties + +### Schema + +```json +{ + "type": "object", + "properties": { "foo": { "enum": ["foo"] }, "bar": { "enum": ["bar"] } }, + "required": ["bar"] +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (!(typeof data === "object" && data && !Array.isArray(data))) return false + if (!(data.bar !== undefined && hasOwn(data, "bar"))) return false + if (data.foo !== undefined && hasOwn(data, "foo")) { + if (!(data.foo === "foo")) return false + } + if (!(data.bar === "bar")) return false + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] additionalProperties or unevaluatedProperties should be specified at #` + + +## enum with escaped characters + +### Schema + +```json +{ "enum": ["foo\nbar", "foo\rbar"] } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (!(data === "foo\nbar" || data === "foo\rbar")) return false + return true +}; +return ref0 +``` + + +## enum with false does not match 0 + +### Schema + +```json +{ "enum": [false] } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (!(data === false)) return false + return true +}; +return ref0 +``` + + +## enum with true does not match 1 + +### Schema + +```json +{ "enum": [true] } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (!(data === true)) return false + return true +}; +return ref0 +``` + + +## enum with 0 does not match false + +### Schema + +```json +{ "enum": [0] } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (!(data === 0)) return false + return true +}; +return ref0 +``` + + +## enum with 1 does not match true + +### Schema + +```json +{ "enum": [1] } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (!(data === 1)) return false + return true +}; +return ref0 +``` + + +## nul characters in strings + +### Schema + +```json +{ "enum": ["hello\u0000there"] } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (!(data === "hello\u0000there")) return false + return true +}; +return ref0 +``` + diff --git a/doc/samples/draft7/exclusiveMaximum.md b/doc/samples/draft7/exclusiveMaximum.md new file mode 100644 index 0000000..fa89b08 --- /dev/null +++ b/doc/samples/draft7/exclusiveMaximum.md @@ -0,0 +1,27 @@ +# exclusiveMaximum + +## exclusiveMaximum validation + +### Schema + +```json +{ "exclusiveMaximum": 3 } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (typeof data === "number") { + if (!(3 > data)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + diff --git a/doc/samples/draft7/exclusiveMinimum.md b/doc/samples/draft7/exclusiveMinimum.md new file mode 100644 index 0000000..4a605e7 --- /dev/null +++ b/doc/samples/draft7/exclusiveMinimum.md @@ -0,0 +1,27 @@ +# exclusiveMinimum + +## exclusiveMinimum validation + +### Schema + +```json +{ "exclusiveMinimum": 1.1 } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (typeof data === "number") { + if (!(1.1 < data)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + diff --git a/doc/samples/draft7/format.md b/doc/samples/draft7/format.md new file mode 100644 index 0000000..6810365 --- /dev/null +++ b/doc/samples/draft7/format.md @@ -0,0 +1,521 @@ +# format + +## email format + +### Schema + +```json +{ "format": "email" } +``` + +### Code + +```js +'use strict' +const format0 = (input) => { + if (input.length > 318) return false + const fast = /^[a-z0-9!#$%&'*+/=?^_`{|}~-]{1,20}(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]{1,21}){0,2}@[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?(?:\.[a-z0-9](?:[a-z0-9-]{0,60}[a-z0-9])?){0,3}$/i + if (fast.test(input)) return true + if (!input.includes('@') || /(^\.|^"|\.@|\.\.)/.test(input)) return false + const [name, host, ...rest] = input.split('@') + if (!name || !host || rest.length !== 0 || name.length > 64 || host.length > 253) return false + if (!/^[a-z0-9.-]+$/i.test(host) || !/^[a-z0-9.!#$%&'*+/=?^_`{|}~-]+$/i.test(name)) return false + return host.split('.').every((part) => /^[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?$/i.test(part)) + }; +const ref0 = function validate(data) { + if (typeof data === "string") { + if (!format0(data)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## idn-email format + +### Schema + +```json +{ "format": "idn-email" } +``` + +### Code + +**FAILED TO COMPILE** + +### Errors + + * `Unrecognized format used: "idn-email" at #` + + +## regex format + +### Schema + +```json +{ "format": "regex" } +``` + +### Code + +```js +'use strict' +const format0 = (str) => { + if (str.length > 1e5) return false + const Z_ANCHOR = /[^\\]\\Z/ + if (Z_ANCHOR.test(str)) return false + try { + new RegExp(str, 'u') + return true + } catch (e) { + return false + } + }; +const ref0 = function validate(data) { + if (typeof data === "string") { + if (!format0(data)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `Unrecognized format used: "regex" at #` + + +## ipv4 format + +### Schema + +```json +{ "format": "ipv4" } +``` + +### Code + +```js +'use strict' +const format0 = (ip) => + ip.length <= 15 && + /^(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)\.){3}(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d\d?)$/.test(ip); +const ref0 = function validate(data) { + if (typeof data === "string") { + if (!format0(data)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## ipv6 format + +### Schema + +```json +{ "format": "ipv6" } +``` + +### Code + +```js +'use strict' +const format0 = (input) => { + if (input.length > 45 || input.length < 2) return false + let s0 = 0, s1 = 0, hex = 0, short = false, letters = false, last = 0, start = true + for (let i = 0; i < input.length; i++) { + const c = input.charCodeAt(i) + if (i === 1 && last === 58 && c !== 58) return false + if (c >= 48 && c <= 57) { + if (++hex > 4) return false + } else if (c === 46) { + if (s0 > 6 || s1 >= 3 || hex === 0 || letters) return false + s1++ + hex = 0 + } else if (c === 58) { + if (s1 > 0 || s0 >= 7) return false + if (last === 58) { + if (short) return false + short = true + } else if (i === 0) start = false + s0++ + hex = 0 + letters = false + } else if ((c >= 97 && c <= 102) || (c >= 65 && c <= 70)) { + if (s1 > 0) return false + if (++hex > 4) return false + letters = true + } else return false + last = c + } + if (s0 < 2 || (s1 > 0 && (s1 !== 3 || hex === 0))) return false + if (short && input.length === 2) return true + if (s1 > 0 && !/(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}$/.test(input)) return false + const spaces = s1 > 0 ? 6 : 7 + if (!short) return s0 === spaces && start && hex > 0 + return (start || hex > 0) && s0 < spaces + }; +const ref0 = function validate(data) { + if (typeof data === "string") { + if (!format0(data)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## idn-hostname format + +### Schema + +```json +{ "format": "idn-hostname" } +``` + +### Code + +**FAILED TO COMPILE** + +### Errors + + * `Unrecognized format used: "idn-hostname" at #` + + +## hostname format + +### Schema + +```json +{ "format": "hostname" } +``` + +### Code + +```js +'use strict' +const format0 = (input) => { + if (input.length > (input.endsWith('.') ? 254 : 253)) return false + const hostname = /^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?(?:\.[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?)*\.?$/i + return hostname.test(input) + }; +const ref0 = function validate(data) { + if (typeof data === "string") { + if (!format0(data)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## date format + +### Schema + +```json +{ "format": "date" } +``` + +### Code + +```js +'use strict' +const format0 = (input) => { + if (input.length !== 10) return false + if (input[5] === '0' && input[6] === '2') { + if (/^\d\d\d\d-02-(?:[012][1-8]|[12]0|[01]9)$/.test(input)) return true + const matches = input.match(/^(\d\d\d\d)-02-29$/) + if (!matches) return false + const year = matches[1] | 0 + return year % 16 === 0 || (year % 4 === 0 && year % 25 !== 0) + } + if (input.endsWith('31')) return /^\d\d\d\d-(?:0[13578]|1[02])-31$/.test(input) + return /^\d\d\d\d-(?:0[13-9]|1[012])-(?:[012][1-9]|[123]0)$/.test(input) + }; +const ref0 = function validate(data) { + if (typeof data === "string") { + if (!format0(data)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## date-time format + +### Schema + +```json +{ "format": "date-time" } +``` + +### Code + +```js +'use strict' +const format0 = (input) => { + if (input.length > 10 + 1 + 9 + 12 + 6) return false + const full = /^\d\d\d\d-(?:0[1-9]|1[0-2])-(?:[0-2]\d|3[01])[t\s](?:2[0-3]|[0-1]\d):[0-5]\d:(?:[0-5]\d|60)(?:\.\d+)?(?:z|[+-](?:2[0-3]|[0-1]\d)(?::?[0-5]\d)?)$/i + const feb = input[5] === '0' && input[6] === '2' + if ((feb && input[8] === '3') || !full.test(input)) return false + if (input[17] === '6') { + const p = input.slice(11).match(/([0-9.]+|[^0-9.])/g) + let hm = Number(p[0]) * 60 + Number(p[2]) + if (p[5] === '+') hm += 24 * 60 - Number(p[6] || 0) * 60 - Number(p[8] || 0) + else if (p[5] === '-') hm += Number(p[6] || 0) * 60 + Number(p[8] || 0) + if (hm % (24 * 60) !== 23 * 60 + 59) return false + } + if (feb) { + if (/^\d\d\d\d-02-(?:[012][1-8]|[12]0|[01]9)/.test(input)) return true + const matches = input.match(/^(\d\d\d\d)-02-29/) + if (!matches) return false + const year = matches[1] | 0 + return year % 16 === 0 || (year % 4 === 0 && year % 25 !== 0) + } + if (input[8] === '3' && input[9] === '1') return /^\d\d\d\d-(?:0[13578]|1[02])-31/.test(input) + return /^\d\d\d\d-(?:0[13-9]|1[012])-(?:[012][1-9]|[123]0)/.test(input) + }; +const ref0 = function validate(data) { + if (typeof data === "string") { + if (!format0(data)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## time format + +### Schema + +```json +{ "format": "time" } +``` + +### Code + +```js +'use strict' +const format0 = (input) => { + if (input.length > 9 + 12 + 6) return false + const time = /^(?:2[0-3]|[0-1]\d):[0-5]\d:(?:[0-5]\d|60)(?:\.\d+)?(?:z|[+-](?:2[0-3]|[0-1]\d)(?::?[0-5]\d)?)?$/i + if (!time.test(input)) return false + if (!/:60/.test(input)) return true + const p = input.match(/([0-9.]+|[^0-9.])/g) + let hm = Number(p[0]) * 60 + Number(p[2]) + if (p[5] === '+') hm += 24 * 60 - Number(p[6] || 0) * 60 - Number(p[8] || 0) + else if (p[5] === '-') hm += Number(p[6] || 0) * 60 + Number(p[8] || 0) + return hm % (24 * 60) === 23 * 60 + 59 + }; +const ref0 = function validate(data) { + if (typeof data === "string") { + if (!format0(data)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## json-pointer format + +### Schema + +```json +{ "format": "json-pointer" } +``` + +### Code + +```js +'use strict' +const format0 = new RegExp("^(?:|\\/(?:[^~]|~0|~1)*)$", ""); +const ref0 = function validate(data) { + if (typeof data === "string") { + if (!format0.test(data)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## relative-json-pointer format + +### Schema + +```json +{ "format": "relative-json-pointer" } +``` + +### Code + +```js +'use strict' +const format0 = new RegExp("^(?:0|[1-9][0-9]*)(?:|#|\\/(?:[^~]|~0|~1)*)$", ""); +const ref0 = function validate(data) { + if (typeof data === "string") { + if (!format0.test(data)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## iri format + +### Schema + +```json +{ "format": "iri" } +``` + +### Code + +**FAILED TO COMPILE** + +### Errors + + * `Unrecognized format used: "iri" at #` + + +## iri-reference format + +### Schema + +```json +{ "format": "iri-reference" } +``` + +### Code + +**FAILED TO COMPILE** + +### Errors + + * `Unrecognized format used: "iri-reference" at #` + + +## uri format + +### Schema + +```json +{ "format": "uri" } +``` + +### Code + +```js +'use strict' +const format0 = new RegExp("^[a-z][a-z0-9+\\-.]*:(?:\\/?\\/(?:(?:[a-z0-9\\-._~!$&'()*+,;=:]|%[0-9a-f]{2})*@)?(?:\\[(?:(?:(?:(?:[0-9a-f]{1,4}:){6}|::(?:[0-9a-f]{1,4}:){5}|(?:[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){4}|(?:(?:[0-9a-f]{1,4}:){0,1}[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){3}|(?:(?:[0-9a-f]{1,4}:){0,2}[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){2}|(?:(?:[0-9a-f]{1,4}:){0,3}[0-9a-f]{1,4})?::[0-9a-f]{1,4}:|(?:(?:[0-9a-f]{1,4}:){0,4}[0-9a-f]{1,4})?::)(?:[0-9a-f]{1,4}:[0-9a-f]{1,4}|(?:(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d\\d?)\\.){3}(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d\\d?))|(?:(?:[0-9a-f]{1,4}:){0,5}[0-9a-f]{1,4})?::[0-9a-f]{1,4}|(?:(?:[0-9a-f]{1,4}:){0,6}[0-9a-f]{1,4})?::)|v[0-9a-f]+\\.[a-z0-9\\-._~!$&'()*+,;=:]+)\\]|(?:(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d\\d?)\\.){3}(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d\\d?)|(?:[a-z0-9\\-._~!$&'()*+,;=]|%[0-9a-f]{2})*)(?::\\d*)?(?:\\/(?:[a-z0-9\\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})*)*|\\/?(?:(?:[a-z0-9\\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})+(?:\\/(?:[a-z0-9\\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})*)*)?)(?:\\?(?:[a-z0-9\\-._~!$&'()*+,;=:@/?]|%[0-9a-f]{2})*)?(?:#(?:[a-z0-9\\-._~!$&'()*+,;=:@/?]|%[0-9a-f]{2})*)?$", "i"); +const ref0 = function validate(data) { + if (typeof data === "string") { + if (!format0.test(data)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## uri-reference format + +### Schema + +```json +{ "format": "uri-reference" } +``` + +### Code + +```js +'use strict' +const format0 = new RegExp("^(?:[a-z][a-z0-9+\\-.]*:)?(?:\\/?\\/(?:(?:[a-z0-9\\-._~!$&'()*+,;=:]|%[0-9a-f]{2})*@)?(?:\\[(?:(?:(?:(?:[0-9a-f]{1,4}:){6}|::(?:[0-9a-f]{1,4}:){5}|(?:[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){4}|(?:(?:[0-9a-f]{1,4}:){0,1}[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){3}|(?:(?:[0-9a-f]{1,4}:){0,2}[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){2}|(?:(?:[0-9a-f]{1,4}:){0,3}[0-9a-f]{1,4})?::[0-9a-f]{1,4}:|(?:(?:[0-9a-f]{1,4}:){0,4}[0-9a-f]{1,4})?::)(?:[0-9a-f]{1,4}:[0-9a-f]{1,4}|(?:(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d\\d?)\\.){3}(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d\\d?))|(?:(?:[0-9a-f]{1,4}:){0,5}[0-9a-f]{1,4})?::[0-9a-f]{1,4}|(?:(?:[0-9a-f]{1,4}:){0,6}[0-9a-f]{1,4})?::)|v[0-9a-f]+\\.[a-z0-9\\-._~!$&'()*+,;=:]+)\\]|(?:(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d\\d?)\\.){3}(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d\\d?)|(?:[a-z0-9\\-._~!$&'()*+,;=]|%[0-9a-f]{2})*)(?::\\d*)?(?:\\/(?:[a-z0-9\\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})*)*|\\/?(?:(?:[a-z0-9\\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})+(?:\\/(?:[a-z0-9\\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})*)*)?)?(?:\\?(?:[a-z0-9\\-._~!$&'()*+,;=:@/?]|%[0-9a-f]{2})*)?(?:#(?:[a-z0-9\\-._~!$&'()*+,;=:@/?]|%[0-9a-f]{2})*)?$", "i"); +const ref0 = function validate(data) { + if (typeof data === "string") { + if (!format0.test(data)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## uri-template format + +### Schema + +```json +{ "format": "uri-template" } +``` + +### Code + +```js +'use strict' +const format0 = new RegExp("^(?:[^\\x00-\\x20\"'<>%\\\\^`{|}]|%[0-9a-f]{2}|\\{[+#./;?&=,!@|]?(?:[a-z0-9_]|%[0-9a-f]{2})+(?::[1-9][0-9]{0,3}|\\*)?(?:,(?:[a-z0-9_]|%[0-9a-f]{2})+(?::[1-9][0-9]{0,3}|\\*)?)*\\})*$", "i"); +const ref0 = function validate(data) { + if (typeof data === "string") { + if (!format0.test(data)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + diff --git a/doc/samples/draft7/id.md b/doc/samples/draft7/id.md new file mode 100644 index 0000000..42032a7 --- /dev/null +++ b/doc/samples/draft7/id.md @@ -0,0 +1,151 @@ +# id + +## id inside an enum is not a real identifier + +### Schema + +```json +{ + "definitions": { + "id_in_enum": { + "enum": [ + { + "$id": "https://localhost:1234/id/my_identifier.json", + "type": "null" + } + ] + }, + "real_id_in_schema": { + "$id": "https://localhost:1234/id/my_identifier.json", + "type": "string" + }, + "zzz_id_in_const": { + "const": { + "$id": "https://localhost:1234/id/my_identifier.json", + "type": "null" + } + } + }, + "anyOf": [ + { "$ref": "#/definitions/id_in_enum" }, + { "$ref": "https://localhost:1234/id/my_identifier.json" } + ] +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref1 = function validate(data) { + if (!(typeof data === "object" && data && !Array.isArray(data) && Object.keys(data).length === 2 && hasOwn(data, "$id") && hasOwn(data, "type") && data["$id"] === "https://localhost:1234/id/my_identifier.json" && data["type"] === "null")) return false + return true +}; +const ref2 = function validate(data) { + if (!(typeof data === "string")) return false + return true +}; +const ref0 = function validate(data) { + const sub0 = (() => { + if (!ref1(data)) return false + return true + })() + if (!sub0) { + const sub1 = (() => { + if (!ref2(data)) return false + return true + })() + if (!sub1) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireStringValidation] pattern, format or contentSchema should be specified for strings, use pattern: ^[\s\S]*$ to opt-out at #` + + +## non-schema object containing a plain-name $id property + +### Schema + +```json +{ + "definitions": { + "const_not_anchor": { "const": { "$id": "#not_a_real_anchor" } } + }, + "if": { "const": "skip not_a_real_anchor" }, + "then": true, + "else": { "$ref": "#/definitions/const_not_anchor" } +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref1 = function validate(data) { + if (!(typeof data === "object" && data && !Array.isArray(data) && Object.keys(data).length === 1 && hasOwn(data, "$id") && data["$id"] === "#not_a_real_anchor")) return false + return true +}; +const ref0 = function validate(data) { + const sub0 = (() => { + if (!(data === "skip not_a_real_anchor")) return false + return true + })() + if (!sub0) { + if (!ref1(data)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] schema = true is not allowed at #/then` + + +## non-schema object containing an $id property + +### Schema + +```json +{ + "definitions": { "const_not_id": { "const": { "$id": "not_a_real_id" } } }, + "if": { "const": "skip not_a_real_id" }, + "then": true, + "else": { "$ref": "#/definitions/const_not_id" } +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref1 = function validate(data) { + if (!(typeof data === "object" && data && !Array.isArray(data) && Object.keys(data).length === 1 && hasOwn(data, "$id") && data["$id"] === "not_a_real_id")) return false + return true +}; +const ref0 = function validate(data) { + const sub0 = (() => { + if (!(data === "skip not_a_real_id")) return false + return true + })() + if (!sub0) { + if (!ref1(data)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] schema = true is not allowed at #/then` + diff --git a/doc/samples/draft7/if-then-else.md b/doc/samples/draft7/if-then-else.md new file mode 100644 index 0000000..836d8cb --- /dev/null +++ b/doc/samples/draft7/if-then-else.md @@ -0,0 +1,305 @@ +# if-then-else + +## ignore if without then or else + +### Schema + +```json +{ "if": { "const": 0 } } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + const sub0 = (() => { + if (!(data === 0)) return false + return true + })() + return true +}; +return ref0 +``` + +### Warnings + + * `Unprocessed keywords: ["if"] at #` + + +## ignore then without if + +### Schema + +```json +{ "then": { "const": 0 } } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + return true +}; +return ref0 +``` + +### Warnings + + * `Unprocessed keywords: ["then"] at #` + + +## ignore else without if + +### Schema + +```json +{ "else": { "const": 0 } } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + return true +}; +return ref0 +``` + +### Warnings + + * `Unprocessed keywords: ["else"] at #` + + +## if and then without else + +### Schema + +```json +{ "if": { "exclusiveMaximum": 0 }, "then": { "minimum": -10 } } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + const sub0 = (() => { + if (typeof data === "number") { + if (!(0 > data)) return false + } + return true + })() + if (sub0) { + if (typeof data === "number") { + if (!(-10 <= data)) return false + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## if and else without then + +### Schema + +```json +{ "if": { "exclusiveMaximum": 0 }, "else": { "multipleOf": 2 } } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + const sub0 = (() => { + if (typeof data === "number") { + if (!(0 > data)) return false + } + return true + })() + if (!sub0) { + if (typeof data === "number") { + if (data % 2 !== 0) return false + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## validate against correct branch, then vs else + +### Schema + +```json +{ + "if": { "exclusiveMaximum": 0 }, + "then": { "minimum": -10 }, + "else": { "multipleOf": 2 } +} +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + const sub0 = (() => { + if (typeof data === "number") { + if (!(0 > data)) return false + } + return true + })() + if (sub0) { + if (typeof data === "number") { + if (!(-10 <= data)) return false + } + } + else { + if (typeof data === "number") { + if (data % 2 !== 0) return false + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## non-interference across combined schemas + +### Schema + +```json +{ + "allOf": [ + { "if": { "exclusiveMaximum": 0 } }, + { "then": { "minimum": -10 } }, + { "else": { "multipleOf": 2 } } + ] +} +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + const sub0 = (() => { + if (typeof data === "number") { + if (!(0 > data)) return false + } + return true + })() + return true +}; +return ref0 +``` + +### Warnings + + * `Unprocessed keywords: ["if"] at #/allOf/0` + + +## if with boolean schema true + +### Schema + +```json +{ "if": true, "then": { "const": "then" }, "else": { "const": "else" } } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (!(data === "then")) return false + return true +}; +return ref0 +``` + +### Warnings + + * `some checks are never reachable at #` + + +## if with boolean schema false + +### Schema + +```json +{ "if": false, "then": { "const": "then" }, "else": { "const": "else" } } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (!(data === "else")) return false + return true +}; +return ref0 +``` + +### Warnings + + * `some checks are never reachable at #` + + +## if appears at the end when serialized (keyword processing sequence) + +### Schema + +```json +{ + "then": { "const": "yes" }, + "else": { "const": "other" }, + "if": { "maxLength": 4 } +} +``` + +### Code + +```js +'use strict' +const stringLength = (string) => + /[\uD800-\uDFFF]/.test(string) ? [...string].length : string.length; +const ref0 = function validate(data) { + const sub0 = (() => { + if (typeof data === "string") { + if (data.length > 4 && stringLength(data) > 4) return false + } + return true + })() + if (sub0) { + if (!(data === "yes")) return false + } + else { + if (!(data === "other")) return false + } + return true +}; +return ref0 +``` + diff --git a/doc/samples/draft7/infinite-loop-detection.md b/doc/samples/draft7/infinite-loop-detection.md new file mode 100644 index 0000000..429be5c --- /dev/null +++ b/doc/samples/draft7/infinite-loop-detection.md @@ -0,0 +1,45 @@ +# infinite-loop-detection + +## evaluating the same schema location against the same data location twice is not a sign of an infinite loop + +### Schema + +```json +{ + "definitions": { "int": { "type": "integer" } }, + "allOf": [ + { "properties": { "foo": { "$ref": "#/definitions/int" } } }, + { "additionalProperties": { "$ref": "#/definitions/int" } } + ] +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref1 = function validate(data) { + if (!Number.isInteger(data)) return false + return true +}; +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.foo !== undefined && hasOwn(data, "foo")) { + if (!ref1(data.foo)) return false + } + } + if (typeof data === "object" && data && !Array.isArray(data)) { + for (const key0 of Object.keys(data)) { + if (!ref1(data[key0])) return false + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] if properties is used, required should be specified at #/allOf/0` + diff --git a/doc/samples/draft7/items.md b/doc/samples/draft7/items.md new file mode 100644 index 0000000..4002db9 --- /dev/null +++ b/doc/samples/draft7/items.md @@ -0,0 +1,323 @@ +# items + +## a schema given for items + +### Schema + +```json +{ "items": { "type": "integer" } } +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (Array.isArray(data)) { + for (let i = 0; i < data.length; i++) { + if (data[i] !== undefined && hasOwn(data, i)) { + if (!(Number.isInteger(data[i]))) return false + } + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## an array of schemas for items + +### Schema + +```json +{ "items": [{ "type": "integer" }, { "type": "string" }] } +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (Array.isArray(data)) { + if (data[0] !== undefined && hasOwn(data, 0)) { + if (!(Number.isInteger(data[0]))) return false + } + if (data[1] !== undefined && hasOwn(data, 1)) { + if (!(typeof data[1] === "string")) return false + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireStringValidation] pattern, format or contentSchema should be specified for strings, use pattern: ^[\s\S]*$ to opt-out at #/1` + + +## items with boolean schema (true) + +### Schema + +```json +{ "items": true } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] schema = true is not allowed at #/items` + + +## items with boolean schema (false) + +### Schema + +```json +{ "items": false } +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (Array.isArray(data)) { + for (let i = 0; i < data.length; i++) { + if (data[i] !== undefined && hasOwn(data, i)) return false + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## items with boolean schemas + +### Schema + +```json +{ "items": [true, false] } +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (Array.isArray(data)) { + if (data[1] !== undefined && hasOwn(data, 1)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] schema = true is not allowed at #/0` + + +## items and subitems + +### Schema + +```json +{ + "definitions": { + "item": { + "type": "array", + "additionalItems": false, + "items": [ + { "$ref": "#/definitions/sub-item" }, + { "$ref": "#/definitions/sub-item" } + ] + }, + "sub-item": { "type": "object", "required": ["foo"] } + }, + "type": "array", + "additionalItems": false, + "items": [ + { "$ref": "#/definitions/item" }, + { "$ref": "#/definitions/item" }, + { "$ref": "#/definitions/item" } + ] +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref2 = function validate(data) { + if (!(typeof data === "object" && data && !Array.isArray(data))) return false + if (!(data.foo !== undefined && hasOwn(data, "foo"))) return false + return true +}; +const ref1 = function validate(data) { + if (!Array.isArray(data)) return false + if (data[0] !== undefined && hasOwn(data, 0)) { + if (!ref2(data[0])) return false + } + if (data[1] !== undefined && hasOwn(data, 1)) { + if (!ref2(data[1])) return false + } + if (data.length > 2) return false + return true +}; +const ref0 = function validate(data) { + if (!Array.isArray(data)) return false + if (data[0] !== undefined && hasOwn(data, 0)) { + if (!ref1(data[0])) return false + } + if (data[1] !== undefined && hasOwn(data, 1)) { + if (!ref1(data[1])) return false + } + if (data[2] !== undefined && hasOwn(data, 2)) { + if (!ref1(data[2])) return false + } + if (data.length > 3) return false + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] additionalProperties or unevaluatedProperties should be specified at #` + + +## nested items + +### Schema + +```json +{ + "type": "array", + "items": { + "type": "array", + "items": { + "type": "array", + "items": { "type": "array", "items": { "type": "number" } } + } + } +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (!Array.isArray(data)) return false + for (let i = 0; i < data.length; i++) { + if (data[i] !== undefined && hasOwn(data, i)) { + if (!(Array.isArray(data[i]))) return false + for (let j = 0; j < data[i].length; j++) { + if (data[i][j] !== undefined && hasOwn(data[i], j)) { + if (!(Array.isArray(data[i][j]))) return false + for (let k = 0; k < data[i][j].length; k++) { + if (data[i][j][k] !== undefined && hasOwn(data[i][j], k)) { + if (!(Array.isArray(data[i][j][k]))) return false + for (let l = 0; l < data[i][j][k].length; l++) { + if (data[i][j][k][l] !== undefined && hasOwn(data[i][j][k], l)) { + if (!(typeof data[i][j][k][l] === "number")) return false + } + } + } + } + } + } + } + } + return true +}; +return ref0 +``` + + +## single-form items with null instance elements + +### Schema + +```json +{ "items": { "type": "null" } } +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (Array.isArray(data)) { + for (let i = 0; i < data.length; i++) { + if (data[i] !== undefined && hasOwn(data, i)) { + if (!(data[i] === null)) return false + } + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## array-form items with null instance elements + +### Schema + +```json +{ "items": [{ "type": "null" }] } +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (Array.isArray(data)) { + if (data[0] !== undefined && hasOwn(data, 0)) { + if (!(data[0] === null)) return false + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + diff --git a/doc/samples/draft7/maxItems.md b/doc/samples/draft7/maxItems.md new file mode 100644 index 0000000..42c80fd --- /dev/null +++ b/doc/samples/draft7/maxItems.md @@ -0,0 +1,53 @@ +# maxItems + +## maxItems validation + +### Schema + +```json +{ "maxItems": 2 } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (Array.isArray(data)) { + if (data.length > 2) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## maxItems validation with a decimal + +### Schema + +```json +{ "maxItems": 2 } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (Array.isArray(data)) { + if (data.length > 2) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + diff --git a/doc/samples/draft7/maxLength.md b/doc/samples/draft7/maxLength.md new file mode 100644 index 0000000..6f2f147 --- /dev/null +++ b/doc/samples/draft7/maxLength.md @@ -0,0 +1,57 @@ +# maxLength + +## maxLength validation + +### Schema + +```json +{ "maxLength": 2 } +``` + +### Code + +```js +'use strict' +const stringLength = (string) => + /[\uD800-\uDFFF]/.test(string) ? [...string].length : string.length; +const ref0 = function validate(data) { + if (typeof data === "string") { + if (data.length > 2 && stringLength(data) > 2) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## maxLength validation with a decimal + +### Schema + +```json +{ "maxLength": 2 } +``` + +### Code + +```js +'use strict' +const stringLength = (string) => + /[\uD800-\uDFFF]/.test(string) ? [...string].length : string.length; +const ref0 = function validate(data) { + if (typeof data === "string") { + if (data.length > 2 && stringLength(data) > 2) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + diff --git a/doc/samples/draft7/maxProperties.md b/doc/samples/draft7/maxProperties.md new file mode 100644 index 0000000..d085599 --- /dev/null +++ b/doc/samples/draft7/maxProperties.md @@ -0,0 +1,79 @@ +# maxProperties + +## maxProperties validation + +### Schema + +```json +{ "maxProperties": 2 } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (Object.keys(data).length > 2) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## maxProperties validation with a decimal + +### Schema + +```json +{ "maxProperties": 2 } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (Object.keys(data).length > 2) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## maxProperties = 0 means the object is empty + +### Schema + +```json +{ "maxProperties": 0 } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (Object.keys(data).length > 0) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + diff --git a/doc/samples/draft7/maximum.md b/doc/samples/draft7/maximum.md new file mode 100644 index 0000000..47de30e --- /dev/null +++ b/doc/samples/draft7/maximum.md @@ -0,0 +1,53 @@ +# maximum + +## maximum validation + +### Schema + +```json +{ "maximum": 3 } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (typeof data === "number") { + if (!(3 >= data)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## maximum validation with unsigned integer + +### Schema + +```json +{ "maximum": 300 } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (typeof data === "number") { + if (!(300 >= data)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + diff --git a/doc/samples/draft7/minItems.md b/doc/samples/draft7/minItems.md new file mode 100644 index 0000000..faaa676 --- /dev/null +++ b/doc/samples/draft7/minItems.md @@ -0,0 +1,53 @@ +# minItems + +## minItems validation + +### Schema + +```json +{ "minItems": 1 } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (Array.isArray(data)) { + if (data.length < 1) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## minItems validation with a decimal + +### Schema + +```json +{ "minItems": 1 } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (Array.isArray(data)) { + if (data.length < 1) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + diff --git a/doc/samples/draft7/minLength.md b/doc/samples/draft7/minLength.md new file mode 100644 index 0000000..9e7f30c --- /dev/null +++ b/doc/samples/draft7/minLength.md @@ -0,0 +1,57 @@ +# minLength + +## minLength validation + +### Schema + +```json +{ "minLength": 2 } +``` + +### Code + +```js +'use strict' +const stringLength = (string) => + /[\uD800-\uDFFF]/.test(string) ? [...string].length : string.length; +const ref0 = function validate(data) { + if (typeof data === "string") { + if (data.length < 2 || stringLength(data) < 2) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## minLength validation with a decimal + +### Schema + +```json +{ "minLength": 2 } +``` + +### Code + +```js +'use strict' +const stringLength = (string) => + /[\uD800-\uDFFF]/.test(string) ? [...string].length : string.length; +const ref0 = function validate(data) { + if (typeof data === "string") { + if (data.length < 2 || stringLength(data) < 2) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + diff --git a/doc/samples/draft7/minProperties.md b/doc/samples/draft7/minProperties.md new file mode 100644 index 0000000..072a920 --- /dev/null +++ b/doc/samples/draft7/minProperties.md @@ -0,0 +1,53 @@ +# minProperties + +## minProperties validation + +### Schema + +```json +{ "minProperties": 1 } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (Object.keys(data).length < 1) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## minProperties validation with a decimal + +### Schema + +```json +{ "minProperties": 1 } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (Object.keys(data).length < 1) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + diff --git a/doc/samples/draft7/minimum.md b/doc/samples/draft7/minimum.md new file mode 100644 index 0000000..7adc25c --- /dev/null +++ b/doc/samples/draft7/minimum.md @@ -0,0 +1,53 @@ +# minimum + +## minimum validation + +### Schema + +```json +{ "minimum": 1.1 } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (typeof data === "number") { + if (!(1.1 <= data)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## minimum validation with signed integer + +### Schema + +```json +{ "minimum": -2 } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (typeof data === "number") { + if (!(-2 <= data)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + diff --git a/doc/samples/draft7/multipleOf.md b/doc/samples/draft7/multipleOf.md new file mode 100644 index 0000000..f56f9b8 --- /dev/null +++ b/doc/samples/draft7/multipleOf.md @@ -0,0 +1,116 @@ +# multipleOf + +## by int + +### Schema + +```json +{ "multipleOf": 2 } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (typeof data === "number") { + if (data % 2 !== 0) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## by number + +### Schema + +```json +{ "multipleOf": 1.5 } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (typeof data === "number") { + if (data % 1.5 !== 0) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## by small number + +### Schema + +```json +{ "multipleOf": 0.0001 } +``` + +### Code + +```js +'use strict' +const isMultipleOf = (value, divisor, factor, factorMultiple) => { + if (value % divisor === 0) return true + let multiple = value * factor + if (multiple === Infinity || multiple === -Infinity) multiple = value + if (multiple % factorMultiple === 0) return true + const normal = Math.floor(multiple + 0.5) + return normal / factor === value && normal % factorMultiple === 0 +}; +const ref0 = function validate(data) { + if (typeof data === "number") { + if (!isMultipleOf(data, 0.0001, 1e4, 1)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## float division = inf + +### Schema + +```json +{ "type": "integer", "multipleOf": 0.123456789 } +``` + +### Code + +```js +'use strict' +const isMultipleOf = (value, divisor, factor, factorMultiple) => { + if (value % divisor === 0) return true + let multiple = value * factor + if (multiple === Infinity || multiple === -Infinity) multiple = value + if (multiple % factorMultiple === 0) return true + const normal = Math.floor(multiple + 0.5) + return normal / factor === value && normal % factorMultiple === 0 +}; +const ref0 = function validate(data) { + if (!Number.isInteger(data)) return false + if (!isMultipleOf(data, 0.123456789, 1e9, 123456789)) return false + return true +}; +return ref0 +``` + diff --git a/doc/samples/draft7/not.md b/doc/samples/draft7/not.md new file mode 100644 index 0000000..ba5ee57 --- /dev/null +++ b/doc/samples/draft7/not.md @@ -0,0 +1,163 @@ +# not + +## not + +### Schema + +```json +{ "not": { "type": "integer" } } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + const sub0 = (() => { + if (!Number.isInteger(data)) return false + return true + })() + if (sub0) return false + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## not multiple types + +### Schema + +```json +{ "not": { "type": ["integer", "boolean"] } } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + const sub0 = (() => { + if (!(Number.isInteger(data) || typeof data === "boolean")) return false + return true + })() + if (sub0) return false + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## not more complex schema + +### Schema + +```json +{ "not": { "type": "object", "properties": { "foo": { "type": "string" } } } } +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + const sub0 = (() => { + if (!(typeof data === "object" && data && !Array.isArray(data))) return false + if (data.foo !== undefined && hasOwn(data, "foo")) { + if (!(typeof data.foo === "string")) return false + } + return true + })() + if (sub0) return false + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] if properties is used, required should be specified at #/not` + + +## forbidden property + +### Schema + +```json +{ "properties": { "foo": { "not": {} } } } +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.foo !== undefined && hasOwn(data, "foo")) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #/properties/foo` + + +## not with boolean schema true + +### Schema + +```json +{ "not": true } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + return false + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## not with boolean schema false + +### Schema + +```json +{ "not": false } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + return true +}; +return ref0 +``` + +### Warnings + + * `some checks are never reachable at #` + diff --git a/doc/samples/draft7/oneOf.md b/doc/samples/draft7/oneOf.md new file mode 100644 index 0000000..4d80f08 --- /dev/null +++ b/doc/samples/draft7/oneOf.md @@ -0,0 +1,371 @@ +# oneOf + +## oneOf + +### Schema + +```json +{ "oneOf": [{ "type": "integer" }, { "minimum": 2 }] } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + let passes0 = 0 + const sub0 = (() => { + if (!Number.isInteger(data)) return false + return true + })() + if (sub0) passes0++ + const sub1 = (() => { + if (typeof data === "number") { + if (!(2 <= data)) return false + } + return true + })() + if (sub1) passes0++ + if (passes0 !== 1) return false + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## oneOf with base schema + +### Schema + +```json +{ "type": "string", "oneOf": [{ "minLength": 2 }, { "maxLength": 4 }] } +``` + +### Code + +```js +'use strict' +const stringLength = (string) => + /[\uD800-\uDFFF]/.test(string) ? [...string].length : string.length; +const ref0 = function validate(data) { + if (!(typeof data === "string")) return false + let passes0 = 0 + const sub0 = (() => { + if (data.length < 2 || stringLength(data) < 2) return false + return true + })() + if (sub0) passes0++ + const sub1 = (() => { + if (data.length > 4 && stringLength(data) > 4) return false + return true + })() + if (sub1) passes0++ + if (passes0 !== 1) return false + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireStringValidation] pattern, format or contentSchema should be specified for strings, use pattern: ^[\s\S]*$ to opt-out at #` + + +## oneOf with boolean schemas, all true + +### Schema + +```json +{ "oneOf": [true, true, true] } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + let passes0 = 0 + passes0++ + passes0++ + if (passes0 > 1) return false + passes0++ + if (passes0 !== 1) return false + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## oneOf with boolean schemas, one true + +### Schema + +```json +{ "oneOf": [true, false, false] } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + let passes0 = 0 + passes0++ + if (passes0 > 1) return false + if (passes0 !== 1) return false + return true +}; +return ref0 +``` + +### Warnings + + * `some checks are never reachable at #` + + +## oneOf with boolean schemas, more than one true + +### Schema + +```json +{ "oneOf": [true, true, false] } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + let passes0 = 0 + passes0++ + passes0++ + if (passes0 > 1) return false + if (passes0 !== 1) return false + return true +}; +return ref0 +``` + +### Warnings + + * `some checks are never reachable at #` + + +## oneOf with boolean schemas, all false + +### Schema + +```json +{ "oneOf": [false, false, false] } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + let passes0 = 0 + if (passes0 > 1) return false + if (passes0 !== 1) return false + return true +}; +return ref0 +``` + +### Warnings + + * `some checks are never reachable at #` + + +## oneOf complex types + +### Schema + +```json +{ + "oneOf": [ + { "properties": { "bar": { "type": "integer" } }, "required": ["bar"] }, + { "properties": { "foo": { "type": "string" } }, "required": ["foo"] } + ] +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + let passes0 = 0 + const sub0 = (() => { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (!(data.bar !== undefined && hasOwn(data, "bar"))) return false + if (!Number.isInteger(data.bar)) return false + } + return true + })() + if (sub0) passes0++ + const sub1 = (() => { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (!(data.foo !== undefined && hasOwn(data, "foo"))) return false + if (!(typeof data.foo === "string")) return false + } + return true + })() + if (sub1) passes0++ + if (passes0 !== 1) return false + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireStringValidation] pattern, format or contentSchema should be specified for strings, use pattern: ^[\s\S]*$ to opt-out at #/oneOf/1/properties/foo` + + +## oneOf with empty schema + +### Schema + +```json +{ "oneOf": [{ "type": "number" }, {}] } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + let passes0 = 0 + const sub0 = (() => { + if (!(typeof data === "number")) return false + return true + })() + if (sub0) passes0++ + passes0++ + if (passes0 !== 1) return false + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## oneOf with required + +### Schema + +```json +{ + "type": "object", + "oneOf": [{ "required": ["foo", "bar"] }, { "required": ["foo", "baz"] }] +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (!(typeof data === "object" && data && !Array.isArray(data))) return false + let passes0 = 0 + const sub0 = (() => { + if (!(data.foo !== undefined && hasOwn(data, "foo"))) return false + if (!(data.bar !== undefined && hasOwn(data, "bar"))) return false + return true + })() + if (sub0) passes0++ + const sub1 = (() => { + if (!(data.foo !== undefined && hasOwn(data, "foo"))) return false + if (!(data.baz !== undefined && hasOwn(data, "baz"))) return false + return true + })() + if (sub1) passes0++ + if (passes0 !== 1) return false + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] additionalProperties or unevaluatedProperties should be specified at #` + + +## oneOf with missing optional property + +### Schema + +```json +{ + "oneOf": [ + { "properties": { "bar": true, "baz": true }, "required": ["bar"] }, + { "properties": { "foo": true }, "required": ["foo"] } + ] +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + let passes0 = 0 + const sub0 = (() => { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (!(data.bar !== undefined && hasOwn(data, "bar"))) return false + } + return true + })() + if (sub0) passes0++ + const sub1 = (() => { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (!(data.foo !== undefined && hasOwn(data, "foo"))) return false + } + return true + })() + if (sub1) passes0++ + if (passes0 !== 1) return false + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] schema = true is not allowed at #/oneOf/0/properties/bar` + + +## nested oneOf, to check validation semantics + +### Schema + +```json +{ "oneOf": [{ "oneOf": [{ "type": "null" }] }] } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (!(data === null)) return false + return true +}; +return ref0 +``` + diff --git a/doc/samples/draft7/optional-bignum.md b/doc/samples/draft7/optional-bignum.md new file mode 100644 index 0000000..a9a7ca7 --- /dev/null +++ b/doc/samples/draft7/optional-bignum.md @@ -0,0 +1,169 @@ +# optional/bignum + +## integer + +### Schema + +```json +{ "type": "integer" } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (!Number.isInteger(data)) return false + return true +}; +return ref0 +``` + + +## number + +### Schema + +```json +{ "type": "number" } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (!(typeof data === "number")) return false + return true +}; +return ref0 +``` + + +## string + +### Schema + +```json +{ "type": "string" } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (!(typeof data === "string")) return false + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireStringValidation] pattern, format or contentSchema should be specified for strings, use pattern: ^[\s\S]*$ to opt-out at #` + + +## maximum integer comparison + +### Schema + +```json +{ "maximum": 18446744073709552000 } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (typeof data === "number") { + if (!(18446744073709552000 >= data)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## float comparison with high precision + +### Schema + +```json +{ "exclusiveMaximum": 9.727837981879871e26 } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (typeof data === "number") { + if (!(9.727837981879871e+26 > data)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## minimum integer comparison + +### Schema + +```json +{ "minimum": -18446744073709552000 } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (typeof data === "number") { + if (!(-18446744073709552000 <= data)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## float comparison with high precision on negative numbers + +### Schema + +```json +{ "exclusiveMinimum": -9.727837981879871e26 } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (typeof data === "number") { + if (!(-9.727837981879871e+26 < data)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + diff --git a/doc/samples/draft7/optional-content.md b/doc/samples/draft7/optional-content.md new file mode 100644 index 0000000..66943c1 --- /dev/null +++ b/doc/samples/draft7/optional-content.md @@ -0,0 +1,102 @@ +# optional/content + +## validation of string-encoded content based on media type + +### Schema + +```json +{ "contentMediaType": "application/json" } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (typeof data === "string") { + let dec0 = data + try { + dec0 = JSON.parse(dec0) + } catch (e) { + return false + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## validation of binary string-encoding + +### Schema + +```json +{ "contentEncoding": "base64" } +``` + +### Code + +```js +'use strict' +const format0 = (input) => input.length % 4 === 0 && /^[a-z0-9+/]*={0,3}$/i.test(input); +const ref0 = function validate(data) { + if (typeof data === "string") { + if (!format0(data)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## validation of binary-encoded media type documents + +### Schema + +```json +{ "contentMediaType": "application/json", "contentEncoding": "base64" } +``` + +### Code + +```js +'use strict' +const format0 = (input) => input.length % 4 === 0 && /^[a-z0-9+/]*={0,3}$/i.test(input); +const deBase64 = (string) => { + if (typeof Buffer !== 'undefined') return Buffer.from(string, 'base64').toString('utf-8') + const b = atob(string) + return new TextDecoder('utf-8').decode(new Uint8Array(b.length).map((_, i) => b.charCodeAt(i))) +}; +const ref0 = function validate(data) { + if (typeof data === "string") { + let dec0 = data + if (!format0(data)) return false + try { + dec0 = deBase64(dec0) + try { + dec0 = JSON.parse(dec0) + } catch (e) { + return false + } + } catch (e) { + return false + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + diff --git a/doc/samples/draft7/optional-cross-draft.md b/doc/samples/draft7/optional-cross-draft.md new file mode 100644 index 0000000..ae3f2d5 --- /dev/null +++ b/doc/samples/draft7/optional-cross-draft.md @@ -0,0 +1,39 @@ +# optional/cross-draft + +## refs to future drafts are processed as future drafts + +### Schema + +```json +{ + "type": "object", + "allOf": [ + { "properties": { "foo": true } }, + { "$ref": "http://localhost:1234/draft2019-09/dependentRequired.json" } + ] +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref1 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.foo !== undefined && hasOwn(data, "foo") && !(data.bar !== undefined && hasOwn(data, "bar"))) return false + } + return true +}; +const ref0 = function validate(data) { + if (!(typeof data === "object" && data && !Array.isArray(data))) return false + if (!ref1(data)) return false + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] schema = true is not allowed at #/allOf/0/properties/foo` + diff --git a/doc/samples/draft7/optional-ecmascript-regex.md b/doc/samples/draft7/optional-ecmascript-regex.md new file mode 100644 index 0000000..f67da04 --- /dev/null +++ b/doc/samples/draft7/optional-ecmascript-regex.md @@ -0,0 +1,515 @@ +# optional/ecmascript-regex + +## ECMA 262 regex $ does not match trailing newline + +### Schema + +```json +{ "type": "string", "pattern": "^abc$" } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (!(typeof data === "string")) return false + if (!(data === "abc")) return false + return true +}; +return ref0 +``` + + +## ECMA 262 regex converts \t to horizontal tab + +### Schema + +```json +{ "type": "string", "pattern": "^\\t$" } +``` + +### Code + +```js +'use strict' +const pattern0 = new RegExp("^\\t$", "u"); +const ref0 = function validate(data) { + if (!(typeof data === "string")) return false + if (!pattern0.test(data)) return false + return true +}; +return ref0 +``` + + +## ECMA 262 regex escapes control codes with \c and upper letter + +### Schema + +```json +{ "type": "string", "pattern": "^\\cC$" } +``` + +### Code + +```js +'use strict' +const pattern0 = new RegExp("^\\cC$", "u"); +const ref0 = function validate(data) { + if (!(typeof data === "string")) return false + if (!pattern0.test(data)) return false + return true +}; +return ref0 +``` + + +## ECMA 262 regex escapes control codes with \c and lower letter + +### Schema + +```json +{ "type": "string", "pattern": "^\\cc$" } +``` + +### Code + +```js +'use strict' +const pattern0 = new RegExp("^\\cc$", "u"); +const ref0 = function validate(data) { + if (!(typeof data === "string")) return false + if (!pattern0.test(data)) return false + return true +}; +return ref0 +``` + + +## ECMA 262 \d matches ascii digits only + +### Schema + +```json +{ "type": "string", "pattern": "^\\d$" } +``` + +### Code + +```js +'use strict' +const pattern0 = new RegExp("^\\d$", "u"); +const ref0 = function validate(data) { + if (!(typeof data === "string")) return false + if (!pattern0.test(data)) return false + return true +}; +return ref0 +``` + + +## ECMA 262 \D matches everything but ascii digits + +### Schema + +```json +{ "type": "string", "pattern": "^\\D$" } +``` + +### Code + +```js +'use strict' +const pattern0 = new RegExp("^\\D$", "u"); +const ref0 = function validate(data) { + if (!(typeof data === "string")) return false + if (!pattern0.test(data)) return false + return true +}; +return ref0 +``` + + +## ECMA 262 \w matches ascii letters only + +### Schema + +```json +{ "type": "string", "pattern": "^\\w$" } +``` + +### Code + +```js +'use strict' +const pattern0 = new RegExp("^\\w$", "u"); +const ref0 = function validate(data) { + if (!(typeof data === "string")) return false + if (!pattern0.test(data)) return false + return true +}; +return ref0 +``` + + +## ECMA 262 \W matches everything but ascii letters + +### Schema + +```json +{ "type": "string", "pattern": "^\\W$" } +``` + +### Code + +```js +'use strict' +const pattern0 = new RegExp("^\\W$", "u"); +const ref0 = function validate(data) { + if (!(typeof data === "string")) return false + if (!pattern0.test(data)) return false + return true +}; +return ref0 +``` + + +## ECMA 262 \s matches whitespace + +### Schema + +```json +{ "type": "string", "pattern": "^\\s$" } +``` + +### Code + +```js +'use strict' +const pattern0 = new RegExp("^\\s$", "u"); +const ref0 = function validate(data) { + if (!(typeof data === "string")) return false + if (!pattern0.test(data)) return false + return true +}; +return ref0 +``` + + +## ECMA 262 \S matches everything but whitespace + +### Schema + +```json +{ "type": "string", "pattern": "^\\S$" } +``` + +### Code + +```js +'use strict' +const pattern0 = new RegExp("^\\S$", "u"); +const ref0 = function validate(data) { + if (!(typeof data === "string")) return false + if (!pattern0.test(data)) return false + return true +}; +return ref0 +``` + + +## patterns always use unicode semantics with pattern + +### Schema + +```json +{ "pattern": "\\p{Letter}cole" } +``` + +### Code + +```js +'use strict' +const pattern0 = new RegExp("\\p{Letter}cole", "u"); +const ref0 = function validate(data) { + if (typeof data === "string") { + if (!pattern0.test(data)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `Should start with ^ and end with $: "\\p{Letter}cole" at #` + + +## \w in patterns matches [A-Za-z0-9_], not unicode letters + +### Schema + +```json +{ "pattern": "\\wcole" } +``` + +### Code + +```js +'use strict' +const pattern0 = new RegExp("\\wcole", "u"); +const ref0 = function validate(data) { + if (typeof data === "string") { + if (!pattern0.test(data)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `Should start with ^ and end with $: "\\wcole" at #` + + +## pattern with ASCII ranges + +### Schema + +```json +{ "pattern": "[a-z]cole" } +``` + +### Code + +```js +'use strict' +const pattern0 = new RegExp("[a-z]cole", "u"); +const ref0 = function validate(data) { + if (typeof data === "string") { + if (!pattern0.test(data)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `Should start with ^ and end with $: "[a-z]cole" at #` + + +## \d in pattern matches [0-9], not unicode digits + +### Schema + +```json +{ "pattern": "^\\d+$" } +``` + +### Code + +```js +'use strict' +const pattern0 = new RegExp("^\\d+$", "u"); +const ref0 = function validate(data) { + if (typeof data === "string") { + if (!pattern0.test(data)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## pattern with non-ASCII digits + +### Schema + +```json +{ "pattern": "^\\p{digit}+$" } +``` + +### Code + +```js +'use strict' +const pattern0 = new RegExp("^\\p{digit}+$", "u"); +const ref0 = function validate(data) { + if (typeof data === "string") { + if (!pattern0.test(data)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[complexityChecks] maxLength should be specified for pattern: "^\\p{digit}+$" at #` + + +## patterns always use unicode semantics with patternProperties + +### Schema + +```json +{ + "type": "object", + "patternProperties": { "\\p{Letter}cole": true }, + "additionalProperties": false +} +``` + +### Code + +```js +'use strict' +const pattern0 = new RegExp("\\p{Letter}cole", "u"); +const ref0 = function validate(data) { + if (!(typeof data === "object" && data && !Array.isArray(data))) return false + for (const key1 of Object.keys(data)) { + if (!pattern0.test(key1)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `Should start with ^ and end with $: "\\p{Letter}cole" at #` + + +## \w in patternProperties matches [A-Za-z0-9_], not unicode letters + +### Schema + +```json +{ + "type": "object", + "patternProperties": { "\\wcole": true }, + "additionalProperties": false +} +``` + +### Code + +```js +'use strict' +const pattern0 = new RegExp("\\wcole", "u"); +const ref0 = function validate(data) { + if (!(typeof data === "object" && data && !Array.isArray(data))) return false + for (const key1 of Object.keys(data)) { + if (!pattern0.test(key1)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `Should start with ^ and end with $: "\\wcole" at #` + + +## patternProperties with ASCII ranges + +### Schema + +```json +{ + "type": "object", + "patternProperties": { "[a-z]cole": true }, + "additionalProperties": false +} +``` + +### Code + +```js +'use strict' +const pattern0 = new RegExp("[a-z]cole", "u"); +const ref0 = function validate(data) { + if (!(typeof data === "object" && data && !Array.isArray(data))) return false + for (const key1 of Object.keys(data)) { + if (!pattern0.test(key1)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `Should start with ^ and end with $: "[a-z]cole" at #` + + +## \d in patternProperties matches [0-9], not unicode digits + +### Schema + +```json +{ + "type": "object", + "patternProperties": { "^\\d+$": true }, + "additionalProperties": false +} +``` + +### Code + +```js +'use strict' +const pattern0 = new RegExp("^\\d+$", "u"); +const ref0 = function validate(data) { + if (!(typeof data === "object" && data && !Array.isArray(data))) return false + for (const key1 of Object.keys(data)) { + if (!pattern0.test(key1)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] schema = true is not allowed at #/patternProperties/^\d+$` + + +## patternProperties with non-ASCII digits + +### Schema + +```json +{ + "type": "object", + "patternProperties": { "^\\p{digit}+$": true }, + "additionalProperties": false +} +``` + +### Code + +```js +'use strict' +const pattern0 = new RegExp("^\\p{digit}+$", "u"); +const ref0 = function validate(data) { + if (!(typeof data === "object" && data && !Array.isArray(data))) return false + for (const key1 of Object.keys(data)) { + if (!pattern0.test(key1)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[complexityChecks] maxLength should be specified for pattern: "^\\p{digit}+$" at #` + diff --git a/doc/samples/draft7/optional-float-overflow.md b/doc/samples/draft7/optional-float-overflow.md new file mode 100644 index 0000000..313af9c --- /dev/null +++ b/doc/samples/draft7/optional-float-overflow.md @@ -0,0 +1,22 @@ +# optional/float-overflow + +## all integers are multiples of 0.5, if overflow is handled + +### Schema + +```json +{ "type": "integer", "multipleOf": 0.5 } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (!Number.isInteger(data)) return false + if (data % 0.5 !== 0) return false + return true +}; +return ref0 +``` + diff --git a/doc/samples/draft7/optional-non-bmp-regex.md b/doc/samples/draft7/optional-non-bmp-regex.md new file mode 100644 index 0000000..8d300cd --- /dev/null +++ b/doc/samples/draft7/optional-non-bmp-regex.md @@ -0,0 +1,59 @@ +# optional/non-bmp-regex + +## Proper UTF-16 surrogate pair handling: pattern + +### Schema + +```json +{ "pattern": "^🐲*$" } +``` + +### Code + +```js +'use strict' +const pattern0 = new RegExp("^🐲*$", "u"); +const ref0 = function validate(data) { + if (typeof data === "string") { + if (!pattern0.test(data)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## Proper UTF-16 surrogate pair handling: patternProperties + +### Schema + +```json +{ "patternProperties": { "^🐲*$": { "type": "integer" } } } +``` + +### Code + +```js +'use strict' +const pattern0 = new RegExp("^🐲*$", "u"); +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + for (const key0 of Object.keys(data)) { + if (pattern0.test(key0)) { + if (!(Number.isInteger(data[key0]))) return false + } + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + diff --git a/doc/samples/draft7/pattern.md b/doc/samples/draft7/pattern.md new file mode 100644 index 0000000..07714d8 --- /dev/null +++ b/doc/samples/draft7/pattern.md @@ -0,0 +1,54 @@ +# pattern + +## pattern validation + +### Schema + +```json +{ "pattern": "^a*$" } +``` + +### Code + +```js +'use strict' +const pattern0 = new RegExp("^a*$", "u"); +const ref0 = function validate(data) { + if (typeof data === "string") { + if (!pattern0.test(data)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## pattern is not anchored + +### Schema + +```json +{ "pattern": "a+" } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (typeof data === "string") { + if (!(data.includes("a"))) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `Should start with ^ and end with $: "a+" at #` + diff --git a/doc/samples/draft7/patternProperties.md b/doc/samples/draft7/patternProperties.md new file mode 100644 index 0000000..ebc285b --- /dev/null +++ b/doc/samples/draft7/patternProperties.md @@ -0,0 +1,168 @@ +# patternProperties + +## patternProperties validates properties matching a regex + +### Schema + +```json +{ "patternProperties": { "f.*o": { "type": "integer" } } } +``` + +### Code + +```js +'use strict' +const pattern0 = new RegExp("f.*o", "u"); +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + for (const key0 of Object.keys(data)) { + if (pattern0.test(key0)) { + if (!(Number.isInteger(data[key0]))) return false + } + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `Should start with ^ and end with $: "f.*o" at #` + + +## multiple simultaneous patternProperties are validated + +### Schema + +```json +{ + "patternProperties": { + "a*": { "type": "integer" }, + "aaa*": { "maximum": 20 } + } +} +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + for (const key0 of Object.keys(data)) { + if (!(Number.isInteger(data[key0]))) return false + if (key0.includes("aa")) { + if (typeof data[key0] === "number") { + if (!(20 >= data[key0])) return false + } + } + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `Should start with ^ and end with $: "a*" at #` + + +## regexes are not anchored by default and are case sensitive + +### Schema + +```json +{ + "patternProperties": { + "[0-9]{2,}": { "type": "boolean" }, + "X_": { "type": "string" } + } +} +``` + +### Code + +```js +'use strict' +const pattern0 = new RegExp("[0-9]{2,}", "u"); +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + for (const key0 of Object.keys(data)) { + if (pattern0.test(key0)) { + if (!(typeof data[key0] === "boolean")) return false + } + if (key0.includes("X_")) { + if (!(typeof data[key0] === "string")) return false + } + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `Should start with ^ and end with $: "[0-9]{2,}" at #` + + +## patternProperties with boolean schemas + +### Schema + +```json +{ "patternProperties": { "f.*": true, "b.*": false } } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + for (const key0 of Object.keys(data)) { + if (key0.includes("b")) return false + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `Should start with ^ and end with $: "f.*" at #` + + +## patternProperties with null valued instance properties + +### Schema + +```json +{ "patternProperties": { "^.*bar$": { "type": "null" } } } +``` + +### Code + +```js +'use strict' +const pattern0 = new RegExp("^.*bar$", "u"); +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + for (const key0 of Object.keys(data)) { + if (pattern0.test(key0)) { + if (!(data[key0] === null)) return false + } + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + diff --git a/doc/samples/draft7/properties.md b/doc/samples/draft7/properties.md new file mode 100644 index 0000000..3100ea9 --- /dev/null +++ b/doc/samples/draft7/properties.md @@ -0,0 +1,240 @@ +# properties + +## object properties validation + +### Schema + +```json +{ "properties": { "foo": { "type": "integer" }, "bar": { "type": "string" } } } +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.foo !== undefined && hasOwn(data, "foo")) { + if (!Number.isInteger(data.foo)) return false + } + if (data.bar !== undefined && hasOwn(data, "bar")) { + if (!(typeof data.bar === "string")) return false + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireStringValidation] pattern, format or contentSchema should be specified for strings, use pattern: ^[\s\S]*$ to opt-out at #/properties/bar` + + +## properties, patternProperties, additionalProperties interaction + +### Schema + +```json +{ + "properties": { + "foo": { "type": "array", "maxItems": 3 }, + "bar": { "type": "array" } + }, + "patternProperties": { "f.o": { "minItems": 2 } }, + "additionalProperties": { "type": "integer" } +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const pattern0 = new RegExp("f.o", "u"); +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.foo !== undefined && hasOwn(data, "foo")) { + if (!Array.isArray(data.foo)) return false + if (data.foo.length > 3) return false + } + if (data.bar !== undefined && hasOwn(data, "bar")) { + if (!Array.isArray(data.bar)) return false + } + for (const key0 of Object.keys(data)) { + if (pattern0.test(key0)) { + if (Array.isArray(data[key0])) { + if (data[key0].length < 2) return false + } + } + } + for (const key1 of Object.keys(data)) { + if (key1 !== "foo" && key1 !== "bar" && !pattern0.test(key1)) { + if (!(Number.isInteger(data[key1]))) return false + } + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] items rule should be specified at #/properties/foo` + + +## properties with boolean schema + +### Schema + +```json +{ "properties": { "foo": true, "bar": false } } +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.bar !== undefined && hasOwn(data, "bar")) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] schema = true is not allowed at #/properties/foo` + + +## properties with escaped characters + +### Schema + +```json +{ + "properties": { + "foo\nbar": { "type": "number" }, + "foo\"bar": { "type": "number" }, + "foo\\bar": { "type": "number" }, + "foo\rbar": { "type": "number" }, + "foo\tbar": { "type": "number" }, + "foo\fbar": { "type": "number" } + } +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data["foo\nbar"] !== undefined && hasOwn(data, "foo\nbar")) { + if (!(typeof data["foo\nbar"] === "number")) return false + } + if (data["foo\"bar"] !== undefined && hasOwn(data, "foo\"bar")) { + if (!(typeof data["foo\"bar"] === "number")) return false + } + if (data["foo\\bar"] !== undefined && hasOwn(data, "foo\\bar")) { + if (!(typeof data["foo\\bar"] === "number")) return false + } + if (data["foo\rbar"] !== undefined && hasOwn(data, "foo\rbar")) { + if (!(typeof data["foo\rbar"] === "number")) return false + } + if (data["foo\tbar"] !== undefined && hasOwn(data, "foo\tbar")) { + if (!(typeof data["foo\tbar"] === "number")) return false + } + if (data["foo\fbar"] !== undefined && hasOwn(data, "foo\fbar")) { + if (!(typeof data["foo\fbar"] === "number")) return false + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## properties with null valued instance properties + +### Schema + +```json +{ "properties": { "foo": { "type": "null" } } } +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.foo !== undefined && hasOwn(data, "foo")) { + if (!(data.foo === null)) return false + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## properties whose names are Javascript object property names + +### Schema + +```json +{ + "properties": { + "__proto__": { "type": "number" }, + "toString": { "properties": { "length": { "type": "string" } } }, + "constructor": { "type": "number" } + } +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data["__proto__"] !== undefined && hasOwn(data, "__proto__")) { + if (!(typeof data["__proto__"] === "number")) return false + } + if (data.toString !== undefined && hasOwn(data, "toString")) { + if (typeof data.toString === "object" && data.toString && !Array.isArray(data.toString)) { + if (data.toString.length !== undefined && hasOwn(data.toString, "length")) { + if (!(typeof data.toString.length === "string")) return false + } + } + } + if (data.constructor !== undefined && hasOwn(data, "constructor")) { + if (!(typeof data.constructor === "number")) return false + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireStringValidation] pattern, format or contentSchema should be specified for strings, use pattern: ^[\s\S]*$ to opt-out at #/properties/toString/properties/length` + diff --git a/doc/samples/draft7/propertyNames.md b/doc/samples/draft7/propertyNames.md new file mode 100644 index 0000000..48fec27 --- /dev/null +++ b/doc/samples/draft7/propertyNames.md @@ -0,0 +1,109 @@ +# propertyNames + +## propertyNames validation + +### Schema + +```json +{ "propertyNames": { "maxLength": 3 } } +``` + +### Code + +```js +'use strict' +const stringLength = (string) => + /[\uD800-\uDFFF]/.test(string) ? [...string].length : string.length; +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + for (const key0 of Object.keys(data)) { + if (key0.length > 3 && stringLength(key0) > 3) return false + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireStringValidation] pattern, format or contentSchema should be specified for strings, use pattern: ^[\s\S]*$ to opt-out at #/propertyNames` + + +## propertyNames validation with pattern + +### Schema + +```json +{ "propertyNames": { "pattern": "^a+$" } } +``` + +### Code + +```js +'use strict' +const pattern0 = new RegExp("^a+$", "u"); +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + for (const key0 of Object.keys(data)) { + if (!pattern0.test(key0)) return false + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## propertyNames with boolean schema true + +### Schema + +```json +{ "propertyNames": true } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] schema = true is not allowed at #/propertyNames` + + +## propertyNames with boolean schema false + +### Schema + +```json +{ "propertyNames": false } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + for (const key0 of Object.keys(data)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + diff --git a/doc/samples/draft7/ref.md b/doc/samples/draft7/ref.md new file mode 100644 index 0000000..c2283d0 --- /dev/null +++ b/doc/samples/draft7/ref.md @@ -0,0 +1,1316 @@ +# ref + +## root pointer ref + +### Schema + +```json +{ "properties": { "foo": { "$ref": "#" } }, "additionalProperties": false } +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.foo !== undefined && hasOwn(data, "foo")) { + if (!validate(data.foo)) return false + } + for (const key0 of Object.keys(data)) { + if (key0 !== "foo") return false + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #/properties/foo` + + +## relative pointer ref to object + +### Schema + +```json +{ + "properties": { + "foo": { "type": "integer" }, + "bar": { "$ref": "#/properties/foo" } + } +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref1 = function validate(data) { + if (!Number.isInteger(data)) return false + return true +}; +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.foo !== undefined && hasOwn(data, "foo")) { + if (!Number.isInteger(data.foo)) return false + } + if (data.bar !== undefined && hasOwn(data, "bar")) { + if (!ref1(data.bar)) return false + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## relative pointer ref to array + +### Schema + +```json +{ "items": [{ "type": "integer" }, { "$ref": "#/items/0" }] } +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref1 = function validate(data) { + if (!Number.isInteger(data)) return false + return true +}; +const ref0 = function validate(data) { + if (Array.isArray(data)) { + if (data[0] !== undefined && hasOwn(data, 0)) { + if (!(Number.isInteger(data[0]))) return false + } + if (data[1] !== undefined && hasOwn(data, 1)) { + if (!ref1(data[1])) return false + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## escaped pointer ref + +### Schema + +```json +{ + "definitions": { + "tilde~field": { "type": "integer" }, + "slash/field": { "type": "integer" }, + "percent%field": { "type": "integer" } + }, + "properties": { + "tilde": { "$ref": "#/definitions/tilde~0field" }, + "slash": { "$ref": "#/definitions/slash~1field" }, + "percent": { "$ref": "#/definitions/percent%25field" } + } +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref1 = function validate(data) { + if (!Number.isInteger(data)) return false + return true +}; +const ref2 = function validate(data) { + if (!Number.isInteger(data)) return false + return true +}; +const ref3 = function validate(data) { + if (!Number.isInteger(data)) return false + return true +}; +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.tilde !== undefined && hasOwn(data, "tilde")) { + if (!ref1(data.tilde)) return false + } + if (data.slash !== undefined && hasOwn(data, "slash")) { + if (!ref2(data.slash)) return false + } + if (data.percent !== undefined && hasOwn(data, "percent")) { + if (!ref3(data.percent)) return false + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## nested refs + +### Schema + +```json +{ + "definitions": { + "a": { "type": "integer" }, + "b": { "$ref": "#/definitions/a" }, + "c": { "$ref": "#/definitions/b" } + }, + "allOf": [{ "$ref": "#/definitions/c" }] +} +``` + +### Code + +```js +'use strict' +const ref3 = function validate(data) { + if (!Number.isInteger(data)) return false + return true +}; +const ref2 = function validate(data) { + if (!ref3(data)) return false + return true +}; +const ref1 = function validate(data) { + if (!ref2(data)) return false + return true +}; +const ref0 = function validate(data) { + if (!ref1(data)) return false + return true +}; +return ref0 +``` + + +## ref overrides any sibling keywords + +### Schema + +```json +{ + "definitions": { "reffed": { "type": "array" } }, + "properties": { "foo": { "$ref": "#/definitions/reffed", "maxItems": 2 } } +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref1 = function validate(data) { + if (!Array.isArray(data)) return false + return true +}; +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.foo !== undefined && hasOwn(data, "foo")) { + if (!ref1(data.foo)) return false + } + } + return true +}; +return ref0 +``` + +### Warnings + + * `Unprocessed keywords: ["maxItems"] at #/properties/foo` + + +## $ref prevents a sibling $id from changing the base uri + +### Schema + +```json +{ + "$id": "http://localhost:1234/sibling_id/base/", + "definitions": { + "foo": { + "$id": "http://localhost:1234/sibling_id/foo.json", + "type": "string" + }, + "base_foo": { + "$comment": "this canonical uri is http://localhost:1234/sibling_id/base/foo.json", + "$id": "foo.json", + "type": "number" + } + }, + "allOf": [ + { + "$comment": "$ref resolves to http://localhost:1234/sibling_id/base/foo.json, not http://localhost:1234/sibling_id/foo.json", + "$id": "http://localhost:1234/sibling_id/", + "$ref": "foo.json" + } + ] +} +``` + +### Code + +```js +'use strict' +const ref1 = function validate(data) { + if (!(typeof data === "number")) return false + return true +}; +const ref0 = function validate(data) { + if (!ref1(data)) return false + return true +}; +return ref0 +``` + +### Warnings + + * `Unprocessed keywords: ["$id"] at #/allOf/0` + + +## remote ref, containing refs itself + +### Schema + +```json +{ "$ref": "http://json-schema.org/draft-07/schema#" } +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const format0 = new RegExp("^(?:[a-z][a-z0-9+\\-.]*:)?(?:\\/?\\/(?:(?:[a-z0-9\\-._~!$&'()*+,;=:]|%[0-9a-f]{2})*@)?(?:\\[(?:(?:(?:(?:[0-9a-f]{1,4}:){6}|::(?:[0-9a-f]{1,4}:){5}|(?:[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){4}|(?:(?:[0-9a-f]{1,4}:){0,1}[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){3}|(?:(?:[0-9a-f]{1,4}:){0,2}[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){2}|(?:(?:[0-9a-f]{1,4}:){0,3}[0-9a-f]{1,4})?::[0-9a-f]{1,4}:|(?:(?:[0-9a-f]{1,4}:){0,4}[0-9a-f]{1,4})?::)(?:[0-9a-f]{1,4}:[0-9a-f]{1,4}|(?:(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d\\d?)\\.){3}(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d\\d?))|(?:(?:[0-9a-f]{1,4}:){0,5}[0-9a-f]{1,4})?::[0-9a-f]{1,4}|(?:(?:[0-9a-f]{1,4}:){0,6}[0-9a-f]{1,4})?::)|v[0-9a-f]+\\.[a-z0-9\\-._~!$&'()*+,;=:]+)\\]|(?:(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d\\d?)\\.){3}(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d\\d?)|(?:[a-z0-9\\-._~!$&'()*+,;=]|%[0-9a-f]{2})*)(?::\\d*)?(?:\\/(?:[a-z0-9\\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})*)*|\\/?(?:(?:[a-z0-9\\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})+(?:\\/(?:[a-z0-9\\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})*)*)?)?(?:\\?(?:[a-z0-9\\-._~!$&'()*+,;=:@/?]|%[0-9a-f]{2})*)?(?:#(?:[a-z0-9\\-._~!$&'()*+,;=:@/?]|%[0-9a-f]{2})*)?$", "i"); +const format1 = new RegExp("^[a-z][a-z0-9+\\-.]*:(?:\\/?\\/(?:(?:[a-z0-9\\-._~!$&'()*+,;=:]|%[0-9a-f]{2})*@)?(?:\\[(?:(?:(?:(?:[0-9a-f]{1,4}:){6}|::(?:[0-9a-f]{1,4}:){5}|(?:[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){4}|(?:(?:[0-9a-f]{1,4}:){0,1}[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){3}|(?:(?:[0-9a-f]{1,4}:){0,2}[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){2}|(?:(?:[0-9a-f]{1,4}:){0,3}[0-9a-f]{1,4})?::[0-9a-f]{1,4}:|(?:(?:[0-9a-f]{1,4}:){0,4}[0-9a-f]{1,4})?::)(?:[0-9a-f]{1,4}:[0-9a-f]{1,4}|(?:(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d\\d?)\\.){3}(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d\\d?))|(?:(?:[0-9a-f]{1,4}:){0,5}[0-9a-f]{1,4})?::[0-9a-f]{1,4}|(?:(?:[0-9a-f]{1,4}:){0,6}[0-9a-f]{1,4})?::)|v[0-9a-f]+\\.[a-z0-9\\-._~!$&'()*+,;=:]+)\\]|(?:(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d\\d?)\\.){3}(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d\\d?)|(?:[a-z0-9\\-._~!$&'()*+,;=]|%[0-9a-f]{2})*)(?::\\d*)?(?:\\/(?:[a-z0-9\\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})*)*|\\/?(?:(?:[a-z0-9\\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})+(?:\\/(?:[a-z0-9\\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})*)*)?)(?:\\?(?:[a-z0-9\\-._~!$&'()*+,;=:@/?]|%[0-9a-f]{2})*)?(?:#(?:[a-z0-9\\-._~!$&'()*+,;=:@/?]|%[0-9a-f]{2})*)?$", "i"); +const ref2 = function validate(data) { + if (!Number.isInteger(data)) return false + if (!(0 <= data)) return false + return true +}; +const ref3 = function validate(data) { + if (!ref2(data)) return false + return true +}; +const format2 = (str) => { + if (str.length > 1e5) return false + const Z_ANCHOR = /[^\\]\\Z/ + if (Z_ANCHOR.test(str)) return false + try { + new RegExp(str, 'u') + return true + } catch (e) { + return false + } + }; +const ref4 = function validate(data) { + if (!Array.isArray(data)) return false + if (data.length < 1) return false + for (let j = 0; j < data.length; j++) { + if (data[j] !== undefined && hasOwn(data, j)) { + if (!ref1(data[j])) return false + } + } + return true +}; +const unique = (array) => { + if (array.length < 2) return true + if (array.length === 2) return !deepEqual(array[0], array[1]) + const objects = [] + const primitives = array.length > 20 ? new Set() : null + let primitivesCount = 0 + let pos = 0 + for (const item of array) { + if (typeof item === 'object') { + objects.push(item) + } else if (primitives) { + primitives.add(item) + if (primitives.size !== ++primitivesCount) return false + } else { + if (array.indexOf(item, pos + 1) !== -1) return false + } + pos++ + } + for (let i = 1; i < objects.length; i++) + for (let j = 0; j < i; j++) if (deepEqual(objects[i], objects[j])) return false + return true +}; +const deepEqual = (obj, obj2) => { + if (obj === obj2) return true + if (!obj || !obj2 || typeof obj !== typeof obj2) return false + if (obj !== obj2 && typeof obj !== 'object') return false + + const proto = Object.getPrototypeOf(obj) + if (proto !== Object.getPrototypeOf(obj2)) return false + + if (proto === Array.prototype) { + if (!Array.isArray(obj) || !Array.isArray(obj2)) return false + if (obj.length !== obj2.length) return false + return obj.every((x, i) => deepEqual(x, obj2[i])) + } else if (proto === Object.prototype) { + const [keys, keys2] = [Object.keys(obj), Object.keys(obj2)] + if (keys.length !== keys2.length) return false + const keyset2 = new Set([...keys, ...keys2]) + return keyset2.size === keys.length && keys.every((key) => deepEqual(obj[key], obj2[key])) + } + return false +}; +const ref5 = function validate(data) { + if (!Array.isArray(data)) return false + for (let k = 0; k < data.length; k++) { + if (data[k] !== undefined && hasOwn(data, k)) { + if (!(typeof data[k] === "string")) return false + } + } + if (!unique(data)) return false + return true +}; +const ref6 = function validate(data) { + if (!(data === "array" || data === "boolean" || data === "integer" || data === "null" || data === "number" || data === "object" || data === "string")) return false + return true +}; +const ref1 = function validate(data) { + if (!(typeof data === "object" && data && !Array.isArray(data) || typeof data === "boolean")) return false + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data["$id"] !== undefined && hasOwn(data, "$id")) { + if (!(typeof data["$id"] === "string")) return false + if (!format0.test(data["$id"])) return false + } + if (data["$schema"] !== undefined && hasOwn(data, "$schema")) { + if (!(typeof data["$schema"] === "string")) return false + if (!format1.test(data["$schema"])) return false + } + if (data["$ref"] !== undefined && hasOwn(data, "$ref")) { + if (!(typeof data["$ref"] === "string")) return false + if (!format0.test(data["$ref"])) return false + } + if (data["$comment"] !== undefined && hasOwn(data, "$comment")) { + if (!(typeof data["$comment"] === "string")) return false + } + if (data.title !== undefined && hasOwn(data, "title")) { + if (!(typeof data.title === "string")) return false + } + if (data.description !== undefined && hasOwn(data, "description")) { + if (!(typeof data.description === "string")) return false + } + if (data.readOnly !== undefined && hasOwn(data, "readOnly")) { + if (!(typeof data.readOnly === "boolean")) return false + } + if (data.writeOnly !== undefined && hasOwn(data, "writeOnly")) { + if (!(typeof data.writeOnly === "boolean")) return false + } + if (data.examples !== undefined && hasOwn(data, "examples")) { + if (!Array.isArray(data.examples)) return false + } + if (data.multipleOf !== undefined && hasOwn(data, "multipleOf")) { + if (!(typeof data.multipleOf === "number")) return false + if (!(0 < data.multipleOf)) return false + } + if (data.maximum !== undefined && hasOwn(data, "maximum")) { + if (!(typeof data.maximum === "number")) return false + } + if (data.exclusiveMaximum !== undefined && hasOwn(data, "exclusiveMaximum")) { + if (!(typeof data.exclusiveMaximum === "number")) return false + } + if (data.minimum !== undefined && hasOwn(data, "minimum")) { + if (!(typeof data.minimum === "number")) return false + } + if (data.exclusiveMinimum !== undefined && hasOwn(data, "exclusiveMinimum")) { + if (!(typeof data.exclusiveMinimum === "number")) return false + } + if (data.maxLength !== undefined && hasOwn(data, "maxLength")) { + if (!ref2(data.maxLength)) return false + } + if (data.minLength !== undefined && hasOwn(data, "minLength")) { + if (!ref3(data.minLength)) return false + } + if (data.pattern !== undefined && hasOwn(data, "pattern")) { + if (!(typeof data.pattern === "string")) return false + if (!format2(data.pattern)) return false + } + if (data.additionalItems !== undefined && hasOwn(data, "additionalItems")) { + if (!validate(data.additionalItems)) return false + } + if (data.items !== undefined && hasOwn(data, "items")) { + const sub0 = (() => { + if (!validate(data.items)) return false + return true + })() + if (!sub0) { + const sub1 = (() => { + if (!ref4(data.items)) return false + return true + })() + if (!sub1) return false + } + } + if (data.maxItems !== undefined && hasOwn(data, "maxItems")) { + if (!ref2(data.maxItems)) return false + } + if (data.minItems !== undefined && hasOwn(data, "minItems")) { + if (!ref3(data.minItems)) return false + } + if (data.uniqueItems !== undefined && hasOwn(data, "uniqueItems")) { + if (!(typeof data.uniqueItems === "boolean")) return false + } + if (data.contains !== undefined && hasOwn(data, "contains")) { + if (!validate(data.contains)) return false + } + if (data.maxProperties !== undefined && hasOwn(data, "maxProperties")) { + if (!ref2(data.maxProperties)) return false + } + if (data.minProperties !== undefined && hasOwn(data, "minProperties")) { + if (!ref3(data.minProperties)) return false + } + if (data.required !== undefined && hasOwn(data, "required")) { + if (!ref5(data.required)) return false + } + if (data.additionalProperties !== undefined && hasOwn(data, "additionalProperties")) { + if (!validate(data.additionalProperties)) return false + } + if (data.definitions !== undefined && hasOwn(data, "definitions")) { + if (!(typeof data.definitions === "object" && data.definitions && !Array.isArray(data.definitions))) return false + for (const key0 of Object.keys(data.definitions)) { + if (!validate(data.definitions[key0])) return false + } + } + if (data.properties !== undefined && hasOwn(data, "properties")) { + if (!(typeof data.properties === "object" && data.properties && !Array.isArray(data.properties))) return false + for (const key1 of Object.keys(data.properties)) { + if (!validate(data.properties[key1])) return false + } + } + if (data.patternProperties !== undefined && hasOwn(data, "patternProperties")) { + if (!(typeof data.patternProperties === "object" && data.patternProperties && !Array.isArray(data.patternProperties))) return false + for (const key2 of Object.keys(data.patternProperties)) { + if (!format2(key2)) return false + } + for (const key3 of Object.keys(data.patternProperties)) { + if (!validate(data.patternProperties[key3])) return false + } + } + if (data.dependencies !== undefined && hasOwn(data, "dependencies")) { + if (!(typeof data.dependencies === "object" && data.dependencies && !Array.isArray(data.dependencies))) return false + for (const key4 of Object.keys(data.dependencies)) { + const sub2 = (() => { + if (!validate(data.dependencies[key4])) return false + return true + })() + if (!sub2) { + const sub3 = (() => { + if (!ref5(data.dependencies[key4])) return false + return true + })() + if (!sub3) return false + } + } + } + if (data.propertyNames !== undefined && hasOwn(data, "propertyNames")) { + if (!validate(data.propertyNames)) return false + } + if (data.enum !== undefined && hasOwn(data, "enum")) { + if (!Array.isArray(data.enum)) return false + if (data.enum.length < 1) return false + if (!unique(data.enum)) return false + } + if (data.type !== undefined && hasOwn(data, "type")) { + const sub4 = (() => { + if (!ref6(data.type)) return false + return true + })() + if (!sub4) { + const sub5 = (() => { + if (!Array.isArray(data.type)) return false + if (data.type.length < 1) return false + for (let m = 0; m < data.type.length; m++) { + if (data.type[m] !== undefined && hasOwn(data.type, m)) { + if (!ref6(data.type[m])) return false + } + } + if (!unique(data.type)) return false + return true + })() + if (!sub5) return false + } + } + if (data.format !== undefined && hasOwn(data, "format")) { + if (!(typeof data.format === "string")) return false + } + if (data.contentMediaType !== undefined && hasOwn(data, "contentMediaType")) { + if (!(typeof data.contentMediaType === "string")) return false + } + if (data.contentEncoding !== undefined && hasOwn(data, "contentEncoding")) { + if (!(typeof data.contentEncoding === "string")) return false + } + if (data.if !== undefined && hasOwn(data, "if")) { + if (!validate(data.if)) return false + } + if (data.then !== undefined && hasOwn(data, "then")) { + if (!validate(data.then)) return false + } + if (data.else !== undefined && hasOwn(data, "else")) { + if (!validate(data.else)) return false + } + if (data.allOf !== undefined && hasOwn(data, "allOf")) { + if (!ref4(data.allOf)) return false + } + if (data.anyOf !== undefined && hasOwn(data, "anyOf")) { + if (!ref4(data.anyOf)) return false + } + if (data.oneOf !== undefined && hasOwn(data, "oneOf")) { + if (!ref4(data.oneOf)) return false + } + if (data.not !== undefined && hasOwn(data, "not")) { + if (!validate(data.not)) return false + } + } + return true +}; +const ref0 = function validate(data) { + if (!ref1(data)) return false + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireStringValidation] pattern, format or contentSchema should be specified for strings, use pattern: ^[\s\S]*$ to opt-out at http://json-schema.org/draft-07/schema#/properties/$comment` + + +## property named $ref that is not a reference + +### Schema + +```json +{ "properties": { "$ref": { "type": "string" } } } +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data["$ref"] !== undefined && hasOwn(data, "$ref")) { + if (!(typeof data["$ref"] === "string")) return false + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireStringValidation] pattern, format or contentSchema should be specified for strings, use pattern: ^[\s\S]*$ to opt-out at #/properties/$ref` + + +## property named $ref, containing an actual $ref + +### Schema + +```json +{ + "properties": { "$ref": { "$ref": "#/definitions/is-string" } }, + "definitions": { "is-string": { "type": "string" } } +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref1 = function validate(data) { + if (!(typeof data === "string")) return false + return true +}; +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data["$ref"] !== undefined && hasOwn(data, "$ref")) { + if (!ref1(data["$ref"])) return false + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireStringValidation] pattern, format or contentSchema should be specified for strings, use pattern: ^[\s\S]*$ to opt-out at #` + + +## $ref to boolean schema true + +### Schema + +```json +{ "allOf": [{ "$ref": "#/definitions/bool" }], "definitions": { "bool": true } } +``` + +### Code + +```js +'use strict' +const ref1 = function validate(data) { + return true +}; +const ref0 = function validate(data) { + if (!ref1(data)) return false + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] schema = true is not allowed at #` + + +## $ref to boolean schema false + +### Schema + +```json +{ + "allOf": [{ "$ref": "#/definitions/bool" }], + "definitions": { "bool": false } +} +``` + +### Code + +```js +'use strict' +const ref1 = function validate(data) { + return false + return true +}; +const ref0 = function validate(data) { + if (!ref1(data)) return false + return true +}; +return ref0 +``` + + +## Recursive references between schemas + +### Schema + +```json +{ + "$id": "http://localhost:1234/tree", + "description": "tree of nodes", + "type": "object", + "properties": { + "meta": { "type": "string" }, + "nodes": { "type": "array", "items": { "$ref": "node" } } + }, + "required": ["meta", "nodes"], + "definitions": { + "node": { + "$id": "http://localhost:1234/node", + "description": "node", + "type": "object", + "properties": { + "value": { "type": "number" }, + "subtree": { "$ref": "tree" } + }, + "required": ["value"] + } + } +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref1 = function validate(data) { + if (!(typeof data === "object" && data && !Array.isArray(data))) return false + if (!(data.value !== undefined && hasOwn(data, "value"))) return false + if (!(typeof data.value === "number")) return false + if (data.subtree !== undefined && hasOwn(data, "subtree")) { + if (!ref0(data.subtree)) return false + } + return true +}; +const ref0 = function validate(data) { + if (!(typeof data === "object" && data && !Array.isArray(data))) return false + if (!(data.meta !== undefined && hasOwn(data, "meta"))) return false + if (!(data.nodes !== undefined && hasOwn(data, "nodes"))) return false + if (!(typeof data.meta === "string")) return false + if (!Array.isArray(data.nodes)) return false + for (let i = 0; i < data.nodes.length; i++) { + if (data.nodes[i] !== undefined && hasOwn(data.nodes, i)) { + if (!ref1(data.nodes[i])) return false + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireStringValidation] pattern, format or contentSchema should be specified for strings, use pattern: ^[\s\S]*$ to opt-out at #/properties/meta` + + +## refs with quote + +### Schema + +```json +{ + "properties": { "foo\"bar": { "$ref": "#/definitions/foo%22bar" } }, + "definitions": { "foo\"bar": { "type": "number" } } +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref1 = function validate(data) { + if (!(typeof data === "number")) return false + return true +}; +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data["foo\"bar"] !== undefined && hasOwn(data, "foo\"bar")) { + if (!ref1(data["foo\"bar"])) return false + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## Location-independent identifier + +### Schema + +```json +{ + "allOf": [{ "$ref": "#foo" }], + "definitions": { "A": { "$id": "#foo", "type": "integer" } } +} +``` + +### Code + +```js +'use strict' +const ref1 = function validate(data) { + if (!Number.isInteger(data)) return false + return true +}; +const ref0 = function validate(data) { + if (!ref1(data)) return false + return true +}; +return ref0 +``` + + +## Location-independent identifier with base URI change in subschema + +### Schema + +```json +{ + "$id": "http://localhost:1234/root", + "allOf": [{ "$ref": "http://localhost:1234/nested.json#foo" }], + "definitions": { + "A": { + "$id": "nested.json", + "definitions": { "B": { "$id": "#foo", "type": "integer" } } + } + } +} +``` + +### Code + +```js +'use strict' +const ref1 = function validate(data) { + if (!Number.isInteger(data)) return false + return true +}; +const ref0 = function validate(data) { + if (!ref1(data)) return false + return true +}; +return ref0 +``` + + +## naive replacement of $ref with its destination is not correct + +### Schema + +```json +{ + "definitions": { "a_string": { "type": "string" } }, + "enum": [{ "$ref": "#/definitions/a_string" }] +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (!(typeof data === "object" && data && !Array.isArray(data) && Object.keys(data).length === 1 && hasOwn(data, "$ref") && data["$ref"] === "#/definitions/a_string")) return false + return true +}; +return ref0 +``` + + +## refs with relative uris and defs + +### Schema + +```json +{ + "$id": "http://example.com/schema-relative-uri-defs1.json", + "properties": { + "foo": { + "$id": "schema-relative-uri-defs2.json", + "definitions": { + "inner": { "properties": { "bar": { "type": "string" } } } + }, + "allOf": [{ "$ref": "#/definitions/inner" }] + } + }, + "allOf": [{ "$ref": "schema-relative-uri-defs2.json" }] +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref1 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.bar !== undefined && hasOwn(data, "bar")) { + if (!(typeof data.bar === "string")) return false + } + } + return true +}; +const ref2 = function validate(data) { + if (!ref1(data)) return false + return true +}; +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.foo !== undefined && hasOwn(data, "foo")) { + if (!ref1(data.foo)) return false + } + } + if (!ref2(data)) return false + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireStringValidation] pattern, format or contentSchema should be specified for strings, use pattern: ^[\s\S]*$ to opt-out at http://example.com/schema-relative-uri-defs2.json#/properties/bar` + + +## relative refs with absolute uris and defs + +### Schema + +```json +{ + "$id": "http://example.com/schema-refs-absolute-uris-defs1.json", + "properties": { + "foo": { + "$id": "http://example.com/schema-refs-absolute-uris-defs2.json", + "definitions": { + "inner": { "properties": { "bar": { "type": "string" } } } + }, + "allOf": [{ "$ref": "#/definitions/inner" }] + } + }, + "allOf": [{ "$ref": "schema-refs-absolute-uris-defs2.json" }] +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref1 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.bar !== undefined && hasOwn(data, "bar")) { + if (!(typeof data.bar === "string")) return false + } + } + return true +}; +const ref2 = function validate(data) { + if (!ref1(data)) return false + return true +}; +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.foo !== undefined && hasOwn(data, "foo")) { + if (!ref1(data.foo)) return false + } + } + if (!ref2(data)) return false + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireStringValidation] pattern, format or contentSchema should be specified for strings, use pattern: ^[\s\S]*$ to opt-out at http://example.com/schema-refs-absolute-uris-defs2.json#/properties/bar` + + +## $id must be resolved against nearest parent, not just immediate parent + +### Schema + +```json +{ + "$id": "http://example.com/a.json", + "definitions": { + "x": { + "$id": "http://example.com/b/c.json", + "not": { "definitions": { "y": { "$id": "d.json", "type": "number" } } } + } + }, + "allOf": [{ "$ref": "http://example.com/b/d.json" }] +} +``` + +### Code + +```js +'use strict' +const ref1 = function validate(data) { + if (!(typeof data === "number")) return false + return true +}; +const ref0 = function validate(data) { + if (!ref1(data)) return false + return true +}; +return ref0 +``` + + +## simple URN base URI with $ref via the URN + +### Schema + +```json +{ + "$comment": "URIs do not have to have HTTP(s) schemes", + "$id": "urn:uuid:deadbeef-1234-ffff-ffff-4321feebdaed", + "minimum": 30, + "properties": { + "foo": { "$ref": "urn:uuid:deadbeef-1234-ffff-ffff-4321feebdaed" } + } +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (typeof data === "number") { + if (!(30 <= data)) return false + } + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.foo !== undefined && hasOwn(data, "foo")) { + if (!validate(data.foo)) return false + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #/properties/foo` + + +## simple URN base URI with JSON pointer + +### Schema + +```json +{ + "$comment": "URIs do not have to have HTTP(s) schemes", + "$id": "urn:uuid:deadbeef-1234-00ff-ff00-4321feebdaed", + "properties": { "foo": { "$ref": "#/definitions/bar" } }, + "definitions": { "bar": { "type": "string" } } +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref1 = function validate(data) { + if (!(typeof data === "string")) return false + return true +}; +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.foo !== undefined && hasOwn(data, "foo")) { + if (!ref1(data.foo)) return false + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireStringValidation] pattern, format or contentSchema should be specified for strings, use pattern: ^[\s\S]*$ to opt-out at urn:uuid:deadbeef-1234-00ff-ff00-4321feebdaed#` + + +## URN base URI with NSS + +### Schema + +```json +{ + "$comment": "RFC 8141 §2.2", + "$id": "urn:example:1/406/47452/2", + "properties": { "foo": { "$ref": "#/definitions/bar" } }, + "definitions": { "bar": { "type": "string" } } +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref1 = function validate(data) { + if (!(typeof data === "string")) return false + return true +}; +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.foo !== undefined && hasOwn(data, "foo")) { + if (!ref1(data.foo)) return false + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireStringValidation] pattern, format or contentSchema should be specified for strings, use pattern: ^[\s\S]*$ to opt-out at urn:example:1/406/47452/2#` + + +## URN base URI with r-component + +### Schema + +```json +{ + "$comment": "RFC 8141 §2.3.1", + "$id": "urn:example:foo-bar-baz-qux?+CCResolve:cc=uk", + "properties": { "foo": { "$ref": "#/definitions/bar" } }, + "definitions": { "bar": { "type": "string" } } +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref1 = function validate(data) { + if (!(typeof data === "string")) return false + return true +}; +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.foo !== undefined && hasOwn(data, "foo")) { + if (!ref1(data.foo)) return false + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireStringValidation] pattern, format or contentSchema should be specified for strings, use pattern: ^[\s\S]*$ to opt-out at urn:example:foo-bar-baz-qux?+CCResolve:cc=uk#` + + +## URN base URI with q-component + +### Schema + +```json +{ + "$comment": "RFC 8141 §2.3.2", + "$id": "urn:example:weather?=op=map&lat=39.56&lon=-104.85&datetime=1969-07-21T02:56:15Z", + "properties": { "foo": { "$ref": "#/definitions/bar" } }, + "definitions": { "bar": { "type": "string" } } +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref1 = function validate(data) { + if (!(typeof data === "string")) return false + return true +}; +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.foo !== undefined && hasOwn(data, "foo")) { + if (!ref1(data.foo)) return false + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireStringValidation] pattern, format or contentSchema should be specified for strings, use pattern: ^[\s\S]*$ to opt-out at urn:example:weather?=op=map&lat=39.56&lon=-104.85&datetime=1969-07-21T02:56:15Z#` + + +## URN base URI with URN and JSON pointer ref + +### Schema + +```json +{ + "$id": "urn:uuid:deadbeef-1234-0000-0000-4321feebdaed", + "properties": { + "foo": { + "$ref": "urn:uuid:deadbeef-1234-0000-0000-4321feebdaed#/definitions/bar" + } + }, + "definitions": { "bar": { "type": "string" } } +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref1 = function validate(data) { + if (!(typeof data === "string")) return false + return true +}; +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.foo !== undefined && hasOwn(data, "foo")) { + if (!ref1(data.foo)) return false + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireStringValidation] pattern, format or contentSchema should be specified for strings, use pattern: ^[\s\S]*$ to opt-out at urn:uuid:deadbeef-1234-0000-0000-4321feebdaed#` + + +## URN base URI with URN and anchor ref + +### Schema + +```json +{ + "$id": "urn:uuid:deadbeef-1234-ff00-00ff-4321feebdaed", + "properties": { + "foo": { "$ref": "urn:uuid:deadbeef-1234-ff00-00ff-4321feebdaed#something" } + }, + "definitions": { "bar": { "$id": "#something", "type": "string" } } +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref1 = function validate(data) { + if (!(typeof data === "string")) return false + return true +}; +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.foo !== undefined && hasOwn(data, "foo")) { + if (!ref1(data.foo)) return false + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireStringValidation] pattern, format or contentSchema should be specified for strings, use pattern: ^[\s\S]*$ to opt-out at urn:uuid:deadbeef-1234-ff00-00ff-4321feebdaed#` + diff --git a/doc/samples/draft7/refRemote.md b/doc/samples/draft7/refRemote.md new file mode 100644 index 0000000..9cda6e5 --- /dev/null +++ b/doc/samples/draft7/refRemote.md @@ -0,0 +1,404 @@ +# refRemote + +## remote ref + +### Schema + +```json +{ "$ref": "http://localhost:1234/integer.json" } +``` + +### Code + +```js +'use strict' +const ref1 = function validate(data) { + if (!Number.isInteger(data)) return false + return true +}; +const ref0 = function validate(data) { + if (!ref1(data)) return false + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireSchema] $schema is required at http://localhost:1234/integer.json#` + + +## fragment within remote ref + +### Schema + +```json +{ "$ref": "http://localhost:1234/subSchemas.json#/integer" } +``` + +### Code + +```js +'use strict' +const ref1 = function validate(data) { + if (!Number.isInteger(data)) return false + return true +}; +const ref0 = function validate(data) { + if (!ref1(data)) return false + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireSchema] $schema is required at http://localhost:1234/subSchemas.json#` + + +## ref within remote ref + +### Schema + +```json +{ "$ref": "http://localhost:1234/subSchemas.json#/refToInteger" } +``` + +### Code + +```js +'use strict' +const ref2 = function validate(data) { + if (!Number.isInteger(data)) return false + return true +}; +const ref1 = function validate(data) { + if (!ref2(data)) return false + return true +}; +const ref0 = function validate(data) { + if (!ref1(data)) return false + return true +}; +return ref0 +``` + + +## base URI change + +### Schema + +```json +{ + "$id": "http://localhost:1234/", + "items": { + "$id": "baseUriChange/", + "items": { "$ref": "folderInteger.json" } + } +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref1 = function validate(data) { + if (!Number.isInteger(data)) return false + return true +}; +const ref0 = function validate(data) { + if (Array.isArray(data)) { + for (let i = 0; i < data.length; i++) { + if (data[i] !== undefined && hasOwn(data, i)) { + if (Array.isArray(data[i])) { + for (let j = 0; j < data[i].length; j++) { + if (data[i][j] !== undefined && hasOwn(data[i], j)) { + if (!ref1(data[i][j])) return false + } + } + } + } + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireSchema] $schema is required at http://localhost:1234/baseUriChange/folderInteger.json#` + + +## base URI change - change folder + +### Schema + +```json +{ + "$id": "http://localhost:1234/scope_change_defs1.json", + "type": "object", + "properties": { "list": { "$ref": "#/definitions/baz" } }, + "definitions": { + "baz": { + "$id": "baseUriChangeFolder/", + "type": "array", + "items": { "$ref": "folderInteger.json" } + } + } +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref2 = function validate(data) { + if (!Number.isInteger(data)) return false + return true +}; +const ref1 = function validate(data) { + if (!Array.isArray(data)) return false + for (let i = 0; i < data.length; i++) { + if (data[i] !== undefined && hasOwn(data, i)) { + if (!ref2(data[i])) return false + } + } + return true +}; +const ref0 = function validate(data) { + if (!(typeof data === "object" && data && !Array.isArray(data))) return false + if (data.list !== undefined && hasOwn(data, "list")) { + if (!ref1(data.list)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireSchema] $schema is required at http://localhost:1234/baseUriChangeFolder/folderInteger.json#` + + +## base URI change - change folder in subschema + +### Schema + +```json +{ + "$id": "http://localhost:1234/scope_change_defs2.json", + "type": "object", + "properties": { "list": { "$ref": "#/definitions/baz/definitions/bar" } }, + "definitions": { + "baz": { + "$id": "baseUriChangeFolderInSubschema/", + "definitions": { + "bar": { "type": "array", "items": { "$ref": "folderInteger.json" } } + } + } + } +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref2 = function validate(data) { + if (!Number.isInteger(data)) return false + return true +}; +const ref1 = function validate(data) { + if (!Array.isArray(data)) return false + for (let i = 0; i < data.length; i++) { + if (data[i] !== undefined && hasOwn(data, i)) { + if (!ref2(data[i])) return false + } + } + return true +}; +const ref0 = function validate(data) { + if (!(typeof data === "object" && data && !Array.isArray(data))) return false + if (data.list !== undefined && hasOwn(data, "list")) { + if (!ref1(data.list)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireSchema] $schema is required at http://localhost:1234/baseUriChangeFolderInSubschema/folderInteger.json#` + + +## root ref in remote ref + +### Schema + +```json +{ + "$id": "http://localhost:1234/object", + "type": "object", + "properties": { "name": { "$ref": "name.json#/definitions/orNull" } } +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref2 = function validate(data) { + if (!(typeof data === "string")) return false + return true +}; +const ref1 = function validate(data) { + const sub0 = (() => { + if (!(data === null)) return false + return true + })() + if (!sub0) { + const sub1 = (() => { + if (!ref2(data)) return false + return true + })() + if (!sub1) return false + } + return true +}; +const ref0 = function validate(data) { + if (!(typeof data === "object" && data && !Array.isArray(data))) return false + if (data.name !== undefined && hasOwn(data, "name")) { + if (!ref1(data.name)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireSchema] $schema is required at http://localhost:1234/name.json#` + + +## remote ref with ref to definitions + +### Schema + +```json +{ + "$id": "http://localhost:1234/schema-remote-ref-ref-defs1.json", + "allOf": [{ "$ref": "ref-and-definitions.json" }] +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref2 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.bar !== undefined && hasOwn(data, "bar")) { + if (!(typeof data.bar === "string")) return false + } + } + return true +}; +const ref1 = function validate(data) { + if (!ref2(data)) return false + return true +}; +const ref0 = function validate(data) { + if (!ref1(data)) return false + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireSchema] $schema is required at http://localhost:1234/ref-and-definitions.json#` + + +## Location-independent identifier in remote ref + +### Schema + +```json +{ + "$ref": "http://localhost:1234/locationIndependentIdentifierPre2019.json#/definitions/refToInteger" +} +``` + +### Code + +```js +'use strict' +const ref2 = function validate(data) { + if (!Number.isInteger(data)) return false + return true +}; +const ref1 = function validate(data) { + if (!ref2(data)) return false + return true +}; +const ref0 = function validate(data) { + if (!ref1(data)) return false + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireSchema] $schema is required at http://localhost:1234/locationIndependentIdentifierPre2019.json#` + + +## retrieved nested refs resolve relative to their URI not $id + +### Schema + +```json +{ + "$id": "http://localhost:1234/some-id", + "properties": { "name": { "$ref": "nested/foo-ref-string.json" } } +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref2 = function validate(data) { + if (!(typeof data === "string")) return false + return true +}; +const ref1 = function validate(data) { + if (!(typeof data === "object" && data && !Array.isArray(data))) return false + if (data.foo !== undefined && hasOwn(data, "foo")) { + if (!ref2(data.foo)) return false + } + return true +}; +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (data.name !== undefined && hasOwn(data, "name")) { + if (!ref1(data.name)) return false + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireSchema] $schema is required at http://localhost:1234/nested/foo-ref-string.json#` + diff --git a/doc/samples/draft7/required.md b/doc/samples/draft7/required.md new file mode 100644 index 0000000..8888dab --- /dev/null +++ b/doc/samples/draft7/required.md @@ -0,0 +1,144 @@ +# required + +## required validation + +### Schema + +```json +{ "properties": { "foo": {}, "bar": {} }, "required": ["foo"] } +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (!(data.foo !== undefined && hasOwn(data, "foo"))) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] empty rules node is not allowed at #/properties/foo` + + +## required default validation + +### Schema + +```json +{ "properties": { "foo": {} } } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] empty rules node is not allowed at #/properties/foo` + + +## required with empty array + +### Schema + +```json +{ "properties": { "foo": {} }, "required": [] } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] empty rules node is not allowed at #/properties/foo` + + +## required with escaped characters + +### Schema + +```json +{ + "required": [ + "foo\nbar", + "foo\"bar", + "foo\\bar", + "foo\rbar", + "foo\tbar", + "foo\fbar" + ] +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (!(data["foo\nbar"] !== undefined && hasOwn(data, "foo\nbar"))) return false + if (!(data["foo\"bar"] !== undefined && hasOwn(data, "foo\"bar"))) return false + if (!(data["foo\\bar"] !== undefined && hasOwn(data, "foo\\bar"))) return false + if (!(data["foo\rbar"] !== undefined && hasOwn(data, "foo\rbar"))) return false + if (!(data["foo\tbar"] !== undefined && hasOwn(data, "foo\tbar"))) return false + if (!(data["foo\fbar"] !== undefined && hasOwn(data, "foo\fbar"))) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## required properties whose names are Javascript object property names + +### Schema + +```json +{ "required": ["__proto__", "toString", "constructor"] } +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (typeof data === "object" && data && !Array.isArray(data)) { + if (!(data["__proto__"] !== undefined && hasOwn(data, "__proto__"))) return false + if (!(data.toString !== undefined && hasOwn(data, "toString"))) return false + if (!(data.constructor !== undefined && hasOwn(data, "constructor"))) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + diff --git a/doc/samples/draft7/type.md b/doc/samples/draft7/type.md new file mode 100644 index 0000000..ed839b2 --- /dev/null +++ b/doc/samples/draft7/type.md @@ -0,0 +1,249 @@ +# type + +## integer type matches integers + +### Schema + +```json +{ "type": "integer" } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (!Number.isInteger(data)) return false + return true +}; +return ref0 +``` + + +## number type matches numbers + +### Schema + +```json +{ "type": "number" } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (!(typeof data === "number")) return false + return true +}; +return ref0 +``` + + +## string type matches strings + +### Schema + +```json +{ "type": "string" } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (!(typeof data === "string")) return false + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireStringValidation] pattern, format or contentSchema should be specified for strings, use pattern: ^[\s\S]*$ to opt-out at #` + + +## object type matches objects + +### Schema + +```json +{ "type": "object" } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (!(typeof data === "object" && data && !Array.isArray(data))) return false + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] additionalProperties or unevaluatedProperties should be specified at #` + + +## array type matches arrays + +### Schema + +```json +{ "type": "array" } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (!Array.isArray(data)) return false + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] items rule should be specified at #` + + +## boolean type matches booleans + +### Schema + +```json +{ "type": "boolean" } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (!(typeof data === "boolean")) return false + return true +}; +return ref0 +``` + + +## null type matches only the null object + +### Schema + +```json +{ "type": "null" } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (!(data === null)) return false + return true +}; +return ref0 +``` + + +## multiple types can be specified in an array + +### Schema + +```json +{ "type": ["integer", "string"] } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (!(Number.isInteger(data) || typeof data === "string")) return false + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireStringValidation] pattern, format or contentSchema should be specified for strings, use pattern: ^[\s\S]*$ to opt-out at #` + + +## type as array with one item + +### Schema + +```json +{ "type": ["string"] } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (!(typeof data === "string")) return false + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireStringValidation] pattern, format or contentSchema should be specified for strings, use pattern: ^[\s\S]*$ to opt-out at #` + + +## type: array or object + +### Schema + +```json +{ "type": ["array", "object"] } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (!(Array.isArray(data) || typeof data === "object" && data && !Array.isArray(data))) return false + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] items rule should be specified at #` + + +## type: array, object or null + +### Schema + +```json +{ "type": ["array", "object", "null"] } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + if (!(Array.isArray(data) || typeof data === "object" && data && !Array.isArray(data) || data === null)) return false + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] items rule should be specified at #` + diff --git a/doc/samples/draft7/uniqueItems.md b/doc/samples/draft7/uniqueItems.md new file mode 100644 index 0000000..bd67a27 --- /dev/null +++ b/doc/samples/draft7/uniqueItems.md @@ -0,0 +1,319 @@ +# uniqueItems + +## uniqueItems validation + +### Schema + +```json +{ "uniqueItems": true } +``` + +### Code + +```js +'use strict' +const unique = (array) => { + if (array.length < 2) return true + if (array.length === 2) return !deepEqual(array[0], array[1]) + const objects = [] + const primitives = array.length > 20 ? new Set() : null + let primitivesCount = 0 + let pos = 0 + for (const item of array) { + if (typeof item === 'object') { + objects.push(item) + } else if (primitives) { + primitives.add(item) + if (primitives.size !== ++primitivesCount) return false + } else { + if (array.indexOf(item, pos + 1) !== -1) return false + } + pos++ + } + for (let i = 1; i < objects.length; i++) + for (let j = 0; j < i; j++) if (deepEqual(objects[i], objects[j])) return false + return true +}; +const deepEqual = (obj, obj2) => { + if (obj === obj2) return true + if (!obj || !obj2 || typeof obj !== typeof obj2) return false + if (obj !== obj2 && typeof obj !== 'object') return false + + const proto = Object.getPrototypeOf(obj) + if (proto !== Object.getPrototypeOf(obj2)) return false + + if (proto === Array.prototype) { + if (!Array.isArray(obj) || !Array.isArray(obj2)) return false + if (obj.length !== obj2.length) return false + return obj.every((x, i) => deepEqual(x, obj2[i])) + } else if (proto === Object.prototype) { + const [keys, keys2] = [Object.keys(obj), Object.keys(obj2)] + if (keys.length !== keys2.length) return false + const keyset2 = new Set([...keys, ...keys2]) + return keyset2.size === keys.length && keys.every((key) => deepEqual(obj[key], obj2[key])) + } + return false +}; +const ref0 = function validate(data) { + if (Array.isArray(data)) { + if (!unique(data)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[complexityChecks] maxItems should be specified for non-primitive uniqueItems at #` + + +## uniqueItems with an array of items + +### Schema + +```json +{ "items": [{ "type": "boolean" }, { "type": "boolean" }], "uniqueItems": true } +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const unique = (array) => { + if (array.length < 2) return true + if (array.length === 2) return !deepEqual(array[0], array[1]) + const objects = [] + const primitives = array.length > 20 ? new Set() : null + let primitivesCount = 0 + let pos = 0 + for (const item of array) { + if (typeof item === 'object') { + objects.push(item) + } else if (primitives) { + primitives.add(item) + if (primitives.size !== ++primitivesCount) return false + } else { + if (array.indexOf(item, pos + 1) !== -1) return false + } + pos++ + } + for (let i = 1; i < objects.length; i++) + for (let j = 0; j < i; j++) if (deepEqual(objects[i], objects[j])) return false + return true +}; +const deepEqual = (obj, obj2) => { + if (obj === obj2) return true + if (!obj || !obj2 || typeof obj !== typeof obj2) return false + if (obj !== obj2 && typeof obj !== 'object') return false + + const proto = Object.getPrototypeOf(obj) + if (proto !== Object.getPrototypeOf(obj2)) return false + + if (proto === Array.prototype) { + if (!Array.isArray(obj) || !Array.isArray(obj2)) return false + if (obj.length !== obj2.length) return false + return obj.every((x, i) => deepEqual(x, obj2[i])) + } else if (proto === Object.prototype) { + const [keys, keys2] = [Object.keys(obj), Object.keys(obj2)] + if (keys.length !== keys2.length) return false + const keyset2 = new Set([...keys, ...keys2]) + return keyset2.size === keys.length && keys.every((key) => deepEqual(obj[key], obj2[key])) + } + return false +}; +const ref0 = function validate(data) { + if (Array.isArray(data)) { + if (data[0] !== undefined && hasOwn(data, 0)) { + if (!(typeof data[0] === "boolean")) return false + } + if (data[1] !== undefined && hasOwn(data, 1)) { + if (!(typeof data[1] === "boolean")) return false + } + if (!unique(data)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[complexityChecks] maxItems should be specified for non-primitive uniqueItems at #` + + +## uniqueItems with an array of items and additionalItems=false + +### Schema + +```json +{ + "items": [{ "type": "boolean" }, { "type": "boolean" }], + "uniqueItems": true, + "additionalItems": false +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const unique = (array) => { + if (array.length < 2) return true + if (array.length === 2) return !deepEqual(array[0], array[1]) + const objects = [] + const primitives = array.length > 20 ? new Set() : null + let primitivesCount = 0 + let pos = 0 + for (const item of array) { + if (typeof item === 'object') { + objects.push(item) + } else if (primitives) { + primitives.add(item) + if (primitives.size !== ++primitivesCount) return false + } else { + if (array.indexOf(item, pos + 1) !== -1) return false + } + pos++ + } + for (let i = 1; i < objects.length; i++) + for (let j = 0; j < i; j++) if (deepEqual(objects[i], objects[j])) return false + return true +}; +const deepEqual = (obj, obj2) => { + if (obj === obj2) return true + if (!obj || !obj2 || typeof obj !== typeof obj2) return false + if (obj !== obj2 && typeof obj !== 'object') return false + + const proto = Object.getPrototypeOf(obj) + if (proto !== Object.getPrototypeOf(obj2)) return false + + if (proto === Array.prototype) { + if (!Array.isArray(obj) || !Array.isArray(obj2)) return false + if (obj.length !== obj2.length) return false + return obj.every((x, i) => deepEqual(x, obj2[i])) + } else if (proto === Object.prototype) { + const [keys, keys2] = [Object.keys(obj), Object.keys(obj2)] + if (keys.length !== keys2.length) return false + const keyset2 = new Set([...keys, ...keys2]) + return keyset2.size === keys.length && keys.every((key) => deepEqual(obj[key], obj2[key])) + } + return false +}; +const ref0 = function validate(data) { + if (Array.isArray(data)) { + if (data[0] !== undefined && hasOwn(data, 0)) { + if (!(typeof data[0] === "boolean")) return false + } + if (data[1] !== undefined && hasOwn(data, 1)) { + if (!(typeof data[1] === "boolean")) return false + } + if (data.length > 2) return false + if (!unique(data)) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## uniqueItems=false validation + +### Schema + +```json +{ "uniqueItems": false } +``` + +### Code + +```js +'use strict' +const ref0 = function validate(data) { + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## uniqueItems=false with an array of items + +### Schema + +```json +{ + "items": [{ "type": "boolean" }, { "type": "boolean" }], + "uniqueItems": false +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (Array.isArray(data)) { + if (data[0] !== undefined && hasOwn(data, 0)) { + if (!(typeof data[0] === "boolean")) return false + } + if (data[1] !== undefined && hasOwn(data, 1)) { + if (!(typeof data[1] === "boolean")) return false + } + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + + +## uniqueItems=false with an array of items and additionalItems=false + +### Schema + +```json +{ + "items": [{ "type": "boolean" }, { "type": "boolean" }], + "uniqueItems": false, + "additionalItems": false +} +``` + +### Code + +```js +'use strict' +const hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); +const ref0 = function validate(data) { + if (Array.isArray(data)) { + if (data[0] !== undefined && hasOwn(data, 0)) { + if (!(typeof data[0] === "boolean")) return false + } + if (data[1] !== undefined && hasOwn(data, 1)) { + if (!(typeof data[1] === "boolean")) return false + } + if (data.length > 2) return false + } + return true +}; +return ref0 +``` + +##### Strong mode notices + + * `[requireValidation] type should be specified at #` + diff --git a/doc/samples/draft7/unknownKeyword.md b/doc/samples/draft7/unknownKeyword.md new file mode 100644 index 0000000..f0ef772 --- /dev/null +++ b/doc/samples/draft7/unknownKeyword.md @@ -0,0 +1,91 @@ +# unknownKeyword + +## $id inside an unknown keyword is not a real identifier + +### Schema + +```json +{ + "definitions": { + "id_in_unknown0": { + "not": { + "array_of_schemas": [ + { + "$id": "https://localhost:1234/unknownKeyword/my_identifier.json", + "type": "null" + } + ] + } + }, + "real_id_in_schema": { + "$id": "https://localhost:1234/unknownKeyword/my_identifier.json", + "type": "string" + }, + "id_in_unknown1": { + "not": { + "object_of_schemas": { + "foo": { + "$id": "https://localhost:1234/unknownKeyword/my_identifier.json", + "type": "integer" + } + } + } + } + }, + "anyOf": [ + { "$ref": "#/definitions/id_in_unknown0" }, + { "$ref": "#/definitions/id_in_unknown1" }, + { "$ref": "https://localhost:1234/unknownKeyword/my_identifier.json" } + ] +} +``` + +### Code + +```js +'use strict' +const ref1 = function validate(data) { + const sub1 = (() => { + return true + })() + if (sub1) return false + return true +}; +const ref2 = function validate(data) { + const sub3 = (() => { + return true + })() + if (sub3) return false + return true +}; +const ref3 = function validate(data) { + if (!(typeof data === "string")) return false + return true +}; +const ref0 = function validate(data) { + const sub0 = (() => { + if (!ref1(data)) return false + return true + })() + if (!sub0) { + const sub2 = (() => { + if (!ref2(data)) return false + return true + })() + if (!sub2) { + const sub4 = (() => { + if (!ref3(data)) return false + return true + })() + if (!sub4) return false + } + } + return true +}; +return ref0 +``` + +### Warnings + + * `Keyword not supported: "array_of_schemas" at #/not` + diff --git a/doc/samples/util/generate.js b/doc/samples/util/generate.js index a22f533..6ad8b0d 100644 --- a/doc/samples/util/generate.js +++ b/doc/samples/util/generate.js @@ -1,16 +1,21 @@ 'use strict' const { mkdirSync, readdirSync, readFileSync, writeFileSync } = require('fs') +const assert = require('assert').strict const path = require('path') const { format: prettify } = require('prettier') const { validator } = require('../../../') const schemas = require('../../../test/util/schemas') +const { schemaVersions } = require('../../../src/known-keywords') const version = process.argv[2] || '2019-09' -const versionName = `draft${version}` -const versionUrl = `https://json-schema.org/draft/${version}/schema` +const versionName = `draft${['next'].includes(version) ? `-${version}` : version}` +const versionDraft = `draft${/^\d$/.test(version) ? '-0' : '/'}${version}` +const versionUrl = `https://json-schema.org/${versionDraft}/schema` const dir = path.join(__dirname, '../../../test/JSON-Schema-Test-Suite/tests', versionName) +assert(schemaVersions.includes(versionUrl), 'Unknown schema version') + mkdirSync(versionName, { recursive: true }) function processSchema(block) {