Refactoring
All checks were successful
Lint / lint (push) Successful in 11s

This commit is contained in:
Julien Valverdé
2025-07-17 14:24:08 +02:00
parent 671156daff
commit e8331dd395

View File

@@ -7,14 +7,18 @@ import type { ExcludeKeys } from "./utils.js"
export interface Component<E, R, P extends {}> extends Pipeable.Pipeable { export interface Component<E, R, P extends {}> extends Pipeable.Pipeable {
readonly body: (props: P) => Effect.Effect<React.ReactNode, E, R> readonly body: (props: P) => Effect.Effect<React.ReactNode, E, R>
readonly displayName?: string readonly displayName?: string
readonly finalizerExecutionMode: "sync" | "fork" readonly options: Component.Options
readonly finalizerExecutionStrategy: ExecutionStrategy.ExecutionStrategy
} }
export namespace Component { export namespace Component {
export type Error<T> = T extends Component<infer E, infer _R, infer _P> ? E : never export type Error<T> = T extends Component<infer E, infer _R, infer _P> ? E : never
export type Context<T> = T extends Component<infer _E, infer R, infer _P> ? R : never export type Context<T> = T extends Component<infer _E, infer R, infer _P> ? R : never
export type Props<T> = T extends Component<infer _E, infer _R, infer P> ? P : never export type Props<T> = T extends Component<infer _E, infer _R, infer P> ? 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(displayName)(spanNameOrBody as any, ...pipeables as [])
: Effect.fn(spanNameOrBody as any, ...pipeables), : Effect.fn(spanNameOrBody as any, ...pipeables),
displayName, displayName,
options: {},
}, ComponentProto) }, ComponentProto)
} }
else { else {
@@ -193,6 +198,7 @@ export const make: (
return (body: any, ...pipeables: any[]) => Object.setPrototypeOf({ return (body: any, ...pipeables: any[]) => Object.setPrototypeOf({
body: Effect.fn(spanNameOrBody, spanOptions)(body, ...pipeables as []), body: Effect.fn(spanNameOrBody, spanOptions)(body, ...pipeables as []),
displayName: displayNameFromBody(body) ?? spanNameOrBody, displayName: displayNameFromBody(body) ?? spanNameOrBody,
options: {},
}, ComponentProto) }, ComponentProto)
} }
} }
@@ -200,11 +206,44 @@ export const make: (
export const makeUntraced: make.Gen = (body: Function, ...pipeables: any[]) => Object.setPrototypeOf({ export const makeUntraced: make.Gen = (body: Function, ...pipeables: any[]) => Object.setPrototypeOf({
body: Effect.fnUntraced(body as any, ...pipeables as []), body: Effect.fnUntraced(body as any, ...pipeables as []),
displayName: displayNameFromBody(body), displayName: displayNameFromBody(body),
options: {},
}, ComponentProto) }, ComponentProto)
const displayNameFromBody = (body: Function) => !String.isEmpty(body.name) ? body.name : undefined const displayNameFromBody = (body: Function) => !String.isEmpty(body.name) ? body.name : undefined
export const withDisplayName: {
<T extends Component<any, any, any>>(
displayName: string
): (self: T) => T
<T extends Component<any, any, any>>(
self: T,
displayName: string,
): T
} = Function.dual(2, <T extends Component<any, any, any>>(
self: T,
displayName: string,
): T => Object.setPrototypeOf(
{ ...self, displayName },
Object.getPrototypeOf(self),
))
export const withOptions: {
<T extends Component<any, any, any>>(
options: Component.Options
): (self: T) => T
<T extends Component<any, any, any>>(
self: T,
options: Component.Options,
): T
} = Function.dual(2, <T extends Component<any, any, any>>(
self: T,
options: Component.Options,
): T => Object.setPrototypeOf(
{ ...self, options: { ...self.options, ...options } },
Object.getPrototypeOf(self),
))
export const withRuntime: { export const withRuntime: {
<E, R, P extends {}>( <E, R, P extends {}>(
context: React.Context<Runtime.Runtime<R>>, context: React.Context<Runtime.Runtime<R>>,
@@ -224,7 +263,13 @@ export const withRuntime: {
export interface Memoized<P> { export interface Memoized<P> {
readonly memo: true readonly memo: true
readonly propsAreEqual?: Equivalence.Equivalence<P> readonly memoOptions: Memoized.Options<P>
}
export namespace Memoized {
export interface Options<P> {
readonly propsAreEqual?: Equivalence.Equivalence<P>
}
} }
export const memo = <T extends Component<any, any, any>>( export const memo = <T extends Component<any, any, any>>(
@@ -248,7 +293,7 @@ export const memoWithEquivalence: {
self: ExcludeKeys<T, keyof Memoized<Component.Props<T>>>, self: ExcludeKeys<T, keyof Memoized<Component.Props<T>>>,
propsAreEqual: Equivalence.Equivalence<Component.Props<T>>, propsAreEqual: Equivalence.Equivalence<Component.Props<T>>,
): T & Memoized<Component.Props<T>> => Object.setPrototypeOf( ): T & Memoized<Component.Props<T>> => Object.setPrototypeOf(
{ ...self, memo: true, propsAreEqual }, { ...self, memo: true, memoOptions: { propsAreEqual } },
Object.getPrototypeOf(self), Object.getPrototypeOf(self),
)) ))
@@ -285,7 +330,7 @@ export const useFC: {
Array.from( Array.from(
Context.omit(...nonReactiveTags)(runtimeRef.current.context).unsafeMap.values() Context.omit(...nonReactiveTags)(runtimeRef.current.context).unsafeMap.values()
), ),
self, self.options,
)) ))
const FC = React.useMemo(() => { const FC = React.useMemo(() => {
@@ -313,7 +358,7 @@ export const useFC: {
f.displayName = self.displayName ?? "Anonymous" f.displayName = self.displayName ?? "Anonymous"
return Predicate.hasProperty(self, "memo") return Predicate.hasProperty(self, "memo")
? React.memo(f, self.propsAreEqual) ? React.memo(f, self.memoOptions.propsAreEqual)
: f : f
}, [scope]) }, [scope])