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
@@ -1156,7 +1156,7 @@ const callbackOptions: <A, E = never, R = never>(
1156
1156
  this: Scheduler.Scheduler,
1157
1157
  resume: (effect: Effect.Effect<A, E, R>) => void,
1158
1158
  signal?: AbortSignal
1159
- ) => void | Effect.Effect<void, never, R>,
1159
+ ) => void | Effect.Effect<void, E, R>,
1160
1160
  withSignal: boolean
1161
1161
  ) => Effect.Effect<A, E, R> = (function() {
1162
1162
  const Proto = makePrimitiveProto({
@@ -1214,7 +1214,7 @@ const asyncFinalizer: (
1214
1214
  },
1215
1215
  [contE](cause, _fiber) {
1216
1216
  return hasInterrupts(cause)
1217
- ? flatMap(this[args](), () => failCause(cause))
1217
+ ? flatMap(combineFinalizerCause(exitFailCause(cause), this[args]()), () => failCause(cause))
1218
1218
  : failCause(cause)
1219
1219
  }
1220
1220
  })
@@ -1225,7 +1225,7 @@ export const callback = <A, E = never, R = never>(
1225
1225
  this: Scheduler.Scheduler,
1226
1226
  resume: (effect: Effect.Effect<A, E, R>) => void,
1227
1227
  signal: AbortSignal
1228
- ) => void | Effect.Effect<void, never, R>
1228
+ ) => void | Effect.Effect<void, E, R>
1229
1229
  ): Effect.Effect<A, E, R> => callbackOptions(register as any, register.length >= 2)
1230
1230
 
1231
1231
  /** @internal */
@@ -1632,13 +1632,15 @@ export const raceAll = <Eff extends Effect.Effect<any, any, any>>(
1632
1632
  Effect.Error<Eff>,
1633
1633
  Effect.Services<Eff>
1634
1634
  > =>
1635
- withFiber((parent) =>
1636
- callback((resume) => {
1635
+ withFiber((parent) => {
1636
+ const fibers = new Set<Fiber.Fiber<any, any>>()
1637
+ // Read fibers on exit to include losers forked after the race settles.
1638
+ onExitUnsafe(parent, () => fibers.size === 0 ? undefined : fiberInterruptAll(fibers))
1639
+ return callback((resume) => {
1637
1640
  const effects = Arr.fromIterable(all)
1638
1641
  const len = effects.length
1639
1642
  let doneCount = 0
1640
1643
  let done = false
1641
- const fibers = new Set<Fiber.Fiber<any, any>>()
1642
1644
  const failures: Array<Cause.Reason<any>> = []
1643
1645
  const onExit = (exit: Exit.Exit<any, any>, fiber: Fiber.Fiber<any, any>, i: number) => {
1644
1646
  doneCount++
@@ -1651,11 +1653,7 @@ export const raceAll = <Eff extends Effect.Effect<any, any, any>>(
1651
1653
  }
1652
1654
  const isWinner = !done
1653
1655
  done = true
1654
- resume(
1655
- fibers.size === 0
1656
- ? exit
1657
- : flatMap(uninterruptible(fiberInterruptAll(fibers)), () => exit)
1658
- )
1656
+ resume(exit)
1659
1657
  if (isWinner && options?.onWinner) {
1660
1658
  options.onWinner({ fiber, index: i, parentFiber: parent })
1661
1659
  }
@@ -1670,10 +1668,8 @@ export const raceAll = <Eff extends Effect.Effect<any, any, any>>(
1670
1668
  })
1671
1669
  if (done) break
1672
1670
  }
1673
-
1674
- return fiberInterruptAll(fibers)
1675
1671
  })
1676
- )
1672
+ })
1677
1673
 
1678
1674
  /** @internal */
1679
1675
  export const raceAllFirst = <Eff extends Effect.Effect<any, any, any>>(
@@ -1690,19 +1686,11 @@ export const raceAllFirst = <Eff extends Effect.Effect<any, any, any>>(
1690
1686
  Effect.Error<Eff>,
1691
1687
  Effect.Services<Eff>
1692
1688
  > =>
1693
- withFiber((parent) =>
1694
- callback((resume) => {
1689
+ withFiber((parent) => {
1690
+ const fibers = new Set<Fiber.Fiber<any, any>>()
1691
+ onExitUnsafe(parent, () => fibers.size === 0 ? undefined : fiberInterruptAll(fibers))
1692
+ return callback((resume) => {
1695
1693
  let done = false
1696
- const fibers = new Set<Fiber.Fiber<any, any>>()
1697
- const onExit = (exit: Exit.Exit<any, any>) => {
1698
- done = true
1699
- resume(
1700
- fibers.size === 0
1701
- ? exit
1702
- : flatMap(uninterruptible(fiberInterruptAll(fibers)), () => exit)
1703
- )
1704
- }
1705
-
1706
1694
  let i = 0
1707
1695
  for (const effect of all) {
1708
1696
  if (done) break
@@ -1712,16 +1700,15 @@ export const raceAllFirst = <Eff extends Effect.Effect<any, any, any>>(
1712
1700
  fiber.addObserver((exit) => {
1713
1701
  fibers.delete(fiber)
1714
1702
  const isWinner = !done
1715
- onExit(exit)
1703
+ done = true
1704
+ resume(exit)
1716
1705
  if (isWinner && options?.onWinner) {
1717
1706
  options.onWinner({ fiber, index, parentFiber: parent })
1718
1707
  }
1719
1708
  })
1720
1709
  }
1721
-
1722
- return fiberInterruptAll(fibers)
1723
1710
  })
1724
- )
1711
+ })
1725
1712
 
1726
1713
  /** @internal */
1727
1714
  export const race: {
@@ -4719,19 +4706,19 @@ export const partition: {
4719
4706
  <A, B, E, R>(
4720
4707
  f: (a: A, i: number) => Effect.Effect<B, E, R>,
4721
4708
  options?: { readonly concurrency?: Concurrency | undefined }
4722
- ): (elements: Iterable<A>) => Effect.Effect<[excluded: Array<E>, satisfying: Array<B>], never, R>
4709
+ ): (elements: Iterable<A>) => Effect.Effect<[passes: Array<B>, fails: Array<E>], never, R>
4723
4710
  <A, B, E, R>(
4724
4711
  elements: Iterable<A>,
4725
4712
  f: (a: A, i: number) => Effect.Effect<B, E, R>,
4726
4713
  options?: { readonly concurrency?: Concurrency | undefined }
4727
- ): Effect.Effect<[excluded: Array<E>, satisfying: Array<B>], never, R>
4714
+ ): Effect.Effect<[passes: Array<B>, fails: Array<E>], never, R>
4728
4715
  } = dual(
4729
4716
  (args) => isIterable(args[0]) && !isEffect(args[0]),
4730
4717
  <A, B, E, R>(
4731
4718
  elements: Iterable<A>,
4732
4719
  f: (a: A, i: number) => Effect.Effect<B, E, R>,
4733
4720
  options?: { readonly concurrency?: Concurrency | undefined }
4734
- ): Effect.Effect<[excluded: Array<E>, satisfying: Array<B>], never, R> =>
4721
+ ): Effect.Effect<[passes: Array<B>, fails: Array<E>], never, R> =>
4735
4722
  map(
4736
4723
  forEach(elements, (a, i) => result(f(a, i)), options),
4737
4724
  (results) => Arr.partition(results, identity)
@@ -4820,11 +4807,11 @@ export const validate: {
4820
4807
  ): Effect.Effect<Array<B> | void, Arr.NonEmptyArray<E>, R> =>
4821
4808
  flatMap(
4822
4809
  partition(elements, f, { concurrency: options?.concurrency }),
4823
- ([excluded, satisfying]) => {
4824
- if (Arr.isArrayNonEmpty(excluded)) {
4825
- return fail(excluded)
4810
+ ([passes, fails]) => {
4811
+ if (Arr.isArrayNonEmpty(fails)) {
4812
+ return fail(fails)
4826
4813
  }
4827
- return options?.discard ? void_ : succeed(satisfying)
4814
+ return options?.discard ? void_ : succeed(passes)
4828
4815
  }
4829
4816
  )
4830
4817
  )
@@ -5085,7 +5072,6 @@ const iterateConcurrentImpl = <S, A, X, E, R, E2>(options: IterateOptions<S, A,
5085
5072
  let parentFiber: Fiber.Fiber<any, any> | undefined
5086
5073
  let fibers: Set<Fiber.Fiber<any, any>> | undefined
5087
5074
  let resume: ((effect: Effect.Effect<void, E | E2, R>) => void) | undefined
5088
- let interrupted = false
5089
5075
  let terminal: Exit.Exit<void, E | E2> | void
5090
5076
  let effect: Effect.Effect<X, E, R> | undefined
5091
5077
 
@@ -5093,9 +5079,8 @@ const iterateConcurrentImpl = <S, A, X, E, R, E2>(options: IterateOptions<S, A,
5093
5079
  const defect = exitDie(error)
5094
5080
  terminal = defect
5095
5081
  done = true
5096
- interrupted = true
5097
5082
  return fibers && fibers.size > 0
5098
- ? flatMap(uninterruptible(fiberInterruptAll(Array.from(fibers))), () => defect)
5083
+ ? flatMap(uninterruptible(fiberInterruptAll(Array.from(fibers))), () => terminal ?? defect)
5099
5084
  : defect
5100
5085
  }
5101
5086
 
@@ -5105,12 +5090,9 @@ const iterateConcurrentImpl = <S, A, X, E, R, E2>(options: IterateOptions<S, A,
5105
5090
  const item = items[index]
5106
5091
  const eff = effect ?? onItem(state, item, index)
5107
5092
 
5108
- // fast case (already an exit)
5109
5093
  if (effectIsExit(eff)) {
5110
5094
  terminal = step(state, item, eff, index)
5111
5095
  if (terminal) break
5112
-
5113
- // We have an effect, so enter "async" mode
5114
5096
  } else if (!parentFiber) {
5115
5097
  return callback((cb) => {
5116
5098
  parentFiber = getCurrentFiber()!
@@ -5125,15 +5107,15 @@ const iterateConcurrentImpl = <S, A, X, E, R, E2>(options: IterateOptions<S, A,
5125
5107
  }
5126
5108
  if (result) return cb(result)
5127
5109
  return suspend(() => {
5128
- terminal = exitVoid
5129
- interrupted = true
5130
- return fibers ? fiberInterruptAll(fibers) : void_
5110
+ terminal ??= exitVoid
5111
+ return flatMap(
5112
+ fibers ? fiberInterruptAll(fibers) : void_,
5113
+ () => terminal?._tag === "Failure" ? terminal : void_
5114
+ )
5131
5115
  })
5132
5116
  })
5133
-
5134
- // Fork the effect with concurrency > 1
5135
5117
  } else {
5136
- // Clear the temporary effect from capturing the parentFiber
5118
+ // Clear the effect cached before the parent fiber was available.
5137
5119
  effect = undefined
5138
5120
 
5139
5121
  const fiber = forkUnsafe(parentFiber, eff, true, true, "inherit")
@@ -5143,7 +5125,6 @@ const iterateConcurrentImpl = <S, A, X, E, R, E2>(options: IterateOptions<S, A,
5143
5125
  continue
5144
5126
  }
5145
5127
 
5146
- // Add the fiber to the Set
5147
5128
  fibers!.add(fiber)
5148
5129
 
5149
5130
  const currentIndex = index
@@ -5151,22 +5132,17 @@ const iterateConcurrentImpl = <S, A, X, E, R, E2>(options: IterateOptions<S, A,
5151
5132
  fibers!.delete(fiber)
5152
5133
  try {
5153
5134
  if (terminal) {
5154
- if (!interrupted && exit._tag === "Failure") {
5155
- for (const reason of exit.cause.reasons) {
5156
- if (reason._tag === "Interrupt") continue
5157
- else if (terminal._tag === "Failure") {
5158
- ;(terminal.cause.reasons as Array<any>).push(reason)
5159
- } else {
5160
- terminal = exitFailCause(causeFromReasons([reason]))
5161
- }
5135
+ if (exit._tag === "Failure") {
5136
+ const reasons = exit.cause.reasons.filter((reason) => reason._tag !== "Interrupt")
5137
+ if (reasons.length > 0) {
5138
+ const cause = causeFromReasons(reasons)
5139
+ terminal = exitFailCause(terminal._tag === "Failure" ? causeCombine(terminal.cause, cause) : cause)
5162
5140
  }
5163
5141
  }
5164
5142
  } else {
5165
5143
  const result = step(state, item, exit, currentIndex)
5166
5144
  if (result) {
5167
- terminal = result._tag === "Failure"
5168
- ? exitFailCause(causeFromReasons(result.cause.reasons.slice()))
5169
- : result
5145
+ terminal = result
5170
5146
  go()
5171
5147
  }
5172
5148
  }
@@ -5182,7 +5158,6 @@ const iterateConcurrentImpl = <S, A, X, E, R, E2>(options: IterateOptions<S, A,
5182
5158
  }
5183
5159
  })
5184
5160
 
5185
- // Check if we have reached the concurrency limit
5186
5161
  if (fibers!.size < concurrency) continue
5187
5162
  paused = true
5188
5163
  index++
@@ -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 = { supported: false, outputFree: false, makeSafe: false, nodes: 1, height: 0 }
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 = { supported: true, outputFree: true, makeSafe: true, nodes: 1, height: 0 }
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 entries = ast.types.map((type, index) =>
301
- `[${constant(emitter, type, `${path}.types[${index}]`)},${
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}=new Map([${entries.join(",")}])`)
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}=U(${input},${types})`,
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}.get(${candidates}[${index}]);${candidate}=${decoder}(${input},o);if(${candidate}!==${invalid}){${output}=${candidate};break}}`
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}.get(${candidates}[${index}]);${candidate}=${decoder}(${input},o);if(${candidate}!==${invalid}){if(++${successes}>1)return ${invalid};${output}=${candidate}}}`
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: "getCandidates",
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
- return `R.matchesTemplateLiteral(${path},${input},o)`
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
- return `const transform=ast.encoding[0].transformation.decode.transform;return function(i,o){try{
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
- inlineIdentityPredicate(ast, "v", "ast") !== undefined &&
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
- inlineIdentityPredicate(link.to, "v", "ast") !== undefined &&
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 = inlineIdentityPredicate(links[links.length - 1].to, `v${index}`, sourcePath)!
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
- let transform = transforms.get(transformation.decode.transform)
857
- if (transform === undefined) {
858
- transform = `t${transforms.size}`
859
- transforms.set(transformation.decode.transform, transform)
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 = inlineIdentityPredicate(property.type, `x${index}`, propertyPath)!
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})){const x${index}=${decoded};` +
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
- let transform = transforms.get(transformation.decode.transform)
879
- if (transform === undefined) {
880
- transform = `t${transforms.size}`
881
- transforms.set(transformation.decode.transform, transform)
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 = inlineIdentityPredicate(target, `x${index}`, targetPath)!
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)}}}`
@@ -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
- const nodeBrands = InternalAnnotations.collectBrands(representation.annotations)
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
- const brands = checkBrands(check)
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
- const Type = includeTypeBrands
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, includeTypeBrands), representation, path, includeTypeBrands)
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], false))
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)}`