UNPKG

effect

Version:

The missing standard library for TypeScript, for writing production-grade software.

1,350 lines (1,349 loc) 332 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.forEach = exports.fnUntraced = exports.fn = exports.flipWith = exports.flip = exports.flatten = exports.flatMap = exports.firstSuccessOf = exports.findFirst = exports.finalizersMask = exports.filterOrFail = exports.filterOrElse = exports.filterOrDieMessage = exports.filterOrDie = exports.filterMap = exports.filterEffectOrFail = exports.filterEffectOrElse = exports.filter = exports.fiberIdWith = exports.fiberId = exports.failSync = exports.failCauseSync = exports.failCause = exports.fail = exports.exit = exports.exists = exports.every = exports.eventually = exports.ensuringChildren = exports.ensuringChild = exports.ensuring = exports.either = exports.dropWhile = exports.dropUntil = exports.disconnect = exports.diffFiberRefs = exports.dieSync = exports.dieMessage = exports.die = exports.descriptorWith = exports.descriptor = exports.delay = exports.daemonChildren = exports.custom = exports.currentSpan = exports.currentParentSpan = exports.contextWithEffect = exports.contextWith = exports.context = exports.consoleWith = exports.console = exports.configProviderWith = exports.clockWith = exports.clock = exports.checkInterruptible = exports.cause = exports.catchTags = exports.catchTag = exports.catchSomeDefect = exports.catchSomeCause = exports.catchSome = exports.catchIf = exports.catchAllDefect = exports.catchAllCause = exports.catchAll = exports.catch = exports.cachedWithTTL = exports.cachedInvalidateWithTTL = exports.cachedFunction = exports.cached = exports.cacheRequestResult = exports.blocked = exports.bindTo = exports.bindAll = exports.bind = exports.awaitAllChildren = exports.asyncEffect = exports.async = exports.asVoid = exports.asSomeError = exports.asSome = exports.as = exports.ap = exports.annotateSpans = exports.annotateLogsScoped = exports.annotateLogs = exports.annotateCurrentSpan = exports.andThen = exports.allowInterrupt = exports.allWith = exports.allSuccesses = exports.all = exports.addFinalizer = exports.acquireUseRelease = exports.acquireReleaseInterruptible = exports.acquireRelease = exports.Tag = exports.Service = exports.EffectTypeId = exports.Do = void 0; exports.repeatOrElse = exports.repeatN = exports.repeat = exports.reduceWhile = exports.reduceRight = exports.reduceEffect = exports.reduce = exports.randomWith = exports.random = exports.raceWith = exports.raceFirst = exports.raceAll = exports.race = exports.provideServiceEffect = exports.provideService = exports.provide = exports.promise = exports.patchRuntimeFlags = exports.patchFiberRefs = exports.partition = exports.parallelFinalizers = exports.parallelErrors = exports.orElseSucceed = exports.orElseFail = exports.orElse = exports.orDieWith = exports.orDie = exports.optionFromOptional = exports.option = exports.once = exports.onInterrupt = exports.onExit = exports.onError = exports.none = exports.never = exports.negate = exports.metricLabels = exports.mergeAll = exports.merge = exports.matchEffect = exports.matchCauseEffect = exports.matchCause = exports.match = exports.mapInputContext = exports.mapErrorCause = exports.mapError = exports.mapBoth = exports.mapAccum = exports.map = exports.makeSpanScoped = exports.makeSpan = exports.makeSemaphore = exports.makeLatch = exports.loop = exports.logWithLevel = exports.logWarning = exports.logTrace = exports.logInfo = exports.logFatal = exports.logError = exports.logDebug = exports.logAnnotations = exports.log = exports.locallyWith = exports.locallyScopedWith = exports.locallyScoped = exports.locally = exports.linkSpans = exports.liftPredicate = exports.let = exports.labelMetricsScoped = exports.labelMetrics = exports.iterate = exports.isSuccess = exports.isFailure = exports.isEffect = exports.intoDeferred = exports.interruptibleMask = exports.interruptible = exports.interruptWith = exports.interrupt = exports.inheritFiberRefs = exports.ignoreLogged = exports.ignore = exports.if = exports.head = exports.getRuntimeFlags = exports.getFiberRefs = exports.gen = exports.functionWithSpan = exports.fromNullable = exports.fromFiberEffect = exports.fromFiber = exports.forkWithErrorHandler = exports.forkScoped = exports.forkIn = exports.forkDaemon = exports.forkAll = exports.fork = exports.forever = void 0; exports.withMetric = exports.withMaxOpsBeforeYield = exports.withLogSpan = exports.withFiberRuntime = exports.withEarlyRelease = exports.withConsoleScoped = exports.withConsole = exports.withConfigProviderScoped = exports.withConfigProvider = exports.withConcurrency = exports.withClockScoped = exports.withClock = exports.whileLoop = exports.whenRef = exports.whenLogLevel = exports.whenFiberRef = exports.whenEffect = exports.when = exports.void = exports.validateWith = exports.validateFirst = exports.validateAll = exports.validate = exports.using = exports.useSpan = exports.updateService = exports.updateFiberRefs = exports.unsandbox = exports.unsafeMakeSemaphore = exports.unsafeMakeLatch = exports.unlessEffect = exports.unless = exports.uninterruptibleMask = exports.uninterruptible = exports.tryPromise = exports.tryMapPromise = exports.tryMap = exports.try = exports.transposeOption = exports.transplant = exports.tracerWith = exports.tracer = exports.timeoutTo = exports.timeoutOption = exports.timeoutFailCause = exports.timeoutFail = exports.timeout = exports.timedWith = exports.timed = exports.tapErrorTag = exports.tapErrorCause = exports.tapError = exports.tapDefect = exports.tapBoth = exports.tap = exports.takeWhile = exports.takeUntil = exports.tagMetricsScoped = exports.tagMetrics = exports.sync = exports.suspend = exports.supervised = exports.summarized = exports.succeedSome = exports.succeedNone = exports.succeed = exports.step = exports.spanLinks = exports.spanAnnotations = exports.sleep = exports.setFiberRefs = exports.serviceOptional = exports.serviceOption = exports.serviceMembers = exports.serviceFunctions = exports.serviceFunctionEffect = exports.serviceFunction = exports.serviceConstants = exports.sequentialFinalizers = exports.scopedWith = exports.scoped = exports.scopeWith = exports.scope = exports.scheduleFrom = exports.scheduleForked = exports.schedule = exports.sandbox = exports.runtime = exports.runSyncExit = exports.runSync = exports.runRequestBlock = exports.runPromiseExit = exports.runPromise = exports.runFork = exports.runCallback = exports.retryOrElse = exports.retry = exports.request = exports.replicateEffect = exports.replicate = void 0; exports.zipWith = exports.zipRight = exports.zipLeft = exports.zip = exports.yieldNow = exports.withUnhandledErrorLogLevel = exports.withTracerTiming = exports.withTracerScoped = exports.withTracerEnabled = exports.withTracer = exports.withSpanScoped = exports.withSpan = exports.withSchedulingPriority = exports.withScheduler = exports.withRuntimeFlagsPatchScoped = exports.withRuntimeFlagsPatch = exports.withRequestCaching = exports.withRequestCache = exports.withRequestBatching = exports.withRandomScoped = exports.withRandom = exports.withParentSpan = void 0; var _Function = require("./Function.js"); var internalCause = _interopRequireWildcard(require("./internal/cause.js")); var console_ = _interopRequireWildcard(require("./internal/console.js")); var _context = require("./internal/context.js"); var effect = _interopRequireWildcard(require("./internal/core-effect.js")); var core = _interopRequireWildcard(require("./internal/core.js")); var defaultServices = _interopRequireWildcard(require("./internal/defaultServices.js")); var circular = _interopRequireWildcard(require("./internal/effect/circular.js")); var fiberRuntime = _interopRequireWildcard(require("./internal/fiberRuntime.js")); var layer = _interopRequireWildcard(require("./internal/layer.js")); var option_ = _interopRequireWildcard(require("./internal/option.js")); var query = _interopRequireWildcard(require("./internal/query.js")); var runtime_ = _interopRequireWildcard(require("./internal/runtime.js")); var schedule_ = _interopRequireWildcard(require("./internal/schedule.js")); var internalTracer = _interopRequireWildcard(require("./internal/tracer.js")); var Request = _interopRequireWildcard(require("./Request.js")); var Scheduler = _interopRequireWildcard(require("./Scheduler.js")); var _Utils = require("./Utils.js"); function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); } function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; } /** * @since 2.0.0 * @category Symbols */ const EffectTypeId = exports.EffectTypeId = core.EffectTypeId; /** * Checks if a given value is an `Effect` value. * * **When to Use** * * This function can be useful for checking the type of a value before * attempting to operate on it as an `Effect` value. For example, you could use * `Effect.isEffect` to check the type of a value before using it as an argument * to a function that expects an `Effect` value. * * @since 2.0.0 * @category Guards */ const isEffect = exports.isEffect = core.isEffect; /** * Returns an effect that caches its result for a specified `Duration`, * known as "timeToLive" (TTL). * * **Details** * * This function is used to cache the result of an effect for a specified amount * of time. This means that the first time the effect is evaluated, its result * is computed and stored. * * If the effect is evaluated again within the specified `timeToLive`, the * cached result will be used, avoiding recomputation. * * After the specified duration has passed, the cache expires, and the effect * will be recomputed upon the next evaluation. * * **When to Use** * * Use this function when you have an effect that involves costly operations or * computations, and you want to avoid repeating them within a short time frame. * * It's ideal for scenarios where the result of an effect doesn't change * frequently and can be reused for a specified duration. * * By caching the result, you can improve efficiency and reduce unnecessary * computations, especially in performance-critical applications. * * @see {@link cached} for a similar function that caches the result * indefinitely. * @see {@link cachedInvalidateWithTTL} for a similar function that includes an * additional effect for manually invalidating the cached value. * * @example * ```ts * import { Effect, Console } from "effect" * * let i = 1 * const expensiveTask = Effect.promise<string>(() => { * console.log("expensive task...") * return new Promise((resolve) => { * setTimeout(() => { * resolve(`result ${i++}`) * }, 100) * }) * }) * * const program = Effect.gen(function* () { * const cached = yield* Effect.cachedWithTTL(expensiveTask, "150 millis") * yield* cached.pipe(Effect.andThen(Console.log)) * yield* cached.pipe(Effect.andThen(Console.log)) * yield* Effect.sleep("100 millis") * yield* cached.pipe(Effect.andThen(Console.log)) * }) * * // Effect.runFork(program) * // Output: * // expensive task... * // result 1 * // result 1 * // expensive task... * // result 2 * ``` * * @since 2.0.0 * @category Caching */ const cachedWithTTL = exports.cachedWithTTL = circular.cached; /** * Caches an effect's result for a specified duration and allows manual * invalidation before expiration. * * **Details** * * This function behaves similarly to {@link cachedWithTTL} by caching the * result of an effect for a specified period of time. However, it introduces an * additional feature: it provides an effect that allows you to manually * invalidate the cached result before it naturally expires. * * This gives you more control over the cache, allowing you to refresh the * result when needed, even if the original cache has not yet expired. * * Once the cache is invalidated, the next time the effect is evaluated, the * result will be recomputed, and the cache will be refreshed. * * **When to Use** * * Use this function when you have an effect whose result needs to be cached for * a certain period, but you also want the option to refresh the cache manually * before the expiration time. * * This is useful when you need to ensure that the cached data remains valid for * a certain period but still want to invalidate it if the underlying data * changes or if you want to force a recomputation. * * @see {@link cached} for a similar function that caches the result * indefinitely. * @see {@link cachedWithTTL} for a similar function that caches the result for * a specified duration but does not include an effect for manual invalidation. * * @example * ```ts * import { Effect, Console } from "effect" * * let i = 1 * const expensiveTask = Effect.promise<string>(() => { * console.log("expensive task...") * return new Promise((resolve) => { * setTimeout(() => { * resolve(`result ${i++}`) * }, 100) * }) * }) * * const program = Effect.gen(function* () { * const [cached, invalidate] = yield* Effect.cachedInvalidateWithTTL( * expensiveTask, * "1 hour" * ) * yield* cached.pipe(Effect.andThen(Console.log)) * yield* cached.pipe(Effect.andThen(Console.log)) * yield* invalidate * yield* cached.pipe(Effect.andThen(Console.log)) * }) * * // Effect.runFork(program) * // Output: * // expensive task... * // result 1 * // result 1 * // expensive task... * // result 2 * ``` * * @since 2.0.0 * @category Caching */ const cachedInvalidateWithTTL = exports.cachedInvalidateWithTTL = circular.cachedInvalidateWithTTL; /** * Returns an effect that lazily computes a result and caches it for subsequent * evaluations. * * **Details** * * This function wraps an effect and ensures that its result is computed only * once. Once the result is computed, it is cached, meaning that subsequent * evaluations of the same effect will return the cached result without * re-executing the logic. * * **When to Use** * * Use this function when you have an expensive or time-consuming operation that * you want to avoid repeating. The first evaluation will compute the result, * and all following evaluations will immediately return the cached value, * improving performance and reducing unnecessary work. * * @see {@link cachedWithTTL} for a similar function that includes a * time-to-live duration for the cached value. * @see {@link cachedInvalidateWithTTL} for a similar function that includes an * additional effect for manually invalidating the cached value. * * @example * ```ts * import { Effect, Console } from "effect" * * let i = 1 * const expensiveTask = Effect.promise<string>(() => { * console.log("expensive task...") * return new Promise((resolve) => { * setTimeout(() => { * resolve(`result ${i++}`) * }, 100) * }) * }) * * const program = Effect.gen(function* () { * console.log("non-cached version:") * yield* expensiveTask.pipe(Effect.andThen(Console.log)) * yield* expensiveTask.pipe(Effect.andThen(Console.log)) * console.log("cached version:") * const cached = yield* Effect.cached(expensiveTask) * yield* cached.pipe(Effect.andThen(Console.log)) * yield* cached.pipe(Effect.andThen(Console.log)) * }) * * // Effect.runFork(program) * // Output: * // non-cached version: * // expensive task... * // result 1 * // expensive task... * // result 2 * // cached version: * // expensive task... * // result 3 * // result 3 * ``` * * @since 2.0.0 * @category Caching */ const cached = exports.cached = effect.memoize; /** * Returns a memoized version of a function with effects, reusing results for * the same inputs. * * **Details** * * This function creates a memoized version of a given function that performs an * effect. Memoization ensures that once a result is computed for a specific * input, it is stored and reused for subsequent calls with the same input, * reducing the need to recompute the result. * * The function can optionally take an `Equivalence` parameter to * determine how inputs are compared for caching purposes. * * **When to Use** * * Use this function when you have a function that performs an effect and you * want to avoid recomputing the result for the same input multiple times. * * It's ideal for functions that produce deterministic results based on their * inputs, and you want to improve performance by caching the output. * * This is particularly useful in scenarios where the function involves * expensive calculations or operations that should be avoided after the first * execution with the same parameters. * * @example * ```ts * import { Effect, Random } from "effect" * * const program = Effect.gen(function* () { * const randomNumber = (n: number) => Random.nextIntBetween(1, n) * console.log("non-memoized version:") * console.log(yield* randomNumber(10)) * console.log(yield* randomNumber(10)) * * console.log("memoized version:") * const memoized = yield* Effect.cachedFunction(randomNumber) * console.log(yield* memoized(10)) * console.log(yield* memoized(10)) * }) * * // Effect.runFork(program) * // Example Output: * // non-memoized version: * // 2 * // 8 * // memoized version: * // 5 * // 5 * ``` * * @since 2.0.0 * @category Caching */ const cachedFunction = exports.cachedFunction = circular.cachedFunction; /** * Returns an effect that executes only once, regardless of how many times it's * called. * * **Details** * * This function ensures that a specific effect is executed only a single time, * no matter how many times it is invoked. The result of the effect will be * cached, and subsequent calls to the effect will immediately return the cached * result without re-executing the original logic. * * **When to Use** * * Use this function when you need to perform a task only once, regardless of * how many times the effect is triggered. It's particularly useful when you * have initialization tasks, logging, or other one-time actions that should not * be repeated. This can help optimize performance and avoid redundant actions. * * @example * ```ts * import { Effect, Console } from "effect" * * const program = Effect.gen(function* () { * const task1 = Console.log("task1") * yield* Effect.repeatN(task1, 2) * const task2 = yield* Effect.once(Console.log("task2")) * yield* Effect.repeatN(task2, 2) * }) * * // Effect.runFork(program) * // Output: * // task1 * // task1 * // task1 * // task2 * ``` * * @since 2.0.0 * @category Caching */ const once = exports.once = effect.once; /** * Combines multiple effects into one, returning results based on the input * structure. * * **Details** * * Use this function when you need to run multiple effects and combine their * results into a single output. It supports tuples, iterables, structs, and * records, making it flexible for different input types. * * For instance, if the input is a tuple: * * ```ts * // ┌─── a tuple of effects * // ▼ * Effect.all([effect1, effect2, ...]) * ``` * * the effects are executed sequentially, and the result is a new effect * containing the results as a tuple. The results in the tuple match the order * of the effects passed to `Effect.all`. * * **Concurrency** * * You can control the execution order (e.g., sequential vs. concurrent) using * the `concurrency` option. * * **Short-Circuiting Behavior** * * This function stops execution on the first error it encounters, this is * called "short-circuiting". If any effect in the collection fails, the * remaining effects will not run, and the error will be propagated. To change * this behavior, you can use the `mode` option, which allows all effects to run * and collect results as `Either` or `Option`. * * **The `mode` option** * * The `{ mode: "either" }` option changes the behavior of `Effect.all` to * ensure all effects run, even if some fail. Instead of stopping on the first * failure, this mode collects both successes and failures, returning an array * of `Either` instances where each result is either a `Right` (success) or a * `Left` (failure). * * Similarly, the `{ mode: "validate" }` option uses `Option` to indicate * success or failure. Each effect returns `None` for success and `Some` with * the error for failure. * * @see {@link forEach} for iterating over elements and applying an effect. * @see {@link allWith} for a data-last version of this function. * * @example * ```ts * // Title: Combining Effects in Tuples * import { Effect, Console } from "effect" * * const tupleOfEffects = [ * Effect.succeed(42).pipe(Effect.tap(Console.log)), * Effect.succeed("Hello").pipe(Effect.tap(Console.log)) * ] as const * * // ┌─── Effect<[number, string], never, never> * // ▼ * const resultsAsTuple = Effect.all(tupleOfEffects) * * // Effect.runPromise(resultsAsTuple).then(console.log) * // Output: * // 42 * // Hello * // [ 42, 'Hello' ] * ``` * * @example * // Title: Combining Effects in Iterables * import { Effect, Console } from "effect" * * const iterableOfEffects: Iterable<Effect.Effect<number>> = [1, 2, 3].map( * (n) => Effect.succeed(n).pipe(Effect.tap(Console.log)) * ) * * // ┌─── Effect<number[], never, never> * // ▼ * const resultsAsArray = Effect.all(iterableOfEffects) * * // Effect.runPromise(resultsAsArray).then(console.log) * // Output: * // 1 * // 2 * // 3 * // [ 1, 2, 3 ] * * @example * // Title: Combining Effects in Structs * import { Effect, Console } from "effect" * * const structOfEffects = { * a: Effect.succeed(42).pipe(Effect.tap(Console.log)), * b: Effect.succeed("Hello").pipe(Effect.tap(Console.log)) * } * * // ┌─── Effect<{ a: number; b: string; }, never, never> * // ▼ * const resultsAsStruct = Effect.all(structOfEffects) * * // Effect.runPromise(resultsAsStruct).then(console.log) * // Output: * // 42 * // Hello * // { a: 42, b: 'Hello' } * * @example * // Title: Combining Effects in Records * import { Effect, Console } from "effect" * * const recordOfEffects: Record<string, Effect.Effect<number>> = { * key1: Effect.succeed(1).pipe(Effect.tap(Console.log)), * key2: Effect.succeed(2).pipe(Effect.tap(Console.log)) * } * * // ┌─── Effect<{ [x: string]: number; }, never, never> * // ▼ * const resultsAsRecord = Effect.all(recordOfEffects) * * // Effect.runPromise(resultsAsRecord).then(console.log) * // Output: * // 1 * // 2 * // { key1: 1, key2: 2 } * * @example * // Title: Short-Circuiting Behavior * import { Effect, Console } from "effect" * * const program = Effect.all([ * Effect.succeed("Task1").pipe(Effect.tap(Console.log)), * Effect.fail("Task2: Oh no!").pipe(Effect.tap(Console.log)), * // Won't execute due to earlier failure * Effect.succeed("Task3").pipe(Effect.tap(Console.log)) * ]) * * // Effect.runPromiseExit(program).then(console.log) * // Output: * // Task1 * // { * // _id: 'Exit', * // _tag: 'Failure', * // cause: { _id: 'Cause', _tag: 'Fail', failure: 'Task2: Oh no!' } * // } * * @example * // Title: Collecting Results with `mode: "either"` * import { Effect, Console } from "effect" * * const effects = [ * Effect.succeed("Task1").pipe(Effect.tap(Console.log)), * Effect.fail("Task2: Oh no!").pipe(Effect.tap(Console.log)), * Effect.succeed("Task3").pipe(Effect.tap(Console.log)) * ] * * const program = Effect.all(effects, { mode: "either" }) * * // Effect.runPromiseExit(program).then(console.log) * // Output: * // Task1 * // Task3 * // { * // _id: 'Exit', * // _tag: 'Success', * // value: [ * // { _id: 'Either', _tag: 'Right', right: 'Task1' }, * // { _id: 'Either', _tag: 'Left', left: 'Task2: Oh no!' }, * // { _id: 'Either', _tag: 'Right', right: 'Task3' } * // ] * // } * * @example * //Example: Collecting Results with `mode: "validate"` * import { Effect, Console } from "effect" * * const effects = [ * Effect.succeed("Task1").pipe(Effect.tap(Console.log)), * Effect.fail("Task2: Oh no!").pipe(Effect.tap(Console.log)), * Effect.succeed("Task3").pipe(Effect.tap(Console.log)) * ] * * const program = Effect.all(effects, { mode: "validate" }) * * // Effect.runPromiseExit(program).then((result) => console.log("%o", result)) * // Output: * // Task1 * // Task3 * // { * // _id: 'Exit', * // _tag: 'Failure', * // cause: { * // _id: 'Cause', * // _tag: 'Fail', * // failure: [ * // { _id: 'Option', _tag: 'None' }, * // { _id: 'Option', _tag: 'Some', value: 'Task2: Oh no!' }, * // { _id: 'Option', _tag: 'None' } * // ] * // } * // } * * @since 2.0.0 * @category Collecting */ const all = exports.all = fiberRuntime.all; /** * A data-last version of {@link all}, designed for use in pipelines. * * **When to Use** * * This function enables you to combine multiple effects and customize execution * options such as concurrency levels. This version is useful in functional * pipelines where you first define your data and then apply operations to it. * * @example * ```ts * import { Effect, pipe } from "effect" * * const task1 = Effect.succeed(1).pipe( * Effect.delay("200 millis"), * Effect.tap(Effect.log("task1 done")) * ) * * const task2 = Effect.succeed("hello").pipe( * Effect.delay("100 millis"), * Effect.tap(Effect.log("task2 done")) * ) * * const program = pipe( * [task1, task2], * // Run both effects concurrently using the concurrent option * Effect.allWith({ concurrency: 2 }) * ) * * // Effect.runPromise(program).then(console.log) * // Output: * // timestamp=... level=INFO fiber=#3 message="task2 done" * // timestamp=... level=INFO fiber=#2 message="task1 done" * // [ 1, 'hello' ] * ``` * * @since 2.0.0 * @category Collecting */ const allWith = exports.allWith = fiberRuntime.allWith; /** * Evaluates and runs each effect in the iterable, collecting only the * successful results while discarding failures. * * **Details** * * This function function processes an iterable of effects and runs each one. If * an effect is successful, its result is collected; if it fails, the result is * discarded. This ensures that only successful outcomes are kept. * * **Options** * * The function also allows you to customize how the effects are handled by * specifying options such as concurrency, batching, and how finalizers behave. * These options provide flexibility in running the effects concurrently or * adjusting other execution details. * * @example * ```ts * import { Effect } from "effect" * * const tasks = [ * Effect.succeed(1), * Effect.fail("Error 1"), * Effect.succeed(2), * Effect.fail("Error 2") * ] * * const program = Effect.gen(function*() { * const successfulResults = yield* Effect.allSuccesses(tasks) * console.log(successfulResults) * }) * * // Effect.runFork(program) * // Output: [1, 2] * * ``` * * @since 2.0.0 * @category Collecting */ const allSuccesses = exports.allSuccesses = fiberRuntime.allSuccesses; /** * Drops elements until the effectful predicate returns `true`. * * **Details** * * This function processes a collection of elements and uses an effectful * predicate to determine when to stop dropping elements. It drops elements from * the beginning of the collection until the predicate returns `true`. * * The predicate is a function that takes an element and its index in the * collection and returns an effect that evaluates to a boolean. * * Once the predicate returns `true`, the remaining elements of the collection * are returned. * * **Note**: The first element for which the predicate returns `true` is also * dropped. * * **When to Use** * * This function allows you to conditionally skip over a part of the collection * based on some criteria defined in the predicate. * * @see {@link dropWhile} for a similar function that drops elements while the * predicate returns `true`. * * @example * ```ts * import { Effect } from "effect" * * const numbers = [1, 2, 3, 4, 5, 6] * const predicate = (n: number, i: number) => Effect.succeed(n > 3) * * const program = Effect.gen(function*() { * const result = yield* Effect.dropUntil(numbers, predicate) * console.log(result) * }) * * // Effect.runFork(program) * // Output: [5, 6] * ``` * * @since 2.0.0 * @category Collecting */ const dropUntil = exports.dropUntil = effect.dropUntil; /** * Drops elements as long as the predicate returns `true`. * * **Details** * * This function processes a collection of elements and uses a predicate to * decide whether to drop an element. * * The predicate is a function that takes an element and its index, and it * returns an effect that evaluates to a boolean. * * As long as the predicate returns `true`, elements will continue to be dropped * from the collection. * * Once the predicate returns `false`, the remaining elements are kept. * * **When to Use** * * This function allows you to discard elements from the start of a collection * based on a condition, and only keep the rest when the condition no longer * holds. * * @see {@link dropUntil} for a similar function that drops elements until the * predicate returns `true`. * * @example * ```ts * import { Effect } from "effect" * * const numbers = [1, 2, 3, 4, 5, 6] * const predicate = (n: number, i: number) => Effect.succeed(n <= 3) * * const program = Effect.gen(function*() { * const result = yield* Effect.dropWhile(numbers, predicate) * console.log(result) * }) * * // Effect.runFork(program) * // Output: [4, 5, 6] * ``` * * @since 2.0.0 * @category Collecting */ const dropWhile = exports.dropWhile = effect.dropWhile; /** * Takes elements from a collection until the effectful predicate returns * `true`. * * **Details** * * This function processes a collection of elements and uses an effectful * predicate to decide when to stop taking elements. The elements are taken from * the beginning of the collection until the predicate returns `true`. * * The predicate is a function that takes an element and its index in the * collection, and returns an effect that resolves to a boolean. * * Once the predicate returns `true`, the remaining elements of the collection * are discarded, and the function stops taking more elements. * * **Note**: The first element for which the predicate returns `true` is also * included in the result. * * **When to Use** * * Use this function when you want to conditionally take elements from a * collection based on a dynamic condition. For example, you may want to collect * numbers from a list until a certain threshold is reached, or gather items * until a specific condition is met. * * @see {@link takeWhile} for a similar function that takes elements while the * predicate returns `true`. * * @example * ```ts * import { Effect } from "effect" * * const numbers = [1, 2, 3, 4, 5, 6] * const predicate = (n: number, i: number) => Effect.succeed(n > 3) * * const program = Effect.gen(function*() { * const result = yield* Effect.takeUntil(numbers, predicate) * console.log(result) * }) * * // Effect.runFork(program) * // Output: [ 1, 2, 3, 4 ] * ``` * * @since 2.0.0 * @category Collecting */ const takeUntil = exports.takeUntil = effect.takeUntil; /** * Takes elements as long as the predicate returns `true`. * * **Details** * * This function processes a collection of elements and uses a predicate to * decide whether to take an element. * * The predicate is a function that takes an element and its index, and it * returns an effect that evaluates to a boolean. * * As long as the predicate returns `true`, elements will continue to be taken * from the collection. * * Once the predicate returns `false`, the remaining elements are discarded. * * @see {@link takeUntil} for a similar function that takes elements until the predicate returns `true`. * * @example * ```ts * import { Effect } from "effect" * * const numbers = [1, 2, 3, 4, 5, 6] * const predicate = (n: number, i: number) => Effect.succeed(n <= 3) * * const program = Effect.gen(function*() { * const result = yield* Effect.takeWhile(numbers, predicate) * console.log(result) * }) * * // Effect.runFork(program) * // Output: [1, 2, 3] * ``` * * @since 2.0.0 * @category Collecting */ const takeWhile = exports.takeWhile = effect.takeWhile; /** * Determines whether all elements of the iterable satisfy the effectful * predicate. * * **Details** * * This function checks whether every element in a given collection (an * iterable) satisfies a condition defined by an effectful predicate. * * The predicate is a function that takes an element and its index, and it * returns an effect that evaluates to a boolean. * * The function will process each element and return `true` if all elements * satisfy the predicate; otherwise, it returns `false`. * * **When to Use** * * This function is useful when you need to verify that all items in a * collection meet certain criteria, even when the evaluation of each item * involves effects, such as asynchronous checks or complex computations. * * @see {@link exists} for a similar function that returns a boolean indicating * whether **any** element satisfies the predicate. * * @example * ```ts * import { Effect } from "effect" * * const numbers = [2, 4, 6, 8] * const predicate = (n: number, i: number) => Effect.succeed(n % 2 === 0) * * const program = Effect.gen(function*() { * const allEven = yield* Effect.every(numbers, predicate) * console.log(allEven) * }) * * // Effect.runFork(program) * // Output: true * ``` * * @since 2.0.0 * @category Condition Checking */ const every = exports.every = effect.every; /** * Determines whether any element of the iterable satisfies the effectual * predicate. * * **Details** * * This function checks whether any element in a given collection (an iterable) * satisfies a condition defined by an effectful predicate. * * The predicate is a function that takes an element and its index, and it * returns an effect that evaluates to a boolean. * * The function will process each element, and if any element satisfies the * predicate (returns `true`), the function will immediately return `true`. * * If none of the elements satisfy the condition, it will return `false`. * * **When to Use** * * This function allows you to quickly check for a condition in a collection * without having to manually iterate over it. * * @see {@link every} for a similar function that checks if **all** elements * satisfy the predicate. * * @example * ```ts * import { Effect } from "effect" * * const numbers = [1, 2, 3, 4] * const predicate = (n: number, i: number) => Effect.succeed(n > 2) * * const program = Effect.gen(function*() { * const hasLargeNumber = yield* Effect.exists(numbers, predicate) * console.log(hasLargeNumber) * }) * * // Effect.runFork(program) * // Output: true * ``` * * @since 2.0.0 * @category Condition Checking */ const exists = exports.exists = fiberRuntime.exists; /** * Filters an iterable using the specified effectful predicate. * * **Details** * * This function filters a collection (an iterable) by applying an effectful * predicate. * * The predicate is a function that takes an element and its index, and it * returns an effect that evaluates to a boolean. * * The function processes each element in the collection and keeps only those * that satisfy the condition defined by the predicate. * * **Options** * * You can also adjust the behavior with options such as concurrency, batching, * or whether to negate the condition. * * **When to Use** * * This function allows you to selectively keep or remove elements based on a * condition that may involve asynchronous or side-effect-causing operations. * * @example * ```ts * import { Effect } from "effect" * * const numbers = [1, 2, 3, 4, 5] * const predicate = (n: number, i: number) => Effect.succeed(n % 2 === 0) * * const program = Effect.gen(function*() { * const result = yield* Effect.filter(numbers, predicate) * console.log(result) * }) * * // Effect.runFork(program) * // Output: [2, 4] * ``` * * @since 2.0.0 * @category Filtering */ const filter = exports.filter = fiberRuntime.filter; /** * Filters and maps elements sequentially in one operation. * * This function processes each element one by one. It applies a function that * returns an `Option` to each element. If the function returns `Some`, the * element is kept; if it returns `None`, the element is removed. The operation * is done sequentially for each element. * * @example * ```ts * import { Console, Effect, Option } from "effect" * * const task = (n: number) => * Effect.succeed(n).pipe( * Effect.delay(1000 - (n * 100)), * Effect.tap(Console.log(`task${n} done`)) * ) * * const program = Effect.filterMap( * [task(1), task(2), task(3), task(4)], * (n) => n % 2 === 0 ? Option.some(n) : Option.none() * ) * * // Effect.runPromise(program).then(console.log) * // Output: * // task1 done * // task2 done * // task3 done * // task4 done * // [ 2, 4 ] * ``` * * @since 2.0.0 * @category Filtering */ const filterMap = exports.filterMap = effect.filterMap; /** * Returns the first element that satisfies the effectful predicate. * * **Details** * * This function processes a collection of elements and applies an effectful * predicate to each element. * * The predicate is a function that takes an element and its index in the * collection, and it returns an effect that evaluates to a boolean. * * The function stops as soon as it finds the first element for which the * predicate returns `true` and returns that element wrapped in an `Option`. * * If no element satisfies the predicate, the result will be `None`. * * **When to Use** * * This function allows you to efficiently find an element that meets a specific * condition, even when the evaluation involves effects like asynchronous * operations or side effects. * * @example * ```ts * import { Effect } from "effect" * * const numbers = [1, 2, 3, 4, 5] * const predicate = (n: number, i: number) => Effect.succeed(n > 3) * * const program = Effect.gen(function*() { * const result = yield* Effect.findFirst(numbers, predicate) * console.log(result) * }) * * // Effect.runFork(program) * // Output: { _id: 'Option', _tag: 'Some', value: 4 } * ``` * * @since 2.0.0 * @category Collecting */ const findFirst = exports.findFirst = effect.findFirst; /** * Executes an effectful operation for each element in an `Iterable`. * * **Details** * * This function applies a provided operation to each element in the iterable, * producing a new effect that returns an array of results. * * If any effect fails, the iteration stops immediately (short-circuiting), and * the error is propagated. * * **Concurrency** * * The `concurrency` option controls how many operations are performed * concurrently. By default, the operations are performed sequentially. * * **Discarding Results** * * If the `discard` option is set to `true`, the intermediate results are not * collected, and the final result of the operation is `void`. * * @see {@link all} for combining multiple effects into one. * * @example * ```ts * // Title: Applying Effects to Iterable Elements * import { Effect, Console } from "effect" * * const result = Effect.forEach([1, 2, 3, 4, 5], (n, index) => * Console.log(`Currently at index ${index}`).pipe(Effect.as(n * 2)) * ) * * // Effect.runPromise(result).then(console.log) * // Output: * // Currently at index 0 * // Currently at index 1 * // Currently at index 2 * // Currently at index 3 * // Currently at index 4 * // [ 2, 4, 6, 8, 10 ] * ``` * * @example * // Title: Using discard to Ignore Results * import { Effect, Console } from "effect" * * // Apply effects but discard the results * const result = Effect.forEach( * [1, 2, 3, 4, 5], * (n, index) => * Console.log(`Currently at index ${index}`).pipe(Effect.as(n * 2)), * { discard: true } * ) * * // Effect.runPromise(result).then(console.log) * // Output: * // Currently at index 0 * // Currently at index 1 * // Currently at index 2 * // Currently at index 3 * // Currently at index 4 * // undefined * * @since 2.0.0 * @category Looping */ const forEach = exports.forEach = fiberRuntime.forEach; /** * Returns the first element of the iterable if the collection is non-empty, or * fails with the error `NoSuchElementException` if the collection is empty. * * **When to Use** * * This function is useful when you need to retrieve the first item from a * collection and want to handle the case where the collection might be empty * without causing an unhandled exception. * * @example * ```ts * import { Effect } from "effect" * * // Simulate an async operation * const fetchNumbers = Effect.succeed([1, 2, 3]).pipe(Effect.delay("100 millis")) * * const program = Effect.gen(function*() { * const firstElement = yield* Effect.head(fetchNumbers) * console.log(firstElement) * }) * * // Effect.runFork(program) * // Output: 1 * ``` * * @since 2.0.0 * @category Collecting */ const head = exports.head = effect.head; /** * Merges an `Iterable<Effect<A, E, R>>` to a single effect. * * **Details** * * This function takes an iterable of effects and combines them into a single * effect. It does this by iterating over each effect in the collection and * applying a function that accumulates results into a "zero" value, which * starts with an initial value and is updated with each effect's success. * * The provided function `f` is called for each element in the iterable, * allowing you to specify how to combine the results. * * **Options** * * The function also allows you to customize how the effects are handled by * specifying options such as concurrency, batching, and how finalizers behave. * These options provide flexibility in running the effects concurrently or * adjusting other execution details. * * @example * ```ts * import { Effect } from "effect" * * const numbers = [Effect.succeed(1), Effect.succeed(2), Effect.succeed(3)] * const add = (sum: number, value: number, i: number) => sum + value * const zero = 0 * * const program = Effect.gen(function*() { * const total = yield* Effect.mergeAll(numbers, zero, add) * console.log(total) * }) * * // Effect.runFork(program) * // Output: 6 * ``` * * @since 2.0.0 * @category Collecting */ const mergeAll = exports.mergeAll = fiberRuntime.mergeAll; /** * Processes an iterable and applies an effectful function to each element, * categorizing the results into successes and failures. * * **Details** * * This function processes each element in the provided iterable by applying an * effectful function to it. The results are then categorized into two separate * lists: one for failures and another for successes. This separation allows you * to handle the two categories differently. Failures are collected in a list * without interrupting the processing of the remaining elements, so the * operation continues even if some elements fail. This is particularly useful * when you need to handle both successful and failed results separately, * without stopping the entire process on encountering a failure. * * **When to Use** * * Use this function when you want to process a collection of items and handle * errors or failures without interrupting the processing of other items. It's * useful when you need to distinguish between successful and failed results and * process them separately, for example, when logging errors while continuing to * work with valid data. The function ensures that failures are captured, while * successes are processed normally. * * @see {@link validateAll} for a function that either collects all failures or all successes. * @see {@link validateFirst} for a function that stops at the first success. * * @example * ```ts * import { Effect } from "effect" * * // ┌─── Effect<[string[], number[]], never, never> * // ▼ * const program = Effect.partition([0, 1, 2, 3, 4], (n) => { * if (n % 2 === 0) { * return Effect.succeed(n) * } else { * return Effect.fail(`${n} is not even`) * } * }) * * // Effect.runPromise(program).then(console.log, console.error) * // Output: * // [ [ '1 is not even', '3 is not even' ], [ 0, 2, 4 ] ] * ``` * * @since 2.0.0 * @category Error Accumulation */ const partition = exports.partition = fiberRuntime.partition; /** * Reduces an `Iterable<A>` using an effectual function `f`, working * sequentially from left to right. * * **Details** * * This function takes an iterable and applies a function `f` to each element in * the iterable. The function works sequentially, starting with an initial value * `zero` and then combining it with each element in the collection. The * provided function `f` is called for each element in the iterable, allowing * you to accumulate a result based on the current value and the element being * processed. * * **When to Use** * * The function is often used for operations like summing a collection of * numbers or combining results from multiple tasks. It ensures that operations * are performed one after the other, maintaining the order of the elements. * * @see {@link reduceWhile} for a similar function that stops the process based on a predicate. * @see {@link reduceRight} for a similar function that works from right to left. * * @example * ```ts * import { Console, Effect } from "effect" * * const processOrder = (id: number) => * Effect.succeed({ id, price: 100 * id }) * .pipe(Effect.tap(() => Console.log(`Order ${id} processed`)), Effect.delay(500 - (id * 100))) * * const program = Effect.reduce( * [1, 2, 3, 4], * 0, * (acc, id, i) => * processOrder(id) * .pipe(Effect.map((order) => acc + order.price)) * ) * * // Effect.runPromise(program).then(console.log) * // Output: * // Order 1 processed * // Order 2 processed * // Order 3 processed * // Order 4 processed * // 1000 * ``` * * @since 2.0.0 * @category Collecting */ const reduce = exports.reduce = effect.reduce; /** * Reduces an `Iterable<A>` using an effectual function `body`, working * sequentially from left to right, stopping the process early when the * predicate `while` is not satisfied. * * **Details** * * This function processes a collection of elements, applying a function `body` * to reduce them to a single value, starting from the first element. It checks * the value of the accumulator against a predicate (`while`). If at any point * the predicate returns `false`, the reduction stops, and the accumulated * result is returned. * * **When to Use** * * Use this function when you need to reduce a collection of elements, but only * continue the process as long as a certain condition holds true. For example, * if you want to sum values in a list but stop as soon as the sum exceeds a * certain threshold, you can use this function. * * @example * ```ts * import { Console, Effect } from "effect" * * const processOrder = (id: number) => * Effect.succeed({ id, price: 100 * id }) * .pipe(Effect.tap(() => Console.log(`Order ${id} processed`)), Effect.delay(500 - (id * 100))) * * const program = Effect.reduceWhile( * [1, 2, 3, 4], * 0, * { * body: (acc, id, i) => * processOrder(id) * .pipe(Effect.map((order) => acc + order.price)), * while: (acc) => acc < 500 * } * ) * * // Effect.runPromise(program).then(console.log) * // Output: * // Order 1 processed * // Order 2 processed * // Order 3 processed * // 600 * ``` * * @since 2.0.0 * @category Collecting */ const reduceWhile = exports.reduceWhile = effect.reduceWhile; /** * Reduces an `Iterable<A>` using an effectual function `f`, working * sequentially from right to left. * * **Details** * * This function takes an iterable and applies a function `f` to each element in * the iterable. The function works sequentially, starting with an initial value * `zero` and then combining it with each element in the collection. The * provided function `f` is called for each element in the iterable, allowing * you to accumulate a result based on the current value and the element being * processed. * * **When to Use** * * The function is often used for operations like summing a collection of * numbers or combining results from multiple tasks. It ensures that operations * are performed one after the other, maintaining the order of the elements. * * @see {@link reduce} for a similar function that works from left to right. * * @example * ```ts * import { Console, Effect } from "effect" * * const processOrder = (id: number) => * Effect.succeed({ id, price: 100 * id }) * .pipe(Effect.tap(() => Console.log(`Order ${id} processed`)), Effect.delay(500 - (id * 100))) * * const program = Effect.reduceRight( * [1, 2, 3, 4], * 0, * (id, acc, i) => * processOrder(id) *