Skip to content

Commit d68a37f

Browse files
committed
[form] Migrate to custom deep equal functions
1 parent 075b3c1 commit d68a37f

File tree

10 files changed

+96
-30
lines changed

10 files changed

+96
-30
lines changed

.changeset/early-mails-itch.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@sjsf/form": minor
3+
---
4+
5+
Add `isSchemaValueDeepEqual` and `isSchemaDeepEqual` functions
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import { isObject } from "@/lib/object.js";
2+
3+
import type { Schema, SchemaValue } from "./schema.js";
4+
5+
export function isSchemaValueDeepEqual(
6+
a: SchemaValue | undefined,
7+
b: SchemaValue | undefined
8+
): boolean {
9+
if (a === b) {
10+
return true;
11+
}
12+
if (isObject(a) && isObject(b)) {
13+
if (Array.isArray(a)) {
14+
if (!Array.isArray(b)) {
15+
return false;
16+
}
17+
const { length } = a;
18+
if (length !== b.length) {
19+
return false;
20+
}
21+
for (let i = length; i-- !== 0; ) {
22+
if (!isSchemaValueDeepEqual(a[i], b[i])) {
23+
return false;
24+
}
25+
}
26+
return true;
27+
}
28+
if (Array.isArray(b)) {
29+
return false;
30+
}
31+
const aKeys = Object.keys(a);
32+
let key;
33+
for (let i = aKeys.length; i-- !== 0; ) {
34+
key = aKeys[i]!;
35+
if (!isSchemaValueDeepEqual(a[key], b[key])) {
36+
return false;
37+
}
38+
}
39+
return Object.keys(b).length === aKeys.length;
40+
}
41+
return a !== a && b !== b
42+
}
43+
44+
export const isSchemaDeepEqual = isSchemaValueDeepEqual as (
45+
a: Schema | undefined,
46+
b: Schema | undefined
47+
) => boolean;

packages/form/src/core/index.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,5 +22,6 @@ export * from "./merger.js";
2222
export * from "./default-merger.js";
2323
export * from "./schema-traverser.js";
2424
export * from "./schema-value-traverser.js";
25-
export * from './schema-transformer.js';
25+
export * from "./schema-transformer.js";
2626
export * from "./path.js";
27+
export * from "./deep-equal.js";

packages/form/src/core/path-schema.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@
22
// Licensed under the Apache License, Version 2.0.
33
// Modifications made by Roman Krasilnikov.
44

5-
import { deepEqual } from "@/lib/deep-equal.js";
6-
75
import { retrieveSchema2 } from "./resolve.js";
86
import {
97
ALL_OF_KEY,
@@ -22,6 +20,7 @@ import { isSchemaObjectValue } from "./value.js";
2220
import type { Merger2 } from './merger.js';
2321
import { defaultMerger } from './merger.js';
2422
import { getClosestMatchingOption2 } from './matching.js';
23+
import { isSchemaDeepEqual } from './deep-equal.js';
2524

2625
export const SJSF_ADDITIONAL_PROPERTIES_FLAG = "__sjsf_additionalProperties";
2726

@@ -88,7 +87,7 @@ function toPathSchemaInternal(
8887
if (REF_KEY in schema || DEPENDENCIES_KEY in schema || ALL_OF_KEY in schema) {
8988
const _schema = retrieveSchema2(validator, merger, schema, rootSchema, formData);
9089
const sameSchemaIndex = _recurseList.findIndex((item) =>
91-
deepEqual(item, _schema)
90+
isSchemaDeepEqual(item, _schema)
9291
);
9392
if (sameSchemaIndex === -1) {
9493
return toPathSchemaInternal(

packages/form/src/core/resolve.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
// Licensed under the Apache License, Version 2.0.
33
// Modifications made by Roman Krasilnikov.
44

5-
import { deepEqual } from "@/lib/deep-equal.js";
65
import { array } from "@/lib/array.js";
76

87
import {
@@ -30,6 +29,7 @@ import { getDiscriminatorFieldFromSchema } from "./discriminator.js";
3029
import { getFirstMatchingOption } from "./matching.js";
3130
import { isSchemaObjectValue } from "./value.js";
3231
import { defaultMerger, type Merger2 } from "./merger.js";
32+
import { isSchemaDeepEqual } from './deep-equal.js';
3333

3434
/**
3535
* @deprecated use `retrieveSchema2`
@@ -157,7 +157,7 @@ export function resolveReference2(
157157
formData?: SchemaValue
158158
): Schema[] {
159159
const resolvedSchema = resolveAllReferences(schema, rootSchema, stack);
160-
if (!deepEqual(schema, resolvedSchema)) {
160+
if (!isSchemaDeepEqual(schema, resolvedSchema)) {
161161
return retrieveSchemaInternal(
162162
validator,
163163
merger,

packages/form/src/form/fields/multi-field.svelte

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
<script lang="ts">
22
import { proxy } from "@/lib/svelte.svelte";
3-
import { deepEqual } from '@/lib/deep-equal.js'
43
import {
54
getDiscriminatorFieldFromSchema,
5+
isSchemaValueDeepEqual,
66
mergeSchemas,
77
type EnumOption,
88
type SchemaValue,
@@ -53,7 +53,7 @@
5353
retrievedOptions;
5454
return -1;
5555
}
56-
if (currentSelected !== undefined && deepEqual(lastValue, value)) {
56+
if (currentSelected !== undefined && isSchemaValueDeepEqual(lastValue, value)) {
5757
return currentSelected
5858
}
5959
lastValue = $state.snapshot(value)

packages/form/src/form/fields/object/object-field.svelte

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
<script lang="ts">
22
import { untrack } from "svelte";
33
4-
import { deepEqual } from "@/lib/deep-equal.js";
54
import {
65
getDefaultValueForType,
76
getSimpleSchemaType,
87
isAdditionalProperty,
8+
isSchemaDeepEqual,
99
isSchemaExpandable,
1010
isSchemaObjectValue,
1111
orderProperties,
@@ -94,7 +94,7 @@
9494
9595
let lastSchemaProperties: Schema["properties"] = undefined;
9696
const schemaProperties = $derived.by(() => {
97-
if (!deepEqual(lastSchemaProperties, retrievedSchema.properties)) {
97+
if (!isSchemaDeepEqual(lastSchemaProperties, retrievedSchema.properties)) {
9898
lastSchemaProperties = $state.snapshot(retrievedSchema.properties);
9999
}
100100
return lastSchemaProperties;

packages/form/src/form/id-schema.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@
22
// Licensed under the Apache License, Version 2.0.
33
// Modifications made by Roman Krasilnikov.
44

5-
import { deepEqual } from "@/lib/deep-equal.js";
6-
75
import {
86
ALL_OF_KEY,
97
defaultMerger,
@@ -12,6 +10,7 @@ import {
1210
ID_KEY,
1311
isNormalArrayItems,
1412
isSchema,
13+
isSchemaDeepEqual,
1514
isSchemaObjectValue,
1615
ITEMS_KEY,
1716
PROPERTIES_KEY,
@@ -93,7 +92,7 @@ export function toIdSchema2(
9392
formData
9493
);
9594
const sameSchemaIndex = _recurseList.findIndex((item) =>
96-
deepEqual(item, _schema)
95+
isSchemaDeepEqual(item, _schema)
9796
);
9897
if (sameSchemaIndex === -1) {
9998
return toIdSchema2(

packages/form/src/form/options.svelte.ts

Lines changed: 26 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,20 @@
1-
import { deepEqual } from "@/lib/deep-equal.js";
2-
import { isObject } from '@/lib/object.js';
1+
import { isObject } from "@/lib/object.js";
32

4-
import type { EnumOption, SchemaArrayValue, SchemaValue } from '@/core/index.js';
3+
import {
4+
isSchemaValueDeepEqual,
5+
type EnumOption,
6+
type SchemaArrayValue,
7+
type SchemaValue,
8+
} from "@/core/index.js";
59

610
export interface OptionsMapper<V> {
711
fromValue: (value: SchemaValue | undefined) => V;
812
toValue: (value: V) => SchemaValue | undefined;
913
}
1014

11-
export function indexMapper(options: EnumOption<SchemaValue>[]): OptionsMapper<number> {
15+
export function indexMapper(
16+
options: EnumOption<SchemaValue>[]
17+
): OptionsMapper<number> {
1218
const map = new Map(options.map((option, index) => [option.value, index]));
1319
return {
1420
fromValue(value: SchemaValue | undefined) {
@@ -22,15 +28,19 @@ export function indexMapper(options: EnumOption<SchemaValue>[]): OptionsMapper<n
2228
if (!isObject(value)) {
2329
return options.findIndex((option) => option.value === value);
2430
}
25-
return options.findIndex((option) => deepEqual(option.value, value));
31+
return options.findIndex((option) =>
32+
isSchemaValueDeepEqual(option.value, value)
33+
);
2634
},
2735
toValue(index: number) {
2836
return options[index]?.value;
2937
},
3038
};
3139
}
3240

33-
export function stringIndexMapper(options: EnumOption<SchemaValue>[]): OptionsMapper<string> {
41+
export function stringIndexMapper(
42+
options: EnumOption<SchemaValue>[]
43+
): OptionsMapper<string> {
3444
const { fromValue, toValue } = indexMapper(options);
3545
return {
3646
fromValue(value) {
@@ -47,9 +57,9 @@ export function singleOption<V>({
4757
value,
4858
update,
4959
}: {
50-
mapper: () => OptionsMapper<V>,
51-
value: () => SchemaValue | undefined,
52-
update: (value: SchemaValue | undefined) => void,
60+
mapper: () => OptionsMapper<V>;
61+
value: () => SchemaValue | undefined;
62+
update: (value: SchemaValue | undefined) => void;
5363
}) {
5464
const { fromValue, toValue } = $derived(mapper());
5565
return {
@@ -58,18 +68,18 @@ export function singleOption<V>({
5868
},
5969
set value(v) {
6070
update(toValue(v));
61-
}
62-
}
71+
},
72+
};
6373
}
6474

6575
export function multipleOptions<V>({
6676
mapper,
6777
value,
6878
update,
6979
}: {
70-
mapper: () => OptionsMapper<V>,
71-
value: () => SchemaArrayValue | undefined,
72-
update: (value: SchemaArrayValue) => void,
80+
mapper: () => OptionsMapper<V>;
81+
value: () => SchemaArrayValue | undefined;
82+
update: (value: SchemaArrayValue) => void;
7383
}) {
7484
const { fromValue, toValue } = $derived(mapper());
7585
return {
@@ -78,6 +88,6 @@ export function multipleOptions<V>({
7888
},
7989
set value(v) {
8090
update(v.map(toValue));
81-
}
82-
}
91+
},
92+
};
8393
}
Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,6 @@
1-
export { deepEqual } from 'fast-equals'
1+
import { deepEqual } from "fast-equals";
2+
3+
export {
4+
/** @deprecated use `isSchemaValueDeepEqual` or `isSchemaDeepEqual` from `form/core` */
5+
deepEqual,
6+
};

0 commit comments

Comments
 (0)