UNPKG

veffect

Version:

powerful TypeScript validation library built on the robust foundation of Effect combining exceptional type safety, high performance, and developer experience. Taking inspiration from Effect's functional principles, VEffect delivers a balanced approach tha

180 lines (178 loc) 6.4 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.nominal = exports.errors = exports.error = exports.all = exports.RefinedConstructorsTypeId = exports.BrandTypeId = void 0; exports.refined = refined; var Either = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("./Either.js")); var _Function = /*#__PURE__*/require("./Function.js"); var Option = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("./Option.js")); var ReadonlyArray = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("./ReadonlyArray.js")); function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); } function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; } /** * This module provides types and utility functions to create and work with branded types, * which are TypeScript types with an added type tag to prevent accidental usage of a value in the wrong context. * * The `refined` and `nominal` functions are both used to create branded types in TypeScript. * The main difference between them is that `refined` allows for validation of the data, while `nominal` does not. * * The `nominal` function is used to create a new branded type that has the same underlying type as the input, but with a different name. * This is useful when you want to distinguish between two values of the same type that have different meanings. * The `nominal` function does not perform any validation of the input data. * * On the other hand, the `refined` function is used to create a new branded type that has the same underlying type as the input, * but with a different name, and it also allows for validation of the input data. * The `refined` function takes a predicate that is used to validate the input data. * If the input data fails the validation, a `BrandErrors` is returned, which provides information about the specific validation failure. * * @since 2.0.0 */ /** * @since 2.0.0 * @category symbols */ const BrandTypeId = exports.BrandTypeId = /*#__PURE__*/Symbol.for("effect/Brand"); /** * @since 2.0.0 * @category symbols */ const RefinedConstructorsTypeId = exports.RefinedConstructorsTypeId = /*#__PURE__*/Symbol.for("effect/Brand/Refined"); /** * Returns a `BrandErrors` that contains a single `RefinementError`. * * @since 2.0.0 * @category constructors */ const error = (message, meta) => [{ message, meta }]; /** * Takes a variable number of `BrandErrors` and returns a single `BrandErrors` that contains all refinement errors. * * @since 2.0.0 * @category constructors */ exports.error = error; const errors = (...errors) => ReadonlyArray.flatten(errors); exports.errors = errors; function refined(...args) { const either = args.length === 2 ? unbranded => args[0](unbranded) ? Either.right(unbranded) : Either.left(args[1](unbranded)) : unbranded => { return Option.match(args[0](unbranded), { onNone: () => Either.right(unbranded), onSome: Either.left }); }; return Object.assign(unbranded => Either.getOrThrowWith(either(unbranded), _Function.identity), { [RefinedConstructorsTypeId]: RefinedConstructorsTypeId, option: args => Option.getRight(either(args)), either, is: args => Either.isRight(either(args)) }); } /** * This function returns a `Brand.Constructor` that **does not apply any runtime checks**, it just returns the provided value. * It can be used to create nominal types that allow distinguishing between two values of the same type but with different meanings. * * If you also want to perform some validation, see {@link refined}. * * @example * import * as Brand from "effect/Brand" * * type UserId = number & Brand.Brand<"UserId"> * * const UserId = Brand.nominal<UserId>() * * assert.strictEqual(UserId(1), 1) * * @since 2.0.0 * @category constructors */ const nominal = () => { // @ts-expect-error return Object.assign(args => args, { [RefinedConstructorsTypeId]: RefinedConstructorsTypeId, option: args => Option.some(args), either: args => Either.right(args), is: _args => true }); }; /** * Combines two or more brands together to form a single branded type. * This API is useful when you want to validate that the input data passes multiple brand validators. * * @example * import * as Brand from "effect/Brand" * * type Int = number & Brand.Brand<"Int"> * const Int = Brand.refined<Int>( * (n) => Number.isInteger(n), * (n) => Brand.error(`Expected ${n} to be an integer`) * ) * type Positive = number & Brand.Brand<"Positive"> * const Positive = Brand.refined<Positive>( * (n) => n > 0, * (n) => Brand.error(`Expected ${n} to be positive`) * ) * * const PositiveInt = Brand.all(Int, Positive) * * assert.strictEqual(PositiveInt(1), 1) * assert.throws(() => PositiveInt(1.1)) * * @since 2.0.0 * @category combining */ exports.nominal = nominal; const all = (...brands) => { const either = args => { let result = Either.right(args); for (const brand of brands) { const nextResult = brand.either(args); if (Either.isLeft(result) && Either.isLeft(nextResult)) { result = Either.left([...result.left, ...nextResult.left]); } else { result = Either.isLeft(result) ? result : nextResult; } } return result; }; // @ts-expect-error return Object.assign(args => Either.match(either(args), { onLeft: e => { throw e; }, onRight: _Function.identity }), { [RefinedConstructorsTypeId]: RefinedConstructorsTypeId, option: args => Option.getRight(either(args)), either, is: args => Either.isRight(either(args)) }); }; exports.all = all; //# sourceMappingURL=Brand.js.map