check-rule-mate 0.4.3 → 0.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,11 +1,18 @@
1
1
  # check-rule-mate
2
- Validate any type of data in JS using your own rules and validations.
2
+ Rule-based, extensible and async-friendly data validation engine for complex forms and business rules.
3
3
 
4
4
  ## Overview
5
5
 
6
- A lightweight and reusable JavaScript "library" for data validation. This library was designed to simplify the process of validating form inputs using flexible rules and error handling. Validating your data by allowing you to define flexible rules, custom error messages, and reusable helper functions—all in a structured format.
6
+ **check-rule-mate** is a lightweight **rule-driven validation engine** for JavaScript.
7
+ Instead of coupling validation logic directly to schemas or fields, check-rule-mate separates concerns into **rules**, **schemas**, **validators**, and **error messages**, allowing you to build **highly reusable**, **composable**, and **context-aware validations**.
7
8
 
8
- The core goal is to provide a **reusable and easy-to-extend** for handling various form inputs, including fields like name, email, birthdate, phone number, and more.
9
+ It is designed for scenarios where traditional schema-based validators start to feel limiting, especially when you need:
10
+
11
+ - Cross-field validation
12
+ - Contextual rules
13
+ - Async checks
14
+ - Reusable validation logic across multiple forms
15
+ - Full control over execution flow and error handling
9
16
 
10
17
 
11
18
  **Github repository:** [check-rule-mate repository](https://github.com/johnrock16/check-rule-mate)
@@ -15,49 +22,76 @@ The core goal is to provide a **reusable and easy-to-extend** for handling vario
15
22
  **Test the core functionalities here:** [check-rule-mate demo](https://johnrock16.github.io/check-rule-mate/)
16
23
  (Note: Creating or modifying custom validators is not supported in the demo, as it requires JavaScript implementation.)
17
24
 
25
+ ## Why check-rule-mate?
18
26
 
19
- ## Features
27
+ Use **check-rule-mate** if you:
28
+ - Need reusable validation logic across different forms and contexts
29
+ - Have complex or conditional validation rules
30
+ - Want full control over how validation runs
31
+ - Need async validations (API calls, database checks, etc.)
32
+ - Prefer rule-driven validation instead of tightly coupled schemas
33
+ - Want clean separation between rules, data, and messages
34
+
35
+
36
+ ## Core Concepts
20
37
 
21
- - **Custom Validation Rules**: Easily define custom rules for form fields.
22
- - **Modular Design**: Separation of rule definitions and error messages for easy management.
23
- - **Easy Integration**: Can be used in any JavaScript environment.
24
- - **Clear Error Handling**: Handles errors and displays messages.
25
- - **Extendable**: Create your custom validators and rules and extend as you want.
38
+ check-rule-mate is built around four main concepts:
26
39
 
27
- ## Advanced Features
40
+ 1. **Rules**: How data is validated
41
+ 2. **Schema**: What should be validated
42
+ 3. **Validation Helpers**: How rules are executed
43
+ 4. **Error Messages**: How errors are communicated
28
44
 
29
- - **Modifiers:** Extend rules for specific use cases (e.g., age validation in a date rule).
30
- - **Dynamic Parameters:** Use $variable to access field data within rules.
31
- - **Modular Rules and Validators:** Create multiple files for rules and helpers, organizing them by context or form.
32
- - **Async Validations:** You could create async functions to validate some data. Do You need to use a fetch or wait a promise to be resolved? No problems.
45
+ This separation makes the system flexible, scalable, and easy to maintain.
46
+
47
+ ## Features
48
+
49
+ - Rule-based validation engine
50
+ - Reusable validation rules
51
+ - Modifiers for contextual rule extensions
52
+ - Cross-field validation using dynamic parameters
53
+ - Async validation support
54
+ - Abort early or collect all errors
55
+ - Strict or loose schema matching
56
+ - i18n-ready error messages
57
+ - Framework-agnostic (frontend or backend)
33
58
 
34
59
  ## Table of Contents
35
60
 
36
61
  - [Getting Started](#Getting-Started)
37
- - [Installation](#Installation)
38
- - [Running Tests](#Running-Tests)
62
+ - [NPM - Installation](#Installation)
63
+ - [Repository - Installation](#Repository---Installation)
64
+ - [Running Tests](#Repository---Running-Tests)
39
65
  - [How It Works](#How-It-Works)
40
- - [Basic Example](#Basic-Example)
41
- - [Defining Validation Components](#Defining-Validation-Components)
42
- - [1. Data Rules](#Data-Rules)
43
- - [2. General Rules](#General-Rules)
44
- - [3. Validation Helpers](#Validation-Helpers)
45
- - [4. Error Messages](#Error-Messages)
66
+ - [Basic Usage](#Basic-Usage)
67
+ - [Defining Validation](#Defining-Validation)
68
+ - [1. Schema](#Defining-a-Schema-What-to-validate)
69
+ - [2. Rules](#Defining-Rules-How-to-validate)
70
+ - [3. Validation Helpers](#Validation-Helpers-Execution-Layer)
71
+ - [4. Error Messages](#Error-Messages-i18n-ready)
46
72
  - [5. Example Usage](#Example-Usage)
47
73
  - [Vanilla](#vanilla)
48
74
  - [Express](#express)
49
75
  - [Frontend](#frontend)
76
+ - [When NOT to use check-rule-mate](#When-NOT-to-use-check-rule-mate)
77
+ - [License](#License);
50
78
 
51
79
  ## Getting Started
80
+
52
81
  ### Installation
82
+ If you are in NPM use this:
83
+ ```bash
84
+ npm install check-rule-mate
85
+ ```
53
86
 
54
- To install and start the library, run:
87
+ ### Repository - Installation
88
+ If you downloaded the repository you can install using:
55
89
  ```bash
56
90
  npm install
57
91
  npm start
58
92
  ```
59
93
 
60
- ### Running Tests
94
+ ### Repository - Running Tests
61
95
 
62
96
  Execute the test suite with:
63
97
  ```bash
@@ -65,69 +99,108 @@ npm test
65
99
  ```
66
100
 
67
101
  ## How It Works
68
- ### Basic Example
102
+ ### Basic Usage
69
103
 
70
- Here’s an example of validating a set of fields:
71
104
  ```javascript
72
- const { myValidator } = require('./dataValidator/validators');
73
- const { dataValidate } = require('./dataValidator/dataValidate');
74
- const MY_RULES = require('./dataValidator/rules/validators/myValidatorRules.json');
75
- const CONTACT_US = require('./dataValidator/rules/data/contactUs.json');
76
- const MY_VALIDATION_ERROR_MESSAGES = require('./i18n/en_US/errors/myValidatorRules.json');
77
-
78
- async function runDataValidate() {
79
- const fields = {
80
- name: "John",
81
- lastName: "Doe",
82
- email: "email@email.com",
83
- emailConfirm: "email@email.com",
84
- phone: "",
85
- subject: "I need a coffee",
86
- message: "Give me coffee"
87
- };
88
-
89
- // This should return { ok: true }
90
- const result = await dataValidate(fields, {
91
- validationHelpers: myValidator,
92
- rules: MY_RULES,
93
- dataRule: CONTACT_US,
94
- dataErrorMessages: MY_VALIDATION_ERROR_MESSAGES,
95
- });
96
-
97
- console.log(result);
98
- }
105
+ import MY_RULES from './rules/myValidatorRules.json' with { type: 'json' };
106
+ import CONTACT_US from './schemas/contactUs.json' with { type: 'json' };
107
+ import ERROR_MESSAGES from './i18n/en_US/errors.json' with { type: 'json' };
108
+
109
+ import { createValidator } from 'check-rule-mate';
110
+ import { myValidator } from './validators/myValidator.js';
111
+
112
+ const fields = {
113
+ name: 'John',
114
+ lastName: 'Doe',
115
+ email: 'email@email.com',
116
+ emailConfirm: 'email@email.com',
117
+ phone: '',
118
+ subject: 'I need a coffee',
119
+ message: 'Give me coffee'
120
+ };
121
+
122
+ async function runFormValidate() {
123
+ const validator = createValidator(fields, {
124
+ validationHelpers: myValidator,
125
+ rules: MY_RULES,
126
+ schema: CONTACT_US,
127
+ errorMessages: ERROR_MESSAGES,
128
+ options: {
129
+ cache: true,
130
+ abortEarly: false,
131
+ propertiesMustMatch: true,
132
+ }
133
+ });
134
+
135
+ const result = await validator.validate();
99
136
 
100
- runDataValidate();
137
+ // This should return { ok: true }
138
+ console.log(result);
139
+ }
140
+
141
+ runFormValidate();
101
142
  ```
102
143
 
103
- #### Parameters for dataValidate:
144
+ ### Validation Result
145
+ A validation result follows this structure:
146
+
147
+ When is **valid**:
148
+ ```javascript
149
+ { ok: true }
150
+ ```
151
+
152
+ When is **invalid** and **has errors**:
153
+ ```typescript
154
+ {
155
+ error: true,
156
+ errors: {
157
+ [field: string]: {
158
+ name: string,
159
+ type: string,
160
+ message: string,
161
+ code: string,
162
+ }[];
163
+ };
164
+ }
165
+ ```
104
166
 
105
- - **fields**: The object containing data to be validated.
106
- - **validationHelpers**: Functions to validate field data (see /dataValidator/validators).
107
- - **rules**: General validation rules for your application.
108
- - **dataRule**: Specific rules linking fields to validation logic.
109
- - **dataErrorMessages**: Custom error messages returned upon validation failure.
110
167
 
111
- ## Defining Validation Components
168
+ ## Defining Validation
112
169
 
113
- ### Data Rules
170
+ ### Defining a Schema (What to validate)
114
171
 
115
- Define rules for specific datasets, such as forms. Example for a "Contact Us" form:
172
+ Schemas map **data fields** to **rules**.
116
173
  ```json
117
174
  {
118
- "name": { "rule": "name", "required": true },
119
- "lastName": { "rule": "name", "required": true },
120
- "email": { "rule": "email", "required": true },
121
- "emailConfirm": { "rule": "email--confirm", "required": true },
122
- "phone": { "rule": "phone", "required": false },
123
- "subject": { "rule": "hasText", "required": true },
124
- "message": { "rule": "hasText", "required": true }
175
+ "name": {
176
+ "rule": "name",
177
+ "required": true
178
+ },
179
+ "email": {
180
+ "rule": "email",
181
+ "required": true,
182
+ "cache": false,
183
+ },
184
+ "emailConfirm": {
185
+ "rule": "email--confirm",
186
+ "required": true,
187
+ "cache": false,
188
+ },
189
+ "phone": {
190
+ "rule": "phone",
191
+ "required": false
192
+ }
125
193
  }
126
194
  ```
127
195
 
128
- ### General Rules
196
+ #### Schema Properties
197
+ - **rule**: Rule name (supports modifiers via `rule--modifier`)
198
+ - **required**: Whether the field must exist and not be empty
199
+ - **cache**: if this field will have cache or not
200
+
201
+ ### Defining Rules (How to validate)
129
202
 
130
- Define reusable validation logic. Example:
203
+ Rules define validation logic, independent of any specific form.
131
204
 
132
205
  ```json
133
206
  {
@@ -169,17 +242,53 @@ Define reusable validation logic. Example:
169
242
  }
170
243
  }
171
244
  ```
172
- #### Key Components:
173
245
 
174
- - **validate**: Array of functions to execute for validation.
175
- - **error**: Error messages for validation failures.
176
- - **regex**: Regular expression for validation.
177
- - **modifier**: Overrides specific rules with additional validations.
178
- - **params**: Parameters for validation functions (e.g., $email accesses email field data).
246
+ #### Rule Properties
247
+
248
+ - **validate**: Ordered list of validation functions
249
+ - **regex**: Optional regex used by the regex helper
250
+ - **error**: Error keys mapped to validation functions
251
+ - **modifier**: Contextual rule extensions
252
+ - **params**: Parameters passed to validation helpers
253
+
254
+ #### Modifiers (Contextual Rules)
255
+ Modifiers allow extending a rule **without duplicating logic**.
256
+
257
+ Example:
258
+ ```json
259
+ "email--confirm"
260
+ ```
261
+
262
+ Internally:
263
+
264
+ - Base rule: email
265
+ - Modifier: confirm
266
+
267
+ Modifiers can override:
268
+
269
+ - validate
270
+ - params
271
+ - regex
272
+ - error
273
+
274
+ This makes rules highly reusable and expressive.
275
+
276
+ #### Dynamic Parameters ($field)
277
+ Rules can reference other fields dynamically:
278
+
279
+ ```json
280
+ "params": {
281
+ "equals": ["$email"]
282
+ }
283
+ ```
284
+
285
+ At runtime:
286
+ - `$email` resolves to `data.email`
287
+ - Enables **cross-field validation**
179
288
 
180
289
 
181
- ### Validation Helpers
182
- Helper functions perform actual validation. Example:
290
+ ### Validation Helpers (Execution Layer)
291
+ Validation helpers are the **runtime implementation** of rules.
183
292
 
184
293
  ```javascript
185
294
  const myValidator = function (value, rule, modifier = null, data = null) {
@@ -219,13 +328,37 @@ const myValidator = function (value, rule, modifier = null, data = null) {
219
328
  };
220
329
  ```
221
330
 
222
- ### Error Messages
331
+ #### Helper Signature
332
+ ```typescript
333
+ (value, rule, modifier?, data?) => Record<string, Function>
334
+ ```
335
+
336
+ Helpers:
337
+ - Can be **sync or async**
338
+ - Are **stateless**
339
+ - Do not know about schemas or error messages
223
340
 
224
- Define custom error messages in a structured format:
341
+ ### Error Messages (i18n-ready)
342
+ Errors are resolved via keys, not hardcoded strings.
225
343
  ``` json
226
344
  {
227
- "common": { "hasText": "Please fill out this field." },
228
- "email": { "regex": "Enter a valid email address." }
345
+ "common": {
346
+ "hasText": "Please fill the field"
347
+ },
348
+ "email": {
349
+ "regex": "Please enter a valid email",
350
+ "equals": "Emails do not match"
351
+ }
352
+ }
353
+ ```
354
+ This makes localization and message customization straightforward.
355
+
356
+ ### Validation Options
357
+ ```typescript
358
+ options: {
359
+ cache?: boolean, // If cache is enabled or not
360
+ abortEarly?: boolean, // Stop on first error
361
+ propertiesMustMatch?: boolean, // Schema vs data strictness
229
362
  }
230
363
  ```
231
364
 
@@ -270,3 +403,12 @@ npm run example:express
270
403
  Here you can found the DEMO page and it's a type of "playground" to test how RULES works and validations works. (Here you can't create customized javascript so custom validatorHelpers are disabled by default)
271
404
 
272
405
  **Frontend example:** [check-rule-mate demo.](https://johnrock16.github.io/check-rule-mate/)
406
+
407
+
408
+ ## When NOT to use check-rule-mate
409
+ - Simple one-off forms
410
+ - Basic required-only validation
411
+ - When schema-based validation is enough
412
+
413
+ ## License
414
+ - ISC
package/dist/main.cjs.js CHANGED
@@ -1 +1 @@
1
- var h=Object.defineProperty;var w=Object.getOwnPropertyDescriptor;var R=Object.getOwnPropertyNames;var M=Object.prototype.hasOwnProperty;var O=(n,s)=>{for(var o in s)h(n,o,{get:s[o],enumerable:!0})},b=(n,s,o,i)=>{if(s&&typeof s=="object"||typeof s=="function")for(let u of R(s))!M.call(n,u)&&u!==o&&h(n,u,{get:()=>s[u],enumerable:!(i=w(s,u))||i.enumerable});return n};var q=n=>b(h({},"__esModule",{value:!0}),n);var P={};O(P,{dataValidate:()=>V});module.exports=q(P);function V(n,{validationHelpers:s={},rules:o,dataRule:i,dataErrorMessages:u={}}){let y={};function g(e,f){if(!e||typeof f!="string")return;let l=f.split("."),t=e;for(let c of l){if(t[c]===void 0)return;t=t[c]}return t}async function a(e,f=null){let{rule:l,required:t}=i[e.key];if((l&&t||!t&&e.value!="")&&l){let c=l.split("--")[0],r=l.split("--").length>1?l.split("--")[1]:"",m=E(e.value,o[c],r,s,f),{isValid:p,errorMessage:v,errorType:k}=await m.validate();return p||(y[e.key]={name:e.key,error:!0,errorMessage:g(u,v)||v,errorType:k}),p}return!0}async function d(){let e=Object.keys(n).map(f=>({key:f,value:n[f]}));if(e&&e.length>0){if(!Object.keys(i).every(r=>n.hasOwnProperty(r)))return{error:!0,errorMessage:"Missing properties"};if((await Promise.all([...e].map(async r=>await a(r,n)))).some(r=>!r))return{error:!0,dataErrors:y};let l=Object.keys(i).map(r=>({key:r,required:i[r].required})),t=e.map(r=>r.key);if(!l.filter(r=>r.required).map(r=>r.key).every(r=>t.includes(r)))return{error:!0}}else if(!e||e.length===0)return{error:!0,errorMessage:"Missing fields for dataRules"};return{ok:!0}}return d()}function E(n,s,o=null,i=null,u=null){async function y(a){let d,e;return{isValid:!(await Promise.all(a.validate.map(async t=>{let c=!0;if(a.params&&a.params[t]&&a.params[t].length>0){let r=a.params[t].map(p=>typeof p=="string"&&p[0]==="$"?p.substring(1,p.length):p);c=await this[t](...r)}else c=await this[t]();return!c&&!d&&(a!=null&&a.error[t])&&(d=a.error[t],e=t),c}))).some(t=>!t),errorMessage:d,errorType:e}}async function g(){if(i&&typeof i=="function"){let d=i(n,s,o,u);Object.keys(d).forEach(e=>{this[e]=d[e]})}return o?await y.call(this,s.modifier[o]):await y.call(this,s)}return{validate:g}}0&&(module.exports={dataValidate});
1
+ var V=Object.defineProperty;var j=Object.getOwnPropertyDescriptor;var D=Object.getOwnPropertyNames;var T=Object.prototype.hasOwnProperty;var U=(r,n)=>{for(var u in n)V(r,u,{get:n[u],enumerable:!0})},F=(r,n,u,i)=>{if(n&&typeof n=="object"||typeof n=="function")for(let y of D(n))!T.call(r,y)&&y!==u&&V(r,y,{get:()=>n[y],enumerable:!(i=j(n,y))||i.enumerable});return r};var L=r=>F(V({},"__esModule",{value:!0}),r);var x={};U(x,{createValidator:()=>E});module.exports=L(x);var m={propertiesMustMatch:!0,abortEarly:!1,cache:!0};function E(r,{validationHelpers:n={},rules:u,schema:i,errorMessages:y={},options:f=m}){f={...m,...f},r=r;let k={},a={},p={all:async e=>Promise.all([...e].map(async s=>await v(s,r))),first:async e=>{let s=[];for(let l of e){let c=await v(l,r);if(s.push(c),!c)return s}return s}};function g(e,s){if(!e||typeof s!="string")return;let l=s.split("."),c=e;for(let d of l){if(c[d]===void 0)return;c=c[d]}return c}async function v(e,s=null){var l,c;if(i[e.key]){let{rule:d,required:t}=i[e.key];if((((l=i[e.key])==null?void 0:l.cache)!==void 0?i[e.key].cache:f.cache)&&s[e.key]===((c=a[e.key])==null?void 0:c.value))return a[e.key].isValid;if((d&&t||!t&&e.value!="")&&d){let O=d.split("--")[0],q=d.split("--").length>1?d.split("--")[1]:"",P=_(e.value,u[O],q,n,s),{isValid:w,errorMessage:R,errorType:I}=await P.validate();return w||(k[e.key]={name:e.key,code:R,type:I,message:g(y,R)||""}),a[e.key]={isValid:w,value:s[e.key]},w}}else if(f.propertiesMustMatch)return k[e.key]={name:e.key,message:"Invalid property"},!1;return!0}async function M(e){return await v({key:e,value:r[e]},r)?{ok:!0}:{error:!0,errors:k[e]}}async function o(){k={};let e=Object.keys(r).map(s=>({key:s,value:r[s]}));if(e&&e.length>0){if(!Object.keys(i).every(t=>r.hasOwnProperty(t)))return{error:!0,errorMessage:"Missing properties"};if((f!=null&&f.abortEarly?await p.first(e):await p.all(e)).some(t=>!t))return{error:!0,errors:k};let l=Object.keys(i).map(t=>({key:t,required:i[t].required})),c=e.map(t=>t.key);if(!l.filter(t=>t.required).map(t=>t.key).every(t=>c.includes(t)))return{error:!0}}else if(!e||e.length===0)return{error:!0,errorMessage:"Missing fields for schema"};return{ok:!0}}function h(e){r=e}return{validate:o,validateField:M,setData:h}}function _(r,n,u=null,i=null,y=null){async function f(a){let p,g;return{isValid:!(await Promise.all(a.validate.map(async o=>{let h=!0;if(a.params&&a.params[o]&&a.params[o].length>0){let e=a.params[o].map(l=>typeof l=="string"&&l[0]==="$"?l.substring(1,l.length):l);h=await this[o](...e)}else h=await this[o]();return!h&&!p&&(a!=null&&a.error[o])&&(p=a.error[o],g=o),h}))).some(o=>!o),errorMessage:p,errorType:g}}async function k(){if(i&&typeof i=="function"){let p=i(r,n,u,y);Object.keys(p).forEach(g=>{this[g]=p[g]})}return u?await f.call(this,n.modifier[u]):await f.call(this,n)}return{validate:k}}0&&(module.exports={createValidator});
package/package.json CHANGED
@@ -1,10 +1,22 @@
1
1
  {
2
2
  "name": "check-rule-mate",
3
- "version": "0.4.3",
3
+ "version": "0.5.1",
4
4
  "description": "",
5
5
  "main": "./dist/main.cjs.js",
6
6
  "type": "commonjs",
7
- "keywords": ["data validation", "data validation js", "validator", "validate", "form validator", "form validator js", "form validate", "check-rule-mate", "check rule", "check rule mate"],
7
+ "types": "index.d.ts",
8
+ "keywords": [
9
+ "data validation",
10
+ "data validation js",
11
+ "validator",
12
+ "validate",
13
+ "form validator",
14
+ "form validator js",
15
+ "form validate",
16
+ "check-rule-mate",
17
+ "check rule",
18
+ "check rule mate"
19
+ ],
8
20
  "scripts": {
9
21
  "start": "node ./examples/vanilla/src/index.js",
10
22
  "build": "node build",
@@ -15,7 +27,7 @@
15
27
  "author": "João Rocha",
16
28
  "license": "ISC",
17
29
  "devDependencies": {
18
- "esbuild": "^0.24.0",
30
+ "esbuild": "^0.27.2",
19
31
  "express": "^4.21.2",
20
32
  "jest": "^29.7.0"
21
33
  }
package/src/index.d.ts ADDED
@@ -0,0 +1,128 @@
1
+ /**
2
+ * This file contains all type definitions used in the project.
3
+ */
4
+
5
+ /**
6
+ * Represents a single data field.
7
+ */
8
+ export interface DataField {
9
+ /** The name and key of the field */
10
+ name: string
11
+
12
+ /** The value of the field */
13
+ value: string
14
+ }
15
+
16
+ /**
17
+ * Options to control validator behavior.
18
+ */
19
+ export interface ValidatorOptions {
20
+ /** If the form fields don't match the expected structure, triggers an error */
21
+ propertiesMustMatch: boolean
22
+
23
+ /** Stops validation when the first error is caught */
24
+ abortEarly: boolean
25
+
26
+ /** Defines if the schema will use cache by default */
27
+ cache: boolean
28
+ }
29
+
30
+ /**
31
+ * A single validation helper function.
32
+ */
33
+ export type ValidatorHelper = (
34
+ value: any,
35
+ rule: string,
36
+ modifier: string,
37
+ data: DataField[]
38
+ ) => boolean
39
+
40
+ /**
41
+ * A map of validation helper functions.
42
+ */
43
+ export type ValidationHelpers = Record<string, ValidatorHelper>
44
+
45
+ /**
46
+ * Schema rule for a single field.
47
+ */
48
+ export interface SchemaRuleField {
49
+ /** The validation rule for the field (e.g., "name", "email", "phone", "hasText") */
50
+ rule: string
51
+
52
+ /** Indicates whether the field is required */
53
+ required: boolean
54
+
55
+ /** Indicates if the field requires cache or not */
56
+ cache: boolean
57
+ }
58
+
59
+ /**
60
+ * Schema rule object.
61
+ */
62
+ export interface SchemaRule {
63
+ field: SchemaRuleField
64
+ }
65
+
66
+ /**
67
+ * Validation schema mapping field names to rules.
68
+ */
69
+ export type SchemaRules = Record<string, SchemaRule>
70
+
71
+ /**
72
+ * Validator configuration object.
73
+ */
74
+ export interface DataValidatorConfigs {
75
+ /** The validator functions to help your validations */
76
+ validationHelpers: ValidationHelpers
77
+
78
+ /** The rules you want to use through validation */
79
+ rules: object
80
+
81
+ /** The rules you want to use per field */
82
+ schema: SchemaRules
83
+
84
+ /** The error messages you want to show during errors */
85
+ errorMessages: object
86
+
87
+ /** Validator options */
88
+ options: ValidatorOptions
89
+ }
90
+
91
+ /**
92
+ * Represents a successful response.
93
+ */
94
+ export interface DataValidatorSuccessResponse {
95
+ /** Indicates the operation was successful */
96
+ ok: boolean
97
+ }
98
+
99
+ /**
100
+ * Error object.
101
+ */
102
+ export interface CheckError {
103
+ /** Field name */
104
+ name: string
105
+
106
+ /** Error path */
107
+ code?: string
108
+
109
+ /** Error type */
110
+ type?: string
111
+
112
+ /** Error message */
113
+ message?: string
114
+ }
115
+
116
+ /**
117
+ * Represents an error response.
118
+ */
119
+ export interface DataValidatorErrorResponse {
120
+ /** Indicates an error occurred */
121
+ error: boolean
122
+
123
+ /** A message describing the error */
124
+ errorMessage?: string
125
+
126
+ /** Additional error details */
127
+ errors?: Record<string, CheckError>
128
+ }
@@ -1,11 +1,30 @@
1
+ const DEFAUL_OPTIONS = { propertiesMustMatch: true, abortEarly: false, cache: true };
2
+
1
3
  /**
2
4
  * Validate your data fields using your rules, data rules and validators.
3
5
  * @param {[DataField]} data - All the data fields to be validate
4
6
  * @param {DataValidatorConfigs} config - The configs which will be followed during validation
5
- * @returns {DataValidatorSuccessResponse | DataValidatorErrorResponse} - The response of your validation
6
7
  */
7
- export function dataValidate(data, {validationHelpers = {}, rules, dataRule, dataErrorMessages = {}}) {
8
- const dataErrors = {};
8
+ export function createValidator(data, {validationHelpers = {}, rules, schema, errorMessages = {}, options = DEFAUL_OPTIONS}) {
9
+ options = { ...DEFAUL_OPTIONS, ...options};
10
+ data = data;
11
+ let errors = {};
12
+ let oldData = {};
13
+
14
+ const validateByStrategies = {
15
+ all: async (dataArr) => Promise.all([...dataArr].map(async (input) => await inputValidation(input, data))),
16
+ first: async (dataArr) => {
17
+ const results = []
18
+ for (const input of dataArr) {
19
+ const result = await inputValidation(input, data);
20
+ results.push(result);
21
+ if (!result) {
22
+ return results
23
+ }
24
+ }
25
+ return results;
26
+ }
27
+ };
9
28
 
10
29
  function getObjectValueByPath(obj, path) {
11
30
  if (!obj || typeof path !== 'string') return undefined;
@@ -22,41 +41,73 @@ export function dataValidate(data, {validationHelpers = {}, rules, dataRule, dat
22
41
  }
23
42
 
24
43
  async function inputValidation(dataAttribute, data = null) {
25
- const { rule, required } = dataRule[dataAttribute.key];
26
-
27
- if ((rule && required) || (!required && dataAttribute.value != '')) {
28
- if (rule) {
29
- const INPUT_RULE = rule.split('--')[0];
30
- const RULE_MODIFIER = rule.split('--').length > 1 ? rule.split('--')[1] : '';
31
- const dataAttributeValidation = dataAttributeValidator(dataAttribute.value, rules[INPUT_RULE], RULE_MODIFIER, validationHelpers, data);
32
- const { isValid, errorMessage, errorType } = await dataAttributeValidation.validate();
33
- if (!isValid) {
34
- dataErrors[dataAttribute.key] = {
35
- name: dataAttribute.key,
36
- error: true,
37
- errorMessage: getObjectValueByPath(dataErrorMessages, errorMessage) || errorMessage,
38
- errorType: errorType
44
+ if (schema[dataAttribute.key]) {
45
+ const { rule, required } = schema[dataAttribute.key];
46
+ const cacheEnabled = schema[dataAttribute.key]?.cache !== undefined ? schema[dataAttribute.key].cache : options.cache;
47
+
48
+ if (cacheEnabled && data[dataAttribute.key] === oldData[dataAttribute.key]?.value) {
49
+ return oldData[dataAttribute.key].isValid;
50
+ }
51
+
52
+ if ((rule && required) || (!required && dataAttribute.value != '')) {
53
+ if (rule) {
54
+ const INPUT_RULE = rule.split('--')[0];
55
+ const RULE_MODIFIER = rule.split('--').length > 1 ? rule.split('--')[1] : '';
56
+ const dataAttributeValidation = dataAttributeValidator(dataAttribute.value, rules[INPUT_RULE], RULE_MODIFIER, validationHelpers, data);
57
+ const { isValid, errorMessage, errorType } = await dataAttributeValidation.validate();
58
+ if (!isValid) {
59
+ errors[dataAttribute.key] = {
60
+ name: dataAttribute.key,
61
+ code: errorMessage,
62
+ type: errorType,
63
+ message: getObjectValueByPath(errorMessages, errorMessage) || ''
64
+ }
39
65
  }
66
+ oldData[dataAttribute.key] = {isValid: isValid, value: data[dataAttribute.key]};
67
+ return isValid;
40
68
  }
41
- return isValid;
42
69
  }
70
+ } else if (options.propertiesMustMatch) {
71
+ errors[dataAttribute.key] = {
72
+ name: dataAttribute.key,
73
+ message: "Invalid property"
74
+ }
75
+ return false;
43
76
  }
44
77
  return true;
45
78
  }
46
79
 
80
+ /**
81
+ * Validate only a field using the attribute key
82
+ * @param {string} key - The field key name you want to validate
83
+ * @returns {DataValidatorSuccessResponse | DataValidatorErrorResponse} - The response of your validation
84
+ */
85
+ async function validateField(key) {
86
+ const result = await inputValidation({key: key, value: data[key]}, data);
87
+ if (!result) {
88
+ return { error: true, errors: errors[key]}
89
+ }
90
+ return { ok: true}
91
+ }
92
+
93
+ /**
94
+ * Validate the entire fields using the schema
95
+ * @returns {DataValidatorSuccessResponse | DataValidatorErrorResponse} - The response of your validation
96
+ */
47
97
  async function validate() {
98
+ errors = {};
48
99
  let dataArr = Object.keys(data).map((key) => ({ key, value: data[key] }));
49
100
  if (dataArr && dataArr.length > 0) {
50
- if(!Object.keys(dataRule).every((key) => data.hasOwnProperty(key))) {
101
+ if(!Object.keys(schema).every((key) => data.hasOwnProperty(key))) {
51
102
  return { error: true, errorMessage: "Missing properties"}
52
103
  }
53
- const dataValidators = await Promise.all([...dataArr].map(async (input) => await inputValidation(input, data)));
104
+ const dataValidators = options?.abortEarly ? await validateByStrategies.first(dataArr) : await validateByStrategies.all(dataArr);
54
105
 
55
106
  if (dataValidators.some((element) => !element)) {
56
- return { error: true, dataErrors: dataErrors };
107
+ return { error: true, errors: errors };
57
108
  }
58
109
 
59
- const dataRuleArr = Object.keys(dataRule).map((key) => ({ key, required: dataRule[key].required}));
110
+ const dataRuleArr = Object.keys(schema).map((key) => ({ key, required: schema[key].required}));
60
111
  const dataAttributesKey = dataArr.map((attribute) => attribute.key);
61
112
  const dataAttributesRequired = dataRuleArr.filter((rule) => rule.required).map((rule) => rule.key);
62
113
 
@@ -64,12 +115,16 @@ export function dataValidate(data, {validationHelpers = {}, rules, dataRule, dat
64
115
  return { error: true };
65
116
  }
66
117
  } else if (!dataArr || dataArr.length === 0) {
67
- return { error: true, errorMessage: "Missing fields for dataRules"}
118
+ return { error: true, errorMessage: "Missing fields for schema"}
68
119
  }
69
120
  return { ok: true };
70
121
  }
71
122
 
72
- return validate();
123
+ function setData(newData) {
124
+ data = newData;
125
+ }
126
+
127
+ return {validate, validateField, setData};
73
128
  }
74
129
 
75
130
  /**
package/src/main.js CHANGED
@@ -1,5 +1,5 @@
1
- import { dataValidate } from './js/dataValidate.js';
1
+ import { createValidator } from './js/dataValidate.js';
2
2
 
3
3
  export {
4
- dataValidate,
4
+ createValidator,
5
5
  }
package/src/types.js CHANGED
@@ -6,15 +6,23 @@
6
6
  /**
7
7
  * @typedef {Object} DataField
8
8
  * @property {string} name - The name and key of the field
9
- * @property {string} value - the value of the field
9
+ * @property {any} value - the value of the field
10
10
  */
11
11
 
12
12
  /**
13
13
  * @typedef {Object} DataValidatorConfigs
14
14
  * @property {ValidationHelpers} validationHelpers - The validator functions to help your validations
15
15
  * @property {Object} rules - The rules you want to use through validation
16
- * @property {dataRule} dataRule - The rules you want to use per field
17
- * @property {Object} dataErrorMessages - The error messages you want to show during errors
16
+ * @property {SchemaRule} schema - The rules you want to use per field
17
+ * @property {Object} errorMessages - The error messages you want to show during errors
18
+ * @property {ValidatorOptions} options - Options
19
+ */
20
+
21
+ /**
22
+ * @typedef {Object} ValidatorOptions
23
+ * @property {boolean} propertiesMustMatch - If the form fields doesn't match with the expected structure will triggers an error
24
+ * @property {boolean} abortEarly - Stops when caughts the first error
25
+ * @property {boolean} cache - Defines if the schema will uses cache as default or not
18
26
  */
19
27
 
20
28
  /**
@@ -31,18 +39,19 @@
31
39
  */
32
40
 
33
41
  /**
34
- * @typedef {Object} DataRule
35
- * @property {dataRuleFiVeld} field - The field which will use the rule
42
+ * @typedef {Object} SchemaRule
43
+ * @property {SchemaRuleField} field - The field which will use the rule
36
44
  */
37
45
 
38
46
  /**
39
- * @typedef {Object} DataRuleField
47
+ * @typedef {Object} SchemaRuleField
40
48
  * @property {string} rule - The validation rule for the field (e.g., "name", "email", "phone", "hasText").
41
49
  * @property {boolean} required - Indicates whether the field is required.
50
+ * @property {boolean} cache - Indicates if the field requires cache or not
42
51
  */
43
52
 
44
53
  /**
45
- * @typedef {Object.<string, DataRule>} DataRule - A dynamic object where the keys are field names and the values define the field rules.
54
+ * @typedef {Object.<string, SchemaRule>} SchemaRule - A dynamic object where the keys are field names and the values define the field rules.
46
55
  */
47
56
 
48
57
  /**
@@ -58,5 +67,15 @@
58
67
  * @typedef {Object} DataValidatorErrorResponse
59
68
  * @property {boolean} error - Indicates an error occurred.
60
69
  * @property {string} [errorMessage] - A message describing the error (optional).
61
- * @property {Object} [dataErrors] - Additional error details (optional).
70
+ * @property {Object.<string, CheckError>} [errors] - Additional error details (optional).
71
+ */
72
+
73
+ /**
74
+ * Error Object
75
+ *
76
+ * @typedef {Object} CheckError
77
+ * @property {string} name - Field name
78
+ * @property {string} code - Error path (optional)
79
+ * @property {string} type - Error type (optional)
80
+ * @property {string} message - Error message (optional)
62
81
  */