Compare commits

...

2 Commits

Author SHA1 Message Date
a766f09f87 Implement construcor parameter parsing 2024-09-14 22:24:21 +02:00
acdfec2715 Rework class name and description parsing 2024-09-14 20:19:39 +02:00
3 changed files with 143 additions and 13 deletions

153
class.go
View File

@@ -6,6 +6,7 @@ import (
"log"
"os"
"path/filepath"
"regexp"
"strings"
"text/template"
@@ -35,6 +36,7 @@ func init() {
type (
Class struct {
ClassName string
Description string
Fields []Field
Methods []Method
Constructors []Constructor
@@ -113,31 +115,150 @@ func ParseClass(file string) (*Class, error) {
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")
dataContainer := doc.Find("div.floatright")
if dataContainer.Length() == 0 {
return nil, fmt.Errorf("no data container found")
}
res.ClassName = strings.TrimSpace(class.Text())
res.Constructors, err = getConstructors(doc)
className, err := getClassName(dataContainer)
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
res.Fields, err = getFields(doc)
classDescription, err := getClassDescription(dataContainer)
if err != nil {
return nil, fmt.Errorf("error getting fields: %w", err)
return nil, fmt.Errorf("error getting class description: %w", err)
}
res.Description = classDescription
res.Methods, err = getMethods(doc)
constructor, err := getConstructor(dataContainer)
if err != nil {
return nil, fmt.Errorf("error getting methods: %w", err)
return nil, fmt.Errorf("error getting constructor: %w", err)
}
constructor = constructor
// Doing div+div specifically skips only the constructor which is usually the first div
// So the constructor would then be located at h1 + p + div OR h1 + div if there is no description (no p)
dataElements := dataContainer.ChildrenFiltered("div + div")
if dataElements.Length() == 0 {
return nil, fmt.Errorf("no data elements found")
}
// spew.Dump(res)
dataElements.Each(func(i int, s *goquery.Selection) {
id, ok := s.Attr("id")
if !ok {
return
}
if id == "Properties" {
// TODO: Implement parsing properties
}
})
return &res, nil
}
func getClassName(dataContainer *goquery.Selection) (string, error) {
class := dataContainer.ChildrenFiltered("h1")
if class.Length() == 0 {
return "", fmt.Errorf("no class found")
}
res := strings.TrimSpace(class.Text())
return res, nil
}
var manySpaceRe = regexp.MustCompile(`\s{2,}`)
func getClassDescription(dataContainer *goquery.Selection) (string, error) {
class := dataContainer.ChildrenFiltered("h1 + p")
if class.Length() == 0 {
return "", fmt.Errorf("no class description found")
}
res := CleanUp(class.Text())
return res, nil
}
func getConstructor(dataContainer *goquery.Selection) (Constructor, error) {
resConstructor := Constructor{}
constructorBlock := dataContainer.Find("h1 + p + div")
if constructorBlock.Length() == 0 {
constructorBlock = dataContainer.Find("h1 + div")
if constructorBlock.Length() == 0 {
return resConstructor, fmt.Errorf("no constructor found")
}
}
types := constructorBlock.Find("div.function span.type")
if types.Length() == 0 {
return resConstructor, fmt.Errorf("no types found")
}
params := constructorBlock.Find("div.function span.parameter")
if params.Length() == 0 {
return resConstructor, fmt.Errorf("no params found")
}
types.Each(func(i int, s *goquery.Selection) {
resConstructor.Params = append(resConstructor.Params, Param{
Name: strings.TrimSpace(params.Eq(i).Text()),
Type: strings.TrimSpace(types.Eq(i).Text()),
Comment: "",
})
})
descriptor := constructorBlock.Find("div:not(.function)")
if descriptor.Length() == 0 {
return resConstructor, fmt.Errorf("no descriptor found")
}
// 0 nothing
// 1 parameters
// 2 returns
state := 0
children := descriptor.Children()
childrenLength := children.Length()
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>
// I assume this is a bug with their documentation generator
// So we just ignore it
return
}
text := strings.TrimSpace(s.Text())
if text == "" {
return
}
if s.Is("p") {
switch text {
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 := strings.TrimSpace(param)
for i := range resConstructor.Params {
cparam := &resConstructor.Params[i]
if paramTrimmed == cparam.Name {
cleanText := strings.TrimPrefix(text, param)
cparam.Comment = CleanUp(cleanText)
}
}
}
}
})
spew.Dump(resConstructor)
return resConstructor, nil
}
// TODO: Implement parsing comments for return values
// Something like "---returns (something) -> comment"
// Where "-> comment" is only shown if there's a comment
@@ -190,7 +311,6 @@ func getConstructors(doc *goquery.Document) ([]Constructor, error) {
resConstructor.Comment = strings.TrimSpace(resConstructor.Comment)
})
spew.Dump(resConstructor)
return append(res, resConstructor), nil
}
@@ -236,3 +356,12 @@ func getMethods(doc *goquery.Document) ([]Method, error) {
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
---@class {{.ClassName}}
---{{.Description}}
{{- range .Fields}}
---@field {{.Name}} {{.Type}}{{if ne .Comment ""}} {{.Comment}}{{end}}
{{- end}}

View File

@@ -207,7 +207,7 @@
<div id="CargoBay" class="">
<p><span class="docheader">Parameters</span></p>
<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
existing entity or nil for the entity in the current script context <br />
</div>