guardz
Version:
A simple and lightweight TypeScript type guard library for runtime type validation.
80 lines (79 loc) • 4.25 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.validateObject = void 0;
const isNonNullObject_1 = require("../typeguards/isNonNullObject");
const createValidationResult_1 = require("./createValidationResult");
const createValidationError_1 = require("./createValidationError");
const createTreeNode_1 = require("./createTreeNode");
const combineResults_1 = require("./combineResults");
const validateProperty_1 = require("./validateProperty");
/**
* Validate an object with multiple properties using functional approach
* @param value - The value to validate
* @param propsTypesToCheck - Object containing type guards for each property
* @param context - The validation context
* @returns A ValidationResult for the entire object
*/
const validateObject = (value, propsTypesToCheck, context) => {
// Handle non-object values functionally
const handleNonObjectValue = () => {
const error = (0, createValidationError_1.createValidationError)(context.path, 'non-null object', value, `Expected ${context.path} (${JSON.stringify(value)}) to be "non-null object"`);
const treeNode = (0, createTreeNode_1.createTreeNode)(context.path, false, 'non-null object', value);
treeNode.errors = [error];
// For JSON mode, don't include the error in the result.errors array
const errorMode = context.config?.errorMode || 'multi';
return errorMode === 'json'
? (0, createValidationResult_1.createValidationResult)(false, [], treeNode)
: (0, createValidationResult_1.createValidationResult)(false, [error], treeNode);
};
// Handle single error mode functionally
const handleSingleErrorMode = () => {
const keys = Object.keys(propsTypesToCheck);
// Handle empty schema case
if (keys.length === 0) {
return (0, createValidationResult_1.createValidationResult)(true, [], (0, createTreeNode_1.createTreeNode)(context.path, true, 'object', value));
}
const findFirstError = (keys) => {
const [key, ...remainingKeys] = keys;
// Object.keys() only returns string keys, so key is guaranteed to be a string
const keyStr = key;
const typeGuard = propsTypesToCheck[keyStr];
const propertyValue = value[keyStr];
// Use validateProperty to avoid duplicate validation logic
const propertyResult = (0, validateProperty_1.validateProperty)(keyStr, propertyValue, typeGuard, context);
return propertyResult.valid
? (remainingKeys.length === 0
? (0, createValidationResult_1.createValidationResult)(true, [], (0, createTreeNode_1.createTreeNode)(context.path, true, 'object', value))
: findFirstError(remainingKeys))
: propertyResult;
};
return findFirstError(keys);
};
// Handle multi/json error mode functionally
const handleMultiJsonMode = () => {
const results = Object.keys(propsTypesToCheck).map(key => {
const typeGuard = propsTypesToCheck[key];
return (0, validateProperty_1.validateProperty)(key, value[key], typeGuard, context);
});
const combinedResult = (0, combineResults_1.combineResults)(results, context.path);
const rootTree = (0, createTreeNode_1.createTreeNode)(context.path, combinedResult.valid, 'object', value);
rootTree.children = {};
results.forEach(result => {
if (result.tree) {
const key = result.tree.path.split('.').pop() || 'unknown';
rootTree.children[key] = result.tree;
}
});
return (0, createValidationResult_1.createValidationResult)(combinedResult.valid, combinedResult.errors, rootTree);
};
// Main validation logic using functional composition
return !(0, isNonNullObject_1.isNonNullObject)(value, null)
? handleNonObjectValue()
: (() => {
const errorMode = context.config?.errorMode || 'multi';
return errorMode === 'single'
? handleSingleErrorMode()
: handleMultiJsonMode();
})();
};
exports.validateObject = validateObject;