diff --git a/.changeset/slimy-moons-share.md b/.changeset/slimy-moons-share.md new file mode 100644 index 0000000..1828047 --- /dev/null +++ b/.changeset/slimy-moons-share.md @@ -0,0 +1,5 @@ +--- +"@effect-rx/rx": patch +--- + +api cleanup diff --git a/docs/rx/Result.ts.md b/docs/rx/Result.ts.md index 51ece9a..51cdb22 100644 --- a/docs/rx/Result.ts.md +++ b/docs/rx/Result.ts.md @@ -147,7 +147,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const waiting: (previous: Option.Option | Failure>) => Waiting +export declare const waiting: (previous: Initial | Success | Failure) => Waiting ``` Added in v1.0.0 @@ -248,7 +248,7 @@ Added in v1.0.0 ```ts export interface Waiting extends Result.Variance { readonly _tag: 'Waiting' - readonly previous: Option.Option | Failure> + readonly previous: Initial | Success | Failure } ``` diff --git a/docs/rx/Rx.ts.md b/docs/rx/Rx.ts.md index 2a6a082..8a197b9 100644 --- a/docs/rx/Rx.ts.md +++ b/docs/rx/Rx.ts.md @@ -37,10 +37,12 @@ Added in v1.0.0 - [Get (type alias)](#get-type-alias) - [GetResult (type alias)](#getresult-type-alias) - [Mount (type alias)](#mount-type-alias) + - [Read (type alias)](#read-type-alias) - [Refresh (type alias)](#refresh-type-alias) - [Set (type alias)](#set-type-alias) - [Subscribe (type alias)](#subscribe-type-alias) - [SubscribeGetter (type alias)](#subscribegetter-type-alias) + - [Write (type alias)](#write-type-alias) - [RxResultFn (interface)](#rxresultfn-interface) - [RxRuntime (interface)](#rxruntime-interface) - [Writable (interface)](#writable-interface) @@ -95,9 +97,9 @@ Added in v1.0.0 ```ts export declare const effect: { - (create: (get: Rx.Get, ctx: Context) => Effect.Effect): Rx> + (create: Rx.Read>): Rx> ( - create: (get: Rx.Get, ctx: Context) => Effect.Effect, + create: Rx.Read>, options: { readonly runtime: RxRuntime } ): Rx> } @@ -136,10 +138,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const readable: ( - read: (get: Rx.Get, ctx: Context) => A, - refresh?: (f: (rx: Rx) => void) => void -) => Rx +export declare const readable: (read: Rx.Read, refresh?: (f: (rx: Rx) => void) => void) => Rx ``` Added in v1.0.0 @@ -163,9 +162,9 @@ Added in v1.0.0 ```ts export declare const scoped: { - (create: (get: Rx.Get, ctx: Context) => Effect.Effect): Rx> + (create: Rx.Read>): Rx> ( - create: (get: Rx.Get, ctx: Context) => Effect.Effect, + create: Rx.Read>, options: { readonly runtime: RxRuntime } ): Rx> } @@ -205,12 +204,10 @@ Added in v1.0.0 ```ts export declare const stream: { - (create: (get: Rx.Get, ctx: Context) => Stream.Stream): Rx< - Result.Result - > + (create: Rx.Read>): Rx> ( - create: (get: Rx.Get, ctx: Context) => Stream.Stream, - runtime: RxRuntime + create: Rx.Read>, + options: { readonly runtime: RxRuntime } ): Rx> } ``` @@ -223,12 +220,12 @@ Added in v1.0.0 ```ts export declare const streamPull: { - ( - create: (get: Rx.Get, ctx: Context) => Stream.Stream, - options?: { readonly disableAccumulation?: boolean } - ): Writable, void> + (create: Rx.Read>, options?: { readonly disableAccumulation?: boolean }): Writable< + Result.Result, + void + > ( - create: (get: Rx.Get, ctx: Context) => Stream.Stream, + create: Rx.Read>, options: { readonly runtime: RxRuntime; readonly disableAccumulation?: boolean | undefined } ): Writable, void> } @@ -242,8 +239,8 @@ Added in v1.0.0 ```ts export declare const writable: ( - read: (get: Rx.Get, ctx: Context) => R, - write: (get: Rx.Get, set: Rx.Set, setSelf: (_: R) => void, value: W) => void, + read: Rx.Read, + write: Rx.Write, refresh?: (f: (rx: Rx) => void) => void ) => Writable ``` @@ -301,7 +298,7 @@ Added in v1.0.0 export interface Rx extends Pipeable, Inspectable.Inspectable { readonly [TypeId]: TypeId readonly keepAlive: boolean - readonly read: (get: Rx.Get, ctx: Context) => A + readonly read: Rx.Read readonly refresh: (f: (rx: Rx) => void) => void readonly label?: readonly [name: string, stack: string] } @@ -343,6 +340,16 @@ export type Mount = (rx: Rx) => () => void Added in v1.0.0 +### Read (type alias) + +**Signature** + +```ts +export type Read = (get: Rx.Get, ctx: Context) => A +``` + +Added in v1.0.0 + ### Refresh (type alias) **Signature** @@ -389,6 +396,16 @@ export type SubscribeGetter = (rx: Rx, f: () => void) => readonly [get: () Added in v1.0.0 +### Write (type alias) + +**Signature** + +```ts +export type Write = (get: Rx.Get, set: Rx.Set, setSelf: (_: R) => void, refreshSelf: () => void, value: W) => void +``` + +Added in v1.0.0 + ## RxResultFn (interface) **Signature** @@ -416,7 +433,7 @@ Added in v1.0.0 ```ts export interface Writable extends Rx { readonly [WritableTypeId]: WritableTypeId - readonly write: (get: Rx.Get, set: Rx.Set, setSelf: (_: R) => void, value: W) => void + readonly write: (get: Rx.Get, set: Rx.Set, setSelf: (_: R) => void, refreshSelf: () => void, value: W) => void } ``` diff --git a/packages/rx/src/Result.ts b/packages/rx/src/Result.ts index ec471c9..925f37d 100644 --- a/packages/rx/src/Result.ts +++ b/packages/rx/src/Result.ts @@ -76,17 +76,16 @@ export const fromExit = (exit: Exit.Exit): Success | Failure(previous: Option.Option>): Waiting => { if (previous._tag === "None") { - return waiting(Option.none()) + return waiting(constInitial) } switch (previous.value._tag) { - case "Initial": - return waiting(Option.none()) case "Waiting": return previous.value + case "Initial": case "Success": case "Failure": - return waiting(Option.some(previous.value)) + return waiting(previous.value) } } @@ -111,7 +110,7 @@ const constInitial: Initial = Object.assign(Object.create(ResultPr */ export interface Waiting extends Result.Variance { readonly _tag: "Waiting" - readonly previous: Option.Option | Failure> + readonly previous: Initial | Success | Failure } /** @@ -124,7 +123,7 @@ export const isWaiting = (result: Result): result is Waiting = * @since 1.0.0 * @category constructors */ -export const waiting = (previous: Option.Option | Failure>): Waiting => { +export const waiting = (previous: Initial | Success | Failure): Waiting => { const result = Object.create(ResultProto) result._tag = "Waiting" result.previous = previous @@ -200,7 +199,7 @@ export const noWaiting = (result: Result): NoWaiting => { case "Failure": return result case "Waiting": - return result.previous._tag === "None" ? constInitial : result.previous.value + return result.previous } } diff --git a/packages/rx/src/Rx.ts b/packages/rx/src/Rx.ts index e136e74..0e051e6 100644 --- a/packages/rx/src/Rx.ts +++ b/packages/rx/src/Rx.ts @@ -35,7 +35,7 @@ export type TypeId = typeof TypeId export interface Rx extends Pipeable, Inspectable.Inspectable { readonly [TypeId]: TypeId readonly keepAlive: boolean - readonly read: (get: Rx.Get, ctx: Context) => A + readonly read: Rx.Read readonly refresh: (f: (rx: Rx) => void) => void readonly label?: readonly [name: string, stack: string] } @@ -45,6 +45,27 @@ export interface Rx extends Pipeable, Inspectable.Inspectable { * @category models */ export declare namespace Rx { + /** + * @since 1.0.0 + * @category models + */ + export type Read = ( + get: Rx.Get, + ctx: Context + ) => A + + /** + * @since 1.0.0 + * @category models + */ + export type Write = ( + get: Rx.Get, + set: Rx.Set, + setSelf: (_: R) => void, + refreshSelf: () => void, + value: W + ) => void + /** * @since 1.0.0 * @category models @@ -128,7 +149,7 @@ export type WritableTypeId = typeof WritableTypeId */ export interface Writable extends Rx { readonly [WritableTypeId]: WritableTypeId - readonly write: (get: Rx.Get, set: Rx.Set, setSelf: (_: R) => void, value: W) => void + readonly write: (get: Rx.Get, set: Rx.Set, setSelf: (_: R) => void, refreshSelf: () => void, value: W) => void } /** @@ -185,7 +206,7 @@ function defaultRefresh(this: Rx, f: any) { * @category constructors */ export const readable = ( - read: (get: Rx.Get, ctx: Context) => A, + read: Rx.Read, refresh: (f: (rx: Rx) => void) => void = defaultRefresh ): Rx => { const rx = Object.create(RxProto) @@ -200,8 +221,8 @@ export const readable = ( * @category constructors */ export const writable = ( - read: (get: Rx.Get, ctx: Context) => R, - write: (get: Rx.Get, set: Rx.Set, setSelf: (_: R) => void, value: W) => void, + read: Rx.Read, + write: Rx.Write, refresh: (f: (rx: Rx) => void) => void = defaultRefresh ): Writable => { const rx = Object.create(WritableProto) @@ -223,7 +244,7 @@ export const state = ( function(_ctx) { return initialValue }, - function(_get, _set, setSelf, value) { + function(_get, _set, setSelf, _refreshSelf, value) { setSelf(value) } ) @@ -246,7 +267,7 @@ function makeEffect( if (previous._tag === "Some") { return Result.waitingFrom(previous) } - return Result.waiting(Option.none()) + return Result.waiting(Result.initial()) } function makeEffectRuntime( @@ -272,13 +293,13 @@ function makeEffectRuntime( * @category constructors */ export const effect: { - (create: (get: Rx.Get, ctx: Context) => Effect.Effect): Rx> + (create: Rx.Read>): Rx> ( - create: (get: Rx.Get, ctx: Context) => Effect.Effect, + create: Rx.Read>, options: { readonly runtime: RxRuntime } ): Rx> } = ( - create: (get: Rx.Get, ctx: Context) => Effect.Effect, + create: Rx.Read>, options?: { readonly runtime?: RxRuntime } ) => readable>(function(get, ctx) { @@ -293,13 +314,13 @@ export const effect: { * @category constructors */ export const scoped: { - (create: (get: Rx.Get, ctx: Context) => Effect.Effect): Rx> + (create: Rx.Read>): Rx> ( - create: (get: Rx.Get, ctx: Context) => Effect.Effect, + create: Rx.Read>, options: { readonly runtime: RxRuntime } ): Rx> } = ( - create: (get: Rx.Get, ctx: Context) => Effect.Effect, + create: Rx.Read>, options?: { readonly runtime?: RxRuntime } ) => readable>(function(get, ctx) { @@ -355,7 +376,7 @@ export const effectFn: { return options?.runtime ? makeEffectRuntime(ctx, effect, options.runtime) : makeEffect(ctx, effect as Effect.Effect) - }, function(get, set, _setSelf, arg) { + }, function(get, set, _setSelf, _refreshSelf, arg) { set(argRx, [get(argRx)[0] + 1, arg]) }) } @@ -397,7 +418,7 @@ export const scopedFn: { return options?.runtime ? makeEffectRuntime(ctx, scopedEffect, options.runtime) : makeEffect(ctx, scopedEffect as Effect.Effect) - }, function(get, set, _setSelf, arg) { + }, function(get, set, _setSelf, _refreshSelf, arg) { set(argRx, [get(argRx)[0] + 1, arg]) }) } @@ -437,7 +458,7 @@ function makeStream( const cancel = runCallback( Stream.runForEach( stream, - (a) => Effect.sync(() => ctx.setSelf(Result.waiting(Option.some(Result.success(a))))) + (a) => Effect.sync(() => ctx.setSelf(Result.waiting(Result.success(a)))) ), (exit) => { if (exit._tag === "Failure") { @@ -486,20 +507,20 @@ function makeStreamRuntime( */ export const stream: { ( - create: (get: Rx.Get, ctx: Context) => Stream.Stream + create: Rx.Read> ): Rx> ( - create: (get: Rx.Get, ctx: Context) => Stream.Stream, - runtime: RxRuntime + create: Rx.Read>, + options: { readonly runtime: RxRuntime } ): Rx> } = ( - create: (get: Rx.Get, ctx: Context) => Stream.Stream, - runtime?: RxRuntime + create: Rx.Read>, + options?: { readonly runtime?: RxRuntime } ) => readable>(function(get, ctx) { const stream = create(get, ctx) - if (runtime !== undefined) { - return makeStreamRuntime(ctx, stream, runtime) + if (options?.runtime !== undefined) { + return makeStreamRuntime(ctx, stream, options.runtime) } return makeStream(ctx, stream as Stream.Stream) }) @@ -509,18 +530,18 @@ export const stream: { * @category constructors */ export const streamPull: { - (create: (get: Rx.Get, ctx: Context) => Stream.Stream, options?: { + (create: Rx.Read>, options?: { readonly disableAccumulation?: boolean }): Writable>, void> ( - create: (get: Rx.Get, ctx: Context) => Stream.Stream, + create: Rx.Read>, options: { readonly runtime: RxRuntime readonly disableAccumulation?: boolean } ): Writable>, void> } = ( - create: (get: Rx.Get, ctx: Context) => Stream.Stream, + create: Rx.Read>, options?: { readonly runtime?: RxRuntime readonly disableAccumulation?: boolean @@ -538,7 +559,6 @@ export const streamPull: { ) return Stream.toPull(accStream) }, options?.runtime as any) - const counter = state(0) return writable>, void>(function(get, ctx) { const previous = ctx.self>>() @@ -549,7 +569,6 @@ export const streamPull: { } return pullResult as any } - get(counter) const pull = pipe( pullResult.value, Effect.map((_) => Chunk.toReadonlyArray(_) as Array), @@ -571,8 +590,8 @@ export const streamPull: { return options?.runtime ? makeEffectRuntime(ctx, pull, options.runtime) : makeEffect(ctx, pull as any) - }, function(get, set, _setSelf, _) { - set(counter, get(counter) + 1) + }, function(_get, _set, _setSelf, refreshSelf, _) { + refreshSelf() }, function(refresh) { refresh(pullRx) }) diff --git a/packages/rx/src/internal/registry.ts b/packages/rx/src/internal/registry.ts index e460aac..17954a7 100644 --- a/packages/rx/src/internal/registry.ts +++ b/packages/rx/src/internal/registry.ts @@ -28,19 +28,21 @@ class RegistryImpl implements Registry.Registry { } set = (rx: Rx.Writable, value: W): void => { + const node = this.ensureNode(rx) rx.write( this.get, this.set, - this.ensureNode(rx).setValue, + node.setValue, + node.invalidate, value ) } - refresh = (rx: Rx.Rx & Rx.Refreshable): void => { - rx.refresh((rx) => this.ensureNode(rx).invalidate()) + refresh(rx: Rx.Rx & Rx.Refreshable): void { + rx.refresh(this.invalidateRx) } - subscribe: Rx.Rx.Subscribe = (rx, f, options) => { + subscribe(rx: Rx.Rx, f: (_: A) => void, options?: { readonly immediate?: boolean }): () => void { const node = this.ensureNode(rx) if (options?.immediate) { f(node.value()) @@ -56,7 +58,7 @@ class RegistryImpl implements Registry.Registry { } } - subscribeGetter = (rx: Rx.Rx, f: () => void): readonly [get: () => A, unmount: () => void] => { + subscribeGetter(rx: Rx.Rx, f: () => void): readonly [get: () => A, unmount: () => void] { const node = this.ensureNode(rx) function get() { return node.value() @@ -91,6 +93,10 @@ class RegistryImpl implements Registry.Registry { return new Node(this, rx) } + invalidateRx = (rx: Rx.Rx): void => { + this.ensureNode(rx).invalidate() + } + scheduleRxRemoval(rx: Rx.Rx): void { queueMicrotask(() => { const node = this.nodes.get(rx) @@ -226,7 +232,7 @@ class Node { } } - invalidate(): void { + invalidate = (): void => { if (this.state === NodeState.valid) { this.state = NodeState.stale this.disposeLifetime() diff --git a/packages/rx/test/Rx.test.ts b/packages/rx/test/Rx.test.ts index 7df10b3..d1c3190 100644 --- a/packages/rx/test/Rx.test.ts +++ b/packages/rx/test/Rx.test.ts @@ -78,7 +78,7 @@ describe("Rx", () => { { runtime: counterRuntime } ) const timesTwo = Rx.effect( - (get, ctx) => + (_get, ctx) => Effect.gen(function*(_) { const counter = yield* _(Counter) const multiplier = yield* _(Multiplier) @@ -159,9 +159,8 @@ describe("Rx", () => { await vi.advanceTimersByTimeAsync(50) result = r.get(count) assert(Result.isWaiting(result)) - assert(Option.isSome(result.previous)) - assert(Result.isSuccess(result.previous.value)) - assert.deepEqual(result.previous.value.value, 0) + assert(Result.isSuccess(result.previous)) + assert.deepEqual(result.previous.value, 0) await vi.advanceTimersByTimeAsync(50) result = r.get(count)