UNPKG

@roqueform/doubter-plugin

Version:
99 lines (98 loc) 3.01 kB
/** * Validates Roqueform fields with [Doubter](https://github.com/smikhalevski/doubter#readme) shapes. * * ```sh * npm install --save-prod @roqueform/doubter-plugin * ``` * * Create a field validated by a Doubter shape: * * ```ts * import * as d from 'doubter'; * import { createField } from 'roqueform'; * import errorsPlugin from 'roqueform/plugin/errors'; * import doubterPlugin, { concatDoubterIssues } from '@roqueform/doubter'; * * const fieldShape = d.object({ * hello: d.string() * }); * * const field = createField({ hello: 'world' }, [ * errorsPlugin(concatDoubterIssues), * doubterPlugin(fieldShape) * ]); * * field.at('hello').validate() // ⮕ true * ``` * * @module @roqueform/doubter-plugin */ import validationPlugin from 'roqueform/plugin/validation'; /** * Validates field with a [Doubter](https://github.com/smikhalevski/doubter#readme) shape. * * @param shape The shape that parses the field value. * @template Value The root field value. */ export default function doubterPlugin(shape) { return (field) => { field._valueShape = field.parentField === null ? shape : field.parentField._valueShape?.at(field.key) || undefined; validationPlugin(validator)(field); }; } /** * Concatenates unique Doubter issues. */ export const concatDoubterIssues = (prevErrors, error) => { for (const e of prevErrors) { if (e.code !== undefined && error.code !== undefined ? e.code === error.code : e.message === error.message) { return prevErrors; } } return prevErrors.concat(error); }; const validator = { validate(field, options) { const { validation, _valueShape } = field; if (validation === null || _valueShape === undefined) { // No validation return; } applyResult(validation, _valueShape.try(field.value, options)); }, validateAsync(field, options) { const { validation, _valueShape } = field; if (validation === null || _valueShape === undefined) { // No validation return Promise.resolve(); } return _valueShape.tryAsync(field.value, options).then(result => { applyResult(validation, result); }); }, }; function applyResult(validation, result) { if (result.ok) { return; } for (const issue of result.issues) { let child = validation.rootField; if (issue.path !== undefined) { for (const key of issue.path) { child = child.at(key); } } if (child.validation !== validation) { continue; } for (let field = validation.rootField; field.parentField !== null; field = field.parentField) { (issue.path ||= []).unshift(field.key); } child.publish({ type: 'errorCaught', target: child, relatedTarget: validation.rootField, payload: issue, }); } }