@effect/schema
Advanced tools
Comparing version 0.0.0-snapshot-64d29bc90eef90891aa52242a56ea80a52c18645 to 0.0.0-snapshot-6e9edd448c6d82afd40e9d971340ed91efdcfce7
@@ -96,3 +96,2 @@ "use strict"; | ||
}; | ||
const getArbitraryErrorMessage = (message, path) => errors_.getErrorMessageWithPath(`cannot build an Arbitrary for ${message}`, path); | ||
const go = (ast, options, path) => { | ||
@@ -113,3 +112,3 @@ const hook = getHook(ast); | ||
{ | ||
throw new Error(getArbitraryErrorMessage(`a declaration without annotations (${ast})`, path)); | ||
throw new Error(errors_.getArbitraryMissingAnnotationErrorMessage(path, ast)); | ||
} | ||
@@ -125,3 +124,3 @@ case "Literal": | ||
return () => { | ||
throw new Error(getArbitraryErrorMessage("`never`", path)); | ||
throw new Error(errors_.getArbitraryUnsupportedErrorMessage(path, ast)); | ||
}; | ||
@@ -201,3 +200,3 @@ case "UnknownKeyword": | ||
} | ||
const rest = ast.rest.map(e => go(e, options, path)); | ||
const rest = ast.rest.map(annotatedAST => go(annotatedAST.type, options, path)); | ||
return fc => { | ||
@@ -297,3 +296,3 @@ // --------------------------------------------- | ||
if (ast.enums.length === 0) { | ||
throw new Error(getArbitraryErrorMessage("an empty enum", path)); | ||
throw new Error(errors_.getArbitraryEmptyEnumErrorMessage(path)); | ||
} | ||
@@ -300,0 +299,0 @@ return fc => fc.oneof(...ast.enums.map(([_, value]) => fc.constant(value))); |
@@ -7,4 +7,5 @@ "use strict"; | ||
exports.formatIssueSync = exports.formatIssue = exports.formatErrorSync = exports.formatError = void 0; | ||
var Arr = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("effect/Array")); | ||
var array_ = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("effect/Array")); | ||
var Effect = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("effect/Effect")); | ||
var util_ = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("./internal/util.js")); | ||
var TreeFormatter = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("./TreeFormatter.js")); | ||
@@ -56,3 +57,3 @@ function _getRequireWildcardCache(e) { | ||
exports.formatIssueSync = formatIssueSync; | ||
const formatError = error => formatIssue(error.error); | ||
const formatError = error => formatIssue(error.issue); | ||
/** | ||
@@ -63,3 +64,3 @@ * @category formatting | ||
exports.formatError = formatError; | ||
const formatErrorSync = error => formatIssueSync(error.error); | ||
const formatErrorSync = error => formatIssueSync(error.issue); | ||
exports.formatErrorSync = formatErrorSync; | ||
@@ -75,3 +76,2 @@ const succeed = issue => Effect.succeed([issue]); | ||
}); | ||
const flatten = eff => Effect.map(eff, Arr.flatten); | ||
const go = (e, path = []) => { | ||
@@ -96,29 +96,19 @@ const _tag = e._tag; | ||
path, | ||
message: `is unexpected, expected ${e.ast.toString(true)}` | ||
message: TreeFormatter.formatUnexpectedMessage(e) | ||
}); | ||
case "Missing": | ||
return succeed({ | ||
return Effect.map(TreeFormatter.formatMissingMessage(e), message => [{ | ||
_tag, | ||
path, | ||
message: "is missing" | ||
}); | ||
case "Union": | ||
return getArray(e, path, () => flatten(Effect.forEach(e.errors, e => { | ||
switch (e._tag) { | ||
case "Member": | ||
return go(e.error, path); | ||
default: | ||
return go(e, path); | ||
} | ||
}))); | ||
case "TupleType": | ||
return getArray(e, path, () => flatten(Effect.forEach(e.errors, index => go(index.error, path.concat(index.index))))); | ||
case "TypeLiteral": | ||
return getArray(e, path, () => flatten(Effect.forEach(e.errors, key => go(key.error, path.concat(key.key))))); | ||
case "Declaration": | ||
message | ||
}]); | ||
case "Pointer": | ||
return go(e.issue, path.concat(e.path)); | ||
case "Composite": | ||
return getArray(e, path, () => util_.isNonEmpty(e.issues) ? Effect.map(Effect.forEach(e.issues, issue => go(issue, path)), array_.flatten) : go(e.issues, path)); | ||
case "Refinement": | ||
case "Transformation": | ||
return getArray(e, path, () => go(e.error, path)); | ||
return getArray(e, path, () => go(e.issue, path)); | ||
} | ||
}; | ||
//# sourceMappingURL=ArrayFormatter.js.map |
@@ -65,3 +65,2 @@ "use strict"; | ||
const getHook = /*#__PURE__*/AST.getAnnotation(EquivalenceHookId); | ||
const getEquivalenceErrorMessage = (message, path) => errors_.getErrorMessageWithPath(`cannot build an Equivalence for ${message}`, path); | ||
const go = (ast, path) => { | ||
@@ -81,3 +80,3 @@ const hook = getHook(ast); | ||
case "NeverKeyword": | ||
throw new Error(getEquivalenceErrorMessage("`never`", path)); | ||
throw new Error(errors_.getEquivalenceUnsupportedErrorMessage(ast, path)); | ||
case "Transformation": | ||
@@ -111,3 +110,3 @@ return go(ast.to, path); | ||
const elements = ast.elements.map((element, i) => go(element.type, path.concat(i))); | ||
const rest = ast.rest.map(ast => go(ast, path)); | ||
const rest = ast.rest.map(annotatedAST => go(annotatedAST.type, path)); | ||
return Equivalence.make((a, b) => { | ||
@@ -114,0 +113,0 @@ const len = a.length; |
@@ -6,3 +6,4 @@ "use strict"; | ||
}); | ||
exports.getErrorMessageWithPath = exports.getErrorMessage = exports.getDuplicatePropertySignatureErrorMessage = void 0; | ||
exports.getSchemaUnsupportedLiteralSpanErrorMessage = exports.getSchemaExtendErrorMessage = exports.getPrettyNoMatchingSchemaErrorMessage = exports.getPrettyNeverErrorMessage = exports.getPrettyMissingAnnotationErrorMessage = exports.getJSONSchemaUnsupportedPostRestElementsErrorMessage = exports.getJSONSchemaUnsupportedParameterErrorMessage = exports.getJSONSchemaUnsupportedKeyErrorMessage = exports.getJSONSchemaMissingIdentifierAnnotationErrorMessage = exports.getJSONSchemaMissingAnnotationErrorMessage = exports.getInvalidArgumentErrorMessage = exports.getEquivalenceUnsupportedErrorMessage = exports.getArbitraryUnsupportedErrorMessage = exports.getArbitraryMissingAnnotationErrorMessage = exports.getArbitraryEmptyEnumErrorMessage = exports.getASTUnsupportedSchema = exports.getASTUnsupportedRenameSchema = exports.getASTUnsupportedLiteral = exports.getASTUnsupportedKeySchema = exports.getASTRequiredElementFollowinAnOptionalElementErrorMessage = exports.getASTIndexSignatureParameterErrorMessage = exports.getASTDuplicatePropertySignatureTransformationErrorMessage = exports.getASTDuplicatePropertySignatureErrorMessage = exports.getASTDuplicateIndexSignatureErrorMessage = void 0; | ||
var array_ = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("effect/Array")); | ||
var util_ = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("./util.js")); | ||
@@ -34,17 +35,107 @@ function _getRequireWildcardCache(e) { | ||
} | ||
const getErrorMessage = (reason, details, path, ast) => { | ||
let out = reason; | ||
if (path && array_.isNonEmptyReadonlyArray(path)) { | ||
out += `\nat path: ${util_.formatPath(path)}`; | ||
} | ||
if (details !== undefined) { | ||
out += `\ndetails: ${details}`; | ||
} | ||
if (ast) { | ||
out += `\nschema (${ast._tag}): ${ast}`; | ||
} | ||
return out; | ||
}; | ||
// --------------------------------------------- | ||
// generic | ||
// --------------------------------------------- | ||
/** @internal */ | ||
const getDuplicatePropertySignatureErrorMessage = name => `Duplicate property signature ${util_.formatUnknown(name)}`; | ||
const getInvalidArgumentErrorMessage = details => getErrorMessage("Invalid Argument", details); | ||
exports.getInvalidArgumentErrorMessage = getInvalidArgumentErrorMessage; | ||
const getUnsupportedSchemaErrorMessage = (details, path, ast) => getErrorMessage("Unsupported schema", details, path, ast); | ||
const getMissingAnnotationErrorMessage = (details, path, ast) => getErrorMessage("Missing annotation", details, path, ast); | ||
// --------------------------------------------- | ||
// Arbitrary | ||
// --------------------------------------------- | ||
/** @internal */ | ||
exports.getDuplicatePropertySignatureErrorMessage = getDuplicatePropertySignatureErrorMessage; | ||
const getErrorMessage = (api, message) => `${api}: ${message}`; | ||
const getArbitraryUnsupportedErrorMessage = (path, ast) => getUnsupportedSchemaErrorMessage("Cannot build an Arbitrary for this schema", path, ast); | ||
/** @internal */ | ||
exports.getErrorMessage = getErrorMessage; | ||
const getErrorMessageWithPath = (message, path) => { | ||
let out = message; | ||
if (path.length > 0) { | ||
out += ` (path [${path.map(util_.formatPropertyKey).join(", ")}])`; | ||
} | ||
return out; | ||
}; | ||
exports.getErrorMessageWithPath = getErrorMessageWithPath; | ||
exports.getArbitraryUnsupportedErrorMessage = getArbitraryUnsupportedErrorMessage; | ||
const getArbitraryMissingAnnotationErrorMessage = (path, ast) => getMissingAnnotationErrorMessage(`Generating an Arbitrary for this schema requires an "arbitrary" annotation`, path, ast); | ||
/** @internal */ | ||
exports.getArbitraryMissingAnnotationErrorMessage = getArbitraryMissingAnnotationErrorMessage; | ||
const getArbitraryEmptyEnumErrorMessage = path => getErrorMessage("Empty Enums schema", "Generating an Arbitrary for this schema requires at least one enum", path); | ||
// --------------------------------------------- | ||
// Equivalence | ||
// --------------------------------------------- | ||
/** @internal */ | ||
exports.getArbitraryEmptyEnumErrorMessage = getArbitraryEmptyEnumErrorMessage; | ||
const getEquivalenceUnsupportedErrorMessage = (ast, path) => getUnsupportedSchemaErrorMessage("Cannot build an Equivalence", path, ast); | ||
// --------------------------------------------- | ||
// JSON Schema | ||
// --------------------------------------------- | ||
/** @internal */ | ||
exports.getEquivalenceUnsupportedErrorMessage = getEquivalenceUnsupportedErrorMessage; | ||
const getJSONSchemaMissingAnnotationErrorMessage = (path, ast) => getMissingAnnotationErrorMessage(`Generating a JSON Schema for this schema requires a "jsonSchema" annotation`, path, ast); | ||
/** @internal */ | ||
exports.getJSONSchemaMissingAnnotationErrorMessage = getJSONSchemaMissingAnnotationErrorMessage; | ||
const getJSONSchemaMissingIdentifierAnnotationErrorMessage = (path, ast) => getMissingAnnotationErrorMessage(`Generating a JSON Schema for this schema requires an "identifier" annotation`, path, ast); | ||
/** @internal */ | ||
exports.getJSONSchemaMissingIdentifierAnnotationErrorMessage = getJSONSchemaMissingIdentifierAnnotationErrorMessage; | ||
const getJSONSchemaUnsupportedParameterErrorMessage = (path, parameter) => getErrorMessage("Unsupported index signature parameter", undefined, path, parameter); | ||
/** @internal */ | ||
exports.getJSONSchemaUnsupportedParameterErrorMessage = getJSONSchemaUnsupportedParameterErrorMessage; | ||
const getJSONSchemaUnsupportedPostRestElementsErrorMessage = path => getErrorMessage("Generating a JSON Schema for post-rest elements is not currently supported. You're welcome to contribute by submitting a Pull Request", undefined, path); | ||
/** @internal */ | ||
exports.getJSONSchemaUnsupportedPostRestElementsErrorMessage = getJSONSchemaUnsupportedPostRestElementsErrorMessage; | ||
const getJSONSchemaUnsupportedKeyErrorMessage = (key, path) => getErrorMessage("Unsupported key", `Cannot encode ${util_.formatPropertyKey(key)} key to JSON Schema`, path); | ||
// --------------------------------------------- | ||
// Pretty | ||
// --------------------------------------------- | ||
/** @internal */ | ||
exports.getJSONSchemaUnsupportedKeyErrorMessage = getJSONSchemaUnsupportedKeyErrorMessage; | ||
const getPrettyMissingAnnotationErrorMessage = (path, ast) => getMissingAnnotationErrorMessage(`Generating a Pretty for this schema requires a "pretty" annotation`, path, ast); | ||
/** @internal */ | ||
exports.getPrettyMissingAnnotationErrorMessage = getPrettyMissingAnnotationErrorMessage; | ||
const getPrettyNeverErrorMessage = exports.getPrettyNeverErrorMessage = "Cannot pretty print a `never` value"; | ||
/** @internal */ | ||
const getPrettyNoMatchingSchemaErrorMessage = (actual, path, ast) => getErrorMessage("Unexpected Error", `Cannot find a matching schema for ${util_.formatUnknown(actual)}`, path, ast); | ||
// --------------------------------------------- | ||
// Schema | ||
// --------------------------------------------- | ||
/** @internal */ | ||
exports.getPrettyNoMatchingSchemaErrorMessage = getPrettyNoMatchingSchemaErrorMessage; | ||
const getSchemaExtendErrorMessage = (x, y, path) => getErrorMessage("Unsupported schema or overlapping types", `cannot extend ${x} with ${y}`, path); | ||
/** @internal */ | ||
exports.getSchemaExtendErrorMessage = getSchemaExtendErrorMessage; | ||
const getSchemaUnsupportedLiteralSpanErrorMessage = ast => getErrorMessage("Unsupported template literal span", undefined, undefined, ast); | ||
// --------------------------------------------- | ||
// AST | ||
// --------------------------------------------- | ||
/** @internal */ | ||
exports.getSchemaUnsupportedLiteralSpanErrorMessage = getSchemaUnsupportedLiteralSpanErrorMessage; | ||
const getASTUnsupportedSchema = ast => getUnsupportedSchemaErrorMessage(undefined, undefined, ast); | ||
/** @internal */ | ||
exports.getASTUnsupportedSchema = getASTUnsupportedSchema; | ||
const getASTUnsupportedKeySchema = ast => getErrorMessage("Unsupported key schema", undefined, undefined, ast); | ||
/** @internal */ | ||
exports.getASTUnsupportedKeySchema = getASTUnsupportedKeySchema; | ||
const getASTUnsupportedLiteral = literal => getErrorMessage("Unsupported literal", `literal value: ${util_.formatUnknown(literal)}`); | ||
/** @internal */ | ||
exports.getASTUnsupportedLiteral = getASTUnsupportedLiteral; | ||
const getASTDuplicateIndexSignatureErrorMessage = type => getErrorMessage("Duplicate index signature", `${type} index signature`); | ||
/** @internal */ | ||
exports.getASTDuplicateIndexSignatureErrorMessage = getASTDuplicateIndexSignatureErrorMessage; | ||
const getASTIndexSignatureParameterErrorMessage = exports.getASTIndexSignatureParameterErrorMessage = /*#__PURE__*/getErrorMessage("Unsupported index signature parameter", "An index signature parameter type must be `string`, `symbol`, a template literal type or a refinement of the previous types"); | ||
/** @internal */ | ||
const getASTRequiredElementFollowinAnOptionalElementErrorMessage = exports.getASTRequiredElementFollowinAnOptionalElementErrorMessage = /*#__PURE__*/getErrorMessage("Invalid element", "A required element cannot follow an optional element. ts(1257)"); | ||
/** @internal */ | ||
const getASTDuplicatePropertySignatureTransformationErrorMessage = key => getErrorMessage("Duplicate property signature transformation", `Duplicate key ${util_.formatUnknown(key)}`); | ||
/** @internal */ | ||
exports.getASTDuplicatePropertySignatureTransformationErrorMessage = getASTDuplicatePropertySignatureTransformationErrorMessage; | ||
const getASTUnsupportedRenameSchema = ast => getUnsupportedSchemaErrorMessage(undefined, undefined, ast); | ||
/** @internal */ | ||
exports.getASTUnsupportedRenameSchema = getASTUnsupportedRenameSchema; | ||
const getASTDuplicatePropertySignatureErrorMessage = key => getErrorMessage("Duplicate property signature", `Duplicate key ${util_.formatUnknown(key)}`); | ||
exports.getASTDuplicatePropertySignatureErrorMessage = getASTDuplicatePropertySignatureErrorMessage; | ||
//# sourceMappingURL=errors.js.map |
@@ -6,3 +6,3 @@ "use strict"; | ||
}); | ||
exports.MinLengthTypeId = exports.MinItemsTypeId = exports.MaxLengthTypeId = exports.MaxItemsTypeId = exports.LessThanTypeId = exports.LessThanOrEqualToTypeId = exports.LessThanOrEqualToBigIntTypeId = exports.LessThanBigIntTypeId = exports.LengthTypeId = exports.ItemsCountTypeId = exports.IntTypeId = exports.GreaterThanTypeId = exports.GreaterThanOrEqualToTypeId = exports.GreaterThanOrEqualToBigIntTypeId = exports.GreaterThanBigintTypeId = exports.BetweenTypeId = exports.BetweenBigintTypeId = void 0; | ||
exports.ParseJsonTypeId = exports.MinLengthTypeId = exports.MinItemsTypeId = exports.MaxLengthTypeId = exports.MaxItemsTypeId = exports.LessThanTypeId = exports.LessThanOrEqualToTypeId = exports.LessThanOrEqualToBigIntTypeId = exports.LessThanBigIntTypeId = exports.LengthTypeId = exports.ItemsCountTypeId = exports.IntTypeId = exports.GreaterThanTypeId = exports.GreaterThanOrEqualToTypeId = exports.GreaterThanOrEqualToBigIntTypeId = exports.GreaterThanBigintTypeId = exports.BetweenTypeId = exports.BetweenBigintTypeId = void 0; | ||
/** @internal */ | ||
@@ -42,2 +42,4 @@ const GreaterThanTypeId = exports.GreaterThanTypeId = /*#__PURE__*/Symbol.for("@effect/schema/TypeId/GreaterThan"); | ||
const ItemsCountTypeId = exports.ItemsCountTypeId = /*#__PURE__*/Symbol.for("@effect/schema/TypeId/ItemsCount"); | ||
/** @internal */ | ||
const ParseJsonTypeId = exports.ParseJsonTypeId = /*#__PURE__*/Symbol.for("@effect/schema/TypeId/ParseJson"); | ||
//# sourceMappingURL=filters.js.map |
@@ -6,3 +6,4 @@ "use strict"; | ||
}); | ||
exports.ownKeys = exports.memoizeThunk = exports.getKeysForIndexSignature = exports.formatUnknown = exports.formatPropertyKey = void 0; | ||
exports.ownKeys = exports.memoizeThunk = exports.isSingle = exports.isNonEmpty = exports.getKeysForIndexSignature = exports.formatUnknown = exports.formatPropertyKey = exports.formatPathKey = exports.formatPath = void 0; | ||
var array_ = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("effect/Array")); | ||
var Predicate = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("effect/Predicate")); | ||
@@ -72,3 +73,3 @@ function _getRequireWildcardCache(e) { | ||
return String(u) + "n"; | ||
} else if (!Array.isArray(u) && Predicate.hasProperty(u, "toString") && Predicate.isFunction(u["toString"]) && u["toString"] !== Object.prototype.toString) { | ||
} else if (!array_.isArray(u) && Predicate.hasProperty(u, "toString") && Predicate.isFunction(u["toString"]) && u["toString"] !== Object.prototype.toString) { | ||
return u["toString"](); | ||
@@ -78,3 +79,3 @@ } | ||
JSON.stringify(u); | ||
if (Array.isArray(u)) { | ||
if (array_.isArray(u)) { | ||
return `[${u.map(formatUnknown).join(",")}]`; | ||
@@ -91,3 +92,15 @@ } else { | ||
const formatPropertyKey = name => typeof name === "string" ? JSON.stringify(name) : String(name); | ||
/** @internal */ | ||
exports.formatPropertyKey = formatPropertyKey; | ||
const isNonEmpty = x => Array.isArray(x); | ||
/** @internal */ | ||
exports.isNonEmpty = isNonEmpty; | ||
const isSingle = x => !Array.isArray(x); | ||
/** @internal */ | ||
exports.isSingle = isSingle; | ||
const formatPathKey = key => `[${formatPropertyKey(key)}]`; | ||
/** @internal */ | ||
exports.formatPathKey = formatPathKey; | ||
const formatPath = path => isNonEmpty(path) ? path.map(formatPathKey).join("") : formatPathKey(path); | ||
exports.formatPath = formatPath; | ||
//# sourceMappingURL=util.js.map |
@@ -12,2 +12,3 @@ "use strict"; | ||
var errors_ = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("./internal/errors.js")); | ||
var filters_ = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("./internal/filters.js")); | ||
function _getRequireWildcardCache(e) { | ||
@@ -101,4 +102,2 @@ if ("function" != typeof WeakMap) return null; | ||
}; | ||
const getMissingAnnotationErrorMessage = (name, path) => errors_.getErrorMessageWithPath(`cannot build a JSON Schema for ${name} without a JSON Schema annotation`, path); | ||
const getUnsupportedIndexSignatureParameterErrorMessage = (parameter, path) => errors_.getErrorMessageWithPath(`unsupported index signature parameter (${parameter})`, path); | ||
/** @internal */ | ||
@@ -124,2 +123,9 @@ const DEFINITION_PREFIX = exports.DEFINITION_PREFIX = "#/$defs/"; | ||
}; | ||
const isParseJsonTransformation = ast => ast.annotations[AST.TypeAnnotationId] === filters_.ParseJsonTypeId; | ||
function merge(a, b) { | ||
return { | ||
...a, | ||
...b | ||
}; | ||
} | ||
const go = (ast, $defs, handleIdentifier, path) => { | ||
@@ -131,12 +137,5 @@ const hook = AST.getJSONSchemaAnnotation(ast); | ||
try { | ||
return { | ||
...go(ast.from, $defs, true, path), | ||
...getJsonSchemaAnnotations(ast), | ||
...handler | ||
}; | ||
return merge(merge(go(ast.from, $defs, true, path), getJsonSchemaAnnotations(ast)), handler); | ||
} catch (e) { | ||
return { | ||
...getJsonSchemaAnnotations(ast), | ||
...handler | ||
}; | ||
return merge(getJsonSchemaAnnotations(ast), handler); | ||
} | ||
@@ -166,3 +165,3 @@ } | ||
case "Declaration": | ||
throw new Error(getMissingAnnotationErrorMessage("a declaration", path)); | ||
throw new Error(errors_.getJSONSchemaMissingAnnotationErrorMessage(path, ast)); | ||
case "Literal": | ||
@@ -172,71 +171,55 @@ { | ||
if (literal === null) { | ||
return { | ||
const: null, | ||
...getJsonSchemaAnnotations(ast) | ||
}; | ||
} else if (Predicate.isString(literal)) { | ||
return { | ||
const: literal, | ||
...getJsonSchemaAnnotations(ast) | ||
}; | ||
} else if (Predicate.isNumber(literal)) { | ||
return { | ||
const: literal, | ||
...getJsonSchemaAnnotations(ast) | ||
}; | ||
} else if (Predicate.isBoolean(literal)) { | ||
return { | ||
const: literal, | ||
...getJsonSchemaAnnotations(ast) | ||
}; | ||
return merge({ | ||
const: null | ||
}, getJsonSchemaAnnotations(ast)); | ||
} else if (Predicate.isString(literal) || Predicate.isNumber(literal) || Predicate.isBoolean(literal)) { | ||
return merge({ | ||
const: literal | ||
}, getJsonSchemaAnnotations(ast)); | ||
} | ||
throw new Error(getMissingAnnotationErrorMessage("a bigint literal", path)); | ||
throw new Error(errors_.getJSONSchemaMissingAnnotationErrorMessage(path, ast)); | ||
} | ||
case "UniqueSymbol": | ||
throw new Error(getMissingAnnotationErrorMessage("a unique symbol", path)); | ||
throw new Error(errors_.getJSONSchemaMissingAnnotationErrorMessage(path, ast)); | ||
case "UndefinedKeyword": | ||
throw new Error(getMissingAnnotationErrorMessage("`undefined`", path)); | ||
throw new Error(errors_.getJSONSchemaMissingAnnotationErrorMessage(path, ast)); | ||
case "VoidKeyword": | ||
throw new Error(getMissingAnnotationErrorMessage("`void`", path)); | ||
throw new Error(errors_.getJSONSchemaMissingAnnotationErrorMessage(path, ast)); | ||
case "NeverKeyword": | ||
throw new Error(getMissingAnnotationErrorMessage("`never`", path)); | ||
throw new Error(errors_.getJSONSchemaMissingAnnotationErrorMessage(path, ast)); | ||
case "UnknownKeyword": | ||
return { | ||
...unknownJsonSchema, | ||
...getJsonSchemaAnnotations(ast) | ||
}; | ||
return merge(unknownJsonSchema, getJsonSchemaAnnotations(ast)); | ||
case "AnyKeyword": | ||
return { | ||
...anyJsonSchema, | ||
...getJsonSchemaAnnotations(ast) | ||
}; | ||
return merge(anyJsonSchema, getJsonSchemaAnnotations(ast)); | ||
case "ObjectKeyword": | ||
return { | ||
...objectJsonSchema, | ||
...getJsonSchemaAnnotations(ast) | ||
}; | ||
return merge(objectJsonSchema, getJsonSchemaAnnotations(ast)); | ||
case "StringKeyword": | ||
return { | ||
type: "string", | ||
...getJsonSchemaAnnotations(ast) | ||
}; | ||
{ | ||
const out = { | ||
type: "string" | ||
}; | ||
return ast === AST.stringKeyword ? out : merge(out, getJsonSchemaAnnotations(ast)); | ||
} | ||
case "NumberKeyword": | ||
return { | ||
type: "number", | ||
...getJsonSchemaAnnotations(ast) | ||
}; | ||
{ | ||
const out = { | ||
type: "number" | ||
}; | ||
return ast === AST.numberKeyword ? out : merge(out, getJsonSchemaAnnotations(ast)); | ||
} | ||
case "BooleanKeyword": | ||
return { | ||
type: "boolean", | ||
...getJsonSchemaAnnotations(ast) | ||
}; | ||
{ | ||
const out = { | ||
type: "boolean" | ||
}; | ||
return ast === AST.booleanKeyword ? out : merge(out, getJsonSchemaAnnotations(ast)); | ||
} | ||
case "BigIntKeyword": | ||
throw new Error(getMissingAnnotationErrorMessage("`bigint`", path)); | ||
throw new Error(errors_.getJSONSchemaMissingAnnotationErrorMessage(path, ast)); | ||
case "SymbolKeyword": | ||
throw new Error(getMissingAnnotationErrorMessage("`symbol`", path)); | ||
throw new Error(errors_.getJSONSchemaMissingAnnotationErrorMessage(path, ast)); | ||
case "TupleType": | ||
{ | ||
const len = ast.elements.length; | ||
const elements = ast.elements.map((e, i) => go(e.type, $defs, true, path.concat(i))); | ||
const rest = ast.rest.map(ast => go(ast, $defs, true, path)); | ||
const elements = ast.elements.map((e, i) => merge(go(e.type, $defs, true, path.concat(i)), getJsonSchemaAnnotations(e))); | ||
const rest = ast.rest.map(annotatedAST => merge(go(annotatedAST.type, $defs, true, path), getJsonSchemaAnnotations(annotatedAST))); | ||
const output = { | ||
@@ -248,2 +231,3 @@ type: "array" | ||
// --------------------------------------------- | ||
const len = ast.elements.length; | ||
if (len > 0) { | ||
@@ -256,8 +240,10 @@ output.minItems = len - ast.elements.filter(element => element.isOptional).length; | ||
// --------------------------------------------- | ||
if (rest.length > 0) { | ||
const restLength = rest.length; | ||
if (restLength > 0) { | ||
const head = rest[0]; | ||
if (len > 0) { | ||
const isHomogeneous = restLength === 1 && ast.elements.every(e => e.type === ast.rest[0].type); | ||
if (isHomogeneous) { | ||
output.items = head; | ||
} else { | ||
output.additionalItems = head; | ||
} else { | ||
output.items = head; | ||
} | ||
@@ -267,4 +253,4 @@ // --------------------------------------------- | ||
// --------------------------------------------- | ||
if (rest.length > 1) { | ||
throw new Error(errors_.getErrorMessageWithPath("Generating a JSON Schema for post-rest elements is not currently supported. You're welcome to contribute by submitting a Pull Request.", path)); | ||
if (restLength > 1) { | ||
throw new Error(errors_.getJSONSchemaUnsupportedPostRestElementsErrorMessage(path)); | ||
} | ||
@@ -278,6 +264,3 @@ } else { | ||
} | ||
return { | ||
...output, | ||
...getJsonSchemaAnnotations(ast) | ||
}; | ||
return merge(output, getJsonSchemaAnnotations(ast)); | ||
} | ||
@@ -287,9 +270,6 @@ case "TypeLiteral": | ||
if (ast.propertySignatures.length === 0 && ast.indexSignatures.length === 0) { | ||
return { | ||
...empty(), | ||
...getJsonSchemaAnnotations(ast) | ||
}; | ||
return merge(empty(), getJsonSchemaAnnotations(ast)); | ||
} | ||
let additionalProperties = undefined; | ||
let patternProperties = undefined; | ||
let propertyNames = undefined; | ||
for (const is of ast.indexSignatures) { | ||
@@ -300,3 +280,3 @@ const parameter = is.parameter; | ||
{ | ||
additionalProperties = go(is.type, $defs, true, path); | ||
patternProperties = go(is.type, $defs, true, path); | ||
break; | ||
@@ -306,4 +286,6 @@ } | ||
{ | ||
patternProperties = { | ||
[AST.getTemplateLiteralRegExp(parameter).source]: go(is.type, $defs, true, path) | ||
patternProperties = go(is.type, $defs, true, path); | ||
propertyNames = { | ||
type: "string", | ||
pattern: AST.getTemplateLiteralRegExp(parameter).source | ||
}; | ||
@@ -314,20 +296,12 @@ break; | ||
{ | ||
const hook = AST.getJSONSchemaAnnotation(parameter); | ||
if (Option.isSome(hook) && "pattern" in hook.value && Predicate.isString(hook.value.pattern)) { | ||
patternProperties = { | ||
[hook.value.pattern]: go(is.type, $defs, true, path) | ||
}; | ||
break; | ||
} | ||
throw new Error(getUnsupportedIndexSignatureParameterErrorMessage(parameter, path)); | ||
patternProperties = go(is.type, $defs, true, path); | ||
propertyNames = go(parameter, $defs, true, path); | ||
break; | ||
} | ||
case "SymbolKeyword": | ||
throw new Error(getUnsupportedIndexSignatureParameterErrorMessage(parameter, path)); | ||
throw new Error(errors_.getJSONSchemaUnsupportedParameterErrorMessage(path, parameter)); | ||
} | ||
} | ||
const propertySignatures = ast.propertySignatures.map(ps => { | ||
return { | ||
...go(pruneUndefinedKeyword(ps), $defs, true, path.concat(ps.name)), | ||
...getJsonSchemaAnnotations(ps) | ||
}; | ||
return merge(go(pruneUndefinedKeyword(ps), $defs, true, path.concat(ps.name)), getJsonSchemaAnnotations(ps)); | ||
}); | ||
@@ -354,3 +328,3 @@ const output = { | ||
} else { | ||
throw new Error(errors_.getErrorMessageWithPath(`cannot encode ${String(name)} key to JSON Schema`, path)); | ||
throw new Error(errors_.getJSONSchemaUnsupportedKeyErrorMessage(name, path)); | ||
} | ||
@@ -361,12 +335,12 @@ } | ||
// --------------------------------------------- | ||
if (additionalProperties !== undefined) { | ||
output.additionalProperties = additionalProperties; | ||
} | ||
if (patternProperties !== undefined) { | ||
output.patternProperties = patternProperties; | ||
delete output.additionalProperties; | ||
output.patternProperties = { | ||
"": patternProperties | ||
}; | ||
} | ||
return { | ||
...output, | ||
...getJsonSchemaAnnotations(ast) | ||
}; | ||
if (propertyNames !== undefined) { | ||
output.propertyNames = propertyNames; | ||
} | ||
return merge(output, getJsonSchemaAnnotations(ast)); | ||
} | ||
@@ -391,11 +365,9 @@ case "Union": | ||
if (enums.length === 1) { | ||
return { | ||
const: enums[0], | ||
...getJsonSchemaAnnotations(ast) | ||
}; | ||
return merge({ | ||
const: enums[0] | ||
}, getJsonSchemaAnnotations(ast)); | ||
} else { | ||
return { | ||
enum: enums, | ||
...getJsonSchemaAnnotations(ast) | ||
}; | ||
return merge({ | ||
enum: enums | ||
}, getJsonSchemaAnnotations(ast)); | ||
} | ||
@@ -412,6 +384,5 @@ } else { | ||
} | ||
return { | ||
anyOf, | ||
...getJsonSchemaAnnotations(ast) | ||
}; | ||
return merge({ | ||
anyOf | ||
}, getJsonSchemaAnnotations(ast)); | ||
} | ||
@@ -421,3 +392,3 @@ } | ||
{ | ||
return { | ||
return merge({ | ||
$comment: "/schemas/enums", | ||
@@ -427,9 +398,8 @@ oneOf: ast.enums.map(e => ({ | ||
const: e[1] | ||
})), | ||
...getJsonSchemaAnnotations(ast) | ||
}; | ||
})) | ||
}, getJsonSchemaAnnotations(ast)); | ||
} | ||
case "Refinement": | ||
{ | ||
throw new Error(errors_.getErrorMessageWithPath("cannot build a JSON Schema for a refinement without a JSON Schema annotation", path)); | ||
throw new Error(errors_.getJSONSchemaMissingAnnotationErrorMessage(path, ast)); | ||
} | ||
@@ -439,8 +409,7 @@ case "TemplateLiteral": | ||
const regex = AST.getTemplateLiteralRegExp(ast); | ||
return { | ||
return merge({ | ||
type: "string", | ||
description: "a template literal", | ||
pattern: regex.source, | ||
...getJsonSchemaAnnotations(ast) | ||
}; | ||
pattern: regex.source | ||
}, getJsonSchemaAnnotations(ast)); | ||
} | ||
@@ -451,3 +420,3 @@ case "Suspend": | ||
if (Option.isNone(identifier)) { | ||
throw new Error(errors_.getErrorMessageWithPath("Generating a JSON Schema for suspended schemas requires an identifier annotation", path)); | ||
throw new Error(errors_.getJSONSchemaMissingIdentifierAnnotationErrorMessage(path, ast)); | ||
} | ||
@@ -457,5 +426,12 @@ return go(ast.f(), $defs, true, path); | ||
case "Transformation": | ||
return go(ast.from, $defs, true, path); | ||
{ | ||
// Properly handle S.parseJson transformations by focusing on | ||
// the 'to' side of the AST. This approach prevents the generation of useless schemas | ||
// derived from the 'from' side (type: string), ensuring the output matches the intended | ||
// complex schema type. | ||
const next = isParseJsonTransformation(ast.from) ? ast.to : ast.from; | ||
return go(next, $defs, true, path); | ||
} | ||
} | ||
}; | ||
//# sourceMappingURL=JSONSchema.js.map |
@@ -6,4 +6,4 @@ "use strict"; | ||
}); | ||
exports.validateSync = exports.validatePromise = exports.validateOption = exports.validateEither = exports.validate = exports.try = exports.succeed = exports.parseError = exports.orElse = exports.missing = exports.mergeParseOptions = exports.mapError = exports.mapBoth = exports.map = exports.is = exports.getSearchTree = exports.getLiterals = exports.getFinalTransformation = exports.fromOption = exports.flatMap = exports.fail = exports.encodeUnknownSync = exports.encodeUnknownPromise = exports.encodeUnknownOption = exports.encodeUnknownEither = exports.encodeUnknown = exports.encodeSync = exports.encodePromise = exports.encodeOption = exports.encodeEither = exports.encode = exports.eitherOrUndefined = exports.decodeUnknownSync = exports.decodeUnknownPromise = exports.decodeUnknownOption = exports.decodeUnknownEither = exports.decodeUnknown = exports.decodeSync = exports.decodePromise = exports.decodeOption = exports.decodeEither = exports.decode = exports.asserts = exports.Union = exports.Unexpected = exports.TypeLiteral = exports.Type = exports.TupleType = exports.Transformation = exports.Refinement = exports.ParseError = exports.Missing = exports.Member = exports.Key = exports.Index = exports.Forbidden = exports.Declaration = void 0; | ||
var Arr = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("effect/Array")); | ||
exports.validateSync = exports.validatePromise = exports.validateOption = exports.validateEither = exports.validate = exports.try = exports.succeed = exports.parseError = exports.orElse = exports.mergeInternalOptions = exports.mapError = exports.mapBoth = exports.map = exports.isParseError = exports.isComposite = exports.is = exports.getSearchTree = exports.getLiterals = exports.getFinalTransformation = exports.fromOption = exports.flatMap = exports.fail = exports.encodeUnknownSync = exports.encodeUnknownPromise = exports.encodeUnknownOption = exports.encodeUnknownEither = exports.encodeUnknown = exports.encodeSync = exports.encodePromise = exports.encodeOption = exports.encodeEither = exports.encode = exports.eitherOrUndefined = exports.decodeUnknownSync = exports.decodeUnknownPromise = exports.decodeUnknownOption = exports.decodeUnknownEither = exports.decodeUnknown = exports.decodeSync = exports.decodePromise = exports.decodeOption = exports.decodeEither = exports.decode = exports.asserts = exports.Unexpected = exports.Type = exports.Transformation = exports.Refinement = exports.Pointer = exports.ParseErrorTypeId = exports.ParseError = exports.Missing = exports.Forbidden = exports.Composite = void 0; | ||
var array_ = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("effect/Array")); | ||
var _Data = /*#__PURE__*/require("effect/Data"); | ||
@@ -50,23 +50,21 @@ var Effect = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("effect/Effect")); | ||
/** | ||
* Error that occurs when a declaration has an error. | ||
* | ||
* @category model | ||
* @since 0.67.0 | ||
* @since 0.68.0 | ||
*/ | ||
class Declaration { | ||
ast; | ||
class Pointer { | ||
path; | ||
actual; | ||
error; | ||
issue; | ||
/** | ||
* @since 0.67.0 | ||
* @since 0.68.0 | ||
*/ | ||
_tag = "Declaration"; | ||
constructor(ast, actual, error) { | ||
this.ast = ast; | ||
_tag = "Pointer"; | ||
constructor(path, actual, issue) { | ||
this.path = path; | ||
this.actual = actual; | ||
this.error = error; | ||
this.issue = issue; | ||
} | ||
} | ||
/** | ||
* Error that occurs when a refinement has an error. | ||
* Error that occurs when an unexpected key or index is present. | ||
* | ||
@@ -76,21 +74,21 @@ * @category model | ||
*/ | ||
exports.Declaration = Declaration; | ||
class Refinement { | ||
ast; | ||
exports.Pointer = Pointer; | ||
class Unexpected { | ||
actual; | ||
kind; | ||
error; | ||
message; | ||
/** | ||
* @since 0.67.0 | ||
*/ | ||
_tag = "Refinement"; | ||
constructor(ast, actual, kind, error) { | ||
this.ast = ast; | ||
_tag = "Unexpected"; | ||
constructor(actual, | ||
/** | ||
* @since 0.68.0 | ||
*/ | ||
message) { | ||
this.actual = actual; | ||
this.kind = kind; | ||
this.error = error; | ||
this.message = message; | ||
} | ||
} | ||
/** | ||
* Error that occurs when an array or tuple has an error. | ||
* Error that occurs when a required key or index is missing. | ||
* | ||
@@ -100,58 +98,47 @@ * @category model | ||
*/ | ||
exports.Refinement = Refinement; | ||
class TupleType { | ||
exports.Unexpected = Unexpected; | ||
class Missing { | ||
ast; | ||
actual; | ||
errors; | ||
output; | ||
message; | ||
/** | ||
* @since 0.67.0 | ||
*/ | ||
_tag = "TupleType"; | ||
constructor(ast, actual, errors, output = []) { | ||
this.ast = ast; | ||
this.actual = actual; | ||
this.errors = errors; | ||
this.output = output; | ||
} | ||
} | ||
/** | ||
* The `Index` error indicates that there was an error at a specific index in an array or tuple. | ||
* | ||
* @category model | ||
* @since 0.67.0 | ||
*/ | ||
exports.TupleType = TupleType; | ||
class Index { | ||
index; | ||
error; | ||
_tag = "Missing"; | ||
/** | ||
* @since 0.67.0 | ||
* @since 0.68.0 | ||
*/ | ||
_tag = "Index"; | ||
constructor(index, error) { | ||
this.index = index; | ||
this.error = error; | ||
actual = undefined; | ||
constructor( | ||
/** | ||
* @since 0.68.0 | ||
*/ | ||
ast, | ||
/** | ||
* @since 0.68.0 | ||
*/ | ||
message) { | ||
this.ast = ast; | ||
this.message = message; | ||
} | ||
} | ||
/** | ||
* Error that occurs when a type literal or record has an error. | ||
* Error that contains multiple issues. | ||
* | ||
* @category model | ||
* @since 0.67.0 | ||
* @since 0.68.0 | ||
*/ | ||
exports.Index = Index; | ||
class TypeLiteral { | ||
exports.Missing = Missing; | ||
class Composite { | ||
ast; | ||
actual; | ||
errors; | ||
issues; | ||
output; | ||
/** | ||
* @since 0.67.0 | ||
* @since 0.68.0 | ||
*/ | ||
_tag = "TypeLiteral"; | ||
constructor(ast, actual, errors, output = {}) { | ||
_tag = "Composite"; | ||
constructor(ast, actual, issues, output) { | ||
this.ast = ast; | ||
this.actual = actual; | ||
this.errors = errors; | ||
this.issues = issues; | ||
this.output = output; | ||
@@ -161,22 +148,11 @@ } | ||
/** | ||
* The `Key` variant of the `ParseIssue` type represents an error that occurs when a key in a type literal or record is invalid. | ||
* Returns `true` if the value is a `Composite`. | ||
* | ||
* @category model | ||
* @since 0.67.0 | ||
* @category guards | ||
* @since 0.68.0 | ||
*/ | ||
exports.TypeLiteral = TypeLiteral; | ||
class Key { | ||
key; | ||
error; | ||
/** | ||
* @since 0.67.0 | ||
*/ | ||
_tag = "Key"; | ||
constructor(key, error) { | ||
this.key = key; | ||
this.error = error; | ||
} | ||
} | ||
exports.Composite = Composite; | ||
const isComposite = u => Predicate.hasProperty(u, "_tag"); | ||
/** | ||
* Error that occurs when an unexpected key or index is present. | ||
* Error that occurs when a refinement has an error. | ||
* | ||
@@ -186,11 +162,17 @@ * @category model | ||
*/ | ||
exports.Key = Key; | ||
class Unexpected { | ||
exports.isComposite = isComposite; | ||
class Refinement { | ||
ast; | ||
actual; | ||
kind; | ||
issue; | ||
/** | ||
* @since 0.67.0 | ||
*/ | ||
_tag = "Unexpected"; | ||
constructor(ast) { | ||
_tag = "Refinement"; | ||
constructor(ast, actual, kind, issue) { | ||
this.ast = ast; | ||
this.actual = actual; | ||
this.kind = kind; | ||
this.issue = issue; | ||
} | ||
@@ -204,3 +186,3 @@ } | ||
*/ | ||
exports.Unexpected = Unexpected; | ||
exports.Refinement = Refinement; | ||
class Transformation { | ||
@@ -210,3 +192,3 @@ ast; | ||
kind; | ||
error; | ||
issue; | ||
/** | ||
@@ -216,7 +198,7 @@ * @since 0.67.0 | ||
_tag = "Transformation"; | ||
constructor(ast, actual, kind, error) { | ||
constructor(ast, actual, kind, issue) { | ||
this.ast = ast; | ||
this.actual = actual; | ||
this.kind = kind; | ||
this.error = error; | ||
this.issue = issue; | ||
} | ||
@@ -235,2 +217,3 @@ } | ||
actual; | ||
message; | ||
/** | ||
@@ -240,10 +223,6 @@ * @since 0.67.0 | ||
_tag = "Type"; | ||
/** | ||
* @since 0.67.0 | ||
*/ | ||
message; | ||
constructor(ast, actual, message) { | ||
this.ast = ast; | ||
this.actual = actual; | ||
this.message = Option.fromNullable(message); | ||
this.message = message; | ||
} | ||
@@ -261,2 +240,3 @@ } | ||
actual; | ||
message; | ||
/** | ||
@@ -266,75 +246,27 @@ * @since 0.67.0 | ||
_tag = "Forbidden"; | ||
/** | ||
* @since 0.67.0 | ||
*/ | ||
message; | ||
constructor(ast, actual, message) { | ||
this.ast = ast; | ||
this.actual = actual; | ||
this.message = Option.fromNullable(message); | ||
this.message = message; | ||
} | ||
} | ||
/** | ||
* Error that occurs when a required key or index is missing. | ||
* | ||
* @category model | ||
* @since 0.67.0 | ||
* @category type id | ||
* @since 0.68.0 | ||
*/ | ||
exports.Forbidden = Forbidden; | ||
class Missing { | ||
/** | ||
* @since 0.67.0 | ||
*/ | ||
_tag = "Missing"; | ||
} | ||
const ParseErrorTypeId = exports.ParseErrorTypeId = /*#__PURE__*/Symbol.for("@effect/schema/ParseErrorTypeId"); | ||
/** | ||
* @category constructors | ||
* @since 0.67.0 | ||
* @since 0.68.0 | ||
*/ | ||
exports.Missing = Missing; | ||
const missing = exports.missing = /*#__PURE__*/new Missing(); | ||
const isParseError = u => Predicate.hasProperty(u, ParseErrorTypeId); | ||
/** | ||
* Error that occurs when a member in a union has an error. | ||
* | ||
* @category model | ||
* @since 0.67.0 | ||
*/ | ||
class Member { | ||
ast; | ||
error; | ||
exports.isParseError = isParseError; | ||
class ParseError extends (0, _Data.TaggedError)("ParseError") { | ||
/** | ||
* @since 0.67.0 | ||
* @since 0.68.0 | ||
*/ | ||
_tag = "Member"; | ||
constructor(ast, error) { | ||
this.ast = ast; | ||
this.error = error; | ||
} | ||
} | ||
/** | ||
* Error that occurs when a union has an error. | ||
* | ||
* @category model | ||
* @since 0.67.0 | ||
*/ | ||
exports.Member = Member; | ||
class Union { | ||
ast; | ||
actual; | ||
errors; | ||
/** | ||
* @since 0.67.0 | ||
*/ | ||
_tag = "Union"; | ||
constructor(ast, actual, errors) { | ||
this.ast = ast; | ||
this.actual = actual; | ||
this.errors = errors; | ||
} | ||
} | ||
/** | ||
* @since 0.67.0 | ||
*/ | ||
exports.Union = Union; | ||
class ParseError extends (0, _Data.TaggedError)("ParseError") { | ||
[ParseErrorTypeId] = ParseErrorTypeId; | ||
get message() { | ||
@@ -347,3 +279,3 @@ return this.toString(); | ||
toString() { | ||
return TreeFormatter.formatIssueSync(this.error); | ||
return TreeFormatter.formatIssueSync(this.issue); | ||
} | ||
@@ -372,3 +304,3 @@ /** | ||
const parseError = issue => new ParseError({ | ||
error: issue | ||
issue | ||
}); | ||
@@ -474,3 +406,3 @@ /** | ||
/** @internal */ | ||
const mergeParseOptions = (options, overrideOptions) => { | ||
const mergeInternalOptions = (options, overrideOptions) => { | ||
if (overrideOptions === undefined || Predicate.isNumber(overrideOptions)) { | ||
@@ -482,17 +414,15 @@ return options; | ||
} | ||
const out = {}; | ||
out.errors = overrideOptions.errors ?? options.errors; | ||
out.onExcessProperty = overrideOptions.onExcessProperty ?? options.onExcessProperty; | ||
return out; | ||
return { | ||
...options, | ||
...overrideOptions | ||
}; | ||
}; | ||
exports.mergeParseOptions = mergeParseOptions; | ||
exports.mergeInternalOptions = mergeInternalOptions; | ||
const getEither = (ast, isDecoding, options) => { | ||
const parser = goMemo(ast, isDecoding); | ||
return (u, overrideOptions) => parser(u, mergeParseOptions(options, overrideOptions)); | ||
return (u, overrideOptions) => parser(u, mergeInternalOptions(options, overrideOptions)); | ||
}; | ||
const getSync = (ast, isDecoding, options) => { | ||
const parser = getEither(ast, isDecoding, options); | ||
return (input, overrideOptions) => Either.getOrThrowWith(parser(input, overrideOptions), issue => new Error(TreeFormatter.formatIssueSync(issue), { | ||
cause: issue | ||
})); | ||
return (input, overrideOptions) => Either.getOrThrowWith(parser(input, overrideOptions), parseError); | ||
}; | ||
@@ -506,3 +436,3 @@ const getOption = (ast, isDecoding, options) => { | ||
return (input, overrideOptions) => parser(input, { | ||
...mergeParseOptions(options, overrideOptions), | ||
...mergeInternalOptions(options, overrideOptions), | ||
isEffectAllowed: true | ||
@@ -512,2 +442,3 @@ }); | ||
/** | ||
* @throws `ParseError` | ||
* @category decoding | ||
@@ -545,2 +476,3 @@ * @since 0.67.0 | ||
/** | ||
* @throws `ParseError` | ||
* @category encoding | ||
@@ -605,2 +537,3 @@ * @since 0.67.0 | ||
/** | ||
* @throws `ParseError` | ||
* @category validation | ||
@@ -648,3 +581,3 @@ * @since 0.67.0 | ||
exact: true, | ||
...mergeParseOptions(options, overrideOptions) | ||
...mergeInternalOptions(options, overrideOptions) | ||
})); | ||
@@ -655,2 +588,3 @@ }; | ||
* | ||
* @throws `ParseError` | ||
* @category validation | ||
@@ -665,8 +599,6 @@ * @since 0.67.0 | ||
exact: true, | ||
...mergeParseOptions(options, overrideOptions) | ||
...mergeInternalOptions(options, overrideOptions) | ||
}); | ||
if (Either.isLeft(result)) { | ||
throw new Error(TreeFormatter.formatIssueSync(result.left), { | ||
cause: result.left | ||
}); | ||
throw parseError(result.left); | ||
} | ||
@@ -709,3 +641,5 @@ }; | ||
} | ||
const parser = go(ast, isDecoding); | ||
const raw = go(ast, isDecoding); | ||
const parseOptionsAnnotation = AST.getParseOptionsAnnotation(ast); | ||
const parser = Option.isSome(parseOptionsAnnotation) ? (i, options) => raw(i, mergeInternalOptions(options, parseOptionsAnnotation.value)) : raw; | ||
memoMap.set(ast, parser); | ||
@@ -742,3 +676,3 @@ return parser; | ||
const parse = isDecoding ? ast.decodeUnknown(...ast.typeParameters) : ast.encodeUnknown(...ast.typeParameters); | ||
return (i, options) => handleForbidden(mapError(parse(i, options ?? AST.defaultParseOption, ast), e => new Declaration(ast, i, e)), ast, i, options); | ||
return (i, options) => handleForbidden(parse(i, options ?? AST.defaultParseOption, ast), ast, i, options); | ||
} | ||
@@ -780,12 +714,13 @@ case "Literal": | ||
const elements = ast.elements.map(e => goMemo(e.type, isDecoding)); | ||
const rest = ast.rest.map(ast => goMemo(ast, isDecoding)); | ||
let requiredLen = ast.elements.filter(e => !e.isOptional).length; | ||
const rest = ast.rest.map(annotatedAST => goMemo(annotatedAST.type, isDecoding)); | ||
let requiredTypes = ast.elements.filter(e => !e.isOptional); | ||
if (ast.rest.length > 0) { | ||
requiredLen += ast.rest.length - 1; | ||
requiredTypes = requiredTypes.concat(ast.rest.slice(1)); | ||
} | ||
const expectedAST = AST.Union.make(ast.elements.map((_, i) => new AST.Literal(i))); | ||
const requiredLen = requiredTypes.length; | ||
const expectedIndexes = ast.elements.length > 0 ? ast.elements.map((_, i) => i).join(" | ") : "never"; | ||
const concurrency = getConcurrency(ast); | ||
const batching = getBatching(ast); | ||
return (input, options) => { | ||
if (!Arr.isArray(input)) { | ||
if (!array_.isArray(input)) { | ||
return Either.left(new Type(ast, input)); | ||
@@ -796,2 +731,3 @@ } | ||
let stepKey = 0; | ||
const output = []; | ||
// --------------------------------------------- | ||
@@ -802,3 +738,3 @@ // handle missing indexes | ||
for (let i = len; i <= requiredLen - 1; i++) { | ||
const e = new Index(i, missing); | ||
const e = new Pointer(i, input, new Missing(requiredTypes[i - len])); | ||
if (allErrors) { | ||
@@ -808,3 +744,3 @@ es.push([stepKey++, e]); | ||
} else { | ||
return Either.left(new TupleType(ast, input, [e])); | ||
return Either.left(new Composite(ast, input, e, output)); | ||
} | ||
@@ -817,3 +753,3 @@ } | ||
for (let i = ast.elements.length; i <= len - 1; i++) { | ||
const e = new Index(i, new Unexpected(expectedAST)); | ||
const e = new Pointer(i, input, new Unexpected(input[i], `is unexpected, expected: ${expectedIndexes}`)); | ||
if (allErrors) { | ||
@@ -823,7 +759,6 @@ es.push([stepKey++, e]); | ||
} else { | ||
return Either.left(new TupleType(ast, input, [e])); | ||
return Either.left(new Composite(ast, input, e, output)); | ||
} | ||
} | ||
} | ||
const output = []; | ||
let i = 0; | ||
@@ -847,3 +782,3 @@ let queue = undefined; | ||
// the input element is present but is not valid | ||
const e = new Index(i, eu.left); | ||
const e = new Pointer(i, input, eu.left); | ||
if (allErrors) { | ||
@@ -853,3 +788,3 @@ es.push([stepKey++, e]); | ||
} else { | ||
return Either.left(new TupleType(ast, input, [e], sortByIndex(output))); | ||
return Either.left(new Composite(ast, input, e, sortByIndex(output))); | ||
} | ||
@@ -870,3 +805,3 @@ } | ||
// the input element is present but is not valid | ||
const e = new Index(index, t.left); | ||
const e = new Pointer(index, input, t.left); | ||
if (allErrors) { | ||
@@ -876,3 +811,3 @@ es.push([nk, e]); | ||
} else { | ||
return Either.left(new TupleType(ast, input, [e], sortByIndex(output))); | ||
return Either.left(new Composite(ast, input, e, sortByIndex(output))); | ||
} | ||
@@ -889,3 +824,3 @@ } | ||
// --------------------------------------------- | ||
if (Arr.isNonEmptyReadonlyArray(rest)) { | ||
if (array_.isNonEmptyReadonlyArray(rest)) { | ||
const [head, ...tail] = rest; | ||
@@ -897,3 +832,3 @@ for (; i < len - tail.length; i++) { | ||
if (Either.isLeft(eu)) { | ||
const e = new Index(i, eu.left); | ||
const e = new Pointer(i, input, eu.left); | ||
if (allErrors) { | ||
@@ -903,3 +838,3 @@ es.push([stepKey++, e]); | ||
} else { | ||
return Either.left(new TupleType(ast, input, [e], sortByIndex(output))); | ||
return Either.left(new Composite(ast, input, e, sortByIndex(output))); | ||
} | ||
@@ -920,3 +855,3 @@ } else { | ||
if (Either.isLeft(t)) { | ||
const e = new Index(index, t.left); | ||
const e = new Pointer(index, input, t.left); | ||
if (allErrors) { | ||
@@ -926,3 +861,3 @@ es.push([nk, e]); | ||
} else { | ||
return Either.left(new TupleType(ast, input, [e], sortByIndex(output))); | ||
return Either.left(new Composite(ast, input, e, sortByIndex(output))); | ||
} | ||
@@ -949,3 +884,3 @@ } else { | ||
// the input element is present but is not valid | ||
const e = new Index(i, eu.left); | ||
const e = new Pointer(i, input, eu.left); | ||
if (allErrors) { | ||
@@ -955,3 +890,3 @@ es.push([stepKey++, e]); | ||
} else { | ||
return Either.left(new TupleType(ast, input, [e], sortByIndex(output))); | ||
return Either.left(new Composite(ast, input, e, sortByIndex(output))); | ||
} | ||
@@ -972,3 +907,3 @@ } | ||
// the input element is present but is not valid | ||
const e = new Index(index, t.left); | ||
const e = new Pointer(index, input, t.left); | ||
if (allErrors) { | ||
@@ -978,3 +913,3 @@ es.push([nk, e]); | ||
} else { | ||
return Either.left(new TupleType(ast, input, [e], sortByIndex(output))); | ||
return Either.left(new Composite(ast, input, e, sortByIndex(output))); | ||
} | ||
@@ -995,3 +930,3 @@ } | ||
output | ||
}) => Arr.isNonEmptyArray(es) ? Either.left(new TupleType(ast, input, sortByIndex(es), sortByIndex(output))) : Either.right(sortByIndex(output)); | ||
}) => array_.isNonEmptyArray(es) ? Either.left(new Composite(ast, input, sortByIndex(es), sortByIndex(output))) : Either.right(sortByIndex(output)); | ||
if (queue && queue.length > 0) { | ||
@@ -1001,4 +936,4 @@ const cqueue = queue; | ||
const state = { | ||
es: Arr.copy(es), | ||
output: Arr.copy(output) | ||
es: array_.copy(es), | ||
output: array_.copy(output) | ||
}; | ||
@@ -1057,3 +992,3 @@ return Effect.flatMap(Effect.forEach(cqueue, f => f(state), { | ||
if (onExcessPropertyError) { | ||
const e = new Key(key, new Unexpected(expectedAST)); | ||
const e = new Pointer(key, input, new Unexpected(input[key], `is unexpected, expected: ${String(expectedAST)}`)); | ||
if (allErrors) { | ||
@@ -1063,3 +998,3 @@ es.push([stepKey++, e]); | ||
} else { | ||
return Either.left(new TypeLiteral(ast, input, [e], output)); | ||
return Either.left(new Composite(ast, input, e, output)); | ||
} | ||
@@ -1083,3 +1018,3 @@ } else { | ||
} else if (isExact) { | ||
const e = new Key(name, missing); | ||
const e = new Pointer(name, input, new Missing(ps)); | ||
if (allErrors) { | ||
@@ -1089,3 +1024,3 @@ es.push([stepKey++, e]); | ||
} else { | ||
return Either.left(new TypeLiteral(ast, input, [e], output)); | ||
return Either.left(new Composite(ast, input, e, output)); | ||
} | ||
@@ -1099,3 +1034,3 @@ } | ||
if (Either.isLeft(eu)) { | ||
const e = new Key(name, hasKey ? eu.left : missing); | ||
const e = new Pointer(name, input, hasKey ? eu.left : new Missing(ps)); | ||
if (allErrors) { | ||
@@ -1105,3 +1040,3 @@ es.push([stepKey++, e]); | ||
} else { | ||
return Either.left(new TypeLiteral(ast, input, [e], output)); | ||
return Either.left(new Composite(ast, input, e, output)); | ||
} | ||
@@ -1121,3 +1056,3 @@ } | ||
if (Either.isLeft(t)) { | ||
const e = new Key(index, hasKey ? t.left : missing); | ||
const e = new Pointer(index, input, hasKey ? t.left : new Missing(ps)); | ||
if (allErrors) { | ||
@@ -1127,3 +1062,3 @@ es.push([nk, e]); | ||
} else { | ||
return Either.left(new TypeLiteral(ast, input, [e], output)); | ||
return Either.left(new Composite(ast, input, e, output)); | ||
} | ||
@@ -1157,3 +1092,3 @@ } | ||
if (Either.isLeft(veu)) { | ||
const e = new Key(key, veu.left); | ||
const e = new Pointer(key, input, veu.left); | ||
if (allErrors) { | ||
@@ -1163,3 +1098,3 @@ es.push([stepKey++, e]); | ||
} else { | ||
return Either.left(new TypeLiteral(ast, input, [e], output)); | ||
return Either.left(new Composite(ast, input, e, output)); | ||
} | ||
@@ -1182,3 +1117,3 @@ } else { | ||
if (Either.isLeft(tv)) { | ||
const e = new Key(index, tv.left); | ||
const e = new Pointer(index, input, tv.left); | ||
if (allErrors) { | ||
@@ -1188,3 +1123,3 @@ es.push([nk, e]); | ||
} else { | ||
return Either.left(new TypeLiteral(ast, input, [e], output)); | ||
return Either.left(new Composite(ast, input, e, output)); | ||
} | ||
@@ -1209,4 +1144,4 @@ } else { | ||
}) => { | ||
if (Arr.isNonEmptyArray(es)) { | ||
return Either.left(new TypeLiteral(ast, input, sortByIndex(es), output)); | ||
if (array_.isNonEmptyArray(es)) { | ||
return Either.left(new Composite(ast, input, sortByIndex(es), output)); | ||
} | ||
@@ -1235,3 +1170,3 @@ if (options?.propertyOrder === "original") { | ||
const state = { | ||
es: Arr.copy(es), | ||
es: array_.copy(es), | ||
output: Object.assign({}, output) | ||
@@ -1282,7 +1217,8 @@ }; | ||
const literals = AST.Union.make(searchTree.keys[name].literals); | ||
es.push([stepKey++, new TypeLiteral(new AST.TypeLiteral([new AST.PropertySignature(name, literals, false, true)], []), input, [new Key(name, new Type(literals, input[name]))])]); | ||
es.push([stepKey++, new Composite(new AST.TypeLiteral([new AST.PropertySignature(name, literals, false, true)], []), input, new Pointer(name, input, new Type(literals, input[name])))]); | ||
} | ||
} else { | ||
const literals = AST.Union.make(searchTree.keys[name].literals); | ||
es.push([stepKey++, new TypeLiteral(new AST.TypeLiteral([new AST.PropertySignature(name, literals, false, true)], []), input, [new Key(name, missing)])]); | ||
const fakeps = new AST.PropertySignature(name, literals, false, true); // TODO: inherit message annotation from the union? | ||
es.push([stepKey++, new Composite(new AST.TypeLiteral([fakeps], []), input, new Pointer(name, input, new Missing(fakeps)))]); | ||
} | ||
@@ -1309,3 +1245,3 @@ } | ||
} else { | ||
es.push([stepKey++, new Member(candidate, eu.left)]); | ||
es.push([stepKey++, eu.left]); | ||
} | ||
@@ -1325,3 +1261,3 @@ } else { | ||
} else { | ||
state.es.push([nk, new Member(candidate, t.left)]); | ||
state.es.push([nk, t.left]); | ||
} | ||
@@ -1337,5 +1273,5 @@ return Effect.void; | ||
// --------------------------------------------- | ||
const computeResult = es => Arr.isNonEmptyArray(es) ? es.length === 1 && es[0][1]._tag === "Type" ? Either.left(es[0][1]) : Either.left(new Union(ast, input, sortByIndex(es))) : | ||
const computeResult = es => array_.isNonEmptyArray(es) ? es.length === 1 && es[0][1]._tag === "Type" ? Either.left(es[0][1]) : Either.left(new Composite(ast, input, sortByIndex(es))) : | ||
// this should never happen | ||
Either.left(new Type(AST.neverKeyword, input)); | ||
Either.left(new Type(ast, input)); | ||
if (queue && queue.length > 0) { | ||
@@ -1345,3 +1281,3 @@ const cqueue = queue; | ||
const state = { | ||
es: Arr.copy(es) | ||
es: array_.copy(es) | ||
}; | ||
@@ -1470,4 +1406,5 @@ return Effect.flatMap(Effect.forEach(cqueue, f => f(state), { | ||
}; | ||
const compare = ([a], [b]) => a > b ? 1 : a < b ? -1 : 0; | ||
function sortByIndex(es) { | ||
return es.sort(([a], [b]) => a > b ? 1 : a < b ? -1 : 0).map(([_, a]) => a); | ||
return es.sort(compare).map(t => t[1]); | ||
} | ||
@@ -1474,0 +1411,0 @@ // ------------------------------------------------------------------------------------- |
@@ -69,3 +69,2 @@ "use strict"; | ||
const formatUnknown = /*#__PURE__*/getMatcher(util_.formatUnknown); | ||
const getPrettyErrorMessage = (message, path) => errors_.getErrorMessageWithPath(`cannot build a Pretty for ${message}`, path); | ||
/** | ||
@@ -80,7 +79,7 @@ * @since 0.67.0 | ||
} | ||
throw new Error(getPrettyErrorMessage(`a declaration without annotations (${ast})`, path)); | ||
throw new Error(errors_.getPrettyMissingAnnotationErrorMessage(path, ast)); | ||
}, | ||
"VoidKeyword": /*#__PURE__*/getMatcher(() => "void(0)"), | ||
"NeverKeyword": /*#__PURE__*/getMatcher(() => { | ||
throw new Error("cannot pretty print a `never` value"); | ||
throw new Error(errors_.getPrettyNeverErrorMessage); | ||
}), | ||
@@ -106,3 +105,3 @@ "Literal": /*#__PURE__*/getMatcher(literal => typeof literal === "bigint" ? `${String(literal)}n` : JSON.stringify(literal)), | ||
const elements = ast.elements.map((e, i) => go(e.type, path.concat(i))); | ||
const rest = ast.rest.map(ast => go(ast, path)); | ||
const rest = ast.rest.map(annotatedAST => go(annotatedAST.type, path)); | ||
return input => { | ||
@@ -194,2 +193,5 @@ const output = []; | ||
const index = types.findIndex(([is]) => is(a)); | ||
if (index === -1) { | ||
throw new Error(errors_.getPrettyNoMatchingSchemaErrorMessage(a, path, ast)); | ||
} | ||
return types[index][1](a); | ||
@@ -196,0 +198,0 @@ }; |
@@ -92,3 +92,3 @@ "use strict"; | ||
exports.exitSchema = exitSchema; | ||
const serialize = self => Schema.encode(self[symbol])(self); | ||
const serialize = self => Schema.encodeUnknown(self[symbol])(self); | ||
/** | ||
@@ -95,0 +95,0 @@ * @since 0.67.0 |
@@ -6,3 +6,3 @@ "use strict"; | ||
}); | ||
exports.getMessage = exports.formatTypeMessage = exports.formatIssueSync = exports.formatIssue = exports.formatForbiddenMessage = exports.formatErrorSync = exports.formatError = void 0; | ||
exports.getMessage = exports.formatUnexpectedMessage = exports.formatTypeMessage = exports.formatMissingMessage = exports.formatIssueSync = exports.formatIssue = exports.formatForbiddenMessage = exports.formatErrorSync = exports.formatError = void 0; | ||
var Effect = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("effect/Effect")); | ||
@@ -62,3 +62,3 @@ var Option = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("effect/Option")); | ||
exports.formatIssueSync = formatIssueSync; | ||
const formatError = error => formatIssue(error.error); | ||
const formatError = error => formatIssue(error.issue); | ||
/** | ||
@@ -69,3 +69,3 @@ * @category formatting | ||
exports.formatError = formatError; | ||
const formatErrorSync = error => formatIssueSync(error.error); | ||
const formatErrorSync = error => formatIssueSync(error.issue); | ||
exports.formatErrorSync = formatErrorSync; | ||
@@ -103,19 +103,4 @@ const drawTree = tree => tree.value + draw("\n", tree.forest); | ||
}; | ||
const getInnerMessage = issue => { | ||
switch (issue._tag) { | ||
case "Refinement": | ||
{ | ||
if (issue.kind === "From") { | ||
return getMessage(issue.error); | ||
} | ||
break; | ||
} | ||
case "Transformation": | ||
{ | ||
return getMessage(issue.error); | ||
} | ||
} | ||
return Option.none(); | ||
}; | ||
const getCurrentMessage = issue => AST.getMessageAnnotation(issue.ast).pipe(Effect.flatMap(annotation => { | ||
const getAnnotated = issue => "ast" in issue ? Option.some(issue.ast) : Option.none(); | ||
const getCurrentMessage = issue => getAnnotated(issue).pipe(Option.flatMap(AST.getMessageAnnotation), Effect.flatMap(annotation => { | ||
const out = annotation(issue); | ||
@@ -136,21 +121,29 @@ return Predicate.isString(out) ? Effect.succeed({ | ||
})); | ||
const createParseIssueGuard = tag => issue => issue._tag === tag; | ||
const isComposite = /*#__PURE__*/createParseIssueGuard("Composite"); | ||
const isRefinement = /*#__PURE__*/createParseIssueGuard("Refinement"); | ||
const isTransformation = /*#__PURE__*/createParseIssueGuard("Transformation"); | ||
/** @internal */ | ||
const getMessage = issue => { | ||
const current = getCurrentMessage(issue); | ||
return getInnerMessage(issue).pipe(Effect.flatMap(inner => Effect.map(current, current => current.override ? current.message : inner)), Effect.catchAll(() => Effect.flatMap(current, current => { | ||
if (!current.override && (issue._tag === "Refinement" && issue.kind !== "Predicate" || issue._tag === "Transformation" && issue.kind !== "Transformation")) { | ||
return Option.none(); | ||
} | ||
return Effect.succeed(current.message); | ||
}))); | ||
}; | ||
const getMessage = issue => getCurrentMessage(issue).pipe(Effect.flatMap(currentMessage => { | ||
const useInnerMessage = !currentMessage.override && (isComposite(issue) || isRefinement(issue) && issue.kind === "From" || isTransformation(issue) && issue.kind !== "Transformation"); | ||
return useInnerMessage ? isTransformation(issue) || isRefinement(issue) ? getMessage(issue.issue) : Option.none() : Effect.succeed(currentMessage.message); | ||
})); | ||
exports.getMessage = getMessage; | ||
const getParseIssueTitleAnnotation = issue => Option.filterMap(AST.getParseIssueTitleAnnotation(issue.ast), annotation => Option.fromNullable(annotation(issue))); | ||
const getParseIssueTitleAnnotation = issue => getAnnotated(issue).pipe(Option.flatMap(AST.getParseIssueTitleAnnotation), Option.filterMap(annotation => Option.fromNullable(annotation(issue)))); | ||
/** @internal */ | ||
const formatTypeMessage = e => getMessage(e).pipe(Effect.orElse(() => getParseIssueTitleAnnotation(e)), Effect.orElse(() => e.message), Effect.catchAll(() => Effect.succeed(`Expected ${e.ast.toString(true)}, actual ${util_.formatUnknown(e.actual)}`))); | ||
const formatTypeMessage = e => getMessage(e).pipe(Effect.orElse(() => getParseIssueTitleAnnotation(e)), Effect.catchAll(() => Effect.succeed(e.message ?? `Expected ${String(e.ast)}, actual ${util_.formatUnknown(e.actual)}`))); | ||
exports.formatTypeMessage = formatTypeMessage; | ||
const getParseIssueTitle = issue => Option.getOrElse(getParseIssueTitleAnnotation(issue), () => String(issue.ast)); | ||
/** @internal */ | ||
const formatForbiddenMessage = e => Option.getOrElse(e.message, () => "is forbidden"); | ||
const formatForbiddenMessage = e => e.message ?? "is forbidden"; | ||
/** @internal */ | ||
exports.formatForbiddenMessage = formatForbiddenMessage; | ||
const formatUnexpectedMessage = e => e.message ?? "is unexpected"; | ||
/** @internal */ | ||
exports.formatUnexpectedMessage = formatUnexpectedMessage; | ||
const formatMissingMessage = e => AST.getMissingMessageAnnotation(e.ast).pipe(Effect.flatMap(annotation => { | ||
const out = annotation(); | ||
return Predicate.isString(out) ? Effect.succeed(out) : out; | ||
}), Effect.catchAll(() => Effect.succeed(e.message ?? "is missing"))); | ||
exports.formatMissingMessage = formatMissingMessage; | ||
const getTree = (issue, onFailure) => Effect.matchEffect(getMessage(issue), { | ||
@@ -167,30 +160,18 @@ onFailure, | ||
case "Unexpected": | ||
return Effect.succeed(make(`is unexpected, expected ${e.ast.toString(true)}`)); | ||
return Effect.succeed(make(formatUnexpectedMessage(e))); | ||
case "Missing": | ||
return Effect.succeed(make("is missing")); | ||
case "Union": | ||
return getTree(e, () => Effect.map(Effect.forEach(e.errors, e => { | ||
switch (e._tag) { | ||
case "Member": | ||
return Effect.map(go(e.error), tree => make(`Union member`, [tree])); | ||
default: | ||
return go(e); | ||
} | ||
}), forest => make(getParseIssueTitle(e), forest))); | ||
case "TupleType": | ||
return getTree(e, () => Effect.map(Effect.forEach(e.errors, index => Effect.map(go(index.error), tree => make(`[${util_.formatPropertyKey(index.index)}]`, [tree]))), forest => make(getParseIssueTitle(e), forest))); | ||
case "TypeLiteral": | ||
return getTree(e, () => Effect.map(Effect.forEach(e.errors, key => Effect.map(go(key.error), tree => make(`[${util_.formatPropertyKey(key.key)}]`, [tree]))), forest => make(getParseIssueTitle(e), forest))); | ||
return Effect.map(formatMissingMessage(e), make); | ||
case "Transformation": | ||
return getTree(e, () => Effect.map(go(e.error), tree => make(getParseIssueTitle(e), [make(formatTransformationKind(e.kind), [tree])]))); | ||
return getTree(e, () => Effect.map(go(e.issue), tree => make(getParseIssueTitle(e), [make(formatTransformationKind(e.kind), [tree])]))); | ||
case "Refinement": | ||
return getTree(e, () => Effect.map(go(e.error), tree => make(getParseIssueTitle(e), [make(formatRefinementKind(e.kind), [tree])]))); | ||
case "Declaration": | ||
return getTree(e, () => { | ||
const error = e.error; | ||
const shouldSkipDefaultMessage = error._tag === "Type" && error.ast === e.ast; | ||
return shouldSkipDefaultMessage ? go(error) : Effect.map(go(error), tree => make(getParseIssueTitle(e), [tree])); | ||
}); | ||
return getTree(e, () => Effect.map(go(e.issue), tree => make(getParseIssueTitle(e), [make(formatRefinementKind(e.kind), [tree])]))); | ||
case "Pointer": | ||
return Effect.map(go(e.issue), tree => make(util_.formatPath(e.path), [tree])); | ||
case "Composite": | ||
{ | ||
const parseIssueTitle = getParseIssueTitle(e); | ||
return getTree(e, () => util_.isNonEmpty(e.issues) ? Effect.map(Effect.forEach(e.issues, go), forest => make(parseIssueTitle, forest)) : Effect.map(go(e.issues), tree => make(parseIssueTitle, [tree]))); | ||
} | ||
} | ||
}; | ||
//# sourceMappingURL=TreeFormatter.js.map |
@@ -11,3 +11,3 @@ /** | ||
export interface Issue { | ||
readonly _tag: "Transformation" | "Type" | "Declaration" | "Refinement" | "TupleType" | "TypeLiteral" | "Union" | "Forbidden" | "Missing" | "Unexpected"; | ||
readonly _tag: ParseResult.ParseIssue["_tag"]; | ||
readonly path: ReadonlyArray<PropertyKey>; | ||
@@ -14,0 +14,0 @@ readonly message: string; |
@@ -51,2 +51,12 @@ /** | ||
*/ | ||
export type MissingMessageAnnotation = () => string | Effect<string>; | ||
/** | ||
* @category annotations | ||
* @since 0.67.0 | ||
*/ | ||
export declare const MissingMessageAnnotationId: unique symbol; | ||
/** | ||
* @category annotations | ||
* @since 0.67.0 | ||
*/ | ||
export type IdentifierAnnotation = string; | ||
@@ -150,2 +160,7 @@ /** | ||
* @category annotations | ||
* @since 0.68.3 | ||
*/ | ||
export declare const ParseOptionsAnnotationId: unique symbol; | ||
/** | ||
* @category annotations | ||
* @since 0.67.0 | ||
@@ -185,2 +200,7 @@ */ | ||
*/ | ||
export declare const getMissingMessageAnnotation: (annotated: Annotated) => Option.Option<MissingMessageAnnotation>; | ||
/** | ||
* @category annotations | ||
* @since 0.67.0 | ||
*/ | ||
export declare const getTitleAnnotation: (annotated: Annotated) => Option.Option<string>; | ||
@@ -233,2 +253,7 @@ /** | ||
/** | ||
* @category annotations | ||
* @since 0.68.3 | ||
*/ | ||
export declare const getParseOptionsAnnotation: (annotated: Annotated) => Option.Option<ParseOptions>; | ||
/** | ||
* @category model | ||
@@ -250,3 +275,3 @@ * @since 0.67.0 | ||
*/ | ||
toString(verbose?: boolean): string; | ||
toString(): string; | ||
/** | ||
@@ -282,3 +307,3 @@ * @since 0.67.0 | ||
*/ | ||
toString(verbose?: boolean): string; | ||
toString(): string; | ||
/** | ||
@@ -316,3 +341,3 @@ * @since 0.67.0 | ||
*/ | ||
toString(verbose?: boolean): string; | ||
toString(): string; | ||
/** | ||
@@ -342,3 +367,3 @@ * @since 0.67.0 | ||
*/ | ||
toString(verbose?: boolean): string; | ||
toString(): string; | ||
/** | ||
@@ -373,3 +398,3 @@ * @since 0.67.0 | ||
*/ | ||
toString(verbose?: boolean): string; | ||
toString(): string; | ||
/** | ||
@@ -404,3 +429,3 @@ * @since 0.67.0 | ||
*/ | ||
toString(verbose?: boolean): string; | ||
toString(): string; | ||
/** | ||
@@ -435,3 +460,3 @@ * @since 0.67.0 | ||
*/ | ||
toString(verbose?: boolean): string; | ||
toString(): string; | ||
/** | ||
@@ -466,3 +491,3 @@ * @since 0.67.0 | ||
*/ | ||
toString(verbose?: boolean): string; | ||
toString(): string; | ||
/** | ||
@@ -497,3 +522,3 @@ * @since 0.67.0 | ||
*/ | ||
toString(verbose?: boolean): string; | ||
toString(): string; | ||
/** | ||
@@ -528,3 +553,3 @@ * @since 0.67.0 | ||
*/ | ||
toString(verbose?: boolean): string; | ||
toString(): string; | ||
/** | ||
@@ -559,3 +584,3 @@ * @since 0.67.0 | ||
*/ | ||
toString(verbose?: boolean): string; | ||
toString(): string; | ||
/** | ||
@@ -590,3 +615,3 @@ * @since 0.67.0 | ||
*/ | ||
toString(verbose?: boolean): string; | ||
toString(): string; | ||
/** | ||
@@ -621,3 +646,3 @@ * @since 0.67.0 | ||
*/ | ||
toString(verbose?: boolean): string; | ||
toString(): string; | ||
/** | ||
@@ -652,3 +677,3 @@ * @since 0.67.0 | ||
*/ | ||
toString(verbose?: boolean): string; | ||
toString(): string; | ||
/** | ||
@@ -684,3 +709,3 @@ * @since 0.67.0 | ||
*/ | ||
toString(verbose?: boolean): string; | ||
toString(): string; | ||
/** | ||
@@ -721,3 +746,2 @@ * @since 0.67.0 | ||
readonly annotations: Annotations; | ||
static make: (head: string, spans: ReadonlyArray<TemplateLiteralSpan>, annotations?: Annotations) => TemplateLiteral | Literal; | ||
/** | ||
@@ -731,3 +755,3 @@ * @since 0.67.0 | ||
*/ | ||
toString(verbose?: boolean): string; | ||
toString(): string; | ||
/** | ||
@@ -745,14 +769,30 @@ * @since 0.67.0 | ||
* @category model | ||
* @since 0.67.0 | ||
* @since 0.68.0 | ||
*/ | ||
export declare class Element { | ||
export declare class Type implements Annotated { | ||
readonly type: AST; | ||
readonly annotations: Annotations; | ||
constructor(type: AST, annotations?: Annotations); | ||
/** | ||
* @since 0.68.0 | ||
*/ | ||
toJSON(): object; | ||
/** | ||
* @since 0.68.0 | ||
*/ | ||
toString(): string; | ||
} | ||
/** | ||
* @category model | ||
* @since 0.68.0 | ||
*/ | ||
export declare class OptionalType extends Type { | ||
readonly isOptional: boolean; | ||
constructor(type: AST, isOptional: boolean); | ||
constructor(type: AST, isOptional: boolean, annotations?: Annotations); | ||
/** | ||
* @since 0.67.0 | ||
* @since 0.68.0 | ||
*/ | ||
toJSON(): object; | ||
/** | ||
* @since 0.67.0 | ||
* @since 0.68.0 | ||
*/ | ||
@@ -766,4 +806,4 @@ toString(): string; | ||
export declare class TupleType implements Annotated { | ||
readonly elements: ReadonlyArray<Element>; | ||
readonly rest: ReadonlyArray<AST>; | ||
readonly elements: ReadonlyArray<OptionalType>; | ||
readonly rest: ReadonlyArray<Type>; | ||
readonly isReadonly: boolean; | ||
@@ -775,7 +815,7 @@ readonly annotations: Annotations; | ||
readonly _tag = "TupleType"; | ||
constructor(elements: ReadonlyArray<Element>, rest: ReadonlyArray<AST>, isReadonly: boolean, annotations?: Annotations); | ||
constructor(elements: ReadonlyArray<OptionalType>, rest: ReadonlyArray<Type>, isReadonly: boolean, annotations?: Annotations); | ||
/** | ||
* @since 0.67.0 | ||
*/ | ||
toString(verbose?: boolean): string; | ||
toString(): string; | ||
/** | ||
@@ -795,8 +835,5 @@ * @since 0.67.0 | ||
*/ | ||
export declare class PropertySignature implements Annotated { | ||
export declare class PropertySignature extends OptionalType { | ||
readonly name: PropertyKey; | ||
readonly type: AST; | ||
readonly isOptional: boolean; | ||
readonly isReadonly: boolean; | ||
readonly annotations: Annotations; | ||
constructor(name: PropertyKey, type: AST, isOptional: boolean, isReadonly: boolean, annotations?: Annotations); | ||
@@ -855,3 +892,3 @@ /** | ||
*/ | ||
toString(verbose?: boolean): string; | ||
toString(): string; | ||
/** | ||
@@ -887,3 +924,3 @@ * @since 0.67.0 | ||
*/ | ||
toString(verbose?: boolean): string; | ||
toString(): string; | ||
/** | ||
@@ -914,3 +951,3 @@ * @since 0.67.0 | ||
*/ | ||
toString(verbose?: boolean): string; | ||
toString(): string; | ||
/** | ||
@@ -942,3 +979,3 @@ * @since 0.67.0 | ||
*/ | ||
toString(verbose?: boolean): string; | ||
toString(): string; | ||
/** | ||
@@ -1021,3 +1058,3 @@ * @since 0.67.0 | ||
*/ | ||
readonly exact?: boolean; | ||
readonly exact?: boolean | undefined; | ||
} | ||
@@ -1045,3 +1082,3 @@ /** | ||
*/ | ||
toString(verbose?: boolean): string; | ||
toString(): string; | ||
/** | ||
@@ -1048,0 +1085,0 @@ * @since 0.67.0 |
@@ -39,4 +39,2 @@ /** | ||
* @since 0.67.0 | ||
* | ||
* Serializable represents an object that has self-contained Schema(s) | ||
*/ | ||
@@ -43,0 +41,0 @@ export * as Serializable from "./Serializable.js"; |
@@ -168,2 +168,3 @@ /** | ||
patternProperties?: Record<string, JsonSchema7>; | ||
propertyNames?: JsonSchema7; | ||
} | ||
@@ -170,0 +171,0 @@ /** |
/** | ||
* @since 0.67.0 | ||
*/ | ||
import * as Arr from "effect/Array"; | ||
import * as array_ from "effect/Array"; | ||
import * as Effect from "effect/Effect"; | ||
@@ -18,38 +18,29 @@ import * as Either from "effect/Either"; | ||
*/ | ||
export type ParseIssue = Declaration | Refinement | TupleType | TypeLiteral | Union | Transformation | Type | Forbidden; | ||
export type ParseIssue = Type | Missing | Unexpected | Forbidden | Pointer | Refinement | Transformation | Composite; | ||
/** | ||
* Error that occurs when a declaration has an error. | ||
* | ||
* @category model | ||
* @since 0.67.0 | ||
* @since 0.68.0 | ||
*/ | ||
export declare class Declaration { | ||
readonly ast: AST.Declaration; | ||
readonly actual: unknown; | ||
readonly error: ParseIssue; | ||
/** | ||
* @since 0.67.0 | ||
*/ | ||
readonly _tag = "Declaration"; | ||
constructor(ast: AST.Declaration, actual: unknown, error: ParseIssue); | ||
} | ||
export type SingleOrNonEmpty<A> = A | array_.NonEmptyReadonlyArray<A>; | ||
/** | ||
* Error that occurs when a refinement has an error. | ||
* | ||
* @category model | ||
* @since 0.67.0 | ||
* @since 0.68.0 | ||
*/ | ||
export declare class Refinement { | ||
readonly ast: AST.Refinement<AST.AST>; | ||
export type Path = SingleOrNonEmpty<PropertyKey>; | ||
/** | ||
* @category model | ||
* @since 0.68.0 | ||
*/ | ||
export declare class Pointer { | ||
readonly path: Path; | ||
readonly actual: unknown; | ||
readonly kind: "From" | "Predicate"; | ||
readonly error: ParseIssue; | ||
readonly issue: ParseIssue; | ||
/** | ||
* @since 0.67.0 | ||
* @since 0.68.0 | ||
*/ | ||
readonly _tag = "Refinement"; | ||
constructor(ast: AST.Refinement<AST.AST>, actual: unknown, kind: "From" | "Predicate", error: ParseIssue); | ||
readonly _tag = "Pointer"; | ||
constructor(path: Path, actual: unknown, issue: ParseIssue); | ||
} | ||
/** | ||
* Error that occurs when an array or tuple has an error. | ||
* Error that occurs when an unexpected key or index is present. | ||
* | ||
@@ -59,15 +50,20 @@ * @category model | ||
*/ | ||
export declare class TupleType { | ||
readonly ast: AST.TupleType; | ||
export declare class Unexpected { | ||
readonly actual: unknown; | ||
readonly errors: Arr.NonEmptyReadonlyArray<Index>; | ||
readonly output: ReadonlyArray<unknown>; | ||
/** | ||
* @since 0.68.0 | ||
*/ | ||
readonly message?: string | undefined; | ||
/** | ||
* @since 0.67.0 | ||
*/ | ||
readonly _tag = "TupleType"; | ||
constructor(ast: AST.TupleType, actual: unknown, errors: Arr.NonEmptyReadonlyArray<Index>, output?: ReadonlyArray<unknown>); | ||
readonly _tag = "Unexpected"; | ||
constructor(actual: unknown, | ||
/** | ||
* @since 0.68.0 | ||
*/ | ||
message?: string | undefined); | ||
} | ||
/** | ||
* The `Index` error indicates that there was an error at a specific index in an array or tuple. | ||
* Error that occurs when a required key or index is missing. | ||
* | ||
@@ -77,49 +73,55 @@ * @category model | ||
*/ | ||
export declare class Index { | ||
readonly index: number; | ||
readonly error: ParseIssue | Missing | Unexpected; | ||
export declare class Missing { | ||
/** | ||
* @since 0.68.0 | ||
*/ | ||
readonly ast: AST.Annotated; | ||
/** | ||
* @since 0.68.0 | ||
*/ | ||
readonly message?: string | undefined; | ||
/** | ||
* @since 0.67.0 | ||
*/ | ||
readonly _tag = "Index"; | ||
constructor(index: number, error: ParseIssue | Missing | Unexpected); | ||
readonly _tag = "Missing"; | ||
/** | ||
* @since 0.68.0 | ||
*/ | ||
readonly actual: undefined; | ||
constructor( | ||
/** | ||
* @since 0.68.0 | ||
*/ | ||
ast: AST.Annotated, | ||
/** | ||
* @since 0.68.0 | ||
*/ | ||
message?: string | undefined); | ||
} | ||
/** | ||
* Error that occurs when a type literal or record has an error. | ||
* Error that contains multiple issues. | ||
* | ||
* @category model | ||
* @since 0.67.0 | ||
* @since 0.68.0 | ||
*/ | ||
export declare class TypeLiteral { | ||
readonly ast: AST.TypeLiteral; | ||
export declare class Composite { | ||
readonly ast: AST.Annotated; | ||
readonly actual: unknown; | ||
readonly errors: Arr.NonEmptyReadonlyArray<Key>; | ||
readonly output: { | ||
readonly [x: string]: unknown; | ||
}; | ||
readonly issues: SingleOrNonEmpty<ParseIssue>; | ||
readonly output?: unknown | undefined; | ||
/** | ||
* @since 0.67.0 | ||
* @since 0.68.0 | ||
*/ | ||
readonly _tag = "TypeLiteral"; | ||
constructor(ast: AST.TypeLiteral, actual: unknown, errors: Arr.NonEmptyReadonlyArray<Key>, output?: { | ||
readonly [x: string]: unknown; | ||
}); | ||
readonly _tag = "Composite"; | ||
constructor(ast: AST.Annotated, actual: unknown, issues: SingleOrNonEmpty<ParseIssue>, output?: unknown | undefined); | ||
} | ||
/** | ||
* The `Key` variant of the `ParseIssue` type represents an error that occurs when a key in a type literal or record is invalid. | ||
* Returns `true` if the value is a `Composite`. | ||
* | ||
* @category model | ||
* @since 0.67.0 | ||
* @category guards | ||
* @since 0.68.0 | ||
*/ | ||
export declare class Key { | ||
readonly key: PropertyKey; | ||
readonly error: ParseIssue | Missing | Unexpected; | ||
/** | ||
* @since 0.67.0 | ||
*/ | ||
readonly _tag = "Key"; | ||
constructor(key: PropertyKey, error: ParseIssue | Missing | Unexpected); | ||
} | ||
export declare const isComposite: (u: unknown) => u is Composite; | ||
/** | ||
* Error that occurs when an unexpected key or index is present. | ||
* Error that occurs when a refinement has an error. | ||
* | ||
@@ -129,9 +131,12 @@ * @category model | ||
*/ | ||
export declare class Unexpected { | ||
readonly ast: AST.AST; | ||
export declare class Refinement { | ||
readonly ast: AST.Refinement; | ||
readonly actual: unknown; | ||
readonly kind: "From" | "Predicate"; | ||
readonly issue: ParseIssue; | ||
/** | ||
* @since 0.67.0 | ||
*/ | ||
readonly _tag = "Unexpected"; | ||
constructor(ast: AST.AST); | ||
readonly _tag = "Refinement"; | ||
constructor(ast: AST.Refinement, actual: unknown, kind: "From" | "Predicate", issue: ParseIssue); | ||
} | ||
@@ -148,3 +153,3 @@ /** | ||
readonly kind: "Encoded" | "Transformation" | "Type"; | ||
readonly error: ParseIssue; | ||
readonly issue: ParseIssue; | ||
/** | ||
@@ -154,3 +159,3 @@ * @since 0.67.0 | ||
readonly _tag = "Transformation"; | ||
constructor(ast: AST.Transformation, actual: unknown, kind: "Encoded" | "Transformation" | "Type", error: ParseIssue); | ||
constructor(ast: AST.Transformation, actual: unknown, kind: "Encoded" | "Transformation" | "Type", issue: ParseIssue); | ||
} | ||
@@ -165,4 +170,5 @@ /** | ||
export declare class Type { | ||
readonly ast: AST.AST; | ||
readonly ast: AST.Annotated; | ||
readonly actual: unknown; | ||
readonly message?: string | undefined; | ||
/** | ||
@@ -172,7 +178,3 @@ * @since 0.67.0 | ||
readonly _tag = "Type"; | ||
/** | ||
* @since 0.67.0 | ||
*/ | ||
readonly message: Option.Option<string>; | ||
constructor(ast: AST.AST, actual: unknown, message?: string); | ||
constructor(ast: AST.Annotated, actual: unknown, message?: string | undefined); | ||
} | ||
@@ -186,4 +188,5 @@ /** | ||
export declare class Forbidden { | ||
readonly ast: AST.AST; | ||
readonly ast: AST.Annotated; | ||
readonly actual: unknown; | ||
readonly message?: string | undefined; | ||
/** | ||
@@ -193,56 +196,18 @@ * @since 0.67.0 | ||
readonly _tag = "Forbidden"; | ||
/** | ||
* @since 0.67.0 | ||
*/ | ||
readonly message: Option.Option<string>; | ||
constructor(ast: AST.AST, actual: unknown, message?: string); | ||
constructor(ast: AST.Annotated, actual: unknown, message?: string | undefined); | ||
} | ||
/** | ||
* Error that occurs when a required key or index is missing. | ||
* | ||
* @category model | ||
* @since 0.67.0 | ||
* @category type id | ||
* @since 0.68.0 | ||
*/ | ||
export declare class Missing { | ||
/** | ||
* @since 0.67.0 | ||
*/ | ||
readonly _tag = "Missing"; | ||
} | ||
export declare const ParseErrorTypeId: unique symbol; | ||
/** | ||
* @category constructors | ||
* @since 0.67.0 | ||
* @category type id | ||
* @since 0.68.0 | ||
*/ | ||
export declare const missing: Missing; | ||
export type ParseErrorTypeId = typeof ParseErrorTypeId; | ||
/** | ||
* Error that occurs when a member in a union has an error. | ||
* | ||
* @category model | ||
* @since 0.67.0 | ||
* @since 0.68.0 | ||
*/ | ||
export declare class Member { | ||
readonly ast: AST.AST; | ||
readonly error: ParseIssue; | ||
/** | ||
* @since 0.67.0 | ||
*/ | ||
readonly _tag = "Member"; | ||
constructor(ast: AST.AST, error: ParseIssue); | ||
} | ||
/** | ||
* Error that occurs when a union has an error. | ||
* | ||
* @category model | ||
* @since 0.67.0 | ||
*/ | ||
export declare class Union { | ||
readonly ast: AST.Union; | ||
readonly actual: unknown; | ||
readonly errors: Arr.NonEmptyReadonlyArray<Type | TypeLiteral | Member>; | ||
/** | ||
* @since 0.67.0 | ||
*/ | ||
readonly _tag = "Union"; | ||
constructor(ast: AST.Union, actual: unknown, errors: Arr.NonEmptyReadonlyArray<Type | TypeLiteral | Member>); | ||
} | ||
export declare const isParseError: (u: unknown) => u is ParseError; | ||
declare const ParseError_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").Equals<A, {}> extends true ? void : { readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }) => import("effect/Cause").YieldableError & { | ||
@@ -255,4 +220,8 @@ readonly _tag: "ParseError"; | ||
export declare class ParseError extends ParseError_base<{ | ||
readonly error: ParseIssue; | ||
readonly issue: ParseIssue; | ||
}> { | ||
/** | ||
* @since 0.68.0 | ||
*/ | ||
readonly [ParseErrorTypeId]: symbol; | ||
get message(): string; | ||
@@ -371,2 +340,3 @@ /** | ||
/** | ||
* @throws `ParseError` | ||
* @category decoding | ||
@@ -397,2 +367,3 @@ * @since 0.67.0 | ||
/** | ||
* @throws `ParseError` | ||
* @category encoding | ||
@@ -448,2 +419,3 @@ * @since 0.67.0 | ||
/** | ||
* @throws `ParseError` | ||
* @category validation | ||
@@ -483,2 +455,3 @@ * @since 0.67.0 | ||
* | ||
* @throws `ParseError` | ||
* @category validation | ||
@@ -485,0 +458,0 @@ * @since 0.67.0 |
/** | ||
* @since 0.67.0 | ||
* | ||
* Serializable represents an object that has self-contained Schema(s) | ||
*/ | ||
@@ -16,2 +14,8 @@ import type * as Effect from "effect/Effect"; | ||
/** | ||
* The `Serializable` trait, part of the `@effect/schema/Serializable` module, | ||
* enables objects to have self-contained schema(s) for serialization. This | ||
* functionality is particularly beneficial in scenarios where objects need to | ||
* be consistently serialized and deserialized across various runtime | ||
* environments or sent over network communications. | ||
* | ||
* @since 0.67.0 | ||
@@ -29,2 +33,10 @@ * @category model | ||
/** | ||
* @since 0.68.15 | ||
*/ | ||
type Type<T> = T extends Serializable<infer A, infer _I, infer _R> ? A : never; | ||
/** | ||
* @since 0.68.15 | ||
*/ | ||
type Encoded<T> = T extends Serializable<infer _A, infer I, infer _R> ? I : never; | ||
/** | ||
* @since 0.67.0 | ||
@@ -45,9 +57,14 @@ */ | ||
/** | ||
* The `WithResult` trait is designed to encapsulate the outcome of an | ||
* operation, distinguishing between success and failure cases. Each case is | ||
* associated with a schema that defines the structure and types of the success | ||
* or failure data. | ||
* | ||
* @since 0.67.0 | ||
* @category model | ||
*/ | ||
export interface WithResult<SuccessA, SuccessI, FailureA, FailureI, SuccessAndFailureR> { | ||
export interface WithResult<Success, SuccessEncoded, Failure, FailureEncoded, SuccessAndFailureR> { | ||
readonly [symbolResult]: { | ||
readonly Success: Schema.Schema<SuccessA, SuccessI, SuccessAndFailureR>; | ||
readonly Failure: Schema.Schema<FailureA, FailureI, SuccessAndFailureR>; | ||
readonly Success: Schema.Schema<Success, SuccessEncoded, SuccessAndFailureR>; | ||
readonly Failure: Schema.Schema<Failure, FailureEncoded, SuccessAndFailureR>; | ||
}; | ||
@@ -61,5 +78,13 @@ } | ||
/** | ||
* @since 0.68.16 | ||
*/ | ||
type Success<T> = T extends WithResult<infer _A, infer _I, infer _E, infer _EI, infer _R> ? _A : never; | ||
/** | ||
* @since 0.68.16 | ||
*/ | ||
type Error<T> = T extends WithResult<infer _A, infer _I, infer _E, infer _EI, infer _R> ? _E : never; | ||
/** | ||
* @since 0.67.0 | ||
*/ | ||
type Context<T> = T extends WithResult<infer _A, infer _I, infer _E, infer _EI, infer R> ? R : never; | ||
type Context<T> = T extends WithResult<infer _SA, infer _SI, infer _FA, infer _FI, infer R> ? R : never; | ||
} | ||
@@ -70,3 +95,3 @@ /** | ||
*/ | ||
export declare const failureSchema: <A, I, E, EI, R>(self: WithResult<A, I, E, EI, R>) => Schema.Schema<E, EI, R>; | ||
export declare const failureSchema: <SA, SI, FA, FI, R>(self: WithResult<SA, SI, FA, FI, R>) => Schema.Schema<FA, FI, R>; | ||
/** | ||
@@ -76,3 +101,3 @@ * @since 0.67.0 | ||
*/ | ||
export declare const successSchema: <A, I, E, EI, R>(self: WithResult<A, I, E, EI, R>) => Schema.Schema<A, I, R>; | ||
export declare const successSchema: <SA, SI, FA, FI, R>(self: WithResult<SA, SI, FA, FI, R>) => Schema.Schema<SA, SI, R>; | ||
/** | ||
@@ -82,3 +107,3 @@ * @since 0.67.0 | ||
*/ | ||
export declare const exitSchema: <A, I, E, EI, R>(self: WithResult<A, I, E, EI, R>) => Schema.Schema<Exit.Exit<A, E>, Schema.ExitEncoded<I, EI>, R>; | ||
export declare const exitSchema: <SA, SI, FA, FI, R>(self: WithResult<SA, SI, FA, FI, R>) => Schema.Schema<Exit.Exit<SA, FA>, Schema.ExitEncoded<SI, FI>, R>; | ||
/** | ||
@@ -88,3 +113,3 @@ * @since 0.67.0 | ||
*/ | ||
export interface SerializableWithResult<Self, FieldsI, FieldsR, SuccessA, SuccessI, FailureA, FailureI, SuccessAndFailureR> extends Serializable<Self, FieldsI, FieldsR>, WithResult<SuccessA, SuccessI, FailureA, FailureI, SuccessAndFailureR> { | ||
export interface SerializableWithResult<A, I, R, Success, SuccessEncoded, Failure, FailureEncoded, SuccessAndFailureR> extends Serializable<A, I, R>, WithResult<Success, SuccessEncoded, Failure, FailureEncoded, SuccessAndFailureR> { | ||
} | ||
@@ -119,4 +144,4 @@ /** | ||
export declare const serializeFailure: { | ||
<E>(value: E): <A, I, EI, R>(self: WithResult<A, I, E, EI, R>) => Effect.Effect<EI, ParseResult.ParseError, R>; | ||
<A, I, E, EI, R>(self: WithResult<A, I, E, EI, R>, value: E): Effect.Effect<EI, ParseResult.ParseError, R>; | ||
<FA>(value: FA): <SA, SI, FI, R>(self: WithResult<SA, SI, FA, FI, R>) => Effect.Effect<FI, ParseResult.ParseError, R>; | ||
<SA, SI, FA, FI, R>(self: WithResult<SA, SI, FA, FI, R>, value: FA): Effect.Effect<FI, ParseResult.ParseError, R>; | ||
}; | ||
@@ -128,4 +153,4 @@ /** | ||
export declare const deserializeFailure: { | ||
(value: unknown): <A, I, E, EI, R>(self: WithResult<A, I, E, EI, R>) => Effect.Effect<E, ParseResult.ParseError, R>; | ||
<A, I, E, EI, R>(self: WithResult<A, I, E, EI, R>, value: unknown): Effect.Effect<E, ParseResult.ParseError, R>; | ||
(value: unknown): <SA, SI, FA, FI, R>(self: WithResult<SA, SI, FA, FI, R>) => Effect.Effect<FA, ParseResult.ParseError, R>; | ||
<SA, SI, FA, FI, R>(self: WithResult<SA, SI, FA, FI, R>, value: unknown): Effect.Effect<FA, ParseResult.ParseError, R>; | ||
}; | ||
@@ -137,4 +162,4 @@ /** | ||
export declare const serializeSuccess: { | ||
<A>(value: A): <I, E, EI, R>(self: WithResult<A, I, E, EI, R>) => Effect.Effect<I, ParseResult.ParseError, R>; | ||
<A, I, E, EI, R>(self: WithResult<A, I, E, EI, R>, value: A): Effect.Effect<I, ParseResult.ParseError, R>; | ||
<SA>(value: SA): <SI, FA, FI, R>(self: WithResult<SA, SI, FA, FI, R>) => Effect.Effect<SI, ParseResult.ParseError, R>; | ||
<SA, SI, FA, FI, R>(self: WithResult<SA, SI, FA, FI, R>, value: SA): Effect.Effect<SI, ParseResult.ParseError, R>; | ||
}; | ||
@@ -146,4 +171,4 @@ /** | ||
export declare const deserializeSuccess: { | ||
(value: unknown): <A, I, E, EI, R>(self: WithResult<A, I, E, EI, R>) => Effect.Effect<A, ParseResult.ParseError, R>; | ||
<A, I, E, EI, R>(self: WithResult<A, I, E, EI, R>, value: unknown): Effect.Effect<A, ParseResult.ParseError, R>; | ||
(value: unknown): <SA, SI, FA, FI, R>(self: WithResult<SA, SI, FA, FI, R>) => Effect.Effect<SA, ParseResult.ParseError, R>; | ||
<SA, SI, FA, FI, R>(self: WithResult<SA, SI, FA, FI, R>, value: unknown): Effect.Effect<SA, ParseResult.ParseError, R>; | ||
}; | ||
@@ -155,4 +180,4 @@ /** | ||
export declare const serializeExit: { | ||
<A, E>(value: Exit.Exit<A, E>): <I, EI, R>(self: WithResult<A, I, E, EI, R>) => Effect.Effect<Schema.ExitEncoded<I, EI>, ParseResult.ParseError, R>; | ||
<A, I, E, EI, R>(self: WithResult<A, I, E, EI, R>, value: Exit.Exit<A, E>): Effect.Effect<Schema.ExitEncoded<I, EI>, ParseResult.ParseError, R>; | ||
<SA, FA>(value: Exit.Exit<SA, FA>): <SI, FI, R>(self: WithResult<SA, SI, FA, FI, R>) => Effect.Effect<Schema.ExitEncoded<SI, FI>, ParseResult.ParseError, R>; | ||
<SA, SI, FA, FI, R>(self: WithResult<SA, SI, FA, FI, R>, value: Exit.Exit<SA, FA>): Effect.Effect<Schema.ExitEncoded<SI, FI>, ParseResult.ParseError, R>; | ||
}; | ||
@@ -164,5 +189,5 @@ /** | ||
export declare const deserializeExit: { | ||
(value: unknown): <A, I, E, EI, R>(self: WithResult<A, I, E, EI, R>) => Effect.Effect<Exit.Exit<A, E>, ParseResult.ParseError, R>; | ||
<A, I, E, EI, R>(self: WithResult<A, I, E, EI, R>, value: unknown): Effect.Effect<Exit.Exit<A, E>, ParseResult.ParseError, R>; | ||
(value: unknown): <SA, SI, FA, FI, R>(self: WithResult<SA, SI, FA, FI, R>) => Effect.Effect<Exit.Exit<SA, FA>, ParseResult.ParseError, R>; | ||
<SA, SI, FA, FI, R>(self: WithResult<SA, SI, FA, FI, R>, value: unknown): Effect.Effect<Exit.Exit<SA, FA>, ParseResult.ParseError, R>; | ||
}; | ||
//# sourceMappingURL=Serializable.d.ts.map |
@@ -61,3 +61,2 @@ /** | ||
}; | ||
const getArbitraryErrorMessage = (message, path) => errors_.getErrorMessageWithPath(`cannot build an Arbitrary for ${message}`, path); | ||
const go = (ast, options, path) => { | ||
@@ -78,3 +77,3 @@ const hook = getHook(ast); | ||
{ | ||
throw new Error(getArbitraryErrorMessage(`a declaration without annotations (${ast})`, path)); | ||
throw new Error(errors_.getArbitraryMissingAnnotationErrorMessage(path, ast)); | ||
} | ||
@@ -90,3 +89,3 @@ case "Literal": | ||
return () => { | ||
throw new Error(getArbitraryErrorMessage("`never`", path)); | ||
throw new Error(errors_.getArbitraryUnsupportedErrorMessage(path, ast)); | ||
}; | ||
@@ -166,3 +165,3 @@ case "UnknownKeyword": | ||
} | ||
const rest = ast.rest.map(e => go(e, options, path)); | ||
const rest = ast.rest.map(annotatedAST => go(annotatedAST.type, options, path)); | ||
return fc => { | ||
@@ -262,3 +261,3 @@ // --------------------------------------------- | ||
if (ast.enums.length === 0) { | ||
throw new Error(getArbitraryErrorMessage("an empty enum", path)); | ||
throw new Error(errors_.getArbitraryEmptyEnumErrorMessage(path)); | ||
} | ||
@@ -265,0 +264,0 @@ return fc => fc.oneof(...ast.enums.map(([_, value]) => fc.constant(value))); |
/** | ||
* @since 0.67.0 | ||
*/ | ||
import * as Arr from "effect/Array"; | ||
import * as array_ from "effect/Array"; | ||
import * as Effect from "effect/Effect"; | ||
import * as util_ from "./internal/util.js"; | ||
import * as TreeFormatter from "./TreeFormatter.js"; | ||
@@ -21,3 +22,3 @@ /** | ||
*/ | ||
export const formatError = error => formatIssue(error.error); | ||
export const formatError = error => formatIssue(error.issue); | ||
/** | ||
@@ -27,3 +28,3 @@ * @category formatting | ||
*/ | ||
export const formatErrorSync = error => formatIssueSync(error.error); | ||
export const formatErrorSync = error => formatIssueSync(error.issue); | ||
const succeed = issue => Effect.succeed([issue]); | ||
@@ -38,3 +39,2 @@ const getArray = (issue, path, onFailure) => Effect.matchEffect(TreeFormatter.getMessage(issue), { | ||
}); | ||
const flatten = eff => Effect.map(eff, Arr.flatten); | ||
const go = (e, path = []) => { | ||
@@ -59,29 +59,19 @@ const _tag = e._tag; | ||
path, | ||
message: `is unexpected, expected ${e.ast.toString(true)}` | ||
message: TreeFormatter.formatUnexpectedMessage(e) | ||
}); | ||
case "Missing": | ||
return succeed({ | ||
return Effect.map(TreeFormatter.formatMissingMessage(e), message => [{ | ||
_tag, | ||
path, | ||
message: "is missing" | ||
}); | ||
case "Union": | ||
return getArray(e, path, () => flatten(Effect.forEach(e.errors, e => { | ||
switch (e._tag) { | ||
case "Member": | ||
return go(e.error, path); | ||
default: | ||
return go(e, path); | ||
} | ||
}))); | ||
case "TupleType": | ||
return getArray(e, path, () => flatten(Effect.forEach(e.errors, index => go(index.error, path.concat(index.index))))); | ||
case "TypeLiteral": | ||
return getArray(e, path, () => flatten(Effect.forEach(e.errors, key => go(key.error, path.concat(key.key))))); | ||
case "Declaration": | ||
message | ||
}]); | ||
case "Pointer": | ||
return go(e.issue, path.concat(e.path)); | ||
case "Composite": | ||
return getArray(e, path, () => util_.isNonEmpty(e.issues) ? Effect.map(Effect.forEach(e.issues, issue => go(issue, path)), array_.flatten) : go(e.issues, path)); | ||
case "Refinement": | ||
case "Transformation": | ||
return getArray(e, path, () => go(e.error, path)); | ||
return getArray(e, path, () => go(e.issue, path)); | ||
} | ||
}; | ||
//# sourceMappingURL=ArrayFormatter.js.map |
@@ -33,2 +33,7 @@ /** | ||
*/ | ||
export const MissingMessageAnnotationId = /*#__PURE__*/Symbol.for("@effect/schema/annotation/MissingMessage"); | ||
/** | ||
* @category annotations | ||
* @since 0.67.0 | ||
*/ | ||
export const IdentifierAnnotationId = /*#__PURE__*/Symbol.for("@effect/schema/annotation/Identifier"); | ||
@@ -80,2 +85,7 @@ /** | ||
export const ParseIssueTitleAnnotationId = /*#__PURE__*/Symbol.for("@effect/schema/annotation/ParseIssueTitle"); | ||
/** | ||
* @category annotations | ||
* @since 0.68.3 | ||
*/ | ||
export const ParseOptionsAnnotationId = /*#__PURE__*/Symbol.for("@effect/schema/annotation/ParseOptions"); | ||
/** @internal */ | ||
@@ -104,2 +114,7 @@ export const SurrogateAnnotationId = /*#__PURE__*/Symbol.for("@effect/schema/annotation/Surrogate"); | ||
*/ | ||
export const getMissingMessageAnnotation = /*#__PURE__*/getAnnotation(MissingMessageAnnotationId); | ||
/** | ||
* @category annotations | ||
* @since 0.67.0 | ||
*/ | ||
export const getTitleAnnotation = /*#__PURE__*/getAnnotation(TitleAnnotationId); | ||
@@ -151,2 +166,7 @@ /** | ||
export const getParseIssueTitleAnnotation = /*#__PURE__*/getAnnotation(ParseIssueTitleAnnotationId); | ||
/** | ||
* @category annotations | ||
* @since 0.68.3 | ||
*/ | ||
export const getParseOptionsAnnotation = /*#__PURE__*/getAnnotation(ParseOptionsAnnotationId); | ||
/** @internal */ | ||
@@ -180,4 +200,4 @@ export const getSurrogateAnnotation = /*#__PURE__*/getAnnotation(SurrogateAnnotationId); | ||
*/ | ||
toString(verbose = false) { | ||
return Option.getOrElse(getExpected(this, verbose), () => "<declaration schema>"); | ||
toString() { | ||
return Option.getOrElse(getExpected(this), () => "<declaration schema>"); | ||
} | ||
@@ -219,4 +239,4 @@ /** | ||
*/ | ||
toString(verbose = false) { | ||
return Option.getOrElse(getExpected(this, verbose), () => util_.formatUnknown(this.literal)); | ||
toString() { | ||
return Option.getOrElse(getExpected(this), () => util_.formatUnknown(this.literal)); | ||
} | ||
@@ -266,4 +286,4 @@ /** | ||
*/ | ||
toString(verbose = false) { | ||
return Option.getOrElse(getExpected(this, verbose), () => util_.formatUnknown(this.symbol)); | ||
toString() { | ||
return Option.getOrElse(getExpected(this), () => util_.formatUnknown(this.symbol)); | ||
} | ||
@@ -302,4 +322,4 @@ /** | ||
*/ | ||
toString(verbose = false) { | ||
return formatKeyword(this, verbose); | ||
toString() { | ||
return formatKeyword(this); | ||
} | ||
@@ -344,4 +364,4 @@ /** | ||
*/ | ||
toString(verbose = false) { | ||
return formatKeyword(this, verbose); | ||
toString() { | ||
return formatKeyword(this); | ||
} | ||
@@ -386,4 +406,4 @@ /** | ||
*/ | ||
toString(verbose = false) { | ||
return formatKeyword(this, verbose); | ||
toString() { | ||
return formatKeyword(this); | ||
} | ||
@@ -428,4 +448,4 @@ /** | ||
*/ | ||
toString(verbose = false) { | ||
return formatKeyword(this, verbose); | ||
toString() { | ||
return formatKeyword(this); | ||
} | ||
@@ -470,4 +490,4 @@ /** | ||
*/ | ||
toString(verbose = false) { | ||
return formatKeyword(this, verbose); | ||
toString() { | ||
return formatKeyword(this); | ||
} | ||
@@ -512,4 +532,4 @@ /** | ||
*/ | ||
toString(verbose = false) { | ||
return formatKeyword(this, verbose); | ||
toString() { | ||
return formatKeyword(this); | ||
} | ||
@@ -555,4 +575,4 @@ /** | ||
*/ | ||
toString(verbose = false) { | ||
return formatKeyword(this, verbose); | ||
toString() { | ||
return formatKeyword(this); | ||
} | ||
@@ -598,4 +618,4 @@ /** | ||
*/ | ||
toString(verbose = false) { | ||
return formatKeyword(this, verbose); | ||
toString() { | ||
return formatKeyword(this); | ||
} | ||
@@ -641,4 +661,4 @@ /** | ||
*/ | ||
toString(verbose = false) { | ||
return formatKeyword(this, verbose); | ||
toString() { | ||
return formatKeyword(this); | ||
} | ||
@@ -684,4 +704,4 @@ /** | ||
*/ | ||
toString(verbose = false) { | ||
return formatKeyword(this, verbose); | ||
toString() { | ||
return formatKeyword(this); | ||
} | ||
@@ -727,4 +747,4 @@ /** | ||
*/ | ||
toString(verbose = false) { | ||
return formatKeyword(this, verbose); | ||
toString() { | ||
return formatKeyword(this); | ||
} | ||
@@ -773,4 +793,4 @@ /** | ||
*/ | ||
toString(verbose = false) { | ||
return Option.getOrElse(getExpected(this, verbose), () => `<enum ${this.enums.length} value(s): ${this.enums.map((_, value) => JSON.stringify(value)).join(" | ")}>`); | ||
toString() { | ||
return Option.getOrElse(getExpected(this), () => `<enum ${this.enums.length} value(s): ${this.enums.map((_, value) => JSON.stringify(value)).join(" | ")}>`); | ||
} | ||
@@ -833,3 +853,2 @@ /** | ||
annotations; | ||
static make = (head, spans, annotations = {}) => Arr.isNonEmptyReadonlyArray(spans) ? new TemplateLiteral(head, spans, annotations) : new Literal(head); | ||
/** | ||
@@ -847,4 +866,4 @@ * @since 0.67.0 | ||
*/ | ||
toString(verbose = false) { | ||
return Option.getOrElse(getExpected(this, verbose), () => formatTemplateLiteral(this)); | ||
toString() { | ||
return Option.getOrElse(getExpected(this), () => formatTemplateLiteral(this)); | ||
} | ||
@@ -871,13 +890,39 @@ /** | ||
* @category model | ||
* @since 0.67.0 | ||
* @since 0.68.0 | ||
*/ | ||
export class Element { | ||
export class Type { | ||
type; | ||
annotations; | ||
constructor(type, annotations = {}) { | ||
this.type = type; | ||
this.annotations = annotations; | ||
} | ||
/** | ||
* @since 0.68.0 | ||
*/ | ||
toJSON() { | ||
return { | ||
type: this.type.toJSON(), | ||
annotations: toJSONAnnotations(this.annotations) | ||
}; | ||
} | ||
/** | ||
* @since 0.68.0 | ||
*/ | ||
toString() { | ||
return String(this.type); | ||
} | ||
} | ||
/** | ||
* @category model | ||
* @since 0.68.0 | ||
*/ | ||
export class OptionalType extends Type { | ||
isOptional; | ||
constructor(type, isOptional) { | ||
this.type = type; | ||
constructor(type, isOptional, annotations = {}) { | ||
super(type, annotations); | ||
this.isOptional = isOptional; | ||
} | ||
/** | ||
* @since 0.67.0 | ||
* @since 0.68.0 | ||
*/ | ||
@@ -887,7 +932,8 @@ toJSON() { | ||
type: this.type.toJSON(), | ||
isOptional: this.isOptional | ||
isOptional: this.isOptional, | ||
annotations: toJSONAnnotations(this.annotations) | ||
}; | ||
} | ||
/** | ||
* @since 0.67.0 | ||
* @since 0.68.0 | ||
*/ | ||
@@ -898,2 +944,3 @@ toString() { | ||
} | ||
const getRestASTs = rest => rest.map(annotatedAST => annotatedAST.type); | ||
/** | ||
@@ -928,3 +975,3 @@ * @category model | ||
if (hasIllegalRequiredElement || hasOptionalElement && rest.length > 1) { | ||
throw new Error(getRequiredElementFollowinAnOptionalElementErrorMessage); | ||
throw new Error(errors_.getASTRequiredElementFollowinAnOptionalElementErrorMessage); | ||
} | ||
@@ -935,4 +982,4 @@ } | ||
*/ | ||
toString(verbose = false) { | ||
return Option.getOrElse(getExpected(this, verbose), () => formatTuple(this)); | ||
toString() { | ||
return Option.getOrElse(getExpected(this), () => formatTuple(this)); | ||
} | ||
@@ -985,14 +1032,9 @@ /** | ||
*/ | ||
export class PropertySignature { | ||
export class PropertySignature extends OptionalType { | ||
name; | ||
type; | ||
isOptional; | ||
isReadonly; | ||
annotations; | ||
constructor(name, type, isOptional, isReadonly, annotations = {}) { | ||
constructor(name, type, isOptional, isReadonly, annotations) { | ||
super(type, isOptional, annotations); | ||
this.name = name; | ||
this.type = type; | ||
this.isOptional = isOptional; | ||
this.isReadonly = isReadonly; | ||
this.annotations = annotations; | ||
} | ||
@@ -1043,3 +1085,3 @@ /** | ||
} else { | ||
throw new Error(getIndexSignatureParameterErrorMessage); | ||
throw new Error(errors_.getASTIndexSignatureParameterErrorMessage); | ||
} | ||
@@ -1083,3 +1125,3 @@ } | ||
if (Object.prototype.hasOwnProperty.call(keys, name)) { | ||
throw new Error(errors_.getDuplicatePropertySignatureErrorMessage(name)); | ||
throw new Error(errors_.getASTDuplicatePropertySignatureErrorMessage(name)); | ||
} | ||
@@ -1097,3 +1139,3 @@ keys[name] = null; | ||
if (parameters.string) { | ||
throw new Error(getDuplicateIndexSignatureErrorMessage("string")); | ||
throw new Error(errors_.getASTDuplicateIndexSignatureErrorMessage("string")); | ||
} | ||
@@ -1103,3 +1145,3 @@ parameters.string = true; | ||
if (parameters.symbol) { | ||
throw new Error(getDuplicateIndexSignatureErrorMessage("symbol")); | ||
throw new Error(errors_.getASTDuplicateIndexSignatureErrorMessage("symbol")); | ||
} | ||
@@ -1115,4 +1157,4 @@ parameters.symbol = true; | ||
*/ | ||
toString(verbose = false) { | ||
return Option.getOrElse(getExpected(this, verbose), () => formatTypeLiteral(this)); | ||
toString() { | ||
return Option.getOrElse(getExpected(this), () => formatTypeLiteral(this)); | ||
} | ||
@@ -1313,4 +1355,4 @@ /** | ||
*/ | ||
toString(verbose = false) { | ||
return Option.getOrElse(getExpected(this, verbose), () => this.types.map(String).join(" | ")); | ||
toString() { | ||
return Option.getOrElse(getExpected(this), () => this.types.map(String).join(" | ")); | ||
} | ||
@@ -1357,4 +1399,4 @@ /** | ||
*/ | ||
toString(verbose = false) { | ||
return getExpected(this, verbose).pipe(Option.orElse(() => Option.flatMap(Option.liftThrowable(this.f)(), ast => getExpected(ast, verbose))), Option.getOrElse(() => "<suspended schema>")); | ||
toString() { | ||
return getExpected(this).pipe(Option.orElse(() => Option.flatMap(Option.liftThrowable(this.f)(), ast => getExpected(ast))), Option.getOrElse(() => "<suspended schema>")); | ||
} | ||
@@ -1407,4 +1449,4 @@ /** | ||
*/ | ||
toString(verbose = false) { | ||
return Option.getOrElse(getExpected(this, verbose), () => `{ ${this.from} | filter }`); | ||
toString() { | ||
return Option.getOrElse(getExpected(this), () => `{ ${this.from} | filter }`); | ||
} | ||
@@ -1453,4 +1495,4 @@ /** | ||
*/ | ||
toString(verbose = false) { | ||
return Option.getOrElse(getExpected(this, verbose), () => `(${String(this.from)} <-> ${String(this.to)})`); | ||
toString() { | ||
return Option.getOrElse(getExpected(this), () => `(${String(this.from)} <-> ${String(this.to)})`); | ||
} | ||
@@ -1561,3 +1603,3 @@ /** | ||
if (fromKeys[from]) { | ||
throw new Error(getDuplicatePropertySignatureTransformationErrorMessage(from)); | ||
throw new Error(errors_.getASTDuplicatePropertySignatureTransformationErrorMessage(from)); | ||
} | ||
@@ -1567,3 +1609,3 @@ fromKeys[from] = true; | ||
if (toKeys[to]) { | ||
throw new Error(getDuplicatePropertySignatureTransformationErrorMessage(to)); | ||
throw new Error(errors_.getASTDuplicatePropertySignatureTransformationErrorMessage(to)); | ||
} | ||
@@ -1655,3 +1697,3 @@ toKeys[to] = true; | ||
} | ||
out = out.concat(ast.rest); | ||
out = out.concat(getRestASTs(ast.rest)); | ||
return Union.make(out); | ||
@@ -1666,3 +1708,3 @@ } | ||
} | ||
throw new Error(errors_.getErrorMessage("getNumberIndexedAccess", `unsupported schema (${ast})`)); | ||
throw new Error(errors_.getASTUnsupportedSchema(ast)); | ||
}; | ||
@@ -1759,3 +1801,3 @@ /** @internal */ | ||
} else { | ||
throw new Error(errors_.getErrorMessage("record", `unsupported literal (${util_.formatUnknown(key.literal)})`)); | ||
throw new Error(errors_.getASTUnsupportedLiteral(key.literal)); | ||
} | ||
@@ -1777,3 +1819,3 @@ break; | ||
default: | ||
throw new Error(errors_.getErrorMessage("record", `unsupported key schema (${key})`)); | ||
throw new Error(errors_.getASTUnsupportedKeySchema(key)); | ||
} | ||
@@ -1818,3 +1860,3 @@ }; | ||
} | ||
throw new Error(errors_.getErrorMessage("pick", "cannot handle this kind of transformation")); | ||
throw new Error(errors_.getASTUnsupportedSchema(ast)); | ||
} | ||
@@ -1842,5 +1884,5 @@ } | ||
case "TupleType": | ||
return new TupleType(ast.elements.map(e => new Element(exact ? e.type : orUndefined(e.type), true)), Arr.match(ast.rest, { | ||
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 => [Union.make([...rest, undefinedKeyword])] | ||
onNonEmpty: rest => [new Type(Union.make([...getRestASTs(rest), undefinedKeyword]))] | ||
}), ast.isReadonly); | ||
@@ -1854,5 +1896,5 @@ case "TypeLiteral": | ||
case "Declaration": | ||
throw new Error(errors_.getErrorMessage("partial", "cannot handle declarations")); | ||
throw new Error(errors_.getASTUnsupportedSchema(ast)); | ||
case "Refinement": | ||
throw new Error(errors_.getErrorMessage("partial", "cannot handle refinements")); | ||
throw new Error(errors_.getASTUnsupportedSchema(ast)); | ||
case "Transformation": | ||
@@ -1863,3 +1905,3 @@ { | ||
} | ||
throw new Error(errors_.getErrorMessage("partial", "cannot handle transformations")); | ||
throw new Error(errors_.getASTUnsupportedSchema(ast)); | ||
} | ||
@@ -1877,3 +1919,3 @@ } | ||
case "TupleType": | ||
return new TupleType(ast.elements.map(e => new Element(e.type, false)), ast.rest, ast.isReadonly); | ||
return new TupleType(ast.elements.map(e => new OptionalType(e.type, false)), ast.rest, ast.isReadonly); | ||
case "TypeLiteral": | ||
@@ -1886,5 +1928,5 @@ return new TypeLiteral(ast.propertySignatures.map(f => new PropertySignature(f.name, f.type, false, f.isReadonly, f.annotations)), ast.indexSignatures); | ||
case "Declaration": | ||
throw new Error(errors_.getErrorMessage("required", "cannot handle declarations")); | ||
throw new Error(errors_.getASTUnsupportedSchema(ast)); | ||
case "Refinement": | ||
throw new Error(errors_.getErrorMessage("required", "cannot handle refinements")); | ||
throw new Error(errors_.getASTUnsupportedSchema(ast)); | ||
case "Transformation": | ||
@@ -1895,3 +1937,3 @@ { | ||
} | ||
throw new Error(errors_.getErrorMessage("required", "cannot handle transformations")); | ||
throw new Error(errors_.getASTUnsupportedSchema(ast)); | ||
} | ||
@@ -1960,6 +2002,7 @@ } | ||
const type = typeAST(e.type); | ||
return type === e.type ? e : new Element(type, e.isOptional); | ||
return type === e.type ? e : new OptionalType(type, e.isOptional); | ||
}); | ||
const rest = changeMap(ast.rest, typeAST); | ||
return elements === ast.elements && rest === ast.rest ? ast : new TupleType(elements, rest, ast.isReadonly, ast.annotations); | ||
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); | ||
} | ||
@@ -1996,3 +2039,20 @@ case "TypeLiteral": | ||
/** @internal */ | ||
export const preserveAnnotations = 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 getJSONIdentifier = annotated => Option.orElse(getJSONIdentifierAnnotation(annotated), () => getIdentifierAnnotation(annotated)); | ||
// 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), { | ||
@@ -2028,6 +2088,7 @@ onNone: () => undefined, | ||
const type = encodedAST_(e.type, isBound); | ||
return type === e.type ? e : new Element(type, e.isOptional); | ||
return type === e.type ? e : new OptionalType(type, e.isOptional); | ||
}); | ||
const rest = changeMap(ast.rest, ast => encodedAST_(ast, isBound)); | ||
return elements === ast.elements && rest === ast.rest ? ast : new TupleType(elements, rest, ast.isReadonly, createJSONIdentifierAnnotation(ast)); | ||
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)); | ||
} | ||
@@ -2237,3 +2298,3 @@ case "TypeLiteral": | ||
} | ||
throw new Error(errors_.getErrorMessage("keyof", `unsupported schema (${ast})`)); | ||
throw new Error(errors_.getASTUnsupportedSchema(ast)); | ||
}; | ||
@@ -2269,23 +2330,8 @@ /** @internal */ | ||
} | ||
throw new Error(`rename: cannot rename (${ast})`); | ||
throw new Error(errors_.getASTUnsupportedRenameSchema(ast)); | ||
}; | ||
const formatKeyword = (ast, verbose = false) => Option.getOrElse(getExpected(ast, verbose), () => ast._tag); | ||
const getExpected = (ast, verbose) => { | ||
if (verbose) { | ||
const description = getDescriptionAnnotation(ast).pipe(Option.orElse(() => getTitleAnnotation(ast))); | ||
return Option.match(getIdentifierAnnotation(ast), { | ||
onNone: () => description, | ||
onSome: identifier => Option.match(description, { | ||
onNone: () => Option.some(identifier), | ||
onSome: description => Option.some(`${identifier} (${description})`) | ||
}) | ||
}); | ||
} else { | ||
return getIdentifierAnnotation(ast).pipe(Option.orElse(() => getTitleAnnotation(ast)), Option.orElse(() => getDescriptionAnnotation(ast))); | ||
} | ||
const formatKeyword = ast => Option.getOrElse(getExpected(ast), () => ast._tag); | ||
const getExpected = ast => { | ||
return getIdentifierAnnotation(ast).pipe(Option.orElse(() => getTitleAnnotation(ast)), Option.orElse(() => getDescriptionAnnotation(ast))); | ||
}; | ||
const getDuplicateIndexSignatureErrorMessage = name => `Duplicate index signature for type \`${name}\``; | ||
const getIndexSignatureParameterErrorMessage = "An index signature parameter type must be `string`, `symbol`, a template literal type or a refinement of the previous types"; | ||
const getRequiredElementFollowinAnOptionalElementErrorMessage = "A required element cannot follow an optional element. ts(1257)"; | ||
const getDuplicatePropertySignatureTransformationErrorMessage = name => `Duplicate property signature transformation ${util_.formatUnknown(name)}`; | ||
//# sourceMappingURL=AST.js.map |
@@ -31,3 +31,2 @@ /** | ||
const getHook = /*#__PURE__*/AST.getAnnotation(EquivalenceHookId); | ||
const getEquivalenceErrorMessage = (message, path) => errors_.getErrorMessageWithPath(`cannot build an Equivalence for ${message}`, path); | ||
const go = (ast, path) => { | ||
@@ -47,3 +46,3 @@ const hook = getHook(ast); | ||
case "NeverKeyword": | ||
throw new Error(getEquivalenceErrorMessage("`never`", path)); | ||
throw new Error(errors_.getEquivalenceUnsupportedErrorMessage(ast, path)); | ||
case "Transformation": | ||
@@ -77,3 +76,3 @@ return go(ast.to, path); | ||
const elements = ast.elements.map((element, i) => go(element.type, path.concat(i))); | ||
const rest = ast.rest.map(ast => go(ast, path)); | ||
const rest = ast.rest.map(annotatedAST => go(annotatedAST.type, path)); | ||
return Equivalence.make((a, b) => { | ||
@@ -80,0 +79,0 @@ const len = a.length; |
@@ -39,4 +39,2 @@ /** | ||
* @since 0.67.0 | ||
* | ||
* Serializable represents an object that has self-contained Schema(s) | ||
*/ | ||
@@ -43,0 +41,0 @@ export * as Serializable from "./Serializable.js"; |
@@ -0,14 +1,87 @@ | ||
import * as array_ from "effect/Array"; | ||
import * as util_ from "./util.js"; | ||
const getErrorMessage = (reason, details, path, ast) => { | ||
let out = reason; | ||
if (path && array_.isNonEmptyReadonlyArray(path)) { | ||
out += `\nat path: ${util_.formatPath(path)}`; | ||
} | ||
if (details !== undefined) { | ||
out += `\ndetails: ${details}`; | ||
} | ||
if (ast) { | ||
out += `\nschema (${ast._tag}): ${ast}`; | ||
} | ||
return out; | ||
}; | ||
// --------------------------------------------- | ||
// generic | ||
// --------------------------------------------- | ||
/** @internal */ | ||
export const getDuplicatePropertySignatureErrorMessage = name => `Duplicate property signature ${util_.formatUnknown(name)}`; | ||
export const getInvalidArgumentErrorMessage = details => getErrorMessage("Invalid Argument", details); | ||
const getUnsupportedSchemaErrorMessage = (details, path, ast) => getErrorMessage("Unsupported schema", details, path, ast); | ||
const getMissingAnnotationErrorMessage = (details, path, ast) => getErrorMessage("Missing annotation", details, path, ast); | ||
// --------------------------------------------- | ||
// Arbitrary | ||
// --------------------------------------------- | ||
/** @internal */ | ||
export const getErrorMessage = (api, message) => `${api}: ${message}`; | ||
export const getArbitraryUnsupportedErrorMessage = (path, ast) => getUnsupportedSchemaErrorMessage("Cannot build an Arbitrary for this schema", path, ast); | ||
/** @internal */ | ||
export const getErrorMessageWithPath = (message, path) => { | ||
let out = message; | ||
if (path.length > 0) { | ||
out += ` (path [${path.map(util_.formatPropertyKey).join(", ")}])`; | ||
} | ||
return out; | ||
}; | ||
export const getArbitraryMissingAnnotationErrorMessage = (path, ast) => getMissingAnnotationErrorMessage(`Generating an Arbitrary for this schema requires an "arbitrary" annotation`, path, ast); | ||
/** @internal */ | ||
export const getArbitraryEmptyEnumErrorMessage = path => getErrorMessage("Empty Enums schema", "Generating an Arbitrary for this schema requires at least one enum", path); | ||
// --------------------------------------------- | ||
// Equivalence | ||
// --------------------------------------------- | ||
/** @internal */ | ||
export const getEquivalenceUnsupportedErrorMessage = (ast, path) => getUnsupportedSchemaErrorMessage("Cannot build an Equivalence", path, ast); | ||
// --------------------------------------------- | ||
// JSON Schema | ||
// --------------------------------------------- | ||
/** @internal */ | ||
export const getJSONSchemaMissingAnnotationErrorMessage = (path, ast) => getMissingAnnotationErrorMessage(`Generating a JSON Schema for this schema requires a "jsonSchema" annotation`, path, ast); | ||
/** @internal */ | ||
export const getJSONSchemaMissingIdentifierAnnotationErrorMessage = (path, ast) => getMissingAnnotationErrorMessage(`Generating a JSON Schema for this schema requires an "identifier" annotation`, path, ast); | ||
/** @internal */ | ||
export const getJSONSchemaUnsupportedParameterErrorMessage = (path, parameter) => getErrorMessage("Unsupported index signature parameter", undefined, path, parameter); | ||
/** @internal */ | ||
export const getJSONSchemaUnsupportedPostRestElementsErrorMessage = path => getErrorMessage("Generating a JSON Schema for post-rest elements is not currently supported. You're welcome to contribute by submitting a Pull Request", undefined, path); | ||
/** @internal */ | ||
export const getJSONSchemaUnsupportedKeyErrorMessage = (key, path) => getErrorMessage("Unsupported key", `Cannot encode ${util_.formatPropertyKey(key)} key to JSON Schema`, path); | ||
// --------------------------------------------- | ||
// Pretty | ||
// --------------------------------------------- | ||
/** @internal */ | ||
export const getPrettyMissingAnnotationErrorMessage = (path, ast) => getMissingAnnotationErrorMessage(`Generating a Pretty for this schema requires a "pretty" annotation`, path, ast); | ||
/** @internal */ | ||
export const getPrettyNeverErrorMessage = "Cannot pretty print a `never` value"; | ||
/** @internal */ | ||
export const getPrettyNoMatchingSchemaErrorMessage = (actual, path, ast) => getErrorMessage("Unexpected Error", `Cannot find a matching schema for ${util_.formatUnknown(actual)}`, path, ast); | ||
// --------------------------------------------- | ||
// Schema | ||
// --------------------------------------------- | ||
/** @internal */ | ||
export const getSchemaExtendErrorMessage = (x, y, path) => getErrorMessage("Unsupported schema or overlapping types", `cannot extend ${x} with ${y}`, path); | ||
/** @internal */ | ||
export const getSchemaUnsupportedLiteralSpanErrorMessage = ast => getErrorMessage("Unsupported template literal span", undefined, undefined, ast); | ||
// --------------------------------------------- | ||
// AST | ||
// --------------------------------------------- | ||
/** @internal */ | ||
export const getASTUnsupportedSchema = ast => getUnsupportedSchemaErrorMessage(undefined, undefined, ast); | ||
/** @internal */ | ||
export const getASTUnsupportedKeySchema = ast => getErrorMessage("Unsupported key schema", undefined, undefined, ast); | ||
/** @internal */ | ||
export const getASTUnsupportedLiteral = literal => getErrorMessage("Unsupported literal", `literal value: ${util_.formatUnknown(literal)}`); | ||
/** @internal */ | ||
export const getASTDuplicateIndexSignatureErrorMessage = type => getErrorMessage("Duplicate index signature", `${type} index signature`); | ||
/** @internal */ | ||
export const getASTIndexSignatureParameterErrorMessage = /*#__PURE__*/getErrorMessage("Unsupported index signature parameter", "An index signature parameter type must be `string`, `symbol`, a template literal type or a refinement of the previous types"); | ||
/** @internal */ | ||
export const getASTRequiredElementFollowinAnOptionalElementErrorMessage = /*#__PURE__*/getErrorMessage("Invalid element", "A required element cannot follow an optional element. ts(1257)"); | ||
/** @internal */ | ||
export const getASTDuplicatePropertySignatureTransformationErrorMessage = key => getErrorMessage("Duplicate property signature transformation", `Duplicate key ${util_.formatUnknown(key)}`); | ||
/** @internal */ | ||
export const getASTUnsupportedRenameSchema = ast => getUnsupportedSchemaErrorMessage(undefined, undefined, ast); | ||
/** @internal */ | ||
export const getASTDuplicatePropertySignatureErrorMessage = key => getErrorMessage("Duplicate property signature", `Duplicate key ${util_.formatUnknown(key)}`); | ||
//# sourceMappingURL=errors.js.map |
@@ -35,2 +35,4 @@ /** @internal */ | ||
export const ItemsCountTypeId = /*#__PURE__*/Symbol.for("@effect/schema/TypeId/ItemsCount"); | ||
/** @internal */ | ||
export const ParseJsonTypeId = /*#__PURE__*/Symbol.for("@effect/schema/TypeId/ParseJson"); | ||
//# sourceMappingURL=filters.js.map |
@@ -0,1 +1,2 @@ | ||
import * as array_ from "effect/Array"; | ||
import * as Predicate from "effect/Predicate"; | ||
@@ -37,3 +38,3 @@ /** @internal */ | ||
return String(u) + "n"; | ||
} else if (!Array.isArray(u) && Predicate.hasProperty(u, "toString") && Predicate.isFunction(u["toString"]) && u["toString"] !== Object.prototype.toString) { | ||
} else if (!array_.isArray(u) && Predicate.hasProperty(u, "toString") && Predicate.isFunction(u["toString"]) && u["toString"] !== Object.prototype.toString) { | ||
return u["toString"](); | ||
@@ -43,3 +44,3 @@ } | ||
JSON.stringify(u); | ||
if (Array.isArray(u)) { | ||
if (array_.isArray(u)) { | ||
return `[${u.map(formatUnknown).join(",")}]`; | ||
@@ -55,2 +56,10 @@ } else { | ||
export const formatPropertyKey = name => typeof name === "string" ? JSON.stringify(name) : String(name); | ||
/** @internal */ | ||
export const isNonEmpty = x => Array.isArray(x); | ||
/** @internal */ | ||
export const isSingle = x => !Array.isArray(x); | ||
/** @internal */ | ||
export const formatPathKey = key => `[${formatPropertyKey(key)}]`; | ||
/** @internal */ | ||
export const formatPath = path => isNonEmpty(path) ? path.map(formatPathKey).join("") : formatPathKey(path); | ||
//# sourceMappingURL=util.js.map |
@@ -9,2 +9,3 @@ /** | ||
import * as errors_ from "./internal/errors.js"; | ||
import * as filters_ from "./internal/filters.js"; | ||
/** | ||
@@ -68,4 +69,2 @@ * @category encoding | ||
}; | ||
const getMissingAnnotationErrorMessage = (name, path) => errors_.getErrorMessageWithPath(`cannot build a JSON Schema for ${name} without a JSON Schema annotation`, path); | ||
const getUnsupportedIndexSignatureParameterErrorMessage = (parameter, path) => errors_.getErrorMessageWithPath(`unsupported index signature parameter (${parameter})`, path); | ||
/** @internal */ | ||
@@ -91,2 +90,9 @@ export const DEFINITION_PREFIX = "#/$defs/"; | ||
}; | ||
const isParseJsonTransformation = ast => ast.annotations[AST.TypeAnnotationId] === filters_.ParseJsonTypeId; | ||
function merge(a, b) { | ||
return { | ||
...a, | ||
...b | ||
}; | ||
} | ||
const go = (ast, $defs, handleIdentifier, path) => { | ||
@@ -98,12 +104,5 @@ const hook = AST.getJSONSchemaAnnotation(ast); | ||
try { | ||
return { | ||
...go(ast.from, $defs, true, path), | ||
...getJsonSchemaAnnotations(ast), | ||
...handler | ||
}; | ||
return merge(merge(go(ast.from, $defs, true, path), getJsonSchemaAnnotations(ast)), handler); | ||
} catch (e) { | ||
return { | ||
...getJsonSchemaAnnotations(ast), | ||
...handler | ||
}; | ||
return merge(getJsonSchemaAnnotations(ast), handler); | ||
} | ||
@@ -133,3 +132,3 @@ } | ||
case "Declaration": | ||
throw new Error(getMissingAnnotationErrorMessage("a declaration", path)); | ||
throw new Error(errors_.getJSONSchemaMissingAnnotationErrorMessage(path, ast)); | ||
case "Literal": | ||
@@ -139,71 +138,55 @@ { | ||
if (literal === null) { | ||
return { | ||
const: null, | ||
...getJsonSchemaAnnotations(ast) | ||
}; | ||
} else if (Predicate.isString(literal)) { | ||
return { | ||
const: literal, | ||
...getJsonSchemaAnnotations(ast) | ||
}; | ||
} else if (Predicate.isNumber(literal)) { | ||
return { | ||
const: literal, | ||
...getJsonSchemaAnnotations(ast) | ||
}; | ||
} else if (Predicate.isBoolean(literal)) { | ||
return { | ||
const: literal, | ||
...getJsonSchemaAnnotations(ast) | ||
}; | ||
return merge({ | ||
const: null | ||
}, getJsonSchemaAnnotations(ast)); | ||
} else if (Predicate.isString(literal) || Predicate.isNumber(literal) || Predicate.isBoolean(literal)) { | ||
return merge({ | ||
const: literal | ||
}, getJsonSchemaAnnotations(ast)); | ||
} | ||
throw new Error(getMissingAnnotationErrorMessage("a bigint literal", path)); | ||
throw new Error(errors_.getJSONSchemaMissingAnnotationErrorMessage(path, ast)); | ||
} | ||
case "UniqueSymbol": | ||
throw new Error(getMissingAnnotationErrorMessage("a unique symbol", path)); | ||
throw new Error(errors_.getJSONSchemaMissingAnnotationErrorMessage(path, ast)); | ||
case "UndefinedKeyword": | ||
throw new Error(getMissingAnnotationErrorMessage("`undefined`", path)); | ||
throw new Error(errors_.getJSONSchemaMissingAnnotationErrorMessage(path, ast)); | ||
case "VoidKeyword": | ||
throw new Error(getMissingAnnotationErrorMessage("`void`", path)); | ||
throw new Error(errors_.getJSONSchemaMissingAnnotationErrorMessage(path, ast)); | ||
case "NeverKeyword": | ||
throw new Error(getMissingAnnotationErrorMessage("`never`", path)); | ||
throw new Error(errors_.getJSONSchemaMissingAnnotationErrorMessage(path, ast)); | ||
case "UnknownKeyword": | ||
return { | ||
...unknownJsonSchema, | ||
...getJsonSchemaAnnotations(ast) | ||
}; | ||
return merge(unknownJsonSchema, getJsonSchemaAnnotations(ast)); | ||
case "AnyKeyword": | ||
return { | ||
...anyJsonSchema, | ||
...getJsonSchemaAnnotations(ast) | ||
}; | ||
return merge(anyJsonSchema, getJsonSchemaAnnotations(ast)); | ||
case "ObjectKeyword": | ||
return { | ||
...objectJsonSchema, | ||
...getJsonSchemaAnnotations(ast) | ||
}; | ||
return merge(objectJsonSchema, getJsonSchemaAnnotations(ast)); | ||
case "StringKeyword": | ||
return { | ||
type: "string", | ||
...getJsonSchemaAnnotations(ast) | ||
}; | ||
{ | ||
const out = { | ||
type: "string" | ||
}; | ||
return ast === AST.stringKeyword ? out : merge(out, getJsonSchemaAnnotations(ast)); | ||
} | ||
case "NumberKeyword": | ||
return { | ||
type: "number", | ||
...getJsonSchemaAnnotations(ast) | ||
}; | ||
{ | ||
const out = { | ||
type: "number" | ||
}; | ||
return ast === AST.numberKeyword ? out : merge(out, getJsonSchemaAnnotations(ast)); | ||
} | ||
case "BooleanKeyword": | ||
return { | ||
type: "boolean", | ||
...getJsonSchemaAnnotations(ast) | ||
}; | ||
{ | ||
const out = { | ||
type: "boolean" | ||
}; | ||
return ast === AST.booleanKeyword ? out : merge(out, getJsonSchemaAnnotations(ast)); | ||
} | ||
case "BigIntKeyword": | ||
throw new Error(getMissingAnnotationErrorMessage("`bigint`", path)); | ||
throw new Error(errors_.getJSONSchemaMissingAnnotationErrorMessage(path, ast)); | ||
case "SymbolKeyword": | ||
throw new Error(getMissingAnnotationErrorMessage("`symbol`", path)); | ||
throw new Error(errors_.getJSONSchemaMissingAnnotationErrorMessage(path, ast)); | ||
case "TupleType": | ||
{ | ||
const len = ast.elements.length; | ||
const elements = ast.elements.map((e, i) => go(e.type, $defs, true, path.concat(i))); | ||
const rest = ast.rest.map(ast => go(ast, $defs, true, path)); | ||
const elements = ast.elements.map((e, i) => merge(go(e.type, $defs, true, path.concat(i)), getJsonSchemaAnnotations(e))); | ||
const rest = ast.rest.map(annotatedAST => merge(go(annotatedAST.type, $defs, true, path), getJsonSchemaAnnotations(annotatedAST))); | ||
const output = { | ||
@@ -215,2 +198,3 @@ type: "array" | ||
// --------------------------------------------- | ||
const len = ast.elements.length; | ||
if (len > 0) { | ||
@@ -223,8 +207,10 @@ output.minItems = len - ast.elements.filter(element => element.isOptional).length; | ||
// --------------------------------------------- | ||
if (rest.length > 0) { | ||
const restLength = rest.length; | ||
if (restLength > 0) { | ||
const head = rest[0]; | ||
if (len > 0) { | ||
const isHomogeneous = restLength === 1 && ast.elements.every(e => e.type === ast.rest[0].type); | ||
if (isHomogeneous) { | ||
output.items = head; | ||
} else { | ||
output.additionalItems = head; | ||
} else { | ||
output.items = head; | ||
} | ||
@@ -234,4 +220,4 @@ // --------------------------------------------- | ||
// --------------------------------------------- | ||
if (rest.length > 1) { | ||
throw new Error(errors_.getErrorMessageWithPath("Generating a JSON Schema for post-rest elements is not currently supported. You're welcome to contribute by submitting a Pull Request.", path)); | ||
if (restLength > 1) { | ||
throw new Error(errors_.getJSONSchemaUnsupportedPostRestElementsErrorMessage(path)); | ||
} | ||
@@ -245,6 +231,3 @@ } else { | ||
} | ||
return { | ||
...output, | ||
...getJsonSchemaAnnotations(ast) | ||
}; | ||
return merge(output, getJsonSchemaAnnotations(ast)); | ||
} | ||
@@ -254,9 +237,6 @@ case "TypeLiteral": | ||
if (ast.propertySignatures.length === 0 && ast.indexSignatures.length === 0) { | ||
return { | ||
...empty(), | ||
...getJsonSchemaAnnotations(ast) | ||
}; | ||
return merge(empty(), getJsonSchemaAnnotations(ast)); | ||
} | ||
let additionalProperties = undefined; | ||
let patternProperties = undefined; | ||
let propertyNames = undefined; | ||
for (const is of ast.indexSignatures) { | ||
@@ -267,3 +247,3 @@ const parameter = is.parameter; | ||
{ | ||
additionalProperties = go(is.type, $defs, true, path); | ||
patternProperties = go(is.type, $defs, true, path); | ||
break; | ||
@@ -273,4 +253,6 @@ } | ||
{ | ||
patternProperties = { | ||
[AST.getTemplateLiteralRegExp(parameter).source]: go(is.type, $defs, true, path) | ||
patternProperties = go(is.type, $defs, true, path); | ||
propertyNames = { | ||
type: "string", | ||
pattern: AST.getTemplateLiteralRegExp(parameter).source | ||
}; | ||
@@ -281,20 +263,12 @@ break; | ||
{ | ||
const hook = AST.getJSONSchemaAnnotation(parameter); | ||
if (Option.isSome(hook) && "pattern" in hook.value && Predicate.isString(hook.value.pattern)) { | ||
patternProperties = { | ||
[hook.value.pattern]: go(is.type, $defs, true, path) | ||
}; | ||
break; | ||
} | ||
throw new Error(getUnsupportedIndexSignatureParameterErrorMessage(parameter, path)); | ||
patternProperties = go(is.type, $defs, true, path); | ||
propertyNames = go(parameter, $defs, true, path); | ||
break; | ||
} | ||
case "SymbolKeyword": | ||
throw new Error(getUnsupportedIndexSignatureParameterErrorMessage(parameter, path)); | ||
throw new Error(errors_.getJSONSchemaUnsupportedParameterErrorMessage(path, parameter)); | ||
} | ||
} | ||
const propertySignatures = ast.propertySignatures.map(ps => { | ||
return { | ||
...go(pruneUndefinedKeyword(ps), $defs, true, path.concat(ps.name)), | ||
...getJsonSchemaAnnotations(ps) | ||
}; | ||
return merge(go(pruneUndefinedKeyword(ps), $defs, true, path.concat(ps.name)), getJsonSchemaAnnotations(ps)); | ||
}); | ||
@@ -321,3 +295,3 @@ const output = { | ||
} else { | ||
throw new Error(errors_.getErrorMessageWithPath(`cannot encode ${String(name)} key to JSON Schema`, path)); | ||
throw new Error(errors_.getJSONSchemaUnsupportedKeyErrorMessage(name, path)); | ||
} | ||
@@ -328,12 +302,12 @@ } | ||
// --------------------------------------------- | ||
if (additionalProperties !== undefined) { | ||
output.additionalProperties = additionalProperties; | ||
} | ||
if (patternProperties !== undefined) { | ||
output.patternProperties = patternProperties; | ||
delete output.additionalProperties; | ||
output.patternProperties = { | ||
"": patternProperties | ||
}; | ||
} | ||
return { | ||
...output, | ||
...getJsonSchemaAnnotations(ast) | ||
}; | ||
if (propertyNames !== undefined) { | ||
output.propertyNames = propertyNames; | ||
} | ||
return merge(output, getJsonSchemaAnnotations(ast)); | ||
} | ||
@@ -358,11 +332,9 @@ case "Union": | ||
if (enums.length === 1) { | ||
return { | ||
const: enums[0], | ||
...getJsonSchemaAnnotations(ast) | ||
}; | ||
return merge({ | ||
const: enums[0] | ||
}, getJsonSchemaAnnotations(ast)); | ||
} else { | ||
return { | ||
enum: enums, | ||
...getJsonSchemaAnnotations(ast) | ||
}; | ||
return merge({ | ||
enum: enums | ||
}, getJsonSchemaAnnotations(ast)); | ||
} | ||
@@ -379,6 +351,5 @@ } else { | ||
} | ||
return { | ||
anyOf, | ||
...getJsonSchemaAnnotations(ast) | ||
}; | ||
return merge({ | ||
anyOf | ||
}, getJsonSchemaAnnotations(ast)); | ||
} | ||
@@ -388,3 +359,3 @@ } | ||
{ | ||
return { | ||
return merge({ | ||
$comment: "/schemas/enums", | ||
@@ -394,9 +365,8 @@ oneOf: ast.enums.map(e => ({ | ||
const: e[1] | ||
})), | ||
...getJsonSchemaAnnotations(ast) | ||
}; | ||
})) | ||
}, getJsonSchemaAnnotations(ast)); | ||
} | ||
case "Refinement": | ||
{ | ||
throw new Error(errors_.getErrorMessageWithPath("cannot build a JSON Schema for a refinement without a JSON Schema annotation", path)); | ||
throw new Error(errors_.getJSONSchemaMissingAnnotationErrorMessage(path, ast)); | ||
} | ||
@@ -406,8 +376,7 @@ case "TemplateLiteral": | ||
const regex = AST.getTemplateLiteralRegExp(ast); | ||
return { | ||
return merge({ | ||
type: "string", | ||
description: "a template literal", | ||
pattern: regex.source, | ||
...getJsonSchemaAnnotations(ast) | ||
}; | ||
pattern: regex.source | ||
}, getJsonSchemaAnnotations(ast)); | ||
} | ||
@@ -418,3 +387,3 @@ case "Suspend": | ||
if (Option.isNone(identifier)) { | ||
throw new Error(errors_.getErrorMessageWithPath("Generating a JSON Schema for suspended schemas requires an identifier annotation", path)); | ||
throw new Error(errors_.getJSONSchemaMissingIdentifierAnnotationErrorMessage(path, ast)); | ||
} | ||
@@ -424,5 +393,12 @@ return go(ast.f(), $defs, true, path); | ||
case "Transformation": | ||
return go(ast.from, $defs, true, path); | ||
{ | ||
// Properly handle S.parseJson transformations by focusing on | ||
// the 'to' side of the AST. This approach prevents the generation of useless schemas | ||
// derived from the 'from' side (type: string), ensuring the output matches the intended | ||
// complex schema type. | ||
const next = isParseJsonTransformation(ast.from) ? ast.to : ast.from; | ||
return go(next, $defs, true, path); | ||
} | ||
} | ||
}; | ||
//# sourceMappingURL=JSONSchema.js.map |
/** | ||
* @since 0.67.0 | ||
*/ | ||
import * as Arr from "effect/Array"; | ||
import * as array_ from "effect/Array"; | ||
import { TaggedError } from "effect/Data"; | ||
@@ -17,23 +17,21 @@ import * as Effect from "effect/Effect"; | ||
/** | ||
* Error that occurs when a declaration has an error. | ||
* | ||
* @category model | ||
* @since 0.67.0 | ||
* @since 0.68.0 | ||
*/ | ||
export class Declaration { | ||
ast; | ||
export class Pointer { | ||
path; | ||
actual; | ||
error; | ||
issue; | ||
/** | ||
* @since 0.67.0 | ||
* @since 0.68.0 | ||
*/ | ||
_tag = "Declaration"; | ||
constructor(ast, actual, error) { | ||
this.ast = ast; | ||
_tag = "Pointer"; | ||
constructor(path, actual, issue) { | ||
this.path = path; | ||
this.actual = actual; | ||
this.error = error; | ||
this.issue = issue; | ||
} | ||
} | ||
/** | ||
* Error that occurs when a refinement has an error. | ||
* Error that occurs when an unexpected key or index is present. | ||
* | ||
@@ -43,20 +41,20 @@ * @category model | ||
*/ | ||
export class Refinement { | ||
ast; | ||
export class Unexpected { | ||
actual; | ||
kind; | ||
error; | ||
message; | ||
/** | ||
* @since 0.67.0 | ||
*/ | ||
_tag = "Refinement"; | ||
constructor(ast, actual, kind, error) { | ||
this.ast = ast; | ||
_tag = "Unexpected"; | ||
constructor(actual, | ||
/** | ||
* @since 0.68.0 | ||
*/ | ||
message) { | ||
this.actual = actual; | ||
this.kind = kind; | ||
this.error = error; | ||
this.message = message; | ||
} | ||
} | ||
/** | ||
* Error that occurs when an array or tuple has an error. | ||
* Error that occurs when a required key or index is missing. | ||
* | ||
@@ -66,55 +64,45 @@ * @category model | ||
*/ | ||
export class TupleType { | ||
export class Missing { | ||
ast; | ||
actual; | ||
errors; | ||
output; | ||
message; | ||
/** | ||
* @since 0.67.0 | ||
*/ | ||
_tag = "TupleType"; | ||
constructor(ast, actual, errors, output = []) { | ||
this.ast = ast; | ||
this.actual = actual; | ||
this.errors = errors; | ||
this.output = output; | ||
} | ||
} | ||
/** | ||
* The `Index` error indicates that there was an error at a specific index in an array or tuple. | ||
* | ||
* @category model | ||
* @since 0.67.0 | ||
*/ | ||
export class Index { | ||
index; | ||
error; | ||
_tag = "Missing"; | ||
/** | ||
* @since 0.67.0 | ||
* @since 0.68.0 | ||
*/ | ||
_tag = "Index"; | ||
constructor(index, error) { | ||
this.index = index; | ||
this.error = error; | ||
actual = undefined; | ||
constructor( | ||
/** | ||
* @since 0.68.0 | ||
*/ | ||
ast, | ||
/** | ||
* @since 0.68.0 | ||
*/ | ||
message) { | ||
this.ast = ast; | ||
this.message = message; | ||
} | ||
} | ||
/** | ||
* Error that occurs when a type literal or record has an error. | ||
* Error that contains multiple issues. | ||
* | ||
* @category model | ||
* @since 0.67.0 | ||
* @since 0.68.0 | ||
*/ | ||
export class TypeLiteral { | ||
export class Composite { | ||
ast; | ||
actual; | ||
errors; | ||
issues; | ||
output; | ||
/** | ||
* @since 0.67.0 | ||
* @since 0.68.0 | ||
*/ | ||
_tag = "TypeLiteral"; | ||
constructor(ast, actual, errors, output = {}) { | ||
_tag = "Composite"; | ||
constructor(ast, actual, issues, output) { | ||
this.ast = ast; | ||
this.actual = actual; | ||
this.errors = errors; | ||
this.issues = issues; | ||
this.output = output; | ||
@@ -124,21 +112,10 @@ } | ||
/** | ||
* The `Key` variant of the `ParseIssue` type represents an error that occurs when a key in a type literal or record is invalid. | ||
* Returns `true` if the value is a `Composite`. | ||
* | ||
* @category model | ||
* @since 0.67.0 | ||
* @category guards | ||
* @since 0.68.0 | ||
*/ | ||
export class Key { | ||
key; | ||
error; | ||
/** | ||
* @since 0.67.0 | ||
*/ | ||
_tag = "Key"; | ||
constructor(key, error) { | ||
this.key = key; | ||
this.error = error; | ||
} | ||
} | ||
export const isComposite = u => Predicate.hasProperty(u, "_tag"); | ||
/** | ||
* Error that occurs when an unexpected key or index is present. | ||
* Error that occurs when a refinement has an error. | ||
* | ||
@@ -148,10 +125,16 @@ * @category model | ||
*/ | ||
export class Unexpected { | ||
export class Refinement { | ||
ast; | ||
actual; | ||
kind; | ||
issue; | ||
/** | ||
* @since 0.67.0 | ||
*/ | ||
_tag = "Unexpected"; | ||
constructor(ast) { | ||
_tag = "Refinement"; | ||
constructor(ast, actual, kind, issue) { | ||
this.ast = ast; | ||
this.actual = actual; | ||
this.kind = kind; | ||
this.issue = issue; | ||
} | ||
@@ -169,3 +152,3 @@ } | ||
kind; | ||
error; | ||
issue; | ||
/** | ||
@@ -175,7 +158,7 @@ * @since 0.67.0 | ||
_tag = "Transformation"; | ||
constructor(ast, actual, kind, error) { | ||
constructor(ast, actual, kind, issue) { | ||
this.ast = ast; | ||
this.actual = actual; | ||
this.kind = kind; | ||
this.error = error; | ||
this.issue = issue; | ||
} | ||
@@ -193,2 +176,3 @@ } | ||
actual; | ||
message; | ||
/** | ||
@@ -198,10 +182,6 @@ * @since 0.67.0 | ||
_tag = "Type"; | ||
/** | ||
* @since 0.67.0 | ||
*/ | ||
message; | ||
constructor(ast, actual, message) { | ||
this.ast = ast; | ||
this.actual = actual; | ||
this.message = Option.fromNullable(message); | ||
this.message = message; | ||
} | ||
@@ -218,2 +198,3 @@ } | ||
actual; | ||
message; | ||
/** | ||
@@ -223,71 +204,25 @@ * @since 0.67.0 | ||
_tag = "Forbidden"; | ||
/** | ||
* @since 0.67.0 | ||
*/ | ||
message; | ||
constructor(ast, actual, message) { | ||
this.ast = ast; | ||
this.actual = actual; | ||
this.message = Option.fromNullable(message); | ||
this.message = message; | ||
} | ||
} | ||
/** | ||
* Error that occurs when a required key or index is missing. | ||
* | ||
* @category model | ||
* @since 0.67.0 | ||
* @category type id | ||
* @since 0.68.0 | ||
*/ | ||
export class Missing { | ||
/** | ||
* @since 0.67.0 | ||
*/ | ||
_tag = "Missing"; | ||
} | ||
export const ParseErrorTypeId = /*#__PURE__*/Symbol.for("@effect/schema/ParseErrorTypeId"); | ||
/** | ||
* @category constructors | ||
* @since 0.67.0 | ||
* @since 0.68.0 | ||
*/ | ||
export const missing = /*#__PURE__*/new Missing(); | ||
export const isParseError = u => Predicate.hasProperty(u, ParseErrorTypeId); | ||
/** | ||
* Error that occurs when a member in a union has an error. | ||
* | ||
* @category model | ||
* @since 0.67.0 | ||
*/ | ||
export class Member { | ||
ast; | ||
error; | ||
export class ParseError extends TaggedError("ParseError") { | ||
/** | ||
* @since 0.67.0 | ||
* @since 0.68.0 | ||
*/ | ||
_tag = "Member"; | ||
constructor(ast, error) { | ||
this.ast = ast; | ||
this.error = error; | ||
} | ||
} | ||
/** | ||
* Error that occurs when a union has an error. | ||
* | ||
* @category model | ||
* @since 0.67.0 | ||
*/ | ||
export class Union { | ||
ast; | ||
actual; | ||
errors; | ||
/** | ||
* @since 0.67.0 | ||
*/ | ||
_tag = "Union"; | ||
constructor(ast, actual, errors) { | ||
this.ast = ast; | ||
this.actual = actual; | ||
this.errors = errors; | ||
} | ||
} | ||
/** | ||
* @since 0.67.0 | ||
*/ | ||
export class ParseError extends TaggedError("ParseError") { | ||
[ParseErrorTypeId] = ParseErrorTypeId; | ||
get message() { | ||
@@ -300,3 +235,3 @@ return this.toString(); | ||
toString() { | ||
return TreeFormatter.formatIssueSync(this.error); | ||
return TreeFormatter.formatIssueSync(this.issue); | ||
} | ||
@@ -324,3 +259,3 @@ /** | ||
export const parseError = issue => new ParseError({ | ||
error: issue | ||
issue | ||
}); | ||
@@ -430,3 +365,3 @@ /** | ||
/** @internal */ | ||
export const mergeParseOptions = (options, overrideOptions) => { | ||
export const mergeInternalOptions = (options, overrideOptions) => { | ||
if (overrideOptions === undefined || Predicate.isNumber(overrideOptions)) { | ||
@@ -438,16 +373,14 @@ return options; | ||
} | ||
const out = {}; | ||
out.errors = overrideOptions.errors ?? options.errors; | ||
out.onExcessProperty = overrideOptions.onExcessProperty ?? options.onExcessProperty; | ||
return out; | ||
return { | ||
...options, | ||
...overrideOptions | ||
}; | ||
}; | ||
const getEither = (ast, isDecoding, options) => { | ||
const parser = goMemo(ast, isDecoding); | ||
return (u, overrideOptions) => parser(u, mergeParseOptions(options, overrideOptions)); | ||
return (u, overrideOptions) => parser(u, mergeInternalOptions(options, overrideOptions)); | ||
}; | ||
const getSync = (ast, isDecoding, options) => { | ||
const parser = getEither(ast, isDecoding, options); | ||
return (input, overrideOptions) => Either.getOrThrowWith(parser(input, overrideOptions), issue => new Error(TreeFormatter.formatIssueSync(issue), { | ||
cause: issue | ||
})); | ||
return (input, overrideOptions) => Either.getOrThrowWith(parser(input, overrideOptions), parseError); | ||
}; | ||
@@ -461,3 +394,3 @@ const getOption = (ast, isDecoding, options) => { | ||
return (input, overrideOptions) => parser(input, { | ||
...mergeParseOptions(options, overrideOptions), | ||
...mergeInternalOptions(options, overrideOptions), | ||
isEffectAllowed: true | ||
@@ -467,2 +400,3 @@ }); | ||
/** | ||
* @throws `ParseError` | ||
* @category decoding | ||
@@ -496,2 +430,3 @@ * @since 0.67.0 | ||
/** | ||
* @throws `ParseError` | ||
* @category encoding | ||
@@ -550,2 +485,3 @@ * @since 0.67.0 | ||
/** | ||
* @throws `ParseError` | ||
* @category validation | ||
@@ -588,3 +524,3 @@ * @since 0.67.0 | ||
exact: true, | ||
...mergeParseOptions(options, overrideOptions) | ||
...mergeInternalOptions(options, overrideOptions) | ||
})); | ||
@@ -595,2 +531,3 @@ }; | ||
* | ||
* @throws `ParseError` | ||
* @category validation | ||
@@ -604,8 +541,6 @@ * @since 0.67.0 | ||
exact: true, | ||
...mergeParseOptions(options, overrideOptions) | ||
...mergeInternalOptions(options, overrideOptions) | ||
}); | ||
if (Either.isLeft(result)) { | ||
throw new Error(TreeFormatter.formatIssueSync(result.left), { | ||
cause: result.left | ||
}); | ||
throw parseError(result.left); | ||
} | ||
@@ -647,3 +582,5 @@ }; | ||
} | ||
const parser = go(ast, isDecoding); | ||
const raw = go(ast, isDecoding); | ||
const parseOptionsAnnotation = AST.getParseOptionsAnnotation(ast); | ||
const parser = Option.isSome(parseOptionsAnnotation) ? (i, options) => raw(i, mergeInternalOptions(options, parseOptionsAnnotation.value)) : raw; | ||
memoMap.set(ast, parser); | ||
@@ -680,3 +617,3 @@ return parser; | ||
const parse = isDecoding ? ast.decodeUnknown(...ast.typeParameters) : ast.encodeUnknown(...ast.typeParameters); | ||
return (i, options) => handleForbidden(mapError(parse(i, options ?? AST.defaultParseOption, ast), e => new Declaration(ast, i, e)), ast, i, options); | ||
return (i, options) => handleForbidden(parse(i, options ?? AST.defaultParseOption, ast), ast, i, options); | ||
} | ||
@@ -718,12 +655,13 @@ case "Literal": | ||
const elements = ast.elements.map(e => goMemo(e.type, isDecoding)); | ||
const rest = ast.rest.map(ast => goMemo(ast, isDecoding)); | ||
let requiredLen = ast.elements.filter(e => !e.isOptional).length; | ||
const rest = ast.rest.map(annotatedAST => goMemo(annotatedAST.type, isDecoding)); | ||
let requiredTypes = ast.elements.filter(e => !e.isOptional); | ||
if (ast.rest.length > 0) { | ||
requiredLen += ast.rest.length - 1; | ||
requiredTypes = requiredTypes.concat(ast.rest.slice(1)); | ||
} | ||
const expectedAST = AST.Union.make(ast.elements.map((_, i) => new AST.Literal(i))); | ||
const requiredLen = requiredTypes.length; | ||
const expectedIndexes = ast.elements.length > 0 ? ast.elements.map((_, i) => i).join(" | ") : "never"; | ||
const concurrency = getConcurrency(ast); | ||
const batching = getBatching(ast); | ||
return (input, options) => { | ||
if (!Arr.isArray(input)) { | ||
if (!array_.isArray(input)) { | ||
return Either.left(new Type(ast, input)); | ||
@@ -734,2 +672,3 @@ } | ||
let stepKey = 0; | ||
const output = []; | ||
// --------------------------------------------- | ||
@@ -740,3 +679,3 @@ // handle missing indexes | ||
for (let i = len; i <= requiredLen - 1; i++) { | ||
const e = new Index(i, missing); | ||
const e = new Pointer(i, input, new Missing(requiredTypes[i - len])); | ||
if (allErrors) { | ||
@@ -746,3 +685,3 @@ es.push([stepKey++, e]); | ||
} else { | ||
return Either.left(new TupleType(ast, input, [e])); | ||
return Either.left(new Composite(ast, input, e, output)); | ||
} | ||
@@ -755,3 +694,3 @@ } | ||
for (let i = ast.elements.length; i <= len - 1; i++) { | ||
const e = new Index(i, new Unexpected(expectedAST)); | ||
const e = new Pointer(i, input, new Unexpected(input[i], `is unexpected, expected: ${expectedIndexes}`)); | ||
if (allErrors) { | ||
@@ -761,7 +700,6 @@ es.push([stepKey++, e]); | ||
} else { | ||
return Either.left(new TupleType(ast, input, [e])); | ||
return Either.left(new Composite(ast, input, e, output)); | ||
} | ||
} | ||
} | ||
const output = []; | ||
let i = 0; | ||
@@ -785,3 +723,3 @@ let queue = undefined; | ||
// the input element is present but is not valid | ||
const e = new Index(i, eu.left); | ||
const e = new Pointer(i, input, eu.left); | ||
if (allErrors) { | ||
@@ -791,3 +729,3 @@ es.push([stepKey++, e]); | ||
} else { | ||
return Either.left(new TupleType(ast, input, [e], sortByIndex(output))); | ||
return Either.left(new Composite(ast, input, e, sortByIndex(output))); | ||
} | ||
@@ -808,3 +746,3 @@ } | ||
// the input element is present but is not valid | ||
const e = new Index(index, t.left); | ||
const e = new Pointer(index, input, t.left); | ||
if (allErrors) { | ||
@@ -814,3 +752,3 @@ es.push([nk, e]); | ||
} else { | ||
return Either.left(new TupleType(ast, input, [e], sortByIndex(output))); | ||
return Either.left(new Composite(ast, input, e, sortByIndex(output))); | ||
} | ||
@@ -827,3 +765,3 @@ } | ||
// --------------------------------------------- | ||
if (Arr.isNonEmptyReadonlyArray(rest)) { | ||
if (array_.isNonEmptyReadonlyArray(rest)) { | ||
const [head, ...tail] = rest; | ||
@@ -835,3 +773,3 @@ for (; i < len - tail.length; i++) { | ||
if (Either.isLeft(eu)) { | ||
const e = new Index(i, eu.left); | ||
const e = new Pointer(i, input, eu.left); | ||
if (allErrors) { | ||
@@ -841,3 +779,3 @@ es.push([stepKey++, e]); | ||
} else { | ||
return Either.left(new TupleType(ast, input, [e], sortByIndex(output))); | ||
return Either.left(new Composite(ast, input, e, sortByIndex(output))); | ||
} | ||
@@ -858,3 +796,3 @@ } else { | ||
if (Either.isLeft(t)) { | ||
const e = new Index(index, t.left); | ||
const e = new Pointer(index, input, t.left); | ||
if (allErrors) { | ||
@@ -864,3 +802,3 @@ es.push([nk, e]); | ||
} else { | ||
return Either.left(new TupleType(ast, input, [e], sortByIndex(output))); | ||
return Either.left(new Composite(ast, input, e, sortByIndex(output))); | ||
} | ||
@@ -887,3 +825,3 @@ } else { | ||
// the input element is present but is not valid | ||
const e = new Index(i, eu.left); | ||
const e = new Pointer(i, input, eu.left); | ||
if (allErrors) { | ||
@@ -893,3 +831,3 @@ es.push([stepKey++, e]); | ||
} else { | ||
return Either.left(new TupleType(ast, input, [e], sortByIndex(output))); | ||
return Either.left(new Composite(ast, input, e, sortByIndex(output))); | ||
} | ||
@@ -910,3 +848,3 @@ } | ||
// the input element is present but is not valid | ||
const e = new Index(index, t.left); | ||
const e = new Pointer(index, input, t.left); | ||
if (allErrors) { | ||
@@ -916,3 +854,3 @@ es.push([nk, e]); | ||
} else { | ||
return Either.left(new TupleType(ast, input, [e], sortByIndex(output))); | ||
return Either.left(new Composite(ast, input, e, sortByIndex(output))); | ||
} | ||
@@ -933,3 +871,3 @@ } | ||
output | ||
}) => Arr.isNonEmptyArray(es) ? Either.left(new TupleType(ast, input, sortByIndex(es), sortByIndex(output))) : Either.right(sortByIndex(output)); | ||
}) => array_.isNonEmptyArray(es) ? Either.left(new Composite(ast, input, sortByIndex(es), sortByIndex(output))) : Either.right(sortByIndex(output)); | ||
if (queue && queue.length > 0) { | ||
@@ -939,4 +877,4 @@ const cqueue = queue; | ||
const state = { | ||
es: Arr.copy(es), | ||
output: Arr.copy(output) | ||
es: array_.copy(es), | ||
output: array_.copy(output) | ||
}; | ||
@@ -995,3 +933,3 @@ return Effect.flatMap(Effect.forEach(cqueue, f => f(state), { | ||
if (onExcessPropertyError) { | ||
const e = new Key(key, new Unexpected(expectedAST)); | ||
const e = new Pointer(key, input, new Unexpected(input[key], `is unexpected, expected: ${String(expectedAST)}`)); | ||
if (allErrors) { | ||
@@ -1001,3 +939,3 @@ es.push([stepKey++, e]); | ||
} else { | ||
return Either.left(new TypeLiteral(ast, input, [e], output)); | ||
return Either.left(new Composite(ast, input, e, output)); | ||
} | ||
@@ -1021,3 +959,3 @@ } else { | ||
} else if (isExact) { | ||
const e = new Key(name, missing); | ||
const e = new Pointer(name, input, new Missing(ps)); | ||
if (allErrors) { | ||
@@ -1027,3 +965,3 @@ es.push([stepKey++, e]); | ||
} else { | ||
return Either.left(new TypeLiteral(ast, input, [e], output)); | ||
return Either.left(new Composite(ast, input, e, output)); | ||
} | ||
@@ -1037,3 +975,3 @@ } | ||
if (Either.isLeft(eu)) { | ||
const e = new Key(name, hasKey ? eu.left : missing); | ||
const e = new Pointer(name, input, hasKey ? eu.left : new Missing(ps)); | ||
if (allErrors) { | ||
@@ -1043,3 +981,3 @@ es.push([stepKey++, e]); | ||
} else { | ||
return Either.left(new TypeLiteral(ast, input, [e], output)); | ||
return Either.left(new Composite(ast, input, e, output)); | ||
} | ||
@@ -1059,3 +997,3 @@ } | ||
if (Either.isLeft(t)) { | ||
const e = new Key(index, hasKey ? t.left : missing); | ||
const e = new Pointer(index, input, hasKey ? t.left : new Missing(ps)); | ||
if (allErrors) { | ||
@@ -1065,3 +1003,3 @@ es.push([nk, e]); | ||
} else { | ||
return Either.left(new TypeLiteral(ast, input, [e], output)); | ||
return Either.left(new Composite(ast, input, e, output)); | ||
} | ||
@@ -1095,3 +1033,3 @@ } | ||
if (Either.isLeft(veu)) { | ||
const e = new Key(key, veu.left); | ||
const e = new Pointer(key, input, veu.left); | ||
if (allErrors) { | ||
@@ -1101,3 +1039,3 @@ es.push([stepKey++, e]); | ||
} else { | ||
return Either.left(new TypeLiteral(ast, input, [e], output)); | ||
return Either.left(new Composite(ast, input, e, output)); | ||
} | ||
@@ -1120,3 +1058,3 @@ } else { | ||
if (Either.isLeft(tv)) { | ||
const e = new Key(index, tv.left); | ||
const e = new Pointer(index, input, tv.left); | ||
if (allErrors) { | ||
@@ -1126,3 +1064,3 @@ es.push([nk, e]); | ||
} else { | ||
return Either.left(new TypeLiteral(ast, input, [e], output)); | ||
return Either.left(new Composite(ast, input, e, output)); | ||
} | ||
@@ -1147,4 +1085,4 @@ } else { | ||
}) => { | ||
if (Arr.isNonEmptyArray(es)) { | ||
return Either.left(new TypeLiteral(ast, input, sortByIndex(es), output)); | ||
if (array_.isNonEmptyArray(es)) { | ||
return Either.left(new Composite(ast, input, sortByIndex(es), output)); | ||
} | ||
@@ -1173,3 +1111,3 @@ if (options?.propertyOrder === "original") { | ||
const state = { | ||
es: Arr.copy(es), | ||
es: array_.copy(es), | ||
output: Object.assign({}, output) | ||
@@ -1220,7 +1158,8 @@ }; | ||
const literals = AST.Union.make(searchTree.keys[name].literals); | ||
es.push([stepKey++, new TypeLiteral(new AST.TypeLiteral([new AST.PropertySignature(name, literals, false, true)], []), input, [new Key(name, new Type(literals, input[name]))])]); | ||
es.push([stepKey++, new Composite(new AST.TypeLiteral([new AST.PropertySignature(name, literals, false, true)], []), input, new Pointer(name, input, new Type(literals, input[name])))]); | ||
} | ||
} else { | ||
const literals = AST.Union.make(searchTree.keys[name].literals); | ||
es.push([stepKey++, new TypeLiteral(new AST.TypeLiteral([new AST.PropertySignature(name, literals, false, true)], []), input, [new Key(name, missing)])]); | ||
const fakeps = new AST.PropertySignature(name, literals, false, true); // TODO: inherit message annotation from the union? | ||
es.push([stepKey++, new Composite(new AST.TypeLiteral([fakeps], []), input, new Pointer(name, input, new Missing(fakeps)))]); | ||
} | ||
@@ -1247,3 +1186,3 @@ } | ||
} else { | ||
es.push([stepKey++, new Member(candidate, eu.left)]); | ||
es.push([stepKey++, eu.left]); | ||
} | ||
@@ -1263,3 +1202,3 @@ } else { | ||
} else { | ||
state.es.push([nk, new Member(candidate, t.left)]); | ||
state.es.push([nk, t.left]); | ||
} | ||
@@ -1275,5 +1214,5 @@ return Effect.void; | ||
// --------------------------------------------- | ||
const computeResult = es => Arr.isNonEmptyArray(es) ? es.length === 1 && es[0][1]._tag === "Type" ? Either.left(es[0][1]) : Either.left(new Union(ast, input, sortByIndex(es))) : | ||
const computeResult = es => array_.isNonEmptyArray(es) ? es.length === 1 && es[0][1]._tag === "Type" ? Either.left(es[0][1]) : Either.left(new Composite(ast, input, sortByIndex(es))) : | ||
// this should never happen | ||
Either.left(new Type(AST.neverKeyword, input)); | ||
Either.left(new Type(ast, input)); | ||
if (queue && queue.length > 0) { | ||
@@ -1283,3 +1222,3 @@ const cqueue = queue; | ||
const state = { | ||
es: Arr.copy(es) | ||
es: array_.copy(es) | ||
}; | ||
@@ -1406,4 +1345,5 @@ return Effect.flatMap(Effect.forEach(cqueue, f => f(state), { | ||
}; | ||
const compare = ([a], [b]) => a > b ? 1 : a < b ? -1 : 0; | ||
function sortByIndex(es) { | ||
return es.sort(([a], [b]) => a > b ? 1 : a < b ? -1 : 0).map(([_, a]) => a); | ||
return es.sort(compare).map(t => t[1]); | ||
} | ||
@@ -1410,0 +1350,0 @@ // ------------------------------------------------------------------------------------- |
@@ -35,3 +35,2 @@ /** | ||
const formatUnknown = /*#__PURE__*/getMatcher(util_.formatUnknown); | ||
const getPrettyErrorMessage = (message, path) => errors_.getErrorMessageWithPath(`cannot build a Pretty for ${message}`, path); | ||
/** | ||
@@ -46,7 +45,7 @@ * @since 0.67.0 | ||
} | ||
throw new Error(getPrettyErrorMessage(`a declaration without annotations (${ast})`, path)); | ||
throw new Error(errors_.getPrettyMissingAnnotationErrorMessage(path, ast)); | ||
}, | ||
"VoidKeyword": /*#__PURE__*/getMatcher(() => "void(0)"), | ||
"NeverKeyword": /*#__PURE__*/getMatcher(() => { | ||
throw new Error("cannot pretty print a `never` value"); | ||
throw new Error(errors_.getPrettyNeverErrorMessage); | ||
}), | ||
@@ -72,3 +71,3 @@ "Literal": /*#__PURE__*/getMatcher(literal => typeof literal === "bigint" ? `${String(literal)}n` : JSON.stringify(literal)), | ||
const elements = ast.elements.map((e, i) => go(e.type, path.concat(i))); | ||
const rest = ast.rest.map(ast => go(ast, path)); | ||
const rest = ast.rest.map(annotatedAST => go(annotatedAST.type, path)); | ||
return input => { | ||
@@ -160,2 +159,5 @@ const output = []; | ||
const index = types.findIndex(([is]) => is(a)); | ||
if (index === -1) { | ||
throw new Error(errors_.getPrettyNoMatchingSchemaErrorMessage(a, path, ast)); | ||
} | ||
return types[index][1](a); | ||
@@ -162,0 +164,0 @@ }; |
@@ -57,3 +57,3 @@ import { dual } from "effect/Function"; | ||
*/ | ||
export const serialize = self => Schema.encode(self[symbol])(self); | ||
export const serialize = self => Schema.encodeUnknown(self[symbol])(self); | ||
/** | ||
@@ -60,0 +60,0 @@ * @since 0.67.0 |
@@ -27,3 +27,3 @@ /** | ||
*/ | ||
export const formatError = error => formatIssue(error.error); | ||
export const formatError = error => formatIssue(error.issue); | ||
/** | ||
@@ -33,3 +33,3 @@ * @category formatting | ||
*/ | ||
export const formatErrorSync = error => formatIssueSync(error.error); | ||
export const formatErrorSync = error => formatIssueSync(error.issue); | ||
const drawTree = tree => tree.value + draw("\n", tree.forest); | ||
@@ -66,19 +66,4 @@ const draw = (indentation, forest) => { | ||
}; | ||
const getInnerMessage = issue => { | ||
switch (issue._tag) { | ||
case "Refinement": | ||
{ | ||
if (issue.kind === "From") { | ||
return getMessage(issue.error); | ||
} | ||
break; | ||
} | ||
case "Transformation": | ||
{ | ||
return getMessage(issue.error); | ||
} | ||
} | ||
return Option.none(); | ||
}; | ||
const getCurrentMessage = issue => AST.getMessageAnnotation(issue.ast).pipe(Effect.flatMap(annotation => { | ||
const getAnnotated = issue => "ast" in issue ? Option.some(issue.ast) : Option.none(); | ||
const getCurrentMessage = issue => getAnnotated(issue).pipe(Option.flatMap(AST.getMessageAnnotation), Effect.flatMap(annotation => { | ||
const out = annotation(issue); | ||
@@ -99,18 +84,24 @@ return Predicate.isString(out) ? Effect.succeed({ | ||
})); | ||
const createParseIssueGuard = tag => issue => issue._tag === tag; | ||
const isComposite = /*#__PURE__*/createParseIssueGuard("Composite"); | ||
const isRefinement = /*#__PURE__*/createParseIssueGuard("Refinement"); | ||
const isTransformation = /*#__PURE__*/createParseIssueGuard("Transformation"); | ||
/** @internal */ | ||
export const getMessage = issue => { | ||
const current = getCurrentMessage(issue); | ||
return getInnerMessage(issue).pipe(Effect.flatMap(inner => Effect.map(current, current => current.override ? current.message : inner)), Effect.catchAll(() => Effect.flatMap(current, current => { | ||
if (!current.override && (issue._tag === "Refinement" && issue.kind !== "Predicate" || issue._tag === "Transformation" && issue.kind !== "Transformation")) { | ||
return Option.none(); | ||
} | ||
return Effect.succeed(current.message); | ||
}))); | ||
}; | ||
const getParseIssueTitleAnnotation = issue => Option.filterMap(AST.getParseIssueTitleAnnotation(issue.ast), annotation => Option.fromNullable(annotation(issue))); | ||
export const getMessage = issue => getCurrentMessage(issue).pipe(Effect.flatMap(currentMessage => { | ||
const useInnerMessage = !currentMessage.override && (isComposite(issue) || isRefinement(issue) && issue.kind === "From" || isTransformation(issue) && issue.kind !== "Transformation"); | ||
return useInnerMessage ? isTransformation(issue) || isRefinement(issue) ? getMessage(issue.issue) : Option.none() : Effect.succeed(currentMessage.message); | ||
})); | ||
const getParseIssueTitleAnnotation = issue => getAnnotated(issue).pipe(Option.flatMap(AST.getParseIssueTitleAnnotation), Option.filterMap(annotation => Option.fromNullable(annotation(issue)))); | ||
/** @internal */ | ||
export const formatTypeMessage = e => getMessage(e).pipe(Effect.orElse(() => getParseIssueTitleAnnotation(e)), Effect.orElse(() => e.message), Effect.catchAll(() => Effect.succeed(`Expected ${e.ast.toString(true)}, actual ${util_.formatUnknown(e.actual)}`))); | ||
export const formatTypeMessage = e => getMessage(e).pipe(Effect.orElse(() => getParseIssueTitleAnnotation(e)), Effect.catchAll(() => Effect.succeed(e.message ?? `Expected ${String(e.ast)}, actual ${util_.formatUnknown(e.actual)}`))); | ||
const getParseIssueTitle = issue => Option.getOrElse(getParseIssueTitleAnnotation(issue), () => String(issue.ast)); | ||
/** @internal */ | ||
export const formatForbiddenMessage = e => Option.getOrElse(e.message, () => "is forbidden"); | ||
export const formatForbiddenMessage = e => e.message ?? "is forbidden"; | ||
/** @internal */ | ||
export const formatUnexpectedMessage = e => e.message ?? "is unexpected"; | ||
/** @internal */ | ||
export const formatMissingMessage = e => AST.getMissingMessageAnnotation(e.ast).pipe(Effect.flatMap(annotation => { | ||
const out = annotation(); | ||
return Predicate.isString(out) ? Effect.succeed(out) : out; | ||
}), Effect.catchAll(() => Effect.succeed(e.message ?? "is missing"))); | ||
const getTree = (issue, onFailure) => Effect.matchEffect(getMessage(issue), { | ||
@@ -127,30 +118,18 @@ onFailure, | ||
case "Unexpected": | ||
return Effect.succeed(make(`is unexpected, expected ${e.ast.toString(true)}`)); | ||
return Effect.succeed(make(formatUnexpectedMessage(e))); | ||
case "Missing": | ||
return Effect.succeed(make("is missing")); | ||
case "Union": | ||
return getTree(e, () => Effect.map(Effect.forEach(e.errors, e => { | ||
switch (e._tag) { | ||
case "Member": | ||
return Effect.map(go(e.error), tree => make(`Union member`, [tree])); | ||
default: | ||
return go(e); | ||
} | ||
}), forest => make(getParseIssueTitle(e), forest))); | ||
case "TupleType": | ||
return getTree(e, () => Effect.map(Effect.forEach(e.errors, index => Effect.map(go(index.error), tree => make(`[${util_.formatPropertyKey(index.index)}]`, [tree]))), forest => make(getParseIssueTitle(e), forest))); | ||
case "TypeLiteral": | ||
return getTree(e, () => Effect.map(Effect.forEach(e.errors, key => Effect.map(go(key.error), tree => make(`[${util_.formatPropertyKey(key.key)}]`, [tree]))), forest => make(getParseIssueTitle(e), forest))); | ||
return Effect.map(formatMissingMessage(e), make); | ||
case "Transformation": | ||
return getTree(e, () => Effect.map(go(e.error), tree => make(getParseIssueTitle(e), [make(formatTransformationKind(e.kind), [tree])]))); | ||
return getTree(e, () => Effect.map(go(e.issue), tree => make(getParseIssueTitle(e), [make(formatTransformationKind(e.kind), [tree])]))); | ||
case "Refinement": | ||
return getTree(e, () => Effect.map(go(e.error), tree => make(getParseIssueTitle(e), [make(formatRefinementKind(e.kind), [tree])]))); | ||
case "Declaration": | ||
return getTree(e, () => { | ||
const error = e.error; | ||
const shouldSkipDefaultMessage = error._tag === "Type" && error.ast === e.ast; | ||
return shouldSkipDefaultMessage ? go(error) : Effect.map(go(error), tree => make(getParseIssueTitle(e), [tree])); | ||
}); | ||
return getTree(e, () => Effect.map(go(e.issue), tree => make(getParseIssueTitle(e), [make(formatRefinementKind(e.kind), [tree])]))); | ||
case "Pointer": | ||
return Effect.map(go(e.issue), tree => make(util_.formatPath(e.path), [tree])); | ||
case "Composite": | ||
{ | ||
const parseIssueTitle = getParseIssueTitle(e); | ||
return getTree(e, () => util_.isNonEmpty(e.issues) ? Effect.map(Effect.forEach(e.issues, go), forest => make(parseIssueTitle, forest)) : Effect.map(go(e.issues), tree => make(parseIssueTitle, [tree]))); | ||
} | ||
} | ||
}; | ||
//# sourceMappingURL=TreeFormatter.js.map |
{ | ||
"name": "@effect/schema", | ||
"version": "0.0.0-snapshot-64d29bc90eef90891aa52242a56ea80a52c18645", | ||
"version": "0.0.0-snapshot-6e9edd448c6d82afd40e9d971340ed91efdcfce7", | ||
"description": "Modeling the schema of data structures as first-class values", | ||
@@ -13,6 +13,6 @@ "license": "MIT", | ||
"dependencies": { | ||
"fast-check": "^3.17.2" | ||
"fast-check": "^3.19.0" | ||
}, | ||
"peerDependencies": { | ||
"effect": "^0.0.0-snapshot-64d29bc90eef90891aa52242a56ea80a52c18645" | ||
"effect": "^0.0.0-snapshot-6e9edd448c6d82afd40e9d971340ed91efdcfce7" | ||
}, | ||
@@ -19,0 +19,0 @@ "publishConfig": { |
@@ -96,5 +96,2 @@ /** | ||
const getArbitraryErrorMessage = (message: string, path: ReadonlyArray<PropertyKey>) => | ||
errors_.getErrorMessageWithPath(`cannot build an Arbitrary for ${message}`, path) | ||
const go = (ast: AST.AST, options: Options, path: ReadonlyArray<PropertyKey>): LazyArbitrary<any> => { | ||
@@ -114,3 +111,3 @@ const hook = getHook(ast) | ||
case "Declaration": { | ||
throw new Error(getArbitraryErrorMessage(`a declaration without annotations (${ast})`, path)) | ||
throw new Error(errors_.getArbitraryMissingAnnotationErrorMessage(path, ast)) | ||
} | ||
@@ -126,3 +123,3 @@ case "Literal": | ||
return () => { | ||
throw new Error(getArbitraryErrorMessage("`never`", path)) | ||
throw new Error(errors_.getArbitraryUnsupportedErrorMessage(path, ast)) | ||
} | ||
@@ -196,3 +193,3 @@ case "UnknownKeyword": | ||
} | ||
const rest = ast.rest.map((e) => go(e, options, path)) | ||
const rest = ast.rest.map((annotatedAST) => go(annotatedAST.type, options, path)) | ||
return (fc) => { | ||
@@ -290,3 +287,3 @@ // --------------------------------------------- | ||
if (ast.enums.length === 0) { | ||
throw new Error(getArbitraryErrorMessage("an empty enum", path)) | ||
throw new Error(errors_.getArbitraryEmptyEnumErrorMessage(path)) | ||
} | ||
@@ -293,0 +290,0 @@ return (fc) => fc.oneof(...ast.enums.map(([_, value]) => fc.constant(value))) |
@@ -5,4 +5,5 @@ /** | ||
import * as Arr from "effect/Array" | ||
import * as array_ from "effect/Array" | ||
import * as Effect from "effect/Effect" | ||
import * as util_ from "./internal/util.js" | ||
import type * as ParseResult from "./ParseResult.js" | ||
@@ -16,13 +17,3 @@ import * as TreeFormatter from "./TreeFormatter.js" | ||
export interface Issue { | ||
readonly _tag: | ||
| "Transformation" | ||
| "Type" | ||
| "Declaration" | ||
| "Refinement" | ||
| "TupleType" | ||
| "TypeLiteral" | ||
| "Union" | ||
| "Forbidden" | ||
| "Missing" | ||
| "Unexpected" | ||
readonly _tag: ParseResult.ParseIssue["_tag"] | ||
readonly path: ReadonlyArray<PropertyKey> | ||
@@ -48,3 +39,3 @@ readonly message: string | ||
*/ | ||
export const formatError = (error: ParseResult.ParseError): Effect.Effect<Array<Issue>> => formatIssue(error.error) | ||
export const formatError = (error: ParseResult.ParseError): Effect.Effect<Array<Issue>> => formatIssue(error.issue) | ||
@@ -55,3 +46,3 @@ /** | ||
*/ | ||
export const formatErrorSync = (error: ParseResult.ParseError): Array<Issue> => formatIssueSync(error.error) | ||
export const formatErrorSync = (error: ParseResult.ParseError): Array<Issue> => formatIssueSync(error.issue) | ||
@@ -70,6 +61,4 @@ const succeed = (issue: Issue) => Effect.succeed([issue]) | ||
const flatten = (eff: Effect.Effect<Array<Array<Issue>>>): Effect.Effect<Array<Issue>> => Effect.map(eff, Arr.flatten) | ||
const go = ( | ||
e: ParseResult.ParseIssue | ParseResult.Missing | ParseResult.Unexpected, | ||
e: ParseResult.ParseIssue | ParseResult.Pointer, | ||
path: ReadonlyArray<PropertyKey> = [] | ||
@@ -84,34 +73,16 @@ ): Effect.Effect<Array<Issue>> => { | ||
case "Unexpected": | ||
return succeed({ _tag, path, message: `is unexpected, expected ${e.ast.toString(true)}` }) | ||
return succeed({ _tag, path, message: TreeFormatter.formatUnexpectedMessage(e) }) | ||
case "Missing": | ||
return succeed({ _tag, path, message: "is missing" }) | ||
case "Union": | ||
return Effect.map(TreeFormatter.formatMissingMessage(e), (message) => [{ _tag, path, message }]) | ||
case "Pointer": | ||
return go(e.issue, path.concat(e.path)) | ||
case "Composite": | ||
return getArray(e, path, () => | ||
flatten( | ||
Effect.forEach(e.errors, (e) => { | ||
switch (e._tag) { | ||
case "Member": | ||
return go(e.error, path) | ||
default: | ||
return go(e, path) | ||
} | ||
}) | ||
)) | ||
case "TupleType": | ||
return getArray( | ||
e, | ||
path, | ||
() => flatten(Effect.forEach(e.errors, (index) => go(index.error, path.concat(index.index)))) | ||
) | ||
case "TypeLiteral": | ||
return getArray( | ||
e, | ||
path, | ||
() => flatten(Effect.forEach(e.errors, (key) => go(key.error, path.concat(key.key)))) | ||
) | ||
case "Declaration": | ||
util_.isNonEmpty(e.issues) | ||
? Effect.map(Effect.forEach(e.issues, (issue) => go(issue, path)), array_.flatten) | ||
: go(e.issues, path)) | ||
case "Refinement": | ||
case "Transformation": | ||
return getArray(e, path, () => go(e.error, path)) | ||
return getArray(e, path, () => go(e.issue, path)) | ||
} | ||
} |
@@ -48,5 +48,2 @@ /** | ||
const getEquivalenceErrorMessage = (message: string, path: ReadonlyArray<PropertyKey>) => | ||
errors_.getErrorMessageWithPath(`cannot build an Equivalence for ${message}`, path) | ||
const go = (ast: AST.AST, path: ReadonlyArray<PropertyKey>): Equivalence.Equivalence<any> => { | ||
@@ -66,3 +63,3 @@ const hook = getHook(ast) | ||
case "NeverKeyword": | ||
throw new Error(getEquivalenceErrorMessage("`never`", path)) | ||
throw new Error(errors_.getEquivalenceUnsupportedErrorMessage(ast, path)) | ||
case "Transformation": | ||
@@ -94,3 +91,3 @@ return go(ast.to, path) | ||
const elements = ast.elements.map((element, i) => go(element.type, path.concat(i))) | ||
const rest = ast.rest.map((ast) => go(ast, path)) | ||
const rest = ast.rest.map((annotatedAST) => go(annotatedAST.type, path)) | ||
return Equivalence.make((a, b) => { | ||
@@ -97,0 +94,0 @@ const len = a.length |
@@ -48,4 +48,2 @@ /** | ||
* @since 0.67.0 | ||
* | ||
* Serializable represents an object that has self-contained Schema(s) | ||
*/ | ||
@@ -52,0 +50,0 @@ export * as Serializable from "./Serializable.js" |
@@ -0,17 +1,189 @@ | ||
import * as array_ from "effect/Array" | ||
import type * as AST from "../AST.js" | ||
import * as util_ from "./util.js" | ||
const getErrorMessage = ( | ||
reason: string, | ||
details?: string, | ||
path?: ReadonlyArray<PropertyKey>, | ||
ast?: AST.AST | ||
): string => { | ||
let out = reason | ||
if (path && array_.isNonEmptyReadonlyArray(path)) { | ||
out += `\nat path: ${util_.formatPath(path)}` | ||
} | ||
if (details !== undefined) { | ||
out += `\ndetails: ${details}` | ||
} | ||
if (ast) { | ||
out += `\nschema (${ast._tag}): ${ast}` | ||
} | ||
return out | ||
} | ||
// --------------------------------------------- | ||
// generic | ||
// --------------------------------------------- | ||
/** @internal */ | ||
export const getDuplicatePropertySignatureErrorMessage = (name: PropertyKey): string => | ||
`Duplicate property signature ${util_.formatUnknown(name)}` | ||
export const getInvalidArgumentErrorMessage = (details: string) => getErrorMessage("Invalid Argument", details) | ||
const getUnsupportedSchemaErrorMessage = (details?: string, path?: ReadonlyArray<PropertyKey>, ast?: AST.AST): string => | ||
getErrorMessage("Unsupported schema", details, path, ast) | ||
const getMissingAnnotationErrorMessage = (details?: string, path?: ReadonlyArray<PropertyKey>, ast?: AST.AST): string => | ||
getErrorMessage("Missing annotation", details, path, ast) | ||
// --------------------------------------------- | ||
// Arbitrary | ||
// --------------------------------------------- | ||
/** @internal */ | ||
export const getErrorMessage = (api: string, message: string) => `${api}: ${message}` | ||
export const getArbitraryUnsupportedErrorMessage = (path: ReadonlyArray<PropertyKey>, ast: AST.AST) => | ||
getUnsupportedSchemaErrorMessage("Cannot build an Arbitrary for this schema", path, ast) | ||
/** @internal */ | ||
export const getErrorMessageWithPath = (message: string, path: ReadonlyArray<PropertyKey>) => { | ||
let out = message | ||
if (path.length > 0) { | ||
out += ` (path [${path.map(util_.formatPropertyKey).join(", ")}])` | ||
} | ||
return out | ||
} | ||
export const getArbitraryMissingAnnotationErrorMessage = ( | ||
path: ReadonlyArray<PropertyKey>, | ||
ast: AST.AST | ||
) => | ||
getMissingAnnotationErrorMessage( | ||
`Generating an Arbitrary for this schema requires an "arbitrary" annotation`, | ||
path, | ||
ast | ||
) | ||
/** @internal */ | ||
export const getArbitraryEmptyEnumErrorMessage = (path: ReadonlyArray<PropertyKey>) => | ||
getErrorMessage("Empty Enums schema", "Generating an Arbitrary for this schema requires at least one enum", path) | ||
// --------------------------------------------- | ||
// Equivalence | ||
// --------------------------------------------- | ||
/** @internal */ | ||
export const getEquivalenceUnsupportedErrorMessage = (ast: AST.AST, path: ReadonlyArray<PropertyKey>) => | ||
getUnsupportedSchemaErrorMessage("Cannot build an Equivalence", path, ast) | ||
// --------------------------------------------- | ||
// JSON Schema | ||
// --------------------------------------------- | ||
/** @internal */ | ||
export const getJSONSchemaMissingAnnotationErrorMessage = ( | ||
path: ReadonlyArray<PropertyKey>, | ||
ast: AST.AST | ||
) => | ||
getMissingAnnotationErrorMessage( | ||
`Generating a JSON Schema for this schema requires a "jsonSchema" annotation`, | ||
path, | ||
ast | ||
) | ||
/** @internal */ | ||
export const getJSONSchemaMissingIdentifierAnnotationErrorMessage = ( | ||
path: ReadonlyArray<PropertyKey>, | ||
ast: AST.AST | ||
) => | ||
getMissingAnnotationErrorMessage( | ||
`Generating a JSON Schema for this schema requires an "identifier" annotation`, | ||
path, | ||
ast | ||
) | ||
/** @internal */ | ||
export const getJSONSchemaUnsupportedParameterErrorMessage = ( | ||
path: ReadonlyArray<PropertyKey>, | ||
parameter: AST.AST | ||
): string => getErrorMessage("Unsupported index signature parameter", undefined, path, parameter) | ||
/** @internal */ | ||
export const getJSONSchemaUnsupportedPostRestElementsErrorMessage = (path: ReadonlyArray<PropertyKey>): string => | ||
getErrorMessage( | ||
"Generating a JSON Schema for post-rest elements is not currently supported. You're welcome to contribute by submitting a Pull Request", | ||
undefined, | ||
path | ||
) | ||
/** @internal */ | ||
export const getJSONSchemaUnsupportedKeyErrorMessage = (key: PropertyKey, path: ReadonlyArray<PropertyKey>): string => | ||
getErrorMessage("Unsupported key", `Cannot encode ${util_.formatPropertyKey(key)} key to JSON Schema`, path) | ||
// --------------------------------------------- | ||
// Pretty | ||
// --------------------------------------------- | ||
/** @internal */ | ||
export const getPrettyMissingAnnotationErrorMessage = ( | ||
path: ReadonlyArray<PropertyKey>, | ||
ast: AST.AST | ||
) => getMissingAnnotationErrorMessage(`Generating a Pretty for this schema requires a "pretty" annotation`, path, ast) | ||
/** @internal */ | ||
export const getPrettyNeverErrorMessage = "Cannot pretty print a `never` value" | ||
/** @internal */ | ||
export const getPrettyNoMatchingSchemaErrorMessage = ( | ||
actual: unknown, | ||
path: ReadonlyArray<PropertyKey>, | ||
ast: AST.AST | ||
) => getErrorMessage("Unexpected Error", `Cannot find a matching schema for ${util_.formatUnknown(actual)}`, path, ast) | ||
// --------------------------------------------- | ||
// Schema | ||
// --------------------------------------------- | ||
/** @internal */ | ||
export const getSchemaExtendErrorMessage = (x: AST.AST, y: AST.AST, path: ReadonlyArray<PropertyKey>) => | ||
getErrorMessage("Unsupported schema or overlapping types", `cannot extend ${x} with ${y}`, path) | ||
/** @internal */ | ||
export const getSchemaUnsupportedLiteralSpanErrorMessage = (ast: AST.AST) => | ||
getErrorMessage("Unsupported template literal span", undefined, undefined, ast) | ||
// --------------------------------------------- | ||
// AST | ||
// --------------------------------------------- | ||
/** @internal */ | ||
export const getASTUnsupportedSchema = (ast: AST.AST) => getUnsupportedSchemaErrorMessage(undefined, undefined, ast) | ||
/** @internal */ | ||
export const getASTUnsupportedKeySchema = (ast: AST.AST) => | ||
getErrorMessage("Unsupported key schema", undefined, undefined, ast) | ||
/** @internal */ | ||
export const getASTUnsupportedLiteral = (literal: AST.LiteralValue) => | ||
getErrorMessage("Unsupported literal", `literal value: ${util_.formatUnknown(literal)}`) | ||
/** @internal */ | ||
export const getASTDuplicateIndexSignatureErrorMessage = (type: "string" | "symbol"): string => | ||
getErrorMessage("Duplicate index signature", `${type} index signature`) | ||
/** @internal */ | ||
export const getASTIndexSignatureParameterErrorMessage = getErrorMessage( | ||
"Unsupported index signature parameter", | ||
"An index signature parameter type must be `string`, `symbol`, a template literal type or a refinement of the previous types" | ||
) | ||
/** @internal */ | ||
export const getASTRequiredElementFollowinAnOptionalElementErrorMessage = getErrorMessage( | ||
"Invalid element", | ||
"A required element cannot follow an optional element. ts(1257)" | ||
) | ||
/** @internal */ | ||
export const getASTDuplicatePropertySignatureTransformationErrorMessage = (key: PropertyKey): string => | ||
getErrorMessage("Duplicate property signature transformation", `Duplicate key ${util_.formatUnknown(key)}`) | ||
/** @internal */ | ||
export const getASTUnsupportedRenameSchema = (ast: AST.AST): string => | ||
getUnsupportedSchemaErrorMessage(undefined, undefined, ast) | ||
/** @internal */ | ||
export const getASTDuplicatePropertySignatureErrorMessage = (key: PropertyKey): string => | ||
getErrorMessage("Duplicate property signature", `Duplicate key ${util_.formatUnknown(key)}`) |
@@ -87,1 +87,4 @@ import type * as Schema from "../Schema.js" | ||
) as Schema.ItemsCountTypeId | ||
/** @internal */ | ||
export const ParseJsonTypeId: unique symbol = Symbol.for("@effect/schema/TypeId/ParseJson") |
@@ -0,3 +1,5 @@ | ||
import * as array_ from "effect/Array" | ||
import * as Predicate from "effect/Predicate" | ||
import type * as AST from "../AST.js" | ||
import type * as ParseResult from "../ParseResult.js" | ||
@@ -53,3 +55,3 @@ /** @internal */ | ||
} else if ( | ||
!Array.isArray(u) | ||
!array_.isArray(u) | ||
&& Predicate.hasProperty(u, "toString") | ||
@@ -63,3 +65,3 @@ && Predicate.isFunction(u["toString"]) | ||
JSON.stringify(u) | ||
if (Array.isArray(u)) { | ||
if (array_.isArray(u)) { | ||
return `[${u.map(formatUnknown).join(",")}]` | ||
@@ -81,1 +83,18 @@ } else { | ||
typeof name === "string" ? JSON.stringify(name) : String(name) | ||
/** @internal */ | ||
export type SingleOrArray<A> = A | ReadonlyArray<A> | ||
/** @internal */ | ||
export const isNonEmpty = <A>(x: ParseResult.SingleOrNonEmpty<A>): x is array_.NonEmptyReadonlyArray<A> => | ||
Array.isArray(x) | ||
/** @internal */ | ||
export const isSingle = <A>(x: A | ReadonlyArray<A>): x is A => !Array.isArray(x) | ||
/** @internal */ | ||
export const formatPathKey = (key: PropertyKey): string => `[${formatPropertyKey(key)}]` | ||
/** @internal */ | ||
export const formatPath = (path: ParseResult.Path): string => | ||
isNonEmpty(path) ? path.map(formatPathKey).join("") : formatPathKey(path) |
@@ -10,2 +10,3 @@ /** | ||
import * as errors_ from "./internal/errors.js" | ||
import * as filters_ from "./internal/filters.js" | ||
import type * as Schema from "./Schema.js" | ||
@@ -184,2 +185,3 @@ | ||
patternProperties?: Record<string, JsonSchema7> | ||
propertyNames?: JsonSchema7 | ||
} | ||
@@ -279,10 +281,2 @@ | ||
const getMissingAnnotationErrorMessage = (name: string, path: ReadonlyArray<PropertyKey>): string => | ||
errors_.getErrorMessageWithPath(`cannot build a JSON Schema for ${name} without a JSON Schema annotation`, path) | ||
const getUnsupportedIndexSignatureParameterErrorMessage = ( | ||
parameter: AST.AST, | ||
path: ReadonlyArray<PropertyKey> | ||
): string => errors_.getErrorMessageWithPath(`unsupported index signature parameter (${parameter})`, path) | ||
/** @internal */ | ||
@@ -311,2 +305,12 @@ export const DEFINITION_PREFIX = "#/$defs/" | ||
const isParseJsonTransformation = (ast: AST.AST): boolean => | ||
ast.annotations[AST.TypeAnnotationId] === filters_.ParseJsonTypeId | ||
function merge(a: JsonSchemaAnnotations, b: JsonSchema7): JsonSchema7 | ||
function merge(a: JsonSchema7, b: JsonSchemaAnnotations): JsonSchema7 | ||
function merge(a: JsonSchema7, b: JsonSchema7): JsonSchema7 | ||
function merge(a: object, b: object): object { | ||
return { ...a, ...b } | ||
} | ||
const go = ( | ||
@@ -323,5 +327,5 @@ ast: AST.AST, | ||
try { | ||
return { ...go(ast.from, $defs, true, path), ...getJsonSchemaAnnotations(ast), ...handler } | ||
return merge(merge(go(ast.from, $defs, true, path), getJsonSchemaAnnotations(ast)), handler) | ||
} catch (e) { | ||
return { ...getJsonSchemaAnnotations(ast), ...handler } | ||
return merge(getJsonSchemaAnnotations(ast), handler) | ||
} | ||
@@ -349,44 +353,55 @@ } | ||
case "Declaration": | ||
throw new Error(getMissingAnnotationErrorMessage("a declaration", path)) | ||
throw new Error(errors_.getJSONSchemaMissingAnnotationErrorMessage(path, ast)) | ||
case "Literal": { | ||
const literal = ast.literal | ||
if (literal === null) { | ||
return { const: null, ...getJsonSchemaAnnotations(ast) } | ||
} else if (Predicate.isString(literal)) { | ||
return { const: literal, ...getJsonSchemaAnnotations(ast) } | ||
} else if (Predicate.isNumber(literal)) { | ||
return { const: literal, ...getJsonSchemaAnnotations(ast) } | ||
} else if (Predicate.isBoolean(literal)) { | ||
return { const: literal, ...getJsonSchemaAnnotations(ast) } | ||
return merge({ const: null }, getJsonSchemaAnnotations(ast)) | ||
} else if (Predicate.isString(literal) || Predicate.isNumber(literal) || Predicate.isBoolean(literal)) { | ||
return merge({ const: literal }, getJsonSchemaAnnotations(ast)) | ||
} | ||
throw new Error(getMissingAnnotationErrorMessage("a bigint literal", path)) | ||
throw new Error(errors_.getJSONSchemaMissingAnnotationErrorMessage(path, ast)) | ||
} | ||
case "UniqueSymbol": | ||
throw new Error(getMissingAnnotationErrorMessage("a unique symbol", path)) | ||
throw new Error(errors_.getJSONSchemaMissingAnnotationErrorMessage(path, ast)) | ||
case "UndefinedKeyword": | ||
throw new Error(getMissingAnnotationErrorMessage("`undefined`", path)) | ||
throw new Error(errors_.getJSONSchemaMissingAnnotationErrorMessage(path, ast)) | ||
case "VoidKeyword": | ||
throw new Error(getMissingAnnotationErrorMessage("`void`", path)) | ||
throw new Error(errors_.getJSONSchemaMissingAnnotationErrorMessage(path, ast)) | ||
case "NeverKeyword": | ||
throw new Error(getMissingAnnotationErrorMessage("`never`", path)) | ||
throw new Error(errors_.getJSONSchemaMissingAnnotationErrorMessage(path, ast)) | ||
case "UnknownKeyword": | ||
return { ...unknownJsonSchema, ...getJsonSchemaAnnotations(ast) } | ||
return merge(unknownJsonSchema, getJsonSchemaAnnotations(ast)) | ||
case "AnyKeyword": | ||
return { ...anyJsonSchema, ...getJsonSchemaAnnotations(ast) } | ||
return merge(anyJsonSchema, getJsonSchemaAnnotations(ast)) | ||
case "ObjectKeyword": | ||
return { ...objectJsonSchema, ...getJsonSchemaAnnotations(ast) } | ||
case "StringKeyword": | ||
return { type: "string", ...getJsonSchemaAnnotations(ast) } | ||
case "NumberKeyword": | ||
return { type: "number", ...getJsonSchemaAnnotations(ast) } | ||
case "BooleanKeyword": | ||
return { type: "boolean", ...getJsonSchemaAnnotations(ast) } | ||
return merge(objectJsonSchema, getJsonSchemaAnnotations(ast)) | ||
case "StringKeyword": { | ||
const out: JsonSchema7 = { type: "string" } | ||
return ast === AST.stringKeyword ? out : merge(out, getJsonSchemaAnnotations(ast)) | ||
} | ||
case "NumberKeyword": { | ||
const out: JsonSchema7 = { type: "number" } | ||
return ast === AST.numberKeyword ? out : merge(out, getJsonSchemaAnnotations(ast)) | ||
} | ||
case "BooleanKeyword": { | ||
const out: JsonSchema7 = { type: "boolean" } | ||
return ast === AST.booleanKeyword ? out : merge(out, getJsonSchemaAnnotations(ast)) | ||
} | ||
case "BigIntKeyword": | ||
throw new Error(getMissingAnnotationErrorMessage("`bigint`", path)) | ||
throw new Error(errors_.getJSONSchemaMissingAnnotationErrorMessage(path, ast)) | ||
case "SymbolKeyword": | ||
throw new Error(getMissingAnnotationErrorMessage("`symbol`", path)) | ||
throw new Error(errors_.getJSONSchemaMissingAnnotationErrorMessage(path, ast)) | ||
case "TupleType": { | ||
const len = ast.elements.length | ||
const elements = ast.elements.map((e, i) => go(e.type, $defs, true, path.concat(i))) | ||
const rest = ast.rest.map((ast) => go(ast, $defs, true, path)) | ||
const elements = ast.elements.map((e, i) => | ||
merge( | ||
go(e.type, $defs, true, path.concat(i)), | ||
getJsonSchemaAnnotations(e) | ||
) | ||
) | ||
const rest = ast.rest.map((annotatedAST) => | ||
merge( | ||
go(annotatedAST.type, $defs, true, path), | ||
getJsonSchemaAnnotations(annotatedAST) | ||
) | ||
) | ||
const output: JsonSchema7Array = { type: "array" } | ||
@@ -396,2 +411,3 @@ // --------------------------------------------- | ||
// --------------------------------------------- | ||
const len = ast.elements.length | ||
if (len > 0) { | ||
@@ -404,8 +420,10 @@ output.minItems = len - ast.elements.filter((element) => element.isOptional).length | ||
// --------------------------------------------- | ||
if (rest.length > 0) { | ||
const restLength = rest.length | ||
if (restLength > 0) { | ||
const head = rest[0] | ||
if (len > 0) { | ||
const isHomogeneous = restLength === 1 && ast.elements.every((e) => e.type === ast.rest[0].type) | ||
if (isHomogeneous) { | ||
output.items = head | ||
} else { | ||
output.additionalItems = head | ||
} else { | ||
output.items = head | ||
} | ||
@@ -416,9 +434,4 @@ | ||
// --------------------------------------------- | ||
if (rest.length > 1) { | ||
throw new Error( | ||
errors_.getErrorMessageWithPath( | ||
"Generating a JSON Schema for post-rest elements is not currently supported. You're welcome to contribute by submitting a Pull Request.", | ||
path | ||
) | ||
) | ||
if (restLength > 1) { | ||
throw new Error(errors_.getJSONSchemaUnsupportedPostRestElementsErrorMessage(path)) | ||
} | ||
@@ -433,10 +446,10 @@ } else { | ||
return { ...output, ...getJsonSchemaAnnotations(ast) } | ||
return merge(output, getJsonSchemaAnnotations(ast)) | ||
} | ||
case "TypeLiteral": { | ||
if (ast.propertySignatures.length === 0 && ast.indexSignatures.length === 0) { | ||
return { ...empty(), ...getJsonSchemaAnnotations(ast) } | ||
return merge(empty(), getJsonSchemaAnnotations(ast)) | ||
} | ||
let additionalProperties: JsonSchema7 | undefined = undefined | ||
let patternProperties: Record<string, JsonSchema7> | undefined = undefined | ||
let patternProperties: JsonSchema7 | undefined = undefined | ||
let propertyNames: JsonSchema7 | undefined = undefined | ||
for (const is of ast.indexSignatures) { | ||
@@ -446,8 +459,10 @@ const parameter = is.parameter | ||
case "StringKeyword": { | ||
additionalProperties = go(is.type, $defs, true, path) | ||
patternProperties = go(is.type, $defs, true, path) | ||
break | ||
} | ||
case "TemplateLiteral": { | ||
patternProperties = { | ||
[AST.getTemplateLiteralRegExp(parameter).source]: go(is.type, $defs, true, path) | ||
patternProperties = go(is.type, $defs, true, path) | ||
propertyNames = { | ||
type: "string", | ||
pattern: AST.getTemplateLiteralRegExp(parameter).source | ||
} | ||
@@ -457,23 +472,15 @@ break | ||
case "Refinement": { | ||
const hook = AST.getJSONSchemaAnnotation(parameter) | ||
if ( | ||
Option.isSome(hook) && "pattern" in hook.value && | ||
Predicate.isString(hook.value.pattern) | ||
) { | ||
patternProperties = { | ||
[hook.value.pattern]: go(is.type, $defs, true, path) | ||
} | ||
break | ||
} | ||
throw new Error(getUnsupportedIndexSignatureParameterErrorMessage(parameter, path)) | ||
patternProperties = go(is.type, $defs, true, path) | ||
propertyNames = go(parameter, $defs, true, path) | ||
break | ||
} | ||
case "SymbolKeyword": | ||
throw new Error(getUnsupportedIndexSignatureParameterErrorMessage(parameter, path)) | ||
throw new Error(errors_.getJSONSchemaUnsupportedParameterErrorMessage(path, parameter)) | ||
} | ||
} | ||
const propertySignatures = ast.propertySignatures.map((ps) => { | ||
return { | ||
...go(pruneUndefinedKeyword(ps), $defs, true, path.concat(ps.name)), | ||
...getJsonSchemaAnnotations(ps) | ||
} | ||
return merge( | ||
go(pruneUndefinedKeyword(ps), $defs, true, path.concat(ps.name)), | ||
getJsonSchemaAnnotations(ps) | ||
) | ||
}) | ||
@@ -500,3 +507,3 @@ const output: JsonSchema7Object = { | ||
} else { | ||
throw new Error(errors_.getErrorMessageWithPath(`cannot encode ${String(name)} key to JSON Schema`, path)) | ||
throw new Error(errors_.getJSONSchemaUnsupportedKeyErrorMessage(name, path)) | ||
} | ||
@@ -507,10 +514,11 @@ } | ||
// --------------------------------------------- | ||
if (additionalProperties !== undefined) { | ||
output.additionalProperties = additionalProperties | ||
} | ||
if (patternProperties !== undefined) { | ||
output.patternProperties = patternProperties | ||
delete output.additionalProperties | ||
output.patternProperties = { "": patternProperties } | ||
} | ||
if (propertyNames !== undefined) { | ||
output.propertyNames = propertyNames | ||
} | ||
return { ...output, ...getJsonSchemaAnnotations(ast) } | ||
return merge(output, getJsonSchemaAnnotations(ast)) | ||
} | ||
@@ -534,5 +542,5 @@ case "Union": { | ||
if (enums.length === 1) { | ||
return { const: enums[0], ...getJsonSchemaAnnotations(ast) } | ||
return merge({ const: enums[0] }, getJsonSchemaAnnotations(ast)) | ||
} else { | ||
return { enum: enums, ...getJsonSchemaAnnotations(ast) } | ||
return merge({ enum: enums }, getJsonSchemaAnnotations(ast)) | ||
} | ||
@@ -545,28 +553,21 @@ } else { | ||
} | ||
return { anyOf, ...getJsonSchemaAnnotations(ast) } | ||
return merge({ anyOf }, getJsonSchemaAnnotations(ast)) | ||
} | ||
} | ||
case "Enums": { | ||
return { | ||
return merge({ | ||
$comment: "/schemas/enums", | ||
oneOf: ast.enums.map((e) => ({ title: e[0], const: e[1] })), | ||
...getJsonSchemaAnnotations(ast) | ||
} | ||
oneOf: ast.enums.map((e) => ({ title: e[0], const: e[1] })) | ||
}, getJsonSchemaAnnotations(ast)) | ||
} | ||
case "Refinement": { | ||
throw new Error( | ||
errors_.getErrorMessageWithPath( | ||
"cannot build a JSON Schema for a refinement without a JSON Schema annotation", | ||
path | ||
) | ||
) | ||
throw new Error(errors_.getJSONSchemaMissingAnnotationErrorMessage(path, ast)) | ||
} | ||
case "TemplateLiteral": { | ||
const regex = AST.getTemplateLiteralRegExp(ast) | ||
return { | ||
return merge({ | ||
type: "string", | ||
description: "a template literal", | ||
pattern: regex.source, | ||
...getJsonSchemaAnnotations(ast) | ||
} | ||
pattern: regex.source | ||
}, getJsonSchemaAnnotations(ast)) | ||
} | ||
@@ -576,14 +577,15 @@ case "Suspend": { | ||
if (Option.isNone(identifier)) { | ||
throw new Error( | ||
errors_.getErrorMessageWithPath( | ||
"Generating a JSON Schema for suspended schemas requires an identifier annotation", | ||
path | ||
) | ||
) | ||
throw new Error(errors_.getJSONSchemaMissingIdentifierAnnotationErrorMessage(path, ast)) | ||
} | ||
return go(ast.f(), $defs, true, path) | ||
} | ||
case "Transformation": | ||
return go(ast.from, $defs, true, path) | ||
case "Transformation": { | ||
// Properly handle S.parseJson transformations by focusing on | ||
// the 'to' side of the AST. This approach prevents the generation of useless schemas | ||
// derived from the 'from' side (type: string), ensuring the output matches the intended | ||
// complex schema type. | ||
const next = isParseJsonTransformation(ast.from) ? ast.to : ast.from | ||
return go(next, $defs, true, path) | ||
} | ||
} | ||
} |
@@ -5,3 +5,3 @@ /** | ||
import * as Arr from "effect/Array" | ||
import * as array_ from "effect/Array" | ||
import { TaggedError } from "effect/Data" | ||
@@ -16,3 +16,3 @@ import * as Effect from "effect/Effect" | ||
import * as Predicate from "effect/Predicate" | ||
import type { Concurrency, Mutable } from "effect/Types" | ||
import type { Concurrency } from "effect/Types" | ||
import * as AST from "./AST.js" | ||
@@ -30,41 +30,38 @@ import * as util_ from "./internal/util.js" | ||
export type ParseIssue = | ||
| Declaration | ||
// leaf | ||
| Type | ||
| Missing | ||
| Unexpected | ||
| Forbidden | ||
// composite | ||
| Pointer | ||
| Refinement | ||
| TupleType | ||
| TypeLiteral | ||
| Union | ||
| Transformation | ||
| Type | ||
| Forbidden | ||
| Composite | ||
/** | ||
* Error that occurs when a declaration has an error. | ||
* | ||
* @category model | ||
* @since 0.67.0 | ||
* @since 0.68.0 | ||
*/ | ||
export class Declaration { | ||
/** | ||
* @since 0.67.0 | ||
*/ | ||
readonly _tag = "Declaration" | ||
constructor(readonly ast: AST.Declaration, readonly actual: unknown, readonly error: ParseIssue) {} | ||
} | ||
export type SingleOrNonEmpty<A> = A | array_.NonEmptyReadonlyArray<A> | ||
/** | ||
* Error that occurs when a refinement has an error. | ||
* | ||
* @category model | ||
* @since 0.67.0 | ||
* @since 0.68.0 | ||
*/ | ||
export class Refinement { | ||
export type Path = SingleOrNonEmpty<PropertyKey> | ||
/** | ||
* @category model | ||
* @since 0.68.0 | ||
*/ | ||
export class Pointer { | ||
/** | ||
* @since 0.67.0 | ||
* @since 0.68.0 | ||
*/ | ||
readonly _tag = "Refinement" | ||
readonly _tag = "Pointer" | ||
constructor( | ||
readonly ast: AST.Refinement<AST.AST>, | ||
readonly path: Path, | ||
readonly actual: unknown, | ||
readonly kind: "From" | "Predicate", | ||
readonly error: ParseIssue | ||
readonly issue: ParseIssue | ||
) {} | ||
@@ -74,3 +71,3 @@ } | ||
/** | ||
* Error that occurs when an array or tuple has an error. | ||
* Error that occurs when an unexpected key or index is present. | ||
* | ||
@@ -80,12 +77,13 @@ * @category model | ||
*/ | ||
export class TupleType { | ||
export class Unexpected { | ||
/** | ||
* @since 0.67.0 | ||
*/ | ||
readonly _tag = "TupleType" | ||
readonly _tag = "Unexpected" | ||
constructor( | ||
readonly ast: AST.TupleType, | ||
readonly actual: unknown, | ||
readonly errors: Arr.NonEmptyReadonlyArray<Index>, | ||
readonly output: ReadonlyArray<unknown> = [] | ||
/** | ||
* @since 0.68.0 | ||
*/ | ||
readonly message?: string | ||
) {} | ||
@@ -95,3 +93,3 @@ } | ||
/** | ||
* The `Index` error indicates that there was an error at a specific index in an array or tuple. | ||
* Error that occurs when a required key or index is missing. | ||
* | ||
@@ -101,26 +99,39 @@ * @category model | ||
*/ | ||
export class Index { | ||
export class Missing { | ||
/** | ||
* @since 0.67.0 | ||
*/ | ||
readonly _tag = "Index" | ||
constructor(readonly index: number, readonly error: ParseIssue | Missing | Unexpected) {} | ||
readonly _tag = "Missing" | ||
/** | ||
* @since 0.68.0 | ||
*/ | ||
readonly actual = undefined | ||
constructor( | ||
/** | ||
* @since 0.68.0 | ||
*/ | ||
readonly ast: AST.Annotated, | ||
/** | ||
* @since 0.68.0 | ||
*/ | ||
readonly message?: string | ||
) {} | ||
} | ||
/** | ||
* Error that occurs when a type literal or record has an error. | ||
* Error that contains multiple issues. | ||
* | ||
* @category model | ||
* @since 0.67.0 | ||
* @since 0.68.0 | ||
*/ | ||
export class TypeLiteral { | ||
export class Composite { | ||
/** | ||
* @since 0.67.0 | ||
* @since 0.68.0 | ||
*/ | ||
readonly _tag = "TypeLiteral" | ||
readonly _tag = "Composite" | ||
constructor( | ||
readonly ast: AST.TypeLiteral, | ||
readonly ast: AST.Annotated, | ||
readonly actual: unknown, | ||
readonly errors: Arr.NonEmptyReadonlyArray<Key>, | ||
readonly output: { readonly [x: string]: unknown } = {} | ||
readonly issues: SingleOrNonEmpty<ParseIssue>, | ||
readonly output?: unknown | ||
) {} | ||
@@ -130,17 +141,11 @@ } | ||
/** | ||
* The `Key` variant of the `ParseIssue` type represents an error that occurs when a key in a type literal or record is invalid. | ||
* Returns `true` if the value is a `Composite`. | ||
* | ||
* @category model | ||
* @since 0.67.0 | ||
* @category guards | ||
* @since 0.68.0 | ||
*/ | ||
export class Key { | ||
/** | ||
* @since 0.67.0 | ||
*/ | ||
readonly _tag = "Key" | ||
constructor(readonly key: PropertyKey, readonly error: ParseIssue | Missing | Unexpected) {} | ||
} | ||
export const isComposite = (u: unknown): u is Composite => Predicate.hasProperty(u, "_tag") | ||
/** | ||
* Error that occurs when an unexpected key or index is present. | ||
* Error that occurs when a refinement has an error. | ||
* | ||
@@ -150,8 +155,13 @@ * @category model | ||
*/ | ||
export class Unexpected { | ||
export class Refinement { | ||
/** | ||
* @since 0.67.0 | ||
*/ | ||
readonly _tag = "Unexpected" | ||
constructor(readonly ast: AST.AST) {} | ||
readonly _tag = "Refinement" | ||
constructor( | ||
readonly ast: AST.Refinement, | ||
readonly actual: unknown, | ||
readonly kind: "From" | "Predicate", | ||
readonly issue: ParseIssue | ||
) {} | ||
} | ||
@@ -174,3 +184,3 @@ | ||
readonly kind: "Encoded" | "Transformation" | "Type", | ||
readonly error: ParseIssue | ||
readonly issue: ParseIssue | ||
) {} | ||
@@ -191,9 +201,7 @@ } | ||
readonly _tag = "Type" | ||
/** | ||
* @since 0.67.0 | ||
*/ | ||
readonly message: Option.Option<string> | ||
constructor(readonly ast: AST.AST, readonly actual: unknown, message?: string) { | ||
this.message = Option.fromNullable(message) | ||
} | ||
constructor( | ||
readonly ast: AST.Annotated, | ||
readonly actual: unknown, | ||
readonly message?: string | ||
) {} | ||
} | ||
@@ -212,66 +220,35 @@ | ||
readonly _tag = "Forbidden" | ||
/** | ||
* @since 0.67.0 | ||
*/ | ||
readonly message: Option.Option<string> | ||
constructor(readonly ast: AST.AST, readonly actual: unknown, message?: string) { | ||
this.message = Option.fromNullable(message) | ||
} | ||
constructor( | ||
readonly ast: AST.Annotated, | ||
readonly actual: unknown, | ||
readonly message?: string | ||
) {} | ||
} | ||
/** | ||
* Error that occurs when a required key or index is missing. | ||
* | ||
* @category model | ||
* @since 0.67.0 | ||
* @category type id | ||
* @since 0.68.0 | ||
*/ | ||
export class Missing { | ||
/** | ||
* @since 0.67.0 | ||
*/ | ||
readonly _tag = "Missing" | ||
} | ||
export const ParseErrorTypeId: unique symbol = Symbol.for("@effect/schema/ParseErrorTypeId") | ||
/** | ||
* @category constructors | ||
* @since 0.67.0 | ||
* @category type id | ||
* @since 0.68.0 | ||
*/ | ||
export const missing: Missing = new Missing() | ||
export type ParseErrorTypeId = typeof ParseErrorTypeId | ||
/** | ||
* Error that occurs when a member in a union has an error. | ||
* | ||
* @category model | ||
* @since 0.67.0 | ||
* @since 0.68.0 | ||
*/ | ||
export class Member { | ||
/** | ||
* @since 0.67.0 | ||
*/ | ||
readonly _tag = "Member" | ||
constructor(readonly ast: AST.AST, readonly error: ParseIssue) {} | ||
} | ||
export const isParseError = (u: unknown): u is ParseError => Predicate.hasProperty(u, ParseErrorTypeId) | ||
/** | ||
* Error that occurs when a union has an error. | ||
* | ||
* @category model | ||
* @since 0.67.0 | ||
*/ | ||
export class Union { | ||
export class ParseError extends TaggedError("ParseError")<{ readonly issue: ParseIssue }> { | ||
/** | ||
* @since 0.67.0 | ||
* @since 0.68.0 | ||
*/ | ||
readonly _tag = "Union" | ||
constructor( | ||
readonly ast: AST.Union, | ||
readonly actual: unknown, | ||
readonly errors: Arr.NonEmptyReadonlyArray<Type | TypeLiteral | Member> | ||
) {} | ||
} | ||
readonly [ParseErrorTypeId] = ParseErrorTypeId | ||
/** | ||
* @since 0.67.0 | ||
*/ | ||
export class ParseError extends TaggedError("ParseError")<{ readonly error: ParseIssue }> { | ||
get message() { | ||
@@ -284,3 +261,3 @@ return this.toString() | ||
toString() { | ||
return TreeFormatter.formatIssueSync(this.error) | ||
return TreeFormatter.formatIssueSync(this.issue) | ||
} | ||
@@ -308,3 +285,3 @@ /** | ||
*/ | ||
export const parseError = (issue: ParseIssue): ParseError => new ParseError({ error: issue }) | ||
export const parseError = (issue: ParseIssue): ParseError => new ParseError({ issue }) | ||
@@ -487,6 +464,6 @@ /** | ||
/** @internal */ | ||
export const mergeParseOptions = ( | ||
options: AST.ParseOptions | undefined, | ||
overrideOptions: AST.ParseOptions | number | undefined | ||
): AST.ParseOptions | undefined => { | ||
export const mergeInternalOptions = ( | ||
options: InternalOptions | undefined, | ||
overrideOptions: InternalOptions | number | undefined | ||
): InternalOptions | undefined => { | ||
if (overrideOptions === undefined || Predicate.isNumber(overrideOptions)) { | ||
@@ -498,6 +475,3 @@ return options | ||
} | ||
const out: Mutable<AST.ParseOptions> = {} | ||
out.errors = overrideOptions.errors ?? options.errors | ||
out.onExcessProperty = overrideOptions.onExcessProperty ?? options.onExcessProperty | ||
return out | ||
return { ...options, ...overrideOptions } | ||
} | ||
@@ -508,3 +482,3 @@ | ||
return (u: unknown, overrideOptions?: AST.ParseOptions): Either.Either<any, ParseIssue> => | ||
parser(u, mergeParseOptions(options, overrideOptions)) as any | ||
parser(u, mergeInternalOptions(options, overrideOptions)) as any | ||
} | ||
@@ -515,6 +489,3 @@ | ||
return (input: unknown, overrideOptions?: AST.ParseOptions) => | ||
Either.getOrThrowWith( | ||
parser(input, overrideOptions), | ||
(issue) => new Error(TreeFormatter.formatIssueSync(issue), { cause: issue }) | ||
) | ||
Either.getOrThrowWith(parser(input, overrideOptions), parseError) | ||
} | ||
@@ -531,6 +502,7 @@ | ||
return (input: unknown, overrideOptions?: AST.ParseOptions): Effect.Effect<any, ParseIssue, R> => | ||
parser(input, { ...mergeParseOptions(options, overrideOptions), isEffectAllowed: true }) | ||
parser(input, { ...mergeInternalOptions(options, overrideOptions), isEffectAllowed: true }) | ||
} | ||
/** | ||
* @throws `ParseError` | ||
* @category decoding | ||
@@ -586,2 +558,3 @@ * @since 0.67.0 | ||
/** | ||
* @throws `ParseError` | ||
* @category encoding | ||
@@ -682,2 +655,3 @@ * @since 0.67.0 | ||
/** | ||
* @throws `ParseError` | ||
* @category validation | ||
@@ -742,3 +716,3 @@ * @since 0.67.0 | ||
return (u: unknown, overrideOptions?: AST.ParseOptions | number): u is A => | ||
Either.isRight(parser(u, { exact: true, ...mergeParseOptions(options, overrideOptions) }) as any) | ||
Either.isRight(parser(u, { exact: true, ...mergeInternalOptions(options, overrideOptions) }) as any) | ||
} | ||
@@ -749,2 +723,3 @@ | ||
* | ||
* @throws `ParseError` | ||
* @category validation | ||
@@ -758,6 +733,6 @@ * @since 0.67.0 | ||
exact: true, | ||
...mergeParseOptions(options, overrideOptions) | ||
...mergeInternalOptions(options, overrideOptions) | ||
}) as any | ||
if (Either.isLeft(result)) { | ||
throw new Error(TreeFormatter.formatIssueSync(result.left), { cause: result.left }) | ||
throw parseError(result.left) | ||
} | ||
@@ -835,3 +810,7 @@ } | ||
} | ||
const parser = go(ast, isDecoding) | ||
const raw = go(ast, isDecoding) | ||
const parseOptionsAnnotation = AST.getParseOptionsAnnotation(ast) | ||
const parser: Parser = Option.isSome(parseOptionsAnnotation) | ||
? (i, options) => raw(i, mergeInternalOptions(options, parseOptionsAnnotation.value)) | ||
: raw | ||
memoMap.set(ast, parser) | ||
@@ -908,9 +887,3 @@ return parser | ||
: ast.encodeUnknown(...ast.typeParameters) | ||
return (i, options) => | ||
handleForbidden( | ||
mapError(parse(i, options ?? AST.defaultParseOption, ast), (e) => new Declaration(ast, i, e)), | ||
ast, | ||
i, | ||
options | ||
) | ||
return (i, options) => handleForbidden(parse(i, options ?? AST.defaultParseOption, ast), ast, i, options) | ||
} | ||
@@ -950,17 +923,19 @@ case "Literal": | ||
const elements = ast.elements.map((e) => goMemo(e.type, isDecoding)) | ||
const rest = ast.rest.map((ast) => goMemo(ast, isDecoding)) | ||
let requiredLen = ast.elements.filter((e) => !e.isOptional).length | ||
const rest = ast.rest.map((annotatedAST) => goMemo(annotatedAST.type, isDecoding)) | ||
let requiredTypes: Array<AST.Type> = ast.elements.filter((e) => !e.isOptional) | ||
if (ast.rest.length > 0) { | ||
requiredLen += ast.rest.length - 1 | ||
requiredTypes = requiredTypes.concat(ast.rest.slice(1)) | ||
} | ||
const expectedAST = AST.Union.make(ast.elements.map((_, i) => new AST.Literal(i))) | ||
const requiredLen = requiredTypes.length | ||
const expectedIndexes = ast.elements.length > 0 ? ast.elements.map((_, i) => i).join(" | ") : "never" | ||
const concurrency = getConcurrency(ast) | ||
const batching = getBatching(ast) | ||
return (input: unknown, options) => { | ||
if (!Arr.isArray(input)) { | ||
if (!array_.isArray(input)) { | ||
return Either.left(new Type(ast, input)) | ||
} | ||
const allErrors = options?.errors === "all" | ||
const es: Array<[number, Index]> = [] | ||
const es: Array<[number, ParseIssue]> = [] | ||
let stepKey = 0 | ||
const output: Array<[number, any]> = [] | ||
// --------------------------------------------- | ||
@@ -971,3 +946,3 @@ // handle missing indexes | ||
for (let i = len; i <= requiredLen - 1; i++) { | ||
const e = new Index(i, missing) | ||
const e = new Pointer(i, input, new Missing(requiredTypes[i - len])) | ||
if (allErrors) { | ||
@@ -977,3 +952,3 @@ es.push([stepKey++, e]) | ||
} else { | ||
return Either.left(new TupleType(ast, input, [e])) | ||
return Either.left(new Composite(ast, input, e, output)) | ||
} | ||
@@ -987,3 +962,3 @@ } | ||
for (let i = ast.elements.length; i <= len - 1; i++) { | ||
const e = new Index(i, new Unexpected(expectedAST)) | ||
const e = new Pointer(i, input, new Unexpected(input[i], `is unexpected, expected: ${expectedIndexes}`)) | ||
if (allErrors) { | ||
@@ -993,3 +968,3 @@ es.push([stepKey++, e]) | ||
} else { | ||
return Either.left(new TupleType(ast, input, [e])) | ||
return Either.left(new Composite(ast, input, e, output)) | ||
} | ||
@@ -999,3 +974,2 @@ } | ||
const output: Array<[number, any]> = [] | ||
let i = 0 | ||
@@ -1026,3 +1000,3 @@ type State = { | ||
// the input element is present but is not valid | ||
const e = new Index(i, eu.left) | ||
const e = new Pointer(i, input, eu.left) | ||
if (allErrors) { | ||
@@ -1032,3 +1006,3 @@ es.push([stepKey++, e]) | ||
} else { | ||
return Either.left(new TupleType(ast, input, [e], sortByIndex(output))) | ||
return Either.left(new Composite(ast, input, e, sortByIndex(output))) | ||
} | ||
@@ -1047,3 +1021,3 @@ } | ||
// the input element is present but is not valid | ||
const e = new Index(index, t.left) | ||
const e = new Pointer(index, input, t.left) | ||
if (allErrors) { | ||
@@ -1053,3 +1027,3 @@ es.push([nk, e]) | ||
} else { | ||
return Either.left(new TupleType(ast, input, [e], sortByIndex(output))) | ||
return Either.left(new Composite(ast, input, e, sortByIndex(output))) | ||
} | ||
@@ -1067,3 +1041,3 @@ } | ||
// --------------------------------------------- | ||
if (Arr.isNonEmptyReadonlyArray(rest)) { | ||
if (array_.isNonEmptyReadonlyArray(rest)) { | ||
const [head, ...tail] = rest | ||
@@ -1075,3 +1049,3 @@ for (; i < len - tail.length; i++) { | ||
if (Either.isLeft(eu)) { | ||
const e = new Index(i, eu.left) | ||
const e = new Pointer(i, input, eu.left) | ||
if (allErrors) { | ||
@@ -1081,3 +1055,3 @@ es.push([stepKey++, e]) | ||
} else { | ||
return Either.left(new TupleType(ast, input, [e], sortByIndex(output))) | ||
return Either.left(new Composite(ast, input, e, sortByIndex(output))) | ||
} | ||
@@ -1097,3 +1071,3 @@ } else { | ||
if (Either.isLeft(t)) { | ||
const e = new Index(index, t.left) | ||
const e = new Pointer(index, input, t.left) | ||
if (allErrors) { | ||
@@ -1103,3 +1077,3 @@ es.push([nk, e]) | ||
} else { | ||
return Either.left(new TupleType(ast, input, [e], sortByIndex(output))) | ||
return Either.left(new Composite(ast, input, e, sortByIndex(output))) | ||
} | ||
@@ -1127,3 +1101,3 @@ } else { | ||
// the input element is present but is not valid | ||
const e = new Index(i, eu.left) | ||
const e = new Pointer(i, input, eu.left) | ||
if (allErrors) { | ||
@@ -1133,3 +1107,3 @@ es.push([stepKey++, e]) | ||
} else { | ||
return Either.left(new TupleType(ast, input, [e], sortByIndex(output))) | ||
return Either.left(new Composite(ast, input, e, sortByIndex(output))) | ||
} | ||
@@ -1149,3 +1123,3 @@ } | ||
// the input element is present but is not valid | ||
const e = new Index(index, t.left) | ||
const e = new Pointer(index, input, t.left) | ||
if (allErrors) { | ||
@@ -1155,3 +1129,3 @@ es.push([nk, e]) | ||
} else { | ||
return Either.left(new TupleType(ast, input, [e], sortByIndex(output))) | ||
return Either.left(new Composite(ast, input, e, sortByIndex(output))) | ||
} | ||
@@ -1172,4 +1146,4 @@ } | ||
const computeResult = ({ es, output }: State) => | ||
Arr.isNonEmptyArray(es) ? | ||
Either.left(new TupleType(ast, input, sortByIndex(es), sortByIndex(output))) : | ||
array_.isNonEmptyArray(es) ? | ||
Either.left(new Composite(ast, input, sortByIndex(es), sortByIndex(output))) : | ||
Either.right(sortByIndex(output)) | ||
@@ -1180,4 +1154,4 @@ if (queue && queue.length > 0) { | ||
const state: State = { | ||
es: Arr.copy(es), | ||
output: Arr.copy(output) | ||
es: array_.copy(es), | ||
output: array_.copy(output) | ||
} | ||
@@ -1227,3 +1201,3 @@ return Effect.flatMap( | ||
const allErrors = options?.errors === "all" | ||
const es: Array<[number, Key]> = [] | ||
const es: Array<[number, ParseIssue]> = [] | ||
let stepKey = 0 | ||
@@ -1236,3 +1210,3 @@ | ||
const onExcessPropertyPreserve = options?.onExcessProperty === "preserve" | ||
const output: any = {} | ||
const output: Record<PropertyKey, unknown> = {} | ||
let inputKeys: Array<PropertyKey> | undefined | ||
@@ -1246,3 +1220,7 @@ if (onExcessPropertyError || onExcessPropertyPreserve) { | ||
if (onExcessPropertyError) { | ||
const e = new Key(key, new Unexpected(expectedAST)) | ||
const e = new Pointer( | ||
key, | ||
input, | ||
new Unexpected(input[key], `is unexpected, expected: ${String(expectedAST)}`) | ||
) | ||
if (allErrors) { | ||
@@ -1252,3 +1230,3 @@ es.push([stepKey++, e]) | ||
} else { | ||
return Either.left(new TypeLiteral(ast, input, [e], output)) | ||
return Either.left(new Composite(ast, input, e, output)) | ||
} | ||
@@ -1283,3 +1261,3 @@ } else { | ||
} else if (isExact) { | ||
const e = new Key(name, missing) | ||
const e = new Pointer(name, input, new Missing(ps)) | ||
if (allErrors) { | ||
@@ -1289,3 +1267,3 @@ es.push([stepKey++, e]) | ||
} else { | ||
return Either.left(new TypeLiteral(ast, input, [e], output)) | ||
return Either.left(new Composite(ast, input, e, output)) | ||
} | ||
@@ -1299,3 +1277,3 @@ } | ||
if (Either.isLeft(eu)) { | ||
const e = new Key(name, hasKey ? eu.left : missing) | ||
const e = new Pointer(name, input, hasKey ? eu.left : new Missing(ps)) | ||
if (allErrors) { | ||
@@ -1305,3 +1283,3 @@ es.push([stepKey++, e]) | ||
} else { | ||
return Either.left(new TypeLiteral(ast, input, [e], output)) | ||
return Either.left(new Composite(ast, input, e, output)) | ||
} | ||
@@ -1320,3 +1298,3 @@ } | ||
if (Either.isLeft(t)) { | ||
const e = new Key(index, hasKey ? t.left : missing) | ||
const e = new Pointer(index, input, hasKey ? t.left : new Missing(ps)) | ||
if (allErrors) { | ||
@@ -1326,3 +1304,3 @@ es.push([nk, e]) | ||
} else { | ||
return Either.left(new TypeLiteral(ast, input, [e], output)) | ||
return Either.left(new Composite(ast, input, e, output)) | ||
} | ||
@@ -1358,3 +1336,3 @@ } | ||
if (Either.isLeft(veu)) { | ||
const e = new Key(key, veu.left) | ||
const e = new Pointer(key, input, veu.left) | ||
if (allErrors) { | ||
@@ -1364,3 +1342,3 @@ es.push([stepKey++, e]) | ||
} else { | ||
return Either.left(new TypeLiteral(ast, input, [e], output)) | ||
return Either.left(new Composite(ast, input, e, output)) | ||
} | ||
@@ -1384,3 +1362,3 @@ } else { | ||
if (Either.isLeft(tv)) { | ||
const e = new Key(index, tv.left) | ||
const e = new Pointer(index, input, tv.left) | ||
if (allErrors) { | ||
@@ -1390,3 +1368,3 @@ es.push([nk, e]) | ||
} else { | ||
return Either.left(new TypeLiteral(ast, input, [e], output)) | ||
return Either.left(new Composite(ast, input, e, output)) | ||
} | ||
@@ -1410,4 +1388,4 @@ } else { | ||
const computeResult = ({ es, output }: State) => { | ||
if (Arr.isNonEmptyArray(es)) { | ||
return Either.left(new TypeLiteral(ast, input, sortByIndex(es), output)) | ||
if (array_.isNonEmptyArray(es)) { | ||
return Either.left(new Composite(ast, input, sortByIndex(es), output)) | ||
} | ||
@@ -1436,3 +1414,3 @@ if (options?.propertyOrder === "original") { | ||
const state: State = { | ||
es: Arr.copy(es), | ||
es: array_.copy(es), | ||
output: Object.assign({}, output) | ||
@@ -1460,3 +1438,3 @@ } | ||
return (input, options) => { | ||
const es: Array<[number, Type | TypeLiteral | Member]> = [] | ||
const es: Array<[number, ParseIssue]> = [] | ||
let stepKey = 0 | ||
@@ -1481,3 +1459,3 @@ let candidates: Array<AST.AST> = [] | ||
stepKey++, | ||
new TypeLiteral( | ||
new Composite( | ||
new AST.TypeLiteral([ | ||
@@ -1487,3 +1465,3 @@ new AST.PropertySignature(name, literals, false, true) | ||
input, | ||
[new Key(name, new Type(literals, input[name]))] | ||
new Pointer(name, input, new Type(literals, input[name])) | ||
) | ||
@@ -1494,10 +1472,9 @@ ]) | ||
const literals = AST.Union.make(searchTree.keys[name].literals) | ||
const fakeps = new AST.PropertySignature(name, literals, false, true) // TODO: inherit message annotation from the union? | ||
es.push([ | ||
stepKey++, | ||
new TypeLiteral( | ||
new AST.TypeLiteral([ | ||
new AST.PropertySignature(name, literals, false, true) | ||
], []), | ||
new Composite( | ||
new AST.TypeLiteral([fakeps], []), | ||
input, | ||
[new Key(name, missing)] | ||
new Pointer(name, input, new Missing(fakeps)) | ||
) | ||
@@ -1535,3 +1512,3 @@ ]) | ||
} else { | ||
es.push([stepKey++, new Member(candidate, eu.left)]) | ||
es.push([stepKey++, eu.left]) | ||
} | ||
@@ -1553,3 +1530,3 @@ } else { | ||
} else { | ||
state.es.push([nk, new Member(candidate, t.left)]) | ||
state.es.push([nk, t.left]) | ||
} | ||
@@ -1568,8 +1545,8 @@ return Effect.void | ||
const computeResult = (es: State["es"]) => | ||
Arr.isNonEmptyArray(es) ? | ||
array_.isNonEmptyArray(es) ? | ||
es.length === 1 && es[0][1]._tag === "Type" ? | ||
Either.left(es[0][1]) : | ||
Either.left(new Union(ast, input, sortByIndex(es))) : | ||
Either.left(new Composite(ast, input, sortByIndex(es))) : | ||
// this should never happen | ||
Either.left(new Type(AST.neverKeyword, input)) | ||
Either.left(new Type(ast, input)) | ||
@@ -1579,3 +1556,3 @@ if (queue && queue.length > 0) { | ||
return Effect.suspend(() => { | ||
const state: State = { es: Arr.copy(es) } | ||
const state: State = { es: array_.copy(es) } | ||
return Effect.flatMap( | ||
@@ -1728,8 +1705,10 @@ Effect.forEach(cqueue, (f) => f(state), { concurrency, batching, discard: true }), | ||
const compare = ([a]: [number, ...Array<unknown>], [b]: [number, ...Array<unknown>]) => a > b ? 1 : a < b ? -1 : 0 | ||
function sortByIndex<T>( | ||
es: Arr.NonEmptyArray<[number, T]> | ||
): Arr.NonEmptyArray<T> | ||
es: array_.NonEmptyArray<[number, T]> | ||
): array_.NonEmptyArray<T> | ||
function sortByIndex<T>(es: Array<[number, T]>): Array<T> | ||
function sortByIndex(es: Array<[number, any]>): any { | ||
return es.sort(([a], [b]) => a > b ? 1 : a < b ? -1 : 0).map(([_, a]) => a) | ||
function sortByIndex(es: Array<[number, any]>) { | ||
return es.sort(compare).map((t) => t[1]) | ||
} | ||
@@ -1736,0 +1715,0 @@ |
@@ -62,5 +62,2 @@ /** | ||
const getPrettyErrorMessage = (message: string, path: ReadonlyArray<PropertyKey>) => | ||
errors_.getErrorMessageWithPath(`cannot build a Pretty for ${message}`, path) | ||
/** | ||
@@ -75,7 +72,7 @@ * @since 0.67.0 | ||
} | ||
throw new Error(getPrettyErrorMessage(`a declaration without annotations (${ast})`, path)) | ||
throw new Error(errors_.getPrettyMissingAnnotationErrorMessage(path, ast)) | ||
}, | ||
"VoidKeyword": getMatcher(() => "void(0)"), | ||
"NeverKeyword": getMatcher(() => { | ||
throw new Error("cannot pretty print a `never` value") | ||
throw new Error(errors_.getPrettyNeverErrorMessage) | ||
}), | ||
@@ -105,3 +102,3 @@ "Literal": getMatcher((literal: AST.LiteralValue): string => | ||
const elements = ast.elements.map((e, i) => go(e.type, path.concat(i))) | ||
const rest = ast.rest.map((ast) => go(ast, path)) | ||
const rest = ast.rest.map((annotatedAST) => go(annotatedAST.type, path)) | ||
return (input: ReadonlyArray<unknown>) => { | ||
@@ -195,2 +192,5 @@ const output: Array<string> = [] | ||
const index = types.findIndex(([is]) => is(a)) | ||
if (index === -1) { | ||
throw new Error(errors_.getPrettyNoMatchingSchemaErrorMessage(a, path, ast)) | ||
} | ||
return types[index][1](a) | ||
@@ -197,0 +197,0 @@ } |
/** | ||
* @since 0.67.0 | ||
* | ||
* Serializable represents an object that has self-contained Schema(s) | ||
*/ | ||
@@ -21,2 +19,8 @@ import type * as Effect from "effect/Effect" | ||
/** | ||
* The `Serializable` trait, part of the `@effect/schema/Serializable` module, | ||
* enables objects to have self-contained schema(s) for serialization. This | ||
* functionality is particularly beneficial in scenarios where objects need to | ||
* be consistently serialized and deserialized across various runtime | ||
* environments or sent over network communications. | ||
* | ||
* @since 0.67.0 | ||
@@ -35,2 +39,10 @@ * @category model | ||
/** | ||
* @since 0.68.15 | ||
*/ | ||
export type Type<T> = T extends Serializable<infer A, infer _I, infer _R> ? A : never | ||
/** | ||
* @since 0.68.15 | ||
*/ | ||
export type Encoded<T> = T extends Serializable<infer _A, infer I, infer _R> ? I : never | ||
/** | ||
* @since 0.67.0 | ||
@@ -54,9 +66,14 @@ */ | ||
/** | ||
* The `WithResult` trait is designed to encapsulate the outcome of an | ||
* operation, distinguishing between success and failure cases. Each case is | ||
* associated with a schema that defines the structure and types of the success | ||
* or failure data. | ||
* | ||
* @since 0.67.0 | ||
* @category model | ||
*/ | ||
export interface WithResult<SuccessA, SuccessI, FailureA, FailureI, SuccessAndFailureR> { | ||
export interface WithResult<Success, SuccessEncoded, Failure, FailureEncoded, SuccessAndFailureR> { | ||
readonly [symbolResult]: { | ||
readonly Success: Schema.Schema<SuccessA, SuccessI, SuccessAndFailureR> | ||
readonly Failure: Schema.Schema<FailureA, FailureI, SuccessAndFailureR> | ||
readonly Success: Schema.Schema<Success, SuccessEncoded, SuccessAndFailureR> | ||
readonly Failure: Schema.Schema<Failure, FailureEncoded, SuccessAndFailureR> | ||
} | ||
@@ -71,5 +88,15 @@ } | ||
/** | ||
* @since 0.68.16 | ||
*/ | ||
export type Success<T> = T extends WithResult<infer _A, infer _I, infer _E, infer _EI, infer _R> ? _A : never | ||
/** | ||
* @since 0.68.16 | ||
*/ | ||
export type Error<T> = T extends WithResult<infer _A, infer _I, infer _E, infer _EI, infer _R> ? _E : never | ||
/** | ||
* @since 0.67.0 | ||
*/ | ||
export type Context<T> = T extends WithResult<infer _A, infer _I, infer _E, infer _EI, infer R> ? R : never | ||
export type Context<T> = T extends WithResult<infer _SA, infer _SI, infer _FA, infer _FI, infer R> ? R : never | ||
} | ||
@@ -81,5 +108,4 @@ | ||
*/ | ||
export const failureSchema = <A, I, E, EI, R>( | ||
self: WithResult<A, I, E, EI, R> | ||
): Schema.Schema<E, EI, R> => self[symbolResult].Failure | ||
export const failureSchema = <SA, SI, FA, FI, R>(self: WithResult<SA, SI, FA, FI, R>): Schema.Schema<FA, FI, R> => | ||
self[symbolResult].Failure | ||
@@ -90,5 +116,4 @@ /** | ||
*/ | ||
export const successSchema = <A, I, E, EI, R>( | ||
self: WithResult<A, I, E, EI, R> | ||
): Schema.Schema<A, I, R> => self[symbolResult].Success | ||
export const successSchema = <SA, SI, FA, FI, R>(self: WithResult<SA, SI, FA, FI, R>): Schema.Schema<SA, SI, R> => | ||
self[symbolResult].Success | ||
@@ -104,5 +129,7 @@ const exitSchemaCache = globalValue( | ||
*/ | ||
export const exitSchema = <A, I, E, EI, R>( | ||
self: WithResult<A, I, E, EI, R> | ||
): Schema.Schema<Exit.Exit<A, E>, Schema.ExitEncoded<I, EI>, R> => { | ||
export const exitSchema = <SA, SI, FA, FI, R>(self: WithResult<SA, SI, FA, FI, R>): Schema.Schema< | ||
Exit.Exit<SA, FA>, | ||
Schema.ExitEncoded<SI, FI>, | ||
R | ||
> => { | ||
const proto = Object.getPrototypeOf(self) | ||
@@ -125,14 +152,11 @@ if (!(symbolResult in proto)) { | ||
export interface SerializableWithResult< | ||
Self, | ||
FieldsI, | ||
FieldsR, | ||
SuccessA, | ||
SuccessI, | ||
FailureA, | ||
FailureI, | ||
A, | ||
I, | ||
R, | ||
Success, | ||
SuccessEncoded, | ||
Failure, | ||
FailureEncoded, | ||
SuccessAndFailureR | ||
> extends | ||
Serializable<Self, FieldsI, FieldsR>, | ||
WithResult<SuccessA, SuccessI, FailureA, FailureI, SuccessAndFailureR> | ||
{} | ||
> extends Serializable<A, I, R>, WithResult<Success, SuccessEncoded, Failure, FailureEncoded, SuccessAndFailureR> {} | ||
@@ -156,5 +180,4 @@ /** | ||
*/ | ||
export const serialize = <A, I, R>( | ||
self: Serializable<A, I, R> | ||
): Effect.Effect<I, ParseResult.ParseError, R> => Schema.encode(self[symbol])(self as A) | ||
export const serialize = <A, I, R>(self: Serializable<A, I, R>): Effect.Effect<I, ParseResult.ParseError, R> => | ||
Schema.encodeUnknown(self[symbol])(self) | ||
@@ -166,15 +189,9 @@ /** | ||
export const deserialize: { | ||
( | ||
value: unknown | ||
): <A, I, R>(self: Serializable<A, I, R>) => Effect.Effect<A, ParseResult.ParseError, R> | ||
(value: unknown): <A, I, R>(self: Serializable<A, I, R>) => Effect.Effect<A, ParseResult.ParseError, R> | ||
<A, I, R>(self: Serializable<A, I, R>, value: unknown): Effect.Effect<A, ParseResult.ParseError, R> | ||
} = dual< | ||
(value: unknown) => <A, I, R>( | ||
self: Serializable<A, I, R> | ||
) => Effect.Effect<A, ParseResult.ParseError, R>, | ||
<A, I, R>( | ||
self: Serializable<A, I, R>, | ||
value: unknown | ||
) => Effect.Effect<A, ParseResult.ParseError, R> | ||
>(2, (self, value) => Schema.decodeUnknown(self[symbol])(value)) | ||
} = dual( | ||
2, | ||
<A, I, R>(self: Serializable<A, I, R>, value: unknown): Effect.Effect<A, ParseResult.ParseError, R> => | ||
Schema.decodeUnknown(self[symbol])(value) | ||
) | ||
@@ -186,18 +203,11 @@ /** | ||
export const serializeFailure: { | ||
<E>( | ||
value: E | ||
): <A, I, EI, R>(self: WithResult<A, I, E, EI, R>) => Effect.Effect<EI, ParseResult.ParseError, R> | ||
<A, I, E, EI, R>( | ||
self: WithResult<A, I, E, EI, R>, | ||
value: E | ||
): Effect.Effect<EI, ParseResult.ParseError, R> | ||
} = dual< | ||
<E>(value: E) => <A, I, EI, R>( | ||
self: WithResult<A, I, E, EI, R> | ||
) => Effect.Effect<EI, ParseResult.ParseError, R>, | ||
<A, I, E, EI, R>( | ||
self: WithResult<A, I, E, EI, R>, | ||
value: E | ||
) => Effect.Effect<EI, ParseResult.ParseError, R> | ||
>(2, (self, value) => Schema.encode(self[symbolResult].Failure)(value)) | ||
<FA>(value: FA): <SA, SI, FI, R>( | ||
self: WithResult<SA, SI, FA, FI, R> | ||
) => Effect.Effect<FI, ParseResult.ParseError, R> | ||
<SA, SI, FA, FI, R>(self: WithResult<SA, SI, FA, FI, R>, value: FA): Effect.Effect<FI, ParseResult.ParseError, R> | ||
} = dual( | ||
2, | ||
<SA, SI, FA, FI, R>(self: WithResult<SA, SI, FA, FI, R>, value: FA): Effect.Effect<FI, ParseResult.ParseError, R> => | ||
Schema.encode(self[symbolResult].Failure)(value) | ||
) | ||
@@ -209,18 +219,13 @@ /** | ||
export const deserializeFailure: { | ||
(value: unknown): <A, I, E, EI, R>( | ||
self: WithResult<A, I, E, EI, R> | ||
) => Effect.Effect<E, ParseResult.ParseError, R> | ||
<A, I, E, EI, R>( | ||
self: WithResult<A, I, E, EI, R>, | ||
( | ||
value: unknown | ||
): Effect.Effect<E, ParseResult.ParseError, R> | ||
} = dual< | ||
(value: unknown) => <A, I, E, EI, R>( | ||
self: WithResult<A, I, E, EI, R> | ||
) => Effect.Effect<E, ParseResult.ParseError, R>, | ||
<A, I, E, EI, R>( | ||
self: WithResult<A, I, E, EI, R>, | ||
): <SA, SI, FA, FI, R>(self: WithResult<SA, SI, FA, FI, R>) => Effect.Effect<FA, ParseResult.ParseError, R> | ||
<SA, SI, FA, FI, R>(self: WithResult<SA, SI, FA, FI, R>, value: unknown): Effect.Effect<FA, ParseResult.ParseError, R> | ||
} = dual( | ||
2, | ||
<SA, SI, FA, FI, R>( | ||
self: WithResult<SA, SI, FA, FI, R>, | ||
value: unknown | ||
) => Effect.Effect<E, ParseResult.ParseError, R> | ||
>(2, (self, value) => Schema.decodeUnknown(self[symbolResult].Failure)(value)) | ||
): Effect.Effect<FA, ParseResult.ParseError, R> => Schema.decodeUnknown(self[symbolResult].Failure)(value) | ||
) | ||
@@ -232,18 +237,11 @@ /** | ||
export const serializeSuccess: { | ||
<A>( | ||
value: A | ||
): <I, E, EI, R>(self: WithResult<A, I, E, EI, R>) => Effect.Effect<I, ParseResult.ParseError, R> | ||
<A, I, E, EI, R>( | ||
self: WithResult<A, I, E, EI, R>, | ||
value: A | ||
): Effect.Effect<I, ParseResult.ParseError, R> | ||
} = dual< | ||
<A>(value: A) => <I, E, EI, R>( | ||
self: WithResult<A, I, E, EI, R> | ||
) => Effect.Effect<I, ParseResult.ParseError, R>, | ||
<A, I, E, EI, R>( | ||
self: WithResult<A, I, E, EI, R>, | ||
value: A | ||
) => Effect.Effect<I, ParseResult.ParseError, R> | ||
>(2, (self, value) => Schema.encode(self[symbolResult].Success)(value)) | ||
<SA>(value: SA): <SI, FA, FI, R>( | ||
self: WithResult<SA, SI, FA, FI, R> | ||
) => Effect.Effect<SI, ParseResult.ParseError, R> | ||
<SA, SI, FA, FI, R>(self: WithResult<SA, SI, FA, FI, R>, value: SA): Effect.Effect<SI, ParseResult.ParseError, R> | ||
} = dual( | ||
2, | ||
<SA, SI, FA, FI, R>(self: WithResult<SA, SI, FA, FI, R>, value: SA): Effect.Effect<SI, ParseResult.ParseError, R> => | ||
Schema.encode(self[symbolResult].Success)(value) | ||
) | ||
@@ -255,20 +253,13 @@ /** | ||
export const deserializeSuccess: { | ||
( | ||
(value: unknown): <SA, SI, FA, FI, R>( | ||
self: WithResult<SA, SI, FA, FI, R> | ||
) => Effect.Effect<SA, ParseResult.ParseError, R> | ||
<SA, SI, FA, FI, R>(self: WithResult<SA, SI, FA, FI, R>, value: unknown): Effect.Effect<SA, ParseResult.ParseError, R> | ||
} = dual( | ||
2, | ||
<SA, SI, FA, FI, R>( | ||
self: WithResult<SA, SI, FA, FI, R>, | ||
value: unknown | ||
): <A, I, E, EI, R>( | ||
self: WithResult<A, I, E, EI, R> | ||
) => Effect.Effect<A, ParseResult.ParseError, R> | ||
<A, I, E, EI, R>( | ||
self: WithResult<A, I, E, EI, R>, | ||
value: unknown | ||
): Effect.Effect<A, ParseResult.ParseError, R> | ||
} = dual< | ||
(value: unknown) => <A, I, E, EI, R>( | ||
self: WithResult<A, I, E, EI, R> | ||
) => Effect.Effect<A, ParseResult.ParseError, R>, | ||
<A, I, E, EI, R>( | ||
self: WithResult<A, I, E, EI, R>, | ||
value: unknown | ||
) => Effect.Effect<A, ParseResult.ParseError, R> | ||
>(2, (self, value) => Schema.decodeUnknown(self[symbolResult].Success)(value)) | ||
): Effect.Effect<SA, ParseResult.ParseError, R> => Schema.decodeUnknown(self[symbolResult].Success)(value) | ||
) | ||
@@ -280,15 +271,13 @@ /** | ||
export const serializeExit: { | ||
<A, E>( | ||
value: Exit.Exit<A, E> | ||
): <I, EI, R>( | ||
self: WithResult<A, I, E, EI, R> | ||
) => Effect.Effect<Schema.ExitEncoded<I, EI>, ParseResult.ParseError, R> | ||
<A, I, E, EI, R>( | ||
self: WithResult<A, I, E, EI, R>, | ||
value: Exit.Exit<A, E> | ||
): Effect.Effect<Schema.ExitEncoded<I, EI>, ParseResult.ParseError, R> | ||
} = dual(2, <A, I, E, EI, R>( | ||
self: WithResult<A, I, E, EI, R>, | ||
value: Exit.Exit<A, E> | ||
): Effect.Effect<Schema.ExitEncoded<I, EI>, ParseResult.ParseError, R> => Schema.encode(exitSchema(self))(value)) | ||
<SA, FA>(value: Exit.Exit<SA, FA>): <SI, FI, R>( | ||
self: WithResult<SA, SI, FA, FI, R> | ||
) => Effect.Effect<Schema.ExitEncoded<SI, FI>, ParseResult.ParseError, R> | ||
<SA, SI, FA, FI, R>( | ||
self: WithResult<SA, SI, FA, FI, R>, | ||
value: Exit.Exit<SA, FA> | ||
): Effect.Effect<Schema.ExitEncoded<SI, FI>, ParseResult.ParseError, R> | ||
} = dual(2, <SA, SI, FA, FI, R>( | ||
self: WithResult<SA, SI, FA, FI, R>, | ||
value: Exit.Exit<SA, FA> | ||
): Effect.Effect<Schema.ExitEncoded<SI, FI>, ParseResult.ParseError, R> => Schema.encode(exitSchema(self))(value)) | ||
@@ -300,12 +289,12 @@ /** | ||
export const deserializeExit: { | ||
(value: unknown): <A, I, E, EI, R>( | ||
self: WithResult<A, I, E, EI, R> | ||
) => Effect.Effect<Exit.Exit<A, E>, ParseResult.ParseError, R> | ||
<A, I, E, EI, R>( | ||
self: WithResult<A, I, E, EI, R>, | ||
(value: unknown): <SA, SI, FA, FI, R>( | ||
self: WithResult<SA, SI, FA, FI, R> | ||
) => Effect.Effect<Exit.Exit<SA, FA>, ParseResult.ParseError, R> | ||
<SA, SI, FA, FI, R>( | ||
self: WithResult<SA, SI, FA, FI, R>, | ||
value: unknown | ||
): Effect.Effect<Exit.Exit<A, E>, ParseResult.ParseError, R> | ||
} = dual(2, <A, I, E, EI, R>( | ||
self: WithResult<A, I, E, EI, R>, | ||
): Effect.Effect<Exit.Exit<SA, FA>, ParseResult.ParseError, R> | ||
} = dual(2, <SA, SI, FA, FI, R>( | ||
self: WithResult<SA, SI, FA, FI, R>, | ||
value: unknown | ||
): Effect.Effect<Exit.Exit<A, E>, ParseResult.ParseError, R> => Schema.decodeUnknown(exitSchema(self))(value)) | ||
): Effect.Effect<Exit.Exit<SA, FA>, ParseResult.ParseError, R> => Schema.decodeUnknown(exitSchema(self))(value)) |
@@ -42,3 +42,3 @@ /** | ||
*/ | ||
export const formatError = (error: ParseResult.ParseError): Effect.Effect<string> => formatIssue(error.error) | ||
export const formatError = (error: ParseResult.ParseError): Effect.Effect<string> => formatIssue(error.issue) | ||
@@ -49,3 +49,3 @@ /** | ||
*/ | ||
export const formatErrorSync = (error: ParseResult.ParseError): string => formatIssueSync(error.error) | ||
export const formatErrorSync = (error: ParseResult.ParseError): string => formatIssueSync(error.issue) | ||
@@ -87,62 +87,58 @@ const drawTree = (tree: Tree<string>): string => tree.value + draw("\n", tree.forest) | ||
const getInnerMessage = ( | ||
issue: ParseResult.ParseIssue | ||
): Effect.Effect<string, Cause.NoSuchElementException> => { | ||
switch (issue._tag) { | ||
case "Refinement": { | ||
if (issue.kind === "From") { | ||
return getMessage(issue.error) | ||
} | ||
break | ||
} | ||
case "Transformation": { | ||
return getMessage(issue.error) | ||
} | ||
} | ||
return Option.none() | ||
const getAnnotated = (issue: ParseResult.ParseIssue): Option.Option<AST.Annotated> => | ||
"ast" in issue ? Option.some(issue.ast) : Option.none() | ||
interface CurrentMessage { | ||
readonly message: string | ||
readonly override: boolean | ||
} | ||
const getCurrentMessage: ( | ||
const getCurrentMessage = ( | ||
issue: ParseResult.ParseIssue | ||
) => Effect.Effect<{ message: string; override: boolean }, Cause.NoSuchElementException> = ( | ||
issue: ParseResult.ParseIssue | ||
) => | ||
AST.getMessageAnnotation(issue.ast).pipe(Effect.flatMap((annotation) => { | ||
const out = annotation(issue) | ||
return Predicate.isString(out) | ||
? Effect.succeed({ message: out, override: false }) | ||
: Effect.isEffect(out) | ||
? Effect.map(out, (message) => ({ message, override: false })) | ||
: Predicate.isString(out.message) | ||
? Effect.succeed({ message: out.message, override: out.override }) | ||
: Effect.map(out.message, (message) => ({ message, override: out.override })) | ||
})) | ||
): Effect.Effect<CurrentMessage, Cause.NoSuchElementException> => | ||
getAnnotated(issue).pipe( | ||
Option.flatMap(AST.getMessageAnnotation), | ||
Effect.flatMap((annotation) => { | ||
const out = annotation(issue) | ||
return Predicate.isString(out) | ||
? Effect.succeed({ message: out, override: false }) | ||
: Effect.isEffect(out) | ||
? Effect.map(out, (message) => ({ message, override: false })) | ||
: Predicate.isString(out.message) | ||
? Effect.succeed({ message: out.message, override: out.override }) | ||
: Effect.map(out.message, (message) => ({ message, override: out.override })) | ||
}) | ||
) | ||
const createParseIssueGuard = | ||
<T extends ParseResult.ParseIssue["_tag"]>(tag: T) => | ||
(issue: ParseResult.ParseIssue): issue is Extract<ParseResult.ParseIssue, { _tag: T }> => issue._tag === tag | ||
const isComposite = createParseIssueGuard("Composite") | ||
const isRefinement = createParseIssueGuard("Refinement") | ||
const isTransformation = createParseIssueGuard("Transformation") | ||
/** @internal */ | ||
export const getMessage: ( | ||
issue: ParseResult.ParseIssue | ||
) => Effect.Effect<string, Cause.NoSuchElementException> = (issue: ParseResult.ParseIssue) => { | ||
const current = getCurrentMessage(issue) | ||
return getInnerMessage(issue).pipe( | ||
Effect.flatMap((inner) => Effect.map(current, (current) => current.override ? current.message : inner)), | ||
Effect.catchAll(() => | ||
Effect.flatMap(current, (current) => { | ||
if ( | ||
!current.override && ( | ||
(issue._tag === "Refinement" && issue.kind !== "Predicate") || | ||
(issue._tag === "Transformation" && issue.kind !== "Transformation") | ||
) | ||
) { | ||
return Option.none() | ||
} | ||
return Effect.succeed(current.message) | ||
}) | ||
) | ||
) => Effect.Effect<string, Cause.NoSuchElementException> = (issue: ParseResult.ParseIssue) => | ||
getCurrentMessage(issue).pipe( | ||
Effect.flatMap((currentMessage) => { | ||
const useInnerMessage = !currentMessage.override && ( | ||
isComposite(issue) || | ||
(isRefinement(issue) && issue.kind === "From") || | ||
(isTransformation(issue) && issue.kind !== "Transformation") | ||
) | ||
return useInnerMessage | ||
? isTransformation(issue) || isRefinement(issue) ? getMessage(issue.issue) : Option.none() | ||
: Effect.succeed(currentMessage.message) | ||
}) | ||
) | ||
} | ||
const getParseIssueTitleAnnotation = (issue: ParseResult.ParseIssue): Option.Option<string> => | ||
Option.filterMap( | ||
AST.getParseIssueTitleAnnotation(issue.ast), | ||
(annotation) => Option.fromNullable(annotation(issue)) | ||
getAnnotated(issue).pipe( | ||
Option.flatMap(AST.getParseIssueTitleAnnotation), | ||
Option.filterMap( | ||
(annotation) => Option.fromNullable(annotation(issue)) | ||
) | ||
) | ||
@@ -154,13 +150,27 @@ | ||
Effect.orElse(() => getParseIssueTitleAnnotation(e)), | ||
Effect.orElse(() => e.message), | ||
Effect.catchAll(() => Effect.succeed(`Expected ${e.ast.toString(true)}, actual ${util_.formatUnknown(e.actual)}`)) | ||
Effect.catchAll(() => | ||
Effect.succeed(e.message ?? `Expected ${String(e.ast)}, actual ${util_.formatUnknown(e.actual)}`) | ||
) | ||
) | ||
const getParseIssueTitle = (issue: ParseResult.ParseIssue): string => | ||
Option.getOrElse(getParseIssueTitleAnnotation(issue), () => String(issue.ast)) | ||
const getParseIssueTitle = ( | ||
issue: ParseResult.Forbidden | ParseResult.Transformation | ParseResult.Refinement | ParseResult.Composite | ||
): string => Option.getOrElse(getParseIssueTitleAnnotation(issue), () => String(issue.ast)) | ||
/** @internal */ | ||
export const formatForbiddenMessage = (e: ParseResult.Forbidden): string => | ||
Option.getOrElse(e.message, () => "is forbidden") | ||
export const formatForbiddenMessage = (e: ParseResult.Forbidden): string => e.message ?? "is forbidden" | ||
/** @internal */ | ||
export const formatUnexpectedMessage = (e: ParseResult.Unexpected): string => e.message ?? "is unexpected" | ||
/** @internal */ | ||
export const formatMissingMessage = (e: ParseResult.Missing): Effect.Effect<string> => | ||
AST.getMissingMessageAnnotation(e.ast).pipe( | ||
Effect.flatMap((annotation) => { | ||
const out = annotation() | ||
return Predicate.isString(out) ? Effect.succeed(out) : out | ||
}), | ||
Effect.catchAll(() => Effect.succeed(e.message ?? "is missing")) | ||
) | ||
const getTree = (issue: ParseResult.ParseIssue, onFailure: () => Effect.Effect<Tree<string>>) => | ||
@@ -172,3 +182,5 @@ Effect.matchEffect(getMessage(issue), { | ||
const go = (e: ParseResult.ParseIssue | ParseResult.Missing | ParseResult.Unexpected): Effect.Effect<Tree<string>> => { | ||
const go = ( | ||
e: ParseResult.ParseIssue | ParseResult.Pointer | ||
): Effect.Effect<Tree<string>> => { | ||
switch (e._tag) { | ||
@@ -180,39 +192,9 @@ case "Type": | ||
case "Unexpected": | ||
return Effect.succeed(make(`is unexpected, expected ${e.ast.toString(true)}`)) | ||
return Effect.succeed(make(formatUnexpectedMessage(e))) | ||
case "Missing": | ||
return Effect.succeed(make("is missing")) | ||
case "Union": | ||
return getTree(e, () => | ||
Effect.map( | ||
Effect.forEach(e.errors, (e) => { | ||
switch (e._tag) { | ||
case "Member": | ||
return Effect.map(go(e.error), (tree) => make(`Union member`, [tree])) | ||
default: | ||
return go(e) | ||
} | ||
}), | ||
(forest) => make(getParseIssueTitle(e), forest) | ||
)) | ||
case "TupleType": | ||
return getTree(e, () => | ||
Effect.map( | ||
Effect.forEach( | ||
e.errors, | ||
(index) => Effect.map(go(index.error), (tree) => make(`[${util_.formatPropertyKey(index.index)}]`, [tree])) | ||
), | ||
(forest) => make(getParseIssueTitle(e), forest) | ||
)) | ||
case "TypeLiteral": | ||
return getTree(e, () => | ||
Effect.map( | ||
Effect.forEach(e.errors, (key) => | ||
Effect.map(go(key.error), (tree) => make(`[${util_.formatPropertyKey(key.key)}]`, [tree]))), | ||
(forest) => | ||
make(getParseIssueTitle(e), forest) | ||
)) | ||
return Effect.map(formatMissingMessage(e), make) | ||
case "Transformation": | ||
return getTree(e, () => | ||
Effect.map( | ||
go(e.error), | ||
go(e.issue), | ||
(tree) => make(getParseIssueTitle(e), [make(formatTransformationKind(e.kind), [tree])]) | ||
@@ -224,13 +206,17 @@ )) | ||
() => | ||
Effect.map(go(e.error), (tree) => make(getParseIssueTitle(e), [make(formatRefinementKind(e.kind), [tree])])) | ||
Effect.map(go(e.issue), (tree) => make(getParseIssueTitle(e), [make(formatRefinementKind(e.kind), [tree])])) | ||
) | ||
case "Declaration": | ||
return getTree(e, () => { | ||
const error = e.error | ||
const shouldSkipDefaultMessage = error._tag === "Type" && error.ast === e.ast | ||
return shouldSkipDefaultMessage | ||
? go(error) | ||
: Effect.map(go(error), (tree) => make(getParseIssueTitle(e), [tree])) | ||
}) | ||
case "Pointer": | ||
return Effect.map(go(e.issue), (tree) => make(util_.formatPath(e.path), [tree])) | ||
case "Composite": { | ||
const parseIssueTitle = getParseIssueTitle(e) | ||
return getTree( | ||
e, | ||
() => | ||
util_.isNonEmpty(e.issues) | ||
? Effect.map(Effect.forEach(e.issues, go), (forest) => make(parseIssueTitle, forest)) | ||
: Effect.map(go(e.issues), (tree) => make(parseIssueTitle, [tree])) | ||
) | ||
} | ||
} | ||
} |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
2477340
40965
9707
Updatedfast-check@^3.19.0