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,