Skip to content

Commit

Permalink
switch lodash.isEqual to @rjsf/utils.deepEquals at utils package
Browse files Browse the repository at this point in the history
  • Loading branch information
igorbrasileiro committed Jan 9, 2025
1 parent 0fb1cc0 commit cc8d4aa
Show file tree
Hide file tree
Showing 9 changed files with 38 additions and 32 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ should change the heading of the (upcoming) version to include a major version b

- Fixed issue with formData not updating when dependencies change, fixing [#4325](https://github.com/rjsf-team/react-jsonschema-form/issues/4325)
- Fixed issue with assigning default values to formData with deeply nested required properties, fixing [#4399](https://github.com/rjsf-team/react-jsonschema-form/issues/4399)
- Switched uses of `lodash.isEqual()` to `@rjsf/utils.deepEquals` at precompiledValidator.

## @rjsf/validator-ajv8

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

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

/** Removes the enum option value at the `valueIndex` from the currently `selected` (list of) value(s). If `selected` is
* a list, then that list is updated to remove the enum option value with the `valueIndex` in `allEnumOptions`. If it is
Expand All @@ -22,7 +23,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) => !deepEquals(v, value));
}
return isEqual(value, selected) ? undefined : selected;
return deepEquals(value, selected) ? undefined : selected;
}
7 changes: 3 additions & 4 deletions packages/utils/src/enumOptionsIsSelected.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import isEqual from 'lodash/isEqual';

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

/** Determines whether the given `value` is (one of) the `selected` value(s).
*
Expand All @@ -13,7 +12,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) => deepEquals(sel, value));
}
return isEqual(selected, value);
return deepEquals(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,4 @@
import get from 'lodash/get';
import isEqual from 'lodash/isEqual';

import { ID_KEY } from '../constants';
import hashForSchema from '../hashForSchema';
Expand All @@ -15,6 +14,7 @@ import {
ValidationData,
ValidatorType,
} from '../types';
import deepEquals from '../deepEquals';

/** The type of the map of schema hash to schema
*/
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 (!deepEquals(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 (!deepEquals(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 { 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';
import deepEquals from '../deepEquals';

/** 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) => deepEquals(item, schema));
if (sameSchemaIndex === -1) {
recurseList.push(schema);
const allOptions = resolveAnyOrOneOfSchemas<T, S, F>(validator, schema, rootSchema, true);
Expand Down
18 changes: 10 additions & 8 deletions packages/utils/src/schema/getDefaultFormState.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
import get from 'lodash/get';
import isEmpty from 'lodash/isEmpty';
import { JSONSchema7Object } from 'json-schema';

import {
ALL_OF_KEY,
ANY_OF_KEY,
CONST_KEY,
DEFAULT_KEY,
DEPENDENCIES_KEY,
PROPERTIES_KEY,
ONE_OF_KEY,
PROPERTIES_KEY,
REF_KEY,
ALL_OF_KEY,
} from '../constants';
import findSchemaDefinition from '../findSchemaDefinition';
import getClosestMatchingOption from './getClosestMatchingOption';
Expand All @@ -33,9 +34,8 @@ import isMultiSelect from './isMultiSelect';
import isSelect from './isSelect';
import retrieveSchema, { resolveDependencies } from './retrieveSchema';
import isConstant from '../isConstant';
import { JSONSchema7Object } from 'json-schema';
import isEqual from 'lodash/isEqual';
import optionsList from '../optionsList';
import deepEquals from '../deepEquals';

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

Expand Down Expand Up @@ -129,8 +129,7 @@ function maybeAddDefaultToObject<T = any>(
if (!isEmpty(computedDefault)) {
obj[key] = computedDefault;
}
}
// Else store computedDefault if it's a non-empty object(e.g. not {}) and satisfies certain conditions
} // Else store computedDefault if it's a non-empty object(e.g. not {}) and satisfies certain conditions
// Condition 1: If computedDefault is not empty or if the key is a required field
// Condition 2: If the parent object is required or emptyObjectFields is not 'populateRequiredDefaults'
else if (
Expand Down Expand Up @@ -271,7 +270,10 @@ export function computeDefaults<T = any, S extends StrictRJSFSchema = RJSFSchema
experimental_dfsb_to_compute?.constAsDefaults === 'skipOneOf'
) {
// If we are in a oneOf of a primitive type, then we want to pass constAsDefaults as 'never' for the recursion
experimental_dfsb_to_compute = { ...experimental_dfsb_to_compute, constAsDefaults: 'never' };
experimental_dfsb_to_compute = {
...experimental_dfsb_to_compute,
constAsDefaults: 'never',
};
}
schemaToCompute = oneOf![
getClosestMatchingOption<T, S, F>(
Expand Down Expand Up @@ -377,7 +379,7 @@ export function ensureFormDataMatchingSchema<
let validFormData: T | T[] | undefined = formData;
if (isSelectField) {
const getOptionsList = optionsList(schema);
const isValid = getOptionsList?.some((option) => isEqual(option.value, formData));
const isValid = getOptionsList?.some((option) => deepEquals(option.value, formData));
validFormData = isValid ? formData : undefined;
}

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,4 @@
import get from 'lodash/get';
import isEqual from 'lodash/isEqual';
import set from 'lodash/set';
import times from 'lodash/times';
import transform from 'lodash/transform';
Expand All @@ -15,10 +14,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 All @@ -34,6 +33,7 @@ import {
ValidatorType,
} from '../types';
import getFirstMatchingOption from './getFirstMatchingOption';
import deepEquals from '../deepEquals';

/** Retrieves an expanded schema that has had all of its conditions, additional properties, references and dependencies
* resolved and merged into the `schema` given a `validator`, `rootSchema` and `rawFormData` that is used to do the
Expand Down Expand Up @@ -256,7 +256,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 @@ -356,7 +359,7 @@ export function resolveAllReferences<S extends StrictRJSFSchema = RJSFSchema>(
};
}

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

/** Creates new 'properties' items for each key in the `formData`
Expand Down
4 changes: 2 additions & 2 deletions packages/utils/src/schema/toIdSchema.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import get from 'lodash/get';
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';
Expand All @@ -14,6 +13,7 @@ import {
} from '../types';
import retrieveSchema from './retrieveSchema';
import getSchemaType from '../getSchemaType';
import deepEquals from '../deepEquals';

/** An internal helper that generates an `IdSchema` object for the `schema`, recursively with protection against
* infinite recursion
Expand Down Expand Up @@ -42,7 +42,7 @@ function toIdSchemaInternal<T = any, S extends StrictRJSFSchema = RJSFSchema, F
): IdSchema<T> {
if (REF_KEY in schema || DEPENDENCIES_KEY in schema || ALL_OF_KEY in schema) {
const _schema = retrieveSchema<T, S, F>(validator, schema, rootSchema, formData, experimental_customMergeAllOf);
const sameSchemaIndex = _recurseList.findIndex((item) => isEqual(item, _schema));
const sameSchemaIndex = _recurseList.findIndex((item) => deepEquals(item, _schema));
if (sameSchemaIndex === -1) {
return toIdSchemaInternal<T, S, F>(
validator,
Expand Down
6 changes: 3 additions & 3 deletions packages/utils/src/schema/toPathSchema.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import get from 'lodash/get';
import isEqual from 'lodash/isEqual';
import set from 'lodash/set';

import {
ADDITIONAL_PROPERTIES_KEY,
ALL_OF_KEY,
ANY_OF_KEY,
ADDITIONAL_PROPERTIES_KEY,
DEPENDENCIES_KEY,
ITEMS_KEY,
NAME_KEY,
Expand All @@ -26,6 +25,7 @@ import {
} from '../types';
import getClosestMatchingOption from './getClosestMatchingOption';
import retrieveSchema from './retrieveSchema';
import deepEquals from '../deepEquals';

/** An internal helper that generates an `PathSchema` object for the `schema`, recursively with protection against
* infinite recursion
Expand All @@ -50,7 +50,7 @@ function toPathSchemaInternal<T = any, S extends StrictRJSFSchema = RJSFSchema,
): PathSchema<T> {
if (REF_KEY in schema || DEPENDENCIES_KEY in schema || ALL_OF_KEY in schema) {
const _schema = retrieveSchema<T, S, F>(validator, schema, rootSchema, formData, experimental_customMergeAllOf);
const sameSchemaIndex = _recurseList.findIndex((item) => isEqual(item, _schema));
const sameSchemaIndex = _recurseList.findIndex((item) => deepEquals(item, _schema));
if (sameSchemaIndex === -1) {
return toPathSchemaInternal<T, S, F>(
validator,
Expand Down

0 comments on commit cc8d4aa

Please sign in to comment.