@effect-ts/system
Version:
Effect-TS is a zero dependency set of libraries to write highly productive, purely functional TypeScript at scale.
1,035 lines (823 loc) • 23.6 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.Tracer = exports.InterruptionState = exports.Async = void 0;
exports.access = access;
exports.accessM = accessM;
exports.bimap = bimap;
exports.bimap_ = bimap_;
exports.catchAll = catchAll;
exports.catchAll_ = catchAll_;
exports.chain = chain;
exports.chain_ = chain_;
exports.default = tryCatchOption_;
exports.delay = delay;
exports.done = done;
exports.either = either;
exports.environment = environment;
exports.fail = fail;
exports.failExit = void 0;
exports.fold = fold;
exports.foldM = foldM;
exports.foldM_ = foldM_;
exports.fold_ = fold_;
exports.fromEither = fromEither;
exports.interruptExit = void 0;
exports.map = map;
exports.mapError = mapError;
exports.mapError_ = mapError_;
exports.map_ = map_;
exports.orElseEither = orElseEither;
exports.orElseEither_ = orElseEither_;
exports.promise = promise;
exports.provide = provide;
exports.provideAll = provideAll;
exports.provideAll_ = provideAll_;
exports.provideSome = provideSome;
exports.runAsync = runAsync;
exports.runAsyncEnv = runAsyncEnv;
exports.runPromise = runPromise;
exports.runPromiseExit = runPromiseExit;
exports.runPromiseExitEnv = runPromiseExitEnv;
exports.sleep = sleep;
exports.succeed = succeed;
exports.succeedWith = succeedWith;
exports.successExit = void 0;
exports.suspend = suspend;
exports.tap = tap;
exports.tapError = tapError;
exports.tap_ = tap_;
exports.tracingContext = void 0;
exports.tryCatch = tryCatch;
exports.tryCatchOption = tryCatchOption;
exports.unfailable = unfailable;
exports.union = union;
exports.unionFn = unionFn;
exports.unit = void 0;
exports.zip = zip;
exports.zipWith = zipWith;
exports.zipWith_ = zipWith_;
exports.zip_ = zip_;
var Tp = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("../Collections/Immutable/Tuple/index.js"));
var _commons = /*#__PURE__*/require("../Effect/commons.js");
var E = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("../Either/index.js"));
var _index3 = /*#__PURE__*/require("../Function/index.js");
var _index4 = /*#__PURE__*/require("../Stack/index.js");
function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
// ets_tracing: off
/* eslint-disable prefer-const */
class Async {}
/**
* @ets_optimize identity
*/
exports.Async = Async;
function concrete(_) {
return _;
}
class ISucceed extends Async {
constructor(a) {
super();
this.a = a;
this._asyncTag = "Succeed";
}
}
class ISuspend extends Async {
constructor(f) {
super();
this.f = f;
this._asyncTag = "Suspend";
}
}
class IFail extends Async {
constructor(e) {
super();
this.e = e;
this._asyncTag = "Fail";
}
}
class IFlatMap extends Async {
constructor(value, cont) {
super();
this.value = value;
this.cont = cont;
this._asyncTag = "FlatMap";
}
}
class IFold extends Async {
constructor(value, failure, success) {
super();
this.value = value;
this.failure = failure;
this.success = success;
this._asyncTag = "Fold";
}
}
class IAccess extends Async {
constructor(access) {
super();
this.access = access;
this._asyncTag = "Access";
}
}
class IProvide extends Async {
constructor(r, cont) {
super();
this.r = r;
this.cont = cont;
this._asyncTag = "Provide";
}
}
class IPromise extends Async {
constructor(promise, onError) {
super();
this.promise = promise;
this.onError = onError;
this._asyncTag = "Promise";
}
}
class IDone extends Async {
constructor(exit) {
super();
this.exit = exit;
this._asyncTag = "Done";
}
}
class FoldFrame {
constructor(failure, apply) {
this.failure = failure;
this.apply = apply;
this._asyncTag = "FoldFrame";
}
}
class ApplyFrame {
constructor(apply) {
this.apply = apply;
this._asyncTag = "ApplyFrame";
}
}
/**
* Models the state of interruption, allows for listening to interruption events & firing interruption events
*/
class InterruptionState {
constructor() {
this.isInterrupted = false;
this.listeners = new Set();
} // listen to an interruption event
listen(f) {
this.listeners.add(f);
return () => {
// stop listening
this.listeners.delete(f);
};
}
get interrupted() {
return this.isInterrupted;
}
interrupt() {
if (!this.isInterrupted) {
// set to interrupted
this.isInterrupted = true; // notify
this.listeners.forEach(i => {
i();
});
}
}
}
exports.InterruptionState = InterruptionState;
const failExit = e => ({
_tag: "Failure",
e
});
exports.failExit = failExit;
const interruptExit = {
_tag: "Interrupt"
};
exports.interruptExit = interruptExit;
const successExit = a => ({
_tag: "Success",
a
});
/**
* Models a cancellable promise
*/
exports.successExit = successExit;
class CancelablePromise {
constructor( // creates the promise
promiseFactory, // listens for interruption events
is) {
this.promiseFactory = promiseFactory;
this.is = is; // gets called with a Rejection<E>, any here is to not break covariance imposed by _E
this.rejection = undefined; // holds the current running promise
this.current = undefined; // creates the computation linking it to the interruption state
this.promise = () => {
if (this.current) {
throw new Error("Bug: promise() have been called twice");
} else if (this.is.interrupted) {
throw new Error("Bug: trying to create a promise already interrupted");
} else {
const onInterrupt = []; // we record the current interrupt in the interruption registry
const removeListener = this.is.listen(() => {
onInterrupt.forEach(f => {
f();
});
this.interrupt();
});
const p = new Promise((res, rej) => {
// set the rejection handler
this.rejection = rej; // creates the underlying promise
this.promiseFactory(f => {
onInterrupt.push(f);
}).then(a => {
// removes the call to interrupt from the interruption registry
removeListener(); // if not interrupted we continue
if (!this.is.interrupted) {
res(a);
}
}).catch(e => {
// removes the call to interrupt from the interruption registry
removeListener(); // if not interrupted we continue
if (!this.is.interrupted) {
rej(e);
}
});
}); // track the current running promise to avoid re-creation
this.current = p; // return the promise
return p;
}
};
this.interrupt = () => {
var _a; // triggeres a promise rejection on the current promise with an interrupt exit
(_a = this.rejection) === null || _a === void 0 ? void 0 : _a.call(this, interruptExit);
};
}
}
class Tracer {
constructor() {
this.running = new Set();
this.traced = this.traced.bind(this);
this.wait = this.wait.bind(this);
this.clear = this.clear.bind(this);
} // tracks a lazy promise lifetime
traced(promise) {
return async () => {
const p = promise();
this.running.add(p);
try {
const a = await p;
this.running.delete(p);
return Promise.resolve(a);
} catch (e) {
this.running.delete(p);
return Promise.reject(e);
}
};
} // awaits for all the running promises to complete
async wait() {
const t = await Promise.all(Array.from(this.running).map(p => p.then(a => successExit(a)).catch(e => Promise.resolve(e))));
return await new Promise(r => {
setTimeout(() => {
r(t);
}, 0);
});
} // clears itself
clear() {
this.running.clear();
}
} // create the root tracing context
exports.Tracer = Tracer;
const tracingContext = /*#__PURE__*/new Tracer();
/**
* Runs this computation with the specified initial state, returning either a
* failure or the updated state and the result
*/
exports.tracingContext = tracingContext;
function runPromiseExitEnv(self, ri, is = new InterruptionState()) {
return tracingContext.traced(async () => {
let stack = undefined;
let a = null;
let r = ri;
let failed = false;
let curAsync = self;
let cnt = 0;
let interruptedLocal = false;
function isInterruted() {
return interruptedLocal || is.interrupted;
}
function pop() {
const nextInstr = stack;
if (nextInstr) {
stack = stack === null || stack === void 0 ? void 0 : stack.previous;
}
return nextInstr === null || nextInstr === void 0 ? void 0 : nextInstr.value;
}
function push(cont) {
stack = new _index4.Stack(cont, stack);
}
function findNextErrorHandler() {
let unwinding = true;
while (unwinding) {
const nextInstr = pop();
if (nextInstr == null) {
unwinding = false;
} else {
if (nextInstr._asyncTag === "FoldFrame") {
unwinding = false;
push(new ApplyFrame(nextInstr.failure));
}
}
}
}
while (curAsync != null && !isInterruted()) {
if (cnt > 10000) {
await new Promise(r => {
setTimeout(() => {
r(undefined);
}, 0);
});
cnt = 0;
}
cnt += 1;
const xp = curAsync;
switch (xp._asyncTag) {
case "FlatMap":
{
const nested = xp.value;
const continuation = xp.cont;
switch (nested._asyncTag) {
case "Succeed":
{
curAsync = continuation(nested.a);
break;
}
default:
{
curAsync = nested;
push(new ApplyFrame(continuation));
}
}
break;
}
case "Suspend":
{
curAsync = xp.f();
break;
}
case "Succeed":
{
a = xp.a;
const nextInstr = pop();
if (nextInstr) {
curAsync = nextInstr.apply(a);
} else {
curAsync = undefined;
}
break;
}
case "Fail":
{
findNextErrorHandler();
const nextInst = pop();
if (nextInst) {
curAsync = nextInst.apply(xp.e);
} else {
failed = true;
a = xp.e;
curAsync = undefined;
}
break;
}
case "Fold":
{
curAsync = xp.value;
push(new FoldFrame(xp.failure, xp.success));
break;
}
case "Done":
{
switch (xp.exit._tag) {
case "Failure":
{
curAsync = new IFail(xp.exit.e);
break;
}
case "Interrupt":
{
interruptedLocal = true;
curAsync = undefined;
break;
}
case "Success":
{
curAsync = new ISucceed(xp.exit.a);
break;
}
}
break;
}
case "Access":
{
curAsync = xp.access(r);
break;
}
case "Provide":
{
r = xp.r;
curAsync = xp.cont;
break;
}
case "Promise":
{
try {
curAsync = new ISucceed(await new CancelablePromise(s => xp.promise(s).catch(e => Promise.reject(failExit(xp.onError(e)))), is).promise());
} catch (e) {
const e_ = e;
switch (e_._tag) {
case "Failure":
{
curAsync = new IFail(e_.e);
break;
}
case "Interrupt":
{
interruptedLocal = true;
curAsync = undefined;
break;
}
}
}
break;
}
}
}
if (is.interrupted) {
return interruptExit;
}
if (failed) {
return failExit(a);
}
return successExit(a);
})();
}
function runPromiseExit(self, is = new InterruptionState()) {
return runPromiseExitEnv(self, {}, is);
} // runs as a Promise of an Exit
async function runPromise(task, is = new InterruptionState()) {
return runPromiseExit(task, is).then(e => e._tag === "Failure" ? Promise.reject(e.e) : e._tag === "Interrupt" ? Promise.reject(e) : Promise.resolve(e.a));
} // runs as a Cancellable
function runAsync(task, cb) {
const is = new InterruptionState();
runPromiseExit(task, is).then(cb);
return () => {
is.interrupt();
};
} // runs as a Cancellable
function runAsyncEnv(task, r, cb) {
const is = new InterruptionState();
runPromiseExitEnv(task, r, is).then(cb);
return () => {
is.interrupt();
};
}
/**
* Extends this computation with another computation that depends on the
* result of this computation by running the first computation, using its
* result to generate a second computation, and running that computation.
*
* @ets_data_first chain_
*/
function chain(f) {
return self => new IFlatMap(self, f);
}
/**
* Extends this computation with another computation that depends on the
* result of this computation by running the first computation, using its
* result to generate a second computation, and running that computation.
*/
function chain_(self, f) {
return new IFlatMap(self, f);
}
/**
* Returns a computation that effectfully "peeks" at the success of this one.
*
* @ets_data_first tap_
*/
function tap(f) {
return self => tap_(self, f);
}
/**
* Returns a computation that effectfully "peeks" at the success of this one.
*/
function tap_(self, f) {
return chain_(self, a => map_(f(a), () => a));
}
/**
* Constructs a computation that always succeeds with the specified value.
*/
function succeed(a) {
return new ISucceed(a);
}
/**
* Constructs a computation that always succeeds with the specified value,
* passing the state through unchanged.
*/
function fail(a) {
return new IFail(a);
}
/**
* Extends this computation with another computation that depends on the
* result of this computation by running the first computation, using its
* result to generate a second computation, and running that computation.
*/
function map_(self, f) {
return chain_(self, a => succeed(f(a)));
}
/**
* Extends this computation with another computation that depends on the
* result of this computation by running the first computation, using its
* result to generate a second computation, and running that computation.
*
* @ets_data_first map_
*/
function map(f) {
return self => map_(self, f);
}
/**
* Recovers from errors by accepting one computation to execute for the case
* of an error, and one computation to execute for the case of success.
*/
function foldM_(self, failure, success) {
return new IFold(self, failure, success);
}
/**
* Recovers from errors by accepting one computation to execute for the case
* of an error, and one computation to execute for the case of success.
*
* @ets_data_first foldM_
*/
function foldM(failure, success) {
return self => foldM_(self, failure, success);
}
/**
* Folds over the failed or successful results of this computation to yield
* a computation that does not fail, but succeeds with the value of the left
* or right function passed to `fold`.
*
* @ets_data_first fold_
*/
function fold(failure, success) {
return self => fold_(self, failure, success);
}
/**
* Folds over the failed or successful results of this computation to yield
* a computation that does not fail, but succeeds with the value of the left
* or righr function passed to `fold`.
*/
function fold_(self, failure, success) {
return foldM_(self, e => succeed(failure(e)), a => succeed(success(a)));
}
/**
* Recovers from all errors.
*
* @ets_data_first catchAll_
*/
function catchAll(failure) {
return self => catchAll_(self, failure);
}
/**
* Recovers from all errors.
*/
function catchAll_(self, failure) {
return foldM_(self, failure, a => succeed(a));
}
/**
* Returns a computation whose error and success channels have been mapped
* by the specified functions, `f` and `g`.
*
* @ets_data_first bimap_
*/
function bimap(f, g) {
return self => bimap_(self, f, g);
}
/**
* Returns a computation whose error and success channels have been mapped
* by the specified functions, `f` and `g`.
*/
function bimap_(self, f, g) {
return foldM_(self, e => fail(f(e)), a => succeed(() => g(a)));
}
/**
* Transforms the error type of this computation with the specified
* function.
*
* @ets_data_first mapError_
*/
function mapError(f) {
return self => mapError_(self, f);
}
/**
* Transforms the error type of this computation with the specified
* function.
*/
function mapError_(self, f) {
return catchAll_(self, e => fail(f(e)));
}
/**
* Constructs a computation that always returns the `Unit` value, passing the
* state through unchanged.
*/
const unit = /*#__PURE__*/succeed(undefined);
/**
* Transforms the initial state of this computation` with the specified
* function.
*/
exports.unit = unit;
function provideSome(f) {
return self => accessM(r => provideAll(f(r))(self));
}
/**
* Provides this computation with its required environment.
*
* @ets_data_first provideAll_
*/
function provideAll(r) {
return self => new IProvide(r, self);
}
/**
* Provides this computation with its required environment.
*/
function provideAll_(self, r) {
return new IProvide(r, self);
}
/**
* Provides some of the environment required to run this effect,
* leaving the remainder `R0` and combining it automatically using spread.
*/
function provide(r) {
return next => provideSome(r0 => ({ ...r0,
...r
}))(next);
}
/**
* Access the environment monadically
*/
function accessM(f) {
return new IAccess(f);
}
/**
* Access the environment with the function f
*/
function access(f) {
return accessM(r => succeed(f(r)));
}
/**
* Access the environment
*/
function environment() {
return accessM(r => succeed(r));
}
/**
* Returns a computation whose failure and success have been lifted into an
* `Either`. The resulting computation cannot fail, because the failure case
* has been exposed as part of the `Either` success case.
*/
function either(self) {
return fold_(self, E.left, E.right);
}
/**
* Executes this computation and returns its value, if it succeeds, but
* otherwise executes the specified computation.
*
* @ets_data_first orElseEither_
*/
function orElseEither(that) {
return self => orElseEither_(self, that);
}
/**
* Executes this computation and returns its value, if it succeeds, but
* otherwise executes the specified computation.
*/
function orElseEither_(self, that) {
return foldM_(self, () => map_(that(), a => E.right(a)), a => succeed(E.left(a)));
}
/**
* Combines this computation with the specified computation, passing the
* updated state from this computation to that computation and combining the
* results of both using the specified function.
*
* @ets_data_first zipWith_
*/
function zipWith(that, f) {
return self => zipWith_(self, that, f);
}
/**
* Combines this computation with the specified computation, passing the
* updated state from this computation to that computation and combining the
* results of both using the specified function.
*/
function zipWith_(self, that, f) {
return chain_(self, a => map_(that, b => f(a, b)));
}
/**
* Combines this computation with the specified computation, passing the
* updated state from this computation to that computation and combining the
* results of both into a tuple.
*
* @ets_data_first zip_
*/
function zip(that) {
return self => zip_(self, that);
}
/**
* Combines this computation with the specified computation, passing the
* updated state from this computation to that computation and combining the
* results of both into a tuple.
*/
function zip_(self, that) {
return zipWith_(self, that, Tp.tuple);
}
/**
* Suspend a computation, useful in recursion
*/
function suspend(f) {
return new ISuspend(f);
}
/**
* Lift a sync (non failable) computation
*/
function succeedWith(f) {
return suspend(() => succeed(f()));
}
/**
* Lift a sync (non failable) computation
*/
function tryCatch(f, onThrow) {
return suspend(() => {
try {
return succeed(f());
} catch (u) {
return fail(onThrow(u));
}
});
} // construct from a promise
function promise(promise, onError) {
return new IPromise(promise, onError);
} // construct from a non failable promise
function unfailable(promise) {
return new IPromise(promise, () => undefined);
} // construct a Task from an exit value
function done(exit) {
return new IDone(exit);
} // like .then in Promise when the result of f is a Promise but ignores the outout of f
// useful for logging or doing things that should not change the result
function tapError(f) {
return self => catchAll(e => chain(_ => fail(e))(f(e)))(self);
} // sleeps for ms milliseconds
function sleep(ms) {
return unfailable(onInterrupt => new Promise(res => {
const timer = setTimeout(() => {
res(undefined);
}, ms);
onInterrupt(() => {
clearTimeout(timer);
});
}));
} // delay the computation prepending a sleep of ms milliseconds
function delay(ms) {
return self => chain(() => self)(sleep(ms));
} // list an Either
function fromEither(e) {
return e._tag === "Right" ? succeed(e.right) : fail(e.left);
}
/**
* Compact the union produced by the result of f
*
* @ets_optimize identity
*/
function unionFn(_) {
return _;
}
/**
* Compact the union
*
* @ets_optimize identity
*/
function union(_) {
return _;
}
/**
* Get the A from an option
*/
function tryCatchOption_(ma, onNone) {
return fromEither(E.fromOption_(ma, onNone));
}
/**
* Get the A from an option
*
* @ets_data_first tryCatchOption_
*/
function tryCatchOption(onNone) {
return ma => tryCatchOption_(ma, onNone);
}
//# sourceMappingURL=core.js.map