Generic configuration validation tool that helps with warnings, errors and deprecation messages as well as showing users examples of correct configuration.
npx @tessl/cli install tessl/npm-jest-validate@30.1.0jest-validate is a generic configuration validation tool that helps with warnings, errors and deprecation messages as well as showing users examples of correct configuration. Originally developed for Jest, it provides a comprehensive validation framework for JavaScript/Node.js applications with extensive customization options.
npm install jest-validateimport { validate, validateCLIOptions, multipleValidOptions, ValidationError, format, formatPrettyObject, createDidYouMeanMessage, logValidationWarning } from "jest-validate";For CommonJS:
const { validate, validateCLIOptions, multipleValidOptions, ValidationError, format, formatPrettyObject, createDidYouMeanMessage, logValidationWarning } = require("jest-validate");import { validate, multipleValidOptions } from "jest-validate";
// Define example configuration (required)
const exampleConfig = {
transform: {},
testMatch: ["**/__tests__/**/*.(js|ts)"],
verbose: false,
timeout: 5000,
retries: multipleValidOptions(1, false) // allows number or boolean
};
// Validate user configuration
const result = validate(userConfig, { exampleConfig });
if (result.isValid) {
console.log("Configuration is valid!");
if (result.hasDeprecationWarnings) {
console.log("Note: Some deprecated options were found");
}
}jest-validate is built around several key components:
validate() function that compares configurations against example schemasvalidateCLIOptions() for command-line argument validation with deprecation supportmultipleValidOptions() utility for options that accept different typesValidationError class with formatted, colorized outputCore validation functionality that compares user configurations against example schemas with comprehensive error reporting and type checking.
/**
* Validates a configuration object against an example configuration schema
* @param config - The configuration object to validate
* @param options - Validation options including required exampleConfig
* @returns Validation result with deprecation warnings flag and validity status
*/
function validate(
config: Record<string, unknown>,
options: ValidationOptions
): { hasDeprecationWarnings: boolean; isValid: boolean };
interface ValidationOptions {
/** Additional comment text to display with error/warning messages */
comment?: string;
/** Custom validation condition function for comparing option values */
condition?: (option: unknown, validOption: unknown) => boolean;
/** Custom deprecation handler function */
deprecate?: (
config: Record<string, unknown>,
option: string,
deprecatedOptions: DeprecatedOptions,
options: ValidationOptions
) => boolean;
/** Object mapping deprecated option names to deprecation message functions */
deprecatedConfig?: DeprecatedOptions;
/** Custom error handler function */
error?: (
option: string,
received: unknown,
defaultValue: unknown,
options: ValidationOptions,
path?: Array<string>
) => void;
/** Required example configuration object that defines valid structure and types */
exampleConfig: Record<string, unknown>;
/** Whether to recursively validate nested objects (default: true) */
recursive?: boolean;
/** Array of key paths to exclude from recursive validation */
recursiveDenylist?: Array<string>;
/** Custom titles for error/warning messages */
title?: Title;
/** Custom handler for unknown/unrecognized options */
unknown?: (
config: Record<string, unknown>,
exampleConfig: Record<string, unknown>,
option: string,
options: ValidationOptions,
path?: Array<string>
) => void;
}
interface Title {
deprecation?: string;
error?: string;
warning?: string;
}
type DeprecatedOptions = Record<string, DeprecatedOptionFunc>;
type DeprecatedOptionFunc = (arg: Record<string, unknown>) => string;Usage Examples:
import { validate } from "jest-validate";
// Basic validation
const result = validate(userConfig, {
exampleConfig: {
verbose: true,
testTimeout: 5000,
setupFiles: []
}
});
// Custom validation with deprecation handling
const result = validate(userConfig, {
exampleConfig: { verbose: true },
deprecatedConfig: {
silent: () => 'Option "silent" has been replaced by "verbose"'
},
comment: 'See documentation at https://example.com/config'
});
// Recursive validation with denylist
const result = validate(userConfig, {
exampleConfig: { nested: { allowed: true, ignored: {} } },
recursive: true,
recursiveDenylist: ['nested.ignored'] // Skip validating nested.ignored
});Validates command-line options against allowed option schemas with support for deprecated options, aliases, and automatic suggestion generation.
/**
* Validates CLI options and arguments with deprecation support
* @param argv - Parsed command-line arguments object (typically from yargs)
* @param options - Object defining allowed options and their configuration
* @param rawArgv - Optional raw argument array for filtering
* @returns true if validation passes, throws ValidationError if not
*/
function validateCLIOptions(
argv: Config.Argv,
options: Record<string, Options> & { deprecationEntries?: DeprecatedOptions },
rawArgv?: Array<string>
): boolean;
interface Options {
/** Alias for the option (single string or array of strings) */
alias?: string | string[];
/** Additional option properties from yargs */
[key: string]: any;
}
type Config.Argv = Record<string, unknown>;Usage Examples:
import { validateCLIOptions } from "jest-validate";
// Define allowed CLI options
const allowedOptions = {
verbose: { alias: 'v' },
config: { alias: 'c' },
watch: { alias: 'w' },
help: { alias: 'h' }
};
// Validate CLI arguments
try {
validateCLIOptions(parsedArgs, allowedOptions);
console.log("CLI options are valid");
} catch (error) {
console.error(error.message);
}
// With deprecation entries
const optionsWithDeprecation = {
...allowedOptions,
deprecationEntries: {
runInBand: () => 'Option "runInBand" has been replaced by "maxWorkers=1"'
}
};
validateCLIOptions(parsedArgs, optionsWithDeprecation);Utility for creating configuration options that accept multiple types, enabling flexible API design while maintaining type safety.
/**
* Creates a configuration that accepts multiple valid types for a single option
* Uses internal symbol marking to allow validation against multiple type examples
* @param args - Variable number of example values of different types
* @returns Array containing the examples, marked internally for multi-type validation
*/
function multipleValidOptions<T extends Array<unknown>>(...args: T): T[number];Usage Examples:
import { validate, multipleValidOptions } from "jest-validate";
// Allow string or number for maxWorkers
const exampleConfig = {
maxWorkers: multipleValidOptions("50%", 4),
verbose: multipleValidOptions(true, "full"), // boolean or specific string
timeout: multipleValidOptions(5000, "30s") // number or string
};
const result = validate({
maxWorkers: "75%", // Valid - matches string type
verbose: true, // Valid - matches boolean type
timeout: "45s" // Valid - matches string type
}, { exampleConfig });Custom error class for validation failures with formatted, colorized output designed for developer-friendly error messages.
/**
* Custom error class for validation failures with formatted output
*/
class ValidationError extends Error {
override name: string;
override message: string;
/**
* Creates a new validation error with formatted message
* @param name - Error name/title to display
* @param message - Main error message content
* @param comment - Optional additional comment or documentation reference
*/
constructor(name: string, message: string, comment?: string | null);
}Helper functions for formatting values and creating user-friendly error messages.
/**
* Formats values for display in error messages
* @param value - Value to format (any type)
* @returns Formatted string representation
*/
function format(value: unknown): string;
/**
* Formats values as pretty-printed objects for display
* @param value - Value to format (any type)
* @returns Pretty-formatted string representation with indentation
*/
function formatPrettyObject(value: unknown): string;
/**
* Creates suggestion messages for similar option names using edit distance
* @param unrecognized - The unrecognized option name
* @param allowedOptions - Array of valid option names
* @returns Suggestion message or empty string if no close matches
*/
function createDidYouMeanMessage(
unrecognized: string,
allowedOptions: Array<string>
): string;
/**
* Logs validation warnings to console with formatted output
* @param name - Warning name/title
* @param message - Warning message content
* @param comment - Optional additional comment
*/
function logValidationWarning(
name: string,
message: string,
comment?: string | null
): void;Usage Examples:
import { ValidationError, format, createDidYouMeanMessage } from "jest-validate";
// Custom error handling
try {
// Some validation logic
throw new ValidationError(
"Custom Validation Error",
`Invalid value: ${format(userValue)}`,
"Check the documentation for valid options"
);
} catch (error) {
console.error(error.message); // Formatted, colorized output
}
// Generate suggestions
const suggestion = createDidYouMeanMessage("verbos", ["verbose", "version"]);
console.log(suggestion); // "Did you mean verbose?"
// Format various value types
console.log(format("hello")); // "hello"
console.log(format(42)); // 42
console.log(format([1, 2, 3])); // [1, 2, 3]
console.log(format(undefined)); // undefined
// Format with pretty printing for objects
console.log(formatPrettyObject({ name: "test", value: 42 }));
// Output:
// {
// "name": "test",
// "value": 42
// }import { validate } from "jest-validate";
const result = validate(userConfig, {
exampleConfig: { port: 3000 },
condition: (option, validOption) => {
// Custom logic for port validation
if (typeof option === 'number' && typeof validOption === 'number') {
return option > 0 && option < 65536;
}
return option === validOption;
}
});import { validate, ValidationError } from "jest-validate";
const result = validate(userConfig, {
exampleConfig: { timeout: 5000 },
error: (option, received, defaultValue, options, path) => {
const fullPath = path ? `${path.join('.')}.${option}` : option;
throw new ValidationError(
"Configuration Error",
`Option "${fullPath}" expected ${typeof defaultValue} but got ${typeof received}`,
"Please check your configuration file"
);
}
});import { validate } from "jest-validate";
const result = validate(userConfig, {
exampleConfig: { knownOption: true },
unknown: (config, exampleConfig, option, options, path) => {
const fullPath = path ? `${path.join('.')}.${option}` : option;
console.warn(`Unknown option "${fullPath}" will be ignored`);
// Could also delete the unknown option: delete config[option];
}
});