JSPM

  • ESM via JSPM
  • ES Module Entrypoint
  • Export Map
  • Keywords
  • License
  • Repository URL
  • TypeScript Types
  • README
  • Created
  • Published
  • Downloads 18
  • Score
    100M100P100Q74383F
  • License MIT

Fluent TypeScript validation checks for objects, arrays, files, and images.

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/checks

Optional peer dependencies

The core object, array, string, number, and date validators work with just:

npm install @samatawy/checks

If you use FileCheck, ImageCheck, field.file(), or field.image(), also install the binary inspection peer dependencies:

npm install @samatawy/checks file-type probe-image-size

Why these are optional:

  • file-type is used to detect MIME types from file buffers
  • probe-image-size is 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

  • ObjectCheck
  • FieldCheck
  • ArrayCheck
  • ArrayItemCheck
  • StringCheck
  • NumberCheck
  • DateCheck
  • FileCheck
  • ImageCheck
  • ValueCheck

Shared types

  • Check
  • CheckOptions
  • StringCheckOptions
  • SingleResult
  • ResultSet
  • IResult

Helpers

  • defined(value) narrows away null and undefined
  • buildErrorMessage(err, options) builds a result payload compatible with the check classes
  • appendError(result, err, options) appends messages to an existing result
  • collectResults(resultSet) merges duplicate field results and flattens nested output
  • isPromise(value) detects promise-like values used by async checks
  • createPackageSummary(input) remains available as the original starter utility

Validation model

The API is designed around fluent checks that accumulate validation output.

  • required(name) asserts that a field exists
  • optional(name) starts a field check without requiring presence
  • check(...) applies nested object rules
  • check_each(...) applies nested array item rules
  • is_true(...) and is_true_each(...) let you add custom predicates
  • file() and image() create asynchronously initialized binary validators
  • result() returns the immediate result state
  • collect() flattens nested results into hints, warnings, and errors

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 build

Useful scripts:

  • npm run build builds ESM, CJS, and declaration files into dist/
  • npm run dev watches the package entrypoint
  • npm run lint runs TypeScript type checking
  • npm test runs the Vitest suite once
  • npm run test:watch runs 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

Before publishing

Review and update the package metadata in package.json before publishing:

  • name
  • description
  • author
  • repository
  • bugs
  • homepage

License

MIT