1
1
import { LiquidTagToken , HTMLToken , QuotedToken , OutputToken , TagToken , OperatorToken , RangeToken , PropertyAccessToken , NumberToken , IdentifierToken } from '../tokens'
2
2
import { Tokenizer } from './tokenizer'
3
+ import { defaultOperators } from '../render/operator'
4
+ import { createTrie } from '../util/operator-trie'
3
5
4
6
describe ( 'Tokenizer' , function ( ) {
5
7
it ( 'should read quoted' , ( ) => {
@@ -15,12 +17,31 @@ describe('Tokenizer', function () {
15
17
// eslint-disable-next-line deprecation/deprecation
16
18
expect ( new Tokenizer ( 'foo bar' ) . readWord ( ) ) . toHaveProperty ( 'content' , 'foo' )
17
19
} )
18
- it ( 'should read number value ' , ( ) => {
19
- const token : NumberToken = new Tokenizer ( '2.33.2 ' ) . readValueOrThrow ( ) as any
20
+ it ( 'should read integer number ' , ( ) => {
21
+ const token : NumberToken = new Tokenizer ( '123 ' ) . readValueOrThrow ( ) as any
20
22
expect ( token ) . toBeInstanceOf ( NumberToken )
21
- expect ( token . whole . getText ( ) ) . toBe ( '2' )
22
- expect ( token . decimal ! . getText ( ) ) . toBe ( '33' )
23
- expect ( token . getText ( ) ) . toBe ( '2.33' )
23
+ expect ( token . getText ( ) ) . toBe ( '123' )
24
+ expect ( token . content ) . toBe ( 123 )
25
+ } )
26
+ it ( 'should read negative number' , ( ) => {
27
+ const token : NumberToken = new Tokenizer ( '-123' ) . readValueOrThrow ( ) as any
28
+ expect ( token ) . toBeInstanceOf ( NumberToken )
29
+ expect ( token . getText ( ) ) . toBe ( '-123' )
30
+ expect ( token . content ) . toBe ( - 123 )
31
+ } )
32
+ it ( 'should read float number' , ( ) => {
33
+ const token : NumberToken = new Tokenizer ( '1.23' ) . readValueOrThrow ( ) as any
34
+ expect ( token ) . toBeInstanceOf ( NumberToken )
35
+ expect ( token . getText ( ) ) . toBe ( '1.23' )
36
+ expect ( token . content ) . toBe ( 1.23 )
37
+ } )
38
+ it ( 'should treat 1.2.3 as property read' , ( ) => {
39
+ const token : PropertyAccessToken = new Tokenizer ( '1.2.3' ) . readValueOrThrow ( ) as any
40
+ expect ( token ) . toBeInstanceOf ( PropertyAccessToken )
41
+ expect ( token . props ) . toHaveLength ( 3 )
42
+ expect ( token . props [ 0 ] . getText ( ) ) . toBe ( '1' )
43
+ expect ( token . props [ 1 ] . getText ( ) ) . toBe ( '2' )
44
+ expect ( token . props [ 2 ] . getText ( ) ) . toBe ( '3' )
24
45
} )
25
46
it ( 'should read quoted value' , ( ) => {
26
47
const value = new Tokenizer ( '"foo"a' ) . readValue ( )
@@ -33,11 +54,7 @@ describe('Tokenizer', function () {
33
54
it ( 'should read quoted property access value' , ( ) => {
34
55
const value = new Tokenizer ( '["a prop"]' ) . readValue ( )
35
56
expect ( value ) . toBeInstanceOf ( PropertyAccessToken )
36
- expect ( ( value as PropertyAccessToken ) . variable . getText ( ) ) . toBe ( '"a prop"' )
37
- } )
38
- it ( 'should throw for broken quoted property access' , ( ) => {
39
- const tokenizer = new Tokenizer ( '[5]' )
40
- expect ( ( ) => tokenizer . readValueOrThrow ( ) ) . toThrow ( )
57
+ expect ( ( value as QuotedToken ) . getText ( ) ) . toBe ( '["a prop"]' )
41
58
} )
42
59
it ( 'should throw for incomplete quoted property access' , ( ) => {
43
60
const tokenizer = new Tokenizer ( '["a prop"' )
@@ -277,10 +294,10 @@ describe('Tokenizer', function () {
277
294
278
295
const pa : PropertyAccessToken = token ! . args [ 0 ] as any
279
296
expect ( token ! . args [ 0 ] ) . toBeInstanceOf ( PropertyAccessToken )
280
- expect ( ( pa . variable as any ) . content ) . toBe ( 'arr' )
281
- expect ( pa . props ) . toHaveLength ( 1 )
282
- expect ( pa . props [ 0 ] ) . toBeInstanceOf ( NumberToken )
283
- expect ( pa . props [ 0 ] . getText ( ) ) . toBe ( '0' )
297
+ expect ( pa . props ) . toHaveLength ( 2 )
298
+ expect ( ( pa . props [ 0 ] as any ) . content ) . toBe ( 'arr' )
299
+ expect ( pa . props [ 1 ] ) . toBeInstanceOf ( NumberToken )
300
+ expect ( pa . props [ 1 ] . getText ( ) ) . toBe ( '0' )
284
301
} )
285
302
it ( 'should read a filter with obj.foo argument' , function ( ) {
286
303
const tokenizer = new Tokenizer ( '| plus: obj.foo' )
@@ -290,10 +307,10 @@ describe('Tokenizer', function () {
290
307
291
308
const pa : PropertyAccessToken = token ! . args [ 0 ] as any
292
309
expect ( token ! . args [ 0 ] ) . toBeInstanceOf ( PropertyAccessToken )
293
- expect ( ( pa . variable as any ) . content ) . toBe ( 'obj' )
294
- expect ( pa . props ) . toHaveLength ( 1 )
295
- expect ( pa . props [ 0 ] ) . toBeInstanceOf ( IdentifierToken )
296
- expect ( pa . props [ 0 ] . getText ( ) ) . toBe ( 'foo' )
310
+ expect ( pa . props ) . toHaveLength ( 2 )
311
+ expect ( ( pa . props [ 0 ] as any ) . content ) . toBe ( 'obj' )
312
+ expect ( pa . props [ 1 ] ) . toBeInstanceOf ( IdentifierToken )
313
+ expect ( pa . props [ 1 ] . getText ( ) ) . toBe ( 'foo' )
297
314
} )
298
315
it ( 'should read a filter with obj["foo"] argument' , function ( ) {
299
316
const tokenizer = new Tokenizer ( '| plus: obj["good luck"]' )
@@ -304,8 +321,8 @@ describe('Tokenizer', function () {
304
321
const pa : PropertyAccessToken = token ! . args [ 0 ] as any
305
322
expect ( token ! . args [ 0 ] ) . toBeInstanceOf ( PropertyAccessToken )
306
323
expect ( pa . getText ( ) ) . toBe ( 'obj["good luck"]' )
307
- expect ( ( pa . variable as any ) . content ) . toBe ( 'obj' )
308
- expect ( pa . props [ 0 ] . getText ( ) ) . toBe ( '"good luck"' )
324
+ expect ( ( pa . props [ 0 ] as any ) . content ) . toBe ( 'obj' )
325
+ expect ( pa . props [ 1 ] . getText ( ) ) . toBe ( '"good luck"' )
309
326
} )
310
327
} )
311
328
describe ( '#readFilters()' , ( ) => {
@@ -341,7 +358,7 @@ describe('Tokenizer', function () {
341
358
expect ( tokens [ 2 ] . args ) . toHaveLength ( 1 )
342
359
expect ( tokens [ 2 ] . args [ 0 ] ) . toBeInstanceOf ( PropertyAccessToken )
343
360
expect ( ( tokens [ 2 ] . args [ 0 ] as any ) . getText ( ) ) . toBe ( 'foo[a.b["c d"]]' )
344
- expect ( ( tokens [ 2 ] . args [ 0 ] as any ) . props [ 0 ] . getText ( ) ) . toBe ( 'a.b["c d"]' )
361
+ expect ( ( tokens [ 2 ] . args [ 0 ] as any ) . props [ 1 ] . getText ( ) ) . toBe ( 'a.b["c d"]' )
345
362
} )
346
363
} )
347
364
describe ( '#readExpression()' , ( ) => {
@@ -358,10 +375,10 @@ describe('Tokenizer', function () {
358
375
expect ( exp ) . toHaveLength ( 1 )
359
376
const pa = exp [ 0 ] as PropertyAccessToken
360
377
expect ( pa ) . toBeInstanceOf ( PropertyAccessToken )
361
- expect ( ( pa . variable as any ) . content ) . toEqual ( 'a' )
362
- expect ( pa . props ) . toHaveLength ( 2 )
378
+ expect ( pa . props ) . toHaveLength ( 3 )
379
+ expect ( ( pa . props [ 0 ] as any ) . content ) . toEqual ( 'a' )
363
380
364
- const [ p1 , p2 ] = pa . props
381
+ const [ , p1 , p2 ] = pa . props
365
382
expect ( p1 ) . toBeInstanceOf ( IdentifierToken )
366
383
expect ( p1 . getText ( ) ) . toBe ( '' )
367
384
expect ( p2 ) . toBeInstanceOf ( PropertyAccessToken )
@@ -373,8 +390,8 @@ describe('Tokenizer', function () {
373
390
expect ( exp ) . toHaveLength ( 1 )
374
391
const pa = exp [ 0 ] as PropertyAccessToken
375
392
expect ( pa ) . toBeInstanceOf ( PropertyAccessToken )
376
- expect ( ( pa . variable as any ) . content ) . toEqual ( 'a' )
377
- expect ( pa . props ) . toHaveLength ( 0 )
393
+ expect ( pa . props ) . toHaveLength ( 1 )
394
+ expect ( ( pa . props [ 0 ] as any ) . content ) . toEqual ( 'a' )
378
395
} )
379
396
it ( 'should read expression `a ==`' , ( ) => {
380
397
const exp = [ ...new Tokenizer ( 'a ==' ) . readExpressionTokens ( ) ]
@@ -481,6 +498,30 @@ describe('Tokenizer', function () {
481
498
expect ( rhs . getText ( ) ) . toEqual ( '"\\""' )
482
499
} )
483
500
} )
501
+ describe ( '#matchTrie()' , function ( ) {
502
+ const opTrie = createTrie ( defaultOperators )
503
+ it ( 'should match contains' , ( ) => {
504
+ expect ( new Tokenizer ( 'contains' ) . matchTrie ( opTrie ) ) . toBe ( 8 )
505
+ } )
506
+ it ( 'should match comparision' , ( ) => {
507
+ expect ( new Tokenizer ( '>' ) . matchTrie ( opTrie ) ) . toBe ( 1 )
508
+ expect ( new Tokenizer ( '>=' ) . matchTrie ( opTrie ) ) . toBe ( 2 )
509
+ expect ( new Tokenizer ( '<' ) . matchTrie ( opTrie ) ) . toBe ( 1 )
510
+ expect ( new Tokenizer ( '<=' ) . matchTrie ( opTrie ) ) . toBe ( 2 )
511
+ } )
512
+ it ( 'should match binary logic' , ( ) => {
513
+ expect ( new Tokenizer ( 'and' ) . matchTrie ( opTrie ) ) . toBe ( 3 )
514
+ expect ( new Tokenizer ( 'or' ) . matchTrie ( opTrie ) ) . toBe ( 2 )
515
+ } )
516
+ it ( 'should not match if word not terminate' , ( ) => {
517
+ expect ( new Tokenizer ( 'true1' ) . matchTrie ( opTrie ) ) . toBe ( - 1 )
518
+ expect ( new Tokenizer ( 'containsa' ) . matchTrie ( opTrie ) ) . toBe ( - 1 )
519
+ } )
520
+ it ( 'should match if word boundary found' , ( ) => {
521
+ expect ( new Tokenizer ( '>=1' ) . matchTrie ( opTrie ) ) . toBe ( 2 )
522
+ expect ( new Tokenizer ( 'contains b' ) . matchTrie ( opTrie ) ) . toBe ( 8 )
523
+ } )
524
+ } )
484
525
describe ( '#readLiquidTagTokens' , ( ) => {
485
526
it ( 'should read newline terminated tokens' , ( ) => {
486
527
const tokenizer = new Tokenizer ( 'echo \'hello\'' )
0 commit comments