diff --git a/src/core/plugins/json-schema-2020-12/components/JSONSchema/JSONSchema.jsx b/src/core/plugins/json-schema-2020-12/components/JSONSchema/JSONSchema.jsx
index 67f254ef..ca7bef6c 100644
--- a/src/core/plugins/json-schema-2020-12/components/JSONSchema/JSONSchema.jsx
+++ b/src/core/plugins/json-schema-2020-12/components/JSONSchema/JSONSchema.jsx
@@ -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) => {
)}
+ {constraints.length > 0 &&
+ constraints.map((constraint) => (
+
+ ))}
(
+ {constraint}
+)
+
+Constraint.propTypes = {
+ constraint: PropTypes.string.isRequired,
+}
+
+export default React.memo(Constraint)
diff --git a/src/core/plugins/json-schema-2020-12/components/keywords/Constraint/_constraint.scss b/src/core/plugins/json-schema-2020-12/components/keywords/Constraint/_constraint.scss
new file mode 100644
index 00000000..f24a6f13
--- /dev/null
+++ b/src/core/plugins/json-schema-2020-12/components/keywords/Constraint/_constraint.scss
@@ -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;
+}
diff --git a/src/core/plugins/json-schema-2020-12/components/keywords/Format/_format.scss b/src/core/plugins/json-schema-2020-12/components/keywords/Format/_format.scss
index 0dc12cfb..9bea4f72 100644
--- a/src/core/plugins/json-schema-2020-12/components/keywords/Format/_format.scss
+++ b/src/core/plugins/json-schema-2020-12/components/keywords/Format/_format.scss
@@ -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;
diff --git a/src/core/plugins/json-schema-2020-12/components/keywords/_all.scss b/src/core/plugins/json-schema-2020-12/components/keywords/_all.scss
index d320eb98..ed0c6b0c 100644
--- a/src/core/plugins/json-schema-2020-12/components/keywords/_all.scss
+++ b/src/core/plugins/json-schema-2020-12/components/keywords/_all.scss
@@ -67,3 +67,4 @@
@import './Properties/properties';
@import './PatternProperties/pattern-properties';
@import './Enum/enum';
+@import './Constraint/constraint';
diff --git a/src/core/plugins/json-schema-2020-12/fn.js b/src/core/plugins/json-schema-2020-12/fn.js
index e585121c..e967a1f7 100644
--- a/src/core/plugins/json-schema-2020-12/fn.js
+++ b/src/core/plugins/json-schema-2020-12/fn.js
@@ -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
+}
diff --git a/src/core/plugins/json-schema-2020-12/hoc.jsx b/src/core/plugins/json-schema-2020-12/hoc.jsx
index c529bfa3..3ee0b93e 100644
--- a/src/core/plugins/json-schema-2020-12/hoc.jsx
+++ b/src/core/plugins/json-schema-2020-12/hoc.jsx
@@ -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,
},
}
diff --git a/src/core/plugins/json-schema-2020-12/index.js b/src/core/plugins/json-schema-2020-12/index.js
index 0dad27c2..1b0658a4 100644
--- a/src/core/plugins/json-schema-2020-12/index.js
+++ b/src/core/plugins/json-schema-2020-12/index.js
@@ -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,
diff --git a/src/core/plugins/oas31/wrap-components/models.jsx b/src/core/plugins/oas31/wrap-components/models.jsx
index e4fd62cc..8c2314e6 100644
--- a/src/core/plugins/oas31/wrap-components/models.jsx
+++ b/src/core/plugins/oas31/wrap-components/models.jsx
@@ -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,