diff --git a/package.json b/package.json index 0e7c7ba2..8207f64a 100644 --- a/package.json +++ b/package.json @@ -32,7 +32,7 @@ "jest": "^27.0.1", "rimraf": "^3.0.2", "ts-jest": "^27.0.0", - "typescript": "^4.2.4" + "typescript": "^4.3.2" }, "resolutions": { "minimist": "1.2.5" diff --git a/packages/app/src/Route/Route.ts b/packages/app/src/Route/Route.ts index ffc5b5f7..42ae45bf 100644 --- a/packages/app/src/Route/Route.ts +++ b/packages/app/src/Route/Route.ts @@ -1,13 +1,12 @@ import {ActionAny} from "@bunt/unit"; import {Ctor, ILogable, isFunction, isString} from "@bunt/util"; -import {Payload} from "../Payload"; -import {IRoute, IRouteMatcher, RouteFactory, RouteMatcherFactory, RouteRuleArg} from "./interfaces"; +import {IRoute, IRouteMatcher, RouteFactory, RouteMatcherFactory, RouteRuleArg, RouteRuleVariants} from "./interfaces"; import {RouteRule} from "./RouteRule"; export class Route implements IRoute, ILogable<{ route: string }> { public readonly route: string; public readonly action: Ctor; - public readonly payload?: Payload; + public readonly payload?: RouteRule; readonly #matcher: IRouteMatcher; constructor(matcher: RouteMatcherFactory, action: Ctor, rule: RouteRuleArg) { @@ -37,7 +36,7 @@ export class Route implements IRoute, ILogable<{ route: return this.#matcher.match(route); } - private getRuleArgs(rule: string | RouteRule): { route: string, payload?: Payload } { + private getRuleArgs(rule: RouteRuleArg): RouteRuleVariants { if (isString(rule)) { return {route: rule, payload: undefined}; } diff --git a/packages/app/src/Route/interfaces.ts b/packages/app/src/Route/interfaces.ts index a323e4d3..b6be16d8 100644 --- a/packages/app/src/Route/interfaces.ts +++ b/packages/app/src/Route/interfaces.ts @@ -1,4 +1,4 @@ -import {ActionAny, ActionContext, ActionCtor, ApplyContext, Context} from "@bunt/unit"; +import {ActionAny, ActionContext, ActionCtor, ActionState, ApplyContext} from "@bunt/unit"; import {Ctor} from "@bunt/util"; import {IRequest} from "../interfaces"; import {Payload} from "../Payload"; @@ -19,9 +19,11 @@ export interface IRoute { export type RouteMatcherFactory = IRouteMatcher | ((route: string) => IRouteMatcher); -export type RouteRuleArg = A extends ActionAny - ? S extends null ? string : RouteRule - : string; +export type RouteRuleVariants = { route: string, payload: undefined } + | { route: string, payload: RouteRule }; + +export type RouteRuleArg = ActionState extends null + ? string : RouteRule; export type RouteFactory = (action: Ctor, rule: RouteRuleArg) => Route; diff --git a/packages/input/src/Assertion/AssertionListError.ts b/packages/input/src/Assertion/AssertionListError.ts index 182d537a..3ac3cf4d 100644 --- a/packages/input/src/Assertion/AssertionListError.ts +++ b/packages/input/src/Assertion/AssertionListError.ts @@ -12,10 +12,7 @@ export interface IReadableListError extends IReadableTypeError { export class AssertionListError extends AssertionTypeError { readonly #fields: IReadableListField[]; - constructor(message: string, - type: TypeAbstract, - payload: unknown, - fields: IReadableListField[]) { + constructor(message: string, type: TypeAbstract, payload: unknown, fields: IReadableListField[]) { super(message, type, payload); this.#fields = fields; } diff --git a/packages/input/src/Assertion/AssertionObjectError.ts b/packages/input/src/Assertion/AssertionObjectError.ts index 7afe2b9a..6497d949 100644 --- a/packages/input/src/Assertion/AssertionObjectError.ts +++ b/packages/input/src/Assertion/AssertionObjectError.ts @@ -9,7 +9,7 @@ export class AssertionObjectError extends AssertionTypeError { readonly #fields: Record; constructor(message: string, - type: TypeAbstract, + type: TypeAbstract, payload: unknown, fields: Record) { super(message, type, payload); diff --git a/packages/input/src/Assertion/AssertionTypeError.ts b/packages/input/src/Assertion/AssertionTypeError.ts index 4ba6fca6..89953d4c 100644 --- a/packages/input/src/Assertion/AssertionTypeError.ts +++ b/packages/input/src/Assertion/AssertionTypeError.ts @@ -9,9 +9,9 @@ export interface IReadableTypeError { export class AssertionTypeError extends Error implements IReadableError, ILogable { readonly #payload: unknown; - readonly #type: TypeAbstract; + readonly #type: TypeAbstract; - constructor(message: string, type: TypeAbstract, payload: unknown) { + constructor(message: string, type: TypeAbstract, payload: unknown) { super(message); this.#payload = payload; this.#type = type; diff --git a/packages/input/src/Assertion/assertion.ts b/packages/input/src/Assertion/assertion.ts index 0a6264bd..e4e8b705 100644 --- a/packages/input/src/Assertion/assertion.ts +++ b/packages/input/src/Assertion/assertion.ts @@ -1,7 +1,7 @@ import {TypeAbstract} from "../TypeAbstract"; import {AssertionTypeError} from "./AssertionTypeError"; -export function assert(expr: unknown, type: TypeAbstract, message: string, payload: unknown): asserts expr { +export function assert(expr: unknown, type: TypeAbstract, message: string, payload: unknown): asserts expr { if (!expr) { throw new AssertionTypeError(message, type, payload); } diff --git a/packages/input/src/SuperType.ts b/packages/input/src/SuperType.ts index a4bd86ac..9830282e 100644 --- a/packages/input/src/SuperType.ts +++ b/packages/input/src/SuperType.ts @@ -1,12 +1,9 @@ -import {MayInput} from "./interfaces"; import {TypeAbstract} from "./TypeAbstract"; -export abstract class SuperType extends TypeAbstract { - protected readonly type: TypeAbstract; +export abstract class SuperType extends TypeAbstract { + protected readonly type: TypeAbstract; - constructor(type: TypeAbstract) { + constructor(type: TypeAbstract) { super(); this.type = type; } diff --git a/packages/input/src/Type/Bool.ts b/packages/input/src/Type/Bool.ts index 6bd54a05..685a662c 100644 --- a/packages/input/src/Type/Bool.ts +++ b/packages/input/src/Type/Bool.ts @@ -1,7 +1,7 @@ import {isBoolean} from "@bunt/util"; import {ScalarType} from "./ScalarType"; -export const Bool = new ScalarType({ +export const Bool = new ScalarType({ name: "Bool", validate(payload) { this.assert(isBoolean(payload), `Wrong payload: ${this.name} expected`, payload); diff --git a/packages/input/src/Type/DateTime.ts b/packages/input/src/Type/DateTime.ts index 19a24339..8b997bc4 100644 --- a/packages/input/src/Type/DateTime.ts +++ b/packages/input/src/Type/DateTime.ts @@ -1,7 +1,7 @@ import {isNumber, isString} from "@bunt/util"; import {ScalarType} from "./ScalarType"; -export const DateTime = new ScalarType({ +export const DateTime = new ScalarType({ name: "DateTime", validate(payload) { this.assert(isNumber(payload) || isString(payload), `Wrong payload: ${this.name} expected`, payload); diff --git a/packages/input/src/Type/Enum.ts b/packages/input/src/Type/Enum.ts index 694d5314..a652c654 100644 --- a/packages/input/src/Type/Enum.ts +++ b/packages/input/src/Type/Enum.ts @@ -1,5 +1,4 @@ -import {isString, MayNullable, Promisify} from "@bunt/util"; -import {MayInput} from "../interfaces"; +import {isString, Promisify} from "@bunt/util"; import {TypeAbstract} from "../TypeAbstract"; export class Enum extends TypeAbstract { @@ -10,7 +9,7 @@ export class Enum extends TypeAbstract { this.#value = value; } - public validate(input: MayNullable): Promisify { + public validate(input: unknown): Promisify { this.assert(isString(input), "Wrong type", input); this.assert(!/^\d+$/.test(input), "Wrong value", input); this.assert(input in this.#value, "Wrong value", input); diff --git a/packages/input/src/Type/Fields.ts b/packages/input/src/Type/Fields.ts index 5ea7a24c..826fc81b 100644 --- a/packages/input/src/Type/Fields.ts +++ b/packages/input/src/Type/Fields.ts @@ -1,9 +1,9 @@ -import {entriesReverse, isFunction, isInstanceOf, isObject, MayNullable} from "@bunt/util"; +import {entriesReverse, isFunction, isInstanceOf, isObject} from "@bunt/util"; import {AssertionObjectError, AssertionTypeError, IReadableTypeError} from "../Assertion"; import {ObjectFields, ObjectTypeMerge} from "../interfaces"; import {TypeAbstract} from "../TypeAbstract"; -export class Fields> extends TypeAbstract> { +export class Fields> extends TypeAbstract { readonly #fields: ObjectFields; readonly #name: string; @@ -33,7 +33,7 @@ export class Fields> extends TypeAbstract>): Promise { + public async validate(payload: unknown): Promise { this.assert(isObject(payload), `Wrong payload: ${this.name} expected`, payload); const entries: [string, any][] = []; diff --git a/packages/input/src/Type/Float.ts b/packages/input/src/Type/Float.ts index 2eb21e53..9257826d 100644 --- a/packages/input/src/Type/Float.ts +++ b/packages/input/src/Type/Float.ts @@ -1,7 +1,7 @@ import {isNumber} from "@bunt/util"; import {ScalarType} from "./ScalarType"; -export const Float = new ScalarType({ +export const Float = new ScalarType({ name: "Float", validate(payload) { this.assert(isNumber(payload), `Wrong payload: ${this.name} expected`, payload); diff --git a/packages/input/src/Type/Int.ts b/packages/input/src/Type/Int.ts index a7e26172..c40a6d6e 100644 --- a/packages/input/src/Type/Int.ts +++ b/packages/input/src/Type/Int.ts @@ -1,7 +1,7 @@ import {isNumber} from "@bunt/util"; import {ScalarType} from "./ScalarType"; -export const Int = new ScalarType({ +export const Int = new ScalarType({ name: "Int", validate(payload) { this.assert(isNumber(payload), `Wrong payload: ${this.name} expected`, payload); diff --git a/packages/input/src/Type/JSONString.ts b/packages/input/src/Type/JSONString.ts index 82f7a686..6a7ca62d 100644 --- a/packages/input/src/Type/JSONString.ts +++ b/packages/input/src/Type/JSONString.ts @@ -1,8 +1,11 @@ +import {isString} from "@bunt/util"; import {ScalarType} from "./ScalarType"; -export const JSONString = new ScalarType({ +export const JSONString = new ScalarType({ name: "JSON", validate(payload) { + this.assert(isString(payload), "Wrong payload", payload); + return JSON.parse(payload); }, }); diff --git a/packages/input/src/Type/List.ts b/packages/input/src/Type/List.ts index b183eff7..3a25865e 100644 --- a/packages/input/src/Type/List.ts +++ b/packages/input/src/Type/List.ts @@ -1,11 +1,9 @@ -import {isArray, isInstanceOf, MayNullable} from "@bunt/util"; +import {isArray, isInstanceOf} from "@bunt/util"; import {AssertionListError, AssertionTypeError, IReadableListField} from "../Assertion"; -import {MayListInput} from "../interfaces"; import {SuperType} from "../SuperType"; -export class List - extends SuperType, TInput> { - public async validate(payload: MayNullable): Promise { +export class List extends SuperType { + public async validate(payload: unknown): Promise { this.assert(isArray(payload), `Wrong payload: ${this.type.name}[] expected`, payload); let index = 0; diff --git a/packages/input/src/Type/NonNull.ts b/packages/input/src/Type/NonNull.ts index 167536e1..809787c0 100644 --- a/packages/input/src/Type/NonNull.ts +++ b/packages/input/src/Type/NonNull.ts @@ -1,17 +1,16 @@ -import {isFunction, isNull, isUndefined, MayNullable, Promisify} from "@bunt/util"; -import {MayInput} from "../interfaces"; +import {isFunction, isNull, isUndefined, Promisify} from "@bunt/util"; import {SuperType} from "../SuperType"; import {TypeAbstract} from "../TypeAbstract"; -export class NonNull extends SuperType { +export class NonNull extends SuperType { readonly #defaultValue: TValue | (() => TValue); - constructor(type: TypeAbstract, defaultValue: TValue | (() => TValue)) { + constructor(type: TypeAbstract, defaultValue: TValue | (() => TValue)) { super(type); this.#defaultValue = defaultValue; } - public validate(payload: MayNullable): Promisify { + public validate(payload: unknown): Promisify { if (isNull(payload) || isUndefined(payload)) { if (isFunction(this.#defaultValue)) { return this.#defaultValue(); diff --git a/packages/input/src/Type/Nullable.ts b/packages/input/src/Type/Nullable.ts index 91349cde..2d27e8b1 100644 --- a/packages/input/src/Type/Nullable.ts +++ b/packages/input/src/Type/Nullable.ts @@ -1,9 +1,8 @@ -import {isNull, isUndefined, MayNullable, Promisify} from "@bunt/util"; -import {MayInput} from "../interfaces"; +import {isNull, isUndefined, Promisify} from "@bunt/util"; import {SuperType} from "../SuperType"; -export class Nullable extends SuperType { - public validate(payload: MayNullable): Promisify { +export class Nullable extends SuperType { + public validate(payload: unknown): Promisify { if (isNull(payload) || isUndefined(payload)) { return undefined; } diff --git a/packages/input/src/Type/Numeric.ts b/packages/input/src/Type/Numeric.ts index 490c54eb..e47d7efd 100644 --- a/packages/input/src/Type/Numeric.ts +++ b/packages/input/src/Type/Numeric.ts @@ -1,7 +1,7 @@ import {isNumber, isString} from "@bunt/util"; import {ScalarType} from "./ScalarType"; -export const Numeric = new ScalarType({ +export const Numeric = new ScalarType({ name: "Numeric", validate(payload) { this.assert(isNumber(payload) || isString(payload), `Wrong payload: ${this.name} expected`, payload); diff --git a/packages/input/src/Type/ScalarType.ts b/packages/input/src/Type/ScalarType.ts index 979bac90..1df45e2b 100644 --- a/packages/input/src/Type/ScalarType.ts +++ b/packages/input/src/Type/ScalarType.ts @@ -1,16 +1,15 @@ -import {MayNullable, Promisify} from "@bunt/util"; -import {MayInput} from "../interfaces"; +import {Promisify} from "@bunt/util"; import {TypeAbstract} from "../TypeAbstract"; -export interface IScalarType { +export interface IScalarType { name: string; - validate: (this: ScalarType, payload: MayNullable) => Promisify; + validate: (this: ScalarType, payload: unknown) => Promisify; } -export class ScalarType extends TypeAbstract { - readonly #type: IScalarType; +export class ScalarType extends TypeAbstract { + readonly #type: IScalarType; - public constructor(type: IScalarType) { + public constructor(type: IScalarType) { super(); this.#type = type; } @@ -19,7 +18,7 @@ export class ScalarType extends TypeAbstract): Promisify { + public validate(payload: unknown): Promisify { return this.#type.validate.call(this, payload); } } diff --git a/packages/input/src/Type/Text.ts b/packages/input/src/Type/Text.ts index 8b353654..00a5fada 100644 --- a/packages/input/src/Type/Text.ts +++ b/packages/input/src/Type/Text.ts @@ -1,10 +1,11 @@ import {isString} from "@bunt/util"; import {ScalarType} from "./ScalarType"; -export const Text = new ScalarType({ +export const Text = new ScalarType({ name: "Text", validate(payload) { this.assert(isString(payload), `Wrong payload: ${this.name} expected`, payload); + return payload; }, }); diff --git a/packages/input/src/Type/ToNumber.ts b/packages/input/src/Type/ToNumber.ts index e6b11a7e..0d2b064b 100644 --- a/packages/input/src/Type/ToNumber.ts +++ b/packages/input/src/Type/ToNumber.ts @@ -1,9 +1,10 @@ -import {isNumber, isString, MayNullable, Promisify} from "@bunt/util"; +import {isNumber, isString, Promisify} from "@bunt/util"; import {SuperType} from "../SuperType"; -export class ToNumber extends SuperType { - public validate(payload: MayNullable): Promisify { +export class ToNumber extends SuperType { + public validate(payload: unknown): Promisify { this.assert(isNumber(payload) || isString(payload), `Wrong payload type`, payload); + return this.type.validate(+payload); } } diff --git a/packages/input/src/Type/UUID.ts b/packages/input/src/Type/UUID.ts index 6c3abd73..64447bfb 100644 --- a/packages/input/src/Type/UUID.ts +++ b/packages/input/src/Type/UUID.ts @@ -3,10 +3,11 @@ import {ScalarType} from "./ScalarType"; const RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89AB][0-9a-f]{3}-[0-9a-f]{12}$/i; -export const UUID = new ScalarType({ +export const UUID = new ScalarType({ name: "UUID", validate(payload) { this.assert(isString(payload) && RE.test(payload), `Wrong payload: ${this.name} expected`, payload); + return payload; }, }); diff --git a/packages/input/src/Type/Union.ts b/packages/input/src/Type/Union.ts index c964c98a..bdc8c94e 100644 --- a/packages/input/src/Type/Union.ts +++ b/packages/input/src/Type/Union.ts @@ -1,15 +1,13 @@ -import {MayNullable, Promisify} from "@bunt/util"; -import {MayInput} from "../interfaces"; +import {Promisify} from "@bunt/util"; import {TypeAbstract} from "../TypeAbstract"; -export type UnionSelector = - (input: MayNullable) => TypeAbstract | undefined; +export type UnionSelector = (input: unknown) => TypeAbstract | undefined; -export class Union extends TypeAbstract { - readonly #selector: UnionSelector; +export class Union extends TypeAbstract { + readonly #selector: UnionSelector; readonly #name: string; - constructor(selector: UnionSelector, name = "Union") { + constructor(selector: UnionSelector, name = "Union") { super(); this.#selector = selector; this.#name = name; @@ -19,9 +17,10 @@ export class Union extends TypeAbstr return this.#name; } - public validate(input: MayNullable): Promisify { + public validate(input: unknown): Promisify { const type = this.#selector(input); this.assert(!!type, `${this.name} detection was failed`, input); + return type.validate(input) as Promisify; } } diff --git a/packages/input/src/Type/Varchar.ts b/packages/input/src/Type/Varchar.ts index 818f7814..9d685c01 100644 --- a/packages/input/src/Type/Varchar.ts +++ b/packages/input/src/Type/Varchar.ts @@ -6,7 +6,7 @@ interface IVarchar { readonly max?: number; } -export class Varchar extends TypeAbstract { +export class Varchar extends TypeAbstract { readonly #options: IVarchar; constructor(options: IVarchar = {}) { diff --git a/packages/input/src/Type/index.ts b/packages/input/src/Type/index.ts index 1a08f578..fc619198 100644 --- a/packages/input/src/Type/index.ts +++ b/packages/input/src/Type/index.ts @@ -3,7 +3,6 @@ export * from "./Float"; export * from "./Int"; export * from "./ToNumber"; export * from "./List"; -export * from "./NonNull"; export * from "./Nullable"; export * from "./NonNull"; export * from "./Fields"; diff --git a/packages/input/src/TypeAbstract.ts b/packages/input/src/TypeAbstract.ts index 426b37d2..adf0ecee 100644 --- a/packages/input/src/TypeAbstract.ts +++ b/packages/input/src/TypeAbstract.ts @@ -1,13 +1,12 @@ -import {MayNullable, Promisify} from "@bunt/util"; +import {Promisify} from "@bunt/util"; import {assert} from "./Assertion"; -import {MayInput} from "./interfaces"; -export abstract class TypeAbstract { +export abstract class TypeAbstract { public get name(): string { return this.constructor.name; } - public abstract validate(input: MayNullable): Promisify; + public abstract validate(input: unknown): Promisify; public assert(expr: unknown, message: string, payload: unknown): asserts expr { assert(expr, this, message, payload); diff --git a/packages/input/src/functions.ts b/packages/input/src/functions.ts index e2af5a86..b70dada4 100644 --- a/packages/input/src/functions.ts +++ b/packages/input/src/functions.ts @@ -1,11 +1,11 @@ import {isFunction} from "@bunt/util"; -import {FieldSelectType, MayInput} from "./interfaces"; +import {FieldSelectType} from "./interfaces"; import {TypeAbstract} from "./TypeAbstract"; export async function validate(type: FieldSelectType, value: unknown): Promise { if (isFunction(type)) { - return type().validate(value as MayInput); + return type().validate(value); } - return (type as TypeAbstract).validate(value as MayInput); + return (type as TypeAbstract).validate(value); } diff --git a/packages/input/src/interfaces.ts b/packages/input/src/interfaces.ts index 9d2659ac..eb5c6030 100644 --- a/packages/input/src/interfaces.ts +++ b/packages/input/src/interfaces.ts @@ -1,37 +1,23 @@ -import {MaybeArray, MayNullable} from "@bunt/util"; import {Fields, List, Union} from "./Type"; import {TypeAbstract} from "./TypeAbstract"; -export type Scalars = string | number | boolean; - -export interface Compound { - [key: string]: MaybeArray; -} - -export type MayInput = MayNullable>>; -export type MayListInput = MayNullable; - export type FieldFn = () => T; export type FieldType = T | FieldFn; export type FieldsSchema = { [K in keyof T]-?: T[K] extends Array - ? FieldType> + ? FieldType> : T[K] extends Date - ? FieldType> + ? FieldType> : T[K] extends Record ? FieldType | Union> - : FieldType>; + : FieldType>; }; export type ObjectFields = T extends Promise ? FieldsSchema> : FieldsSchema>; -export type FieldSelectType = T extends Record - ? FieldType> - : T extends Array - ? FieldType> - : FieldType>; +export type FieldSelectType = FieldType>; export type ObjectTypeMerge> = Fields | ObjectFields; diff --git a/packages/input/test/src/Main.test.ts b/packages/input/test/src/Main.test.ts index e876140a..ff795232 100644 --- a/packages/input/test/src/Main.test.ts +++ b/packages/input/test/src/Main.test.ts @@ -22,7 +22,7 @@ import {TestEnum, TestEnumType} from "./Type/TestEnum"; describe("Test Input", () => { const rand = Math.random(); - const union = new Union( + const union = new Union( (input) => { switch (typeof input) { case "string": @@ -34,7 +34,7 @@ describe("Test Input", () => { }, ); - const samples: [any, any, TypeAbstract][] = [ + const samples: [any, any, TypeAbstract][] = [ [1, 1, Int], ["1", 1, new ToNumber(Int)], [false, false, Bool], @@ -82,7 +82,7 @@ describe("Test Input", () => { name: Text, children: () => new NonNull(new List(human), []), parent: () => new Nullable(human), - links: () => new List(Text), + links: new List(Text), hobby: new Nullable(Hobby), }, "Human"); diff --git a/yarn.lock b/yarn.lock index 842566ba..85c241d6 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7103,10 +7103,10 @@ typedarray@^0.0.6: resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c= -typescript@^4.2.4: - version "4.2.4" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.2.4.tgz#8610b59747de028fda898a8aef0e103f156d0961" - integrity sha512-V+evlYHZnQkaz8TRBuxTA92yZBPotr5H+WhQ7bD3hZUndx5tGOa1fuCgeSjxAzM1RiN5IzvadIXTVefuuwZCRg== +typescript@^4.3.2: + version "4.3.2" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.3.2.tgz#399ab18aac45802d6f2498de5054fcbbe716a805" + integrity sha512-zZ4hShnmnoVnAHpVHWpTcxdv7dWP60S2FsydQLV8V5PbS3FifjWFFRiHSWpDJahly88PRyV5teTSLoq4eG7mKw== uglify-js@^3.1.4: version "3.13.5"