UNPKG

react-formal

Version:

Classy HTML form management for React

115 lines 3.83 kB
import omitBy from 'lodash/omitBy'; import pick from 'lodash/pick'; import { inPath, toArray } from './utils/paths'; export const EMPTY_ERRORS = Object.freeze({}); export let isChildPath = (basePath, path) => path !== basePath && inPath(basePath, path); function mapKeys(errors, baseName, fn) { if (errors === EMPTY_ERRORS) return errors; const newErrors = {}; let workDone = false; Object.keys(errors).forEach(path => { let newKey = path; if (isChildPath(baseName, path)) { var _fn; const matches = path.slice(baseName.length).match(/\[(\d+)\](.*)$/); newKey = (_fn = fn(+matches[1], matches[2] || '', path)) != null ? _fn : path; if (!workDone && newKey !== path) workDone = true; } newErrors[newKey] = errors[path]; }); return workDone ? newErrors : errors; } const prefixName = (name, baseName) => baseName + (!name || name[0] === '[' ? '' : '.') + name; export function prefix(errors, baseName) { const paths = Object.keys(errors); const result = {}; paths.forEach(path => { result[prefixName(path, baseName)] = errors[path]; }); return result; } export function unprefix(errors, baseName) { const paths = Object.keys(errors); const result = {}; paths.forEach(path => { const shortened = path.slice(baseName.length).replace(/^\./, ''); result[shortened] = errors[path]; }); return result; } export function pickErrors(errors, names) { if (!names.length) return errors; return pick(errors, names); } export function filter(errors, baseName) { const paths = Object.keys(errors); const result = {}; paths.forEach(path => { if (isChildPath(baseName, path)) { result[path] = errors[path]; } }); return result; } export function filterAndMapErrors({ errors, names, mapErrors = pickErrors }) { if (!errors || errors === EMPTY_ERRORS) return EMPTY_ERRORS; return mapErrors(errors, toArray(names)); } export function remove(errors, ...basePaths) { return omitBy(errors, (_, path) => basePaths.some(b => inPath(b, path))); } export function shift(errors, baseName, atIndex = 0) { const current = `${baseName}[${atIndex}]`; return mapKeys(remove(errors, current), baseName, (index, tail) => { if (index >= atIndex) { return `${baseName}[${index - 1}]${tail}`; } return null; }); } export function unshift(errors, baseName, atIndex = 0) { return mapKeys(errors, baseName, (index, tail) => { if (index >= atIndex) { return `${baseName}[${index + 1}]${tail}`; } return null; }); } export function move(errors, baseName, fromIndex, toIndex) { return mapKeys(errors, baseName, (index, tail) => { if (fromIndex > toIndex) { if (index === fromIndex) return `${baseName}[${toIndex}]${tail}`; // increment everything above the pivot if (index >= toIndex && index < fromIndex) return `${baseName}[${index + 1}]${tail}`; } else if (fromIndex < toIndex) { if (index === fromIndex) return `${baseName}[${toIndex}]${tail}`; // decrement everything above the from item we moved if (index >= fromIndex && index < toIndex) return `${baseName}[${index - 1}]${tail}`; } return null; }); } export function swap(errors, baseName, indexA, indexB) { return mapKeys(errors, baseName, (index, tail) => { if (index === indexA) return `${baseName}[${indexB}]${tail}`; if (index === indexB) return `${baseName}[${indexA}]${tail}`; return null; }); } export function inclusiveMapErrors(errors, names) { if (!names.length || errors === EMPTY_ERRORS) return EMPTY_ERRORS; let activeErrors = {}; let paths = Object.keys(errors); names.forEach(name => { paths.forEach(path => { if (errors[path] && inPath(name, path)) { activeErrors[path] = errors[path]; } }); }); return activeErrors; }