diff --git a/packages/effect/src/Data.ts b/packages/effect/src/Data.ts index 52890b21c9..fb01e8ae43 100644 --- a/packages/effect/src/Data.ts +++ b/packages/effect/src/Data.ts @@ -2,6 +2,7 @@ * @since 2.0.0 */ import type * as Cause from "./Cause.js" +import type { LazyArg } from "./Function.js" import * as core from "./internal/core.js" import * as internal from "./internal/data.js" import { StructuralPrototype } from "./internal/effectable.js" @@ -452,10 +453,17 @@ export const TaggedError = (tag: Tag): new(f: LazyArg) => A = internal.withDeepEquality + /** * Uses a proxy to compare objects by value, supports deep equality * * @since 2.0.0 * @category constructors */ -export const proxy: (value: A, options?: { deep: boolean }) => A = internal.proxy +export const proxy: (value: A) => A = internal.proxy diff --git a/packages/effect/src/internal/data.ts b/packages/effect/src/internal/data.ts index 7d215ae4d3..5d509d2e57 100644 --- a/packages/effect/src/internal/data.ts +++ b/packages/effect/src/internal/data.ts @@ -1,5 +1,7 @@ import * as Equal from "../Equal.js" +import type { LazyArg } from "../Function.js" import { pipe } from "../Function.js" +import { globalValue } from "../GlobalValue.js" import * as Hash from "../Hash.js" import type * as Types from "../Types.js" import { StructuralPrototype } from "./effectable.js" @@ -38,8 +40,21 @@ export const struct = >>(as: As): As => const deepSymbol = Symbol.for("effect/Data/deep") +const regionalConfig = globalValue("effect/Data/regionalConfig", () => ({ deep: false })) + +/** @internal */ +export const withDeepEquality = (f: LazyArg): A => { + try { + regionalConfig.deep = true + return f() + } finally { + regionalConfig.deep = false + } +} + /** @internal */ -export const proxy = (value: A, options?: { deep: boolean }): A => { +export const proxy = (value: A): A => { + const useDeep = regionalConfig.deep if ((typeof value === "function" || typeof value === "object") && value !== null) { let hashCache: any = "INIT" return new Proxy(value, { @@ -51,12 +66,12 @@ export const proxy = (value: A, options?: { deep: boolean }): A => { }, get(target, p) { if (p === deepSymbol) { - return options?.deep + return useDeep } if (p === Hash.symbol) { return () => { if (hashCache === "INIT") { - hashCache = options?.deep === true + hashCache = useDeep ? deepHash(value) : Array.isArray(value) ? Hash.array(value) @@ -66,7 +81,7 @@ export const proxy = (value: A, options?: { deep: boolean }): A => { } } if (p === Equal.symbol) { - if (options?.deep === true) { + if (useDeep) { return deepComp } if (Array.isArray(value)) { diff --git a/packages/effect/test/Data.test.ts b/packages/effect/test/Data.test.ts index 9079f7518f..34b0f0b0c0 100644 --- a/packages/effect/test/Data.test.ts +++ b/packages/effect/test/Data.test.ts @@ -11,23 +11,27 @@ describe("Data", () => { }) it("proxy deep", () => { - const x = Data.proxy({ - a: 0, - b: 1, - c: { a: 0, b: 7 } - }, { deep: true }) - - const y = Data.proxy({ - a: 0, - b: 1, - c: { a: 0, b: 7 } - }, { deep: true }) + const x = Data.withDeepEquality(() => + Data.proxy({ + a: 0, + b: 1, + c: { a: 0, b: 7 } + }) + ) + + const y = Data.withDeepEquality(() => + Data.proxy({ + a: 0, + b: 1, + c: { a: 0, b: 7 } + }) + ) const z = Data.proxy({ a: 0, b: 1, c: { a: 0, b: 7 } - }, { deep: false }) + }) expect(Equal.equals(x, y)).toBe(true) expect(Equal.equals(x, z)).toBe(false)