@visisoft/staticland
Advanced tools
Comparing version 0.1.15 to 0.1.16
Changelog | ||
========= | ||
0.1.16 | ||
------- | ||
- Begun API for CancelableComputation incl. natural transformations to and from Bacon and Most streams | ||
0.1.15 | ||
@@ -5,0 +9,0 @@ ------ |
/* @license Apache-2.0 | ||
@visisoft/staticland v.0.1.15 visisoft.de | ||
(Build date: 2/12/2021 - 12:19:42 AM) | ||
@visisoft/staticland v.0.1.16 visisoft.de | ||
(Build date: 3/1/2021 - 1:05:25 PM) | ||
*/ | ||
@@ -5,0 +5,0 @@ 'use strict'; |
/* @license Apache-2.0 | ||
@visisoft/staticland v.0.1.15 visisoft.de | ||
(Build date: 2/12/2021 - 12:19:42 AM) | ||
@visisoft/staticland v.0.1.16 visisoft.de | ||
(Build date: 3/1/2021 - 1:05:25 PM) | ||
*/ | ||
@@ -5,0 +5,0 @@ 'use strict'; |
/* @license Apache-2.0 | ||
@visisoft/staticland v.0.1.15 visisoft.de | ||
(Build date: 2/12/2021 - 12:19:42 AM) | ||
@visisoft/staticland v.0.1.16 visisoft.de | ||
(Build date: 3/1/2021 - 1:05:25 PM) | ||
*/ | ||
@@ -11,3 +11,35 @@ 'use strict'; | ||
// map :: (a -> b) -> Promise e a -> Promise e b | ||
var map = semmelRamda.curry((fn, aPromise) => aPromise.then(fn)); | ||
/** | ||
* StaticLand: ap.js | ||
* | ||
* Created by Matthias Seemann on 1.03.2021. | ||
* Copyright (c) 2021 Visisoft OHG. All rights reserved. | ||
*/ | ||
const | ||
// sequential ap | ||
// This implementation prioritises the left promise in way that | ||
// if the left promise fails it's rejected value takes precedence over | ||
// the rejected value of the right promise regardless of the time sequence. | ||
// Caveat: if the right promise fails, is that an UnhandledPromiseRejection? | ||
// Note: ap(mf, ma) = chain(f => map(f, ma)) | ||
//ap = curry((fnPromise, aPromise) => fnPromise.then(fn => aPromise.then(fn))), | ||
// parallel ap | ||
// Note: ap(mf, ma) = chain(f => map(f, ma)) | ||
// ap :: Promise (a -> b) -> Promise a -> Promise b | ||
ap_p = semmelRamda.curry((fnPromise, aPromise) => | ||
Promise.all([ | ||
fnPromise, | ||
aPromise | ||
]) | ||
.then(([fn, a]) => fn(a)) | ||
); | ||
var liftA2 = semmelRamda.curry((f, ma, mb) => ap_p(map(f, ma), mb)); | ||
/** | ||
* StaticLand: promise.js | ||
@@ -43,53 +75,3 @@ * | ||
ap_ = semmelRamda.curry((fnPromise, aPromise) => fnPromise.then(fn => aPromise.then(fn))), | ||
// this implementation avoids the UnhandledPromiseRejection error | ||
// when Promise a fails | ||
// ap :: Promise (a -> b) -> Promise a -> Promise b | ||
ap = semmelRamda.curry((fnPromise, aPromise) => { | ||
if (typeof Promise.allSettled === 'function') { | ||
return Promise.allSettled([fnPromise, aPromise]) | ||
.then(([fnOutcome, anOutcome]) => { | ||
if ((fnOutcome.status === 'fulfilled') && (anOutcome.status === 'fulfilled')) { | ||
return fnOutcome.value(anOutcome.value); | ||
} | ||
else if (fnOutcome.status === 'fulfilled') { | ||
return Promise.reject(anOutcome.reason); | ||
} | ||
else if (anOutcome.status === 'fulfilled') { | ||
return Promise.reject(fnOutcome.reason); | ||
} | ||
else if (anOutcome.reason === fnOutcome.reason) { | ||
return Promise.reject(fnOutcome.reason); | ||
} | ||
else { | ||
const | ||
aggregateError = new Error(`${fnOutcome.reason.message},\n${anOutcome.reason.message}`); | ||
aggregateError.name = "AggregateError"; | ||
if (anOutcome.reason.name === "AggregateError") { | ||
aggregateError.errors = anOutcome.reason.errors.concat([fnOutcome.reason]); | ||
} | ||
else if (fnOutcome.reason.name === "AggregateError") { | ||
aggregateError.errors = fnOutcome.reason.errors.concat([anOutcome.reason]); | ||
} | ||
else { | ||
aggregateError.errors = [fnOutcome.reason, anOutcome.reason]; | ||
} | ||
return Promise.reject(aggregateError); | ||
} | ||
}); | ||
} | ||
else { | ||
return ap_(fnPromise, aPromise); | ||
} | ||
}), | ||
// Transformation // | ||
// map :: (a -> b) -> Promise e a -> Promise e b | ||
map = semmelRamda.curry((fn, aPromise) => aPromise.then(fn)), | ||
@@ -193,2 +175,62 @@ /** | ||
// This implementation prioritises the left promise in way that | ||
// if the left promise fails it's rejected value takes precedence over | ||
// the rejected value of the right promise regardless of the time sequence. | ||
// Thus if the right promise fails that's UnhandledPromiseRejection | ||
// Note: ap(mf, ma) = chain(f => map(f, ma)) | ||
// ap :: Promise (a -> b) -> Promise a -> Promise b | ||
/*ap_ = curry((fnPromise, aPromise) => fnPromise.then(fn => aPromise.then(fn))),*/ | ||
// this implementation avoids the UnhandledPromiseRejection error | ||
// when Promise a fails. | ||
// Note: Is the UnhandledPromiseRejection really an issue? | ||
// It occurs only if there is no .catch or .then(, onError) | ||
// in a promise which is a result of ap (i.e. which is created on calling .then) | ||
// see https://stackoverflow.com/a/52409612/564642 | ||
// ap :: Promise (a -> b) -> Promise a -> Promise b | ||
/*ap = curry((fnPromise, aPromise) => { | ||
if (typeof Promise.allSettled === 'function') { | ||
return Promise.allSettled([fnPromise, aPromise]) | ||
.then(([fnOutcome, anOutcome]) => { | ||
if ((fnOutcome.status === 'fulfilled') && (anOutcome.status === 'fulfilled')) { | ||
return fnOutcome.value(anOutcome.value); | ||
} | ||
else if (fnOutcome.status === 'fulfilled') { | ||
return Promise.reject(anOutcome.reason); | ||
} | ||
else if (anOutcome.status === 'fulfilled') { | ||
return Promise.reject(fnOutcome.reason); | ||
} | ||
else if (anOutcome.reason === fnOutcome.reason) { | ||
return Promise.reject(fnOutcome.reason); | ||
} | ||
else { | ||
const | ||
aggregateError = new Error(`${fnOutcome.reason.message},\n${anOutcome.reason.message}`); | ||
aggregateError.name = "AggregateError"; | ||
if (anOutcome.reason.name === "AggregateError") { | ||
aggregateError.errors = anOutcome.reason.errors.concat([fnOutcome.reason]); | ||
} | ||
else if (fnOutcome.reason.name === "AggregateError") { | ||
aggregateError.errors = fnOutcome.reason.errors.concat([anOutcome.reason]); | ||
} | ||
else { | ||
aggregateError.errors = [fnOutcome.reason, anOutcome.reason]; | ||
} | ||
return Promise.reject(aggregateError); | ||
} | ||
}); | ||
} | ||
else { | ||
return ap_(fnPromise, aPromise); | ||
} | ||
}), | ||
liftA2 = curry((fn, pa, pb) => | ||
ap(map(fn, pa), pb) | ||
),*/ | ||
// :: [Promise e a] -> Promise e [a] | ||
@@ -224,3 +266,3 @@ all = promises => Promise.all(promises), | ||
exports.alt = alt; | ||
exports.ap = ap; | ||
exports.ap = ap_p; | ||
exports.bimap = bimap; | ||
@@ -235,2 +277,3 @@ exports.chain = chain; | ||
exports.join = join; | ||
exports.liftA2 = liftA2; | ||
exports.map = map; | ||
@@ -237,0 +280,0 @@ exports.mapRej = mapRej; |
/* @license Apache-2.0 | ||
@visisoft/staticland v.0.1.15 visisoft.de | ||
(Build date: 2/12/2021 - 12:19:42 AM) | ||
@visisoft/staticland v.0.1.16 visisoft.de | ||
(Build date: 3/1/2021 - 1:05:25 PM) | ||
*/ | ||
@@ -10,4 +10,37 @@ 'use strict'; | ||
var semmelRamda = require('semmel-ramda'); | ||
var Bacon = require('baconjs'); | ||
// map :: (a -> b) -> Promise e a -> Promise e b | ||
var map_p = semmelRamda.curry((fn, aPromise) => aPromise.then(fn)); | ||
/** | ||
* StaticLand: ap.js | ||
* | ||
* Created by Matthias Seemann on 1.03.2021. | ||
* Copyright (c) 2021 Visisoft OHG. All rights reserved. | ||
*/ | ||
const | ||
// sequential ap | ||
// This implementation prioritises the left promise in way that | ||
// if the left promise fails it's rejected value takes precedence over | ||
// the rejected value of the right promise regardless of the time sequence. | ||
// Caveat: if the right promise fails, is that an UnhandledPromiseRejection? | ||
// Note: ap(mf, ma) = chain(f => map(f, ma)) | ||
//ap = curry((fnPromise, aPromise) => fnPromise.then(fn => aPromise.then(fn))), | ||
// parallel ap | ||
// Note: ap(mf, ma) = chain(f => map(f, ma)) | ||
// ap :: Promise (a -> b) -> Promise a -> Promise b | ||
ap_p = semmelRamda.curry((fnPromise, aPromise) => | ||
Promise.all([ | ||
fnPromise, | ||
aPromise | ||
]) | ||
.then(([fn, a]) => fn(a)) | ||
); | ||
var liftA2 = semmelRamda.curry((f, ma, mb) => ap_p(map_p(f, ma), mb)); | ||
/** | ||
* StaticLand: promise.js | ||
@@ -43,53 +76,3 @@ * | ||
ap_ = semmelRamda.curry((fnPromise, aPromise) => fnPromise.then(fn => aPromise.then(fn))), | ||
// this implementation avoids the UnhandledPromiseRejection error | ||
// when Promise a fails | ||
// ap :: Promise (a -> b) -> Promise a -> Promise b | ||
ap = semmelRamda.curry((fnPromise, aPromise) => { | ||
if (typeof Promise.allSettled === 'function') { | ||
return Promise.allSettled([fnPromise, aPromise]) | ||
.then(([fnOutcome, anOutcome]) => { | ||
if ((fnOutcome.status === 'fulfilled') && (anOutcome.status === 'fulfilled')) { | ||
return fnOutcome.value(anOutcome.value); | ||
} | ||
else if (fnOutcome.status === 'fulfilled') { | ||
return Promise.reject(anOutcome.reason); | ||
} | ||
else if (anOutcome.status === 'fulfilled') { | ||
return Promise.reject(fnOutcome.reason); | ||
} | ||
else if (anOutcome.reason === fnOutcome.reason) { | ||
return Promise.reject(fnOutcome.reason); | ||
} | ||
else { | ||
const | ||
aggregateError = new Error(`${fnOutcome.reason.message},\n${anOutcome.reason.message}`); | ||
aggregateError.name = "AggregateError"; | ||
if (anOutcome.reason.name === "AggregateError") { | ||
aggregateError.errors = anOutcome.reason.errors.concat([fnOutcome.reason]); | ||
} | ||
else if (fnOutcome.reason.name === "AggregateError") { | ||
aggregateError.errors = fnOutcome.reason.errors.concat([anOutcome.reason]); | ||
} | ||
else { | ||
aggregateError.errors = [fnOutcome.reason, anOutcome.reason]; | ||
} | ||
return Promise.reject(aggregateError); | ||
} | ||
}); | ||
} | ||
else { | ||
return ap_(fnPromise, aPromise); | ||
} | ||
}), | ||
// Transformation // | ||
// map :: (a -> b) -> Promise e a -> Promise e b | ||
map = semmelRamda.curry((fn, aPromise) => aPromise.then(fn)), | ||
@@ -193,2 +176,62 @@ /** | ||
// This implementation prioritises the left promise in way that | ||
// if the left promise fails it's rejected value takes precedence over | ||
// the rejected value of the right promise regardless of the time sequence. | ||
// Thus if the right promise fails that's UnhandledPromiseRejection | ||
// Note: ap(mf, ma) = chain(f => map(f, ma)) | ||
// ap :: Promise (a -> b) -> Promise a -> Promise b | ||
/*ap_ = curry((fnPromise, aPromise) => fnPromise.then(fn => aPromise.then(fn))),*/ | ||
// this implementation avoids the UnhandledPromiseRejection error | ||
// when Promise a fails. | ||
// Note: Is the UnhandledPromiseRejection really an issue? | ||
// It occurs only if there is no .catch or .then(, onError) | ||
// in a promise which is a result of ap (i.e. which is created on calling .then) | ||
// see https://stackoverflow.com/a/52409612/564642 | ||
// ap :: Promise (a -> b) -> Promise a -> Promise b | ||
/*ap = curry((fnPromise, aPromise) => { | ||
if (typeof Promise.allSettled === 'function') { | ||
return Promise.allSettled([fnPromise, aPromise]) | ||
.then(([fnOutcome, anOutcome]) => { | ||
if ((fnOutcome.status === 'fulfilled') && (anOutcome.status === 'fulfilled')) { | ||
return fnOutcome.value(anOutcome.value); | ||
} | ||
else if (fnOutcome.status === 'fulfilled') { | ||
return Promise.reject(anOutcome.reason); | ||
} | ||
else if (anOutcome.status === 'fulfilled') { | ||
return Promise.reject(fnOutcome.reason); | ||
} | ||
else if (anOutcome.reason === fnOutcome.reason) { | ||
return Promise.reject(fnOutcome.reason); | ||
} | ||
else { | ||
const | ||
aggregateError = new Error(`${fnOutcome.reason.message},\n${anOutcome.reason.message}`); | ||
aggregateError.name = "AggregateError"; | ||
if (anOutcome.reason.name === "AggregateError") { | ||
aggregateError.errors = anOutcome.reason.errors.concat([fnOutcome.reason]); | ||
} | ||
else if (fnOutcome.reason.name === "AggregateError") { | ||
aggregateError.errors = fnOutcome.reason.errors.concat([anOutcome.reason]); | ||
} | ||
else { | ||
aggregateError.errors = [fnOutcome.reason, anOutcome.reason]; | ||
} | ||
return Promise.reject(aggregateError); | ||
} | ||
}); | ||
} | ||
else { | ||
return ap_(fnPromise, aPromise); | ||
} | ||
}), | ||
liftA2 = curry((fn, pa, pb) => | ||
ap(map(fn, pa), pb) | ||
),*/ | ||
// :: [Promise e a] -> Promise e [a] | ||
@@ -227,3 +270,2 @@ all = promises => Promise.all(promises), | ||
alt: alt, | ||
ap: ap, | ||
bimap: bimap, | ||
@@ -236,3 +278,3 @@ chain: chain, | ||
create: create, | ||
map: map, | ||
map: map_p, | ||
mapRej: mapRej, | ||
@@ -245,3 +287,5 @@ race: race, | ||
join: join, | ||
unit: unit | ||
unit: unit, | ||
ap: ap_p, | ||
liftA2: liftA2 | ||
}); | ||
@@ -308,3 +352,3 @@ | ||
// map :: (a -> b) -> Maybe a -> Maybe b | ||
map$1 = semmelRamda.curry((f, mx) => mx.map(semmelRamda.unary(f))), | ||
map = semmelRamda.curry((f, mx) => mx.map(semmelRamda.unary(f))), | ||
// chain :: (a -> Maybe b) -> Maybe a -> Maybe b | ||
@@ -315,3 +359,3 @@ //chain = curry((f, mx) => isJust(mx) ? mx.flatMap(f) : singleNothing), | ||
ap$1 = semmelRamda.curry((mf, mx) => chain$1(f => map$1(f, mx), mf)), | ||
ap = semmelRamda.curry((mf, mx) => chain$1(f => map(f, mx), mf)), | ||
reduce = semmelRamda.reduce,//curry((f, initial, mx) => mx.reduce(f, initial)), | ||
@@ -358,3 +402,3 @@ | ||
maybe = semmelRamda.curry((nothingFn, justFn, ma) => | ||
isJust(ma) ? getOrElse("THIS_VALUE_SHOWING_ANYWHERE_IS_AN_ERROR", map$1(justFn, ma)) | ||
isJust(ma) ? getOrElse("THIS_VALUE_SHOWING_ANYWHERE_IS_AN_ERROR", map(justFn, ma)) | ||
: nothingFn() | ||
@@ -407,6 +451,6 @@ ), | ||
lift: lift, | ||
map: map$1, | ||
map: map, | ||
maybe: maybe, | ||
chain: chain$1, | ||
ap: ap$1, | ||
ap: ap, | ||
reduce: reduce, | ||
@@ -456,3 +500,3 @@ tap: tap$1, | ||
map$2 = semmelRamda.curry((f, mx) => | ||
map$1 = semmelRamda.curry((f, mx) => | ||
semmelRamda.when(isRight, semmelRamda.compose(of$2, semmelRamda.unary(f), semmelRamda.nth(1)))(mx) | ||
@@ -499,3 +543,3 @@ ), | ||
left: left, | ||
map: map$2, | ||
map: map$1, | ||
of: of$2, | ||
@@ -505,2 +549,65 @@ right: right | ||
// :: Promise e a -> Cancelable e a | ||
const promiseToCancelable = promise => (res, rej) => { | ||
let | ||
resolveInner = res, | ||
rejectInner = rej; | ||
promise.then(x => resolveInner(x), e => rejectInner(e)); | ||
return () => { | ||
resolveInner = () => undefined; | ||
rejectInner = () => undefined; | ||
}; | ||
}; | ||
const cancelableToPromise = cancelable => new Promise(cancelable); | ||
const | ||
baconObservableToCancelable = observable => (res, rej) => | ||
observable.last().subscribe(evt => { | ||
if (evt.hasValue) { | ||
res(evt.value); | ||
} | ||
else if (evt.isError) { | ||
rej(evt.error); | ||
} | ||
return Bacon.noMore; | ||
}); | ||
const | ||
cancelableToBaconStream = cc => Bacon.fromBinder(sink => { | ||
return cc( | ||
x => { | ||
sink(x); | ||
sink(new Bacon.End()); | ||
}, | ||
e => { | ||
sink(new Bacon.Error(e)); | ||
sink(new Bacon.End()); | ||
} | ||
); | ||
}); | ||
const | ||
// :: Number -> a -> Cancelable * a | ||
laterSucceed = semmelRamda.curry((dt, value) => (resolve, unused) => { | ||
const timer = setTimeout(resolve, dt, value); | ||
return () => { clearTimeout(timer); }; | ||
}); | ||
const | ||
// :: a -> Cancelable * a | ||
of$3 = laterSucceed(0); | ||
// :: Number -> e -> Cancelable e * | ||
const laterFail = semmelRamda.curry((dt, value) => (unused, reject) => { | ||
const timer = setTimeout(reject, dt, value); | ||
return () => { clearTimeout(timer); }; | ||
}); | ||
const reject$1 = laterFail(0); | ||
var eitherToCancelable = either(reject$1, of$3); | ||
/** | ||
@@ -535,3 +642,3 @@ * StaticLand: transformations.js | ||
// maybeOfPromiseToPromiseOfMaybe :: Maybe Promise e a -> Promise e Maybe a | ||
maybeOfPromiseToPromiseOfMaybe = maybe(semmelRamda.compose(of, nothing), map(of$1)), | ||
maybeOfPromiseToPromiseOfMaybe = maybe(semmelRamda.compose(of, nothing), map_p(of$1)), | ||
@@ -541,3 +648,3 @@ // keyPromiseToPromiseCollection :: String -> {ki: Promise e vi, k:v …} -> Promise e {ki:vi, k:v …} | ||
keyPromiseToPromiseCollection = semmelRamda.curry((key, obj) => | ||
map(semmelRamda.assoc(key, semmelRamda.__, obj), obj[key]) | ||
map_p(semmelRamda.assoc(key, semmelRamda.__, obj), obj[key]) | ||
); | ||
@@ -553,5 +660,163 @@ | ||
keyPromiseToPromiseCollection: keyPromiseToPromiseCollection, | ||
keyMaybeToMaybeObj: keyMaybeToMaybeObj | ||
keyMaybeToMaybeObj: keyMaybeToMaybeObj, | ||
promiseToCancelable: promiseToCancelable, | ||
cancelableToPromise: cancelableToPromise, | ||
observableToCancelable: baconObservableToCancelable, | ||
cancelableToEventStream: cancelableToBaconStream, | ||
eitherToCancelable: eitherToCancelable | ||
}); | ||
const race$1 = semmelRamda.curry((ccA, ccB) => (resolve, reject) => { | ||
let | ||
cancelB, | ||
cancelA = ccA( | ||
x => { | ||
cancelB(); | ||
resolve(x); | ||
}, | ||
e => { | ||
cancelB(); | ||
reject(e); | ||
} | ||
); | ||
cancelB = ccB( | ||
x => { | ||
cancelA(); | ||
resolve(x); | ||
}, | ||
e => { | ||
cancelA(); | ||
reject(e); | ||
} | ||
); | ||
return () => { | ||
cancelA(); | ||
cancelB(); | ||
}; | ||
}); | ||
var map$2 = semmelRamda.curry((fn, cc) => (resolve, reject) => cc(semmelRamda.o(resolve, fn), reject)); | ||
var chain$3 = semmelRamda.curry((fn, cc) => (resolve, reject) => { | ||
let cancel = semmelRamda.identity; | ||
const resolveInner = x => { | ||
cancel = fn(x)(resolve, reject); | ||
}; | ||
cancel = cc(resolveInner, reject); | ||
return () => cancel(); | ||
}); | ||
/** | ||
* StaticLand: ap.js | ||
* | ||
* Created by Matthias Seemann on 27.02.2021. | ||
* Copyright (c) 2021 Visisoft OHG. All rights reserved. | ||
*/ | ||
const | ||
// Note: parallel execution | ||
// Sequential execution is derived from chain and map: ap(mf, ma) = chain(f => map(f, ma), mf) | ||
ap$1 = semmelRamda.curry((ccF, ccB) => (res, rej) => { | ||
let theF, theB, cancelB, hasB; | ||
const cancelF = ccF( | ||
f => { | ||
if (hasB) { | ||
res(f(theB)); | ||
} | ||
else { | ||
theF = f; | ||
} | ||
}, | ||
e => { | ||
if (!hasB) { | ||
cancelB(); | ||
} | ||
rej(e); | ||
} | ||
); | ||
cancelB = ccB( | ||
b => { | ||
if (theF) { | ||
res(theF(b)); | ||
} | ||
hasB = true; | ||
}, | ||
e => { | ||
if (!theF) { | ||
cancelF(); | ||
} | ||
rej(e); | ||
}); | ||
return () => { | ||
if (!theF) { | ||
cancelF(); | ||
} | ||
if (!hasB) { | ||
cancelB(); | ||
} | ||
}; | ||
}); | ||
var liftA2$1 = semmelRamda.curry((f, ma, mb) => ap$1(map$2(f, ma), mb)); | ||
/*** | ||
* Browser version | ||
*/ | ||
const | ||
IS_ABORT_CONTROLLER_SUPPORTED = typeof AbortController === 'function', | ||
/** | ||
* @param {Object} options | ||
* @param {String|URL} options.url | ||
* @param {Object} [options.init] | ||
* @return {CancelableComputation} | ||
*/ | ||
// fetchResponse :: {url: (String|URL), init: {}} -> CancelableComputation Error Response | ||
fetchResponse = ({url, init = {}}) => (resolve, reject) => { | ||
const | ||
abortController = IS_ABORT_CONTROLLER_SUPPORTED ? new AbortController() : undefined, | ||
cancelPromiseContinuation = | ||
promiseToCancelable( | ||
fetch( | ||
url.toString(), | ||
{...init, signal: abortController ? abortController.signal: undefined} | ||
) | ||
)(resolve, reject); | ||
return () => { | ||
cancelPromiseContinuation(); | ||
if (abortController) { | ||
abortController.abort(); | ||
} | ||
}; | ||
}; | ||
/** | ||
* @typedef {function(function(*): void, function(*): void): function(): void} CancelableComputation | ||
*/ | ||
var cancelable = /*#__PURE__*/Object.freeze({ | ||
__proto__: null, | ||
of: of$3, | ||
reject: reject$1, | ||
later: laterSucceed, | ||
laterReject: laterFail, | ||
race: race$1, | ||
map: map$2, | ||
chain: chain$3, | ||
ap: ap$1, | ||
liftA2: liftA2$1, | ||
fetchResponse: fetchResponse | ||
}); | ||
exports.C = cancelable; | ||
exports.E = either$1; | ||
@@ -558,0 +823,0 @@ exports.M = maybe$1; |
/* @license Apache-2.0 | ||
@visisoft/staticland v.0.1.15 visisoft.de | ||
(Build date: 2/12/2021 - 12:19:42 AM) | ||
@visisoft/staticland v.0.1.16 visisoft.de | ||
(Build date: 3/1/2021 - 1:05:25 PM) | ||
*/ | ||
@@ -10,2 +10,3 @@ 'use strict'; | ||
var semmelRamda = require('semmel-ramda'); | ||
var Bacon = require('baconjs'); | ||
@@ -74,3 +75,35 @@ /** | ||
// map :: (a -> b) -> Promise e a -> Promise e b | ||
var map_p = semmelRamda.curry((fn, aPromise) => aPromise.then(fn)); | ||
/** | ||
* StaticLand: ap.js | ||
* | ||
* Created by Matthias Seemann on 1.03.2021. | ||
* Copyright (c) 2021 Visisoft OHG. All rights reserved. | ||
*/ | ||
const | ||
// sequential ap | ||
// This implementation prioritises the left promise in way that | ||
// if the left promise fails it's rejected value takes precedence over | ||
// the rejected value of the right promise regardless of the time sequence. | ||
// Caveat: if the right promise fails, is that an UnhandledPromiseRejection? | ||
// Note: ap(mf, ma) = chain(f => map(f, ma)) | ||
//ap = curry((fnPromise, aPromise) => fnPromise.then(fn => aPromise.then(fn))), | ||
// parallel ap | ||
// Note: ap(mf, ma) = chain(f => map(f, ma)) | ||
// ap :: Promise (a -> b) -> Promise a -> Promise b | ||
ap_p = semmelRamda.curry((fnPromise, aPromise) => | ||
Promise.all([ | ||
fnPromise, | ||
aPromise | ||
]) | ||
.then(([fn, a]) => fn(a)) | ||
); | ||
semmelRamda.curry((f, ma, mb) => ap_p(map_p(f, ma), mb)); | ||
/** | ||
* StaticLand: promise.js | ||
@@ -99,51 +132,3 @@ * | ||
ap_ = semmelRamda.curry((fnPromise, aPromise) => fnPromise.then(fn => aPromise.then(fn))), | ||
// this implementation avoids the UnhandledPromiseRejection error | ||
// when Promise a fails | ||
// ap :: Promise (a -> b) -> Promise a -> Promise b | ||
ap = semmelRamda.curry((fnPromise, aPromise) => { | ||
if (typeof Promise.allSettled === 'function') { | ||
return Promise.allSettled([fnPromise, aPromise]) | ||
.then(([fnOutcome, anOutcome]) => { | ||
if ((fnOutcome.status === 'fulfilled') && (anOutcome.status === 'fulfilled')) { | ||
return fnOutcome.value(anOutcome.value); | ||
} | ||
else if (fnOutcome.status === 'fulfilled') { | ||
return Promise.reject(anOutcome.reason); | ||
} | ||
else if (anOutcome.status === 'fulfilled') { | ||
return Promise.reject(fnOutcome.reason); | ||
} | ||
else if (anOutcome.reason === fnOutcome.reason) { | ||
return Promise.reject(fnOutcome.reason); | ||
} | ||
else { | ||
const | ||
aggregateError = new Error(`${fnOutcome.reason.message},\n${anOutcome.reason.message}`); | ||
aggregateError.name = "AggregateError"; | ||
if (anOutcome.reason.name === "AggregateError") { | ||
aggregateError.errors = anOutcome.reason.errors.concat([fnOutcome.reason]); | ||
} | ||
else if (fnOutcome.reason.name === "AggregateError") { | ||
aggregateError.errors = fnOutcome.reason.errors.concat([anOutcome.reason]); | ||
} | ||
else { | ||
aggregateError.errors = [fnOutcome.reason, anOutcome.reason]; | ||
} | ||
return Promise.reject(aggregateError); | ||
} | ||
}); | ||
} | ||
else { | ||
return ap_(fnPromise, aPromise); | ||
} | ||
}), | ||
// Transformation // | ||
// map :: (a -> b) -> Promise e a -> Promise e b | ||
map$1 = semmelRamda.curry((fn, aPromise) => aPromise.then(fn)), | ||
@@ -309,3 +294,3 @@ /** | ||
// map :: (a -> b) -> Maybe a -> Maybe b | ||
map$2 = semmelRamda.curry((f, mx) => mx.map(semmelRamda.unary(f))), | ||
map$1 = semmelRamda.curry((f, mx) => mx.map(semmelRamda.unary(f))), | ||
// chain :: (a -> Maybe b) -> Maybe a -> Maybe b | ||
@@ -316,3 +301,3 @@ //chain = curry((f, mx) => isJust(mx) ? mx.flatMap(f) : singleNothing), | ||
ap$1 = semmelRamda.curry((mf, mx) => chain$2(f => map$2(f, mx), mf)), | ||
ap = semmelRamda.curry((mf, mx) => chain$2(f => map$1(f, mx), mf)), | ||
reduce = semmelRamda.reduce,//curry((f, initial, mx) => mx.reduce(f, initial)), | ||
@@ -359,3 +344,3 @@ | ||
maybe = semmelRamda.curry((nothingFn, justFn, ma) => | ||
isJust(ma) ? getOrElse("THIS_VALUE_SHOWING_ANYWHERE_IS_AN_ERROR", map$2(justFn, ma)) | ||
isJust(ma) ? getOrElse("THIS_VALUE_SHOWING_ANYWHERE_IS_AN_ERROR", map$1(justFn, ma)) | ||
: nothingFn() | ||
@@ -373,2 +358,65 @@ ), | ||
// :: Promise e a -> Cancelable e a | ||
const promiseToCancelable = promise => (res, rej) => { | ||
let | ||
resolveInner = res, | ||
rejectInner = rej; | ||
promise.then(x => resolveInner(x), e => rejectInner(e)); | ||
return () => { | ||
resolveInner = () => undefined; | ||
rejectInner = () => undefined; | ||
}; | ||
}; | ||
const cancelableToPromise = cancelable => new Promise(cancelable); | ||
const | ||
baconObservableToCancelable = observable => (res, rej) => | ||
observable.last().subscribe(evt => { | ||
if (evt.hasValue) { | ||
res(evt.value); | ||
} | ||
else if (evt.isError) { | ||
rej(evt.error); | ||
} | ||
return Bacon.noMore; | ||
}); | ||
const | ||
cancelableToBaconStream = cc => Bacon.fromBinder(sink => { | ||
return cc( | ||
x => { | ||
sink(x); | ||
sink(new Bacon.End()); | ||
}, | ||
e => { | ||
sink(new Bacon.Error(e)); | ||
sink(new Bacon.End()); | ||
} | ||
); | ||
}); | ||
const | ||
// :: Number -> a -> Cancelable * a | ||
laterSucceed = semmelRamda.curry((dt, value) => (resolve, unused) => { | ||
const timer = setTimeout(resolve, dt, value); | ||
return () => { clearTimeout(timer); }; | ||
}); | ||
const | ||
// :: a -> Cancelable * a | ||
of$3 = laterSucceed(0); | ||
// :: Number -> e -> Cancelable e * | ||
const laterFail = semmelRamda.curry((dt, value) => (unused, reject) => { | ||
const timer = setTimeout(reject, dt, value); | ||
return () => { clearTimeout(timer); }; | ||
}); | ||
const reject$1 = laterFail(0); | ||
var eitherToCancelable = either(reject$1, of$3); | ||
/** | ||
@@ -403,3 +451,3 @@ * StaticLand: transformations.js | ||
// maybeOfPromiseToPromiseOfMaybe :: Maybe Promise e a -> Promise e Maybe a | ||
maybeOfPromiseToPromiseOfMaybe = maybe(semmelRamda.compose(of$1, nothing), map$1(of$2)), | ||
maybeOfPromiseToPromiseOfMaybe = maybe(semmelRamda.compose(of$1, nothing), map_p(of$2)), | ||
@@ -409,5 +457,8 @@ // keyPromiseToPromiseCollection :: String -> {ki: Promise e vi, k:v …} -> Promise e {ki:vi, k:v …} | ||
keyPromiseToPromiseCollection = semmelRamda.curry((key, obj) => | ||
map$1(semmelRamda.assoc(key, semmelRamda.__, obj), obj[key]) | ||
map_p(semmelRamda.assoc(key, semmelRamda.__, obj), obj[key]) | ||
); | ||
exports.cancelableToEventStream = cancelableToBaconStream; | ||
exports.cancelableToPromise = cancelableToPromise; | ||
exports.eitherToCancelable = eitherToCancelable; | ||
exports.eitherToPromise = eitherToPromise; | ||
@@ -419,2 +470,4 @@ exports.keyMaybeToMaybeObj = keyMaybeToMaybeObj; | ||
exports.maybeToPromise = maybeToPromise; | ||
exports.observableToCancelable = baconObservableToCancelable; | ||
exports.promiseToCancelable = promiseToCancelable; | ||
exports.promiseToPromiseOfEither = promiseToPromiseOfEither; |
@@ -11,6 +11,11 @@ { | ||
"devDependencies": { | ||
"@most/core": "^1.6.1", | ||
"@most/scheduler": "^1.3.0", | ||
"@rollup/plugin-node-resolve": "^11.0.1", | ||
"abort-controller": "^3.0.0", | ||
"baconjs": "^3.0.17", | ||
"chai": "^4.2.0", | ||
"es-module-shims": "^0.4.6", | ||
"hirestime": "^6.0.1", | ||
"node-fetch": "^2.6.1", | ||
"rollup": "^2.35.1" | ||
@@ -23,2 +28,6 @@ }, | ||
}, | ||
"./cancelable": { | ||
"require": "./dist/cjs/cancelable.js", | ||
"default": "./src/cancelable.js" | ||
}, | ||
"./promise": { | ||
@@ -59,2 +68,7 @@ "require": "./dist/cjs/promise.js", | ||
"name": "@visisoft/staticland", | ||
"peerDependencies": { | ||
"abort-controller": ">= 3.0.0", | ||
"baconjs": ">= 3.0.17", | ||
"node-fetch": ">= 2.6.1" | ||
}, | ||
"repository": { | ||
@@ -70,6 +84,6 @@ "type": "git", | ||
"setup:test": "npm run setup:chai && npm run setup:hirestime", | ||
"test": "mocha" | ||
"test": "mocha --recursive --extension mjs ./test" | ||
}, | ||
"type": "module", | ||
"version": "0.1.15" | ||
"version": "0.1.16" | ||
} |
@@ -5,10 +5,14 @@ [![Dependencies](https://img.shields.io/david/semmel/StaticLand.svg?style=flat-square)](https://david-dm.org/semmel/StaticLand) [![NPM Version](https://img.shields.io/npm/v/@visisoft/staticland.svg?style=flat-square)](https://www.npmjs.com/package/@visisoft/staticland) | ||
==================== | ||
Operations on Algebraic Data Types (ADT) (Either, Maybe, Promise) realised with *free static functions*. The static functions do not expect custom-made ADTs but work on the *native JavaScript types* as `Array`, `Promise` and `Function`. Using these native types means that | ||
Operations on Algebraic Data Types (ADT) (Either, Maybe, Promise, CancelableComputation) realised with *free static functions*. The static functions do not expect custom-made ADT classes but work on the *native JavaScript types* as `Array`, `Promise` and `Function`. Fairness demands to confess that `Function` carries some data in the closed over variables. | ||
- *@visisoft/staticland* practically gives up on type inspection and leaves that to the calling code. This is in line with the characteristics of JavaScript. | ||
- The implementation of the static functions is mostly trivial | ||
Using simple native types means that | ||
- Conversion between the types is easy, but | ||
- *@visisoft/staticland* practically gives up on type inspection and leaves that to the calling code. This is in line with the characteristics of JavaScript. | ||
| | `of` | `map` | `chain` | Consumption | | ||
|-----------|---------------|---------------|---------------|---------------| | ||
| Maybe | `x => [x]` |`Array.prototype.map`|`Array.prototype.flatMap`|`xs => xs[0]`| | ||
| Either | `x => [,x]` |`Array.prototype.map`|`Array.prototype.flatMap`|`xs => xs[1]`| | ||
|CancelableComputation| `cc = (resolve, reject) => () => ()` | | | `new Promise(cc)` | | ||
| Promise | `Promise.resolve`|`Promise.then`|`Promise.then`|`Promise.then`| | ||
@@ -15,0 +19,0 @@ | IO | `x => x` |`compose` |`run(compose)` |`call`| |
@@ -9,2 +9,3 @@ /** | ||
import { curry, o, identity } from 'semmel-ramda'; | ||
import map from './promise/map.js'; | ||
@@ -35,53 +36,3 @@ const | ||
ap_ = curry((fnPromise, aPromise) => fnPromise.then(fn => aPromise.then(fn))), | ||
// this implementation avoids the UnhandledPromiseRejection error | ||
// when Promise a fails | ||
// ap :: Promise (a -> b) -> Promise a -> Promise b | ||
ap = curry((fnPromise, aPromise) => { | ||
if (typeof Promise.allSettled === 'function') { | ||
return Promise.allSettled([fnPromise, aPromise]) | ||
.then(([fnOutcome, anOutcome]) => { | ||
if ((fnOutcome.status === 'fulfilled') && (anOutcome.status === 'fulfilled')) { | ||
return fnOutcome.value(anOutcome.value); | ||
} | ||
else if (fnOutcome.status === 'fulfilled') { | ||
return Promise.reject(anOutcome.reason); | ||
} | ||
else if (anOutcome.status === 'fulfilled') { | ||
return Promise.reject(fnOutcome.reason); | ||
} | ||
else if (anOutcome.reason === fnOutcome.reason) { | ||
return Promise.reject(fnOutcome.reason); | ||
} | ||
else { | ||
const | ||
aggregateError = new Error(`${fnOutcome.reason.message},\n${anOutcome.reason.message}`); | ||
aggregateError.name = "AggregateError"; | ||
if (anOutcome.reason.name === "AggregateError") { | ||
aggregateError.errors = anOutcome.reason.errors.concat([fnOutcome.reason]); | ||
} | ||
else if (fnOutcome.reason.name === "AggregateError") { | ||
aggregateError.errors = fnOutcome.reason.errors.concat([anOutcome.reason]); | ||
} | ||
else { | ||
aggregateError.errors = [fnOutcome.reason, anOutcome.reason]; | ||
} | ||
return Promise.reject(aggregateError); | ||
} | ||
}); | ||
} | ||
else { | ||
return ap_(fnPromise, aPromise); | ||
} | ||
}), | ||
// Transformation // | ||
// map :: (a -> b) -> Promise e a -> Promise e b | ||
map = curry((fn, aPromise) => aPromise.then(fn)), | ||
@@ -186,2 +137,62 @@ /** | ||
// This implementation prioritises the left promise in way that | ||
// if the left promise fails it's rejected value takes precedence over | ||
// the rejected value of the right promise regardless of the time sequence. | ||
// Thus if the right promise fails that's UnhandledPromiseRejection | ||
// Note: ap(mf, ma) = chain(f => map(f, ma)) | ||
// ap :: Promise (a -> b) -> Promise a -> Promise b | ||
/*ap_ = curry((fnPromise, aPromise) => fnPromise.then(fn => aPromise.then(fn))),*/ | ||
// this implementation avoids the UnhandledPromiseRejection error | ||
// when Promise a fails. | ||
// Note: Is the UnhandledPromiseRejection really an issue? | ||
// It occurs only if there is no .catch or .then(, onError) | ||
// in a promise which is a result of ap (i.e. which is created on calling .then) | ||
// see https://stackoverflow.com/a/52409612/564642 | ||
// ap :: Promise (a -> b) -> Promise a -> Promise b | ||
/*ap = curry((fnPromise, aPromise) => { | ||
if (typeof Promise.allSettled === 'function') { | ||
return Promise.allSettled([fnPromise, aPromise]) | ||
.then(([fnOutcome, anOutcome]) => { | ||
if ((fnOutcome.status === 'fulfilled') && (anOutcome.status === 'fulfilled')) { | ||
return fnOutcome.value(anOutcome.value); | ||
} | ||
else if (fnOutcome.status === 'fulfilled') { | ||
return Promise.reject(anOutcome.reason); | ||
} | ||
else if (anOutcome.status === 'fulfilled') { | ||
return Promise.reject(fnOutcome.reason); | ||
} | ||
else if (anOutcome.reason === fnOutcome.reason) { | ||
return Promise.reject(fnOutcome.reason); | ||
} | ||
else { | ||
const | ||
aggregateError = new Error(`${fnOutcome.reason.message},\n${anOutcome.reason.message}`); | ||
aggregateError.name = "AggregateError"; | ||
if (anOutcome.reason.name === "AggregateError") { | ||
aggregateError.errors = anOutcome.reason.errors.concat([fnOutcome.reason]); | ||
} | ||
else if (fnOutcome.reason.name === "AggregateError") { | ||
aggregateError.errors = fnOutcome.reason.errors.concat([anOutcome.reason]); | ||
} | ||
else { | ||
aggregateError.errors = [fnOutcome.reason, anOutcome.reason]; | ||
} | ||
return Promise.reject(aggregateError); | ||
} | ||
}); | ||
} | ||
else { | ||
return ap_(fnPromise, aPromise); | ||
} | ||
}), | ||
liftA2 = curry((fn, pa, pb) => | ||
ap(map(fn, pa), pb) | ||
),*/ | ||
// :: [Promise e a] -> Promise e [a] | ||
@@ -212,8 +223,11 @@ all = promises => Promise.all(promises), | ||
export { | ||
of, all, alt, ap, bimap, chain, chainIf, chainTap, chainRej, coalesce, create, map, mapRej, | ||
of, all, alt, bimap, chain, chainIf, chainTap, chainRej, coalesce, create, map, mapRej, | ||
race, reject, tap, tapRegardless, empty | ||
}; | ||
export {default as ap} from './promise/ap.js'; | ||
export {default as liftA2} from './promise/liftA2.js'; | ||
export let join = identity; | ||
/** @deprecated */ | ||
export let unit = empty; |
@@ -9,5 +9,11 @@ /** | ||
import { either, left, right } from './either.js'; | ||
import { coalesce, map as map_p, reject, of as of_p } from './promise.js'; | ||
import { coalesce, reject, of as of_p } from './promise.js'; | ||
import map_p from './promise/map.js'; | ||
import { maybe, nothing, of as of_mb, just } from './maybe.js'; | ||
import { __, always, assoc, compose, curry, o, objOf, thunkify } from 'semmel-ramda'; | ||
export {default as promiseToCancelable} from './transformations/promiseToCancelable.js'; | ||
export {default as cancelableToPromise} from './transformations/cancelableToPromise.js'; | ||
export {default as observableToCancelable} from './transformations/baconObservableToCancelable.js'; | ||
export {default as cancelableToEventStream} from './transformations/cancelableToBaconStream.js'; | ||
export {default as eitherToCancelable} from './transformations/eitherToCancelable.js'; | ||
@@ -52,2 +58,2 @@ const | ||
keyMaybeToMaybeObj | ||
}; | ||
}; |
Network access
Supply chain riskThis module accesses the network.
Found 1 instance in 1 package
101804
40
2475
108
4
10
4