check-rule-mate 0.5.2 → 0.5.3

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
@@ -13,6 +13,7 @@ It is designed for scenarios where traditional schema-based validators start to
13
13
  - Async checks
14
14
  - Reusable validation logic across multiple forms
15
15
  - Full control over execution flow and error handling
16
+ - Lifecycle Hooks
16
17
 
17
18
 
18
19
  **Github repository:** [check-rule-mate repository](https://github.com/johnrock16/check-rule-mate)
@@ -66,6 +67,7 @@ This separation makes the system flexible, scalable, and easy to maintain.
66
67
  - [Running Tests](#Repository---Running-Tests)
67
68
  - [How It Works](#How-It-Works)
68
69
  - [Basic Usage](#Basic-Usage)
70
+ - [Lifecycle Hooks](#Lifecycle-Hooks)
69
71
  - [Auto documentation](#Auto-Documentation)
70
72
  - [Defining Validation](#Defining-Validation)
71
73
  - [1. Schema](#Defining-a-Schema-What-to-validate)
@@ -167,14 +169,129 @@ When is **invalid** and **has errors**:
167
169
  }
168
170
  ```
169
171
 
172
+ ### Lifecycle Hooks
173
+ The **check-rule-mate** lifecycle hooks allow you to observe, extend and react to the validation process without coupling logic to rules or helpers.
174
+
175
+ Hooks are especially useful for:
176
+
177
+ - Logging and debugging
178
+ - Analytics and metrics
179
+ - Custom side-effects
180
+ - Integrating validation with UI or external systems
181
+ - Advanced error handling and reporting
182
+ - They provide fine-grained control over the validation lifecycle.
183
+
184
+ ```typescript
185
+ hooks?: {
186
+ onValidateStart?: (payload) => void;
187
+ onValidateFieldStart?: (payload) => void;
188
+ onValidateFieldError?: (payload) => void;
189
+ onValidateFieldSuccess?: (payload) => void;
190
+ onValidateEnd?: (payload) => void;
191
+ }
192
+ ```
193
+
194
+ #### Hook Payloads
195
+
196
+ ##### `onValidateStart`
197
+ Triggered once before validation begins.
198
+ ```typescript
199
+ onValidateStart: ({ data }) => void
200
+ ```
201
+
202
+ **Payload:**
203
+ - `data`: Full form data object being validated
204
+
205
+ ##### `onValidateFieldStart`
206
+ Triggered before validating each field.
207
+ ```typescript
208
+ onValidateFieldStart: ({ field, value, schemaField }) => void
209
+ ```
210
+
211
+ **Payload:**
212
+ - `field`: Field name
213
+ - `value`: Field value
214
+ - `schemaField`: Schema configuration for the field (or `null` if missing)
215
+
216
+ ##### `onValidateFieldError`
217
+ Triggered when a field fails validation.
218
+ ```typescript
219
+ onValidateFieldError: ({ field, value, schemaField, error }) => void
220
+ ```
221
+
222
+ **Payload:**
223
+ - `field`: Field name
224
+ - `value`: Field value
225
+ - `schemaField`: Schema configuration for the field (or `null` if missing)
226
+ - `error`: Validation error object
227
+
228
+ ##### `onValidateFieldSuccess`
229
+ Triggered when a field is successfully validated.
230
+ ```typescript
231
+ onValidateFieldSuccess: ({ field, value, schemaField }) => void
232
+ ```
233
+
234
+ **Payload:**
235
+ - `field`: Field name
236
+ - `value`: Field value
237
+ - `schemaField`: Schema configuration for the field (or `null` if missing)
238
+
239
+ ##### `onValidateEnd`
240
+ Triggered once after validation finishes.
241
+ ```typescript
242
+ onValidateEnd: ({ data, errors }) => void
243
+ ```
244
+
245
+ **Payload:**
246
+ - `data`: Full form data object being validated
247
+ - `errors`: Validation errors (if any)
248
+ If no errors occurred, `errors` may be `undefined`.
249
+
250
+ #### Hooks - Example Usage
251
+ ```javascript
252
+ const validator = createValidator(fields, {
253
+ validationHelpers: myValidator,
254
+ rules: MY_RULES,
255
+ schema: CONTACT_US,
256
+ errorMessages: ERROR_MESSAGES,
257
+ hooks: {
258
+ onValidateStart: ({ data }) => {
259
+ console.log('Validation started', data);
260
+ },
261
+
262
+ onValidateFieldStart: ({ field, value }) => {
263
+ console.log(`Validating ${field}`, value);
264
+ },
265
+
266
+ onValidateFieldError: ({ field, error }) => {
267
+ console.error(`Error on ${field}`, error);
268
+ },
269
+
270
+ onValidateFieldSuccess: ({ field }) => {
271
+ console.log(`${field} validated successfully`);
272
+ },
273
+
274
+ onValidateEnd: ({ data, errors }) => {
275
+ if (errors) {
276
+ console.log('Validation finished with errors', errors);
277
+ } else {
278
+ console.log('Validation finished successfully');
279
+ }
280
+ }
281
+ }
282
+ });
283
+
284
+ await validator.validate();
285
+ ```
286
+
170
287
  ### Auto Documentation
171
288
 
172
- check-rule-mate contains a script to generate documentation based in your rules, schemas and error messages.
289
+ **check-rule-mate** contains a script to generate **automatic documentation** based in your rules, schemas and error messages.
173
290
 
174
291
  To use that it is simple, you only need to run this command:
175
292
 
176
293
  ```bash
177
- npx generate-docs --rules rules-path --schemas schemas-path --errors errors-path --out file.html
294
+ npx check-rule-mate-auto-docs --rules rules-path --schemas schemas-path --errors errors-path --out file.html
178
295
  ```
179
296
 
180
297
  This will generate a HTML file containing the rules, schemas and errors.
@@ -9,7 +9,7 @@
9
9
 
10
10
  const fs = require('fs');
11
11
  const path = require('path');
12
- const process = require('process')
12
+ const process = require('process');
13
13
 
14
14
  /* ---------------------------------------
15
15
  * CLI ARGS
@@ -28,7 +28,7 @@ const OUTPUT = getArg('--out') || "check-rule-mate-docs.html";
28
28
  if (!RULES_DIR || !SCHEMAS_DIR) {
29
29
  console.error(`
30
30
  Usage:
31
- node generate-docs.js --rules ./rules --schemas ./schemas --out docs.html
31
+ npx check-rule-mate-auto-docs --rules ./rules --schemas ./schemas --errors ./errors --out docs.html
32
32
  `);
33
33
  process.exit(1);
34
34
  }
package/dist/main.cjs.js CHANGED
@@ -1 +1 @@
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});
1
+ var M=Object.defineProperty;var j=Object.getOwnPropertyDescriptor;var D=Object.getOwnPropertyNames;var U=Object.prototype.hasOwnProperty;var L=(r,a)=>{for(var u in a)M(r,u,{get:a[u],enumerable:!0})},_=(r,a,u,l)=>{if(a&&typeof a=="object"||typeof a=="function")for(let d of D(a))!U.call(r,d)&&d!==u&&M(r,d,{get:()=>a[d],enumerable:!(l=j(a,d))||l.enumerable});return r};var x=r=>_(M({},"__esModule",{value:!0}),r);var K={};L(K,{createValidator:()=>q});module.exports=x(K);var O={propertiesMustMatch:!0,abortEarly:!1,cache:!0};function q(r,{validationHelpers:a={},rules:u,schema:l,errorMessages:d={},hooks:g={},options:p=O}){p={...O,...p},r=r;let i={},y={},v={all:async e=>Promise.all([...e].map(async n=>await m(n,r))),first:async e=>{let n=[];for(let V of e){let t=await m(V,r);if(n.push(t),!t)return n}return n}};function w(e,n){if(!e||typeof n!="string")return;let V=n.split("."),t=e;for(let f of V){if(t[f]===void 0)return;t=t[f]}return t}async function m(e,n=null){var V,t;if(o("onValidateFieldStart",{field:e.key,value:e.value,schemaField:l[e.key]||null}),l[e.key]){let{rule:f,required:s}=l[e.key];if((((V=l[e.key])==null?void 0:V.cache)!==void 0?l[e.key].cache:p.cache)&&n[e.key]===((t=y[e.key])==null?void 0:t.value))return y[e.key].isValid;if((f&&s||!s&&e.value!="")&&f){let P=f.split("--")[0],S=f.split("--").length>1?f.split("--")[1]:"",I=B(e.value,u[P],S,a,n),{isValid:E,errorMessage:F,errorType:T}=await I.validate();if(E)o("onValidateFieldSuccess",{field:e.key,value:e.value,schemaField:l[e.key]});else{let R={name:e.key,field:e.key,code:F,type:T,message:w(d,F)||""};i[e.key]=R,o("onValidateFieldError",{field:e.key,value:e.value,schemaField:l[e.key],error:R})}return y[e.key]={isValid:E,value:n[e.key]},E}}else if(p.propertiesMustMatch){let f={name:e.key,field:e.key,message:"Invalid property",internal:!0};return i[e.key]=f,o("onValidateFieldError",{field:e.key,value:e.value,error:f}),!1}return o("onValidateFieldSuccess",{field:e.key,value:e.value}),!0}async function c(e){return await m({key:e,value:r[e]},r)?{ok:!0}:{error:!0,errors:i[e]}}async function k(){o("onValidateStart",{data:r}),i={};let e=Object.keys(r).map(n=>({key:n,value:r[n]}));if(e&&e.length>0){if(!Object.keys(l).every(s=>r.hasOwnProperty(s)))return o("onValidateEnd",{data:r,errors:[{name:"internal: schema - missing properties",message:"Missing properties",internal:!0}]}),{error:!0,errorMessage:"Missing properties"};if((p!=null&&p.abortEarly?await v.first(e):await v.all(e)).some(s=>!s))return o("onValidateEnd",{data:r,errors:i}),{error:!0,errors:i};let V=Object.keys(l).map(s=>({key:s,required:l[s].required})),t=e.map(s=>s.key);if(!V.filter(s=>s.required).map(s=>s.key).every(s=>t.includes(s))){let s={error:!0};return o("onValidateEnd",{data:r,errors:[{name:"internal: fields - required",message:"",internal:!0}]}),s}}else if(!e||e.length===0){let n={error:!0,errorMessage:"Missing fields for schema"};return o("onValidateEnd",{data:r,errors:[{name:"internal: schema - missing fields",message:n.errorMessage,internal:!0}]}),n}return o("onValidateEnd",{data:r}),{ok:!0}}function o(e,n){g!=null&&g[e]&&typeof g[e]=="function"&&g[e]({...n})}function h(e){r=e}return{validate:k,validateField:c,setData:h}}function B(r,a,u=null,l=null,d=null){async function g(i){let y,v;return{isValid:!(await Promise.all(i.validate.map(async c=>{let k=!0;if(i.params&&i.params[c]&&i.params[c].length>0){let o=i.params[c].map(e=>typeof e=="string"&&e[0]==="$"?e.substring(1,e.length):e);k=await this[c](...o)}else k=await this[c]();return!k&&!y&&(i!=null&&i.error[c])&&(y=i.error[c],v=c),k}))).some(c=>!c),errorMessage:y,errorType:v}}async function p(){if(l&&typeof l=="function"){let y=l(r,a,u,d);Object.keys(y).forEach(v=>{this[v]=y[v]})}return u?await g.call(this,a.modifier[u]):await g.call(this,a)}return{validate:p}}0&&(module.exports={createValidator});
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "check-rule-mate",
3
- "version": "0.5.2",
3
+ "version": "0.5.3",
4
4
  "description": "",
5
5
  "main": "./dist/main.cjs.js",
6
6
  "type": "commonjs",
@@ -18,7 +18,7 @@
18
18
  "check rule mate"
19
19
  ],
20
20
  "bin": {
21
- "generate-docs": "./bin/generate-docs.js"
21
+ "check-rule-mate-auto-docs": "./bin/generate-docs.js"
22
22
  },
23
23
  "scripts": {
24
24
  "start": "node ./examples/vanilla/src/index.js",
package/src/index.d.ts CHANGED
@@ -86,6 +86,9 @@ export interface DataValidatorConfigs {
86
86
 
87
87
  /** Validator options */
88
88
  options: ValidatorOptions
89
+
90
+ /** Validator hooks */
91
+ hooks: ValidatorHooks
89
92
  }
90
93
 
91
94
  /**
@@ -100,9 +103,12 @@ export interface DataValidatorSuccessResponse {
100
103
  * Error object.
101
104
  */
102
105
  export interface CheckError {
103
- /** Field name */
106
+ /** Error name */
104
107
  name: string
105
108
 
109
+ /** Field name */
110
+ field?: string
111
+
106
112
  /** Error path */
107
113
  code?: string
108
114
 
@@ -111,6 +117,9 @@ export interface CheckError {
111
117
 
112
118
  /** Error message */
113
119
  message?: string
120
+
121
+ /** Internal error flag */
122
+ internal?: boolean
114
123
  }
115
124
 
116
125
  /**
@@ -126,3 +135,94 @@ export interface DataValidatorErrorResponse {
126
135
  /** Additional error details */
127
136
  errors?: Record<string, CheckError>
128
137
  }
138
+
139
+ export interface ValidatorHooks {
140
+ /** Executed before validation runs */
141
+ onValidateStart?: onValidateStart
142
+
143
+ /** Executed before validation runs for each field */
144
+ onValidateFieldStart?: onValidateFieldStart
145
+
146
+ /** Executed when validation fails for some field */
147
+ onValidateFieldError?: onValidateFieldError
148
+
149
+ /** Executed when validation has success for some field */
150
+ onValidateFieldSuccess?: onValidateFieldSuccess
151
+
152
+ /** Executed after validation runs */
153
+ onValidateEnd?: onValidateEnd
154
+ }
155
+
156
+ export interface onValidateStart {
157
+ /** Returns the payload of hook */
158
+ payload: onValidateStartPayload
159
+ }
160
+
161
+ export interface onValidateFieldStart {
162
+ /** Returns the payload of hook */
163
+ payload: onValidateFieldStartPayload
164
+ }
165
+
166
+ export interface onValidateFieldError {
167
+ /** Returns the payload of hook */
168
+ payload: onValidateFieldErrorPayload
169
+ }
170
+
171
+ export interface onValidateFieldSuccess {
172
+ /** Returns the payload of hook */
173
+ payload: onValidateFieldSuccessPayload
174
+ }
175
+
176
+ export interface onValidateEnd {
177
+ /** Returns the payload of hook */
178
+ payload: onValidateEndPayload
179
+ }
180
+
181
+ export interface onValidateStartPayload {
182
+ /** Form data object */
183
+ data: Object
184
+ }
185
+
186
+ export interface onValidateFieldStart {
187
+ /** Field name */
188
+ field: string
189
+
190
+ /** Field value */
191
+ value: any
192
+
193
+ /** Schema field */
194
+ schemaField: SchemaRuleField
195
+ }
196
+
197
+ export interface onValidateFieldError {
198
+ /** Field name */
199
+ field: string
200
+
201
+ /** Field value */
202
+ value: any
203
+
204
+ /** Schema field */
205
+ schemaField: SchemaRuleField
206
+
207
+ /** Field error */
208
+ error: CheckError
209
+ }
210
+
211
+ export interface onValidateFieldSuccess {
212
+ /** Field name */
213
+ field: string
214
+
215
+ /** Field value */
216
+ value: any
217
+
218
+ /** Schema field */
219
+ schemaField: SchemaRuleField
220
+ }
221
+
222
+ export interface onValidateEndPayload {
223
+ /** Form data object */
224
+ data: Object
225
+
226
+ /** Form errors */
227
+ errors?: Record<string, CheckError>
228
+ }
@@ -5,7 +5,7 @@ const DEFAUL_OPTIONS = { propertiesMustMatch: true, abortEarly: false, cache: tr
5
5
  * @param {[DataField]} data - All the data fields to be validate
6
6
  * @param {DataValidatorConfigs} config - The configs which will be followed during validation
7
7
  */
8
- export function createValidator(data, {validationHelpers = {}, rules, schema, errorMessages = {}, options = DEFAUL_OPTIONS}) {
8
+ export function createValidator(data, {validationHelpers = {}, rules, schema, errorMessages = {}, hooks = {}, options = DEFAUL_OPTIONS}) {
9
9
  options = { ...DEFAUL_OPTIONS, ...options};
10
10
  data = data;
11
11
  let errors = {};
@@ -41,6 +41,7 @@ export function createValidator(data, {validationHelpers = {}, rules, schema, er
41
41
  }
42
42
 
43
43
  async function inputValidation(dataAttribute, data = null) {
44
+ hookTrigger('onValidateFieldStart', { field: dataAttribute.key, value: dataAttribute.value, schemaField: schema[dataAttribute.key] || null });
44
45
  if (schema[dataAttribute.key]) {
45
46
  const { rule, required } = schema[dataAttribute.key];
46
47
  const cacheEnabled = schema[dataAttribute.key]?.cache !== undefined ? schema[dataAttribute.key].cache : options.cache;
@@ -56,24 +57,36 @@ export function createValidator(data, {validationHelpers = {}, rules, schema, er
56
57
  const dataAttributeValidation = dataAttributeValidator(dataAttribute.value, rules[INPUT_RULE], RULE_MODIFIER, validationHelpers, data);
57
58
  const { isValid, errorMessage, errorType } = await dataAttributeValidation.validate();
58
59
  if (!isValid) {
59
- errors[dataAttribute.key] = {
60
+ const error = {
60
61
  name: dataAttribute.key,
62
+ field: dataAttribute.key,
61
63
  code: errorMessage,
62
64
  type: errorType,
63
65
  message: getObjectValueByPath(errorMessages, errorMessage) || ''
64
- }
66
+ };
67
+
68
+ errors[dataAttribute.key] = error;
69
+ hookTrigger('onValidateFieldError', { field: dataAttribute.key, value: dataAttribute.value, schemaField: schema[dataAttribute.key] , error: error });
70
+ } else {
71
+ hookTrigger('onValidateFieldSuccess', { field: dataAttribute.key, value: dataAttribute.value, schemaField: schema[dataAttribute.key] });
65
72
  }
66
73
  oldData[dataAttribute.key] = {isValid: isValid, value: data[dataAttribute.key]};
67
74
  return isValid;
68
75
  }
69
76
  }
70
77
  } else if (options.propertiesMustMatch) {
71
- errors[dataAttribute.key] = {
78
+ const error = {
72
79
  name: dataAttribute.key,
73
- message: "Invalid property"
80
+ field: dataAttribute.key,
81
+ message: "Invalid property",
82
+ internal: true
74
83
  }
84
+
85
+ errors[dataAttribute.key] = error;
86
+ hookTrigger('onValidateFieldError', { field: dataAttribute.key, value: dataAttribute.value, error: error });
75
87
  return false;
76
88
  }
89
+ hookTrigger('onValidateFieldSuccess', { field: dataAttribute.key, value: dataAttribute.value });
77
90
  return true;
78
91
  }
79
92
 
@@ -95,15 +108,18 @@ export function createValidator(data, {validationHelpers = {}, rules, schema, er
95
108
  * @returns {DataValidatorSuccessResponse | DataValidatorErrorResponse} - The response of your validation
96
109
  */
97
110
  async function validate() {
111
+ hookTrigger('onValidateStart', { data });
98
112
  errors = {};
99
113
  let dataArr = Object.keys(data).map((key) => ({ key, value: data[key] }));
100
114
  if (dataArr && dataArr.length > 0) {
101
115
  if(!Object.keys(schema).every((key) => data.hasOwnProperty(key))) {
116
+ hookTrigger('onValidateEnd', { data, errors: [{name: 'internal: schema - missing properties' , message: 'Missing properties', internal: true}] });
102
117
  return { error: true, errorMessage: "Missing properties"}
103
118
  }
104
119
  const dataValidators = options?.abortEarly ? await validateByStrategies.first(dataArr) : await validateByStrategies.all(dataArr);
105
120
 
106
121
  if (dataValidators.some((element) => !element)) {
122
+ hookTrigger('onValidateEnd', { data, errors: errors });
107
123
  return { error: true, errors: errors };
108
124
  }
109
125
 
@@ -112,14 +128,27 @@ export function createValidator(data, {validationHelpers = {}, rules, schema, er
112
128
  const dataAttributesRequired = dataRuleArr.filter((rule) => rule.required).map((rule) => rule.key);
113
129
 
114
130
  if (!dataAttributesRequired.every((fieldRequired) => dataAttributesKey.includes(fieldRequired))) {
115
- return { error: true };
131
+ const error = { error: true };
132
+
133
+ hookTrigger('onValidateEnd', { data, errors: [{name: 'internal: fields - required' , message: '', internal: true}] });
134
+ return error;
116
135
  }
117
136
  } else if (!dataArr || dataArr.length === 0) {
118
- return { error: true, errorMessage: "Missing fields for schema"}
137
+ const error = { error: true, errorMessage: "Missing fields for schema"};
138
+
139
+ hookTrigger('onValidateEnd', { data, errors: [{name: 'internal: schema - missing fields' , message: error.errorMessage, internal: true}] });
140
+ return error;
119
141
  }
142
+ hookTrigger('onValidateEnd', { data });
120
143
  return { ok: true };
121
144
  }
122
145
 
146
+ function hookTrigger(hookName, parameters) {
147
+ if (hooks?.[hookName] && typeof hooks[hookName] === 'function') {
148
+ hooks[hookName]({...parameters});
149
+ }
150
+ }
151
+
123
152
  function setData(newData) {
124
153
  data = newData;
125
154
  }
package/src/types.js CHANGED
@@ -16,6 +16,7 @@
16
16
  * @property {SchemaRule} schema - The rules you want to use per field
17
17
  * @property {Object} errorMessages - The error messages you want to show during errors
18
18
  * @property {ValidatorOptions} options - Options
19
+ * @property {ValidatorHooks} hooks - The hooks you want to execute in some specific phase of validation
19
20
  */
20
21
 
21
22
  /**
@@ -74,8 +75,78 @@
74
75
  * Error Object
75
76
  *
76
77
  * @typedef {Object} CheckError
77
- * @property {string} name - Field name
78
+ * @property {string} name - Error name
79
+ * @property {string} field - Field name (optional)
78
80
  * @property {string} code - Error path (optional)
79
81
  * @property {string} type - Error type (optional)
80
82
  * @property {string} message - Error message (optional)
83
+ * @property {boolean} internal - Flag to know if it is a internal error (optional)
84
+ */
85
+
86
+
87
+ /**
88
+ * @typedef {Object} ValidatorHooks
89
+ * @property {onValidateStart} onValidateStart - Executed before validation runs
90
+ * @property {onValidateFieldStart} onValidateFieldStart - Executed before validation runs for each field
91
+ * @property {onValidateFieldError} onValidateFieldError - Executed when validation fails for some field
92
+ * @property {onValidateFieldSuccess} onValidateFieldSuccess - Executed when validation has success for some field
93
+ * @property {onValidateEnd} onValidateEnd - Executed after validation runs
94
+ */
95
+
96
+ /**
97
+ * @typedef {Function} onValidateStart
98
+ * @property {onValidateStartPayload} payload - Returns the payload of validate form hook
99
+ */
100
+
101
+ /**
102
+ * @typedef {Object} onValidateStartPayload
103
+ * @property {Object} data - Returns the form data
104
+ */
105
+
106
+ /**
107
+ * @typedef {Function} onValidateFieldStart
108
+ * @property {onValidateFieldStartPayload} payload - Returns the payload of validate field hook
109
+ */
110
+
111
+ /**
112
+ * @typedef {Object} onValidateFieldStartPayload
113
+ * @property {string} field - Returns the field name
114
+ * @property {any} value - Returns the value of field
115
+ * @property {SchemaRuleField} schemaField - Returns the schema field
116
+ */
117
+
118
+ /**
119
+ * @typedef {Function} onValidateFieldError
120
+ * @property {onValidateFieldErrorPayload} payload - Returns the payload of validate field error hook
121
+ */
122
+
123
+ /**
124
+ * @typedef {Object} onValidateFieldErrorPayload
125
+ * @property {string} field - Returns the field name
126
+ * @property {string} value - Returns the value of field
127
+ * @property {SchemaRuleField} schemaField - Returns the schema field
128
+ * @property {CheckError} error - Returns the error data
129
+ */
130
+
131
+ /**
132
+ * @typedef {Function} onValidateFieldSuccess
133
+ * @property {onValidateFieldSuccessPayload} payload - Returns the payload of validate field success hook
134
+ */
135
+
136
+ /**
137
+ * @typedef {Object} onValidateFieldSuccessPayload
138
+ * @property {string} field - Returns the field name
139
+ * @property {string} value - Returns the value of field
140
+ * @property {SchemaRuleField} schemaField - Returns the schema field
141
+ */
142
+
143
+ /**
144
+ * @typedef {Function} onValidateEnd
145
+ * @property {onValidateEndPayload} payload - Returns the payload of validate form hook
146
+ */
147
+
148
+ /**
149
+ * @typedef {Object} onValidateEndPayload
150
+ * @property {Object} data - Returns the form data
151
+ * @property {DataValidatorErrorResponse} errors - Returns the errors of validation if had
81
152
  */