Rewrite generator and update for Lemmy 0.18.3
This commit is contained in:
		
							
								
								
									
										192
									
								
								cmd/gen/extractor/extractor.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										192
									
								
								cmd/gen/extractor/extractor.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,192 @@
 | 
			
		||||
package extractor
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"os"
 | 
			
		||||
	"strings"
 | 
			
		||||
 | 
			
		||||
	"github.com/tidwall/gjson"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type Route struct {
 | 
			
		||||
	Name       string
 | 
			
		||||
	Summary    string
 | 
			
		||||
	Method     string
 | 
			
		||||
	Path       string
 | 
			
		||||
	ParamsName string
 | 
			
		||||
	ParamsID   int64
 | 
			
		||||
	ReturnName string
 | 
			
		||||
	ReturnID   int64
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type Struct struct {
 | 
			
		||||
	Name       string
 | 
			
		||||
	Fields     []Field
 | 
			
		||||
	UnionNames []string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type Field struct {
 | 
			
		||||
	Name       string
 | 
			
		||||
	IsArray    bool
 | 
			
		||||
	IsOptional bool
 | 
			
		||||
	Type       string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type Extractor struct {
 | 
			
		||||
	root gjson.Result
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func New(path string) (*Extractor, error) {
 | 
			
		||||
	data, err := os.ReadFile(path)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return &Extractor{gjson.ParseBytes(data)}, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (e *Extractor) Routes() []Route {
 | 
			
		||||
	var out []Route
 | 
			
		||||
	routes := e.root.Get("children.#.children.#(kind==2048)#|@flatten")
 | 
			
		||||
	for _, route := range routes.Array() {
 | 
			
		||||
		name := route.Get("name").String()
 | 
			
		||||
		signature := route.Get(`signatures.0`)
 | 
			
		||||
 | 
			
		||||
		httpInfo := signature.Get(`comment.summary.#(kind=="code").text`).String()
 | 
			
		||||
		if !strings.HasPrefix(httpInfo, "`HTTP") {
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
		method, path := parseHTTPInfo(httpInfo)
 | 
			
		||||
 | 
			
		||||
		summary := strings.TrimSpace(signature.Get(`comment.summary.#(kind=="text").text`).String())
 | 
			
		||||
		if summary == "" {
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		paramsID := signature.Get("parameters.0.type.target").Int()
 | 
			
		||||
		paramsName := signature.Get("parameters.0.type.name").String()
 | 
			
		||||
		returnID := signature.Get("type.typeArguments.0.target").Int()
 | 
			
		||||
		returnName := signature.Get("type.typeArguments.0.name").String()
 | 
			
		||||
 | 
			
		||||
		out = append(out, Route{
 | 
			
		||||
			Name:       name,
 | 
			
		||||
			Summary:    summary,
 | 
			
		||||
			Method:     method,
 | 
			
		||||
			Path:       path,
 | 
			
		||||
			ParamsName: paramsName,
 | 
			
		||||
			ParamsID:   paramsID,
 | 
			
		||||
			ReturnName: returnName,
 | 
			
		||||
			ReturnID:   returnID,
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
	return out
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (e *Extractor) Structs(routes []Route) []Struct {
 | 
			
		||||
	var ids []int64
 | 
			
		||||
	for _, route := range routes {
 | 
			
		||||
		ids = append(ids, route.ParamsID)
 | 
			
		||||
		if route.ReturnID != 0 {
 | 
			
		||||
			ids = append(ids, route.ReturnID)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	structs := map[int64]Struct{}
 | 
			
		||||
	e.getStructs(ids, structs)
 | 
			
		||||
	return getKeys(structs)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (e *Extractor) getStructs(ids []int64, structs map[int64]Struct) {
 | 
			
		||||
	for _, id := range ids {
 | 
			
		||||
		if _, ok := structs[id]; ok {
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		jstruct := e.root.Get(fmt.Sprintf("children.#(id==%d)", id))
 | 
			
		||||
		if !jstruct.Exists() {
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		name := jstruct.Get("name").String()
 | 
			
		||||
 | 
			
		||||
		if jstruct.Get("type.type").String() == "union" {
 | 
			
		||||
			structs[id] = Struct{
 | 
			
		||||
				Name:       name,
 | 
			
		||||
				UnionNames: e.unionNames(jstruct),
 | 
			
		||||
			}
 | 
			
		||||
		} else {
 | 
			
		||||
			fields, newIDs := e.fields(jstruct)
 | 
			
		||||
 | 
			
		||||
			structs[id] = Struct{
 | 
			
		||||
				Name:   name,
 | 
			
		||||
				Fields: fields,
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			e.getStructs(newIDs, structs)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (e *Extractor) unionNames(jstruct gjson.Result) []string {
 | 
			
		||||
	jnames := jstruct.Get("type.types").Array()
 | 
			
		||||
	out := make([]string, len(jnames))
 | 
			
		||||
	for i, name := range jnames {
 | 
			
		||||
		out[i] = name.Get("value").String()
 | 
			
		||||
	}
 | 
			
		||||
	return out
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (e *Extractor) fields(jstruct gjson.Result) ([]Field, []int64) {
 | 
			
		||||
	var fields []Field
 | 
			
		||||
	var ids []int64
 | 
			
		||||
	jfields := jstruct.Get("children").Array()
 | 
			
		||||
	for _, jfield := range jfields {
 | 
			
		||||
		var field Field
 | 
			
		||||
 | 
			
		||||
		field.Name = jfield.Get("name").String()
 | 
			
		||||
		field.IsOptional = jfield.Get("flags.isOptional").Bool()
 | 
			
		||||
 | 
			
		||||
		if jfield.Get("type.type").String() == "array" {
 | 
			
		||||
			field.IsArray = true
 | 
			
		||||
			field.Type = jfield.Get("type.elementType.name").String()
 | 
			
		||||
 | 
			
		||||
			switch jfield.Get("type.elementType.type").String() {
 | 
			
		||||
			case "reference":
 | 
			
		||||
				ids = append(ids, jfield.Get("type.elementType.target").Int())
 | 
			
		||||
			case "union":
 | 
			
		||||
				field.Type = "string"
 | 
			
		||||
			}
 | 
			
		||||
		} else {
 | 
			
		||||
			field.Type = jfield.Get("type.name").String()
 | 
			
		||||
 | 
			
		||||
			switch jfield.Get("type.type").String() {
 | 
			
		||||
			case "reference":
 | 
			
		||||
				ids = append(ids, jfield.Get("type.target").Int())
 | 
			
		||||
			case "union":
 | 
			
		||||
				field.Type = "string"
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		fields = append(fields, field)
 | 
			
		||||
	}
 | 
			
		||||
	return fields, ids
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func parseHTTPInfo(httpInfo string) (method, path string) {
 | 
			
		||||
	httpInfo = strings.Trim(httpInfo, "`")
 | 
			
		||||
	method, path, _ = strings.Cut(httpInfo, " ")
 | 
			
		||||
	method = strings.TrimPrefix(method, "HTTP.")
 | 
			
		||||
	method = strings.ToUpper(method)
 | 
			
		||||
	return method, path
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func getKeys(m map[int64]Struct) []Struct {
 | 
			
		||||
	out := make([]Struct, len(m))
 | 
			
		||||
	i := 0
 | 
			
		||||
	for _, s := range m {
 | 
			
		||||
		out[i] = s
 | 
			
		||||
		i++
 | 
			
		||||
	}
 | 
			
		||||
	return out
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user