express5-valid 1.0.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 +314 -0
- package/dist/arg-error.d.mts +12 -0
- package/dist/arg-error.d.ts +12 -0
- package/dist/arg-error.d.ts.map +1 -0
- package/dist/index.d.mts +11 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +884 -0
- package/dist/index.js.map +7 -0
- package/dist/index.mjs +851 -0
- package/dist/index.mjs.map +7 -0
- package/dist/middleware.d.mts +10 -0
- package/dist/middleware.d.ts +10 -0
- package/dist/middleware.d.ts.map +1 -0
- package/dist/router.d.mts +14 -0
- package/dist/router.d.ts +14 -0
- package/dist/router.d.ts.map +1 -0
- package/dist/types.d.mts +17 -0
- package/dist/types.d.ts +17 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/valid-array.d.mts +28 -0
- package/dist/valid-array.d.ts +28 -0
- package/dist/valid-array.d.ts.map +1 -0
- package/dist/valid-base.d.mts +20 -0
- package/dist/valid-base.d.ts +20 -0
- package/dist/valid-base.d.ts.map +1 -0
- package/dist/valid-boolean.d.mts +14 -0
- package/dist/valid-boolean.d.ts +14 -0
- package/dist/valid-boolean.d.ts.map +1 -0
- package/dist/valid-date.d.mts +22 -0
- package/dist/valid-date.d.ts +22 -0
- package/dist/valid-date.d.ts.map +1 -0
- package/dist/valid-enum.d.mts +15 -0
- package/dist/valid-enum.d.ts +15 -0
- package/dist/valid-enum.d.ts.map +1 -0
- package/dist/valid-error-handler.d.mts +4 -0
- package/dist/valid-error-handler.d.ts +4 -0
- package/dist/valid-error-handler.d.ts.map +1 -0
- package/dist/valid-number.d.mts +27 -0
- package/dist/valid-number.d.ts +27 -0
- package/dist/valid-number.d.ts.map +1 -0
- package/dist/valid-object.d.mts +16 -0
- package/dist/valid-object.d.ts +16 -0
- package/dist/valid-object.d.ts.map +1 -0
- package/dist/valid-string.d.mts +32 -0
- package/dist/valid-string.d.ts +32 -0
- package/dist/valid-string.d.ts.map +1 -0
- package/package.json +70 -0
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,851 @@
|
|
|
1
|
+
// src/arg-error.ts
|
|
2
|
+
var ArgError = class extends Error {
|
|
3
|
+
field;
|
|
4
|
+
code;
|
|
5
|
+
details;
|
|
6
|
+
params;
|
|
7
|
+
constructor(field, code, details, params2 = {}) {
|
|
8
|
+
super(`${field} ${details}`);
|
|
9
|
+
this.field = field;
|
|
10
|
+
this.code = code;
|
|
11
|
+
this.details = details;
|
|
12
|
+
this.params = params2;
|
|
13
|
+
}
|
|
14
|
+
get msg() {
|
|
15
|
+
return this.details;
|
|
16
|
+
}
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
// src/valid-number.ts
|
|
20
|
+
var ValidNumber = class {
|
|
21
|
+
_value;
|
|
22
|
+
_name;
|
|
23
|
+
_isRequired = false;
|
|
24
|
+
_isNullable = false;
|
|
25
|
+
_default;
|
|
26
|
+
_min;
|
|
27
|
+
_max;
|
|
28
|
+
_isInteger = false;
|
|
29
|
+
_isPositive = false;
|
|
30
|
+
_isNegative = false;
|
|
31
|
+
_oneOf;
|
|
32
|
+
constructor(value, name) {
|
|
33
|
+
this._value = value;
|
|
34
|
+
this._name = name;
|
|
35
|
+
}
|
|
36
|
+
error(code, details, params2 = {}) {
|
|
37
|
+
throw new ArgError(`${this._name}`, code, details, params2);
|
|
38
|
+
}
|
|
39
|
+
get required() {
|
|
40
|
+
this._isRequired = true;
|
|
41
|
+
return this;
|
|
42
|
+
}
|
|
43
|
+
get nullable() {
|
|
44
|
+
this._isNullable = true;
|
|
45
|
+
return this;
|
|
46
|
+
}
|
|
47
|
+
default(v) {
|
|
48
|
+
this._default = v;
|
|
49
|
+
return this;
|
|
50
|
+
}
|
|
51
|
+
min(n) {
|
|
52
|
+
this._min = n;
|
|
53
|
+
return this;
|
|
54
|
+
}
|
|
55
|
+
max(n) {
|
|
56
|
+
this._max = n;
|
|
57
|
+
return this;
|
|
58
|
+
}
|
|
59
|
+
get integer() {
|
|
60
|
+
this._isInteger = true;
|
|
61
|
+
return this;
|
|
62
|
+
}
|
|
63
|
+
get positive() {
|
|
64
|
+
this._isPositive = true;
|
|
65
|
+
return this;
|
|
66
|
+
}
|
|
67
|
+
get negative() {
|
|
68
|
+
this._isNegative = true;
|
|
69
|
+
return this;
|
|
70
|
+
}
|
|
71
|
+
between(min, max) {
|
|
72
|
+
this._min = min;
|
|
73
|
+
this._max = max;
|
|
74
|
+
return this;
|
|
75
|
+
}
|
|
76
|
+
oneOf(values) {
|
|
77
|
+
this._oneOf = values;
|
|
78
|
+
return this;
|
|
79
|
+
}
|
|
80
|
+
get value() {
|
|
81
|
+
let val = this._value;
|
|
82
|
+
if (val === void 0 && this._default !== void 0) {
|
|
83
|
+
val = this._default;
|
|
84
|
+
}
|
|
85
|
+
if (val === void 0) {
|
|
86
|
+
if (this._isRequired) {
|
|
87
|
+
this.error("REQUIRED", "is required");
|
|
88
|
+
}
|
|
89
|
+
return void 0;
|
|
90
|
+
}
|
|
91
|
+
if (val === null) {
|
|
92
|
+
if (!this._isNullable) {
|
|
93
|
+
this.error("NOT_NULLABLE", "cannot be null");
|
|
94
|
+
}
|
|
95
|
+
return null;
|
|
96
|
+
}
|
|
97
|
+
let num;
|
|
98
|
+
if (typeof val === "number") {
|
|
99
|
+
num = val;
|
|
100
|
+
} else if (typeof val === "string") {
|
|
101
|
+
num = parseFloat(val);
|
|
102
|
+
} else {
|
|
103
|
+
this.error("INVALID_TYPE", "must be a number", { expected: "number" });
|
|
104
|
+
}
|
|
105
|
+
if (isNaN(num)) {
|
|
106
|
+
this.error("INVALID_NUMBER", "must be a valid number");
|
|
107
|
+
}
|
|
108
|
+
if (this._isInteger && !Number.isInteger(num)) {
|
|
109
|
+
this.error("NOT_INTEGER", "must be an integer");
|
|
110
|
+
}
|
|
111
|
+
if (this._isPositive && num <= 0) {
|
|
112
|
+
this.error("NOT_POSITIVE", "must be positive");
|
|
113
|
+
}
|
|
114
|
+
if (this._isNegative && num >= 0) {
|
|
115
|
+
this.error("NOT_NEGATIVE", "must be negative");
|
|
116
|
+
}
|
|
117
|
+
if (this._min !== void 0 && num < this._min) {
|
|
118
|
+
this.error("MIN_VALUE", `must be at least ${this._min}`, { min: this._min });
|
|
119
|
+
}
|
|
120
|
+
if (this._max !== void 0 && num > this._max) {
|
|
121
|
+
this.error("MAX_VALUE", `must be at most ${this._max}`, { max: this._max });
|
|
122
|
+
}
|
|
123
|
+
if (this._oneOf !== void 0 && !this._oneOf.includes(num)) {
|
|
124
|
+
this.error("NOT_IN_LIST", `must be one of: ${this._oneOf.join(", ")}`, { allowed: this._oneOf });
|
|
125
|
+
}
|
|
126
|
+
return num;
|
|
127
|
+
}
|
|
128
|
+
};
|
|
129
|
+
|
|
130
|
+
// src/valid-string.ts
|
|
131
|
+
var EMAIL_REGEX = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
132
|
+
var URL_REGEX = /^https?:\/\/.+/;
|
|
133
|
+
var ValidString = class {
|
|
134
|
+
_value;
|
|
135
|
+
_name;
|
|
136
|
+
_isRequired = false;
|
|
137
|
+
_isNullable = false;
|
|
138
|
+
_default;
|
|
139
|
+
_minLength;
|
|
140
|
+
_maxLength;
|
|
141
|
+
_pattern;
|
|
142
|
+
_isEmail = false;
|
|
143
|
+
_isUrl = false;
|
|
144
|
+
_shouldTrim = false;
|
|
145
|
+
_toLowercase = false;
|
|
146
|
+
_toUppercase = false;
|
|
147
|
+
_oneOf;
|
|
148
|
+
constructor(value, name) {
|
|
149
|
+
this._value = value;
|
|
150
|
+
this._name = name;
|
|
151
|
+
}
|
|
152
|
+
error(code, details, params2 = {}) {
|
|
153
|
+
throw new ArgError(`${this._name}`, code, details, params2);
|
|
154
|
+
}
|
|
155
|
+
get required() {
|
|
156
|
+
this._isRequired = true;
|
|
157
|
+
return this;
|
|
158
|
+
}
|
|
159
|
+
get nullable() {
|
|
160
|
+
this._isNullable = true;
|
|
161
|
+
return this;
|
|
162
|
+
}
|
|
163
|
+
default(v) {
|
|
164
|
+
this._default = v;
|
|
165
|
+
return this;
|
|
166
|
+
}
|
|
167
|
+
minLength(n) {
|
|
168
|
+
this._minLength = n;
|
|
169
|
+
return this;
|
|
170
|
+
}
|
|
171
|
+
maxLength(n) {
|
|
172
|
+
this._maxLength = n;
|
|
173
|
+
return this;
|
|
174
|
+
}
|
|
175
|
+
pattern(regex) {
|
|
176
|
+
this._pattern = regex;
|
|
177
|
+
return this;
|
|
178
|
+
}
|
|
179
|
+
get email() {
|
|
180
|
+
this._isEmail = true;
|
|
181
|
+
return this;
|
|
182
|
+
}
|
|
183
|
+
get url() {
|
|
184
|
+
this._isUrl = true;
|
|
185
|
+
return this;
|
|
186
|
+
}
|
|
187
|
+
get trim() {
|
|
188
|
+
this._shouldTrim = true;
|
|
189
|
+
return this;
|
|
190
|
+
}
|
|
191
|
+
get lowercase() {
|
|
192
|
+
this._toLowercase = true;
|
|
193
|
+
return this;
|
|
194
|
+
}
|
|
195
|
+
get uppercase() {
|
|
196
|
+
this._toUppercase = true;
|
|
197
|
+
return this;
|
|
198
|
+
}
|
|
199
|
+
oneOf(values) {
|
|
200
|
+
this._oneOf = values;
|
|
201
|
+
return this;
|
|
202
|
+
}
|
|
203
|
+
get value() {
|
|
204
|
+
let val = this._value;
|
|
205
|
+
if (val === void 0 && this._default !== void 0) {
|
|
206
|
+
val = this._default;
|
|
207
|
+
}
|
|
208
|
+
if (val === void 0) {
|
|
209
|
+
if (this._isRequired) {
|
|
210
|
+
this.error("REQUIRED", "is required");
|
|
211
|
+
}
|
|
212
|
+
return void 0;
|
|
213
|
+
}
|
|
214
|
+
if (val === null) {
|
|
215
|
+
if (!this._isNullable) {
|
|
216
|
+
this.error("NOT_NULLABLE", "cannot be null");
|
|
217
|
+
}
|
|
218
|
+
return null;
|
|
219
|
+
}
|
|
220
|
+
if (typeof val !== "string") {
|
|
221
|
+
this.error("INVALID_TYPE", "must be a string", { expected: "string" });
|
|
222
|
+
}
|
|
223
|
+
let str = val;
|
|
224
|
+
if (this._shouldTrim) {
|
|
225
|
+
str = str.trim();
|
|
226
|
+
}
|
|
227
|
+
if (this._toLowercase) {
|
|
228
|
+
str = str.toLowerCase();
|
|
229
|
+
}
|
|
230
|
+
if (this._toUppercase) {
|
|
231
|
+
str = str.toUpperCase();
|
|
232
|
+
}
|
|
233
|
+
if (this._minLength !== void 0 && str.length < this._minLength) {
|
|
234
|
+
this.error("MIN_LENGTH", `must be at least ${this._minLength} characters`, { min: this._minLength });
|
|
235
|
+
}
|
|
236
|
+
if (this._maxLength !== void 0 && str.length > this._maxLength) {
|
|
237
|
+
this.error("MAX_LENGTH", `must be at most ${this._maxLength} characters`, { max: this._maxLength });
|
|
238
|
+
}
|
|
239
|
+
if (this._pattern !== void 0 && !this._pattern.test(str)) {
|
|
240
|
+
this.error("PATTERN_MISMATCH", "does not match required pattern");
|
|
241
|
+
}
|
|
242
|
+
if (this._isEmail && !EMAIL_REGEX.test(str)) {
|
|
243
|
+
this.error("INVALID_EMAIL", "must be a valid email");
|
|
244
|
+
}
|
|
245
|
+
if (this._isUrl && !URL_REGEX.test(str)) {
|
|
246
|
+
this.error("INVALID_URL", "must be a valid URL");
|
|
247
|
+
}
|
|
248
|
+
if (this._oneOf !== void 0 && !this._oneOf.includes(str)) {
|
|
249
|
+
this.error("NOT_IN_LIST", `must be one of: ${this._oneOf.join(", ")}`, { allowed: this._oneOf });
|
|
250
|
+
}
|
|
251
|
+
return str;
|
|
252
|
+
}
|
|
253
|
+
};
|
|
254
|
+
|
|
255
|
+
// src/valid-boolean.ts
|
|
256
|
+
var ValidBoolean = class {
|
|
257
|
+
_value;
|
|
258
|
+
_name;
|
|
259
|
+
_isRequired = false;
|
|
260
|
+
_isNullable = false;
|
|
261
|
+
_default;
|
|
262
|
+
constructor(value, name) {
|
|
263
|
+
this._value = value;
|
|
264
|
+
this._name = name;
|
|
265
|
+
}
|
|
266
|
+
error(code, details) {
|
|
267
|
+
throw new ArgError(`${this._name}`, code, details);
|
|
268
|
+
}
|
|
269
|
+
get required() {
|
|
270
|
+
this._isRequired = true;
|
|
271
|
+
return this;
|
|
272
|
+
}
|
|
273
|
+
get nullable() {
|
|
274
|
+
this._isNullable = true;
|
|
275
|
+
return this;
|
|
276
|
+
}
|
|
277
|
+
default(v) {
|
|
278
|
+
this._default = v;
|
|
279
|
+
return this;
|
|
280
|
+
}
|
|
281
|
+
get value() {
|
|
282
|
+
let val = this._value;
|
|
283
|
+
if (val === void 0 && this._default !== void 0) {
|
|
284
|
+
val = this._default;
|
|
285
|
+
}
|
|
286
|
+
if (val === void 0) {
|
|
287
|
+
if (this._isRequired) {
|
|
288
|
+
this.error("REQUIRED", "is required");
|
|
289
|
+
}
|
|
290
|
+
return void 0;
|
|
291
|
+
}
|
|
292
|
+
if (val === null) {
|
|
293
|
+
if (!this._isNullable) {
|
|
294
|
+
this.error("NOT_NULLABLE", "cannot be null");
|
|
295
|
+
}
|
|
296
|
+
return null;
|
|
297
|
+
}
|
|
298
|
+
let bool;
|
|
299
|
+
if (typeof val === "boolean") {
|
|
300
|
+
bool = val;
|
|
301
|
+
} else if (val === "true" || val === 1) {
|
|
302
|
+
bool = true;
|
|
303
|
+
} else if (val === "false" || val === 0) {
|
|
304
|
+
bool = false;
|
|
305
|
+
} else {
|
|
306
|
+
this.error("INVALID_TYPE", "must be a boolean");
|
|
307
|
+
}
|
|
308
|
+
return bool;
|
|
309
|
+
}
|
|
310
|
+
};
|
|
311
|
+
|
|
312
|
+
// src/valid-array.ts
|
|
313
|
+
var EMAIL_REGEX2 = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
314
|
+
var URL_REGEX2 = /^https?:\/\/.+/;
|
|
315
|
+
var ValidArray = class {
|
|
316
|
+
_value;
|
|
317
|
+
_name;
|
|
318
|
+
_isRequired = false;
|
|
319
|
+
_isNullable = false;
|
|
320
|
+
_default;
|
|
321
|
+
_minLength;
|
|
322
|
+
_maxLength;
|
|
323
|
+
_elementValidator;
|
|
324
|
+
constructor(value, name) {
|
|
325
|
+
this._value = value;
|
|
326
|
+
this._name = name;
|
|
327
|
+
}
|
|
328
|
+
error(code, details, params2 = {}) {
|
|
329
|
+
throw new ArgError(`${this._name}`, code, details, params2);
|
|
330
|
+
}
|
|
331
|
+
elementError(code, details, index, params2 = {}) {
|
|
332
|
+
throw new ArgError(
|
|
333
|
+
`${this._name}`,
|
|
334
|
+
"ARRAY_ELEMENT",
|
|
335
|
+
`element at index ${index} ${details}`,
|
|
336
|
+
{ index, code, ...params2 }
|
|
337
|
+
);
|
|
338
|
+
}
|
|
339
|
+
get required() {
|
|
340
|
+
this._isRequired = true;
|
|
341
|
+
return this;
|
|
342
|
+
}
|
|
343
|
+
get nullable() {
|
|
344
|
+
this._isNullable = true;
|
|
345
|
+
return this;
|
|
346
|
+
}
|
|
347
|
+
default(v) {
|
|
348
|
+
this._default = v;
|
|
349
|
+
return this;
|
|
350
|
+
}
|
|
351
|
+
minLength(n) {
|
|
352
|
+
this._minLength = n;
|
|
353
|
+
return this;
|
|
354
|
+
}
|
|
355
|
+
maxLength(n) {
|
|
356
|
+
this._maxLength = n;
|
|
357
|
+
return this;
|
|
358
|
+
}
|
|
359
|
+
ofNumbers(config) {
|
|
360
|
+
this._elementValidator = (val, index) => {
|
|
361
|
+
let num;
|
|
362
|
+
if (typeof val === "number") {
|
|
363
|
+
num = val;
|
|
364
|
+
} else if (typeof val === "string") {
|
|
365
|
+
num = parseFloat(val);
|
|
366
|
+
} else {
|
|
367
|
+
this.elementError("INVALID_TYPE", "must be a number", index, { expected: "number" });
|
|
368
|
+
}
|
|
369
|
+
if (isNaN(num)) {
|
|
370
|
+
this.elementError("INVALID_NUMBER", "must be a valid number", index);
|
|
371
|
+
}
|
|
372
|
+
if (config) {
|
|
373
|
+
if (config.integer && !Number.isInteger(num)) {
|
|
374
|
+
this.elementError("NOT_INTEGER", "must be an integer", index);
|
|
375
|
+
}
|
|
376
|
+
if (config.positive && num <= 0) {
|
|
377
|
+
this.elementError("NOT_POSITIVE", "must be positive", index);
|
|
378
|
+
}
|
|
379
|
+
if (config.negative && num >= 0) {
|
|
380
|
+
this.elementError("NOT_NEGATIVE", "must be negative", index);
|
|
381
|
+
}
|
|
382
|
+
if (config.min !== void 0 && num < config.min) {
|
|
383
|
+
this.elementError("MIN_VALUE", `must be at least ${config.min}`, index, { min: config.min });
|
|
384
|
+
}
|
|
385
|
+
if (config.max !== void 0 && num > config.max) {
|
|
386
|
+
this.elementError("MAX_VALUE", `must be at most ${config.max}`, index, { max: config.max });
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
return num;
|
|
390
|
+
};
|
|
391
|
+
return this;
|
|
392
|
+
}
|
|
393
|
+
ofStrings(config) {
|
|
394
|
+
this._elementValidator = (val, index) => {
|
|
395
|
+
if (typeof val !== "string") {
|
|
396
|
+
this.elementError("INVALID_TYPE", "must be a string", index, { expected: "string" });
|
|
397
|
+
}
|
|
398
|
+
let str = val;
|
|
399
|
+
if (config) {
|
|
400
|
+
if (config.trim) {
|
|
401
|
+
str = str.trim();
|
|
402
|
+
}
|
|
403
|
+
if (config.minLength !== void 0 && str.length < config.minLength) {
|
|
404
|
+
this.elementError("MIN_LENGTH", `must be at least ${config.minLength} characters`, index, { min: config.minLength });
|
|
405
|
+
}
|
|
406
|
+
if (config.maxLength !== void 0 && str.length > config.maxLength) {
|
|
407
|
+
this.elementError("MAX_LENGTH", `must be at most ${config.maxLength} characters`, index, { max: config.maxLength });
|
|
408
|
+
}
|
|
409
|
+
if (config.pattern && !config.pattern.test(str)) {
|
|
410
|
+
this.elementError("PATTERN_MISMATCH", "does not match required pattern", index);
|
|
411
|
+
}
|
|
412
|
+
if (config.email && !EMAIL_REGEX2.test(str)) {
|
|
413
|
+
this.elementError("INVALID_EMAIL", "must be a valid email", index);
|
|
414
|
+
}
|
|
415
|
+
if (config.url && !URL_REGEX2.test(str)) {
|
|
416
|
+
this.elementError("INVALID_URL", "must be a valid URL", index);
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
return str;
|
|
420
|
+
};
|
|
421
|
+
return this;
|
|
422
|
+
}
|
|
423
|
+
ofBooleans() {
|
|
424
|
+
this._elementValidator = (val, index) => {
|
|
425
|
+
if (typeof val === "boolean") {
|
|
426
|
+
return val;
|
|
427
|
+
}
|
|
428
|
+
if (val === "true" || val === 1) {
|
|
429
|
+
return true;
|
|
430
|
+
}
|
|
431
|
+
if (val === "false" || val === 0) {
|
|
432
|
+
return false;
|
|
433
|
+
}
|
|
434
|
+
this.elementError("INVALID_TYPE", "must be a boolean", index, { expected: "boolean" });
|
|
435
|
+
};
|
|
436
|
+
return this;
|
|
437
|
+
}
|
|
438
|
+
ofObjects(validator) {
|
|
439
|
+
this._elementValidator = (val, index) => {
|
|
440
|
+
if (val === null || typeof val !== "object" || Array.isArray(val)) {
|
|
441
|
+
this.elementError("INVALID_TYPE", "must be an object", index, { expected: "object" });
|
|
442
|
+
}
|
|
443
|
+
try {
|
|
444
|
+
return validator(val, index);
|
|
445
|
+
} catch (e) {
|
|
446
|
+
if (e instanceof ArgError) {
|
|
447
|
+
throw new ArgError(
|
|
448
|
+
`${this._name}[${index}].${e.field}`,
|
|
449
|
+
e.code,
|
|
450
|
+
e.details,
|
|
451
|
+
e.params
|
|
452
|
+
);
|
|
453
|
+
}
|
|
454
|
+
throw e;
|
|
455
|
+
}
|
|
456
|
+
};
|
|
457
|
+
return this;
|
|
458
|
+
}
|
|
459
|
+
get value() {
|
|
460
|
+
let val = this._value;
|
|
461
|
+
if (val === void 0 && this._default !== void 0) {
|
|
462
|
+
val = this._default;
|
|
463
|
+
}
|
|
464
|
+
if (val === void 0) {
|
|
465
|
+
if (this._isRequired) {
|
|
466
|
+
this.error("REQUIRED", "is required");
|
|
467
|
+
}
|
|
468
|
+
return void 0;
|
|
469
|
+
}
|
|
470
|
+
if (val === null) {
|
|
471
|
+
if (!this._isNullable) {
|
|
472
|
+
this.error("NOT_NULLABLE", "cannot be null");
|
|
473
|
+
}
|
|
474
|
+
return null;
|
|
475
|
+
}
|
|
476
|
+
if (!Array.isArray(val)) {
|
|
477
|
+
this.error("INVALID_TYPE", "must be an array", { expected: "array" });
|
|
478
|
+
}
|
|
479
|
+
if (this._minLength !== void 0 && val.length < this._minLength) {
|
|
480
|
+
this.error("ARRAY_MIN_LENGTH", `must have at least ${this._minLength} elements`, { min: this._minLength });
|
|
481
|
+
}
|
|
482
|
+
if (this._maxLength !== void 0 && val.length > this._maxLength) {
|
|
483
|
+
this.error("ARRAY_MAX_LENGTH", `must have at most ${this._maxLength} elements`, { max: this._maxLength });
|
|
484
|
+
}
|
|
485
|
+
if (this._elementValidator) {
|
|
486
|
+
const validated = val.map((item, index) => this._elementValidator(item, index));
|
|
487
|
+
return validated;
|
|
488
|
+
}
|
|
489
|
+
return val;
|
|
490
|
+
}
|
|
491
|
+
};
|
|
492
|
+
|
|
493
|
+
// src/valid-date.ts
|
|
494
|
+
var ValidDate = class {
|
|
495
|
+
_value;
|
|
496
|
+
_name;
|
|
497
|
+
_isRequired = false;
|
|
498
|
+
_isNullable = false;
|
|
499
|
+
_default;
|
|
500
|
+
_min;
|
|
501
|
+
_max;
|
|
502
|
+
_isPast = false;
|
|
503
|
+
_isFuture = false;
|
|
504
|
+
constructor(value, name) {
|
|
505
|
+
this._value = value;
|
|
506
|
+
this._name = name;
|
|
507
|
+
}
|
|
508
|
+
error(code, details, params2 = {}) {
|
|
509
|
+
throw new ArgError(`${this._name}`, code, details, params2);
|
|
510
|
+
}
|
|
511
|
+
get required() {
|
|
512
|
+
this._isRequired = true;
|
|
513
|
+
return this;
|
|
514
|
+
}
|
|
515
|
+
get nullable() {
|
|
516
|
+
this._isNullable = true;
|
|
517
|
+
return this;
|
|
518
|
+
}
|
|
519
|
+
default(v) {
|
|
520
|
+
this._default = v;
|
|
521
|
+
return this;
|
|
522
|
+
}
|
|
523
|
+
min(date) {
|
|
524
|
+
this._min = date;
|
|
525
|
+
return this;
|
|
526
|
+
}
|
|
527
|
+
max(date) {
|
|
528
|
+
this._max = date;
|
|
529
|
+
return this;
|
|
530
|
+
}
|
|
531
|
+
get past() {
|
|
532
|
+
this._isPast = true;
|
|
533
|
+
return this;
|
|
534
|
+
}
|
|
535
|
+
get future() {
|
|
536
|
+
this._isFuture = true;
|
|
537
|
+
return this;
|
|
538
|
+
}
|
|
539
|
+
get value() {
|
|
540
|
+
let val = this._value;
|
|
541
|
+
if (val === void 0 && this._default !== void 0) {
|
|
542
|
+
val = this._default;
|
|
543
|
+
}
|
|
544
|
+
if (val === void 0) {
|
|
545
|
+
if (this._isRequired) {
|
|
546
|
+
this.error("REQUIRED", "is required");
|
|
547
|
+
}
|
|
548
|
+
return void 0;
|
|
549
|
+
}
|
|
550
|
+
if (val === null) {
|
|
551
|
+
if (!this._isNullable) {
|
|
552
|
+
this.error("NOT_NULLABLE", "cannot be null");
|
|
553
|
+
}
|
|
554
|
+
return null;
|
|
555
|
+
}
|
|
556
|
+
let date;
|
|
557
|
+
if (val instanceof Date) {
|
|
558
|
+
date = val;
|
|
559
|
+
} else if (typeof val === "string" || typeof val === "number") {
|
|
560
|
+
date = new Date(val);
|
|
561
|
+
} else {
|
|
562
|
+
this.error("INVALID_TYPE", "must be a date", { expected: "date" });
|
|
563
|
+
}
|
|
564
|
+
if (isNaN(date.getTime())) {
|
|
565
|
+
this.error("INVALID_DATE", "must be a valid date");
|
|
566
|
+
}
|
|
567
|
+
const now = /* @__PURE__ */ new Date();
|
|
568
|
+
if (this._isPast && date >= now) {
|
|
569
|
+
this.error("DATE_NOT_PAST", "must be in the past");
|
|
570
|
+
}
|
|
571
|
+
if (this._isFuture && date <= now) {
|
|
572
|
+
this.error("DATE_NOT_FUTURE", "must be in the future");
|
|
573
|
+
}
|
|
574
|
+
if (this._min !== void 0 && date < this._min) {
|
|
575
|
+
this.error("DATE_MIN", `must be after ${this._min.toISOString()}`, { min: this._min.toISOString() });
|
|
576
|
+
}
|
|
577
|
+
if (this._max !== void 0 && date > this._max) {
|
|
578
|
+
this.error("DATE_MAX", `must be before ${this._max.toISOString()}`, { max: this._max.toISOString() });
|
|
579
|
+
}
|
|
580
|
+
return date;
|
|
581
|
+
}
|
|
582
|
+
};
|
|
583
|
+
|
|
584
|
+
// src/valid-enum.ts
|
|
585
|
+
var ValidEnum = class {
|
|
586
|
+
_value;
|
|
587
|
+
_name;
|
|
588
|
+
_allowedValues;
|
|
589
|
+
_isRequired = false;
|
|
590
|
+
_isNullable = false;
|
|
591
|
+
_default;
|
|
592
|
+
constructor(value, name, allowedValues) {
|
|
593
|
+
this._value = value;
|
|
594
|
+
this._name = name;
|
|
595
|
+
this._allowedValues = allowedValues;
|
|
596
|
+
}
|
|
597
|
+
error(code, details, params2 = {}) {
|
|
598
|
+
throw new ArgError(`${this._name}`, code, details, params2);
|
|
599
|
+
}
|
|
600
|
+
get required() {
|
|
601
|
+
this._isRequired = true;
|
|
602
|
+
return this;
|
|
603
|
+
}
|
|
604
|
+
get nullable() {
|
|
605
|
+
this._isNullable = true;
|
|
606
|
+
return this;
|
|
607
|
+
}
|
|
608
|
+
default(v) {
|
|
609
|
+
this._default = v;
|
|
610
|
+
return this;
|
|
611
|
+
}
|
|
612
|
+
get value() {
|
|
613
|
+
let val = this._value;
|
|
614
|
+
if (val === void 0 && this._default !== void 0) {
|
|
615
|
+
val = this._default;
|
|
616
|
+
}
|
|
617
|
+
if (val === void 0) {
|
|
618
|
+
if (this._isRequired) {
|
|
619
|
+
this.error("REQUIRED", "is required");
|
|
620
|
+
}
|
|
621
|
+
return void 0;
|
|
622
|
+
}
|
|
623
|
+
if (val === null) {
|
|
624
|
+
if (!this._isNullable) {
|
|
625
|
+
this.error("NOT_NULLABLE", "cannot be null");
|
|
626
|
+
}
|
|
627
|
+
return null;
|
|
628
|
+
}
|
|
629
|
+
if (!this._allowedValues.includes(val)) {
|
|
630
|
+
this.error("NOT_IN_LIST", `must be one of: ${this._allowedValues.join(", ")}`, { allowed: this._allowedValues });
|
|
631
|
+
}
|
|
632
|
+
return val;
|
|
633
|
+
}
|
|
634
|
+
};
|
|
635
|
+
|
|
636
|
+
// src/valid-object.ts
|
|
637
|
+
var ValidObject = class {
|
|
638
|
+
_value;
|
|
639
|
+
_name;
|
|
640
|
+
_validator;
|
|
641
|
+
_isRequired = false;
|
|
642
|
+
_isNullable = false;
|
|
643
|
+
_default;
|
|
644
|
+
constructor(value, name, validator) {
|
|
645
|
+
this._value = value;
|
|
646
|
+
this._name = name;
|
|
647
|
+
this._validator = validator;
|
|
648
|
+
}
|
|
649
|
+
error(code, details, params2 = {}) {
|
|
650
|
+
throw new ArgError(`${this._name}`, code, details, params2);
|
|
651
|
+
}
|
|
652
|
+
get required() {
|
|
653
|
+
this._isRequired = true;
|
|
654
|
+
return this;
|
|
655
|
+
}
|
|
656
|
+
get nullable() {
|
|
657
|
+
this._isNullable = true;
|
|
658
|
+
return this;
|
|
659
|
+
}
|
|
660
|
+
default(v) {
|
|
661
|
+
this._default = v;
|
|
662
|
+
return this;
|
|
663
|
+
}
|
|
664
|
+
get value() {
|
|
665
|
+
let val = this._value;
|
|
666
|
+
if (val === void 0 && this._default !== void 0) {
|
|
667
|
+
val = this._default;
|
|
668
|
+
}
|
|
669
|
+
if (val === void 0) {
|
|
670
|
+
if (this._isRequired) {
|
|
671
|
+
this.error("REQUIRED", "is required");
|
|
672
|
+
}
|
|
673
|
+
return void 0;
|
|
674
|
+
}
|
|
675
|
+
if (val === null) {
|
|
676
|
+
if (!this._isNullable) {
|
|
677
|
+
this.error("NOT_NULLABLE", "cannot be null");
|
|
678
|
+
}
|
|
679
|
+
return null;
|
|
680
|
+
}
|
|
681
|
+
if (typeof val !== "object" || Array.isArray(val)) {
|
|
682
|
+
this.error("INVALID_TYPE", "must be an object", { expected: "object" });
|
|
683
|
+
}
|
|
684
|
+
try {
|
|
685
|
+
const validated = this._validator(val);
|
|
686
|
+
return validated;
|
|
687
|
+
} catch (e) {
|
|
688
|
+
if (e instanceof ArgError) {
|
|
689
|
+
throw new ArgError(
|
|
690
|
+
`${this._name}.${e.field}`,
|
|
691
|
+
e.code,
|
|
692
|
+
e.details,
|
|
693
|
+
e.params
|
|
694
|
+
);
|
|
695
|
+
}
|
|
696
|
+
throw e;
|
|
697
|
+
}
|
|
698
|
+
}
|
|
699
|
+
};
|
|
700
|
+
|
|
701
|
+
// src/valid-base.ts
|
|
702
|
+
var ValidBase = class {
|
|
703
|
+
_value;
|
|
704
|
+
_name;
|
|
705
|
+
constructor(value, name) {
|
|
706
|
+
this._value = value;
|
|
707
|
+
this._name = name;
|
|
708
|
+
}
|
|
709
|
+
get number() {
|
|
710
|
+
return new ValidNumber(this._value, this._name);
|
|
711
|
+
}
|
|
712
|
+
get string() {
|
|
713
|
+
return new ValidString(this._value, this._name);
|
|
714
|
+
}
|
|
715
|
+
get boolean() {
|
|
716
|
+
return new ValidBoolean(this._value, this._name);
|
|
717
|
+
}
|
|
718
|
+
get array() {
|
|
719
|
+
return new ValidArray(this._value, this._name);
|
|
720
|
+
}
|
|
721
|
+
get date() {
|
|
722
|
+
return new ValidDate(this._value, this._name);
|
|
723
|
+
}
|
|
724
|
+
enum(allowedValues) {
|
|
725
|
+
return new ValidEnum(this._value, this._name, allowedValues);
|
|
726
|
+
}
|
|
727
|
+
object(validator) {
|
|
728
|
+
return new ValidObject(this._value, this._name, validator);
|
|
729
|
+
}
|
|
730
|
+
};
|
|
731
|
+
|
|
732
|
+
// src/middleware.ts
|
|
733
|
+
import { AsyncLocalStorage } from "node:async_hooks";
|
|
734
|
+
var requestStorage = new AsyncLocalStorage();
|
|
735
|
+
function getContext() {
|
|
736
|
+
const ctx = requestStorage.getStore();
|
|
737
|
+
if (!ctx) {
|
|
738
|
+
throw new Error("body/params must be called inside validMiddleware context");
|
|
739
|
+
}
|
|
740
|
+
return ctx;
|
|
741
|
+
}
|
|
742
|
+
function validMiddleware(req, _res, next) {
|
|
743
|
+
const context = {
|
|
744
|
+
body: req.body,
|
|
745
|
+
params: req.params
|
|
746
|
+
};
|
|
747
|
+
requestStorage.run(context, next);
|
|
748
|
+
}
|
|
749
|
+
|
|
750
|
+
// src/valid-error-handler.ts
|
|
751
|
+
var validErrorHandler = (error, req, res, next) => {
|
|
752
|
+
if (error instanceof ArgError) {
|
|
753
|
+
res.status(400).json({
|
|
754
|
+
error: error.message,
|
|
755
|
+
code: 400,
|
|
756
|
+
errorCode: error.code,
|
|
757
|
+
params: error.params,
|
|
758
|
+
field: error.field,
|
|
759
|
+
url: req.originalUrl,
|
|
760
|
+
message: error.msg
|
|
761
|
+
});
|
|
762
|
+
} else {
|
|
763
|
+
next(error);
|
|
764
|
+
}
|
|
765
|
+
};
|
|
766
|
+
var valid_error_handler_default = validErrorHandler;
|
|
767
|
+
|
|
768
|
+
// src/router.ts
|
|
769
|
+
import { Router } from "express";
|
|
770
|
+
function wrapHandler(handler) {
|
|
771
|
+
return async (req, res, next) => {
|
|
772
|
+
const context = {
|
|
773
|
+
body: req.body,
|
|
774
|
+
params: req.params
|
|
775
|
+
};
|
|
776
|
+
requestStorage.run(context, async () => {
|
|
777
|
+
try {
|
|
778
|
+
const result = await handler(req, res);
|
|
779
|
+
if (res.headersSent) {
|
|
780
|
+
return;
|
|
781
|
+
}
|
|
782
|
+
if (result === void 0 || result === null) {
|
|
783
|
+
res.status(204).end();
|
|
784
|
+
} else {
|
|
785
|
+
res.json(result);
|
|
786
|
+
}
|
|
787
|
+
} catch (error) {
|
|
788
|
+
next(error);
|
|
789
|
+
}
|
|
790
|
+
});
|
|
791
|
+
};
|
|
792
|
+
}
|
|
793
|
+
function createJsonRouter() {
|
|
794
|
+
const expressRouter = Router();
|
|
795
|
+
const jsonRouter = {
|
|
796
|
+
router: expressRouter,
|
|
797
|
+
get: (path, handler, ...middlewares) => {
|
|
798
|
+
expressRouter.get(path, ...middlewares, wrapHandler(handler));
|
|
799
|
+
return jsonRouter;
|
|
800
|
+
},
|
|
801
|
+
post: (path, handler, ...middlewares) => {
|
|
802
|
+
expressRouter.post(path, ...middlewares, wrapHandler(handler));
|
|
803
|
+
return jsonRouter;
|
|
804
|
+
},
|
|
805
|
+
put: (path, handler, ...middlewares) => {
|
|
806
|
+
expressRouter.put(path, ...middlewares, wrapHandler(handler));
|
|
807
|
+
return jsonRouter;
|
|
808
|
+
},
|
|
809
|
+
patch: (path, handler, ...middlewares) => {
|
|
810
|
+
expressRouter.patch(path, ...middlewares, wrapHandler(handler));
|
|
811
|
+
return jsonRouter;
|
|
812
|
+
},
|
|
813
|
+
delete: (path, handler, ...middlewares) => {
|
|
814
|
+
expressRouter.delete(path, ...middlewares, wrapHandler(handler));
|
|
815
|
+
return jsonRouter;
|
|
816
|
+
}
|
|
817
|
+
};
|
|
818
|
+
return jsonRouter;
|
|
819
|
+
}
|
|
820
|
+
|
|
821
|
+
// src/index.ts
|
|
822
|
+
function body(name) {
|
|
823
|
+
const ctx = getContext();
|
|
824
|
+
if (ctx.body === void 0) {
|
|
825
|
+
throw new ArgError("body", "BODY_UNDEFINED", "body must be defined");
|
|
826
|
+
}
|
|
827
|
+
if (ctx.body === null) {
|
|
828
|
+
throw new ArgError("body", "BODY_NULL", "body must not be null");
|
|
829
|
+
}
|
|
830
|
+
if (Array.isArray(ctx.body)) {
|
|
831
|
+
throw new ArgError("body", "BODY_ARRAY", "body must not be an array");
|
|
832
|
+
}
|
|
833
|
+
return validArgument(ctx.body, name);
|
|
834
|
+
}
|
|
835
|
+
function params(name) {
|
|
836
|
+
const ctx = getContext();
|
|
837
|
+
return validArgument(ctx.params, name);
|
|
838
|
+
}
|
|
839
|
+
function validArgument(obj, name) {
|
|
840
|
+
return new ValidBase(obj[name], name);
|
|
841
|
+
}
|
|
842
|
+
export {
|
|
843
|
+
ArgError,
|
|
844
|
+
body,
|
|
845
|
+
createJsonRouter,
|
|
846
|
+
params,
|
|
847
|
+
validArgument,
|
|
848
|
+
valid_error_handler_default as validErrorHandler,
|
|
849
|
+
validMiddleware
|
|
850
|
+
};
|
|
851
|
+
//# sourceMappingURL=index.mjs.map
|