Skip to content

Commit 8e32112

Browse files
committed
docs: show enums in reference and allow groupings
1 parent 66934bd commit 8e32112

465 files changed

Lines changed: 6420 additions & 996 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

docs/hack/config/partials/main.go

Lines changed: 184 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -5,21 +5,30 @@ import (
55
"io/ioutil"
66
"os"
77
"path/filepath"
8+
"sort"
9+
"strconv"
810
"strings"
911

12+
"github.com/gertd/go-pluralize"
1013
"github.com/invopop/jsonschema"
1114
"github.com/loft-sh/devspace/docs/hack/util"
15+
"github.com/loft-sh/devspace/pkg/devspace/config/versions"
1216
"github.com/loft-sh/devspace/pkg/devspace/config/versions/latest"
1317
)
1418

1519
const configPartialBasePath = "docs/pages/configuration/_partials/"
1620
const nameFieldName = "name"
21+
const versionFieldName = "version"
22+
const groupKey = "group"
23+
const groupNameKey = "group_name"
24+
25+
var pluralizeClient = pluralize.NewClient()
1726

1827
func main() {
1928
r := new(jsonschema.Reflector)
2029
r.AllowAdditionalProperties = true
2130
r.PreferYAMLSchema = true
22-
r.RequiredFromJSONSchemaTags = false
31+
r.RequiredFromJSONSchemaTags = true
2332
r.YAMLEmbeddedStructs = false
2433
r.ExpandedStruct = true
2534

@@ -30,14 +39,51 @@ func main() {
3039

3140
schema := r.Reflect(&latest.Config{})
3241

42+
versionField, ok := schema.Properties.Get(versionFieldName)
43+
if ok {
44+
if fieldSchema, ok := versionField.(*jsonschema.Schema); ok {
45+
versionEnum := []string{}
46+
for version := range versions.VersionLoader {
47+
versionEnum = append(versionEnum, version)
48+
}
49+
50+
sort.SliceStable(versionEnum, func(a, b int) bool {
51+
majorA, _ := strconv.Atoi(string(versionEnum[a][1]))
52+
majorB, _ := strconv.Atoi(string(versionEnum[b][1]))
53+
minorA, _ := strconv.Atoi(string(versionEnum[a][6:]))
54+
minorB, _ := strconv.Atoi(string(versionEnum[b][6:]))
55+
56+
if majorA == majorB {
57+
return minorA > minorB
58+
} else {
59+
return majorA > majorB
60+
}
61+
})
62+
63+
fieldSchema.Enum = []interface{}{}
64+
for _, version := range versionEnum {
65+
fieldSchema.Enum = append(fieldSchema.Enum, version)
66+
}
67+
}
68+
}
69+
3370
createSections("", schema, schema.Definitions, 1, false)
3471
}
3572

73+
type Group struct {
74+
File string
75+
Name string
76+
Content string
77+
Imports *[]string
78+
}
79+
3680
func createSections(prefix string, schema *jsonschema.Schema, definitions jsonschema.Definitions, depth int, parentIsNameObjectMap bool) string {
3781
partialImports := &[]string{}
3882
content := ""
3983
headlinePrefix := strings.Repeat("#", depth+1) + " "
4084

85+
groups := map[string]*Group{}
86+
4187
for _, fieldName := range schema.Properties.Keys() {
4288
if parentIsNameObjectMap && fieldName == nameFieldName {
4389
continue
@@ -50,14 +96,16 @@ func createSections(prefix string, schema *jsonschema.Schema, definitions jsonsc
5096
fieldFile := fmt.Sprintf(configPartialBasePath+"%s/%s%s.mdx", latest.Version, prefix, fieldName)
5197
fieldType := "object"
5298
isNameObjectMap := false
99+
groupID, _ := fieldSchema.Extras[groupKey].(string)
53100

101+
var patternPropertySchema *jsonschema.Schema
54102
var nestedSchema *jsonschema.Schema
55103

56104
ref := ""
57105
if fieldSchema.Type == "array" {
58106
ref = fieldSchema.Items.Ref
59107
fieldType = "object[]"
60-
} else if patternPropertySchema, ok := fieldSchema.PatternProperties[".*"]; ok {
108+
} else if patternPropertySchema, ok = fieldSchema.PatternProperties[".*"]; ok {
61109
ref = patternPropertySchema.Ref
62110
isNameObjectMap = true
63111
} else if fieldSchema.Ref != "" {
@@ -74,17 +122,49 @@ func createSections(prefix string, schema *jsonschema.Schema, definitions jsonsc
74122
}
75123
} else {
76124
required := contains(schema.Required, fieldName)
125+
fieldDefault := ""
126+
77127
fieldType = fieldSchema.Type
128+
if fieldType == "" && fieldSchema.OneOf != nil {
129+
for _, oneOfType := range fieldSchema.OneOf {
130+
if fieldType != "" {
131+
fieldType = fieldType + "|"
132+
}
133+
fieldType = fieldType + oneOfType.Type
134+
}
135+
}
136+
137+
if isNameObjectMap {
138+
fieldNameSingular := pluralizeClient.Singular(fieldName)
139+
fieldType = "<" + fieldNameSingular + "_name>:"
140+
141+
if patternPropertySchema != nil && patternPropertySchema.Type != "" {
142+
fieldType = fieldType + patternPropertySchema.Type
143+
} else {
144+
fieldType = fieldType + "object"
145+
}
146+
}
147+
78148
if fieldType == "array" {
79149
fieldType = fieldSchema.Items.Type + "[]"
80150
}
81151

82-
fieldDefault, ok := fieldSchema.Default.(string)
83-
if !ok {
84-
fieldDefault = ""
152+
if fieldType == "boolean" {
153+
fieldDefault = "false"
154+
if required {
155+
fieldDefault = "true"
156+
required = false
157+
}
158+
} else {
159+
fieldDefault, ok = fieldSchema.Default.(string)
160+
if !ok {
161+
fieldDefault = ""
162+
}
85163
}
86164

87-
fieldContent = fmt.Sprintf(util.TemplateConfigField, false, " open", headlinePrefix, fieldName, required, fieldType, fieldDefault, fieldSchema.Description, "")
165+
enumValues := GetEumValues(fieldSchema, required, &fieldDefault)
166+
167+
fieldContent = fmt.Sprintf(util.TemplateConfigField, false, " open", headlinePrefix, fieldName, required, fieldType, fieldDefault, enumValues, fieldSchema.Description, "")
88168

89169
err := os.MkdirAll(filepath.Dir(fieldFile), os.ModePerm)
90170
if err != nil {
@@ -97,43 +177,93 @@ func createSections(prefix string, schema *jsonschema.Schema, definitions jsonsc
97177
}
98178
}
99179

100-
*partialImports = append(*partialImports, fieldFile)
101180
fieldPartial := fmt.Sprintf(util.TemplatePartialUse, util.GetPartialImportName(fieldFile))
102181
if ref != "" {
103182
if isNameObjectMap && nestedSchema != nil {
104183
nameField, ok := nestedSchema.Properties.Get(nameFieldName)
105184
if ok {
106185
if nameFieldSchema, ok := nameField.(*jsonschema.Schema); ok {
107-
fieldPartial = fmt.Sprintf(util.TemplateConfigField, true, "open", headlinePrefix, "<"+nameFieldName+">", false, "object", "", nameFieldSchema.Description, fieldPartial)
186+
fieldNameSingular := pluralizeClient.Singular(fieldName)
187+
nameFieldRequired := true
188+
nameFieldDefault := ""
189+
nameFieldEnumValues := GetEumValues(nameFieldSchema, nameFieldRequired, &nameFieldDefault)
190+
191+
fieldPartial = fmt.Sprintf(util.TemplateConfigField, true, "open", headlinePrefix, "<"+fieldNameSingular+"_"+nameFieldName+">", nameFieldRequired, "string", nameFieldDefault, nameFieldEnumValues, nameFieldSchema.Description, fieldPartial)
192+
fieldType = "&lt;" + fieldNameSingular + "_name&gt;:object"
108193
}
109194
}
110195
}
111-
fieldPartial = fmt.Sprintf(util.TemplateConfigField, true, "", headlinePrefix, fieldName, false, fieldType, "", fieldSchema.Description, fieldPartial)
196+
197+
fieldPartial = fmt.Sprintf(util.TemplateConfigField, true, "", headlinePrefix, fieldName, false, fieldType, "", "", fieldSchema.Description, fieldPartial)
112198
}
113199

114-
content = content + "\n\n" + fieldPartial
200+
if groupID != "" {
201+
group, ok := groups[groupID]
202+
if !ok {
203+
group = &Group{
204+
File: fmt.Sprintf(configPartialBasePath+"%s/%sgroup_%s.mdx", latest.Version, prefix, groupID),
205+
Imports: &[]string{},
206+
}
207+
groups[groupID] = group
208+
209+
groupPartial := fmt.Sprintf(util.TemplatePartialUse, util.GetPartialImportName(group.File))
210+
211+
content = content + "\n\n" + groupPartial
212+
*partialImports = append(*partialImports, group.File)
213+
}
214+
215+
if groupName, ok := fieldSchema.Extras[groupNameKey]; ok {
216+
group.Name = groupName.(string)
217+
}
218+
219+
group.Content = group.Content + fieldPartial
220+
*group.Imports = append(*group.Imports, fieldFile)
221+
} else {
222+
content = content + "\n\n" + fieldPartial
223+
*partialImports = append(*partialImports, fieldFile)
224+
}
115225
}
116226
}
117227
}
118228

119-
if prefix == "" {
120-
prefix = "reference"
121-
}
229+
for groupID, group := range groups {
230+
groupContent := group.Content
122231

123-
pageFile := fmt.Sprintf(configPartialBasePath+"%s/%s.mdx", latest.Version, strings.TrimSuffix(prefix, "/"))
232+
if group.Name != "" {
233+
groupContent = "\n" + `<div className="group-name">` + group.Name + `</div>` + "\n\n" + groupContent
234+
}
124235

125-
importContent := ""
126-
for _, partialImport := range *partialImports {
127-
partialImportPath, err := filepath.Rel(filepath.Dir(pageFile), partialImport)
236+
groupImportContent := ""
237+
for _, partialFile := range *group.Imports {
238+
groupImportContent = groupImportContent + GetPartialImport(partialFile, group.File)
239+
}
240+
241+
if groupImportContent != "" {
242+
groupImportContent = groupImportContent + "\n\n"
243+
}
244+
245+
groupFileContent := fmt.Sprintf(`%s<div className="group" data-group="%s">%s`+"\n"+`</div>`, groupImportContent, groupID, groupContent)
246+
247+
err := os.MkdirAll(filepath.Dir(group.File), os.ModePerm)
128248
if err != nil {
129249
panic(err)
130250
}
131251

132-
if partialImportPath[0:1] != "." {
133-
partialImportPath = "./" + partialImportPath
252+
err = ioutil.WriteFile(group.File, []byte(groupFileContent), os.ModePerm)
253+
if err != nil {
254+
panic(err)
134255
}
256+
}
257+
258+
if prefix == "" {
259+
prefix = "reference"
260+
}
135261

136-
importContent = importContent + fmt.Sprintf(util.TemplatePartialImport, util.GetPartialImportName(partialImport), partialImportPath)
262+
pageFile := fmt.Sprintf(configPartialBasePath+"%s/%s.mdx", latest.Version, strings.TrimSuffix(prefix, "/"))
263+
264+
importContent := ""
265+
for _, partialFile := range *partialImports {
266+
importContent = importContent + GetPartialImport(partialFile, pageFile)
137267
}
138268

139269
content = fmt.Sprintf("%s%s", importContent, content)
@@ -148,6 +278,40 @@ func createSections(prefix string, schema *jsonschema.Schema, definitions jsonsc
148278
return content
149279
}
150280

281+
func GetPartialImport(partialFile, importingFile string) string {
282+
partialImportPath, err := filepath.Rel(filepath.Dir(importingFile), partialFile)
283+
if err != nil {
284+
panic(err)
285+
}
286+
287+
if partialImportPath[0:1] != "." {
288+
partialImportPath = "./" + partialImportPath
289+
}
290+
291+
return fmt.Sprintf(util.TemplatePartialImport, util.GetPartialImportName(partialFile), partialImportPath)
292+
}
293+
294+
func GetEumValues(fieldSchema *jsonschema.Schema, required bool, fieldDefault *string) string {
295+
enumValues := ""
296+
if fieldSchema.Enum != nil {
297+
for i, enumVal := range fieldSchema.Enum {
298+
enumValString, ok := enumVal.(string)
299+
if ok {
300+
if i == 0 && !required && *fieldDefault == "" {
301+
*fieldDefault = enumValString
302+
}
303+
304+
if enumValues != "" {
305+
enumValues = enumValues + "<br/>"
306+
}
307+
enumValues = enumValues + enumValString
308+
}
309+
}
310+
enumValues = fmt.Sprintf("<span>%s</span>", enumValues)
311+
}
312+
return enumValues
313+
}
314+
151315
func contains(s []string, e string) bool {
152316
for _, a := range s {
153317
if a == e {

docs/hack/util/templates.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ const TemplateConfigField = `
3939
<details className="config-field" data-expandable="%t"%s>
4040
<summary>
4141
42-
%s` + "`%s`" + ` <span class="config-field-required" data-required="%t">required</span> <span class="config-field-type">%s</span> <span class="config-field-default">%s</span>
42+
%s` + "`%s`" + ` <span class="config-field-required" data-required="%t">required</span> <span class="config-field-type">%s</span> <span class="config-field-default">%s</span> <span class="config-field-enum">%s</span>
4343
4444
%s
4545
Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,24 @@
11

22
import PartialCommand from "./commands/command.mdx"
3-
import PartialAfter from "./commands/after.mdx"
4-
import PartialDisableReplace from "./commands/disableReplace.mdx"
5-
import PartialInternal from "./commands/internal.mdx"
63
import PartialArgs from "./commands/args.mdx"
74
import PartialAppendArgs from "./commands/appendArgs.mdx"
85
import PartialDescription from "./commands/description.mdx"
6+
import PartialInternal from "./commands/internal.mdx"
7+
import PartialAfter from "./commands/after.mdx"
98

109
<PartialCommand />
1110

1211

13-
<PartialAfter />
14-
15-
16-
<PartialDisableReplace />
12+
<PartialArgs />
1713

1814

19-
<PartialInternal />
15+
<PartialAppendArgs />
2016

2117

22-
<PartialArgs />
18+
<PartialDescription />
2319

2420

25-
<PartialAppendArgs />
21+
<PartialInternal />
2622

2723

28-
<PartialDescription />
24+
<PartialAfter />

docs/pages/configuration/_partials/v2beta1/commands/after.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
<details className="config-field" data-expandable="false" open>
33
<summary>
44

5-
### `after` <span class="config-field-required" data-required="false">required</span> <span class="config-field-type">string</span> <span class="config-field-default"></span>
5+
### `after` <span class="config-field-required" data-required="false">required</span> <span class="config-field-type">string</span> <span class="config-field-default"></span> <span class="config-field-enum"></span>
66

77
After is executed after the command was run. It is executed also when
88
the command was interrupted which will set the env variable COMMAND_INTERRUPT

docs/pages/configuration/_partials/v2beta1/commands/appendArgs.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
<details className="config-field" data-expandable="false" open>
33
<summary>
44

5-
### `appendArgs` <span class="config-field-required" data-required="false">required</span> <span class="config-field-type">boolean</span> <span class="config-field-default"></span>
5+
### `appendArgs` <span class="config-field-required" data-required="false">required</span> <span class="config-field-type">boolean</span> <span class="config-field-default">false</span> <span class="config-field-enum"></span>
66

77
AppendArgs will append arguments passed to the DevSpace command automatically to
88
the specified command.

docs/pages/configuration/_partials/v2beta1/commands/args.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
<details className="config-field" data-expandable="false" open>
33
<summary>
44

5-
### `args` <span class="config-field-required" data-required="false">required</span> <span class="config-field-type">string[]</span> <span class="config-field-default"></span>
5+
### `args` <span class="config-field-required" data-required="false">required</span> <span class="config-field-type">string[]</span> <span class="config-field-default"></span> <span class="config-field-enum"></span>
66

77
Args are optional and if defined, command is not executed within a shell
88
and rather directly.

docs/pages/configuration/_partials/v2beta1/commands/command.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
<details className="config-field" data-expandable="false" open>
33
<summary>
44

5-
### `command` <span class="config-field-required" data-required="true">required</span> <span class="config-field-type">string</span> <span class="config-field-default"></span>
5+
### `command` <span class="config-field-required" data-required="true">required</span> <span class="config-field-type">string</span> <span class="config-field-default"></span> <span class="config-field-enum"></span>
66

77
Command is the command that should be executed. For example: 'echo 123'
88

docs/pages/configuration/_partials/v2beta1/commands/description.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
<details className="config-field" data-expandable="false" open>
33
<summary>
44

5-
### `description` <span class="config-field-required" data-required="false">required</span> <span class="config-field-type">string</span> <span class="config-field-default"></span>
5+
### `description` <span class="config-field-required" data-required="false">required</span> <span class="config-field-type">string</span> <span class="config-field-default"></span> <span class="config-field-enum"></span>
66

77
Description describes what the command is doing and can be seen in `devspace list commands`
88

0 commit comments

Comments
 (0)