Files
renamer/internal/extension/parser.go

78 lines
2.3 KiB
Go

package extension
import (
"errors"
"fmt"
"strings"
)
// ParseResult captures normalized CLI arguments for the extension command.
type ParseResult struct {
SourcesCanonical []string
SourcesDisplay []string
Duplicates []string
NoOps []string
Target string
}
// ParseArgs validates extension command arguments and returns normalized tokens.
func ParseArgs(args []string) (ParseResult, error) {
if len(args) < 2 {
return ParseResult{}, errors.New("at least one source extension and a target extension are required")
}
target := NormalizeTargetExtension(args[len(args)-1])
if target == "" {
return ParseResult{}, errors.New("target extension cannot be empty")
}
if !strings.HasPrefix(target, ".") {
return ParseResult{}, fmt.Errorf("target extension %q must start with '.'", target)
}
if len(target) == 1 {
return ParseResult{}, fmt.Errorf("target extension %q must include characters after '.'", target)
}
rawSources := args[:len(args)-1]
trimmedSources := make([]string, len(rawSources))
for i, src := range rawSources {
trimmed := strings.TrimSpace(src)
if trimmed == "" {
return ParseResult{}, errors.New("source extensions cannot be empty")
}
if !strings.HasPrefix(trimmed, ".") {
return ParseResult{}, fmt.Errorf("source extension %q must start with '.'", trimmed)
}
if len(trimmed) == 1 {
return ParseResult{}, fmt.Errorf("source extension %q must include characters after '.'", trimmed)
}
trimmedSources[i] = trimmed
}
canonical, display, duplicates := NormalizeSourceExtensions(trimmedSources)
targetCanonical := CanonicalExtension(target)
filteredCanonical := make([]string, 0, len(canonical))
filteredDisplay := make([]string, 0, len(display))
noOps := make([]string, 0)
for i, canon := range canonical {
if canon == targetCanonical && display[i] == target {
noOps = append(noOps, display[i])
continue
}
filteredCanonical = append(filteredCanonical, canon)
filteredDisplay = append(filteredDisplay, display[i])
}
if len(filteredCanonical) == 0 {
return ParseResult{}, errors.New("all source extensions match the target extension; provide at least one distinct source extension")
}
return ParseResult{
SourcesCanonical: filteredCanonical,
SourcesDisplay: filteredDisplay,
Duplicates: duplicates,
NoOps: noOps,
Target: target,
}, nil
}