📤 Deep resolve promises in objects.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

67 lines
1.6 KiB

"use strict";
const isObject = obj => obj && typeof obj === 'object' && obj.constructor === Object;
const makeCircular = (obj, path) => {
const start = (o, p, i = 1) => {
if (i === path.length) return o[p[0]] = obj;
if (p.length > 0) {
o[p[0]] = {};
return start(o[p[0]], p.slice(1), i + 1);
} else return obj;
}
return start(obj, path);
};
const findPath = (obj, query) => {
return Object.keys(obj).reduce((acc, key) => {
const value = obj[key];
if (value === query) return [...acc, key];
if (isObject(value)) return [...acc, ...findPath(value)];
else return acc;
}, []);
};
// Resolves array
const PromiseMap = (arr, functor) =>
Promise.all(arr.map(x => Promise.resolve(x).then(functor)));
// Resolves objects
const ResolveObject = obj =>
Promise.all(
Object.keys(obj).map(key =>
Promise.resolve(obj[key]).then(val => obj[key] = val))
)
.then(_ => obj);
// Resolves recrusive deep objects
const PromiseObject = parent => {
const ResolveDeepObject = object =>
Promise
.resolve(object)
.then(obj => {
if (Array.isArray(obj)) {
return PromiseMap(obj, obj => ResolveDeepObject(obj));
} else if (isObject(obj)) {
return ResolveObject(
Object
.keys(obj)
.reduce((acc, key) =>
(obj[key] === parent) ? {
...acc,
[key]: '[[ SELF ]]',
} : {
...acc,
[key]: ResolveDeepObject(obj[key]),
}, {}));
}
return obj;
});
return ResolveDeepObject(parent)
.then(obj => {
const path = findPath(obj, '[[ SELF ]]');
return path.length > 0 ? makeCircular(obj, path) : obj;
})
};
module.exports = PromiseObject;