effect 4.0.0-rc.118 → 4.0.1
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/README.md +17 -4
- package/dist/Array.d.ts +25 -25
- package/dist/Array.d.ts.map +1 -1
- package/dist/Array.js +16 -16
- package/dist/Array.js.map +1 -1
- package/dist/Cache.d.ts.map +1 -1
- package/dist/Cache.js +20 -16
- package/dist/Cache.js.map +1 -1
- package/dist/Cause.d.ts.map +1 -1
- package/dist/Cause.js +1 -1
- package/dist/Cause.js.map +1 -1
- package/dist/Chunk.d.ts +26 -26
- package/dist/Chunk.d.ts.map +1 -1
- package/dist/Chunk.js +15 -15
- package/dist/Chunk.js.map +1 -1
- package/dist/Effect.d.ts +167 -39
- package/dist/Effect.d.ts.map +1 -1
- package/dist/Effect.js +16 -10
- package/dist/Effect.js.map +1 -1
- package/dist/HashRing.d.ts.map +1 -1
- package/dist/HashRing.js +13 -5
- package/dist/HashRing.js.map +1 -1
- package/dist/MutableHashMap.d.ts.map +1 -1
- package/dist/MutableHashMap.js +4 -22
- package/dist/MutableHashMap.js.map +1 -1
- package/dist/Option.d.ts +17 -17
- package/dist/Option.d.ts.map +1 -1
- package/dist/Option.js +6 -6
- package/dist/Option.js.map +1 -1
- package/dist/Pool.d.ts +9 -5
- package/dist/Pool.d.ts.map +1 -1
- package/dist/Pool.js +34 -41
- package/dist/Pool.js.map +1 -1
- package/dist/Queue.d.ts +19 -2
- package/dist/Queue.d.ts.map +1 -1
- package/dist/Queue.js +9 -4
- package/dist/Queue.js.map +1 -1
- package/dist/RcMap.d.ts.map +1 -1
- package/dist/RcMap.js +16 -1
- package/dist/RcMap.js.map +1 -1
- package/dist/Record.d.ts +14 -14
- package/dist/Record.d.ts.map +1 -1
- package/dist/Record.js +10 -10
- package/dist/Record.js.map +1 -1
- package/dist/Schema.d.ts +37 -21
- package/dist/Schema.d.ts.map +1 -1
- package/dist/Schema.js +29 -10
- package/dist/Schema.js.map +1 -1
- package/dist/SchemaAST.d.ts.map +1 -1
- package/dist/SchemaAST.js +116 -97
- package/dist/SchemaAST.js.map +1 -1
- package/dist/SchemaRepresentation.d.ts +3 -1
- package/dist/SchemaRepresentation.d.ts.map +1 -1
- package/dist/SchemaRepresentation.js +3 -1
- package/dist/SchemaRepresentation.js.map +1 -1
- package/dist/ScopedCache.d.ts.map +1 -1
- package/dist/ScopedCache.js +24 -16
- package/dist/ScopedCache.js.map +1 -1
- package/dist/Stream.d.ts +45 -6
- package/dist/Stream.d.ts.map +1 -1
- package/dist/Stream.js +55 -44
- package/dist/Stream.js.map +1 -1
- package/dist/ai/LanguageModel.d.ts +8 -0
- package/dist/ai/LanguageModel.d.ts.map +1 -1
- package/dist/ai/LanguageModel.js +13 -2
- package/dist/ai/LanguageModel.js.map +1 -1
- package/dist/ai/McpSchema.d.ts +402 -402
- package/dist/ai/McpSchema.d.ts.map +1 -1
- package/dist/ai/McpSchema.js +1 -1
- package/dist/ai/McpSchema.js.map +1 -1
- package/dist/ai/McpServer.d.ts.map +1 -1
- package/dist/ai/McpServer.js +11 -3
- package/dist/ai/McpServer.js.map +1 -1
- package/dist/ai/Response.d.ts.map +1 -1
- package/dist/ai/Response.js +22 -12
- package/dist/ai/Response.js.map +1 -1
- package/dist/ai/internal/mcpProtocol/v2024_11_05.js +1 -0
- package/dist/ai/internal/mcpProtocol/v2024_11_05.js.map +1 -1
- package/dist/ai/internal/mcpProtocol/v2025_03_26.js +1 -0
- package/dist/ai/internal/mcpProtocol/v2025_03_26.js.map +1 -1
- package/dist/ai/internal/mcpProtocol/v2025_06_18.js +1 -0
- package/dist/ai/internal/mcpProtocol/v2025_06_18.js.map +1 -1
- package/dist/ai/internal/mcpProtocol/v2025_11_25.js +1 -0
- package/dist/ai/internal/mcpProtocol/v2025_11_25.js.map +1 -1
- package/dist/ai/internal/mcpSchema/v2024_11_05.js +3 -1
- package/dist/ai/internal/mcpSchema/v2024_11_05.js.map +1 -1
- package/dist/cluster/ClusterWorkflowEngine.d.ts.map +1 -1
- package/dist/cluster/ClusterWorkflowEngine.js +16 -3
- package/dist/cluster/ClusterWorkflowEngine.js.map +1 -1
- package/dist/cluster/MessageStorage.d.ts +32 -8
- package/dist/cluster/MessageStorage.d.ts.map +1 -1
- package/dist/cluster/MessageStorage.js +2 -1
- package/dist/cluster/MessageStorage.js.map +1 -1
- package/dist/cluster/Sharding.d.ts +5 -2
- package/dist/cluster/Sharding.d.ts.map +1 -1
- package/dist/cluster/Sharding.js +15 -8
- package/dist/cluster/Sharding.js.map +1 -1
- package/dist/cluster/SqlMessageStorage.d.ts.map +1 -1
- package/dist/cluster/SqlMessageStorage.js +36 -16
- package/dist/cluster/SqlMessageStorage.js.map +1 -1
- package/dist/cluster/SqlRunnerStorage.d.ts.map +1 -1
- package/dist/cluster/SqlRunnerStorage.js +30 -44
- package/dist/cluster/SqlRunnerStorage.js.map +1 -1
- package/dist/cluster/internal/entityManager.js +63 -62
- package/dist/cluster/internal/entityManager.js.map +1 -1
- package/dist/cluster/internal/interruptors.js +8 -0
- package/dist/cluster/internal/interruptors.js.map +1 -1
- package/dist/cluster/internal/resourceMap.js +39 -14
- package/dist/cluster/internal/resourceMap.js.map +1 -1
- package/dist/cluster/internal/resourceRef.js +168 -87
- package/dist/cluster/internal/resourceRef.js.map +1 -1
- package/dist/http/HttpEffect.d.ts +1 -0
- package/dist/http/HttpEffect.d.ts.map +1 -1
- package/dist/http/HttpEffect.js +29 -22
- package/dist/http/HttpEffect.js.map +1 -1
- package/dist/http/HttpMiddleware.d.ts.map +1 -1
- package/dist/http/HttpMiddleware.js +3 -2
- package/dist/http/HttpMiddleware.js.map +1 -1
- package/dist/http/HttpStaticServer.d.ts.map +1 -1
- package/dist/http/HttpStaticServer.js +14 -0
- package/dist/http/HttpStaticServer.js.map +1 -1
- package/dist/http/HttpTraceContext.d.ts +1 -1
- package/dist/http/HttpTraceContext.d.ts.map +1 -1
- package/dist/http/HttpTraceContext.js +4 -4
- package/dist/http/HttpTraceContext.js.map +1 -1
- package/dist/http-api/HttpApiError.d.ts +1 -0
- package/dist/http-api/HttpApiError.d.ts.map +1 -1
- package/dist/http-api/HttpApiError.js +1 -0
- package/dist/http-api/HttpApiError.js.map +1 -1
- package/dist/internal/core.js +43 -2
- package/dist/internal/core.js.map +1 -1
- package/dist/internal/dateTime.js +1 -1
- package/dist/internal/dateTime.js.map +1 -1
- package/dist/internal/effect.js +138 -165
- package/dist/internal/effect.js.map +1 -1
- package/dist/internal/rcRef.js +59 -23
- package/dist/internal/rcRef.js.map +1 -1
- package/dist/internal/schema/annotations.js +1 -7
- package/dist/internal/schema/annotations.js.map +1 -1
- package/dist/internal/schema/codegen.js +56 -28
- package/dist/internal/schema/codegen.js.map +1 -1
- package/dist/internal/schema/fromJsonSchemaDocument.js +11 -8
- package/dist/internal/schema/fromJsonSchemaDocument.js.map +1 -1
- package/dist/internal/schema/toCodeDocument.js +10 -30
- package/dist/internal/schema/toCodeDocument.js.map +1 -1
- package/dist/internal/schema/toCodec.js +1 -15
- package/dist/internal/schema/toCodec.js.map +1 -1
- package/dist/internal/schema/toEquivalence.js +4 -3
- package/dist/internal/schema/toEquivalence.js.map +1 -1
- package/dist/internal/schema/toFormatter.js +4 -4
- package/dist/internal/schema/toFormatter.js.map +1 -1
- package/dist/reactivity/Atom.d.ts.map +1 -1
- package/dist/reactivity/Atom.js +6 -2
- package/dist/reactivity/Atom.js.map +1 -1
- package/dist/reactivity/AtomRpc.d.ts +3 -3
- package/dist/reactivity/AtomRpc.d.ts.map +1 -1
- package/dist/rpc/Rpc.d.ts +2 -2
- package/dist/rpc/Rpc.d.ts.map +1 -1
- package/dist/rpc/RpcClient.d.ts +7 -7
- package/dist/rpc/RpcClient.d.ts.map +1 -1
- package/dist/rpc/RpcClient.js +21 -16
- package/dist/rpc/RpcClient.js.map +1 -1
- package/dist/rpc/RpcMessage.d.ts +1 -1
- package/dist/rpc/RpcMessage.d.ts.map +1 -1
- package/dist/rpc/RpcServer.d.ts.map +1 -1
- package/dist/rpc/RpcServer.js +2 -2
- package/dist/rpc/RpcServer.js.map +1 -1
- package/dist/rpc/Utils.d.ts +2 -3
- package/dist/rpc/Utils.d.ts.map +1 -1
- package/dist/rpc/Utils.js +3 -4
- package/dist/rpc/Utils.js.map +1 -1
- package/dist/schema/SchemaCompiler/runtime.js +6 -1
- package/dist/schema/SchemaCompiler/runtime.js.map +1 -1
- package/dist/testing/TestSchema.d.ts +234 -6
- package/dist/testing/TestSchema.d.ts.map +1 -1
- package/dist/testing/TestSchema.js +244 -25
- package/dist/testing/TestSchema.js.map +1 -1
- package/dist/testing/index.d.ts +1 -0
- package/dist/testing/index.d.ts.map +1 -1
- package/dist/testing/index.js +1 -0
- package/dist/testing/index.js.map +1 -1
- package/dist/workflow/DurableDeferred.js +1 -1
- package/dist/workflow/DurableDeferred.js.map +1 -1
- package/dist/workflow/Workflow.js +1 -1
- package/dist/workflow/Workflow.js.map +1 -1
- package/dist/workflow/WorkflowEngine.d.ts +2 -0
- package/dist/workflow/WorkflowEngine.d.ts.map +1 -1
- package/dist/workflow/WorkflowEngine.js +1 -0
- package/dist/workflow/WorkflowEngine.js.map +1 -1
- package/package.json +1 -1
- package/src/Array.ts +31 -31
- package/src/Cache.ts +22 -16
- package/src/Cause.ts +1 -1
- package/src/Chunk.ts +29 -29
- package/src/Effect.ts +170 -39
- package/src/HashRing.ts +14 -5
- package/src/MutableHashMap.ts +4 -24
- package/src/Option.ts +19 -19
- package/src/Pool.ts +28 -36
- package/src/Queue.ts +26 -6
- package/src/RcMap.ts +26 -2
- package/src/Record.ts +20 -20
- package/src/Schema.ts +48 -24
- package/src/SchemaAST.ts +135 -115
- package/src/SchemaRepresentation.ts +3 -1
- package/src/ScopedCache.ts +27 -16
- package/src/Stream.ts +158 -88
- package/src/ai/LanguageModel.ts +27 -2
- package/src/ai/McpSchema.ts +3 -3
- package/src/ai/McpServer.ts +12 -3
- package/src/ai/Response.ts +27 -12
- package/src/ai/internal/mcpProtocol/v2024_11_05.ts +1 -0
- package/src/ai/internal/mcpProtocol/v2025_03_26.ts +1 -0
- package/src/ai/internal/mcpProtocol/v2025_06_18.ts +1 -0
- package/src/ai/internal/mcpProtocol/v2025_11_25.ts +1 -0
- package/src/ai/internal/mcpSchema/v2024_11_05.ts +4 -2
- package/src/cluster/ClusterWorkflowEngine.ts +26 -5
- package/src/cluster/MessageStorage.ts +22 -5
- package/src/cluster/Sharding.ts +32 -28
- package/src/cluster/SqlMessageStorage.ts +45 -21
- package/src/cluster/SqlRunnerStorage.ts +85 -113
- package/src/cluster/internal/entityManager.ts +68 -80
- package/src/cluster/internal/interruptors.ts +13 -0
- package/src/cluster/internal/resourceMap.ts +55 -17
- package/src/cluster/internal/resourceRef.ts +189 -96
- package/src/http/HttpEffect.ts +15 -9
- package/src/http/HttpMiddleware.ts +8 -2
- package/src/http/HttpStaticServer.ts +16 -0
- package/src/http/HttpTraceContext.ts +8 -4
- package/src/http-api/HttpApiError.ts +1 -0
- package/src/internal/core.ts +56 -2
- package/src/internal/dateTime.ts +3 -1
- package/src/internal/effect.ts +146 -173
- package/src/internal/rcRef.ts +83 -33
- package/src/internal/schema/annotations.ts +0 -9
- package/src/internal/schema/codegen.ts +90 -43
- package/src/internal/schema/fromJsonSchemaDocument.ts +5 -3
- package/src/internal/schema/toCodeDocument.ts +10 -47
- package/src/internal/schema/toCodec.ts +3 -16
- package/src/internal/schema/toEquivalence.ts +4 -5
- package/src/internal/schema/toFormatter.ts +4 -6
- package/src/reactivity/Atom.ts +6 -2
- package/src/reactivity/AtomRpc.ts +5 -5
- package/src/rpc/Rpc.ts +2 -2
- package/src/rpc/RpcClient.ts +35 -32
- package/src/rpc/RpcMessage.ts +1 -1
- package/src/rpc/RpcServer.ts +2 -1
- package/src/rpc/Utils.ts +4 -10
- package/src/schema/SchemaCompiler/runtime.ts +17 -1
- package/src/testing/TestSchema.ts +315 -63
- package/src/testing/index.ts +1 -0
- package/src/workflow/DurableDeferred.ts +1 -1
- package/src/workflow/Workflow.ts +1 -1
- package/src/workflow/WorkflowEngine.ts +4 -0
package/src/internal/rcRef.ts
CHANGED
|
@@ -7,17 +7,26 @@ import { identity } from "../Function.ts"
|
|
|
7
7
|
import { pipeArguments } from "../Pipeable.ts"
|
|
8
8
|
import type * as RcRef from "../RcRef.ts"
|
|
9
9
|
import * as Scope from "../Scope.ts"
|
|
10
|
-
import * as Semaphore from "../Semaphore.ts"
|
|
11
10
|
|
|
12
11
|
const TypeId = "~effect/RcRef"
|
|
13
12
|
|
|
14
|
-
type State<A> = State.Empty | State.Acquired<A> | State.Closed
|
|
13
|
+
type State<A> = State.Empty | State.Acquiring<A> | State.Acquired<A> | State.Closed
|
|
15
14
|
|
|
16
15
|
declare namespace State {
|
|
17
16
|
interface Empty {
|
|
18
17
|
readonly _tag: "Empty"
|
|
19
18
|
}
|
|
20
19
|
|
|
20
|
+
interface Acquiring<A> {
|
|
21
|
+
readonly _tag: "Acquiring"
|
|
22
|
+
// Assigned as soon as the acquisition is forked.
|
|
23
|
+
fiber: Fiber.Fiber<Acquired<A>, unknown>
|
|
24
|
+
awaiters: number
|
|
25
|
+
// Set once references are allocated to the waiters, which can happen
|
|
26
|
+
// before the acquisition fiber exits.
|
|
27
|
+
acquired: Acquired<A> | undefined
|
|
28
|
+
}
|
|
29
|
+
|
|
21
30
|
interface Acquired<A> {
|
|
22
31
|
readonly _tag: "Acquired"
|
|
23
32
|
readonly value: A
|
|
@@ -48,7 +57,6 @@ class RcRefImpl<A, E> implements RcRef.RcRef<A, E> {
|
|
|
48
57
|
}
|
|
49
58
|
|
|
50
59
|
state: State<A> = stateEmpty
|
|
51
|
-
readonly semaphore = Semaphore.makeUnsafe(1)
|
|
52
60
|
readonly acquire: Effect.Effect<A, E>
|
|
53
61
|
readonly context: Context.Context<never>
|
|
54
62
|
readonly scope: Scope.Scope
|
|
@@ -85,11 +93,11 @@ export const make = <A, E, R>(options: {
|
|
|
85
93
|
)
|
|
86
94
|
return Effect.as(
|
|
87
95
|
Scope.addFinalizerExit(scope, () => {
|
|
88
|
-
const
|
|
89
|
-
? Scope.close(ref.state.scope, Exit.void)
|
|
90
|
-
: Effect.void
|
|
96
|
+
const state = ref.state
|
|
91
97
|
ref.state = stateClosed
|
|
92
|
-
return close
|
|
98
|
+
if (state._tag === "Acquired") return Scope.close(state.scope, Exit.void)
|
|
99
|
+
if (state._tag === "Acquiring") return Fiber.interrupt(state.fiber)
|
|
100
|
+
return Effect.void
|
|
93
101
|
}),
|
|
94
102
|
ref
|
|
95
103
|
)
|
|
@@ -110,40 +118,82 @@ const getState = <A, E>(
|
|
|
110
118
|
? Effect.as(Fiber.interrupt(state.fiber), state)
|
|
111
119
|
: Effect.succeed(state)
|
|
112
120
|
}
|
|
121
|
+
case "Acquiring": {
|
|
122
|
+
const state = self.state
|
|
123
|
+
state.awaiters++
|
|
124
|
+
return awaitAcquiring(self, state, restore)
|
|
125
|
+
}
|
|
113
126
|
case "Empty": {
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
127
|
+
// The caller that starts the acquisition counts as its first awaiter.
|
|
128
|
+
const acquiring: State.Acquiring<A> = {
|
|
129
|
+
_tag: "Acquiring",
|
|
130
|
+
fiber: undefined as any,
|
|
131
|
+
awaiters: 1,
|
|
132
|
+
acquired: undefined
|
|
133
|
+
}
|
|
134
|
+
self.state = acquiring
|
|
135
|
+
const scope = Scope.makeUnsafe()
|
|
136
|
+
// Acquire on a detached fiber so the acquisition is shared by every
|
|
137
|
+
// caller and only interrupted once all of them have been interrupted.
|
|
138
|
+
const acquire = Effect.provideContext(
|
|
139
|
+
self.acquire as Effect.Effect<A, E>,
|
|
140
|
+
Context.add(self.context, Scope.Scope, scope)
|
|
141
|
+
).pipe(
|
|
142
|
+
Effect.flatMap((value) => {
|
|
143
|
+
// The ref was closed, or the acquisition was abandoned.
|
|
144
|
+
if (self.state !== acquiring) {
|
|
145
|
+
return Effect.interrupt
|
|
146
|
+
}
|
|
147
|
+
const state: State.Acquired<A> = {
|
|
148
|
+
_tag: "Acquired",
|
|
149
|
+
value,
|
|
150
|
+
scope,
|
|
151
|
+
fiber: undefined,
|
|
152
|
+
// Every caller still waiting holds a reference.
|
|
153
|
+
refCount: acquiring.awaiters,
|
|
154
|
+
invalidated: false
|
|
118
155
|
}
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
}
|
|
128
|
-
const state: State.Acquired<A> = {
|
|
129
|
-
_tag: "Acquired",
|
|
130
|
-
value,
|
|
131
|
-
scope,
|
|
132
|
-
fiber: undefined,
|
|
133
|
-
refCount: 1,
|
|
134
|
-
invalidated: false
|
|
135
|
-
}
|
|
136
|
-
self.state = state
|
|
137
|
-
return Effect.succeed(state)
|
|
138
|
-
}),
|
|
139
|
-
Effect.onExit((exit) => Exit.isFailure(exit) ? Scope.close(scope, exit) : Effect.void)
|
|
140
|
-
)
|
|
156
|
+
self.state = state
|
|
157
|
+
acquiring.acquired = state
|
|
158
|
+
return Effect.succeed(state)
|
|
159
|
+
}),
|
|
160
|
+
Effect.onExit((exit) => {
|
|
161
|
+
if (Exit.isSuccess(exit)) return Effect.void
|
|
162
|
+
if (self.state === acquiring) self.state = stateEmpty
|
|
163
|
+
return Scope.close(scope, exit)
|
|
141
164
|
})
|
|
142
165
|
)
|
|
166
|
+
acquiring.fiber = Effect.runForkWith(Fiber.getCurrent()!.context)(acquire)
|
|
167
|
+
return awaitAcquiring(self, acquiring, restore)
|
|
143
168
|
}
|
|
144
169
|
}
|
|
145
170
|
}
|
|
146
171
|
|
|
172
|
+
const awaitAcquiring = <A, E>(
|
|
173
|
+
self: RcRefImpl<A, E>,
|
|
174
|
+
acquiring: State.Acquiring<A>,
|
|
175
|
+
restore: <AX, EX, RX>(effect: Effect.Effect<AX, EX, RX>) => Effect.Effect<AX, EX, RX>
|
|
176
|
+
): Effect.Effect<State.Acquired<A>, E> =>
|
|
177
|
+
Effect.onExit(
|
|
178
|
+
restore(Fiber.join(acquiring.fiber)) as Effect.Effect<State.Acquired<A>, E>,
|
|
179
|
+
(exit) => {
|
|
180
|
+
const acquired = acquiring.acquired
|
|
181
|
+
if (acquired !== undefined) {
|
|
182
|
+
// The acquisition counted this caller as a reference, possibly before
|
|
183
|
+
// its fiber exited. Release it if the caller was interrupted before it
|
|
184
|
+
// could register its finalizer.
|
|
185
|
+
return Exit.isFailure(exit) ? release(self, acquired) : Effect.void
|
|
186
|
+
}
|
|
187
|
+
// Abandon the acquisition once every caller has left, unless it already
|
|
188
|
+
// failed (a failed acquisition allocated no references).
|
|
189
|
+
if (--acquiring.awaiters > 0 || self.state !== acquiring) return Effect.void
|
|
190
|
+
// Detach it first so new callers start a fresh acquisition instead of
|
|
191
|
+
// joining one that is being interrupted.
|
|
192
|
+
self.state = stateEmpty
|
|
193
|
+
return Fiber.interrupt(acquiring.fiber)
|
|
194
|
+
}
|
|
195
|
+
)
|
|
196
|
+
|
|
147
197
|
/** @internal */
|
|
148
198
|
export const get = <A, E>(self_: RcRef.RcRef<A, E>): Effect.Effect<A, E, Scope.Scope> => {
|
|
149
199
|
const self = self_ as RcRefImpl<A, E>
|
|
@@ -50,9 +50,6 @@ export const resolveTitle = resolveAt<string>("title")
|
|
|
50
50
|
/** @internal */
|
|
51
51
|
export const resolveDescription = resolveAt<string>("description")
|
|
52
52
|
|
|
53
|
-
/** @internal */
|
|
54
|
-
export const resolveBrands = resolveAt<ReadonlyArray<string>>("brands")
|
|
55
|
-
|
|
56
53
|
/** @internal */
|
|
57
54
|
export const getExpected = memoize((ast: SchemaAST.AST): string => {
|
|
58
55
|
const identifier = resolve(ast)?.identifier
|
|
@@ -60,18 +57,12 @@ export const getExpected = memoize((ast: SchemaAST.AST): string => {
|
|
|
60
57
|
return ast.getExpected(getExpected)
|
|
61
58
|
})
|
|
62
59
|
|
|
63
|
-
/** @internal */
|
|
64
|
-
export function collectBrands(annotations: Schema.Annotations.Annotations | undefined): ReadonlyArray<string> {
|
|
65
|
-
return annotations !== undefined && Array.isArray(annotations.brands) ? annotations.brands : []
|
|
66
|
-
}
|
|
67
|
-
|
|
68
60
|
/** @internal */
|
|
69
61
|
export const annotationExcludedKeys = new Set([
|
|
70
62
|
SENTINELS_ANNOTATION_KEY,
|
|
71
63
|
STRUCTURAL_ANNOTATION_KEY,
|
|
72
64
|
"representation",
|
|
73
65
|
"arbitraryConstraint",
|
|
74
|
-
"brands",
|
|
75
66
|
"toJsonSchema",
|
|
76
67
|
"toCode",
|
|
77
68
|
"toEquivalence",
|
|
@@ -22,13 +22,21 @@ type Facts = {
|
|
|
22
22
|
supported: boolean
|
|
23
23
|
outputFree: boolean
|
|
24
24
|
makeSafe: boolean
|
|
25
|
+
hasOneOf: boolean
|
|
25
26
|
nodes: number
|
|
26
27
|
height: number
|
|
27
28
|
}
|
|
28
29
|
|
|
29
30
|
const factsCache = new WeakMap<SchemaAST.AST, Facts>()
|
|
30
31
|
|
|
31
|
-
const unsupportedFacts: Facts = {
|
|
32
|
+
const unsupportedFacts: Facts = {
|
|
33
|
+
supported: false,
|
|
34
|
+
outputFree: false,
|
|
35
|
+
makeSafe: false,
|
|
36
|
+
hasOneOf: false,
|
|
37
|
+
nodes: 1,
|
|
38
|
+
height: 0
|
|
39
|
+
}
|
|
32
40
|
|
|
33
41
|
const isMakeSafeNode = (ast: SchemaAST.AST): boolean =>
|
|
34
42
|
ast._tag !== "Union" && ast._tag !== "Declaration" && ast._tag !== "Suspend" &&
|
|
@@ -59,6 +67,7 @@ const addChild = (
|
|
|
59
67
|
}
|
|
60
68
|
if (!childFacts.outputFree) facts.outputFree = false
|
|
61
69
|
if (!childFacts.makeSafe) facts.makeSafe = false
|
|
70
|
+
if (childFacts.hasOneOf) facts.hasOneOf = true
|
|
62
71
|
facts.nodes += childFacts.nodes
|
|
63
72
|
if (childFacts.height >= facts.height) facts.height = childFacts.height + 1
|
|
64
73
|
return true
|
|
@@ -89,13 +98,25 @@ const getFacts = (
|
|
|
89
98
|
return budget.remaining < 0 || depth + cached.height > maxGeneratedDepth ? undefined : cached
|
|
90
99
|
}
|
|
91
100
|
if (--budget.remaining < 0 || depth > maxGeneratedDepth) return undefined
|
|
92
|
-
const facts: Facts = {
|
|
101
|
+
const facts: Facts = {
|
|
102
|
+
supported: true,
|
|
103
|
+
outputFree: true,
|
|
104
|
+
makeSafe: true,
|
|
105
|
+
hasOneOf: ast._tag === "Union" && ast.options?.mode === "oneOf",
|
|
106
|
+
nodes: 1,
|
|
107
|
+
height: 0
|
|
108
|
+
}
|
|
93
109
|
const next = depth + 1
|
|
94
110
|
switch (ast._tag) {
|
|
95
111
|
case "TemplateLiteral":
|
|
96
112
|
for (const part of ast.parts) {
|
|
97
113
|
if (!addChild(facts, part, next, budget)) return stop(ast, facts)
|
|
98
114
|
}
|
|
115
|
+
// matchPart only segments the input; the tuple parser enforces oneOf.
|
|
116
|
+
if (facts.hasOneOf) {
|
|
117
|
+
facts.supported = false
|
|
118
|
+
return stop(ast, facts)
|
|
119
|
+
}
|
|
99
120
|
break
|
|
100
121
|
case "Arrays":
|
|
101
122
|
for (const element of ast.elements) {
|
|
@@ -297,12 +318,10 @@ const emitUnionHelper = (ast: SchemaAST.Union, emitter: Emitter, operation: Oper
|
|
|
297
318
|
if (cached !== undefined) return cached
|
|
298
319
|
const name = `u${emitter.next++}`
|
|
299
320
|
emitter.unionHelpers.set(ast, name)
|
|
300
|
-
const
|
|
301
|
-
|
|
302
|
-
emitDecoderHelper(type, emitter, operation, `${path}.types[${index}]`)
|
|
303
|
-
}]`
|
|
321
|
+
const decoders = ast.types.map((type, index) =>
|
|
322
|
+
emitDecoderHelper(type, emitter, operation, `${path}.types[${index}]`)
|
|
304
323
|
)
|
|
305
|
-
emitter.initializers.push(`const ${name}=
|
|
324
|
+
emitter.initializers.push(`const ${name}=[${decoders.join(",")}]`)
|
|
306
325
|
return name
|
|
307
326
|
}
|
|
308
327
|
|
|
@@ -607,20 +626,22 @@ const emitBase = (
|
|
|
607
626
|
const decoder = variable(emitter)
|
|
608
627
|
const types = constant(emitter, ast.types, `${path}.types`)
|
|
609
628
|
const decoders = emitUnionHelper(ast, emitter, operation, path)
|
|
629
|
+
const select = variable(emitter)
|
|
630
|
+
emitter.initializers.push(`const ${select}=U(${types})`)
|
|
610
631
|
statements.push(
|
|
611
|
-
`const ${candidates}
|
|
632
|
+
`const ${candidates}=${select}(${input},false)`,
|
|
612
633
|
`let ${output}=${invalid},${candidate},${decoder}`
|
|
613
634
|
)
|
|
614
635
|
if (ast.options?.mode !== "oneOf") {
|
|
615
636
|
statements.push(
|
|
616
|
-
`for(let ${index}=0;${index}<${candidates}.length;${index}++){${decoder}=${decoders}
|
|
637
|
+
`for(let ${index}=0;${index}<${candidates}.length;${index}++){${decoder}=${decoders}[${candidates}[${index}]];${candidate}=${decoder}(${input},o);if(${candidate}!==${invalid}){${output}=${candidate};break}}`
|
|
617
638
|
)
|
|
618
639
|
statements.push(`if(${output}===${invalid})return ${invalid}`)
|
|
619
640
|
} else {
|
|
620
641
|
const successes = variable(emitter)
|
|
621
642
|
statements.push(`let ${successes}=0`)
|
|
622
643
|
statements.push(
|
|
623
|
-
`for(let ${index}=0;${index}<${candidates}.length;${index}++){${decoder}=${decoders}
|
|
644
|
+
`for(let ${index}=0;${index}<${candidates}.length;${index}++){${decoder}=${decoders}[${candidates}[${index}]];${candidate}=${decoder}(${input},o);if(${candidate}!==${invalid}){if(++${successes}>1)return ${invalid};${output}=${candidate}}}`
|
|
624
645
|
)
|
|
625
646
|
statements.push(`if(${successes}!==1)return ${invalid}`)
|
|
626
647
|
}
|
|
@@ -664,7 +685,7 @@ const emitOperation = (ast: SchemaAST.AST, operation: Operation, path = "ast"):
|
|
|
664
685
|
const bindings = {
|
|
665
686
|
K: "getCheckIssues",
|
|
666
687
|
T: "matchesTemplateLiteral",
|
|
667
|
-
U: "
|
|
688
|
+
U: "getCandidateIndex",
|
|
668
689
|
G: "getIndexSignatureKeys",
|
|
669
690
|
D: "defaultParseOptions",
|
|
670
691
|
E: "hasExcessProperties"
|
|
@@ -761,17 +782,13 @@ const inlineTypePredicate = (ast: SchemaAST.AST, input: string, path: string): s
|
|
|
761
782
|
case "BigInt":
|
|
762
783
|
return `typeof ${input}==="bigint"`
|
|
763
784
|
case "TemplateLiteral":
|
|
764
|
-
|
|
785
|
+
// Its parser reports structured issues, not an InvalidType failure.
|
|
786
|
+
return undefined
|
|
765
787
|
default:
|
|
766
788
|
return undefined
|
|
767
789
|
}
|
|
768
790
|
}
|
|
769
791
|
|
|
770
|
-
const inlineIdentityPredicate = (ast: SchemaAST.AST, input: string, path: string): string | undefined =>
|
|
771
|
-
ast.checks === undefined && getEncodingChecks(ast) === undefined
|
|
772
|
-
? inlineTypePredicate(ast, input, path)
|
|
773
|
-
: undefined
|
|
774
|
-
|
|
775
792
|
const emitEncoding = (ast: SchemaAST.AST): string | undefined => {
|
|
776
793
|
const links = ast.encoding
|
|
777
794
|
if (links?.length !== 1 || getEncodingChecks(ast) !== undefined) return undefined
|
|
@@ -779,7 +796,6 @@ const emitEncoding = (ast: SchemaAST.AST): string | undefined => {
|
|
|
779
796
|
const transformation = link.transformation
|
|
780
797
|
if (
|
|
781
798
|
link.to.encoding !== undefined ||
|
|
782
|
-
link.to.checks !== undefined ||
|
|
783
799
|
getEncodingChecks(link.to) !== undefined ||
|
|
784
800
|
transformation._tag !== "Transformation" ||
|
|
785
801
|
transformation.decode._tag !== "Transform"
|
|
@@ -790,10 +806,14 @@ const emitEncoding = (ast: SchemaAST.AST): string | undefined => {
|
|
|
790
806
|
const target = inlineTypePredicate(ast, "value", "ast")
|
|
791
807
|
if (source === undefined || target === undefined) return undefined
|
|
792
808
|
const success = ast.checks === undefined ? "R.succeed(value)" : "R.check(ast,value,o)"
|
|
793
|
-
|
|
809
|
+
const sourceChecks = link.to.checks === undefined
|
|
810
|
+
? ""
|
|
811
|
+
: "const issues=R.getCheckIssues(from,i,false,o);" +
|
|
812
|
+
"if(issues!==void 0)return R.invalidEncodingChecks(ast,i,issues,o);"
|
|
813
|
+
return `const transform=ast.encoding[0].transformation.decode.transform,from=ast.encoding[0].to;return function(i,o){try{
|
|
794
814
|
if(i===R.missing)return R.missingExit;
|
|
795
815
|
if(!(${source}))return R.invalidEncoding(ast,1,i,i,o);
|
|
796
|
-
const value=transform(i);
|
|
816
|
+
${sourceChecks}const value=transform(i);
|
|
797
817
|
if(value===R.missing)return R.missingExit;
|
|
798
818
|
if(!(${target}))return R.invalidEncoding(ast,0,i,value,o);
|
|
799
819
|
return ${success}
|
|
@@ -804,10 +824,13 @@ const canInlineEncoding = (ast: SchemaAST.AST): ast is SchemaAST.AST & { readonl
|
|
|
804
824
|
ast.encoding !== undefined &&
|
|
805
825
|
ast.checks === undefined &&
|
|
806
826
|
getEncodingChecks(ast) === undefined &&
|
|
807
|
-
|
|
808
|
-
ast.encoding.every((link) =>
|
|
827
|
+
inlineTypePredicate(ast, "v", "ast") !== undefined &&
|
|
828
|
+
ast.encoding.every((link, index, links) =>
|
|
809
829
|
link.to.encoding === undefined &&
|
|
810
|
-
|
|
830
|
+
getEncodingChecks(link.to) === undefined &&
|
|
831
|
+
// Only the initial source may have checks; they run before any transformation.
|
|
832
|
+
(link.to.checks === undefined || index === links.length - 1) &&
|
|
833
|
+
inlineTypePredicate(link.to, "v", "ast") !== undefined &&
|
|
811
834
|
link.transformation._tag === "Transformation" &&
|
|
812
835
|
(link.transformation.decode._tag === "Passthrough" || link.transformation.decode._tag === "Transform")
|
|
813
836
|
)
|
|
@@ -818,8 +841,18 @@ const inlinePropertyHandler =
|
|
|
818
841
|
const emitObject = (ast: SchemaAST.Objects): string => {
|
|
819
842
|
const initializers: Array<string> = []
|
|
820
843
|
const transforms = new Map<object, string>()
|
|
844
|
+
const bindTransform = (transform: object, path: string): string => {
|
|
845
|
+
let name = transforms.get(transform)
|
|
846
|
+
if (name === undefined) {
|
|
847
|
+
name = `t${transforms.size}`
|
|
848
|
+
transforms.set(transform, name)
|
|
849
|
+
initializers.push(`const ${name}=${path}`)
|
|
850
|
+
}
|
|
851
|
+
return name
|
|
852
|
+
}
|
|
821
853
|
let usesInlinePropertyHandler = false
|
|
822
854
|
let usesInlinePropertyFailure = false
|
|
855
|
+
let usesInlineSourceFailure = false
|
|
823
856
|
const lazyProperties = ast.propertySignatures.every((property) =>
|
|
824
857
|
typeof property.name !== "symbol" && canInlineEncoding(property.type)
|
|
825
858
|
)
|
|
@@ -845,51 +878,60 @@ const emitObject = (ast: SchemaAST.Objects): string => {
|
|
|
845
878
|
const descriptor = lazyProperties ? `p(${index})` : `p${index}`
|
|
846
879
|
const handleInline = `t=handle(state,${index},${descriptor},h${index},v${index},r);if(t)return t`
|
|
847
880
|
const links = property.type.encoding
|
|
881
|
+
const sourceAst = links[links.length - 1].to
|
|
848
882
|
const sourcePath = `${propertyPath}.encoding[${links.length - 1}].to`
|
|
849
|
-
const source =
|
|
883
|
+
const source = inlineTypePredicate(sourceAst, `v${index}`, sourcePath)!
|
|
884
|
+
const sourceChecks = sourceAst.checks !== undefined
|
|
885
|
+
if (sourceChecks) initializers.push(`const s${index}=${sourcePath}`)
|
|
886
|
+
const checkSource = sourceChecks ? `const c${index}=R.getCheckIssues(s${index},v${index},false,o);` : ""
|
|
850
887
|
// Share cold diagnostics without adding a call to the successful path.
|
|
851
888
|
if (lazyProperties && links.length === 1 && property.name !== "__proto__") {
|
|
852
889
|
usesInlinePropertyFailure = true
|
|
853
890
|
const transformation = links[0].transformation
|
|
854
891
|
let decoded = `v${index}`
|
|
855
892
|
if (transformation._tag === "Transformation" && transformation.decode._tag === "Transform") {
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
initializers.push(`const ${transform}=${propertyPath}.encoding[0].transformation.decode.transform`)
|
|
861
|
-
}
|
|
893
|
+
const transform = bindTransform(
|
|
894
|
+
transformation.decode.transform,
|
|
895
|
+
`${propertyPath}.encoding[0].transformation.decode.transform`
|
|
896
|
+
)
|
|
862
897
|
decoded = `${transform}(v${index})`
|
|
863
898
|
}
|
|
864
|
-
const predicate =
|
|
899
|
+
const predicate = inlineTypePredicate(property.type, `x${index}`, propertyPath)!
|
|
900
|
+
let run = `const x${index}=${decoded};` +
|
|
901
|
+
`if(x${index}!==R.missing&&(${predicate})){out[${key}]=x${index}}` +
|
|
902
|
+
`else{t=invalid(state,${index},h${index},v${index},x${index},o);if(t)return t}`
|
|
903
|
+
if (sourceChecks) {
|
|
904
|
+
usesInlineSourceFailure = true
|
|
905
|
+
run = `${checkSource}if(c${index}===void 0){${run}}` +
|
|
906
|
+
`else{t=invalidSource(state,${index},h${index},v${index},c${index},o);if(t)return t}`
|
|
907
|
+
}
|
|
865
908
|
statements.push(
|
|
866
909
|
`const h${index}=${present},v${index}=h${index}?i[${key}]:R.missing`,
|
|
867
|
-
`if(v${index}!==R.missing&&(${source})){
|
|
868
|
-
`if(x${index}!==R.missing&&(${predicate})){out[${key}]=x${index}}` +
|
|
869
|
-
`else{t=invalid(state,${index},h${index},v${index},x${index},o);if(t)return t}}` +
|
|
910
|
+
`if(v${index}!==R.missing&&(${source})){${run}}` +
|
|
870
911
|
`else{t=fallbackProperty(state,${index},h${index},v${index},o);if(t)return t}`
|
|
871
912
|
)
|
|
872
913
|
return
|
|
873
914
|
}
|
|
874
915
|
const fast: Array<string> = [`let x${index}=v${index};r=void 0;l${index}:{`]
|
|
916
|
+
if (sourceChecks) {
|
|
917
|
+
fast.push(
|
|
918
|
+
`${checkSource}if(c${index}!==void 0){r=R.invalidEncodingChecks(${descriptor}.type,v${index},c${index},o);break l${index}}`
|
|
919
|
+
)
|
|
920
|
+
}
|
|
875
921
|
for (let linkIndex = links.length - 1; linkIndex >= 0; linkIndex--) {
|
|
876
922
|
const transformation = links[linkIndex].transformation
|
|
877
923
|
if (transformation._tag === "Transformation" && transformation.decode._tag === "Transform") {
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
initializers.push(
|
|
883
|
-
`const ${transform}=${propertyPath}.encoding[${linkIndex}].transformation.decode.transform`
|
|
884
|
-
)
|
|
885
|
-
}
|
|
924
|
+
const transform = bindTransform(
|
|
925
|
+
transformation.decode.transform,
|
|
926
|
+
`${propertyPath}.encoding[${linkIndex}].transformation.decode.transform`
|
|
927
|
+
)
|
|
886
928
|
fast.push(`x${index}=${transform}(x${index})`)
|
|
887
929
|
}
|
|
888
930
|
const targetPath = linkIndex === 0
|
|
889
931
|
? propertyPath
|
|
890
932
|
: `${propertyPath}.encoding[${linkIndex - 1}].to`
|
|
891
933
|
const target = linkIndex === 0 ? property.type : links[linkIndex - 1].to
|
|
892
|
-
const predicate =
|
|
934
|
+
const predicate = inlineTypePredicate(target, `x${index}`, targetPath)!
|
|
893
935
|
fast.push(
|
|
894
936
|
`if(x${index}===R.missing){r=R.missingExit;break l${index}}else if(!(${predicate})){r=R.invalidEncoding(${descriptor}.type,${linkIndex},v${index},x${index},o);break l${index}}`
|
|
895
937
|
)
|
|
@@ -924,6 +966,11 @@ const emitObject = (ast: SchemaAST.Objects): string => {
|
|
|
924
966
|
"const fallbackProperty=(state,index,present,input,o)=>{const property=p(index);return handle(state,index,property,present,input,property.parser(input,o))}"
|
|
925
967
|
)
|
|
926
968
|
}
|
|
969
|
+
if (usesInlineSourceFailure) {
|
|
970
|
+
initializers.push(
|
|
971
|
+
"const invalidSource=(state,index,present,input,issues,o)=>{const property=p(index);return handle(state,index,property,present,input,R.invalidEncodingChecks(property.type,input,issues,o))}"
|
|
972
|
+
)
|
|
973
|
+
}
|
|
927
974
|
return `function({ast,getProperties,fallback,resume,step}){${initializers.join(";")};return function(i,o){try{${
|
|
928
975
|
statements.join(";")
|
|
929
976
|
}}catch(e){return R.die(e)}}}`
|
|
@@ -1067,13 +1067,15 @@ function translateJsonSchemaMultiDocument(
|
|
|
1067
1067
|
)
|
|
1068
1068
|
case "ignore":
|
|
1069
1069
|
return undefined
|
|
1070
|
-
case "apply":
|
|
1070
|
+
case "apply": {
|
|
1071
|
+
let regex: RegExp
|
|
1071
1072
|
try {
|
|
1072
|
-
globalThis.RegExp(pattern, jsonSchemaPatternFlags)
|
|
1073
|
+
regex = globalThis.RegExp(pattern, jsonSchemaPatternFlags)
|
|
1073
1074
|
} catch {
|
|
1074
1075
|
throw errorWithPath("Cannot import pattern using ECMAScript Unicode mode.", path)
|
|
1075
1076
|
}
|
|
1076
|
-
return jsonSchemaFilter("effect/schema/isPattern", { source:
|
|
1077
|
+
return jsonSchemaFilter("effect/schema/isPattern", { source: regex.source, flags: regex.flags })
|
|
1078
|
+
}
|
|
1077
1079
|
}
|
|
1078
1080
|
}
|
|
1079
1081
|
|
|
@@ -297,31 +297,6 @@ export function toCodeDocument(
|
|
|
297
297
|
return representation?.schemas?.map((schema, index) => recur(schema, [...path, "schemas", index])) ?? []
|
|
298
298
|
}
|
|
299
299
|
|
|
300
|
-
function checkBrands(
|
|
301
|
-
check: SchemaRepresentation.Check
|
|
302
|
-
): ReadonlyArray<string> {
|
|
303
|
-
const own = InternalAnnotations.collectBrands(check.annotations)
|
|
304
|
-
if (
|
|
305
|
-
check._tag === "FilterGroup" &&
|
|
306
|
-
check.annotations?.toCode === undefined
|
|
307
|
-
) {
|
|
308
|
-
return [...own, ...check.checks.flatMap(checkBrands)]
|
|
309
|
-
}
|
|
310
|
-
return own
|
|
311
|
-
}
|
|
312
|
-
|
|
313
|
-
function runtimeBrands(brands: ReadonlyArray<string>): string {
|
|
314
|
-
return brands.length === 0
|
|
315
|
-
? ""
|
|
316
|
-
: `.pipe(${brands.map((brand) => `Schema.brand(${format(brand)})`).join(", ")})`
|
|
317
|
-
}
|
|
318
|
-
|
|
319
|
-
function typeBrands(brands: ReadonlyArray<string>): string {
|
|
320
|
-
if (brands.length === 0) return ""
|
|
321
|
-
addImport(`import type * as Brand from "effect/Brand"`)
|
|
322
|
-
return brands.map((brand) => ` & Brand.Brand<${format(brand)}>`).join("")
|
|
323
|
-
}
|
|
324
|
-
|
|
325
300
|
function runtimeAnnotate(
|
|
326
301
|
annotations: Schema.Annotations.Annotations | undefined,
|
|
327
302
|
method: "annotate" | "annotateKey" = "annotate"
|
|
@@ -361,25 +336,19 @@ export function toCodeDocument(
|
|
|
361
336
|
function applyNode(
|
|
362
337
|
base: SchemaRepresentation.Code,
|
|
363
338
|
representation: Exclude<SchemaRepresentation.Representation, SchemaRepresentation.Reference>,
|
|
364
|
-
path: Path
|
|
365
|
-
includeTypeBrands: boolean = true
|
|
339
|
+
path: Path
|
|
366
340
|
): SchemaRepresentation.Code {
|
|
367
|
-
|
|
368
|
-
let runtime = base.runtime + runtimeAnnotate(representation.annotations) + runtimeBrands(nodeBrands)
|
|
369
|
-
let Type = base.Type + (includeTypeBrands ? typeBrands(nodeBrands) : "")
|
|
341
|
+
let runtime = base.runtime + runtimeAnnotate(representation.annotations)
|
|
370
342
|
for (let index = 0; index < representation.checks.length; index++) {
|
|
371
343
|
const check = representation.checks[index]
|
|
372
|
-
|
|
373
|
-
runtime += `.check(${compileCheck(check, [...path, "checks", index])})${runtimeBrands(brands)}`
|
|
374
|
-
if (includeTypeBrands) Type += typeBrands(brands)
|
|
344
|
+
runtime += `.check(${compileCheck(check, [...path, "checks", index])})`
|
|
375
345
|
}
|
|
376
|
-
return makeCode(runtime, Type)
|
|
346
|
+
return makeCode(runtime, base.Type)
|
|
377
347
|
}
|
|
378
348
|
|
|
379
349
|
function recur(
|
|
380
350
|
representation: SchemaRepresentation.Representation,
|
|
381
|
-
path: Path
|
|
382
|
-
includeTypeBrands: boolean = true
|
|
351
|
+
path: Path
|
|
383
352
|
): SchemaRepresentation.Code {
|
|
384
353
|
if (representation._tag === "Reference") {
|
|
385
354
|
if (!Object.hasOwn(document.references, representation.$ref)) {
|
|
@@ -392,18 +361,14 @@ export function toCodeDocument(
|
|
|
392
361
|
) {
|
|
393
362
|
return makeCode(`Schema.suspend((): Schema.Codec<${identifier}> => ${identifier})`, identifier)
|
|
394
363
|
}
|
|
395
|
-
|
|
396
|
-
? identifier
|
|
397
|
-
: recur(document.references[representation.$ref], ["references", representation.$ref], false).Type
|
|
398
|
-
return makeCode(identifier, Type)
|
|
364
|
+
return makeCode(identifier, identifier)
|
|
399
365
|
}
|
|
400
|
-
return applyNode(on(representation, path
|
|
366
|
+
return applyNode(on(representation, path), representation, path)
|
|
401
367
|
}
|
|
402
368
|
|
|
403
369
|
function on(
|
|
404
370
|
representation: Exclude<SchemaRepresentation.Representation, SchemaRepresentation.Reference>,
|
|
405
|
-
path: Path
|
|
406
|
-
includeTypeBrands: boolean
|
|
371
|
+
path: Path
|
|
407
372
|
): SchemaRepresentation.Code {
|
|
408
373
|
switch (representation._tag) {
|
|
409
374
|
case "Declaration": {
|
|
@@ -473,7 +438,7 @@ export function toCodeDocument(
|
|
|
473
438
|
return makeCode(`Schema.Enum(${identifier})`, identifier)
|
|
474
439
|
}
|
|
475
440
|
case "TemplateLiteral": {
|
|
476
|
-
const parts = representation.parts.map((part, index) => recur(part, [...path, "parts", index]
|
|
441
|
+
const parts = representation.parts.map((part, index) => recur(part, [...path, "parts", index]))
|
|
477
442
|
const Type = `\`${parts.map((part) => `\${${part.Type}}`).join("")}\``
|
|
478
443
|
return makeCode(`Schema.TemplateLiteral([${parts.map((part) => part.runtime).join(", ")}])`, Type)
|
|
479
444
|
}
|
|
@@ -576,9 +541,7 @@ export function toCodeDocument(
|
|
|
576
541
|
? makeCode(`Schema.Literal(${literals[0]})`, literals[0])
|
|
577
542
|
: makeCode(`Schema.Literals([${literals.join(", ")}])`, literals.join(" | "))
|
|
578
543
|
}
|
|
579
|
-
const types = representation.types.map((type, index) =>
|
|
580
|
-
recur(type, [...path, "types", index], includeTypeBrands)
|
|
581
|
-
)
|
|
544
|
+
const types = representation.types.map((type, index) => recur(type, [...path, "types", index]))
|
|
582
545
|
const options = representation.options === undefined
|
|
583
546
|
? ""
|
|
584
547
|
: `, ${unionOptionsRuntime(representation.options)}`
|
|
@@ -33,22 +33,9 @@ function validateCanonicalObjectPropertyNames(ast: SchemaAST.Objects): void {
|
|
|
33
33
|
|
|
34
34
|
function makeReorder(getPriority: (ast: SchemaAST.AST) => number) {
|
|
35
35
|
return (types: ReadonlyArray<SchemaAST.AST>): ReadonlyArray<SchemaAST.AST> => {
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
indexMap.set(SchemaAST.toEncoded(types[i]), i)
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
// Create a sorted copy of the types array
|
|
43
|
-
const sortedTypes = [...types].sort((a, b) => {
|
|
44
|
-
a = SchemaAST.toEncoded(a)
|
|
45
|
-
b = SchemaAST.toEncoded(b)
|
|
46
|
-
const pa = getPriority(a)
|
|
47
|
-
const pb = getPriority(b)
|
|
48
|
-
if (pa !== pb) return pa - pb
|
|
49
|
-
// If priorities are equal, maintain original order (stable sort)
|
|
50
|
-
return indexMap.get(a)! - indexMap.get(b)!
|
|
51
|
-
})
|
|
36
|
+
const sortedTypes = [...types].sort((a, b) =>
|
|
37
|
+
getPriority(SchemaAST.toEncoded(a)) - getPriority(SchemaAST.toEncoded(b))
|
|
38
|
+
)
|
|
52
39
|
|
|
53
40
|
// Check if order changed by comparing arrays
|
|
54
41
|
const orderChanged = sortedTypes.some((ast, index) => ast !== types[index])
|
|
@@ -136,13 +136,12 @@ function recur(ast: SchemaAST.AST): Equivalence.Equivalence<any> {
|
|
|
136
136
|
}
|
|
137
137
|
case "Union": {
|
|
138
138
|
const types = SchemaAST.toType(ast).types
|
|
139
|
-
const
|
|
140
|
-
|
|
141
|
-
)
|
|
139
|
+
const index = SchemaAST.getCandidateIndex(types)
|
|
140
|
+
const compiled = types.map((candidate, i) => [SchemaParser._is(candidate), recur(ast.types[i])] as const)
|
|
142
141
|
return Equivalence.make((a, b) => {
|
|
143
|
-
const candidates =
|
|
142
|
+
const candidates = index(a, false)
|
|
144
143
|
for (let i = 0; i < candidates.length; i++) {
|
|
145
|
-
const [is, equivalence] = compiled
|
|
144
|
+
const [is, equivalence] = compiled[candidates[i]]
|
|
146
145
|
if (is(a) && is(b)) {
|
|
147
146
|
return equivalence(a, b)
|
|
148
147
|
}
|
|
@@ -217,14 +217,12 @@ export function toFormatter<T>(ast: SchemaAST.AST, options?: {
|
|
|
217
217
|
}
|
|
218
218
|
case "Union": {
|
|
219
219
|
const types = SchemaAST.toType(ast).types
|
|
220
|
-
const
|
|
221
|
-
const compiled =
|
|
222
|
-
types.map((candidate, i) => [candidate, [SchemaParser._is(candidate), recur(ast.types[i])] as const] as const)
|
|
223
|
-
)
|
|
220
|
+
const index = SchemaAST.getCandidateIndex(types)
|
|
221
|
+
const compiled = types.map((candidate, i) => [SchemaParser._is(candidate), recur(ast.types[i])] as const)
|
|
224
222
|
return (value) => {
|
|
225
|
-
const candidates =
|
|
223
|
+
const candidates = index(value, false)
|
|
226
224
|
for (let i = 0; i < candidates.length; i++) {
|
|
227
|
-
const [is, formatter] = compiled
|
|
225
|
+
const [is, formatter] = compiled[candidates[i]]
|
|
228
226
|
if (is(value)) {
|
|
229
227
|
return formatter(value)
|
|
230
228
|
}
|