UNPKG

mutoid

Version:

Reactive library for data fetching, caching, state management

113 lines (112 loc) 5.32 kB
import * as A from 'fp-ts/Array'; import * as O from 'fp-ts/Option'; import * as RE from 'fp-ts/Record'; import { flow, pipe } from 'fp-ts/function'; // ------------------------------------------------------------------------------------- // guards // ------------------------------------------------------------------------------------- const isBrowser = () => typeof window !== 'undefined' && typeof window.document !== 'undefined'; const isNode = () => typeof process !== 'undefined' && process.versions !== null && process.versions.node !== null; const isBlob = (d) => isBrowser() && d instanceof Blob; const isBuffer = (d) => isNode() && d instanceof Buffer; const isBoolean = (d) => typeof d === 'boolean'; const isString = (d) => typeof d === 'string'; const isNumber = (d) => typeof d === 'number'; const noNeeRehashUrl = (d) => isString(d) || isBoolean(d) || isNumber(d); const noNeeRehashForm = (d) => isString(d) || isBoolean(d) || isNumber(d) || isBlob(d) || isBuffer(d); const hasTag = (a) => typeof a === 'object' && Object.prototype.hasOwnProperty.call(a, '_tag'); const isOption = (oi) => { return hasTag(oi) && (oi._tag === 'None' || oi._tag === 'Some'); }; // ------------------------------------------------------------------------------------- // null -> to Option // ------------------------------------------------------------------------------------- const convertNullableArray = (noNeedRecursion) => (data) => { return pipe(data, A.map(O.fromNullable), A.map(O.map(d => { if (noNeedRecursion(d)) { return d; } if (Array.isArray(d)) { return convertNullableArray(noNeedRecursion)(d); } return convertNullableObject(noNeedRecursion)(d); }))); }; const convertNullableObject = (noNeedRecursion) => (data) => { return pipe(data, RE.map(O.fromNullable), RE.map(O.map(d => { if (noNeedRecursion(d)) { return d; } if (Array.isArray(d)) { return convertNullableArray(noNeedRecursion)(d); } return convertNullableObject(noNeedRecursion)(d); }))); }; // ------------------------------------------------------------------------------------- // map input to DataRecord // ------------------------------------------------------------------------------------- const generateKey = (key, root) => (root ? `${root}[${key}]` : key); const mapArray = (noNeedRecursion) => (data, root) => { return pipe(data, A.map(oi => (isOption(oi) ? oi : O.some(oi))), A.filter(O.isSome), A.map(d => d.value), A.mapWithIndex((i, d) => { if (noNeedRecursion(d)) { return { [`${root}[]`]: d }; } if (Array.isArray(d)) { return { [generateKey(i.toString(), root)]: mapArray(noNeedRecursion)(d, generateKey(i.toString(), root)), }; } return mapObject(noNeedRecursion)(d, generateKey(i.toString(), root)); })); }; const mapObject = (noNeedRecursion) => (data, root) => { return pipe(data, RE.map(oi => (isOption(oi) ? oi : O.some(oi))), RE.filter(O.isSome), RE.map(d => d.value), RE.mapWithIndex((k, d) => { if (noNeedRecursion(d)) { return { [generateKey(k, root)]: d }; } if (Array.isArray(d)) { return mapArray(noNeedRecursion)(d, generateKey(k, root)); } return mapObject(noNeedRecursion)(d, generateKey(k, root)); })); }; // ------------------------------------------------------------------------------------- // append DataRecord to collector // ------------------------------------------------------------------------------------- const appendToFormData = (noNeedRecursion) => (collector) => (data) => { return pipe(data, RE.reduceWithIndex(collector, (k, fd, d) => { if (noNeedRecursion(d)) { fd.append(k, d); return fd; } if (Array.isArray(d)) { return pipe(d, A.reduce(fd, (ffd, dr) => appendToFormData(noNeedRecursion)(ffd)(dr))); } return appendToFormData(noNeedRecursion)(fd)(d); })); }; export const serializeNullable = (collector, noNeedRecursion, data) => { return pipe(data, O.fromNullable, O.map(flow(convertNullableObject(noNeedRecursion), mapObject(noNeedRecursion), appendToFormData(noNeedRecursion)(collector))), O.getOrElse(() => collector)); }; export const serialize = (collector, noNeedRecursion, data) => { return pipe(data, mapObject(noNeedRecursion), appendToFormData(noNeedRecursion)(collector)); }; // ------------------------------------------------------------------------------------- // entry point // ------------------------------------------------------------------------------------- export const serializeNullableForm = (collector) => (data) => { return serializeNullable(collector, noNeeRehashForm, data); }; export const serializeForm = (collector) => (data) => { return serialize(collector, noNeeRehashForm, data); }; export const serializeNullableUrl = (collector) => (data) => { return serializeNullable(collector, noNeeRehashUrl, data); }; export const serializeUrl = (collector) => (data) => { return serialize(collector, noNeeRehashUrl, data); }; export const toQueryString = (c) => { return pipe(c.toString(), s => (s.length > 0 ? `?${s}` : '')); };