@effect/schema
Advanced tools
Comparing version 0.0.4 to 0.0.5
@@ -48,3 +48,3 @@ "use strict"; | ||
if (typeof actual === "number") { | ||
return Number.isNaN(actual) ? "NaN" : String(actual); | ||
return String(actual); | ||
} | ||
@@ -51,0 +51,0 @@ if (typeof actual === "bigint") { |
@@ -28,2 +28,6 @@ /** | ||
*/ | ||
getOption, | ||
/** | ||
* @since 1.0.0 | ||
*/ | ||
is } from "@effect/schema/Parser"; | ||
@@ -30,0 +34,0 @@ export type { |
@@ -12,2 +12,3 @@ "use strict"; | ||
encodeOrThrow: true, | ||
getOption: true, | ||
is: true, | ||
@@ -62,2 +63,8 @@ failure: true, | ||
}); | ||
Object.defineProperty(exports, "getOption", { | ||
enumerable: true, | ||
get: function () { | ||
return _Parser.getOption; | ||
} | ||
}); | ||
Object.defineProperty(exports, "is", { | ||
@@ -64,0 +71,0 @@ enumerable: true, |
@@ -6,5 +6,5 @@ "use strict"; | ||
}); | ||
exports.brand = exports.boolean = exports.bigint = exports.array = exports.any = exports.annotations = exports._void = exports._undefined = exports._null = void 0; | ||
exports.boolean = exports.bigint = exports.array = exports.any = exports.annotations = exports._void = exports._undefined = exports._null = void 0; | ||
exports.filter = filter; | ||
exports.unknown = exports.uniqueSymbol = exports.union = exports.typeAlias = exports.tuple = exports.transformOrFail = exports.transform = exports.symbol = exports.struct = exports.string = exports.record = exports.optional = exports.object = exports.number = exports.nullable = exports.never = exports.mutableAppend = exports.memoize = exports.map = exports.makeSchema = exports.makePretty = exports.makeParser = exports.makeArbitrary = exports.literal = exports.lazy = exports.isNonEmptyReadonlyArray = exports.getTemplateLiteralRegex = exports.getKeysForIndexSignature = exports.fromRefinement = exports.flatMap = void 0; | ||
exports.unknown = exports.uniqueSymbol = exports.union = exports.typeAlias = exports.tuple = exports.transformOrFail = exports.transform = exports.toAnnotations = exports.symbol = exports.struct = exports.string = exports.record = exports.optional = exports.object = exports.number = exports.nullable = exports.never = exports.mutableAppend = exports.memoize = exports.map = exports.makeSchema = exports.makePretty = exports.makeParser = exports.makeArbitrary = exports.literal = exports.lazy = exports.isNonEmptyReadonlyArray = exports.getTemplateLiteralRegex = exports.getKeysForIndexSignature = exports.fromRefinement = exports.flatMap = void 0; | ||
var E = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("@effect/data/Either")); | ||
@@ -75,2 +75,3 @@ var _Function = /*#__PURE__*/require("@effect/data/Function"); | ||
const annotations = annotations => self => makeSchema(AST.mergeAnnotations(self.ast, annotations)); | ||
/** @internal */ | ||
exports.annotations = annotations; | ||
@@ -111,15 +112,7 @@ const toAnnotations = options => { | ||
}; | ||
exports.toAnnotations = toAnnotations; | ||
function filter(predicate, options) { | ||
return from => makeSchema(AST.createRefinement(from.ast, predicate, toAnnotations(options))); | ||
} | ||
const getBrands = ast => ast.annotations[A.BrandId] || []; | ||
/** @internal */ | ||
const brand = (brand, options) => self => { | ||
const annotations = toAnnotations(options); | ||
annotations[A.BrandId] = [...getBrands(self.ast), brand]; | ||
const ast = AST.mergeAnnotations(self.ast, annotations); | ||
return makeSchema(ast); | ||
}; | ||
/** @internal */ | ||
exports.brand = brand; | ||
const transformOrFail = (to, decode, encode) => self => makeSchema(AST.createTransform(self.ast, to.ast, decode, encode)); | ||
@@ -126,0 +119,0 @@ /** @internal */ |
{ | ||
"name": "@effect/schema", | ||
"version": "0.0.4", | ||
"version": "0.0.5", | ||
"license": "MIT", | ||
@@ -5,0 +5,0 @@ "repository": { |
/** | ||
* @since 1.0.0 | ||
*/ | ||
import * as O from "@effect/data/Option"; | ||
import type { Option } from "@effect/data/Option"; | ||
import type { ParseOptions } from "@effect/schema/AST"; | ||
@@ -29,2 +31,7 @@ import * as PR from "@effect/schema/ParseResult"; | ||
*/ | ||
export declare const getOption: <A>(schema: Schema<A>) => (input: unknown, options?: ParseOptions) => O.Option<A>; | ||
/** | ||
* @category decoding | ||
* @since 1.0.0 | ||
*/ | ||
export declare const decodeOrThrow: <A>(schema: Schema<A>) => (input: unknown, options?: ParseOptions) => A; | ||
@@ -31,0 +38,0 @@ /** |
@@ -6,8 +6,6 @@ "use strict"; | ||
}); | ||
exports.make = exports.is = exports.encodeOrThrow = exports.encode = exports.decodeOrThrow = exports.decode = exports.asserts = exports._getSearchTree = exports._getLiterals = void 0; | ||
var _Boolean = /*#__PURE__*/require("@effect/data/Boolean"); | ||
exports.make = exports.is = exports.getOption = exports.encodeOrThrow = exports.encode = exports.decodeOrThrow = exports.decode = exports.asserts = exports._getSearchTree = exports._getLiterals = void 0; | ||
var _Function = /*#__PURE__*/require("@effect/data/Function"); | ||
var _Number = /*#__PURE__*/require("@effect/data/Number"); | ||
var O = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("@effect/data/Option")); | ||
var _Predicate = /*#__PURE__*/require("@effect/data/Predicate"); | ||
var P = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("@effect/data/Predicate")); | ||
var RA = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("@effect/data/ReadonlyArray")); | ||
@@ -41,2 +39,8 @@ var H = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("@effect/schema/annotation/Hook")); | ||
exports.decode = decode; | ||
const getOption = schema => (input, options) => O.fromEither(parserFor(schema).parse(input, options)); | ||
/** | ||
* @category decoding | ||
* @since 1.0.0 | ||
*/ | ||
exports.getOption = getOption; | ||
const decodeOrThrow = schema => (input, options) => { | ||
@@ -98,7 +102,7 @@ const t = parserFor(schema).parse(input, options); | ||
case "UndefinedKeyword": | ||
return I.fromRefinement(I.makeSchema(ast), _Predicate.isUndefined); | ||
return I.fromRefinement(I.makeSchema(ast), P.isUndefined); | ||
case "VoidKeyword": | ||
return I.fromRefinement(I.makeSchema(ast), _Predicate.isUndefined); | ||
return I.fromRefinement(I.makeSchema(ast), P.isUndefined); | ||
case "NeverKeyword": | ||
return I.fromRefinement(I.makeSchema(ast), _Predicate.isNever); | ||
return I.fromRefinement(I.makeSchema(ast), P.isNever); | ||
case "UnknownKeyword": | ||
@@ -108,13 +112,13 @@ case "AnyKeyword": | ||
case "StringKeyword": | ||
return I.fromRefinement(I.makeSchema(ast), _Predicate.isString); | ||
return I.fromRefinement(I.makeSchema(ast), P.isString); | ||
case "NumberKeyword": | ||
return I.fromRefinement(I.makeSchema(ast), _Number.isNumber); | ||
return I.fromRefinement(I.makeSchema(ast), P.isNumber); | ||
case "BooleanKeyword": | ||
return I.fromRefinement(I.makeSchema(ast), _Boolean.isBoolean); | ||
return I.fromRefinement(I.makeSchema(ast), P.isBoolean); | ||
case "BigIntKeyword": | ||
return I.fromRefinement(I.makeSchema(ast), _Predicate.isBigint); | ||
return I.fromRefinement(I.makeSchema(ast), P.isBigint); | ||
case "SymbolKeyword": | ||
return I.fromRefinement(I.makeSchema(ast), _Predicate.isSymbol); | ||
return I.fromRefinement(I.makeSchema(ast), P.isSymbol); | ||
case "ObjectKeyword": | ||
return I.fromRefinement(I.makeSchema(ast), _Predicate.isObject); | ||
return I.fromRefinement(I.makeSchema(ast), P.isObject); | ||
case "Enums": | ||
@@ -125,3 +129,3 @@ return I.fromRefinement(I.makeSchema(ast), u => ast.enums.some(([_, value]) => value === u)); | ||
const regex = I.getTemplateLiteralRegex(ast); | ||
return I.fromRefinement(I.makeSchema(ast), u => (0, _Predicate.isString)(u) && regex.test(u)); | ||
return I.fromRefinement(I.makeSchema(ast), u => P.isString(u) && regex.test(u)); | ||
} | ||
@@ -241,3 +245,3 @@ case "Tuple": | ||
if (ast.propertySignatures.length === 0 && ast.indexSignatures.length === 0) { | ||
return I.fromRefinement(I.makeSchema(ast), _Predicate.isNotNullable); | ||
return I.fromRefinement(I.makeSchema(ast), P.isNotNullable); | ||
} | ||
@@ -247,3 +251,3 @@ const propertySignaturesTypes = ast.propertySignatures.map(f => go(f.type)); | ||
return make(I.makeSchema(ast), (input, options) => { | ||
if (!(0, _Predicate.isRecord)(input)) { | ||
if (!P.isRecord(input)) { | ||
return PR.failure(PR.type(unknownRecord, input)); | ||
@@ -361,2 +365,3 @@ } | ||
const len = ownKeys.length; | ||
const otherwise = searchTree.otherwise; | ||
return make(I.makeSchema(ast), (input, options) => { | ||
@@ -366,3 +371,3 @@ const es = []; | ||
// if there is at least one key then input must be an object | ||
if ((0, _Predicate.isRecord)(input)) { | ||
if (P.isRecord(input)) { | ||
for (let i = 0; i < len; i++) { | ||
@@ -399,3 +404,2 @@ const name = ownKeys[i]; | ||
// proceed with those that have no literal at all | ||
const otherwise = searchTree.otherwise; | ||
for (let i = 0; i < otherwise.length; i++) { | ||
@@ -402,0 +406,0 @@ const t = otherwise[i].parse(input, options); |
@@ -12,2 +12,3 @@ "use strict"; | ||
var AST = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("@effect/schema/AST")); | ||
var _Tree = /*#__PURE__*/require("@effect/schema/formatter/Tree"); | ||
var I = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("@effect/schema/internal/common")); | ||
@@ -28,2 +29,5 @@ var P = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("@effect/schema/Parser")); | ||
const getHook = /*#__PURE__*/AST.getAnnotation(H.PrettyHookId); | ||
const toString = ast => make(I.makeSchema(ast), a => String(a)); | ||
const stringify = ast => make(I.makeSchema(ast), a => JSON.stringify(a)); | ||
const format = ast => make(I.makeSchema(ast), _Tree.formatActual); | ||
/** | ||
@@ -36,8 +40,2 @@ * @since 1.0.0 | ||
}) => handler(...ast.typeParameters.map(go)))), | ||
"Literal": ast => make(I.makeSchema(ast), literal => typeof literal === "bigint" ? `${literal.toString()}n` : JSON.stringify(literal)), | ||
"SymbolKeyword": ast => make(I.makeSchema(ast), s => String(s)), | ||
"BooleanKeyword": ast => make(I.makeSchema(ast), s => String(s)), | ||
"UniqueSymbol": ast => make(I.makeSchema(ast), s => String(s)), | ||
"TemplateLiteral": ast => make(I.makeSchema(ast), s => String(s)), | ||
"UndefinedKeyword": ast => make(I.makeSchema(ast), () => "undefined"), | ||
"VoidKeyword": ast => make(I.makeSchema(ast), () => "void(0)"), | ||
@@ -47,8 +45,15 @@ "NeverKeyword": ast => make(I.makeSchema(ast), () => { | ||
}), | ||
"UnknownKeyword": ast => make(I.makeSchema(ast), a => JSON.stringify(a, null, 2)), | ||
"AnyKeyword": ast => make(I.makeSchema(ast), a => JSON.stringify(a, null, 2)), | ||
"ObjectKeyword": ast => make(I.makeSchema(ast), a => JSON.stringify(a, null, 2)), | ||
"StringKeyword": ast => make(I.makeSchema(ast), s => JSON.stringify(s)), | ||
"NumberKeyword": ast => make(I.makeSchema(ast), n => Number.isNaN(n) ? "NaN" : String(n)), | ||
"BigIntKeyword": ast => make(I.makeSchema(ast), bi => `${bi.toString()}n`), | ||
"Literal": ast => make(I.makeSchema(ast), literal => typeof literal === "bigint" ? `${String(literal)}n` : JSON.stringify(literal)), | ||
"SymbolKeyword": toString, | ||
"UniqueSymbol": toString, | ||
"TemplateLiteral": stringify, | ||
"UndefinedKeyword": toString, | ||
"UnknownKeyword": format, | ||
"AnyKeyword": format, | ||
"ObjectKeyword": format, | ||
"StringKeyword": stringify, | ||
"NumberKeyword": toString, | ||
"BooleanKeyword": toString, | ||
"BigIntKeyword": ast => make(I.makeSchema(ast), a => `${String(a)}n`), | ||
"Enums": stringify, | ||
"Tuple": (ast, go) => { | ||
@@ -107,3 +112,3 @@ const elements = ast.elements.map(e => go(e.type)); | ||
} | ||
output.push(`${prettyName(name)}: ${propertySignaturesTypes[i].pretty(input[name])}`); | ||
output.push(`${getPrettyPropertyKey(name)}: ${propertySignaturesTypes[i].pretty(input[name])}`); | ||
expectedKeys[name] = null; | ||
@@ -122,3 +127,3 @@ } | ||
} | ||
output.push(`${prettyName(key)}: ${type.pretty(input[key])}`); | ||
output.push(`${getPrettyPropertyKey(key)}: ${type.pretty(input[key])}`); | ||
} | ||
@@ -143,3 +148,2 @@ } | ||
}, | ||
"Enums": ast => make(I.makeSchema(ast), sn => JSON.stringify(sn)), | ||
"Refinement": (ast, go) => go(ast.from), | ||
@@ -156,3 +160,3 @@ "Transform": (ast, go) => go(ast.to) | ||
exports.pretty = pretty; | ||
const prettyName = name => typeof name === "string" ? JSON.stringify(name) : String(name); | ||
const getPrettyPropertyKey = name => typeof name === "string" ? JSON.stringify(name) : String(name); | ||
//# sourceMappingURL=Pretty.js.map |
@@ -508,2 +508,74 @@ <h3 align="center"> | ||
## Branded types | ||
TypeScript's type system is structural, which means that any two types that are structurally equivalent are considered the same. This can cause issues when types that are semantically different are treated as if they were the same. | ||
```ts | ||
type UserId = string | ||
type Username = string | ||
const getUser = (id: UserId) => { ... } | ||
const myUsername: Username = "gcanti" | ||
getUser(myUsername) // works fine | ||
``` | ||
In the above example, `UserId` and `Username` are both aliases for the same type, `string`. This means that the `getUser` function can mistakenly accept a `Username` as a valid `UserId`, causing bugs and errors. | ||
To avoid these kinds of issues, the `@effect` ecosystem provides a way to create custom types with a unique identifier attached to them. These are known as "branded types". | ||
```ts | ||
import type * as B from "@effect/data/Brand" | ||
type UserId = string & B.Brand<"UserId"> | ||
type Username = string | ||
const getUser = (id: UserId) => { ... } | ||
const myUsername: Username = "gcanti" | ||
getUser(myUsername) // error | ||
``` | ||
By defining `UserId` as a branded type, the `getUser` function can accept only values of type `UserId`, and not plain strings or other types that are compatible with strings. This helps to prevent bugs caused by accidentally passing the wrong type of value to the function. | ||
There are two ways to define a schema for a branded type, depending on whether you: | ||
- want to define the schema from scratch | ||
- have already defined a branded type via `@effect/data/Brand` and want to reuse it to define a schema | ||
### Defining a schema from scratch | ||
To define a schema for a branded type from scratch, you can use the `brand` combinator exported by the `@effect/schema` module. Here's an example: | ||
```ts | ||
import { pipe } from "@effect/data/Function" | ||
import * as S from "@effect/schema" | ||
const UserIdSchema = pipe(S.string, S.brand("UserId")) | ||
type UserId = S.Infer<typeof UserIdSchema> // string & Brand<"UserId"> | ||
``` | ||
In the above example, `UserIdSchema` is a schema for the `UserId` branded type. The `brand` combinator takes a string argument that specifies the name of the brand to attach to the type. | ||
### Reusing an existing branded type | ||
If you have already defined a branded type using the `@effect/data/Brand` module, you can reuse it to define a schema using the `brand` combinator exported by the `@effect/schema/data/Brand` module. Here's an example: | ||
```ts | ||
import * as B from "@effect/data/Brand" | ||
// the existing branded type | ||
type UserId = string & B.Brand<"UserId"> | ||
const UserId = B.nominal<UserId>() | ||
import { pipe } from "@effect/data/Function" | ||
import * as S from "@effect/schema" | ||
import { brand } from "@effect/schema/data/Brand" | ||
// Define a schema for the branded type | ||
const UserIdSchema = pipe(S.string, brand(UserId)) | ||
``` | ||
## Native enums | ||
@@ -510,0 +582,0 @@ |
@@ -315,2 +315,8 @@ /** | ||
/** | ||
* @category model | ||
* @since 1.0.0 | ||
*/ | ||
export interface BrandSchema<A extends Brand<any>> extends Schema<A>, Brand.Constructor<A> { | ||
} | ||
/** | ||
* Returns a nominal branded schema by applying a brand to a given schema. | ||
@@ -335,3 +341,3 @@ * | ||
*/ | ||
export declare const brand: <B extends string, A>(brand: B, options?: AnnotationOptions<A>) => (self: Schema<A>) => Schema<A & Brand<B>>; | ||
export declare const brand: <B extends string, A>(brand: B, options?: AnnotationOptions<A> | undefined) => (self: Schema<A>) => BrandSchema<A & Brand<B>>; | ||
/** | ||
@@ -338,0 +344,0 @@ * @category combinators |
@@ -9,2 +9,4 @@ "use strict"; | ||
exports.void = exports.unknown = exports.uniqueSymbol = exports.union = exports.undefined = exports.typeAlias = exports.tuple = exports.trimmed = exports.trim = exports.transformOrFail = exports.transform = exports.title = exports.templateLiteral = exports.symbol = exports.struct = exports.string = exports.startsWith = exports.rest = exports.record = exports.positive = exports.pick = exports.pattern = exports.partial = exports.optionalElement = exports.optional = exports.option = exports.omit = exports.object = exports.number = exports.nullable = exports.null = exports.nonPositive = exports.nonNegative = exports.nonNaN = exports.nonEmptyArray = exports.nonEmpty = exports.never = exports.negative = exports.minLength = exports.minItems = exports.message = exports.maxLength = exports.maxItems = exports.make = exports.literal = exports.lessThanOrEqualTo = exports.lessThan = exports.length = exports.lazy = exports.keyof = exports.itemsCount = exports.int = exports.instanceOf = exports.includes = exports.identifier = exports.greaterThanOrEqualTo = exports.greaterThan = exports.getPropertySignatures = exports.finite = void 0; | ||
var _Brand = /*#__PURE__*/require("@effect/data/Brand"); | ||
var E = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("@effect/data/Either")); | ||
var _Function = /*#__PURE__*/require("@effect/data/Function"); | ||
@@ -16,7 +18,9 @@ var RA = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("@effect/data/ReadonlyArray")); | ||
var N = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("@effect/schema/data/Number")); | ||
var O = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("@effect/schema/data/Object")); | ||
var DataObject = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("@effect/schema/data/Object")); | ||
var DataOption = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("@effect/schema/data/Option")); | ||
var SRA = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("@effect/schema/data/ReadonlyArray")); | ||
var S = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("@effect/schema/data/String")); | ||
var _Tree = /*#__PURE__*/require("@effect/schema/formatter/Tree"); | ||
var I = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("@effect/schema/internal/common")); | ||
var P = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("@effect/schema/Parser")); | ||
function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); } | ||
@@ -59,3 +63,3 @@ function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; } | ||
exports.enums = enums; | ||
const instanceOf = O.instanceOf; | ||
const instanceOf = DataObject.instanceOf; | ||
/** | ||
@@ -416,3 +420,25 @@ * @category constructors | ||
exports.getPropertySignatures = getPropertySignatures; | ||
const brand = I.brand; | ||
const brand = (brand, options) => self => { | ||
const annotations = I.toAnnotations(options); | ||
annotations[A.BrandId] = [...getBrands(self.ast), brand]; | ||
const ast = AST.mergeAnnotations(self.ast, annotations); | ||
const schema = make(ast); | ||
const decodeOrThrow = P.decodeOrThrow(schema); | ||
const getOption = P.getOption(schema); | ||
const decode = P.decode(schema); | ||
const is = P.is(schema); | ||
const out = Object.assign(input => decodeOrThrow(input), { | ||
[_Brand.RefinedConstructorsTypeId]: _Brand.RefinedConstructorsTypeId, | ||
ast, | ||
option: input => getOption(input), | ||
either: input => E.mapLeft(decode(input), errors => [{ | ||
meta: input, | ||
message: (0, _Tree.formatErrors)(errors) | ||
}]), | ||
refine: input => is(input) | ||
}); | ||
return out; | ||
}; | ||
exports.brand = brand; | ||
const getBrands = ast => ast.annotations[A.BrandId] || []; | ||
/** | ||
@@ -422,3 +448,2 @@ * @category combinators | ||
*/ | ||
exports.brand = brand; | ||
const partial = self => make(AST.partial(self.ast)); | ||
@@ -425,0 +450,0 @@ /** |
@@ -54,3 +54,3 @@ /** | ||
if (typeof actual === "number") { | ||
return Number.isNaN(actual) ? "NaN" : String(actual) | ||
return String(actual) | ||
} | ||
@@ -57,0 +57,0 @@ if (typeof actual === "bigint") { |
@@ -30,2 +30,6 @@ /** | ||
*/ | ||
getOption, | ||
/** | ||
* @since 1.0.0 | ||
*/ | ||
is | ||
@@ -32,0 +36,0 @@ } from "@effect/schema/Parser" |
@@ -5,3 +5,2 @@ /** | ||
import type { Brand } from "@effect/data/Brand" | ||
import * as E from "@effect/data/Either" | ||
@@ -88,3 +87,6 @@ import { pipe } from "@effect/data/Function" | ||
const toAnnotations = <A>(options?: S.AnnotationOptions<A>): AST.Annotated["annotations"] => { | ||
/** @internal */ | ||
export const toAnnotations = <A>( | ||
options?: S.AnnotationOptions<A> | ||
): AST.Annotated["annotations"] => { | ||
const annotations: AST.Annotated["annotations"] = {} | ||
@@ -140,15 +142,3 @@ if (options?.typeId !== undefined) { | ||
const getBrands = (ast: AST.AST): Array<string> => | ||
(ast.annotations[A.BrandId] as Array<string> | undefined) || [] | ||
/** @internal */ | ||
export const brand = <B extends string, A>(brand: B, options?: S.AnnotationOptions<A>) => | ||
(self: S.Schema<A>): S.Schema<A & Brand<B>> => { | ||
const annotations = toAnnotations(options) | ||
annotations[A.BrandId] = [...getBrands(self.ast), brand] | ||
const ast = AST.mergeAnnotations(self.ast, annotations) | ||
return makeSchema(ast) | ||
} | ||
/** @internal */ | ||
export const transformOrFail = <A, B>( | ||
@@ -155,0 +145,0 @@ to: S.Schema<B>, |
@@ -5,16 +5,6 @@ /** | ||
import { isBoolean } from "@effect/data/Boolean" | ||
import { pipe } from "@effect/data/Function" | ||
import { isNumber } from "@effect/data/Number" | ||
import * as O from "@effect/data/Option" | ||
import { | ||
isBigint, | ||
isNever, | ||
isNotNullable, | ||
isObject, | ||
isRecord, | ||
isString, | ||
isSymbol, | ||
isUndefined | ||
} from "@effect/data/Predicate" | ||
import type { Option } from "@effect/data/Option" | ||
import * as P from "@effect/data/Predicate" | ||
import * as RA from "@effect/data/ReadonlyArray" | ||
@@ -56,2 +46,10 @@ import * as H from "@effect/schema/annotation/Hook" | ||
*/ | ||
export const getOption = <A>(schema: Schema<A>) => | ||
(input: unknown, options?: ParseOptions): Option<A> => | ||
O.fromEither(parserFor(schema).parse(input, options)) | ||
/** | ||
* @category decoding | ||
* @since 1.0.0 | ||
*/ | ||
export const decodeOrThrow = <A>(schema: Schema<A>) => | ||
@@ -144,7 +142,7 @@ (input: unknown, options?: ParseOptions): A => { | ||
case "UndefinedKeyword": | ||
return I.fromRefinement(I.makeSchema(ast), isUndefined) | ||
return I.fromRefinement(I.makeSchema(ast), P.isUndefined) | ||
case "VoidKeyword": | ||
return I.fromRefinement(I.makeSchema(ast), isUndefined) | ||
return I.fromRefinement(I.makeSchema(ast), P.isUndefined) | ||
case "NeverKeyword": | ||
return I.fromRefinement(I.makeSchema(ast), isNever) | ||
return I.fromRefinement(I.makeSchema(ast), P.isNever) | ||
case "UnknownKeyword": | ||
@@ -154,13 +152,13 @@ case "AnyKeyword": | ||
case "StringKeyword": | ||
return I.fromRefinement(I.makeSchema(ast), isString) | ||
return I.fromRefinement(I.makeSchema(ast), P.isString) | ||
case "NumberKeyword": | ||
return I.fromRefinement(I.makeSchema(ast), isNumber) | ||
return I.fromRefinement(I.makeSchema(ast), P.isNumber) | ||
case "BooleanKeyword": | ||
return I.fromRefinement(I.makeSchema(ast), isBoolean) | ||
return I.fromRefinement(I.makeSchema(ast), P.isBoolean) | ||
case "BigIntKeyword": | ||
return I.fromRefinement(I.makeSchema(ast), isBigint) | ||
return I.fromRefinement(I.makeSchema(ast), P.isBigint) | ||
case "SymbolKeyword": | ||
return I.fromRefinement(I.makeSchema(ast), isSymbol) | ||
return I.fromRefinement(I.makeSchema(ast), P.isSymbol) | ||
case "ObjectKeyword": | ||
return I.fromRefinement(I.makeSchema(ast), isObject) | ||
return I.fromRefinement(I.makeSchema(ast), P.isObject) | ||
case "Enums": | ||
@@ -173,3 +171,3 @@ return I.fromRefinement( | ||
const regex = I.getTemplateLiteralRegex(ast) | ||
return I.fromRefinement(I.makeSchema(ast), (u): u is any => isString(u) && regex.test(u)) | ||
return I.fromRefinement(I.makeSchema(ast), (u): u is any => P.isString(u) && regex.test(u)) | ||
} | ||
@@ -293,3 +291,3 @@ case "Tuple": { | ||
if (ast.propertySignatures.length === 0 && ast.indexSignatures.length === 0) { | ||
return I.fromRefinement(I.makeSchema(ast), isNotNullable) | ||
return I.fromRefinement(I.makeSchema(ast), P.isNotNullable) | ||
} | ||
@@ -303,3 +301,3 @@ const propertySignaturesTypes = ast.propertySignatures.map((f) => go(f.type)) | ||
(input: unknown, options) => { | ||
if (!isRecord(input)) { | ||
if (!P.isRecord(input)) { | ||
return PR.failure(PR.type(unknownRecord, input)) | ||
@@ -421,2 +419,3 @@ } | ||
const len = ownKeys.length | ||
const otherwise = searchTree.otherwise | ||
return make(I.makeSchema(ast), (input, options) => { | ||
@@ -427,3 +426,3 @@ const es: Array<PR.ParseError> = [] | ||
// if there is at least one key then input must be an object | ||
if (isRecord(input)) { | ||
if (P.isRecord(input)) { | ||
for (let i = 0; i < len; i++) { | ||
@@ -467,3 +466,2 @@ const name = ownKeys[i] | ||
// proceed with those that have no literal at all | ||
const otherwise = searchTree.otherwise | ||
for (let i = 0; i < otherwise.length; i++) { | ||
@@ -470,0 +468,0 @@ const t = otherwise[i].parse(input, options) |
@@ -9,2 +9,3 @@ /** | ||
import * as AST from "@effect/schema/AST" | ||
import { formatActual } from "@effect/schema/formatter/Tree" | ||
import * as I from "@effect/schema/internal/common" | ||
@@ -32,2 +33,8 @@ import * as P from "@effect/schema/Parser" | ||
const toString = (ast: AST.AST) => make(I.makeSchema(ast), (a) => String(a)) | ||
const stringify = (ast: AST.AST) => make(I.makeSchema(ast), (a) => JSON.stringify(a)) | ||
const format = (ast: AST.AST) => make(I.makeSchema(ast), formatActual) | ||
/** | ||
@@ -45,2 +52,7 @@ * @since 1.0.0 | ||
), | ||
"VoidKeyword": (ast) => make(I.makeSchema(ast), () => "void(0)"), | ||
"NeverKeyword": (ast) => | ||
make(I.makeSchema(ast), () => { | ||
throw new Error("cannot pretty print a `never` value") | ||
}), | ||
"Literal": (ast) => | ||
@@ -51,25 +63,17 @@ make( | ||
typeof literal === "bigint" ? | ||
`${literal.toString()}n` : | ||
`${String(literal)}n` : | ||
JSON.stringify(literal) | ||
), | ||
"SymbolKeyword": (ast) => make(I.makeSchema(ast), (s) => String(s)), | ||
"BooleanKeyword": (ast) => make(I.makeSchema(ast), (s) => String(s)), | ||
"UniqueSymbol": (ast) => make(I.makeSchema(ast), (s) => String(s)), | ||
"TemplateLiteral": (ast) => make(I.makeSchema(ast), (s) => String(s)), | ||
"UndefinedKeyword": (ast) => make(I.makeSchema(ast), () => "undefined"), | ||
"VoidKeyword": (ast) => make(I.makeSchema(ast), () => "void(0)"), | ||
"NeverKeyword": (ast) => | ||
make(I.makeSchema(ast), () => { | ||
throw new Error("cannot pretty print a `never` value") | ||
}) as any, | ||
"UnknownKeyword": (ast) => make(I.makeSchema(ast), (a) => JSON.stringify(a, null, 2)), | ||
"AnyKeyword": (ast) => make(I.makeSchema(ast), (a) => JSON.stringify(a, null, 2)), | ||
"ObjectKeyword": (ast) => make(I.makeSchema(ast), (a) => JSON.stringify(a, null, 2)), | ||
"StringKeyword": (ast) => make(I.makeSchema(ast), (s) => JSON.stringify(s)), | ||
"NumberKeyword": (ast) => | ||
make( | ||
I.makeSchema(ast), | ||
(n) => Number.isNaN(n) ? "NaN" : String(n) | ||
), | ||
"BigIntKeyword": (ast) => make(I.makeSchema(ast), (bi) => `${bi.toString()}n`), | ||
"SymbolKeyword": toString, | ||
"UniqueSymbol": toString, | ||
"TemplateLiteral": stringify, | ||
"UndefinedKeyword": toString, | ||
"UnknownKeyword": format, | ||
"AnyKeyword": format, | ||
"ObjectKeyword": format, | ||
"StringKeyword": stringify, | ||
"NumberKeyword": toString, | ||
"BooleanKeyword": toString, | ||
"BigIntKeyword": (ast: AST.AST) => make(I.makeSchema(ast), (a) => `${String(a)}n`), | ||
"Enums": stringify, | ||
"Tuple": (ast, go) => { | ||
@@ -134,3 +138,5 @@ const elements = ast.elements.map((e) => go(e.type)) | ||
} | ||
output.push(`${prettyName(name)}: ${propertySignaturesTypes[i].pretty(input[name])}`) | ||
output.push( | ||
`${getPrettyPropertyKey(name)}: ${propertySignaturesTypes[i].pretty(input[name])}` | ||
) | ||
expectedKeys[name] = null | ||
@@ -149,3 +155,3 @@ } | ||
} | ||
output.push(`${prettyName(key)}: ${type.pretty(input[key])}`) | ||
output.push(`${getPrettyPropertyKey(key)}: ${type.pretty(input[key])}`) | ||
} | ||
@@ -172,3 +178,2 @@ } | ||
}, | ||
"Enums": (ast) => make(I.makeSchema(ast), (sn) => JSON.stringify(sn)), | ||
"Refinement": (ast, go) => go(ast.from), | ||
@@ -186,3 +191,3 @@ "Transform": (ast, go) => go(ast.to) | ||
const prettyName = (name: PropertyKey): string => | ||
const getPrettyPropertyKey = (name: PropertyKey): string => | ||
typeof name === "string" ? JSON.stringify(name) : String(name) |
@@ -6,2 +6,4 @@ /** | ||
import type { Brand } from "@effect/data/Brand" | ||
import { RefinedConstructorsTypeId } from "@effect/data/Brand" | ||
import * as E from "@effect/data/Either" | ||
import { pipe } from "@effect/data/Function" | ||
@@ -16,7 +18,9 @@ import type { Option } from "@effect/data/Option" | ||
import * as N from "@effect/schema/data/Number" | ||
import * as O from "@effect/schema/data/Object" | ||
import * as DataObject from "@effect/schema/data/Object" | ||
import * as DataOption from "@effect/schema/data/Option" | ||
import * as SRA from "@effect/schema/data/ReadonlyArray" | ||
import * as S from "@effect/schema/data/String" | ||
import { formatErrors } from "@effect/schema/formatter/Tree" | ||
import * as I from "@effect/schema/internal/common" | ||
import * as P from "@effect/schema/Parser" | ||
import type { ParseResult } from "@effect/schema/ParseResult" | ||
@@ -87,3 +91,3 @@ | ||
annotationOptions?: AnnotationOptions<object> | ||
) => Schema<InstanceType<A>> = O.instanceOf | ||
) => Schema<InstanceType<A>> = DataObject.instanceOf | ||
@@ -570,2 +574,8 @@ /** | ||
/** | ||
* @category model | ||
* @since 1.0.0 | ||
*/ | ||
export interface BrandSchema<A extends Brand<any>> extends Schema<A>, Brand.Constructor<A> {} | ||
/** | ||
* Returns a nominal branded schema by applying a brand to a given schema. | ||
@@ -590,7 +600,29 @@ * | ||
*/ | ||
export const brand: <B extends string, A>( | ||
export const brand = <B extends string, A>( | ||
brand: B, | ||
options?: AnnotationOptions<A> | ||
) => (self: Schema<A>) => Schema<A & Brand<B>> = I.brand | ||
) => | ||
(self: Schema<A>): BrandSchema<A & Brand<B>> => { | ||
const annotations = I.toAnnotations(options) | ||
annotations[A.BrandId] = [...getBrands(self.ast), brand] | ||
const ast = AST.mergeAnnotations(self.ast, annotations) | ||
const schema: Schema<A & Brand<B>> = make(ast) | ||
const decodeOrThrow = P.decodeOrThrow(schema) | ||
const getOption = P.getOption(schema) | ||
const decode = P.decode(schema) | ||
const is = P.is(schema) | ||
const out: any = Object.assign((input: unknown) => decodeOrThrow(input), { | ||
[RefinedConstructorsTypeId]: RefinedConstructorsTypeId, | ||
ast, | ||
option: (input: unknown) => getOption(input), | ||
either: (input: unknown) => | ||
E.mapLeft(decode(input), (errors) => [{ meta: input, message: formatErrors(errors) }]), | ||
refine: (input: unknown): input is A & Brand<B> => is(input) | ||
}) | ||
return out | ||
} | ||
const getBrands = (ast: AST.AST): Array<string> => | ||
(ast.annotations[A.BrandId] as Array<string> | undefined) || [] | ||
/** | ||
@@ -597,0 +629,0 @@ * @category combinators |
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 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
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
830801
14723
1393