Update dependency jsdom to v29 - autoclosed #51

Closed
renovate-bot wants to merge 52 commits from renovate/jsdom-29.x into master
14 changed files with 154 additions and 193 deletions
Showing only changes of commit 3fc3904c6c - Show all commits
+14 -7
View File
@@ -58,17 +58,18 @@
"name": "effect-fc-next",
"version": "0.1.0-beta.0",
"dependencies": {
"effect-lens": "2.0.0-beta.0",
"effect-lens": "^2.0.0-beta.1",
},
"devDependencies": {
"@effect/platform-browser": "^4.0.0-beta.85",
"@effect/platform-browser": "4.0.0-beta.98",
"@testing-library/react": "^16.3.0",
"effect": "4.0.0-beta.98",
"jsdom": "^26.1.0",
"vitest": "^3.2.4",
},
"peerDependencies": {
"@types/react": "^19.2.0",
"effect": "4.0.0-beta.85",
"effect": "4.0.0-beta.98",
"react": "^19.2.0",
},
},
@@ -3063,11 +3064,11 @@
"dot-prop/is-obj": ["is-obj@2.0.0", "", {}, "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w=="],
"effect-fc-next/@effect/platform-browser": ["@effect/platform-browser@4.0.0-beta.87", "", { "dependencies": { "multipasta": "^0.2.7" }, "peerDependencies": { "effect": "^4.0.0-beta.87" } }, "sha512-sBUUdRt5PjFPLI7+ayxEX/jgnjCbOuc3I//98CmqiwhfgWbCMZ/rofYYb8Zk5tLpNsmdHnWgHWTsBLvH2SFrCw=="],
"effect-fc-next/@effect/platform-browser": ["@effect/platform-browser@4.0.0-beta.98", "", { "dependencies": { "multipasta": "^0.2.8" }, "peerDependencies": { "effect": "^4.0.0-beta.98" } }, "sha512-Y0BEe0N8clKmJTHqmZpS85pLZbqAxP5uV3IYF0tDw/1dcs8AbTRHjbRmOLdyLtmU32NBVAiaUD3Vopb5Et5R/g=="],
"effect-fc-next/effect": ["effect@4.0.0-beta.85", "", { "dependencies": { "@standard-schema/spec": "^1.1.0", "fast-check": "^4.8.0", "find-my-way-ts": "^0.1.6", "ini": "^7.0.0", "kubernetes-types": "^1.30.0", "msgpackr": "^2.0.1", "multipasta": "^0.2.7", "toml": "^4.1.1", "uuid": "^14.0.0", "yaml": "^2.9.0" } }, "sha512-Cjv9YQyv4CiIccmRAQIWAoeESCpCpiuHYY8zb5vqiYs3Ac2yE5RQAnKq7z4Ir/3VJYZb8kxh6rS8czDDnpTdkQ=="],
"effect-fc-next/effect": ["effect@4.0.0-beta.98", "", { "dependencies": { "@standard-schema/spec": "^1.1.0", "fast-check": "^4.9.0", "find-my-way-ts": "^0.1.6", "ini": "^7.0.0", "kubernetes-types": "^1.30.0", "msgpackr": "^2.0.4", "multipasta": "^0.2.8", "toml": "^4.1.2", "uuid": "^14.0.1", "yaml": "^2.9.0" } }, "sha512-oz+bsG5h+6RNrw4t5GMfQrk/xBS8ROoqkYsuvRhBr5O7mCOrpvH/hbw+QrDzvKIpX4HJClwm86F94c87W0sJxg=="],
"effect-fc-next/effect-lens": ["effect-lens@2.0.0-beta.0", "", { "peerDependencies": { "effect": "4.0.0-beta.85" } }, "sha512-ntsRQSrzoX+GsNpkNVEGqebl/g1YOEDPIFRAHigf+4P6AtGnnOFcklqDHLrbm4zqnaxuWEgQvvn1J6S3eyC4yw=="],
"effect-fc-next/effect-lens": ["effect-lens@2.0.0-beta.1", "", { "peerDependencies": { "effect": "4.0.0-beta.98" } }, "sha512-3MwsrezPczZHH4Tl2SvliZdiNRq9e/XbH+Vr1ckr/FPCEp6Wv8IYQL4Ie/hhI+XBiLlxbQERbgL8FlHW21avtw=="],
"esrecurse/estraverse": ["estraverse@5.3.0", "", {}, "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA=="],
@@ -3373,10 +3374,16 @@
"csso/css-tree/mdn-data": ["mdn-data@2.0.28", "", {}, "sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g=="],
"effect-fc-next/effect/fast-check": ["fast-check@4.8.0", "", { "dependencies": { "pure-rand": "^8.0.0" } }, "sha512-GOJ158CUMnN6cSahsv4+ExARvIDuzzinFjkp0E9WtiBa5zcVeLozVkWaE4IzFcc+Y48Wp1EDlUZsXRyAztQcSg=="],
"effect-fc-next/@effect/platform-browser/multipasta": ["multipasta@0.2.8", "", {}, "sha512-ZPWuMKyv0cSO29f7hozp+k6+crZbQijV8ipMvxNxRf2SwtYGTX1ZX89Kd20VV4H9Znonx+EQn+iy1wGQsJ+b+Q=="],
"effect-fc-next/effect/fast-check": ["fast-check@4.9.0", "", { "dependencies": { "pure-rand": "^8.0.0" } }, "sha512-7ms6T7SybUev/PQITciI0yLM2pOSFy5zpG8Ty7tQofcVaQUvrMXp6CBwqF6fThLCLOrfBtuHAtwq6Yu4XPCllg=="],
"effect-fc-next/effect/msgpackr": ["msgpackr@2.0.4", "", { "optionalDependencies": { "msgpackr-extract": "^3.0.4" } }, "sha512-o1C5KRmuRt+apqMr1HuGSqWStZoRBUpEsCsl15uM9VdAF1qHLtvMOU2En747EnTyEl6c4pzPewRMFF31s1CNbA=="],
"effect-fc-next/effect/multipasta": ["multipasta@0.2.8", "", {}, "sha512-ZPWuMKyv0cSO29f7hozp+k6+crZbQijV8ipMvxNxRf2SwtYGTX1ZX89Kd20VV4H9Znonx+EQn+iy1wGQsJ+b+Q=="],
"effect-fc-next/effect/toml": ["toml@4.3.0", "", {}, "sha512-lVb8X9BsPVuH0M4BKeS91tXAmJvCjQ5UIyAbQFaxkKGyUFK2RPkhwaFSQH8vbpl1d23eu/IBH+dwVMHWaq9A5A=="],
"express/debug/ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="],
"file-loader/schema-utils/ajv": ["ajv@6.15.0", "", { "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", "json-schema-traverse": "^0.4.1", "uri-js": "^4.2.2" } }, "sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw=="],
+4 -3
View File
@@ -39,17 +39,18 @@
"clean:modules": "rm -rf node_modules"
},
"devDependencies": {
"@effect/platform-browser": "^4.0.0-beta.85",
"@effect/platform-browser": "4.0.0-beta.98",
"@testing-library/react": "^16.3.0",
"effect": "4.0.0-beta.98",
"jsdom": "^26.1.0",
"vitest": "^3.2.4"
},
"peerDependencies": {
"@types/react": "^19.2.0",
"effect": "4.0.0-beta.85",
"effect": "4.0.0-beta.98",
"react": "^19.2.0"
},
"dependencies": {
"effect-lens": "2.0.0-beta.0"
"effect-lens": "^2.0.0-beta.1"
}
}
+19 -19
View File
@@ -2,7 +2,7 @@ import { Array, type Cause, Chunk, type Duration, Effect, Equal, Function, ident
import type * as React from "react"
import * as Component from "./Component.js"
import * as Lens from "./Lens.js"
import * as Subscribable from "./Subscribable.js"
import * as View from "./View.js"
export const FormTypeId: unique symbol = Symbol.for("@effect-fc/Form/Form")
@@ -18,12 +18,12 @@ extends Pipeable.Pipeable {
readonly [FormTypeId]: FormTypeId
readonly path: P
readonly value: Subscribable.Subscribable<Option.Option<A>, ER, never>
readonly value: View.View<Option.Option<A>, ER, never>
readonly encodedValue: Lens.Lens<I, ER, EW, never, never>
readonly issues: Subscribable.Subscribable<readonly FormIssue[], never, never>
readonly isValidating: Subscribable.Subscribable<boolean, never, never>
readonly canCommit: Subscribable.Subscribable<boolean, never, never>
readonly isCommitting: Subscribable.Subscribable<boolean, never, never>
readonly issues: View.View<readonly FormIssue[], never, never>
readonly isValidating: View.View<boolean, never, never>
readonly canCommit: View.View<boolean, never, never>
readonly isCommitting: View.View<boolean, never, never>
}
export class FormImpl<out P extends readonly PropertyKey[], in out A, in out I = A, in out ER = never, in out EW = never>
@@ -32,12 +32,12 @@ extends Pipeable.Class implements Form<P, A, I, ER, EW> {
constructor(
readonly path: P,
readonly value: Subscribable.Subscribable<Option.Option<A>, ER, never>,
readonly value: View.View<Option.Option<A>, ER, never>,
readonly encodedValue: Lens.Lens<I, ER, EW, never, never>,
readonly issues: Subscribable.Subscribable<readonly FormIssue[], never, never>,
readonly isValidating: Subscribable.Subscribable<boolean, never, never>,
readonly canCommit: Subscribable.Subscribable<boolean, never, never>,
readonly isCommitting: Subscribable.Subscribable<boolean, never, never>,
readonly issues: View.View<readonly FormIssue[], never, never>,
readonly isValidating: View.View<boolean, never, never>,
readonly canCommit: View.View<boolean, never, never>,
readonly isCommitting: View.View<boolean, never, never>,
) {
super()
}
@@ -71,9 +71,9 @@ export const focusObjectOn: {
return new FormImpl(
path,
Subscribable.mapOption(form.value, a => a[key]),
View.mapOption(form.value, a => a[key]),
Lens.focusObjectOn(form.encodedValue, key),
Subscribable.map(form.issues, issues => filterIssuesByPath(issues, path)),
View.map(form.issues, issues => filterIssuesByPath(issues, path)),
form.isValidating,
form.canCommit,
form.isCommitting,
@@ -97,9 +97,9 @@ export const focusArrayAt: {
return new FormImpl(
path,
Subscribable.mapOptionEffect(form.value, values => Effect.fromOption(Array.get(values, index))),
View.mapOptionEffect(form.value, values => Effect.fromOption(Array.get(values, index))),
Lens.focusArrayAt(form.encodedValue, index),
Subscribable.map(form.issues, issues => filterIssuesByPath(issues, path)),
View.map(form.issues, issues => filterIssuesByPath(issues, path)),
form.isValidating,
form.canCommit,
form.isCommitting,
@@ -123,9 +123,9 @@ export const focusTupleAt: {
return new FormImpl(
path,
Subscribable.mapOption(form.value, values => values[index]),
View.mapOption(form.value, values => values[index]),
Lens.focusTupleAt(form.encodedValue, index),
Subscribable.map(form.issues, issues => filterIssuesByPath(issues, path)),
View.map(form.issues, issues => filterIssuesByPath(issues, path)),
form.isValidating,
form.canCommit,
form.isCommitting,
@@ -149,9 +149,9 @@ export const focusChunkAt: {
return new FormImpl(
path,
Subscribable.mapOptionEffect(form.value, values => Effect.fromOption(Chunk.get(values, index))),
View.mapOptionEffect(form.value, values => Effect.fromOption(Chunk.get(values, index))),
Lens.focusChunkAt(form.encodedValue, index),
Subscribable.map(form.issues, issues => filterIssuesByPath(issues, path)),
View.map(form.issues, issues => filterIssuesByPath(issues, path)),
form.isValidating,
form.canCommit,
form.isCommitting,
+14 -14
View File
@@ -1,26 +1,26 @@
import { type Context, Effect, Equal, Exit, type Fiber, Option, Pipeable, Predicate, type Scope, Stream, SubscriptionRef } from "effect"
import { AsyncResult } from "effect/unstable/reactivity"
import * as Lens from "./Lens.js"
import type * as Subscribable from "./Subscribable.js"
import * as View from "./View.js"
export const MutationTypeId: unique symbol = Symbol.for("@effect-fc/Mutation/Mutation")
export type MutationTypeId = typeof MutationTypeId
export interface Mutation<in out K, in out A, in out E = never, in out R = never>
export interface Mutation<in out K, out A, out E = never, in out R = never>
extends Pipeable.Pipeable {
readonly [MutationTypeId]: MutationTypeId
readonly context: Context.Context<Scope.Scope | R>
readonly f: (key: K) => Effect.Effect<A, E, R>
readonly latestKey: Subscribable.Subscribable<Option.Option<K>>
readonly fiber: Subscribable.Subscribable<Option.Option<Fiber.Fiber<A, E>>>
readonly result: Subscribable.Subscribable<AsyncResult.AsyncResult<A, E>>
readonly latestFinalResult: Subscribable.Subscribable<Option.Option<AsyncResult.Success<A, E> | AsyncResult.Failure<A, E>>>
readonly latestKey: View.View<Option.Option<K>>
readonly fiber: View.View<Option.Option<Fiber.Fiber<A, E>>>
readonly state: View.View<AsyncResult.AsyncResult<A, E>>
readonly latestFinalResult: View.View<Option.Option<AsyncResult.Success<A, E> | AsyncResult.Failure<A, E>>>
mutate(key: K): Effect.Effect<AsyncResult.Success<A, E> | AsyncResult.Failure<A, E>>
mutateSubscribable(key: K): Effect.Effect<Subscribable.Subscribable<AsyncResult.AsyncResult<A, E>>>
mutateView(key: K): Effect.Effect<View.View<AsyncResult.AsyncResult<A, E>>>
}
export const isMutation = (u: unknown): u is Mutation<unknown, unknown, unknown, unknown> => Predicate.hasProperty(u, MutationTypeId)
@@ -36,7 +36,7 @@ extends Pipeable.Class implements Mutation<K, A, E, R> {
readonly latestKey: Lens.Lens<Option.Option<K>>,
readonly fiber: Lens.Lens<Option.Option<Fiber.Fiber<A, E>>>,
readonly result: Lens.Lens<AsyncResult.AsyncResult<A, E>>,
readonly state: Lens.Lens<AsyncResult.AsyncResult<A, E>>,
readonly latestFinalResult: Lens.Lens<Option.Option<AsyncResult.Success<A, E> | AsyncResult.Failure<A, E>>>,
) {
super()
@@ -49,7 +49,7 @@ extends Pipeable.Class implements Mutation<K, A, E, R> {
Effect.provide(this.context),
)
}
mutateSubscribable(key: K): Effect.Effect<Subscribable.Subscribable<AsyncResult.AsyncResult<A, E>>> {
mutateView(key: K): Effect.Effect<View.View<AsyncResult.AsyncResult<A, E>>> {
return Lens.set(this.latestKey, Option.some(key)).pipe(
Effect.andThen(this.start(key)),
Effect.tap(state => Effect.forkScoped(this.watch(state))),
@@ -58,7 +58,7 @@ extends Pipeable.Class implements Mutation<K, A, E, R> {
}
start(key: K): Effect.Effect<
Subscribable.Subscribable<AsyncResult.AsyncResult<A, E>>,
View.View<AsyncResult.AsyncResult<A, E>>,
never,
Scope.Scope | R
> {
@@ -114,13 +114,13 @@ extends Pipeable.Class implements Mutation<K, A, E, R> {
}
watch(
state: Subscribable.Subscribable<AsyncResult.AsyncResult<A, E>>
state: View.View<AsyncResult.AsyncResult<A, E>>
): Effect.Effect<AsyncResult.Success<A, E> | AsyncResult.Failure<A, E>> {
return state.get.pipe(
return View.get(state).pipe(
Effect.andThen(initial => Stream.runFoldEffect(
state.changes,
View.changes(state),
() => initial,
(_, result) => Effect.as(Lens.set(this.result, result), result),
(_, result) => Effect.as(Lens.set(this.state, result), result),
) as Effect.Effect<AsyncResult.Success<A, E> | AsyncResult.Failure<A, E>>),
Effect.tap(result => Lens.set(this.latestFinalResult, Option.some(result))),
)
+28 -28
View File
@@ -2,44 +2,44 @@ import { type Cause, type Context, Duration, Effect, Equal, type Equivalence, Ex
import { AsyncResult } from "effect/unstable/reactivity"
import * as Lens from "./Lens.js"
import * as QueryClient from "./QueryClient.js"
import * as Subscribable from "./Subscribable.js"
import * as View from "./View.js"
export const QueryTypeId: unique symbol = Symbol.for("@effect-fc/Query/Query")
export type QueryTypeId = typeof QueryTypeId
export interface Query<in out K, in out A, in out E = never, in out R = never>
export interface Query<in out K, out A, out E = never, in out R = never>
extends Pipeable.Pipeable {
readonly [QueryTypeId]: QueryTypeId
readonly context: Context.Context<Scope.Scope | QueryClient.QueryClient | R>
readonly key: Subscribable.Subscribable<K>
readonly key: View.View<K>
readonly keyEquivalence: Equivalence.Equivalence<K>
readonly f: (key: K) => Effect.Effect<A, E, R>
readonly staleTime: Duration.Duration
readonly refreshOnWindowFocus: boolean
readonly fiber: Subscribable.Subscribable<Option.Option<Fiber.Fiber<A, E>>>
readonly state: Subscribable.Subscribable<QueryState<K, A, E>>
readonly latestFinalState: Subscribable.Subscribable<Option.Option<FinalQueryState<K, A, E>>>
readonly fiber: View.View<Option.Option<Fiber.Fiber<A, E>>>
readonly state: View.View<QueryState<K, A, E>>
readonly latestFinalState: View.View<Option.Option<FinalQueryState<K, A, E>>>
readonly run: Effect.Effect<void>
fetch(key: K): Effect.Effect<FinalQueryState<K, A, E>, Cause.NoSuchElementError>
fetchSubscribable(key: K): Effect.Effect<Subscribable.Subscribable<QueryState<K, A, E>>, Cause.NoSuchElementError>
fetchView(key: K): Effect.Effect<View.View<QueryState<K, A, E>>, Cause.NoSuchElementError>
readonly refresh: Effect.Effect<FinalQueryState<K, A, E>, Cause.NoSuchElementError>
readonly refreshSubscribable: Effect.Effect<Subscribable.Subscribable<QueryState<K, A, E>>, Cause.NoSuchElementError>
readonly refreshView: Effect.Effect<View.View<QueryState<K, A, E>>, Cause.NoSuchElementError>
readonly invalidateCache: Effect.Effect<void>
invalidateCacheEntry(key: K): Effect.Effect<void>
}
export interface QueryState<in out K, in out A, in out E = never> {
export interface QueryState<out K, out A, out E = never> {
readonly key: K
readonly result: AsyncResult.AsyncResult<A, E>
}
export interface FinalQueryState<in out K, in out A, in out E = never> {
export interface FinalQueryState<out K, out A, out E = never> {
readonly key: K
readonly result: AsyncResult.Success<A, E> | AsyncResult.Failure<A, E>
}
@@ -53,7 +53,7 @@ extends Pipeable.Class implements Query<K, A, E, R> {
constructor(
readonly context: Context.Context<Scope.Scope | QueryClient.QueryClient | R>,
readonly key: Subscribable.Subscribable<K>,
readonly key: View.View<K>,
readonly keyEquivalence: Equivalence.Equivalence<K>,
readonly f: (key: K) => Effect.Effect<A, E, R>,
@@ -94,7 +94,7 @@ extends Pipeable.Class implements Query<K, A, E, R> {
Effect.flatMap(({ BrowserStream }) => this.refreshOnWindowFocus
? Stream.runForEach(
BrowserStream.fromEventListenerWindow("focus"),
() => this.refreshSubscribable,
() => this.refreshView,
)
: Effect.void
),
@@ -127,8 +127,8 @@ extends Pipeable.Class implements Query<K, A, E, R> {
)
}
fetchSubscribable(key: K): Effect.Effect<
Subscribable.Subscribable<QueryState<K, A, E>>,
fetchView(key: K): Effect.Effect<
View.View<QueryState<K, A, E>>,
Cause.NoSuchElementError
> {
return Effect.gen({ self: this }, function*() {
@@ -166,8 +166,8 @@ extends Pipeable.Class implements Query<K, A, E, R> {
)
}
get refreshSubscribable(): Effect.Effect<
Subscribable.Subscribable<QueryState<K, A, E>>,
get refreshView(): Effect.Effect<
View.View<QueryState<K, A, E>>,
Cause.NoSuchElementError
> {
return Effect.gen({ self: this }, function*() {
@@ -194,7 +194,7 @@ extends Pipeable.Class implements Query<K, A, E, R> {
startCached(
previous: QueryState<K, A, E>,
): Effect.Effect<
Subscribable.Subscribable<QueryState<K, A, E>>,
View.View<QueryState<K, A, E>>,
Cause.NoSuchElementError,
Scope.Scope | QueryClient.QueryClient | R
> {
@@ -206,7 +206,7 @@ extends Pipeable.Class implements Query<K, A, E, R> {
key: previous.key,
result: entry.result as AsyncResult.AsyncResult<A, E>,
})
: Effect.succeed(Subscribable.make({
: Effect.succeed(View.make({
get: Effect.succeed({
key: previous.key,
result: entry.result as AsyncResult.AsyncResult<A, E>,
@@ -226,15 +226,15 @@ extends Pipeable.Class implements Query<K, A, E, R> {
start(
previous: QueryState<K, A, E>,
): Effect.Effect<
Subscribable.Subscribable<QueryState<K, A, E>>,
View.View<QueryState<K, A, E>>,
never,
Scope.Scope | R
> {
return Effect.gen({ self: this }, function*() {
const subscribable = Lens.fromSubscriptionRef(yield* SubscriptionRef.make(previous))
const state = Lens.fromSubscriptionRef(yield* SubscriptionRef.make(previous))
const fiber = yield* Effect.forkScoped(Effect.andThen(
Lens.update(subscribable, previous => AsyncResult.match(previous.result, {
Lens.update(state, previous => AsyncResult.match(previous.result, {
onInitial: () => ({
key: previous.key,
result: AsyncResult.initial(true),
@@ -255,7 +255,7 @@ extends Pipeable.Class implements Query<K, A, E, R> {
})),
Effect.onExit(this.f(previous.key), exit => Lens.update(
subscribable,
state,
previous => Exit.match(exit, {
onSuccess: v => ({
key: previous.key,
@@ -295,17 +295,17 @@ extends Pipeable.Class implements Query<K, A, E, R> {
))
yield* Lens.set(this.fiber, Option.some(fiber))
return subscribable
return state
})
}
watch(
subscribable: Subscribable.Subscribable<QueryState<K, A, E>>
view: View.View<QueryState<K, A, E>>
): Effect.Effect<FinalQueryState<K, A, E>, never, QueryClient.QueryClient> {
return Effect.gen({ self: this }, function*() {
const initial = yield* subscribable.get
const initial = yield* View.get(view)
const final = yield* Stream.runFoldEffect(
subscribable.changes,
View.changes(view),
() => initial,
(_, state) => Effect.as(Lens.set(this.state, state), state),
) as Effect.Effect<FinalQueryState<K, A, E>>
@@ -367,7 +367,7 @@ extends Pipeable.Class implements Query<K, A, E, R> {
export declare namespace make {
export interface Options<K, A, E = never, R = never> {
readonly key: Subscribable.Subscribable<K>,
readonly key: View.View<K>,
readonly keyEquivalence?: Equivalence.Equivalence<K>,
readonly f: (key: K) => Effect.Effect<A, E, R>
@@ -396,7 +396,7 @@ export const make = Effect.fnUntraced(function* <K, A, E = never, R = never>(
Lens.fromSubscriptionRef(yield* SubscriptionRef.make(Option.none<Fiber.Fiber<A, E>>())),
Lens.fromSubscriptionRef(yield* SubscriptionRef.make<QueryState<K, A, E>>({
key: yield* options.key.get,
key: yield* View.get(options.key),
result: AsyncResult.initial(false),
})),
Lens.fromSubscriptionRef(yield* SubscriptionRef.make(Option.none<FinalQueryState<K, A, E>>())),
+2 -2
View File
@@ -1,7 +1,7 @@
import { type Cause, Context, DateTime, Duration, Effect, Equal, Equivalence, Hash, HashMap, type Option, Pipeable, Predicate, Schedule, type Scope, Semaphore, SubscriptionRef } from "effect"
import type { AsyncResult } from "effect/unstable/reactivity"
import * as Lens from "./Lens.js"
import type * as Subscribable from "./Subscribable.js"
import type * as View from "./View.js"
export const QueryClientServiceTypeId: unique symbol = Symbol.for("@effect-fc/QueryClient/QueryClientService")
@@ -10,7 +10,7 @@ export type QueryClientServiceTypeId = typeof QueryClientServiceTypeId
export interface QueryClientService extends Pipeable.Pipeable {
readonly [QueryClientServiceTypeId]: QueryClientServiceTypeId
readonly cache: Subscribable.Subscribable<HashMap.HashMap<QueryClientCacheKey, QueryClientCacheEntry>>
readonly cache: View.View<HashMap.HashMap<QueryClientCacheKey, QueryClientCacheEntry>>
readonly cacheGcTime: Duration.Duration
readonly defaultStaleTime: Duration.Duration
readonly defaultRefreshOnWindowFocus: boolean
+4 -3
View File
@@ -1,5 +1,6 @@
import { Cause, Context, Data, Effect, Equal, Exit, type Fiber, Hash, Layer, Match, Pipeable, Predicate, pipe, type Scope, SubscriptionRef } from "effect"
import { Lens, Subscribable } from "effect-lens"
import { Lens } from "effect-lens"
import type { View } from "effect-lens/View"
export const ResultTypeId: unique symbol = Symbol.for("@effect-fc/Result/Result")
@@ -207,7 +208,7 @@ export const unsafeForkEffect = Effect.fnUntraced(function* <A, E, R, P = never>
effect: Effect.Effect<A, E, R>,
options?: unsafeForkEffect.Options<NoInfer<A>, NoInfer<E>, P>,
): Effect.fn.Return<
readonly [result: Subscribable.Subscribable<Result<A, E, P>, never, never>, fiber: Fiber.Fiber<A, E>],
readonly [result: View<Result<A, E, P>, never, never>, fiber: Fiber.Fiber<A, E>],
never,
Scope.Scope | unsafeForkEffect.OutputContext<R, P>
> {
@@ -242,7 +243,7 @@ export const forkEffect: {
effect: Effect.Effect<A, E, forkEffect.InputContext<R, NoInfer<P>>>,
options?: forkEffect.Options<NoInfer<A>, NoInfer<E>, P>,
): Effect.Effect<
readonly [result: Subscribable.Subscribable<Result<A, E, P>, never, never>, fiber: Fiber.Fiber<A, E>],
readonly [result: View<Result<A, E, P>, never, never>, fiber: Fiber.Fiber<A, E>],
never,
Scope.Scope | forkEffect.OutputContext<R, P>
>
+10 -10
View File
@@ -18,7 +18,7 @@ import * as Form from "./Form.js"
import * as Lens from "./Lens.js"
import * as Mutation from "./Mutation.js"
import * as Result from "./Result.js"
import * as Subscribable from "./Subscribable.js"
import * as View from "./View.js"
type FormSchema<A, I, R> = Schema.Top & {
@@ -39,7 +39,7 @@ extends Form.Form<readonly [], A, I, never, never> {
readonly [value: A, form: SubmittableForm<A, I, R, unknown, unknown, unknown>],
MA, ME, MR, MP
>
readonly validationFiber: Subscribable.Subscribable<Option.Option<Fiber.Fiber<A, SchemaIssue.Issue>>, never, never>
readonly validationFiber: View.View<Option.Option<Fiber.Fiber<A, SchemaIssue.Issue>>, never, never>
readonly run: Effect.Effect<void>
readonly submit: Effect.Effect<Option.Option<Result.Final<MA, ME, MP>>, Cause.NoSuchElementError>
}
@@ -50,9 +50,9 @@ extends Pipeable.Class implements SubmittableForm<A, I, R, MA, ME, MR, MP> {
readonly [SubmittableFormTypeId]: SubmittableFormTypeId = SubmittableFormTypeId
readonly path = [] as const
readonly encodedValue: Lens.Lens<I, never, never, never, never>
readonly isValidating: Subscribable.Subscribable<boolean, never, never>
readonly canCommit: Subscribable.Subscribable<boolean, never, never>
readonly isCommitting: Subscribable.Subscribable<boolean, never, never>
readonly isValidating: View.View<boolean, never, never>
readonly canCommit: View.View<boolean, never, never>
readonly isCommitting: View.View<boolean, never, never>
constructor(
readonly schema: FormSchema<A, I, R>,
@@ -77,26 +77,26 @@ extends Pipeable.Class implements SubmittableForm<A, I, R, MA, ME, MR, MP> {
),
lock: Lens.asLensImpl(internalEncodedValue).lock,
})
this.isValidating = Subscribable.map(validationFiber, Option.isSome)
const commitState = Subscribable.zipLatestAll(
this.isValidating = View.map(validationFiber, Option.isSome)
const commitState = View.zipLatestAll(
value as any,
issues as any,
validationFiber as any,
mutation.result as any,
) as unknown as Subscribable.Subscribable<readonly [
) as unknown as View.View<readonly [
Option.Option<A>,
readonly Form.FormIssue[],
Option.Option<Fiber.Fiber<A, SchemaIssue.Issue>>,
Result.Result<MA, ME, MP>,
]>
this.canCommit = Subscribable.map(
this.canCommit = View.map(
commitState,
([current, currentIssues, fiber, result]: readonly [Option.Option<A>, readonly Form.FormIssue[], Option.Option<Fiber.Fiber<A, SchemaIssue.Issue>>, Result.Result<MA, ME, MP>]) => Option.isSome(current)
&& currentIssues.length === 0
&& Option.isNone(fiber)
&& !(Result.isRunning(result) || Result.hasRefreshingFlag(result)),
)
this.isCommitting = Subscribable.map(
this.isCommitting = View.map(
mutation.result,
result => Result.isRunning(result) || Result.hasRefreshingFlag(result),
)
@@ -1,53 +0,0 @@
import { Effect, Equivalence, Stream } from "effect"
import { Subscribable } from "effect-lens"
import * as React from "react"
import * as Component from "./Component.js"
export * from "effect-lens/Subscribable"
export const zipLatestAll = <const T extends readonly Subscribable.Subscribable<any, any, any>[]>(
...elements: T
): Subscribable.Subscribable<
[T[number]] extends [never]
? never
: { [K in keyof T]: T[K] extends Subscribable.Subscribable<infer A, infer _E, infer _R> ? A : never },
[T[number]] extends [never] ? never : T[number] extends Subscribable.Subscribable<infer _A, infer E, infer _R> ? E : never,
[T[number]] extends [never] ? never : T[number] extends Subscribable.Subscribable<infer _A, infer _E, infer R> ? R : never
> => Subscribable.make({
get: Effect.all(elements.map(v => v.get)),
changes: Stream.zipLatestAll(...elements.map(v => v.changes)),
}) as any
export declare namespace useAll {
export type Success<T extends readonly Subscribable.Subscribable<any, any, any>[]> = [T[number]] extends [never]
? never
: { [K in keyof T]: T[K] extends Subscribable.Subscribable<infer A, infer _E, infer _R> ? A : never }
export interface Options<A> {
readonly equivalence?: Equivalence.Equivalence<A>
}
}
export const useAll = Effect.fnUntraced(function* <const T extends readonly Subscribable.Subscribable<any, any, any>[]>(
elements: T,
options?: useAll.Options<useAll.Success<NoInfer<T>>>,
): Effect.fn.Return<
useAll.Success<T>,
[T[number]] extends [never] ? never : T[number] extends Subscribable.Subscribable<infer _A, infer E, infer _R> ? E : never,
[T[number]] extends [never] ? never : T[number] extends Subscribable.Subscribable<infer _A, infer _E, infer R> ? R : never
> {
const [reactStateValue, setReactStateValue] = React.useState(
yield* Component.useOnMount(() => Effect.all(elements.map(v => v.get)))
)
yield* Component.useReactEffect(() => Stream.zipLatestAll(...elements.map(ref => ref.changes)).pipe(
Stream.changesWith((options?.equivalence as Equivalence.Equivalence<any[]> | undefined) ?? Equivalence.Array(Equivalence.strictEqual())),
Stream.runForEach(v =>
Effect.sync(() => setReactStateValue(v))
),
Effect.forkScoped,
), elements)
return reactStateValue as any
})
@@ -17,7 +17,7 @@ import {
} from "effect"
import * as Form from "./Form.js"
import * as Lens from "./Lens.js"
import * as Subscribable from "./Subscribable.js"
import * as View from "./View.js"
type FormSchema<A, I, R> = Schema.Top & {
@@ -43,7 +43,7 @@ export interface SynchronizedForm<
readonly schema: FormSchema<A, I, R>
readonly context: Context.Context<Scope.Scope | R | TRR | TRW>
readonly target: Lens.Lens<A, TER, TEW, TRR, TRW>
readonly validationFiber: Subscribable.Subscribable<Option.Option<Fiber.Fiber<A, SchemaIssue.Issue>>, never, never>
readonly validationFiber: View.View<Option.Option<Fiber.Fiber<A, SchemaIssue.Issue>>, never, never>
readonly run: Effect.Effect<void, TER>
}
@@ -59,10 +59,10 @@ export class SynchronizedFormImpl<
readonly [Form.FormTypeId]: Form.FormTypeId = Form.FormTypeId
readonly [SynchronizedFormTypeId]: SynchronizedFormTypeId = SynchronizedFormTypeId
readonly path = [] as const
readonly value: Subscribable.Subscribable<Option.Option<A>, TER, never>
readonly value: View.View<Option.Option<A>, TER, never>
readonly encodedValue: Lens.Lens<I, TER, TER | TEW, never, never>
readonly isValidating: Subscribable.Subscribable<boolean, never, never>
readonly canCommit: Subscribable.Subscribable<boolean, never, never>
readonly isValidating: View.View<boolean, never, never>
readonly canCommit: View.View<boolean, never, never>
constructor(
readonly schema: FormSchema<A, I, R>,
@@ -75,7 +75,7 @@ export class SynchronizedFormImpl<
readonly runSemaphore: Semaphore.Semaphore,
) {
super()
this.value = Subscribable.make({
this.value = View.make({
get: Effect.provide(Effect.map(target.get, Option.some), context),
changes: Stream.provideContext(
target.changes.pipe(
@@ -94,13 +94,13 @@ export class SynchronizedFormImpl<
),
lock: Lens.asLensImpl(internalEncodedValue).lock,
}) as unknown as Lens.Lens<I, TER, TER | TEW, never, never>
this.isValidating = Subscribable.map(validationFiber, Option.isSome)
const commitState = Subscribable.zipLatestAll(issues as any, validationFiber as any, isCommitting as any) as unknown as Subscribable.Subscribable<readonly [
this.isValidating = View.map(validationFiber, Option.isSome)
const commitState = View.zipLatestAll(issues as any, validationFiber as any, isCommitting as any) as unknown as View.View<readonly [
readonly Form.FormIssue[],
Option.Option<Fiber.Fiber<A, SchemaIssue.Issue>>,
boolean,
]>
this.canCommit = Subscribable.map(
this.canCommit = View.map(
commitState,
([currentIssues, fiber, committing]) => currentIssues.length === 0 && Option.isNone(fiber) && !committing,
)
+40
View File
@@ -0,0 +1,40 @@
import { Effect, Equivalence, Stream } from "effect"
import { View } from "effect-lens"
import * as React from "react"
import * as Component from "./Component.js"
export * from "effect-lens/View"
export declare namespace useAll {
export type Success<T extends readonly View.View<any, any, any>[]> = [T[number]] extends [never]
? never
: { [K in keyof T]: T[K] extends View.View<infer A, infer _E, infer _R> ? A : never }
export interface Options<A> {
readonly equivalence?: Equivalence.Equivalence<A>
}
}
export const useAll = Effect.fnUntraced(function* <const T extends readonly View.View<any, any, any>[]>(
elements: T,
options?: useAll.Options<useAll.Success<NoInfer<T>>>,
): Effect.fn.Return<
useAll.Success<T>,
[T[number]] extends [never] ? never : T[number] extends View.View<infer _A, infer E, infer _R> ? E : never,
[T[number]] extends [never] ? never : T[number] extends View.View<infer _A, infer _E, infer R> ? R : never
> {
const [reactStateValue, setReactStateValue] = React.useState(
yield* Component.useOnMount(() => Effect.all(elements.map(View.get)))
)
yield* Component.useReactEffect(() => View.changes(View.zipLatestAll(...elements)).pipe(
Stream.changesWith((options?.equivalence as Equivalence.Equivalence<any[]> | undefined) ?? Equivalence.Array(Equivalence.strictEqual())),
Stream.runForEach(v =>
Effect.sync(() => setReactStateValue(v))
),
Effect.forkScoped,
), elements)
return reactStateValue as any
})
+1 -1
View File
@@ -13,5 +13,5 @@ export * as Result from "./Result.js"
export * as SetStateAction from "./SetStateAction.js"
export * as Stream from "./Stream.js"
export * as SubmittableForm from "./SubmittableForm.js"
export * as Subscribable from "./Subscribable.js"
export * as SynchronizedForm from "./SynchronizedForm.js"
export * as View from "./View.js"
@@ -1,10 +1,10 @@
import { render, screen, waitFor } from "@testing-library/react"
import { Effect, Fiber, Layer, Stream, SubscriptionRef } from "effect"
import { Effect, Layer, SubscriptionRef } from "effect"
import { Lens } from "effect-lens"
import { describe, expect, it } from "vitest"
import * as Component from "../src/Component.js"
import * as ReactRuntime from "../src/ReactRuntime.js"
import * as Subscribable from "../src/Subscribable.js"
import * as View from "../src/View.js"
const makeRuntime = async () => {
@@ -18,42 +18,7 @@ const makeRuntime = async () => {
}
}
describe("Subscribable", () => {
it("zipLatestAll reads current values from all inputs", async () => {
const leftRef = await Effect.runPromise(SubscriptionRef.make(1))
const rightRef = await Effect.runPromise(SubscriptionRef.make("a"))
const left = Lens.fromSubscriptionRef(leftRef)
const right = Lens.fromSubscriptionRef(rightRef)
const zipped = Subscribable.zipLatestAll(left, right)
expect(await Effect.runPromise(zipped.get)).toEqual([1, "a"])
})
it("zipLatestAll emits updates when any input changes", async () => {
const leftRef = await Effect.runPromise(SubscriptionRef.make(1))
const rightRef = await Effect.runPromise(SubscriptionRef.make("a"))
const left = Lens.fromSubscriptionRef(leftRef)
const right = Lens.fromSubscriptionRef(rightRef)
const zipped = Subscribable.zipLatestAll(left, right)
const values: Array<readonly [number, string]> = []
const collector = Effect.runFork(Effect.scoped(zipped.changes.pipe(
Stream.runForEach(value => Effect.sync(() => {
values.push(value as readonly [number, string])
})),
)))
await Effect.runPromise(Lens.set(left, 2))
await waitFor(() => expect(values).toContainEqual([2, "a"]))
await Effect.runPromise(Lens.set(right, "b"))
await waitFor(() => expect(values).toContainEqual([2, "b"]))
await Effect.runPromise(Fiber.interrupt(collector))
})
describe("View", () => {
it("useAll returns the latest values and rerenders when any input changes", async () => {
const { runtime, effectRuntime, dispose } = await makeRuntime()
const countRef = await Effect.runPromise(SubscriptionRef.make(1))
@@ -61,8 +26,8 @@ describe("Subscribable", () => {
const count = Lens.fromSubscriptionRef(countRef)
const label = Lens.fromSubscriptionRef(labelRef)
const Probe = Component.makeUntraced("SubscribableUseAllProbe")(function*() {
const [currentCount, currentLabel] = yield* Subscribable.useAll([count, label])
const Probe = Component.makeUntraced("ViewUseAllProbe")(function*() {
const [currentCount, currentLabel] = yield* View.useAll([count, label])
return <div>{`${currentCount}:${currentLabel}`}</div>
}).pipe(
@@ -94,8 +59,8 @@ describe("Subscribable", () => {
const item = Lens.fromSubscriptionRef(itemRef)
const flag = Lens.fromSubscriptionRef(flagRef)
const Probe = Component.makeUntraced("SubscribableUseAllEquivalenceProbe")(function*() {
const [currentItem, currentFlag] = yield* Subscribable.useAll([item, flag], {
const Probe = Component.makeUntraced("ViewUseAllEquivalenceProbe")(function*() {
const [currentItem, currentFlag] = yield* View.useAll([item, flag], {
equivalence: ([selfItem, selfFlag], [thatItem, thatFlag]) =>
selfItem.id === thatItem.id && selfFlag === thatFlag,
})
+2 -2
View File
@@ -1,5 +1,5 @@
import { Effect, Layer, SubscriptionRef } from "effect"
import { Component, Lens, ReactRuntime, Subscribable } from "effect-fc-next"
import { Component, Lens, ReactRuntime, View } from "effect-fc-next"
import { StrictMode } from "react"
import { createRoot } from "react-dom/client"
import "./index.css"
@@ -10,7 +10,7 @@ const Counter = Component.make("Counter")(function*() {
SubscriptionRef.make(0),
Lens.fromSubscriptionRef,
))
const [value] = yield* Subscribable.useAll([count])
const [value] = yield* View.useAll([count])
const increment = yield* Component.useCallbackSync(
() => Lens.update(count, n => n + 1),
[count],