Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 3 additions & 10 deletions cmd/internal/migrations/v3/cache_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,17 +35,10 @@ func MigrateCacheConfig(cmd *cobra.Command, cwd string, _, _ *semver.Version) er
s = strings.ReplaceAll(s, "Store:", "Storage:")
s = strings.ReplaceAll(s, "Key:", "KeyGenerator:")
s = reCacheControl.ReplaceAllStringFunc(s, func(match string) string {
value := strings.TrimPrefix(match, "CacheControl:")
value = strings.TrimSpace(value)
rawValue := strings.TrimPrefix(match, "CacheControl:")
rawValue = strings.TrimSpace(rawValue)

comment := ""
if idx := strings.Index(value, "//"); idx != -1 {
comment = strings.TrimSpace(value[idx:])
value = value[:idx]
} else if idx := strings.Index(value, "/*"); idx != -1 {
comment = strings.TrimSpace(value[idx:])
value = value[:idx]
}
value, comment := ExtractCommentAndValue(rawValue)

hasComma := strings.HasSuffix(strings.TrimRight(value, " \t"), ",")
if hasComma {
Expand Down
87 changes: 87 additions & 0 deletions cmd/internal/migrations/v3/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package v3

import (
"fmt"
"go/ast"
"regexp"
"sort"
"strconv"
Expand Down Expand Up @@ -480,3 +481,89 @@ func addImport(content, path string) string {

return content
}

// GetBaseIdent recursively resolves an expression to its base identifier.
// It handles selector expressions, call expressions, and identifiers.
// Returns nil if the expression cannot be resolved to a simple identifier.
func GetBaseIdent(expr ast.Expr) *ast.Ident {
for {
switch e := expr.(type) {
case *ast.Ident:
return e
case *ast.SelectorExpr:
expr = e.X
case *ast.CallExpr:
expr = e.Fun
default:
return nil
}
}
}

// ExtractCommentAndValue separates a value from its trailing comment.
// It handles both line comments (//) and block comments (/* */).
// Returns the value (trimmed) and the comment (with original delimiters).
func ExtractCommentAndValue(line string) (value, comment string) {
value = line
if idx := strings.Index(line, "//"); idx >= 0 {
comment = strings.TrimSpace(line[idx:])
value = strings.TrimSpace(line[:idx])
} else if idx := strings.Index(line, "/*"); idx >= 0 {
comment = strings.TrimSpace(line[idx:])
value = strings.TrimSpace(line[:idx])
}
return value, comment
}

// FormatFieldWithComment formats a field assignment with consistent spacing
// for indentation, value, comma, comment, and newline.
func FormatFieldWithComment(indent, fieldName, value, comma, comment, newline string) string {
if comment != "" {
comment = " " + comment
}
return fmt.Sprintf("%s%s: %s%s%s%s", indent, fieldName, value, comma, comment, newline)
}

// IterateConfigBlocks finds all occurrences matching the given regex pattern,
// extracts their config blocks using braces, processes each block with the
// provided function, and reconstructs the content.
func IterateConfigBlocks(content string, pattern *regexp.Regexp, processor func(string) string) string {
matches := pattern.FindAllStringIndex(content, -1)
if len(matches) == 0 {
return content
}

var b strings.Builder
last := 0
for _, m := range matches {
if m[0] < last {
// Skip matches that fall inside a block we've already processed.
continue
}
b.WriteString(content[last:m[0]]) //nolint:errcheck // WriteString never returns an error
start := m[0]
end := extractBlock(content, m[1], '{', '}')
cfg := content[start:end]

// Process the config block
cfg = processor(cfg)

b.WriteString(cfg) //nolint:errcheck // WriteString never returns an error
last = end
}
b.WriteString(content[last:]) //nolint:errcheck // WriteString never returns an error
return b.String()
}

// BuildExtractorChain builds an extractor expression from a slice of extractors.
// Returns a single extractor for one element, Chain() for multiple, or empty for none.
func BuildExtractorChain(extractors []string) string {
switch len(extractors) {
case 0:
return ""
case 1:
return extractors[0]
default:
return fmt.Sprintf("extractors.Chain(%s)", strings.Join(extractors, ", "))
}
}
16 changes: 1 addition & 15 deletions cmd/internal/migrations/v3/context_methods.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,20 +26,6 @@ func MigrateContextMethods(cmd *cobra.Command, cwd string, _, _ *semver.Version)
file, err := parser.ParseFile(fset, "", content, parser.ParseComments)
if err == nil {
modified := false
baseIdent := func(expr ast.Expr) *ast.Ident {
for {
switch e := expr.(type) {
case *ast.Ident:
return e
case *ast.SelectorExpr:
expr = e.X
case *ast.CallExpr:
expr = e.Fun
default:
return nil
}
}
}
ast.Inspect(file, func(n ast.Node) bool {
call, ok := n.(*ast.CallExpr)
if !ok {
Expand All @@ -49,7 +35,7 @@ func MigrateContextMethods(cmd *cobra.Command, cwd string, _, _ *semver.Version)
if !ok || sel.Sel.Name != "Context" || len(call.Args) != 0 {
return true
}
if ident := baseIdent(sel.X); ident != nil && isFiberCtx(orig, ident.Name) {
if ident := GetBaseIdent(sel.X); ident != nil && isFiberCtx(orig, ident.Name) {
sel.Sel.Name = "RequestCtx"
modified = true
}
Expand Down
44 changes: 8 additions & 36 deletions cmd/internal/migrations/v3/csrfconfig.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,55 +15,27 @@ func MigrateCSRFConfig(cmd *cobra.Command, cwd string, _, _ *semver.Version) err
reConfig := regexp.MustCompile(`csrf\.Config{`)
reSession := regexp.MustCompile(`(?m)\s*SessionKey:\s*[^,\n]+,?\s*(//[^\n]*)?\n`)
changed, err := internal.ChangeFileContent(cwd, func(content string) string {
matches := reConfig.FindAllStringIndex(content, -1)
if len(matches) == 0 {
return content
}

var b strings.Builder
last := 0
for _, m := range matches {
if _, err := b.WriteString(content[last:m[0]]); err != nil {
return content
}
start := m[0]
end := extractBlock(content, m[1], '{', '}')
cfg := content[start:end]
updated := IterateConfigBlocks(content, reConfig, func(cfg string) string {
cfg = strings.ReplaceAll(cfg, "Expiration:", "IdleTimeout:")
cfg = reSession.ReplaceAllString(cfg, "")

cfg = replaceKeyLookup(cfg, func(indent, val, comma, comment, newline string) string {
return replaceKeyLookup(cfg, func(indent, val, comma, comment, newline string) string {
var extractor string
switch {
case strings.HasPrefix(val, "header:"):
extractor = fmt.Sprintf("Extractor: extractors.FromHeader(%q)", strings.TrimPrefix(val, "header:"))
extractor = fmt.Sprintf("extractors.FromHeader(%q)", strings.TrimPrefix(val, "header:"))
case strings.HasPrefix(val, "form:"):
extractor = fmt.Sprintf("Extractor: extractors.FromForm(%q)", strings.TrimPrefix(val, "form:"))
extractor = fmt.Sprintf("extractors.FromForm(%q)", strings.TrimPrefix(val, "form:"))
case strings.HasPrefix(val, "query:"):
extractor = fmt.Sprintf("Extractor: extractors.FromQuery(%q)", strings.TrimPrefix(val, "query:"))
extractor = fmt.Sprintf("extractors.FromQuery(%q)", strings.TrimPrefix(val, "query:"))
default:
if comment != "" {
comment = " " + comment
}
return fmt.Sprintf("%s// TODO: migrate KeyLookup: %s%s%s", indent, val, comment, newline)
return FormatFieldWithComment(indent, "// TODO: migrate KeyLookup", val, "", comment, newline)
}

if comment != "" {
comment = " " + comment
}
return fmt.Sprintf("%s%s%s%s%s", indent, extractor, comma, comment, newline)
return FormatFieldWithComment(indent, "Extractor", extractor, comma, comment, newline)
})
})

if _, err := b.WriteString(cfg); err != nil {
return content
}
last = end
}
if _, err := b.WriteString(content[last:]); err != nil {
return content
}

updated := b.String()
if updated != content {
updated = addImport(updated, "github.com/gofiber/fiber/v3/extractors")
}
Expand Down
29 changes: 3 additions & 26 deletions cmd/internal/migrations/v3/encryptcookie_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,34 +15,11 @@ func MigrateEncryptcookieConfig(cmd *cobra.Command, cwd string, _, _ *semver.Ver
reConfig := regexp.MustCompile(`encryptcookie\.Config{`)

changed, err := internal.ChangeFileContent(cwd, func(content string) string {
matches := reConfig.FindAllStringIndex(content, -1)
if len(matches) == 0 {
return content
}

var b strings.Builder
last := 0
for _, m := range matches {
if _, err := b.WriteString(content[last:m[0]]); err != nil {
return content
}

start := m[0]
end := extractBlock(content, m[1], '{', '}')
cfg := content[start:end]
return IterateConfigBlocks(content, reConfig, func(cfg string) string {
cfg = addEncryptcookieParam(cfg, "Encryptor")
cfg = addEncryptcookieParam(cfg, "Decryptor")

if _, err := b.WriteString(cfg); err != nil {
return content
}
last = end
}

if _, err := b.WriteString(content[last:]); err != nil {
return content
}
return b.String()
return cfg
})
})
if err != nil {
return fmt.Errorf("failed to migrate encryptcookie configs: %w", err)
Expand Down
25 changes: 4 additions & 21 deletions cmd/internal/migrations/v3/jwt_extractor.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,33 +60,16 @@ func MigrateJWTExtractor(cmd *cobra.Command, cwd string, _, _ *semver.Version) e
case strings.HasPrefix(p, "form:"):
extractors = append(extractors, fmt.Sprintf("extractors.FromForm(%q)", strings.TrimPrefix(p, "form:")))
default:
if comment != "" {
comment = " " + comment
}
return fmt.Sprintf("%s// TODO: migrate TokenLookup: %s%s%s", indent, val, comment, newline)
return FormatFieldWithComment(indent, "// TODO: migrate TokenLookup", val, "", comment, newline)
}
}

extractor := ""
switch len(extractors) {
case 1:
extractor = extractors[0]
case 0:
default:
extractor = fmt.Sprintf("extractors.Chain(%s)", strings.Join(extractors, ", "))
}

extractor := BuildExtractorChain(extractors)
if extractor == "" {
if comment != "" {
comment = " " + comment
}
return fmt.Sprintf("%s// TODO: migrate TokenLookup: %s%s%s", indent, val, comment, newline)
return FormatFieldWithComment(indent, "// TODO: migrate TokenLookup", val, "", comment, newline)
}

if comment != "" {
comment = " " + comment
}
return fmt.Sprintf("%sExtractor: %s%s%s%s", indent, extractor, comma, comment, newline)
return FormatFieldWithComment(indent, "Extractor", extractor, comma, comment, newline)
})

cfg = reAuthLine.ReplaceAllString(cfg, "")
Expand Down
22 changes: 4 additions & 18 deletions cmd/internal/migrations/v3/key_auth_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,30 +48,16 @@ func MigrateKeyAuthConfig(cmd *cobra.Command, cwd string, _, _ *semver.Version)
case strings.HasPrefix(p, "cookie:"):
extractors = append(extractors, fmt.Sprintf("extractors.FromCookie(%q)", strings.TrimPrefix(p, "cookie:")))
default:
if comment != "" {
comment = " " + comment
}
return fmt.Sprintf("%s// TODO: migrate KeyLookup: %s%s%s", indent, val, comment, newline)
return FormatFieldWithComment(indent, "// TODO: migrate KeyLookup", val, "", comment, newline)
}
}

extractor := ""
if len(extractors) == 1 {
extractor = extractors[0]
} else if len(extractors) > 1 {
extractor = fmt.Sprintf("extractors.Chain(%s)", strings.Join(extractors, ", "))
}
extractor := BuildExtractorChain(extractors)
if extractor == "" {
if comment != "" {
comment = " " + comment
}
return fmt.Sprintf("%s// TODO: migrate KeyLookup: %s%s%s", indent, val, comment, newline)
return FormatFieldWithComment(indent, "// TODO: migrate KeyLookup", val, "", comment, newline)
}

if comment != "" {
comment = " " + comment
}
return fmt.Sprintf("%sExtractor: %s%s%s%s", indent, extractor, comma, comment, newline)
return FormatFieldWithComment(indent, "Extractor", extractor, comma, comment, newline)
})

cfg = removeConfigField(cfg, "AuthScheme")
Expand Down
15 changes: 3 additions & 12 deletions cmd/internal/migrations/v3/paseto_extractor.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,7 @@ func MigratePasetoExtractor(cmd *cobra.Command, cwd string, _, _ *semver.Version
lookup = strings.TrimSuffix(lookup, "}")
parts := splitArgs(lookup)
if len(parts) < 2 {
if comment != "" {
comment = " " + comment
}
return fmt.Sprintf("%s// TODO: migrate TokenLookup: %s%s%s", indent, val, comment, newline)
return FormatFieldWithComment(indent, "// TODO: migrate TokenLookup", val, "", comment, newline)
}

source := strings.TrimSpace(parts[0])
Expand Down Expand Up @@ -99,16 +96,10 @@ func MigratePasetoExtractor(cmd *cobra.Command, cwd string, _, _ *semver.Version
}

if extractor == "" {
if comment != "" {
comment = " " + comment
}
return fmt.Sprintf("%s// TODO: migrate TokenLookup: %s%s%s", indent, val, comment, newline)
return FormatFieldWithComment(indent, "// TODO: migrate TokenLookup", val, "", comment, newline)
}

if comment != "" {
comment = " " + comment
}
return fmt.Sprintf("%sExtractor: %s%s%s%s", indent, extractor, comma, comment, newline)
return FormatFieldWithComment(indent, "Extractor", extractor, comma, comment, newline)
})

cfg = removeConfigField(cfg, "TokenPrefix")
Expand Down
17 changes: 1 addition & 16 deletions cmd/internal/migrations/v3/redirect_methods.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,21 +27,6 @@ func MigrateRedirectMethods(cmd *cobra.Command, cwd string, _, _ *semver.Version

modified := false

baseIdent := func(expr ast.Expr) *ast.Ident {
for {
switch e := expr.(type) {
case *ast.Ident:
return e
case *ast.SelectorExpr:
expr = e.X
case *ast.CallExpr:
expr = e.Fun
default:
return nil
}
}
}

ast.Inspect(file, func(n ast.Node) bool {
call, ok := n.(*ast.CallExpr)
if !ok {
Expand All @@ -53,7 +38,7 @@ func MigrateRedirectMethods(cmd *cobra.Command, cwd string, _, _ *semver.Version
return true
}

ident := baseIdent(sel.X)
ident := GetBaseIdent(sel.X)
if ident == nil || !isFiberCtx(orig, ident.Name) {
return true
}
Expand Down
Loading
Loading