@lara-node/validator 0.1.1 → 0.1.2

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.
Files changed (2) hide show
  1. package/README.md +218 -0
  2. package/package.json +1 -1
package/README.md ADDED
@@ -0,0 +1,218 @@
1
+ # @lara-node/validator
2
+
3
+ Laravel-inspired validation engine for Lara-Node applications.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ pnpm add @lara-node/validator
9
+ ```
10
+
11
+ ## Usage
12
+
13
+ ```typescript
14
+ import { validate, ValidationError } from '@lara-node/validator';
15
+
16
+ const data = await validate(req.body, {
17
+ name: 'required|string|min:2|max:100',
18
+ email: 'required|email|unique:users,email',
19
+ password: 'required|string|min:8|confirmed',
20
+ age: 'required|integer|min:18|max:120',
21
+ role: 'nullable|in:admin,user,moderator',
22
+ });
23
+ ```
24
+
25
+ If validation fails, a `ValidationError` is thrown with an `errors` map and `messages` array.
26
+
27
+ ## Built-in Rules
28
+
29
+ ### Presence
30
+ | Rule | Description |
31
+ |------|-------------|
32
+ | `required` | Field must be present and non-empty |
33
+ | `nullable` | Field may be null/undefined (stops further rules) |
34
+ | `sometimes` | Only validate if the field is present |
35
+
36
+ ### Type
37
+ | Rule | Description |
38
+ |------|-------------|
39
+ | `string` | Must be a string |
40
+ | `integer` | Must be an integer |
41
+ | `numeric` | Must be a number |
42
+ | `boolean` | Must be true/false/1/0/'true'/'false' |
43
+ | `array` | Must be an array |
44
+ | `json` | Must be valid JSON |
45
+
46
+ ### String
47
+ | Rule | Description |
48
+ |------|-------------|
49
+ | `min:n` | Minimum length (string) or value (number) |
50
+ | `max:n` | Maximum length (string) or value (number) |
51
+ | `between:min,max` | Length or value between min and max |
52
+ | `size:n` | Exact length |
53
+ | `email` | Valid email address |
54
+ | `url` | Valid URL |
55
+ | `uuid` | Valid UUID |
56
+ | `regex:/pattern/` | Must match regex |
57
+ | `starts_with:prefix` | Must start with prefix |
58
+ | `ends_with:suffix` | Must end with suffix |
59
+ | `contains:str` | Must contain str |
60
+ | `phone` | Valid phone number (E.164 or common formats) |
61
+
62
+ ### Comparison
63
+ | Rule | Description |
64
+ |------|-------------|
65
+ | `in:a,b,c` | Value must be one of the listed values |
66
+ | `not_in:a,b,c` | Value must not be one of the listed values |
67
+ | `gt:n` | Greater than n |
68
+ | `gte:n` | Greater than or equal to n |
69
+ | `lt:n` | Less than n |
70
+ | `lte:n` | Less than or equal to n |
71
+ | `same:field` | Must equal another field |
72
+ | `different:field` | Must not equal another field |
73
+ | `confirmed` | Must equal `field_confirmation` |
74
+ | `accepted` | Must be truthy (true/1/'yes'/'on') |
75
+ | `declined` | Must be falsy (false/0/'no'/'off') |
76
+
77
+ ### Date
78
+ | Rule | Description |
79
+ |------|-------------|
80
+ | `date` | Valid date string |
81
+ | `date_format:format` | Must match specific format |
82
+ | `before:date` | Must be before a given date |
83
+ | `after:date` | Must be after a given date |
84
+ | `time` | Valid time string (HH:MM or HH:MM:SS) |
85
+ | `datetime` | Valid datetime string |
86
+ | `timezone` | Valid timezone identifier |
87
+
88
+ ### Database
89
+ | Rule | Description |
90
+ |------|-------------|
91
+ | `exists:table,column` | Record must exist in DB |
92
+ | `unique:table,column` | Value must not exist in DB |
93
+
94
+ ## Rule Spec Objects
95
+
96
+ For more control, use a `RuleSpec` object instead of a pipe-delimited string:
97
+
98
+ ```typescript
99
+ const data = await validate(body, {
100
+ email: {
101
+ rule: 'required|email|unique:users,email',
102
+ message: 'Please provide a valid, unique email address.',
103
+ },
104
+ age: {
105
+ rule: 'required|integer|between:18,120',
106
+ messages: {
107
+ required: 'Age is required.',
108
+ between: 'You must be between 18 and 120 years old.',
109
+ },
110
+ },
111
+ });
112
+ ```
113
+
114
+ ## Custom Rule Functions
115
+
116
+ ```typescript
117
+ import { validate, RuleFn } from '@lara-node/validator';
118
+
119
+ const isEvenNumber: RuleFn = (value, field) => {
120
+ if (value % 2 !== 0) return `${field} must be an even number`;
121
+ return null;
122
+ };
123
+
124
+ await validate(body, { quantity: isEvenNumber });
125
+ ```
126
+
127
+ ## Conditional Rules
128
+
129
+ ```typescript
130
+ import { requiredIf, requiredUnless } from '@lara-node/validator';
131
+
132
+ await validate(body, {
133
+ // required only when type === 'business'
134
+ company_name: requiredIf('type', 'business'),
135
+
136
+ // required unless type is 'guest'
137
+ email: requiredUnless('type', 'guest'),
138
+ });
139
+ ```
140
+
141
+ ## File Validation
142
+
143
+ ```typescript
144
+ import { fileRule, mimes, maxFileSize } from '@lara-node/validator';
145
+
146
+ await validate({ file: req.file }, {
147
+ file: [
148
+ fileRule(), // must be a multer file object
149
+ mimes(['image/jpeg', 'image/png', 'image/webp']),
150
+ maxFileSize(5 * 1024 * 1024), // 5 MB
151
+ ],
152
+ });
153
+ ```
154
+
155
+ ## Nested Objects
156
+
157
+ ```typescript
158
+ import { nestedRule, arrayOfObjectsRule } from '@lara-node/validator';
159
+
160
+ await validate(body, {
161
+ address: nestedRule({
162
+ street: 'required|string',
163
+ city: 'required|string',
164
+ zip: 'required|string|min:4',
165
+ }),
166
+ items: arrayOfObjectsRule({
167
+ product_id: 'required|integer|exists:products,id',
168
+ quantity: 'required|integer|min:1',
169
+ }),
170
+ });
171
+ ```
172
+
173
+ ## Express Integration
174
+
175
+ The `@lara-node/middlewares` package attaches `req.validate()` via `ValidatorMiddleware`:
176
+
177
+ ```typescript
178
+ import { ValidatorMiddleware } from '@lara-node/middlewares';
179
+
180
+ app.use((req, res, next) => new ValidatorMiddleware().handle(req as any, res, next));
181
+
182
+ // In controllers:
183
+ const data = await req.validate({
184
+ email: 'required|email',
185
+ password: 'required|string|min:8',
186
+ });
187
+ ```
188
+
189
+ ## Error Handling
190
+
191
+ ```typescript
192
+ import { ValidationError } from '@lara-node/validator';
193
+
194
+ try {
195
+ const data = await validate(body, rules);
196
+ } catch (err) {
197
+ if (err instanceof ValidationError) {
198
+ console.log(err.errors); // { email: ['The email field is required.'] }
199
+ console.log(err.messages); // ['The email field is required.']
200
+ }
201
+ }
202
+ ```
203
+
204
+ The `ErrorHandlerMiddleware` from `@lara-node/middlewares` automatically catches `ValidationError` and returns HTTP 422.
205
+
206
+ ## Custom Messages
207
+
208
+ ```typescript
209
+ await validate(body, rules, {
210
+ 'name.required': 'Please enter your full name.',
211
+ 'email.email': 'That doesn\'t look like a valid email.',
212
+ 'age.min': 'You must be at least 18 years old.',
213
+ });
214
+ ```
215
+
216
+ ## License
217
+
218
+ MIT
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lara-node/validator",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
4
4
  "description": "Laravel-inspired validation engine for Lara-Node",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",