0.2.2 #31

Merged
Thilawyn merged 184 commits from next into master 2026-01-16 17:05:31 +01:00
Showing only changes of commit 9801444c0a - Show all commits

View File

@@ -1,6 +1,6 @@
/** biome-ignore-all lint/complexity/noBannedTypes: {} is the default type for React props */ /** biome-ignore-all lint/complexity/noBannedTypes: {} is the default type for React props */
/** biome-ignore-all lint/complexity/useArrowFunction: necessary for class prototypes */ /** biome-ignore-all lint/complexity/useArrowFunction: necessary for class prototypes */
import { Context, Effect, Effectable, Equivalence, ExecutionStrategy, Exit, Fiber, Function, HashMap, Layer, ManagedRuntime, Option, Predicate, Ref, Runtime, Scope, Tracer, type Types, type Utils } from "effect" import { Context, type Duration, Effect, Effectable, Equivalence, ExecutionStrategy, Exit, Fiber, Function, HashMap, Layer, ManagedRuntime, Option, Predicate, Ref, Runtime, Scope, Tracer, type Types, type Utils } from "effect"
import * as React from "react" import * as React from "react"
import { Memoized } from "./index.js" import { Memoized } from "./index.js"
@@ -40,6 +40,7 @@ export namespace Component {
export interface Options { export interface Options {
readonly displayName?: string readonly displayName?: string
readonly finalizerExecutionStrategy: ExecutionStrategy.ExecutionStrategy readonly finalizerExecutionStrategy: ExecutionStrategy.ExecutionStrategy
readonly finalizerExecutionDebounce: Duration.DurationInput
} }
} }
@@ -84,6 +85,7 @@ const ComponentProto = Object.freeze({
const defaultOptions: Component.Options = { const defaultOptions: Component.Options = {
finalizerExecutionStrategy: ExecutionStrategy.sequential, finalizerExecutionStrategy: ExecutionStrategy.sequential,
finalizerExecutionDebounce: "100 millis",
} }
const nonReactiveTags = [Tracer.ParentSpan] as const const nonReactiveTags = [Tracer.ParentSpan] as const
@@ -415,6 +417,7 @@ export namespace ScopeMap {
export namespace useScope { export namespace useScope {
export interface Options { export interface Options {
readonly finalizerExecutionStrategy?: ExecutionStrategy.ExecutionStrategy readonly finalizerExecutionStrategy?: ExecutionStrategy.ExecutionStrategy
readonly finalizerExecutionDebounce?: Duration.DurationInput
} }
} }
@@ -436,7 +439,7 @@ export const useScope: {
Option.match(HashMap.get(map, key), { Option.match(HashMap.get(map, key), {
onSome: entry => Effect.succeed(entry.scope), onSome: entry => Effect.succeed(entry.scope),
onNone: () => Effect.tap( onNone: () => Effect.tap(
Scope.make(options?.finalizerExecutionStrategy ?? ExecutionStrategy.sequential), Scope.make(options?.finalizerExecutionStrategy ?? defaultOptions.finalizerExecutionStrategy),
scope => Ref.update(scopeMap.ref, HashMap.set(key, { scope => Ref.update(scopeMap.ref, HashMap.set(key, {
scope, scope,
closeFiber: Option.none(), closeFiber: Option.none(),
@@ -460,7 +463,7 @@ export const useScope: {
})), })),
Effect.map(({ scope }) => Effect.map(({ scope }) =>
() => Runtime.runSync(runtimeRef.current)(Effect.andThen( () => Runtime.runSync(runtimeRef.current)(Effect.andThen(
Effect.forkDaemon(Effect.sleep("100 millis").pipe( Effect.forkDaemon(Effect.sleep(options?.finalizerExecutionDebounce ?? defaultOptions.finalizerExecutionDebounce).pipe(
Effect.andThen(Scope.close(scope, Exit.void)), Effect.andThen(Scope.close(scope, Exit.void)),
Effect.andThen(Ref.update(scopeMap.ref, HashMap.remove(key))), Effect.andThen(Ref.update(scopeMap.ref, HashMap.remove(key))),
)), )),
@@ -528,7 +531,7 @@ const runReactEffect = <E, R>(
f: () => Effect.Effect<void, E, R>, f: () => Effect.Effect<void, E, R>,
options?: useReactEffect.Options, options?: useReactEffect.Options,
) => Effect.Do.pipe( ) => Effect.Do.pipe(
Effect.bind("scope", () => Scope.make(options?.finalizerExecutionStrategy ?? ExecutionStrategy.sequential)), Effect.bind("scope", () => Scope.make(options?.finalizerExecutionStrategy ?? defaultOptions.finalizerExecutionStrategy)),
Effect.bind("exit", ({ scope }) => Effect.exit(Effect.provideService(f(), Scope.Scope, scope))), Effect.bind("exit", ({ scope }) => Effect.exit(Effect.provideService(f(), Scope.Scope, scope))),
Effect.map(({ scope }) => Effect.map(({ scope }) =>
() => { () => {