Skip to content

Commit

Permalink
feat(json-schema-2020-12): add support for validation keywords for nu…
Browse files Browse the repository at this point in the history
…mbers (#8624)

Includes following keywords:
  - multipleOf
  - minimum
  - maximum
  - inclusiveMinimum
  - inclusiveMaximum

Refs #8513
  • Loading branch information
char0n authored May 8, 2023
1 parent 3b940d0 commit 1a29662
Show file tree
Hide file tree
Showing 10 changed files with 108 additions and 18 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand Down Expand Up @@ -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")
Expand Down Expand Up @@ -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", {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
//}
}


Original file line number Diff line number Diff line change
@@ -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)
Original file line number Diff line number Diff line change
@@ -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;
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,3 +67,4 @@
@import './Properties/properties';
@import './PatternProperties/pattern-properties';
@import './Enum/enum';
@import './Constraint/constraint';
64 changes: 64 additions & 0 deletions src/core/plugins/json-schema-2020-12/fn.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
4 changes: 4 additions & 0 deletions src/core/plugins/json-schema-2020-12/hoc.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -48,6 +49,7 @@ import {
hasKeyword,
isExpandable,
stringify,
stringifyConstraints,
} from "./fn"

export const withJSONSchemaContext = (Component, overrides = {}) => {
Expand Down Expand Up @@ -83,6 +85,7 @@ export const withJSONSchemaContext = (Component, overrides = {}) => {
KeywordType,
KeywordEnum,
KeywordConst,
KeywordConstraint,
KeywordFormat,
KeywordTitle,
KeywordDescription,
Expand Down Expand Up @@ -112,6 +115,7 @@ export const withJSONSchemaContext = (Component, overrides = {}) => {
hasKeyword,
isExpandable,
stringify,
stringifyConstraints,
...overrides.fn,
},
}
Expand Down
2 changes: 2 additions & 0 deletions src/core/plugins/json-schema-2020-12/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -72,6 +73,7 @@ const JSONSchema202012Plugin = () => ({
JSONSchema202012KeywordType: KeywordType,
JSONSchema202012KeywordEnum: KeywordEnum,
JSONSchema202012KeywordConst: KeywordConst,
JSONSchema202012KeywordConstraint: KeywordConstraint,
JSONSchema202012KeywordFormat: KeywordFormat,
JSONSchema202012KeywordTitle: KeywordTitle,
JSONSchema202012KeywordDescription: KeywordDescription,
Expand Down
2 changes: 2 additions & 0 deletions src/core/plugins/oas31/wrap-components/models.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down Expand Up @@ -105,6 +106,7 @@ const ModelsWrapper = createOnlyOAS31ComponentWrapper(({ getSystem }) => {
KeywordType,
KeywordEnum,
KeywordConst,
KeywordConstraint,
KeywordFormat,
KeywordTitle,
KeywordDescription,
Expand Down

0 comments on commit 1a29662

Please sign in to comment.