-
Notifications
You must be signed in to change notification settings - Fork 2.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix: Implement precompiled validator support in @rjsf/validator-ajv8 #3652
fix: Implement precompiled validator support in @rjsf/validator-ajv8 #3652
Conversation
4f94b29
to
f80ed1b
Compare
f80ed1b
to
eb7a423
Compare
Fixes rjsf-team#3543 by implementing support for precompiled validators - In `@rjsf/validator-ajv8` added support for precompiled validators as follows: - Added a new `compileSchemaValidators()` API function used to generate the precompiled validators for a schema to an output file - Updated the documentation for the `customizeValidator()` API function - Added a new `AJV8PrecompiledValidator` implementation of the `ValidatorType` interface - Refactored a large piece of the raw validation error processing from the `AJV8Validator` into a new `processRawValidationErrors()` function also used by the `AJV8PrecompiledValidator` - Added a new `usePrecompiledValidator()` API function that is similar to `customizeValidator()` but returning a precompiled validator-based `ValidatorType` interface implementation - Added some new types to the `types.ts` file in support of precompiled validators - Updated the main `index.ts` file to export the new types and API functions - Added 100% unit test coverage of the new feature - This included implementing a node function to precompile the `superSchema.json` file found in the `test/harness` directory - Added `ignorePatterns` to the `.eslintrc` file to ignore the precompiled schema files - Updated the `validation.md` documentation for the new precompiled validator functionality - Added a new `validator-ajv8.md` documentation file to the `api-reference` directory and the `sidebar.js` - Updated the `CHANGELOG.md` file accordingly
… improved the `CHANGELOG.md` comments related to rjsf-team#3546
f1353a8
to
31b69af
Compare
Just leaving a note to cross-reference with #1961 and follow-up later...while this isn't a silver bullet for that issue, I'm curious to see how much better the pre-compiled validator performs when using schemas with high conditional complexity. |
* @returns - The precompiled validator function associated with this schema | ||
*/ | ||
getValidator(schema: S) { | ||
const key = get(schema, ID_KEY, hashForSchema(schema)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We shouldn't need to compute the hash if we have an $id
. This is not a big deal if the hash is not an expensive computation.
- output: string - The name of the file into which the precompiled validator functions will be generated | ||
- [options={}]: CustomValidatorOptionsType - The set of `CustomValidatorOptionsType` information used to alter the AJV validator used for compiling the schema. They are the same options that are passed to the `customizeValidator()` function in order to modify the behavior of the regular AJV-based validator. | ||
|
||
### usePrecompiledValidator<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends FormContextType = any>() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
use...
makes this look like a React hook, so I would suggest a slightly different name, like
### usePrecompiledValidator<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends FormContextType = any>() | |
### createPrecompiledValidator<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends FormContextType = any>() |
packages/validator-ajv8/src/types.ts
Outdated
export interface CompiledValidateFunction<T = any> extends Omit<ValidateFunction<T>, 'schema' | 'schemaEnv'> { | ||
/** This is literally copied from the `ValidateFunction` type definition from which it extends because it seems to get | ||
* lost as part of the Omit<>. | ||
*/ | ||
(this: Ajv | any, data: any, dataCxt?: DataValidationCxt): boolean; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Tbh I don't really know how a function definition is supposed to work with Omit
, but it makes sense to do this, since it also has properties you want to drop.
* @param [localizer] - If provided, is used to localize a list of Ajv `ErrorObject`s | ||
* @returns - The precompiled validator implementation resulting from the set of parameters provided | ||
*/ | ||
export default function usePrecompiledValidator< |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As mentioned before, prefer a different name so this doesn't look like a React hook.
* In order to keep things in sync, it may be necessary to run this after making changes in the schemaParser world in | ||
* `@rjsf/utils` OR if an AJV update is installed. To run this, simply do the following, starting in the root directory | ||
* of the `@rjsf/validator-ajv8` directory: | ||
* | ||
* - cd test/harness | ||
* - node compileTestSchema.js | ||
* | ||
* Then add the two updated `superSchema.js` and `superSchemaOptions.js` files to your PR |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm...we'd have no idea if something breaks unless we're disciplined about following these steps. Is it burdensome to just run this file and recompile the validators before we run the tests?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
And if so, we can .gitignore the compiled files, of course
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmmm, good idea, let me see how that goes
const compileSchemaValidators = require('../../dist').compileSchemaValidators; | ||
const superSchema = require('./superSchema.json'); | ||
|
||
// NOTE these are the same as the CUSTOM_OPTIONS in `testData.ts`, keep them in sync |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why can't we just import this from testData
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The TS file is using imports for types which don't work in a CJS world that this file is running in.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Gotcha, so this is easier than using ts-node or something like that. That's fine.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fantastic set of tests
describe('passing validatorFns and rootSchema to usePrecompiledValidator', () => { | ||
let custom: any; | ||
beforeAll(() => { | ||
(AJV8PrecompiledValidator as unknown as jest.Mock).mockClear(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can probably use jest.mocked()
instead of this sequence of casts - https://jestjs.io/docs/mock-function-api/#jestmockedsource-options
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wow, I just learned something new
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I just learned about it recently 🙂
@@ -32,10 +25,10 @@ describe('AJV8Validator', () => { | |||
builder.resetAllErrors(); | |||
}); | |||
describe('default options', () => { | |||
// Use the TestValidator to access the `withIdRefPrefix` function | |||
let validator: TestValidator; | |||
// Use the AJV8Validator to access the `withIdRefPrefix` function |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does it make sense to remove this comment (and the other 3 times it appears in this file)? Seems like the refactor made this easy to clean up and we're not even accessing withIdRefPrefix
in this file
// Use the AJV8Validator to access the `withIdRefPrefix` function |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks great! Excited to see this released!
Reasons for making this change
Fixes #3543 by implementing support for precompiled validators
@rjsf/validator-ajv8
added support for precompiled validators as follows:compileSchemaValidators()
API function used to generate the precompiled validators for a schema to an output filecustomizeValidator()
API functionAJV8PrecompiledValidator
implementation of theValidatorType
interfaceAJV8Validator
into a newprocessRawValidationErrors()
function also used by theAJV8PrecompiledValidator
usePrecompiledValidator()
API function that is similar tocustomizeValidator()
but returning a precompiled validator-basedValidatorType
interface implementationtypes.ts
file in support of precompiled validatorsindex.ts
file to export the new types and API functionssuperSchema.json
file found in thetest/harness
directoryvalidation.md
documentation for the new precompiled validator functionalityvalidator-ajv8.md
documentation file to theapi-reference
directory and thesidebar.js
CHANGELOG.md
file accordinglyChecklist
npm run test:update
to update snapshots, if needed.