97 lines
2.9 KiB
JavaScript
97 lines
2.9 KiB
JavaScript
import { some, map, filter, keys, includes, countBy, flatten } from "lodash/fp"
|
|
import {
|
|
isSomething,
|
|
$,
|
|
isNonEmptyString,
|
|
isNothingOrEmpty,
|
|
isNothing,
|
|
} from "../common"
|
|
import { all, getDefaultOptions } from "../types"
|
|
import { applyRuleSet, makerule } from "../common/validationCommon"
|
|
import { BadRequestError } from "../common/errors"
|
|
import { generate } from "shortid"
|
|
|
|
export const fieldErrors = {
|
|
AddFieldValidationFailed: "Add field validation: ",
|
|
}
|
|
|
|
export const allowedTypes = () => keys(all)
|
|
|
|
export const getNewField = type => ({
|
|
id: generate(),
|
|
name: "", // how field is referenced internally
|
|
type,
|
|
typeOptions: getDefaultOptions(type),
|
|
label: "", // how field is displayed
|
|
getInitialValue: "default", // function that gets value when initially created
|
|
getUndefinedValue: "default", // function that gets value when field undefined on record
|
|
})
|
|
|
|
const fieldRules = allFields => [
|
|
makerule("name", "field name is not set", f => isNonEmptyString(f.name)),
|
|
makerule("type", "field type is not set", f => isNonEmptyString(f.type)),
|
|
makerule("label", "field label is not set", f => isNonEmptyString(f.label)),
|
|
makerule("getInitialValue", "getInitialValue function is not set", f =>
|
|
isNonEmptyString(f.getInitialValue)
|
|
),
|
|
makerule("getUndefinedValue", "getUndefinedValue function is not set", f =>
|
|
isNonEmptyString(f.getUndefinedValue)
|
|
),
|
|
makerule(
|
|
"name",
|
|
"field name is duplicated",
|
|
f => isNothingOrEmpty(f.name) || countBy("name")(allFields)[f.name] === 1
|
|
),
|
|
makerule(
|
|
"type",
|
|
"type is unknown",
|
|
f => isNothingOrEmpty(f.type) || some(t => f.type === t)(allowedTypes())
|
|
),
|
|
]
|
|
|
|
const typeOptionsRules = field => {
|
|
const type = all[field.type]
|
|
if (isNothing(type)) return []
|
|
|
|
const def = optName => type.optionDefinitions[optName]
|
|
|
|
return $(field.typeOptions, [
|
|
keys,
|
|
filter(o => isSomething(def(o)) && isSomething(def(o).isValid)),
|
|
map(o =>
|
|
makerule(`typeOptions.${o}`, `${def(o).requirementDescription}`, field =>
|
|
def(o).isValid(field.typeOptions[o])
|
|
)
|
|
),
|
|
])
|
|
}
|
|
|
|
export const validateField = allFields => field => {
|
|
const everySingleField = includes(field)(allFields)
|
|
? allFields
|
|
: [...allFields, field]
|
|
return applyRuleSet([
|
|
...fieldRules(everySingleField),
|
|
...typeOptionsRules(field),
|
|
])(field)
|
|
}
|
|
|
|
export const validateAllFields = recordNode =>
|
|
$(recordNode.fields, [map(validateField(recordNode.fields)), flatten])
|
|
|
|
export const addField = (recordTemplate, field) => {
|
|
if (isNothingOrEmpty(field.label)) {
|
|
field.label = field.name
|
|
}
|
|
const validationMessages = validateField([...recordTemplate.fields, field])(
|
|
field
|
|
)
|
|
if (validationMessages.length > 0) {
|
|
const errors = map(m => m.error)(validationMessages)
|
|
throw new BadRequestError(
|
|
`${fieldErrors.AddFieldValidationFailed} ${errors.join(", ")}`
|
|
)
|
|
}
|
|
recordTemplate.fields.push(field)
|
|
}
|