/** * @since 3.10.0 */ import * as Arr from "./Array.js"; import { dual, identity } from "./Function.js"; import { globalValue } from "./GlobalValue.js"; import * as errors_ from "./internal/schema/errors.js"; import * as util_ from "./internal/schema/util.js"; import * as Number from "./Number.js"; import * as Option from "./Option.js"; import * as Order from "./Order.js"; import * as Predicate from "./Predicate.js"; import * as regexp from "./RegExp.js"; /** * @category annotations * @since 3.10.0 */ export const BrandAnnotationId = /*#__PURE__*/Symbol.for("effect/annotation/Brand"); /** * @category annotations * @since 3.10.0 */ export const SchemaIdAnnotationId = /*#__PURE__*/Symbol.for("effect/annotation/SchemaId"); /** * @category annotations * @since 3.10.0 */ export const MessageAnnotationId = /*#__PURE__*/Symbol.for("effect/annotation/Message"); /** * @category annotations * @since 3.10.0 */ export const MissingMessageAnnotationId = /*#__PURE__*/Symbol.for("effect/annotation/MissingMessage"); /** * @category annotations * @since 3.10.0 */ export const IdentifierAnnotationId = /*#__PURE__*/Symbol.for("effect/annotation/Identifier"); /** * @category annotations * @since 3.10.0 */ export const TitleAnnotationId = /*#__PURE__*/Symbol.for("effect/annotation/Title"); /** @internal */ export const AutoTitleAnnotationId = /*#__PURE__*/Symbol.for("effect/annotation/AutoTitle"); /** * @category annotations * @since 3.10.0 */ export const DescriptionAnnotationId = /*#__PURE__*/Symbol.for("effect/annotation/Description"); /** * @category annotations * @since 3.10.0 */ export const ExamplesAnnotationId = /*#__PURE__*/Symbol.for("effect/annotation/Examples"); /** * @category annotations * @since 3.10.0 */ export const DefaultAnnotationId = /*#__PURE__*/Symbol.for("effect/annotation/Default"); /** * @category annotations * @since 3.10.0 */ export const JSONSchemaAnnotationId = /*#__PURE__*/Symbol.for("effect/annotation/JSONSchema"); /** * @category annotations * @since 3.10.0 */ export const ArbitraryAnnotationId = /*#__PURE__*/Symbol.for("effect/annotation/Arbitrary"); /** * @category annotations * @since 3.10.0 */ export const PrettyAnnotationId = /*#__PURE__*/Symbol.for("effect/annotation/Pretty"); /** * @category annotations * @since 3.10.0 */ export const EquivalenceAnnotationId = /*#__PURE__*/Symbol.for("effect/annotation/Equivalence"); /** * @category annotations * @since 3.10.0 */ export const DocumentationAnnotationId = /*#__PURE__*/Symbol.for("effect/annotation/Documentation"); /** * @category annotations * @since 3.10.0 */ export const ConcurrencyAnnotationId = /*#__PURE__*/Symbol.for("effect/annotation/Concurrency"); /** * @category annotations * @since 3.10.0 */ export const BatchingAnnotationId = /*#__PURE__*/Symbol.for("effect/annotation/Batching"); /** * @category annotations * @since 3.10.0 */ export const ParseIssueTitleAnnotationId = /*#__PURE__*/Symbol.for("effect/annotation/ParseIssueTitle"); /** * @category annotations * @since 3.10.0 */ export const ParseOptionsAnnotationId = /*#__PURE__*/Symbol.for("effect/annotation/ParseOptions"); /** * @category annotations * @since 3.10.0 */ export const DecodingFallbackAnnotationId = /*#__PURE__*/Symbol.for("effect/annotation/DecodingFallback"); /** * @category annotations * @since 3.10.0 */ export const SurrogateAnnotationId = /*#__PURE__*/Symbol.for("effect/annotation/Surrogate"); /** @internal */ export const StableFilterAnnotationId = /*#__PURE__*/Symbol.for("effect/annotation/StableFilter"); /** * @category annotations * @since 3.10.0 */ export const getAnnotation = /*#__PURE__*/dual(2, (annotated, key) => Object.prototype.hasOwnProperty.call(annotated.annotations, key) ? Option.some(annotated.annotations[key]) : Option.none()); /** * @category annotations * @since 3.10.0 */ export const getBrandAnnotation = /*#__PURE__*/getAnnotation(BrandAnnotationId); /** * @category annotations * @since 3.14.2 */ export const getSchemaIdAnnotation = /*#__PURE__*/getAnnotation(SchemaIdAnnotationId); /** * @category annotations * @since 3.10.0 */ export const getMessageAnnotation = /*#__PURE__*/getAnnotation(MessageAnnotationId); /** * @category annotations * @since 3.10.0 */ export const getMissingMessageAnnotation = /*#__PURE__*/getAnnotation(MissingMessageAnnotationId); /** * @category annotations * @since 3.10.0 */ export const getTitleAnnotation = /*#__PURE__*/getAnnotation(TitleAnnotationId); /** @internal */ export const getAutoTitleAnnotation = /*#__PURE__*/getAnnotation(AutoTitleAnnotationId); /** * @category annotations * @since 3.10.0 */ export const getIdentifierAnnotation = /*#__PURE__*/getAnnotation(IdentifierAnnotationId); /** * @category annotations * @since 3.10.0 */ export const getDescriptionAnnotation = /*#__PURE__*/getAnnotation(DescriptionAnnotationId); /** * @category annotations * @since 3.10.0 */ export const getExamplesAnnotation = /*#__PURE__*/getAnnotation(ExamplesAnnotationId); /** * @category annotations * @since 3.10.0 */ export const getDefaultAnnotation = /*#__PURE__*/getAnnotation(DefaultAnnotationId); /** * @category annotations * @since 3.10.0 */ export const getJSONSchemaAnnotation = /*#__PURE__*/getAnnotation(JSONSchemaAnnotationId); /** * @category annotations * @since 3.10.0 */ export const getDocumentationAnnotation = /*#__PURE__*/getAnnotation(DocumentationAnnotationId); /** * @category annotations * @since 3.10.0 */ export const getConcurrencyAnnotation = /*#__PURE__*/getAnnotation(ConcurrencyAnnotationId); /** * @category annotations * @since 3.10.0 */ export const getBatchingAnnotation = /*#__PURE__*/getAnnotation(BatchingAnnotationId); /** * @category annotations * @since 3.10.0 */ export const getParseIssueTitleAnnotation = /*#__PURE__*/getAnnotation(ParseIssueTitleAnnotationId); /** * @category annotations * @since 3.10.0 */ export const getParseOptionsAnnotation = /*#__PURE__*/getAnnotation(ParseOptionsAnnotationId); /** * @category annotations * @since 3.10.0 */ export const getDecodingFallbackAnnotation = /*#__PURE__*/getAnnotation(DecodingFallbackAnnotationId); /** * @category annotations * @since 3.10.0 */ export const getSurrogateAnnotation = /*#__PURE__*/getAnnotation(SurrogateAnnotationId); const getStableFilterAnnotation = /*#__PURE__*/getAnnotation(StableFilterAnnotationId); /** @internal */ export const hasStableFilter = annotated => Option.exists(getStableFilterAnnotation(annotated), b => b === true); /** * @category annotations * @since 3.10.0 */ export const JSONIdentifierAnnotationId = /*#__PURE__*/Symbol.for("effect/annotation/JSONIdentifier"); /** * @category annotations * @since 3.10.0 */ export const getJSONIdentifierAnnotation = /*#__PURE__*/getAnnotation(JSONIdentifierAnnotationId); /** * @category annotations * @since 3.10.0 */ export const getJSONIdentifier = annotated => Option.orElse(getJSONIdentifierAnnotation(annotated), () => getIdentifierAnnotation(annotated)); // ------------------------------------------------------------------------------------- // schema ids // ------------------------------------------------------------------------------------- /** * @category schema id * @since 3.10.0 */ export const ParseJsonSchemaId = /*#__PURE__*/Symbol.for("effect/schema/ParseJson"); /** * @category model * @since 3.10.0 */ export class Declaration { typeParameters; decodeUnknown; encodeUnknown; annotations; /** * @since 3.10.0 */ _tag = "Declaration"; constructor(typeParameters, decodeUnknown, encodeUnknown, annotations = {}) { this.typeParameters = typeParameters; this.decodeUnknown = decodeUnknown; this.encodeUnknown = encodeUnknown; this.annotations = annotations; } /** * @since 3.10.0 */ toString() { return Option.getOrElse(getExpected(this), () => ""); } /** * @since 3.10.0 */ toJSON() { return { _tag: this._tag, typeParameters: this.typeParameters.map(ast => ast.toJSON()), annotations: toJSONAnnotations(this.annotations) }; } } const createASTGuard = tag => ast => ast._tag === tag; /** * @category guards * @since 3.10.0 */ export const isDeclaration = /*#__PURE__*/createASTGuard("Declaration"); /** * @category model * @since 3.10.0 */ export class Literal { literal; annotations; /** * @since 3.10.0 */ _tag = "Literal"; constructor(literal, annotations = {}) { this.literal = literal; this.annotations = annotations; } /** * @since 3.10.0 */ toString() { return Option.getOrElse(getExpected(this), () => util_.formatUnknown(this.literal)); } /** * @since 3.10.0 */ toJSON() { return { _tag: this._tag, literal: Predicate.isBigInt(this.literal) ? String(this.literal) : this.literal, annotations: toJSONAnnotations(this.annotations) }; } } /** * @category guards * @since 3.10.0 */ export const isLiteral = /*#__PURE__*/createASTGuard("Literal"); const $null = /*#__PURE__*/new Literal(null); export { /** * @category constructors * @since 3.10.0 */ $null as null }; /** * @category model * @since 3.10.0 */ export class UniqueSymbol { symbol; annotations; /** * @since 3.10.0 */ _tag = "UniqueSymbol"; constructor(symbol, annotations = {}) { this.symbol = symbol; this.annotations = annotations; } /** * @since 3.10.0 */ toString() { return Option.getOrElse(getExpected(this), () => util_.formatUnknown(this.symbol)); } /** * @since 3.10.0 */ toJSON() { return { _tag: this._tag, symbol: String(this.symbol), annotations: toJSONAnnotations(this.annotations) }; } } /** * @category guards * @since 3.10.0 */ export const isUniqueSymbol = /*#__PURE__*/createASTGuard("UniqueSymbol"); /** * @category model * @since 3.10.0 */ export class UndefinedKeyword { annotations; /** * @since 3.10.0 */ _tag = "UndefinedKeyword"; constructor(annotations = {}) { this.annotations = annotations; } /** * @since 3.10.0 */ toString() { return formatKeyword(this); } /** * @since 3.10.0 */ toJSON() { return { _tag: this._tag, annotations: toJSONAnnotations(this.annotations) }; } } /** * @category constructors * @since 3.10.0 */ export const undefinedKeyword = /*#__PURE__*/new UndefinedKeyword({ [TitleAnnotationId]: "undefined" }); /** * @category guards * @since 3.10.0 */ export const isUndefinedKeyword = /*#__PURE__*/createASTGuard("UndefinedKeyword"); /** * @category model * @since 3.10.0 */ export class VoidKeyword { annotations; /** * @since 3.10.0 */ _tag = "VoidKeyword"; constructor(annotations = {}) { this.annotations = annotations; } /** * @since 3.10.0 */ toString() { return formatKeyword(this); } /** * @since 3.10.0 */ toJSON() { return { _tag: this._tag, annotations: toJSONAnnotations(this.annotations) }; } } /** * @category constructors * @since 3.10.0 */ export const voidKeyword = /*#__PURE__*/new VoidKeyword({ [TitleAnnotationId]: "void" }); /** * @category guards * @since 3.10.0 */ export const isVoidKeyword = /*#__PURE__*/createASTGuard("VoidKeyword"); /** * @category model * @since 3.10.0 */ export class NeverKeyword { annotations; /** * @since 3.10.0 */ _tag = "NeverKeyword"; constructor(annotations = {}) { this.annotations = annotations; } /** * @since 3.10.0 */ toString() { return formatKeyword(this); } /** * @since 3.10.0 */ toJSON() { return { _tag: this._tag, annotations: toJSONAnnotations(this.annotations) }; } } /** * @category constructors * @since 3.10.0 */ export const neverKeyword = /*#__PURE__*/new NeverKeyword({ [TitleAnnotationId]: "never" }); /** * @category guards * @since 3.10.0 */ export const isNeverKeyword = /*#__PURE__*/createASTGuard("NeverKeyword"); /** * @category model * @since 3.10.0 */ export class UnknownKeyword { annotations; /** * @since 3.10.0 */ _tag = "UnknownKeyword"; constructor(annotations = {}) { this.annotations = annotations; } /** * @since 3.10.0 */ toString() { return formatKeyword(this); } /** * @since 3.10.0 */ toJSON() { return { _tag: this._tag, annotations: toJSONAnnotations(this.annotations) }; } } /** * @category constructors * @since 3.10.0 */ export const unknownKeyword = /*#__PURE__*/new UnknownKeyword({ [TitleAnnotationId]: "unknown" }); /** * @category guards * @since 3.10.0 */ export const isUnknownKeyword = /*#__PURE__*/createASTGuard("UnknownKeyword"); /** * @category model * @since 3.10.0 */ export class AnyKeyword { annotations; /** * @since 3.10.0 */ _tag = "AnyKeyword"; constructor(annotations = {}) { this.annotations = annotations; } /** * @since 3.10.0 */ toString() { return formatKeyword(this); } /** * @since 3.10.0 */ toJSON() { return { _tag: this._tag, annotations: toJSONAnnotations(this.annotations) }; } } /** * @category constructors * @since 3.10.0 */ export const anyKeyword = /*#__PURE__*/new AnyKeyword({ [TitleAnnotationId]: "any" }); /** * @category guards * @since 3.10.0 */ export const isAnyKeyword = /*#__PURE__*/createASTGuard("AnyKeyword"); /** * @category model * @since 3.10.0 */ export class StringKeyword { annotations; /** * @since 3.10.0 */ _tag = "StringKeyword"; constructor(annotations = {}) { this.annotations = annotations; } /** * @since 3.10.0 */ toString() { return formatKeyword(this); } /** * @since 3.10.0 */ toJSON() { return { _tag: this._tag, annotations: toJSONAnnotations(this.annotations) }; } } /** * @category constructors * @since 3.10.0 */ export const stringKeyword = /*#__PURE__*/new StringKeyword({ [TitleAnnotationId]: "string", [DescriptionAnnotationId]: "a string" }); /** * @category guards * @since 3.10.0 */ export const isStringKeyword = /*#__PURE__*/createASTGuard("StringKeyword"); /** * @category model * @since 3.10.0 */ export class NumberKeyword { annotations; /** * @since 3.10.0 */ _tag = "NumberKeyword"; constructor(annotations = {}) { this.annotations = annotations; } /** * @since 3.10.0 */ toString() { return formatKeyword(this); } /** * @since 3.10.0 */ toJSON() { return { _tag: this._tag, annotations: toJSONAnnotations(this.annotations) }; } } /** * @category constructors * @since 3.10.0 */ export const numberKeyword = /*#__PURE__*/new NumberKeyword({ [TitleAnnotationId]: "number", [DescriptionAnnotationId]: "a number" }); /** * @category guards * @since 3.10.0 */ export const isNumberKeyword = /*#__PURE__*/createASTGuard("NumberKeyword"); /** * @category model * @since 3.10.0 */ export class BooleanKeyword { annotations; /** * @since 3.10.0 */ _tag = "BooleanKeyword"; constructor(annotations = {}) { this.annotations = annotations; } /** * @since 3.10.0 */ toString() { return formatKeyword(this); } /** * @since 3.10.0 */ toJSON() { return { _tag: this._tag, annotations: toJSONAnnotations(this.annotations) }; } } /** * @category constructors * @since 3.10.0 */ export const booleanKeyword = /*#__PURE__*/new BooleanKeyword({ [TitleAnnotationId]: "boolean", [DescriptionAnnotationId]: "a boolean" }); /** * @category guards * @since 3.10.0 */ export const isBooleanKeyword = /*#__PURE__*/createASTGuard("BooleanKeyword"); /** * @category model * @since 3.10.0 */ export class BigIntKeyword { annotations; /** * @since 3.10.0 */ _tag = "BigIntKeyword"; constructor(annotations = {}) { this.annotations = annotations; } /** * @since 3.10.0 */ toString() { return formatKeyword(this); } /** * @since 3.10.0 */ toJSON() { return { _tag: this._tag, annotations: toJSONAnnotations(this.annotations) }; } } /** * @category constructors * @since 3.10.0 */ export const bigIntKeyword = /*#__PURE__*/new BigIntKeyword({ [TitleAnnotationId]: "bigint", [DescriptionAnnotationId]: "a bigint" }); /** * @category guards * @since 3.10.0 */ export const isBigIntKeyword = /*#__PURE__*/createASTGuard("BigIntKeyword"); /** * @category model * @since 3.10.0 */ export class SymbolKeyword { annotations; /** * @since 3.10.0 */ _tag = "SymbolKeyword"; constructor(annotations = {}) { this.annotations = annotations; } /** * @since 3.10.0 */ toString() { return formatKeyword(this); } /** * @since 3.10.0 */ toJSON() { return { _tag: this._tag, annotations: toJSONAnnotations(this.annotations) }; } } /** * @category constructors * @since 3.10.0 */ export const symbolKeyword = /*#__PURE__*/new SymbolKeyword({ [TitleAnnotationId]: "symbol", [DescriptionAnnotationId]: "a symbol" }); /** * @category guards * @since 3.10.0 */ export const isSymbolKeyword = /*#__PURE__*/createASTGuard("SymbolKeyword"); /** * @category model * @since 3.10.0 */ export class ObjectKeyword { annotations; /** * @since 3.10.0 */ _tag = "ObjectKeyword"; constructor(annotations = {}) { this.annotations = annotations; } /** * @since 3.10.0 */ toString() { return formatKeyword(this); } /** * @since 3.10.0 */ toJSON() { return { _tag: this._tag, annotations: toJSONAnnotations(this.annotations) }; } } /** * @category constructors * @since 3.10.0 */ export const objectKeyword = /*#__PURE__*/new ObjectKeyword({ [TitleAnnotationId]: "object", [DescriptionAnnotationId]: "an object in the TypeScript meaning, i.e. the `object` type" }); /** * @category guards * @since 3.10.0 */ export const isObjectKeyword = /*#__PURE__*/createASTGuard("ObjectKeyword"); /** * @category model * @since 3.10.0 */ export class Enums { enums; annotations; /** * @since 3.10.0 */ _tag = "Enums"; constructor(enums, annotations = {}) { this.enums = enums; this.annotations = annotations; } /** * @since 3.10.0 */ toString() { return Option.getOrElse(getExpected(this), () => ` JSON.stringify(value)).join(" | ")}>`); } /** * @since 3.10.0 */ toJSON() { return { _tag: this._tag, enums: this.enums, annotations: toJSONAnnotations(this.annotations) }; } } /** * @category guards * @since 3.10.0 */ export const isEnums = /*#__PURE__*/createASTGuard("Enums"); const isTemplateLiteralSpanType = ast => { switch (ast._tag) { case "Literal": case "NumberKeyword": case "StringKeyword": case "TemplateLiteral": return true; case "Union": return ast.types.every(isTemplateLiteralSpanType); } return false; }; const templateLiteralSpanUnionTypeToString = type => { switch (type._tag) { case "Literal": return JSON.stringify(String(type.literal)); case "StringKeyword": return "string"; case "NumberKeyword": return "number"; case "TemplateLiteral": return String(type); case "Union": return type.types.map(templateLiteralSpanUnionTypeToString).join(" | "); } }; const templateLiteralSpanTypeToString = type => { switch (type._tag) { case "Literal": return String(type.literal); case "StringKeyword": return "${string}"; case "NumberKeyword": return "${number}"; case "TemplateLiteral": return "${" + String(type) + "}"; case "Union": return "${" + type.types.map(templateLiteralSpanUnionTypeToString).join(" | ") + "}"; } }; /** * @category model * @since 3.10.0 */ export class TemplateLiteralSpan { literal; /** * @since 3.10.0 */ type; constructor(type, literal) { this.literal = literal; if (isTemplateLiteralSpanType(type)) { this.type = type; } else { throw new Error(errors_.getSchemaUnsupportedLiteralSpanErrorMessage(type)); } } /** * @since 3.10.0 */ toString() { return templateLiteralSpanTypeToString(this.type) + this.literal; } /** * @since 3.10.0 */ toJSON() { return { type: this.type.toJSON(), literal: this.literal }; } } /** * @category model * @since 3.10.0 */ export class TemplateLiteral { head; spans; annotations; /** * @since 3.10.0 */ _tag = "TemplateLiteral"; constructor(head, spans, annotations = {}) { this.head = head; this.spans = spans; this.annotations = annotations; } /** * @since 3.10.0 */ toString() { return Option.getOrElse(getExpected(this), () => formatTemplateLiteral(this)); } /** * @since 3.10.0 */ toJSON() { return { _tag: this._tag, head: this.head, spans: this.spans.map(span => span.toJSON()), annotations: toJSONAnnotations(this.annotations) }; } } const formatTemplateLiteral = ast => "`" + ast.head + ast.spans.map(String).join("") + "`"; /** * @category guards * @since 3.10.0 */ export const isTemplateLiteral = /*#__PURE__*/createASTGuard("TemplateLiteral"); /** * @category model * @since 3.10.0 */ export class Type { type; annotations; constructor(type, annotations = {}) { this.type = type; this.annotations = annotations; } /** * @since 3.10.0 */ toJSON() { return { type: this.type.toJSON(), annotations: toJSONAnnotations(this.annotations) }; } /** * @since 3.10.0 */ toString() { return String(this.type); } } /** * @category model * @since 3.10.0 */ export class OptionalType extends Type { isOptional; constructor(type, isOptional, annotations = {}) { super(type, annotations); this.isOptional = isOptional; } /** * @since 3.10.0 */ toJSON() { return { type: this.type.toJSON(), isOptional: this.isOptional, annotations: toJSONAnnotations(this.annotations) }; } /** * @since 3.10.0 */ toString() { return String(this.type) + (this.isOptional ? "?" : ""); } } const getRestASTs = rest => rest.map(annotatedAST => annotatedAST.type); /** * @category model * @since 3.10.0 */ export class TupleType { elements; rest; isReadonly; annotations; /** * @since 3.10.0 */ _tag = "TupleType"; constructor(elements, rest, isReadonly, annotations = {}) { this.elements = elements; this.rest = rest; this.isReadonly = isReadonly; this.annotations = annotations; let hasOptionalElement = false; let hasIllegalRequiredElement = false; for (const e of elements) { if (e.isOptional) { hasOptionalElement = true; } else if (hasOptionalElement) { hasIllegalRequiredElement = true; break; } } if (hasIllegalRequiredElement || hasOptionalElement && rest.length > 1) { throw new Error(errors_.getASTRequiredElementFollowinAnOptionalElementErrorMessage); } } /** * @since 3.10.0 */ toString() { return Option.getOrElse(getExpected(this), () => formatTuple(this)); } /** * @since 3.10.0 */ toJSON() { return { _tag: this._tag, elements: this.elements.map(e => e.toJSON()), rest: this.rest.map(ast => ast.toJSON()), isReadonly: this.isReadonly, annotations: toJSONAnnotations(this.annotations) }; } } const formatTuple = ast => { const formattedElements = ast.elements.map(String).join(", "); return Arr.matchLeft(ast.rest, { onEmpty: () => `readonly [${formattedElements}]`, onNonEmpty: (head, tail) => { const formattedHead = String(head); const wrappedHead = formattedHead.includes(" | ") ? `(${formattedHead})` : formattedHead; if (tail.length > 0) { const formattedTail = tail.map(String).join(", "); if (ast.elements.length > 0) { return `readonly [${formattedElements}, ...${wrappedHead}[], ${formattedTail}]`; } else { return `readonly [...${wrappedHead}[], ${formattedTail}]`; } } else { if (ast.elements.length > 0) { return `readonly [${formattedElements}, ...${wrappedHead}[]]`; } else { return `ReadonlyArray<${formattedHead}>`; } } } }); }; /** * @category guards * @since 3.10.0 */ export const isTupleType = /*#__PURE__*/createASTGuard("TupleType"); /** * @category model * @since 3.10.0 */ export class PropertySignature extends OptionalType { name; isReadonly; constructor(name, type, isOptional, isReadonly, annotations) { super(type, isOptional, annotations); this.name = name; this.isReadonly = isReadonly; } /** * @since 3.10.0 */ toString() { return (this.isReadonly ? "readonly " : "") + String(this.name) + (this.isOptional ? "?" : "") + ": " + this.type; } /** * @since 3.10.0 */ toJSON() { return { name: String(this.name), type: this.type.toJSON(), isOptional: this.isOptional, isReadonly: this.isReadonly, annotations: toJSONAnnotations(this.annotations) }; } } /** * @since 3.10.0 */ export const isParameter = ast => { switch (ast._tag) { case "StringKeyword": case "SymbolKeyword": case "TemplateLiteral": return true; case "Refinement": return isParameter(ast.from); } return false; }; /** * @category model * @since 3.10.0 */ export class IndexSignature { type; isReadonly; /** * @since 3.10.0 */ parameter; constructor(parameter, type, isReadonly) { this.type = type; this.isReadonly = isReadonly; if (isParameter(parameter)) { this.parameter = parameter; } else { throw new Error(errors_.getASTIndexSignatureParameterErrorMessage); } } /** * @since 3.10.0 */ toString() { return (this.isReadonly ? "readonly " : "") + `[x: ${this.parameter}]: ${this.type}`; } /** * @since 3.10.0 */ toJSON() { return { parameter: this.parameter.toJSON(), type: this.type.toJSON(), isReadonly: this.isReadonly }; } } /** * @category model * @since 3.10.0 */ export class TypeLiteral { annotations; /** * @since 3.10.0 */ _tag = "TypeLiteral"; /** * @since 3.10.0 */ propertySignatures; /** * @since 3.10.0 */ indexSignatures; constructor(propertySignatures, indexSignatures, annotations = {}) { this.annotations = annotations; // check for duplicate property signatures const keys = {}; for (let i = 0; i < propertySignatures.length; i++) { const name = propertySignatures[i].name; if (Object.prototype.hasOwnProperty.call(keys, name)) { throw new Error(errors_.getASTDuplicatePropertySignatureErrorMessage(name)); } keys[name] = null; } // check for duplicate index signatures const parameters = { string: false, symbol: false }; for (let i = 0; i < indexSignatures.length; i++) { const encodedParameter = getEncodedParameter(indexSignatures[i].parameter); if (isStringKeyword(encodedParameter)) { if (parameters.string) { throw new Error(errors_.getASTDuplicateIndexSignatureErrorMessage("string")); } parameters.string = true; } else if (isSymbolKeyword(encodedParameter)) { if (parameters.symbol) { throw new Error(errors_.getASTDuplicateIndexSignatureErrorMessage("symbol")); } parameters.symbol = true; } } this.propertySignatures = propertySignatures; this.indexSignatures = indexSignatures; } /** * @since 3.10.0 */ toString() { return Option.getOrElse(getExpected(this), () => formatTypeLiteral(this)); } /** * @since 3.10.0 */ toJSON() { return { _tag: this._tag, propertySignatures: this.propertySignatures.map(ps => ps.toJSON()), indexSignatures: this.indexSignatures.map(ps => ps.toJSON()), annotations: toJSONAnnotations(this.annotations) }; } } const formatIndexSignatures = iss => iss.map(String).join("; "); const formatTypeLiteral = ast => { if (ast.propertySignatures.length > 0) { const pss = ast.propertySignatures.map(String).join("; "); if (ast.indexSignatures.length > 0) { return `{ ${pss}; ${formatIndexSignatures(ast.indexSignatures)} }`; } else { return `{ ${pss} }`; } } else { if (ast.indexSignatures.length > 0) { return `{ ${formatIndexSignatures(ast.indexSignatures)} }`; } else { return "{}"; } } }; /** * @category guards * @since 3.10.0 */ export const isTypeLiteral = /*#__PURE__*/createASTGuard("TypeLiteral"); const sortCandidates = /*#__PURE__*/Arr.sort(/*#__PURE__*/Order.mapInput(Number.Order, ast => { switch (ast._tag) { case "AnyKeyword": return 0; case "UnknownKeyword": return 1; case "ObjectKeyword": return 2; case "StringKeyword": case "NumberKeyword": case "BooleanKeyword": case "BigIntKeyword": case "SymbolKeyword": return 3; } return 4; })); const literalMap = { string: "StringKeyword", number: "NumberKeyword", boolean: "BooleanKeyword", bigint: "BigIntKeyword" }; /** @internal */ export const flatten = candidates => Arr.flatMap(candidates, ast => isUnion(ast) ? flatten(ast.types) : [ast]); /** @internal */ export const unify = candidates => { const cs = sortCandidates(candidates); const out = []; const uniques = {}; const literals = []; for (const ast of cs) { switch (ast._tag) { case "NeverKeyword": break; case "AnyKeyword": return [anyKeyword]; case "UnknownKeyword": return [unknownKeyword]; // uniques case "ObjectKeyword": case "UndefinedKeyword": case "VoidKeyword": case "StringKeyword": case "NumberKeyword": case "BooleanKeyword": case "BigIntKeyword": case "SymbolKeyword": { if (!uniques[ast._tag]) { uniques[ast._tag] = ast; out.push(ast); } break; } case "Literal": { const type = typeof ast.literal; switch (type) { case "string": case "number": case "bigint": case "boolean": { const _tag = literalMap[type]; if (!uniques[_tag] && !literals.includes(ast.literal)) { literals.push(ast.literal); out.push(ast); } break; } // null case "object": { if (!literals.includes(ast.literal)) { literals.push(ast.literal); out.push(ast); } break; } } break; } case "UniqueSymbol": { if (!uniques["SymbolKeyword"] && !literals.includes(ast.symbol)) { literals.push(ast.symbol); out.push(ast); } break; } case "TupleType": { if (!uniques["ObjectKeyword"]) { out.push(ast); } break; } case "TypeLiteral": { if (ast.propertySignatures.length === 0 && ast.indexSignatures.length === 0) { if (!uniques["{}"]) { uniques["{}"] = ast; out.push(ast); } } else if (!uniques["ObjectKeyword"]) { out.push(ast); } break; } default: out.push(ast); } } return out; }; /** * @category model * @since 3.10.0 */ export class Union { types; annotations; static make = (types, annotations) => { return isMembers(types) ? new Union(types, annotations) : types.length === 1 ? types[0] : neverKeyword; }; /** @internal */ static unify = (candidates, annotations) => { return Union.make(unify(flatten(candidates)), annotations); }; /** * @since 3.10.0 */ _tag = "Union"; constructor(types, annotations = {}) { this.types = types; this.annotations = annotations; } /** * @since 3.10.0 */ toString() { return Option.getOrElse(getExpected(this), () => this.types.map(String).join(" | ")); } /** * @since 3.10.0 */ toJSON() { return { _tag: this._tag, types: this.types.map(ast => ast.toJSON()), annotations: toJSONAnnotations(this.annotations) }; } } /** @internal */ export const mapMembers = (members, f) => members.map(f); /** @internal */ export const isMembers = as => as.length > 1; /** * @category guards * @since 3.10.0 */ export const isUnion = /*#__PURE__*/createASTGuard("Union"); const toJSONMemoMap = /*#__PURE__*/globalValue(/*#__PURE__*/Symbol.for("effect/Schema/AST/toJSONMemoMap"), () => new WeakMap()); /** * @category model * @since 3.10.0 */ export class Suspend { f; annotations; /** * @since 3.10.0 */ _tag = "Suspend"; constructor(f, annotations = {}) { this.f = f; this.annotations = annotations; this.f = util_.memoizeThunk(f); } /** * @since 3.10.0 */ toString() { return getExpected(this).pipe(Option.orElse(() => Option.flatMap(Option.liftThrowable(this.f)(), ast => getExpected(ast))), Option.getOrElse(() => "")); } /** * @since 3.10.0 */ toJSON() { const ast = this.f(); let out = toJSONMemoMap.get(ast); if (out) { return out; } toJSONMemoMap.set(ast, { _tag: this._tag }); out = { _tag: this._tag, ast: ast.toJSON(), annotations: toJSONAnnotations(this.annotations) }; toJSONMemoMap.set(ast, out); return out; } } /** * @category guards * @since 3.10.0 */ export const isSuspend = /*#__PURE__*/createASTGuard("Suspend"); /** * @category model * @since 3.10.0 */ export class Refinement { from; filter; annotations; /** * @since 3.10.0 */ _tag = "Refinement"; constructor(from, filter, annotations = {}) { this.from = from; this.filter = filter; this.annotations = annotations; } /** * @since 3.10.0 */ toString() { return getIdentifierAnnotation(this).pipe(Option.getOrElse(() => Option.match(getOrElseExpected(this), { onNone: () => `{ ${this.from} | filter }`, onSome: expected => isRefinement(this.from) ? String(this.from) + " & " + expected : expected }))); } /** * @since 3.10.0 */ toJSON() { return { _tag: this._tag, from: this.from.toJSON(), annotations: toJSONAnnotations(this.annotations) }; } } /** * @category guards * @since 3.10.0 */ export const isRefinement = /*#__PURE__*/createASTGuard("Refinement"); /** * @since 3.10.0 */ export const defaultParseOption = {}; /** * @category model * @since 3.10.0 */ export class Transformation { from; to; transformation; annotations; /** * @since 3.10.0 */ _tag = "Transformation"; constructor(from, to, transformation, annotations = {}) { this.from = from; this.to = to; this.transformation = transformation; this.annotations = annotations; } /** * @since 3.10.0 */ toString() { return Option.getOrElse(getExpected(this), () => `(${String(this.from)} <-> ${String(this.to)})`); } /** * @since 3.10.0 */ toJSON() { return { _tag: this._tag, from: this.from.toJSON(), to: this.to.toJSON(), annotations: toJSONAnnotations(this.annotations) }; } } /** * @category guards * @since 3.10.0 */ export const isTransformation = /*#__PURE__*/createASTGuard("Transformation"); /** * @category model * @since 3.10.0 */ export class FinalTransformation { decode; encode; /** * @since 3.10.0 */ _tag = "FinalTransformation"; constructor(decode, encode) { this.decode = decode; this.encode = encode; } } const createTransformationGuard = tag => ast => ast._tag === tag; /** * @category guards * @since 3.10.0 */ export const isFinalTransformation = /*#__PURE__*/createTransformationGuard("FinalTransformation"); /** * @category model * @since 3.10.0 */ export class ComposeTransformation { /** * @since 3.10.0 */ _tag = "ComposeTransformation"; } /** * @category constructors * @since 3.10.0 */ export const composeTransformation = /*#__PURE__*/new ComposeTransformation(); /** * @category guards * @since 3.10.0 */ export const isComposeTransformation = /*#__PURE__*/createTransformationGuard("ComposeTransformation"); /** * Represents a `PropertySignature -> PropertySignature` transformation * * The semantic of `decode` is: * - `none()` represents the absence of the key/value pair * - `some(value)` represents the presence of the key/value pair * * The semantic of `encode` is: * - `none()` you don't want to output the key/value pair * - `some(value)` you want to output the key/value pair * * @category model * @since 3.10.0 */ export class PropertySignatureTransformation { from; to; decode; encode; constructor(from, to, decode, encode) { this.from = from; this.to = to; this.decode = decode; this.encode = encode; } } const isRenamingPropertySignatureTransformation = t => t.decode === identity && t.encode === identity; /** * @category model * @since 3.10.0 */ export class TypeLiteralTransformation { propertySignatureTransformations; /** * @since 3.10.0 */ _tag = "TypeLiteralTransformation"; constructor(propertySignatureTransformations) { this.propertySignatureTransformations = propertySignatureTransformations; // check for duplicate property signature transformations const fromKeys = {}; const toKeys = {}; for (const pst of propertySignatureTransformations) { const from = pst.from; if (fromKeys[from]) { throw new Error(errors_.getASTDuplicatePropertySignatureTransformationErrorMessage(from)); } fromKeys[from] = true; const to = pst.to; if (toKeys[to]) { throw new Error(errors_.getASTDuplicatePropertySignatureTransformationErrorMessage(to)); } toKeys[to] = true; } } } /** * @category guards * @since 3.10.0 */ export const isTypeLiteralTransformation = /*#__PURE__*/createTransformationGuard("TypeLiteralTransformation"); // ------------------------------------------------------------------------------------- // API // ------------------------------------------------------------------------------------- /** * Merges a set of new annotations with existing ones, potentially overwriting * any duplicates. * * @since 3.10.0 */ export const annotations = (ast, overrides) => { const d = Object.getOwnPropertyDescriptors(ast); const value = { ...ast.annotations, ...overrides }; const surrogate = getSurrogateAnnotation(ast); if (Option.isSome(surrogate)) { value[SurrogateAnnotationId] = annotations(surrogate.value, overrides); } d.annotations.value = value; return Object.create(Object.getPrototypeOf(ast), d); }; /** * Equivalent at runtime to the TypeScript type-level `keyof` operator. * * @since 3.10.0 */ export const keyof = ast => Union.unify(_keyof(ast)); const STRING_KEYWORD_PATTERN = "[\\s\\S]*"; // any string, including newlines const NUMBER_KEYWORD_PATTERN = "[+-]?\\d*\\.?\\d+(?:[Ee][+-]?\\d+)?"; const getTemplateLiteralSpanTypePattern = (type, capture) => { switch (type._tag) { case "Literal": return regexp.escape(String(type.literal)); case "StringKeyword": return STRING_KEYWORD_PATTERN; case "NumberKeyword": return NUMBER_KEYWORD_PATTERN; case "TemplateLiteral": return getTemplateLiteralPattern(type, capture, false); case "Union": return type.types.map(type => getTemplateLiteralSpanTypePattern(type, capture)).join("|"); } }; const handleTemplateLiteralSpanTypeParens = (type, s, capture, top) => { if (isUnion(type)) { if (capture && !top) { return `(?:${s})`; } } else if (!capture || !top) { return s; } return `(${s})`; }; const getTemplateLiteralPattern = (ast, capture, top) => { let pattern = ``; if (ast.head !== "") { const head = regexp.escape(ast.head); pattern += capture && top ? `(${head})` : head; } for (const span of ast.spans) { const spanPattern = getTemplateLiteralSpanTypePattern(span.type, capture); pattern += handleTemplateLiteralSpanTypeParens(span.type, spanPattern, capture, top); if (span.literal !== "") { const literal = regexp.escape(span.literal); pattern += capture && top ? `(${literal})` : literal; } } return pattern; }; /** * Generates a regular expression from a `TemplateLiteral` AST node. * * @see {@link getTemplateLiteralCapturingRegExp} for a variant that captures the pattern. * * @since 3.10.0 */ export const getTemplateLiteralRegExp = ast => new RegExp(`^${getTemplateLiteralPattern(ast, false, true)}$`); /** * Generates a regular expression that captures the pattern defined by the given `TemplateLiteral` AST. * * @see {@link getTemplateLiteralRegExp} for a variant that does not capture the pattern. * * @since 3.10.0 */ export const getTemplateLiteralCapturingRegExp = ast => new RegExp(`^${getTemplateLiteralPattern(ast, true, true)}$`); /** * @since 3.10.0 */ export const getPropertySignatures = ast => { const annotation = getSurrogateAnnotation(ast); if (Option.isSome(annotation)) { return getPropertySignatures(annotation.value); } switch (ast._tag) { case "TypeLiteral": return ast.propertySignatures.slice(); case "Suspend": return getPropertySignatures(ast.f()); case "Refinement": return getPropertySignatures(ast.from); } return getPropertyKeys(ast).map(name => getPropertyKeyIndexedAccess(ast, name)); }; const getIndexSignatures = ast => { const annotation = getSurrogateAnnotation(ast); if (Option.isSome(annotation)) { return getIndexSignatures(annotation.value); } switch (ast._tag) { case "TypeLiteral": return ast.indexSignatures.slice(); case "Suspend": return getIndexSignatures(ast.f()); case "Refinement": return getIndexSignatures(ast.from); } return []; }; /** @internal */ export const getNumberIndexedAccess = ast => { switch (ast._tag) { case "TupleType": { let hasOptional = false; let out = []; for (const e of ast.elements) { if (e.isOptional) { hasOptional = true; } out.push(e.type); } if (hasOptional) { out.push(undefinedKeyword); } out = out.concat(getRestASTs(ast.rest)); return Union.make(out); } case "Refinement": return getNumberIndexedAccess(ast.from); case "Union": return Union.make(ast.types.map(getNumberIndexedAccess)); case "Suspend": return getNumberIndexedAccess(ast.f()); } throw new Error(errors_.getASTUnsupportedSchemaErrorMessage(ast)); }; const getTypeLiteralPropertySignature = (ast, name) => { // from property signatures... const ops = Arr.findFirst(ast.propertySignatures, ps => ps.name === name); if (Option.isSome(ops)) { return ops.value; } // from index signatures... if (Predicate.isString(name)) { let out = undefined; for (const is of ast.indexSignatures) { const encodedParameter = getEncodedParameter(is.parameter); switch (encodedParameter._tag) { case "TemplateLiteral": { const regex = getTemplateLiteralRegExp(encodedParameter); if (regex.test(name)) { return new PropertySignature(name, is.type, false, true); } break; } case "StringKeyword": { if (out === undefined) { out = new PropertySignature(name, is.type, false, true); } } } } if (out) { return out; } } else if (Predicate.isSymbol(name)) { for (const is of ast.indexSignatures) { const encodedParameter = getEncodedParameter(is.parameter); if (isSymbolKeyword(encodedParameter)) { return new PropertySignature(name, is.type, false, true); } } } }; /** @internal */ export const getPropertyKeyIndexedAccess = (ast, name) => { const annotation = getSurrogateAnnotation(ast); if (Option.isSome(annotation)) { return getPropertyKeyIndexedAccess(annotation.value, name); } switch (ast._tag) { case "TypeLiteral": { const ps = getTypeLiteralPropertySignature(ast, name); if (ps) { return ps; } break; } case "Union": return new PropertySignature(name, Union.make(ast.types.map(ast => getPropertyKeyIndexedAccess(ast, name).type)), false, true); case "Suspend": return getPropertyKeyIndexedAccess(ast.f(), name); case "Refinement": return getPropertyKeyIndexedAccess(ast.from, name); } throw new Error(errors_.getASTUnsupportedSchemaErrorMessage(ast)); }; const getPropertyKeys = ast => { const annotation = getSurrogateAnnotation(ast); if (Option.isSome(annotation)) { return getPropertyKeys(annotation.value); } switch (ast._tag) { case "TypeLiteral": return ast.propertySignatures.map(ps => ps.name); case "Union": return ast.types.slice(1).reduce((out, ast) => Arr.intersection(out, getPropertyKeys(ast)), getPropertyKeys(ast.types[0])); case "Suspend": return getPropertyKeys(ast.f()); case "Refinement": return getPropertyKeys(ast.from); case "Transformation": return getPropertyKeys(ast.to); } return []; }; /** @internal */ export const record = (key, value) => { const propertySignatures = []; const indexSignatures = []; const go = key => { switch (key._tag) { case "NeverKeyword": break; case "StringKeyword": case "SymbolKeyword": case "TemplateLiteral": case "Refinement": indexSignatures.push(new IndexSignature(key, value, true)); break; case "Literal": if (Predicate.isString(key.literal) || Predicate.isNumber(key.literal)) { propertySignatures.push(new PropertySignature(key.literal, value, false, true)); } else { throw new Error(errors_.getASTUnsupportedLiteralErrorMessage(key.literal)); } break; case "Enums": { for (const [_, name] of key.enums) { propertySignatures.push(new PropertySignature(name, value, false, true)); } break; } case "UniqueSymbol": propertySignatures.push(new PropertySignature(key.symbol, value, false, true)); break; case "Union": key.types.forEach(go); break; default: throw new Error(errors_.getASTUnsupportedKeySchemaErrorMessage(key)); } }; go(key); return { propertySignatures, indexSignatures }; }; /** * Equivalent at runtime to the built-in TypeScript utility type `Pick`. * * @since 3.10.0 */ export const pick = (ast, keys) => { const annotation = getSurrogateAnnotation(ast); if (Option.isSome(annotation)) { return pick(annotation.value, keys); } switch (ast._tag) { case "TypeLiteral": { const pss = []; const names = {}; for (const ps of ast.propertySignatures) { names[ps.name] = null; if (keys.includes(ps.name)) { pss.push(ps); } } for (const key of keys) { if (!(key in names)) { const ps = getTypeLiteralPropertySignature(ast, key); if (ps) { pss.push(ps); } } } return new TypeLiteral(pss, []); } case "Union": return new TypeLiteral(keys.map(name => getPropertyKeyIndexedAccess(ast, name)), []); case "Suspend": return pick(ast.f(), keys); case "Refinement": return pick(ast.from, keys); case "Transformation": { switch (ast.transformation._tag) { case "ComposeTransformation": return new Transformation(pick(ast.from, keys), pick(ast.to, keys), composeTransformation); case "TypeLiteralTransformation": { const ts = []; const fromKeys = []; for (const k of keys) { const t = ast.transformation.propertySignatureTransformations.find(t => t.to === k); if (t) { ts.push(t); fromKeys.push(t.from); } else { fromKeys.push(k); } } return Arr.isNonEmptyReadonlyArray(ts) ? new Transformation(pick(ast.from, fromKeys), pick(ast.to, keys), new TypeLiteralTransformation(ts)) : pick(ast.from, fromKeys); } } } } throw new Error(errors_.getASTUnsupportedSchemaErrorMessage(ast)); }; /** * Equivalent at runtime to the built-in TypeScript utility type `Omit`. * * @since 3.10.0 */ export const omit = (ast, keys) => { let indexSignatures = getIndexSignatures(ast); if (indexSignatures.length > 0) { if (indexSignatures.some(is => isStringKeyword(getEncodedParameter(is.parameter)))) { indexSignatures = indexSignatures.filter(is => !isTemplateLiteral(getEncodedParameter(is.parameter))); } return new TypeLiteral([], indexSignatures); } return pick(ast, getPropertyKeys(ast).filter(name => !keys.includes(name))); }; /** @internal */ export const orUndefined = ast => Union.make([ast, undefinedKeyword]); /** * Equivalent at runtime to the built-in TypeScript utility type `Partial`. * * @since 3.10.0 */ export const partial = (ast, options) => { const exact = options?.exact === true; switch (ast._tag) { case "TupleType": return new TupleType(ast.elements.map(e => new OptionalType(exact ? e.type : orUndefined(e.type), true)), Arr.match(ast.rest, { onEmpty: () => ast.rest, onNonEmpty: rest => [new Type(Union.make([...getRestASTs(rest), undefinedKeyword]))] }), ast.isReadonly); case "TypeLiteral": return new TypeLiteral(ast.propertySignatures.map(ps => new PropertySignature(ps.name, exact ? ps.type : orUndefined(ps.type), true, ps.isReadonly, ps.annotations)), ast.indexSignatures.map(is => new IndexSignature(is.parameter, orUndefined(is.type), is.isReadonly))); case "Union": return Union.make(ast.types.map(member => partial(member, options))); case "Suspend": return new Suspend(() => partial(ast.f(), options)); case "Declaration": case "Refinement": throw new Error(errors_.getASTUnsupportedSchemaErrorMessage(ast)); case "Transformation": { if (isTypeLiteralTransformation(ast.transformation) && ast.transformation.propertySignatureTransformations.every(isRenamingPropertySignatureTransformation)) { return new Transformation(partial(ast.from, options), partial(ast.to, options), ast.transformation); } throw new Error(errors_.getASTUnsupportedSchemaErrorMessage(ast)); } } return ast; }; /** * Equivalent at runtime to the built-in TypeScript utility type `Required`. * * @since 3.10.0 */ export const required = ast => { switch (ast._tag) { case "TupleType": return new TupleType(ast.elements.map(e => new OptionalType(e.type, false)), ast.rest, ast.isReadonly); case "TypeLiteral": return new TypeLiteral(ast.propertySignatures.map(f => new PropertySignature(f.name, f.type, false, f.isReadonly, f.annotations)), ast.indexSignatures); case "Union": return Union.make(ast.types.map(member => required(member))); case "Suspend": return new Suspend(() => required(ast.f())); case "Declaration": case "Refinement": throw new Error(errors_.getASTUnsupportedSchemaErrorMessage(ast)); case "Transformation": { if (isTypeLiteralTransformation(ast.transformation) && ast.transformation.propertySignatureTransformations.every(isRenamingPropertySignatureTransformation)) { return new Transformation(required(ast.from), required(ast.to), ast.transformation); } throw new Error(errors_.getASTUnsupportedSchemaErrorMessage(ast)); } } return ast; }; /** * Creates a new AST with shallow mutability applied to its properties. * * @since 3.10.0 */ export const mutable = ast => { switch (ast._tag) { case "TupleType": return ast.isReadonly === false ? ast : new TupleType(ast.elements, ast.rest, false, ast.annotations); case "TypeLiteral": { const propertySignatures = changeMap(ast.propertySignatures, ps => ps.isReadonly === false ? ps : new PropertySignature(ps.name, ps.type, ps.isOptional, false, ps.annotations)); const indexSignatures = changeMap(ast.indexSignatures, is => is.isReadonly === false ? is : new IndexSignature(is.parameter, is.type, false)); return propertySignatures === ast.propertySignatures && indexSignatures === ast.indexSignatures ? ast : new TypeLiteral(propertySignatures, indexSignatures, ast.annotations); } case "Union": { const types = changeMap(ast.types, mutable); return types === ast.types ? ast : Union.make(types, ast.annotations); } case "Suspend": return new Suspend(() => mutable(ast.f()), ast.annotations); case "Refinement": { const from = mutable(ast.from); return from === ast.from ? ast : new Refinement(from, ast.filter, ast.annotations); } case "Transformation": { const from = mutable(ast.from); const to = mutable(ast.to); return from === ast.from && to === ast.to ? ast : new Transformation(from, to, ast.transformation, ast.annotations); } } return ast; }; /** * @since 3.10.0 */ export const getCompiler = match => { const compile = (ast, path) => match[ast._tag](ast, compile, path); return compile; }; /** @internal */ export const pickAnnotations = annotationIds => annotated => { let out = undefined; for (const id of annotationIds) { if (Object.prototype.hasOwnProperty.call(annotated.annotations, id)) { if (out === undefined) { out = {}; } out[id] = annotated.annotations[id]; } } return out; }; /** @internal */ export const omitAnnotations = annotationIds => annotated => { const out = { ...annotated.annotations }; for (const id of annotationIds) { delete out[id]; } return out; }; const preserveTransformationAnnotations = /*#__PURE__*/pickAnnotations([ExamplesAnnotationId, DefaultAnnotationId, JSONSchemaAnnotationId, ArbitraryAnnotationId, PrettyAnnotationId, EquivalenceAnnotationId]); /** * @since 3.10.0 */ export const typeAST = ast => { switch (ast._tag) { case "Declaration": { const typeParameters = changeMap(ast.typeParameters, typeAST); return typeParameters === ast.typeParameters ? ast : new Declaration(typeParameters, ast.decodeUnknown, ast.encodeUnknown, ast.annotations); } case "TupleType": { const elements = changeMap(ast.elements, e => { const type = typeAST(e.type); return type === e.type ? e : new OptionalType(type, e.isOptional); }); const restASTs = getRestASTs(ast.rest); const rest = changeMap(restASTs, typeAST); return elements === ast.elements && rest === restASTs ? ast : new TupleType(elements, rest.map(type => new Type(type)), ast.isReadonly, ast.annotations); } case "TypeLiteral": { const propertySignatures = changeMap(ast.propertySignatures, p => { const type = typeAST(p.type); return type === p.type ? p : new PropertySignature(p.name, type, p.isOptional, p.isReadonly); }); const indexSignatures = changeMap(ast.indexSignatures, is => { const type = typeAST(is.type); return type === is.type ? is : new IndexSignature(is.parameter, type, is.isReadonly); }); return propertySignatures === ast.propertySignatures && indexSignatures === ast.indexSignatures ? ast : new TypeLiteral(propertySignatures, indexSignatures, ast.annotations); } case "Union": { const types = changeMap(ast.types, typeAST); return types === ast.types ? ast : Union.make(types, ast.annotations); } case "Suspend": return new Suspend(() => typeAST(ast.f()), ast.annotations); case "Refinement": { const from = typeAST(ast.from); return from === ast.from ? ast : new Refinement(from, ast.filter, ast.annotations); } case "Transformation": { const preserve = preserveTransformationAnnotations(ast); return typeAST(preserve !== undefined ? annotations(ast.to, preserve) : ast.to); } } return ast; }; // To generate a JSON Schema from a recursive schema, an `identifier` annotation // is required. So, when we calculate the encodedAST, we need to preserve the // annotation in the form of an internal custom annotation that acts as a // surrogate for the identifier, which the JSON Schema compiler can then read. const createJSONIdentifierAnnotation = annotated => Option.match(getJSONIdentifier(annotated), { onNone: () => undefined, onSome: identifier => ({ [JSONIdentifierAnnotationId]: identifier }) }); function changeMap(as, f) { let changed = false; const out = Arr.allocate(as.length); for (let i = 0; i < as.length; i++) { const a = as[i]; const fa = f(a); if (fa !== a) { changed = true; } out[i] = fa; } return changed ? out : as; } /** * Returns the from part of a transformation if it exists * * @internal */ export const getTransformationFrom = ast => { switch (ast._tag) { case "Transformation": return ast.from; case "Refinement": return getTransformationFrom(ast.from); case "Suspend": return getTransformationFrom(ast.f()); } }; const encodedAST_ = (ast, isBound) => { switch (ast._tag) { case "Declaration": { const typeParameters = changeMap(ast.typeParameters, ast => encodedAST_(ast, isBound)); return typeParameters === ast.typeParameters ? ast : new Declaration(typeParameters, ast.decodeUnknown, ast.encodeUnknown, ast.annotations); } case "TupleType": { const elements = changeMap(ast.elements, e => { const type = encodedAST_(e.type, isBound); return type === e.type ? e : new OptionalType(type, e.isOptional); }); const restASTs = getRestASTs(ast.rest); const rest = changeMap(restASTs, ast => encodedAST_(ast, isBound)); return elements === ast.elements && rest === restASTs ? ast : new TupleType(elements, rest.map(ast => new Type(ast)), ast.isReadonly, createJSONIdentifierAnnotation(ast)); } case "TypeLiteral": { const propertySignatures = changeMap(ast.propertySignatures, ps => { const type = encodedAST_(ps.type, isBound); return type === ps.type ? ps : new PropertySignature(ps.name, type, ps.isOptional, ps.isReadonly); }); const indexSignatures = changeMap(ast.indexSignatures, is => { const type = encodedAST_(is.type, isBound); return type === is.type ? is : new IndexSignature(is.parameter, type, is.isReadonly); }); return propertySignatures === ast.propertySignatures && indexSignatures === ast.indexSignatures ? ast : new TypeLiteral(propertySignatures, indexSignatures, createJSONIdentifierAnnotation(ast)); } case "Union": { const types = changeMap(ast.types, ast => encodedAST_(ast, isBound)); return types === ast.types ? ast : Union.make(types, createJSONIdentifierAnnotation(ast)); } case "Suspend": return new Suspend(() => encodedAST_(ast.f(), isBound), createJSONIdentifierAnnotation(ast)); case "Refinement": { const from = encodedAST_(ast.from, isBound); if (isBound) { if (from === ast.from) { return ast; } if (getTransformationFrom(ast.from) === undefined && hasStableFilter(ast)) { return new Refinement(from, ast.filter, ast.annotations); } } const identifier = createJSONIdentifierAnnotation(ast); return identifier ? annotations(from, identifier) : from; } case "Transformation": { const identifier = createJSONIdentifierAnnotation(ast); return encodedAST_(identifier ? annotations(ast.from, identifier) : ast.from, isBound); } } return ast; }; /** * @since 3.10.0 */ export const encodedAST = ast => encodedAST_(ast, false); /** * @since 3.10.0 */ export const encodedBoundAST = ast => encodedAST_(ast, true); const toJSONAnnotations = annotations => { const out = {}; for (const k of Object.getOwnPropertySymbols(annotations)) { out[String(k)] = annotations[k]; } return out; }; /** @internal */ export const getEncodedParameter = ast => { switch (ast._tag) { case "StringKeyword": case "SymbolKeyword": case "TemplateLiteral": return ast; case "Refinement": return getEncodedParameter(ast.from); } }; /** @internal */ export const equals = (self, that) => { switch (self._tag) { case "Literal": return isLiteral(that) && that.literal === self.literal; case "UniqueSymbol": return isUniqueSymbol(that) && that.symbol === self.symbol; case "UndefinedKeyword": case "VoidKeyword": case "NeverKeyword": case "UnknownKeyword": case "AnyKeyword": case "StringKeyword": case "NumberKeyword": case "BooleanKeyword": case "BigIntKeyword": case "SymbolKeyword": case "ObjectKeyword": return that._tag === self._tag; case "TemplateLiteral": return isTemplateLiteral(that) && that.head === self.head && equalsTemplateLiteralSpan(that.spans, self.spans); case "Enums": return isEnums(that) && equalsEnums(that.enums, self.enums); case "Union": return isUnion(that) && equalsUnion(self.types, that.types); case "Refinement": case "TupleType": case "TypeLiteral": case "Suspend": case "Transformation": case "Declaration": return self === that; } }; const equalsTemplateLiteralSpan = /*#__PURE__*/Arr.getEquivalence((self, that) => { return self.literal === that.literal && equals(self.type, that.type); }); const equalsEnums = /*#__PURE__*/Arr.getEquivalence((self, that) => that[0] === self[0] && that[1] === self[1]); const equalsUnion = /*#__PURE__*/Arr.getEquivalence(equals); const intersection = /*#__PURE__*/Arr.intersectionWith(equals); const _keyof = ast => { switch (ast._tag) { case "Declaration": { const annotation = getSurrogateAnnotation(ast); if (Option.isSome(annotation)) { return _keyof(annotation.value); } break; } case "TypeLiteral": return ast.propertySignatures.map(p => Predicate.isSymbol(p.name) ? new UniqueSymbol(p.name) : new Literal(p.name)).concat(ast.indexSignatures.map(is => getEncodedParameter(is.parameter))); case "Suspend": return _keyof(ast.f()); case "Union": return ast.types.slice(1).reduce((out, ast) => intersection(out, _keyof(ast)), _keyof(ast.types[0])); case "Transformation": return _keyof(ast.to); } throw new Error(errors_.getASTUnsupportedSchemaErrorMessage(ast)); }; /** @internal */ export const compose = (ab, cd) => new Transformation(ab, cd, composeTransformation); /** @internal */ export const rename = (ast, mapping) => { switch (ast._tag) { case "TypeLiteral": { const propertySignatureTransformations = []; for (const key of util_.ownKeys(mapping)) { const name = mapping[key]; if (name !== undefined) { propertySignatureTransformations.push(new PropertySignatureTransformation(key, name, identity, identity)); } } if (propertySignatureTransformations.length === 0) { return ast; } return new Transformation(ast, new TypeLiteral(ast.propertySignatures.map(ps => { const name = mapping[ps.name]; return new PropertySignature(name === undefined ? ps.name : name, typeAST(ps.type), ps.isOptional, ps.isReadonly, ps.annotations); }), ast.indexSignatures), new TypeLiteralTransformation(propertySignatureTransformations)); } case "Union": return Union.make(ast.types.map(ast => rename(ast, mapping))); case "Suspend": return new Suspend(() => rename(ast.f(), mapping)); case "Transformation": return compose(ast, rename(typeAST(ast), mapping)); } throw new Error(errors_.getASTUnsupportedRenameSchemaErrorMessage(ast)); }; const formatKeyword = ast => Option.getOrElse(getExpected(ast), () => ast._tag); function getBrands(ast) { return Option.match(getBrandAnnotation(ast), { onNone: () => "", onSome: brands => brands.map(brand => ` & Brand<${util_.formatUnknown(brand)}>`).join("") }); } const getOrElseExpected = ast => getTitleAnnotation(ast).pipe(Option.orElse(() => getDescriptionAnnotation(ast)), Option.orElse(() => getAutoTitleAnnotation(ast)), Option.map(s => s + getBrands(ast))); const getExpected = ast => Option.orElse(getIdentifierAnnotation(ast), () => getOrElseExpected(ast)); /** @internal */ export const pruneUndefined = (ast, self, onTransformation) => { switch (ast._tag) { case "UndefinedKeyword": return neverKeyword; case "Union": { const types = []; let hasUndefined = false; for (const type of ast.types) { const pruned = self(type); if (pruned) { hasUndefined = true; if (!isNeverKeyword(pruned)) { types.push(pruned); } } else { types.push(type); } } if (hasUndefined) { return Union.make(types); } break; } case "Suspend": return self(ast.f()); case "Transformation": return onTransformation(ast); } }; //# sourceMappingURL=SchemaAST.js.map