149 lines
4.3 KiB
Go
149 lines
4.3 KiB
Go
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"strings"
|
|
"unicode"
|
|
)
|
|
|
|
// AddTag generates code for a new custom tag
|
|
func AddTag(delimiter, tagName, targetElement string) {
|
|
fmt.Printf("Adding tag: %s -> %s (delimiter: %s)\n", tagName, targetElement, delimiter)
|
|
|
|
if err := updateTagsFile(delimiter, tagName); err != nil {
|
|
fmt.Printf("Error updating templates/tags.go: %v\n", err)
|
|
os.Exit(1)
|
|
}
|
|
|
|
if err := updateParseFile(tagName, targetElement); err != nil {
|
|
fmt.Printf("Error updating parse.go: %v\n", err)
|
|
os.Exit(1)
|
|
}
|
|
|
|
fmt.Println("Successfully added tag!")
|
|
}
|
|
|
|
func updateTagsFile(delimiter, tagName string) error {
|
|
path := "templates/tags.go"
|
|
content, err := os.ReadFile(path)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
pascalTagName := toPascalCase(tagName)
|
|
newLine := fmt.Sprintf("var %s = customtag.New(\"%s\", \"%s\")\n", pascalTagName, delimiter, tagName)
|
|
|
|
// check if already exists
|
|
if strings.Contains(string(content), newLine) {
|
|
fmt.Println("Tag definition already exists in templates/tags.go")
|
|
return nil
|
|
}
|
|
|
|
// Append to file
|
|
f, err := os.OpenFile(path, os.O_APPEND|os.O_WRONLY, 0644)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer f.Close()
|
|
|
|
if _, err := f.WriteString(newLine); err != nil {
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func updateParseFile(tagName, targetElement string) error {
|
|
path := "parse.go"
|
|
contentBytes, err := os.ReadFile(path)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
content := string(contentBytes)
|
|
|
|
pascalTagName := toPascalCase(tagName)
|
|
|
|
// 1. Add to Goldmark Extensions
|
|
// Find `templates.SidebarTag,` or `templates.TopBanner,` and add after it
|
|
// We'll look for `goldmark.WithExtensions(` and find the closing `),`
|
|
|
|
extLine := fmt.Sprintf("\t\t\t\ttemplates.%s,", pascalTagName)
|
|
if !strings.Contains(content, extLine) {
|
|
// Simple insertion strategy: find `templates.TopBanner,`
|
|
anchor := "templates.TopBanner,"
|
|
if idx := strings.Index(content, anchor); idx != -1 {
|
|
insertAt := idx + len(anchor)
|
|
content = content[:insertAt] + "\n" + extLine + content[insertAt:]
|
|
} else {
|
|
return fmt.Errorf("could not find anchor 'templates.TopBanner,' in parse.go to insert extension registration")
|
|
}
|
|
} else {
|
|
fmt.Println("Extension registration already exists in parse.go")
|
|
}
|
|
|
|
// 2. Add Post-Processing Logic
|
|
// We'll look for `// Build Full Page` and insert before it, or after the TopBanner block.
|
|
// A good anchor is `// _-_- TopBanner` block's end.
|
|
|
|
// Let's construct the code block to insert
|
|
targetTag, targetClass := parseTargetElement(targetElement)
|
|
|
|
// Prepare the replacement logic
|
|
var replacementLogic string
|
|
if targetClass != "" {
|
|
replacementLogic = fmt.Sprintf(`return fmt.Sprintf("<%s class=\"%s\">%%s</%s>", innerContent)`, targetTag, targetClass, targetTag)
|
|
} else {
|
|
replacementLogic = fmt.Sprintf(`return fmt.Sprintf("<%s>%%s</%s>", innerContent)`, targetTag, targetTag)
|
|
}
|
|
|
|
codeBlock := fmt.Sprintf(`
|
|
// %s %s
|
|
%sRegex := regexp.MustCompile("(?s)<%s>.*?</%s>")
|
|
if %sRegex.MatchString(htmlContent) {
|
|
htmlContent = %sRegex.ReplaceAllStringFunc(htmlContent, func(match string) string {
|
|
innerContent := strings.TrimPrefix(match, "<%s>")
|
|
innerContent = strings.TrimSuffix(innerContent, "</%s>")
|
|
%s
|
|
})
|
|
}
|
|
`, pascalTagName, tagName, tagName, tagName, tagName, tagName, tagName, tagName, tagName, replacementLogic)
|
|
|
|
if !strings.Contains(content, fmt.Sprintf("%sRegex :=", tagName)) {
|
|
// Anchor: find end of TopBanner block
|
|
// We know TopBanner block ends with a closing brace for the `if topbannerRegex.MatchString` block
|
|
// But strictly speaking, we are inside `if file.RoutePath == "/" { ... }`.
|
|
// Let's look for `// Build Full Page` and insert BEFORE it.
|
|
|
|
|
|
anchor := "// Build Full Page"
|
|
if idx := strings.Index(content, anchor); idx != -1 {
|
|
// Insert BEFORE "// Build Full Page", which matches the global scope (after the if block)
|
|
content = content[:idx] + codeBlock + content[idx:]
|
|
} else {
|
|
return fmt.Errorf("could not find anchor '// Build Full Page' in parse.go")
|
|
}
|
|
} else {
|
|
fmt.Println("Regex logic already exists in parse.go")
|
|
}
|
|
|
|
return os.WriteFile(path, []byte(content), 0644)
|
|
}
|
|
|
|
func toPascalCase(s string) string {
|
|
if s == "" {
|
|
return ""
|
|
}
|
|
runes := []rune(s)
|
|
runes[0] = unicode.ToUpper(runes[0])
|
|
return string(runes)
|
|
}
|
|
|
|
func parseTargetElement(t string) (string, string) {
|
|
parts := strings.Split(t, ".")
|
|
if len(parts) == 2 {
|
|
return parts[0], parts[1]
|
|
}
|
|
return t, ""
|
|
}
|