33 * and provides a way to retrieve those changes.
44 */
55
6+ import { deepEquals , isTemporal } from "./utils"
7+
68/**
79 * Simple debug utility that only logs when debug mode is enabled
810 * Set DEBUG to true in localStorage to enable debug logging
@@ -133,6 +135,13 @@ function deepClone<T extends unknown>(
133135 return clone as unknown as T
134136 }
135137
138+ // Handle Temporal objects
139+ if ( isTemporal ( obj ) ) {
140+ // Temporal objects are immutable, so we can return them directly
141+ // This preserves all their internal state correctly
142+ return obj
143+ }
144+
136145 const clone = { } as Record < string | symbol , unknown >
137146 visited . set ( obj as object , clone )
138147
@@ -156,107 +165,6 @@ function deepClone<T extends unknown>(
156165 return clone as T
157166}
158167
159- /**
160- * Deep equality check that handles special types like Date, RegExp, Map, and Set
161- */
162- function deepEqual < T > ( a : T , b : T ) : boolean {
163- // Handle primitive types
164- if ( a === b ) return true
165-
166- // If either is null or not an object, they're not equal
167- if (
168- a === null ||
169- b === null ||
170- typeof a !== `object` ||
171- typeof b !== `object`
172- ) {
173- return false
174- }
175-
176- // Handle Date objects
177- if ( a instanceof Date && b instanceof Date ) {
178- return a . getTime ( ) === b . getTime ( )
179- }
180-
181- // Handle RegExp objects
182- if ( a instanceof RegExp && b instanceof RegExp ) {
183- return a . source === b . source && a . flags === b . flags
184- }
185-
186- // Handle Map objects
187- if ( a instanceof Map && b instanceof Map ) {
188- if ( a . size !== b . size ) return false
189-
190- const entries = Array . from ( a . entries ( ) )
191- for ( const [ key , val ] of entries ) {
192- if ( ! b . has ( key ) || ! deepEqual ( val , b . get ( key ) ) ) {
193- return false
194- }
195- }
196-
197- return true
198- }
199-
200- // Handle Set objects
201- if ( a instanceof Set && b instanceof Set ) {
202- if ( a . size !== b . size ) return false
203-
204- // Convert to arrays for comparison
205- const aValues = Array . from ( a )
206- const bValues = Array . from ( b )
207-
208- // Simple comparison for primitive values
209- if ( aValues . every ( ( val ) => typeof val !== `object` ) ) {
210- return aValues . every ( ( val ) => b . has ( val ) )
211- }
212-
213- // For objects in sets, we need to do a more complex comparison
214- // This is a simplified approach and may not work for all cases
215- return aValues . length === bValues . length
216- }
217-
218- // Handle arrays
219- if ( Array . isArray ( a ) && Array . isArray ( b ) ) {
220- if ( a . length !== b . length ) return false
221-
222- for ( let i = 0 ; i < a . length ; i ++ ) {
223- if ( ! deepEqual ( a [ i ] , b [ i ] ) ) return false
224- }
225-
226- return true
227- }
228-
229- // Handle TypedArrays
230- if (
231- ArrayBuffer . isView ( a ) &&
232- ArrayBuffer . isView ( b ) &&
233- ! ( a instanceof DataView ) &&
234- ! ( b instanceof DataView )
235- ) {
236- const typedA = a as unknown as TypedArray
237- const typedB = b as unknown as TypedArray
238- if ( typedA . length !== typedB . length ) return false
239-
240- for ( let i = 0 ; i < typedA . length ; i ++ ) {
241- if ( typedA [ i ] !== typedB [ i ] ) return false
242- }
243-
244- return true
245- }
246-
247- // Handle plain objects
248- const keysA = Object . keys ( a as object )
249- const keysB = Object . keys ( b as object )
250-
251- if ( keysA . length !== keysB . length ) return false
252-
253- return keysA . every (
254- ( key ) =>
255- Object . prototype . hasOwnProperty . call ( b , key ) &&
256- deepEqual ( ( a as any ) [ key ] , ( b as any ) [ key ] )
257- )
258- }
259-
260168let count = 0
261169function getProxyCount ( ) {
262170 count += 1
@@ -392,7 +300,7 @@ export function createChangeProxy<
392300 )
393301
394302 // If the value is not equal to original, something is still changed
395- if ( ! deepEqual ( currentValue , originalValue ) ) {
303+ if ( ! deepEquals ( currentValue , originalValue ) ) {
396304 debugLog ( `Property ${ String ( prop ) } is different, returning false` )
397305 return false
398306 }
@@ -411,7 +319,7 @@ export function createChangeProxy<
411319 const originalValue = ( state . originalObject as any ) [ sym ]
412320
413321 // If the value is not equal to original, something is still changed
414- if ( ! deepEqual ( currentValue , originalValue ) ) {
322+ if ( ! deepEquals ( currentValue , originalValue ) ) {
415323 debugLog ( `Symbol property is different, returning false` )
416324 return false
417325 }
@@ -741,12 +649,13 @@ export function createChangeProxy<
741649 return value . bind ( ptarget )
742650 }
743651
744- // If the value is an object, create a proxy for it
652+ // If the value is an object (but not Date, RegExp, or Temporal) , create a proxy for it
745653 if (
746654 value &&
747655 typeof value === `object` &&
748656 ! ( ( value as any ) instanceof Date ) &&
749- ! ( ( value as any ) instanceof RegExp )
657+ ! ( ( value as any ) instanceof RegExp ) &&
658+ ! isTemporal ( value )
750659 ) {
751660 // Create a parent reference for the nested object
752661 const nestedParent = {
@@ -779,11 +688,11 @@ export function createChangeProxy<
779688 )
780689
781690 // Only track the change if the value is actually different
782- if ( ! deepEqual ( currentValue , value ) ) {
691+ if ( ! deepEquals ( currentValue , value ) ) {
783692 // Check if the new value is equal to the original value
784693 // Important: Use the originalObject to get the true original value
785694 const originalValue = changeTracker . originalObject [ prop as keyof T ]
786- const isRevertToOriginal = deepEqual ( value , originalValue )
695+ const isRevertToOriginal = deepEquals ( value , originalValue )
787696 debugLog (
788697 `value:` ,
789698 value ,
0 commit comments