Skip to content

Commit 49a95b5

Browse files
committed
refresh package index page: display schemas in the index page
1 parent 460d3de commit 49a95b5

39 files changed

+614
-635
lines changed

pkg/tools/gen/gendoc.go

Lines changed: 121 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -67,9 +67,13 @@ const (
6767

6868
// KclPackage contains package information of package metadata(such as name, version, description, ...) and exported models(such as schemas)
6969
type KclPackage struct {
70-
Name string
71-
Version string `toml:"version,omitempty"` // kcl package version
72-
Schemas []*KclOpenAPIType
70+
Name string `json:"name,omitempty"` // kcl package name
71+
Version string `json:"version,omitempty"` // kcl package version
72+
Description string `json:"description,omitempty"` // summary of the kcl package
73+
schemaMapping map[string]*KclOpenAPIType
74+
subPackageMapping map[string]*KclPackage
75+
SchemaList []*KclOpenAPIType `json:"schemaList,omitempty"` // the schema list sorted by name in the KCL package
76+
SubPackageList []*KclPackage `json:"subPackageList,omitempty"` // the sub package list sorted by name in the KCL package
7377
}
7478

7579
func (g *GenContext) render(spec *SwaggerV2Spec) error {
@@ -78,48 +82,78 @@ func (g *GenContext) render(spec *SwaggerV2Spec) error {
7882
if err != nil {
7983
return fmt.Errorf("failed to create docs/ directory under the target directory: %s", err)
8084
}
85+
// extract kcl package from swaggerV2 spec
86+
rootPkg := spec.toKclPackage()
87+
// sort schemas and subpackages by their names
88+
rootPkg.sortSchemasAndPkgs()
89+
// render the package
90+
err = g.renderPackage(rootPkg, g.Target)
91+
if err != nil {
92+
return err
93+
}
94+
return nil
95+
}
8196

82-
// collect all the packages and schema list that they contain
83-
pkgs := make(map[string]*KclPackage)
97+
// toKclPackage extracts a kcl package and sub packages, schemas from a SwaggerV2 spec
98+
func (spec SwaggerV2Spec) toKclPackage() *KclPackage {
99+
rootPkg := &KclPackage{
100+
Name: spec.Info.Title,
101+
Version: spec.Info.Version,
102+
Description: spec.Info.Description,
103+
}
84104

85-
for _, schema := range spec.Definitions {
105+
for schemaName, schema := range spec.Definitions {
86106
pkgName := schema.KclExtensions.XKclModelType.Import.Package
87-
if _, ok := pkgs[pkgName]; ok {
88-
pkgs[pkgName].Schemas = append(pkgs[pkgName].Schemas, schema)
89-
} else {
90-
pkgs[pkgName] = &KclPackage{
91-
Name: pkgName,
107+
if pkgName == "" {
108+
addOrCreateSchema(rootPkg, schemaName, schema)
109+
continue
110+
}
111+
parentPkg := rootPkg
112+
subs := strings.Split(pkgName, ".")
113+
for _, sub := range subs {
114+
if parentPkg.subPackageMapping == nil {
115+
parentPkg.subPackageMapping = map[string]*KclPackage{}
92116
}
93-
pkgs[pkgName].Schemas = []*KclOpenAPIType{schema}
117+
if _, ok := parentPkg.subPackageMapping[sub]; !ok {
118+
parentPkg.subPackageMapping[sub] = &KclPackage{
119+
Name: sub,
120+
}
121+
}
122+
parentPkg = parentPkg.subPackageMapping[sub]
94123
}
124+
125+
addOrCreateSchema(parentPkg, schemaName, schema)
95126
}
127+
return rootPkg
128+
}
96129

97-
err = g.renderPackage(pkgs)
98-
if err != nil {
99-
return err
130+
func (pkg *KclPackage) sortSchemasAndPkgs() {
131+
pkg.SubPackageList = sortMapToSlice(pkg.subPackageMapping)
132+
pkg.SchemaList = sortMapToSlice(pkg.schemaMapping)
133+
for _, sub := range pkg.SubPackageList {
134+
sub.sortSchemasAndPkgs()
100135
}
136+
}
101137

102-
for _, schema := range spec.Definitions {
103-
// create package directory if not exist
104-
pkgDir := schema.GetSchemaPkgDir(g.Target)
105-
err := os.MkdirAll(pkgDir, 0755)
106-
if err != nil {
107-
return fmt.Errorf("failed to create docs/%s directory under the target directory: %s", pkgDir, err)
108-
}
109-
// get doc file name
110-
fileName := fmt.Sprintf("%s.%s", schema.KclExtensions.XKclModelType.Type, g.Format)
111-
// render doc content
112-
content, err := g.renderSchemaDocContent(schema)
113-
if err != nil {
114-
return err
115-
}
116-
// write content to file
117-
err = os.WriteFile(filepath.Join(pkgDir, fileName), content, 0644)
118-
if err != nil {
119-
return fmt.Errorf("failed to write file %s in %s: %v", fileName, pkgDir, err)
120-
}
138+
func sortMapToSlice[T any](mapping map[string]T) []T {
139+
keys := make([]string, 0, len(mapping))
140+
for k := range mapping {
141+
keys = append(keys, k)
142+
}
143+
sort.Strings(keys)
144+
sorted := make([]T, 0, len(mapping))
145+
for _, k := range keys {
146+
sorted = append(sorted, mapping[k])
147+
}
148+
return sorted
149+
}
150+
151+
func addOrCreateSchema(pkg *KclPackage, schemaName string, schema *KclOpenAPIType) {
152+
if pkg.schemaMapping == nil {
153+
pkg.schemaMapping = map[string]*KclOpenAPIType{schemaName: schema}
154+
} else {
155+
pkg.schemaMapping[schemaName] = schema
121156
}
122-
return nil
123157
}
124158

125159
func funcMap() template.FuncMap {
@@ -145,38 +179,69 @@ func funcMap() template.FuncMap {
145179
// todo: let users specify the source code base path
146180
return filepath.Join(tpe.GetSchemaPkgDir(""), tpe.KclExtensions.XKclModelType.Import.Alias)
147181
},
148-
"sortSchemas": func(schemas []*KclOpenAPIType) []*KclOpenAPIType {
149-
sort.Slice(schemas, func(i, j int) bool {
150-
return schemas[i].KclExtensions.XKclModelType.Type < schemas[j].KclExtensions.XKclModelType.Type
151-
})
152-
return schemas
182+
"index": func(pkg *KclPackage) string {
183+
return pkg.getIndexContent(0, " ", "")
153184
},
154185
}
155186
}
156187

157-
func (g *GenContext) renderPackage(pkgs map[string]*KclPackage) error {
158-
for name, pkg := range pkgs {
159-
// create the package directory
160-
pkgDir := GetPkgDir(g.Target, name)
188+
func (pkg *KclPackage) getPackageIndexContent(level int, indentation string, pkgPath string) string {
189+
currentPkgPath := filepath.Join(pkgPath, pkg.Name)
190+
currentDocPath := filepath.Join(currentPkgPath, "index.md")
191+
return fmt.Sprintf(`%s- [%s](%s)
192+
%s`, strings.Repeat(indentation, level), pkg.Name, currentDocPath, pkg.getIndexContent(level+1, indentation, currentPkgPath))
193+
}
194+
195+
func (tpe *KclOpenAPIType) getSchemaIndexContent(level int, indentation string, pkgPath string) string {
196+
docPath := filepath.Join(pkgPath, "index.md")
197+
if level == 0 {
198+
docPath = ""
199+
}
200+
return fmt.Sprintf(`%s- [%s](%s#schema-%s)
201+
`, strings.Repeat(indentation, level), tpe.KclExtensions.XKclModelType.Type, docPath, tpe.KclExtensions.XKclModelType.Type)
202+
}
203+
204+
func (pkg *KclPackage) getIndexContent(level int, indentation string, pkgPath string) string {
205+
var content string
206+
if len(pkg.SchemaList) > 0 {
207+
for _, sch := range pkg.SchemaList {
208+
content += sch.getSchemaIndexContent(level, indentation, pkgPath)
209+
}
210+
}
211+
if len(pkg.SubPackageList) > 0 {
212+
for _, pkg := range pkg.SubPackageList {
213+
content += pkg.getPackageIndexContent(level, indentation, pkgPath)
214+
}
215+
}
216+
return content
217+
}
218+
219+
func (g *GenContext) renderPackage(pkg *KclPackage, parentDir string) error {
220+
// render the package's index.md page
221+
//fmt.Println(fmt.Sprintf("creating %s/index.md", parentDir))
222+
indexFileName := fmt.Sprintf("%s.%s", "index", g.Format)
223+
var contentBuf bytes.Buffer
224+
err := tmpl.ExecuteTemplate(&contentBuf, "packageDoc", pkg)
225+
if err != nil {
226+
return fmt.Errorf("failed to render package %s with template, err: %s", pkg.Name, err)
227+
}
228+
// write content to file
229+
err = os.WriteFile(filepath.Join(parentDir, indexFileName), contentBuf.Bytes(), 0644)
230+
if err != nil {
231+
return fmt.Errorf("failed to write file %s in %s: %v", indexFileName, parentDir, err)
232+
}
233+
234+
for _, sub := range pkg.SubPackageList {
235+
pkgDir := GetPkgDir(parentDir, sub.Name)
236+
//fmt.Println(fmt.Sprintf("creating directory: %s", pkgDir))
161237
err := os.MkdirAll(pkgDir, 0755)
162238
if err != nil {
163239
return fmt.Errorf("failed to create docs/%s directory under the target directory: %s", pkgDir, err)
164240
}
165-
indexFileName := fmt.Sprintf("%s.%s", "index", g.Format)
166-
// render index doc content
167-
var contentBuf bytes.Buffer
168-
err = tmpl.ExecuteTemplate(&contentBuf, "packageDoc", pkg)
169-
if err != nil {
170-
return fmt.Errorf("failed to render package %s with template, err: %s", name, err)
171-
}
241+
err = g.renderPackage(sub, pkgDir)
172242
if err != nil {
173243
return err
174244
}
175-
// write content to file
176-
err = os.WriteFile(filepath.Join(pkgDir, indexFileName), contentBuf.Bytes(), 0644)
177-
if err != nil {
178-
return fmt.Errorf("failed to write file %s in %s: %v", indexFileName, pkgDir, err)
179-
}
180245
}
181246
return nil
182247
}
@@ -251,7 +316,6 @@ func (g *GenContext) GenDoc() error {
251316
return fmt.Errorf("filePath is not a KCL package: %s", err)
252317
}
253318
spec, err := g.getSwagger2Spec(pkg)
254-
//todo: deal err
255319
err = g.render(spec)
256320
if err != nil {
257321
return fmt.Errorf("render doc failed: %s", err)

pkg/tools/gen/gendoc_test.go

Lines changed: 7 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,8 @@ import (
1414

1515
func TestDocRender(t *testing.T) {
1616
tcases := [...]struct {
17-
source *KclOpenAPIType
18-
expectUnix string
19-
expectWindows string
17+
source *KclOpenAPIType
18+
expect string
2019
}{
2120
{
2221
source: &KclOpenAPIType{
@@ -39,43 +38,18 @@ func TestDocRender(t *testing.T) {
3938
},
4039
},
4140

42-
expectUnix: `## Schema Person
41+
expect: `### Schema Person
4342
4443
Description of Schema Person
4544
46-
### Attributes
45+
#### Attributes
4746
4847
**name** *required*
4948
5049
` + "`" + `str` + "`" + `
5150
5251
name of the person
5352
54-
55-
## Source Files
56-
57-
- [models.Person](models/person.k)
58-
59-
<!-- Auto generated by kcl-doc tool, please do not edit. -->
60-
`,
61-
expectWindows: `## Schema Person
62-
63-
Description of Schema Person
64-
65-
### Attributes
66-
67-
**name** *required*
68-
69-
` + "`" + `str` + "`" + `
70-
71-
name of the person
72-
73-
74-
## Source Files
75-
76-
- [models.Person](models\person.k)
77-
78-
<!-- Auto generated by kcl-doc tool, please do not edit. -->
7953
`,
8054
},
8155
}
@@ -93,10 +67,11 @@ name of the person
9367

9468
var expect string
9569
if runtime.GOOS == "windows" {
96-
expect = strings.ReplaceAll(tcase.expectWindows, "\n", "\r\n")
70+
expect = strings.ReplaceAll(tcase.expect, "\n", "\r\n")
9771
} else {
98-
expect = tcase.expectUnix
72+
expect = tcase.expect
9973
}
74+
//fmt.Println(string(content))
10075
assert2.Equal(t, expect, string(content), "render content mismatch")
10176
}
10277
}

pkg/tools/gen/genopenapi.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -330,7 +330,6 @@ func PackageName(pkgPath string, t *kcl.KclType) string {
330330
if pkgPath == "." {
331331
return ""
332332
} else {
333-
334333
return strings.Join(strings.Split(pkgPath, string(os.PathSeparator)), ".")
335334
}
336335
}
Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,18 @@
11
{{- define "packageDoc" -}}
2-
## Package {{if ne .Name ""}}{{.Name}}{{else}}main{{end}}
2+
# Package {{if ne .Name ""}}{{.Name}}{{else}}main{{end}}{{/* the package name should not be empty, issue: https://github.com/kcl-lang/kpm/issues/171 */}}
3+
{{if ne .Description ""}}
4+
## Overview
35

4-
### Index
6+
{{.Description}}
7+
{{end}}
8+
## Index
59

6-
{{range $index, $schema := sortSchemas .Schemas}}- [{{$schema.KclExtensions.XKclModelType.Type}}]({{$schema.KclExtensions.XKclModelType.Type}}.md)
10+
{{ index . }}
11+
{{ if .SchemaList}}
12+
## Schemas
713

14+
{{range $index, $schema := .SchemaList }}{{template "schemaDoc" $schema}}
15+
{{- end -}}
816
{{end -}}
917
<!-- Auto generated by kcl-doc tool, please do not edit. -->
1018
{{end}}
Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,18 @@
11
{{- define "schemaDoc" -}}
2-
## Schema {{.KclExtensions.XKclModelType.Type}}
3-
2+
### Schema {{.KclExtensions.XKclModelType.Type}}
3+
{{if ne .Description ""}}
44
{{.Description}}
5-
6-
### Attributes
5+
{{end}}
6+
#### Attributes
77

88
{{range $name, $property := .Properties}}**{{$name}}**{{if containsString $.Required $name }} *required*{{end}}{{if $property.ReadOnly}} *readOnly*{{end}}
99

1010
`{{kclType $property}}`{{if ne $property.Description ""}}
1111

1212
{{$property.Description}}{{end}}
1313

14-
{{end}}{{if ne .Example ""}}### Examples
14+
{{end}}{{if ne .Example ""}}#### Examples
1515

1616
{{.Example}}
17-
{{end}}
18-
## Source Files
19-
20-
- [{{fullTypeName . }}]({{sourcePath .}})
21-
22-
<!-- Auto generated by kcl-doc tool, please do not edit. -->
23-
{{end}}
17+
{{end -}}
18+
{{- end -}}

pkg/tools/gen/testdata/doc/k8s/unixlike/md/apps/Deployment.md

Lines changed: 0 additions & 20 deletions
This file was deleted.

0 commit comments

Comments
 (0)