Skip to main content
Version: 6.x

Data Parsers

Data parsers transform values as they pass through an enforce chain. Unlike validation rules that only check whether a value is valid, parsers coerce the value into a new form — trimming whitespace, converting types, clamping numbers, and more.

Parsers are available on lazy chains started with a type rule such as enforce.isString(), enforce.isNumber(), or enforce.isArray(). They are not available on eager enforce(value) chains.

Accessing parsed results​

Use .run() or .parse() to get the transformed output:

// .run() returns { pass, type } — type holds the transformed value
const result = enforce.isString().trim().toUpper().run(' hello ');
// result → { pass: true, type: 'HELLO' }

// .parse() returns the transformed value directly, or throws on failure
const value = enforce.isString().trim().toUpper().parse(' hello ');
// value → 'HELLO'

Parsers also work inside schema definitions, so schema.parse(data) returns a fully transformed object:

const schema = enforce.shape({
name: enforce.isString().trim().toTitle(),
age: enforce.isNumeric().toNumber().clamp(0, 120),
});

schema.parse({ name: ' jANE DOE ', age: '180' });
// → { name: 'Jane Doe', age: 120 }

String Parsers​

Available on enforce.isString() chains.

trim​

Removes leading and trailing whitespace.

enforce.isString().trim().parse('  vest  ');
// → 'vest'

trimStart​

Removes leading whitespace only.

enforce.isString().trimStart().parse('  vest');
// → 'vest'

trimEnd​

Removes trailing whitespace only.

enforce.isString().trimEnd().parse('vest  ');
// → 'vest'

toUpper​

Converts to uppercase.

enforce.isString().toUpper().parse('vest');
// → 'VEST'

toLower​

Converts to lowercase.

enforce.isString().toLower().parse('VeSt');
// → 'vest'

toTitle​

Capitalizes the first letter of each word.

enforce.isString().toTitle().parse('hello world');
// → 'Hello World'

toCapitalized​

Capitalizes the first character and lowercases the rest.

enforce.isString().toCapitalized().parse('vEST');
// → 'Vest'

toCamel​

Converts to camelCase.

enforce.isString().toCamel().parse('hello_world-test');
// → 'helloWorldTest'

toPascal​

Converts to PascalCase.

enforce.isString().toPascal().parse('hello_world-test');
// → 'HelloWorldTest'

toSnake​

Converts to snake_case.

enforce.isString().toSnake().parse('helloWorld Test');
// → 'hello_world_test'

toKebab​

Converts to kebab-case.

enforce.isString().toKebab().parse('helloWorld Test');
// → 'hello-world-test'

append​

Appends a suffix string.

enforce.isString().append('-js').parse('vest');
// → 'vest-js'

prepend​

Prepends a prefix string.

enforce.isString().prepend('hello-').parse('vest');
// → 'hello-vest'

replace​

Replaces the first match of a search value.

enforce.isString().replace('rocks', 'rules').parse('vest rocks');
// → 'vest rules'

replaceAll​

Replaces all occurrences of a search value.

enforce.isString().replaceAll('vest', 'n4s').parse('vest vest vest');
// → 'n4s n4s n4s'

split​

Splits a string into an array by a separator. Accepts an optional limit.

enforce.isString().split(',', 2).parse('a,b,c');
// → ['a', 'b']

normalizeWhitespace​

Collapses multiple whitespace characters into a single space and trims.

enforce.isString().normalizeWhitespace().parse('  v   e   s t  ');
// → 'v e s t'

stripWhitespace​

Removes all whitespace characters.

enforce.isString().stripWhitespace().parse(' v e s t ');
// → 'vest'

removeNonAlphanumeric​

Removes all characters that are not letters or digits.

enforce.isString().removeNonAlphanumeric().parse('v-e_s t!42');
// → 'vest42'

removeNonDigits​

Removes all non-digit characters.

enforce.isString().removeNonDigits().parse('v1e2s3t');
// → '123'

removeNonLetters​

Removes all non-letter characters.

enforce.isString().removeNonLetters().parse('v1e_2s-3t!');
// → 'vest'

Number Parsers​

Available on enforce.isNumber() and enforce.isNumeric() chains.

round​

Rounds to the nearest integer.

enforce.isNumber().round().parse(2.5);
// → 3

ceil​

Rounds up to the next integer.

enforce.isNumber().ceil().parse(2.1);
// → 3

floor​

Rounds down to the previous integer.

enforce.isNumber().floor().parse(2.9);
// → 2

clamp​

Clamps a value between a minimum and maximum.

enforce.isNumeric().toNumber().clamp(0, 100).parse('120');
// → 100

enforce.isNumber().clamp(0, 100).parse(-5);
// → 0

toAbsolute​

Returns the absolute value.

enforce.isNumber().toAbsolute().parse(-15);
// → 15

toFloat​

Parses a value into a floating-point number. Fails if the result is NaN.

enforce.isNumeric().toFloat().parse('10.5');
// → 10.5

toInteger​

Parses a value into an integer. Accepts an optional radix (2–36, default 10). Fails if the result is NaN.

enforce.isNumeric().toInteger().parse('11.8');
// → 11

enforce.isNumeric().toInteger(2).parse('1011');
// → 11

toDate​

Parses a string, number, or Date into a Date object. Fails for invalid or non-date-like inputs.

enforce.isNumber().toDate().parse(1704067200000);
// → Date object (2024-01-01T00:00:00.000Z)

Array Parsers​

Available on enforce.isArray() chains.

uniq​

Removes duplicate elements (uses Set).

enforce.isArray().uniq().parse(['a', 'a', 'b']);
// → ['a', 'b']

join​

Joins array elements into a string with a separator (default ',').

enforce.isArray().join('-').parse(['a', 'b', 'c']);
// → 'a-b-c'

General Parsers​

Available on all typed chains (isString, isNumber, isNumeric, isArray).

toBoolean​

Parses a value into a boolean. Recognizes common truthy/falsy representations. Fails for unrecognized input.

Truthy values: true, 1, 'true', '1', 'yes', 'on'

Falsy values: false, 0, 'false', '0', 'no', 'off'

enforce.isString().trim().toBoolean().parse(' yes ');
// → true

enforce.isString().trim().toBoolean().parse('0');
// → false

// Fails for unrecognized values:
enforce.isString().toBoolean().run('unknown');
// → { pass: false, type: false, message: 'Could not parse to boolean' }

parseJSON​

Parses a JSON string into a JavaScript value. Fails if the input is not valid JSON.

enforce.isString().parseJSON().parse('{"name":"vest"}');
// → { name: 'vest' }

defaultTo​

Provides a fallback value for null or undefined inputs. This parser runs before other rules in the chain, so the fallback is applied before type checks.

const schema = enforce.shape({
label: enforce.isString().defaultTo('N/A'),
});

schema.parse({ label: null });
// → { label: 'N/A' }

schema.parse({ label: 'hello' });
// → { label: 'hello' }

Chaining Parsers​

Parsers can be chained together to build transformation pipelines. Each parser receives the output of the previous one:

const schema = enforce.shape({
name: enforce.isString().trim().toTitle(),
age: enforce.isNumeric().toNumber().clamp(0, 120),
subscribed: enforce.isString().trim().toBoolean(),
tags: enforce.isArray().uniq().join('|'),
payload: enforce.isString().parseJSON(),
nickname: enforce.isString().trim().defaultTo('N/A'),
});

schema.parse({
name: ' jANE DOE ',
age: '180',
subscribed: ' yes ',
tags: ['vest', 'n4s', 'vest'],
payload: '{"env":"test"}',
nickname: ' ',
});
// → {
// name: 'Jane Doe',
// age: 120,
// subscribed: true,
// tags: 'vest|n4s',
// payload: { env: 'test' },
// nickname: '',
// }

TypeScript type inference​

Parser chains correctly distinguish between input and output types. The first rule in the chain determines the input type (what the caller passes in), and the last parser determines the output type (what the consumer receives).

// Input: string | number → Output: number
const ageRule = enforce.isNumeric().toNumber().clamp(0, 120);

// Input: string → Output: boolean
const subscribedRule = enforce.isString().trim().toBoolean();

// Input: string[] → Output: string
const tagsRule = enforce.isArray<string>().uniq().join('|');

When used inside a Vest suite schema, this means suite.run() accepts the input types while the suite callback and result.value use the output types — no type casts needed.