Compare commits
1 Commits
ca448c6bae
...
3242f64ef4
| Author | SHA1 | Date | |
|---|---|---|---|
| 3242f64ef4 |
4
bun.lock
4
bun.lock
@@ -5,7 +5,7 @@
|
||||
"name": "@effect-fc/monorepo",
|
||||
"devDependencies": {
|
||||
"@biomejs/biome": "^2.2.5",
|
||||
"@effect/language-service": "^0.52.0",
|
||||
"@effect/language-service": "^0.51.0",
|
||||
"@types/bun": "^1.2.23",
|
||||
"npm-check-updates": "^19.0.0",
|
||||
"npm-sort": "^0.0.4",
|
||||
@@ -130,7 +130,7 @@
|
||||
|
||||
"@effect-fc/example": ["@effect-fc/example@workspace:packages/example"],
|
||||
|
||||
"@effect/language-service": ["@effect/language-service@0.52.1", "", { "bin": { "effect-language-service": "cli.js" } }, "sha512-1azwmMvg5UhJ2HgJ7iNhdbrbCvXgPNvszjOKBZmxEWLUSlvzki/e0JX33nz6pW15GTO2ZkuCf2ExwnsFX9atnQ=="],
|
||||
"@effect/language-service": ["@effect/language-service@0.51.1", "", { "bin": { "effect-language-service": "cli.js" } }, "sha512-JdKKw7EP5Na9ZdvQgs3rHBsrWAvvMh99yAaB0jgX7kKEkx0L8mdIndxtOqc3DrZ/H6qJxCLSjxa873Z5TEecVg=="],
|
||||
|
||||
"@effect/platform": ["@effect/platform@0.92.1", "", { "dependencies": { "find-my-way-ts": "^0.1.6", "msgpackr": "^1.11.4", "multipasta": "^0.2.7" }, "peerDependencies": { "effect": "^3.18.1" } }, "sha512-XXWCBVwyhaKZISN7aM1fv/3fWDGyxr84ObywnUrL8aHvJLoIeskWFAP/fqw3c5MFCrJ3ZV97RWLbv6JiBQugdg=="],
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@biomejs/biome": "^2.2.5",
|
||||
"@effect/language-service": "^0.52.0",
|
||||
"@effect/language-service": "^0.51.0",
|
||||
"@types/bun": "^1.2.23",
|
||||
"npm-check-updates": "^19.0.0",
|
||||
"npm-sort": "^0.0.4",
|
||||
|
||||
@@ -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 { Context, type Duration, Effect, Effectable, Equivalence, ExecutionStrategy, Exit, Fiber, Function, HashMap, Layer, ManagedRuntime, Option, Predicate, Ref, Runtime, Scope, Stream, Tracer, type Utils } from "effect"
|
||||
import { Context, type Duration, Effect, Effectable, Equivalence, ExecutionStrategy, Exit, Fiber, Function, HashMap, Layer, ManagedRuntime, Option, Predicate, Ref, Runtime, Scope, Stream, Tracer, type Types, type Utils } from "effect"
|
||||
import * as React from "react"
|
||||
import { Memoized } from "./index.js"
|
||||
import * as Result from "./Result.js"
|
||||
@@ -387,9 +387,9 @@ export const withOptions: {
|
||||
export const withRuntime: {
|
||||
<P extends {}, A extends React.ReactNode, E, R>(
|
||||
context: React.Context<Runtime.Runtime<R>>,
|
||||
): (self: Component<P, A, E, Scope.Scope | NoInfer<R>>) => (props: P) => A
|
||||
): (self: Component<P, A, E, Types.NoInfer<R>>) => (props: P) => A
|
||||
<P extends {}, A extends React.ReactNode, E, R>(
|
||||
self: Component<P, A, E, Scope.Scope | NoInfer<R>>,
|
||||
self: Component<P, A, E, Types.NoInfer<R>>,
|
||||
context: React.Context<Runtime.Runtime<R>>,
|
||||
): (props: P) => A
|
||||
} = Function.dual(2, <P extends {}, A extends React.ReactNode, E, R>(
|
||||
@@ -403,7 +403,7 @@ export const withRuntime: {
|
||||
})
|
||||
|
||||
|
||||
export class ScopeMap extends Effect.Service<ScopeMap>()("@effect-fc/Component/ScopeMap", {
|
||||
export class ScopeMap extends Effect.Service<ScopeMap>()("effect-fc/Component/ScopeMap", {
|
||||
effect: Effect.bind(Effect.Do, "ref", () => Ref.make(HashMap.empty<object, ScopeMap.Entry>()))
|
||||
}) {}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Cause, Context, Data, Effect, Equal, Exit, Hash, Layer, Match, Option, Pipeable, Predicate, pipe, Queue, Ref, Scope } from "effect"
|
||||
import { Cause, Context, Data, Effect, Equal, Exit, Hash, Layer, Match, Option, Pipeable, Predicate, pipe, Queue, Ref, type Scope } from "effect"
|
||||
|
||||
|
||||
export const ResultTypeId: unique symbol = Symbol.for("@effect-fc/Result/Result")
|
||||
@@ -177,46 +177,6 @@ export const makeProgressLayer = <A, E, P = never>(
|
||||
}))
|
||||
|
||||
|
||||
export namespace forkEffect {
|
||||
export type InputContext<R, P> = R extends Progress<infer X> ? [X] extends [P] ? R : never : R
|
||||
export type OutputContext<R> = Scope.Scope | Exclude<R, Progress<any> | Progress<never>>
|
||||
|
||||
export interface Options<P> {
|
||||
readonly initialProgress?: P
|
||||
}
|
||||
}
|
||||
|
||||
export const forkEffect = <A, E, R, P = never>(
|
||||
effect: Effect.Effect<A, E, forkEffect.InputContext<R, NoInfer<P>>>,
|
||||
options?: forkEffect.Options<P>,
|
||||
): Effect.Effect<
|
||||
Queue.Dequeue<Result<A, E, P>>,
|
||||
never,
|
||||
forkEffect.OutputContext<R>
|
||||
> => Effect.Do.pipe(
|
||||
Effect.bind("scope", () => Scope.Scope),
|
||||
Effect.bind("queue", () => Queue.unbounded<Result<A, E, P>>()),
|
||||
Effect.bind("ref", () => Ref.make<Result<A, E, P>>(initial())),
|
||||
Effect.tap(({ queue, ref }) => Effect.andThen(ref, v => Queue.offer(queue, v))),
|
||||
Effect.tap(({ scope, queue, ref }) => Effect.forkScoped(
|
||||
Effect.addFinalizer(() => Queue.shutdown(queue)).pipe(
|
||||
Effect.andThen(Effect.succeed(running(options?.initialProgress)).pipe(
|
||||
Effect.tap(v => Ref.set(ref, v)),
|
||||
Effect.tap(v => Queue.offer(queue, v)),
|
||||
)),
|
||||
Effect.andThen(Effect.provideService(effect, Scope.Scope, scope)),
|
||||
Effect.exit,
|
||||
Effect.andThen(exit => Effect.succeed(fromExit(exit)).pipe(
|
||||
Effect.tap(v => Ref.set(ref, v)),
|
||||
Effect.tap(v => Queue.offer(queue, v)),
|
||||
)),
|
||||
Effect.scoped,
|
||||
Effect.provide(makeProgressLayer(queue, ref)),
|
||||
)
|
||||
)),
|
||||
Effect.map(({ queue }) => queue),
|
||||
) as Effect.Effect<Queue.Queue<Result<A, E, P>>, never, Scope.Scope>
|
||||
|
||||
export namespace forkEffectScoped {
|
||||
export type InputContext<R, P> = (R extends Progress<infer X>
|
||||
? [X] extends [P]
|
||||
@@ -240,17 +200,16 @@ export const forkEffectScoped = <A, E, R, P = never>(
|
||||
never,
|
||||
forkEffectScoped.OutputContext<R>
|
||||
> => Effect.Do.pipe(
|
||||
Effect.bind("scope", () => Scope.Scope),
|
||||
Effect.bind("queue", () => Queue.unbounded<Result<A, E, P>>()),
|
||||
Effect.bind("ref", () => Ref.make<Result<A, E, P>>(initial())),
|
||||
Effect.tap(({ queue, ref }) => Effect.andThen(ref, v => Queue.offer(queue, v))),
|
||||
Effect.tap(({ scope, queue, ref }) => Effect.forkScoped(
|
||||
Effect.tap(({ queue, ref }) => Effect.forkScoped(
|
||||
Effect.addFinalizer(() => Queue.shutdown(queue)).pipe(
|
||||
Effect.andThen(Effect.succeed(running(options?.initialProgress)).pipe(
|
||||
Effect.tap(v => Ref.set(ref, v)),
|
||||
Effect.tap(v => Queue.offer(queue, v)),
|
||||
)),
|
||||
Effect.andThen(Effect.provideService(effect, Scope.Scope, scope)),
|
||||
Effect.andThen(effect),
|
||||
Effect.exit,
|
||||
Effect.andThen(exit => Effect.succeed(fromExit(exit)).pipe(
|
||||
Effect.tap(v => Ref.set(ref, v)),
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
// Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified.
|
||||
|
||||
import { Route as rootRouteImport } from './routes/__root'
|
||||
import { Route as ResultRouteImport } from './routes/result'
|
||||
import { Route as FormRouteImport } from './routes/form'
|
||||
import { Route as BlankRouteImport } from './routes/blank'
|
||||
import { Route as IndexRouteImport } from './routes/index'
|
||||
@@ -17,11 +16,6 @@ import { Route as DevMemoRouteImport } from './routes/dev/memo'
|
||||
import { Route as DevContextRouteImport } from './routes/dev/context'
|
||||
import { Route as DevAsyncRenderingRouteImport } from './routes/dev/async-rendering'
|
||||
|
||||
const ResultRoute = ResultRouteImport.update({
|
||||
id: '/result',
|
||||
path: '/result',
|
||||
getParentRoute: () => rootRouteImport,
|
||||
} as any)
|
||||
const FormRoute = FormRouteImport.update({
|
||||
id: '/form',
|
||||
path: '/form',
|
||||
@@ -57,7 +51,6 @@ export interface FileRoutesByFullPath {
|
||||
'/': typeof IndexRoute
|
||||
'/blank': typeof BlankRoute
|
||||
'/form': typeof FormRoute
|
||||
'/result': typeof ResultRoute
|
||||
'/dev/async-rendering': typeof DevAsyncRenderingRoute
|
||||
'/dev/context': typeof DevContextRoute
|
||||
'/dev/memo': typeof DevMemoRoute
|
||||
@@ -66,7 +59,6 @@ export interface FileRoutesByTo {
|
||||
'/': typeof IndexRoute
|
||||
'/blank': typeof BlankRoute
|
||||
'/form': typeof FormRoute
|
||||
'/result': typeof ResultRoute
|
||||
'/dev/async-rendering': typeof DevAsyncRenderingRoute
|
||||
'/dev/context': typeof DevContextRoute
|
||||
'/dev/memo': typeof DevMemoRoute
|
||||
@@ -76,7 +68,6 @@ export interface FileRoutesById {
|
||||
'/': typeof IndexRoute
|
||||
'/blank': typeof BlankRoute
|
||||
'/form': typeof FormRoute
|
||||
'/result': typeof ResultRoute
|
||||
'/dev/async-rendering': typeof DevAsyncRenderingRoute
|
||||
'/dev/context': typeof DevContextRoute
|
||||
'/dev/memo': typeof DevMemoRoute
|
||||
@@ -87,7 +78,6 @@ export interface FileRouteTypes {
|
||||
| '/'
|
||||
| '/blank'
|
||||
| '/form'
|
||||
| '/result'
|
||||
| '/dev/async-rendering'
|
||||
| '/dev/context'
|
||||
| '/dev/memo'
|
||||
@@ -96,7 +86,6 @@ export interface FileRouteTypes {
|
||||
| '/'
|
||||
| '/blank'
|
||||
| '/form'
|
||||
| '/result'
|
||||
| '/dev/async-rendering'
|
||||
| '/dev/context'
|
||||
| '/dev/memo'
|
||||
@@ -105,7 +94,6 @@ export interface FileRouteTypes {
|
||||
| '/'
|
||||
| '/blank'
|
||||
| '/form'
|
||||
| '/result'
|
||||
| '/dev/async-rendering'
|
||||
| '/dev/context'
|
||||
| '/dev/memo'
|
||||
@@ -115,7 +103,6 @@ export interface RootRouteChildren {
|
||||
IndexRoute: typeof IndexRoute
|
||||
BlankRoute: typeof BlankRoute
|
||||
FormRoute: typeof FormRoute
|
||||
ResultRoute: typeof ResultRoute
|
||||
DevAsyncRenderingRoute: typeof DevAsyncRenderingRoute
|
||||
DevContextRoute: typeof DevContextRoute
|
||||
DevMemoRoute: typeof DevMemoRoute
|
||||
@@ -123,13 +110,6 @@ export interface RootRouteChildren {
|
||||
|
||||
declare module '@tanstack/react-router' {
|
||||
interface FileRoutesByPath {
|
||||
'/result': {
|
||||
id: '/result'
|
||||
path: '/result'
|
||||
fullPath: '/result'
|
||||
preLoaderRoute: typeof ResultRouteImport
|
||||
parentRoute: typeof rootRouteImport
|
||||
}
|
||||
'/form': {
|
||||
id: '/form'
|
||||
path: '/form'
|
||||
@@ -179,7 +159,6 @@ const rootRouteChildren: RootRouteChildren = {
|
||||
IndexRoute: IndexRoute,
|
||||
BlankRoute: BlankRoute,
|
||||
FormRoute: FormRoute,
|
||||
ResultRoute: ResultRoute,
|
||||
DevAsyncRenderingRoute: DevAsyncRenderingRoute,
|
||||
DevContextRoute: DevContextRoute,
|
||||
DevMemoRoute: DevMemoRoute,
|
||||
|
||||
@@ -1,44 +0,0 @@
|
||||
import { HttpClient } from "@effect/platform"
|
||||
import { Container, Heading, Text } from "@radix-ui/themes"
|
||||
import { createFileRoute } from "@tanstack/react-router"
|
||||
import { Effect, Match, Schema } from "effect"
|
||||
import { Component } from "effect-fc"
|
||||
import { runtime } from "@/runtime"
|
||||
|
||||
|
||||
const Post = Schema.Struct({
|
||||
userId: Schema.Int,
|
||||
id: Schema.Int,
|
||||
title: Schema.String,
|
||||
body: Schema.String,
|
||||
})
|
||||
|
||||
const Result = Component.makeUntraced("Result")(function*() {
|
||||
const result = yield* Component.useOnMountResult(() => HttpClient.HttpClient.pipe(
|
||||
Effect.andThen(client => client.get("https://jsonplaceholder.typicode.com/posts/1")),
|
||||
Effect.andThen(Schema.decodeUnknown(Post)),
|
||||
Effect.tap(Effect.sleep("250 millis")),
|
||||
))
|
||||
|
||||
return (
|
||||
<Container>
|
||||
{Match.value(result).pipe(
|
||||
Match.tag("Running", () => <Text>Loading...</Text>),
|
||||
Match.tag("Success", result => <>
|
||||
<Heading>{result.value.title}</Heading>
|
||||
<Text>{result.value.body}</Text>
|
||||
</>),
|
||||
Match.tag("Failure", result =>
|
||||
<Text>An error has occured: {result.cause.toString()}</Text>
|
||||
),
|
||||
Match.orElse(() => <></>),
|
||||
)}
|
||||
</Container>
|
||||
)
|
||||
}).pipe(
|
||||
Component.withRuntime(runtime.context)
|
||||
)
|
||||
|
||||
export const Route = createFileRoute("/result")({
|
||||
component: Result
|
||||
})
|
||||
Reference in New Issue
Block a user