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