effect 3.12.4 → 3.12.5

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 (43) hide show
  1. package/dist/cjs/Arbitrary.js +72 -14
  2. package/dist/cjs/Arbitrary.js.map +1 -1
  3. package/dist/cjs/Inspectable.js +0 -4
  4. package/dist/cjs/Inspectable.js.map +1 -1
  5. package/dist/cjs/ParseResult.js +2 -2
  6. package/dist/cjs/ParseResult.js.map +1 -1
  7. package/dist/cjs/Schema.js +154 -93
  8. package/dist/cjs/Schema.js.map +1 -1
  9. package/dist/cjs/internal/dateTime.js +12 -3
  10. package/dist/cjs/internal/dateTime.js.map +1 -1
  11. package/dist/cjs/internal/effect/circular.js +15 -2
  12. package/dist/cjs/internal/effect/circular.js.map +1 -1
  13. package/dist/cjs/internal/fiberRuntime.js.map +1 -1
  14. package/dist/cjs/internal/version.js +1 -1
  15. package/dist/dts/Arbitrary.d.ts.map +1 -1
  16. package/dist/dts/Inspectable.d.ts.map +1 -1
  17. package/dist/dts/ParseResult.d.ts +11 -0
  18. package/dist/dts/ParseResult.d.ts.map +1 -1
  19. package/dist/dts/Schema.d.ts +34 -15
  20. package/dist/dts/Schema.d.ts.map +1 -1
  21. package/dist/esm/Arbitrary.js +72 -14
  22. package/dist/esm/Arbitrary.js.map +1 -1
  23. package/dist/esm/Inspectable.js +0 -3
  24. package/dist/esm/Inspectable.js.map +1 -1
  25. package/dist/esm/ParseResult.js +2 -2
  26. package/dist/esm/ParseResult.js.map +1 -1
  27. package/dist/esm/Schema.js +149 -86
  28. package/dist/esm/Schema.js.map +1 -1
  29. package/dist/esm/internal/dateTime.js +11 -2
  30. package/dist/esm/internal/dateTime.js.map +1 -1
  31. package/dist/esm/internal/effect/circular.js +15 -2
  32. package/dist/esm/internal/effect/circular.js.map +1 -1
  33. package/dist/esm/internal/fiberRuntime.js.map +1 -1
  34. package/dist/esm/internal/version.js +1 -1
  35. package/package.json +1 -1
  36. package/src/Arbitrary.ts +84 -14
  37. package/src/Inspectable.ts +0 -1
  38. package/src/ParseResult.ts +15 -2
  39. package/src/Schema.ts +191 -93
  40. package/src/internal/dateTime.ts +12 -2
  41. package/src/internal/effect/circular.ts +19 -17
  42. package/src/internal/fiberRuntime.ts +2 -1
  43. package/src/internal/version.ts +1 -1
package/src/Arbitrary.ts CHANGED
@@ -4,6 +4,7 @@
4
4
 
5
5
  import * as Arr from "./Array.js"
6
6
  import * as FastCheck from "./FastCheck.js"
7
+ import { globalValue } from "./GlobalValue.js"
7
8
  import * as errors_ from "./internal/schema/errors.js"
8
9
  import * as schemaId_ from "./internal/schema/schemaId.js"
9
10
  import * as util_ from "./internal/schema/util.js"
@@ -276,6 +277,11 @@ const makeArrayConfig = (options: {
276
277
 
277
278
  type Config = StringConstraints | NumberConstraints | BigIntConstraints | DateConstraints | ArrayConfig
278
279
 
280
+ const arbitraryMemoMap = globalValue(
281
+ Symbol.for("effect/Arbitrary/arbitraryMemoMap"),
282
+ () => new WeakMap<AST.AST, LazyArbitrary<any>>()
283
+ )
284
+
279
285
  const go = (
280
286
  ast: AST.AST,
281
287
  ctx: ArbitraryGenerationContext,
@@ -311,6 +317,7 @@ const go = (
311
317
  const constStringConstraints = makeStringConstraints({})
312
318
  const constNumberConstraints = makeNumberConstraints({})
313
319
  const constBigIntConstraints = makeBigIntConstraints({})
320
+ const defaultSuspendedArrayConstraints: FastCheck.ArrayConstraints = { maxLength: 2 }
314
321
 
315
322
  /** @internal */
316
323
  export const toOp = (
@@ -439,8 +446,22 @@ export const toOp = (
439
446
  const value = indexSignatures[i][1](fc)
440
447
  output = output.chain((o) => {
441
448
  const item = fc.tuple(key, value)
449
+ /*
450
+
451
+ `getSuspendedArray` is used to generate less key/value pairs in
452
+ the context of a recursive schema. Without it, the following schema
453
+ would generate an big amount of values possibly leading to a stack
454
+ overflow:
455
+
456
+ ```ts
457
+ type A = { [_: string]: A }
458
+
459
+ const schema = S.Record({ key: S.String, value: S.suspend((): S.Schema<A> => schema) })
460
+ ```
461
+
462
+ */
442
463
  const arr = ctx.depthIdentifier !== undefined ?
443
- getSuspendedArray(fc, ctx.depthIdentifier, ctx.maxDepth, item) :
464
+ getSuspendedArray(fc, ctx.depthIdentifier, ctx.maxDepth, item, defaultSuspendedArrayConstraints) :
444
465
  fc.array(item)
445
466
  return arr.map((tuples) => ({ ...Object.fromEntries(tuples), ...o }))
446
467
  })
@@ -454,16 +475,39 @@ export const toOp = (
454
475
  return new Succeed((fc) => fc.oneof(...types.map((arb) => arb(fc))))
455
476
  }
456
477
  case "Suspend": {
478
+ const memo = arbitraryMemoMap.get(ast)
479
+ if (memo) {
480
+ return new Succeed(memo)
481
+ }
457
482
  const get = util_.memoizeThunk(() => {
458
483
  return go(ast.f(), getSuspendedContext(ctx, ast), path)
459
484
  })
460
- return new Succeed((fc) => fc.constant(null).chain(() => get()(fc)))
485
+ const out: LazyArbitrary<any> = (fc) => fc.constant(null).chain(() => get()(fc))
486
+ arbitraryMemoMap.set(ast, out)
487
+ return new Succeed(out)
461
488
  }
462
489
  case "Transformation":
463
490
  return toOp(ast.to, ctx, path)
464
491
  }
465
492
  }
466
493
 
494
+ function subtractElementsLength(
495
+ constraints: FastCheck.ArrayConstraints,
496
+ elementsLength: number
497
+ ): FastCheck.ArrayConstraints {
498
+ if (elementsLength === 0 || (constraints.minLength === undefined && constraints.maxLength === undefined)) {
499
+ return constraints
500
+ }
501
+ const out = { ...constraints }
502
+ if (out.minLength !== undefined) {
503
+ out.minLength = Math.max(out.minLength - elementsLength, 0)
504
+ }
505
+ if (out.maxLength !== undefined) {
506
+ out.maxLength = Math.max(out.maxLength - elementsLength, 0)
507
+ }
508
+ return out
509
+ }
510
+
467
511
  const goTupleType = (
468
512
  ast: AST.TupleType,
469
513
  ctx: ArbitraryGenerationContext,
@@ -508,9 +552,36 @@ const goTupleType = (
508
552
  const [head, ...tail] = rest
509
553
  const item = head(fc)
510
554
  output = output.chain((as) => {
511
- return (ctx.depthIdentifier !== undefined
512
- ? getSuspendedArray(fc, ctx.depthIdentifier, ctx.maxDepth, item, constraints)
513
- : fc.array(item, constraints)).map((rest) => [...as, ...rest])
555
+ const len = as.length
556
+ // We must adjust the constraints for the rest element
557
+ // because the elements might have generated some values
558
+ const restArrayConstraints = subtractElementsLength(constraints, len)
559
+ if (restArrayConstraints.maxLength === 0) {
560
+ return fc.constant(as)
561
+ }
562
+ /*
563
+
564
+ `getSuspendedArray` is used to generate less values in
565
+ the context of a recursive schema. Without it, the following schema
566
+ would generate an big amount of values possibly leading to a stack
567
+ overflow:
568
+
569
+ ```ts
570
+ type A = ReadonlyArray<A | null>
571
+
572
+ const schema = S.Array(
573
+ S.NullOr(S.suspend((): S.Schema<A> => schema))
574
+ )
575
+ ```
576
+
577
+ */
578
+ const arr = ctx.depthIdentifier !== undefined
579
+ ? getSuspendedArray(fc, ctx.depthIdentifier, ctx.maxDepth, item, restArrayConstraints)
580
+ : fc.array(item, restArrayConstraints)
581
+ if (len === 0) {
582
+ return arr
583
+ }
584
+ return arr.map((rest) => [...as, ...rest])
514
585
  })
515
586
  // ---------------------------------------------
516
587
  // handle post rest elements
@@ -660,20 +731,19 @@ const getSuspendedArray = (
660
731
  depthIdentifier: string,
661
732
  maxDepth: number,
662
733
  item: FastCheck.Arbitrary<any>,
663
- constraints?: FastCheck.ArrayConstraints
734
+ constraints: FastCheck.ArrayConstraints
664
735
  ) => {
665
- let minLength = 1
666
- let maxLength = 2
667
- if (constraints && constraints.minLength !== undefined && constraints.minLength > minLength) {
668
- minLength = constraints.minLength
669
- if (minLength > maxLength) {
670
- maxLength = minLength
671
- }
736
+ // In the context of a recursive schema, we don't want a `maxLength` greater than 2.
737
+ // The only exception is when `minLength` is also set, in which case we set
738
+ // `maxLength` to the minimum value, which is `minLength`.
739
+ const maxLengthLimit = Math.max(2, constraints.minLength ?? 0)
740
+ if (constraints.maxLength !== undefined && constraints.maxLength > maxLengthLimit) {
741
+ constraints = { ...constraints, maxLength: maxLengthLimit }
672
742
  }
673
743
  return fc.oneof(
674
744
  { maxDepth, depthIdentifier },
675
745
  fc.constant([]),
676
- fc.array(item, { minLength, maxLength })
746
+ fc.array(item, constraints)
677
747
  )
678
748
  }
679
749
 
@@ -1,7 +1,6 @@
1
1
  /**
2
2
  * @since 2.0.0
3
3
  */
4
-
5
4
  import type * as FiberRefs from "./FiberRefs.js"
6
5
  import { globalValue } from "./GlobalValue.js"
7
6
  import { hasProperty, isFunction } from "./Predicate.js"
@@ -809,11 +809,11 @@ interface Parser {
809
809
  }
810
810
 
811
811
  const decodeMemoMap = globalValue(
812
- Symbol.for("effect/Schema/Parser/decodeMemoMap"),
812
+ Symbol.for("effect/ParseResult/decodeMemoMap"),
813
813
  () => new WeakMap<AST.AST, Parser>()
814
814
  )
815
815
  const encodeMemoMap = globalValue(
816
- Symbol.for("effect/Schema/Parser/encodeMemoMap"),
816
+ Symbol.for("effect/ParseResult/encodeMemoMap"),
817
817
  () => new WeakMap<AST.AST, Parser>()
818
818
  )
819
819
 
@@ -1983,12 +1983,25 @@ const formatTree = (
1983
1983
  }
1984
1984
 
1985
1985
  /**
1986
+ * Represents an issue returned by the {@link ArrayFormatter} formatter.
1987
+ *
1986
1988
  * @category model
1987
1989
  * @since 3.10.0
1988
1990
  */
1989
1991
  export interface ArrayFormatterIssue {
1992
+ /**
1993
+ * The tag identifying the type of parse issue.
1994
+ */
1990
1995
  readonly _tag: ParseIssue["_tag"]
1996
+
1997
+ /**
1998
+ * The path to the property where the issue occurred.
1999
+ */
1991
2000
  readonly path: ReadonlyArray<PropertyKey>
2001
+
2002
+ /**
2003
+ * A descriptive message explaining the issue.
2004
+ */
1992
2005
  readonly message: string
1993
2006
  }
1994
2007