apiful
Version:
Extensible, typed API tooling
88 lines (87 loc) • 2.48 kB
JavaScript
//#region src/utils/validator.ts
const validatorSymbol = Symbol.for("apiful.validator");
var TypeValidationError = class extends Error {
value;
cause;
constructor({ value, cause }) {
super(`Type validation failed with value: ${JSON.stringify(value)}\nError message: ${getErrorMessage(cause)}`);
this.value = value;
this.cause = cause;
}
};
/**
* Create a validator.
*
* @param validate A validation function for the schema.
*/
function validator(validate) {
return {
[validatorSymbol]: true,
validate
};
}
/**
* Validates the types of an unknown object using a schema and
* return a strongly-typed object.
*
* @template T - The type of the object to validate.
* @param {string} options.value - The object to validate.
* @param {Validator<T>} options.schema - The schema to use for validating the JSON.
* @returns {T} - The typed object.
*/
function validateTypes({ value, schema: inputSchema }) {
const result = safeValidateTypes({
value,
schema: inputSchema
});
if (!result.success) throw new TypeValidationError({
value,
cause: result.error
});
return result.value;
}
/**
* Safely validates the types of an unknown object using a schema and
* return a strongly-typed object.
*
* @template T - The type of the object to validate.
* @param {string} options.value - The JSON object to validate.
* @param {Validator<T>} options.schema - The schema to use for validating the JSON.
* @returns An object with either a `success` flag and the parsed and typed data, or a `success` flag and an error object.
*/
function safeValidateTypes({ value, schema }) {
try {
if (schema.validate == null) return {
success: true,
value
};
const result = schema.validate(value);
if (result.success) return result;
return {
success: false,
error: new TypeValidationError({
value,
cause: result.error
})
};
} catch (error) {
return {
success: false,
error: new TypeValidationError({
value,
cause: error
})
};
}
}
function isValidator(value) {
return typeof value === "object" && value !== null && validatorSymbol in value && value[validatorSymbol] === true && "validate" in value;
}
function getErrorMessage(error) {
if (error == null) return "Unknown error";
if (typeof error === "string") return error;
if (error instanceof Error) return error.message;
return JSON.stringify(error);
}
//#endregion
export { TypeValidationError, isValidator, safeValidateTypes, validateTypes, validator, validatorSymbol };