From e8331dd395c72ee60c2478514cb7f18ec68232e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Valverd=C3=A9?= Date: Thu, 17 Jul 2025 14:24:08 +0200 Subject: [PATCH] Refactoring --- packages/effect-fc/src/Component.ts | 57 ++++++++++++++++++++++++++--- 1 file changed, 51 insertions(+), 6 deletions(-) diff --git a/packages/effect-fc/src/Component.ts b/packages/effect-fc/src/Component.ts index bb01c6d..7a5efb6 100644 --- a/packages/effect-fc/src/Component.ts +++ b/packages/effect-fc/src/Component.ts @@ -7,14 +7,18 @@ import type { ExcludeKeys } from "./utils.js" export interface Component extends Pipeable.Pipeable { readonly body: (props: P) => Effect.Effect readonly displayName?: string - readonly finalizerExecutionMode: "sync" | "fork" - readonly finalizerExecutionStrategy: ExecutionStrategy.ExecutionStrategy + readonly options: Component.Options } export namespace Component { export type Error = T extends Component ? E : never export type Context = T extends Component ? R : never export type Props = T extends Component ? P : never + + export interface Options { + readonly finalizerExecutionMode: "sync" | "fork" + readonly finalizerExecutionStrategy: ExecutionStrategy.ExecutionStrategy + } } @@ -186,6 +190,7 @@ export const make: ( ? Effect.fn(displayName)(spanNameOrBody as any, ...pipeables as []) : Effect.fn(spanNameOrBody as any, ...pipeables), displayName, + options: {}, }, ComponentProto) } else { @@ -193,6 +198,7 @@ export const make: ( return (body: any, ...pipeables: any[]) => Object.setPrototypeOf({ body: Effect.fn(spanNameOrBody, spanOptions)(body, ...pipeables as []), displayName: displayNameFromBody(body) ?? spanNameOrBody, + options: {}, }, ComponentProto) } } @@ -200,11 +206,44 @@ export const make: ( export const makeUntraced: make.Gen = (body: Function, ...pipeables: any[]) => Object.setPrototypeOf({ body: Effect.fnUntraced(body as any, ...pipeables as []), displayName: displayNameFromBody(body), + options: {}, }, ComponentProto) const displayNameFromBody = (body: Function) => !String.isEmpty(body.name) ? body.name : undefined +export const withDisplayName: { + >( + displayName: string + ): (self: T) => T + >( + self: T, + displayName: string, + ): T +} = Function.dual(2, >( + self: T, + displayName: string, +): T => Object.setPrototypeOf( + { ...self, displayName }, + Object.getPrototypeOf(self), +)) + +export const withOptions: { + >( + options: Component.Options + ): (self: T) => T + >( + self: T, + options: Component.Options, + ): T +} = Function.dual(2, >( + self: T, + options: Component.Options, +): T => Object.setPrototypeOf( + { ...self, options: { ...self.options, ...options } }, + Object.getPrototypeOf(self), +)) + export const withRuntime: { ( context: React.Context>, @@ -224,7 +263,13 @@ export const withRuntime: { export interface Memoized

{ readonly memo: true - readonly propsAreEqual?: Equivalence.Equivalence

+ readonly memoOptions: Memoized.Options

+} + +export namespace Memoized { + export interface Options

{ + readonly propsAreEqual?: Equivalence.Equivalence

+ } } export const memo = >( @@ -248,7 +293,7 @@ export const memoWithEquivalence: { self: ExcludeKeys>>, propsAreEqual: Equivalence.Equivalence>, ): T & Memoized> => Object.setPrototypeOf( - { ...self, memo: true, propsAreEqual }, + { ...self, memo: true, memoOptions: { propsAreEqual } }, Object.getPrototypeOf(self), )) @@ -285,7 +330,7 @@ export const useFC: { Array.from( Context.omit(...nonReactiveTags)(runtimeRef.current.context).unsafeMap.values() ), - self, + self.options, )) const FC = React.useMemo(() => { @@ -313,7 +358,7 @@ export const useFC: { f.displayName = self.displayName ?? "Anonymous" return Predicate.hasProperty(self, "memo") - ? React.memo(f, self.propsAreEqual) + ? React.memo(f, self.memoOptions.propsAreEqual) : f }, [scope])