@@ -5,6 +5,7 @@ function run(route, url, loose) {
5
5
let i = 0 , out = { } , result = fn ( route , ! ! loose ) ;
6
6
let matches = result . pattern . exec ( url ) ;
7
7
if ( matches === null ) return false ;
8
+ if ( matches . groups ) return matches . groups ;
8
9
while ( i < result . keys . length ) {
9
10
out [ result . keys [ i ] ] = matches [ ++ i ] || null ;
10
11
}
@@ -568,3 +569,229 @@ test('(extra) exec :: loose', t => {
568
569
569
570
t . end ( ) ;
570
571
} ) ;
572
+
573
+ // ---
574
+
575
+ test ( '(RegExp) static' , t => {
576
+ let rgx = / ^ \/ ? b o o k s / ;
577
+ let { keys, pattern } = fn ( rgx ) ;
578
+ t . same ( keys , false , '~> keys = false' ) ;
579
+ t . same ( rgx , pattern , '~> pattern = input' ) ;
580
+ t . true ( pattern . test ( '/books' ) , '~> matches route' ) ;
581
+ t . true ( pattern . test ( '/books/' ) , '~> matches trailing slash' ) ;
582
+ t . true ( pattern . test ( '/books/' ) , '~> matches without leading slash' ) ;
583
+ t . end ( ) ;
584
+ } ) ;
585
+
586
+ test ( '(RegExp) param' , t => {
587
+ let rgx = / ^ \/ (?< year > [ 0 - 9 ] { 4 } ) / i;
588
+ let { keys, pattern } = fn ( rgx ) ;
589
+ t . same ( keys , false , '~> keys = false' ) ;
590
+ t . same ( rgx , pattern , '~> pattern = input' ) ;
591
+
592
+ // RegExp testing (not regexparam related)
593
+ t . false ( pattern . test ( '/123' ) , '~> does not match 3-digit string' ) ;
594
+ t . false ( pattern . test ( '/asdf' ) , '~> does not match 4 alpha characters' ) ;
595
+ t . true ( pattern . test ( '/2019' ) , '~> matches definition' ) ;
596
+ t . true ( pattern . test ( '/2019/' ) , '~> matches definition w/ trailing slash' ) ;
597
+ t . false ( pattern . test ( '2019' ) , '~> does not match without lead slash' ) ;
598
+ t . true ( pattern . test ( '/2019/narnia/hello' ) , '~> allows extra bits' ) ;
599
+
600
+ // exec results, array access
601
+ let [ url , value ] = pattern . exec ( '/2019/books' ) ;
602
+ t . is ( url , '/2019' , '~> executing pattern on correct trimming' ) ;
603
+ t . is ( value , '2019' , '~> executing pattern gives correct value' ) ;
604
+
605
+ // exec results, named object
606
+ t . toExec ( rgx , '/2019/books' , { year : '2019' } ) ;
607
+ t . toExec ( rgx , '/2019/books/narnia' , { year : '2019' } ) ;
608
+
609
+ t . end ( ) ;
610
+ } ) ;
611
+
612
+ test ( '(RegExp) param :: w/ static' , t => {
613
+ let rgx = / ^ \/ b o o k s \/ (?< title > [ a - z ] + ) / i;
614
+ let { keys, pattern } = fn ( rgx ) ;
615
+ t . same ( keys , false , '~> keys = false' ) ;
616
+ t . same ( rgx , pattern , '~> pattern = input' ) ;
617
+
618
+ // RegExp testing (not regexparam related)
619
+ t . false ( pattern . test ( '/books' ) , '~> does not match naked base' ) ;
620
+ t . false ( pattern . test ( '/books/' ) , '~> does not match naked base w/ trailing slash' ) ;
621
+ t . true ( pattern . test ( '/books/narnia' ) , '~> matches definition' ) ;
622
+ t . true ( pattern . test ( '/books/narnia/' ) , '~> matches definition w/ trailing slash' ) ;
623
+ t . true ( pattern . test ( '/books/narnia/hello' ) , '~> allows extra bits' ) ;
624
+ t . false ( pattern . test ( 'books/narnia' ) , '~> does not match path without lead slash' ) ;
625
+
626
+ // exec results, array access
627
+ let [ url , value ] = pattern . exec ( '/books/narnia' ) ;
628
+ t . is ( url , '/books/narnia' , '~> executing pattern on correct trimming' ) ;
629
+ t . is ( value , 'narnia' , '~> executing pattern gives correct value' ) ;
630
+
631
+ // exec results, named object
632
+ t . toExec ( rgx , '/books/narnia' , { title : 'narnia' } ) ;
633
+ t . toExec ( rgx , '/books/narnia/hello' , { title : 'narnia' } ) ;
634
+
635
+ t . end ( ) ;
636
+ } ) ;
637
+
638
+ test ( '(RegExp) param :: multiple' , t => {
639
+ let rgx = / ^ \/ (?< year > [ 0 - 9 ] { 4 } ) - (?< month > [ 0 - 9 ] { 2 } ) \/ (?< day > [ 0 - 9 ] { 2 } ) / i;
640
+ let { keys, pattern } = fn ( rgx ) ;
641
+ t . same ( keys , false , '~> keys = false' ) ;
642
+ t . same ( rgx , pattern , '~> pattern = input' ) ;
643
+
644
+ // RegExp testing (not regexparam related)
645
+ t . false ( pattern . test ( '/123-1' ) ) ;
646
+ t . false ( pattern . test ( '/123-10' ) ) ;
647
+ t . false ( pattern . test ( '/1234-10' ) ) ;
648
+ t . false ( pattern . test ( '/1234-10/1' ) ) ;
649
+ t . false ( pattern . test ( '/1234-10/as' ) ) ;
650
+ t . true ( pattern . test ( '/1234-10/01/' ) ) ;
651
+ t . true ( pattern . test ( '/2019-10/30' ) ) ;
652
+
653
+ // exec results, array access
654
+ let [ url , year , month , day ] = pattern . exec ( '/2019-05/30/' ) ;
655
+ t . is ( url , '/2019-05/30' , '~> executing pattern on correct trimming' ) ;
656
+ t . is ( year , '2019' , '~> executing pattern gives correct "year" value' ) ;
657
+ t . is ( month , '05' , '~> executing pattern gives correct "month" value' ) ;
658
+ t . is ( day , '30' , '~> executing pattern gives correct "day" value' ) ;
659
+
660
+ // exec results, named object
661
+ t . toExec ( rgx , '/2019-10/02' , { year :'2019' , month :'10' , day :'02' } ) ;
662
+ t . toExec ( rgx , '/2019-10/02/narnia' , { year :'2019' , month :'10' , day :'02' } ) ;
663
+
664
+ t . end ( ) ;
665
+ } ) ;
666
+
667
+ test ( '(RegExp) param :: suffix' , t => {
668
+ let rgx = / ^ \/ m o v i e s [ / ] (?< title > \w + ) \. m p 4 / i;
669
+ let { keys, pattern } = fn ( rgx ) ;
670
+ t . same ( keys , false , '~> keys = false' ) ;
671
+ t . same ( rgx , pattern , '~> pattern = input' ) ;
672
+
673
+ // RegExp testing (not regexparam related)
674
+ t . false ( pattern . test ( '/movies' ) ) ;
675
+ t . false ( pattern . test ( '/movies/' ) ) ;
676
+ t . false ( pattern . test ( '/movies/foo' ) ) ;
677
+ t . false ( pattern . test ( '/movies/foo.mp3' ) ) ;
678
+ t . true ( pattern . test ( '/movies/foo.mp4' ) ) ;
679
+ t . true ( pattern . test ( '/movies/foo.mp4/' ) ) ;
680
+
681
+ // exec results, array access
682
+ let [ url , title ] = pattern . exec ( '/movies/narnia.mp4' ) ;
683
+ t . is ( url , '/movies/narnia.mp4' , '~> executing pattern on correct trimming' ) ;
684
+ t . is ( title , 'narnia' , '~> executing pattern gives correct "title" value' ) ;
685
+
686
+ // exec results, named object
687
+ t . toExec ( rgx , '/movies/narnia.mp4' , { title : 'narnia' } ) ;
688
+ t . toExec ( rgx , '/movies/narnia.mp4/' , { title : 'narnia' } ) ;
689
+
690
+ t . end ( ) ;
691
+ } ) ;
692
+
693
+ test ( '(RegExp) param :: suffices' , t => {
694
+ let rgx = / ^ \/ m o v i e s [ / ] (?< title > \w + ) \. ( m p 4 | m o v ) / i;
695
+ let { keys, pattern } = fn ( rgx ) ;
696
+ t . same ( keys , false , '~> keys = false' ) ;
697
+ t . same ( rgx , pattern , '~> pattern = input' ) ;
698
+
699
+ // RegExp testing (not regexparam related)
700
+ t . false ( pattern . test ( '/movies' ) ) ;
701
+ t . false ( pattern . test ( '/movies/' ) ) ;
702
+ t . false ( pattern . test ( '/movies/foo' ) ) ;
703
+ t . false ( pattern . test ( '/movies/foo.mp3' ) ) ;
704
+ t . true ( pattern . test ( '/movies/foo.mp4' ) ) ;
705
+ t . true ( pattern . test ( '/movies/foo.mp4/' ) ) ;
706
+ t . true ( pattern . test ( '/movies/foo.mov/' ) ) ;
707
+
708
+ // exec results, array access
709
+ let [ url , title ] = pattern . exec ( '/movies/narnia.mov' ) ;
710
+ t . is ( url , '/movies/narnia.mov' , '~> executing pattern on correct trimming' ) ;
711
+ t . is ( title , 'narnia' , '~> executing pattern gives correct "title" value' ) ;
712
+
713
+ // exec results, named object
714
+ t . toExec ( rgx , '/movies/narnia.mov' , { title : 'narnia' } ) ;
715
+ t . toExec ( rgx , '/movies/narnia.mov/' , { title : 'narnia' } ) ;
716
+
717
+ t . end ( ) ;
718
+ } ) ;
719
+
720
+ test ( '(RegExp) param :: optional' , t => {
721
+ let rgx = / ^ \/ b o o k s [ / ] (?< author > [ ^ / ] + ) [ / ] ? (?< title > [ ^ / ] + ) ? [ / ] ? $ /
722
+ let { keys, pattern } = fn ( rgx ) ;
723
+ t . same ( keys , false , '~> keys = false' ) ;
724
+ t . same ( rgx , pattern , '~> pattern = input' ) ;
725
+
726
+ // RegExp testing (not regexparam related)
727
+ t . false ( pattern . test ( '/books' ) ) ;
728
+ t . false ( pattern . test ( '/books/' ) ) ;
729
+ t . true ( pattern . test ( '/books/smith' ) ) ;
730
+ t . true ( pattern . test ( '/books/smith/' ) ) ;
731
+ t . true ( pattern . test ( '/books/smith/narnia' ) ) ;
732
+ t . true ( pattern . test ( '/books/smith/narnia/' ) ) ;
733
+ t . false ( pattern . test ( '/books/smith/narnia/reviews' ) ) ;
734
+ t . false ( pattern . test ( 'books/smith/narnia' ) ) ;
735
+
736
+ // exec results, array access
737
+ let [ url , author , title ] = pattern . exec ( '/books/smith/narnia/' ) ;
738
+ t . is ( url , '/books/smith/narnia/' , '~> executing pattern on correct trimming' ) ;
739
+ t . is ( author , 'smith' , '~> executing pattern gives correct value' ) ;
740
+ t . is ( title , 'narnia' , '~> executing pattern gives correct value' ) ;
741
+
742
+ // exec results, named object
743
+ t . toExec ( rgx , '/books/smith/narnia' , { author : 'smith' , title : 'narnia' } ) ;
744
+ t . toExec ( rgx , '/books/smith/narnia/' , { author : 'smith' , title : 'narnia' } ) ;
745
+ t . toExec ( rgx , '/books/smith/' , { author : 'smith' , title : undefined } ) ;
746
+
747
+ t . end ( ) ;
748
+ } ) ;
749
+
750
+ test ( 'param :: optional' , t => {
751
+ let { keys, pattern } = fn ( '/books/:author/:title?' ) ;
752
+ t . same ( keys , [ 'author' , 'title' ] , '~> keys has "author" & "title" values' ) ;
753
+ t . false ( pattern . test ( '/books' ) , '~> does not match naked base' ) ;
754
+ t . false ( pattern . test ( '/books/' ) , '~> does not match naked base w/ trailing slash' ) ;
755
+ t . true ( pattern . test ( '/books/smith' ) , '~> matches when optional parameter is missing counts' ) ;
756
+ t . true ( pattern . test ( '/books/smith/' ) , '~> matches when optional paramter is missing w/ trailing slash' ) ;
757
+ t . true ( pattern . test ( '/books/smith/narnia' ) , '~> matches when fully populated' ) ;
758
+ t . true ( pattern . test ( '/books/smith/narnia/' ) , '~> matches when fully populated w/ trailing slash' ) ;
759
+ t . false ( pattern . test ( '/books/smith/narnia/reviews' ) , '~> does not match extra bits' ) ;
760
+ t . false ( pattern . test ( 'books/smith/narnia' ) , '~> does not match path without lead slash' ) ;
761
+ let [ _ , author , title ] = pattern . exec ( '/books/smith/narnia' ) ;
762
+ t . is ( author , 'smith' , '~> executing pattern gives correct value' ) ;
763
+ t . is ( title , 'narnia' , '~> executing pattern gives correct value' ) ;
764
+ t . end ( ) ;
765
+ } ) ;
766
+
767
+ test ( '(RegExp) nameless' , t => {
768
+ // For whatever reason~
769
+ // ~> regexparam CANNOT give `keys` list cuz unknown
770
+ let rgx = / ^ \/ b o o k s [ / ] ( [ ^ / ] \w + ) [ / ] ? ( \w + ) ? (? = \/ | $ ) / i;
771
+ let { keys, pattern } = fn ( rgx ) ;
772
+ t . same ( keys , false , '~> keys = false' ) ;
773
+ t . same ( rgx , pattern , '~> pattern = input' ) ;
774
+
775
+ // RegExp testing (not regexparam related)
776
+ t . false ( pattern . test ( '/books' ) ) ;
777
+ t . false ( pattern . test ( '/books/' ) ) ;
778
+ t . true ( pattern . test ( '/books/smith' ) ) ;
779
+ t . true ( pattern . test ( '/books/smith/' ) ) ;
780
+ t . true ( pattern . test ( '/books/smith/narnia' ) ) ;
781
+ t . true ( pattern . test ( '/books/smith/narnia/' ) ) ;
782
+ t . false ( pattern . test ( 'books/smith/narnia' ) ) ;
783
+
784
+ // exec results, array access
785
+ let [ url , author , title ] = pattern . exec ( '/books/smith/narnia/' ) ;
786
+ t . is ( url , '/books/smith/narnia' , '~> executing pattern on correct trimming' ) ;
787
+ t . is ( author , 'smith' , '~> executing pattern gives correct value' ) ;
788
+ t . is ( title , 'narnia' , '~> executing pattern gives correct value' ) ;
789
+
790
+ // exec results, named object
791
+ // Note: UNKNOWN & UNNAMED KEYS
792
+ t . toExec ( rgx , '/books/smith/narnia' , { } ) ;
793
+ t . toExec ( rgx , '/books/smith/narnia/' , { } ) ;
794
+ t . toExec ( rgx , '/books/smith/' , { } ) ;
795
+
796
+ t . end ( ) ;
797
+ } ) ;
0 commit comments