feat(rules): replace go templates with custom variable expansion

- Replace template syntax ({{ .Request.Method }}) with $-prefixed variables ($req_method)
- Implement custom variable parser with static ($req_method, $status_code) and dynamic ($header(), $arg(), $form()) variables
- Replace templateOrStr interface with templateString struct and ExpandVars methods
- Add parser improvements for reliable quote handling
- Add new error types: ErrUnterminatedParenthesis, ErrUnexpectedVar, ErrExpectOneOrTwoArgs
- Update all tests and help text to use new variable syntax
- Add comprehensive unit and benchmark tests for variable expansion
This commit is contained in:
yusing
2025-10-25 22:43:47 +08:00
parent 9c3346dd9d
commit 1ec2872f3d
16 changed files with 1253 additions and 161 deletions

View File

@@ -8,7 +8,6 @@ import (
"path/filepath"
"strconv"
"strings"
"text/template"
"github.com/rs/zerolog"
nettypes "github.com/yusing/godoxy/internal/net/types"
@@ -91,11 +90,11 @@ func toKeyValueTemplate(args []string) (any, gperr.Error) {
return nil, ErrExpectTwoArgs
}
tmpl, err := validateTemplate(args[1], false)
isTemplate, err := validateTemplate(args[1], false)
if err != nil {
return nil, err
}
return &keyValueTemplate{args[0], tmpl}, nil
return &keyValueTemplate{args[0], isTemplate}, nil
}
// validateURL returns types.URL with the URL validated.
@@ -300,33 +299,20 @@ func validateModField(mod FieldModifier, args []string) (CommandHandler, gperr.E
return set, nil
}
func isTemplate(tmplStr string) bool {
return strings.Contains(tmplStr, "{{")
}
type templateWithLen struct {
*template.Template
len int
}
func (t *templateWithLen) Len() int {
return t.len
}
func validateTemplate(tmplStr string, newline bool) (templateOrStr, gperr.Error) {
func validateTemplate(tmplStr string, newline bool) (templateString, gperr.Error) {
if newline && !strings.HasSuffix(tmplStr, "\n") {
tmplStr += "\n"
}
if !isTemplate(tmplStr) {
return strTemplate(tmplStr), nil
if !NeedExpandVars(tmplStr) {
return templateString{tmplStr, false}, nil
}
tmpl, err := template.New("template").Parse(tmplStr)
err := ValidateVars(tmplStr)
if err != nil {
return nil, ErrInvalidArguments.With(err)
return templateString{}, gperr.Wrap(err)
}
return &templateWithLen{tmpl, len(tmplStr)}, nil
return templateString{tmplStr, true}, nil
}
func validateLevel(level string) (zerolog.Level, gperr.Error) {