/** * @since 3.10.0 */ import * as array_ from "./Array.js"; import * as bigDecimal_ from "./BigDecimal.js"; import * as bigInt_ from "./BigInt.js"; import * as boolean_ from "./Boolean.js"; import * as cause_ from "./Cause.js"; import * as chunk_ from "./Chunk.js"; import * as config_ from "./Config.js"; import * as configError_ from "./ConfigError.js"; import * as data_ from "./Data.js"; import * as dateTime from "./DateTime.js"; import * as duration_ from "./Duration.js"; import * as Effect from "./Effect.js"; import * as either_ from "./Either.js"; import * as Encoding from "./Encoding.js"; import * as Equal from "./Equal.js"; import * as Equivalence from "./Equivalence.js"; import * as exit_ from "./Exit.js"; import * as fastCheck_ from "./FastCheck.js"; import * as fiberId_ from "./FiberId.js"; import { dual, identity } from "./Function.js"; import { globalValue } from "./GlobalValue.js"; import * as hashMap_ from "./HashMap.js"; import * as hashSet_ from "./HashSet.js"; import * as internalCause_ from "./internal/cause.js"; import * as errors_ from "./internal/schema/errors.js"; import * as schemaId_ from "./internal/schema/schemaId.js"; import * as util_ from "./internal/schema/util.js"; import * as list_ from "./List.js"; import * as number_ from "./Number.js"; import * as option_ from "./Option.js"; import * as ParseResult from "./ParseResult.js"; import { pipeArguments } from "./Pipeable.js"; import * as Predicate from "./Predicate.js"; import * as redacted_ from "./Redacted.js"; import * as Request from "./Request.js"; import * as scheduler_ from "./Scheduler.js"; import * as AST from "./SchemaAST.js"; import * as sortedSet_ from "./SortedSet.js"; import * as string_ from "./String.js"; import * as struct_ from "./Struct.js"; /** * @since 3.10.0 * @category symbol */ export const TypeId = /*#__PURE__*/Symbol.for("effect/Schema"); /** * @category constructors * @since 3.10.0 */ export function make(ast) { return class SchemaClass { [TypeId] = variance; static ast = ast; static annotations(annotations) { return make(mergeSchemaAnnotations(this.ast, annotations)); } static pipe() { return pipeArguments(this, arguments); } static toString() { return String(ast); } static Type; static Encoded; static Context; static [TypeId] = variance; }; } const variance = { /* c8 ignore next */ _A: _ => _, /* c8 ignore next */ _I: _ => _, /* c8 ignore next */ _R: _ => _ }; const makeStandardResult = exit => exit_.isSuccess(exit) ? exit.value : makeStandardFailureResult(cause_.pretty(exit.cause)); const makeStandardFailureResult = message => ({ issues: [{ message }] }); const makeStandardFailureFromParseIssue = issue => Effect.map(ParseResult.ArrayFormatter.formatIssue(issue), issues => ({ issues: issues.map(issue => ({ path: issue.path, message: issue.message })) })); /** * Returns a "Standard Schema" object conforming to the [Standard Schema * v1](https://standardschema.dev/) specification. * * This function creates a schema whose `validate` method attempts to decode and * validate the provided input synchronously. If the underlying `Schema` * includes any asynchronous components (e.g., asynchronous message resolutions * or checks), then validation will necessarily return a `Promise` instead. * * Any detected defects will be reported via a single issue containing no * `path`. * * @example * ```ts * import { Schema } from "effect" * * const schema = Schema.Struct({ * name: Schema.String * }) * * // ┌─── StandardSchemaV1<{ readonly name: string; }> * // ▼ * const standardSchema = Schema.standardSchemaV1(schema) * ``` * * @category Standard Schema * @since 3.13.0 */ export const standardSchemaV1 = (schema, overrideOptions) => { const decodeUnknown = ParseResult.decodeUnknown(schema, { errors: "all" }); return class StandardSchemaV1Class extends make(schema.ast) { static "~standard" = { version: 1, vendor: "effect", validate(value) { const scheduler = new scheduler_.SyncScheduler(); const fiber = Effect.runFork(Effect.matchEffect(decodeUnknown(value, overrideOptions), { onFailure: makeStandardFailureFromParseIssue, onSuccess: value => Effect.succeed({ value }) }), { scheduler }); scheduler.flush(); const exit = fiber.unsafePoll(); if (exit) { return makeStandardResult(exit); } return new Promise(resolve => { fiber.addObserver(exit => { resolve(makeStandardResult(exit)); }); }); } }; }; }; const builtInAnnotations = { schemaId: AST.SchemaIdAnnotationId, message: AST.MessageAnnotationId, missingMessage: AST.MissingMessageAnnotationId, identifier: AST.IdentifierAnnotationId, title: AST.TitleAnnotationId, description: AST.DescriptionAnnotationId, examples: AST.ExamplesAnnotationId, default: AST.DefaultAnnotationId, documentation: AST.DocumentationAnnotationId, jsonSchema: AST.JSONSchemaAnnotationId, arbitrary: AST.ArbitraryAnnotationId, pretty: AST.PrettyAnnotationId, equivalence: AST.EquivalenceAnnotationId, concurrency: AST.ConcurrencyAnnotationId, batching: AST.BatchingAnnotationId, parseIssueTitle: AST.ParseIssueTitleAnnotationId, parseOptions: AST.ParseOptionsAnnotationId, decodingFallback: AST.DecodingFallbackAnnotationId }; const toASTAnnotations = annotations => { if (!annotations) { return {}; } const out = { ...annotations }; for (const key in builtInAnnotations) { if (key in annotations) { const id = builtInAnnotations[key]; out[id] = annotations[key]; delete out[key]; } } return out; }; const mergeSchemaAnnotations = (ast, annotations) => AST.annotations(ast, toASTAnnotations(annotations)); /** * @since 3.10.0 */ export function asSchema(schema) { return schema; } /** * @category formatting * @since 3.10.0 */ export const format = schema => String(schema.ast); /** * The `encodedSchema` function allows you to extract the `Encoded` portion of a * schema, creating a new schema that conforms to the properties defined in the * original schema without retaining any refinements or transformations that * were applied previously. * * @since 3.10.0 */ export const encodedSchema = schema => make(AST.encodedAST(schema.ast)); /** * The `encodedBoundSchema` function is similar to `encodedSchema` but preserves * the refinements up to the first transformation point in the original schema. * * @since 3.10.0 */ export const encodedBoundSchema = schema => make(AST.encodedBoundAST(schema.ast)); /** * The `typeSchema` function allows you to extract the `Type` portion of a * schema, creating a new schema that conforms to the properties defined in the * original schema without considering the initial encoding or transformation * processes. * * @since 3.10.0 */ export const typeSchema = schema => make(AST.typeAST(schema.ast)); /* c8 ignore start */ export { /** * By default the option `exact` is set to `true`. * * @throws `ParseError` * @category validation * @since 3.10.0 */ asserts, /** * @category decoding * @since 3.10.0 */ decodeOption, /** * @throws `ParseError` * @category decoding * @since 3.10.0 */ decodeSync, /** * @category decoding * @since 3.10.0 */ decodeUnknownOption, /** * @throws `ParseError` * @category decoding * @since 3.10.0 */ decodeUnknownSync, /** * @category encoding * @since 3.10.0 */ encodeOption, /** * @throws `ParseError` * @category encoding * @since 3.10.0 */ encodeSync, /** * @category encoding * @since 3.10.0 */ encodeUnknownOption, /** * @throws `ParseError` * @category encoding * @since 3.10.0 */ encodeUnknownSync, /** * By default the option `exact` is set to `true`. * * @category validation * @since 3.10.0 */ is, /** * @category validation * @since 3.10.0 */ validateOption, /** * @throws `ParseError` * @category validation * @since 3.10.0 */ validateSync } from "./ParseResult.js"; /* c8 ignore end */ /** * @category encoding * @since 3.10.0 */ export const encodeUnknown = (schema, options) => { const encodeUnknown = ParseResult.encodeUnknown(schema, options); return (u, overrideOptions) => ParseResult.mapError(encodeUnknown(u, overrideOptions), ParseResult.parseError); }; /** * @category encoding * @since 3.10.0 */ export const encodeUnknownEither = (schema, options) => { const encodeUnknownEither = ParseResult.encodeUnknownEither(schema, options); return (u, overrideOptions) => either_.mapLeft(encodeUnknownEither(u, overrideOptions), ParseResult.parseError); }; /** * @category encoding * @since 3.10.0 */ export const encodeUnknownPromise = (schema, options) => { const parser = encodeUnknown(schema, options); return (u, overrideOptions) => Effect.runPromise(parser(u, overrideOptions)); }; /** * @category encoding * @since 3.10.0 */ export const encode = encodeUnknown; /** * @category encoding * @since 3.10.0 */ export const encodeEither = encodeUnknownEither; /** * @category encoding * @since 3.10.0 */ export const encodePromise = encodeUnknownPromise; /** * @category decoding * @since 3.10.0 */ export const decodeUnknown = (schema, options) => { const decodeUnknown = ParseResult.decodeUnknown(schema, options); return (u, overrideOptions) => ParseResult.mapError(decodeUnknown(u, overrideOptions), ParseResult.parseError); }; /** * @category decoding * @since 3.10.0 */ export const decodeUnknownEither = (schema, options) => { const decodeUnknownEither = ParseResult.decodeUnknownEither(schema, options); return (u, overrideOptions) => either_.mapLeft(decodeUnknownEither(u, overrideOptions), ParseResult.parseError); }; /** * @category decoding * @since 3.10.0 */ export const decodeUnknownPromise = (schema, options) => { const parser = decodeUnknown(schema, options); return (u, overrideOptions) => Effect.runPromise(parser(u, overrideOptions)); }; /** * @category decoding * @since 3.10.0 */ export const decode = decodeUnknown; /** * @category decoding * @since 3.10.0 */ export const decodeEither = decodeUnknownEither; /** * @category decoding * @since 3.10.0 */ export const decodePromise = decodeUnknownPromise; /** * @category validation * @since 3.10.0 */ export const validate = (schema, options) => { const validate = ParseResult.validate(schema, options); return (u, overrideOptions) => ParseResult.mapError(validate(u, overrideOptions), ParseResult.parseError); }; /** * @category validation * @since 3.10.0 */ export const validateEither = (schema, options) => { const validateEither = ParseResult.validateEither(schema, options); return (u, overrideOptions) => either_.mapLeft(validateEither(u, overrideOptions), ParseResult.parseError); }; /** * @category validation * @since 3.10.0 */ export const validatePromise = (schema, options) => { const parser = validate(schema, options); return (u, overrideOptions) => Effect.runPromise(parser(u, overrideOptions)); }; /** * Tests if a value is a `Schema`. * * @category guards * @since 3.10.0 */ export const isSchema = u => Predicate.hasProperty(u, TypeId) && Predicate.isObject(u[TypeId]); function getDefaultLiteralAST(literals) { return AST.isMembers(literals) ? AST.Union.make(AST.mapMembers(literals, literal => new AST.Literal(literal))) : new AST.Literal(literals[0]); } function makeLiteralClass(literals, ast = getDefaultLiteralAST(literals)) { return class LiteralClass extends make(ast) { static annotations(annotations) { return makeLiteralClass(this.literals, mergeSchemaAnnotations(this.ast, annotations)); } static literals = [...literals]; }; } export function Literal(...literals) { return array_.isNonEmptyReadonlyArray(literals) ? makeLiteralClass(literals) : Never; } /** * Creates a new `Schema` from a literal schema. * * @example * ```ts * import * as assert from "node:assert" * import { Either, Schema } from "effect" * * const schema = Schema.Literal("a", "b", "c").pipe(Schema.pickLiteral("a", "b")) * * assert.deepStrictEqual(Schema.decodeSync(schema)("a"), "a") * assert.deepStrictEqual(Schema.decodeSync(schema)("b"), "b") * assert.strictEqual(Either.isLeft(Schema.decodeUnknownEither(schema)("c")), true) * ``` * * @category constructors * @since 3.10.0 */ export const pickLiteral = (...literals) => _schema => Literal(...literals); /** * @category constructors * @since 3.10.0 */ export const UniqueSymbolFromSelf = symbol => make(new AST.UniqueSymbol(symbol)); const getDefaultEnumsAST = enums => new AST.Enums(Object.keys(enums).filter(key => typeof enums[enums[key]] !== "number").map(key => [key, enums[key]])); const makeEnumsClass = (enums, ast = getDefaultEnumsAST(enums)) => class EnumsClass extends make(ast) { static annotations(annotations) { return makeEnumsClass(this.enums, mergeSchemaAnnotations(this.ast, annotations)); } static enums = { ...enums }; }; /** * @category constructors * @since 3.10.0 */ export const Enums = enums => makeEnumsClass(enums); /** * @category template literal * @since 3.10.0 */ export const TemplateLiteral = (...[head, ...tail]) => { const spans = []; let h = ""; let ts = tail; if (isSchema(head)) { if (AST.isLiteral(head.ast)) { h = String(head.ast.literal); } else { ts = [head, ...ts]; } } else { h = String(head); } for (let i = 0; i < ts.length; i++) { const item = ts[i]; if (isSchema(item)) { if (i < ts.length - 1) { const next = ts[i + 1]; if (isSchema(next)) { if (AST.isLiteral(next.ast)) { spans.push(new AST.TemplateLiteralSpan(item.ast, String(next.ast.literal))); i++; continue; } } else { spans.push(new AST.TemplateLiteralSpan(item.ast, String(next))); i++; continue; } } spans.push(new AST.TemplateLiteralSpan(item.ast, "")); } else { spans.push(new AST.TemplateLiteralSpan(new AST.Literal(item), "")); } } if (array_.isNonEmptyArray(spans)) { return make(new AST.TemplateLiteral(h, spans)); } else { return make(new AST.TemplateLiteral("", [new AST.TemplateLiteralSpan(new AST.Literal(h), "")])); } }; function getTemplateLiteralParserCoercedElement(encoded, schema) { const ast = encoded.ast; switch (ast._tag) { case "Literal": { const literal = ast.literal; if (!Predicate.isString(literal)) { const s = String(literal); return transform(Literal(s), schema, { strict: true, decode: () => literal, encode: () => s }); } break; } case "NumberKeyword": return compose(NumberFromString, schema); case "Union": { const members = []; let hasCoercions = false; for (const member of ast.types) { const schema = make(member); const encoded = encodedSchema(schema); const coerced = getTemplateLiteralParserCoercedElement(encoded, schema); if (coerced) { hasCoercions = true; } members.push(coerced ?? schema); } return hasCoercions ? compose(Union(...members), schema) : schema; } } } /** * @category template literal * @since 3.10.0 */ export const TemplateLiteralParser = (...params) => { const encodedSchemas = []; const elements = []; const schemas = []; let coerced = false; for (let i = 0; i < params.length; i++) { const param = params[i]; const schema = isSchema(param) ? param : Literal(param); schemas.push(schema); const encoded = encodedSchema(schema); encodedSchemas.push(encoded); const element = getTemplateLiteralParserCoercedElement(encoded, schema); if (element) { elements.push(element); coerced = true; } else { elements.push(schema); } } const from = TemplateLiteral(...encodedSchemas); const re = AST.getTemplateLiteralCapturingRegExp(from.ast); let to = Tuple(...elements); if (coerced) { to = to.annotations({ [AST.AutoTitleAnnotationId]: format(Tuple(...schemas)) }); } return class TemplateLiteralParserClass extends transformOrFail(from, to, { strict: false, decode: (i, _, ast) => { const match = re.exec(i); return match ? ParseResult.succeed(match.slice(1, params.length + 1)) : ParseResult.fail(new ParseResult.Type(ast, i, `${re.source}: no match for ${JSON.stringify(i)}`)); }, encode: tuple => ParseResult.succeed(tuple.join("")) }) { static params = params.slice(); }; }; const declareConstructor = (typeParameters, options, annotations) => makeDeclareClass(typeParameters, new AST.Declaration(typeParameters.map(tp => tp.ast), (...typeParameters) => options.decode(...typeParameters.map(make)), (...typeParameters) => options.encode(...typeParameters.map(make)), toASTAnnotations(annotations))); const declarePrimitive = (is, annotations) => { const decodeUnknown = () => (input, _, ast) => is(input) ? ParseResult.succeed(input) : ParseResult.fail(new ParseResult.Type(ast, input)); const encodeUnknown = decodeUnknown; return makeDeclareClass([], new AST.Declaration([], decodeUnknown, encodeUnknown, toASTAnnotations(annotations))); }; function makeDeclareClass(typeParameters, ast) { return class DeclareClass extends make(ast) { static annotations(annotations) { return makeDeclareClass(this.typeParameters, mergeSchemaAnnotations(this.ast, annotations)); } static typeParameters = [...typeParameters]; }; } /** * The constraint `R extends Schema.Context
` enforces dependencies solely from `typeParameters`.
* This ensures that when you call `Schema.to` or `Schema.from`, you receive a schema with a `never` context.
*
* @category constructors
* @since 3.10.0
*/
export const declare = function () {
if (Array.isArray(arguments[0])) {
const typeParameters = arguments[0];
const options = arguments[1];
const annotations = arguments[2];
return declareConstructor(typeParameters, options, annotations);
}
const is = arguments[0];
const annotations = arguments[1];
return declarePrimitive(is, annotations);
};
/**
* @category schema id
* @since 3.10.0
*/
export const BrandSchemaId = /*#__PURE__*/Symbol.for("effect/SchemaId/Brand");
/**
* @category constructors
* @since 3.10.0
*/
export const fromBrand = (constructor, annotations) => self => {
const out = makeBrandClass(self, new AST.Refinement(self.ast, function predicate(a, _, ast) {
const either = constructor.either(a);
return either_.isLeft(either) ? option_.some(new ParseResult.Type(ast, a, either.left.map(v => v.message).join(", "))) : option_.none();
}, toASTAnnotations({
schemaId: BrandSchemaId,
[BrandSchemaId]: {
constructor
},
...annotations
})));
return out;
};
/**
* @category schema id
* @since 3.10.0
*/
export const InstanceOfSchemaId = /*#__PURE__*/Symbol.for("effect/SchemaId/InstanceOf");
/**
* @category constructors
* @since 3.10.0
*/
export const instanceOf = (constructor, annotations) => declare(u => u instanceof constructor, {
title: constructor.name,
description: `an instance of ${constructor.name}`,
pretty: () => String,
schemaId: InstanceOfSchemaId,
[InstanceOfSchemaId]: {
constructor
},
...annotations
});
/**
* @category primitives
* @since 3.10.0
*/
export class Undefined extends /*#__PURE__*/make(AST.undefinedKeyword) {}
/**
* @category primitives
* @since 3.10.0
*/
export class Void extends /*#__PURE__*/make(AST.voidKeyword) {}
/**
* @category primitives
* @since 3.10.0
*/
export class Null extends /*#__PURE__*/make(AST.null) {}
/**
* @category primitives
* @since 3.10.0
*/
export class Never extends /*#__PURE__*/make(AST.neverKeyword) {}
/**
* @category primitives
* @since 3.10.0
*/
export class Unknown extends /*#__PURE__*/make(AST.unknownKeyword) {}
/**
* @category primitives
* @since 3.10.0
*/
export class Any extends /*#__PURE__*/make(AST.anyKeyword) {}
/**
* @category primitives
* @since 3.10.0
*/
export class BigIntFromSelf extends /*#__PURE__*/make(AST.bigIntKeyword) {}
/**
* @category primitives
* @since 3.10.0
*/
export class SymbolFromSelf extends /*#__PURE__*/make(AST.symbolKeyword) {}
/** @ignore */
class String$ extends /*#__PURE__*/make(AST.stringKeyword) {}
/** @ignore */
class Number$ extends /*#__PURE__*/make(AST.numberKeyword) {}
/** @ignore */
class Boolean$ extends /*#__PURE__*/make(AST.booleanKeyword) {}
/** @ignore */
class Object$ extends /*#__PURE__*/make(AST.objectKeyword) {}
export {
/**
* @category primitives
* @since 3.10.0
*/
Boolean$ as Boolean,
/**
* @category primitives
* @since 3.10.0
*/
Number$ as Number,
/**
* @category primitives
* @since 3.10.0
*/
Object$ as Object,
/**
* @category primitives
* @since 3.10.0
*/
String$ as String };
const getDefaultUnionAST = members => AST.Union.make(members.map(m => m.ast));
function makeUnionClass(members, ast = getDefaultUnionAST(members)) {
return class UnionClass extends make(ast) {
static annotations(annotations) {
return makeUnionClass(this.members, mergeSchemaAnnotations(this.ast, annotations));
}
static members = [...members];
};
}
export function Union(...members) {
return AST.isMembers(members) ? makeUnionClass(members) : array_.isNonEmptyReadonlyArray(members) ? members[0] : Never;
}
/**
* @category combinators
* @since 3.10.0
*/
export const NullOr = self => Union(self, Null);
/**
* @category combinators
* @since 3.10.0
*/
export const UndefinedOr = self => Union(self, Undefined);
/**
* @category combinators
* @since 3.10.0
*/
export const NullishOr = self => Union(self, Null, Undefined);
/**
* @category combinators
* @since 3.10.0
*/
export const keyof = self => make(AST.keyof(self.ast));
/**
* @since 3.10.0
*/
export const element = self => new ElementImpl(new AST.OptionalType(self.ast, false), self);
/**
* @since 3.10.0
*/
export const optionalElement = self => new ElementImpl(new AST.OptionalType(self.ast, true), self);
class ElementImpl {
ast;
from;
[TypeId];
_Token;
constructor(ast, from) {
this.ast = ast;
this.from = from;
}
annotations(annotations) {
return new ElementImpl(new AST.OptionalType(this.ast.type, this.ast.isOptional, {
...this.ast.annotations,
...toASTAnnotations(annotations)
}), this.from);
}
toString() {
return `${this.ast.type}${this.ast.isOptional ? "?" : ""}`;
}
}
const getDefaultTupleTypeAST = (elements, rest) => new AST.TupleType(elements.map(el => isSchema(el) ? new AST.OptionalType(el.ast, false) : el.ast), rest.map(el => isSchema(el) ? new AST.Type(el.ast) : el.ast), true);
function makeTupleTypeClass(elements, rest, ast = getDefaultTupleTypeAST(elements, rest)) {
return class TupleTypeClass extends make(ast) {
static annotations(annotations) {
return makeTupleTypeClass(this.elements, this.rest, mergeSchemaAnnotations(this.ast, annotations));
}
static elements = [...elements];
static rest = [...rest];
};
}
export function Tuple(...args) {
return Array.isArray(args[0]) ? makeTupleTypeClass(args[0], args.slice(1)) : makeTupleTypeClass(args, []);
}
function makeArrayClass(value, ast) {
return class ArrayClass extends makeTupleTypeClass([], [value], ast) {
static annotations(annotations) {
return makeArrayClass(this.value, mergeSchemaAnnotations(this.ast, annotations));
}
static value = value;
};
}
const Array$ = value => makeArrayClass(value);
export {
/**
* @category constructors
* @since 3.10.0
*/
Array$ as Array };
function makeNonEmptyArrayClass(value, ast) {
return class NonEmptyArrayClass extends makeTupleTypeClass([value], [value], ast) {
static annotations(annotations) {
return makeNonEmptyArrayClass(this.value, mergeSchemaAnnotations(this.ast, annotations));
}
static value = value;
};
}
/**
* @category constructors
* @since 3.10.0
*/
export const NonEmptyArray = value => makeNonEmptyArrayClass(value);
/**
* @category constructors
* @since 3.10.0
*/
export function ArrayEnsure(value) {
return transform(Union(value, Array$(value)), Array$(typeSchema(asSchema(value))), {
strict: true,
decode: i => array_.ensure(i),
encode: a => a.length === 1 ? a[0] : a
});
}
/**
* @category constructors
* @since 3.10.0
*/
export function NonEmptyArrayEnsure(value) {
return transform(Union(value, NonEmptyArray(value)), NonEmptyArray(typeSchema(asSchema(value))), {
strict: true,
decode: i => array_.isNonEmptyReadonlyArray(i) ? i : array_.of(i),
encode: a => a.length === 1 ? a[0] : a
});
}
const formatPropertySignatureToken = isOptional => isOptional ? "\"?:\"" : "\":\"";
/**
* @category PropertySignature
* @since 3.10.0
*/
export class PropertySignatureDeclaration extends AST.OptionalType {
isReadonly;
defaultValue;
/**
* @since 3.10.0
*/
_tag = "PropertySignatureDeclaration";
constructor(type, isOptional, isReadonly, annotations, defaultValue) {
super(type, isOptional, annotations);
this.isReadonly = isReadonly;
this.defaultValue = defaultValue;
}
/**
* @since 3.10.0
*/
toString() {
const token = formatPropertySignatureToken(this.isOptional);
const type = String(this.type);
return `PropertySignature<${token}, ${type}, never, ${token}, ${type}>`;
}
}
/**
* @category PropertySignature
* @since 3.10.0
*/
export class FromPropertySignature extends AST.OptionalType {
isReadonly;
fromKey;
constructor(type, isOptional, isReadonly, annotations, fromKey) {
super(type, isOptional, annotations);
this.isReadonly = isReadonly;
this.fromKey = fromKey;
}
}
/**
* @category PropertySignature
* @since 3.10.0
*/
export class ToPropertySignature extends AST.OptionalType {
isReadonly;
defaultValue;
constructor(type, isOptional, isReadonly, annotations, defaultValue) {
super(type, isOptional, annotations);
this.isReadonly = isReadonly;
this.defaultValue = defaultValue;
}
}
const formatPropertyKey = p => {
if (p === undefined) {
return "never";
}
if (Predicate.isString(p)) {
return JSON.stringify(p);
}
return String(p);
};
/**
* @category PropertySignature
* @since 3.10.0
*/
export class PropertySignatureTransformation {
from;
to;
decode;
encode;
/**
* @since 3.10.0
*/
_tag = "PropertySignatureTransformation";
constructor(from, to, decode, encode) {
this.from = from;
this.to = to;
this.decode = decode;
this.encode = encode;
}
/**
* @since 3.10.0
*/
toString() {
return `PropertySignature<${formatPropertySignatureToken(this.to.isOptional)}, ${this.to.type}, ${formatPropertyKey(this.from.fromKey)}, ${formatPropertySignatureToken(this.from.isOptional)}, ${this.from.type}>`;
}
}
const mergeSignatureAnnotations = (ast, annotations) => {
switch (ast._tag) {
case "PropertySignatureDeclaration":
{
return new PropertySignatureDeclaration(ast.type, ast.isOptional, ast.isReadonly, {
...ast.annotations,
...annotations
}, ast.defaultValue);
}
case "PropertySignatureTransformation":
{
return new PropertySignatureTransformation(ast.from, new ToPropertySignature(ast.to.type, ast.to.isOptional, ast.to.isReadonly, {
...ast.to.annotations,
...annotations
}, ast.to.defaultValue), ast.decode, ast.encode);
}
}
};
/**
* @since 3.10.0
* @category symbol
*/
export const PropertySignatureTypeId = /*#__PURE__*/Symbol.for("effect/PropertySignature");
/**
* @since 3.10.0
* @category guards
*/
export const isPropertySignature = u => Predicate.hasProperty(u, PropertySignatureTypeId);
class PropertySignatureImpl {
ast;
[TypeId];
[PropertySignatureTypeId] = null;
_TypeToken;
_Key;
_EncodedToken;
_HasDefault;
constructor(ast) {
this.ast = ast;
}
pipe() {
return pipeArguments(this, arguments);
}
annotations(annotations) {
return new PropertySignatureImpl(mergeSignatureAnnotations(this.ast, toASTAnnotations(annotations)));
}
toString() {
return String(this.ast);
}
}
/**
* @category PropertySignature
* @since 3.10.0
*/
export const makePropertySignature = ast => new PropertySignatureImpl(ast);
class PropertySignatureWithFromImpl extends PropertySignatureImpl {
from;
constructor(ast, from) {
super(ast);
this.from = from;
}
annotations(annotations) {
return new PropertySignatureWithFromImpl(mergeSignatureAnnotations(this.ast, toASTAnnotations(annotations)), this.from);
}
}
/**
* Lifts a `Schema` into a `PropertySignature`.
*
* @category PropertySignature
* @since 3.10.0
*/
export const propertySignature = self => new PropertySignatureWithFromImpl(new PropertySignatureDeclaration(self.ast, false, true, {}, undefined), self);
/**
* Enhances a property signature with a default constructor value.
*
* @category PropertySignature
* @since 3.10.0
*/
export const withConstructorDefault = /*#__PURE__*/dual(2, (self, defaultValue) => {
const ast = self.ast;
switch (ast._tag) {
case "PropertySignatureDeclaration":
return makePropertySignature(new PropertySignatureDeclaration(ast.type, ast.isOptional, ast.isReadonly, ast.annotations, defaultValue));
case "PropertySignatureTransformation":
return makePropertySignature(new PropertySignatureTransformation(ast.from, new ToPropertySignature(ast.to.type, ast.to.isOptional, ast.to.isReadonly, ast.to.annotations, defaultValue), ast.decode, ast.encode));
}
});
const applyDefaultValue = (o, defaultValue) => option_.match(o, {
onNone: () => option_.some(defaultValue()),
onSome: value => option_.some(value === undefined ? defaultValue() : value)
});
const pruneUndefined = ast => AST.pruneUndefined(ast, pruneUndefined, ast => {
const pruned = pruneUndefined(ast.to);
if (pruned) {
return new AST.Transformation(ast.from, pruned, ast.transformation);
}
});
/**
* Enhances a property signature with a default decoding value.
*
* @category PropertySignature
* @since 3.10.0
*/
export const withDecodingDefault = /*#__PURE__*/dual(2, (self, defaultValue) => {
const ast = self.ast;
switch (ast._tag) {
case "PropertySignatureDeclaration":
{
const to = AST.typeAST(ast.type);
return makePropertySignature(new PropertySignatureTransformation(new FromPropertySignature(ast.type, ast.isOptional, ast.isReadonly, ast.annotations), new ToPropertySignature(pruneUndefined(to) ?? to, false, true, {}, ast.defaultValue), o => applyDefaultValue(o, defaultValue), identity));
}
case "PropertySignatureTransformation":
{
const to = ast.to.type;
return makePropertySignature(new PropertySignatureTransformation(ast.from, new ToPropertySignature(pruneUndefined(to) ?? to, false, ast.to.isReadonly, ast.to.annotations, ast.to.defaultValue), o => applyDefaultValue(ast.decode(o), defaultValue), ast.encode));
}
}
});
/**
* Enhances a property signature with a default decoding value and a default constructor value.
*
* @category PropertySignature
* @since 3.10.0
*/
export const withDefaults = /*#__PURE__*/dual(2, (self, defaults) => self.pipe(withDecodingDefault(defaults.decoding), withConstructorDefault(defaults.constructor)));
/**
* Enhances a property signature by specifying a different key for it in the Encoded type.
*
* @category PropertySignature
* @since 3.10.0
*/
export const fromKey = /*#__PURE__*/dual(2, (self, key) => {
const ast = self.ast;
switch (ast._tag) {
case "PropertySignatureDeclaration":
{
return makePropertySignature(new PropertySignatureTransformation(new FromPropertySignature(ast.type, ast.isOptional, ast.isReadonly, ast.annotations, key), new ToPropertySignature(AST.typeAST(ast.type), ast.isOptional, ast.isReadonly, {}, ast.defaultValue), identity, identity));
}
case "PropertySignatureTransformation":
return makePropertySignature(new PropertySignatureTransformation(new FromPropertySignature(ast.from.type, ast.from.isOptional, ast.from.isReadonly, ast.from.annotations, key), ast.to, ast.decode, ast.encode));
}
});
/**
* Converts an optional property to a required one through a transformation `Option -> Type`.
*
* - `decode`: `none` as argument means the value is missing in the input.
* - `encode`: `none` as return value means the value will be missing in the output.
*
* @category PropertySignature
* @since 3.10.0
*/
export const optionalToRequired = (from, to, options) => makePropertySignature(new PropertySignatureTransformation(new FromPropertySignature(from.ast, true, true, {}, undefined), new ToPropertySignature(to.ast, false, true, {}, undefined), o => option_.some(options.decode(o)), option_.flatMap(options.encode)));
/**
* Converts an optional property to a required one through a transformation `Type -> Option`.
*
* - `decode`: `none` as return value means the value will be missing in the output.
* - `encode`: `none` as argument means the value is missing in the input.
*
* @category PropertySignature
* @since 3.10.0
*/
export const requiredToOptional = (from, to, options) => makePropertySignature(new PropertySignatureTransformation(new FromPropertySignature(from.ast, false, true, {}, undefined), new ToPropertySignature(to.ast, true, true, {}, undefined), option_.flatMap(options.decode), o => option_.some(options.encode(o))));
/**
* Converts an optional property to another optional property through a transformation `Option -> Option`.
*
* - `decode`:
* - `none` as argument means the value is missing in the input.
* - `none` as return value means the value will be missing in the output.
* - `encode`:
* - `none` as argument means the value is missing in the input.
* - `none` as return value means the value will be missing in the output.
*
* @category PropertySignature
* @since 3.10.0
*/
export const optionalToOptional = (from, to, options) => makePropertySignature(new PropertySignatureTransformation(new FromPropertySignature(from.ast, true, true, {}, undefined), new ToPropertySignature(to.ast, true, true, {}, undefined), options.decode, options.encode));
const optionalPropertySignatureAST = (self, options) => {
const isExact = options?.exact;
const defaultValue = options?.default;
const isNullable = options?.nullable;
const asOption = options?.as == "Option";
const asOptionEncode = options?.onNoneEncoding ? option_.orElse(options.onNoneEncoding) : identity;
if (isExact) {
if (defaultValue) {
if (isNullable) {
return withConstructorDefault(optionalToRequired(NullOr(self), typeSchema(self), {
decode: option_.match({
onNone: defaultValue,
onSome: a => a === null ? defaultValue() : a
}),
encode: option_.some
}), defaultValue).ast;
} else {
return withConstructorDefault(optionalToRequired(self, typeSchema(self), {
decode: option_.match({
onNone: defaultValue,
onSome: identity
}),
encode: option_.some
}), defaultValue).ast;
}
} else if (asOption) {
if (isNullable) {
return optionalToRequired(NullOr(self), OptionFromSelf(typeSchema(self)), {
decode: option_.filter(Predicate.isNotNull),
encode: asOptionEncode
}).ast;
} else {
return optionalToRequired(self, OptionFromSelf(typeSchema(self)), {
decode: identity,
encode: identity
}).ast;
}
} else {
if (isNullable) {
return optionalToOptional(NullOr(self), typeSchema(self), {
decode: option_.filter(Predicate.isNotNull),
encode: identity
}).ast;
} else {
return new PropertySignatureDeclaration(self.ast, true, true, {}, undefined);
}
}
} else {
if (defaultValue) {
if (isNullable) {
return withConstructorDefault(optionalToRequired(NullishOr(self), typeSchema(self), {
decode: option_.match({
onNone: defaultValue,
onSome: a => a == null ? defaultValue() : a
}),
encode: option_.some
}), defaultValue).ast;
} else {
return withConstructorDefault(optionalToRequired(UndefinedOr(self), typeSchema(self), {
decode: option_.match({
onNone: defaultValue,
onSome: a => a === undefined ? defaultValue() : a
}),
encode: option_.some
}), defaultValue).ast;
}
} else if (asOption) {
if (isNullable) {
return optionalToRequired(NullishOr(self), OptionFromSelf(typeSchema(self)), {
decode: option_.filter(a => a != null),
encode: asOptionEncode
}).ast;
} else {
return optionalToRequired(UndefinedOr(self), OptionFromSelf(typeSchema(self)), {
decode: option_.filter(Predicate.isNotUndefined),
encode: asOptionEncode
}).ast;
}
} else {
if (isNullable) {
return optionalToOptional(NullishOr(self), UndefinedOr(typeSchema(self)), {
decode: option_.filter(Predicate.isNotNull),
encode: identity
}).ast;
} else {
return new PropertySignatureDeclaration(UndefinedOr(self).ast, true, true, {}, undefined);
}
}
}
};
/**
* @category PropertySignature
* @since 3.10.0
*/
export const optional = self => {
const ast = self.ast === AST.undefinedKeyword || self.ast === AST.neverKeyword ? AST.undefinedKeyword : UndefinedOr(self).ast;
return new PropertySignatureWithFromImpl(new PropertySignatureDeclaration(ast, true, true, {}, undefined), self);
};
/**
* @category PropertySignature
* @since 3.10.0
*/
export const optionalWith = /*#__PURE__*/dual(args => isSchema(args[0]), (self, options) => {
return new PropertySignatureWithFromImpl(optionalPropertySignatureAST(self, options), self);
});
const preserveMissingMessageAnnotation = /*#__PURE__*/AST.pickAnnotations([AST.MissingMessageAnnotationId]);
const getDefaultTypeLiteralAST = (fields, records) => {
const ownKeys = util_.ownKeys(fields);
const pss = [];
if (ownKeys.length > 0) {
const from = [];
const to = [];
const transformations = [];
for (let i = 0; i < ownKeys.length; i++) {
const key = ownKeys[i];
const field = fields[key];
if (isPropertySignature(field)) {
const ast = field.ast;
switch (ast._tag) {
case "PropertySignatureDeclaration":
{
const type = ast.type;
const isOptional = ast.isOptional;
const toAnnotations = ast.annotations;
from.push(new AST.PropertySignature(key, type, isOptional, true, preserveMissingMessageAnnotation(ast)));
to.push(new AST.PropertySignature(key, AST.typeAST(type), isOptional, true, toAnnotations));
pss.push(new AST.PropertySignature(key, type, isOptional, true, toAnnotations));
break;
}
case "PropertySignatureTransformation":
{
const fromKey = ast.from.fromKey ?? key;
from.push(new AST.PropertySignature(fromKey, ast.from.type, ast.from.isOptional, true, ast.from.annotations));
to.push(new AST.PropertySignature(key, ast.to.type, ast.to.isOptional, true, ast.to.annotations));
transformations.push(new AST.PropertySignatureTransformation(fromKey, key, ast.decode, ast.encode));
break;
}
}
} else {
from.push(new AST.PropertySignature(key, field.ast, false, true));
to.push(new AST.PropertySignature(key, AST.typeAST(field.ast), false, true));
pss.push(new AST.PropertySignature(key, field.ast, false, true));
}
}
if (array_.isNonEmptyReadonlyArray(transformations)) {
const issFrom = [];
const issTo = [];
for (const r of records) {
const {
indexSignatures,
propertySignatures
} = AST.record(r.key.ast, r.value.ast);
propertySignatures.forEach(ps => {
from.push(ps);
to.push(new AST.PropertySignature(ps.name, AST.typeAST(ps.type), ps.isOptional, ps.isReadonly, ps.annotations));
});
indexSignatures.forEach(is => {
issFrom.push(is);
issTo.push(new AST.IndexSignature(is.parameter, AST.typeAST(is.type), is.isReadonly));
});
}
return new AST.Transformation(new AST.TypeLiteral(from, issFrom, {
[AST.AutoTitleAnnotationId]: "Struct (Encoded side)"
}), new AST.TypeLiteral(to, issTo, {
[AST.AutoTitleAnnotationId]: "Struct (Type side)"
}), new AST.TypeLiteralTransformation(transformations));
}
}
const iss = [];
for (const r of records) {
const {
indexSignatures,
propertySignatures
} = AST.record(r.key.ast, r.value.ast);
propertySignatures.forEach(ps => pss.push(ps));
indexSignatures.forEach(is => iss.push(is));
}
return new AST.TypeLiteral(pss, iss);
};
const lazilyMergeDefaults = (fields, out) => {
const ownKeys = util_.ownKeys(fields);
for (const key of ownKeys) {
const field = fields[key];
if (out[key] === undefined && isPropertySignature(field)) {
const ast = field.ast;
const defaultValue = ast._tag === "PropertySignatureDeclaration" ? ast.defaultValue : ast.to.defaultValue;
if (defaultValue !== undefined) {
out[key] = defaultValue();
}
}
}
return out;
};
function makeTypeLiteralClass(fields, records, ast = getDefaultTypeLiteralAST(fields, records)) {
return class TypeLiteralClass extends make(ast) {
static annotations(annotations) {
return makeTypeLiteralClass(this.fields, this.records, mergeSchemaAnnotations(this.ast, annotations));
}
static fields = {
...fields
};
static records = [...records];
static make = (props, options) => {
const propsWithDefaults = lazilyMergeDefaults(fields, {
...props
});
return getDisableValidationMakeOption(options) ? propsWithDefaults : ParseResult.validateSync(this)(propsWithDefaults);
};
static pick(...keys) {
return Struct(struct_.pick(fields, ...keys));
}
static omit(...keys) {
return Struct(struct_.omit(fields, ...keys));
}
};
}
export function Struct(fields, ...records) {
return makeTypeLiteralClass(fields, records);
}
/**
* Returns a property signature that represents a tag.
* A tag is a literal value that is used to distinguish between different types of objects.
* The tag is optional when using the `make` method.
*
* @example
* ```ts
* import * as assert from "node:assert"
* import { Schema } from "effect"
*
* const User = Schema.Struct({
* _tag: Schema.tag("User"),
* name: Schema.String,
* age: Schema.Number
* })
*
* assert.deepStrictEqual(User.make({ name: "John", age: 44 }), { _tag: "User", name: "John", age: 44 })
* ```
*
* @see {@link TaggedStruct}
*
* @since 3.10.0
*/
export const tag = tag => Literal(tag).pipe(propertySignature, withConstructorDefault(() => tag));
/**
* A tagged struct is a struct that has a tag property that is used to distinguish between different types of objects.
*
* The tag is optional when using the `make` method.
*
* @example
* ```ts
* import * as assert from "node:assert"
* import { Schema } from "effect"
*
* const User = Schema.TaggedStruct("User", {
* name: Schema.String,
* age: Schema.Number
* })
*
* assert.deepStrictEqual(User.make({ name: "John", age: 44 }), { _tag: "User", name: "John", age: 44 })
* ```
*
* @category constructors
* @since 3.10.0
*/
export const TaggedStruct = (value, fields) => Struct({
_tag: tag(value),
...fields
});
function makeRecordClass(key, value, ast) {
return class RecordClass extends makeTypeLiteralClass({}, [{
key,
value
}], ast) {
static annotations(annotations) {
return makeRecordClass(key, value, mergeSchemaAnnotations(this.ast, annotations));
}
static key = key;
static value = value;
};
}
/**
* @category constructors
* @since 3.10.0
*/
export const Record = options => makeRecordClass(options.key, options.value);
/**
* @category struct transformations
* @since 3.10.0
*/
export const pick = (...keys) => self => make(AST.pick(self.ast, keys));
/**
* @category struct transformations
* @since 3.10.0
*/
export const omit = (...keys) => self => make(AST.omit(self.ast, keys));
/**
* Given a schema `Schema` and a key `key: K`, this function extracts a specific field from the `A` type,
* producing a new schema that represents a transformation from the `{ readonly [key]: I[K] }` type to `A[K]`.
*
* @example
* ```ts
* import * as Schema from "effect/Schema"
*
* // ---------------------------------------------
* // use case: pull out a single field from a
* // struct through a transformation
* // ---------------------------------------------
*
* const mytable = Schema.Struct({
* column1: Schema.NumberFromString,
* column2: Schema.Number
* })
*
* // const pullOutColumn: S.Schema