@linktic/validator 1.0.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.
@@ -0,0 +1,159 @@
1
+ import { V as ValidationMessageMap } from './es-QPgrpTLv.js';
2
+ export { s as spanishMessages } from './es-QPgrpTLv.js';
3
+
4
+ interface ValidationFieldError {
5
+ field: string;
6
+ message: string;
7
+ rule: string;
8
+ value?: unknown;
9
+ }
10
+
11
+ type ValidationType = 'string' | 'number' | 'boolean' | 'array' | 'object' | 'date' | 'email' | 'uuid';
12
+ interface ValidationRuleConfig {
13
+ required?: boolean;
14
+ type?: ValidationType;
15
+ minLength?: number;
16
+ maxLength?: number;
17
+ min?: number;
18
+ max?: number;
19
+ pattern?: RegExp;
20
+ patternExample?: string;
21
+ enum?: unknown[];
22
+ allowedChars?: string;
23
+ custom?: (value: unknown) => boolean | string;
24
+ }
25
+ interface FieldValidationConfig extends ValidationRuleConfig {
26
+ field: string;
27
+ label?: string;
28
+ messages?: Partial<Record<keyof ValidationRuleConfig, string>>;
29
+ }
30
+ interface SchemaValidationConfig {
31
+ [field: string]: ValidationRuleConfig & {
32
+ label?: string;
33
+ messages?: Partial<Record<keyof ValidationRuleConfig, string>>;
34
+ };
35
+ }
36
+ interface ValidationResult {
37
+ isValid: boolean;
38
+ errors: ValidationFieldError[];
39
+ }
40
+
41
+ interface ValidatorOptions {
42
+ stopOnFirstError?: boolean;
43
+ throwOnError?: boolean;
44
+ }
45
+ declare class FieldValidator {
46
+ private readonly fieldName;
47
+ private readonly fieldLabel;
48
+ private readonly value;
49
+ private readonly options;
50
+ private readonly parentErrors;
51
+ private readonly errors;
52
+ private isOptional;
53
+ constructor(fieldName: string, fieldLabel: string, value: unknown, options: ValidatorOptions, parentErrors: ValidationFieldError[]);
54
+ private get isEmpty();
55
+ private addError;
56
+ private shouldSkip;
57
+ optional(): this;
58
+ required(message?: string): this;
59
+ string(message?: string): this;
60
+ number(message?: string): this;
61
+ boolean(message?: string): this;
62
+ array(message?: string): this;
63
+ object(message?: string): this;
64
+ type(expectedType: ValidationType, message?: string): this;
65
+ minLength(min: number, message?: string): this;
66
+ maxLength(max: number, message?: string): this;
67
+ private getLength;
68
+ min(minValue: number, message?: string): this;
69
+ max(maxValue: number, message?: string): this;
70
+ range(minValue: number, maxValue: number, message?: string): this;
71
+ pattern(regex: RegExp, example?: string, message?: string): this;
72
+ email(message?: string): this;
73
+ uuid(message?: string): this;
74
+ date(message?: string): this;
75
+ enum(allowedValues: unknown[], message?: string): this;
76
+ allowedChars(chars: string, message?: string): this;
77
+ custom(validator: (value: unknown) => boolean | string, message?: string): this;
78
+ nullable(): this;
79
+ }
80
+ declare class Validator<T extends object = object> {
81
+ private readonly data;
82
+ private readonly errors;
83
+ private readonly options;
84
+ constructor(data: T, options?: ValidatorOptions);
85
+ field(fieldName: string, label?: string): FieldValidator;
86
+ private getNestedValue;
87
+ schema(config: SchemaValidationConfig): this;
88
+ validate(): void;
89
+ getResult(): ValidationResult;
90
+ getErrors(): ValidationFieldError[];
91
+ isValid(): boolean;
92
+ hasErrors(): boolean;
93
+ reset(): this;
94
+ }
95
+ declare const validate: <T extends object>(data: T, options?: ValidatorOptions) => Validator<T>;
96
+
97
+ declare class DomainError extends Error {
98
+ readonly code: string;
99
+ readonly statusCode?: number | undefined;
100
+ readonly metadata?: Record<string, unknown> | undefined;
101
+ constructor(message: string, code: string, statusCode?: number | undefined, metadata?: Record<string, unknown> | undefined);
102
+ }
103
+
104
+ declare class ValidationError extends DomainError {
105
+ readonly errors: ValidationFieldError[];
106
+ constructor(errors: ValidationFieldError[]);
107
+ static single(field: string, message: string, rule: string, value?: unknown): ValidationError;
108
+ hasFieldError(field: string): boolean;
109
+ getFieldErrors(field: string): ValidationFieldError[];
110
+ getFirstError(): ValidationFieldError | undefined;
111
+ }
112
+
113
+ declare function interpolate(template: string, params: Record<string, unknown>): string;
114
+
115
+ declare const ValidationMessages: {
116
+ required: (campo: string) => string;
117
+ pattern: (campo: string, ejemplo: string) => string;
118
+ maxLength: (campo: string, max: number, actual: number) => string;
119
+ minLength: (campo: string, min: number) => string;
120
+ range: (campo: string, min: number, max: number) => string;
121
+ date: (campo: string) => string;
122
+ allowedChars: (campo: string, permitidos: string) => string;
123
+ email: () => string;
124
+ string: (campo: string) => string;
125
+ number: (campo: string) => string;
126
+ boolean: (campo: string) => string;
127
+ array: (campo: string) => string;
128
+ object: (campo: string) => string;
129
+ uuid: (campo: string) => string;
130
+ enum: (campo: string, valores: unknown[]) => string;
131
+ custom: (campo: string) => string;
132
+ };
133
+
134
+ /**
135
+ * Replace ALL messages at once.
136
+ * Useful for full locale swaps (e.g., switching to English).
137
+ */
138
+ declare function setMessages(messages: ValidationMessageMap): void;
139
+ /**
140
+ * Merge partial overrides on top of current messages.
141
+ * Useful for customizing only a few messages while keeping the rest.
142
+ *
143
+ * @example
144
+ * configure({
145
+ * required: (campo) => `${campo} is required`,
146
+ * email: () => 'Invalid email address',
147
+ * })
148
+ */
149
+ declare function configure(overrides: Partial<ValidationMessageMap>): void;
150
+ /**
151
+ * Reset to Spanish defaults.
152
+ */
153
+ declare function resetMessages(): void;
154
+ /**
155
+ * Get the currently active message map. Used internally by ValidationRules.
156
+ */
157
+ declare function getMessages(): ValidationMessageMap;
158
+
159
+ export { DomainError, type FieldValidationConfig, type SchemaValidationConfig, ValidationError, type ValidationFieldError, ValidationMessageMap, ValidationMessages, type ValidationResult, type ValidationRuleConfig, type ValidationType, Validator, configure, getMessages, interpolate, resetMessages, setMessages, validate };
package/dist/index.js ADDED
@@ -0,0 +1,437 @@
1
+ import { spanishMessages } from './chunk-5LU5LI4H.js';
2
+ export { interpolate, spanishMessages } from './chunk-5LU5LI4H.js';
3
+
4
+ // src/errors/DomainError.ts
5
+ var DomainError = class extends Error {
6
+ constructor(message, code, statusCode, metadata) {
7
+ super(message);
8
+ this.code = code;
9
+ this.statusCode = statusCode;
10
+ this.metadata = metadata;
11
+ this.name = this.constructor.name;
12
+ Object.setPrototypeOf(this, new.target.prototype);
13
+ }
14
+ };
15
+
16
+ // src/ValidationError.ts
17
+ var ValidationError = class _ValidationError extends DomainError {
18
+ errors;
19
+ constructor(errors) {
20
+ const message = errors.length === 1 ? errors[0]?.message : `Errores de validaci\xF3n: ${errors.map((e) => e.message).join(", ")}`;
21
+ super(message ?? "", "VALIDATION_ERROR", 422, { errors });
22
+ this.errors = errors;
23
+ this.name = "ValidationError";
24
+ }
25
+ static single(field, message, rule, value) {
26
+ return new _ValidationError([{ field, message, rule, value }]);
27
+ }
28
+ hasFieldError(field) {
29
+ return this.errors.some((e) => e.field === field);
30
+ }
31
+ getFieldErrors(field) {
32
+ return this.errors.filter((e) => e.field === field);
33
+ }
34
+ getFirstError() {
35
+ return this.errors[0];
36
+ }
37
+ };
38
+
39
+ // src/messages/index.ts
40
+ var currentMessages = { ...spanishMessages };
41
+ function setMessages(messages) {
42
+ currentMessages = { ...messages };
43
+ }
44
+ function configure(overrides) {
45
+ currentMessages = { ...currentMessages, ...overrides };
46
+ }
47
+ function resetMessages() {
48
+ currentMessages = { ...spanishMessages };
49
+ }
50
+ function getMessages() {
51
+ return currentMessages;
52
+ }
53
+
54
+ // src/ValidationRules.ts
55
+ var ValidationMessages = {
56
+ required: (campo) => getMessages().required(campo),
57
+ pattern: (campo, ejemplo) => getMessages().pattern(campo, ejemplo),
58
+ maxLength: (campo, max, actual) => getMessages().maxLength(campo, max, actual),
59
+ minLength: (campo, min) => getMessages().minLength(campo, min),
60
+ range: (campo, min, max) => getMessages().range(campo, min, max),
61
+ date: (campo) => getMessages().date(campo),
62
+ allowedChars: (campo, permitidos) => getMessages().allowedChars(campo, permitidos),
63
+ email: () => getMessages().email(),
64
+ string: (campo) => getMessages().string(campo),
65
+ number: (campo) => getMessages().number(campo),
66
+ boolean: (campo) => getMessages().boolean(campo),
67
+ array: (campo) => getMessages().array(campo),
68
+ object: (campo) => getMessages().object(campo),
69
+ uuid: (campo) => getMessages().uuid(campo),
70
+ enum: (campo, valores) => getMessages().enum(campo, valores),
71
+ custom: (campo) => getMessages().custom(campo)
72
+ };
73
+
74
+ // src/Validator.ts
75
+ var FieldValidator = class {
76
+ constructor(fieldName, fieldLabel, value, options, parentErrors) {
77
+ this.fieldName = fieldName;
78
+ this.fieldLabel = fieldLabel;
79
+ this.value = value;
80
+ this.options = options;
81
+ this.parentErrors = parentErrors;
82
+ }
83
+ errors = [];
84
+ isOptional = false;
85
+ get isEmpty() {
86
+ if (this.value === void 0 || this.value === null) return true;
87
+ if (typeof this.value === "string" && this.value.trim() === "") return true;
88
+ if (Array.isArray(this.value) && this.value.length === 0) return true;
89
+ return false;
90
+ }
91
+ addError(rule, message) {
92
+ const error = {
93
+ field: this.fieldName,
94
+ message,
95
+ rule,
96
+ value: this.value
97
+ };
98
+ this.errors.push(error);
99
+ this.parentErrors.push(error);
100
+ if (this.options.stopOnFirstError && this.options.throwOnError) {
101
+ throw new ValidationError(this.parentErrors);
102
+ }
103
+ return this;
104
+ }
105
+ shouldSkip() {
106
+ if (this.options.stopOnFirstError && this.errors.length > 0) return true;
107
+ if (this.isOptional && this.isEmpty) return true;
108
+ return false;
109
+ }
110
+ optional() {
111
+ this.isOptional = true;
112
+ return this;
113
+ }
114
+ required(message) {
115
+ if (this.isEmpty) {
116
+ this.addError(
117
+ "required",
118
+ message ?? ValidationMessages.required(this.fieldLabel)
119
+ );
120
+ }
121
+ return this;
122
+ }
123
+ string(message) {
124
+ if (this.shouldSkip()) return this;
125
+ if (!this.isEmpty && typeof this.value !== "string") {
126
+ this.addError(
127
+ "string",
128
+ message ?? ValidationMessages.string(this.fieldLabel)
129
+ );
130
+ }
131
+ return this;
132
+ }
133
+ number(message) {
134
+ if (this.shouldSkip()) return this;
135
+ if (!this.isEmpty && typeof this.value !== "number") {
136
+ this.addError(
137
+ "number",
138
+ message ?? ValidationMessages.number(this.fieldLabel)
139
+ );
140
+ }
141
+ return this;
142
+ }
143
+ boolean(message) {
144
+ if (this.shouldSkip()) return this;
145
+ if (!this.isEmpty && typeof this.value !== "boolean") {
146
+ this.addError(
147
+ "boolean",
148
+ message ?? ValidationMessages.boolean(this.fieldLabel)
149
+ );
150
+ }
151
+ return this;
152
+ }
153
+ array(message) {
154
+ if (this.shouldSkip()) return this;
155
+ if (!this.isEmpty && !Array.isArray(this.value)) {
156
+ this.addError(
157
+ "array",
158
+ message ?? ValidationMessages.array(this.fieldLabel)
159
+ );
160
+ }
161
+ return this;
162
+ }
163
+ object(message) {
164
+ if (this.shouldSkip()) return this;
165
+ if (!this.isEmpty && (typeof this.value !== "object" || Array.isArray(this.value))) {
166
+ this.addError(
167
+ "object",
168
+ message ?? ValidationMessages.object(this.fieldLabel)
169
+ );
170
+ }
171
+ return this;
172
+ }
173
+ type(expectedType, message) {
174
+ switch (expectedType) {
175
+ case "string":
176
+ return this.string(message);
177
+ case "number":
178
+ return this.number(message);
179
+ case "boolean":
180
+ return this.boolean(message);
181
+ case "array":
182
+ return this.array(message);
183
+ case "object":
184
+ return this.object(message);
185
+ case "date":
186
+ return this.date(message);
187
+ case "email":
188
+ return this.email(message);
189
+ case "uuid":
190
+ return this.uuid(message);
191
+ default:
192
+ return this;
193
+ }
194
+ }
195
+ minLength(min, message) {
196
+ if (this.shouldSkip()) return this;
197
+ const len = this.getLength();
198
+ if (!this.isEmpty && len < min) {
199
+ this.addError(
200
+ "minLength",
201
+ message ?? ValidationMessages.minLength(this.fieldLabel, min)
202
+ );
203
+ }
204
+ return this;
205
+ }
206
+ maxLength(max, message) {
207
+ if (this.shouldSkip()) return this;
208
+ const len = this.getLength();
209
+ if (!this.isEmpty && len > max) {
210
+ this.addError(
211
+ "maxLength",
212
+ message ?? ValidationMessages.maxLength(this.fieldLabel, max, len)
213
+ );
214
+ }
215
+ return this;
216
+ }
217
+ getLength() {
218
+ if (typeof this.value === "string") return this.value.length;
219
+ if (Array.isArray(this.value)) return this.value.length;
220
+ return 0;
221
+ }
222
+ min(minValue, message) {
223
+ if (this.shouldSkip()) return this;
224
+ if (!this.isEmpty && typeof this.value === "number" && this.value < minValue) {
225
+ this.addError(
226
+ "min",
227
+ message ?? ValidationMessages.range(this.fieldLabel, minValue, Infinity)
228
+ );
229
+ }
230
+ return this;
231
+ }
232
+ max(maxValue, message) {
233
+ if (this.shouldSkip()) return this;
234
+ if (!this.isEmpty && typeof this.value === "number" && this.value > maxValue) {
235
+ this.addError(
236
+ "max",
237
+ message ?? ValidationMessages.range(this.fieldLabel, -Infinity, maxValue)
238
+ );
239
+ }
240
+ return this;
241
+ }
242
+ range(minValue, maxValue, message) {
243
+ if (this.shouldSkip()) return this;
244
+ if (!this.isEmpty && typeof this.value === "number" && (this.value < minValue || this.value > maxValue)) {
245
+ this.addError(
246
+ "range",
247
+ message ?? ValidationMessages.range(this.fieldLabel, minValue, maxValue)
248
+ );
249
+ }
250
+ return this;
251
+ }
252
+ pattern(regex, example, message) {
253
+ if (this.shouldSkip()) return this;
254
+ if (!this.isEmpty && typeof this.value === "string" && !regex.test(this.value)) {
255
+ this.addError(
256
+ "pattern",
257
+ message ?? ValidationMessages.pattern(
258
+ this.fieldLabel,
259
+ example ?? regex.toString()
260
+ )
261
+ );
262
+ }
263
+ return this;
264
+ }
265
+ email(message) {
266
+ if (this.shouldSkip()) return this;
267
+ const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
268
+ if (!this.isEmpty && typeof this.value === "string" && !emailRegex.test(this.value)) {
269
+ this.addError("email", message ?? ValidationMessages.email() ?? "");
270
+ }
271
+ return this;
272
+ }
273
+ uuid(message) {
274
+ if (this.shouldSkip()) return this;
275
+ const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
276
+ if (!this.isEmpty && typeof this.value === "string" && !uuidRegex.test(this.value)) {
277
+ this.addError("uuid", message ?? ValidationMessages.uuid(this.fieldLabel));
278
+ }
279
+ return this;
280
+ }
281
+ date(message) {
282
+ if (this.shouldSkip()) return this;
283
+ let isValid = false;
284
+ if (this.value instanceof Date && !isNaN(this.value.getTime())) {
285
+ isValid = true;
286
+ } else if (typeof this.value === "string") {
287
+ const parsed = new Date(this.value);
288
+ isValid = !isNaN(parsed.getTime());
289
+ }
290
+ if (!this.isEmpty && !isValid) {
291
+ this.addError("date", message ?? ValidationMessages.date(this.fieldLabel));
292
+ }
293
+ return this;
294
+ }
295
+ enum(allowedValues, message) {
296
+ if (this.shouldSkip()) return this;
297
+ if (!this.isEmpty && !allowedValues.includes(this.value)) {
298
+ this.addError(
299
+ "enum",
300
+ message ?? ValidationMessages.enum(this.fieldLabel, allowedValues)
301
+ );
302
+ }
303
+ return this;
304
+ }
305
+ allowedChars(chars, message) {
306
+ if (this.shouldSkip()) return this;
307
+ if (!this.isEmpty && typeof this.value === "string") {
308
+ const regex = new RegExp(
309
+ `^[${chars.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&")}]+$`
310
+ );
311
+ if (!regex.test(this.value)) {
312
+ this.addError(
313
+ "allowedChars",
314
+ message ?? ValidationMessages.allowedChars(this.fieldLabel, chars)
315
+ );
316
+ }
317
+ }
318
+ return this;
319
+ }
320
+ custom(validator, message) {
321
+ if (this.shouldSkip()) return this;
322
+ if (!this.isEmpty) {
323
+ const result = validator(this.value);
324
+ if (result !== true) {
325
+ const errorMessage = typeof result === "string" ? result : message ?? ValidationMessages.custom(this.fieldLabel);
326
+ this.addError("custom", errorMessage);
327
+ }
328
+ }
329
+ return this;
330
+ }
331
+ nullable() {
332
+ return this.optional();
333
+ }
334
+ };
335
+ var Validator = class {
336
+ constructor(data, options = {}) {
337
+ this.data = data;
338
+ this.options = {
339
+ stopOnFirstError: false,
340
+ throwOnError: true,
341
+ ...options
342
+ };
343
+ }
344
+ errors = [];
345
+ options;
346
+ field(fieldName, label) {
347
+ const value = this.getNestedValue(fieldName);
348
+ const fieldLabel = label ?? fieldName;
349
+ return new FieldValidator(
350
+ fieldName,
351
+ fieldLabel,
352
+ value,
353
+ this.options,
354
+ this.errors
355
+ );
356
+ }
357
+ getNestedValue(path) {
358
+ return path.split(".").reduce((obj, key) => {
359
+ if (obj && typeof obj === "object" && key in obj) {
360
+ return obj[key];
361
+ }
362
+ return void 0;
363
+ }, this.data);
364
+ }
365
+ schema(config) {
366
+ for (const [fieldName, rules] of Object.entries(config)) {
367
+ const fieldValidator = this.field(fieldName, rules.label);
368
+ const messages = rules.messages ?? {};
369
+ if (rules.required) {
370
+ fieldValidator.required(messages.required);
371
+ } else {
372
+ fieldValidator.optional();
373
+ }
374
+ if (rules.type) {
375
+ fieldValidator.type(rules.type, messages.type);
376
+ }
377
+ if (rules.minLength !== void 0) {
378
+ fieldValidator.minLength(rules.minLength, messages.minLength);
379
+ }
380
+ if (rules.maxLength !== void 0) {
381
+ fieldValidator.maxLength(rules.maxLength, messages.maxLength);
382
+ }
383
+ if (rules.min !== void 0) {
384
+ fieldValidator.min(rules.min, messages.min);
385
+ }
386
+ if (rules.max !== void 0) {
387
+ fieldValidator.max(rules.max, messages.max);
388
+ }
389
+ if (rules.pattern) {
390
+ fieldValidator.pattern(
391
+ rules.pattern,
392
+ rules.patternExample,
393
+ messages.pattern
394
+ );
395
+ }
396
+ if (rules.enum) {
397
+ fieldValidator.enum(rules.enum, messages.enum);
398
+ }
399
+ if (rules.allowedChars) {
400
+ fieldValidator.allowedChars(rules.allowedChars, messages.allowedChars);
401
+ }
402
+ if (rules.custom) {
403
+ fieldValidator.custom(rules.custom, messages.custom);
404
+ }
405
+ }
406
+ return this;
407
+ }
408
+ validate() {
409
+ if (this.errors.length > 0) {
410
+ throw new ValidationError(this.errors);
411
+ }
412
+ }
413
+ getResult() {
414
+ return {
415
+ isValid: this.errors.length === 0,
416
+ errors: [...this.errors]
417
+ };
418
+ }
419
+ getErrors() {
420
+ return [...this.errors];
421
+ }
422
+ isValid() {
423
+ return this.errors.length === 0;
424
+ }
425
+ hasErrors() {
426
+ return this.errors.length > 0;
427
+ }
428
+ reset() {
429
+ this.errors.length = 0;
430
+ return this;
431
+ }
432
+ };
433
+ var validate = (data, options) => {
434
+ return new Validator(data, options);
435
+ };
436
+
437
+ export { DomainError, ValidationError, ValidationMessages, Validator, configure, getMessages, resetMessages, setMessages, validate };
@@ -0,0 +1,10 @@
1
+ 'use strict';
2
+
3
+ var chunkGGX2GQQ6_cjs = require('../chunk-GGX2GQQ6.cjs');
4
+
5
+
6
+
7
+ Object.defineProperty(exports, "spanishMessages", {
8
+ enumerable: true,
9
+ get: function () { return chunkGGX2GQQ6_cjs.spanishMessages; }
10
+ });
@@ -0,0 +1 @@
1
+ export { s as spanishMessages } from '../es-QPgrpTLv.cjs';
@@ -0,0 +1 @@
1
+ export { s as spanishMessages } from '../es-QPgrpTLv.js';
@@ -0,0 +1 @@
1
+ export { spanishMessages } from '../chunk-5LU5LI4H.js';
package/package.json ADDED
@@ -0,0 +1,62 @@
1
+ {
2
+ "name": "@linktic/validator",
3
+ "version": "1.0.0",
4
+ "description": "Framework-agnostic TypeScript validation library with fluent API and configurable Spanish default messages",
5
+ "author": "LinkTIC",
6
+ "license": "UNLICENSED",
7
+ "private": false,
8
+ "type": "module",
9
+ "main": "./dist/index.cjs",
10
+ "module": "./dist/index.js",
11
+ "types": "./dist/index.d.ts",
12
+ "exports": {
13
+ ".": {
14
+ "types": "./dist/index.d.ts",
15
+ "import": "./dist/index.js",
16
+ "require": "./dist/index.cjs",
17
+ "default": "./dist/index.js"
18
+ },
19
+ "./messages/es": {
20
+ "types": "./dist/messages/es.d.ts",
21
+ "import": "./dist/messages/es.js",
22
+ "require": "./dist/messages/es.cjs",
23
+ "default": "./dist/messages/es.js"
24
+ }
25
+ },
26
+ "typesVersions": {
27
+ "*": {
28
+ "messages/es": [
29
+ "./dist/messages/es.d.ts"
30
+ ]
31
+ }
32
+ },
33
+ "files": [
34
+ "dist",
35
+ "README.md"
36
+ ],
37
+ "engines": {
38
+ "node": ">=18.0.0"
39
+ },
40
+ "devDependencies": {
41
+ "tsup": "^8.0.0",
42
+ "typescript": "~5.6.0",
43
+ "vitest": "^2.0.0"
44
+ },
45
+ "keywords": [
46
+ "validation",
47
+ "validator",
48
+ "typescript",
49
+ "fluent-api",
50
+ "linktic"
51
+ ],
52
+ "scripts": {
53
+ "build": "tsup",
54
+ "clean": "rm -rf dist",
55
+ "prebuild": "npm run clean",
56
+ "dev": "tsup --watch",
57
+ "test": "vitest run",
58
+ "test:watch": "vitest",
59
+ "test:coverage": "vitest run --coverage",
60
+ "typecheck": "tsc --noEmit"
61
+ }
62
+ }