feat(json-schema-2020-12): add support for validation keywords for numbers (#8624)
Includes following keywords: - multipleOf - minimum - maximum - inclusiveMinimum - inclusiveMaximum Refs #8513
This commit is contained in:
@@ -31,6 +31,7 @@ const JSONSchema = forwardRef(({ schema, name, onExpand }, ref) => {
|
|||||||
const isExpandable = fn.isExpandable(schema)
|
const isExpandable = fn.isExpandable(schema)
|
||||||
const isCircular = useIsCircular(schema)
|
const isCircular = useIsCircular(schema)
|
||||||
const renderedSchemas = useRenderedSchemas(schema)
|
const renderedSchemas = useRenderedSchemas(schema)
|
||||||
|
const constraints = fn.stringifyConstraints(schema)
|
||||||
const Accordion = useComponent("Accordion")
|
const Accordion = useComponent("Accordion")
|
||||||
const Keyword$schema = useComponent("Keyword$schema")
|
const Keyword$schema = useComponent("Keyword$schema")
|
||||||
const Keyword$vocabulary = useComponent("Keyword$vocabulary")
|
const Keyword$vocabulary = useComponent("Keyword$vocabulary")
|
||||||
@@ -65,6 +66,7 @@ const JSONSchema = forwardRef(({ schema, name, onExpand }, ref) => {
|
|||||||
const KeywordType = useComponent("KeywordType")
|
const KeywordType = useComponent("KeywordType")
|
||||||
const KeywordEnum = useComponent("KeywordEnum")
|
const KeywordEnum = useComponent("KeywordEnum")
|
||||||
const KeywordConst = useComponent("KeywordConst")
|
const KeywordConst = useComponent("KeywordConst")
|
||||||
|
const KeywordConstraint = useComponent("KeywordConstraint")
|
||||||
const KeywordFormat = useComponent("KeywordFormat")
|
const KeywordFormat = useComponent("KeywordFormat")
|
||||||
const KeywordTitle = useComponent("KeywordTitle")
|
const KeywordTitle = useComponent("KeywordTitle")
|
||||||
const KeywordDescription = useComponent("KeywordDescription")
|
const KeywordDescription = useComponent("KeywordDescription")
|
||||||
@@ -129,6 +131,10 @@ const JSONSchema = forwardRef(({ schema, name, onExpand }, ref) => {
|
|||||||
)}
|
)}
|
||||||
<KeywordType schema={schema} isCircular={isCircular} />
|
<KeywordType schema={schema} isCircular={isCircular} />
|
||||||
<KeywordFormat schema={schema} />
|
<KeywordFormat schema={schema} />
|
||||||
|
{constraints.length > 0 &&
|
||||||
|
constraints.map((constraint) => (
|
||||||
|
<KeywordConstraint key={constraint} constraint={constraint} />
|
||||||
|
))}
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
className={classNames("json-schema-2020-12-body", {
|
className={classNames("json-schema-2020-12-body", {
|
||||||
|
|||||||
@@ -25,23 +25,6 @@
|
|||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&__limit {
|
|
||||||
@include text_code();
|
|
||||||
margin-left: 10px;
|
|
||||||
line-height: 1.5;
|
|
||||||
padding: 1px;
|
|
||||||
color: white;
|
|
||||||
background-color: #805AD5;
|
|
||||||
border-radius: 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
//&-note {
|
|
||||||
// @include text_headline($section-models-model-title-font-color);
|
|
||||||
// padding: 10px 0 0 20px;
|
|
||||||
// font-size: 11px;
|
|
||||||
// color: #6b6b6b;
|
|
||||||
//}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,19 @@
|
|||||||
|
/**
|
||||||
|
* @prettier
|
||||||
|
*/
|
||||||
|
import React from "react"
|
||||||
|
import PropTypes from "prop-types"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This component represents various constraint keywords
|
||||||
|
* from JSON Schema 2020-12 validation vocabulary.
|
||||||
|
*/
|
||||||
|
const Constraint = ({ constraint }) => (
|
||||||
|
<span className="json-schema-2020-12__constraint">{constraint}</span>
|
||||||
|
)
|
||||||
|
|
||||||
|
Constraint.propTypes = {
|
||||||
|
constraint: PropTypes.string.isRequired,
|
||||||
|
}
|
||||||
|
|
||||||
|
export default React.memo(Constraint)
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
.json-schema-2020-12__constraint {
|
||||||
|
@include text_code();
|
||||||
|
margin-left: 10px;
|
||||||
|
line-height: 1.5;
|
||||||
|
padding: 1px 3px;
|
||||||
|
color: white;
|
||||||
|
background-color: #805AD5;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
@include text_code();
|
@include text_code();
|
||||||
margin-left: 10px;
|
margin-left: 10px;
|
||||||
line-height: 1.5;
|
line-height: 1.5;
|
||||||
padding: 1px;
|
padding: 1px 3px;
|
||||||
color: white;
|
color: white;
|
||||||
background-color: #D69E2E;
|
background-color: #D69E2E;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
|
|||||||
@@ -67,3 +67,4 @@
|
|||||||
@import './Properties/properties';
|
@import './Properties/properties';
|
||||||
@import './PatternProperties/pattern-properties';
|
@import './PatternProperties/pattern-properties';
|
||||||
@import './Enum/enum';
|
@import './Enum/enum';
|
||||||
|
@import './Constraint/constraint';
|
||||||
|
|||||||
@@ -179,3 +179,67 @@ export const stringify = (value) => {
|
|||||||
|
|
||||||
return JSON.stringify(value)
|
return JSON.stringify(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const stringifyConstraintMultipleOf = (schema) => {
|
||||||
|
if (typeof schema?.multipleOf !== "number") return null
|
||||||
|
if (schema.multipleOf <= 0) return null
|
||||||
|
if (schema.multipleOf === 1) return null
|
||||||
|
|
||||||
|
const { multipleOf } = schema
|
||||||
|
|
||||||
|
if (Number.isInteger(multipleOf)) {
|
||||||
|
return `multiple of ${multipleOf}`
|
||||||
|
}
|
||||||
|
|
||||||
|
const decimalPlaces = multipleOf.toString().split(".")[1].length
|
||||||
|
const factor = 10 ** decimalPlaces
|
||||||
|
const numerator = multipleOf * factor
|
||||||
|
const denominator = factor
|
||||||
|
return `multiple of ${numerator}/${denominator}`
|
||||||
|
}
|
||||||
|
|
||||||
|
const stringifyConstraintNumberRange = (schema) => {
|
||||||
|
const minimum = schema?.minimum
|
||||||
|
const maximum = schema?.maximum
|
||||||
|
const exclusiveMinimum = schema?.exclusiveMinimum
|
||||||
|
const exclusiveMaximum = schema?.exclusiveMaximum
|
||||||
|
const hasMinimum = typeof minimum === "number"
|
||||||
|
const hasMaximum = typeof maximum === "number"
|
||||||
|
const hasExclusiveMinimum = typeof exclusiveMinimum === "number"
|
||||||
|
const hasExclusiveMaximum = typeof exclusiveMaximum === "number"
|
||||||
|
const isMinExclusive = hasExclusiveMinimum && minimum < exclusiveMinimum
|
||||||
|
const isMaxExclusive = hasExclusiveMaximum && maximum > exclusiveMaximum
|
||||||
|
|
||||||
|
if (hasMinimum && hasMaximum) {
|
||||||
|
const minSymbol = isMinExclusive ? "(" : "["
|
||||||
|
const maxSymbol = isMaxExclusive ? ")" : "]"
|
||||||
|
const minValue = isMinExclusive ? exclusiveMinimum : minimum
|
||||||
|
const maxValue = isMaxExclusive ? exclusiveMaximum : maximum
|
||||||
|
return `${minSymbol}${minValue}, ${maxValue}${maxSymbol}`
|
||||||
|
}
|
||||||
|
if (hasMinimum) {
|
||||||
|
const minSymbol = isMinExclusive ? ">" : "≥"
|
||||||
|
const minValue = isMinExclusive ? exclusiveMinimum : minimum
|
||||||
|
return `${minSymbol} ${minValue}`
|
||||||
|
}
|
||||||
|
if (hasMaximum) {
|
||||||
|
const maxSymbol = isMaxExclusive ? "<" : "≤"
|
||||||
|
const maxValue = isMaxExclusive ? exclusiveMaximum : maximum
|
||||||
|
return `${maxSymbol} ${maxValue}`
|
||||||
|
}
|
||||||
|
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
export const stringifyConstraints = (schema) => {
|
||||||
|
const constraints = []
|
||||||
|
|
||||||
|
// Validation Keywords for Numeric Instances (number and integer)
|
||||||
|
const constraintMultipleOf = stringifyConstraintMultipleOf(schema)
|
||||||
|
if (constraintMultipleOf !== null) constraints.push(constraintMultipleOf)
|
||||||
|
|
||||||
|
const constraintNumberRange = stringifyConstraintNumberRange(schema)
|
||||||
|
if (constraintNumberRange !== null) constraints.push(constraintNumberRange)
|
||||||
|
|
||||||
|
return constraints
|
||||||
|
}
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ import KeywordUnevaluatedProperties from "./components/keywords/UnevaluatedPrope
|
|||||||
import KeywordType from "./components/keywords/Type/Type"
|
import KeywordType from "./components/keywords/Type/Type"
|
||||||
import KeywordEnum from "./components/keywords/Enum/Enum"
|
import KeywordEnum from "./components/keywords/Enum/Enum"
|
||||||
import KeywordConst from "./components/keywords/Const"
|
import KeywordConst from "./components/keywords/Const"
|
||||||
|
import KeywordConstraint from "./components/keywords/Constraint/Constraint"
|
||||||
import KeywordFormat from "./components/keywords/Format/Format"
|
import KeywordFormat from "./components/keywords/Format/Format"
|
||||||
import KeywordTitle from "./components/keywords/Title/Title"
|
import KeywordTitle from "./components/keywords/Title/Title"
|
||||||
import KeywordDescription from "./components/keywords/Description/Description"
|
import KeywordDescription from "./components/keywords/Description/Description"
|
||||||
@@ -48,6 +49,7 @@ import {
|
|||||||
hasKeyword,
|
hasKeyword,
|
||||||
isExpandable,
|
isExpandable,
|
||||||
stringify,
|
stringify,
|
||||||
|
stringifyConstraints,
|
||||||
} from "./fn"
|
} from "./fn"
|
||||||
|
|
||||||
export const withJSONSchemaContext = (Component, overrides = {}) => {
|
export const withJSONSchemaContext = (Component, overrides = {}) => {
|
||||||
@@ -83,6 +85,7 @@ export const withJSONSchemaContext = (Component, overrides = {}) => {
|
|||||||
KeywordType,
|
KeywordType,
|
||||||
KeywordEnum,
|
KeywordEnum,
|
||||||
KeywordConst,
|
KeywordConst,
|
||||||
|
KeywordConstraint,
|
||||||
KeywordFormat,
|
KeywordFormat,
|
||||||
KeywordTitle,
|
KeywordTitle,
|
||||||
KeywordDescription,
|
KeywordDescription,
|
||||||
@@ -112,6 +115,7 @@ export const withJSONSchemaContext = (Component, overrides = {}) => {
|
|||||||
hasKeyword,
|
hasKeyword,
|
||||||
isExpandable,
|
isExpandable,
|
||||||
stringify,
|
stringify,
|
||||||
|
stringifyConstraints,
|
||||||
...overrides.fn,
|
...overrides.fn,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ import KeywordUnevaluatedProperties from "./components/keywords/UnevaluatedPrope
|
|||||||
import KeywordType from "./components/keywords/Type/Type"
|
import KeywordType from "./components/keywords/Type/Type"
|
||||||
import KeywordEnum from "./components/keywords/Enum/Enum"
|
import KeywordEnum from "./components/keywords/Enum/Enum"
|
||||||
import KeywordConst from "./components/keywords/Const"
|
import KeywordConst from "./components/keywords/Const"
|
||||||
|
import KeywordConstraint from "./components/keywords/Constraint/Constraint"
|
||||||
import KeywordFormat from "./components/keywords/Format/Format"
|
import KeywordFormat from "./components/keywords/Format/Format"
|
||||||
import KeywordTitle from "./components/keywords/Title/Title"
|
import KeywordTitle from "./components/keywords/Title/Title"
|
||||||
import KeywordDescription from "./components/keywords/Description/Description"
|
import KeywordDescription from "./components/keywords/Description/Description"
|
||||||
@@ -72,6 +73,7 @@ const JSONSchema202012Plugin = () => ({
|
|||||||
JSONSchema202012KeywordType: KeywordType,
|
JSONSchema202012KeywordType: KeywordType,
|
||||||
JSONSchema202012KeywordEnum: KeywordEnum,
|
JSONSchema202012KeywordEnum: KeywordEnum,
|
||||||
JSONSchema202012KeywordConst: KeywordConst,
|
JSONSchema202012KeywordConst: KeywordConst,
|
||||||
|
JSONSchema202012KeywordConstraint: KeywordConstraint,
|
||||||
JSONSchema202012KeywordFormat: KeywordFormat,
|
JSONSchema202012KeywordFormat: KeywordFormat,
|
||||||
JSONSchema202012KeywordTitle: KeywordTitle,
|
JSONSchema202012KeywordTitle: KeywordTitle,
|
||||||
JSONSchema202012KeywordDescription: KeywordDescription,
|
JSONSchema202012KeywordDescription: KeywordDescription,
|
||||||
|
|||||||
@@ -58,6 +58,7 @@ const ModelsWrapper = createOnlyOAS31ComponentWrapper(({ getSystem }) => {
|
|||||||
const KeywordType = getComponent("JSONSchema202012KeywordType")
|
const KeywordType = getComponent("JSONSchema202012KeywordType")
|
||||||
const KeywordEnum = getComponent("JSONSchema202012KeywordEnum")
|
const KeywordEnum = getComponent("JSONSchema202012KeywordEnum")
|
||||||
const KeywordConst = getComponent("JSONSchema202012KeywordConst")
|
const KeywordConst = getComponent("JSONSchema202012KeywordConst")
|
||||||
|
const KeywordConstraint = getComponent("JSONSchema202012KeywordConstraint")
|
||||||
const KeywordFormat = getComponent("JSONSchema202012KeywordFormat")
|
const KeywordFormat = getComponent("JSONSchema202012KeywordFormat")
|
||||||
const KeywordTitle = getComponent("JSONSchema202012KeywordTitle")
|
const KeywordTitle = getComponent("JSONSchema202012KeywordTitle")
|
||||||
const KeywordDescription = getComponent(
|
const KeywordDescription = getComponent(
|
||||||
@@ -105,6 +106,7 @@ const ModelsWrapper = createOnlyOAS31ComponentWrapper(({ getSystem }) => {
|
|||||||
KeywordType,
|
KeywordType,
|
||||||
KeywordEnum,
|
KeywordEnum,
|
||||||
KeywordConst,
|
KeywordConst,
|
||||||
|
KeywordConstraint,
|
||||||
KeywordFormat,
|
KeywordFormat,
|
||||||
KeywordTitle,
|
KeywordTitle,
|
||||||
KeywordDescription,
|
KeywordDescription,
|
||||||
|
|||||||
Reference in New Issue
Block a user