Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 0f80598

Browse files
committedJun 21, 2024·
feat: impl go package to kcl files
Signed-off-by: peefy <xpf6677@163.com>
1 parent f4a0793 commit 0f80598

File tree

7 files changed

+562
-420
lines changed

7 files changed

+562
-420
lines changed
 

‎pkg/tools/gen/genkcl.go

-182
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,15 @@ package gen
22

33
import (
44
"errors"
5-
"fmt"
65
"io"
76
"path/filepath"
8-
"regexp"
9-
"strconv"
107
"strings"
118

129
"kcl-lang.io/kcl-go/pkg/loader"
13-
"kcl-lang.io/kcl-go/pkg/logger"
1410
)
1511

1612
type GenKclOptions struct {
1713
Mode Mode
18-
ParseFromTag bool
1914
CastingOption castingOption
2015
UseIntegersForNumbers bool
2116
}
@@ -104,180 +99,3 @@ func (k *kclGenerator) GenSchema(w io.Writer, filename string, src interface{})
10499
return errors.New("unknown mode")
105100
}
106101
}
107-
108-
func (k *kclGenerator) genSchemaFromGoStruct(w io.Writer, filename string, src interface{}) error {
109-
fmt.Fprintln(w)
110-
goStructs, err := ParseGoSourceCode(filename, src)
111-
if err != nil {
112-
return err
113-
}
114-
for _, goStruct := range goStructs {
115-
fmt.Fprintf(w, "schema %s:\n", goStruct.Name)
116-
if goStruct.StructComment != "" {
117-
fmt.Fprintf(w, " \"\"\"%s\"\"\"\n", goStruct.StructComment)
118-
}
119-
for _, field := range goStruct.Fields {
120-
kclFieldName, kclFieldType, err := k.GetTypeName(field)
121-
if err != nil {
122-
logger.GetLogger().Warningf("get struct tag key kcl info err: %s, will generate kcl schema from the struct field metadata data, field info %#v", err.Error(), field)
123-
kclFieldName, kclFieldType = k.GetKclTypeFromStructField(field)
124-
}
125-
fmt.Fprintf(w, " %s: %s\n", kclFieldName, kclFieldType)
126-
}
127-
fmt.Fprintf(w, "\n")
128-
}
129-
return nil
130-
}
131-
132-
func (k *kclGenerator) GetTypeName(f *GoStructField) (string, string, error) {
133-
if k.opts.ParseFromTag {
134-
return k.parserGoStructFieldTag(f.FieldTag)
135-
}
136-
fieldName, fieldType := k.GetKclTypeFromStructField(f)
137-
return fieldName, fieldType, nil
138-
}
139-
140-
func (k *kclGenerator) parserGoStructFieldTag(tag string) (string, string, error) {
141-
tagMap := make(map[string]string, 0)
142-
sp := strings.Split(tag, "`")
143-
if len(sp) == 1 {
144-
return "", "", errors.New("this field not found tag string like ``")
145-
}
146-
value, ok := k.Lookup(sp[1], "kcl")
147-
if !ok {
148-
return "", "", errors.New("not found tag key named kcl")
149-
}
150-
reg := "name=.*,type=.*"
151-
match, err := regexp.Match(reg, []byte(value))
152-
if err != nil {
153-
return "", "", err
154-
}
155-
if !match {
156-
return "", "", errors.New("don't match the kcl tag info, the tag info style is name=NAME,type=TYPE")
157-
}
158-
tagInfo := strings.Split(value, ",")
159-
for _, s := range tagInfo {
160-
t := strings.Split(s, "=")
161-
tagMap[t[0]] = t[1]
162-
}
163-
fieldType := tagMap["type"]
164-
if strings.Contains(tagMap["type"], ")|") {
165-
typeUnionList := strings.Split(tagMap["type"], "|")
166-
var ss []string
167-
for _, u := range typeUnionList {
168-
_, _, litValue := k.isLitType(u)
169-
ss = append(ss, litValue)
170-
}
171-
fieldType = strings.Join(ss, "|")
172-
}
173-
return tagMap["name"], fieldType, nil
174-
}
175-
176-
func (k *kclGenerator) GetKclTypeFromStructField(f *GoStructField) (string, string) {
177-
return f.FieldName, k.isLitGoType(f.FieldType)
178-
}
179-
180-
func (k *kclGenerator) isLitType(fieldType string) (ok bool, basicTyp, litValue string) {
181-
if !strings.HasSuffix(fieldType, ")") {
182-
return
183-
}
184-
185-
i := strings.Index(fieldType, "(") + 1
186-
j := strings.LastIndex(fieldType, ")")
187-
188-
switch {
189-
case strings.HasPrefix(fieldType, "bool("):
190-
return true, "bool", fieldType[i:j]
191-
case strings.HasPrefix(fieldType, "int("):
192-
return true, "int", fieldType[i:j]
193-
case strings.HasPrefix(fieldType, "float("):
194-
return true, "float", fieldType[i:j]
195-
case strings.HasPrefix(fieldType, "str("):
196-
return true, "str", strconv.Quote(fieldType[i:j])
197-
}
198-
return
199-
}
200-
201-
func (k *kclGenerator) isLitGoType(fieldType string) string {
202-
switch fieldType {
203-
case "int", "int32", "int64":
204-
return "int"
205-
case "float", "float64":
206-
return "float"
207-
case "string":
208-
return "str"
209-
case "bool":
210-
return "bool"
211-
case "interface{}":
212-
return "any"
213-
default:
214-
if strings.HasPrefix(fieldType, "*") {
215-
i := strings.Index(fieldType, "*") + 1
216-
return k.isLitGoType(fieldType[i:])
217-
}
218-
if strings.HasPrefix(fieldType, "map") {
219-
i := strings.Index(fieldType, "[") + 1
220-
j := strings.Index(fieldType, "]")
221-
return fmt.Sprintf("{%s:%s}", k.isLitGoType(fieldType[i:j]), k.isLitGoType(fieldType[j+1:]))
222-
}
223-
if strings.HasPrefix(fieldType, "[]") {
224-
i := strings.Index(fieldType, "]") + 1
225-
return fmt.Sprintf("[%s]", k.isLitGoType(fieldType[i:]))
226-
}
227-
return fieldType
228-
}
229-
}
230-
231-
func (k *kclGenerator) Lookup(tag, key string) (value string, ok bool) {
232-
// When modifying this code, also update the validateStructTag code
233-
// in cmd/vet/structtag.go.
234-
235-
for tag != "" {
236-
// Skip leading space.
237-
i := 0
238-
for i < len(tag) && tag[i] == ' ' {
239-
i++
240-
}
241-
tag = tag[i:]
242-
if tag == "" {
243-
break
244-
}
245-
246-
// Scan to colon. A space, a quote or a control character is a syntax error.
247-
// Strictly speaking, control chars include the range [0x7f, 0x9f], not just
248-
// [0x00, 0x1f], but in practice, we ignore the multi-byte control characters
249-
// as it is simpler to inspect the tag's bytes than the tag's runes.
250-
i = 0
251-
for i < len(tag) && tag[i] > ' ' && tag[i] != ':' && tag[i] != '"' && tag[i] != 0x7f {
252-
i++
253-
}
254-
if i == 0 || i+1 >= len(tag) || tag[i] != ':' || tag[i+1] != '"' {
255-
break
256-
}
257-
name := string(tag[:i])
258-
tag = tag[i+1:]
259-
260-
// Scan quoted string to find value.
261-
i = 1
262-
for i < len(tag) && tag[i] != '"' {
263-
if tag[i] == '\\' {
264-
i++
265-
}
266-
i++
267-
}
268-
if i >= len(tag) {
269-
break
270-
}
271-
qvalue := string(tag[:i+1])
272-
tag = tag[i+1:]
273-
274-
if key == name {
275-
value, err := strconv.Unquote(qvalue)
276-
if err != nil {
277-
break
278-
}
279-
return value, true
280-
}
281-
}
282-
return "", false
283-
}

‎pkg/tools/gen/genkcl_gostruct.go

+442
Large diffs are not rendered by default.

‎pkg/tools/gen/genkcl_jsonschema.go

+15-9
Original file line numberDiff line numberDiff line change
@@ -24,15 +24,19 @@ const (
2424
camelCase
2525
)
2626

27+
type context struct {
28+
imports map[string]struct{}
29+
resultMap map[string]convertResult
30+
paths []string
31+
castingOption castingOption
32+
}
33+
2734
type convertContext struct {
35+
context
2836
rootSchema *jsonschema.Schema
29-
imports map[string]struct{}
30-
resultMap map[string]convertResult
31-
paths []string
3237
// pathObjects is used to avoid infinite loop when converting recursive schema
3338
// TODO: support recursive schema
34-
pathObjects []*jsonschema.Schema
35-
castingOption castingOption
39+
pathObjects []*jsonschema.Schema
3640
}
3741

3842
type convertResult struct {
@@ -66,10 +70,12 @@ func (k *kclGenerator) genSchemaFromJsonSchema(w io.Writer, filename string, src
6670

6771
// convert json schema to kcl schema
6872
ctx := convertContext{
69-
rootSchema: js,
70-
resultMap: make(map[string]convertResult),
71-
imports: make(map[string]struct{}),
72-
paths: []string{},
73+
rootSchema: js,
74+
context: context{
75+
resultMap: make(map[string]convertResult),
76+
imports: make(map[string]struct{}),
77+
paths: []string{},
78+
},
7379
pathObjects: []*jsonschema.Schema{},
7480
}
7581
result := convertSchemaFromJsonSchema(&ctx, js,

‎pkg/tools/gen/genkcl_test.go

+85-75
Original file line numberDiff line numberDiff line change
@@ -14,97 +14,107 @@ import (
1414

1515
func TestGenKcl(t *testing.T) {
1616
var buf bytes.Buffer
17-
opts := &GenKclOptions{
18-
ParseFromTag: false,
19-
}
17+
opts := &GenKclOptions{}
2018
err := GenKcl(&buf, "./testdata/genkcldata.go", nil, opts)
2119
// err := GenKcl(&buf, "demo", code, opts)
2220
if err != nil {
2321
log.Fatal(err)
2422
}
2523
kclCode := buf.String()
26-
fmt.Println("###############")
27-
fmt.Print(kclCode)
28-
expectedKclCodeFromTag := `
29-
schema Person:
30-
"""Person Example"""
31-
name: str
32-
age: int
33-
friends: [str]
34-
movies: {str:Movie}
35-
MapInterface: {str:{str:any}}
36-
Ep: employee
37-
Com: Company
38-
StarInt: int
39-
StarMap: {str:str}
40-
Inter: any
24+
expectedKclCodeFromField := `"""
25+
This file was generated by the KCL auto-gen tool. DO NOT EDIT.
26+
Editing this file might prove futile when you re-run the KCL auto-gen generate command.
27+
"""
28+
29+
schema Company:
30+
r"""
31+
Company
32+
33+
Attributes
34+
----------
35+
name : str, optional
36+
employees : [Employee], optional
37+
persons : Person, optional
38+
"""
39+
40+
name?: str
41+
employees?: [Employee]
42+
persons?: Person
43+
44+
schema Employee:
45+
r"""
46+
Employee
47+
48+
Attributes
49+
----------
50+
name : str, optional
51+
age : int, optional
52+
friends : [str], optional
53+
movies : {str:Movie}, optional
54+
bankCard : int, optional
55+
nationality : str, optional
56+
"""
57+
58+
name?: str
59+
age?: int
60+
friends?: [str]
61+
movies?: {str:Movie}
62+
bankCard?: int
63+
nationality?: str
4164
4265
schema Movie:
43-
desc: str
44-
size: units.NumberMultiplier
66+
r"""
67+
Movie
68+
69+
Attributes
70+
----------
71+
Desc : str, optional
72+
size : units.NumberMultiplier, optional
73+
kind : "Superhero"|"War"|"Unknown", optional
74+
unknown1 : int|str, optional
75+
unknown2 : any, optional
76+
"""
77+
78+
Desc?: str
79+
size?: units.NumberMultiplier
4580
kind?: "Superhero"|"War"|"Unknown"
4681
unknown1?: int|str
4782
unknown2?: any
4883
49-
schema employee:
50-
name: str
51-
age: int
52-
friends: [str]
53-
movies: {str:Movie}
54-
bankCard: int
55-
nationality: str
56-
57-
schema Company:
58-
name: str
59-
employees: [employee]
60-
persons: Person
61-
62-
`
63-
expectedKclCodeFromField := `
6484
schema Person:
65-
"""Person Example"""
66-
name: str
67-
age: int
68-
friends: [str]
69-
movies: {str:Movie}
70-
MapInterface: {str:{str:any}}
71-
Ep: employee
72-
Com: Company
73-
StarInt: int
74-
StarMap: {str:str}
75-
Inter: any
76-
77-
schema Movie:
78-
desc: str
79-
size: int
80-
kind: str
81-
unknown1: any
82-
unknown2: any
83-
84-
schema employee:
85-
name: str
86-
age: int
87-
friends: [str]
88-
movies: {str:Movie}
89-
bankCard: int
90-
nationality: str
91-
92-
schema Company:
93-
name: str
94-
employees: [employee]
95-
persons: Person
85+
r"""
86+
Person Example
87+
88+
89+
Attributes
90+
----------
91+
name : str, optional
92+
age : int, optional
93+
friends : [str], optional
94+
movies : {str:Movie}, optional
95+
MapInterface : {str:{str:any}}, optional
96+
Ep : Employee, optional
97+
Com : Company, optional
98+
StarInt : int, optional
99+
StarMap : {str:str}, optional
100+
Inter : any, optional
101+
"""
102+
103+
name?: str
104+
age?: int
105+
friends?: [str]
106+
movies?: {str:Movie}
107+
MapInterface?: {str:{str:any}}
108+
Ep?: Employee
109+
Com?: Company
110+
StarInt?: int
111+
StarMap?: {str:str}
112+
Inter?: any
96113
97114
`
98-
if opts.ParseFromTag {
99-
if kclCode != expectedKclCodeFromTag {
100-
panic(fmt.Sprintf("test failed, expected %s got %s", expectedKclCodeFromTag, kclCode))
101-
}
102-
} else {
103-
if kclCode != expectedKclCodeFromField {
104-
panic(fmt.Sprintf("test failed, expected %s got %s", expectedKclCodeFromField, kclCode))
105-
}
115+
if kclCode != expectedKclCodeFromField {
116+
panic(fmt.Sprintf("test failed, expected %s got %s", expectedKclCodeFromField, kclCode))
106117
}
107-
108118
}
109119

110120
func TestGenKclFromJsonSchema(t *testing.T) {

‎pkg/tools/gen/gotypes.go

-107
This file was deleted.

‎pkg/tools/gen/gotypes_test.go

-27
This file was deleted.

‎pkg/tools/gen/testdata/genkcldata.go

+20-20
Original file line numberDiff line numberDiff line change
@@ -2,37 +2,37 @@ package testdata
22

33
// Person Example
44
type Person struct {
5-
name string `kcl:"name=name,type=str"` // kcl-type: str
6-
age int `kcl:"name=age,type=int"` // kcl-type: int
7-
friends []string `kcl:"name=friends,type=[str]"` // kcl-type: [str]
8-
movies map[string]*Movie `kcl:"name=movies,type={str:Movie}"` // kcl-type: {str:Movie}
5+
Name string `kcl:"name=name,type=str"` // kcl-type: str
6+
Age int `kcl:"name=age,type=int"` // kcl-type: int
7+
Friends []string `kcl:"name=friends,type=[str]"` // kcl-type: [str]
8+
Movies map[string]*Movie `kcl:"name=movies,type={str:Movie}"` // kcl-type: {str:Movie}
99
MapInterface map[string]map[string]interface{}
10-
Ep *employee
10+
Ep *Employee
1111
Com Company
1212
StarInt *int
1313
StarMap map[string]string
1414
Inter interface{}
1515
}
1616

1717
type Movie struct {
18-
desc string `kcl:"nam=desc,type=str"` // kcl-type: str
19-
size int `kcl:"name=size,type=units.NumberMultiplier"` // kcl-type: units.NumberMultiplier
20-
kind string `kcl:"name=kind?,type=str(Superhero)|str(War)|str(Unknown)"` // kcl-type: "Superhero"|"War"|"Unknown"
21-
unknown1 interface{} `kcl:"name=unknown1?,type=int|str"` // kcl-type: int|str
22-
unknown2 interface{} `kcl:"name=unknown2?,type=any"` // kcl-type: any
18+
Desc string `kcl:"nam=desc,type=str"` // kcl-type: str
19+
Size int `kcl:"name=size,type=units.NumberMultiplier"` // kcl-type: units.NumberMultiplier
20+
Kind string `kcl:"name=kind,type=str(Superhero)|str(War)|str(Unknown)"` // kcl-type: "Superhero"|"War"|"Unknown"
21+
Unknown1 interface{} `kcl:"name=unknown1,type=int|str"` // kcl-type: int|str
22+
Unknown2 interface{} `kcl:"name=unknown2,type=any"` // kcl-type: any
2323
}
2424

25-
type employee struct {
26-
name string `kcl:"name=name,type=str"` // kcl-type: str
27-
age int `kcl:"name=age,type=int"` // kcl-type: int
28-
friends []string `kcl:"name=friends,type=[str]"` // kcl-type: [str]
29-
movies map[string]*Movie `kcl:"name=movies,type={str:Movie}"` // kcl-type: {str:Movie}
30-
bankCard int `kcl:"name=bankCard,type=int"` // kcl-type: int
31-
nationality string `kcl:"name=nationality,type=str"` // kcl-type: str
25+
type Employee struct {
26+
Name string `kcl:"name=name,type=str"` // kcl-type: str
27+
Age int `kcl:"name=age,type=int"` // kcl-type: int
28+
Friends []string `kcl:"name=friends,type=[str]"` // kcl-type: [str]
29+
Movies map[string]*Movie `kcl:"name=movies,type={str:Movie}"` // kcl-type: {str:Movie}
30+
BankCard int `kcl:"name=bankCard,type=int"` // kcl-type: int
31+
Nationality string `kcl:"name=nationality,type=str"` // kcl-type: str
3232
}
3333

3434
type Company struct {
35-
name string `kcl:"name=name,type=str"` // kcl-type: str
36-
employees []*employee `kcl:"name=employees,type=[employee]"` // kcl-type: [employee]
37-
persons *Person `kcl:"name=persons,type=Person"` // kcl-type: Person
35+
Name string `kcl:"name=name,type=str"` // kcl-type: str
36+
Employees []*Employee `kcl:"name=employees,type=[Employee]"` // kcl-type: [Employee]
37+
Persons *Person `kcl:"name=persons,type=Person"` // kcl-type: Person
3838
}

0 commit comments

Comments
 (0)
Please sign in to comment.