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