Package Exports
- @samatawy/checks
Readme
@samatawy/checks
TypeScript validation utilities for fluent object, array, field, string, number, date, file, and image checks.
The package builds to both ESM and CommonJS, ships declaration files, and exposes a validation DSL that supports both synchronous and asynchronous rules.
Installation
npm install @samatawy/checksOptional peer dependencies
The core object, array, string, number, and date validators work with just:
npm install @samatawy/checksIf you use FileCheck, ImageCheck, field.file(), or field.image(), also install the binary inspection peer dependencies:
npm install @samatawy/checks file-type probe-image-sizeWhy these are optional:
file-typeis used to detect MIME types from file buffersprobe-image-sizeis used for image metadata in Node runtimes- browser image dimension checks can also use browser-native APIs, so these packages are not required for every consumer
Quick start
import { ObjectCheck } from '@samatawy/checks';
const check = await ObjectCheck.for({
name: 'Sam',
age: 34,
address: {
city: 'Cairo'
}
})
.notEmpty()
.check(person => [
person.required('name').string().minLength(2),
person.optional('age').number().atLeast(18),
person.required('address').object().check(address => [
address.required('city').string()
])
]);
const result = check.collect();
if (!result.valid) {
console.error(result.errors);
}check, rules, is_true, check_each, is_true_each, file, and image may all be async depending on which validators you use, so await at the rule boundary is the safe default.
Public API
Entry points
Everything is exported from the package root in src/index.ts.
Check classes
ObjectCheckFieldCheckArrayCheckArrayItemCheckStringCheckEmailCheckUrlCheckNumberCheckDateCheckFileCheckImageCheckValueCheck
Shared types
CheckCheckOptionsStringCheckOptionsSingleResultResultSetIResult
Validation model
The API is designed around fluent checks that accumulate validation output.
required(name)asserts that a field existsoptional(name)starts a field check without requiring presenceconditional(name, condition)requires a field only when another condition is metnoExtraFields()rejects undeclared object keys when collecting resultscheck(...)applies nested object rulescheck(...)on arrays applies array-level rules and nested synthetic resultscheck_each(...)applies nested array item rulesnoDuplicates()rejects duplicate array values or duplicate keys when you provide a selector keyis_true(...)andis_true_each(...)let you add custom predicatesfile()andimage()create asynchronously initialized binary validatorsemail()andurl()are available from bothFieldCheckandStringCheckand branch into protocol-specific validatorstrim(),integer(),positive(),isBase64(), and related helpers support common string and number validation tasksresult()returns the immediate result statecollect()returns nested results with flattenedhints,warnings, anderrorscollectFlat()returns a flattened result structure onlycollectNested()returns a nested result structure that mirrors the input shape
String-related inheritance:
StringCheck,EmailCheck, andUrlCheckshare the common string comparison methods through an internalStringBaseCheck- those inherited methods are available on the exported concrete classes;
StringBaseCheckitself is internal and is not required for consumers
Example with warnings and nested arrays:
import { ObjectCheck } from '@samatawy/checks';
const check = await ObjectCheck.for({
child_count: 2,
children: [{ name: 'A', age: 10 }, { name: 'B', age: 19 }]
})
.check(person => [
person.optional('children').array().maxLength(10)
.check_each(child => [
child.object(),
child.required('name').string(),
child.optional('age').number().greaterThan(0).atMost(17)
]),
person.is_true(data => (data.child_count || 0) === (data.children?.length || 0), {
warn: 'child_count should equal the number of children'
})
]);
const result = check.collect();Example with files and images:
import { ObjectCheck } from '@samatawy/checks';
const check = await ObjectCheck.for(input).check(person => [
person.optional('avatar').file().then(file =>
file.notEmpty()
.mimeType('image/*')
.minSize(5 * 1024)
.maxSize(5 * 1024 * 1024)
),
person.optional('avatar').image().then(image =>
image.isImage()
.minWidth(200)
.minHeight(200)
.maxWidth(2000)
.maxHeight(2000)
)
]);
const result = check.collect();Result shapes
SingleResult represents a single validation outcome.
interface SingleResult {
valid: boolean;
field?: string | number | null | undefined;
hint?: string | string[];
warn?: string | string[];
err?: string;
}ResultSet extends that model with nested results plus flattened hints, warnings, and errors arrays.
CheckOptions supports either a single hint/warn string or an array of messages:
interface CheckOptions {
hint?: string | string[];
warn?: string | string[];
err?: string;
}Development
npm install
npm run lint
npm test
npm run buildUseful scripts:
npm run buildbuilds ESM, CJS, and declaration files intodist/npm run devwatches the package entrypointnpm run lintruns TypeScript type checkingnpm testruns the Vitest suite oncenpm run test:watchruns Vitest in watch mode
When validating integration in this workspace, use the package build output from dist/ and then rebuild the local consumer package if it depends on file:../checks.
Documentation
License
MIT