effect-start 0.13.1 → 0.15.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +13 -14
- package/src/Commander.test.ts +507 -245
- package/src/ContentNegotiation.test.ts +500 -0
- package/src/ContentNegotiation.ts +535 -0
- package/src/FileRouter.ts +16 -12
- package/src/{FileRouterCodegen.test.ts → FileRouterCodegen.todo.ts} +384 -219
- package/src/FileRouterCodegen.ts +6 -6
- package/src/FileRouterPattern.test.ts +93 -62
- package/src/FileRouter_files.test.ts +6 -6
- package/src/FileRouter_path.test.ts +121 -69
- package/src/FileRouter_tree.test.ts +62 -56
- package/src/FileSystemExtra.test.ts +46 -30
- package/src/Http.test.ts +24 -0
- package/src/Http.ts +25 -0
- package/src/HttpAppExtra.test.ts +40 -21
- package/src/HttpAppExtra.ts +0 -1
- package/src/HttpUtils.test.ts +35 -18
- package/src/HttpUtils.ts +2 -0
- package/src/PathPattern.test.ts +648 -0
- package/src/PathPattern.ts +483 -0
- package/src/Route.ts +258 -1073
- package/src/RouteBody.test.ts +182 -0
- package/src/RouteBody.ts +106 -0
- package/src/RouteHook.test.ts +40 -0
- package/src/RouteHook.ts +105 -0
- package/src/RouteHttp.test.ts +443 -0
- package/src/RouteHttp.ts +219 -0
- package/src/RouteMount.test.ts +468 -0
- package/src/RouteMount.ts +313 -0
- package/src/RouteSchema.test.ts +81 -0
- package/src/RouteSchema.ts +44 -0
- package/src/RouteTree.test.ts +346 -0
- package/src/RouteTree.ts +165 -0
- package/src/RouteTrie.test.ts +322 -0
- package/src/RouteTrie.ts +224 -0
- package/src/RouterPattern.test.ts +569 -548
- package/src/RouterPattern.ts +7 -7
- package/src/Start.ts +3 -37
- package/src/StartApp.ts +20 -16
- package/src/TuplePathPattern.ts +64 -0
- package/src/Values.ts +16 -0
- package/src/bun/BunBundle.test.ts +37 -43
- package/src/bun/BunBundle.ts +2 -2
- package/src/bun/BunBundle_imports.test.ts +6 -8
- package/src/bun/BunHttpServer.test.ts +183 -6
- package/src/bun/BunHttpServer.ts +56 -32
- package/src/bun/BunHttpServer_web.ts +18 -6
- package/src/bun/BunImportTrackerPlugin.test.ts +3 -3
- package/src/bun/BunRoute.ts +29 -210
- package/src/{Bundle.ts → bundler/Bundle.ts} +0 -35
- package/src/{BundleHttp.test.ts → bundler/BundleHttp.test.ts} +36 -64
- package/src/{BundleHttp.ts → bundler/BundleHttp.ts} +1 -1
- package/src/client/index.ts +1 -1
- package/src/{Effect_HttpRouter.test.ts → effect/HttpRouter.test.ts} +69 -91
- package/src/{EncryptedCookies.test.ts → experimental/EncryptedCookies.test.ts} +125 -64
- package/src/{SseHttpResponse.ts → experimental/SseHttpResponse.ts} +1 -1
- package/src/experimental/index.ts +2 -0
- package/src/hyper/Hyper.ts +89 -0
- package/src/{HyperHtml.test.ts → hyper/HyperHtml.test.ts} +13 -13
- package/src/{HyperHtml.ts → hyper/HyperHtml.ts} +2 -2
- package/src/{jsx.d.ts → hyper/jsx.d.ts} +1 -1
- package/src/index.ts +1 -21
- package/src/middlewares/BasicAuthMiddleware.test.ts +29 -19
- package/src/middlewares/index.ts +1 -0
- package/src/{NodeFileSystem.ts → node/FileSystem.ts} +6 -2
- package/src/{TestHttpClient.test.ts → testing/TestHttpClient.test.ts} +27 -27
- package/src/{TestHttpClient.ts → testing/TestHttpClient.ts} +0 -1
- package/src/{TestLogger.test.ts → testing/TestLogger.test.ts} +27 -11
- package/src/testing/index.ts +3 -0
- package/src/x/datastar/Datastar.test.ts +47 -48
- package/src/x/datastar/Datastar.ts +1 -1
- package/src/x/tailwind/TailwindPlugin.test.ts +56 -58
- package/src/x/tailwind/TailwindPlugin.ts +23 -17
- package/src/x/tailwind/plugin.ts +1 -1
- package/src/FileHttpRouter.test.ts +0 -239
- package/src/FileHttpRouter.ts +0 -194
- package/src/Hyper.ts +0 -194
- package/src/JsModule.test.ts +0 -14
- package/src/JsModule.ts +0 -116
- package/src/PublicDirectory.test.ts +0 -280
- package/src/PublicDirectory.ts +0 -108
- package/src/Route.test.ts +0 -1370
- package/src/RouteRender.ts +0 -40
- package/src/Router.test.ts +0 -375
- package/src/Router.ts +0 -255
- package/src/StartHttp.ts +0 -42
- package/src/bun/BunRoute.test.ts +0 -480
- package/src/bun/BunRoute_bundles.test.ts +0 -219
- /package/src/{BundleFiles.ts → bundler/BundleFiles.ts} +0 -0
- /package/src/{EncryptedCookies.ts → experimental/EncryptedCookies.ts} +0 -0
- /package/src/{HyperNode.ts → hyper/HyperNode.ts} +0 -0
- /package/src/{jsx-runtime.ts → hyper/jsx-runtime.ts} +0 -0
- /package/src/{NodeUtils.ts → node/Utils.ts} +0 -0
- /package/src/{TestLogger.ts → testing/TestLogger.ts} +0 -0
- /package/src/{testing.ts → testing/utils.ts} +0 -0
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
import * as test from "bun:test"
|
|
2
|
+
import * as Effect from "effect/Effect"
|
|
3
|
+
import * as RouteBody from "./RouteBody.ts"
|
|
4
|
+
import * as RouteMount from "./RouteMount.ts"
|
|
5
|
+
|
|
6
|
+
const text = RouteBody.build<string, "text">({
|
|
7
|
+
format: "text",
|
|
8
|
+
})
|
|
9
|
+
|
|
10
|
+
test.it("infers parent descriptions", () => {
|
|
11
|
+
RouteMount.get(
|
|
12
|
+
text((ctx) =>
|
|
13
|
+
Effect.gen(function*() {
|
|
14
|
+
test
|
|
15
|
+
.expectTypeOf(ctx)
|
|
16
|
+
.toExtend<{
|
|
17
|
+
method: "GET"
|
|
18
|
+
format: "text"
|
|
19
|
+
}>()
|
|
20
|
+
|
|
21
|
+
return "Hello, world!"
|
|
22
|
+
})
|
|
23
|
+
),
|
|
24
|
+
)
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
test.it("cannot modify context", () => {
|
|
28
|
+
text((ctx, next) =>
|
|
29
|
+
Effect.gen(function*() {
|
|
30
|
+
test
|
|
31
|
+
.expectTypeOf(next)
|
|
32
|
+
.parameters
|
|
33
|
+
.toEqualTypeOf<[]>()
|
|
34
|
+
|
|
35
|
+
return "Hello, world!"
|
|
36
|
+
})
|
|
37
|
+
)
|
|
38
|
+
})
|
|
39
|
+
|
|
40
|
+
test.it("enforces result value", () => {
|
|
41
|
+
// @ts-expect-error must return string
|
|
42
|
+
text((ctx, next) =>
|
|
43
|
+
Effect.gen(function*() {
|
|
44
|
+
return 1337
|
|
45
|
+
})
|
|
46
|
+
)
|
|
47
|
+
})
|
|
48
|
+
|
|
49
|
+
test.it("accepts value directly", () => {
|
|
50
|
+
const value = "Hello, world!"
|
|
51
|
+
|
|
52
|
+
test
|
|
53
|
+
.expectTypeOf(text)
|
|
54
|
+
.toBeCallableWith(value)
|
|
55
|
+
})
|
|
56
|
+
|
|
57
|
+
test.describe(`${RouteBody.handle.name}()`, () => {
|
|
58
|
+
const ctx = {}
|
|
59
|
+
const next = () => Effect.succeed("next" as const)
|
|
60
|
+
|
|
61
|
+
test.it("accepts all HandlerInput variants", () => {
|
|
62
|
+
test
|
|
63
|
+
.expectTypeOf<
|
|
64
|
+
RouteBody.HandlerInput<{ foo: string }, string, Error, never>
|
|
65
|
+
>()
|
|
66
|
+
.toExtend<Parameters<typeof RouteBody.handle>[0]>()
|
|
67
|
+
})
|
|
68
|
+
|
|
69
|
+
test.it("handles plain value", async () => {
|
|
70
|
+
const handler = RouteBody.handle("hello")
|
|
71
|
+
|
|
72
|
+
test
|
|
73
|
+
.expectTypeOf(handler)
|
|
74
|
+
.returns
|
|
75
|
+
.toEqualTypeOf<
|
|
76
|
+
Effect.Effect<string, never, never>
|
|
77
|
+
>()
|
|
78
|
+
|
|
79
|
+
const result = await Effect.runPromise(handler(ctx, next))
|
|
80
|
+
test.expect(result).toBe("hello")
|
|
81
|
+
})
|
|
82
|
+
|
|
83
|
+
test.it("handles Effect directly", async () => {
|
|
84
|
+
const handler = RouteBody.handle(Effect.succeed("from effect"))
|
|
85
|
+
|
|
86
|
+
test
|
|
87
|
+
.expectTypeOf(handler)
|
|
88
|
+
.returns
|
|
89
|
+
.toEqualTypeOf<
|
|
90
|
+
Effect.Effect<string, never, never>
|
|
91
|
+
>()
|
|
92
|
+
|
|
93
|
+
const result = await Effect.runPromise(handler(ctx, next))
|
|
94
|
+
|
|
95
|
+
test
|
|
96
|
+
.expect(result)
|
|
97
|
+
.toBe("from effect")
|
|
98
|
+
})
|
|
99
|
+
|
|
100
|
+
test.it("handles Effect with error", async () => {
|
|
101
|
+
const handler = RouteBody.handle(Effect.fail(new Error("oops")))
|
|
102
|
+
|
|
103
|
+
test
|
|
104
|
+
.expectTypeOf(handler)
|
|
105
|
+
.returns
|
|
106
|
+
.toEqualTypeOf<
|
|
107
|
+
Effect.Effect<never, Error, never>
|
|
108
|
+
>()
|
|
109
|
+
})
|
|
110
|
+
|
|
111
|
+
test.it("handles function", async () => {
|
|
112
|
+
const handler = RouteBody.handle(
|
|
113
|
+
(ctx: { id: number }) => Effect.succeed(ctx.id),
|
|
114
|
+
)
|
|
115
|
+
|
|
116
|
+
test
|
|
117
|
+
.expectTypeOf(handler)
|
|
118
|
+
.parameters
|
|
119
|
+
.toEqualTypeOf<
|
|
120
|
+
[{ id: number }, () => Effect.Effect<number>]
|
|
121
|
+
>()
|
|
122
|
+
test
|
|
123
|
+
.expectTypeOf(handler)
|
|
124
|
+
.returns
|
|
125
|
+
.toEqualTypeOf<
|
|
126
|
+
Effect.Effect<number, never, never>
|
|
127
|
+
>()
|
|
128
|
+
|
|
129
|
+
const result = await Effect.runPromise(
|
|
130
|
+
handler({ id: 42 }, () => Effect.succeed(23)),
|
|
131
|
+
)
|
|
132
|
+
|
|
133
|
+
test
|
|
134
|
+
.expect(result)
|
|
135
|
+
.toBe(42)
|
|
136
|
+
})
|
|
137
|
+
|
|
138
|
+
test.it("handles generator", async () => {
|
|
139
|
+
const handler = RouteBody.handle(function*(ctx: { id: number }) {
|
|
140
|
+
const n = yield* Effect.succeed(ctx.id)
|
|
141
|
+
return n * 2
|
|
142
|
+
})
|
|
143
|
+
|
|
144
|
+
test
|
|
145
|
+
.expectTypeOf(handler)
|
|
146
|
+
.parameters
|
|
147
|
+
.toEqualTypeOf<
|
|
148
|
+
[{ id: number }, () => Effect.Effect<number>]
|
|
149
|
+
>()
|
|
150
|
+
|
|
151
|
+
test
|
|
152
|
+
.expectTypeOf(handler)
|
|
153
|
+
.returns
|
|
154
|
+
.toEqualTypeOf<
|
|
155
|
+
Effect.Effect<number, never, never>
|
|
156
|
+
>()
|
|
157
|
+
|
|
158
|
+
const result = await Effect.runPromise(
|
|
159
|
+
// TODO: we should accept Effect.void in next here
|
|
160
|
+
handler({ id: 21 }, () => Effect.succeed(23)),
|
|
161
|
+
)
|
|
162
|
+
|
|
163
|
+
test
|
|
164
|
+
.expect(result)
|
|
165
|
+
.toBe(42)
|
|
166
|
+
})
|
|
167
|
+
|
|
168
|
+
test.it("generator can call next", async () => {
|
|
169
|
+
const handler = RouteBody.handle(
|
|
170
|
+
function*(_ctx: {}, next: () => Effect.Effect<string>) {
|
|
171
|
+
const fromNext = yield* next()
|
|
172
|
+
return `got: ${fromNext}`
|
|
173
|
+
},
|
|
174
|
+
)
|
|
175
|
+
|
|
176
|
+
const result = await Effect.runPromise(handler(ctx, next))
|
|
177
|
+
|
|
178
|
+
test
|
|
179
|
+
.expect(result)
|
|
180
|
+
.toBe("got: next")
|
|
181
|
+
})
|
|
182
|
+
})
|
package/src/RouteBody.ts
ADDED
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import * as Effect from "effect/Effect"
|
|
2
|
+
import type * as Utils from "effect/Utils"
|
|
3
|
+
import * as Route from "./Route.ts"
|
|
4
|
+
|
|
5
|
+
export type Format =
|
|
6
|
+
| "text"
|
|
7
|
+
| "html"
|
|
8
|
+
| "json"
|
|
9
|
+
| "bytes"
|
|
10
|
+
|
|
11
|
+
export type HandlerInput<B, A, E, R> =
|
|
12
|
+
| A
|
|
13
|
+
| Effect.Effect<A, E, R>
|
|
14
|
+
| ((context: _Simplify<B>, next: () => Effect.Effect<A>) =>
|
|
15
|
+
| Effect.Effect<A, E, R>
|
|
16
|
+
| Generator<Utils.YieldWrap<Effect.Effect<any, E, R>>, A, any>)
|
|
17
|
+
|
|
18
|
+
export function handle<B, A, E, R>(
|
|
19
|
+
handler: (context: B, next: () => Effect.Effect<A>) =>
|
|
20
|
+
| Effect.Effect<A, E, R>
|
|
21
|
+
| Generator<Utils.YieldWrap<Effect.Effect<any, E, R>>, A, any>,
|
|
22
|
+
): Route.Route.HandlerImmutable<B, A, E, R>
|
|
23
|
+
export function handle<A, E, R>(
|
|
24
|
+
handler: Effect.Effect<A, E, R>,
|
|
25
|
+
): Route.Route.HandlerImmutable<{}, A, E, R>
|
|
26
|
+
export function handle<A>(
|
|
27
|
+
handler: A,
|
|
28
|
+
): Route.Route.HandlerImmutable<{}, A, never, never>
|
|
29
|
+
export function handle<B, A, E, R>(
|
|
30
|
+
handler: HandlerInput<B, A, E, R>,
|
|
31
|
+
): Route.Route.HandlerImmutable<B, A, E, R> {
|
|
32
|
+
if (typeof handler === "function") {
|
|
33
|
+
return (
|
|
34
|
+
context: B,
|
|
35
|
+
next: () => Effect.Effect<A>,
|
|
36
|
+
): Effect.Effect<A, E, R> => {
|
|
37
|
+
const result = (handler as Function)(context, next)
|
|
38
|
+
if (Effect.isEffect(result)) {
|
|
39
|
+
return result as Effect.Effect<A, E, R>
|
|
40
|
+
}
|
|
41
|
+
return Effect.gen(function*() {
|
|
42
|
+
return yield* result
|
|
43
|
+
}) as Effect.Effect<A, E, R>
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
if (Effect.isEffect(handler)) {
|
|
47
|
+
return (_context, _next) => handler
|
|
48
|
+
}
|
|
49
|
+
return (_context, _next) => Effect.succeed(handler as A)
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export function build<
|
|
53
|
+
Value,
|
|
54
|
+
F extends Format,
|
|
55
|
+
>(
|
|
56
|
+
descriptors: { format: F },
|
|
57
|
+
) {
|
|
58
|
+
return function<
|
|
59
|
+
D extends Route.RouteDescriptor.Any,
|
|
60
|
+
B extends {},
|
|
61
|
+
I extends Route.Route.Tuple,
|
|
62
|
+
A extends Value,
|
|
63
|
+
E = never,
|
|
64
|
+
R = never,
|
|
65
|
+
>(
|
|
66
|
+
handler: HandlerInput<
|
|
67
|
+
NoInfer<
|
|
68
|
+
D & B & Route.ExtractBindings<I> & { format: F }
|
|
69
|
+
>,
|
|
70
|
+
A,
|
|
71
|
+
E,
|
|
72
|
+
R
|
|
73
|
+
>,
|
|
74
|
+
) {
|
|
75
|
+
return function(
|
|
76
|
+
self: Route.RouteSet.RouteSet<D, B, I>,
|
|
77
|
+
) {
|
|
78
|
+
const route = Route.make<{ format: F }, {}, A, E, R>(
|
|
79
|
+
handle(handler) as any,
|
|
80
|
+
descriptors,
|
|
81
|
+
)
|
|
82
|
+
|
|
83
|
+
const items: [...I, Route.Route.Route<{ format: F }, {}, A, E, R>] = [
|
|
84
|
+
...Route.items(self),
|
|
85
|
+
route,
|
|
86
|
+
]
|
|
87
|
+
|
|
88
|
+
return Route.set<
|
|
89
|
+
D,
|
|
90
|
+
B,
|
|
91
|
+
[...I, Route.Route.Route<{ format: F }, {}, A, E, R>]
|
|
92
|
+
>(
|
|
93
|
+
items,
|
|
94
|
+
Route.descriptor(self),
|
|
95
|
+
)
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// used to simplify the context type passed to route handlers
|
|
101
|
+
// for those who prefer to write code by hand :)
|
|
102
|
+
type _Simplify<T> = {
|
|
103
|
+
-readonly [K in keyof T]: T[K] extends object
|
|
104
|
+
? { -readonly [P in keyof T[K]]: T[K][P] }
|
|
105
|
+
: T[K]
|
|
106
|
+
} extends infer U ? { [K in keyof U]: U[K] } : never
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import * as test from "bun:test"
|
|
2
|
+
import { Effect } from "effect"
|
|
3
|
+
import * as Route from "./Route.ts"
|
|
4
|
+
|
|
5
|
+
test.it("passes bindings", () => {
|
|
6
|
+
const headers = {
|
|
7
|
+
"origin": "nounder.org",
|
|
8
|
+
}
|
|
9
|
+
const filterResult = {
|
|
10
|
+
context: {
|
|
11
|
+
headers,
|
|
12
|
+
},
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const routes = Route.empty.pipe(
|
|
16
|
+
Route.filter(() => Effect.succeed(filterResult)),
|
|
17
|
+
Route.text(context => {
|
|
18
|
+
test
|
|
19
|
+
.expectTypeOf(context)
|
|
20
|
+
.toExtend<typeof filterResult.context>()
|
|
21
|
+
|
|
22
|
+
return Effect.succeed(
|
|
23
|
+
`Origin: ${context.headers.origin}`,
|
|
24
|
+
)
|
|
25
|
+
}),
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
test
|
|
29
|
+
.expectTypeOf(routes)
|
|
30
|
+
.toExtend<
|
|
31
|
+
Route.RouteSet.RouteSet<{}, {}, [
|
|
32
|
+
Route.Route.Route<{}, typeof filterResult.context, any>,
|
|
33
|
+
Route.Route.Route<{ format: "text" }, {}, string>,
|
|
34
|
+
]>
|
|
35
|
+
>()
|
|
36
|
+
|
|
37
|
+
test
|
|
38
|
+
.expect(Route.items(routes))
|
|
39
|
+
.toHaveLength(2)
|
|
40
|
+
})
|
package/src/RouteHook.ts
ADDED
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import * as Effect from "effect/Effect"
|
|
2
|
+
import type * as Utils from "effect/Utils"
|
|
3
|
+
import * as Route from "./Route.ts"
|
|
4
|
+
|
|
5
|
+
export type FilterResult<BOut, E, R> =
|
|
6
|
+
| { context: BOut }
|
|
7
|
+
| Effect.Effect<{ context: BOut }, E, R>
|
|
8
|
+
|
|
9
|
+
export type FilterHandlerInput<BIn, BOut, E, R> =
|
|
10
|
+
| FilterResult<BOut, E, R>
|
|
11
|
+
| ((context: BIn) =>
|
|
12
|
+
| FilterResult<BOut, E, R>
|
|
13
|
+
| Generator<
|
|
14
|
+
Utils.YieldWrap<Effect.Effect<any, E, R>>,
|
|
15
|
+
{ context: BOut },
|
|
16
|
+
any
|
|
17
|
+
>)
|
|
18
|
+
|
|
19
|
+
export function filter<
|
|
20
|
+
D extends Route.RouteDescriptor.Any,
|
|
21
|
+
SB extends {},
|
|
22
|
+
P extends Route.Route.Tuple,
|
|
23
|
+
BOut extends {},
|
|
24
|
+
E = never,
|
|
25
|
+
R = never,
|
|
26
|
+
BIn = D & SB & Route.ExtractBindings<P>,
|
|
27
|
+
>(
|
|
28
|
+
filterHandler: FilterHandlerInput<BIn, BOut, E, R>,
|
|
29
|
+
) {
|
|
30
|
+
const normalized = normalizeFilterHandler(filterHandler)
|
|
31
|
+
|
|
32
|
+
return function(
|
|
33
|
+
self: Route.RouteSet.RouteSet<D, SB, P>,
|
|
34
|
+
): Route.RouteSet.RouteSet<
|
|
35
|
+
D,
|
|
36
|
+
SB,
|
|
37
|
+
[...P, Route.Route.Route<{}, BOut, void, E, R>]
|
|
38
|
+
> {
|
|
39
|
+
const route = Route.make<
|
|
40
|
+
{},
|
|
41
|
+
BOut,
|
|
42
|
+
void,
|
|
43
|
+
E,
|
|
44
|
+
R
|
|
45
|
+
>((context: BOut, next) =>
|
|
46
|
+
Effect.gen(function*() {
|
|
47
|
+
const filterResult = yield* normalized(context as unknown as BIn)
|
|
48
|
+
|
|
49
|
+
yield* next(
|
|
50
|
+
filterResult
|
|
51
|
+
? {
|
|
52
|
+
...context,
|
|
53
|
+
...filterResult.context,
|
|
54
|
+
}
|
|
55
|
+
: context,
|
|
56
|
+
)
|
|
57
|
+
})
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
return Route.set(
|
|
61
|
+
[
|
|
62
|
+
...Route.items(self),
|
|
63
|
+
route,
|
|
64
|
+
] as [...P, Route.Route.Route<{}, BOut, void, E, R>],
|
|
65
|
+
Route.descriptor(self),
|
|
66
|
+
)
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function isGenerator(value: unknown): value is Generator {
|
|
71
|
+
return (
|
|
72
|
+
typeof value === "object"
|
|
73
|
+
&& value !== null
|
|
74
|
+
&& Symbol.iterator in value
|
|
75
|
+
&& typeof (value as Generator).next === "function"
|
|
76
|
+
)
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function normalizeFilterHandler<BIn, BOut, E, R>(
|
|
80
|
+
handler: FilterHandlerInput<BIn, BOut, E, R>,
|
|
81
|
+
): (context: BIn) => Effect.Effect<{ context: BOut }, E, R> {
|
|
82
|
+
if (typeof handler === "function") {
|
|
83
|
+
return (context: BIn): Effect.Effect<{ context: BOut }, E, R> => {
|
|
84
|
+
const result = handler(context)
|
|
85
|
+
|
|
86
|
+
if (Effect.isEffect(result)) {
|
|
87
|
+
return result as Effect.Effect<{ context: BOut }, E, R>
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
if (isGenerator(result)) {
|
|
91
|
+
return Effect.gen(function*() {
|
|
92
|
+
return yield* result
|
|
93
|
+
}) as Effect.Effect<{ context: BOut }, E, R>
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
return Effect.succeed(result)
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
if (Effect.isEffect(handler)) {
|
|
101
|
+
return (_context) => handler as Effect.Effect<{ context: BOut }, E, R>
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
return (_context) => Effect.succeed(handler as { context: BOut })
|
|
105
|
+
}
|