mirror of
https://github.com/opbnq-q/nto-cli.git
synced 2025-12-06 14:30:35 +07:00
3
.gitignore
vendored
3
.gitignore
vendored
@@ -2,4 +2,5 @@ main
|
||||
main.exe
|
||||
frontend
|
||||
task.py
|
||||
example
|
||||
example
|
||||
nto_cli
|
||||
8
.idea/.gitignore
generated
vendored
Normal file
8
.idea/.gitignore
generated
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
# Editor-based HTTP Client requests
|
||||
/httpRequests/
|
||||
# Datasource local storage ignored files
|
||||
/dataSources/
|
||||
/dataSources.local.xml
|
||||
8
.idea/modules.xml
generated
Normal file
8
.idea/modules.xml
generated
Normal file
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/nto-cli.iml" filepath="$PROJECT_DIR$/.idea/nto-cli.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
||||
9
.idea/nto-cli.iml
generated
Normal file
9
.idea/nto-cli.iml
generated
Normal file
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="WEB_MODULE" version="4">
|
||||
<component name="Go" enabled="true" />
|
||||
<component name="NewModuleRootManager">
|
||||
<content url="file://$MODULE_DIR$" />
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
||||
6
.idea/vcs.xml
generated
Normal file
6
.idea/vcs.xml
generated
Normal file
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
||||
@@ -2,6 +2,7 @@ package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"nto_cli/utils"
|
||||
"os"
|
||||
|
||||
@@ -16,16 +17,20 @@ func Input() (string, string) {
|
||||
}
|
||||
|
||||
func SelectionInput() ([]string, string) {
|
||||
if len(os.Args) == 1 {
|
||||
log.Fatalf("Please provide path to models.go")
|
||||
}
|
||||
|
||||
path := os.Args[1]
|
||||
|
||||
structNames := utils.GetStructList(path)
|
||||
|
||||
result := []string{}
|
||||
var result []string
|
||||
|
||||
app := tview.NewApplication()
|
||||
|
||||
form := tview.NewForm()
|
||||
checkboxes := []*tview.Checkbox{}
|
||||
var checkboxes []*tview.Checkbox
|
||||
|
||||
for _, name := range structNames {
|
||||
cb := tview.NewCheckbox().SetLabel(name)
|
||||
|
||||
@@ -9,44 +9,44 @@ import (
|
||||
type Field struct {
|
||||
Name string
|
||||
Type string
|
||||
Medatada []Medatada
|
||||
Medatada []Metadata
|
||||
}
|
||||
|
||||
var PRIMITIVE_TYPES = map[string]string{
|
||||
"date": "date",
|
||||
"number": "number",
|
||||
"string": "string",
|
||||
var PrimitiveTypes = map[string]string{
|
||||
"date": "date",
|
||||
"number": "number",
|
||||
"string": "string",
|
||||
"multiple": "multiple",
|
||||
"boolean": "boolean",
|
||||
"bool": "boolean",
|
||||
"int": "number",
|
||||
"uint": "number",
|
||||
"float32": "number",
|
||||
"float64": "number",
|
||||
"int32": "number",
|
||||
"int64": "number",
|
||||
"uint32": "number",
|
||||
"uint64": "number",
|
||||
"int8": "number",
|
||||
"int16": "number",
|
||||
"uint8": "number",
|
||||
"uint16": "number",
|
||||
"byte": "number",
|
||||
"rune": "number",
|
||||
"boolean": "boolean",
|
||||
"bool": "boolean",
|
||||
"int": "number",
|
||||
"uint": "number",
|
||||
"float32": "number",
|
||||
"float64": "number",
|
||||
"int32": "number",
|
||||
"int64": "number",
|
||||
"uint32": "number",
|
||||
"uint64": "number",
|
||||
"int8": "number",
|
||||
"int16": "number",
|
||||
"uint8": "number",
|
||||
"uint16": "number",
|
||||
"byte": "number",
|
||||
"rune": "number",
|
||||
}
|
||||
|
||||
func (f *Field) GenerateType() string {
|
||||
result := " type: {\n"
|
||||
|
||||
keys := make([]string, 0, len(PRIMITIVE_TYPES))
|
||||
for k := range PRIMITIVE_TYPES {
|
||||
keys := make([]string, 0, len(PrimitiveTypes))
|
||||
for k := range PrimitiveTypes {
|
||||
keys = append(keys, k)
|
||||
}
|
||||
|
||||
if slices.Contains(keys, strings.ToLower(f.Type)) {
|
||||
result += fmt.Sprintf(` primitive: "%s",`, PRIMITIVE_TYPES[strings.ToLower(f.Type)])
|
||||
result += fmt.Sprintf(` primitive: "%s",`, PrimitiveTypes[strings.ToLower(f.Type)])
|
||||
} else {
|
||||
var field string = "[]"
|
||||
var field = "[]"
|
||||
for _, meta := range f.Medatada {
|
||||
if meta.Name == "field" {
|
||||
if len(meta.Values) > 0 {
|
||||
|
||||
@@ -4,30 +4,30 @@ import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
type Medatada struct {
|
||||
type Metadata struct {
|
||||
Name string
|
||||
Values []string
|
||||
}
|
||||
|
||||
func NewMetadata(tag string) *Medatada {
|
||||
func NewMetadata(tag string) *Metadata {
|
||||
tag = strings.TrimSpace(tag)
|
||||
tagName := ""
|
||||
var values []string
|
||||
if strings.Contains(tag, "=") {
|
||||
tagName = tag[:strings.Index(tag, "=")]
|
||||
if tag[strings.Index(tag, "=") + 1] == '[' {
|
||||
values = append(values, strings.Split(tag[strings.Index(tag, "=") + 2:len(tag)-1], ";")...)
|
||||
if tag[strings.Index(tag, "=")+1] == '[' {
|
||||
values = append(values, strings.Split(tag[strings.Index(tag, "=")+2:len(tag)-1], ";")...)
|
||||
for i := range values {
|
||||
values[i] = strings.TrimSpace(values[i])
|
||||
}
|
||||
} else {
|
||||
values = append(values, strings.TrimSpace(tag[strings.Index(tag, "=") + 1:]))
|
||||
values = append(values, strings.TrimSpace(tag[strings.Index(tag, "=")+1:]))
|
||||
}
|
||||
} else {
|
||||
tagName = tag
|
||||
}
|
||||
return &Medatada{
|
||||
Name: strings.TrimSpace(strings.ToLower(tagName)),
|
||||
return &Metadata{
|
||||
Name: strings.TrimSpace(strings.ToLower(tagName)),
|
||||
Values: values,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package generation
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"nto_cli/entities"
|
||||
"nto_cli/utils"
|
||||
"os"
|
||||
@@ -9,10 +10,10 @@ import (
|
||||
)
|
||||
|
||||
func Generate(structName string, fields []entities.Field) {
|
||||
mkPath := fmt.Sprintf("%s/frontend/src/%s", utils.FindFrontendPath() , strings.ToLower(structName))
|
||||
mkPath := fmt.Sprintf("%s/frontend/src/%s", utils.FindFrontendPath(), strings.ToLower(structName))
|
||||
if err := os.Mkdir(mkPath, 0755); err != nil {
|
||||
panic(err)
|
||||
log.Fatalf("Failed to mkdir for model: %s", err)
|
||||
}
|
||||
GenerateService(structName, mkPath)
|
||||
GenerateScheme(structName, fields, mkPath)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package generation
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"nto_cli/entities"
|
||||
"nto_cli/utils"
|
||||
"os"
|
||||
@@ -10,10 +11,11 @@ import (
|
||||
|
||||
func GenerateScheme(structName string, fields []entities.Field, mkPath string) {
|
||||
schemeFile, err := os.Create(mkPath + "/" + strings.ToUpper(structName[:1]) + strings.ToLower(structName[1:]) + "Scheme.vue")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer schemeFile.Close()
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to create file: %s", err)
|
||||
}
|
||||
|
||||
_, err = schemeFile.WriteString(fmt.Sprintf(
|
||||
`<script setup lang="ts">
|
||||
import Table from '../table/Table.vue'
|
||||
@@ -40,7 +42,7 @@ const getDefaults = () => getDefaultValues(scheme)
|
||||
</template>
|
||||
`, strings.ToLower(structName), structName, utils.GetServiceStructType(structName), LoadDependencies(fields), structName, GenerateFields(fields)))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
log.Fatalf("Failed to write to file: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,23 +55,23 @@ func GenerateFields(fields []entities.Field) string {
|
||||
}
|
||||
|
||||
func LoadDependencies(fields []entities.Field) string {
|
||||
type Dependency struct{
|
||||
fieldName string
|
||||
type Dependency struct {
|
||||
fieldName string
|
||||
dependencyName string
|
||||
}
|
||||
}
|
||||
|
||||
result := ""
|
||||
dependencies := []Dependency{}
|
||||
var dependencies []Dependency
|
||||
for _, field := range fields {
|
||||
for _, meta := range field.Medatada {
|
||||
if meta.Name == "data" {
|
||||
dependency := meta.Values[0]
|
||||
dependencies = append(dependencies, Dependency{
|
||||
fieldName: field.Name,
|
||||
fieldName: field.Name,
|
||||
dependencyName: dependency,
|
||||
})
|
||||
result += fmt.Sprintf("import %sService from '../%s/%s.service.ts'\n", dependency, strings.ToLower(dependency), strings.ToLower(dependency))
|
||||
result += fmt.Sprintf("const %sService = new %sService\n", strings.ToLower(dependency), strings.ToUpper(dependency[:1]) + strings.ToLower(dependency[1:]))
|
||||
result += fmt.Sprintf("const %sService = new %sService\n", strings.ToLower(dependency), strings.ToUpper(dependency[:1])+strings.ToLower(dependency[1:]))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -80,6 +82,6 @@ func LoadDependencies(fields []entities.Field) string {
|
||||
|
||||
result += fmt.Sprintf(`onMounted(async () => {
|
||||
%s
|
||||
})` + "\n", insertIntoScheme)
|
||||
})`+"\n", insertIntoScheme)
|
||||
return result
|
||||
}
|
||||
|
||||
@@ -2,13 +2,12 @@ package generation
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"nto_cli/utils"
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
|
||||
|
||||
|
||||
func GenerateService(structName, mkPath string) {
|
||||
serviceFile, err := os.Create(mkPath + "/" + strings.ToLower(structName) + ".service.ts")
|
||||
if err != nil {
|
||||
@@ -22,11 +21,11 @@ import type { IService } from "%s"
|
||||
|
||||
export default class %sService implements IService<%s> {
|
||||
async read(id: number) {
|
||||
return await GetById(id)
|
||||
return await GetById(id) as %s
|
||||
}
|
||||
|
||||
async readAll() {
|
||||
return await GetAll()
|
||||
return await GetAll() as %s[]
|
||||
}
|
||||
|
||||
async create(item: %s) {
|
||||
@@ -35,16 +34,18 @@ export default class %sService implements IService<%s> {
|
||||
|
||||
async delete(id: number) {
|
||||
return await Delete(id)
|
||||
}
|
||||
}
|
||||
|
||||
async update(item: %s) {
|
||||
await Update(item)
|
||||
}
|
||||
|
||||
async count() {
|
||||
return await Count()
|
||||
}
|
||||
}
|
||||
`, utils.GetServiceBindPath(structName), structName, utils.GetServiceStructType(structName), utils.GetServiceType(), structName, structName, structName, structName))
|
||||
`, utils.GetServiceBindPath(structName), structName, utils.GetServiceStructType(structName), utils.GetServiceType(), structName, structName, structName, structName, structName, structName))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
log.Fatalf("Failed to write to file: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
2
go.mod
2
go.mod
@@ -1,6 +1,6 @@
|
||||
module nto_cli
|
||||
|
||||
go 1.23.6
|
||||
go 1.22.12
|
||||
|
||||
require (
|
||||
github.com/fatih/structtag v1.2.0 // indirect
|
||||
|
||||
5
main.go
5
main.go
@@ -1,6 +1,7 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
"nto_cli/cmd"
|
||||
"nto_cli/generation"
|
||||
"nto_cli/utils"
|
||||
@@ -8,13 +9,13 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
log.SetFlags(0)
|
||||
structNames, path := cmd.SelectionInput()
|
||||
|
||||
for _, structName := range structNames {
|
||||
file, err := os.Open(path)
|
||||
defer file.Close()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
log.Fatalf("Failed to open file: %s", err)
|
||||
}
|
||||
structFields := utils.GetStructFields(file, structName)
|
||||
generation.Generate(structName, structFields)
|
||||
|
||||
@@ -2,14 +2,14 @@ package utils
|
||||
|
||||
import "strings"
|
||||
|
||||
func ContainsMany(str string, substrs... string) bool {
|
||||
count := 0
|
||||
for _, substr := range substrs {
|
||||
func ContainsMany(str string, substrings ...string) bool {
|
||||
var matches int
|
||||
for _, substr := range substrings {
|
||||
if strings.Contains(str, substr) {
|
||||
count++;
|
||||
matches++
|
||||
} else {
|
||||
return false;
|
||||
return false
|
||||
}
|
||||
}
|
||||
return count == len(substrs)
|
||||
}
|
||||
return matches == len(substrings)
|
||||
}
|
||||
|
||||
@@ -1,45 +1,45 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
func FindFrontendPath() string {
|
||||
currentPath, err := os.Getwd()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
currentPath, err := os.Getwd()
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to find path for frontend: %s", err)
|
||||
}
|
||||
|
||||
var dirs []string
|
||||
for currentPath != filepath.VolumeName(currentPath)+string(os.PathSeparator) {
|
||||
dir, file := filepath.Split(currentPath)
|
||||
if file != "" {
|
||||
dirs = append([]string{file}, dirs...)
|
||||
}
|
||||
currentPath = filepath.Clean(dir)
|
||||
}
|
||||
var dirs []string
|
||||
for currentPath != filepath.VolumeName(currentPath)+string(os.PathSeparator) {
|
||||
dir, file := filepath.Split(currentPath)
|
||||
if file != "" {
|
||||
dirs = append([]string{file}, dirs...)
|
||||
}
|
||||
currentPath = filepath.Clean(dir)
|
||||
}
|
||||
|
||||
if len(dirs) < 2 || filepath.Join(dirs[len(dirs)-2], dirs[len(dirs)-1]) != filepath.Join("frontend", "src") {
|
||||
panic(errors.New("You're not in frontend/src"))
|
||||
}
|
||||
if len(dirs) < 2 || filepath.Join(dirs[len(dirs)-2], dirs[len(dirs)-1]) != filepath.Join("frontend", "src") {
|
||||
log.Fatalf("Run this program in frontend/ directory")
|
||||
}
|
||||
|
||||
var path string
|
||||
for i, dir := range dirs {
|
||||
if dir == "frontend" {
|
||||
break
|
||||
}
|
||||
if i > 0 {
|
||||
path = filepath.Join(path, dir)
|
||||
} else {
|
||||
path = dir
|
||||
}
|
||||
}
|
||||
var path string
|
||||
for i, dir := range dirs {
|
||||
if dir == "frontend" {
|
||||
break
|
||||
}
|
||||
if i > 0 {
|
||||
path = filepath.Join(path, dir)
|
||||
} else {
|
||||
path = dir
|
||||
}
|
||||
}
|
||||
|
||||
if filepath.VolumeName(path) == "" {
|
||||
path = filepath.Join(string(os.PathSeparator), path)
|
||||
}
|
||||
if filepath.VolumeName(path) == "" {
|
||||
path = filepath.Join(string(os.PathSeparator), path)
|
||||
}
|
||||
|
||||
return path
|
||||
}
|
||||
return path
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package utils
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"log"
|
||||
"nto_cli/entities"
|
||||
"os"
|
||||
"strings"
|
||||
@@ -12,7 +13,7 @@ func GetStructFields(file *os.File, structName string) []entities.Field {
|
||||
|
||||
structFound := false
|
||||
|
||||
structFields := []entities.Field{}
|
||||
var structFields []entities.Field
|
||||
|
||||
scanner := bufio.NewScanner(file)
|
||||
for i := 1; scanner.Scan() && bracketsCount > 0; i++ {
|
||||
@@ -35,7 +36,7 @@ func GetStructFields(file *os.File, structName string) []entities.Field {
|
||||
}
|
||||
|
||||
if err := scanner.Err(); err != nil {
|
||||
panic(err)
|
||||
log.Fatalf("Failed to read file with scanner: %s", err)
|
||||
}
|
||||
return structFields
|
||||
}
|
||||
|
||||
@@ -1,32 +1,36 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"os"
|
||||
"strings"
|
||||
"bufio"
|
||||
"log"
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func GetStructList(filePath string) ([]string) {
|
||||
file, err := os.Open(filePath)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer file.Close()
|
||||
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 err := s.Err(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return structNames
|
||||
}
|
||||
func GetStructList(filePath string) []string {
|
||||
file, err := os.Open(filePath)
|
||||
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
|
||||
}
|
||||
|
||||
@@ -18,4 +18,4 @@ func GetServiceStructType(structName string) string {
|
||||
func GetServiceType() string {
|
||||
path := "../types/service.type.ts"
|
||||
return path
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,12 +3,12 @@ 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
|
||||
}
|
||||
parts := strings.Split(strings.TrimSpace(input), " ")
|
||||
var result []string
|
||||
for _, p := range parts {
|
||||
if p != "" {
|
||||
result = append(result, p)
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package utils
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"log"
|
||||
"nto_cli/entities"
|
||||
"strings"
|
||||
|
||||
@@ -13,19 +14,21 @@ func SplitStructField(field string) (*entities.Field, error) {
|
||||
return nil, nil
|
||||
}
|
||||
if len(strings.TrimSpace(field)) < 2 {
|
||||
return nil, errors.New("End")
|
||||
return nil, errors.New("unexpected end of struct field")
|
||||
}
|
||||
startBacktip := strings.Index(field, "`")
|
||||
endBacktip := -1
|
||||
var metadata []entities.Medatada
|
||||
if startBacktip > -1 {
|
||||
endBacktip = strings.Index(field[startBacktip+1:], "`")
|
||||
if endBacktip > -1 {
|
||||
endBacktip += startBacktip + 1
|
||||
meta := field[startBacktip+1 : endBacktip]
|
||||
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
|
||||
meta := field[startBacktick+1 : endBacktick]
|
||||
tags, err := structtag.Parse(meta)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
log.Fatalf("failed to parse struct tag: %s", err)
|
||||
}
|
||||
uiTag, err := tags.Get("ui")
|
||||
|
||||
@@ -40,9 +43,10 @@ func SplitStructField(field string) (*entities.Field, error) {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
startBacktip = len(field)
|
||||
startBacktick = len(field)
|
||||
}
|
||||
field = strings.TrimSpace(field[:startBacktip])
|
||||
|
||||
field = strings.TrimSpace(field[:startBacktick])
|
||||
|
||||
data := SplitBySingleSpace(field)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user