Skip to content

Commit

Permalink
Replace jsonschema package with ajv in ketcher-react
Browse files Browse the repository at this point in the history
  • Loading branch information
neiloxx committed Feb 21, 2022
1 parent d878109 commit f0e3deb
Show file tree
Hide file tree
Showing 8 changed files with 84 additions and 51 deletions.
2 changes: 1 addition & 1 deletion packages/ketcher-react/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
"@emotion/react": "^11.7.1",
"@emotion/styled": "^11.6.0",
"@mui/material": "^5.3.1",
"ajv": "^8.10.0",
"clsx": "^1.1.1",
"draft-js": "^0.11.7",
"draft-js-custom-styles": "^2.1.1",
Expand All @@ -57,7 +58,6 @@
"font-face-observer": "^1.0.0",
"hoist-non-react-statics": "^3.3.2",
"intersection-observer": "^0.12.0",
"jsonschema": "^1.4.0",
"ketcher-core": "workspace:*",
"lodash": "^4.17.21",
"miew-react": "^1.0.0",
Expand Down
38 changes: 22 additions & 16 deletions packages/ketcher-react/src/script/ui/component/form/form/form.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import Input from '../input'
import classes from './form.module.less'
import clsx from 'clsx'
import { connect } from 'react-redux'
import jsonschema from 'jsonschema'
import Ajv from 'ajv'
import { updateFormState } from '../../../state/modal/form'
import { useFormContext } from '../../../../../hooks'
import Select from '../Select'
Expand Down Expand Up @@ -153,27 +153,33 @@ const SelectOneOf = (props) => {
//

function propSchema(schema, { customValid, serialize = {}, deserialize = {} }) {
const validator = new jsonschema.Validator()
const ajv = new Ajv({ allErrors: true, verbose: true, strictSchema: false })

if (customValid) {
schema = Object.assign({}, schema) // copy
schema.properties = Object.keys(customValid).reduce((res, prop) => {
validator.customFormats[prop] = customValid[prop]
ajv.addFormat(customValid[prop].name, customValid[prop])
res[prop] = { format: prop, ...res[prop] }
return res
}, schema.properties)
}

const validate = ajv.compile(schema)

return {
key: schema.key || '',
serialize: (inst) =>
validator.validate(inst, schema, {
rewrite: serializeRewrite.bind(null, serialize)
}),
deserialize: (inst) =>
validator.validate(inst, schema, {
rewrite: deserializeRewrite.bind(null, deserialize)
})
serialize: (inst) => {
validate(inst)
return {
instance: serializeRewrite(serialize, inst, schema),
valid: validate(inst),
errors: validate.errors || []
}
},
deserialize: (inst) => {
validate(inst)
return deserializeRewrite(deserialize, inst)
}
}
}

Expand All @@ -195,18 +201,18 @@ function deserializeRewrite(deserializeMap, instance) {
}

function getInvalidMessage(item) {
if (!item.schema.invalidMessage) return item.message
return typeof item.schema.invalidMessage === 'function'
? item.schema.invalidMessage(item.instance)
: item.schema.invalidMessage
if (!item.parentSchema.invalidMessage) return item.message
return typeof item.parentSchema.invalidMessage === 'function'
? item.parentSchema.invalidMessage(item.data)
: item.parentSchema.invalidMessage
}

function getErrorsObj(errors) {
const errs = {}
let field

errors.forEach((item) => {
field = item.property.split('.')[1]
field = item.instancePath.slice(1)
if (!errs[field]) errs[field] = getInvalidMessage(item)
})

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -263,7 +263,7 @@ function ctrlMap(component, { schema, multiple, onChange }) {
}

function componentMap({ schema, type, multiple }) {
if (schema?.type === 'slider') {
if (schema?.type === 'boolean' && schema?.description === 'slider') {
return Slider
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ function fromAtom(satom) {
function toAtom(atom) {
// TODO merge this to Atom.attrlist?
// see ratomtool
const chargeRegexp = atomSchema.properties.charge.pattern
const chargeRegexp = new RegExp(atomSchema.properties.charge.pattern)
const pch = chargeRegexp.exec(atom.charge)
const charge = pch ? parseInt(pch[1] + pch[3] + pch[2]) : atom.charge

Expand Down
80 changes: 53 additions & 27 deletions packages/ketcher-react/src/script/ui/data/schema/options-schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,12 @@
***************************************************************************/

import { StereLabelStyleType, StereoColoringType } from 'ketcher-core'
import jsonschema, { Schema } from 'jsonschema'
import Ajv, { SchemaObject } from 'ajv'

type ExtendedSchema = Schema & { enumNames?: Array<string>; default?: any }
type ExtendedSchema = SchemaObject & {
enumNames?: Array<string>
default?: any
}

const editor: {
resetToSelect: ExtendedSchema
Expand Down Expand Up @@ -66,17 +69,20 @@ const render: {
} = {
showValenceWarnings: {
title: 'Show valence warnings',
type: 'slider',
type: 'boolean',
description: 'slider',
default: true
},
atomColoring: {
title: 'Atom coloring',
type: 'slider',
type: 'boolean',
description: 'slider',
default: true
},
showStereoFlags: {
title: 'Show the Stereo flags',
type: 'slider',
type: 'boolean',
description: 'slider',
default: true
},
stereoLabelStyle: {
Expand Down Expand Up @@ -118,27 +124,28 @@ const render: {
},
autoFadeOfStereoLabels: {
title: 'Auto fade And/Or center labels',
type: 'slider',
type: 'boolean',
description: 'slider',
default: true
},
absFlagLabel: {
title: 'Text of Absolute flag',
type: 'String',
type: 'string',
default: 'ABS (Chiral)'
},
andFlagLabel: {
title: 'Text of AND flag',
type: 'String',
type: 'string',
default: 'AND Enantiomer'
},
mixedFlagLabel: {
title: 'Text of Mixed flag',
type: 'String',
type: 'string',
default: 'Mixed'
},
orFlagLabel: {
title: 'Text of OR flag',
type: 'String',
type: 'string',
default: 'OR Enantiomer'
},
font: {
Expand All @@ -163,17 +170,20 @@ const render: {
// Atom
carbonExplicitly: {
title: 'Display carbon explicitly',
type: 'slider',
type: 'boolean',
description: 'slider',
default: false
},
showCharge: {
title: 'Display charge',
type: 'slider',
type: 'boolean',
description: 'slider',
default: true
},
showValence: {
title: 'Display valence',
type: 'slider',
type: 'boolean',
description: 'slider',
default: true
},
showHydrogenLabels: {
Expand All @@ -184,7 +194,8 @@ const render: {
// Bonds
aromaticCircle: {
title: 'Aromatic Bonds as circle',
type: 'slider',
type: 'boolean',
description: 'slider',
default: true
},
doubleBondWidth: {
Expand Down Expand Up @@ -219,27 +230,32 @@ const server: {
} = {
'smart-layout': {
title: 'Smart-layout',
type: 'slider',
type: 'boolean',
description: 'slider',
default: true
},
'ignore-stereochemistry-errors': {
title: 'Ignore stereochemistry errors',
type: 'slider',
type: 'boolean',
description: 'slider',
default: true
},
'mass-skip-error-on-pseudoatoms': {
title: 'Ignore pseudoatoms at mass',
type: 'slider',
type: 'boolean',
description: 'slider',
default: false
},
'gross-formula-add-rsites': {
title: 'Add Rsites at mass calculation',
type: 'slider',
type: 'boolean',
description: 'slider',
default: true
},
'gross-formula-add-isotopes': {
title: 'Add Isotopes at mass calculation',
type: 'slider',
type: 'boolean',
description: 'slider',
default: true
}
}
Expand All @@ -254,22 +270,26 @@ const debug: {
} = {
showAtomIds: {
title: 'Show atom Ids',
type: 'slider',
type: 'boolean',
description: 'slider',
default: false
},
showBondIds: {
title: 'Show bonds Ids',
type: 'slider',
type: 'boolean',
description: 'slider',
default: false
},
showHalfBondIds: {
title: 'Show half bonds Ids',
type: 'slider',
type: 'boolean',
description: 'slider',
default: false
},
showLoopIds: {
title: 'Show loop Ids',
type: 'slider',
type: 'boolean',
description: 'slider',
default: false
}
}
Expand Down Expand Up @@ -328,14 +348,20 @@ export function getDefaultOptions(): Record<string, any> {
export function validation(settings): Record<string, string> | null {
if (typeof settings !== 'object' || settings === null) return null

const v = new jsonschema.Validator()
const { errors } = v.validate(settings, optionsSchema)
const errProps = errors.map((err) => err.property.split('.')[1])
const ajv = new Ajv({
allErrors: true,
keywords: [{ keyword: 'enumNames', schemaType: 'array' }]
})

const validate = ajv.compile(optionsSchema)
validate(settings)
const errors = validate.errors || []
const propsErrors = errors.map((el) => el.instancePath.slice(1))

return Object.keys(settings).reduce((res, prop) => {
if (!optionsSchema.properties) return res

if (optionsSchema.properties[prop] && errProps.indexOf(prop) === -1)
if (optionsSchema.properties[prop] && propsErrors.indexOf(prop) === -1)
res[prop] = settings[prop]

return res
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import { range } from 'lodash/fp'
export const atom = {
title: 'Atom',
type: 'object',
required: 'label',
required: ['label'],
properties: {
label: {
title: 'Label',
Expand All @@ -36,7 +36,7 @@ export const atom = {
charge: {
title: 'Charge',
type: 'string',
pattern: /^([+-]?)(\d{1,3}|1000)([+-]?)$/,
pattern: '^([+-]?)([0-9]{1,3}|1000)([+-]?)$',
maxLength: 5,
default: '0',
invalidMessage: 'Invalid charge value'
Expand Down Expand Up @@ -247,7 +247,7 @@ const sgroup = {
title: 'Polymer label',
type: 'string',
default: 'n',
pattern: /^[a-zA-Z]$/,
pattern: '^[a-zA-Z]$',
invalidMessage: 'SRU subscript should consist of a single letter'
},
connectivity: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ const saveSchema = {
title: 'File name:',
type: 'string',
maxLength: 128,
pattern: /^[^.<>:?"*|/\\][^<>:?"*|/\\]*$/,
pattern: '^[^.<>:?"*\\\\|\\/][^<>:?"*\\\\|\\/]*$',
invalidMessage: (res) => {
if (!res) return 'Filename should contain at least one character'
if (res.length > 128) return 'Filename is too long'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,8 @@ function atomValid(label) {
}

function chargeValid(charge) {
const result = atomSchema.properties.charge.pattern.exec(charge)
const regex = new RegExp(atomSchema.properties.charge.pattern)
const result = regex.exec(charge)
return result && (result[1] === '' || result[3] === '')
}

Expand Down

0 comments on commit f0e3deb

Please sign in to comment.