Skip to content

Commit

Permalink
use fast-deep-equal
Browse files Browse the repository at this point in the history
  • Loading branch information
igorbrasileiro committed Sep 5, 2024
1 parent 9018ef1 commit 274a0a5
Show file tree
Hide file tree
Showing 11 changed files with 91 additions and 106 deletions.
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -79,5 +79,6 @@
"packages/validator-ajv6",
"packages/validator-ajv8",
"packages/snapshot-tests"
]
],
"packageManager": "[email protected]+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e"
}
52 changes: 36 additions & 16 deletions packages/core/src/components/Form.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { Component, ElementType, FormEvent, ReactNode, Ref, RefObject, createRef } from 'react';
import { Component, createRef, ElementType, FormEvent, ReactNode, Ref, RefObject } from 'react';
import {
createSchemaUtils,
CustomValidator,
deepEquals,
ErrorSchema,
ErrorTransformer,
Experimental_DefaultFormStateBehavior,
FormContextType,
GenericObjectType,
getTemplate,
Expand All @@ -14,31 +15,31 @@ import {
mergeObjects,
NAME_KEY,
PathSchema,
StrictRJSFSchema,
Registry,
RegistryFieldsType,
RegistryWidgetsType,
RJSF_ADDITIONAL_PROPERTIES_FLAG,
RJSFSchema,
RJSFValidationError,
RJSF_ADDITIONAL_PROPERTIES_FLAG,
SchemaUtilsType,
shouldRender,
StrictRJSFSchema,
SUBMIT_BTN_OPTIONS_KEY,
TemplatesType,
toErrorList,
UiSchema,
UI_GLOBAL_OPTIONS_KEY,
UI_OPTIONS_KEY,
UiSchema,
ValidationData,
validationDataMerge,
ValidatorType,
Experimental_DefaultFormStateBehavior,
} from '@rjsf/utils';
import _forEach from 'lodash/forEach';
import _get from 'lodash/get';
import _isEmpty from 'lodash/isEmpty';
import _pick from 'lodash/pick';
import _toPath from 'lodash/toPath';
import fastDeepEqual from 'fast-deep-equal';

import getDefaultRegistry from '../getDefaultRegistry';

Expand Down Expand Up @@ -282,7 +283,7 @@ export default class Form<
}

this.state = this.getStateFromProps(props, props.formData);
if (this.props.onChange && !deepEquals(this.state.formData, this.props.formData)) {
if (this.props.onChange && !fastDeepEqual(this.state.formData, this.props.formData)) {
this.props.onChange(this.state);
}
this.formElement = createRef();
Expand All @@ -309,10 +310,14 @@ export default class Form<
getSnapshotBeforeUpdate(
prevProps: FormProps<T, S, F>,
prevState: FormState<T, S, F>
): { nextState: FormState<T, S, F>; shouldUpdate: true } | { shouldUpdate: false } {
):
| { nextState: FormState<T, S, F>; shouldUpdate: true }
| {
shouldUpdate: false;
} {
if (!deepEquals(this.props, prevProps)) {
const isSchemaChanged = !deepEquals(prevProps.schema, this.props.schema);
const isFormDataChanged = !deepEquals(prevProps.formData, this.props.formData);
const isSchemaChanged = !fastDeepEqual(prevProps.schema, this.props.schema);
const isFormDataChanged = !fastDeepEqual(prevProps.formData, this.props.formData);
const nextState = this.getStateFromProps(
this.props,
this.props.formData,
Expand Down Expand Up @@ -346,14 +351,18 @@ export default class Form<
componentDidUpdate(
_: FormProps<T, S, F>,
prevState: FormState<T, S, F>,
snapshot: { nextState: FormState<T, S, F>; shouldUpdate: true } | { shouldUpdate: false }
snapshot:
| { nextState: FormState<T, S, F>; shouldUpdate: true }
| {
shouldUpdate: false;
}
) {
if (snapshot.shouldUpdate) {
const { nextState } = snapshot;

if (
!deepEquals(nextState.formData, this.props.formData) &&
!deepEquals(nextState.formData, prevState.formData) &&
!fastDeepEqual(nextState.formData, this.props.formData) &&
!fastDeepEqual(nextState.formData, prevState.formData) &&
this.props.onChange
) {
this.props.onChange(nextState);
Expand Down Expand Up @@ -692,7 +701,6 @@ export default class Form<
* Callback function to handle reset form data.
* - Reset all fields with default values.
* - Reset validations and errors
*
*/
reset = () => {
const { onChange } = this.props;
Expand Down Expand Up @@ -772,7 +780,14 @@ export default class Form<
},
() => {
if (onSubmit) {
onSubmit({ ...this.state, formData: newFormData, status: 'submitted' }, event);
onSubmit(
{
...this.state,
formData: newFormData,
status: 'submitted',
},
event
);
}
}
);
Expand Down Expand Up @@ -956,9 +971,14 @@ export default class Form<

let { [SUBMIT_BTN_OPTIONS_KEY]: submitOptions = {} } = getUiOptions<T, S, F>(uiSchema);
if (disabled) {
submitOptions = { ...submitOptions, props: { ...submitOptions.props, disabled: true } };
submitOptions = {
...submitOptions,
props: { ...submitOptions.props, disabled: true },
};
}
const submitUiSchema = { [UI_OPTIONS_KEY]: { [SUBMIT_BTN_OPTIONS_KEY]: submitOptions } };
const submitUiSchema = {
[UI_OPTIONS_KEY]: { [SUBMIT_BTN_OPTIONS_KEY]: submitOptions },
};

return (
<FormTag
Expand Down
6 changes: 3 additions & 3 deletions packages/core/src/components/fields/MultiSchemaField.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import isEmpty from 'lodash/isEmpty';
import omit from 'lodash/omit';
import {
ANY_OF_KEY,
deepEquals,
ERRORS_KEY,
FieldProps,
FormContextType,
Expand All @@ -18,6 +17,7 @@ import {
TranslatableString,
UiSchema,
} from '@rjsf/utils';
import fastDeepEqual from 'fast-deep-equal';

/** Type used for the state of the `AnyOfField` component */
type AnyOfFieldState<S extends StrictRJSFSchema = RJSFSchema> = {
Expand Down Expand Up @@ -67,15 +67,15 @@ class AnyOfField<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends For
const { formData, options, idSchema } = this.props;
const { selectedOption } = this.state;
let newState = this.state;
if (!deepEquals(prevProps.options, options)) {
if (!fastDeepEqual(prevProps.options, options)) {
const {
registry: { schemaUtils },
} = this.props;
// re-cache the retrieved options in state in case they have $refs to save doing it later
const retrievedOptions = options.map((opt: S) => schemaUtils.retrieveSchema(opt, formData));
newState = { selectedOption, retrievedOptions };
}
if (!deepEquals(formData, prevProps.formData) && idSchema.$id === prevProps.idSchema.$id) {
if (!fastDeepEqual(formData, prevProps.formData) && idSchema.$id === prevProps.idSchema.$id) {
const { retrievedOptions } = newState;
const matchingOption = this.getMatchingOption(selectedOption, formData, retrievedOptions);

Expand Down
6 changes: 3 additions & 3 deletions packages/utils/src/enumOptionsDeselectValue.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import isEqual from 'lodash/isEqual';
import fastDeepEqual from 'fast-deep-equal';

import { EnumOptionsType, RJSFSchema, StrictRJSFSchema } from './types';
import enumOptionsValueForIndex from './enumOptionsValueForIndex';
Expand All @@ -22,7 +22,7 @@ export default function enumOptionsDeselectValue<S extends StrictRJSFSchema = RJ
): EnumOptionsType<S>['value'] | EnumOptionsType<S>['value'][] | undefined {
const value = enumOptionsValueForIndex<S>(valueIndex, allEnumOptions);
if (Array.isArray(selected)) {
return selected.filter((v) => !isEqual(v, value));
return selected.filter((v) => !fastDeepEqual(v, value));
}
return isEqual(value, selected) ? undefined : selected;
return fastDeepEqual(value, selected) ? undefined : selected;
}
6 changes: 3 additions & 3 deletions packages/utils/src/enumOptionsIsSelected.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import isEqual from 'lodash/isEqual';
import fastDeepEqual from 'fast-deep-equal';

import { EnumOptionsType, RJSFSchema, StrictRJSFSchema } from './types';

Expand All @@ -13,7 +13,7 @@ export default function enumOptionsIsSelected<S extends StrictRJSFSchema = RJSFS
selected: EnumOptionsType<S>['value'] | EnumOptionsType<S>['value'][]
) {
if (Array.isArray(selected)) {
return selected.some((sel) => isEqual(sel, value));
return selected.some((sel) => fastDeepEqual(sel, value));
}
return isEqual(selected, value);
return fastDeepEqual(selected, value);
}
6 changes: 3 additions & 3 deletions packages/utils/src/parser/ParserValidator.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import get from 'lodash/get';
import isEqual from 'lodash/isEqual';
import fastDeepEqual from 'fast-deep-equal';

import { ID_KEY } from '../constants';
import hashForSchema from '../hashForSchema';
Expand Down Expand Up @@ -67,7 +67,7 @@ export default class ParserValidator<T = any, S extends StrictRJSFSchema = RJSFS
const existing = this.schemaMap[key];
if (!existing) {
this.schemaMap[key] = identifiedSchema;
} else if (!isEqual(existing, identifiedSchema)) {
} else if (!fastDeepEqual(existing, identifiedSchema)) {
console.error('existing schema:', JSON.stringify(existing, null, 2));
console.error('new schema:', JSON.stringify(identifiedSchema, null, 2));
throw new Error(
Expand All @@ -91,7 +91,7 @@ export default class ParserValidator<T = any, S extends StrictRJSFSchema = RJSFS
* @throws - Error when the given `rootSchema` differs from the root schema provided during construction
*/
isValid(schema: S, _formData: T, rootSchema: S): boolean {
if (!isEqual(rootSchema, this.rootSchema)) {
if (!fastDeepEqual(rootSchema, this.rootSchema)) {
throw new Error('Unexpectedly calling isValid() with a rootSchema that differs from the construction rootSchema');
}
this.addSchema(schema, hashForSchema<S>(schema));
Expand Down
8 changes: 4 additions & 4 deletions packages/utils/src/parser/schemaParser.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import forEach from 'lodash/forEach';
import isEqual from 'lodash/isEqual';
import fastDeepEqual from 'fast-deep-equal';

import { FormContextType, RJSFSchema, StrictRJSFSchema } from '../types';
import { PROPERTIES_KEY, ITEMS_KEY } from '../constants';
import { ITEMS_KEY, PROPERTIES_KEY } from '../constants';
import ParserValidator, { SchemaMap } from './ParserValidator';
import { retrieveSchemaInternal, resolveAnyOrOneOfSchemas } from '../schema/retrieveSchema';
import { resolveAnyOrOneOfSchemas, retrieveSchemaInternal } from '../schema/retrieveSchema';

/** Recursive function used to parse the given `schema` belonging to the `rootSchema`. The `validator` is used to
* capture the sub-schemas that the `isValid()` function is called with. For each schema returned by the
Expand All @@ -24,7 +24,7 @@ function parseSchema<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends
) {
const schemas = retrieveSchemaInternal<T, S, F>(validator, schema, rootSchema, undefined, true);
schemas.forEach((schema) => {
const sameSchemaIndex = recurseList.findIndex((item) => isEqual(item, schema));
const sameSchemaIndex = recurseList.findIndex((item) => fastDeepEqual(item, schema));
if (sameSchemaIndex === -1) {
recurseList.push(schema);
const allOptions = resolveAnyOrOneOfSchemas<T, S, F>(validator, schema, rootSchema, true);
Expand Down
13 changes: 8 additions & 5 deletions packages/utils/src/schema/retrieveSchema.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import get from 'lodash/get';
import isEqual from 'lodash/isEqual';
import fastDeepEqual from 'fast-deep-equal';
import set from 'lodash/set';
import times from 'lodash/times';
import transform from 'lodash/transform';
Expand All @@ -15,10 +15,10 @@ import {
ANY_OF_KEY,
DEPENDENCIES_KEY,
IF_KEY,
ITEMS_KEY,
ONE_OF_KEY,
REF_KEY,
PROPERTIES_KEY,
ITEMS_KEY,
REF_KEY,
} from '../constants';
import findSchemaDefinition, { splitKeyElementFromObject } from '../findSchemaDefinition';
import getDiscriminatorFieldFromSchema from '../getDiscriminatorFieldFromSchema';
Expand Down Expand Up @@ -196,7 +196,10 @@ export function resolveSchema<T = any, S extends StrictRJSFSchema = RJSFSchema,
)
);
const allPermutations = getAllPermutationsOfXxxOf<S>(allOfSchemaElements);
return allPermutations.map((permutation) => ({ ...schema, allOf: permutation }));
return allPermutations.map((permutation) => ({
...schema,
allOf: permutation,
}));
}
// No $ref or dependencies or allOf attribute was found, returning the original schema.
return [schema];
Expand Down Expand Up @@ -293,7 +296,7 @@ export function resolveAllReferences<S extends StrictRJSFSchema = RJSFSchema>(
};
}

return isEqual(schema, resolvedSchema) ? schema : resolvedSchema;
return fastDeepEqual(schema, resolvedSchema) ? schema : resolvedSchema;
}

/** Creates new 'properties' items for each key in the `formData`
Expand Down
6 changes: 3 additions & 3 deletions packages/utils/src/schema/toIdSchema.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import get from 'lodash/get';
import isEqual from 'lodash/isEqual';
import fastDeepEqual from 'fast-deep-equal';

import { ALL_OF_KEY, DEPENDENCIES_KEY, ID_KEY, ITEMS_KEY, PROPERTIES_KEY, REF_KEY } from '../constants';
import isObject from '../isObject';
Expand Down Expand Up @@ -46,7 +46,7 @@ function toIdSchemaInternal<T = any, S extends StrictRJSFSchema = RJSFSchema, F
const { validator, schema, rootSchema, _recurseList, formData, idPrefix, idSeparator, id, idSchema } = stack.pop()!;
if (REF_KEY in schema || DEPENDENCIES_KEY in schema || ALL_OF_KEY in schema) {
const _schema = retrieveSchema<T, S, F>(validator, schema, rootSchema, formData);
const sameSchemaIndex = _recurseList.findIndex((item) => isEqual(item, _schema));
const sameSchemaIndex = _recurseList.findIndex((item) => fastDeepEqual(item, _schema));
if (sameSchemaIndex === -1) {
stack.push({
validator,
Expand Down Expand Up @@ -112,7 +112,7 @@ function toIdSchemaInternal<T = any, S extends StrictRJSFSchema = RJSFSchema, F
// formData,
// );
// const sameSchemaIndex = _recurseList.findIndex((item) =>
// isEqual(item, _schema)
// fastDeepEqual(item, _schema)
// );
// if (sameSchemaIndex === -1) {
// return toIdSchemaInternal<T, S, F>(
Expand Down
Loading

0 comments on commit 274a0a5

Please sign in to comment.