Compare commits

15 Commits

5 changed files with 471 additions and 115 deletions

437
class.go
View File

@@ -3,14 +3,15 @@ package main
import ( import (
_ "embed" _ "embed"
"fmt" "fmt"
"io"
"log" "log"
"os" "os"
"path/filepath" "path/filepath"
"regexp"
"strings" "strings"
"text/template" "text/template"
"github.com/PuerkitoBio/goquery" "github.com/PuerkitoBio/goquery"
"github.com/davecgh/go-spew/spew"
) )
//go:embed class.tmpl //go:embed class.tmpl
@@ -35,6 +36,7 @@ func init() {
type ( type (
Class struct { Class struct {
ClassName string ClassName string
Description string
Fields []Field Fields []Field
Methods []Method Methods []Method
Constructors []Constructor Constructors []Constructor
@@ -61,6 +63,7 @@ type (
} }
Constructor struct { Constructor struct {
Params []Param Params []Param
Returns string
Comment string Comment string
} }
) )
@@ -76,6 +79,7 @@ func (c *Class) GetOutFile(root string) (*os.File, error) {
filename = strings.ReplaceAll(filename, ":", "") filename = strings.ReplaceAll(filename, ":", "")
filePath := filepath.Join(root, filename) filePath := filepath.Join(root, filename)
filePath = filepath.Clean(filePath) filePath = filepath.Clean(filePath)
log.Printf("Writing file to '%s'", filePath)
f, err := os.Create(filePath) f, err := os.Create(filePath)
if err != nil { if err != nil {
return nil, err return nil, err
@@ -88,6 +92,7 @@ func (c *Class) Write(root string, tmpl *template.Template) error {
if err != nil { if err != nil {
return fmt.Errorf("error creating output file %v: %v", c.ClassName, err) return fmt.Errorf("error creating output file %v: %v", c.ClassName, err)
} }
// spew.Dump(c)
err = tmpl.Execute(outfile, c) err = tmpl.Execute(outfile, c)
if err != nil { if err != nil {
return fmt.Errorf("error writing output file %v: %v", c.ClassName, err) return fmt.Errorf("error writing output file %v: %v", c.ClassName, err)
@@ -95,14 +100,26 @@ func (c *Class) Write(root string, tmpl *template.Template) error {
return nil return nil
} }
func ParseClass(file string) (*Class, error) { type ClassParser struct {
log.Printf("Parsing file: '%s'", file) log *log.Logger
inputfile string
}
func NewClassParser(file string) *ClassParser {
return &ClassParser{
log: log.New(io.MultiWriter(os.Stdout, os.Stderr), fmt.Sprintf("%s[ClassParser] %s%s", GenerateRandomAnsiColor(), file, Reset), log.Lmicroseconds|log.Lshortfile),
inputfile: file,
}
}
func (p *ClassParser) Parse() (*Class, error) {
p.log.Printf("Parsing file: '%s'", p.inputfile)
res := Class{ res := Class{
Fields: []Field{}, Fields: []Field{},
Methods: []Method{}, Methods: []Method{},
Constructors: []Constructor{}, Constructors: []Constructor{},
} }
filehandle, err := os.Open(file) filehandle, err := os.Open(p.inputfile)
if err != nil { if err != nil {
return nil, fmt.Errorf("error opening file: %w", err) return nil, fmt.Errorf("error opening file: %w", err)
} }
@@ -112,127 +129,365 @@ func ParseClass(file string) (*Class, error) {
if err != nil { if err != nil {
return nil, fmt.Errorf("error parsing file: %w", err) return nil, fmt.Errorf("error parsing file: %w", err)
} }
p.log.Printf("Document loaded")
class := doc.Find("div.floatright > h1") dataContainer := doc.Find("div.floatright")
if class.Length() == 0 { if dataContainer.Length() == 0 {
return nil, fmt.Errorf("no class found") return nil, fmt.Errorf("no data container found")
} }
res.ClassName = strings.TrimSpace(class.Text()) p.log.Printf("Data container found")
res.Constructors, err = getConstructors(doc) className, err := p.getClassName(dataContainer)
if err != nil { if err != nil {
return nil, fmt.Errorf("error getting constructors: %w", err) return nil, fmt.Errorf("error getting class name: %w", err)
}
res.ClassName = className
p.log.Printf("Class name resolved as '%s'", res.ClassName)
classDescription, err := p.getClassDescription(dataContainer)
if err == nil {
// return nil, fmt.Errorf("error getting class description: %w", err)
res.Description = classDescription
p.log.Printf("Class description resolved as '%s'", res.Description)
} }
res.Fields, err = getFields(doc) constructor, err := p.getConstructor(dataContainer)
if err != nil { if err != nil {
return nil, fmt.Errorf("error getting fields: %w", err) return nil, fmt.Errorf("error getting constructor: %w", err)
} }
res.Constructors = append(res.Constructors, constructor)
p.log.Printf("Constructor resolved")
res.Methods, err = getMethods(doc) // Doing div+div specifically skips only the constructor which is usually the first div
if err != nil { // So the constructor would then be located at h1 + p + div OR h1 + div if there is no description (no p)
return nil, fmt.Errorf("error getting methods: %w", err) dataElements := dataContainer.ChildrenFiltered("div + div")
if dataElements.Length() == 0 {
return nil, fmt.Errorf("no data elements found")
} }
p.log.Printf("Data elements (%d) found", dataElements.Length())
// spew.Dump(res) dataElements.Each(func(i int, s *goquery.Selection) {
id, ok := s.Attr("id")
if !ok {
return
}
if id == "Properties" {
s.Children().Each(func(i int, s *goquery.Selection) {
p.log.Printf("Parsing field")
field, err := p.parseField(s)
if err != nil {
Error.Printf("Error parsing field: %v", err)
return
}
res.Fields = append(res.Fields, field)
})
} else {
p.log.Printf("Parsing method")
method, err := p.parseMethod(s)
if err != nil {
Error.Printf("Error parsing method: %v", err)
return
}
res.Methods = append(res.Methods, method)
}
})
p.log.Printf("Class parsed")
return &res, nil return &res, nil
} }
// TODO: Implement parsing comments for return values func (p *ClassParser) getClassName(dataContainer *goquery.Selection) (string, error) {
// Something like "---returns (something) -> comment" p.log.Printf("Getting class name")
// Where "-> comment" is only shown if there's a comment class := dataContainer.ChildrenFiltered("h1")
// And "---returns" only if there's a return type if class.Length() == 0 {
// This is NOT a luals annotation because we can not use annotations on @overload return "", fmt.Errorf("no class found")
// But just a regular plain Lua comment }
// TODO: Implement parsing comments for classes and constructors res := CleanUp(class.Text())
func getConstructors(doc *goquery.Document) ([]Constructor, error) { p.log.Printf("Class name resolved as '%s'", res)
res := []Constructor{} return res, nil
}
codeblocks := doc.Find("div.floatright > div.codecontainer") var manySpaceRe = regexp.MustCompile(`\s{2,}`)
if codeblocks.Length() == 0 {
return res, fmt.Errorf("no codeblocks found") func (p *ClassParser) getClassDescription(dataContainer *goquery.Selection) (string, error) {
p.log.Printf("Getting class description")
class := dataContainer.ChildrenFiltered("h1 + p")
if class.Length() == 0 {
return "", fmt.Errorf("no class description found")
}
res := CleanUp(class.Text())
p.log.Printf("Class description resolved as '%s'", res)
return res, nil
}
func (p *ClassParser) getConstructor(dataContainer *goquery.Selection) (Constructor, error) {
resConstructor := Constructor{}
p.log.Printf("Getting constructor")
constructorBlock := dataContainer.Find("h1 + p + div")
if constructorBlock.Length() == 0 {
p.log.Printf("No constructor block found, trying fallback (h1 + div)")
constructorBlock = dataContainer.Find("h1 + div")
if constructorBlock.Length() == 0 {
return resConstructor, fmt.Errorf("no constructor found")
}
p.log.Printf("Fallback constructor block found")
} }
// The first code block should be the constructor types := constructorBlock.Find("div.function span.type")
// So far I have not found any classes with overloaded constructors... if types.Length() == 0 {
// So I can not handle that case yet return resConstructor, fmt.Errorf("no types found")
constructorBlock := codeblocks.Eq(0) }
constructor := constructorBlock.Find("div.function") p.log.Printf("Constructor types found")
paramTypes := constructor.Find("span.type") params := constructorBlock.Find("div.function span.parameter")
paramNames := constructor.Find("span.parameter") if params.Length() == 0 {
return resConstructor, fmt.Errorf("no params found")
resConstructor := Constructor{} }
paramTypes.Each(func(i int, s *goquery.Selection) { p.log.Printf("Constructor params found")
pname := strings.TrimSpace(paramNames.Eq(i).Text())
ptype := strings.TrimSpace(paramTypes.Eq(i).Text())
ptype = MapType(ptype)
types.Each(func(i int, s *goquery.Selection) {
resConstructor.Params = append(resConstructor.Params, Param{ resConstructor.Params = append(resConstructor.Params, Param{
Name: pname, Name: CleanUp(params.Eq(i).Text()),
Type: ptype, Type: MapType(CleanUp(types.Eq(i).Text())),
Comment: "", Comment: "",
}) })
}) })
p.log.Printf("Constructor params resolved")
constructorDetails := constructorBlock.Children().Eq(1) descriptor := constructorBlock.Find("div:not(.function)")
constructorParameterDetails := constructorDetails.Find("span.parameter") if descriptor.Length() == 0 {
constructorParameterDetails.Each(func(i int, s *goquery.Selection) { return resConstructor, fmt.Errorf("no descriptor found")
param := strings.TrimSpace(s.Text()) }
parameterParent := s.Parent() p.log.Printf("Constructor descriptor found")
parameterDescription := parameterParent.Text()
parameterDescription = strings.ReplaceAll(parameterDescription, fmt.Sprintf("\n%s\n", param), "")
parameterDescription = strings.TrimSpace(parameterDescription)
resConstructor.Params[i].Comment = parameterDescription
})
constructorBlock.Find("div:not(.function):not(.indented) > p:not(:has(*))").Each(func(i int, s *goquery.Selection) { // 0 nothing
resConstructor.Comment += strings.TrimSpace(s.Text()) + "\n" // 1 parameters
resConstructor.Comment = strings.TrimSpace(resConstructor.Comment) // 2 returns
}) state := 0
children := descriptor.Eq(0).Children()
spew.Dump(resConstructor) childrenLength := children.Length()
return append(res, resConstructor), nil children.Each(func(i int, s *goquery.Selection) {
} if i == childrenLength-1 {
// For some stupid reason the last child is always a mispalced </p> tag that does not close any open <p>
func getFields(doc *goquery.Document) ([]Field, error) { // I assume this is a bug with their documentation generator
res := []Field{} // So we just ignore it
properties := doc.Find("div.floatright > div.codecontainer#Properties") return
properties.ChildrenFiltered("div").Each(func(i int, s *goquery.Selection) { }
property := Field{} text := CleanUp(s.Text())
property.Name = strings.TrimSpace(s.Find("span.property").Text()) if text == "" {
property.Type = strings.TrimSpace(s.Find("span.type").Text()) return
property.Type = MapType(property.Type) }
comment := s.Find("td[align='right']").Text() if s.Is("p") {
if comment != "" { switch text {
property.Comment = strings.TrimSpace(comment) case "Parameters":
state = 1
return
case "Returns":
state = 2
return
}
} else {
switch state {
case 0:
return
case 1:
param := s.ChildrenFiltered("span.parameter").Text()
paramTrimmed := CleanUp(param)
p.log.Printf("Parameter '%s' found", paramTrimmed)
for i := range resConstructor.Params {
cparam := &resConstructor.Params[i]
if paramTrimmed == cparam.Name {
cleanText := strings.TrimPrefix(text, param)
cparam.Comment = CleanUp(cleanText)
}
}
case 2:
cleaned := CleanUp(s.Text())
p.log.Printf("Return value '%s' found", cleaned)
if resConstructor.Returns != "" {
resConstructor.Returns += "\n"
}
resConstructor.Returns = cleaned
}
} }
res = append(res, property)
}) })
p.log.Printf("Constructor resolved")
// spew.Dump(resConstructor)
return resConstructor, nil
}
func (p *ClassParser) parseField(s *goquery.Selection) (Field, error) {
res := Field{}
p.log.Printf("Parsing field")
id, ok := s.Attr("id")
if !ok {
return res, fmt.Errorf("no id found")
}
res.Name = id
p.log.Printf("Field name resolved as '%s'", res.Name)
typeElement := s.Find("span.type")
if typeElement.Length() == 0 {
return res, fmt.Errorf("no type found")
}
res.Type = MapType(CleanUp(typeElement.Text()))
p.log.Printf("Field type resolved as '%s'", res.Type)
readonlyElement := s.Find("td[align='right']")
if readonlyElement.Length() != 0 {
// return res, fmt.Errorf("no readonly found")
res.Comment = CleanUp(readonlyElement.Text())
p.log.Printf("Field comment resolved as '%s'", res.Comment)
}
comments := s.ChildrenFiltered("div")
if comments.Length() == 0 {
return res, fmt.Errorf("no comments found")
}
comments.Each(func(i int, s *goquery.Selection) {
text := CleanUp(s.Text())
if text == "" {
return
}
p.log.Printf("Field comment resolved as '%s'", text)
if res.Comment != "" {
res.Comment += ". "
}
res.Comment += text
})
res.Comment = strings.ReplaceAll(res.Comment, "\n--", ". ")
p.log.Printf("Field resolved")
return res, nil return res, nil
} }
// TODO: Implement parsing return value types and comments func (p *ClassParser) parseMethod(s *goquery.Selection) (Method, error) {
func getMethods(doc *goquery.Document) ([]Method, error) { res := Method{}
res := []Method{} p.log.Printf("Parsing method")
codeblocks := doc.Find("div.floatright > div.codecontainer") id, ok := s.Attr("id")
codeblocks.ChildrenFiltered("div.function").Each(func(i int, s *goquery.Selection) { if !ok {
method := Method{} return res, fmt.Errorf("no id found")
method.Name = strings.TrimSpace(s.AttrOr("id", "")) }
method.Comment = strings.TrimSpace(s.Find("span.comment").Text()) res.Name = id
p.log.Printf("Method name resolved as '%s'", res.Name)
types := s.Find("span.type") signatureData := s.Children().Eq(0)
parameters := s.Find("span.parameter") returns := signatureData.Find("span.keyword")
types.Each(func(i int, s *goquery.Selection) { if returns.Length() != 0 {
param := Param{} returnsText := CleanUp(returns.Text())
param.Name = strings.TrimSpace(parameters.Eq(i).Text()) returnsText = strings.ReplaceAll(returnsText, "function", "")
param.Type = strings.TrimSpace(types.Eq(i).Text()) returnsText = CleanUp(returnsText)
param.Type = MapType(param.Type)
method.Params = append(method.Params, param) res.Returns = append(res.Returns, Return{
Type: MapType(returnsText),
Comment: "",
}) })
p.log.Printf("Method return value resolved as '%s'", res.Returns[0].Type)
}
res = append(res, method) types := signatureData.Find("span.type")
parameters := signatureData.Find("span.parameter")
types.Each(func(i int, s *goquery.Selection) {
res.Params = append(res.Params, Param{
Name: MapName(CleanUp(parameters.Eq(i).Text())),
Type: MapType(CleanUp(types.Eq(i).Text())),
Comment: "",
})
p.log.Printf("Method parameter resolved as '%s'", res.Params[i].Name)
}) })
// 0 nothing
// 1 parameters
// 2 returns
state := 0
signatureDetails := s.Children().Eq(1)
signatureDetailsChildren := signatureDetails.Children()
signatureDetailsChildrenLength := signatureDetailsChildren.Length()
signatureDetailsChildren.Each(func(i int, s *goquery.Selection) {
if s.Is("p") && i == 0 {
methodDescription := CleanUp(s.Text())
methodDescription = strings.ReplaceAll(methodDescription, "\n--", "<br>\n\t---")
res.Comment = methodDescription
p.log.Printf("Method description resolved as '%s'", res.Comment)
}
if i == signatureDetailsChildrenLength-1 {
// For some stupid reason the last child is always a mispalced </p> tag that does not close any open <p>
// I assume this is a bug with their documentation generator
// So we just ignore it
return
}
text := CleanUp(s.Text())
if text == "" {
return
}
if s.Is("p") {
switch text {
case "Parameters":
state = 1
case "Returns":
state = 2
return
}
} else {
if s.Is("div.indented") {
if state == 1 {
parameter := ""
html, err := s.Html()
if err != nil {
Error.Printf("Error parsing html: %v", err)
return
}
html = strings.ReplaceAll(html, "\t", "")
htmlLines := strings.Split(html, "\n")
for _, line := range htmlLines {
if strings.Contains(line, "<span class=\"parameter\">") {
line = strings.TrimSpace(line)
line = strings.ReplaceAll(line, "<span class=\"parameter\">", "")
line = strings.ReplaceAll(line, "</span>", "")
parameter = line
p.log.Printf("Parameter '%s' found", parameter)
continue
}
if strings.Contains(line, "<br/>") {
comment := strings.TrimSpace(line)
comment = strings.ReplaceAll(comment, "<br/>", "")
for i := range res.Params {
if res.Params[i].Name == parameter {
res.Params[i].Comment = comment
p.log.Printf("Parameter '%s' comment resolved as '%s'", parameter, comment)
break
}
}
}
}
} else if state == 2 {
text := CleanUp(s.Text())
if text == "" {
return
}
p.log.Printf("Return value comment '%s' found", text)
// TODO: Figure out what to do when a function
if res.Returns[0].Comment != "" {
res.Returns[0].Comment += "\n"
}
res.Returns[0].Comment += text
}
}
}
})
p.log.Printf("Method resolved")
return res, nil return res, nil
} }
func CleanUp(s string) string {
s = strings.TrimSpace(s)
s = strings.ReplaceAll(s, "\t", " ")
s = strings.ReplaceAll(s, "\n", "")
s = manySpaceRe.ReplaceAllString(s, " ")
s = strings.ReplaceAll(s, ". ", "\n--")
return s
}

View File

@@ -1,5 +1,6 @@
---@diagnostic disable: missing-return, lowercase-global ---@diagnostic disable: missing-return, lowercase-global
---@class {{.ClassName}} ---@class {{.ClassName}}{{if ne .Description ""}}
---{{.Description}}{{end}}
{{- range .Fields}} {{- range .Fields}}
---@field {{.Name}} {{.Type}}{{if ne .Comment ""}} {{.Comment}}{{end}} ---@field {{.Name}} {{.Type}}{{if ne .Comment ""}} {{.Comment}}{{end}}
{{- end}} {{- end}}
@@ -12,11 +13,11 @@
{{- end}} {{- end}}
{{- range $ret := $method.Returns}} {{- range $ret := $method.Returns}}
---@return {{.Type}}{{if ne .Comment ""}} #{{.Comment}}{{end}} ---@return {{.Type}}{{if ne .Comment ""}} #{{.Comment}}{{end}}
{{- end}} {{- end}}{{if ne .Comment ""}}
---{{.Comment}}{{end}}
{{.Name}} = function(self{{if gt (len .Params) 0}}, {{range $index, $param := .Params}}{{if $index}}, {{end}}{{$param.Name}}{{end}}{{end}}) end, {{.Name}} = function(self{{if gt (len .Params) 0}}, {{range $index, $param := .Params}}{{if $index}}, {{end}}{{$param.Name}}{{end}}{{end}}) end,
{{- if ne (plus1 $index) $n}} {{- if ne (plus1 $index) $n}}
{{end}}
{{- end}}
{{- end}} {{- end}}
} }
@@ -26,7 +27,8 @@
{{- if ne .Comment ""}} {{- if ne .Comment ""}}
---{{.Name}} ({{.Type}}) -> {{.Comment}} ---{{.Name}} ({{.Type}}) -> {{.Comment}}
{{- end}} {{- end}}
{{- end}} {{- end}}{{if ne .Returns ""}}
---Returns {{.Returns}}{{end}}
---@overload fun({{range $index, $param := .Params}}{{if $index}}, {{end}}{{$param.Name}}: {{$param.Type}}{{end}}): {{$.ClassName}}{{- if ne .Comment ""}} ---@overload fun({{range $index, $param := .Params}}{{if $index}}, {{end}}{{$param.Name}}: {{$param.Type}}{{end}}): {{$.ClassName}}{{- if ne .Comment ""}}
---{{.Comment}} ---{{.Comment}}
{{- end}} {{- end}}

99
color.go Normal file
View File

@@ -0,0 +1,99 @@
package main
import (
"fmt"
"math/rand/v2"
)
const (
// Reset
Reset = "\033[0m" // Text Reset
// Regular Colors
Black = "\033[0;30m" // Black
Red = "\033[0;31m" // Red
Green = "\033[0;32m" // Green
Yellow = "\033[0;33m" // Yellow
Blue = "\033[0;34m" // Blue
Purple = "\033[0;35m" // Purple
Cyan = "\033[0;36m" // Cyan
White = "\033[0;37m" // White
// Bold
BBlack = "\033[1;30m" // Black
BRed = "\033[1;31m" // Red
BGreen = "\033[1;32m" // Green
BYellow = "\033[1;33m" // Yellow
BBlue = "\033[1;34m" // Blue
BPurple = "\033[1;35m" // Purple
BCyan = "\033[1;36m" // Cyan
BWhite = "\033[1;37m" // White
// Underline
UBlack = "\033[4;30m" // Black
URed = "\033[4;31m" // Red
UGreen = "\033[4;32m" // Green
UYellow = "\033[4;33m" // Yellow
UBlue = "\033[4;34m" // Blue
UPurple = "\033[4;35m" // Purple
UCyan = "\033[4;36m" // Cyan
UWhite = "\033[4;37m" // White
// Background
On_Black = "\033[40m" // Black
On_Red = "\033[41m" // Red
On_Green = "\033[42m" // Green
On_Yellow = "\033[43m" // Yellow
On_Blue = "\033[44m" // Blue
On_Purple = "\033[45m" // Purple
On_Cyan = "\033[46m" // Cyan
On_White = "\033[47m" // White
// High Intensty
IBlack = "\033[0;90m" // Black
IRed = "\033[0;91m" // Red
IGreen = "\033[0;92m" // Green
IYellow = "\033[0;93m" // Yellow
IBlue = "\033[0;94m" // Blue
IPurple = "\033[0;95m" // Purple
ICyan = "\033[0;96m" // Cyan
IWhite = "\033[0;97m" // White
// Bold High Intensty
BIBlack = "\033[1;90m" // Black
BIRed = "\033[1;91m" // Red
BIGreen = "\033[1;92m" // Green
BIYellow = "\033[1;93m" // Yellow
BIBlue = "\033[1;94m" // Blue
BIPurple = "\033[1;95m" // Purple
BICyan = "\033[1;96m" // Cyan
BIWhite = "\033[1;97m" // White
// High Intensty backgrounds
On_IBlack = "\033[0;100m" // Black
On_IRed = "\033[0;101m" // Red
On_IGreen = "\033[0;102m" // Green
On_IYellow = "\033[0;103m" // Yellow
On_IBlue = "\033[0;104m" // Blue
On_IPurple = "\033[10;95m" // Purple
On_ICyan = "\033[0;106m" // Cyan
On_IWhite = "\033[0;107m" // White
)
// The acceptable range is [16, 231] but here we remove some very dark colors
// That make text unreadable on a dark terminal
// See https://www.hackitu.de/termcolor256/
var colors = []int{22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 57, 62, 63, 64, 65, 67, 68, 69, 70, 71, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 148, 149, 150, 151, 152, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 184, 185, 186, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 226, 227, 228, 229, 230}
var colorsIndex int = -1
var shuffled bool
func GenerateRandomAnsiColor() string {
if !shuffled {
rand.Shuffle(len(colors), func(i int, j int) {
colors[i], colors[j] = colors[j], colors[i]
})
shuffled = true
}
colorsIndex++
return fmt.Sprintf("\033[1;4;38;5;%dm", colors[colorsIndex%len(colors)])
}

34
main.go
View File

@@ -6,6 +6,7 @@ import (
"io" "io"
"log" "log"
"os" "os"
"strings"
"sync" "sync"
"github.com/davecgh/go-spew/spew" "github.com/davecgh/go-spew/spew"
@@ -49,7 +50,8 @@ func main() {
wg.Add(1) wg.Add(1)
go func(file string) { go func(file string) {
defer wg.Done() defer wg.Done()
class, err := ParseClass(file) parser := NewClassParser(file)
class, err := parser.Parse()
if err != nil { if err != nil {
Error.Printf("Error parsing file: %v", err) Error.Printf("Error parsing file: %v", err)
return return
@@ -61,20 +63,18 @@ func main() {
} }
func MapType(t string) string { func MapType(t string) string {
switch t { t = strings.ReplaceAll(t, "var", "any")
case "var": t = strings.ReplaceAll(t, "int", "number")
return "any" t = strings.ReplaceAll(t, "unsigned", "")
case "int": t = strings.ReplaceAll(t, "float", "number")
return "number" t = strings.ReplaceAll(t, "double", "number")
case "float": t = strings.ReplaceAll(t, "bool", "boolean")
return "number" t = strings.ReplaceAll(t, "table_t", "table")
case "double": t = strings.ReplaceAll(t, "...", "[]")
return "number" return t
case "bool": }
return "boolean"
case "table_t": func MapName(s string) string {
return "table" s = strings.ReplaceAll(s, "in", "input")
default: return s
return t
}
} }

View File

@@ -207,7 +207,7 @@
<div id="CargoBay" class=""> <div id="CargoBay" class="">
<p><span class="docheader">Parameters</span></p> <p><span class="docheader">Parameters</span></p>
<div class="indented"> <div class="indented">
<span class="parameter">id</span> <span class="parameter">name</span>
The id of the entity this component belongs to, or the entity itself, must be an id of an The id of the entity this component belongs to, or the entity itself, must be an id of an
existing entity or nil for the entity in the current script context <br /> existing entity or nil for the entity in the current script context <br />
</div> </div>