diff --git a/docs/en/v1/api/clean/castConstraint.md b/docs/en/v1/api/clean/castConstraint.md new file mode 100644 index 000000000..1bf397172 --- /dev/null +++ b/docs/en/v1/api/clean/castConstraint.md @@ -0,0 +1,48 @@ +--- +outline: [2, 3] +prev: + text: "Constraints" + link: "/en/v1/api/clean/constraints" +next: + text: "NewType" + link: "/en/v1/api/clean/newType" +description: "Extends the typing of a constrained value by adding compatible constraints without re-validating it." +--- + +# castConstraint + +`castConstraint` extends the typing of an already constrained value by adding one or more compatible constraints. +It does not re-validate the value; it only adds constraint markers. TypeScript prevents invalid casts. + +## Interactive example + + + +## Syntax + +### Classic signature + +```typescript +function castConstraint( + constrainedType: ConstrainedType, + constraintHandler: ConstraintHandler | ConstraintHandler[] +): ConstrainedType +``` + +## Parameters + +- `constrainedType`: A value already carrying one or more constraints. +- `constraintHandler`: A constraint handler (or an array of handlers) to add. + +## Return value + +A new constrained value with the same wrapped value and the additional constraint markers. + +## See also + +- [`constraints`](/en/v1/api/clean/constraints) +- [`newType`](/en/v1/api/clean/newType) diff --git a/docs/en/v1/api/clean/constraints.md b/docs/en/v1/api/clean/constraints.md index 095690da7..8d0c09fb7 100644 --- a/docs/en/v1/api/clean/constraints.md +++ b/docs/en/v1/api/clean/constraints.md @@ -5,8 +5,8 @@ prev: text: "Primitives" link: "/en/v1/api/clean/primitives" next: - text: "NewType" - link: "/en/v1/api/clean/newType" + text: "castConstraint" + link: "/en/v1/api/clean/castConstraint" --- # Constraints @@ -105,14 +105,6 @@ function is( The unique name of the constraint (e.g. `"email"`, `"int"`, ...). -#### `checkers` - -The list of `DDataParser` checkers used to validate the value. - -#### `primitiveHandler` - -The primitive to which the constraint applies (e.g. `C.String`, `C.Number`). - ## Constraints provided by the library The library exports a few ready-to-use constraints via `C.*`: @@ -177,16 +169,6 @@ Validates a strictly positive number (>= 1). height="240px" /> -### `PositiveInt` - -Validates a strictly positive integer (>= 1). - - - ### `Negative` Validates a strictly negative number (<= -1). diff --git a/docs/en/v1/api/clean/entity.md b/docs/en/v1/api/clean/entity.md index b5dca6360..6ae6cbde2 100644 --- a/docs/en/v1/api/clean/entity.md +++ b/docs/en/v1/api/clean/entity.md @@ -143,10 +143,6 @@ The unique name of the entity (e.g. `"User"`), used as a runtime identifier. The properties definition (as declared in `createEntity`). -#### `mapDataParser` - -The `DataParser` generated from `propertiesDefinition` (handy if you want to reuse validation/transform elsewhere). It accepts `unknown` input and produces typed entity properties. - ## Get the type To retrieve the type of the generated entity: diff --git a/docs/en/v1/api/clean/index.md b/docs/en/v1/api/clean/index.md index 3900edc6d..133c64073 100644 --- a/docs/en/v1/api/clean/index.md +++ b/docs/en/v1/api/clean/index.md @@ -28,6 +28,9 @@ Primitives let you handle base types (`String`, `Number`, `Date`, …) in busine ## [Constraints](/en/v1/api/clean/constraints) Constraints allow adding additional rules on primitives. +## [castConstraint](/en/v1/api/clean/castConstraint) +Extends a constrained value with compatible constraints without re-validating it. + ## [NewType](/en/v1/api/clean/newType) Creates a `NewType` (brand) backed by a `DataParser`, with optional constraints. diff --git a/docs/en/v1/api/clean/newType.md b/docs/en/v1/api/clean/newType.md index 2505daf26..30ba5d2c8 100644 --- a/docs/en/v1/api/clean/newType.md +++ b/docs/en/v1/api/clean/newType.md @@ -2,8 +2,8 @@ outline: [2, 3] description: "A NewType is a type designed to meet business requirements, while being based on an existing primitive type (or data structure). It allows you to add constraints and specific rules, ensuring that values satisfy the conditions defined by the business." prev: - text: "Constraints" - link: "/en/v1/api/clean/constraints" + text: "castConstraint" + link: "/en/v1/api/clean/castConstraint" next: text: "Entities" link: "/en/v1/api/clean/entity" @@ -108,14 +108,6 @@ function getConstraint( The unique name of the `NewType` (e.g. `"userId"`). -#### `dataParser` - -The `DataParser` used to validate the data (including checkers added by constraints). - -#### `constrains` - -The list of constraints applied to the `NewType`. - ## See also - [Primitives](/en/v1/api/clean/primitives/) diff --git a/docs/en/v1/api/clean/primitives/index.md b/docs/en/v1/api/clean/primitives/index.md index 056b71193..1b8c27220 100644 --- a/docs/en/v1/api/clean/primitives/index.md +++ b/docs/en/v1/api/clean/primitives/index.md @@ -91,12 +91,6 @@ function is( ): value is Primitive ``` -### Properties - -#### `dataParser` - -Corresponds to the [dataParser](/en/v1/api/dataParser/) that validates the primitive. - ## Operators ### [equal](/en/v1/api/clean/primitives/operators/equal) diff --git a/docs/examples/v1/api/clean/castConstraint/tryout.doc.ts b/docs/examples/v1/api/clean/castConstraint/tryout.doc.ts new file mode 100644 index 000000000..7bb86383b --- /dev/null +++ b/docs/examples/v1/api/clean/castConstraint/tryout.doc.ts @@ -0,0 +1,28 @@ +import { C, type ExpectType } from "@duplojs/utils"; + +const baseMin = C.NumberMin(5).createOrThrow(7); +const widenedMin = C.castConstraint(baseMin, C.NumberMin(3)); + +type CheckWidenedMin = ExpectType< + typeof widenedMin, + & C.ConstrainedType<"number-min-5", 7> + & C.ConstrainedType<"number-min-3", number>, + "strict" +>; + +const baseMax = C.NumberMax(5).createOrThrow(-2); +const widenedMax = C.castConstraint( + baseMax, + [ + C.NumberMax(8), + C.NumberMax(10), + ], +); + +type CheckWidenedMax = ExpectType< + typeof widenedMax, + & C.ConstrainedType<"number-max-5", -2> + & C.ConstrainedType<"number-max-8", number> + & C.ConstrainedType<"number-max-10", number>, + "strict" +>; diff --git a/docs/examples/v1/api/clean/constraints/positiveInt.doc.ts b/docs/examples/v1/api/clean/constraints/positiveInt.doc.ts deleted file mode 100644 index bb585cb55..000000000 --- a/docs/examples/v1/api/clean/constraints/positiveInt.doc.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { type ExpectType, C, DP } from "@duplojs/utils"; - -const Score = C.createNewType("score", DP.number(), C.PositiveInt); - -const score = Score.createOrThrow(42); - -type check = ExpectType< - typeof score, - C.NewType<"score", 42, "positive-int">, - "strict" ->; diff --git a/docs/examples/v1/api/clean/maybe/tryout.doc.ts b/docs/examples/v1/api/clean/maybe/tryout.doc.ts index 6c89ec91a..c3d2126c0 100644 --- a/docs/examples/v1/api/clean/maybe/tryout.doc.ts +++ b/docs/examples/v1/api/clean/maybe/tryout.doc.ts @@ -1,6 +1,6 @@ import { C, DP, type ExpectType } from "@duplojs/utils"; -const UserId = C.createNewType("userId", DP.number(), C.PositiveInt); +const UserId = C.createNewType("userId", DP.number(), C.Positive); const User = C.createEntity("User", () => ({ id: UserId, })); diff --git a/docs/fr/v1/api/clean/castConstraint.md b/docs/fr/v1/api/clean/castConstraint.md new file mode 100644 index 000000000..d9cde4dc5 --- /dev/null +++ b/docs/fr/v1/api/clean/castConstraint.md @@ -0,0 +1,48 @@ +--- +outline: [2, 3] +prev: + text: "Contraintes" + link: "/fr/v1/api/clean/constraints" +next: + text: "NewType" + link: "/fr/v1/api/clean/newType" +description: "Étend le typage d'une valeur contrainte en ajoutant des contraintes compatibles sans revalider." +--- + +# castConstraint + +`castConstraint` étend le typage d'une valeur déjà contrainte en ajoutant une ou plusieurs contraintes compatibles. +La valeur n'est pas revalidée : seules les marques de contraintes sont ajoutées. TypeScript empêche les casts invalides. + +## Exemple interactif + + + +## Syntaxe + +### Signature classique + +```typescript +function castConstraint( + constrainedType: ConstrainedType, + constraintHandler: ConstraintHandler | ConstraintHandler[] +): ConstrainedType +``` + +## Paramètres + +- `constrainedType` : Une valeur qui porte déjà une ou plusieurs contraintes. +- `constraintHandler` : Une contrainte (ou un tableau de contraintes) à ajouter. + +## Valeur de retour + +Une nouvelle valeur contrainte avec la même valeur wrappée et les contraintes ajoutées. + +## Voir aussi + +- [`constraints`](/fr/v1/api/clean/constraints) +- [`newType`](/fr/v1/api/clean/newType) diff --git a/docs/fr/v1/api/clean/constraints.md b/docs/fr/v1/api/clean/constraints.md index bd207a70a..889def9ef 100644 --- a/docs/fr/v1/api/clean/constraints.md +++ b/docs/fr/v1/api/clean/constraints.md @@ -5,8 +5,8 @@ prev: text: "Primitives" link: "/fr/v1/api/clean/primitives" next: - text: "NewType" - link: "/fr/v1/api/clean/newType" + text: "castConstraint" + link: "/fr/v1/api/clean/castConstraint" --- # Contraintes @@ -105,14 +105,6 @@ function is( Le nom unique de la contrainte (ex: `"email"`, `"int"`, ...). -#### `checkers` - -La liste des checkers du `DDataParser` utilisés pour valider la valeur. - -#### `primitiveHandler` - -La primitive sur laquelle s'applique la contrainte (ex: `C.String`, `C.Number`). - ## Contraintes fournies par la librairie La librairie exporte quelques contraintes prêtes à l'emploi via `C.*` : @@ -177,16 +169,6 @@ Valide un nombre strictement positif (>= 1). height="240px" /> -### `PositiveInt` - -Valide un nombre entier strictement positif (>= 1). - - - ### `Negative` Valide un nombre strictement négatif (<= -1). diff --git a/docs/fr/v1/api/clean/entity.md b/docs/fr/v1/api/clean/entity.md index 59493ecd0..042d1ca03 100644 --- a/docs/fr/v1/api/clean/entity.md +++ b/docs/fr/v1/api/clean/entity.md @@ -143,10 +143,6 @@ Le nom unique de l'entité (ex: `"User"`), utilisé comme identifiant runtime. La définition des propriétés (telle que déclarée dans `createEntity`). -#### `mapDataParser` - -Le `DataParser` généré à partir de `propertiesDefinition` (pratique si vous voulez réutiliser la validation/transform ailleurs). Il accepte une entrée `unknown` et produit des propriétés d'entité typées. - ## Récupérer le type Pour récupérer le type de l'entité générée : diff --git a/docs/fr/v1/api/clean/index.md b/docs/fr/v1/api/clean/index.md index 003888d31..469a4f31b 100644 --- a/docs/fr/v1/api/clean/index.md +++ b/docs/fr/v1/api/clean/index.md @@ -28,6 +28,9 @@ Les primitives permettent de manipuler dans du métier des types de base (`Strin ## [Contraintes](/fr/v1/api/clean/constraints) Les contraintes permettent d'ajouter des règles supplémentaires sur les primitives. +## [castConstraint](/fr/v1/api/clean/castConstraint) +Étend une valeur contrainte avec des contraintes compatibles sans revalidation. + ## [NewType](/fr/v1/api/clean/newType) Crée un `NewType` (brand) adossé à un `DataParser`, avec contraintes optionnelles. diff --git a/docs/fr/v1/api/clean/newType.md b/docs/fr/v1/api/clean/newType.md index 14df6f796..e1c974a28 100644 --- a/docs/fr/v1/api/clean/newType.md +++ b/docs/fr/v1/api/clean/newType.md @@ -2,8 +2,8 @@ outline: [2, 3] description: "Un NewType est un type conçu pour répondre aux exigences métier, tout en étant basé sur un type primitif (ou une structure de données) existant. Il permet d'ajouter des contraintes et des règles spécifiques, garantissant que les valeurs respectent les conditions définies par le métier." prev: - text: "Contraintes" - link: "/fr/v1/api/clean/constraints" + text: "castConstraint" + link: "/fr/v1/api/clean/castConstraint" next: text: "Entités" link: "/fr/v1/api/clean/entity" @@ -108,14 +108,6 @@ function getConstraint( Le nom unique du `NewType` (ex: `"userId"`). -#### `dataParser` - -Le `DataParser` utilisé pour valider la donnée (incluant les checkers ajoutés par les contraintes). - -#### `constrains` - -La liste des contraintes appliquées au `NewType`. - ## Voir aussi - [Primitives](/fr/v1/api/clean/primitives/) diff --git a/docs/fr/v1/api/clean/primitives/index.md b/docs/fr/v1/api/clean/primitives/index.md index 4384ae576..4cf307c62 100644 --- a/docs/fr/v1/api/clean/primitives/index.md +++ b/docs/fr/v1/api/clean/primitives/index.md @@ -91,12 +91,6 @@ function is( ): value is Primitive ``` -### Propriétés - -#### `dataParser` - -Correspond au [dataParser](/fr/v1/api/dataParser/) qui valide la primitive. - ## Opérateurs ### [equal](/fr/v1/api/clean/primitives/operators/equal) diff --git a/docs/public/libs/v1/array/types/createTuple.d.ts b/docs/public/libs/v1/array/types/createTuple.d.ts index 927953527..8d87d6881 100644 --- a/docs/public/libs/v1/array/types/createTuple.d.ts +++ b/docs/public/libs/v1/array/types/createTuple.d.ts @@ -1,2 +1,2 @@ import { type IsEqual } from "../../common/types/isEqual"; -export type CreateTuple = IsEqual extends true ? GenericValue[] : IsEqual extends true ? [] : [...GenericLastTuple, GenericValue] extends infer InferredResult extends any[] ? IsEqual extends true ? InferredResult : IsEqual extends true ? [...InferredResult, ...GenericValue[]] : CreateTuple : never; +export type CreateTuple = IsEqual extends true ? GenericValue[] : IsEqual extends true ? [] : [...GenericLastTuple, GenericValue] extends infer InferredResult extends any[] ? IsEqual extends true ? InferredResult : IsEqual extends true ? [...InferredResult, ...GenericValue[]] : CreateTuple : never; diff --git a/docs/public/libs/v1/clean/constraint/base.cjs b/docs/public/libs/v1/clean/constraint/base.cjs index 9defc9826..07e49c970 100644 --- a/docs/public/libs/v1/clean/constraint/base.cjs +++ b/docs/public/libs/v1/clean/constraint/base.cjs @@ -33,6 +33,7 @@ function createConstraint(name, primitiveHandler, checker) { const dataParserWithCheckers = primitiveHandler .dataParser .addChecker(...checkers); + const constraintKindValue = { [name]: null }; function create$2(data) { const result = dataParserWithCheckers.parse(unwrap.unwrap(data)); if (is.isLeft(result)) { @@ -68,6 +69,12 @@ function createConstraint(name, primitiveHandler, checker) { name, primitiveHandler, checkers, + internal: { + primitiveHandler, + dataParser: dataParserWithCheckers, + checkers, + constraintKindValue, + }, create: create$2, createOrThrow, createWithUnknown: create$2, diff --git a/docs/public/libs/v1/clean/constraint/base.d.ts b/docs/public/libs/v1/clean/constraint/base.d.ts index cfb86ae1f..bc8a84eb4 100644 --- a/docs/public/libs/v1/clean/constraint/base.d.ts +++ b/docs/public/libs/v1/clean/constraint/base.d.ts @@ -4,7 +4,7 @@ import * as DArray from "../../array"; import * as DEither from "../../either"; import type * as DDataParser from "../../dataParser"; export declare const constrainedTypeKind: import("../..").KindHandler>>; -export interface ConstrainedType extends Kind>, WrappedValue { +export interface ConstrainedType extends Kind>, WrappedValue { } export declare const constraintHandlerKind: import("../..").KindHandler>; export interface ConstraintHandler extends Kind { @@ -14,15 +14,35 @@ export interface ConstraintHandler; + readonly internal: { + /** + * The DataParser with the constraint checkers applied. + * + */ + readonly dataParser: DDataParser.Contract; + /** + * The primitive handler on which the constraint applies (String, Number, etc.). + * + */ + readonly primitiveHandler: PrimitiveHandler; + /** + * The list of DataParser checkers used to validate the primitive. + * + */ + readonly checkers: GenericCheckers; + /** + * The constraint kind metadata used to tag constrained values. + * + */ + readonly constraintKindValue: Record; + }; /** * Creates a constrained value and returns an Either. * @@ -143,5 +163,5 @@ export declare function createConstraint[], unknown>>; } -export type GetConstraint = DDataParser.InputChecker> = Extract, any>; +export type GetConstraint = DDataParser.InputChecker> = Extract, any>; export {}; diff --git a/docs/public/libs/v1/clean/constraint/base.mjs b/docs/public/libs/v1/clean/constraint/base.mjs index cfe9d1b18..8994808f8 100644 --- a/docs/public/libs/v1/clean/constraint/base.mjs +++ b/docs/public/libs/v1/clean/constraint/base.mjs @@ -31,6 +31,7 @@ function createConstraint(name, primitiveHandler, checker) { const dataParserWithCheckers = primitiveHandler .dataParser .addChecker(...checkers); + const constraintKindValue = { [name]: null }; function create(data) { const result = dataParserWithCheckers.parse(unwrap(data)); if (isLeft(result)) { @@ -66,6 +67,12 @@ function createConstraint(name, primitiveHandler, checker) { name, primitiveHandler, checkers, + internal: { + primitiveHandler, + dataParser: dataParserWithCheckers, + checkers, + constraintKindValue, + }, create, createOrThrow, createWithUnknown: create, diff --git a/docs/public/libs/v1/clean/constraint/cast.cjs b/docs/public/libs/v1/clean/constraint/cast.cjs new file mode 100644 index 000000000..c3fc18731 --- /dev/null +++ b/docs/public/libs/v1/clean/constraint/cast.cjs @@ -0,0 +1,18 @@ +'use strict'; + +var base = require('./base.cjs'); +var coalescing = require('../../array/coalescing.cjs'); + +function castConstraint(constrainedType, constraintHandler) { + const preparedConstraintHandler = coalescing.coalescing(constraintHandler); + const newConstraints = { + ...base.constrainedTypeKind.getValue(constrainedType), + }; + for (let index = 0; index < preparedConstraintHandler.length; index++) { + const constraintHandler = preparedConstraintHandler[index]; + newConstraints[constraintHandler.name] = null; + } + return base.constrainedTypeKind.addTo(constrainedType, newConstraints); +} + +exports.castConstraint = castConstraint; diff --git a/docs/public/libs/v1/clean/constraint/cast.d.ts b/docs/public/libs/v1/clean/constraint/cast.d.ts new file mode 100644 index 000000000..87f535d79 --- /dev/null +++ b/docs/public/libs/v1/clean/constraint/cast.d.ts @@ -0,0 +1,29 @@ +import { type UnionToIntersection, type SimplifyTopLevel, type NeverCoalescing, type And, type Not, type IsEqual } from "../../common"; +import { type ConstraintHandler, type ConstrainedType, type GetConstraint } from "./base"; +import { type Negative, type NumberMaxHandlerInternal, type NumberMaxInternal, type NumberMinHandlerInternal, type NumberMinInternal, type Positive, type StringMaxHandlerInternal, type StringMaxInternal, type StringMinHandlerInternal, type StringMinInternal } from "./defaultConstraint"; +import { type IsLess, type IsGreater } from "../../number"; +declare const SymbolCastErrorMessage: unique symbol; +type CastConstraintError = SimplifyTopLevel<{ + [SymbolCastErrorMessage]: `The constraint "${GenericConstrainHandler["name"]}" is not applicable: ${GenericReason}.`; +}>; +type ForbiddenBadCast = ((GenericConstrainHandler extends NumberMinHandlerInternal ? GenericConstrainedType extends Positive ? IsLess extends true ? never : CastConstraintError : GenericConstrainedType extends NumberMinInternal ? And<[ + IsLess, + Not> +]> extends true ? never : CastConstraintError : CastConstraintError : never) | (GenericConstrainHandler extends NumberMaxHandlerInternal ? GenericConstrainedType extends Negative ? IsGreater extends true ? never : CastConstraintError : GenericConstrainedType extends NumberMaxInternal ? And<[ + IsGreater, + Not> +]> extends true ? never : CastConstraintError : CastConstraintError : never) | (GenericConstrainHandler extends StringMinHandlerInternal ? GenericConstrainedType extends StringMinInternal ? And<[ + IsLess, + Not> +]> extends true ? never : CastConstraintError : CastConstraintError : never) | (GenericConstrainHandler extends StringMaxHandlerInternal ? GenericConstrainedType extends StringMaxInternal ? And<[ + IsGreater, + Not> +]> extends true ? never : CastConstraintError : CastConstraintError : never) | (GenericConstrainHandler extends typeof Positive ? GenericConstrainedType extends NumberMinInternal ? And<[ + IsLess<0, InferredReferenceValue>, + Not> +]> extends true ? never : CastConstraintError : CastConstraintError : never) | (GenericConstrainHandler extends typeof Negative ? GenericConstrainedType extends NumberMaxInternal ? And<[ + IsGreater<0, InferredReferenceValue>, + Not> +]> extends true ? never : CastConstraintError : CastConstraintError : never) | (GenericConstrainHandler extends (typeof Negative | typeof Positive | StringMaxHandlerInternal | StringMinHandlerInternal | NumberMaxHandlerInternal | NumberMinHandlerInternal) ? never : CastConstraintError)) extends infer InferredResult ? NeverCoalescing : never; +export declare function castConstraint(constrainedType: (GenericConstrainedType & ForbiddenBadCast), constraintHandler: GenericConstrainHandler | GenericConstrainHandler[]): (GenericConstrainedType & UnionToIntersection : never>); +export {}; diff --git a/docs/public/libs/v1/clean/constraint/cast.mjs b/docs/public/libs/v1/clean/constraint/cast.mjs new file mode 100644 index 000000000..ae69f1f5a --- /dev/null +++ b/docs/public/libs/v1/clean/constraint/cast.mjs @@ -0,0 +1,16 @@ +import { constrainedTypeKind } from './base.mjs'; +import { coalescing } from '../../array/coalescing.mjs'; + +function castConstraint(constrainedType, constraintHandler) { + const preparedConstraintHandler = coalescing(constraintHandler); + const newConstraints = { + ...constrainedTypeKind.getValue(constrainedType), + }; + for (let index = 0; index < preparedConstraintHandler.length; index++) { + const constraintHandler = preparedConstraintHandler[index]; + newConstraints[constraintHandler.name] = null; + } + return constrainedTypeKind.addTo(constrainedType, newConstraints); +} + +export { castConstraint }; diff --git a/docs/public/libs/v1/clean/constraint/defaultConstraint/number.cjs b/docs/public/libs/v1/clean/constraint/defaultConstraint/number.cjs index 95be9f5ce..3a5953865 100644 --- a/docs/public/libs/v1/clean/constraint/defaultConstraint/number.cjs +++ b/docs/public/libs/v1/clean/constraint/defaultConstraint/number.cjs @@ -13,11 +13,11 @@ const Int = base.createConstraint("int", base$1.Number, int.checkerInt()); /** * {@include clean/Positive/index.md} */ -const Positive = base.createConstraint("positive", base$1.Number, min.checkerNumberMin(1)); +const Positive = base.createConstraint("positive", base$1.Number, min.checkerNumberMin(0)); /** * {@include clean/Negative/index.md} */ -const Negative = base.createConstraint("negative", base$1.Number, max.checkerNumberMax(-1)); +const Negative = base.createConstraint("negative", base$1.Number, max.checkerNumberMax(0)); /** * {@include clean/NumberMin/index.md} */ @@ -30,17 +30,9 @@ function NumberMin(value) { function NumberMax(value) { return base.createConstraint(`number-max-${value}`, base$1.Number, max.checkerNumberMax(value)); } -/** - * {@include clean/PositiveInt/index.md} - */ -const PositiveInt = base.createConstraint("positive-int", base$1.Number, [ - int.checkerInt(), - min.checkerNumberMin(1), -]); exports.Int = Int; exports.Negative = Negative; exports.NumberMax = NumberMax; exports.NumberMin = NumberMin; exports.Positive = Positive; -exports.PositiveInt = PositiveInt; diff --git a/docs/public/libs/v1/clean/constraint/defaultConstraint/number.d.ts b/docs/public/libs/v1/clean/constraint/defaultConstraint/number.d.ts index b757969c6..2d636fb14 100644 --- a/docs/public/libs/v1/clean/constraint/defaultConstraint/number.d.ts +++ b/docs/public/libs/v1/clean/constraint/defaultConstraint/number.d.ts @@ -1,4 +1,4 @@ -import { type GetConstraint } from "../base"; +import { type ConstraintHandler, type GetConstraint } from "../base"; import * as DDataParser from "../../../dataParser"; import { type OnlyLiteralNumber } from "../../../common"; /** @@ -28,7 +28,7 @@ import { type OnlyLiteralNumber } from "../../../common"; * @namespace C * */ -export declare const Int: import("..").ConstraintHandler<"int", number, readonly [DDataParser.DataParserCheckerInt], never>; +export declare const Int: ConstraintHandler<"int", number, readonly [DDataParser.DataParserCheckerInt], never>; export type Int = GetConstraint; /** * Constraint handler that validates strictly positive numbers (>= 1). @@ -57,7 +57,7 @@ export type Int = GetConstraint; * @namespace C * */ -export declare const Positive: import("..").ConstraintHandler<"positive", number, readonly [DDataParser.DataParserCheckerNumberMin], never>; +export declare const Positive: ConstraintHandler<"positive", number, readonly [DDataParser.DataParserCheckerNumberMin], never>; export type Positive = GetConstraint; /** * Constraint handler that validates strictly negative numbers (<= -1). @@ -86,8 +86,10 @@ export type Positive = GetConstraint; * @namespace C * */ -export declare const Negative: import("..").ConstraintHandler<"negative", number, readonly [DDataParser.DataParserCheckerNumberMax], never>; +export declare const Negative: ConstraintHandler<"negative", number, readonly [DDataParser.DataParserCheckerNumberMax], never>; export type Negative = GetConstraint; +export type NumberMinHandlerInternal = Extract, any>; +export type NumberMinInternal = GetConstraint>; /** * Constraint factory that validates numbers greater than or equal to a minimum. * @@ -116,8 +118,10 @@ export type Negative = GetConstraint; * @namespace C * */ -export declare function NumberMin(value: GenericValue & OnlyLiteralNumber): import("..").ConstraintHandler<`number-min-${GenericValue & OnlyLiteralNumber}`, number, readonly [DDataParser.DataParserCheckerNumberMin], never>; -export type NumberMin = ReturnType>; +export declare function NumberMin(value: GenericValue & OnlyLiteralNumber): NumberMinHandlerInternal; +export type NumberMin = GetConstraint>>; +export type NumberMaxHandlerInternal = Extract, any>; +export type NumberMaxInternal = GetConstraint>; /** * Constraint factory that validates numbers less than or equal to a maximum. * @@ -146,34 +150,5 @@ export type NumberMin = ReturnType(value: GenericValue & OnlyLiteralNumber): import("..").ConstraintHandler<`number-max-${GenericValue & OnlyLiteralNumber}`, number, readonly [DDataParser.DataParserCheckerNumberMax], never>; -export type NumberMax = ReturnType>; -/** - * Constraint handler that validates strictly positive integers (>= 1). - * - * **Supported call styles:** - * - Classic: `PositiveInt.create(value)` -> returns Either - * - * Use it as a reusable rule to validate inputs and to constrain NewTypes to positive integer numbers. - * - * ```ts - * const result = C.PositiveInt.create(4); - * - * if (E.isRight(result)) { - * // result: E.Right<"createConstrainedType", C.ConstrainedType<"positive-int", 4>> - * } - * - * const value = C.PositiveInt.createOrThrow(10); - * // value: C.ConstrainedType<"positive-int", 10> - * - * C.PositiveInt.is(value); // type guard - * - * ``` - * - * @see https://utils.duplojs.dev/en/v1/api/clean/constraints - * - * @namespace C - * - */ -export declare const PositiveInt: import("..").ConstraintHandler<"positive-int", number, readonly [DDataParser.DataParserCheckerInt, DDataParser.DataParserCheckerNumberMin], never>; -export type PositiveInt = GetConstraint; +export declare function NumberMax(value: GenericValue & OnlyLiteralNumber): NumberMaxHandlerInternal; +export type NumberMax = GetConstraint>>; diff --git a/docs/public/libs/v1/clean/constraint/defaultConstraint/number.mjs b/docs/public/libs/v1/clean/constraint/defaultConstraint/number.mjs index ae09c6337..962e1b2ed 100644 --- a/docs/public/libs/v1/clean/constraint/defaultConstraint/number.mjs +++ b/docs/public/libs/v1/clean/constraint/defaultConstraint/number.mjs @@ -11,11 +11,11 @@ const Int = createConstraint("int", Number, checkerInt()); /** * {@include clean/Positive/index.md} */ -const Positive = createConstraint("positive", Number, checkerNumberMin(1)); +const Positive = createConstraint("positive", Number, checkerNumberMin(0)); /** * {@include clean/Negative/index.md} */ -const Negative = createConstraint("negative", Number, checkerNumberMax(-1)); +const Negative = createConstraint("negative", Number, checkerNumberMax(0)); /** * {@include clean/NumberMin/index.md} */ @@ -28,12 +28,5 @@ function NumberMin(value) { function NumberMax(value) { return createConstraint(`number-max-${value}`, Number, checkerNumberMax(value)); } -/** - * {@include clean/PositiveInt/index.md} - */ -const PositiveInt = createConstraint("positive-int", Number, [ - checkerInt(), - checkerNumberMin(1), -]); -export { Int, Negative, NumberMax, NumberMin, Positive, PositiveInt }; +export { Int, Negative, NumberMax, NumberMin, Positive }; diff --git a/docs/public/libs/v1/clean/constraint/defaultConstraint/string.d.ts b/docs/public/libs/v1/clean/constraint/defaultConstraint/string.d.ts index 3a45f915f..3555bf612 100644 --- a/docs/public/libs/v1/clean/constraint/defaultConstraint/string.d.ts +++ b/docs/public/libs/v1/clean/constraint/defaultConstraint/string.d.ts @@ -1,4 +1,4 @@ -import { type GetConstraint } from "../base"; +import { type ConstraintHandler, type GetConstraint } from "../base"; import * as DDataParser from "../../../dataParser"; import { type OnlyLiteralNumber } from "../../../common"; /** @@ -28,7 +28,7 @@ import { type OnlyLiteralNumber } from "../../../common"; * @namespace C * */ -export declare const Email: import("..").ConstraintHandler<"email", string, readonly [DDataParser.DataParserCheckerEmail], never>; +export declare const Email: ConstraintHandler<"email", string, readonly [DDataParser.DataParserCheckerEmail], never>; export type Email = GetConstraint; /** * Constraint handler that validates a URL string. @@ -57,8 +57,10 @@ export type Email = GetConstraint; * @namespace C * */ -export declare const Url: import("..").ConstraintHandler<"url", string, readonly [DDataParser.DataParserCheckerUrl], never>; +export declare const Url: ConstraintHandler<"url", string, readonly [DDataParser.DataParserCheckerUrl], never>; export type Url = GetConstraint; +export type StringMinHandlerInternal = Extract, any>; +export type StringMinInternal = GetConstraint>; /** * Constraint factory that validates strings with a minimum length. * @@ -87,8 +89,10 @@ export type Url = GetConstraint; * @namespace C * */ -export declare function StringMin(value: GenericValue & OnlyLiteralNumber): import("..").ConstraintHandler<`string-min-${GenericValue & OnlyLiteralNumber}`, string, readonly [DDataParser.DataParserCheckerStringMin], never>; +export declare function StringMin(value: GenericValue & OnlyLiteralNumber): StringMinHandlerInternal; export type StringMin = GetConstraint>>; +export type StringMaxHandlerInternal = Extract, any>; +export type StringMaxInternal = GetConstraint>; /** * Constraint factory that validates strings with a maximum length. * @@ -117,5 +121,5 @@ export type StringMin = GetConstraint(value: GenericValue & OnlyLiteralNumber): import("..").ConstraintHandler<`string-max-${GenericValue & OnlyLiteralNumber}`, string, readonly [DDataParser.DataParserCheckerStringMax], never>; +export declare function StringMax(value: GenericValue & OnlyLiteralNumber): StringMaxHandlerInternal; export type StringMax = GetConstraint>>; diff --git a/docs/public/libs/v1/clean/constraint/index.d.ts b/docs/public/libs/v1/clean/constraint/index.d.ts index 3a7aea1cb..626baee44 100644 --- a/docs/public/libs/v1/clean/constraint/index.d.ts +++ b/docs/public/libs/v1/clean/constraint/index.d.ts @@ -1,3 +1,4 @@ export * from "./base"; +export * from "./cast"; export * from "./defaultConstraint"; export * from "./set"; diff --git a/docs/public/libs/v1/clean/constraint/set.cjs b/docs/public/libs/v1/clean/constraint/set.cjs index 03936f5f2..b7a01b530 100644 --- a/docs/public/libs/v1/clean/constraint/set.cjs +++ b/docs/public/libs/v1/clean/constraint/set.cjs @@ -32,7 +32,7 @@ class CreateConstraintsSetError extends kind$1.kindHeritage("create-constraint-s */ function createConstraintsSet(primitiveHandler, constraint) { const constraints = coalescing.coalescing(constraint); - const checkers = flatMap.flatMap(constraints, ({ checkers }) => checkers); + const checkers = flatMap.flatMap(constraints, ({ internal }) => internal.checkers); const dataParserWithCheckers = primitiveHandler .dataParser .addChecker(...checkers); @@ -80,6 +80,12 @@ function createConstraintsSet(primitiveHandler, constraint) { return pipe.pipe({ primitiveHandler, constraints, + internal: { + primitiveHandler, + constraints, + constraintKindValue, + dataParser: dataParserWithCheckers, + }, getConstraint, create: create$2, createOrThrow, diff --git a/docs/public/libs/v1/clean/constraint/set.d.ts b/docs/public/libs/v1/clean/constraint/set.d.ts index 61a788da0..32586358c 100644 --- a/docs/public/libs/v1/clean/constraint/set.d.ts +++ b/docs/public/libs/v1/clean/constraint/set.d.ts @@ -7,15 +7,35 @@ import type * as DDataParser from "../../dataParser"; export declare const constraintsSetHandlerKind: import("../..").KindHandler>; export interface ConstraintsSetHandler extends Kind { /** - * The primitive handler used to validate and wrap values (e.g. `C.String`, `C.Number`). - * + * @deprecated */ readonly primitiveHandler: PrimitiveHandler; /** - * The list of constraint handlers applied by this set. - * + * @deprecated */ readonly constraints: GenericConstraintsHandler; + readonly internal: { + /** + * The DataParser with all constraint checkers from the set applied. + * + */ + readonly dataParser: DDataParser.Contract; + /** + * The primitive handler used to validate and wrap values (e.g. `C.String`, `C.Number`). + * + */ + readonly primitiveHandler: PrimitiveHandler; + /** + * The list of constraint handlers applied by this set. + * + */ + readonly constraints: GenericConstraintsHandler; + /** + * The constraint kind metadata applied by the set. + * + */ + readonly constraintKindValue: Record; + }; /** * Creates a constrained value and returns an Either. * @@ -145,5 +165,5 @@ export declare function createConstraintsSet>; } -export type GetConstraints> = Extract : never : never> : never, any>; +export type GetConstraints> = Extract : never : never> : never, any>; export {}; diff --git a/docs/public/libs/v1/clean/constraint/set.mjs b/docs/public/libs/v1/clean/constraint/set.mjs index 120bf11f2..a13cfa346 100644 --- a/docs/public/libs/v1/clean/constraint/set.mjs +++ b/docs/public/libs/v1/clean/constraint/set.mjs @@ -30,7 +30,7 @@ class CreateConstraintsSetError extends kindHeritage("create-constraint-set-erro */ function createConstraintsSet(primitiveHandler, constraint) { const constraints = coalescing(constraint); - const checkers = flatMap(constraints, ({ checkers }) => checkers); + const checkers = flatMap(constraints, ({ internal }) => internal.checkers); const dataParserWithCheckers = primitiveHandler .dataParser .addChecker(...checkers); @@ -78,6 +78,12 @@ function createConstraintsSet(primitiveHandler, constraint) { return pipe({ primitiveHandler, constraints, + internal: { + primitiveHandler, + constraints, + constraintKindValue, + dataParser: dataParserWithCheckers, + }, getConstraint, create, createOrThrow, diff --git a/docs/public/libs/v1/clean/entity/index.cjs b/docs/public/libs/v1/clean/entity/index.cjs index 478174c0d..13e5947fd 100644 --- a/docs/public/libs/v1/clean/entity/index.cjs +++ b/docs/public/libs/v1/clean/entity/index.cjs @@ -7,12 +7,12 @@ var kind$1 = require('../../common/kind.cjs'); var pipe = require('../../common/pipe.cjs'); var map = require('../../array/map.cjs'); var entry = require('../../object/entry.cjs'); -var fromEntries = require('../../object/fromEntries.cjs'); var transform = require('../../dataParser/parsers/transform.cjs'); var entries = require('../../object/entries.cjs'); var forward = require('../../common/forward.cjs'); var errorKindNamespace = require('../../common/errorKindNamespace.cjs'); var index = require('../../dataParser/parsers/object/index.cjs'); +var fromEntries = require('../../object/fromEntries.cjs'); var base = require('../constraint/base.cjs'); var wrapValue = require('../../common/wrapValue.cjs'); var override = require('../../common/override.cjs'); @@ -40,10 +40,7 @@ function createEntity(name, getPropertiesDefinition) { return entityKind.addTo(properties, name); } const propertiesDefinition = getPropertiesDefinition(property.entityPropertyDefinitionTools); - const mapDataParser = pipe.pipe(forward.forward(propertiesDefinition), entries.entries, map.map(([key, property$1]) => entry.entry(key, property.entityPropertyDefinitionToDataParser(property$1, (newTypeHandler) => { - const constraintKindValue = pipe.pipe(newTypeHandler.constraints, map.map(({ name }) => entry.entry(name, null)), fromEntries.fromEntries); - return transform.transform(newTypeHandler.dataParser, (value) => base.constrainedTypeKind.setTo(newType.newTypeKind.setTo(wrapValue.wrapValue(value), newTypeHandler.name), constraintKindValue)); - }))), fromEntries.fromEntries, index.object, (dataParser) => transform.transform(dataParser, (value) => entityKind.setTo(value, name))); + const mapDataParser = pipe.pipe(forward.forward(propertiesDefinition), entries.entries, map.map(([key, property$1]) => entry.entry(key, property.entityPropertyDefinitionToDataParser(property$1, (newTypeHandler) => transform.transform(newTypeHandler.internal.dataParser, (value) => base.constrainedTypeKind.setTo(newType.newTypeKind.setTo(wrapValue.wrapValue(value), newTypeHandler.name), newTypeHandler.internal.constraintKindValue))))), fromEntries.fromEntries, index.object, (dataParser) => transform.transform(dataParser, (value) => entityKind.setTo(value, name))); function map$1(rawProperties) { const result = mapDataParser.parse(rawProperties); if (is.isLeft(result)) { @@ -74,6 +71,9 @@ function createEntity(name, getPropertiesDefinition) { name, propertiesDefinition, mapDataParser, + internal: { + mapDataParser, + }, new: theNew, map: map$1, mapOrThrow, @@ -92,4 +92,5 @@ exports.entityPropertyStructureKind = property.entityPropertyStructureKind; exports.entityPropertyUnionKind = property.entityPropertyUnionKind; exports.CreateEntityError = CreateEntityError; exports.createEntity = createEntity; +exports.entityHandlerKind = entityHandlerKind; exports.entityKind = entityKind; diff --git a/docs/public/libs/v1/clean/entity/index.d.ts b/docs/public/libs/v1/clean/entity/index.d.ts index 6a2ac8257..1fe4e099d 100644 --- a/docs/public/libs/v1/clean/entity/index.d.ts +++ b/docs/public/libs/v1/clean/entity/index.d.ts @@ -18,7 +18,7 @@ export type PropertiesToMapOfEntity>; export interface Entity extends Kind { } -declare const entityHandlerKind: import("../../common").KindHandler>; +export declare const entityHandlerKind: import("../../common").KindHandler>; export interface EntityHandler extends Kind { /** * The entity name used as a runtime identifier (for example "User"). @@ -30,7 +30,17 @@ export interface EntityHandler, unknown>; + readonly internal: { + /** + * The DataParser used internally to map raw properties into an entity. + * + */ + readonly mapDataParser: DDataParser.Contract, unknown>; + }; /** * Builds an entity from already typed properties. * diff --git a/docs/public/libs/v1/clean/entity/index.mjs b/docs/public/libs/v1/clean/entity/index.mjs index 3d65fda16..8f5418fe0 100644 --- a/docs/public/libs/v1/clean/entity/index.mjs +++ b/docs/public/libs/v1/clean/entity/index.mjs @@ -6,12 +6,12 @@ import { kindHeritage } from '../../common/kind.mjs'; import { pipe } from '../../common/pipe.mjs'; import { map } from '../../array/map.mjs'; import { entry } from '../../object/entry.mjs'; -import { fromEntries } from '../../object/fromEntries.mjs'; import { transform } from '../../dataParser/parsers/transform.mjs'; import { entries } from '../../object/entries.mjs'; import { forward } from '../../common/forward.mjs'; import { createErrorKind } from '../../common/errorKindNamespace.mjs'; import { object } from '../../dataParser/parsers/object/index.mjs'; +import { fromEntries } from '../../object/fromEntries.mjs'; import { constrainedTypeKind } from '../constraint/base.mjs'; import { wrapValue } from '../../common/wrapValue.mjs'; import { createOverride } from '../../common/override.mjs'; @@ -39,10 +39,7 @@ function createEntity(name, getPropertiesDefinition) { return entityKind.addTo(properties, name); } const propertiesDefinition = getPropertiesDefinition(entityPropertyDefinitionTools); - const mapDataParser = pipe(forward(propertiesDefinition), entries, map(([key, property]) => entry(key, entityPropertyDefinitionToDataParser(property, (newTypeHandler) => { - const constraintKindValue = pipe(newTypeHandler.constraints, map(({ name }) => entry(name, null)), fromEntries); - return transform(newTypeHandler.dataParser, (value) => constrainedTypeKind.setTo(newTypeKind.setTo(wrapValue(value), newTypeHandler.name), constraintKindValue)); - }))), fromEntries, object, (dataParser) => transform(dataParser, (value) => entityKind.setTo(value, name))); + const mapDataParser = pipe(forward(propertiesDefinition), entries, map(([key, property]) => entry(key, entityPropertyDefinitionToDataParser(property, (newTypeHandler) => transform(newTypeHandler.internal.dataParser, (value) => constrainedTypeKind.setTo(newTypeKind.setTo(wrapValue(value), newTypeHandler.name), newTypeHandler.internal.constraintKindValue))))), fromEntries, object, (dataParser) => transform(dataParser, (value) => entityKind.setTo(value, name))); function map$1(rawProperties) { const result = mapDataParser.parse(rawProperties); if (isLeft(result)) { @@ -73,6 +70,9 @@ function createEntity(name, getPropertiesDefinition) { name, propertiesDefinition, mapDataParser, + internal: { + mapDataParser, + }, new: theNew, map: map$1, mapOrThrow, @@ -82,4 +82,4 @@ function createEntity(name, getPropertiesDefinition) { } createEntity.overrideHandler = createOverride("@duplojs/utils/clean/entity"); -export { CreateEntityError, createEntity, entityKind, entityPropertyDefinitionToDataParser, entityPropertyDefinitionTools }; +export { CreateEntityError, createEntity, entityHandlerKind, entityKind, entityPropertyDefinitionToDataParser, entityPropertyDefinitionTools }; diff --git a/docs/public/libs/v1/clean/index.cjs b/docs/public/libs/v1/clean/index.cjs index 482825775..82da38ac7 100644 --- a/docs/public/libs/v1/clean/index.cjs +++ b/docs/public/libs/v1/clean/index.cjs @@ -7,9 +7,11 @@ var repository = require('./repository.cjs'); var useCase = require('./useCase.cjs'); var flag = require('./flag.cjs'); var maybe = require('./maybe.cjs'); +var toMapDataParser = require('./toMapDataParser.cjs'); var property = require('./entity/property.cjs'); var unwrap = require('./entity/unwrap.cjs'); var base = require('./constraint/base.cjs'); +var cast = require('./constraint/cast.cjs'); var number = require('./constraint/defaultConstraint/number.cjs'); var string = require('./constraint/defaultConstraint/string.cjs'); var time = require('./constraint/defaultConstraint/time.cjs'); @@ -52,6 +54,7 @@ exports.newTypeHandlerKind = newType.newTypeHandlerKind; exports.newTypeKind = newType.newTypeKind; exports.CreateEntityError = index.CreateEntityError; exports.createEntity = index.createEntity; +exports.entityHandlerKind = index.entityHandlerKind; exports.entityKind = index.entityKind; exports.createRepository = repository.createRepository; exports.repositoryHandlerKind = repository.repositoryHandlerKind; @@ -62,6 +65,7 @@ exports.createFlag = flag.createFlag; exports.flagKind = flag.flagKind; exports.none = maybe.none; exports.some = maybe.some; +exports.toMapDataParser = toMapDataParser.toMapDataParser; exports.entityPropertyArrayKind = property.entityPropertyArrayKind; exports.entityPropertyDefinitionToDataParser = property.entityPropertyDefinitionToDataParser; exports.entityPropertyDefinitionTools = property.entityPropertyDefinitionTools; @@ -75,12 +79,12 @@ exports.CreateConstrainedTypeError = base.CreateConstrainedTypeError; exports.constrainedTypeKind = base.constrainedTypeKind; exports.constraintHandlerKind = base.constraintHandlerKind; exports.createConstraint = base.createConstraint; +exports.castConstraint = cast.castConstraint; exports.Int = number.Int; exports.Negative = number.Negative; exports.NumberMax = number.NumberMax; exports.NumberMin = number.NumberMin; exports.Positive = number.Positive; -exports.PositiveInt = number.PositiveInt; exports.Email = string.Email; exports.StringMax = string.StringMax; exports.StringMin = string.StringMin; diff --git a/docs/public/libs/v1/clean/index.d.ts b/docs/public/libs/v1/clean/index.d.ts index a7a8d2cb7..51749bb7d 100644 --- a/docs/public/libs/v1/clean/index.d.ts +++ b/docs/public/libs/v1/clean/index.d.ts @@ -33,3 +33,4 @@ export * from "./repository"; export * from "./useCase"; export * from "./flag"; export * from "./maybe"; +export * from "./toMapDataParser"; diff --git a/docs/public/libs/v1/clean/index.mjs b/docs/public/libs/v1/clean/index.mjs index 8e0178ebb..a3d87eb04 100644 --- a/docs/public/libs/v1/clean/index.mjs +++ b/docs/public/libs/v1/clean/index.mjs @@ -1,14 +1,16 @@ export { createCleanKind } from './kind.mjs'; export { CreateNewTypeError, createNewType, newTypeHandlerKind, newTypeKind } from './newType.mjs'; -export { CreateEntityError, createEntity, entityKind } from './entity/index.mjs'; +export { CreateEntityError, createEntity, entityHandlerKind, entityKind } from './entity/index.mjs'; export { createRepository, repositoryHandlerKind } from './repository.mjs'; export { createUseCase, useCaseHandlerKind, useCaseInstances } from './useCase.mjs'; export { createFlag, flagKind } from './flag.mjs'; export { none, some } from './maybe.mjs'; +export { toMapDataParser } from './toMapDataParser.mjs'; export { entityPropertyArrayKind, entityPropertyDefinitionToDataParser, entityPropertyDefinitionTools, entityPropertyIdentifierKind, entityPropertyNullableKind, entityPropertyStructureKind, entityPropertyUnionKind } from './entity/property.mjs'; export { unwrapEntity, unwrapEntityProperty } from './entity/unwrap.mjs'; export { CreateConstrainedTypeError, constrainedTypeKind, constraintHandlerKind, createConstraint } from './constraint/base.mjs'; -export { Int, Negative, NumberMax, NumberMin, Positive, PositiveInt } from './constraint/defaultConstraint/number.mjs'; +export { castConstraint } from './constraint/cast.mjs'; +export { Int, Negative, NumberMax, NumberMin, Positive } from './constraint/defaultConstraint/number.mjs'; export { Email, StringMax, StringMin, Url } from './constraint/defaultConstraint/string.mjs'; export { NegativeTime, PositiveTime } from './constraint/defaultConstraint/time.mjs'; export { CreateConstraintsSetError, constraintsSetHandlerKind, createConstraintsSet } from './constraint/set.mjs'; diff --git a/docs/public/libs/v1/clean/newType.cjs b/docs/public/libs/v1/clean/newType.cjs index 63407c1e4..8084ca085 100644 --- a/docs/public/libs/v1/clean/newType.cjs +++ b/docs/public/libs/v1/clean/newType.cjs @@ -35,7 +35,7 @@ class CreateNewTypeError extends kind$1.kindHeritage("create-new-type-error", er */ function createNewType(name, dataParser, constraint) { const constraints = coalescing.coalescing(constraint ?? []); - const checkers = flatMap.flatMap(constraints, ({ checkers }) => checkers); + const checkers = flatMap.flatMap(constraints, ({ internal }) => internal.checkers); const dataParserWithCheckers = constraint ? dataParser.addChecker(...checkers) : dataParser; @@ -85,6 +85,11 @@ function createNewType(name, dataParser, constraint) { name, dataParser: dataParserWithCheckers, constraints, + internal: { + dataParser: dataParserWithCheckers, + constraints, + constraintKindValue, + }, getConstraint, create: create$2, createOrThrow, diff --git a/docs/public/libs/v1/clean/newType.d.ts b/docs/public/libs/v1/clean/newType.d.ts index 1deb44c26..9d4df1335 100644 --- a/docs/public/libs/v1/clean/newType.d.ts +++ b/docs/public/libs/v1/clean/newType.d.ts @@ -17,15 +17,30 @@ export interface NewTypeHandler; /** - * The list of constraints applied to this NewType. - * + * @deprecated */ readonly constraints: GenericConstraintsHandler; + readonly internal: { + /** + * The DataParser used to validate and transform raw inputs. + * + */ + readonly dataParser: DDataParser.Contract; + /** + * The list of constraints applied to this NewType. + * + */ + readonly constraints: GenericConstraintsHandler; + /** + * The constraint kind metadata applied to this NewType. + * + */ + readonly constraintKindValue: Record; + }; /** * Creates a NewType value and returns an Either. * @@ -156,5 +171,5 @@ export declare function createNewType[], unknown>[], unknown>>; } -export type GetNewType, GenericValue extends DDataParser.Output = DDataParser.Output> = Extract : never, any>; +export type GetNewType, GenericValue extends DDataParser.Output = DDataParser.Output> = Extract : never, any>; export {}; diff --git a/docs/public/libs/v1/clean/newType.mjs b/docs/public/libs/v1/clean/newType.mjs index e793a160d..a337a3a8c 100644 --- a/docs/public/libs/v1/clean/newType.mjs +++ b/docs/public/libs/v1/clean/newType.mjs @@ -33,7 +33,7 @@ class CreateNewTypeError extends kindHeritage("create-new-type-error", createErr */ function createNewType(name, dataParser, constraint) { const constraints = coalescing(constraint ?? []); - const checkers = flatMap(constraints, ({ checkers }) => checkers); + const checkers = flatMap(constraints, ({ internal }) => internal.checkers); const dataParserWithCheckers = constraint ? dataParser.addChecker(...checkers) : dataParser; @@ -83,6 +83,11 @@ function createNewType(name, dataParser, constraint) { name, dataParser: dataParserWithCheckers, constraints, + internal: { + dataParser: dataParserWithCheckers, + constraints, + constraintKindValue, + }, getConstraint, create, createOrThrow, diff --git a/docs/public/libs/v1/clean/primitive/operations/equal.cjs b/docs/public/libs/v1/clean/primitive/operations/equal.cjs index 30f3d3a04..d17a682bd 100644 --- a/docs/public/libs/v1/clean/primitive/operations/equal.cjs +++ b/docs/public/libs/v1/clean/primitive/operations/equal.cjs @@ -8,6 +8,9 @@ function equal(...args) { return (input) => equal(input, value); } const [input, value] = args; + if (input === null || value === null) { + return input === value; + } return unwrap.unwrap(input).toString() === unwrap.unwrap(value).toString(); } diff --git a/docs/public/libs/v1/clean/primitive/operations/equal.d.ts b/docs/public/libs/v1/clean/primitive/operations/equal.d.ts index aa741d98f..cb9da7aeb 100644 --- a/docs/public/libs/v1/clean/primitive/operations/equal.d.ts +++ b/docs/public/libs/v1/clean/primitive/operations/equal.d.ts @@ -34,5 +34,5 @@ import { type Primitive, type Primitives } from "../base"; * @namespace C * */ -export declare function equal> | Unwrap)>(value: GenericValue): (input: GenericInput) => input is GenericInput & Primitive>; -export declare function equal> | Unwrap)>(input: GenericInput, value: GenericValue): input is GenericInput & Primitive>; +export declare function equal>> | Unwrap)>(value: GenericValue): (input: GenericInput) => input is (GenericInput & (GenericValue extends null ? GenericValue : Primitive>>)); +export declare function equal>> | Unwrap)>(input: GenericInput, value: GenericValue): input is (GenericInput & (GenericValue extends null ? GenericValue : Primitive>>)); diff --git a/docs/public/libs/v1/clean/primitive/operations/equal.mjs b/docs/public/libs/v1/clean/primitive/operations/equal.mjs index b284062e0..3d9b0833c 100644 --- a/docs/public/libs/v1/clean/primitive/operations/equal.mjs +++ b/docs/public/libs/v1/clean/primitive/operations/equal.mjs @@ -6,6 +6,9 @@ function equal(...args) { return (input) => equal(input, value); } const [input, value] = args; + if (input === null || value === null) { + return input === value; + } return unwrap(input).toString() === unwrap(value).toString(); } diff --git a/docs/public/libs/v1/clean/toMapDataParser.cjs b/docs/public/libs/v1/clean/toMapDataParser.cjs new file mode 100644 index 000000000..20da7ffaa --- /dev/null +++ b/docs/public/libs/v1/clean/toMapDataParser.cjs @@ -0,0 +1,52 @@ +'use strict'; + +var newType = require('./newType.cjs'); +var base = require('./primitive/base.cjs'); +var base$1 = require('./constraint/base.cjs'); +var set = require('./constraint/set.cjs'); +var hasSomeKinds = require('../common/hasSomeKinds.cjs'); +var index = require('../pattern/match/index.cjs'); +var transform = require('../dataParser/parsers/transform.cjs'); +var index$1 = require('../dataParser/parsers/string/index.cjs'); +var index$2 = require('../dataParser/parsers/number/index.cjs'); +var index$3 = require('../dataParser/parsers/bigint/index.cjs'); +var boolean = require('../dataParser/parsers/boolean.cjs'); +var date = require('../dataParser/parsers/date.cjs'); +var index$4 = require('../dataParser/parsers/time/index.cjs'); +var empty = require('../dataParser/parsers/empty.cjs'); +var nil = require('../dataParser/parsers/nil.cjs'); +var wrapValue = require('../common/wrapValue.cjs'); + +function toMapDataParser(input, params) { + const dataParser = (base.primitiveHandlerKind.has(input) + ? input.dataParser.clone() + : input.internal.dataParser.clone()); + if (params?.coerce + && hasSomeKinds.hasSomeKinds(dataParser, [ + index$1.stringKind, + index$2.numberKind, + index$3.bigIntKind, + index$3.bigIntKind, + boolean.booleanKind, + date.dateKind, + index$4.timeKind, + empty.emptyKind, + nil.nilKind, + ])) { + dataParser.definition.coerce = true; + } + const valueContainer = index.match(input) + .when(newType.newTypeHandlerKind.has, (newType$1) => ({ + ...newType.newTypeKind.setTo({}, newType$1.name), + ...base$1.constrainedTypeKind.setTo({}, newType$1.internal.constraintKindValue), + })) + .when(hasSomeKinds.hasSomeKinds([base$1.constraintHandlerKind, set.constraintsSetHandlerKind]), (constraintOrSet) => base$1.constrainedTypeKind.setTo({}, constraintOrSet.internal.constraintKindValue)) + .when(base.primitiveHandlerKind.has, () => ({})) + .exhaustive(); + return transform.transform(dataParser, (value) => ({ + ...valueContainer, + [wrapValue.keyWrappedValue]: value, + })); +} + +exports.toMapDataParser = toMapDataParser; diff --git a/docs/public/libs/v1/clean/toMapDataParser.d.ts b/docs/public/libs/v1/clean/toMapDataParser.d.ts new file mode 100644 index 000000000..8ef67f6ac --- /dev/null +++ b/docs/public/libs/v1/clean/toMapDataParser.d.ts @@ -0,0 +1,53 @@ +import * as DDataParser from "../dataParser"; +import { type ConstraintHandler, type ConstraintsSetHandler, type GetConstraint, type GetConstraints } from "./constraint"; +import { type GetNewType, type NewTypeHandler } from "./newType"; +import { type PrimitiveHandler } from "./primitive"; +type ToMapDataParserInput = NewTypeHandler | ConstraintHandler | ConstraintsSetHandler | PrimitiveHandler; +type OutputDataParser = GenericInput extends NewTypeHandler ? GetNewType : GenericInput extends ConstraintHandler ? GetConstraint : GenericInput extends ConstraintsSetHandler ? GetConstraints : GenericInput extends PrimitiveHandler ? ReturnType : never; +interface ToMapDataParserParams { + coerce?: boolean; +} +/** + * Creates a DataParser that maps Clean handlers or primitives into a wrapped value object. + * + * **Supported call styles:** + * - Classic: `toMapDataParser(handler, params?)` -> returns a DataParser + * - Pipe: `pipe(handler, toMapDataParser)` -> returns a DataParser + * + * The resulting parser preserves kind tags (`newTypeKind`, `constrainedTypeKind`) and stores the parsed value under the wrapped value key. When `coerce` is enabled, compatible primitive parsers will coerce inputs before validation. + * + * ```ts + * const ShortLabel = C.createNewType( + * "ShortLabel", + * DP.string(), + * [C.StringMax(5)], + * ); + * + * const labelParser = C.toMapDataParser(ShortLabel); + * labelParser.parseOrThrow("hello"); + * + * const userIdParser = pipe( + * C.Number, + * C.toMapDataParser, + * ); + * userIdParser.parseOrThrow(42); + * + * const coerceParser = C.toMapDataParser( + * C.String, + * { coerce: true }, + * ); + * coerceParser.parseOrThrow(123); + * + * ``` + * + * @remarks + * - Supported inputs: `NewTypeHandler`, `ConstraintHandler`, `ConstraintsSetHandler`, and `PrimitiveHandler`. + * - Use `coerce: true` to allow conversions (e.g. number to string) on compatible parsers. + * + * @see https://utils.duplojs.dev/en/v1/api/clean/toMapDataParser + * + * @namespace C + * + */ +export declare function toMapDataParser(input: GenericInput, params?: ToMapDataParserParams): DDataParser.Contract, GenericInputDataParser>; +export {}; diff --git a/docs/public/libs/v1/clean/toMapDataParser.mjs b/docs/public/libs/v1/clean/toMapDataParser.mjs new file mode 100644 index 000000000..9e8412450 --- /dev/null +++ b/docs/public/libs/v1/clean/toMapDataParser.mjs @@ -0,0 +1,50 @@ +import { newTypeHandlerKind, newTypeKind } from './newType.mjs'; +import { primitiveHandlerKind } from './primitive/base.mjs'; +import { constrainedTypeKind, constraintHandlerKind } from './constraint/base.mjs'; +import { constraintsSetHandlerKind } from './constraint/set.mjs'; +import { hasSomeKinds } from '../common/hasSomeKinds.mjs'; +import { match } from '../pattern/match/index.mjs'; +import { transform } from '../dataParser/parsers/transform.mjs'; +import { stringKind } from '../dataParser/parsers/string/index.mjs'; +import { numberKind } from '../dataParser/parsers/number/index.mjs'; +import { bigIntKind } from '../dataParser/parsers/bigint/index.mjs'; +import { booleanKind } from '../dataParser/parsers/boolean.mjs'; +import { dateKind } from '../dataParser/parsers/date.mjs'; +import { timeKind } from '../dataParser/parsers/time/index.mjs'; +import { emptyKind } from '../dataParser/parsers/empty.mjs'; +import { nilKind } from '../dataParser/parsers/nil.mjs'; +import { keyWrappedValue } from '../common/wrapValue.mjs'; + +function toMapDataParser(input, params) { + const dataParser = (primitiveHandlerKind.has(input) + ? input.dataParser.clone() + : input.internal.dataParser.clone()); + if (params?.coerce + && hasSomeKinds(dataParser, [ + stringKind, + numberKind, + bigIntKind, + bigIntKind, + booleanKind, + dateKind, + timeKind, + emptyKind, + nilKind, + ])) { + dataParser.definition.coerce = true; + } + const valueContainer = match(input) + .when(newTypeHandlerKind.has, (newType) => ({ + ...newTypeKind.setTo({}, newType.name), + ...constrainedTypeKind.setTo({}, newType.internal.constraintKindValue), + })) + .when(hasSomeKinds([constraintHandlerKind, constraintsSetHandlerKind]), (constraintOrSet) => constrainedTypeKind.setTo({}, constraintOrSet.internal.constraintKindValue)) + .when(primitiveHandlerKind.has, () => ({})) + .exhaustive(); + return transform(dataParser, (value) => ({ + ...valueContainer, + [keyWrappedValue]: value, + })); +} + +export { toMapDataParser }; diff --git a/docs/public/libs/v1/common/index.d.ts b/docs/public/libs/v1/common/index.d.ts index 075e600b1..98df42d00 100644 --- a/docs/public/libs/v1/common/index.d.ts +++ b/docs/public/libs/v1/common/index.d.ts @@ -80,3 +80,4 @@ export * from "./toRegExp"; export * from "./justExec"; export * from "./callThen"; export * from "./queue"; +export * from "./printer"; diff --git a/docs/public/libs/v1/common/printer.cjs b/docs/public/libs/v1/common/printer.cjs new file mode 100644 index 000000000..0c6915620 --- /dev/null +++ b/docs/public/libs/v1/common/printer.cjs @@ -0,0 +1,73 @@ +'use strict'; + +var repeat = require('../string/repeat.cjs'); + +exports.Printer = void 0; +(function (Printer) { + const codeColors = { + red: "\x1b[31m", + green: "\x1b[32m", + yellow: "\x1b[33m", + blue: "\x1b[34m", + magenta: "\x1b[35m", + cyan: "\x1b[36m", + gray: "\x1b[90m", + }; + const codeBold = "\x1b[1m"; + const codeReset = "\x1b[0m"; + Printer.tab = "\t"; + Printer.back = "\n"; + Printer.dash = "-"; + function colorized(...args) { + if (args.length === 1) { + const [color] = args; + return (input) => colorized(input, color); + } + const [input, color] = args; + return `${codeColors[color]}${input}${codeReset}`; + } + Printer.colorized = colorized; + /** + * {@include common/printer/bold/index.md} + */ + function bold(input) { + return `${codeBold}${input}${codeReset}`; + } + Printer.bold = bold; + function colorizedBold(...args) { + if (args.length === 1) { + const [color] = args; + return (input) => colorizedBold(input, color); + } + const [input, color] = args; + return bold(colorized(input, color)); + } + Printer.colorizedBold = colorizedBold; + function indent(level) { + return repeat.repeat(Printer.tab, level); + } + Printer.indent = indent; + function stringify(value) { + try { + return JSON.stringify(value); + } + catch { + return String(value); + } + } + Printer.stringify = stringify; + function render(...args) { + if (args.length === 1) { + const [joinCharacter] = args; + return (values) => render(values, joinCharacter); + } + const [values, joinCharacter] = args; + return values + .flat(Infinity) + .filter((value) => typeof value === "string" || value === true) + .join(joinCharacter); + } + Printer.render = render; + Printer.renderLine = render(" "); + Printer.renderParagraph = render(Printer.back); +})(exports.Printer || (exports.Printer = {})); diff --git a/docs/public/libs/v1/common/printer.d.ts b/docs/public/libs/v1/common/printer.d.ts new file mode 100644 index 000000000..958cd47af --- /dev/null +++ b/docs/public/libs/v1/common/printer.d.ts @@ -0,0 +1,139 @@ +export declare namespace Printer { + const codeColors: { + readonly red: "\u001B[31m"; + readonly green: "\u001B[32m"; + readonly yellow: "\u001B[33m"; + readonly blue: "\u001B[34m"; + readonly magenta: "\u001B[35m"; + readonly cyan: "\u001B[36m"; + readonly gray: "\u001B[90m"; + }; + export const tab = "\t"; + export const back = "\n"; + export const dash = "-"; + export type Colors = keyof typeof codeColors; + /** + * Wraps a string with the ANSI escape sequence of the selected color. Exists in immediate or curried form. + * + * **Supported call styles:** + * - Classic: `Printer.colorized(input, color)` -> returns the colored string + * - Curried: `Printer.colorized(color)` -> returns a function waiting for the string + * + * The function only adds the opening color code and the reset code around the input string. + * + * ```ts + * const directResult = Printer.colorized("Hello", "green"); + * // directResult: "\x1b[32mHello\x1b[0m" + * + * const pipedResult = pipe( + * "Warning", + * Printer.colorized("yellow"), + * ); + * // pipedResult: "\x1b[33mWarning\x1b[0m" + * + * const errorResult = Printer.colorized("Error", "red"); + * // errorResult: "\x1b[31mError\x1b[0m" + * + * ``` + * + * @see https://utils.duplojs.dev/en/v1/api/common/printer/colorized + * + */ + export function colorized(color: Colors): (input: GenericInput) => string; + export function colorized(input: GenericInput, color: Colors): string; + /** + * Wraps a string with the ANSI escape sequence for bold text. + * + * Signature: `Printer.bold(input)` -> returns the bold string + * + * The function prepends the bold code and appends the reset code without altering the input content. + * + * ```ts + * const title = Printer.bold("Build report"); + * // title: "\x1b[1mBuild report\x1b[0m" + * + * const symbol = Printer.bold("!"); + * // symbol: "\x1b[1m!\x1b[0m" + * + * const empty = Printer.bold(""); + * // empty: "\x1b[1m\x1b[0m" + * + * ``` + * + * @see https://utils.duplojs.dev/en/v1/api/common/printer/bold + * + */ + export function bold(input: string): string; + /** + * Applies a color and bold formatting to a string by combining `Printer.colorized()` and `Printer.bold()`. Exists in immediate or curried form. + * + * **Supported call styles:** + * - Classic: `Printer.colorizedBold(input, color)` -> returns the formatted string + * - Curried: `Printer.colorizedBold(color)` -> returns a function waiting for the string + * + * The produced string contains the bold ANSI code, then the colorized content, and finally the reset codes. + * + * ```ts + * const directResult = Printer.colorizedBold("Fatal", "red"); + * // directResult: "\x1b[1m\x1b[31mFatal\x1b[0m\x1b[0m" + * + * const pipedResult = pipe( + * "Info", + * Printer.colorizedBold("cyan"), + * ); + * // pipedResult: "\x1b[1m\x1b[36mInfo\x1b[0m\x1b[0m" + * + * const successResult = Printer.colorizedBold("Done", "green"); + * // successResult: "\x1b[1m\x1b[32mDone\x1b[0m\x1b[0m" + * + * ``` + * + * @see https://utils.duplojs.dev/en/v1/api/common/printer/colorizedBold + * + */ + export function colorizedBold(color: Colors): (input: GenericInput) => string; + export function colorizedBold(input: GenericInput, color: Colors): string; + export function indent(level: number): string; + export function stringify(value: unknown): string; + export type RenderInput = string | boolean | null | undefined | RenderInput[]; + /** + * Flattens printable values, keeps strings and `true`, then joins the result with a custom separator. Exists in immediate or curried form. + * + * **Supported call styles:** + * - Classic: `Printer.render(values, joinCharacter)` -> returns the rendered string + * - Curried: `Printer.render(joinCharacter)` -> returns a function waiting for the values array + * + * Nested arrays are flattened recursively. `false`, `null`, and `undefined` are ignored, while `true` is kept as the string `"true"`. + * The namespace also exposes two ready-to-use defaults: `Printer.renderLine`, which joins with a space, and `Printer.renderParagraph`, which joins with `Printer.back`. + * + * ```ts + * const customResult = Printer.render( + * ["alpha", ["beta", false], true, undefined], + * " | ", + * ); + * // customResult: "alpha | beta | true" + * + * const lineResult = Printer.renderLine([ + * "hello", + * ["world", null], + * true, + * ]); + * // lineResult: "hello world true" + * + * const paragraphResult = pipe( + * ["title", ["", "body"], false, true] as const, + * Printer.renderParagraph, + * ); + * // paragraphResult: "title\n\nbody\ntrue" + * + * ``` + * + * @see https://utils.duplojs.dev/en/v1/api/common/printer/render + * + */ + export function render(joinCharacter: string): (values: GenericValues) => string; + export function render(values: GenericValues, joinCharacter: string): string; + export const renderLine: (values: readonly RenderInput[]) => string; + export const renderParagraph: (values: readonly RenderInput[]) => string; + export {}; +} diff --git a/docs/public/libs/v1/common/printer.mjs b/docs/public/libs/v1/common/printer.mjs new file mode 100644 index 000000000..8a1a420da --- /dev/null +++ b/docs/public/libs/v1/common/printer.mjs @@ -0,0 +1,73 @@ +import { repeat } from '../string/repeat.mjs'; + +var Printer; +(function (Printer) { + const codeColors = { + red: "\x1b[31m", + green: "\x1b[32m", + yellow: "\x1b[33m", + blue: "\x1b[34m", + magenta: "\x1b[35m", + cyan: "\x1b[36m", + gray: "\x1b[90m", + }; + const codeBold = "\x1b[1m"; + const codeReset = "\x1b[0m"; + Printer.tab = "\t"; + Printer.back = "\n"; + Printer.dash = "-"; + function colorized(...args) { + if (args.length === 1) { + const [color] = args; + return (input) => colorized(input, color); + } + const [input, color] = args; + return `${codeColors[color]}${input}${codeReset}`; + } + Printer.colorized = colorized; + /** + * {@include common/printer/bold/index.md} + */ + function bold(input) { + return `${codeBold}${input}${codeReset}`; + } + Printer.bold = bold; + function colorizedBold(...args) { + if (args.length === 1) { + const [color] = args; + return (input) => colorizedBold(input, color); + } + const [input, color] = args; + return bold(colorized(input, color)); + } + Printer.colorizedBold = colorizedBold; + function indent(level) { + return repeat(Printer.tab, level); + } + Printer.indent = indent; + function stringify(value) { + try { + return JSON.stringify(value); + } + catch { + return String(value); + } + } + Printer.stringify = stringify; + function render(...args) { + if (args.length === 1) { + const [joinCharacter] = args; + return (values) => render(values, joinCharacter); + } + const [values, joinCharacter] = args; + return values + .flat(Infinity) + .filter((value) => typeof value === "string" || value === true) + .join(joinCharacter); + } + Printer.render = render; + Printer.renderLine = render(" "); + Printer.renderParagraph = render(Printer.back); +})(Printer || (Printer = {})); + +export { Printer }; diff --git a/docs/public/libs/v1/common/types/and.d.ts b/docs/public/libs/v1/common/types/and.d.ts index f4a10d519..1d4f83c5c 100644 --- a/docs/public/libs/v1/common/types/and.d.ts +++ b/docs/public/libs/v1/common/types/and.d.ts @@ -1,2 +1 @@ -import { type IsEqual } from "./isEqual"; -export type And = IsEqual; +export type And = GenericBooleans[number] extends true ? true : false; diff --git a/docs/public/libs/v1/common/types/or.d.ts b/docs/public/libs/v1/common/types/or.d.ts index fee465311..8da4c0e26 100644 --- a/docs/public/libs/v1/common/types/or.d.ts +++ b/docs/public/libs/v1/common/types/or.d.ts @@ -1,2 +1 @@ -import { type IsEqual } from "./isEqual"; -export type Or = IsEqual; +export type Or = GenericBooleans[number] extends false ? false : true; diff --git a/docs/public/libs/v1/dataParser/base.cjs b/docs/public/libs/v1/dataParser/base.cjs index 870d36f10..fa2de3cc3 100644 --- a/docs/public/libs/v1/dataParser/base.cjs +++ b/docs/public/libs/v1/dataParser/base.cjs @@ -11,8 +11,6 @@ var errorKindNamespace = require('../common/errorKindNamespace.cjs'); var error$1 = require('../either/left/error.cjs'); var success = require('../either/right/success.cjs'); -const SymbolDataParserErrorLabel = "SymbolDataParserError"; -const SymbolDataParserError = Symbol.for(SymbolDataParserErrorLabel); const checkerKind = kind.createDataParserKind("checker"); function dataParserCheckerInit(kind, params, exec) { return kind.setTo(checkerKind.setTo({ @@ -22,9 +20,7 @@ function dataParserCheckerInit(kind, params, exec) { } const dataParserKind = kind.createDataParserKind("base"); // This allows for better performance WTF ??? -const SDPEI = error.SymbolDataParserErrorIssue; -const SDPEPI = error.SymbolDataParserErrorPromiseIssue; -const SDPE = SymbolDataParserError; +const SDPE = error.SymbolDataParserError; const DPE = error.createError(); const EE = error$1.error(null); const ES = success.success(null); @@ -44,22 +40,13 @@ function dataParserInit(kind, definition, exec, specificOverrideHandler) { async: exec, isAsynchronous: () => false, }; - function middleExec(data, error$1) { - let result = formattedExec.sync(data, error$1, self); - if (result === SDPEI) { - error.addIssue(error$1, self, data); - return SDPE; - } - else if (result === SDPEPI) { - error.addPromiseIssue(error$1, self, data); - return SDPE; - } - else if (result !== SDPE + function middleExec(data, error) { + let result = formattedExec.sync(data, error, self); + if (result !== SDPE && self.definition.checkers.length) { for (const checker of self.definition.checkers) { - const checkerResult = checker.exec(result, checker); - if (checkerResult === SDPEI) { - error.addIssue(error$1, checker, result); + const checkerResult = checker.exec(result, error, checker); + if (checkerResult === SDPE) { return SDPE; } else { @@ -69,22 +56,13 @@ function dataParserInit(kind, definition, exec, specificOverrideHandler) { } return result; } - async function middleAsyncExec(data, error$1) { - let result = await formattedExec.async(data, error$1, self); - if (result === SDPEI) { - error.addIssue(error$1, self, data); - return SDPE; - } - else if (result === SDPEPI) { - error.addPromiseIssue(error$1, self, data); - return SDPE; - } - else if (result !== SDPE + async function middleAsyncExec(data, error) { + let result = await formattedExec.async(data, error, self); + if (result !== SDPE && self.definition.checkers.length) { for (const checker of self.definition.checkers) { - const checkerResult = checker.exec(result, checker); - if (checkerResult === SDPEI) { - error.addIssue(error$1, checker, result); + const checkerResult = checker.exec(result, error, checker); + if (checkerResult === SDPE) { return SDPE; } else { @@ -172,9 +150,8 @@ function dataParserInit(kind, definition, exec, specificOverrideHandler) { } dataParserInit.overrideHandler = override.createOverride("@duplojs/utils/data-parser/base"); +exports.SymbolDataParserError = error.SymbolDataParserError; exports.DataParserThrowError = DataParserThrowError; -exports.SymbolDataParserError = SymbolDataParserError; -exports.SymbolDataParserErrorLabel = SymbolDataParserErrorLabel; exports.checkerKind = checkerKind; exports.dataParserCheckerInit = dataParserCheckerInit; exports.dataParserInit = dataParserInit; diff --git a/docs/public/libs/v1/dataParser/base.d.ts b/docs/public/libs/v1/dataParser/base.d.ts index adb655610..a5ce5889c 100644 --- a/docs/public/libs/v1/dataParser/base.d.ts +++ b/docs/public/libs/v1/dataParser/base.d.ts @@ -1,19 +1,17 @@ import { type GetKind, type GetKindHandler, type GetKindValue, type IsEqual, type Kind, type KindHandler, type OverrideHandler, type RemoveKind } from "../common"; -import { SymbolDataParserErrorIssue, SymbolDataParserErrorPromiseIssue, type DataParserError } from "./error"; +import { SymbolDataParserError, type DataParserError } from "./error"; import * as DEither from "../either"; -export declare const SymbolDataParserErrorLabel = "SymbolDataParserError"; -export declare const SymbolDataParserError: unique symbol; -export type SymbolDataParserError = typeof SymbolDataParserError; +export { SymbolDataParserError } from "./error"; export declare const checkerKind: KindHandler>; export interface DataParserCheckerDefinition { readonly errorMessage?: string; } export interface DataParserChecker extends Kind { readonly definition: GenericDefinition; - exec(data: GenericInput, self: this): GenericInput | SymbolDataParserErrorIssue; + exec(data: GenericInput, error: DataParserError, self: this): GenericInput | SymbolDataParserError; } export type InputChecker = Parameters[0]; -export declare function dataParserCheckerInit(kind: Exclude, typeof checkerKind>, params: NoInfer, "exec">>, exec: (...args: Parameters) => GetKindValue | SymbolDataParserErrorIssue): GenericDataParserChecker; +export declare function dataParserCheckerInit(kind: Exclude, typeof checkerKind>, params: NoInfer, "exec">>, exec: (...args: Parameters) => GetKindValue | SymbolDataParserError): GenericDataParserChecker; export declare const dataParserKind: KindHandler { - sync(...args: [...Parameters, self: GenericDataParser]): (GetKindValue["output"] | SymbolDataParserError | SymbolDataParserErrorIssue | SymbolDataParserErrorPromiseIssue); - async(...args: [...Parameters, self: GenericDataParser]): Promise["output"] | SymbolDataParserError | SymbolDataParserErrorIssue | SymbolDataParserErrorPromiseIssue>; + sync(...args: [...Parameters, self: GenericDataParser]): (GetKindValue["output"] | SymbolDataParserError); + async(...args: [...Parameters, self: GenericDataParser]): Promise["output"] | SymbolDataParserError>; isAsynchronous(self: GenericDataParser): boolean; } declare const DataParserThrowError_base: new (params: { @@ -261,4 +259,3 @@ export type AdvancedContract = (GetKind; clone(): AdvancedContract; }); -export {}; diff --git a/docs/public/libs/v1/dataParser/base.mjs b/docs/public/libs/v1/dataParser/base.mjs index e74c7a029..8f56f5aa9 100644 --- a/docs/public/libs/v1/dataParser/base.mjs +++ b/docs/public/libs/v1/dataParser/base.mjs @@ -1,4 +1,4 @@ -import { createError, addIssue, addPromiseIssue, SymbolDataParserErrorIssue, SymbolDataParserErrorPromiseIssue } from './error.mjs'; +import { createError, SymbolDataParserError } from './error.mjs'; import { createDataParserKind } from './kind.mjs'; import { simpleClone } from '../common/simpleClone.mjs'; import { keyWrappedValue } from '../common/wrapValue.mjs'; @@ -9,8 +9,6 @@ import { createErrorKind } from '../common/errorKindNamespace.mjs'; import { error } from '../either/left/error.mjs'; import { success } from '../either/right/success.mjs'; -const SymbolDataParserErrorLabel = "SymbolDataParserError"; -const SymbolDataParserError = Symbol.for(SymbolDataParserErrorLabel); const checkerKind = createDataParserKind("checker"); function dataParserCheckerInit(kind, params, exec) { return kind.setTo(checkerKind.setTo({ @@ -20,8 +18,6 @@ function dataParserCheckerInit(kind, params, exec) { } const dataParserKind = createDataParserKind("base"); // This allows for better performance WTF ??? -const SDPEI = SymbolDataParserErrorIssue; -const SDPEPI = SymbolDataParserErrorPromiseIssue; const SDPE = SymbolDataParserError; const DPE = createError(); const EE = error(null); @@ -44,20 +40,11 @@ function dataParserInit(kind, definition, exec, specificOverrideHandler) { }; function middleExec(data, error) { let result = formattedExec.sync(data, error, self); - if (result === SDPEI) { - addIssue(error, self, data); - return SDPE; - } - else if (result === SDPEPI) { - addPromiseIssue(error, self, data); - return SDPE; - } - else if (result !== SDPE + if (result !== SDPE && self.definition.checkers.length) { for (const checker of self.definition.checkers) { - const checkerResult = checker.exec(result, checker); - if (checkerResult === SDPEI) { - addIssue(error, checker, result); + const checkerResult = checker.exec(result, error, checker); + if (checkerResult === SDPE) { return SDPE; } else { @@ -69,20 +56,11 @@ function dataParserInit(kind, definition, exec, specificOverrideHandler) { } async function middleAsyncExec(data, error) { let result = await formattedExec.async(data, error, self); - if (result === SDPEI) { - addIssue(error, self, data); - return SDPE; - } - else if (result === SDPEPI) { - addPromiseIssue(error, self, data); - return SDPE; - } - else if (result !== SDPE + if (result !== SDPE && self.definition.checkers.length) { for (const checker of self.definition.checkers) { - const checkerResult = checker.exec(result, checker); - if (checkerResult === SDPEI) { - addIssue(error, checker, result); + const checkerResult = checker.exec(result, error, checker); + if (checkerResult === SDPE) { return SDPE; } else { @@ -170,4 +148,4 @@ function dataParserInit(kind, definition, exec, specificOverrideHandler) { } dataParserInit.overrideHandler = createOverride("@duplojs/utils/data-parser/base"); -export { DataParserThrowError, SymbolDataParserError, SymbolDataParserErrorLabel, checkerKind, dataParserCheckerInit, dataParserInit, dataParserKind }; +export { DataParserThrowError, SymbolDataParserError, checkerKind, dataParserCheckerInit, dataParserInit, dataParserKind }; diff --git a/docs/public/libs/v1/dataParser/error.cjs b/docs/public/libs/v1/dataParser/error.cjs index 7ff7562ad..4649944c1 100644 --- a/docs/public/libs/v1/dataParser/error.cjs +++ b/docs/public/libs/v1/dataParser/error.cjs @@ -1,13 +1,20 @@ 'use strict'; var kind = require('./kind.cjs'); +var printer = require('../common/printer.cjs'); +var unwrap = require('../common/unwrap.cjs'); -const SymbolDataParserErrorIssueLabel = "SymbolDataParserErrorIssue"; +const SymbolDataParserErrorLabel = "SymbolDataParserError"; +const SymbolDataParserError = Symbol.for(SymbolDataParserErrorLabel); +/** + * @deprecated + */ +const SymbolDataParserErrorIssueLabel = "SymbolDataParserError"; +/** + * @deprecated + */ const SymbolDataParserErrorIssue = Symbol.for(SymbolDataParserErrorIssueLabel); const errorIssueKind = kind.createDataParserKind("error-issue"); -const SymbolDataParserErrorPromiseIssueLabel = "SymbolDataParserErrorPromiseIssue"; -const SymbolDataParserErrorPromiseIssue = Symbol.for(SymbolDataParserErrorPromiseIssueLabel); -const errorPromiseIssueKind = kind.createDataParserKind("error-issue-promise"); const errorKind = kind.createDataParserKind("error"); function createError() { return errorKind.setTo({ @@ -15,23 +22,14 @@ function createError() { currentPath: [], }); } -function addIssue(error, source, data, moreInformation) { +function addIssue(error, expected, data, message) { error.issues.push(errorIssueKind.setTo({ - source, + expected, path: error.currentPath.join("."), data, - moreInformation, + message, })); - return error; -} -function addPromiseIssue(error, source, data, moreInformation) { - error.issues.push(errorPromiseIssueKind.setTo({ - source, - path: error.currentPath.join("."), - data, - moreInformation, - })); - return error; + return SymbolDataParserError; } function setErrorPath(error, value, index) { error.currentPath[index] = value; @@ -41,16 +39,36 @@ function popErrorPath(error) { error.currentPath.pop(); return error; } +function interpretError(error) { + const dataParserError = errorKind.has(error) + ? error + : unwrap.unwrap(error); + return printer.Printer.renderParagraph([ + printer.Printer.colorizedBold("Validation failed", "red"), + dataParserError.issues.map((issue) => printer.Printer.renderParagraph([ + "", + printer.Printer.renderLine([ + printer.Printer.colorizedBold("✖", "red"), + printer.Printer.colorizedBold(issue.path || "", "cyan"), + "expected", + printer.Printer.colorized(issue.expected, "green"), + "but received", + printer.Printer.colorized(printer.Printer.stringify(issue.data), "red"), + ]), + issue.message !== undefined && `${printer.Printer.indent(1)}↳ ${issue.message}`, + ])), + dataParserError.issues.length === 0 && "No issue found", + ]); +} +exports.SymbolDataParserError = SymbolDataParserError; exports.SymbolDataParserErrorIssue = SymbolDataParserErrorIssue; exports.SymbolDataParserErrorIssueLabel = SymbolDataParserErrorIssueLabel; -exports.SymbolDataParserErrorPromiseIssue = SymbolDataParserErrorPromiseIssue; -exports.SymbolDataParserErrorPromiseIssueLabel = SymbolDataParserErrorPromiseIssueLabel; +exports.SymbolDataParserErrorLabel = SymbolDataParserErrorLabel; exports.addIssue = addIssue; -exports.addPromiseIssue = addPromiseIssue; exports.createError = createError; exports.errorIssueKind = errorIssueKind; exports.errorKind = errorKind; -exports.errorPromiseIssueKind = errorPromiseIssueKind; +exports.interpretError = interpretError; exports.popErrorPath = popErrorPath; exports.setErrorPath = setErrorPath; diff --git a/docs/public/libs/v1/dataParser/error.d.ts b/docs/public/libs/v1/dataParser/error.d.ts index 1c964526e..560009e6c 100644 --- a/docs/public/libs/v1/dataParser/error.d.ts +++ b/docs/public/libs/v1/dataParser/error.d.ts @@ -1,34 +1,34 @@ import { type Kind } from "../common"; -import { type DataParserTransform } from "./parsers"; -import { type DataParser } from "./base"; -import { type DataParserCheckers } from "./types"; -export declare const SymbolDataParserErrorIssueLabel = "SymbolDataParserErrorIssue"; +import type * as DEither from "../either"; +export declare const SymbolDataParserErrorLabel = "SymbolDataParserError"; +export declare const SymbolDataParserError: unique symbol; +export type SymbolDataParserError = typeof SymbolDataParserError; +/** + * @deprecated + */ +export declare const SymbolDataParserErrorIssueLabel = "SymbolDataParserError"; +/** + * @deprecated + */ export declare const SymbolDataParserErrorIssue: unique symbol; +/** + * @deprecated + */ export type SymbolDataParserErrorIssue = typeof SymbolDataParserErrorIssue; export declare const errorIssueKind: import("../common").KindHandler>; export interface DataParserErrorIssue extends Kind { - readonly source: DataParser | DataParserCheckers; + readonly expected: string; readonly path: string; readonly data: unknown; - readonly moreInformation?: string; -} -export declare const SymbolDataParserErrorPromiseIssueLabel = "SymbolDataParserErrorPromiseIssue"; -export declare const SymbolDataParserErrorPromiseIssue: unique symbol; -export type SymbolDataParserErrorPromiseIssue = typeof SymbolDataParserErrorPromiseIssue; -export declare const errorPromiseIssueKind: import("../common").KindHandler>; -export interface DataParserErrorPromiseIssue extends Kind { - readonly source: DataParserTransform; - readonly path: string; - readonly data: unknown; - readonly moreInformation?: string; + readonly message: string | undefined; } export declare const errorKind: import("../common").KindHandler>; export interface DataParserError extends Kind { - readonly issues: (DataParserErrorIssue | DataParserErrorPromiseIssue)[]; + readonly issues: DataParserErrorIssue[]; readonly currentPath: string[]; } export declare function createError(): DataParserError; -export declare function addIssue(error: DataParserError, source: DataParser | DataParserCheckers, data: unknown, moreInformation?: string): DataParserError; -export declare function addPromiseIssue(error: DataParserError, source: DataParserTransform, data: unknown, moreInformation?: string): DataParserError; +export declare function addIssue(error: DataParserError, expected: string, data: unknown, message: string | undefined): SymbolDataParserError; export declare function setErrorPath(error: DataParserError, value: string, index: number): DataParserError; export declare function popErrorPath(error: DataParserError): DataParserError; +export declare function interpretError(error: DataParserError | DEither.Left): string; diff --git a/docs/public/libs/v1/dataParser/error.mjs b/docs/public/libs/v1/dataParser/error.mjs index bc002a79c..f771fc762 100644 --- a/docs/public/libs/v1/dataParser/error.mjs +++ b/docs/public/libs/v1/dataParser/error.mjs @@ -1,11 +1,18 @@ import { createDataParserKind } from './kind.mjs'; +import { Printer } from '../common/printer.mjs'; +import { unwrap } from '../common/unwrap.mjs'; -const SymbolDataParserErrorIssueLabel = "SymbolDataParserErrorIssue"; +const SymbolDataParserErrorLabel = "SymbolDataParserError"; +const SymbolDataParserError = Symbol.for(SymbolDataParserErrorLabel); +/** + * @deprecated + */ +const SymbolDataParserErrorIssueLabel = "SymbolDataParserError"; +/** + * @deprecated + */ const SymbolDataParserErrorIssue = Symbol.for(SymbolDataParserErrorIssueLabel); const errorIssueKind = createDataParserKind("error-issue"); -const SymbolDataParserErrorPromiseIssueLabel = "SymbolDataParserErrorPromiseIssue"; -const SymbolDataParserErrorPromiseIssue = Symbol.for(SymbolDataParserErrorPromiseIssueLabel); -const errorPromiseIssueKind = createDataParserKind("error-issue-promise"); const errorKind = createDataParserKind("error"); function createError() { return errorKind.setTo({ @@ -13,23 +20,14 @@ function createError() { currentPath: [], }); } -function addIssue(error, source, data, moreInformation) { +function addIssue(error, expected, data, message) { error.issues.push(errorIssueKind.setTo({ - source, + expected, path: error.currentPath.join("."), data, - moreInformation, + message, })); - return error; -} -function addPromiseIssue(error, source, data, moreInformation) { - error.issues.push(errorPromiseIssueKind.setTo({ - source, - path: error.currentPath.join("."), - data, - moreInformation, - })); - return error; + return SymbolDataParserError; } function setErrorPath(error, value, index) { error.currentPath[index] = value; @@ -39,5 +37,26 @@ function popErrorPath(error) { error.currentPath.pop(); return error; } +function interpretError(error) { + const dataParserError = errorKind.has(error) + ? error + : unwrap(error); + return Printer.renderParagraph([ + Printer.colorizedBold("Validation failed", "red"), + dataParserError.issues.map((issue) => Printer.renderParagraph([ + "", + Printer.renderLine([ + Printer.colorizedBold("✖", "red"), + Printer.colorizedBold(issue.path || "", "cyan"), + "expected", + Printer.colorized(issue.expected, "green"), + "but received", + Printer.colorized(Printer.stringify(issue.data), "red"), + ]), + issue.message !== undefined && `${Printer.indent(1)}↳ ${issue.message}`, + ])), + dataParserError.issues.length === 0 && "No issue found", + ]); +} -export { SymbolDataParserErrorIssue, SymbolDataParserErrorIssueLabel, SymbolDataParserErrorPromiseIssue, SymbolDataParserErrorPromiseIssueLabel, addIssue, addPromiseIssue, createError, errorIssueKind, errorKind, errorPromiseIssueKind, popErrorPath, setErrorPath }; +export { SymbolDataParserError, SymbolDataParserErrorIssue, SymbolDataParserErrorIssueLabel, SymbolDataParserErrorLabel, addIssue, createError, errorIssueKind, errorKind, interpretError, popErrorPath, setErrorPath }; diff --git a/docs/public/libs/v1/dataParser/extended/index.cjs b/docs/public/libs/v1/dataParser/extended/index.cjs index 37fd53ca8..0cba8786d 100644 --- a/docs/public/libs/v1/dataParser/extended/index.cjs +++ b/docs/public/libs/v1/dataParser/extended/index.cjs @@ -53,15 +53,14 @@ exports.templateLiteral = templateLiteral.templateLiteral; exports.tuple = tuple.tuple; exports.unknown = unknown.unknown; exports.recover = recover.recover; +exports.SymbolDataParserError = error.SymbolDataParserError; exports.SymbolDataParserErrorIssue = error.SymbolDataParserErrorIssue; exports.SymbolDataParserErrorIssueLabel = error.SymbolDataParserErrorIssueLabel; -exports.SymbolDataParserErrorPromiseIssue = error.SymbolDataParserErrorPromiseIssue; -exports.SymbolDataParserErrorPromiseIssueLabel = error.SymbolDataParserErrorPromiseIssueLabel; +exports.SymbolDataParserErrorLabel = error.SymbolDataParserErrorLabel; exports.addIssue = error.addIssue; -exports.addPromiseIssue = error.addPromiseIssue; exports.createError = error.createError; exports.errorIssueKind = error.errorIssueKind; exports.errorKind = error.errorKind; -exports.errorPromiseIssueKind = error.errorPromiseIssueKind; +exports.interpretError = error.interpretError; exports.popErrorPath = error.popErrorPath; exports.setErrorPath = error.setErrorPath; diff --git a/docs/public/libs/v1/dataParser/extended/index.mjs b/docs/public/libs/v1/dataParser/extended/index.mjs index 4bb79e15d..e84f29d9b 100644 --- a/docs/public/libs/v1/dataParser/extended/index.mjs +++ b/docs/public/libs/v1/dataParser/extended/index.mjs @@ -22,4 +22,4 @@ export { templateLiteral } from './templateLiteral.mjs'; export { tuple } from './tuple.mjs'; export { unknown } from './unknown.mjs'; export { recover } from './recover.mjs'; -export { SymbolDataParserErrorIssue, SymbolDataParserErrorIssueLabel, SymbolDataParserErrorPromiseIssue, SymbolDataParserErrorPromiseIssueLabel, addIssue, addPromiseIssue, createError, errorIssueKind, errorKind, errorPromiseIssueKind, popErrorPath, setErrorPath } from '../error.mjs'; +export { SymbolDataParserError, SymbolDataParserErrorIssue, SymbolDataParserErrorIssueLabel, SymbolDataParserErrorLabel, addIssue, createError, errorIssueKind, errorKind, interpretError, popErrorPath, setErrorPath } from '../error.mjs'; diff --git a/docs/public/libs/v1/dataParser/identifier.d.ts b/docs/public/libs/v1/dataParser/identifier.d.ts index 47a0baf42..fd612d298 100644 --- a/docs/public/libs/v1/dataParser/identifier.d.ts +++ b/docs/public/libs/v1/dataParser/identifier.d.ts @@ -8,13 +8,13 @@ import { type DataParser } from "./base"; * parsers, the correct type can be retrieved. */ export declare const identifier: { - > | import("../common").KindHandler> | import("../common").KindHandler> | import("../common").KindHandler> | import("../common").KindHandler> | import("../common").KindHandler> | import("../common").KindHandler> | import("../common").KindHandler> | import("../common").KindHandler> | import("../common").KindHandler> | import("../common").KindHandler> | import("../common").KindHandler> | import("../common").KindHandler> | import("../common").KindHandler> | import("../common").KindHandler> | import("../common").KindHandler> | import("../common").KindHandler> | import("../common").KindHandler> | import("../common").KindHandler> | import("../common").KindHandler> | import("../common").KindHandler> | import("../common").KindHandler> | import("../common").KindHandler> | import("../common").KindHandler> | import("../common").KindHandler> | import("../common").KindHandler> | import("../common").KindHandler> | import("../common").KindHandler> | import("../common").KindHandler> | import("../common").KindHandler> | import("../common").KindHandler> | import("../common").KindHandler> | import("../common").KindHandler> | import("../common").KindHandler> | import("../common").KindHandler> | import("../common").KindHandler> | import("../common").KindHandler> | import("../common").KindHandler> | import("../common").KindHandler> | import("../common").KindHandler> | import("../common").KindHandler> | import("../common").KindHandler> | import("../common").KindHandler> | import("../common").KindHandler> | import("../common").KindHandler> | import("../common").KindHandler> | import("../common").KindHandler> | import("../common").KindHandler> | import("../common").KindHandler> | import("../common").KindHandler> | import("../common").KindHandler; output: Record; }>>, GenericInput extends unknown, GenericGroupedKind extends import("../common").UnionToIntersection> ? import("../common").Kind : never>>(kind: GenericKindHandler | GenericKindHandler[]): (input: GenericInput) => input is (import("../common").IsEqual>, unknown, unknown>> : never), boolean>, true> extends true ? Extract>, unknown, unknown>, GenericGroupedKind> | Extract, GenericGroupedKind> | Extract, GenericGroupedKind> | Extract, GenericGroupedKind> | Extract, GenericGroupedKind> | Extract, GenericGroupedKind> | Extract, GenericGroupedKind> | Extract, GenericGroupedKind> | Extract, GenericGroupedKind> | Extract, GenericGroupedKind> | Extract, GenericGroupedKind> | Extract, GenericGroupedKind> | Extract, GenericGroupedKind> | Extract, GenericGroupedKind> | Extract, GenericGroupedKind> | Extract, GenericGroupedKind> | Extract, GenericGroupedKind> | Extract>, GenericGroupedKind> | Extract>, GenericGroupedKind> | Extract, GenericGroupedKind> | Extract, GenericGroupedKind> | Extract, GenericGroupedKind> | Extract, GenericGroupedKind> | Extract>, unknown, unknown>, GenericGroupedKind> | Extract, GenericGroupedKind> | Extract, GenericGroupedKind> | Extract, GenericGroupedKind> | Extract, GenericGroupedKind> | Extract, GenericGroupedKind> | Extract, GenericGroupedKind> | Extract, GenericGroupedKind> | Extract, GenericGroupedKind> | Extract, GenericGroupedKind> | Extract, GenericGroupedKind> | Extract, GenericGroupedKind> | Extract, GenericGroupedKind> | Extract, GenericGroupedKind> | Extract, GenericGroupedKind> | Extract, GenericGroupedKind> | Extract, GenericGroupedKind> | Extract>, GenericGroupedKind> | Extract>, GenericGroupedKind> | Extract, GenericGroupedKind> | Extract, GenericGroupedKind> | Extract, GenericGroupedKind> | Extract, GenericGroupedKind> : never) | Extract; - > | import("../common").KindHandler> | import("../common").KindHandler> | import("../common").KindHandler> | import("../common").KindHandler> | import("../common").KindHandler> | import("../common").KindHandler> | import("../common").KindHandler> | import("../common").KindHandler> | import("../common").KindHandler> | import("../common").KindHandler> | import("../common").KindHandler> | import("../common").KindHandler> | import("../common").KindHandler> | import("../common").KindHandler> | import("../common").KindHandler> | import("../common").KindHandler> | import("../common").KindHandler> | import("../common").KindHandler> | import("../common").KindHandler> | import("../common").KindHandler> | import("../common").KindHandler> | import("../common").KindHandler> | import("../common").KindHandler> | import("../common").KindHandler> | import("../common").KindHandler> | import("../common").KindHandler> | import("../common").KindHandler> | import("../common").KindHandler> | import("../common").KindHandler> | import("../common").KindHandler> | import("../common").KindHandler> | import("../common").KindHandler> | import("../common").KindHandler> | import("../common").KindHandler> | import("../common").KindHandler> | import("../common").KindHandler> | import("../common").KindHandler> | import("../common").KindHandler> | import("../common").KindHandler> | import("../common").KindHandler> | import("../common").KindHandler> | import("../common").KindHandler> | import("../common").KindHandler> | import("../common").KindHandler> | import("../common").KindHandler> | import("../common").KindHandler> | import("../common").KindHandler> | import("../common").KindHandler> | import("../common").KindHandler> | import("../common").KindHandler { - if (data.length > self.definition.max) { - return error.SymbolDataParserErrorIssue; - } - return data; - }); + }, (data, error$1, self) => data.length <= self.definition.max + ? data + : error.addIssue(error$1, `array.length <= ${self.definition.max}`, data, self.definition.errorMessage)); } exports.checkerArrayMax = checkerArrayMax; diff --git a/docs/public/libs/v1/dataParser/parsers/array/checkers/max.mjs b/docs/public/libs/v1/dataParser/parsers/array/checkers/max.mjs index c218f2be4..3957498af 100644 --- a/docs/public/libs/v1/dataParser/parsers/array/checkers/max.mjs +++ b/docs/public/libs/v1/dataParser/parsers/array/checkers/max.mjs @@ -1,5 +1,5 @@ import { dataParserCheckerInit } from '../../../base.mjs'; -import { SymbolDataParserErrorIssue } from '../../../error.mjs'; +import { addIssue } from '../../../error.mjs'; import { createDataParserKind } from '../../../kind.mjs'; const checkerArrayMaxKind = createDataParserKind("checker-array-max"); @@ -9,12 +9,9 @@ function checkerArrayMax(max, definition = {}) { ...definition, max, }, - }, (data, self) => { - if (data.length > self.definition.max) { - return SymbolDataParserErrorIssue; - } - return data; - }); + }, (data, error, self) => data.length <= self.definition.max + ? data + : addIssue(error, `array.length <= ${self.definition.max}`, data, self.definition.errorMessage)); } export { checkerArrayMax, checkerArrayMaxKind }; diff --git a/docs/public/libs/v1/dataParser/parsers/array/checkers/min.cjs b/docs/public/libs/v1/dataParser/parsers/array/checkers/min.cjs index 57d9094e4..be0b35bd8 100644 --- a/docs/public/libs/v1/dataParser/parsers/array/checkers/min.cjs +++ b/docs/public/libs/v1/dataParser/parsers/array/checkers/min.cjs @@ -11,12 +11,9 @@ function checkerArrayMin(min, definition = {}) { ...definition, min, }, - }, (data, self) => { - if (data.length < self.definition.min) { - return error.SymbolDataParserErrorIssue; - } - return data; - }); + }, (data, error$1, self) => data.length >= self.definition.min + ? data + : error.addIssue(error$1, `array.length >= ${self.definition.min}`, data, self.definition.errorMessage)); } exports.checkerArrayMin = checkerArrayMin; diff --git a/docs/public/libs/v1/dataParser/parsers/array/checkers/min.mjs b/docs/public/libs/v1/dataParser/parsers/array/checkers/min.mjs index 9444f4b83..fa75795e1 100644 --- a/docs/public/libs/v1/dataParser/parsers/array/checkers/min.mjs +++ b/docs/public/libs/v1/dataParser/parsers/array/checkers/min.mjs @@ -1,5 +1,5 @@ import { dataParserCheckerInit } from '../../../base.mjs'; -import { SymbolDataParserErrorIssue } from '../../../error.mjs'; +import { addIssue } from '../../../error.mjs'; import { createDataParserKind } from '../../../kind.mjs'; const checkerArrayMinKind = createDataParserKind("checker-array-min"); @@ -9,12 +9,9 @@ function checkerArrayMin(min, definition = {}) { ...definition, min, }, - }, (data, self) => { - if (data.length < self.definition.min) { - return SymbolDataParserErrorIssue; - } - return data; - }); + }, (data, error, self) => data.length >= self.definition.min + ? data + : addIssue(error, `array.length >= ${self.definition.min}`, data, self.definition.errorMessage)); } export { checkerArrayMin, checkerArrayMinKind }; diff --git a/docs/public/libs/v1/dataParser/parsers/array/index.cjs b/docs/public/libs/v1/dataParser/parsers/array/index.cjs index 94a5b8cfa..27143a67f 100644 --- a/docs/public/libs/v1/dataParser/parsers/array/index.cjs +++ b/docs/public/libs/v1/dataParser/parsers/array/index.cjs @@ -17,7 +17,7 @@ function array(element, definition) { }, { sync: (data, error$1, self) => { if (!(data instanceof Array)) { - return error.SymbolDataParserErrorIssue; + return error.addIssue(error$1, "array", data, self.definition.errorMessage); } let output = []; const currentIndexPath = error$1.currentPath.length; @@ -27,10 +27,10 @@ function array(element, definition) { .definition .element .exec(data[index], error$1); - if (result === base.SymbolDataParserError) { - output = base.SymbolDataParserError; + if (result === error.SymbolDataParserError) { + output = error.SymbolDataParserError; } - else if (output !== base.SymbolDataParserError) { + else if (output !== error.SymbolDataParserError) { output.push(result); } } @@ -39,7 +39,7 @@ function array(element, definition) { }, async: async (data, error$1, self) => { if (!(data instanceof Array)) { - return error.SymbolDataParserErrorIssue; + return error.addIssue(error$1, "array", data, self.definition.errorMessage); } let output = []; const currentIndexPath = error$1.currentPath.length; @@ -49,10 +49,10 @@ function array(element, definition) { .definition .element .asyncExec(data[index], error$1); - if (result === base.SymbolDataParserError) { - output = base.SymbolDataParserError; + if (result === error.SymbolDataParserError) { + output = error.SymbolDataParserError; } - else if (output !== base.SymbolDataParserError) { + else if (output !== error.SymbolDataParserError) { output.push(result); } } diff --git a/docs/public/libs/v1/dataParser/parsers/array/index.mjs b/docs/public/libs/v1/dataParser/parsers/array/index.mjs index e4b310b71..b01c753fe 100644 --- a/docs/public/libs/v1/dataParser/parsers/array/index.mjs +++ b/docs/public/libs/v1/dataParser/parsers/array/index.mjs @@ -1,5 +1,5 @@ -import { dataParserInit, SymbolDataParserError } from '../../base.mjs'; -import { SymbolDataParserErrorIssue, setErrorPath, popErrorPath } from '../../error.mjs'; +import { dataParserInit } from '../../base.mjs'; +import { addIssue, setErrorPath, SymbolDataParserError, popErrorPath } from '../../error.mjs'; import { createDataParserKind } from '../../kind.mjs'; import { createOverride } from '../../../common/override.mjs'; @@ -15,7 +15,7 @@ function array(element, definition) { }, { sync: (data, error, self) => { if (!(data instanceof Array)) { - return SymbolDataParserErrorIssue; + return addIssue(error, "array", data, self.definition.errorMessage); } let output = []; const currentIndexPath = error.currentPath.length; @@ -37,7 +37,7 @@ function array(element, definition) { }, async: async (data, error, self) => { if (!(data instanceof Array)) { - return SymbolDataParserErrorIssue; + return addIssue(error, "array", data, self.definition.errorMessage); } let output = []; const currentIndexPath = error.currentPath.length; diff --git a/docs/public/libs/v1/dataParser/parsers/bigint/checkers/max.cjs b/docs/public/libs/v1/dataParser/parsers/bigint/checkers/max.cjs index 2a4bb573f..24d06fc6d 100644 --- a/docs/public/libs/v1/dataParser/parsers/bigint/checkers/max.cjs +++ b/docs/public/libs/v1/dataParser/parsers/bigint/checkers/max.cjs @@ -11,9 +11,9 @@ function checkerBigIntMax(max, definition = {}) { ...definition, max, }, - }, (value, self) => { + }, (value, error$1, self) => { if (value > self.definition.max) { - return error.SymbolDataParserErrorIssue; + return error.addIssue(error$1, `bigint <= ${self.definition.max}n`, value, self.definition.errorMessage); } return value; }); diff --git a/docs/public/libs/v1/dataParser/parsers/bigint/checkers/max.mjs b/docs/public/libs/v1/dataParser/parsers/bigint/checkers/max.mjs index 1cc70e260..5cadd5a4d 100644 --- a/docs/public/libs/v1/dataParser/parsers/bigint/checkers/max.mjs +++ b/docs/public/libs/v1/dataParser/parsers/bigint/checkers/max.mjs @@ -1,5 +1,5 @@ import { dataParserCheckerInit } from '../../../base.mjs'; -import { SymbolDataParserErrorIssue } from '../../../error.mjs'; +import { addIssue } from '../../../error.mjs'; import { createDataParserKind } from '../../../kind.mjs'; const checkerBigIntMaxKind = createDataParserKind("checker-bigint-max"); @@ -9,9 +9,9 @@ function checkerBigIntMax(max, definition = {}) { ...definition, max, }, - }, (value, self) => { + }, (value, error, self) => { if (value > self.definition.max) { - return SymbolDataParserErrorIssue; + return addIssue(error, `bigint <= ${self.definition.max}n`, value, self.definition.errorMessage); } return value; }); diff --git a/docs/public/libs/v1/dataParser/parsers/bigint/checkers/min.cjs b/docs/public/libs/v1/dataParser/parsers/bigint/checkers/min.cjs index 22333523b..f27213b5d 100644 --- a/docs/public/libs/v1/dataParser/parsers/bigint/checkers/min.cjs +++ b/docs/public/libs/v1/dataParser/parsers/bigint/checkers/min.cjs @@ -11,9 +11,9 @@ function checkerBigIntMin(min, definition = {}) { ...definition, min, }, - }, (value, self) => { + }, (value, error$1, self) => { if (value < self.definition.min) { - return error.SymbolDataParserErrorIssue; + return error.addIssue(error$1, `bigint >= ${self.definition.min}n`, value, self.definition.errorMessage); } return value; }); diff --git a/docs/public/libs/v1/dataParser/parsers/bigint/checkers/min.mjs b/docs/public/libs/v1/dataParser/parsers/bigint/checkers/min.mjs index d032dc39e..51b816d89 100644 --- a/docs/public/libs/v1/dataParser/parsers/bigint/checkers/min.mjs +++ b/docs/public/libs/v1/dataParser/parsers/bigint/checkers/min.mjs @@ -1,5 +1,5 @@ import { dataParserCheckerInit } from '../../../base.mjs'; -import { SymbolDataParserErrorIssue } from '../../../error.mjs'; +import { addIssue } from '../../../error.mjs'; import { createDataParserKind } from '../../../kind.mjs'; const checkerBigIntMinKind = createDataParserKind("checker-bigint-min"); @@ -9,9 +9,9 @@ function checkerBigIntMin(min, definition = {}) { ...definition, min, }, - }, (value, self) => { + }, (value, error, self) => { if (value < self.definition.min) { - return SymbolDataParserErrorIssue; + return addIssue(error, `bigint >= ${self.definition.min}n`, value, self.definition.errorMessage); } return value; }); diff --git a/docs/public/libs/v1/dataParser/parsers/bigint/index.cjs b/docs/public/libs/v1/dataParser/parsers/bigint/index.cjs index eb0a2c2f6..14f4a3011 100644 --- a/docs/public/libs/v1/dataParser/parsers/bigint/index.cjs +++ b/docs/public/libs/v1/dataParser/parsers/bigint/index.cjs @@ -14,7 +14,7 @@ function bigint(definition) { errorMessage: definition?.errorMessage, checkers: definition?.checkers ?? [], coerce: definition?.coerce ?? false, - }, (data, _error, self) => { + }, (data, error$1, self) => { if (self.definition.coerce) { try { // eslint-disable-next-line no-param-reassign @@ -25,7 +25,7 @@ function bigint(definition) { if (typeof data === "bigint") { return data; } - return error.SymbolDataParserErrorIssue; + return error.addIssue(error$1, "bigint", data, self.definition.errorMessage); }, bigint.overrideHandler); return self; } diff --git a/docs/public/libs/v1/dataParser/parsers/bigint/index.mjs b/docs/public/libs/v1/dataParser/parsers/bigint/index.mjs index d9afda97c..f8c4d2875 100644 --- a/docs/public/libs/v1/dataParser/parsers/bigint/index.mjs +++ b/docs/public/libs/v1/dataParser/parsers/bigint/index.mjs @@ -1,5 +1,5 @@ import { dataParserInit } from '../../base.mjs'; -import { SymbolDataParserErrorIssue } from '../../error.mjs'; +import { addIssue } from '../../error.mjs'; import { createDataParserKind } from '../../kind.mjs'; import { createOverride } from '../../../common/override.mjs'; @@ -12,7 +12,7 @@ function bigint(definition) { errorMessage: definition?.errorMessage, checkers: definition?.checkers ?? [], coerce: definition?.coerce ?? false, - }, (data, _error, self) => { + }, (data, error, self) => { if (self.definition.coerce) { try { // eslint-disable-next-line no-param-reassign @@ -23,7 +23,7 @@ function bigint(definition) { if (typeof data === "bigint") { return data; } - return SymbolDataParserErrorIssue; + return addIssue(error, "bigint", data, self.definition.errorMessage); }, bigint.overrideHandler); return self; } diff --git a/docs/public/libs/v1/dataParser/parsers/boolean.cjs b/docs/public/libs/v1/dataParser/parsers/boolean.cjs index 3407861c2..d60d82f9a 100644 --- a/docs/public/libs/v1/dataParser/parsers/boolean.cjs +++ b/docs/public/libs/v1/dataParser/parsers/boolean.cjs @@ -14,7 +14,7 @@ function boolean(definition) { errorMessage: definition?.errorMessage, checkers: definition?.checkers ?? [], coerce: definition?.coerce ?? false, - }, (data, _error, self) => { + }, (data, error$1, self) => { if (typeof data === "boolean") { return data; } @@ -25,7 +25,7 @@ function boolean(definition) { return lower === "true"; } else { - return error.SymbolDataParserErrorIssue; + return error.addIssue(error$1, "boolean", data, self.definition.errorMessage); } } else if (typeof data === "number" @@ -34,7 +34,7 @@ function boolean(definition) { return data === 1; } } - return error.SymbolDataParserErrorIssue; + return error.addIssue(error$1, "boolean", data, self.definition.errorMessage); }, boolean.overrideHandler); return self; } diff --git a/docs/public/libs/v1/dataParser/parsers/boolean.mjs b/docs/public/libs/v1/dataParser/parsers/boolean.mjs index f8c400124..b1f7938c2 100644 --- a/docs/public/libs/v1/dataParser/parsers/boolean.mjs +++ b/docs/public/libs/v1/dataParser/parsers/boolean.mjs @@ -1,5 +1,5 @@ import { dataParserInit } from '../base.mjs'; -import { SymbolDataParserErrorIssue } from '../error.mjs'; +import { addIssue } from '../error.mjs'; import { createDataParserKind } from '../kind.mjs'; import { createOverride } from '../../common/override.mjs'; @@ -12,7 +12,7 @@ function boolean(definition) { errorMessage: definition?.errorMessage, checkers: definition?.checkers ?? [], coerce: definition?.coerce ?? false, - }, (data, _error, self) => { + }, (data, error, self) => { if (typeof data === "boolean") { return data; } @@ -23,7 +23,7 @@ function boolean(definition) { return lower === "true"; } else { - return SymbolDataParserErrorIssue; + return addIssue(error, "boolean", data, self.definition.errorMessage); } } else if (typeof data === "number" @@ -32,7 +32,7 @@ function boolean(definition) { return data === 1; } } - return SymbolDataParserErrorIssue; + return addIssue(error, "boolean", data, self.definition.errorMessage); }, boolean.overrideHandler); return self; } diff --git a/docs/public/libs/v1/dataParser/parsers/date.cjs b/docs/public/libs/v1/dataParser/parsers/date.cjs index 0e1577d6d..be58040bb 100644 --- a/docs/public/libs/v1/dataParser/parsers/date.cjs +++ b/docs/public/libs/v1/dataParser/parsers/date.cjs @@ -18,11 +18,11 @@ function date(definition) { errorMessage: definition?.errorMessage, checkers: definition?.checkers ?? [], coerce: definition?.coerce ?? false, - }, (data, _error, self) => { + }, (data, error$1, self) => { if (self.definition.coerce) { if (typeof data === "number") { if (!isSafeTimestamp.isSafeTimestamp(data)) { - return error.SymbolDataParserErrorIssue; + return error.addIssue(error$1, "date", data, self.definition.errorMessage); } return theDate.TheDate.new(data); } @@ -43,11 +43,11 @@ function date(definition) { else if (data instanceof Date) { const timestamp = data.getTime(); if (!isSafeTimestamp.isSafeTimestamp(timestamp)) { - return error.SymbolDataParserErrorIssue; + return error.addIssue(error$1, "date", data, self.definition.errorMessage); } return theDate.TheDate.new(timestamp); } - return error.SymbolDataParserErrorIssue; + return error.addIssue(error$1, "date", data, self.definition.errorMessage); }, date.overrideHandler); return self; } diff --git a/docs/public/libs/v1/dataParser/parsers/date.mjs b/docs/public/libs/v1/dataParser/parsers/date.mjs index 80cba40a2..19f89a29f 100644 --- a/docs/public/libs/v1/dataParser/parsers/date.mjs +++ b/docs/public/libs/v1/dataParser/parsers/date.mjs @@ -1,5 +1,5 @@ import { dataParserInit } from '../base.mjs'; -import { SymbolDataParserErrorIssue } from '../error.mjs'; +import { addIssue } from '../error.mjs'; import { createDataParserKind } from '../kind.mjs'; import { isSafeTimestamp } from '../../date/isSafeTimestamp.mjs'; import { TheDate } from '../../date/theDate.mjs'; @@ -16,11 +16,11 @@ function date(definition) { errorMessage: definition?.errorMessage, checkers: definition?.checkers ?? [], coerce: definition?.coerce ?? false, - }, (data, _error, self) => { + }, (data, error, self) => { if (self.definition.coerce) { if (typeof data === "number") { if (!isSafeTimestamp(data)) { - return SymbolDataParserErrorIssue; + return addIssue(error, "date", data, self.definition.errorMessage); } return TheDate.new(data); } @@ -41,11 +41,11 @@ function date(definition) { else if (data instanceof Date) { const timestamp = data.getTime(); if (!isSafeTimestamp(timestamp)) { - return SymbolDataParserErrorIssue; + return addIssue(error, "date", data, self.definition.errorMessage); } return TheDate.new(timestamp); } - return SymbolDataParserErrorIssue; + return addIssue(error, "date", data, self.definition.errorMessage); }, date.overrideHandler); return self; } diff --git a/docs/public/libs/v1/dataParser/parsers/empty.cjs b/docs/public/libs/v1/dataParser/parsers/empty.cjs index 1a8e0f25e..43a790a53 100644 --- a/docs/public/libs/v1/dataParser/parsers/empty.cjs +++ b/docs/public/libs/v1/dataParser/parsers/empty.cjs @@ -14,14 +14,14 @@ function empty(definition) { errorMessage: definition?.errorMessage, checkers: definition?.checkers ?? [], coerce: definition?.coerce ?? false, - }, (data, _error, self) => { + }, (data, error$1, self) => { if (data === undefined) { return data; } else if (self.definition.coerce && data === "undefined") { return undefined; } - return error.SymbolDataParserErrorIssue; + return error.addIssue(error$1, "undefined", data, self.definition.errorMessage); }, empty.overrideHandler); return self; } diff --git a/docs/public/libs/v1/dataParser/parsers/empty.mjs b/docs/public/libs/v1/dataParser/parsers/empty.mjs index 978c5a4c9..8229f193e 100644 --- a/docs/public/libs/v1/dataParser/parsers/empty.mjs +++ b/docs/public/libs/v1/dataParser/parsers/empty.mjs @@ -1,5 +1,5 @@ import { dataParserInit } from '../base.mjs'; -import { SymbolDataParserErrorIssue } from '../error.mjs'; +import { addIssue } from '../error.mjs'; import { createDataParserKind } from '../kind.mjs'; import { createOverride } from '../../common/override.mjs'; @@ -12,14 +12,14 @@ function empty(definition) { errorMessage: definition?.errorMessage, checkers: definition?.checkers ?? [], coerce: definition?.coerce ?? false, - }, (data, _error, self) => { + }, (data, error, self) => { if (data === undefined) { return data; } else if (self.definition.coerce && data === "undefined") { return undefined; } - return SymbolDataParserErrorIssue; + return addIssue(error, "undefined", data, self.definition.errorMessage); }, empty.overrideHandler); return self; } diff --git a/docs/public/libs/v1/dataParser/parsers/literal.cjs b/docs/public/libs/v1/dataParser/parsers/literal.cjs index 850c72821..a23d298c6 100644 --- a/docs/public/libs/v1/dataParser/parsers/literal.cjs +++ b/docs/public/libs/v1/dataParser/parsers/literal.cjs @@ -15,11 +15,11 @@ function literal(value, definition) { errorMessage: definition?.errorMessage, checkers: definition?.checkers ?? [], value: coalescing.coalescing(value), - }, (data, _error, self) => { + }, (data, error$1, self) => { if (self.definition.value.includes(data)) { return data; } - return error.SymbolDataParserErrorIssue; + return error.addIssue(error$1, `one of ${self.definition.value.map((value) => String(value)).join(", ")}`, data, self.definition.errorMessage); }, literal.overrideHandler); return self; } diff --git a/docs/public/libs/v1/dataParser/parsers/literal.mjs b/docs/public/libs/v1/dataParser/parsers/literal.mjs index e56d26c3a..a79d63559 100644 --- a/docs/public/libs/v1/dataParser/parsers/literal.mjs +++ b/docs/public/libs/v1/dataParser/parsers/literal.mjs @@ -1,5 +1,5 @@ import { dataParserInit } from '../base.mjs'; -import { SymbolDataParserErrorIssue } from '../error.mjs'; +import { addIssue } from '../error.mjs'; import { createDataParserKind } from '../kind.mjs'; import { coalescing } from '../../array/coalescing.mjs'; import { createOverride } from '../../common/override.mjs'; @@ -13,11 +13,11 @@ function literal(value, definition) { errorMessage: definition?.errorMessage, checkers: definition?.checkers ?? [], value: coalescing(value), - }, (data, _error, self) => { + }, (data, error, self) => { if (self.definition.value.includes(data)) { return data; } - return SymbolDataParserErrorIssue; + return addIssue(error, `one of ${self.definition.value.map((value) => String(value)).join(", ")}`, data, self.definition.errorMessage); }, literal.overrideHandler); return self; } diff --git a/docs/public/libs/v1/dataParser/parsers/nil.cjs b/docs/public/libs/v1/dataParser/parsers/nil.cjs index d824da0d8..07114149e 100644 --- a/docs/public/libs/v1/dataParser/parsers/nil.cjs +++ b/docs/public/libs/v1/dataParser/parsers/nil.cjs @@ -14,14 +14,14 @@ function nil(definition) { errorMessage: definition?.errorMessage, checkers: definition?.checkers ?? [], coerce: definition?.coerce ?? false, - }, (data, _error, self) => { + }, (data, error$1, self) => { if (data === null) { return data; } else if (self.definition.coerce && data === "null") { return null; } - return error.SymbolDataParserErrorIssue; + return error.addIssue(error$1, "null", data, self.definition.errorMessage); }, nil.overrideHandler); return self; } diff --git a/docs/public/libs/v1/dataParser/parsers/nil.mjs b/docs/public/libs/v1/dataParser/parsers/nil.mjs index aa4828e61..da2564515 100644 --- a/docs/public/libs/v1/dataParser/parsers/nil.mjs +++ b/docs/public/libs/v1/dataParser/parsers/nil.mjs @@ -1,5 +1,5 @@ import { dataParserInit } from '../base.mjs'; -import { SymbolDataParserErrorIssue } from '../error.mjs'; +import { addIssue } from '../error.mjs'; import { createDataParserKind } from '../kind.mjs'; import { createOverride } from '../../common/override.mjs'; @@ -12,14 +12,14 @@ function nil(definition) { errorMessage: definition?.errorMessage, checkers: definition?.checkers ?? [], coerce: definition?.coerce ?? false, - }, (data, _error, self) => { + }, (data, error, self) => { if (data === null) { return data; } else if (self.definition.coerce && data === "null") { return null; } - return SymbolDataParserErrorIssue; + return addIssue(error, "null", data, self.definition.errorMessage); }, nil.overrideHandler); return self; } diff --git a/docs/public/libs/v1/dataParser/parsers/number/checkers/int.cjs b/docs/public/libs/v1/dataParser/parsers/number/checkers/int.cjs index a7f89df47..5fa131cab 100644 --- a/docs/public/libs/v1/dataParser/parsers/number/checkers/int.cjs +++ b/docs/public/libs/v1/dataParser/parsers/number/checkers/int.cjs @@ -9,11 +9,11 @@ const checkerIntKind = kind.createDataParserKind("checker-number-int"); function checkerInt(definition = {}) { return base.dataParserCheckerInit(checkerIntKind, { definition, - }, (data) => { + }, (data, error$1, self) => { if (Number.isInteger(data)) { return data; } - return error.SymbolDataParserErrorIssue; + return error.addIssue(error$1, "integer", data, self.definition.errorMessage); }); } function int(definition) { diff --git a/docs/public/libs/v1/dataParser/parsers/number/checkers/int.mjs b/docs/public/libs/v1/dataParser/parsers/number/checkers/int.mjs index bf82bc014..2c7abaefa 100644 --- a/docs/public/libs/v1/dataParser/parsers/number/checkers/int.mjs +++ b/docs/public/libs/v1/dataParser/parsers/number/checkers/int.mjs @@ -1,5 +1,5 @@ import { dataParserCheckerInit } from '../../../base.mjs'; -import { SymbolDataParserErrorIssue } from '../../../error.mjs'; +import { addIssue } from '../../../error.mjs'; import { number } from '../index.mjs'; import { createDataParserKind } from '../../../kind.mjs'; @@ -7,11 +7,11 @@ const checkerIntKind = createDataParserKind("checker-number-int"); function checkerInt(definition = {}) { return dataParserCheckerInit(checkerIntKind, { definition, - }, (data) => { + }, (data, error, self) => { if (Number.isInteger(data)) { return data; } - return SymbolDataParserErrorIssue; + return addIssue(error, "integer", data, self.definition.errorMessage); }); } function int(definition) { diff --git a/docs/public/libs/v1/dataParser/parsers/number/checkers/max.cjs b/docs/public/libs/v1/dataParser/parsers/number/checkers/max.cjs index 5557848ac..7d2455aac 100644 --- a/docs/public/libs/v1/dataParser/parsers/number/checkers/max.cjs +++ b/docs/public/libs/v1/dataParser/parsers/number/checkers/max.cjs @@ -11,7 +11,9 @@ function checkerNumberMax(max, definition = {}) { ...definition, max, }, - }, (value, self) => value <= self.definition.max ? value : error.SymbolDataParserErrorIssue); + }, (value, error$1, self) => value <= self.definition.max + ? value + : error.addIssue(error$1, `number <= ${self.definition.max}`, value, self.definition.errorMessage)); } exports.checkerNumberMax = checkerNumberMax; diff --git a/docs/public/libs/v1/dataParser/parsers/number/checkers/max.mjs b/docs/public/libs/v1/dataParser/parsers/number/checkers/max.mjs index e79bf145a..6e908a902 100644 --- a/docs/public/libs/v1/dataParser/parsers/number/checkers/max.mjs +++ b/docs/public/libs/v1/dataParser/parsers/number/checkers/max.mjs @@ -1,5 +1,5 @@ import { dataParserCheckerInit } from '../../../base.mjs'; -import { SymbolDataParserErrorIssue } from '../../../error.mjs'; +import { addIssue } from '../../../error.mjs'; import { createDataParserKind } from '../../../kind.mjs'; const checkerNumberMaxKind = createDataParserKind("checker-number-max"); @@ -9,7 +9,9 @@ function checkerNumberMax(max, definition = {}) { ...definition, max, }, - }, (value, self) => value <= self.definition.max ? value : SymbolDataParserErrorIssue); + }, (value, error, self) => value <= self.definition.max + ? value + : addIssue(error, `number <= ${self.definition.max}`, value, self.definition.errorMessage)); } export { checkerNumberMax, checkerNumberMaxKind }; diff --git a/docs/public/libs/v1/dataParser/parsers/number/checkers/min.cjs b/docs/public/libs/v1/dataParser/parsers/number/checkers/min.cjs index 246460fe6..59058c689 100644 --- a/docs/public/libs/v1/dataParser/parsers/number/checkers/min.cjs +++ b/docs/public/libs/v1/dataParser/parsers/number/checkers/min.cjs @@ -11,7 +11,9 @@ function checkerNumberMin(min, definition = {}) { ...definition, min, }, - }, (value, self) => value >= self.definition.min ? value : error.SymbolDataParserErrorIssue); + }, (value, error$1, self) => value >= self.definition.min + ? value + : error.addIssue(error$1, `number >= ${self.definition.min}`, value, self.definition.errorMessage)); } exports.checkerNumberMin = checkerNumberMin; diff --git a/docs/public/libs/v1/dataParser/parsers/number/checkers/min.mjs b/docs/public/libs/v1/dataParser/parsers/number/checkers/min.mjs index 96ffc91ca..11138be66 100644 --- a/docs/public/libs/v1/dataParser/parsers/number/checkers/min.mjs +++ b/docs/public/libs/v1/dataParser/parsers/number/checkers/min.mjs @@ -1,5 +1,5 @@ import { dataParserCheckerInit } from '../../../base.mjs'; -import { SymbolDataParserErrorIssue } from '../../../error.mjs'; +import { addIssue } from '../../../error.mjs'; import { createDataParserKind } from '../../../kind.mjs'; const checkerNumberMinKind = createDataParserKind("checker-number-min"); @@ -9,7 +9,9 @@ function checkerNumberMin(min, definition = {}) { ...definition, min, }, - }, (value, self) => value >= self.definition.min ? value : SymbolDataParserErrorIssue); + }, (value, error, self) => value >= self.definition.min + ? value + : addIssue(error, `number >= ${self.definition.min}`, value, self.definition.errorMessage)); } export { checkerNumberMin, checkerNumberMinKind }; diff --git a/docs/public/libs/v1/dataParser/parsers/number/index.cjs b/docs/public/libs/v1/dataParser/parsers/number/index.cjs index 22184f3ff..d8a62434a 100644 --- a/docs/public/libs/v1/dataParser/parsers/number/index.cjs +++ b/docs/public/libs/v1/dataParser/parsers/number/index.cjs @@ -14,7 +14,7 @@ function number(definition) { errorMessage: definition?.errorMessage, checkers: definition?.checkers ?? [], coerce: definition?.coerce ?? false, - }, (data, _error, self) => { + }, (data, error$1, self) => { if (self.definition.coerce) { try { // eslint-disable-next-line no-param-reassign @@ -25,7 +25,7 @@ function number(definition) { if (typeof data === "number" && !Number.isNaN(data)) { return data; } - return error.SymbolDataParserErrorIssue; + return error.addIssue(error$1, "number", data, self.definition.errorMessage); }, number.overrideHandler); return self; } diff --git a/docs/public/libs/v1/dataParser/parsers/number/index.mjs b/docs/public/libs/v1/dataParser/parsers/number/index.mjs index eee49fc89..bfcda2971 100644 --- a/docs/public/libs/v1/dataParser/parsers/number/index.mjs +++ b/docs/public/libs/v1/dataParser/parsers/number/index.mjs @@ -1,5 +1,5 @@ import { dataParserInit } from '../../base.mjs'; -import { SymbolDataParserErrorIssue } from '../../error.mjs'; +import { addIssue } from '../../error.mjs'; import { createDataParserKind } from '../../kind.mjs'; import { createOverride } from '../../../common/override.mjs'; @@ -12,7 +12,7 @@ function number(definition) { errorMessage: definition?.errorMessage, checkers: definition?.checkers ?? [], coerce: definition?.coerce ?? false, - }, (data, _error, self) => { + }, (data, error, self) => { if (self.definition.coerce) { try { // eslint-disable-next-line no-param-reassign @@ -23,7 +23,7 @@ function number(definition) { if (typeof data === "number" && !Number.isNaN(data)) { return data; } - return SymbolDataParserErrorIssue; + return addIssue(error, "number", data, self.definition.errorMessage); }, number.overrideHandler); return self; } diff --git a/docs/public/libs/v1/dataParser/parsers/object/index.cjs b/docs/public/libs/v1/dataParser/parsers/object/index.cjs index aea2a2f57..f6a033966 100644 --- a/docs/public/libs/v1/dataParser/parsers/object/index.cjs +++ b/docs/public/libs/v1/dataParser/parsers/object/index.cjs @@ -30,17 +30,17 @@ function object(shape, definition) { if (!data || typeof data !== "object" || data instanceof Array) { - return error.SymbolDataParserErrorIssue; + return error.addIssue(error$1, "object", data, self.definition.errorMessage); } let output = {}; const currentIndexPath = error$1.currentPath.length; for (const entry of self.definition.optimizedShape.value) { error.setErrorPath(error$1, entry.key, currentIndexPath); const result = entry.value.exec(data[entry.key], error$1); - if (result === base.SymbolDataParserError) { - output = base.SymbolDataParserError; + if (result === error.SymbolDataParserError) { + output = error.SymbolDataParserError; } - else if (output !== base.SymbolDataParserError + else if (output !== error.SymbolDataParserError && result !== undefined) { output[entry.key] = result; } @@ -52,17 +52,17 @@ function object(shape, definition) { if (!data || typeof data !== "object" || data instanceof Array) { - return error.SymbolDataParserErrorIssue; + return error.addIssue(error$1, "object", data, self.definition.errorMessage); } let output = {}; const currentIndexPath = error$1.currentPath.length; for (const entry of self.definition.optimizedShape.value) { error.setErrorPath(error$1, entry.key, currentIndexPath); const result = await entry.value.asyncExec(data[entry.key], error$1); - if (result === base.SymbolDataParserError) { - output = base.SymbolDataParserError; + if (result === error.SymbolDataParserError) { + output = error.SymbolDataParserError; } - else if (output !== base.SymbolDataParserError + else if (output !== error.SymbolDataParserError && result !== undefined) { output[entry.key] = result; } diff --git a/docs/public/libs/v1/dataParser/parsers/object/index.mjs b/docs/public/libs/v1/dataParser/parsers/object/index.mjs index 2ac2f89c2..7b8852d5b 100644 --- a/docs/public/libs/v1/dataParser/parsers/object/index.mjs +++ b/docs/public/libs/v1/dataParser/parsers/object/index.mjs @@ -1,5 +1,5 @@ -import { dataParserInit, SymbolDataParserError, dataParserKind } from '../../base.mjs'; -import { SymbolDataParserErrorIssue, setErrorPath, popErrorPath } from '../../error.mjs'; +import { dataParserInit, dataParserKind } from '../../base.mjs'; +import { addIssue, setErrorPath, SymbolDataParserError, popErrorPath } from '../../error.mjs'; import { createDataParserKind } from '../../kind.mjs'; import { memo } from '../../../common/memo.mjs'; import { some } from '../../../array/some.mjs'; @@ -28,7 +28,7 @@ function object(shape, definition) { if (!data || typeof data !== "object" || data instanceof Array) { - return SymbolDataParserErrorIssue; + return addIssue(error, "object", data, self.definition.errorMessage); } let output = {}; const currentIndexPath = error.currentPath.length; @@ -50,7 +50,7 @@ function object(shape, definition) { if (!data || typeof data !== "object" || data instanceof Array) { - return SymbolDataParserErrorIssue; + return addIssue(error, "object", data, self.definition.errorMessage); } let output = {}; const currentIndexPath = error.currentPath.length; diff --git a/docs/public/libs/v1/dataParser/parsers/pipe.cjs b/docs/public/libs/v1/dataParser/parsers/pipe.cjs index 173f1a9e3..8e4d9529d 100644 --- a/docs/public/libs/v1/dataParser/parsers/pipe.cjs +++ b/docs/public/libs/v1/dataParser/parsers/pipe.cjs @@ -2,6 +2,7 @@ var base = require('../base.cjs'); var kind = require('../kind.cjs'); +var error = require('../error.cjs'); var override = require('../../common/override.cjs'); const pipeKind = kind.createDataParserKind("pipe"); @@ -15,19 +16,19 @@ function pipe(input, output, definition) { input, output, }, { - sync: (data, error, self) => { - const result = self.definition.input.exec(data, error); - if (result === base.SymbolDataParserError) { - return base.SymbolDataParserError; + sync: (data, error$1, self) => { + const result = self.definition.input.exec(data, error$1); + if (result === error.SymbolDataParserError) { + return error.SymbolDataParserError; } - return self.definition.output.exec(result, error); + return self.definition.output.exec(result, error$1); }, - async: async (data, error, self) => { - const result = await self.definition.input.asyncExec(data, error); - if (result === base.SymbolDataParserError) { - return base.SymbolDataParserError; + async: async (data, error$1, self) => { + const result = await self.definition.input.asyncExec(data, error$1); + if (result === error.SymbolDataParserError) { + return error.SymbolDataParserError; } - return self.definition.output.asyncExec(result, error); + return self.definition.output.asyncExec(result, error$1); }, isAsynchronous: (self) => self.definition.input.isAsynchronous() || self.definition.output.isAsynchronous(), }, pipe.overrideHandler); diff --git a/docs/public/libs/v1/dataParser/parsers/pipe.mjs b/docs/public/libs/v1/dataParser/parsers/pipe.mjs index 6c0457e44..b40957685 100644 --- a/docs/public/libs/v1/dataParser/parsers/pipe.mjs +++ b/docs/public/libs/v1/dataParser/parsers/pipe.mjs @@ -1,5 +1,6 @@ -import { dataParserInit, SymbolDataParserError } from '../base.mjs'; +import { dataParserInit } from '../base.mjs'; import { createDataParserKind } from '../kind.mjs'; +import { SymbolDataParserError } from '../error.mjs'; import { createOverride } from '../../common/override.mjs'; const pipeKind = createDataParserKind("pipe"); diff --git a/docs/public/libs/v1/dataParser/parsers/record/index.cjs b/docs/public/libs/v1/dataParser/parsers/record/index.cjs index 8714e1056..eaf309224 100644 --- a/docs/public/libs/v1/dataParser/parsers/record/index.cjs +++ b/docs/public/libs/v1/dataParser/parsers/record/index.cjs @@ -28,7 +28,7 @@ function record(key, value, definition) { if (!data || typeof data !== "object" || data instanceof Array) { - return error.SymbolDataParserErrorIssue; + return error.addIssue(error$1, "record object", data, self.definition.errorMessage); } let output = {}; const fromData = { @@ -42,22 +42,22 @@ function record(key, value, definition) { .definition .key .exec(key, error$1); - if (resultKey === base.SymbolDataParserError) { - output = base.SymbolDataParserError; + if (resultKey === error.SymbolDataParserError) { + output = error.SymbolDataParserError; } const resultValue = self .definition .value .exec(fromData[key], error$1); - if (resultValue === base.SymbolDataParserError) { - output = base.SymbolDataParserError; + if (resultValue === error.SymbolDataParserError) { + output = error.SymbolDataParserError; } - if (output !== base.SymbolDataParserError) { + if (output !== error.SymbolDataParserError) { output[resultKey] = resultValue; } } void (currentIndexPath !== error$1.currentPath.length && error.popErrorPath(error$1)); - if (output === base.SymbolDataParserError) { + if (output === error.SymbolDataParserError) { return output; } return output; @@ -66,7 +66,7 @@ function record(key, value, definition) { if (!data || typeof data !== "object" || data instanceof Array) { - return error.SymbolDataParserErrorIssue; + return error.addIssue(error$1, "record object", data, self.definition.errorMessage); } let output = {}; const fromData = { @@ -80,22 +80,22 @@ function record(key, value, definition) { .definition .key .asyncExec(key, error$1); - if (resultKey === base.SymbolDataParserError) { - output = base.SymbolDataParserError; + if (resultKey === error.SymbolDataParserError) { + output = error.SymbolDataParserError; } const resultValue = await self .definition .value .asyncExec(fromData[key], error$1); - if (resultValue === base.SymbolDataParserError) { - output = base.SymbolDataParserError; + if (resultValue === error.SymbolDataParserError) { + output = error.SymbolDataParserError; } - if (output !== base.SymbolDataParserError) { + if (output !== error.SymbolDataParserError) { output[resultKey] = resultValue; } } void (currentIndexPath !== error$1.currentPath.length && error.popErrorPath(error$1)); - if (output === base.SymbolDataParserError) { + if (output === error.SymbolDataParserError) { return output; } return output; diff --git a/docs/public/libs/v1/dataParser/parsers/record/index.mjs b/docs/public/libs/v1/dataParser/parsers/record/index.mjs index 39d3b14b9..e01725f0c 100644 --- a/docs/public/libs/v1/dataParser/parsers/record/index.mjs +++ b/docs/public/libs/v1/dataParser/parsers/record/index.mjs @@ -1,5 +1,5 @@ -import { dataParserInit, SymbolDataParserError } from '../../base.mjs'; -import { SymbolDataParserErrorIssue, setErrorPath, popErrorPath } from '../../error.mjs'; +import { dataParserInit } from '../../base.mjs'; +import { addIssue, setErrorPath, SymbolDataParserError, popErrorPath } from '../../error.mjs'; import { createDataParserKind } from '../../kind.mjs'; import { findRecordRequiredKey } from './findRecordRequiredKey.mjs'; export { findRecordRequiredKeyOnTemplateLiteralPart } from './findRecordRequiredKey.mjs'; @@ -27,7 +27,7 @@ function record(key, value, definition) { if (!data || typeof data !== "object" || data instanceof Array) { - return SymbolDataParserErrorIssue; + return addIssue(error, "record object", data, self.definition.errorMessage); } let output = {}; const fromData = { @@ -65,7 +65,7 @@ function record(key, value, definition) { if (!data || typeof data !== "object" || data instanceof Array) { - return SymbolDataParserErrorIssue; + return addIssue(error, "record object", data, self.definition.errorMessage); } let output = {}; const fromData = { diff --git a/docs/public/libs/v1/dataParser/parsers/recover.cjs b/docs/public/libs/v1/dataParser/parsers/recover.cjs index c1c5c1931..552b5d109 100644 --- a/docs/public/libs/v1/dataParser/parsers/recover.cjs +++ b/docs/public/libs/v1/dataParser/parsers/recover.cjs @@ -2,6 +2,7 @@ var base = require('../base.cjs'); var kind = require('../kind.cjs'); +var error = require('../error.cjs'); var override = require('../../common/override.cjs'); const recoverKind = kind.createDataParserKind("recover"); @@ -15,15 +16,15 @@ function recover(inner, recoveredValue, definition) { inner, recoveredValue, }, { - sync: (data, error, self) => { - const result = self.definition.inner.exec(data, error); - return result === base.SymbolDataParserError + sync: (data, error$1, self) => { + const result = self.definition.inner.exec(data, error$1); + return result === error.SymbolDataParserError ? self.definition.recoveredValue : result; }, - async: async (data, error, self) => { - const result = await self.definition.inner.asyncExec(data, error); - return result === base.SymbolDataParserError + async: async (data, error$1, self) => { + const result = await self.definition.inner.asyncExec(data, error$1); + return result === error.SymbolDataParserError ? self.definition.recoveredValue : result; }, diff --git a/docs/public/libs/v1/dataParser/parsers/recover.mjs b/docs/public/libs/v1/dataParser/parsers/recover.mjs index 570034384..01e598d54 100644 --- a/docs/public/libs/v1/dataParser/parsers/recover.mjs +++ b/docs/public/libs/v1/dataParser/parsers/recover.mjs @@ -1,5 +1,6 @@ -import { dataParserInit, SymbolDataParserError } from '../base.mjs'; +import { dataParserInit } from '../base.mjs'; import { createDataParserKind } from '../kind.mjs'; +import { SymbolDataParserError } from '../error.mjs'; import { createOverride } from '../../common/override.mjs'; const recoverKind = createDataParserKind("recover"); diff --git a/docs/public/libs/v1/dataParser/parsers/refine.cjs b/docs/public/libs/v1/dataParser/parsers/refine.cjs index 09b9fc00b..4bf0161df 100644 --- a/docs/public/libs/v1/dataParser/parsers/refine.cjs +++ b/docs/public/libs/v1/dataParser/parsers/refine.cjs @@ -11,7 +11,9 @@ function checkerRefine(theFunction, definition) { ...definition, theFunction, }, - }, (value, self) => self.definition.theFunction(value) ? value : error.SymbolDataParserErrorIssue); + }, (value, error$1, self) => self.definition.theFunction(value) + ? value + : error.addIssue(error$1, "value matching refine predicate", value, self.definition.errorMessage)); } exports.checkerRefine = checkerRefine; diff --git a/docs/public/libs/v1/dataParser/parsers/refine.mjs b/docs/public/libs/v1/dataParser/parsers/refine.mjs index 4bfd2aa15..ecdc64ecc 100644 --- a/docs/public/libs/v1/dataParser/parsers/refine.mjs +++ b/docs/public/libs/v1/dataParser/parsers/refine.mjs @@ -1,5 +1,5 @@ import { dataParserCheckerInit } from '../base.mjs'; -import { SymbolDataParserErrorIssue } from '../error.mjs'; +import { addIssue } from '../error.mjs'; import { createDataParserKind } from '../kind.mjs'; const dataParserCheckerRefineKind = createDataParserKind("refine"); @@ -9,7 +9,9 @@ function checkerRefine(theFunction, definition) { ...definition, theFunction, }, - }, (value, self) => self.definition.theFunction(value) ? value : SymbolDataParserErrorIssue); + }, (value, error, self) => self.definition.theFunction(value) + ? value + : addIssue(error, "value matching refine predicate", value, self.definition.errorMessage)); } export { checkerRefine, dataParserCheckerRefineKind }; diff --git a/docs/public/libs/v1/dataParser/parsers/string/checkers/email.cjs b/docs/public/libs/v1/dataParser/parsers/string/checkers/email.cjs index 7713fbb61..868007131 100644 --- a/docs/public/libs/v1/dataParser/parsers/string/checkers/email.cjs +++ b/docs/public/libs/v1/dataParser/parsers/string/checkers/email.cjs @@ -13,9 +13,9 @@ function checkerEmail(definition = {}) { ...definition, pattern: emailPattern, }, - }, (input, self) => { + }, (input, error$1, self) => { if (!self.definition.pattern.test(input)) { - return error.SymbolDataParserErrorIssue; + return error.addIssue(error$1, "email", input, self.definition.errorMessage); } return self.definition.normalize ? input.toLowerCase() : input; }); diff --git a/docs/public/libs/v1/dataParser/parsers/string/checkers/email.mjs b/docs/public/libs/v1/dataParser/parsers/string/checkers/email.mjs index d1db96181..9f3972267 100644 --- a/docs/public/libs/v1/dataParser/parsers/string/checkers/email.mjs +++ b/docs/public/libs/v1/dataParser/parsers/string/checkers/email.mjs @@ -1,5 +1,5 @@ import { dataParserCheckerInit } from '../../../base.mjs'; -import { SymbolDataParserErrorIssue } from '../../../error.mjs'; +import { addIssue } from '../../../error.mjs'; import { string } from '../index.mjs'; import { createDataParserKind } from '../../../kind.mjs'; @@ -11,9 +11,9 @@ function checkerEmail(definition = {}) { ...definition, pattern: emailPattern, }, - }, (input, self) => { + }, (input, error, self) => { if (!self.definition.pattern.test(input)) { - return SymbolDataParserErrorIssue; + return addIssue(error, "email", input, self.definition.errorMessage); } return self.definition.normalize ? input.toLowerCase() : input; }); diff --git a/docs/public/libs/v1/dataParser/parsers/string/checkers/max.cjs b/docs/public/libs/v1/dataParser/parsers/string/checkers/max.cjs index eb9baf4df..bdb677c59 100644 --- a/docs/public/libs/v1/dataParser/parsers/string/checkers/max.cjs +++ b/docs/public/libs/v1/dataParser/parsers/string/checkers/max.cjs @@ -11,7 +11,9 @@ function checkerStringMax(max, definition = {}) { ...definition, max, }, - }, (value, self) => value.length <= self.definition.max ? value : error.SymbolDataParserErrorIssue); + }, (value, error$1, self) => value.length <= self.definition.max + ? value + : error.addIssue(error$1, `string.length <= ${self.definition.max}`, value, self.definition.errorMessage)); } exports.checkerStringMax = checkerStringMax; diff --git a/docs/public/libs/v1/dataParser/parsers/string/checkers/max.mjs b/docs/public/libs/v1/dataParser/parsers/string/checkers/max.mjs index ab5e42f94..112c45e19 100644 --- a/docs/public/libs/v1/dataParser/parsers/string/checkers/max.mjs +++ b/docs/public/libs/v1/dataParser/parsers/string/checkers/max.mjs @@ -1,5 +1,5 @@ import { dataParserCheckerInit } from '../../../base.mjs'; -import { SymbolDataParserErrorIssue } from '../../../error.mjs'; +import { addIssue } from '../../../error.mjs'; import { createDataParserKind } from '../../../kind.mjs'; const checkerStringMaxKind = createDataParserKind("checker-string-max"); @@ -9,7 +9,9 @@ function checkerStringMax(max, definition = {}) { ...definition, max, }, - }, (value, self) => value.length <= self.definition.max ? value : SymbolDataParserErrorIssue); + }, (value, error, self) => value.length <= self.definition.max + ? value + : addIssue(error, `string.length <= ${self.definition.max}`, value, self.definition.errorMessage)); } export { checkerStringMax, checkerStringMaxKind }; diff --git a/docs/public/libs/v1/dataParser/parsers/string/checkers/min.cjs b/docs/public/libs/v1/dataParser/parsers/string/checkers/min.cjs index 79700e1f0..73731c8a1 100644 --- a/docs/public/libs/v1/dataParser/parsers/string/checkers/min.cjs +++ b/docs/public/libs/v1/dataParser/parsers/string/checkers/min.cjs @@ -11,7 +11,9 @@ function checkerStringMin(min, definition = {}) { ...definition, min, }, - }, (value, self) => value.length >= self.definition.min ? value : error.SymbolDataParserErrorIssue); + }, (value, error$1, self) => value.length >= self.definition.min + ? value + : error.addIssue(error$1, `string.length >= ${self.definition.min}`, value, self.definition.errorMessage)); } exports.checkerStringMin = checkerStringMin; diff --git a/docs/public/libs/v1/dataParser/parsers/string/checkers/min.mjs b/docs/public/libs/v1/dataParser/parsers/string/checkers/min.mjs index 7783779a6..e5ba6d4b8 100644 --- a/docs/public/libs/v1/dataParser/parsers/string/checkers/min.mjs +++ b/docs/public/libs/v1/dataParser/parsers/string/checkers/min.mjs @@ -1,5 +1,5 @@ import { dataParserCheckerInit } from '../../../base.mjs'; -import { SymbolDataParserErrorIssue } from '../../../error.mjs'; +import { addIssue } from '../../../error.mjs'; import { createDataParserKind } from '../../../kind.mjs'; const checkerStringMinKind = createDataParserKind("checker-string-min"); @@ -9,7 +9,9 @@ function checkerStringMin(min, definition = {}) { ...definition, min, }, - }, (value, self) => value.length >= self.definition.min ? value : SymbolDataParserErrorIssue); + }, (value, error, self) => value.length >= self.definition.min + ? value + : addIssue(error, `string.length >= ${self.definition.min}`, value, self.definition.errorMessage)); } export { checkerStringMin, checkerStringMinKind }; diff --git a/docs/public/libs/v1/dataParser/parsers/string/checkers/regex.cjs b/docs/public/libs/v1/dataParser/parsers/string/checkers/regex.cjs index 76a327bdb..2cd9bf5dd 100644 --- a/docs/public/libs/v1/dataParser/parsers/string/checkers/regex.cjs +++ b/docs/public/libs/v1/dataParser/parsers/string/checkers/regex.cjs @@ -11,9 +11,9 @@ function checkerStringRegex(regex, definition = {}) { ...definition, regex, }, - }, (value, self) => self.definition.regex.test(value) + }, (value, error$1, self) => self.definition.regex.test(value) ? value - : error.SymbolDataParserErrorIssue); + : error.addIssue(error$1, `string with pattern ${self.definition.regex.source.toString()}`, value, self.definition.errorMessage)); } exports.checkerStringRegex = checkerStringRegex; diff --git a/docs/public/libs/v1/dataParser/parsers/string/checkers/regex.mjs b/docs/public/libs/v1/dataParser/parsers/string/checkers/regex.mjs index 50ecaa178..42ee3bd30 100644 --- a/docs/public/libs/v1/dataParser/parsers/string/checkers/regex.mjs +++ b/docs/public/libs/v1/dataParser/parsers/string/checkers/regex.mjs @@ -1,5 +1,5 @@ import { dataParserCheckerInit } from '../../../base.mjs'; -import { SymbolDataParserErrorIssue } from '../../../error.mjs'; +import { addIssue } from '../../../error.mjs'; import { createDataParserKind } from '../../../kind.mjs'; const checkerStringRegexKind = createDataParserKind("checker-string-regex"); @@ -9,9 +9,9 @@ function checkerStringRegex(regex, definition = {}) { ...definition, regex, }, - }, (value, self) => self.definition.regex.test(value) + }, (value, error, self) => self.definition.regex.test(value) ? value - : SymbolDataParserErrorIssue); + : addIssue(error, `string with pattern ${self.definition.regex.source.toString()}`, value, self.definition.errorMessage)); } export { checkerStringRegex, checkerStringRegexKind }; diff --git a/docs/public/libs/v1/dataParser/parsers/string/checkers/url.cjs b/docs/public/libs/v1/dataParser/parsers/string/checkers/url.cjs index ff74afdc3..4759651f5 100644 --- a/docs/public/libs/v1/dataParser/parsers/string/checkers/url.cjs +++ b/docs/public/libs/v1/dataParser/parsers/string/checkers/url.cjs @@ -10,19 +10,19 @@ const regexRemoveDote = /:$/; function checkerUrl(definition = {}) { return base.dataParserCheckerInit(checkerUrlKind, { definition: definition, - }, (input, self) => { + }, (input, error$1, self) => { try { const url = new URL(input); if (self.definition.hostname) { self.definition.hostname.lastIndex = 0; if (!self.definition.hostname.test(url.hostname)) { - return error.SymbolDataParserErrorIssue; + return error.addIssue(error$1, `URL with hostname matching ${self.definition.hostname.source}`, input, self.definition.errorMessage); } } if (self.definition.protocol) { self.definition.protocol.lastIndex = 0; if (!self.definition.protocol.test(url.protocol.replace(regexRemoveDote, ""))) { - return error.SymbolDataParserErrorIssue; + return error.addIssue(error$1, `URL with protocol matching ${self.definition.protocol.source}`, input, self.definition.errorMessage); } } if (self.definition.normalize) { @@ -33,7 +33,7 @@ function checkerUrl(definition = {}) { } } catch { - return error.SymbolDataParserErrorIssue; + return error.addIssue(error$1, "valid URL", input, self.definition.errorMessage); } }); } diff --git a/docs/public/libs/v1/dataParser/parsers/string/checkers/url.mjs b/docs/public/libs/v1/dataParser/parsers/string/checkers/url.mjs index 2da6d19ca..c7edf618c 100644 --- a/docs/public/libs/v1/dataParser/parsers/string/checkers/url.mjs +++ b/docs/public/libs/v1/dataParser/parsers/string/checkers/url.mjs @@ -1,5 +1,5 @@ import { dataParserCheckerInit } from '../../../base.mjs'; -import { SymbolDataParserErrorIssue } from '../../../error.mjs'; +import { addIssue } from '../../../error.mjs'; import { string } from '../index.mjs'; import { createDataParserKind } from '../../../kind.mjs'; @@ -8,19 +8,19 @@ const regexRemoveDote = /:$/; function checkerUrl(definition = {}) { return dataParserCheckerInit(checkerUrlKind, { definition: definition, - }, (input, self) => { + }, (input, error, self) => { try { const url = new URL(input); if (self.definition.hostname) { self.definition.hostname.lastIndex = 0; if (!self.definition.hostname.test(url.hostname)) { - return SymbolDataParserErrorIssue; + return addIssue(error, `URL with hostname matching ${self.definition.hostname.source}`, input, self.definition.errorMessage); } } if (self.definition.protocol) { self.definition.protocol.lastIndex = 0; if (!self.definition.protocol.test(url.protocol.replace(regexRemoveDote, ""))) { - return SymbolDataParserErrorIssue; + return addIssue(error, `URL with protocol matching ${self.definition.protocol.source}`, input, self.definition.errorMessage); } } if (self.definition.normalize) { @@ -31,7 +31,7 @@ function checkerUrl(definition = {}) { } } catch { - return SymbolDataParserErrorIssue; + return addIssue(error, "valid URL", input, self.definition.errorMessage); } }); } diff --git a/docs/public/libs/v1/dataParser/parsers/string/index.cjs b/docs/public/libs/v1/dataParser/parsers/string/index.cjs index bee9a5929..0650c2bfc 100644 --- a/docs/public/libs/v1/dataParser/parsers/string/index.cjs +++ b/docs/public/libs/v1/dataParser/parsers/string/index.cjs @@ -14,7 +14,7 @@ function string(definition) { errorMessage: definition?.errorMessage, checkers: definition?.checkers ?? [], coerce: definition?.coerce ?? false, - }, (data, _error, self) => { + }, (data, error$1, self) => { if (self.definition.coerce) { try { // eslint-disable-next-line no-param-reassign @@ -25,7 +25,7 @@ function string(definition) { if (typeof data === "string") { return data; } - return error.SymbolDataParserErrorIssue; + return error.addIssue(error$1, "string", data, self.definition.errorMessage); }, string.overrideHandler); return self; } diff --git a/docs/public/libs/v1/dataParser/parsers/string/index.mjs b/docs/public/libs/v1/dataParser/parsers/string/index.mjs index 833ae1b82..f826f146e 100644 --- a/docs/public/libs/v1/dataParser/parsers/string/index.mjs +++ b/docs/public/libs/v1/dataParser/parsers/string/index.mjs @@ -1,5 +1,5 @@ import { dataParserInit } from '../../base.mjs'; -import { SymbolDataParserErrorIssue } from '../../error.mjs'; +import { addIssue } from '../../error.mjs'; import { createDataParserKind } from '../../kind.mjs'; import { createOverride } from '../../../common/override.mjs'; @@ -12,7 +12,7 @@ function string(definition) { errorMessage: definition?.errorMessage, checkers: definition?.checkers ?? [], coerce: definition?.coerce ?? false, - }, (data, _error, self) => { + }, (data, error, self) => { if (self.definition.coerce) { try { // eslint-disable-next-line no-param-reassign @@ -23,7 +23,7 @@ function string(definition) { if (typeof data === "string") { return data; } - return SymbolDataParserErrorIssue; + return addIssue(error, "string", data, self.definition.errorMessage); }, string.overrideHandler); return self; } diff --git a/docs/public/libs/v1/dataParser/parsers/templateLiteral/index.cjs b/docs/public/libs/v1/dataParser/parsers/templateLiteral/index.cjs index 1259b1d65..b007049ff 100644 --- a/docs/public/libs/v1/dataParser/parsers/templateLiteral/index.cjs +++ b/docs/public/libs/v1/dataParser/parsers/templateLiteral/index.cjs @@ -18,11 +18,11 @@ function templateLiteral(template, definition) { checkers: definition?.checkers ?? [], template, pattern, - }, (data, _error, self) => { + }, (data, error$1, self) => { if (typeof data === "string" && self.definition.pattern.test(data)) { return data; } - return error.SymbolDataParserErrorIssue; + return error.addIssue(error$1, `string matching template literal pattern ${self.definition.pattern.source}`, data, self.definition.errorMessage); }, templateLiteral.overrideHandler); return self; } diff --git a/docs/public/libs/v1/dataParser/parsers/templateLiteral/index.mjs b/docs/public/libs/v1/dataParser/parsers/templateLiteral/index.mjs index 5acc677aa..d0dbbf741 100644 --- a/docs/public/libs/v1/dataParser/parsers/templateLiteral/index.mjs +++ b/docs/public/libs/v1/dataParser/parsers/templateLiteral/index.mjs @@ -1,5 +1,5 @@ import { dataParserInit } from '../../base.mjs'; -import { SymbolDataParserErrorIssue } from '../../error.mjs'; +import { addIssue } from '../../error.mjs'; import { createDataParserKind } from '../../kind.mjs'; import { createTemplateLiteralPattern } from './createTemplateLiteralPattern.mjs'; import { pipe } from '../../../common/pipe.mjs'; @@ -16,11 +16,11 @@ function templateLiteral(template, definition) { checkers: definition?.checkers ?? [], template, pattern, - }, (data, _error, self) => { + }, (data, error, self) => { if (typeof data === "string" && self.definition.pattern.test(data)) { return data; } - return SymbolDataParserErrorIssue; + return addIssue(error, `string matching template literal pattern ${self.definition.pattern.source}`, data, self.definition.errorMessage); }, templateLiteral.overrideHandler); return self; } diff --git a/docs/public/libs/v1/dataParser/parsers/time/checkers/max.cjs b/docs/public/libs/v1/dataParser/parsers/time/checkers/max.cjs index 10cd571c7..3b97bf6dc 100644 --- a/docs/public/libs/v1/dataParser/parsers/time/checkers/max.cjs +++ b/docs/public/libs/v1/dataParser/parsers/time/checkers/max.cjs @@ -15,7 +15,9 @@ function checkerTimeMax(max, definition = {}) { ...definition, max, }, - }, (value, self) => lessTime.lessTime(value, self.definition.max) ? value : error.SymbolDataParserErrorIssue); + }, (value, error$1, self) => lessTime.lessTime(value, self.definition.max) + ? value + : error.addIssue(error$1, `time <= ${self.definition.max.toString()}`, value, self.definition.errorMessage)); } exports.checkerTimeMax = checkerTimeMax; diff --git a/docs/public/libs/v1/dataParser/parsers/time/checkers/max.mjs b/docs/public/libs/v1/dataParser/parsers/time/checkers/max.mjs index b9fad9651..4b4416b74 100644 --- a/docs/public/libs/v1/dataParser/parsers/time/checkers/max.mjs +++ b/docs/public/libs/v1/dataParser/parsers/time/checkers/max.mjs @@ -1,5 +1,5 @@ import { dataParserCheckerInit } from '../../../base.mjs'; -import { SymbolDataParserErrorIssue } from '../../../error.mjs'; +import { addIssue } from '../../../error.mjs'; import { createDataParserKind } from '../../../kind.mjs'; import { lessTime } from '../../../../date/operators/lessTime.mjs'; @@ -13,7 +13,9 @@ function checkerTimeMax(max, definition = {}) { ...definition, max, }, - }, (value, self) => lessTime(value, self.definition.max) ? value : SymbolDataParserErrorIssue); + }, (value, error, self) => lessTime(value, self.definition.max) + ? value + : addIssue(error, `time <= ${self.definition.max.toString()}`, value, self.definition.errorMessage)); } export { checkerTimeMax, checkerTimeMaxKind }; diff --git a/docs/public/libs/v1/dataParser/parsers/time/checkers/min.cjs b/docs/public/libs/v1/dataParser/parsers/time/checkers/min.cjs index f750cf44e..3e548c472 100644 --- a/docs/public/libs/v1/dataParser/parsers/time/checkers/min.cjs +++ b/docs/public/libs/v1/dataParser/parsers/time/checkers/min.cjs @@ -15,7 +15,9 @@ function checkerTimeMin(min, definition = {}) { ...definition, min, }, - }, (value, self) => greaterTime.greaterTime(value, self.definition.min) ? value : error.SymbolDataParserErrorIssue); + }, (value, error$1, self) => greaterTime.greaterTime(value, self.definition.min) + ? value + : error.addIssue(error$1, `time >= ${self.definition.min.toString()}`, value, self.definition.errorMessage)); } exports.checkerTimeMin = checkerTimeMin; diff --git a/docs/public/libs/v1/dataParser/parsers/time/checkers/min.mjs b/docs/public/libs/v1/dataParser/parsers/time/checkers/min.mjs index 78660d7c7..71d0f7d20 100644 --- a/docs/public/libs/v1/dataParser/parsers/time/checkers/min.mjs +++ b/docs/public/libs/v1/dataParser/parsers/time/checkers/min.mjs @@ -1,5 +1,5 @@ import { dataParserCheckerInit } from '../../../base.mjs'; -import { SymbolDataParserErrorIssue } from '../../../error.mjs'; +import { addIssue } from '../../../error.mjs'; import { createDataParserKind } from '../../../kind.mjs'; import { greaterTime } from '../../../../date/operators/greaterTime.mjs'; @@ -13,7 +13,9 @@ function checkerTimeMin(min, definition = {}) { ...definition, min, }, - }, (value, self) => greaterTime(value, self.definition.min) ? value : SymbolDataParserErrorIssue); + }, (value, error, self) => greaterTime(value, self.definition.min) + ? value + : addIssue(error, `time >= ${self.definition.min.toString()}`, value, self.definition.errorMessage)); } export { checkerTimeMin, checkerTimeMinKind }; diff --git a/docs/public/libs/v1/dataParser/parsers/time/index.cjs b/docs/public/libs/v1/dataParser/parsers/time/index.cjs index 907927f66..890fcb436 100644 --- a/docs/public/libs/v1/dataParser/parsers/time/index.cjs +++ b/docs/public/libs/v1/dataParser/parsers/time/index.cjs @@ -22,12 +22,12 @@ function time(definition) { errorMessage: definition?.errorMessage, checkers: definition?.checkers ?? [], coerce: definition?.coerce ?? false, - }, (data, _error, self) => { + }, (data, error$1, self) => { if (self.definition.coerce) { if (typeof data === "string" && constants.isoTimeRegex.test(data)) { const result = createTime.createTime({ value: data }); if (is.isLeft(result)) { - return error.SymbolDataParserErrorIssue; + return error.addIssue(error$1, "time", data, self.definition.errorMessage); } return unwrap.unwrap(result); } @@ -40,11 +40,11 @@ function time(definition) { } else if (typeof data === "number") { if (!isSafeTimeValue.isSafeTimeValue(data)) { - return error.SymbolDataParserErrorIssue; + return error.addIssue(error$1, "time", data, self.definition.errorMessage); } return theTime.TheTime.new(data); } - return error.SymbolDataParserErrorIssue; + return error.addIssue(error$1, "time", data, self.definition.errorMessage); }, time.overrideHandler); return self; } diff --git a/docs/public/libs/v1/dataParser/parsers/time/index.mjs b/docs/public/libs/v1/dataParser/parsers/time/index.mjs index 0fb7f3c73..aeca36525 100644 --- a/docs/public/libs/v1/dataParser/parsers/time/index.mjs +++ b/docs/public/libs/v1/dataParser/parsers/time/index.mjs @@ -1,5 +1,5 @@ import { dataParserInit } from '../../base.mjs'; -import { SymbolDataParserErrorIssue } from '../../error.mjs'; +import { addIssue } from '../../error.mjs'; import { createDataParserKind } from '../../kind.mjs'; import { isoTimeRegex } from '../../../date/constants.mjs'; import { createTime } from '../../../date/createTime.mjs'; @@ -20,12 +20,12 @@ function time(definition) { errorMessage: definition?.errorMessage, checkers: definition?.checkers ?? [], coerce: definition?.coerce ?? false, - }, (data, _error, self) => { + }, (data, error, self) => { if (self.definition.coerce) { if (typeof data === "string" && isoTimeRegex.test(data)) { const result = createTime({ value: data }); if (isLeft(result)) { - return SymbolDataParserErrorIssue; + return addIssue(error, "time", data, self.definition.errorMessage); } return unwrap(result); } @@ -38,11 +38,11 @@ function time(definition) { } else if (typeof data === "number") { if (!isSafeTimeValue(data)) { - return SymbolDataParserErrorIssue; + return addIssue(error, "time", data, self.definition.errorMessage); } return TheTime.new(data); } - return SymbolDataParserErrorIssue; + return addIssue(error, "time", data, self.definition.errorMessage); }, time.overrideHandler); return self; } diff --git a/docs/public/libs/v1/dataParser/parsers/transform.cjs b/docs/public/libs/v1/dataParser/parsers/transform.cjs index f52d6be04..454c65f4f 100644 --- a/docs/public/libs/v1/dataParser/parsers/transform.cjs +++ b/docs/public/libs/v1/dataParser/parsers/transform.cjs @@ -18,23 +18,23 @@ function transform(inner, theFunction, definition) { }, { sync: (data, error$1, self) => { const innerResult = self.definition.inner.exec(data, error$1); - if (innerResult === base.SymbolDataParserError) { - return base.SymbolDataParserError; + if (innerResult === error.SymbolDataParserError) { + return error.SymbolDataParserError; } const result = self.definition.theFunction(innerResult, error$1); if (result instanceof Promise) { - return error.SymbolDataParserErrorPromiseIssue; + return error.addIssue(error$1, "non-promise transform result", result, self.definition.errorMessage); } return result; }, async: async (data, error$1, self) => { const innerResult = await self.definition.inner.asyncExec(data, error$1); - if (innerResult === base.SymbolDataParserError) { - return base.SymbolDataParserError; + if (innerResult === error.SymbolDataParserError) { + return error.SymbolDataParserError; } let result = self.definition.theFunction(innerResult, error$1); if (result instanceof Promise) { - result = result.catch(() => error.SymbolDataParserErrorPromiseIssue); + result = await result.catch(() => error.addIssue(error$1, "successful async transform result", result, self.definition.errorMessage)); } return result; }, diff --git a/docs/public/libs/v1/dataParser/parsers/transform.d.ts b/docs/public/libs/v1/dataParser/parsers/transform.d.ts index a2879c24d..ade19f2ed 100644 --- a/docs/public/libs/v1/dataParser/parsers/transform.d.ts +++ b/docs/public/libs/v1/dataParser/parsers/transform.d.ts @@ -1,7 +1,7 @@ import { type FixDeepFunctionInfer, type Kind, type NeverCoalescing } from "../../common"; import { type DataParserDefinition, type DataParser, type Input, type Output, SymbolDataParserError, type DataParserChecker } from "../base"; import { type AddCheckersToDefinition, type MergeDefinition } from "../../dataParser/types"; -import { type DataParserError, type SymbolDataParserErrorIssue, SymbolDataParserErrorPromiseIssue } from "../../dataParser/error"; +import { type DataParserError } from "../../dataParser/error"; import { type CheckerRefineImplementation } from "./refine"; import { type GetPropsWithValueExtends } from "../../object"; export interface DataParserTransformCheckerCustom { @@ -12,7 +12,7 @@ export interface DataParserDefinitionTransform extends DataParserDefinition>; -export type DataParserTransformOutput = Exclude>, SymbolDataParserError | SymbolDataParserErrorIssue | SymbolDataParserErrorPromiseIssue>; +export type DataParserTransformOutput = Exclude>, SymbolDataParserError>; type _DataParserTransform = (DataParser, Input> & Kind); export interface DataParserTransform extends _DataParserTransform { addChecker SymbolDataParserErrorPromiseIssue); + result = await result.catch(() => addIssue(error, "successful async transform result", result, self.definition.errorMessage)); } return result; }, diff --git a/docs/public/libs/v1/dataParser/parsers/tuple.cjs b/docs/public/libs/v1/dataParser/parsers/tuple.cjs index be830fb86..376aac23e 100644 --- a/docs/public/libs/v1/dataParser/parsers/tuple.cjs +++ b/docs/public/libs/v1/dataParser/parsers/tuple.cjs @@ -19,17 +19,17 @@ function tuple(shape, definition) { }, { sync: (data, error$1, self) => { if (!(data instanceof Array)) { - return error.SymbolDataParserErrorIssue; + return error.addIssue(error$1, "tuple array", data, self.definition.errorMessage); } let output = []; const currentIndexPath = error$1.currentPath.length; for (let index = 0; index < self.definition.shape.length; index++) { error.setErrorPath(error$1, `[${index}]`, currentIndexPath); const result = self.definition.shape[index]?.exec(data[index], error$1); - if (result === base.SymbolDataParserError) { - output = base.SymbolDataParserError; + if (result === error.SymbolDataParserError) { + output = error.SymbolDataParserError; } - else if (output !== base.SymbolDataParserError) { + else if (output !== error.SymbolDataParserError) { output.push(result); } } @@ -37,10 +37,10 @@ function tuple(shape, definition) { for (let index = self.definition.shape.length; index < data.length; index++) { error.setErrorPath(error$1, `[${index}]`, currentIndexPath); const result = self.definition.rest.exec(data[index], error$1); - if (result === base.SymbolDataParserError) { - output = base.SymbolDataParserError; + if (result === error.SymbolDataParserError) { + output = error.SymbolDataParserError; } - else if (output !== base.SymbolDataParserError) { + else if (output !== error.SymbolDataParserError) { output.push(result); } } @@ -50,17 +50,17 @@ function tuple(shape, definition) { }, async: async (data, error$1, self) => { if (!(data instanceof Array)) { - return error.SymbolDataParserErrorIssue; + return error.addIssue(error$1, "tuple array", data, self.definition.errorMessage); } let output = []; const currentIndexPath = error$1.currentPath.length; for (let index = 0; index < self.definition.shape.length; index++) { error.setErrorPath(error$1, `[${index}]`, currentIndexPath); const result = await self.definition.shape[index]?.asyncExec(data[index], error$1); - if (result === base.SymbolDataParserError) { - output = base.SymbolDataParserError; + if (result === error.SymbolDataParserError) { + output = error.SymbolDataParserError; } - else if (output !== base.SymbolDataParserError) { + else if (output !== error.SymbolDataParserError) { output.push(result); } } @@ -68,10 +68,10 @@ function tuple(shape, definition) { for (let index = self.definition.shape.length; index < data.length; index++) { error.setErrorPath(error$1, `[${index}]`, currentIndexPath); const result = await self.definition.rest.asyncExec(data[index], error$1); - if (result === base.SymbolDataParserError) { - output = base.SymbolDataParserError; + if (result === error.SymbolDataParserError) { + output = error.SymbolDataParserError; } - else if (output !== base.SymbolDataParserError) { + else if (output !== error.SymbolDataParserError) { output.push(result); } } diff --git a/docs/public/libs/v1/dataParser/parsers/tuple.mjs b/docs/public/libs/v1/dataParser/parsers/tuple.mjs index 57d924f24..356fd3886 100644 --- a/docs/public/libs/v1/dataParser/parsers/tuple.mjs +++ b/docs/public/libs/v1/dataParser/parsers/tuple.mjs @@ -1,5 +1,5 @@ -import { dataParserInit, SymbolDataParserError } from '../base.mjs'; -import { SymbolDataParserErrorIssue, setErrorPath, popErrorPath } from '../error.mjs'; +import { dataParserInit } from '../base.mjs'; +import { addIssue, setErrorPath, SymbolDataParserError, popErrorPath } from '../error.mjs'; import { createDataParserKind } from '../kind.mjs'; import { some } from '../../array/some.mjs'; import { createOverride } from '../../common/override.mjs'; @@ -17,7 +17,7 @@ function tuple(shape, definition) { }, { sync: (data, error, self) => { if (!(data instanceof Array)) { - return SymbolDataParserErrorIssue; + return addIssue(error, "tuple array", data, self.definition.errorMessage); } let output = []; const currentIndexPath = error.currentPath.length; @@ -48,7 +48,7 @@ function tuple(shape, definition) { }, async: async (data, error, self) => { if (!(data instanceof Array)) { - return SymbolDataParserErrorIssue; + return addIssue(error, "tuple array", data, self.definition.errorMessage); } let output = []; const currentIndexPath = error.currentPath.length; diff --git a/docs/public/libs/v1/dataParser/parsers/union.cjs b/docs/public/libs/v1/dataParser/parsers/union.cjs index 2b2a76a5c..bd5b394e4 100644 --- a/docs/public/libs/v1/dataParser/parsers/union.cjs +++ b/docs/public/libs/v1/dataParser/parsers/union.cjs @@ -17,22 +17,40 @@ function union(options, definition) { options, }, { sync: (data, error$1, self) => { - for (const dataParser of self.definition.options) { - const result = dataParser.exec(data, error$1); - if (result !== base.SymbolDataParserError) { + const unionError = { + ...error$1, + currentPath: [...error$1.currentPath], + issues: [], + }; + const currentIndexPath = unionError.currentPath.length; + for (let index = 0; index < self.definition.options.length; index++) { + error.setErrorPath(unionError, `(option ${index})`, currentIndexPath); + const dataParser = self.definition.options[index]; + const result = dataParser.exec(data, unionError); + if (result !== error.SymbolDataParserError) { return result; } } - return error.SymbolDataParserErrorIssue; + error$1.issues.push(...unionError.issues); + return error.addIssue(error$1, "respect at least one union value", data, self.definition.errorMessage); }, async: async (data, error$1, self) => { - for (const dataParser of self.definition.options) { - const result = await dataParser.asyncExec(data, error$1); - if (result !== base.SymbolDataParserError) { + const unionError = { + ...error$1, + currentPath: [...error$1.currentPath], + issues: [], + }; + const currentIndexPath = unionError.currentPath.length; + for (let index = 0; index < self.definition.options.length; index++) { + error.setErrorPath(unionError, `(option ${index})`, currentIndexPath); + const dataParser = self.definition.options[index]; + const result = await dataParser.asyncExec(data, unionError); + if (result !== error.SymbolDataParserError) { return result; } } - return error.SymbolDataParserErrorIssue; + error$1.issues.push(...unionError.issues); + return error.addIssue(error$1, "respect at least one union value", data, self.definition.errorMessage); }, isAsynchronous: (self) => some.some(self.definition.options, (element) => element.isAsynchronous()), }, union.overrideHandler); diff --git a/docs/public/libs/v1/dataParser/parsers/union.mjs b/docs/public/libs/v1/dataParser/parsers/union.mjs index eb89ed739..b426c4e5d 100644 --- a/docs/public/libs/v1/dataParser/parsers/union.mjs +++ b/docs/public/libs/v1/dataParser/parsers/union.mjs @@ -1,5 +1,5 @@ -import { dataParserInit, SymbolDataParserError } from '../base.mjs'; -import { SymbolDataParserErrorIssue } from '../error.mjs'; +import { dataParserInit } from '../base.mjs'; +import { setErrorPath, SymbolDataParserError, addIssue } from '../error.mjs'; import { createDataParserKind } from '../kind.mjs'; import { some } from '../../array/some.mjs'; import { createOverride } from '../../common/override.mjs'; @@ -15,22 +15,40 @@ function union(options, definition) { options, }, { sync: (data, error, self) => { - for (const dataParser of self.definition.options) { - const result = dataParser.exec(data, error); + const unionError = { + ...error, + currentPath: [...error.currentPath], + issues: [], + }; + const currentIndexPath = unionError.currentPath.length; + for (let index = 0; index < self.definition.options.length; index++) { + setErrorPath(unionError, `(option ${index})`, currentIndexPath); + const dataParser = self.definition.options[index]; + const result = dataParser.exec(data, unionError); if (result !== SymbolDataParserError) { return result; } } - return SymbolDataParserErrorIssue; + error.issues.push(...unionError.issues); + return addIssue(error, "respect at least one union value", data, self.definition.errorMessage); }, async: async (data, error, self) => { - for (const dataParser of self.definition.options) { - const result = await dataParser.asyncExec(data, error); + const unionError = { + ...error, + currentPath: [...error.currentPath], + issues: [], + }; + const currentIndexPath = unionError.currentPath.length; + for (let index = 0; index < self.definition.options.length; index++) { + setErrorPath(unionError, `(option ${index})`, currentIndexPath); + const dataParser = self.definition.options[index]; + const result = await dataParser.asyncExec(data, unionError); if (result !== SymbolDataParserError) { return result; } } - return SymbolDataParserErrorIssue; + error.issues.push(...unionError.issues); + return addIssue(error, "respect at least one union value", data, self.definition.errorMessage); }, isAsynchronous: (self) => some(self.definition.options, (element) => element.isAsynchronous()), }, union.overrideHandler); diff --git a/docs/public/libs/v1/index.cjs b/docs/public/libs/v1/index.cjs index 28debf3ce..e0ebc73fb 100644 --- a/docs/public/libs/v1/index.cjs +++ b/docs/public/libs/v1/index.cjs @@ -69,6 +69,7 @@ var toRegExp = require('./common/toRegExp.cjs'); var justExec = require('./common/justExec.cjs'); var callThen = require('./common/callThen.cjs'); var queue = require('./common/queue.cjs'); +var printer = require('./common/printer.cjs'); @@ -176,3 +177,7 @@ exports.justExec = justExec.justExec; exports.callThen = callThen.callThen; exports.createQueue = queue.createQueue; exports.queueKind = queue.queueKind; +Object.defineProperty(exports, "Printer", { + enumerable: true, + get: function () { return printer.Printer; } +}); diff --git a/docs/public/libs/v1/index.mjs b/docs/public/libs/v1/index.mjs index 8cbfe3b30..d1c1aa505 100644 --- a/docs/public/libs/v1/index.mjs +++ b/docs/public/libs/v1/index.mjs @@ -93,3 +93,4 @@ export { toRegExp } from './common/toRegExp.mjs'; export { justExec } from './common/justExec.mjs'; export { callThen } from './common/callThen.mjs'; export { createQueue, queueKind } from './common/queue.mjs'; +export { Printer } from './common/printer.mjs'; diff --git a/docs/public/libs/v1/metadata.json b/docs/public/libs/v1/metadata.json index aa1b5f2df..d287ecae1 100644 --- a/docs/public/libs/v1/metadata.json +++ b/docs/public/libs/v1/metadata.json @@ -645,6 +645,15 @@ { "name": "base.mjs" }, + { + "name": "cast.cjs" + }, + { + "name": "cast.d.ts" + }, + { + "name": "cast.mjs" + }, { "name": "index.d.ts" }, @@ -1038,6 +1047,15 @@ { "name": "repository.mjs" }, + { + "name": "toMapDataParser.cjs" + }, + { + "name": "toMapDataParser.d.ts" + }, + { + "name": "toMapDataParser.mjs" + }, { "name": "useCase.cjs" }, @@ -1561,6 +1579,15 @@ { "name": "pipeCall.mjs" }, + { + "name": "printer.cjs" + }, + { + "name": "printer.d.ts" + }, + { + "name": "printer.mjs" + }, { "name": "promiseObject.cjs" }, diff --git a/docs/public/libs/v1/number/types/isGreater.d.ts b/docs/public/libs/v1/number/types/isGreater.d.ts index ab235146a..3f6fb5c81 100644 --- a/docs/public/libs/v1/number/types/isGreater.d.ts +++ b/docs/public/libs/v1/number/types/isGreater.d.ts @@ -25,10 +25,33 @@ type CheckIsGreater, GreaterTa infer InferredRestSplitValue extends AnyTuple, infer InferredRestSplitReference extends AnyTuple ] ? CheckIsGreater : never : false; -export type IsGreater = IsEqual extends true ? true : [ - `${GenericValue}`, - `${GenericReference}` +type toStringDecimal = `${GenericValue}` extends `${DString.Number}.${DString.Number}` ? `${GenericValue}` : `${GenericValue}.0`; +type PrepareValues = [ + toStringDecimal, + toStringDecimal ] extends [ + `${infer InferredValueInteger extends DString.Number}.${infer InferredValueDecimals extends DString.Number}`, + `${infer InferredReferenceInteger extends DString.Number}.${infer InferredReferenceDecimals extends DString.Number}` +] ? And<[ + IsEqual, + IsEqual +]> extends true ? [InferredValueInteger, InferredReferenceInteger] : IsEqual extends true ? [ + DString.Split, + DString.Split +] extends [ + infer InferredSplitValue extends AnyTuple, + infer InferredSplitReference extends AnyTuple +] ? (IsEqual extends true ? [ + DArray.JoinTuple, + DArray.JoinTuple +] : (DArray.CreateTuple extends [...DArray.CreateTuple, ...any[]] ? InferredSplitValue["length"] : InferredSplitReference["length"]) extends infer InferredLength extends number ? [ + DArray.JoinTuple extends true ? InferredSplitValue : DArray.CreateTuple<"0", InferredLength, InferredSplitValue>, AnyTuple>, "">, + DArray.JoinTuple extends true ? InferredSplitReference : DArray.CreateTuple<"0", InferredLength, InferredSplitReference>, AnyTuple>, ""> +] : never) extends [ + `${infer InferredResultValue}`, + `${infer InferredResultReference}` +] ? [`${InferredResultValue}`, `${InferredResultReference}`] : never : never : [InferredValueInteger, InferredReferenceInteger] : never; +export type IsGreater = IsEqual extends true ? true : PrepareValues extends [ infer InferredValue extends DString.Number, infer InferredReference extends DString.Number ] ? And<[ diff --git a/jsDoc/clean/PositiveInt/example.ts b/jsDoc/clean/PositiveInt/example.ts deleted file mode 100644 index 35b27f831..000000000 --- a/jsDoc/clean/PositiveInt/example.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { C, E } from "@scripts"; - -const result = C.PositiveInt.create(4); - -if (E.isRight(result)) { - // result: E.Right<"createConstrainedType", C.ConstrainedType<"positive-int", 4>> -} - -const value = C.PositiveInt.createOrThrow(10); -// value: C.ConstrainedType<"positive-int", 10> - -C.PositiveInt.is(value); // type guard diff --git a/jsDoc/clean/PositiveInt/index.md b/jsDoc/clean/PositiveInt/index.md deleted file mode 100644 index 387adcd9b..000000000 --- a/jsDoc/clean/PositiveInt/index.md +++ /dev/null @@ -1,14 +0,0 @@ -Constraint handler that validates strictly positive integers (>= 1). - -**Supported call styles:** -- Classic: `PositiveInt.create(value)` -> returns Either - -Use it as a reusable rule to validate inputs and to constrain NewTypes to positive integer numbers. - -```ts -{@include clean/PositiveInt/example.ts[3,13]} -``` - -@see https://utils.duplojs.dev/en/v1/api/clean/constraints - -@namespace C diff --git a/jsDoc/clean/castConstraint/example.ts b/jsDoc/clean/castConstraint/example.ts new file mode 100644 index 000000000..49b69d1b6 --- /dev/null +++ b/jsDoc/clean/castConstraint/example.ts @@ -0,0 +1,19 @@ +import { C } from "@scripts"; + +const baseMin = C.NumberMin(5).createOrThrow(7); +const widenedMin = C.castConstraint(baseMin, C.NumberMin(3)); +// widenedMin: ConstrainedType<"number-min-5", 7> & ConstrainedType<"number-min-3", number> + +const baseMax = C.NumberMax(5).createOrThrow(-2); +const widenedMax = C.castConstraint( + baseMax, + [ + C.NumberMax(8), + C.NumberMax(10), + ], +); +// widenedMax has "number-max-5", "number-max-8", "number-max-10" + +const positive = C.Positive.createOrThrow(2); +const relaxed = C.castConstraint(positive, C.NumberMin(-5)); +// relaxed keeps the same value and can be used where "number-min--5" is required diff --git a/jsDoc/clean/castConstraint/index.md b/jsDoc/clean/castConstraint/index.md new file mode 100644 index 000000000..e2d8d9aff --- /dev/null +++ b/jsDoc/clean/castConstraint/index.md @@ -0,0 +1,18 @@ +Adds compatible constraint markers to an already constrained value without re-validating it. + +**Supported call styles:** +- Classic: `castConstraint(value, handler)` -> returns a value with added constraints (supports handler arrays) + +It returns a new constrained value that carries the same wrapped value and the additional constraint markers. TypeScript prevents invalid casts. + +```ts +{@include clean/castConstraint/example.ts[3,19]} +``` + +@remarks +- The function does not run constraint checkers at runtime. +- Use it to widen constraints you already know are compatible. + +@see https://utils.duplojs.dev/en/v1/api/clean/castConstraint + +@namespace C diff --git a/jsDoc/clean/createConstraint/constraintKindValue.md b/jsDoc/clean/createConstraint/constraintKindValue.md new file mode 100644 index 000000000..e47d5c294 --- /dev/null +++ b/jsDoc/clean/createConstraint/constraintKindValue.md @@ -0,0 +1 @@ +The constraint kind metadata used to tag constrained values. diff --git a/jsDoc/clean/createConstraint/dataParser.md b/jsDoc/clean/createConstraint/dataParser.md new file mode 100644 index 000000000..07b94e16c --- /dev/null +++ b/jsDoc/clean/createConstraint/dataParser.md @@ -0,0 +1 @@ +The DataParser with the constraint checkers applied. diff --git a/jsDoc/clean/createConstraintsSet/constraintKindValue.md b/jsDoc/clean/createConstraintsSet/constraintKindValue.md new file mode 100644 index 000000000..43367b49a --- /dev/null +++ b/jsDoc/clean/createConstraintsSet/constraintKindValue.md @@ -0,0 +1 @@ +The constraint kind metadata applied by the set. diff --git a/jsDoc/clean/createConstraintsSet/dataParser.md b/jsDoc/clean/createConstraintsSet/dataParser.md new file mode 100644 index 000000000..b652109e3 --- /dev/null +++ b/jsDoc/clean/createConstraintsSet/dataParser.md @@ -0,0 +1 @@ +The DataParser with all constraint checkers from the set applied. diff --git a/jsDoc/clean/createEntity/mapDataParser.md b/jsDoc/clean/createEntity/mapDataParser.md new file mode 100644 index 000000000..891c03601 --- /dev/null +++ b/jsDoc/clean/createEntity/mapDataParser.md @@ -0,0 +1 @@ +The DataParser used internally to map raw properties into an entity. diff --git a/jsDoc/clean/createNewType/constraintKindValue.md b/jsDoc/clean/createNewType/constraintKindValue.md new file mode 100644 index 000000000..90734f6df --- /dev/null +++ b/jsDoc/clean/createNewType/constraintKindValue.md @@ -0,0 +1 @@ +The constraint kind metadata applied to this NewType. diff --git a/jsDoc/clean/toMapDataParser/example.ts b/jsDoc/clean/toMapDataParser/example.ts new file mode 100644 index 000000000..1695d9a83 --- /dev/null +++ b/jsDoc/clean/toMapDataParser/example.ts @@ -0,0 +1,22 @@ +import { C, DP, pipe } from "@scripts"; + +const ShortLabel = C.createNewType( + "ShortLabel", + DP.string(), + [C.StringMax(5)], +); + +const labelParser = C.toMapDataParser(ShortLabel); +labelParser.parseOrThrow("hello"); + +const userIdParser = pipe( + C.Number, + C.toMapDataParser, +); +userIdParser.parseOrThrow(42); + +const coerceParser = C.toMapDataParser( + C.String, + { coerce: true }, +); +coerceParser.parseOrThrow(123); diff --git a/jsDoc/clean/toMapDataParser/index.md b/jsDoc/clean/toMapDataParser/index.md new file mode 100644 index 000000000..6a4bc9926 --- /dev/null +++ b/jsDoc/clean/toMapDataParser/index.md @@ -0,0 +1,19 @@ +Creates a DataParser that maps Clean handlers or primitives into a wrapped value object. + +**Supported call styles:** +- Classic: `toMapDataParser(handler, params?)` -> returns a DataParser +- Pipe: `pipe(handler, toMapDataParser)` -> returns a DataParser + +The resulting parser preserves kind tags (`newTypeKind`, `constrainedTypeKind`) and stores the parsed value under the wrapped value key. When `coerce` is enabled, compatible primitive parsers will coerce inputs before validation. + +```ts +{@include clean/toMapDataParser/example.ts[3,30]} +``` + +@remarks +- Supported inputs: `NewTypeHandler`, `ConstraintHandler`, `ConstraintsSetHandler`, and `PrimitiveHandler`. +- Use `coerce: true` to allow conversions (e.g. number to string) on compatible parsers. + +@see https://utils.duplojs.dev/en/v1/api/clean/toMapDataParser + +@namespace C diff --git a/jsDoc/common/printer/bold/example.ts b/jsDoc/common/printer/bold/example.ts new file mode 100644 index 000000000..7d741265e --- /dev/null +++ b/jsDoc/common/printer/bold/example.ts @@ -0,0 +1,10 @@ +import { Printer } from "@scripts"; + +const title = Printer.bold("Build report"); +// title: "\x1b[1mBuild report\x1b[0m" + +const symbol = Printer.bold("!"); +// symbol: "\x1b[1m!\x1b[0m" + +const empty = Printer.bold(""); +// empty: "\x1b[1m\x1b[0m" diff --git a/jsDoc/common/printer/bold/index.md b/jsDoc/common/printer/bold/index.md new file mode 100644 index 000000000..d9baa2891 --- /dev/null +++ b/jsDoc/common/printer/bold/index.md @@ -0,0 +1,11 @@ +Wraps a string with the ANSI escape sequence for bold text. + +Signature: `Printer.bold(input)` -> returns the bold string + +The function prepends the bold code and appends the reset code without altering the input content. + +```ts +{@include common/printer/bold/example.ts[3,11]} +``` + +@see https://utils.duplojs.dev/en/v1/api/common/printer/bold diff --git a/jsDoc/common/printer/colorized/example.ts b/jsDoc/common/printer/colorized/example.ts new file mode 100644 index 000000000..30647637d --- /dev/null +++ b/jsDoc/common/printer/colorized/example.ts @@ -0,0 +1,13 @@ +import { pipe, Printer } from "@scripts"; + +const directResult = Printer.colorized("Hello", "green"); +// directResult: "\x1b[32mHello\x1b[0m" + +const pipedResult = pipe( + "Warning", + Printer.colorized("yellow"), +); +// pipedResult: "\x1b[33mWarning\x1b[0m" + +const errorResult = Printer.colorized("Error", "red"); +// errorResult: "\x1b[31mError\x1b[0m" diff --git a/jsDoc/common/printer/colorized/index.md b/jsDoc/common/printer/colorized/index.md new file mode 100644 index 000000000..2aee4be99 --- /dev/null +++ b/jsDoc/common/printer/colorized/index.md @@ -0,0 +1,13 @@ +Wraps a string with the ANSI escape sequence of the selected color. Exists in immediate or curried form. + +**Supported call styles:** +- Classic: `Printer.colorized(input, color)` -> returns the colored string +- Curried: `Printer.colorized(color)` -> returns a function waiting for the string + +The function only adds the opening color code and the reset code around the input string. + +```ts +{@include common/printer/colorized/example.ts[3,14]} +``` + +@see https://utils.duplojs.dev/en/v1/api/common/printer/colorized diff --git a/jsDoc/common/printer/colorizedBold/example.ts b/jsDoc/common/printer/colorizedBold/example.ts new file mode 100644 index 000000000..bbc7549ab --- /dev/null +++ b/jsDoc/common/printer/colorizedBold/example.ts @@ -0,0 +1,13 @@ +import { pipe, Printer } from "@scripts"; + +const directResult = Printer.colorizedBold("Fatal", "red"); +// directResult: "\x1b[1m\x1b[31mFatal\x1b[0m\x1b[0m" + +const pipedResult = pipe( + "Info", + Printer.colorizedBold("cyan"), +); +// pipedResult: "\x1b[1m\x1b[36mInfo\x1b[0m\x1b[0m" + +const successResult = Printer.colorizedBold("Done", "green"); +// successResult: "\x1b[1m\x1b[32mDone\x1b[0m\x1b[0m" diff --git a/jsDoc/common/printer/colorizedBold/index.md b/jsDoc/common/printer/colorizedBold/index.md new file mode 100644 index 000000000..5dd50205c --- /dev/null +++ b/jsDoc/common/printer/colorizedBold/index.md @@ -0,0 +1,13 @@ +Applies a color and bold formatting to a string by combining `Printer.colorized()` and `Printer.bold()`. Exists in immediate or curried form. + +**Supported call styles:** +- Classic: `Printer.colorizedBold(input, color)` -> returns the formatted string +- Curried: `Printer.colorizedBold(color)` -> returns a function waiting for the string + +The produced string contains the bold ANSI code, then the colorized content, and finally the reset codes. + +```ts +{@include common/printer/colorizedBold/example.ts[3,14]} +``` + +@see https://utils.duplojs.dev/en/v1/api/common/printer/colorizedBold diff --git a/jsDoc/common/printer/render/example.ts b/jsDoc/common/printer/render/example.ts new file mode 100644 index 000000000..007e9ddba --- /dev/null +++ b/jsDoc/common/printer/render/example.ts @@ -0,0 +1,20 @@ +import { pipe, Printer } from "@scripts"; + +const customResult = Printer.render( + ["alpha", ["beta", false], true, undefined], + " | ", +); +// customResult: "alpha | beta | true" + +const lineResult = Printer.renderLine([ + "hello", + ["world", null], + true, +]); +// lineResult: "hello world true" + +const paragraphResult = pipe( + ["title", ["", "body"], false, true] as const, + Printer.renderParagraph, +); +// paragraphResult: "title\n\nbody\ntrue" diff --git a/jsDoc/common/printer/render/index.md b/jsDoc/common/printer/render/index.md new file mode 100644 index 000000000..7cdb7230d --- /dev/null +++ b/jsDoc/common/printer/render/index.md @@ -0,0 +1,14 @@ +Flattens printable values, keeps strings and `true`, then joins the result with a custom separator. Exists in immediate or curried form. + +**Supported call styles:** +- Classic: `Printer.render(values, joinCharacter)` -> returns the rendered string +- Curried: `Printer.render(joinCharacter)` -> returns a function waiting for the values array + +Nested arrays are flattened recursively. `false`, `null`, and `undefined` are ignored, while `true` is kept as the string `"true"`. +The namespace also exposes two ready-to-use defaults: `Printer.renderLine`, which joins with a space, and `Printer.renderParagraph`, which joins with `Printer.back`. + +```ts +{@include common/printer/render/example.ts[3,21]} +``` + +@see https://utils.duplojs.dev/en/v1/api/common/printer/render diff --git a/scripts/array/types/createTuple.ts b/scripts/array/types/createTuple.ts index abc1821e5..9eaf1535f 100644 --- a/scripts/array/types/createTuple.ts +++ b/scripts/array/types/createTuple.ts @@ -3,7 +3,7 @@ import { type IsEqual } from "../../common/types/isEqual"; export type CreateTuple< GenericValue extends unknown, GenericLength extends number, - GenericLastTuple extends unknown[] = [], + GenericLastTuple extends readonly unknown[] = [], > = IsEqual extends true ? GenericValue[] : IsEqual extends true diff --git a/scripts/clean/constraint/base.ts b/scripts/clean/constraint/base.ts index 3527655d5..2d29203d5 100644 --- a/scripts/clean/constraint/base.ts +++ b/scripts/clean/constraint/base.ts @@ -11,8 +11,8 @@ export const constrainedTypeKind = createCleanKind< >("constrained-type"); export interface ConstrainedType< - GenericName extends string, - GenericValue extends unknown, + GenericName extends string = string, + GenericValue extends unknown = unknown, > extends Kind< typeof constrainedTypeKind.definition, Record @@ -36,15 +36,38 @@ export interface ConstraintHandler< readonly name: GenericName; /** - * {@include clean/createConstraint/checkers.md} + * @deprecated */ readonly checkers: GenericCheckers; /** - * {@include clean/createConstraint/primitiveHandler.md} + * @deprecated */ readonly primitiveHandler: PrimitiveHandler; + readonly internal: { + + /** + * {@include clean/createConstraint/dataParser.md} + */ + readonly dataParser: DDataParser.Contract; + + /** + * {@include clean/createConstraint/primitiveHandler.md} + */ + readonly primitiveHandler: PrimitiveHandler; + + /** + * {@include clean/createConstraint/checkers.md} + */ + readonly checkers: GenericCheckers; + + /** + * {@include clean/createConstraint/constraintKindValue.md} + */ + readonly constraintKindValue: Record; + }; + /** * {@include clean/createConstraint/create.md} */ @@ -206,6 +229,8 @@ export function createConstraint< .dataParser .addChecker(...checkers as never); + const constraintKindValue = { [name]: null }; + function create(data: any) { const result = dataParserWithCheckers.parse(unwrap(data)); @@ -262,6 +287,12 @@ export function createConstraint< name, primitiveHandler, checkers, + internal: { + primitiveHandler, + dataParser: dataParserWithCheckers, + checkers, + constraintKindValue, + }, create, createOrThrow, createWithUnknown: create, @@ -277,8 +308,8 @@ createConstraint.overrideHandler = createOverride("@duplojs/u export type GetConstraint< GenericConstrainHandler extends ConstraintHandler, - GenericValue extends DDataParser.InputChecker - = DDataParser.InputChecker, + GenericValue extends DDataParser.InputChecker + = DDataParser.InputChecker, > = Extract< ConstrainedType< GenericConstrainHandler["name"], diff --git a/scripts/clean/constraint/cast.ts b/scripts/clean/constraint/cast.ts new file mode 100644 index 000000000..ae443553f --- /dev/null +++ b/scripts/clean/constraint/cast.ts @@ -0,0 +1,153 @@ +/* eslint-disable @typescript-eslint/prefer-for-of */ +import { type UnionToIntersection, type SimplifyTopLevel, type NeverCoalescing, type And, type Not, type IsEqual } from "@scripts/common"; +import { type ConstraintHandler, type ConstrainedType, type GetConstraint, constrainedTypeKind } from "./base"; +import { type Negative, type NumberMaxHandlerInternal, type NumberMaxInternal, type NumberMinHandlerInternal, type NumberMinInternal, type Positive, type StringMaxHandlerInternal, type StringMaxInternal, type StringMinHandlerInternal, type StringMinInternal } from "./defaultConstraint"; +import { type IsLess, type IsGreater } from "@scripts/number"; +import * as DArray from "@scripts/array"; + +declare const SymbolCastErrorMessage: unique symbol; + +type CastConstraintError< + GenericConstrainHandler extends ConstraintHandler, + GenericReason extends string, +> = SimplifyTopLevel<{ + [SymbolCastErrorMessage]: `The constraint "${GenericConstrainHandler["name"]}" is not applicable: ${GenericReason}.`; +}>; + +type ForbiddenBadCast< + GenericConstrainedType extends ConstrainedType, + GenericConstrainHandler extends ConstraintHandler, +> = ( + | ( + GenericConstrainHandler extends NumberMinHandlerInternal + ? GenericConstrainedType extends Positive + ? IsLess extends true + ? never + : CastConstraintError + : GenericConstrainedType extends NumberMinInternal + ? And<[ + IsLess, + Not>, + ]> extends true + ? never + : CastConstraintError + : CastConstraintError + : never + ) + | ( + GenericConstrainHandler extends NumberMaxHandlerInternal + ? GenericConstrainedType extends Negative + ? IsGreater extends true + ? never + : CastConstraintError + : GenericConstrainedType extends NumberMaxInternal + ? And<[ + IsGreater, + Not>, + ]> extends true + ? never + : CastConstraintError + : CastConstraintError + : never + ) + | ( + GenericConstrainHandler extends StringMinHandlerInternal + ? GenericConstrainedType extends StringMinInternal + ? And<[ + IsLess, + Not>, + ]> extends true + ? never + : CastConstraintError + : CastConstraintError + : never + ) + | ( + GenericConstrainHandler extends StringMaxHandlerInternal + ? GenericConstrainedType extends StringMaxInternal + ? And<[ + IsGreater, + Not>, + ]> extends true + ? never + : CastConstraintError + : CastConstraintError + : never + ) + | ( + GenericConstrainHandler extends typeof Positive + ? GenericConstrainedType extends NumberMinInternal + ? And<[ + IsLess<0, InferredReferenceValue>, + Not>, + ]> extends true + ? never + : CastConstraintError + : CastConstraintError + : never + ) + | ( + GenericConstrainHandler extends typeof Negative + ? GenericConstrainedType extends NumberMaxInternal + ? And<[ + IsGreater<0, InferredReferenceValue>, + Not>, + ]> extends true + ? never + : CastConstraintError + : CastConstraintError + : never + ) + | ( + GenericConstrainHandler extends ( + | typeof Negative + | typeof Positive + | StringMaxHandlerInternal + | StringMinHandlerInternal + | NumberMaxHandlerInternal + | NumberMinHandlerInternal + ) + ? never + : CastConstraintError + ) +) extends infer InferredResult + ? NeverCoalescing + : never; + +export function castConstraint< + GenericConstrainedType extends ConstrainedType, + GenericConstrainHandler extends ConstraintHandler, +>( + constrainedType: ( + & GenericConstrainedType + & ForbiddenBadCast< + GenericConstrainedType, + GenericConstrainHandler + > + ), + constraintHandler: GenericConstrainHandler | GenericConstrainHandler[], +): ( + & GenericConstrainedType + & UnionToIntersection< + GenericConstrainHandler extends ConstraintHandler + ? GetConstraint + : never + > + ) { + const preparedConstraintHandler = DArray.coalescing(constraintHandler); + + const newConstraints = { + ...constrainedTypeKind.getValue(constrainedType), + }; + + for (let index = 0; index < preparedConstraintHandler.length; index++) { + const constraintHandler = preparedConstraintHandler[index]!; + + (newConstraints[constraintHandler.name] as any) = null; + } + + return constrainedTypeKind.addTo( + constrainedType, + newConstraints, + ) as never; +} diff --git a/scripts/clean/constraint/defaultConstraint/number.ts b/scripts/clean/constraint/defaultConstraint/number.ts index de0467a64..595d3ddf0 100644 --- a/scripts/clean/constraint/defaultConstraint/number.ts +++ b/scripts/clean/constraint/defaultConstraint/number.ts @@ -1,5 +1,5 @@ import { Number } from "@scripts/clean/primitive"; -import { type GetConstraint, createConstraint } from "../base"; +import { type ConstraintHandler, type GetConstraint, createConstraint } from "../base"; import * as DDataParser from "../../../dataParser"; import { type OnlyLiteralNumber } from "@scripts/common"; @@ -19,7 +19,7 @@ export type Int = GetConstraint; export const Positive = createConstraint( "positive", Number, - DDataParser.checkerNumberMin(1), + DDataParser.checkerNumberMin(0), ); export type Positive = GetConstraint; @@ -29,10 +29,28 @@ export type Positive = GetConstraint; export const Negative = createConstraint( "negative", Number, - DDataParser.checkerNumberMax(-1), + DDataParser.checkerNumberMax(0), ); export type Negative = GetConstraint; +export type NumberMinHandlerInternal< + GenericValue extends number = number, +> = Extract< + ConstraintHandler< + `number-min-${GenericValue}`, + number, + readonly [DDataParser.DataParserCheckerNumberMin], + never + >, + any +>; + +export type NumberMinInternal< + GenericValue extends number = number, +> = GetConstraint< + NumberMinHandlerInternal +>; + /** * {@include clean/NumberMin/index.md} */ @@ -40,9 +58,9 @@ export function NumberMin< GenericValue extends number, >( value: GenericValue & OnlyLiteralNumber, -) { +): NumberMinHandlerInternal { return createConstraint( - `number-min-${value}`, + `number-min-${value as any}`, Number, DDataParser.checkerNumberMin(value), ); @@ -50,7 +68,29 @@ export function NumberMin< export type NumberMin< GenericValue extends number, -> = ReturnType>; +> = GetConstraint< + ReturnType< + typeof NumberMin + > +>; + +export type NumberMaxHandlerInternal< + GenericValue extends number = number, +> = Extract< + ConstraintHandler< + `number-max-${GenericValue}`, + number, + readonly [DDataParser.DataParserCheckerNumberMax], + never + >, + any +>; + +export type NumberMaxInternal< + GenericValue extends number = number, +> = GetConstraint< + NumberMaxHandlerInternal +>; /** * {@include clean/NumberMax/index.md} @@ -59,9 +99,9 @@ export function NumberMax< GenericValue extends number, >( value: GenericValue & OnlyLiteralNumber, -) { +): NumberMaxHandlerInternal { return createConstraint( - `number-max-${value}`, + `number-max-${value as any}`, Number, DDataParser.checkerNumberMax(value), ); @@ -69,17 +109,8 @@ export function NumberMax< export type NumberMax< GenericValue extends number, -> = ReturnType>; - -/** - * {@include clean/PositiveInt/index.md} - */ -export const PositiveInt = createConstraint( - "positive-int", - Number, - [ - DDataParser.checkerInt(), - DDataParser.checkerNumberMin(1), - ], -); -export type PositiveInt = GetConstraint; +> = GetConstraint< + ReturnType< + typeof NumberMax + > +>; diff --git a/scripts/clean/constraint/defaultConstraint/string.ts b/scripts/clean/constraint/defaultConstraint/string.ts index 31ace93f0..87a0e3a42 100644 --- a/scripts/clean/constraint/defaultConstraint/string.ts +++ b/scripts/clean/constraint/defaultConstraint/string.ts @@ -1,5 +1,5 @@ import { String } from "@scripts/clean/primitive"; -import { type GetConstraint, createConstraint } from "../base"; +import { type ConstraintHandler, type GetConstraint, createConstraint } from "../base"; import * as DDataParser from "../../../dataParser"; import { type OnlyLiteralNumber } from "@scripts/common"; @@ -24,6 +24,24 @@ export const Url = createConstraint( export type Url = GetConstraint; +export type StringMinHandlerInternal< + GenericValue extends number = number, +> = Extract< + ConstraintHandler< + `string-min-${GenericValue}`, + string, + readonly [DDataParser.DataParserCheckerStringMin], + never + >, + any +>; + +export type StringMinInternal< + GenericValue extends number = number, +> = GetConstraint< + StringMinHandlerInternal +>; + /** * {@include clean/StringMin/index.md} */ @@ -31,9 +49,9 @@ export function StringMin< GenericValue extends number, >( value: GenericValue & OnlyLiteralNumber, -) { +): StringMinHandlerInternal { return createConstraint( - `string-min-${value}`, + `string-min-${value as any}`, String, DDataParser.checkerStringMin(value), ); @@ -41,7 +59,29 @@ export function StringMin< export type StringMin< GenericValue extends number, -> = GetConstraint>>; +> = GetConstraint< + ReturnType< + typeof StringMin + > +>; + +export type StringMaxHandlerInternal< + GenericValue extends number = number, +> = Extract< + ConstraintHandler< + `string-max-${GenericValue}`, + string, + readonly [DDataParser.DataParserCheckerStringMax], + never + >, + any +>; + +export type StringMaxInternal< + GenericValue extends number = number, +> = GetConstraint< + StringMaxHandlerInternal +>; /** * {@include clean/StringMax/index.md} @@ -50,9 +90,9 @@ export function StringMax< GenericValue extends number, >( value: GenericValue & OnlyLiteralNumber, -) { +): StringMaxHandlerInternal { return createConstraint( - `string-max-${value}`, + `string-max-${value as any}`, String, DDataParser.checkerStringMax(value), ); @@ -60,4 +100,8 @@ export function StringMax< export type StringMax< GenericValue extends number, -> = GetConstraint>>; +> = GetConstraint< + ReturnType< + typeof StringMax + > +>; diff --git a/scripts/clean/constraint/index.ts b/scripts/clean/constraint/index.ts index 3a7aea1cb..626baee44 100644 --- a/scripts/clean/constraint/index.ts +++ b/scripts/clean/constraint/index.ts @@ -1,3 +1,4 @@ export * from "./base"; +export * from "./cast"; export * from "./defaultConstraint"; export * from "./set"; diff --git a/scripts/clean/constraint/set.ts b/scripts/clean/constraint/set.ts index 09dae5b29..54de77a6e 100644 --- a/scripts/clean/constraint/set.ts +++ b/scripts/clean/constraint/set.ts @@ -16,15 +16,38 @@ export interface ConstraintsSetHandler< > extends Kind { /** - * {@include clean/createConstraintsSet/primitiveHandler.md} + * @deprecated */ readonly primitiveHandler: PrimitiveHandler; /** - * {@include clean/createConstraintsSet/constraints.md} + * @deprecated */ readonly constraints: GenericConstraintsHandler; + readonly internal: { + + /** + * {@include clean/createConstraintsSet/dataParser.md} + */ + readonly dataParser: DDataParser.Contract; + + /** + * {@include clean/createConstraintsSet/primitiveHandler.md} + */ + readonly primitiveHandler: PrimitiveHandler; + + /** + * {@include clean/createConstraintsSet/constraints.md} + */ + readonly constraints: GenericConstraintsHandler; + + /** + * {@include clean/createConstraintsSet/constraintKindValue.md} + */ + readonly constraintKindValue: Record; + }; + /** * {@include clean/createConstraintsSet/create.md} */ @@ -282,7 +305,7 @@ export function createConstraintsSet< const checkers = DArray.flatMap( constraints, - ({ checkers }) => checkers, + ({ internal }) => internal.checkers, ); const dataParserWithCheckers = primitiveHandler @@ -364,6 +387,12 @@ export function createConstraintsSet< { primitiveHandler, constraints, + internal: { + primitiveHandler, + constraints, + constraintKindValue, + dataParser: dataParserWithCheckers, + }, getConstraint, create, createOrThrow, @@ -383,7 +412,7 @@ export type GetConstraints< > = Extract< GenericHandler extends any ? & UnionToIntersection< - GenericHandler["constraints"][number] extends infer InferredConstraint + GenericHandler["internal"]["constraints"][number] extends infer InferredConstraint ? InferredConstraint extends ConstraintHandler ? GetConstraint : never diff --git a/scripts/clean/entity/index.ts b/scripts/clean/entity/index.ts index c40d17bda..6644bde1e 100644 --- a/scripts/clean/entity/index.ts +++ b/scripts/clean/entity/index.ts @@ -1,4 +1,4 @@ -import { type SimplifyTopLevel, type Kind, unwrap, kindHeritage, createErrorKind, pipe, forward, wrapValue, type RemoveKind, type RemoveReadonly, createOverride, type AnyFunction, GetKind, type GetKindValue } from "@scripts/common"; +import { type SimplifyTopLevel, type Kind, unwrap, kindHeritage, createErrorKind, pipe, forward, type RemoveKind, type RemoveReadonly, createOverride, type AnyFunction, type GetKindValue, keyWrappedValue } from "@scripts/common"; import { createCleanKind } from "../kind"; import { newTypeKind } from "../newType"; import { constrainedTypeKind } from "../constraint"; @@ -55,7 +55,7 @@ export interface Entity< > { } -const entityHandlerKind = createCleanKind("entity-handler"); +export const entityHandlerKind = createCleanKind("entity-handler"); export interface EntityHandler< GenericName extends string = string, @@ -72,11 +72,25 @@ export interface EntityHandler< */ readonly propertiesDefinition: GenericPropertiesDefinition; + /** + * @deprecated + */ readonly mapDataParser: DDataParser.Contract< EntityProperties, unknown >; + readonly internal: { + + /** + * {@include clean/createEntity/mapDataParser.md} + */ + readonly mapDataParser: DDataParser.Contract< + EntityProperties, + unknown + >; + }; + /** * {@include clean/createEntity/new.md} */ @@ -179,21 +193,23 @@ export function createEntity< entityPropertyDefinitionToDataParser( property, (newTypeHandler) => { - const constraintKindValue = pipe( - newTypeHandler.constraints, - DArray.map(({ name }) => DObject.entry(name, null)), - DObject.fromEntries, - ); + const allKind = { + ...constrainedTypeKind.setTo( + {}, + newTypeHandler.internal.constraintKindValue, + ), + ...newTypeKind.setTo( + {}, + newTypeHandler.name, + ), + }; return DDataParser.transform( - newTypeHandler.dataParser, - (value) => constrainedTypeKind.setTo( - newTypeKind.setTo( - wrapValue(value), - newTypeHandler.name, - ), - constraintKindValue, - ), + newTypeHandler.internal.dataParser, + (value) => ({ + ...allKind, + [keyWrappedValue]: value, + }), ); }, ), @@ -257,6 +273,9 @@ export function createEntity< name, propertiesDefinition, mapDataParser, + internal: { + mapDataParser, + }, new: theNew, map, mapOrThrow, diff --git a/scripts/clean/index.ts b/scripts/clean/index.ts index 86105776d..858a4fbd2 100644 --- a/scripts/clean/index.ts +++ b/scripts/clean/index.ts @@ -12,3 +12,4 @@ export * from "./repository"; export * from "./useCase"; export * from "./flag"; export * from "./maybe"; +export * from "./toMapDataParser"; diff --git a/scripts/clean/newType.ts b/scripts/clean/newType.ts index 104ac83c6..9316be157 100644 --- a/scripts/clean/newType.ts +++ b/scripts/clean/newType.ts @@ -49,15 +49,33 @@ export interface NewTypeHandler< readonly name: GenericName; /** - * {@include clean/createNewType/dataParser.md} + * @deprecated */ readonly dataParser: DDataParser.Contract; /** - * {@include clean/createNewType/constraints.md} + * @deprecated */ readonly constraints: GenericConstraintsHandler; + readonly internal: { + + /** + * {@include clean/createNewType/dataParser.md} + */ + readonly dataParser: DDataParser.Contract; + + /** + * {@include clean/createNewType/constraints.md} + */ + readonly constraints: GenericConstraintsHandler; + + /** + * {@include clean/createNewType/constraintKindValue.md} + */ + readonly constraintKindValue: Record; + }; + /** * {@include clean/createNewType/create.md} */ @@ -280,7 +298,7 @@ export function createNewType< const checkers = DArray.flatMap( constraints, - ({ checkers }) => checkers, + ({ internal }) => internal.checkers, ); const dataParserWithCheckers = constraint @@ -372,6 +390,11 @@ export function createNewType< name, dataParser: dataParserWithCheckers, constraints, + internal: { + dataParser: dataParserWithCheckers, + constraints, + constraintKindValue, + }, getConstraint, create, createOrThrow, @@ -388,13 +411,13 @@ createNewType.overrideHandler = createOverride("@duplojs/utils/c export type GetNewType< GenericHandler extends NewTypeHandler, - GenericValue extends DDataParser.Output = DDataParser.Output, + GenericValue extends DDataParser.Output = DDataParser.Output, > = Extract< GenericHandler extends any ? NewType< GenericHandler["name"], GenericValue, - GenericHandler["constraints"][number]["name"] + GenericHandler["internal"]["constraints"][number]["name"] > : never, any diff --git a/scripts/clean/primitive/operations/equal.ts b/scripts/clean/primitive/operations/equal.ts index 1b8fb3b3c..95750ecdc 100644 --- a/scripts/clean/primitive/operations/equal.ts +++ b/scripts/clean/primitive/operations/equal.ts @@ -5,39 +5,69 @@ import { type Primitive, type Primitives } from "../base"; * {@include clean/equal/index.md} */ export function equal< - GenericInput extends Primitives, - GenericValue extends( + GenericInput extends Primitives | null, + const GenericValue extends( | Primitive< - Unwrap + Unwrap< + Exclude + > > | Unwrap ), >( value: GenericValue, -): (input: GenericInput) => input is GenericInput & Primitive>; +): (input: GenericInput) => input is ( + & GenericInput + & ( + GenericValue extends null + ? GenericValue + : Primitive< + Unwrap< + Exclude + > + > + ) +); export function equal< - GenericInput extends Primitives, - GenericValue extends( + GenericInput extends Primitives | null, + const GenericValue extends( | Primitive< - Unwrap + Unwrap< + Exclude + > > | Unwrap ), >( input: GenericInput, value: GenericValue, -): input is GenericInput & Primitive>; +): input is ( + & GenericInput + & ( + GenericValue extends null + ? GenericValue + : Primitive< + Unwrap< + Exclude + > + > + ) +); export function equal( - ...args: [Primitives] | [Primitives, Primitives] + ...args: [Primitives | null] | [Primitives | null, Primitives | null] ) { if (args.length === 1) { const [value] = args; - return (input: Primitives) => equal(input, value); + return (input: Primitives | null) => equal(input, value); } const [input, value] = args; + if (input === null || value === null) { + return input === value; + } + return unwrap(input).toString() === unwrap(value).toString() as never; } diff --git a/scripts/clean/toMapDataParser.ts b/scripts/clean/toMapDataParser.ts new file mode 100644 index 000000000..7cd0a083b --- /dev/null +++ b/scripts/clean/toMapDataParser.ts @@ -0,0 +1,100 @@ +import * as DDataParser from "../dataParser"; +import * as DCommon from "../common"; +import * as DPattern from "../pattern"; +import { constrainedTypeKind, constraintHandlerKind, constraintsSetHandlerKind, type ConstraintHandler, type ConstraintsSetHandler, type GetConstraint, type GetConstraints } from "./constraint"; +import { newTypeHandlerKind, newTypeKind, type GetNewType, type NewTypeHandler } from "./newType"; +import { primitiveHandlerKind, type PrimitiveHandler } from "./primitive"; + +type ToMapDataParserInput = + | NewTypeHandler + | ConstraintHandler + | ConstraintsSetHandler + | PrimitiveHandler; + +type OutputDataParser< + GenericInput extends ToMapDataParserInput, +> = GenericInput extends NewTypeHandler + ? GetNewType + : GenericInput extends ConstraintHandler + ? GetConstraint + : GenericInput extends ConstraintsSetHandler + ? GetConstraints + : GenericInput extends PrimitiveHandler + ? ReturnType + : never; + +interface ToMapDataParserParams { + coerce?: boolean; +} + +/** + * {@include clean/toMapDataParser/index.md} + */ +export function toMapDataParser< + GenericInput extends ToMapDataParserInput, + GenericInputDataParser extends unknown = unknown, +>( + input: GenericInput, + params?: ToMapDataParserParams, +): DDataParser.Contract< + OutputDataParser, + GenericInputDataParser +>; + +export function toMapDataParser( + input: ToMapDataParserInput, + params?: ToMapDataParserParams, +) { + const dataParser = (primitiveHandlerKind.has(input) + ? input.dataParser.clone() + : input.internal.dataParser.clone()) as DDataParser.DataParsers; + + if ( + params?.coerce + && DCommon.hasSomeKinds( + dataParser, + [ + DDataParser.stringKind, + DDataParser.numberKind, + DDataParser.bigIntKind, + DDataParser.bigIntKind, + DDataParser.booleanKind, + DDataParser.dateKind, + DDataParser.timeKind, + DDataParser.emptyKind, + DDataParser.nilKind, + ], + ) + ) { + (dataParser.definition.coerce as any) = true; + } + + const valueContainer = DPattern.match(input) + .when( + newTypeHandlerKind.has, + (newType) => ({ + ...newTypeKind.setTo({}, newType.name), + ...constrainedTypeKind.setTo({}, newType.internal.constraintKindValue), + }), + ) + .when( + DCommon.hasSomeKinds([constraintHandlerKind, constraintsSetHandlerKind]), + (constraintOrSet) => constrainedTypeKind.setTo( + {}, + constraintOrSet.internal.constraintKindValue, + ), + ) + .when( + primitiveHandlerKind.has, + () => ({}), + ) + .exhaustive(); + + return DDataParser.transform( + dataParser, + (value) => ({ + ...valueContainer, + [DCommon.keyWrappedValue]: value, + }), + ) as never; +} diff --git a/scripts/common/index.ts b/scripts/common/index.ts index b8563cd24..9b04da747 100644 --- a/scripts/common/index.ts +++ b/scripts/common/index.ts @@ -59,3 +59,4 @@ export * from "./toRegExp"; export * from "./justExec"; export * from "./callThen"; export * from "./queue"; +export * from "./printer"; diff --git a/scripts/common/printer.ts b/scripts/common/printer.ts new file mode 100644 index 000000000..bbb8e0242 --- /dev/null +++ b/scripts/common/printer.ts @@ -0,0 +1,131 @@ +import * as DString from "@scripts/string"; + +export namespace Printer { + const codeColors = { + red: "\x1b[31m", + green: "\x1b[32m", + yellow: "\x1b[33m", + blue: "\x1b[34m", + magenta: "\x1b[35m", + cyan: "\x1b[36m", + gray: "\x1b[90m", + } as const; + + const codeBold = "\x1b[1m"; + const codeReset = "\x1b[0m"; + + export const tab = "\t"; + export const back = "\n"; + export const dash = "-"; + + export type Colors = keyof typeof codeColors; + + /** + * {@include common/printer/colorized/index.md} + */ + export function colorized< + GenericInput extends string, + >( + color: Colors, + ): (input: GenericInput) => string; + export function colorized< + GenericInput extends string, + >( + input: GenericInput, + color: Colors, + ): string; + export function colorized(...args: [string, Colors] | [Colors]) { + if (args.length === 1) { + const [color] = args; + + return (input: string) => colorized(input, color); + } + + const [input, color] = args; + + return `${codeColors[color]}${input}${codeReset}`; + } + + /** + * {@include common/printer/bold/index.md} + */ + export function bold(input: string) { + return `${codeBold}${input}${codeReset}`; + } + + /** + * {@include common/printer/colorizedBold/index.md} + */ + export function colorizedBold< + GenericInput extends string, + >( + color: Colors, + ): (input: GenericInput) => string; + export function colorizedBold< + GenericInput extends string, + >( + input: GenericInput, + color: Colors, + ): string; + export function colorizedBold(...args: [string, Colors] | [Colors]) { + if (args.length === 1) { + const [color] = args; + + return (input: string) => colorizedBold(input, color); + } + + const [input, color] = args; + + return bold(colorized(input, color)); + } + + export function indent(level: number) { + return DString.repeat(tab, level); + } + + export function stringify(value: unknown) { + try { + return JSON.stringify(value); + } catch { + return String(value); + } + } + + export type RenderInput = string | boolean | null | undefined | RenderInput[]; + + /** + * {@include common/printer/render/index.md} + */ + export function render< + GenericValues extends readonly RenderInput[], + >( + joinCharacter: string, + ): (values: GenericValues) => string; + export function render< + GenericValues extends readonly RenderInput[], + >( + values: GenericValues, + joinCharacter: string + ): string; + export function render( + ...args: + | [readonly (string | boolean | null | undefined)[], string] + | [string] + ) { + if (args.length === 1) { + const [joinCharacter] = args; + + return (values: readonly (string | boolean | null | undefined)[]) => render(values, joinCharacter); + } + + const [values, joinCharacter] = args; + + return values + .flat(Infinity) + .filter((value) => typeof value === "string" || value === true) + .join(joinCharacter); + } + + export const renderLine = render(" "); + export const renderParagraph = render(back); +} diff --git a/scripts/common/types/and.ts b/scripts/common/types/and.ts index 22b943a6f..ffcebbcac 100644 --- a/scripts/common/types/and.ts +++ b/scripts/common/types/and.ts @@ -1,5 +1,5 @@ -import { type IsEqual } from "./isEqual"; - export type And< GenericBooleans extends [boolean, ...boolean[]], -> = IsEqual; +> = GenericBooleans[number] extends true + ? true + : false; diff --git a/scripts/common/types/or.ts b/scripts/common/types/or.ts index 8c3df7f2a..3658d7a75 100644 --- a/scripts/common/types/or.ts +++ b/scripts/common/types/or.ts @@ -1,5 +1,5 @@ -import { type IsEqual } from "./isEqual"; - export type Or< GenericBooleans extends [boolean, ...boolean[]], -> = IsEqual; +> = GenericBooleans[number] extends false + ? false + : true; diff --git a/scripts/dataParser/base.ts b/scripts/dataParser/base.ts index a87169028..65d5265d6 100644 --- a/scripts/dataParser/base.ts +++ b/scripts/dataParser/base.ts @@ -1,11 +1,8 @@ import { type AnyFunction, createErrorKind, createOverride, type GetKind, type GetKindHandler, type GetKindValue, type IsEqual, keyWrappedValue, type Kind, type KindHandler, kindHeritage, type OverrideHandler, pipe, type RemoveKind, simpleClone } from "@scripts/common"; -import { addIssue, createError, SymbolDataParserErrorIssue, SymbolDataParserErrorPromiseIssue, type DataParserError, addPromiseIssue } from "./error"; +import { createError, SymbolDataParserError, type DataParserError } from "./error"; import * as DEither from "@scripts/either"; import { createDataParserKind } from "./kind"; - -export const SymbolDataParserErrorLabel = "SymbolDataParserError"; -export const SymbolDataParserError = Symbol.for(SymbolDataParserErrorLabel); -export type SymbolDataParserError = typeof SymbolDataParserError; +export { SymbolDataParserError } from "./error"; export const checkerKind = createDataParserKind("checker"); @@ -18,7 +15,11 @@ export interface DataParserChecker< GenericInput extends unknown = unknown, > extends Kind { readonly definition: GenericDefinition; - exec(data: GenericInput, self: this): GenericInput | SymbolDataParserErrorIssue; + exec( + data: GenericInput, + error: DataParserError, + self: this, + ): GenericInput | SymbolDataParserError; } export type InputChecker< @@ -40,10 +41,12 @@ export function dataParserCheckerInit< >, exec: ( ...args: Parameters - ) => GetKindValue< + ) => + | GetKindValue< typeof checkerKind, - GenericDataParserChecker - > | SymbolDataParserErrorIssue, + GenericDataParserChecker + > + | SymbolDataParserError, ): GenericDataParserChecker { return (kind as KindHandler).setTo( checkerKind.setTo({ @@ -160,8 +163,6 @@ interface DataParserInitExecParams< GenericDataParser >["output"] | SymbolDataParserError - | SymbolDataParserErrorIssue - | SymbolDataParserErrorPromiseIssue ); async(...args: [...Parameters, self: GenericDataParser]): Promise< | GetKindValue< @@ -169,16 +170,12 @@ interface DataParserInitExecParams< GenericDataParser >["output"] | SymbolDataParserError - | SymbolDataParserErrorIssue - | SymbolDataParserErrorPromiseIssue >; isAsynchronous(self: GenericDataParser): boolean; } // This allows for better performance WTF ??? -const SDPEI = SymbolDataParserErrorIssue; -const SDPEPI = SymbolDataParserErrorPromiseIssue; const SDPE = SymbolDataParserError; const DPE = createError(); @@ -226,24 +223,14 @@ export function dataParserInit< ) { let result = (formattedExec.sync as AnyFunction)(data, error, self) as unknown; - if (result === SDPEI) { - addIssue(error, self as never, data); - - return SDPE; - } else if (result === SDPEPI) { - addPromiseIssue(error, self as never, data); - - return SDPE; - } else if ( + if ( result !== SDPE && self.definition.checkers.length ) { for (const checker of self.definition.checkers) { - const checkerResult = checker.exec(result, checker); - - if (checkerResult === SDPEI) { - addIssue(error, checker as never, result); + const checkerResult = checker.exec(result, error, checker); + if (checkerResult === SDPE) { return SDPE; } else { result = checkerResult; @@ -260,24 +247,14 @@ export function dataParserInit< ) { let result = await (formattedExec.async as AnyFunction)(data, error, self) as unknown; - if (result === SDPEI) { - addIssue(error, self as never, data); - - return SDPE; - } else if (result === SDPEPI) { - addPromiseIssue(error, self as never, data); - - return SDPE; - } else if ( + if ( result !== SDPE && self.definition.checkers.length ) { for (const checker of self.definition.checkers) { - const checkerResult = checker.exec(result, checker); - - if (checkerResult === SDPEI) { - addIssue(error, checker as never, result); + const checkerResult = checker.exec(result, error, checker); + if (checkerResult === SDPE) { return SDPE; } else { result = checkerResult; diff --git a/scripts/dataParser/error.ts b/scripts/dataParser/error.ts index f41a384a7..716a874be 100644 --- a/scripts/dataParser/error.ts +++ b/scripts/dataParser/error.ts @@ -1,39 +1,39 @@ -import { type Kind } from "@scripts/common"; -import { type DataParserTransform } from "./parsers"; +import { type Kind, Printer, unwrap } from "@scripts/common"; import { createDataParserKind } from "./kind"; -import { type DataParser } from "./base"; -import { type DataParserCheckers } from "./types"; +import type * as DEither from "@scripts/either"; -export const SymbolDataParserErrorIssueLabel = "SymbolDataParserErrorIssue"; +export const SymbolDataParserErrorLabel = "SymbolDataParserError"; +export const SymbolDataParserError = Symbol.for(SymbolDataParserErrorLabel); +export type SymbolDataParserError = typeof SymbolDataParserError; + +/** + * @deprecated + */ +export const SymbolDataParserErrorIssueLabel = "SymbolDataParserError"; + +/** + * @deprecated + */ export const SymbolDataParserErrorIssue = Symbol.for(SymbolDataParserErrorIssueLabel); + +/** + * @deprecated + */ export type SymbolDataParserErrorIssue = typeof SymbolDataParserErrorIssue; export const errorIssueKind = createDataParserKind("error-issue"); export interface DataParserErrorIssue extends Kind { - readonly source: DataParser | DataParserCheckers; + readonly expected: string; readonly path: string; readonly data: unknown; - readonly moreInformation?: string; -} - -export const SymbolDataParserErrorPromiseIssueLabel = "SymbolDataParserErrorPromiseIssue"; -export const SymbolDataParserErrorPromiseIssue = Symbol.for(SymbolDataParserErrorPromiseIssueLabel); -export type SymbolDataParserErrorPromiseIssue = typeof SymbolDataParserErrorPromiseIssue; - -export const errorPromiseIssueKind = createDataParserKind("error-issue-promise"); - -export interface DataParserErrorPromiseIssue extends Kind { - readonly source: DataParserTransform; - readonly path: string; - readonly data: unknown; - readonly moreInformation?: string; + readonly message: string | undefined; } export const errorKind = createDataParserKind("error"); export interface DataParserError extends Kind { - readonly issues: (DataParserErrorIssue | DataParserErrorPromiseIssue)[]; + readonly issues: DataParserErrorIssue[]; readonly currentPath: string[]; } @@ -46,38 +46,20 @@ export function createError(): DataParserError { export function addIssue( error: DataParserError, - source: DataParser | DataParserCheckers, + expected: string, data: unknown, - moreInformation?: string, -) { + message: string | undefined, +): SymbolDataParserError { error.issues.push( errorIssueKind.setTo({ - source, + expected, path: error.currentPath.join("."), data, - moreInformation, + message, }), ); - return error; -} - -export function addPromiseIssue( - error: DataParserError, - source: DataParserTransform, - data: unknown, - moreInformation?: string, -) { - error.issues.push( - errorPromiseIssueKind.setTo({ - source, - path: error.currentPath.join("."), - data, - moreInformation, - }), - ); - - return error; + return SymbolDataParserError; } export function setErrorPath( @@ -97,3 +79,26 @@ export function popErrorPath( return error; } + +export function interpretError(error: DataParserError | DEither.Left) { + const dataParserError = errorKind.has(error) + ? error + : unwrap(error); + + return Printer.renderParagraph([ + Printer.colorizedBold("Validation failed", "red"), + dataParserError.issues.map((issue) => Printer.renderParagraph([ + "", + Printer.renderLine([ + Printer.colorizedBold("✖", "red"), + Printer.colorizedBold(issue.path || "", "cyan"), + "expected", + Printer.colorized(issue.expected, "green"), + "but received", + Printer.colorized(Printer.stringify(issue.data), "red"), + ]), + issue.message !== undefined && `${Printer.indent(1)}↳ ${issue.message}`, + ])), + dataParserError.issues.length === 0 && "No issue found", + ]); +} diff --git a/scripts/dataParser/parsers/array/checkers/max.ts b/scripts/dataParser/parsers/array/checkers/max.ts index c14ae29b7..e0fe1635e 100644 --- a/scripts/dataParser/parsers/array/checkers/max.ts +++ b/scripts/dataParser/parsers/array/checkers/max.ts @@ -1,6 +1,6 @@ import { type Kind } from "@scripts/common"; import { type DataParserCheckerDefinition, dataParserCheckerInit, type DataParserChecker } from "@scripts/dataParser/base"; -import { SymbolDataParserErrorIssue } from "@scripts/dataParser/error"; +import { addIssue } from "@scripts/dataParser/error"; import { createDataParserKind } from "../../../kind"; export interface DataParserCheckerDefinitionArrayMax extends DataParserCheckerDefinition { @@ -35,12 +35,9 @@ export function checkerArrayMax( max, }, }, - (data, self) => { - if (data.length > self.definition.max) { - return SymbolDataParserErrorIssue; - } + (data, error, self) => data.length <= self.definition.max + ? data + : addIssue(error, `array.length <= ${self.definition.max}`, data, self.definition.errorMessage), - return data; - }, ); } diff --git a/scripts/dataParser/parsers/array/checkers/min.ts b/scripts/dataParser/parsers/array/checkers/min.ts index 7c82b24aa..95483153a 100644 --- a/scripts/dataParser/parsers/array/checkers/min.ts +++ b/scripts/dataParser/parsers/array/checkers/min.ts @@ -1,6 +1,6 @@ import { type Kind } from "@scripts/common"; import { type DataParserCheckerDefinition, dataParserCheckerInit, type DataParserChecker } from "@scripts/dataParser/base"; -import { SymbolDataParserErrorIssue } from "@scripts/dataParser/error"; +import { addIssue } from "@scripts/dataParser/error"; import { createDataParserKind } from "../../../kind"; export interface DataParserCheckerDefinitionArrayMin extends DataParserCheckerDefinition { @@ -35,12 +35,8 @@ export function checkerArrayMin( min, }, }, - (data, self) => { - if (data.length < self.definition.min) { - return SymbolDataParserErrorIssue; - } - - return data; - }, + (data, error, self) => data.length >= self.definition.min + ? data + : addIssue(error, `array.length >= ${self.definition.min}`, data, self.definition.errorMessage), ); } diff --git a/scripts/dataParser/parsers/array/index.ts b/scripts/dataParser/parsers/array/index.ts index 9c1d3876e..970491112 100644 --- a/scripts/dataParser/parsers/array/index.ts +++ b/scripts/dataParser/parsers/array/index.ts @@ -1,7 +1,7 @@ import { type NeverCoalescing, type Kind, type FixDeepFunctionInfer, createOverride } from "@scripts/common"; import { type DataParserDefinition, type DataParser, dataParserInit, type Output, type Input, SymbolDataParserError, type DataParserChecker } from "../../base"; import { type AddCheckersToDefinition, type MergeDefinition } from "@scripts/dataParser/types"; -import { popErrorPath, setErrorPath, SymbolDataParserErrorIssue } from "@scripts/dataParser/error"; +import { addIssue, popErrorPath, setErrorPath } from "@scripts/dataParser/error"; import { type DataParserCheckerArrayMin, type DataParserCheckerArrayMax } from "./checkers"; import { createDataParserKind } from "../../kind"; import { type CheckerRefineImplementation } from "../refine"; @@ -101,7 +101,7 @@ export function array< { sync: (data, error, self) => { if (!(data instanceof Array)) { - return SymbolDataParserErrorIssue; + return addIssue(error, "array", data, self.definition.errorMessage); } let output: SymbolDataParserError | unknown[] = []; @@ -128,7 +128,7 @@ export function array< }, async: async(data, error, self) => { if (!(data instanceof Array)) { - return SymbolDataParserErrorIssue; + return addIssue(error, "array", data, self.definition.errorMessage); } let output: SymbolDataParserError | unknown[] = []; diff --git a/scripts/dataParser/parsers/bigint/checkers/max.ts b/scripts/dataParser/parsers/bigint/checkers/max.ts index 4b52685dd..a9b88fe7b 100644 --- a/scripts/dataParser/parsers/bigint/checkers/max.ts +++ b/scripts/dataParser/parsers/bigint/checkers/max.ts @@ -1,6 +1,6 @@ import { type Kind } from "@scripts/common"; import { type DataParserCheckerDefinition, dataParserCheckerInit, type DataParserChecker } from "@scripts/dataParser/base"; -import { SymbolDataParserErrorIssue } from "@scripts/dataParser/error"; +import { addIssue } from "@scripts/dataParser/error"; import { createDataParserKind } from "../../../kind"; export interface DataParserCheckerDefinitionBigIntMax extends DataParserCheckerDefinition { @@ -35,9 +35,9 @@ export function checkerBigIntMax( max, }, }, - (value, self) => { + (value, error, self) => { if (value > self.definition.max) { - return SymbolDataParserErrorIssue; + return addIssue(error, `bigint <= ${self.definition.max}n`, value, self.definition.errorMessage); } return value; diff --git a/scripts/dataParser/parsers/bigint/checkers/min.ts b/scripts/dataParser/parsers/bigint/checkers/min.ts index 78f409839..75fd42704 100644 --- a/scripts/dataParser/parsers/bigint/checkers/min.ts +++ b/scripts/dataParser/parsers/bigint/checkers/min.ts @@ -1,6 +1,6 @@ import { type Kind } from "@scripts/common"; import { type DataParserCheckerDefinition, dataParserCheckerInit, type DataParserChecker } from "@scripts/dataParser/base"; -import { SymbolDataParserErrorIssue } from "@scripts/dataParser/error"; +import { addIssue } from "@scripts/dataParser/error"; import { createDataParserKind } from "../../../kind"; export interface DataParserCheckerDefinitionBigIntMin extends DataParserCheckerDefinition { @@ -35,9 +35,9 @@ export function checkerBigIntMin( min, }, }, - (value, self) => { + (value, error, self) => { if (value < self.definition.min) { - return SymbolDataParserErrorIssue; + return addIssue(error, `bigint >= ${self.definition.min}n`, value, self.definition.errorMessage); } return value; diff --git a/scripts/dataParser/parsers/bigint/index.ts b/scripts/dataParser/parsers/bigint/index.ts index 4795346de..c08527ad8 100644 --- a/scripts/dataParser/parsers/bigint/index.ts +++ b/scripts/dataParser/parsers/bigint/index.ts @@ -1,7 +1,7 @@ import { type NeverCoalescing, type Kind, type FixDeepFunctionInfer, createOverride } from "@scripts/common"; import { type DataParserDefinition, type DataParser, dataParserInit, type DataParserChecker } from "../../base"; import { type AddCheckersToDefinition, type MergeDefinition } from "@scripts/dataParser/types"; -import { SymbolDataParserErrorIssue } from "@scripts/dataParser/error"; +import { addIssue } from "@scripts/dataParser/error"; import { type DataParserCheckerBigIntMin, type DataParserCheckerBigIntMax } from "./checkers"; import { createDataParserKind } from "../../kind"; import { type CheckerRefineImplementation } from "../refine"; @@ -87,7 +87,7 @@ export function bigint< checkers: definition?.checkers ?? [], coerce: definition?.coerce ?? false, }, - (data, _error, self) => { + (data, error, self) => { if (self.definition.coerce) { try { // eslint-disable-next-line no-param-reassign @@ -99,7 +99,7 @@ export function bigint< return data; } - return SymbolDataParserErrorIssue; + return addIssue(error, "bigint", data, self.definition.errorMessage); }, bigint.overrideHandler, ) as never; diff --git a/scripts/dataParser/parsers/boolean.ts b/scripts/dataParser/parsers/boolean.ts index da2a78501..2d3bd31dd 100644 --- a/scripts/dataParser/parsers/boolean.ts +++ b/scripts/dataParser/parsers/boolean.ts @@ -1,7 +1,7 @@ import { type NeverCoalescing, type Kind, type FixDeepFunctionInfer, createOverride } from "@scripts/common"; import { type DataParserDefinition, type DataParser, dataParserInit, type DataParserChecker } from "../base"; import { type AddCheckersToDefinition, type MergeDefinition } from "@scripts/dataParser/types"; -import { SymbolDataParserErrorIssue } from "@scripts/dataParser/error"; +import { addIssue } from "@scripts/dataParser/error"; import { createDataParserKind } from "../kind"; import { type CheckerRefineImplementation } from "./refine"; import { type GetPropsWithValueExtends } from "@scripts/object"; @@ -82,7 +82,7 @@ export function boolean< checkers: definition?.checkers ?? [], coerce: definition?.coerce ?? false, }, - (data, _error, self) => { + (data, error, self) => { if (typeof data === "boolean") { return data; } else if (self.definition.coerce) { @@ -91,7 +91,7 @@ export function boolean< if (lower === "true" || lower === "false") { return lower === "true"; } else { - return SymbolDataParserErrorIssue; + return addIssue(error, "boolean", data, self.definition.errorMessage); } } else if ( typeof data === "number" @@ -104,7 +104,7 @@ export function boolean< } } - return SymbolDataParserErrorIssue; + return addIssue(error, "boolean", data, self.definition.errorMessage); }, boolean.overrideHandler, ) as never; diff --git a/scripts/dataParser/parsers/date.ts b/scripts/dataParser/parsers/date.ts index 774e81a4d..4005c6df4 100644 --- a/scripts/dataParser/parsers/date.ts +++ b/scripts/dataParser/parsers/date.ts @@ -1,7 +1,7 @@ import { type NeverCoalescing, type Kind, type FixDeepFunctionInfer, createOverride } from "@scripts/common"; import { type DataParserDefinition, type DataParser, dataParserInit, type DataParserChecker } from "../base"; import { type AddCheckersToDefinition, type MergeDefinition } from "@scripts/dataParser/types"; -import { SymbolDataParserErrorIssue } from "@scripts/dataParser/error"; +import { addIssue } from "@scripts/dataParser/error"; import { createDataParserKind } from "../kind"; import { type CheckerRefineImplementation } from "./refine"; import { type GetPropsWithValueExtends } from "@scripts/object"; @@ -83,11 +83,11 @@ export function date< checkers: definition?.checkers ?? [], coerce: definition?.coerce ?? false, }, - (data, _error, self) => { + (data, error, self) => { if (self.definition.coerce) { if (typeof data === "number") { if (!DDate.isSafeTimestamp(data)) { - return SymbolDataParserErrorIssue; + return addIssue(error, "date", data, self.definition.errorMessage); } return DDate.TheDate.new(data); @@ -110,12 +110,12 @@ export function date< const timestamp = data.getTime(); if (!DDate.isSafeTimestamp(timestamp)) { - return SymbolDataParserErrorIssue; + return addIssue(error, "date", data, self.definition.errorMessage); } return DDate.TheDate.new(timestamp); } - return SymbolDataParserErrorIssue; + return addIssue(error, "date", data, self.definition.errorMessage); }, date.overrideHandler, ) as never; diff --git a/scripts/dataParser/parsers/empty.ts b/scripts/dataParser/parsers/empty.ts index 83de32fc0..c1909539d 100644 --- a/scripts/dataParser/parsers/empty.ts +++ b/scripts/dataParser/parsers/empty.ts @@ -1,7 +1,7 @@ import { type NeverCoalescing, type Kind, type FixDeepFunctionInfer, createOverride } from "@scripts/common"; import { type DataParserDefinition, type DataParser, dataParserInit, type DataParserChecker } from "../base"; import { type AddCheckersToDefinition, type MergeDefinition } from "@scripts/dataParser/types"; -import { SymbolDataParserErrorIssue } from "@scripts/dataParser/error"; +import { addIssue } from "@scripts/dataParser/error"; import { createDataParserKind } from "../kind"; import { type CheckerRefineImplementation } from "./refine"; import { type GetPropsWithValueExtends } from "@scripts/object"; @@ -82,14 +82,14 @@ export function empty< checkers: definition?.checkers ?? [], coerce: definition?.coerce ?? false, }, - (data, _error, self) => { + (data, error, self) => { if (data === undefined) { return data; } else if (self.definition.coerce && data === "undefined") { return undefined; } - return SymbolDataParserErrorIssue; + return addIssue(error, "undefined", data, self.definition.errorMessage); }, empty.overrideHandler, ) as never; diff --git a/scripts/dataParser/parsers/literal.ts b/scripts/dataParser/parsers/literal.ts index e89c05494..46a3639e1 100644 --- a/scripts/dataParser/parsers/literal.ts +++ b/scripts/dataParser/parsers/literal.ts @@ -1,7 +1,7 @@ import { type NeverCoalescing, type Kind, type FixDeepFunctionInfer, createOverride } from "@scripts/common"; import { type DataParserDefinition, type DataParser, dataParserInit, type Output, type DataParserChecker } from "../base"; import { type AddCheckersToDefinition, type MergeDefinition } from "@scripts/dataParser/types"; -import { SymbolDataParserErrorIssue } from "@scripts/dataParser/error"; +import { addIssue } from "@scripts/dataParser/error"; import * as DArray from "@scripts/array"; import { createDataParserKind } from "../kind"; import { type CheckerRefineImplementation } from "./refine"; @@ -93,12 +93,17 @@ export function literal< checkers: definition?.checkers ?? [], value: DArray.coalescing(value), }, - (data, _error, self) => { + (data, error, self) => { if (self.definition.value.includes(data as never)) { return data as never; } - return SymbolDataParserErrorIssue; + return addIssue( + error, + `one of ${self.definition.value.map((value) => String(value)).join(", ")}`, + data, + self.definition.errorMessage, + ); }, literal.overrideHandler, ) as never; diff --git a/scripts/dataParser/parsers/nil.ts b/scripts/dataParser/parsers/nil.ts index 7a8d59ce8..aa2430c13 100644 --- a/scripts/dataParser/parsers/nil.ts +++ b/scripts/dataParser/parsers/nil.ts @@ -1,7 +1,7 @@ import { type NeverCoalescing, type Kind, type FixDeepFunctionInfer, createOverride } from "@scripts/common"; import { type DataParserDefinition, type DataParser, dataParserInit, type DataParserChecker } from "../base"; import { type AddCheckersToDefinition, type MergeDefinition } from "@scripts/dataParser/types"; -import { SymbolDataParserErrorIssue } from "@scripts/dataParser/error"; +import { addIssue } from "@scripts/dataParser/error"; import { createDataParserKind } from "../kind"; import { type CheckerRefineImplementation } from "./refine"; import { type GetPropsWithValueExtends } from "@scripts/object"; @@ -82,14 +82,14 @@ export function nil< checkers: definition?.checkers ?? [], coerce: definition?.coerce ?? false, }, - (data, _error, self) => { + (data, error, self) => { if (data === null) { return data; } else if (self.definition.coerce && data === "null") { return null; } - return SymbolDataParserErrorIssue; + return addIssue(error, "null", data, self.definition.errorMessage); }, nil.overrideHandler, ) as never; diff --git a/scripts/dataParser/parsers/number/checkers/int.ts b/scripts/dataParser/parsers/number/checkers/int.ts index eef49bee5..6bb5e5321 100644 --- a/scripts/dataParser/parsers/number/checkers/int.ts +++ b/scripts/dataParser/parsers/number/checkers/int.ts @@ -1,6 +1,6 @@ import { type Kind } from "@scripts/common"; import { type DataParserCheckerDefinition, dataParserCheckerInit, type DataParserChecker } from "@scripts/dataParser/base"; -import { SymbolDataParserErrorIssue } from "@scripts/dataParser/error"; +import { addIssue } from "@scripts/dataParser/error"; import { number as numberParser } from ".."; import { createDataParserKind } from "../../../kind"; @@ -30,12 +30,12 @@ export function checkerInt( { definition, }, - (data) => { + (data, error, self) => { if (Number.isInteger(data)) { return data; } - return SymbolDataParserErrorIssue; + return addIssue(error, "integer", data, self.definition.errorMessage); }, ); } diff --git a/scripts/dataParser/parsers/number/checkers/max.ts b/scripts/dataParser/parsers/number/checkers/max.ts index 91f53ea82..ef1cd2e9f 100644 --- a/scripts/dataParser/parsers/number/checkers/max.ts +++ b/scripts/dataParser/parsers/number/checkers/max.ts @@ -1,6 +1,6 @@ import { type Kind } from "@scripts/common"; import { dataParserCheckerInit, type DataParserCheckerDefinition, type DataParserChecker } from "@scripts/dataParser/base"; -import { SymbolDataParserErrorIssue } from "@scripts/dataParser/error"; +import { addIssue } from "@scripts/dataParser/error"; import { createDataParserKind } from "../../../kind"; export interface DataParserCheckerDefinitionNumberMax extends DataParserCheckerDefinition { @@ -35,6 +35,8 @@ export function checkerNumberMax( max, }, }, - (value, self) => value <= self.definition.max ? value : SymbolDataParserErrorIssue, + (value, error, self) => value <= self.definition.max + ? value + : addIssue(error, `number <= ${self.definition.max}`, value, self.definition.errorMessage), ); } diff --git a/scripts/dataParser/parsers/number/checkers/min.ts b/scripts/dataParser/parsers/number/checkers/min.ts index fe638ce08..8b354f9d3 100644 --- a/scripts/dataParser/parsers/number/checkers/min.ts +++ b/scripts/dataParser/parsers/number/checkers/min.ts @@ -1,6 +1,6 @@ import { type Kind } from "@scripts/common"; import { dataParserCheckerInit, type DataParserCheckerDefinition, type DataParserChecker } from "@scripts/dataParser/base"; -import { SymbolDataParserErrorIssue } from "@scripts/dataParser/error"; +import { addIssue } from "@scripts/dataParser/error"; import { createDataParserKind } from "../../../kind"; export interface DataParserCheckerDefinitionNumberMin extends DataParserCheckerDefinition { @@ -35,6 +35,8 @@ export function checkerNumberMin( min, }, }, - (value, self) => value >= self.definition.min ? value : SymbolDataParserErrorIssue, + (value, error, self) => value >= self.definition.min + ? value + : addIssue(error, `number >= ${self.definition.min}`, value, self.definition.errorMessage), ); } diff --git a/scripts/dataParser/parsers/number/index.ts b/scripts/dataParser/parsers/number/index.ts index c1944ca3f..098b67b22 100644 --- a/scripts/dataParser/parsers/number/index.ts +++ b/scripts/dataParser/parsers/number/index.ts @@ -1,7 +1,7 @@ import { type NeverCoalescing, type Kind, type FixDeepFunctionInfer, createOverride } from "@scripts/common"; import { type DataParserDefinition, type DataParser, dataParserInit, type DataParserChecker } from "../../base"; import { type AddCheckersToDefinition, type MergeDefinition } from "@scripts/dataParser/types"; -import { SymbolDataParserErrorIssue } from "@scripts/dataParser/error"; +import { addIssue } from "@scripts/dataParser/error"; import { type DataParserCheckerInt, type DataParserCheckerNumberMin, type DataParserCheckerNumberMax } from "./checkers"; import { createDataParserKind } from "../../kind"; import { type CheckerRefineImplementation } from "../refine"; @@ -88,7 +88,7 @@ export function number< checkers: definition?.checkers ?? [], coerce: definition?.coerce ?? false, }, - (data, _error, self) => { + (data, error, self) => { if (self.definition.coerce) { try { // eslint-disable-next-line no-param-reassign @@ -100,7 +100,7 @@ export function number< return data; } - return SymbolDataParserErrorIssue; + return addIssue(error, "number", data, self.definition.errorMessage); }, number.overrideHandler, ) as never; diff --git a/scripts/dataParser/parsers/object/index.ts b/scripts/dataParser/parsers/object/index.ts index 972abae0b..3b2eebaaa 100644 --- a/scripts/dataParser/parsers/object/index.ts +++ b/scripts/dataParser/parsers/object/index.ts @@ -1,7 +1,7 @@ import { type Kind, pipe, forward, type AnyValue, memo, type NeverCoalescing, type Memoized, type FixDeepFunctionInfer, createOverride } from "@scripts/common"; import { dataParserInit, dataParserKind, type Input, type Output, type DataParser, type DataParserDefinition, SymbolDataParserError, type DataParserChecker } from "../../base"; import { type AddCheckersToDefinition, type MergeDefinition } from "../../types"; -import { popErrorPath, setErrorPath, SymbolDataParserErrorIssue } from "../../error"; +import { addIssue, popErrorPath, setErrorPath } from "../../error"; import * as DArray from "@scripts/array"; import * as DObject from "@scripts/object"; import { type GetPropsWithValueExtends } from "@scripts/object"; @@ -160,7 +160,7 @@ export function object< || typeof data !== "object" || data instanceof Array ) { - return SymbolDataParserErrorIssue; + return addIssue(error, "object", data, self.definition.errorMessage); } let output = {}; @@ -194,7 +194,7 @@ export function object< || typeof data !== "object" || data instanceof Array ) { - return SymbolDataParserErrorIssue; + return addIssue(error, "object", data, self.definition.errorMessage); } let output = {}; diff --git a/scripts/dataParser/parsers/pipe.ts b/scripts/dataParser/parsers/pipe.ts index 61c134844..698e868d9 100644 --- a/scripts/dataParser/parsers/pipe.ts +++ b/scripts/dataParser/parsers/pipe.ts @@ -4,6 +4,7 @@ import { type AddCheckersToDefinition, type MergeDefinition } from "@scripts/dat import { createDataParserKind } from "../kind"; import { type CheckerRefineImplementation } from "./refine"; import { type GetPropsWithValueExtends } from "@scripts/object"; +import { popErrorPath, setErrorPath } from "../error"; export interface DataParserPipeCheckerCustom< GenericInput extends unknown = unknown, @@ -98,22 +99,41 @@ export function pipe< }, { sync: (data, error, self) => { - const result = self.definition.input.exec(data, error); + const currentIndexPath = error.currentPath.length; - if (result === SymbolDataParserError) { + setErrorPath(error, "(pipeIn)", currentIndexPath); + const resultIn = self.definition.input.exec(data, error); + + if (resultIn === SymbolDataParserError) { + popErrorPath(error); return SymbolDataParserError; } - return self.definition.output.exec(result, error); + setErrorPath(error, "(pipeOut)", currentIndexPath); + const resultOut = self.definition.output.exec(resultIn, error); + + popErrorPath(error); + return resultOut; }, async: async(data, error, self) => { - const result = await self.definition.input.asyncExec(data, error); + const currentIndexPath = error.currentPath.length; + + setErrorPath(error, "(pipeIn)", currentIndexPath); + const resultIn = await self.definition.input.asyncExec(data, error); - if (result === SymbolDataParserError) { + if (resultIn === SymbolDataParserError) { + popErrorPath(error); return SymbolDataParserError; } - return self.definition.output.asyncExec(result, error); + setErrorPath(error, "(pipeOut)", currentIndexPath); + return self.definition.output.asyncExec(resultIn, error) + .then( + (resultOut) => { + popErrorPath(error); + return resultOut; + }, + ); }, isAsynchronous: (self) => self.definition.input.isAsynchronous() || self.definition.output.isAsynchronous(), }, diff --git a/scripts/dataParser/parsers/record/index.ts b/scripts/dataParser/parsers/record/index.ts index 64662639a..e93e0ba22 100644 --- a/scripts/dataParser/parsers/record/index.ts +++ b/scripts/dataParser/parsers/record/index.ts @@ -2,7 +2,7 @@ import { type NeverCoalescing, type Kind, type FixDeepFunctionInfer, createOverride, type IsEqual, pipe } from "@scripts/common"; import { type DataParserDefinition, type DataParser, dataParserInit, type Output, type Input, SymbolDataParserError, type DataParserChecker } from "../../base"; import { type AddCheckersToDefinition, type MergeDefinition } from "@scripts/dataParser/types"; -import { popErrorPath, setErrorPath, SymbolDataParserErrorIssue } from "@scripts/dataParser/error"; +import { addIssue, popErrorPath, setErrorPath } from "@scripts/dataParser/error"; import { type DataParserString } from "../string"; import { type DataParserTemplateLiteral } from "../templateLiteral"; import { type DataParserDefinitionLiteral, type DataParserLiteral } from "../literal"; @@ -205,7 +205,7 @@ export function record< || typeof data !== "object" || data instanceof Array ) { - return SymbolDataParserErrorIssue; + return addIssue(error, "record object", data, self.definition.errorMessage); } let output = {}; @@ -216,7 +216,7 @@ export function record< const currentIndexPath = error.currentPath.length; for (const key in fromData) { - setErrorPath(error, key, currentIndexPath); + setErrorPath(error, `(recordKey: ${key})`, currentIndexPath); const resultKey = self .definition @@ -227,6 +227,8 @@ export function record< output = SymbolDataParserError; } + setErrorPath(error, key, currentIndexPath); + const resultValue = self .definition .value @@ -255,7 +257,7 @@ export function record< || typeof data !== "object" || data instanceof Array ) { - return SymbolDataParserErrorIssue; + return addIssue(error, "record object", data, self.definition.errorMessage); } let output = {}; @@ -266,7 +268,7 @@ export function record< const currentIndexPath = error.currentPath.length; for (const key in fromData) { - setErrorPath(error, key, currentIndexPath); + setErrorPath(error, `(recordKey: ${key})`, currentIndexPath); const resultKey = await self .definition @@ -277,6 +279,8 @@ export function record< output = SymbolDataParserError; } + setErrorPath(error, key, currentIndexPath); + const resultValue = await self .definition .value diff --git a/scripts/dataParser/parsers/refine.ts b/scripts/dataParser/parsers/refine.ts index 4463864a0..a07ce4659 100644 --- a/scripts/dataParser/parsers/refine.ts +++ b/scripts/dataParser/parsers/refine.ts @@ -1,6 +1,6 @@ import { type NeverCoalescing, type Kind } from "@scripts/common"; import { dataParserCheckerInit, type DataParserCheckerDefinition, type DataParserChecker } from "@scripts/dataParser/base"; -import { SymbolDataParserErrorIssue } from "@scripts/dataParser/error"; +import { addIssue } from "@scripts/dataParser/error"; import { createDataParserKind } from "../kind"; import { type AssignObjects } from "@scripts/object"; @@ -48,7 +48,9 @@ export function checkerRefine< theFunction, }, }, - (value, self) => self.definition.theFunction(value) ? value : SymbolDataParserErrorIssue, + (value, error, self) => self.definition.theFunction(value) + ? value + : addIssue(error, "value matching refine predicate", value, self.definition.errorMessage), ) as never; } diff --git a/scripts/dataParser/parsers/string/checkers/email.ts b/scripts/dataParser/parsers/string/checkers/email.ts index c88dfda3b..8340dd303 100644 --- a/scripts/dataParser/parsers/string/checkers/email.ts +++ b/scripts/dataParser/parsers/string/checkers/email.ts @@ -1,6 +1,6 @@ import { type Kind } from "@scripts/common"; import { dataParserCheckerInit, type DataParserChecker, type DataParserCheckerDefinition } from "@scripts/dataParser/base"; -import { SymbolDataParserErrorIssue } from "@scripts/dataParser/error"; +import { addIssue } from "@scripts/dataParser/error"; import { string } from ".."; import { createDataParserKind } from "../../../kind"; @@ -36,9 +36,9 @@ export function checkerEmail( pattern: emailPattern, }, }, - (input, self) => { + (input, error, self) => { if (!self.definition.pattern.test(input)) { - return SymbolDataParserErrorIssue; + return addIssue(error, "email", input, self.definition.errorMessage); } return self.definition.normalize ? input.toLowerCase() : input; diff --git a/scripts/dataParser/parsers/string/checkers/max.ts b/scripts/dataParser/parsers/string/checkers/max.ts index d34201ef7..a145de329 100644 --- a/scripts/dataParser/parsers/string/checkers/max.ts +++ b/scripts/dataParser/parsers/string/checkers/max.ts @@ -1,6 +1,6 @@ import { type Kind } from "@scripts/common"; import { dataParserCheckerInit, type DataParserCheckerDefinition, type DataParserChecker } from "@scripts/dataParser/base"; -import { SymbolDataParserErrorIssue } from "@scripts/dataParser/error"; +import { addIssue } from "@scripts/dataParser/error"; import { createDataParserKind } from "../../../kind"; export interface DataParserCheckerDefinitionStringMax extends DataParserCheckerDefinition { @@ -35,6 +35,8 @@ export function checkerStringMax( max, }, }, - (value, self) => value.length <= self.definition.max ? value : SymbolDataParserErrorIssue, + (value, error, self) => value.length <= self.definition.max + ? value + : addIssue(error, `string.length <= ${self.definition.max}`, value, self.definition.errorMessage), ); } diff --git a/scripts/dataParser/parsers/string/checkers/min.ts b/scripts/dataParser/parsers/string/checkers/min.ts index 7fdae45b5..6919e22f7 100644 --- a/scripts/dataParser/parsers/string/checkers/min.ts +++ b/scripts/dataParser/parsers/string/checkers/min.ts @@ -1,6 +1,6 @@ import { type Kind } from "@scripts/common"; import { dataParserCheckerInit, type DataParserCheckerDefinition, type DataParserChecker } from "@scripts/dataParser/base"; -import { SymbolDataParserErrorIssue } from "@scripts/dataParser/error"; +import { addIssue } from "@scripts/dataParser/error"; import { createDataParserKind } from "../../../kind"; export interface DataParserCheckerDefinitionStringMin extends DataParserCheckerDefinition { @@ -35,6 +35,8 @@ export function checkerStringMin( min, }, }, - (value, self) => value.length >= self.definition.min ? value : SymbolDataParserErrorIssue, + (value, error, self) => value.length >= self.definition.min + ? value + : addIssue(error, `string.length >= ${self.definition.min}`, value, self.definition.errorMessage), ); } diff --git a/scripts/dataParser/parsers/string/checkers/regex.ts b/scripts/dataParser/parsers/string/checkers/regex.ts index 04bd1e18c..d016e6493 100644 --- a/scripts/dataParser/parsers/string/checkers/regex.ts +++ b/scripts/dataParser/parsers/string/checkers/regex.ts @@ -1,6 +1,6 @@ import { type Kind } from "@scripts/common"; import { dataParserCheckerInit, type DataParserCheckerDefinition, type DataParserChecker } from "@scripts/dataParser/base"; -import { SymbolDataParserErrorIssue } from "@scripts/dataParser/error"; +import { addIssue } from "@scripts/dataParser/error"; import { createDataParserKind } from "../../../kind"; export interface DataParserCheckerDefinitionStringRegex extends DataParserCheckerDefinition { @@ -35,8 +35,8 @@ export function checkerStringRegex( regex, }, }, - (value, self) => self.definition.regex.test(value) + (value, error, self) => self.definition.regex.test(value) ? value - : SymbolDataParserErrorIssue, + : addIssue(error, `string with pattern ${self.definition.regex.source.toString()}`, value, self.definition.errorMessage), ); } diff --git a/scripts/dataParser/parsers/string/checkers/url.ts b/scripts/dataParser/parsers/string/checkers/url.ts index 6e259876b..8e95313e6 100644 --- a/scripts/dataParser/parsers/string/checkers/url.ts +++ b/scripts/dataParser/parsers/string/checkers/url.ts @@ -1,6 +1,6 @@ import { type Kind } from "@scripts/common"; import { type DataParserCheckerDefinition, dataParserCheckerInit, type DataParserChecker } from "@scripts/dataParser/base"; -import { SymbolDataParserErrorIssue } from "@scripts/dataParser/error"; +import { addIssue } from "@scripts/dataParser/error"; import { string } from ".."; import { createDataParserKind } from "../../../kind"; @@ -34,21 +34,21 @@ export function checkerUrl( { definition: definition, }, - (input, self) => { + (input, error, self) => { try { const url = new URL(input); if (self.definition.hostname) { self.definition.hostname.lastIndex = 0; if (!self.definition.hostname.test(url.hostname)) { - return SymbolDataParserErrorIssue; + return addIssue(error, `URL with hostname matching ${self.definition.hostname.source}`, input, self.definition.errorMessage); } } if (self.definition.protocol) { self.definition.protocol.lastIndex = 0; if (!self.definition.protocol.test(url.protocol.replace(regexRemoveDote, ""))) { - return SymbolDataParserErrorIssue; + return addIssue(error, `URL with protocol matching ${self.definition.protocol.source}`, input, self.definition.errorMessage); } } if (self.definition.normalize) { @@ -57,7 +57,7 @@ export function checkerUrl( return input; } } catch { - return SymbolDataParserErrorIssue; + return addIssue(error, "valid URL", input, self.definition.errorMessage); } }, ); diff --git a/scripts/dataParser/parsers/string/index.ts b/scripts/dataParser/parsers/string/index.ts index 89778c4d0..4f55cb796 100644 --- a/scripts/dataParser/parsers/string/index.ts +++ b/scripts/dataParser/parsers/string/index.ts @@ -2,7 +2,7 @@ import { type NeverCoalescing, type Kind, type FixDeepFunctionInfer, createOverr import { type DataParserDefinition, type DataParser, dataParserInit, type DataParserChecker } from "../../base"; import { type AddCheckersToDefinition, type MergeDefinition } from "@scripts/dataParser/types"; import { type DataParserCheckerUrl, type DataParserCheckerEmail, type DataParserCheckerStringMin, type DataParserCheckerStringMax, type DataParserCheckerStringRegex } from "./checkers"; -import { SymbolDataParserErrorIssue } from "@scripts/dataParser/error"; +import { addIssue } from "@scripts/dataParser/error"; import { createDataParserKind } from "../../kind"; import { type CheckerRefineImplementation } from "../refine"; import { type GetPropsWithValueExtends } from "@scripts/object"; @@ -90,7 +90,7 @@ export function string< checkers: definition?.checkers ?? [], coerce: definition?.coerce ?? false, }, - (data, _error, self) => { + (data, error, self) => { if (self.definition.coerce) { try { // eslint-disable-next-line no-param-reassign @@ -102,7 +102,7 @@ export function string< return data; } - return SymbolDataParserErrorIssue; + return addIssue(error, "string", data, self.definition.errorMessage); }, string.overrideHandler, ) as never; diff --git a/scripts/dataParser/parsers/templateLiteral/index.ts b/scripts/dataParser/parsers/templateLiteral/index.ts index 8255da94b..06cec333d 100644 --- a/scripts/dataParser/parsers/templateLiteral/index.ts +++ b/scripts/dataParser/parsers/templateLiteral/index.ts @@ -1,7 +1,7 @@ import { type Adaptor, type AnyTuple, type FixDeepFunctionInfer, type Kind, type NeverCoalescing, pipe, createOverride, type SimplifyTopLevel } from "@scripts/common"; import { type DataParserDefinition, type DataParser, dataParserInit, type Output, type Input, type DataParserChecker } from "../../base"; import { type AddCheckersToDefinition, type MergeDefinition } from "@scripts/dataParser/types"; -import { SymbolDataParserErrorIssue } from "@scripts/dataParser/error"; +import { addIssue } from "@scripts/dataParser/error"; import { type DataParserCheckerStringMax, type DataParserCheckerStringMin, type DataParserCheckerStringRegex, type DataParserCheckerEmail, type DataParserDefinitionString, type DataParserString } from "../string"; import { type DataParserCheckerInt, type DataParserDefinitionNumber, type DataParserNumber } from "../number"; import { type DataParserDefinitionBigInt, type DataParserBigInt } from "../bigint"; @@ -252,12 +252,17 @@ export function templateLiteral< template, pattern, }, - (data, _error, self) => { + (data, error, self) => { if (typeof data === "string" && self.definition.pattern.test(data)) { return data as never; } - return SymbolDataParserErrorIssue; + return addIssue( + error, + `string matching template literal pattern ${self.definition.pattern.source}`, + data, + self.definition.errorMessage, + ); }, templateLiteral.overrideHandler, ) as never; diff --git a/scripts/dataParser/parsers/time/checkers/max.ts b/scripts/dataParser/parsers/time/checkers/max.ts index d47120558..e7d934348 100644 --- a/scripts/dataParser/parsers/time/checkers/max.ts +++ b/scripts/dataParser/parsers/time/checkers/max.ts @@ -1,6 +1,6 @@ import { type Kind } from "@scripts/common"; import { dataParserCheckerInit, type DataParserCheckerDefinition, type DataParserChecker } from "@scripts/dataParser/base"; -import { SymbolDataParserErrorIssue } from "@scripts/dataParser/error"; +import { addIssue } from "@scripts/dataParser/error"; import { createDataParserKind } from "../../../kind"; import * as DDate from "@scripts/date"; @@ -39,6 +39,8 @@ export function checkerTimeMax( max, }, }, - (value, self) => DDate.lessTime(value, self.definition.max) ? value : SymbolDataParserErrorIssue, + (value, error, self) => DDate.lessTime(value, self.definition.max) + ? value + : addIssue(error, `time <= ${self.definition.max.toString()}`, value, self.definition.errorMessage), ); } diff --git a/scripts/dataParser/parsers/time/checkers/min.ts b/scripts/dataParser/parsers/time/checkers/min.ts index 4f6d56d35..23e316403 100644 --- a/scripts/dataParser/parsers/time/checkers/min.ts +++ b/scripts/dataParser/parsers/time/checkers/min.ts @@ -1,6 +1,6 @@ import { type Kind } from "@scripts/common"; import { dataParserCheckerInit, type DataParserCheckerDefinition, type DataParserChecker } from "@scripts/dataParser/base"; -import { SymbolDataParserErrorIssue } from "@scripts/dataParser/error"; +import { addIssue } from "@scripts/dataParser/error"; import { createDataParserKind } from "../../../kind"; import * as DDate from "@scripts/date"; @@ -39,6 +39,8 @@ export function checkerTimeMin( min, }, }, - (value, self) => DDate.greaterTime(value, self.definition.min) ? value : SymbolDataParserErrorIssue, + (value, error, self) => DDate.greaterTime(value, self.definition.min) + ? value + : addIssue(error, `time >= ${self.definition.min.toString()}`, value, self.definition.errorMessage), ); } diff --git a/scripts/dataParser/parsers/time/index.ts b/scripts/dataParser/parsers/time/index.ts index 4386456e2..c4a6747d3 100644 --- a/scripts/dataParser/parsers/time/index.ts +++ b/scripts/dataParser/parsers/time/index.ts @@ -1,7 +1,7 @@ import { type NeverCoalescing, type Kind, type FixDeepFunctionInfer, createOverride, unwrap } from "@scripts/common"; import { type DataParserDefinition, type DataParser, dataParserInit, type DataParserChecker } from "../../base"; import { type AddCheckersToDefinition, type MergeDefinition } from "@scripts/dataParser/types"; -import { SymbolDataParserErrorIssue } from "@scripts/dataParser/error"; +import { addIssue } from "@scripts/dataParser/error"; import { createDataParserKind } from "../../kind"; import { type CheckerRefineImplementation } from "../refine"; import { type GetPropsWithValueExtends } from "@scripts/object"; @@ -89,13 +89,13 @@ export function time< checkers: definition?.checkers ?? [], coerce: definition?.coerce ?? false, }, - (data, _error, self) => { + (data, error, self) => { if (self.definition.coerce) { if (typeof data === "string" && DDate.isoTimeRegex.test(data)) { const result = DDate.createTime({ value: data }); if (DEither.isLeft(result)) { - return SymbolDataParserErrorIssue; + return addIssue(error, "time", data, self.definition.errorMessage); } return unwrap(result); @@ -108,13 +108,13 @@ export function time< return DDate.TheTime.new(DDate.toTimeValue(data)); } else if (typeof data === "number") { if (!DDate.isSafeTimeValue(data)) { - return SymbolDataParserErrorIssue; + return addIssue(error, "time", data, self.definition.errorMessage); } return DDate.TheTime.new(data); } - return SymbolDataParserErrorIssue; + return addIssue(error, "time", data, self.definition.errorMessage); }, time.overrideHandler, ) as never; diff --git a/scripts/dataParser/parsers/transform.ts b/scripts/dataParser/parsers/transform.ts index 58e822ed6..b0d34f0a4 100644 --- a/scripts/dataParser/parsers/transform.ts +++ b/scripts/dataParser/parsers/transform.ts @@ -1,7 +1,7 @@ import { type FixDeepFunctionInfer, type Kind, type NeverCoalescing, createOverride } from "@scripts/common"; import { type DataParserDefinition, type DataParser, dataParserInit, type Input, type Output, SymbolDataParserError, type DataParserChecker } from "../base"; import { type AddCheckersToDefinition, type MergeDefinition } from "@scripts/dataParser/types"; -import { type DataParserError, type SymbolDataParserErrorIssue, SymbolDataParserErrorPromiseIssue } from "@scripts/dataParser/error"; +import { addIssue, type DataParserError } from "@scripts/dataParser/error"; import { createDataParserKind } from "../kind"; import { type CheckerRefineImplementation } from "./refine"; import { type GetPropsWithValueExtends } from "@scripts/object"; @@ -37,8 +37,6 @@ export type DataParserTransformOutput< > = Exclude< Awaited>, | SymbolDataParserError - | SymbolDataParserErrorIssue - | SymbolDataParserErrorPromiseIssue >; type _DataParserTransform< @@ -120,7 +118,7 @@ export function transform< const result = self.definition.theFunction(innerResult as never, error); if (result instanceof Promise) { - return SymbolDataParserErrorPromiseIssue; + return addIssue(error, "non-promise transform result", result, self.definition.errorMessage); } return result; @@ -135,7 +133,9 @@ export function transform< let result: unknown = self.definition.theFunction(innerResult as never, error); if (result instanceof Promise) { - result = result.catch(() => SymbolDataParserErrorPromiseIssue); + result = await result.catch( + () => addIssue(error, "successful async transform result", result, self.definition.errorMessage), + ); } return result as never; diff --git a/scripts/dataParser/parsers/tuple.ts b/scripts/dataParser/parsers/tuple.ts index 3f22cd498..684336ade 100644 --- a/scripts/dataParser/parsers/tuple.ts +++ b/scripts/dataParser/parsers/tuple.ts @@ -1,7 +1,7 @@ import { type UnionContain, type IsEqual, type Kind, type Adaptor, type NeverCoalescing, type FixDeepFunctionInfer, type AnyTuple, createOverride, type Or } from "@scripts/common"; import { type DataParserDefinition, type DataParser, dataParserInit, type Output, type Input, SymbolDataParserError, type DataParserChecker } from "../base"; import { type AddCheckersToDefinition, type MergeDefinition } from "@scripts/dataParser/types"; -import { popErrorPath, setErrorPath, SymbolDataParserErrorIssue } from "@scripts/dataParser/error"; +import { addIssue, popErrorPath, setErrorPath } from "@scripts/dataParser/error"; import { type DataParserCheckerArrayMax, type DataParserCheckerArrayMin } from "./array"; import { createDataParserKind } from "../kind"; import { type CheckerRefineImplementation } from "./refine"; @@ -178,7 +178,7 @@ export function tuple< { sync: (data, error, self) => { if (!(data instanceof Array)) { - return SymbolDataParserErrorIssue; + return addIssue(error, "tuple array", data, self.definition.errorMessage); } let output: SymbolDataParserError | unknown[] = []; @@ -216,7 +216,7 @@ export function tuple< }, async: async(data, error, self) => { if (!(data instanceof Array)) { - return SymbolDataParserErrorIssue; + return addIssue(error, "tuple array", data, self.definition.errorMessage); } let output: SymbolDataParserError | unknown[] = []; diff --git a/scripts/dataParser/parsers/union.ts b/scripts/dataParser/parsers/union.ts index 34a97de0d..f3e7a8265 100644 --- a/scripts/dataParser/parsers/union.ts +++ b/scripts/dataParser/parsers/union.ts @@ -1,7 +1,7 @@ import { type NeverCoalescing, type Kind, type FixDeepFunctionInfer, createOverride } from "@scripts/common"; import { type DataParserDefinition, type DataParser, dataParserInit, type Output, type Input, SymbolDataParserError, type DataParserChecker } from "../base"; import { type AddCheckersToDefinition, type MergeDefinition } from "@scripts/dataParser/types"; -import { SymbolDataParserErrorIssue } from "@scripts/dataParser/error"; +import { addIssue, setErrorPath } from "@scripts/dataParser/error"; import { createDataParserKind } from "../kind"; import { type CheckerRefineImplementation } from "./refine"; import { type GetPropsWithValueExtends } from "@scripts/object"; @@ -98,26 +98,50 @@ export function union< }, { sync: (data, error, self) => { - for (const dataParser of self.definition.options) { - const result = dataParser.exec(data, error); + const unionError = { + ...error, + currentPath: [...error.currentPath], + issues: [], + }; + const currentIndexPath = unionError.currentPath.length; + + for (let index = 0; index < self.definition.options.length; index++) { + setErrorPath(unionError, `(option: ${index})`, currentIndexPath); + + const dataParser = self.definition.options[index]!; + const result = dataParser.exec(data, unionError); if (result !== SymbolDataParserError) { return result; } } - return SymbolDataParserErrorIssue; + error.issues.push(...unionError.issues); + + return addIssue(error, "respect at least one union value", data, self.definition.errorMessage); }, async: async(data, error, self) => { - for (const dataParser of self.definition.options) { - const result = await dataParser.asyncExec(data, error); + const unionError = { + ...error, + currentPath: [...error.currentPath], + issues: [], + }; + const currentIndexPath = unionError.currentPath.length; + + for (let index = 0; index < self.definition.options.length; index++) { + setErrorPath(unionError, `(option: ${index})`, currentIndexPath); + + const dataParser = self.definition.options[index]!; + const result = await dataParser.asyncExec(data, unionError); if (result !== SymbolDataParserError) { return result; } } - return SymbolDataParserErrorIssue; + error.issues.push(...unionError.issues); + + return addIssue(error, "respect at least one union value", data, self.definition.errorMessage); }, isAsynchronous: (self) => DArray.some( self.definition.options, diff --git a/scripts/number/types/isGreater.ts b/scripts/number/types/isGreater.ts index b6126bf94..202ccb1bc 100644 --- a/scripts/number/types/isGreater.ts +++ b/scripts/number/types/isGreater.ts @@ -55,15 +55,89 @@ type CheckIsGreater< : never : false; +type toStringDecimal< + GenericValue extends number, +> = `${GenericValue}` extends `${DString.Number}.${DString.Number}` + ? `${GenericValue}` + : `${GenericValue}.0`; + +type PrepareValues< + GenericValue extends number, + GenericReference extends number, +> = [ + toStringDecimal, + toStringDecimal, +] extends [ + `${infer InferredValueInteger extends DString.Number}.${infer InferredValueDecimals extends DString.Number}`, + `${infer InferredReferenceInteger extends DString.Number}.${infer InferredReferenceDecimals extends DString.Number}`, +] + ? And<[ + IsEqual, + IsEqual, + ]> extends true + ? [InferredValueInteger, InferredReferenceInteger] + : IsEqual< + InferredValueInteger, + InferredReferenceInteger + > extends true + ? [ + DString.Split, + DString.Split, + ] extends [ + infer InferredSplitValue extends AnyTuple, + infer InferredSplitReference extends AnyTuple, + ] + ? ( + IsEqual extends true + ? [ + DArray.JoinTuple, + DArray.JoinTuple, + ] + : ( + DArray.CreateTuple extends [...DArray.CreateTuple, ...any[]] + ? InferredSplitValue["length"] + : InferredSplitReference["length"] + ) extends infer InferredLength extends number + ? [ + DArray.JoinTuple< + Extract< + IsEqual extends true + ? InferredSplitValue + : DArray.CreateTuple<"0", InferredLength, InferredSplitValue>, + AnyTuple + >, + "" + >, + DArray.JoinTuple< + Extract< + IsEqual extends true + ? InferredSplitReference + : DArray.CreateTuple<"0", InferredLength, InferredSplitReference>, + AnyTuple + >, + "" + >, + ] + : never + ) extends [ + `${infer InferredResultValue}`, + `${infer InferredResultReference}`, + ] + ? [`${InferredResultValue}`, `${InferredResultReference}`] + : never + : never + : [InferredValueInteger, InferredReferenceInteger] + : never; + export type IsGreater< GenericValue extends number, GenericReference extends number, > = IsEqual extends true ? true - : [ - `${GenericValue}`, - `${GenericReference}`, - ] extends [ + : PrepareValues< + GenericValue, + GenericReference + > extends [ infer InferredValue extends DString.Number, infer InferredReference extends DString.Number, ] diff --git a/scripts/string/length.ts b/scripts/string/length.ts index e41bcc53b..1fc186c36 100644 --- a/scripts/string/length.ts +++ b/scripts/string/length.ts @@ -1,10 +1,12 @@ -import { type StringLength } from "./types/stringLength"; +import { type TemplateLiteralContainLargeType, type StringLength } from "./types"; /** * {@include string/length/index.md} */ export function length< GenericInput extends string, ->(input: GenericInput): StringLength { - return input.length; +>(input: GenericInput): TemplateLiteralContainLargeType extends true + ? number + : StringLength { + return input.length as never; } diff --git a/scripts/string/types/split.ts b/scripts/string/types/split.ts index 111428e09..3036020b1 100644 --- a/scripts/string/types/split.ts +++ b/scripts/string/types/split.ts @@ -1,6 +1,7 @@ -import { type Or, type IsEqual } from "@scripts/common"; +import { type IsEqual } from "@scripts/common"; import { type Includes } from "./includes"; import { type TemplateLiteralContainLargeType } from "./templateLiteralContainLargeType"; +import { type CreateTuple } from "@scripts/array"; type _Split< GenericString extends string, @@ -32,13 +33,22 @@ export type Split< GenericLimit extends number = number, > = IsEqual extends true ? [] - : Or<[ - TemplateLiteralContainLargeType, - TemplateLiteralContainLargeType, - ]> extends true + : TemplateLiteralContainLargeType extends true ? [string, ...string[]] - : _Split< - GenericString, - GenericSeparator, - GenericLimit - >; + : TemplateLiteralContainLargeType extends true + ? [ + ...CreateTuple< + string, + _Split< + GenericString, + GenericSeparator, + GenericLimit + >["length"] + >, + ...string[], + ] + : _Split< + GenericString, + GenericSeparator, + GenericLimit + >; diff --git a/tests/clean/constraint/cast.test.ts b/tests/clean/constraint/cast.test.ts new file mode 100644 index 000000000..466188a7d --- /dev/null +++ b/tests/clean/constraint/cast.test.ts @@ -0,0 +1,221 @@ +import { DClean, DPE, unwrap, type ExpectType } from "@scripts"; + +describe("castConstraint", () => { + it("adds a single constraint to an already constrained value", () => { + const base = DClean.StringMin(5).createOrThrow("hello"); + const result = DClean.castConstraint(base, DClean.StringMin(3)); + + expect(result).toStrictEqual( + DClean.constrainedTypeKind.addTo( + base, + { + "string-min-5": null, + "string-min-3": null, + }, + ), + ); + + expect(DClean.StringMin(3).is(result)).toBe(true); + expect(DClean.StringMin(5).is(result)).toBe(true); + + type Check = ExpectType< + typeof result, + & DClean.ConstrainedType<"string-min-5", "hello"> + & DClean.ConstrainedType<"string-min-3", string>, + "strict" + >; + }); + + it("adds multiple constraints when handlers are provided as an array", () => { + const base = DClean.NumberMin(5).createOrThrow(7); + const result = DClean.castConstraint( + base, + [ + DClean.NumberMin(3), + DClean.NumberMin(-1), + ], + ); + + expect(result).toStrictEqual( + DClean.constrainedTypeKind.addTo( + base, + { + "number-min-5": null, + "number-min-3": null, + "number-min--1": null, + }, + ), + ); + + type Check = ExpectType< + typeof result, + & DClean.ConstrainedType<"number-min-5", 7> + & DClean.ConstrainedType<"number-min-3", number> + & DClean.ConstrainedType<"number-min--1", number>, + "strict" + >; + }); + + it("preserves wrapped value identity while extending constraint metadata", () => { + const base = DClean.createNewType("nt", DPE.number(), DClean.NumberMax(2)).createOrThrow(-2); + const result = DClean.castConstraint(base, DClean.NumberMax(5)); + + expect(result).not.toBe(base); + expect(unwrap(result)).toBe(unwrap(base)); + expect(unwrap(result)).toBe(-2); + expect(DClean.constrainedTypeKind.getValue(result)).toStrictEqual({ + "number-max-2": null, + "number-max-5": null, + }); + }); + + it("supports every valid cast combination at the type level", () => { + const positive = DClean.Positive.createOrThrow(2); + const numberMinFromPositive = DClean.castConstraint( + positive, + DClean.NumberMin(-5), + ); + type CheckNumberMinFromPositive = ExpectType< + typeof numberMinFromPositive, + & DClean.ConstrainedType<"positive", 2> + & DClean.ConstrainedType<"number-min--5", number>, + "strict" + >; + + DClean.castConstraint( + //@ts-expect-error 10 is greater than zero + positive, + DClean.NumberMin(10), + ); + + const numberMin = DClean.NumberMin(5).createOrThrow(7); + const narrowedNumberMin = DClean.castConstraint( + numberMin, + DClean.NumberMin(3), + ); + type CheckNumberMinFromNumberMin = ExpectType< + typeof narrowedNumberMin, + & DClean.ConstrainedType<"number-min-5", 7> + & DClean.ConstrainedType<"number-min-3", number>, + "strict" + >; + + DClean.castConstraint( + //@ts-expect-error 50 is greater than 6 + numberMin, + DClean.NumberMin(50), + ); + + const negative = DClean.Negative.createOrThrow(-2); + const numberMaxFromNegative = DClean.castConstraint( + negative, + DClean.NumberMax(20), + ); + type CheckNumberMaxFromNegative = ExpectType< + typeof numberMaxFromNegative, + & DClean.ConstrainedType<"negative", -2> + & DClean.ConstrainedType<"number-max-20", number>, + "strict" + >; + + DClean.castConstraint( + //@ts-expect-error -60 is less than zero + negative, + DClean.NumberMax(-60), + ); + + const numberMax = DClean.NumberMax(2).createOrThrow(-1); + const widenedNumberMax = DClean.castConstraint( + numberMax, + DClean.NumberMax(5), + ); + type CheckNumberMaxFromNumberMax = ExpectType< + typeof widenedNumberMax, + & DClean.ConstrainedType<"number-max-2", -1> + & DClean.ConstrainedType<"number-max-5", number>, + "strict" + >; + + DClean.castConstraint( + //@ts-expect-error -2 is less than 2 + numberMax, + DClean.NumberMax(-22), + ); + + const stringMin = DClean.StringMin(5).createOrThrow("hello"); + const narrowedStringMin = DClean.castConstraint( + stringMin, + DClean.StringMin(3), + ); + type CheckStringMinFromStringMin = ExpectType< + typeof narrowedStringMin, + & DClean.ConstrainedType<"string-min-5", "hello"> + & DClean.ConstrainedType<"string-min-3", string>, + "strict" + >; + + DClean.castConstraint( + //@ts-expect-error 10 is greater than 5 + stringMin, + DClean.StringMin(10), + ); + + const stringMax = DClean.StringMax(5).createOrThrow("hello"); + const widenedStringMax = DClean.castConstraint( + stringMax, + DClean.StringMax(8), + ); + type CheckStringMaxFromStringMax = ExpectType< + typeof widenedStringMax, + & DClean.ConstrainedType<"string-max-5", "hello"> + & DClean.ConstrainedType<"string-max-8", string>, + "strict" + >; + + DClean.castConstraint( + //@ts-expect-error -800 is less than 5 + stringMax, + DClean.StringMax(-800), + ); + + const positiveFromNumberMin = DClean.castConstraint( + DClean.NumberMin(15).createOrThrow(20), + DClean.Positive, + ); + type CheckPositiveFromNumberMin = ExpectType< + typeof positiveFromNumberMin, + & DClean.ConstrainedType<"number-min-15", 20> + & DClean.ConstrainedType<"positive", number>, + "strict" + >; + + DClean.castConstraint( + //@ts-expect-error -2 is less than 0 + DClean.NumberMin(-2).createOrThrow(3), + DClean.Positive, + ); + + const negativeFromNumberMin = DClean.castConstraint( + DClean.NumberMax(-10).createOrThrow(-60), + DClean.Negative, + ); + type CheckNegativeFromNumberMin = ExpectType< + typeof negativeFromNumberMin, + & DClean.ConstrainedType<"number-max--10", -60> + & DClean.ConstrainedType<"negative", number>, + "strict" + >; + + DClean.castConstraint( + //@ts-expect-error 10 is greater than 0 + DClean.NumberMax(10).createOrThrow(-60), + DClean.Negative, + ); + + DClean.castConstraint( + //@ts-expect-error no casting possible + DClean.NumberMax(10).createOrThrow(-60), + DClean.Email, + ); + }); +}); diff --git a/tests/clean/constraint/index.test.ts b/tests/clean/constraint/index.test.ts index 389ee53b7..3e893f59a 100644 --- a/tests/clean/constraint/index.test.ts +++ b/tests/clean/constraint/index.test.ts @@ -38,10 +38,12 @@ describe("createConstraint", () => { it("create returns error on invalid input", () => { const result = constraint.create("hi"); - const expectedError = DDataParser.addIssue( - DDataParser.createError(), - minLengthChecker, + const expectedError = DDataParser.createError(); + DDataParser.addIssue( + expectedError, + "string.length >= 3", "hi", + undefined, ); expect(result).toStrictEqual( diff --git a/tests/clean/constraint/set.test.ts b/tests/clean/constraint/set.test.ts index b52d420f9..fb6c9737b 100644 --- a/tests/clean/constraint/set.test.ts +++ b/tests/clean/constraint/set.test.ts @@ -43,10 +43,12 @@ describe("createConstraintsSet", () => { it("create returns error on invalid input", () => { const result = handler.create("hi"); - const expectedError = DDataParser.addIssue( - DDataParser.createError(), - minConstraint.checkers[0], + const expectedError = DDataParser.createError(); + DDataParser.addIssue( + expectedError, + "string.length >= 3", "hi", + undefined, ); expect(result).toStrictEqual( diff --git a/tests/clean/newType.test.ts b/tests/clean/newType.test.ts index 4652e9e3b..90d96d906 100644 --- a/tests/clean/newType.test.ts +++ b/tests/clean/newType.test.ts @@ -50,10 +50,12 @@ describe("createNewType", () => { it("create returns error on invalid input", () => { const result = handler.create("too long"); - const expectedError = DDataParser.addIssue( - DDataParser.createError(), - constraint.checkers[0], + const expectedError = DDataParser.createError(); + DDataParser.addIssue( + expectedError, + "string.length <= 5", "too long", + undefined, ); expect(result).toStrictEqual( diff --git a/tests/clean/primitive/base.test.ts b/tests/clean/primitive/base.test.ts index 0c707e87f..7f0c56d08 100644 --- a/tests/clean/primitive/base.test.ts +++ b/tests/clean/primitive/base.test.ts @@ -16,10 +16,12 @@ describe("primitive handler String", () => { const invalidValue = 10; const result = DClean.String.create(invalidValue as never); - const expectedError = DDataParser.addIssue( - DDataParser.createError(), - DClean.String.dataParser, + const expectedError = DDataParser.createError(); + DDataParser.addIssue( + expectedError, + "string", invalidValue, + undefined, ); expect(result).toStrictEqual( @@ -39,10 +41,12 @@ describe("primitive handler String", () => { it("createOrThrow throws on invalid value with error details", () => { const invalidValue = 10; - const expectedError = DDataParser.addIssue( - DDataParser.createError(), - DClean.String.dataParser, + const expectedError = DDataParser.createError(); + DDataParser.addIssue( + expectedError, + "string", invalidValue, + undefined, ); expect(() => DClean.String.createOrThrow(invalidValue as never)).toThrow(DClean.CreatePrimitiveError); diff --git a/tests/clean/primitive/operations/equal.test.ts b/tests/clean/primitive/operations/equal.test.ts index 3a1553bba..68c50228b 100644 --- a/tests/clean/primitive/operations/equal.test.ts +++ b/tests/clean/primitive/operations/equal.test.ts @@ -3,7 +3,7 @@ import { type Primitive } from "@scripts/clean"; describe("equal", () => { it("returns true for primitives with same underlying value", () => { - const one = DClean.Number.createOrThrow(1); + const one = DClean.Number.createOrThrow(1 as number); const same = DClean.Number.createOrThrow(1); const result = DClean.equal(one, same); @@ -12,7 +12,7 @@ describe("equal", () => { if (result) { type Check = ExpectType< typeof one, - typeof same, + DClean.Primitive & DClean.Primitive<1>, "strict" >; } @@ -27,17 +27,6 @@ describe("equal", () => { expect(DClean.equal(one, two)).toBe(false); }); - it("supports curried usage", () => { - const one = DClean.Number.createOrThrow(1); - const isEqual = DClean.equal(one); - - const result = isEqual( - DClean.Number.createOrThrow(1), - ); - - expect(result).toBe(true); - }); - it("works with date primitives", () => { const dateValue = DClean.Date.createOrThrow("date1700000000+"); const sameDate = DClean.Date.createOrThrow("date1700000000+"); @@ -47,16 +36,34 @@ describe("equal", () => { expect(DClean.equal(dateValue, otherDate)).toBe(false); }); + it("works with null", () => { + const dateValue = DClean.Date.createOrThrow("date1700000000+") as DClean.Date | null; + + const result = DClean.equal(dateValue, null); + + expect(result).toBe(false); + expect(DClean.equal(null as DClean.Date | null, dateValue)).toBe(false); + expect(DClean.equal(null, null)).toBe(true); + + if (result) { + type check = ExpectType< + typeof dateValue, + null, + "strict" + >; + } + }); + it("works in pipe with when", () => { - const one = DClean.Number.createOrThrow(1); + const one = DClean.Number.createOrThrow(1 as number); const result = pipe( one, when( - DClean.equal(DClean.Number.createOrThrow(1)), + DClean.equal(1), (value) => { type Check = ExpectType< typeof value, - typeof one, + DClean.Primitive & DClean.Primitive<1>, "strict" >; diff --git a/tests/clean/toMapDataParser.test.ts b/tests/clean/toMapDataParser.test.ts new file mode 100644 index 000000000..444b52eb2 --- /dev/null +++ b/tests/clean/toMapDataParser.test.ts @@ -0,0 +1,112 @@ +import { DClean, DDataParser, DEither, keyWrappedValue, pipe, type ExpectType } from "@scripts"; + +describe("toMapDataParser", () => { + it("maps newType handler to a data parser with newType and constraint kinds", () => { + const newTypeLabel = DClean.createNewType( + "Label", + DDataParser.string(), + [DClean.StringMax(5)], + ); + const parser = DClean.toMapDataParser(newTypeLabel); + + const result = parser.parse("hello"); + + expect(result).toStrictEqual( + DEither.success({ + ...DClean.newTypeKind.setTo({}, "Label"), + ...DClean.constrainedTypeKind.setTo({}, newTypeLabel.internal.constraintKindValue), + [keyWrappedValue]: "hello", + }), + ); + + const value = parser.parseOrThrow("hello"); + + type Check = ExpectType< + typeof value, + DClean.GetNewType, + "strict" + >; + }); + + it("maps constraint handler to a data parser with constraint kind", () => { + const constraint = DClean.StringMax(5); + const parser = DClean.toMapDataParser(constraint); + + const result = parser.parse("hey"); + + expect(result).toStrictEqual( + DEither.success({ + ...DClean.constrainedTypeKind.setTo({}, constraint.internal.constraintKindValue), + [keyWrappedValue]: "hey", + }), + ); + + const value = parser.parseOrThrow("hey"); + + type Check = ExpectType< + typeof value, + DClean.GetConstraint, + "strict" + >; + }); + + it("maps constraints set handler to a data parser with constraint kinds", () => { + const minConstraint = DClean.StringMin(2); + const maxConstraint = DClean.StringMax(5); + const constraintsSet = DClean.createConstraintsSet( + DClean.String, + [minConstraint, maxConstraint], + ); + const parser = DClean.toMapDataParser(constraintsSet); + + const result = parser.parse("test"); + + expect(result).toStrictEqual( + DEither.success({ + ...DClean.constrainedTypeKind.setTo({}, constraintsSet.internal.constraintKindValue), + [keyWrappedValue]: "test", + }), + ); + + const value = parser.parseOrThrow("test"); + + type Check = ExpectType< + typeof value, + DClean.GetConstraints, + "strict" + >; + }); + + it("maps primitive handler to a data parser with wrapped value only", () => { + const parser = DClean.toMapDataParser(DClean.String); + + const result = parser.parse("hello"); + + expect(result).toStrictEqual( + DEither.success({ + [keyWrappedValue]: "hello", + }), + ); + + const value = parser.parseOrThrow("hello"); + + type Check = ExpectType< + typeof value, + DClean.String, + "strict" + >; + }); + + it("supports coerce option on supported parsers", () => { + const parser = DClean.toMapDataParser( + DClean.String, + { coerce: true }, + ); + + const result = parser.parseOrThrow(42); + + expect(result).toStrictEqual({ + [keyWrappedValue]: "42", + }); + }); +}); diff --git a/tests/common/printer.test.ts b/tests/common/printer.test.ts new file mode 100644 index 000000000..3aa583249 --- /dev/null +++ b/tests/common/printer.test.ts @@ -0,0 +1,89 @@ +import { pipe, Printer, type ExpectType } from "@scripts"; + +describe("Printer", () => { + it("colorized supports direct and curried calls", () => { + const directResult = Printer.colorized("value", "red"); + const curriedResult = pipe( + "value", + Printer.colorized("red"), + ); + + expect(directResult).toBe("\x1b[31mvalue\x1b[0m"); + expect(curriedResult).toBe("\x1b[31mvalue\x1b[0m"); + + type CheckDirect = ExpectType< + typeof directResult, + string, + "strict" + >; + + type CheckCurried = ExpectType< + typeof curriedResult, + string, + "strict" + >; + }); + + it("colorizedBold supports direct and curried calls", () => { + const directResult = Printer.colorizedBold("value", "cyan"); + const curriedResult = pipe( + "value", + Printer.colorizedBold("cyan"), + ); + + expect(directResult).toBe("\x1b[1m\x1b[36mvalue\x1b[0m\x1b[0m"); + expect(curriedResult).toBe("\x1b[1m\x1b[36mvalue\x1b[0m\x1b[0m"); + + type CheckDirect = ExpectType< + typeof directResult, + string, + "strict" + >; + + type CheckCurried = ExpectType< + typeof curriedResult, + string, + "strict" + >; + }); + + it("render helpers flatten nested values and skip falsy non-string values", () => { + const lineResult = Printer.renderLine([ + "alpha", + ["beta", false, null, undefined], + true, + ["gamma"], + ]); + const paragraphResult = pipe( + [ + "title", + ["", "body"], + false, + true, + ] as const, + Printer.renderParagraph, + ); + + expect(lineResult).toBe("alpha beta true gamma"); + expect(paragraphResult).toBe("title\n\nbody\ntrue"); + }); + + it("stringify returns JSON when possible and falls back to string coercion", () => { + const objectResult = Printer.stringify({ + name: "duplo", + }); + const bigintResult = Printer.stringify(12n); + const circular = {} as { + self?: unknown; + toString(): string; + }; + circular.self = circular; + circular.toString = () => "[Circular]"; + + const circularResult = Printer.stringify(circular); + + expect(objectResult).toBe("{\"name\":\"duplo\"}"); + expect(bigintResult).toBe("12"); + expect(circularResult).toBe("[Circular]"); + }); +}); diff --git a/tests/dataParser/base.test.ts b/tests/dataParser/base.test.ts index 1a53a2c5d..9dec9ed3b 100644 --- a/tests/dataParser/base.test.ts +++ b/tests/dataParser/base.test.ts @@ -101,7 +101,7 @@ describe("base parser", () => { expect(result).toStrictEqual(DEither.success(5)); expect(exec).toHaveBeenCalledWith(5, DDataParser.createError(), parser); - expect(execChecker).toHaveBeenCalledWith(5, checker); + expect(execChecker).toHaveBeenCalledWith(5, DDataParser.createError(), checker); }); it("parseOrThrow returns value on success", () => { @@ -114,50 +114,6 @@ describe("base parser", () => { expect(() => parser.parseOrThrow("test")).toThrow(DDataParser.DataParserThrowError); }); - it("run base exec and return error", () => { - const result = parser.parse("test"); - - expect(result).toStrictEqual(DEither.error( - DDataParser.addIssue( - DDataParser.createError(), - parser, - "test", - ), - )); - expect(exec).toHaveBeenCalledWith( - "test", - DDataParser.addIssue( - DDataParser.createError(), - parser, - "test", - ), - parser, - ); - expect(execChecker).toHaveBeenCalledTimes(0); - }); - - it("run base exec and check return error", () => { - const result = parser.parse(-1); - - expect(result).toStrictEqual(DEither.error( - DDataParser.addIssue( - DDataParser.createError(), - checker, - -1, - ), - )); - expect(exec).toHaveBeenCalledWith( - -1, - DDataParser.addIssue( - DDataParser.createError(), - checker, - -1, - ), - parser, - ); - expect(execChecker).toHaveBeenCalledWith(-1, checker); - }); - it("run base exec and check return error", () => { const parser = DDataParser.dataParserInit( dataParserTestKind as never, @@ -231,32 +187,6 @@ describe("base parser", () => { ); }); - it("promise issue", () => { - const parser = DDataParser.dataParserInit( - dataParserTestKind as never, - { - errorMessage: "invalid", - checkers: [], - }, - () => DDataParser.SymbolDataParserErrorPromiseIssue, - specificOverrideHandler, - ); - - const result = parser.parse(-1); - - expect(result).toStrictEqual( - DEither.error( - DDataParser.addPromiseIssue( - DDataParser.createError(), - parser as never, - -1, - ), - ), - ); - - expect(specificOverrideHandler.apply).toHaveBeenCalledOnce(); - }); - it("isAsynchronous", () => { expect(parser.isAsynchronous()).toBe(false); }); @@ -309,7 +239,7 @@ describe("base parser", () => { expect(result).toStrictEqual(DEither.success(5)); expect(exec).toHaveBeenCalledWith(5, DDataParser.createError(), parser); - expect(execChecker).toHaveBeenCalledWith(5, checker); + expect(execChecker).toHaveBeenCalledWith(5, DDataParser.createError(), checker); }); it("asyncParseOrThrow returns value on success", async() => { @@ -322,50 +252,6 @@ describe("base parser", () => { await expect(parser.asyncParseOrThrow("test")).rejects.toThrow(DDataParser.DataParserThrowError); }); - it("run base exec and return error", async() => { - const result = await parser.asyncParse("test"); - - expect(result).toStrictEqual(DEither.error( - DDataParser.addIssue( - DDataParser.createError(), - parser, - "test", - ), - )); - expect(exec).toHaveBeenCalledWith( - "test", - DDataParser.addIssue( - DDataParser.createError(), - parser, - "test", - ), - parser, - ); - expect(execChecker).toHaveBeenCalledTimes(0); - }); - - it("run base exec and check return error", async() => { - const result = await parser.asyncParse(-1); - - expect(result).toStrictEqual(DEither.error( - DDataParser.addIssue( - DDataParser.createError(), - checker, - -1, - ), - )); - expect(exec).toHaveBeenCalledWith( - -1, - DDataParser.addIssue( - DDataParser.createError(), - checker, - -1, - ), - parser, - ); - expect(execChecker).toHaveBeenCalledWith(-1, checker); - }); - it("run base exec and check return error", async() => { const parser = DDataParser.dataParserInit( dataParserTestKind as never, @@ -383,30 +269,6 @@ describe("base parser", () => { expect(exec).toHaveBeenCalledWith(-1, DDataParser.createError(), parser); }); - it("promise issue", async() => { - const parser = DDataParser.dataParserInit( - dataParserTestKind as never, - { - errorMessage: "invalid", - checkers: [], - }, - () => DDataParser.SymbolDataParserErrorPromiseIssue, - specificOverrideHandler, - ); - - const result = await parser.asyncParse(-1); - - expect(result).toStrictEqual( - DEither.error( - DDataParser.addPromiseIssue( - DDataParser.createError(), - parser as never, - -1, - ), - ), - ); - }); - it("isAsynchronous", () => { expect(parser.isAsynchronous()).toBe(true); }); diff --git a/tests/dataParser/error.test.ts b/tests/dataParser/error.test.ts index fed9ef1ab..1dab0d151 100644 --- a/tests/dataParser/error.test.ts +++ b/tests/dataParser/error.test.ts @@ -1,13 +1,6 @@ -import { DDataParser } from "@scripts"; +import { DDataParser, DEither, Printer } from "@scripts"; describe("dataParser error helpers", () => { - it("SymbolDataParserError constants", () => { - expect(typeof DDataParser.SymbolDataParserErrorIssue).toBe("symbol"); - expect( - Symbol.keyFor(DDataParser.SymbolDataParserErrorIssue), - ).toBe(DDataParser.SymbolDataParserErrorIssueLabel); - }); - it("createError returns kind-wrapped accumulator", () => { const error = DDataParser.createError(); @@ -32,28 +25,20 @@ describe("dataParser error helpers", () => { expect(error.currentPath).toStrictEqual(["user", "email"]); }); - it("addIssue stores source with joined path and popErrorPath removes last segment", () => { + it("addIssue stores expected with joined path and popErrorPath removes last segment", () => { const error = DDataParser.createError(); - const parser = DDataParser.string(); DDataParser.setErrorPath(error, "user", 0); DDataParser.setErrorPath(error, "email", 1); - DDataParser.addIssue(error, parser, undefined); - DDataParser.addPromiseIssue(error, parser as never, undefined); + DDataParser.addIssue(error, "value", undefined, undefined); expect(error.issues).toStrictEqual([ DDataParser.errorIssueKind.addTo({ - source: parser, + expected: "value", path: "user.email", data: undefined, - moreInformation: undefined, - }), - DDataParser.errorPromiseIssueKind.addTo({ - source: parser, - path: "user.email", - data: undefined, - moreInformation: undefined, + message: undefined, }), ]); @@ -61,4 +46,83 @@ describe("dataParser error helpers", () => { expect(afterPop).toBe(error); expect(error.currentPath).toStrictEqual(["user"]); }); + + it("interpretError renders multiple nested issues", () => { + const error = DDataParser.createError(); + + DDataParser.setErrorPath(error, "user", 0); + DDataParser.setErrorPath(error, "email", 1); + DDataParser.addIssue(error, "string with max 5 characters", "tonton", "email is invalid"); + + DDataParser.setErrorPath(error, "useAsyncRetry", 0); + DDataParser.setErrorPath(error, "(option 1)", 1); + DDataParser.setErrorPath(error, "age", 2); + DDataParser.addIssue(error, "number >= 18", "15", "age too small"); + + expect(DDataParser.interpretError(error)).toBe( + Printer.renderParagraph([ + Printer.colorizedBold("Validation failed", "red"), + Printer.renderParagraph([ + "", + Printer.renderLine([ + Printer.colorizedBold("✖", "red"), + Printer.colorizedBold("user.email", "cyan"), + "expected", + Printer.colorized("string with max 5 characters", "green"), + "but received", + Printer.colorized("\"tonton\"", "red"), + ]), + `${Printer.indent(1)}↳ email is invalid`, + ]), + Printer.renderParagraph([ + "", + Printer.renderLine([ + Printer.colorizedBold("✖", "red"), + Printer.colorizedBold("useAsyncRetry.(option 1).age", "cyan"), + "expected", + Printer.colorized("number >= 18", "green"), + "but received", + Printer.colorized("\"15\"", "red"), + ]), + `${Printer.indent(1)}↳ age too small`, + ]), + ]), + ); + }); + + it("interpretError renders no issue found for empty errors and supports either left input", () => { + const error = DDataParser.createError(); + const eitherError = DEither.left("error", error); + + expect(DDataParser.interpretError(eitherError)).toBe( + Printer.renderParagraph([ + Printer.colorizedBold("Validation failed", "red"), + "No issue found", + ]), + ); + }); + + it("interpretError renders root when issue path is empty", () => { + const error = DDataParser.createError(); + + DDataParser.addIssue(error, "string", "", "root issue"); + + expect(DDataParser.interpretError(error)).toBe( + Printer.renderParagraph([ + Printer.colorizedBold("Validation failed", "red"), + Printer.renderParagraph([ + "", + Printer.renderLine([ + Printer.colorizedBold("✖", "red"), + Printer.colorizedBold("", "cyan"), + "expected", + Printer.colorized("string", "green"), + "but received", + Printer.colorized("\"\"", "red"), + ]), + `${Printer.indent(1)}↳ root issue`, + ]), + ]), + ); + }); }); diff --git a/tests/dataParser/parsers/array/checkers/max.test.ts b/tests/dataParser/parsers/array/checkers/max.test.ts index ac1b0c90d..745630a6e 100644 --- a/tests/dataParser/parsers/array/checkers/max.test.ts +++ b/tests/dataParser/parsers/array/checkers/max.test.ts @@ -30,11 +30,17 @@ describe("DDataParser array checker max", () => { expect(result).toStrictEqual( DEither.error( - DDataParser.addIssue( - DDataParser.createError(), - checker, - ["one", "two", "three"], - ), + DDataParser.errorKind.addTo({ + issues: [ + DDataParser.errorIssueKind.addTo({ + expected: "array.length <= 2", + path: "", + data: ["one", "two", "three"], + message: undefined, + }), + ], + currentPath: [], + }), ), ); }); diff --git a/tests/dataParser/parsers/array/checkers/min.test.ts b/tests/dataParser/parsers/array/checkers/min.test.ts index 7ca0b34bb..dc4f20dab 100644 --- a/tests/dataParser/parsers/array/checkers/min.test.ts +++ b/tests/dataParser/parsers/array/checkers/min.test.ts @@ -30,11 +30,17 @@ describe("DDataParser array checker min", () => { expect(result).toStrictEqual( DEither.error( - DDataParser.addIssue( - DDataParser.createError(), - checker, - ["a", "b"], - ), + DDataParser.errorKind.addTo({ + issues: [ + DDataParser.errorIssueKind.addTo({ + expected: "array.length >= 3", + path: "", + data: ["a", "b"], + message: undefined, + }), + ], + currentPath: [], + }), ), ); }); diff --git a/tests/dataParser/parsers/array/index.test.ts b/tests/dataParser/parsers/array/index.test.ts index 247a0e1a1..c8c70a02c 100644 --- a/tests/dataParser/parsers/array/index.test.ts +++ b/tests/dataParser/parsers/array/index.test.ts @@ -35,11 +35,17 @@ describe("DDataParser array", () => { expect(result).toStrictEqual( DEither.error( - DDataParser.addIssue( - DDataParser.createError(), - schema, - "not-array", - ), + DDataParser.errorKind.addTo({ + issues: [ + DDataParser.errorIssueKind.addTo({ + expected: "array", + path: "", + data: "not-array", + message: undefined, + }), + ], + currentPath: [], + }), ), ); }); @@ -52,18 +58,17 @@ describe("DDataParser array", () => { expect(result).toStrictEqual( DEither.error( - { - ...DDataParser.addIssue( - DDataParser.setErrorPath( - DDataParser.createError(), - "[0]", - 0, - ), - elementSchema, - 42, - ), + DDataParser.errorKind.addTo({ + issues: [ + DDataParser.errorIssueKind.addTo({ + expected: "string", + path: "[0]", + data: 42, + message: undefined, + }), + ], currentPath: [], - }, + }), ), ); }); @@ -85,11 +90,17 @@ describe("DDataParser array", () => { expect(result).toStrictEqual( DEither.error( - DDataParser.addIssue( - DDataParser.createError(), - schema, - "not-array", - ), + DDataParser.errorKind.addTo({ + issues: [ + DDataParser.errorIssueKind.addTo({ + expected: "array", + path: "", + data: "not-array", + message: undefined, + }), + ], + currentPath: [], + }), ), ); }); @@ -102,18 +113,17 @@ describe("DDataParser array", () => { expect(result).toStrictEqual( DEither.error( - { - ...DDataParser.addIssue( - DDataParser.setErrorPath( - DDataParser.createError(), - "[0]", - 0, - ), - elementSchema, - 42, - ), + DDataParser.errorKind.addTo({ + issues: [ + DDataParser.errorIssueKind.addTo({ + expected: "string", + path: "[0]", + data: 42, + message: undefined, + }), + ], currentPath: [], - }, + }), ), ); }); diff --git a/tests/dataParser/parsers/bigint/checkers/max.test.ts b/tests/dataParser/parsers/bigint/checkers/max.test.ts index 56baca4a2..0148c92b7 100644 --- a/tests/dataParser/parsers/bigint/checkers/max.test.ts +++ b/tests/dataParser/parsers/bigint/checkers/max.test.ts @@ -22,11 +22,17 @@ describe("DDataParser bigint checker max", () => { expect(result).toStrictEqual( DEither.error( - DDataParser.addIssue( - DDataParser.createError(), - checker, - 11n, - ), + DDataParser.errorKind.addTo({ + issues: [ + DDataParser.errorIssueKind.addTo({ + expected: "bigint <= 10n", + path: "", + data: 11n, + message: undefined, + }), + ], + currentPath: [], + }), ), ); }); diff --git a/tests/dataParser/parsers/bigint/checkers/min.test.ts b/tests/dataParser/parsers/bigint/checkers/min.test.ts index 8cb901cc3..6ed698710 100644 --- a/tests/dataParser/parsers/bigint/checkers/min.test.ts +++ b/tests/dataParser/parsers/bigint/checkers/min.test.ts @@ -22,11 +22,17 @@ describe("DDataParser bigint checker min", () => { expect(result).toStrictEqual( DEither.error( - DDataParser.addIssue( - DDataParser.createError(), - checker, - -1n, - ), + DDataParser.errorKind.addTo({ + issues: [ + DDataParser.errorIssueKind.addTo({ + expected: "bigint >= 0n", + path: "", + data: -1n, + message: undefined, + }), + ], + currentPath: [], + }), ), ); }); diff --git a/tests/dataParser/parsers/bigint/index.test.ts b/tests/dataParser/parsers/bigint/index.test.ts index ab9e180e1..8a2ff1917 100644 --- a/tests/dataParser/parsers/bigint/index.test.ts +++ b/tests/dataParser/parsers/bigint/index.test.ts @@ -37,11 +37,17 @@ describe("DDataParser bigint", () => { expect(result).toStrictEqual( DEither.error( - DDataParser.addIssue( - DDataParser.createError(), - schema, - 10, - ), + DDataParser.errorKind.addTo({ + issues: [ + DDataParser.errorIssueKind.addTo({ + expected: "bigint", + path: "", + data: 10, + message: "not-bigint", + }), + ], + currentPath: [], + }), ), ); }); diff --git a/tests/dataParser/parsers/boolean.test.ts b/tests/dataParser/parsers/boolean.test.ts index 2246cf9df..85755b4ad 100644 --- a/tests/dataParser/parsers/boolean.test.ts +++ b/tests/dataParser/parsers/boolean.test.ts @@ -27,11 +27,17 @@ describe("DDataParser boolean", () => { schema.parse("true"), ).toStrictEqual( DEither.error( - DDataParser.addIssue( - DDataParser.createError(), - schema, - "true", - ), + DDataParser.errorKind.addTo({ + issues: [ + DDataParser.errorIssueKind.addTo({ + expected: "boolean", + path: "", + data: "true", + message: "boolean.invalid", + }), + ], + currentPath: [], + }), ), ); }); @@ -57,11 +63,17 @@ describe("DDataParser boolean", () => { expect(result).toStrictEqual( DEither.error( - DDataParser.addIssue( - DDataParser.createError(), - schema, - "yes", - ), + DDataParser.errorKind.addTo({ + issues: [ + DDataParser.errorIssueKind.addTo({ + expected: "boolean", + path: "", + data: "yes", + message: "boolean.invalid", + }), + ], + currentPath: [], + }), ), ); }); @@ -76,11 +88,17 @@ describe("DDataParser boolean", () => { expect(result).toStrictEqual( DEither.error( - DDataParser.addIssue( - DDataParser.createError(), - schema, - 12n, - ), + DDataParser.errorKind.addTo({ + issues: [ + DDataParser.errorIssueKind.addTo({ + expected: "boolean", + path: "", + data: 12n, + message: "boolean.invalid", + }), + ], + currentPath: [], + }), ), ); }); diff --git a/tests/dataParser/parsers/date.test.ts b/tests/dataParser/parsers/date.test.ts index 64968b7e7..15e275bb6 100644 --- a/tests/dataParser/parsers/date.test.ts +++ b/tests/dataParser/parsers/date.test.ts @@ -29,11 +29,17 @@ describe("DDataParser date", () => { expect(result).toStrictEqual( DEither.error( - DDataParser.addIssue( - DDataParser.createError(), - schema, - input, - ), + DDataParser.errorKind.addTo({ + issues: [ + DDataParser.errorIssueKind.addTo({ + expected: "date", + path: "", + data: input, + message: "date.invalid", + }), + ], + currentPath: [], + }), ), ); }); @@ -79,65 +85,107 @@ describe("DDataParser date", () => { expect(timestampResult).toStrictEqual( DEither.error( - DDataParser.addIssue( - DDataParser.createError(), - schema, - outOfRangeTimestamp, - ), + DDataParser.errorKind.addTo({ + issues: [ + DDataParser.errorIssueKind.addTo({ + expected: "date", + path: "", + data: outOfRangeTimestamp, + message: "date.invalid", + }), + ], + currentPath: [], + }), ), ); expect(monthResult).toStrictEqual( DEither.error( - DDataParser.addIssue( - DDataParser.createError(), - schema, - invalidMonth, - ), + DDataParser.errorKind.addTo({ + issues: [ + DDataParser.errorIssueKind.addTo({ + expected: "date", + path: "", + data: invalidMonth, + message: "date.invalid", + }), + ], + currentPath: [], + }), ), ); expect(dayResult).toStrictEqual( DEither.error( - DDataParser.addIssue( - DDataParser.createError(), - schema, - invalidDay, - ), + DDataParser.errorKind.addTo({ + issues: [ + DDataParser.errorIssueKind.addTo({ + expected: "date", + path: "", + data: invalidDay, + message: "date.invalid", + }), + ], + currentPath: [], + }), ), ); expect(hourResult).toStrictEqual( DEither.error( - DDataParser.addIssue( - DDataParser.createError(), - schema, - invalidHour, - ), + DDataParser.errorKind.addTo({ + issues: [ + DDataParser.errorIssueKind.addTo({ + expected: "date", + path: "", + data: invalidHour, + message: "date.invalid", + }), + ], + currentPath: [], + }), ), ); expect(typeResult).toStrictEqual( DEither.error( - DDataParser.addIssue( - DDataParser.createError(), - schema, - invalidType, - ), + DDataParser.errorKind.addTo({ + issues: [ + DDataParser.errorIssueKind.addTo({ + expected: "date", + path: "", + data: invalidType, + message: "date.invalid", + }), + ], + currentPath: [], + }), ), ); expect(dateResult).toStrictEqual( DEither.error( - DDataParser.addIssue( - DDataParser.createError(), - schema, - outOfRangeDate, - ), + DDataParser.errorKind.addTo({ + issues: [ + DDataParser.errorIssueKind.addTo({ + expected: "date", + path: "", + data: outOfRangeDate, + message: "date.invalid", + }), + ], + currentPath: [], + }), ), ); expect(unsafeTheDateResult).toStrictEqual( DEither.error( - DDataParser.addIssue( - DDataParser.createError(), - schema, - unsafeTheDate, - ), + DDataParser.errorKind.addTo({ + issues: [ + DDataParser.errorIssueKind.addTo({ + expected: "date", + path: "", + data: unsafeTheDate, + message: "date.invalid", + }), + ], + currentPath: [], + }), ), ); }); diff --git a/tests/dataParser/parsers/empty.test.ts b/tests/dataParser/parsers/empty.test.ts index 4bec713da..ee5806800 100644 --- a/tests/dataParser/parsers/empty.test.ts +++ b/tests/dataParser/parsers/empty.test.ts @@ -26,11 +26,17 @@ describe("DDataParser empty", () => { expect(result).toStrictEqual( DEither.error( - DDataParser.addIssue( - DDataParser.createError(), - schema, - "value", - ), + DDataParser.errorKind.addTo({ + issues: [ + DDataParser.errorIssueKind.addTo({ + expected: "undefined", + path: "", + data: "value", + message: "undefined.invalid", + }), + ], + currentPath: [], + }), ), ); }); @@ -41,11 +47,17 @@ describe("DDataParser empty", () => { expect(schema.parse("undefined")).toStrictEqual(DEither.success(undefined)); expect(schema.parse("not-undefined")).toStrictEqual( DEither.error( - DDataParser.addIssue( - DDataParser.createError(), - schema, - "not-undefined", - ), + DDataParser.errorKind.addTo({ + issues: [ + DDataParser.errorIssueKind.addTo({ + expected: "undefined", + path: "", + data: "not-undefined", + message: undefined, + }), + ], + currentPath: [], + }), ), ); }); diff --git a/tests/dataParser/parsers/lazy.test.ts b/tests/dataParser/parsers/lazy.test.ts index 766a23c6a..a9a9b50f3 100644 --- a/tests/dataParser/parsers/lazy.test.ts +++ b/tests/dataParser/parsers/lazy.test.ts @@ -66,11 +66,17 @@ describe("DDataParser lazy", () => { expect(result).toStrictEqual( DEither.error( - DDataParser.addIssue( - DDataParser.createError(), - inner, - "oops", - ), + DDataParser.errorKind.addTo({ + issues: [ + DDataParser.errorIssueKind.addTo({ + expected: "number", + path: "", + data: "oops", + message: "not-number", + }), + ], + currentPath: [], + }), ), ); }); @@ -115,11 +121,17 @@ describe("DDataParser lazy", () => { expect(result).toStrictEqual( DEither.error( - DDataParser.addIssue( - DDataParser.createError(), - inner, - "oops", - ), + DDataParser.errorKind.addTo({ + issues: [ + DDataParser.errorIssueKind.addTo({ + expected: "number", + path: "", + data: "oops", + message: "not-number", + }), + ], + currentPath: [], + }), ), ); }); diff --git a/tests/dataParser/parsers/literal.test.ts b/tests/dataParser/parsers/literal.test.ts index 34ea615c9..90c081d44 100644 --- a/tests/dataParser/parsers/literal.test.ts +++ b/tests/dataParser/parsers/literal.test.ts @@ -44,11 +44,17 @@ describe("literal parser", () => { expect(result).toStrictEqual( DEither.error( - DDataParser.addIssue( - DDataParser.createError(), - schema, - 1, - ), + DDataParser.errorKind.addTo({ + issues: [ + DDataParser.errorIssueKind.addTo({ + expected: "one of one", + path: "", + data: 1, + message: undefined, + }), + ], + currentPath: [], + }), ), ); }); diff --git a/tests/dataParser/parsers/nil.test.ts b/tests/dataParser/parsers/nil.test.ts index c32bcdd14..7e3ea5b42 100644 --- a/tests/dataParser/parsers/nil.test.ts +++ b/tests/dataParser/parsers/nil.test.ts @@ -26,11 +26,17 @@ describe("DDataParser null", () => { expect(result).toStrictEqual( DEither.error( - DDataParser.addIssue( - DDataParser.createError(), - schema, - "not-null", - ), + DDataParser.errorKind.addTo({ + issues: [ + DDataParser.errorIssueKind.addTo({ + expected: "null", + path: "", + data: "not-null", + message: "null.invalid", + }), + ], + currentPath: [], + }), ), ); }); @@ -41,11 +47,17 @@ describe("DDataParser null", () => { expect(schema.parse("null")).toStrictEqual(DEither.success(null)); expect(schema.parse("not-null")).toStrictEqual( DEither.error( - DDataParser.addIssue( - DDataParser.createError(), - schema, - "not-null", - ), + DDataParser.errorKind.addTo({ + issues: [ + DDataParser.errorIssueKind.addTo({ + expected: "null", + path: "", + data: "not-null", + message: undefined, + }), + ], + currentPath: [], + }), ), ); }); diff --git a/tests/dataParser/parsers/nullable.test.ts b/tests/dataParser/parsers/nullable.test.ts index 3737e1370..3ccbf699f 100644 --- a/tests/dataParser/parsers/nullable.test.ts +++ b/tests/dataParser/parsers/nullable.test.ts @@ -56,11 +56,17 @@ describe("DDataParser nullable", () => { expect(result).toStrictEqual( DEither.error( - DDataParser.addIssue( - DDataParser.createError(), - inner, - "nope", - ), + DDataParser.errorKind.addTo({ + issues: [ + DDataParser.errorIssueKind.addTo({ + expected: "number", + path: "", + data: "nope", + message: "not-number", + }), + ], + currentPath: [], + }), ), ); }); @@ -101,11 +107,17 @@ describe("DDataParser nullable", () => { expect(result).toStrictEqual( DEither.error( - DDataParser.addIssue( - DDataParser.createError(), - inner, - "nope", - ), + DDataParser.errorKind.addTo({ + issues: [ + DDataParser.errorIssueKind.addTo({ + expected: "number", + path: "", + data: "nope", + message: "not-number", + }), + ], + currentPath: [], + }), ), ); }); diff --git a/tests/dataParser/parsers/number/checkers/int.test.ts b/tests/dataParser/parsers/number/checkers/int.test.ts index ca73f6abb..984f0d1c5 100644 --- a/tests/dataParser/parsers/number/checkers/int.test.ts +++ b/tests/dataParser/parsers/number/checkers/int.test.ts @@ -22,11 +22,17 @@ describe("DDataParser number checker int", () => { expect(result).toStrictEqual( DEither.error( - DDataParser.addIssue( - DDataParser.createError(), - checker, - 3.14, - ), + DDataParser.errorKind.addTo({ + issues: [ + DDataParser.errorIssueKind.addTo({ + expected: "integer", + path: "", + data: 3.14, + message: undefined, + }), + ], + currentPath: [], + }), ), ); }); @@ -40,11 +46,17 @@ describe("DDataParser number checker int", () => { expect(result).toStrictEqual( DEither.error( - DDataParser.addIssue( - DDataParser.createError(), - schema.definition.checkers[0], - 7.5, - ), + DDataParser.errorKind.addTo({ + issues: [ + DDataParser.errorIssueKind.addTo({ + expected: "integer", + path: "", + data: 7.5, + message: undefined, + }), + ], + currentPath: [], + }), ), ); }); diff --git a/tests/dataParser/parsers/number/checkers/max.test.ts b/tests/dataParser/parsers/number/checkers/max.test.ts index 9616b7f9a..3b058e74e 100644 --- a/tests/dataParser/parsers/number/checkers/max.test.ts +++ b/tests/dataParser/parsers/number/checkers/max.test.ts @@ -22,11 +22,17 @@ describe("DDataParser number checker max", () => { expect(result).toStrictEqual( DEither.error( - DDataParser.addIssue( - DDataParser.createError(), - checker, - 11, - ), + DDataParser.errorKind.addTo({ + issues: [ + DDataParser.errorIssueKind.addTo({ + expected: "number <= 10", + path: "", + data: 11, + message: undefined, + }), + ], + currentPath: [], + }), ), ); }); diff --git a/tests/dataParser/parsers/number/checkers/min.test.ts b/tests/dataParser/parsers/number/checkers/min.test.ts index a858bd1d9..1345eba7b 100644 --- a/tests/dataParser/parsers/number/checkers/min.test.ts +++ b/tests/dataParser/parsers/number/checkers/min.test.ts @@ -22,11 +22,17 @@ describe("DDataParser number checker min", () => { expect(result).toStrictEqual( DEither.error( - DDataParser.addIssue( - DDataParser.createError(), - checker, - -1, - ), + DDataParser.errorKind.addTo({ + issues: [ + DDataParser.errorIssueKind.addTo({ + expected: "number >= 0", + path: "", + data: -1, + message: undefined, + }), + ], + currentPath: [], + }), ), ); }); diff --git a/tests/dataParser/parsers/number/index.test.ts b/tests/dataParser/parsers/number/index.test.ts index 5e3c9482d..af472d7e1 100644 --- a/tests/dataParser/parsers/number/index.test.ts +++ b/tests/dataParser/parsers/number/index.test.ts @@ -34,11 +34,17 @@ describe("DDataParser number", () => { expect(result).toStrictEqual( DEither.error( - DDataParser.addIssue( - DDataParser.createError(), - schema, - "42", - ), + DDataParser.errorKind.addTo({ + issues: [ + DDataParser.errorIssueKind.addTo({ + expected: "number", + path: "", + data: "42", + message: "error", + }), + ], + currentPath: [], + }), ), ); }); @@ -58,11 +64,17 @@ describe("DDataParser number", () => { expect(result).toStrictEqual( DEither.error( - DDataParser.addIssue( - DDataParser.createError(), - schema, - "not-a-number", - ), + DDataParser.errorKind.addTo({ + issues: [ + DDataParser.errorIssueKind.addTo({ + expected: "number", + path: "", + data: Number.NaN, + message: undefined, + }), + ], + currentPath: [], + }), ), ); }); @@ -74,11 +86,17 @@ describe("DDataParser number", () => { expect(result).toStrictEqual( DEither.error( - DDataParser.addIssue( - DDataParser.createError(), - schema, - Number.NaN, - ), + DDataParser.errorKind.addTo({ + issues: [ + DDataParser.errorIssueKind.addTo({ + expected: "number", + path: "", + data: Number.NaN, + message: undefined, + }), + ], + currentPath: [], + }), ), ); }); diff --git a/tests/dataParser/parsers/object/index.test.ts b/tests/dataParser/parsers/object/index.test.ts index 8ca799839..aa2bda07c 100644 --- a/tests/dataParser/parsers/object/index.test.ts +++ b/tests/dataParser/parsers/object/index.test.ts @@ -1,4 +1,4 @@ -import { DDataParser, DEither, pipe, type ExpectType } from "@scripts"; +import { DDataParser, DEither, type ExpectType } from "@scripts"; describe("DDataParser object", () => { it("success parsing", () => { @@ -55,9 +55,21 @@ describe("DDataParser object", () => { const result = schema.parse("mathcovax"); - expect(result).toStrictEqual(DEither.error( - DDataParser.addIssue(DDataParser.createError(), schema, "mathcovax"), - )); + expect(result).toStrictEqual( + DEither.error( + DDataParser.errorKind.addTo({ + issues: [ + DDataParser.errorIssueKind.addTo({ + expected: "object", + path: "", + data: "mathcovax", + message: undefined, + }), + ], + currentPath: [], + }), + ), + ); }); it("key type error parsing", () => { @@ -70,18 +82,17 @@ describe("DDataParser object", () => { expect(result).toStrictEqual( DEither.error( - { - ...DDataParser.addIssue( - DDataParser.setErrorPath( - DDataParser.createError(), - "name", - 0, - ), - nameSchema, - 11, - ), + DDataParser.errorKind.addTo({ + issues: [ + DDataParser.errorIssueKind.addTo({ + expected: "string", + path: "name", + data: 11, + message: undefined, + }), + ], currentPath: [], - }, + }), ), ); }); @@ -97,18 +108,17 @@ describe("DDataParser object", () => { expect(result).toStrictEqual( DEither.error( - { - ...DDataParser.addIssue( - DDataParser.setErrorPath( - DDataParser.createError(), - "name", - 0, - ), - nameSchema, - undefined, - ), + DDataParser.errorKind.addTo({ + issues: [ + DDataParser.errorIssueKind.addTo({ + expected: "string", + path: "name", + data: undefined, + message: undefined, + }), + ], currentPath: [], - }, + }), ), ); }); @@ -150,9 +160,21 @@ describe("DDataParser object", () => { const result = await schema.asyncParse("mathcovax"); - expect(result).toStrictEqual(DEither.error( - DDataParser.addIssue(DDataParser.createError(), schema, "mathcovax"), - )); + expect(result).toStrictEqual( + DEither.error( + DDataParser.errorKind.addTo({ + issues: [ + DDataParser.errorIssueKind.addTo({ + expected: "object", + path: "", + data: "mathcovax", + message: undefined, + }), + ], + currentPath: [], + }), + ), + ); }); it("key type error parsing", async() => { @@ -165,18 +187,17 @@ describe("DDataParser object", () => { expect(result).toStrictEqual( DEither.error( - { - ...DDataParser.addIssue( - DDataParser.setErrorPath( - DDataParser.createError(), - "name", - 0, - ), - nameSchema, - 11, - ), + DDataParser.errorKind.addTo({ + issues: [ + DDataParser.errorIssueKind.addTo({ + expected: "string", + path: "name", + data: 11, + message: undefined, + }), + ], currentPath: [], - }, + }), ), ); }); @@ -192,18 +213,17 @@ describe("DDataParser object", () => { expect(result).toStrictEqual( DEither.error( - { - ...DDataParser.addIssue( - DDataParser.setErrorPath( - DDataParser.createError(), - "name", - 0, - ), - nameSchema, - undefined, - ), + DDataParser.errorKind.addTo({ + issues: [ + DDataParser.errorIssueKind.addTo({ + expected: "string", + path: "name", + data: undefined, + message: undefined, + }), + ], currentPath: [], - }, + }), ), ); }); diff --git a/tests/dataParser/parsers/optional.test.ts b/tests/dataParser/parsers/optional.test.ts index 11d47e69d..a41ba321e 100644 --- a/tests/dataParser/parsers/optional.test.ts +++ b/tests/dataParser/parsers/optional.test.ts @@ -56,11 +56,17 @@ describe("DDataParser optional", () => { expect(result).toStrictEqual( DEither.error( - DDataParser.addIssue( - DDataParser.createError(), - inner, - "nope", - ), + DDataParser.errorKind.addTo({ + issues: [ + DDataParser.errorIssueKind.addTo({ + expected: "number", + path: "", + data: "nope", + message: "not-number", + }), + ], + currentPath: [], + }), ), ); }); @@ -101,11 +107,17 @@ describe("DDataParser optional", () => { expect(result).toStrictEqual( DEither.error( - DDataParser.addIssue( - DDataParser.createError(), - inner, - "nope", - ), + DDataParser.errorKind.addTo({ + issues: [ + DDataParser.errorIssueKind.addTo({ + expected: "number", + path: "", + data: "nope", + message: "not-number", + }), + ], + currentPath: [], + }), ), ); }); diff --git a/tests/dataParser/parsers/pipe.test.ts b/tests/dataParser/parsers/pipe.test.ts index 38cafb2e3..fca79e143 100644 --- a/tests/dataParser/parsers/pipe.test.ts +++ b/tests/dataParser/parsers/pipe.test.ts @@ -41,11 +41,17 @@ describe("DDataParser pipe", () => { expect(result).toStrictEqual( DEither.error( - DDataParser.addIssue( - DDataParser.createError(), - inputParser, - "nope", - ), + DDataParser.errorKind.addTo({ + issues: [ + DDataParser.errorIssueKind.addTo({ + expected: "number", + path: "(pipeIn)", + data: "nope", + message: "not-number", + }), + ], + currentPath: [], + }), ), ); }); @@ -61,11 +67,17 @@ describe("DDataParser pipe", () => { expect(result).toStrictEqual( DEither.error( - DDataParser.addIssue( - DDataParser.createError(), - outputParser, - 5, - ), + DDataParser.errorKind.addTo({ + issues: [ + DDataParser.errorIssueKind.addTo({ + expected: "string", + path: "(pipeOut)", + data: 5, + message: undefined, + }), + ], + currentPath: [], + }), ), ); }); @@ -93,12 +105,17 @@ describe("DDataParser pipe", () => { expect(result).toStrictEqual( DEither.error( - DDataParser.addIssue( - DDataParser.createError(), - inputParser, - "nope", - ), - + DDataParser.errorKind.addTo({ + issues: [ + DDataParser.errorIssueKind.addTo({ + expected: "number", + path: "(pipeIn)", + data: "nope", + message: "not-number", + }), + ], + currentPath: [], + }), ), ); }); diff --git a/tests/dataParser/parsers/record/index.test.ts b/tests/dataParser/parsers/record/index.test.ts index 8b6ea26d0..5aef302ad 100644 --- a/tests/dataParser/parsers/record/index.test.ts +++ b/tests/dataParser/parsers/record/index.test.ts @@ -1,4 +1,4 @@ -import { DDataParser, DEither, pipe, type ExpectType } from "@scripts"; +import { DDataParser, DEither, type ExpectType } from "@scripts"; describe("DDataParser record", () => { it("parses record of strings", () => { @@ -89,45 +89,34 @@ describe("DDataParser record", () => { const result = schema.parse({ forbidden: "testValue" }); expect(result).toStrictEqual( - pipe( - DDataParser.createError(), - (error) => DDataParser.setErrorPath( - error, - "value", - 0, - ), - (error) => DDataParser.addIssue( - error, - valueParser, - undefined, - ), - (error) => DDataParser.setErrorPath( - error, - "tt", - 0, - ), - (error) => DDataParser.addIssue( - error, - valueParser, - undefined, - ), - (error) => DDataParser.setErrorPath( - error, - "forbidden", - 0, - ), - (error) => DDataParser.addIssue( - error, - keyParser, - "forbidden", - ), - (error) => DDataParser.addIssue( - error, - valueParser, - "testValue", - ), - (error) => DEither.error({ - ...error, + DEither.error( + DDataParser.errorKind.addTo({ + issues: [ + DDataParser.errorIssueKind.addTo({ + expected: "number", + path: "value", + data: undefined, + message: undefined, + }), + DDataParser.errorIssueKind.addTo({ + expected: "number", + path: "tt", + data: undefined, + message: undefined, + }), + DDataParser.errorIssueKind.addTo({ + expected: "one of value, tt", + path: "(recordKey: forbidden)", + data: "forbidden", + message: undefined, + }), + DDataParser.errorIssueKind.addTo({ + expected: "number", + path: "forbidden", + data: "testValue", + message: undefined, + }), + ], currentPath: [], }), ), @@ -145,11 +134,17 @@ describe("DDataParser record", () => { expect(result).toStrictEqual( DEither.error( - DDataParser.addIssue( - DDataParser.createError(), - schema, - "not-an-object", - ), + DDataParser.errorKind.addTo({ + issues: [ + DDataParser.errorIssueKind.addTo({ + expected: "record object", + path: "", + data: "not-an-object", + message: "record.invalid", + }), + ], + currentPath: [], + }), ), ); }); @@ -198,12 +193,16 @@ describe("DDataParser record", () => { const result = schema.parse({ foo: "bar" }); expect(result).toStrictEqual( - pipe( - DDataParser.createError(), - (error) => DDataParser.setErrorPath(error, "foo", 0), - (error) => DDataParser.addIssue(error, valueParser, "bar"), - (error) => DEither.error({ - ...error, + DEither.error( + DDataParser.errorKind.addTo({ + issues: [ + DDataParser.errorIssueKind.addTo({ + expected: "number", + path: "foo", + data: "bar", + message: undefined, + }), + ], currentPath: [], }), ), @@ -350,45 +349,34 @@ describe("DDataParser record", () => { const result = await schema.asyncParse({ forbidden: "testValue" }); expect(result).toStrictEqual( - pipe( - DDataParser.createError(), - (error) => DDataParser.setErrorPath( - error, - "value", - 0, - ), - (error) => DDataParser.addIssue( - error, - valueParser, - undefined, - ), - (error) => DDataParser.setErrorPath( - error, - "tt", - 0, - ), - (error) => DDataParser.addIssue( - error, - valueParser, - undefined, - ), - (error) => DDataParser.setErrorPath( - error, - "forbidden", - 0, - ), - (error) => DDataParser.addIssue( - error, - keyParser, - "forbidden", - ), - (error) => DDataParser.addIssue( - error, - valueParser, - "testValue", - ), - (error) => DEither.error({ - ...error, + DEither.error( + DDataParser.errorKind.addTo({ + issues: [ + DDataParser.errorIssueKind.addTo({ + expected: "number", + path: "value", + data: undefined, + message: undefined, + }), + DDataParser.errorIssueKind.addTo({ + expected: "number", + path: "tt", + data: undefined, + message: undefined, + }), + DDataParser.errorIssueKind.addTo({ + expected: "one of value, tt", + path: "(recordKey: forbidden)", + data: "forbidden", + message: undefined, + }), + DDataParser.errorIssueKind.addTo({ + expected: "number", + path: "forbidden", + data: "testValue", + message: undefined, + }), + ], currentPath: [], }), ), @@ -406,11 +394,17 @@ describe("DDataParser record", () => { expect(result).toStrictEqual( DEither.error( - DDataParser.addIssue( - DDataParser.createError(), - schema, - "not-an-object", - ), + DDataParser.errorKind.addTo({ + issues: [ + DDataParser.errorIssueKind.addTo({ + expected: "record object", + path: "", + data: "not-an-object", + message: "record.invalid", + }), + ], + currentPath: [], + }), ), ); }); @@ -453,12 +447,16 @@ describe("DDataParser record", () => { const result = await schema.asyncParse({ foo: "bar" }); expect(result).toStrictEqual( - pipe( - DDataParser.createError(), - (error) => DDataParser.setErrorPath(error, "foo", 0), - (error) => DDataParser.addIssue(error, valueParser, "bar"), - (error) => DEither.error({ - ...error, + DEither.error( + DDataParser.errorKind.addTo({ + issues: [ + DDataParser.errorIssueKind.addTo({ + expected: "number", + path: "foo", + data: "bar", + message: undefined, + }), + ], currentPath: [], }), ), diff --git a/tests/dataParser/parsers/recover.test.ts b/tests/dataParser/parsers/recover.test.ts index e726cd6e3..9c4b62499 100644 --- a/tests/dataParser/parsers/recover.test.ts +++ b/tests/dataParser/parsers/recover.test.ts @@ -1,4 +1,4 @@ -import { DDataParser, DEither, pipe, type ExpectType } from "@scripts"; +import { DDataParser, DEither, type ExpectType } from "@scripts"; describe("DDataParser recover", () => { it("parses inner value when valid", () => { @@ -42,19 +42,24 @@ describe("DDataParser recover", () => { ); expect(schema.parse("invalid")).toStrictEqual( - pipe( - DDataParser.createError(), - (error) => DDataParser.addIssue( - error, - schema.definition.inner, - "invalid", - ), - (error) => DDataParser.addIssue( - error, - schema.definition.checkers[0], - -1, - ), - (error) => DEither.error(error), + DEither.error( + DDataParser.errorKind.addTo({ + issues: [ + DDataParser.errorIssueKind.addTo({ + expected: "number", + path: "", + data: "invalid", + message: "not-number", + }), + DDataParser.errorIssueKind.addTo({ + expected: "value matching refine predicate", + path: "", + data: -1, + message: "must-be-positive", + }), + ], + currentPath: [], + }), ), ); }); @@ -86,19 +91,24 @@ describe("DDataParser recover", () => { ); expect(await schema.asyncParse("invalid")).toStrictEqual( - pipe( - DDataParser.createError(), - (error) => DDataParser.addIssue( - error, - schema.definition.inner, - "invalid", - ), - (error) => DDataParser.addIssue( - error, - schema.definition.checkers[0], - -1, - ), - (error) => DEither.error(error), + DEither.error( + DDataParser.errorKind.addTo({ + issues: [ + DDataParser.errorIssueKind.addTo({ + expected: "number", + path: "", + data: "invalid", + message: "not-number", + }), + DDataParser.errorIssueKind.addTo({ + expected: "value matching refine predicate", + path: "", + data: -1, + message: "must-be-positive", + }), + ], + currentPath: [], + }), ), ); }); diff --git a/tests/dataParser/parsers/refine.test.ts b/tests/dataParser/parsers/refine.test.ts index 800da198a..ec9aad48c 100644 --- a/tests/dataParser/parsers/refine.test.ts +++ b/tests/dataParser/parsers/refine.test.ts @@ -8,11 +8,17 @@ describe("DDataParser checker refine", () => { expect(schema.parse("123")).toStrictEqual(DEither.success("123")); expect(schema.parse("test")).toStrictEqual( DEither.error( - DDataParser.addIssue( - DDataParser.createError(), - checker, - "test", - ), + DDataParser.errorKind.addTo({ + issues: [ + DDataParser.errorIssueKind.addTo({ + expected: "value matching refine predicate", + path: "", + data: "test", + message: "test", + }), + ], + currentPath: [], + }), ), ); }); diff --git a/tests/dataParser/parsers/string/checkers/email.test.ts b/tests/dataParser/parsers/string/checkers/email.test.ts index f2f40c0a9..33cd98421 100644 --- a/tests/dataParser/parsers/string/checkers/email.test.ts +++ b/tests/dataParser/parsers/string/checkers/email.test.ts @@ -25,11 +25,17 @@ describe("DDataParser string checker email", () => { expect(result).toStrictEqual( DEither.error( - DDataParser.addIssue( - DDataParser.createError(), - checker, - "invalid-email", - ), + DDataParser.errorKind.addTo({ + issues: [ + DDataParser.errorIssueKind.addTo({ + expected: "email", + path: "", + data: "invalid-email", + message: undefined, + }), + ], + currentPath: [], + }), ), ); }); diff --git a/tests/dataParser/parsers/string/checkers/max.test.ts b/tests/dataParser/parsers/string/checkers/max.test.ts index 547ce19ed..5f932d383 100644 --- a/tests/dataParser/parsers/string/checkers/max.test.ts +++ b/tests/dataParser/parsers/string/checkers/max.test.ts @@ -21,11 +21,17 @@ describe("DDataParser string checker max length", () => { expect(result).toStrictEqual( DEither.error( - DDataParser.addIssue( - DDataParser.createError(), - checker, - "test", - ), + DDataParser.errorKind.addTo({ + issues: [ + DDataParser.errorIssueKind.addTo({ + expected: "string.length <= 3", + path: "", + data: "test", + message: undefined, + }), + ], + currentPath: [], + }), ), ); }); diff --git a/tests/dataParser/parsers/string/checkers/min.test.ts b/tests/dataParser/parsers/string/checkers/min.test.ts index fcda4ec4e..a13f74bb7 100644 --- a/tests/dataParser/parsers/string/checkers/min.test.ts +++ b/tests/dataParser/parsers/string/checkers/min.test.ts @@ -21,11 +21,17 @@ describe("DDataParser string checker min length", () => { expect(result).toStrictEqual( DEither.error( - DDataParser.addIssue( - DDataParser.createError(), - checker, - "ok", - ), + DDataParser.errorKind.addTo({ + issues: [ + DDataParser.errorIssueKind.addTo({ + expected: "string.length >= 3", + path: "", + data: "ok", + message: undefined, + }), + ], + currentPath: [], + }), ), ); }); diff --git a/tests/dataParser/parsers/string/checkers/regex.test.ts b/tests/dataParser/parsers/string/checkers/regex.test.ts index 361298aa3..cb8054338 100644 --- a/tests/dataParser/parsers/string/checkers/regex.test.ts +++ b/tests/dataParser/parsers/string/checkers/regex.test.ts @@ -21,11 +21,17 @@ describe("DDataParser string checker match with regex", () => { expect(result).toStrictEqual( DEither.error( - DDataParser.addIssue( - DDataParser.createError(), - checker, - "ok", - ), + DDataParser.errorKind.addTo({ + issues: [ + DDataParser.errorIssueKind.addTo({ + expected: "string with pattern t", + path: "", + data: "ok", + message: undefined, + }), + ], + currentPath: [], + }), ), ); }); diff --git a/tests/dataParser/parsers/string/checkers/url.test.ts b/tests/dataParser/parsers/string/checkers/url.test.ts index d7aa6a5a7..97ea213ee 100644 --- a/tests/dataParser/parsers/string/checkers/url.test.ts +++ b/tests/dataParser/parsers/string/checkers/url.test.ts @@ -15,11 +15,17 @@ describe("DDataParser string url checker", () => { expect(schema.parse("sftp://example.com/path")).toStrictEqual( DEither.error( - DDataParser.addIssue( - DDataParser.createError(), - checker, - "sftp://example.com/path", - ), + DDataParser.errorKind.addTo({ + issues: [ + DDataParser.errorIssueKind.addTo({ + expected: "URL with protocol matching ^https?$", + path: "", + data: "sftp://example.com/path", + message: undefined, + }), + ], + currentPath: [], + }), ), ); }); @@ -45,11 +51,17 @@ describe("DDataParser string url checker", () => { expect(result).toStrictEqual( DEither.error( - DDataParser.addIssue( - DDataParser.createError(), - checker, - "https://www.example.com", - ), + DDataParser.errorKind.addTo({ + issues: [ + DDataParser.errorIssueKind.addTo({ + expected: "URL with hostname matching ^api\\.example\\.com$", + path: "", + data: "https://www.example.com", + message: undefined, + }), + ], + currentPath: [], + }), ), ); @@ -68,11 +80,17 @@ describe("DDataParser string url checker", () => { expect(result).toStrictEqual( DEither.error( - DDataParser.addIssue( - DDataParser.createError(), - checker, - "not a url", - ), + DDataParser.errorKind.addTo({ + issues: [ + DDataParser.errorIssueKind.addTo({ + expected: "valid URL", + path: "", + data: "not a url", + message: undefined, + }), + ], + currentPath: [], + }), ), ); }); diff --git a/tests/dataParser/parsers/string/index.test.ts b/tests/dataParser/parsers/string/index.test.ts index cea3e8db4..bc5fce2be 100644 --- a/tests/dataParser/parsers/string/index.test.ts +++ b/tests/dataParser/parsers/string/index.test.ts @@ -32,7 +32,21 @@ describe("DDataParser string", () => { const result = schema.parse(11); - expect(result).toStrictEqual(DEither.error(DDataParser.addIssue(DDataParser.createError(), schema, 11))); + expect(result).toStrictEqual( + DEither.error( + DDataParser.errorKind.addTo({ + issues: [ + DDataParser.errorIssueKind.addTo({ + expected: "string", + path: "", + data: 11, + message: "error", + }), + ], + currentPath: [], + }), + ), + ); }); it("succes coerc parsing", () => { diff --git a/tests/dataParser/parsers/templateLiteral/index.test.ts b/tests/dataParser/parsers/templateLiteral/index.test.ts index 4fd827430..1dc6a527d 100644 --- a/tests/dataParser/parsers/templateLiteral/index.test.ts +++ b/tests/dataParser/parsers/templateLiteral/index.test.ts @@ -69,11 +69,17 @@ describe("DDataParser templateLiteral", () => { expect(result).toStrictEqual( DEither.error( - DDataParser.addIssue( - DDataParser.createError(), - schema, - invalid, - ), + DDataParser.errorKind.addTo({ + issues: [ + DDataParser.errorIssueKind.addTo({ + expected: `string matching template literal pattern ${schema.definition.pattern.source}`, + path: "", + data: invalid, + message: undefined, + }), + ], + currentPath: [], + }), ), ); }); @@ -91,11 +97,17 @@ describe("DDataParser templateLiteral", () => { expect(result).toStrictEqual( DEither.error( - DDataParser.addIssue( - DDataParser.createError(), - schema, - invalid, - ), + DDataParser.errorKind.addTo({ + issues: [ + DDataParser.errorIssueKind.addTo({ + expected: `string matching template literal pattern ${schema.definition.pattern.source}`, + path: "", + data: invalid, + message: "invalid.template", + }), + ], + currentPath: [], + }), ), ); }); diff --git a/tests/dataParser/parsers/time/checkers/max.test.ts b/tests/dataParser/parsers/time/checkers/max.test.ts index 4ad13b4be..0c633cd95 100644 --- a/tests/dataParser/parsers/time/checkers/max.test.ts +++ b/tests/dataParser/parsers/time/checkers/max.test.ts @@ -32,11 +32,17 @@ describe("DDataParser time checker max", () => { expect(result).toStrictEqual( DEither.error( - DDataParser.addIssue( - DDataParser.createError(), - checker, - input, - ), + DDataParser.errorKind.addTo({ + issues: [ + DDataParser.errorIssueKind.addTo({ + expected: "time <= time60000+", + path: "", + data: input, + message: undefined, + }), + ], + currentPath: [], + }), ), ); diff --git a/tests/dataParser/parsers/time/checkers/min.test.ts b/tests/dataParser/parsers/time/checkers/min.test.ts index f8515aab9..1335545a6 100644 --- a/tests/dataParser/parsers/time/checkers/min.test.ts +++ b/tests/dataParser/parsers/time/checkers/min.test.ts @@ -32,11 +32,17 @@ describe("DDataParser time checker min", () => { expect(result).toStrictEqual( DEither.error( - DDataParser.addIssue( - DDataParser.createError(), - checker, - input, - ), + DDataParser.errorKind.addTo({ + issues: [ + DDataParser.errorIssueKind.addTo({ + expected: "time >= time60000+", + path: "", + data: input, + message: undefined, + }), + ], + currentPath: [], + }), ), ); diff --git a/tests/dataParser/parsers/time/index.test.ts b/tests/dataParser/parsers/time/index.test.ts index d7a8273e2..ac8ff97bb 100644 --- a/tests/dataParser/parsers/time/index.test.ts +++ b/tests/dataParser/parsers/time/index.test.ts @@ -29,11 +29,17 @@ describe("DDataParser time", () => { expect(result).toStrictEqual( DEither.error( - DDataParser.addIssue( - DDataParser.createError(), - schema, - input, - ), + DDataParser.errorKind.addTo({ + issues: [ + DDataParser.errorIssueKind.addTo({ + expected: "time", + path: "", + data: input, + message: "time.invalid", + }), + ], + currentPath: [], + }), ), ); }); @@ -67,38 +73,62 @@ describe("DDataParser time", () => { expect(timestampResult).toStrictEqual( DEither.error( - DDataParser.addIssue( - DDataParser.createError(), - schema, - outOfRangeTimestamp, - ), + DDataParser.errorKind.addTo({ + issues: [ + DDataParser.errorIssueKind.addTo({ + expected: "time", + path: "", + data: outOfRangeTimestamp, + message: "time.invalid", + }), + ], + currentPath: [], + }), ), ); expect(stringResult).toStrictEqual( DEither.error( - DDataParser.addIssue( - DDataParser.createError(), - schema, - invalidString, - ), + DDataParser.errorKind.addTo({ + issues: [ + DDataParser.errorIssueKind.addTo({ + expected: "time", + path: "", + data: invalidString, + message: "time.invalid", + }), + ], + currentPath: [], + }), ), ); expect(typeResult).toStrictEqual( DEither.error( - DDataParser.addIssue( - DDataParser.createError(), - schema, - invalidType, - ), + DDataParser.errorKind.addTo({ + issues: [ + DDataParser.errorIssueKind.addTo({ + expected: "time", + path: "", + data: invalidType, + message: "time.invalid", + }), + ], + currentPath: [], + }), ), ); expect(unsafeTheTimeResult).toStrictEqual( DEither.error( - DDataParser.addIssue( - DDataParser.createError(), - schema, - unsafeTheTime, - ), + DDataParser.errorKind.addTo({ + issues: [ + DDataParser.errorIssueKind.addTo({ + expected: "time", + path: "", + data: unsafeTheTime, + message: "time.invalid", + }), + ], + currentPath: [], + }), ), ); }); @@ -116,11 +146,17 @@ describe("DDataParser time", () => { expect(result).toStrictEqual( DEither.error( - DDataParser.addIssue( - DDataParser.createError(), - schema, - input, - ), + DDataParser.errorKind.addTo({ + issues: [ + DDataParser.errorIssueKind.addTo({ + expected: "time", + path: "", + data: input, + message: "time.invalid", + }), + ], + currentPath: [], + }), ), ); expect(createTimeSpy).toHaveBeenCalledWith({ value: input }); diff --git a/tests/dataParser/parsers/transform.test.ts b/tests/dataParser/parsers/transform.test.ts index aa646c48b..16ae19731 100644 --- a/tests/dataParser/parsers/transform.test.ts +++ b/tests/dataParser/parsers/transform.test.ts @@ -33,17 +33,14 @@ describe("DDataParser transform", () => { it("fails when inner parser fails", () => { const inner = DDataParser.number({ errorMessage: "not-number" }); const schema = DDataParser.transform(inner, (value) => value); + const expectedError = DDataParser.createError(); + + DDataParser.addIssue(expectedError, "number", "value", "not-number"); const result = schema.parse("value"); expect(result).toStrictEqual( - DEither.error( - DDataParser.addIssue( - DDataParser.createError(), - inner, - "value", - ), - ), + DEither.error(expectedError), ); }); @@ -57,11 +54,14 @@ describe("DDataParser transform", () => { expect(result).toStrictEqual( DEither.error( - DDataParser.addPromiseIssue( - DDataParser.createError(), - schema, - 10, - ), + expect.objectContaining({ + issues: [ + expect.objectContaining({ + expected: "non-promise transform result", + data: expect.any(Promise), + }), + ], + }), ), ); }); @@ -81,17 +81,14 @@ describe("DDataParser transform", () => { it("fails when inner parser fails", async() => { const inner = DDataParser.number({ errorMessage: "not-number" }); const schema = DDataParser.transform(inner, (value) => Promise.resolve(value)); + const expectedError = DDataParser.createError(); + + DDataParser.addIssue(expectedError, "number", "value", "not-number"); const result = await schema.asyncParse("value"); expect(result).toStrictEqual( - DEither.error( - DDataParser.addIssue( - DDataParser.createError(), - inner, - "value", - ), - ), + DEither.error(expectedError), ); }); @@ -105,11 +102,14 @@ describe("DDataParser transform", () => { expect(result).toStrictEqual( DEither.error( - DDataParser.addPromiseIssue( - DDataParser.createError(), - schema, - 10, - ), + expect.objectContaining({ + issues: [ + expect.objectContaining({ + expected: "successful async transform result", + data: expect.any(Promise), + }), + ], + }), ), ); }); diff --git a/tests/dataParser/parsers/tuple.test.ts b/tests/dataParser/parsers/tuple.test.ts index ed9751f23..b46ebdca5 100644 --- a/tests/dataParser/parsers/tuple.test.ts +++ b/tests/dataParser/parsers/tuple.test.ts @@ -1,4 +1,4 @@ -import { DDataParser, DEither, pipe, type ExpectType } from "@scripts"; +import { DDataParser, DEither, type ExpectType } from "@scripts"; describe("DDataParser tuple", () => { it("parses fixed tuple shape", () => { @@ -101,11 +101,17 @@ describe("DDataParser tuple", () => { expect(result).toStrictEqual( DEither.error( - DDataParser.addIssue( - DDataParser.createError(), - schema, - "invalid", - ), + DDataParser.errorKind.addTo({ + issues: [ + DDataParser.errorIssueKind.addTo({ + expected: "tuple array", + path: "", + data: "invalid", + message: "tuple.invalid", + }), + ], + currentPath: [], + }), ), ); }); @@ -127,30 +133,22 @@ describe("DDataParser tuple", () => { const result = schema.parse(["ok", "33", 20, "ok", 40, "yess"]); expect(result).toStrictEqual( - pipe( - DDataParser.createError(), - (error) => DDataParser.setErrorPath( - error, - "[1]", - 0, - ), - (error) => DDataParser.addIssue( - error, - numberParser, - "33", - ), - (error) => DDataParser.setErrorPath( - error, - "[4]", - 0, - ), - (error) => DDataParser.addIssue( - error, - stringParser, - 40, - ), - (error) => DEither.error({ - ...error, + DEither.error( + DDataParser.errorKind.addTo({ + issues: [ + DDataParser.errorIssueKind.addTo({ + expected: "number", + path: "[1]", + data: "33", + message: undefined, + }), + DDataParser.errorIssueKind.addTo({ + expected: "string", + path: "[4]", + data: 40, + message: undefined, + }), + ], currentPath: [], }), ), @@ -188,11 +186,17 @@ describe("DDataParser tuple", () => { expect(result).toStrictEqual( DEither.error( - DDataParser.addIssue( - DDataParser.createError(), - schema, - "invalid", - ), + DDataParser.errorKind.addTo({ + issues: [ + DDataParser.errorIssueKind.addTo({ + expected: "tuple array", + path: "", + data: "invalid", + message: "tuple.invalid", + }), + ], + currentPath: [], + }), ), ); }); @@ -214,30 +218,22 @@ describe("DDataParser tuple", () => { const result = await schema.asyncParse(["ok", "33", 20, "ok", 40, "yess"]); expect(result).toStrictEqual( - pipe( - DDataParser.createError(), - (error) => DDataParser.setErrorPath( - error, - "[1]", - 0, - ), - (error) => DDataParser.addIssue( - error, - numberParser, - "33", - ), - (error) => DDataParser.setErrorPath( - error, - "[4]", - 0, - ), - (error) => DDataParser.addIssue( - error, - stringParser, - 40, - ), - (error) => DEither.error({ - ...error, + DEither.error( + DDataParser.errorKind.addTo({ + issues: [ + DDataParser.errorIssueKind.addTo({ + expected: "number", + path: "[1]", + data: "33", + message: undefined, + }), + DDataParser.errorIssueKind.addTo({ + expected: "string", + path: "[4]", + data: 40, + message: undefined, + }), + ], currentPath: [], }), ), diff --git a/tests/dataParser/parsers/union.test.ts b/tests/dataParser/parsers/union.test.ts index e0e043825..cb9c481af 100644 --- a/tests/dataParser/parsers/union.test.ts +++ b/tests/dataParser/parsers/union.test.ts @@ -1,4 +1,4 @@ -import { DDataParser, DEither, pipe, type ExpectType } from "@scripts"; +import { DDataParser, DEither, E, type ExpectType } from "@scripts"; describe("DDataParser union", () => { it("parses with the first matching parser", () => { @@ -52,24 +52,30 @@ describe("DDataParser union", () => { const result = schema.parse(true); expect(result).toStrictEqual( - pipe( - DDataParser.createError(), - (error) => DDataParser.addIssue( - error, - stringParser, - true, - ), - (error) => DDataParser.addIssue( - error, - numberParser, - true, - ), - (error) => DDataParser.addIssue( - error, - schema, - true, - ), - DEither.error, + DEither.error( + DDataParser.errorKind.addTo({ + issues: [ + DDataParser.errorIssueKind.addTo({ + expected: "string", + path: "(option: 0)", + data: true, + message: undefined, + }), + DDataParser.errorIssueKind.addTo({ + expected: "number", + path: "(option: 1)", + data: true, + message: undefined, + }), + DDataParser.errorIssueKind.addTo({ + expected: "respect at least one union value", + path: "", + data: true, + message: undefined, + }), + ], + currentPath: [], + }), ), ); }); @@ -97,24 +103,30 @@ describe("DDataParser union", () => { const result = await schema.asyncParse(true); expect(result).toStrictEqual( - pipe( - DDataParser.createError(), - (error) => DDataParser.addIssue( - error, - stringParser, - true, - ), - (error) => DDataParser.addIssue( - error, - numberParser, - true, - ), - (error) => DDataParser.addIssue( - error, - schema, - true, - ), - DEither.error, + DEither.error( + DDataParser.errorKind.addTo({ + issues: [ + DDataParser.errorIssueKind.addTo({ + expected: "string", + path: "(option: 0)", + data: true, + message: undefined, + }), + DDataParser.errorIssueKind.addTo({ + expected: "number", + path: "(option: 1)", + data: true, + message: undefined, + }), + DDataParser.errorIssueKind.addTo({ + expected: "respect at least one union value", + path: "", + data: true, + message: undefined, + }), + ], + currentPath: [], + }), ), ); });