Files
remark42/backend/app/migrator/mapper.go
T
Dmitry VerkhoturovandGitHub ba7c3aed94 refactor: modernise Go code with go fix and manual improvements (#2027)
Apply go fix ./... analysers (Go 1.26) across backend and examples:
- interface{} → any (type alias, no behaviour change)
- for i := 0; i < N; i++ → for range N / for i := range N
- slices.Contains / slices.ContainsFunc replacing manual loops
- strings.SplitSeq replacing strings.Split in range (avoids allocation)
- strings.CutPrefix replacing HasPrefix+TrimPrefix
- min() replacing manual if/else
- fmt.Appendf replacing []byte(fmt.Sprintf(...))
- strings.Builder replacing string += concatenation
- wg.Go(func(){}) replacing wg.Add(1)/go/wg.Done() pattern
- removed redundant ii := i loop variable copies (unnecessary since Go 1.22)

omitempty on struct-typed JSON fields: go fix removed omitempty from
struct-typed fields (time.Time, PostInfo, UserDetailEntry) because
encoding/json's omitempty never applied to struct types — it was always
a no-op. Kept as bare tags (no omitzero replacement) to preserve the
existing serialisation behaviour.
2026-03-25 16:42:37 -05:00

74 lines
1.8 KiB
Go

package migrator
import (
"fmt"
"io"
"strings"
)
// URLMapper implements Mapper interface
type URLMapper struct {
rules map[string]string
}
// NewURLMapper reads rules from given reader and returns initialized URLMapper
// if given rules are valid.
func NewURLMapper(reader io.Reader) (Mapper, error) {
u := &URLMapper{}
if err := u.loadRules(reader); err != nil {
return u, err
}
return u, nil
}
// loadRules loads url-mapping rules from reader to mapper.
// Rules must be a text consists of rows separated by \n.
// Each row holds from-url and to-url separated by space.
// If urls end with asterisk (*) it means try to match by prefix.
// Example:
// https://www.myblog.com/blog/1/ https://myblog.com/blog/1/
// https://www.myblog.com/* https://myblog.com/*
func (u *URLMapper) loadRules(reader io.Reader) error {
data, err := io.ReadAll(reader)
if err != nil {
return err
}
rulesText := strings.TrimSpace(string(data))
u.rules = make(map[string]string)
for row := range strings.SplitSeq(rulesText, "\n") {
row = strings.TrimSpace(row)
urls := strings.Split(row, " ")
if len(urls) != 2 {
return fmt.Errorf("bad row %s", row)
}
from, to := strings.TrimSpace(urls[0]), strings.TrimSpace(urls[1])
u.rules[from] = to
}
return nil
}
// URL maps given url to another url according loaded url-rules.
// If not matched returns given url.
func (u *URLMapper) URL(url string) string {
if newURL, ok := u.rules[url]; ok {
return newURL
}
// try to match by prefix
for oldURL, newURL := range u.rules {
if !strings.HasSuffix(oldURL, "*") {
continue
}
oldURL = strings.TrimSuffix(oldURL, "*")
newURL = strings.TrimSuffix(newURL, "*")
if after, ok := strings.CutPrefix(url, oldURL); ok {
return newURL + after
}
}
// search failed, return given url
return url
}