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 isCircular = useIsCircular(schema)
|
||||
const renderedSchemas = useRenderedSchemas(schema)
|
||||
const constraints = fn.stringifyConstraints(schema)
|
||||
const Accordion = useComponent("Accordion")
|
||||
const Keyword$schema = useComponent("Keyword$schema")
|
||||
const Keyword$vocabulary = useComponent("Keyword$vocabulary")
|
||||
@@ -65,6 +66,7 @@ const JSONSchema = forwardRef(({ schema, name, onExpand }, ref) => {
|
||||
const KeywordType = useComponent("KeywordType")
|
||||
const KeywordEnum = useComponent("KeywordEnum")
|
||||
const KeywordConst = useComponent("KeywordConst")
|
||||
const KeywordConstraint = useComponent("KeywordConstraint")
|
||||
const KeywordFormat = useComponent("KeywordFormat")
|
||||
const KeywordTitle = useComponent("KeywordTitle")
|
||||
const KeywordDescription = useComponent("KeywordDescription")
|
||||
@@ -129,6 +131,10 @@ const JSONSchema = forwardRef(({ schema, name, onExpand }, ref) => {
|
||||
)}
|
||||
<KeywordType schema={schema} isCircular={isCircular} />
|
||||
<KeywordFormat schema={schema} />
|
||||
{constraints.length > 0 &&
|
||||
constraints.map((constraint) => (
|
||||
<KeywordConstraint key={constraint} constraint={constraint} />
|
||||
))}
|
||||
</div>
|
||||
<div
|
||||
className={classNames("json-schema-2020-12-body", {
|
||||
|
||||
@@ -25,23 +25,6 @@
|
||||
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();
|
||||
margin-left: 10px;
|
||||
line-height: 1.5;
|
||||
padding: 1px;
|
||||
padding: 1px 3px;
|
||||
color: white;
|
||||
background-color: #D69E2E;
|
||||
border-radius: 4px;
|
||||
|
||||
@@ -67,3 +67,4 @@
|
||||
@import './Properties/properties';
|
||||
@import './PatternProperties/pattern-properties';
|
||||
@import './Enum/enum';
|
||||
@import './Constraint/constraint';
|
||||
|
||||
@@ -179,3 +179,67 @@ export const 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 KeywordEnum from "./components/keywords/Enum/Enum"
|
||||
import KeywordConst from "./components/keywords/Const"
|
||||
import KeywordConstraint from "./components/keywords/Constraint/Constraint"
|
||||
import KeywordFormat from "./components/keywords/Format/Format"
|
||||
import KeywordTitle from "./components/keywords/Title/Title"
|
||||
import KeywordDescription from "./components/keywords/Description/Description"
|
||||
@@ -48,6 +49,7 @@ import {
|
||||
hasKeyword,
|
||||
isExpandable,
|
||||
stringify,
|
||||
stringifyConstraints,
|
||||
} from "./fn"
|
||||
|
||||
export const withJSONSchemaContext = (Component, overrides = {}) => {
|
||||
@@ -83,6 +85,7 @@ export const withJSONSchemaContext = (Component, overrides = {}) => {
|
||||
KeywordType,
|
||||
KeywordEnum,
|
||||
KeywordConst,
|
||||
KeywordConstraint,
|
||||
KeywordFormat,
|
||||
KeywordTitle,
|
||||
KeywordDescription,
|
||||
@@ -112,6 +115,7 @@ export const withJSONSchemaContext = (Component, overrides = {}) => {
|
||||
hasKeyword,
|
||||
isExpandable,
|
||||
stringify,
|
||||
stringifyConstraints,
|
||||
...overrides.fn,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -31,6 +31,7 @@ import KeywordUnevaluatedProperties from "./components/keywords/UnevaluatedPrope
|
||||
import KeywordType from "./components/keywords/Type/Type"
|
||||
import KeywordEnum from "./components/keywords/Enum/Enum"
|
||||
import KeywordConst from "./components/keywords/Const"
|
||||
import KeywordConstraint from "./components/keywords/Constraint/Constraint"
|
||||
import KeywordFormat from "./components/keywords/Format/Format"
|
||||
import KeywordTitle from "./components/keywords/Title/Title"
|
||||
import KeywordDescription from "./components/keywords/Description/Description"
|
||||
@@ -72,6 +73,7 @@ const JSONSchema202012Plugin = () => ({
|
||||
JSONSchema202012KeywordType: KeywordType,
|
||||
JSONSchema202012KeywordEnum: KeywordEnum,
|
||||
JSONSchema202012KeywordConst: KeywordConst,
|
||||
JSONSchema202012KeywordConstraint: KeywordConstraint,
|
||||
JSONSchema202012KeywordFormat: KeywordFormat,
|
||||
JSONSchema202012KeywordTitle: KeywordTitle,
|
||||
JSONSchema202012KeywordDescription: KeywordDescription,
|
||||
|
||||
@@ -58,6 +58,7 @@ const ModelsWrapper = createOnlyOAS31ComponentWrapper(({ getSystem }) => {
|
||||
const KeywordType = getComponent("JSONSchema202012KeywordType")
|
||||
const KeywordEnum = getComponent("JSONSchema202012KeywordEnum")
|
||||
const KeywordConst = getComponent("JSONSchema202012KeywordConst")
|
||||
const KeywordConstraint = getComponent("JSONSchema202012KeywordConstraint")
|
||||
const KeywordFormat = getComponent("JSONSchema202012KeywordFormat")
|
||||
const KeywordTitle = getComponent("JSONSchema202012KeywordTitle")
|
||||
const KeywordDescription = getComponent(
|
||||
@@ -105,6 +106,7 @@ const ModelsWrapper = createOnlyOAS31ComponentWrapper(({ getSystem }) => {
|
||||
KeywordType,
|
||||
KeywordEnum,
|
||||
KeywordConst,
|
||||
KeywordConstraint,
|
||||
KeywordFormat,
|
||||
KeywordTitle,
|
||||
KeywordDescription,
|
||||
|
||||
Reference in New Issue
Block a user