jsonpath-mapper
Version:
A json to json transformation utility with a few nice features to use when translating for example API responses into a domain object for use in your domain-driven JavaScript applications. Can be used in React applications with the 'useMapper' hook.
242 lines (235 loc) • 8.06 kB
JavaScript
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
var jsonpathPlus = require('jsonpath-plus');
var fromEntries = require('fromentries');
const jpath = (query, json) => {
const result = jsonpathPlus.JSONPath({
path: `$${query.startsWith('.') ? '' : '.'}${query}`,
json: json,
});
if (result.length > 1 ||
(query.match(/\[.*?\]/) && !query.match(/\[[0-9]\]/)))
return result;
return result[0];
};
const isArray = (val) => val && Array.isArray(val);
const isWireFunction = (val) => typeof val === 'function';
const isNull = (val) => val === null;
const isUndefined = (val) => typeof val === 'undefined';
const isNullOrUndefined = (val) => {
if (isUndefined(val))
return true;
if (isNull(val))
return true;
return false;
};
const isNumber = (val) => typeof val === 'number';
const isMapperFunctions = (val) => typeof val === 'object' && '$path' in val;
const isObject = (val) => typeof val === 'object';
const isString = (val) => typeof val === 'string';
const tryMultiple$1 = (json, arr, $root, findMultiple) => {
const result = findMultiple(json, arr, $root).filter(r => isNumber(r) || r);
if (arr.every(i => (typeof i === "string")))
return result.length > 0 ? result[0] : null;
return result;
};
const formatResult$1 = (value, $formatting, $root) => isWireFunction($formatting)
? $formatting(value, $root)
: isObject($formatting)
? mapObject$1(value, $formatting, $root)
: value;
const handleMapperFunctions$1 = async ([k, v], json, $root) => {
let val, formatted, finalVal;
if (isString(v.$path)) {
val = jpath(v.$path, json);
}
if (isArray(v.$path)) {
val = await tryMultiple(json, v.$path, $root, findMultiple$1);
}
if (!isUndefined(v.$formatting) && !isNullOrUndefined(val)) {
if (isArray(val)) {
formatted = await Promise.all(val.map(async (inner) => !isUndefined(v.$formatting) &&
(await formatResult$1(inner, v.$formatting, $root))));
}
else {
formatted = await formatResult$1(val, v.$formatting, $root);
}
val = formatted;
}
if (v.$return) {
finalVal = await formatResult$1(val, v.$return, $root);
}
else {
finalVal = val;
}
if (!isUndefined(v.$default) && isNullOrUndefined(finalVal)) {
if (isWireFunction(v.$default)) {
finalVal = await v.$default(json, $root);
}
else {
finalVal = v.$default;
}
}
if (v.$disable &&
isWireFunction(v.$disable) &&
(await v.$disable(finalVal, $root))) {
return null;
}
return finalVal;
};
const mapElement$1 = async ([k, v], json, $root) => {
if (isNullOrUndefined(v) || v === '')
return [k, undefined];
if (isString(v)) {
return [k, jpath(v, json)];
}
if (isWireFunction(v)) {
return [k, await v(json, $root)];
}
if (isArray(v)) {
return [k, await tryMultiple(json, v, $root, findMultiple$1)];
}
if (isMapperFunctions(v)) {
return [k, await handleMapperFunctions$1([k, v], json, $root)];
}
if (typeof v === 'object')
return [k, await mapObject$1(json, v, $root)];
return [k, v];
};
const mapObject$1 = async (json, obj, $root) => {
const objectAsEntries = (await Promise.all(Object.entries(obj).map(async ([k, v]) => await mapElement$1([k, v], json, $root)))).filter(([, v]) => v !== null);
return fromEntries(objectAsEntries);
};
const mapArray$1 = async (json, arr, $root) => {
return (await Promise.all(arr.map(async (v) => await mapObject$1(json, v, $root))));
};
const findMultiple$1 = (json, arr, $root) => {
const results = arr.map(async (inner, i) => {
if (isString(inner))
return jpath(inner, json);
if (isWireFunction(inner))
return await inner(json, $root);
if (isArray(inner))
return await tryMultiple(json, inner, $root, findMultiple$1);
if (isMapperFunctions(inner))
return await handleMapperFunctions$1([i.toString(), inner], json, $root);
if (typeof inner === 'object')
return await mapObject$1(json, inner, $root);
});
return results;
};
const tryMultiple = async (json, arr, $root, findMultiple) => {
const result = (await Promise.all(findMultiple(json, arr, $root)))
.filter(r => isNumber(r) || r);
if (arr.every((i) => typeof i === 'string'))
return result.length > 0 ? result[0] : null;
return result;
};
const mapJson$1 = async (json, template) => {
const $root = json;
if (typeof template === 'function') {
return await template(json);
}
if (isArray(template)) {
return await mapArray$1(json, template, $root);
}
return await mapObject$1(json, template, $root);
};
const formatResult = (value, $formatting, $root) => isWireFunction($formatting)
? $formatting(value, $root)
: isObject($formatting)
? mapObject(value, $formatting, $root)
: value;
const handleMapperFunctions = ([k, v], json, $root) => {
let val, formatted, finalVal;
if (isString(v.$path)) {
val = jpath(v.$path, json);
}
if (isArray(v.$path)) {
val = tryMultiple$1(json, v.$path, $root, findMultiple);
}
if (!isUndefined(v.$formatting) && !isNullOrUndefined(val)) {
if (isArray(val)) {
formatted = val.map((inner) => !isUndefined(v.$formatting) &&
formatResult(inner, v.$formatting, $root));
}
else {
formatted = formatResult(val, v.$formatting, $root);
}
val = formatted;
}
if (v.$return) {
finalVal = formatResult(val, v.$return, $root);
}
else {
finalVal = val;
}
if (!isUndefined(v.$default) && isNullOrUndefined(finalVal)) {
if (isWireFunction(v.$default)) {
finalVal = v.$default(json, $root);
}
else {
finalVal = v.$default;
}
}
if (v.$disable && isWireFunction(v.$disable) && v.$disable(finalVal, $root)) {
return null;
}
return finalVal;
};
const mapElement = ([k, v], json, $root) => {
if (isNullOrUndefined(v) || v === '')
return [k, undefined];
if (isString(v)) {
return [k, jpath(v, json)];
}
if (isWireFunction(v)) {
return [k, v(json, $root)];
}
if (isArray(v)) {
return [k, tryMultiple$1(json, v, $root, findMultiple)];
}
if (isMapperFunctions(v)) {
return [k, handleMapperFunctions([k, v], json, $root)];
}
if (typeof v === 'object')
return [k, mapObject(json, v, $root)];
return [k, v];
};
const mapObject = (json, obj, $root) => {
const objectAsEntries = Object.entries(obj)
.map(([k, v]) => mapElement([k, v], json, $root))
.filter((obj) => isArray(obj) && obj[1] !== null);
return fromEntries(objectAsEntries);
};
const mapArray = (json, arr, $root) => {
return arr.map((v) => mapObject(json, v, $root));
};
const findMultiple = (json, arr, $root) => {
const results = arr.map((inner, i) => {
if (isString(inner))
return jpath(inner, json);
if (isWireFunction(inner))
return inner(json, $root);
if (isArray(inner))
return tryMultiple$1(json, inner, $root, findMultiple);
if (isMapperFunctions(inner))
return handleMapperFunctions([i.toString(), inner], json, $root);
if (typeof inner === 'object')
return mapObject(json, inner, $root);
});
return results;
};
const mapJson = (json, template) => {
const $root = json;
if (typeof template === 'function') {
return template(json);
}
if (isArray(template)) {
return mapArray(json, template, $root);
}
return mapObject(json, template, $root);
};
exports.default = mapJson;
exports.jpath = jpath;
exports.mapJsonAsync = mapJson$1;