
Product
Introducing Webhook Events for Alert Changes
Add real-time Socket webhook events to your workflows to automatically receive software supply chain alert changes in real time.
zee-light-validate
Advanced tools
A lightweight TypeScript object validation library with zero dependencies
A comprehensive, lightweight validation library for TypeScript/JavaScript with zero dependencies. Tree-shakeable, type-safe, and designed for modern applications with support for file validation, cross-field validation, async validation, and internationalization.
npm install light-validate
import { string, number, boolean, object, array, schema } from "light-validate";
// Simple validation
const nameValidator = string().min(2).max(50).required();
const result = nameValidator.validate("Zohaib Irshad");
console.log(result); // { success: true }
// Object validation
const userSchema = object({
name: string().required().min(3),
email: string().email().required(),
age: number().min(18).max(120),
isActive: boolean(),
});
const user = {
name: "Zohaib Irshad",
email: "zohaib@example.com",
age: 25,
isActive: true,
};
const validation = userSchema.validate(user);
console.log(validation); // { success: true }
import {
schema,
field,
greater,
equalTo,
string,
number,
} from "light-validate";
// Cross-field validation
const eventSchema = schema({
title: string().required(),
startDate: string().required(),
endDate: field(string().required(), greater("startDate")),
originalPrice: number().min(0).required(),
salePrice: field(number().min(0), lessThan("originalPrice")),
});
// Password confirmation
const passwordSchema = schema({
password: string().min(8).required(),
confirmPassword: field(string().required(), equalTo("password")),
});
import { schema, string, asyncEmail, asyncUsername } from "light-validate";
// Database/API validation
const registrationSchema = schema({
username: string().username().required(),
email: string().email().required(),
})
.asyncValidate(
"email",
asyncEmail(async (email) => {
// Check if email exists in database
const exists = await checkEmailInDatabase(email);
return !exists; // Return true if unique
})
)
.asyncValidate(
"username",
asyncUsername(async (username) => {
// Check username availability
const available = await checkUsernameAvailability(username);
return available;
})
);
// Use async validation
const result = await registrationSchema.validateAsync({
username: "zohaib_irshad",
email: "zohaib@example.com",
});
import { schema, string } from "light-validate";
const userSchema = schema({
name: string().required(),
email: string().email().required(),
}).locale({
locale: "ur", // Urdu
messages: {
ur: {
required: "یہ فیلڈ ضروری ہے",
email: "درست ای میل ایڈریس درج کریں",
type: "یہ فیلڈ ایک آبجیکٹ ہونا چاہیے",
},
es: {
required: "Este campo es requerido",
email: "Ingrese una dirección de correo válida",
},
},
});
import { array, string, number } from "light-validate";
// Array of user objects
const usersValidator = array()
.min(1, "At least one user required")
.max(10, "Maximum 10 users allowed")
.arrayOf({
name: string().required(),
email: string().email().required(),
age: number().min(0).max(120),
})
.unique("All users must be unique");
const users = [
{ name: "Zohaib Irshad", email: "zohaib@example.com", age: 25 },
{ name: "John Doe", email: "john@example.com", age: 30 },
];
const result = usersValidator.validate(users);
import { schema, string, number } from "light-validate";
// Reusable address schema
const addressSchema = schema({
street: string().required(),
city: string().required(),
zipCode: string().postalCode("US").required(),
country: string().countryCode().required(),
});
// User schema using address
const userSchema = schema({
name: string().required(),
email: string().email().required(),
address: addressSchema, // Nested schema
billingAddress: addressSchema, // Reuse same schema
});
// Company schema
const companySchema = schema({
name: string().required(),
email: string().email().required(),
employees: number().min(1).required(),
headquarters: addressSchema, // Reuse address schema
});
import { string } from "light-validate";
const validator = string()
.required("Name is required")
.min(2, "Minimum 2 characters")
.max(50, "Maximum 50 characters");
// Custom regex
const codeValidator = string().regex(/^[A-Z]{2,3}-\d{3,6}$/, "Invalid format");
// Email validation
const emailValidator = string().email("Invalid email address");
// URL validation
const urlValidator = string().url("Must be a valid URL");
// Domain validation (without protocol)
const domainValidator = string().domain("Invalid domain name");
// IP address (IPv4 & IPv6)
const ipValidator = string().ip("Invalid IP address");
// Latitude/Longitude coordinates
const coordsValidator = string().latLng("Invalid coordinates (lat,lng)");
// Postal codes (190+ countries supported)
const zipValidator = string().postalCode("US", "Invalid US zip code");
const pkZipValidator = string().postalCode(
"PK",
"Invalid Pakistan postal code"
);
// Country codes (ISO 2 or 3 letter)
const countryValidator = string().countryCode("Invalid country code");
// Language codes (ISO 639)
const langValidator = string().languageCode("Invalid language code");
// Timezone validation
const timezoneValidator = string().timezone("Invalid timezone");
// Username validation (no spaces, only _ or . allowed)
const usernameValidator = string().username("Invalid username format");
// Environment variable names
const envVarValidator = string().envVar("Invalid environment variable");
// MAC address validation
const macValidator = string().mac("Invalid MAC address");
// Hexadecimal validation
const hexValidator = string().hex("Invalid hex value");
// Base64 validation
const base64Validator = string().base64("Invalid Base64 string");
// JWT token validation
const jwtValidator = string().jwt("Invalid JWT token");
// Port number validation (1-65535)
const portValidator = string().port("Invalid port number");
// Cron expression validation
const cronValidator = string().cron("Invalid cron expression");
// UUID validation
const uuidValidator = string().uuid("Invalid UUID format");
// API key validation (32+ characters)
const apiKeyValidator = string().apiKey("Invalid API key format");
// OTP validation (customizable length)
const otpValidator = string().otp(6, "Invalid 6-digit OTP");
// Hash validation (MD5, SHA1, SHA256, SHA512)
const hashValidator = string().hash("sha256", "Invalid SHA256 hash");
// Credit card validation (with Luhn algorithm)
const cardValidator = string().creditCard("Invalid credit card number");
// IBAN validation
const ibanValidator = string().iban("Invalid IBAN");
// Time validation (HH:mm format)
const timeValidator = string().time("Invalid time format");
// Slug validation (URL-friendly strings)
const slugValidator = string().slug("Invalid slug format");
// Currency codes (ISO 4217)
const currencyValidator = string().currency("Invalid currency code");
// Safe string validation (XSS/SQL injection protection)
const safeValidator = string().safeString("Contains unsafe content");
import { number } from "light-validate";
const ageValidator = number()
.required("Age is required")
.min(0, "Age cannot be negative")
.max(120, "Age cannot exceed 120");
const priceValidator = number()
.min(0, "Price must be positive")
.custom((val) =>
val % 0.01 === 0 ? null : "Price must have max 2 decimal places"
);
import { boolean } from "light-validate";
const termsValidator = boolean()
.required("Must accept terms")
.custom((val) => (val === true ? null : "Terms must be accepted"));
import { array, string, number } from "light-validate";
// Basic array validation
const tagsValidator = array()
.min(1, "At least one tag required")
.max(10, "Maximum 10 tags allowed")
.of(string().min(2))
.unique("Tags must be unique");
// Array of numbers
const scoresValidator = array()
.of(number().min(0).max(100))
.min(3, "Minimum 3 scores required");
// Array of objects
const productsValidator = array().arrayOf({
name: string().required(),
price: number().min(0).required(),
category: string().required(),
});
import { file } from "light-validate";
// Image validation
const avatarValidator = file()
.images("Only image files allowed")
.maxSizeMB(5, "File too large")
.required("Avatar is required");
// Document validation
const docValidator = file()
.documents("Only document files allowed")
.maxSizeKB(500, "Document too large");
// Custom file validation
const customValidator = file()
.mimeTypes(["application/pdf", "text/plain"])
.extensions([".pdf", ".txt"])
.maxSizeBytes(1024 * 1024); // 1MB
import { enum as enumValidator } from "light-validate";
// String enum
const statusValidator = enumValidator(["active", "inactive", "pending"]);
// Number enum
const priorityValidator = enumValidator([1, 2, 3, 4, 5]);
// Mixed enum
const mixedValidator = enumValidator(["low", "medium", "high", 1, 2, 3]);
import { dateRange } from "light-validate";
// ISO date format (YYYY-MM-DD)
const isoRangeValidator = dateRange({
dateFormat: "ISO",
allowSameDate: false,
});
// US date format (MM/DD/YYYY)
const usRangeValidator = dateRange({
dateFormat: "US",
allowSameDate: true,
});
// EU date format (DD/MM/YYYY)
const euRangeValidator = dateRange({
dateFormat: "EU",
});
const result = isoRangeValidator.validate({
start: "2025-01-01",
end: "2025-12-31",
});
name: "User Name", email: "test@test.com", age: 22, status: "active", });
console.log(result); // { success: true }
### Node.js/CommonJS
```javascript
const {
object,
string,
number,
enum: enumValidator,
} = require("light-validate");
const schema = object({
name: string().required().min(3),
email: string().email(),
age: number().min(18),
status: enumValidator(["active", "inactive"]).required(),
});
const result = schema.validate({
name: "User Name",
email: "test@test.com",
age: 22,
status: "active",
});
console.log(result);
// { success: true }
string()Creates a string validator with comprehensive validation options.
import { string } from "light-validate";
const validator = string()
.required() // Field is required
.min(3) // Minimum length
.max(50) // Maximum length
.email() // Valid email format
.url() // Valid URL (http/https)
.ip() // Valid IP address (IPv4/IPv6)
.uuid() // Valid UUID v4 format
.time() // Valid time format (HH:mm)
.slug() // Valid slug (alphanumeric, dash, underscore)
.creditCard() // Valid credit card (Luhn algorithm)
.iban() // Valid IBAN format
.safeString() // XSS/SQL injection protection
.regex(/^[A-Z0-9]+$/) // Custom regex pattern
.postalCode("PK") // Postal code for specific country
.custom((value) => {
// Custom validation
return value.includes("@") ? null : "Must contain @";
});
// Advanced string validations examples:
// URL validation
string().url().validate("https://example.com"); // ✅
string().url().validate("invalid-url"); // ❌
// IP address validation
string().ip().validate("192.168.0.1"); // ✅ IPv4
string().ip().validate("2001:db8::1"); // ✅ IPv6
// UUID validation
string().uuid().validate("550e8400-e29b-41d4-a716-446655440000"); // ✅
// Time validation
string().time().validate("14:30"); // ✅
string().time().validate("25:30"); // ❌
// Slug validation
string().slug().validate("zohaib_irshad"); // ✅
string().slug().validate("invalid slug"); // ❌
// Credit card validation (Luhn algorithm)
string().creditCard().validate("4111111111111111"); // ✅ Visa test card
// IBAN validation
string().iban().validate("PK36SCBL0000001123456702"); // ✅
// Safe string (XSS/SQL injection protection)
string().safeString().validate("Safe user input"); // ✅
string().safeString().validate("<script>alert(1)</script>"); // ❌
// Custom regex
string()
.regex(/^[A-Z0-9]+$/)
.validate("ABC123"); // ✅
// Postal codes for different countries
string().postalCode("US").validate("12345"); // ✅ US ZIP
string().postalCode("PK").validate("54000"); // ✅ Pakistan
string().postalCode("UK").validate("SW1A 1AA"); // ✅ UK postcode
string().postalCode("CA").validate("K1A 0A6"); // ✅ Canada
number()Creates a number validator.
import { number } from "light-validate";
const validator = number()
.required() // Field is required
.min(0) // Minimum value
.max(100) // Maximum value
.custom((value) => {
// Custom validation
return value % 2 === 0 ? null : "Must be even";
});
boolean()Creates a boolean validator.
import { boolean } from "light-validate";
const validator = boolean()
.required() // Field is required
.custom((value) => {
// Custom validation
return value === true ? null : "Must be true";
});
object(schema)Creates an object validator with a schema.
import { object, string, number, array } from "light-validate";
const validator = object({
name: string().required(),
age: number().min(0),
})
.required() // Object itself is required
.custom((obj) => {
// Custom validation on entire object
return obj.name && obj.age ? null : "Invalid user";
});
// Advanced Object Validations
// Non-empty object validation
object({
name: string(),
email: string()
})
.notEmpty() // Object cannot be empty
.validate({ name: 'John' }); // ✅
// Required keys validation
object({
name: string(),
email: string(),
age: number()
})
.hasKeys(['name', 'email']) // These keys must exist
.validate({ name: 'John', email: 'john@test.com', age: 30 }); // ✅
// Strict keys validation (no unexpected keys)
object({
name: string(),
age: number()
})
.strictKeys() // Only defined keys allowed
.validate({ name: 'John', age: 30 }); // ✅
.validate({ name: 'John', age: 30, email: 'extra' }); // ❌ (unexpected key)
// Deep nested validation using dot notation
object({
user: object({
profile: object({
name: string()
})
})
})
.deepKey('user.profile.name', string().min(2))
.validate({
user: {
profile: {
name: 'John'
}
}
}); // ✅
// Array contains validation (validate arrays inside objects)
object({
tags: array(),
categories: array()
})
.arrayContains('tags', 'javascript') // tags array must contain 'javascript'
.validate({
tags: ['javascript', 'typescript'],
categories: ['frontend']
}); // ✅
// Plain object validation (reject Date, RegExp, etc.)
object({
data: string()
})
.plainObject() // Must be a plain object, not Date/RegExp/etc
.validate({ data: 'value' }); // ✅
.validate(new Date()); // ❌ (not a plain object)
// Combined advanced validations
object({
name: string().required(),
email: string().email().required(),
age: number().min(18),
tags: array()
})
.notEmpty()
.hasKeys(['name', 'email'])
.strictKeys()
.plainObject()
.arrayContains('tags', 'verified')
.validate({
name: 'John',
email: 'john@test.com',
age: 25,
tags: ['verified', 'user']
}); // ✅ (passes all validations)
array()Creates an array validator with advanced validation options.
import { array, string, number } from "light-validate";
const validator = array()
.required() // Array is required
.min(1) // Minimum number of items
.max(10) // Maximum number of items
.unique() // All items must be unique
.of(string()) // Validate each item as string
.custom((arr) => {
// Custom validation
return arr.length > 0 ? null : "Cannot be empty";
});
// Array validation examples:
// Basic array with length constraints
array().min(1).max(5).validate([1, 2, 3]); // ✅
// Unique items validation
array().unique().validate([1, 2, 3, 4]); // ✅
array().unique().validate([1, 2, 2, 3]); // ❌ (duplicate items)
// Array of validated items
array().of(string().email()).validate(["test@test.com", "user@example.org"]); // ✅
// Complex array validation
array()
.min(2, "At least 2 items required")
.max(5, "Maximum 5 items allowed")
.unique("All items must be unique")
.of(
string()
.min(3, "Each item must be at least 3 characters")
.slug("Each item must be a valid slug")
)
.validate(["user_1", "admin_2", "guest_3"]); // ✅
// Advanced Array Validations
// Sorted array validation
array()
.of(number())
.sorted() // Must be sorted in ascending order
.validate([1, 2, 3, 4]); // ✅
array()
.of(number())
.sorted("desc") // Must be sorted in descending order
.validate([4, 3, 2, 1]); // ✅
// Type consistency validation
array()
.ofType("string") // All items must be strings
.validate(["a", "b", "c"]); // ✅
array()
.ofType("number") // All items must be numbers
.validate([1, 2, 3]); // ✅
// Exact length validation
array()
.length(3) // Must have exactly 3 items
.validate([1, 2, 3]); // ✅
// Non-empty validation
array()
.notEmpty() // Cannot be empty
.validate([1]); // ✅
// Contains specific value
array()
.contains("required-item") // Must contain this value
.validate(["a", "required-item", "c"]); // ✅
// Does not contain specific value
array()
.notContains("forbidden") // Must not contain this value
.validate(["a", "b", "c"]); // ✅
// Combined advanced validations
array()
.of(number())
.notEmpty()
.length(3)
.sorted()
.contains(2)
.validate([1, 2, 3]); // ✅ (exactly 3 numbers, sorted, contains 2)
enum(allowedValues)Creates an enum validator for predefined values.
import { enum as enumValidator } from "light-validate";
// String enum validation
const statusValidator = enumValidator([
"active",
"inactive",
"pending",
] as const)
.required() // Enum value is required
.custom((value) => {
// Custom validation
return value === "inactive" ? "Inactive status not allowed" : null;
});
// Number enum validation
const priorityValidator = enumValidator([1, 2, 3, 4, 5] as const);
// TypeScript enum support
enum UserRole {
ADMIN = "admin",
USER = "user",
GUEST = "guest",
}
const roleValidator = enumValidator(Object.values(UserRole));
// Mixed enum (string + number)
const mixedValidator = enumValidator([
"low",
1,
"medium",
2,
"high",
3,
] as const);
dateRange(options)Creates a date range validator to ensure start date is before end date.
import { dateRange } from "light-validate";
// Basic date range validation (ISO format: YYYY-MM-DD)
const basicRange = dateRange().required().validate({
start: "2025-01-01",
end: "2025-12-31",
}); // ✅
// Date range with options
const flexibleRange = dateRange({
allowSameDate: true, // Allow start = end
dateFormat: "US", // MM/DD/YYYY format
});
// Different date formats supported:
const isoRange = dateRange({ dateFormat: "ISO" }); // YYYY-MM-DD
const usRange = dateRange({ dateFormat: "US" }); // MM/DD/YYYY
const euRange = dateRange({ dateFormat: "EU" }); // DD/MM/YYYY
// Usage examples:
dateRange().validate({
start: "2025-01-01",
end: "2025-12-31",
}); // ✅ Valid range
dateRange().validate({
start: "2025-12-31",
end: "2025-01-01",
}); // ❌ Start after end
dateRange({ allowSameDate: true }).validate({
start: "2025-06-15",
end: "2025-06-15",
}); // ✅ Same date allowed
// Custom validation on date ranges
dateRange()
.custom((range) => {
const start = new Date(range.start);
const end = new Date(range.end);
const diffDays = (end.getTime() - start.getTime()) / (1000 * 60 * 60 * 24);
return diffDays <= 365 ? null : "Date range cannot exceed 1 year";
})
.validate({ start: "2025-01-01", end: "2025-12-31" }); // ✅
file()Creates a file validator for validating File objects or file-like data.
import { file } from "light-validate";
const validator = file()
.required() // File is required
.images() // Accept only image files
.maxSizeMB(5) // Maximum 5MB
.minSizeKB(10) // Minimum 10KB
.extensions(["jpg", "png"]) // Specific extensions
.types("IMAGE", "DOCUMENT") // File type categories
.mimeTypes(["image/jpeg", "image/png"]) // Specific MIME types
.custom((fileData) => {
// Custom validation (e.g., filename patterns)
return fileData.name.includes("profile") ? null : "Must be a profile image";
});
// File type categories available:
// IMAGE, AUDIO, VIDEO, DOCUMENT, TEXT, ARCHIVE, CODE
// File size methods:
file().maxSize(1024); // Maximum size in bytes
file().minSize(512); // Minimum size in bytes
file().maxSizeKB(500); // Maximum in kilobytes
file().minSizeKB(10); // Minimum in kilobytes
file().maxSizeMB(5); // Maximum in megabytes
file().minSizeMB(1); // Minimum in megabytes
// Multiple file type validation:
file().types("IMAGE", "DOCUMENT"); // Accept images and documents
file().extensions(["pdf", "jpg", "png"]); // Specific extensions
file().mimeTypes(["application/pdf", "image/jpeg"]); // MIME types
// Convenience methods for common file types:
file().images(); // Accept images only
file().audio(); // Accept audio files only
file().video(); // Accept video files only
file().documents(); // Accept documents only
file().textFiles(); // Accept text files only
file().archives(); // Accept archive files only
file().codeFiles(); // Accept code files only
// Note: Image dimension validation (width/height) can be implemented
// using custom validation with image processing libraries
All validators support custom error messages for internationalization and better UX:
import { string, number, object } from "light-validate";
// Individual custom messages
const nameValidator = string()
.required("نام ضروری ہے") // Name is required (Urdu)
.min(3, "کم از کم 3 حروف") // At least 3 characters (Urdu)
.email("صحیح ای میل درج کریں"); // Enter valid email (Urdu)
// Bulk custom messages using messages() method
const ageValidator = number()
.messages({
required: "Age is mandatory",
type: "Must be a valid number",
min: "Too young for this service",
max: "Age limit exceeded",
})
.required()
.min(18)
.max(65);
// Custom validation with custom error message
const passwordValidator = string().custom(
(password) =>
/^(?=.*[A-Z])(?=.*[a-z])(?=.*[0-9])/.test(password) ? null : "Invalid",
"پاس ورڈ میں کم از کم ایک بڑا حرف، چھوٹا حرف اور نمبر ہونا چاہیے"
);
All validators support these methods:
.required() - Makes the field required (fails on null/undefined).custom(validator) - Adds a custom validation functionType-specific methods:
.min(length), .max(length), .email(), .url(), .ip(), .uuid(), .time(), .slug(), .creditCard(), .iban(), .safeString(), .regex(pattern), .postalCode(country).min(value), .max(value).min(length), .max(length), .of(validator), .unique().maxSizeMB(), .extensions(), .mimeTypes(), .images(), .types(), etc.ISO, US, EU), .allowSameDate optionAll validators return a ValidationResult:
interface ValidationResult {
success: boolean;
errors?: string[];
}
Example:
// Success
{ success: true }
// Failure
{
success: false,
errors: ["This field is required", "Must be at least 3 characters"]
}
import { object, string, file, array } from "light-validate";
// Single file validation with comprehensive checks
const profileSchema = object({
name: string().required("نام ضروری ہے").min(2), // Urdu error message
avatar: file()
.required("تصویر اپ لوڈ کریں") // Upload image (Urdu)
.images() // Only image files
.maxSizeMB(5) // Maximum 5MB
.minSizeKB(10) // Minimum 10KB
.extensions(["jpg", "jpeg", "png"]) // Specific extensions
.mimeTypes(["image/jpeg", "image/png"]) // MIME type validation
.custom((fileData) => {
return fileData.name.includes("profile")
? null
: 'Filename must contain "profile"';
}),
});
// Multiple files validation with different types
const documentSchema = object({
title: string().required().min(5),
attachments: array()
.required()
.min(1, "At least one document required")
.max(5, "Maximum 5 documents allowed")
.of(
file()
.types("DOCUMENT", "TEXT") // PDF, DOC, CSV, etc.
.maxSizeMB(10) // Each file max 10MB
.mimeTypes([
"application/pdf",
"text/csv",
"application/vnd.openxmlformats-officedocument.wordprocessingml.document",
])
),
// Mixed media files
mediaFiles: array()
.of(
file()
.types("IMAGE", "VIDEO", "AUDIO") // Multiple categories
.maxSizeMB(50) // Larger limit for media
.custom((fileData) => {
// Custom business rule
if (
fileData.size > 20 * 1024 * 1024 &&
fileData.name.includes("preview")
) {
return "Preview files should be under 20MB";
}
return null;
})
)
.max(10, "Maximum 10 media files"),
});
// Advanced file validation with size and type checks
const advancedFileSchema = object({
documents: array().of(
file()
.documents() // Document files only
.maxSizeMB(25)
.extensions(["pdf", "docx", "xlsx"])
),
images: array().of(
file()
.images() // Image files only
.maxSizeMB(5)
.minSizeKB(50) // Prevent tiny/corrupt images
.mimeTypes(["image/jpeg", "image/png", "image/webp"])
),
archives: array().of(
file()
.archives() // ZIP, RAR, etc.
.maxSizeMB(100)
.extensions(["zip", "rar", "7z"])
),
});
// Usage with File objects from input[type="file"]
const fileInput = document.getElementById("upload") as HTMLInputElement;
const files = fileInput.files;
if (files && files.length > 0) {
const result = profileSchema.validate({
name: "احمد علی", // Urdu name
avatar: files[0], // File object
});
console.log(result);
}
import { object, string, number } from "light-validate";
// English version
const englishSchema = object({
email: string()
.required("Email is required")
.email("Please enter a valid email address"),
age: number()
.required("Age is required")
.min(18, "You must be at least 18 years old"),
});
// Urdu version with same validation logic
const urduSchema = object({
email: string()
.required("ای میل ایڈریس ضروری ہے")
.email("صحیح ای میل ایڈریس درج کریں"),
age: number()
.required("عمر ضروری ہے")
.min(18, "آپ کی عمر کم از کم 18 سال ہونی چاہیے"),
});
// Test data
const userData = { email: "invalid", age: 16 };
console.log("English:", englishSchema.validate(userData));
// English: { success: false, errors: ['email: Please enter a valid email address', 'age: You must be at least 18 years old'] }
console.log("Urdu:", urduSchema.validate(userData));
// Urdu: { success: false, errors: ['email: صحیح ای میل ایڈریس درج کریں', 'age: آپ کی عمر کم از کم 18 سال ہونی چاہیے'] }
import { object, string, number, file } from "light-validate";
// E-commerce product validation with business rules
const productSchema = object({
title: string()
.required("Product name is required")
.min(5, "Product name too short")
.custom((title) => {
// Business rule: No spam words allowed
const spamWords = ["free", "urgent", "limited"];
const hasSpam = spamWords.some((word) =>
title.toLowerCase().includes(word)
);
return hasSpam ? "Product name contains prohibited words" : null;
}),
price: number()
.required("Price is required")
.min(1, "Price must be positive")
.custom((price) => {
// Business rule: Price should be reasonable
if (price > 10000 && price % 1000 === 0) {
return "Price seems too rounded - please set market rate";
}
return null;
}),
images: array()
.required("Product images required")
.min(1, "At least one image required")
.max(10, "Maximum 10 images allowed")
.of(
file()
.images()
.maxSizeMB(5)
.custom((fileData) => {
// Business rule: Images must follow naming convention
return fileData.name.includes("product_")
? null
: 'Image filename must start with "product_"';
})
),
});
import { object, string, array, dateRange } from "light-validate";
// Comprehensive user profile validation
const userProfileSchema = object({
// Personal Information
username: string()
.required("صارف نام ضروری ہے") // Username required (Urdu)
.slug("صرف حروف، نمبرز، ڈیش اور انڈر سکور") // Only letters, numbers, dash, underscore (Urdu)
.min(3, "کم از کم 3 حروف")
.max(20, "زیادہ سے زیادہ 20 حروف"),
email: string().required("ای میل ضروری ہے").email("صحیح ای میل درج کریں"),
website: string()
.url("صحیح ویب سائٹ کا لنک درج کریں")
.custom((url) => {
// Business rule: Only allow HTTPS
return url.startsWith("https://") ? null : "صرف HTTPS لنکس کی اجازت ہے";
}),
phone: string().regex(
/^\+92[0-9]{10}$/,
"پاکستانی فون نمبر درج کریں (+92xxxxxxxxxx)"
),
// Security
ipAddress: string().ip("صحیح IP ایڈریس درج کریں"),
userId: string().uuid("صحیح UUID فارمیٹ درج کریں"),
// Financial
creditCard: string().creditCard("صحیح کریڈٹ کارڈ نمبر درج کریں"),
iban: string().iban("صحیح IBAN نمبر درج کریں"),
// Address
postalCode: string().postalCode("PK", "پاکستان کا صحیح پوسٹل کوڈ درج کریں"),
// Content Security
bio: string()
.safeString("غیر محفوظ مواد کی اجازت نہیں")
.max(500, "تعارف 500 حروف سے زیادہ نہیں ہو سکتا"),
// Time & Schedule
workingHours: object({
start: string().time("صحیح وقت فارمیٹ (HH:mm)"),
end: string().time("صحیح وقت فارمیٹ (HH:mm)"),
}),
// Project dates
projectDuration: dateRange({
dateFormat: "ISO",
allowSameDate: false,
})
.required("منصوبے کی تاریخ ضروری ہے")
.custom((range) => {
const start = new Date(range.start);
const end = new Date(range.end);
const diffMonths =
(end.getFullYear() - start.getFullYear()) * 12 +
(end.getMonth() - start.getMonth());
return diffMonths <= 24 ? null : "منصوبہ 2 سال سے زیادہ نہیں ہو سکتا";
}),
// Skills array with unique validation
skills: array()
.required("کم از کم ایک مہارت ضروری ہے")
.min(1, "کم از کم ایک مہارت")
.max(10, "زیادہ سے زیادہ 10 مہارتیں")
.unique("تمام مہارتیں منفرد ہونی چاہیے")
.of(
string()
.min(2, "مہارت کم از کم 2 حروف")
.slug("مہارت میں صرف حروف، نمبرز، ڈیش")
.custom((skill) => {
const forbiddenSkills = ["hacking", "spam", "fraud"];
return forbiddenSkills.includes(skill.toLowerCase())
? "یہ مہارت قابل قبول نہیں"
: null;
})
),
// Languages with proficiency
languages: array()
.min(1, "کم از کم ایک زبان")
.of(
object({
language: enumValidator([
"en",
"ur",
"ar",
"es",
"fr",
"de",
] as const).required("زبان کا انتخاب ضروری"),
proficiency: enumValidator([
"beginner",
"intermediate",
"advanced",
"native",
] as const).required("مہارت کی سطح"),
})
)
.unique("ہر زبان صرف ایک بار"),
});
// API validation example
const apiRequestSchema = object({
// Request validation
apiKey: string()
.required("API کلید ضروری")
.regex(/^[A-Za-z0-9]{32}$/, "API کلید 32 حروف کی ہونی چاہیے"),
callback: string()
.url("صحیح callback URL")
.custom((url) => {
// Security: Only allow HTTPS callbacks
return url.startsWith("https://") ? null : "Callback URL must use HTTPS";
}),
serverIp: string().required("سرور IP ضروری").ip("صحیح IP address"),
requestId: string().uuid("صحیح request UUID"),
// Data validation
payload: object({
data: string()
.safeString("غیر محفوظ ڈیٹا کی اجازت نہیں")
.max(10000, "ڈیٹا 10KB سے زیادہ نہیں"),
checksum: string().regex(/^[a-f0-9]{64}$/, "صحیح SHA-256 checksum"),
}),
});
// E-commerce validation
const productSchema = object({
sku: string()
.required("SKU ضروری")
.regex(/^[A-Z0-9-]{6,20}$/, "SKU: 6-20 حروف، بڑے حروف، نمبرز، ڈیش"),
pricing: object({
currency: enumValidator(["PKR", "USD", "EUR", "GBP"] as const).required(
"کرنسی کا انتخاب"
),
amount: number()
.min(0.01, "کم از کم 0.01")
.max(999999.99, "زیادہ سے زیادہ 999999.99"),
}),
availability: dateRange({
dateFormat: "ISO",
}).required("دستیابی کی تاریخ"),
tags: array()
.max(20, "زیادہ سے زیادہ 20 ٹیگز")
.unique("تمام ٹیگز منفرد")
.of(
string()
.slug("ٹیگ میں صرف حروف، نمبرز، ڈیش")
.min(2, "کم از کم 2 حروف")
.max(30, "زیادہ سے زیادہ 30 حروف")
),
});
// Usage examples
const profileResult = userProfileSchema.validate({
username: "zohaib_dev",
email: "zohaib@example.com",
website: "https://zohaib.dev",
phone: "+923001234567",
skills: ["javascript", "typescript", "react", "node"],
languages: [
{ language: "en", proficiency: "native" },
{ language: "ur", proficiency: "native" },
],
projectDuration: {
start: "2025-01-01",
end: "2025-06-30",
},
});
import { object, string, enum as enumValidator } from "light-validate";
// Basic enum validation
const orderSchema = object({
status: enumValidator([
"pending",
"processing",
"shipped",
"delivered",
] as const).required("Order status is required"),
priority: enumValidator([1, 2, 3, 4, 5] as const).required(
"Priority level is required"
),
});
// TypeScript enum support
enum PaymentMethod {
CREDIT_CARD = "credit_card",
DEBIT_CARD = "debit_card",
PAYPAL = "paypal",
BANK_TRANSFER = "bank_transfer",
}
enum SubscriptionTier {
FREE = 0,
BASIC = 1,
PREMIUM = 2,
ENTERPRISE = 3,
}
const subscriptionSchema = object({
paymentMethod: enumValidator(Object.values(PaymentMethod)).required(
"Payment method is required"
),
tier: enumValidator([
SubscriptionTier.FREE,
SubscriptionTier.BASIC,
SubscriptionTier.PREMIUM,
SubscriptionTier.ENTERPRISE,
])
.required("Subscription tier is required")
.custom((tier) => {
// Business rule: Free tier has limitations
if (tier === SubscriptionTier.FREE) {
return "Free tier signup is temporarily disabled";
}
return null;
}),
});
// Multi-language enum with custom messages
const languageSchema = object({
language: enumValidator(["en", "ur", "ar", "es", "fr"] as const)
.required("زبان کا انتخاب ضروری ہے") // Language selection required (Urdu)
.messages({
enum: "صرف مدد شدہ زبانیں منتخب کریں: انگریزی، اردو، عربی، ہسپانوی، فرانسیسی", // Only supported languages (Urdu)
}),
region: enumValidator(["US", "UK", "PK", "IN", "CA"] as const)
.required()
.custom((region) => {
return region === "PK"
? null
: "Service currently available in Pakistan only";
}),
});
// Usage examples
const result1 = orderSchema.validate({
status: "shipped",
priority: 3,
});
const result2 = subscriptionSchema.validate({
paymentMethod: PaymentMethod.CREDIT_CARD,
tier: SubscriptionTier.PREMIUM,
});
const result3 = languageSchema.validate({
language: "ur",
region: "PK",
});
The library provides sophisticated validation capabilities for complex data structures with chainable APIs.
import { array, string, number } from "light-validate";
// Sorted array validation
const sortedNumbers = array()
.of(number())
.sorted() // Ascending order
.notEmpty()
.validate([1, 2, 3, 4, 5]); // ✅
const sortedDescending = array()
.of(number())
.sorted("desc") // Descending order
.validate([5, 4, 3, 2, 1]); // ✅
// Type consistency validation
const stringArray = array()
.ofType("string") // All items must be strings
.notEmpty()
.validate(["apple", "banana", "cherry"]); // ✅
const numberArray = array()
.ofType("number") // All items must be numbers
.min(3) // At least 3 items
.max(10) // At most 10 items
.validate([1, 2, 3, 4, 5]); // ✅
// Exact length and content validation
const exactArray = array()
.length(3) // Exactly 3 items
.contains("required") // Must contain 'required'
.notContains("forbidden") // Must not contain 'forbidden'
.validate(["item1", "required", "item3"]); // ✅
// Complex array validation combining multiple rules
const advancedArray = array()
.of(string().min(2).max(20))
.notEmpty()
.length(5)
.sorted()
.ofType("string")
.contains("admin")
.unique()
.validate(["admin", "guest", "moderator", "user", "visitor"]); // ✅
import { object, string, number, array } from "light-validate";
// Non-empty and required keys validation
const userProfile = object({
name: string().required(),
email: string().email(),
age: number(),
skills: array(),
})
.notEmpty() // Object cannot be empty
.hasKeys(["name", "email"]) // These keys must exist
.validate({
name: "John Doe",
email: "john@example.com",
age: 30,
skills: ["JavaScript", "TypeScript"],
}); // ✅
// Strict keys validation (no unexpected properties)
const strictUser = object({
username: string().required(),
password: string().required(),
})
.hasKeys(["username", "password"])
.strictKeys() // Only defined keys allowed
.validate({
username: "johndoe",
password: "secret123",
// email: 'extra@example.com' // ❌ Would fail - unexpected key
}); // ✅
// Deep nested property validation using dot notation
const nestedValidation = object({
user: object({
profile: object({
personal: object({
name: string(),
contact: object({
email: string(),
phone: string(),
}),
}),
}),
settings: object({
preferences: array(),
}),
}),
})
.deepKey("user.profile.personal.name", string().min(2).required())
.deepKey("user.profile.personal.contact.email", string().email())
.deepKey("user.settings.preferences", array().notEmpty())
.validate({
user: {
profile: {
personal: {
name: "John",
contact: {
email: "john@test.com",
phone: "+1234567890",
},
},
},
settings: {
preferences: ["dark-mode", "notifications"],
},
},
}); // ✅
// Array contains validation within objects
const projectValidation = object({
name: string().required(),
technologies: array(),
categories: array(),
team: array(),
})
.arrayContains("technologies", "javascript") // Must use JavaScript
.arrayContains("categories", "web") // Must be web category
.arrayContains("team", "developer") // Must have a developer
.validate({
name: "My Web App",
technologies: ["javascript", "typescript", "react"],
categories: ["web", "frontend"],
team: ["developer", "designer", "manager"],
}); // ✅
// Plain object validation (reject special objects)
const plainObjectValidation = object({
data: string(),
metadata: object({}),
})
.plainObject() // Must be plain object, not Date/RegExp/etc
.validate({
data: "sample",
metadata: { version: "1.0" },
}); // ✅
// .validate(new Date()); // ❌ Would fail - not a plain object
// Enterprise-level validation combining all features
const enterpriseUserSchema = object({
profile: object({
personalInfo: object({
firstName: string().required(),
lastName: string().required(),
email: string().email().required(),
}),
professionalInfo: object({
skills: array(),
experience: number(),
certifications: array(),
}),
}),
account: object({
permissions: array(),
roles: array(),
status: string(),
}),
preferences: object({
notifications: array(),
privacy: object({}),
}),
})
.notEmpty()
.hasKeys(["profile", "account"])
.strictKeys()
.plainObject()
.deepKey("profile.personalInfo.firstName", string().min(2))
.deepKey("profile.personalInfo.lastName", string().min(2))
.deepKey(
"profile.professionalInfo.skills",
array().notEmpty().ofType("string")
)
.deepKey("account.permissions", array().notEmpty())
.arrayContains("account.roles", "user")
.arrayContains("preferences.notifications", "email")
.validate({
profile: {
personalInfo: {
firstName: "John",
lastName: "Doe",
email: "john.doe@company.com",
},
professionalInfo: {
skills: ["JavaScript", "TypeScript", "React"],
experience: 5,
certifications: ["AWS", "Google Cloud"],
},
},
account: {
permissions: ["read", "write", "delete"],
roles: ["user", "admin"],
status: "active",
},
preferences: {
notifications: ["email", "push", "sms"],
privacy: { shareProfile: false },
},
}); // ✅ Passes all validations
import { object, string, number, boolean } from "light-validate";
const userSchema = object({
username: string().required().min(3).max(20),
email: string().required().email(),
password: string()
.required()
.min(8)
.custom((value) => {
if (!/[A-Z]/.test(value)) return "Must contain uppercase letter";
if (!/[a-z]/.test(value)) return "Must contain lowercase letter";
if (!/[0-9]/.test(value)) return "Must contain number";
return null;
}),
age: number().required().min(13),
acceptTerms: boolean()
.required()
.custom((value) => {
return value === true ? null : "Must accept terms";
}),
});
const result = userSchema.validate({
username: "john_doe",
email: "john@example.com",
password: "SecurePass123",
age: 25,
acceptTerms: true,
});
import { object, string, array } from "light-validate";
const companySchema = object({
name: string().required(),
employees: array()
.of(
object({
name: string().required(),
email: string().email(),
department: string().required(),
})
)
.min(1),
address: object({
street: string().required(),
city: string().required(),
zipCode: string().min(5).max(10),
}).required(),
});
// Import only what you need for smaller bundle size
import { string as createStringValidator } from "light-validate";
import { number as createNumberValidator } from "light-validate";
const nameValidator = createStringValidator().required().min(2);
const ageValidator = createNumberValidator().min(0).max(120);
The library is written in TypeScript and provides excellent type inference:
import { object, string, number } from "light-validate";
// TypeScript will infer the correct types
const schema = object({
name: string().required(),
age: number(),
});
// result is typed as ValidationResult
const result = schema.validate(someData);
if (result.success) {
// No errors
console.log("Validation passed!");
} else {
// result.errors is string[]
console.log("Errors:", result.errors);
}
The library provides clear, descriptive error messages:
const schema = object({
name: string().required().min(3),
age: number().min(18),
});
const result = schema.validate({ name: "Jo", age: 15 });
console.log(result.errors);
// [
// "name: Must be at least 3 characters long",
// "age: Must be at least 18"
// ]
Light Validate is designed to be minimal:
| Feature | Light Validate | Yup | Joi | Zod |
|---|---|---|---|---|
| Bundle Size | ~3KB | ~65KB | ~145KB | ~30KB |
| Dependencies | 0 | Several | Several | 0 |
| Tree Shaking | ✅ | ❌ | ❌ | ✅ |
| TypeScript | ✅ | ✅ | ❌ | ✅ |
| Learning Curve | Easy | Medium | Medium | Medium |
MIT
Contributions are welcome! Please feel free to submit a Pull Request.
FAQs
A lightweight TypeScript object validation library with zero dependencies
The npm package zee-light-validate receives a total of 0 weekly downloads. As such, zee-light-validate popularity was classified as not popular.
We found that zee-light-validate demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Product
Add real-time Socket webhook events to your workflows to automatically receive software supply chain alert changes in real time.

Security News
ENISA has become a CVE Program Root, giving the EU a central authority for coordinating vulnerability reporting, disclosure, and cross-border response.

Product
Socket now scans OpenVSX extensions, giving teams early detection of risky behaviors, hidden capabilities, and supply chain threats in developer tools.