| 1 | import * as Context from "effect/Context"; |
| 2 | import * as Effect from "effect/Effect"; |
| 3 | import * as Option from "effect/Option"; |
| 4 | |
| 5 | export interface NamespaceNode { |
| 6 | Id: string; |
| 7 | Parent?: NamespaceNode; |
| 8 | } |
| 9 | |
| 10 | export class Namespace extends Context.Service<Namespace, NamespaceNode>()( |
| 11 | "Alchemy/Namespace", |
| 12 | ) {} |
| 13 | |
| 14 | export function push<const Id extends string, A, Err = never, Req = never>( |
| 15 | id: Id, |
| 16 | eff: Effect.Effect<A, Err, Req>, |
| 17 | ): Effect.Effect<A, Err, Req>; |
| 18 | |
| 19 | export function push<const Id extends string>( |
| 20 | id: Id, |
| 21 | ): <A, Err = never, Req = never>( |
| 22 | eff: Effect.Effect<A, Err, Req>, |
| 23 | ) => Effect.Effect<A, Err, Req>; |
| 24 | |
| 25 | export function push(id: string, eff?: Effect.Effect<any, any, any>) { |
| 26 | return eff |
| 27 | ? Effect.flatMap(CurrentNamespace, (parent) => |
| 28 | Effect.provideService(eff, Namespace, { |
| 29 | Id: id, |
| 30 | Parent: parent, |
| 31 | }), |
| 32 | ) |
| 33 | : (eff: Effect.Effect<any, any, any>) => push(id, eff); |
| 34 | } |
| 35 | |
| 36 | export const set = (namespace: string | NamespaceNode) => |
| 37 | Effect.provideService( |
| 38 | Namespace, |
| 39 | typeof namespace === "string" ? { Id: namespace } : namespace, |
| 40 | ); |
| 41 | |
| 42 | export const CurrentNamespace = Effect.serviceOption(Namespace) |
| 43 | |
| 44 | .pipe(Effect.map(Option.getOrUndefined)); |
| 45 | |
| 46 | export const CurrentChain = CurrentNamespace.pipe( |
| 47 | Effect.map(function findRoot(ns): string[] { |
| 48 | if (ns?.Parent) { |
| 49 | return [ns.Id, ...findRoot(ns.Parent)]; |
| 50 | } |
| 51 | return ns ? [ns.Id] : []; |
| 52 | }), |
| 53 | ); |
| 54 | |
| 55 | export const Parent = Namespace.pipe(Effect.map((ns) => ns?.Parent)); |
| 56 | |
| 57 | export const Root = Namespace.pipe( |
| 58 | Effect.map(function findRoot(ns) { |
| 59 | if (ns.Parent) { |
| 60 | return findRoot(ns.Parent); |
| 61 | } |
| 62 | return ns; |
| 63 | }), |
| 64 | ); |