From e6818d5a66cbef78a518d0d45e4d2b93a4439659 Mon Sep 17 00:00:00 2001 From: bousalih-hamza Date: Sat, 28 Sep 2024 21:08:56 +0100 Subject: [PATCH 1/3] - impl primitive validator feature - fix some bugs --- CHANGELOG.md | 16 +++++++++++++ __tests__/index.test.ts | 2 ++ __tests__/primitive-validator.ts | 23 ++++++++++++++++++ src/validators/main/validator-item.ts | 10 +++++++- src/validators/main/validator.ts | 3 +-- .../results/validator-result-objects.ts | 18 ++++++++++---- src/validators/utils/types.ts | 24 +------------------ src/validators/validators-fn/base.ts | 11 +++++++++ 8 files changed, 77 insertions(+), 30 deletions(-) create mode 100644 __tests__/primitive-validator.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index e0cbee3..9923c1c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,22 @@ ## Previous Releases +### 0.6.5 + +- introduce inline validator, to validate primitive values: +````ts +import {v, m} from 'src' + +const emailValidator = v.string().required().email().build(); + +emailValidator.apply("test.com") + +console.log(emailValidator.valid) // false +console.log(emailValidator.message) // Invalid email format +```` + +- fix some bugs + ### 0.6.0 - add validator status to define the status of the validator after being executed [#commet](https://github.com/bsh-generator/bshg_validation_ts/tree/7901e77f88f88bf047af7ff9dc78a62363d39abb) diff --git a/__tests__/index.test.ts b/__tests__/index.test.ts index 08971c9..6071b81 100644 --- a/__tests__/index.test.ts +++ b/__tests__/index.test.ts @@ -1,5 +1,7 @@ import SimpleValidationTests from './simple-validation' import NestedValidationTests from './nested-validation' +import PrimitiveValidator from "./primitive-validator"; describe('Simple Validation Tests', SimpleValidationTests) describe('Nested Validation Tests', NestedValidationTests) +describe('Primitive Validation Tests', PrimitiveValidator) diff --git a/__tests__/primitive-validator.ts b/__tests__/primitive-validator.ts new file mode 100644 index 0000000..2fa7388 --- /dev/null +++ b/__tests__/primitive-validator.ts @@ -0,0 +1,23 @@ +import { m, v } from "@bshg/validation"; + +export default () => { + const pv = v.string().required().email().build(); + + it("should build a validator correctly", () => { + expect(pv).toBeDefined() + }); + + it("should validate", () => { + const actual = pv.apply("bshg@mail.com"); + expect(actual).toBeDefined() + expect(actual.status).toBe(true) + expect(actual.err).toBeUndefined() + }); + + it("should validate", () => { + const actual = pv.apply("bshgmail.com"); + expect(actual).toBeDefined() + expect(actual.status).toBe(false) + expect(actual.err).toBe(m.Messages.en.string.email) + }); +} \ No newline at end of file diff --git a/src/validators/main/validator-item.ts b/src/validators/main/validator-item.ts index e6ec6f2..d9b5138 100644 --- a/src/validators/main/validator-item.ts +++ b/src/validators/main/validator-item.ts @@ -55,7 +55,7 @@ export class ValidatorItem> { } #onChange() { - this.validator.onChangeEvent && this.validator.onChangeEvent(this.container()) + this.validator?.onChangeEvent && this.validator.onChangeEvent(this.container()) } reset() { @@ -74,7 +74,9 @@ export class ValidatorItem> { /** * @deprecated + * replaced with `markAsError` * @param msg + * @see #markAsError */ error(msg: string) { this.markAsError(msg) @@ -86,6 +88,12 @@ export class ValidatorItem> { this.#onChange() } + apply(value: T): { status?: boolean, err?: string } { + this.get = () => value + this.validate() + return {status: this.valid, err: this.message} + } + validate = () => { try { this.#validations?.forEach(it => this.#doValidations(it)) diff --git a/src/validators/main/validator.ts b/src/validators/main/validator.ts index 5f9f6ca..ac2fb80 100644 --- a/src/validators/main/validator.ts +++ b/src/validators/main/validator.ts @@ -1,6 +1,6 @@ import { BshBatchValidationError, - BshValidationError, + BshValidationError, ValidatorComplexResultObjects, ValidatorComplexResultVFieldName, ValidatorResult, ValidatorResultArrays, @@ -12,7 +12,6 @@ import { BatchValidatorResultInfo, ExtractNonPrimitiveKeys, NestedType, - ValidatorComplexResultObjects, ValidatorConfig, ValidatorOptions, ValidatorResultInfo, diff --git a/src/validators/results/validator-result-objects.ts b/src/validators/results/validator-result-objects.ts index 39d0860..c784ce9 100644 --- a/src/validators/results/validator-result-objects.ts +++ b/src/validators/results/validator-result-objects.ts @@ -1,14 +1,14 @@ -import { ValidatorComplexResultObjects } from "../utils"; +import {Primitive} from "../utils"; export type ValidatorResult = any> = ValidatorResultObjects | ValidatorResultArrays -type ValidatorResultTemplate = { +type ValidatorResultBase = { items?: SimpleType nested?: NestedType } export type ValidatorResultObjects> = - ValidatorResultTemplate< + ValidatorResultBase< ValidatorSimpleResult[], ValidatorComplexResultObjects > @@ -20,10 +20,20 @@ export type ValidatorSimpleResult = { message?: string } +export type ValidatorComplexResultObjects> = { + [k in keyof T as T[k] extends Primitive + ? never + : T[k] extends infer U | undefined + ? U extends Primitive + ? never + : k + : k]?: ValidatorResultObjects; +} + ////////////////////// export type ValidatorResultArrays = - ValidatorResultTemplate< + ValidatorResultBase< ValidatorSimpleResult[], ValidatorComplexResultVFieldName[] > diff --git a/src/validators/utils/types.ts b/src/validators/utils/types.ts index 6b59448..66d367d 100644 --- a/src/validators/utils/types.ts +++ b/src/validators/utils/types.ts @@ -1,6 +1,6 @@ import {Validator, ValidatorTemplate} from '../main'; import {TypeValidator} from '../validators-fn'; -import { ValidatorResult, ValidatorResultObjects } from "../results"; +import { ValidatorResult } from "../results"; import {TypeValidatorWithContext} from "../validators-fn/base"; import { Primitive } from "./types-utils"; @@ -43,10 +43,6 @@ export type ItemType> = { [K in keyof T]?: TypeValidator | TypeValidatorWithContext[] } -// export type NestedType> = NonSimpleValues extends { -// [K in keyof NonSimpleValues]: Validator[K]>; -// } ? { [K in NonSimpleKeys]?: Validator[K]> } : never; - export type NestedType, TContext extends Record> = { [k in keyof T as T[k] extends Primitive ? never @@ -57,10 +53,6 @@ export type NestedType, TContext extends Record; } -// export type TemplateNestedType, TContext extends Record> = NonSimpleValues extends { -// [K in keyof NonSimpleValues]: ValidatorTemplate[K], TContext>; -// } ? { [K in NonSimpleKeys]?: ValidatorTemplate[K], TContext> } : never; - export type TemplateNestedType, TContext extends Record> = { [k in keyof T as T[k] extends Primitive ? never @@ -71,20 +63,6 @@ export type TemplateNestedType, TContext extends R : k]?: ValidatorTemplate; } -// export type ValidatorComplexResultObjects = NonSimpleValues extends { -// [K in keyof NonSimpleValues]: ValidatorResultObjects[K]>; -// } ? { [K in NonSimpleKeys]?: ValidatorResultObjects[K]> } : never; - -export type ValidatorComplexResultObjects> = { - [k in keyof T as T[k] extends Primitive - ? never - : T[k] extends infer U | undefined - ? U extends Primitive - ? never - : k - : k]?: ValidatorResultObjects; -} - //// export type ValidatorConfig, TContext extends Record> = { id?: string, diff --git a/src/validators/validators-fn/base.ts b/src/validators/validators-fn/base.ts index 2b70ce8..a85ad28 100644 --- a/src/validators/validators-fn/base.ts +++ b/src/validators/validators-fn/base.ts @@ -8,6 +8,7 @@ import { ValidatorFnDependConfigCtx, ValidatorFnDependConfigCtxAsync, } from "../utils"; +import {ValidatorItem} from "../main"; export const messageVars = { prefix: '%', @@ -126,6 +127,16 @@ export class TypeValidator { } return this; } + + /** + * build validator for single type (string | number | ...) + */ + // TODO make this works with TypeValidatorWithContext + build(): ValidatorItem { + const vi = new ValidatorItem(); + vi.setValidations(this); + return vi; + } } export type TypeValidatorWithContext> = { From 5526fcfddbffe9a6b5fb2a5441f91ac49eccc23e Mon Sep 17 00:00:00 2001 From: bousalih-hamza Date: Sat, 28 Sep 2024 21:10:46 +0100 Subject: [PATCH 2/3] add test-pr pipeline --- .github/workflows/test-pr.yml | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 .github/workflows/test-pr.yml diff --git a/.github/workflows/test-pr.yml b/.github/workflows/test-pr.yml new file mode 100644 index 0000000..16caa2c --- /dev/null +++ b/.github/workflows/test-pr.yml @@ -0,0 +1,35 @@ +name: Release +on: + push: + branches: + - main + - beta + pull-request: + branches: + - main + - beta + +jobs: + test: + runs-on: ubuntu-latest + permissions: + contents: write + pull-requests: read + id-token: write + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set up Node.js + uses: actions/setup-node@v4 + with: + node-version: 20 + + - name: Install dependencies + run: npm install + + - name: Run tests + run: npm test + + - name: Build project + run: npm run build From 6c00122dfe14fbff1aea5c47ec13492ec5231754 Mon Sep 17 00:00:00 2001 From: bousalih-hamza Date: Wed, 30 Oct 2024 23:56:29 +0100 Subject: [PATCH 3/3] - fix some issues. - give the access to all library types. - introduce inline validator, to validate primitive values --- CHANGELOG.md | 65 +- CODE_OF_CONDUCT.md | 7 +- CONTRIBUTING.md | 7 +- README.md | 1306 +---------------- __tests__/index.test.ts | 12 +- __tests__/primitive-validator.ts | 32 +- __tests__/simple-validation.ts | 52 +- configs/tsconfig.base.json | 15 +- configs/tsconfig.cjs.json | 5 +- configs/tsconfig.esm.json | 5 +- jest.config.js | 4 +- playground.ts | 4 +- src/index.ts | 2 +- src/validators/configuration/index.ts | 16 +- src/validators/exceptions/index.ts | 4 +- src/validators/index.ts | 15 +- src/validators/main/Validator-template.ts | 14 +- src/validators/main/index.ts | 6 +- src/validators/main/validator-item.ts | 141 +- src/validators/main/validator.ts | 3 +- src/validators/messages/ar.ts | 28 +- src/validators/messages/en.ts | 28 +- src/validators/messages/fr.ts | 26 +- src/validators/messages/index.ts | 32 +- src/validators/options/index.ts | 12 +- src/validators/results/index.ts | 4 +- src/validators/results/validation-error.ts | 16 +- .../results/validator-result-objects.ts | 14 +- src/validators/utils/index.ts | 6 +- src/validators/utils/regex.ts | 6 +- src/validators/utils/types.ts | 8 +- src/validators/v.ts | 36 +- src/validators/validators-fn/arrays.ts | 26 +- src/validators/validators-fn/base.ts | 55 +- src/validators/validators-fn/booleans.ts | 20 +- src/validators/validators-fn/dates.ts | 40 +- src/validators/validators-fn/datetimes.ts | 32 +- src/validators/validators-fn/enums.ts | 10 +- src/validators/validators-fn/index.ts | 65 +- src/validators/validators-fn/numbers.ts | 52 +- src/validators/validators-fn/objects.ts | 2 +- src/validators/validators-fn/strings.ts | 54 +- src/validators/validators-fn/times.ts | 34 +- tsconfig.json | 4 +- 44 files changed, 562 insertions(+), 1763 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9923c1c..5ff3b4a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,15 +1,20 @@ - # Changelog ## Previous Releases ### 0.6.5 +- fix some issues. +- give the access to all library types. - introduce inline validator, to validate primitive values: + ````ts -import {v, m} from 'src' +import { v, m } from 'src' -const emailValidator = v.string().required().email().build(); +type Ctx = { role: string } // the context +const emailValidator = v.primitive( + v.string().required().email() /* validations */ +) emailValidator.apply("test.com") @@ -21,8 +26,10 @@ console.log(emailValidator.message) // Invalid email format ### 0.6.0 -- add validator status to define the status of the validator after being executed [#commet](https://github.com/bsh-generator/bshg_validation_ts/tree/7901e77f88f88bf047af7ff9dc78a62363d39abb) -- update the loggers [#commet](https://github.com/bsh-generator/bshg_validation_ts/tree/a8476b8b069e5eeab001203c464e13a45401ccd2) +- add validator status to define the status of the validator after being + executed [#commet](https://github.com/bsh-generator/bshg_validation_ts/tree/7901e77f88f88bf047af7ff9dc78a62363d39abb) +- update the + loggers [#commet](https://github.com/bsh-generator/bshg_validation_ts/tree/a8476b8b069e5eeab001203c464e13a45401ccd2) - start using tests in the library - Simplify Access to Validation Status and Messages [#2](https://github.com/bsh-generator/bshg_validation_ts/issues/2) @@ -44,19 +51,19 @@ console.log(emailValidator.message) // Invalid email format - **Improved Documentation**: Clearer and more comprehensive. - **Async Validation**: - - Support for asynchronous validation rules with `onErrorAsync()`. - - Async batch validations for multiple objects. + - Support for asynchronous validation rules with `onErrorAsync()`. + - Async batch validations for multiple objects. - **Context Validation**: - - Alter validation behavior based on context information. - - Dynamic rules based on specific conditions. + - Alter validation behavior based on context information. + - Dynamic rules based on specific conditions. - **Unified Error Messages**: - - Single `message` property for both string and function messages. + - Single `message` property for both string and function messages. - **Bug Fixes**: - - Stability and performance improvements. - - Enhanced date comparison logic. + - Stability and performance improvements. + - Enhanced date comparison logic. ### 0.3.2 @@ -70,24 +77,29 @@ console.log(emailValidator.message) // Invalid email format ### 0.3.0 -- remove `validationResult` from validator options, and replace it with methods for more type safe for the return type of the validation. +- remove `validationResult` from validator options, and replace it with methods for more type safe for the return type + of the validation. - Develop new way to validate: - - `.validate(): boolean`: return true if the validation passes. - - `.validateInfo(): {success, results}`: return object with the validation details if it fails. - - `.validateThrow()`: throw an Error of type `BshValidationError` if validation fails. + - `.validate(): boolean`: return true if the validation passes. + - `.validateInfo(): {success, results}`: return object with the validation details if it fails. + - `.validateThrow()`: throw an Error of type `BshValidationError` if validation fails. - update validate methods to accept object to be validated, as you can still using `.init()` - Introduce `v.template()`: create template for validators to instantiate validators from it. - Introduce `validator.options(ValidatorOptions)`: override the default options. -- Introduce `Batch Validation`: Enable batch validation of multiple objects or fields at once, returning aggregated results. +- Introduce `Batch Validation`: Enable batch validation of multiple objects or fields at once, returning aggregated + results. - Provide multi-language support for validation messages, allowing users to define error messages in various languages. ### 0.2.0 -- Added `.as()` method to the following validators: `v.string()`, `v.number()`, `v.boolean()`, `v.time()`, `v.date()`, `v.datetime()`. This method allows comparison with a property of the parent object. -- Introduced `.onError()` method to enable custom validation based on the value of the field and the parent object. +- Added `.as()` method to the following validators: `v.string()`, `v.number()`, `v.boolean()`, `v.time()`, `v.date()`, + `v.datetime()`. This method allows comparison with a property of the parent object. +- Introduced `.onError()` method to enable custom validation based on the value of the field and the parent + object. - Added `%name` placeholder to dynamically include the field name in error messages. -These updates enhance the functionality and flexibility of the validation library, providing more options for custom validations and error message customization. +These updates enhance the functionality and flexibility of the validation library, providing more options for custom +validations and error message customization. ### 0.1.1 @@ -95,12 +107,14 @@ These updates enhance the functionality and flexibility of the validation librar - add `%val` to use it in messages string to be replaced with actual field value. - rename `.add()` -to add costumes validations- to `.onError()` - fix issue of marking the validator functions type as undefinable by default: - - make validator function use generics to set the type as undefinable `v.string()`. by default is take type `string`, and the same for the other. - - add `.undefined()` to validator functions to mark types as undefinable. + - make validator function use generics to set the type as undefinable `v.string()`. by default + is take type `string`, and the same for the other. + - add `.undefined()` to validator functions to mark types as undefinable. ### 0.1.0 #### Features: + - Upgraded the library to use functions instead of extending classes, enhancing flexibility and ease of use. - Expanded validation methods to cover various types, increasing validation options. - Introduced the `v.costume()` method, enabling users to create validators for custom types. @@ -109,15 +123,18 @@ These updates enhance the functionality and flexibility of the validation librar - Introduced `v.configure()` method for configuring the library according to user preferences. - Made regex and error messages configurable, providing customization options. - Enhanced compatibility with both front-end and back-end projects for seamless integration. -- Introduced `.import(results)` method for importing validation results from backend to frontend, facilitating sharing of results across environments. +- Introduced `.import(results)` method for importing validation results from backend to frontend, facilitating sharing + of results across environments. #### Improvements: + - Improved documentation and logging for better clarity and understanding. - Enhanced error handling and reporting for smoother user experience. - Optimized performance for faster validation processes. - Streamlined code structure for better maintainability and readability. -These updates aim to provide users with a more versatile and customizable validation library, ensuring smoother integration and enhanced validation capabilities across various project environments. +These updates aim to provide users with a more versatile and customizable validation library, ensuring smoother +integration and enhanced validation capabilities across various project environments. ### 0.0.7 diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index 605eaac..acf0276 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -2,7 +2,9 @@ ## Our Pledge -We as members, contributors, and maintainers pledge to make participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion. +We as members, contributors, and maintainers pledge to make participation in our project and our community a +harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and +expression, level of experience, nationality, personal appearance, race, religion. ## Our Standards @@ -114,6 +116,9 @@ For answers to common questions about this code of conduct, see the FAQ at [https://www.contributor-covenant.org/translations][translations]. [homepage]: https://www.contributor-covenant.org + [v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html + [faq]: https://www.contributor-covenant.org/faq + [translations]: https://www.contributor-covenant.org/translations diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 545d564..61fb733 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -6,7 +6,9 @@ your contribution. ## Initial steps -Before you start working on a contribution, create an issue describing what you want to build. It's possible someone else is already working on something similar, or perhaps there is a reason that feature isn't implemented. The maintainers will point you in the right direction. +Before you start working on a contribution, create an issue describing what you want to build. It's possible someone +else is already working on something similar, or perhaps there is a reason that feature isn't implemented. The +maintainers will point you in the right direction. - -## Table of Contents +visit our docs site: [Bshg Docs](https://docs.bshgen.com/ts-validation) -- [@bshg/validation](#bshgvalidation) - - [Introduction](#introduction) - - [Why Choose `@bshg/validation`?](#why-choose-bshgvalidation) - - [Getting Started](#getting-started) - - [Installation](#installation) - - [Basic Usage](#basic-usage) - - [`v.validator({ ... })`](#vvalidatortype-tcontext--) - - [Function Signature](#function-signature) - - [Config Param: `ValidatorConfig`](#config-param-validatorconfig) - - [Example](#example) - - [Validator Methods](#validator-methods) - - [String](#string) - - [Number](#number) - - [DateTime](#datetime) - - [Date](#date) - - [Time](#time) - - [Boolean](#boolean) - - [Arrays](#arrays) - - [Custom Validation Rule](#custom-validation-rule) - - [Custom Validator Method](#custom-validator-method) - - [Define Rules](#define-rules) - - [Simple Fields](#simple-fields) - - [Defining Validation Rules for Simple Fields](#defining-validation-rules-for-simple-fields) - - [Example](#example-1) - - [Nested Fields](#nested-fields) - - [1. Using the `nested` Property](#1-using-the-nested-property) - - [2. Using the `items` Property](#2-using-the-items-property) - - [Validator API](#validator-api) - - [Properties](#properties) - - [Methods](#methods) - - [ValidatorItem API](#validatoritem-api) - - [Validator Options](#validator-options) - - [Validator Template](#validator-template) - - [`v.template(config)`](#vtemplateconfig) - - [How To Validate Objects?](#how-to-validate-objects) - - [1. `validate()`: Simple Boolean Check](#1-validate-simple-boolean-check) - - [2. `validateInfo()`: Detailed Validation Results](#2-validateinfo-detailed-validation-results) - - [3. `validateThrow()`: Throwing Errors on Validation Failure](#3-validatethrow-throwing-errors-on-validation-failure) - - [Choosing Between `.init()` and `.validate(object)`](#choosing-between-init-and-validateobject) - - [How To Use Real-Time Validation?](#how-to-use-real-time-validation) - - [Steps to Implement Real-Time Validation](#steps-to-implement-real-time-validation) - - [Example Usage](#example-usage) - - [Batch Validation: validate multi objects](#batch-validation-validate-multi-objects) - - [Async Validation](#async-validation) - - [Example of Async Validation](#example-of-async-validation) - - [Context Validation](#context-validation) - - [Context Type](#context-type) - - [Context Validation Rules](#context-validation-rules) - - [Method 1: Static Context Values](#method-1-static-context-values) - - [Method 2: Dynamic Context Evaluation](#method-2-dynamic-context-evaluation) - - [Method 3: Context-Aware Validation](#method-3-context-aware-validation) - - [Error Messages Customization](#error-messages-customization) - - [Static Messages](#static-messages) - - [Placeholder Messages](#placeholder-messages) - - [1. `%n`](#1-n) - - [2. `%val`](#2-val) - - [3. `%name`](#3-name) - - [Dynamic Messages](#dynamic-messages) - - [Combining Placeholder and Dynamic Messages](#combining-placeholder-and-dynamic-messages) - - [`import()` API](#import-api) - - [Multi-Language Support for Validation Messages](#multi-language-support-for-validation-messages) - - [Configuration](#configuration) - - [Setting the Default Locale](#setting-the-default-locale) - - [Changing the Locale at Runtime](#changing-the-locale-at-runtime) - - [Example Usage](#example-usage-1) - - [Supported Locales](#supported-locales) - - [Overriding Default Values](#overriding-default-values) - - [Overriding Options Globally](#overriding-options-globally) - - [Overriding Options For A Specific Validator](#overriding-options-for-a-specific-validator) - - [Overriding Regex Values](#overriding-regex-values) - - [Using `v.configure()` Method:](#using-vconfigure-method) - - [Directly in `v.regex` Container:](#directly-in-vregex-container) - - [Default Regex Patterns:](#default-regex-patterns) - - [Overriding Localization](#overriding-localization) - - [What is New?](#what-is-new) +Welcome to `@bshg/validation`, a versatile TypeScript library crafted for seamless data validation within your projects. +Whether you're working on a front-end or back-end application, this library empowers you to validate data in a +declarative manner, ensuring your objects align with your expectations. - +Designed with simplicity and efficiency in mind, `@bshg/validation` streamlines the validation process, making it a +reliable choice for your projects. It offers extensive customization options, enabling you to tailor validation rules +and error messages to fit your specific requirements with ease. -## Introduction - -Welcome to `@bshg/validation`, a versatile TypeScript library crafted for seamless data validation within your projects. Whether you're working on a front-end or back-end application, this library empowers you to validate data in a declarative manner, ensuring your objects align with your expectations. - -Designed with simplicity and efficiency in mind, `@bshg/validation` streamlines the validation process, making it a reliable choice for your projects. It offers extensive customization options, enabling you to tailor validation rules and error messages to fit your specific requirements with ease. - -This library is lightweight and has no external dependencies, ensuring fast load times and minimal impact on your application's performance. Whether you're building a web application, API, or mobile app, you can rely on `@bshg/validation` to handle validation consistently across platforms. - -In this guide, you'll explore the features and functionalities of `@bshg/validation`, learning how to leverage its capabilities to fortify your projects with robust data validation. +This library is lightweight and has no external dependencies, ensuring fast load times and minimal impact on your +application's performance. Whether you're building a web application, API, or mobile app, you can rely on +`@bshg/validation` to handle validation consistently across platforms. ## Why Choose `@bshg/validation`? -- **Simplicity and Efficiency**: `@bshg/validation` is designed to be straightforward and efficient, making implementation easy while maintaining high performance. -- **Customization**: The library offers extensive customization options for validation rules and error messages, providing flexibility and control tailored to your project's needs. -- **Lightweight**: With no external dependencies, `@bshg/validation` ensures fast load times and minimal impact on performance. -- **Cross-Platform Compatibility**: Suitable for both front-end and back-end applications, it ensures consistent validation across different platforms. -- **Full Stack Library**: Use `@bshg/validation` in both frontend and backend projects, and seamlessly share validation logic between them. This makes displaying server-side validation results on the client-side straightforward and requires no extra code. -- **Autocompletion**: Enhance your development experience with autocompletion support in popular IDEs like VSCode, improving coding efficiency and reducing errors. +- **Simplicity and Efficiency**: `@bshg/validation` is designed to be straightforward and efficient, making + implementation easy while maintaining high performance. +- **Customization**: The library offers extensive customization options for validation rules and error messages, + providing flexibility and control tailored to your project's needs. +- **Lightweight**: With no external dependencies, `@bshg/validation` ensures fast load times and minimal impact on + performance. +- **Cross-Platform Compatibility**: Suitable for both front-end and back-end applications, it ensures consistent + validation across different platforms. +- **Full Stack Library**: Use `@bshg/validation` in both frontend and backend projects, and seamlessly share validation + logic between them. This makes displaying server-side validation results on the client-side straightforward and + requires no extra code. +- **Autocompletion**: Enhance your development experience with autocompletion support in popular IDEs like VSCode, + improving coding efficiency and reducing errors. ## Getting Started @@ -111,6 +40,9 @@ Install `@bshg/validation` via npm: ```bash npm install @bshg/validation +``` + +```bash yarn add @bshg/validation ``` @@ -153,1189 +85,3 @@ yarn add @bshg/validation } }).init(() => item); ``` - -## `v.validator({ ... })` - -The `v.validator()` function is the core method that allows you to create validators for your data types. As seen in the previous [Basic Usage](#basic-usage) example with the `User` type, this function requires the data type and accepts a configuration object as a parameter. - -This method returns a [`Validator`](#validator-api) instance that can be used to validate your data. - -### Function Signature - -```typescript -function validator(config: ValidatorConfig): Validator { -} -``` - -### Config Param: `ValidatorConfig` - -The configuration object for `v.validator()` has the following structure: - -```typescript -type ValidatorConfig = { - id?: string, - items?: ItemType, - nested?: NestedType, - options?: ValidatorOptions -} -``` - -| Property | Type | Description | -|-----------|--------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| `id` | `string` | An optional identifier for the validator. This can be useful if you need to distinguish between multiple validators in your application. It is used to differentiate between the logs of the validators. | -| `items` | `ItemType` | Defines the validation rules for the individual fields of your data type. This is where you specify the constraints and requirements for each property of your data type. [(read more)](#validator-methods) | -| `nested` | `NestedType` | Allows you to define nested validation rules if your data type contains nested objects that also need validation. | -| `options` | `ValidatorOptions` | Additional options to configure the behavior of the validator. [(read more)](#validator-options) | - -### Example - -1. Data Types: - - ```typescript - type Profile = { - fullname: string; - age: number; - } - - type User = { - email: string; - password: string; - profile: Profile; - } - ``` - -2. Define The Validator: - - ```typescript - import { v } from '@bshg/validation'; - - const profileValidator = v.validator({ - id: 'profileValidator', - items: { - fullname: v.string().required(), - age: v.number().required().positive(), - }, - }); - - const userValidator = v.validator({ - id: 'userValidator', - items: { - email: v.string().required().email(), - password: v.string().required().min(8), - }, - nested: { - profile: profileValidator, - } - }); - ``` - -In this example: - -- `profileValidator` is used within `userValidator` to validate nested objects. -- The `id` property is specified to distinguish between different validators and manage their logs effectively. -- The `items` property defines validation rules for individual fields. -- The `nested` property allows for the inclusion of validators for nested objects. -- The `options` property can be used for additional configurations to fine-tune the validator's behavior. - -> **Note:** `TContext` is used to pass a type of the [context](#context-validation). - -## Validator Methods - -### String - -```typescript -v.string() - .undefined() // Allows `undefined` - .required() // Requires a value - .min(5) // Minimum length is 5 - .max(10) // Maximum length is 10 - .includes("sub") // Must include 'sub' - .includesAll(["sub1", "sub2"]) // Must include 'sub1' and 'sub2' - .startsWith("prefix") // Must start with 'prefix' - .endsWith("suffix") // Must end with 'suffix' - .matches(/regexp/) // Must match the regular expression - .email() // Must be a valid email - .phone() // Must be a valid phone number - .url() // Must be a valid URL - .date() // Must be a valid date (yyyy-mm-dd) - .time() // Must be a valid time (hh:mm:ss) - .hexColor() // Must be a valid hex color - .creditCard() // Must be a valid credit card number - .htmlTag() // Must be a valid HTML tag - .base64() // Must be a valid base64 string - .alphanumeric() // Must contain only numbers and letters - .numeric() // Must contain only numbers - .alpha() // Must contain only letters - .as('key') // Ensures the value is equal to the value of the specified 'key' property in the parent object. - // The 'key' must be a valid key of Type. -``` - -### Number - -```typescript -v.number() - .undefined() // Allows `undefined` - .required() // Requires a value - .min(5) // Value must be greater than or equal to 5 - .max(10) // Value must be less than or equal to 10 - .range(5, 10) // Value must be between 5 and 10 - .integer() // Value must be an integer - .positive() // Value must be positive - .negative() // Value must be negative - .decimal() // Value must be a decimal number - .multipleOf(3) // Value must be a multiple of 3 - .betweenExclusive(5, 10) // Value must be between 5 (exclusive) and 10 (exclusive) - .even() // Value must be an even number - .odd() // Value must be an odd number - .positiveInteger() // Value must be a positive integer - .negativeInteger() // Value must be a negative integer - .positiveDecimal() // Value must be a positive decimal number - .negativeDecimal() // Value must be a negative decimal number - .divisibleBy(3) // Value must be divisible by 3 - .perfectSquare() // Value must be a perfect square - .primeNumber() // Value must be a prime number - .fibonacciNumber() // Value must be a Fibonacci number - .powerOfTwo() // Value must be a power of two - .as('key') // Same as for strings -``` - -### DateTime - -```typescript -v.datetime() - .undefined() // Allows `undefined` - .required() // Requires a value - .after(new Date()) // DateTime must be after the specified date - .before(new Date()) // DateTime must be before the specified date - .between(new Date(), new Date()) // DateTime must be between the specified start and end dates - .todayOrAfter() // DateTime must be today or after today - .todayOrBefore() // DateTime must be today or before today - .past() // DateTime must be in the past - .future() // DateTime must be in the future - .weekday() // DateTime must be a weekday (Monday to Friday) - .weekend() // DateTime must be a weekend (Saturday or Sunday) - .as('key') // Same as for strings -``` - -### Date - -```typescript -v.date() - .undefined() // Allows `undefined` - .required() // Requires a value - .after(new Date()) // Date must be after the specified date - .before(new Date()) // Date must be before the specified date - .between(new Date(), new Date()) // Date must be between the specified start and end dates - .todayOrAfter() // Date must be today or after today - .todayOrBefore() // Date must be today or before today - .past() // Date must be in the past - .future() // Date must be in the future - .weekday() // Date must be a weekday (Monday to Friday) - .weekend() // Date must be a weekend (Saturday or Sunday) - .leapYear() // Date must be in a leap year - .sameDayAs(new Date()) // Date must be the same day as the specified date - .as('key') // Same as for strings -``` - -### Time - -```typescript -v.time() - .undefined() // Allows `undefined` - .required() // Requires a value - .after(new Date()) // Time must be after the specified time - .before(new Date()) // Time must be before the specified time - .between(new Date(), new Date()) // Time must be between the specified start and end times - .nowOrAfter() // Time must be now or after now - .nowOrBefore() // Time must be now or before now - .past() // Time must be in the past - .future() // Time must be in the future - .within24Hours() // Time must be within the next 24 hours - .as('key') // Same as for strings -``` - -### Boolean - -```typescript -v.boolean() - .undefined() // Allows `undefined` - .required() // Requires a value - .true() // Value must be `true` - .false() // Value must be `false` - .equals(true) // Value must be equal to `true` - .equals(false) // Value must be equal to `false` - .as('key') // Same as for strings -``` - -### Arrays - -```typescript -v.array() - .required() // Requires a value - .length(5) // Array must have a length of 5 - .min(5) // Minimum length required is 5 - .max(10) // Maximum length allowed is 10 - .has("value") // Array must include "value" - .hasAll(["value1", "value2"]) // Array must include all of: value1, value2 - .hasAny(["value1", "value2"]) // Array must include any of: value1, value2 - .hasNone(["value1", "value2"]) // Array must include none of: value1, value2 - .some(predicate) // Array matches the given predicate - .every(predicate) // Every element in the array matches the given predicate -``` - -### Custom Validation Rule - -`.onError()` allows for custom error handling tailored to specific validation scenarios. This method accepts an object of type `ValidatorFnConfig`, which provides a structured way to define validation functions and associated error messages. - -- **`error`**: This field specifies the validation function. It accepts parameters: - - `value`: The current value of the field being validated. - - `container` (optional): The object containing the field being validated. - - The function returns `true` if validation fails (i.e., an error condition is detected), and `false` otherwise. - -- **`message`**: Optionally, you can specify an error message associated with the validation function. This can be a string or a function returning a string, allowing for dynamic error messages based on validation outcomes. - -### Custom Validator Method - -For types not covered by predefined validators, `v.custom()` allows you to create custom validators with tailored validation logic. - -```typescript -v.custom() - .onError({ - error: (value): boolean => false, // Custom validation function returning `false` if validation fails - message: "Custom error message" // Optional error message associated with the validation function - }) - .onError({...}) // You can define multiple custom error handlers as needed -``` - -Using `v.custom()`, you can implement specialized validation rules specific to your application's requirements, ensuring robust validation across various data types and scenarios. - -## Define Rules - -### Simple Fields - -You can define validation rules for simple fields using the `items` property of the [ValidatorConfig](#config-param-validatorconfig). This property accepts an object where you specify the fields to validate. The object should include only the fields of the type passed to [`v.validator`](#vvalidatortype-tcontext--). Each field is of type `ItemType`. - -```typescript -type ItemType = { - [K in keyof T]?: TypeValidator | TypeValidatorWithContext[]; -} -``` - -> **Note:** `TypeValidatorWithContext` is used to define validation rules that depend on contextual information. For example, validations based on the [context](#context-validation) of the application or specific data dependencies. - -#### Defining Validation Rules for Simple Fields - -Here's how you can define validation rules for individual fields: - -```typescript -{ - fieldName: v.validatorMethod.rule1().rule2().onError(...) -} -``` - -In this structure: - -- `validatorMethod` refers to predefined methods provided by the library (`v`) to create `TypeValidator` objects containing validation rules. -- `rule1`, `rule2`, etc., are methods or functions chained together to specify validation criteria such as required fields, string length, format, etc. [(read more)](#validator-methods) - -This approach allows you to configure detailed validation requirements for each field in your data type, ensuring data integrity and consistency in your application. - -#### Example - -```typescript -v.validator({ - id: 'validator id', - items: { - username: v.string().required(), - age: v.number().positive(), - password: v.string().onError({ - error: (value) => { - // Custom validation logic to ensure password complexity - return true; - }, - message: 'Password must be complex' - }) - } -}) -``` - -### Nested Fields - -To define rules for nested objects in your data, there are two approaches: - -#### 1. Using the `nested` Property - -One way to validate nested objects is to create their own validators and then pass them in the `nested` property of the [ValidatorConfig](#config-param-validatorconfig). - -```typescript -const childValidator = v.validator({ - items: { - name: v.string().required(), - age: v.number().positive() - } -}); - -v.validator({ - nested: { - child: childValidator - } -}); -``` - -In this example: - -- `childValidator` is created to validate the `ChildType`, specifying rules for fields like `name` and `age`. -- The `v.validator` creates a validator for `ParentType`, where the `nested` property includes `child: childValidator`. -- This setup ensures that when validating a `ParentType` object, the `child` property will be validated according to the rules defined in `childValidator`. - -Using this approach allows for modular and reusable validation logic, especially useful when dealing with complex data structures that include nested objects. It promotes code organization and maintains clear separation of validation rules for different parts of your data model. - -#### 2. Using the `items` Property - -Another approach to validate nested objects is by using `v.custom()` within the `items` property of the [ValidatorConfig](#config-param-validatorconfig). This method allows you to validate nested objects without needing to create separate validators for them. - -```typescript -v.validator({ - items: { - child: v.custom().onError({ - error: (value) => { - // Custom validation logic for the nested object 'child' - // Example: Checking if 'child' object meets specific criteria - return !value.name || value.age < 0; - }, - message: 'Error: Invalid child object' - }) - } -}); -``` - -In this example: - -- `v.validator` creates a validator for `ParentType`. -- The `items` property defines validation rules for fields directly within `ParentType`. -- `child: v.custom()` specifies that the `child` property should be validated using a custom validator for `ChildType`. -- `.onError({ ... })` allows customization of error handling for the nested object validation. - - The `error` function defines custom logic to validate the `child` object. Here, it checks if `child.name` exists and `child.age` is not negative. - - The `message` provides an error message when validation fails for the nested object. - -This approach is useful when you prefer to define validation rules inline within the main validator configuration, especially for nested objects that do not require extensive validation or are context-specific. It simplifies the structure by consolidating all validation logic within a single validator definition. - -## Validator API - -The `v.validator()` method returns an instance of `Validator`, the primary class of this library designed for comprehensive data validation. This class provides a robust set of methods and options to effectively manage and validate your data structures. - -### Properties - -| Property | Description | -|------------|-------------------------------------------------------------------------------------------------------| -| **items** | Retrieves the validation items to inspect their status, results, or to control them programmatically. | -| **nested** | Accesses nested validations to manage their status, results, or to control them as needed. | - -### Methods - -| Method | Description | -|----------------------------------------|-----------------------------------------------------------------------------------------------------------------------| -| **options(options: ValidatorOptions)** | Updates the validator's configuration options after instantiation. [See options](#validator-options) | -| **allGood()** | Checks if all validations pass. Returns `true` if all validations are successful, otherwise `false`. | -| **applyAll()** | Executes all defined validations on the items specified within the validator configuration. | -| **applyAllAsync()** | Asynchronously applies all validations on the items specified within the validator. | -| **reset()** | Resets the state of validations, clearing all previous results and errors. | -| **init(getter: () => T)** | Initializes the validator with a `getter` function to retrieve the latest state of the data to be validated. | -| **withContext(context: TContext)** | Provides a context object to the validator, enabling contextual validations. | -| **validate(data?: T)** | Synchronously validates the provided object or uses the current `getter` value if no argument is provided. | -| **validateInfo(data?: T)** | Similar to `validate(data?)`, but returns an object containing the validation status and detailed results. | -| **validateThrow(data?: T)** | Similar to `validate(data?)`, but throws an error if any validation fails, providing comprehensive error information. | -| **import(errors: ValidatorResult)** | Imports a list of errors into the validator to manage or display validation failures effectively. | - -The `Validator` class offers a versatile and powerful solution for validating complex data structures. By leveraging its methods and properties, developers can ensure data integrity, manage validation outcomes effectively, and handle validation errors with precision. Whether validating single objects or batches, the `Validator` class provides the flexibility and reliability required for robust data validation in various application scenarios. - -## ValidatorItem API - -The `ValidatorItem` class is designed to encapsulate the validation state and behavior for individual properties within data structures. It integrates seamlessly with validation methods such as `v.string()`, `v.number()`, `v.boolean()`, `v.array()`, and `v.custom()`, providing comprehensive management and access to validation results. - -| Property/Method | Description | -|------------------------------|-------------------------------------------------------------------------------------------------------------------| -| **`valid`** | Returns `true` if the value is valid, `false` if invalid, and `undefined` if not yet validated. | -| **`name`** | The name of the field or property associated with this `ValidatorItem`. | -| **`message`** | The error message associated with validation failures. | -| **`get(): T`** | Retrieves the current value of the property being validated. | -| **`set(value: T)`** | Updates the value of the property being validated. | -| **`error(message: string)`** | Marks the validation state of the item as `false` and sets the error message. | -| **`reset()`** | Resets the validation state of the item to `undefined`, allowing for re-evaluation during subsequent validations. | - -The `ValidatorItem` class provides a structured approach to managing validation states and results for individual properties within your data structures. By using these properties and methods, you can effectively handle validation outcomes, track field-specific errors, and ensure data integrity throughout your application. Integrate `ValidatorItem` seamlessly with the validation methods offered by this library to enhance the reliability and accuracy of your data validation processes. - -## Validator Options - -The validator in this library offers customizable behavior through the 'options' object that can be passed during initialization in the `options` property config in [`v.validator()`](#vvalidatortype-tcontext--) - --`dev?: boolean` - -- If set to `true`, enables debug mode for the validator. When enabled, debug messages are logged to the console to aid in the debugging process. -- **Default Value:** `false` - -- `resultsType?: "array" | "object"` - - Specify the type of structure used to store nested validation results. - - `"array"`: Uses arrays to store nested validation results. - - `"object"`: Uses objects to store nested validation results. - - **Default Value:** `"object"` - -The `ValidatorOptions` object allows you to tailor the behavior of the validator to suit your application's needs. - -- Setting `dev` to `true` provides enhanced debugging capabilities by logging debug messages to the console. -- The `resultsType` option lets you choose between using arrays or objects to organize nested validation outcomes. - providing flexibility based on your application requirements. - Adjust these options to effectively manage and interpret validation results within your application. - -## Validator Template - -The `ValidatorTemplate` class provides a convenient way to create reusable templates for validators in this library. This allows you to define validation configurations once and instantiate validators based on those configurations multiple times. - -| Method | Description | -|-----------------------------------------|----------------------------------------------------------------------------------------------------------| -| **`instant(): Validator`** | Creates and returns a new instance of `Validator` based on the template configuration. | -| **`batchValidate(...data: T[])`** | Validates multiple objects simultaneously using the template configuration. | -| **`batchValidateThrow(...data: T[])`** | Validates multiple objects using the template configuration and throws an error if any validation fails. | - -### `v.template(config)` - -The `template` function creates and returns an instance of `ValidatorTemplate`, which encapsulates a validator template configuration. Use this function to define reusable validator templates that can be instantiated with specific data objects for validation. - -- `config`: A configuration object (`ValidatorTemplateConfig`) defining the settings and structure of the validator template. - -> **Usage**: The `ValidatorTemplate` class and the `template` function simplify the process of creating and using validator templates. Define a template configuration using `template` and its associated methods to instantiate validators, validate multiple objects in batches, or handle validation errors effectively within your application. - -## How To Validate Objects? - -When validating objects, ensuring they conform to the expected schema is essential. Here, we present three methods for handling validation results, each offering a different approach to error handling and result management. - -### 1. `validate()`: Simple Boolean Check - -The `validate()` method returns a boolean value indicating whether the validation passed or failed. This method is straightforward and suitable when only the validation outcome is needed, without detailed information about the validation results. - -```typescript -const result = userValidator.validate(); - -if (result) { - console.log('Validation passed!'); -} else { - console.log('Validation failed.'); -} -``` - -### 2. `validateInfo()`: Detailed Validation Results - -The `validateInfo()` method returns an object with `success` and `results` properties. These results are of type `ValidatorResult`, providing detailed information about why the validation failed, enabling precise error handling. - -```typescript -const validationResult = userValidator.validateInfo(); - -if (validationResult.success) { - console.log('Validation passed!'); -} else { - console.log('Validation failed.'); - console.log('Validation errors:', validationResult.results); -} -``` - -### 3. `validateThrow()`: Throwing Errors on Validation Failure - -The `validateThrow()` method throws a `BshValidationError` error if the validation fails. This method is useful for handling validation errors using exception handling mechanisms. - -```typescript -try { - userValidator.validateThrow(); - console.log('Validation passed!'); -} catch (e) { - const validationError = e as BshValidationError; - console.log('Validation failed.'); - console.log('Validation errors:', validationError.results); -} -``` - -### Choosing Between `.init()` and `.validate(object)` - -You can choose between `.init()` and `.validate(object)` based on your validation needs: - -- **`.init()`:** Recommended for real-time validation scenarios, such as when object fields change (e.g., in HTML forms). Requires a function to retrieve the current object state. - -- **`.validate(object)`:** Useful in backend applications where the entire object is available for validation before processing. - -By leveraging these methods (`validate()`, `validateInfo()`, and `validateThrow()`), you can implement a robust and adaptable validation strategy that meets your application's validation requirements effectively. - -## Access The Validation status - -### `validateItem(fieldName: string): void` -Triggers validation for the specified field. - -**Usage:** -```javascript -validator.validateItem('email'); -``` - -### `itemMessage(fieldName: string): string | undefined` -Retrieves the validation message for the specified field. - -**Usage:** -```javascript -const emailMessage = validator.itemMessage('email'); -``` - -### `isItemValid(fieldName: string): boolean | undefined` -Checks if the specified field is valid. - -**Usage:** -```javascript -const isEmailValid = validator.isItemValid('email'); -``` - -These methods provide a simpler and more intuitive way to access validation results. They replace the need for deep property access, making your code cleaner and easier to maintain. The existing methods remain available for backward compatibility. - -## How To Use Real-Time Validation? - -Real-time validation is crucial for validating objects as they change dynamically, such as in user interfaces. This section outlines how to achieve real-time validation using the `init()` method to track object changes and validate individual properties using the Validator library. - -### Steps to Implement Real-Time Validation - -1. **Define Data Types:** - - Define TypeScript types for the objects you want to validate. For example: - - ```typescript - type Profile = { - fullname: string; - age: number; - }; - - type User = { - email: string; - password: string; - profile: Profile; - }; - ``` - -2. **Declare Validators:** - - Create validators for each property and nested object using the Validator library: - - ```typescript - const profileValidator = v.validator({ - id: 'profileValidator', - items: { - fullname: v.string().required(), - age: v.number().required().positive(), - }, - }); - - const userValidator = v.validator({ - id: 'userValidator', - items: { - email: v.string().required().email(), - password: v.string().required().min(8), - }, - nested: { - profile: profileValidator, - }, - }); - ``` - -3. **Initialize Object State:** - - Use the `init()` method to initialize the validator with the current object state. This is essential for tracking changes and validating in real-time, especially useful in scenarios like form validations: - - ```typescript - const user = new User(); - - userValidator.init(() => user); // Initialize with a function to retrieve the current object state - ``` - -4. **Validate Single Property:** - -You can validate a single property using the validator's: - -- `items..validate()` method -- `nested..items..validate()` method. -- `.validateItem('property-name')` - -This allows you to validate specific fields as they are updated in the UI: - - ```typescript - // Example to validate the 'email' property -const emailValidatorItem = userValidator.items.email; - -emailValidatorItem.validate(); - -// Get validation status and error message -const isValid = emailValidatorItem.valid; -const errorMessage = emailValidatorItem.message; - -// Update validation state if needed -if (!isValid) { - emailValidatorItem.error('Email is not valid!'); -} - ``` - -### Example Usage - -Here's a complete example demonstrating real-time validation with the Validator library: - -```typescript -// Define Data Types -type Profile = { - fullname: string; - age: number; -}; - -type User = { - email: string; - password: string; - profile: Profile; -}; - -// Declare Validators -const profileValidator = v.validator({ - id: 'profileValidator', - items: { - fullname: v.string().required(), - age: v.number().required().positive(), - }, -}); - -const userValidator = v.validator({ - id: 'userValidator', - items: { - email: v.string().required().email(), - password: v.string().required().min(8), - }, - nested: { - profile: profileValidator, - }, -}); - -// Initialize Object State -const user = new User(); - -userValidator.init(() => user); // Initialize with a function to retrieve the current object state - -// Validate a Single Property -const emailValidatorItem = userValidator.items.email; - -// Simulate change and validation -user.email = 'invalid-email'; // Assume user input - -emailValidatorItem.validate(); - -// Get validation status and error message -const isValid = emailValidatorItem.valid; -const errorMessage = emailValidatorItem.message; - -// Get validation status of proprerty of nested object -const isAgeValid = userValidator.nested.profile.items.age.valid; -``` - -By following these steps, you can implement robust real-time validation for your application using the Validator library, ensuring data integrity and user experience consistency. Adjust validations and error handling according to your specific application requirements for seamless integration and functionality. - -## Batch Validation: validate multi objects - -to validate multiple objects, the library provides `batchValidate()` and `batchValidatethrow()` methods of [`Validator`](#validator-api), this method accept list of objects, of the same type, to be validated. - -```typescript -validator.batchValidateThrow(object1, object2, object3); -``` - -## Async Validation - -The Validator library supports asynchronous validation rules through the `onErrorAsync()` method, enabling seamless handling of asynchronous validation checks within your validation workflows. - -### Example of Async Validation - -Define async validation rules using the `onErrorAsync()` method: - -```typescript -v.validator({ - id: 'userValidator', - items: { - email: v.string().required().email().onErrorAsync({ - error: async value => { - const isEmailInUse = await checkEmailInUse(value); - return isEmailInUse; - }, - message: 'The email is already in use!' - }), - } -}); -``` - -To execute async validation rules, use the following methods: - -- `validateAsync(data?)` -- `validateInfoAsync(data?)` -- `validateThrowAsync(data?)` - -By using async validation rules and these methods (`validateAsync`, `validateInfoAsync`, and `validateThrowAsync`), you can efficiently handle asynchronous validation scenarios in your application, ensuring robust data validation and error handling. Adjust the async validation logic according to your specific application requirements for optimal performance and functionality. - -> **Note:** using non async validation methods as `validate()` will ignore the async validation! - -## Context Validation - -Context validation involves altering the validation behavior based on additional information known as `context`. This contextual information influences how validation rules are applied or interpreted, allowing developers to tailor validation logic to specific scenarios or conditions. - -### Context Type - -The `v.validator()` function accepts two types: `Type` and `TContext`. The `TContext` type represents the context that will be passed to the validation rules. By default, `TContext` is of type `any`, as it is not required. - -### Context Validation Rules - -Using context validation rules allows developers to apply different validation logic based on the context. Below are three methods to implement context validation rules. - -### Method 1: Static Context Values - -In this method, specific validation rules are applied based on predefined context values. - -```typescript -type SomeType = { - startDate: Date, -} - -type Context = { - role: "admin" | "user" -} - -v.validator({ - id: "user validator", - items: { - startDate: [ - {ctx: {role: "admin"}, validations: v.date()}, - {ctx: {role: "user"}, validations: v.date().future()} - ], - } -}) -``` - -### Method 2: Dynamic Context Evaluation - -In this method, validation rules are applied based on a dynamic evaluation of the context. - -```typescript -v.validator({ - id: "user validator", - items: { - startDate: [ - {ctx: context => context.role == 'admin', validations: v.date()}, - {ctx: context => context.role == 'user', validations: v.date().future()} - ], - } -}) -``` - -### Method 3: Context-Aware Validation - -In this method, validation rules use the context within the validation logic itself, allowing for more complex and dynamic validation scenarios. - -```typescript -v.validator({ - id: "user validator", - items: { - startDate: v.date().onErrorCtx({ - error: (value, context) => { - if (context.role == 'admin') { - // some validation if the role is admin - return true; - } - return false; - }, - message: 'Start date validation failed based on role context.' - }) - } -}) -``` - -These methods provide flexibility in defining validation logic based on various contextual factors, enhancing the adaptability and precision of the validation process. - -## Error Messages Customization - -The library provides a flexible way to customize the error messages of the validation results. You can set your own error messages in three main ways: [Static Message](#static-messages), [Variants of Static Message](#placeholder-messages), -and [Dynamic Message](#dynamic-messages). - -### Static Messages - -Static messages are straightforward and do not change based on the input value or any external variables. You can provide static messages by using the optional argument of the validation methods, passing the message in the `message: string` property. - -```TypeScript -v.string().required({message: "your costume message."}) -v.number().min(10, {message: "your costume message."}) -``` - -### Placeholder Messages - -The library allows you to customize error messages dynamically using placeholders. Here are the placeholders you can use: - -1. `%n`: Replaced by the `n` argument of the method. -2. `%val`: Replaced with the actual value of the validated field. -3. `%name`: Replaced with the name of the validated field. - -#### 1. `%n` - -The `%n` placeholder makes the error message more informative by incorporating method-specific parameters. - -```typescript -v.number().min(10, {message: "Minimum value is %1."}) // Minimum value is 10. -v.number().range(10, 20, {message: "Value must be between %1 and %2."}) // Value must be between 10 and 20. -``` - -#### 2. `%val` - -The `%val` placeholder provides context to the user by showing the invalid value within the error message. - -```typescript -const validator = v.validator<{ username: string }>({ - items: { - username: v.string() - .min(10, {message: `'%val' must contain at least %1 characters!`}) - }, -}).init(() => { - return { - username: "bshg" - } -}) - -validator.validate() -console.log(validator.items.username?.message) // 'bshg' must contain at least 10 characters! -``` - -#### 3. `%name` - -The `%name` placeholder includes the field name in the error message, providing clarity and specificity. - -```typescript -const validator = v.validator<{ username: string }>({ - items: { - username: v.string() - .min(10, {message: `'%name' must contain at least %1 characters!`}) - }, -}).init(() => { - return { - username: "bshg" - } -}) - -validator.validate() -console.log(validator.items.username?.message) // 'username' must contain at least 10 characters! -``` - -Using these placeholders, you can create error messages that are both informative and contextually relevant, enhancing the user experience of your application. - -### Dynamic Messages - -Dynamic messages allow you to use functions to generate error messages based on external variables or complex logic. This approach is highly flexible and can adapt to changes in the environment. For this we use `messageFn: () => string` property. - -```TypeScript -let role = "admin" - -const validator = v.validator<{ username: string }>({ - items: { - username: v.string() - .min(10, {messageFn: () => `invalid '${role}' username!`}) - }, -}).init(() => { - return { - username: "bshg" - } -}) - -validator.validate() -console.log(validator.items.username?.message) // invalid 'admin' username! -``` - -### Combining Placeholder and Dynamic Messages - -You can combine [Placeholder Message](#placeholder-messages) and [Dynamic Message](#dynamic-messages) to create sophisticated and detailed error messages. - -```TypeScript -let role = "admin" - -const validator = v.validator<{ username: string }>({ - items: { - username: v.string() - .min(10, {messageFn: () => `invalid '${role}' username! min lenght is %1.`}) - }, -}).init(() => { - return { - username: "bshg" - } -}) - -validator.validate() -console.log(validator.items.username?.message) // invalid 'admin' username! min lenght is 10. -``` - -## `import()` API - -The `import()` method accepts the `ValidatorResult` object and sets the validation results to the validator. This API is used to pass validation results from one validator to another, which can be useful when transferring validation results from a server to a client. - -- **Description:** Sets the validation results of another validator to the current validator. -- **Parameters:** - - `results`: The validation results object to be imported. -- **Usage:** - ```typescript - const userValidator = v.validator({ - items: { - username: v.string().required(), - password: v.string().required() - }, - }).init(() => item); - - const userValidator2 = v.validator({ - items: { - username: v.string(), - password: v.string() - } - }).init(() => item2); - - try { - userValidator.validateThrow(); // Validate the object - } catch (e) { - // Pass the validation results to the second validator - userValidator2.import((e as BshValidationError).results); - } - ``` - -The `import()` method is particularly useful when you need to transfer validation results from one validator to another. It facilitates the propagation of validation errors between different parts of your application, ensuring consistent handling of validation outcomes. This method is commonly used when performing validation on the server side and relaying the results to the client for display or further processing. - -## Multi-Language Support for Validation Messages - -Your validation library now supports error messages in multiple languages. Users can define error messages in the following supported languages: - -- English (`en`) -- French (`fr`) -- Arabic (`ar`) - -### Configuration - -#### Setting the Default Locale - -To set the default locale for your validation messages, configure it during the initial setup. Here’s how: - -```typescript -import {v, m} from '@bshg/validation'; - -// Set the default locale to French -v.configure({ - validatorOptions: {/**/}, - regex: {/**/}, - local: "ar" // Set the default locale to Arabic -}); -``` - -#### Changing the Locale at Runtime - -You can change the locale dynamically at runtime using the `changeLocal(local)` method provided by the `m` module. - -```typescript -import {v, m} from '@bshg/validation'; - -// Change the locale to Arabic -m.changeLocal('ar'); -``` - -### Example Usage - -Here’s a complete example demonstrating how to configure and change locales for validation messages: - -```typescript -import {v, m} from '@bshg/validation'; - -// Initial configuration with French as the default locale -v.configure({ - validatorOptions: {/**/}, - regex: {/**/}, - local: "fr" // Set the default locale to French -}); - -// Validate some data (error messages will be in French) -const validationResult = v.validator<{ email: string }>({ - items: {email: v.string().required()} -}).validateInfo(); -console.log(validationResult); // Outputs error messages in French - -// Change the locale to Arabic at runtime -m.changeLocal('ar'); - -// Validate the same data again (error messages will now be in Arabic) -const validationResultAr = v.validator<{ email: string }>({ - items: {email: v.string().required()} -}).validateInfo(); -console.log(validationResultAr); // Outputs error messages in Arabic - -// Change the locale to English at runtime -m.changeLocal('en'); - -// Validate the same data again (error messages will now be in English) -const validationResultEn = v.validator<{ email: string }>({ - items: {email: v.string().required()} -}).validateInfo(); -console.log(validationResultEn); // Outputs error messages in English -``` - -### Supported Locales - -The library currently supports the following locales: - -- **English** (`en`) -- **French** (`fr`) -- **Arabic** (`ar`) - -With the new multi-language support, you can switch between different languages for your validation messages, making your application more accessible to a wider audience. Use the configuration and runtime methods provided to customize the validation messages to suit your application's needs. - -## Overriding Default Values - -### Overriding Options Globally - -You can customize the default validation options globally using the `v.configure()` method. This method accepts an object where you can specify the options you want to override. Here's how you can do it: - -```typescript -v.configure({ - validatorOptions: { - dev: true, - warn: true, - resultsType: "array" - }, - regex: { - EMAIL: /regex/ - }, - local: 'en' -}) -``` - -In the configuration object: - -- **`validatorOptions`**: This property allows you to specify various options for validation. If you don't provide this property, the default options will be used. -- **`regex`**: You can override or define custom regex patterns for specific validation rules. -- **`local`**: This property sets the default locale for validation messages. - -Here are the options that you can override: - -| Option | Explanation | Default Value | -|---------------|-------------------------------------------------------------------------------------|---------------| -| `dev` | Enables development mode which provides additional debugging information. | `false` | -| `warn` | If set to `true`, warnings will be shown for non-critical issues during validation. | `false` | -| `resultsType` | Defines the format of the validation results. Can be `array` or `object`. | `object` | - -By customizing these options, you can tailor the validation behavior according to your application's specific requirements. - -### Overriding Options For A Specific Validator - -While you can set global options using `v.configure()`, sometimes you may need to customize options for a specific validator instance. This allows you to fine-tune validation behavior according to the unique requirements of each validator. - -To override default options for a specific validator, provide the `options` property in the validator object during its creation. - -Here's an example: - -```typescript -const userValidator = v.validator({ - id: "userValidator", - items: { - username: v.string().required(), - password: v.string().required() - }, - options: { // Customize options for this validator instance - dev: true, - warn: false, - resultsType: "object", - } -}) -``` - -In this example: - -- The `dev` option is set to `true`, enabling development mode for this validator instance. This provides additional debugging information. -- The `warn` option is set to `false`, meaning warnings for non-critical issues during validation will be suppressed. -- The `resultsType` option is set to `"object"`, defining the format of the validation results for this validator as an object. - -By overriding options for specific validators, you can precisely control their behavior to meet your application's requirements. This allows for greater flexibility and customization in validation logic. - -### Overriding Regex Values - -This library provides the flexibility to override default regex values used for validating string data, such as email addresses, phone numbers, URLs, and more. You can customize these regex patterns to better suit your specific validation requirements. - -#### Using `v.configure()` Method: - -You can override default regex values globally by using the `v.configure()` method. Provide the desired regex patterns within the `regex` property of the configuration object. - -```typescript -v.configure({ - validatorOptions: {/**/}, - regex: { - EMAIL: /email@[a-z]+\.[a-z]+/i, - PHONE: /\+\d{1,3}\(\d{3}\)\d{3}-\d{4}/, - // Add or override other regex values as needed - } -}) -``` - -#### Directly in `v.regex` Container: - -Alternatively, you can directly modify the `v.regex` container to override default regex values. This method offers more flexibility and control over individual regex patterns. - -```typescript -import {v} from '@bshg/validation' - -v.regex.EMAIL = /email@[a-z]+\.[a-z]+/i -v.regex.PHONE = /\+\d{1,3}\(\d{3}\)\d{3}-\d{4}/ -// Add or override other regex values as needed -``` - -#### Default Regex Patterns: - -Here are the default regex patterns used for various validations: - -| Regex Name | Regex Pattern | Used in | -|:-------------|:----------------------------------------------------------------------------------------------------------|:----------------------------| -| EMAIL | `/^[^\s@]+@[^\s@]+\.[^\s@]+$/` | `v.string().email()` | -| PHONE | `/^[\+]?[(]?[0-9]{3}[)]?[-\s\.]?[0-9]{3}[-\s\.]?[0-9]{4,6}$/im` | `v.string().phone()` | -| NUMERIC | `/^[0-9]+$/` | `v.string().numeric()` | -| ALPHA | `/^[a-zA-Z]+$/` | `v.string().alpha()` | -| ALPHANUMERIC | `/^[a-zA-Z0-9]+$/` | `v.string().alphanumeric()` | -| URL | `/^(ftp\|http\|https):\/\/[^ "]+$/` | `v.string().url()` | -| DATE | `/^\d{4}-\d{2}-\d{2}$/` | `v.string().date()` | -| TIME | `/^([01]\d\|2[0-3]):([0-5]\d):([0-5]\d)$/` | `v.string().time()` | -| HEX_COLOR | `/^#?([a-fA-F0-9]{6}\|[a-fA-F0-9]{3})$/` | `v.string().hexColor()` | -| CREDIT_CARD | `/^(?:3[47]\d{2}([\s-]?)\d{6}\1\d{5}\|(?:4\d\|5[1-5]\|65)\d{2}\d{5}\d{4}\|6011([\s-]?)\d{4}\d{4}\d{4})$/` | `v.string().creditCard()` | -| HTML_TAG | `/<("[^"]*"\|'[^']*'\|[^'">])*>/` | `v.string().htmlTag()` | -| BASE64 | `/[^A-Za-z0-9+/=]/` | `v.string().base64()` | - -Feel free to modify these regex patterns according to your specific validation needs. - -### Overriding Localization - -Localization is essential for providing error messages and validation feedback in different languages or cultural contexts. This feature allows you to customize the language used for validation messages, making your application more accessible to users from diverse backgrounds. - -1. **Using `v.configure()` Method:** - When using `v.configure()`, you can specify the desired locale directly in the configuration object. This will set the default language for all validation messages generated by the library. - - ```typescript - v.configure({ - validatorOptions: {/**/}, - regex: {/**/}, - local: "ar" // Set the default locale to Arabic - }) - ``` - -2. **Using `m.changeLocal()` API:** - Alternatively, you can dynamically change the locale at runtime using the `m.changeLocal()` method provided by the library. This allows you to switch languages based on user preferences or application settings. - - ```typescript - import {m} from '@bshg/validation' - - m.changeLocal("ar") // Change the locale to Arabic - ``` - -By overriding the localization settings, you can ensure that validation messages are displayed in the appropriate language for your users. This enhances the user experience and helps improve accessibility for a global audience. - -## What is New in 0.5.5 - -- add validator status to define the status of the validator after being executed [#commet](https://github.com/bsh-generator/bshg_validation_ts/tree/7901e77f88f88bf047af7ff9dc78a62363d39abb) -- update the loggers [#commet](https://github.com/bsh-generator/bshg_validation_ts/tree/a8476b8b069e5eeab001203c464e13a45401ccd2) -- start using tests in the library -- Simplify Access to Validation Status and Messages [#2](https://github.com/bsh-generator/bshg_validation_ts/issues/2) diff --git a/__tests__/index.test.ts b/__tests__/index.test.ts index 6071b81..e90af7c 100644 --- a/__tests__/index.test.ts +++ b/__tests__/index.test.ts @@ -1,7 +1,9 @@ -import SimpleValidationTests from './simple-validation' -import NestedValidationTests from './nested-validation' +import SimpleValidationTests from "./simple-validation"; +import NestedValidationTests from "./nested-validation"; import PrimitiveValidator from "./primitive-validator"; -describe('Simple Validation Tests', SimpleValidationTests) -describe('Nested Validation Tests', NestedValidationTests) -describe('Primitive Validation Tests', PrimitiveValidator) +// TODO: add typeValidator test, test each function... + +describe("Simple Validation Tests", SimpleValidationTests); +describe("Nested Validation Tests", NestedValidationTests); +describe("Primitive Validation Tests", PrimitiveValidator); diff --git a/__tests__/primitive-validator.ts b/__tests__/primitive-validator.ts index 2fa7388..3e2adb0 100644 --- a/__tests__/primitive-validator.ts +++ b/__tests__/primitive-validator.ts @@ -1,23 +1,23 @@ import { m, v } from "@bshg/validation"; export default () => { - const pv = v.string().required().email().build(); + const pv = v.primitive(v.string().required().email()); - it("should build a validator correctly", () => { - expect(pv).toBeDefined() - }); + it("should build a validator correctly", () => { + expect(pv).toBeDefined(); + }); - it("should validate", () => { - const actual = pv.apply("bshg@mail.com"); - expect(actual).toBeDefined() - expect(actual.status).toBe(true) - expect(actual.err).toBeUndefined() - }); + it("should validate", () => { + const actual = pv.apply("bshg@mail.com"); + expect(actual).toBeDefined(); + expect(actual.status).toBe(true); + expect(actual.err).toBeUndefined(); + }); - it("should validate", () => { - const actual = pv.apply("bshgmail.com"); - expect(actual).toBeDefined() - expect(actual.status).toBe(false) - expect(actual.err).toBe(m.Messages.en.string.email) - }); + it("should validate", () => { + const actual = pv.apply("bshgmail.com"); + expect(actual).toBeDefined(); + expect(actual.status).toBe(false); + expect(actual.err).toBe(m.Messages.en.string.email); + }); } \ No newline at end of file diff --git a/__tests__/simple-validation.ts b/__tests__/simple-validation.ts index 1a80b2d..2dfdfe9 100644 --- a/__tests__/simple-validation.ts +++ b/__tests__/simple-validation.ts @@ -1,33 +1,33 @@ -import { v } from '@bshg/validation'; +import { v } from "@bshg/validation"; import { Profile, User } from "./types"; -const emails = ['example@mail.com']; +const emails = ["example@mail.com"]; const userValidator = v.validator({ - id: 'validator', + id: "validator", items: { email: v.string().required().email().onError({ error: (value) => !emails.includes(value), - message: 'unexpected email', + message: "unexpected email", }), username: v.string().notEmpty().alphanumeric(), profile: v.custom().onError({ error: (value) => value.age < 18, - message: 'too young', + message: "too young", }).onError({ error: (value) => value.age > 100, - message: 'too old', + message: "too old", }), }, }); export default () => { - it('should validate a correct user', () => { + it("should validate a correct user", () => { const res = userValidator.validate({ - email: 'example@mail.com', - username: 'testuser', + email: "example@mail.com", + username: "testuser", profile: { - name: 'test', + name: "test", age: 25, }, }); @@ -35,12 +35,12 @@ export default () => { expect(res).toBe(true); }); - it('should invalidate an incorrect email', () => { + it("should invalidate an incorrect email", () => { const res = userValidator.validate({ - email: 'wrong@mail.com', - username: 'testuser', + email: "wrong@mail.com", + username: "testuser", profile: { - name: 'test', + name: "test", age: 25, }, }); @@ -48,12 +48,12 @@ export default () => { expect(res).toBe(false); }); - it('should invalidate an empty username', () => { + it("should invalidate an empty username", () => { const res = userValidator.validate({ - email: 'example@mail.com', - username: '', + email: "example@mail.com", + username: "", profile: { - name: 'test', + name: "test", age: 25, }, }); @@ -61,12 +61,12 @@ export default () => { expect(res).toBe(false); }); - it('should invalidate an underage user', () => { + it("should invalidate an underage user", () => { const res = userValidator.validate({ - email: 'example@mail.com', - username: 'testuser', + email: "example@mail.com", + username: "testuser", profile: { - name: 'test', + name: "test", age: 16, }, }); @@ -74,12 +74,12 @@ export default () => { expect(res).toBe(false); }); - it('should invalidate an overage user', () => { + it("should invalidate an overage user", () => { const res = userValidator.validate({ - email: 'example@mail.com', - username: 'testuser', + email: "example@mail.com", + username: "testuser", profile: { - name: 'test', + name: "test", age: 105, }, }); diff --git a/configs/tsconfig.base.json b/configs/tsconfig.base.json index dffa42b..9e9a409 100644 --- a/configs/tsconfig.base.json +++ b/configs/tsconfig.base.json @@ -1,6 +1,12 @@ { "compilerOptions": { - "lib": ["es5", "es6", "es7", "esnext", "dom"], + "lib": [ + "es5", + "es6", + "es7", + "esnext", + "dom" + ], "target": "es2018", "removeComments": false, "esModuleInterop": true, @@ -15,7 +21,10 @@ "noFallthroughCasesInSwitch": true, "downlevelIteration": true, "isolatedModules": true, - "declaration": true, + "declaration": true }, - "include": ["../src/**/*", "../playground.ts"] + "include": [ + "../src/**/*", + "../playground.ts" + ] } diff --git a/configs/tsconfig.cjs.json b/configs/tsconfig.cjs.json index 04e1efe..5028350 100644 --- a/configs/tsconfig.cjs.json +++ b/configs/tsconfig.cjs.json @@ -7,5 +7,8 @@ "declarationMap": false, "sourceMap": false }, - "exclude": ["../src/**/__tests__", "../playground.ts"] + "exclude": [ + "../src/**/__tests__", + "../playground.ts" + ] } diff --git a/configs/tsconfig.esm.json b/configs/tsconfig.esm.json index b5c23f2..3512900 100644 --- a/configs/tsconfig.esm.json +++ b/configs/tsconfig.esm.json @@ -7,5 +7,8 @@ "declarationMap": false, "sourceMap": false }, - "exclude": ["../src/**/__tests__", "../src/playground.ts"] + "exclude": [ + "../src/**/__tests__", + "../src/playground.ts" + ] } diff --git a/jest.config.js b/jest.config.js index d2d2223..ab15dd0 100644 --- a/jest.config.js +++ b/jest.config.js @@ -2,8 +2,8 @@ module.exports = { preset: "ts-jest", testEnvironment: "node", "testRegex": "__tests__/.*\\.test\\.ts$", - moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx'], + moduleFileExtensions: ["ts", "tsx", "js", "jsx"], moduleNameMapper: { - "^@bshg/validation(.*)$": "/src$1" + "^@bshg/validation(.*)$": "/src$1", }, }; diff --git a/playground.ts b/playground.ts index 52af867..84f2b4f 100644 --- a/playground.ts +++ b/playground.ts @@ -2,6 +2,6 @@ import { v } from "./src"; v.configure({ validatorOptions: { - dev: true - } + dev: true, + }, }); diff --git a/src/index.ts b/src/index.ts index 011b41e..5856449 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1 +1 @@ -export * from './validators'; +export * from "./validators"; diff --git a/src/validators/configuration/index.ts b/src/validators/configuration/index.ts index 5bdc657..1b56e1d 100644 --- a/src/validators/configuration/index.ts +++ b/src/validators/configuration/index.ts @@ -1,7 +1,7 @@ -import {ValidatorOptions} from "../utils"; -import {RegexType, updateRegex} from "../utils/regex"; -import {updateValidatorOptions} from "../options"; -import {changeLocal, LocalType} from "../messages"; +import { ValidatorOptions } from "../utils"; +import { RegexType, updateRegex } from "../utils/regex"; +import { updateValidatorOptions } from "../options"; +import { changeLocal, LocalType } from "../messages"; type LibConfig = { validatorOptions?: ValidatorOptions, @@ -10,7 +10,7 @@ type LibConfig = { } export const configure = (config: LibConfig) => { - config.validatorOptions && updateValidatorOptions(config.validatorOptions) - config.regex && updateRegex(config.regex) - config.local && changeLocal(config.local) -} + config.validatorOptions && updateValidatorOptions(config.validatorOptions); + config.regex && updateRegex(config.regex); + config.local && changeLocal(config.local); +}; diff --git a/src/validators/exceptions/index.ts b/src/validators/exceptions/index.ts index ad17709..0f42179 100644 --- a/src/validators/exceptions/index.ts +++ b/src/validators/exceptions/index.ts @@ -3,12 +3,12 @@ import { LOGGER } from "../logger"; export class BshgError extends Error { constructor(tag?: string, err?: string) { super(err); - if (tag != undefined) LOGGER.error(tag, true, err) + if (tag != undefined) LOGGER.error(tag, true, err); } } export class ValidationFailedError extends BshgError { constructor() { - super() + super(); } } \ No newline at end of file diff --git a/src/validators/index.ts b/src/validators/index.ts index d46b7c7..f1fb927 100644 --- a/src/validators/index.ts +++ b/src/validators/index.ts @@ -1,5 +1,10 @@ -export * as v from './v' -export * as m from './messages' -export {BshValidationError, BshBatchValidationError} from './results' -export {options} from './options' -export {ValidatorItem,Validator} from './main' +export * as v from "./v"; +export * as m from "./messages"; +export * from "./results"; +export * from "./options"; +export * from "./main"; +export * from "./configuration"; +export * from "./exceptions"; +export * from "./logger"; +export * from "./utils"; +export * from "./validators-fn"; diff --git a/src/validators/main/Validator-template.ts b/src/validators/main/Validator-template.ts index 11f8ef4..be3443a 100644 --- a/src/validators/main/Validator-template.ts +++ b/src/validators/main/Validator-template.ts @@ -1,11 +1,11 @@ import { NestedType, ValidatorConfig, ValidatorTemplateConfig } from "../utils"; -import {Validator} from "./validator"; +import { Validator } from "./validator"; export class ValidatorTemplate, TContext extends Record> { private readonly config: ValidatorTemplateConfig; constructor(config: ValidatorTemplateConfig) { - this.config = config + this.config = config; } instant(): Validator { @@ -13,18 +13,18 @@ export class ValidatorTemplate, TContext extends R id: this.config.id, options: this.config.options, items: this.config.items, - } + }; const nested = this.config.nested; if (nested) { Object.keys(nested).forEach((it) => { - if (validatorConfig.nested == undefined) validatorConfig.nested = {} as NestedType + if (validatorConfig.nested == undefined) validatorConfig.nested = {} as NestedType; // @ts-ignore - validatorConfig.nested[it] = nested[it as keyof typeof nested]?.instant() - }) + validatorConfig.nested[it] = nested[it as keyof typeof nested]?.instant(); + }); } - return new Validator().config(validatorConfig) + return new Validator().config(validatorConfig); } batchValidate(...data: T[]) { diff --git a/src/validators/main/index.ts b/src/validators/main/index.ts index 43e01de..b9f9bb4 100644 --- a/src/validators/main/index.ts +++ b/src/validators/main/index.ts @@ -1,3 +1,3 @@ -export * from './validator-item' -export * from './validator' -export * from './Validator-template' +export * from "./validator-item"; +export * from "./validator"; +export * from "./Validator-template"; diff --git a/src/validators/main/validator-item.ts b/src/validators/main/validator-item.ts index d9b5138..ad9808c 100644 --- a/src/validators/main/validator-item.ts +++ b/src/validators/main/validator-item.ts @@ -7,12 +7,12 @@ import { ValidatorFnDependConfig, ValidatorFnDependConfigAsync, ValidatorFnDependConfigCtx, - ValidatorFnDependConfigCtxAsync + ValidatorFnDependConfigCtxAsync, } from "../utils"; -import {TypeValidator} from "../validators-fn"; -import {message, messageVars, TypeValidatorWithContext} from "../validators-fn/base"; -import {CurrentLocalize} from '../messages' -import {Validator} from "./validator"; +import { TypeValidator } from "../validators-fn"; +import { message, messageVars, TypeValidatorWithContext } from "../validators-fn/base"; +import { CurrentLocalize } from "../messages"; +import { Validator } from "./validator"; import { ValidationFailedError } from "../exceptions"; export class ValidatorItem> { @@ -22,25 +22,26 @@ export class ValidatorItem> { get!: () => T; set!: (value: T) => void; container!: () => TC; - validator!: Validator + validator!: Validator; + context: Record = this.validator?.context; - #validations?: ValidatorFnConfig[] - #validationsDepend?: ValidatorFnDependConfig[] - #validationsAsync?: ValidatorFnConfigAsync[] - #validationsDependAsync?: ValidatorFnDependConfigAsync[] + #validations?: ValidatorFnConfig[]; + #validationsDepend?: ValidatorFnDependConfig[]; + #validationsAsync?: ValidatorFnConfigAsync[]; + #validationsDependAsync?: ValidatorFnDependConfigAsync[]; - #validationsCtx?: ValidatorFnConfigCtx[] - #validationsDependCtx?: ValidatorFnDependConfigCtx[] - #validationsCtxAsync?: ValidatorFnConfigCtxAsync[] - #validationsDependCtxAsync?: ValidatorFnDependConfigCtxAsync[] + #validationsCtx?: ValidatorFnConfigCtx[]; + #validationsDependCtx?: ValidatorFnDependConfigCtx[]; + #validationsCtxAsync?: ValidatorFnConfigCtxAsync[]; + #validationsDependCtxAsync?: ValidatorFnDependConfigCtxAsync[]; - #validationsWithContext?: TypeValidatorWithContext[] + #validationsWithContext?: TypeValidatorWithContext[]; setValidations(value: TypeValidator | TypeValidatorWithContext[] | undefined) { if (value instanceof Array) { - this.#validationsWithContext = value + this.#validationsWithContext = value; } else if (value) { - value = value as TypeValidator + value = value as TypeValidator; this.#validations = value?.validations; this.#validationsDepend = value?.validationsDepend; @@ -55,21 +56,21 @@ export class ValidatorItem> { } #onChange() { - this.validator?.onChangeEvent && this.validator.onChangeEvent(this.container()) + this.validator?.onChangeEvent && this.validator.onChangeEvent(this.container()); } reset() { - this.valid = undefined - this.message = undefined - this.#onChange() + this.valid = undefined; + this.message = undefined; + this.#onChange(); } markAsError(msg: string) { - this.valid = false + this.valid = false; this.message = msg .replace(messageVars.value, this.get() + "") - .replace(messageVars.name, this.name) - this.#onChange() + .replace(messageVars.name, this.name); + this.#onChange(); } /** @@ -79,60 +80,60 @@ export class ValidatorItem> { * @see #markAsError */ error(msg: string) { - this.markAsError(msg) + this.markAsError(msg); } markAsValid() { this.valid = true; this.message = undefined; - this.#onChange() + this.#onChange(); } apply(value: T): { status?: boolean, err?: string } { - this.get = () => value - this.validate() - return {status: this.valid, err: this.message} + this.get = () => value; + this.validate(); + return { status: this.valid, err: this.message }; } validate = () => { try { - this.#validations?.forEach(it => this.#doValidations(it)) - this.#validationsDepend?.forEach(it => this.#doValidations(it)) - this.#validationsCtx?.forEach(it => this.#doValidationsCtx(it)) - this.#validationsDependCtx?.forEach(it => this.#doValidationsCtx(it)) - this.#doValidationsWithContext() + this.#validations?.forEach(it => this.#doValidations(it)); + this.#validationsDepend?.forEach(it => this.#doValidations(it)); + this.#validationsCtx?.forEach(it => this.#doValidationsCtx(it)); + this.#validationsDependCtx?.forEach(it => this.#doValidationsCtx(it)); + this.#doValidationsWithContext(); } catch (e) { if (e instanceof ValidationFailedError) return; - throw e + throw e; } - this.markAsValid() - } + this.markAsValid(); + }; validateAsync = async () => { try { - this.#validations?.forEach(it => this.#doValidations(it)) - this.#validationsDepend?.forEach(it => this.#doValidations(it)) - this.#validationsCtx?.forEach(it => this.#doValidationsCtx(it)) - this.#validationsDependCtx?.forEach(it => this.#doValidationsCtx(it)) + this.#validations?.forEach(it => this.#doValidations(it)); + this.#validationsDepend?.forEach(it => this.#doValidations(it)); + this.#validationsCtx?.forEach(it => this.#doValidationsCtx(it)); + this.#validationsDependCtx?.forEach(it => this.#doValidationsCtx(it)); await Promise.all([ ...(this.#validationsAsync?.map(async it => await this.#doValidationsAsync(it)) || []), ...(this.#validationsDependAsync?.map(async it => await this.#doValidationsAsync(it)) || []), ...(this.#validationsCtxAsync?.map(async it => await this.#doValidationsCtxAsync(it)) || []), - ...(this.#validationsDependCtxAsync?.map(async it => await this.#doValidationsCtxAsync(it)) || []) - ]) - await this.#doValidationsWithContextAsync() + ...(this.#validationsDependCtxAsync?.map(async it => await this.#doValidationsCtxAsync(it)) || []), + ]); + await this.#doValidationsWithContextAsync(); } catch (e) { return; } this.valid = true; this.message = undefined; - } + }; #getMessage = (fn: BaseValidatorFnConfig) => { - return message(CurrentLocalize.noMessage, {message: fn.message}) - } + return message(CurrentLocalize.noMessage, { message: fn.message }); + }; ////////////////////////////////////////////////////// ////////////// DO VALIDATIONS METHOD ///////////////// @@ -142,11 +143,11 @@ export class ValidatorItem> { ValidatorFnConfigCtx | ValidatorFnDependConfigCtxAsync | ValidatorFnConfigCtxAsync, - result: boolean + result: boolean, ) { if (result) { - this.markAsError(this.#getMessage(fn)) - throw new ValidationFailedError() + this.markAsError(this.#getMessage(fn)); + throw new ValidationFailedError(); } } @@ -155,9 +156,9 @@ export class ValidatorItem> { #doValidations(fn: ValidatorFnDependConfig | ValidatorFnConfig): void { const result = fn.error.length > 1 ? (fn as ValidatorFnDependConfig).error(this.get(), this.container()) - : (fn as ValidatorFnConfig).error(this.get()) + : (fn as ValidatorFnConfig).error(this.get()); - this.#setTheError(fn, result) + this.#setTheError(fn, result); } #doValidationsCtx(fn: ValidatorFnConfigCtx): void @@ -165,9 +166,9 @@ export class ValidatorItem> { #doValidationsCtx(fn: ValidatorFnDependConfigCtx | ValidatorFnConfigCtx): void { const result = fn.error.length > 2 ? (fn as ValidatorFnDependConfigCtx).error(this.get(), this.container(), this.validator?.context) - : (fn as ValidatorFnConfigCtx).error(this.get(), this.validator?.context) + : (fn as ValidatorFnConfigCtx).error(this.get(), this.validator?.context); - this.#setTheError(fn, result) + this.#setTheError(fn, result); } async #doValidationsAsync(fn: ValidatorFnConfigAsync): Promise @@ -175,9 +176,9 @@ export class ValidatorItem> { async #doValidationsAsync(fn: ValidatorFnDependConfigAsync | ValidatorFnConfigAsync): Promise { const result = fn.error.length > 1 ? await (fn as ValidatorFnDependConfigAsync).error(this.get(), this.container()) - : await (fn as ValidatorFnConfigAsync).error(this.get()) + : await (fn as ValidatorFnConfigAsync).error(this.get()); - this.#setTheError(fn, result) + this.#setTheError(fn, result); } async #doValidationsCtxAsync(fn: ValidatorFnConfigCtxAsync): Promise @@ -185,9 +186,9 @@ export class ValidatorItem> { async #doValidationsCtxAsync(fn: ValidatorFnDependConfigCtxAsync | ValidatorFnConfigCtxAsync): Promise { const result = fn.error.length > 2 ? await (fn as ValidatorFnDependConfigCtxAsync).error(this.get(), this.container(), this.validator?.context) - : await (fn as ValidatorFnConfigCtxAsync).error(this.get(), this.validator?.context) + : await (fn as ValidatorFnConfigCtxAsync).error(this.get(), this.validator?.context); - this.#setTheError(fn, result) + this.#setTheError(fn, result); } ///////// @@ -195,34 +196,34 @@ export class ValidatorItem> { return val.ctx == undefined ? false : typeof val.ctx == "function" ? val.ctx(this.validator.context) - : Object.keys(val.ctx).every(key => this.validator.context[key] == (val.ctx as Record)[key]) + : Object.keys(val.ctx).every(key => this.validator.context[key] == (val.ctx as Record)[key]); } #doValidationsWithContext(): void { this.#validationsWithContext?.forEach(val => { if (this.#takeValidationsFromContext(val)) { - val.validations.validations?.forEach(it => this.#doValidationsCtx(it)) - val.validations.validationsDepend?.forEach(it => this.#doValidationsCtx(it)) - val.validations.validationsCtx?.forEach(it => this.#doValidationsCtx(it)) - val.validations.validationsDependCtx?.forEach(it => this.#doValidationsCtx(it)) + val.validations.validations?.forEach(it => this.#doValidationsCtx(it)); + val.validations.validationsDepend?.forEach(it => this.#doValidationsCtx(it)); + val.validations.validationsCtx?.forEach(it => this.#doValidationsCtx(it)); + val.validations.validationsDependCtx?.forEach(it => this.#doValidationsCtx(it)); } - }) + }); } async #doValidationsWithContextAsync(): Promise { if (this.#validationsWithContext) { for (let val of this.#validationsWithContext) { if (this.#takeValidationsFromContext(val)) { - val.validations.validations?.forEach(it => this.#doValidations(it)) - val.validations.validationsDepend?.forEach(it => this.#doValidations(it)) - val.validations.validationsCtx?.forEach(it => this.#doValidationsCtx(it)) - val.validations.validationsDependCtx?.forEach(it => this.#doValidationsCtx(it)) + val.validations.validations?.forEach(it => this.#doValidations(it)); + val.validations.validationsDepend?.forEach(it => this.#doValidations(it)); + val.validations.validationsCtx?.forEach(it => this.#doValidationsCtx(it)); + val.validations.validationsDependCtx?.forEach(it => this.#doValidationsCtx(it)); await Promise.all([ ...(val.validations.validationsAsync?.map(async it => await this.#doValidationsAsync(it)) || []), ...(val.validations.validationsDependAsync?.map(async it => await this.#doValidationsAsync(it)) || []), ...(val.validations.validationsCtxAsync?.map(async it => await this.#doValidationsCtxAsync(it)) || []), - ...(val.validations.validationsDependCtxAsync?.map(async it => await this.#doValidationsCtxAsync(it)) || []) - ]) + ...(val.validations.validationsDependCtxAsync?.map(async it => await this.#doValidationsCtxAsync(it)) || []), + ]); } } } diff --git a/src/validators/main/validator.ts b/src/validators/main/validator.ts index ac2fb80..84367f8 100644 --- a/src/validators/main/validator.ts +++ b/src/validators/main/validator.ts @@ -1,6 +1,7 @@ import { BshBatchValidationError, - BshValidationError, ValidatorComplexResultObjects, + BshValidationError, + ValidatorComplexResultObjects, ValidatorComplexResultVFieldName, ValidatorResult, ValidatorResultArrays, diff --git a/src/validators/messages/ar.ts b/src/validators/messages/ar.ts index f475a5a..814d0f7 100644 --- a/src/validators/messages/ar.ts +++ b/src/validators/messages/ar.ts @@ -1,4 +1,4 @@ -import {ErrorMessage} from "./index"; +import { ErrorMessage } from "./index"; export const ar: ErrorMessage = { noMessage: "No Error Message Was Provided!", @@ -7,10 +7,10 @@ export const ar: ErrorMessage = { notEmpty: "هذا الحقل إلزامي!", min: "الحد الأدنى للطول هو %1", max: "الحد الأقصى للطول هو %1", - includes: 'يجب أن يحتوي على "%1"', - includesAll: 'يجب أن يحتوي على الكل: %1', - startsWith: 'يجب أن يبدأ بـ "%1"', - endsWith: 'يجب أن ينتهي بـ "%1"', + includes: "يجب أن يحتوي على \"%1\"", + includesAll: "يجب أن يحتوي على الكل: %1", + startsWith: "يجب أن يبدأ بـ \"%1\"", + endsWith: "يجب أن ينتهي بـ \"%1\"", matches: "لا يتطابق مع النمط المطلوب", email: "صيغة البريد الإلكتروني غير صالحة", phone: "صيغة الهاتف غير صالحة", @@ -24,7 +24,7 @@ export const ar: ErrorMessage = { alphanumeric: "يجب أن يحتوي على حروف أبجدية وأرقام فقط", numeric: "يجب أن يحتوي على أرقام فقط", alpha: "يجب أن يحتوي على حروف أبجدية فقط", - as: "القيمة يجب أن تكون كـ '%1'" + as: "القيمة يجب أن تكون كـ '%1'", }, number: { required: "هذا الحقل إلزامي!", @@ -48,14 +48,14 @@ export const ar: ErrorMessage = { primeNumber: "القيمة يجب أن تكون عددًا أوليًا", fibonacciNumber: "القيمة يجب أن تكون عددًا في سلسلة فيبوناتشي", powerOfTwo: "القيمة يجب أن تكون عددًا مربعًا للعدد 2", - as: "القيمة يجب أن تكون كـ '%1'" + as: "القيمة يجب أن تكون كـ '%1'", }, boolean: { required: "هذا الحقل إلزامي!", true: "القيمة يجب أن تكون 'صحيحة'", false: "القيمة يجب أن تكون 'خاطئة'", equals: "القيمة يجب أن تكون %1", - as: "القيمة يجب أن تكون '%1'" + as: "القيمة يجب أن تكون '%1'", }, array: { length: "القيمة يجب أن تكون بطول %1", @@ -66,7 +66,7 @@ export const ar: ErrorMessage = { hasAny: "القيمة يجب أن تتضمن أيًا من: %1", hasNone: "القيمة يجب أن لا تتضمن أيًا من: %1", some: "المصفوفة لا تتطابق مع الشرط المعطى!", - every: "المصفوفة لا تتطابق مع الشرط المعطى!" + every: "المصفوفة لا تتطابق مع الشرط المعطى!", }, datetime: { required: "هذا الحقل إلزامي!", @@ -80,7 +80,7 @@ export const ar: ErrorMessage = { future: "يجب أن يكون التاريخ في المستقبل", weekday: "يجب أن يكون التاريخ يومًا عمليًا", weekend: "يجب أن يكون التاريخ عطلة نهاية أسبوع", - as: "القيمة يجب أن تكون كـ '%1'" + as: "القيمة يجب أن تكون كـ '%1'", }, date: { required: "هذا الحقل إلزامي!", @@ -96,7 +96,7 @@ export const ar: ErrorMessage = { weekend: "يجب أن يكون التاريخ عطلة نهاية أسبوع", leapYear: "يجب أن يكون التاريخ في سنة كبيسة", sameDayAs: "يجب أن يكون التاريخ نفس اليوم كـ %1", - as: "القيمة يجب أن تكون كـ '%1'" + as: "القيمة يجب أن تكون كـ '%1'", }, time: { required: "هذا الحقل إلزامي!", @@ -109,6 +109,6 @@ export const ar: ErrorMessage = { past: "يجب أن يكون الوقت في الماضي", future: "يجب أن يكون الوقت في المستقبل", within24Hours: "يجب أن يكون الوقت خلال الـ 24 ساعة القادمة", - as: "القيمة يجب أن تكون كـ '%1'" - } -} + as: "القيمة يجب أن تكون كـ '%1'", + }, +}; diff --git a/src/validators/messages/en.ts b/src/validators/messages/en.ts index 29680b9..07ee9e5 100644 --- a/src/validators/messages/en.ts +++ b/src/validators/messages/en.ts @@ -1,4 +1,4 @@ -import {ErrorMessage} from "./index"; +import { ErrorMessage } from "./index"; export const en: ErrorMessage = { noMessage: "No Error Message Was Provided!", @@ -7,10 +7,10 @@ export const en: ErrorMessage = { notEmpty: "This field is required!", min: "Minimum length required is %1", max: "Maximum length allowed is %1", - includes: 'Must include "%1"', - includesAll: 'Must include all of: %1', - startsWith: 'Must start with "%1"', - endsWith: 'Must end with "%1"', + includes: "Must include \"%1\"", + includesAll: "Must include all of: %1", + startsWith: "Must start with \"%1\"", + endsWith: "Must end with \"%1\"", matches: "Does not match the required pattern", email: "Invalid email format", phone: "Invalid phone format", @@ -24,7 +24,7 @@ export const en: ErrorMessage = { alphanumeric: "Must contain only alphanumeric characters", numeric: "Must contain only numeric characters", alpha: "Must contain only alphabetic characters", - as: "Value must be as '%1'" + as: "Value must be as '%1'", }, number: { required: "This field is required!", @@ -48,14 +48,14 @@ export const en: ErrorMessage = { primeNumber: "Value must be a prime number", fibonacciNumber: "Value must be a Fibonacci number", powerOfTwo: "Value must be a power of two", - as: "value must be as '%1'" + as: "value must be as '%1'", }, boolean: { required: "This field is required!", true: "Value must be true", false: "Value must be false", equals: "Value must be equal to %1", - as: "value must be as '%1'" + as: "value must be as '%1'", }, array: { length: "Value must be of length %1", @@ -66,7 +66,7 @@ export const en: ErrorMessage = { hasAny: "Value must include any of: %1", hasNone: "Value must include none of: %1", some: "Array does not match the given predicate!", - every: "Array does not match the given predicate!" + every: "Array does not match the given predicate!", }, datetime: { required: "This field is required!", @@ -80,7 +80,7 @@ export const en: ErrorMessage = { future: "DateTime must be in the future", weekday: "DateTime must be a weekday", weekend: "DateTime must be a weekend", - as: "Value must be as '%1'" + as: "Value must be as '%1'", }, date: { required: "This field is required!", @@ -96,7 +96,7 @@ export const en: ErrorMessage = { weekend: "Date must be a weekend", leapYear: "Date must be in a leap year", sameDayAs: "Date must be the same day as %1", - as: "value must be as '%1'" + as: "value must be as '%1'", }, time: { required: "This field is required!", @@ -109,6 +109,6 @@ export const en: ErrorMessage = { past: "Time must be in the past", future: "Time must be in the future", within24Hours: "Time must be within the next 24 hours", - as: "value must be as '%1'" - } -} + as: "value must be as '%1'", + }, +}; diff --git a/src/validators/messages/fr.ts b/src/validators/messages/fr.ts index 9ecb3c6..9bb09f9 100644 --- a/src/validators/messages/fr.ts +++ b/src/validators/messages/fr.ts @@ -7,10 +7,10 @@ export const fr: ErrorMessage = { notEmpty: "Ce champ ne peut pas être vide !", min: "La longueur minimale requise est de %1", max: "La longueur maximale autorisée est de %1", - includes: 'Doit inclure "%1"', - includesAll: 'Doit inclure tous : %1', - startsWith: 'Doit commencer par "%1"', - endsWith: 'Doit se terminer par "%1"', + includes: "Doit inclure \"%1\"", + includesAll: "Doit inclure tous : %1", + startsWith: "Doit commencer par \"%1\"", + endsWith: "Doit se terminer par \"%1\"", matches: "Ne correspond pas au modèle requis", email: "Format d'email invalide", phone: "Format de téléphone invalide", @@ -24,7 +24,7 @@ export const fr: ErrorMessage = { alphanumeric: "Doit contenir uniquement des caractères alphanumériques", numeric: "Doit contenir uniquement des caractères numériques", alpha: "Doit contenir uniquement des caractères alphabétiques", - as: "La valeur doit être comme '%1'" + as: "La valeur doit être comme '%1'", }, number: { required: "Ce champ est requis !", @@ -48,14 +48,14 @@ export const fr: ErrorMessage = { primeNumber: "La valeur doit être un nombre premier", fibonacciNumber: "La valeur doit être un nombre de Fibonacci", powerOfTwo: "La valeur doit être une puissance de deux", - as: "La valeur doit être comme '%1'" + as: "La valeur doit être comme '%1'", }, boolean: { required: "Ce champ est requis !", true: "La valeur doit être vrai", false: "La valeur doit être faux", equals: "La valeur doit être égale à %1", - as: "La valeur doit être comme '%1'" + as: "La valeur doit être comme '%1'", }, array: { length: "La valeur doit avoir une longueur de %1", @@ -66,7 +66,7 @@ export const fr: ErrorMessage = { hasAny: "La valeur doit inclure n'importe lequel de : %1", hasNone: "La valeur ne doit inclure aucun de : %1", some: "Le tableau ne correspond pas au prédicat donné", - every: "Le tableau ne correspond pas au prédicat donné" + every: "Le tableau ne correspond pas au prédicat donné", }, datetime: { required: "Ce champ est requis !", @@ -80,7 +80,7 @@ export const fr: ErrorMessage = { future: "La date et l'heure doivent être dans le futur", weekday: "La date et l'heure doivent être un jour de semaine", weekend: "La date et l'heure doivent être un jour de week-end", - as: "La valeur doit être comme '%1'" + as: "La valeur doit être comme '%1'", }, date: { required: "Ce champ est requis !", @@ -96,7 +96,7 @@ export const fr: ErrorMessage = { weekend: "La date doit être un jour de week-end", leapYear: "La date doit être dans une année bissextile", sameDayAs: "La date doit être le même jour que %1", - as: "La valeur doit être comme '%1'" + as: "La valeur doit être comme '%1'", }, time: { required: "Ce champ est requis !", @@ -109,6 +109,6 @@ export const fr: ErrorMessage = { past: "L'heure doit être dans le passé", future: "L'heure doit être dans le futur", within24Hours: "L'heure doit être dans les 24 prochaines heures", - as: "La valeur doit être comme '%1'" - } -} + as: "La valeur doit être comme '%1'", + }, +}; diff --git a/src/validators/messages/index.ts b/src/validators/messages/index.ts index eaebc7a..19f311c 100644 --- a/src/validators/messages/index.ts +++ b/src/validators/messages/index.ts @@ -1,18 +1,18 @@ -import {Strings} from "../validators-fn/strings"; -import {Numbers} from "../validators-fn/numbers"; -import {Booleans} from "../validators-fn/booleans"; -import {Arrays} from "../validators-fn/arrays"; -import {Dates} from "../validators-fn/dates"; -import {DateTimes} from "../validators-fn/datetimes"; -import {Times} from "../validators-fn/times"; -import {TypeValidator} from "../validators-fn"; -import {fr} from "./fr"; -import {en} from "./en"; -import {ar} from "./ar"; +import { Strings } from "../validators-fn/strings"; +import { Numbers } from "../validators-fn/numbers"; +import { Booleans } from "../validators-fn/booleans"; +import { Arrays } from "../validators-fn/arrays"; +import { Dates } from "../validators-fn/dates"; +import { DateTimes } from "../validators-fn/datetimes"; +import { Times } from "../validators-fn/times"; +import { TypeValidator } from "../validators-fn"; +import { fr } from "./fr"; +import { en } from "./en"; +import { ar } from "./ar"; type KeysWithout = T extends EX | keyof TypeValidator ? never : T -type Messages, EX = 'undefined'> = { [k in KeysWithout]: string } +type Messages, EX = "undefined"> = { [k in KeysWithout]: string } export type ErrorMessage = { noMessage: string, @@ -25,12 +25,12 @@ export type ErrorMessage = { time: Messages, } -export const Messages = {en, fr, ar} +export const Messages = { en, fr, ar }; export type LocalType = keyof typeof Messages -export let CurrentLocalize = en +export let CurrentLocalize = en; export const changeLocal = (local: LocalType) => { - CurrentLocalize = Messages[local] -} + CurrentLocalize = Messages[local]; +}; diff --git a/src/validators/options/index.ts b/src/validators/options/index.ts index fa3e22b..23a3c10 100644 --- a/src/validators/options/index.ts +++ b/src/validators/options/index.ts @@ -1,11 +1,11 @@ -import {ValidatorOptions} from "../utils"; +import { ValidatorOptions } from "../utils"; export const options: ValidatorOptions = { dev: false, - resultsType: `object` -} + resultsType: `object`, +}; export const updateValidatorOptions = (validatorOptions: ValidatorOptions) => { - options.dev = validatorOptions.dev ?? options.dev - options.resultsType = validatorOptions.resultsType ?? options.resultsType -} + options.dev = validatorOptions.dev ?? options.dev; + options.resultsType = validatorOptions.resultsType ?? options.resultsType; +}; diff --git a/src/validators/results/index.ts b/src/validators/results/index.ts index 1de43d0..1299b9d 100644 --- a/src/validators/results/index.ts +++ b/src/validators/results/index.ts @@ -1,2 +1,2 @@ -export * from './validation-error' -export * from './validator-result-objects' +export * from "./validation-error"; +export * from "./validator-result-objects"; diff --git a/src/validators/results/validation-error.ts b/src/validators/results/validation-error.ts index 0aa2f21..be1dceb 100644 --- a/src/validators/results/validation-error.ts +++ b/src/validators/results/validation-error.ts @@ -1,21 +1,21 @@ -import {ValidatorResult} from "./validator-result-objects" -import {ValidatorResultInfo} from "../utils"; +import { ValidatorResult } from "./validator-result-objects"; +import { ValidatorResultInfo } from "../utils"; import { BshgError } from "../exceptions"; export class BshValidationError = any> extends BshgError { - readonly results: ValidatorResult + readonly results: ValidatorResult; constructor(results: ValidatorResult) { - super() - this.results = results + super(); + this.results = results; } } export class BshBatchValidationError extends BshgError { - readonly results: ValidatorResultInfo[] + readonly results: ValidatorResultInfo[]; constructor(results: ValidatorResultInfo[]) { - super() - this.results = results + super(); + this.results = results; } } diff --git a/src/validators/results/validator-result-objects.ts b/src/validators/results/validator-result-objects.ts index c784ce9..994bbe6 100644 --- a/src/validators/results/validator-result-objects.ts +++ b/src/validators/results/validator-result-objects.ts @@ -1,4 +1,4 @@ -import {Primitive} from "../utils"; +import { Primitive } from "../utils"; export type ValidatorResult = any> = ValidatorResultObjects | ValidatorResultArrays @@ -22,12 +22,12 @@ export type ValidatorSimpleResult = { export type ValidatorComplexResultObjects> = { [k in keyof T as T[k] extends Primitive - ? never - : T[k] extends infer U | undefined - ? U extends Primitive - ? never - : k - : k]?: ValidatorResultObjects; + ? never + : T[k] extends infer U | undefined + ? U extends Primitive + ? never + : k + : k]?: ValidatorResultObjects; } ////////////////////// diff --git a/src/validators/utils/index.ts b/src/validators/utils/index.ts index 6d31e0e..0c8faef 100644 --- a/src/validators/utils/index.ts +++ b/src/validators/utils/index.ts @@ -1,3 +1,3 @@ -export {regex} from './regex' -export * from './types' -export * from './types-utils' +export { regex } from "./regex"; +export * from "./types"; +export * from "./types-utils"; diff --git a/src/validators/utils/regex.ts b/src/validators/utils/regex.ts index debdcc6..07d4364 100644 --- a/src/validators/utils/regex.ts +++ b/src/validators/utils/regex.ts @@ -13,7 +13,7 @@ export const regex = { CREDIT_CARD: /^(?:3[47]\d{2}([\s-]?)\d{6}\1\d{5}|(?:4\d|5[1-5]|65)\d{2}\d{5}\d{4}|6011([\s-]?)\d{4}\d{4}\d{4})$/, HTML_TAG: /<("[^"]*"|'[^']*'|[^'">])*>/, BASE64: /[^A-Za-z0-9+/=]/, -} +}; export type RegexType = { [k in keyof typeof regex]: RegExp @@ -27,8 +27,8 @@ export const updateRegex = (newRegex: Partial) => { if (newValue != undefined) regex[key as keyof RegexType] = newValue; } else { - LOGGER.warn('updateRegex', true, `Regex key '${key}' does not exist.`); + LOGGER.warn("updateRegex", true, `Regex key '${key}' does not exist.`); } } } -} +}; diff --git a/src/validators/utils/types.ts b/src/validators/utils/types.ts index 66d367d..fa4683f 100644 --- a/src/validators/utils/types.ts +++ b/src/validators/utils/types.ts @@ -1,7 +1,7 @@ -import {Validator, ValidatorTemplate} from '../main'; -import {TypeValidator} from '../validators-fn'; +import { Validator, ValidatorTemplate } from "../main"; +import { TypeValidator } from "../validators-fn"; import { ValidatorResult } from "../results"; -import {TypeValidatorWithContext} from "../validators-fn/base"; +import { TypeValidatorWithContext } from "../validators-fn/base"; import { Primitive } from "./types-utils"; export type BaseValidatorFnConfig = { @@ -36,7 +36,7 @@ export type BatchValidatorResultInfo = { success: boolean, results: ValidatorRes ///////////////// export type ValidatorOptions = { dev?: boolean - resultsType?: 'array' | 'object' // TODO: remove this and replace it with more meaning way ? + resultsType?: "array" | "object" // TODO: remove this and replace it with more meaning way ? } export type ItemType> = { diff --git a/src/validators/v.ts b/src/validators/v.ts index c6b025a..68869c5 100644 --- a/src/validators/v.ts +++ b/src/validators/v.ts @@ -1,30 +1,30 @@ -import {options} from "./options"; -import {Validator, ValidatorTemplate} from "./main"; -import {ValidatorConfig, ValidatorTemplateConfig} from "./utils"; +import { options } from "./options"; +import { Validator, ValidatorTemplate } from "./main"; +import { ValidatorConfig, ValidatorTemplateConfig } from "./utils"; import { LOGGER } from "./logger"; export const validator = , TContext extends Record = any>(config: ValidatorConfig): Validator => { const validator = new Validator(); - const _options = {...options, ...config.options} - validator.options(_options) - validator.config(config) - LOGGER.info('init', _options?.dev, validator) - return validator -} + const _options = { ...options, ...config.options }; + validator.options(_options); + validator.config(config); + LOGGER.info("init", _options?.dev, validator); + return validator; +}; export const template = , TContext extends Record = any>(config: ValidatorTemplateConfig): ValidatorTemplate => { - return new ValidatorTemplate(config) -} + return new ValidatorTemplate(config); +}; export const batchValidate = , TContext extends Record = any>(template: ValidatorTemplate, data: T[]) => { - return template.batchValidate(...data) -} + return template.batchValidate(...data); +}; export const batchValidateThrow = , TContext extends Record = any>(template: ValidatorTemplate, data: T[]) => { - template.batchValidateThrow(...data) -} + template.batchValidateThrow(...data); +}; -export * from './validators-fn'; -export * from './configuration'; -export {regex} from './utils/regex' +export * from "./validators-fn"; +export * from "./configuration"; +export { regex } from "./utils/regex"; diff --git a/src/validators/validators-fn/arrays.ts b/src/validators/validators-fn/arrays.ts index 19dbd43..a0f2df1 100644 --- a/src/validators/validators-fn/arrays.ts +++ b/src/validators/validators-fn/arrays.ts @@ -1,11 +1,11 @@ -import {FnConfig, TypeValidator} from "./base"; -import {CurrentLocalize} from "../messages"; +import { FnConfig, TypeValidator } from "./base"; +import { CurrentLocalize } from "../messages"; -const msgs = () => CurrentLocalize.array +const msgs = () => CurrentLocalize.array; export class Arrays | undefined> extends TypeValidator { undefined(): Arrays { - return new Arrays() + return new Arrays(); } length(length: number, options?: FnConfig): Arrays { @@ -13,7 +13,7 @@ export class Arrays | undefined> extends TypeValidator value !== undefined && value.length !== length, message: msgs().length, options: options, - args: [length] + args: [length], }); } @@ -22,7 +22,7 @@ export class Arrays | undefined> extends TypeValidator value !== undefined && value.length < length, message: msgs().min, options: options, - args: [length] + args: [length], }); } @@ -31,7 +31,7 @@ export class Arrays | undefined> extends TypeValidator value !== undefined && value.length > length, message: msgs().max, options: options, - args: [length] + args: [length], }); } @@ -40,7 +40,7 @@ export class Arrays | undefined> extends TypeValidator array !== undefined && !array.includes(value), message: msgs().has, options: options, - args: [value] + args: [value], }); } @@ -49,7 +49,7 @@ export class Arrays | undefined> extends TypeValidator array !== undefined && !values.every(value => array.includes(value)), message: msgs().hasAll, options: options, - args: [values.join(", ")] + args: [values.join(", ")], }); } @@ -58,7 +58,7 @@ export class Arrays | undefined> extends TypeValidator array !== undefined && values.some(value => array.includes(value)), message: msgs().hasAny, options: options, - args: [values.join(", ")] + args: [values.join(", ")], }); } @@ -67,7 +67,7 @@ export class Arrays | undefined> extends TypeValidator array !== undefined && values.every(value => !array.includes(value)), message: msgs().hasNone, options: options, - args: [values.join(", ")] + args: [values.join(", ")], }); } @@ -75,7 +75,7 @@ export class Arrays | undefined> extends TypeValidator array !== undefined && array.some(predicate), message: msgs().some, - options: options + options: options, }); } @@ -83,7 +83,7 @@ export class Arrays | undefined> extends TypeValidator array !== undefined && array.every(predicate), message: msgs().every, - options: options + options: options, }); } } diff --git a/src/validators/validators-fn/base.ts b/src/validators/validators-fn/base.ts index a85ad28..af51db0 100644 --- a/src/validators/validators-fn/base.ts +++ b/src/validators/validators-fn/base.ts @@ -8,13 +8,12 @@ import { ValidatorFnDependConfigCtx, ValidatorFnDependConfigCtxAsync, } from "../utils"; -import {ValidatorItem} from "../main"; export const messageVars = { - prefix: '%', - value: '%val', - name: '%name' -} + prefix: "%", + value: "%val", + name: "%name", +}; export type FnConfig = { message?: string | (() => string) @@ -37,25 +36,25 @@ type UseDependCreateArgs> = { export const messageArgs = (defaultMsg: string, options?: FnConfig, ...args: any[]) => { const msg = message(defaultMsg, options); return (msg.includes("%") || args?.length > 0) ? msg.replace(/%(\d+)/g, (_, i) => args[i - 1]) : msg; -} +}; export const message = (message: string, options?: FnConfig) => { if (options && options.message) { - return (typeof options.message == "string") ? options.message : options.message() + return (typeof options.message == "string") ? options.message : options.message(); } - return message -} + return message; +}; export class TypeValidator { - validations: ValidatorFnConfig[] = [] - validationsDepend: ValidatorFnDependConfig[] = [] - validationsAsync: ValidatorFnConfigAsync[] = [] - validationsDependAsync: ValidatorFnDependConfigAsync[] = [] + validations: ValidatorFnConfig[] = []; + validationsDepend: ValidatorFnDependConfig[] = []; + validationsAsync: ValidatorFnConfigAsync[] = []; + validationsDependAsync: ValidatorFnDependConfigAsync[] = []; - validationsCtx: ValidatorFnConfigCtx[] = [] - validationsDependCtx: ValidatorFnDependConfigCtx[] = [] - validationsCtxAsync: ValidatorFnConfigCtxAsync[] = [] - validationsDependCtxAsync: ValidatorFnDependConfigCtxAsync[] = [] + validationsCtx: ValidatorFnConfigCtx[] = []; + validationsDependCtx: ValidatorFnDependConfigCtx[] = []; + validationsCtxAsync: ValidatorFnConfigCtxAsync[] = []; + validationsDependCtxAsync: ValidatorFnDependConfigCtxAsync[] = []; /** * add simple validation errors @@ -63,7 +62,7 @@ export class TypeValidator { onError(config: ValidatorFnConfig): this; onError(config: ValidatorFnDependConfig): this; onError(config: ValidatorFnConfig | ValidatorFnDependConfig): this { - if ('error' in config) { + if ("error" in config) { if (config.error.length > 1) { this.validationsDepend.push(config as ValidatorFnDependConfig); } else { @@ -80,7 +79,7 @@ export class TypeValidator { onErrorCtx(config: ValidatorFnConfigCtx): this; onErrorCtx(config: ValidatorFnDependConfigCtx): this; onErrorCtx(config: ValidatorFnConfigCtx | ValidatorFnDependConfigCtx): this { - if ('error' in config) { + if ("error" in config) { if (config.error.length > 2) { this.validationsDependCtx.push(config as ValidatorFnDependConfigCtx); } else { @@ -106,9 +105,9 @@ export class TypeValidator { onErrorAsync(config: ValidatorFnConfigAsync): this; onErrorAsync(config: ValidatorFnDependConfigAsync): this; onErrorAsync(config: ValidatorFnConfigAsync | ValidatorFnDependConfigAsync): this { - if ('error' in config && config.error.length > 1) { + if ("error" in config && config.error.length > 1) { this.validationsDependAsync.push(config as ValidatorFnDependConfigAsync); - } else if ('error' in config) { + } else if ("error" in config) { this.validationsAsync.push(config as ValidatorFnConfigAsync); } return this; @@ -120,23 +119,13 @@ export class TypeValidator { onErrorCtxAsync(config: ValidatorFnConfigCtxAsync): this; onErrorCtxAsync(config: ValidatorFnDependConfigCtxAsync): this; onErrorCtxAsync(config: ValidatorFnConfigCtxAsync | ValidatorFnDependConfigCtxAsync): this { - if ('error' in config && config.error.length > 2) { + if ("error" in config && config.error.length > 2) { this.validationsDependCtxAsync.push(config as ValidatorFnDependConfigCtxAsync); - } else if ('error' in config) { + } else if ("error" in config) { this.validationsCtxAsync.push(config as ValidatorFnConfigCtxAsync); } return this; } - - /** - * build validator for single type (string | number | ...) - */ - // TODO make this works with TypeValidatorWithContext - build(): ValidatorItem { - const vi = new ValidatorItem(); - vi.setValidations(this); - return vi; - } } export type TypeValidatorWithContext> = { diff --git a/src/validators/validators-fn/booleans.ts b/src/validators/validators-fn/booleans.ts index 3a21b4f..24e642e 100644 --- a/src/validators/validators-fn/booleans.ts +++ b/src/validators/validators-fn/booleans.ts @@ -1,12 +1,12 @@ -import {FnConfig, TypeValidator} from "./base"; -import {KeysOfType} from "../utils"; -import {CurrentLocalize} from "../messages"; +import { FnConfig, TypeValidator } from "./base"; +import { KeysOfType } from "../utils"; +import { CurrentLocalize } from "../messages"; -const msgs = () => CurrentLocalize.boolean +const msgs = () => CurrentLocalize.boolean; export class Booleans extends TypeValidator { - undefined(): Booleans{ - return new Booleans() + undefined(): Booleans { + return new Booleans(); } required(options?: FnConfig): Booleans { @@ -21,7 +21,7 @@ export class Booleans extends TypeValid return this.useCostume({ error: value => value !== true, message: msgs().true, - options: options + options: options, }); } @@ -29,7 +29,7 @@ export class Booleans extends TypeValid return this.useCostume({ error: value => value !== false, message: msgs().false, - options: options + options: options, }); } @@ -38,7 +38,7 @@ export class Booleans extends TypeValid error: value => value !== compareValue, message: msgs().equals, options: options, - args: [compareValue] + args: [compareValue], }); } @@ -49,6 +49,6 @@ export class Booleans extends TypeValid message: msgs().as, options: options, args: [key], - }) + }); } } diff --git a/src/validators/validators-fn/dates.ts b/src/validators/validators-fn/dates.ts index e22f026..9382e2e 100644 --- a/src/validators/validators-fn/dates.ts +++ b/src/validators/validators-fn/dates.ts @@ -1,15 +1,15 @@ -import {FnConfig, TypeValidator} from "./base"; -import {KeysOfType} from "../utils"; -import {CurrentLocalize} from "../messages"; +import { FnConfig, TypeValidator } from "./base"; +import { KeysOfType } from "../utils"; +import { CurrentLocalize } from "../messages"; -const msgs = () => CurrentLocalize.date +const msgs = () => CurrentLocalize.date; -const toDate = (date: Date) => date.toISOString().slice(0, 10) -const toTimestamp = (date: Date): number => new Date(date.getFullYear(), date.getMonth(), date.getDate()).valueOf() +const toDate = (date: Date) => date.toISOString().slice(0, 10); +const toTimestamp = (date: Date): number => new Date(date.getFullYear(), date.getMonth(), date.getDate()).valueOf(); export class Dates extends TypeValidator { undefined(): Dates { - return new Dates() + return new Dates(); } required(options?: FnConfig): Dates { @@ -25,7 +25,7 @@ export class Dates extends TypeValidator { error: value => value !== undefined && toTimestamp(value) != toTimestamp(dateTime), message: msgs().equals, options: options, - args: [toDate(dateTime)] + args: [toDate(dateTime)], }); } @@ -34,7 +34,7 @@ export class Dates extends TypeValidator { error: value => value !== undefined && toTimestamp(value) <= toTimestamp(date), message: msgs().after, options: options, - args: [toDate(date)] + args: [toDate(date)], }); } @@ -43,7 +43,7 @@ export class Dates extends TypeValidator { error: value => value !== undefined && toTimestamp(value) >= toTimestamp(date), message: msgs().before, options: options, - args: [toDate(date)] + args: [toDate(date)], }); } @@ -52,7 +52,7 @@ export class Dates extends TypeValidator { error: value => value !== undefined && (toTimestamp(value) < toTimestamp(start) || toTimestamp(value) > toTimestamp(end)), message: msgs().between, options: options, - args: [toDate(start), toDate(end)] + args: [toDate(start), toDate(end)], }); } @@ -62,7 +62,7 @@ export class Dates extends TypeValidator { return this.useCostume({ error: value => value !== undefined && toTimestamp(value) < toTimestamp(today), message: msgs().todayOrAfter, - options: options + options: options, }); } @@ -72,23 +72,23 @@ export class Dates extends TypeValidator { return this.useCostume({ error: value => value !== undefined && toTimestamp(value) > toTimestamp(today), message: msgs().todayOrBefore, - options: options + options: options, }); } past(options?: FnConfig): Dates { - return this.before(new Date(), {...options, message: options?.message || msgs().past}); + return this.before(new Date(), { ...options, message: options?.message || msgs().past }); } future(options?: FnConfig): Dates { - return this.after(new Date(), {...options, message: options?.message || msgs().future}); + return this.after(new Date(), { ...options, message: options?.message || msgs().future }); } weekday(options?: FnConfig): Dates { return this.useCostume({ error: value => value !== undefined && value.getDay() % 6 === 0, // 0 or 6 represent Sunday and Saturday message: msgs().weekday, - options: options + options: options, }); } @@ -96,7 +96,7 @@ export class Dates extends TypeValidator { return this.useCostume({ error: value => value !== undefined && value.getDay() % 6 !== 0, // 1-5 represent Monday to Friday message: msgs().weekend, - options: options + options: options, }); } @@ -108,7 +108,7 @@ export class Dates extends TypeValidator { value.getFullYear() % 400 === 0 ), message: msgs().leapYear, - options: options + options: options, }); } @@ -117,7 +117,7 @@ export class Dates extends TypeValidator { error: value => value !== undefined && toTimestamp(value) !== toTimestamp(date), message: msgs().sameDayAs, options: options, - args: [toDate(date)] + args: [toDate(date)], }); } @@ -128,6 +128,6 @@ export class Dates extends TypeValidator { message: msgs().as, options: options, args: [key], - }) + }); } } diff --git a/src/validators/validators-fn/datetimes.ts b/src/validators/validators-fn/datetimes.ts index 6c67773..f3da074 100644 --- a/src/validators/validators-fn/datetimes.ts +++ b/src/validators/validators-fn/datetimes.ts @@ -1,13 +1,13 @@ -import {FnConfig, TypeValidator} from "./base"; -import {KeysOfType} from "../utils"; -import {CurrentLocalize} from "../messages"; +import { FnConfig, TypeValidator } from "./base"; +import { KeysOfType } from "../utils"; +import { CurrentLocalize } from "../messages"; -const msgs = () => CurrentLocalize.datetime -const toTimestamp = (date: Date): number => new Date(date).valueOf() +const msgs = () => CurrentLocalize.datetime; +const toTimestamp = (date: Date): number => new Date(date).valueOf(); export class DateTimes extends TypeValidator { - undefined(): DateTimes{ - return new DateTimes() + undefined(): DateTimes { + return new DateTimes(); } required(options?: FnConfig): DateTimes { @@ -23,7 +23,7 @@ export class DateTimes extends TypeValidator< error: value => value && toTimestamp(value) != toTimestamp(dateTime), message: msgs().equals, options: options, - args: [dateTime.toISOString()] + args: [dateTime.toISOString()], }); } @@ -32,7 +32,7 @@ export class DateTimes extends TypeValidator< error: value => value && toTimestamp(value) <= toTimestamp(dateTime), message: msgs().after, options: options, - args: [dateTime.toISOString()] + args: [dateTime.toISOString()], }); } @@ -41,7 +41,7 @@ export class DateTimes extends TypeValidator< error: value => value && toTimestamp(value) >= toTimestamp(dateTime), message: msgs().before, options: options, - args: [dateTime.toISOString()] + args: [dateTime.toISOString()], }); } @@ -50,7 +50,7 @@ export class DateTimes extends TypeValidator< error: value => value && (toTimestamp(value) < toTimestamp(start) || toTimestamp(value) > toTimestamp(end)), message: msgs().between, options: options, - args: [start.toISOString(), end.toISOString()] + args: [start.toISOString(), end.toISOString()], }); } @@ -73,18 +73,18 @@ export class DateTimes extends TypeValidator< } past(options?: FnConfig): DateTimes { - return this.before(new Date(), {...options, message: options?.message || msgs().past}); + return this.before(new Date(), { ...options, message: options?.message || msgs().past }); } future(options?: FnConfig): DateTimes { - return this.after(new Date(), {...options, message: options?.message || msgs().future}); + return this.after(new Date(), { ...options, message: options?.message || msgs().future }); } weekday(options?: FnConfig): DateTimes { return this.useCostume({ error: value => value && value.getDay() % 6 === 0, // 0 or 6 represent Sunday and Saturday message: msgs().weekday, - options: options + options: options, }); } @@ -92,7 +92,7 @@ export class DateTimes extends TypeValidator< return this.useCostume({ error: value => value && value.getDay() % 6 !== 0, // 1-5 represent Monday to Friday message: msgs().weekend, - options: options + options: options, }); } @@ -103,6 +103,6 @@ export class DateTimes extends TypeValidator< message: msgs().as, options: options, args: [key], - }) + }); } } diff --git a/src/validators/validators-fn/enums.ts b/src/validators/validators-fn/enums.ts index e9207b8..2cb5b02 100644 --- a/src/validators/validators-fn/enums.ts +++ b/src/validators/validators-fn/enums.ts @@ -1,4 +1,4 @@ -import {FnConfig, TypeValidator} from "./base"; +import { FnConfig, TypeValidator } from "./base"; export class Enums extends TypeValidator { in(values: T[], options?: FnConfig): Enums { @@ -6,7 +6,7 @@ export class Enums extends TypeValidator< error: value => value !== undefined && !values.includes(value), message: `Value must be one of %1`, options: options, - args: [values] + args: [values], }); } @@ -15,7 +15,7 @@ export class Enums extends TypeValidator< error: value => value !== undefined && values.includes(value), message: `Value must not be one of %1`, options: options, - args: [values] + args: [values], }); } @@ -24,7 +24,7 @@ export class Enums extends TypeValidator< error: value => value !== compareValue, message: `Value must be equal to %1`, options: options, - args: [compareValue] + args: [compareValue], }); } @@ -33,7 +33,7 @@ export class Enums extends TypeValidator< error: value => value === compareValue, message: `Value must not be equal to %1`, options: options, - args: [compareValue] + args: [compareValue], }); } } diff --git a/src/validators/validators-fn/index.ts b/src/validators/validators-fn/index.ts index d1c294f..9b48897 100644 --- a/src/validators/validators-fn/index.ts +++ b/src/validators/validators-fn/index.ts @@ -1,45 +1,47 @@ -import {Strings} from "./strings"; -import {Numbers} from "./numbers"; -import {Booleans} from "./booleans"; -import {Dates} from "./dates"; -import {DateTimes} from "./datetimes"; -import {Times} from "./times"; -import {TypeValidator} from "./base"; -import {Arrays} from "./arrays"; - -export {TypeValidator} from './base' +import { Strings } from "./strings"; +import { Numbers } from "./numbers"; +import { Booleans } from "./booleans"; +import { Dates } from "./dates"; +import { DateTimes } from "./datetimes"; +import { Times } from "./times"; +import { TypeValidator, TypeValidatorWithContext } from "./base"; +import { Arrays } from "./arrays"; +import { ValidatorItem } from "../main"; +import { Primitive } from "../utils"; + +export { TypeValidator } from "./base"; export const custom = (): TypeValidator => { - return new TypeValidator() -} + return new TypeValidator(); +}; export const string = (): Strings => { - return new Strings() -} + return new Strings(); +}; export const number = (): Numbers => { - return new Numbers() -} + return new Numbers(); +}; export const boolean = (): Booleans => { - return new Booleans() -} + return new Booleans(); +}; export const date = (): Dates => { - return new Dates() -} + return new Dates(); +}; export const time = (): Times => { - return new Times() -} + return new Times(); +}; export const datetime = (): DateTimes => { - return new DateTimes() -} + return new DateTimes(); +}; export const array = (): Arrays> => { - return new Arrays>() -} + return new Arrays>(); +}; // export const eNum = (): Enums => { // return new Enums() @@ -48,3 +50,14 @@ export const array = (): Arrays> => { // export const object = (): Objects => { // return new Objects() // } + +/** + * build validator for single type (string | number | ...) + */ +export function primitive = any>( + validations: TypeValidator | TypeValidatorWithContext[], +): ValidatorItem { + const vi = new ValidatorItem(); + vi.setValidations(validations); + return vi; +} diff --git a/src/validators/validators-fn/numbers.ts b/src/validators/validators-fn/numbers.ts index bca1a58..06ce383 100644 --- a/src/validators/validators-fn/numbers.ts +++ b/src/validators/validators-fn/numbers.ts @@ -1,12 +1,12 @@ -import {FnConfig, TypeValidator} from "./base"; -import {KeysOfType} from "../utils"; -import {CurrentLocalize} from "../messages"; +import { FnConfig, TypeValidator } from "./base"; +import { KeysOfType } from "../utils"; +import { CurrentLocalize } from "../messages"; -const msgs = () => CurrentLocalize.number +const msgs = () => CurrentLocalize.number; export class Numbers extends TypeValidator { undefined(): Numbers { - return new Numbers() + return new Numbers(); } required(options?: FnConfig): Numbers { @@ -22,7 +22,7 @@ export class Numbers extends TypeValidato error: value => value !== undefined && value < minValue, message: msgs().min, options: options, - args: [minValue] + args: [minValue], }); } @@ -31,7 +31,7 @@ export class Numbers extends TypeValidato error: value => value !== undefined && value > maxValue, message: msgs().max, options: options, - args: [maxValue] + args: [maxValue], }); } @@ -40,7 +40,7 @@ export class Numbers extends TypeValidato error: value => value !== undefined && (value < minValue || value > maxValue), message: msgs().range, options: options, - args: [minValue, maxValue] + args: [minValue, maxValue], }); } @@ -48,23 +48,23 @@ export class Numbers extends TypeValidato return this.useCostume({ error: value => value !== undefined && !Number.isInteger(value), message: msgs().integer, - options: options + options: options, }); } positive(options?: FnConfig): Numbers { - return this.min(0, {...options, message: options?.message || msgs().positive}); + return this.min(0, { ...options, message: options?.message || msgs().positive }); } negative(options?: FnConfig): Numbers { - return this.max(0, {...options, message: options?.message || msgs().negative}); + return this.max(0, { ...options, message: options?.message || msgs().negative }); } decimal(options?: FnConfig): Numbers { return this.useCostume({ error: value => value !== undefined && Number.isInteger(value), message: msgs().decimal, - options: options + options: options, }); } @@ -73,7 +73,7 @@ export class Numbers extends TypeValidato error: value => value !== undefined && value % divisor !== 0, message: msgs().multipleOf, options: options, - args: [divisor] + args: [divisor], }); } @@ -82,7 +82,7 @@ export class Numbers extends TypeValidato error: value => value !== undefined && (value <= minValue || value >= maxValue), message: msgs().betweenExclusive, options: options, - args: [minValue, maxValue] + args: [minValue, maxValue], }); } @@ -90,7 +90,7 @@ export class Numbers extends TypeValidato return this.useCostume({ error: value => value !== undefined && value % 2 !== 0, message: msgs().even, - options: options + options: options, }); } @@ -98,7 +98,7 @@ export class Numbers extends TypeValidato return this.useCostume({ error: value => value !== undefined && value % 2 === 0, message: msgs().odd, - options: options + options: options, }); } @@ -106,7 +106,7 @@ export class Numbers extends TypeValidato return this.useCostume({ error: value => value !== undefined && (!Number.isInteger(value) || value <= 0), message: msgs().positiveInteger, - options: options + options: options, }); } @@ -114,7 +114,7 @@ export class Numbers extends TypeValidato return this.useCostume({ error: value => value !== undefined && (!Number.isInteger(value) || value >= 0), message: msgs().negativeInteger, - options: options + options: options, }); } @@ -122,7 +122,7 @@ export class Numbers extends TypeValidato return this.useCostume({ error: value => value !== undefined && (Number.isInteger(value) || value <= 0), message: msgs().positiveDecimal, - options: options + options: options, }); } @@ -130,7 +130,7 @@ export class Numbers extends TypeValidato return this.useCostume({ error: value => value !== undefined && (Number.isInteger(value) || value >= 0), message: msgs().negativeDecimal, - options: options + options: options, }); } @@ -139,7 +139,7 @@ export class Numbers extends TypeValidato error: value => value !== undefined && !Number.isInteger(value / divisor), message: msgs().divisibleBy, options: options, - args: [divisor] + args: [divisor], }); } @@ -147,7 +147,7 @@ export class Numbers extends TypeValidato return this.useCostume({ error: value => value !== undefined && !Number.isInteger(Math.sqrt(value)), message: msgs().perfectSquare, - options: options + options: options, }); } @@ -161,7 +161,7 @@ export class Numbers extends TypeValidato return false; }, message: msgs().primeNumber, - options: options + options: options, }); } @@ -178,7 +178,7 @@ export class Numbers extends TypeValidato return b !== value; }, message: msgs().fibonacciNumber, - options: options + options: options, }); } @@ -186,7 +186,7 @@ export class Numbers extends TypeValidato return this.useCostume({ error: value => value !== undefined && (value & (value - 1)) !== 0, message: msgs().powerOfTwo, - options: options + options: options, }); } @@ -197,6 +197,6 @@ export class Numbers extends TypeValidato message: msgs().as, options: options, args: [key], - }) + }); } } diff --git a/src/validators/validators-fn/objects.ts b/src/validators/validators-fn/objects.ts index 6d2dee3..0227ab4 100644 --- a/src/validators/validators-fn/objects.ts +++ b/src/validators/validators-fn/objects.ts @@ -1,4 +1,4 @@ -import {TypeValidator} from "./base"; +import { TypeValidator } from "./base"; export class Objects extends TypeValidator { } diff --git a/src/validators/validators-fn/strings.ts b/src/validators/validators-fn/strings.ts index 5dda102..835bdbb 100644 --- a/src/validators/validators-fn/strings.ts +++ b/src/validators/validators-fn/strings.ts @@ -1,12 +1,12 @@ -import {FnConfig, TypeValidator} from "./base"; -import {KeysOfType, regex} from '../utils' -import {CurrentLocalize} from "../messages"; +import { FnConfig, TypeValidator } from "./base"; +import { KeysOfType, regex } from "../utils"; +import { CurrentLocalize } from "../messages"; -const msgs = () => CurrentLocalize.string +const msgs = () => CurrentLocalize.string; export class Strings extends TypeValidator { - undefined(): Strings{ - return new Strings() + undefined(): Strings { + return new Strings(); } required(options?: FnConfig): Strings { @@ -19,9 +19,9 @@ export class Strings extends TypeValidato notEmpty(options?: FnConfig): Strings { return this.useCostume({ - error: value => value !== undefined && value === '', + error: value => value !== undefined && value === "", message: msgs().notEmpty, - options: options + options: options, }); } @@ -30,7 +30,7 @@ export class Strings extends TypeValidato error: value => value !== undefined && value.length < length, message: msgs().min, options: options, - args: [length] + args: [length], }); } @@ -39,7 +39,7 @@ export class Strings extends TypeValidato error: value => value !== undefined && value.length > length, message: msgs().max, options: options, - args: [length] + args: [length], }); } @@ -48,7 +48,7 @@ export class Strings extends TypeValidato error: value => value !== undefined && !value.includes(substring), message: msgs().includes, options: options, - args: [substring] + args: [substring], }); } @@ -57,7 +57,7 @@ export class Strings extends TypeValidato error: value => value !== undefined && !substrings.every(substring => value.includes(substring)), message: msgs().includesAll, options: options, - args: [substrings.join(", ")] + args: [substrings.join(", ")], }); } @@ -66,7 +66,7 @@ export class Strings extends TypeValidato error: value => value !== undefined && !value.startsWith(prefix), message: msgs().startsWith, options: options, - args: [prefix] + args: [prefix], }); } @@ -75,7 +75,7 @@ export class Strings extends TypeValidato error: value => value !== undefined && !value.endsWith(suffix), message: msgs().endsWith, options: options, - args: [suffix] + args: [suffix], }); } @@ -88,51 +88,51 @@ export class Strings extends TypeValidato } email(options?: FnConfig): Strings { - return this.matches(regex.EMAIL, {...options, message: options?.message || msgs().email}) + return this.matches(regex.EMAIL, { ...options, message: options?.message || msgs().email }); } phone(options?: FnConfig): Strings { - return this.matches(regex.PHONE, {...options, message: options?.message || msgs().phone}) + return this.matches(regex.PHONE, { ...options, message: options?.message || msgs().phone }); } url(options?: FnConfig): Strings { - return this.matches(regex.URL, {...options, message: options?.message || msgs().url}); + return this.matches(regex.URL, { ...options, message: options?.message || msgs().url }); } date(options?: FnConfig): Strings { - return this.matches(regex.DATE, {...options, message: options?.message || msgs().date}); + return this.matches(regex.DATE, { ...options, message: options?.message || msgs().date }); } time(options?: FnConfig): Strings { - return this.matches(regex.TIME, {...options, message: options?.message || msgs().time}); + return this.matches(regex.TIME, { ...options, message: options?.message || msgs().time }); } hexColor(options?: FnConfig): Strings { - return this.matches(regex.HEX_COLOR, {...options, message: options?.message || msgs().hexColor}); + return this.matches(regex.HEX_COLOR, { ...options, message: options?.message || msgs().hexColor }); } creditCard(options?: FnConfig): Strings { - return this.matches(regex.CREDIT_CARD, {...options, message: options?.message || msgs().creditCard}); + return this.matches(regex.CREDIT_CARD, { ...options, message: options?.message || msgs().creditCard }); } htmlTag(options?: FnConfig): Strings { - return this.matches(regex.HTML_TAG, {...options, message: options?.message || msgs().htmlTag}); + return this.matches(regex.HTML_TAG, { ...options, message: options?.message || msgs().htmlTag }); } base64(options?: FnConfig): Strings { - return this.matches(regex.BASE64, {...options, message: options?.message || msgs().base64}); + return this.matches(regex.BASE64, { ...options, message: options?.message || msgs().base64 }); } alphanumeric(options?: FnConfig): Strings { - return this.matches(regex.ALPHANUMERIC, {...options, message: options?.message || msgs().alphanumeric}) + return this.matches(regex.ALPHANUMERIC, { ...options, message: options?.message || msgs().alphanumeric }); } numeric(options?: FnConfig): Strings { - return this.matches(regex.NUMERIC, {...options, message: options?.message || msgs().numeric}) + return this.matches(regex.NUMERIC, { ...options, message: options?.message || msgs().numeric }); } alpha(options?: FnConfig): Strings { - return this.matches(regex.ALPHA, {...options, message: options?.message || msgs().alpha}) + return this.matches(regex.ALPHA, { ...options, message: options?.message || msgs().alpha }); } /////TODO add in() to set the allowed values @@ -144,6 +144,6 @@ export class Strings extends TypeValidato message: msgs().as, options: options, args: [key], - }) + }); } } diff --git a/src/validators/validators-fn/times.ts b/src/validators/validators-fn/times.ts index 1c5d103..ecab14f 100644 --- a/src/validators/validators-fn/times.ts +++ b/src/validators/validators-fn/times.ts @@ -1,14 +1,14 @@ -import {FnConfig, TypeValidator} from "./base"; -import {KeysOfType} from "../utils"; -import {CurrentLocalize} from "../messages"; +import { FnConfig, TypeValidator } from "./base"; +import { KeysOfType } from "../utils"; +import { CurrentLocalize } from "../messages"; -const msgs = () => CurrentLocalize.time -const toTimestamp = (date: Date): number => new Date(0, 0, 0, date.getHours(), date.getMinutes(), date.getSeconds()).valueOf() -const toFullTimestamp = (date: Date): number => new Date(date).valueOf() +const msgs = () => CurrentLocalize.time; +const toTimestamp = (date: Date): number => new Date(0, 0, 0, date.getHours(), date.getMinutes(), date.getSeconds()).valueOf(); +const toFullTimestamp = (date: Date): number => new Date(date).valueOf(); export class Times extends TypeValidator { undefined(): Times { - return new Times() + return new Times(); } required(options?: FnConfig): Times { @@ -24,7 +24,7 @@ export class Times extends TypeValidator { error: value => value !== undefined && toTimestamp(value) != toTimestamp(time), message: msgs().equals, options: options, - args: [time.toISOString()] + args: [time.toISOString()], }); } @@ -33,7 +33,7 @@ export class Times extends TypeValidator { error: value => value !== undefined && toTimestamp(value) <= toTimestamp(time), message: msgs().after, options, - args: [time.toTimeString()] + args: [time.toTimeString()], }); } @@ -42,7 +42,7 @@ export class Times extends TypeValidator { error: value => value !== undefined && toTimestamp(value) >= toTimestamp(time), message: msgs().before, options, - args: [time.toTimeString()] + args: [time.toTimeString()], }); } @@ -51,7 +51,7 @@ export class Times extends TypeValidator { error: value => value !== undefined && (toTimestamp(value) < toTimestamp(start) || toTimestamp(value) > toTimestamp(end)), message: msgs().between, options, - args: [start.toTimeString(), end.toTimeString()] + args: [start.toTimeString(), end.toTimeString()], }); } @@ -60,7 +60,7 @@ export class Times extends TypeValidator { return this.useCostume({ error: value => value !== undefined && toTimestamp(value) <= toTimestamp(now), message: msgs().nowOrAfter, - options + options, }); } @@ -69,18 +69,18 @@ export class Times extends TypeValidator { return this.useCostume({ error: value => value !== undefined && toTimestamp(value) >= toTimestamp(now), message: msgs().nowOrBefore, - options + options, }); } past(options?: FnConfig): Times { const now = new Date(); - return this.after(now, {...options, message: options?.message || msgs().past}); + return this.after(now, { ...options, message: options?.message || msgs().past }); } future(options?: FnConfig): Times { const now = new Date(); - return this.before(now, {...options, message: options?.message || msgs().future}); + return this.before(now, { ...options, message: options?.message || msgs().future }); } within24Hours(options?: FnConfig): Times { @@ -92,7 +92,7 @@ export class Times extends TypeValidator { toFullTimestamp(value) > toFullTimestamp(_24HoursFromNow) ), message: msgs().within24Hours, - options + options, }); } @@ -102,6 +102,6 @@ export class Times extends TypeValidator { message: msgs().as, options: options, args: [key], - }) + }); } } diff --git a/tsconfig.json b/tsconfig.json index f057f1a..140ca94 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -4,7 +4,9 @@ "outDir": "../lib", "baseUrl": "./", "paths": { - "@bshg/validation": ["./src"] + "@bshg/validation": [ + "./src" + ] } } }