@@ -167,10 +167,12 @@ export class JSONPath {
167167 #CURRENT = 2 ;
168168 #CHILDREN = 3 ;
169169 #DESCENDANTS = 4 ;
170+ #QUANTIFIER = 5 ;
170171 #reUnquotedIdentifier = / ^ [ A - Z a - z _ ] [ \w ] * | ^ \* / ;
171172 #reExpr = / ^ \s * ( [ ! = ^ $ * ] = | [ < > ] = ? ) \s * ( .+ ?) \] / ;
172173 #reIndice = / ^ - ? \d + / ;
173174 #reRval = / ^ = ( [ a - z ] + ) \( ( .+ ) \) $ / ;
175+ #reQuantifier = / ^ \{ ( \d + | \d + , \d + | \d + , | , \d + ) \} ; \$ / ;
174176 #root;
175177 #compiled;
176178 #compile( query , i ) {
@@ -206,9 +208,32 @@ export class JSONPath {
206208 }
207209 continue ;
208210 }
209- if ( c === 0x24 /* $ */ ) {
210- steps . push ( { mv : this . #ROOT } ) ;
211- i += 1 ;
211+ if ( c === 0x3B /* ; */ ) {
212+ if ( query . startsWith ( ';$' , i ) === false ) { return ; }
213+ steps . push (
214+ { mv : this . #QUANTIFIER, min : 1 , max : 1e6 } ,
215+ { mv : this . #ROOT }
216+ ) ;
217+ i += 2 ;
218+ mv = this . #UNDEFINED;
219+ continue ;
220+ }
221+ if ( c === 0x7B /* { */ ) {
222+ const match = this . #reQuantifier. exec ( query . slice ( i ) ) ;
223+ if ( match === null ) { return ; }
224+ const comma = match [ 1 ] . indexOf ( ',' ) ;
225+ let min , max ;
226+ if ( comma === - 1 ) {
227+ min = max = parseInt ( match [ 1 ] ) ;
228+ } else {
229+ min = parseInt ( match [ 1 ] . slice ( 0 , comma ) ) || 0 ;
230+ max = parseInt ( match [ 1 ] . slice ( comma + 1 ) ) || 1e6 ;
231+ }
232+ steps . push (
233+ { mv : this . #QUANTIFIER, min, max } ,
234+ { mv : this . #ROOT }
235+ ) ;
236+ i += match [ 0 ] . length ;
212237 mv = this . #UNDEFINED;
213238 continue ;
214239 }
@@ -261,11 +286,9 @@ export class JSONPath {
261286 #evaluate( steps , pathin ) {
262287 let resultset = [ ] ;
263288 if ( Array . isArray ( steps ) === false ) { return resultset ; }
264- for ( let i = 0 ; i < steps . length ; i ++ ) {
265- const step = steps [ i ] ;
289+ for ( const step of steps ) {
266290 switch ( step . mv ) {
267291 case this . #ROOT:
268- if ( resultset . length === 0 && i !== 0 ) { break ; }
269292 resultset = [ [ '$' ] ] ;
270293 break ;
271294 case this . #CURRENT:
@@ -282,6 +305,12 @@ export class JSONPath {
282305 resultset = this . #getMatches( resultset , step ) ;
283306 break ;
284307 }
308+ case this . #QUANTIFIER: {
309+ const { length } = resultset ;
310+ if ( length < step . min || length > step . max ) { return [ ] ; }
311+ resultset = [ ] ;
312+ break ;
313+ }
285314 default :
286315 break ;
287316 }
0 commit comments