fortify-schema
Version:
TypeScript interface-like schema validation system that's easier to use than Zod
129 lines (125 loc) • 4.04 kB
JavaScript
'use strict';
var BaseSchema = require('./BaseSchema.js');
/**
* Object schema with property validation
*/
class ObjectSchema extends BaseSchema.BaseSchema {
constructor(shape) {
super();
this.shape = shape;
this._strict = false;
this._allowUnknown = true;
}
/**
* Enable strict mode (no extra properties allowed)
*/
strict() {
const cloned = this.clone();
cloned._strict = true;
cloned._allowUnknown = false;
return cloned;
}
/**
* Allow unknown properties
*/
allowUnknown(allow = true) {
const cloned = this.clone();
cloned._allowUnknown = allow;
return cloned;
}
/**
* Validate object value
*/
validate(value) {
// Handle common validation (undefined/null)
const commonResult = this.handleCommonValidation(value);
if (commonResult) {
return commonResult;
}
const result = {
success: true,
errors: [],
warnings: [],
data: undefined,
};
// Type check
if (typeof value !== "object" || Array.isArray(value)) {
result.success = false;
result.errors.push("Expected object");
return result;
}
const validatedObject = {};
const inputKeys = Object.keys(value);
const shapeKeys = Object.keys(this.shape);
// Validate each property in shape
for (const [key, schema] of Object.entries(this.shape)) {
const propResult = schema.validate(value[key]);
if (!propResult.success) {
result.success = false;
result.errors.push(`Property '${key}': ${propResult.errors.join(", ")}`);
}
else if (propResult.data !== undefined) {
validatedObject[key] = propResult.data;
}
// Collect warnings from properties
if (propResult.warnings.length > 0) {
result.warnings.push(...propResult.warnings.map((w) => `Property '${key}': ${w}`));
}
}
// Handle extra properties
const extraKeys = inputKeys.filter((key) => !shapeKeys.includes(key));
if (extraKeys.length > 0) {
if (this._strict) {
result.success = false;
result.errors.push(`Unexpected properties: ${extraKeys.join(", ")}`);
}
else if (this._allowUnknown) {
// Include unknown properties in result
for (const key of extraKeys) {
validatedObject[key] = value[key];
}
if (extraKeys.length > 0) {
result.warnings.push(`Unknown properties included: ${extraKeys.join(", ")}`);
}
}
else {
result.warnings.push(`Unknown properties ignored: ${extraKeys.join(", ")}`);
}
}
if (result.success) {
result.data = validatedObject;
}
return result;
}
/**
* Clone the object schema with shape
*/
clone() {
const cloned = new ObjectSchema(this.shape);
cloned._strict = this._strict;
cloned._allowUnknown = this._allowUnknown;
cloned._optional = this._optional;
cloned._nullable = this._nullable;
cloned._default = this._default;
return cloned;
}
/**
* Get schema configuration
*/
getConfig() {
const properties = {};
for (const [key, schema] of Object.entries(this.shape)) {
properties[key] = schema.getConfig();
}
return {
strict: this._strict,
allowUnknown: this._allowUnknown,
optional: this._optional,
nullable: this._nullable,
default: this._default,
properties,
};
}
}
exports.ObjectSchema = ObjectSchema;
//# sourceMappingURL=ObjectSchema.js.map