mutoid
Version:
Reactive library for data fetching, caching, state management
113 lines (112 loc) • 5.32 kB
JavaScript
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}` : ''));
};