svelte-forms-lib
Version:
Svelte forms lib - A lightweight library for managing forms in Svelte v3
131 lines (109 loc) • 3.08 kB
JavaScript
import {dequal as isEqual} from 'dequal/lite';
function subscribeOnce(observable) {
return new Promise((resolve) => {
observable.subscribe(resolve)(); // immediately invoke to unsubscribe
});
}
function update(object, path, value) {
object.update((o) => {
set(o, path, value);
return o;
});
}
function cloneDeep(object) {
return JSON.parse(JSON.stringify(object));
}
function isNullish(value) {
return value === undefined || value === null;
}
function isEmpty(object) {
return isNullish(object) || Object.keys(object).length <= 0;
}
function getValues(object) {
let results = [];
for (const [, value] of Object.entries(object)) {
const values = typeof value === 'object' ? getValues(value) : [value];
results = [...results, ...values];
}
return results;
}
// TODO: refactor this so as not to rely directly on yup's API
// This should use dependency injection, with a default callback which may assume
// yup as the validation schema
function getErrorsFromSchema(initialValues, schema, errors = {}) {
for (const key in schema) {
switch (true) {
case schema[key].type === 'object' && !isEmpty(schema[key].fields): {
errors[key] = getErrorsFromSchema(
initialValues[key],
schema[key].fields,
{...errors[key]},
);
break;
}
case schema[key].type === 'array': {
const values =
initialValues && initialValues[key] ? initialValues[key] : [];
errors[key] = values.map((value) => {
const innerError = getErrorsFromSchema(
value,
schema[key].innerType.fields,
{...errors[key]},
);
return Object.keys(innerError).length > 0 ? innerError : '';
});
break;
}
default: {
errors[key] = '';
}
}
}
return errors;
}
const deepEqual = isEqual;
function assignDeep(object, value) {
if (Array.isArray(object)) {
return object.map((o) => assignDeep(o, value));
}
const copy = {};
for (const key in object) {
copy[key] =
typeof object[key] === 'object' && !isNullish(object[key]) ? assignDeep(object[key], value) : value;
}
return copy;
}
function set(object, path, value) {
if (new Object(object) !== object) return object;
if (!Array.isArray(path)) {
path = path.toString().match(/[^.[\]]+/g) || [];
}
const result = path
.slice(0, -1)
// TODO: replace this reduce with something more readable
// eslint-disable-next-line unicorn/no-array-reduce
.reduce(
(accumulator, key, index) =>
new Object(accumulator[key]) === accumulator[key]
? accumulator[key]
: (accumulator[key] =
Math.trunc(Math.abs(path[index + 1])) === +path[index + 1]
? []
: {}),
object,
);
result[path[path.length - 1]] = value;
return object;
}
export const util = {
assignDeep,
cloneDeep,
deepEqual,
getErrorsFromSchema,
getValues,
isEmpty,
isNullish,
set,
subscribeOnce,
update,
};