1+ const ostr = Object . prototype . toString ;
2+ const tname = v => ostr . call ( v ) . slice ( 8 , - 1 ) ;
3+ const isEmptyObj = v => {
4+ for ( let p in v ) {
5+ return false ;
6+ }
7+ return true ;
8+ }
9+
10+ const TYPE = ( a , b ) => {
11+ let nameA = tname ( a ) , nameB = tname ( b ) ;
12+ return nameA === nameB ? nameA : '*' ;
13+ } ;
14+
15+ const CONTAINS = {
16+ 'Array' : ( a , b , trap ) => {
17+ if ( trap . indexOf ( b ) > - 1 ) {
18+ return true ;
19+ }
20+ trap . push ( b ) ;
21+ if ( b . length <= a . length ) {
22+ return b . every ( ( vb , i ) => contains ( a [ i ] , vb , trap ) )
23+ } else {
24+ return false ;
25+ }
26+ } ,
27+ 'Object' : ( a , b , trap ) => {
28+ if ( trap . indexOf ( b ) > - 1 ) {
29+ return true ;
30+ }
31+ trap . push ( b ) ;
32+ let bKeys = Object . keys ( b ) ;
33+ if ( bKeys . some ( k => ! ( k in a ) ) ) {
34+ return false ;
35+ }
36+ return bKeys . every ( i => contains ( a [ i ] , b [ i ] , trap ) )
37+ }
38+ } ;
39+ const contains = ( a , b , trap = [ ] ) => {
40+ let t = TYPE ( a , b ) ;
41+ if ( t === '*' || ! ( t in CONTAINS ) ) {
42+ return a === b ;
43+ } else {
44+ return CONTAINS [ t ] ( a , b , trap )
45+ }
46+ } ;
47+
48+ const CLONE = {
49+ 'Array' : ( v , trap ) => {
50+ if ( trap . indexOf ( v ) > - 1 ) {
51+ return [ ...v ] ;
52+ } else {
53+ trap . push ( v ) ;
54+ return v . map ( vv => clone ( vv , trap ) ) ;
55+ }
56+ } ,
57+ 'Object' : ( v , trap ) => {
58+ if ( trap . indexOf ( v ) > - 1 ) {
59+ return { ...v } ;
60+ } else {
61+ trap . push ( v ) ;
62+ let o = { } ;
63+ Object . keys ( v ) . forEach ( key => o [ key ] = clone ( v [ key ] , trap ) ) ;
64+ return o ;
65+ }
66+ }
67+ } ;
68+ const clone = ( v , trap = [ ] ) => {
69+ let t = tname ( v ) ;
70+ if ( t in CLONE ) {
71+ return CLONE [ t ] ( v , trap ) ;
72+ }
73+ return v ;
74+ } ;
75+
76+ const DIFF_NONE = Symbol ( '-diff-none-' ) ;
77+ const DIFF = {
78+ 'Array' : ( a , b , trap ) => {
79+ if ( trap . indexOf ( b ) > - 1 ) {
80+ return DIFF_NONE ;
81+ }
82+ trap . push ( b ) ;
83+ let i = 0 , len = Math . max ( a . length , b . length ) , o = [ ] , none = true ;
84+ for ( ; i < len ; i ++ ) {
85+ o . push ( diff ( a [ i ] , b [ i ] , trap ) )
86+ } ;
87+ while ( o [ o . length - 1 ] === DIFF_NONE ) {
88+ o . pop ( ) ;
89+ }
90+ return o . length > 0 ? o : DIFF_NONE ;
91+ } ,
92+ 'Object' : ( a , b , trap ) => {
93+ if ( trap . indexOf ( b ) > - 1 ) {
94+ return DIFF_NONE ;
95+ }
96+ trap . push ( b ) ;
97+ let o = { } , none = true ;
98+ let keys = [ ...Object . keys ( a ) , ...Object . keys ( b ) ] . filter ( ( k , i , kk ) => kk . indexOf ( k ) === i ) ;
99+ keys . forEach ( i => {
100+ if ( ! contains ( a [ i ] , b [ i ] ) ) {
101+ let r = diff ( a [ i ] , b [ i ] , trap ) ;
102+ if ( r !== DIFF_NONE ) {
103+ none = false ;
104+ o [ i ] = r ;
105+ }
106+ }
107+ } ) ;
108+ return none ? DIFF_NONE : o ;
109+ }
110+ } ;
111+ const diff = ( a , b , trap = [ ] ) => {
112+ if ( typeof ( a ) === 'undefined' ) {
113+ if ( typeof ( b ) === 'undefined' ) {
114+ return DIFF_NONE ;
115+ } else {
116+ return clone ( b ) ;
117+ }
118+ } else if ( typeof ( b ) === 'undefined' ) {
119+ return DIFF_NONE ;
120+ }
121+ let t = TYPE ( a , b ) , r ;
122+ if ( t === '*' || ! ( t in DIFF ) ) {
123+ r = a === b ? DIFF_NONE : b ;
124+ } else {
125+ r = DIFF [ t ] ( a , b , trap ) ;
126+ }
127+ return r ;
128+ }
129+
130+ module . exports = {
131+ contains, clone, diff
132+ } ;
0 commit comments