mirror of
https://github.com/opbnq-q/nto-cli.git
synced 2025-12-06 16:30:33 +07:00
feat: new parser & generator
This commit is contained in:
@@ -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
14
utils/get_models_path.go
Normal 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]
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
63
utils/is_primitive_type.go
Normal file
63
utils/is_primitive_type.go
Normal 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
11
utils/is_slice.go
Normal 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
|
||||
}
|
||||
21
utils/resolve_base_type.go
Normal file
21
utils/resolve_base_type.go
Normal 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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
Reference in New Issue
Block a user