Files
jfa-go/scripts/variants/main.go
Harvey Tindall 4a9bac1027 scripts: replace dark-variant.sh with go scripts/variants
uses regex mostly, resulting in a significantly faster execution (old:
~2s, new: ~31ms). Only matches classList.add/remove and class="..."
(won't touch string literal variables or colours), but these weren't
really used anyway. Supports multi-line classList.add/remove, which was
the reason I wrote this anyway (formatting the codebase introduced some
of these).
2025-12-09 14:28:05 +00:00

147 lines
3.8 KiB
Go

// Package variants provides a script to comb through typescript/javascript files and
// find (most) instances of a a17t color (~neutral...) being used without
// an accompanying dark version (dark:~d_neutral...) and insert one.
// Not fully feature-matched with the old bash version, only matching classList.add/remove and class="...",
// but doesn't break on multi line function params, and is probably much faster.
package main
import (
"bytes"
"flag"
"fmt"
"io/fs"
"log"
"os"
"path/filepath"
"regexp"
)
var classList = func() *regexp.Regexp {
classList, err := regexp.Compile(`classList\.(add|remove)(\((?:[^()]*|\((?:[^()]*|\([^()]*\))\))*\))`)
if err != nil {
panic(err)
}
return classList
}()
var color = func() *regexp.Regexp {
color, err := regexp.Compile(`\~(neutral|positive|warning|critical|info|urge|gray)`)
if err != nil {
panic(err)
}
return color
}()
var quotedColor = func() *regexp.Regexp {
quotedColor, err := regexp.Compile(`("|'|\x60)\~(neutral|positive|warning|critical|info|urge|gray)("|'|\x60)`)
if err != nil {
panic(err)
}
return quotedColor
}()
var htmlClassList = func() *regexp.Regexp {
htmlClassList, err := regexp.Compile(`class="[^"]*\~(neutral|positive|warning|critical|info|urge|gray)[^"]*"`)
if err != nil {
panic(err)
}
return htmlClassList
}()
func ParseDir(in, out string) error {
err := filepath.WalkDir(in, func(path string, d fs.DirEntry, err error) error {
if err != nil {
return err
}
info, err := d.Info()
if err != nil {
return err
}
perm := info.Mode()
rel, err := filepath.Rel(in, path)
outFile := filepath.Join(out, rel)
if d.IsDir() {
return os.MkdirAll(outFile, perm)
}
log.Printf("\"%s\" => \"%s\"\n", path, outFile)
if err != nil {
return err
}
return ParseFile(path, outFile, &perm)
})
return err
}
func ParseFile(in, out string, perm *fs.FileMode) error {
file, err := os.ReadFile(in)
if err != nil {
return err
}
if perm == nil {
f, err := os.Stat(in)
if err != nil {
return err
}
p := f.Mode()
perm = &p
}
outText := classList.ReplaceAllFunc(file, func(match []byte) []byte {
if bytes.Contains(match, []byte("dark:~d_")) {
log.Printf("Skipping pre-set dark colour: `%s`\n", string(match))
return match
}
submatches := quotedColor.FindSubmatch(match)
if len(submatches) == 0 {
return match
}
quote := string(submatches[1])
color := string(submatches[2])
fmt.Printf("Matched quote %s, color %s\n", quote, color)
newVal := bytes.Replace(match, []byte(quote+"~"+color+quote), []byte(quote+"~"+color+quote+", "+quote+"dark:~d_"+color+quote), 1)
fmt.Printf("`%s` => `%s`\n", string(match), string(newVal))
return newVal
})
outText = htmlClassList.ReplaceAllFunc(outText, func(match []byte) []byte {
if bytes.Contains(match, []byte("dark:~d_")) {
log.Printf("Skipping pre-set dark colour: `%s`\n", string(match))
return match
}
// Sucks we can't get a submatch from ReplaceAllFunc
submatches := color.FindSubmatch(match)
if len(submatches) == 0 {
return match
}
c := submatches[1]
newVal := bytes.Replace(match, []byte("~"+string(c)), []byte("~"+string(c)+" dark:~d_"+string(c)), 1)
fmt.Printf("`%s` => `%s`\n", string(match), string(newVal))
return newVal
})
err = os.WriteFile(out, outText, *perm)
return err
}
func main() {
var inFile, inDir, out string
flag.StringVar(&inFile, "file", "", "Input of an individual file.")
flag.StringVar(&inDir, "dir", "", "Input of a whole directory.")
flag.StringVar(&out, "out", "", "Output filepath/directory, depending on if -file or -dir passed.")
flag.Parse()
if out == "" {
flag.PrintDefaults()
os.Exit(1)
}
var err error
if inFile != "" {
err = ParseFile(inFile, out, nil)
} else if inDir != "" {
err = ParseDir(inDir, out)
} else {
flag.PrintDefaults()
os.Exit(1)
}
if err != nil {
log.Fatalf("failed: %v\n", err)
os.Exit(1)
}
}