diff --git a/package.json b/package.json index 86482fea4..e6f27648f 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,6 @@ "build": "tsc --build", "docs": "npm i --force --silent && typedoc", "build-docs": "npm run clean && npm run build --silent && npm run docs", - "core/main": "test -d ./node_modules || npm i --force && ts-node packages/core/src/main.ts", "core/test": "npm run test --prefix=packages/core", "core/build": "npm run build --prefix=packages/core", "core/deploy:minor": "npm run deploy:minor --prefix=packages/core", diff --git a/packages/core/package.json b/packages/core/package.json index 0953ee222..39ab1b5f3 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -16,8 +16,7 @@ "deploy:minor": "bash ../../scripts/deploy.sh core minor", "deploy:major": "bash ../../scripts/deploy.sh core major", "deploy:patch": "bash ../../scripts/deploy.sh core patch", - "test": "bash ../../scripts/test.sh core", - "main": "ts-node src/main.ts" + "test": "bash ../../scripts/test.sh core" }, "repository": { "type": "git", diff --git a/packages/core/src/main.ts b/packages/core/src/main.ts deleted file mode 100644 index dee692805..000000000 --- a/packages/core/src/main.ts +++ /dev/null @@ -1,133 +0,0 @@ -import Required from "../validators/any/Required"; -import Rule from "../validators/any/Rule"; -import Truthy from "../validators/any/Truthy"; -import valid from "../validators/any/valid"; -import validators from "../validators/index"; -import ExactLength from "../validators/string/ExactLength"; -import MaxLength from "../validators/string/MaxLength"; -import MinLength from "../validators/string/MinLength"; -import Password from "../validators/string/Password"; -import Email from "../validators/string/regex/impl/Email"; -import { DecoratorPartialProps } from "./decorators/types/DecoratorProps.type"; -import { setLocale } from "./messages/model/Locale"; -import EntityProcessor from "./model/processor/EntityProcessor"; -import { StripClass } from "./types/Class.type"; -import { TypeGroup } from "./types/namespace/TypeGroup.ns"; -import { $ } from "./types/namespace/Utility.ns"; -import { extractGroups, extractMessage } from "./utils/decorator.utils"; - -setLocale("en"); - -export class SomeClass { - idk?: string; -} - -// prettier-ignore -function ExactCharCount>(props: DecoratorPartialProps) { - const key = "ExactCharCount"; - const charCount: number = typeof props === "number" ? props : props.value; - const defaultMessage = `Text must have exactly ${charCount} characters` - return Rule({ - groups: extractGroups(props), - isValid: (v: T) => ({ - key, - message: extractMessage(props, defaultMessage), - valid: v?.length === charCount, - }), - }); -} - -export class AddressForm { - @ExactLength(2) - @Required() - @ExactCharCount(10) - country!: string; -} - -export class UserForm2 { - @MinLength(5) - @MaxLength(10) - @Required() - firstName?: string; - - @MinLength(5) - @MaxLength(10) - @Required() - lastName?: string; - - @Password() - @Required() - password?: string; - - @Email() - @Required() - email?: string; - - @valid(AddressForm) - addressForm?: AddressForm; - - someClass?: SomeClass; - - @Truthy() - get passwordsMatch() { - return false; - } -} - -type AddressFormType = TypeGroup.Primitive; -// ^? - -export type UserFormFields = { - confirmPassword: string; - firstName: string; - lastName: string; - password: string; - url: string; - age: number; -}; - -export default class UserForm implements UserFormFields { - @validators.string.MinLength(5) - @validators.string.Required() - firstName!: string; - - @validators.string.Required() - lastName!: string; - - @validators.string.Required() - @validators.string.Password() - password!: string; - - confirmPassword!: string; - - @validators.string.URL() - url!: string; - - @validators.number.ValueRange({ min: 18, max: 100 }) - age!: number; - - @validators.boolean.Truthy("Passwords must match") - get passwordsMatch(): boolean { - return this.password === this.confirmPassword; - } -} - -const dummy: Partial = { - firstName: "", - lastName: "", - password: "12345", - confirmPassword: "", - url: "", - age: 10, -}; - -function main() { - const processor = new EntityProcessor(UserForm); - const { errors } = processor.validate(dummy); - console.log(JSON.stringify(errors, null, 2)); -} - -main(); - -type TestType = StripClass; -// ^? diff --git a/packages/core/src/messages/message.factory.ts b/packages/core/src/messages/message.factory.ts index 0dec614d0..552682e9f 100644 --- a/packages/core/src/messages/message.factory.ts +++ b/packages/core/src/messages/message.factory.ts @@ -1,8 +1,13 @@ import { $ } from "../types/namespace/Utility.ns"; -import { sprintf } from "../utils/string.utils"; import { getLocale } from "./model/Locale"; import translations from "./model/Translations"; +function sprintf(str: string, ...args: any[]) { + return str.replace(/{(\d+)}/g, function (match, number) { + return typeof args[number] != "undefined" ? args[number] : match; + }); +} + export type MessageFn = $.FuncFactory; // Central method for getting translation handlers. diff --git a/packages/core/src/utils/array.utils.ts b/packages/core/src/utils/array.utils.ts deleted file mode 100644 index 7ffeb7eec..000000000 --- a/packages/core/src/utils/array.utils.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { $ } from "../types/namespace/Utility.ns"; - -export function isArrayUnique(arr: T[], equals: $.Equals): boolean { - const set = new Set(); - for (const val of arr) { - for (const el of set) { - if (equals(val, el)) { - return false; - } - } - set.add(val); - } - return true; -} diff --git a/packages/core/src/utils/class.utils.ts b/packages/core/src/utils/class.utils.ts index 8b91a00b3..7199f26d5 100644 --- a/packages/core/src/utils/class.utils.ts +++ b/packages/core/src/utils/class.utils.ts @@ -3,15 +3,17 @@ import { ConstructorType } from "../types/Class.type"; export function getClassFieldNames( constructor: ConstructorType ): string[] { - const instance = new constructor(); - return [ - ...getPropertyNames(instance), - ...getPropertyNames((instance as any).__proto__), - ]; + const instance: any = new constructor(); + const prototype = instance.__proto__; + const instanceProps = getPropertyNames(instance); + const prototypeProps = getPropertyNames(prototype); + const uniquePropsSet = new Set([...instanceProps, ...prototypeProps]); + const uniquePropsArray = [...uniquePropsSet]; + return uniquePropsArray; } -function getPropertyNames(object: any): string[] { - return Object.getOwnPropertyNames(object).filter( +function getPropertyNames(classInstance: any): string[] { + return Object.getOwnPropertyNames(classInstance ?? {}).filter( (property) => property !== "constructor" ); } diff --git a/packages/core/src/utils/object.utils.ts b/packages/core/src/utils/object.utils.ts index a4c09e725..5ba8a827b 100644 --- a/packages/core/src/utils/object.utils.ts +++ b/packages/core/src/utils/object.utils.ts @@ -8,10 +8,16 @@ function hasSetter(parent: T, key: K): boolean { ); } +function isFunctionSetter( + value: T[K] | (() => T[K]) +): value is () => T[K] { + return typeof value === "function"; +} + export function safeSetter(parent: T, key: K) { return (value: T[K] | (() => T[K])) => { if (hasSetter(parent, key)) { - parent[key] = typeof value === "function" ? (value as Function)() : value; + parent[key] = isFunctionSetter(value) ? value() : value; } }; } diff --git a/packages/core/src/utils/string.utils.ts b/packages/core/src/utils/string.utils.ts deleted file mode 100644 index 520a6aad2..000000000 --- a/packages/core/src/utils/string.utils.ts +++ /dev/null @@ -1,5 +0,0 @@ -export function sprintf(str: string, ...args: any[]) { - return str.replace(/{(\d+)}/g, function (match, number) { - return typeof args[number] != "undefined" ? args[number] : match; - }); -} diff --git a/packages/core/validators/array/ArrayUnique.ts b/packages/core/validators/array/ArrayUnique.ts index 231e7ff82..212df759e 100644 --- a/packages/core/validators/array/ArrayUnique.ts +++ b/packages/core/validators/array/ArrayUnique.ts @@ -1,13 +1,12 @@ import { makeValidator } from "../../src/decorators/facade/validator.facade"; -import ErrorMessage from "../../src/messages/impl/ErrorMessage"; -import { hash } from "../../src/utils/object.utils"; -import { $ } from "../../src/types/namespace/Utility.ns"; -import { isArrayUnique } from "../../src/utils/array.utils"; -import { extractGroups, extractMessage } from "../../src/utils/decorator.utils"; import { - DecoratorPartialProps, DecoratorImpartialProps, + DecoratorPartialProps, } from "../../src/decorators/types/DecoratorProps.type"; +import ErrorMessage from "../../src/messages/impl/ErrorMessage"; +import { $ } from "../../src/types/namespace/Utility.ns"; +import { extractGroups, extractMessage } from "../../src/utils/decorator.utils"; +import { hash } from "../../src/utils/object.utils"; export type ArrayUniqueType = { hash?: $.HashGenerator; @@ -19,6 +18,19 @@ const DEFAULTS: DecoratorImpartialProps> = { message: ErrorMessage.ArrayUnique(), }; +function isArrayUnique(arr: T[], equals: $.Equals): boolean { + const set = new Set(); + for (const val of arr) { + for (const el of set) { + if (equals(val, el)) { + return false; + } + } + set.add(val); + } + return true; +} + export default function ArrayUnique( props: DecoratorPartialProps> = DEFAULTS ) {