effect 4.0.0-rc.118 → 4.0.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.
Files changed (132) hide show
  1. package/README.md +17 -4
  2. package/dist/Array.d.ts +25 -25
  3. package/dist/Array.d.ts.map +1 -1
  4. package/dist/Array.js +16 -16
  5. package/dist/Array.js.map +1 -1
  6. package/dist/Chunk.d.ts +26 -26
  7. package/dist/Chunk.d.ts.map +1 -1
  8. package/dist/Chunk.js +15 -15
  9. package/dist/Chunk.js.map +1 -1
  10. package/dist/Effect.d.ts +17 -17
  11. package/dist/Effect.d.ts.map +1 -1
  12. package/dist/Effect.js +5 -5
  13. package/dist/MutableHashMap.d.ts.map +1 -1
  14. package/dist/MutableHashMap.js +4 -22
  15. package/dist/MutableHashMap.js.map +1 -1
  16. package/dist/Option.d.ts +17 -17
  17. package/dist/Option.d.ts.map +1 -1
  18. package/dist/Option.js +6 -6
  19. package/dist/Option.js.map +1 -1
  20. package/dist/Queue.d.ts +19 -2
  21. package/dist/Queue.d.ts.map +1 -1
  22. package/dist/Queue.js +9 -4
  23. package/dist/Queue.js.map +1 -1
  24. package/dist/Record.d.ts +14 -14
  25. package/dist/Record.d.ts.map +1 -1
  26. package/dist/Record.js +10 -10
  27. package/dist/Record.js.map +1 -1
  28. package/dist/Schema.d.ts +37 -21
  29. package/dist/Schema.d.ts.map +1 -1
  30. package/dist/Schema.js +29 -10
  31. package/dist/Schema.js.map +1 -1
  32. package/dist/SchemaAST.d.ts.map +1 -1
  33. package/dist/SchemaAST.js +116 -97
  34. package/dist/SchemaAST.js.map +1 -1
  35. package/dist/SchemaRepresentation.d.ts +3 -1
  36. package/dist/SchemaRepresentation.d.ts.map +1 -1
  37. package/dist/SchemaRepresentation.js +3 -1
  38. package/dist/SchemaRepresentation.js.map +1 -1
  39. package/dist/ai/McpSchema.d.ts +110 -110
  40. package/dist/ai/McpSchema.d.ts.map +1 -1
  41. package/dist/cluster/ClusterWorkflowEngine.d.ts.map +1 -1
  42. package/dist/cluster/ClusterWorkflowEngine.js +5 -1
  43. package/dist/cluster/ClusterWorkflowEngine.js.map +1 -1
  44. package/dist/cluster/MessageStorage.d.ts +32 -8
  45. package/dist/cluster/MessageStorage.d.ts.map +1 -1
  46. package/dist/cluster/MessageStorage.js +2 -1
  47. package/dist/cluster/MessageStorage.js.map +1 -1
  48. package/dist/cluster/Sharding.d.ts +5 -2
  49. package/dist/cluster/Sharding.d.ts.map +1 -1
  50. package/dist/cluster/Sharding.js +1 -1
  51. package/dist/cluster/Sharding.js.map +1 -1
  52. package/dist/cluster/SqlMessageStorage.d.ts.map +1 -1
  53. package/dist/cluster/SqlMessageStorage.js +15 -4
  54. package/dist/cluster/SqlMessageStorage.js.map +1 -1
  55. package/dist/http/HttpEffect.d.ts +1 -0
  56. package/dist/http/HttpEffect.d.ts.map +1 -1
  57. package/dist/http/HttpEffect.js +29 -22
  58. package/dist/http/HttpEffect.js.map +1 -1
  59. package/dist/internal/effect.js +75 -84
  60. package/dist/internal/effect.js.map +1 -1
  61. package/dist/internal/schema/annotations.js +1 -7
  62. package/dist/internal/schema/annotations.js.map +1 -1
  63. package/dist/internal/schema/codegen.js +56 -28
  64. package/dist/internal/schema/codegen.js.map +1 -1
  65. package/dist/internal/schema/toCodeDocument.js +10 -30
  66. package/dist/internal/schema/toCodeDocument.js.map +1 -1
  67. package/dist/internal/schema/toCodec.js +1 -15
  68. package/dist/internal/schema/toCodec.js.map +1 -1
  69. package/dist/internal/schema/toEquivalence.js +4 -3
  70. package/dist/internal/schema/toEquivalence.js.map +1 -1
  71. package/dist/internal/schema/toFormatter.js +4 -4
  72. package/dist/internal/schema/toFormatter.js.map +1 -1
  73. package/dist/reactivity/Atom.d.ts.map +1 -1
  74. package/dist/reactivity/Atom.js +6 -2
  75. package/dist/reactivity/Atom.js.map +1 -1
  76. package/dist/reactivity/AtomRpc.d.ts +3 -3
  77. package/dist/reactivity/AtomRpc.d.ts.map +1 -1
  78. package/dist/rpc/Rpc.d.ts +2 -2
  79. package/dist/rpc/Rpc.d.ts.map +1 -1
  80. package/dist/rpc/RpcClient.d.ts +7 -7
  81. package/dist/rpc/RpcClient.d.ts.map +1 -1
  82. package/dist/rpc/RpcClient.js +1 -2
  83. package/dist/rpc/RpcClient.js.map +1 -1
  84. package/dist/rpc/RpcMessage.d.ts +1 -1
  85. package/dist/rpc/RpcMessage.d.ts.map +1 -1
  86. package/dist/schema/SchemaCompiler/runtime.js +6 -1
  87. package/dist/schema/SchemaCompiler/runtime.js.map +1 -1
  88. package/dist/testing/TestSchema.d.ts +234 -6
  89. package/dist/testing/TestSchema.d.ts.map +1 -1
  90. package/dist/testing/TestSchema.js +244 -25
  91. package/dist/testing/TestSchema.js.map +1 -1
  92. package/dist/testing/index.d.ts +1 -0
  93. package/dist/testing/index.d.ts.map +1 -1
  94. package/dist/testing/index.js +1 -0
  95. package/dist/testing/index.js.map +1 -1
  96. package/dist/workflow/DurableDeferred.js +1 -1
  97. package/dist/workflow/DurableDeferred.js.map +1 -1
  98. package/dist/workflow/Workflow.js +1 -1
  99. package/dist/workflow/Workflow.js.map +1 -1
  100. package/package.json +1 -1
  101. package/src/Array.ts +31 -31
  102. package/src/Chunk.ts +29 -29
  103. package/src/Effect.ts +17 -17
  104. package/src/MutableHashMap.ts +4 -24
  105. package/src/Option.ts +19 -19
  106. package/src/Queue.ts +26 -6
  107. package/src/Record.ts +20 -20
  108. package/src/Schema.ts +48 -24
  109. package/src/SchemaAST.ts +135 -115
  110. package/src/SchemaRepresentation.ts +3 -1
  111. package/src/cluster/ClusterWorkflowEngine.ts +8 -1
  112. package/src/cluster/MessageStorage.ts +22 -5
  113. package/src/cluster/Sharding.ts +8 -4
  114. package/src/cluster/SqlMessageStorage.ts +19 -8
  115. package/src/http/HttpEffect.ts +15 -9
  116. package/src/internal/effect.ts +37 -62
  117. package/src/internal/schema/annotations.ts +0 -9
  118. package/src/internal/schema/codegen.ts +90 -43
  119. package/src/internal/schema/toCodeDocument.ts +10 -47
  120. package/src/internal/schema/toCodec.ts +3 -16
  121. package/src/internal/schema/toEquivalence.ts +4 -5
  122. package/src/internal/schema/toFormatter.ts +4 -6
  123. package/src/reactivity/Atom.ts +6 -2
  124. package/src/reactivity/AtomRpc.ts +5 -5
  125. package/src/rpc/Rpc.ts +2 -2
  126. package/src/rpc/RpcClient.ts +9 -10
  127. package/src/rpc/RpcMessage.ts +1 -1
  128. package/src/schema/SchemaCompiler/runtime.ts +17 -1
  129. package/src/testing/TestSchema.ts +315 -63
  130. package/src/testing/index.ts +1 -0
  131. package/src/workflow/DurableDeferred.ts +1 -1
  132. package/src/workflow/Workflow.ts +1 -1
@@ -7,14 +7,22 @@
7
7
  * `Decoding` and `Encoding` can be used directly when a test only needs one
8
8
  * direction.
9
9
  *
10
+ * Methods with an `Effect` suffix return lazy assertions that use the calling
11
+ * fiber's services. The Promise-returning methods can be used with any test
12
+ * runner.
13
+ *
14
+ * @stability unstable
10
15
  * @since 4.0.0
11
16
  */
12
17
  import * as assert from "node:assert"
13
18
  import { isDeepStrictEqual } from "node:util"
14
19
  import * as Arbitrary from "../Arbitrary.ts"
20
+ import * as Cause from "../Cause.ts"
15
21
  import type * as Context from "../Context.ts"
16
22
  import * as Effect from "../Effect.ts"
23
+ import * as Exit from "../Exit.ts"
17
24
  import { pipe } from "../Function.ts"
25
+ import * as InternalSchemaCause from "../internal/schema/cause.ts"
18
26
  import * as Result from "../Result.ts"
19
27
  import * as Schema from "../Schema.ts"
20
28
  import * as SchemaAST from "../SchemaAST.ts"
@@ -26,6 +34,32 @@ function assertPropertyPassed<A, E>(result: Arbitrary.CheckResult<A, E>): void {
26
34
  if (failure !== undefined) assert.fail(failure)
27
35
  }
28
36
 
37
+ const schemaResult = Effect.fnUntraced(function*<A, R>(
38
+ effect: Effect.Effect<A, SchemaIssue.Issue, R>
39
+ ): Effect.fn.Return<Result.Result<A, string>, never, R> {
40
+ const exit = yield* Effect.exit(effect)
41
+ if (Exit.isSuccess(exit)) {
42
+ return Result.succeed(exit.value)
43
+ }
44
+ const issue = InternalSchemaCause.getSchemaIssue(exit.cause)
45
+ if (issue !== undefined) {
46
+ return Result.fail(SchemaIssue.defaultFormatter(issue))
47
+ }
48
+ return yield* Effect.failCause(Cause.fromReasons<never>(exit.cause.reasons.map((reason) =>
49
+ Cause.isFailReason(reason)
50
+ ? Cause.makeDieReason(reason.error).annotate(Cause.reasonAnnotations(reason))
51
+ : reason
52
+ )))
53
+ })
54
+
55
+ const assertResult = Effect.fnUntraced(function*<A, R>(
56
+ parse: () => Effect.Effect<A, SchemaIssue.Issue, R>,
57
+ expected: Result.Result<A, string>
58
+ ) {
59
+ const result = yield* schemaResult(parse())
60
+ assert.deepStrictEqual(result, expected)
61
+ })
62
+
29
63
  /**
30
64
  * Provides schema test assertions for decoding, encoding, make, arbitrary generation, and round-trip verification.
31
65
  *
@@ -51,6 +85,7 @@ function assertPropertyPassed<A, E>(result: Arbitrary.CheckResult<A, E>): void {
51
85
  *
52
86
  * @see {@link Decoding}
53
87
  * @see {@link Encoding}
88
+ * @stability unstable
54
89
  * @category testing
55
90
  * @since 4.0.0
56
91
  */
@@ -77,9 +112,21 @@ export class Asserts<S extends Schema.Constraint> {
77
112
  * const fieldsB = { name: Schema.String }
78
113
  * TestSchema.Asserts.ast.fields.equals(fieldsA, fieldsB) // => undefined
79
114
  * ```
115
+ *
116
+ * @stability unstable
80
117
  */
81
118
  static ast = {
119
+ /**
120
+ * Groups schema field comparisons.
121
+ *
122
+ * @stability unstable
123
+ */
82
124
  fields: {
125
+ /**
126
+ * Asserts that schema fields have equal AST structures.
127
+ *
128
+ * @stability unstable
129
+ */
83
130
  equals: (a: Schema.Struct.Fields, b: Schema.Struct.Fields) => {
84
131
  assert.deepStrictEqual(
85
132
  Object.fromEntries(Reflect.ownKeys(a).map((key) => [key, SchemaAST.getAST(a[key])])),
@@ -87,19 +134,39 @@ export class Asserts<S extends Schema.Constraint> {
87
134
  )
88
135
  }
89
136
  },
137
+ /**
138
+ * Groups tuple element comparisons.
139
+ *
140
+ * @stability unstable
141
+ */
90
142
  elements: {
143
+ /**
144
+ * Asserts that tuple elements have equal AST structures.
145
+ *
146
+ * @stability unstable
147
+ */
91
148
  equals: (a: Schema.Tuple.Elements, b: Schema.Tuple.Elements) => {
92
149
  assert.deepStrictEqual(a.map(SchemaAST.getAST), b.map(SchemaAST.getAST))
93
150
  }
94
151
  }
95
152
  } as const
96
153
 
154
+ /**
155
+ * Schema used by these assertions.
156
+ *
157
+ * @stability unstable
158
+ */
97
159
  readonly schema: S
160
+ /**
161
+ * Creates assertions for a schema.
162
+ *
163
+ * @stability unstable
164
+ */
98
165
  constructor(schema: S) {
99
166
  this.schema = schema
100
167
  }
101
168
  /**
102
- * Returns an object with `succeed` and `fail` helpers for testing the schema's `make` operation.
169
+ * Returns Promise and Effect assertions for the schema's `make` operation.
103
170
  *
104
171
  * **When to use**
105
172
  *
@@ -109,6 +176,8 @@ export class Asserts<S extends Schema.Constraint> {
109
176
  * **Details**
110
177
  *
111
178
  * `succeed(input)` asserts make returns the input unchanged. `succeed(input, expected)` asserts make returns `expected`. `fail(input, message)` asserts make fails with `message`.
179
+ * `succeedEffect` and `failEffect` return lazy effects with the same assertions.
180
+ * Assertion mismatches are defects in the returned effects.
112
181
  *
113
182
  * **Example** (Testing make)
114
183
  *
@@ -123,31 +192,52 @@ export class Asserts<S extends Schema.Constraint> {
123
192
  *
124
193
  * @see {@link decoding} for assertions against decoded input
125
194
  * @see {@link encoding} for assertions against encoded output
195
+ * @stability unstable
126
196
  */
127
197
  make(options?: Schema.MakeOptions) {
128
198
  const makeEffect = SchemaParser.makeEffect(this.schema)
199
+ function succeedEffect(input: S["Type"]): Effect.Effect<void>
200
+ function succeedEffect(input: S["~type.make.in"], expected: S["Type"]): Effect.Effect<void>
201
+ function succeedEffect(input: S["~type.make.in"], expected?: S["Type"]): Effect.Effect<void> {
202
+ return assertResult(
203
+ () => makeEffect(input, options),
204
+ Result.succeed(arguments.length === 1 ? input : expected)
205
+ )
206
+ }
129
207
  async function succeed(input: S["Type"]): Promise<void>
130
208
  async function succeed(input: S["~type.make.in"], expected: S["Type"]): Promise<void>
131
209
  async function succeed(input: S["~type.make.in"], expected?: S["Type"]) {
132
- const r = await Effect.runPromise(
133
- makeEffect(input, options).pipe(
134
- Effect.mapErrorEager(SchemaIssue.defaultFormatter),
135
- Effect.result
136
- )
137
- )
138
- expected = arguments.length === 1 ? input : expected
139
- assert.deepStrictEqual(r, Result.succeed(expected))
210
+ return Effect.runPromise(succeedEffect(input, arguments.length === 1 ? input : expected))
211
+ }
212
+ function failEffect(input: unknown, message: string): Effect.Effect<void> {
213
+ return assertResult(() => makeEffect(input, options), Result.fail(message))
140
214
  }
141
215
  return {
216
+ /**
217
+ * Asserts that construction succeeds with the input or the explicit expected value.
218
+ *
219
+ * @stability unstable
220
+ */
142
221
  succeed,
222
+ /**
223
+ * Returns a lazy construction success assertion whose mismatches are defects.
224
+ *
225
+ * @stability unstable
226
+ */
227
+ succeedEffect,
228
+ /**
229
+ * Returns a lazy assertion that construction fails with the expected issue message.
230
+ *
231
+ * @stability unstable
232
+ */
233
+ failEffect,
234
+ /**
235
+ * Asserts that construction fails with the expected issue message.
236
+ *
237
+ * @stability unstable
238
+ */
143
239
  async fail(input: unknown, message: string) {
144
- const r = await Effect.runPromise(
145
- makeEffect(input, options).pipe(
146
- Effect.mapErrorEager(SchemaIssue.defaultFormatter),
147
- Effect.result
148
- )
149
- )
150
- assert.deepStrictEqual(r, Result.fail(message))
240
+ return Effect.runPromise(failEffect(input, message))
151
241
  }
152
242
  }
153
243
  }
@@ -171,29 +261,67 @@ export class Asserts<S extends Schema.Constraint> {
171
261
  * import { TestSchema } from "effect/testing"
172
262
  *
173
263
  * const asserts = new TestSchema.Asserts(Schema.String)
174
- * await asserts.verifyLosslessTransformation({ seed: 1, runs: 20 }) // => undefined
264
+ * await asserts.verifyRoundTrip({ seed: 1, runs: 20 }) // => undefined
175
265
  * ```
176
266
  *
177
267
  * @see {@link arbitrary} for checking that generated values satisfy the schema
268
+ * @see {@link verifyRoundTripEffect} for the Effect variant
269
+ * @stability unstable
178
270
  */
179
- verifyLosslessTransformation<S extends Schema.ConstraintCodec<unknown, unknown>>(
271
+ verifyRoundTrip<S extends Schema.ConstraintCodec<unknown, unknown>>(
180
272
  this: Asserts<S>,
181
273
  options?: Arbitrary.CheckOptions
182
274
  ): Promise<void> {
183
- const decodeUnknownEffect = SchemaParser.decodeUnknownEffect(this.schema)
184
- const encodeEffect = SchemaParser.encodeEffect(this.schema)
185
- const arbitrary = Arbitrary.schema(this.schema)
186
- return Effect.runPromise(Arbitrary.checkEffect(
187
- arbitrary,
188
- (value) =>
189
- encodeEffect(value).pipe(
190
- Effect.flatMapEager((encoded) => decodeUnknownEffect(encoded)),
191
- Effect.mapErrorEager(SchemaIssue.defaultFormatter),
192
- Effect.result,
193
- Effect.mapEager((result) => isDeepStrictEqual(result, Result.succeed(value)))
194
- ),
195
- options
196
- )).then(assertPropertyPassed)
275
+ return Effect.runPromise(this.verifyRoundTripEffect(options))
276
+ }
277
+ /**
278
+ * Returns a lazy property-based assertion that generated values survive an
279
+ * encode-then-decode round trip.
280
+ *
281
+ * **When to use**
282
+ *
283
+ * Use to check round trips with the calling fiber's decoding and encoding services.
284
+ *
285
+ * **Details**
286
+ *
287
+ * Assertion mismatches are defects containing the shrunk input and replay token.
288
+ * Schema defects and interruption propagate without becoming assertion failures.
289
+ *
290
+ * **Example** (Composing round-trip assertions)
291
+ *
292
+ * ```ts import.meta.vitest
293
+ * import { Effect, Schema } from "effect"
294
+ * import { TestSchema } from "effect/testing"
295
+ *
296
+ * const asserts = new TestSchema.Asserts(Schema.NumberFromString)
297
+ * const test = Effect.gen(function*() {
298
+ * yield* asserts.decoding().succeedEffect("42", 42)
299
+ * yield* asserts.verifyRoundTripEffect({ seed: 1, runs: 20 })
300
+ * })
301
+ * await Effect.runPromise(test) // => undefined
302
+ * ```
303
+ *
304
+ * @see {@link verifyRoundTrip} for the Promise variant
305
+ * @stability unstable
306
+ */
307
+ verifyRoundTripEffect(
308
+ options?: Arbitrary.CheckOptions
309
+ ): Effect.Effect<void, never, S["DecodingServices"] | S["EncodingServices"]> {
310
+ return Effect.suspend(() => {
311
+ const decodeUnknownEffect = SchemaParser.decodeUnknownEffect(this.schema)
312
+ const encodeEffect = SchemaParser.encodeEffect(this.schema)
313
+ const arbitrary = Arbitrary.schema(this.schema)
314
+ return Arbitrary.checkEffect(
315
+ arbitrary,
316
+ (value) =>
317
+ Effect.suspend(() => encodeEffect(value)).pipe(
318
+ Effect.flatMapEager((encoded) => decodeUnknownEffect(encoded)),
319
+ schemaResult,
320
+ Effect.mapEager((result) => isDeepStrictEqual(result, Result.succeed(value)))
321
+ ),
322
+ options
323
+ ).pipe(Effect.mapEager(assertPropertyPassed))
324
+ })
197
325
  }
198
326
  /**
199
327
  * Returns a {@link Decoding} instance for this schema with helpers for decoding assertions.
@@ -220,6 +348,7 @@ export class Asserts<S extends Schema.Constraint> {
220
348
  *
221
349
  * @see {@link Decoding}
222
350
  * @see {@link encoding} for assertions in the opposite direction
351
+ * @stability unstable
223
352
  */
224
353
  decoding(options?: {
225
354
  readonly parseOptions?: SchemaAST.ParseOptions | undefined
@@ -250,6 +379,7 @@ export class Asserts<S extends Schema.Constraint> {
250
379
  *
251
380
  * @see {@link Encoding}
252
381
  * @see {@link decoding} for assertions in the opposite direction
382
+ * @stability unstable
253
383
  */
254
384
  encoding(options?: {
255
385
  readonly parseOptions?: SchemaAST.ParseOptions | undefined
@@ -279,11 +409,17 @@ export class Asserts<S extends Schema.Constraint> {
279
409
  * asserts.arbitrary().verifyGeneration({ seed: 1, runs: 20 }) // => undefined
280
410
  * ```
281
411
  *
282
- * @see {@link verifyLosslessTransformation} for property-based round-trip checks
412
+ * @see {@link verifyRoundTrip} for property-based round-trip checks
413
+ * @stability unstable
283
414
  */
284
415
  arbitrary<S extends Schema.ConstraintCodec<unknown, unknown>>(this: Asserts<S>) {
285
416
  const schema = this.schema
286
417
  return {
418
+ /**
419
+ * Asserts that generated values satisfy the schema's predicate.
420
+ *
421
+ * @stability unstable
422
+ */
287
423
  verifyGeneration(options?: Arbitrary.CheckOptions): void {
288
424
  const is = Schema.is(schema)
289
425
  const arbitrary = Arbitrary.schema(schema)
@@ -302,7 +438,12 @@ export class Asserts<S extends Schema.Constraint> {
302
438
  *
303
439
  * **Details**
304
440
  *
305
- * All assertions are async and use `assert.deepStrictEqual` internally. `succeed(input)` asserts the decoded output equals `input`; `succeed(input, expected)` asserts it equals `expected`; `fail(input, message)` asserts decoding fails and the stringified issue equals `message`. `provide(key, impl)` returns a new `Decoding` with the service injected into the decoding context.
441
+ * `succeed` and `fail` return Promises. `succeedEffect` and `failEffect` return lazy
442
+ * effects that preserve required decoding services. All assertions use
443
+ * `assert.deepStrictEqual` internally. With one argument, success assertions
444
+ * compare the output to the input; with two, they compare it to `expected`.
445
+ * Failure assertions compare the formatted schema issue to `message`.
446
+ * `provide(key, impl)` returns a new `Decoding` with the service injected.
306
447
  *
307
448
  * **Example** (Decoding with service provision)
308
449
  *
@@ -317,18 +458,39 @@ export class Asserts<S extends Schema.Constraint> {
317
458
  *
318
459
  * @see {@link Asserts}
319
460
  * @see {@link Encoding}
461
+ * @stability unstable
320
462
  * @category testing
321
463
  * @since 4.0.0
322
464
  */
323
465
  export class Decoding<S extends Schema.Constraint> {
466
+ /**
467
+ * Schema used by these decoding assertions.
468
+ *
469
+ * @stability unstable
470
+ */
324
471
  readonly schema: S
472
+ /**
473
+ * Decoder used by these assertions, preserving schema issues and required services.
474
+ *
475
+ * @stability unstable
476
+ */
325
477
  readonly decodeUnknownEffect: (
326
478
  input: unknown,
327
479
  options?: SchemaAST.ParseOptions
328
480
  ) => Effect.Effect<S["Type"], SchemaIssue.Issue, S["DecodingServices"]>
481
+ /**
482
+ * Parsing options used by these assertions.
483
+ *
484
+ * @stability unstable
485
+ */
329
486
  readonly options?: {
330
487
  readonly parseOptions?: SchemaAST.ParseOptions | undefined
331
488
  } | undefined
489
+ /**
490
+ * Creates decoding assertions for a schema and optional parsing options.
491
+ *
492
+ * @stability unstable
493
+ */
332
494
  constructor(schema: S, options?: {
333
495
  readonly parseOptions?: SchemaAST.ParseOptions | undefined
334
496
  }) {
@@ -355,7 +517,9 @@ export class Decoding<S extends Schema.Constraint> {
355
517
  * await decoding.succeed("1", 1) // => undefined
356
518
  * ```
357
519
  *
520
+ * @see {@link succeedEffect} for the Effect variant
358
521
  * @see {@link fail} for asserting decoding failures
522
+ * @stability unstable
359
523
  */
360
524
  async succeed<S extends Schema.ConstraintDecoder<unknown, never>>(
361
525
  this: Decoding<S>,
@@ -371,14 +535,31 @@ export class Decoding<S extends Schema.Constraint> {
371
535
  input: unknown,
372
536
  expected?: S["Type"]
373
537
  ) {
374
- const r = await Effect.runPromise(
375
- this.decodeUnknownEffect(input, this.options?.parseOptions).pipe(
376
- Effect.mapErrorEager(SchemaIssue.defaultFormatter),
377
- Effect.result
378
- )
538
+ return Effect.runPromise(this.succeedEffect(input, arguments.length === 1 ? input : expected))
539
+ }
540
+ /**
541
+ * Returns a lazy assertion that decoding succeeds with the input or the
542
+ * explicit expected value.
543
+ *
544
+ * **When to use**
545
+ *
546
+ * Use to assert decoding in an Effect test while preserving required decoding services.
547
+ *
548
+ * **Details**
549
+ *
550
+ * Assertion mismatches are defects. The decoder uses the calling fiber's services.
551
+ *
552
+ * @see {@link succeed} for the Promise variant
553
+ * @see {@link failEffect} for asserting decoding failures
554
+ * @stability unstable
555
+ */
556
+ succeedEffect(input: unknown): Effect.Effect<void, never, S["DecodingServices"]>
557
+ succeedEffect(input: unknown, expected: S["Type"]): Effect.Effect<void, never, S["DecodingServices"]>
558
+ succeedEffect(input: unknown, expected?: S["Type"]): Effect.Effect<void, never, S["DecodingServices"]> {
559
+ return assertResult(
560
+ () => this.decodeUnknownEffect(input, this.options?.parseOptions),
561
+ Result.succeed(arguments.length === 1 ? input : expected)
379
562
  )
380
- expected = arguments.length === 1 ? input : expected
381
- assert.deepStrictEqual(r, Result.succeed(expected))
382
563
  }
383
564
  /**
384
565
  * Asserts that decoding `input` fails and the stringified issue equals
@@ -398,20 +579,32 @@ export class Decoding<S extends Schema.Constraint> {
398
579
  * await decoding.fail(42, "Expected string") // => undefined
399
580
  * ```
400
581
  *
582
+ * @see {@link failEffect} for the Effect variant
401
583
  * @see {@link succeed} for asserting successful decoding
584
+ * @stability unstable
402
585
  */
403
586
  async fail<S extends Schema.ConstraintDecoder<unknown, never>>(
404
587
  this: Decoding<S>,
405
588
  input: unknown,
406
589
  message: string
407
590
  ) {
408
- const r = await Effect.runPromise(
409
- this.decodeUnknownEffect(input, this.options?.parseOptions).pipe(
410
- Effect.mapErrorEager(SchemaIssue.defaultFormatter),
411
- Effect.result
412
- )
413
- )
414
- assert.deepStrictEqual(r, Result.fail(message))
591
+ return Effect.runPromise(this.failEffect(input, message))
592
+ }
593
+ /**
594
+ * Returns a lazy assertion that decoding fails with the expected issue message.
595
+ *
596
+ * **Details**
597
+ *
598
+ * Assertion mismatches are defects. Schema defects and interruption propagate
599
+ * without satisfying the assertion. Required decoding services come from the
600
+ * calling fiber.
601
+ *
602
+ * @see {@link fail} for the Promise variant
603
+ * @see {@link succeedEffect} for asserting decoding success
604
+ * @stability unstable
605
+ */
606
+ failEffect(input: unknown, message: string): Effect.Effect<void, never, S["DecodingServices"]> {
607
+ return assertResult(() => this.decodeUnknownEffect(input, this.options?.parseOptions), Result.fail(message))
415
608
  }
416
609
  /**
417
610
  * Returns a new {@link Decoding} instance with the given service injected into the decoding effect context.
@@ -421,6 +614,7 @@ export class Decoding<S extends Schema.Constraint> {
421
614
  * Use when the schema's decoder requires a service dependency.
422
615
  *
423
616
  * @see {@link Encoding.provide}
617
+ * @stability unstable
424
618
  */
425
619
  provide<Id, Service>(
426
620
  service: Context.Key<Id, Service>,
@@ -442,7 +636,12 @@ export class Decoding<S extends Schema.Constraint> {
442
636
  *
443
637
  * **Details**
444
638
  *
445
- * All assertions are async and use `assert.deepStrictEqual` internally. `succeed(input)` asserts the encoded output equals `input`; `succeed(input, expected)` asserts it equals `expected`; `fail(input, message)` asserts encoding fails and the stringified issue equals `message`. `provide(key, impl)` returns a new `Encoding` with the service injected into the encoding context.
639
+ * `succeed` and `fail` return Promises. `succeedEffect` and `failEffect` return lazy
640
+ * effects that preserve required encoding services. All assertions use
641
+ * `assert.deepStrictEqual` internally. With one argument, success assertions
642
+ * compare the output to the input; with two, they compare it to `expected`.
643
+ * Failure assertions compare the formatted schema issue to `message`.
644
+ * `provide(key, impl)` returns a new `Encoding` with the service injected.
446
645
  *
447
646
  * **Example** (Encoding assertions)
448
647
  *
@@ -457,18 +656,39 @@ export class Decoding<S extends Schema.Constraint> {
457
656
  * @see {@link Asserts}
458
657
  * @see {@link Decoding}
459
658
  *
659
+ * @stability unstable
460
660
  * @category testing
461
661
  * @since 4.0.0
462
662
  */
463
663
  export class Encoding<S extends Schema.Constraint> {
664
+ /**
665
+ * Schema used by these encoding assertions.
666
+ *
667
+ * @stability unstable
668
+ */
464
669
  readonly schema: S
670
+ /**
671
+ * Encoder used by these assertions, preserving schema issues and required services.
672
+ *
673
+ * @stability unstable
674
+ */
465
675
  readonly encodeUnknownEffect: (
466
676
  input: unknown,
467
677
  options?: SchemaAST.ParseOptions
468
678
  ) => Effect.Effect<S["Encoded"], SchemaIssue.Issue, S["EncodingServices"]>
679
+ /**
680
+ * Parsing options used by these assertions.
681
+ *
682
+ * @stability unstable
683
+ */
469
684
  readonly options?: {
470
685
  readonly parseOptions?: SchemaAST.ParseOptions | undefined
471
686
  } | undefined
687
+ /**
688
+ * Creates encoding assertions for a schema and optional parsing options.
689
+ *
690
+ * @stability unstable
691
+ */
472
692
  constructor(schema: S, options?: {
473
693
  readonly parseOptions?: SchemaAST.ParseOptions | undefined
474
694
  }) {
@@ -495,7 +715,9 @@ export class Encoding<S extends Schema.Constraint> {
495
715
  * await encoding.succeed(1, "1") // => undefined
496
716
  * ```
497
717
  *
718
+ * @see {@link succeedEffect} for the Effect variant
498
719
  * @see {@link fail} for asserting encoding failures
720
+ * @stability unstable
499
721
  */
500
722
  async succeed<S extends Schema.ConstraintEncoder<unknown, never>>(
501
723
  this: Encoding<S>,
@@ -511,14 +733,31 @@ export class Encoding<S extends Schema.Constraint> {
511
733
  input: unknown,
512
734
  expected?: S["Encoded"]
513
735
  ) {
514
- const r = await Effect.runPromise(
515
- this.encodeUnknownEffect(input, this.options?.parseOptions).pipe(
516
- Effect.mapErrorEager(SchemaIssue.defaultFormatter),
517
- Effect.result
518
- )
736
+ return Effect.runPromise(this.succeedEffect(input, arguments.length === 1 ? input : expected))
737
+ }
738
+ /**
739
+ * Returns a lazy assertion that encoding succeeds with the input or the
740
+ * explicit expected value.
741
+ *
742
+ * **When to use**
743
+ *
744
+ * Use to assert encoding in an Effect test while preserving required encoding services.
745
+ *
746
+ * **Details**
747
+ *
748
+ * Assertion mismatches are defects. The encoder uses the calling fiber's services.
749
+ *
750
+ * @see {@link succeed} for the Promise variant
751
+ * @see {@link failEffect} for asserting encoding failures
752
+ * @stability unstable
753
+ */
754
+ succeedEffect(input: unknown): Effect.Effect<void, never, S["EncodingServices"]>
755
+ succeedEffect(input: unknown, expected: S["Encoded"]): Effect.Effect<void, never, S["EncodingServices"]>
756
+ succeedEffect(input: unknown, expected?: S["Encoded"]): Effect.Effect<void, never, S["EncodingServices"]> {
757
+ return assertResult(
758
+ () => this.encodeUnknownEffect(input, this.options?.parseOptions),
759
+ Result.succeed(arguments.length === 1 ? input : expected)
519
760
  )
520
- expected = arguments.length === 1 ? input : expected
521
- assert.deepStrictEqual(r, Result.succeed(expected))
522
761
  }
523
762
  /**
524
763
  * Asserts that encoding `input` fails and the stringified issue equals
@@ -538,20 +777,32 @@ export class Encoding<S extends Schema.Constraint> {
538
777
  * await encoding.fail("not-a-number", "Expected number") // => undefined
539
778
  * ```
540
779
  *
780
+ * @see {@link failEffect} for the Effect variant
541
781
  * @see {@link succeed} for asserting successful encoding
782
+ * @stability unstable
542
783
  */
543
784
  async fail<S extends Schema.ConstraintEncoder<unknown, never>>(
544
785
  this: Encoding<S>,
545
786
  input: unknown,
546
787
  message: string
547
788
  ) {
548
- const r = await Effect.runPromise(
549
- this.encodeUnknownEffect(input, this.options?.parseOptions).pipe(
550
- Effect.mapErrorEager(SchemaIssue.defaultFormatter),
551
- Effect.result
552
- )
553
- )
554
- assert.deepStrictEqual(r, Result.fail(message))
789
+ return Effect.runPromise(this.failEffect(input, message))
790
+ }
791
+ /**
792
+ * Returns a lazy assertion that encoding fails with the expected issue message.
793
+ *
794
+ * **Details**
795
+ *
796
+ * Assertion mismatches are defects. Schema defects and interruption propagate
797
+ * without satisfying the assertion. Required encoding services come from the
798
+ * calling fiber.
799
+ *
800
+ * @see {@link fail} for the Promise variant
801
+ * @see {@link succeedEffect} for asserting encoding success
802
+ * @stability unstable
803
+ */
804
+ failEffect(input: unknown, message: string): Effect.Effect<void, never, S["EncodingServices"]> {
805
+ return assertResult(() => this.encodeUnknownEffect(input, this.options?.parseOptions), Result.fail(message))
555
806
  }
556
807
  /**
557
808
  * Returns a new {@link Encoding} instance with the given service injected into the encoding effect context.
@@ -561,6 +812,7 @@ export class Encoding<S extends Schema.Constraint> {
561
812
  * Use when the schema's encoder requires a service dependency.
562
813
  *
563
814
  * @see {@link Decoding.provide}
815
+ * @stability unstable
564
816
  */
565
817
  provide<Id, Service>(
566
818
  service: Context.Key<Id, Service>,
@@ -15,6 +15,7 @@ export * as TestClock from "./TestClock.ts"
15
15
  export * as TestConsole from "./TestConsole.ts"
16
16
 
17
17
  /**
18
+ * @stability unstable
18
19
  * @since 4.0.0
19
20
  */
20
21
  export * as TestSchema from "./TestSchema.ts"
@@ -253,7 +253,7 @@ export const into: {
253
253
  Effect.provideService(effect, InstanceTag, instance),
254
254
  Effect.fnUntraced(function*(exit) {
255
255
  if (Exit.isFailure(exit)) {
256
- const [reasons, interrupts] = Arr.partition(
256
+ const [interrupts, reasons] = Arr.partition(
257
257
  exit.cause.reasons,
258
258
  Filter.fromPredicate(Cause.isInterruptReason)
259
259
  )
@@ -711,7 +711,7 @@ export const intoResult = <A, E, R>(
711
711
  Effect.matchCauseEffect({
712
712
  onSuccess: (value) => Effect.succeed(new Complete({ exit: Exit.succeed(value) })),
713
713
  onFailure: (cause): Effect.Effect<Result<A, E>> => {
714
- const [reasons, interrupts] = Arr.partition(
714
+ const [interrupts, reasons] = Arr.partition(
715
715
  cause.reasons,
716
716
  Filter.fromPredicate(Cause.isInterruptReason)
717
717
  )