1/**
2 * Describes data shapes and how unknown input becomes trusted values.
3 *
4 * A schema can validate input, decode it into an application type, and encode
5 * that value back to another representation. This module contains the main
6 * schema, codec, decoder, and encoder APIs, together with schemas for common
7 * JavaScript values and Effect data types. It also supports refinements,
8 * transformations, defaults, classes, JSON Schema generation, test data
9 * generation, formatting, equivalence, optics, and differs derived from schema
10 * definitions.
11 *
12 * @since 4.0.0
13 */
14
15import * as Arr from "./Array.ts"
16import * as BigDecimal_ from "./BigDecimal.ts"
17import type * as Brand from "./Brand.ts"
18import * as ByteSize_ from "./ByteSize.ts"
19import * as Cause_ from "./Cause.ts"
20import * as Chunk_ from "./Chunk.ts"
21import * as Data from "./Data.ts"
22import * as DateTime from "./DateTime.ts"
23import type { Differ } from "./Differ.ts"
24import * as Duration_ from "./Duration.ts"
25import * as Effect from "./Effect.ts"
26import * as Base64 from "./encoding/Base64.ts"
27import * as Equal from "./Equal.ts"
28import type * as Equivalence from "./Equivalence.ts"
29import * as Exit_ from "./Exit.ts"
30import type { Formatter } from "./Formatter.ts"
31import { format, formatPropertyKey } from "./Formatter.ts"
32import { identity } from "./Function.ts"
33import type * as Graph_ from "./Graph.ts"
34import * as HashMap_ from "./HashMap.ts"
35import * as HashSet_ from "./HashSet.ts"
36import * as Cookies_ from "./http/Cookies.ts"
37import * as Headers_ from "./http/Headers.ts"
38import * as UrlParams_ from "./http/UrlParams.ts"
39import * as core from "./internal/core.ts"
40import { effectIsExit } from "./internal/effect.ts"
41import * as InternalGraph from "./internal/graph.ts"
42import * as InternalRecord from "./internal/record.ts"
43import * as InternalAnnotations from "./internal/schema/annotations.ts"
44import * as InternalMake from "./internal/schema/make.ts"
45import * as InternalStandardSchema from "./internal/schema/standardSchema.ts"
46import * as InternalToCodec from "./internal/schema/toCodec.ts"
47import * as InternalToDifferJsonPatch from "./internal/schema/toDifferJsonPatch.ts"
48import * as InternalToEncoderXml from "./internal/schema/toEncoderXml.ts"
49import * as InternalEquivalence from "./internal/schema/toEquivalence.ts"
50import * as InternalToFormatter from "./internal/schema/toFormatter.ts"
51import * as InternalToIso from "./internal/schema/toIso.ts"
52import * as InternalToJsonSchemaDocument from "./internal/schema/toJsonSchemaDocument.ts"
53import * as InternalToRepresentation from "./internal/schema/toRepresentation.ts"
54import { isSchemaError as isSchemaErrorInternal, SchemaErrorTypeId } from "./internal/schemaError.ts"
55import { getStackTraceLimit, setStackTraceLimit } from "./internal/stackTraceLimit.ts"
56import type * as JsonPatch from "./JsonPatch.ts"
57import type * as JsonSchema from "./JsonSchema.ts"
58import * as IpInterface_ from "./net/IpInterface.ts"
59import * as IpNetwork_ from "./net/IpNetwork.ts"
60import * as NetAddress_ from "./net/NetAddress.ts"
61import { remainder } from "./Number.ts"
62import type * as Optic_ from "./Optic.ts"
63import * as Option_ from "./Option.ts"
64import * as Order from "./Order.ts"
65import * as Pipeable from "./Pipeable.ts"
66import * as Predicate from "./Predicate.ts"
67import * as Record_ from "./Record.ts"
68import * as Redacted_ from "./Redacted.ts"
69import * as RegExp_ from "./RegExp.ts"
70import * as Result_ from "./Result.ts"
71import * as SchemaAST from "./SchemaAST.ts"
72import * as SchemaGetter from "./SchemaGetter.ts"
73import * as SchemaIssue from "./SchemaIssue.ts"
74import * as SchemaParser from "./SchemaParser.ts"
75import type * as SchemaRepresentation from "./SchemaRepresentation.ts"
76import * as SchemaTransformation from "./SchemaTransformation.ts"
77import type { StandardJSONSchemaV1, StandardSchemaV1 } from "./StandardSchema.ts"
78import type { Assign, Lambda, Mutable, Simplify } from "./Struct.ts"
79import * as Struct_ from "./Struct.ts"
80import type { IsUnion, RequiredKeys } from "./Types.ts"
81import type { Unify } from "./Unify.ts"
82
83const TypeId = InternalMake.TypeId
84/**
85 * Whether a schema field is required or optional within a struct.
86 *
87 * @see {@link optionalKey} — mark a struct field as optional
88 * @see {@link optional} — mark a struct field as optional with `| undefined`
89 *
90 * @category models
91 * @since 4.0.0
92 */
93export type Optionality = "required" | "optional"
94/**
95 * Whether a schema field is readonly or mutable within a struct.
96 *
97 * @see {@link mutableKey} — mark a struct field as mutable
98 *
99 * @category models
100 * @since 4.0.0
101 */
102export type Mutability = "readonly" | "mutable"
103/**
104 * Whether a schema field has a constructor default value.
105 *
106 * @see {@link withConstructorDefault} — add a default to a schema field
107 * @see {@link tag} — creates a literal field with a constructor default
108 *
109 * @category models
110 * @since 4.0.0
111 */
112export type ConstructorDefault = "no-default" | "with-default"
113/**
114 * Options for `makeEffect`, `make`, and Class constructors.
115 *
116 * **When to use**
117 *
118 * Use when passing `disableChecks: true` to skip validation when you trust the
119 * data. Pass `parseOptions` to control parsing behavior.
120 *
121 * @see {@link BottomWithoutNew.makeEffect}
122 * @see {@link BottomWithoutNew.make}
123 *
124 * @category options
125 * @since 3.13.4
126 */
127export interface MakeOptions {
128 /**
129 * The parse options to use for the schema.
130 */
131 readonly parseOptions?: SchemaAST.ParseOptions | undefined
132 /**
133 * Whether to disable validation for the schema.
134 */
135 readonly disableChecks?: boolean | undefined
136
137 /** @internal */
138 readonly "~payload"?: {
139 readonly token: unknown
140 readonly value: unknown
141 }
142}
143/**
144 * The fully-parameterized schema interface without a construct signature.
145 * Exposes all 14 type parameters controlling type inference, mutability,
146 * optionality, services, and transformation behavior.
147 *
148 * **When to use**
149 *
150 * Use as the base for schema interfaces that provide a specialized construct
151 * signature.
152 *
153 * @category models
154 * @since 4.0.0
155 */
156export interface BottomWithoutNew<
157 out T,
158 out E,
159 out RD,
160 out RE,
161 out Ast extends SchemaAST.AST,
162 out Rebuild extends Top,
163 out TypeMakeIn = T,
164 out Iso = T,
165 in out TypeParameters extends ReadonlyArray<Constraint> = readonly [],
166 out TypeMake = TypeMakeIn,
167 out TypeMutability extends Mutability = "readonly",
168 out TypeOptionality extends Optionality = "required",
169 out TypeConstructorDefault extends ConstructorDefault = "no-default",
170 out EncodedMutability extends Mutability = "readonly",
171 out EncodedOptionality extends Optionality = "required"
172> extends Pipeable.Pipeable {
173 readonly [TypeId]: typeof TypeId
174 readonly "ast": Ast
175 readonly "Rebuild": Rebuild
176 readonly "~type.parameters": TypeParameters
177 readonly "Type": T
178 readonly "Encoded": E
179 readonly "DecodingServices": RD
180 readonly "EncodingServices": RE
181 readonly "~type.make.in": TypeMakeIn
182 readonly "~type.make": TypeMake
183 readonly "~type.constructor.default": TypeConstructorDefault
184 readonly "Iso": Iso
185 readonly "~type.mutability": TypeMutability
186 readonly "~type.optionality": TypeOptionality
187 readonly "~encoded.mutability": EncodedMutability
188 readonly "~encoded.optionality": EncodedOptionality
189 annotate(annotations: Annotations.Bottom<this["Type"], this["~type.parameters"]>): this["Rebuild"]
190 annotateKey(annotations: Annotations.Key<this["Type"]>): this["Rebuild"]
191 check(...checks: readonly [SchemaAST.Check<this["Type"]>, ...Array<SchemaAST.Check<this["Type"]>>]): this["Rebuild"]
192 rebuild(ast: this["ast"]): this["Rebuild"]
193 /**
194 * Constructs a value from the make input representation synchronously.
195 *
196 * **When to use**
197 *
198 * Use when constructor input is trusted or when validation failure
199 * should abort with a thrown `Error`.
200 *
201 * **Details**
202 *
203 * Applies constructor defaults and type-side validation according to
204 * `MakeOptions`.
205 *
206 * **Gotchas**
207 *
208 * Throws an `Error` with the schema issue in its `cause` when validation
209 * fails. Schema validation failures use the generic message
210 * `"Schema validation failed"`; format the `cause` explicitly with
211 * `SchemaIssue.makeFormatterDefault()` when human-readable details are needed.
212 * Causes that contain defects, interruptions, or other non-schema reasons
213 * throw with the underlying `Cause` attached instead.
214 *
215 * @see {@link BottomWithoutNew.makeOption} — construct synchronously and discard validation details
216 * @see {@link BottomWithoutNew.makeEffect} — construct through `Effect` when validation failure should stay in the error channel
217 */
218 make(input: this["~type.make.in"], options?: MakeOptions): this["Type"]
219 /**
220 * Constructs a value from the make input representation, returning `Option.none`
221 * when validation fails.
222 *
223 * **When to use**
224 *
225 * Use when you only need to know whether construction succeeds
226 * and do not need validation details.
227 *
228 * **Details**
229 *
230 * Applies constructor defaults and type-side validation according to
231 * `MakeOptions`.
232 *
233 * **Gotchas**
234 *
235 * Only causes made entirely of schema issues are converted to `None`. Causes
236 * that contain defects, interruptions, or other non-schema reasons throw
237 * instead.
238 *
239 * @see {@link BottomWithoutNew.make} — construct synchronously when validation failure should throw
240 * @see {@link BottomWithoutNew.makeEffect} — construct through `Effect` when validation details should stay in the error channel
241 */
242 makeOption(input: this["~type.make.in"], options?: MakeOptions): Option_.Option<this["Type"]>
243 /**
244 * Constructs a value from the make input representation, returning validation
245 * failures in the `Effect` error channel.
246 *
247 * **When to use**
248 *
249 * Use when construction must compose with other `Effect` operations or when
250 * the result supplies a nested constructor default. Otherwise, use
251 * {@link BottomWithoutNew.make} when invalid construction should throw.
252 *
253 * **Details**
254 *
255 * `SchemaParser` uses `SchemaIssue.Issue` as its canonical structured failure,
256 * and this method exposes the same representation directly. Keeping the issue
257 * unwrapped lets an enclosing schema attach its own path when the effect is
258 * used with {@link withConstructorDefault}. It also avoids allocating a
259 * `SchemaError` and keeps its formatting path out of the resulting bundle.
260 *
261 * **Gotchas**
262 *
263 * Unlike the decoding helpers in `Schema`, validation failures are not wrapped
264 * in `SchemaError`. Map the issue to `SchemaError` or to a domain-specific error
265 * when a wrapped error is needed at the application boundary.
266 *
267 * @see {@link BottomWithoutNew.make} — construct synchronously when validation failure should throw
268 * @see {@link BottomWithoutNew.makeOption} — construct synchronously and discard validation details
269 */
270 makeEffect(input: this["~type.make.in"], options?: MakeOptions): Effect.Effect<this["Type"], SchemaIssue.Issue>
271}
272/**
273 * Fully-parameterized base interface for schemas that can be extended directly
274 * by TypeScript classes.
275 *
276 * **When to use**
277 *
278 * Use as the base for concrete schema interfaces whose runtime values support
279 * `class ... extends schema`.
280 *
281 * **Details**
282 *
283 * Extends {@link BottomWithoutNew} with a construct signature that accepts `never`. The
284 * signature enables class extension without making ordinary schemas directly
285 * constructible.
286 *
287 * @see {@link BottomWithoutNew} for the schema protocol without a construct signature
288 *
289 * @category utility types
290 * @since 4.0.0
291 */
292export interface Bottom<
293 out T,
294 out E,
295 out RD,
296 out RE,
297 out Ast extends SchemaAST.AST,
298 out Rebuild extends Top,
299 out TypeMakeIn = T,
300 out Iso = T,
301 in out TypeParameters extends ReadonlyArray<Constraint> = readonly [],
302 out TypeMake = TypeMakeIn,
303 out TypeMutability extends Mutability = "readonly",
304 out TypeOptionality extends Optionality = "required",
305 out TypeConstructorDefault extends ConstructorDefault = "no-default",
306 out EncodedMutability extends Mutability = "readonly",
307 out EncodedOptionality extends Optionality = "required"
308> extends
309 BottomWithoutNew<
310 T,
311 E,
312 RD,
313 RE,
314 Ast,
315 Rebuild,
316 TypeMakeIn,
317 Iso,
318 TypeParameters,
319 TypeMake,
320 TypeMutability,
321 TypeOptionality,
322 TypeConstructorDefault,
323 EncodedMutability,
324 EncodedOptionality
325 >
326{
327 new(_: never): {}
328}
329/**
330 * Lazy `BottomWithoutNew` variant for schema implementations that
331 * compute their public views on demand.
332 *
333 * **When to use**
334 *
335 * Use as the base for lazy schema interfaces that provide a specialized
336 * construct signature.
337 *
338 * **Details**
339 *
340 * The laziness is purely type-level; runtime behavior is unchanged.
341 * `BottomLazyWithoutNew` keeps the structural operations inherited from
342 * `BottomWithoutNew`, but erases the expensive schema views to
343 * `unknown`. Concrete schema interfaces can then redeclare the precise views
344 * they expose. This keeps wide schemas such as `Struct` and `Union` cheaper when
345 * generic code reads a single view, while preserving their exact public types.
346 *
347 * @see {@link BottomWithoutNew} for the fully parameterized schema interface when every
348 * view must be supplied directly.
349 *
350 * @category utility types
351 * @since 4.0.0
352 */
353export interface BottomLazyWithoutNew<
354 out Ast extends SchemaAST.AST,
355 out Rebuild extends Top,
356 in out TypeParameters extends ReadonlyArray<Constraint> = readonly [],
357 out TypeMutability extends Mutability = "readonly",
358 out TypeOptionality extends Optionality = "required",
359 out TypeConstructorDefault extends ConstructorDefault = "no-default",
360 out EncodedMutability extends Mutability = "readonly",
361 out EncodedOptionality extends Optionality = "required"
362> extends
363 BottomWithoutNew<
364 unknown,
365 unknown,
366 unknown,
367 unknown,
368 Ast,
369 Rebuild,
370 unknown,
371 unknown,
372 TypeParameters,
373 unknown,
374 TypeMutability,
375 TypeOptionality,
376 TypeConstructorDefault,
377 EncodedMutability,
378 EncodedOptionality
379 >
380{}
381/**
382 * Lazy `Bottom` variant for schemas that can be extended directly by TypeScript
383 * classes.
384 *
385 * **When to use**
386 *
387 * Use as the base for concrete lazy schema interfaces whose runtime values
388 * support `class ... extends schema`.
389 *
390 * **Details**
391 *
392 * Extends {@link BottomLazyWithoutNew} with a construct signature that accepts `never`.
393 * The signature enables class extension without making ordinary schemas
394 * directly constructible.
395 *
396 * @see {@link BottomLazyWithoutNew} for the lazy schema protocol without a construct signature
397 *
398 * @category utility types
399 * @since 4.0.0
400 */
401export interface BottomLazy<
402 out Ast extends SchemaAST.AST,
403 out Rebuild extends Top,
404 in out TypeParameters extends ReadonlyArray<Constraint> = readonly [],
405 out TypeMutability extends Mutability = "readonly",
406 out TypeOptionality extends Optionality = "required",
407 out TypeConstructorDefault extends ConstructorDefault = "no-default",
408 out EncodedMutability extends Mutability = "readonly",
409 out EncodedOptionality extends Optionality = "required"
410> extends
411 BottomLazyWithoutNew<
412 Ast,
413 Rebuild,
414 TypeParameters,
415 TypeMutability,
416 TypeOptionality,
417 TypeConstructorDefault,
418 EncodedMutability,
419 EncodedOptionality
420 >
421{
422 new(_: never): {}
423}
424/**
425 * Type-level representation returned by {@link declareConstructor}.
426 *
427 * @category constructors
428 * @since 4.0.0
429 */
430export interface declareConstructor<T, E, TypeParameters extends ReadonlyArray<Constraint>, Iso = T> extends
431 Bottom<
432 T,
433 E,
434 TypeParameters[number]["DecodingServices"],
435 TypeParameters[number]["EncodingServices"],
436 SchemaAST.Declaration,
437 declareConstructor<T, E, TypeParameters, Iso>,
438 T,
439 Iso,
440 TypeParameters
441 >
442{}
443/**
444 * Creates a schema for a **parametric** type (a generic container such as
445 * `Array<A>`, `Option<A>`, etc.) by accepting a list of type-parameter schemas
446 * and a decoder factory.
447 *
448 * **When to use**
449 *
450 * Use when you are defining a schema for a generic container whose validation
451 * depends on one or more type-parameter schemas.
452 *
453 * **Details**
454 *
455 * The outer call `declareConstructor<T, E, Iso>()` fixes the decoded type `T`,
456 * the encoded type `E`, and the optional iso type. The inner call receives:
457 * - `typeParameters` — the concrete schemas for each type variable
458 * - `run` — a factory that, given resolved codecs for each type parameter,
459 * returns a parsing function `(u, ast, options) => Effect<T, Issue>`
460 * - `annotations` — optional metadata
461 *
462 * @see {@link declare} for creating schemas for non-parametric types.
463 *
464 * **Example** (Schema for a parametric `Box<A>` type)
465 *
466 * ```ts import.meta.vitest
467 * import { Effect, Schema, SchemaIssue, SchemaParser } from "effect"
468 *
469 * interface Box<A> {
470 * readonly value: A
471 * }
472 *
473 * const isBox = (u: unknown): u is Box<unknown> =>
474 * typeof u === "object" && u !== null && "value" in u
475 *
476 * const Box = <A extends Schema.Constraint>(item: A) =>
477 * Schema.declareConstructor<Box<A["Type"]>, Box<A["Encoded"]>>()(
478 * [item],
479 * ([itemCodec]) =>
480 * (u, ast, options) => {
481 * if (!isBox(u)) {
482 * return Effect.fail(new SchemaIssue.InvalidType(ast, u, options))
483 * }
484 * return Effect.map(
485 * SchemaParser.decodeUnknownEffect(itemCodec)(u.value, options),
486 * (value) => ({ value })
487 * )
488 * }
489 * )
490 *
491 * const schema = Box(Schema.Number)
492 * Effect.runSync(Schema.decodeUnknownEffect(schema)({ value: 1 })) // => { value: 1 }
493 * ```
494 *
495 * @category constructors
496 * @since 4.0.0
497 */
498export function declareConstructor<T, E = T, Iso = T>() {
499 return <const TypeParameters extends ReadonlyArray<Constraint>>(
500 typeParameters: TypeParameters,
501 run: (
502 typeParameters: {
503 readonly [K in keyof TypeParameters]: Codec<TypeParameters[K]["Type"], TypeParameters[K]["Encoded"]>
504 }
505 ) => (
506 u: unknown,
507 self: SchemaAST.Declaration,
508 options: SchemaAST.ParseOptions
509 ) => Effect.Effect<T, SchemaIssue.Issue>,
510 annotations?: Annotations.Declaration<T, TypeParameters>
511 ): declareConstructor<T, E, TypeParameters, Iso> => {
512 return make(
513 new SchemaAST.Declaration(
514 typeParameters.map(SchemaAST.getAST),
515 (typeParameters) => run(typeParameters.map((ast) => make(ast)) as any),
516 annotations
517 )
518 )
519 }
520}
521/**
522 * Type-level representation returned by {@link declare}.
523 *
524 * @category constructors
525 * @since 3.13.3
526 */
527export interface declare<T, Iso = T> extends declareConstructor<T, T, readonly [], Iso> {
528 readonly "Rebuild": declare<T, Iso>
529}
530/**
531 * Creates a schema for a **non-parametric** opaque type using a type-guard
532 * function. The schema accepts any unknown value and succeeds when `is` returns
533 * `true`, failing with an `InvalidType` issue otherwise.
534 *
535 * **When to use**
536 *
537 * Use when you are defining a schema for an opaque type with no type parameters
538 * and validation can be expressed as a type guard.
539 *
540 * **Example** (Defining a schema for a custom `UserId` branded type)
541 *
542 * ```ts import.meta.vitest
543 * import { Schema } from "effect"
544 *
545 * type UserId = string & { readonly _tag: "UserId" }
546 *
547 * const isUserId = (u: unknown): u is UserId =>
548 * typeof u === "string" && u.startsWith("user_")
549 *
550 * const UserId = Schema.declare<UserId>(isUserId, {
551 * title: "UserId",
552 * description: "A user identifier starting with 'user_'"
553 * })
554 * Schema.decodeUnknownSync(UserId)("user_123") // => "user_123"
555 * ```
556 *
557 * @see {@link declareConstructor} for creating schemas for parametric types.
558 *
559 * @category constructors
560 * @since 3.10.0
561 */
562export function declare<T, Iso = T>(
563 is: (u: unknown) => u is T,
564 annotations?: Annotations.Declaration<T> | undefined
565): declare<T, Iso> {
566 return declareConstructor<T, T, Iso>()(
567 [],
568 () => (input, ast, options) =>
569 is(input) ?
570 Effect.succeed(input) :
571 Effect.fail(new SchemaIssue.InvalidType(ast, input, options)),
572 annotations
573 )
574}
575/**
576 * Returns a schema widened to the fully-parameterized {@link Bottom} interface,
577 * making all 14 type parameters visible to TypeScript.
578 *
579 * **Details**
580 *
581 * Normally, concrete schema interfaces (e.g. `Schema<string>`) hide most type
582 * parameters. `revealBottom` is useful when writing generic utilities that need
583 * to inspect or propagate the complete set of type parameters.
584 *
585 * **Example** (Inspecting all type parameters of a schema)
586 *
587 * ```ts import.meta.vitest
588 * import { Schema } from "effect"
589 *
590 * const schema = Schema.String
591 *
592 * // Widen to Bottom to access all 14 type parameters
593 * const bottom = Schema.revealBottom(schema)
594 *
595 * // `bottom` now exposes Type, Encoded, DecodingServices, EncodingServices,
596 * // ast, Rebuild, ~type.make.in, Iso, ~type.parameters, etc.
597 * type T = typeof bottom["Type"] // string
598 * type E = typeof bottom["Encoded"] // string
599 * ```
600 *
601 * @category utility types
602 * @since 4.0.0
603 */
604export function revealBottom<S extends Top>(
605 bottom: S
606): Bottom<
607 S["Type"],
608 S["Encoded"],
609 S["DecodingServices"],
610 S["EncodingServices"],
611 S["ast"],
612 S["Rebuild"],
613 S["~type.make.in"],
614 S["Iso"],
615 S["~type.parameters"],
616 S["~type.make"],
617 S["~type.mutability"],
618 S["~type.optionality"],
619 S["~type.constructor.default"],
620 S["~encoded.mutability"],
621 S["~encoded.optionality"]
622> {
623 return bottom
624}
625/**
626 * Adds metadata annotations to a schema without changing its runtime behavior.
627 * This is the pipeable (curried) counterpart of the `.annotate` method.
628 *
629 * **Details**
630 *
631 * Annotations provide extra context used by documentation generators, JSON
632 * Schema converters, error formatters, and other tooling. Common keys include
633 * `title`, `description`, `examples`, `message`, and `identifier`.
634 *
635 * **Example** (Adding a title and description)
636 *
637 * ```ts import.meta.vitest
638 * import { Schema } from "effect"
639 *
640 * const Age = Schema.Natural.pipe(
641 * Schema.annotate({
642 * title: "Age",
643 * description: "A non-negative integer representing age in years"
644 * })
645 * )
646 * Schema.resolveAnnotations(Age)?.title // => "Age"
647 * ```
648 *
649 * @see {@link annotateEncoded} to annotate the encoded side instead.
650 *
651 * @category annotations
652 * @since 4.0.0
653 */
654export function annotate<S extends Top>(annotations: Annotations.Bottom<S["Type"], S["~type.parameters"]>) {
655 return (self: S) => self.annotate(annotations)
656}
657/**
658 * Adds metadata annotations to the **encoded** side of a schema without
659 * changing its runtime behavior. This is the encoded-side counterpart of
660 * `annotate`, which targets the decoded (Type) side.
661 *
662 * **Details**
663 *
664 * Internally the schema is flipped so that `Encoded` becomes `Type`,
665 * annotated, and then flipped back.
666 *
667 * **Example** (Adding a title to the encoded representation)
668 *
669 * ```ts import.meta.vitest
670 * import { Schema } from "effect"
671 *
672 * const schema = Schema.NumberFromString.pipe(
673 * Schema.annotateEncoded({
674 * title: "my title"
675 * })
676 * )
677 *
678 * Schema.toEncoded(schema).ast.annotations?.title // => "my title"
679 * ```
680 *
681 * @see {@link annotate} to annotate the type side instead.
682 *
683 * @category annotations
684 * @since 4.0.0
685 */
686export function annotateEncoded<S extends Top>(annotations: Annotations.Bottom<S["Encoded"], readonly []>) {
687 return (self: S): S["Rebuild"] => flip(flip(self).annotate(annotations))
688}
689/**
690 * Adds key-level annotations to a schema field. This is the pipeable
691 * (curried) counterpart of the `.annotateKey` method.
692 *
693 * **Details**
694 *
695 * Key annotations apply to a field's position inside a `Struct` or `Tuple`
696 * rather than to the field's value type. They can carry a
697 * `messageMissingKey` to customise the error shown when the field is absent,
698 * as well as standard documentation fields such as `title`, `description`,
699 * and `examples`.
700 *
701 * **Example** (Customizing the missing-key message for a required field)
702 *
703 * ```ts import.meta.vitest
704 * import { Schema } from "effect"
705 *
706 * const schema = Schema.Struct({
707 * username: Schema.String.pipe(
708 * Schema.annotateKey({
709 * description: "The username used to log in",
710 * messageMissingKey: "Username is required"
711 * })
712 * )
713 * })
714 * schema.fields.username.ast.context?.annotations?.messageMissingKey // => "Username is required"
715 * ```
716 *
717 * @category annotations
718 * @since 4.0.0
719 */
720export function annotateKey<S extends Top>(annotations: Annotations.Key<S["Type"]>) {
721 return (self: S): S["Rebuild"] => {
722 return self.rebuild(SchemaAST.annotateKey(self.ast, annotations))
723 }
724}
725/**
726 * The existential "any schema" type — all type parameters are erased to `unknown`.
727 *
728 * **Details**
729 *
730 * Use `Top` as a constraint when writing generic utilities that must accept *any*
731 * schema regardless of its `Type`, `Encoded`, or service requirements. It is the
732 * widest possible schema type and therefore gives you the least static information.
733 *
734 * In user code prefer the narrower interfaces:
735 * - {@link Schema}`<T>` — when you only care about the decoded type
736 * - {@link Codec}`<T, E, RD, RE>` — when you need the encoded type and service requirements
737 * - {@link ConstraintDecoder}`<T, RD>` — for decode-only APIs
738 * - {@link ConstraintEncoder}`<E, RE>` — for encode-only APIs
739 *
740 * @category models
741 * @since 4.0.0
742 */
743export interface Top extends
744 Bottom<
745 unknown,
746 unknown,
747 unknown,
748 unknown,
749 SchemaAST.AST,
750 Top,
751 unknown,
752 unknown,
753 any, // this is because TypeParameters is invariant
754 unknown,
755 Mutability,
756 Optionality,
757 ConstructorDefault,
758 Mutability,
759 Optionality
760 >
761{}
762/**
763 * Lightweight structural constraint for APIs that accept schema values but only
764 * read their data and type-level views.
765 *
766 * **When to use**
767 *
768 * Use when you need to constrain a generic value to be a schema, but the API
769 * only reads properties such as `ast`, `Type`, `Encoded`, service
770 * requirements, constructor input views, or modifier flags.
771 *
772 * **Details**
773 *
774 * `Constraint` keeps the schema type identifier and the property surface needed
775 * by schema constructors, while avoiding the full `Bottom` protocol. Use
776 * {@link Top} when an API calls schema methods such as `annotate`, `check`,
777 * `rebuild`, `make`, or `makeEffect`.
778 *
779 * @see {@link Top} for the complete schema protocol.
780 *
781 * @category models
782 * @since 4.0.0
783 */
784export interface Constraint {
785 readonly [TypeId]: typeof TypeId
786 readonly "ast": SchemaAST.AST
787
788 readonly "Type": unknown
789 readonly "Encoded": unknown
790 readonly "DecodingServices": unknown
791 readonly "EncodingServices": unknown
792
793 readonly "~type.parameters": any
794 readonly "~type.make.in": unknown
795 readonly "~type.make": unknown
796 readonly "Iso": unknown
797
798 readonly "~type.optionality": Optionality
799 readonly "~type.mutability": Mutability
800 readonly "~type.constructor.default": ConstructorDefault
801 readonly "~encoded.optionality": Optionality
802 readonly "~encoded.mutability": Mutability
803}
804/**
805 * Lightweight structural constraint for APIs that need codec type views but do
806 * not need the full schema protocol.
807 *
808 * **When to use**
809 *
810 * Use when you need to preserve decoded type, encoded type, and service
811 * requirements for a schema value, but the API does not call schema methods
812 * such as `annotate`, `check`, `rebuild`, `make`, or `makeEffect`.
813 *
814 * @see {@link Constraint} for the generic lightweight schema constraint.
815 * @see {@link Codec} for the full schema protocol with codec type views.
816 *
817 * @category models
818 * @since 4.0.0
819 */
820export interface ConstraintCodec<out T, out E = T, out RD = never, out RE = never> extends Constraint {
821 readonly "Type": T
822 readonly "Encoded": E
823 readonly "DecodingServices": RD
824 readonly "EncodingServices": RE
825}
826/**
827 * Lightweight structural constraint for APIs that need decoder type views but
828 * do not need the full schema protocol.
829 *
830 * **When to use**
831 *
832 * Use when you need to preserve a schema's decoded type and decoding services,
833 * but the API does not constrain the encoded type, encoding services, or call
834 * schema methods such as `annotate`, `check`, `rebuild`, `make`, or
835 * `makeEffect`.
836 *
837 * @see {@link ConstraintCodec} for APIs that need both decoded and encoded codec views.
838 * @see {@link Codec} for the full schema protocol with codec type views.
839 *
840 * @category models
841 * @since 4.0.0
842 */
843export interface ConstraintDecoder<out T, out RD = never> extends ConstraintCodec<T, unknown, RD, unknown> {}
844/**
845 * Lightweight structural constraint for APIs that need encoder type views but
846 * do not need the full schema protocol.
847 *
848 * **When to use**
849 *
850 * Use when you need to preserve a schema's encoded type and encoding services,
851 * but the API does not constrain the decoded type, decoding services, or call
852 * schema methods such as `annotate`, `check`, `rebuild`, `make`, or
853 * `makeEffect`.
854 *
855 * @see {@link ConstraintCodec} for APIs that need both decoded and encoded codec views.
856 * @see {@link Codec} for the full schema protocol with codec type views.
857 *
858 * @category models
859 * @since 4.0.0
860 */
861export interface ConstraintEncoder<out E, out RE = never> extends ConstraintCodec<unknown, E, unknown, RE> {}
862/**
863 * Lightweight structural constraint for APIs that need schema views and the
864 * rebuilt schema type, but do not call the full schema protocol.
865 *
866 * **When to use**
867 *
868 * Use when an API needs to read `Rebuild` in addition to the schema views
869 * exposed by {@link Constraint}, but does not call methods such as `annotate`,
870 * `check`, `rebuild`, `make`, or `makeEffect`.
871 *
872 * @category models
873 * @since 4.0.0
874 */
875export interface ConstraintRebuildable extends Constraint {
876 readonly "Rebuild": Constraint
877}
878/**
879 * Namespace of type-level helpers for {@link Schema}.
880 *
881 * @since 3.10.0
882 */
883export declare namespace Schema {
884 /**
885 * Extracts the decoded `Type` from a schema.
886 *
887 * **Example** (Extracting the decoded type)
888 *
889 * ```ts import.meta.vitest
890 * import { Schema } from "effect"
891 *
892 * const Person = Schema.Struct({ name: Schema.String, age: Schema.Number })
893 * type Person = Schema.Schema.Type<typeof Person>
894 * // { readonly name: string; readonly age: number }
895 * ```
896 *
897 * @category utility types
898 * @since 3.10.0
899 */
900 type Type<S> = S extends {
901 readonly "Type": infer T
902 } ? T :
903 never
904}
905/**
906 * A typed view of a schema that tracks only the decoded (output) type `T`.
907 *
908 * **Details**
909 *
910 * Use `Schema<T>` as a constraint when you want to accept "any schema that
911 * decodes to `T`" and do not need to know or constrain the encoded
912 * representation, required services, or any other type parameters.
913 *
914 * This is a structural interface — concrete schema values are produced by the
915 * constructors in this module (e.g. {@link Struct}, {@link String}, {@link Number}).
916 * When you also need the encoded type or service requirements, use {@link Codec}.
917 *
918 * **Example** (Accepting any schema decoding to `string`)
919 *
920 * ```ts import.meta.vitest
921 * import { Schema } from "effect"
922 *
923 * const accept = (_schema: Schema.Schema<string>): void => {}
924 *
925 * accept(Schema.String)
926 * accept(Schema.NonEmptyString)
927 * ```
928 *
929 * @see {@link Codec} — also tracks Encoded, DecodingServices, EncodingServices
930 * @see {@link Schema.Type} — extract the decoded type at the type level
931 *
932 * @category models
933 * @since 3.10.0
934 */
935export interface Schema<out T> extends Top {
936 readonly "Type": T
937 readonly "Rebuild": Schema<T>
938}
939/**
940 * Namespace of type-level helpers for {@link Codec}.
941 *
942 * @since 4.0.0
943 */
944export declare namespace Codec {
945 /**
946 * Extracts the encoded (`Encoded`) type from a schema.
947 *
948 * **Example** (Extracting the encoded type)
949 *
950 * ```ts import.meta.vitest
951 * import { Schema } from "effect"
952 *
953 * const schema = Schema.NumberFromString
954 * type Enc = Schema.Codec.Encoded<typeof schema>
955 * // string
956 * ```
957 *
958 * @category utility types
959 * @since 3.10.0
960 */
961 type Encoded<S> = S extends {
962 readonly "Encoded": infer E
963 } ? E :
964 never
965 /**
966 * Extracts the Effect services required during *decoding* from a schema.
967 *
968 * **Example** (Checking decoding service requirements)
969 *
970 * ```ts import.meta.vitest
971 * import { Schema } from "effect"
972 *
973 * const schema = Schema.String
974 * type RD = Schema.Codec.DecodingServices<typeof schema>
975 * // never
976 * ```
977 *
978 * @category utility types
979 * @since 4.0.0
980 */
981 type DecodingServices<S> = S extends {
982 readonly "DecodingServices": infer R
983 } ? R :
984 never
985 /**
986 * Extracts the Effect services required during *encoding* from a schema.
987 *
988 * **Example** (Checking encoding service requirements)
989 *
990 * ```ts import.meta.vitest
991 * import { Schema } from "effect"
992 *
993 * const schema = Schema.String
994 * type RE = Schema.Codec.EncodingServices<typeof schema>
995 * // never
996 * ```
997 *
998 * @category utility types
999 * @since 4.0.0
1000 */
1001 type EncodingServices<S> = S extends {
1002 readonly "EncodingServices": infer R
1003 } ? R :
1004 never
1005}
1006/**
1007 * A schema that tracks the decoded type `T`, the encoded type `E`, and the
1008 * Effect services required during decoding (`RD`) and encoding (`RE`).
1009 *
1010 * **Details**
1011 *
1012 * Use `Codec<T, E, RD, RE>` when you need to preserve full type information
1013 * about a schema — both what it decodes to and what it serializes from/to.
1014 * Most concrete schemas produced by this module implement `Codec`.
1015 *
1016 * For APIs that only need one direction, prefer the narrower views:
1017 * - {@link Decoder}`<T, RD>` — decode-only
1018 * - {@link Encoder}`<E, RE>` — encode-only
1019 * - {@link Schema}`<T>` — type-only (no encoded representation)
1020 *
1021 * **Example** (Accepting a codec that decodes to `number` from `string`)
1022 *
1023 * ```ts import.meta.vitest
1024 * import { Schema } from "effect"
1025 *
1026 * const serialize = <T>(codec: Schema.Codec<T, string>, value: T): string =>
1027 * Schema.encodeSync(codec)(value)
1028 *
1029 * serialize(Schema.NumberFromString, 42) // => "42"
1030 * ```
1031 *
1032 * @see {@link Codec.Encoded} — extract the encoded type
1033 * @see {@link Codec.DecodingServices} — extract required decoding services
1034 * @see {@link Codec.EncodingServices} — extract required encoding services
1035 * @see {@link revealCodec} — helper to make TypeScript infer the full Codec type
1036 *
1037 * @category models
1038 * @since 4.0.0
1039 */
1040export interface Codec<out T, out E = T, out RD = never, out RE = never> extends Schema<T> {
1041 readonly "Encoded": E
1042 readonly "DecodingServices": RD
1043 readonly "EncodingServices": RE
1044 readonly "Rebuild": Codec<T, E, RD, RE>
1045}
1046/**
1047 * A schema that tracks the decoded type `T` and the Effect services required
1048 * during decoding (`RD`).
1049 *
1050 * **When to use**
1051 *
1052 * Use when you need to preserve a schema's decoded type and decoding service
1053 * requirements, but do not need to constrain its encoded representation or
1054 * encoding services.
1055 *
1056 * @see {@link Codec} for preserving both decoded and encoded type information.
1057 * @see {@link Encoder} for the encode-only view.
1058 *
1059 * @category models
1060 * @since 4.0.0
1061 */
1062export interface Decoder<out T, out RD = never> extends Schema<T> {
1063 readonly "Encoded": unknown
1064 readonly "DecodingServices": RD
1065 readonly "EncodingServices": unknown
1066 readonly "Rebuild": Decoder<T, RD>
1067}
1068/**
1069 * A schema that tracks the encoded type `E` and the Effect services required
1070 * during encoding (`RE`).
1071 *
1072 * **When to use**
1073 *
1074 * Use when you need to preserve a schema's encoded type and encoding service
1075 * requirements, but do not need to constrain its decoded representation or
1076 * decoding services.
1077 *
1078 * @see {@link Codec} for preserving both decoded and encoded type information.
1079 * @see {@link Decoder} for the decode-only view.
1080 *
1081 * @category models
1082 * @since 4.0.0
1083 */
1084export interface Encoder<out E, out RE = never> extends Schema<unknown> {
1085 readonly "Encoded": E
1086 readonly "DecodingServices": unknown
1087 readonly "EncodingServices": RE
1088 readonly "Rebuild": Encoder<E, RE>
1089}
1090/**
1091 * Returns a codec widened to the full {@link Codec} interface, prompting
1092 * TypeScript to infer all four type parameters (`T`, `E`, `RD`, `RE`).
1093 *
1094 * **Details**
1095 *
1096 * When a schema is stored in a variable typed as `Schema<T>` or `Top`, the
1097 * encoded type and service requirements are erased. Passing the value through
1098 * `revealCodec` recovers those parameters without any runtime cost.
1099 *
1100 * **Example** (Recovering encoded type from a schema variable)
1101 *
1102 * ```ts import.meta.vitest
1103 * import { Schema } from "effect"
1104 *
1105 * const schema: Schema.Schema<number> = Schema.NumberFromString
1106 *
1107 * // Without revealCodec, Encoded is unknown
1108 * const codec = Schema.revealCodec(schema)
1109 * type Enc = typeof codec["Encoded"] // string
1110 * ```
1111 *
1112 * @category utility types
1113 * @since 4.0.0
1114 */
1115export function revealCodec<T, E, RD, RE>(codec: Codec<T, E, RD, RE>) {
1116 return codec
1117}
1118/**
1119 * A schema that additionally supports optic (lens/prism) operations.
1120 *
1121 * **Details**
1122 *
1123 * `Optic<T, Iso>` extends {@link Schema}`<T>` with an `Iso` type that
1124 * describes the isomorphic counterpart used by the optic layer. Crucially,
1125 * decoding and encoding require *no* Effect services (`DecodingServices` and
1126 * `EncodingServices` are both `never`), which means the optic can operate
1127 * purely without an Effect runtime.
1128 *
1129 * Most primitive schemas (e.g. `Schema.String`, `Schema.Number`) implement
1130 * `Optic` automatically. You normally interact with this interface through
1131 * {@link Optic_} utilities rather than constructing it directly.
1132 *
1133 * @category models
1134 * @since 4.0.0
1135 */
1136export interface Optic<out T, out Iso> extends Schema<T> {
1137 readonly "Iso": Iso
1138 readonly "DecodingServices": never
1139 readonly "EncodingServices": never
1140 readonly "Rebuild": Optic<T, Iso>
1141}
1142/**
1143 * Error thrown or returned when schema decoding or encoding fails.
1144 *
1145 * **Details**
1146 *
1147 * The `issue` field contains a structured {@link SchemaIssue.Issue} tree describing
1148 * every validation failure, including the path to the problematic value and
1149 * the expected type or constraint. The `message` field renders the issue tree
1150 * with the default formatter.
1151 *
1152 * **Gotchas**
1153 *
1154 * Parsing with `reportInput: true` adds an enumerable `input` field to
1155 * value-bearing issues. Built-in messages may include reported input, and
1156 * custom annotations or messages are not sanitized.
1157 *
1158 * **Example** (Inspecting a SchemaError)
1159 *
1160 * ```ts import.meta.vitest
1161 * import { Result, Schema } from "effect"
1162 *
1163 * const result = Schema.decodeUnknownResult(Schema.Number)("not a number")
1164 * const message = Result.isFailure(result) ? result.failure.message : ""
1165 * message // => "Expected number"
1166 * ```
1167 *
1168 * @see {@link isSchemaError} for narrowing unknown values
1169 * @category errors
1170 * @since 4.0.0
1171 */
1172export class SchemaError extends Data.TaggedError("SchemaError")<{
1173 readonly issue: SchemaIssue.Issue
1174}> {
1175 readonly [SchemaErrorTypeId]: typeof SchemaErrorTypeId = SchemaErrorTypeId
1176 constructor(issue: SchemaIssue.Issue) {
1177 const stackTraceLimit = getStackTraceLimit()
1178 setStackTraceLimit(0)
1179 try {
1180 super({ issue })
1181 } finally {
1182 setStackTraceLimit(stackTraceLimit)
1183 }
1184 }
1185 override get message() {
1186 return SchemaIssue.defaultFormatter(this.issue)
1187 }
1188 override toString() {
1189 return `SchemaError(${this.message})`
1190 }
1191}
1192/**
1193 * Returns `true` if `u` is a {@link SchemaError}.
1194 *
1195 * **When to use**
1196 *
1197 * Use when you need to narrow an unknown value to `SchemaError`.
1198 *
1199 * **Example** (Narrowing Schema errors)
1200 *
1201 * ```ts import.meta.vitest
1202 * import { Result, Schema } from "effect"
1203 *
1204 * const result = Result.try(() => Schema.decodeUnknownSync(Schema.Number)("oops"))
1205 * const error: unknown = Result.isFailure(result) ? result.failure : undefined
1206 * Schema.isSchemaError(error) // => true
1207 * ```
1208 *
1209 * @category guards
1210 * @since 4.0.0
1211 */
1212export function isSchemaError(u: unknown): u is SchemaError {
1213 return isSchemaErrorInternal(u)
1214}
1215
1216function fromIssueEffect<A, R>(
1217 self: Effect.Effect<A, SchemaIssue.Issue, R>
1218): Effect.Effect<A, SchemaError, R> {
1219 if (effectIsExit(self)) {
1220 return fromIssueExit(self as Exit_.Exit<A, SchemaIssue.Issue>)
1221 }
1222 return Effect.catchCause(
1223 self,
1224 (cause) => Effect.failCauseSync(() => Cause_.map(cause, (issue) => new SchemaError(issue)))
1225 )
1226}
1227
1228function fromIssueExit<A>(exit: Exit_.Exit<A, SchemaIssue.Issue>): Exit_.Exit<A, SchemaError> {
1229 return Exit_.isSuccess(exit)
1230 ? exit as unknown as Exit_.Exit<A, SchemaError>
1231 : Exit_.failCause(Cause_.map(exit.cause, (issue) => new SchemaError(issue)))
1232}
1233
1234function getSchemaErrorOrThrow(
1235 cause: Cause_.Cause<SchemaError>,
1236 message: string
1237): SchemaError {
1238 let schemaError: SchemaError | undefined
1239 for (const reason of cause.reasons) {
1240 if (!Cause_.isFailReason(reason) || !isSchemaError(reason.error)) {
1241 throw new globalThis.Error(message, { cause })
1242 }
1243 schemaError ??= reason.error
1244 }
1245 if (schemaError === undefined) {
1246 throw new globalThis.Error(message, { cause })
1247 }
1248 return schemaError
1249}
1250
1251function runSchemaErrorPromise<A>(
1252 self: Effect.Effect<A, SchemaError>
1253): Promise<A> {
1254 return Effect.runPromiseExit(self).then((exit) => {
1255 if (Exit_.isSuccess(exit)) {
1256 return exit.value
1257 }
1258 throw getSchemaErrorOrThrow(exit.cause, "Promise adapter can only reject schema errors")
1259 })
1260}
1261
1262function runSchemaErrorSync<A>(
1263 self: Effect.Effect<A, SchemaError>
1264): A {
1265 const exit = Effect.runSyncExit(self)
1266 if (Exit_.isSuccess(exit)) {
1267 return exit.value
1268 }
1269 throw getSchemaErrorOrThrow(exit.cause, "Sync adapter can only throw schema errors")
1270}
1271/**
1272 * Returns a "Standard Schema" object conforming to the [Standard Schema
1273 * v1](https://standardschema.dev/) specification.
1274 *
1275 * **Details**
1276 *
1277 * This function creates a schema whose `validate` method attempts to decode and
1278 * validate the provided input synchronously. If the underlying `Schema`
1279 * includes any asynchronous components (e.g., asynchronous message resolutions
1280 * or checks), then validation will necessarily return a `Promise` instead.
1281 *
1282 * **Example** (Creating a standard schema from a regular schema)
1283 *
1284 * ```ts import.meta.vitest
1285 * import { Schema } from "effect"
1286 *
1287 * // Define custom hook functions for error formatting
1288 * const leafHook = (issue: any) => {
1289 * switch (issue._tag) {
1290 * case "InvalidType":
1291 * return "Expected different type"
1292 * case "InvalidValue":
1293 * return "Invalid value provided"
1294 * case "MissingKey":
1295 * return "Required property missing"
1296 * case "UnexpectedKey":
1297 * return "Unexpected property found"
1298 * case "Forbidden":
1299 * return "Operation not allowed"
1300 * case "OneOf":
1301 * return "Multiple valid options available"
1302 * default:
1303 * return "Validation error"
1304 * }
1305 * }
1306 *
1307 * // Create a standard schema from a regular schema
1308 * const PersonSchema = Schema.Struct({
1309 * name: Schema.NonEmptyString,
1310 * age: Schema.Finite.check(Schema.isBetween({ minimum: 0, maximum: 150 }))
1311 * })
1312 *
1313 * const standardSchema = Schema.toStandardSchemaV1(PersonSchema, {
1314 * leafHook
1315 * })
1316 *
1317 * // The standard schema can be used with any Standard Schema v1 compatible library
1318 * const validResult = standardSchema["~standard"].validate({
1319 * name: "Alice",
1320 * age: 30
1321 * })
1322 * const invalidResult = standardSchema["~standard"].validate({
1323 * name: "",
1324 * age: 200
1325 * })
1326 *
1327 * if (validResult instanceof Promise || invalidResult instanceof Promise) {
1328 * throw new Error("Expected synchronous validation")
1329 * }
1330 * if ("value" in validResult) {
1331 * validResult.value // => { name: "Alice", age: 30 }
1332 * }
1333 * invalidResult.issues?.map((issue) => issue.path) // => [["name"], ["age"]]
1334 * ```
1335 *
1336 * @category converting
1337 * @since 4.0.0
1338 */
1339export function toStandardSchemaV1<S extends ConstraintDecoder<unknown>>(
1340 self: S,
1341 options?: {
1342 readonly leafHook?: SchemaIssue.LeafHook | undefined
1343 readonly checkHook?: SchemaIssue.CheckHook | undefined
1344 readonly parseOptions?: SchemaAST.ParseOptions | undefined
1345 }
1346): StandardSchemaV1<S["Encoded"], S["Type"]> & S {
1347 return InternalStandardSchema.toStandardSchemaV1(self, options)
1348}
1349/**
1350 * Converts a schema to an experimental Standard JSON Schema V1 representation.
1351 *
1352 * **Details**
1353 *
1354 * https://github.com/standard-schema/standard-schema/pull/134
1355 *
1356 * @category converting
1357 * @since 4.0.0
1358 */
1359export function toStandardJSONSchemaV1<S extends Constraint>(
1360 self: S
1361): StandardJSONSchemaV1<S["Encoded"], S["Type"]> & S {
1362 return InternalStandardSchema.toStandardJSONSchemaV1(self)
1363}
1364/**
1365 * Creates a type guard function that checks if a value conforms to a given
1366 * schema.
1367 *
1368 * **Details**
1369 *
1370 * This function returns a predicate that performs a type-safe check, narrowing
1371 * the type of the input value if the check passes. The predicate returns `false`
1372 * for schema mismatches.
1373 *
1374 * **Gotchas**
1375 *
1376 * Only causes made entirely of schema issues are converted to `false`. Causes
1377 * that contain defects, interruptions, or other non-schema reasons throw
1378 * instead.
1379 *
1380 * **Example** (Defining a basic type guard)
1381 *
1382 * ```ts import.meta.vitest
1383 * import { Schema } from "effect"
1384 *
1385 * const isString = Schema.is(Schema.String)
1386 *
1387 * isString("hello") // => true
1388 * isString(42) // => false
1389 *
1390 * // Type narrowing in action
1391 * const value: unknown = "hello"
1392 * if (isString(value)) {
1393 * // value is now typed as string
1394 * value.toUpperCase() // => "HELLO"
1395 * }
1396 * ```
1397 *
1398 * @category guards
1399 * @since 3.10.0
1400 */
1401export const is: typeof SchemaParser.is = SchemaParser.is
1402/**
1403 * Creates an assertion function that throws an error if the input does not match
1404 * the schema.
1405 *
1406 * **When to use**
1407 *
1408 * Use to validate unknown input at runtime while narrowing the value with a
1409 * TypeScript assertion signature.
1410 *
1411 * **Details**
1412 *
1413 * The input is narrowed if the assertion succeeds. If schema validation fails,
1414 * the assertion throws an `Error` whose cause is `SchemaIssue.Issue`.
1415 * Schema validation failures use the generic message `"Schema validation failed"`.
1416 * Format the `cause` explicitly with `SchemaIssue.makeFormatterDefault()` when
1417 * human-readable details are needed.
1418 *
1419 * **Gotchas**
1420 *
1421 * Causes that contain defects, interruptions, or other non-schema reasons throw
1422 * with the underlying `Cause` attached instead of being converted to schema
1423 * validation errors.
1424 *
1425 * **Example** (Asserting and narrowing an input)
1426 *
1427 * ```ts import.meta.vitest
1428 * import { Schema, SchemaIssue } from "effect"
1429 *
1430 * const input: unknown = "hello"
1431 *
1432 * // This will pass silently (no return value) and narrow input to string
1433 * Schema.asserts(Schema.String, input)
1434 * input.toUpperCase() // => "HELLO"
1435 *
1436 * // This will throw an error
1437 * try {
1438 * const invalid: unknown = 123
1439 * Schema.asserts(Schema.String, invalid)
1440 * } catch (error) {
1441 * if (error instanceof Error) {
1442 * SchemaIssue.isIssue(error.cause) // => true
1443 * }
1444 * }
1445 * ```
1446 *
1447 * @category guards
1448 * @since 4.0.0
1449 */
1450export const asserts: <S extends Constraint, I>(schema: S, input: I) => asserts input is I & S["Type"] =
1451 SchemaParser.asserts
1452/**
1453 * Decodes an `unknown` input against a schema, returning an `Effect` that
1454 * succeeds with the decoded value or fails with a {@link SchemaError}.
1455 *
1456 * **When to use**
1457 *
1458 * Use when you need to decode unknown input in an `Effect` whose failure
1459 * channel is `SchemaError`.
1460 *
1461 * **Details**
1462 *
1463 * Prefer {@link decodeEffect} when the input is already typed as the schema's
1464 * `Encoded` type.
1465 * Options may be provided either when creating the decoder or when applying it;
1466 * application options override creation options.
1467 *
1468 * @see {@link SchemaParser.decodeUnknownEffect} for the adapter that fails with `SchemaIssue.Issue` directly
1469 *
1470 * @category decoding
1471 * @since 4.0.0
1472 */
1473export function decodeUnknownEffect<S extends Constraint>(schema: S, options?: SchemaAST.ParseOptions) {
1474 const parser = SchemaParser.decodeUnknownEffect(schema, options)
1475 return (
1476 input: unknown,
1477 options?: SchemaAST.ParseOptions
1478 ): Effect.Effect<S["Type"], SchemaError, S["DecodingServices"]> => {
1479 return fromIssueEffect(parser(input, options))
1480 }
1481}
1482/**
1483 * Decodes a typed input (the schema's `Encoded` type) against a schema,
1484 * returning an `Effect` that succeeds with the decoded value or fails with a
1485 * {@link SchemaError}.
1486 *
1487 * **When to use**
1488 *
1489 * Use when you need to decode input already typed as the schema's `Encoded`
1490 * type in an `Effect` whose failure channel is `SchemaError`.
1491 *
1492 * **Details**
1493 *
1494 * For `unknown` input use {@link decodeUnknownEffect}.
1495 * Options may be provided either when creating the decoder or when applying it;
1496 * application options override creation options.
1497 *
1498 * @see {@link SchemaParser.decodeEffect} for the adapter that fails with `SchemaIssue.Issue` directly
1499 *
1500 * @category decoding
1501 * @since 4.0.0
1502 */
1503export const decodeEffect: <S extends Constraint>(
1504 schema: S,
1505 options?: SchemaAST.ParseOptions
1506) => (
1507 input: S["Encoded"],
1508 options?: SchemaAST.ParseOptions
1509) => Effect.Effect<S["Type"], SchemaError, S["DecodingServices"]> = decodeUnknownEffect
1510/**
1511 * Decodes an `unknown` input against a schema synchronously, returning an
1512 * `Exit` that is either a `Success` with the decoded value or a `Failure`.
1513 *
1514 * **When to use**
1515 *
1516 * Use when you need to decode unknown input into an `Exit` and capture schema
1517 * mismatches as `SchemaError`.
1518 *
1519 * **Details**
1520 *
1521 * Only usable with schemas that have no `DecodingServices` requirement. Prefer
1522 * {@link decodeExit} when the input is already typed as the schema's `Encoded`
1523 * type.
1524 * Options may be provided either when creating the decoder or when applying it;
1525 * application options override creation options.
1526 * Schema mismatches are represented by a `Failure` cause containing
1527 * `SchemaError`.
1528 *
1529 * **Gotchas**
1530 *
1531 * Schema issue fail reasons are wrapped as `SchemaError`. Defects,
1532 * interruptions, and other non-schema reasons remain in the returned `Cause`,
1533 * including when they are mixed with schema issues.
1534 *
1535 * @see {@link SchemaParser.decodeUnknownExit} for the adapter whose failure contains `SchemaIssue.Issue` directly
1536 *
1537 * @category decoding
1538 * @since 4.0.0
1539 */
1540export function decodeUnknownExit<S extends ConstraintDecoder<unknown>>(schema: S, options?: SchemaAST.ParseOptions) {
1541 const parser = SchemaParser.decodeUnknownExit(schema, options)
1542 return (input: unknown, options?: SchemaAST.ParseOptions): Exit_.Exit<S["Type"], SchemaError> => {
1543 return fromIssueExit(parser(input, options))
1544 }
1545}
1546/**
1547 * Decodes a typed input (the schema's `Encoded` type) against a schema
1548 * synchronously, returning an `Exit` that is either a `Success` with the decoded
1549 * value or a `Failure`.
1550 *
1551 * **When to use**
1552 *
1553 * Use when you need to decode already typed `Encoded` input into an `Exit` and
1554 * capture schema mismatches as `SchemaError`.
1555 *
1556 * **Details**
1557 *
1558 * Only usable with schemas that have no `DecodingServices` requirement. For
1559 * `unknown` input use {@link decodeUnknownExit}.
1560 * Options may be provided either when creating the decoder or when applying it;
1561 * application options override creation options.
1562 * Schema mismatches are represented by a `Failure` cause containing
1563 * `SchemaError`.
1564 *
1565 * **Gotchas**
1566 *
1567 * Schema issue fail reasons are wrapped as `SchemaError`. Defects,
1568 * interruptions, and other non-schema reasons remain in the returned `Cause`,
1569 * including when they are mixed with schema issues.
1570 *
1571 * @see {@link SchemaParser.decodeExit} for the adapter whose failure contains `SchemaIssue.Issue` directly
1572 *
1573 * @category decoding
1574 * @since 4.0.0
1575 */
1576export const decodeExit: <S extends ConstraintDecoder<unknown>>(
1577 schema: S,
1578 options?: SchemaAST.ParseOptions
1579) => (input: S["Encoded"], options?: SchemaAST.ParseOptions) => Exit_.Exit<S["Type"], SchemaError> = decodeUnknownExit
1580/**
1581 * Decodes an `unknown` input against a schema, returning an `Option` that is
1582 * `Some` with the decoded value on success or `None` for schema mismatches.
1583 *
1584 * **When to use**
1585 *
1586 * Use when you do not know the input type statically and only need to know
1587 * whether decoding succeeded.
1588 *
1589 * **Details**
1590 *
1591 * Prefer this over {@link decodeUnknownExit} or {@link decodeUnknownEffect}
1592 * when you don't need error details. For input already typed as the schema's
1593 * `Encoded` type use {@link decodeOption}.
1594 * Options may be provided either when creating the decoder or when applying it;
1595 * application options override creation options.
1596 *
1597 * **Gotchas**
1598 *
1599 * Only causes made entirely of schema issues are converted to `None`. Causes
1600 * that contain defects, interruptions, or other non-schema reasons throw
1601 * instead.
1602 *
1603 * @category decoding
1604 * @since 3.10.0
1605 */
1606export const decodeUnknownOption: <S extends ConstraintDecoder<unknown>>(
1607 schema: S,
1608 options?: SchemaAST.ParseOptions
1609) => (input: unknown, options?: SchemaAST.ParseOptions) => Option_.Option<S["Type"]> = SchemaParser.decodeUnknownOption
1610/**
1611 * Decodes a typed input (the schema's `Encoded` type) against a schema,
1612 * returning an `Option` that is `Some` with the decoded value on success or
1613 * `None` for schema mismatches.
1614 *
1615 * **When to use**
1616 *
1617 * Use when you already have input typed as the schema's `Encoded` type and
1618 * only need to know whether decoding succeeded.
1619 *
1620 * **Details**
1621 *
1622 * For `unknown` input use {@link decodeUnknownOption}.
1623 * Options may be provided either when creating the decoder or when applying it;
1624 * application options override creation options.
1625 *
1626 * **Gotchas**
1627 *
1628 * Only causes made entirely of schema issues are converted to `None`. Causes
1629 * that contain defects, interruptions, or other non-schema reasons throw
1630 * instead.
1631 *
1632 * @category decoding
1633 * @since 3.10.0
1634 */
1635export const decodeOption: <S extends ConstraintDecoder<unknown>>(
1636 schema: S,
1637 options?: SchemaAST.ParseOptions
1638) => (input: S["Encoded"], options?: SchemaAST.ParseOptions) => Option_.Option<S["Type"]> = SchemaParser.decodeOption
1639/**
1640 * Decodes an `unknown` input against a schema, returning a `Result` that
1641 * succeeds with the decoded value or fails with a {@link SchemaError} for schema
1642 * mismatches.
1643 *
1644 * **When to use**
1645 *
1646 * Use when you do not know the input type statically and want schema mismatches
1647 * returned as `Result.fail` with `SchemaError`.
1648 *
1649 * **Details**
1650 *
1651 * For input already typed as the schema's `Encoded` type use
1652 * {@link decodeResult}.
1653 * Options may be provided either when creating the decoder or when applying it;
1654 * application options override creation options.
1655 * Schema mismatches are returned as `Result.fail` with `SchemaError`.
1656 *
1657 * **Gotchas**
1658 *
1659 * Only causes made entirely of schema issues are returned as `Result.fail`.
1660 * Causes that contain defects, interruptions, or other non-schema reasons throw
1661 * instead.
1662 *
1663 * @see {@link SchemaParser.decodeUnknownResult} for the adapter that fails with `SchemaIssue.Issue` directly
1664 *
1665 * @category decoding
1666 * @since 4.0.0
1667 */
1668export function decodeUnknownResult<S extends ConstraintDecoder<unknown>>(schema: S, options?: SchemaAST.ParseOptions) {
1669 const parser = SchemaParser.decodeUnknownResult(schema, options)
1670 return (input: unknown, options?: SchemaAST.ParseOptions): Result_.Result<S["Type"], SchemaError> => {
1671 return Result_.mapError(parser(input, options), (issue) => new SchemaError(issue))
1672 }
1673}
1674/**
1675 * Decodes a typed input (the schema's `Encoded` type) against a schema,
1676 * returning a `Result` that succeeds with the decoded value or fails with a
1677 * {@link SchemaError} for schema mismatches.
1678 *
1679 * **When to use**
1680 *
1681 * Use when you already have input typed as the schema's `Encoded` type and want
1682 * schema mismatches returned as `Result.fail` with `SchemaError`.
1683 *
1684 * **Details**
1685 *
1686 * For `unknown` input use {@link decodeUnknownResult}.
1687 * Options may be provided either when creating the decoder or when applying it;
1688 * application options override creation options.
1689 * Schema mismatches are returned as `Result.fail` with `SchemaError`.
1690 *
1691 * **Gotchas**
1692 *
1693 * Only causes made entirely of schema issues are returned as `Result.fail`.
1694 * Causes that contain defects, interruptions, or other non-schema reasons throw
1695 * instead.
1696 *
1697 * @see {@link SchemaParser.decodeResult} for the adapter that fails with `SchemaIssue.Issue` directly
1698 *
1699 * @category decoding
1700 * @since 4.0.0
1701 */
1702export const decodeResult: <S extends ConstraintDecoder<unknown>>(
1703 schema: S,
1704 options?: SchemaAST.ParseOptions
1705) => (input: S["Encoded"], options?: SchemaAST.ParseOptions) => Result_.Result<S["Type"], SchemaError> =
1706 decodeUnknownResult
1707/**
1708 * Decodes an `unknown` input against a schema, returning a `Promise` that
1709 * resolves with the decoded value or rejects with a {@link SchemaError} for
1710 * schema mismatches.
1711 *
1712 * **When to use**
1713 *
1714 * Use when you need decoding of unknown input to return a JavaScript `Promise`
1715 * that rejects with `SchemaError` for schema mismatches.
1716 *
1717 * **Details**
1718 *
1719 * For input already typed as the schema's `Encoded` type use
1720 * {@link decodePromise}.
1721 * Options may be provided either when creating the decoder or when applying it;
1722 * application options override creation options.
1723 *
1724 * **Gotchas**
1725 *
1726 * Non-schema failures may reject with a runtime failure instead of
1727 * `SchemaError`.
1728 *
1729 * @see {@link SchemaParser.decodeUnknownPromise} for the adapter that rejects with an `Error` whose cause is `SchemaIssue.Issue`
1730 *
1731 * @category decoding
1732 * @since 3.10.0
1733 */
1734export function decodeUnknownPromise<S extends ConstraintDecoder<unknown>>(
1735 schema: S,
1736 options?: SchemaAST.ParseOptions
1737) {
1738 const parser = decodeUnknownEffect(schema, options)
1739 return (input: unknown, options?: SchemaAST.ParseOptions): Promise<S["Type"]> => {
1740 return runSchemaErrorPromise(parser(input, options))
1741 }
1742}
1743/**
1744 * Decodes a typed input (the schema's `Encoded` type) against a schema,
1745 * returning a `Promise` that resolves with the decoded value or rejects with a
1746 * {@link SchemaError} for schema mismatches.
1747 *
1748 * **When to use**
1749 *
1750 * Use when you already have input typed as the schema's `Encoded` type and
1751 * need decoding to return a JavaScript `Promise` that rejects with
1752 * `SchemaError` for schema mismatches.
1753 *
1754 * **Details**
1755 *
1756 * For `unknown` input use `decodeUnknownPromise`.
1757 * Options may be provided either when creating the decoder or when applying it;
1758 * application options override creation options.
1759 *
1760 * **Gotchas**
1761 *
1762 * Non-schema failures may reject with a runtime failure instead of
1763 * `SchemaError`.
1764 *
1765 * @see {@link SchemaParser.decodePromise} for the adapter that rejects with an `Error` whose cause is `SchemaIssue.Issue`
1766 *
1767 * @category decoding
1768 * @since 3.10.0
1769 */
1770export const decodePromise: <S extends ConstraintDecoder<unknown>>(
1771 schema: S,
1772 options?: SchemaAST.ParseOptions
1773) => (input: S["Encoded"], options?: SchemaAST.ParseOptions) => Promise<S["Type"]> = decodeUnknownPromise
1774/**
1775 * Decodes an `unknown` input against a schema synchronously, returning the
1776 * decoded value or throwing a {@link SchemaError} for schema mismatches.
1777 *
1778 * **When to use**
1779 *
1780 * Use when you need to validate unknown data at a synchronous boundary and want
1781 * schema mismatches to throw `SchemaError`.
1782 *
1783 * **Details**
1784 *
1785 * For input already typed as the schema's `Encoded` type use `decodeSync`.
1786 * Only service-free schemas can be decoded synchronously. For alternatives that
1787 * do not throw on schema mismatches, see `decodeUnknownOption`,
1788 * `decodeUnknownExit`, or `decodeUnknownEffect`. Options may be provided either
1789 * when creating the decoder or when applying it; application options override
1790 * creation options.
1791 *
1792 * **Gotchas**
1793 *
1794 * Non-schema failures may throw a runtime failure instead of `SchemaError`.
1795 *
1796 * **Example** (Decoding with a transformation schema)
1797 *
1798 * ```ts import.meta.vitest
1799 * import { Schema } from "effect"
1800 *
1801 * const NumberFromString = Schema.NumberFromString
1802 *
1803 * Schema.decodeUnknownSync(NumberFromString)("42") // => 42
1804 * ```
1805 *
1806 * @see {@link SchemaParser.decodeUnknownSync} for the adapter that throws an `Error` whose cause is `SchemaIssue.Issue`
1807 *
1808 * @category decoding
1809 * @since 4.0.0
1810 */
1811export function decodeUnknownSync<S extends ConstraintDecoder<unknown>>(schema: S, options?: SchemaAST.ParseOptions) {
1812 const parser = decodeUnknownEffect(schema, options)
1813 return (input: unknown, options?: SchemaAST.ParseOptions): S["Type"] => {
1814 return runSchemaErrorSync(parser(input, options))
1815 }
1816}
1817/**
1818 * Decodes a typed input (the schema's `Encoded` type) against a schema
1819 * synchronously, returning the decoded value or throwing a {@link SchemaError}
1820 * for schema mismatches.
1821 *
1822 * **When to use**
1823 *
1824 * Use when you already have input typed as the schema's `Encoded` type and
1825 * want schema mismatches to throw `SchemaError` synchronously.
1826 *
1827 * **Details**
1828 *
1829 * For `unknown` input use `decodeUnknownSync`.
1830 * Only service-free schemas can be decoded synchronously. Options may be
1831 * provided either when creating the decoder or when applying it; application
1832 * options override creation options.
1833 *
1834 * **Gotchas**
1835 *
1836 * Non-schema failures may throw a runtime failure instead of `SchemaError`.
1837 *
1838 * @see {@link SchemaParser.decodeSync} for the adapter that throws an `Error` whose cause is `SchemaIssue.Issue`
1839 *
1840 * @category decoding
1841 * @since 4.0.0
1842 */
1843export const decodeSync: <S extends ConstraintDecoder<unknown>>(
1844 schema: S,
1845 options?: SchemaAST.ParseOptions
1846) => (input: S["Encoded"], options?: SchemaAST.ParseOptions) => S["Type"] = decodeUnknownSync
1847/**
1848 * Encodes an `unknown` input against a schema, returning an `Effect` that
1849 * succeeds with the encoded value or fails with a {@link SchemaError}.
1850 *
1851 * **When to use**
1852 *
1853 * Use when you need to encode unknown input in an `Effect` whose failure
1854 * channel is `SchemaError`.
1855 *
1856 * **Details**
1857 *
1858 * Prefer {@link encodeEffect} when the value is already typed as the schema's
1859 * `Type`.
1860 * Options may be provided either when creating the encoder or when applying it;
1861 * application options override creation options.
1862 *
1863 * **Example** (Encoding a value to a string)
1864 *
1865 * ```ts import.meta.vitest
1866 * import { Effect, Schema } from "effect"
1867 *
1868 * const NumberFromString = Schema.NumberFromString
1869 *
1870 * await Effect.runPromise(Schema.encodeUnknownEffect(NumberFromString)(42)) // => "42"
1871 * ```
1872 *
1873 * @see {@link SchemaParser.encodeUnknownEffect} for the adapter that fails with `SchemaIssue.Issue` directly
1874 *
1875 * @category encoding
1876 * @since 4.0.0
1877 */
1878export function encodeUnknownEffect<S extends Constraint>(schema: S, options?: SchemaAST.ParseOptions) {
1879 const parser = SchemaParser.encodeUnknownEffect(schema, options)
1880 return (
1881 input: unknown,
1882 options?: SchemaAST.ParseOptions
1883 ): Effect.Effect<S["Encoded"], SchemaError, S["EncodingServices"]> => {
1884 return fromIssueEffect(parser(input, options))
1885 }
1886}
1887/**
1888 * Encodes a typed input (the schema's `Type`) against a schema, returning an
1889 * `Effect` that succeeds with the encoded value or fails with a
1890 * {@link SchemaError}.
1891 *
1892 * **When to use**
1893 *
1894 * Use when you need to encode input already typed as the schema's `Type` in
1895 * an `Effect` whose failure channel is `SchemaError`.
1896 *
1897 * **Details**
1898 *
1899 * For `unknown` input use {@link encodeUnknownEffect}.
1900 * Options may be provided either when creating the encoder or when applying it;
1901 * application options override creation options.
1902 *
1903 * @see {@link SchemaParser.encodeEffect} for the adapter that fails with `SchemaIssue.Issue` directly
1904 *
1905 * @category encoding
1906 * @since 4.0.0
1907 */
1908export const encodeEffect: <S extends Constraint>(
1909 schema: S,
1910 options?: SchemaAST.ParseOptions
1911) => (
1912 input: S["Type"],
1913 options?: SchemaAST.ParseOptions
1914) => Effect.Effect<S["Encoded"], SchemaError, S["EncodingServices"]> = encodeUnknownEffect
1915/**
1916 * Encodes an `unknown` input against a schema synchronously, returning an
1917 * `Exit` that is either a `Success` with the encoded value or a `Failure`.
1918 *
1919 * **When to use**
1920 *
1921 * Use when you need to encode unknown input into an `Exit` and capture schema
1922 * mismatches as `SchemaError`.
1923 *
1924 * **Details**
1925 *
1926 * Only usable with schemas that have no `EncodingServices` requirement. Prefer
1927 * {@link encodeExit} when the value is already typed as the schema's `Type`.
1928 * Options may be provided either when creating the encoder or when applying it;
1929 * application options override creation options.
1930 * Schema mismatches are represented by a `Failure` cause containing
1931 * `SchemaError`.
1932 *
1933 * **Gotchas**
1934 *
1935 * Schema issue fail reasons are wrapped as `SchemaError`. Defects,
1936 * interruptions, and other non-schema reasons remain in the returned `Cause`,
1937 * including when they are mixed with schema issues.
1938 *
1939 * @see {@link SchemaParser.encodeUnknownExit} for the adapter whose failure contains `SchemaIssue.Issue` directly
1940 *
1941 * @category encoding
1942 * @since 4.0.0
1943 */
1944export function encodeUnknownExit<S extends ConstraintEncoder<unknown>>(schema: S, options?: SchemaAST.ParseOptions) {
1945 const parser = SchemaParser.encodeUnknownExit(schema, options)
1946 return (input: unknown, options?: SchemaAST.ParseOptions): Exit_.Exit<S["Encoded"], SchemaError> => {
1947 return fromIssueExit(parser(input, options))
1948 }
1949}
1950/**
1951 * Encodes a typed input (the schema's `Type`) against a schema synchronously,
1952 * returning an `Exit` that is either a `Success` with the encoded value or a
1953 * `Failure`.
1954 *
1955 * **When to use**
1956 *
1957 * Use when you need to encode already typed schema values into an `Exit` and
1958 * capture schema mismatches as `SchemaError`.
1959 *
1960 * **Details**
1961 *
1962 * Only usable with schemas that have no `EncodingServices` requirement. For
1963 * `unknown` input use {@link encodeUnknownExit}.
1964 * Options may be provided either when creating the encoder or when applying it;
1965 * application options override creation options.
1966 * Schema mismatches are represented by a `Failure` cause containing
1967 * `SchemaError`.
1968 *
1969 * **Gotchas**
1970 *
1971 * Schema issue fail reasons are wrapped as `SchemaError`. Defects,
1972 * interruptions, and other non-schema reasons remain in the returned `Cause`,
1973 * including when they are mixed with schema issues.
1974 *
1975 * @see {@link SchemaParser.encodeExit} for the adapter whose failure contains `SchemaIssue.Issue` directly
1976 *
1977 * @category encoding
1978 * @since 4.0.0
1979 */
1980export const encodeExit: <S extends ConstraintEncoder<unknown>>(
1981 schema: S,
1982 options?: SchemaAST.ParseOptions
1983) => (input: S["Type"], options?: SchemaAST.ParseOptions) => Exit_.Exit<S["Encoded"], SchemaError> = encodeUnknownExit
1984/**
1985 * Encodes an `unknown` input against a schema, returning an `Option` that is
1986 * `Some` with the encoded value on success or `None` for schema mismatches.
1987 *
1988 * **When to use**
1989 *
1990 * Use when you do not know the input type statically and only need to know
1991 * whether encoding succeeded.
1992 *
1993 * **Details**
1994 *
1995 * Prefer this over {@link encodeUnknownExit} or {@link encodeUnknownEffect}
1996 * when you don't need error details. For values already typed as the schema's
1997 * `Type` use {@link encodeOption}.
1998 * Options may be provided either when creating the encoder or when applying it;
1999 * application options override creation options.
2000 *
2001 * **Gotchas**
2002 *
2003 * Only causes made entirely of schema issues are converted to `None`. Causes
2004 * that contain defects, interruptions, or other non-schema reasons throw
2005 * instead.
2006 *
2007 * @category encoding
2008 * @since 3.10.0
2009 */
2010export const encodeUnknownOption: <S extends ConstraintEncoder<unknown>>(
2011 schema: S,
2012 options?: SchemaAST.ParseOptions
2013) => (input: unknown, options?: SchemaAST.ParseOptions) => Option_.Option<S["Encoded"]> =
2014 SchemaParser.encodeUnknownOption
2015/**
2016 * Encodes a typed input (the schema's `Type`) against a schema, returning an
2017 * `Option` that is `Some` with the encoded value on success or `None` for schema
2018 * mismatches.
2019 *
2020 * **When to use**
2021 *
2022 * Use when you already have a value typed as the schema's `Type` and only need
2023 * to know whether encoding succeeded.
2024 *
2025 * **Details**
2026 *
2027 * For `unknown` input use {@link encodeUnknownOption}.
2028 * Options may be provided either when creating the encoder or when applying it;
2029 * application options override creation options.
2030 *
2031 * **Gotchas**
2032 *
2033 * Only causes made entirely of schema issues are converted to `None`. Causes
2034 * that contain defects, interruptions, or other non-schema reasons throw
2035 * instead.
2036 *
2037 * @category encoding
2038 * @since 3.10.0
2039 */
2040export const encodeOption: <S extends ConstraintEncoder<unknown>>(
2041 schema: S,
2042 options?: SchemaAST.ParseOptions
2043) => (input: S["Type"], options?: SchemaAST.ParseOptions) => Option_.Option<S["Encoded"]> = SchemaParser.encodeOption
2044/**
2045 * Encodes an `unknown` input against a schema, returning a `Result` that
2046 * succeeds with the encoded value or fails with a {@link SchemaError} for schema
2047 * mismatches.
2048 *
2049 * **When to use**
2050 *
2051 * Use when you do not know the input type statically and want schema mismatches
2052 * returned as `Result.fail` with `SchemaError`.
2053 *
2054 * **Details**
2055 *
2056 * For values already typed as the schema's `Type` use {@link encodeResult}.
2057 * Options may be provided either when creating the encoder or when applying it;
2058 * application options override creation options.
2059 * Schema mismatches are returned as `Result.fail` with `SchemaError`.
2060 *
2061 * **Gotchas**
2062 *
2063 * Only causes made entirely of schema issues are returned as `Result.fail`.
2064 * Causes that contain defects, interruptions, or other non-schema reasons throw
2065 * instead.
2066 *
2067 * @see {@link SchemaParser.encodeUnknownResult} for the adapter that fails with `SchemaIssue.Issue` directly
2068 *
2069 * @category encoding
2070 * @since 4.0.0
2071 */
2072export function encodeUnknownResult<S extends ConstraintEncoder<unknown>>(schema: S, options?: SchemaAST.ParseOptions) {
2073 const parser = SchemaParser.encodeUnknownResult(schema, options)
2074 return (input: unknown, options?: SchemaAST.ParseOptions): Result_.Result<S["Encoded"], SchemaError> => {
2075 return Result_.mapError(parser(input, options), (issue) => new SchemaError(issue))
2076 }
2077}
2078/**
2079 * Encodes a typed input (the schema's `Type`) against a schema, returning a
2080 * `Result` that succeeds with the encoded value or fails with a
2081 * {@link SchemaError} for schema mismatches.
2082 *
2083 * **When to use**
2084 *
2085 * Use when you already have a value typed as the schema's `Type` and want schema
2086 * mismatches returned as `Result.fail` with `SchemaError`.
2087 *
2088 * **Details**
2089 *
2090 * For `unknown` input use {@link encodeUnknownResult}.
2091 * Options may be provided either when creating the encoder or when applying it;
2092 * application options override creation options.
2093 * Schema mismatches are returned as `Result.fail` with `SchemaError`.
2094 *
2095 * **Gotchas**
2096 *
2097 * Only causes made entirely of schema issues are returned as `Result.fail`.
2098 * Causes that contain defects, interruptions, or other non-schema reasons throw
2099 * instead.
2100 *
2101 * @see {@link SchemaParser.encodeResult} for the adapter that fails with `SchemaIssue.Issue` directly
2102 *
2103 * @category encoding
2104 * @since 4.0.0
2105 */
2106export const encodeResult: <S extends ConstraintEncoder<unknown>>(
2107 schema: S,
2108 options?: SchemaAST.ParseOptions
2109) => (input: S["Type"], options?: SchemaAST.ParseOptions) => Result_.Result<S["Encoded"], SchemaError> =
2110 encodeUnknownResult
2111/**
2112 * Encodes an `unknown` input against a schema, returning a `Promise` that
2113 * resolves with the encoded value or rejects with a {@link SchemaError} for
2114 * schema mismatches.
2115 *
2116 * **When to use**
2117 *
2118 * Use when you need encoding of unknown input to return a JavaScript `Promise`
2119 * that rejects with `SchemaError` for schema mismatches.
2120 *
2121 * **Details**
2122 *
2123 * For values already typed as the schema's `Type` use {@link encodePromise}.
2124 * Options may be provided either when creating the encoder or when applying it;
2125 * application options override creation options.
2126 *
2127 * **Gotchas**
2128 *
2129 * Non-schema failures may reject with a runtime failure instead of
2130 * `SchemaError`.
2131 *
2132 * @see {@link SchemaParser.encodeUnknownPromise} for the adapter that rejects with an `Error` whose cause is `SchemaIssue.Issue`
2133 *
2134 * @category encoding
2135 * @since 3.10.0
2136 */
2137export function encodeUnknownPromise<S extends ConstraintEncoder<unknown>>(
2138 schema: S,
2139 options?: SchemaAST.ParseOptions
2140) {
2141 const parser = encodeUnknownEffect(schema, options)
2142 return (input: unknown, options?: SchemaAST.ParseOptions): Promise<S["Encoded"]> => {
2143 return runSchemaErrorPromise(parser(input, options))
2144 }
2145}
2146/**
2147 * Encodes a typed input (the schema's `Type`) against a schema, returning a
2148 * `Promise` that resolves with the encoded value or rejects with a
2149 * {@link SchemaError} for schema mismatches.
2150 *
2151 * **When to use**
2152 *
2153 * Use when you already have a value typed as the schema's `Type` and need
2154 * encoding to return a JavaScript `Promise` that rejects with `SchemaError` for
2155 * schema mismatches.
2156 *
2157 * **Details**
2158 *
2159 * For `unknown` input use {@link encodeUnknownPromise}.
2160 * Options may be provided either when creating the encoder or when applying it;
2161 * application options override creation options.
2162 *
2163 * **Gotchas**
2164 *
2165 * Non-schema failures may reject with a runtime failure instead of
2166 * `SchemaError`.
2167 *
2168 * @see {@link SchemaParser.encodePromise} for the adapter that rejects with an `Error` whose cause is `SchemaIssue.Issue`
2169 *
2170 * @category encoding
2171 * @since 3.10.0
2172 */
2173export const encodePromise: <S extends ConstraintEncoder<unknown>>(
2174 schema: S,
2175 options?: SchemaAST.ParseOptions
2176) => (input: S["Type"], options?: SchemaAST.ParseOptions) => Promise<S["Encoded"]> = encodeUnknownPromise
2177/**
2178 * Encodes an `unknown` input against a schema synchronously, throwing a
2179 * {@link SchemaError} for schema mismatches.
2180 *
2181 * **When to use**
2182 *
2183 * Use when you need to serialize unknown data at a synchronous boundary and
2184 * want schema mismatches to throw `SchemaError`.
2185 *
2186 * **Details**
2187 *
2188 * For alternatives that do not throw on schema mismatches, see
2189 * {@link encodeUnknownOption}, {@link encodeUnknownExit}, or
2190 * {@link encodeUnknownEffect}. For values already typed as the schema's `Type`
2191 * use {@link encodeSync}. Options may be provided either when creating the
2192 * encoder or when applying it; application options override creation options.
2193 *
2194 * **Gotchas**
2195 *
2196 * Non-schema failures may throw a runtime failure instead of `SchemaError`.
2197 *
2198 * @see {@link SchemaParser.encodeUnknownSync} for the adapter that throws an `Error` whose cause is `SchemaIssue.Issue`
2199 *
2200 * @category encoding
2201 * @since 4.0.0
2202 */
2203export function encodeUnknownSync<S extends ConstraintEncoder<unknown>>(schema: S, options?: SchemaAST.ParseOptions) {
2204 const parser = encodeUnknownEffect(schema, options)
2205 return (input: unknown, options?: SchemaAST.ParseOptions): S["Encoded"] => {
2206 return runSchemaErrorSync(parser(input, options) as Effect.Effect<S["Encoded"], SchemaError>)
2207 }
2208}
2209/**
2210 * Encodes a typed input (the schema's `Type`) against a schema synchronously,
2211 * throwing a {@link SchemaError} for schema mismatches.
2212 *
2213 * **When to use**
2214 *
2215 * Use when you already have a value typed as the schema's `Type` and want
2216 * schema mismatches to throw `SchemaError` synchronously.
2217 *
2218 * **Details**
2219 *
2220 * For `unknown` input use {@link encodeUnknownSync}.
2221 * Options may be provided either when creating the encoder or when applying it;
2222 * application options override creation options.
2223 *
2224 * **Gotchas**
2225 *
2226 * Non-schema failures may throw a runtime failure instead of `SchemaError`.
2227 *
2228 * @see {@link SchemaParser.encodeSync} for the adapter that throws an `Error` whose cause is `SchemaIssue.Issue`
2229 *
2230 * @category encoding
2231 * @since 4.0.0
2232 */
2233export const encodeSync: <S extends ConstraintEncoder<unknown>>(
2234 schema: S,
2235 options?: SchemaAST.ParseOptions
2236) => (input: S["Type"], options?: SchemaAST.ParseOptions) => S["Encoded"] = encodeUnknownSync
2237/**
2238 * Creates a schema from an AST (Abstract Syntax Tree) node.
2239 *
2240 * **Details**
2241 *
2242 * This is the fundamental constructor for all schemas in the Effect Schema
2243 * library. It takes an AST node and wraps it in a fully-typed schema that
2244 * preserves all type information and provides the complete schema API.
2245 *
2246 * The `make` function is used internally to create all primitive schemas like
2247 * `String`, `Number`, `Boolean`, etc., as well as more complex schemas. It's
2248 * the bridge between the untyped AST representation and the strongly-typed
2249 * schema.
2250 *
2251 * @category constructors
2252 * @since 3.10.0
2253 */
2254export const make: <S extends Constraint>(ast: S["ast"], options?: object) => S = InternalMake.make
2255/**
2256 * Checks whether a value is a `Schema`.
2257 *
2258 * @category guards
2259 * @since 3.10.0
2260 */
2261export function isSchema(u: unknown): u is Top {
2262 return Predicate.hasProperty(u, TypeId) && u[TypeId] === TypeId
2263}
2264/**
2265 * Type-level representation returned by {@link optionalKey}.
2266 *
2267 * @category models
2268 * @since 4.0.0
2269 */
2270export interface optionalKey<S extends Constraint> extends
2271 BottomLazy<
2272 S["ast"],
2273 optionalKey<S>,
2274 S["~type.parameters"],
2275 S["~type.mutability"],
2276 "optional",
2277 S["~type.constructor.default"],
2278 S["~encoded.mutability"],
2279 "optional"
2280 >
2281{
2282 readonly "Type": S["Type"]
2283 readonly "Encoded": S["Encoded"]
2284 readonly "DecodingServices": S["DecodingServices"]
2285 readonly "EncodingServices": S["EncodingServices"]
2286 readonly "~type.make.in": S["~type.make.in"]
2287 readonly "~type.make": S["~type.make"]
2288 readonly "Iso": S["Iso"]
2289 readonly schema: S
2290}
2291interface optionalKeyLambda extends Lambda {
2292 <S extends Constraint>(self: S): optionalKey<S>
2293 readonly "~lambda.out": this["~lambda.in"] extends Constraint ? optionalKey<this["~lambda.in"]> : never
2294}
2295/**
2296 * Creates an exact optional key schema for struct fields. Unlike `optional`,
2297 * this creates exact optional properties (not `| undefined`) that can be
2298 * completely omitted from the object.
2299 *
2300 * **Example** (Creating a struct with optional key)
2301 *
2302 * ```ts import.meta.vitest
2303 * import { Schema } from "effect"
2304 *
2305 * const schema = Schema.Struct({
2306 * name: Schema.String,
2307 * age: Schema.optionalKey(Schema.Number)
2308 * })
2309 *
2310 * // Type: { readonly name: string; readonly age?: number }
2311 * type Person = typeof schema["Type"]
2312 * ```
2313 *
2314 * @category combinators
2315 * @since 4.0.0
2316 */
2317export const optionalKey: optionalKeyLambda = Struct_.lambda<optionalKeyLambda>((schema) =>
2318 make(SchemaAST.optionalKey(schema.ast), { schema })
2319)
2320interface requiredKeyLambda extends Lambda {
2321 <S extends Constraint>(self: optionalKey<S>): S
2322 readonly "~lambda.out": this["~lambda.in"] extends optionalKey<Constraint> ? this["~lambda.in"]["schema"]
2323 : "Error: schema not eligible for requiredKey"
2324}
2325/**
2326 * Reverses `optionalKey` and returns the inner required schema.
2327 *
2328 * **When to use**
2329 *
2330 * Use to remove optional-key wrapping from a schema field that was previously
2331 * wrapped with {@link optionalKey}.
2332 *
2333 * @category combinators
2334 * @since 4.0.0
2335 */
2336export const requiredKey: requiredKeyLambda = Struct_.lambda<requiredKeyLambda>((self) => self.schema)
2337/**
2338 * Type-level representation returned by {@link optional}.
2339 *
2340 * @category models
2341 * @since 3.10.0
2342 */
2343export interface optional<S extends Constraint> extends optionalKey<UndefinedOr<S>> {
2344 readonly "Rebuild": optional<S>
2345}
2346interface optionalLambda extends Lambda {
2347 <S extends Constraint>(self: S): optional<S>
2348 readonly "~lambda.out": this["~lambda.in"] extends Constraint ? optional<this["~lambda.in"]> : never
2349}
2350/**
2351 * Marks a struct field as optional, allowing the key to be absent or
2352 * `undefined`.
2353 *
2354 * **Details**
2355 *
2356 * The resulting property may be absent or explicitly set to `undefined`.
2357 * Equivalent to `optionalKey(UndefinedOr(S))`.
2358 *
2359 * Use {@link optionalKey} instead if you want exact optional semantics (absent
2360 * only, not `undefined`).
2361 *
2362 * **Example** (Defining an optional field accepting undefined)
2363 *
2364 * ```ts import.meta.vitest
2365 * import { Schema } from "effect"
2366 *
2367 * const schema = Schema.Struct({
2368 * name: Schema.String,
2369 * age: Schema.optional(Schema.Number)
2370 * })
2371 *
2372 * // { readonly name: string; readonly age?: number | undefined }
2373 * type Person = typeof schema.Type
2374 * ```
2375 *
2376 * @category combinators
2377 * @since 3.10.0
2378 */
2379export const optional: optionalLambda = Struct_.lambda<optionalLambda>((self) => {
2380 const schema = UndefinedOr(self)
2381 return make(SchemaAST.optional(self.ast), { schema })
2382})
2383interface requiredLambda extends Lambda {
2384 <S extends Constraint>(self: optional<S>): S
2385 readonly "~lambda.out": this["~lambda.in"] extends optional<Constraint> ? this["~lambda.in"]["schema"]["members"][0]
2386 : "Error: schema not eligible for required"
2387}
2388/**
2389 * Reverses `optional` and returns the inner schema.
2390 *
2391 * **When to use**
2392 *
2393 * Use to remove optional wrapping from a schema field that was previously
2394 * wrapped with {@link optional}.
2395 *
2396 * **Details**
2397 *
2398 * This also unwraps the `UndefinedOr` member added by `optional`.
2399 *
2400 * @category combinators
2401 * @since 3.10.0
2402 */
2403export const required: requiredLambda = Struct_.lambda<requiredLambda>((self) => self.schema.members[0])
2404/**
2405 * Type-level representation returned by {@link mutableKey}.
2406 *
2407 * @category models
2408 * @since 4.0.0
2409 */
2410export interface mutableKey<S extends Constraint> extends
2411 BottomLazy<
2412 S["ast"],
2413 mutableKey<S>,
2414 S["~type.parameters"],
2415 "mutable",
2416 S["~type.optionality"],
2417 S["~type.constructor.default"],
2418 "mutable",
2419 S["~encoded.optionality"]
2420 >
2421{
2422 readonly "Type": S["Type"]
2423 readonly "Encoded": S["Encoded"]
2424 readonly "DecodingServices": S["DecodingServices"]
2425 readonly "EncodingServices": S["EncodingServices"]
2426 readonly "~type.make.in": S["~type.make.in"]
2427 readonly "~type.make": S["~type.make"]
2428 readonly "Iso": S["Iso"]
2429 readonly schema: S
2430}
2431interface mutableKeyLambda extends Lambda {
2432 <S extends Constraint>(self: S): mutableKey<S>
2433 readonly "~lambda.out": this["~lambda.in"] extends Constraint ? mutableKey<this["~lambda.in"]> : never
2434}
2435/**
2436 * Makes a struct field mutable (removes the `readonly` modifier on the property).
2437 * Use {@link readonlyKey} to reverse.
2438 *
2439 * @category combinators
2440 * @since 4.0.0
2441 */
2442export const mutableKey: mutableKeyLambda = Struct_.lambda<mutableKeyLambda>((schema) =>
2443 make(SchemaAST.mutableKey(schema.ast), { schema })
2444)
2445interface readonlyKeyLambda extends Lambda {
2446 <S extends Constraint>(self: mutableKey<S>): S
2447 readonly "~lambda.out": this["~lambda.in"] extends mutableKey<Constraint> ? this["~lambda.in"]["schema"]
2448 : "Error: schema not eligible for readonlyKey"
2449}
2450/**
2451 * Reverses `mutableKey` and returns the inner readonly schema.
2452 *
2453 * **When to use**
2454 *
2455 * Use to remove mutable-key wrapping from a schema field that was previously
2456 * wrapped with {@link mutableKey}.
2457 *
2458 * @category combinators
2459 * @since 4.0.0
2460 */
2461export const readonlyKey: readonlyKeyLambda = Struct_.lambda<readonlyKeyLambda>((self) => self.schema)
2462/**
2463 * Type-level representation returned by {@link toType}.
2464 *
2465 * @category transforming
2466 * @since 4.0.0
2467 */
2468export interface toType<S extends Constraint> extends
2469 BottomLazy<
2470 S["ast"],
2471 toType<S>,
2472 S["~type.parameters"],
2473 S["~type.mutability"],
2474 S["~type.optionality"],
2475 S["~type.constructor.default"],
2476 S["~encoded.mutability"],
2477 S["~encoded.optionality"]
2478 >
2479{
2480 readonly "Type": S["Type"]
2481 readonly "Encoded": S["Type"]
2482 readonly "DecodingServices": never
2483 readonly "EncodingServices": never
2484 readonly "~type.make.in": S["~type.make.in"]
2485 readonly "~type.make": S["~type.make"]
2486 readonly "Iso": S["Iso"]
2487 readonly schema: S
2488}
2489interface toTypeLambda extends Lambda {
2490 <S extends Constraint>(self: S): toType<S>
2491 readonly "~lambda.out": this["~lambda.in"] extends Constraint ? toType<this["~lambda.in"]> : never
2492}
2493/**
2494 * Extracts the type-side schema: sets `Encoded` to equal the decoded `Type`,
2495 * discarding the encoding transformation path.
2496 *
2497 * @category transforming
2498 * @since 4.0.0
2499 */
2500export const toType: toTypeLambda = Struct_.lambda<toTypeLambda>((schema) =>
2501 make(SchemaAST.toType(schema.ast), { schema })
2502)
2503/**
2504 * Type-level representation returned by {@link toEncoded}.
2505 *
2506 * @category transforming
2507 * @since 4.0.0
2508 */
2509export interface toEncoded<S extends Constraint> extends
2510 BottomLazy<
2511 SchemaAST.AST,
2512 toEncoded<S>,
2513 ReadonlyArray<Constraint>,
2514 S["~type.mutability"],
2515 S["~type.optionality"],
2516 S["~type.constructor.default"],
2517 S["~encoded.mutability"],
2518 S["~encoded.optionality"]
2519 >
2520{
2521 readonly "Type": S["Encoded"]
2522 readonly "Encoded": S["Encoded"]
2523 readonly "DecodingServices": never
2524 readonly "EncodingServices": never
2525 readonly "~type.make.in": S["Encoded"]
2526 readonly "~type.make": S["Encoded"]
2527 readonly "Iso": S["Encoded"]
2528 readonly schema: S
2529}
2530interface toEncodedLambda extends Lambda {
2531 <S extends Constraint>(self: S): toEncoded<S>
2532 readonly "~lambda.out": this["~lambda.in"] extends Constraint ? toEncoded<this["~lambda.in"]> : never
2533}
2534/**
2535 * Extracts the encoded-side schema: sets `Type` to equal the `Encoded`,
2536 * discarding the decoding transformation path.
2537 *
2538 * @category transforming
2539 * @since 4.0.0
2540 */
2541export const toEncoded: toEncodedLambda = Struct_.lambda<toEncodedLambda>((schema) =>
2542 make(SchemaAST.toEncoded(schema.ast), { schema })
2543)
2544const FlipTypeId = "~effect/Schema/flip"
2545/**
2546 * Type-level representation returned by {@link flip}.
2547 *
2548 * @category transforming
2549 * @since 4.0.0
2550 */
2551export interface flip<S extends Top> extends
2552 BottomLazy<
2553 SchemaAST.AST,
2554 flip<S>,
2555 ReadonlyArray<Constraint>,
2556 S["~encoded.mutability"],
2557 S["~encoded.optionality"],
2558 ConstructorDefault,
2559 S["~type.mutability"],
2560 S["~type.optionality"]
2561 >
2562{
2563 readonly "Type": S["Encoded"]
2564 readonly "Encoded": S["Type"]
2565 readonly "DecodingServices": S["EncodingServices"]
2566 readonly "EncodingServices": S["DecodingServices"]
2567 readonly "~type.make.in": S["Encoded"]
2568 readonly "~type.make": S["Encoded"]
2569 readonly "Iso": S["Encoded"]
2570 readonly [FlipTypeId]: typeof FlipTypeId
2571 readonly schema: S
2572}
2573
2574function isFlip$(schema: Top): schema is flip<any> {
2575 return Predicate.hasProperty(schema, FlipTypeId) && schema[FlipTypeId] === FlipTypeId
2576}
2577/**
2578 * Swaps the decoded and encoded sides of a schema.
2579 *
2580 * **When to use**
2581 *
2582 * Use to invert a schema transformation direction.
2583 *
2584 * **Details**
2585 *
2586 * Calling `flip` twice returns the original schema.
2587 *
2588 * **Example** (Flipping a number-from-string schema)
2589 *
2590 * ```ts import.meta.vitest
2591 * import { Schema } from "effect"
2592 *
2593 * // NumberFromString: decodes string → number
2594 * const flipped = Schema.flip(Schema.NumberFromString)
2595 * Schema.decodeSync(flipped)(42) // => "42"
2596 * ```
2597 *
2598 * @category transforming
2599 * @since 4.0.0
2600 */
2601export function flip<S extends Top>(schema: S): S extends flip<infer F> ? F["Rebuild"] : flip<S>
2602export function flip<S extends Top>(schema: S): flip<S> {
2603 if (isFlip$(schema)) {
2604 return schema.schema.rebuild(SchemaAST.flip(schema.ast))
2605 }
2606 return make(SchemaAST.flip(schema.ast), { [FlipTypeId]: FlipTypeId, schema })
2607}
2608/**
2609 * Type-level representation returned by {@link Literal}.
2610 *
2611 * @category models
2612 * @since 3.10.0
2613 */
2614export interface Literal<L extends SchemaAST.LiteralValue>
2615 extends Bottom<L, L, never, never, SchemaAST.Literal, Literal<L>>
2616{
2617 readonly literal: L
2618 transform<L2 extends SchemaAST.LiteralValue>(to: L2): decodeTo<Literal<L2>, Literal<L>>
2619}
2620/**
2621 * Creates a schema for a single literal value (string, number, bigint, boolean, or null).
2622 *
2623 * **Example** (Defining a string literal)
2624 *
2625 * ```ts import.meta.vitest
2626 * import { Schema } from "effect"
2627 *
2628 * const schema = Schema.Literal("hello")
2629 * // Type: Schema.Literal<"hello">
2630 * Schema.decodeSync(schema)("hello") // => "hello"
2631 * ```
2632 *
2633 * @see {@link Literals} for a schema that represents a union of literals.
2634 * @see {@link tag} for a schema that represents a literal value that can be
2635 * used as a discriminator field in tagged unions and has a constructor default.
2636 * @category constructors
2637 * @since 3.10.0
2638 */
2639export function Literal<L extends SchemaAST.LiteralValue>(literal: L): Literal<L> {
2640 const out = make<Literal<L>>(new SchemaAST.Literal(literal), {
2641 literal,
2642 transform<L2 extends SchemaAST.LiteralValue>(to: L2): decodeTo<Literal<L2>, Literal<L>> {
2643 return out.pipe(decodeTo(Literal(to), {
2644 decode: SchemaGetter.transform(() => to),
2645 encode: SchemaGetter.transform(() => literal)
2646 }))
2647 }
2648 })
2649 return out
2650}
2651/**
2652 * Namespace for {@link TemplateLiteral} helper types.
2653 *
2654 * @since 3.10.0
2655 */
2656export declare namespace TemplateLiteral {
2657 /**
2658 * Constraint for schema parts that can appear inside a `TemplateLiteral`.
2659 *
2660 * **Details**
2661 *
2662 * The schema's encoded value must be a `string`, `number`, or `bigint` so it can
2663 * be converted into a template literal string segment.
2664 * `TemplateLiteral` additionally rejects encodings at runtime;
2665 * `TemplateLiteralParser` supports transformed parts.
2666 *
2667 * @category utility types
2668 * @since 4.0.0
2669 */
2670 interface SchemaPart extends Constraint {
2671 readonly Encoded: string | number | bigint
2672 }
2673 /**
2674 * Literal value that can be used directly as a part of a `TemplateLiteral`.
2675 *
2676 * @category utility types
2677 * @since 4.0.0
2678 */
2679 type LiteralPart = string | number | bigint
2680 /**
2681 * A single part of a `TemplateLiteral`, either an interpolated schema part or a
2682 * literal `string`, `number`, or `bigint`.
2683 *
2684 * @category utility types
2685 * @since 4.0.0
2686 */
2687 type Part = SchemaPart | LiteralPart
2688 /**
2689 * Ordered list of parts used to construct a `TemplateLiteral` schema.
2690 *
2691 * @category utility types
2692 * @since 4.0.0
2693 */
2694 type Parts = ReadonlyArray<Part>
2695 type AppendType<Template extends string, Next> = Next extends LiteralPart ? `${Template}${Next}` : Next extends {
2696 readonly Encoded: infer E extends LiteralPart
2697 } ? `${Template}${E}` :
2698 never
2699 /**
2700 * Computes the encoded string literal type produced by concatenating the encoded
2701 * forms of all template literal parts.
2702 *
2703 * @category utility types
2704 * @since 3.10.0
2705 */
2706 type Encoded<Parts> = Parts extends readonly [...infer Init, infer Last] ? AppendType<Encoded<Init>, Last> : ``
2707}
2708/**
2709 * Type-level representation returned by {@link TemplateLiteral}.
2710 *
2711 * @category models
2712 * @since 3.10.0
2713 */
2714export interface TemplateLiteral<Parts extends TemplateLiteral.Parts> extends
2715 Bottom<
2716 TemplateLiteral.Encoded<Parts>,
2717 TemplateLiteral.Encoded<Parts>,
2718 never,
2719 never,
2720 SchemaAST.TemplateLiteral,
2721 TemplateLiteral<Parts>
2722 >
2723{
2724 readonly parts: Parts
2725}
2726
2727function templateLiteralParts(parts: TemplateLiteral.Parts) {
2728 return parts.map((part) => isSchema(part) ? part.ast : new SchemaAST.Literal(part as TemplateLiteral.LiteralPart))
2729}
2730/**
2731 * Creates a schema that validates strings by matching ordered template literal
2732 * parts.
2733 *
2734 * **When to use**
2735 *
2736 * Use when the decoded value should remain the matched string and you do not
2737 * need the individual template parts parsed into a tuple.
2738 *
2739 * **Details**
2740 *
2741 * Each part can be a literal `string`, `number`, or `bigint`, or a schema whose
2742 * encoded type is `string`, `number`, or `bigint`. Checks on string, number,
2743 * and bigint schema parts are applied while matching each segment.
2744 *
2745 * **Gotchas**
2746 *
2747 * Parts must not contain encodings, including inside unions or nested templates.
2748 * Construction throws for transformed parts even when their decoded and encoded
2749 * types are the same. Use {@link TemplateLiteralParser} to decode transformed parts.
2750 * Brands and supported checks without encodings remain valid.
2751 *
2752 * **Example** (Defining a URL path pattern)
2753 *
2754 * ```ts import.meta.vitest
2755 * import { Schema } from "effect"
2756 *
2757 * const schema = Schema.TemplateLiteral(["/user/", Schema.Number])
2758 * Schema.is(schema)("/user/123") // => true
2759 * ```
2760 *
2761 * @see {@link TemplateLiteralParser} for a schema that also parses matched parts into a tuple.
2762 * @category constructors
2763 * @since 3.10.0
2764 */
2765export function TemplateLiteral<const Parts extends TemplateLiteral.Parts>(parts: Parts): TemplateLiteral<Parts> {
2766 return make(new SchemaAST.TemplateLiteral(templateLiteralParts(parts)), { parts })
2767}
2768/**
2769 * Namespace for {@link TemplateLiteralParser} helper types.
2770 *
2771 * @since 3.10.0
2772 */
2773export declare namespace TemplateLiteralParser {
2774 /**
2775 * Computes the decoded tuple type produced by `TemplateLiteralParser`.
2776 *
2777 * **Details**
2778 *
2779 * Literal parts contribute their literal value to the tuple. Schema parts
2780 * contribute their decoded `Type`.
2781 *
2782 * @category utility types
2783 * @since 3.10.0
2784 */
2785 type Type<Parts> = Parts extends readonly [infer Head, ...infer Tail] ? readonly [
2786 Head extends TemplateLiteral.LiteralPart ? Head : Head extends ConstraintDecoder<infer T, unknown> ? T : never,
2787 ...Type<Tail>
2788 ] :
2789 []
2790}
2791/**
2792 * Type-level representation returned by {@link TemplateLiteralParser}.
2793 *
2794 * @category models
2795 * @since 3.10.0
2796 */
2797export interface TemplateLiteralParser<Parts extends TemplateLiteral.Parts> extends
2798 BottomLazy<
2799 SchemaAST.Arrays,
2800 TemplateLiteralParser<Parts>
2801 >
2802{
2803 readonly "Type": TemplateLiteralParser.Type<Parts>
2804 readonly "Encoded": TemplateLiteral.Encoded<Parts>
2805 readonly "DecodingServices": Extract<Parts[number], Constraint>["DecodingServices"]
2806 readonly "EncodingServices": Extract<Parts[number], Constraint>["EncodingServices"]
2807 readonly "~type.make.in": TemplateLiteralParser.Type<Parts>
2808 readonly "~type.make": TemplateLiteralParser.Type<Parts>
2809 readonly "Iso": TemplateLiteralParser.Type<Parts>
2810 readonly parts: Parts
2811}
2812/**
2813 * Schema for parsing matched template literal strings into typed tuple parts.
2814 *
2815 * **When to use**
2816 *
2817 * Use to validate a template literal string and decode the matched parts into
2818 * typed values.
2819 *
2820 * **Details**
2821 *
2822 * Unlike {@link TemplateLiteral}, this schema decodes the matched string into a
2823 * readonly tuple with one element per schema part. Checks on string, number,
2824 * and bigint schema parts are applied while matching each segment.
2825 * The source template uses the encoded sides of the parts; the tuple retains
2826 * their transformations, checks, and decoding and encoding service requirements.
2827 *
2828 * **Gotchas**
2829 *
2830 * Ambiguous templates use greedy segmentation with backtracking. Encoding a
2831 * tuple and decoding the resulting string can therefore produce a different
2832 * tuple when a segment contains a separator used by the template.
2833 *
2834 * **Example** (Parsing path parameters)
2835 *
2836 * ```ts import.meta.vitest
2837 * import { Schema } from "effect"
2838 *
2839 * const schema = Schema.TemplateLiteralParser(["/user/", Schema.NumberFromString])
2840 * Schema.decodeSync(schema)("/user/42") // => ["/user/", 42]
2841 * ```
2842 *
2843 * @see {@link TemplateLiteral} for a validation-only version that keeps the string encoded.
2844 * @category constructors
2845 * @since 3.10.0
2846 */
2847export function TemplateLiteralParser<const Parts extends TemplateLiteral.Parts>(
2848 parts: Parts
2849): TemplateLiteralParser<Parts> {
2850 return make(SchemaAST.templateLiteralParser(templateLiteralParts(parts)), { parts })
2851}
2852/**
2853 * Type-level representation returned by {@link Enum}.
2854 *
2855 * @category models
2856 * @since 4.0.0
2857 */
2858export interface Enum<A extends { [x: string]: string | number }>
2859 extends Bottom<A[keyof A], A[keyof A], never, never, SchemaAST.Enum, Enum<A>>
2860{
2861 readonly enums: A
2862}
2863/**
2864 * Creates a schema from a TypeScript enum object. Validates that the input is one of the enum's values.
2865 * Numeric enum values must be finite.
2866 *
2867 * **Gotchas**
2868 *
2869 * Throws when a numeric member is `NaN`, `Infinity`, or `-Infinity`.
2870 *
2871 * **Example** (Defining a direction enum)
2872 *
2873 * ```ts import.meta.vitest
2874 * import { Schema } from "effect"
2875 *
2876 * enum Direction {
2877 * Up = "Up",
2878 * Down = "Down"
2879 * }
2880 *
2881 * const schema = Schema.Enum(Direction)
2882 * Schema.decodeSync(schema)(Direction.Up) // => "Up"
2883 * ```
2884 *
2885 * @category constructors
2886 * @since 4.0.0
2887 */
2888export function Enum<A extends { [x: string]: string | number }>(enums: A): Enum<A> {
2889 return make(
2890 new SchemaAST.Enum(
2891 Object.keys(enums).filter(
2892 (key) => typeof enums[enums[key]] !== "number"
2893 ).map((key) => [key, enums[key]])
2894 ),
2895 { enums }
2896 )
2897}
2898/**
2899 * Type-level representation of {@link Never}.
2900 *
2901 * @category models
2902 * @since 3.10.0
2903 */
2904export interface Never extends Bottom<never, never, never, never, SchemaAST.Never, Never> {}
2905/**
2906 * Schema for the `never` type. Always fails validation — no value satisfies it.
2907 *
2908 * @category schemas
2909 * @since 3.10.0
2910 */
2911export const Never: Never = make(SchemaAST.never)
2912/**
2913 * Type-level representation of {@link Any}.
2914 *
2915 * @category models
2916 * @since 3.10.0
2917 */
2918export interface Any extends Bottom<any, any, never, never, SchemaAST.Any, Any> {}
2919/**
2920 * Schema for the `any` type. Accepts any value without validation.
2921 *
2922 * @see {@link Unknown} for a safer alternative that uses `unknown`.
2923 * @category schemas
2924 * @since 3.10.0
2925 */
2926export const Any: Any = make(SchemaAST.any)
2927/**
2928 * Type-level representation of {@link Unknown}.
2929 *
2930 * @category models
2931 * @since 3.10.0
2932 */
2933export interface Unknown extends Bottom<unknown, unknown, never, never, SchemaAST.Unknown, Unknown> {}
2934/**
2935 * Schema for the `unknown` type. Accepts any value without validation.
2936 *
2937 * **When to use**
2938 *
2939 * Use as a top schema when you need to accept any input while preserving
2940 * TypeScript's `unknown` safety at use sites.
2941 *
2942 * @see {@link Any} for the `any` variant.
2943 * @category schemas
2944 * @since 3.10.0
2945 */
2946export const Unknown: Unknown = make(SchemaAST.unknown)
2947/**
2948 * Type-level representation of {@link Null}.
2949 *
2950 * @category models
2951 * @since 3.10.0
2952 */
2953export interface Null extends Bottom<null, null, never, never, SchemaAST.Null, Null> {}
2954/**
2955 * Schema for the `null` literal. Validates that the input is strictly `null`.
2956 *
2957 * @see {@link NullOr} for a union with another schema.
2958 * @category schemas
2959 * @since 3.10.0
2960 */
2961export const Null: Null = make(SchemaAST.null)
2962/**
2963 * Type-level representation of {@link Undefined}.
2964 *
2965 * @category models
2966 * @since 3.10.0
2967 */
2968export interface Undefined extends Bottom<undefined, undefined, never, never, SchemaAST.Undefined, Undefined> {}
2969/**
2970 * Schema for the `undefined` literal. Validates that the input is strictly `undefined`.
2971 *
2972 * @see {@link UndefinedOr} for a union with another schema.
2973 * @category schemas
2974 * @since 3.10.0
2975 */
2976export const Undefined: Undefined = make(SchemaAST.undefined)
2977/**
2978 * Type-level representation of {@link String}.
2979 *
2980 * @category models
2981 * @since 4.0.0
2982 */
2983export interface String extends Bottom<string, string, never, never, SchemaAST.String, String> {}
2984/**
2985 * Schema for `string` values. Validates that the input is `typeof` `"string"`.
2986 *
2987 * @category schemas
2988 * @since 4.0.0
2989 */
2990export const String: String = make(SchemaAST.string)
2991
2992/**
2993 * Type-level representation of {@link StringForLiteralAutocomplete}.
2994 *
2995 * @category models
2996 * @since 4.0.0
2997 */
2998export interface StringForLiteralAutocomplete extends
2999 Bottom<
3000 string & {},
3001 string & {},
3002 never,
3003 never,
3004 SchemaAST.String,
3005 StringForLiteralAutocomplete
3006 >
3007{}
3008/**
3009 * Schema for `string & {}`. Validates that the input is `typeof` `"string"`.
3010 *
3011 * **When to use**
3012 *
3013 * Use with {@link Union} and {@link Literals} when a value may be any string
3014 * and known literals should stay available for editor autocomplete.
3015 *
3016 * **Details**
3017 *
3018 * `string & {}` stays alongside string literals in a union, so editors keep
3019 * suggesting those literals. Any string still passes validation. Read the
3020 * literals from the {@link Literals} member.
3021 *
3022 * **Example** (Suggesting known HTTP methods)
3023 *
3024 * ```ts import.meta.vitest
3025 * import { Schema } from "effect"
3026 *
3027 * const Method = Schema.Union([
3028 * Schema.StringForLiteralAutocomplete,
3029 * Schema.Literals(["GET", "POST"])
3030 * ])
3031 *
3032 * // Type: "GET" | "POST" | (string & {})
3033 * Method.make("PATCH") // => "PATCH"
3034 * Method.members[1].literals // => ["GET", "POST"]
3035 * ```
3036 *
3037 * @see {@link String} for a schema whose type is plain `string`.
3038 * @see {@link Literals} for the known literals to include in the union.
3039 * @category schemas
3040 * @since 4.0.0
3041 */
3042export const StringForLiteralAutocomplete: StringForLiteralAutocomplete = String
3043/**
3044 * Type-level representation of {@link Number}.
3045 *
3046 * @category models
3047 * @since 4.0.0
3048 */
3049export interface Number extends Bottom<number, number, never, never, SchemaAST.Number, Number> {}
3050/**
3051 * Schema for `number` values, including `NaN`, `Infinity`, and `-Infinity`.
3052 *
3053 * **Details**
3054 *
3055 * Default JSON serializer:
3056 *
3057 * - Finite numbers are serialized as numbers.
3058 * - Non-finite values are serialized as strings (`"NaN"`, `"Infinity"`, `"-Infinity"`).
3059 *
3060 * @see {@link Finite} for a schema that excludes non-finite values.
3061 * @category schemas
3062 * @since 4.0.0
3063 */
3064export const Number: Number = make(SchemaAST.number)
3065/**
3066 * Type-level representation of {@link Boolean}.
3067 *
3068 * @category models
3069 * @since 4.0.0
3070 */
3071export interface Boolean extends Bottom<boolean, boolean, never, never, SchemaAST.Boolean, Boolean> {}
3072/**
3073 * Schema for `boolean` values. Validates that the input is `typeof` `"boolean"`.
3074 *
3075 * **When to use**
3076 *
3077 * Use to validate values that are already JavaScript booleans.
3078 *
3079 * @see {@link BooleanFromBit} for a schema that decodes bit literals `0` or `1` into a boolean
3080 *
3081 * @category schemas
3082 * @since 4.0.0
3083 */
3084export const Boolean: Boolean = make(SchemaAST.boolean)
3085/**
3086 * Type-level representation of {@link Symbol}.
3087 *
3088 * @category models
3089 * @since 4.0.0
3090 */
3091export interface Symbol extends Bottom<symbol, symbol, never, never, SchemaAST.Symbol, Symbol> {}
3092/**
3093 * Schema for `symbol` values. Validates that the input is `typeof` `"symbol"`.
3094 *
3095 * @see {@link UniqueSymbol} for a schema that matches a specific symbol.
3096 * @category schemas
3097 * @since 4.0.0
3098 */
3099export const Symbol: Symbol = make(SchemaAST.symbol)
3100/**
3101 * Type-level representation of {@link BigInt}.
3102 *
3103 * @category models
3104 * @since 4.0.0
3105 */
3106export interface BigInt extends Bottom<bigint, bigint, never, never, SchemaAST.BigInt, BigInt> {}
3107/**
3108 * Schema for `bigint` values. Validates that the input is `typeof` `"bigint"`.
3109 *
3110 * **When to use**
3111 *
3112 * Use when the input is already a bigint and the schema should validate and
3113 * preserve bigint values without parsing from another representation.
3114 *
3115 * @see {@link BigIntFromString} for parsing string input into a bigint
3116 *
3117 * @category schemas
3118 * @since 4.0.0
3119 */
3120export const BigInt: BigInt = make(SchemaAST.bigInt)
3121/**
3122 * Type-level representation of {@link Void}.
3123 *
3124 * @category models
3125 * @since 3.10.0
3126 */
3127export interface Void extends Bottom<void, void, never, never, SchemaAST.Void, Void> {}
3128/**
3129 * Schema for a TypeScript `void` return value.
3130 *
3131 * **When to use**
3132 *
3133 * Use when you need to model the return value of a function, RPC, or endpoint
3134 * whose result is intentionally ignored.
3135 *
3136 * **Details**
3137 *
3138 * Runtime parsing accepts any present value and discards it, producing
3139 * `undefined`. The public decoded and encoded TypeScript representation remains
3140 * `void`, so typed construction, decoding, and encoding APIs are still modeled
3141 * as `void`.
3142 *
3143 * @see {@link Undefined} for a schema that matches only the exact `undefined` value.
3144 * @category schemas
3145 * @since 3.10.0
3146 */
3147export const Void: Void = make(SchemaAST.void)
3148/**
3149 * Type-level representation of {@link ObjectKeyword}.
3150 *
3151 * @category models
3152 * @since 4.0.0
3153 */
3154export interface ObjectKeyword extends Bottom<object, object, never, never, SchemaAST.ObjectKeyword, ObjectKeyword> {}
3155/**
3156 * Schema for the `object` type. Validates that the input is a non-null object or function
3157 * (i.e. `typeof value === "object" && value !== null || typeof value === "function"`).
3158 *
3159 * @category schemas
3160 * @since 4.0.0
3161 */
3162export const ObjectKeyword: ObjectKeyword = make(SchemaAST.objectKeyword)
3163/**
3164 * Type-level representation returned by {@link UniqueSymbol}.
3165 *
3166 * @category models
3167 * @since 4.0.0
3168 */
3169export interface UniqueSymbol<sym extends symbol>
3170 extends Bottom<sym, sym, never, never, SchemaAST.UniqueSymbol, UniqueSymbol<sym>>
3171{}
3172/**
3173 * Creates a schema for a specific symbol. Only that exact symbol satisfies the schema.
3174 *
3175 * **Gotchas**
3176 *
3177 * Only globally registered symbols have a JSON encoding. Their canonical JSON
3178 * form is the exact string returned by `String(symbol)`. A local symbol cannot
3179 * be encoded as JSON.
3180 *
3181 * **Example** (Defining a specific symbol)
3182 *
3183 * ```ts import.meta.vitest
3184 * import { Schema } from "effect"
3185 *
3186 * const mySymbol = Symbol.for("mySymbol")
3187 * const schema = Schema.UniqueSymbol(mySymbol)
3188 * Schema.decodeSync(schema)(mySymbol) === mySymbol // => true
3189 * ```
3190 *
3191 * @see {@link Symbol} for a schema that accepts any symbol.
3192 * @category constructors
3193 * @since 4.0.0
3194 */
3195export function UniqueSymbol<const sym extends symbol>(symbol: sym): UniqueSymbol<sym> {
3196 return make(new SchemaAST.UniqueSymbol(symbol))
3197}
3198/**
3199 * Namespace for struct field type utilities.
3200 *
3201 * **Details**
3202 *
3203 * These types compute the decoded `Type`, encoded `Encoded`, and constructor
3204 * input `MakeIn` of a {@link Struct} from its field map, handling optional,
3205 * mutable, and other field modifiers automatically.
3206 *
3207 * - `Struct.Fields` — constraint for the field map object
3208 * - `Struct.Type<F>` — decoded type of the struct
3209 * - `Struct.Encoded<F>` — encoded type of the struct
3210 * - `Struct.MakeIn<F>` — constructor input (optional/defaulted fields may be omitted)
3211 * - `Struct.DecodingServices<F>` / `Struct.EncodingServices<F>` — required services
3212 *
3213 * @since 3.10.0
3214 */
3215export declare namespace Struct {
3216 /**
3217 * Constraint for a struct field map: an object whose values are schemas.
3218 *
3219 * @category utility types
3220 * @since 3.10.0
3221 */
3222 type Fields = {
3223 readonly [x: PropertyKey]: Constraint
3224 }
3225 type TypeOptionalKeys<Fields extends Struct.Fields> = {
3226 [K in keyof Fields]: Fields[K] extends { readonly "~type.optionality": "optional" } ? K
3227 : never
3228 }[keyof Fields]
3229 type TypeMutableKeys<Fields extends Struct.Fields> = {
3230 [K in keyof Fields]: Fields[K] extends { readonly "~type.mutability": "mutable" } ? K
3231 : never
3232 }[keyof Fields]
3233 type SetOptional<A, K extends keyof A> = Omit<A, K> & Partial<Pick<A, K>>
3234 type Mutable<A> = { -readonly [K in keyof A]: A[K] }
3235 type SetMutable<A, K extends keyof A> = Omit<A, K> & Mutable<Pick<A, K>>
3236 type Side = "Type" | "Iso" | "Encoded"
3237 type EncodedOptionalKeys<Fields extends Struct.Fields> = {
3238 [K in keyof Fields]: Fields[K] extends { readonly "~encoded.optionality": "optional" } ? K
3239 : never
3240 }[keyof Fields]
3241 type EncodedMutableKeys<Fields extends Struct.Fields> = {
3242 [K in keyof Fields]: Fields[K] extends { readonly "~encoded.mutability": "mutable" } ? K
3243 : never
3244 }[keyof Fields]
3245 type SideOptionalKeys<F extends Fields, S extends Side> = S extends "Encoded" ? EncodedOptionalKeys<F>
3246 : TypeOptionalKeys<F>
3247 type SideMutableKeys<F extends Fields, S extends Side> = S extends "Encoded" ? EncodedMutableKeys<F>
3248 : TypeMutableKeys<F>
3249 type ReadonlySide<F extends Fields, S extends Side> = { readonly [K in keyof F]: F[K][S] }
3250 type View<
3251 F extends Fields,
3252 S extends Side,
3253 O extends keyof F = SideOptionalKeys<F, S>,
3254 M extends keyof F = SideMutableKeys<F, S>
3255 > = [O | M] extends [never] ? Simplify<ReadonlySide<F, S>>
3256 : [M] extends [never] ? Simplify<SetOptional<ReadonlySide<F, S>, O>>
3257 : [O] extends [never] ? Simplify<SetMutable<ReadonlySide<F, S>, M>>
3258 : Simplify<
3259 SetMutable<
3260 SetOptional<ReadonlySide<F, S>, O>,
3261 Extract<keyof SetOptional<ReadonlySide<F, S>, O>, M>
3262 >
3263 >
3264 /**
3265 * Computes the decoded object type for a struct field map.
3266 *
3267 * **Details**
3268 *
3269 * Field schemas contribute their decoded `Type`. `optionalKey` and `optional`
3270 * produce optional properties, while `mutableKey` produces writable properties.
3271 *
3272 * @category utility types
3273 * @since 3.10.0
3274 */
3275 type Type<F extends Fields> = View<F, "Type">
3276 /**
3277 * Computes the iso object type for a struct field map from each field schema's
3278 * `Iso` type.
3279 *
3280 * **Details**
3281 *
3282 * The resulting property optionality and mutability follow the same field
3283 * modifiers used by `Struct.Type`.
3284 *
3285 * @category utility types
3286 * @since 4.0.0
3287 */
3288 type Iso<F extends Fields> = View<F, "Iso">
3289 /**
3290 * Computes the encoded object type for a struct field map.
3291 *
3292 * **Details**
3293 *
3294 * Field schemas contribute their `Encoded` type. Encoded-side optionality and
3295 * mutability modifiers determine whether properties are optional or writable in
3296 * the encoded shape.
3297 *
3298 * @category utility types
3299 * @since 3.10.0
3300 */
3301 type Encoded<F extends Fields> = View<F, "Encoded">
3302 /**
3303 * Union of all decoding service requirements needed by the schemas in a struct
3304 * field map.
3305 *
3306 * @category utility types
3307 * @since 4.0.0
3308 */
3309 type DecodingServices<F extends Fields> = {
3310 readonly [K in keyof F]: F[K]["DecodingServices"]
3311 }[keyof F]
3312 /**
3313 * Union of all encoding service requirements needed by the schemas in a struct
3314 * field map.
3315 *
3316 * @category utility types
3317 * @since 4.0.0
3318 */
3319 type EncodingServices<F extends Fields> = {
3320 readonly [K in keyof F]: F[K]["EncodingServices"]
3321 }[keyof F]
3322 type TypeConstructorDefaultedKeys<Fields extends Struct.Fields> = {
3323 [K in keyof Fields]: Fields[K] extends { readonly "~type.constructor.default": "with-default" } ? K
3324 : never
3325 }[keyof Fields]
3326 type ReadonlyMakeIn<F extends Fields> = { readonly [K in keyof F]: F[K]["~type.make"] }
3327 type MakeInView<
3328 F extends Fields,
3329 O extends keyof F = TypeOptionalKeys<F> | TypeConstructorDefaultedKeys<F>
3330 > = [O] extends [never] ? Simplify<ReadonlyMakeIn<F>> : Simplify<SetOptional<ReadonlyMakeIn<F>, O>>
3331 /**
3332 * Computes the input object type accepted when constructing a struct value.
3333 *
3334 * **Details**
3335 *
3336 * Required fields use each field schema's `~type.make` input. Fields marked
3337 * optional or with a constructor default may be omitted.
3338 *
3339 * @category utility types
3340 * @since 4.0.0
3341 */
3342 type MakeIn<F extends Fields> = MakeInView<F>
3343}
3344/**
3345 * Type-level representation returned by {@link Struct}.
3346 *
3347 * @category models
3348 * @since 3.10.0
3349 */
3350export interface Struct<Fields extends Struct.Fields> extends BottomLazy<SchemaAST.Objects, Struct<Fields>> {
3351 readonly "Type": Struct.Type<Fields>
3352 readonly "Encoded": Struct.Encoded<Fields>
3353 readonly "DecodingServices": Struct.DecodingServices<Fields>
3354 readonly "EncodingServices": Struct.EncodingServices<Fields>
3355 readonly "~type.make.in": Struct.MakeIn<Fields>
3356 readonly "~type.make": Struct.MakeIn<Fields>
3357 readonly "Iso": Struct.Iso<Fields>
3358 /**
3359 * The field definitions of this struct. Spread them into a new struct to
3360 * reuse fields across schemas.
3361 *
3362 * **Example** (Reusing fields across structs)
3363 *
3364 * ```ts import.meta.vitest
3365 * import { Schema } from "effect"
3366 *
3367 * const Timestamped = Schema.Struct({
3368 * createdAt: Schema.Date,
3369 * updatedAt: Schema.Date
3370 * })
3371 *
3372 * const User = Schema.Struct({
3373 * ...Timestamped.fields,
3374 * name: Schema.String,
3375 * email: Schema.String
3376 * })
3377 * Object.keys(User.fields) // => ["createdAt", "updatedAt", "name", "email"]
3378 * ```
3379 */
3380 readonly fields: Fields
3381 /**
3382 * Returns a new struct with the fields modified by the provided function.
3383 *
3384 * **Details**
3385 *
3386 * Options:
3387 *
3388 * - `unsafePreserveChecks` - if `true`, keep any `.check(...)` constraints
3389 * that were attached to the original union. Defaults to `false`.
3390 *
3391 * **Warning**: This is an unsafe operation. Since `mapFields`
3392 * transformations change the schema type, the original refinement functions
3393 * may no longer be valid or safe to apply to the transformed schema. Only
3394 * use this option if you have verified that your refinements remain correct
3395 * after the transformation.
3396 */
3397 mapFields<To extends Struct.Fields>(
3398 f: (fields: Fields) => To,
3399 options?: {
3400 readonly unsafePreserveChecks?: boolean | undefined
3401 } | undefined
3402 ): Struct<Simplify<Readonly<To>>>
3403}
3404
3405function makeStruct<const Fields extends Struct.Fields>(ast: SchemaAST.Objects, fields: Fields): Struct<Fields> {
3406 return make(ast, {
3407 fields,
3408 mapFields<To extends Struct.Fields>(
3409 this: Struct<Fields>,
3410 f: (fields: Fields) => To,
3411 options?: {
3412 readonly unsafePreserveChecks?: boolean | undefined
3413 } | undefined
3414 ): Struct<To> {
3415 const fields = f(this.fields)
3416 return makeStruct(SchemaAST.struct(fields, options?.unsafePreserveChecks ? this.ast.checks : undefined), fields)
3417 }
3418 })
3419}
3420/**
3421 * Defines a struct schema from a map of field schemas.
3422 *
3423 * **Details**
3424 *
3425 * Each field value is a schema. Use {@link optionalKey} or {@link optional} to
3426 * mark fields as optional, and {@link mutableKey} to mark them as mutable.
3427 *
3428 * The resulting schema's `Type` is a readonly object type with the fields'
3429 * decoded types. The `Encoded` form mirrors the field schemas' encoded types.
3430 * Declared fields may be inherited and are copied to own properties in the
3431 * output. The `__proto__` field is accepted only when it is an own property.
3432 * Parsing does not guarantee that output keys retain their input order.
3433 *
3434 * **Example** (Defining a basic struct)
3435 *
3436 * ```ts import.meta.vitest
3437 * import { Schema } from "effect"
3438 *
3439 * const Person = Schema.Struct({
3440 * name: Schema.String,
3441 * age: Schema.Number,
3442 * email: Schema.optionalKey(Schema.String)
3443 * })
3444 *
3445 * // { readonly name: string; readonly age: number; readonly email?: string }
3446 * type Person = typeof Person.Type
3447 *
3448 * Schema.decodeUnknownSync(Person)({ name: "Alice", age: 30 }) // => { name: "Alice", age: 30 }
3449 * ```
3450 *
3451 * @category constructors
3452 * @since 3.10.0
3453 */
3454export function Struct<const Fields extends Struct.Fields>(fields: Fields): Struct<Fields> {
3455 return makeStruct(SchemaAST.struct(fields, undefined), fields)
3456}
3457interface fieldsAssign<NewFields extends Struct.Fields> extends Lambda {
3458 <Fields extends Struct.Fields>(
3459 struct: Struct<Fields>
3460 ): Struct<Struct_.Simplify<Struct_.Assign<Fields, NewFields>>>
3461 readonly "~lambda.out": this["~lambda.in"] extends Struct<Struct.Fields>
3462 ? Struct<Struct_.Simplify<Struct_.Assign<this["~lambda.in"]["fields"], NewFields>>>
3463 : "Error: schema not eligible for fieldsAssign"
3464}
3465/**
3466 * Adds fields to a struct schema through a struct-mapping lambda.
3467 *
3468 * **When to use**
3469 *
3470 * Use to add the same fields to an existing struct or every struct member of a
3471 * union.
3472 *
3473 * **Details**
3474 *
3475 * This is a shortcut for `MyStruct.mapFields(Struct.assign(fields))`.
3476 *
3477 * **Example** (Adding fields to a union of structs)
3478 *
3479 * ```ts import.meta.vitest
3480 * import { Schema, Tuple } from "effect"
3481 *
3482 * // Add a new field to all members of a union of structs
3483 * const schema = Schema.Union([
3484 * Schema.Struct({ a: Schema.String }),
3485 * Schema.Struct({ b: Schema.Number })
3486 * ]).mapMembers(Tuple.map(Schema.fieldsAssign({ c: Schema.Number })))
3487 * Schema.decodeSync(schema)({ a: "a", c: 1 }) // => { a: "a", c: 1 }
3488 * ```
3489 *
3490 * @category combinators
3491 * @since 4.0.0
3492 */
3493export function fieldsAssign<const NewFields extends Struct.Fields>(fields: NewFields) {
3494 return Struct_.lambda<fieldsAssign<NewFields>>((struct) => struct.mapFields(Struct_.assign(fields)))
3495}
3496/**
3497 * Type-level representation returned by {@link encodeKeys}.
3498 *
3499 * @category transforming
3500 * @since 4.0.0
3501 */
3502export interface encodeKeys<
3503 S extends Constraint & { readonly fields: Struct.Fields },
3504 M extends { readonly [K in keyof S["fields"]]?: PropertyKey }
3505> extends
3506 decodeTo<
3507 S,
3508 Struct<
3509 {
3510 [
3511 K in keyof S["fields"] as K extends keyof M ? M[K] extends PropertyKey ? M[K] : K : K
3512 ]: toEncoded<S["fields"][K]>
3513 }
3514 >
3515 >
3516{}
3517
3518const canonicalPropertyKey = (key: PropertyKey): string | symbol =>
3519 typeof key === "symbol" ? key : globalThis.String(key)
3520/**
3521 * Renames struct keys in the encoded form without changing the decoded type.
3522 *
3523 * **Details**
3524 *
3525 * Takes a partial mapping `{ decodedKey: encodedKey }` and produces a
3526 * transformation schema that decodes from the renamed keys and encodes back to
3527 * the renamed keys. Keys not present in the mapping are left unchanged.
3528 * If two existing fields would produce the same encoded key, construction
3529 * fails.
3530 *
3531 * **Example** (Renaming `name` to `full_name` in the encoded form)
3532 *
3533 * ```ts import.meta.vitest
3534 * import { Schema } from "effect"
3535 *
3536 * const Person = Schema.Struct({ name: Schema.String, age: Schema.Number })
3537 * const Encoded = Person.pipe(Schema.encodeKeys({ name: "full_name" }))
3538 *
3539 * // Decodes { full_name: "Alice", age: 30 } → { name: "Alice", age: 30 }
3540 * Schema.decodeUnknownSync(Encoded)({ full_name: "Alice", age: 30 }) // => { name: "Alice", age: 30 }
3541 * ```
3542 *
3543 * @category transforming
3544 * @since 4.0.0
3545 */
3546export function encodeKeys<
3547 S extends Constraint & { readonly fields: Struct.Fields },
3548 const M extends { readonly [K in keyof S["fields"]]?: PropertyKey }
3549>(mapping: M) {
3550 return function(self: S): encodeKeys<S, M> {
3551 const fields: any = {}
3552 const appliedMapping: any = Object.create(null)
3553 const reverseMapping: any = Object.create(null)
3554 const seenEncodedKeys = new Set<string | symbol>()
3555 for (const k of Reflect.ownKeys(self.fields)) {
3556 const encoded = toEncoded(self.fields[k])
3557 const hasMapping = Object.hasOwn(mapping, k)
3558 const encodedKey = hasMapping ? (mapping as any)[k] as PropertyKey : k
3559 const canonical = canonicalPropertyKey(encodedKey)
3560 if (seenEncodedKeys.has(canonical)) {
3561 throw new globalThis.Error(`Duplicate encoded keys: ${formatPropertyKey(encodedKey)}`)
3562 }
3563 seenEncodedKeys.add(canonical)
3564 InternalRecord.assignProperty(fields, encodedKey, encoded)
3565 if (hasMapping) {
3566 appliedMapping[k] = encodedKey
3567 reverseMapping[encodedKey] = k
3568 }
3569 }
3570 return Struct(fields).pipe(decodeTo(
3571 self,
3572 SchemaTransformation.transform<any, any>({
3573 decode: Struct_.renameKeys(reverseMapping),
3574 encode: Struct_.renameKeys(appliedMapping)
3575 })
3576 )) as any
3577 }
3578}
3579/**
3580 * Adds derived fields to a struct schema during decoding.
3581 *
3582 * **Details**
3583 *
3584 * Each new field is derived from the decoded struct value via a function that
3585 * returns `Option`. On encoding the derived fields are stripped. This allows
3586 * computed or enriched fields to live in the decoded type without appearing in
3587 * the encoded form.
3588 *
3589 * **Example** (Adding a computed `fullName` field)
3590 *
3591 * ```ts import.meta.vitest
3592 * import { Option, Schema } from "effect"
3593 *
3594 * const Person = Schema.Struct({ first: Schema.String, last: Schema.String })
3595 * const Extended = Person.pipe(
3596 * Schema.extendTo(
3597 * { fullName: Schema.String },
3598 * { fullName: (p) => Option.some(`${p.first} ${p.last}`) }
3599 * )
3600 * )
3601 *
3602 * const alice = Schema.decodeUnknownSync(Extended)({ first: "Alice", last: "Smith" })
3603 * alice.fullName // => "Alice Smith"
3604 * ```
3605 *
3606 * @category transforming
3607 * @since 4.0.0
3608 */
3609export function extendTo<S extends Struct<Struct.Fields>, const Fields extends Struct.Fields>(
3610 fields: Fields,
3611 derive: { readonly [K in keyof Fields]: (s: S["Type"]) => Option_.Option<Fields[K]["Type"]> }
3612) {
3613 return (
3614 self: S
3615 ): decodeTo<Struct<Simplify<{ [K in keyof S["fields"]]: toType<S["fields"][K]> } & Fields>>, S> => {
3616 const f = Record_.map(self.fields, toType)
3617 const to = Struct({ ...f, ...fields })
3618 return self.pipe(decodeTo(
3619 to,
3620 SchemaTransformation.transform({
3621 decode: (input) => {
3622 const out: any = { ...input }
3623 for (const k in fields) {
3624 const f = derive[k]
3625 const o = f(input)
3626 if (Option_.isSome(o)) {
3627 InternalRecord.assignProperty(out, k, o.value)
3628 }
3629 }
3630 return out
3631 },
3632 encode: (input) => {
3633 const out = { ...input }
3634 for (const k in fields) {
3635 delete out[k]
3636 }
3637 return out
3638 }
3639 })
3640 )) as any
3641 }
3642}
3643/**
3644 * Namespace for `Record` type utilities.
3645 *
3646 * **Details**
3647 *
3648 * - `Record.Key` — constraint for the key schema (must encode to `PropertyKey`)
3649 * - `Record.Type<K, V>` — decoded type of the record
3650 * - `Record.Encoded<K, V>` — encoded type of the record
3651 *
3652 * @since 3.10.0
3653 */
3654export declare namespace Record {
3655 /**
3656 * Constraint for schemas that can be used as record keys.
3657 *
3658 * **Details**
3659 *
3660 * The key schema must decode and encode property keys (`string`, `number`, or
3661 * `symbol`) so it can describe object property names.
3662 *
3663 * @category utility types
3664 * @since 4.0.0
3665 */
3666 interface Key extends Codec<PropertyKey, PropertyKey, unknown, unknown> {
3667 readonly "~type.make": PropertyKey
3668 readonly "Iso": PropertyKey
3669 }
3670 /**
3671 * Computes the decoded object type for a record schema from its key and value
3672 * schemas.
3673 *
3674 * **Details**
3675 *
3676 * The key schema supplies the property keys and the value schema supplies each
3677 * property's decoded `Type`. Optional and mutable value schemas affect the
3678 * resulting property optionality and writability.
3679 *
3680 * @category utility types
3681 * @since 3.10.0
3682 */
3683 type Type<Key extends Record.Key, Value extends Constraint> = Value extends {
3684 readonly "~type.optionality": "optional"
3685 } ? Value extends {
3686 readonly "~type.mutability": "mutable"
3687 } ? {
3688 [P in Key["Type"]]?: Value["Type"]
3689 } :
3690 {
3691 readonly [P in Key["Type"]]?: Value["Type"]
3692 } :
3693 Value extends {
3694 readonly "~type.mutability": "mutable"
3695 } ? {
3696 [P in Key["Type"]]: Value["Type"]
3697 } :
3698 {
3699 readonly [P in Key["Type"]]: Value["Type"]
3700 }
3701 /**
3702 * Computes the iso object type for a record schema from the key schema's `Iso`
3703 * keys and the value schema's `Iso` values.
3704 *
3705 * @category utility types
3706 * @since 4.0.0
3707 */
3708 type Iso<Key extends Record.Key, Value extends Constraint> = Value extends {
3709 readonly "~type.optionality": "optional"
3710 } ? Value extends {
3711 readonly "~type.mutability": "mutable"
3712 } ? {
3713 [P in Key["Iso"]]?: Value["Iso"]
3714 } :
3715 {
3716 readonly [P in Key["Iso"]]?: Value["Iso"]
3717 } :
3718 Value extends {
3719 readonly "~type.mutability": "mutable"
3720 } ? {
3721 [P in Key["Iso"]]: Value["Iso"]
3722 } :
3723 {
3724 readonly [P in Key["Iso"]]: Value["Iso"]
3725 }
3726 /**
3727 * Computes the encoded object type for a record schema from the key and value
3728 * schemas' encoded types.
3729 *
3730 * **Details**
3731 *
3732 * Encoded-side optionality and mutability on the value schema determine whether
3733 * the encoded record properties are optional or writable.
3734 *
3735 * @category utility types
3736 * @since 3.10.0
3737 */
3738 type Encoded<Key extends Record.Key, Value extends Constraint> = Value extends {
3739 readonly "~encoded.optionality": "optional"
3740 } ? Value extends {
3741 readonly "~encoded.mutability": "mutable"
3742 } ? {
3743 [P in Key["Encoded"]]?: Value["Encoded"]
3744 } :
3745 {
3746 readonly [P in Key["Encoded"]]?: Value["Encoded"]
3747 } :
3748 Value extends {
3749 readonly "~encoded.mutability": "mutable"
3750 } ? {
3751 [P in Key["Encoded"]]: Value["Encoded"]
3752 } :
3753 {
3754 readonly [P in Key["Encoded"]]: Value["Encoded"]
3755 }
3756 /**
3757 * Union of the decoding service requirements of a record's key schema and value
3758 * schema.
3759 *
3760 * @category utility types
3761 * @since 4.0.0
3762 */
3763 type DecodingServices<Key extends Record.Key, Value extends Constraint> =
3764 | Key["DecodingServices"]
3765 | Value["DecodingServices"]
3766 /**
3767 * Union of the encoding service requirements of a record's key schema and value
3768 * schema.
3769 *
3770 * @category utility types
3771 * @since 4.0.0
3772 */
3773 type EncodingServices<Key extends Record.Key, Value extends Constraint> =
3774 | Key["EncodingServices"]
3775 | Value["EncodingServices"]
3776 /**
3777 * Computes the input object type accepted when constructing a record value.
3778 *
3779 * **Details**
3780 *
3781 * Keys use the key schema's `~type.make` type and values use the value schema's
3782 * `~type.make` type. Value optionality and mutability determine whether
3783 * properties are optional or writable.
3784 *
3785 * @category utility types
3786 * @since 4.0.0
3787 */
3788 type MakeIn<Key extends Record.Key, Value extends Constraint> = Value extends {
3789 readonly "~encoded.optionality": "optional"
3790 } ? Value extends {
3791 readonly "~encoded.mutability": "mutable"
3792 } ? {
3793 [P in Key["~type.make"]]?: Value["~type.make"]
3794 } :
3795 {
3796 readonly [P in Key["~type.make"]]?: Value["~type.make"]
3797 } :
3798 Value extends {
3799 readonly "~encoded.mutability": "mutable"
3800 } ? {
3801 [P in Key["~type.make"]]: Value["~type.make"]
3802 } :
3803 {
3804 readonly [P in Key["~type.make"]]: Value["~type.make"]
3805 }
3806}
3807/**
3808 * Type-level representation returned by {@link Record}.
3809 *
3810 * @category models
3811 * @since 4.0.0
3812 */
3813export interface $Record<Key extends Record.Key, Value extends Constraint> extends
3814 BottomLazy<
3815 SchemaAST.Objects,
3816 $Record<Key, Value>
3817 >
3818{
3819 readonly "Type": Record.Type<Key, Value>
3820 readonly "Encoded": Record.Encoded<Key, Value>
3821 readonly "DecodingServices": Record.DecodingServices<Key, Value>
3822 readonly "EncodingServices": Record.EncodingServices<Key, Value>
3823 readonly "~type.make.in": Simplify<Record.MakeIn<Key, Value>>
3824 readonly "~type.make": Simplify<Record.MakeIn<Key, Value>>
3825 readonly "Iso": Record.Iso<Key, Value>
3826 readonly key: Key
3827 readonly value: Value
3828}
3829/**
3830 * Defines a record schema whose dynamic properties are selected by a key schema
3831 * and decoded with a value schema.
3832 *
3833 * **Details**
3834 *
3835 * For dynamic keys, the key schema selects matching own properties and the
3836 * value schema decodes or encodes only those selected properties. Checks on
3837 * string, number, symbol, and template literal key schemas narrow which
3838 * properties are selected.
3839 *
3840 * For transformed key schemas, property selection is based on encoded property
3841 * names before the selected key is decoded.
3842 *
3843 * **Gotchas**
3844 *
3845 * When decoded or encoded key transformations produce the same property key,
3846 * sequential parsing applies selected own properties in selection order, so
3847 * the later selected property overwrites the earlier value. Dynamic key
3848 * selection always examines own properties. Finite literal keys are declared
3849 * fields and may therefore be inherited. Output key order is not guaranteed.
3850 *
3851 * **Example** (Defining a string-keyed record of numbers)
3852 *
3853 * ```ts import.meta.vitest
3854 * import { Schema } from "effect"
3855 *
3856 * const schema = Schema.Record(Schema.String, Schema.Number)
3857 *
3858 * // { readonly [x: string]: number }
3859 * type R = typeof schema.Type
3860 *
3861 * Schema.decodeUnknownSync(schema)({ a: 1, b: 2 }) // => { a: 1, b: 2 }
3862 * ```
3863 *
3864 * @category constructors
3865 * @since 3.10.0
3866 */
3867export function Record<Key extends Record.Key, Value extends Constraint>(
3868 key: Key,
3869 value: Value
3870): $Record<Key, Value> {
3871 return make(SchemaAST.record(key.ast, value.ast), { key, value })
3872}
3873/**
3874 * Namespace for `StructWithRest` type utilities.
3875 *
3876 * **Details**
3877 *
3878 * - `StructWithRest.Type<S, R>` — decoded type (struct type intersected with record types)
3879 * - `StructWithRest.Encoded<S, R>` — encoded type
3880 *
3881 * @since 4.0.0
3882 */
3883export declare namespace StructWithRest {
3884 /**
3885 * Constraint for object-like schemas that can be used as the fixed portion of a
3886 * `StructWithRest` schema.
3887 *
3888 * @category utility types
3889 * @since 4.0.0
3890 */
3891 type Objects = Constraint & {
3892 readonly ast: SchemaAST.Objects
3893 }
3894 /**
3895 * Readonly list of record schemas that provide the additional index signatures
3896 * for a `StructWithRest` schema.
3897 *
3898 * @category utility types
3899 * @since 3.10.0
3900 */
3901 type Records = ReadonlyArray<$Record<Record.Key, Constraint>>
3902 type MergeTuple<T extends ReadonlyArray<unknown>> = T extends readonly [infer Head, ...infer Tail] ?
3903 Head & MergeTuple<Tail>
3904 : {}
3905 type Intersect<
3906 S extends Objects,
3907 Records extends StructWithRest.Records,
3908 Side extends "Type" | "Iso" | "Encoded" | "~type.make"
3909 > =
3910 & S[Side]
3911 & MergeTuple<{ readonly [K in keyof Records]: Records[K][Side] }>
3912 /**
3913 * Computes the decoded type for `StructWithRest` by intersecting the base object
3914 * schema's decoded `Type` with the decoded types of all rest record schemas.
3915 *
3916 * @category utility types
3917 * @since 3.10.0
3918 */
3919 type Type<S extends Objects, Records extends StructWithRest.Records> = Intersect<S, Records, "Type">
3920 /**
3921 * Computes the iso type for `StructWithRest` by intersecting the base object
3922 * schema's `Iso` type with the `Iso` types of all rest record schemas.
3923 *
3924 * @category utility types
3925 * @since 4.0.0
3926 */
3927 type Iso<S extends Objects, Records extends StructWithRest.Records> = Intersect<S, Records, "Iso">
3928 /**
3929 * Computes the encoded type for `StructWithRest` by intersecting the base object
3930 * schema's encoded type with the encoded types of all rest record schemas.
3931 *
3932 * @category utility types
3933 * @since 3.10.0
3934 */
3935 type Encoded<S extends Objects, Records extends StructWithRest.Records> = Intersect<S, Records, "Encoded">
3936 /**
3937 * Computes the input type accepted when constructing a `StructWithRest` value by
3938 * intersecting the base object's make input with the make inputs of all rest
3939 * record schemas.
3940 *
3941 * @category utility types
3942 * @since 4.0.0
3943 */
3944 type MakeIn<S extends Objects, Records extends StructWithRest.Records> = Intersect<S, Records, "~type.make">
3945 type Services<
3946 S extends Objects,
3947 Records extends StructWithRest.Records,
3948 Side extends "DecodingServices" | "EncodingServices"
3949 > =
3950 | S[Side]
3951 | { [K in keyof Records]: Records[K][Side] }[number]
3952 /**
3953 * Union of the decoding service requirements of the base object schema and all
3954 * rest record schemas.
3955 *
3956 * @category utility types
3957 * @since 4.0.0
3958 */
3959 type DecodingServices<S extends Objects, Records extends StructWithRest.Records> = Services<
3960 S,
3961 Records,
3962 "DecodingServices"
3963 >
3964 /**
3965 * Union of the encoding service requirements of the base object schema and all
3966 * rest record schemas.
3967 *
3968 * @category utility types
3969 * @since 4.0.0
3970 */
3971 type EncodingServices<S extends Objects, Records extends StructWithRest.Records> = Services<
3972 S,
3973 Records,
3974 "EncodingServices"
3975 >
3976 type IncompatibleKeys<A, B, OK extends (keyof A & keyof B) = Extract<keyof A, keyof B>> = {
3977 [K in OK]: Required<Pick<A, K>>[K] extends B[K] ? never : K
3978 }[OK]
3979 type IncompatibleSideKeys<
3980 S extends Objects,
3981 Records extends StructWithRest.Records,
3982 Side extends "Type" | "Encoded" | "Iso" | "~type.make"
3983 > = {
3984 [I in keyof Records]: Records[I][Side] extends object ? IncompatibleKeys<S[Side], Records[I][Side]> : never
3985 }[number]
3986 type IncompatibleRecords<S extends Objects, Records extends StructWithRest.Records> =
3987 | IncompatibleSideKeys<S, Records, "Type">
3988 | IncompatibleSideKeys<S, Records, "Encoded">
3989 | IncompatibleSideKeys<S, Records, "Iso">
3990 | IncompatibleSideKeys<S, Records, "~type.make">
3991 /**
3992 * Checks whether fixed fields are compatible with the rest record schemas.
3993 *
3994 * **Details**
3995 *
3996 * Returns `true` when all fixed fields can also satisfy the matching rest
3997 * index signatures. Returns a diagnostic object when TypeScript would make
3998 * the resulting intersection too narrow for one or more fixed keys.
3999 *
4000 * **Example** (Checking record compatibility)
4001 *
4002 * ```ts import.meta.vitest
4003 * import { Schema } from "effect"
4004 *
4005 * const user = Schema.Struct({ id: Schema.String })
4006 * const stringExtras = [Schema.Record(Schema.String, Schema.String)] as const
4007 *
4008 * type UserCheck = Schema.StructWithRest.ValidateRecords<typeof user, typeof stringExtras>
4009 *
4010 * const userCheck: UserCheck = true
4011 * void userCheck
4012 *
4013 * const counter = Schema.Struct({ count: Schema.NumberFromString })
4014 *
4015 * type CounterCheck = Schema.StructWithRest.ValidateRecords<typeof counter, typeof stringExtras>
4016 * // ^? { "incompatible index signatures": "count" }
4017 *
4018 * const counterCheck = null as unknown as CounterCheck
4019 * void counterCheck
4020 * ```
4021 *
4022 * @category utility types
4023 * @since 4.0.0
4024 */
4025 type ValidateRecords<S extends Objects, Records extends StructWithRest.Records> =
4026 [IncompatibleRecords<S, Records>] extends [never] ? true : {
4027 "incompatible index signatures": IncompatibleRecords<S, Records>
4028 }
4029}
4030/**
4031 * Type-level representation returned by {@link StructWithRest}.
4032 *
4033 * @category models
4034 * @since 4.0.0
4035 */
4036export interface StructWithRest<
4037 S extends StructWithRest.Objects,
4038 Records extends StructWithRest.Records
4039> extends
4040 BottomLazy<
4041 SchemaAST.Objects,
4042 StructWithRest<S, Records>
4043 >
4044{
4045 readonly "Type": Simplify<StructWithRest.Type<S, Records>>
4046 readonly "Encoded": Simplify<StructWithRest.Encoded<S, Records>>
4047 readonly "DecodingServices": StructWithRest.DecodingServices<S, Records>
4048 readonly "EncodingServices": StructWithRest.EncodingServices<S, Records>
4049 readonly "~type.make.in": Simplify<StructWithRest.MakeIn<S, Records>>
4050 readonly "~type.make": Simplify<StructWithRest.MakeIn<S, Records>>
4051 readonly "Iso": Simplify<StructWithRest.Iso<S, Records>>
4052 readonly schema: S
4053 readonly records: Records
4054}
4055/**
4056 * Extends a struct schema with one or more record (index-signature) schemas,
4057 * producing a schema whose decoded type intersects the struct and all records.
4058 *
4059 * **Gotchas**
4060 *
4061 * TypeScript index signatures also apply to fixed keys. `StructWithRest` does
4062 * not reject incompatible fixed fields at the call site; use
4063 * `StructWithRest.ValidateRecords` when you want an explicit type-level
4064 * compatibility check.
4065 *
4066 * **Example** (Defining structs with string-indexed extra keys)
4067 *
4068 * ```ts import.meta.vitest
4069 * import { Schema } from "effect"
4070 *
4071 * const schema = Schema.StructWithRest(
4072 * Schema.Struct({ id: Schema.Number }),
4073 * [Schema.Record(Schema.String, Schema.Number)]
4074 * )
4075 *
4076 * // { readonly id: number, readonly [x: string]: number }
4077 * type T = typeof schema.Type
4078 * ```
4079 *
4080 * @category constructors
4081 * @since 4.0.0
4082 */
4083export function StructWithRest<
4084 const S extends StructWithRest.Objects,
4085 const Records extends StructWithRest.Records
4086>(
4087 schema: S,
4088 records: Records
4089): StructWithRest<S, Records> {
4090 return make(SchemaAST.structWithRest(schema.ast, records.map(SchemaAST.getAST)), { schema, records })
4091}
4092/**
4093 * Namespace for `Tuple` type utilities.
4094 *
4095 * **Details**
4096 *
4097 * - `Tuple.Elements` — constraint for the element schema array
4098 * - `Tuple.Type<E>` — decoded tuple type
4099 * - `Tuple.Encoded<E>` — encoded tuple type
4100 * - `Tuple.MakeIn<E>` — constructor input tuple
4101 *
4102 * @since 3.10.0
4103 */
4104export declare namespace Tuple {
4105 /**
4106 * Constraint for the readonly array of element schemas used to define a
4107 * fixed-length `Tuple` schema.
4108 *
4109 * @category utility types
4110 * @since 3.10.0
4111 */
4112 type Elements = ReadonlyArray<Constraint>
4113 type Type_<
4114 Elements,
4115 Out extends ReadonlyArray<any> = readonly []
4116 > = Elements extends readonly [infer Head, ...infer Tail] ?
4117 Head extends { readonly "Type": infer T } ?
4118 Head extends { readonly "~type.optionality": "optional" } ? Type_<Tail, readonly [...Out, T?]>
4119 : Type_<Tail, readonly [...Out, T]>
4120 : Out
4121 : Out
4122 /**
4123 * Computes the decoded tuple type for a tuple element schema array.
4124 *
4125 * **Details**
4126 *
4127 * Each element contributes its decoded `Type`; optional element schemas produce
4128 * optional tuple positions.
4129 *
4130 * @category utility types
4131 * @since 3.10.0
4132 */
4133 type Type<E extends Elements> = Type_<E>
4134 type Iso_<
4135 Elements,
4136 Out extends ReadonlyArray<any> = readonly []
4137 > = Elements extends readonly [infer Head, ...infer Tail] ?
4138 Head extends { readonly "Iso": infer T } ?
4139 Head extends { readonly "~type.optionality": "optional" } ? Iso_<Tail, readonly [...Out, T?]>
4140 : Iso_<Tail, readonly [...Out, T]>
4141 : Out
4142 : Out
4143 /**
4144 * Computes the iso tuple type for a tuple element schema array from each
4145 * element schema's `Iso` type.
4146 *
4147 * @category utility types
4148 * @since 4.0.0
4149 */
4150 type Iso<E extends Elements> = Iso_<E>
4151 type Encoded_<
4152 Elements,
4153 Out extends ReadonlyArray<any> = readonly []
4154 > = Elements extends readonly [infer Head, ...infer Tail] ?
4155 Head extends { readonly "Encoded": infer T } ?
4156 Head extends { readonly "~encoded.optionality": "optional" } ? Encoded_<Tail, readonly [...Out, T?]>
4157 : Encoded_<Tail, readonly [...Out, T]>
4158 : Out
4159 : Out
4160 /**
4161 * Computes the encoded tuple type for a tuple element schema array.
4162 *
4163 * **Details**
4164 *
4165 * Each element contributes its `Encoded` type; encoded-side optional element
4166 * schemas produce optional tuple positions.
4167 *
4168 * @category utility types
4169 * @since 3.10.0
4170 */
4171 type Encoded<E extends Elements> = Encoded_<E>
4172 /**
4173 * Union of all decoding service requirements needed by the tuple element
4174 * schemas.
4175 *
4176 * @category utility types
4177 * @since 4.0.0
4178 */
4179 type DecodingServices<E extends Elements> = E[number]["DecodingServices"]
4180 /**
4181 * Union of all encoding service requirements needed by the tuple element
4182 * schemas.
4183 *
4184 * @category utility types
4185 * @since 4.0.0
4186 */
4187 type EncodingServices<E extends Elements> = E[number]["EncodingServices"]
4188 type MakeIn_<
4189 E,
4190 Out extends ReadonlyArray<any> = readonly []
4191 > = E extends readonly [infer Head, ...infer Tail] ?
4192 Head extends { "~type.make": infer T } ?
4193 Head extends
4194 { readonly "~type.optionality": "optional" } | { readonly "~type.constructor.default": "with-default" } ?
4195 MakeIn_<Tail, readonly [...Out, T?]> :
4196 MakeIn_<Tail, readonly [...Out, T]>
4197 : Out :
4198 Out
4199 /**
4200 * Computes the input tuple type accepted when constructing a tuple value.
4201 *
4202 * **Details**
4203 *
4204 * Each element uses its `~type.make` input type. Optional elements and elements
4205 * with constructor defaults produce optional tuple positions.
4206 *
4207 * @category utility types
4208 * @since 4.0.0
4209 */
4210 type MakeIn<E extends Elements> = MakeIn_<E>
4211}
4212/**
4213 * Type-level representation returned by {@link Tuple}.
4214 *
4215 * @category models
4216 * @since 3.10.0
4217 */
4218export interface Tuple<Elements extends Tuple.Elements> extends
4219 BottomLazy<
4220 SchemaAST.Arrays,
4221 Tuple<Elements>
4222 >
4223{
4224 readonly "Type": Tuple.Type<Elements>
4225 readonly "Encoded": Tuple.Encoded<Elements>
4226 readonly "DecodingServices": Tuple.DecodingServices<Elements>
4227 readonly "EncodingServices": Tuple.EncodingServices<Elements>
4228 readonly "~type.make.in": Tuple.MakeIn<Elements>
4229 readonly "~type.make": Tuple.MakeIn<Elements>
4230 readonly "Iso": Tuple.Iso<Elements>
4231 readonly elements: Elements
4232 /**
4233 * Returns a new tuple with the elements modified by the provided function.
4234 *
4235 * **Details**
4236 *
4237 * Options:
4238 *
4239 * - `unsafePreserveChecks` - if `true`, keep any `.check(...)` constraints
4240 * that were attached to the original union. Defaults to `false`.
4241 *
4242 * **Warning**: This is an unsafe operation. Since `mapFields`
4243 * transformations change the schema type, the original refinement functions
4244 * may no longer be valid or safe to apply to the transformed schema. Only
4245 * use this option if you have verified that your refinements remain correct
4246 * after the transformation.
4247 */
4248 mapElements<To extends Tuple.Elements>(
4249 f: (elements: Elements) => To,
4250 options?: {
4251 readonly unsafePreserveChecks?: boolean | undefined
4252 } | undefined
4253 ): Tuple<Simplify<Readonly<To>>>
4254}
4255
4256function makeTuple<Elements extends Tuple.Elements>(ast: SchemaAST.Arrays, elements: Elements): Tuple<Elements> {
4257 return make(ast, {
4258 elements,
4259 mapElements<To extends Tuple.Elements>(
4260 this: Tuple<Elements>,
4261 f: (elements: Elements) => To,
4262 options?: {
4263 readonly unsafePreserveChecks?: boolean | undefined
4264 } | undefined
4265 ): Tuple<Simplify<Readonly<To>>> {
4266 const elements = f(this.elements)
4267 return makeTuple(SchemaAST.tuple(elements, options?.unsafePreserveChecks ? this.ast.checks : undefined), elements)
4268 }
4269 })
4270}
4271/**
4272 * Defines a fixed-length tuple schema from an array of element schemas.
4273 *
4274 * **Example** (Defining a pair of string and number)
4275 *
4276 * ```ts import.meta.vitest
4277 * import { Schema } from "effect"
4278 *
4279 * const schema = Schema.Tuple([Schema.String, Schema.Number])
4280 *
4281 * Schema.decodeUnknownSync(schema)(["hello", 42]) // => ["hello", 42]
4282 * ```
4283 *
4284 * @category constructors
4285 * @since 3.10.0
4286 */
4287export function Tuple<const Elements extends ReadonlyArray<Constraint>>(elements: Elements): Tuple<Elements> {
4288 return makeTuple(SchemaAST.tuple(elements), elements)
4289}
4290/**
4291 * Namespace for `TupleWithRest` type utilities.
4292 *
4293 * **Details**
4294 *
4295 * - `TupleWithRest.TupleType` — constraint for the leading tuple schema
4296 * - `TupleWithRest.Rest` — the rest element schema(s)
4297 * - `TupleWithRest.Type<T, R>` — decoded type (fixed elements + rest)
4298 * - `TupleWithRest.Encoded<T, R>` — encoded type
4299 *
4300 * @since 4.0.0
4301 */
4302export declare namespace TupleWithRest {
4303 /**
4304 * Constraint for tuple-like schemas that can be used as the fixed leading
4305 * portion of a `TupleWithRest` schema.
4306 *
4307 * @category utility types
4308 * @since 3.10.0
4309 */
4310 type TupleType = Constraint & {
4311 readonly Type: ReadonlyArray<unknown>
4312 readonly Encoded: ReadonlyArray<unknown>
4313 readonly ast: SchemaAST.Arrays
4314 readonly "~type.make": ReadonlyArray<unknown>
4315 readonly "Iso": ReadonlyArray<unknown>
4316 }
4317 /**
4318 * Non-empty list of schemas used for the rest portion of a `TupleWithRest`.
4319 *
4320 * **Details**
4321 *
4322 * The first schema describes the repeated rest element. Additional schemas, when
4323 * present, describe trailing tuple elements after the repeated rest segment.
4324 *
4325 * @category utility types
4326 * @since 3.10.0
4327 */
4328 type Rest = readonly [Constraint, ...Array<Constraint>]
4329 /**
4330 * Computes the decoded tuple type for a `TupleWithRest`.
4331 *
4332 * **Details**
4333 *
4334 * The output starts with the fixed tuple elements, continues with zero or more
4335 * values decoded by the first rest schema, and includes any trailing rest schemas
4336 * as fixed tuple positions.
4337 *
4338 * @category utility types
4339 * @since 3.10.0
4340 */
4341 type Type<T extends ReadonlyArray<unknown>, Rest extends TupleWithRest.Rest> = Rest extends
4342 readonly [infer Head extends Constraint, ...infer Tail extends ReadonlyArray<Constraint>] ? Readonly<[
4343 ...T,
4344 ...Array<Head["Type"]>,
4345 ...{
4346 readonly [K in keyof Tail]: Tail[K]["Type"]
4347 }
4348 ]> :
4349 T
4350 /**
4351 * Computes the iso tuple type for a `TupleWithRest`.
4352 *
4353 * **Details**
4354 *
4355 * The output starts with the fixed tuple's `Iso` elements, continues with zero
4356 * or more values using the first rest schema's `Iso`, and includes any trailing
4357 * rest schemas as fixed tuple positions.
4358 *
4359 * @category utility types
4360 * @since 4.0.0
4361 */
4362 type Iso<T extends ReadonlyArray<unknown>, Rest extends TupleWithRest.Rest> = Rest extends
4363 readonly [infer Head extends Constraint, ...infer Tail extends ReadonlyArray<Constraint>] ? Readonly<[
4364 ...T,
4365 ...Array<Head["Iso"]>,
4366 ...{
4367 readonly [K in keyof Tail]: Tail[K]["Iso"]
4368 }
4369 ]> :
4370 T
4371 /**
4372 * Computes the encoded tuple type for `TupleWithRest`.
4373 *
4374 * **Details**
4375 *
4376 * The leading tuple's encoded elements are kept first. The encoded type of the
4377 * first rest schema may repeat zero or more times, and the encoded types of any
4378 * additional rest schemas become required trailing tuple elements.
4379 *
4380 * @category utility types
4381 * @since 3.10.0
4382 */
4383 type Encoded<E extends ReadonlyArray<unknown>, Rest extends TupleWithRest.Rest> = Rest extends
4384 readonly [infer Head extends Constraint, ...infer Tail extends ReadonlyArray<Constraint>] ? readonly [
4385 ...E,
4386 ...Array<Head["Encoded"]>,
4387 ...{
4388 readonly [K in keyof Tail]: Tail[K]["Encoded"]
4389 }
4390 ] :
4391 E
4392 /**
4393 * Computes the constructor input tuple type for `TupleWithRest`.
4394 *
4395 * **Details**
4396 *
4397 * The leading tuple's make input elements are kept first. The make input type of
4398 * the first rest schema may repeat zero or more times, and the make input types
4399 * of any additional rest schemas become required trailing tuple elements.
4400 *
4401 * @category utility types
4402 * @since 4.0.0
4403 */
4404 type MakeIn<M extends ReadonlyArray<unknown>, Rest extends TupleWithRest.Rest> = Rest extends
4405 readonly [infer Head extends Constraint, ...infer Tail extends ReadonlyArray<Constraint>] ? readonly [
4406 ...M,
4407 ...Array<Head["~type.make"]>,
4408 ...{
4409 readonly [K in keyof Tail]: Tail[K]["~type.make"]
4410 }
4411 ] :
4412 M
4413}
4414/**
4415 * Type-level representation returned by {@link TupleWithRest}.
4416 *
4417 * @category models
4418 * @since 4.0.0
4419 */
4420export interface TupleWithRest<
4421 S extends TupleWithRest.TupleType,
4422 Rest extends TupleWithRest.Rest
4423> extends
4424 BottomLazy<
4425 SchemaAST.Arrays,
4426 TupleWithRest<S, Rest>
4427 >
4428{
4429 readonly "Type": TupleWithRest.Type<S["Type"], Rest>
4430 readonly "Encoded": TupleWithRest.Encoded<S["Encoded"], Rest>
4431 readonly "DecodingServices": S["DecodingServices"] | Rest[number]["DecodingServices"]
4432 readonly "EncodingServices": S["EncodingServices"] | Rest[number]["EncodingServices"]
4433 readonly "~type.make.in": TupleWithRest.MakeIn<S["~type.make"], Rest>
4434 readonly "~type.make": TupleWithRest.MakeIn<S["~type.make"], Rest>
4435 readonly "Iso": TupleWithRest.Iso<S["Iso"], Rest>
4436 readonly schema: S
4437 readonly rest: Rest
4438}
4439/**
4440 * Extends a fixed-length tuple schema with a variadic rest segment.
4441 *
4442 * **Details**
4443 *
4444 * The resulting tuple starts with the fixed elements from `schema`. The first
4445 * schema in `rest` is the repeatable element schema, and any additional schemas
4446 * in `rest` are required trailing tuple elements after the variadic segment. For
4447 * example, `[Schema.Boolean, Schema.String]` represents zero or more booleans
4448 * followed by a final string.
4449 *
4450 * **Example** (Defining tuples with rest elements)
4451 *
4452 * ```ts import.meta.vitest
4453 * import { Schema } from "effect"
4454 *
4455 * // [string, number, ...boolean[]]
4456 * const schema = Schema.TupleWithRest(
4457 * Schema.Tuple([Schema.String, Schema.Number]),
4458 * [Schema.Boolean]
4459 * )
4460 *
4461 * Schema.decodeUnknownSync(schema)(["hello", 1, true, false]) // => ["hello", 1, true, false]
4462 * ```
4463 *
4464 * @category constructors
4465 * @since 4.0.0
4466 */
4467export function TupleWithRest<S extends Tuple<Tuple.Elements>, const Rest extends TupleWithRest.Rest>(
4468 schema: S,
4469 rest: Rest
4470): TupleWithRest<S, Rest> {
4471 return make(SchemaAST.tupleWithRest(schema.ast, rest.map(SchemaAST.getAST)), { schema, rest })
4472}
4473/**
4474 * Type-level representation returned by {@link Array}.
4475 *
4476 * @category models
4477 * @since 4.0.0
4478 */
4479export interface $Array<S extends Constraint> extends
4480 BottomLazy<
4481 SchemaAST.Arrays,
4482 $Array<S>
4483 >
4484{
4485 readonly "Type": ReadonlyArray<S["Type"]>
4486 readonly "Encoded": ReadonlyArray<S["Encoded"]>
4487 readonly "DecodingServices": S["DecodingServices"]
4488 readonly "EncodingServices": S["EncodingServices"]
4489 readonly "~type.make.in": ReadonlyArray<S["~type.make"]>
4490 readonly "~type.make": ReadonlyArray<S["~type.make"]>
4491 readonly "Iso": ReadonlyArray<S["Iso"]>
4492 readonly value: S
4493}
4494interface ArrayLambda extends Lambda {
4495 <S extends Constraint>(self: S): $Array<S>
4496 readonly "~lambda.out": this["~lambda.in"] extends Constraint ? $Array<this["~lambda.in"]> : never
4497}
4498/**
4499 * @category constructors
4500 * @since 4.0.0
4501 */
4502const ArraySchema: ArrayLambda = Struct_.lambda<ArrayLambda>((schema) =>
4503 make(new SchemaAST.Arrays(false, [], [schema.ast]), { value: schema })
4504)
4505export {
4506 /**
4507 * Defines a `ReadonlyArray` schema for a given element schema.
4508 *
4509 * **Example** (Defining an array of strings)
4510 *
4511 * ```ts import.meta.vitest
4512 * import { Schema } from "effect"
4513 *
4514 * const schema = Schema.Array(Schema.String)
4515 *
4516 * Schema.decodeUnknownSync(schema)(["a", "b", "c"]) // => ["a", "b", "c"]
4517 * ```
4518 *
4519 * @category constructors
4520 * @since 4.0.0
4521 */
4522 ArraySchema as Array
4523}
4524
4525/** @internal */
4526export function withArrayLengthConstraints<Item extends Constraint>(
4527 self: $Array<Item>,
4528 minimum: number | undefined,
4529 maximum: number | undefined
4530): $Array<Item> {
4531 if (minimum !== undefined && maximum !== undefined) {
4532 return self.check(isBetweenLength(minimum, maximum))
4533 }
4534 if (minimum !== undefined) return self.check(isMinLength(minimum))
4535 if (maximum !== undefined) return self.check(isMaxLength(maximum))
4536 return self
4537}
4538/**
4539 * Type-level representation returned by {@link NonEmptyArray}.
4540 *
4541 * @category models
4542 * @since 3.10.0
4543 */
4544export interface NonEmptyArray<S extends Constraint> extends
4545 BottomLazy<
4546 SchemaAST.Arrays,
4547 NonEmptyArray<S>
4548 >
4549{
4550 readonly "Type": readonly [S["Type"], ...Array<S["Type"]>]
4551 readonly "Encoded": readonly [S["Encoded"], ...Array<S["Encoded"]>]
4552 readonly "DecodingServices": S["DecodingServices"]
4553 readonly "EncodingServices": S["EncodingServices"]
4554 readonly "~type.make.in": readonly [S["~type.make"], ...Array<S["~type.make"]>]
4555 readonly "~type.make": readonly [S["~type.make"], ...Array<S["~type.make"]>]
4556 readonly "Iso": readonly [S["Iso"], ...Array<S["Iso"]>]
4557 readonly value: S
4558}
4559interface NonEmptyArrayLambda extends Lambda {
4560 <S extends Constraint>(self: S): NonEmptyArray<S>
4561 readonly "~lambda.out": this["~lambda.in"] extends Constraint ? NonEmptyArray<this["~lambda.in"]> : never
4562}
4563/**
4564 * Defines a non-empty `ReadonlyArray` schema — at least one element required.
4565 * Type is `readonly [T, ...T[]]`.
4566 *
4567 * **Example** (Defining a non-empty array of numbers)
4568 *
4569 * ```ts import.meta.vitest
4570 * import { Schema } from "effect"
4571 *
4572 * const schema = Schema.NonEmptyArray(Schema.Number)
4573 *
4574 * Schema.decodeUnknownSync(schema)([1, 2, 3]) // => [1, 2, 3]
4575 * ```
4576 *
4577 * @category constructors
4578 * @since 3.10.0
4579 */
4580export const NonEmptyArray: NonEmptyArrayLambda = Struct_.lambda<NonEmptyArrayLambda>((schema) =>
4581 make(new SchemaAST.Arrays(false, [schema.ast], [schema.ast]), { value: schema })
4582)
4583/**
4584 * Type-level representation returned by {@link ArrayEnsure}.
4585 *
4586 * @category constructors
4587 * @since 3.10.0
4588 */
4589export interface ArrayEnsure<S extends Constraint> extends decodeTo<$Array<toType<S>>, Union<readonly [S, $Array<S>]>> {
4590 readonly "Rebuild": ArrayEnsure<S>
4591}
4592/**
4593 * Creates a schema that accepts either a value decoded by `schema` or an array
4594 * decoded by `Schema.Array(schema)`, then returns an array.
4595 *
4596 * **When to use**
4597 *
4598 * Use to accept input that may be provided either as one item or as an array,
4599 * while normalizing decoded values to a readonly array.
4600 *
4601 * **Details**
4602 *
4603 * During encoding, one-element arrays are encoded as the single element. Empty
4604 * arrays and arrays with two or more elements are encoded as arrays.
4605 *
4606 * **Gotchas**
4607 *
4608 * The single-value branch is tried before the array branch. If `schema` itself
4609 * accepts arrays, an array input can be treated as one value and wrapped in a
4610 * one-element array.
4611 *
4612 * @see {@link Array} for accepting only array input
4613 * @see {@link NonEmptyArray} for requiring at least one decoded element
4614 *
4615 * @category constructors
4616 * @since 3.10.0
4617 */
4618export function ArrayEnsure<S extends Constraint>(schema: S): ArrayEnsure<S> {
4619 const many = ArraySchema(schema)
4620 const to = ArraySchema(toType(schema))
4621 const one = decodeTo(
4622 Tuple([Unknown]),
4623 SchemaTransformation.transform({
4624 decode: (value) => [value] as const,
4625 encode: ([value]) => value
4626 })
4627 )(schema)
4628 return make(Union([one, many]).pipe(decodeTo(to)).ast, { from: Union([schema, many]), to })
4629}
4630/**
4631 * Type-level representation returned by {@link UniqueArray}.
4632 *
4633 * @category models
4634 * @since 4.0.0
4635 */
4636export interface UniqueArray<S extends Constraint> extends $Array<S> {
4637 readonly "Rebuild": UniqueArray<S>
4638}
4639/**
4640 * Returns a new array schema that ensures all elements are unique.
4641 *
4642 * **Details**
4643 *
4644 * The equivalence used to determine uniqueness is the one provided by
4645 * `Schema.toEquivalence(item)`.
4646 *
4647 * @category constructors
4648 * @since 4.0.0
4649 */
4650export function UniqueArray<S extends Constraint>(item: S): UniqueArray<S> {
4651 return ArraySchema(item).check(isUnique())
4652}
4653/**
4654 * Type-level representation returned by {@link mutable}.
4655 *
4656 * @category transforming
4657 * @since 3.10.0
4658 */
4659export interface mutable<
4660 S extends Constraint & {
4661 readonly "ast": SchemaAST.Arrays
4662 }
4663> extends
4664 BottomLazy<
4665 S["ast"],
4666 mutable<S>,
4667 S["~type.parameters"],
4668 S["~type.mutability"],
4669 S["~type.optionality"],
4670 S["~type.constructor.default"],
4671 S["~encoded.mutability"],
4672 S["~encoded.optionality"]
4673 >
4674{
4675 readonly "Type": Mutable<S["Type"]>
4676 readonly "Encoded": Mutable<S["Encoded"]>
4677 readonly "DecodingServices": S["DecodingServices"]
4678 readonly "EncodingServices": S["EncodingServices"]
4679 readonly "~type.make.in": S["~type.make.in"]
4680 readonly "~type.make": S["~type.make"]
4681 readonly "Iso": S["Iso"]
4682 readonly schema: S
4683}
4684interface mutableLambda extends Lambda {
4685 <S extends Constraint & { readonly "ast": SchemaAST.Arrays }>(self: S): mutable<S>
4686 readonly "~lambda.out": this["~lambda.in"] extends Constraint & { readonly "ast": SchemaAST.Arrays } ?
4687 mutable<this["~lambda.in"]>
4688 : "Error: schema not eligible for mutable"
4689}
4690/**
4691 * Makes an array or tuple schema mutable, removing the `readonly` modifier.
4692 *
4693 * **Gotchas**
4694 *
4695 * This combinator does not support an encoding attached to the array or tuple
4696 * node and throws if one is present. Encodings on element schemas are
4697 * supported.
4698 *
4699 * **Example** (Defining mutable arrays)
4700 *
4701 * ```ts import.meta.vitest
4702 * import { Schema } from "effect"
4703 *
4704 * const schema = Schema.mutable(Schema.Array(Schema.Number))
4705 *
4706 * // number[] (mutable)
4707 * type T = typeof schema.Type
4708 * const value: T = [1, 2]
4709 * value.push(3)
4710 * value // => [1, 2, 3]
4711 * ```
4712 *
4713 * @category transforming
4714 * @since 3.10.0
4715 */
4716export const mutable: mutableLambda = Struct_.lambda<mutableLambda>((schema) =>
4717 make(SchemaAST.mutable(schema.ast), { schema })
4718)
4719/**
4720 * Type-level representation returned by {@link Union}.
4721 *
4722 * @category models
4723 * @since 3.10.0
4724 */
4725export interface Union<Members extends ReadonlyArray<Constraint>> extends
4726 BottomLazy<
4727 SchemaAST.Union<{ [K in keyof Members]: Members[K]["ast"] }[number]>,
4728 Union<Members>
4729 >
4730{
4731 readonly "Type": { [K in keyof Members]: Members[K]["Type"] }[number]
4732 readonly "Encoded": { [K in keyof Members]: Members[K]["Encoded"] }[number]
4733 readonly "DecodingServices": { [K in keyof Members]: Members[K]["DecodingServices"] }[number]
4734 readonly "EncodingServices": { [K in keyof Members]: Members[K]["EncodingServices"] }[number]
4735 readonly "~type.make.in": { [K in keyof Members]: Members[K]["~type.make"] }[number]
4736 readonly "~type.make": { [K in keyof Members]: Members[K]["~type.make"] }[number]
4737 readonly "Iso": { [K in keyof Members]: Members[K]["Iso"] }[number]
4738 readonly members: Members
4739 /**
4740 * Returns a new union with the members modified by the provided function.
4741 *
4742 * **Details**
4743 *
4744 * Options:
4745 *
4746 * - `unsafePreserveChecks` - if `true`, keep any `.check(...)` constraints
4747 * that were attached to the original union. Defaults to `false`.
4748 *
4749 * **Warning**: This is an unsafe operation. Since `mapFields`
4750 * transformations change the schema type, the original refinement functions
4751 * may no longer be valid or safe to apply to the transformed schema. Only
4752 * use this option if you have verified that your refinements remain correct
4753 * after the transformation.
4754 */
4755 mapMembers<To extends ReadonlyArray<Constraint>>(
4756 f: (members: Members) => To,
4757 options?: {
4758 readonly unsafePreserveChecks?: boolean | undefined
4759 } | undefined
4760 ): Union<Simplify<Readonly<To>>>
4761}
4762
4763function makeUnion<Members extends ReadonlyArray<Constraint>>(
4764 ast: SchemaAST.Union<Members[number]["ast"]>,
4765 members: Members
4766): Union<Members> {
4767 return make(ast, {
4768 members,
4769 mapMembers<To extends ReadonlyArray<Constraint>>(
4770 this: Union<Members>,
4771 f: (members: Members) => To,
4772 options?: {
4773 readonly unsafePreserveChecks?: boolean | undefined
4774 } | undefined
4775 ): Union<Simplify<Readonly<To>>> {
4776 const members = f(this.members)
4777 return makeUnion(
4778 SchemaAST.union(members, this.ast.options, options?.unsafePreserveChecks ? this.ast.checks : undefined),
4779 members
4780 )
4781 }
4782 })
4783}
4784/**
4785 * Creates a union schema from an array of member schemas. Members are tested in
4786 * order; the first match is returned.
4787 *
4788 * **Details**
4789 *
4790 * Optionally, specify `mode`:
4791 * - `"anyOf"` (default) — matches if any member matches.
4792 * - `"oneOf"` — matches if exactly one member matches.
4793 *
4794 * **Example** (Defining a string or number union)
4795 *
4796 * ```ts import.meta.vitest
4797 * import { Schema } from "effect"
4798 *
4799 * const schema = Schema.Union([Schema.String, Schema.Number])
4800 *
4801 * Schema.decodeUnknownSync(schema)("hello") // => "hello"
4802 * Schema.decodeUnknownSync(schema)(42) // => 42
4803 * ```
4804 *
4805 * @category constructors
4806 * @since 3.10.0
4807 */
4808export function Union<const Members extends ReadonlyArray<Constraint>>(
4809 members: Members,
4810 options?: SchemaAST.UnionOptions
4811): Union<Members> {
4812 return makeUnion(SchemaAST.union(members, options, undefined), members)
4813}
4814/**
4815 * Type-level representation returned by {@link Literals}.
4816 *
4817 * @category models
4818 * @since 4.0.0
4819 */
4820export interface Literals<L extends ReadonlyArray<SchemaAST.LiteralValue>>
4821 extends Bottom<L[number], L[number], never, never, SchemaAST.Union<SchemaAST.Literal>, Literals<L>>
4822{
4823 readonly literals: L
4824 readonly members: { readonly [K in keyof L]: Literal<L[K]> }
4825 /**
4826 * Map over the members of the union.
4827 */
4828 mapMembers<To extends ReadonlyArray<Constraint>>(f: (members: this["members"]) => To): Union<Simplify<Readonly<To>>>
4829
4830 pick<const L2 extends ReadonlyArray<L[number]>>(literals: L2): Literals<L2>
4831
4832 transform<const L2 extends { readonly [I in keyof L]: SchemaAST.LiteralValue }>(
4833 to: L2
4834 ): Union<{ [I in keyof L]: decodeTo<Literal<L2[I]>, Literal<L[I]>> }>
4835}
4836/**
4837 * Creates a union schema from an array of literal values.
4838 *
4839 * **Example** (Defining status codes)
4840 *
4841 * ```ts import.meta.vitest
4842 * import { Schema } from "effect"
4843 *
4844 * const schema = Schema.Literals(["active", "inactive", "pending"])
4845 * Schema.decodeSync(schema)("active") // => "active"
4846 * ```
4847 *
4848 * @see {@link Literal} for a schema that represents a single literal.
4849 * @category constructors
4850 * @since 4.0.0
4851 */
4852export function Literals<const L extends ReadonlyArray<SchemaAST.LiteralValue>>(literals: L): Literals<L> {
4853 const members = literals.map(Literal) as { readonly [K in keyof L]: Literal<L[K]> }
4854 return make(SchemaAST.union(members, undefined, undefined), {
4855 literals,
4856 members,
4857 mapMembers<To extends ReadonlyArray<Constraint>>(
4858 this: Literals<L>,
4859 f: (members: Literals<L>["members"]) => To
4860 ): Union<Simplify<Readonly<To>>> {
4861 return Union(f(this.members))
4862 },
4863 pick<const L2 extends ReadonlyArray<L[number]>>(literals: L2): Literals<L2> {
4864 return Literals(literals)
4865 },
4866 transform<const L2 extends { readonly [I in keyof L]: SchemaAST.LiteralValue }>(
4867 to: L2
4868 ): Union<{ [I in keyof L]: decodeTo<Literal<L2[I]>, Literal<L[I]>> }> {
4869 return Union(members.map((member, index) => member.transform(to[index]))) as any
4870 }
4871 })
4872}
4873/**
4874 * Type-level representation returned by {@link NullOr}.
4875 *
4876 * @category models
4877 * @since 3.10.0
4878 */
4879export interface NullOr<S extends Constraint> extends Union<readonly [S, Null]> {
4880 readonly "Rebuild": NullOr<S>
4881}
4882interface NullOrLambda extends Lambda {
4883 <S extends Constraint>(self: S): NullOr<S>
4884 readonly "~lambda.out": this["~lambda.in"] extends Constraint ? NullOr<this["~lambda.in"]> : never
4885}
4886/**
4887 * Creates a union schema of `S | null`.
4888 *
4889 * @category constructors
4890 * @since 3.10.0
4891 */
4892export const NullOr: NullOrLambda = Struct_.lambda<NullOrLambda>((self) => Union([self, Null]))
4893/**
4894 * Type-level representation returned by {@link UndefinedOr}.
4895 *
4896 * @category models
4897 * @since 3.10.0
4898 */
4899export interface UndefinedOr<S extends Constraint> extends Union<readonly [S, Undefined]> {
4900 readonly "Rebuild": UndefinedOr<S>
4901}
4902interface UndefinedOrLambda extends Lambda {
4903 <S extends Constraint>(self: S): UndefinedOr<S>
4904 readonly "~lambda.out": this["~lambda.in"] extends Constraint ? UndefinedOr<this["~lambda.in"]> : never
4905}
4906/**
4907 * Creates a union schema of `S | undefined`.
4908 *
4909 * @category constructors
4910 * @since 3.10.0
4911 */
4912export const UndefinedOr: UndefinedOrLambda = Struct_.lambda<UndefinedOrLambda>((self) => Union([self, Undefined]))
4913/**
4914 * Type-level representation returned by {@link NullishOr}.
4915 *
4916 * @category models
4917 * @since 3.10.0
4918 */
4919export interface NullishOr<S extends Constraint> extends Union<readonly [S, Null, Undefined]> {
4920 readonly "Rebuild": NullishOr<S>
4921}
4922interface NullishOrLambda extends Lambda {
4923 <S extends Constraint>(self: S): NullishOr<S>
4924 readonly "~lambda.out": this["~lambda.in"] extends Constraint ? NullishOr<this["~lambda.in"]> : never
4925}
4926/**
4927 * Creates a union schema of `S | null | undefined`.
4928 *
4929 * @category constructors
4930 * @since 3.10.0
4931 */
4932export const NullishOr: NullishOrLambda = Struct_.lambda<NullishOrLambda>((self) => Union([self, Null, Undefined]))
4933/**
4934 * Type-level representation returned by {@link suspend}.
4935 *
4936 * @category models
4937 * @since 3.10.0
4938 */
4939export interface suspend<S extends Constraint> extends
4940 BottomLazy<
4941 SchemaAST.Suspend,
4942 suspend<S>,
4943 S["~type.parameters"],
4944 S["~type.mutability"],
4945 S["~type.optionality"],
4946 S["~type.constructor.default"],
4947 S["~encoded.mutability"],
4948 S["~encoded.optionality"]
4949 >
4950{
4951 readonly "Type": S["Type"]
4952 readonly "Encoded": S["Encoded"]
4953 readonly "DecodingServices": S["DecodingServices"]
4954 readonly "EncodingServices": S["EncodingServices"]
4955 readonly "~type.make.in": S["~type.make.in"]
4956 readonly "~type.make": S["~type.make"]
4957 readonly "Iso": S["Iso"]
4958}
4959/**
4960 * Creates a suspended schema that defers evaluation until needed. This is
4961 * essential for creating recursive schemas where a schema references itself,
4962 * preventing infinite recursion during schema definition.
4963 *
4964 * **Example** (Defining recursive tree schemas)
4965 *
4966 * ```ts import.meta.vitest
4967 * import { Schema } from "effect"
4968 *
4969 * interface Tree {
4970 * readonly value: number
4971 * readonly children: ReadonlyArray<Tree>
4972 * }
4973 *
4974 * const Tree = Schema.Struct({
4975 * value: Schema.Number,
4976 * children: Schema.Array(Schema.suspend((): Schema.Codec<Tree> => Tree))
4977 * })
4978 * Schema.decodeSync(Tree)({ value: 1, children: [] }) // => { value: 1, children: [] }
4979 * ```
4980 *
4981 * @category constructors
4982 * @since 3.10.0
4983 */
4984export function suspend<S extends Constraint>(f: () => S): suspend<S> {
4985 return make(new SchemaAST.Suspend(() => f().ast))
4986}
4987/**
4988 * Attaches one or more filter checks to a schema without changing the
4989 * TypeScript type.
4990 *
4991 * **Example** (Adding checks to a schema)
4992 *
4993 * ```ts import.meta.vitest
4994 * import { Schema } from "effect"
4995 *
4996 * const AgeSchema = Schema.Finite.pipe(
4997 * Schema.check(Schema.isGreaterThanOrEqualTo(0), Schema.isLessThanOrEqualTo(120))
4998 * )
4999 * Schema.is(AgeSchema)(42) // => true
5000 * Schema.is(AgeSchema)(121) // => false
5001 * ```
5002 *
5003 * @category filtering
5004 * @since 4.0.0
5005 */
5006export function check<S extends Top>(
5007 ...checks: readonly [SchemaAST.Check<S["Type"]>, ...Array<SchemaAST.Check<S["Type"]>>]
5008) {
5009 return (self: S): S["Rebuild"] => self.check(...checks)
5010}
5011/**
5012 * Type-level representation returned by {@link refine}.
5013 *
5014 * @category filtering
5015 * @since 3.10.0
5016 */
5017export interface refine<T extends S["Type"], S extends Constraint> extends
5018 BottomLazy<
5019 S["ast"],
5020 refine<T, S>,
5021 S["~type.parameters"],
5022 S["~type.mutability"],
5023 S["~type.optionality"],
5024 S["~type.constructor.default"],
5025 S["~encoded.mutability"],
5026 S["~encoded.optionality"]
5027 >
5028{
5029 readonly "Type": T
5030 readonly "Encoded": S["Encoded"]
5031 readonly "DecodingServices": S["DecodingServices"]
5032 readonly "EncodingServices": S["EncodingServices"]
5033 readonly "~type.make.in": S["~type.make.in"]
5034 readonly "~type.make": T
5035 readonly "Iso": T
5036 readonly schema: S
5037}
5038/**
5039 * Narrows the TypeScript type of a schema's output via a type guard predicate,
5040 * attaching the guard as a runtime filter check.
5041 *
5042 * **Details**
5043 *
5044 * The `annotations` parameter annotates the filter created by the refinement.
5045 * With the default formatter, failed refinements use `message` first,
5046 * `expected` second, and `<filter>` when neither is provided. `identifier`
5047 * names type-level failures before the refinement runs; it does not name the
5048 * failed refinement itself.
5049 *
5050 * @category filtering
5051 * @since 3.10.0
5052 */
5053export function refine<S extends Constraint, T extends S["Type"]>(
5054 refinement: (value: S["Type"]) => value is T,
5055 annotations?: Annotations.Filter
5056): (schema: S) => refine<T, S> {
5057 return (schema: S): refine<T, S> =>
5058 make(SchemaAST.appendChecks(schema.ast, [SchemaAST.makeFilterByGuard(refinement, annotations)]), { schema })
5059}
5060// A concrete key requires a property; broad and open template keys do not.
5061type EnsureSingleBrandKey<K extends PropertyKey> = IsUnion<K> extends false
5062 ? {} extends Record<K, unknown> ? never : unknown
5063 : never
5064// Collect all keys, including those not shared by every union member.
5065type FromBrandKeys<A extends Brand.Brand<any>> = A extends unknown ? Brand.Brand.Keys<A> : never
5066/**
5067 * Type-level representation returned by {@link brand}.
5068 *
5069 * @category branding
5070 * @since 3.10.0
5071 */
5072export interface brand<S extends Constraint, B extends string> extends
5073 BottomLazy<
5074 S["ast"],
5075 brand<S, B>,
5076 S["~type.parameters"],
5077 S["~type.mutability"],
5078 S["~type.optionality"],
5079 S["~type.constructor.default"],
5080 S["~encoded.mutability"],
5081 S["~encoded.optionality"]
5082 >
5083{
5084 readonly "Type": S["Type"] & Brand.Brand<B>
5085 readonly "Encoded": S["Encoded"]
5086 readonly "DecodingServices": S["DecodingServices"]
5087 readonly "EncodingServices": S["EncodingServices"]
5088 readonly "~type.make.in": S["~type.make.in"]
5089 readonly "~type.make": S["Type"] & Brand.Brand<B>
5090 readonly "Iso": S["Type"] & Brand.Brand<B>
5091 readonly schema: S
5092 readonly identifier: string
5093}
5094/**
5095 * Intersects a schema's output type with `Brand.Brand<B>` to prevent accidental
5096 * mixing of structurally identical types.
5097 *
5098 * **When to use**
5099 *
5100 * Use to make values decoded by an existing schema nominally distinct when the
5101 * schema already carries the runtime validation you need.
5102 *
5103 * **Gotchas**
5104 *
5105 * - `identifier` must be a single concrete string literal. Widened strings,
5106 * unions, and open template literal types are rejected.
5107 * - `brand` only narrows the TypeScript output type. It does not change the
5108 * schema's runtime AST or add runtime checks.
5109 * - Schema representations and generated schema code omit the brand. Reapply
5110 * `brand` after rebuilding or generating a schema when the nominal type is
5111 * still required.
5112 *
5113 * @see {@link fromBrand} for applying a Brand constructor's checks along with its branded type
5114 *
5115 * @category branding
5116 * @since 3.10.0
5117 */
5118export function brand<B extends string>(identifier: B & EnsureSingleBrandKey<B>) {
5119 return <S extends ConstraintRebuildable>(schema: S): brand<S["Rebuild"], B> =>
5120 make(schema.ast, { schema, identifier })
5121}
5122/**
5123 * Creates a branded schema from a {@link Brand.Constructor}, applying the
5124 * constructor's checks and branded type to the underlying schema.
5125 *
5126 * **When to use**
5127 *
5128 * Use to reuse the checks from a constructor with one concrete brand key.
5129 *
5130 * **Gotchas**
5131 *
5132 * `identifier` must match the constructor's only brand key. Apply `fromBrand`
5133 * repeatedly to compose distinct brands, and use {@link Union} to represent
5134 * alternatives.
5135 *
5136 * @see {@link brand} for adding a brand without constructor checks
5137 *
5138 * @category branding
5139 * @since 3.10.0
5140 */
5141export function fromBrand<A extends Brand.Brand<any>>(
5142 identifier: Brand.Brand.Keys<A> & string,
5143 ctor: Brand.Constructor<A> & EnsureSingleBrandKey<FromBrandKeys<A>>
5144) {
5145 type B = Brand.Brand.Keys<A> & string
5146 return <S extends Top & { readonly "Type": Brand.Brand.Unbranded<A> }>(
5147 self: S
5148 ): brand<S["Rebuild"], B> =>
5149 // The constructor already guarantees a single concrete brand key.
5150 (ctor.checks ? self.check(...ctor.checks) : self).pipe(brand<B>(identifier as B & EnsureSingleBrandKey<B>))
5151}
5152/**
5153 * Type-level representation returned by {@link middlewareDecoding}.
5154 *
5155 * @category decoding
5156 * @since 4.0.0
5157 */
5158export interface middlewareDecoding<S extends Constraint, RD> extends
5159 BottomLazy<
5160 S["ast"],
5161 middlewareDecoding<S, RD>,
5162 S["~type.parameters"],
5163 S["~type.mutability"],
5164 S["~type.optionality"],
5165 S["~type.constructor.default"],
5166 S["~encoded.mutability"],
5167 S["~encoded.optionality"]
5168 >
5169{
5170 readonly "Type": S["Type"]
5171 readonly "Encoded": S["Encoded"]
5172 readonly "DecodingServices": RD
5173 readonly "EncodingServices": S["EncodingServices"]
5174 readonly "~type.make.in": S["~type.make.in"]
5175 readonly "~type.make": S["~type.make"]
5176 readonly "Iso": S["Iso"]
5177 readonly schema: S
5178}
5179/**
5180 * Intercepts the decoding pipeline of a schema.
5181 *
5182 * **Details**
5183 *
5184 * The provided function receives the current decoding `Effect` and `ParseOptions`,
5185 * and returns a new `Effect` — potentially adding service requirements (`RD`),
5186 * recovering from errors, or augmenting the result.
5187 *
5188 * **Example** (Logging decode failures)
5189 *
5190 * ```ts import.meta.vitest
5191 * import { Effect, Schema } from "effect"
5192 *
5193 * const events: Array<string> = []
5194 * const Logged = Schema.String.pipe(
5195 * Schema.middlewareDecoding((effect) =>
5196 * Effect.tapError(effect, () => Effect.sync(() => events.push("decode failed")))
5197 * )
5198 * )
5199 * Effect.runSync(Effect.result(Schema.decodeUnknownEffect(Logged)(42)))
5200 * events // => ["decode failed"]
5201 * ```
5202 *
5203 * @see {@link catchDecoding} for a simpler error-recovery variant
5204 * @category decoding
5205 * @since 4.0.0
5206 */
5207export function middlewareDecoding<S extends Constraint, RD>(
5208 decode: (
5209 effect: Effect.Effect<Option_.Option<S["Type"]>, SchemaIssue.Issue, S["DecodingServices"]>,
5210 options: SchemaAST.ParseOptions
5211 ) => Effect.Effect<Option_.Option<S["Type"]>, SchemaIssue.Issue, RD>
5212) {
5213 return (schema: S): middlewareDecoding<S, RD> =>
5214 make(
5215 SchemaAST.middlewareDecoding(schema.ast, new SchemaTransformation.Middleware(decode, identity)),
5216 { schema }
5217 )
5218}
5219/**
5220 * Type-level representation returned by {@link middlewareEncoding}.
5221 *
5222 * @category encoding
5223 * @since 4.0.0
5224 */
5225export interface middlewareEncoding<S extends Constraint, RE> extends
5226 BottomLazy<
5227 S["ast"],
5228 middlewareEncoding<S, RE>,
5229 S["~type.parameters"],
5230 S["~type.mutability"],
5231 S["~type.optionality"],
5232 S["~type.constructor.default"],
5233 S["~encoded.mutability"],
5234 S["~encoded.optionality"]
5235 >
5236{
5237 readonly "Type": S["Type"]
5238 readonly "Encoded": S["Encoded"]
5239 readonly "DecodingServices": S["DecodingServices"]
5240 readonly "EncodingServices": RE
5241 readonly "~type.make.in": S["~type.make.in"]
5242 readonly "~type.make": S["~type.make"]
5243 readonly "Iso": S["Iso"]
5244 readonly schema: S
5245}
5246/**
5247 * Intercepts the encoding pipeline of a schema.
5248 *
5249 * **Details**
5250 *
5251 * The provided function receives the current encoding `Effect` and `ParseOptions`,
5252 * and returns a new `Effect` — potentially adding service requirements (`RE`),
5253 * recovering from errors, or augmenting the result.
5254 *
5255 * **Example** (Logging encode failures)
5256 *
5257 * ```ts import.meta.vitest
5258 * import { Effect, Schema } from "effect"
5259 *
5260 * const events: Array<string> = []
5261 * const Logged = Schema.String.pipe(
5262 * Schema.middlewareEncoding((effect) =>
5263 * Effect.tapError(effect, () => Effect.sync(() => events.push("encode failed")))
5264 * )
5265 * )
5266 * Effect.runSync(Effect.result(Schema.encodeUnknownEffect(Logged)(42)))
5267 * events // => ["encode failed"]
5268 * ```
5269 *
5270 * @see {@link catchEncoding} for a simpler error-recovery variant
5271 * @category encoding
5272 * @since 4.0.0
5273 */
5274export function middlewareEncoding<S extends Constraint, RE>(
5275 encode: (
5276 effect: Effect.Effect<Option_.Option<S["Encoded"]>, SchemaIssue.Issue, S["EncodingServices"]>,
5277 options: SchemaAST.ParseOptions
5278 ) => Effect.Effect<Option_.Option<S["Encoded"]>, SchemaIssue.Issue, RE>
5279) {
5280 return (schema: S): middlewareEncoding<S, RE> =>
5281 make(
5282 SchemaAST.middlewareEncoding(schema.ast, new SchemaTransformation.Middleware(identity, encode)),
5283 { schema }
5284 )
5285}
5286/**
5287 * Recovers from a decoding error by providing a fallback value.
5288 *
5289 * **Details**
5290 *
5291 * The handler receives the `Issue` and returns an `Effect` that either
5292 * succeeds with a fallback value or re-fails with a (possibly different) issue.
5293 *
5294 * **Example** (Returning a default on decode failure)
5295 *
5296 * ```ts import.meta.vitest
5297 * import { Effect, Option, Schema } from "effect"
5298 *
5299 * const schema = Schema.Number.pipe(
5300 * Schema.catchDecoding((_issue) => Effect.succeed(Option.some(0)))
5301 * )
5302 * Effect.runSync(Schema.decodeUnknownEffect(schema)("invalid")) // => 0
5303 * ```
5304 *
5305 * @see {@link catchDecodingWithContext} to add service requirements to the handler
5306 * @category error handling
5307 * @since 4.0.0
5308 */
5309export function catchDecoding<S extends Constraint>(
5310 f: (issue: SchemaIssue.Issue) => Effect.Effect<Option_.Option<S["Type"]>, SchemaIssue.Issue>
5311): (self: S) => middlewareDecoding<S, S["DecodingServices"]> {
5312 return catchDecodingWithContext(f)
5313}
5314/**
5315 * Recovers from a decoding error with a handler that may require Effect services.
5316 *
5317 * **When to use**
5318 *
5319 * Use when you need decoding fallback logic to require services from the Effect
5320 * context.
5321 *
5322 * **Details**
5323 *
5324 * The handler receives the `Issue` and returns an `Effect` that either succeeds
5325 * with a fallback value or re-fails with a (possibly different) issue. The
5326 * handler's services are added to the schema's decoding services.
5327 *
5328 * @see {@link catchDecoding} for recovery handlers that do not require services
5329 * @see {@link middlewareDecoding} for intercepting or replacing the full decoding pipeline
5330 *
5331 * @category error handling
5332 * @since 4.0.0
5333 */
5334export function catchDecodingWithContext<S extends Constraint, R = never>(
5335 f: (issue: SchemaIssue.Issue) => Effect.Effect<Option_.Option<S["Type"]>, SchemaIssue.Issue, R>
5336) {
5337 return (self: S): middlewareDecoding<S, S["DecodingServices"] | R> =>
5338 middlewareDecoding<S, S["DecodingServices"] | R>(Effect.catchEager(f))(self)
5339}
5340/**
5341 * Recovers from an encoding error by providing a fallback value.
5342 *
5343 * **Details**
5344 *
5345 * The handler receives the `Issue` and returns an `Effect` that either
5346 * succeeds with a fallback value or re-fails with a (possibly different) issue.
5347 *
5348 * @see {@link catchEncodingWithContext} to add service requirements to the handler
5349 * @category error handling
5350 * @since 4.0.0
5351 */
5352export function catchEncoding<S extends Constraint>(
5353 f: (issue: SchemaIssue.Issue) => Effect.Effect<Option_.Option<S["Encoded"]>, SchemaIssue.Issue>
5354): (self: S) => middlewareEncoding<S, S["EncodingServices"]> {
5355 return catchEncodingWithContext(f)
5356}
5357/**
5358 * Recovers from an encoding error with a handler that may require Effect services.
5359 *
5360 * **When to use**
5361 *
5362 * Use when you need encoding fallback logic to require services from the Effect
5363 * context.
5364 *
5365 * **Details**
5366 *
5367 * The handler receives the `Issue` and returns an `Effect` that either succeeds
5368 * with a fallback encoded value or re-fails with a (possibly different) issue.
5369 * The handler's services are added to the schema's encoding services.
5370 *
5371 * @see {@link catchEncoding} for recovery handlers that do not require services
5372 * @see {@link middlewareEncoding} for intercepting or replacing the full encoding pipeline
5373 *
5374 * @category error handling
5375 * @since 4.0.0
5376 */
5377export function catchEncodingWithContext<S extends Constraint, R = never>(
5378 f: (issue: SchemaIssue.Issue) => Effect.Effect<Option_.Option<S["Encoded"]>, SchemaIssue.Issue, R>
5379) {
5380 return (self: S): middlewareEncoding<S, S["EncodingServices"] | R> =>
5381 middlewareEncoding<S, S["EncodingServices"] | R>(Effect.catchEager(f))(self)
5382}
5383/**
5384 * Type-level representation returned by {@link decodeTo}.
5385 *
5386 * @category transforming
5387 * @since 4.0.0
5388 */
5389export interface decodeTo<To extends Constraint, From extends Constraint, RD = never, RE = never> extends
5390 BottomLazy<
5391 To["ast"],
5392 decodeTo<To, From, RD, RE>,
5393 To["~type.parameters"],
5394 To["~type.mutability"],
5395 To["~type.optionality"],
5396 To["~type.constructor.default"],
5397 From["~encoded.mutability"],
5398 From["~encoded.optionality"]
5399 >
5400{
5401 readonly "Type": To["Type"]
5402 readonly "Encoded": From["Encoded"]
5403 readonly "DecodingServices": To["DecodingServices"] | From["DecodingServices"] | RD
5404 readonly "EncodingServices": To["EncodingServices"] | From["EncodingServices"] | RE
5405 readonly "~type.make.in": To["~type.make.in"]
5406 readonly "~type.make": To["~type.make"]
5407 readonly "Iso": To["Iso"]
5408 readonly from: From
5409 readonly to: To
5410}
5411/**
5412 * Type-level representation returned by {@link decodeTo} without a custom transformation.
5413 *
5414 * @category transforming
5415 * @since 3.10.0
5416 */
5417export interface compose<To extends Constraint, From extends Constraint> extends decodeTo<To, From> {}
5418/**
5419 * Creates a schema that transforms from a source schema to a target schema.
5420 *
5421 * **When to use**
5422 *
5423 * Use when decoding should change the schema's decoded type or encoded shape,
5424 * with an optional custom bidirectional transformation.
5425 *
5426 * **Details**
5427 *
5428 * Call it with the target schema `to` and then pipe the source schema `from`
5429 * into the returned function. The resulting schema decodes from
5430 * `From["Encoded"]` to `To["Type"]` and encodes from `To["Type"]` back to
5431 * `From["Encoded"]`.
5432 *
5433 * When no transformation is provided, `SchemaTransformation.passthrough()` is
5434 * used, so `From["Type"]` must already be compatible with `To["Encoded"]`.
5435 * The resulting schema combines decoding and encoding services from both
5436 * schemas and any custom transformation.
5437 *
5438 * **Gotchas**
5439 *
5440 * In a custom transformation, `decode` maps `From["Type"]` to `To["Encoded"]`
5441 * and is used on the encoding path, while `encode` maps `To["Encoded"]` to
5442 * `From["Type"]` and is used on the decoding path.
5443 *
5444 * **Example** (Transforming strings to numbers with a schema transformation)
5445 *
5446 * ```ts import.meta.vitest
5447 * import { Schema, SchemaGetter } from "effect"
5448 *
5449 * const NumberFromString = Schema.String.pipe(
5450 * Schema.decodeTo(
5451 * Schema.Number,
5452 * {
5453 * decode: SchemaGetter.transform((s) => Number(s)),
5454 * encode: SchemaGetter.transform((n) => String(n))
5455 * }
5456 * )
5457 * )
5458 *
5459 * Schema.decodeUnknownSync(NumberFromString)("123") // => 123
5460 * ```
5461 *
5462 * @category transforming
5463 * @since 4.0.0
5464 */
5465export function decodeTo<To extends Constraint>(to: To): <From extends Constraint>(from: From) => compose<To, From>
5466export function decodeTo<To extends Constraint, From extends Constraint, RD = never, RE = never>(
5467 to: To,
5468 transformation: {
5469 readonly decode: SchemaGetter.Getter<NoInfer<To["Encoded"]>, NoInfer<From["Type"]>, RD>
5470 readonly encode: SchemaGetter.Getter<NoInfer<From["Type"]>, NoInfer<To["Encoded"]>, RE>
5471 }
5472): (from: From) => decodeTo<To, From, RD, RE>
5473export function decodeTo<To extends Constraint, From extends Constraint, RD = never, RE = never>(
5474 to: To,
5475 transformation?: {
5476 readonly decode: SchemaGetter.Getter<To["Encoded"], From["Type"], RD>
5477 readonly encode: SchemaGetter.Getter<From["Type"], To["Encoded"], RE>
5478 } | undefined
5479) {
5480 return (from: From) => {
5481 return make(
5482 SchemaAST.decodeTo(
5483 from.ast,
5484 to.ast,
5485 transformation ? SchemaTransformation.makeTransformation(transformation) : SchemaTransformation.passthrough()
5486 ),
5487 {
5488 from,
5489 to
5490 }
5491 )
5492 }
5493}
5494
5495/**
5496 * Constructs a decode-only `SchemaAST.Link`.
5497 *
5498 * @internal
5499 */
5500export function linkDecoding<T>(): <To extends Constraint>(
5501 to: To,
5502 decode: SchemaGetter.Getter<T, NoInfer<To["Type"]>>
5503) => SchemaAST.Link {
5504 return <To extends Constraint>(
5505 to: To,
5506 decode: SchemaGetter.Getter<T, NoInfer<To["Type"]>>
5507 ): SchemaAST.Link => link<T>()(to, { decode, encode: SchemaGetter.forbiddenEncoding })
5508}
5509
5510/** @internal */
5511export const TrueLiterals = Literals(["true", "yes", "on", "1", "y"])
5512
5513/** @internal */
5514export const FalseLiterals = Literals(["false", "no", "off", "0", "n"])
5515
5516/** @internal */
5517export const BooleanLiterals = Literals([...TrueLiterals.literals, ...FalseLiterals.literals]).pipe(
5518 decodeTo(
5519 Boolean,
5520 SchemaTransformation.transform({
5521 decode: (value) => value === "true" || value === "yes" || value === "on" || value === "1" || value === "y",
5522 encode: (value) => value ? "true" : "false"
5523 })
5524 )
5525)
5526/**
5527 * Applies a transformation to a schema, creating a new schema with the same type but transformed encoding/decoding.
5528 *
5529 * **When to use**
5530 *
5531 * Use when the decoded type stays the same and the transformation only
5532 * normalizes values during encoding and decoding.
5533 *
5534 * **Details**
5535 *
5536 * Call it with a transformation object and then pipe a schema into the returned
5537 * function. The resulting schema keeps the same `Type` and `Encoded` types as
5538 * the source schema, while applying the transformation during both decoding and
5539 * encoding.
5540 *
5541 * Internally this uses `toType(self)` as the target schema and combines service
5542 * requirements from the source schema and the transformation.
5543 *
5544 * **Gotchas**
5545 *
5546 * Use {@link decodeTo} instead when the transformation should change the
5547 * decoded type. For this helper, both transformation getters operate on
5548 * `S["Type"]` values.
5549 *
5550 * **Example** (Trimming string values during encoding/decoding)
5551 *
5552 * ```ts import.meta.vitest
5553 * import { Schema, SchemaGetter } from "effect"
5554 *
5555 * const Trimmed = Schema.String.pipe(
5556 * Schema.decode({
5557 * decode: SchemaGetter.transform((s) => s.trim()),
5558 * encode: SchemaGetter.transform((s) => s.trim())
5559 * })
5560 * )
5561 *
5562 * Schema.decodeUnknownSync(Trimmed)(" hello ") // => "hello"
5563 * ```
5564 *
5565 * @category transforming
5566 * @since 4.0.0
5567 */
5568export function decode<S extends Constraint, RD = never, RE = never>(transformation: {
5569 readonly decode: SchemaGetter.Getter<S["Type"], S["Type"], RD>
5570 readonly encode: SchemaGetter.Getter<S["Type"], S["Type"], RE>
5571}) {
5572 return (self: S): decodeTo<toType<S>, S, RD, RE> => {
5573 return decodeTo<toType<S>, S, RD, RE>(toType(self), transformation)(self)
5574 }
5575}
5576/**
5577 * Reverses a schema transformation so the encoded schema is supplied first.
5578 *
5579 * **When to use**
5580 *
5581 * Use to define a transformation by naming the encoded schema before the
5582 * decoded schema.
5583 *
5584 * **Details**
5585 *
5586 * `encodeTo(to)(from)` is equivalent to `to.pipe(decodeTo(from))`. The `from`
5587 * schema acts as the target decoded schema and `to` acts as the encoded source.
5588 *
5589 * **Example** (Encoding a number back to a string)
5590 *
5591 * ```ts import.meta.vitest
5592 * import { Schema, SchemaGetter } from "effect"
5593 *
5594 * const NumberFromString = Schema.Number.pipe(
5595 * Schema.encodeTo(Schema.String, {
5596 * decode: SchemaGetter.transform((s: string) => Number(s)),
5597 * encode: SchemaGetter.transform((n: number) => String(n))
5598 * })
5599 * )
5600 * Schema.decodeSync(NumberFromString)("42") // => 42
5601 * ```
5602 *
5603 * @category transforming
5604 * @since 4.0.0
5605 */
5606export function encodeTo<To extends Constraint>(
5607 to: To
5608): <From extends Constraint>(from: From) => compose<From, To>
5609export function encodeTo<To extends Constraint, From extends Constraint, RD = never, RE = never>(
5610 to: To,
5611 transformation: {
5612 readonly decode: SchemaGetter.Getter<NoInfer<From["Encoded"]>, NoInfer<To["Type"]>, RD>
5613 readonly encode: SchemaGetter.Getter<NoInfer<To["Type"]>, NoInfer<From["Encoded"]>, RE>
5614 }
5615): (from: From) => decodeTo<From, To, RD, RE>
5616export function encodeTo<To extends Constraint, From extends Constraint, RD = never, RE = never>(
5617 to: To,
5618 transformation?: {
5619 readonly decode: SchemaGetter.Getter<From["Encoded"], To["Type"], RD>
5620 readonly encode: SchemaGetter.Getter<To["Type"], From["Encoded"], RE>
5621 }
5622) {
5623 return (from: From): decodeTo<From, To, RD, RE> => {
5624 return transformation ?
5625 decodeTo<From, To, RD, RE>(from, transformation)(to) :
5626 decodeTo<From>(from)(to)
5627 }
5628}
5629/**
5630 * Applies a transformation to a schema's encoded type, creating a new schema where encoding/decoding
5631 * operate on `S["Encoded"]` rather than `S["Type"]`.
5632 *
5633 * **Details**
5634 *
5635 * The `decode` getter maps `S["Encoded"]` → `S["Encoded"]` (applied during decoding),
5636 * and the `encode` getter maps `S["Encoded"]` → `S["Encoded"]` (applied during encoding).
5637 *
5638 * **Example** (Upper-casing encoded strings)
5639 *
5640 * ```ts import.meta.vitest
5641 * import { Schema, SchemaGetter } from "effect"
5642 *
5643 * const UpperFromLower = Schema.String.pipe(
5644 * Schema.encode({
5645 * decode: SchemaGetter.transform((s: string) => s.toLowerCase()),
5646 * encode: SchemaGetter.transform((s: string) => s.toUpperCase())
5647 * })
5648 * )
5649 * Schema.encodeSync(UpperFromLower)("hello") // => "HELLO"
5650 * ```
5651 *
5652 * @category transforming
5653 * @since 4.0.0
5654 */
5655export function encode<S extends Constraint, RD = never, RE = never>(transformation: {
5656 readonly decode: SchemaGetter.Getter<S["Encoded"], S["Encoded"], RD>
5657 readonly encode: SchemaGetter.Getter<S["Encoded"], S["Encoded"], RE>
5658}) {
5659 return (self: S): decodeTo<S, toEncoded<S>, RD, RE> => {
5660 return decodeTo<S, toEncoded<S>, RD, RE>(self, transformation)(toEncoded(self))
5661 }
5662}
5663/**
5664 * Constraint used to ensure a schema field does not already have a constructor default.
5665 *
5666 * **Details**
5667 *
5668 * Only schemas that satisfy this constraint can be passed to {@link withConstructorDefault}.
5669 *
5670 * @category models
5671 * @since 4.0.0
5672 */
5673export interface WithoutConstructorDefault {
5674 readonly "~type.constructor.default": "no-default"
5675}
5676/**
5677 * Type-level representation returned by {@link withConstructorDefault}.
5678 *
5679 * @category constructors
5680 * @since 3.10.0
5681 */
5682export interface withConstructorDefault<S extends Constraint & WithoutConstructorDefault> extends
5683 BottomLazy<
5684 S["ast"],
5685 withConstructorDefault<S>,
5686 S["~type.parameters"],
5687 S["~type.mutability"],
5688 S["~type.optionality"],
5689 "with-default",
5690 S["~encoded.mutability"],
5691 S["~encoded.optionality"]
5692 >
5693{
5694 readonly "Type": S["Type"]
5695 readonly "Encoded": S["Encoded"]
5696 readonly "DecodingServices": S["DecodingServices"]
5697 readonly "EncodingServices": S["EncodingServices"]
5698 readonly "~type.make.in": S["~type.make.in"]
5699 readonly "~type.make": S["~type.make"]
5700 readonly "Iso": S["Iso"]
5701 readonly schema: S
5702}
5703/**
5704 * Attaches a constructor default value to a schema field.
5705 *
5706 * **Details**
5707 *
5708 * Constructor defaults are applied only during `make*`, not during decoding or
5709 * encoding. Failures are represented directly as `SchemaIssue.Issue` values.
5710 *
5711 * **Example** (Defining an optional field with a static default)
5712 *
5713 * ```ts import.meta.vitest
5714 * import { Effect, Schema } from "effect"
5715 *
5716 * const MySchema = Schema.Struct({
5717 * name: Schema.String.pipe(
5718 * Schema.optionalKey,
5719 * Schema.withConstructorDefault(Effect.succeed("anonymous"))
5720 * )
5721 * })
5722 *
5723 * MySchema.make({}).name // => "anonymous"
5724 * ```
5725 *
5726 * @category constructors
5727 * @since 3.10.0
5728 */
5729export function withConstructorDefault<S extends Constraint & WithoutConstructorDefault>(
5730 // `S["~type.make.in"]` instead of `S["Type"]` is intentional here because
5731 // it makes easier to define the default value if there are nested defaults
5732 defaultValue: Effect.Effect<S["~type.make.in"], SchemaIssue.Issue>
5733) {
5734 return (schema: S): withConstructorDefault<S> =>
5735 make(SchemaAST.withConstructorDefault(schema.ast, defaultValue), { schema })
5736}
5737/**
5738 * Type-level representation returned by {@link withDecodingDefaultKey}.
5739 *
5740 * @category decoding
5741 * @since 4.0.0
5742 */
5743export interface withDecodingDefaultKey<S extends Constraint, R = never>
5744 extends decodeTo<S, optionalKey<toEncoded<S>>, R>
5745{
5746 readonly "Rebuild": withDecodingDefaultKey<S, R>
5747}
5748/**
5749 * Options for {@link withDecodingDefaultKey} and {@link withDecodingDefault}.
5750 *
5751 * **Details**
5752 *
5753 * - `encodingStrategy`:
5754 * - `"passthrough"` (default): pass the value through during encoding
5755 * - `"omit"`: omit the key from the encoded output
5756 *
5757 * @category options
5758 * @since 4.0.0
5759 */
5760export type DecodingDefaultOptions = {
5761 readonly encodingStrategy?: "omit" | "passthrough" | undefined
5762}
5763
5764function toIssueEffect<A, R>(
5765 self: Effect.Effect<A, SchemaError, R>
5766): Effect.Effect<A, SchemaIssue.Issue, R> {
5767 return Effect.catchCause(self, (cause) => Effect.failCauseSync(() => Cause_.map(cause, (error) => error.issue)))
5768}
5769/**
5770 * Makes a struct key optional on the `Encoded` side and provides a default
5771 * `Encoded` value when the key is missing during decoding.
5772 *
5773 * **Details**
5774 *
5775 * The key uses `optionalKey` on the encoded side, so it may be absent from the
5776 * input object but **not** `undefined`. The default value is specified in terms
5777 * of the `Encoded` type (before any decoding transformations).
5778 *
5779 * Options:
5780 *
5781 * - `encodingStrategy`:
5782 * - `"passthrough"` (default): include the value in the encoded output.
5783 * - `"omit"`: omit the key from the encoded output.
5784 *
5785 * **Example** (Providing a default for a missing struct key)
5786 *
5787 * ```ts import.meta.vitest
5788 * import { Effect, Schema } from "effect"
5789 *
5790 * const MySchema = Schema.Struct({
5791 * name: Schema.String.pipe(Schema.withDecodingDefaultKey(Effect.succeed("anonymous")))
5792 * })
5793 *
5794 * Schema.decodeUnknownSync(MySchema)({}).name // => "anonymous"
5795 * ```
5796 *
5797 * @see {@link withDecodingDefault} for the value-level variant (key absent **or** `undefined`)
5798 * @see {@link withDecodingDefaultTypeKey} for the variant where the default is a `Type` value
5799 * @category decoding
5800 * @since 4.0.0
5801 */
5802export function withDecodingDefaultKey<S extends Constraint, R = never>(
5803 defaultValue: Effect.Effect<S["Encoded"], SchemaError, R>,
5804 options?: DecodingDefaultOptions
5805): (self: S) => withDecodingDefaultKey<S, R> {
5806 const encode = options?.encodingStrategy === "omit" ? SchemaGetter.omit() : SchemaGetter.passthrough()
5807 return (self: S): withDecodingDefaultKey<S, R> => {
5808 return optionalKey(toEncoded(self)).pipe(decodeTo(self, {
5809 decode: SchemaGetter.withDefault(toIssueEffect(defaultValue)),
5810 encode
5811 }))
5812 }
5813}
5814/**
5815 * Type-level representation returned by {@link withDecodingDefaultTypeKey}.
5816 *
5817 * @category decoding
5818 * @since 4.0.0
5819 */
5820export interface withDecodingDefaultTypeKey<S extends Constraint, R = never>
5821 extends decodeTo<withDecodingDefaultKey<toType<S>, R>, optionalKey<S>>
5822{
5823 readonly "Rebuild": withDecodingDefaultTypeKey<S, R>
5824}
5825/**
5826 * Makes a struct key optional on the `Encoded` side (`optionalKey`, so the
5827 * key may be absent but **not** `undefined`) and provides a default `Type`
5828 * value when the key is missing during decoding.
5829 *
5830 * **Details**
5831 *
5832 * Unlike {@link withDecodingDefaultKey}, the default value is specified in
5833 * terms of the `Type` (decoded) representation, so it does not need to go
5834 * through the decoding transformation.
5835 *
5836 * Options:
5837 *
5838 * - `encodingStrategy`:
5839 * - `"passthrough"` (default): include the value in the encoded output.
5840 * - `"omit"`: omit the key from the encoded output.
5841 *
5842 * @see {@link withDecodingDefaultKey} for the variant where the default is an `Encoded` value
5843 * @see {@link withDecodingDefaultType} for the value-level variant
5844 * @category decoding
5845 * @since 4.0.0
5846 */
5847export function withDecodingDefaultTypeKey<S extends Constraint, R = never>(
5848 defaultValue: Effect.Effect<S["Type"], SchemaError, R>,
5849 options?: DecodingDefaultOptions
5850): (self: S) => withDecodingDefaultTypeKey<S, R> {
5851 return (self: S): withDecodingDefaultTypeKey<S, R> => {
5852 return toType(self).pipe(
5853 withDecodingDefaultKey<toType<S>, R>(defaultValue, options),
5854 encodeTo(optionalKey(self))
5855 )
5856 }
5857}
5858/**
5859 * Type-level representation returned by {@link withDecodingDefault}.
5860 *
5861 * @category decoding
5862 * @since 3.10.0
5863 */
5864export interface withDecodingDefault<S extends Constraint, R = never> extends decodeTo<S, optional<toEncoded<S>>, R> {
5865 readonly "Rebuild": withDecodingDefault<S, R>
5866}
5867/**
5868 * Wraps the `Encoded` side with `optional` (key absent **or** `undefined`)
5869 * and provides a default `Encoded` value when the field is missing or
5870 * `undefined` during decoding.
5871 *
5872 * **When to use**
5873 *
5874 * Use when the default is expressed in the encoded representation, before the
5875 * field's decoding transformation runs.
5876 *
5877 * **Details**
5878 *
5879 * The default value is specified in terms of the `Encoded` type (before any
5880 * decoding transformations).
5881 *
5882 * Options:
5883 *
5884 * - `encodingStrategy`:
5885 * - `"passthrough"` (default): include the value in the encoded output.
5886 * - `"omit"`: omit the key from the encoded output.
5887 *
5888 * **Example** (Providing a default for an optional field value)
5889 *
5890 * ```ts import.meta.vitest
5891 * import { Effect, Schema } from "effect"
5892 *
5893 * const MySchema = Schema.Struct({
5894 * name: Schema.String.pipe(Schema.optional, Schema.withDecodingDefault(Effect.succeed("anonymous")))
5895 * })
5896 *
5897 * Schema.decodeUnknownSync(MySchema)({ name: undefined }).name // => "anonymous"
5898 * ```
5899 *
5900 * @see {@link withDecodingDefaultKey} for the key-level variant (key absent only, not `undefined`)
5901 * @see {@link withDecodingDefaultType} for the variant where the default is a `Type` value
5902 * @category decoding
5903 * @since 3.10.0
5904 */
5905export function withDecodingDefault<S extends Constraint, R = never>(
5906 defaultValue: Effect.Effect<S["Encoded"], SchemaError, R>,
5907 options?: DecodingDefaultOptions
5908): (self: S) => withDecodingDefault<S, R> {
5909 const encode = options?.encodingStrategy === "omit" ? SchemaGetter.omit() : SchemaGetter.passthrough()
5910 return (self: S): withDecodingDefault<S, R> => {
5911 return optional(toEncoded(self)).pipe(decodeTo(self, {
5912 decode: SchemaGetter.withDefault(toIssueEffect(defaultValue)),
5913 encode
5914 }))
5915 }
5916}
5917/**
5918 * Type-level representation returned by {@link withDecodingDefaultType}.
5919 *
5920 * @category decoding
5921 * @since 4.0.0
5922 */
5923export interface withDecodingDefaultType<S extends Constraint, R = never>
5924 extends decodeTo<withDecodingDefault<toType<S>, R>, optional<S>>
5925{
5926 readonly "Rebuild": withDecodingDefaultType<S, R>
5927}
5928/**
5929 * Wraps the `Encoded` side with `optional` (key absent **or** `undefined`)
5930 * and provides a default `Type` value when the field is missing or
5931 * `undefined` during decoding.
5932 *
5933 * **When to use**
5934 *
5935 * Use when the default is already in the decoded representation and should not
5936 * pass through the field's decoding transformation.
5937 *
5938 * **Details**
5939 *
5940 * Unlike {@link withDecodingDefault}, the default value is specified in terms
5941 * of the `Type` (decoded) representation, so it does not need to go through
5942 * the decoding transformation.
5943 *
5944 * Options:
5945 *
5946 * - `encodingStrategy`:
5947 * - `"passthrough"` (default): include the value in the encoded output.
5948 * - `"omit"`: omit the key from the encoded output.
5949 *
5950 * @see {@link withDecodingDefault} for the variant where the default is an `Encoded` value
5951 * @see {@link withDecodingDefaultTypeKey} for the key-level variant
5952 * @category decoding
5953 * @since 4.0.0
5954 */
5955export function withDecodingDefaultType<S extends Constraint, R = never>(
5956 defaultValue: Effect.Effect<S["Type"], SchemaError, R>,
5957 options?: DecodingDefaultOptions
5958): (self: S) => withDecodingDefaultType<S, R> {
5959 return (self: S): withDecodingDefaultType<S, R> => {
5960 return toType(self).pipe(
5961 withDecodingDefault<toType<S>, R>(defaultValue, options),
5962 encodeTo(optional(self))
5963 )
5964 }
5965}
5966/**
5967 * Type-level representation returned by {@link tag}.
5968 *
5969 * @category constructors
5970 * @since 3.10.0
5971 */
5972export interface tag<Tag extends SchemaAST.LiteralValue> extends withConstructorDefault<Literal<Tag>> {}
5973/**
5974 * Combines a {@link Literal} schema with {@link withConstructorDefault}, making it ideal
5975 * for discriminator fields in tagged unions. When constructing via `make`, the
5976 * `_tag` field can be omitted and will be filled automatically.
5977 *
5978 * **Example** (Defining a discriminated union tag)
5979 *
5980 * ```ts import.meta.vitest
5981 * import { Schema } from "effect"
5982 *
5983 * const A = Schema.Struct({ _tag: Schema.tag("A"), value: Schema.Number })
5984 *
5985 * // _tag is optional in make, auto-filled to "A"
5986 * const a = A.make({ value: 42 })
5987 * a // => { _tag: "A", value: 42 }
5988 * ```
5989 *
5990 * @see {@link tagDefaultOmit} to also omit the tag during encoding
5991 * @see {@link TaggedStruct} for a shorthand that adds `_tag` automatically
5992 * @category constructors
5993 * @since 3.10.0
5994 */
5995export function tag<Tag extends SchemaAST.LiteralValue>(literal: Tag): tag<Tag> {
5996 return Literal(literal).pipe(withConstructorDefault(Effect.succeed(literal)))
5997}
5998/**
5999 * Creates a literal `_tag` schema that is omitted from encoded output.
6000 *
6001 * **When to use**
6002 *
6003 * Use to decode data that omits the discriminator field while still constructing
6004 * values with a `_tag` for tagged union matching.
6005 *
6006 * **Details**
6007 *
6008 * The tag is filled during decoding and construction, like {@link tag}, but is
6009 * omitted when encoding.
6010 *
6011 * **Example** (Omitting tags during encoding)
6012 *
6013 * ```ts import.meta.vitest
6014 * import { Schema } from "effect"
6015 *
6016 * const A = Schema.Struct({
6017 * _tag: Schema.tagDefaultOmit("A"),
6018 * value: Schema.Number
6019 * })
6020 *
6021 * // Encode strips the _tag field
6022 * Schema.encodeUnknownSync(A)({ _tag: "A", value: 1 }) // => { value: 1 }
6023 * ```
6024 *
6025 * @see {@link tag} for the variant that keeps the tag during encoding
6026 * @category constructors
6027 * @since 4.0.0
6028 */
6029export function tagDefaultOmit<Tag extends SchemaAST.LiteralValue>(literal: Tag) {
6030 return tag(literal).pipe(withDecodingDefaultKey(Effect.succeed(literal), { encodingStrategy: "omit" }))
6031}
6032/**
6033 * Type-level representation returned by {@link TaggedStruct}.
6034 *
6035 * @category models
6036 * @since 3.10.0
6037 */
6038export type TaggedStruct<Tag extends SchemaAST.LiteralValue, Fields extends Struct.Fields> = Struct<
6039 Simplify<{ readonly _tag: tag<Tag> } & Fields>
6040>
6041/**
6042 * Creates a struct schema with an automatically populated `_tag` field.
6043 *
6044 * **When to use**
6045 *
6046 * Use to define a tagged union case from a literal tag and a set of fields.
6047 *
6048 * **Details**
6049 *
6050 * When using the `make` method, the `_tag` field is optional and will be
6051 * added automatically. However, when decoding or encoding, the `_tag` field
6052 * must be present in the input.
6053 *
6054 * **Example** (Defining a tagged struct shorthand)
6055 *
6056 * ```ts import.meta.vitest
6057 * import { Schema } from "effect"
6058 *
6059 * // Defines a struct with a fixed `_tag` field
6060 * const tagged = Schema.TaggedStruct("A", {
6061 * a: Schema.String
6062 * })
6063 *
6064 * // This is the same as writing:
6065 * const equivalent = Schema.Struct({
6066 * _tag: Schema.tag("A"),
6067 * a: Schema.String
6068 * })
6069 * void tagged
6070 * void equivalent
6071 * ```
6072 *
6073 * **Example** (Accessing the literal value of the tag)
6074 *
6075 * ```ts import.meta.vitest
6076 * import { Schema } from "effect"
6077 *
6078 * const tagged = Schema.TaggedStruct("A", {
6079 * a: Schema.String
6080 * })
6081 *
6082 * tagged.fields._tag.schema.literal // => "A"
6083 * ```
6084 *
6085 * @category constructors
6086 * @since 3.10.0
6087 */
6088export function TaggedStruct<const Tag extends SchemaAST.LiteralValue, const Fields extends Struct.Fields>(
6089 value: Tag,
6090 fields: Fields
6091): TaggedStruct<Tag, Fields> {
6092 return Struct({ _tag: tag(value), ...fields }) as any
6093}
6094/**
6095 * Recursively flatten any nested Schema.Union members into a single tuple of leaf schemas.
6096 */
6097type Flatten<Schemas> = Schemas extends readonly [infer Head, ...infer Tail]
6098 ? Head extends Union<infer Inner> ? [...Flatten<Inner>, ...Flatten<Tail>]
6099 : [Head, ...Flatten<Tail>]
6100 : []
6101type MatchCasesResult<Cases> = {
6102 [K in keyof Cases]-?: NonNullable<Cases[K]> extends (...args: Array<any>) => infer R ? R : never
6103}[keyof Cases]
6104type MatchOrElseResult<Cases, OrElse extends (...args: Array<any>) => any> = Unify<
6105 MatchCasesResult<Cases> | ReturnType<OrElse>
6106>
6107type TaggedUnionUtils<
6108 Tag extends PropertyKey,
6109 Members extends ReadonlyArray<Constraint & { readonly Type: { readonly [K in Tag]: PropertyKey } }>,
6110 Flattened extends ReadonlyArray<Constraint & { readonly Type: { readonly [K in Tag]: PropertyKey } }> = Flatten<
6111 Members
6112 >
6113> = {
6114 /**
6115 * Discriminant values in flattened member order.
6116 */
6117 readonly discriminants: { readonly [I in keyof Flattened]: Flattened[I]["Type"][Tag] }
6118 readonly cases: Simplify<{ [M in Flattened[number] as M["Type"][Tag]]: M }>
6119 readonly isAnyOf: <const Keys>(
6120 keys: ReadonlyArray<Keys>
6121 ) => (value: Members[number]["Type"]) => value is Extract<Members[number]["Type"], { readonly [K in Tag]: Keys }>
6122 readonly guards: { [M in Flattened[number] as M["Type"][Tag]]: (u: unknown) => u is M["Type"] }
6123 readonly match: {
6124 <
6125 Cases extends { [M in Flattened[number] as M["Type"][Tag]]: (value: M["Type"]) => any }
6126 >(
6127 value: Members[number]["Type"],
6128 cases: Cases
6129 ): Cases[keyof Cases] extends (value: any) => infer R ? Unify<R>
6130 : never
6131 <
6132 Cases extends { [M in Flattened[number] as M["Type"][Tag]]: (value: M["Type"]) => any }
6133 >(
6134 cases: Cases
6135 ): (value: Members[number]["Type"]) => Cases[keyof Cases] extends (value: any) => infer R ? Unify<R>
6136 : never
6137 }
6138 readonly matchOrElse: {
6139 <
6140 Cases extends
6141 & { [M in Flattened[number] as M["Type"][Tag]]+?: (value: M["Type"]) => any }
6142 & { [K in Exclude<keyof Cases, Flattened[number]["Type"][Tag]>]: never },
6143 OrElse extends (
6144 value: Exclude<Members[number]["Type"], { readonly [K in Tag]: keyof Cases }>
6145 ) => any
6146 >(
6147 value: Members[number]["Type"],
6148 cases: Cases,
6149 orElse: OrElse
6150 ): MatchOrElseResult<Cases, OrElse>
6151 <
6152 Cases extends
6153 & { [M in Flattened[number] as M["Type"][Tag]]+?: (value: M["Type"]) => any }
6154 & { [K in Exclude<keyof Cases, Flattened[number]["Type"][Tag]>]: never },
6155 OrElse extends (
6156 value: Exclude<Members[number]["Type"], { readonly [K in Tag]: keyof Cases }>
6157 ) => any
6158 >(
6159 cases: Cases,
6160 orElse: OrElse
6161 ): (value: Members[number]["Type"]) => MatchOrElseResult<Cases, OrElse>
6162 }
6163}
6164/**
6165 * Type-level representation returned by {@link toTaggedUnion}.
6166 *
6167 * @category combinators
6168 * @since 4.0.0
6169 */
6170export type toTaggedUnion<
6171 Tag extends PropertyKey,
6172 Members extends ReadonlyArray<Constraint & { readonly Type: { readonly [K in Tag]: PropertyKey } }>
6173> = Union<Members> & TaggedUnionUtils<Tag, Members>
6174/**
6175 * Augments an existing {@link Union} of tagged structs with utility methods and an ordered tuple of discriminant
6176 * values.
6177 *
6178 * **Gotchas**
6179 *
6180 * Throws if multiple members use the same discriminant property key.
6181 *
6182 * **Example** (Adding tagged-union utilities to an existing union)
6183 *
6184 * ```ts import.meta.vitest
6185 * import { Schema } from "effect"
6186 *
6187 * const A = Schema.TaggedStruct("A", { value: Schema.Number })
6188 * const B = Schema.TaggedStruct("B", { name: Schema.String })
6189 *
6190 * const MyUnion = Schema.Union([A, B]).pipe(Schema.toTaggedUnion("_tag"))
6191 *
6192 * // Pattern-match on the union
6193 * const result = MyUnion.match({ _tag: "A", value: 1 }, {
6194 * A: (a) => `number: ${a.value}`,
6195 * B: (b) => `name: ${b.name}`
6196 * })
6197 * result // => "number: 1"
6198 * ```
6199 *
6200 * @see {@link TaggedUnion} for a shorthand that builds the union from scratch
6201 * @category combinators
6202 * @since 4.0.0
6203 */
6204export function toTaggedUnion<const Tag extends PropertyKey>(tag: Tag) {
6205 return <const Members extends ReadonlyArray<Constraint & { readonly Type: { readonly [K in Tag]: PropertyKey } }>>(
6206 self: Union<Members>
6207 ): toTaggedUnion<Tag, Members> => {
6208 const cases: Record<PropertyKey, unknown> = {}
6209 const discriminants: Array<PropertyKey> = []
6210 const discriminantKeys = new Set<string | symbol>()
6211 const guards: Record<PropertyKey, (u: unknown) => boolean> = {}
6212 const isAnyOf = (keys: ReadonlyArray<PropertyKey>) => (value: Members[number]["Type"]) => keys.includes(value[tag])
6213
6214 walk(self)
6215
6216 return Object.assign(self, { cases, discriminants, isAnyOf, guards, match, matchOrElse }) as any
6217
6218 function walk(schema: Constraint) {
6219 const ast = schema.ast
6220
6221 if (
6222 SchemaAST.isUnion(ast) && "members" in schema && globalThis.Array.isArray(schema.members) &&
6223 schema.members.every(isSchema)
6224 ) {
6225 return schema.members.forEach(walk)
6226 }
6227
6228 const sentinels = SchemaAST.collectSentinels(ast)
6229 if (sentinels.length > 0) {
6230 const literal = sentinels.find((s) => s.key === tag)?.literal
6231 if (Predicate.isPropertyKey(literal)) {
6232 const key = typeof literal === "number" ? globalThis.String(literal) : literal
6233 if (discriminantKeys.has(key)) {
6234 throw new globalThis.Error(`Duplicate discriminant: ${globalThis.String(literal)}`)
6235 }
6236 discriminantKeys.add(key)
6237 discriminants.push(literal)
6238 InternalRecord.assignProperty(cases, literal, schema)
6239 InternalRecord.assignProperty(guards, literal, SchemaParser.is(toType(schema)))
6240 return
6241 }
6242 }
6243
6244 throw new globalThis.Error("No literal or unique symbol found")
6245 }
6246
6247 function match() {
6248 if (arguments.length === 1) {
6249 const cases = arguments[0]
6250 return function(value: any) {
6251 const key = value[tag]
6252 const handler = Object.hasOwn(cases, key) ? cases[key] : undefined
6253 return handler(value)
6254 }
6255 }
6256 const value = arguments[0]
6257 const cases = arguments[1]
6258 const key = value[tag]
6259 const handler = Object.hasOwn(cases, key) ? cases[key] : undefined
6260 return handler(value)
6261 }
6262
6263 function matchOrElse() {
6264 if (arguments.length === 2) {
6265 const cases = arguments[0]
6266 const orElse = arguments[1]
6267 return function(value: any) {
6268 const key = value[tag]
6269 const handler = Object.hasOwn(cases, key) ? cases[key] ?? orElse : orElse
6270 return handler(value)
6271 }
6272 }
6273 const value = arguments[0]
6274 const cases = arguments[1]
6275 const orElse = arguments[2]
6276 const key = value[tag]
6277 const handler = Object.hasOwn(cases, key) ? cases[key] ?? orElse : orElse
6278 return handler(value)
6279 }
6280 }
6281}
6282/**
6283 * Type-level representation returned by {@link TaggedUnion}.
6284 *
6285 * @category models
6286 * @since 4.0.0
6287 */
6288export interface TaggedUnion<Cases extends Record<string, Constraint>> extends
6289 BottomLazy<
6290 SchemaAST.Union<SchemaAST.Objects>,
6291 TaggedUnion<Cases>
6292 >
6293{
6294 readonly "Type": { [K in keyof Cases]: Cases[K]["Type"] }[keyof Cases]
6295 readonly "Encoded": { [K in keyof Cases]: Cases[K]["Encoded"] }[keyof Cases]
6296 readonly "DecodingServices": { [K in keyof Cases]: Cases[K]["DecodingServices"] }[keyof Cases]
6297 readonly "EncodingServices": { [K in keyof Cases]: Cases[K]["EncodingServices"] }[keyof Cases]
6298 readonly "~type.make.in": { [K in keyof Cases]: Cases[K]["~type.make"] }[keyof Cases]
6299 readonly "~type.make": { [K in keyof Cases]: Cases[K]["~type.make"] }[keyof Cases]
6300 readonly "Iso": { [K in keyof Cases]: Cases[K]["Type"] }[keyof Cases]
6301 readonly cases: Cases
6302 readonly isAnyOf: <const Keys>(
6303 keys: ReadonlyArray<Keys>
6304 ) => (value: Cases[keyof Cases]["Type"]) => value is Extract<Cases[keyof Cases]["Type"], { _tag: Keys }>
6305 readonly guards: { [K in keyof Cases]: (u: unknown) => u is Cases[K]["Type"] }
6306 readonly match: {
6307 <Output>(
6308 cases: { [K in keyof Cases]: (value: Cases[K]["Type"]) => Output }
6309 ): (value: Cases[keyof Cases]["Type"]) => Output
6310 <Output>(
6311 value: Cases[keyof Cases]["Type"],
6312 cases: { [K in keyof Cases]: (value: Cases[K]["Type"]) => Output }
6313 ): Output
6314 }
6315 readonly matchOrElse: {
6316 <Output>(
6317 value: Cases[keyof Cases]["Type"],
6318 cases: { [K in keyof Cases]?: (value: Cases[K]["Type"]) => Output },
6319 orElse: (value: Cases[keyof Cases]["Type"]) => Output
6320 ): Output
6321 <Output>(
6322 cases: { [K in keyof Cases]?: (value: Cases[K]["Type"]) => Output },
6323 orElse: (value: Cases[keyof Cases]["Type"]) => Output
6324 ): (value: Cases[keyof Cases]["Type"]) => Output
6325 }
6326}
6327/**
6328 * Builds a discriminated union from a record of field sets, one per variant.
6329 * Each key becomes the `_tag` literal and the value is passed to {@link TaggedStruct}.
6330 * The result includes `cases`, `guards`, `isAnyOf`, `match`, and `matchOrElse` utilities.
6331 *
6332 * **Example** (Pattern matching a discriminated union)
6333 *
6334 * ```ts import.meta.vitest
6335 * import { Schema } from "effect"
6336 *
6337 * const Shape = Schema.TaggedUnion({
6338 * Circle: { radius: Schema.Number },
6339 * Rectangle: { width: Schema.Number, height: Schema.Number }
6340 * })
6341 *
6342 * // Pattern-match on a decoded value
6343 * const area = Shape.match({ _tag: "Circle", radius: 5 }, {
6344 * Circle: (c) => Math.PI * c.radius ** 2,
6345 * Rectangle: (r) => r.width * r.height
6346 * })
6347 * Math.round(area * 100) / 100 // => 78.54
6348 * ```
6349 *
6350 * @see {@link toTaggedUnion} to augment an existing union instead
6351 * @category constructors
6352 * @since 4.0.0
6353 */
6354export function TaggedUnion<const CasesByTag extends Record<string, Struct.Fields>>(
6355 casesByTag: CasesByTag
6356): TaggedUnion<{ readonly [K in keyof CasesByTag & string]: TaggedStruct<K, CasesByTag[K]> }> {
6357 const cases: any = {}
6358 const members: any = []
6359 for (const key of Object.keys(casesByTag)) {
6360 const member = TaggedStruct(key, casesByTag[key])
6361 InternalRecord.assignProperty(cases, key, member)
6362 members.push(member)
6363 }
6364 const union = Union(members)
6365 const { guards, isAnyOf, match, matchOrElse } = toTaggedUnion("_tag")(union)
6366 return make(union.ast, { cases, isAnyOf, guards, match, matchOrElse })
6367}
6368/**
6369 * Type-level representation returned by {@link Opaque}.
6370 *
6371 * @category models
6372 * @since 4.0.0
6373 */
6374export interface Opaque<Self, S extends Top, Brand> extends
6375 BottomLazyWithoutNew<
6376 S["ast"],
6377 S["Rebuild"],
6378 S["~type.parameters"],
6379 S["~type.mutability"],
6380 S["~type.optionality"],
6381 S["~type.constructor.default"],
6382 S["~encoded.mutability"],
6383 S["~encoded.optionality"]
6384 >
6385{
6386 readonly "Type": Self
6387 readonly "Encoded": S["Encoded"]
6388 readonly "DecodingServices": S["DecodingServices"]
6389 readonly "EncodingServices": S["EncodingServices"]
6390 readonly "~type.make.in": S["~type.make.in"]
6391 readonly "~type.make": S["~type.make"]
6392 readonly "Iso": S["Iso"]
6393 new(_: never): S["Type"] & Brand
6394}
6395/**
6396 * Wraps a struct schema so that its decoded `Type` becomes a nominally distinct type `Self`.
6397 * Useful for creating opaque types that are structurally identical to a base struct
6398 * but type-incompatible with it.
6399 *
6400 * **Example** (Defining opaque structs)
6401 *
6402 * ```ts import.meta.vitest
6403 * import { Schema } from "effect"
6404 *
6405 * class Person extends Schema.Opaque<Person>()(
6406 * Schema.Struct({
6407 * name: Schema.String
6408 * })
6409 * ) {}
6410 *
6411 * // Decoded value is Person, not { name: string }
6412 * const person = Schema.decodeUnknownSync(Person)({ name: "Alice" })
6413 * person.name // => "Alice"
6414 * ```
6415 *
6416 * @category constructors
6417 * @since 4.0.0
6418 */
6419export function Opaque<Self, Brand = {}>() {
6420 return <S extends Top>(
6421 schema: S
6422 ): Opaque<Self, S, Brand> & Omit<S, keyof Top> => schema as any
6423}
6424/**
6425 * Type-level representation returned by {@link instanceOf}.
6426 *
6427 * @category models
6428 * @since 3.10.0
6429 */
6430export interface instanceOf<T, Iso = T> extends declare<T, Iso> {
6431 readonly "Rebuild": instanceOf<T, Iso>
6432}
6433/**
6434 * Creates a schema that validates values using `instanceof`.
6435 * Decoding and encoding pass the value through unchanged.
6436 *
6437 * **Example** (Defining a schema for a built-in class)
6438 *
6439 * ```ts import.meta.vitest
6440 * import { Schema } from "effect"
6441 *
6442 * const DateSchema = Schema.instanceOf(Date)
6443 *
6444 * const decoded = Schema.decodeUnknownSync(DateSchema)(new Date("2024-01-01"))
6445 * decoded.toISOString() // => "2024-01-01T00:00:00.000Z"
6446 * ```
6447 *
6448 * @category constructors
6449 * @since 3.10.0
6450 */
6451export function instanceOf<C extends abstract new(...args: any) => any, Iso = InstanceType<C>>(
6452 constructor: C,
6453 annotations?: Annotations.Declaration<InstanceType<C>> | undefined
6454): instanceOf<InstanceType<C>, Iso> {
6455 return declare((u): u is InstanceType<C> => u instanceof constructor, annotations)
6456}
6457/**
6458 * Constructs an `SchemaAST.Link` that describes how a value of type `T` encodes to and decodes from a `To` schema.
6459 * Used when building low-level AST transformations that bridge two schema types.
6460 *
6461 * @category transforming
6462 * @since 4.0.0
6463 */
6464export function link<T>() {
6465 return <To extends Constraint>(
6466 encodeTo: To,
6467 transformation: {
6468 readonly decode: SchemaGetter.Getter<T, NoInfer<To["Type"]>>
6469 readonly encode: SchemaGetter.Getter<NoInfer<To["Type"]>, T>
6470 }
6471 ): SchemaAST.Link => {
6472 return new SchemaAST.Link(encodeTo.ast, SchemaTransformation.makeTransformation(transformation))
6473 }
6474}
6475/**
6476 * Creates a custom validation filter from a predicate function.
6477 *
6478 * **Details**
6479 *
6480 * The predicate receives the decoded input value, the schema AST, and parse
6481 * options, and returns a `FilterOutput`. Non-success outputs are normalized into
6482 * schema issues. The `annotations` parameter annotates the filter itself; with
6483 * the default formatter, failures use `message` first, `expected` second, and
6484 * `<filter>` when neither is provided.
6485 *
6486 * When `abort` is `true`, parsing stops after this filter fails instead of
6487 * collecting later check failures.
6488 *
6489 * **Example** (Reporting failure at a nested path)
6490 *
6491 * ```ts import.meta.vitest
6492 * import { Result, Schema } from "effect"
6493 *
6494 * const schema = Schema.Struct({ password: Schema.String, confirmPassword: Schema.String }).check(
6495 * Schema.makeFilter((o) =>
6496 * o.password === o.confirmPassword
6497 * ? undefined
6498 * : { path: ["password"], issue: "password and confirmPassword must match" }
6499 * )
6500 * )
6501 *
6502 * const result = Schema.decodeUnknownResult(schema)({ password: "123456", confirmPassword: "1234567" })
6503 * if (Result.isFailure(result) && result.failure.issue._tag === "Filter" && result.failure.issue.issue._tag === "Pointer") {
6504 * result.failure.issue.issue.path // => ["password"]
6505 * }
6506 * ```
6507 *
6508 * **Example** (Reporting multiple failures at once)
6509 *
6510 * ```ts import.meta.vitest
6511 * import { Result, Schema } from "effect"
6512 *
6513 * const schema = Schema.Struct({ a: Schema.Finite, b: Schema.Finite, c: Schema.Finite }).check(
6514 * Schema.makeFilter((o) => {
6515 * const issues: Array<Schema.FilterIssue> = []
6516 * if (o.a > 0) {
6517 * if (o.b <= 0) issues.push({ path: ["b"], issue: "b must be greater than 0" })
6518 * if (o.c <= 0) issues.push({ path: ["c"], issue: "c must be greater than 0" })
6519 * }
6520 * return issues
6521 * })
6522 * )
6523 *
6524 * const result = Schema.decodeUnknownResult(schema)({ a: 1, b: 0, c: 0 })
6525 * if (Result.isFailure(result) && result.failure.issue._tag === "Filter" && result.failure.issue.issue._tag === "Composite") {
6526 * result.failure.issue.issue.issues.map((issue) => issue._tag === "Pointer" ? issue.path : []) // => [["b"], ["c"]]
6527 * }
6528 * ```
6529 *
6530 * @category constructors
6531 * @since 4.0.0
6532 */
6533export const makeFilter: <T>(
6534 filter: (input: T, ast: SchemaAST.AST, options: SchemaAST.ParseOptions) => FilterOutput,
6535 annotations?: Annotations.Filter | undefined,
6536 abort?: boolean
6537) => SchemaAST.Filter<T> = SchemaAST.makeFilter
6538/**
6539 * A single failure reported by a filter predicate. Used as the element type
6540 * of the array arm of {@link FilterOutput}, and also accepted on its own.
6541 *
6542 * **Details**
6543 *
6544 * - `string`: failure with that string as the message. Produces an
6545 * {@link SchemaIssue.InvalidValue} with the string used as the issue's
6546 * `message` annotation and honors `reportInput`.
6547 * - {@link SchemaIssue.Issue}: a fully-formed issue, returned as-is. It is not
6548 * enriched when `reportInput` is enabled.
6549 * - `{ path, issue }`: failure attached to a nested path. `issue` is either
6550 * a `string` (wrapped in an {@link SchemaIssue.InvalidValue} that honors
6551 * `reportInput`) or a full {@link SchemaIssue.Issue} (returned unchanged);
6552 * the result is wrapped in an {@link SchemaIssue.Pointer} at the given `path`.
6553 *
6554 * @category models
6555 * @since 3.10.0
6556 */
6557export type FilterIssue = string | SchemaIssue.Issue | {
6558 readonly path: ReadonlyArray<PropertyKey>
6559 readonly issue: string | SchemaIssue.Issue
6560}
6561/**
6562 * The value a filter predicate (see {@link makeFilter}) may return.
6563 *
6564 * **Details**
6565 *
6566 * Each shape is normalized into an {@link SchemaIssue.Issue} (or `undefined` for
6567 * success) before being attached to the parse result:
6568 *
6569 * - `undefined`: success. The input satisfies the filter.
6570 * - `true`: success. Equivalent to `undefined`, useful when the predicate is
6571 * a plain boolean expression.
6572 * - `false`: generic failure. Produces an {@link SchemaIssue.InvalidValue}
6573 * with no custom message and honors `reportInput`.
6574 * - {@link FilterIssue}: a single failure. See {@link FilterIssue} for the
6575 * shapes (`string`, {@link SchemaIssue.Issue}, or `{ path, issue }`).
6576 * - `ReadonlyArray<FilterIssue>`: several failures reported together. An
6577 * empty array is treated as success; a single-element array is equivalent
6578 * to returning that element directly; otherwise the entries are grouped
6579 * into an {@link SchemaIssue.Composite}.
6580 *
6581 * @category models
6582 * @since 3.10.0
6583 */
6584export type FilterOutput = undefined | boolean | FilterIssue | ReadonlyArray<FilterIssue>
6585/**
6586 * Groups multiple checks into a single {@link SchemaAST.FilterGroup}, applying
6587 * optional shared annotations to the group as a whole.
6588 *
6589 * @category constructors
6590 * @since 4.0.0
6591 */
6592export function makeFilterGroup<T>(
6593 checks: readonly [SchemaAST.Check<T>, ...Array<SchemaAST.Check<T>>],
6594 annotations: Annotations.Filter | undefined = undefined
6595): SchemaAST.FilterGroup<T> {
6596 return new SchemaAST.FilterGroup(checks, annotations)
6597}
6598
6599const TRIMMED_PATTERN = "^\\S[\\s\\S]*\\S$|^\\S$|^$"
6600/**
6601 * Validates that a string has no leading or trailing whitespace.
6602 *
6603 * **Details**
6604 *
6605 * JSON Schema:
6606 *
6607 * This check corresponds to a `pattern` constraint in JSON Schema that
6608 * matches strings without leading or trailing whitespace.
6609 *
6610 * Arbitrary:
6611 *
6612 * During arbitrary generation, this applies a `patterns`
6613 * constraint to ensure generated strings match the trimmed pattern.
6614 *
6615 * @category validation
6616 * @since 4.0.0
6617 */
6618export function isTrimmed(annotations?: Annotations.Filter) {
6619 const regExp = new globalThis.RegExp(TRIMMED_PATTERN)
6620 return makeFilter(
6621 (s: string) => s.trim() === s,
6622 {
6623 expected: "a string with no leading or trailing whitespace",
6624 representation: {
6625 id: "effect/schema/isTrimmed",
6626 payload: null
6627 },
6628 toJsonSchema: () => ({ pattern: regExp.source }),
6629 toCode: () => ({ runtime: "Schema.isTrimmed()" }),
6630 arbitraryConstraint: {
6631 patterns: [{ source: TRIMMED_PATTERN, flags: "" }]
6632 },
6633 ...annotations
6634 }
6635 )
6636}
6637/**
6638 * Validates that a string matches the specified regular expression pattern.
6639 *
6640 * **Details**
6641 *
6642 * JSON Schema:
6643 *
6644 * Unless annotations override `toJsonSchema`, JSON Schema receives a `pattern`
6645 * only when the JavaScript RegExp uses the Unicode flag and its other flags are
6646 * `d`, `g`, or `y`. Sticky patterns are anchored at the start of the string.
6647 *
6648 * Arbitrary:
6649 *
6650 * During arbitrary generation, this applies a `patterns`
6651 * constraint to ensure generated strings match the specified RegExp pattern.
6652 *
6653 * @category validation
6654 * @since 4.0.0
6655 */
6656export function isPattern(
6657 regExp: globalThis.RegExp,
6658 annotations?: Annotations.Filter
6659): SchemaAST.Filter<string> {
6660 const source = regExp.source
6661 const flags = regExp.flags
6662 const canExport = /^[dg]*uy?$/.test(flags)
6663 const runtimeRegExp = flags === ""
6664 ? `new RegExp(${format(source)})`
6665 : `new RegExp(${format(source)}, ${format(flags)})`
6666 return SchemaAST.isPattern(regExp, {
6667 toJsonSchema: () => canExport ? { pattern: flags.endsWith("y") ? `^(?:${source})` : source } : [{}, true],
6668 toCode: () => ({ runtime: `Schema.isPattern(${runtimeRegExp})` }),
6669 ...annotations
6670 })
6671}
6672/**
6673 * Validates that a string represents a finite number.
6674 *
6675 * **Details**
6676 *
6677 * JSON Schema:
6678 *
6679 * This check corresponds to a `pattern` constraint in JSON Schema that matches
6680 * strings representing finite numbers.
6681 *
6682 * Arbitrary:
6683 *
6684 * During arbitrary generation, this applies a `patterns`
6685 * constraint to ensure generated strings match the number string pattern.
6686 *
6687 * @category validation
6688 * @since 4.0.0
6689 */
6690export function isStringFinite(annotations?: Annotations.Filter): SchemaAST.Filter<string> {
6691 return SchemaAST.isStringFinite({
6692 toCode: () => ({ runtime: "Schema.isStringFinite()" }),
6693 ...annotations
6694 })
6695}
6696/**
6697 * Validates that a string is a signed base-10 integer literal for Effect's
6698 * BigInt string encoding.
6699 *
6700 * **Details**
6701 *
6702 * The check uses the pattern `^-?\d+$`. It does not accept leading `+`, decimal
6703 * points, exponent notation, separators, or non-decimal inputs such as
6704 * hexadecimal strings.
6705 *
6706 * JSON Schema:
6707 * This check corresponds to a `pattern` constraint with the same signed
6708 * base-10 integer pattern.
6709 *
6710 * @category validation
6711 * @since 4.0.0
6712 */
6713export function isStringBigInt(annotations?: Annotations.Filter): SchemaAST.Filter<string> {
6714 return SchemaAST.isStringBigInt({
6715 toCode: () => ({ runtime: "Schema.isStringBigInt()" }),
6716 ...annotations
6717 })
6718}
6719/**
6720 * Validates that a string has the `Symbol(description)` format used by Effect's
6721 * symbol string encoding.
6722 *
6723 * **Details**
6724 *
6725 * The check uses the pattern `^Symbol\((.*)\)$`. It is not a general test for
6726 * whether a string can be passed to JavaScript's `Symbol()` function.
6727 *
6728 * @category validation
6729 * @since 4.0.0
6730 */
6731export function isStringSymbol(annotations?: Annotations.Filter): SchemaAST.Filter<string> {
6732 return SchemaAST.isStringSymbol({
6733 toCode: () => ({ runtime: "Schema.isStringSymbol()" }),
6734 ...annotations
6735 })
6736}
6737
6738const getUUIDRegExp = (version?: 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8): globalThis.RegExp => {
6739 if (version) {
6740 return new globalThis.RegExp(
6741 `^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-${version}[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$`
6742 )
6743 }
6744 return /^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|[fF]{8}-[fF]{4}-[fF]{4}-[fF]{4}-[fF]{12})$/
6745}
6746/**
6747 * Validates that a string is a strict Universally Unique Identifier (UUID).
6748 *
6749 * **When to use**
6750 *
6751 * Use when you need UUID semantics, including version and RFC variant bits,
6752 * rather than only the dashed hexadecimal shape.
6753 *
6754 * **Details**
6755 *
6756 * Without a version argument, this accepts UUID versions 1 through 8, the nil
6757 * UUID (`00000000-0000-0000-0000-000000000000`), and the max UUID
6758 * (`ffffffff-ffff-ffff-ffff-ffffffffffff`). With a version argument, this
6759 * accepts only UUIDs with that version and RFC variant bits; nil and max UUIDs
6760 * are not versioned UUIDs and do not match version-specific checks.
6761 *
6762 * JSON Schema:
6763 *
6764 * This check corresponds to a `pattern` constraint in JSON Schema that matches
6765 * UUID format, and includes a `format: "uuid"` annotation.
6766 *
6767 * Arbitrary:
6768 *
6769 * During arbitrary generation, this applies a `patterns`
6770 * constraint to ensure generated strings match the UUID pattern.
6771 *
6772 * @see {@link isGUID} for shape-only GUID validation.
6773 * @category validation
6774 * @since 4.0.0
6775 */
6776export function isUUID(version?: 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8, annotations?: Annotations.Filter) {
6777 const regExp = getUUIDRegExp(version)
6778 return isPattern(
6779 regExp,
6780 {
6781 expected: version ? `a UUID v${version}` : "a UUID",
6782 representation: {
6783 id: "effect/schema/isUUID",
6784 payload: { version: version ?? null }
6785 },
6786 toJsonSchema: () => ({ pattern: regExp.source, format: "uuid" }),
6787 toCode: () => ({ runtime: version === undefined ? "Schema.isUUID()" : `Schema.isUUID(${version})` }),
6788 ...annotations
6789 }
6790 )
6791}
6792
6793const GUID_REGEXP = /^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$/
6794/**
6795 * Validates that a string has the GUID / UUID textual shape.
6796 *
6797 * **When to use**
6798 *
6799 * Use when you need to accept dashed hexadecimal identifiers without enforcing
6800 * UUID version or variant bits.
6801 *
6802 * **Details**
6803 *
6804 * This check accepts strings in the `8-4-4-4-12` hexadecimal form. JSON Schema
6805 * output includes the corresponding `pattern` constraint and intentionally does
6806 * not include `format: "uuid"` because GUID validation is looser than UUID
6807 * validation.
6808 *
6809 * Arbitrary:
6810 *
6811 * During arbitrary generation, this applies a `patterns`
6812 * constraint to ensure generated strings match the GUID pattern.
6813 *
6814 * @see {@link isUUID} for strict UUID validation.
6815 * @category validation
6816 * @since 4.0.0
6817 */
6818export function isGUID(annotations?: Annotations.Filter) {
6819 return isPattern(
6820 GUID_REGEXP,
6821 {
6822 expected: "a GUID",
6823 representation: {
6824 id: "effect/schema/isGUID",
6825 payload: null
6826 },
6827 toJsonSchema: () => ({ pattern: GUID_REGEXP.source }),
6828 toCode: () => ({ runtime: "Schema.isGUID()" }),
6829 ...annotations
6830 }
6831 )
6832}
6833/**
6834 * Validates that a string is a valid ULID (Universally Unique Lexicographically
6835 * Sortable Identifier).
6836 *
6837 * **Details**
6838 *
6839 * JSON Schema:
6840 *
6841 * This check corresponds to a `pattern` constraint in JSON Schema that matches
6842 * the ULID format.
6843 *
6844 * Arbitrary:
6845 *
6846 * During arbitrary generation, this applies a `patterns`
6847 * constraint to ensure generated strings match the ULID pattern.
6848 *
6849 * @category validation
6850 * @since 4.0.0
6851 */
6852export function isULID(annotations?: Annotations.Filter) {
6853 const regExp = /^[0-9A-HJKMNP-TV-Za-hjkmnp-tv-z]{26}$/
6854 return isPattern(
6855 regExp,
6856 {
6857 representation: {
6858 id: "effect/schema/isULID",
6859 payload: null
6860 },
6861 toJsonSchema: () => ({ pattern: regExp.source }),
6862 toCode: () => ({ runtime: "Schema.isULID()" }),
6863 ...annotations
6864 }
6865 )
6866}
6867/**
6868 * Validates that a string is valid Base64 encoded data.
6869 *
6870 * **Details**
6871 *
6872 * JSON Schema:
6873 *
6874 * This check corresponds to a `pattern` constraint in JSON Schema that matches
6875 * Base64 format.
6876 *
6877 * Arbitrary:
6878 *
6879 * During arbitrary generation, this applies a `patterns`
6880 * constraint to ensure generated strings match the Base64 pattern.
6881 *
6882 * @category validation
6883 * @since 4.0.0
6884 */
6885export function isBase64(annotations?: Annotations.Filter) {
6886 const regExp = /^([0-9a-zA-Z+/]{4})*(([0-9a-zA-Z+/]{2}==)|([0-9a-zA-Z+/]{3}=))?$/
6887 return isPattern(
6888 regExp,
6889 {
6890 expected: "a base64 encoded string",
6891 representation: {
6892 id: "effect/schema/isBase64",
6893 payload: null
6894 },
6895 toJsonSchema: () => ({ pattern: regExp.source }),
6896 toCode: () => ({ runtime: "Schema.isBase64()" }),
6897 ...annotations
6898 }
6899 )
6900}
6901/**
6902 * Validates that a string is valid Base64URL encoded data (Base64 with URL-safe
6903 * characters).
6904 *
6905 * **Details**
6906 *
6907 * JSON Schema:
6908 *
6909 * This check corresponds to a `pattern` constraint in JSON Schema that matches
6910 * Base64URL format.
6911 *
6912 * Arbitrary:
6913 *
6914 * During arbitrary generation, this applies a `patterns`
6915 * constraint to ensure generated strings match the Base64URL pattern.
6916 *
6917 * @category validation
6918 * @since 4.0.0
6919 */
6920export function isBase64Url(annotations?: Annotations.Filter) {
6921 const regExp = /^([0-9a-zA-Z-_]{4})*(([0-9a-zA-Z-_]{2}(==)?)|([0-9a-zA-Z-_]{3}(=)?))?$/
6922 return isPattern(
6923 regExp,
6924 {
6925 expected: "a base64url encoded string",
6926 representation: {
6927 id: "effect/schema/isBase64Url",
6928 payload: null
6929 },
6930 toJsonSchema: () => ({ pattern: regExp.source }),
6931 toCode: () => ({ runtime: "Schema.isBase64Url()" }),
6932 ...annotations
6933 }
6934 )
6935}
6936
6937function literalToJsonSchema(
6938 literal: string,
6939 original: string,
6940 pattern: string
6941): SchemaRepresentation.ToJsonSchema.CheckOutput {
6942 if (literal.length === 0) return original.length === 0 ? {} : [{}, true]
6943 const constraint = { pattern: new globalThis.RegExp(pattern).source }
6944 return literal === original ? constraint : [constraint, true]
6945}
6946
6947/**
6948 * Validates at runtime that a string starts with the specified literal prefix.
6949 *
6950 * **Details**
6951 *
6952 * RegExp metacharacters in the prefix are escaped in JSON Schema and arbitrary
6953 * metadata. If the prefix ends with a high surrogate, the JSON Schema pattern
6954 * omits that code unit so Unicode matching cannot reject a valid string.
6955 *
6956 * @category validation
6957 * @since 4.0.0
6958 */
6959export function isStartingWith(startsWith: string, annotations?: Annotations.Filter) {
6960 const formatted = JSON.stringify(startsWith)
6961 const regExp = new globalThis.RegExp(`^${RegExp_.escape(startsWith)}`)
6962 const jsonSchemaLiteral = startsWith.replace(/[\uD800-\uDBFF]$/, "")
6963 return makeFilter(
6964 (s: string) => s.startsWith(startsWith),
6965 {
6966 expected: `a string starting with ${formatted}`,
6967 representation: {
6968 id: "effect/schema/isStartingWith",
6969 payload: { startsWith }
6970 },
6971 toJsonSchema: () => literalToJsonSchema(jsonSchemaLiteral, startsWith, `^${RegExp_.escape(jsonSchemaLiteral)}`),
6972 toCode: () => ({ runtime: `Schema.isStartingWith(${format(startsWith)})` }),
6973 arbitraryConstraint: {
6974 patterns: [{ source: regExp.source, flags: regExp.flags }]
6975 },
6976 ...annotations
6977 }
6978 )
6979}
6980/**
6981 * Validates at runtime that a string ends with the specified literal suffix.
6982 *
6983 * **Details**
6984 *
6985 * RegExp metacharacters in the suffix are escaped in JSON Schema and arbitrary
6986 * metadata. If the suffix begins with a low surrogate, the JSON Schema pattern
6987 * omits that code unit so Unicode matching cannot reject a valid string.
6988 *
6989 * @category validation
6990 * @since 4.0.0
6991 */
6992export function isEndingWith(endsWith: string, annotations?: Annotations.Filter) {
6993 const formatted = JSON.stringify(endsWith)
6994 const regExp = new globalThis.RegExp(`${RegExp_.escape(endsWith)}$`)
6995 const jsonSchemaLiteral = endsWith.replace(/^[\uDC00-\uDFFF]/, "")
6996 return makeFilter(
6997 (s: string) => s.endsWith(endsWith),
6998 {
6999 expected: `a string ending with ${formatted}`,
7000 representation: {
7001 id: "effect/schema/isEndingWith",
7002 payload: { endsWith }
7003 },
7004 toJsonSchema: () => literalToJsonSchema(jsonSchemaLiteral, endsWith, `${RegExp_.escape(jsonSchemaLiteral)}$`),
7005 toCode: () => ({ runtime: `Schema.isEndingWith(${format(endsWith)})` }),
7006 arbitraryConstraint: {
7007 patterns: [{ source: regExp.source, flags: regExp.flags }]
7008 },
7009 ...annotations
7010 }
7011 )
7012}
7013/**
7014 * Validates at runtime that a string contains the specified literal substring.
7015 *
7016 * **Details**
7017 *
7018 * RegExp metacharacters in the substring are escaped in JSON Schema and
7019 * arbitrary metadata. A leading low surrogate or trailing high surrogate is
7020 * omitted from the JSON Schema pattern so Unicode matching cannot reject a
7021 * valid string.
7022 *
7023 * @category validation
7024 * @since 4.0.0
7025 */
7026export function isIncluding(includes: string, annotations?: Annotations.Filter) {
7027 const formatted = JSON.stringify(includes)
7028 const regExp = new globalThis.RegExp(RegExp_.escape(includes))
7029 const jsonSchemaLiteral = includes.replace(/^[\uDC00-\uDFFF]|[\uD800-\uDBFF]$/g, "")
7030 return makeFilter(
7031 (s: string) => s.includes(includes),
7032 {
7033 expected: `a string including ${formatted}`,
7034 representation: {
7035 id: "effect/schema/isIncluding",
7036 payload: { includes }
7037 },
7038 toJsonSchema: () => literalToJsonSchema(jsonSchemaLiteral, includes, RegExp_.escape(jsonSchemaLiteral)),
7039 toCode: () => ({ runtime: `Schema.isIncluding(${format(includes)})` }),
7040 arbitraryConstraint: {
7041 patterns: [{ source: regExp.source, flags: regExp.flags }]
7042 },
7043 ...annotations
7044 }
7045 )
7046}
7047
7048const UPPERCASED_PATTERN = "^[^a-z]*$"
7049/**
7050 * Validates that a string is unchanged by JavaScript's `toUpperCase()`.
7051 *
7052 * **Details**
7053 *
7054 * This accepts empty strings and characters that do not have lowercase forms,
7055 * such as digits, punctuation, and whitespace. It rejects strings that would
7056 * change when uppercased.
7057 *
7058 * @category validation
7059 * @since 4.0.0
7060 */
7061export function isUppercased(annotations?: Annotations.Filter) {
7062 const regExp = new globalThis.RegExp(UPPERCASED_PATTERN)
7063 return makeFilter(
7064 (s: string) => s.toUpperCase() === s,
7065 {
7066 expected: "a string with all characters in uppercase",
7067 representation: {
7068 id: "effect/schema/isUppercased",
7069 payload: null
7070 },
7071 toJsonSchema: () => [{ pattern: regExp.source }, true],
7072 toCode: () => ({ runtime: "Schema.isUppercased()" }),
7073 arbitraryConstraint: {
7074 patterns: [{ source: UPPERCASED_PATTERN, flags: "" }]
7075 },
7076 ...annotations
7077 }
7078 )
7079}
7080
7081const LOWERCASED_PATTERN = "^[^A-Z]*$"
7082/**
7083 * Validates that a string is unchanged by JavaScript's `toLowerCase()`.
7084 *
7085 * **Details**
7086 *
7087 * This accepts empty strings and characters that do not have uppercase forms,
7088 * such as digits, punctuation, and whitespace. It rejects strings that would
7089 * change when lowercased.
7090 *
7091 * @category validation
7092 * @since 4.0.0
7093 */
7094export function isLowercased(annotations?: Annotations.Filter) {
7095 const regExp = new globalThis.RegExp(LOWERCASED_PATTERN)
7096 return makeFilter(
7097 (s: string) => s.toLowerCase() === s,
7098 {
7099 expected: "a string with all characters in lowercase",
7100 representation: {
7101 id: "effect/schema/isLowercased",
7102 payload: null
7103 },
7104 toJsonSchema: () => [{ pattern: regExp.source }, true],
7105 toCode: () => ({ runtime: "Schema.isLowercased()" }),
7106 arbitraryConstraint: {
7107 patterns: [{ source: LOWERCASED_PATTERN, flags: "" }]
7108 },
7109 ...annotations
7110 }
7111 )
7112}
7113
7114const CAPITALIZED_PATTERN = "^(?:[^a-z][\\s\\S]*)?$"
7115/**
7116 * Validates that the first character of a string is unchanged by
7117 * `toUpperCase()`.
7118 *
7119 * **Details**
7120 *
7121 * Empty strings pass. Strings whose first character has no lowercase form, such
7122 * as a digit, punctuation mark, or whitespace, also pass.
7123 *
7124 * @category validation
7125 * @since 4.0.0
7126 */
7127export function isCapitalized(annotations?: Annotations.Filter) {
7128 const regExp = new globalThis.RegExp(CAPITALIZED_PATTERN)
7129 return makeFilter(
7130 (s: string) => s.charAt(0).toUpperCase() === s.charAt(0),
7131 {
7132 expected: "a string with the first character in uppercase",
7133 representation: {
7134 id: "effect/schema/isCapitalized",
7135 payload: null
7136 },
7137 toJsonSchema: () => [{ pattern: regExp.source }, true],
7138 toCode: () => ({ runtime: "Schema.isCapitalized()" }),
7139 arbitraryConstraint: {
7140 patterns: [{ source: CAPITALIZED_PATTERN, flags: "" }]
7141 },
7142 ...annotations
7143 }
7144 )
7145}
7146
7147const UNCAPITALIZED_PATTERN = "^(?:[^A-Z][\\s\\S]*)?$"
7148/**
7149 * Validates that the first character of a string is unchanged by
7150 * `toLowerCase()`.
7151 *
7152 * **Details**
7153 *
7154 * Empty strings pass. Strings whose first character has no uppercase form, such
7155 * as a digit, punctuation mark, or whitespace, also pass.
7156 *
7157 * @category validation
7158 * @since 4.0.0
7159 */
7160export function isUncapitalized(annotations?: Annotations.Filter) {
7161 const regExp = new globalThis.RegExp(UNCAPITALIZED_PATTERN)
7162 return makeFilter(
7163 (s: string) => s.charAt(0).toLowerCase() === s.charAt(0),
7164 {
7165 expected: "a string with the first character in lowercase",
7166 representation: {
7167 id: "effect/schema/isUncapitalized",
7168 payload: null
7169 },
7170 toJsonSchema: () => [{ pattern: regExp.source }, true],
7171 toCode: () => ({ runtime: "Schema.isUncapitalized()" }),
7172 arbitraryConstraint: {
7173 patterns: [{ source: UNCAPITALIZED_PATTERN, flags: "" }]
7174 },
7175 ...annotations
7176 }
7177 )
7178}
7179/**
7180 * Type-level representation of {@link Finite}.
7181 *
7182 * @category models
7183 * @since 3.10.0
7184 */
7185export interface Finite extends Number {
7186 readonly "Rebuild": Finite
7187}
7188/**
7189 * Schema for finite numbers, rejecting `NaN`, `Infinity`, and `-Infinity`.
7190 *
7191 * @category schemas
7192 * @since 3.10.0
7193 */
7194export const Finite: Finite = make(SchemaAST.finite)
7195/**
7196 * Validates that a number is finite (not `Infinity`, `-Infinity`, or `NaN`).
7197 *
7198 * **Details**
7199 *
7200 * JSON Schema:
7201 *
7202 * This check does not have a direct JSON Schema equivalent, but ensures the
7203 * number is valid and finite.
7204 *
7205 * Arbitrary:
7206 *
7207 * During arbitrary generation, this applies a finite-number constraint.
7208 *
7209 * @category validation
7210 * @since 4.0.0
7211 */
7212export const isFinite: (annotations?: Annotations.Filter) => SchemaAST.Filter<number> = SchemaAST.isFinite
7213/**
7214 * Creates a greater-than (`>`) check for any ordered type from an
7215 * `Order.Order` instance.
7216 *
7217 * @category validation
7218 * @since 4.0.0
7219 */
7220export function makeIsGreaterThan<T>(options: {
7221 readonly order: Order.Order<T>
7222 readonly annotate?: ((exclusiveMinimum: T) => Annotations.Filter) | undefined
7223 readonly formatter?: Formatter<T> | undefined
7224}) {
7225 const gt = Order.isGreaterThan(options.order)
7226 const formatter = options.formatter ?? format
7227 return (exclusiveMinimum: T, annotations?: Annotations.Filter) => {
7228 return makeFilter<T>(
7229 (input) => gt(input, exclusiveMinimum),
7230 {
7231 expected: `a value greater than ${formatter(exclusiveMinimum)}`,
7232 arbitraryConstraint: {
7233 order: options.order,
7234 minimum: exclusiveMinimum,
7235 exclusiveMinimum: true
7236 },
7237 ...options.annotate?.(exclusiveMinimum),
7238 ...annotations
7239 }
7240 )
7241 }
7242}
7243/**
7244 * Creates a greater-than-or-equal-to (`>=`) check for any ordered type from an
7245 * `Order.Order` instance.
7246 *
7247 * @category validation
7248 * @since 4.0.0
7249 */
7250export function makeIsGreaterThanOrEqualTo<T>(options: {
7251 readonly order: Order.Order<T>
7252 readonly annotate?: ((exclusiveMinimum: T) => Annotations.Filter) | undefined
7253 readonly formatter?: Formatter<T> | undefined
7254}) {
7255 const gte = Order.isGreaterThanOrEqualTo(options.order)
7256 const formatter = options.formatter ?? format
7257 return (minimum: T, annotations?: Annotations.Filter) => {
7258 return makeFilter<T>(
7259 (input) => gte(input, minimum),
7260 {
7261 expected: `a value greater than or equal to ${formatter(minimum)}`,
7262 arbitraryConstraint: {
7263 order: options.order,
7264 minimum
7265 },
7266 ...options.annotate?.(minimum),
7267 ...annotations
7268 }
7269 )
7270 }
7271}
7272/**
7273 * Creates a less-than (`<`) check for any ordered type from an `Order.Order`
7274 * instance.
7275 *
7276 * @category validation
7277 * @since 4.0.0
7278 */
7279export function makeIsLessThan<T>(options: {
7280 readonly order: Order.Order<T>
7281 readonly annotate?: ((exclusiveMaximum: T) => Annotations.Filter) | undefined
7282 readonly formatter?: Formatter<T> | undefined
7283}) {
7284 const lt = Order.isLessThan(options.order)
7285 const formatter = options.formatter ?? format
7286 return (exclusiveMaximum: T, annotations?: Annotations.Filter) => {
7287 return makeFilter<T>(
7288 (input) => lt(input, exclusiveMaximum),
7289 {
7290 expected: `a value less than ${formatter(exclusiveMaximum)}`,
7291 arbitraryConstraint: {
7292 order: options.order,
7293 maximum: exclusiveMaximum,
7294 exclusiveMaximum: true
7295 },
7296 ...options.annotate?.(exclusiveMaximum),
7297 ...annotations
7298 }
7299 )
7300 }
7301}
7302/**
7303 * Creates a less-than-or-equal-to (`<=`) check for any ordered type from an
7304 * `Order.Order` instance.
7305 *
7306 * @category validation
7307 * @since 4.0.0
7308 */
7309export function makeIsLessThanOrEqualTo<T>(options: {
7310 readonly order: Order.Order<T>
7311 readonly annotate?: ((exclusiveMaximum: T) => Annotations.Filter) | undefined
7312 readonly formatter?: Formatter<T> | undefined
7313}) {
7314 const lte = Order.isLessThanOrEqualTo(options.order)
7315 const formatter = options.formatter ?? format
7316 return (maximum: T, annotations?: Annotations.Filter) => {
7317 return makeFilter<T>(
7318 (input) => lte(input, maximum),
7319 {
7320 expected: `a value less than or equal to ${formatter(maximum)}`,
7321 arbitraryConstraint: {
7322 order: options.order,
7323 maximum
7324 },
7325 ...options.annotate?.(maximum),
7326 ...annotations
7327 }
7328 )
7329 }
7330}
7331/**
7332 * Creates an inclusive or exclusive range check for any ordered type from an
7333 * `Order.Order` instance.
7334 *
7335 * @category validation
7336 * @since 4.0.0
7337 */
7338export function makeIsBetween<T>(deriveOptions: {
7339 readonly order: Order.Order<T>
7340 readonly annotate?:
7341 | ((options: {
7342 readonly minimum: T
7343 readonly maximum: T
7344 readonly exclusiveMinimum?: boolean | undefined
7345 readonly exclusiveMaximum?: boolean | undefined
7346 }) => Annotations.Filter)
7347 | undefined
7348 readonly formatter?: Formatter<T> | undefined
7349}) {
7350 const greaterThanOrEqualTo = Order.isGreaterThanOrEqualTo(deriveOptions.order)
7351 const greaterThan = Order.isGreaterThan(deriveOptions.order)
7352 const lessThanOrEqualTo = Order.isLessThanOrEqualTo(deriveOptions.order)
7353 const lessThan = Order.isLessThan(deriveOptions.order)
7354 const formatter = deriveOptions.formatter ?? format
7355 return (options: {
7356 readonly minimum: T
7357 readonly maximum: T
7358 readonly exclusiveMinimum?: boolean | undefined
7359 readonly exclusiveMaximum?: boolean | undefined
7360 }, annotations?: Annotations.Filter) => {
7361 const gte = options.exclusiveMinimum ? greaterThan : greaterThanOrEqualTo
7362 const lte = options.exclusiveMaximum ? lessThan : lessThanOrEqualTo
7363 return makeFilter<T>(
7364 (input) => gte(input, options.minimum) && lte(input, options.maximum),
7365 {
7366 expected: `a value between ${formatter(options.minimum)}${options.exclusiveMinimum ? " (excluded)" : ""} and ${
7367 formatter(options.maximum)
7368 }${options.exclusiveMaximum ? " (excluded)" : ""}`,
7369 arbitraryConstraint: {
7370 order: deriveOptions.order,
7371 minimum: options.minimum,
7372 maximum: options.maximum,
7373 ...(options.exclusiveMinimum && { exclusiveMinimum: true }),
7374 ...(options.exclusiveMaximum && { exclusiveMaximum: true })
7375 },
7376 ...deriveOptions.annotate?.(options),
7377 ...annotations
7378 }
7379 )
7380 }
7381}
7382/**
7383 * Creates a divisibility check for any numeric type from a remainder function
7384 * and a zero value.
7385 *
7386 * @category validation
7387 * @since 4.0.0
7388 */
7389export function makeIsMultipleOf<T>(options: {
7390 readonly remainder: (input: T, divisor: T) => T
7391 readonly zero: NoInfer<T>
7392 readonly annotate?: ((divisor: T) => Annotations.Filter) | undefined
7393 readonly formatter?: Formatter<T> | undefined
7394}) {
7395 return (divisor: T, annotations?: Annotations.Filter) => {
7396 const formatter = options.formatter ?? format
7397 return makeFilter<T>(
7398 (input) => options.remainder(input, divisor) === options.zero,
7399 {
7400 expected: `a value that is a multiple of ${formatter(divisor)}`,
7401 ...options.annotate?.(divisor),
7402 ...annotations
7403 }
7404 )
7405 }
7406}
7407
7408function encodeNumberPayload(number: number): number {
7409 if (!globalThis.Number.isFinite(number)) {
7410 throw new globalThis.RangeError(`Expected a finite number, got ${format(number)}`)
7411 }
7412 return number
7413}
7414/**
7415 * Validates that a number is greater than the specified value (exclusive).
7416 *
7417 * **Details**
7418 *
7419 * JSON Schema:
7420 *
7421 * This check corresponds to the `exclusiveMinimum` constraint in JSON Schema.
7422 *
7423 * Arbitrary:
7424 *
7425 * During arbitrary generation, this applies an
7426 * `exclusiveMinimum` constraint to ensure generated numbers are greater than
7427 * the specified value.
7428 *
7429 * @category validation
7430 * @since 4.0.0
7431 */
7432export const isGreaterThan: (exclusiveMinimum: number, annotations?: Annotations.Filter) => SchemaAST.Filter<number> =
7433 makeIsGreaterThan({
7434 order: Order.Number,
7435 annotate: (exclusiveMinimum) => ({
7436 representation: {
7437 id: "effect/schema/isGreaterThan",
7438 payload: { exclusiveMinimum: encodeNumberPayload(exclusiveMinimum) }
7439 },
7440 toJsonSchema: () => ({ exclusiveMinimum }),
7441 toCode: () => ({ runtime: `Schema.isGreaterThan(${format(exclusiveMinimum)})` })
7442 })
7443 })
7444/**
7445 * Validates that a number is greater than or equal to the specified value
7446 * (inclusive).
7447 *
7448 * **Details**
7449 *
7450 * JSON Schema:
7451 *
7452 * This check corresponds to the `minimum` constraint in JSON Schema.
7453 *
7454 * Arbitrary:
7455 *
7456 * During arbitrary generation, this applies a `minimum` constraint
7457 * to ensure generated numbers are greater than or equal to the specified value.
7458 *
7459 * @category validation
7460 * @since 4.0.0
7461 */
7462export const isGreaterThanOrEqualTo: (minimum: number, annotations?: Annotations.Filter) => SchemaAST.Filter<number> =
7463 makeIsGreaterThanOrEqualTo({
7464 order: Order.Number,
7465 annotate: (minimum) => ({
7466 representation: {
7467 id: "effect/schema/isGreaterThanOrEqualTo",
7468 payload: { minimum: encodeNumberPayload(minimum) }
7469 },
7470 toJsonSchema: () => ({ minimum }),
7471 toCode: () => ({ runtime: `Schema.isGreaterThanOrEqualTo(${format(minimum)})` })
7472 })
7473 })
7474/**
7475 * Validates that a number is less than the specified value (exclusive).
7476 *
7477 * **Details**
7478 *
7479 * JSON Schema:
7480 *
7481 * This check corresponds to the `exclusiveMaximum` constraint in JSON Schema.
7482 *
7483 * Arbitrary:
7484 *
7485 * During arbitrary generation, this applies an
7486 * `exclusiveMaximum` constraint to ensure generated numbers are less than the
7487 * specified value.
7488 *
7489 * @category validation
7490 * @since 4.0.0
7491 */
7492export const isLessThan: (exclusiveMaximum: number, annotations?: Annotations.Filter) => SchemaAST.Filter<number> =
7493 makeIsLessThan({
7494 order: Order.Number,
7495 annotate: (exclusiveMaximum) => ({
7496 representation: {
7497 id: "effect/schema/isLessThan",
7498 payload: { exclusiveMaximum: encodeNumberPayload(exclusiveMaximum) }
7499 },
7500 toJsonSchema: () => ({ exclusiveMaximum }),
7501 toCode: () => ({ runtime: `Schema.isLessThan(${format(exclusiveMaximum)})` })
7502 })
7503 })
7504/**
7505 * Validates that a number is less than or equal to the specified value
7506 * (inclusive).
7507 *
7508 * **Details**
7509 *
7510 * JSON Schema:
7511 *
7512 * This check corresponds to the `maximum` constraint in JSON Schema.
7513 *
7514 * Arbitrary:
7515 *
7516 * During arbitrary generation, this applies a `maximum` constraint
7517 * to ensure generated numbers are less than or equal to the specified value.
7518 *
7519 * @category validation
7520 * @since 4.0.0
7521 */
7522export const isLessThanOrEqualTo: (maximum: number, annotations?: Annotations.Filter) => SchemaAST.Filter<number> =
7523 makeIsLessThanOrEqualTo({
7524 order: Order.Number,
7525 annotate: (maximum) => ({
7526 representation: {
7527 id: "effect/schema/isLessThanOrEqualTo",
7528 payload: { maximum: encodeNumberPayload(maximum) }
7529 },
7530 toJsonSchema: () => ({ maximum }),
7531 toCode: () => ({ runtime: `Schema.isLessThanOrEqualTo(${format(maximum)})` })
7532 })
7533 })
7534/**
7535 * Validates that a number is within a specified range. The range boundaries can
7536 * be inclusive or exclusive based on the provided options.
7537 *
7538 * **Details**
7539 *
7540 * JSON Schema:
7541 *
7542 * This check corresponds to `minimum`/`maximum` or `exclusiveMinimum`/`exclusiveMaximum`
7543 * constraints in JSON Schema, depending on the options provided.
7544 *
7545 * Arbitrary:
7546 *
7547 * During arbitrary generation, this applies `minimum` and
7548 * `maximum` constraints with optional `exclusiveMinimum` and
7549 * `exclusiveMaximum` flags to ensure generated numbers fall within the
7550 * specified range.
7551 *
7552 * @category validation
7553 * @since 4.0.0
7554 */
7555export const isBetween: (options: {
7556 readonly minimum: number
7557 readonly maximum: number
7558 readonly exclusiveMinimum?: boolean | undefined
7559 readonly exclusiveMaximum?: boolean | undefined
7560}, annotations?: Annotations.Filter) => SchemaAST.Filter<number> = makeIsBetween({
7561 order: Order.Number,
7562 annotate: (options) => {
7563 const exclusiveMinimum = options.exclusiveMinimum ? true : undefined
7564 const exclusiveMaximum = options.exclusiveMaximum ? true : undefined
7565 const payload = {
7566 minimum: encodeNumberPayload(options.minimum),
7567 maximum: encodeNumberPayload(options.maximum),
7568 ...(exclusiveMinimum && { exclusiveMinimum }),
7569 ...(exclusiveMaximum && { exclusiveMaximum })
7570 }
7571 return {
7572 representation: {
7573 id: "effect/schema/isBetween",
7574 payload
7575 },
7576 toJsonSchema: () => ({
7577 [exclusiveMinimum ? "exclusiveMinimum" : "minimum"]: options.minimum,
7578 [exclusiveMaximum ? "exclusiveMaximum" : "maximum"]: options.maximum
7579 }),
7580 toCode: () => ({
7581 runtime: `Schema.isBetween({ minimum: ${format(options.minimum)}, maximum: ${
7582 format(options.maximum)
7583 }, exclusiveMinimum: ${format(exclusiveMinimum)}, exclusiveMaximum: ${format(exclusiveMaximum)} })`
7584 })
7585 }
7586 }
7587})
7588/**
7589 * Validates that a number is a multiple of the specified divisor.
7590 *
7591 * **Details**
7592 *
7593 * JSON Schema:
7594 *
7595 * This check corresponds to the `multipleOf` constraint in JSON Schema.
7596 * Negative divisors are normalized to their absolute value because JSON
7597 * Schema requires `multipleOf` to be positive.
7598 *
7599 * **Gotchas**
7600 *
7601 * Throws a `RangeError` when `divisor` is zero or is not finite.
7602 *
7603 * @category validation
7604 * @since 4.0.0
7605 */
7606export function isMultipleOf(
7607 divisor: number,
7608 annotations?: Annotations.Filter
7609): SchemaAST.Filter<number> {
7610 if (!globalThis.Number.isFinite(divisor) || divisor === 0) {
7611 throw new globalThis.RangeError(`Expected a finite non-zero number, got ${globalThis.String(divisor)}`)
7612 }
7613 divisor = globalThis.Math.abs(divisor)
7614 return makeFilter(
7615 (input: number) => remainder(input, divisor) === 0,
7616 {
7617 expected: `a value that is a multiple of ${divisor}`,
7618 representation: {
7619 id: "effect/schema/isMultipleOf",
7620 payload: { divisor }
7621 },
7622 toJsonSchema: () => ({ multipleOf: divisor }),
7623 toCode: () => ({ runtime: `Schema.isMultipleOf(${format(divisor)})` }),
7624 ...annotations
7625 }
7626 )
7627}
7628/**
7629 * Validates that a number is a safe integer (within the safe integer range
7630 * that can be exactly represented in JavaScript).
7631 *
7632 * **Details**
7633 *
7634 * JSON Schema:
7635 *
7636 * This check corresponds to the `type: "integer"` constraint in JSON Schema.
7637 *
7638 * Arbitrary:
7639 *
7640 * During arbitrary generation, this applies an integer constraint.
7641 *
7642 * @category validation
7643 * @since 4.0.0
7644 */
7645export function isInt(annotations?: Annotations.Filter) {
7646 return makeFilter(
7647 (n: number) => globalThis.Number.isSafeInteger(n),
7648 {
7649 expected: "an integer",
7650 representation: {
7651 id: "effect/schema/isInt",
7652 payload: null
7653 },
7654 toJsonSchema: () => [{ type: "integer" }, true],
7655 toCode: () => ({ runtime: "Schema.isInt()" }),
7656 arbitraryConstraint: {
7657 number: "integer"
7658 },
7659 ...annotations
7660 }
7661 )
7662}
7663/**
7664 * Type-level representation of {@link Int}.
7665 *
7666 * @category models
7667 * @since 3.10.0
7668 */
7669export interface Int extends Number {
7670 readonly "Rebuild": Int
7671}
7672/**
7673 * Schema for integers, rejecting `NaN`, `Infinity`, and `-Infinity`.
7674 *
7675 * @category schemas
7676 * @since 3.10.0
7677 */
7678export const Int: Int = Number.check(isInt())
7679/**
7680 * Type-level representation of {@link Natural}.
7681 *
7682 * @category models
7683 * @since 4.0.0
7684 */
7685export interface Natural extends Int {
7686 readonly "Rebuild": Natural
7687}
7688/**
7689 * Schema for non-negative safe integers, including zero.
7690 *
7691 * **When to use**
7692 *
7693 * Use when you need a count, index, or size that cannot be negative.
7694 *
7695 * @see {@link Int} for safe integers that may be negative
7696 *
7697 * @category schemas
7698 * @since 4.0.0
7699 */
7700export const Natural: Natural = Int.check(isGreaterThanOrEqualTo(0))
7701/**
7702 * Validates that a number is a 32-bit signed integer (range: -2,147,483,648 to
7703 * 2,147,483,647).
7704 *
7705 * **Details**
7706 *
7707 * JSON Schema:
7708 *
7709 * This check corresponds to the `format: "int32"` constraint in OpenAPI 3.1,
7710 * or `minimum`/`maximum` constraints in other JSON Schema targets.
7711 *
7712 * Arbitrary:
7713 *
7714 * During arbitrary generation, this applies integer and range
7715 * constraints to ensure generated numbers are 32-bit signed integers.
7716 *
7717 * @category validation
7718 * @since 4.0.0
7719 */
7720export function isInt32(annotations?: Annotations.Filter) {
7721 return new SchemaAST.FilterGroup(
7722 [
7723 isInt(),
7724 isBetween({ minimum: -2147483648, maximum: 2147483647 })
7725 ],
7726 {
7727 expected: "a 32-bit integer",
7728 ...annotations
7729 }
7730 )
7731}
7732/**
7733 * Validates that a number is a 32-bit unsigned integer (range: 0 to
7734 * 4,294,967,295).
7735 *
7736 * **Details**
7737 *
7738 * JSON Schema:
7739 *
7740 * This check corresponds to the `format: "uint32"` constraint in OpenAPI 3.1,
7741 * or `minimum`/`maximum` constraints in other JSON Schema targets.
7742 *
7743 * Arbitrary:
7744 *
7745 * During arbitrary generation, this applies integer and range
7746 * constraints to ensure generated numbers are 32-bit unsigned integers.
7747 *
7748 * @category validation
7749 * @since 4.0.0
7750 */
7751export function isUint32(annotations?: Annotations.Filter) {
7752 return new SchemaAST.FilterGroup(
7753 [
7754 isInt(),
7755 isBetween({ minimum: 0, maximum: 4294967295 })
7756 ],
7757 {
7758 expected: "a 32-bit unsigned integer",
7759 ...annotations
7760 }
7761 )
7762}
7763
7764function encodeDatePayload(date: globalThis.Date): string {
7765 if (globalThis.Number.isNaN(date.getTime())) {
7766 throw new globalThis.RangeError(`Expected a valid Date, got ${format(date)}`)
7767 }
7768 return date.toISOString()
7769}
7770
7771function formatDateRuntime(date: globalThis.Date): string {
7772 return `new Date(${format(date.getTime())})`
7773}
7774/**
7775 * Validates that a Date is greater than the specified value (exclusive).
7776 *
7777 * **Details**
7778 *
7779 * Arbitrary:
7780 *
7781 * During arbitrary generation, this applies an exclusive lower bound.
7782 *
7783 * @category validation
7784 * @since 4.0.0
7785 */
7786export const isGreaterThanDate: (
7787 exclusiveMinimum: globalThis.Date,
7788 annotations?: Annotations.Filter
7789) => SchemaAST.Filter<globalThis.Date> = makeIsGreaterThan({
7790 order: Order.Date,
7791 annotate: (exclusiveMinimum) => {
7792 const encoded = encodeDatePayload(exclusiveMinimum)
7793 return {
7794 representation: {
7795 id: "effect/schema/isGreaterThanDate",
7796 payload: { exclusiveMinimum: encoded }
7797 },
7798 toJsonSchema: () => [{}, true],
7799 toCode: () => ({ runtime: `Schema.isGreaterThanDate(${formatDateRuntime(exclusiveMinimum)})` })
7800 }
7801 }
7802})
7803/**
7804 * Validates that a Date is greater than or equal to the specified date
7805 * (inclusive).
7806 *
7807 * **Details**
7808 *
7809 * JSON Schema:
7810 *
7811 * This check does not have a direct JSON Schema equivalent, as JSON Schema
7812 * validates date strings, not Date objects.
7813 *
7814 * Arbitrary:
7815 *
7816 * During arbitrary generation, this applies an inclusive lower bound.
7817 *
7818 * @category validation
7819 * @since 4.0.0
7820 */
7821export const isGreaterThanOrEqualToDate: (
7822 minimum: globalThis.Date,
7823 annotations?: Annotations.Filter
7824) => SchemaAST.Filter<globalThis.Date> = makeIsGreaterThanOrEqualTo({
7825 order: Order.Date,
7826 annotate: (minimum) => {
7827 const encoded = encodeDatePayload(minimum)
7828 return {
7829 representation: {
7830 id: "effect/schema/isGreaterThanOrEqualToDate",
7831 payload: { minimum: encoded }
7832 },
7833 toJsonSchema: () => [{}, true],
7834 toCode: () => ({ runtime: `Schema.isGreaterThanOrEqualToDate(${formatDateRuntime(minimum)})` })
7835 }
7836 }
7837})
7838/**
7839 * Validates that a Date is less than the specified value (exclusive).
7840 *
7841 * **Details**
7842 *
7843 * Arbitrary:
7844 *
7845 * During arbitrary generation, this applies an exclusive upper bound.
7846 *
7847 * @category validation
7848 * @since 4.0.0
7849 */
7850export const isLessThanDate: (
7851 exclusiveMaximum: globalThis.Date,
7852 annotations?: Annotations.Filter
7853) => SchemaAST.Filter<globalThis.Date> = makeIsLessThan({
7854 order: Order.Date,
7855 annotate: (exclusiveMaximum) => {
7856 const encoded = encodeDatePayload(exclusiveMaximum)
7857 return {
7858 representation: {
7859 id: "effect/schema/isLessThanDate",
7860 payload: { exclusiveMaximum: encoded }
7861 },
7862 toJsonSchema: () => [{}, true],
7863 toCode: () => ({ runtime: `Schema.isLessThanDate(${formatDateRuntime(exclusiveMaximum)})` })
7864 }
7865 }
7866})
7867/**
7868 * Validates that a Date is less than or equal to the specified date
7869 * (inclusive).
7870 *
7871 * **Details**
7872 *
7873 * JSON Schema:
7874 *
7875 * This check does not have a direct JSON Schema equivalent, as JSON Schema
7876 * validates date strings, not Date objects.
7877 *
7878 * Arbitrary:
7879 *
7880 * During arbitrary generation, this applies an inclusive upper bound.
7881 *
7882 * @category validation
7883 * @since 4.0.0
7884 */
7885export const isLessThanOrEqualToDate: (
7886 maximum: globalThis.Date,
7887 annotations?: Annotations.Filter
7888) => SchemaAST.Filter<globalThis.Date> = makeIsLessThanOrEqualTo({
7889 order: Order.Date,
7890 annotate: (maximum) => {
7891 const encoded = encodeDatePayload(maximum)
7892 return {
7893 representation: {
7894 id: "effect/schema/isLessThanOrEqualToDate",
7895 payload: { maximum: encoded }
7896 },
7897 toJsonSchema: () => [{}, true],
7898 toCode: () => ({ runtime: `Schema.isLessThanOrEqualToDate(${formatDateRuntime(maximum)})` })
7899 }
7900 }
7901})
7902/**
7903 * Validates that a Date is within a specified range. The range boundaries can
7904 * be inclusive or exclusive based on the provided options.
7905 *
7906 * **Details**
7907 *
7908 * JSON Schema:
7909 *
7910 * This check does not have a direct JSON Schema equivalent, as JSON Schema
7911 * validates date strings, not Date objects.
7912 *
7913 * Arbitrary:
7914 *
7915 * During arbitrary generation, this applies the specified lower and upper bounds.
7916 *
7917 * @category validation
7918 * @since 4.0.0
7919 */
7920export const isBetweenDate: (options: {
7921 readonly minimum: globalThis.Date
7922 readonly maximum: globalThis.Date
7923 readonly exclusiveMinimum?: boolean | undefined
7924 readonly exclusiveMaximum?: boolean | undefined
7925}, annotations?: Annotations.Filter) => SchemaAST.Filter<globalThis.Date> = makeIsBetween({
7926 order: Order.Date,
7927 annotate: (options) => {
7928 const exclusiveMinimum = options.exclusiveMinimum ? true : undefined
7929 const exclusiveMaximum = options.exclusiveMaximum ? true : undefined
7930 const payload = {
7931 minimum: encodeDatePayload(options.minimum),
7932 maximum: encodeDatePayload(options.maximum),
7933 ...(exclusiveMinimum && { exclusiveMinimum }),
7934 ...(exclusiveMaximum && { exclusiveMaximum })
7935 }
7936 return {
7937 representation: {
7938 id: "effect/schema/isBetweenDate",
7939 payload
7940 },
7941 toJsonSchema: () => [{}, true],
7942 toCode: () => ({
7943 runtime: `Schema.isBetweenDate({ minimum: ${formatDateRuntime(options.minimum)}, maximum: ${
7944 formatDateRuntime(options.maximum)
7945 }, exclusiveMinimum: ${format(exclusiveMinimum)}, exclusiveMaximum: ${format(exclusiveMaximum)} })`
7946 })
7947 }
7948 }
7949})
7950/**
7951 * Validates that a BigInt is greater than the specified value (exclusive).
7952 *
7953 * **Details**
7954 *
7955 * Arbitrary:
7956 *
7957 * During arbitrary generation, this applies an exclusive lower bound.
7958 *
7959 * @category validation
7960 * @since 4.0.0
7961 */
7962export const isGreaterThanBigInt: (
7963 exclusiveMinimum: bigint,
7964 annotations?: Annotations.Filter
7965) => SchemaAST.Filter<bigint> = makeIsGreaterThan({
7966 order: Order.BigInt,
7967 annotate: (exclusiveMinimum) => {
7968 const encoded = exclusiveMinimum.toString(10)
7969 return {
7970 representation: {
7971 id: "effect/schema/isGreaterThanBigInt",
7972 payload: { exclusiveMinimum: encoded }
7973 },
7974 toJsonSchema: () => [{}, true],
7975 toCode: () => ({ runtime: `Schema.isGreaterThanBigInt(${format(exclusiveMinimum)})` })
7976 }
7977 }
7978})
7979/**
7980 * Validates that a BigInt is greater than or equal to the specified value
7981 * (inclusive).
7982 *
7983 * **Details**
7984 *
7985 * Arbitrary:
7986 *
7987 * During arbitrary generation, this applies an inclusive lower bound.
7988 *
7989 * @category validation
7990 * @since 4.0.0
7991 */
7992export const isGreaterThanOrEqualToBigInt: (
7993 minimum: bigint,
7994 annotations?: Annotations.Filter
7995) => SchemaAST.Filter<bigint> = makeIsGreaterThanOrEqualTo({
7996 order: Order.BigInt,
7997 annotate: (minimum) => {
7998 const encoded = minimum.toString(10)
7999 return {
8000 representation: {
8001 id: "effect/schema/isGreaterThanOrEqualToBigInt",
8002 payload: { minimum: encoded }
8003 },
8004 toJsonSchema: () => [{}, true],
8005 toCode: () => ({ runtime: `Schema.isGreaterThanOrEqualToBigInt(${format(minimum)})` })
8006 }
8007 }
8008})
8009/**
8010 * Validates that a BigInt is less than the specified value (exclusive).
8011 *
8012 * **Details**
8013 *
8014 * Arbitrary:
8015 *
8016 * During arbitrary generation, this applies an exclusive upper bound.
8017 *
8018 * @category validation
8019 * @since 4.0.0
8020 */
8021export const isLessThanBigInt: (
8022 exclusiveMaximum: bigint,
8023 annotations?: Annotations.Filter
8024) => SchemaAST.Filter<bigint> = makeIsLessThan({
8025 order: Order.BigInt,
8026 annotate: (exclusiveMaximum) => {
8027 const encoded = exclusiveMaximum.toString(10)
8028 return {
8029 representation: {
8030 id: "effect/schema/isLessThanBigInt",
8031 payload: { exclusiveMaximum: encoded }
8032 },
8033 toJsonSchema: () => [{}, true],
8034 toCode: () => ({ runtime: `Schema.isLessThanBigInt(${format(exclusiveMaximum)})` })
8035 }
8036 }
8037})
8038/**
8039 * Validates that a BigInt is less than or equal to the specified value
8040 * (inclusive).
8041 *
8042 * **Details**
8043 *
8044 * Arbitrary:
8045 *
8046 * During arbitrary generation, this applies an inclusive upper bound.
8047 *
8048 * @category validation
8049 * @since 4.0.0
8050 */
8051export const isLessThanOrEqualToBigInt: (
8052 maximum: bigint,
8053 annotations?: Annotations.Filter
8054) => SchemaAST.Filter<bigint> = makeIsLessThanOrEqualTo({
8055 order: Order.BigInt,
8056 annotate: (maximum) => {
8057 const encoded = maximum.toString(10)
8058 return {
8059 representation: {
8060 id: "effect/schema/isLessThanOrEqualToBigInt",
8061 payload: { maximum: encoded }
8062 },
8063 toJsonSchema: () => [{}, true],
8064 toCode: () => ({ runtime: `Schema.isLessThanOrEqualToBigInt(${format(maximum)})` })
8065 }
8066 }
8067})
8068/**
8069 * Validates that a BigInt is within a specified range. The range boundaries can
8070 * be inclusive or exclusive based on the provided options.
8071 *
8072 * **Details**
8073 *
8074 * Arbitrary:
8075 *
8076 * During arbitrary generation, this applies the specified lower and upper bounds.
8077 *
8078 * @category validation
8079 * @since 4.0.0
8080 */
8081export const isBetweenBigInt: (options: {
8082 readonly minimum: bigint
8083 readonly maximum: bigint
8084 readonly exclusiveMinimum?: boolean | undefined
8085 readonly exclusiveMaximum?: boolean | undefined
8086}, annotations?: Annotations.Filter) => SchemaAST.Filter<bigint> = makeIsBetween({
8087 order: Order.BigInt,
8088 annotate: (options) => {
8089 const exclusiveMinimum = options.exclusiveMinimum ? true : undefined
8090 const exclusiveMaximum = options.exclusiveMaximum ? true : undefined
8091 const payload = {
8092 minimum: options.minimum.toString(10),
8093 maximum: options.maximum.toString(10),
8094 ...(exclusiveMinimum && { exclusiveMinimum }),
8095 ...(exclusiveMaximum && { exclusiveMaximum })
8096 }
8097 return {
8098 representation: {
8099 id: "effect/schema/isBetweenBigInt",
8100 payload
8101 },
8102 toJsonSchema: () => [{}, true],
8103 toCode: () => ({
8104 runtime: `Schema.isBetweenBigInt({ minimum: ${format(options.minimum)}, maximum: ${
8105 format(options.maximum)
8106 }, exclusiveMinimum: ${format(exclusiveMinimum)}, exclusiveMaximum: ${format(exclusiveMaximum)} })`
8107 })
8108 }
8109 }
8110})
8111
8112/**
8113 * Validates that a value has at least the specified length. Works with strings
8114 * and arrays.
8115 *
8116 * **Details**
8117 *
8118 * JSON Schema:
8119 *
8120 * The bound must be finite; it is rounded down and clamped to zero. For arrays,
8121 * this check corresponds to `minItems`. JavaScript counts UTF-16 code units
8122 * while JSON Schema counts Unicode code points, so strings use
8123 * `minLength: Math.ceil(minLength / 2)`, the tightest lower bound that cannot
8124 * reject a string accepted by this check.
8125 *
8126 * Arbitrary:
8127 *
8128 * During arbitrary generation, this applies a `minLength`
8129 * constraint to ensure generated strings or arrays have at least the required
8130 * length.
8131 *
8132 * **Example** (Checking minimum length)
8133 *
8134 * ```ts import.meta.vitest
8135 * import { Schema } from "effect"
8136 *
8137 * const NonEmptyStringSchema = Schema.String.check(Schema.isMinLength(1))
8138 * const NonEmptyArraySchema = Schema.Array(Schema.Number).check(Schema.isMinLength(1))
8139 * Schema.is(NonEmptyStringSchema)("a") // => true
8140 * Schema.is(NonEmptyArraySchema)([1]) // => true
8141 * ```
8142 *
8143 * @category validation
8144 * @since 4.0.0
8145 */
8146export function isMinLength(minLength: number, annotations?: Annotations.Filter) {
8147 minLength = normalizeCardinality(minLength)
8148 return makeIsMinLength(minLength, Math.ceil(minLength / 2), annotations)
8149}
8150
8151function makeIsMinLength(minLength: number, minCodePoints: number, annotations?: Annotations.Filter) {
8152 return makeFilter<{ readonly length: number }>(
8153 (input) => input.length >= minLength,
8154 {
8155 expected: `a value with a length of at least ${minLength}`,
8156 representation: {
8157 id: "effect/schema/isMinLength",
8158 payload: { minLength }
8159 },
8160 toJsonSchema: ({ type }) =>
8161 type === "string"
8162 ? minLength <= 1
8163 ? { minLength: minCodePoints }
8164 : [{ minLength: minCodePoints }, true]
8165 : type === "array"
8166 ? { minItems: minLength }
8167 : type === undefined
8168 ? [{ minLength: minCodePoints, minItems: minLength }, true]
8169 : [{}, true],
8170 toCode: () => ({ runtime: `Schema.isMinLength(${minLength})` }),
8171 [InternalAnnotations.STRUCTURAL_ANNOTATION_KEY]: true,
8172 arbitraryConstraint: {
8173 minLength
8174 },
8175 ...annotations
8176 }
8177 )
8178}
8179/**
8180 * Validates that a value has at least one element. Works with strings and arrays.
8181 * This is equivalent to `isMinLength(1)`.
8182 *
8183 * **Details**
8184 *
8185 * JSON Schema:
8186 *
8187 * This check corresponds to the `minLength: 1` constraint for strings or the
8188 * `minItems: 1` constraint for arrays in JSON Schema.
8189 *
8190 * Arbitrary:
8191 *
8192 * During arbitrary generation, this applies a `minLength: 1`
8193 * constraint to ensure generated strings or arrays are non-empty.
8194 *
8195 * @category validation
8196 * @since 4.0.0
8197 */
8198export function isNonEmpty(annotations?: Annotations.Filter) {
8199 return makeIsMinLength(1, 1, annotations)
8200}
8201/**
8202 * Validates that a value has at most the specified length. Works with strings
8203 * and arrays.
8204 *
8205 * **Details**
8206 *
8207 * JSON Schema:
8208 *
8209 * The bound must be finite; it is rounded down and clamped to zero. This check
8210 * corresponds to `maxItems` for arrays. Strings use the same bound for
8211 * `maxLength`, which cannot reject a string accepted by this check because a
8212 * string has no more code points than UTF-16 code units.
8213 *
8214 * Arbitrary:
8215 *
8216 * During arbitrary generation, this applies a `maxLength`
8217 * constraint to ensure generated strings or arrays have at most the required
8218 * length.
8219 *
8220 * @category validation
8221 * @since 4.0.0
8222 */
8223export function isMaxLength(maxLength: number, annotations?: Annotations.Filter) {
8224 maxLength = normalizeCardinality(maxLength)
8225 return makeFilter<{ readonly length: number }>(
8226 (input) => input.length <= maxLength,
8227 {
8228 expected: `a value with a length of at most ${maxLength}`,
8229 representation: {
8230 id: "effect/schema/isMaxLength",
8231 payload: { maxLength }
8232 },
8233 toJsonSchema: ({ type }) =>
8234 type === "string"
8235 ? maxLength === 0 ? { maxLength } : [{ maxLength }, true]
8236 : type === "array"
8237 ? { maxItems: maxLength }
8238 : type === undefined
8239 ? [{ maxLength, maxItems: maxLength }, true]
8240 : [{}, true],
8241 toCode: () => ({ runtime: `Schema.isMaxLength(${maxLength})` }),
8242 [InternalAnnotations.STRUCTURAL_ANNOTATION_KEY]: true,
8243 arbitraryConstraint: {
8244 maxLength
8245 },
8246 ...annotations
8247 }
8248 )
8249}
8250/**
8251 * Validates that a value's length is within the specified range. Works with
8252 * strings and arrays.
8253 *
8254 * **Details**
8255 *
8256 * JSON Schema:
8257 *
8258 * Both bounds must be finite; they are rounded down and clamped to zero. Arrays
8259 * use the same bounds for `minItems` and `maxItems`. JavaScript counts UTF-16
8260 * code units while JSON Schema counts Unicode code points, so strings use
8261 * `Math.ceil(minimum / 2)` for `minLength` and `maximum` for `maxLength`. These
8262 * are the tightest bounds that cannot reject a string accepted by this check.
8263 *
8264 * Arbitrary:
8265 *
8266 * During arbitrary generation, this applies `minLength` and
8267 * `maxLength` constraints to ensure generated strings or arrays have a length
8268 * within the specified range.
8269 *
8270 * @category validation
8271 * @since 4.0.0
8272 */
8273export function isBetweenLength(minimum: number, maximum: number, annotations?: Annotations.Filter) {
8274 minimum = normalizeCardinality(minimum)
8275 maximum = normalizeCardinality(maximum)
8276 return makeFilter<{ readonly length: number }>(
8277 (input) => input.length >= minimum && input.length <= maximum,
8278 {
8279 expected: minimum === maximum
8280 ? `a value with a length of ${minimum}`
8281 : `a value with a length between ${minimum} and ${maximum}`,
8282
8283 representation: {
8284 id: "effect/schema/isBetweenLength",
8285 payload: { minimum, maximum }
8286 },
8287 toJsonSchema: ({ type }) =>
8288 type === "string"
8289 ? maximum === 0 || Math.ceil(minimum / 2) > maximum
8290 ? { minLength: Math.ceil(minimum / 2), maxLength: maximum }
8291 : [{ minLength: Math.ceil(minimum / 2), maxLength: maximum }, true]
8292 : type === "array"
8293 ? { minItems: minimum, maxItems: maximum }
8294 : type === undefined
8295 ? [{
8296 minLength: Math.ceil(minimum / 2),
8297 maxLength: maximum,
8298 minItems: minimum,
8299 maxItems: maximum
8300 }, true]
8301 : [{}, true],
8302 toCode: () => ({ runtime: `Schema.isBetweenLength(${minimum}, ${maximum})` }),
8303 [InternalAnnotations.STRUCTURAL_ANNOTATION_KEY]: true,
8304 arbitraryConstraint: {
8305 minLength: minimum,
8306 maxLength: maximum
8307 },
8308 ...annotations
8309 }
8310 )
8311}
8312/**
8313 * Validates that a string contains at least the specified number of Unicode code points.
8314 *
8315 * **Details**
8316 *
8317 * The bound must be finite; it is rounded down and clamped to zero. This check
8318 * corresponds to `minLength` in JSON Schema and guides arbitrary generation by
8319 * code point count.
8320 *
8321 * **Gotchas**
8322 *
8323 * Code points are not grapheme clusters: combining marks and joined emoji can
8324 * contribute multiple code points to one visible character. Unpaired UTF-16
8325 * surrogates count as one code point each. This check does not normalize strings.
8326 *
8327 * @see {@link isMinLength} for counting UTF-16 code units
8328 * @see {@link isMaxCodePoints}
8329 * @see {@link isBetweenCodePoints}
8330 * @category validation
8331 * @since 4.0.0
8332 */
8333export function isMinCodePoints(minCodePoints: number, annotations?: Annotations.Filter) {
8334 minCodePoints = normalizeCardinality(minCodePoints)
8335 return makeFilter<string>(
8336 (input) => countCodePointsUpTo(input, minCodePoints) >= minCodePoints,
8337 {
8338 expected: `a string with at least ${minCodePoints} code points`,
8339 representation: {
8340 id: "effect/schema/isMinCodePoints",
8341 payload: { minCodePoints }
8342 },
8343 toJsonSchema: () => ({ minLength: minCodePoints }),
8344 toCode: () => ({ runtime: `Schema.isMinCodePoints(${minCodePoints})` }),
8345 arbitraryConstraint: { minCodePoints },
8346 ...annotations
8347 }
8348 )
8349}
8350/**
8351 * Validates that a string contains at most the specified number of Unicode code points.
8352 *
8353 * **Details**
8354 *
8355 * The bound must be finite; it is rounded down and clamped to zero. This check
8356 * corresponds to `maxLength` in JSON Schema and guides arbitrary generation by
8357 * code point count.
8358 *
8359 * **Gotchas**
8360 *
8361 * Code points are not grapheme clusters: combining marks and joined emoji can
8362 * contribute multiple code points to one visible character. Unpaired UTF-16
8363 * surrogates count as one code point each. This check does not normalize strings.
8364 *
8365 * @see {@link isMaxLength} for counting UTF-16 code units
8366 * @see {@link isMinCodePoints}
8367 * @see {@link isBetweenCodePoints}
8368 * @category validation
8369 * @since 4.0.0
8370 */
8371export function isMaxCodePoints(maxCodePoints: number, annotations?: Annotations.Filter) {
8372 maxCodePoints = normalizeCardinality(maxCodePoints)
8373 return makeFilter<string>(
8374 (input) => countCodePointsUpTo(input, maxCodePoints + 1) <= maxCodePoints,
8375 {
8376 expected: `a string with at most ${maxCodePoints} code points`,
8377 representation: {
8378 id: "effect/schema/isMaxCodePoints",
8379 payload: { maxCodePoints }
8380 },
8381 toJsonSchema: () => ({ maxLength: maxCodePoints }),
8382 toCode: () => ({ runtime: `Schema.isMaxCodePoints(${maxCodePoints})` }),
8383 arbitraryConstraint: { maxCodePoints },
8384 ...annotations
8385 }
8386 )
8387}
8388/**
8389 * Validates that a string's Unicode code point count is within the specified inclusive range.
8390 *
8391 * **Details**
8392 *
8393 * Bounds must be finite; they are rounded down and clamped to zero. Equal bounds
8394 * require an exact count. This check corresponds to `minLength` and `maxLength`
8395 * in JSON Schema and guides arbitrary generation by code point count.
8396 *
8397 * **Gotchas**
8398 *
8399 * Code points are not grapheme clusters: combining marks and joined emoji can
8400 * contribute multiple code points to one visible character. Unpaired UTF-16
8401 * surrogates count as one code point each. This check does not normalize strings.
8402 *
8403 * @see {@link isBetweenLength} for counting UTF-16 code units
8404 * @see {@link isMinCodePoints}
8405 * @see {@link isMaxCodePoints}
8406 * @category validation
8407 * @since 4.0.0
8408 */
8409export function isBetweenCodePoints(minimum: number, maximum: number, annotations?: Annotations.Filter) {
8410 minimum = normalizeCardinality(minimum)
8411 maximum = normalizeCardinality(maximum)
8412 return makeFilter<string>(
8413 (input) => {
8414 const count = countCodePointsUpTo(input, maximum + 1)
8415 return count >= minimum && count <= maximum
8416 },
8417 {
8418 expected: minimum === maximum
8419 ? `a string with ${minimum} code points`
8420 : `a string with between ${minimum} and ${maximum} code points`,
8421 representation: {
8422 id: "effect/schema/isBetweenCodePoints",
8423 payload: { minimum, maximum }
8424 },
8425 toJsonSchema: () => ({ allOf: [{ minLength: minimum }, { maxLength: maximum }] }),
8426 toCode: () => ({ runtime: `Schema.isBetweenCodePoints(${minimum}, ${maximum})` }),
8427 arbitraryConstraint: { minCodePoints: minimum, maxCodePoints: maximum },
8428 ...annotations
8429 }
8430 )
8431}
8432
8433function countCodePointsUpTo(input: string, limit: number): number {
8434 if (limit === 0) return 0
8435 let count = 0
8436 for (const _ of input) {
8437 if (++count >= limit) break
8438 }
8439 return count
8440}
8441
8442function normalizeCardinality(value: number): number {
8443 if (!globalThis.Number.isFinite(value)) {
8444 throw new globalThis.RangeError(`Expected a finite number, got ${value}`)
8445 }
8446 return Math.max(0, Math.floor(value))
8447}
8448
8449/**
8450 * Validates that a value has at least the specified size. Works with values
8451 * that have a `size` property, such as `Set` or `Map`.
8452 *
8453 * **Details**
8454 *
8455 * The bound must be finite; it is rounded down and clamped to zero.
8456 *
8457 * JSON Schema:
8458 *
8459 * This check does not have a direct JSON Schema equivalent, as it applies to
8460 * values with a `size` property rather than standard JSON Schema types.
8461 *
8462 * Arbitrary:
8463 *
8464 * During arbitrary generation, this applies a node-local `minSize` constraint.
8465 *
8466 * @category validation
8467 * @since 4.0.0
8468 */
8469export function isMinSize(minSize: number, annotations?: Annotations.Filter) {
8470 minSize = normalizeCardinality(minSize)
8471 return makeFilter<{ readonly size: number }>(
8472 (input) => input.size >= minSize,
8473 {
8474 expected: `a value with a size of at least ${minSize}`,
8475 representation: {
8476 id: "effect/schema/isMinSize",
8477 payload: { minSize }
8478 },
8479 toJsonSchema: () => [{}, true],
8480 toCode: () => ({ runtime: `Schema.isMinSize(${minSize})` }),
8481 [InternalAnnotations.STRUCTURAL_ANNOTATION_KEY]: true,
8482 arbitraryConstraint: {
8483 minSize
8484 },
8485 ...annotations
8486 }
8487 )
8488}
8489/**
8490 * Validates that a value has at most the specified size. Works with values
8491 * that have a `size` property, such as `Set` or `Map`.
8492 *
8493 * **Details**
8494 *
8495 * The bound must be finite; it is rounded down and clamped to zero.
8496 *
8497 * JSON Schema:
8498 *
8499 * This check does not have a direct JSON Schema equivalent, as it applies to
8500 * values with a `size` property rather than standard JSON Schema types.
8501 *
8502 * Arbitrary:
8503 *
8504 * During arbitrary generation, this applies a node-local `maxSize` constraint.
8505 *
8506 * @category validation
8507 * @since 4.0.0
8508 */
8509export function isMaxSize(maxSize: number, annotations?: Annotations.Filter) {
8510 maxSize = normalizeCardinality(maxSize)
8511 return makeFilter<{ readonly size: number }>(
8512 (input) => input.size <= maxSize,
8513 {
8514 expected: `a value with a size of at most ${maxSize}`,
8515 representation: {
8516 id: "effect/schema/isMaxSize",
8517 payload: { maxSize }
8518 },
8519 toJsonSchema: () => [{}, true],
8520 toCode: () => ({ runtime: `Schema.isMaxSize(${maxSize})` }),
8521 [InternalAnnotations.STRUCTURAL_ANNOTATION_KEY]: true,
8522 arbitraryConstraint: {
8523 maxSize
8524 },
8525 ...annotations
8526 }
8527 )
8528}
8529/**
8530 * Validates that a value's size is within the specified range. Works with
8531 * values that have a `size` property, such as `Set` or `Map`.
8532 *
8533 * **Details**
8534 *
8535 * Both bounds must be finite; they are rounded down and clamped to zero.
8536 *
8537 * JSON Schema:
8538 *
8539 * This check does not have a direct JSON Schema equivalent, as it applies to
8540 * values with a `size` property rather than standard JSON Schema types.
8541 *
8542 * Arbitrary:
8543 *
8544 * During arbitrary generation, this applies node-local `minSize` and `maxSize` constraints.
8545 *
8546 * @category validation
8547 * @since 4.0.0
8548 */
8549export function isBetweenSize(minimum: number, maximum: number, annotations?: Annotations.Filter) {
8550 minimum = normalizeCardinality(minimum)
8551 maximum = normalizeCardinality(maximum)
8552 return makeFilter<{ readonly size: number }>(
8553 (input) => input.size >= minimum && input.size <= maximum,
8554 {
8555 expected: minimum === maximum
8556 ? `a value with a size of ${minimum}`
8557 : `a value with a size between ${minimum} and ${maximum}`,
8558
8559 representation: {
8560 id: "effect/schema/isBetweenSize",
8561 payload: { minimum, maximum }
8562 },
8563 toJsonSchema: () => [{}, true],
8564 toCode: () => ({ runtime: `Schema.isBetweenSize(${minimum}, ${maximum})` }),
8565 [InternalAnnotations.STRUCTURAL_ANNOTATION_KEY]: true,
8566 arbitraryConstraint: {
8567 minSize: minimum,
8568 maxSize: maximum
8569 },
8570 ...annotations
8571 }
8572 )
8573}
8574/**
8575 * Validates that an object contains at least the specified number of
8576 * properties. This includes both string and symbol keys when counting
8577 * properties.
8578 *
8579 * **Details**
8580 *
8581 * The bound must be finite; it is rounded down and clamped to zero.
8582 *
8583 * JSON Schema:
8584 *
8585 * This check corresponds to `minProperties` in JSON Schema. Effect applies the
8586 * check to the decoded object, while JSON Schema applies it to the original
8587 * input. Defaults and property transformations can therefore produce different
8588 * results.
8589 *
8590 * Arbitrary:
8591 *
8592 * During arbitrary generation, this applies a node-local `minProperties` constraint.
8593 *
8594 * @category validation
8595 * @since 4.0.0
8596 */
8597export function isMinProperties(minProperties: number, annotations?: Annotations.Filter) {
8598 minProperties = normalizeCardinality(minProperties)
8599 return makeFilter<object>(
8600 (input) => Reflect.ownKeys(input).length >= minProperties,
8601 {
8602 expected: `a value with at least ${minProperties === 1 ? "1 entry" : `${minProperties} entries`}`,
8603 representation: {
8604 id: "effect/schema/isMinProperties",
8605 payload: { minProperties }
8606 },
8607 toJsonSchema: ({ type }) => type === "object" ? { minProperties } : [{ minProperties }, true],
8608 toCode: () => ({ runtime: `Schema.isMinProperties(${minProperties})` }),
8609 [InternalAnnotations.STRUCTURAL_ANNOTATION_KEY]: true,
8610 arbitraryConstraint: {
8611 minProperties
8612 },
8613 ...annotations
8614 }
8615 )
8616}
8617/**
8618 * Validates that an object contains at most the specified number of properties.
8619 * This includes both string and symbol keys when counting properties.
8620 *
8621 * **Details**
8622 *
8623 * The bound must be finite; it is rounded down and clamped to zero.
8624 *
8625 * JSON Schema:
8626 *
8627 * This check corresponds to `maxProperties` in JSON Schema. Effect applies the
8628 * check to the decoded object, while JSON Schema applies it to the original
8629 * input. Excess-property handling and property transformations can therefore
8630 * produce different results.
8631 *
8632 * Arbitrary:
8633 *
8634 * During arbitrary generation, this applies a node-local `maxProperties` constraint.
8635 *
8636 * @category validation
8637 * @since 4.0.0
8638 */
8639export function isMaxProperties(maxProperties: number, annotations?: Annotations.Filter) {
8640 maxProperties = normalizeCardinality(maxProperties)
8641 return makeFilter<object>(
8642 (input) => Reflect.ownKeys(input).length <= maxProperties,
8643 {
8644 expected: `a value with at most ${maxProperties === 1 ? "1 entry" : `${maxProperties} entries`}`,
8645 representation: {
8646 id: "effect/schema/isMaxProperties",
8647 payload: { maxProperties }
8648 },
8649 toJsonSchema: ({ type }) => type === "object" ? { maxProperties } : [{ maxProperties }, true],
8650 toCode: () => ({ runtime: `Schema.isMaxProperties(${maxProperties})` }),
8651 [InternalAnnotations.STRUCTURAL_ANNOTATION_KEY]: true,
8652 arbitraryConstraint: {
8653 maxProperties
8654 },
8655 ...annotations
8656 }
8657 )
8658}
8659/**
8660 * Validates that an object contains between `minimum` and `maximum` properties (inclusive).
8661 * This includes both string and symbol keys when counting properties.
8662 *
8663 * **Details**
8664 *
8665 * Both bounds must be finite; they are rounded down and clamped to zero.
8666 *
8667 * JSON Schema:
8668 *
8669 * This check corresponds to `minProperties` and `maxProperties` in JSON
8670 * Schema. Effect applies the check to the decoded object, while JSON Schema
8671 * applies it to the original input. Defaults, excess-property handling, and
8672 * property transformations can therefore produce different results.
8673 *
8674 * Arbitrary:
8675 *
8676 * During arbitrary generation, this applies node-local `minProperties` and `maxProperties` constraints.
8677 *
8678 * @category validation
8679 * @since 4.0.0
8680 */
8681export function isBetweenProperties(minimum: number, maximum: number, annotations?: Annotations.Filter) {
8682 minimum = normalizeCardinality(minimum)
8683 maximum = normalizeCardinality(maximum)
8684 return makeFilter<object>(
8685 (input) => Reflect.ownKeys(input).length >= minimum && Reflect.ownKeys(input).length <= maximum,
8686 {
8687 expected: minimum === maximum
8688 ? `a value with exactly ${minimum === 1 ? "1 entry" : `${minimum} entries`}`
8689 : `a value with between ${minimum} and ${maximum} entries`,
8690
8691 representation: {
8692 id: "effect/schema/isBetweenProperties",
8693 payload: { minimum, maximum }
8694 },
8695 toJsonSchema: ({ type }) =>
8696 type === "object"
8697 ? { minProperties: minimum, maxProperties: maximum }
8698 : [{ minProperties: minimum, maxProperties: maximum }, true],
8699 toCode: () => ({ runtime: `Schema.isBetweenProperties(${minimum}, ${maximum})` }),
8700 [InternalAnnotations.STRUCTURAL_ANNOTATION_KEY]: true,
8701 arbitraryConstraint: {
8702 minProperties: minimum,
8703 maxProperties: maximum
8704 },
8705 ...annotations
8706 }
8707 )
8708}
8709/**
8710 * Validates that every own property key of an object satisfies the encoded side
8711 * of the provided key schema.
8712 *
8713 * **Details**
8714 *
8715 * This check uses `Reflect.ownKeys`, so symbol keys are validated in addition to
8716 * string property names.
8717 *
8718 * JSON Schema:
8719 * This check corresponds to `propertyNames` in JSON Schema. Effect checks the
8720 * decoded object's keys, including symbols, while JSON Schema checks the string
8721 * names in the original input. Property transformations and excess-property
8722 * handling can therefore produce different results.
8723 *
8724 * @category validation
8725 * @since 4.0.0
8726 */
8727export function isPropertyNames(keySchema: Constraint, annotations?: Annotations.Filter) {
8728 const propertyNames = toEncoded(keySchema)
8729 const parser = SchemaParser._issue(propertyNames.ast)
8730 return makeFilter<object>(
8731 (input, ast, options) => {
8732 const keys = Reflect.ownKeys(input)
8733 const issues: Array<SchemaIssue.Issue> = []
8734 for (const key of keys) {
8735 const issue = parser(key, options)
8736 if (issue !== undefined) {
8737 issues.push(new SchemaIssue.Pointer([key], issue))
8738 if (options.errors === "first") break
8739 }
8740 }
8741 if (Arr.isArrayNonEmpty(issues)) {
8742 return new SchemaIssue.Composite(ast, issues, input, options)
8743 }
8744 return true
8745 },
8746 {
8747 expected: "an object with property names matching the schema",
8748 representation: {
8749 id: "effect/schema/isPropertyNames",
8750 payload: null,
8751 schemas: [propertyNames.ast]
8752 },
8753 toJsonSchema: ({ schemas, type }) =>
8754 type === "object" ? { propertyNames: schemas[0] } : [{ propertyNames: schemas[0] }, true],
8755 toCode: ({ schemas }) => ({ runtime: `Schema.isPropertyNames(${schemas[0].runtime})` }),
8756 [InternalAnnotations.STRUCTURAL_ANNOTATION_KEY]: true,
8757 ...annotations
8758 }
8759 )
8760}
8761/**
8762 * Validates that all items in an array are unique according to Effect equality.
8763 *
8764 * **Details**
8765 *
8766 * JSON Schema:
8767 * This check corresponds to the `uniqueItems: true` constraint in JSON Schema.
8768 *
8769 * Arbitrary:
8770 * During arbitrary generation, this applies a node-local identity selector
8771 * for constructive uniqueness using Effect equality.
8772 *
8773 * @category validation
8774 * @since 4.0.0
8775 */
8776export function isUnique<T>(annotations?: Annotations.Filter) {
8777 return makeFilter<ReadonlyArray<T>>(
8778 (input) => Arr.dedupe(input).length === input.length,
8779 {
8780 expected: "an array with unique items",
8781 representation: {
8782 id: "effect/schema/isUnique",
8783 payload: null
8784 },
8785 toJsonSchema: () => ({ uniqueItems: true }),
8786 toCode: () => ({ runtime: "Schema.isUnique()" }),
8787 arbitraryConstraint: {
8788 uniqueBy: identity
8789 },
8790 ...annotations
8791 }
8792 )
8793}
8794/**
8795 * Validates that all first elements in an array of key-value tuples are unique according to Effect equality.
8796 *
8797 * **Details**
8798 *
8799 * Arbitrary:
8800 * During arbitrary generation, this projects each entry to its key for constructive uniqueness.
8801 *
8802 * JSON Schema:
8803 * JSON Schema has no equivalent constraint, so this check is omitted from generated documents.
8804 *
8805 * @see {@link isUnique} for validating uniqueness of complete array elements
8806 * @category validation
8807 * @since 4.0.0
8808 */
8809export function isUniqueKey<Key, Value>(annotations?: Annotations.Filter) {
8810 return makeFilter<ReadonlyArray<readonly [Key, Value]>>(
8811 (input) => Arr.dedupe(input.map(([key]) => key)).length === input.length,
8812 {
8813 expected: "an array with unique keys",
8814 representation: {
8815 id: "effect/schema/isUniqueKey",
8816 payload: null
8817 },
8818 toCode: () => ({ runtime: "Schema.isUniqueKey()" }),
8819 arbitraryConstraint: {
8820 uniqueBy: (entry: readonly [Key, Value]) => entry[0]
8821 },
8822 ...annotations
8823 }
8824 )
8825}
8826/**
8827 * Type-level representation of {@link NonEmptyString}.
8828 *
8829 * @category models
8830 * @since 3.10.0
8831 */
8832export interface NonEmptyString extends String {
8833 readonly "Rebuild": NonEmptyString
8834}
8835/**
8836 * Schema for non-empty strings. Validates that a string has at least one
8837 * character.
8838 *
8839 * @category schemas
8840 * @since 3.10.0
8841 */
8842export const NonEmptyString: NonEmptyString = String.check(isNonEmpty())
8843/**
8844 * Type-level representation of {@link Char}.
8845 *
8846 * @category models
8847 * @since 3.10.0
8848 */
8849export interface Char extends String {
8850 readonly "Rebuild": Char
8851}
8852/**
8853 * Schema for strings whose JavaScript `length` is exactly `1`.
8854 *
8855 * **When to use**
8856 *
8857 * Use to validate string values that must have `length === 1`.
8858 *
8859 * **Gotchas**
8860 *
8861 * This schema uses JavaScript `String.length`, so visible characters made from
8862 * multiple UTF-16 code units do not satisfy `length === 1`.
8863 *
8864 * @see {@link String} for unconstrained string values
8865 * @see {@link NonEmptyString} for strings with length greater than zero
8866 * @see {@link isBetweenLength} for the underlying length check
8867 *
8868 * @category schemas
8869 * @since 3.10.0
8870 */
8871export const Char: Char = String.check(isBetweenLength(1, 1))
8872/**
8873 * Type-level representation of {@link ErrorInstance}.
8874 *
8875 * @category models
8876 * @since 4.0.0
8877 */
8878export interface ErrorInstance extends instanceOf<globalThis.Error> {
8879 readonly "Rebuild": ErrorInstance
8880}
8881/**
8882 * Options for {@link ErrorInstance} and {@link Defect}.
8883 *
8884 * @category options
8885 * @since 4.0.0
8886 */
8887export interface ErrorOptions {
8888 /**
8889 * Includes string stack traces in encoded `Error` values when set to `true`.
8890 *
8891 * @default false
8892 */
8893 readonly includeStack?: boolean | undefined
8894 /**
8895 * Excludes `Error.cause` values from encoded `Error` values when set to
8896 * `true`.
8897 *
8898 * @default false
8899 */
8900 readonly excludeCause?: boolean | undefined
8901}
8902
8903type NormalizedErrorOptions =
8904 | { readonly includeStack: true }
8905 | { readonly excludeCause: true }
8906 | { readonly includeStack: true; readonly excludeCause: true }
8907
8908type ErrorOptionsKey = 0 | 1 | 2 | 3
8909
8910const getErrorOptionsKey = (options?: ErrorOptions): ErrorOptionsKey =>
8911 ((options?.includeStack === true ? 1 : 0) |
8912 (options?.excludeCause === true ? 2 : 0)) as ErrorOptionsKey
8913
8914const getErrorOptions = (key: ErrorOptionsKey): NormalizedErrorOptions | undefined => {
8915 switch (key) {
8916 case 0:
8917 return undefined
8918 case 1:
8919 return { includeStack: true }
8920 case 2:
8921 return { excludeCause: true }
8922 case 3:
8923 return { includeStack: true, excludeCause: true }
8924 }
8925}
8926
8927const errorSchemaCache: Array<ErrorInstance | undefined> = []
8928/**
8929 * Schema for JavaScript `Error` objects.
8930 *
8931 * **Details**
8932 *
8933 * Default JSON serializer:
8934 *
8935 * Encodes an `Error` as an object with `message`, optional `name`, and optional
8936 * `cause` properties, and decodes that object back into an `Error`. Stack
8937 * traces are omitted by default for security. Pass `{ includeStack: true }` to
8938 * include stack traces, or `{ excludeCause: true }` to omit causes.
8939 *
8940 * @category schemas
8941 * @since 4.0.0
8942 */
8943export function ErrorInstance(options?: ErrorOptions): ErrorInstance {
8944 const key = getErrorOptionsKey(options)
8945 const cached = errorSchemaCache[key]
8946 if (cached !== undefined) {
8947 return cached
8948 }
8949 const normalizedOptions = getErrorOptions(key)
8950 const schema = instanceOf(globalThis.Error, {
8951 representation: {
8952 id: "effect/schema/Error",
8953 payload: normalizedOptions ?? null
8954 },
8955 toCode: () => ({
8956 runtime: normalizedOptions !== undefined
8957 ? `Schema.ErrorInstance(${format(normalizedOptions)})`
8958 : `Schema.ErrorInstance()`,
8959 Type: `globalThis.Error`
8960 }),
8961 expected: "Error",
8962 toCodecJson: () => link<globalThis.Error>()(JsonError, SchemaTransformation.errorFromJsonError(normalizedOptions))
8963 })
8964 errorSchemaCache[key] = schema
8965 return schema
8966}
8967/**
8968 * Type-level representation of {@link Defect}.
8969 *
8970 * @category models
8971 * @since 3.10.0
8972 */
8973export interface Defect extends decodeTo<Unknown, typeof Json> {
8974 readonly "Rebuild": Defect
8975}
8976
8977const defectSchemaCache: Array<Defect | undefined> = []
8978/**
8979 * Schema for unexpected defect values represented as `unknown` with a JSON
8980 * encoded form.
8981 *
8982 * **When to use**
8983 *
8984 * Use when you need a schema for `Cause` defects or other unexpected failures
8985 * whose runtime value may be any value.
8986 *
8987 * **Details**
8988 *
8989 * The encoded side is {@link Json}. During decoding, JSON objects with a string
8990 * `message` property are decoded into JavaScript `Error` values, preserving a
8991 * non-default `name` and any string `stack`. Other JSON values decode
8992 * unchanged.
8993 *
8994 * During encoding, JavaScript `Error` values encode to JSON objects with
8995 * `name`, `message`, and optional `cause` properties. Pass
8996 * `{ includeStack: true }` to include string stack traces in encoded `Error`
8997 * defects, or `{ excludeCause: true }` to omit causes. Other values are
8998 * serialized through Effect's JSON formatter and then parsed back into JSON
8999 * when possible.
9000 *
9001 * **Gotchas**
9002 *
9003 * This schema is for carrying defects across JSON boundaries, not for
9004 * preserving every JavaScript value exactly. Some values cannot round-trip
9005 * unchanged:
9006 *
9007 * - A non-`Error` object such as `{ message: "boom" }` encodes as an
9008 * error-shaped JSON object and decodes back as an `Error`.
9009 * - JSON serialization normalizes unsupported values. For example,
9010 * `undefined` array elements encode as `null`, unsupported object properties
9011 * are omitted, and circular references are dropped.
9012 * - Values that cannot be represented as JSON fall back to Effect's formatted
9013 * string representation.
9014 *
9015 * @see {@link ErrorInstance} for a schema that only accepts JavaScript `Error` values.
9016 * @category schemas
9017 * @since 4.0.0
9018 */
9019export function Defect(options?: ErrorOptions): Defect {
9020 const key = getErrorOptionsKey(options)
9021 const cached = defectSchemaCache[key]
9022 if (cached !== undefined) {
9023 return cached
9024 }
9025 const schema = Json.pipe(decodeTo(Unknown, SchemaTransformation.defectFromJson(getErrorOptions(key))))
9026 defectSchemaCache[key] = schema
9027 return schema
9028}
9029/**
9030 * Type-level representation returned by {@link ReadonlyMap}.
9031 *
9032 * @category models
9033 * @since 4.0.0
9034 */
9035export interface $ReadonlyMap<Key extends Constraint, Value extends Constraint> extends
9036 declareConstructor<
9037 globalThis.ReadonlyMap<Key["Type"], Value["Type"]>,
9038 globalThis.ReadonlyMap<Key["Encoded"], Value["Encoded"]>,
9039 readonly [Key, Value],
9040 ReadonlyMapIso<Key, Value>
9041 >
9042{
9043 readonly "Rebuild": $ReadonlyMap<Key, Value>
9044 readonly key: Key
9045 readonly value: Value
9046}
9047/**
9048 * Iso representation used for `ReadonlyMap` schemas: an array of readonly
9049 * `[key, value]` tuples using each entry schema's `Iso` type.
9050 *
9051 * @category utility types
9052 * @since 4.0.0
9053 */
9054export type ReadonlyMapIso<Key extends Constraint, Value extends Constraint> = ReadonlyArray<
9055 readonly [Key["Iso"], Value["Iso"]]
9056>
9057/**
9058 * Schema for readonly maps whose keys and values conform to the provided
9059 * schemas.
9060 *
9061 * @category schemas
9062 * @since 3.10.0
9063 */
9064export function ReadonlyMap<Key extends Constraint, Value extends Constraint>(
9065 key: Key,
9066 value: Value
9067): $ReadonlyMap<Key, Value> {
9068 const schema = declareConstructor<
9069 globalThis.ReadonlyMap<Key["Type"], Value["Type"]>,
9070 globalThis.ReadonlyMap<Key["Encoded"], Value["Encoded"]>,
9071 ReadonlyMapIso<Key, Value>
9072 >()(
9073 [key, value],
9074 ([key, value]) => {
9075 const array = ArraySchema(Tuple([key, value]))
9076 return (input, ast, options) => {
9077 if (input instanceof globalThis.Map) {
9078 return Effect.mapBothEager(
9079 SchemaParser.decodeUnknownEffect(array)([...input], options),
9080 {
9081 onSuccess: (array: ReadonlyArray<readonly [Key["Type"], Value["Type"]]>) => new globalThis.Map(array),
9082 onFailure: (issue) => SchemaIssue.makeCompositeAtKey(ast, "entries", issue, input, options)
9083 }
9084 )
9085 }
9086 return Effect.fail(new SchemaIssue.InvalidType(ast, input, options))
9087 }
9088 },
9089 {
9090 representation: {
9091 id: "effect/schema/ReadonlyMap",
9092 payload: null
9093 },
9094 toCode: ({ typeParameters }) => ({
9095 runtime: `Schema.ReadonlyMap(${typeParameters[0].runtime}, ${typeParameters[1].runtime})`,
9096 Type: `globalThis.ReadonlyMap<${typeParameters[0].Type}, ${typeParameters[1].Type}>`
9097 }),
9098 expected: "ReadonlyMap",
9099 toCodec: ([key, value]) =>
9100 link<globalThis.Map<Key["Encoded"], Value["Encoded"]>>()(
9101 ArraySchema(Tuple([key, value])),
9102 SchemaTransformation.transform({
9103 decode: (entries) => new globalThis.Map(entries),
9104 encode: (map) => [...map.entries()]
9105 })
9106 )
9107 }
9108 )
9109 return make(schema.ast, { key, value })
9110}
9111/**
9112 * Type-level representation returned by {@link ReadonlySet}.
9113 *
9114 * @category models
9115 * @since 4.0.0
9116 */
9117export interface $ReadonlySet<Value extends Constraint> extends
9118 declareConstructor<
9119 globalThis.ReadonlySet<Value["Type"]>,
9120 globalThis.ReadonlySet<Value["Encoded"]>,
9121 readonly [Value],
9122 ReadonlySetIso<Value>
9123 >
9124{
9125 readonly "Rebuild": $ReadonlySet<Value>
9126 readonly value: Value
9127}
9128/**
9129 * Iso representation used for `ReadonlySet` schemas: an array of element values
9130 * using the element schema's `Iso` type.
9131 *
9132 * @category utility types
9133 * @since 4.0.0
9134 */
9135export type ReadonlySetIso<Value extends Constraint> = ReadonlyArray<Value["Iso"]>
9136/**
9137 * Schema for readonly sets whose values conform to the provided element schema.
9138 *
9139 * @category schemas
9140 * @since 3.10.0
9141 */
9142export function ReadonlySet<Value extends Constraint>(value: Value): $ReadonlySet<Value> {
9143 const schema = declareConstructor<
9144 globalThis.ReadonlySet<Value["Type"]>,
9145 globalThis.ReadonlySet<Value["Encoded"]>,
9146 ReadonlySetIso<Value>
9147 >()(
9148 [value],
9149 ([value]) => {
9150 const array = ArraySchema(value)
9151 return (input, ast, options) => {
9152 if (input instanceof globalThis.Set) {
9153 return Effect.mapBothEager(
9154 SchemaParser.decodeUnknownEffect(array)([...input], options),
9155 {
9156 onSuccess: (array: ReadonlyArray<Value["Type"]>) => new globalThis.Set(array),
9157 onFailure: (issue) => SchemaIssue.makeCompositeAtKey(ast, "values", issue, input, options)
9158 }
9159 )
9160 }
9161 return Effect.fail(new SchemaIssue.InvalidType(ast, input, options))
9162 }
9163 },
9164 {
9165 representation: {
9166 id: "effect/schema/ReadonlySet",
9167 payload: null
9168 },
9169 toCode: ({ typeParameters }) => ({
9170 runtime: `Schema.ReadonlySet(${typeParameters[0].runtime})`,
9171 Type: `globalThis.ReadonlySet<${typeParameters[0].Type}>`
9172 }),
9173 expected: "ReadonlySet",
9174 toCodec: ([value]) =>
9175 link<globalThis.Set<Value["Encoded"]>>()(
9176 ArraySchema(value),
9177 SchemaTransformation.transform({
9178 decode: (values) => new globalThis.Set(values),
9179 encode: (set) => [...set.values()]
9180 })
9181 )
9182 }
9183 )
9184 return make(schema.ast, { value })
9185}
9186/**
9187 * Type-level representation of {@link RegExp}.
9188 *
9189 * @category models
9190 * @since 4.0.0
9191 */
9192export interface RegExp extends instanceOf<globalThis.RegExp> {
9193 readonly "Rebuild": RegExp
9194}
9195/**
9196 * Schema for JavaScript `RegExp` objects.
9197 *
9198 * **Details**
9199 *
9200 * The default JSON serializer encodes a `RegExp` as `{ source, flags }`.
9201 *
9202 * @category schemas
9203 * @since 4.0.0
9204 */
9205export const RegExp: RegExp = instanceOf(
9206 globalThis.RegExp,
9207 {
9208 representation: {
9209 id: "effect/schema/RegExp",
9210 payload: null
9211 },
9212 toCode: () => ({
9213 runtime: `Schema.RegExp`,
9214 Type: `globalThis.RegExp`
9215 }),
9216 expected: "RegExp",
9217 toCodecJson: () =>
9218 link<globalThis.RegExp>()(
9219 Struct({
9220 source: String,
9221 flags: String
9222 }),
9223 SchemaTransformation.transformEffect({
9224 decode: (e, options) =>
9225 Effect.try({
9226 try: () => new globalThis.RegExp(e.source, e.flags),
9227 catch: () =>
9228 new SchemaIssue.InvalidValue(
9229 { expected: "valid RegExp source and flags" },
9230 e,
9231 options
9232 )
9233 }),
9234 encode: (regExp) =>
9235 Effect.succeed({
9236 source: regExp.source,
9237 flags: regExp.flags
9238 })
9239 })
9240 )
9241 }
9242)
9243/**
9244 * Type-level representation of {@link URL}.
9245 *
9246 * @category models
9247 * @since 4.0.0
9248 */
9249export interface URL extends instanceOf<globalThis.URL> {
9250 readonly "Rebuild": URL
9251}
9252
9253const URLString = String.annotate({ expected: "a string that will be decoded as a URL" })
9254/**
9255 * Schema for JavaScript `URL` objects.
9256 *
9257 * **Details**
9258 *
9259 * Default JSON serializer:
9260 *
9261 * - encodes `URL` as a `string`
9262 *
9263 * @category schemas
9264 * @since 4.0.0
9265 */
9266export const URL: URL = instanceOf(
9267 globalThis.URL,
9268 {
9269 representation: {
9270 id: "effect/schema/URL",
9271 payload: null
9272 },
9273 toCode: () => ({
9274 runtime: `Schema.URL`,
9275 Type: `globalThis.URL`
9276 }),
9277 expected: "URL",
9278 toCodecJson: () =>
9279 link<globalThis.URL>()(
9280 URLString,
9281 SchemaTransformation.urlFromString
9282 )
9283 }
9284)
9285/**
9286 * Type-level representation of {@link URLFromString}.
9287 *
9288 * @category models
9289 * @since 4.0.0
9290 */
9291export interface URLFromString extends decodeTo<URL, String> {
9292 readonly "Rebuild": URLFromString
9293}
9294/**
9295 * Schema that decodes a `string` into a `URL`.
9296 *
9297 * **Details**
9298 *
9299 * Decoding:
9300 * - A **valid** URL `string` is decoded as a `URL`
9301 *
9302 * Encoding:
9303 * - A `URL` is encoded as a `string`
9304 *
9305 * @category schemas
9306 * @since 4.0.0
9307 */
9308export const URLFromString: URLFromString = URLString.pipe(decodeTo(URL, SchemaTransformation.urlFromString))
9309/**
9310 * Type-level representation of {@link Date}.
9311 *
9312 * @category models
9313 * @since 4.0.0
9314 */
9315export interface Date extends declare<globalThis.Date> {
9316 readonly "Rebuild": Date
9317}
9318
9319const DateString = String.annotate({ expected: "a string that will be decoded as a Date" })
9320/**
9321 * Schema for valid JavaScript `Date` objects.
9322 *
9323 * **When to use**
9324 *
9325 * Use to validate in-memory values that must already be valid JavaScript date
9326 * objects.
9327 *
9328 * **Details**
9329 *
9330 * This schema accepts `Date` instances whose timestamp is not `NaN`. The
9331 * default JSON serializer encodes dates as ISO 8601 strings.
9332 *
9333 * **Example** (Defining a Date schema)
9334 *
9335 * ```ts import.meta.vitest
9336 * import { Schema } from "effect"
9337 *
9338 * const date = Schema.decodeUnknownSync(Schema.Date)(new Date("2024-01-01"))
9339 * date.toISOString() // => "2024-01-01T00:00:00.000Z"
9340 * ```
9341 *
9342 * @see {@link DateFromString} for decoding strings into Date instances
9343 * @see {@link DateFromMillis} for decoding epoch milliseconds into Date instances
9344 *
9345 * @category schemas
9346 * @since 4.0.0
9347 */
9348export const Date: Date = declare(
9349 (input): input is globalThis.Date => input instanceof globalThis.Date && !globalThis.Number.isNaN(input.getTime()),
9350 {
9351 representation: {
9352 id: "effect/schema/Date",
9353 payload: null
9354 },
9355 toCode: () => ({
9356 runtime: `Schema.Date`,
9357 Type: `globalThis.Date`
9358 }),
9359 expected: "a valid Date",
9360 toCodecJson: () =>
9361 link<globalThis.Date>()(
9362 DateString,
9363 SchemaTransformation.dateFromString
9364 )
9365 }
9366)
9367/**
9368 * Type-level representation of {@link DateFromString}.
9369 *
9370 * @category models
9371 * @since 3.10.0
9372 */
9373export interface DateFromString extends decodeTo<Date, String> {
9374 readonly "Rebuild": DateFromString
9375}
9376/**
9377 * Schema that decodes a string into a JavaScript `Date`.
9378 *
9379 * **When to use**
9380 *
9381 * Use to model string-encoded dates that decode to JavaScript `Date` objects
9382 * and encode back to strings.
9383 *
9384 * **Details**
9385 *
9386 * Decoding:
9387 * The string is passed to JavaScript `Date` construction.
9388 *
9389 * Encoding:
9390 * A `Date` is encoded as an ISO string.
9391 *
9392 * Invalid date strings fail decoding.
9393 *
9394 * @see {@link DateFromMillis} for decoding epoch milliseconds into Date instances
9395 * @see {@link DateTimeUtcFromString} for decoding date-time strings into UTC values
9396 * @see {@link Date} for accepting Date instances directly
9397 *
9398 * @category schemas
9399 * @since 3.10.0
9400 */
9401export const DateFromString: DateFromString = DateString.pipe(decodeTo(Date, SchemaTransformation.dateFromString))
9402/**
9403 * Type-level representation of {@link DateFromMillis}.
9404 *
9405 * @category models
9406 * @since 4.0.0
9407 */
9408export interface DateFromMillis extends decodeTo<Date, Int> {
9409 readonly "Rebuild": DateFromMillis
9410}
9411/**
9412 * Schema that decodes epoch milliseconds into a JavaScript `Date`.
9413 *
9414 * **When to use**
9415 *
9416 * Use to model numeric millisecond timestamps that decode to JavaScript `Date`
9417 * objects and encode back to numbers.
9418 *
9419 * **Details**
9420 *
9421 * Decoding:
9422 * A safe integer number of milliseconds since the Unix epoch is decoded as a
9423 * `Date`.
9424 *
9425 * Encoding:
9426 * A `Date` is encoded as its millisecond timestamp.
9427 *
9428 * **Gotchas**
9429 *
9430 * JavaScript `Date` supports a narrower range than safe integers, so integers
9431 * outside the supported `Date` range fail decoding.
9432 *
9433 * @see {@link DateFromString} for decoding string-encoded dates
9434 * @see {@link DateTimeUtcFromMillis} for decoding epoch milliseconds into UTC values
9435 *
9436 * @category schemas
9437 * @since 4.0.0
9438 */
9439export const DateFromMillis: DateFromMillis = Int.pipe(
9440 decodeTo(Date, SchemaTransformation.dateFromMillis)
9441)
9442/**
9443 * Type-level representation returned by {@link fromJsonString}.
9444 *
9445 * @category models
9446 * @since 4.0.0
9447 */
9448export interface fromJsonString<S extends Constraint> extends decodeTo<S, String> {
9449 readonly "Rebuild": fromJsonString<S>
9450}
9451
9452const JsonString = String.annotate({
9453 expected: "a string that will be decoded as JSON",
9454 contentMediaType: "application/json"
9455})
9456/**
9457 * Returns a schema that decodes a JSON string and then decodes the parsed value
9458 * using the given schema.
9459 *
9460 * **Details**
9461 *
9462 * This is useful when working with JSON-encoded strings where the actual
9463 * structure of the value is known and described by an existing schema.
9464 *
9465 * During decoding, the resulting schema first parses the input string as JSON,
9466 * using `reviver` when provided, and then runs the provided schema on the
9467 * parsed result. During encoding, it first encodes with the provided schema and
9468 * then passes the result to `JSON.stringify` with the optional `replacer` and
9469 * `space`.
9470 *
9471 * **Example** (Formatting encoded JSON)
9472 *
9473 * ```ts import.meta.vitest
9474 * import { Schema } from "effect"
9475 *
9476 * const schema = Schema.Struct({ a: Schema.Number })
9477 * const schemaFromJsonString = Schema.fromJsonString(schema, { space: 2 })
9478 *
9479 * Schema.encodeSync(schemaFromJsonString)({ a: 1 }) // => "{\n \"a\": 1\n}"
9480 * ```
9481 *
9482 * @category schemas
9483 * @since 4.0.0
9484 */
9485export function fromJsonString<S extends Constraint>(
9486 schema: S,
9487 options?: {
9488 readonly reviver?: Parameters<typeof JSON.parse>[1] | undefined
9489 readonly replacer?: SchemaGetter.JsonReplacer | undefined
9490 readonly space?: Parameters<typeof JSON.stringify>[2] | undefined
9491 }
9492): fromJsonString<S> {
9493 return JsonString.pipe(decodeTo(schema, SchemaTransformation.fromJsonString(options)))
9494}
9495/** @internal */
9496export const UnknownFromJsonString: fromJsonString<Unknown> = fromJsonString(Unknown)
9497/**
9498 * Type-level representation of {@link File}.
9499 *
9500 * @category models
9501 * @since 4.0.0
9502 */
9503export interface File extends instanceOf<globalThis.File> {
9504 readonly "Rebuild": File
9505}
9506/**
9507 * Schema for JavaScript `File` objects.
9508 *
9509 * **Details**
9510 *
9511 * The default JSON serializer encodes a `File` as `{ data, type, name, lastModified }`
9512 * where `data` is base64-encoded.
9513 *
9514 * @category schemas
9515 * @since 4.0.0
9516 */
9517export const File: File = instanceOf(globalThis.File, {
9518 representation: {
9519 id: "effect/schema/File",
9520 payload: null
9521 },
9522 toCode: () => ({
9523 runtime: `Schema.File`,
9524 Type: `globalThis.File`
9525 }),
9526 expected: "File",
9527 toCodecJson: () =>
9528 link<globalThis.File>()(
9529 Struct({
9530 data: String.check(isBase64()),
9531 type: String,
9532 name: String,
9533 lastModified: Int
9534 }),
9535 SchemaTransformation.transformEffect({
9536 decode: (e, options) =>
9537 Result_.match(Base64.decode(e.data), {
9538 onFailure: () =>
9539 Effect.fail(
9540 new SchemaIssue.InvalidValue(
9541 { expected: "a valid Base64 string" },
9542 e.data,
9543 options
9544 )
9545 ),
9546 onSuccess: (bytes) => {
9547 const buffer = new globalThis.Uint8Array(bytes)
9548 return Effect.succeed(
9549 new globalThis.File([buffer], e.name, { type: e.type, lastModified: e.lastModified })
9550 )
9551 }
9552 }),
9553 encode: (file, options) =>
9554 Effect.tryPromise({
9555 try: async () => {
9556 const bytes = new globalThis.Uint8Array(await file.arrayBuffer())
9557 return {
9558 data: Base64.encode(bytes),
9559 type: file.type,
9560 name: file.name,
9561 lastModified: file.lastModified
9562 }
9563 },
9564 catch: () =>
9565 new SchemaIssue.InvalidValue(
9566 { expected: "a readable File" },
9567 file,
9568 options
9569 )
9570 })
9571 })
9572 )
9573})
9574/**
9575 * Type-level representation of {@link FormData}.
9576 *
9577 * @category models
9578 * @since 4.0.0
9579 */
9580export interface FormData extends instanceOf<globalThis.FormData> {
9581 readonly "Rebuild": FormData
9582}
9583/**
9584 * Schema for JavaScript `FormData` objects.
9585 *
9586 * **Details**
9587 *
9588 * The default JSON serializer encodes a `FormData` as an array of `[key, entry]`
9589 * pairs where each entry is tagged as `"String"` or `"File"`.
9590 *
9591 * @category schemas
9592 * @since 4.0.0
9593 */
9594export const FormData: FormData = instanceOf(globalThis.FormData, {
9595 representation: {
9596 id: "effect/schema/FormData",
9597 payload: null
9598 },
9599 toCode: () => ({
9600 runtime: `Schema.FormData`,
9601 Type: `globalThis.FormData`
9602 }),
9603 expected: "FormData",
9604 toCodecJson: () =>
9605 link<globalThis.FormData>()(
9606 ArraySchema(
9607 Tuple([
9608 String,
9609 Union([
9610 Struct({ _tag: tag("String"), value: String }),
9611 Struct({ _tag: tag("File"), value: File })
9612 ])
9613 ])
9614 ),
9615 SchemaTransformation.transformEffect({
9616 decode: (e) => {
9617 const out = new globalThis.FormData()
9618 for (const [key, entry] of e) {
9619 out.append(key, entry.value)
9620 }
9621 return Effect.succeed(out)
9622 },
9623 encode: (formData) => {
9624 return Effect.succeed(
9625 globalThis.Array.from(formData.entries()).map(([key, value]) => {
9626 if (typeof value === "string") {
9627 return [key, { _tag: "String", value }] as const
9628 } else {
9629 return [key, { _tag: "File", value }] as const
9630 }
9631 })
9632 )
9633 }
9634 })
9635 )
9636})
9637/**
9638 * Type-level representation returned by {@link fromFormData}.
9639 *
9640 * @category models
9641 * @since 4.0.0
9642 */
9643export interface fromFormData<S extends Constraint> extends decodeTo<S, FormData> {
9644 readonly "Rebuild": fromFormData<S>
9645}
9646/**
9647 * Schema for decoding `FormData` through a bracket-notation tree.
9648 *
9649 * **When to use**
9650 *
9651 * Use to decode browser or multipart form data into a structured schema value.
9652 *
9653 * **Details**
9654 *
9655 * The decoding process has two steps:
9656 *
9657 * 1. Parse `FormData` into a nested tree record.
9658 * 2. Decode the parsed value with the given schema.
9659 *
9660 * You can express nested values using bracket notation.
9661 *
9662 * If you want to decode string fields into non-string primitive values, use
9663 * `Schema.toCodecStringTree`.
9664 *
9665 * **Example** (Decoding a flat structure)
9666 *
9667 * ```ts import.meta.vitest
9668 * import { Schema } from "effect"
9669 *
9670 * const schema = Schema.fromFormData(
9671 * Schema.Struct({
9672 * a: Schema.String
9673 * })
9674 * )
9675 *
9676 * const formData = new FormData()
9677 * formData.append("a", "1")
9678 * formData.append("b", "2")
9679 *
9680 * Schema.decodeUnknownSync(schema)(formData) // => { a: "1" }
9681 * ```
9682 *
9683 * **Example** (Decoding nested fields)
9684 *
9685 * ```ts import.meta.vitest
9686 * import { Schema } from "effect"
9687 *
9688 * const schema = Schema.fromFormData(
9689 * Schema.Struct({
9690 * a: Schema.String,
9691 * b: Schema.Struct({
9692 * c: Schema.String,
9693 * d: Schema.String
9694 * })
9695 * })
9696 * )
9697 *
9698 * const formData = new FormData()
9699 * formData.append("a", "1")
9700 * formData.append("b[c]", "2")
9701 * formData.append("b[d]", "3")
9702 *
9703 * Schema.decodeUnknownSync(schema)(formData) // => { a: "1", b: { c: "2", d: "3" } }
9704 * ```
9705 *
9706 * **Example** (Parsing non-string values)
9707 *
9708 * ```ts import.meta.vitest
9709 * import { Schema } from "effect"
9710 *
9711 * const schema = Schema.fromFormData(
9712 * Schema.toCodecStringTree(
9713 * Schema.Struct({
9714 * a: Schema.Int
9715 * })
9716 * )
9717 * )
9718 *
9719 * const formData = new FormData()
9720 * formData.append("a", "1")
9721 *
9722 * Schema.decodeUnknownSync(schema)(formData) // => { a: 1 }
9723 * ```
9724 *
9725 * @category decoding
9726 * @since 4.0.0
9727 */
9728export function fromFormData<S extends Constraint>(schema: S): fromFormData<S> {
9729 return FormData.pipe(decodeTo(schema, SchemaTransformation.fromFormData))
9730}
9731/**
9732 * Type-level representation of {@link URLSearchParams}.
9733 *
9734 * @category models
9735 * @since 4.0.0
9736 */
9737export interface URLSearchParams extends instanceOf<globalThis.URLSearchParams> {
9738 readonly "Rebuild": URLSearchParams
9739}
9740/**
9741 * Schema for JavaScript `URLSearchParams` objects.
9742 *
9743 * **Details**
9744 *
9745 * The default JSON serializer encodes a `URLSearchParams` as a query string.
9746 *
9747 * @category schemas
9748 * @since 4.0.0
9749 */
9750export const URLSearchParams: URLSearchParams = instanceOf(globalThis.URLSearchParams, {
9751 representation: {
9752 id: "effect/schema/URLSearchParams",
9753 payload: null
9754 },
9755 toCode: () => ({
9756 runtime: `Schema.URLSearchParams`,
9757 Type: `globalThis.URLSearchParams`
9758 }),
9759 expected: "URLSearchParams",
9760 toCodecJson: () =>
9761 link<globalThis.URLSearchParams>()(
9762 String.annotate({ expected: "a query string that will be decoded as URLSearchParams" }),
9763 SchemaTransformation.transform({
9764 decode: (e) => new globalThis.URLSearchParams(e),
9765 encode: (params) => params.toString()
9766 })
9767 )
9768})
9769/**
9770 * Type-level representation returned by {@link fromURLSearchParams}.
9771 *
9772 * @category models
9773 * @since 4.0.0
9774 */
9775export interface fromURLSearchParams<S extends Constraint> extends decodeTo<S, URLSearchParams> {
9776 readonly "Rebuild": fromURLSearchParams<S>
9777}
9778/**
9779 * Schema for decoding `URLSearchParams` through a bracket-notation tree.
9780 *
9781 * **When to use**
9782 *
9783 * Use to decode query parameters into a structured schema value.
9784 *
9785 * **Details**
9786 *
9787 * The decoding process has two steps:
9788 *
9789 * 1. Parse `URLSearchParams` into a nested tree record.
9790 * 2. Decode the parsed value with the given schema.
9791 *
9792 * You can express nested values using bracket notation.
9793 *
9794 * If you want to decode values that are not strings, use
9795 * `Schema.toCodecStringTree`. This serializer preserves values such as
9796 * numbers when compatible with the schema.
9797 *
9798 * **Example** (Decoding a flat structure)
9799 *
9800 * ```ts import.meta.vitest
9801 * import { Schema } from "effect"
9802 *
9803 * const schema = Schema.fromURLSearchParams(
9804 * Schema.Struct({
9805 * a: Schema.String
9806 * })
9807 * )
9808 *
9809 * const urlSearchParams = new URLSearchParams("a=1&b=2")
9810 *
9811 * Schema.decodeUnknownSync(schema)(urlSearchParams) // => { a: "1" }
9812 * ```
9813 *
9814 * **Example** (Decoding nested fields)
9815 *
9816 * ```ts import.meta.vitest
9817 * import { Schema } from "effect"
9818 *
9819 * const schema = Schema.fromURLSearchParams(
9820 * Schema.Struct({
9821 * a: Schema.String,
9822 * b: Schema.Struct({
9823 * c: Schema.String,
9824 * d: Schema.String
9825 * })
9826 * })
9827 * )
9828 *
9829 * const urlSearchParams = new URLSearchParams("a=1&b[c]=2&b[d]=3")
9830 *
9831 * Schema.decodeUnknownSync(schema)(urlSearchParams) // => { a: "1", b: { c: "2", d: "3" } }
9832 * ```
9833 *
9834 * **Example** (Parsing non-string values)
9835 *
9836 * ```ts import.meta.vitest
9837 * import { Schema } from "effect"
9838 *
9839 * const schema = Schema.fromURLSearchParams(
9840 * Schema.toCodecStringTree(
9841 * Schema.Struct({
9842 * a: Schema.Int
9843 * })
9844 * )
9845 * )
9846 *
9847 * const urlSearchParams = new URLSearchParams("a=1&b=2")
9848 *
9849 * Schema.decodeUnknownSync(schema)(urlSearchParams) // => { a: 1 }
9850 * ```
9851 *
9852 * @category decoding
9853 * @since 4.0.0
9854 */
9855export function fromURLSearchParams<S extends Constraint>(schema: S): fromURLSearchParams<S> {
9856 return URLSearchParams.pipe(decodeTo(schema, SchemaTransformation.fromURLSearchParams))
9857}
9858/**
9859 * Type-level representation of {@link NumberFromString}.
9860 *
9861 * @category models
9862 * @since 3.10.0
9863 */
9864export interface NumberFromString extends decodeTo<Number, String> {
9865 readonly "Rebuild": NumberFromString
9866}
9867/**
9868 * Schema that parses a string into a `number` using JavaScript
9869 * number coercion.
9870 *
9871 * **Details**
9872 *
9873 * Decoding:
9874 * A `string` is decoded as a number, including possible non-finite values such as
9875 * `NaN`, `Infinity`, and `-Infinity`. Use `FiniteFromString` to reject non-finite
9876 * numbers.
9877 *
9878 * Encoding:
9879 * A number is encoded as a `string`.
9880 *
9881 * @category schemas
9882 * @since 3.10.0
9883 */
9884export const NumberFromString: NumberFromString = String.annotate({
9885 expected: "a string that will be decoded as a number"
9886}).pipe(decodeTo(Number, SchemaTransformation.numberFromString))
9887/**
9888 * Type-level representation of {@link FiniteFromString}.
9889 *
9890 * @category models
9891 * @since 4.0.0
9892 */
9893export interface FiniteFromString extends decodeTo<Finite, String> {
9894 readonly "Rebuild": FiniteFromString
9895}
9896/**
9897 * Schema that parses a string into a finite number.
9898 *
9899 * **Details**
9900 *
9901 * Decoding:
9902 * - A `string` is decoded as a finite number, rejecting `NaN`, `Infinity`, and
9903 * `-Infinity` values.
9904 *
9905 * Encoding:
9906 * - A finite number is encoded as a `string`.
9907 *
9908 * @category schemas
9909 * @since 4.0.0
9910 */
9911export const FiniteFromString: FiniteFromString = String.annotate({
9912 expected: "a string that will be decoded as a finite number"
9913}).pipe(decodeTo(Finite, SchemaTransformation.numberFromString))
9914/**
9915 * Type-level representation of {@link BigIntFromString}.
9916 *
9917 * @category models
9918 * @since 4.0.0
9919 */
9920export interface BigIntFromString extends decodeTo<BigInt, String> {
9921 readonly "Rebuild": BigIntFromString
9922}
9923/**
9924 * Schema that parses a string into a `bigint`.
9925 *
9926 * **When to use**
9927 *
9928 * Use to parse signed base-10 integer strings into bigint values while encoding
9929 * bigint values back to decimal strings.
9930 *
9931 * **Details**
9932 *
9933 * Decoding:
9934 * - A `string` is decoded as a `bigint`.
9935 *
9936 * Encoding:
9937 * - A `bigint` is encoded as a `string`.
9938 *
9939 * **Gotchas**
9940 *
9941 * Decoding accepts only strings matching `^-?\d+$`.
9942 *
9943 * @see {@link isStringBigInt} for the string predicate used by this schema
9944 * @see {@link BigInt} for validating values that are already bigint values
9945 * @see {@link NumberFromString} for parsing JavaScript number strings, including non-finite values
9946 * @see {@link BigDecimalFromString} for parsing decimal number strings
9947 *
9948 * @category schemas
9949 * @since 4.0.0
9950 */
9951export const BigIntFromString: BigIntFromString = make<String>(SchemaAST.bigIntString).pipe(
9952 decodeTo(BigInt, SchemaTransformation.bigintFromString)
9953)
9954/**
9955 * Type-level representation of {@link Trimmed}.
9956 *
9957 * @category models
9958 * @since 3.10.0
9959 */
9960export interface Trimmed extends String {
9961 readonly "Rebuild": Trimmed
9962}
9963/**
9964 * Schema for strings that contains no leading or trailing whitespaces.
9965 *
9966 * @category schemas
9967 * @since 3.10.0
9968 */
9969export const Trimmed: Trimmed = String.check(isTrimmed())
9970/**
9971 * Type-level representation of {@link Trim}.
9972 *
9973 * @category models
9974 * @since 3.10.0
9975 */
9976export interface Trim extends decodeTo<Trimmed, String> {
9977 readonly "Rebuild": Trim
9978}
9979/**
9980 * Schema that trims whitespace from a string.
9981 *
9982 * **Details**
9983 *
9984 * Decoding:
9985 * - A `string` is decoded as a string with no leading or trailing whitespaces.
9986 *
9987 * Encoding:
9988 * - The trimmed string is encoded as is.
9989 *
9990 * @category schemas
9991 * @since 3.10.0
9992 */
9993export const Trim: Trim = String.annotate({
9994 expected: "a string that will be decoded as a trimmed string"
9995}).pipe(decodeTo(Trimmed, SchemaTransformation.trim()))
9996/**
9997 * Type-level representation of {@link StringFromBase64}.
9998 *
9999 * @category models
10000 * @since 3.10.0
10001 */
10002export interface StringFromBase64 extends decodeTo<String, String> {
10003 readonly "Rebuild": StringFromBase64
10004}
10005/**
10006 * Decodes a base64 (RFC4648) encoded string into a UTF-8 string.
10007 *
10008 * **Details**
10009 *
10010 * Decoding:
10011 * - A **valid** base64 encoded string is decoded as a UTF-8 `string`.
10012 *
10013 * Encoding:
10014 * - A `string` is encoded as a base64-encoded string.
10015 *
10016 * @category schemas
10017 * @since 3.10.0
10018 */
10019export const StringFromBase64: StringFromBase64 = String.annotate({
10020 expected: "a base64 encoded string that will be decoded as a UTF-8 string"
10021}).pipe(
10022 decodeTo(String, SchemaTransformation.stringFromBase64String)
10023)
10024/**
10025 * Type-level representation of {@link StringFromBase64Url}.
10026 *
10027 * @category models
10028 * @since 3.10.0
10029 */
10030export interface StringFromBase64Url extends decodeTo<String, String> {
10031 readonly "Rebuild": StringFromBase64Url
10032}
10033/**
10034 * Decodes a base64 (URL) encoded string into a UTF-8 string.
10035 *
10036 * **Details**
10037 *
10038 * Decoding:
10039 * - A **valid** base64 (URL) encoded string is decoded as a UTF-8 `string`.
10040 *
10041 * Encoding:
10042 * - A `string` is encoded as a base64 (URL) encoded string.
10043 *
10044 * @category schemas
10045 * @since 3.10.0
10046 */
10047export const StringFromBase64Url: StringFromBase64Url = String.annotate({
10048 expected: "a base64 (URL) encoded string that will be decoded as a UTF-8 string"
10049}).pipe(
10050 decodeTo(String, SchemaTransformation.stringFromBase64UrlString)
10051)
10052/**
10053 * Type-level representation of {@link StringFromHex}.
10054 *
10055 * @category models
10056 * @since 3.10.0
10057 */
10058export interface StringFromHex extends decodeTo<String, String> {
10059 readonly "Rebuild": StringFromHex
10060}
10061/**
10062 * Decodes a hex encoded string into a UTF-8 string.
10063 *
10064 * **Details**
10065 *
10066 * Decoding:
10067 * - A **valid** hex encoded string is decoded as a UTF-8 `string`.
10068 *
10069 * Encoding:
10070 * - A `string` is encoded as a hex string.
10071 *
10072 * @category schemas
10073 * @since 3.10.0
10074 */
10075export const StringFromHex: StringFromHex = String.annotate({
10076 expected: "a hex encoded string that will be decoded as a UTF-8 string"
10077}).pipe(
10078 decodeTo(String, SchemaTransformation.stringFromHexString)
10079)
10080/**
10081 * Type-level representation of {@link StringFromUriComponent}.
10082 *
10083 * @category models
10084 * @since 3.12.0
10085 */
10086export interface StringFromUriComponent extends decodeTo<String, String> {
10087 readonly "Rebuild": StringFromUriComponent
10088}
10089/**
10090 * Decodes a URI component encoded string into a UTF-8 string.
10091 * Can be used to store data in a URL.
10092 *
10093 * **Details**
10094 *
10095 * Decoding:
10096 * - A **valid** URI component encoded string is decoded as a UTF-8 `string`.
10097 *
10098 * Encoding:
10099 * - A `string` is encoded as a URI component encoded string.
10100 *
10101 * **Example** (Decoding URI component strings)
10102 *
10103 * ```ts import.meta.vitest
10104 * import { Schema } from "effect"
10105 *
10106 * const PaginationSchema = Schema.Struct({
10107 * maxItemPerPage: Schema.Number,
10108 * page: Schema.Number
10109 * })
10110 *
10111 * const UrlSchema = Schema.StringFromUriComponent.pipe(
10112 * Schema.decodeTo(Schema.fromJsonString(PaginationSchema))
10113 * )
10114 *
10115 * Schema.encodeSync(UrlSchema)({ maxItemPerPage: 10, page: 1 }) // => "%7B%22maxItemPerPage%22%3A10%2C%22page%22%3A1%7D"
10116 * ```
10117 *
10118 * @category schemas
10119 * @since 3.12.0
10120 */
10121export const StringFromUriComponent: StringFromUriComponent = String.annotate({
10122 expected: "a URI component encoded string that will be decoded as a UTF-8 string"
10123}).pipe(
10124 decodeTo(String, SchemaTransformation.stringFromUriComponent)
10125)
10126/**
10127 * Schema for property keys accepted by Effect schemas: finite `number`,
10128 * `symbol`, or `string`.
10129 *
10130 * @category schemas
10131 * @since 4.0.0
10132 */
10133export const PropertyKey: Union<readonly [Finite, Symbol, String]> = Union([Finite, Symbol, String])
10134/**
10135 * Schema for a Standard Schema v1 failure result.
10136 *
10137 * **Details**
10138 *
10139 * The result contains an `issues` array where each issue has a message and an
10140 * optional path made of property keys or keyed path segments.
10141 *
10142 * @category schemas
10143 * @since 4.0.0
10144 */
10145export const StandardSchemaV1FailureResult: Struct<{
10146 readonly issues: $Array<
10147 Struct<{
10148 readonly message: String
10149 readonly path: optional<
10150 $Array<
10151 Union<
10152 readonly [
10153 Union<readonly [Finite, Symbol, String]>,
10154 Struct<{
10155 readonly key: Union<readonly [Finite, Symbol, String]>
10156 }>
10157 ]
10158 >
10159 >
10160 >
10161 }>
10162 >
10163}> = Struct({
10164 issues: ArraySchema(Struct({
10165 message: String,
10166 path: optional(ArraySchema(Union([PropertyKey, Struct({ key: PropertyKey })])))
10167 }))
10168})
10169/**
10170 * Type-level representation of {@link BooleanFromBit}.
10171 *
10172 * @category models
10173 * @since 4.0.0
10174 */
10175export interface BooleanFromBit extends decodeTo<Boolean, Literals<readonly [0, 1]>> {
10176 readonly "Rebuild": BooleanFromBit
10177}
10178/**
10179 * Schema for a boolean parsed from 0 or 1.
10180 *
10181 * **When to use**
10182 *
10183 * Use when decoding data sources that represent booleans as `0 | 1` while
10184 * keeping boolean values in the decoded model.
10185 *
10186 * **Details**
10187 *
10188 * Decoding accepts only `0 | 1`, maps `1` to `true`, and maps `0` to `false`.
10189 * Encoding maps `true` to `1` and `false` to `0`.
10190 *
10191 * @see {@link Boolean} for validating values that are already booleans
10192 * @see {@link Literals} for keeping bit literals instead of decoding them
10193 *
10194 * @category schemas
10195 * @since 4.0.0
10196 */
10197export const BooleanFromBit: BooleanFromBit = Literals([0, 1]).pipe(
10198 decodeTo(
10199 Boolean,
10200 SchemaTransformation.transform({
10201 decode: (bit) => bit === 1,
10202 encode: (bool) => bool ? 1 : 0
10203 })
10204 )
10205)
10206/**
10207 * Type-level representation of {@link Uint8Array}.
10208 *
10209 * @category models
10210 * @since 4.0.0
10211 */
10212export interface Uint8Array extends instanceOf<globalThis.Uint8Array<ArrayBufferLike>> {
10213 readonly "Rebuild": Uint8Array
10214}
10215
10216const Base64String = String.annotate({
10217 expected: "a base64 encoded string that will be decoded as Uint8Array",
10218 format: "byte",
10219 contentEncoding: "base64"
10220})
10221/**
10222 * Schema for JavaScript `Uint8Array` objects.
10223 *
10224 * **Details**
10225 *
10226 * Default JSON serializer:
10227 *
10228 * The default JSON serializer encodes Uint8Array as a Base64 encoded string.
10229 *
10230 * @category schemas
10231 * @since 4.0.0
10232 */
10233export const Uint8Array: Uint8Array = instanceOf(globalThis.Uint8Array<ArrayBufferLike>, {
10234 representation: {
10235 id: "effect/schema/Uint8Array",
10236 payload: null
10237 },
10238 toCode: () => ({
10239 runtime: `Schema.Uint8Array`,
10240 Type: `globalThis.Uint8Array`
10241 }),
10242 expected: "Uint8Array",
10243 toCodecJson: () =>
10244 link<globalThis.Uint8Array<ArrayBufferLike>>()(
10245 Base64String,
10246 SchemaTransformation.uint8ArrayFromBase64String
10247 )
10248})
10249/**
10250 * Type-level representation of {@link Uint8ArrayFromBase64}.
10251 *
10252 * @category models
10253 * @since 3.10.0
10254 */
10255export interface Uint8ArrayFromBase64 extends decodeTo<Uint8Array, String> {
10256 readonly "Rebuild": Uint8ArrayFromBase64
10257}
10258/**
10259 * Schema that decodes a base64 encoded string into a
10260 * `Uint8Array`.
10261 *
10262 * **Details**
10263 *
10264 * Decoding:
10265 * - A **valid** base64 encoded string is decoded as a `Uint8Array`.
10266 *
10267 * Encoding:
10268 * - A `Uint8Array` is encoded as a base64-encoded string.
10269 *
10270 * @category schemas
10271 * @since 3.10.0
10272 */
10273export const Uint8ArrayFromBase64: Uint8ArrayFromBase64 = Base64String.pipe(
10274 decodeTo(Uint8Array, SchemaTransformation.uint8ArrayFromBase64String)
10275)
10276/**
10277 * Type-level representation of {@link Uint8ArrayFromBase64Url}.
10278 *
10279 * @category models
10280 * @since 3.10.0
10281 */
10282export interface Uint8ArrayFromBase64Url extends decodeTo<Uint8Array, String> {
10283 readonly "Rebuild": Uint8ArrayFromBase64Url
10284}
10285/**
10286 * Schema that decodes a base64 (URL) encoded string into a
10287 * `Uint8Array`.
10288 *
10289 * **Details**
10290 *
10291 * Decoding:
10292 * - A **valid** base64 (URL) encoded string is decoded as a `Uint8Array`.
10293 *
10294 * Encoding:
10295 * - A `Uint8Array` is encoded as a base64 (URL) encoded string.
10296 *
10297 * @category schemas
10298 * @since 3.10.0
10299 */
10300export const Uint8ArrayFromBase64Url: Uint8ArrayFromBase64Url = String.annotate({
10301 expected: "a base64 (URL) encoded string that will be decoded as a Uint8Array"
10302}).pipe(
10303 decodeTo(Uint8Array, {
10304 decode: SchemaGetter.decodeBase64Url(),
10305 encode: SchemaGetter.encodeBase64Url()
10306 })
10307)
10308/**
10309 * Type-level representation of {@link Uint8ArrayFromHex}.
10310 *
10311 * @category models
10312 * @since 3.10.0
10313 */
10314export interface Uint8ArrayFromHex extends decodeTo<Uint8Array, String> {
10315 readonly "Rebuild": Uint8ArrayFromHex
10316}
10317/**
10318 * Schema that decodes a hex encoded string into a
10319 * `Uint8Array`.
10320 *
10321 * **Details**
10322 *
10323 * Decoding:
10324 * - A **valid** hex encoded string is decoded as a `Uint8Array`.
10325 *
10326 * Encoding:
10327 * - A `Uint8Array` is encoded as a hex encoded string.
10328 *
10329 * @category schemas
10330 * @since 3.10.0
10331 */
10332export const Uint8ArrayFromHex: Uint8ArrayFromHex = String.annotate({
10333 expected: "a hex encoded string that will be decoded as a Uint8Array"
10334}).pipe(
10335 decodeTo(Uint8Array, {
10336 decode: SchemaGetter.decodeHex(),
10337 encode: SchemaGetter.encodeHex()
10338 })
10339)
10340
10341// -----------------------------------------------------------------------------
10342// BigDecimal schemas
10343// -----------------------------------------------------------------------------
10344
10345const bigDecimalFromString: SchemaTransformation.Transformation<BigDecimal_.BigDecimal, string> = SchemaTransformation
10346 .transformEffect<BigDecimal_.BigDecimal, string>({
10347 decode: (s, options) => {
10348 const result = BigDecimal_.fromString(s)
10349 return Option_.isNone(result)
10350 ? Effect.fail(
10351 new SchemaIssue.InvalidValue(
10352 { expected: "a valid BigDecimal string" },
10353 s,
10354 options
10355 )
10356 )
10357 : Effect.succeed(result.value)
10358 },
10359 encode: (bd) => Effect.succeed(BigDecimal_.format(bd))
10360 })
10361/**
10362 * Validates that a BigDecimal is greater than the specified value (exclusive).
10363 *
10364 * @category validation
10365 * @since 4.0.0
10366 */
10367export const isGreaterThanBigDecimal: (
10368 exclusiveMinimum: BigDecimal_.BigDecimal,
10369 annotations?: Annotations.Filter
10370) => SchemaAST.Filter<BigDecimal_.BigDecimal> = makeIsGreaterThan({
10371 order: BigDecimal_.Order,
10372 formatter: (bd) => BigDecimal_.format(bd)
10373})
10374/**
10375 * Validates that a BigDecimal is greater than or equal to the specified value
10376 * (inclusive).
10377 *
10378 * @category validation
10379 * @since 4.0.0
10380 */
10381export const isGreaterThanOrEqualToBigDecimal: (
10382 minimum: BigDecimal_.BigDecimal,
10383 annotations?: Annotations.Filter
10384) => SchemaAST.Filter<BigDecimal_.BigDecimal> = makeIsGreaterThanOrEqualTo({
10385 order: BigDecimal_.Order,
10386 formatter: (bd) => BigDecimal_.format(bd)
10387})
10388/**
10389 * Validates that a BigDecimal is less than the specified value (exclusive).
10390 *
10391 * @category validation
10392 * @since 4.0.0
10393 */
10394export const isLessThanBigDecimal: (
10395 exclusiveMaximum: BigDecimal_.BigDecimal,
10396 annotations?: Annotations.Filter
10397) => SchemaAST.Filter<BigDecimal_.BigDecimal> = makeIsLessThan({
10398 order: BigDecimal_.Order,
10399 formatter: (bd) => BigDecimal_.format(bd)
10400})
10401/**
10402 * Validates that a BigDecimal is less than or equal to the specified value
10403 * (inclusive).
10404 *
10405 * @category validation
10406 * @since 4.0.0
10407 */
10408export const isLessThanOrEqualToBigDecimal: (
10409 maximum: BigDecimal_.BigDecimal,
10410 annotations?: Annotations.Filter
10411) => SchemaAST.Filter<BigDecimal_.BigDecimal> = makeIsLessThanOrEqualTo({
10412 order: BigDecimal_.Order,
10413 formatter: (bd) => BigDecimal_.format(bd)
10414})
10415/**
10416 * Validates that a `BigDecimal` is within a specified range.
10417 *
10418 * **Details**
10419 *
10420 * The minimum and maximum boundaries are inclusive by default. Pass
10421 * `exclusiveMinimum` or `exclusiveMaximum` to exclude either boundary.
10422 *
10423 * @category validation
10424 * @since 4.0.0
10425 */
10426export const isBetweenBigDecimal: (options: {
10427 readonly minimum: BigDecimal_.BigDecimal
10428 readonly maximum: BigDecimal_.BigDecimal
10429 readonly exclusiveMinimum?: boolean | undefined
10430 readonly exclusiveMaximum?: boolean | undefined
10431}, annotations?: Annotations.Filter) => SchemaAST.Filter<BigDecimal_.BigDecimal> = makeIsBetween({
10432 order: BigDecimal_.Order,
10433 formatter: (bd) => BigDecimal_.format(bd)
10434})
10435/**
10436 * Type-level representation of {@link BigDecimal}.
10437 *
10438 * @category models
10439 * @since 3.10.0
10440 */
10441export interface BigDecimal extends declare<BigDecimal_.BigDecimal> {
10442 readonly "Rebuild": BigDecimal
10443}
10444const BigDecimalString = String.annotate({ expected: "a string that will be decoded as a BigDecimal" })
10445/**
10446 * Schema for `BigDecimal` values.
10447 *
10448 * **When to use**
10449 *
10450 * Use when you already have Effect decimal instances and need schema
10451 * validation, formatting, equivalence, and JSON string serialization.
10452 *
10453 * **Details**
10454 *
10455 * Default JSON serializer:
10456 *
10457 * - encodes `BigDecimal` as a `string`
10458 *
10459 * @see {@link BigDecimalFromString} for parsing string input into a BigDecimal
10460 *
10461 * @category schemas
10462 * @since 3.10.0
10463 */
10464export const BigDecimal: BigDecimal = declare(
10465 BigDecimal_.isBigDecimal,
10466 {
10467 representation: {
10468 id: "effect/schema/BigDecimal",
10469 payload: null
10470 },
10471 toCode: () => ({
10472 runtime: `Schema.BigDecimal`,
10473 Type: `BigDecimal.BigDecimal`,
10474 importDeclarations: [`import * as BigDecimal from "effect/BigDecimal"`]
10475 }),
10476 expected: "BigDecimal",
10477 toCodecJson: () =>
10478 link<BigDecimal_.BigDecimal>()(
10479 BigDecimalString,
10480 bigDecimalFromString
10481 ),
10482 toFormatter: () => (bd) => BigDecimal_.format(bd)
10483 }
10484)
10485/**
10486 * Type-level representation of {@link BigDecimalFromString}.
10487 *
10488 * @category models
10489 * @since 4.0.0
10490 */
10491export interface BigDecimalFromString extends decodeTo<BigDecimal, String> {
10492 readonly "Rebuild": BigDecimalFromString
10493}
10494/**
10495 * Schema that parses a string into a `BigDecimal`.
10496 *
10497 * **When to use**
10498 *
10499 * Use to parse decimal or exponent-notation strings into arbitrary-precision
10500 * BigDecimal values while encoding them back to strings.
10501 *
10502 * **Details**
10503 *
10504 * Decoding:
10505 * - A `string` is decoded with `BigDecimal.fromString`.
10506 *
10507 * Encoding:
10508 * - A `BigDecimal` is encoded with `BigDecimal.format`.
10509 *
10510 * **Gotchas**
10511 *
10512 * An empty string decodes as zero.
10513 *
10514 * @see {@link BigDecimal} for validating values that are already BigDecimal values
10515 * @see {@link BigIntFromString} for parsing base-10 integer strings into bigint values
10516 * @see {@link NumberFromString} for parsing JavaScript number strings
10517 *
10518 * @category schemas
10519 * @since 4.0.0
10520 */
10521export const BigDecimalFromString: BigDecimalFromString = BigDecimalString.pipe(
10522 decodeTo(BigDecimal, bigDecimalFromString)
10523)
10524
10525// -----------------------------------------------------------------------------
10526// ByteSize schemas
10527// -----------------------------------------------------------------------------
10528
10529/**
10530 * Type-level representation of {@link ByteSize}.
10531 *
10532 * @category models
10533 * @since 4.0.0
10534 */
10535export interface ByteSize extends declare<ByteSize_.ByteSize> {
10536 readonly "Rebuild": ByteSize
10537}
10538/**
10539 * Schema for exact, non-negative `ByteSize` values.
10540 *
10541 * **Details**
10542 *
10543 * The JSON codec encodes the byte count as a bigint string, preserving values
10544 * beyond JavaScript's safe-integer range. The StringTree codec uses the
10545 * human-readable byte-size syntax exposed by {@link ByteSizeFromString}.
10546 *
10547 * @category schemas
10548 * @since 4.0.0
10549 */
10550export const ByteSize: ByteSize = declare(
10551 ByteSize_.isByteSize,
10552 {
10553 representation: {
10554 id: "effect/schema/ByteSize",
10555 payload: null
10556 },
10557 toCode: () => ({
10558 runtime: `Schema.ByteSize`,
10559 Type: `ByteSize.ByteSize`,
10560 importDeclarations: [`import * as ByteSize from "effect/ByteSize"`]
10561 }),
10562 expected: "ByteSize",
10563 toCodecJson: () =>
10564 link<ByteSize_.ByteSize>()(
10565 BigInt.check(isGreaterThanOrEqualToBigInt(globalThis.BigInt(0))),
10566 SchemaTransformation.transform({
10567 decode: ByteSize_.bytes,
10568 encode: ByteSize_.toBigInt
10569 })
10570 ),
10571 toCodecStringTree: () =>
10572 link<ByteSize_.ByteSize>()(
10573 ByteSizeString,
10574 SchemaTransformation.byteSizeFromString
10575 )
10576 }
10577)
10578const ByteSizeString = String.annotate({ expected: "a string that will be decoded as a ByteSize" })
10579/**
10580 * Type-level representation of {@link ByteSizeFromString}.
10581 *
10582 * @category models
10583 * @since 4.0.0
10584 */
10585export interface ByteSizeFromString extends decodeTo<ByteSize, String> {
10586 readonly "Rebuild": ByteSizeFromString
10587}
10588/**
10589 * Schema that decodes byte-size strings into exact, non-negative `ByteSize`
10590 * values.
10591 *
10592 * **Details**
10593 *
10594 * Decoding accepts an unsigned base-10 integer or decimal followed by optional
10595 * whitespace and one of these case-sensitive units:
10596 *
10597 * - bytes: `B`, `byte`, or `bytes`
10598 * - decimal SI units (powers of 1,000): `kB`, `MB`, `GB`, `TB`, `PB`, `EB`,
10599 * `ZB`, `YB`, `RB`, or `QB`, plus their lowercase singular and plural names
10600 * - binary IEC units (powers of 1,024): `KiB`, `MiB`, `GiB`, `TiB`, `PiB`,
10601 * `EiB`, `ZiB`, or `YiB`, plus their lowercase singular and plural names
10602 *
10603 * Leading and trailing whitespace is ignored. A decimal quantity must resolve
10604 * to an integral number of bytes, so `1.5 kB` is accepted while `0.1 KiB` is
10605 * rejected.
10606 *
10607 * Encoding returns the exact byte count as `<count> byte` or `<count> bytes`.
10608 *
10609 * **Gotchas**
10610 *
10611 * A unit is required. Signs, exponent notation, digit separators, and ambiguous
10612 * unit spellings such as `KB`, `mb`, `Mb`, or `b` are rejected.
10613 *
10614 * @category schemas
10615 * @since 4.0.0
10616 */
10617export const ByteSizeFromString: ByteSizeFromString = ByteSizeString.pipe(
10618 decodeTo(ByteSize, SchemaTransformation.byteSizeFromString)
10619)
10620/**
10621 * Type-level representation of {@link ByteSizeFromBigInt}.
10622 *
10623 * @category models
10624 * @since 4.0.0
10625 */
10626export interface ByteSizeFromBigInt extends decodeTo<ByteSize, BigInt> {
10627 readonly "Rebuild": ByteSizeFromBigInt
10628}
10629/**
10630 * Schema that decodes non-negative bigint byte counts.
10631 *
10632 * @category schemas
10633 * @since 4.0.0
10634 */
10635export const ByteSizeFromBigInt: ByteSizeFromBigInt = BigInt.pipe(
10636 decodeTo(ByteSize, SchemaTransformation.byteSizeFromBigInt)
10637)
10638/**
10639 * Type-level representation of {@link ByteSizeFromNumber}.
10640 *
10641 * @category models
10642 * @since 4.0.0
10643 */
10644export interface ByteSizeFromNumber extends decodeTo<ByteSize, Number> {
10645 readonly "Rebuild": ByteSizeFromNumber
10646}
10647/**
10648 * Schema that decodes non-negative safe-integer byte counts.
10649 *
10650 * **Details**
10651 *
10652 * Encoding fails when the byte count exceeds `Number.MAX_SAFE_INTEGER`.
10653 *
10654 * @category schemas
10655 * @since 4.0.0
10656 */
10657export const ByteSizeFromNumber: ByteSizeFromNumber = Number.pipe(
10658 decodeTo(ByteSize, SchemaTransformation.byteSizeFromNumber)
10659)
10660
10661// -----------------------------------------------------------------------------
10662// Cause schemas
10663// -----------------------------------------------------------------------------
10664
10665/**
10666 * Type-level representation returned by {@link CauseReason}.
10667 *
10668 * @category models
10669 * @since 4.0.0
10670 */
10671export interface CauseReason<E extends Constraint, D extends Constraint> extends
10672 declareConstructor<
10673 Cause_.Reason<E["Type"]>,
10674 Cause_.Reason<E["Encoded"]>,
10675 readonly [E, D],
10676 CauseReasonIso<E, D>
10677 >
10678{
10679 readonly "Rebuild": CauseReason<E, D>
10680 readonly error: E
10681 readonly defect: D
10682}
10683/**
10684 * Iso representation used for `CauseReason` schemas.
10685 *
10686 * **Details**
10687 *
10688 * Failures are represented with a `Fail` tag and encoded error, defects with a
10689 * `Die` tag and encoded defect, and interrupts with an optional `fiberId`.
10690 *
10691 * @category utility types
10692 * @since 4.0.0
10693 */
10694export type CauseReasonIso<E extends Constraint, D extends Constraint> = {
10695 readonly _tag: "Fail"
10696 readonly error: E["Iso"]
10697} | {
10698 readonly _tag: "Die"
10699 readonly error: D["Iso"]
10700} | {
10701 readonly _tag: "Interrupt"
10702 readonly fiberId: number | undefined
10703}
10704/**
10705 * Creates a schema for `Cause.Reason` values using separate schemas for typed
10706 * failures and unexpected defects.
10707 *
10708 * **When to use**
10709 *
10710 * Use when serializing or decoding individual cause reasons separately from a
10711 * full failure cause, with distinct schemas for typed errors and defects.
10712 *
10713 * **Details**
10714 *
10715 * `Fail` reasons use the `error` schema, `Die` reasons use the `defect` schema,
10716 * and `Interrupt` reasons carry only an optional fiber id.
10717 *
10718 * @see {@link Cause} for constructing schemas for full Cause values
10719 * @see {@link CauseReasonIso} for the ISO shape of each cause reason
10720 *
10721 * @category schemas
10722 * @since 4.0.0
10723 */
10724export function CauseReason<E extends Constraint, D extends Constraint>(
10725 error: E,
10726 defect: D
10727): CauseReason<E, D> {
10728 const schema = declareConstructor<
10729 Cause_.Reason<E["Type"]>,
10730 Cause_.Reason<E["Encoded"]>,
10731 CauseReasonIso<E, D>
10732 >()(
10733 [error, defect],
10734 ([error, defect]) => (input, ast, options) => {
10735 if (!Cause_.isReason(input)) {
10736 return Effect.fail(new SchemaIssue.InvalidType(ast, input, options))
10737 }
10738 switch (input._tag) {
10739 case "Fail":
10740 return Effect.mapBothEager(
10741 SchemaParser.decodeUnknownEffect(error)(input.error, options),
10742 {
10743 onSuccess: Cause_.makeFailReason,
10744 onFailure: (issue) => SchemaIssue.makeCompositeAtKey(ast, "error", issue, input, options)
10745 }
10746 )
10747 case "Die":
10748 return Effect.mapBothEager(
10749 SchemaParser.decodeUnknownEffect(defect)(input.defect, options),
10750 {
10751 onSuccess: Cause_.makeDieReason,
10752 onFailure: (issue) => SchemaIssue.makeCompositeAtKey(ast, "defect", issue, input, options)
10753 }
10754 )
10755 case "Interrupt":
10756 return Effect.succeed(input)
10757 }
10758 },
10759 {
10760 representation: {
10761 id: "effect/schema/CauseReason",
10762 payload: null
10763 },
10764 toCode: ({ typeParameters }) => ({
10765 runtime: `Schema.CauseReason(${typeParameters[0].runtime}, ${typeParameters[1].runtime})`,
10766 Type: `Cause.Failure<${typeParameters[0].Type}, ${typeParameters[1].Type}>`,
10767 importDeclarations: [`import * as Cause from "effect/Cause"`]
10768 }),
10769 expected: "Cause.Failure",
10770 toCodec: ([error, defect]) =>
10771 link<Cause_.Reason<E["Encoded"]>>()(
10772 Union([
10773 Struct({ _tag: Literal("Fail"), error }),
10774 Struct({ _tag: Literal("Die"), defect }),
10775 Struct({
10776 _tag: Literal("Interrupt"),
10777 fiberId: UndefinedOr(Finite)
10778 })
10779 ]),
10780 SchemaTransformation.transform({
10781 decode: (e) => {
10782 switch (e._tag) {
10783 case "Fail":
10784 return Cause_.makeFailReason(e.error)
10785 case "Die":
10786 return Cause_.makeDieReason(e.defect)
10787 case "Interrupt":
10788 return Cause_.makeInterruptReason(e.fiberId)
10789 }
10790 },
10791 encode: (reason) => {
10792 switch (reason._tag) {
10793 case "Fail":
10794 return { _tag: "Fail" as const, error: reason.error }
10795 case "Die":
10796 return { _tag: "Die" as const, defect: reason.defect }
10797 case "Interrupt":
10798 return { _tag: "Interrupt" as const, fiberId: reason.fiberId }
10799 }
10800 }
10801 })
10802 )
10803 }
10804 )
10805 return make(schema.ast, { error, defect })
10806}
10807/**
10808 * Type-level representation returned by {@link Cause}.
10809 *
10810 * @category models
10811 * @since 3.10.0
10812 */
10813export interface Cause<E extends Constraint, D extends Constraint> extends
10814 declareConstructor<
10815 Cause_.Cause<E["Type"]>,
10816 Cause_.Cause<E["Encoded"]>,
10817 readonly [E, D],
10818 CauseIso<E, D>
10819 >
10820{
10821 readonly "Rebuild": Cause<E, D>
10822 readonly error: E
10823 readonly defect: D
10824}
10825/**
10826 * Iso representation used for `Cause` schemas: an ordered array of
10827 * `CauseReasonIso` values.
10828 *
10829 * **When to use**
10830 *
10831 * Use when working with the ISO shape of a `Cause` schema, such as `toIso`
10832 * optics or codecs that expose a cause as its ordered array of encoded reasons.
10833 *
10834 * @see {@link Cause} for constructing schemas for full Cause values
10835 * @see {@link CauseReasonIso} for the ISO shape of each array element
10836 *
10837 * @category utility types
10838 * @since 4.0.0
10839 */
10840export type CauseIso<E extends Constraint, D extends Constraint> = ReadonlyArray<CauseReasonIso<E, D>>
10841/**
10842 * Creates a schema for `Cause` values using separate schemas for typed failures
10843 * and unexpected defects.
10844 *
10845 * **When to use**
10846 *
10847 * Use to validate, transform, or serialize Effect failure causes when typed
10848 * failures and unexpected defects need separate schemas.
10849 *
10850 * **Details**
10851 *
10852 * The `error` schema is applied to `Fail` reasons and the `defect` schema is
10853 * applied to `Die` reasons. Interrupt reasons do not use either schema and
10854 * carry only an optional fiber id.
10855 *
10856 * @see {@link CauseReason} for the schema used by each individual cause reason
10857 * @see {@link CauseIso} for the ordered array representation used by the schema ISO
10858 *
10859 * @category schemas
10860 * @since 3.10.0
10861 */
10862export function Cause<E extends Constraint, D extends Constraint>(error: E, defect: D): Cause<E, D> {
10863 const schema = declareConstructor<Cause_.Cause<E["Type"]>, Cause_.Cause<E["Encoded"]>, CauseIso<E, D>>()(
10864 [error, defect],
10865 ([error, defect]) => {
10866 const failures = ArraySchema(CauseReason(error, defect))
10867 return (input, ast, options) => {
10868 if (!Cause_.isCause(input)) {
10869 return Effect.fail(new SchemaIssue.InvalidType(ast, input, options))
10870 }
10871 return Effect.mapBothEager(SchemaParser.decodeUnknownEffect(failures)(input.reasons, options), {
10872 onSuccess: Cause_.fromReasons,
10873 onFailure: (issue) => SchemaIssue.makeCompositeAtKey(ast, "failures", issue, input, options)
10874 })
10875 }
10876 },
10877 {
10878 representation: {
10879 id: "effect/schema/Cause",
10880 payload: null
10881 },
10882 toCode: ({ typeParameters }) => ({
10883 runtime: `Schema.Cause(${typeParameters[0].runtime}, ${typeParameters[1].runtime})`,
10884 Type: `Cause.Cause<${typeParameters[0].Type}, ${typeParameters[1].Type}>`,
10885 importDeclarations: [`import * as Cause from "effect/Cause"`]
10886 }),
10887 expected: "Cause",
10888 toCodec: ([error, defect]) =>
10889 link<Cause_.Cause<E["Encoded"]>>()(
10890 ArraySchema(CauseReason(error, defect)),
10891 SchemaTransformation.transform({
10892 decode: Cause_.fromReasons,
10893 encode: ({ reasons: failures }) => failures
10894 })
10895 )
10896 }
10897 )
10898 return make(schema.ast, { error, defect })
10899}
10900
10901// -----------------------------------------------------------------------------
10902// Chunk schemas
10903// -----------------------------------------------------------------------------
10904
10905function chunkLink<Value>(values: Schema<ReadonlyArray<Value>>) {
10906 return link<Chunk_.Chunk<Value>>()(
10907 values,
10908 SchemaTransformation.transform({
10909 decode: Chunk_.fromIterable,
10910 encode: Arr.fromIterable
10911 })
10912 )
10913}
10914/**
10915 * Type-level representation returned by {@link Chunk}.
10916 *
10917 * @category models
10918 * @since 3.10.0
10919 */
10920export interface Chunk<Value extends Constraint> extends
10921 declareConstructor<
10922 Chunk_.Chunk<Value["Type"]>,
10923 Chunk_.Chunk<Value["Encoded"]>,
10924 readonly [Value],
10925 ChunkIso<Value>
10926 >
10927{
10928 readonly "Rebuild": Chunk<Value>
10929 readonly value: Value
10930}
10931/**
10932 * Iso representation used for `Chunk` schemas: an array of element values using
10933 * the element schema's `Iso` type.
10934 *
10935 * **When to use**
10936 *
10937 * Use when annotating type-level helpers that work with the readonly-array ISO
10938 * shape of a `Chunk` schema.
10939 *
10940 * @see {@link Chunk} for the schema interface and constructor that use this ISO representation
10941 *
10942 * @category utility types
10943 * @since 4.0.0
10944 */
10945export type ChunkIso<Value extends Constraint> = ReadonlyArray<Value["Iso"]>
10946/**
10947 * Schema for chunks whose values conform to the provided element schema.
10948 *
10949 * @category schemas
10950 * @since 3.10.0
10951 */
10952export function Chunk<Value extends Constraint>(value: Value): Chunk<Value> {
10953 const schema = declareConstructor<
10954 Chunk_.Chunk<Value["Type"]>,
10955 Chunk_.Chunk<Value["Encoded"]>,
10956 ChunkIso<Value>
10957 >()(
10958 [value],
10959 ([value]) => {
10960 const values = ArraySchema(value)
10961 return (input, ast, options) => {
10962 if (Chunk_.isChunk(input)) {
10963 return Effect.mapBothEager(
10964 SchemaParser.decodeUnknownEffect(values)(Arr.fromIterable(input), options),
10965 {
10966 onSuccess: Chunk_.fromIterable,
10967 onFailure: (issue) => SchemaIssue.makeCompositeAtKey(ast, "values", issue, input, options)
10968 }
10969 )
10970 }
10971 return Effect.fail(new SchemaIssue.InvalidType(ast, input, options))
10972 }
10973 },
10974 {
10975 representation: {
10976 id: "effect/schema/Chunk",
10977 payload: null
10978 },
10979 toCode: ({ typeParameters }) => ({
10980 runtime: `Schema.Chunk(${typeParameters[0].runtime})`,
10981 Type: `Chunk.Chunk<${typeParameters[0].Type}>`
10982 }),
10983 expected: "Chunk",
10984 toCodec: ([value]) => chunkLink(ArraySchema(value)),
10985 toCodecArbitrary: ({ constraint, typeParameters: [value] }) =>
10986 chunkLink(
10987 withArrayLengthConstraints(
10988 ArraySchema(value),
10989 constraint?.minLength,
10990 constraint?.maxLength
10991 )
10992 ),
10993 toEquivalence: ([value]) => Chunk_.makeEquivalence(value)
10994 }
10995 )
10996 return make(schema.ast, { value })
10997}
10998
10999// -----------------------------------------------------------------------------
11000// DateTime schemas
11001// -----------------------------------------------------------------------------
11002
11003function dateTimeUtcFromInput<E extends DateTime.DateTime.Input>(): SchemaGetter.Getter<DateTime.Utc, E> {
11004 return SchemaGetter.transformEffect((input, options) => {
11005 return Option_.match(DateTime.make(input), {
11006 onNone: () =>
11007 Effect.fail(
11008 new SchemaIssue.InvalidValue({ message: "Invalid DateTime input" }, input, options)
11009 ),
11010 onSome: (dt) => Effect.succeed(DateTime.toUtc(dt))
11011 })
11012 })
11013}
11014const timeZoneOffsetFromNumber: SchemaTransformation.Transformation<DateTime.TimeZone.Offset, number> =
11015 SchemaTransformation.transform<DateTime.TimeZone.Offset, number>({
11016 decode: (n) => DateTime.zoneMakeOffset(n),
11017 encode: (tz) => tz.offset
11018 })
11019const timeZoneNamedFromString: SchemaTransformation.Transformation<DateTime.TimeZone.Named, string> =
11020 SchemaTransformation.transformEffect<DateTime.TimeZone.Named, string>({
11021 decode: (s, options) => {
11022 return Option_.match(DateTime.zoneMakeNamed(s), {
11023 onNone: () =>
11024 Effect.fail(
11025 new SchemaIssue.InvalidValue(
11026 { expected: "a valid IANA time zone" },
11027 s,
11028 options
11029 )
11030 ),
11031 onSome: Effect.succeed
11032 })
11033 },
11034 encode: (tz) => Effect.succeed(tz.id)
11035 })
11036const timeZoneFromString: SchemaTransformation.Transformation<DateTime.TimeZone, string> = SchemaTransformation
11037 .transformEffect<DateTime.TimeZone, string>({
11038 decode: (s, options) => {
11039 return Option_.match(DateTime.zoneFromString(s), {
11040 onNone: () =>
11041 Effect.fail(
11042 new SchemaIssue.InvalidValue(
11043 { expected: "a valid time zone" },
11044 s,
11045 options
11046 )
11047 ),
11048 onSome: Effect.succeed
11049 })
11050 },
11051 encode: (tz) => Effect.succeed(DateTime.zoneToString(tz))
11052 })
11053const dateTimeUtcFromString: SchemaTransformation.Transformation<DateTime.Utc, string> = SchemaTransformation
11054 .transformEffect<DateTime.Utc, string>({
11055 decode: (s, options) => {
11056 return Option_.match(DateTime.make(s), {
11057 onNone: () =>
11058 Effect.fail(
11059 new SchemaIssue.InvalidValue(
11060 { expected: "a valid UTC DateTime string" },
11061 s,
11062 options
11063 )
11064 ),
11065 onSome: (result) => Effect.succeed(DateTime.toUtc(result))
11066 })
11067 },
11068 encode: (utc) => Effect.succeed(DateTime.formatIso(utc))
11069 })
11070const dateTimeZonedFromString: SchemaTransformation.Transformation<DateTime.Zoned, string> = SchemaTransformation
11071 .transformEffect<DateTime.Zoned, string>({
11072 decode: (s, options) => {
11073 return Option_.match(DateTime.makeZonedFromString(s), {
11074 onNone: () =>
11075 Effect.fail(
11076 new SchemaIssue.InvalidValue(
11077 { expected: "a valid Zoned DateTime string" },
11078 s,
11079 options
11080 )
11081 ),
11082 onSome: Effect.succeed
11083 })
11084 },
11085 encode: (zoned) => Effect.succeed(DateTime.formatIsoZoned(zoned))
11086 })
11087const arbitraryMinimumDateTimestamp = -8_640_000_000_000_000
11088const arbitraryMaximumDateTimestamp = 8_640_000_000_000_000
11089const arbitraryMinimumZonedDateTimeTimestamp = arbitraryMinimumDateTimestamp + 14 * 60 * 60 * 1000
11090const arbitraryMaximumZonedDateTimeTimestamp = arbitraryMaximumDateTimestamp - 14 * 60 * 60 * 1000
11091const arbitraryMinimumTimeZoneOffset = -12 * 60 * 60 * 1000
11092const arbitraryMaximumTimeZoneOffset = 14 * 60 * 60 * 1000
11093const arbitraryNamedTimeZones = [
11094 "UTC",
11095 "Europe/London",
11096 "America/New_York",
11097 "Asia/Tokyo",
11098 "Australia/Sydney"
11099] as const
11100function dateTimeArbitraryBounds<T extends { readonly epochMilliseconds: number }>(
11101 constraint: Annotations.ToArbitrary.GenerationConstraint<T> | undefined,
11102 domainMinimum: number,
11103 domainMaximum: number
11104): readonly [minimum: number, maximum: number] {
11105 const minimum = Math.max(
11106 domainMinimum,
11107 constraint?.minimum === undefined
11108 ? domainMinimum
11109 : constraint.minimum.epochMilliseconds + (constraint.exclusiveMinimum === true ? 1 : 0)
11110 )
11111 const maximum = Math.min(
11112 domainMaximum,
11113 constraint?.maximum === undefined
11114 ? domainMaximum
11115 : constraint.maximum.epochMilliseconds - (constraint.exclusiveMaximum === true ? 1 : 0)
11116 )
11117 return minimum <= maximum ? [minimum, maximum] : [domainMinimum, domainMaximum]
11118}
11119function dateTimeArbitraryInteger(minimum: number, maximum: number): Codec<number> {
11120 return Int.check(isBetween({ minimum, maximum }))
11121}
11122function timeZoneArbitrarySchema(): Codec<number | string> {
11123 return Union([
11124 dateTimeArbitraryInteger(arbitraryMinimumTimeZoneOffset, arbitraryMaximumTimeZoneOffset),
11125 Literals(arbitraryNamedTimeZones)
11126 ])
11127}
11128/**
11129 * Type-level representation of {@link DateTimeUtc}.
11130 *
11131 * @category models
11132 * @since 3.10.0
11133 */
11134export interface DateTimeUtc extends declare<DateTime.Utc> {
11135 readonly "Rebuild": DateTimeUtc
11136}
11137/**
11138 * Schema for `DateTime.Utc` values.
11139 *
11140 * **When to use**
11141 *
11142 * Use to validate existing `DateTime.Utc` schema values and use the default JSON
11143 * codec that represents them as UTC ISO strings.
11144 *
11145 * **Details**
11146 *
11147 * The default JSON codec decodes UTC ISO strings into `DateTime.Utc` values and
11148 * encodes `DateTime.Utc` values as UTC ISO strings.
11149 *
11150 * @see {@link DateTimeUtcFromString} for decoding date-time strings into UTC values
11151 * @see {@link DateTimeUtcFromDate} for decoding JavaScript Date values into UTC values
11152 * @see {@link DateTimeUtcFromMillis} for decoding epoch milliseconds into UTC values
11153 * @see {@link DateTimeZoned} for preserving zoned DateTime values
11154 *
11155 * @category schemas
11156 * @since 3.10.0
11157 */
11158export const DateTimeUtc: DateTimeUtc = declare(
11159 (u) => DateTime.isDateTime(u) && DateTime.isUtc(u),
11160 {
11161 representation: {
11162 id: "effect/schema/DateTimeUtc",
11163 payload: null
11164 },
11165 toCode: () => ({
11166 runtime: `Schema.DateTimeUtc`,
11167 Type: `DateTime.Utc`,
11168 importDeclarations: [`import * as DateTime from "effect/DateTime"`]
11169 }),
11170 expected: "DateTime.Utc",
11171 toCodecArbitrary: ({ constraint }) => {
11172 const [minimum, maximum] = dateTimeArbitraryBounds(
11173 constraint,
11174 arbitraryMinimumDateTimestamp,
11175 arbitraryMaximumDateTimestamp
11176 )
11177 return linkDecoding<DateTime.Utc>()(
11178 dateTimeArbitraryInteger(minimum, maximum),
11179 SchemaGetter.transform(DateTime.makeUnsafe)
11180 )
11181 },
11182 toCodecJson: () =>
11183 link<DateTime.Utc>()(
11184 String,
11185 dateTimeUtcFromString
11186 ),
11187 toFormatter: () => (utc) => utc.toString()
11188 }
11189)
11190/**
11191 * Type-level representation of {@link DateTimeUtcFromDate}.
11192 *
11193 * @category models
11194 * @since 3.12.0
11195 */
11196export interface DateTimeUtcFromDate extends decodeTo<DateTimeUtc, Date> {
11197 readonly "Rebuild": DateTimeUtcFromDate
11198}
11199/**
11200 * Schema that decodes a `Date` into a `DateTime.Utc`.
11201 *
11202 * **When to use**
11203 *
11204 * Use when you need to decode valid JavaScript `Date` objects into
11205 * `DateTime.Utc` values.
11206 *
11207 * **Details**
11208 *
11209 * Decoding:
11210 * - A **valid** `Date` is decoded as a `DateTime.Utc`
11211 *
11212 * Encoding:
11213 * - A `DateTime.Utc` is encoded as a `Date`
11214 *
11215 * @see {@link DateTimeUtc} for validating values that are already `DateTime.Utc`
11216 * @see {@link DateTimeUtcFromString} for decoding date-time strings into UTC values
11217 * @see {@link DateTimeUtcFromMillis} for decoding epoch milliseconds into UTC values
11218 * @see {@link Date} for validating Date instances without converting them
11219 *
11220 * @category schemas
11221 * @since 3.12.0
11222 */
11223export const DateTimeUtcFromDate: DateTimeUtcFromDate = Date.pipe(
11224 decodeTo(DateTimeUtc, {
11225 decode: dateTimeUtcFromInput(),
11226 encode: SchemaGetter.transform(DateTime.toDateUtc)
11227 })
11228)
11229/**
11230 * Type-level representation of {@link DateTimeUtcFromString}.
11231 *
11232 * @category models
11233 * @since 4.0.0
11234 */
11235export interface DateTimeUtcFromString extends decodeTo<DateTimeUtc, String> {
11236 readonly "Rebuild": DateTimeUtcFromString
11237}
11238/**
11239 * Schema that decodes a date-time string into a `DateTime.Utc`.
11240 *
11241 * **Details**
11242 *
11243 * Decoding:
11244 *
11245 * - A string accepted by `DateTime.make` is parsed and normalized to UTC. Strings
11246 * without an explicit zone are interpreted as UTC.
11247 *
11248 * Encoding:
11249 *
11250 * - A `DateTime.Utc` is encoded as a UTC ISO 8601 string.
11251 *
11252 * @see {@link DateTimeUtcFromDate} for decoding JavaScript Date values into UTC values
11253 * @see {@link DateTimeUtcFromMillis} for decoding epoch milliseconds into UTC values
11254 * @see {@link DateFromString} for decoding strings into JavaScript Date instances
11255 *
11256 * @category schemas
11257 * @since 4.0.0
11258 */
11259export const DateTimeUtcFromString: DateTimeUtcFromString = String.annotate({
11260 expected: "a string that will be decoded as a DateTime.Utc"
11261}).pipe(
11262 decodeTo(
11263 DateTimeUtc,
11264 dateTimeUtcFromString
11265 )
11266)
11267/**
11268 * Type-level representation of {@link DateTimeUtcFromMillis}.
11269 *
11270 * @category models
11271 * @since 4.0.0
11272 */
11273export interface DateTimeUtcFromMillis extends decodeTo<instanceOf<DateTime.Utc>, Int> {
11274 readonly "Rebuild": DateTimeUtcFromMillis
11275}
11276/**
11277 * Schema that decodes a number into a `DateTime.Utc`.
11278 *
11279 * **Details**
11280 *
11281 * Decoding:
11282 * - A number of milliseconds since the Unix epoch is decoded as a `DateTime.Utc`
11283 *
11284 * Encoding:
11285 * - A `DateTime.Utc` is encoded as a number of milliseconds since the Unix epoch.
11286 *
11287 * @see {@link DateTimeUtcFromDate} for decoding JavaScript Date values into UTC values
11288 * @see {@link DateTimeUtcFromString} for decoding date-time strings into UTC values
11289 * @see {@link DateFromMillis} for decoding epoch milliseconds into JavaScript Date instances
11290 *
11291 * @category schemas
11292 * @since 4.0.0
11293 */
11294export const DateTimeUtcFromMillis: DateTimeUtcFromMillis = Int.pipe(
11295 decodeTo(DateTimeUtc, {
11296 decode: dateTimeUtcFromInput(),
11297 encode: SchemaGetter.transform(DateTime.toEpochMillis)
11298 })
11299)
11300/**
11301 * Type-level representation of {@link TimeZoneOffset}.
11302 *
11303 * @category models
11304 * @since 3.10.0
11305 */
11306export interface TimeZoneOffset extends declare<DateTime.TimeZone.Offset> {
11307 readonly "Rebuild": TimeZoneOffset
11308}
11309/**
11310 * Schema for `DateTime.TimeZone.Offset` values.
11311 *
11312 * **Details**
11313 *
11314 * Default JSON serializer:
11315 *
11316 * - encodes `DateTime.TimeZone.Offset` as a number (offset in milliseconds)
11317 *
11318 * @category schemas
11319 * @since 3.10.0
11320 */
11321export const TimeZoneOffset: TimeZoneOffset = declare(
11322 DateTime.isTimeZoneOffset,
11323 {
11324 representation: {
11325 id: "effect/schema/TimeZoneOffset",
11326 payload: null
11327 },
11328 toCode: () => ({
11329 runtime: `Schema.TimeZoneOffset`,
11330 Type: `DateTime.TimeZone.Offset`,
11331 importDeclarations: [`import * as DateTime from "effect/DateTime"`]
11332 }),
11333 expected: "DateTime.TimeZone.Offset",
11334 toCodecJson: () =>
11335 link<DateTime.TimeZone.Offset>()(
11336 Int,
11337 timeZoneOffsetFromNumber
11338 ),
11339 toFormatter: () => (tz) => DateTime.zoneToString(tz)
11340 }
11341)
11342/**
11343 * Type-level representation of {@link TimeZoneNamed}.
11344 *
11345 * @category models
11346 * @since 3.10.0
11347 */
11348export interface TimeZoneNamed extends declare<DateTime.TimeZone.Named> {
11349 readonly "Rebuild": TimeZoneNamed
11350}
11351const TimeZoneNamedString = String.annotate({ expected: "an IANA time zone identifier" })
11352/**
11353 * Schema for `DateTime.TimeZone.Named` values.
11354 *
11355 * **Details**
11356 *
11357 * Default JSON serializer:
11358 *
11359 * - encodes `DateTime.TimeZone.Named` as a string (IANA time zone identifier)
11360 *
11361 * @category schemas
11362 * @since 3.10.0
11363 */
11364export const TimeZoneNamed: TimeZoneNamed = declare(
11365 DateTime.isTimeZoneNamed,
11366 {
11367 representation: {
11368 id: "effect/schema/TimeZoneNamed",
11369 payload: null
11370 },
11371 toCode: () => ({
11372 runtime: `Schema.TimeZoneNamed`,
11373 Type: `DateTime.TimeZone.Named`,
11374 importDeclarations: [`import * as DateTime from "effect/DateTime"`]
11375 }),
11376 expected: "DateTime.TimeZone.Named",
11377 toCodecArbitrary: () =>
11378 linkDecoding<DateTime.TimeZone.Named>()(
11379 Literals(arbitraryNamedTimeZones),
11380 SchemaGetter.transform(DateTime.zoneMakeNamedUnsafe)
11381 ),
11382 toCodecJson: () =>
11383 link<DateTime.TimeZone.Named>()(
11384 TimeZoneNamedString,
11385 timeZoneNamedFromString
11386 ),
11387 toFormatter: () => (tz) => DateTime.zoneToString(tz)
11388 }
11389)
11390/**
11391 * Type-level representation of {@link TimeZoneNamedFromString}.
11392 *
11393 * @category models
11394 * @since 4.0.0
11395 */
11396export interface TimeZoneNamedFromString extends decodeTo<TimeZoneNamed, String> {
11397 readonly "Rebuild": TimeZoneNamedFromString
11398}
11399/**
11400 * Schema that parses an IANA time zone identifier string into a `DateTime.TimeZone.Named`.
11401 *
11402 * **Details**
11403 *
11404 * Decoding:
11405 * - A `string` is decoded as a `DateTime.TimeZone.Named`.
11406 *
11407 * Encoding:
11408 * - A `DateTime.TimeZone.Named` is encoded as a `string`.
11409 *
11410 * @category schemas
11411 * @since 4.0.0
11412 */
11413export const TimeZoneNamedFromString: TimeZoneNamedFromString = TimeZoneNamedString.pipe(
11414 decodeTo(TimeZoneNamed, timeZoneNamedFromString)
11415)
11416/**
11417 * Type-level representation of {@link TimeZone}.
11418 *
11419 * @category models
11420 * @since 3.10.0
11421 */
11422export interface TimeZone extends declare<DateTime.TimeZone> {
11423 readonly "Rebuild": TimeZone
11424}
11425const TimeZoneString = String.annotate({
11426 expected: "a time zone string (IANA identifier or offset like +03:00)"
11427})
11428/**
11429 * Schema for `DateTime.TimeZone` values.
11430 *
11431 * **Details**
11432 *
11433 * Default JSON serializer:
11434 *
11435 * - encodes `DateTime.TimeZone` as a string (IANA identifier or offset like
11436 * `+03:00`)
11437 *
11438 * @category schemas
11439 * @since 3.10.0
11440 */
11441export const TimeZone: TimeZone = declare(
11442 DateTime.isTimeZone,
11443 {
11444 representation: {
11445 id: "effect/schema/TimeZone",
11446 payload: null
11447 },
11448 toCode: () => ({
11449 runtime: `Schema.TimeZone`,
11450 Type: `DateTime.TimeZone`,
11451 importDeclarations: [`import * as DateTime from "effect/DateTime"`]
11452 }),
11453 expected: "DateTime.TimeZone",
11454 toCodecArbitrary: () =>
11455 linkDecoding<DateTime.TimeZone>()(
11456 timeZoneArbitrarySchema(),
11457 SchemaGetter.transform((value) =>
11458 typeof value === "number" ? DateTime.zoneMakeOffset(value) : DateTime.zoneMakeNamedUnsafe(value)
11459 )
11460 ),
11461 toCodecJson: () =>
11462 link<DateTime.TimeZone>()(
11463 TimeZoneString,
11464 timeZoneFromString
11465 ),
11466 toFormatter: () => (tz) => DateTime.zoneToString(tz)
11467 }
11468)
11469/**
11470 * Type-level representation of {@link TimeZoneFromString}.
11471 *
11472 * @category models
11473 * @since 4.0.0
11474 */
11475export interface TimeZoneFromString extends decodeTo<TimeZone, String> {
11476 readonly "Rebuild": TimeZoneFromString
11477}
11478/**
11479 * Schema that parses a time zone string into a `DateTime.TimeZone`.
11480 *
11481 * **Details**
11482 *
11483 * Decoding:
11484 * - A `string` (IANA identifier or offset like `+03:00`) is decoded as a `DateTime.TimeZone`.
11485 *
11486 * Encoding:
11487 * - A `DateTime.TimeZone` is encoded as a `string`.
11488 *
11489 * @category schemas
11490 * @since 4.0.0
11491 */
11492export const TimeZoneFromString: TimeZoneFromString = TimeZoneString.pipe(
11493 decodeTo(TimeZone, timeZoneFromString)
11494)
11495/**
11496 * Type-level representation of {@link DateTimeZoned}.
11497 *
11498 * @category models
11499 * @since 3.10.0
11500 */
11501export interface DateTimeZoned extends declare<DateTime.Zoned> {
11502 readonly "Rebuild": DateTimeZoned
11503}
11504const DateTimeZonedString = String.annotate({
11505 expected: "a zoned DateTime string (e.g. 2024-01-01T00:00:00.000+00:00[Europe/London])"
11506})
11507/**
11508 * Schema for `DateTime.Zoned` values.
11509 *
11510 * **Details**
11511 *
11512 * Default JSON serializer:
11513 *
11514 * - encodes offset zones as an ISO date-time with a numeric offset, such as
11515 * `YYYY-MM-DDTHH:mm:ss.sss+HH:MM`
11516 * - encodes named zones by appending the IANA identifier in brackets, such as
11517 * `YYYY-MM-DDTHH:mm:ss.sss+HH:MM[Time/Zone]`
11518 *
11519 * @category schemas
11520 * @since 3.10.0
11521 */
11522export const DateTimeZoned: DateTimeZoned = declare(
11523 (u) => DateTime.isDateTime(u) && DateTime.isZoned(u),
11524 {
11525 representation: {
11526 id: "effect/schema/DateTimeZoned",
11527 payload: null
11528 },
11529 toCode: () => ({
11530 runtime: `Schema.DateTimeZoned`,
11531 Type: `DateTime.Zoned`,
11532 importDeclarations: [`import * as DateTime from "effect/DateTime"`]
11533 }),
11534 expected: "DateTime.Zoned",
11535 toCodecArbitrary: ({ constraint }) => {
11536 const [minimum, maximum] = dateTimeArbitraryBounds(
11537 constraint,
11538 arbitraryMinimumZonedDateTimeTimestamp,
11539 arbitraryMaximumZonedDateTimeTimestamp
11540 )
11541 return linkDecoding<DateTime.Zoned>()(
11542 Struct({
11543 epochMilliseconds: dateTimeArbitraryInteger(minimum, maximum),
11544 timeZone: timeZoneArbitrarySchema()
11545 }),
11546 SchemaGetter.transform(({ epochMilliseconds, timeZone }) =>
11547 DateTime.makeZonedUnsafe(epochMilliseconds, { timeZone })
11548 )
11549 )
11550 },
11551 toCodecJson: () =>
11552 link<DateTime.Zoned>()(
11553 DateTimeZonedString,
11554 dateTimeZonedFromString
11555 ),
11556 toFormatter: () => (zoned) => DateTime.formatIsoZoned(zoned),
11557 toEquivalence: () => DateTime.Equivalence
11558 }
11559)
11560/**
11561 * Type-level representation of {@link DateTimeZonedFromString}.
11562 *
11563 * @category models
11564 * @since 4.0.0
11565 */
11566export interface DateTimeZonedFromString extends decodeTo<DateTimeZoned, String> {
11567 readonly "Rebuild": DateTimeZonedFromString
11568}
11569/**
11570 * Schema that parses a zoned DateTime string into a `DateTime.Zoned`.
11571 *
11572 * **Details**
11573 *
11574 * Decoding:
11575 * - A `string` (e.g. `2024-01-01T00:00:00.000+00:00[Europe/London]`) is decoded as a `DateTime.Zoned`.
11576 *
11577 * Encoding:
11578 * - A `DateTime.Zoned` is encoded as a `string`.
11579 *
11580 * @category schemas
11581 * @since 4.0.0
11582 */
11583export const DateTimeZonedFromString: DateTimeZonedFromString = DateTimeZonedString.pipe(
11584 decodeTo(DateTimeZoned, dateTimeZonedFromString)
11585)
11586
11587const netAddressFromString = <S extends declare<any>, E extends { readonly message: string }>(
11588 declaration: S,
11589 parse: (input: string) => Result_.Result<S["Type"], E>,
11590 encode: (value: S["Type"]) => string,
11591 identifier: string
11592) =>
11593 String.pipe(decodeTo(
11594 declaration,
11595 SchemaTransformation.transformEffect({
11596 decode: (input, options) => {
11597 const result = parse(input)
11598 return Result_.isSuccess(result)
11599 ? Effect.succeed(result.success)
11600 : Effect.fail(new SchemaIssue.InvalidValue({ message: result.failure.message }, input, options))
11601 },
11602 encode: (value) => Effect.succeed(encode(value))
11603 })
11604 )).annotate({ identifier })
11605
11606/**
11607 * Type-level representation of {@link MacAddress}.
11608 *
11609 * @stability unstable
11610 * @category models
11611 * @since 4.0.0
11612 */
11613export interface MacAddress extends declare<NetAddress_.MacAddress> {
11614 readonly "Rebuild": MacAddress
11615}
11616
11617/**
11618 * Schema for already-constructed MAC address values.
11619 *
11620 * @stability unstable
11621 * @category schemas
11622 * @since 4.0.0
11623 */
11624export const MacAddress: MacAddress = declare(NetAddress_.isMacAddress, {
11625 identifier: "MacAddress"
11626})
11627
11628/**
11629 * Type-level representation of {@link MacAddressFromString}.
11630 *
11631 * @stability unstable
11632 * @category models
11633 * @since 4.0.0
11634 */
11635export interface MacAddressFromString extends decodeTo<MacAddress, String> {
11636 readonly "Rebuild": MacAddressFromString
11637}
11638
11639/**
11640 * Schema for MAC addresses encoded as canonical colon-separated hexadecimal strings.
11641 *
11642 * @stability unstable
11643 * @category schemas
11644 * @since 4.0.0
11645 */
11646export const MacAddressFromString: MacAddressFromString = netAddressFromString(
11647 MacAddress,
11648 NetAddress_.macAddressFromString,
11649 NetAddress_.formatMacAddress,
11650 "MacAddressFromString"
11651)
11652
11653/**
11654 * Type-level representation of {@link Ipv4Address}.
11655 *
11656 * @stability unstable
11657 * @category models
11658 * @since 4.0.0
11659 */
11660export interface Ipv4Address extends declare<NetAddress_.Ipv4Address> {
11661 readonly "Rebuild": Ipv4Address
11662}
11663
11664/**
11665 * Schema for already-constructed IPv4 address values.
11666 *
11667 * @stability unstable
11668 * @category schemas
11669 * @since 4.0.0
11670 */
11671export const Ipv4Address: Ipv4Address = declare(NetAddress_.isIpv4Address, {
11672 identifier: "Ipv4Address"
11673})
11674
11675/**
11676 * Type-level representation of {@link Ipv4AddressFromString}.
11677 *
11678 * @stability unstable
11679 * @category models
11680 * @since 4.0.0
11681 */
11682export interface Ipv4AddressFromString extends decodeTo<Ipv4Address, String> {
11683 readonly "Rebuild": Ipv4AddressFromString
11684}
11685
11686/**
11687 * Schema for IPv4 addresses encoded as canonical dotted-decimal strings.
11688 *
11689 * @stability unstable
11690 * @category schemas
11691 * @since 4.0.0
11692 */
11693export const Ipv4AddressFromString: Ipv4AddressFromString = netAddressFromString(
11694 Ipv4Address,
11695 NetAddress_.ipv4FromString,
11696 NetAddress_.formatIp,
11697 "Ipv4AddressFromString"
11698)
11699
11700/**
11701 * Type-level representation of {@link Ipv6Address}.
11702 *
11703 * @stability unstable
11704 * @category models
11705 * @since 4.0.0
11706 */
11707export interface Ipv6Address extends declare<NetAddress_.Ipv6Address> {
11708 readonly "Rebuild": Ipv6Address
11709}
11710
11711/**
11712 * Schema for already-constructed IPv6 address values.
11713 *
11714 * @stability unstable
11715 * @category schemas
11716 * @since 4.0.0
11717 */
11718export const Ipv6Address: Ipv6Address = declare(NetAddress_.isIpv6Address, {
11719 identifier: "Ipv6Address"
11720})
11721
11722/**
11723 * Type-level representation of {@link Ipv6AddressFromString}.
11724 *
11725 * @stability unstable
11726 * @category models
11727 * @since 4.0.0
11728 */
11729export interface Ipv6AddressFromString extends decodeTo<Ipv6Address, String> {
11730 readonly "Rebuild": Ipv6AddressFromString
11731}
11732
11733/**
11734 * Schema for IPv6 addresses encoded as canonical strings.
11735 *
11736 * @stability unstable
11737 * @category schemas
11738 * @since 4.0.0
11739 */
11740export const Ipv6AddressFromString: Ipv6AddressFromString = netAddressFromString(
11741 Ipv6Address,
11742 NetAddress_.ipv6FromString,
11743 NetAddress_.formatIp,
11744 "Ipv6AddressFromString"
11745)
11746
11747/**
11748 * Type-level representation of {@link IpAddress}.
11749 *
11750 * @stability unstable
11751 * @category models
11752 * @since 4.0.0
11753 */
11754export interface IpAddress extends declare<NetAddress_.IpAddress> {
11755 readonly "Rebuild": IpAddress
11756}
11757
11758/**
11759 * Schema for already-constructed IPv4 or IPv6 address values.
11760 *
11761 * @stability unstable
11762 * @category schemas
11763 * @since 4.0.0
11764 */
11765export const IpAddress: IpAddress = declare(NetAddress_.isIpAddress, {
11766 identifier: "IpAddress"
11767})
11768
11769/**
11770 * Type-level representation of {@link IpAddressFromString}.
11771 *
11772 * @stability unstable
11773 * @category models
11774 * @since 4.0.0
11775 */
11776export interface IpAddressFromString extends decodeTo<IpAddress, String> {
11777 readonly "Rebuild": IpAddressFromString
11778}
11779
11780/**
11781 * Schema for IP addresses encoded as canonical numeric strings.
11782 *
11783 * @stability unstable
11784 * @category schemas
11785 * @since 4.0.0
11786 */
11787export const IpAddressFromString: IpAddressFromString = netAddressFromString(
11788 IpAddress,
11789 NetAddress_.ipFromString,
11790 NetAddress_.formatIp,
11791 "IpAddressFromString"
11792)
11793
11794const netAddressRefinement = <S extends Constraint, T extends S["Type"]>(
11795 schema: S,
11796 guard: (value: S["Type"]) => value is T,
11797 expected: string,
11798 identifier: string
11799): refine<T, S> => refine(guard, { expected })(schema).annotate({ identifier })
11800
11801/**
11802 * Type-level representation of {@link IpMulticastAddress}.
11803 *
11804 * @stability unstable
11805 * @category models
11806 * @since 4.0.0
11807 */
11808export interface IpMulticastAddress extends refine<NetAddress_.MulticastAddress<NetAddress_.IpAddress>, IpAddress> {
11809 readonly "Rebuild": IpMulticastAddress
11810}
11811
11812/**
11813 * Schema for already-constructed multicast IP addresses.
11814 *
11815 * @stability unstable
11816 * @category schemas
11817 * @since 4.0.0
11818 */
11819export const IpMulticastAddress: IpMulticastAddress = netAddressRefinement(
11820 IpAddress,
11821 NetAddress_.isMulticast,
11822 "a multicast address",
11823 "IpMulticastAddress"
11824)
11825
11826/**
11827 * Type-level representation of {@link IpMulticastAddressFromString}.
11828 *
11829 * @stability unstable
11830 * @category models
11831 * @since 4.0.0
11832 */
11833export interface IpMulticastAddressFromString
11834 extends refine<NetAddress_.MulticastAddress<NetAddress_.IpAddress>, IpAddressFromString>
11835{
11836 readonly "Rebuild": IpMulticastAddressFromString
11837}
11838
11839/**
11840 * Schema for multicast IP addresses encoded as numeric strings.
11841 *
11842 * **Example** (Decoding a validated multicast address)
11843 *
11844 * ```ts import.meta.vitest
11845 * import { assert } from "@effect/vitest"
11846 * import { Schema } from "effect"
11847 * import { NetAddress } from "effect/net"
11848 *
11849 * const address = Schema.decodeUnknownSync(Schema.IpMulticastAddressFromString)("239.255.0.1")
11850 * assert.isTrue(NetAddress.isMulticast(address))
11851 * ```
11852 *
11853 * @stability unstable
11854 * @category schemas
11855 * @since 4.0.0
11856 */
11857export const IpMulticastAddressFromString: IpMulticastAddressFromString = netAddressRefinement(
11858 IpAddressFromString,
11859 NetAddress_.isMulticast,
11860 "a multicast address",
11861 "IpMulticastAddressFromString"
11862)
11863
11864/**
11865 * Type-level representation of {@link MacMulticastAddress}.
11866 *
11867 * @stability unstable
11868 * @category models
11869 * @since 4.0.0
11870 */
11871export interface MacMulticastAddress extends refine<NetAddress_.MulticastAddress<NetAddress_.MacAddress>, MacAddress> {
11872 readonly "Rebuild": MacMulticastAddress
11873}
11874
11875/**
11876 * Schema for already-constructed multicast MAC addresses.
11877 *
11878 * @stability unstable
11879 * @category schemas
11880 * @since 4.0.0
11881 */
11882export const MacMulticastAddress: MacMulticastAddress = netAddressRefinement(
11883 MacAddress,
11884 NetAddress_.isMulticast,
11885 "a multicast address",
11886 "MacMulticastAddress"
11887)
11888
11889/**
11890 * Type-level representation of {@link MacMulticastAddressFromString}.
11891 *
11892 * @stability unstable
11893 * @category models
11894 * @since 4.0.0
11895 */
11896export interface MacMulticastAddressFromString
11897 extends refine<NetAddress_.MulticastAddress<NetAddress_.MacAddress>, MacAddressFromString>
11898{
11899 readonly "Rebuild": MacMulticastAddressFromString
11900}
11901
11902/**
11903 * Schema for multicast MAC addresses encoded as canonical strings.
11904 *
11905 * @stability unstable
11906 * @category schemas
11907 * @since 4.0.0
11908 */
11909export const MacMulticastAddressFromString: MacMulticastAddressFromString = netAddressRefinement(
11910 MacAddressFromString,
11911 NetAddress_.isMulticast,
11912 "a multicast address",
11913 "MacMulticastAddressFromString"
11914)
11915
11916/**
11917 * Type-level representation of {@link IpUnicastAddress}.
11918 *
11919 * @stability unstable
11920 * @category models
11921 * @since 4.0.0
11922 */
11923export interface IpUnicastAddress extends refine<NetAddress_.UnicastAddress<NetAddress_.IpAddress>, IpAddress> {
11924 readonly "Rebuild": IpUnicastAddress
11925}
11926
11927/**
11928 * Schema for already-constructed syntactic unicast IP addresses.
11929 *
11930 * @stability unstable
11931 * @category schemas
11932 * @since 4.0.0
11933 */
11934export const IpUnicastAddress: IpUnicastAddress = netAddressRefinement(
11935 IpAddress,
11936 NetAddress_.isUnicast,
11937 "a unicast address",
11938 "IpUnicastAddress"
11939)
11940
11941/**
11942 * Type-level representation of {@link IpUnicastAddressFromString}.
11943 *
11944 * @stability unstable
11945 * @category models
11946 * @since 4.0.0
11947 */
11948export interface IpUnicastAddressFromString
11949 extends refine<NetAddress_.UnicastAddress<NetAddress_.IpAddress>, IpAddressFromString>
11950{
11951 readonly "Rebuild": IpUnicastAddressFromString
11952}
11953
11954/**
11955 * Schema for syntactic unicast IP addresses encoded as numeric strings.
11956 *
11957 * @stability unstable
11958 * @category schemas
11959 * @since 4.0.0
11960 */
11961export const IpUnicastAddressFromString: IpUnicastAddressFromString = netAddressRefinement(
11962 IpAddressFromString,
11963 NetAddress_.isUnicast,
11964 "a unicast address",
11965 "IpUnicastAddressFromString"
11966)
11967
11968/**
11969 * Type-level representation of {@link MacUnicastAddress}.
11970 *
11971 * @stability unstable
11972 * @category models
11973 * @since 4.0.0
11974 */
11975export interface MacUnicastAddress extends refine<NetAddress_.UnicastAddress<NetAddress_.MacAddress>, MacAddress> {
11976 readonly "Rebuild": MacUnicastAddress
11977}
11978
11979/**
11980 * Schema for already-constructed unicast MAC addresses.
11981 *
11982 * @stability unstable
11983 * @category schemas
11984 * @since 4.0.0
11985 */
11986export const MacUnicastAddress: MacUnicastAddress = netAddressRefinement(
11987 MacAddress,
11988 NetAddress_.isMacUnicast,
11989 "a unicast address",
11990 "MacUnicastAddress"
11991)
11992
11993/**
11994 * Type-level representation of {@link MacUnicastAddressFromString}.
11995 *
11996 * @stability unstable
11997 * @category models
11998 * @since 4.0.0
11999 */
12000export interface MacUnicastAddressFromString
12001 extends refine<NetAddress_.UnicastAddress<NetAddress_.MacAddress>, MacAddressFromString>
12002{
12003 readonly "Rebuild": MacUnicastAddressFromString
12004}
12005
12006/**
12007 * Schema for unicast MAC addresses encoded as canonical strings.
12008 *
12009 * @stability unstable
12010 * @category schemas
12011 * @since 4.0.0
12012 */
12013export const MacUnicastAddressFromString: MacUnicastAddressFromString = netAddressRefinement(
12014 MacAddressFromString,
12015 NetAddress_.isMacUnicast,
12016 "a unicast address",
12017 "MacUnicastAddressFromString"
12018)
12019
12020/**
12021 * Type-level representation of {@link Ipv4BroadcastAddress}.
12022 *
12023 * @stability unstable
12024 * @category models
12025 * @since 4.0.0
12026 */
12027export interface Ipv4BroadcastAddress
12028 extends refine<NetAddress_.BroadcastAddress<NetAddress_.Ipv4Address>, Ipv4Address>
12029{
12030 readonly "Rebuild": Ipv4BroadcastAddress
12031}
12032
12033/**
12034 * Schema for the already-constructed IPv4 limited broadcast address.
12035 *
12036 * @stability unstable
12037 * @category schemas
12038 * @since 4.0.0
12039 */
12040export const Ipv4BroadcastAddress: Ipv4BroadcastAddress = netAddressRefinement(
12041 Ipv4Address,
12042 NetAddress_.isBroadcast,
12043 "a broadcast address",
12044 "Ipv4BroadcastAddress"
12045)
12046
12047/**
12048 * Type-level representation of {@link Ipv4BroadcastAddressFromString}.
12049 *
12050 * @stability unstable
12051 * @category models
12052 * @since 4.0.0
12053 */
12054export interface Ipv4BroadcastAddressFromString
12055 extends refine<NetAddress_.BroadcastAddress<NetAddress_.Ipv4Address>, Ipv4AddressFromString>
12056{
12057 readonly "Rebuild": Ipv4BroadcastAddressFromString
12058}
12059
12060/**
12061 * Schema for the IPv4 limited broadcast address encoded as a string.
12062 *
12063 * @stability unstable
12064 * @category schemas
12065 * @since 4.0.0
12066 */
12067export const Ipv4BroadcastAddressFromString: Ipv4BroadcastAddressFromString = netAddressRefinement(
12068 Ipv4AddressFromString,
12069 NetAddress_.isBroadcast,
12070 "a broadcast address",
12071 "Ipv4BroadcastAddressFromString"
12072)
12073
12074/**
12075 * Type-level representation of {@link MacBroadcastAddress}.
12076 *
12077 * @stability unstable
12078 * @category models
12079 * @since 4.0.0
12080 */
12081export interface MacBroadcastAddress extends refine<NetAddress_.BroadcastAddress<NetAddress_.MacAddress>, MacAddress> {
12082 readonly "Rebuild": MacBroadcastAddress
12083}
12084
12085/**
12086 * Schema for the already-constructed MAC all-ones broadcast address.
12087 *
12088 * @stability unstable
12089 * @category schemas
12090 * @since 4.0.0
12091 */
12092export const MacBroadcastAddress: MacBroadcastAddress = netAddressRefinement(
12093 MacAddress,
12094 NetAddress_.isMacBroadcast,
12095 "a broadcast address",
12096 "MacBroadcastAddress"
12097)
12098
12099/**
12100 * Type-level representation of {@link MacBroadcastAddressFromString}.
12101 *
12102 * @stability unstable
12103 * @category models
12104 * @since 4.0.0
12105 */
12106export interface MacBroadcastAddressFromString
12107 extends refine<NetAddress_.BroadcastAddress<NetAddress_.MacAddress>, MacAddressFromString>
12108{
12109 readonly "Rebuild": MacBroadcastAddressFromString
12110}
12111
12112/**
12113 * Schema for the MAC all-ones broadcast address encoded as a string.
12114 *
12115 * @stability unstable
12116 * @category schemas
12117 * @since 4.0.0
12118 */
12119export const MacBroadcastAddressFromString: MacBroadcastAddressFromString = netAddressRefinement(
12120 MacAddressFromString,
12121 NetAddress_.isMacBroadcast,
12122 "a broadcast address",
12123 "MacBroadcastAddressFromString"
12124)
12125
12126/**
12127 * Type-level representation of {@link IpLoopbackAddress}.
12128 *
12129 * @stability unstable
12130 * @category models
12131 * @since 4.0.0
12132 */
12133export interface IpLoopbackAddress extends refine<NetAddress_.LoopbackAddress<NetAddress_.IpAddress>, IpAddress> {
12134 readonly "Rebuild": IpLoopbackAddress
12135}
12136
12137/**
12138 * Schema for already-constructed loopback IP addresses.
12139 *
12140 * @stability unstable
12141 * @category schemas
12142 * @since 4.0.0
12143 */
12144export const IpLoopbackAddress: IpLoopbackAddress = netAddressRefinement(
12145 IpAddress,
12146 NetAddress_.isLoopback,
12147 "a loopback address",
12148 "IpLoopbackAddress"
12149)
12150
12151/**
12152 * Type-level representation of {@link IpLoopbackAddressFromString}.
12153 *
12154 * @stability unstable
12155 * @category models
12156 * @since 4.0.0
12157 */
12158export interface IpLoopbackAddressFromString
12159 extends refine<NetAddress_.LoopbackAddress<NetAddress_.IpAddress>, IpAddressFromString>
12160{
12161 readonly "Rebuild": IpLoopbackAddressFromString
12162}
12163
12164/**
12165 * Schema for loopback IP addresses encoded as numeric strings.
12166 *
12167 * @stability unstable
12168 * @category schemas
12169 * @since 4.0.0
12170 */
12171export const IpLoopbackAddressFromString: IpLoopbackAddressFromString = netAddressRefinement(
12172 IpAddressFromString,
12173 NetAddress_.isLoopback,
12174 "a loopback address",
12175 "IpLoopbackAddressFromString"
12176)
12177
12178/**
12179 * Type-level representation of {@link IpLinkLocalAddress}.
12180 *
12181 * @stability unstable
12182 * @category models
12183 * @since 4.0.0
12184 */
12185export interface IpLinkLocalAddress extends refine<NetAddress_.LinkLocalAddress<NetAddress_.IpAddress>, IpAddress> {
12186 readonly "Rebuild": IpLinkLocalAddress
12187}
12188
12189/**
12190 * Schema for already-constructed link-local IP addresses.
12191 *
12192 * @stability unstable
12193 * @category schemas
12194 * @since 4.0.0
12195 */
12196export const IpLinkLocalAddress: IpLinkLocalAddress = netAddressRefinement(
12197 IpAddress,
12198 NetAddress_.isLinkLocal,
12199 "a link-local address",
12200 "IpLinkLocalAddress"
12201)
12202
12203/**
12204 * Type-level representation of {@link IpLinkLocalAddressFromString}.
12205 *
12206 * @stability unstable
12207 * @category models
12208 * @since 4.0.0
12209 */
12210export interface IpLinkLocalAddressFromString
12211 extends refine<NetAddress_.LinkLocalAddress<NetAddress_.IpAddress>, IpAddressFromString>
12212{
12213 readonly "Rebuild": IpLinkLocalAddressFromString
12214}
12215
12216/**
12217 * Schema for link-local IP addresses encoded as numeric strings.
12218 *
12219 * @stability unstable
12220 * @category schemas
12221 * @since 4.0.0
12222 */
12223export const IpLinkLocalAddressFromString: IpLinkLocalAddressFromString = netAddressRefinement(
12224 IpAddressFromString,
12225 NetAddress_.isLinkLocal,
12226 "a link-local address",
12227 "IpLinkLocalAddressFromString"
12228)
12229
12230/**
12231 * Type-level representation of {@link IpUnspecifiedAddress}.
12232 *
12233 * @stability unstable
12234 * @category models
12235 * @since 4.0.0
12236 */
12237export interface IpUnspecifiedAddress extends refine<NetAddress_.UnspecifiedAddress<NetAddress_.IpAddress>, IpAddress> {
12238 readonly "Rebuild": IpUnspecifiedAddress
12239}
12240
12241/**
12242 * Schema for already-constructed unspecified IP addresses.
12243 *
12244 * @stability unstable
12245 * @category schemas
12246 * @since 4.0.0
12247 */
12248export const IpUnspecifiedAddress: IpUnspecifiedAddress = netAddressRefinement(
12249 IpAddress,
12250 NetAddress_.isUnspecified,
12251 "an unspecified address",
12252 "IpUnspecifiedAddress"
12253)
12254
12255/**
12256 * Type-level representation of {@link IpUnspecifiedAddressFromString}.
12257 *
12258 * @stability unstable
12259 * @category models
12260 * @since 4.0.0
12261 */
12262export interface IpUnspecifiedAddressFromString
12263 extends refine<NetAddress_.UnspecifiedAddress<NetAddress_.IpAddress>, IpAddressFromString>
12264{
12265 readonly "Rebuild": IpUnspecifiedAddressFromString
12266}
12267
12268/**
12269 * Schema for unspecified IP addresses encoded as numeric strings.
12270 *
12271 * @stability unstable
12272 * @category schemas
12273 * @since 4.0.0
12274 */
12275export const IpUnspecifiedAddressFromString: IpUnspecifiedAddressFromString = netAddressRefinement(
12276 IpAddressFromString,
12277 NetAddress_.isUnspecified,
12278 "an unspecified address",
12279 "IpUnspecifiedAddressFromString"
12280)
12281
12282/**
12283 * Type-level representation of {@link Ipv4PrivateAddress}.
12284 *
12285 * @stability unstable
12286 * @category models
12287 * @since 4.0.0
12288 */
12289export interface Ipv4PrivateAddress extends refine<NetAddress_.PrivateAddress<NetAddress_.Ipv4Address>, Ipv4Address> {
12290 readonly "Rebuild": Ipv4PrivateAddress
12291}
12292
12293/**
12294 * Schema for already-constructed RFC 1918 private-use addresses.
12295 *
12296 * @stability unstable
12297 * @category schemas
12298 * @since 4.0.0
12299 */
12300export const Ipv4PrivateAddress: Ipv4PrivateAddress = netAddressRefinement(
12301 Ipv4Address,
12302 NetAddress_.isPrivate,
12303 "a private address",
12304 "Ipv4PrivateAddress"
12305)
12306
12307/**
12308 * Type-level representation of {@link Ipv4PrivateAddressFromString}.
12309 *
12310 * @stability unstable
12311 * @category models
12312 * @since 4.0.0
12313 */
12314export interface Ipv4PrivateAddressFromString
12315 extends refine<NetAddress_.PrivateAddress<NetAddress_.Ipv4Address>, Ipv4AddressFromString>
12316{
12317 readonly "Rebuild": Ipv4PrivateAddressFromString
12318}
12319
12320/**
12321 * Schema for RFC 1918 private-use addresses encoded as strings.
12322 *
12323 * @stability unstable
12324 * @category schemas
12325 * @since 4.0.0
12326 */
12327export const Ipv4PrivateAddressFromString: Ipv4PrivateAddressFromString = netAddressRefinement(
12328 Ipv4AddressFromString,
12329 NetAddress_.isPrivate,
12330 "a private address",
12331 "Ipv4PrivateAddressFromString"
12332)
12333
12334/**
12335 * Type-level representation of {@link Ipv6UniqueLocalAddress}.
12336 *
12337 * @stability unstable
12338 * @category models
12339 * @since 4.0.0
12340 */
12341export interface Ipv6UniqueLocalAddress
12342 extends refine<NetAddress_.UniqueLocalAddress<NetAddress_.Ipv6Address>, Ipv6Address>
12343{
12344 readonly "Rebuild": Ipv6UniqueLocalAddress
12345}
12346
12347/**
12348 * Schema for already-constructed IPv6 unique-local addresses.
12349 *
12350 * @stability unstable
12351 * @category schemas
12352 * @since 4.0.0
12353 */
12354export const Ipv6UniqueLocalAddress: Ipv6UniqueLocalAddress = netAddressRefinement(
12355 Ipv6Address,
12356 NetAddress_.isUniqueLocal,
12357 "a unique-local address",
12358 "Ipv6UniqueLocalAddress"
12359)
12360
12361/**
12362 * Type-level representation of {@link Ipv6UniqueLocalAddressFromString}.
12363 *
12364 * @stability unstable
12365 * @category models
12366 * @since 4.0.0
12367 */
12368export interface Ipv6UniqueLocalAddressFromString
12369 extends refine<NetAddress_.UniqueLocalAddress<NetAddress_.Ipv6Address>, Ipv6AddressFromString>
12370{
12371 readonly "Rebuild": Ipv6UniqueLocalAddressFromString
12372}
12373
12374/**
12375 * Schema for IPv6 unique-local addresses encoded as strings.
12376 *
12377 * @stability unstable
12378 * @category schemas
12379 * @since 4.0.0
12380 */
12381export const Ipv6UniqueLocalAddressFromString: Ipv6UniqueLocalAddressFromString = netAddressRefinement(
12382 Ipv6AddressFromString,
12383 NetAddress_.isUniqueLocal,
12384 "a unique-local address",
12385 "Ipv6UniqueLocalAddressFromString"
12386)
12387
12388/**
12389 * Type-level representation of {@link MacLocallyAdministeredAddress}.
12390 *
12391 * @stability unstable
12392 * @category models
12393 * @since 4.0.0
12394 */
12395export interface MacLocallyAdministeredAddress
12396 extends refine<NetAddress_.LocallyAdministeredAddress<NetAddress_.MacAddress>, MacAddress>
12397{
12398 readonly "Rebuild": MacLocallyAdministeredAddress
12399}
12400
12401/**
12402 * Schema for already-constructed locally administered MAC addresses.
12403 *
12404 * @stability unstable
12405 * @category schemas
12406 * @since 4.0.0
12407 */
12408export const MacLocallyAdministeredAddress: MacLocallyAdministeredAddress = netAddressRefinement(
12409 MacAddress,
12410 NetAddress_.isMacLocallyAdministered,
12411 "a locally administered address",
12412 "MacLocallyAdministeredAddress"
12413)
12414
12415/**
12416 * Type-level representation of {@link MacLocallyAdministeredAddressFromString}.
12417 *
12418 * @stability unstable
12419 * @category models
12420 * @since 4.0.0
12421 */
12422export interface MacLocallyAdministeredAddressFromString
12423 extends refine<NetAddress_.LocallyAdministeredAddress<NetAddress_.MacAddress>, MacAddressFromString>
12424{
12425 readonly "Rebuild": MacLocallyAdministeredAddressFromString
12426}
12427
12428/**
12429 * Schema for locally administered MAC addresses encoded as strings.
12430 *
12431 * @stability unstable
12432 * @category schemas
12433 * @since 4.0.0
12434 */
12435export const MacLocallyAdministeredAddressFromString: MacLocallyAdministeredAddressFromString = netAddressRefinement(
12436 MacAddressFromString,
12437 NetAddress_.isMacLocallyAdministered,
12438 "a locally administered address",
12439 "MacLocallyAdministeredAddressFromString"
12440)
12441
12442/**
12443 * Type-level representation of {@link MacUniversallyAdministeredAddress}.
12444 *
12445 * @stability unstable
12446 * @category models
12447 * @since 4.0.0
12448 */
12449export interface MacUniversallyAdministeredAddress
12450 extends refine<NetAddress_.UniversallyAdministeredAddress<NetAddress_.MacAddress>, MacAddress>
12451{
12452 readonly "Rebuild": MacUniversallyAdministeredAddress
12453}
12454
12455/**
12456 * Schema for already-constructed universally administered MAC addresses.
12457 *
12458 * @stability unstable
12459 * @category schemas
12460 * @since 4.0.0
12461 */
12462export const MacUniversallyAdministeredAddress: MacUniversallyAdministeredAddress = netAddressRefinement(
12463 MacAddress,
12464 NetAddress_.isMacUniversallyAdministered,
12465 "a universally administered address",
12466 "MacUniversallyAdministeredAddress"
12467)
12468
12469/**
12470 * Type-level representation of {@link MacUniversallyAdministeredAddressFromString}.
12471 *
12472 * @stability unstable
12473 * @category models
12474 * @since 4.0.0
12475 */
12476export interface MacUniversallyAdministeredAddressFromString
12477 extends refine<NetAddress_.UniversallyAdministeredAddress<NetAddress_.MacAddress>, MacAddressFromString>
12478{
12479 readonly "Rebuild": MacUniversallyAdministeredAddressFromString
12480}
12481
12482/**
12483 * Schema for universally administered MAC addresses encoded as strings.
12484 *
12485 * @stability unstable
12486 * @category schemas
12487 * @since 4.0.0
12488 */
12489export const MacUniversallyAdministeredAddressFromString: MacUniversallyAdministeredAddressFromString =
12490 netAddressRefinement(
12491 MacAddressFromString,
12492 NetAddress_.isMacUniversallyAdministered,
12493 "a universally administered address",
12494 "MacUniversallyAdministeredAddressFromString"
12495 )
12496
12497/**
12498 * Type-level representation of {@link Ipv4Interface}.
12499 *
12500 * @stability unstable
12501 * @category models
12502 * @since 4.0.0
12503 */
12504export interface Ipv4Interface extends declare<IpInterface_.Ipv4Interface> {
12505 readonly "Rebuild": Ipv4Interface
12506}
12507
12508/**
12509 * Schema for already-constructed IPv4 interface address values.
12510 *
12511 * @stability unstable
12512 * @category schemas
12513 * @since 4.0.0
12514 */
12515export const Ipv4Interface: Ipv4Interface = declare(IpInterface_.isIpv4Interface, {
12516 identifier: "Ipv4Interface"
12517})
12518
12519/**
12520 * Type-level representation of {@link Ipv4InterfaceFromString}.
12521 *
12522 * @stability unstable
12523 * @category models
12524 * @since 4.0.0
12525 */
12526export interface Ipv4InterfaceFromString extends decodeTo<Ipv4Interface, String> {
12527 readonly "Rebuild": Ipv4InterfaceFromString
12528}
12529
12530/**
12531 * Schema for IPv4 interface addresses encoded as an address and prefix length.
12532 *
12533 * @stability unstable
12534 * @category schemas
12535 * @since 4.0.0
12536 */
12537export const Ipv4InterfaceFromString: Ipv4InterfaceFromString = netAddressFromString(
12538 Ipv4Interface,
12539 IpInterface_.ipv4FromString,
12540 IpInterface_.format,
12541 "Ipv4InterfaceFromString"
12542)
12543
12544/**
12545 * Type-level representation of {@link Ipv6Interface}.
12546 *
12547 * @stability unstable
12548 * @category models
12549 * @since 4.0.0
12550 */
12551export interface Ipv6Interface extends declare<IpInterface_.Ipv6Interface> {
12552 readonly "Rebuild": Ipv6Interface
12553}
12554
12555/**
12556 * Schema for already-constructed IPv6 interface address values.
12557 *
12558 * @stability unstable
12559 * @category schemas
12560 * @since 4.0.0
12561 */
12562export const Ipv6Interface: Ipv6Interface = declare(IpInterface_.isIpv6Interface, {
12563 identifier: "Ipv6Interface"
12564})
12565
12566/**
12567 * Type-level representation of {@link Ipv6InterfaceFromString}.
12568 *
12569 * @stability unstable
12570 * @category models
12571 * @since 4.0.0
12572 */
12573export interface Ipv6InterfaceFromString extends decodeTo<Ipv6Interface, String> {
12574 readonly "Rebuild": Ipv6InterfaceFromString
12575}
12576
12577/**
12578 * Schema for IPv6 interface addresses encoded as an address and prefix length.
12579 *
12580 * @stability unstable
12581 * @category schemas
12582 * @since 4.0.0
12583 */
12584export const Ipv6InterfaceFromString: Ipv6InterfaceFromString = netAddressFromString(
12585 Ipv6Interface,
12586 IpInterface_.ipv6FromString,
12587 IpInterface_.format,
12588 "Ipv6InterfaceFromString"
12589)
12590
12591/**
12592 * Type-level representation of {@link IpInterface}.
12593 *
12594 * @stability unstable
12595 * @category models
12596 * @since 4.0.0
12597 */
12598export interface IpInterface extends declare<IpInterface_.IpInterface> {
12599 readonly "Rebuild": IpInterface
12600}
12601
12602/**
12603 * Schema for already-constructed IPv4 or IPv6 interface address values.
12604 *
12605 * @stability unstable
12606 * @category schemas
12607 * @since 4.0.0
12608 */
12609export const IpInterface: IpInterface = declare(IpInterface_.isIpInterface, {
12610 identifier: "IpInterface"
12611})
12612
12613/**
12614 * Type-level representation of {@link IpInterfaceFromString}.
12615 *
12616 * @stability unstable
12617 * @category models
12618 * @since 4.0.0
12619 */
12620export interface IpInterfaceFromString extends decodeTo<IpInterface, String> {
12621 readonly "Rebuild": IpInterfaceFromString
12622}
12623
12624/**
12625 * Schema for IPv4 or IPv6 interface addresses encoded as an address and prefix length.
12626 *
12627 * @stability unstable
12628 * @category schemas
12629 * @since 4.0.0
12630 */
12631export const IpInterfaceFromString: IpInterfaceFromString = netAddressFromString(
12632 IpInterface,
12633 IpInterface_.fromString,
12634 IpInterface_.format,
12635 "IpInterfaceFromString"
12636)
12637
12638/**
12639 * Type-level representation of {@link Ipv4Network}.
12640 *
12641 * @stability unstable
12642 * @category models
12643 * @since 4.0.0
12644 */
12645export interface Ipv4Network extends declare<IpNetwork_.Ipv4Network> {
12646 readonly "Rebuild": Ipv4Network
12647}
12648
12649/**
12650 * Schema for already-constructed canonical IPv4 network prefixes.
12651 *
12652 * @stability unstable
12653 * @category schemas
12654 * @since 4.0.0
12655 */
12656export const Ipv4Network: Ipv4Network = declare(IpNetwork_.isIpv4Network, {
12657 identifier: "Ipv4Network"
12658})
12659
12660/**
12661 * Type-level representation of {@link Ipv4NetworkFromString}.
12662 *
12663 * @stability unstable
12664 * @category models
12665 * @since 4.0.0
12666 */
12667export interface Ipv4NetworkFromString extends decodeTo<Ipv4Network, String> {
12668 readonly "Rebuild": Ipv4NetworkFromString
12669}
12670
12671/**
12672 * Schema for canonical IPv4 network prefixes encoded in CIDR notation.
12673 *
12674 * @stability unstable
12675 * @category schemas
12676 * @since 4.0.0
12677 */
12678export const Ipv4NetworkFromString: Ipv4NetworkFromString = netAddressFromString(
12679 Ipv4Network,
12680 IpNetwork_.ipv4FromString,
12681 IpNetwork_.format,
12682 "Ipv4NetworkFromString"
12683)
12684
12685/**
12686 * Type-level representation of {@link Ipv6Network}.
12687 *
12688 * @stability unstable
12689 * @category models
12690 * @since 4.0.0
12691 */
12692export interface Ipv6Network extends declare<IpNetwork_.Ipv6Network> {
12693 readonly "Rebuild": Ipv6Network
12694}
12695
12696/**
12697 * Schema for already-constructed canonical IPv6 network prefixes.
12698 *
12699 * @stability unstable
12700 * @category schemas
12701 * @since 4.0.0
12702 */
12703export const Ipv6Network: Ipv6Network = declare(IpNetwork_.isIpv6Network, {
12704 identifier: "Ipv6Network"
12705})
12706
12707/**
12708 * Type-level representation of {@link Ipv6NetworkFromString}.
12709 *
12710 * @stability unstable
12711 * @category models
12712 * @since 4.0.0
12713 */
12714export interface Ipv6NetworkFromString extends decodeTo<Ipv6Network, String> {
12715 readonly "Rebuild": Ipv6NetworkFromString
12716}
12717
12718/**
12719 * Schema for canonical IPv6 network prefixes encoded in CIDR notation.
12720 *
12721 * @stability unstable
12722 * @category schemas
12723 * @since 4.0.0
12724 */
12725export const Ipv6NetworkFromString: Ipv6NetworkFromString = netAddressFromString(
12726 Ipv6Network,
12727 IpNetwork_.ipv6FromString,
12728 IpNetwork_.format,
12729 "Ipv6NetworkFromString"
12730)
12731
12732/**
12733 * Type-level representation of {@link IpNetwork}.
12734 *
12735 * @stability unstable
12736 * @category models
12737 * @since 4.0.0
12738 */
12739export interface IpNetwork extends declare<IpNetwork_.IpNetwork> {
12740 readonly "Rebuild": IpNetwork
12741}
12742
12743/**
12744 * Schema for already-constructed canonical IPv4 or IPv6 network prefixes.
12745 *
12746 * @stability unstable
12747 * @category schemas
12748 * @since 4.0.0
12749 */
12750export const IpNetwork: IpNetwork = declare(IpNetwork_.isIpNetwork, {
12751 identifier: "IpNetwork"
12752})
12753
12754/**
12755 * Type-level representation of {@link IpNetworkFromString}.
12756 *
12757 * @stability unstable
12758 * @category models
12759 * @since 4.0.0
12760 */
12761export interface IpNetworkFromString extends decodeTo<IpNetwork, String> {
12762 readonly "Rebuild": IpNetworkFromString
12763}
12764
12765/**
12766 * Schema for canonical IPv4 or IPv6 network prefixes encoded in CIDR notation.
12767 *
12768 * @stability unstable
12769 * @category schemas
12770 * @since 4.0.0
12771 */
12772export const IpNetworkFromString: IpNetworkFromString = netAddressFromString(
12773 IpNetwork,
12774 IpNetwork_.fromString,
12775 IpNetwork_.format,
12776 "IpNetworkFromString"
12777)
12778
12779/**
12780 * Type-level representation of {@link InetAddressV4}.
12781 *
12782 * @stability unstable
12783 * @category models
12784 * @since 4.0.0
12785 */
12786export interface InetAddressV4 extends declare<NetAddress_.InetAddressV4> {
12787 readonly "Rebuild": InetAddressV4
12788}
12789
12790/**
12791 * Schema for already-constructed resolved IPv4 internet addresses.
12792 *
12793 * @stability unstable
12794 * @category schemas
12795 * @since 4.0.0
12796 */
12797export const InetAddressV4: InetAddressV4 = declare(NetAddress_.isInetAddressV4, {
12798 identifier: "InetAddressV4"
12799})
12800
12801/**
12802 * Type-level representation of {@link InetAddressV6}.
12803 *
12804 * @stability unstable
12805 * @category models
12806 * @since 4.0.0
12807 */
12808export interface InetAddressV6 extends declare<NetAddress_.InetAddressV6> {
12809 readonly "Rebuild": InetAddressV6
12810}
12811
12812/**
12813 * Schema for already-constructed resolved IPv6 internet addresses.
12814 *
12815 * @stability unstable
12816 * @category schemas
12817 * @since 4.0.0
12818 */
12819export const InetAddressV6: InetAddressV6 = declare(NetAddress_.isInetAddressV6, {
12820 identifier: "InetAddressV6"
12821})
12822
12823/**
12824 * Type-level representation of {@link InetAddress}.
12825 *
12826 * @stability unstable
12827 * @category models
12828 * @since 4.0.0
12829 */
12830export interface InetAddress extends declare<NetAddress_.InetAddress> {
12831 readonly "Rebuild": InetAddress
12832}
12833
12834/**
12835 * Schema for already-constructed resolved internet addresses.
12836 *
12837 * @stability unstable
12838 * @category schemas
12839 * @since 4.0.0
12840 */
12841export const InetAddress: InetAddress = declare(NetAddress_.isInetAddress, {
12842 identifier: "InetAddress"
12843})
12844
12845/**
12846 * Type-level representation of {@link InetAddressFromString}.
12847 *
12848 * @stability unstable
12849 * @category models
12850 * @since 4.0.0
12851 */
12852export interface InetAddressFromString extends decodeTo<InetAddress, String> {
12853 readonly "Rebuild": InetAddressFromString
12854}
12855
12856/**
12857 * Schema for resolved internet addresses encoded as numeric socket strings.
12858 *
12859 * @stability unstable
12860 * @category schemas
12861 * @since 4.0.0
12862 */
12863export const InetAddressFromString: InetAddressFromString = netAddressFromString(
12864 InetAddress,
12865 NetAddress_.inetAddressFromString,
12866 NetAddress_.formatInet,
12867 "InetAddressFromString"
12868)
12869
12870/**
12871 * Type-level representation of {@link UnixPathAddress}.
12872 *
12873 * @stability unstable
12874 * @category models
12875 * @since 4.0.0
12876 */
12877export interface UnixPathAddress extends declare<NetAddress_.UnixPathAddress> {
12878 readonly "Rebuild": UnixPathAddress
12879}
12880
12881/**
12882 * Schema for already-constructed Unix-domain filesystem addresses.
12883 *
12884 * @stability unstable
12885 * @category schemas
12886 * @since 4.0.0
12887 */
12888export const UnixPathAddress: UnixPathAddress = declare(
12889 NetAddress_.isUnixPathAddress,
12890 { identifier: "UnixPathAddress" }
12891)
12892
12893/**
12894 * Type-level representation of {@link UnixPathAddressFromString}.
12895 *
12896 * @stability unstable
12897 * @category models
12898 * @since 4.0.0
12899 */
12900export interface UnixPathAddressFromString extends decodeTo<UnixPathAddress, String> {
12901 readonly "Rebuild": UnixPathAddressFromString
12902}
12903
12904/**
12905 * Schema for Unix-domain filesystem addresses encoded as opaque path strings.
12906 *
12907 * @stability unstable
12908 * @category schemas
12909 * @since 4.0.0
12910 */
12911export const UnixPathAddressFromString: UnixPathAddressFromString = String.pipe(decodeTo(
12912 UnixPathAddress,
12913 SchemaTransformation.transform({
12914 decode: NetAddress_.unixPathAddress,
12915 encode: (address) => address.path
12916 })
12917)).annotate({ identifier: "UnixPathAddressFromString" })
12918
12919/**
12920 * Type-level representation of {@link SocketAddress}.
12921 *
12922 * @stability unstable
12923 * @category models
12924 * @since 4.0.0
12925 */
12926export interface SocketAddress extends declare<NetAddress_.SocketAddress> {
12927 readonly "Rebuild": SocketAddress
12928}
12929
12930/**
12931 * Schema for already-constructed portable concrete socket addresses.
12932 *
12933 * @stability unstable
12934 * @category schemas
12935 * @since 4.0.0
12936 */
12937export const SocketAddress: SocketAddress = declare(NetAddress_.isSocketAddress, {
12938 identifier: "SocketAddress"
12939})
12940
12941// -----------------------------------------------------------------------------
12942// Duration schemas
12943// -----------------------------------------------------------------------------
12944
12945const durationFromString: SchemaTransformation.Transformation<Duration_.Duration, string> = SchemaTransformation
12946 .transformEffect<Duration_.Duration, string>({
12947 decode: (s, options) =>
12948 Option_.match(Duration_.fromInput(s as Duration_.Input), {
12949 onNone: () =>
12950 Effect.fail(
12951 new SchemaIssue.InvalidValue(
12952 { expected: "a valid Duration string" },
12953 s,
12954 options
12955 )
12956 ),
12957 onSome: Effect.succeed
12958 }),
12959 encode: (duration) => Effect.succeed(globalThis.String(duration))
12960 })
12961const durationFromNanos: SchemaTransformation.Transformation<Duration_.Duration, bigint> = SchemaTransformation
12962 .transformEffect({
12963 decode: (i) => Effect.succeed(Duration_.nanos(i)),
12964 encode: (a, options) =>
12965 Option_.match(Duration_.toNanos(a), {
12966 onNone: () =>
12967 Effect.fail(
12968 new SchemaIssue.InvalidValue(
12969 { expected: "a Duration representable as a bigint" },
12970 a,
12971 options
12972 )
12973 ),
12974 onSome: (nanos) => Effect.succeed(nanos)
12975 })
12976 })
12977const durationFromMillis: SchemaTransformation.Transformation<Duration_.Duration, number> = SchemaTransformation
12978 .transform({
12979 decode: (i) => Duration_.millis(i),
12980 encode: (a) => Duration_.toMillis(a)
12981 })
12982/**
12983 * Type-level representation of {@link Duration}.
12984 *
12985 * @category models
12986 * @since 3.10.0
12987 */
12988export interface Duration extends declare<Duration_.Duration> {
12989 readonly "Rebuild": Duration
12990}
12991/**
12992 * Schema for `Duration` values.
12993 *
12994 * **Details**
12995 *
12996 * The default JSON serializer encodes `Duration` as a tagged object with the
12997 * duration type and value.
12998 *
12999 * **Example** (Defining a Duration schema)
13000 *
13001 * ```ts import.meta.vitest
13002 * import { Duration, Schema } from "effect"
13003 *
13004 * Schema.decodeUnknownSync(Schema.Duration)(Duration.seconds(5)) // => Duration.seconds(5)
13005 * ```
13006 *
13007 * @category schemas
13008 *
13009 * @since 3.10.0
13010 */
13011export const Duration: Duration = declare(
13012 Duration_.isDuration,
13013 {
13014 representation: {
13015 id: "effect/schema/Duration",
13016 payload: null
13017 },
13018 toCode: () => ({
13019 runtime: `Schema.Duration`,
13020 Type: `Duration.Duration`,
13021 importDeclarations: [`import * as Duration from "effect/Duration"`]
13022 }),
13023 expected: "Duration",
13024 toCodecJson: () =>
13025 link<Duration_.Duration>()(
13026 Union([
13027 Struct({ _tag: Literal("Infinity") }),
13028 Struct({ _tag: Literal("NegativeInfinity") }),
13029 Struct({ _tag: Literal("Nanos"), value: BigInt }),
13030 Struct({ _tag: Literal("Millis"), value: Int })
13031 ]),
13032 SchemaTransformation.transform({
13033 decode: (e) => {
13034 switch (e._tag) {
13035 case "Infinity":
13036 return Duration_.infinity
13037 case "NegativeInfinity":
13038 return Duration_.negativeInfinity
13039 case "Nanos":
13040 return Duration_.nanos(e.value)
13041 case "Millis":
13042 return Duration_.millis(e.value)
13043 }
13044 },
13045 encode: (duration) => {
13046 switch (duration.value._tag) {
13047 case "Infinity":
13048 return { _tag: "Infinity" } as const
13049 case "NegativeInfinity":
13050 return { _tag: "NegativeInfinity" } as const
13051 case "Nanos":
13052 return { _tag: "Nanos", value: duration.value.nanos } as const
13053 case "Millis":
13054 return { _tag: "Millis", value: duration.value.millis } as const
13055 }
13056 }
13057 })
13058 )
13059 }
13060)
13061const DurationString = String.annotate({ expected: "a string that will be decoded as a Duration" })
13062/**
13063 * Type-level representation of {@link DurationFromString}.
13064 *
13065 * @category models
13066 * @since 4.0.0
13067 */
13068export interface DurationFromString extends decodeTo<Duration, String> {
13069 readonly "Rebuild": DurationFromString
13070}
13071/**
13072 * Schema that parses a string into a `Duration`.
13073 *
13074 * **Details**
13075 *
13076 * Decoding:
13077 * - A `string` is decoded as a `Duration`, accepting any format that
13078 * `Duration.fromInput` can parse.
13079 *
13080 * Encoding:
13081 * - A `Duration` is encoded as a parseable `string`.
13082 *
13083 * @category schemas
13084 * @since 4.0.0
13085 */
13086export const DurationFromString: DurationFromString = DurationString.pipe(
13087 decodeTo(Duration, durationFromString)
13088)
13089/**
13090 * Type-level representation of {@link DurationFromNanos}.
13091 *
13092 * @category models
13093 * @since 3.10.0
13094 */
13095export interface DurationFromNanos extends decodeTo<Duration, BigInt> {
13096 readonly "Rebuild": DurationFromNanos
13097}
13098/**
13099 * Schema that decodes a `bigint` into a `Duration`, treating the bigint as
13100 * nanoseconds.
13101 *
13102 * **Details**
13103 *
13104 * Decoding:
13105 * A `bigint` representing nanoseconds is decoded as a `Duration`.
13106 *
13107 * Encoding:
13108 * Finite durations are encoded as a `bigint` number of nanoseconds. Encoding
13109 * fails when the duration cannot be represented as nanoseconds, such as
13110 * `Duration.infinity` or `Duration.negativeInfinity`.
13111 *
13112 * @category schemas
13113 * @since 3.10.0
13114 */
13115export const DurationFromNanos: DurationFromNanos = BigInt.pipe(
13116 decodeTo(Duration, durationFromNanos)
13117)
13118/**
13119 * Type-level representation of {@link DurationFromMillis}.
13120 *
13121 * @category models
13122 * @since 3.10.0
13123 */
13124export interface DurationFromMillis extends decodeTo<Duration, Number> {
13125 readonly "Rebuild": DurationFromMillis
13126}
13127/**
13128 * Schema that decodes a number into a `Duration`, treating the number as
13129 * milliseconds.
13130 *
13131 * **Details**
13132 *
13133 * Decoding:
13134 * - A finite or infinite number is decoded as a `Duration`
13135 *
13136 * Encoding:
13137 * - A `Duration` is encoded to a finite or infinite number of milliseconds
13138 *
13139 * **Gotchas**
13140 *
13141 * `NaN` is decoded as `Duration.zero`, matching `Duration.millis`.
13142 *
13143 * @category schemas
13144 * @since 3.10.0
13145 */
13146export const DurationFromMillis: DurationFromMillis = Number.pipe(
13147 decodeTo(Duration, durationFromMillis)
13148)
13149
13150// -----------------------------------------------------------------------------
13151// Exit schemas
13152// -----------------------------------------------------------------------------
13153
13154/**
13155 * Type-level representation returned by {@link Exit}.
13156 *
13157 * @category models
13158 * @since 3.10.0
13159 */
13160export interface Exit<A extends Constraint, E extends Constraint, D extends Constraint> extends
13161 declareConstructor<
13162 Exit_.Exit<A["Type"], E["Type"]>,
13163 Exit_.Exit<A["Encoded"], E["Encoded"]>,
13164 readonly [A, E, D],
13165 ExitIso<A, E, D>
13166 >
13167{
13168 readonly "Rebuild": Exit<A, E, D>
13169 readonly value: A
13170 readonly error: E
13171 readonly defect: D
13172}
13173/**
13174 * Iso representation used for `Exit` schemas.
13175 *
13176 * **Details**
13177 *
13178 * Successful exits are represented as `{ _tag: "Success", value }`, while failed
13179 * exits are represented as `{ _tag: "Failure", cause }`.
13180 *
13181 * @category utility types
13182 * @since 4.0.0
13183 */
13184export type ExitIso<A extends Constraint, E extends Constraint, D extends Constraint> = {
13185 readonly _tag: "Success"
13186 readonly value: A["Iso"]
13187} | {
13188 readonly _tag: "Failure"
13189 readonly cause: CauseIso<E, D>
13190}
13191/**
13192 * Creates a schema for `Exit` values using schemas for the success value, typed
13193 * failure, and unexpected defect channels.
13194 *
13195 * **When to use**
13196 *
13197 * Use when serializing or validating an effect outcome where success, typed
13198 * failure, and defects each need their own schema.
13199 *
13200 * @category schemas
13201 * @since 3.10.0
13202 */
13203export function Exit<
13204 A extends Constraint,
13205 E extends Constraint,
13206 D extends Constraint
13207>(
13208 value: A,
13209 error: E,
13210 defect: D
13211): Exit<A, E, D> {
13212 const schema = declareConstructor<
13213 Exit_.Exit<A["Type"], E["Type"]>,
13214 Exit_.Exit<A["Encoded"], E["Encoded"]>,
13215 ExitIso<A, E, D>
13216 >()(
13217 [value, error, defect],
13218 ([value, error, defect]) => {
13219 const cause = Cause(error, defect)
13220 return (input, ast, options) => {
13221 if (!Exit_.isExit(input)) {
13222 return Effect.fail(new SchemaIssue.InvalidType(ast, input, options))
13223 }
13224 switch (input._tag) {
13225 case "Success":
13226 return Effect.mapBothEager(
13227 SchemaParser.decodeUnknownEffect(value)(input.value, options),
13228 {
13229 onSuccess: Exit_.succeed,
13230 onFailure: (issue) => SchemaIssue.makeCompositeAtKey(ast, "value", issue, input, options)
13231 }
13232 )
13233 case "Failure":
13234 return Effect.mapBothEager(
13235 SchemaParser.decodeUnknownEffect(cause)(input.cause, options),
13236 {
13237 onSuccess: Exit_.failCause,
13238 onFailure: (issue) => SchemaIssue.makeCompositeAtKey(ast, "cause", issue, input, options)
13239 }
13240 )
13241 }
13242 }
13243 },
13244 {
13245 representation: {
13246 id: "effect/schema/Exit",
13247 payload: null
13248 },
13249 toCode: ({ typeParameters }) => ({
13250 runtime: `Schema.Exit(${typeParameters[0].runtime}, ${typeParameters[1].runtime}, ${
13251 typeParameters[2].runtime
13252 })`,
13253 Type: `Exit.Exit<${typeParameters[0].Type}, ${typeParameters[1].Type}, ${typeParameters[2].Type}>`,
13254 importDeclarations: [`import * as Exit from "effect/Exit"`]
13255 }),
13256 expected: "Exit",
13257 toCodec: ([value, error, defect]) =>
13258 link<Exit_.Exit<A["Encoded"], E["Encoded"]>>()(
13259 Union([
13260 Struct({ _tag: Literal("Success"), value }),
13261 Struct({
13262 _tag: Literal("Failure"),
13263 cause: Cause(error, defect)
13264 })
13265 ]),
13266 SchemaTransformation.transform({
13267 decode: (e): Exit_.Exit<A["Encoded"], E["Encoded"]> =>
13268 e._tag === "Success" ? Exit_.succeed(e.value) : Exit_.failCause(e.cause),
13269 encode: (exit) =>
13270 Exit_.isSuccess(exit)
13271 ? { _tag: "Success", value: exit.value } as const
13272 : { _tag: "Failure", cause: exit.cause } as const
13273 })
13274 )
13275 }
13276 )
13277 return make(schema.ast, { value, error, defect })
13278}
13279
13280// -----------------------------------------------------------------------------
13281// Graph schemas
13282// -----------------------------------------------------------------------------
13283
13284/**
13285 * Encoded representation of an immutable Effect graph.
13286 *
13287 * @category models
13288 * @since 4.0.0
13289 */
13290export type EncodedGraph<N, E, T extends Graph_.Kind> = Graph_.Snapshot<N, E, T>
13291/**
13292 * Iso representation used for {@link Graph} schemas.
13293 *
13294 * @category utility types
13295 * @since 4.0.0
13296 */
13297export type GraphIso<T extends Graph_.Kind, Node extends Constraint, Edge extends Constraint> = EncodedGraph<
13298 Node["Iso"],
13299 Edge["Iso"],
13300 T
13301>
13302/**
13303 * Type-level representation returned by {@link Graph}.
13304 *
13305 * @category models
13306 * @since 4.0.0
13307 */
13308export interface Graph<T extends Graph_.Kind, Node extends Constraint, Edge extends Constraint>
13309 extends
13310 declareConstructor<
13311 Graph_.Graph<Node["Type"], Edge["Type"], T>,
13312 Graph_.Graph<Node["Encoded"], Edge["Encoded"], T>,
13313 readonly [Node, Edge],
13314 GraphIso<T, Node, Edge>
13315 >
13316{
13317 readonly "Rebuild": Graph<T, Node, Edge>
13318 readonly type: T
13319 readonly node: Node
13320 readonly edge: Edge
13321}
13322function graphEncodedSchema<T extends Graph_.Kind, Node extends Constraint, Edge extends Constraint>(
13323 type: T,
13324 node: Node,
13325 edge: Edge
13326) {
13327 return Struct({
13328 type: Literal(type),
13329 nodes: ArraySchema(Struct({ index: Natural, data: node })),
13330 edges: ArraySchema(Struct({ index: Natural, source: Natural, target: Natural, data: edge }))
13331 })
13332}
13333function graphDecode<N, E, T extends Graph_.Kind>(
13334 input: EncodedGraph<N, E, T>,
13335 options: SchemaAST.ParseOptions
13336): Effect.Effect<Graph_.Graph<N, E, T>, SchemaIssue.Issue> {
13337 let previous = -1
13338 const indexes = new Set<Graph_.NodeIndex>()
13339 for (let i = 0; i < input.nodes.length; i++) {
13340 const index = input.nodes[i].index
13341 if (index <= previous) {
13342 return Effect.fail(
13343 new SchemaIssue.Pointer(
13344 ["nodes", i, "index"],
13345 new SchemaIssue.InvalidValue({ expected: "a strictly increasing node index" }, index, options)
13346 )
13347 )
13348 }
13349 previous = index
13350 indexes.add(index)
13351 }
13352
13353 previous = -1
13354 for (let i = 0; i < input.edges.length; i++) {
13355 const edge = input.edges[i]
13356 if (edge.index <= previous) {
13357 return Effect.fail(
13358 new SchemaIssue.Pointer(
13359 ["edges", i, "index"],
13360 new SchemaIssue.InvalidValue({ expected: "a strictly increasing edge index" }, edge.index, options)
13361 )
13362 )
13363 }
13364 previous = edge.index
13365 if (!indexes.has(edge.source)) {
13366 return Effect.fail(
13367 new SchemaIssue.Pointer(
13368 ["edges", i, "source"],
13369 new SchemaIssue.InvalidValue({ expected: "an encoded node index" }, edge.source, options)
13370 )
13371 )
13372 }
13373 if (!indexes.has(edge.target)) {
13374 return Effect.fail(
13375 new SchemaIssue.Pointer(
13376 ["edges", i, "target"],
13377 new SchemaIssue.InvalidValue({ expected: "an encoded node index" }, edge.target, options)
13378 )
13379 )
13380 }
13381 }
13382
13383 return Effect.succeed(InternalGraph.hydrate(input))
13384}
13385function graphEncode<N, E, T extends Graph_.Kind>(
13386 input: Graph_.Graph<N, E, T>,
13387 type: T,
13388 options: SchemaAST.ParseOptions
13389): Effect.Effect<EncodedGraph<N, E, T>, SchemaIssue.Issue> {
13390 if (!InternalGraph.isGraph(input) || input.mutable || input.type !== type) {
13391 return Effect.fail(new SchemaIssue.InvalidValue({ expected: `an immutable ${type} Graph` }, input, options))
13392 }
13393 return Effect.succeed(InternalGraph.snapshot(input))
13394}
13395function graphToEquivalence<N, E, T extends Graph_.Kind>(
13396 node: Equivalence.Equivalence<N>,
13397 edge: Equivalence.Equivalence<E>
13398) {
13399 return (self: Graph_.Graph<N, E, T>, that: Graph_.Graph<N, E, T>): boolean => {
13400 const a = InternalGraph.snapshot(self)
13401 const b = InternalGraph.snapshot(that)
13402 if (a.type !== b.type || a.nodes.length !== b.nodes.length || a.edges.length !== b.edges.length) return false
13403 for (let i = 0; i < a.nodes.length; i++) {
13404 if (a.nodes[i].index !== b.nodes[i].index || !node(a.nodes[i].data, b.nodes[i].data)) return false
13405 }
13406 for (let i = 0; i < a.edges.length; i++) {
13407 const ae = a.edges[i]
13408 const be = b.edges[i]
13409 const sameEndpoints = a.type === "directed"
13410 ? ae.source === be.source && ae.target === be.target
13411 : (ae.source === be.source && ae.target === be.target) ||
13412 (ae.source === be.target && ae.target === be.source)
13413 if (
13414 ae.index !== be.index || !sameEndpoints || !edge(ae.data, be.data)
13415 ) return false
13416 }
13417 return true
13418 }
13419}
13420type GraphArbitraryRepresentation<N, E> = null | {
13421 readonly nodes: readonly [N, ...Array<N>]
13422 readonly edges: ReadonlyArray<readonly [source: number, target: number, data: E]>
13423}
13424function graphToArbitrary<N, E, T extends Graph_.Kind>(
13425 type: T,
13426 node: Codec<N>,
13427 edge: Codec<E>
13428) {
13429 return linkDecoding<Graph_.Graph<N, E, T>>()(
13430 Union([
13431 Null,
13432 Struct({
13433 nodes: NonEmptyArray(node),
13434 edges: ArraySchema(Tuple([Natural, Natural, edge]))
13435 })
13436 ]),
13437 SchemaGetter.transform<Graph_.Graph<N, E, T>, GraphArbitraryRepresentation<N, E>>((input) => {
13438 if (input === null) return InternalGraph.hydrate({ type, nodes: [], edges: [] })
13439 const nodes = input.nodes.map((data, index) => ({ index, data }))
13440 return InternalGraph.hydrate({
13441 type,
13442 nodes,
13443 edges: input.edges.map(([source, target, data], index) => ({
13444 index,
13445 source: source % nodes.length,
13446 target: target % nodes.length,
13447 data
13448 }))
13449 })
13450 })
13451 )
13452}
13453/**
13454 * Creates a schema for immutable directed or undirected Effect graphs.
13455 *
13456 * **Details**
13457 *
13458 * Encoding preserves active node and edge indexes, payloads, endpoints,
13459 * isolated nodes, self-loops, parallel edges, and stored edge orientation. It
13460 * does not encode removed-ID allocator history; after decoding, future allocation starts
13461 * after the highest active decoded index. Encoding rejects mutable graphs.
13462 * `Graph.toJSON()` remains an inspection summary and is not this wire format.
13463 *
13464 * **Example** (Encoding a directed graph as JSON)
13465 *
13466 * ```ts import.meta.vitest
13467 * import { Graph, Schema } from "effect"
13468 *
13469 * const codec = Schema.toCodecJson(Schema.Graph("directed", Schema.String, Schema.Number))
13470 * const graph = Graph.directed<string, number>((mutable) => {
13471 * const source = Graph.addNode(mutable, "A")
13472 * const target = Graph.addNode(mutable, "B")
13473 * Graph.addEdge(mutable, source, target, 1)
13474 * })
13475 *
13476 * const encoded = Schema.encodeSync(codec)(graph)
13477 *
13478 * encoded.type // => "directed"
13479 * encoded.nodes // => [{ index: 0, data: "A" }, { index: 1, data: "B" }]
13480 * encoded.edges // => [{ index: 0, source: 0, target: 1, data: 1 }]
13481 * ```
13482 *
13483 * @category schemas
13484 * @since 4.0.0
13485 */
13486export function Graph<Node extends Constraint, Edge extends Constraint>(
13487 type: "directed",
13488 node: Node,
13489 edge: Edge
13490): Graph<"directed", Node, Edge>
13491export function Graph<Node extends Constraint, Edge extends Constraint>(
13492 type: "undirected",
13493 node: Node,
13494 edge: Edge
13495): Graph<"undirected", Node, Edge>
13496export function Graph<T extends Graph_.Kind, Node extends Constraint, Edge extends Constraint>(
13497 type: T,
13498 node: Node,
13499 edge: Edge
13500): Graph<T, Node, Edge>
13501export function Graph<T extends Graph_.Kind, Node extends Constraint, Edge extends Constraint>(
13502 type: T,
13503 node: Node,
13504 edge: Edge
13505): Graph<T, Node, Edge> {
13506 const schema = declareConstructor<
13507 Graph_.Graph<Node["Type"], Edge["Type"], T>,
13508 Graph_.Graph<Node["Encoded"], Edge["Encoded"], T>,
13509 GraphIso<T, Node, Edge>
13510 >()(
13511 [node, edge],
13512 ([node, edge]) => {
13513 const encoded = graphEncodedSchema(type, node, edge)
13514 return (input, ast, options) => {
13515 if (!InternalGraph.isGraph(input) || input.mutable || input.type !== type) {
13516 return Effect.fail(new SchemaIssue.InvalidType(ast, input, options))
13517 }
13518 return Effect.flatMap(
13519 SchemaParser.decodeUnknownEffect(encoded)(InternalGraph.snapshot(input), options),
13520 (snapshot) => graphDecode(snapshot, options)
13521 )
13522 }
13523 },
13524 {
13525 representation: {
13526 id: "effect/schema/Graph",
13527 payload: type
13528 },
13529 toCode: ({ typeParameters }) => ({
13530 runtime: `Schema.Graph(${format(type)}, ${typeParameters[0].runtime}, ${typeParameters[1].runtime})`,
13531 Type: `Graph.Graph<${typeParameters[0].Type}, ${typeParameters[1].Type}, ${format(type)}>`,
13532 importDeclarations: [`import * as Graph from "effect/Graph"`]
13533 }),
13534 expected: `an immutable ${type} Graph`,
13535 toCodec: ([node, edge]) =>
13536 link<Graph_.Graph<Node["Encoded"], Edge["Encoded"], T>>()(
13537 graphEncodedSchema(type, node, edge),
13538 SchemaTransformation.transformEffect({
13539 decode: graphDecode,
13540 encode: (graph, options) => graphEncode(graph, type, options)
13541 })
13542 ),
13543 toCodecArbitrary: ({ typeParameters: [node, edge] }) => graphToArbitrary(type, node, edge),
13544 toEquivalence: ([node, edge]) => graphToEquivalence(node, edge)
13545 }
13546 )
13547 return make(schema.ast, { type, node, edge })
13548}
13549
13550// -----------------------------------------------------------------------------
13551// HashMap schemas
13552// -----------------------------------------------------------------------------
13553
13554function hashMapLink<Key, Value>(entries: Schema<ReadonlyArray<readonly [Key, Value]>>) {
13555 return link<HashMap_.HashMap<Key, Value>>()(
13556 entries,
13557 SchemaTransformation.transform({
13558 decode: HashMap_.fromIterable,
13559 encode: HashMap_.toEntries
13560 })
13561 )
13562}
13563/**
13564 * Type-level representation returned by {@link HashMap}.
13565 *
13566 * @category models
13567 * @since 3.10.0
13568 */
13569export interface HashMap<Key extends Constraint, Value extends Constraint> extends
13570 declareConstructor<
13571 HashMap_.HashMap<Key["Type"], Value["Type"]>,
13572 HashMap_.HashMap<Key["Encoded"], Value["Encoded"]>,
13573 readonly [Key, Value],
13574 HashMapIso<Key, Value>
13575 >
13576{
13577 readonly "Rebuild": HashMap<Key, Value>
13578 readonly key: Key
13579 readonly value: Value
13580}
13581/**
13582 * Iso representation used for `HashMap` schemas: an array of readonly
13583 * `[key, value]` tuples using each entry schema's `Iso` type.
13584 *
13585 * @category utility types
13586 * @since 4.0.0
13587 */
13588export type HashMapIso<Key extends Constraint, Value extends Constraint> = ReadonlyArray<
13589 readonly [Key["Iso"], Value["Iso"]]
13590>
13591/**
13592 * Schema for hash maps whose keys and values conform to the provided schemas.
13593 *
13594 * @category schemas
13595 * @since 3.10.0
13596 */
13597export function HashMap<Key extends Constraint, Value extends Constraint>(key: Key, value: Value): HashMap<Key, Value> {
13598 const schema = declareConstructor<
13599 HashMap_.HashMap<Key["Type"], Value["Type"]>,
13600 HashMap_.HashMap<Key["Encoded"], Value["Encoded"]>,
13601 HashMapIso<Key, Value>
13602 >()(
13603 [key, value],
13604 ([key, value]) => {
13605 const entries = ArraySchema(Tuple([key, value]))
13606 return (input, ast, options) => {
13607 if (HashMap_.isHashMap(input)) {
13608 return Effect.mapBothEager(
13609 SchemaParser.decodeUnknownEffect(entries)(HashMap_.toEntries(input), options),
13610 {
13611 onSuccess: HashMap_.fromIterable,
13612 onFailure: (issue) => SchemaIssue.makeCompositeAtKey(ast, "entries", issue, input, options)
13613 }
13614 )
13615 }
13616 return Effect.fail(new SchemaIssue.InvalidType(ast, input, options))
13617 }
13618 },
13619 {
13620 representation: {
13621 id: "effect/schema/HashMap",
13622 payload: null
13623 },
13624 toCode: ({ typeParameters }) => ({
13625 runtime: `Schema.HashMap(${typeParameters[0].runtime}, ${typeParameters[1].runtime})`,
13626 Type: `HashMap.HashMap<${typeParameters[0].Type}, ${typeParameters[1].Type}>`,
13627 importDeclarations: [`import * as HashMap from "effect/HashMap"`]
13628 }),
13629 expected: "HashMap",
13630 toCodec: ([key, value]) => hashMapLink(ArraySchema(Tuple([key, value]))),
13631 toCodecArbitrary: ({ constraint, typeParameters: [key, value] }) =>
13632 hashMapLink(
13633 withArrayLengthConstraints(
13634 ArraySchema(Tuple([key, value])).check(isUniqueKey()),
13635 constraint?.minSize,
13636 constraint?.maxSize
13637 )
13638 ),
13639 toEquivalence: ([key, value]) => Equal.makeCompareMap(key, value)
13640 }
13641 )
13642 return make(schema.ast, { key, value })
13643}
13644
13645// -----------------------------------------------------------------------------
13646// HashSet schemas
13647// -----------------------------------------------------------------------------
13648
13649function hashSetLink<Value>(values: Schema<ReadonlyArray<Value>>) {
13650 return link<HashSet_.HashSet<Value>>()(
13651 values,
13652 SchemaTransformation.transform({
13653 decode: HashSet_.fromIterable,
13654 encode: Arr.fromIterable
13655 })
13656 )
13657}
13658/**
13659 * Type-level representation returned by {@link HashSet}.
13660 *
13661 * @category models
13662 * @since 3.10.0
13663 */
13664export interface HashSet<Value extends Constraint> extends
13665 declareConstructor<
13666 HashSet_.HashSet<Value["Type"]>,
13667 HashSet_.HashSet<Value["Encoded"]>,
13668 readonly [Value],
13669 HashSetIso<Value>
13670 >
13671{
13672 readonly "Rebuild": HashSet<Value>
13673 readonly value: Value
13674}
13675/**
13676 * Iso representation used for `HashSet` schemas: an array of element values
13677 * using the element schema's `Iso` type.
13678 *
13679 * @category utility types
13680 * @since 4.0.0
13681 */
13682export type HashSetIso<Value extends Constraint> = ReadonlyArray<Value["Iso"]>
13683/**
13684 * Schema for hash sets whose values conform to the provided element schema.
13685 *
13686 * @category schemas
13687 * @since 3.10.0
13688 */
13689export function HashSet<Value extends Constraint>(value: Value): HashSet<Value> {
13690 const schema = declareConstructor<
13691 HashSet_.HashSet<Value["Type"]>,
13692 HashSet_.HashSet<Value["Encoded"]>,
13693 HashSetIso<Value>
13694 >()(
13695 [value],
13696 ([value]) => {
13697 const values = ArraySchema(value)
13698 return (input, ast, options) => {
13699 if (HashSet_.isHashSet(input)) {
13700 return Effect.mapBothEager(
13701 SchemaParser.decodeUnknownEffect(values)(Arr.fromIterable(input), options),
13702 {
13703 onSuccess: HashSet_.fromIterable,
13704 onFailure: (issue) => SchemaIssue.makeCompositeAtKey(ast, "values", issue, input, options)
13705 }
13706 )
13707 }
13708 return Effect.fail(new SchemaIssue.InvalidType(ast, input, options))
13709 }
13710 },
13711 {
13712 representation: {
13713 id: "effect/schema/HashSet",
13714 payload: null
13715 },
13716 toCode: ({ typeParameters }) => ({
13717 runtime: `Schema.HashSet(${typeParameters[0].runtime})`,
13718 Type: `HashSet.HashSet<${typeParameters[0].Type}>`
13719 }),
13720 expected: "HashSet",
13721 toCodec: ([value]) => hashSetLink(ArraySchema(value)),
13722 toCodecArbitrary: ({ constraint, typeParameters: [value] }) =>
13723 hashSetLink(
13724 withArrayLengthConstraints(
13725 ArraySchema(value).check(isUnique()),
13726 constraint?.minSize,
13727 constraint?.maxSize
13728 )
13729 ),
13730 toEquivalence: ([value]) => Equal.makeCompareSet(value)
13731 }
13732 )
13733 return make(schema.ast, { value })
13734}
13735
13736// -----------------------------------------------------------------------------
13737// Option schemas
13738// -----------------------------------------------------------------------------
13739
13740/**
13741 * Type-level representation returned by {@link Option}.
13742 *
13743 * @category models
13744 * @since 3.10.0
13745 */
13746export interface Option<A extends Constraint> extends
13747 declareConstructor<
13748 Option_.Option<A["Type"]>,
13749 Option_.Option<A["Encoded"]>,
13750 readonly [A],
13751 OptionIso<A>
13752 >
13753{
13754 readonly "Rebuild": Option<A>
13755 readonly value: A
13756}
13757/**
13758 * Iso representation used for `Option` schemas.
13759 *
13760 * **Details**
13761 *
13762 * `None` is represented as `{ _tag: "None" }`, while `Some` is represented as
13763 * `{ _tag: "Some", value }` using the wrapped schema's `Iso` type.
13764 *
13765 * @category utility types
13766 * @since 4.0.0
13767 */
13768export type OptionIso<A extends Constraint> = {
13769 readonly _tag: "None"
13770} | {
13771 readonly _tag: "Some"
13772 readonly value: A["Iso"]
13773}
13774/**
13775 * Schema for `Option<A>` values.
13776 *
13777 * @category schemas
13778 * @since 3.10.0
13779 */
13780export function Option<A extends Constraint>(value: A): Option<A> {
13781 const schema = declareConstructor<
13782 Option_.Option<A["Type"]>,
13783 Option_.Option<A["Encoded"]>,
13784 OptionIso<A>
13785 >()(
13786 [value],
13787 ([value]) => (input, ast, options) => {
13788 if (Option_.isOption(input)) {
13789 if (Option_.isNone(input)) {
13790 return Effect.succeedNone
13791 }
13792 return Effect.mapBothEager(
13793 SchemaParser.decodeUnknownEffect(value)(input.value, options),
13794 {
13795 onSuccess: Option_.some,
13796 onFailure: (issue) => SchemaIssue.makeCompositeAtKey(ast, "value", issue, input, options)
13797 }
13798 )
13799 }
13800 return Effect.fail(new SchemaIssue.InvalidType(ast, input, options))
13801 },
13802 {
13803 representation: {
13804 id: "effect/schema/Option",
13805 payload: null
13806 },
13807 toCode: ({ typeParameters }) => ({
13808 runtime: `Schema.Option(${typeParameters[0].runtime})`,
13809 Type: `Option.Option<${typeParameters[0].Type}>`,
13810 importDeclarations: [`import * as Option from "effect/Option"`]
13811 }),
13812 expected: "Option",
13813 toCodec: ([value]) =>
13814 link<Option_.Option<A["Encoded"]>>()(
13815 Union([
13816 Struct({ _tag: Literal("Some"), value }),
13817 Struct({ _tag: Literal("None") })
13818 ]),
13819 SchemaTransformation.transform({
13820 decode: (e) => e._tag === "None" ? Option_.none() : Option_.some(e.value),
13821 encode: (o) => (Option_.isSome(o) ? { _tag: "Some", value: o.value } as const : { _tag: "None" } as const)
13822 })
13823 )
13824 }
13825 )
13826 return make(schema.ast, { value })
13827}
13828/**
13829 * Type-level representation returned by {@link OptionFromNullOr}.
13830 *
13831 * @category models
13832 * @since 3.10.0
13833 */
13834export interface OptionFromNullOr<S extends Constraint> extends decodeTo<Option<toType<S>>, NullOr<S>> {
13835 readonly "Rebuild": OptionFromNullOr<S>
13836}
13837/**
13838 * Decodes a nullable, required value `T` to a required `Option<T>` value.
13839 *
13840 * **Details**
13841 *
13842 * Decoding maps `null` to `None` and all other values to `Some`. Encoding maps
13843 * `None` to `null` and maps `Some` to its value.
13844 *
13845 * @category schemas
13846 * @since 3.10.0
13847 */
13848export function OptionFromNullOr<S extends Constraint>(schema: S): OptionFromNullOr<S> {
13849 return NullOr(schema).pipe(decodeTo(
13850 Option(toType(schema)),
13851 SchemaTransformation.optionFromNullOr()
13852 ))
13853}
13854/**
13855 * Type-level representation returned by {@link OptionFromUndefinedOr}.
13856 *
13857 * @category models
13858 * @since 3.10.0
13859 */
13860export interface OptionFromUndefinedOr<S extends Constraint> extends decodeTo<Option<toType<S>>, UndefinedOr<S>> {
13861 readonly "Rebuild": OptionFromUndefinedOr<S>
13862}
13863/**
13864 * Decodes a required value that may be `undefined` to a required `Option<T>`
13865 * value.
13866 *
13867 * **Details**
13868 *
13869 * Decoding maps `undefined` to `None` and all other values to `Some`. Encoding
13870 * maps `None` to `undefined` and maps `Some` to its value.
13871 *
13872 * @category schemas
13873 * @since 3.10.0
13874 */
13875export function OptionFromUndefinedOr<S extends Constraint>(schema: S): OptionFromUndefinedOr<S> {
13876 return UndefinedOr(schema).pipe(decodeTo(
13877 Option(toType(schema)),
13878 SchemaTransformation.optionFromUndefinedOr()
13879 ))
13880}
13881/**
13882 * Type-level representation returned by {@link OptionFromNullishOr}.
13883 *
13884 * @category models
13885 * @since 3.10.0
13886 */
13887export interface OptionFromNullishOr<S extends Constraint> extends decodeTo<Option<toType<S>>, NullishOr<S>> {
13888 readonly "Rebuild": OptionFromNullishOr<S>
13889}
13890/**
13891 * Decodes a nullish value `T` to a required `Option<T>` value.
13892 *
13893 * **Details**
13894 *
13895 * Decoding maps `null` and `undefined` to `None` and all other values to
13896 * `Some`. Encoding maps `None` to `null` or `undefined` depending on
13897 * `options.onNoneEncoding`, which defaults to `undefined`, and maps `Some` to
13898 * its value.
13899 *
13900 * @category schemas
13901 * @since 3.10.0
13902 */
13903export function OptionFromNullishOr<S extends Constraint>(
13904 schema: S,
13905 options?: {
13906 onNoneEncoding: null | undefined
13907 }
13908): OptionFromNullishOr<S> {
13909 return NullishOr(schema).pipe(decodeTo(
13910 Option(toType(schema)),
13911 SchemaTransformation.optionFromNullishOr(options)
13912 ))
13913}
13914
13915/**
13916 * Type-level representation of {@link Cookie}.
13917 *
13918 * @stability unstable
13919 * @category models
13920 * @since 4.0.0
13921 */
13922export interface Cookie extends declare<Cookies_.Cookie> {
13923 readonly "Rebuild": Cookie
13924}
13925
13926/**
13927 * Schema for HTTP cookie values.
13928 *
13929 * @stability unstable
13930 * @category schemas
13931 * @since 4.0.0
13932 */
13933export const Cookie: Cookie = declare(
13934 Cookies_.isCookie,
13935 {
13936 representation: {
13937 id: "effect/http/Cookie",
13938 payload: null
13939 },
13940 toCode: () => ({
13941 runtime: "Schema.Cookie",
13942 Type: "Cookies.Cookie",
13943 importDeclarations: [`import * as Cookies from "effect/http/Cookies"`]
13944 }),
13945 expected: "Cookie"
13946 }
13947)
13948
13949/**
13950 * Type-level representation of {@link Cookies}.
13951 *
13952 * @stability unstable
13953 * @category models
13954 * @since 4.0.0
13955 */
13956export interface Cookies extends
13957 declare<
13958 Cookies_.Cookies,
13959 Record_.ReadonlyRecord<string, Cookies_.Cookie>
13960 >
13961{
13962 readonly "Rebuild": Cookies
13963}
13964
13965/**
13966 * Schema for HTTP cookie collections.
13967 *
13968 * **Details**
13969 *
13970 * JSON encoding uses `Set-Cookie` header strings, while isomorphic encoding uses
13971 * a readonly record of cookie values.
13972 *
13973 * @stability unstable
13974 * @category schemas
13975 * @since 4.0.0
13976 */
13977export const Cookies: Cookies = declare(
13978 Cookies_.isCookies,
13979 {
13980 representation: {
13981 id: "effect/http/Cookies",
13982 payload: null
13983 },
13984 toCode: () => ({
13985 runtime: "Schema.Cookies",
13986 Type: "Cookies.Cookies",
13987 importDeclarations: [`import * as Cookies from "effect/http/Cookies"`]
13988 }),
13989 expected: "Cookies",
13990 toCodecJson: () =>
13991 link<Cookies_.Cookies>()(
13992 ArraySchema(String),
13993 SchemaTransformation.transform<Cookies_.Cookies, ReadonlyArray<string>>({
13994 decode: Cookies_.fromSetCookie,
13995 encode: Cookies_.toSetCookieHeaders
13996 })
13997 ),
13998 toCodecIso: () =>
13999 link<Cookies_.Cookies>()(
14000 Record(String, Cookie),
14001 SchemaTransformation.transform({
14002 decode: Cookies_.fromReadonlyRecord,
14003 encode: (cookies) => cookies.cookies
14004 })
14005 )
14006 }
14007)
14008
14009/**
14010 * Type-level representation of {@link RecordFromCookies}.
14011 *
14012 * @stability unstable
14013 * @category models
14014 * @since 4.0.0
14015 */
14016export interface RecordFromCookies extends decodeTo<$Record<String, String>, Cookies> {
14017 readonly "Rebuild": RecordFromCookies
14018}
14019
14020/**
14021 * Schema that decodes HTTP cookies into a record of decoded string values keyed
14022 * by cookie name.
14023 *
14024 * @stability unstable
14025 * @category schemas
14026 * @since 4.0.0
14027 */
14028export const RecordFromCookies: RecordFromCookies = Cookies.pipe(
14029 decodeTo(
14030 Record(String, String),
14031 SchemaTransformation.transform({
14032 decode: Cookies_.toRecord,
14033 encode: (self) =>
14034 Cookies_.fromIterable(
14035 globalThis.Object.entries(self).map(([name, value]) => Cookies_.makeCookieUnsafe(name, value))
14036 )
14037 })
14038 )
14039)
14040
14041/**
14042 * Type-level representation of {@link Headers}.
14043 *
14044 * @stability unstable
14045 * @category models
14046 * @since 4.0.0
14047 */
14048export interface Headers extends declare<Headers_.Headers, { readonly [x: string]: string }> {
14049 readonly "Rebuild": Headers
14050}
14051
14052/**
14053 * Schema for HTTP headers encoded as records of string values.
14054 *
14055 * **Details**
14056 *
14057 * Decoding normalizes header names; encoding returns a plain record.
14058 *
14059 * @stability unstable
14060 * @category schemas
14061 * @since 4.0.0
14062 */
14063export const Headers: Headers = declare(
14064 Headers_.isHeaders,
14065 {
14066 representation: {
14067 id: "effect/http/Headers",
14068 payload: null
14069 },
14070 toCode: () => ({
14071 runtime: "Schema.Headers",
14072 Type: "Headers.Headers",
14073 importDeclarations: [`import * as Headers from "effect/http/Headers"`]
14074 }),
14075 expected: "Headers",
14076 toEquivalence: () => Headers_.Equivalence,
14077 toCodec: () =>
14078 link<Headers_.Headers>()(
14079 Record(String, String),
14080 SchemaTransformation.transform<Headers_.Headers, { readonly [x: string]: string }>({
14081 decode: Headers_.fromInput,
14082 encode: (headers) => ({ ...headers })
14083 })
14084 )
14085 }
14086)
14087
14088/**
14089 * Type-level representation of {@link UrlParams}.
14090 *
14091 * @stability unstable
14092 * @category models
14093 * @since 4.0.0
14094 */
14095export interface UrlParams extends
14096 declare<
14097 UrlParams_.UrlParams,
14098 ReadonlyArray<readonly [string, string]>
14099 >
14100{
14101 readonly "Rebuild": UrlParams
14102}
14103
14104/**
14105 * Schema for HTTP URL parameters.
14106 *
14107 * **Details**
14108 *
14109 * The encoded representation is an array of string key-value tuples.
14110 *
14111 * @stability unstable
14112 * @category schemas
14113 * @since 4.0.0
14114 */
14115export const UrlParams: UrlParams = declare(
14116 UrlParams_.isUrlParams,
14117 {
14118 representation: {
14119 id: "effect/http/UrlParams",
14120 payload: null
14121 },
14122 toCode: () => ({
14123 runtime: "Schema.UrlParams",
14124 Type: "UrlParams.UrlParams",
14125 importDeclarations: [`import * as UrlParams from "effect/http/UrlParams"`]
14126 }),
14127 expected: "UrlParams",
14128 toEquivalence: () => UrlParams_.Equivalence,
14129 toCodec: () =>
14130 link<UrlParams_.UrlParams>()(
14131 ArraySchema(Tuple([String, String])),
14132 SchemaTransformation.transform({
14133 decode: UrlParams_.make,
14134 encode: (self) => self.params
14135 })
14136 )
14137 }
14138)
14139
14140/**
14141 * Type-level representation of {@link JsonFromUrlParamsField}.
14142 *
14143 * @stability unstable
14144 * @category models
14145 * @since 4.0.0
14146 */
14147export interface JsonFromUrlParamsField extends decodeTo<fromJsonString<Unknown>, UrlParams> {
14148 readonly "Rebuild": JsonFromUrlParamsField
14149}
14150
14151/**
14152 * Extracts a JSON value from the first occurrence of the given `field` in URL
14153 * parameters.
14154 *
14155 * **Example** (Decoding a JSON parameter field)
14156 *
14157 * ```ts import.meta.vitest
14158 * import { Schema } from "effect"
14159 * import { UrlParams } from "effect/http"
14160 *
14161 * const extractFoo = Schema.JsonFromUrlParamsField("foo").pipe(
14162 * Schema.decodeTo(Schema.Struct({
14163 * some: Schema.String,
14164 * number: Schema.Number
14165 * }))
14166 * )
14167 *
14168 * const decoded = Schema.decodeSync(extractFoo)(UrlParams.fromInput({
14169 * foo: `{"some":"bar","number":42}`,
14170 * baz: "qux"
14171 * }))
14172 * const result = [decoded.some, decoded.number] // => ["bar", 42]
14173 * ```
14174 *
14175 * @stability unstable
14176 * @category schemas
14177 * @since 4.0.0
14178 */
14179export const JsonFromUrlParamsField = (
14180 field: string,
14181 options?: { readonly reviver?: Parameters<typeof JSON.parse>[1] | undefined } | undefined
14182): JsonFromUrlParamsField =>
14183 UrlParams.pipe(
14184 decodeTo(
14185 fromJsonString(Unknown, options),
14186 SchemaTransformation.transformEffect({
14187 decode: (params) =>
14188 Option_.match(UrlParams_.getFirst(params, field), {
14189 onNone: () => Effect.fail(new SchemaIssue.Pointer([field], new SchemaIssue.MissingKey(undefined))),
14190 onSome: Effect.succeed
14191 }),
14192 encode: (value) => Effect.succeed(UrlParams_.make([[field, value]]))
14193 })
14194 )
14195 )
14196
14197/**
14198 * Type-level representation of {@link RecordFromUrlParams}.
14199 *
14200 * @stability unstable
14201 * @category models
14202 * @since 4.0.0
14203 */
14204export interface RecordFromUrlParams extends
14205 decodeTo<
14206 $Record<String, Union<readonly [String, NonEmptyArray<String>]>>,
14207 UrlParams,
14208 never,
14209 never
14210 >
14211{
14212 readonly "Rebuild": RecordFromUrlParams
14213}
14214
14215/**
14216 * Schema that decodes URL parameters into a record of string values.
14217 *
14218 * **Details**
14219 *
14220 * Keys with one value decode to a string, and keys with multiple values decode to
14221 * a non-empty readonly array of strings.
14222 *
14223 * **Example** (Decoding URL parameters to a record)
14224 *
14225 * ```ts import.meta.vitest
14226 * import { Schema } from "effect"
14227 * import { UrlParams } from "effect/http"
14228 *
14229 * const toStruct = Schema.RecordFromUrlParams.pipe(
14230 * Schema.decodeTo(Schema.Struct({
14231 * some: Schema.String,
14232 * number: Schema.FiniteFromString
14233 * }))
14234 * )
14235 *
14236 * const decoded = Schema.decodeSync(toStruct)(UrlParams.fromInput({
14237 * some: "value",
14238 * number: 42
14239 * }))
14240 * const result = [decoded.some, decoded.number] // => ["value", 42]
14241 * ```
14242 *
14243 * @stability unstable
14244 * @category schemas
14245 * @since 4.0.0
14246 */
14247export const RecordFromUrlParams: RecordFromUrlParams = UrlParams.pipe(
14248 decodeTo(
14249 Record(
14250 String,
14251 Union([String, NonEmptyArray(String)])
14252 ),
14253 SchemaTransformation.transform({
14254 decode: UrlParams_.toReadonlyRecord,
14255 encode: UrlParams_.fromInput
14256 })
14257 )
14258)
14259
14260/**
14261 * Type-level representation returned by {@link OptionFromOptionalKey}.
14262 *
14263 * @category models
14264 * @since 4.0.0
14265 */
14266export interface OptionFromOptionalKey<S extends Constraint> extends decodeTo<Option<toType<S>>, optionalKey<S>> {
14267 readonly "Rebuild": OptionFromOptionalKey<S>
14268}
14269/**
14270 * Decodes an optional value `A` to a required `Option<A>` value.
14271 *
14272 * **Details**
14273 *
14274 * Decoding maps a missing key to `None` and a present value to `Some`.
14275 * Encoding maps `None` to a missing key and maps `Some` to its value.
14276 *
14277 * @category schemas
14278 * @since 4.0.0
14279 */
14280export function OptionFromOptionalKey<S extends Constraint>(schema: S): OptionFromOptionalKey<S> {
14281 return optionalKey(schema).pipe(decodeTo(
14282 Option(toType(schema)),
14283 SchemaTransformation.optionFromOptionalKey()
14284 ))
14285}
14286/**
14287 * Type-level representation returned by {@link OptionFromOptional}.
14288 *
14289 * @category models
14290 * @since 4.0.0
14291 */
14292export interface OptionFromOptional<S extends Constraint> extends decodeTo<Option<toType<S>>, optional<S>> {
14293 readonly "Rebuild": OptionFromOptional<S>
14294}
14295/**
14296 * Decodes an optional or `undefined` value `A` to a required `Option<A>`
14297 * value.
14298 *
14299 * **Details**
14300 *
14301 * Decoding maps a missing key or a present `undefined` value to `None`, and
14302 * maps all other values to `Some`. Encoding maps `None` to a missing key and
14303 * maps `Some` to its value.
14304 *
14305 * @category schemas
14306 * @since 4.0.0
14307 */
14308export function OptionFromOptional<S extends Constraint>(schema: S): OptionFromOptional<S> {
14309 return optional(schema).pipe(decodeTo(
14310 Option(toType(schema)),
14311 SchemaTransformation.optionFromOptional<any>()
14312 ))
14313}
14314/**
14315 * Type-level representation returned by {@link OptionFromOptionalNullOr}.
14316 *
14317 * @category models
14318 * @since 4.0.0
14319 */
14320export interface OptionFromOptionalNullOr<S extends Constraint>
14321 extends decodeTo<Option<toType<S>>, optional<NullOr<S>>>
14322{
14323 readonly "Rebuild": OptionFromOptionalNullOr<S>
14324}
14325/**
14326 * Decodes an optional or `null` or `undefined` value `A` to a required `Option<A>`
14327 * value.
14328 *
14329 * **Details**
14330 *
14331 * Decoding maps a missing key, `undefined`, or `null` to `None`, and maps all
14332 * other values to `Some`. Encoding maps `Some` to its value. `None` is encoded
14333 * according to `options.onNoneEncoding`: `"omit"` encodes a missing key,
14334 * `null` encodes `null`, and `undefined` encodes `undefined`.
14335 *
14336 * @category schemas
14337 * @since 4.0.0
14338 */
14339export function OptionFromOptionalNullOr<S extends Constraint>(
14340 schema: S,
14341 options?: {
14342 readonly onNoneEncoding: "omit" | null | undefined
14343 }
14344): OptionFromOptionalNullOr<S> {
14345 const onNoneEncoding = options === undefined ? "omit" : options.onNoneEncoding
14346 const noneValue = onNoneEncoding === null
14347 ? null as S["Type"] | null | undefined
14348 : undefined as S["Type"] | null | undefined
14349 return optional(NullOr(schema)).pipe(decodeTo(
14350 Option(toType(schema)),
14351 SchemaTransformation.transformOptional<Option_.Option<S["Type"]>, S["Type"] | null | undefined>({
14352 decode: (oe) => oe.pipe(Option_.filter(Predicate.isNotNullish), Option_.some),
14353 encode: onNoneEncoding === "omit"
14354 ? Option_.flatten
14355 : (ot) => Option_.some(Option_.getOrElse(Option_.flatten(ot), () => noneValue))
14356 })
14357 ))
14358}
14359
14360// -----------------------------------------------------------------------------
14361// Redacted schemas
14362// -----------------------------------------------------------------------------
14363
14364/**
14365 * Type-level representation returned by {@link Redacted}.
14366 *
14367 * @category models
14368 * @since 3.10.0
14369 */
14370export interface Redacted<S extends Constraint> extends
14371 declareConstructor<
14372 Redacted_.Redacted<S["Type"]>,
14373 Redacted_.Redacted<S["Encoded"]>,
14374 readonly [S]
14375 >
14376{
14377 readonly "Rebuild": Redacted<S>
14378 readonly value: S
14379}
14380type NormalizedRedactedOptions =
14381 | { readonly label: string }
14382 | { readonly disallowJsonEncode: true }
14383 | { readonly label: string; readonly disallowJsonEncode: true }
14384/**
14385 * Schema for `Redacted` values, which hide their contents from inspection.
14386 *
14387 * **Details**
14388 *
14389 * Options:
14390 *
14391 * - `label`: When provided, the schema will behave as follows:
14392 * - Values will be validated against the label in addition to the wrapped schema
14393 * - The default JSON serializer will deserialize into a `Redacted` instance with the label
14394 * - The arbitrary generator will produce a `Redacted` instance with the label
14395 * - The formatter will return the label
14396 * - `disallowJsonEncode`: When set to `true`, when attempting to encode a `Redacted` instance
14397 * into JSON, it will fail with an error. This is useful when the wrapped schema is
14398 * sensitive and should not be exposed in JSON.
14399 *
14400 * @see {@link RedactedFromValue} for decoding raw values and wrapping them in `Redacted`.
14401 * @category schemas
14402 * @since 3.10.0
14403 */
14404export function Redacted<S extends Constraint>(value: S, options?: {
14405 readonly label?: string | undefined
14406 readonly disallowJsonEncode?: boolean | undefined
14407}): Redacted<S> {
14408 const label = typeof options?.label === "string" ? options.label : undefined
14409 const disallowJsonEncode = options?.disallowJsonEncode === true
14410 const normalizedOptions: NormalizedRedactedOptions | undefined = label !== undefined
14411 ? disallowJsonEncode ? { label, disallowJsonEncode: true } : { label }
14412 : disallowJsonEncode
14413 ? { disallowJsonEncode: true }
14414 : undefined
14415 const decodeLabel = label !== undefined
14416 ? SchemaParser.decodeUnknownEffect(Literal(label))
14417 : undefined
14418 const schema = declareConstructor<Redacted_.Redacted<S["Type"]>, Redacted_.Redacted<S["Encoded"]>>()(
14419 [value],
14420 ([value]) => (input, ast, poptions) => {
14421 if (Redacted_.isRedacted(input)) {
14422 const label: Effect.Effect<void, SchemaIssue.Issue, never> = decodeLabel !== undefined
14423 ? Effect.mapErrorEager(
14424 decodeLabel(input.label, poptions),
14425 (issue) => new SchemaIssue.Pointer(["label"], issue)
14426 )
14427 : Effect.void
14428 return Effect.flatMapEager(
14429 label,
14430 () =>
14431 Effect.mapBothEager(
14432 SchemaParser.decodeUnknownEffect(value)(Redacted_.value(input), poptions),
14433 {
14434 onSuccess: (value) => Redacted_.make(value, { label: input.label }),
14435 onFailure: () => {
14436 return new SchemaIssue.Composite(
14437 ast,
14438 [
14439 new SchemaIssue.Pointer(
14440 ["value"],
14441 new SchemaIssue.InvalidValue(undefined, input, poptions)
14442 )
14443 ],
14444 input,
14445 poptions
14446 )
14447 }
14448 }
14449 )
14450 )
14451 }
14452 return Effect.fail(new SchemaIssue.InvalidType(ast, input, poptions))
14453 },
14454 {
14455 representation: {
14456 id: "effect/schema/Redacted",
14457 payload: normalizedOptions ?? null
14458 },
14459 toCode: ({ typeParameters }) => ({
14460 runtime: normalizedOptions !== undefined
14461 ? `Schema.Redacted(${typeParameters[0].runtime}, ${format(normalizedOptions)})`
14462 : `Schema.Redacted(${typeParameters[0].runtime})`,
14463 Type: `Redacted.Redacted<${typeParameters[0].Type}>`,
14464 importDeclarations: [`import * as Redacted from "effect/Redacted"`]
14465 }),
14466 expected: "Redacted",
14467 toCodecJson: ([value]) =>
14468 link<Redacted_.Redacted<S["Encoded"]>>()(
14469 value,
14470 {
14471 decode: SchemaGetter.transform((e) => Redacted_.make(e, { label })),
14472 encode: disallowJsonEncode ?
14473 SchemaGetter.forbidden((oe) =>
14474 "Cannot serialize Redacted" +
14475 (Option_.isSome(oe) && typeof oe.value.label === "string" ? ` with label: "${oe.value.label}"` : "")
14476 ) :
14477 SchemaGetter.transform(Redacted_.value)
14478 }
14479 ),
14480 toEquivalence: ([value]) => Redacted_.makeEquivalence(value)
14481 }
14482 )
14483 return make(schema.ast, { value })
14484}
14485/**
14486 * Type-level representation returned by {@link RedactedFromValue}.
14487 *
14488 * @category models
14489 * @since 4.0.0
14490 */
14491export interface RedactedFromValue<S extends Constraint> extends decodeTo<Redacted<toType<S>>, S> {
14492 readonly "Rebuild": RedactedFromValue<S>
14493}
14494/**
14495 * Decodes a value and wraps it in `Redacted<A>`. Unlike {@link Redacted} which
14496 * expects the input to already be a `Redacted` instance, this schema decodes
14497 * the raw value and wraps it.
14498 *
14499 * @see {@link Redacted} for schemas whose input is already a `Redacted` value.
14500 * @category schemas
14501 * @since 4.0.0
14502 */
14503export function RedactedFromValue<S extends Constraint>(value: S, options?: {
14504 readonly label?: string | undefined
14505 readonly disallowEncode?: boolean | undefined
14506}): RedactedFromValue<S> {
14507 return decodeTo<Redacted<toType<S>>, S>(
14508 Redacted(toType(value), {
14509 label: options?.label,
14510 disallowJsonEncode: options?.disallowEncode
14511 }),
14512 {
14513 decode: SchemaGetter.transform((t) => Redacted_.make(t, { label: options?.label })),
14514 encode: options?.disallowEncode ?
14515 SchemaGetter.forbidden((oe) =>
14516 "Cannot encode Redacted" +
14517 (Option_.isSome(oe) && typeof oe.value.label === "string" ? ` with label: "${oe.value.label}"` : "")
14518 ) :
14519 SchemaGetter.transform(Redacted_.value)
14520 }
14521 )(value)
14522}
14523
14524// -----------------------------------------------------------------------------
14525// Result schemas
14526// -----------------------------------------------------------------------------
14527
14528/**
14529 * Type-level representation returned by {@link Result}.
14530 *
14531 * @category models
14532 * @since 4.0.0
14533 */
14534export interface Result<A extends Constraint, E extends Constraint> extends
14535 declareConstructor<
14536 Result_.Result<A["Type"], E["Type"]>,
14537 Result_.Result<A["Encoded"], E["Encoded"]>,
14538 readonly [A, E],
14539 ResultIso<A, E>
14540 >
14541{
14542 readonly "Rebuild": Result<A, E>
14543 readonly success: A
14544 readonly failure: E
14545}
14546/**
14547 * Iso representation used for `Result` schemas.
14548 *
14549 * **Details**
14550 *
14551 * Successful results are represented as `{ _tag: "Success", success }`, while
14552 * failed results are represented as `{ _tag: "Failure", failure }`.
14553 *
14554 * @category utility types
14555 * @since 4.0.0
14556 */
14557export type ResultIso<A extends Constraint, E extends Constraint> = {
14558 readonly _tag: "Success"
14559 readonly success: A["Iso"]
14560} | {
14561 readonly _tag: "Failure"
14562 readonly failure: E["Iso"]
14563}
14564/**
14565 * Schema for `Result<A, E>` values.
14566 *
14567 * @category schemas
14568 * @since 4.0.0
14569 */
14570export function Result<A extends Constraint, E extends Constraint>(
14571 success: A,
14572 failure: E
14573): Result<A, E> {
14574 const schema = declareConstructor<
14575 Result_.Result<A["Type"], E["Type"]>,
14576 Result_.Result<A["Encoded"], E["Encoded"]>,
14577 ResultIso<A, E>
14578 >()(
14579 [success, failure],
14580 ([success, failure]) => (input, ast, options) => {
14581 if (!Result_.isResult(input)) {
14582 return Effect.fail(new SchemaIssue.InvalidType(ast, input, options))
14583 }
14584 switch (input._tag) {
14585 case "Success":
14586 return Effect.mapBothEager(SchemaParser.decodeEffect(success)(input.success, options), {
14587 onSuccess: Result_.succeed,
14588 onFailure: (issue) => SchemaIssue.makeCompositeAtKey(ast, "success", issue, input, options)
14589 })
14590 case "Failure":
14591 return Effect.mapBothEager(SchemaParser.decodeEffect(failure)(input.failure, options), {
14592 onSuccess: Result_.fail,
14593 onFailure: (issue) => SchemaIssue.makeCompositeAtKey(ast, "failure", issue, input, options)
14594 })
14595 }
14596 },
14597 {
14598 representation: {
14599 id: "effect/schema/Result",
14600 payload: null
14601 },
14602 toCode: ({ typeParameters }) => ({
14603 runtime: `Schema.Result(${typeParameters[0].runtime}, ${typeParameters[1].runtime})`,
14604 Type: `Result.Result<${typeParameters[0].Type}, ${typeParameters[1].Type}>`,
14605 importDeclarations: [`import * as Result from "effect/Result"`]
14606 }),
14607 expected: "Result",
14608 toCodec: ([success, failure]) =>
14609 link<Result_.Result<A["Encoded"], E["Encoded"]>>()(
14610 Union([
14611 Struct({ _tag: Literal("Success"), success }),
14612 Struct({ _tag: Literal("Failure"), failure })
14613 ]),
14614 SchemaTransformation.transform({
14615 decode: (e): Result_.Result<A["Encoded"], E["Encoded"]> =>
14616 e._tag === "Success" ? Result_.succeed(e.success) : Result_.fail(e.failure),
14617 encode: (r) =>
14618 Result_.isSuccess(r)
14619 ? { _tag: "Success", success: r.success } as const
14620 : { _tag: "Failure", failure: r.failure } as const
14621 })
14622 )
14623 }
14624 )
14625 return make(schema.ast, { success, failure })
14626}
14627
14628/**
14629 * Type-level representation returned by {@link Class}.
14630 *
14631 * @category models
14632 * @since 3.10.0
14633 */
14634export interface Class<Self, S extends Constraint & { readonly fields: Struct.Fields }, Inherited>
14635 extends
14636 BottomLazyWithoutNew<
14637 SchemaAST.Declaration,
14638 decodeTo<declareConstructor<Self, S["Encoded"], readonly [S], S["Iso"]>, S>,
14639 readonly [S],
14640 S["~type.mutability"],
14641 S["~type.optionality"],
14642 S["~type.constructor.default"],
14643 S["~encoded.mutability"],
14644 S["~encoded.optionality"]
14645 >
14646{
14647 /**
14648 * `make`, `makeOption`, and `makeEffect` preserve an existing instance of
14649 * this class. Use `new` when a distinct instance is required.
14650 */
14651 readonly "Type": Self
14652 readonly "Encoded": S["Encoded"]
14653 readonly "DecodingServices": S["DecodingServices"]
14654 readonly "EncodingServices": S["EncodingServices"]
14655 readonly "~type.make.in": RequiredKeys<S["~type.make.in"]> extends never ? void | S["~type.make.in"]
14656 : S["~type.make.in"]
14657 readonly "~type.make": Self
14658 readonly "Iso": S["Iso"]
14659 new(
14660 ...args: {} extends S["~type.make.in"] ? [props?: S["~type.make.in"], options?: MakeOptions]
14661 : [props: S["~type.make.in"], options?: MakeOptions]
14662 ): S["Type"] & Inherited
14663 readonly identifier: string
14664 readonly fields: S["fields"]
14665
14666 /**
14667 * Returns a new struct with the fields modified by the provided function.
14668 *
14669 * **Details**
14670 *
14671 * Options:
14672 *
14673 * - `unsafePreserveChecks` - if `true`, keep any `.check(...)` constraints
14674 * that were attached to the original struct. Defaults to `false`.
14675 *
14676 * **Warning**: This is an unsafe operation. Since `mapFields`
14677 * transformations change the schema type, the original refinement functions
14678 * may no longer be valid or safe to apply to the transformed schema. Only
14679 * use this option if you have verified that your refinements remain correct
14680 * after the transformation.
14681 */
14682 mapFields<To extends Struct.Fields>(
14683 f: (fields: S["fields"]) => To,
14684 options?: {
14685 readonly unsafePreserveChecks?: boolean | undefined
14686 } | undefined
14687 ): Struct<Simplify<Readonly<To>>>
14688
14689 /**
14690 * Returns a function that creates a schema-backed subclass with this class's
14691 * fields plus additional fields.
14692 *
14693 * **When to use**
14694 *
14695 * Use when you need a subclass whose constructor validates both inherited
14696 * fields and newly added fields.
14697 *
14698 * **Details**
14699 *
14700 * The returned function accepts either a field map or a `Struct`. When you
14701 * pass a `Struct`, checks attached to that extension schema are preserved and
14702 * combined with checks from the base class schema.
14703 *
14704 * **Gotchas**
14705 *
14706 * Checks from a `Struct` argument are evaluated against the full subclass
14707 * value after inherited and extension fields are merged. Object-wide checks
14708 * such as `isMaxProperties` count inherited fields too.
14709 */
14710 extend<Extended = never, Static = {}, Brand = {}>(
14711 identifier: string
14712 ): {
14713 <NewFields extends Struct.Fields>(
14714 fields: NewFields,
14715 annotations?: Annotations.Declaration<Extended, readonly [Struct<Simplify<Assign<S["fields"], NewFields>>>]>
14716 ): [Extended] extends [never] ? MissingSelfGeneric<"Base.extend"> : InheritStaticMembers<
14717 Class<Extended, Struct<Simplify<Assign<S["fields"], NewFields>>>, Self & Brand>,
14718 Static
14719 >
14720 <Extension extends Struct<Struct.Fields>>(
14721 schema: Extension,
14722 annotations?: Annotations.Declaration<
14723 Extended,
14724 readonly [Struct<Simplify<Assign<S["fields"], Extension["fields"]>>>]
14725 >
14726 ): [Extended] extends [never] ? MissingSelfGeneric<"Base.extend"> : InheritStaticMembers<
14727 Class<Extended, Struct<Simplify<Assign<S["fields"], Extension["fields"]>>>, Self & Brand>,
14728 Static
14729 >
14730 }
14731}
14732type InheritStaticMembers<C, Static> = C & Pick<Static, Exclude<keyof Static, keyof C>>
14733type MissingSelfGeneric<Usage extends string> =
14734 `Missing \`Self\` generic - use \`class Self extends ${Usage}<Self>(...)\``
14735
14736const immerable: unique symbol = globalThis.Symbol.for("immer-draftable") as any
14737
14738const payloadToken = {}
14739
14740function makeClass<
14741 Self,
14742 S extends Struct<Struct.Fields>,
14743 Inherited extends new(...args: ReadonlyArray<any>) => any
14744>(
14745 Inherited: Inherited,
14746 identifier: string,
14747 struct: S,
14748 annotations: Annotations.Declaration<Self, readonly [S]> | undefined,
14749 proto: ((identifier: string) => object) | undefined
14750): any {
14751 const getClassSchema = getClassSchemaFactory(struct, identifier, annotations)
14752 const ClassTypeId = getClassTypeId(identifier) // HMR support
14753
14754 const out = class extends Inherited {
14755 constructor(...[input, options]: ReadonlyArray<any>) {
14756 const internalOptions = options as MakeOptions | undefined
14757 const payload = internalOptions?.["~payload"]
14758 const value = payload?.token === payloadToken
14759 ? payload.value
14760 : struct.make(input ?? {}, options)
14761 super(value, { ...options, disableChecks: true, "~payload": { token: payloadToken, value } })
14762 }
14763
14764 static readonly [TypeId] = TypeId
14765
14766 get [ClassTypeId]() {
14767 return ClassTypeId
14768 }
14769
14770 static readonly [immerable] = true
14771
14772 static readonly identifier = identifier
14773 static readonly fields = struct.fields
14774
14775 static get ast(): SchemaAST.Declaration {
14776 return getClassSchema(this).ast
14777 }
14778 static pipe() {
14779 return Pipeable.pipeArguments(this, arguments)
14780 }
14781 static rebuild(ast: SchemaAST.Declaration) {
14782 return getClassSchema(this).rebuild(ast)
14783 }
14784 static make(input: S["~type.make.in"], options?: MakeOptions): Self {
14785 return SchemaParser.make(getClassSchema(this) as any)(input ?? {}, options) as Self
14786 }
14787 static makeOption(input: S["~type.make.in"], options?: MakeOptions): Option_.Option<Self> {
14788 return SchemaParser.makeOption(getClassSchema(this) as any)(input ?? {}, options) as any
14789 }
14790 static makeEffect(input: S["~type.make.in"], options?: MakeOptions): Effect.Effect<Self, SchemaIssue.Issue> {
14791 return (getClassSchema(this) as any).makeEffect(input ?? {}, options)
14792 }
14793 static annotate(annotations: Annotations.Declaration<Self, readonly [S]>) {
14794 return this.rebuild(SchemaAST.annotate(this.ast, annotations))
14795 }
14796 static annotateKey(annotations: Annotations.Key<Self>) {
14797 return this.rebuild(SchemaAST.annotateKey(this.ast, annotations))
14798 }
14799 static check(...checks: readonly [SchemaAST.Check<Self>, ...Array<SchemaAST.Check<Self>>]) {
14800 return this.rebuild(SchemaAST.appendChecks(this.ast, checks))
14801 }
14802 static extend(
14803 identifier: string
14804 ) {
14805 return (
14806 schema: Struct.Fields | Struct<Struct.Fields>,
14807 annotations?: Annotations.Declaration<any, readonly [any]>
14808 ) => {
14809 const extension = isStruct(schema) ? schema : Struct(schema)
14810 const fields = { ...struct.fields, ...extension.fields }
14811 const ast = SchemaAST.struct(fields, struct.ast.checks, { identifier })
14812 return makeClass(
14813 this,
14814 identifier,
14815 makeStruct(SchemaAST.appendChecks(ast, extension.ast.checks), fields),
14816 annotations,
14817 proto
14818 )
14819 }
14820 }
14821 static mapFields<To extends Struct.Fields>(
14822 f: (fields: S["fields"]) => To,
14823 options?: {
14824 readonly unsafePreserveChecks?: boolean | undefined
14825 } | undefined
14826 ): Struct<Simplify<Readonly<To>>> {
14827 return struct.mapFields(f, options)
14828 }
14829 }
14830
14831 if (proto !== undefined) {
14832 Object.assign(out.prototype, proto(identifier))
14833 }
14834
14835 return out
14836}
14837
14838function getClassTransformation(self: new(...args: ReadonlyArray<any>) => any) {
14839 return new SchemaTransformation.Transformation<any, any, never, never>(
14840 SchemaGetter.transform((input) =>
14841 new self(input, {
14842 "~payload": {
14843 token: payloadToken,
14844 value: input
14845 }
14846 })
14847 ),
14848 SchemaGetter.passthrough()
14849 )
14850}
14851
14852function getClassTypeId(identifier: string) {
14853 return `~effect/Schema/Class/${identifier}`
14854}
14855
14856function getClassSchemaFactory<S extends Constraint>(
14857 from: S,
14858 identifier: string,
14859 annotations: Annotations.Declaration<any, readonly [S]> | undefined
14860) {
14861 let memo: decodeTo<declareConstructor<any, S["Encoded"], readonly [S]>, S> | undefined
14862 return <Self extends (new(...args: ReadonlyArray<any>) => any) & { readonly identifier: string }>(
14863 self: Self
14864 ): decodeTo<declareConstructor<Self, S["Encoded"], readonly [S]>, S> => {
14865 if (memo !== undefined) {
14866 return memo
14867 }
14868 const ClassTypeId = getClassTypeId(identifier)
14869 const isClassValue: Predicate.Predicate<unknown> = (input) =>
14870 input instanceof self || Predicate.hasProperty(input, ClassTypeId)
14871 const transformation = getClassTransformation(self)
14872 const to = make<declareConstructor<Self, S["Encoded"], readonly [S]>>(
14873 new SchemaAST.Declaration(
14874 [from.ast],
14875 () => (input, ast, options) => {
14876 return isClassValue(input) ?
14877 Effect.succeed(input) :
14878 Effect.fail(new SchemaIssue.InvalidType(ast, input, options))
14879 },
14880 {
14881 identifier,
14882 [InternalAnnotations.CONSTRUCTOR_ANNOTATION_KEY]: (
14883 [from]: readonly [SchemaAST.AST]
14884 ): SchemaAST.ConstructorDescriptor => ({
14885 isConstructed: isClassValue,
14886 link: new SchemaAST.Link(from, transformation)
14887 }),
14888 toCodec: ([from]: readonly [ConstraintCodec<S["Encoded"], S["Encoded"]>]) =>
14889 new SchemaAST.Link(from.ast, transformation),
14890 toEquivalence: ([from]: readonly [Equivalence.Equivalence<S["Type"]>]) => from,
14891 toFormatter: ([from]: readonly [Formatter<S["Type"]>]) => (t: Self) => `${self.identifier}(${from(t)})`,
14892 [InternalAnnotations.SENTINELS_ANNOTATION_KEY]: SchemaAST.collectSentinels(from.ast),
14893 ...annotations
14894 }
14895 )
14896 )
14897 return memo = decodeTo<declareConstructor<Self, S["Encoded"], readonly [S]>, S>(to, transformation)(from)
14898 }
14899}
14900
14901function isStruct(schema: Struct.Fields | Struct<Struct.Fields>): schema is Struct<Struct.Fields> {
14902 return isSchema(schema)
14903}
14904/**
14905 * Creates a schema-backed class whose constructor validates input against a
14906 * {@link Struct} schema. Construction throws an `Error` with a
14907 * `SchemaIssue.Issue` in its `cause` on invalid input.
14908 *
14909 * **When to use**
14910 *
14911 * Use when you need a schema-backed data class with validated construction,
14912 * schema-derived decoding/encoding, and class-style methods or inheritance.
14913 *
14914 * **Details**
14915 *
14916 * Pass the desired class type as the first type parameter. The second optional
14917 * type parameter can be used to add nominal brands.
14918 *
14919 * The `identifier` is the schema's stable runtime name. It is exposed on the
14920 * class, stored in the schema AST, and used to label diagnostics and generated
14921 * references as well as to format class instances.
14922 *
14923 * It also derives a runtime marker that recognizes instances across hot module
14924 * reloads, where `instanceof` can fail because the constructor has been
14925 * replaced. The identifier is explicit because the outer JavaScript class name
14926 * is not available while the `extends` expression is evaluated and may change
14927 * through renaming or minification.
14928 *
14929 * **Gotchas**
14930 *
14931 * Passing `disableChecks` in the options skips constructor validation.
14932 *
14933 * **Example** (Defining a basic class)
14934 *
14935 * ```ts import.meta.vitest
14936 * import { Schema } from "effect"
14937 *
14938 * class Person extends Schema.Class<Person>("Person")({
14939 * name: Schema.String,
14940 * age: Schema.Number
14941 * }) {}
14942 *
14943 * const alice = new Person({ name: "Alice", age: 30 })
14944 * alice.name // => "Alice"
14945 * String(alice) // => "Person({\"name\":\"Alice\",\"age\":30})"
14946 * ```
14947 *
14948 * **Example** (Extending a class)
14949 *
14950 * ```ts import.meta.vitest
14951 * import { Schema } from "effect"
14952 *
14953 * class Animal extends Schema.Class<Animal>("Animal")({
14954 * name: Schema.String
14955 * }) {}
14956 *
14957 * class Dog extends Animal.extend<Dog>("Dog")({
14958 * breed: Schema.String
14959 * }) {}
14960 *
14961 * const dog = new Dog({ name: "Rex", breed: "Labrador" })
14962 * dog.name // => "Rex"
14963 * dog.breed // => "Labrador"
14964 * ```
14965 *
14966 * @see {@link TaggedClass} for adding a `_tag` literal field to the class schema
14967 * @see {@link Error} for defining schema-backed error classes
14968 * @see {@link TaggedError} for defining tagged schema-backed error classes
14969 *
14970 * @category constructors
14971 * @since 3.10.0
14972 */
14973export const Class: {
14974 <Self = never, Brand = {}>(identifier: string): {
14975 <const Fields extends Struct.Fields>(
14976 fields: Fields,
14977 annotations?: Annotations.Declaration<Self, readonly [Struct<Fields>]>
14978 ): [Self] extends [never] ? MissingSelfGeneric<"Schema.Class"> : Class<Self, Struct<Fields>, Brand>
14979 <S extends Struct<Struct.Fields>>(
14980 schema: S,
14981 annotations?: Annotations.Declaration<Self, readonly [S]>
14982 ): [Self] extends [never] ? MissingSelfGeneric<"Schema.Class"> : Class<Self, S, Brand>
14983 }
14984} = <Self, Brand = {}>(identifier: string) =>
14985(
14986 schema: Struct.Fields | Struct<Struct.Fields>,
14987 annotations?: Annotations.Declaration<Self, readonly [Struct<Struct.Fields>]>
14988): [Self] extends [never] ? MissingSelfGeneric<"Schema.Class"> : Class<Self, Struct<Struct.Fields>, Brand> => {
14989 const struct = isStruct(schema) ? schema : Struct(schema)
14990 return makeClass(
14991 Data.Class,
14992 identifier,
14993 struct,
14994 annotations,
14995 (identifier) => ({
14996 toString() {
14997 return `${identifier}(${format({ ...this })})`
14998 }
14999 })
15000 )
15001}
15002/**
15003 * Defines a schema-backed class with an automatically populated `_tag` field.
15004 *
15005 * **When to use**
15006 *
15007 * Use to define class instances that are validated by a schema and participate
15008 * in tagged union matching.
15009 *
15010 * **Details**
15011 *
15012 * The optional `identifier` parameter overrides the schema identifier;
15013 * it defaults to the `tag` value.
15014 *
15015 * **Example** (Defining a tagged class)
15016 *
15017 * ```ts import.meta.vitest
15018 * import { Schema } from "effect"
15019 *
15020 * class Circle extends Schema.TaggedClass<Circle>()("Circle", {
15021 * radius: Schema.Number
15022 * }) {}
15023 *
15024 * const c = new Circle({ radius: 5 })
15025 * c._tag // => "Circle"
15026 * c.radius // => 5
15027 * ```
15028 *
15029 * @category constructors
15030 * @since 3.10.0
15031 */
15032export const TaggedClass: {
15033 <Self = never, Brand = {}>(identifier?: string): {
15034 <Tag extends string, const Fields extends Struct.Fields>(
15035 tag: Tag,
15036 fields: Fields,
15037 annotations?: Annotations.Declaration<Self, readonly [TaggedStruct<Tag, Fields>]>
15038 ): [Self] extends [never] ? MissingSelfGeneric<"Schema.TaggedClass"> : Class<Self, TaggedStruct<Tag, Fields>, Brand>
15039 <Tag extends string, S extends Struct<Struct.Fields>>(
15040 tag: Tag,
15041 schema: S,
15042 annotations?: Annotations.Declaration<
15043 Self,
15044 readonly [Struct<Simplify<{ readonly _tag: tag<Tag> } & S["fields"]>>]
15045 >
15046 ): [Self] extends [never] ? MissingSelfGeneric<"Schema.TaggedClass">
15047 : Class<Self, Struct<Simplify<{ readonly _tag: tag<Tag> } & S["fields"]>>, Brand>
15048 }
15049} = (identifier?: string) => {
15050 return (
15051 tagValue: string,
15052 schema: Struct.Fields | Struct<Struct.Fields>,
15053 annotations?: Annotations.Declaration<any, readonly [Struct<Struct.Fields>]>
15054 ): any => {
15055 const struct = isStruct(schema) ?
15056 schema.mapFields((fields) => ({ _tag: tag(tagValue), ...fields }), {
15057 unsafePreserveChecks: true
15058 }) :
15059 TaggedStruct(tagValue, schema)
15060 return Class<any, {}>(identifier ?? tagValue)(
15061 struct,
15062 annotations as Annotations.Declaration<any, readonly [typeof struct]>
15063 )
15064 }
15065}
15066/**
15067 * Creates a schema-backed error class that can be used as a typed,
15068 * yieldable error in Effect programs. Combines {@link Class} validation with
15069 * the `YieldableError` interface so instances can be yielded directly inside
15070 * `Effect.gen`.
15071 *
15072 * **Example** (Schema-backed error)
15073 *
15074 * ```ts import.meta.vitest
15075 * import { Effect, Schema } from "effect"
15076 *
15077 * class NotFound extends Schema.Error<NotFound>("NotFound")({
15078 * id: Schema.Number
15079 * }) {}
15080 *
15081 * const program = Effect.gen(function*() {
15082 * yield* new NotFound({ id: 1 })
15083 * })
15084 * const error = await Effect.runPromise(Effect.flip(program))
15085 * error.id // => 1
15086 * ```
15087 *
15088 * @category constructors
15089 * @since 4.0.0
15090 */
15091export const Error: {
15092 <Self = never, Brand = {}>(identifier: string): {
15093 <const Fields extends Struct.Fields>(
15094 fields: Fields,
15095 annotations?: Annotations.Declaration<Self, readonly [Struct<Fields>]>
15096 ): [Self] extends [never] ? MissingSelfGeneric<"Schema.Error">
15097 : Class<Self, Struct<Fields>, Cause_.YieldableError & Brand>
15098 <S extends Struct<Struct.Fields>>(
15099 schema: S,
15100 annotations?: Annotations.Declaration<Self, readonly [S]>
15101 ): [Self] extends [never] ? MissingSelfGeneric<"Schema.Error"> : Class<Self, S, Cause_.YieldableError & Brand>
15102 }
15103} = <Self, Brand = {}>(identifier: string) =>
15104(
15105 schema: Struct.Fields | Struct<Struct.Fields>,
15106 annotations?: Annotations.Declaration<Self, readonly [Struct<Struct.Fields>]>
15107): [Self] extends [never] ? MissingSelfGeneric<"Schema.Error">
15108 : Class<Self, Struct<Struct.Fields>, Cause_.YieldableError & Brand> =>
15109{
15110 const struct = isStruct(schema) ? schema : Struct(schema)
15111 const self = makeClass(
15112 core.Error,
15113 identifier,
15114 struct,
15115 annotations,
15116 (identifier) => ({
15117 name: identifier
15118 })
15119 )
15120 return self
15121}
15122/**
15123 * Defines a schema-backed yieldable error class with an automatically populated
15124 * `_tag` field.
15125 *
15126 * **When to use**
15127 *
15128 * Use to define typed errors that are schema validated, yielded in `Effect.gen`,
15129 * and matched as tagged union members.
15130 *
15131 * **Example** (Defining a tagged error class)
15132 *
15133 * ```ts import.meta.vitest
15134 * import { Effect, Schema } from "effect"
15135 *
15136 * class NotFound extends Schema.TaggedError<NotFound>()("NotFound", {
15137 * id: Schema.Number
15138 * }) {}
15139 *
15140 * const program = Effect.gen(function*() {
15141 * yield* new NotFound({ id: 42 })
15142 * })
15143 * const error = await Effect.runPromise(Effect.flip(program))
15144 * error._tag // => "NotFound"
15145 * error.id // => 42
15146 * ```
15147 *
15148 * @category constructors
15149 * @since 3.10.0
15150 */
15151export const TaggedError: {
15152 <Self = never, Brand = {}>(identifier?: string): {
15153 <Tag extends string, const Fields extends Struct.Fields>(
15154 tag: Tag,
15155 fields: Fields,
15156 annotations?: Annotations.Declaration<Self, readonly [TaggedStruct<Tag, Fields>]>
15157 ): [Self] extends [never] ? MissingSelfGeneric<"Schema.TaggedError">
15158 : Class<Self, TaggedStruct<Tag, Fields>, Cause_.YieldableError & Brand>
15159 <Tag extends string, S extends Struct<Struct.Fields>>(
15160 tag: Tag,
15161 schema: S,
15162 annotations?: Annotations.Declaration<
15163 Self,
15164 readonly [Struct<Simplify<{ readonly _tag: tag<Tag> } & S["fields"]>>]
15165 >
15166 ): [Self] extends [never] ? MissingSelfGeneric<"Schema.TaggedError">
15167 : Class<Self, Struct<Simplify<{ readonly _tag: tag<Tag> } & S["fields"]>>, Cause_.YieldableError & Brand>
15168 }
15169} = (identifier?: string) => {
15170 return (
15171 tagValue: string,
15172 schema: Struct.Fields | Struct<Struct.Fields>,
15173 annotations?: Annotations.Declaration<any, readonly [Struct<Struct.Fields>]>
15174 ): any => {
15175 const struct = isStruct(schema) ?
15176 schema.mapFields((fields) => ({ _tag: tag(tagValue), ...fields }), {
15177 unsafePreserveChecks: true
15178 }) :
15179 TaggedStruct(tagValue, schema)
15180 return Error<any, {}>(identifier ?? tagValue)(
15181 struct,
15182 annotations as Annotations.Declaration<any, readonly [typeof struct]>
15183 )
15184 }
15185}
15186/**
15187 * Attaches a custom formatter used by `toFormatter`.
15188 *
15189 * **Details**
15190 *
15191 * Use this when the formatter derived from the schema structure is not suitable.
15192 * The annotation is applied through this helper because adding it directly to
15193 * `Annotations.Bottom` would make schemas invariant.
15194 *
15195 * @category formatting
15196 * @since 4.0.0
15197 */
15198export function overrideToFormatter<S extends Top>(toFormatter: () => Formatter<S["Type"]>) {
15199 return (self: S): S["Rebuild"] => self.annotate({ toFormatter })
15200}
15201/**
15202 * Derives a string formatter function from a schema. The formatter converts
15203 * a value to its human-readable string representation, recursing into structs,
15204 * arrays, and unions.
15205 *
15206 * **Details**
15207 *
15208 * The optional `onBefore` hook lets you intercept specific AST nodes before
15209 * the default formatting logic runs.
15210 *
15211 * @category formatting
15212 * @since 4.0.0
15213 */
15214export function toFormatter<S extends Constraint>(schema: S, options?: {
15215 readonly onBefore?:
15216 | ((ast: SchemaAST.AST, recur: (ast: SchemaAST.AST) => Formatter<any>) => Formatter<any> | undefined)
15217 | undefined
15218}): Formatter<S["Type"]> {
15219 return InternalToFormatter.toFormatter(schema.ast, options)
15220}
15221/**
15222 * Overrides the equivalence derivation for a schema by supplying a custom
15223 * `Equivalence`.
15224 *
15225 * **When to use**
15226 *
15227 * Use when you need a custom equivalence instead of the default structural
15228 * equivalence derived by {@link toEquivalence}.
15229 *
15230 * @category instances
15231 * @since 4.0.0
15232 */
15233export function overrideToEquivalence<S extends Top>(toEquivalence: () => Equivalence.Equivalence<S["Type"]>) {
15234 return (self: S): S["Rebuild"] => self.annotate({ toEquivalence })
15235}
15236/**
15237 * Derives an `Equivalence` from a schema. Two values are considered equal when
15238 * every field (and nested field) compares equal according to the schema
15239 * structure.
15240 *
15241 * **Example** (Comparing structs)
15242 *
15243 * ```ts import.meta.vitest
15244 * import { Schema } from "effect"
15245 *
15246 * const eq = Schema.toEquivalence(Schema.Struct({ id: Schema.Number, name: Schema.String }))
15247 *
15248 * eq({ id: 1, name: "Alice" }, { id: 1, name: "Alice" }) // => true
15249 * eq({ id: 1, name: "Alice" }, { id: 2, name: "Alice" }) // => false
15250 * ```
15251 *
15252 * @category instances
15253 * @since 4.0.0
15254 */
15255export function toEquivalence<T>(schema: Schema<T>): Equivalence.Equivalence<T> {
15256 return InternalEquivalence.toEquivalence(schema.ast)
15257}
15258/**
15259 * Derives an intermediate `SchemaRepresentation.Document` from the encoded
15260 * side of a schema.
15261 *
15262 * **When to use**
15263 *
15264 * Use when you have a `Schema` and need its live structural representation for inspection, persistence, or compilation.
15265 *
15266 * **Details**
15267 *
15268 * Use {@link toType} before this function to represent the type side instead.
15269 * The optional reference policy controls which candidates are extracted into the document's reference table. By
15270 * default, only candidates with a resolved identifier become references; recursive candidates always require one.
15271 * TypeScript-only distinctions such as those added by {@link brand} are not
15272 * part of the schema AST and are therefore omitted.
15273 *
15274 * @see {@link SchemaRepresentation.toRepresentation} for converting a `SchemaAST.AST` directly
15275 *
15276 * @category converting
15277 * @since 4.0.0
15278 */
15279export function toRepresentation(
15280 schema: Constraint,
15281 options?: SchemaRepresentation.ToRepresentationOptions
15282): SchemaRepresentation.Document {
15283 return InternalToRepresentation.toRepresentation(schema.ast, options)
15284}
15285/**
15286 * Options for reference allocation and JSON Schema generation in {@link toJsonSchemaDocument}.
15287 *
15288 * **Details**
15289 *
15290 * The inherited `referencePolicy` runs after the input schema is converted to its canonical JSON codec, so it receives
15291 * canonical JSON-encoded ASTs. The remaining options control compilation of the resulting live representation.
15292 *
15293 * **Gotchas**
15294 *
15295 * When these options are passed directly to `SchemaRepresentation.toJsonSchemaDocument` or
15296 * `SchemaRepresentation.toJsonSchemaMultiDocument`, reference allocation has already happened and `referencePolicy`
15297 * has no effect.
15298 *
15299 * @category options
15300 * @since 4.0.0
15301 */
15302export interface ToJsonSchemaOptions extends SchemaRepresentation.ToRepresentationOptions {
15303 /**
15304 * Controls whether generated object schemas accept properties that are not
15305 * modeled by the Effect schema.
15306 *
15307 * **Details**
15308 *
15309 * The default, `"ignore"`, matches the decoder's default excess-property
15310 * behavior and leaves unmodeled properties open. Use `"error"` together
15311 * with the decoder option of the same name to reject unmodeled properties
15312 * whenever the key space can be represented.
15313 *
15314 * Index signatures still determine the schema for properties they model.
15315 * When an index-signature key cannot be used as a `patternProperties`
15316 * selector, `"ignore"` leaves unmatched properties open. `"error"` instead
15317 * constrains their names with `propertyNames` and uses the candidate index
15318 * value schemas for `additionalProperties`.
15319 */
15320 readonly onExcessProperty?: "ignore" | "error" | undefined
15321 /**
15322 * Controls whether to generate descriptions for checks (if the user has not
15323 * provided them) based on the `expected` annotation of the check.
15324 */
15325 readonly generateDescriptions?: boolean | undefined
15326 /**
15327 * A predicate that controls which additional annotation keys (beyond the
15328 * standard JSON Schema keys) are included in the generated output.
15329 *
15330 * **When to use**
15331 *
15332 * Use when you need to include non-standard annotation keys in the generated
15333 * JSON Schema, such as Monaco Editor properties (`markdownDescription`,
15334 * `defaultSnippets`) or vendor extensions (`x-*`).
15335 *
15336 * **Details**
15337 *
15338 * Standard JSON Schema keys (`title`, `description`, `default`, `examples`,
15339 * `readOnly`, `writeOnly`, `format`, `contentEncoding`, `contentMediaType`,
15340 * `contentSchema`) are always included. This predicate is checked for any
15341 * *other* annotation key.
15342 *
15343 * **Gotchas**
15344 *
15345 * Prefer whitelisting the custom annotation keys you want to emit instead of
15346 * using a broad predicate such as `() => true`, because broad predicates can
15347 * include Effect-specific annotations that are preserved for internal schema
15348 * generation.
15349 *
15350 * **Example** (Including custom annotations)
15351 *
15352 * ```ts import.meta.vitest
15353 * import { Schema } from "effect"
15354 *
15355 * const schema = Schema.String.annotate({
15356 * description: "A name",
15357 * markdownDescription: "The **name** field"
15358 * })
15359 *
15360 * const doc = Schema.toJsonSchemaDocument(schema, {
15361 * includeAnnotationKey: (key) =>
15362 * key === "markdownDescription" || key.startsWith("x-")
15363 * })
15364 *
15365 * doc.schema // => { type: "string", description: "A name", markdownDescription: "The **name** field" }
15366 * ```
15367 */
15368 readonly includeAnnotationKey?: ((key: string) => boolean) | undefined
15369}
15370/**
15371 * Returns a JSON Schema document using draft 2020-12.
15372 *
15373 * **When to use**
15374 *
15375 * Use when you need a draft-2020-12 description of the canonical JSON form of a runtime schema.
15376 *
15377 * **Details**
15378 *
15379 * The document describes the encoded side of `Schema.toCodecJson(schema)`.
15380 * Use that codec to decode JSON inputs. For example, it decodes JSON `null`
15381 * to JavaScript `undefined` for a field defined with `Schema.optional(Schema.String)`.
15382 * Decoding the same input with the original schema rejects `null`.
15383 *
15384 * The `options` parameter controls reference extraction and generation details
15385 * such as excess properties and synthesized check descriptions; it does not
15386 * change the draft target. The reference policy receives canonical JSON
15387 * encoded ASTs. By default, anonymous non-recursive candidates remain inline,
15388 * while candidates with resolved identifiers become definitions. Declarations
15389 * are lowered through their `toCodecJson` or `toCodec` annotation when
15390 * available before the representation document is compiled.
15391 *
15392 * The generated document is intended for preliminary validation. JSON Schema
15393 * and Effect checks do not always have identical semantics, so the Effect
15394 * decoder remains the final authority. Passing JSON Schema validation does not
15395 * guarantee that Effect decoding will succeed.
15396 *
15397 * **Gotchas**
15398 *
15399 * JSON Schema generation is best-effort. String length uses Unicode code points
15400 * in JSON Schema and UTF-16 code units in Effect. A generated `pattern` cannot
15401 * retain JavaScript RegExp flags. Object property checks apply to the original
15402 * input in JSON Schema but to the decoded object in Effect. When a `oneOf`
15403 * branch contains a known approximation, the compiler emits `anyOf` so that
15404 * the approximation cannot create a false rejection. Unions with only exact
15405 * branches retain `oneOf`. Custom `toJsonSchema` callbacks return `[schema, true]` for safe,
15406 * looser approximations and are responsible for the semantics they declare. When
15407 * canonical JSON derivation adds an artificial transformation, checks and
15408 * annotations on its source node are not copied to the JSON target, so they do
15409 * not appear in the emitted document. Opaque declarations without a structural
15410 * codec are represented by an unconstrained JSON Schema. The default
15411 * `onExcessProperty: "ignore"` matches the decoder default and leaves
15412 * index-signature keys without exact selectors open. In `"error"` mode, the compiler
15413 * constrains those keys with `propertyNames` and applies a permissive choice of
15414 * candidate index value schemas. The Effect decoder enforces the exact
15415 * key-value association.
15416 *
15417 * **Example** (Decoding JSON with the matching codec)
15418 *
15419 * ```ts import.meta.vitest
15420 * import { Schema } from "effect"
15421 *
15422 * const schema = Schema.Struct({
15423 * name: Schema.optional(Schema.String)
15424 * })
15425 *
15426 * const document = Schema.toJsonSchemaDocument(schema)
15427 * const jsonCodec = Schema.toCodecJson(schema)
15428 *
15429 * Schema.decodeUnknownResult(schema)({ name: null })._tag // => "Failure"
15430 * Schema.decodeUnknownSync(jsonCodec)({ name: null }) // => { name: undefined }
15431 * Schema.decodeUnknownSync(jsonCodec)({}) // => {}
15432 * Schema.encodeSync(jsonCodec)({ name: undefined }) // => { name: null }
15433 * ```
15434 *
15435 * @see {@link toCodecJson} for decoding and encoding the canonical JSON representation
15436 * @see {@link SchemaRepresentation.toJsonSchemaDocument} for compiling an existing live representation document
15437 *
15438 * @category converting
15439 * @since 4.0.0
15440 */
15441export function toJsonSchemaDocument(
15442 schema: Constraint,
15443 options?: ToJsonSchemaOptions
15444): JsonSchema.Document<"draft-2020-12"> {
15445 const document = InternalToRepresentation.toRepresentation(
15446 InternalToCodec.toCodecJsonAST(schema.ast),
15447 options
15448 )
15449 return InternalToJsonSchemaDocument.toJsonSchemaDocument(document, options)
15450}
15451/**
15452 * Type-level representation returned by {@link toCodecJson}.
15453 *
15454 * @category converting
15455 * @since 4.0.0
15456 */
15457export interface toCodecJson<S extends Constraint> extends
15458 BottomLazy<
15459 S["ast"],
15460 toCodecJson<S>,
15461 S["~type.parameters"],
15462 S["~type.mutability"],
15463 S["~type.optionality"],
15464 S["~type.constructor.default"],
15465 S["~encoded.mutability"],
15466 S["~encoded.optionality"]
15467 >
15468{
15469 readonly "Type": S["Type"]
15470 readonly "Encoded": Json
15471 readonly "DecodingServices": S["DecodingServices"]
15472 readonly "EncodingServices": S["EncodingServices"]
15473 readonly "~type.make.in": S["~type.make.in"]
15474 readonly "~type.make": S["~type.make"]
15475 readonly "Iso": S["Iso"]
15476 readonly schema: S
15477}
15478/**
15479 * Derives a canonical JSON codec from a schema. The encoded form is `Json`, and
15480 * decoding produces the schema's `Type`.
15481 *
15482 * **Details**
15483 *
15484 * Derivation does not run transformations. Annotation links may be asynchronous,
15485 * may fail, and may use optional services; the consuming parser chooses the
15486 * execution and failure handling. Because hooks do not widen the returned
15487 * service types, links cannot require services not declared by the input schema.
15488 *
15489 * **Gotchas**
15490 *
15491 * Declarations without a `toCodecJson` or `toCodec` annotation use `Json` as
15492 * their encoded schema. This keeps codec construction total, but encoding or
15493 * decoding can still fail when declaration values are not JSON values. A
15494 * `toCodecJson` callback can return `undefined` when the declaration is already
15495 * in canonical JSON form. When derivation adds an artificial transformation,
15496 * checks and annotations remain on its source node rather than being copied to
15497 * the JSON target. Source checks still run after the transformation.
15498 *
15499 * @category converting
15500 * @since 4.0.0
15501 */
15502export const toCodecJson: {
15503 <S extends Constraint>(schema: S): toCodecJson<S>
15504} = InternalToCodec.toCodecJson
15505/**
15506 * Derives an isomorphism codec from a schema. The encoded form is the schema's
15507 * `Iso` type — the intermediate representation used for round-tripping.
15508 *
15509 * **Details**
15510 *
15511 * Annotation links may be asynchronous, may fail, and may use optional services;
15512 * the consuming parser chooses the execution and failure handling.
15513 *
15514 * **Gotchas**
15515 *
15516 * Links cannot require services because the returned `Codec` does not expose
15517 * service requirements.
15518 *
15519 * @category converting
15520 * @since 4.0.0
15521 */
15522export const toCodecIso: {
15523 <S extends Constraint>(schema: S): Codec<S["Type"], S["Iso"]>
15524} = InternalToCodec.toCodecIso
15525/**
15526 * A {@link Tree} of `string | undefined` nodes. Leaf values are either a
15527 * string representation or `undefined` for opaque/declaration types.
15528 *
15529 * @category models
15530 * @since 4.0.0
15531 */
15532export type StringTree = Tree<string | undefined>
15533/**
15534 * Type-level representation returned by {@link toCodecStringTree}.
15535 *
15536 * @category converting
15537 * @since 4.0.0
15538 */
15539export interface toCodecStringTree<S extends Constraint> extends
15540 BottomLazy<
15541 S["ast"],
15542 toCodecStringTree<S>,
15543 ReadonlyArray<Constraint>,
15544 S["~type.mutability"],
15545 S["~type.optionality"],
15546 S["~type.constructor.default"],
15547 S["~encoded.mutability"],
15548 S["~encoded.optionality"]
15549 >
15550{
15551 readonly "Type": S["Type"]
15552 readonly "Encoded": StringTree
15553 readonly "DecodingServices": S["DecodingServices"]
15554 readonly "EncodingServices": S["EncodingServices"]
15555 readonly "~type.make.in": S["~type.make.in"]
15556 readonly "~type.make": S["~type.make"]
15557 readonly "Iso": S["Iso"]
15558 readonly schema: S
15559}
15560/**
15561 * Converts a schema to the StringTree canonical codec, where every leaf value
15562 * becomes a string while preserving the original structure.
15563 *
15564 * **Details**
15565 *
15566 * Derivation does not run transformations. Annotation links may be asynchronous,
15567 * may fail, and may use optional services; the consuming parser chooses the
15568 * execution and failure handling. Links cannot require services not declared by
15569 * the input schema because hooks do not widen the returned service types.
15570 *
15571 * **Gotchas**
15572 *
15573 * Declarations must provide a structural `toCodecStringTree`, `toCodecJson`, or
15574 * `toCodec` encoding. A callback can return `undefined` when the declaration is
15575 * already in canonical StringTree form.
15576 *
15577 * @category converting
15578 * @since 4.0.0
15579 */
15580export const toCodecStringTree: {
15581 <S extends Constraint>(schema: S): toCodecStringTree<S>
15582} = InternalToCodec.toCodecStringTree
15583/**
15584 * Type-level representation returned by {@link toCodecArrayFromSingle}.
15585 *
15586 * @category converting
15587 * @since 4.0.0
15588 */
15589export interface toCodecArrayFromSingle<S extends Constraint> extends
15590 BottomLazy<
15591 S["ast"],
15592 toCodecArrayFromSingle<S>,
15593 S["~type.parameters"],
15594 S["~type.mutability"],
15595 S["~type.optionality"],
15596 S["~type.constructor.default"],
15597 S["~encoded.mutability"],
15598 S["~encoded.optionality"]
15599 >
15600{
15601 readonly "Type": S["Type"]
15602 readonly "Encoded": S["Encoded"]
15603 readonly "DecodingServices": S["DecodingServices"]
15604 readonly "EncodingServices": S["EncodingServices"]
15605 readonly "~type.make.in": S["~type.make.in"]
15606 readonly "~type.make": S["~type.make"]
15607 readonly "Iso": S["Iso"]
15608}
15609/**
15610 * Allows array schemas to decode from either an array input or a single value
15611 * input.
15612 *
15613 * **When to use**
15614 *
15615 * Use when you need to accept transport formats that may represent a
15616 * single-item array as a bare value, such as query-string or form-data adapters.
15617 *
15618 * **Gotchas**
15619 *
15620 * This combinator is intentionally not part of `toCodecStringTree`; it adds a
15621 * decoding convenience rather than a canonical StringTree representation. It
15622 * does not parse comma-separated strings.
15623 *
15624 * @category converting
15625 * @since 4.0.0
15626 */
15627export const toCodecArrayFromSingle: {
15628 <S extends Constraint>(schema: S): toCodecArrayFromSingle<S>
15629} = InternalToCodec.toCodecArrayFromSingle
15630type XmlEncoderOptions = {
15631 /** Root element name for the returned XML string. Default: "root" */
15632 readonly rootName?: string | undefined
15633 /** When an array doesn't have a natural item name, use this. Default: "item" */
15634 readonly arrayItemName?: string | undefined
15635 /** Pretty-print output. Default: true */
15636 readonly pretty?: boolean | undefined
15637 /** Indentation used when pretty-printing. Default: " " (two spaces) */
15638 readonly indent?: string | undefined
15639 /** Sort object keys for stable output. Default: true */
15640 readonly sortKeys?: boolean | undefined
15641}
15642/**
15643 * Derives an XML encoder from a codec.
15644 *
15645 * **Details**
15646 *
15647 * The returned function encodes a value through `toCodecStringTree` and returns
15648 * an `Effect` that succeeds with the XML string or fails with a
15649 * {@link SchemaIssue.Issue} if codec encoding fails.
15650 *
15651 * @category encoding
15652 * @since 4.0.0
15653 */
15654export function toEncoderXml<T, RE>(
15655 codec: ConstraintCodec<T, unknown, unknown, RE>,
15656 options?: XmlEncoderOptions
15657): (t: T) => Effect.Effect<string, SchemaIssue.Issue, RE> {
15658 return InternalToEncoderXml.toEncoderXml(codec, options)
15659}
15660/**
15661 * Derives an `Iso` optic from a schema that isomorphically converts between
15662 * the schema's `Type` and its `Iso` (intermediate / serialized form).
15663 *
15664 * **Details**
15665 *
15666 * Reading through the `Iso` encodes the schema value, while replacing through
15667 * it decodes the new focus.
15668 *
15669 * **Gotchas**
15670 *
15671 * This API runs synchronously, so failing, asynchronous, or service-dependent
15672 * transformations can throw. Schema failures use `"Schema validation failed"`
15673 * with a `SchemaIssue.Issue` in `cause`; format it with
15674 * `SchemaIssue.makeFormatterDefault()`. Consume {@link toCodecIso} with an
15675 * effectful parser for asynchronous execution or explicit failure handling.
15676 *
15677 * @category converting
15678 * @since 4.0.0
15679 */
15680export function toIso<S extends Constraint>(schema: S): Optic_.Iso<S["Type"], S["Iso"]> {
15681 return InternalToIso.toIso(schema)
15682}
15683/**
15684 * Returns an identity `Iso` over the schema's source (`Type`) side.
15685 *
15686 * @category constructors
15687 * @since 4.0.0
15688 */
15689export function toIsoSource<S extends Constraint>(schema: S): Optic_.Iso<S["Type"], S["Type"]> {
15690 return InternalToIso.toIsoSource(schema)
15691}
15692/**
15693 * Returns an identity `Iso` over the schema's focus (`Iso`) side.
15694 *
15695 * @category constructors
15696 * @since 4.0.0
15697 */
15698export function toIsoFocus<S extends Constraint>(schema: S): Optic_.Iso<S["Iso"], S["Iso"]> {
15699 return InternalToIso.toIsoFocus(schema)
15700}
15701/**
15702 * Type-level representation returned by {@link overrideToCodecIso}.
15703 *
15704 * @category transforming
15705 * @since 4.0.0
15706 */
15707export interface overrideToCodecIso<S extends Constraint, Iso> extends
15708 BottomLazy<
15709 S["ast"],
15710 overrideToCodecIso<S, Iso>,
15711 S["~type.parameters"],
15712 S["~type.mutability"],
15713 S["~type.optionality"],
15714 S["~type.constructor.default"],
15715 S["~encoded.mutability"],
15716 S["~encoded.optionality"]
15717 >
15718{
15719 readonly "Type": S["Type"]
15720 readonly "Encoded": S["Encoded"]
15721 readonly "DecodingServices": S["DecodingServices"]
15722 readonly "EncodingServices": S["EncodingServices"]
15723 readonly "~type.make.in": S["~type.make.in"]
15724 readonly "~type.make": S["~type.make"]
15725 readonly "Iso": Iso
15726 readonly schema: S
15727}
15728/**
15729 * Overrides a schema's derived ISO codec with an explicit target codec.
15730 *
15731 * **When to use**
15732 *
15733 * Use to provide a custom ISO transformation when the default derivation is not
15734 * appropriate.
15735 *
15736 * **Details**
15737 *
15738 * The resulting schema carries a custom `Iso` type parameter and uses the
15739 * provided `decode` and `encode` getters to transform between the schema type
15740 * and the target codec.
15741 *
15742 * @category transforming
15743 * @since 4.0.0
15744 */
15745export function overrideToCodecIso<S extends Constraint, Iso>(
15746 to: ConstraintCodec<Iso>,
15747 transformation: {
15748 readonly decode: SchemaGetter.Getter<S["Type"], Iso>
15749 readonly encode: SchemaGetter.Getter<Iso, S["Type"]>
15750 }
15751) {
15752 return (schema: S): overrideToCodecIso<S, Iso> => {
15753 return make(
15754 SchemaAST.annotate(schema.ast, {
15755 toCodecIso: () => new SchemaAST.Link(to.ast, SchemaTransformation.makeTransformation(transformation))
15756 }),
15757 { schema }
15758 )
15759 }
15760}
15761/**
15762 * Derives a JSON Patch differ from a codec. Serializes values to JSON (via
15763 * {@link toCodecJson}), computes RFC 6902 JSON Patch operations between old
15764 * and new values, and can apply patches back to the typed value.
15765 *
15766 * **Details**
15767 *
15768 * `diff` encodes both values before computing the patch. `patch` encodes the old
15769 * value, applies the patch to its JSON representation, and decodes the result.
15770 *
15771 * **Gotchas**
15772 *
15773 * This API runs synchronously, so failing, asynchronous, or service-dependent
15774 * transformations can throw. Schema failures use `"Schema validation failed"`
15775 * with a `SchemaIssue.Issue` in `cause`; format it with
15776 * `SchemaIssue.makeFormatterDefault()`. Invalid patch operations instead produce
15777 * {@link JsonPatch.apply} errors.
15778 *
15779 * @category converting
15780 * @since 4.0.0
15781 */
15782export function toDifferJsonPatch<T>(schema: ConstraintCodec<T, unknown>): Differ<T, JsonPatch.JsonPatch> {
15783 return InternalToDifferJsonPatch.toDifferJsonPatch(schema)
15784}
15785/**
15786 * Recursive tree type whose leaves are `Node` values and whose branches are
15787 * readonly arrays or string-keyed records of child trees.
15788 *
15789 * @category models
15790 * @since 4.0.0
15791 */
15792export type Tree<Node> = Node | TreeRecord<Node> | ReadonlyArray<Tree<Node>>
15793/**
15794 * A record node in a {@link Tree}: an object mapping string keys to child
15795 * `Tree` nodes.
15796 *
15797 * @category models
15798 * @since 4.0.0
15799 */
15800export interface TreeRecord<A> {
15801 readonly [x: string]: Tree<A>
15802}
15803/**
15804 * Creates a recursive schema for a {@link Tree} of values described by `node`.
15805 * The resulting schema accepts a single node value, an array of trees, or an
15806 * object whose values are trees.
15807 *
15808 * @category schemas
15809 * @since 4.0.0
15810 */
15811export function Tree<S extends Constraint>(node: S) {
15812 const Tree$ref = suspend((): Codec<
15813 Tree<S["Type"]>,
15814 Tree<S["Encoded"]>,
15815 S["DecodingServices"],
15816 S["EncodingServices"]
15817 > => Tree)
15818 const Tree = Union([
15819 node,
15820 ArraySchema(Tree$ref),
15821 Record(String, Tree$ref)
15822 ])
15823 return Tree
15824}
15825/**
15826 * Recursive TypeScript type for any valid immutable JSON value: `null`,
15827 * `number`, `boolean`, `string`, a readonly array of `Json` values, or a
15828 * readonly record of `string → Json`. For the corresponding schema, see the
15829 * {@link Json} const.
15830 *
15831 * @category models
15832 * @since 4.0.0
15833 */
15834export type Json = null | number | boolean | string | JsonArray | JsonObject
15835/**
15836 * A readonly array of {@link Json} values.
15837 *
15838 * @category models
15839 * @since 4.0.0
15840 */
15841export interface JsonArray extends ReadonlyArray<Json> {}
15842/**
15843 * A readonly record whose values are {@link Json} values.
15844 *
15845 * @category models
15846 * @since 4.0.0
15847 */
15848export interface JsonObject {
15849 readonly [x: string]: Json
15850}
15851/**
15852 * Schema that accepts and validates any immutable JSON-compatible value.
15853 *
15854 * **Example** (Validating a JSON value)
15855 *
15856 * ```ts import.meta.vitest
15857 * import { Option, Schema } from "effect"
15858 *
15859 * Schema.decodeUnknownOption(Schema.Json)({ key: [1, true, null] }) // => Option.some({ key: [1, true, null] })
15860 * ```
15861 *
15862 * @category schemas
15863 * @since 4.0.0
15864 */
15865export const Json: Codec<Json> = make(SchemaAST.annotate(SchemaAST.Json, {
15866 toCode: () => ({
15867 runtime: "Schema.Json",
15868 Type: "Schema.Json"
15869 })
15870}))
15871/**
15872 * Schema for readonly string-keyed records whose values are JSON-compatible.
15873 *
15874 * **When to use**
15875 *
15876 * Use when you need to validate a JSON object rather than any JSON value.
15877 *
15878 * **Example** (Validating a JSON object)
15879 *
15880 * ```ts import.meta.vitest
15881 * import { Option, Schema } from "effect"
15882 *
15883 * Schema.decodeUnknownOption(Schema.JsonObject)({ key: [1, true, null] }) // => Option.some({ key: [1, true, null] })
15884 * Schema.decodeUnknownOption(Schema.JsonObject)([1, 2, 3]) // => Option.none()
15885 * ```
15886 *
15887 * @see {@link Json} for a schema that also accepts JSON arrays and primitive values
15888 * @category schemas
15889 * @since 4.0.0
15890 */
15891export const JsonObject: $Record<String, Codec<Json, Json, never, never>> = Record(String, Json)
15892/**
15893 * Recursive TypeScript type for mutable JSON values: `null`, `number`,
15894 * `boolean`, `string`, mutable arrays, or mutable string-keyed records.
15895 *
15896 * @category models
15897 * @since 4.0.0
15898 */
15899export type MutableJson = null | number | boolean | string | MutableJsonArray | MutableJsonObject
15900/**
15901 * A mutable array of {@link MutableJson} values.
15902 *
15903 * @category models
15904 * @since 4.0.0
15905 */
15906export interface MutableJsonArray extends Array<MutableJson> {}
15907/**
15908 * A mutable record whose values are {@link MutableJson} values.
15909 *
15910 * @category models
15911 * @since 4.0.0
15912 */
15913export interface MutableJsonObject {
15914 [x: string]: MutableJson
15915}
15916
15917const JsonError = Struct({
15918 message: String,
15919 name: optionalKey(String),
15920 stack: optionalKey(String),
15921 cause: optionalKey(Json)
15922})
15923/**
15924 * Schema that accepts any mutable JSON-compatible value. See {@link Json} for
15925 * the immutable variant.
15926 *
15927 * @category schemas
15928 * @since 4.0.0
15929 */
15930export const MutableJson: Codec<MutableJson> = make(SchemaAST.annotate(SchemaAST.MutableJson, {
15931 toCode: () => ({
15932 runtime: "Schema.MutableJson",
15933 Type: "Schema.MutableJson"
15934 })
15935}))
15936/**
15937 * Resolves the typed annotations from a schema. The term "resolve" (rather
15938 * than "get") reflects the lookup strategy: if the schema has checks, the
15939 * annotations are taken from the last check; otherwise they are taken from
15940 * the base schema instance.
15941 *
15942 * @category getters
15943 * @since 4.0.0
15944 */
15945export function resolveAnnotations<S extends Constraint>(
15946 schema: S
15947): Annotations.Bottom<S["Type"], S["~type.parameters"]> | undefined {
15948 return InternalAnnotations.resolve(schema.ast)
15949}
15950/**
15951 * Resolves the context (key-level) annotations from a schema. Context
15952 * annotations are those attached via `annotateKey` and live on the AST's
15953 * `context` rather than on the schema node itself.
15954 *
15955 * @category getters
15956 * @since 4.0.0
15957 */
15958export function resolveAnnotationsKey<S extends Constraint>(schema: S): Annotations.Key<S["Type"]> | undefined {
15959 return schema.ast.context?.annotations
15960}
15961/**
15962 * The `Annotations` namespace groups all annotation interfaces used to attach
15963 * metadata to schemas. Annotations control documentation, validation messages,
15964 * JSON Schema generation, equivalence, arbitrary generation, and more.
15965 *
15966 * **Details**
15967 *
15968 * Use {@link resolveAnnotations} to read the annotations attached to a schema at
15969 * runtime.
15970 *
15971 * @category models
15972 * @since 4.0.0
15973 */
15974export declare namespace Annotations {
15975 /**
15976 * This interface is used to define the annotations that can be attached to a
15977 * schema. You can extend this interface to define your own annotations.
15978 *
15979 * **Details**
15980 *
15981 * Note that both a missing key or `undefined` is used to indicate that the
15982 * annotation is not present.
15983 *
15984 * This means that can remove any annotation by setting it to `undefined`.
15985 *
15986 * **Example** (Defining your own annotations)
15987 *
15988 * ```ts import.meta.vitest
15989 * import { Schema } from "effect"
15990 *
15991 * // Extend the Annotations interface with a custom `version` annotation
15992 * declare module "effect/Schema" {
15993 * namespace Annotations {
15994 * interface Annotations {
15995 * readonly version?:
15996 * | readonly [major: number, minor: number, patch: number]
15997 * | undefined
15998 * }
15999 * }
16000 * }
16001 *
16002 * // The `version` annotation is now recognized by the TypeScript compiler
16003 * const schema = Schema.String.annotate({ version: [1, 2, 0] })
16004 *
16005 * // const version: readonly [major: number, minor: number, patch: number] | undefined
16006 * const version = Schema.resolveAnnotations(schema)?.["version"]
16007 *
16008 * if (version) {
16009 * // Access individual parts of the version
16010 * version[1] // => 2
16011 * }
16012 * ```
16013 *
16014 * @category models
16015 * @since 4.0.0
16016 */
16017 interface Annotations {
16018 readonly [x: string]: unknown
16019 }
16020 /**
16021 * Annotations shared by all schema nodes. These map to common JSON Schema /
16022 * OpenAPI fields: `title`, `description`, `format`, etc.
16023 *
16024 * @category models
16025 * @since 4.0.0
16026 */
16027 interface Augment extends Annotations {
16028 /**
16029 * Human-readable description of what a value is expected to satisfy.
16030 *
16031 * **Details**
16032 *
16033 * For filter and refinement failures, the default formatter uses
16034 * `message` first, then `expected`, and finally falls back to `<filter>`.
16035 *
16036 * Use this to name a failed filter in the default message:
16037 * `Expected <expected>`.
16038 */
16039 readonly expected?: string | undefined
16040 readonly title?: string | undefined
16041 readonly description?: string | undefined
16042 readonly documentation?: string | undefined
16043 readonly readOnly?: boolean | undefined
16044 readonly writeOnly?: boolean | undefined
16045 readonly format?: string | undefined
16046 readonly contentEncoding?: string | undefined
16047 readonly contentMediaType?: string | undefined
16048 readonly contentSchema?: Json | undefined
16049 }
16050 /**
16051 * Extends {@link Augment} with type-parametric `default` and `examples` fields.
16052 *
16053 * @category models
16054 * @since 4.0.0
16055 */
16056 interface Documentation<T> extends Augment {
16057 readonly default?: T | undefined
16058 readonly examples?: ReadonlyArray<T> | undefined
16059 }
16060 /**
16061 * Annotations for struct property schemas. Extends {@link Documentation}
16062 * with an optional `messageMissingKey` to override the error message when
16063 * the property key is absent during decoding.
16064 *
16065 * @category models
16066 * @since 4.0.0
16067 */
16068 interface Key<T> extends Documentation<T> {
16069 /**
16070 * The message to use when a key is missing.
16071 */
16072 readonly messageMissingKey?: string | undefined
16073 }
16074 /**
16075 * Base annotations shared by all composite schema nodes. Extends
16076 * {@link Documentation} with error messages and arbitrary generation hooks.
16077 * {@link Declaration} and other annotation
16078 * interfaces build on top of this.
16079 *
16080 * @category models
16081 * @since 4.0.0
16082 */
16083 interface Bottom<T, TypeParameters extends ReadonlyArray<Constraint>> extends Documentation<T> {
16084 /**
16085 * Complete message to use when this schema node reports an issue.
16086 *
16087 * **Details**
16088 *
16089 * This replaces the default message for matching issue types instead of
16090 * only changing the expected label. For a filter or refinement failure,
16091 * annotate the filter with `message` to replace the whole filter failure
16092 * message, or `expected` to keep the default
16093 * `Expected <expected>` shape.
16094 */
16095 readonly message?: string | undefined
16096 /**
16097 * The message to use when a key is unexpected.
16098 */
16099 readonly messageUnexpectedKey?: string | undefined
16100 /**
16101 * Stable identifier for this schema node.
16102 *
16103 * **Details**
16104 *
16105 * Identifiers are used by schema tooling, including JSON Schema
16106 * generation, to name references. The default formatter also uses
16107 * `identifier` as the expected label for type-level failures, such as
16108 * `Expected UserId`.
16109 *
16110 * `identifier` does not name a failed filter or refinement. If the base
16111 * type matches and a filter fails, put `expected` or `message` on the
16112 * filter/refinement instead.
16113 */
16114 readonly identifier?: string | undefined
16115 }
16116 /**
16117 * Helpers for projecting declaration type-parameter schemas into decoded or
16118 * encoded codec arrays used by annotation hooks.
16119 *
16120 * @since 4.0.0
16121 */
16122 namespace TypeParameters {
16123 /**
16124 * Maps declaration type-parameter schemas to codecs for their decoded `Type`
16125 * values.
16126 *
16127 * @category utility types
16128 * @since 4.0.0
16129 */
16130 type Type<TypeParameters extends ReadonlyArray<Constraint>> = {
16131 readonly [K in keyof TypeParameters]: Codec<TypeParameters[K]["Type"]>
16132 }
16133 /**
16134 * Maps declaration type-parameter schemas to codecs for their `Encoded` values.
16135 *
16136 * @category utility types
16137 * @since 4.0.0
16138 */
16139 type Encoded<TypeParameters extends ReadonlyArray<Constraint>> = {
16140 readonly [K in keyof TypeParameters]: Codec<TypeParameters[K]["Encoded"]>
16141 }
16142 }
16143 /**
16144 * Full annotation set for `Declaration` schema nodes — used when defining
16145 * custom, opaque schema types via `Schema.declare`. Extends {@link Bottom}
16146 * with optional codec, arbitrary, equivalence, and formatter hooks so that
16147 * derived capabilities (JSON encoding, property testing, etc.) can be
16148 * provided for the custom type.
16149 *
16150 * @category models
16151 * @since 4.0.0
16152 */
16153 interface Declaration<T, TypeParameters extends ReadonlyArray<Constraint> = readonly []>
16154 extends Bottom<T, TypeParameters>
16155 {
16156 readonly representation?: SchemaRepresentation.RepresentationAnnotation | undefined
16157 /**
16158 * Returns the fallback link used by canonical codec derivations.
16159 *
16160 * **Details**
16161 *
16162 * Transformations may be asynchronous, may fail, and may use optional
16163 * services, but cannot require services absent from the derived codec type.
16164 */
16165 readonly toCodec?: ((typeParameters: TypeParameters.Encoded<TypeParameters>) => SchemaAST.Link) | undefined
16166 /**
16167 * Returns the link used to derive the declaration's JSON representation, or
16168 * `undefined` when the declaration is already in canonical JSON form.
16169 *
16170 * **Details**
16171 *
16172 * Transformations follow the execution and service constraints of `toCodec`.
16173 */
16174 readonly toCodecJson?:
16175 | ((typeParameters: TypeParameters.Encoded<TypeParameters>) => SchemaAST.Link | undefined)
16176 | undefined
16177 /**
16178 * Returns the link used to derive the declaration's StringTree
16179 * representation, or `undefined` when it is already canonical.
16180 *
16181 * **Details**
16182 *
16183 * Transformations follow the execution and service constraints of `toCodec`.
16184 */
16185 readonly toCodecStringTree?:
16186 | ((typeParameters: TypeParameters.Encoded<TypeParameters>) => SchemaAST.Link | undefined)
16187 | undefined
16188 /**
16189 * Returns the link used to derive the declaration's isomorphism
16190 * representation.
16191 *
16192 * **Details**
16193 *
16194 * Transformations may be asynchronous, may fail, and may use optional
16195 * services, but cannot require services because the derived `Codec` exposes
16196 * none.
16197 */
16198 readonly toCodecIso?: ((typeParameters: TypeParameters.Type<TypeParameters>) => SchemaAST.Link) | undefined
16199 /**
16200 * Provides a generatable representation for native arbitrary derivation.
16201 *
16202 * **Details**
16203 *
16204 * The callback receives decoded type-parameter schemas and normalized constraints for the declaration. The returned
16205 * Link is preferred over canonical codec annotations by the native arbitrary compiler. Generated representation
16206 * values are decoded and checked against the declaration, so the Link may be asynchronous or partial. As with the
16207 * other `toCodec*` hooks, the Link cannot require additional services because the derived `Arbitrary` exposes none.
16208 *
16209 * This annotation is experimental and may change while native arbitrary generation remains unstable.
16210 *
16211 * @since 4.0.0
16212 */
16213 readonly toCodecArbitrary?: ToArbitrary.Declaration<T, TypeParameters> | undefined
16214 readonly toEquivalence?: ToEquivalence.Declaration<T, TypeParameters> | undefined
16215 readonly toFormatter?: ToFormatter.Declaration<T, TypeParameters> | undefined
16216 readonly toCode?: SchemaRepresentation.Generation.Declaration | undefined
16217 /**
16218 * Used to collect sentinels from a Declaration SchemaAST.
16219 *
16220 * @internal
16221 */
16222 readonly "~sentinels"?: ReadonlyArray<SchemaAST.Sentinel> | undefined
16223 }
16224 /**
16225 * Annotations for filter schema nodes (created via `Schema.filter`). Extends
16226 * {@link Augment} with an optional error message, identifier, and metadata.
16227 * Filters are intentionally non-parametric to keep them covariant.
16228 *
16229 * @category models
16230 * @since 4.0.0
16231 */
16232 interface Filter extends Augment {
16233 readonly representation?: SchemaRepresentation.CheckRepresentationAnnotation<SchemaAST.AST> | undefined
16234 /**
16235 * Compiles this filter to a JSON Schema fragment.
16236 *
16237 * **Details**
16238 *
16239 * Return the fragment directly for an exact translation or `[fragment, true]`
16240 * for a safe, looser approximation. Use `[{}, true]` to omit the constraint.
16241 * Approximation propagates from `representation.schemas` automatically. It
16242 * makes enclosing `oneOf` unions export as `anyOf` and prevents approximate
16243 * record-key patterns from selecting `patternProperties` values.
16244 *
16245 * **Gotchas**
16246 *
16247 * The compiler trusts the declared semantics. Treat the input schemas as immutable. The returned fragment must be
16248 * a valid JSON Schema object graph and must not be mutated after this function returns. Return a new object graph
16249 * to produce different output during a later compilation.
16250 *
16251 * @see {@link SchemaRepresentation.ToJsonSchema.CheckOutput} for the result contract
16252 */
16253 readonly toJsonSchema?: SchemaRepresentation.ToJsonSchema.Check | undefined
16254 readonly toCode?: SchemaRepresentation.Generation.Check | undefined
16255 /**
16256 * Complete message to use when this filter or refinement fails.
16257 *
16258 * **Details**
16259 *
16260 * The default formatter checks filter annotations in this order:
16261 * `message`, then `expected`, then `<filter>`.
16262 */
16263 readonly message?: string | undefined
16264 /**
16265 * Stable identifier for the schema after this filter is attached.
16266 *
16267 * **Details**
16268 *
16269 * This can affect schema tooling such as JSON Schema generation and
16270 * type-level failures before the filter runs, but it does not name the
16271 * failed filter itself. For filter failure messages, use `expected` or
16272 * `message`.
16273 */
16274 readonly identifier?: string | undefined
16275 /**
16276 * Native arbitrary-generation hints for this filter.
16277 *
16278 * **Details**
16279 *
16280 * The value is declarative metadata merged with constraints from the other filters on the node. The filter
16281 * predicate remains authoritative.
16282 *
16283 * @since 4.0.0
16284 */
16285 readonly arbitraryConstraint?: ToArbitrary.FilterConstraint<any> | undefined
16286 /**
16287 * Marks the filter as *structural*, meaning it applies to the shape or
16288 * structure of the container (e.g., array length, object keys) rather than
16289 * the contents.
16290 *
16291 * **Details**
16292 *
16293 * Reserved to internal use only.
16294 *
16295 * Example: `minLength` on an array is a structural filter.
16296 */
16297 readonly "~structural"?: boolean | undefined
16298 }
16299 /**
16300 * Types used to guide native arbitrary derivation through constraints and declaration representations.
16301 *
16302 * @since 4.0.0
16303 */
16304 namespace ToArbitrary {
16305 /**
16306 * Regular-expression source and flags used for constructive string generation.
16307 *
16308 * @category models
16309 * @since 4.0.0
16310 */
16311 interface Pattern {
16312 readonly source: string
16313 readonly flags: string
16314 }
16315 /**
16316 * Normalized generation constraints for a declaration or schema node.
16317 *
16318 * **Details**
16319 *
16320 * Missing fields are unconstrained. These values guide construction but do not replace Schema validation.
16321 *
16322 * @category models
16323 * @since 4.0.0
16324 */
16325 interface GenerationConstraint<T = unknown> {
16326 readonly minimum?: T | undefined
16327 readonly exclusiveMinimum?: true | undefined
16328 readonly maximum?: T | undefined
16329 readonly exclusiveMaximum?: true | undefined
16330 readonly minLength?: number | undefined
16331 readonly maxLength?: number | undefined
16332 readonly minCodePoints?: number | undefined
16333 readonly maxCodePoints?: number | undefined
16334 readonly minSize?: number | undefined
16335 readonly maxSize?: number | undefined
16336 readonly minProperties?: number | undefined
16337 readonly maxProperties?: number | undefined
16338 readonly patterns?: readonly [Pattern, ...Array<Pattern>]
16339 readonly number?: "finite" | "integer" | undefined
16340 readonly uniqueBy?: ((value: any) => unknown) | undefined
16341 }
16342 /**
16343 * Raw constraint contribution attached to a Schema filter.
16344 *
16345 * **Details**
16346 *
16347 * `order` identifies the domain while the compiler merges bounds. It is removed before normalized constraints reach
16348 * a declaration callback.
16349 *
16350 * @category models
16351 * @since 4.0.0
16352 */
16353 interface FilterConstraint<T = unknown> extends GenerationConstraint<T> {
16354 readonly order?: Order.Order<T> | undefined
16355 }
16356 /**
16357 * Input provided to a declaration's native arbitrary callback.
16358 *
16359 * @category models
16360 * @since 4.0.0
16361 */
16362 interface DeclarationInput<T, Parameters extends ReadonlyArray<Constraint>> {
16363 readonly typeParameters: TypeParameters.Type<Parameters>
16364 readonly constraint: GenerationConstraint<T> | undefined
16365 }
16366 /**
16367 * Selects a Schema Link whose source representation is optimized for native arbitrary generation.
16368 *
16369 * @category models
16370 * @since 4.0.0
16371 */
16372 interface Declaration<T, Parameters extends ReadonlyArray<Constraint>> {
16373 (input: DeclarationInput<T, Parameters>): SchemaAST.Link
16374 }
16375 }
16376 /**
16377 * Types used by formatter annotations to customize formatter derivation for
16378 * declaration schemas.
16379 *
16380 * @since 4.0.0
16381 */
16382 namespace ToFormatter {
16383 /**
16384 * Hook signature for declaration schema formatter annotations.
16385 *
16386 * **Details**
16387 *
16388 * Given formatters for any type parameters, returns a formatter for `T`.
16389 *
16390 * @category models
16391 * @since 4.0.0
16392 */
16393 interface Declaration<T, TypeParameters extends ReadonlyArray<Constraint>> {
16394 (
16395 typeParameters: {
16396 readonly [K in keyof TypeParameters]: Formatter<TypeParameters[K]["Type"]>
16397 }
16398 ): Formatter<T>
16399 }
16400 }
16401 /**
16402 * Types used by equivalence annotations to customize equivalence derivation for
16403 * declaration schemas.
16404 *
16405 * @since 4.0.0
16406 */
16407 namespace ToEquivalence {
16408 /**
16409 * Hook signature for declaration schema equivalence annotations.
16410 *
16411 * **Details**
16412 *
16413 * Given equivalences for any type parameters, returns an `Equivalence` for `T`.
16414 *
16415 * @category models
16416 * @since 4.0.0
16417 */
16418 interface Declaration<T, TypeParameters extends ReadonlyArray<Constraint>> {
16419 (
16420 typeParameters: {
16421 readonly [K in keyof TypeParameters]: Equivalence.Equivalence<TypeParameters[K]["Type"]>
16422 }
16423 ): Equivalence.Equivalence<T>
16424 }
16425 }
16426 /**
16427 * Annotations that can be attached to schema issues.
16428 *
16429 * **Details**
16430 *
16431 * For `InvalidValue` issues, `message` overrides the complete formatted
16432 * message. When `message` is absent, `expected` uses the default expected
16433 * value policy, including reported input when available. Other issue types
16434 * ignore `expected`.
16435 *
16436 * @category models
16437 * @since 4.0.0
16438 */
16439 interface Issue extends Annotations {
16440 /**
16441 * The expected value description for an `InvalidValue` issue.
16442 */
16443 readonly expected?: string | undefined
16444 /**
16445 * The complete formatted message for the issue.
16446 */
16447 readonly message?: string | undefined
16448 }
16449}