UNPKG

integreat

Version:
145 lines 5.76 kB
import mapAny from 'map-any'; import { nanoid } from 'nanoid'; import booleanFn from './castFns/boolean.js'; import dateFn from './castFns/date.js'; import integerFn from './castFns/integer.js'; import numberFn from './castFns/number.js'; import objectFn from './castFns/object.js'; import nonPrimitiveFn from './castFns/nonPrimitive.js'; import stringFn from './castFns/string.js'; import { isObject, isFieldDefinition, isShape, isNotNullOrUndefined, } from '../utils/is.js'; import unwrapValue from '../utils/unwrapValue.js'; import { ensureArray } from '../utils/array.js'; function castFnFromType(type, schemas) { switch (type) { case 'string': return stringFn; case 'integer': return integerFn; case 'number': case 'float': return numberFn; case 'boolean': return booleanFn; case 'date': return dateFn; case 'object': return objectFn; case 'unknown': return (value) => value; default: return nonPrimitiveFn(type, schemas); } } const typeFromDef = (prop) => isFieldDefinition(prop) ? prop.$type : typeof prop === 'string' ? prop : undefined; const hasArrayNotation = (key) => typeof key === 'string' && key.endsWith('[]'); const removeArrayNotation = (key) => hasArrayNotation(key) ? key.slice(0, key.length - 2) : key; function createCastFn(def, schemas) { if (isFieldDefinition(def)) { if (def?.const !== undefined) { return () => () => def.const; } const castFn = castFnFromType(removeArrayNotation(def.$type), schemas); return (isRev, noDefaults = false) => function castValue(rawValue) { const value = unwrapValue(rawValue); if (value === undefined) { return noDefaults ? undefined : def.default; } else { return castFn(value, isRev); } }; } else if (isShape(def)) { return createShapeCast(def, undefined, schemas); } else { return undefined; } } const unwrapSingleArrayItem = (fn) => (value) => Array.isArray(value) && value.length === 1 ? fn(value[0]) : fn(value); const handleArray = (fn, isArrayExpected, type) => isArrayExpected ? (isRev, noDefaults) => (value) => value === undefined ? undefined : ensureArray(value).map(fn(isRev, noDefaults)) : type === 'unknown' ? (isRev, noDefaults) => fn(isRev, noDefaults) : (isRev, noDefaults) => unwrapSingleArrayItem(fn(isRev, noDefaults)); function getDates(shouldHaveCreatedAt, shouldHaveUpdatedAt, createdAt, updatedAt, noDefaults) { if (noDefaults) { return {}; } const nextCreatedAt = shouldHaveCreatedAt ? createdAt ? createdAt : (updatedAt ?? new Date()) : undefined; const nextUpdatedAt = shouldHaveUpdatedAt ? updatedAt ? updatedAt : (nextCreatedAt ?? new Date()) : undefined; return { ...(nextCreatedAt ? { createdAt: nextCreatedAt } : {}), ...(nextUpdatedAt ? { updatedAt: nextUpdatedAt } : {}), }; } function createCastFnHandlingArrays(key, def, schemas) { const cast = createCastFn(def, schemas); if (cast) { const type = typeFromDef(def); return handleArray(cast, hasArrayNotation(key) || hasArrayNotation(type), type); } else { return undefined; } } const completeItemBeforeCast = (shouldHaveCreatedAt, shouldHaveUpdatedAt, doGenerateId) => (item, noDefaults) => ({ ...item, id: item.id ?? (doGenerateId && !noDefaults ? nanoid() : null), ...getDates(shouldHaveCreatedAt, shouldHaveUpdatedAt, item.createdAt, item.updatedAt, noDefaults), }); const castField = (item, isRev, noDefaults) => ([key, cast]) => [ key, cast(isRev, noDefaults)(item[key]), ]; const fieldHasValue = ([_, value]) => value !== undefined; const createFieldCast = (schemas) => ([key, def]) => [removeArrayNotation(key), createCastFnHandlingArrays(key, def, schemas)]; const entryHasCastFn = (entry) => entry[1] !== undefined; const includeType = (isRev, type) => !isRev && typeof type === 'string' ? [['$type', type]] : []; const includeIsNewAndIsDeleted = (item) => [ ...(item.isNew === true ? [['isNew', true]] : []), ...(item.isDeleted === true ? [['isDeleted', true]] : []), ]; const createCastItemFn = (completeItem, fields, type) => (isRev, noDefaults) => function castItem(rawItem) { if (!isObject(rawItem)) { return undefined; } const item = completeItem(rawItem, noDefaults); return Object.fromEntries([ ...fields.map(castField(item, isRev, noDefaults)).filter(fieldHasValue), ...includeType(isRev, type), ...includeIsNewAndIsDeleted(item), ]); }; function createShapeCast(shape, type, schemas, doGenerateId = false) { const fields = Object.entries(shape) .map(createFieldCast(schemas)) .filter(entryHasCastFn); const shouldHaveCreatedAt = !!shape.createdAt; const shouldHaveUpdatedAt = !!shape.updatedAt; const completeItem = completeItemBeforeCast(shouldHaveCreatedAt, shouldHaveUpdatedAt, doGenerateId); return createCastItemFn(completeItem, fields, type); } export default function createCast(shape, type, schemas = new Map(), doGenerateId = false) { const castShape = createShapeCast(shape, type, schemas, doGenerateId); return function castItem(data, isRev = false, noDefaults = false) { const casted = mapAny(castShape(isRev, noDefaults), data); return Array.isArray(casted) ? casted.filter(isNotNullOrUndefined) : casted; }; } //# sourceMappingURL=createCast.js.map