diff --git a/CHANGELOG.md b/CHANGELOG.md index 9715ccf54d..ef4f2cb437 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,14 @@ should change the heading of the (upcoming) version to include a major version b - Fix case where NumberField would not properly reset the field when using programmatic form reset (#4202)[https://github.com/rjsf-team/react-jsonschema-form/issues/4202] +## @rjsf/validator-ajv6 + +- Improved performance issues with large schema dependencies and oneOf conditions [#4203](https://github.com/rjsf-team/react-jsonschema-form/issues/4203). + +## @rjsf/validator-ajv8 + +- Improved performance issues with large schema dependencies and oneOf conditions [#4203](https://github.com/rjsf-team/react-jsonschema-form/issues/4203). + # 5.18.4 ## Dev / docs / playground diff --git a/packages/validator-ajv6/src/validator.ts b/packages/validator-ajv6/src/validator.ts index 02249bd8d2..79c221a246 100644 --- a/packages/validator-ajv6/src/validator.ts +++ b/packages/validator-ajv6/src/validator.ts @@ -2,6 +2,7 @@ import { Ajv, ErrorObject } from 'ajv'; import { createErrorHandler, CustomValidator, + deepEquals, ErrorSchema, ErrorTransformer, FormContextType, @@ -158,6 +159,23 @@ export default class AJV6Validator({ errors, errorSchema }, userErrorSchema); } + /** + * 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: RJSFSchema): void { + const rootSchemaId = ROOT_SCHEMA_PREFIX; + // add the rootSchema ROOT_SCHEMA_PREFIX as id. + // if schema validator instance doesn't exist, add it. + // else 'handleRootSchemaChange' should be called if the root schema changes so we don't have to remove and recompile the schema every run. + if (this.ajv.getSchema(ROOT_SCHEMA_PREFIX) === undefined) { + this.ajv.addSchema(rootSchema, ROOT_SCHEMA_PREFIX); + } else if (!deepEquals(rootSchema, this.ajv.getSchema(ROOT_SCHEMA_PREFIX)?.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. @@ -168,17 +186,14 @@ export default class AJV6Validator(schema) as S; const schemaId = schemaWithIdRefPrefix[ID_KEY] ?? hashForSchema(schemaWithIdRefPrefix); let compiledValidator: ValidateFunction | undefined; @@ -155,10 +168,6 @@ export default class AJV8Validator { validator.isValid(schema, formData, rootSchema); // Root schema is added twice - expect(addSchemaSpy).toHaveBeenCalledTimes(3); + expect(addSchemaSpy).toHaveBeenCalledTimes(2); expect(addSchemaSpy).toHaveBeenNthCalledWith(1, expect.objectContaining(rootSchema), rootSchema.$id); expect(addSchemaSpy).toHaveBeenNthCalledWith(2, expect.objectContaining(schema), schema.$id); - expect(addSchemaSpy).toHaveBeenLastCalledWith(expect.objectContaining(rootSchema), rootSchema.$id); }); it('should fallback to using compile', () => { const schema: RJSFSchema = { @@ -594,10 +593,9 @@ describe('AJV8Validator', () => { validator.isValid(schema, formData, rootSchema); // Root schema is added twice - expect(addSchemaSpy).toHaveBeenCalledTimes(3); + expect(addSchemaSpy).toHaveBeenCalledTimes(2); expect(addSchemaSpy).toHaveBeenNthCalledWith(1, expect.objectContaining(rootSchema), rootSchema.$id); expect(addSchemaSpy).toHaveBeenNthCalledWith(2, expect.objectContaining(schema), schema.$id); - expect(addSchemaSpy).toHaveBeenLastCalledWith(expect.objectContaining(rootSchema), rootSchema.$id); }); }); describe('validator.toErrorList()', () => { @@ -1050,10 +1048,9 @@ describe('AJV8Validator', () => { validator.isValid(schema, formData, rootSchema); // Root schema is added twice - expect(addSchemaSpy).toHaveBeenCalledTimes(3); + expect(addSchemaSpy).toHaveBeenCalledTimes(2); expect(addSchemaSpy).toHaveBeenNthCalledWith(1, expect.objectContaining(rootSchema), rootSchema.$id); expect(addSchemaSpy).toHaveBeenNthCalledWith(2, expect.objectContaining(schema), schema.$id); - expect(addSchemaSpy).toHaveBeenLastCalledWith(expect.objectContaining(rootSchema), rootSchema.$id); }); }); describe('validator.toErrorList()', () => {