package main import ( "flag" "fmt" "io" "log" "os" "text/template" "github.com/PuerkitoBio/goquery" _ "embed" ) //go:embed class.tmpl var templatestr string var Error *log.Logger var Warning *log.Logger func init() { log.SetFlags(log.Lmicroseconds | log.Lshortfile) logger := io.MultiWriter(os.Stdout) log.SetOutput(logger) Error = log.New(io.MultiWriter(os.Stderr, os.Stdout), fmt.Sprintf("%sERROR:%s ", "\033[0;101m", "\033[0m"), log.Lmicroseconds|log.Lshortfile) Warning = log.New(io.MultiWriter(os.Stdout), fmt.Sprintf("%sWarning:%s ", "\033[0;93m", "\033[0m"), log.Lmicroseconds|log.Lshortfile) } var fns = template.FuncMap{ "plus1": func(x int) int { return x + 1 }, } func main() { flag.Parse() files := flag.Args() // if len(files) == 0 { // Error.Printf("No files specified") // flag.Usage() // return // } ltemplate, err := template.New("class").Funcs(fns).Parse(templatestr) if err != nil { Error.Printf("Error parsing template: %v", err) return } for _, file := range files { class, err := ParseFile(file) if err != nil { Error.Printf("Error parsing file: %v", err) continue } outfile, err := class.GetOutFile() if err != nil { Error.Printf("Error creating output file: %v", err) return } ltemplate.Execute(outfile, class) } } func ParseFile(filename string) (*Class, error) { log.Printf("Parsing file: '%s'", filename) res := Class{ Fields: []Field{}, Methods: []Method{}, Constructors: []Constructor{}, } file, err := os.Open(filename) if err != nil { return nil, fmt.Errorf("error opening file: %w", err) } defer file.Close() doc, err := goquery.NewDocumentFromReader(file) if err != nil { return nil, fmt.Errorf("error parsing file: %w", err) } class := doc.Find("div.floatright > h1") if class.Length() == 0 { return nil, fmt.Errorf("no class found") } res.ClassName = class.Text() codeblocks := doc.Find("div.floatright > div.codecontainer") if codeblocks.Length() == 0 { return nil, fmt.Errorf("no codeblocks found") } // The first code block should be the constructor // So far I have not found any classes with overloaded constructors... // So I can not handle that case yet constructorBlock := codeblocks.Eq(0) constructor := constructorBlock.Find("div.function") paramTypes := constructor.Find("span.type") paramNames := constructor.Find("span.parameter") resConstructor := Constructor{} paramTypes.Each(func(i int, s *goquery.Selection) { pname := paramNames.Eq(i).Text() ptype := paramTypes.Eq(i).Text() ptype = MapType(ptype) resConstructor.Params = append(resConstructor.Params, Param{ Name: pname, Type: ptype, Comment: "", }) }) res.Constructors = append(res.Constructors, resConstructor) // constructorDetails := codeblocks.Eq(1) log.Printf("%#v", res) return &res, nil } func MapType(t string) string { switch t { case "var": return "any" case "int": return "number" case "float": return "number" case "string": return "string" case "boolean": return "boolean" case "void": return "nil" default: return t } }