@@ -41,22 +41,22 @@ function getRecordId(record: any, idField?: string): string | number | undefined
4141 * Supports conditions like ['field', 'op', value] and logical
4242 * combinations like ['and', ...conditions] or ['or', ...conditions].
4343 */
44- function matchesASTFilter ( record : any , ast : any [ ] ) : boolean {
45- if ( ! ast || ast . length === 0 ) return true ;
44+ function matchesASTFilter ( record : any , filterNode : any [ ] ) : boolean {
45+ if ( ! filterNode || filterNode . length === 0 ) return true ;
4646
47- const head = ast [ 0 ] ;
47+ const head = filterNode [ 0 ] ;
4848
4949 // Logical operators: ['and', ...conditions] or ['or', ...conditions]
5050 if ( head === 'and' ) {
51- return ast . slice ( 1 ) . every ( ( sub : any ) => matchesASTFilter ( record , sub ) ) ;
51+ return filterNode . slice ( 1 ) . every ( ( sub : any ) => matchesASTFilter ( record , sub ) ) ;
5252 }
5353 if ( head === 'or' ) {
54- return ast . slice ( 1 ) . some ( ( sub : any ) => matchesASTFilter ( record , sub ) ) ;
54+ return filterNode . slice ( 1 ) . some ( ( sub : any ) => matchesASTFilter ( record , sub ) ) ;
5555 }
5656
5757 // Condition node: [field, operator, value]
58- if ( ast . length === 3 && typeof head === 'string' ) {
59- const [ field , operator , target ] = ast ;
58+ if ( filterNode . length === 3 && typeof head === 'string' ) {
59+ const [ field , operator , target ] = filterNode ;
6060 const value = record [ field ] ;
6161
6262 switch ( operator ) {
@@ -75,14 +75,20 @@ function matchesASTFilter(record: any, ast: any[]): boolean {
7575 case 'in' :
7676 return Array . isArray ( target ) && target . includes ( value ) ;
7777 case 'not in' :
78- case 'notin' :
78+ case 'notin' : // alias used by convertFiltersToAST
7979 return Array . isArray ( target ) && ! target . includes ( value ) ;
80- case 'contains' :
81- return typeof value === 'string' && value . toLowerCase ( ) . includes ( String ( target ) . toLowerCase ( ) ) ;
82- case 'notcontains' :
83- return typeof value === 'string' && ! value . toLowerCase ( ) . includes ( String ( target ) . toLowerCase ( ) ) ;
84- case 'startswith' :
85- return typeof value === 'string' && value . toLowerCase ( ) . startsWith ( String ( target ) . toLowerCase ( ) ) ;
80+ case 'contains' : {
81+ const lv = typeof value === 'string' ? value . toLowerCase ( ) : '' ;
82+ return typeof value === 'string' && lv . includes ( String ( target ) . toLowerCase ( ) ) ;
83+ }
84+ case 'notcontains' : {
85+ const lv = typeof value === 'string' ? value . toLowerCase ( ) : '' ;
86+ return typeof value === 'string' && ! lv . includes ( String ( target ) . toLowerCase ( ) ) ;
87+ }
88+ case 'startswith' : {
89+ const lv = typeof value === 'string' ? value . toLowerCase ( ) : '' ;
90+ return typeof value === 'string' && lv . startsWith ( String ( target ) . toLowerCase ( ) ) ;
91+ }
8692 case 'between' :
8793 return Array . isArray ( target ) && target . length === 2 && value >= target [ 0 ] && value <= target [ 1 ] ;
8894 default :
0 commit comments