check-rule-mate 0.4.2 → 0.5.0

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,10 +1,18 @@
1
1
  # check-rule-mate
2
+ Rule-based, extensible and async-friendly data validation engine for complex forms and business rules.
2
3
 
3
4
  ## Overview
4
5
 
5
- 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**.
6
8
 
7
- 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
8
16
 
9
17
 
10
18
  **Github repository:** [check-rule-mate repository](https://github.com/johnrock16/check-rule-mate)
@@ -14,49 +22,76 @@ The core goal is to provide a **reusable and easy-to-extend** for handling vario
14
22
  **Test the core functionalities here:** [check-rule-mate demo](https://johnrock16.github.io/check-rule-mate/)
15
23
  (Note: Creating or modifying custom validators is not supported in the demo, as it requires JavaScript implementation.)
16
24
 
25
+ ## Why check-rule-mate?
17
26
 
18
- ## 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
19
37
 
20
- - **Custom Validation Rules**: Easily define custom rules for form fields.
21
- - **Modular Design**: Separation of rule definitions and error messages for easy management.
22
- - **Easy Integration**: Can be used in any JavaScript environment.
23
- - **Clear Error Handling**: Handles errors and displays messages.
24
- - **Extendable**: Create your custom validators and rules and extend as you want.
38
+ check-rule-mate is built around four main concepts:
25
39
 
26
- ## 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
27
44
 
28
- - **Modifiers:** Extend rules for specific use cases (e.g., age validation in a date rule).
29
- - **Dynamic Parameters:** Use $variable to access field data within rules.
30
- - **Modular Rules and Validators:** Create multiple files for rules and helpers, organizing them by context or form.
31
- - **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)
32
58
 
33
59
  ## Table of Contents
34
60
 
35
61
  - [Getting Started](#Getting-Started)
36
- - [Installation](#Installation)
62
+ - [NPM - Installation](#Installation)
63
+ - [Repository - Installation](#Repository---Installation)
37
64
  - [Running Tests](#Running-Tests)
38
65
  - [How It Works](#How-It-Works)
39
66
  - [Basic Example](#Basic-Example)
40
- - [Defining Validation Components](#Defining-Validation-Components)
41
- - [1. Data Rules](#Data-Rules)
42
- - [2. General Rules](#General-Rules)
43
- - [3. Validation Helpers](#Validation-Helpers)
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)
44
71
  - [4. Error Messages](#Error-Messages)
45
72
  - [5. Example Usage](#Example-Usage)
46
73
  - [Vanilla](#vanilla)
47
74
  - [Express](#express)
48
75
  - [Frontend](#frontend)
76
+ - [When NOT to use check-rule-mate](#When-NOT-to-use-check-rule-mate)
77
+ - [License](#License);
49
78
 
50
79
  ## Getting Started
80
+
51
81
  ### Installation
82
+ If you are in NPM use this:
83
+ ```bash
84
+ npm install check-rule-mate
85
+ ```
52
86
 
53
- To install and start the library, run:
87
+ ### Repository - Installation
88
+ If you downloaded the repository you can install using:
54
89
  ```bash
55
90
  npm install
56
91
  npm start
57
92
  ```
58
93
 
59
- ### Running Tests
94
+ ### Repository - Running Tests
60
95
 
61
96
  Execute the test suite with:
62
97
  ```bash
@@ -64,69 +99,102 @@ npm test
64
99
  ```
65
100
 
66
101
  ## How It Works
67
- ### Basic Example
102
+ ### Basic Usage
68
103
 
69
- Here’s an example of validating a set of fields:
70
104
  ```javascript
71
- const { myValidator } = require('./dataValidator/validators');
72
- const { dataValidate } = require('./dataValidator/dataValidate');
73
- const MY_RULES = require('./dataValidator/rules/validators/myValidatorRules.json');
74
- const CONTACT_US = require('./dataValidator/rules/data/contactUs.json');
75
- const MY_VALIDATION_ERROR_MESSAGES = require('./i18n/en_US/errors/myValidatorRules.json');
76
-
77
- async function runDataValidate() {
78
- const fields = {
79
- name: "John",
80
- lastName: "Doe",
81
- email: "email@email.com",
82
- emailConfirm: "email@email.com",
83
- phone: "",
84
- subject: "I need a coffee",
85
- message: "Give me coffee"
86
- };
87
-
88
- // This should return { ok: true }
89
- const result = await dataValidate(fields, {
90
- validationHelpers: myValidator,
91
- rules: MY_RULES,
92
- dataRule: CONTACT_US,
93
- dataErrorMessages: MY_VALIDATION_ERROR_MESSAGES,
94
- });
95
-
96
- console.log(result);
97
- }
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
+ abortEarly: false,
130
+ propertiesMustMatch: true
131
+ }
132
+ });
133
+
134
+ const result = await validator.validate();
98
135
 
99
- runDataValidate();
136
+ // This should return { ok: true }
137
+ console.log(result);
138
+ }
139
+
140
+ runFormValidate();
100
141
  ```
101
142
 
102
- #### Parameters for dataValidate:
143
+ ### Validation Result
144
+ A validation result follows this structure:
103
145
 
104
- - **fields**: The object containing data to be validated.
105
- - **validationHelpers**: Functions to validate field data (see /dataValidator/validators).
106
- - **rules**: General validation rules for your application.
107
- - **dataRule**: Specific rules linking fields to validation logic.
108
- - **dataErrorMessages**: Custom error messages returned upon validation failure.
146
+ When is **valid**:
147
+ ```javascript
148
+ { ok: true }
149
+ ```
109
150
 
110
- ## Defining Validation Components
151
+ When is **invalid** and **has errors**:
152
+ ```javascript
153
+ {
154
+ error: true;
155
+ errors: {
156
+ [field: string]: {
157
+ type: string;
158
+ message: string;
159
+ }[];
160
+ };
161
+ }
162
+ ```
111
163
 
112
- ### Data Rules
113
164
 
114
- Define rules for specific datasets, such as forms. Example for a "Contact Us" form:
165
+ ## Defining Validation
166
+
167
+ ### Defining a Schema (What to validate)
168
+
169
+ Schemas map **data fields** to **rules**.
115
170
  ```json
116
171
  {
117
- "name": { "rule": "name", "required": true },
118
- "lastName": { "rule": "name", "required": true },
119
- "email": { "rule": "email", "required": true },
120
- "emailConfirm": { "rule": "email--confirm", "required": true },
121
- "phone": { "rule": "phone", "required": false },
122
- "subject": { "rule": "hasText", "required": true },
123
- "message": { "rule": "hasText", "required": true }
172
+ "name": {
173
+ "rule": "name",
174
+ "required": true
175
+ },
176
+ "email": {
177
+ "rule": "email",
178
+ "required": true
179
+ },
180
+ "emailConfirm": {
181
+ "rule": "email--confirm",
182
+ "required": true
183
+ },
184
+ "phone": {
185
+ "rule": "phone",
186
+ "required": false
187
+ }
124
188
  }
125
189
  ```
126
190
 
127
- ### General Rules
191
+ #### Schema Properties
192
+ - **rule**: Rule name (supports modifiers via `rule--modifier`)
193
+ - **required**: Whether the field must exist and not be empty
194
+
195
+ ### Defining Rules (How to validate)
128
196
 
129
- Define reusable validation logic. Example:
197
+ Rules define validation logic, independent of any specific form.
130
198
 
131
199
  ```json
132
200
  {
@@ -168,17 +236,53 @@ Define reusable validation logic. Example:
168
236
  }
169
237
  }
170
238
  ```
171
- #### Key Components:
172
239
 
173
- - **validate**: Array of functions to execute for validation.
174
- - **error**: Error messages for validation failures.
175
- - **regex**: Regular expression for validation.
176
- - **modifier**: Overrides specific rules with additional validations.
177
- - **params**: Parameters for validation functions (e.g., $email accesses email field data).
240
+ #### Rule Properties
241
+
242
+ - **validate**: Ordered list of validation functions
243
+ - **regex**: Optional regex used by the regex helper
244
+ - **error**: Error keys mapped to validation functions
245
+ - **modifier**: Contextual rule extensions
246
+ - **params**: Parameters passed to validation helpers
247
+
248
+ #### Modifiers (Contextual Rules)
249
+ Modifiers allow extending a rule **without duplicating logic**.
250
+
251
+ Example:
252
+ ```json
253
+ "email--confirm"
254
+ ```
255
+
256
+ Internally:
178
257
 
258
+ - Base rule: email
259
+ - Modifier: confirm
179
260
 
180
- ### Validation Helpers
181
- Helper functions perform actual validation. Example:
261
+ Modifiers can override:
262
+
263
+ - validate
264
+ - params
265
+ - regex
266
+ - error
267
+
268
+ This makes rules highly reusable and expressive.
269
+
270
+ #### Dynamic Parameters ($field)
271
+ Rules can reference other fields dynamically:
272
+
273
+ ```json
274
+ "params": {
275
+ "equals": ["$email"]
276
+ }
277
+ ```
278
+
279
+ At runtime:
280
+ - `$email` resolves to `data.email`
281
+ - Enables **cross-field validation**
282
+
283
+
284
+ ### Validation Helpers (Execution Layer)
285
+ Validation helpers are the **runtime implementation** of rules.
182
286
 
183
287
  ```javascript
184
288
  const myValidator = function (value, rule, modifier = null, data = null) {
@@ -218,13 +322,36 @@ const myValidator = function (value, rule, modifier = null, data = null) {
218
322
  };
219
323
  ```
220
324
 
221
- ### Error Messages
325
+ #### Helper Signature
326
+ ```typescript
327
+ (value, rule, modifier?, data?) => Record<string, Function>
328
+ ```
222
329
 
223
- Define custom error messages in a structured format:
330
+ Helpers:
331
+ - Can be **sync or async**
332
+ - Are **stateless**
333
+ - Do not know about schemas or error messages
334
+
335
+ ### Error Messages (i18n-ready)
336
+ Errors are resolved via keys, not hardcoded strings.
224
337
  ``` json
225
338
  {
226
- "common": { "hasText": "Please fill out this field." },
227
- "email": { "regex": "Enter a valid email address." }
339
+ "common": {
340
+ "hasText": "Please fill the field"
341
+ },
342
+ "email": {
343
+ "regex": "Please enter a valid email",
344
+ "equals": "Emails do not match"
345
+ }
346
+ }
347
+ ```
348
+ This makes localization and message customization straightforward.
349
+
350
+ ### Validation Options
351
+ ```typescript
352
+ options: {
353
+ abortEarly?: boolean; // Stop on first error
354
+ propertiesMustMatch?: boolean; // Schema vs data strictness
228
355
  }
229
356
  ```
230
357
 
@@ -269,3 +396,12 @@ npm run example:express
269
396
  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)
270
397
 
271
398
  **Frontend example:** [check-rule-mate demo.](https://johnrock16.github.io/check-rule-mate/)
399
+
400
+
401
+ ## When NOT to use check-rule-mate
402
+ - Simple one-off forms
403
+ - Basic required-only validation
404
+ - When schema-based validation is enough
405
+
406
+ ## License
407
+ - 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 k=Object.defineProperty;var E=Object.getOwnPropertyDescriptor;var b=Object.getOwnPropertyNames;var P=Object.prototype.hasOwnProperty;var j=(u,n)=>{for(var c in n)k(u,c,{get:n[c],enumerable:!0})},I=(u,n,c,i)=>{if(n&&typeof n=="object"||typeof n=="function")for(let f of b(n))!P.call(u,f)&&f!==c&&k(u,f,{get:()=>n[f],enumerable:!(i=E(n,f))||i.enumerable});return u};var T=u=>I(k({},"__esModule",{value:!0}),u);var x={};j(x,{createValidator:()=>V});module.exports=T(x);function V(u,{validationHelpers:n={},rules:c,schema:i,errorMessages:f={},options:y={propertiesMustMatch:!0,abortEarly:!1}}){let p={},r=u,d={all:async e=>Promise.all([...e].map(async s=>await h(s,r))),first:async e=>{let s=[];for(let t of e){let l=await h(t,r);if(s.push(l),!l)return s}return s}};function g(e,s){if(!e||typeof s!="string")return;let t=s.split("."),l=e;for(let M of t){if(l[M]===void 0)return;l=l[M]}return l}async function h(e,s=null){if(i[e.key]){let{rule:t,required:l}=i[e.key];if((t&&l||!l&&e.value!="")&&t){let M=t.split("--")[0],a=t.split("--").length>1?t.split("--")[1]:"",O=U(e.value,c[M],a,n,s),{isValid:R,errorMessage:m,errorType:q}=await O.validate();return R||(p[e.key]={name:e.key,error:!0,errorMessage:g(f,m)||m,errorType:q}),R}}else if(y.propertiesMustMatch)return p[e.key]={name:e.key,error:!0,errorMessage:"Invalid property"},!1;return!0}async function w(e){return await h({key:e,value:r[e]},r)?{ok:!0}:{error:!0,errors:p[e]}}async function o(){p={};let e=Object.keys(r).map(s=>({key:s,value:r[s]}));if(e&&e.length>0){if(!Object.keys(i).every(a=>r.hasOwnProperty(a)))return{error:!0,errorMessage:"Missing properties"};if((y!=null&&y.abortEarly?await d.first(e):await d.all(e)).some(a=>!a))return{error:!0,errors:p};let t=Object.keys(i).map(a=>({key:a,required:i[a].required})),l=e.map(a=>a.key);if(!t.filter(a=>a.required).map(a=>a.key).every(a=>l.includes(a)))return{error:!0}}else if(!e||e.length===0)return{error:!0,errorMessage:"Missing fields for schema"};return{ok:!0}}function v(e){r=e}return{validate:o,validateField:w,setData:v}}function U(u,n,c=null,i=null,f=null){async function y(r){let d,g;return{isValid:!(await Promise.all(r.validate.map(async o=>{let v=!0;if(r.params&&r.params[o]&&r.params[o].length>0){let e=r.params[o].map(t=>typeof t=="string"&&t[0]==="$"?t.substring(1,t.length):t);v=await this[o](...e)}else v=await this[o]();return!v&&!d&&(r!=null&&r.error[o])&&(d=r.error[o],g=o),v}))).some(o=>!o),errorMessage:d,errorType:g}}async function p(){if(i&&typeof i=="function"){let d=i(u,n,c,f);Object.keys(d).forEach(g=>{this[g]=d[g]})}return c?await y.call(this,n.modifier[c]):await y.call(this,n)}return{validate:p}}0&&(module.exports={createValidator});
package/package.json CHANGED
@@ -1,9 +1,21 @@
1
1
  {
2
2
  "name": "check-rule-mate",
3
- "version": "0.4.2",
3
+ "version": "0.5.0",
4
4
  "description": "",
5
5
  "main": "./dist/main.cjs.js",
6
6
  "type": "commonjs",
7
+ "keywords": [
8
+ "data validation",
9
+ "data validation js",
10
+ "validator",
11
+ "validate",
12
+ "form validator",
13
+ "form validator js",
14
+ "form validate",
15
+ "check-rule-mate",
16
+ "check rule",
17
+ "check rule mate"
18
+ ],
7
19
  "scripts": {
8
20
  "start": "node ./examples/vanilla/src/index.js",
9
21
  "build": "node build",
@@ -14,7 +26,7 @@
14
26
  "author": "João Rocha",
15
27
  "license": "ISC",
16
28
  "devDependencies": {
17
- "esbuild": "^0.24.0",
29
+ "esbuild": "^0.27.2",
18
30
  "express": "^4.21.2",
19
31
  "jest": "^29.7.0"
20
32
  }
@@ -1,11 +1,26 @@
1
1
  /**
2
2
  * Validate your data fields using your rules, data rules and validators.
3
- * @param {[DataField]} data - All the data fields to be validate
3
+ * @param {[DataField]} dataParameter - All the data fields to be validate
4
4
  * @param {DataValidatorConfigs} config - The configs which will be followed during validation
5
- * @returns {DataValidatorSuccessResponse | DataValidatorErrorResponse} - The response of your validation
6
5
  */
7
- export function dataValidate(data, {validationHelpers = {}, rules, dataRule, dataErrorMessages = {}}) {
8
- const dataErrors = {};
6
+ export function createValidator(dataParameter, {validationHelpers = {}, rules, schema, errorMessages = {}, options = { propertiesMustMatch: true, abortEarly: false}}) {
7
+ let errors = {};
8
+ let data = dataParameter;
9
+
10
+ const validateByStrategies = {
11
+ all: async (dataArr) => Promise.all([...dataArr].map(async (input) => await inputValidation(input, data))),
12
+ first: async (dataArr) => {
13
+ const results = []
14
+ for (const input of dataArr) {
15
+ const result = await inputValidation(input, data);
16
+ results.push(result);
17
+ if (!result) {
18
+ return results
19
+ }
20
+ }
21
+ return results;
22
+ }
23
+ };
9
24
 
10
25
  function getObjectValueByPath(obj, path) {
11
26
  if (!obj || typeof path !== 'string') return undefined;
@@ -22,41 +37,67 @@ export function dataValidate(data, {validationHelpers = {}, rules, dataRule, dat
22
37
  }
23
38
 
24
39
  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
40
+ if (schema[dataAttribute.key]) {
41
+ const { rule, required } = schema[dataAttribute.key];
42
+ if ((rule && required) || (!required && dataAttribute.value != '')) {
43
+ if (rule) {
44
+ const INPUT_RULE = rule.split('--')[0];
45
+ const RULE_MODIFIER = rule.split('--').length > 1 ? rule.split('--')[1] : '';
46
+ const dataAttributeValidation = dataAttributeValidator(dataAttribute.value, rules[INPUT_RULE], RULE_MODIFIER, validationHelpers, data);
47
+ const { isValid, errorMessage, errorType } = await dataAttributeValidation.validate();
48
+ if (!isValid) {
49
+ errors[dataAttribute.key] = {
50
+ name: dataAttribute.key,
51
+ error: true,
52
+ errorMessage: getObjectValueByPath(errorMessages, errorMessage) || errorMessage,
53
+ errorType: errorType
54
+ }
39
55
  }
56
+ return isValid;
40
57
  }
41
- return isValid;
42
58
  }
59
+ } else if (options.propertiesMustMatch) {
60
+ errors[dataAttribute.key] = {
61
+ name: dataAttribute.key,
62
+ error: true,
63
+ errorMessage: "Invalid property"
64
+ }
65
+ return false;
43
66
  }
44
67
  return true;
45
68
  }
46
69
 
70
+ /**
71
+ * Validate only a field using the attribute key
72
+ * @param {string} key - The field key name you want to validate
73
+ * @returns {DataValidatorSuccessResponse | DataValidatorErrorResponse} - The response of your validation
74
+ */
75
+ async function validateField(key) {
76
+ const result = await inputValidation({key: key, value: data[key]}, data);
77
+ if (!result) {
78
+ return { error: true, errors: errors[key]}
79
+ }
80
+ return { ok: true}
81
+ }
82
+
83
+ /**
84
+ * Validate the entire fields using the schema
85
+ * @returns {DataValidatorSuccessResponse | DataValidatorErrorResponse} - The response of your validation
86
+ */
47
87
  async function validate() {
88
+ errors = {};
48
89
  let dataArr = Object.keys(data).map((key) => ({ key, value: data[key] }));
49
90
  if (dataArr && dataArr.length > 0) {
50
- if(!Object.keys(dataRule).every((key) => data.hasOwnProperty(key))) {
91
+ if(!Object.keys(schema).every((key) => data.hasOwnProperty(key))) {
51
92
  return { error: true, errorMessage: "Missing properties"}
52
93
  }
53
- const dataValidators = await Promise.all([...dataArr].map(async (input) => await inputValidation(input, data)));
94
+ const dataValidators = options?.abortEarly ? await validateByStrategies.first(dataArr) : await validateByStrategies.all(dataArr);
54
95
 
55
96
  if (dataValidators.some((element) => !element)) {
56
- return { error: true, dataErrors: dataErrors };
97
+ return { error: true, errors: errors };
57
98
  }
58
99
 
59
- const dataRuleArr = Object.keys(dataRule).map((key) => ({ key, required: dataRule[key].required}));
100
+ const dataRuleArr = Object.keys(schema).map((key) => ({ key, required: schema[key].required}));
60
101
  const dataAttributesKey = dataArr.map((attribute) => attribute.key);
61
102
  const dataAttributesRequired = dataRuleArr.filter((rule) => rule.required).map((rule) => rule.key);
62
103
 
@@ -64,12 +105,16 @@ export function dataValidate(data, {validationHelpers = {}, rules, dataRule, dat
64
105
  return { error: true };
65
106
  }
66
107
  } else if (!dataArr || dataArr.length === 0) {
67
- return { error: true, errorMessage: "Missing fields for dataRules"}
108
+ return { error: true, errorMessage: "Missing fields for schema"}
68
109
  }
69
110
  return { ok: true };
70
111
  }
71
112
 
72
- return validate();
113
+ function setData(newData) {
114
+ data = newData;
115
+ }
116
+
117
+ return {validate, validateField, setData};
73
118
  }
74
119
 
75
120
  /**
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
@@ -13,8 +13,15 @@
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 {ValidatorOption} options - Options
19
+ */
20
+
21
+ /**
22
+ * @typedef {Object} ValidatorOption
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
18
25
  */
19
26
 
20
27
  /**
@@ -31,18 +38,18 @@
31
38
  */
32
39
 
33
40
  /**
34
- * @typedef {Object} DataRule
35
- * @property {dataRuleFiVeld} field - The field which will use the rule
41
+ * @typedef {Object} SchemaRule
42
+ * @property {SchemaRuleFiVeld} field - The field which will use the rule
36
43
  */
37
44
 
38
45
  /**
39
- * @typedef {Object} DataRuleField
46
+ * @typedef {Object} SchemaRuleField
40
47
  * @property {string} rule - The validation rule for the field (e.g., "name", "email", "phone", "hasText").
41
48
  * @property {boolean} required - Indicates whether the field is required.
42
49
  */
43
50
 
44
51
  /**
45
- * @typedef {Object.<string, DataRule>} DataRule - A dynamic object where the keys are field names and the values define the field rules.
52
+ * @typedef {Object.<string, SchemaRule>} SchemaRule - A dynamic object where the keys are field names and the values define the field rules.
46
53
  */
47
54
 
48
55
  /**