Skip to content

Commit 86570fe

Browse files
switch lodash.isEqual to fast-equals.deepEqual to improve performance
1 parent f5a24b2 commit 86570fe

13 files changed

+62
-34
lines changed

CHANGELOG.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,16 @@ should change the heading of the (upcoming) version to include a major version b
1616
1717
-->
1818

19+
# 5.25.0
20+
21+
## @rjsf/utils
22+
23+
- Switched uses of `lodash.isEqual()` to `fast-equals.deepEqual()` in many utility functions.
24+
25+
## @rjsf/validator-ajv8
26+
27+
- Switched uses of `lodash.isEqual()` to `fast-equals.deepEqual()` at precompiledValidator.
28+
1929
# 5.24.0
2030

2131
## @rjsf/core

package-lock.json

Lines changed: 11 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/utils/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
"react": "^16.14.0 || >=17"
3737
},
3838
"dependencies": {
39+
"fast-equals": "^5.2.1",
3940
"json-schema-merge-allof": "^0.8.1",
4041
"jsonpointer": "^5.0.1",
4142
"lodash": "^4.17.21",

packages/utils/src/enumOptionsDeselectValue.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import isEqual from 'lodash/isEqual';
1+
import { deepEqual } from 'fast-equals';
22

33
import { EnumOptionsType, RJSFSchema, StrictRJSFSchema } from './types';
44
import enumOptionsValueForIndex from './enumOptionsValueForIndex';
@@ -22,7 +22,7 @@ export default function enumOptionsDeselectValue<S extends StrictRJSFSchema = RJ
2222
): EnumOptionsType<S>['value'] | EnumOptionsType<S>['value'][] | undefined {
2323
const value = enumOptionsValueForIndex<S>(valueIndex, allEnumOptions);
2424
if (Array.isArray(selected)) {
25-
return selected.filter((v) => !isEqual(v, value));
25+
return selected.filter((v) => !deepEqual(v, value));
2626
}
27-
return isEqual(value, selected) ? undefined : selected;
27+
return deepEqual(value, selected) ? undefined : selected;
2828
}

packages/utils/src/enumOptionsIsSelected.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import isEqual from 'lodash/isEqual';
1+
import { deepEqual } from 'fast-equals';
22

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

@@ -13,7 +13,7 @@ export default function enumOptionsIsSelected<S extends StrictRJSFSchema = RJSFS
1313
selected: EnumOptionsType<S>['value'] | EnumOptionsType<S>['value'][]
1414
) {
1515
if (Array.isArray(selected)) {
16-
return selected.some((sel) => isEqual(sel, value));
16+
return selected.some((sel) => deepEqual(sel, value));
1717
}
18-
return isEqual(selected, value);
18+
return deepEqual(selected, value);
1919
}

packages/utils/src/parser/ParserValidator.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import get from 'lodash/get';
2-
import isEqual from 'lodash/isEqual';
2+
import { deepEqual } from 'fast-equals';
33

44
import { ID_KEY } from '../constants';
55
import hashForSchema from '../hashForSchema';
@@ -67,7 +67,7 @@ export default class ParserValidator<T = any, S extends StrictRJSFSchema = RJSFS
6767
const existing = this.schemaMap[key];
6868
if (!existing) {
6969
this.schemaMap[key] = identifiedSchema;
70-
} else if (!isEqual(existing, identifiedSchema)) {
70+
} else if (!deepEqual(existing, identifiedSchema)) {
7171
console.error('existing schema:', JSON.stringify(existing, null, 2));
7272
console.error('new schema:', JSON.stringify(identifiedSchema, null, 2));
7373
throw new Error(
@@ -91,7 +91,7 @@ export default class ParserValidator<T = any, S extends StrictRJSFSchema = RJSFS
9191
* @throws - Error when the given `rootSchema` differs from the root schema provided during construction
9292
*/
9393
isValid(schema: S, _formData: T, rootSchema: S): boolean {
94-
if (!isEqual(rootSchema, this.rootSchema)) {
94+
if (!deepEqual(rootSchema, this.rootSchema)) {
9595
throw new Error('Unexpectedly calling isValid() with a rootSchema that differs from the construction rootSchema');
9696
}
9797
this.addSchema(schema, hashForSchema<S>(schema));

packages/utils/src/parser/schemaParser.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
import forEach from 'lodash/forEach';
2-
import isEqual from 'lodash/isEqual';
32

43
import { FormContextType, RJSFSchema, StrictRJSFSchema } from '../types';
5-
import { PROPERTIES_KEY, ITEMS_KEY } from '../constants';
4+
import { ITEMS_KEY, PROPERTIES_KEY } from '../constants';
65
import ParserValidator, { SchemaMap } from './ParserValidator';
7-
import { retrieveSchemaInternal, resolveAnyOrOneOfSchemas } from '../schema/retrieveSchema';
6+
import { resolveAnyOrOneOfSchemas, retrieveSchemaInternal } from '../schema/retrieveSchema';
7+
import { deepEqual } from 'fast-equals';
88

99
/** Recursive function used to parse the given `schema` belonging to the `rootSchema`. The `validator` is used to
1010
* capture the sub-schemas that the `isValid()` function is called with. For each schema returned by the
@@ -24,7 +24,7 @@ function parseSchema<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends
2424
) {
2525
const schemas = retrieveSchemaInternal<T, S, F>(validator, schema, rootSchema, undefined, true);
2626
schemas.forEach((schema) => {
27-
const sameSchemaIndex = recurseList.findIndex((item) => isEqual(item, schema));
27+
const sameSchemaIndex = recurseList.findIndex((item) => deepEqual(item, schema));
2828
if (sameSchemaIndex === -1) {
2929
recurseList.push(schema);
3030
const allOptions = resolveAnyOrOneOfSchemas<T, S, F>(validator, schema, rootSchema, true);

packages/utils/src/schema/getDefaultFormState.ts

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,14 @@ import get from 'lodash/get';
22
import isEmpty from 'lodash/isEmpty';
33

44
import {
5+
ALL_OF_KEY,
56
ANY_OF_KEY,
67
CONST_KEY,
78
DEFAULT_KEY,
89
DEPENDENCIES_KEY,
9-
PROPERTIES_KEY,
1010
ONE_OF_KEY,
11+
PROPERTIES_KEY,
1112
REF_KEY,
12-
ALL_OF_KEY,
1313
} from '../constants';
1414
import findSchemaDefinition from '../findSchemaDefinition';
1515
import getClosestMatchingOption from './getClosestMatchingOption';
@@ -34,8 +34,8 @@ import isSelect from './isSelect';
3434
import retrieveSchema, { resolveDependencies } from './retrieveSchema';
3535
import isConstant from '../isConstant';
3636
import { JSONSchema7Object } from 'json-schema';
37-
import isEqual from 'lodash/isEqual';
3837
import optionsList from '../optionsList';
38+
import { deepEqual } from 'fast-equals';
3939

4040
const PRIMITIVE_TYPES = ['string', 'number', 'integer', 'boolean', 'null'];
4141

@@ -129,8 +129,7 @@ function maybeAddDefaultToObject<T = any>(
129129
if (!isEmpty(computedDefault)) {
130130
obj[key] = computedDefault;
131131
}
132-
}
133-
// Else store computedDefault if it's a non-empty object(e.g. not {}) and satisfies certain conditions
132+
} // Else store computedDefault if it's a non-empty object(e.g. not {}) and satisfies certain conditions
134133
// Condition 1: If computedDefault is not empty or if the key is a required field
135134
// Condition 2: If the parent object is required or emptyObjectFields is not 'populateRequiredDefaults'
136135
else if (
@@ -271,7 +270,10 @@ export function computeDefaults<T = any, S extends StrictRJSFSchema = RJSFSchema
271270
experimental_dfsb_to_compute?.constAsDefaults === 'skipOneOf'
272271
) {
273272
// If we are in a oneOf of a primitive type, then we want to pass constAsDefaults as 'never' for the recursion
274-
experimental_dfsb_to_compute = { ...experimental_dfsb_to_compute, constAsDefaults: 'never' };
273+
experimental_dfsb_to_compute = {
274+
...experimental_dfsb_to_compute,
275+
constAsDefaults: 'never',
276+
};
275277
}
276278
schemaToCompute = oneOf![
277279
getClosestMatchingOption<T, S, F>(
@@ -377,7 +379,7 @@ export function ensureFormDataMatchingSchema<
377379
let validFormData: T | T[] | undefined = formData;
378380
if (isSelectField) {
379381
const getOptionsList = optionsList(schema);
380-
const isValid = getOptionsList?.some((option) => isEqual(option.value, formData));
382+
const isValid = getOptionsList?.some((option) => deepEqual(option.value, formData));
381383
validFormData = isValid ? formData : undefined;
382384
}
383385

packages/utils/src/schema/retrieveSchema.ts

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import get from 'lodash/get';
2-
import isEqual from 'lodash/isEqual';
32
import set from 'lodash/set';
43
import times from 'lodash/times';
54
import transform from 'lodash/transform';
@@ -15,10 +14,10 @@ import {
1514
ANY_OF_KEY,
1615
DEPENDENCIES_KEY,
1716
IF_KEY,
17+
ITEMS_KEY,
1818
ONE_OF_KEY,
19-
REF_KEY,
2019
PROPERTIES_KEY,
21-
ITEMS_KEY,
20+
REF_KEY,
2221
} from '../constants';
2322
import findSchemaDefinition, { splitKeyElementFromObject } from '../findSchemaDefinition';
2423
import getDiscriminatorFieldFromSchema from '../getDiscriminatorFieldFromSchema';
@@ -34,6 +33,7 @@ import {
3433
ValidatorType,
3534
} from '../types';
3635
import getFirstMatchingOption from './getFirstMatchingOption';
36+
import { deepEqual } from 'fast-equals';
3737

3838
/** Retrieves an expanded schema that has had all of its conditions, additional properties, references and dependencies
3939
* resolved and merged into the `schema` given a `validator`, `rootSchema` and `rawFormData` that is used to do the
@@ -256,7 +256,10 @@ export function resolveSchema<T = any, S extends StrictRJSFSchema = RJSFSchema,
256256
)
257257
);
258258
const allPermutations = getAllPermutationsOfXxxOf<S>(allOfSchemaElements);
259-
return allPermutations.map((permutation) => ({ ...schema, allOf: permutation }));
259+
return allPermutations.map((permutation) => ({
260+
...schema,
261+
allOf: permutation,
262+
}));
260263
}
261264
// No $ref or dependencies or allOf attribute was found, returning the original schema.
262265
return [schema];
@@ -356,7 +359,7 @@ export function resolveAllReferences<S extends StrictRJSFSchema = RJSFSchema>(
356359
};
357360
}
358361

359-
return isEqual(schema, resolvedSchema) ? schema : resolvedSchema;
362+
return deepEqual(schema, resolvedSchema) ? schema : resolvedSchema;
360363
}
361364

362365
/** Creates new 'properties' items for each key in the `formData`

packages/utils/src/schema/toIdSchema.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import get from 'lodash/get';
2-
import isEqual from 'lodash/isEqual';
2+
import { deepEqual } from 'fast-equals';
33

44
import { ALL_OF_KEY, DEPENDENCIES_KEY, ID_KEY, ITEMS_KEY, PROPERTIES_KEY, REF_KEY } from '../constants';
55
import isObject from '../isObject';
@@ -42,7 +42,7 @@ function toIdSchemaInternal<T = any, S extends StrictRJSFSchema = RJSFSchema, F
4242
): IdSchema<T> {
4343
if (REF_KEY in schema || DEPENDENCIES_KEY in schema || ALL_OF_KEY in schema) {
4444
const _schema = retrieveSchema<T, S, F>(validator, schema, rootSchema, formData, experimental_customMergeAllOf);
45-
const sameSchemaIndex = _recurseList.findIndex((item) => isEqual(item, _schema));
45+
const sameSchemaIndex = _recurseList.findIndex((item) => deepEqual(item, _schema));
4646
if (sameSchemaIndex === -1) {
4747
return toIdSchemaInternal<T, S, F>(
4848
validator,

0 commit comments

Comments
 (0)