diff --git a/packages/effect-fc/src/Component.ts b/packages/effect-fc/src/Component.ts index f2773e9..d24c8ce 100644 --- a/packages/effect-fc/src/Component.ts +++ b/packages/effect-fc/src/Component.ts @@ -1,4 +1,4 @@ -import { Context, Effect, Effectable, ExecutionStrategy, Function, Predicate, Runtime, Scope, String, Tracer, type Types } from "effect" +import { Context, Effect, Effectable, ExecutionStrategy, Function, Predicate, Runtime, Scope, String, Tracer, type Types, type Utils } from "effect" import * as React from "react" import { Hooks } from "./hooks/index.js" import * as Memoized from "./Memoized.js" @@ -97,16 +97,276 @@ const nonReactiveTags = [Tracer.ParentSpan] as const export const isComponent = (u: unknown): u is Component => Predicate.hasProperty(u, TypeId) -export const make = ( - body: (...args: Args) => Effect.Effect -): Component<(...args: Args) => A, E, R> => Object.setPrototypeOf( +export namespace make { + export type Gen = { + >, A extends React.ReactNode, P = never>( + body: (props: P) => Generator + ): Component< + P, A, + [Eff] extends [never] ? never : [Eff] extends [Utils.YieldWrap>] ? E : never, + [Eff] extends [never] ? never : [Eff] extends [Utils.YieldWrap>] ? R : never + > + >, A, B extends Effect.Effect, P extends {} = {}>( + body: (props: P) => Generator, + a: ( + _: Effect.Effect< + A, + [Eff] extends [never] ? never : [Eff] extends [Utils.YieldWrap>] ? E : never, + [Eff] extends [never] ? never : [Eff] extends [Utils.YieldWrap>] ? R : never + >, + props: NoInfer

, + ) => B + ): Component, Effect.Effect.Context> + >, A, B, C extends Effect.Effect, P extends {} = {}>( + body: (props: P) => Generator, + a: ( + _: Effect.Effect< + A, + [Eff] extends [never] ? never : [Eff] extends [Utils.YieldWrap>] ? E : never, + [Eff] extends [never] ? never : [Eff] extends [Utils.YieldWrap>] ? R : never + >, + props: NoInfer

, + ) => B, + b: (_: B, props: NoInfer

) => C, + ): Component, Effect.Effect.Context> + >, A, B, C, D extends Effect.Effect, P extends {} = {}>( + body: (props: P) => Generator, + a: ( + _: Effect.Effect< + A, + [Eff] extends [never] ? never : [Eff] extends [Utils.YieldWrap>] ? E : never, + [Eff] extends [never] ? never : [Eff] extends [Utils.YieldWrap>] ? R : never + >, + props: NoInfer

, + ) => B, + b: (_: B, props: NoInfer

) => C, + c: (_: C, props: NoInfer

) => D, + ): Component, Effect.Effect.Context> + >, A, B, C, D, E extends Effect.Effect, P extends {} = {}>( + body: (props: P) => Generator, + a: ( + _: Effect.Effect< + A, + [Eff] extends [never] ? never : [Eff] extends [Utils.YieldWrap>] ? E : never, + [Eff] extends [never] ? never : [Eff] extends [Utils.YieldWrap>] ? R : never + >, + props: NoInfer

, + ) => B, + b: (_: B, props: NoInfer

) => C, + c: (_: C, props: NoInfer

) => D, + d: (_: D, props: NoInfer

) => E, + ): Component, Effect.Effect.Context> + >, A, B, C, D, E, F extends Effect.Effect, P extends {} = {}>( + body: (props: P) => Generator, + a: ( + _: Effect.Effect< + A, + [Eff] extends [never] ? never : [Eff] extends [Utils.YieldWrap>] ? E : never, + [Eff] extends [never] ? never : [Eff] extends [Utils.YieldWrap>] ? R : never + >, + props: NoInfer

, + ) => B, + b: (_: B, props: NoInfer

) => C, + c: (_: C, props: NoInfer

) => D, + d: (_: D, props: NoInfer

) => E, + e: (_: E, props: NoInfer

) => F, + ): Component, Effect.Effect.Context> + >, A, B, C, D, E, F, G extends Effect.Effect, P extends {} = {}>( + body: (props: P) => Generator, + a: ( + _: Effect.Effect< + A, + [Eff] extends [never] ? never : [Eff] extends [Utils.YieldWrap>] ? E : never, + [Eff] extends [never] ? never : [Eff] extends [Utils.YieldWrap>] ? R : never + >, + props: NoInfer

, + ) => B, + b: (_: B, props: NoInfer

) => C, + c: (_: C, props: NoInfer

) => D, + d: (_: D, props: NoInfer

) => E, + e: (_: E, props: NoInfer

) => F, + f: (_: F, props: NoInfer

) => G, + ): Component, Effect.Effect.Context> + >, A, B, C, D, E, F, G, H extends Effect.Effect, P extends {} = {}>( + body: (props: P) => Generator, + a: ( + _: Effect.Effect< + A, + [Eff] extends [never] ? never : [Eff] extends [Utils.YieldWrap>] ? E : never, + [Eff] extends [never] ? never : [Eff] extends [Utils.YieldWrap>] ? R : never + >, + props: NoInfer

, + ) => B, + b: (_: B, props: NoInfer

) => C, + c: (_: C, props: NoInfer

) => D, + d: (_: D, props: NoInfer

) => E, + e: (_: E, props: NoInfer

) => F, + f: (_: F, props: NoInfer

) => G, + g: (_: G, props: NoInfer

) => H, + ): Component, Effect.Effect.Context> + >, A, B, C, D, E, F, G, H, I extends Effect.Effect, P extends {} = {}>( + body: (props: P) => Generator, + a: ( + _: Effect.Effect< + A, + [Eff] extends [never] ? never : [Eff] extends [Utils.YieldWrap>] ? E : never, + [Eff] extends [never] ? never : [Eff] extends [Utils.YieldWrap>] ? R : never + >, + props: NoInfer

, + ) => B, + b: (_: B, props: NoInfer

) => C, + c: (_: C, props: NoInfer

) => D, + d: (_: D, props: NoInfer

) => E, + e: (_: E, props: NoInfer

) => F, + f: (_: F, props: NoInfer

) => G, + g: (_: G, props: NoInfer

) => H, + h: (_: H, props: NoInfer

) => I, + ): Component, Effect.Effect.Context> + >, A, B, C, D, E, F, G, H, I, J extends Effect.Effect, P extends {} = {}>( + body: (props: P) => Generator, + a: ( + _: Effect.Effect< + A, + [Eff] extends [never] ? never : [Eff] extends [Utils.YieldWrap>] ? E : never, + [Eff] extends [never] ? never : [Eff] extends [Utils.YieldWrap>] ? R : never + >, + props: NoInfer

, + ) => B, + b: (_: B, props: NoInfer

) => C, + c: (_: C, props: NoInfer

) => D, + d: (_: D, props: NoInfer

) => E, + e: (_: E, props: NoInfer

) => F, + f: (_: F, props: NoInfer

) => G, + g: (_: G, props: NoInfer

) => H, + h: (_: H, props: NoInfer

) => I, + i: (_: I, props: NoInfer

) => J, + ): Component, Effect.Effect.Context> + } + + export type NonGen = { + , P extends {} = {}>( + body: (props: P) => Eff + ): Component, Effect.Effect.Context> + , A, P extends {} = {}>( + body: (props: P) => A, + a: (_: A, props: NoInfer

) => Eff, + ): Component, Effect.Effect.Context> + , A, B, P extends {} = {}>( + body: (props: P) => A, + a: (_: A, props: NoInfer

) => B, + b: (_: B, props: NoInfer

) => Eff, + ): Component, Effect.Effect.Context> + , A, B, C, P extends {} = {}>( + body: (props: P) => A, + a: (_: A, props: NoInfer

) => B, + b: (_: B, props: NoInfer

) => C, + c: (_: C, props: NoInfer

) => Eff, + ): Component, Effect.Effect.Context> + , A, B, C, D, P extends {} = {}>( + body: (props: P) => A, + a: (_: A, props: NoInfer

) => B, + b: (_: B, props: NoInfer

) => C, + c: (_: C, props: NoInfer

) => D, + d: (_: D, props: NoInfer

) => Eff, + ): Component, Effect.Effect.Context> + , A, B, C, D, E, P extends {} = {}>( + body: (props: P) => A, + a: (_: A, props: NoInfer

) => B, + b: (_: B, props: NoInfer

) => C, + c: (_: C, props: NoInfer

) => D, + d: (_: D, props: NoInfer

) => E, + e: (_: E, props: NoInfer

) => Eff, + ): Component, Effect.Effect.Context> + , A, B, C, D, E, F, P extends {} = {}>( + body: (props: P) => A, + a: (_: A, props: NoInfer

) => B, + b: (_: B, props: NoInfer

) => C, + c: (_: C, props: NoInfer

) => D, + d: (_: D, props: NoInfer

) => E, + e: (_: E, props: NoInfer

) => F, + f: (_: F, props: NoInfer

) => Eff, + ): Component, Effect.Effect.Context> + , A, B, C, D, E, F, G, P extends {} = {}>( + body: (props: P) => A, + a: (_: A, props: NoInfer

) => B, + b: (_: B, props: NoInfer

) => C, + c: (_: C, props: NoInfer

) => D, + d: (_: D, props: NoInfer

) => E, + e: (_: E, props: NoInfer

) => F, + f: (_: F, props: NoInfer

) => G, + g: (_: G, props: NoInfer

) => Eff, + ): Component, Effect.Effect.Context> + , A, B, C, D, E, F, G, H, P extends {} = {}>( + body: (props: P) => A, + a: (_: A, props: NoInfer

) => B, + b: (_: B, props: NoInfer

) => C, + c: (_: C, props: NoInfer

) => D, + d: (_: D, props: NoInfer

) => E, + e: (_: E, props: NoInfer

) => F, + f: (_: F, props: NoInfer

) => G, + g: (_: G, props: NoInfer

) => H, + h: (_: H, props: NoInfer

) => Eff, + ): Component, Effect.Effect.Context> + , A, B, C, D, E, F, G, H, I, P extends {} = {}>( + body: (props: P) => A, + a: (_: A, props: NoInfer

) => B, + b: (_: B, props: NoInfer

) => C, + c: (_: C, props: NoInfer

) => D, + d: (_: D, props: NoInfer

) => E, + e: (_: E, props: NoInfer

) => F, + f: (_: F, props: NoInfer

) => G, + g: (_: G, props: NoInfer

) => H, + h: (_: H, props: NoInfer

) => I, + i: (_: I, props: NoInfer

) => Eff, + ): Component, Effect.Effect.Context> + } +} + +export const make: ( + & make.Gen + & make.NonGen + & (( + spanName: string, + spanOptions?: Tracer.SpanOptions, + ) => make.Gen & make.NonGen) +) = (spanNameOrBody: Function | string, ...pipeables: any[]): any => { + if (typeof spanNameOrBody !== "string") { + const displayName = displayNameFromBody(spanNameOrBody) + return Object.setPrototypeOf( + Object.assign(function() {}, defaultOptions, { + body: displayName + ? Effect.fn(displayName)(spanNameOrBody as any, ...pipeables as []) + : Effect.fn(spanNameOrBody as any, ...pipeables), + displayName, + }), + ComponentProto, + ) + } + else { + const spanOptions = pipeables[0] + return (body: any, ...pipeables: any[]) => Object.setPrototypeOf( + Object.assign(function() {}, defaultOptions, { + body: Effect.fn(spanNameOrBody, spanOptions)(body, ...pipeables as []), + displayName: displayNameFromBody(body) ?? spanNameOrBody, + }), + ComponentProto, + ) + } +} + +export const makeUntraced: make.Gen & make.NonGen = ( + body: Function, + ...pipeables: any[] +) => Object.setPrototypeOf( Object.assign(function() {}, defaultOptions, { - body, - displayName: !String.isEmpty(body.name) ? body.name : undefined, + body: Effect.fnUntraced(body as any, ...pipeables as []), + displayName: displayNameFromBody(body), }), ComponentProto, ) +const displayNameFromBody = (body: Function) => !String.isEmpty(body.name) ? body.name : undefined + export const withOptions: { >( options: Partial