lightjx-validation.md

Comprehensive AI developer guidance for LightJx validation framework - complete reference with examples, patterns, and best practices

lightjx-validation.mdv1.0.132.2 KB
lightjx-validation.md(markdown)
1# LightJx AI Developer Guidance
2
3This comprehensive guide provides everything an AI developer needs to become proficient with LightJx validation framework. LightJx is a fluent JavaScript validation library that works in both browser and Node.js environments.
4
5## Table of Contents
61. [Quick Start](#quick-start)
72. [Core Concepts](#core-concepts)
83. [Usage Patterns](#usage-patterns)
94. [Complete Validator Reference](#complete-validator-reference)
105. [Implementation Examples](#implementation-examples)
116. [Best Practices](#best-practices)
12
13## Quick Start
14
15### Installation
16```bash
17npm install lightjx
18```
19
20### Basic Usage
21```javascript
22import { Validate } from 'lightjx';
23
24// Define a validator
25const emailValidator = Validate.field("email", "Email Address")
26    .required()
27    .asEmail();
28
29// Validate input
30const result = emailValidator.validate("user@example.com");
31if (!result.isValid) {
32    console.log(result.errorMessage); // "Email Address is required"
33}
34```
35
36## Core Concepts
37
38### Fluent API
39LightJx uses method chaining to build validation rules:
40```javascript
41Validate.field("username", "Username")
42    .required()
43    .asAlphaNumericText()
44    .hasMinLength(3)
45    .hasMaxLength(20)
46```
47
48### Two Entry Points
49
501. **Named Fields**: Use when you have a specific field to validate
51```javascript
52Validate.field("fieldName", "Display Name")
53```
54
552. **Anonymous Validation**: Use for general-purpose validation
56```javascript
57Validate.define()
58```
59
60### Validation Result Structure
61```javascript
62{
63    isValid: boolean,
64    errorMessage: string,        // Combined error messages
65    errorMessages: string[],     // Array of all errors
66    input: any                   // The validated input
67}
68```
69
70### Important Behaviors
71- Most validators **succeed on empty values** (null, undefined, "") unless `.required()` is used
72- Validators can accept **functions** for dynamic values
73- Error messages automatically include field display names
74- Multiple validators are executed in order, collecting all errors
75
76## Usage Patterns
77
78### Pattern 1: Direct Fluent API
79```javascript
80// Inline validation
81const isValid = Validate.field("age", "Age")
82    .required()
83    .asNumber()
84    .min(18)
85    .max(120)
86    .validate(25)
87    .isValid;
88```
89
90### Pattern 2: Reusable Validators
91```javascript
92// Define once, use multiple times
93const passwordValidator = Validate.field("password", "Password")
94    .required()
95    .hasMinLength(8)
96    .containsText(/[A-Z]/) // At least one uppercase
97    .containsText(/[0-9]/); // At least one number
98
99// Use repeatedly
100passwordValidator.validate("Pass123!"); // true
101passwordValidator.validate("weak");     // false
102```
103
104### Pattern 3: Form Validation Object
105```javascript
106const validators = {
107    username: Validate.field("username", "Username").required().asAlphaNumericText(),
108    email: Validate.field("email", "Email").required().asEmail(),
109    age: Validate.field("age", "Age").required().asNumber().min(18)
110};
111
112// Validate form data
113function validateForm(formData) {
114    const errors = {};
115    for (const [field, validator] of Object.entries(validators)) {
116        const result = validator.validate(formData[field]);
117        if (!result.isValid) {
118            errors[field] = result.errorMessage;
119        }
120    }
121    return errors;
122}
123```
124
125### Pattern 4: Dynamic Validation
126```javascript
127// Using functions for runtime values
128const dateValidator = Validate.field("startDate", "Start Date")
129    .required()
130    .asDate()
131    .isDateOnOrAfter(() => new Date()); // Function executed at validation time
132
133// Dynamic min/max
134const priceValidator = Validate.field("price", "Price")
135    .required()
136    .asNumber()
137    .min(() => getMinPrice())
138    .max(() => getMaxPrice());
139```
140
141## Complete Validator Reference
142
143### Text Validators
144
145#### asAlphaText()
146Validates alphabetic characters and spaces only.
147```javascript
148Validate.field("name", "Name").asAlphaText()
149// Valid: "John Doe", "ABC", "Test Name"
150// Invalid: "John123", "Test-Name", "user@email"
151```
152
153#### asAlphaNumericText()
154Validates alphanumeric characters only (no spaces).
155```javascript
156Validate.field("code", "Code").asAlphaNumericText()
157// Valid: "ABC123", "test", "123"
158// Invalid: "ABC 123", "test-code", "user@123"
159```
160
161#### asAlphaNumericHyphenText()
162Validates alphanumeric characters, spaces, and hyphens.
163```javascript
164Validate.field("slug", "Slug").asAlphaNumericHyphenText()
165// Valid: "my-slug-123", "ABC 123", "test-name"
166// Invalid: "test@name", "slug#123", "name!"
167```
168
169#### asName()
170Validates names (letters, spaces, hyphens, apostrophes).
171```javascript
172Validate.field("fullName", "Full Name").asName()
173// Valid: "John O'Brien", "Mary-Jane", "José"
174// Invalid: "John123", "Name@test", "User#1"
175```
176
177### Email & URL Validators
178
179#### asEmail()
180Validates email addresses.
181```javascript
182Validate.field("email", "Email").asEmail()
183// Valid: "user@example.com", "test.user+tag@domain.co.uk"
184// Invalid: "notanemail", "@example.com", "user@"
185```
186
187#### asUrl()
188Validates URLs (http, https, mailto, news).
189```javascript
190Validate.field("website", "Website").asUrl()
191// Valid: "https://example.com", "http://test.org", "mailto:user@example.com"
192// Invalid: "example.com", "ftp://file.com", "not a url"
193```
194
195#### asSecureUrl()
196Validates HTTPS URLs only.
197```javascript
198Validate.field("apiEndpoint", "API Endpoint").asSecureUrl()
199// Valid: "https://api.example.com", "https://secure.test.org"
200// Invalid: "http://example.com", "ftp://file.com", "example.com"
201```
202
203### Number Validators
204
205#### asNumber()
206Validates numeric values (accepts number type or numeric strings).
207```javascript
208Validate.field("quantity", "Quantity").asNumber()
209// Valid: 123, "456", -789, "12.34"
210// Invalid: "abc", "12a", null (without required)
211```
212
213#### asInt()
214Validates integers only.
215```javascript
216Validate.field("count", "Count").asInt()
217// Valid: 123, "456", -789, "0"
218// Invalid: 12.34, "12.34", "abc", "1.0"
219```
220
221#### asFloat()
222Validates floating-point numbers.
223```javascript
224Validate.field("price", "Price").asFloat()
225// Valid: 12.34, "56.78", 100, "0.5"
226// Invalid: "abc", "12.34.56", "1,234.56"
227```
228
229#### min(value)
230Sets minimum value (works with numbers).
231```javascript
232Validate.field("age", "Age").asNumber().min(18)
233// Valid: 18, 19, 100, "25"
234// Invalid: 17, "10", -5
235
236// With function
237Validate.field("price", "Price").asNumber().min(() => getMinPrice())
238```
239
240#### max(value)
241Sets maximum value (works with numbers).
242```javascript
243Validate.field("percentage", "Percentage").asNumber().max(100)
244// Valid: 0, 50, 100, "99.9"
245// Invalid: 101, "150", 200
246
247// With function
248Validate.field("quantity", "Quantity").asNumber().max(() => getStock())
249```
250
251### Date Validators
252
253#### asDate()
254Validates date objects or ISO date strings.
255```javascript
256Validate.field("birthDate", "Birth Date").asDate()
257// Valid: new Date(), "2023-12-25", "2023-01-01T00:00:00Z"
258// Invalid: "invalid-date", "25/12/2023", "December 25, 2023"
259```
260
261#### isDateOnOrAfter(date)
262Validates date is on or after specified date.
263```javascript
264const today = new Date();
265Validate.field("startDate", "Start Date").isDateOnOrAfter(today)
266// Valid: today, tomorrow, future dates
267// Invalid: yesterday, past dates
268
269// With function
270Validate.field("endDate", "End Date").isDateOnOrAfter(() => getStartDate())
271```
272
273#### isDateOnOrBefore(date)
274Validates date is on or before specified date.
275```javascript
276const deadline = new Date('2024-12-31');
277Validate.field("submitDate", "Submit Date").isDateOnOrBefore(deadline)
278// Valid: today, deadline, past dates
279// Invalid: dates after deadline
280
281// With function
282Validate.field("startDate", "Start Date").isDateOnOrBefore(() => getEndDate())
283```
284
285#### isDateBetween(minDate, maxDate)
286Validates date is between two dates (inclusive).
287```javascript
288const start = new Date('2024-01-01');
289const end = new Date('2024-12-31');
290Validate.field("eventDate", "Event Date").isDateBetween(start, end)
291// Valid: any date in 2024
292// Invalid: dates before 2024 or after 2024
293```
294
295### String Length Validators
296
297#### hasMinLength(length)
298Validates minimum string length.
299```javascript
300Validate.field("username", "Username").hasMinLength(3)
301// Valid: "abc", "username", "test123"
302// Invalid: "ab", "a", ""
303
304// With function
305Validate.field("code", "Code").hasMinLength(() => getMinCodeLength())
306```
307
308#### hasMaxLength(length)
309Validates maximum string length.
310```javascript
311Validate.field("tweet", "Tweet").hasMaxLength(280)
312// Valid: any string up to 280 characters
313// Invalid: strings longer than 280 characters
314
315// With function
316Validate.field("comment", "Comment").hasMaxLength(() => getMaxCommentLength())
317```
318
319#### hasLengthRange(min, max)
320Validates string length within range.
321```javascript
322Validate.field("password", "Password").hasLengthRange(8, 20)
323// Valid: "password123" (11 chars), "securepass" (10 chars)
324// Invalid: "short" (5 chars), "verylongpasswordthatexceedslimit" (32 chars)
325```
326
327#### hasLength(length)
328Validates exact string length. Useful for postal codes, IDs, phone numbers, and any field requiring specific character counts.
329```javascript
330// US Zip Code validation
331Validate.field("zipCode", "Zip Code").hasLength(5)
332// Valid: "12345", "90210", "54321"
333// Invalid: "1234", "123456", "abc12"
334
335// UK Postal Code (first part)
336Validate.field("postalCode", "Postal Code").hasLength(4).asAlphaNumericText()
337// Valid: "SW1A", "M1 1A", "B33 8TH" (first 4 chars)
338// Invalid: "SW1", "SW1AB1", "12345"
339
340// Product SKU validation
341Validate.field("sku", "SKU").hasLength(8).asAlphaNumericText()
342// Valid: "ABC12345", "XYZ98765", "12345678"
343// Invalid: "ABC123", "ABC123456", "ABC-1234"
344
345// Works with numbers (converted to string length)
346Validate.field("employeeId", "Employee ID").hasLength(6)
347// Valid: 123456, "654321", "000001"
348// Invalid: 12345, 1234567, "abc123"
349
350// Works with arrays (validates array length)
351Validate.field("coordinates", "Coordinates").hasLength(2)
352// Valid: [10, 20], ["lat", "lng"]
353// Invalid: [10], [10, 20, 30]
354
355// Dynamic length with function
356Validate.field("securityCode", "Security Code").hasLength(() => getRequiredCodeLength())
357// Function called at validation time
358
359// Combined with other validators
360Validate.field("productCode", "Product Code")
361    .required()
362    .hasLength(10)
363    .asAlphaNumericHyphenText()
364// Must be exactly 10 characters, alphanumeric with hyphens allowed
365```
366
367### Content Validators
368
369#### required()
370Makes field required (must have a value).
371```javascript
372Validate.field("name", "Name").required()
373// Valid: "any value", 0, false, " " (space)
374// Invalid: null, undefined, "", NaN
375```
376
377#### asBoolean()
378Validates boolean values.
379```javascript
380Validate.field("agreed", "Agreement").asBoolean()
381// Valid: true, false, "true", "false"
382// Invalid: "yes", "no", 1, 0, "1"
383```
384
385#### containsText(text, ignoreCase)
386Validates string contains specific text.
387```javascript
388Validate.field("description", "Description").containsText("important")
389// Valid: "This is important", "important notice"
390// Invalid: "This is not", "IMPORTANT" (case sensitive)
391
392// Case insensitive
393Validate.field("content", "Content").containsText("warning", true)
394// Valid: "Warning!", "WARNING", "wArNiNg"
395
396// With function
397Validate.field("message", "Message").containsText(() => getRequiredKeyword())
398```
399
400#### doesNotContainText(text, ignoreCase)
401Validates string does not contain specific text.
402```javascript
403Validate.field("username", "Username").doesNotContainText("admin")
404// Valid: "user123", "john_doe"
405// Invalid: "administrator", "admin_user"
406
407// Case insensitive
408Validate.field("comment", "Comment").doesNotContainText("spam", true)
409// Valid: "Great post!", "Thanks"
410// Invalid: "SPAM", "This is spam", "SpAm"
411```
412
413#### hasNoBrackets()
414Prevents angle brackets (basic XSS prevention).
415```javascript
416Validate.field("comment", "Comment").hasNoBrackets()
417// Valid: "This is safe text", "No HTML here"
418// Invalid: "<script>", "Hello <b>world</b>", "%3Cscript%3E"
419```
420
421### Format Validators
422
423#### asPhoneNumber()
424Validates phone numbers (flexible format).
425```javascript
426Validate.field("phone", "Phone").asPhoneNumber()
427// Valid: "+1234567890", "(123) 456-7890", "123-456-7890", "1234567890"
428// Invalid: "abc", "123", "phone"
429```
430
431#### asGuid()
432Validates GUID/UUID format.
433```javascript
434Validate.field("id", "ID").asGuid()
435// Valid: "123e4567-e89b-12d3-a456-426614174000", "{123e4567-e89b-12d3-a456-426614174000}"
436// Invalid: "not-a-guid", "123456", "12345678-1234-1234-1234-123456789012X"
437```
438
439#### asHexColor()
440Validates hex color codes.
441```javascript
442Validate.field("color", "Color").asHexColor()
443// Valid: "#FFF", "#FFFFFF", "#123456", "#aAbBcC"
444// Invalid: "FFF", "#GGG", "#12345", "rgb(255,255,255)"
445```
446
447### Array & Value Validators
448
449#### in(array)
450Validates value is in specified array.
451```javascript
452Validate.field("status", "Status").in(["active", "pending", "completed"])
453// Valid: "active", "pending", "completed"
454// Invalid: "cancelled", "unknown", null
455
456// With numbers
457Validate.field("rating", "Rating").in([1, 2, 3, 4, 5])
458// Valid: 1, 2, 3, 4, 5
459// Invalid: 0, 6, "1" (string)
460```
461
462#### notIn(array)
463Validates value is not in specified array.
464```javascript
465Validate.field("username", "Username").notIn(["admin", "root", "system"])
466// Valid: "user123", "john_doe"
467// Invalid: "admin", "root", "system"
468```
469
470#### is(value)
471Validates exact value match.
472```javascript
473Validate.field("confirmed", "Confirmed").is("YES")
474// Valid: "YES"
475// Invalid: "yes", "Yes", "NO", true
476```
477
478#### isNot(value)
479Validates value does not match.
480```javascript
481Validate.field("status", "Status").isNot("deleted")
482// Valid: "active", "pending", anything except "deleted"
483// Invalid: "deleted"
484```
485
486#### isNull()
487Validates value is null.
488```javascript
489Validate.field("deletedAt", "Deleted At").isNull()
490// Valid: null
491// Invalid: undefined, "", 0, false, any other value
492```
493
494#### isEmptyString()
495Validates value is empty string.
496```javascript
497Validate.field("placeholder", "Placeholder").isEmptyString()
498// Valid: ""
499// Invalid: " ", "text", null, undefined
500```
501
502### Custom Validators
503
504#### with(validator)
505Uses custom validator instance.
506```javascript
507import { RequiredValidator } from 'lightjx';
508
509const customRequired = new RequiredValidator();
510Validate.field("data", "Data").with(customRequired)
511```
512
513#### withExpression(regex)
514Validates with custom regex pattern.
515```javascript
516// US Zip code
517Validate.field("zipCode", "Zip Code").withExpression(/^\d{5}(-\d{4})?$/)
518// Valid: "12345", "12345-6789"
519// Invalid: "1234", "123456", "12345-67"
520
521// Custom pattern
522Validate.field("code", "Code").withExpression(/^[A-Z]{3}-\d{4}$/)
523// Valid: "ABC-1234", "XYZ-9999"
524// Invalid: "abc-1234", "AB-1234", "ABC-123"
525```
526
527## Implementation Examples
528
529### Example 1: User Registration Form
530```javascript
531const registrationValidators = {
532    username: Validate.field("username", "Username")
533        .required("Please enter a username")
534        .asAlphaNumericText("Username can only contain letters and numbers")
535        .hasMinLength(3, "Username must be at least 3 characters")
536        .hasMaxLength(20, "Username cannot exceed 20 characters"),
537    
538    email: Validate.field("email", "Email Address")
539        .required("Email address is required")
540        .asEmail("Please enter a valid email address"),
541    
542    password: Validate.field("password", "Password")
543        .required("Password is required")
544        .hasMinLength(8, "Password must be at least 8 characters")
545        .containsText("A", false, "Password must contain at least one uppercase letter")
546        .containsText("0", false, "Password must contain at least one number"),
547    
548    confirmPassword: Validate.field("confirmPassword", "Confirm Password")
549        .required("Please confirm your password"),
550    
551    age: Validate.field("age", "Age")
552        .required("Age is required")
553        .asInt("Age must be a whole number")
554        .min(13, "You must be at least 13 years old")
555        .max(120, "Please enter a valid age"),
556    
557    termsAccepted: Validate.field("terms", "Terms Acceptance")
558        .required("You must accept the terms and conditions")
559        .is(true, "You must accept the terms to continue"),
560    
561    zipCode: Validate.field("zipCode", "Zip Code")
562        .required("Zip code is required")
563        .hasLength(5, "Zip code must be exactly 5 digits")
564        .asNumber("Zip code must contain only numbers")
565};
566
567function validateRegistration(formData) {
568    const errors = {};
569    
570    // Validate each field
571    for (const [field, validator] of Object.entries(registrationValidators)) {
572        const result = validator.validate(formData[field]);
573        if (!result.isValid) {
574            errors[field] = result.errorMessage;
575        }
576    }
577    
578    // Custom password match validation
579    if (formData.password !== formData.confirmPassword) {
580        errors.confirmPassword = "Passwords do not match";
581    }
582    
583    return {
584        isValid: Object.keys(errors).length === 0,
585        errors
586    };
587}
588```
589
590### Example 2: Product Form Validation
591```javascript
592const productValidators = {
593    name: Validate.field("name", "Product Name")
594        .required()
595        .hasMinLength(3)
596        .hasMaxLength(100),
597    
598    sku: Validate.field("sku", "SKU")
599        .required()
600        .hasLength(12)
601        .withExpression(/^[A-Z]{3}-\d{4}-[A-Z0-9]{4}$/),
602    
603    price: Validate.field("price", "Price")
604        .required()
605        .asFloat()
606        .min(0.01)
607        .max(99999.99),
608    
609    salePrice: Validate.field("salePrice", "Sale Price")
610        .asFloat()
611        .min(0),
612    
613    category: Validate.field("category", "Category")
614        .required()
615        .in(["electronics", "clothing", "food", "books", "other"]),
616    
617    availableFrom: Validate.field("availableFrom", "Available From")
618        .required()
619        .asDate()
620        .isDateOnOrAfter(() => new Date()),
621    
622    description: Validate.field("description", "Description")
623        .hasMaxLength(1000)
624        .hasNoBrackets(),
625    
626    tags: Validate.field("tags", "Tags")
627        .hasMaxLength(200)
628};
629
630// Validate with conditional logic
631function validateProduct(product) {
632    const errors = {};
633    
634    // Standard validation
635    for (const [field, validator] of Object.entries(productValidators)) {
636        if (product[field] !== undefined) {
637            const result = validator.validate(product[field]);
638            if (!result.isValid) {
639                errors[field] = result.errorMessage;
640            }
641        }
642    }
643    
644    // Conditional validation: sale price must be less than regular price
645    if (product.salePrice && product.price) {
646        if (product.salePrice >= product.price) {
647            errors.salePrice = "Sale price must be less than regular price";
648        }
649    }
650    
651    return { isValid: Object.keys(errors).length === 0, errors };
652}
653```
654
655### Example 3: Dynamic Configuration Validation
656```javascript
657function createConfigValidator(config) {
658    const validators = {};
659    
660    // API Configuration
661    if (config.enableAPI) {
662        validators.apiKey = Validate.field("apiKey", "API Key")
663            .required()
664            .hasMinLength(32)
665            .asAlphaNumericText();
666            
667        validators.apiEndpoint = Validate.field("apiEndpoint", "API Endpoint")
668            .required()
669            .asSecureUrl();
670    }
671    
672    // Email Configuration
673    if (config.enableEmail) {
674        validators.smtpHost = Validate.field("smtpHost", "SMTP Host")
675            .required()
676            .containsText(".");
677            
678        validators.smtpPort = Validate.field("smtpPort", "SMTP Port")
679            .required()
680            .asInt()
681            .in([25, 465, 587, 2525]);
682            
683        validators.fromEmail = Validate.field("fromEmail", "From Email")
684            .required()
685            .asEmail();
686    }
687    
688    // Database Configuration
689    validators.dbConnectionString = Validate.field("dbConnectionString", "Database Connection")
690        .required()
691        .hasMinLength(10);
692        
693    validators.maxConnections = Validate.field("maxConnections", "Max Connections")
694        .required()
695        .asInt()
696        .min(1)
697        .max(100);
698    
699    return validators;
700}
701
702// Usage
703const config = {
704    enableAPI: true,
705    enableEmail: false,
706    // ... other config
707};
708
709const validators = createConfigValidator(config);
710```
711
712### Example 4: Fixed-Length Field Validation
713```javascript
714// Common use cases for hasLength() validation
715const fixedLengthValidators = {
716    // US Social Security Number (9 digits, no dashes)
717    ssn: Validate.field("ssn", "Social Security Number")
718        .required()
719        .hasLength(9)
720        .asNumber(),
721    
722    // Credit Card CVV (3 or 4 digits depending on card type)
723    cvv: Validate.field("cvv", "CVV")
724        .required()
725        .hasLength(3) // Most cards use 3 digits
726        .asNumber(),
727    
728    // Product batch code (exactly 8 alphanumeric characters)
729    batchCode: Validate.field("batchCode", "Batch Code")
730        .required()
731        .hasLength(8)
732        .asAlphaNumericText(),
733    
734    // US ZIP code (exactly 5 digits)
735    zipCode: Validate.field("zipCode", "ZIP Code")
736        .required()
737        .hasLength(5)
738        .asNumber(),
739    
740    // International phone number country code (2-3 digits)
741    countryCode: Validate.field("countryCode", "Country Code")
742        .required()
743        .hasLengthRange(2, 3)
744        .asNumber(),
745    
746    // Two-factor authentication code (6 digits)
747    authCode: Validate.field("authCode", "Authentication Code")
748        .required()
749        .hasLength(6)
750        .asNumber(),
751    
752    // License plate (variable length by state, this example: 7 chars)
753    licensePlate: Validate.field("licensePlate", "License Plate")
754        .required()
755        .hasLength(7)
756        .asAlphaNumericText(),
757    
758    // ISBN-10 (exactly 10 characters)
759    isbn10: Validate.field("isbn10", "ISBN-10")
760        .hasLength(10)
761        .asAlphaNumericText() // Can include 'X' as check digit
762};
763
764// Dynamic length validation example
765function createDynamicValidator(config) {
766    return {
767        customId: Validate.field("customId", "Custom ID")
768            .required()
769            .hasLength(() => config.idLength)
770            .asAlphaNumericText(),
771            
772        securityCode: Validate.field("securityCode", "Security Code")
773            .required()
774            .hasLength(() => config.securityCodeLength)
775            .asNumber()
776    };
777}
778
779// Usage with different configurations
780const config1 = { idLength: 8, securityCodeLength: 4 };
781const config2 = { idLength: 12, securityCodeLength: 6 };
782
783const validator1 = createDynamicValidator(config1);
784const validator2 = createDynamicValidator(config2);
785```
786
787### Example 5: Batch Data Validation
788```javascript
789function createCSVRowValidator() {
790    return {
791        id: Validate.field("id", "ID")
792            .required()
793            .asGuid(),
794            
795        timestamp: Validate.field("timestamp", "Timestamp")
796            .required()
797            .asDate(),
798            
799        amount: Validate.field("amount", "Amount")
800            .required()
801            .asFloat()
802            .min(0),
803            
804        currency: Validate.field("currency", "Currency")
805            .required()
806            .withExpression(/^[A-Z]{3}$/),
807            
808        status: Validate.field("status", "Status")
809            .required()
810            .in(["pending", "completed", "failed", "refunded"])
811    };
812}
813
814function validateCSVData(rows) {
815    const validators = createCSVRowValidator();
816    const results = [];
817    
818    rows.forEach((row, index) => {
819        const rowErrors = {};
820        let hasErrors = false;
821        
822        for (const [field, validator] of Object.entries(validators)) {
823            const result = validator.validate(row[field]);
824            if (!result.isValid) {
825                rowErrors[field] = result.errorMessage;
826                hasErrors = true;
827            }
828        }
829        
830        results.push({
831            row: index + 1,
832            isValid: !hasErrors,
833            errors: rowErrors,
834            data: row
835        });
836    });
837    
838    return {
839        totalRows: rows.length,
840        validRows: results.filter(r => r.isValid).length,
841        invalidRows: results.filter(r => !r.isValid).length,
842        results
843    };
844}
845```
846
847## Best Practices
848
849### 1. Field Naming Convention
850Always provide both technical field name and display name:
851```javascript
852// Good
853Validate.field("emailAddress", "Email Address")
854
855// Less informative
856Validate.field("email")
857```
858
859### 2. Order Validators Logically
860Place validators from most to least restrictive:
861```javascript
862// Good order
863Validate.field("username", "Username")
864    .required()           // Check existence first
865    .asAlphaNumericText() // Then check format
866    .hasMinLength(3)      // Then check constraints
867    .hasMaxLength(20)
868
869// Less optimal
870Validate.field("username", "Username")
871    .hasMaxLength(20)
872    .asAlphaNumericText()
873    .hasMinLength(3)
874    .required()
875```
876
877### 3. Use Functions for Dynamic Values
878When validation depends on runtime values:
879```javascript
880// Good - function evaluated at validation time
881Validate.field("endDate", "End Date")
882    .isDateOnOrAfter(() => document.getElementById('startDate').value)
883
884// Bad - value fixed at validator creation
885Validate.field("endDate", "End Date")
886    .isDateOnOrAfter(document.getElementById('startDate').value)
887```
888
889### 4. Handle Empty Values Appropriately
890Remember most validators pass on empty values:
891```javascript
892// This allows empty values
893Validate.field("email", "Email").asEmail()
894
895// This requires a value and validates format
896Validate.field("email", "Email").required().asEmail()
897```
898
899### 5. Custom Error Messages
900All validator methods support custom error messages through an optional `errorMessage` parameter. When provided, your custom message replaces the default validator error message.
901
902#### Basic Custom Error Messages
903```javascript
904// Custom error message for required validation
905Validate.field("email", "Email Address")
906    .required("Please enter your email address")
907    .validate("");
908// Error: "Email Address Please enter your email address"
909
910// Custom error message for format validation
911Validate.field("phone", "Phone Number")
912    .asPhoneNumber("Enter a valid phone number format")
913    .validate("invalid");
914// Error: "Phone Number Enter a valid phone number format"
915```
916
917#### All Methods Support Custom Messages
918Every fluent API method accepts an optional `errorMessage` parameter:
919```javascript
920// Core validators
921.required("This field is mandatory")
922.asBoolean("Must be true or false")
923.asEmail("Enter a valid email address")
924.asPhoneNumber("Invalid phone number format")
925.asAlphaText("Only letters and spaces allowed")
926.asAlphaNumericText("Only letters and numbers allowed")
927.asAlphaNumericHyphenText("Only letters, numbers, spaces and hyphens")
928.asName("Enter a valid name")
929
930// Number validators
931.asNumber("Must be a numeric value")
932.asInt("Must be a whole number")
933.asFloat("Must be a decimal number")
934.min(10, "Value must be at least 10")
935.max(100, "Value cannot exceed 100")
936
937// Length validators
938.hasMinLength(5, "Too short - minimum 5 characters")
939.hasMaxLength(20, "Too long - maximum 20 characters")
940.hasLength(8, "Must be exactly 8 characters")
941.hasLengthRange(3, 15, "Must be between 3 and 15 characters")
942
943// Value validators
944.is("expected", "Must match expected value")
945.isNot("forbidden", "This value is not allowed")
946.in(["red", "green", "blue"], "Please select a valid color")
947.notIn(["admin", "root"], "Username not allowed")
948.isNull("Must be null")
949.isEmptyString("Must be empty")
950
951// Text content validators
952.containsText("password", false, "Must contain the word 'password'")
953.doesNotContainText("spam", false, "Cannot contain spam")
954
955// Date validators
956.asDate("Enter a valid date")
957.isDateOnOrAfter(minDate, "Date is too early")
958.isDateOnOrBefore(maxDate, "Date is too late")
959.isDateBetween(start, end, "Date must be within range")
960
961// Format validators
962.asGuid("Must be a valid GUID")
963.asHexColor("Enter a valid hex color code")
964.asUrl("Must be a valid URL")
965.asSecureUrl("Must be a secure HTTPS URL")
966```
967
968#### Chaining with Custom Messages
969```javascript
970const validator = Validate.field("password", "Password")
971    .required("Password is required")
972    .hasMinLength(8, "Password must be at least 8 characters")
973    .containsText("A", false, "Password must contain uppercase letters");
974
975const result = validator.validate("abc");
976// Multiple errors: "Password Password must be at least 8 characters. Password Password must contain uppercase letters"
977```
978
979#### Mixed Custom and Default Messages
980```javascript
981const validator = Validate.field("username", "Username")
982    .required("Username is required")
983    .asAlphaNumericText() // uses default message
984    .hasLengthRange(3, 20, "Username must be 3-20 characters");
985
986const result = validator.validate("user@name");
987// Error: "Username must contain only letters and numbers (no spaces or special characters)"
988```
989
990#### Custom Messages Override Defaults
991```javascript
992// Without custom message
993Validate.field("age", "Age").asInt().validate("12.5");
994// Error: "Age is not a valid whole number"
995
996// With custom message
997Validate.field("age", "Age").asInt("Please enter your age as a whole number").validate("12.5");
998// Error: "Age Please enter your age as a whole number"
999```
1000
1001### 6. Reuse Validators
1002Create validator objects for common fields:
1003```javascript
1004// Define once
1005const validators = {
1006    email: Validate.field("email", "Email").required().asEmail(),
1007    phone: Validate.field("phone", "Phone Number").asPhoneNumber(),
1008    url: Validate.field("url", "Website").asUrl()
1009};
1010
1011// Reuse everywhere
1012function validateContact(data) {
1013    return validators.email.validate(data.email);
1014}
1015
1016function validateProfile(data) {
1017    return validators.email.validate(data.email);
1018}
1019```
1020
1021### 7. Combine with Form Libraries
1022LightJx works well with form libraries:
1023```javascript
1024// React example pattern
1025const useValidator = (validator) => {
1026    const [error, setError] = useState('');
1027    
1028    const validate = (value) => {
1029        const result = validator.validate(value);
1030        setError(result.isValid ? '' : result.errorMessage);
1031        return result.isValid;
1032    };
1033    
1034    return { error, validate };
1035};
1036```
1037
1038### 8. Server-Side Validation
1039Always validate on the server, even with client validation:
1040```javascript
1041// Express.js middleware pattern
1042const validateRequest = (validators) => {
1043    return (req, res, next) => {
1044        const errors = {};
1045        
1046        for (const [field, validator] of Object.entries(validators)) {
1047            const result = validator.validate(req.body[field]);
1048            if (!result.isValid) {
1049                errors[field] = result.errorMessage;
1050            }
1051        }
1052        
1053        if (Object.keys(errors).length > 0) {
1054            return res.status(400).json({ errors });
1055        }
1056        
1057        next();
1058    };
1059};
1060```
1061
1062## Key Concepts Summary
1063
10641. **Fluent API**: Chain validators for readable validation rules
10652. **Empty Value Handling**: Most validators pass on empty values unless `.required()` is used
10663. **Dynamic Functions**: Many validators accept functions for runtime values
10674. **Error Context**: Display names are automatically included in error messages
10685. **Type Flexibility**: Validators intelligently handle different input types
10696. **Validation Flow**: All validators run and collect errors (doesn't stop on first error)
1070
1071## Common Pitfalls
1072
10731. **Forgetting `.required()`**: Validators pass empty values by default
10742. **Wrong validator order**: Put format validators before length validators
10753. **Static vs Dynamic values**: Use functions for values that change
10764. **Type mismatches**: Some validators work with strings, others with specific types
10775. **Case sensitivity**: Text validators are case-sensitive by default
1078
1079This guide provides comprehensive coverage of LightJx for AI developers. Use it to understand available validators, implementation patterns, and best practices for effective validation.

Metadata

Path
utaba/main/guidance/validation/lightjx-validation.md
Namespace
utaba/main/guidance/validation
Author
utaba
Category
guidance
Technology
javascript
Contract Version
1.0.1
MIME Type
text/markdown
Published
29-Jul-2025
Last Updated
29-Jul-2025