UNPKG

@creditkarma/dynamic-config

Version:

Dynamic Config for Node.js backed by Consul and Vault

164 lines 5.25 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.resolveObjectPromises = exports.valuesForPromises = exports.race = exports.some = void 0; const object_1 = require("./object"); function executePromiseAtIndex(index, promise) { return promise.then((val) => { return [index, val]; }, (err) => { return [index, null]; }); } function some(promises) { return new Promise((resolve, reject) => { const temp = []; let count = 0; promises.forEach((next, index) => { executePromiseAtIndex(index, next).then((tuple) => { count++; temp[tuple[0]] = tuple[1]; if (count === promises.length) { const result = temp.filter((val) => val !== null); if (result.length > 0) { resolve(result); } else { reject(new Error('All promises completed without success')); } } }, (err) => { count++; if (count >= promises.length) { const result = temp.filter((val) => val !== null); if (result.length > 0) { resolve(result); } else { reject(new Error('All promises completed without success')); } } }); }); }); } exports.some = some; /** * Given an array of Promises return a new Promise that resolves with the value * of the first of the array to resolve, ignoring rejections. The resulting Promise * only rejects if all of the Promises reject. */ function race(promises) { const count = promises.length; let current = 0; let resolved = false; return new Promise((resolve, reject) => { promises.forEach((next) => { next.then((val) => { if (!resolved) { resolved = true; resolve(val); } }, (err) => { current++; if (!resolved && current === count) { // Propagate the last promise error back to caller reject(err); } }); }); }); } exports.race = race; /** * Recursively traverses an object, looking for keys with Promised values and returns a Promise of * the object with all nested Promises resolved. */ async function valuesForPromises(promises) { return Promise.all(promises.map((next, index) => { return resolveAtIndex(next, index); })).then((values) => { return processValues(values); }); } exports.valuesForPromises = valuesForPromises; function processValues(values) { return values .sort((a, b) => { if (a[1] < b[1]) { return -1; } else { return 1; } }) .map((next) => { return next[0]; }); } function resolveAtIndex(promise, index) { return new Promise((resolve, reject) => { promise.then((val) => { return resolve([val, index]); }, (err) => { return reject(err); }); }); } function appendUpdateForObject(value, path, updates) { if (value instanceof Promise) { updates.push([path, value]); } else if (typeof value === 'object') { collectUnresolvedPromises(value, path, updates); } } function collectUnresolvedPromises(obj, path = [], updates = []) { if (Array.isArray(obj)) { for (let i = 0; i < obj.length; i++) { const value = obj[i]; const newPath = [...path, `${i}`]; appendUpdateForObject(value, newPath, updates); } return updates; } else if (obj instanceof Promise) { updates.push([path, obj]); return updates; } else if (typeof obj === 'object') { for (const key of Object.keys(obj)) { const value = obj[key]; const newPath = [...path, key]; appendUpdateForObject(value, newPath, updates); } return updates; } else { return []; } } async function handleUnresolved(unresolved, base) { const paths = unresolved.map((next) => next[0].join('.')); const promises = unresolved.map((next) => next[1]); const resolvedPromises = await Promise.all(promises.map((next) => { return next.then((val) => { const nested = collectUnresolvedPromises(val); if (nested.length > 0) { return handleUnresolved(nested, val); } else { return Promise.resolve(val); } }); })); const newObj = resolvedPromises.reduce((acc, next, currentIndex) => { return (0, object_1.setValueForKey)(paths[currentIndex], next, acc); }, base); return newObj; } async function resolveObjectPromises(obj) { const unresolved = collectUnresolvedPromises(obj); return handleUnresolved(unresolved, obj); } exports.resolveObjectPromises = resolveObjectPromises; //# sourceMappingURL=promises.js.map