From d03e9c99068c414d8872ee44e21da22a3cb64851 Mon Sep 17 00:00:00 2001 From: Frank Wang <1454884738@qq.com> Date: Thu, 1 Aug 2024 16:50:51 -0500 Subject: [PATCH] fix --- dev/Todos.ts | 36 ++++------- dev/worker/client.ts | 25 ++++--- dev/worker/schema.ts | 29 ++++----- dev/worker/worker.ts | 10 +-- package.json | 3 +- src/index.ts | 151 +++++++++++++++++++++++-------------------- 6 files changed, 123 insertions(+), 131 deletions(-) diff --git a/dev/Todos.ts b/dev/Todos.ts index 13bd968..91dc5fc 100644 --- a/dev/Todos.ts +++ b/dev/Todos.ts @@ -1,11 +1,11 @@ -import { Rx } from "../src" -import * as HttpClient from "@effect/platform/HttpClient" -import * as HttpRequest from "@effect/platform/HttpClientRequest" -import * as HttpResponse from "@effect/platform/HttpClientResponse" -import * as Schema from "@effect/schema/Schema" -import { Effect, Layer, Option, Stream } from "effect" +import { Rx } from '../src' +import * as HttpClient from '@effect/platform/HttpClient' +import * as HttpRequest from '@effect/platform/HttpClientRequest' +import * as HttpResponse from '@effect/platform/HttpClientResponse' +import * as Schema from '@effect/schema/Schema' +import { Effect, Layer, Option, Stream } from 'effect' -export class Todo extends Schema.Class("Todo")({ +export class Todo extends Schema.Class('Todo')({ id: Schema.Number, title: Schema.String, completed: Schema.Boolean, @@ -17,13 +17,11 @@ export class Todo extends Schema.Class("Todo")({ const make = Effect.gen(function* () { const defaultClient = yield* HttpClient.HttpClient const client = defaultClient.pipe( - HttpClient.mapRequest( - HttpRequest.prependUrl("https://jsonplaceholder.typicode.com"), - ), + HttpClient.mapRequest(HttpRequest.prependUrl('https://jsonplaceholder.typicode.com')), HttpClient.filterStatusOk, ) - const getTodos = HttpRequest.get("/todos") + const getTodos = HttpRequest.get('/todos') const stream = (perPage: number) => Stream.paginateChunkEffect(1, page => getTodos.pipe( @@ -35,24 +33,16 @@ const make = Effect.gen(function* () { HttpResponse.schemaBodyJsonScoped(Todo.chunk), Effect.map(chunk => [ chunk, - Option.some(page + 1).pipe( - Option.filter(() => chunk.length === perPage), - ), + Option.some(page + 1).pipe(Option.filter(() => chunk.length === perPage)), ]), ), ) - const effect = getTodos.pipe( - client, - HttpResponse.schemaBodyJsonScoped(Todo.array), - ) + const effect = getTodos.pipe(client, HttpResponse.schemaBodyJsonScoped(Todo.array)) return { stream, effect } as const }) -export class Todos extends Effect.Tag("Todos")< - Todos, - Effect.Effect.Success ->() { +export class Todos extends Effect.Tag('Todos')>() { static Live = Layer.effect(Todos, make).pipe(Layer.provide(HttpClient.layer)) } @@ -74,5 +64,5 @@ export const effect = todosRuntime.rx(Todos.effect) export const streamIsDone = Rx.make(get => { const r = get(stream) - return r._tag === "Success" && r.value.done + return r._tag === 'Success' && r.value.done }) diff --git a/dev/worker/client.ts b/dev/worker/client.ts index 841acd3..6ed1963 100644 --- a/dev/worker/client.ts +++ b/dev/worker/client.ts @@ -1,9 +1,9 @@ -import * as Worker from "@effect/platform/Worker" -import * as BrowserWorker from "@effect/platform-browser/BrowserWorker" -import { GetId, InitialMessage, Requests } from "./schema" -import { Array, Context, Effect, Layer } from "effect" -import TestWorker from "./worker?worker" -import { Rx } from "../../src" +import * as Worker from '@effect/platform/Worker' +import * as BrowserWorker from '@effect/platform-browser/BrowserWorker' +import { GetId, InitialMessage, Requests } from './schema' +import { Array, Context, Effect, Layer } from 'effect' +import TestWorker from './worker?worker' +import { Rx } from '../../src' const makePool = Worker.makePoolSerialized({ initialMessage: () => new InitialMessage(), @@ -12,12 +12,9 @@ const makePool = Worker.makePoolSerialized({ timeToLive: 20000, concurrency: 5, targetUtilization: 0.8, -}).pipe(Effect.tap(pool => pool.executeEffect(new GetId({ id: "1" })))) +}).pipe(Effect.tap(pool => pool.executeEffect(new GetId({ id: '1' })))) -export class Pool extends Context.Tag("app/Pool")< - Pool, - Effect.Effect.Success ->() { +export class Pool extends Context.Tag('app/Pool')>() { static Live = Layer.scoped(this, makePool).pipe( Layer.provide(BrowserWorker.layer(() => new TestWorker())), ) @@ -28,7 +25,7 @@ export class Pool extends Context.Tag("app/Pool")< const runtime = Rx.runtime(Pool.Live) export const getIdRx = runtime.fn((id: string) => { - console.log("getIdRx", id) + console.log('getIdRx', id) return Pool.pipe( Effect.flatMap(pool => Effect.forEach( @@ -37,11 +34,11 @@ export const getIdRx = runtime.fn((id: string) => { pool.executeEffect(new GetId({ id: id.toString() })).pipe( Effect.tap(Effect.log), Effect.annotateLogs({ - rx: "getIdRx", + rx: 'getIdRx', id, }), ), - { concurrency: "unbounded" }, + { concurrency: 'unbounded' }, ), ), ) diff --git a/dev/worker/schema.ts b/dev/worker/schema.ts index b5df4d3..cfe9f53 100644 --- a/dev/worker/schema.ts +++ b/dev/worker/schema.ts @@ -1,23 +1,16 @@ +import * as Schema from '@effect/schema/Schema' -import * as Schema from "@effect/schema/Schema" +export class InitialMessage extends Schema.TaggedRequest()('InitialMessage', { + failure: Schema.Never, + success: Schema.Void, + payload: {}, +}) {} -export class InitialMessage extends Schema.TaggedRequest()( - "InitialMessage", - { - failure: Schema.Never, - success: Schema.Void, - payload: {} - } -) {} - -export class GetId extends Schema.TaggedRequest()( - "GetId", - { - failure: Schema.Never, - success: Schema.String, - payload: { id: Schema.String }, - } -) {} +export class GetId extends Schema.TaggedRequest()('GetId', { + failure: Schema.Never, + success: Schema.String, + payload: { id: Schema.String }, +}) {} export const Requests = Schema.Union(InitialMessage, GetId) export type Requests = Schema.Schema.Type diff --git a/dev/worker/worker.ts b/dev/worker/worker.ts index 615b7e2..dee8c22 100644 --- a/dev/worker/worker.ts +++ b/dev/worker/worker.ts @@ -1,13 +1,13 @@ /* eslint-disable require-yield */ -import * as Runner from "@effect/platform/WorkerRunner" -import * as BrowserRunner from "@effect/platform-browser/BrowserWorkerRunner" -import { Requests } from "./schema" -import { Effect, Layer } from "effect" +import * as Runner from '@effect/platform/WorkerRunner' +import * as BrowserRunner from '@effect/platform-browser/BrowserWorkerRunner' +import { Requests } from './schema' +import { Effect, Layer } from 'effect' Runner.layerSerialized(Requests, { InitialMessage: () => Effect.gen(function* () { - console.log("Hello from worker") + console.log('Hello from worker') }), GetId: ({ id }) => Effect.succeed(id).pipe(Effect.delay(1000)), }).pipe(Layer.provide(BrowserRunner.layer), Layer.launch, Effect.runPromise) diff --git a/package.json b/package.json index 6275650..58b3309 100644 --- a/package.json +++ b/package.json @@ -47,7 +47,8 @@ "lint": "concurrently pnpm:lint:*", "lint:code": "eslint --ignore-path .gitignore --max-warnings 0 src/**/*.{js,ts,tsx,jsx}", "lint:types": "tsc --noEmit", - "update-deps": "pnpm up -Li" + "update-deps": "pnpm up -Li", + "postinstall": "pnpm build" }, "peerDependencies": { "solid-js": "^1.6.0" diff --git a/src/index.ts b/src/index.ts index 9297979..75d7d93 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,91 +1,101 @@ -import { createContext, useContext, createSignal, onCleanup, createEffect, Accessor, createResource, Resource, createMemo } from 'solid-js'; -import * as Registry from "@effect-rx/rx/Registry"; -import * as Rx from "@effect-rx/rx/Rx"; -import type * as RxRef from "@effect-rx/rx/RxRef"; -import { globalValue } from "effect/GlobalValue" -import * as Result from '@effect-rx/rx/Result'; +import { + createContext, + useContext, + createSignal, + onCleanup, + createEffect, + Accessor, + createResource, + Resource, + createMemo, +} from 'solid-js' +import * as Registry from '@effect-rx/rx/Registry' +import * as Rx from '@effect-rx/rx/Rx' +import type * as RxRef from '@effect-rx/rx/RxRef' +import { globalValue } from 'effect/GlobalValue' +import * as Result from '@effect-rx/rx/Result' // Re-exporting for easy access -export * as Registry from "@effect-rx/rx/Registry"; -export * as Result from "@effect-rx/rx/Result"; -export * as Rx from "@effect-rx/rx/Rx"; -export * as RxRef from "@effect-rx/rx/RxRef"; -import * as Scheduler from "scheduler" +export * as Registry from '@effect-rx/rx/Registry' +export * as Result from '@effect-rx/rx/Result' +export * as Rx from '@effect-rx/rx/Rx' +export * as RxRef from '@effect-rx/rx/RxRef' +import * as Scheduler from 'scheduler' // Context for Registry -export const RegistryContext = createContext(); +export const RegistryContext = createContext() function scheduleTask(f: () => void): void { Scheduler.unstable_scheduleCallback(Scheduler.unstable_LowPriority, f) } // Default registry using a global value as fallback export const defaultRegistry: Registry.Registry = globalValue( - "@effect-rx/solid/defaultRegistry", - () => Registry.make({ - scheduleTask, - defaultIdleTTL: 400 - }) -); + '@effect-rx/solid/defaultRegistry', + () => + Registry.make({ + scheduleTask, + defaultIdleTTL: 400, + }), +) // Function to inject the registry, providing a default if not present in context export const injectRegistry = (): Registry.Registry => { - const registry = useContext(RegistryContext); + const registry = useContext(RegistryContext) if (!registry) { - throw new Error("No registry found"); + throw new Error('No registry found') } - return registry; -}; - + return registry +} // Hook to use an Rx.Writable, similar to useRx in Vue export const useRx = (rx: Rx.Writable): [Accessor, (newValue: W) => void] => { - const registry = injectRegistry(); - const [value, setValue] = createSignal(registry.get(rx)); + const registry = injectRegistry() + const [value, setValue] = createSignal(registry.get(rx)) createEffect(() => { - const cancel = registry.subscribe(rx, setValue as (newValue: R) => void); - onCleanup(cancel); - }); + const cancel = registry.subscribe(rx, setValue as (newValue: R) => void) + onCleanup(cancel) + }) - const set = (newValue: W) => registry.set(rx, newValue); + const set = (newValue: W) => registry.set(rx, newValue) - return [value, set]; -}; + return [value, set] +} export const useRxValue = (rx: Rx.Rx): Accessor => { - const registry = injectRegistry(); - const [value, setValue] = createSignal(registry.get(rx)); + const registry = injectRegistry() + const [value, setValue] = createSignal(registry.get(rx)) createEffect(() => { - const cancel = registry.subscribe(rx, setValue as (newValue: A) => void); - onCleanup(cancel); - }); + const cancel = registry.subscribe(rx, setValue as (newValue: A) => void) + onCleanup(cancel) + }) - return value; -}; + return value +} // Hook to set values on an Rx.Writable -export const useRxSet = (rx: Rx.Writable): (newValue: W) => void => { - const registry = injectRegistry(); +export const useRxSet = (rx: Rx.Writable): ((newValue: W) => void) => { + const registry = injectRegistry() createEffect(() => { - const cancel = registry.mount(rx); - onCleanup(cancel); - }); + const cancel = registry.mount(rx) + onCleanup(cancel) + }) - return (newValue: W) => registry.set(rx, newValue); -}; + return (newValue: W) => registry.set(rx, newValue) +} // Hook to use an RxRef export const useRxRef = (rxRef: RxRef.ReadonlyRef): Accessor => { - const [value, setValue] = createSignal(rxRef.value); + const [value, setValue] = createSignal(rxRef.value) createEffect(() => { - const cancel = rxRef.subscribe(setValue as (newValue: A) => void); - onCleanup(cancel); - }); + const cancel = rxRef.subscribe(setValue as (newValue: A) => void) + onCleanup(cancel) + }) - return value; -}; + return value +} // Suspense implementation using createResource // type SuspenseResult = Result.Success | Result.Failure; @@ -186,29 +196,30 @@ export const useRxRef = (rxRef: RxRef.ReadonlyRef): Accessor => { // return () => result().result as Result.Success | Result.Failure // } -export const useRxSuspense = ( - rx: Rx.Rx>, - suspendOnWaiting?: boolean -) => { - const registry = injectRegistry(); - const [state, {mutate}] = createResource(() => { - return new Promise>((resolve) => { - const unsubscribe = registry.subscribe(rx, (result) => { - if (result._tag !== "Initial" && (!suspendOnWaiting || !result.waiting)) { - resolve(result); - unsubscribe(); - } - }, { immediate: true }); - }); - }); +export const useRxSuspense = (rx: Rx.Rx>, suspendOnWaiting?: boolean) => { + const registry = injectRegistry() + const [state, { mutate }] = createResource(() => { + return new Promise>(resolve => { + const unsubscribe = registry.subscribe( + rx, + result => { + if (result._tag !== 'Initial' && (!suspendOnWaiting || !result.waiting)) { + resolve(result) + unsubscribe() + } + }, + { immediate: true }, + ) + }) + }) createEffect(() => { - const cancel = registry.subscribe(rx, mutate); - onCleanup(cancel); + const cancel = registry.subscribe(rx, mutate) + onCleanup(cancel) }) - return state; -}; + return state +} // function createSuspenseResource( // registry: Registry.Registry,