0.0.0 • Published 7 months ago

navapi v0.0.0

Weekly downloads
-
License
MIT
Repository
-
Last release
7 months ago

Expressive Validation for Objects.

An object validation library with a strong TypeScript support.

Installation

npm install xvo

Usage

import { x } from 'xvo';
// Declare
const schema = x.union(
    x.object({
        account_type: x.literal('individual'),
        first_name: x.string(),
        last_name: x.string(),
        phone_number: x.string().phone(),
        email: x.string().email(),
        nickname: x.string().optional(),
        email_verified: x.boolean().default(false)
    }),
    x.object({
        account_type: x.literal('business'),
        business_name: x.string(),
        phone_number: x.string().phone(),
        email: x.string().email(),
        alias: x.string().optional(),
        email_verified: x.boolean().default(false)
    })
);
// Parse
const result = schema.parse({
    account_type: 'individual',
    first_name: 'John',
    last_name: 'Doe',
    phone_number: '+1 (123) 456-7890',
    email_verified: 'user@example.com'
});
// result: { ok: boolean }
if (!result.ok) {
    // result: { ok: false, error: XvoError }
    throw new Error(x.error_to_string(result.error));
}
// result: { ok: true, value: object }
const value = result.value;
console.log(value);
{
    "account_type": "individual",
    "first_name": "John",
    "last_name": "Doe",
    "phone_number": "+11234567890",
    "email": "user@example.com",
    "verified": false
}
if (value.account_type === 'individual') {
    console.log("Welcome back, " + value.first_name + "!");
}
"Welcome back, John!"

Custom Error-Handling

if (!result.ok) {
    // result: { ok: false, error: XvoError }
    const error = result.error;
    switch (error.type) {
        'missing_required':
            // error: { type: 'missing_required', field: string }
            break;
        default:
            // 'invalid_type' |
            // 'invalid_range' |
            // 'invalid_pattern' |
            // 'invalid_format' |
            // 'invalid_literal' |
            // 'custom', 'unknown' ...
            break;
    }
}

RFC-compliant Normalization

(Default - On) Receive RFC-compliant version of the value, as long as it is a valid phone number.

x.string().phone().parse('+1 (123) 456-7890'); 
// { ok: true, value: '+11234567890'; }

(Off) Receive value as-is, as long as it is a valid phone number.

x.string().phone(false).parse('+1 (123) 456-7890'); 
// { ok: true, value: '+1 (123) 456-7890'; }

This does not affect the validation of the fields—both are valid. It only affects the received value on the result object.

No redundant method-chaining

// 🚫 Invalid: Mixing optional and default doesn't make logical sense.
x.string().optional().default("example").optional(); // invalid
x.string().optional().default("example"); // invalid

// ✅ Valid: Choose one approach—`default()` inherently makes the field optional.
x.string().default("example"); // valid

Cleaner Type Errors for Easier Developement

Example with comparison to other validation libraries

Setting .default(null) without .nullable().

In Zod: z.string().default(null) -> Type Error.

No overload matches this call.
  Overload 1 of 2, '(def: string): ZodDefault<ZodString>', gave the following error.
    Argument of type 'null' is not assignable to parameter of type 'string'.
  Overload 2 of 2, '(def: () => string): ZodDefault<ZodString>', gave the following error.
    Argument of type 'null' is not assignable to parameter of type '() => string'.

In Xvo: x.string().default(null) -> Type Error.

Argument of type 'null' is not assignable to parameter of type 'string'.
0.0.0

7 months ago