From 28d0b8e13abf4abeb7238c48c0f6c927bfdbe3c6 Mon Sep 17 00:00:00 2001 From: Muthu Kumar Date: Fri, 1 Jun 2018 11:59:55 +0530 Subject: [PATCH] [Promise.object] initial implementation * Resolves normal objects * Resolves promises in objects * Resolves nested promises * Fails on circular objects with more than one ref to self --- index.js | 67 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) create mode 100644 index.js diff --git a/index.js b/index.js new file mode 100644 index 0000000..5b43d01 --- /dev/null +++ b/index.js @@ -0,0 +1,67 @@ +"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; \ No newline at end of file