@samatawy/checks
    Preparing search index...

    Composite Checks

    Use these helpers when one validator needs to combine several rule branches.

    Use check(...) when you want to attach ordinary nested object or array rules.

    Use checkEach(...) when you want to run ordinary rules for each array item.

    Use allOf(...) when you want JSON-Schema-style naming for “all returned checks must pass” inside one composed branch. In practice, allOf(...) is an alias for the same grouped behavior as check(...) on ObjectCheck and ArrayCheck, and a grouped wrapper on FieldCheck and ArrayItemCheck.

    import { ObjectCheck } from '@samatawy/checks';

    const check = await ObjectCheck.for({
    profile: {
    name: 'Ada',
    age: 37
    }
    }).check(root => [
    root.required('profile').object().allOf(profile => [
    profile.required('name').string().minLength(2),
    profile.required('age').number().atLeast(18)
    ])
    ]);

    If you do not need JSON-Schema-style naming for an “all checks must pass” group, plain check(...) is still the most direct tool on objects and arrays. checkEach(...) remains the array-item entry point when you need to validate each item individually.

    Use contains(...) when an array is valid as long as some bounded number of items match one nested item rule.

    import { ObjectCheck } from '@samatawy/checks';

    const check = await ObjectCheck.for({
    tags: [' x ', ' Ada ']
    }).check(root => [
    root.required('tags').array().contains(item => [
    item.string().trim().minLength(2)
    ], {
    minCount: 1,
    maxCount: 2
    })
    ]);

    Unlike checkEach(...), non-matching items do not emit their own errors. contains(...) only reports an aggregate failure when too few or too many items satisfy the nested checks.

    Use anyOf(...) when more than one rule shape is acceptable and at least one branch may pass.

    import { ObjectCheck } from '@samatawy/checks';

    const input = {
    profile: {
    name: ' Ada ',
    age: '37'
    }
    };

    const check = await ObjectCheck.for(input).check(root => [
    root.required('profile').object().anyOf([
    profile => [
    profile.required('name').string().trim().minLength(3)
    ],
    profile => [
    profile.required('age').number({ tolerant: true }).greaterThan(17)
    ]
    ])
    ]);

    const result = check.result({ language: 'en' });

    console.log(result.valid);
    console.log(input.profile.name);
    console.log(input.profile.age);

    Valid anyOf(...) branches are replayed on the real object, so mutations such as trim() or tolerant parsing still affect the original input.

    Use oneOf(...) when several branches are possible but exactly one must pass.

    import { ObjectCheck } from '@samatawy/checks';

    const check = await ObjectCheck.for({
    value: '37'
    }).check(root => [
    root.required('value').oneOf([
    field => [field.number({ tolerant: true }).greaterThan(10)],
    field => [field.string().minLength(2)]
    ])
    ]);

    const result = check.result({ flattened: true, language: 'en' });
    console.log(result.errors);

    That pattern is useful when overlapping rule branches would be a problem and should be reported explicitly.

    Use not(...) when one specific rule shape must not match.

    import { ObjectCheck } from '@samatawy/checks';

    const input = {
    profile: {
    name: ' Ada '
    }
    };

    const check = await ObjectCheck.for(input).check(root => [
    root.required('profile').object().not(profile => [
    profile.required('name').string().trim().minLength(3)
    ])
    ]);

    const result = check.result({ flattened: true, language: 'en' });
    console.log(result.errors);
    console.log(input.profile.name);

    Unlike anyOf(...) and oneOf(...), not(...) runs its branch on isolated data and never replays mutations onto the original input.

    • allOf(fn) takes one callback returning the checks that must all pass
    • anyOf([branch1, branch2]) takes an array of branch functions and succeeds when one or more branches pass
    • oneOf([branch1, branch2]) takes an array of branch functions and succeeds only when exactly one branch passes
    • not(fn) takes one callback returning the checks that must fail

    FieldCheck also supports allOf(...), anyOf(...), oneOf(...), and not(...) when one field can satisfy more than one rule shape.

    import { ObjectCheck } from '@samatawy/checks';

    const check = await ObjectCheck.for({
    value: '37'
    }).check(root => [
    root.required('value').allOf(field => [
    field.number({ tolerant: true }).greaterThan(10),
    field.equals(37)
    ])
    ]);

    ArrayCheck and ArrayItemCheck support the same composition family for whole-array alternatives, per-item alternatives, and negated branches.

    import { ObjectCheck } from '@samatawy/checks';

    const check = await ObjectCheck.for({
    tags: [' Ada ', ' Bob ']
    }).check(root => [
    root.required('tags').array().anyOf([
    tags => [tags.checkEach(item => [item.string().trim().minLength(2)])],
    tags => [tags.maxLength(1)]
    ])
    ]);
    import { ObjectCheck } from '@samatawy/checks';

    const check = await ObjectCheck.for({
    values: [' Ada ']
    }).check(root => [
    root.required('values').array().checkEach(item => [
    item.oneOf([
    entry => [entry.string().trim().minLength(2)],
    entry => [entry.number({ tolerant: true }).greaterThan(10)]
    ])
    ])
    ]);