-
Notifications
You must be signed in to change notification settings - Fork 0
Implement ordering for parameters #15
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -179,6 +179,7 @@ type Node struct { | |
| Comment string | ||
| Parent *Node | ||
| Child map[string]*Node | ||
| Order int | ||
| } | ||
|
|
||
| func newNode(name string, p *Node) *Node { | ||
|
|
@@ -196,6 +197,7 @@ func ensure(root *Node, name string) *Node { | |
|
|
||
| func Build(rows []Raw) *Node { | ||
| root := newNode("Config", nil) | ||
| orderCounter := 0 | ||
| isPrim := func(s string) bool { return isPrimitive(strings.TrimPrefix(s, "*")) } | ||
| addImplicit := func(name string) { | ||
| if name == "" || isPrim(name) || strings.HasPrefix(name, "[]") || strings.HasPrefix(name, "map[") { | ||
|
|
@@ -222,6 +224,8 @@ func Build(rows []Raw) *Node { | |
| if i == len(r.Path)-1 { | ||
| if r.K == kParam { | ||
| cur.IsParam = true | ||
| cur.Order = orderCounter | ||
| orderCounter++ | ||
| } | ||
| cur.TypeExpr = r.TypeExpr | ||
| cur.Comment = r.Description | ||
|
|
@@ -260,6 +264,11 @@ type gen struct { | |
| def map[string]bool | ||
| } | ||
|
|
||
| // NewGen creates a new generator instance | ||
| func NewGen(pkg string) *gen { | ||
| return &gen{pkg: pkg} | ||
| } | ||
|
|
||
| func (g *gen) addImpAlias(path, alias string) { | ||
| if g.imp == nil { | ||
| g.imp = map[string]string{} | ||
|
|
@@ -422,7 +431,7 @@ func (g *gen) writeStruct(n *Node) { | |
| g.buf.WriteString("}\n\n") | ||
|
|
||
| g.buf.WriteString("type ConfigSpec struct {\n") | ||
| keys := sortedKeys(n.Child) | ||
| keys := sortedKeysByOrder(n.Child) | ||
| for _, k := range keys { | ||
| c := n.Child[k] | ||
| if !c.IsParam { | ||
|
|
@@ -448,7 +457,7 @@ func (g *gen) writeStruct(n *Node) { | |
| } | ||
|
|
||
| g.buf.WriteString(fmt.Sprintf("type %s struct {\n", name)) | ||
| keys := sortedKeys(n.Child) | ||
| keys := sortedKeysByOrder(n.Child) | ||
| for _, k := range keys { | ||
| g.emitField(n.Child[k]) | ||
| } | ||
|
|
@@ -566,6 +575,22 @@ func sortedKeys[M ~map[K]V, K comparable, V any](m M) []K { | |
| return keys | ||
| } | ||
|
|
||
| func sortedKeysByOrder(nodes map[string]*Node) []string { | ||
| keys := make([]string, 0, len(nodes)) | ||
| for k := range nodes { | ||
| keys = append(keys, k) | ||
| } | ||
| sort.Slice(keys, func(i, j int) bool { | ||
| nodeI := nodes[keys[i]] | ||
| nodeJ := nodes[keys[j]] | ||
| if nodeI.Order != 0 || nodeJ.Order != 0 { | ||
| return nodeI.Order < nodeJ.Order | ||
| } | ||
| return keys[i] < keys[j] | ||
| }) | ||
| return keys | ||
| } | ||
|
|
||
| /* -------------------------------------------------------------------------- */ | ||
| /* Temporary project scaffolding */ | ||
| /* -------------------------------------------------------------------------- */ | ||
|
|
@@ -744,6 +769,10 @@ func CG(pkgDir string) ([]byte, error) { | |
| /* -------------------------------------------------------------------------- */ | ||
|
|
||
| func WriteValuesSchema(crdBytes []byte, outPath string) error { | ||
| return WriteValuesSchemaWithOrder(crdBytes, outPath, nil) | ||
| } | ||
|
|
||
| func WriteValuesSchemaWithOrder(crdBytes []byte, outPath string, root *Node) error { | ||
| docs := bytes.Split(crdBytes, []byte("\n---")) | ||
| if len(docs) == 0 { | ||
| return fmt.Errorf("empty CRD data") | ||
|
|
@@ -758,6 +787,42 @@ func WriteValuesSchema(crdBytes []byte, outPath string) error { | |
| } | ||
|
|
||
| specSchema := obj.Spec.Versions[0].Schema.OpenAPIV3Schema.Properties["spec"] | ||
|
|
||
| if root != nil { | ||
| keys := sortedKeysByOrder(root.Child) | ||
|
|
||
| var buf bytes.Buffer | ||
| buf.WriteString("{\n") | ||
| buf.WriteString(" \"title\": \"Chart Values\",\n") | ||
| buf.WriteString(" \"type\": \"object\",\n") | ||
| buf.WriteString(" \"properties\": {\n") | ||
|
|
||
| first := true | ||
| for _, key := range keys { | ||
| if node, exists := root.Child[key]; exists && node.IsParam { | ||
| if prop, exists := specSchema.Properties[key]; exists { | ||
| if !first { | ||
| buf.WriteString(",\n") | ||
| } | ||
| first = false | ||
|
|
||
| propJSON, err := json.MarshalIndent(prop, " ", " ") | ||
| if err != nil { | ||
| return err | ||
| } | ||
|
|
||
| buf.WriteString(fmt.Sprintf(" \"%s\": %s", key, string(propJSON))) | ||
|
Comment on lines
+809
to
+814
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The manual JSON generation for properties results in incorrect indentation in the output To produce a correctly formatted JSON, you can marshal the property without a prefix and then manually handle the indentation to align it properly under its key. propJSON, err := json.MarshalIndent(prop, "", " ")
if err != nil {
return err
}
// Manually indent the property JSON to align correctly.
lines := strings.Split(string(propJSON), "\n")
buf.WriteString(fmt.Sprintf(" \"%s\": %s", key, lines[0]))
for _, line := range lines[1:] {
buf.WriteString("\n " + line)
} |
||
| } | ||
| } | ||
| } | ||
|
|
||
| buf.WriteString("\n }\n") | ||
| buf.WriteString("}\n") | ||
|
|
||
| return os.WriteFile(outPath, buf.Bytes(), 0o644) | ||
| } | ||
|
|
||
| // Fallback | ||
| out := struct { | ||
| Title string `json:"title"` | ||
| Type string `json:"type"` | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The sorting logic in
sortedKeysByOrderis flawed and doesn't correctly order parameters.Order = 0, which is the same as the default for non-parameter fields. When comparing this parameter with a non-parameter, theif nodeI.Order != 0 || nodeJ.Order != 0condition is false, causing it to fall back to alphabetical sorting. This is incorrect.Order > 0against a non-parameter withOrder = 0, the conditionnodeI.Order < nodeJ.Orderwill be false, causing the non-parameter to be sorted first.A more robust approach is to use the
IsParamboolean field, which clearly distinguishes parameters from other fields. This ensures parameters are always sorted before non-parameters, and then by their specified order.