@nicolastoulemont/std 0.7.0 → 0.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +0 -6
- package/dist/context-CCHj1nab.mjs.map +1 -1
- package/dist/data/index.d.mts +1 -1
- package/dist/data/index.mjs +1 -1
- package/dist/{data-CJxw6al9.mjs → data-BLXO4XwS.mjs} +2 -2
- package/dist/{data-CJxw6al9.mjs.map → data-BLXO4XwS.mjs.map} +1 -1
- package/dist/data.tagged-error.types-CGiKD-ES.d.mts +29 -0
- package/dist/data.tagged-error.types-CGiKD-ES.d.mts.map +1 -0
- package/dist/either/index.d.mts +1 -1
- package/dist/either/index.mjs +1 -1
- package/dist/{either-6BwadiFj.mjs → either-BMLPfvMl.mjs} +2 -2
- package/dist/either-BMLPfvMl.mjs.map +1 -0
- package/dist/fx/index.d.mts +1 -1
- package/dist/fx/index.mjs +1 -1
- package/dist/{fx-BzxLbf1Q.mjs → fx-K-a9Smhn.mjs} +2 -2
- package/dist/fx-K-a9Smhn.mjs.map +1 -0
- package/dist/{fx.runtime-BcC6yMSy.mjs → fx.runtime-DclEDyjY.mjs} +2 -2
- package/dist/{fx.runtime-BcC6yMSy.mjs.map → fx.runtime-DclEDyjY.mjs.map} +1 -1
- package/dist/{index-DSsDFLGw.d.mts → index-B1-tBzc0.d.mts} +2 -2
- package/dist/{index-DSsDFLGw.d.mts.map → index-B1-tBzc0.d.mts.map} +1 -1
- package/dist/{index-CugDqdx6.d.mts → index-BNQ9xSAz.d.mts} +2 -2
- package/dist/{index-CugDqdx6.d.mts.map → index-BNQ9xSAz.d.mts.map} +1 -1
- package/dist/index-By6dNRc4.d.mts.map +1 -1
- package/dist/{index-DaTvFhZ8.d.mts → index-CGiLfREk.d.mts} +37 -37
- package/dist/{index-DaTvFhZ8.d.mts.map → index-CGiLfREk.d.mts.map} +1 -1
- package/dist/{index-CCo85AdC.d.mts → index-Cq2IFito.d.mts} +2 -2
- package/dist/{index-CCo85AdC.d.mts.map → index-Cq2IFito.d.mts.map} +1 -1
- package/dist/index-DEAWPlcI.d.mts.map +1 -1
- package/dist/{index-Dm2dFysv.d.mts → index-UzMbg1dh.d.mts} +2 -2
- package/dist/{index-Dm2dFysv.d.mts.map → index-UzMbg1dh.d.mts.map} +1 -1
- package/dist/index.d.mts +5 -5
- package/dist/index.mjs +1 -1
- package/dist/layer-BttmtDrs.mjs.map +1 -1
- package/dist/multithread-xUUh4eLn.mjs.map +1 -1
- package/dist/option/index.d.mts +1 -1
- package/dist/option/index.mjs +1 -1
- package/dist/{option-Qt1H-u7c.mjs → option-Tfbo4wty.mjs} +2 -2
- package/dist/option-Tfbo4wty.mjs.map +1 -0
- package/dist/option.types-D1mm0zUb.mjs +2 -0
- package/dist/option.types-D1mm0zUb.mjs.map +1 -0
- package/dist/{option.types-DlAb6Sr0.d.mts → option.types-qPevEZQd.d.mts} +5 -10
- package/dist/option.types-qPevEZQd.d.mts.map +1 -0
- package/dist/order-D5c4QChk.mjs.map +1 -1
- package/dist/provide/index.mjs +1 -1
- package/dist/{provide-B_SqJpCd.mjs → provide-C2cWOx2B.mjs} +2 -2
- package/dist/provide-C2cWOx2B.mjs.map +1 -0
- package/dist/queue/index.d.mts +1 -1
- package/dist/queue/index.mjs +1 -1
- package/dist/{queue-CG5izEBS.mjs → queue-Sg6KJerl.mjs} +2 -2
- package/dist/{queue-CG5izEBS.mjs.map → queue-Sg6KJerl.mjs.map} +1 -1
- package/dist/result-BEzV0DYC.mjs.map +1 -1
- package/dist/result.types-_xDAei3-.d.mts.map +1 -1
- package/dist/scope/index.mjs +1 -1
- package/dist/{scope-qwL1VUh2.mjs → scope-D_kzd1nT.mjs} +2 -2
- package/dist/scope-D_kzd1nT.mjs.map +1 -0
- package/package.json +1 -1
- package/dist/data.tagged-error.types-CLlJJ3n5.d.mts +0 -50
- package/dist/data.tagged-error.types-CLlJJ3n5.d.mts.map +0 -1
- package/dist/either-6BwadiFj.mjs.map +0 -1
- package/dist/fx-BzxLbf1Q.mjs.map +0 -1
- package/dist/option-Qt1H-u7c.mjs.map +0 -1
- package/dist/option.types-DRUm2QiI.mjs +0 -2
- package/dist/option.types-DRUm2QiI.mjs.map +0 -1
- package/dist/option.types-DlAb6Sr0.d.mts.map +0 -1
- package/dist/provide-B_SqJpCd.mjs.map +0 -1
- package/dist/scope-qwL1VUh2.mjs.map +0 -1
package/README.md
CHANGED
|
@@ -539,9 +539,3 @@ const normalizeProfile = (input: RawProfile) =>
|
|
|
539
539
|
(p) => ({ ...p, isAdult: p.age >= 18 }),
|
|
540
540
|
)
|
|
541
541
|
```
|
|
542
|
-
|
|
543
|
-
## Documentation
|
|
544
|
-
|
|
545
|
-
- Usage examples: `EXAMPLES.md`
|
|
546
|
-
- Fx integration notes: `docs/fx-react-integration.md`
|
|
547
|
-
- JSDoc conventions: `docs/jsdoc-style.md`
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"context-CCHj1nab.mjs","names":["service","impl","ctx"],"sources":["../src/context/context.ts"],"sourcesContent":["/**\n * Immutable service context map used by `Fx`, `Layer`, and `Provide`.\n *\n * **Mental model**\n * - A `Context` is a typed map from service key to implementation.\n * - Use it as the runtime carrier for dependency injection.\n *\n * **Common tasks**\n * - Start with `Context.empty` or `Context.make`.\n * - Combine contexts with `Context.add` and `Context.merge`.\n * - Resolve implementations with `Context.get`.\n *\n * **Gotchas**\n * - `Context.get` throws when a service is missing.\n * - Context values are immutable snapshots.\n *\n * **Quickstart**\n *\n * @example\n * ```ts\n * import { Context } from \"@nicolastoulemont/std\"\n *\n * const ctx = Context.empty()\n * // => { _tag: \"Context\", _services: Map(0) }\n * ```\n *\n * @module\n */\nimport type { ServiceClass } from \"../service/service\"\n\n/* oxlint-disable no-unsafe-type-assertion -- Context uses phantom service-type markers and overloaded accessors that require narrowed assertions. */\n\n// ============================================================================\n// Context Type\n// ============================================================================\n\n/**\n * Context<Services> is an immutable map storing service implementations.\n * The Services type parameter tracks which services are available.\n *\n * @example\n * ```ts\n * import { Context } from \"@nicolastoulemont/std\"\n *\n * type Example = typeof Context\n * ```\n *\n * @category Models\n */\nexport type Context<Services = never> = {\n readonly _tag: \"Context\"\n readonly _services: ReadonlyMap<string, unknown>\n // Phantom type for tracking available services\n readonly _Services: Services\n}\n\n// ============================================================================\n// Context Constructors\n// ============================================================================\n\n/**\n * Create an empty context with no services.\n *\n * @example\n * ```ts\n * import { Context } from \"@nicolastoulemont/std\"\n *\n * const ctx = Context.empty()\n * // => { _tag: \"Context\", _services: Map(0) }\n * ```\n *\n * @category Constructors\n */\nexport const empty = (): Context => ({\n _tag: \"Context\",\n _services: new Map(),\n _Services: undefined as never,\n})\n\n/**\n * Create a context with a single service.\n *\n * @param service - The service class (tag)\n * @param impl - The service implementation\n * @returns A context containing the service\n *\n * @example\n * ```ts\n * import { Context } from \"@nicolastoulemont/std\"\n *\n * import { Service } from \"@nicolastoulemont/std\"\n
|
|
1
|
+
{"version":3,"file":"context-CCHj1nab.mjs","names":["service","impl","ctx"],"sources":["../src/context/context.ts"],"sourcesContent":["/**\n * Immutable service context map used by `Fx`, `Layer`, and `Provide`.\n *\n * **Mental model**\n * - A `Context` is a typed map from service key to implementation.\n * - Use it as the runtime carrier for dependency injection.\n *\n * **Common tasks**\n * - Start with `Context.empty` or `Context.make`.\n * - Combine contexts with `Context.add` and `Context.merge`.\n * - Resolve implementations with `Context.get`.\n *\n * **Gotchas**\n * - `Context.get` throws when a service is missing.\n * - Context values are immutable snapshots.\n *\n * **Quickstart**\n *\n * @example\n * ```ts\n * import { Context } from \"@nicolastoulemont/std\"\n *\n * const ctx = Context.empty()\n * // => { _tag: \"Context\", _services: Map(0) }\n * ```\n *\n * @module\n */\nimport type { ServiceClass } from \"../service/service\"\n\n/* oxlint-disable no-unsafe-type-assertion -- Context uses phantom service-type markers and overloaded accessors that require narrowed assertions. */\n\n// ============================================================================\n// Context Type\n// ============================================================================\n\n/**\n * Context<Services> is an immutable map storing service implementations.\n * The Services type parameter tracks which services are available.\n *\n * @example\n * ```ts\n * import { Context } from \"@nicolastoulemont/std\"\n *\n * type Example = typeof Context\n * ```\n *\n * @category Models\n */\nexport type Context<Services = never> = {\n readonly _tag: \"Context\"\n readonly _services: ReadonlyMap<string, unknown>\n // Phantom type for tracking available services\n readonly _Services: Services\n}\n\n// ============================================================================\n// Context Constructors\n// ============================================================================\n\n/**\n * Create an empty context with no services.\n *\n * @example\n * ```ts\n * import { Context } from \"@nicolastoulemont/std\"\n *\n * const ctx = Context.empty()\n * // => { _tag: \"Context\", _services: Map(0) }\n * ```\n *\n * @category Constructors\n */\nexport const empty = (): Context => ({\n _tag: \"Context\",\n _services: new Map(),\n _Services: undefined as never,\n})\n\n/**\n * Create a context with a single service.\n *\n * @param service - The service class (tag)\n * @param impl - The service implementation\n * @returns A context containing the service\n *\n * @example\n * ```ts\n * import { Context } from \"@nicolastoulemont/std\"\n *\n * import { Service } from \"@nicolastoulemont/std\"\n *\n * const Logger = Service.tag<{ log: (message: string) => void }>(\"Logger\")\n * const ctx = Context.make(Logger, { log: (message) => console.log(message) })\n * // => context containing Logger\n * ```\n *\n * @category Utilities\n */\nexport const make = <S>(service: ServiceClass<S>, impl: S): Context<S> => ({\n _tag: \"Context\",\n _services: new Map([[service.key, impl]]),\n _Services: undefined as unknown as S,\n})\n\n// ============================================================================\n// Context Operations\n// ============================================================================\n\n/**\n * Add a service to an existing context (returns new context).\n * Curried for use with pipe.\n *\n * @param service - The service class (tag)\n * @param impl - The service implementation\n * @returns A function that takes a context and returns a new context with the service added\n *\n * @example\n * ```ts\n * import { Context } from \"@nicolastoulemont/std\"\n *\n * import { Service } from \"@nicolastoulemont/std\"\n *\n * const Logger = Service.tag<{ log: (message: string) => void }>(\"Logger\")\n * const Clock = Service.tag<{ now: () => number }>(\"Clock\")\n * const base = Context.make(Logger, { log: () => undefined })\n * const extended = Context.add(Clock, { now: () => 123 })(base)\n * // => context with Logger and Clock\n * ```\n *\n * @category Utilities\n */\nexport const add =\n <S>(service: ServiceClass<S>, impl: S) =>\n <Existing>(ctx: Context<Existing>): Context<Existing | S> => ({\n _tag: \"Context\",\n _services: new Map([...ctx._services, [service.key, impl]]),\n _Services: undefined as unknown as Existing | S,\n })\n\n/**\n * Merge two contexts together.\n * If both contexts have the same service, the second context's implementation wins.\n *\n * @param a - First context\n * @param b - Second context\n * @returns A new context with services from both\n *\n * @example\n * ```ts\n * import { Context } from \"@nicolastoulemont/std\"\n *\n * import { Service } from \"@nicolastoulemont/std\"\n *\n * const Logger = Service.tag<{ log: (message: string) => void }>(\"Logger\")\n * const Clock = Service.tag<{ now: () => number }>(\"Clock\")\n * const a = Context.make(Logger, { log: () => undefined })\n * const b = Context.make(Clock, { now: () => 123 })\n * const merged = Context.merge(a, b)\n * // => context with both services\n * ```\n *\n * @category Utilities\n */\nexport const merge = <A, B>(a: Context<A>, b: Context<B>): Context<A | B> => ({\n _tag: \"Context\",\n _services: new Map([...a._services, ...b._services]),\n _Services: undefined as unknown as A | B,\n})\n\n/**\n * Get a service from a context.\n * Throws if the service is not found.\n *\n * @param service - The service class (tag)\n * @returns The service implementation\n * @throws Error if service not found\n *\n * @example\n * ```ts\n * import { Context } from \"@nicolastoulemont/std\"\n *\n * import { Service } from \"@nicolastoulemont/std\"\n *\n * const Port = Service.tag<number>(\"Port\")\n * const ctx = Context.make(Port, 3000)\n * const port = Context.get(ctx, Port)\n * // => 3000\n * ```\n *\n * @category Utilities\n */\n// Use overload to handle both curried and uncurried calls\nexport function get<S>(ctx: Context<S>, service: ServiceClass<S>): S\nexport function get<S>(service: ServiceClass<S>): (ctx: Context<S>) => S\nexport function get<S>(\n ctxOrService: Context<S> | ServiceClass<S>,\n maybeService?: ServiceClass<S>,\n): S | ((ctx: Context<S>) => S) {\n // Curried form: get(service)(ctx)\n if (maybeService === undefined) {\n const service = ctxOrService as ServiceClass<S>\n return (ctx: Context<S>): S => {\n const impl = ctx._services.get(service.key)\n if (impl === undefined) {\n throw new Error(\n `Service \"${service.key}\" not found in context. Available services: [${[...ctx._services.keys()].join(\", \")}]`,\n )\n }\n return impl as S\n }\n }\n\n // Uncurried form: get(ctx, service)\n const ctx = ctxOrService as Context<S>\n const service = maybeService\n const impl = ctx._services.get(service.key)\n if (impl === undefined) {\n throw new Error(\n `Service \"${service.key}\" not found in context. Available services: [${[...ctx._services.keys()].join(\", \")}]`,\n )\n }\n return impl as S\n}\n\n/**\n * Check if a context contains a specific service.\n *\n * @param ctx - The context to check\n * @param service - The service class (tag)\n * @returns true if the service is in the context\n *\n * @example\n * ```ts\n * import { Context } from \"@nicolastoulemont/std\"\n *\n * import { Service } from \"@nicolastoulemont/std\"\n *\n * const Port = Service.tag<number>(\"Port\")\n * const ctx = Context.make(Port, 3000)\n * const present = Context.has(ctx, Port)\n * // => true\n * ```\n *\n * @category Guards\n */\nexport const has = <S>(ctx: Context<unknown>, service: ServiceClass<S>): boolean => ctx._services.has(service.key)\n\n/**\n * Get the size (number of services) in a context.\n *\n * @example\n * ```ts\n * import { Context } from \"@nicolastoulemont/std\"\n *\n * import { Service } from \"@nicolastoulemont/std\"\n *\n * const Port = Service.tag<number>(\"Port\")\n * const Logger = Service.tag<{ log: (message: string) => void }>(\"Logger\")\n * const ctx = Context.add(Logger, { log: () => undefined })(Context.make(Port, 3000))\n * const count = Context.size(ctx)\n * // => 2\n * ```\n *\n * @category Getters\n */\nexport const size = (ctx: Context<unknown>): number => ctx._services.size\n\n/* oxlint-enable no-unsafe-type-assertion */\n"],"mappings":"gIAyEA,MAAa,OAAwB,CACnC,KAAM,UACN,UAAW,IAAI,IACf,UAAW,IAAA,GACZ,EAsBY,GAAW,EAA0B,KAAyB,CACzE,KAAM,UACN,UAAW,IAAI,IAAI,CAAC,CAAC,EAAQ,IAAK,EAAK,CAAC,CAAC,CACzC,UAAW,IAAA,GACZ,EA6BY,GACP,EAA0B,IACnB,IAAmD,CAC5D,KAAM,UACN,UAAW,IAAI,IAAI,CAAC,GAAG,EAAI,UAAW,CAAC,EAAQ,IAAK,EAAK,CAAC,CAAC,CAC3D,UAAW,IAAA,GACZ,EA0BU,GAAe,EAAe,KAAmC,CAC5E,KAAM,UACN,UAAW,IAAI,IAAI,CAAC,GAAG,EAAE,UAAW,GAAG,EAAE,UAAU,CAAC,CACpD,UAAW,IAAA,GACZ,EA2BD,SAAgB,EACd,EACA,EAC8B,CAE9B,GAAI,IAAiB,IAAA,GAAW,CAC9B,IAAMA,EAAU,EAChB,MAAQ,IAAuB,CAC7B,IAAMC,EAAOC,EAAI,UAAU,IAAIF,EAAQ,IAAI,CAC3C,GAAIC,IAAS,IAAA,GACX,MAAU,MACR,YAAYD,EAAQ,IAAI,+CAA+C,CAAC,GAAGE,EAAI,UAAU,MAAM,CAAC,CAAC,KAAK,KAAK,CAAC,GAC7G,CAEH,OAAOD,GAKX,IAAM,EAAM,EACN,EAAU,EACV,EAAO,EAAI,UAAU,IAAI,EAAQ,IAAI,CAC3C,GAAI,IAAS,IAAA,GACX,MAAU,MACR,YAAY,EAAQ,IAAI,+CAA+C,CAAC,GAAG,EAAI,UAAU,MAAM,CAAC,CAAC,KAAK,KAAK,CAAC,GAC7G,CAEH,OAAO,EAwBT,MAAa,GAAU,EAAuB,IAAsC,EAAI,UAAU,IAAI,EAAQ,IAAI,CAoBrG,EAAQ,GAAkC,EAAI,UAAU"}
|
package/dist/data/index.d.mts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { t as data_d_exports } from "../index-
|
|
1
|
+
import { t as data_d_exports } from "../index-CGiLfREk.mjs";
|
|
2
2
|
export { data_d_exports as Data };
|
package/dist/data/index.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{n as e}from"../data-
|
|
1
|
+
import{n as e}from"../data-BLXO4XwS.mjs";export{e as Data};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{t as e}from"./chunk-C934ptG5.mjs";import{a as t,i as n,o as r,r as i}from"./equality-CoyUHWh9.mjs";import{t as a}from"./fx.types-Bg-Mmdm5.mjs";function o(e){let n=[...e];Object.defineProperty(n,`equals`,{value:e=>t(n,e),enumerable:!1,writable:!1,configurable:!1}),Object.defineProperty(n,`hash`,{value:()=>r(n),enumerable:!1,writable:!1,configurable:!1});let i=n.map.bind(n);Object.defineProperty(n,`map`,{value:e=>o(i(e)),enumerable:!1,writable:!1,configurable:!1});let a=n.filter.bind(n);Object.defineProperty(n,`filter`,{value:e=>o(a(e)),enumerable:!1,writable:!1,configurable:!1});let s=n.slice.bind(n);Object.defineProperty(n,`slice`,{value:(e,t)=>o(s(e,t)),enumerable:!1,writable:!1,configurable:!1});let c=n.concat.bind(n);return Object.defineProperty(n,`concat`,{value:(...e)=>o(c(...e)),enumerable:!1,writable:!1,configurable:!1}),Object.freeze(n)}function s(e){let n={...e};return Object.defineProperty(n,`equals`,{value:e=>t(n,e),enumerable:!1,writable:!1,configurable:!1}),Object.defineProperty(n,`hash`,{value:()=>r(n),enumerable:!1,writable:!1,configurable:!1}),Object.freeze(n)}function c(e){return class extends Error{static _tag=e;_tag=e;[a]={_A:()=>void 0,_E:()=>this,_R:()=>void 0};constructor(...t){super(e),this.name=e;let n=t[0];n&&Object.assign(this,n),Object.setPrototypeOf(this,new.target.prototype)}*[Symbol.iterator](){throw yield this,Error(`Unreachable: Fx.gen should short-circuit on error`)}}}function
|
|
2
|
-
//# sourceMappingURL=data-
|
|
1
|
+
import{t as e}from"./chunk-C934ptG5.mjs";import{a as t,i as n,o as r,r as i}from"./equality-CoyUHWh9.mjs";import{t as a}from"./fx.types-Bg-Mmdm5.mjs";function o(e){let n=[...e];Object.defineProperty(n,`equals`,{value:e=>t(n,e),enumerable:!1,writable:!1,configurable:!1}),Object.defineProperty(n,`hash`,{value:()=>r(n),enumerable:!1,writable:!1,configurable:!1});let i=n.map.bind(n);Object.defineProperty(n,`map`,{value:e=>o(i(e)),enumerable:!1,writable:!1,configurable:!1});let a=n.filter.bind(n);Object.defineProperty(n,`filter`,{value:e=>o(a(e)),enumerable:!1,writable:!1,configurable:!1});let s=n.slice.bind(n);Object.defineProperty(n,`slice`,{value:(e,t)=>o(s(e,t)),enumerable:!1,writable:!1,configurable:!1});let c=n.concat.bind(n);return Object.defineProperty(n,`concat`,{value:(...e)=>o(c(...e)),enumerable:!1,writable:!1,configurable:!1}),Object.freeze(n)}function s(e){let n={...e};return Object.defineProperty(n,`equals`,{value:e=>t(n,e),enumerable:!1,writable:!1,configurable:!1}),Object.defineProperty(n,`hash`,{value:()=>r(n),enumerable:!1,writable:!1,configurable:!1}),Object.freeze(n)}function c(e){let t=t=>Object.freeze({...t,_tag:e});return t.is=t=>typeof t==`object`&&!!t&&`_tag`in t&&t._tag===e,t.equals=i(e),t.hash=n(e),t._tag=e,t}function l(e){return class extends Error{static _tag=e;_tag=e;[a]={_A:()=>void 0,_E:()=>this,_R:()=>void 0};constructor(...t){super(e),this.name=e;let n=t[0];n&&Object.assign(this,n),Object.setPrototypeOf(this,new.target.prototype)}*[Symbol.iterator](){throw yield this,Error(`Unreachable: Fx.gen should short-circuit on error`)}}}function u(...e){let n=[...e];return Object.defineProperty(n,`equals`,{value:e=>t(n,e),enumerable:!1,writable:!1,configurable:!1}),Object.defineProperty(n,`hash`,{value:()=>r(n),enumerable:!1,writable:!1,configurable:!1}),Object.freeze(n)}var d=e({TaggedError:()=>p,array:()=>g,struct:()=>m,tagged:()=>f,tuple:()=>h});const f=c,p=l,m=s,h=u,g=o;export{d as n,p as t};
|
|
2
|
+
//# sourceMappingURL=data-BLXO4XwS.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"data-CJxw6al9.mjs","names":["array","struct","TaggedError","tagged","tuple","taggedImpl","TaggedErrorImpl","structImpl","tupleImpl","arrayImpl"],"sources":["../src/data/data.array.ts","../src/data/data.struct.ts","../src/data/data.tagged-error.ts","../src/data/data.tagged.ts","../src/data/data.tuple.ts","../src/data/data.ts"],"sourcesContent":["import { deepEquals, deepHash } from \"../equality/equality\"\nimport type { ArrayValue } from \"./data.types\"\n\n/**\n * Create an array with structural equality.\n *\n * The returned array is frozen (immutable) and has non-enumerable\n * equals() and hash() methods for structural comparison.\n *\n * The map() and filter() methods are overridden to return ArrayValue,\n * enabling method chaining with preserved equality semantics.\n *\n * @template T - The element type of the array\n * @param items - The array elements\n * @returns A frozen array with equals(), hash(), map(), and filter()\n *\n * @see {@link tuple} for fixed-length typed tuples\n * @see {@link struct} for object value types\n *\n * @example\n * ```ts\n * const arr1 = array([1, 2, 3])\n * const arr2 = array([1, 2, 3])\n *\n * arr1.equals(arr2) // true\n * arr1.hash() // number\n *\n * // Chainable operations return ArrayValue\n * arr1.map(x => x * 2) // ArrayValue<number>\n * arr1.filter(x => x > 1) // ArrayValue<number>\n *\n * // Chained equality check\n * arr1.map(x => x * 2).equals(array([2, 4, 6])) // true\n *\n * // Array is frozen\n * arr1[0] = 5 // TypeError\n * arr1.push(4) // TypeError\n * ```\n */\nexport function array<T>(items: readonly T[]): ArrayValue<T> {\n const value = [...items]\n\n // Add equals method (non-enumerable)\n Object.defineProperty(value, \"equals\", {\n value: (other: readonly T[]) => deepEquals(value, other),\n enumerable: false,\n writable: false,\n configurable: false,\n })\n\n // Add hash method (non-enumerable)\n Object.defineProperty(value, \"hash\", {\n value: () => deepHash(value),\n enumerable: false,\n writable: false,\n configurable: false,\n })\n\n // Override map to return ArrayValue\n const originalMap = value.map.bind(value)\n Object.defineProperty(value, \"map\", {\n value: <U>(fn: (item: T, index: number, arr: readonly T[]) => U): ArrayValue<U> => {\n return array(originalMap(fn))\n },\n enumerable: false,\n writable: false,\n configurable: false,\n })\n\n // Override filter to return ArrayValue\n const originalFilter = value.filter.bind(value)\n Object.defineProperty(value, \"filter\", {\n value: (fn: (item: T, index: number, arr: readonly T[]) => boolean): ArrayValue<T> => {\n return array(originalFilter(fn))\n },\n enumerable: false,\n writable: false,\n configurable: false,\n })\n\n // Override slice to return ArrayValue\n const originalSlice = value.slice.bind(value)\n Object.defineProperty(value, \"slice\", {\n value: (start?: number, end?: number): ArrayValue<T> => {\n return array(originalSlice(start, end))\n },\n enumerable: false,\n writable: false,\n configurable: false,\n })\n\n // Override concat to return ArrayValue\n const originalConcat = value.concat.bind(value)\n Object.defineProperty(value, \"concat\", {\n value: (...args: readonly (T | readonly T[])[]): ArrayValue<T> => {\n // oxlint-disable-next-line no-unsafe-type-assertion -- Required for concat argument spread\n return array(originalConcat(...(args as T[][])))\n },\n enumerable: false,\n writable: false,\n configurable: false,\n })\n\n // oxlint-disable-next-line no-unsafe-type-assertion -- Required for generic array return type\n return Object.freeze(value) as unknown as ArrayValue<T>\n}\n","import { deepEquals, deepHash } from \"../equality/equality\"\nimport type { StructValue } from \"./data.types\"\n\n/**\n * Create a frozen value object with structural equality.\n *\n * Unlike tagged(), struct() does not add a _tag discriminator.\n * Use this for simple value objects that don't need discrimination.\n *\n * The returned object is frozen (immutable) and has non-enumerable\n * equals() and hash() methods for structural comparison.\n *\n * @template T - The object shape type\n * @param input - The object to wrap\n * @returns A frozen object with equals() and hash() methods\n *\n * @see {@link tagged} for discriminated value objects with _tag\n * @see {@link array} for array value types\n *\n * @example\n * ```ts\n * const point = struct({ x: 10, y: 20 })\n * const point2 = struct({ x: 10, y: 20 })\n *\n * point.equals(point2) // true\n * point.hash() // number\n *\n * // Object is frozen\n * point.x = 5 // TypeError\n *\n * // equals/hash are non-enumerable\n * Object.keys(point) // [\"x\", \"y\"]\n * ```\n */\nexport function struct<T extends Record<string, unknown>>(input: T): StructValue<T> {\n const value = { ...input }\n\n // Add equals method (non-enumerable)\n Object.defineProperty(value, \"equals\", {\n value: (other: T) => deepEquals(value, other),\n enumerable: false,\n writable: false,\n configurable: false,\n })\n\n // Add hash method (non-enumerable)\n Object.defineProperty(value, \"hash\", {\n value: () => deepHash(value),\n enumerable: false,\n writable: false,\n configurable: false,\n })\n\n // oxlint-disable-next-line no-unsafe-type-assertion -- Required for generic struct return type\n return Object.freeze(value) as StructValue<T>\n}\n","import { FxTypeId } from \"../fx/fx.types\"\nimport type { TaggedErrorFactory } from \"./data.tagged-error.types\"\n\n/* oxlint-disable no-unsafe-type-assertion -- Tagged error factories intentionally cast to preserve ergonomic constructor signatures and Fx marker channels. */\n\n/**\n * Create a class-based tagged error type (Effect-style syntax).\n * Returns a class that can be extended to create custom error types.\n * Errors are native Error objects with proper stack traces and instanceof support.\n * Implements Yieldable protocol so errors can be directly yielded in Fx.gen computations.\n *\n * @template Tag - The error tag (discriminator string)\n * @param tag - The error tag\n * @returns A class that can be extended with custom data\n *\n * @example\n * ```ts\n * // Error with data\n * class NotFoundError extends TaggedError(\"NotFoundError\")<{ id: string }> {}\n * const err = new NotFoundError({ id: \"123\" })\n * err.id // \"123\"\n * err._tag // \"NotFoundError\"\n * err.stack // Error stack trace\n *\n * // Error without data\n * class UnauthorizedError extends TaggedError(\"UnauthorizedError\") {}\n * const err2 = new UnauthorizedError()\n *\n * // Direct yielding in Fx.gen computation\n * const program = Fx.gen(function* () {\n * yield* new NotFoundError({ id: \"123\" }) // Short-circuits with error\n * })\n *\n * // instanceof checks work\n * if (err instanceof NotFoundError) {\n * console.log(err.id)\n * }\n * ```\n */\nexport function TaggedError<Tag extends string>(tag: Tag): TaggedErrorFactory<Tag> {\n return class TaggedErrorImpl<Data extends object = object> extends Error {\n static readonly _tag: Tag = tag\n readonly _tag: Tag = tag\n\n readonly [FxTypeId] = {\n _A: () => undefined as never,\n _E: () => this as TaggedErrorImpl<Data>,\n _R: () => undefined as never,\n }\n\n constructor(...args: keyof Data extends never ? [] : [data: Data]) {\n super(tag)\n this.name = tag\n const data = args[0]\n if (data) Object.assign(this, data)\n Object.setPrototypeOf(this, new.target.prototype)\n }\n\n *[Symbol.iterator](): Generator<this, never, unknown> {\n yield this\n throw new Error(\"Unreachable: Fx.gen should short-circuit on error\")\n }\n } as unknown as TaggedErrorFactory<Tag>\n}\n\n/* oxlint-enable no-unsafe-type-assertion */\n","import { createEqualsMethod, createHashMethod } from \"../equality/equality\"\nimport type { Discriminator } from \"../shared/discriminator.types\"\nimport type { TaggedConstructor, TaggedValue } from \"./data.types\"\n\n/**\n * Create a tagged value constructor without schema validation.\n *\n * Unlike variant(), this creates values directly without validation.\n * Values are frozen and have structural equality via equals() and hash() methods.\n *\n * @template T - The data shape type (excluding _tag)\n * @param tag - The _tag discriminator value\n * @returns A constructor function with is(), equals(), and hash() methods\n *\n * @see {@link variant} for validated variant with schema support\n * @see {@link struct} for untagged value objects\n *\n * @example\n * ```ts\n * const Person = tagged<{ name: string; age: number }>(\"Person\")\n *\n * const alice = Person({ name: \"Alice\", age: 30 })\n * // => { _tag: \"Person\", name: \"Alice\", age: 30 }\n *\n * Person.equals(alice, Person({ name: \"Alice\", age: 30 })) // true\n * Person.is(alice) // true\n *\n * // Type guard usage\n * if (Person.is(unknownValue)) {\n * console.log(unknownValue.name) // TypeScript knows it's a Person\n * }\n *\n * // Values are frozen (immutable)\n * alice.name = \"Bob\" // TypeError\n * ```\n */\nexport function tagged<T extends Record<string, unknown>>(tag: string): TaggedConstructor<typeof tag, T> {\n type Output = TaggedValue<typeof tag, T>\n\n // Constructor function\n const constructor = (input: T): Output => {\n return Object.freeze({ ...input, _tag: tag }) as Output\n }\n\n // Type guard\n constructor.is = (value: unknown): value is Output => {\n return (\n typeof value === \"object\" &&\n value !== null &&\n \"_tag\" in value &&\n // oxlint-disable-next-line no-unsafe-type-assertion -- Already checked with 'in' operator\n (value as Discriminator)._tag === tag\n )\n }\n\n // Equality (static method on constructor)\n constructor.equals = createEqualsMethod<typeof tag, T>(tag)\n\n // Hashing (static method on constructor)\n constructor.hash = createHashMethod<typeof tag, T>(tag)\n\n // Store tag for reflection\n constructor._tag = tag\n\n return constructor as TaggedConstructor<typeof tag, T>\n}\n","import { deepEquals, deepHash } from \"../equality/equality\"\nimport type { TupleValue } from \"./data.types\"\n\n/**\n * Create a tuple with structural equality.\n *\n * The returned tuple is frozen (immutable) and has non-enumerable\n * equals() and hash() methods for structural comparison.\n *\n * @template T - The tuple type as a readonly array of element types\n * @param args - The tuple elements\n * @returns A frozen tuple-like array with equals() and hash() methods\n *\n * @see {@link array} for variable-length arrays with equality\n * @see {@link struct} for object value types\n *\n * @example\n * ```ts\n * const t1 = tuple(1, \"hello\", true)\n * const t2 = tuple(1, \"hello\", true)\n *\n * t1.equals(t2) // true\n * t1.hash() // number\n *\n * // Access elements (typed)\n * t1[0] // number\n * t1[1] // string\n * t1[2] // boolean\n *\n * // Tuple is frozen\n * t1[0] = 5 // TypeError\n * ```\n */\nexport function tuple<T extends readonly unknown[]>(...args: T): TupleValue<T> {\n const value = [...args]\n\n // Add equals method (non-enumerable)\n Object.defineProperty(value, \"equals\", {\n value: (other: readonly unknown[]) => deepEquals(value, other),\n enumerable: false,\n writable: false,\n configurable: false,\n })\n\n // Add hash method (non-enumerable)\n Object.defineProperty(value, \"hash\", {\n value: () => deepHash(value),\n enumerable: false,\n writable: false,\n configurable: false,\n })\n\n // oxlint-disable-next-line no-unsafe-type-assertion -- Required for generic tuple return type\n return Object.freeze(value) as unknown as TupleValue<T>\n}\n","/**\n * Structural data constructors for tagged objects, tuples, arrays, and records.\n *\n * **Mental model**\n * - `Data` helpers create immutable-friendly values with structural equality semantics.\n * - Use `tagged` and `TaggedError` to model domain objects and errors.\n *\n * **Common tasks**\n * - Build tagged records via `Data.tagged`.\n * - Define typed tagged errors with `Data.TaggedError`.\n * - Create structural containers with `Data.struct`, `Data.tuple`, and `Data.array`.\n *\n * **Gotchas**\n * - These constructors are value-level utilities, not validation schemas.\n * - Prefer explicit tagged names for debugging and pattern matching.\n *\n * **Quickstart**\n *\n * @example\n * ```ts\n * import { Data } from \"@nicolastoulemont/std\"\n *\n * const User = Data.tagged<{ id: string }>(\"User\")\n * const user = User({ id: \"u1\" })\n * // => { _tag: \"User\", id: \"u1\" }\n * ```\n *\n * @module\n */\nimport { array as arrayImpl } from \"./data.array\"\nimport { struct as structImpl } from \"./data.struct\"\nimport { TaggedError as TaggedErrorImpl } from \"./data.tagged-error\"\nimport { tagged as taggedImpl } from \"./data.tagged\"\nimport { tuple as tupleImpl } from \"./data.tuple\"\n\n/**\n * Construct tagged data objects.\n *\n * @example\n * ```ts\n * import { Data } from \"@nicolastoulemont/std\"\n *\n * const User = Data.tagged<{ id: string }>(\"User\")\n * const user = User({ id: \"u1\" })\n * // => { _tag: \"User\", id: \"u1\" }\n * ```\n *\n * @category Constructors\n */\nexport const tagged = taggedImpl\n\n/**\n * Construct tagged error classes.\n *\n * @example\n * ```ts\n * import { Data } from \"@nicolastoulemont/std\"\n *\n * class NotFoundError extends Data.TaggedError(\"NotFoundError\")<{ id: string }> {}\n * const error = new NotFoundError({ id: \"u1\" })\n * // => { _tag: \"NotFoundError\", id: \"u1\" }\n * ```\n *\n * @category Constructors\n */\nexport const TaggedError = TaggedErrorImpl\n\n/**\n * Construct immutable-like structs with stable structural behavior.\n *\n * @example\n * ```ts\n * import { Data } from \"@nicolastoulemont/std\"\n *\n * const point = Data.struct({ x: 1, y: 2 })\n * const same = point.equals({ x: 1, y: 2 })\n * // => true\n * ```\n *\n * @category Constructors\n */\nexport const struct = structImpl\n\n/**\n * Construct immutable-like tuples with stable structural behavior.\n *\n * @example\n * ```ts\n * import { Data } from \"@nicolastoulemont/std\"\n *\n * const pair = Data.tuple(\"left\", 1)\n * const first = pair[0]\n * // => \"left\"\n * ```\n *\n * @category Constructors\n */\nexport const tuple = tupleImpl\n\n/**\n * Construct immutable-like arrays with stable structural behavior.\n *\n * @example\n * ```ts\n * import { Data } from \"@nicolastoulemont/std\"\n *\n * const ids = Data.array([\"a\", \"b\"])\n * const upper = ids.map((id) => id.toUpperCase())\n * // => [\"A\", \"B\"]\n * ```\n *\n * @category Constructors\n */\nexport const array = arrayImpl\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"data-BLXO4XwS.mjs","names":["array","struct","tagged","TaggedError","tuple","taggedImpl","TaggedErrorImpl","structImpl","tupleImpl","arrayImpl"],"sources":["../src/data/data.array.ts","../src/data/data.struct.ts","../src/data/data.tagged.ts","../src/data/data.tagged-error.ts","../src/data/data.tuple.ts","../src/data/data.ts"],"sourcesContent":["import { deepEquals, deepHash } from \"../equality/equality\"\nimport type { ArrayValue } from \"./data.types\"\n\n/**\n * Create an array with structural equality.\n *\n * The returned array is frozen (immutable) and has non-enumerable\n * equals() and hash() methods for structural comparison.\n *\n * The map() and filter() methods are overridden to return ArrayValue,\n * enabling method chaining with preserved equality semantics.\n *\n * @template T - The element type of the array\n * @param items - The array elements\n * @returns A frozen array with equals(), hash(), map(), and filter()\n *\n * @see {@link tuple} for fixed-length typed tuples\n * @see {@link struct} for object value types\n *\n * @example\n * ```ts\n * const arr1 = array([1, 2, 3])\n * const arr2 = array([1, 2, 3])\n *\n * arr1.equals(arr2) // true\n * arr1.hash() // number\n *\n * // Chainable operations return ArrayValue\n * arr1.map(x => x * 2) // ArrayValue<number>\n * arr1.filter(x => x > 1) // ArrayValue<number>\n *\n * // Chained equality check\n * arr1.map(x => x * 2).equals(array([2, 4, 6])) // true\n *\n * // Array is frozen\n * arr1[0] = 5 // TypeError\n * arr1.push(4) // TypeError\n * ```\n */\nexport function array<T>(items: readonly T[]): ArrayValue<T> {\n const value = [...items]\n\n // Add equals method (non-enumerable)\n Object.defineProperty(value, \"equals\", {\n value: (other: readonly T[]) => deepEquals(value, other),\n enumerable: false,\n writable: false,\n configurable: false,\n })\n\n // Add hash method (non-enumerable)\n Object.defineProperty(value, \"hash\", {\n value: () => deepHash(value),\n enumerable: false,\n writable: false,\n configurable: false,\n })\n\n // Override map to return ArrayValue\n const originalMap = value.map.bind(value)\n Object.defineProperty(value, \"map\", {\n value: <U>(fn: (item: T, index: number, arr: readonly T[]) => U): ArrayValue<U> => {\n return array(originalMap(fn))\n },\n enumerable: false,\n writable: false,\n configurable: false,\n })\n\n // Override filter to return ArrayValue\n const originalFilter = value.filter.bind(value)\n Object.defineProperty(value, \"filter\", {\n value: (fn: (item: T, index: number, arr: readonly T[]) => boolean): ArrayValue<T> => {\n return array(originalFilter(fn))\n },\n enumerable: false,\n writable: false,\n configurable: false,\n })\n\n // Override slice to return ArrayValue\n const originalSlice = value.slice.bind(value)\n Object.defineProperty(value, \"slice\", {\n value: (start?: number, end?: number): ArrayValue<T> => {\n return array(originalSlice(start, end))\n },\n enumerable: false,\n writable: false,\n configurable: false,\n })\n\n // Override concat to return ArrayValue\n const originalConcat = value.concat.bind(value)\n Object.defineProperty(value, \"concat\", {\n value: (...args: readonly (T | readonly T[])[]): ArrayValue<T> => {\n // oxlint-disable-next-line no-unsafe-type-assertion -- Required for concat argument spread\n return array(originalConcat(...(args as T[][])))\n },\n enumerable: false,\n writable: false,\n configurable: false,\n })\n\n // oxlint-disable-next-line no-unsafe-type-assertion -- Required for generic array return type\n return Object.freeze(value) as unknown as ArrayValue<T>\n}\n","import { deepEquals, deepHash } from \"../equality/equality\"\nimport type { StructValue } from \"./data.types\"\n\n/**\n * Create a frozen value object with structural equality.\n *\n * Unlike tagged(), struct() does not add a _tag discriminator.\n * Use this for simple value objects that don't need discrimination.\n *\n * The returned object is frozen (immutable) and has non-enumerable\n * equals() and hash() methods for structural comparison.\n *\n * @template T - The object shape type\n * @param input - The object to wrap\n * @returns A frozen object with equals() and hash() methods\n *\n * @see {@link tagged} for discriminated value objects with _tag\n * @see {@link array} for array value types\n *\n * @example\n * ```ts\n * const point = struct({ x: 10, y: 20 })\n * const point2 = struct({ x: 10, y: 20 })\n *\n * point.equals(point2) // true\n * point.hash() // number\n *\n * // Object is frozen\n * point.x = 5 // TypeError\n *\n * // equals/hash are non-enumerable\n * Object.keys(point) // [\"x\", \"y\"]\n * ```\n */\nexport function struct<T extends Record<string, unknown>>(input: T): StructValue<T> {\n const value = { ...input }\n\n // Add equals method (non-enumerable)\n Object.defineProperty(value, \"equals\", {\n value: (other: T) => deepEquals(value, other),\n enumerable: false,\n writable: false,\n configurable: false,\n })\n\n // Add hash method (non-enumerable)\n Object.defineProperty(value, \"hash\", {\n value: () => deepHash(value),\n enumerable: false,\n writable: false,\n configurable: false,\n })\n\n // oxlint-disable-next-line no-unsafe-type-assertion -- Required for generic struct return type\n return Object.freeze(value) as StructValue<T>\n}\n","import { createEqualsMethod, createHashMethod } from \"../equality/equality\"\nimport type { Discriminator } from \"../shared/discriminator.types\"\nimport type { TaggedConstructor, TaggedValue } from \"./data.types\"\n\n/**\n * Create a tagged value constructor without schema validation.\n *\n * Unlike variant(), this creates values directly without validation.\n * Values are frozen and have structural equality via equals() and hash() methods.\n *\n * @template T - The data shape type (excluding _tag)\n * @param tag - The _tag discriminator value\n * @returns A constructor function with is(), equals(), and hash() methods\n *\n * @see {@link variant} for validated variant with schema support\n * @see {@link struct} for untagged value objects\n *\n * @example\n * ```ts\n * const Person = tagged<{ name: string; age: number }>(\"Person\")\n *\n * const alice = Person({ name: \"Alice\", age: 30 })\n * // => { _tag: \"Person\", name: \"Alice\", age: 30 }\n *\n * Person.equals(alice, Person({ name: \"Alice\", age: 30 })) // true\n * Person.is(alice) // true\n *\n * // Type guard usage\n * if (Person.is(unknownValue)) {\n * console.log(unknownValue.name) // TypeScript knows it's a Person\n * }\n *\n * // Values are frozen (immutable)\n * alice.name = \"Bob\" // TypeError\n * ```\n */\nexport function tagged<T extends Record<string, unknown>>(tag: string): TaggedConstructor<typeof tag, T> {\n type Output = TaggedValue<typeof tag, T>\n\n // Constructor function\n const constructor = (input: T): Output => {\n return Object.freeze({ ...input, _tag: tag }) as Output\n }\n\n // Type guard\n constructor.is = (value: unknown): value is Output => {\n return (\n typeof value === \"object\" &&\n value !== null &&\n \"_tag\" in value &&\n // oxlint-disable-next-line no-unsafe-type-assertion -- Already checked with 'in' operator\n (value as Discriminator)._tag === tag\n )\n }\n\n // Equality (static method on constructor)\n constructor.equals = createEqualsMethod<typeof tag, T>(tag)\n\n // Hashing (static method on constructor)\n constructor.hash = createHashMethod<typeof tag, T>(tag)\n\n // Store tag for reflection\n constructor._tag = tag\n\n return constructor as TaggedConstructor<typeof tag, T>\n}\n","import { FxTypeId } from \"../fx/fx.types\"\nimport type { TaggedErrorFactory } from \"./data.tagged-error.types\"\n\n/* oxlint-disable no-unsafe-type-assertion -- Tagged error factories intentionally cast to preserve ergonomic constructor signatures and Fx marker channels. */\n\n/**\n * Create a class-based tagged error type (Effect-style syntax).\n * Returns a class that can be extended to create custom error types.\n * Errors are native Error objects with proper stack traces and instanceof support.\n * Implements Yieldable protocol so errors can be directly yielded in Fx.gen computations.\n *\n * @template Tag - The error tag (discriminator string)\n * @param tag - The error tag\n * @returns A class that can be extended with custom data\n *\n * @example\n * ```ts\n * // Error with data\n * class NotFoundError extends TaggedError(\"NotFoundError\")<{ id: string }> {}\n * const err = new NotFoundError({ id: \"123\" })\n * err.id // \"123\"\n * err._tag // \"NotFoundError\"\n * err.stack // Error stack trace\n *\n * // Error without data\n * class UnauthorizedError extends TaggedError(\"UnauthorizedError\") {}\n * const err2 = new UnauthorizedError()\n *\n * // Direct yielding in Fx.gen computation\n * const program = Fx.gen(function* () {\n * yield* new NotFoundError({ id: \"123\" }) // Short-circuits with error\n * })\n *\n * // instanceof checks work\n * if (err instanceof NotFoundError) {\n * console.log(err.id)\n * }\n * ```\n */\nexport function TaggedError<Tag extends string>(tag: Tag): TaggedErrorFactory<Tag> {\n return class TaggedErrorImpl<Data extends object = object> extends Error {\n static readonly _tag: Tag = tag\n readonly _tag: Tag = tag\n\n readonly [FxTypeId] = {\n _A: () => undefined as never,\n _E: () => this as TaggedErrorImpl<Data>,\n _R: () => undefined as never,\n }\n\n constructor(...args: keyof Data extends never ? [] : [data: Data]) {\n super(tag)\n this.name = tag\n const data = args[0]\n if (data) Object.assign(this, data)\n Object.setPrototypeOf(this, new.target.prototype)\n }\n\n *[Symbol.iterator](): Generator<this, never, unknown> {\n yield this\n throw new Error(\"Unreachable: Fx.gen should short-circuit on error\")\n }\n } as unknown as TaggedErrorFactory<Tag>\n}\n\n/* oxlint-enable no-unsafe-type-assertion */\n","import { deepEquals, deepHash } from \"../equality/equality\"\nimport type { TupleValue } from \"./data.types\"\n\n/**\n * Create a tuple with structural equality.\n *\n * The returned tuple is frozen (immutable) and has non-enumerable\n * equals() and hash() methods for structural comparison.\n *\n * @template T - The tuple type as a readonly array of element types\n * @param args - The tuple elements\n * @returns A frozen tuple-like array with equals() and hash() methods\n *\n * @see {@link array} for variable-length arrays with equality\n * @see {@link struct} for object value types\n *\n * @example\n * ```ts\n * const t1 = tuple(1, \"hello\", true)\n * const t2 = tuple(1, \"hello\", true)\n *\n * t1.equals(t2) // true\n * t1.hash() // number\n *\n * // Access elements (typed)\n * t1[0] // number\n * t1[1] // string\n * t1[2] // boolean\n *\n * // Tuple is frozen\n * t1[0] = 5 // TypeError\n * ```\n */\nexport function tuple<T extends readonly unknown[]>(...args: T): TupleValue<T> {\n const value = [...args]\n\n // Add equals method (non-enumerable)\n Object.defineProperty(value, \"equals\", {\n value: (other: readonly unknown[]) => deepEquals(value, other),\n enumerable: false,\n writable: false,\n configurable: false,\n })\n\n // Add hash method (non-enumerable)\n Object.defineProperty(value, \"hash\", {\n value: () => deepHash(value),\n enumerable: false,\n writable: false,\n configurable: false,\n })\n\n // oxlint-disable-next-line no-unsafe-type-assertion -- Required for generic tuple return type\n return Object.freeze(value) as unknown as TupleValue<T>\n}\n","/**\n * Structural data constructors for tagged objects, tuples, arrays, and records.\n *\n * **Mental model**\n * - `Data` helpers create immutable-friendly values with structural equality semantics.\n * - Use `tagged` and `TaggedError` to model domain objects and errors.\n *\n * **Common tasks**\n * - Build tagged records via `Data.tagged`.\n * - Define typed tagged errors with `Data.TaggedError`.\n * - Create structural containers with `Data.struct`, `Data.tuple`, and `Data.array`.\n *\n * **Gotchas**\n * - These constructors are value-level utilities, not validation schemas.\n * - Prefer explicit tagged names for debugging and pattern matching.\n *\n * **Quickstart**\n *\n * @example\n * ```ts\n * import { Data } from \"@nicolastoulemont/std\"\n *\n * const User = Data.tagged<{ id: string }>(\"User\")\n * const user = User({ id: \"u1\" })\n * // => { _tag: \"User\", id: \"u1\" }\n * ```\n *\n * @module\n */\nimport { array as arrayImpl } from \"./data.array\"\nimport { struct as structImpl } from \"./data.struct\"\nimport { tagged as taggedImpl } from \"./data.tagged\"\nimport { TaggedError as TaggedErrorImpl } from \"./data.tagged-error\"\nimport { tuple as tupleImpl } from \"./data.tuple\"\n\n/**\n * Construct tagged data objects.\n *\n * @example\n * ```ts\n * import { Data } from \"@nicolastoulemont/std\"\n *\n * const User = Data.tagged<{ id: string }>(\"User\")\n * const user = User({ id: \"u1\" })\n * // => { _tag: \"User\", id: \"u1\" }\n * ```\n *\n * @category Constructors\n */\nexport const tagged = taggedImpl\n\n/**\n * Construct tagged error classes.\n *\n * @example\n * ```ts\n * import { Data } from \"@nicolastoulemont/std\"\n *\n * class NotFoundError extends Data.TaggedError(\"NotFoundError\")<{ id: string }> {}\n * const error = new NotFoundError({ id: \"u1\" })\n * // => { _tag: \"NotFoundError\", id: \"u1\" }\n * ```\n *\n * @category Constructors\n */\nexport const TaggedError = TaggedErrorImpl\n\n/**\n * Construct immutable-like structs with stable structural behavior.\n *\n * @example\n * ```ts\n * import { Data } from \"@nicolastoulemont/std\"\n *\n * const point = Data.struct({ x: 1, y: 2 })\n * const same = point.equals({ x: 1, y: 2 })\n * // => true\n * ```\n *\n * @category Constructors\n */\nexport const struct = structImpl\n\n/**\n * Construct immutable-like tuples with stable structural behavior.\n *\n * @example\n * ```ts\n * import { Data } from \"@nicolastoulemont/std\"\n *\n * const pair = Data.tuple(\"left\", 1)\n * const first = pair[0]\n * // => \"left\"\n * ```\n *\n * @category Constructors\n */\nexport const tuple = tupleImpl\n\n/**\n * Construct immutable-like arrays with stable structural behavior.\n *\n * @example\n * ```ts\n * import { Data } from \"@nicolastoulemont/std\"\n *\n * const ids = Data.array([\"a\", \"b\"])\n * const upper = ids.map((id) => id.toUpperCase())\n * // => [\"A\", \"B\"]\n * ```\n *\n * @category Constructors\n */\nexport const array = arrayImpl\n"],"mappings":"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"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { i as Fx } from "./fx.types-DeEWEltG.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/data/data.tagged-error.types.d.ts
|
|
4
|
+
interface TaggedErrorCore<Tag extends string, Data extends object = object> extends Error, Fx<never, TaggedErrorCore<Tag, Data>, never> {
|
|
5
|
+
readonly _tag: Tag;
|
|
6
|
+
[Symbol.iterator](): Generator<TaggedErrorCore<Tag, Data>, never, unknown>;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Type for instances created by the TaggedError class factory.
|
|
10
|
+
* Extends Error and includes the tag, data, Fx protocol, and Yieldable protocol.
|
|
11
|
+
* When yielded, yields itself as an Fx type for proper inference.
|
|
12
|
+
*
|
|
13
|
+
* @template Tag - The error tag (discriminator string)
|
|
14
|
+
* @template Data - Additional error data (optional)
|
|
15
|
+
*/
|
|
16
|
+
type TaggedErrorInstance<Tag extends string, Data extends object = object> = TaggedErrorCore<Tag, Data> & Readonly<Data>;
|
|
17
|
+
/**
|
|
18
|
+
* Type for the class returned by TaggedError factory.
|
|
19
|
+
* Supports the Effect-style curried syntax: `TaggedError("Tag")<{ data }>` and `TaggedError("Tag")`
|
|
20
|
+
*
|
|
21
|
+
* @template Tag - The error tag (discriminator string)
|
|
22
|
+
*/
|
|
23
|
+
type TaggedErrorFactory<Tag extends string> = {
|
|
24
|
+
new <Data extends object = object>(...args: keyof Data extends never ? [] : [data: Data]): TaggedErrorInstance<Tag, Data>;
|
|
25
|
+
readonly _tag: Tag;
|
|
26
|
+
};
|
|
27
|
+
//#endregion
|
|
28
|
+
export { TaggedErrorFactory as t };
|
|
29
|
+
//# sourceMappingURL=data.tagged-error.types-CGiKD-ES.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"data.tagged-error.types-CGiKD-ES.d.mts","names":[],"sources":["../src/data/data.tagged-error.types.ts"],"sourcesContent":[],"mappings":";;;UAGU,0EACA,OAAO,UAAU,gBAAgB,KAAK;iBAC/B;EAFP,CAAA,MAAA,CAAA,QAAA,GAAe,EAGF,SAHE,CAGQ,eAHR,CAGwB,GAHxB,EAG6B,IAH7B,CAAA,EAAA,KAAA,EAAA,OAAA,CAAA;;;;;;;;;;KAcpB,mBAbY,CAAA,YAAA,MAAA,EAAA,aAAA,MAAA,GAAA,MAAA,CAAA,GAa4D,eAb5D,CAa4E,GAb5E,EAaiF,IAbjF,CAAA,GAayF,QAbzF,CAakG,IAblG,CAAA;;AAAE;;;;;AAauF,KAQ9F,kBAR8F,CAAA,YAAA,MAAA,CAAA,GAAA;EAAQ,IAAA,CAAA,aAAA,MAAA,GAAA,MAAA,CAAA,CAAA,GAAA,IAAA,EAAA,MAU/F,IAV+F,SAAA,KAAA,GAAA,EAAA,GAAA,CAAA,IAAA,EAU9D,IAV8D,CAAA,CAAA,EAW7G,mBAX6G,CAWzF,GAXyF,EAWpF,IAXoF,CAAA;EAQtG,SAAA,IAAA,EAIK,GAJL;CAEO"}
|
package/dist/either/index.d.mts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { t as either_d_exports } from "../index-
|
|
1
|
+
import { t as either_d_exports } from "../index-B1-tBzc0.mjs";
|
|
2
2
|
export { either_d_exports as Either };
|
package/dist/either/index.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{t as e}from"../either-
|
|
1
|
+
import{t as e}from"../either-BMLPfvMl.mjs";export{e as Either};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{t as e}from"./chunk-C934ptG5.mjs";import{t}from"./fx.types-Bg-Mmdm5.mjs";import{t as n}from"./dual-CZhzZslG.mjs";import{n as r}from"./flow-D8_tllWl.mjs";import{t as i}from"./pipeable-COGyGMUV.mjs";import{r as a,t as o}from"./result-BEzV0DYC.mjs";import{i as s,n as c}from"./option-
|
|
2
|
-
//# sourceMappingURL=either-
|
|
1
|
+
import{t as e}from"./chunk-C934ptG5.mjs";import{t}from"./fx.types-Bg-Mmdm5.mjs";import{t as n}from"./dual-CZhzZslG.mjs";import{n as r}from"./flow-D8_tllWl.mjs";import{t as i}from"./pipeable-COGyGMUV.mjs";import{r as a,t as o}from"./result-BEzV0DYC.mjs";import{i as s,n as c}from"./option-Tfbo4wty.mjs";var l=e({all:()=>C,bimap:()=>g,filter:()=>S,flatMap:()=>_,fromNullable:()=>j,fromOption:()=>k,fromPredicate:()=>M,fromResult:()=>D,isLeft:()=>p,isRight:()=>f,left:()=>d,map:()=>m,mapLeft:()=>h,match:()=>E,orElse:()=>b,right:()=>u,swap:()=>x,tap:()=>v,tapLeft:()=>y,toOption:()=>A,toResult:()=>O,unwrapOr:()=>w,unwrapOrElse:()=>T});const u=e=>({_tag:`Right`,value:e,[t]:{_A:()=>e,_E:()=>void 0,_R:()=>void 0},pipe:i,*[Symbol.iterator](){return e}}),d=e=>({_tag:`Left`,value:e,[t]:{_A:()=>e,_E:()=>void 0,_R:()=>void 0},pipe:i,*[Symbol.iterator](){return e}}),f=e=>e._tag===`Right`,p=e=>e._tag===`Left`,m=n(2,(e,t)=>{if(e._tag===`Left`)return e;let n=t(e.value);return r(n)?Promise.resolve(n).then(u):u(n)}),h=n(2,(e,t)=>{if(e._tag===`Right`)return e;let n=t(e.value);return r(n)?Promise.resolve(n).then(d):d(n)}),g=n(3,(e,t,n)=>{if(e._tag===`Right`){let t=n(e.value);return r(t)?Promise.resolve(t).then(u):u(t)}let i=t(e.value);return r(i)?Promise.resolve(i).then(d):d(i)}),_=n(2,(e,t)=>e._tag===`Left`?e:t(e.value)),v=n(2,(e,t)=>{if(e._tag===`Left`)return e;let n=t(e.value);return r(n)?Promise.resolve(n).then(()=>e):e}),y=n(2,(e,t)=>{if(e._tag===`Right`)return e;let n=t(e.value);return r(n)?Promise.resolve(n).then(()=>e):e}),b=n(2,(e,t)=>e._tag===`Right`?e:t(e.value)),x=()=>e=>e._tag===`Left`?u(e.value):d(e.value),S=n(3,(e,t,n)=>e._tag===`Left`||t(e.value)?e:d(n(e.value))),C=e=>{if(Array.isArray(e)){let t=[];for(let n of e){if(n._tag===`Left`)return n;t.push(n.value)}return u(t)}let t={};for(let n in e){let r=e[n];if(r._tag===`Left`)return r;t[n]=r.value}return u(t)},w=n(2,(e,t)=>e._tag===`Right`?e.value:t),T=n(2,(e,t)=>e._tag===`Right`?e.value:t(e.value)),E=n(2,(e,t)=>e._tag===`Right`?t.Right(e.value):t.Left(e.value)),D=e=>e._tag===`Ok`?u(e.value):d(e.error),O=e=>e._tag===`Right`?a(e.value):o(e.value),k=(e,t)=>e._tag===`Some`?u(e.value):d(t()),A=e=>e._tag===`Right`?s(e.value):c(),j=(e,t)=>e==null?d(t()):u(e),M=(e,t,n)=>t(e)?u(e):d(n(e));export{l as t};
|
|
2
|
+
//# sourceMappingURL=either-BMLPfvMl.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"either-BMLPfvMl.mjs","names":["mapped","Result.ok","Result.err","Option.some","Option.none"],"sources":["../src/either/either.ts"],"sourcesContent":["/**\n * Biased disjoint union primitives for modeling two valid branches (`Left` / `Right`).\n *\n * **Mental model**\n * - `Either<L, R>` represents two meaningful outcomes.\n * - This module is right-biased for `map` / `flatMap`.\n *\n * **Common tasks**\n * - Construct with `Either.left` and `Either.right`.\n * - Transform with `Either.map`, `Either.mapLeft`, `Either.bimap`.\n * - Handle with `Either.match`, `Either.unwrapOr`, and conversions.\n *\n * **Gotchas**\n * - `Either.left` does not short-circuit in `Fx.gen`.\n * - Use `Result` when the left side should model failure semantics.\n *\n * **Quickstart**\n *\n * @example\n * ```ts\n * import { Either } from \"@nicolastoulemont/std\"\n *\n * const value = Either.right(2)\n * const next = Either.map(value, (n) => n + 1)\n * ```\n *\n * @module\n */\nimport { FxTypeId } from \"../fx/fx.types\"\nimport { Option } from \"../option\"\nimport type { Option as OptionType } from \"../option/option.types\"\nimport { Result } from \"../result\"\nimport type { Result as ResultType } from \"../result/result.types\"\nimport { dual } from \"../shared/dual\"\nimport { isPromise } from \"../shared/is-promise\"\nimport { pipeMethod } from \"../shared/pipeable\"\nimport type {\n Either as EitherType,\n EitherAll,\n EitherBimap,\n EitherFilter,\n EitherFlatMap,\n EitherMap,\n EitherMapLeft,\n EitherMatch,\n EitherOrElse,\n EitherTap,\n EitherTapLeft,\n EitherUnwrapOr,\n EitherUnwrapOrElse,\n} from \"./either.types\"\n\n/**\n * Re-exported `Either` type.\n *\n * @example\n * ```ts\n * import type { Either } from \"@nicolastoulemont/std\"\n *\n * type Example = Either.Either<unknown, unknown>\n * ```\n *\n * @category Re-exports\n */\nexport type Either<L, R> = EitherType<L, R>\n\n/* oxlint-disable no-unsafe-type-assertion -- Either constructors encode Fx marker channels and left/right union normalization through intentional assertions. */\n\n// ============================================================================\n// Constructors\n// ============================================================================\n\n/**\n * Create a right Either value (success/preferred path).\n *\n * By convention, right represents the correct/preferred outcome.\n * In Fx.gen(), this returns the value without short-circuiting.\n *\n * @param value - The right value\n * @returns An Either in the right state\n *\n * @example\n * ```ts\n * import { Either } from \"@nicolastoulemont/std\"\n *\n * const value = Either.right(42)\n * // => { _tag: \"Right\", value: 42 }\n * ```\n *\n * @category Constructors\n */\nexport const right = <R, L = never>(value: R): EitherType<L, R> => ({\n _tag: \"Right\",\n value,\n [FxTypeId]: {\n _A: () => value as L | R,\n _E: () => undefined as never,\n _R: () => undefined as never,\n },\n pipe: pipeMethod,\n // oxlint-disable-next-line require-yield\n *[Symbol.iterator](): Generator<never, R, unknown> {\n return value\n },\n})\n\n/**\n * Create a left Either value (alternative path).\n *\n * By convention, left represents the alternative outcome.\n * Unlike Result's err(), left doesn't imply an error - it's a valid value.\n *\n * In Fx.gen(), left returns its value without short-circuiting.\n * This is the key difference from Result.err() which short-circuits.\n *\n * @param value - The left value\n * @returns An Either in the left state\n *\n * @example\n * ```ts\n * import { Either } from \"@nicolastoulemont/std\"\n *\n * const value = Either.left(\"missing\")\n * // => { _tag: \"Left\", value: \"missing\" }\n * ```\n *\n * @category Constructors\n */\nexport const left = <L, R = never>(value: L): EitherType<L, R> => ({\n _tag: \"Left\",\n value,\n [FxTypeId]: {\n _A: () => value as L | R,\n _E: () => undefined as never,\n _R: () => undefined as never,\n },\n pipe: pipeMethod,\n // oxlint-disable-next-line require-yield\n *[Symbol.iterator](): Generator<never, L, unknown> {\n return value\n },\n})\n\n// ============================================================================\n// Type Guards\n// ============================================================================\n\n/**\n * Type guard to check if an Either is in the right state.\n *\n * @param either - The Either to check\n * @returns True if right, false if left (with type narrowing)\n *\n * @example\n * ```ts\n * import { Either } from \"@nicolastoulemont/std\"\n *\n * const isRight = Either.isRight(Either.right(1))\n * // => true\n * ```\n *\n * @category Guards\n */\nexport const isRight = <L, R>(either: EitherType<L, R>): either is Extract<EitherType<L, R>, { _tag: \"Right\" }> =>\n either._tag === \"Right\"\n\n/**\n * isLeft utility.\n *\n * @example\n * ```ts\n * import { Either } from \"@nicolastoulemont/std\"\n *\n * const isLeft = Either.isLeft(Either.left(\"missing\"))\n * // => true\n * ```\n *\n * @category Guards\n */\nexport const isLeft = <L, R>(either: EitherType<L, R>): either is Extract<EitherType<L, R>, { _tag: \"Left\" }> =>\n either._tag === \"Left\"\n\n// ============================================================================\n// Right-biased Transformations\n// ============================================================================\n\n/**\n * Transform the right value of an Either.\n * Left values pass through unchanged.\n *\n * Supports both data-first and data-last calling styles:\n * - Data-first: `map(either, fn)`\n * - Data-last: `pipe(either, map(fn))`\n *\n * Supports async functions.\n *\n * @param fn - Transformation function for right values\n * @returns A curried function that transforms an Either\n *\n * @example\n * ```ts\n * import { Either } from \"@nicolastoulemont/std\"\n *\n * const input = Either.right(2)\n * const dataFirst = Either.map(input, (n) => n + 1)\n * // => { _tag: \"Right\", value: 3 }\n *\n * const dataLast = Either.map((n: number) => n + 1)(input)\n * // => { _tag: \"Right\", value: 3 }\n * ```\n *\n * @category Mapping\n */\n/* oxlint-disable no-explicit-any, no-unsafe-return, no-unsafe-type-assertion -- Required for overloaded return types in curried functions */\nexport const map: EitherMap = dual(2, (either: EitherType<unknown, unknown>, fn: (value: unknown) => unknown) => {\n if (either._tag === \"Left\") return either as any\n const mapped = fn(either.value)\n if (isPromise(mapped)) {\n return Promise.resolve(mapped).then(right) as any\n }\n return right(mapped) as any\n})\n/* oxlint-enable no-explicit-any, no-unsafe-return, no-unsafe-type-assertion */\n\n/**\n * Transform the left value of an Either.\n * Right values pass through unchanged.\n *\n * Supports both data-first and data-last calling styles:\n * - Data-first: `mapLeft(either, fn)`\n * - Data-last: `pipe(either, mapLeft(fn))`\n *\n * Supports async functions.\n *\n * @param fn - Transformation function for left values\n * @returns A curried function that transforms an Either\n *\n * @example\n * ```ts\n * import { Either } from \"@nicolastoulemont/std\"\n *\n * const input = Either.left(\"missing\")\n * const dataFirst = Either.mapLeft(input, (msg) => msg.toUpperCase())\n * // => { _tag: \"Left\", value: \"MISSING\" }\n *\n * const dataLast = Either.mapLeft((msg: string) => msg.toUpperCase())(input)\n * // => { _tag: \"Left\", value: \"MISSING\" }\n * ```\n *\n * @category Mapping\n */\n/* oxlint-disable no-explicit-any, no-unsafe-return, no-unsafe-type-assertion -- Required for overloaded return types in curried functions */\nexport const mapLeft: EitherMapLeft = dual(\n 2,\n (either: EitherType<unknown, unknown>, fn: (value: unknown) => unknown) => {\n if (either._tag === \"Right\") return either as any\n const mapped = fn(either.value)\n if (isPromise(mapped)) {\n return Promise.resolve(mapped).then(left) as any\n }\n return left(mapped) as any\n },\n)\n/* oxlint-enable no-explicit-any, no-unsafe-return, no-unsafe-type-assertion */\n/**\n * Transform both sides of an Either simultaneously.\n * Unique to Either - not available in Result/Option.\n *\n * Supports both data-first and data-last calling styles:\n * - Data-first: `bimap(either, fnLeft, fnRight)`\n * - Data-last: `pipe(either, bimap(fnLeft, fnRight))`\n *\n * Supports async functions.\n *\n * @param fnLeft - Transformation function for left values\n * @param fnRight - Transformation function for right values\n * @returns A curried function that transforms an Either\n *\n * @example\n * ```ts\n * import { Either } from \"@nicolastoulemont/std\"\n *\n * const input = Either.left(\"missing\")\n * const dataFirst = Either.bimap(input, (left) => left.toUpperCase(), (right: number) => right + 1)\n * // => { _tag: \"Left\", value: \"MISSING\" }\n *\n * const dataLast = Either.bimap((left: string) => left.toUpperCase(), (right: number) => right + 1)(input)\n * // => { _tag: \"Left\", value: \"MISSING\" }\n * ```\n *\n * @category Mapping\n */\n/* oxlint-disable no-explicit-any, no-unsafe-return, no-unsafe-type-assertion -- Required for overloaded return types in curried functions */\nexport const bimap: EitherBimap = dual(\n 3,\n (either: EitherType<unknown, unknown>, fnLeft: (value: unknown) => unknown, fnRight: (value: unknown) => unknown) => {\n if (either._tag === \"Right\") {\n const mapped = fnRight(either.value)\n if (isPromise(mapped)) {\n return Promise.resolve(mapped).then(right) as any\n }\n return right(mapped) as any\n }\n const mapped = fnLeft(either.value)\n if (isPromise(mapped)) {\n return Promise.resolve(mapped).then(left) as any\n }\n return left(mapped) as any\n },\n)\n/* oxlint-enable no-explicit-any, no-unsafe-return, no-unsafe-type-assertion */\n/**\n * Chain operations that return Either.\n * Left values short-circuit the chain.\n *\n * Supports both data-first and data-last calling styles:\n * - Data-first: `flatMap(either, fn)`\n * - Data-last: `pipe(either, flatMap(fn))`\n *\n * Supports async functions. Combines left error unions.\n *\n * @param fn - Function that returns an Either\n * @returns A curried function that chains Eithers\n *\n * @example\n * ```ts\n * import { Either } from \"@nicolastoulemont/std\"\n *\n * const input = Either.right(2)\n * const dataFirst = Either.flatMap(input, (n) => Either.right(n + 1))\n * // => { _tag: \"Right\", value: 3 }\n *\n * const dataLast = Either.flatMap((n: number) => Either.right(n + 1))(input)\n * // => { _tag: \"Right\", value: 3 }\n * ```\n *\n * @category Sequencing\n */\n/* oxlint-disable no-explicit-any, no-unsafe-return, no-unsafe-type-assertion -- Required for overloaded return types in curried functions */\nexport const flatMap: EitherFlatMap = dual(\n 2,\n (either: EitherType<unknown, unknown>, fn: (value: unknown) => unknown) => {\n if (either._tag === \"Left\") return either as any\n const result = fn(either.value)\n return result as any\n },\n)\n/* oxlint-enable no-explicit-any, no-unsafe-return, no-unsafe-type-assertion */\n/**\n * Execute a side effect on right values without modifying the Either.\n * Left values pass through unchanged.\n *\n * Supports both data-first and data-last calling styles:\n * - Data-first: `tap(either, fn)`\n * - Data-last: `pipe(either, tap(fn))`\n *\n * Supports async functions.\n *\n * @param fn - Side effect function for right values\n * @returns A curried function that executes side effects\n *\n * @example\n * ```ts\n * import { Either } from \"@nicolastoulemont/std\"\n *\n * let seen = 0\n * const input = Either.right(2)\n * const dataFirst = Either.tap(input, (n) => {\n * seen = n\n * })\n * // => { _tag: \"Right\", value: 2 }\n *\n * const dataLast = Either.tap((n: number) => {\n * seen = n\n * })(input)\n * // => { _tag: \"Right\", value: 2 }\n * ```\n *\n * @category Sequencing\n */\n/* oxlint-disable no-explicit-any, no-unsafe-return, no-unsafe-type-assertion -- Required for overloaded return types in curried functions */\nexport const tap: EitherTap = dual(2, (either: EitherType<unknown, unknown>, fn: (value: unknown) => unknown) => {\n if (either._tag === \"Left\") return either as any\n const result = fn(either.value)\n if (isPromise(result)) {\n return Promise.resolve(result).then(() => either) as any\n }\n return either as any\n})\n/* oxlint-enable no-explicit-any, no-unsafe-return, no-unsafe-type-assertion */\n/**\n * Execute a side effect on left values without modifying the Either.\n * Right values pass through unchanged.\n *\n * Supports both data-first and data-last calling styles:\n * - Data-first: `tapLeft(either, fn)`\n * - Data-last: `pipe(either, tapLeft(fn))`\n *\n * Supports async functions.\n *\n * @param fn - Side effect function for left values\n * @returns A curried function that executes side effects\n *\n * @example\n * ```ts\n * import { Either } from \"@nicolastoulemont/std\"\n *\n * let seen = \"\"\n * const input = Either.left(\"missing\")\n * const dataFirst = Either.tapLeft(input, (msg) => {\n * seen = msg\n * })\n * // => { _tag: \"Left\", value: \"missing\" }\n *\n * const dataLast = Either.tapLeft((msg: string) => {\n * seen = msg\n * })(input)\n * // => { _tag: \"Left\", value: \"missing\" }\n * ```\n *\n * @category Sequencing\n */\n/* oxlint-disable no-explicit-any, no-unsafe-return, no-unsafe-type-assertion -- Required for overloaded return types in curried functions */\nexport const tapLeft: EitherTapLeft = dual(\n 2,\n (either: EitherType<unknown, unknown>, fn: (value: unknown) => unknown) => {\n if (either._tag === \"Right\") return either as any\n const result = fn(either.value)\n if (isPromise(result)) {\n return Promise.resolve(result).then(() => either) as any\n }\n return either as any\n },\n)\n/* oxlint-enable no-explicit-any, no-unsafe-return, no-unsafe-type-assertion */\n// ============================================================================\n// Recovery/Fallback\n// ============================================================================\n\n/**\n * Recover from a left value by providing an alternative Either.\n * Right values pass through unchanged.\n *\n * Supports both data-first and data-last calling styles:\n * - Data-first: `orElse(either, fn)`\n * - Data-last: `pipe(either, orElse(fn))`\n *\n * Supports async functions. Combines right value unions.\n *\n * @param fn - Function that returns an alternative Either\n * @returns A curried function that recovers from left\n *\n * @example\n * ```ts\n * import { Either } from \"@nicolastoulemont/std\"\n *\n * const input = Either.left(\"missing\")\n * const dataFirst = Either.orElse(input, () => Either.right(0))\n * // => { _tag: \"Right\", value: 0 }\n *\n * const dataLast = Either.orElse(() => Either.right(0))(input)\n * // => { _tag: \"Right\", value: 0 }\n * ```\n *\n * @category Error Handling\n */\n/* oxlint-disable no-explicit-any, no-unsafe-return, no-unsafe-type-assertion -- Required for overloaded return types in curried functions */\nexport const orElse: EitherOrElse = dual(2, (either: EitherType<unknown, unknown>, fn: (value: unknown) => unknown) => {\n if (either._tag === \"Right\") return either as any\n const result = fn(either.value)\n return result as any\n})\n/* oxlint-enable no-explicit-any, no-unsafe-return, no-unsafe-type-assertion */\n/**\n * Swap left and right values.\n * Unique to Either - not available in Result/Option.\n *\n * Curried for use with pipe().\n *\n * @returns A curried function that swaps left and right\n *\n * @example\n * ```ts\n * import { Either } from \"@nicolastoulemont/std\"\n *\n * const swap = Either.swap<string, number>()\n * const value = swap(Either.left(\"missing\"))\n * // => { _tag: \"Right\", value: \"missing\" }\n * ```\n *\n * @category Conversions\n */\nexport const swap =\n <L, R>() =>\n (either: EitherType<L, R>): EitherType<R, L> =>\n either._tag === \"Left\" ? right(either.value) : left(either.value)\n\n// ============================================================================\n// Filtering\n// ============================================================================\n\n/**\n * Filter right values based on a predicate.\n * Failed predicates convert to left with onFail callback.\n * Left values pass through unchanged.\n *\n * Supports both data-first and data-last calling styles:\n * - Data-first: `filter(either, predicate, onFail)`\n * - Data-last: `pipe(either, filter(predicate, onFail))`\n *\n * @param predicate - Function to test right values\n * @param onFail - Function to produce left value on failure\n * @returns A curried function that filters an Either\n *\n * @example\n * ```ts\n * import { Either } from \"@nicolastoulemont/std\"\n *\n * const input = Either.right(3)\n * const dataFirst = Either.filter(input, (n) => n > 0, (n) => `${n} must be positive`)\n * // => { _tag: \"Right\", value: 3 }\n *\n * const dataLast = Either.filter((n: number) => n > 0, (n) => `${n} must be positive`)(input)\n * // => { _tag: \"Right\", value: 3 }\n * ```\n *\n * @category Filtering\n */\n/* oxlint-disable no-explicit-any, no-unsafe-return, no-unsafe-type-assertion -- Required for overloaded return types in curried functions */\nexport const filter: EitherFilter = dual(\n 3,\n (\n either: EitherType<unknown, unknown>,\n predicate: (value: unknown) => boolean,\n onFail: (value: unknown) => unknown,\n ) => {\n if (either._tag === \"Left\") return either as any\n return predicate(either.value) ? (either as any) : left(onFail(either.value))\n },\n)\n/* oxlint-enable no-explicit-any, no-unsafe-return, no-unsafe-type-assertion */\n// ============================================================================\n// Combinators\n// ============================================================================\n\n/**\n * Combine multiple Eithers into a single Either.\n * Short-circuits on the first left value.\n *\n * Supports both array and object inputs with full type preservation.\n * For arrays of 1-6 elements, tuple types are inferred automatically.\n * For longer arrays, use `as const` to preserve tuple structure.\n *\n * @param eithers - Array or object of Eithers to combine\n * @returns Either with all right values or first left\n *\n * @example\n * ```ts\n * import { Either } from \"@nicolastoulemont/std\"\n *\n * const combined = Either.all([Either.right(1), Either.right(2)] as const)\n * // => { _tag: \"Right\", value: [1, 2] }\n * ```\n *\n * @category Combining\n */\n/* oxlint-disable no-explicit-any, no-unsafe-return, no-unsafe-member-access, strict-boolean-expressions, no-unsafe-assignment -- Required for handling union types in overloaded function */\nexport const all: EitherAll = (eithers: any): any => {\n // Array case\n if (Array.isArray(eithers)) {\n const values: unknown[] = []\n for (const either of eithers) {\n if (either._tag === \"Left\") return either\n values.push(either.value)\n }\n return right(values)\n }\n\n // Object case\n const result: Record<string, unknown> = {}\n for (const key in eithers) {\n const either = eithers[key]\n if (either._tag === \"Left\") return either\n result[key] = either.value\n }\n return right(result)\n}\n/* oxlint-enable no-explicit-any, no-unsafe-return, no-unsafe-member-access, strict-boolean-expressions, no-unsafe-assignment */\n// ============================================================================\n// Extraction\n// ============================================================================\n\n/**\n * Extract the right value or return a default.\n *\n * Supports both data-first and data-last calling styles:\n * - Data-first: `unwrapOr(either, defaultValue)`\n * - Data-last: `pipe(either, unwrapOr(defaultValue))`\n *\n * Uses NoInfer to prevent type inference from the default value.\n *\n * @param defaultValue - Value to return if Either is left\n * @returns A curried function that extracts the value\n *\n * @example\n * ```ts\n * import { Either } from \"@nicolastoulemont/std\"\n *\n * const input = Either.left(\"missing\") as Either.Either<string, number>\n * const dataFirst = Either.unwrapOr(input, 0)\n * // => 0\n *\n * const dataLast = Either.unwrapOr(0)(input)\n * // => 0\n * ```\n *\n * @category Getters\n */\nexport const unwrapOr: EitherUnwrapOr = dual(\n 2,\n <L, R>(either: EitherType<L, R>, defaultValue: NoInfer<R>): R =>\n either._tag === \"Right\" ? either.value : defaultValue,\n)\n\n/**\n * Extract the right value or compute one from the left value.\n *\n * Supports both data-first and data-last calling styles:\n * - Data-first: `unwrapOrElse(either, fn)`\n * - Data-last: `pipe(either, unwrapOrElse(fn))`\n *\n * @param fn - Function to compute default from left value\n * @returns A curried function that extracts the value\n *\n * @example\n * ```ts\n * import { Either } from \"@nicolastoulemont/std\"\n *\n * const input = Either.left(\"missing\") as Either.Either<string, number>\n * const dataFirst = Either.unwrapOrElse(input, () => 0)\n * // => 0\n *\n * const dataLast = Either.unwrapOrElse(() => 0)(input)\n * // => 0\n * ```\n *\n * @category Getters\n */\nexport const unwrapOrElse: EitherUnwrapOrElse = dual(\n 2,\n <L, R>(either: EitherType<L, R>, fn: (left: L) => R): R =>\n either._tag === \"Right\" ? either.value : fn(either.value),\n)\n\n/**\n * Pattern match on an Either with handlers for both cases.\n *\n * Supports both data-first and data-last calling styles:\n * - Data-first: `match(either, { Left: ..., Right: ... })`\n * - Data-last: `pipe(either, match({ Left: ..., Right: ... }))`\n *\n * @param handlers - Object with left and right handler functions\n * @returns A curried function that pattern matches\n *\n * @example\n * ```ts\n * import { Either } from \"@nicolastoulemont/std\"\n *\n * const input = Either.right(2) as Either.Either<string, number>\n * const dataFirst = Either.match(input, {\n * Left: (left) => `error:${left}` ,\n * Right: (right) => `ok:${right}` ,\n * })\n * // => \"ok:2\"\n *\n * const dataLast = Either.match({\n * Left: (left: string) => `error:${left}` ,\n * Right: (right: number) => `ok:${right}` ,\n * })(input)\n * // => \"ok:2\"\n * ```\n *\n * @category Pattern Matching\n */\nexport const match: EitherMatch = dual(\n 2,\n <L, R, U>(either: EitherType<L, R>, handlers: { Left: (value: L) => U; Right: (value: R) => U }): U =>\n either._tag === \"Right\" ? handlers.Right(either.value) : handlers.Left(either.value),\n)\n\n// ============================================================================\n// Conversions\n// ============================================================================\n\n/**\n * Convert a Result to an Either.\n * Result's ok becomes right, err becomes left.\n *\n * @param result - The Result to convert\n * @returns An Either with the same semantics\n *\n * @example\n * ```ts\n * import { Either } from \"@nicolastoulemont/std\"\n *\n * import { Result } from \"@nicolastoulemont/std\"\n *\n * const value = Either.fromResult(Result.ok(1))\n * // => { _tag: \"Right\", value: 1 }\n * ```\n *\n * @category Conversions\n */\nexport const fromResult = <R, E>(result: ResultType<R, E>): EitherType<E, R> =>\n result._tag === \"Ok\" ? right(result.value) : left(result.error)\n\n/**\n * Convert an Either to a Result.\n * Either's right becomes ok, left becomes err.\n *\n * Curried for use with pipe().\n *\n * @param either - The Either to convert\n * @returns A Result with error semantics\n *\n * @example\n * ```ts\n * import { Either } from \"@nicolastoulemont/std\"\n *\n * const value = Either.toResult(Either.left(\"missing\"))\n * // => { _tag: \"Err\", error: \"missing\" }\n * ```\n *\n * @category Conversions\n */\nexport const toResult = <L, R>(either: EitherType<L, R>): ResultType<R, L> =>\n either._tag === \"Right\" ? Result.ok(either.value) : Result.err(either.value)\n\n/**\n * Convert an Option to an Either.\n * Option's some becomes right, none becomes left with onNone callback.\n *\n * @param option - The Option to convert\n * @param onNone - Function to produce left value for none\n * @returns An Either\n *\n * @example\n * ```ts\n * import { Either } from \"@nicolastoulemont/std\"\n *\n * import { Option } from \"@nicolastoulemont/std\"\n *\n * const value = Either.fromOption(Option.some(1), () => \"missing\")\n * // => { _tag: \"Right\", value: 1 }\n * ```\n *\n * @category Conversions\n */\nexport const fromOption = <R, L>(option: OptionType<R>, onNone: () => L): EitherType<L, R> =>\n option._tag === \"Some\" ? right(option.value) : left(onNone())\n\n/**\n * Convert an Either to an Option.\n * Either's right becomes some, left is discarded.\n *\n * Curried for use with pipe().\n *\n * @param either - The Either to convert\n * @returns An Option (left value is discarded)\n *\n * @example\n * ```ts\n * import { Either } from \"@nicolastoulemont/std\"\n *\n * const value = Either.toOption(Either.left(\"missing\"))\n * // => { _tag: \"None\" }\n * ```\n *\n * @category Conversions\n */\nexport const toOption = <L, R>(either: EitherType<L, R>): OptionType<R> =>\n either._tag === \"Right\" ? Option.some(either.value) : Option.none<R>()\n\n/**\n * Convert a nullable value to an Either.\n * null/undefined becomes left with onNull callback, otherwise right.\n *\n * @param value - The nullable value\n * @param onNull - Function to produce left value for null/undefined\n * @returns An Either\n *\n * @example\n * ```ts\n * import { Either } from \"@nicolastoulemont/std\"\n *\n * const value = Either.fromNullable(\"Ada\", () => \"missing\")\n * // => { _tag: \"Right\", value: \"Ada\" }\n * ```\n *\n * @category Conversions\n */\nexport const fromNullable = <R, L>(value: R | null | undefined, onNull: () => L): EitherType<L, R> =>\n value === null || value === undefined ? left(onNull()) : right(value)\n\n/**\n * Create an Either from a predicate.\n * Predicate success becomes right, failure becomes left with onFail callback.\n *\n * @param value - The value to test\n * @param predicate - Function to test the value\n * @param onFail - Function to produce left value on failure\n * @returns An Either\n *\n * @example\n * ```ts\n * import { Either } from \"@nicolastoulemont/std\"\n *\n * const value = Either.fromPredicate(3, (n) => n > 0, (n) => `${n} must be positive`)\n * // => { _tag: \"Right\", value: 3 }\n * ```\n *\n * @category Constructors\n */\nexport const fromPredicate = <R, L>(\n value: R,\n predicate: (value: R) => boolean,\n onFail: (value: R) => L,\n): EitherType<L, R> => (predicate(value) ? right(value) : left(onFail(value)))\n\n/* oxlint-enable no-unsafe-type-assertion */\n"],"mappings":"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"}
|
package/dist/fx/index.d.mts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { t as fx_d_exports } from "../index-
|
|
1
|
+
import { t as fx_d_exports } from "../index-BNQ9xSAz.mjs";
|
|
2
2
|
export { fx_d_exports as Fx };
|
package/dist/fx/index.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{t as e}from"../fx-
|
|
1
|
+
import{t as e}from"../fx-K-a9Smhn.mjs";export{e as Fx};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{t as e}from"./chunk-C934ptG5.mjs";import{n as t,t as n}from"./fx.types-Bg-Mmdm5.mjs";import{t as r}from"./dual-CZhzZslG.mjs";import{n as i,r as a,t as o}from"./result-BEzV0DYC.mjs";import{t as s}from"./option.types-
|
|
2
|
-
//# sourceMappingURL=fx-
|
|
1
|
+
import{t as e}from"./chunk-C934ptG5.mjs";import{n as t,t as n}from"./fx.types-Bg-Mmdm5.mjs";import{t as r}from"./dual-CZhzZslG.mjs";import{n as i,r as a,t as o}from"./result-BEzV0DYC.mjs";import{t as s}from"./option.types-D1mm0zUb.mjs";import{t as c}from"./option-Tfbo4wty.mjs";import{t as l}from"./service-resolution-C19smeaO.mjs";import{i as u,n as d,r as f,t as p}from"./queue-Sg6KJerl.mjs";import{n as m,r as h,t as g}from"./fx.runtime-DclEDyjY.mjs";var _=class extends Error{_tag=`TypedFailure`;constructor(e){super(`TypedFailure`),this.error=e,this.name=`TypedFailure`}};const v=e=>e instanceof _,y=e=>typeof e==`object`&&!!e&&`_tag`in e&&e._tag===`Err`&&`error`in e,b=e=>e instanceof s?e:y(e)?e.error:e,x=e=>e!=null&&typeof e[Symbol.iterator]==`function`,S=e=>new f({reason:e.reason}),C=e=>e instanceof Error?e:Error(`Fx.forEach defect was not an Error`,{cause:e}),w=()=>{throw Error(`Unreachable: Fx type marker should never execute at runtime`)},T=()=>w,E=async(e,t,n)=>{if(e._tag===`AsyncFx`){let r=e[Symbol.asyncIterator](),i=await r.next();for(;i.done!==!0;){if(t.aborted)throw S(t);let e=i.value;if(l(e)!==void 0){let a=await n(e,t);i=await r.next(a);continue}throw new _(b(e))}return i.value}let r=e[Symbol.iterator](),i=r.next();for(;i.done!==!0;){if(t.aborted)throw S(t);let e=i.value;if(l(e)!==void 0){let a=await n(e,t);i=r.next(a);continue}throw new _(b(e))}return i.value},D=r(e=>x(e[0])&&typeof e[1]==`function`,(e,t,r)=>{let i=[...e],a=r?.discard===!0;return{_tag:`AsyncFx`,[n]:{_A:T(),_E:T(),_R:T()},async*[Symbol.asyncIterator](){if(i.length===0)return a?void 0:[];let e=u({concurrency:r?.concurrency??`unbounded`}),n=a?void 0:[],o=i.length,s,c,l=!1,m=[],h=new Set,g=()=>{for(let e of h)e();h.clear()},_=()=>new Promise(e=>{h.add(e)}),y=(e,t)=>t.aborted?Promise.reject(S(t)):new Promise((n,r)=>{let i={yielded:e,signal:t,resolve:e=>{t.removeEventListener(`abort`,a),n(e)},reject:e=>{t.removeEventListener(`abort`,a),r(e)}},a=()=>{let e=m.indexOf(i);e!==-1&&m.splice(e,1),r(S(t))};t.addEventListener(`abort`,a,{once:!0}),m.push(i),g()}),b=e=>{let t=m.splice(0);for(let n of t)n.reject(e)},x=t=>{l||(l=!0,e.shutdown({mode:`abort`,reason:t}).catch(()=>{}))},w=e=>{if(v(e)){s===void 0&&c===void 0&&(s=e.error,x(e.error));return}if(!((e instanceof p||e instanceof f||e instanceof d)&&(s!==void 0||c!==void 0))&&c===void 0&&s===void 0){let t=C(e);c=t,x(t)}},T=()=>{--o,g()};for(let[r,a]of i.entries())e.enqueue(async({signal:e})=>{let i=await E(t(a,r),e,y);n!==void 0&&(n[r]=i)}).catch(w).finally(T);for(;;){if(c!==void 0)throw b(c),Error(`Fx.forEach defect`,{cause:c});if(s!==void 0)throw b(new p({reason:s})),yield s,Error(`Unreachable: Fx runtime short-circuits on first failure`);let e=m.shift();if(e!==void 0){if(e.signal.aborted){e.reject(S(e.signal));continue}try{let t=yield e.yielded;e.resolve(t)}catch(t){e.reject(C(t))}continue}if(o===0)break;await _()}return a?void 0:n}}});var O=e({Exit:()=>h,FxTypeId:()=>n,err:()=>X,fn:()=>G,forEach:()=>J,gen:()=>W,isServiceRequest:()=>t,match:()=>$,ok:()=>Y,option:()=>Z,retry:()=>q,run:()=>K,try:()=>Q});function k(e){return e._tag===`AsyncFx`?g(e):m(e)}const A=e=>new Promise(t=>{setTimeout(t,e)}),j=async e=>{e<=0||await A(e)},M=e=>{typeof e.return==`function`&&e.return(void 0)},N=async e=>{typeof e.return==`function`&&await e.return(void 0)},P=(e,t)=>({_tag:`SyncFx`,[n]:{_A:()=>void 0,_E:()=>void 0,_R:()=>void 0},*[Symbol.iterator](){let n=0;attemptLoop:for(;;){let r=e[Symbol.iterator](),i=r.next();for(;i.done!==!0;){let e=i.value;if(l(e)!==void 0){let t=yield e;i=r.next(t);continue}if(n+=1,n<=t.maxRetries){M(r);continue attemptLoop}yield e;return}return i.value}}}),F=(e,t)=>({_tag:`AsyncFx`,[n]:{_A:()=>void 0,_E:()=>void 0,_R:()=>void 0},async*[Symbol.asyncIterator](){let n=0;attemptLoop:for(;;){if(e._tag===`AsyncFx`){let r=e[Symbol.asyncIterator](),i=await r.next();for(;i.done!==!0;){let e=i.value;if(l(e)!==void 0){let t=yield e;i=await r.next(t);continue}if(n+=1,n<=t.maxRetries){await j(t.delayForAttempt(n)),await N(r);continue attemptLoop}return yield e,void 0}return i.value}let r=e[Symbol.iterator](),i=r.next();for(;i.done!==!0;){let e=i.value;if(l(e)!==void 0){let t=yield e;i=r.next(t);continue}if(n+=1,n<=t.maxRetries){await j(t.delayForAttempt(n)),await N(r);continue attemptLoop}return yield e,void 0}return i.value}}}),I=r(2,(e,t)=>e._tag===`AsyncFx`||!t._sync?F(e,t):P(e,t));function L(e){if(e.length>0)return(...t)=>L(()=>e(...t));let t=e();return Symbol.asyncIterator in t?{_tag:`AsyncFx`,[n]:{_A:()=>void 0,_E:()=>void 0,_R:()=>void 0},async*[Symbol.asyncIterator](){let t=e(),n=await t.next();for(;n.done!==!0;){let e=yield n.value;n=await t.next(e)}return n.value}}:{_tag:`SyncFx`,[n]:{_A:()=>void 0,_E:()=>void 0,_R:()=>void 0},*[Symbol.iterator](){let t=e(),n=t.next();for(;n.done!==!0;){let e=yield n.value;n=t.next(e)}return n.value}}}function R(e,t){let n=L(e);return k(t?(n._tag,t(n)):n)}const z=a,B=o,V=i,H=c,U=r(2,(e,t)=>t[e._tag](e)),W=L,G=R,K=k,q=I,J=D,Y=z,X=B,Z=H,Q=V,$=U;export{O as t};
|
|
2
|
+
//# sourceMappingURL=fx-K-a9Smhn.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fx-K-a9Smhn.mjs","names":["gen","result","makeQueue","gen","result","resultOk","resultErr","resultTry","optionFromNullable"],"sources":["../src/fx/foreach.ts","../src/fx/fx.ts"],"sourcesContent":["import { NoSuchElementError } from \"../option/option.types\"\nimport { make as makeQueue, QueueAbortedError, QueueClosedError, QueueTaskAbortedError } from \"../queue/queue\"\nimport type { Concurrency } from \"../queue/queue.types\"\nimport { asServiceRequest } from \"../service/service-resolution\"\nimport { dual } from \"../shared/dual\"\nimport { FxTypeId } from \"./fx.types\"\nimport type { AsyncFx, FxError, FxRequirements, FxValue, FxYield, RunnableFx } from \"./fx.types\"\n\n/* oxlint-disable no-await-in-loop -- Fx.forEach coordinates child iterators and queue scheduling sequentially at specific yield points. */\n\ntype ForEachValue<Discard extends boolean, B> = Discard extends true ? void : Array<B>\n\ntype FxForEachOptions<Discard extends boolean = false> = {\n readonly concurrency?: Concurrency\n readonly discard?: Discard\n}\n\ntype ForEachFx<\n F extends (a: never, i: number) => RunnableFx<unknown, unknown, unknown>,\n Discard extends boolean,\n> = AsyncFx<ForEachValue<Discard, FxValue<ReturnType<F>>>, FxError<ReturnType<F>>, FxRequirements<ReturnType<F>>>\n\ntype FxForEach = {\n <A, F extends (a: A, i: number) => RunnableFx<unknown, unknown, unknown>, const Discard extends boolean = false>(\n self: Iterable<A>,\n f: F,\n options?: FxForEachOptions<Discard>,\n ): ForEachFx<F, Discard>\n <A, F extends (a: A, i: number) => RunnableFx<unknown, unknown, unknown>, const Discard extends boolean = false>(\n f: F,\n options?: FxForEachOptions<Discard>,\n ): (self: Iterable<A>) => ForEachFx<F, Discard>\n}\n\ntype ServiceRequestEntry<E, R> = {\n readonly yielded: FxYield<E, R>\n readonly signal: AbortSignal\n readonly resolve: (value: unknown) => void\n readonly reject: (reason: Error) => void\n}\n\ntype ResultErrShape = {\n readonly _tag: \"Err\"\n readonly error: unknown\n}\n\nclass TypedFailure<E> extends Error {\n readonly _tag = \"TypedFailure\"\n\n constructor(readonly error: E) {\n super(\"TypedFailure\")\n this.name = \"TypedFailure\"\n }\n}\n\nconst isTypedFailure = <E>(value: unknown): value is TypedFailure<E> => value instanceof TypedFailure\n\nconst isResultErr = (value: unknown): value is ResultErrShape =>\n typeof value === \"object\" && value !== null && \"_tag\" in value && value._tag === \"Err\" && \"error\" in value\n\nconst toFailureValue = (yielded: unknown): unknown => {\n if (yielded instanceof NoSuchElementError) {\n return yielded\n }\n\n if (isResultErr(yielded)) {\n return yielded.error\n }\n\n return yielded\n}\n\nconst isIterable = (value: unknown): value is Iterable<unknown> =>\n value !== null &&\n value !== undefined &&\n typeof (value as { [Symbol.iterator]?: unknown })[Symbol.iterator] === \"function\"\n\nconst queueTaskAbortedError = (signal: AbortSignal): QueueTaskAbortedError =>\n new QueueTaskAbortedError({ reason: signal.reason })\n\nconst toError = (reason: unknown): Error =>\n reason instanceof Error ? reason : new Error(\"Fx.forEach defect was not an Error\", { cause: reason })\n\nconst unreachableType = (): never => {\n throw new Error(\"Unreachable: Fx type marker should never execute at runtime\")\n}\n\nconst typeMarker = <A>(): (() => A) => unreachableType\n\nconst runMappedFx = async <B, E, R>(\n fx: RunnableFx<B, E, R>,\n signal: AbortSignal,\n requestService: (yielded: FxYield<E, R>, signal: AbortSignal) => Promise<unknown>,\n): Promise<B> => {\n if (fx._tag === \"AsyncFx\") {\n const gen = fx[Symbol.asyncIterator]()\n let result = await gen.next()\n\n while (result.done !== true) {\n if (signal.aborted) {\n throw queueTaskAbortedError(signal)\n }\n\n const yielded = result.value\n const serviceRequest = asServiceRequest(yielded)\n if (serviceRequest !== undefined) {\n const injected = await requestService(yielded, signal)\n result = await gen.next(injected)\n continue\n }\n\n // oxlint-disable-next-line typescript-eslint/no-unsafe-type-assertion -- failure channel values come from generic E at runtime.\n throw new TypedFailure<E>(toFailureValue(yielded) as E)\n }\n\n return result.value\n }\n\n const gen = fx[Symbol.iterator]()\n let result = gen.next()\n\n while (result.done !== true) {\n if (signal.aborted) {\n throw queueTaskAbortedError(signal)\n }\n\n const yielded = result.value\n const serviceRequest = asServiceRequest(yielded)\n if (serviceRequest !== undefined) {\n const injected = await requestService(yielded, signal)\n result = gen.next(injected)\n continue\n }\n\n // oxlint-disable-next-line typescript-eslint/no-unsafe-type-assertion -- failure channel values come from generic E at runtime.\n throw new TypedFailure<E>(toFailureValue(yielded) as E)\n }\n\n return result.value\n}\n\nconst fxForEach = dual(\n (args) => isIterable(args[0]) && typeof args[1] === \"function\",\n <A, B, E, R>(\n self: Iterable<A>,\n f: (a: A, i: number) => RunnableFx<B, E, R>,\n options?: FxForEachOptions<boolean>,\n ): AsyncFx<Array<B> | void, E, R> => {\n const items = [...self]\n const discard = options?.discard === true\n\n const program: AsyncFx<Array<B> | void, E, R> = {\n _tag: \"AsyncFx\",\n [FxTypeId]: {\n _A: typeMarker<Array<B> | void>(),\n _E: typeMarker<E>(),\n _R: typeMarker<R>(),\n },\n async *[Symbol.asyncIterator](): AsyncGenerator<FxYield<E, R>, Array<B> | void, unknown> {\n if (items.length === 0) {\n return discard ? undefined : []\n }\n\n const queue = makeQueue({ concurrency: options?.concurrency ?? \"unbounded\" })\n const results: Array<B> | undefined = discard ? undefined : []\n\n let remaining = items.length\n let firstFailure: E | undefined\n let firstDefect: Error | undefined\n let queueAborted = false\n\n const serviceRequests: ServiceRequestEntry<E, R>[] = []\n const eventWaiters = new Set<() => void>()\n\n const notifyEvent = () => {\n for (const resolve of eventWaiters) {\n resolve()\n }\n eventWaiters.clear()\n }\n\n const waitForEvent = () =>\n new Promise<void>((resolve) => {\n eventWaiters.add(resolve)\n })\n\n const requestService = (yielded: FxYield<E, R>, signal: AbortSignal): Promise<unknown> => {\n if (signal.aborted) {\n return Promise.reject(queueTaskAbortedError(signal))\n }\n\n return new Promise<unknown>((resolve, reject) => {\n const entry: ServiceRequestEntry<E, R> = {\n yielded,\n signal,\n resolve: (value) => {\n signal.removeEventListener(\"abort\", onAbort)\n resolve(value)\n },\n reject: (reason) => {\n signal.removeEventListener(\"abort\", onAbort)\n reject(reason)\n },\n }\n\n const onAbort = () => {\n const index = serviceRequests.indexOf(entry)\n if (index !== -1) {\n serviceRequests.splice(index, 1)\n }\n reject(queueTaskAbortedError(signal))\n }\n\n signal.addEventListener(\"abort\", onAbort, { once: true })\n serviceRequests.push(entry)\n notifyEvent()\n })\n }\n\n const rejectPendingServiceRequests = (reason: Error) => {\n const pending = serviceRequests.splice(0)\n for (const request of pending) {\n request.reject(reason)\n }\n }\n\n const abortQueue = (reason: unknown) => {\n if (queueAborted) {\n return\n }\n\n queueAborted = true\n void queue.shutdown({ mode: \"abort\", reason }).catch(() => {\n // no-op: fail-fast cleanup should never interrupt parent error handling\n })\n }\n\n const onTaskFailure = (error: unknown) => {\n if (isTypedFailure<E>(error)) {\n if (firstFailure === undefined && firstDefect === undefined) {\n firstFailure = error.error\n abortQueue(error.error)\n }\n return\n }\n\n if (\n (error instanceof QueueAbortedError ||\n error instanceof QueueTaskAbortedError ||\n error instanceof QueueClosedError) &&\n (firstFailure !== undefined || firstDefect !== undefined)\n ) {\n return\n }\n\n if (firstDefect === undefined && firstFailure === undefined) {\n const defect = toError(error)\n firstDefect = defect\n abortQueue(defect)\n }\n }\n\n const onTaskSettled = () => {\n remaining -= 1\n notifyEvent()\n }\n\n for (const [index, item] of items.entries()) {\n void queue\n .enqueue(async ({ signal }) => {\n const value = await runMappedFx(f(item, index), signal, requestService)\n if (results !== undefined) {\n results[index] = value\n }\n })\n .catch(onTaskFailure)\n .finally(onTaskSettled)\n }\n\n while (true) {\n if (firstDefect !== undefined) {\n rejectPendingServiceRequests(firstDefect)\n throw new Error(\"Fx.forEach defect\", { cause: firstDefect })\n }\n\n if (firstFailure !== undefined) {\n rejectPendingServiceRequests(new QueueAbortedError({ reason: firstFailure }))\n yield firstFailure\n throw new Error(\"Unreachable: Fx runtime short-circuits on first failure\")\n }\n\n const request = serviceRequests.shift()\n if (request !== undefined) {\n if (request.signal.aborted) {\n request.reject(queueTaskAbortedError(request.signal))\n continue\n }\n\n try {\n const injected = yield request.yielded\n request.resolve(injected)\n } catch (error) {\n request.reject(toError(error))\n }\n continue\n }\n\n if (remaining === 0) {\n break\n }\n\n await waitForEvent()\n }\n\n return discard ? undefined : results\n },\n }\n\n return program\n },\n) as FxForEach\n\nexport { fxForEach as forEach }\n\n/* oxlint-enable no-await-in-loop */\n","/**\n * Lightweight effect runtime with typed success, error, and requirement channels.\n *\n * **Mental model**\n * - `Fx<A, E, R>` models computations that may fail and require services.\n * - Build with `Fx.gen`, run with `Fx.run`, and compose with `Layer`/`Provide`.\n *\n * **Common tasks**\n * - Create workflows with `Fx.gen`.\n * - Execute with `Fx.run` or `Fx.fn`.\n * - Retry with `Fx.retry` and match outcomes with `Fx.match`.\n *\n * **Gotchas**\n * - Dependencies (`R`) must be provided before execution.\n * - `Fx.run` returns `Exit`, not raw values.\n *\n * **Quickstart**\n *\n * @example\n * ```ts\n * import { Fx } from \"@nicolastoulemont/std\"\n *\n * const program = Fx.gen(function* () {\n * const value = yield* Fx.ok(2)\n * return value + 1\n * })\n * const exit = Fx.run(program)\n * // => { _tag: \"Ok\", value: 3 }\n * ```\n *\n * @module\n */\nimport { fromNullable as optionFromNullable } from \"../option/option\"\nimport { ok as resultOk, err as resultErr, fromTry as resultTry } from \"../result/result\"\nimport type { RetrySchedule, SyncRetrySchedule } from \"../schedule/schedule\"\nimport { asServiceRequest } from \"../service/service-resolution\"\nimport { dual } from \"../shared/dual\"\nimport type { Exit as ExitType } from \"./exit\"\nimport { forEach as fxForEach } from \"./foreach\"\nimport { runSync, runAsync } from \"./fx.runtime\"\nimport { FxTypeId } from \"./fx.types\"\nimport type { RunnableFx, SyncFx, AsyncFx, FxYield, Fx as FxProtocol, FxGenerator, AsyncFxGenerator } from \"./fx.types\"\nexport {\n /**\n * `Exit` utilities namespace for `Fx.run` outcomes.\n *\n * @example\n * ```ts\n * import { Fx } from \"@nicolastoulemont/std\"\n *\n * const exit = Fx.Exit.ok(1)\n * // => { _tag: \"Ok\", value: 1 }\n * ```\n *\n * @category Re-exports\n */\n Exit,\n} from \"./exit\"\nexport {\n /**\n * Type guard for Fx service requests.\n *\n * @example\n * ```ts\n * import { Fx } from \"@nicolastoulemont/std\"\n *\n * const request = { _tag: \"ServiceRequest\", serviceKey: \"Logger\" } as Fx.ServiceRequest<unknown>\n * const isRequest = Fx.isServiceRequest(request)\n * // => true\n * ```\n *\n * @category Guards\n */\n isServiceRequest,\n} from \"./fx.types\"\nexport {\n /**\n * Runtime unique symbol identifying Fx values.\n *\n * @example\n * ```ts\n * import { Fx } from \"@nicolastoulemont/std\"\n *\n * const marker = { [Fx.FxTypeId]: true }\n * // => Object.getOwnPropertySymbols(marker).includes(Fx.FxTypeId)\n * ```\n *\n * @category Re-exports\n */\n FxTypeId,\n} from \"./fx.types\"\nexport {\n /**\n * Re-exported core Fx protocol type.\n *\n * @example\n * ```ts\n * import { Fx } from \"@nicolastoulemont/std\"\n *\n * type Example = typeof Fx.Fx<unknown, unknown, unknown>\n * ```\n *\n * @category Re-exports\n */\n type Fx,\n} from \"./fx.types\"\nexport {\n /**\n * Re-exported synchronous Fx type.\n *\n * @example\n * ```ts\n * import { Fx } from \"@nicolastoulemont/std\"\n *\n * type Example = typeof Fx.SyncFx<unknown, unknown, unknown>\n * ```\n *\n * @category Re-exports\n */\n type SyncFx,\n} from \"./fx.types\"\nexport {\n /**\n * Re-exported asynchronous Fx type.\n *\n * @example\n * ```ts\n * import { Fx } from \"@nicolastoulemont/std\"\n *\n * type Example = typeof Fx.AsyncFx<unknown, unknown, unknown>\n * ```\n *\n * @category Re-exports\n */\n type AsyncFx,\n} from \"./fx.types\"\nexport {\n /**\n * Re-exported runnable Fx union type.\n *\n * @example\n * ```ts\n * import { Fx } from \"@nicolastoulemont/std\"\n *\n * type Example = typeof Fx.RunnableFx<unknown, unknown, unknown>\n * ```\n *\n * @category Re-exports\n */\n type RunnableFx,\n} from \"./fx.types\"\nexport {\n /**\n * Re-exported service-request protocol type.\n *\n * @example\n * ```ts\n * import { Fx } from \"@nicolastoulemont/std\"\n *\n * type Example = typeof Fx.ServiceRequest<unknown>\n * ```\n *\n * @category Re-exports\n */\n type ServiceRequest,\n} from \"./fx.types\"\nexport {\n /**\n * Re-exported helper extracting Fx success type.\n *\n * @example\n * ```ts\n * import { Fx } from \"@nicolastoulemont/std\"\n *\n * type Example = typeof Fx.FxValue<Fx.SyncFx<number>>\n * ```\n *\n * @category Re-exports\n */\n type FxValue,\n} from \"./fx.types\"\nexport {\n /**\n * Re-exported helper extracting Fx error type.\n *\n * @example\n * ```ts\n * import { Fx } from \"@nicolastoulemont/std\"\n *\n * type Example = typeof Fx.FxError<Fx.SyncFx<number, string>>\n * ```\n *\n * @category Re-exports\n */\n type FxError,\n} from \"./fx.types\"\nexport {\n /**\n * Re-exported helper extracting Fx requirements type.\n *\n * @example\n * ```ts\n * import { Fx } from \"@nicolastoulemont/std\"\n *\n * type Example = typeof Fx.FxRequirements<Fx.SyncFx<number, never, { readonly svc: unknown }>>\n * ```\n *\n * @category Re-exports\n */\n type FxRequirements,\n} from \"./fx.types\"\nexport {\n /**\n * Re-exported generator yield union for Fx internals.\n *\n * @example\n * ```ts\n * import { Fx } from \"@nicolastoulemont/std\"\n *\n * type Example = typeof Fx.FxYield<unknown, unknown>\n * ```\n *\n * @category Re-exports\n */\n type FxYield,\n} from \"./fx.types\"\nexport {\n /**\n * Re-exported sync generator signature used by `Fx.gen`.\n *\n * @example\n * ```ts\n * import { Fx } from \"@nicolastoulemont/std\"\n *\n * type Example = typeof Fx.FxGenerator<unknown, unknown, unknown>\n * ```\n *\n * @category Re-exports\n */\n type FxGenerator,\n} from \"./fx.types\"\nexport {\n /**\n * Re-exported async generator signature used by `Fx.gen`.\n *\n * @example\n * ```ts\n * import { Fx } from \"@nicolastoulemont/std\"\n *\n * type Example = typeof Fx.AsyncFxGenerator<unknown, unknown, unknown>\n * ```\n *\n * @category Re-exports\n */\n type AsyncFxGenerator,\n} from \"./fx.types\"\nexport {\n /**\n * Re-exported sync Fx yieldable protocol type.\n *\n * @example\n * ```ts\n * import { Fx } from \"@nicolastoulemont/std\"\n *\n * type Example = typeof Fx.FxYieldable<unknown, unknown, unknown>\n * ```\n *\n * @category Re-exports\n */\n type FxYieldable,\n} from \"./fx.types\"\nexport {\n /**\n * Re-exported async Fx yieldable protocol type.\n *\n * @example\n * ```ts\n * import { Fx } from \"@nicolastoulemont/std\"\n *\n * type Example = typeof Fx.AsyncFxYieldable<unknown, unknown, unknown>\n * ```\n *\n * @category Re-exports\n */\n type AsyncFxYieldable,\n} from \"./fx.types\"\n\n/* oxlint-disable no-unsafe-type-assertion, no-unsafe-assignment, no-unsafe-call, no-unsafe-member-access, no-unsafe-return, no-unsafe-argument, no-unnecessary-type-assertion -- Fx runtime adapters intentionally traverse erased generator channels and rehydrate typed effects through controlled dynamic boundaries. */\n\n// ============================================================================\n// Fx.run - Execute computations\n// ============================================================================\n\n/**\n * Execute a sync Fx computation and return the Exit.\n * Catches unexpected thrown exceptions and wraps them as Defect.\n * Only available when R = never (all dependencies provided).\n *\n * @param fx - The sync computation to execute\n * @returns Exit<A, E>\n */\nfunction fxRun<A, E>(fx: SyncFx<A, E>): ExitType<A, E>\n\n/**\n * Execute an async Fx computation and return a Promise of the Exit.\n * Catches unexpected thrown exceptions and wraps them as Defect.\n * Only available when R = never (all dependencies provided).\n *\n * @param fx - The async computation to execute\n * @returns Promise<Exit<A, E>>\n */\nfunction fxRun<A, E>(fx: AsyncFx<A, E>): Promise<ExitType<A, E>>\n\n/**\n * Execute an Fx computation (union type).\n * Returns Exit for sync, Promise<Exit> for async.\n * Catches unexpected thrown exceptions and wraps them as Defect.\n */\nfunction fxRun<A, E>(fx: RunnableFx<A, E>): ExitType<A, E> | Promise<ExitType<A, E>>\n\n/**\n * Implementation of Fx.run.\n * Detects sync vs async and executes appropriately.\n */\nfunction fxRun<A, E>(fx: RunnableFx<A, E>): ExitType<A, E> | Promise<ExitType<A, E>> {\n if (fx._tag === \"AsyncFx\") {\n return runAsync(fx)\n }\n return runSync(fx)\n}\n\n// ============================================================================\n// Fx.retry - Retry failed computations\n// ============================================================================\n\nconst sleep = (ms: number): Promise<void> =>\n new Promise((resolve) => {\n setTimeout(resolve, ms)\n })\n\nconst sleepIfNeeded = async (ms: number): Promise<void> => {\n if (ms <= 0) {\n return\n }\n await sleep(ms)\n}\n\nconst closeSyncAttempt = (gen: Generator<unknown, unknown, unknown>) => {\n if (typeof gen.return === \"function\") {\n gen.return(undefined)\n }\n}\n\nconst closeAsyncAttempt = async (\n gen: Generator<unknown, unknown, unknown> | AsyncGenerator<unknown, unknown, unknown>,\n) => {\n if (typeof gen.return === \"function\") {\n await gen.return(undefined)\n }\n}\n\nconst makeSyncRetryFx = <A, E, R>(fx: SyncFx<A, E, R>, schedule: SyncRetrySchedule): SyncFx<A, E, R> => ({\n _tag: \"SyncFx\",\n [FxTypeId]: {\n _A: () => undefined as unknown as A,\n _E: () => undefined as unknown as E,\n _R: () => undefined as unknown as R,\n },\n *[Symbol.iterator](): Generator<FxYield<E, R>, A, unknown> {\n let retryAttempt = 0\n attemptLoop: while (true) {\n const gen = fx[Symbol.iterator]()\n let result = gen.next()\n\n while (result.done !== true) {\n const yielded = result.value\n const serviceRequest = asServiceRequest(yielded)\n if (serviceRequest !== undefined) {\n const injected = yield yielded as FxYield<E, R>\n result = gen.next(injected)\n continue\n }\n\n retryAttempt += 1\n if (retryAttempt <= schedule.maxRetries) {\n closeSyncAttempt(gen)\n continue attemptLoop\n }\n\n // Forward the terminal typed failure to the outer runtime.\n yield yielded as FxYield<E, R>\n return undefined as never\n }\n\n return result.value\n }\n },\n})\n\n/* oxlint-disable no-await-in-loop -- retry execution is intentionally sequential across attempts and iterator steps. */\nconst makeAsyncRetryFx = <A, E, R>(fx: RunnableFx<A, E, R>, schedule: RetrySchedule): AsyncFx<A, E, R> => ({\n _tag: \"AsyncFx\",\n [FxTypeId]: {\n _A: () => undefined as unknown as A,\n _E: () => undefined as unknown as E,\n _R: () => undefined as unknown as R,\n },\n async *[Symbol.asyncIterator](): AsyncGenerator<FxYield<E, R>, A, unknown> {\n let retryAttempt = 0\n\n attemptLoop: while (true) {\n if (fx._tag === \"AsyncFx\") {\n const gen = fx[Symbol.asyncIterator]()\n // Sequential async iterator protocol: each step depends on the previous one.\n let result = await gen.next()\n\n while (result.done !== true) {\n const yielded = result.value\n const serviceRequest = asServiceRequest(yielded)\n if (serviceRequest !== undefined) {\n const injected = yield yielded as FxYield<E, R>\n // oxlint-disable-next-line no-await-in-loop\n result = await gen.next(injected)\n continue\n }\n\n retryAttempt += 1\n if (retryAttempt <= schedule.maxRetries) {\n const delayMs = schedule.delayForAttempt(retryAttempt)\n await sleepIfNeeded(delayMs)\n await closeAsyncAttempt(gen)\n continue attemptLoop\n }\n\n // Forward the terminal typed failure to the outer runtime.\n yield yielded as FxYield<E, R>\n return undefined as never\n }\n\n return result.value\n }\n\n const gen = fx[Symbol.iterator]()\n let result = gen.next()\n\n while (result.done !== true) {\n const yielded = result.value\n const serviceRequest = asServiceRequest(yielded)\n if (serviceRequest !== undefined) {\n const injected = yield yielded as FxYield<E, R>\n result = gen.next(injected)\n continue\n }\n\n retryAttempt += 1\n if (retryAttempt <= schedule.maxRetries) {\n const delayMs = schedule.delayForAttempt(retryAttempt)\n await sleepIfNeeded(delayMs)\n await closeAsyncAttempt(gen)\n continue attemptLoop\n }\n\n // Forward the terminal typed failure to the outer runtime.\n yield yielded as FxYield<E, R>\n return undefined as never\n }\n\n return result.value\n }\n },\n})\n/* oxlint-enable no-await-in-loop */\n\n/**\n * Retry a computation according to the given schedule.\n *\n * Retries only typed failures (Err channel). Defects are not retried.\n */\ntype RetryResult<Fx extends RunnableFx<unknown, unknown, unknown>, S extends RetrySchedule> =\n Fx extends AsyncFx<infer A, infer E, infer R>\n ? AsyncFx<A, E, R>\n : S extends SyncRetrySchedule\n ? Fx extends SyncFx<infer A, infer E, infer R>\n ? SyncFx<A, E, R>\n : never\n : Fx extends SyncFx<infer A, infer E, infer R>\n ? AsyncFx<A, E, R>\n : never\n\nconst fxRetry: {\n <Fx extends RunnableFx<unknown, unknown, unknown>, S extends RetrySchedule>(fx: Fx, schedule: S): RetryResult<Fx, S>\n <S extends RetrySchedule>(\n schedule: S,\n ): <Fx extends RunnableFx<unknown, unknown, unknown>>(fx: Fx) => RetryResult<Fx, S>\n} = dual(\n 2,\n <Fx extends RunnableFx<unknown, unknown, unknown>, S extends RetrySchedule>(\n fx: Fx,\n schedule: S,\n ): RetryResult<Fx, S> => {\n if (fx._tag === \"AsyncFx\" || !schedule._sync) {\n return makeAsyncRetryFx(fx, schedule) as RetryResult<Fx, S>\n }\n return makeSyncRetryFx(fx as SyncFx<unknown, unknown, unknown>, schedule as SyncRetrySchedule) as RetryResult<Fx, S>\n },\n)\n\n// ============================================================================\n// Fx.gen - Create composable computations\n// ============================================================================\n\ntype FxGenError<Yielded> = Yielded extends FxProtocol<unknown, infer E, unknown> ? E : Yielded\ntype FxGenRequirements<Yielded> = Yielded extends FxProtocol<unknown, unknown, infer R> ? R : never\n\n/**\n * Create a composable computation from a sync generator function.\n * Returns a SyncFx that can be stored, passed around, and executed later.\n *\n * @template Yielded - The type of values yielded by the generator\n * @template A - The success value type\n * @param generatorFn - A function that returns a sync generator\n * @returns SyncFx<A, FxGenError<Yielded>, FxGenRequirements<Yielded>>\n *\n * @example\n * ```ts\n * const getUser = (id: string) => Fx.gen(function* () {\n * const db = yield* Database\n * const logger = yield* Logger\n *\n * logger.info(`Fetching user ${id}`)\n * return yield* db.query<User>(`SELECT * FROM users WHERE id = '${id}'`)\n * })\n * // Type: SyncFx<User[], DatabaseError, Database | Logger>\n *\n * // Execute later with dependencies provided\n * const exit = pipe(getUser(\"123\"), Provide.layer(AppLayer)).run()\n * ```\n */\nfunction fxGen<Yielded, A>(\n generatorFn: () => Generator<Yielded, A, unknown>,\n): SyncFx<A, FxGenError<Yielded>, FxGenRequirements<Yielded>>\n\n/**\n * Create a composable computation from an async generator function.\n * Returns an AsyncFx that can be stored, passed around, and executed later.\n *\n * @template Yielded - The type of values yielded by the generator\n * @template A - The success value type\n * @param generatorFn - A function that returns an async generator\n * @returns AsyncFx<A, FxGenError<Yielded>, FxGenRequirements<Yielded>>\n *\n * @example\n * ```ts\n * const fetchData = (url: string) => Fx.gen(async function* () {\n * const logger = yield* Logger\n *\n * logger.info(`Fetching ${url}`)\n * const response = await fetch(url)\n * return yield* Result.try(async () => await response.json())\n * })\n * // Type: AsyncFx<unknown, Error, Logger>\n * ```\n */\nfunction fxGen<Yielded, A>(\n generatorFn: () => AsyncGenerator<Yielded, A, unknown>,\n): AsyncFx<A, FxGenError<Yielded>, FxGenRequirements<Yielded>>\n\n/**\n * Create a composable computation from a sync generator function that takes parameters.\n * Returns a factory function that, when called with parameters, produces a SyncFx.\n *\n * @template P - The parameter types (must be non-empty)\n * @template Yielded - The type of values yielded by the generator\n * @template A - The success value type\n * @param generatorFn - A function that takes parameters and returns a sync generator\n * @returns A factory function that produces SyncFx<A, FxGenError<Yielded>, FxGenRequirements<Yielded>>\n *\n * @example\n * ```ts\n * const getUser = Fx.gen(function* ({userId}: {userId: string}) {\n * const db = yield* Database\n * return yield* db.query(`SELECT * FROM users WHERE id = '${userId}'`)\n * })\n * // Type: (params: {userId: string}) => SyncFx<...>\n *\n * const exit = Fx.run(pipe(getUser({userId: \"123\"}), Provide.layer(DbLayer)))\n * ```\n */\nfunction fxGen<P extends [unknown, ...unknown[]], Yielded, A>(\n generatorFn: (...params: P) => Generator<Yielded, A, unknown>,\n): (...params: P) => SyncFx<A, FxGenError<Yielded>, FxGenRequirements<Yielded>>\n\n/**\n * Create a composable computation from an async generator function that takes parameters.\n * Returns a factory function that, when called with parameters, produces an AsyncFx.\n *\n * @template P - The parameter types (must be non-empty)\n * @template Yielded - The type of values yielded by the generator\n * @template A - The success value type\n * @param generatorFn - A function that takes parameters and returns an async generator\n * @returns A factory function that produces AsyncFx<A, FxGenError<Yielded>, FxGenRequirements<Yielded>>\n *\n * @example\n * ```ts\n * const fetchUser = Fx.gen(async function* ({url}: {url: string}) {\n * const response = await fetch(url)\n * return yield* Result.try(async () => await response.json())\n * })\n * // Type: (params: {url: string}) => AsyncFx<...>\n * ```\n */\nfunction fxGen<P extends [unknown, ...unknown[]], Yielded, A>(\n generatorFn: (...params: P) => AsyncGenerator<Yielded, A, unknown>,\n): (...params: P) => AsyncFx<A, FxGenError<Yielded>, FxGenRequirements<Yielded>>\n\n/**\n * Implementation of unified Fx.gen function.\n * Detects sync vs async generator and returns appropriate computation type.\n * For parameterized generators (length > 0), returns a factory function.\n */\n// oxlint-disable-next-line no-explicit-any\nfunction fxGen(generatorFn: (...args: any[]) => any): any {\n if (generatorFn.length > 0) {\n return (...params: unknown[]) => fxGen(() => generatorFn(...params))\n }\n\n // Check if we're dealing with async generator\n const testGen = generatorFn()\n const isAsync = Symbol.asyncIterator in testGen\n\n if (isAsync) {\n return {\n _tag: \"AsyncFx\",\n [FxTypeId]: {\n _A: () => undefined,\n _E: () => undefined,\n _R: () => undefined,\n },\n // oxlint-disable-next-line no-explicit-any\n async *[Symbol.asyncIterator](): AsyncGenerator<any, any, unknown> {\n const gen = generatorFn()\n let result = await gen.next()\n\n while (result.done !== true) {\n // Pass through yields (errors or services as Fx values)\n const injected = yield result.value\n // oxlint-disable-next-line no-await-in-loop\n result = await gen.next(injected)\n }\n\n return result.value\n },\n }\n }\n\n // Sync generator\n return {\n _tag: \"SyncFx\",\n [FxTypeId]: {\n _A: () => undefined,\n _E: () => undefined,\n _R: () => undefined,\n },\n // oxlint-disable-next-line no-explicit-any\n *[Symbol.iterator](): Generator<any, any, unknown> {\n const gen = generatorFn()\n let result = gen.next()\n\n while (result.done !== true) {\n const injected = yield result.value\n result = gen.next(injected)\n }\n\n return result.value\n },\n }\n}\n\n// ============================================================================\n// Fx.fn - Execute computations immediately\n// ============================================================================\n\ntype FxRunResult<F extends RunnableFx<unknown, unknown, unknown>> =\n F extends AsyncFx<infer A, infer E, unknown>\n ? Promise<ExitType<A, E>>\n : F extends SyncFx<infer A, infer E, unknown>\n ? ExitType<A, E>\n : never\n\n/**\n * Execute a sync computation immediately and return the Exit.\n * Catches unexpected thrown exceptions and wraps them as Defect.\n * For computations without service dependencies.\n *\n * @template A - The success value type\n * @template E - The error type\n * @param generatorFn - A function that returns a sync generator\n * @returns Exit<A, E>\n *\n * @example\n * ```ts\n * const exit = Fx.fn(function* () {\n * const a = yield* Result.ok(10)\n * const b = yield* Result.ok(20)\n * return a + b\n * })\n * // Type: Exit<number, never>\n * // exit = { _tag: \"Ok\", value: 30 }\n * ```\n */\nfunction fxFn<A, E>(generatorFn: () => FxGenerator<A, E, never>): ExitType<A, E>\n\n/**\n * Execute an async computation immediately and return a Promise of the Exit.\n * Catches unexpected thrown exceptions and wraps them as Defect.\n * For computations without service dependencies.\n *\n * @template A - The success value type\n * @template E - The error type\n * @param generatorFn - A function that returns an async generator\n * @returns Promise<Exit<A, E>>\n *\n * @example\n * ```ts\n * const exit = await Fx.fn(async function* () {\n * const response = await fetch(\"/api/users\")\n * const data = yield* Result.try(async () => await response.json())\n * return data\n * })\n * // Type: Promise<Exit<unknown, Error>>\n * ```\n */\nfunction fxFn<A, E>(generatorFn: () => AsyncFxGenerator<A, E, never>): Promise<ExitType<A, E>>\n\n/**\n * Execute a sync computation with service dependencies immediately.\n * Catches unexpected thrown exceptions and wraps them as Defect.\n * The second argument is required when the computation has service requirements (R ≠ never).\n *\n * @template A - The success value type\n * @template E - The error type from the computation\n * @template R - The required services type\n * @param generatorFn - A function that returns a sync generator with service requirements\n * @param provider - A function that provides the services (e.g., Provide.layer(AppLayer))\n * @returns Exit result from running the provided Fx (sync or async depending on provider output)\n *\n * @example\n * ```ts\n * const exit = Fx.fn(function* () {\n * const config = yield* Config\n * const logger = yield* Logger\n * logger.info(`DB URL: ${config.dbUrl}`)\n * return config.dbUrl\n * }, Provide.layer(AppLayer))\n * // Type: Exit<string, never>\n * ```\n */\nfunction fxFn<A, E, R, ProvidedFx extends RunnableFx<unknown, unknown, unknown>>(\n generatorFn: () => FxGenerator<A, E, R>,\n provider: (fx: SyncFx<A, E, R>) => ProvidedFx,\n): FxRunResult<ProvidedFx>\n\n/**\n * Execute an async computation with service dependencies immediately.\n * Catches unexpected thrown exceptions and wraps them as Defect.\n * The second argument is required when the computation has service requirements (R ≠ never).\n *\n * @template A - The success value type\n * @template E - The error type from the computation\n * @template R - The required services type\n * @param generatorFn - A function that returns an async generator with service requirements\n * @param provider - A function that provides the services (e.g., Provide.layer(AppLayer))\n * @returns Exit result from running the provided Fx (sync or async depending on provider output)\n *\n * @example\n * ```ts\n * const exit = await Fx.fn(async function* () {\n * const config = yield* Config\n * await doAsyncWork()\n * return config.dbUrl\n * }, Provide.layer(AppLayer))\n * // Type: Promise<Exit<string, never>>\n * ```\n */\nfunction fxFn<A, E, R, ProvidedFx extends RunnableFx<unknown, unknown, unknown>>(\n generatorFn: () => AsyncFxGenerator<A, E, R>,\n provider: (fx: AsyncFx<A, E, R>) => ProvidedFx,\n): FxRunResult<ProvidedFx>\n\n/**\n * Implementation of Fx.fn.\n * Reuses fxGen() for Fx creation and fxRun() for execution to ensure consistent behavior.\n */\nfunction fxFn<A, E, E2, R>(\n generatorFn: () => FxGenerator<A, E, R> | AsyncFxGenerator<A, E, R>,\n provider?: ((fx: SyncFx<A, E, R>) => RunnableFx<A, E | E2>) | ((fx: AsyncFx<A, E, R>) => RunnableFx<A, E | E2>),\n): ExitType<A, E | E2> | Promise<ExitType<A, E | E2>> {\n // Create the Fx using fxGen (single source of truth for Fx creation)\n // Type cast needed because fxGen infers E/R from yielded Fx values,\n // while fxFn receives E/R as explicit type parameters\n // oxlint-disable-next-line no-explicit-any\n const fx = fxGen(generatorFn as any) as RunnableFx<A, E, R>\n\n if (provider) {\n // Apply provider and run\n const provided =\n fx._tag === \"AsyncFx\"\n ? (provider as (fx: AsyncFx<A, E, R>) => RunnableFx<A, E | E2>)(fx)\n : (provider as (fx: SyncFx<A, E, R>) => RunnableFx<A, E | E2>)(fx)\n return fxRun(provided as RunnableFx<A, E | E2>) as ExitType<A, E | E2> | Promise<ExitType<A, E | E2>>\n }\n\n // No provider - run directly (R must be never at the type level)\n return fxRun(fx as RunnableFx<A, E | E2>) as ExitType<A, E | E2> | Promise<ExitType<A, E | E2>>\n}\n\n// ============================================================================\n// Fx.ok / Fx.err / Fx.option - Convenience aliases\n// ============================================================================\n\n/**\n * Convenience alias for Result.ok.\n * Creates a successful Result that can be yielded in an Fx computation.\n *\n * @param value - The success value\n * @returns Result<T, never>\n *\n * @example\n * ```ts\n * const workflow = Fx.gen(function* () {\n * const value = yield* Fx.ok(42)\n * return value * 2\n * })\n * ```\n */\nconst fxOk = resultOk\n\n/**\n * Convenience alias for Result.err.\n * Creates an error Result that can be yielded in an Fx computation.\n *\n * @param error - The error value\n * @returns Result<never, E>\n *\n * @example\n * ```ts\n * const workflow = Fx.gen(function* () {\n * const config = yield* Config\n *\n * if (!config.dbUrl) {\n * return yield* Fx.err(new ValidationError({ field: \"dbUrl\" }))\n * }\n *\n * return config.dbUrl\n * })\n * ```\n */\nconst fxErr = resultErr\n\n/**\n * Convenience alias for Result.try.\n * Creates a Result that can be yielded in an Fx computation.\n *\n * @param fn - A function that returns a value or throws an error\n * @returns Result<T, E>\n *\n * @example\n * ```ts\n * const result = Fx.try(() => {\n * return 42\n * })\n *\n * const workflow = Fx.gen(function* () {\n * const result = yield* Fx.try(() => {\n * return 42\n * })\n * return result\n * })\n * ```\n */\nconst fxTry = resultTry\n\n/**\n * Convenience alias for Option.fromNullable.\n * Converts nullable values into an Option that can be yielded in an Fx computation.\n *\n * @param value - A possibly nullish value\n * @returns Option<NonNullable<T>>\n *\n * @example\n * ```ts\n * const workflow = Fx.gen(function* () {\n * const apiKey = yield* Fx.option(request.headers[\"x-api-key\"])\n * return apiKey\n * })\n * ```\n */\nconst fxOption = optionFromNullable\n\n// ============================================================================\n// Fx.match - Universal pattern matching\n// ============================================================================\n\n/**\n * Handler functions for matching on a tagged union by `_tag` discriminator.\n * Each handler receives the narrowed variant corresponding to its tag key.\n *\n * @example\n * ```ts\n * import { Fx } from \"@nicolastoulemont/std\"\n *\n * type Example = typeof Fx\n * ```\n *\n * @category Type-level\n */\nexport type TaggedMatch<T extends { readonly _tag: string }, R> = {\n readonly [K in T[\"_tag\"]]: (variant: Extract<T, { readonly _tag: K }>) => R\n}\n\n/**\n * Generic pattern matcher for any `_tag`-based discriminated union.\n *\n * Works with Exit, tagged errors, or any type with a `readonly _tag` discriminator.\n * Each handler receives the full narrowed variant object for its tag.\n *\n * Supports both data-first and data-last (pipe) calling styles.\n *\n * @example\n * ```ts\n * // Match on Exit\n * Fx.match(exit, {\n * Ok: (ok) => ok.value,\n * Err: (err) =>\n * Fx.match(err.error, {\n * DatabaseError: (e) => e.message,\n * NotFoundError: (e) => e.resourceId,\n * }),\n * Defect: (d) => String(d.defect),\n * })\n *\n * // Data-last with pipe\n * pipe(exit, Fx.match({\n * Ok: (ok) => ok.value,\n * Err: (err) => \"error\",\n * Defect: (d) => \"defect\",\n * }))\n * ```\n */\nconst fxMatch: {\n <T extends { readonly _tag: string }, R>(value: T, handlers: TaggedMatch<T, R>): R\n <T extends { readonly _tag: string }, R>(handlers: TaggedMatch<T, R>): (value: T) => R\n} = dual(\n 2,\n // oxlint-disable-next-line no-explicit-any\n (value: any, handlers: any): any => handlers[value._tag](value),\n)\n\n// ============================================================================\n// Exports\n// ============================================================================\n\n/**\n * Build typed computations from generator functions.\n *\n * @example\n * ```ts\n * import { Fx } from \"@nicolastoulemont/std\"\n *\n * const program = Fx.gen(function* () {\n * const value = yield* Fx.ok(2)\n * return value + 1\n * })\n * const exit = Fx.run(program)\n * // => { _tag: \"Ok\", value: 3 }\n * ```\n *\n * @category Constructors\n */\nexport const gen = fxGen\n\n/**\n * Run a generator function immediately and return its `Exit`.\n *\n * @example\n * ```ts\n * import { Fx } from \"@nicolastoulemont/std\"\n *\n * const exit = Fx.fn(function* () {\n * return yield* Fx.ok(2)\n * })\n * // => { _tag: \"Ok\", value: 2 }\n * ```\n *\n * @category Utilities\n */\nexport const fn = fxFn\n\n/**\n * Execute an existing `Fx` value and produce an `Exit`.\n *\n * @example\n * ```ts\n * import { Fx } from \"@nicolastoulemont/std\"\n *\n * const exit = Fx.run(Fx.gen(function* () {\n * return 1\n * }))\n * // => { _tag: \"Ok\", value: 1 }\n * ```\n *\n * @category Utilities\n */\nexport const run = fxRun\n\n/**\n * Retry failed computations according to a schedule.\n *\n * @example\n * ```ts\n * import { Fx } from \"@nicolastoulemont/std\"\n *\n * import { Schedule } from \"@nicolastoulemont/std\"\n *\n * const retried = Fx.retry(\n * Fx.gen(function* () {\n * return yield* Fx.err(\"boom\")\n * }),\n * Schedule.recurs(2),\n * )\n * const exit = Fx.run(retried)\n * // => { _tag: \"Err\", error: \"boom\" }\n * ```\n *\n * @category Error Handling\n */\nexport const retry = fxRetry\n\n/**\n * Run an effectful function for each item in a collection.\n *\n * @example\n * ```ts\n * import { Fx } from \"@nicolastoulemont/std\"\n *\n * const fx = Fx.forEach([1, 2, 3], (n) => Fx.gen(function* () {\n * return n * 2\n * }))\n * // => AsyncFx<readonly number[], ...>\n * ```\n *\n * @category Sequencing\n */\nexport const forEach = fxForEach\n\n/**\n * Alias for `Result.ok` in `Fx` namespace.\n *\n * @example\n * ```ts\n * import { Fx } from \"@nicolastoulemont/std\"\n *\n * const value = Fx.ok(42)\n * // => { _tag: \"Ok\", value: 42 }\n * ```\n *\n * @category Constructors\n */\nexport const ok = fxOk\n\n/**\n * Alias for `Result.err` in `Fx` namespace.\n *\n * @example\n * ```ts\n * import { Fx } from \"@nicolastoulemont/std\"\n *\n * const value = Fx.err(\"boom\")\n * // => { _tag: \"Err\", error: \"boom\" }\n * ```\n *\n * @category Constructors\n */\nexport const err = fxErr\n\n/**\n * Alias for `Option.fromNullable` in `Fx` namespace.\n *\n * @example\n * ```ts\n * import { Fx } from \"@nicolastoulemont/std\"\n *\n * const value = Fx.option(\"token\")\n * // => { _tag: \"Some\", value: \"token\" }\n * ```\n *\n * @category Conversions\n */\nexport const option = fxOption\n\nconst try_ = fxTry\n\nexport {\n /**\n * Alias for `Result.fromTry` in `Fx` namespace.\n *\n * @example\n * ```ts\n * import { Fx } from \"@nicolastoulemont/std\"\n *\n * const parsed = Fx.try(() => Number.parseInt(\"42\", 10))\n * // => { _tag: \"Ok\", value: 42 }\n * ```\n *\n * @category Constructors\n */\n try_ as try,\n}\n\n/**\n * Pattern matching helper for tagged unions.\n *\n * @example\n * ```ts\n * import { Fx } from \"@nicolastoulemont/std\"\n *\n * const value = Fx.match({ _tag: \"Ok\", value: 2 } as const, {\n * Ok: (ok) => ok.value + 1,\n * })\n * // => 3\n * ```\n *\n * @category Pattern Matching\n */\nexport const match = fxMatch\n\n/* oxlint-enable no-unsafe-type-assertion, no-unsafe-assignment, no-unsafe-call, no-unsafe-member-access, no-unsafe-return, no-unsafe-argument, no-unnecessary-type-assertion */\n"],"mappings":"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"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{t as e}from"./dual-CZhzZslG.mjs";import{t}from"./option.types-
|
|
2
|
-
//# sourceMappingURL=fx.runtime-
|
|
1
|
+
import{t as e}from"./dual-CZhzZslG.mjs";import{t}from"./option.types-D1mm0zUb.mjs";import{t as n}from"./service-resolution-C19smeaO.mjs";const r=e=>({_tag:`Ok`,value:e}),i=e=>({_tag:`Err`,error:e}),a=e=>({_tag:`Defect`,defect:e}),o={ok:r,err:i,defect:a,isOk:e=>e._tag===`Ok`,isErr:e=>e._tag===`Err`,isDefect:e=>e._tag===`Defect`,match:e(2,(e,t)=>{switch(e._tag){case`Ok`:return t.Ok(e.value);case`Err`:return t.Err(e.error);case`Defect`:return t.Defect(e.defect)}}),getOrThrow:e=>{switch(e._tag){case`Ok`:return e.value;case`Err`:throw e.error;case`Defect`:throw e.defect}}};function s(e){try{let o=e[Symbol.iterator]().next();if(o.done!==!0){let e=o.value,r=n(e);return r===void 0?e instanceof t?i(e):typeof e==`object`&&e&&`_tag`in e&&e._tag===`Err`?i(e.error):i(e):a(Error(`Service "${r.key}" not provided. Use Provide.layer() to inject services.`))}return r(o.value)}catch(e){return a(e)}}async function c(e){try{let o=await e[Symbol.asyncIterator]().next();if(o.done!==!0){let e=o.value,r=n(e);return r===void 0?e instanceof t?i(e):typeof e==`object`&&e&&`_tag`in e&&e._tag===`Err`?i(e.error):i(e):a(Error(`Service "${r.key}" not provided. Use Provide.layer() to inject services.`))}return r(o.value)}catch(e){return a(e)}}export{s as n,o as r,c as t};
|
|
2
|
+
//# sourceMappingURL=fx.runtime-DclEDyjY.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fx.runtime-
|
|
1
|
+
{"version":3,"file":"fx.runtime-DclEDyjY.mjs","names":["exitDefect","exitErr","exitOk"],"sources":["../src/fx/exit.ts","../src/fx/fx.runtime.ts"],"sourcesContent":["import { dual } from \"../shared/dual\"\nimport type { Err, Ok } from \"../shared/type-utils.types\"\n\n// ============================================================================\n// Exit Types - Flat 3-variant discriminated union\n// ============================================================================\n\n/**\n * Represents an unexpected thrown exception (defect) caught during Fx execution.\n */\ntype Defect = {\n readonly _tag: \"Defect\"\n readonly defect: unknown\n}\n\n/**\n * Exit represents the outcome of an Fx computation.\n * A flat 3-variant discriminated union that cleanly separates:\n * - `Ok<A>`: successful result with value of type A\n * - `Err<E>`: typed failure with error of type E\n * - `Defect`: unexpected thrown exception (defect)\n *\n * @example\n * ```ts\n * const exit = Fx.run(computation)\n * switch (exit._tag) {\n * case \"Ok\": exit.value // A\n * case \"Err\": exit.error // E (clean!)\n * case \"Defect\": exit.defect // unknown\n * }\n * ```\n */\nexport type Exit<A, E> = Ok<A> | Err<E> | Defect\n\n// ============================================================================\n// Constructors\n// ============================================================================\n\n/**\n * Create a successful Exit.\n */\nexport const ok = <A>(value: A): Ok<A> => ({ _tag: \"Ok\", value })\n\n/**\n * Create a typed failure Exit.\n */\nexport const err = <E>(error: E): Err<E> => ({ _tag: \"Err\", error })\n\n/**\n * Create a defect Exit from an unexpected thrown value.\n */\nexport const defect = (thrown: unknown): Defect => ({ _tag: \"Defect\", defect: thrown })\n\n// ============================================================================\n// Guards\n// ============================================================================\n\n/**\n * Check if an Exit is a successful result.\n */\nconst isOk = <A, E>(exit: Exit<A, E>): exit is Ok<A> => exit._tag === \"Ok\"\n\n/**\n * Check if an Exit is a typed failure.\n */\nconst isErr = <A, E>(exit: Exit<A, E>): exit is Err<E> => exit._tag === \"Err\"\n\n/**\n * Check if an Exit is an unexpected defect.\n */\nconst isDefect = <A, E>(exit: Exit<A, E>): exit is Defect => exit._tag === \"Defect\"\n\n// ============================================================================\n// Match\n// ============================================================================\n\n/**\n * Handler functions for Exit.match.\n */\ntype ExitMatch<A, E, R> = {\n readonly Ok: (value: A) => R\n readonly Err: (error: E) => R\n readonly Defect: (defect: unknown) => R\n}\n\n/**\n * Pattern match on an Exit value.\n *\n * @example\n * ```ts\n * // Data-first\n * Exit.match(exit, {\n * Ok: (value) => `Success: ${value}`,\n * Err: (error) => `Error: ${error}`,\n * Defect: (defect) => `Defect: ${defect}`,\n * })\n *\n * // Data-last (pipe)\n * pipe(exit, Exit.match({\n * Ok: (value) => `Success: ${value}`,\n * Err: (error) => `Error: ${error}`,\n * Defect: (defect) => `Defect: ${defect}`,\n * }))\n * ```\n */\nconst match: {\n <A, E, R>(exit: Exit<A, E>, handlers: ExitMatch<A, E, R>): R\n <A, E, R>(handlers: ExitMatch<A, E, R>): (exit: Exit<A, E>) => R\n} = dual(2, <A, E, R>(exit: Exit<A, E>, handlers: ExitMatch<A, E, R>): R => {\n switch (exit._tag) {\n case \"Ok\":\n return handlers.Ok(exit.value)\n case \"Err\":\n return handlers.Err(exit.error)\n case \"Defect\":\n return handlers.Defect(exit.defect)\n }\n})\n\n// ============================================================================\n// Utility\n// ============================================================================\n\n/**\n * Extract the value from an Ok exit, or throw.\n * Useful for tests and scripts where you expect success.\n *\n * @throws The error for Err exits, or the defect for Defect exits\n */\nconst getOrThrow = <A, E>(exit: Exit<A, E>): A => {\n switch (exit._tag) {\n case \"Ok\":\n return exit.value\n case \"Err\":\n // oxlint-disable-next-line only-throw-error -- E is intentionally generic and may be a non-Error domain value.\n throw exit.error\n case \"Defect\":\n throw exit.defect\n }\n}\n\n// ============================================================================\n// Namespace\n// ============================================================================\n\n/**\n * Exit namespace containing all Exit utilities.\n */\nexport const Exit = {\n ok,\n err,\n defect,\n isOk,\n isErr,\n isDefect,\n match,\n getOrThrow,\n} as const\n","import { NoSuchElementError } from \"../option/option.types\"\nimport { asServiceRequest } from \"../service/service-resolution\"\nimport { ok as exitOk, err as exitErr, defect as exitDefect } from \"./exit\"\nimport type { Exit } from \"./exit\"\nimport type { AsyncFx, SyncFx } from \"./fx.types\"\n\nexport function runSync<A, E>(fx: SyncFx<A, E>): Exit<A, E> {\n try {\n const gen = fx[Symbol.iterator]()\n const result = gen.next()\n\n if (result.done !== true) {\n const yielded = result.value as unknown\n const serviceRequest = asServiceRequest(yielded)\n if (serviceRequest !== undefined) {\n return exitDefect(\n new Error(`Service \"${serviceRequest.key}\" not provided. Use Provide.layer() to inject services.`),\n )\n }\n\n if (yielded instanceof NoSuchElementError) {\n return exitErr(yielded as E)\n }\n\n if (typeof yielded === \"object\" && yielded !== null && \"_tag\" in yielded && yielded._tag === \"Err\") {\n return exitErr((yielded as Record<string, unknown>)[\"error\"] as E)\n }\n\n return exitErr(yielded as E)\n }\n\n return exitOk(result.value)\n } catch (thrown) {\n return exitDefect(thrown)\n }\n}\n\nexport async function runAsync<A, E>(fx: AsyncFx<A, E>): Promise<Exit<A, E>> {\n try {\n const gen = fx[Symbol.asyncIterator]()\n const result = await gen.next()\n\n if (result.done !== true) {\n const yielded = result.value as unknown\n const serviceRequest = asServiceRequest(yielded)\n if (serviceRequest !== undefined) {\n return exitDefect(\n new Error(`Service \"${serviceRequest.key}\" not provided. Use Provide.layer() to inject services.`),\n )\n }\n\n if (yielded instanceof NoSuchElementError) {\n return exitErr(yielded as E)\n }\n\n if (typeof yielded === \"object\" && yielded !== null && \"_tag\" in yielded && yielded._tag === \"Err\") {\n return exitErr((yielded as Record<string, unknown>)[\"error\"] as E)\n }\n\n return exitErr(yielded as E)\n }\n\n return exitOk(result.value)\n } catch (thrown) {\n return exitDefect(thrown)\n }\n}\n"],"mappings":"yIAyCA,MAAa,EAAS,IAAqB,CAAE,KAAM,KAAM,QAAO,EAKnD,EAAU,IAAsB,CAAE,KAAM,MAAO,QAAO,EAKtD,EAAU,IAA6B,CAAE,KAAM,SAAU,OAAQ,EAAQ,EAiGzE,EAAO,CAClB,KACA,MACA,SACA,KA5FkB,GAAoC,EAAK,OAAS,KA6FpE,MAxFmB,GAAqC,EAAK,OAAS,MAyFtE,SApFsB,GAAqC,EAAK,OAAS,SAqFzE,MA/CE,EAAK,GAAa,EAAkB,IAAoC,CAC1E,OAAQ,EAAK,KAAb,CACE,IAAK,KACH,OAAO,EAAS,GAAG,EAAK,MAAM,CAChC,IAAK,MACH,OAAO,EAAS,IAAI,EAAK,MAAM,CACjC,IAAK,SACH,OAAO,EAAS,OAAO,EAAK,OAAO,GAEvC,CAuCA,WA3BwB,GAAwB,CAChD,OAAQ,EAAK,KAAb,CACE,IAAK,KACH,OAAO,EAAK,MACd,IAAK,MAEH,MAAM,EAAK,MACb,IAAK,SACH,MAAM,EAAK,SAoBhB,CCvJD,SAAgB,EAAc,EAA8B,CAC1D,GAAI,CAEF,IAAM,EADM,EAAG,OAAO,WAAW,CACd,MAAM,CAEzB,GAAI,EAAO,OAAS,GAAM,CACxB,IAAM,EAAU,EAAO,MACjB,EAAiB,EAAiB,EAAQ,CAehD,OAdI,IAAmB,IAAA,GAMnB,aAAmB,EACdC,EAAQ,EAAa,CAG1B,OAAO,GAAY,UAAY,GAAoB,SAAU,GAAW,EAAQ,OAAS,MACpFA,EAAS,EAAoC,MAAc,CAG7DA,EAAQ,EAAa,CAbnBD,EACD,MAAM,YAAY,EAAe,IAAI,yDAAyD,CACnG,CAcL,OAAOE,EAAO,EAAO,MAAM,OACpB,EAAQ,CACf,OAAOF,EAAW,EAAO,EAI7B,eAAsB,EAAe,EAAwC,CAC3E,GAAI,CAEF,IAAM,EAAS,MADH,EAAG,OAAO,gBAAgB,CACb,MAAM,CAE/B,GAAI,EAAO,OAAS,GAAM,CACxB,IAAM,EAAU,EAAO,MACjB,EAAiB,EAAiB,EAAQ,CAehD,OAdI,IAAmB,IAAA,GAMnB,aAAmB,EACdC,EAAQ,EAAa,CAG1B,OAAO,GAAY,UAAY,GAAoB,SAAU,GAAW,EAAQ,OAAS,MACpFA,EAAS,EAAoC,MAAc,CAG7DA,EAAQ,EAAa,CAbnBD,EACD,MAAM,YAAY,EAAe,IAAI,yDAAyD,CACnG,CAcL,OAAOE,EAAO,EAAO,MAAM,OACpB,EAAQ,CACf,OAAOF,EAAW,EAAO"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { i as Fx } from "./fx.types-DeEWEltG.mjs";
|
|
2
2
|
import { t as Pipeable } from "./pipeable-rfqacPxZ.mjs";
|
|
3
3
|
import { t as Result } from "./result.types-_xDAei3-.mjs";
|
|
4
|
-
import { r as Option } from "./option.types-
|
|
4
|
+
import { r as Option } from "./option.types-qPevEZQd.mjs";
|
|
5
5
|
|
|
6
6
|
//#region src/either/either.types.d.ts
|
|
7
7
|
/**
|
|
@@ -774,4 +774,4 @@ declare const fromNullable: <R, L>(value: R | null | undefined, onNull: () => L)
|
|
|
774
774
|
declare const fromPredicate: <R, L>(value: R, predicate: (value: R) => boolean, onFail: (value: R) => L) => Either$1<L, R>;
|
|
775
775
|
//#endregion
|
|
776
776
|
export { either_d_exports as t };
|
|
777
|
-
//# sourceMappingURL=index-
|
|
777
|
+
//# sourceMappingURL=index-B1-tBzc0.d.mts.map
|