From 5d7a0b17e0ea3420992f1707bffb09189ecd2beb Mon Sep 17 00:00:00 2001 From: mathcovax Date: Fri, 12 Jun 2026 16:13:13 +0000 Subject: [PATCH] feat(85): init checker refinement type --- scripts/common/types/neverCoalescing.ts | 4 +- .../dataParser/parsers/array/checkers/max.ts | 22 +++++--- .../dataParser/parsers/array/checkers/min.ts | 24 +++++--- scripts/dataParser/parsers/array/index.ts | 7 ++- scripts/dataParser/parsers/refine.ts | 53 +++++++++++++----- scripts/dataParser/parsers/string/index.ts | 7 ++- scripts/dataParser/types/checkers.ts | 56 ++++++++++++++++++- .../parsers/array/checkers/max.test.ts | 8 ++- .../parsers/array/checkers/min.test.ts | 8 ++- tests/dataParser/parsers/array/index.test.ts | 25 ++++++++- tests/dataParser/parsers/string/index.test.ts | 25 ++++++++- 11 files changed, 193 insertions(+), 46 deletions(-) diff --git a/scripts/common/types/neverCoalescing.ts b/scripts/common/types/neverCoalescing.ts index e97b0e206..aeae33ee0 100644 --- a/scripts/common/types/neverCoalescing.ts +++ b/scripts/common/types/neverCoalescing.ts @@ -1,8 +1,6 @@ -import { type IsEqual } from "./isEqual"; - export type NeverCoalescing< GenericValue extends unknown, GenericCoalescingValue extends unknown, -> = IsEqual extends true +> = [GenericValue] extends [never] ? GenericCoalescingValue : GenericValue; diff --git a/scripts/dataParser/parsers/array/checkers/max.ts b/scripts/dataParser/parsers/array/checkers/max.ts index 013f9b4cf..231e9c821 100644 --- a/scripts/dataParser/parsers/array/checkers/max.ts +++ b/scripts/dataParser/parsers/array/checkers/max.ts @@ -4,16 +4,20 @@ import { createDataParserKind } from "../../../kind"; import { DataParserCheckerBase, type DataParserCheckerDefinition } from "../../../baseChecker"; import { type DataParser } from "../../../base"; -export interface DataParserCheckerDefinitionArrayMax extends DataParserCheckerDefinition { - max: number; +export interface DataParserCheckerDefinitionArrayMax< + GenericMax extends number = number, +> extends DataParserCheckerDefinition { + max: GenericMax; } export const checkerArrayMaxKind = createDataParserKind("checker-array-max"); -export class DataParserCheckerArrayMax extends DataParserCheckerBase.init( - checkerArrayMaxKind, -)< - DataParserCheckerDefinitionArrayMax, +export class DataParserCheckerArrayMax< + GenericMax extends number = number, +> extends DataParserCheckerBase.init( + checkerArrayMaxKind, + )< + DataParserCheckerDefinitionArrayMax, unknown[] > { public get classConstructor() { @@ -40,8 +44,10 @@ export class DataParserCheckerArrayMax extends DataParserCheckerBase.init( ); } - public static override create( - max: number, + public static override create< + GenericMax extends number, + >( + max: GenericMax, definition: Partial< Omit > = {}, diff --git a/scripts/dataParser/parsers/array/checkers/min.ts b/scripts/dataParser/parsers/array/checkers/min.ts index 0a07d6b2f..5540db11c 100644 --- a/scripts/dataParser/parsers/array/checkers/min.ts +++ b/scripts/dataParser/parsers/array/checkers/min.ts @@ -1,19 +1,23 @@ -import { detachObjectMethod } from "@scripts/common"; +import { detachObjectMethod, NeverCoalescing, type SimplifyTopLevel } from "@scripts/common"; import { addIssue, type DataParserError } from "@scripts/dataParser/error"; import { createDataParserKind } from "../../../kind"; import { DataParserCheckerBase, type DataParserCheckerDefinition } from "../../../baseChecker"; import { type DataParser } from "../../../base"; -export interface DataParserCheckerDefinitionArrayMin extends DataParserCheckerDefinition { - min: number; +export interface DataParserCheckerDefinitionArrayMin< + GenericMin extends number = number, +> extends DataParserCheckerDefinition { + min: GenericMin; } export const checkerArrayMinKind = createDataParserKind("checker-array-min"); -export class DataParserCheckerArrayMin extends DataParserCheckerBase.init( - checkerArrayMinKind, -)< - DataParserCheckerDefinitionArrayMin, +export class DataParserCheckerArrayMin< + GenericMin extends number = number, +> extends DataParserCheckerBase.init( + checkerArrayMinKind, + )< + DataParserCheckerDefinitionArrayMin, unknown[] > { public get classConstructor() { @@ -40,8 +44,10 @@ export class DataParserCheckerArrayMin extends DataParserCheckerBase.init( ); } - public static override create( - min: number, + public static override create< + GenericMin extends number, + >( + min: GenericMin, definition: Partial< Omit > = {}, diff --git a/scripts/dataParser/parsers/array/index.ts b/scripts/dataParser/parsers/array/index.ts index e951620d7..22822acbe 100644 --- a/scripts/dataParser/parsers/array/index.ts +++ b/scripts/dataParser/parsers/array/index.ts @@ -3,7 +3,7 @@ import { createDataParserKind } from "@scripts/dataParser/kind"; import { DataParserBase, type DataParser, type DataParserDefinition } from "../../base"; import { addIssue, popErrorPath, setErrorPath, type DataParserError, SymbolDataParserError } from "@scripts/dataParser/error"; import { type DataParserChecker } from "../../baseChecker"; -import { type AddCheckersToDefinition, type GetEligibleChecker, type Input, type MergeDefinition, type Output, type PrepareDataParserDefinition } from "../../types"; +import { type ApplyRefinementOfChecker, type AddCheckersToDefinition, type GetEligibleChecker, type Input, type MergeDefinition, type Output, type PrepareDataParserDefinition } from "../../types"; export * from "./checkers"; @@ -27,7 +27,10 @@ export class DataParserArray< arrayKind, )< GenericDefinition, - Output[], + ApplyRefinementOfChecker< + Output[], + GenericDefinition + >, Input[] > { public get classConstructor() { diff --git a/scripts/dataParser/parsers/refine.ts b/scripts/dataParser/parsers/refine.ts index 2f31dece2..6446edfbe 100644 --- a/scripts/dataParser/parsers/refine.ts +++ b/scripts/dataParser/parsers/refine.ts @@ -1,4 +1,4 @@ -import { detachObjectMethod, callThen, type NeverCoalescing, type SimplifyTopLevel, type MaybePromise } from "@scripts/common"; +import { detachObjectMethod, callThen, type NeverCoalescing, type SimplifyTopLevel, type MaybePromise, type AnyFunction } from "@scripts/common"; import { DataParserCheckerBase, type DataParserCheckerDefinition } from "../baseChecker"; import { type DataParser } from "../base"; import { addIssue, type DataParserError } from "@scripts/dataParser/error"; @@ -54,6 +54,28 @@ export class DataParserCheckerRefine< ); } + public static override create< + GenericInput extends unknown, + GenericPredicate extends GenericInput, + const GenericDefinition extends Partial< + Omit + > = never, + >( + theFunction: (input: GenericInput) => input is GenericPredicate, + definition?: GenericDefinition, + ): DataParserCheckerRefine< + SimplifyTopLevel< + & NeverCoalescing< + GenericDefinition, + DataParserCheckerDefinitionRefine + > + & { + theFunction(input: GenericInput): input is GenericPredicate; + } + >, + GenericInput + >; + public static override create< GenericInput extends unknown, const GenericDefinition extends Partial< @@ -63,21 +85,26 @@ export class DataParserCheckerRefine< theFunction: (input: GenericInput) => MaybePromise, definition?: GenericDefinition, ): DataParserCheckerRefine< - SimplifyTopLevel< - & NeverCoalescing< - GenericDefinition, - DataParserCheckerDefinitionRefine - > - & { - theFunction(input: GenericInput): MaybePromise; - } - >, - GenericInput - > { + SimplifyTopLevel< + & NeverCoalescing< + GenericDefinition, + DataParserCheckerDefinitionRefine + > + & { + theFunction(input: GenericInput): MaybePromise; + } + >, + GenericInput + >; + + public static override create( + theFunction: AnyFunction, + definition?: Partial, + ) { return new DataParserCheckerRefine({ ...definition, theFunction, - }) as never; + }); } } diff --git a/scripts/dataParser/parsers/string/index.ts b/scripts/dataParser/parsers/string/index.ts index a05da20e5..af117e234 100644 --- a/scripts/dataParser/parsers/string/index.ts +++ b/scripts/dataParser/parsers/string/index.ts @@ -3,7 +3,7 @@ import { createDataParserKind } from "@scripts/dataParser/kind"; import { DataParserBase, type DataParserDefinition } from "../../base"; import { addIssue, type DataParserError, type SymbolDataParserError } from "@scripts/dataParser/error"; import { type DataParserChecker } from "../../baseChecker"; -import { type GetEligibleChecker, type AddCheckersToDefinition, type MergeDefinition, type Output, type PrepareDataParserDefinition } from "../../types"; +import { type GetEligibleChecker, type AddCheckersToDefinition, type MergeDefinition, type Output, type PrepareDataParserDefinition, type ApplyRefinementOfChecker } from "../../types"; export * from "./checkers"; @@ -23,7 +23,10 @@ export class DataParserString< stringKind, )< GenericDefinition, - string, + ApplyRefinementOfChecker< + string, + GenericDefinition + >, string > { public get classConstructor() { diff --git a/scripts/dataParser/types/checkers.ts b/scripts/dataParser/types/checkers.ts index 705585a3e..bf2f317bd 100644 --- a/scripts/dataParser/types/checkers.ts +++ b/scripts/dataParser/types/checkers.ts @@ -1,7 +1,9 @@ -import { type IsExtends } from "@scripts/common"; +import { type NeverCoalescing, type UnionToIntersection, type AnyPredicate, type IsExtends } from "@scripts/common"; import { type DataParserChecker } from "../baseChecker"; import type * as AllDataParser from "../parsers"; -import { type TheTime } from "@scripts/date"; +import type * as DDate from "@scripts/date"; +import type * as DArray from "@scripts/array"; +import { type DataParserDefinition } from "../base"; export interface CheckerCustom { base: DataParserChecker; @@ -65,7 +67,7 @@ export interface EligibleChecker< | AllDataParser.DataParserCheckerUuid ) : never; - time: IsExtends extends true + time: IsExtends extends true ? ( | AllDataParser.DataParserCheckerTimeMax | AllDataParser.DataParserCheckerTimeMin @@ -83,3 +85,51 @@ export type GetEligibleChecker< > > : never; + +export interface RefinementOfChecker< + GenericValue extends unknown, + GenericChecker extends DataParserChecker, +> { + refine: GenericChecker extends AllDataParser.DataParserCheckerRefine + ? GenericChecker["definition"]["theFunction"] extends AnyPredicate + ? InferredPredicate + : never + : never; + + arrayMin: GenericChecker extends AllDataParser.DataParserCheckerArrayMin + ? number extends GenericChecker["definition"]["min"] + ? never + : GenericValue extends readonly unknown[] + ? [ + ...DArray.CreateTuple, + ...GenericValue[number][], + ] + : never + : never; + arrayMax: GenericChecker extends AllDataParser.DataParserCheckerArrayMax + ? number extends GenericChecker["definition"]["max"] + ? never + : GenericValue & DArray.MaxElements + : never; +} + +export type ApplyRefinementOfChecker< + GenericValue extends unknown, + GenericDataParserDefinition extends DataParserDefinition, +> = GenericDataParserDefinition["checkers"][number] extends infer inferredChecker extends DataParserChecker + ? NeverCoalescing< + UnionToIntersection< + inferredChecker extends any + ? RefinementOfChecker extends infer InferredResult + ? InferredResult[keyof InferredResult] + : never + : never + > extends infer InferredResult extends GenericValue + ? ( + & InferredResult + & GenericValue + ) + : never, + GenericValue + > + : never; diff --git a/tests/dataParser/parsers/array/checkers/max.test.ts b/tests/dataParser/parsers/array/checkers/max.test.ts index 33d133300..79bcaca79 100644 --- a/tests/dataParser/parsers/array/checkers/max.test.ts +++ b/tests/dataParser/parsers/array/checkers/max.test.ts @@ -1,4 +1,4 @@ -import { DDataParser, DEither } from "@scripts"; +import { type DArray, DDataParser, DEither, type ExpectType } from "@scripts"; describe("DDataParser array checker max", () => { it("accepts arrays at or below maximum length", () => { @@ -12,6 +12,12 @@ describe("DDataParser array checker max", () => { }, ); + type check = ExpectType< + DDataParser.Output, + string[] & DArray.MaxElements<3>, + "strict" + >; + expect(schema.parse(["a", "b"])).toStrictEqual(DEither.success(["a", "b"])); expect(schema.parse(["one", "two", "three"])).toStrictEqual( DEither.success(["one", "two", "three"]), diff --git a/tests/dataParser/parsers/array/checkers/min.test.ts b/tests/dataParser/parsers/array/checkers/min.test.ts index f10ffa7f2..0bbd5cade 100644 --- a/tests/dataParser/parsers/array/checkers/min.test.ts +++ b/tests/dataParser/parsers/array/checkers/min.test.ts @@ -1,4 +1,4 @@ -import { DDataParser, DEither } from "@scripts"; +import { DDataParser, DEither, type ExpectType } from "@scripts"; describe("DDataParser array checker min", () => { it("accepts arrays at or above minimum length", () => { @@ -12,6 +12,12 @@ describe("DDataParser array checker min", () => { }, ); + type check = ExpectType< + DDataParser.Output, + [string, string, ...string[]] & string[], + "strict" + >; + expect(schema.parse(["a", "b"])).toStrictEqual(DEither.success(["a", "b"])); expect(schema.parse(["one", "two", "three"])).toStrictEqual( DEither.success(["one", "two", "three"]), diff --git a/tests/dataParser/parsers/array/index.test.ts b/tests/dataParser/parsers/array/index.test.ts index 2159c34b2..86fc449b4 100644 --- a/tests/dataParser/parsers/array/index.test.ts +++ b/tests/dataParser/parsers/array/index.test.ts @@ -1,4 +1,4 @@ -import { DDataParser, DEither, type ExpectType } from "@scripts"; +import { DArray, DDataParser, DEither, type ExpectType } from "@scripts"; describe("DDataParser array", () => { it("create data parser with checker", () => { @@ -20,7 +20,28 @@ describe("DDataParser array", () => { }), ); - void dataParser; + type _CheckOut = ExpectType< + DDataParser.Output, + string[], + "strict" + >; + }); + + it("create data parser with refine predicate checker", () => { + const dataParser = DDataParser.array(DDataParser.string(), { + checkers: [DDataParser.checkerRefine(DArray.maxElements(10))], + }).addChecker( + DDataParser.checkerRefine((value) => { + type check = ExpectType, "strict">; + return true; + }), + ); + + type _CheckOut = ExpectType< + DDataParser.Output, + string[] & DArray.MaxElements<10>, + "strict" + >; }); it("success parsing", () => { diff --git a/tests/dataParser/parsers/string/index.test.ts b/tests/dataParser/parsers/string/index.test.ts index e6c51a3cc..94434c253 100644 --- a/tests/dataParser/parsers/string/index.test.ts +++ b/tests/dataParser/parsers/string/index.test.ts @@ -1,4 +1,4 @@ -import { DDataParser, DEither, type ExpectType } from "@scripts"; +import { DDataParser, DEither, DString, type ExpectType } from "@scripts"; describe("DDataParser string", () => { it("create data parser with checker", () => { @@ -16,7 +16,28 @@ describe("DDataParser string", () => { }), ); - void dataParser; + type _CheckOut = ExpectType< + DDataParser.Output, + string, + "strict" + >; + }); + + it("create data parser with refine predicate checker", () => { + const dataParser = DDataParser.string({ + checkers: [DDataParser.checkerRefine(DString.startsWith("test"))], + }).addChecker( + DDataParser.checkerRefine((value) => { + type check = ExpectType; + return true; + }), + ); + + type _CheckOut = ExpectType< + DDataParser.Output, + `test${string}`, + "strict" + >; }); it("succes parsing", () => {