import { deepEquals, ID_KEY, ROOT_SCHEMA_PREFIX, toErrorList, withIdRefPrefix, hashForSchema, } from '@rjsf/utils';
import createAjvInstance from './createAjvInstance';
import processRawValidationErrors from './processRawValidationErrors';
/** `ValidatorType` implementation that uses the AJV 8 validation mechanism.
 */
export default class AJV8Validator {
    /** Constructs an `AJV8Validator` instance using the `options`
     *
     * @param options - The `CustomValidatorOptionsType` options that are used to create the AJV instance
     * @param [localizer] - If provided, is used to localize a list of Ajv `ErrorObject`s
     */
    constructor(options, localizer) {
        const { additionalMetaSchemas, customFormats, ajvOptionsOverrides, ajvFormatOptions, AjvClass } = options;
        this.ajv = createAjvInstance(additionalMetaSchemas, customFormats, ajvOptionsOverrides, ajvFormatOptions, AjvClass);
        this.localizer = localizer;
    }
    /** Resets the internal AJV validator to clear schemas from it. Can be helpful for resetting the validator for tests.
     */
    reset() {
        this.ajv.removeSchema();
    }
    /** Converts an `errorSchema` into a list of `RJSFValidationErrors`
     *
     * @param errorSchema - The `ErrorSchema` instance to convert
     * @param [fieldPath=[]] - The current field path, defaults to [] if not specified
     * @deprecated - Use the `toErrorList()` function provided by `@rjsf/utils` instead. This function will be removed in
     *        the next major release.
     */
    toErrorList(errorSchema, fieldPath = []) {
        return toErrorList(errorSchema, fieldPath);
    }
    /** Runs the pure validation of the `schema` and `formData` without any of the RJSF functionality. Provided for use
     * by the playground. Returns the `errors` from the validation
     *
     * @param schema - The schema against which to validate the form data   * @param schema
     * @param formData - The form data to validate
     */
    rawValidation(schema, formData) {
        var _a, _b;
        let compilationError = undefined;
        let compiledValidator;
        if (schema[ID_KEY]) {
            compiledValidator = this.ajv.getSchema(schema[ID_KEY]);
        }
        try {
            if (compiledValidator === undefined) {
                compiledValidator = this.ajv.compile(schema);
            }
            compiledValidator(formData);
        }
        catch (err) {
            compilationError = err;
        }
        let errors;
        if (compiledValidator) {
            if (typeof this.localizer === 'function') {
                // Missing properties need to be enclosed with quotes so that
                // `AJV8Validator#transformRJSFValidationErrors` replaces property names
                // with `title` or `ui:title`. See #4348, #4349, and #4387.
                ((_a = compiledValidator.errors) !== null && _a !== void 0 ? _a : []).forEach((error) => {
                    var _a;
                    if ((_a = error.params) === null || _a === void 0 ? void 0 : _a.missingProperty) {
                        error.params.missingProperty = `'${error.params.missingProperty}'`;
                    }
                });
                this.localizer(compiledValidator.errors);
                // Revert to originals
                ((_b = compiledValidator.errors) !== null && _b !== void 0 ? _b : []).forEach((error) => {
                    var _a;
                    if ((_a = error.params) === null || _a === void 0 ? void 0 : _a.missingProperty) {
                        error.params.missingProperty = error.params.missingProperty.slice(1, -1);
                    }
                });
            }
            errors = compiledValidator.errors || undefined;
            // Clear errors to prevent persistent errors, see #1104
            compiledValidator.errors = null;
        }
        return {
            errors: errors,
            validationError: compilationError,
        };
    }
    /** This function processes the `formData` with an optional user contributed `customValidate` function, which receives
     * the form data and a `errorHandler` function that will be used to add custom validation errors for each field. Also
     * supports a `transformErrors` function that will take the raw AJV validation errors, prior to custom validation and
     * transform them in what ever way it chooses.
     *
     * @param formData - The form data to validate
     * @param schema - The schema against which to validate the form data
     * @param [customValidate] - An optional function that is used to perform custom validation
     * @param [transformErrors] - An optional function that is used to transform errors after AJV validation
     * @param [uiSchema] - An optional uiSchema that is passed to `transformErrors` and `customValidate`
     */
    validateFormData(formData, schema, customValidate, transformErrors, uiSchema) {
        const rawErrors = this.rawValidation(schema, formData);
        return processRawValidationErrors(this, rawErrors, formData, schema, customValidate, transformErrors, uiSchema);
    }
    /**
     * This function checks if a schema needs to be added and if the root schemas don't match it removes the old root schema from the ajv instance and adds the new one.
     * @param rootSchema - The root schema used to provide $ref resolutions
     */
    handleSchemaUpdate(rootSchema) {
        var _a, _b;
        const rootSchemaId = (_a = rootSchema[ID_KEY]) !== null && _a !== void 0 ? _a : ROOT_SCHEMA_PREFIX;
        // add the rootSchema ROOT_SCHEMA_PREFIX as id.
        // if schema validator instance doesn't exist, add it.
        // else if the root schemas don't match, we should remove and add the root schema so we don't have to remove and recompile the schema every run.
        if (this.ajv.getSchema(rootSchemaId) === undefined) {
            this.ajv.addSchema(rootSchema, rootSchemaId);
        }
        else if (!deepEquals(rootSchema, (_b = this.ajv.getSchema(rootSchemaId)) === null || _b === void 0 ? void 0 : _b.schema)) {
            this.ajv.removeSchema(rootSchemaId);
            this.ajv.addSchema(rootSchema, rootSchemaId);
        }
    }
    /** Validates data against a schema, returning true if the data is valid, or
     * false otherwise. If the schema is invalid, then this function will return
     * false.
     *
     * @param schema - The schema against which to validate the form data
     * @param formData - The form data to validate
     * @param rootSchema - The root schema used to provide $ref resolutions
     */
    isValid(schema, formData, rootSchema) {
        var _a;
        try {
            this.handleSchemaUpdate(rootSchema);
            // then rewrite the schema ref's to point to the rootSchema
            // this accounts for the case where schema have references to models
            // that lives in the rootSchema but not in the schema in question.
            const schemaWithIdRefPrefix = withIdRefPrefix(schema);
            const schemaId = (_a = schemaWithIdRefPrefix[ID_KEY]) !== null && _a !== void 0 ? _a : hashForSchema(schemaWithIdRefPrefix);
            let compiledValidator;
            compiledValidator = this.ajv.getSchema(schemaId);
            if (compiledValidator === undefined) {
                // Add schema by an explicit ID so it can be fetched later
                // Fall back to using compile if necessary
                // https://ajv.js.org/guide/managing-schemas.html#pre-adding-all-schemas-vs-adding-on-demand
                compiledValidator =
                    this.ajv.addSchema(schemaWithIdRefPrefix, schemaId).getSchema(schemaId) ||
                        this.ajv.compile(schemaWithIdRefPrefix);
            }
            const result = compiledValidator(formData);
            return result;
        }
        catch (e) {
            console.warn('Error encountered compiling schema:', e);
            return false;
        }
    }
}
//# sourceMappingURL=validator.js.map