Files
xo-cash-utils/source/parser/ajv/ajv-utils.ts
2026-01-25 12:51:34 +00:00

61 lines
2.2 KiB
TypeScript

/**
* This code is inspired from https://github.com/bitauth/libauth
*/
import { lossyNormalize } from '@bitauth/libauth';
import type { AjvValidator, XOAjvError } from './ajv-types.ts';
import { FailedToParseTemplateError } from '../../errors.ts';
const errorsToDescription = (errors: XOAjvError[]): string => {
// TODO: translate instancePath and make errors more descriptive.
const descriptions = errors.map((error) => `${error.instancePath}: ${error.message}`).join(',');
return descriptions;
};
/**
* Given an untrusted JSON string or object, verify that
* the untrusted value is of the expected shape. Note, this method first
* normalizes all characters in the input using `Normalization Form KC`
* (Compatibility Decomposition, followed by Canonical Composition).
*
* @param {unknown} jsonOrObject - The JSON string or object to parse
* @returns {T} The parsed object
* @throws {FailedToParseTemplateError} If JSON parsing fails
*/
export const parseJson = <T>(jsonOrObject: unknown): T => {
try {
// If the JSON object is a string, use it directly.
const stringified = typeof jsonOrObject === 'string' ? jsonOrObject : JSON.stringify(jsonOrObject);
// Normalize the JSON string using `Normalization Form KC` (Compatibility Decomposition, followed by Canonical Composition).
const normalized = lossyNormalize(stringified);
// Parse the normalized JSON string into the expected type.
const parsed = JSON.parse(normalized);
// Return the parsed object.
return parsed;
} catch (error) {
// Error wrapping. If the JSON parsing fails, throw an error.
throw new FailedToParseTemplateError(error instanceof Error ? error.message : String(error));
}
};
/**
* Validates a parsed object against an AJV schema.
*
* @param parsed - The parsed object to validate
* @param validator - The AJV validator function
* @returns The validated object if valid, or an error message string if invalid
*/
export const validateSchema = <T>(parsed: unknown, validator: AjvValidator<T>): T | string => {
if (validator(parsed)) {
return parsed;
}
// If the object is invalid, return the error message.
return errorsToDescription(validator.errors ?? []);
};