Implement ScopeRegistry
Lint / lint (push) Failing after 42s

This commit is contained in:
Julien Valverdé
2026-07-23 01:22:14 +02:00
parent 8fed17789a
commit cb62639829
4 changed files with 253 additions and 68 deletions
+17 -45
View File
@@ -1,6 +1,6 @@
/** biome-ignore-all lint/complexity/noBannedTypes: {} is the default type for React props */
/** biome-ignore-all lint/complexity/useArrowFunction: necessary for class prototypes */
import { Cause, Context, type Duration, Effect, Equal, Equivalence, Exit, Fiber, Function, HashMap, identity, Layer, Option, Pipeable, Predicate, Ref, Scheduler, Scope, Tracer } from "effect"
import { Context, type Duration, Effect, Equivalence, Exit, Function, identity, Layer, Pipeable, Predicate, Scheduler, Scope, Tracer } from "effect"
import * as React from "react"
import * as ScopeRegistry from "./ScopeRegistry.js"
@@ -668,54 +668,26 @@ export const useScope = Effect.fnUntraced(function*(
// biome-ignore lint/style/noNonNullAssertion: context initialization
const contextRef = React.useRef<Context.Context<never>>(null!)
contextRef.current = yield* Effect.context()
const registry = yield* ScopeRegistry.ScopeRegistry as unknown as Effect.Effect<ScopeRegistry.ScopeRegistryService>
const { key, scope } = React.useMemo(() => Effect.runSyncWith(contextRef.current)(Effect.Do.pipe(
Effect.bind("scopeRegistryRef", () => Effect.map(
ScopeRegistry.ScopeRegistry as unknown as Effect.Effect<ScopeRegistry.ScopeRegistry["Service"]>,
scopeRegistry => scopeRegistry.ref,
)),
Effect.let("key", () => Equal.byReference({})),
Effect.bind("scope", () => Scope.make(options?.finalizerExecutionStrategy ?? defaultOptions.finalizerExecutionStrategy)),
Effect.tap(({ scopeRegistryRef, key, scope }) =>
Ref.update(scopeRegistryRef, HashMap.set(key, Equal.byReference({
scope,
closeFiber: Option.none(),
})))
),
const [key, scope] = React.useMemo(() => Effect.runSyncWith(contextRef.current)(Effect.gen(function*() {
const key = ScopeRegistry.makeKey()
const entry = yield* registry.register(key, {
finalizerExecutionStrategy: options?.finalizerExecutionStrategy ?? defaultOptions.finalizerExecutionStrategy,
finalizerExecutionDebounce: options?.finalizerExecutionDebounce ?? defaultOptions.finalizerExecutionDebounce,
})
return [key, entry.scope]
// biome-ignore lint/correctness/useExhaustiveDependencies: use of React.DependencyList
)), deps)
})), deps)
// biome-ignore lint/correctness/useExhaustiveDependencies: only reactive on "key"
React.useEffect(() => Effect.runSyncWith(contextRef.current)(
(ScopeRegistry.ScopeRegistry as unknown as Effect.Effect<ScopeRegistry.ScopeRegistry["Service"]>).pipe(
Effect.map(scopeRegistry => scopeRegistry.ref),
Effect.tap(ref => Ref.get(ref).pipe(
Effect.flatMap(map => Effect.fromOption(HashMap.get(map, key))),
Effect.flatMap(entry => Option.match(entry.closeFiber, {
onSome: fiber => Effect.forkDetach(Fiber.interrupt(fiber)),
onNone: () => Effect.void,
})),
)),
Effect.map(ref =>
() => Effect.runSyncWith(contextRef.current)(Effect.flatMap(
Effect.sleep(options?.finalizerExecutionDebounce ?? defaultOptions.finalizerExecutionDebounce).pipe(
Effect.andThen(Scope.close(scope, Exit.void)),
Effect.onExit(exit => Exit.match(exit, {
onSuccess: () => Ref.update(ref, HashMap.remove(key)),
onFailure: cause => Cause.hasInterruptsOnly(cause)
? Effect.void
: Ref.update(ref, HashMap.remove(key)),
})),
Effect.forkDetach,
),
fiber => Ref.update(ref, HashMap.set(key, Equal.byReference({
scope,
closeFiber: Option.some(fiber),
}))),
))
),
)
), [key])
React.useEffect(() => {
Effect.runSyncWith(contextRef.current)(registry.commit(key))
return () => {
Effect.runSyncWith(contextRef.current)(registry.release(key))
}
}, [key])
return scope
})