File tree Expand file tree Collapse file tree 4 files changed +91
-6
lines changed
Expand file tree Collapse file tree 4 files changed +91
-6
lines changed Original file line number Diff line number Diff line change @@ -58,9 +58,56 @@ export class Match implements FilterFunction {
5858
5959 protected fullMatch ( pattern : string ) : string {
6060 const parts : string [ ] = [ ] ;
61- if ( ! pattern . startsWith ( "^" ) ) parts . push ( "^" ) ;
62- parts . push ( pattern ) ;
63- if ( ! pattern . endsWith ( "$" ) ) parts . push ( "$" ) ;
61+ let nonCaptureGroup = false ;
62+
63+ if ( ! pattern . startsWith ( "^" ) && ! pattern . startsWith ( "^(" ) ) {
64+ nonCaptureGroup = true ;
65+ parts . push ( "^(?:" ) ;
66+ }
67+ parts . push ( this . mapRegexp ( pattern ) ) ;
68+
69+ if ( nonCaptureGroup && ! pattern . endsWith ( "$" ) && ! pattern . endsWith ( ")$" ) ) {
70+ parts . push ( ")$" ) ;
71+ }
72+
73+ return parts . join ( "" ) ;
74+ }
75+
76+ // See https://datatracker.ietf.org/doc/html/rfc9485#name-ecmascript-regexps
77+ protected mapRegexp ( pattern : string ) : string {
78+ let escaped = false ;
79+ let charClass = false ;
80+ const parts : string [ ] = [ ] ;
81+ for ( const ch of pattern ) {
82+ switch ( ch ) {
83+ case "." :
84+ if ( ! escaped && ! charClass ) {
85+ parts . push ( "(?:(?![\r\n])\\P{Cs}|\\p{Cs}\\p{Cs})" ) ;
86+ } else {
87+ parts . push ( ch ) ;
88+ escaped = false ;
89+ }
90+ break ;
91+ case "\\" :
92+ escaped = true ;
93+ parts . push ( ch ) ;
94+ break ;
95+ case "[" :
96+ charClass = true ;
97+ escaped = false ;
98+ parts . push ( ch ) ;
99+ break ;
100+ case "]" :
101+ charClass = false ;
102+ escaped = false ;
103+ parts . push ( ch ) ;
104+ break ;
105+ default :
106+ escaped = false ;
107+ parts . push ( ch ) ;
108+ break ;
109+ }
110+ }
64111 return parts . join ( "" ) ;
65112 }
66113}
Original file line number Diff line number Diff line change @@ -48,12 +48,50 @@ export class Search implements FilterFunction {
4848 }
4949
5050 try {
51- const re = new RegExp ( pattern , "u" ) ;
51+ const re = new RegExp ( this . mapRegexp ( pattern ) , "u" ) ;
5252 if ( this . cacheSize > 0 ) this . #cache. set ( pattern , re ) ;
5353 return ! ! s . match ( re ) ;
5454 } catch ( error ) {
5555 if ( this . throwErrors ) throw error ;
5656 return false ;
5757 }
5858 }
59+
60+ // See https://datatracker.ietf.org/doc/html/rfc9485#name-ecmascript-regexps
61+ protected mapRegexp ( pattern : string ) : string {
62+ let escaped = false ;
63+ let charClass = false ;
64+ const parts : string [ ] = [ ] ;
65+ for ( const ch of pattern ) {
66+ switch ( ch ) {
67+ case "." :
68+ if ( ! escaped && ! charClass ) {
69+ parts . push ( "(?:(?![\r\n])\\P{Cs}|\\p{Cs}\\p{Cs})" ) ;
70+ } else {
71+ parts . push ( ch ) ;
72+ escaped = false ;
73+ }
74+ break ;
75+ case "\\" :
76+ escaped = true ;
77+ parts . push ( ch ) ;
78+ break ;
79+ case "[" :
80+ charClass = true ;
81+ escaped = false ;
82+ parts . push ( ch ) ;
83+ break ;
84+ case "]" :
85+ charClass = false ;
86+ escaped = false ;
87+ parts . push ( ch ) ;
88+ break ;
89+ default :
90+ escaped = false ;
91+ parts . push ( ch ) ;
92+ break ;
93+ }
94+ }
95+ return parts . join ( "" ) ;
96+ }
5997}
Original file line number Diff line number Diff line change @@ -367,6 +367,7 @@ function lexInsideBracketedSelection(l: Lexer): StateFn | null {
367367 }
368368
369369 if ( ! l . environment . strict && l . acceptMatchRun ( l . environment . keysPattern ) ) {
370+ // FIXME: fall back to legacy behavior if keysPattern is not the default
370371 switch ( l . peek ( ) ) {
371372 case "'" :
372373 l . ignore ( ) ; // ~
@@ -377,7 +378,6 @@ function lexInsideBracketedSelection(l: Lexer): StateFn | null {
377378 l . next ( ) ;
378379 return lexDoubleQuoteKeyString ( l ) ;
379380 case "?" :
380- l . ignore ( ) ; // ~
381381 l . next ( ) ;
382382 l . emit ( TokenKind . KEYS_FILTER ) ;
383383 l . filterLevel += 1 ;
You can’t perform that action at this time.
0 commit comments