@@ -119,104 +119,85 @@ function filterFilter() {
119
119
return function ( array , expression , comparator ) {
120
120
if ( ! isArray ( array ) ) return array ;
121
121
122
- var comparatorType = typeof ( comparator ) ,
123
- predicates = [ ] ;
124
-
125
- predicates . check = function ( value , index ) {
126
- for ( var j = 0 ; j < predicates . length ; j ++ ) {
127
- if ( ! predicates [ j ] ( value , index ) ) {
128
- return false ;
129
- }
130
- }
131
- return true ;
132
- } ;
133
-
134
- if ( comparatorType !== 'function' ) {
135
- if ( comparatorType === 'boolean' && comparator ) {
136
- comparator = function ( obj , text ) {
137
- return angular . equals ( obj , text ) ;
138
- } ;
139
- } else {
140
- comparator = function ( obj , text ) {
141
- if ( obj && text && typeof obj === 'object' && typeof text === 'object' ) {
142
- for ( var objKey in obj ) {
143
- if ( objKey . charAt ( 0 ) !== '$' && hasOwnProperty . call ( obj , objKey ) &&
144
- comparator ( obj [ objKey ] , text [ objKey ] ) ) {
145
- return true ;
146
- }
147
- }
148
- return false ;
149
- }
150
- text = ( '' + text ) . toLowerCase ( ) ;
151
- return ( '' + obj ) . toLowerCase ( ) . indexOf ( text ) > - 1 ;
152
- } ;
153
- }
154
- }
122
+ var predicateFn ;
155
123
156
- var search = function ( obj , text ) {
157
- if ( typeof text === 'string' && text . charAt ( 0 ) === '!' ) {
158
- return ! search ( obj , text . substr ( 1 ) ) ;
159
- }
160
- switch ( typeof obj ) {
161
- case 'boolean' :
162
- case 'number' :
163
- case 'string' :
164
- return comparator ( obj , text ) ;
165
- case 'object' :
166
- switch ( typeof text ) {
167
- case 'object' :
168
- return comparator ( obj , text ) ;
169
- default :
170
- for ( var objKey in obj ) {
171
- if ( objKey . charAt ( 0 ) !== '$' && search ( obj [ objKey ] , text ) ) {
172
- return true ;
173
- }
174
- }
175
- break ;
176
- }
177
- return false ;
178
- case 'array' :
179
- for ( var i = 0 ; i < obj . length ; i ++ ) {
180
- if ( search ( obj [ i ] , text ) ) {
181
- return true ;
182
- }
183
- }
184
- return false ;
185
- default :
186
- return false ;
187
- }
188
- } ;
189
124
switch ( typeof expression ) {
125
+ case 'object' :
126
+ // Replace `{$: 'xyz'}` with `'xyz'` and fall through
127
+ var keys = Object . keys ( expression ) ;
128
+ if ( ( keys . length === 1 ) && ( keys [ 0 ] === '$' ) ) expression = expression . $ ;
129
+ // jshint -W086
190
130
case 'boolean' :
191
131
case 'number' :
192
132
case 'string' :
193
- // Set up expression object and fall through
194
- expression = { $ :expression } ;
195
- // jshint -W086
196
- case 'object' :
197
133
// jshint +W086
198
- for ( var key in expression ) {
199
- ( function ( path ) {
200
- if ( typeof expression [ path ] === 'undefined' ) return ;
201
- predicates . push ( function ( value ) {
202
- return search ( path == '$' ? value : ( value && value [ path ] ) , expression [ path ] ) ;
203
- } ) ;
204
- } ) ( key ) ;
205
- }
134
+ predicateFn = createPredicateFn ( expression , comparator ) ;
206
135
break ;
207
136
case 'function' :
208
- predicates . push ( expression ) ;
137
+ predicateFn = expression ;
209
138
break ;
210
139
default :
211
140
return array ;
212
141
}
213
- var filtered = [ ] ;
214
- for ( var j = 0 ; j < array . length ; j ++ ) {
215
- var value = array [ j ] ;
216
- if ( predicates . check ( value , j ) ) {
217
- filtered . push ( value ) ;
218
- }
219
- }
220
- return filtered ;
142
+
143
+ return array . filter ( predicateFn ) ;
221
144
} ;
222
145
}
146
+
147
+ // Helper functions for `filterFilter`
148
+ function createPredicateFn ( expression , comparator ) {
149
+ var predicateFn ;
150
+
151
+ if ( comparator === true ) {
152
+ comparator = equals ;
153
+ } else if ( ! isFunction ( comparator ) ) {
154
+ comparator = function ( actual , expected ) {
155
+ actual = ( '' + actual ) . toLowerCase ( ) ;
156
+ expected = ( '' + expected ) . toLowerCase ( ) ;
157
+ return actual . indexOf ( expected ) !== - 1 ;
158
+ } ;
159
+ }
160
+
161
+ predicateFn = function ( item ) {
162
+ return deepCompare ( item , expression , comparator ) ;
163
+ } ;
164
+
165
+ return predicateFn ;
166
+ }
167
+
168
+ function deepCompare ( actual , expected , comparator ) {
169
+ var actualType = typeof actual ;
170
+ var expectedType = typeof expected ;
171
+
172
+ if ( expectedType === 'function' ) {
173
+ return expected ( actual ) ;
174
+ } else if ( ( expectedType === 'string' ) && ( expected . charAt ( 0 ) === '!' ) ) {
175
+ return ! deepCompare ( actual , expected . substring ( 1 ) , comparator ) ;
176
+ } else if ( actualType === 'array' ) {
177
+ return actual . some ( function ( item ) {
178
+ return deepCompare ( item , expected , comparator ) ;
179
+ } ) ;
180
+ }
181
+
182
+ switch ( actualType ) {
183
+ case 'object' :
184
+ if ( expectedType === 'object' ) {
185
+ return Object . keys ( expected ) . every ( function ( key ) {
186
+ var actualVal = ( key === '$' ) ? actual : actual [ key ] ;
187
+ var expectedVal = expected [ key ] ;
188
+ return deepCompare ( actualVal , expectedVal , comparator ) ;
189
+ } ) ;
190
+ } else {
191
+ return Object . keys ( actual ) . some ( function ( key ) {
192
+ return ( key . charAt ( 0 ) !== '$' ) && deepCompare ( actual [ key ] , expected , comparator ) ;
193
+ } ) ;
194
+ }
195
+ break ;
196
+ default :
197
+ if ( expectedType === 'object' ) {
198
+ return true ;
199
+ }
200
+
201
+ return comparator ( actual , expected ) ;
202
+ }
203
+ }
0 commit comments