diff --git a/packages/react-form-renderer/src/files/parse-condition.d.ts b/packages/react-form-renderer/src/files/parse-condition.d.ts new file mode 100644 index 000000000..3c5a31562 --- /dev/null +++ b/packages/react-form-renderer/src/files/parse-condition.d.ts @@ -0,0 +1,6 @@ +import { AnyObject } from "./common"; +import { ConditionDefinition } from "./condition"; + +export type ParseCondition = (condition: ConditionDefinition, values: AnyObject) => void; +declare const parseCondition: ParseCondition +export default parseCondition; diff --git a/packages/react-form-renderer/src/files/parse-condition.js b/packages/react-form-renderer/src/files/parse-condition.js new file mode 100644 index 000000000..22d161281 --- /dev/null +++ b/packages/react-form-renderer/src/files/parse-condition.js @@ -0,0 +1,85 @@ +import lodashIsEmpty from 'lodash/isEmpty'; +import get from 'lodash/get'; + +const isEmptyValue = (value) => (typeof value === 'number' || value === true ? false : lodashIsEmpty(value)); + +const fieldCondition = (value, { is, isNotEmpty, isEmpty, pattern, notMatch, flags }) => { + if (isNotEmpty) { + return !isEmptyValue(value); + } + + if (isEmpty) { + return isEmptyValue(value); + } + + if (pattern) { + const regExpPattern = RegExp(pattern, flags); + + return notMatch ? !regExpPattern.test(value) : regExpPattern.test(value); + } + + const isMatched = Array.isArray(is) ? !!is.includes(value) : value === is; + + return notMatch ? !isMatched : isMatched; +}; + +export const parseCondition = (condition, values) => { + let positiveResult = { + visible: true, + ...condition.then, + result: true + }; + + let negativeResult = { + visible: false, + ...condition.else, + result: false + }; + + if (Array.isArray(condition)) { + return !condition.map((condition) => parseCondition(condition, values)).some(({ result }) => result === false) ? positiveResult : negativeResult; + } + + if (condition.and) { + return !condition.and.map((condition) => parseCondition(condition, values)).some(({ result }) => result === false) + ? positiveResult + : negativeResult; + } + + if (condition.sequence) { + return condition.sequence.reduce( + (acc, curr) => { + const result = parseCondition(curr, values); + + return { + sets: [...acc.sets, ...(result.set ? [result.set] : [])], + visible: acc.visible || result.visible, + result: acc.result || result.result + }; + }, + { ...negativeResult, sets: [] } + ); + } + + if (condition.or) { + return condition.or.map((condition) => parseCondition(condition, values)).some(({ result }) => result === true) ? positiveResult : negativeResult; + } + + if (condition.not) { + return !parseCondition(condition.not, values).result ? positiveResult : negativeResult; + } + + if (typeof condition.when === 'string') { + return fieldCondition(get(values, condition.when), condition) ? positiveResult : negativeResult; + } + + if (Array.isArray(condition.when)) { + return condition.when.map((fieldName) => fieldCondition(get(values, fieldName), condition)).find((condition) => !!condition) + ? positiveResult + : negativeResult; + } + + return negativeResult; +}; + +export default parseCondition; diff --git a/packages/react-form-renderer/src/form-renderer/condition.js b/packages/react-form-renderer/src/form-renderer/condition.js index 34df578e0..3ad339d12 100644 --- a/packages/react-form-renderer/src/form-renderer/condition.js +++ b/packages/react-form-renderer/src/form-renderer/condition.js @@ -1,91 +1,9 @@ import React, { useEffect, useReducer } from 'react'; import PropTypes from 'prop-types'; -import lodashIsEmpty from 'lodash/isEmpty'; -import get from 'lodash/get'; import isEqual from 'lodash/isEqual'; import useFormApi from '../files/use-form-api'; - -const isEmptyValue = (value) => (typeof value === 'number' || value === true ? false : lodashIsEmpty(value)); - -const fieldCondition = (value, { is, isNotEmpty, isEmpty, pattern, notMatch, flags }) => { - if (isNotEmpty) { - return !isEmptyValue(value); - } - - if (isEmpty) { - return isEmptyValue(value); - } - - if (pattern) { - const regExpPattern = RegExp(pattern, flags); - - return notMatch ? !regExpPattern.test(value) : regExpPattern.test(value); - } - - const isMatched = Array.isArray(is) ? !!is.includes(value) : value === is; - - return notMatch ? !isMatched : isMatched; -}; - -export const parseCondition = (condition, values) => { - let positiveResult = { - visible: true, - ...condition.then, - result: true - }; - - let negativeResult = { - visible: false, - ...condition.else, - result: false - }; - - if (Array.isArray(condition)) { - return !condition.map((condition) => parseCondition(condition, values)).some(({ result }) => result === false) ? positiveResult : negativeResult; - } - - if (condition.and) { - return !condition.and.map((condition) => parseCondition(condition, values)).some(({ result }) => result === false) - ? positiveResult - : negativeResult; - } - - if (condition.sequence) { - return condition.sequence.reduce( - (acc, curr) => { - const result = parseCondition(curr, values); - - return { - sets: [...acc.sets, ...(result.set ? [result.set] : [])], - visible: acc.visible || result.visible, - result: acc.result || result.result - }; - }, - { ...negativeResult, sets: [] } - ); - } - - if (condition.or) { - return condition.or.map((condition) => parseCondition(condition, values)).some(({ result }) => result === true) ? positiveResult : negativeResult; - } - - if (condition.not) { - return !parseCondition(condition.not, values).result ? positiveResult : negativeResult; - } - - if (typeof condition.when === 'string') { - return fieldCondition(get(values, condition.when), condition) ? positiveResult : negativeResult; - } - - if (Array.isArray(condition.when)) { - return condition.when.map((fieldName) => fieldCondition(get(values, fieldName), condition)).find((condition) => !!condition) - ? positiveResult - : negativeResult; - } - - return negativeResult; -}; +import parseCondition from '../files/parse-condition'; export const reducer = (state, { type, sets }) => { switch (type) { diff --git a/packages/react-form-renderer/src/index.js b/packages/react-form-renderer/src/index.js index d481596fa..437fa39fe 100644 --- a/packages/react-form-renderer/src/index.js +++ b/packages/react-form-renderer/src/index.js @@ -14,3 +14,4 @@ export { default as FieldProvider } from './files/field-provider'; export { default as useFieldApi } from './files/use-field-api'; export { default as DefaultSchemaError } from './files/schema-errors'; export { default as WizardContext } from './files/wizard-context'; +export { default as parseCondition } from './files/parse-condition'; diff --git a/packages/react-form-renderer/src/tests/form-renderer/parse-condition.test.js b/packages/react-form-renderer/src/tests/form-renderer/parse-condition.test.js index 0310671cb..9c8a59f90 100644 --- a/packages/react-form-renderer/src/tests/form-renderer/parse-condition.test.js +++ b/packages/react-form-renderer/src/tests/form-renderer/parse-condition.test.js @@ -1,4 +1,4 @@ -import { parseCondition } from '../../form-renderer/condition'; +import parseCondition from '../../files/parse-condition'; describe('parseCondition', () => { let condition;