feat: new parser & generator

This commit is contained in:
2025-03-09 13:12:12 +07:00
parent 70fc3345d8
commit a3283b9a57
25 changed files with 372 additions and 301 deletions

View File

@@ -1,15 +0,0 @@
package utils
import "strings"
func ContainsMany(str string, substrings ...string) bool {
var matches int
for _, substr := range substrings {
if strings.Contains(str, substr) {
matches++
} else {
return false
}
}
return matches == len(substrings)
}

14
utils/get_models_path.go Normal file
View File

@@ -0,0 +1,14 @@
package utils
import (
"log"
"os"
)
func GetModelsPath() string {
if len(os.Args) == 1 {
log.Fatalf("Please provide path to models.go")
}
return os.Args[1]
}

View File

@@ -1,11 +0,0 @@
package utils
func GetNotImplementedStructs(modelsFilePath string) []string {
var models []string
for _, model := range GetStructsList(modelsFilePath) {
if !IsEntityImplemented(model) {
models = append(models, model)
}
}
return models
}

View File

@@ -1,40 +0,0 @@
package utils
import (
"bufio"
"log"
"nto_cli/entities"
"os"
"strings"
)
func GetStructFields(file *os.File, structName string) []entities.Field {
bracketsCount := 1
var structFound bool
var structFields []entities.Field
scanner := bufio.NewScanner(file)
for i := 1; scanner.Scan() && bracketsCount > 0; i++ {
line := scanner.Text()
if ContainsMany(line, structName, "type", "struct") {
structFound = true
}
if structFound {
bracketsCount += strings.Count(line, "{")
bracketsCount -= strings.Count(line, "}")
line = strings.TrimSpace(line)
newField, err := SplitStructField(line)
if err != nil {
return structFields
}
if newField != nil {
structFields = append(structFields, *newField)
}
}
}
if err := scanner.Err(); err != nil {
log.Fatalf("Failed to read file with scanner: %s", err)
}
return structFields
}

View File

@@ -1,36 +0,0 @@
package utils
import (
"bufio"
"log"
"os"
"strings"
)
func GetStructsList(modelsFilePath string) []string {
file, err := os.Open(modelsFilePath)
defer file.Close()
if err != nil {
log.Fatalf("Failed to open a file: %s", err)
}
var structNames []string
s := bufio.NewScanner(file)
for s.Scan() {
line := s.Text()
if strings.Contains(line, "type ") && strings.Contains(line, " struct") {
start := strings.Index(line, "type ") + 5
end := strings.Index(line, " struct")
name := strings.TrimSpace(line[start:end])
if name != "" {
structNames = append(structNames, name)
}
}
}
if s.Err() != nil {
log.Fatalf("Unexpected scanner error: %s", err)
}
return structNames
}

View File

@@ -0,0 +1,63 @@
package utils
import "go/ast"
var primitives = map[string]bool{
"bool": true,
"string": true,
"int": true,
"int8": true,
"int16": true,
"int32": true,
"int64": true,
"uint": true,
"uint8": true,
"uint16": true,
"uint32": true,
"uint64": true,
"uintptr": true,
"byte": true,
"rune": true,
"float32": true,
"float64": true,
"complex64": true,
"complex128": true,
}
func IsPrimitiveType(expr ast.Expr) bool {
if ident, ok := expr.(*ast.Ident); ok {
return primitives[ident.Name]
}
if _, ok := expr.(*ast.ArrayType); ok {
// Arrays and slices are not primitives
return false
}
if _, ok := expr.(*ast.MapType); ok {
// Maps are not primitives
return false
}
if _, ok := expr.(*ast.ChanType); ok {
// Channels are not primitives
return false
}
if _, ok := expr.(*ast.StructType); ok {
// Structs are not primitives
return false
}
if _, ok := expr.(*ast.StarExpr); ok {
// Handle pointers
return IsPrimitiveType(expr.(*ast.StarExpr).X)
}
if _, ok := expr.(*ast.SelectorExpr); ok {
// Handle selector expressions (like pkg.Type)
return false
}
return false
}

11
utils/is_slice.go Normal file
View File

@@ -0,0 +1,11 @@
package utils
import "go/ast"
func IsSlice(expr ast.Expr) bool {
arrayType, ok := expr.(*ast.ArrayType)
if !ok {
return false
}
return arrayType.Len == nil
}

View File

@@ -0,0 +1,21 @@
package utils
import (
"go/ast"
)
func ResolveBaseType(expr ast.Expr) *string {
switch e := expr.(type) {
case *ast.Ident:
return &e.Name
case *ast.StarExpr:
return ResolveBaseType(e.X)
case *ast.ArrayType:
return ResolveBaseType(e.Elt)
case *ast.SelectorExpr:
return ResolveBaseType(e.X)
case *ast.ParenExpr:
return ResolveBaseType(e.X)
}
return nil
}

View File

@@ -1,14 +0,0 @@
package utils
import "strings"
func SplitBySingleSpace(input string) []string {
parts := strings.Split(strings.TrimSpace(input), " ")
var result []string
for _, p := range parts {
if p != "" {
result = append(result, p)
}
}
return result
}

View File

@@ -1,59 +0,0 @@
package utils
import (
"errors"
"log"
"nto_cli/entities"
"strings"
"github.com/fatih/structtag"
)
func SplitStructField(field string) (*entities.Field, error) {
if strings.Contains(field, "type") {
return nil, nil
}
if len(strings.TrimSpace(field)) < 2 {
return nil, errors.New("unexpected end of struct field")
}
startBacktick := strings.Index(field, "`")
endBacktick := -1
var metadata []entities.Metadata
if startBacktick > -1 {
endBacktick = strings.Index(field[startBacktick+1:], "`")
if endBacktick > -1 {
endBacktick += startBacktick + 1
structTag := field[startBacktick+1 : endBacktick]
tags, err := structtag.Parse(structTag)
if err != nil {
log.Fatalf("failed to parse struct tag: %s", err)
}
if uiTag, e := tags.Get("ui"); e == nil {
uiTags := append([]string{uiTag.Name}, uiTag.Options...)
for _, t := range uiTags {
analyzed := entities.NewMetadata(t)
if analyzed != nil {
metadata = append(metadata, *analyzed)
}
}
}
}
} else {
startBacktick = len(field)
}
field = strings.TrimSpace(field[:startBacktick])
data := SplitBySingleSpace(field)
name := data[0]
dataType := data[1]
return &entities.Field{
Metadata: metadata,
Type: dataType,
Name: name,
}, nil
}