From 1b9057f4a6767e9d6f5e3c232a77c40ec21fc1d8 Mon Sep 17 00:00:00 2001 From: solimant Date: Sun, 19 May 2024 02:27:33 -0400 Subject: [PATCH 1/2] Fix IdSchema and PathSchema types --- packages/utils/src/schema/toIdSchema.ts | 6 +- packages/utils/src/schema/toPathSchema.ts | 65 +++++++++---------- packages/utils/src/types.ts | 20 +++--- .../test/utilsTests/getTestValidator.ts | 2 +- .../test/utilsTests/getTestValidator.ts | 2 +- 5 files changed, 50 insertions(+), 45 deletions(-) diff --git a/packages/utils/src/schema/toIdSchema.ts b/packages/utils/src/schema/toIdSchema.ts index 831404fbda..d372aaa59a 100644 --- a/packages/utils/src/schema/toIdSchema.ts +++ b/packages/utils/src/schema/toIdSchema.ts @@ -64,7 +64,11 @@ function toIdSchemaInternal( + (idSchema as { [key in keyof IdSchema]: IdSchema })[name as keyof IdSchema] = toIdSchemaInternal< + T, + S, + F + >( validator, isObject(field) ? field : {}, idPrefix, diff --git a/packages/utils/src/schema/toPathSchema.ts b/packages/utils/src/schema/toPathSchema.ts index ea168361bc..f0f4795428 100644 --- a/packages/utils/src/schema/toPathSchema.ts +++ b/packages/utils/src/schema/toPathSchema.ts @@ -78,52 +78,49 @@ function toPathSchemaInternal { if (schemaItems[i]) { - pathSchema[i] = toPathSchemaInternal( - validator, - schemaItems[i] as S, - `${name}.${i}`, - rootSchema, - element, - _recurseList - ); + (pathSchema as { [key in keyof PathSchema]: PathSchema })[i as keyof PathSchema] = + toPathSchemaInternal( + validator, + schemaItems[i] as S, + `${name}.${i}`, + rootSchema, + element, + _recurseList + ); } else if (schemaAdditionalItems) { - pathSchema[i] = toPathSchemaInternal( - validator, - schemaAdditionalItems as S, - `${name}.${i}`, - rootSchema, - element, - _recurseList - ); + (pathSchema as { [key in keyof PathSchema]: PathSchema })[i as keyof PathSchema] = + toPathSchemaInternal( + validator, + schemaAdditionalItems as S, + `${name}.${i}`, + rootSchema, + element, + _recurseList + ); } else { console.warn(`Unable to generate path schema for "${name}.${i}". No schema defined for it`); } }); } else { formData.forEach((element, i: number) => { - pathSchema[i] = toPathSchemaInternal( - validator, - schemaItems as S, - `${name}.${i}`, - rootSchema, - element, - _recurseList - ); + (pathSchema as { [key in keyof PathSchema]: PathSchema })[i as keyof PathSchema] = + toPathSchemaInternal(validator, schemaItems as S, `${name}.${i}`, rootSchema, element, _recurseList); }); } } else if (PROPERTIES_KEY in schema) { for (const property in schema.properties) { const field = get(schema, [PROPERTIES_KEY, property]); - pathSchema[property] = toPathSchemaInternal( - validator, - field, - `${name}.${property}`, - rootSchema, - // It's possible that formData is not an object -- this can happen if an - // array item has just been added, but not populated with data yet - get(formData, [property]), - _recurseList - ); + (pathSchema as { [key in keyof PathSchema]: PathSchema })[property as keyof PathSchema] = + toPathSchemaInternal( + validator, + field, + `${name}.${property}`, + rootSchema, + // It's possible that formData is not an object -- this can happen if an + // array item has just been added, but not populated with data yet + get(formData, [property]), + _recurseList + ); } } return pathSchema as PathSchema; diff --git a/packages/utils/src/types.ts b/packages/utils/src/types.ts index 4343be2353..2f031afd24 100644 --- a/packages/utils/src/types.ts +++ b/packages/utils/src/types.ts @@ -131,10 +131,12 @@ export type FieldId = { }; /** Type describing a recursive structure of `FieldId`s for an object with a non-empty set of keys */ -export type IdSchema = FieldId & { - /** The set of ids for fields in the recursive object structure */ - [key in keyof T]?: IdSchema; -}; +export type IdSchema = T extends GenericObjectType + ? FieldId & { + /** The set of ids for fields in the recursive object structure */ + [key in keyof T]?: IdSchema; + } + : FieldId; /** Type describing a name used for a field in the `PathSchema` */ export type FieldPath = { @@ -143,10 +145,12 @@ export type FieldPath = { }; /** Type describing a recursive structure of `FieldPath`s for an object with a non-empty set of keys */ -export type PathSchema = FieldPath & { - /** The set of names for fields in the recursive object structure */ - [key in keyof T]?: PathSchema; -}; +export type PathSchema = T extends GenericObjectType + ? FieldPath & { + /** The set of names for fields in the recursive object structure */ + [key in keyof T]?: PathSchema; + } + : FieldPath; /** The type for error produced by RJSF schema validation */ export type RJSFValidationError = { diff --git a/packages/validator-ajv6/test/utilsTests/getTestValidator.ts b/packages/validator-ajv6/test/utilsTests/getTestValidator.ts index 9119b6f9b1..86a1466e15 100644 --- a/packages/validator-ajv6/test/utilsTests/getTestValidator.ts +++ b/packages/validator-ajv6/test/utilsTests/getTestValidator.ts @@ -22,7 +22,7 @@ export default function getTestValidator(options: CustomValidatorOption validateFormData( formData: T, schema: RJSFSchema, - customValidate?: CustomValidator, + customValidate?: CustomValidator, transformErrors?: ErrorTransformer ): ValidationData { return validator.validateFormData(formData, schema, customValidate, transformErrors); diff --git a/packages/validator-ajv8/test/utilsTests/getTestValidator.ts b/packages/validator-ajv8/test/utilsTests/getTestValidator.ts index 59f5e25ac2..5bf8c834e4 100644 --- a/packages/validator-ajv8/test/utilsTests/getTestValidator.ts +++ b/packages/validator-ajv8/test/utilsTests/getTestValidator.ts @@ -22,7 +22,7 @@ export default function getTestValidator(options: CustomValidatorOption validateFormData( formData: T | undefined, schema: RJSFSchema, - customValidate?: CustomValidator, + customValidate?: CustomValidator, transformErrors?: ErrorTransformer ): ValidationData { return validator.validateFormData(formData, schema, customValidate, transformErrors); From e149e3c2618cb6f027662d6e92c9fa7f71af4391 Mon Sep 17 00:00:00 2001 From: solimant Date: Tue, 2 Jul 2024 02:26:57 +0000 Subject: [PATCH 2/2] Simplify type assertions --- CHANGELOG.md | 14 ++++ packages/utils/src/schema/toIdSchema.ts | 12 +-- packages/utils/src/schema/toPathSchema.ts | 73 ++++++++++--------- packages/utils/src/types.ts | 6 +- packages/utils/test/schema/types.ts | 4 +- .../test/utilsTests/getTestValidator.ts | 6 +- .../test/utilsTests/getTestValidator.ts | 6 +- 7 files changed, 69 insertions(+), 52 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ad895e5692..be2989de74 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,20 @@ should change the heading of the (upcoming) version to include a major version b --> +# 5.18.7 + +## @rjsf/utils + +- Fix IdSchema and PathSchema types ([#4196](https://github.com/rjsf-team/react-jsonschema-form/pull/4196)) + +## @rjsf/validator-ajv6 + +- Fix IdSchema and PathSchema types ([#4196](https://github.com/rjsf-team/react-jsonschema-form/pull/4196)) + +## @rjsf/validator-ajv8 + +- Fix IdSchema and PathSchema types ([#4196](https://github.com/rjsf-team/react-jsonschema-form/pull/4196)) + # 5.18.6 ## @rjsf/antd diff --git a/packages/utils/src/schema/toIdSchema.ts b/packages/utils/src/schema/toIdSchema.ts index d372aaa59a..04fb79eaac 100644 --- a/packages/utils/src/schema/toIdSchema.ts +++ b/packages/utils/src/schema/toIdSchema.ts @@ -3,7 +3,7 @@ import isEqual from 'lodash/isEqual'; import { ALL_OF_KEY, DEPENDENCIES_KEY, ID_KEY, ITEMS_KEY, PROPERTIES_KEY, REF_KEY } from '../constants'; import isObject from '../isObject'; -import { FormContextType, IdSchema, RJSFSchema, StrictRJSFSchema, ValidatorType } from '../types'; +import { FormContextType, GenericObjectType, IdSchema, RJSFSchema, StrictRJSFSchema, ValidatorType } from '../types'; import retrieveSchema from './retrieveSchema'; import getSchemaType from '../getSchemaType'; @@ -59,16 +59,12 @@ function toIdSchemaInternal; + const idSchema: IdSchema = { $id } as IdSchema; if (getSchemaType(schema) === 'object' && PROPERTIES_KEY in schema) { for (const name in schema.properties) { const field = get(schema, [PROPERTIES_KEY, name]); const fieldId = idSchema[ID_KEY] + idSeparator + name; - (idSchema as { [key in keyof IdSchema]: IdSchema })[name as keyof IdSchema] = toIdSchemaInternal< - T, - S, - F - >( + (idSchema as IdSchema)[name] = toIdSchemaInternal( validator, isObject(field) ? field : {}, idPrefix, @@ -82,7 +78,7 @@ function toIdSchemaInternal; + return idSchema; } /** Generates an `IdSchema` object for the `schema`, recursively diff --git a/packages/utils/src/schema/toPathSchema.ts b/packages/utils/src/schema/toPathSchema.ts index f0f4795428..e0b2abb368 100644 --- a/packages/utils/src/schema/toPathSchema.ts +++ b/packages/utils/src/schema/toPathSchema.ts @@ -15,7 +15,7 @@ import { RJSF_ADDITIONAL_PROPERTIES_FLAG, } from '../constants'; import getDiscriminatorFieldFromSchema from '../getDiscriminatorFieldFromSchema'; -import { FormContextType, PathSchema, RJSFSchema, StrictRJSFSchema, ValidatorType } from '../types'; +import { FormContextType, GenericObjectType, PathSchema, RJSFSchema, StrictRJSFSchema, ValidatorType } from '../types'; import getClosestMatchingOption from './getClosestMatchingOption'; import retrieveSchema from './retrieveSchema'; @@ -53,9 +53,9 @@ function toPathSchemaInternal = { [NAME_KEY]: name.replace(/^\./, ''), - } as PathSchema; + } as PathSchema; if (ONE_OF_KEY in schema || ANY_OF_KEY in schema) { const xxxOf: S[] = ONE_OF_KEY in schema ? (schema.oneOf as S[]) : (schema.anyOf as S[]); @@ -78,52 +78,55 @@ function toPathSchemaInternal { if (schemaItems[i]) { - (pathSchema as { [key in keyof PathSchema]: PathSchema })[i as keyof PathSchema] = - toPathSchemaInternal( - validator, - schemaItems[i] as S, - `${name}.${i}`, - rootSchema, - element, - _recurseList - ); + (pathSchema as PathSchema)[i] = toPathSchemaInternal( + validator, + schemaItems[i] as S, + `${name}.${i}`, + rootSchema, + element, + _recurseList + ); } else if (schemaAdditionalItems) { - (pathSchema as { [key in keyof PathSchema]: PathSchema })[i as keyof PathSchema] = - toPathSchemaInternal( - validator, - schemaAdditionalItems as S, - `${name}.${i}`, - rootSchema, - element, - _recurseList - ); + (pathSchema as PathSchema)[i] = toPathSchemaInternal( + validator, + schemaAdditionalItems as S, + `${name}.${i}`, + rootSchema, + element, + _recurseList + ); } else { console.warn(`Unable to generate path schema for "${name}.${i}". No schema defined for it`); } }); } else { formData.forEach((element, i: number) => { - (pathSchema as { [key in keyof PathSchema]: PathSchema })[i as keyof PathSchema] = - toPathSchemaInternal(validator, schemaItems as S, `${name}.${i}`, rootSchema, element, _recurseList); + (pathSchema as PathSchema)[i] = toPathSchemaInternal( + validator, + schemaItems as S, + `${name}.${i}`, + rootSchema, + element, + _recurseList + ); }); } } else if (PROPERTIES_KEY in schema) { for (const property in schema.properties) { const field = get(schema, [PROPERTIES_KEY, property]); - (pathSchema as { [key in keyof PathSchema]: PathSchema })[property as keyof PathSchema] = - toPathSchemaInternal( - validator, - field, - `${name}.${property}`, - rootSchema, - // It's possible that formData is not an object -- this can happen if an - // array item has just been added, but not populated with data yet - get(formData, [property]), - _recurseList - ); + (pathSchema as PathSchema)[property] = toPathSchemaInternal( + validator, + field, + `${name}.${property}`, + rootSchema, + // It's possible that formData is not an object -- this can happen if an + // array item has just been added, but not populated with data yet + get(formData, [property]), + _recurseList + ); } } - return pathSchema as PathSchema; + return pathSchema; } /** Generates an `PathSchema` object for the `schema`, recursively diff --git a/packages/utils/src/types.ts b/packages/utils/src/types.ts index 7e7b335249..f3bfe2127c 100644 --- a/packages/utils/src/types.ts +++ b/packages/utils/src/types.ts @@ -145,7 +145,11 @@ export type FieldPath = { }; /** Type describing a recursive structure of `FieldPath`s for an object with a non-empty set of keys */ -export type PathSchema = T extends GenericObjectType +export type PathSchema = T extends Array + ? FieldPath & { + [i: number]: PathSchema; + } + : T extends GenericObjectType ? FieldPath & { /** The set of names for fields in the recursive object structure */ [key in keyof T]?: PathSchema; diff --git a/packages/utils/test/schema/types.ts b/packages/utils/test/schema/types.ts index dacc5264f7..02136856bc 100644 --- a/packages/utils/test/schema/types.ts +++ b/packages/utils/test/schema/types.ts @@ -6,7 +6,7 @@ export interface TestValidatorParams { errorList?: RJSFValidationError[][]; } -export interface TestValidatorType extends ValidatorType { +export interface TestValidatorType extends ValidatorType { // eslint-disable-next-line no-unused-vars - setReturnValues(params?: TestValidatorParams): void; + setReturnValues(params?: TestValidatorParams): void; } diff --git a/packages/validator-ajv6/test/utilsTests/getTestValidator.ts b/packages/validator-ajv6/test/utilsTests/getTestValidator.ts index 86a1466e15..e977a0b45c 100644 --- a/packages/validator-ajv6/test/utilsTests/getTestValidator.ts +++ b/packages/validator-ajv6/test/utilsTests/getTestValidator.ts @@ -16,14 +16,14 @@ import { customizeValidator, CustomValidatorOptionsType } from '../../src'; * * @param options */ -export default function getTestValidator(options: CustomValidatorOptionsType): TestValidatorType { +export default function getTestValidator(options: CustomValidatorOptionsType): TestValidatorType { const validator = customizeValidator(options); return { validateFormData( formData: T, schema: RJSFSchema, - customValidate?: CustomValidator, - transformErrors?: ErrorTransformer + customValidate?: CustomValidator, + transformErrors?: ErrorTransformer ): ValidationData { return validator.validateFormData(formData, schema, customValidate, transformErrors); }, diff --git a/packages/validator-ajv8/test/utilsTests/getTestValidator.ts b/packages/validator-ajv8/test/utilsTests/getTestValidator.ts index 5bf8c834e4..9510443322 100644 --- a/packages/validator-ajv8/test/utilsTests/getTestValidator.ts +++ b/packages/validator-ajv8/test/utilsTests/getTestValidator.ts @@ -16,14 +16,14 @@ import { customizeValidator, CustomValidatorOptionsType } from '../../src'; * * @param options */ -export default function getTestValidator(options: CustomValidatorOptionsType): TestValidatorType { +export default function getTestValidator(options: CustomValidatorOptionsType): TestValidatorType { const validator = customizeValidator(options); return { validateFormData( formData: T | undefined, schema: RJSFSchema, - customValidate?: CustomValidator, - transformErrors?: ErrorTransformer + customValidate?: CustomValidator, + transformErrors?: ErrorTransformer ): ValidationData { return validator.validateFormData(formData, schema, customValidate, transformErrors); },