mirror of
https://github.com/0xJacky/nginx-ui.git
synced 2025-05-10 18:05:48 +02:00
289 lines
7.6 KiB
Go
289 lines
7.6 KiB
Go
//go:generate go run .
|
|
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"go/ast"
|
|
"go/parser"
|
|
"go/token"
|
|
"os"
|
|
"path/filepath"
|
|
"regexp"
|
|
"runtime"
|
|
"sort"
|
|
"strings"
|
|
"text/template"
|
|
|
|
"github.com/uozi-tech/cosy/logger"
|
|
)
|
|
|
|
// Structure to hold extracted notifier information
|
|
type NotifierInfo struct {
|
|
Name string
|
|
Fields []FieldInfo
|
|
FileName string
|
|
ConfigKey string
|
|
}
|
|
|
|
// Structure to hold field information for notifier
|
|
type FieldInfo struct {
|
|
Name string
|
|
Key string
|
|
Title string
|
|
}
|
|
|
|
// Template for the TypeScript config file
|
|
const tsConfigTemplate = `// This file is auto-generated by notification generator. DO NOT EDIT.
|
|
import type { ExternalNotifyConfig } from './types'
|
|
|
|
const {{.Name | replaceSpaces}}Config: ExternalNotifyConfig = {
|
|
name: () => $gettext('{{.Name}}'),
|
|
config: [
|
|
{{- range .Fields}}
|
|
{
|
|
key: '{{.Key}}',
|
|
label: '{{.Title}}',
|
|
},
|
|
{{- end}}
|
|
],
|
|
}
|
|
|
|
export default {{.Name | replaceSpaces}}Config
|
|
`
|
|
|
|
// Regular expression to extract @external_notifier annotation
|
|
var externalNotifierRegex = regexp.MustCompile(`@external_notifier\(([a-zA-Z0-9 _]+)\)`)
|
|
|
|
func main() {
|
|
logger.Init("release")
|
|
|
|
_, file, _, ok := runtime.Caller(0)
|
|
if !ok {
|
|
logger.Error("Unable to get the current file")
|
|
return
|
|
}
|
|
basePath := filepath.Join(filepath.Dir(file), "../../")
|
|
if err := GenerateExternalNotifiers(basePath); err != nil {
|
|
fmt.Printf("error generating external notifier configs: %v\n", err)
|
|
}
|
|
}
|
|
|
|
// GenerateExternalNotifiers generates TypeScript config files for external notifiers
|
|
func GenerateExternalNotifiers(root string) error {
|
|
fmt.Println("Generating external notifier configs...")
|
|
|
|
// Notification package path
|
|
notificationPkgPath := filepath.Join(root, "internal/notification")
|
|
outputDir := filepath.Join(root, "app/src/views/preference/components/ExternalNotify")
|
|
|
|
// Create output directory if it doesn't exist
|
|
if err := os.MkdirAll(outputDir, 0755); err != nil {
|
|
return fmt.Errorf("error creating output directory: %w", err)
|
|
}
|
|
|
|
// Get all Go files in the notification package
|
|
files, err := filepath.Glob(filepath.Join(notificationPkgPath, "*.go"))
|
|
if err != nil {
|
|
return fmt.Errorf("error scanning notification package: %w", err)
|
|
}
|
|
|
|
// Collect all notifier info
|
|
notifiers := []NotifierInfo{}
|
|
|
|
for _, file := range files {
|
|
notifier, found := extractNotifierInfo(file)
|
|
if found {
|
|
notifiers = append(notifiers, notifier)
|
|
logger.Infof("Found notifier: %s in %s\n", notifier.Name, file)
|
|
}
|
|
}
|
|
|
|
// Generate TypeScript config files
|
|
for _, notifier := range notifiers {
|
|
if err := generateTSConfig(notifier, outputDir); err != nil {
|
|
return fmt.Errorf("error generating config for %s: %w", notifier.Name, err)
|
|
}
|
|
}
|
|
|
|
// Update index.ts
|
|
if err := updateIndexFile(notifiers, outputDir); err != nil {
|
|
return fmt.Errorf("error updating index.ts: %w", err)
|
|
}
|
|
|
|
logger.Info("Generation completed successfully!")
|
|
return nil
|
|
}
|
|
|
|
// Extract notifier information from a Go file
|
|
func extractNotifierInfo(filePath string) (NotifierInfo, bool) {
|
|
// Create the FileSet
|
|
fset := token.NewFileSet()
|
|
|
|
// Parse the file
|
|
file, err := parser.ParseFile(fset, filePath, nil, parser.ParseComments)
|
|
if err != nil {
|
|
logger.Errorf("Error parsing file %s: %v\n", filePath, err)
|
|
return NotifierInfo{}, false
|
|
}
|
|
|
|
var notifierInfo NotifierInfo
|
|
found := false
|
|
|
|
// Look for the type declaration with the @external_notifier annotation
|
|
for _, decl := range file.Decls {
|
|
genDecl, ok := decl.(*ast.GenDecl)
|
|
if !ok || genDecl.Tok != token.TYPE {
|
|
continue
|
|
}
|
|
|
|
for _, spec := range genDecl.Specs {
|
|
typeSpec, ok := spec.(*ast.TypeSpec)
|
|
if !ok {
|
|
continue
|
|
}
|
|
|
|
structType, ok := typeSpec.Type.(*ast.StructType)
|
|
if !ok {
|
|
continue
|
|
}
|
|
|
|
// Check if we have a comment with @external_notifier
|
|
if genDecl.Doc != nil {
|
|
for _, comment := range genDecl.Doc.List {
|
|
matches := externalNotifierRegex.FindStringSubmatch(comment.Text)
|
|
if len(matches) > 1 {
|
|
notifierInfo.Name = matches[1]
|
|
notifierInfo.ConfigKey = strings.ToLower(typeSpec.Name.Name)
|
|
notifierInfo.FileName = strings.ToLower(strings.ReplaceAll(matches[1], " ", "_"))
|
|
found = true
|
|
|
|
// Extract fields
|
|
for _, field := range structType.Fields.List {
|
|
if len(field.Names) > 0 {
|
|
fieldName := field.Names[0].Name
|
|
|
|
// Get json tag and title from field tags
|
|
var jsonKey, title string
|
|
if field.Tag != nil {
|
|
tagValue := strings.Trim(field.Tag.Value, "`")
|
|
|
|
// Extract json key
|
|
jsonRegex := regexp.MustCompile(`json:"([^"]+)"`)
|
|
jsonMatches := jsonRegex.FindStringSubmatch(tagValue)
|
|
if len(jsonMatches) > 1 {
|
|
jsonKey = jsonMatches[1]
|
|
}
|
|
|
|
// Extract title
|
|
titleRegex := regexp.MustCompile(`title:"([^"]+)"`)
|
|
titleMatches := titleRegex.FindStringSubmatch(tagValue)
|
|
if len(titleMatches) > 1 {
|
|
title = titleMatches[1]
|
|
}
|
|
}
|
|
|
|
if jsonKey == "" {
|
|
jsonKey = strings.ToLower(fieldName)
|
|
}
|
|
|
|
if title == "" {
|
|
title = fieldName
|
|
}
|
|
|
|
notifierInfo.Fields = append(notifierInfo.Fields, FieldInfo{
|
|
Name: fieldName,
|
|
Key: jsonKey,
|
|
Title: title,
|
|
})
|
|
}
|
|
}
|
|
break
|
|
}
|
|
}
|
|
}
|
|
|
|
if found {
|
|
break
|
|
}
|
|
}
|
|
|
|
if found {
|
|
break
|
|
}
|
|
}
|
|
|
|
return notifierInfo, found
|
|
}
|
|
|
|
// Generate TypeScript config file for a notifier
|
|
func generateTSConfig(notifier NotifierInfo, outputDir string) error {
|
|
// Create function map for template
|
|
funcMap := template.FuncMap{
|
|
"replaceSpaces": func(s string) string {
|
|
return strings.ReplaceAll(s, " ", "")
|
|
},
|
|
}
|
|
|
|
// Create template with function map
|
|
tmpl, err := template.New("tsConfig").Funcs(funcMap).Parse(tsConfigTemplate)
|
|
if err != nil {
|
|
return fmt.Errorf("error creating template: %w", err)
|
|
}
|
|
|
|
// Create output file
|
|
outputFile := filepath.Join(outputDir, notifier.FileName+".ts")
|
|
file, err := os.Create(outputFile)
|
|
if err != nil {
|
|
return fmt.Errorf("error creating output file %s: %w", outputFile, err)
|
|
}
|
|
defer file.Close()
|
|
|
|
// Execute template
|
|
err = tmpl.Execute(file, notifier)
|
|
if err != nil {
|
|
return fmt.Errorf("error executing template: %w", err)
|
|
}
|
|
|
|
logger.Infof("Generated TypeScript config for %s at %s\n", notifier.Name, outputFile)
|
|
return nil
|
|
}
|
|
|
|
// Update index.ts file
|
|
func updateIndexFile(notifiers []NotifierInfo, outputDir string) error {
|
|
// Create content for index.ts
|
|
var imports strings.Builder
|
|
var configMap strings.Builder
|
|
|
|
// Sort notifiers alphabetically by name for stable output
|
|
sort.Slice(notifiers, func(i, j int) bool {
|
|
return notifiers[i].Name < notifiers[j].Name
|
|
})
|
|
|
|
for _, notifier := range notifiers {
|
|
fileName := notifier.FileName
|
|
configName := strings.ReplaceAll(notifier.Name, " ", "") + "Config"
|
|
|
|
imports.WriteString(fmt.Sprintf("import %s from './%s'\n", configName, fileName))
|
|
}
|
|
|
|
// Generate the map
|
|
configMap.WriteString("const configMap = {\n")
|
|
for _, notifier := range notifiers {
|
|
configKey := strings.ToLower(strings.ReplaceAll(notifier.Name, " ", "_"))
|
|
configMap.WriteString(fmt.Sprintf(" %s: %sConfig", configKey, strings.ReplaceAll(notifier.Name, " ", "")))
|
|
configMap.WriteString(",\n")
|
|
}
|
|
configMap.WriteString("}\n")
|
|
|
|
content := fmt.Sprintf("// This file is auto-generated by notification generator. DO NOT EDIT.\n%s\n%s\nexport default configMap\n", imports.String(), configMap.String())
|
|
|
|
// Write to index.ts
|
|
indexPath := filepath.Join(outputDir, "index.ts")
|
|
err := os.WriteFile(indexPath, []byte(content), 0644)
|
|
if err != nil {
|
|
return fmt.Errorf("error writing index.ts: %w", err)
|
|
}
|
|
|
|
logger.Infof("Updated index.ts at %s\n", indexPath)
|
|
return nil
|
|
}
|