22// Use of this source code is governed by a MIT style
33// license that can be found in the LICENSE file.
44
5- package path_to_regexp
5+ package pathtoregexp
66
77import (
88 "errors"
@@ -16,7 +16,9 @@ import (
1616 "github.com/dlclark/regexp2"
1717)
1818
19- type Key struct {
19+ // Token is parsed from path. For example, using `/user/:id`, `tokens` will
20+ // contain `[{name:'id', delimiter:'/', optional:false, repeat:false}]`
21+ type Token struct {
2022 // The name of the token (string for named or number for index)
2123 name interface {}
2224
@@ -36,6 +38,7 @@ type Key struct {
3638 pattern string
3739}
3840
41+ // Options contains some optional configs
3942type Options struct {
4043 // When true the regexp will be case sensitive. (default: false)
4144 sensitive bool
@@ -64,18 +67,18 @@ type Options struct {
6467 encode func (uri string , token interface {}) string
6568}
6669
67- // Default configs .
70+ // DefaultDelimiter is the default delimiter of path .
6871const DefaultDelimiter = "/"
6972
70- // The main path matching regexp utility.
73+ // PathRegexp is the main path matching regexp utility.
7174var PathRegexp = regexp2 .MustCompile (strings .Join ([]string {
7275 "(\\ \\ .)" ,
7376 "(?:\\ :(\\ w+)(?:\\ (((?:\\ \\ .|[^\\ \\ ()])+)\\ ))?|\\ (((?:\\ \\ .|[^\\ \\ ()])+)\\ ))([+*?])?" ,
7477}, "|" ), regexp2 .None )
7578
7679// Parse a string for the raw tokens.
7780func Parse (str string , o * Options ) []interface {} {
78- tokens , keyIndex , index , path , pathEscaped := make ([]interface {}, 0 ), 0 , 0 , "" , false
81+ tokens , tokenIndex , index , path , pathEscaped := make ([]interface {}, 0 ), 0 , 0 , "" , false
7982 if o == nil {
8083 o = & Options {}
8184 }
@@ -127,10 +130,10 @@ func Parse(str string, o *Options) []interface{} {
127130 pattern := orString (capture , group )
128131 delimiter := orString (prev , defaultDelimiter )
129132
130- var keyName interface {} = name
133+ var tokenName interface {} = name
131134 if name == "" {
132- keyName = keyIndex
133- keyIndex ++
135+ tokenName = tokenIndex
136+ tokenIndex ++
134137 }
135138 if pattern != "" {
136139 pattern = escapeGroup (pattern )
@@ -141,8 +144,8 @@ func Parse(str string, o *Options) []interface{} {
141144 }
142145 pattern = "[^" + escapeString (d ) + "]+?"
143146 }
144- tokens = append (tokens , Key {
145- name : keyName ,
147+ tokens = append (tokens , Token {
148+ name : tokenName ,
146149 prefix : prev ,
147150 delimiter : delimiter ,
148151 optional : optional ,
@@ -172,7 +175,7 @@ func tokensToFunction(tokens []interface{}, o *Options) (
172175
173176 // Compile all the patterns before compilation.
174177 for i , token := range tokens {
175- if token , ok := token .(Key ); ok {
178+ if token , ok := token .(Token ); ok {
176179 m , err := regexp2 .Compile ("^(?:" + token .pattern + ")$" , flags (o ))
177180 if err != nil {
178181 return nil , err
@@ -199,7 +202,7 @@ func tokensToFunction(tokens []interface{}, o *Options) (
199202 continue
200203 }
201204
202- if token , ok := token .(Key ); ok {
205+ if token , ok := token .(Token ); ok {
203206 if data != nil && reflect .TypeOf (data ).Kind () == reflect .Map {
204207 data := toMap (data )
205208 value := data [token .name ]
@@ -331,9 +334,9 @@ func toSlice(data interface{}) []interface{} {
331334
332335func toMap (data interface {}) map [interface {}]interface {} {
333336 v , m := reflect .ValueOf (data ), make (map [interface {}]interface {})
334- for _ , key := range v .MapKeys () {
335- value := v .MapIndex (key )
336- m [key .Interface ()] = value .Interface ()
337+ for _ , k := range v .MapKeys () {
338+ value := v .MapIndex (k )
339+ m [k .Interface ()] = value .Interface ()
337340 }
338341 return m
339342}
@@ -372,16 +375,16 @@ func flags(o *Options) regexp2.RegexOptions {
372375 return regexp2 .IgnoreCase
373376}
374377
375- // Pull out keys from a regexp.
376- func regexpToRegexp (path * regexp2.Regexp , keys * []Key ) * regexp2.Regexp {
377- if keys != nil {
378+ // Pull out tokens from a regexp.
379+ func regexpToRegexp (path * regexp2.Regexp , tokens * []Token ) * regexp2.Regexp {
380+ if tokens != nil {
378381 r := regexp2 .MustCompile ("\\ ((?!\\ ?)" , regexp2 .None )
379382 m , _ := r .FindStringMatch (path .String ())
380383 if m != nil && m .GroupCount () > 0 {
381- newKeys := make ([]Key , 0 , len (* keys )+ m .GroupCount ())
382- newKeys = append (newKeys , * keys ... )
384+ newTokens := make ([]Token , 0 , len (* tokens )+ m .GroupCount ())
385+ newTokens = append (newTokens , * tokens ... )
383386 for i := 0 ; i < m .GroupCount (); i ++ {
384- newKeys = append (newKeys , Key {
387+ newTokens = append (newTokens , Token {
385388 name : i ,
386389 prefix : "" ,
387390 delimiter : "" ,
@@ -390,20 +393,20 @@ func regexpToRegexp(path *regexp2.Regexp, keys *[]Key) *regexp2.Regexp {
390393 pattern : "" ,
391394 })
392395 }
393- hdr := (* reflect .SliceHeader )(unsafe .Pointer (keys ))
394- * hdr = * (* reflect .SliceHeader )(unsafe .Pointer (& newKeys ))
396+ hdr := (* reflect .SliceHeader )(unsafe .Pointer (tokens ))
397+ * hdr = * (* reflect .SliceHeader )(unsafe .Pointer (& newTokens ))
395398 }
396399 }
397400
398401 return path
399402}
400403
401404// Transform an array into a regexp.
402- func arrayToRegexp (path []interface {}, keys * []Key , o * Options ) (* regexp2.Regexp , error ) {
405+ func arrayToRegexp (path []interface {}, tokens * []Token , o * Options ) (* regexp2.Regexp , error ) {
403406 var parts []string
404407
405408 for i := 0 ; i < len (path ); i ++ {
406- r , err := PathToRegexp (path [i ], keys , o )
409+ r , err := PathToRegexp (path [i ], tokens , o )
407410 if err != nil {
408411 return nil , err
409412 }
@@ -414,12 +417,12 @@ func arrayToRegexp(path []interface{}, keys *[]Key, o *Options) (*regexp2.Regexp
414417}
415418
416419// Create a path regexp from string input.
417- func stringToRegexp (path string , keys * []Key , o * Options ) (* regexp2.Regexp , error ) {
418- return tokensToRegExp (Parse (path , o ), keys , o )
420+ func stringToRegexp (path string , tokens * []Token , o * Options ) (* regexp2.Regexp , error ) {
421+ return tokensToRegExp (Parse (path , o ), tokens , o )
419422}
420423
421424// Expose a function for taking tokens and returning a RegExp.
422- func tokensToRegExp (tokens []interface {}, keys * []Key , o * Options ) (* regexp2.Regexp , error ) {
425+ func tokensToRegExp (rawTokens []interface {}, tokens * []Token , o * Options ) (* regexp2.Regexp , error ) {
423426 if o == nil {
424427 o = & Options {}
425428 }
@@ -456,25 +459,25 @@ func tokensToRegExp(tokens []interface{}, keys *[]Key, o *Options) (*regexp2.Reg
456459 route = "^"
457460 }
458461
459- var newKeys []Key
460- if keys != nil {
461- newKeys = make ([]Key , 0 , len (* keys )+ len (tokens ))
462- newKeys = append (newKeys , * keys ... )
462+ var newTokens []Token
463+ if tokens != nil {
464+ newTokens = make ([]Token , 0 , len (* tokens )+ len (rawTokens ))
465+ newTokens = append (newTokens , * tokens ... )
463466 }
464467
465468 // Iterate over the tokens and create our regexp string.
466- for _ , token := range tokens {
469+ for _ , token := range rawTokens {
467470 if str , ok := token .(string ); ok {
468471 route += escapeString (str )
469- } else if token , ok := token .(Key ); ok {
472+ } else if token , ok := token .(Token ); ok {
470473 capture := token .pattern
471474 if token .repeat {
472475 capture = "(?:" + token .pattern + ")(?:" + escapeString (token .delimiter ) +
473476 "(?:" + token .pattern + "))*"
474477 }
475478
476- if keys != nil {
477- newKeys = append (newKeys , token )
479+ if tokens != nil {
480+ newTokens = append (newTokens , token )
478481 }
479482
480483 if token .optional {
@@ -489,9 +492,9 @@ func tokensToRegExp(tokens []interface{}, keys *[]Key, o *Options) (*regexp2.Reg
489492 }
490493 }
491494
492- if keys != nil {
493- hdr := (* reflect .SliceHeader )(unsafe .Pointer (keys ))
494- * hdr = * (* reflect .SliceHeader )(unsafe .Pointer (& newKeys ))
495+ if tokens != nil {
496+ hdr := (* reflect .SliceHeader )(unsafe .Pointer (tokens ))
497+ * hdr = * (* reflect .SliceHeader )(unsafe .Pointer (& newTokens ))
495498 }
496499
497500 if end {
@@ -506,10 +509,10 @@ func tokensToRegExp(tokens []interface{}, keys *[]Key, o *Options) (*regexp2.Reg
506509 route += s
507510 } else {
508511 isEndDelimited := false
509- if len (tokens ) == 0 {
512+ if len (rawTokens ) == 0 {
510513 isEndDelimited = true
511514 } else {
512- endToken := tokens [len (tokens )- 1 ]
515+ endToken := rawTokens [len (rawTokens )- 1 ]
513516 if endToken == nil {
514517 isEndDelimited = true
515518 } else if str , ok := endToken .(string ); ok {
@@ -528,23 +531,21 @@ func tokensToRegExp(tokens []interface{}, keys *[]Key, o *Options) (*regexp2.Reg
528531 return regexp2 .Compile (route , flags (o ))
529532}
530533
531- // Normalize the given path string, returning a regular expression.
532- // An empty array can be passed in for the keys , which will hold the
533- // placeholder key descriptions. For example, using `/user/:id`, `keys ` will
534- // contain `[{ name: 'id', delimiter: '/', optional: false, repeat: false }]`.
535- func PathToRegexp (path interface {}, keys * []Key , options * Options ) (* regexp2.Regexp , error ) {
534+ // PathToRegexp normalizes the given path string, returning a regular expression.
535+ // An empty array can be passed in for the tokens , which will hold the
536+ // placeholder token descriptions. For example, using `/user/:id`, `tokens ` will
537+ // contain `[{name: 'id', delimiter: '/', optional: false, repeat: false}]`.
538+ func PathToRegexp (path interface {}, tokens * []Token , options * Options ) (* regexp2.Regexp , error ) {
536539 switch path := path .(type ) {
537540 case * regexp2.Regexp :
538- return regexpToRegexp (path , keys ), nil
539- case []interface {}:
540- return arrayToRegexp (path , keys , options )
541+ return regexpToRegexp (path , tokens ), nil
541542 case string :
542- return stringToRegexp (path , keys , options )
543+ return stringToRegexp (path , tokens , options )
543544 }
544545
545546 switch reflect .TypeOf (path ).Kind () {
546547 case reflect .Slice , reflect .Array :
547- return arrayToRegexp (toSlice (path ), keys , options )
548+ return arrayToRegexp (toSlice (path ), tokens , options )
548549 }
549550
550551 return nil , errors .New (`path should be string, array or slice of strings,
0 commit comments