-
-
Notifications
You must be signed in to change notification settings - Fork 59
/
conform.ts
99 lines (67 loc) · 2.6 KB
/
conform.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
namespace $ {
const cache = new WeakMap< any , boolean >()
export const $mol_conform_stack = [] as any[]
export function $mol_conform< Target , Source >( target : Target , source : Source ) : Target {
if( Object.is( target , source ) ) return source as any
if( !target || typeof target !== 'object' ) return target
if( !source || typeof source !== 'object' ) return target
if( target instanceof Error ) return target
if( source instanceof Error ) return target
if( target['constructor'] !== source['constructor'] ) return target
if( cache.get( target ) ) return target
cache.set( target , true )
const conform = $mol_conform_handlers.get( target['constructor'] )
if( !conform ) return target
if( $mol_conform_stack.indexOf( target ) !== -1 ) return target
$mol_conform_stack.push( target )
try { return conform( target , source ) }
finally { $mol_conform_stack.pop() }
}
export const $mol_conform_handlers = new WeakMap< Object , ( target : any , source : any )=> any >()
export function $mol_conform_handler< Class >(
cl : { new( ... args : any[] ) : Class } ,
handler : ( target : Class , source : Class )=> Class ,
) {
$mol_conform_handlers.set( cl , handler )
}
export function $mol_conform_array<
Value ,
List extends {
[ index : number ] : Value
length : number
} ,
>( target : List , source : List ) {
if( source.length !== target.length ) return target
for( let i = 0 ; i < target.length ; ++i ) {
if( !Object.is( source[i] , target[i] ) ) return target
}
return source
}
$mol_conform_handler( Array , $mol_conform_array )
$mol_conform_handler( Uint8Array , $mol_conform_array )
$mol_conform_handler( Uint16Array , $mol_conform_array )
$mol_conform_handler( Uint32Array , $mol_conform_array )
$mol_conform_handler( ({})['constructor'] as any , ( target: Object, source )=> {
let count = 0
let equal = true
for( let key in target ) {
const conformed = $mol_conform( target[key] , source[key] )
if( conformed !== target[key] ) {
try { target[key] = conformed } catch( error: any ) {}
if( !Object.is( conformed , target[key] ) ) equal = false
}
if( !Object.is( conformed , source[key] ) ) equal = false
++ count
}
for( let key in source ) if( -- count < 0 ) break
return ( equal && count === 0 ) ? source : target
} )
$mol_conform_handler( Date , ( target , source )=> {
if( target.getTime() === source.getTime() ) return source
return target
} )
$mol_conform_handler( RegExp , ( target , source )=> {
if( target.toString() === source.toString() ) return source
return target
} )
}