Files
bknd/app/src/ui/components/form/json-schema/JsonSchemaValidator.ts

122 lines
3.8 KiB
TypeScript

import { type OutputUnit, Validator } from "@cfworker/json-schema";
import type {
CustomValidator,
ErrorSchema,
ErrorTransformer,
FormContextType,
RJSFSchema,
RJSFValidationError,
StrictRJSFSchema,
UiSchema,
ValidationData,
ValidatorType
} from "@rjsf/utils";
import { toErrorSchema } from "@rjsf/utils";
import { get } from "lodash-es";
function removeUndefinedKeys(obj: any): any {
if (!obj) return obj;
if (typeof obj === "object") {
Object.keys(obj).forEach((key) => {
if (obj[key] === undefined) {
delete obj[key];
} else if (typeof obj[key] === "object") {
removeUndefinedKeys(obj[key]);
}
});
}
if (Array.isArray(obj)) {
return obj.filter((item) => item !== undefined);
}
return obj;
}
function onlyKeepMostSpecific(errors: OutputUnit[]) {
const mostSpecific = errors.filter((error) => {
return !errors.some((other) => {
return error !== other && other.instanceLocation.startsWith(error.instanceLocation);
});
});
return mostSpecific;
}
const debug = true;
const validate = true;
export class JsonSchemaValidator<
T = any,
S extends StrictRJSFSchema = RJSFSchema,
F extends FormContextType = any
> implements ValidatorType
{
// @ts-ignore
rawValidation<Result extends OutputUnit = OutputUnit>(schema: S, formData?: T) {
if (!validate) return { errors: [], validationError: null };
debug && console.log("JsonSchemaValidator.rawValidation", schema, formData);
const validator = new Validator(schema as any);
const validation = validator.validate(removeUndefinedKeys(formData));
const specificErrors = onlyKeepMostSpecific(validation.errors);
return { errors: specificErrors, validationError: null as any };
}
validateFormData(
formData: T | undefined,
schema: S,
customValidate?: CustomValidator,
transformErrors?: ErrorTransformer,
uiSchema?: UiSchema
): ValidationData<T> {
if (!validate) return { errors: [], errorSchema: {} as any };
debug &&
console.log(
"JsonSchemaValidator.validateFormData",
formData,
schema,
customValidate,
transformErrors,
uiSchema
);
const { errors } = this.rawValidation(schema, formData);
debug && console.log("errors", { errors });
const transformedErrors = errors
//.filter((error) => error.keyword !== "properties")
.map((error) => {
const schemaLocation = error.keywordLocation.replace(/^#\/?/, "").split("/").join(".");
const propertyError = get(schema, schemaLocation);
const errorText = `${error.error.replace(/\.$/, "")}${propertyError ? ` "${propertyError}"` : ""}`;
//console.log(error, schemaLocation, get(schema, schemaLocation));
return {
name: error.keyword,
message: errorText,
property: "." + error.instanceLocation.replace(/^#\/?/, "").split("/").join("."),
schemaPath: error.keywordLocation,
stack: error.error
};
});
debug && console.log("transformed", transformedErrors);
return {
errors: transformedErrors,
errorSchema: toErrorSchema(transformedErrors)
} as any;
}
toErrorList(errorSchema?: ErrorSchema<T>, fieldPath?: string[]): RJSFValidationError[] {
debug && console.log("JsonSchemaValidator.toErrorList", errorSchema, fieldPath);
return [];
}
isValid(schema: S, formData: T | undefined, rootSchema: S): boolean {
if (!validate) return true;
debug && console.log("JsonSchemaValidator.isValid", schema, formData, rootSchema);
return this.rawValidation(schema, formData).errors.length === 0;
}
}