PromiseApplySpec is a Promise utility function like Promise.all
plus Ramda's
applySpec
for arbitrary raw data structures containing Promises and functions.
-
Captures and reports all errors from promises with enough detail to trace their location in the original structure.
-
(Optionally) recursively resolves Promises within promise-resolved leaf structures.
-
(Optionally) recursively expands functions in the
spec
with supplied arguments. -
Differing from Ramda, handles structures with strings and classed objects, leaving them untouched.
-
Offers 3 different API styles (traditional, fluent, functional/tacit).
-
Covered by extensive functional testing.
// Standard API
const applySpecP = require('promise-apply-spec');
const data = [Promise.resolve(1), {a: 2, b: Promise.resolve(3)}];
applySpecP(data); // => Promise([1, {a: 2, b: 3});
const failing = [
Promise.resolve(1),
{a: Promise.reject(new Error('two'))},
Promise.reject({c: 3})
];
applySpecP(failing).catch(function(err) {
err; // => Error('Promises rejected:\n - two\n - [Object object]')
err.errors; // => [Error('two'), {c: 3}]
err.errors[0].path; // => '1.a'
err.errors[1].path; // => `undefined` (will only mutate Errors)
});
// Fluent API
const applySpecP = require('promise-apply-spec');
applySpecP
.withSpec(data)
.exec(); // => Promise([1, {a: 2, b: 3});
// Functional API
const { all, once, applySpec, unravel, unravelOnce } = require('promise-apply-spec');
const spec = {
a: Promise.resolve(1),
b: Promise.resolve({c: Promise.resolve(3), d: x => x+1})
};
// expand everything, recursively
unravel(spec, [4]).then(function(data) {
data; // => {a: 1, b: {c: 3, d: 5}}
});
// expand initial promises and functions only
unravelOnce(spec)([4]).then(function(data) {
data; // => {a: 1, b: {c: Promise(3), d: 5}}
});
// expand promises only, recursively
all(spec).then(function(data) {
data; // => {a: 1, b: {c: 3, d: x => x+1}}
});
// expand functions once only
applySpec(spec)([4]); // => spec
applySpec({a: x => x+1}, [4]); // => {a: 5}
const { applySpecP } = require('promise-apply-spec');
The fully featured main function — provided as both the default export and a named export — with a traditional, data-first and non-curried signature.
Params:
-
spec: Any: any combination of nested arrays, plain objects, functions, promises, and other values ('other values' that look like plain objects containing promises or functions will get recreated as truly plain objects)
-
args: Array: arguments to pass into invoked
spec
functions -
options: Configuration object
- apply: Boolean: whether to replace
spec
functions with their invocation — defaulttrue
- resolve: Boolean: whether to resolve promises — default
true
- once: Boolean: when true, unwraps promises at most once, then expands
functions at most once, and returns — default
false
- apply: Boolean: whether to replace
Return:
- when
options.resolve = true
, a Promise of the resolved and optionally function-applied data structure - when
options.resolve = false
, the optionally function-expanded data structure
const Fluent = require('promise-apply-spec');
The initial immutable Fluent instance with options {apply: true, resolve: true, once: false}
.
Get a new immutable Fluent with default args
provided and options.apply = true
.
Get a new immutable Fluent with default spec
provided.
Get a new immutable Fluent with options.once
reconfigured.
Get a new immutable Fluent with options.apply
reconfigured.
Get a new immutable Fluent with options.resolve
reconfigured.
Execute applySpecP
with all arguments defaulting to the Fluent instance configuration.
const { all, once, applySpec, unravel, unravelOnce } = require('promise-apply-spec');
Recursively expands promises, ignores functions.
Expands promises once, ignores functions.
Expands functions once, ignores promises.
Recursively expands promises and functions.
Expands promises once, then functions once.
-
promise-all
: Turns a flat array or object of promises into a promise of the same data structure with promises unwrapped. Limitations: only supports flat data (no nested objects or arrays), cannot recursively expand promises, does not expand functions. -
promise-all-recursive
: Turns a data structure containing promises into a promise of the data structure with promises recursively unwrapped. Limitation: does not handle promise rejections or expand functions. -
promise-traverse
: Turns a data structure containing promises into a promise of the data structure with promises unwrapped. Limitations: cannot recursively expand promises, does not handle promise rejections or expand functions. -
ramda.applySpec
: Turns aspec
object into a function that returns the same data structure but replacing inner functions with their invocation on the supplied argument. Limitations: only works forspec
objects containing only non-string primitives and functions as leaf nodes, does not resolve promises, and does not pass more than one argument tospec
functions.