@ -16,6 +16,11 @@ type PathPart interface {
regex ( ) string
regex ( ) string
}
}
var _ PathPart = PathLiteral { }
var _ PathPart = PathShortPattern { }
var _ PathPart = PathLongPattern { }
var _ PathPart = PathString { }
type PathLiteral struct {
type PathLiteral struct {
LongAny bool ` parser:" @'**'" `
LongAny bool ` parser:" @'**'" `
ShortAny bool ` parser:"| @'*' " `
ShortAny bool ` parser:"| @'*' " `
@ -25,7 +30,7 @@ type PathLiteral struct {
func ( p PathLiteral ) regex ( ) string {
func ( p PathLiteral ) regex ( ) string {
switch {
switch {
case p . Slash :
case p . Slash :
return "/"
return regexp . QuoteMeta ( "/" )
case p . ShortAny :
case p . ShortAny :
return "([^/]+?)"
return "([^/]+?)"
case p . LongAny :
case p . LongAny :
@ -52,7 +57,7 @@ func (p PathLongPattern) regex() string {
}
}
type PathString struct {
type PathString struct {
Value string ` parser:"@ Ident"`
Value string ` parser:"@ ( Ident|Rune)+ "`
}
}
func ( p PathString ) regex ( ) string {
func ( p PathString ) regex ( ) string {
@ -63,18 +68,44 @@ type Pattern struct {
Parts [ ] PathPart ` parser:"@@+" `
Parts [ ] PathPart ` parser:"@@+" `
}
}
func ( pp Pattern ) regex ( ) string {
var parser = participle . MustBuild [ Pattern ] (
sb := & strings . Builder { }
participle . Union [ PathPart ] (
& PathLiteral { } ,
& PathLongPattern { } ,
& PathShortPattern { } ,
& PathString { } ,
) ,
participle . Lexer (
lexer . MustSimple ( [ ] lexer . SimpleRule {
{ Name : "Slash" , Pattern : ` / ` } ,
{ Name : "LongAny" , Pattern : ` \*\* ` } ,
{ Name : "ShortAny" , Pattern : ` \* ` } ,
{ Name : "PatternLongOpen" , Pattern : ` {{ ` } ,
{ Name : "PatternLongClose" , Pattern : ` }} ` } ,
{ Name : "PatternShortOpen" , Pattern : ` { ` } ,
{ Name : "PatternShortClose" , Pattern : ` } ` } ,
{ Name : "Ident" , Pattern : ` [a-zA-Z][a-zA-Z0-9\_]* ` } ,
{ Name : "Rune" , Pattern : ` [^/ { }]+ ` } ,
} ) ,
) ,
)
for _ , p := range pp . Parts {
func ParsePattern ( path string ) ( * Pattern , error ) {
sb . WriteString ( p . regex ( ) )
return parser . ParseString ( "" , path )
}
}
return sb . String ( )
func MustParsePattern ( path string ) * Pattern {
p , err := ParsePattern ( path )
if err != nil {
panic ( err )
}
return p
}
}
func ( pp Pattern ) Match ( s string ) ( bool , map [ string ] string , error ) {
// Match takes a path "s" and matches it against this pattern and returns whether it matched and in that case a map containing all captures for this pattern. This will throw an error if it can't compile the internal regex (should never happen).
r , err := regexp . Compile ( "^" + pp . regex ( ) + "$" )
func ( p Pattern ) Match ( s string ) ( bool , map [ string ] string , error ) {
r , err := regexp . Compile ( "^" + p . regex ( ) + "$" )
if err != nil {
if err != nil {
return false , nil , err
return false , nil , err
}
}
@ -96,26 +127,15 @@ func (pp Pattern) Match(s string) (bool, map[string]string, error) {
return true , ctx , nil
return true , ctx , nil
}
}
var parser = participle . MustBuild [ Pattern ] (
func ( p Pattern ) regex ( ) string {
participle . Union [ PathPart ] (
sb := & strings . Builder { }
& PathLiteral { } ,
& PathLongPattern { } ,
for _ , part := range p . Parts {
& PathShortPattern { } ,
sb . WriteString ( part . regex ( ) )
& PathString { } ,
}
) ,
participle . Lexer (
return sb . String ( )
lexer . MustSimple ( [ ] lexer . SimpleRule {
}
{ Name : "Slash" , Pattern : ` / ` } ,
{ Name : "LongAny" , Pattern : ` \*\* ` } ,
{ Name : "ShortAny" , Pattern : ` \* ` } ,
{ Name : "PatternLongOpen" , Pattern : ` {{ ` } ,
{ Name : "PatternLongClose" , Pattern : ` }} ` } ,
{ Name : "PatternShortOpen" , Pattern : ` { ` } ,
{ Name : "PatternShortClose" , Pattern : ` } ` } ,
{ Name : "Ident" , Pattern : ` [^/ { }]+ ` } ,
} ) ,
) ,
)
func RenderTemplate ( tmpl string , ctx map [ string ] string ) string {
func RenderTemplate ( tmpl string , ctx map [ string ] string ) string {
s := tmpl
s := tmpl
@ -124,16 +144,3 @@ func RenderTemplate(tmpl string, ctx map[string]string) string {
}
}
return s
return s
}
}
func ParsePattern ( path string ) ( * Pattern , error ) {
return parser . ParseString ( "" , path )
}
func MustParsePattern ( path string ) * Pattern {
p , err := ParsePattern ( path )
if err != nil {
panic ( err )
}
return p
}