@syntropysoft/praetorian
Version:
Praetorian CLI – A universal multi-environment configuration validator for DevSecOps teams. Validate, compare, and secure YAML/ENV files with ease.
209 lines • 7.07 kB
JavaScript
;
/**
* Structure Validator - Functional Programming
*
* Single Responsibility: Validate object and array structures only
* Pure functions, no state, no side effects
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.validateRequiredProperties = exports.validateValue = exports.validateArray = exports.validateObject = void 0;
const TypeValidator_1 = require("./TypeValidator");
const FormatValidator_1 = require("./FormatValidator");
const RangeValidator_1 = require("./RangeValidator");
/**
* Pure function to validate object structure
*/
const validateObject = (value, schema, path, errors, warnings, context) => {
// Guard clause: not an object
if (!isObject(value)) {
return;
}
// Guard clause: no properties defined
if (!schema.properties) {
return;
}
// Validate required properties first
const requiredErrors = (0, exports.validateRequiredProperties)(value, schema, path);
errors.push(...requiredErrors);
// Validate known properties
Object.entries(schema.properties).forEach(([key, propSchema]) => {
const propPath = buildPath(path, key);
const propErrors = (0, exports.validateValue)(value[key], propSchema, propPath, context);
errors.push(...propErrors);
});
// Check for additional properties
const additionalErrors = validateAdditionalProperties(value, schema, path);
errors.push(...additionalErrors);
};
exports.validateObject = validateObject;
/**
* Pure function to validate array structure
*/
const validateArray = (value, schema, path, errors, warnings, context) => {
// Guard clause: not an array
if (!Array.isArray(value)) {
return;
}
// Guard clause: no items schema
if (!schema.items) {
return;
}
const arrayErrors = Array.isArray(schema.items)
? validateTuple(value, schema.items, path, context)
: validateArrayItems(value, schema.items, path, context);
errors.push(...arrayErrors);
};
exports.validateArray = validateArray;
/**
* Pure function to validate tuple array
*/
const validateTuple = (value, itemSchemas, path, context) => {
return value.flatMap((item, i) => {
const itemSchema = itemSchemas[i] || itemSchemas[itemSchemas.length - 1];
const itemPath = buildArrayPath(path, i);
return (0, exports.validateValue)(item, itemSchema, itemPath, context);
});
};
/**
* Pure function to validate array items
*/
const validateArrayItems = (value, itemSchema, path, context) => {
return value.flatMap((item, i) => {
const itemPath = buildArrayPath(path, i);
return (0, exports.validateValue)(item, itemSchema, itemPath, context);
});
};
/**
* Pure function to validate additional properties
*/
const validateAdditionalProperties = (value, schema, path) => {
// Guard clause: additional properties allowed
if (schema.additionalProperties !== false) {
return [];
}
const knownProps = new Set(Object.keys(schema.properties || {}));
return Object.keys(value)
.filter(key => !knownProps.has(key))
.map(key => createAdditionalPropertyError(buildPath(path, key), key));
};
/**
* Pure function to validate a value against schema (delegates to specialized validators)
*/
const validateValue = (value, schema, path, context) => {
return [
// Type validation
...(0, TypeValidator_1.validateType)(value, schema, path),
// Format validation
...(0, FormatValidator_1.validateFormat)(value, schema, path),
...(0, FormatValidator_1.validatePattern)(value, schema, path),
// Range validation
...(0, RangeValidator_1.validateStringLength)(value, schema, path),
...(0, RangeValidator_1.validateNumberRange)(value, schema, path),
// Enum validation
...validateEnum(value, schema, path),
// Structure validation
...validateObjectStructure(value, schema, path, context),
...validateArrayStructure(value, schema, path, context)
];
};
exports.validateValue = validateValue;
/**
* Pure function to validate object structure
*/
const validateObjectStructure = (value, schema, path, context) => {
if (schema.type === 'object' && isObject(value)) {
const errors = [];
const warnings = [];
(0, exports.validateObject)(value, schema, path, errors, warnings, context);
return errors;
}
return [];
};
/**
* Pure function to validate array structure
*/
const validateArrayStructure = (value, schema, path, context) => {
if (schema.type === 'array' && Array.isArray(value)) {
const errors = [];
const warnings = [];
(0, exports.validateArray)(value, schema, path, errors, warnings, context);
return errors;
}
return [];
};
/**
* Pure function to validate enum values
*/
const validateEnum = (value, schema, path) => {
// Guard clause: no enum defined
if (!schema.enum) {
return [];
}
return !schema.enum.includes(value)
? [createEnumError(path, value, schema.enum)]
: [];
};
/**
* Pure function to check if value is object
*/
const isObject = (value) => typeof value === 'object' && !Array.isArray(value) && value !== null;
/**
* Pure function to build property path
*/
const buildPath = (basePath, key) => basePath ? `${basePath}.${key}` : key;
/**
* Pure function to build array path
*/
const buildArrayPath = (basePath, index) => `${basePath}[${index}]`;
/**
* Pure function to create additional property error
*/
const createAdditionalPropertyError = (path, key) => ({
path,
message: `Additional property '${key}' is not allowed`,
code: 'ADDITIONAL_PROPERTY_NOT_ALLOWED',
actual: key
});
/**
* Pure function to create enum error
*/
const createEnumError = (path, value, enumValues) => ({
path,
message: `Value must be one of: ${enumValues.join(', ')}`,
code: 'INVALID_ENUM',
actual: value,
expected: enumValues
});
/**
* Pure function to validate required properties
*/
const validateRequiredProperties = (value, schema, path) => {
// Guard clause: no required properties
if (!schema.required || !Array.isArray(schema.required)) {
return [];
}
// Guard clause: not an object
if (!isObject(value)) {
return [];
}
const errors = [];
// Check each required property
schema.required.forEach(propName => {
if (!(propName in value) || value[propName] === undefined || value[propName] === null) {
errors.push(createRequiredPropertyError(buildPath(path, propName), propName));
}
});
return errors;
};
exports.validateRequiredProperties = validateRequiredProperties;
/**
* Pure function to create required property error
*/
const createRequiredPropertyError = (path, propName) => ({
path,
message: `Required property '${propName}' is missing`,
code: 'REQUIRED_PROPERTY_MISSING',
actual: undefined,
expected: propName
});
//# sourceMappingURL=StructureValidator.js.map