Codegen: Render constraints in generated docs (#63196)

* Add constraints rendering

* Generate docs

* Fix constraint format

* Add type alias

* Compare numbers as strings

* fixup! Compare numbers as strings

* Add missing return
This commit is contained in:
Tania
2023-02-10 12:40:50 +01:00
committed by GitHub
parent 7f6a1c06a6
commit f0333ac41f
11 changed files with 131 additions and 45 deletions

View File

@@ -60,7 +60,9 @@ func (j docsJenny) Generate(kind kindsys.Kind) (*codejen.File, error) {
Schemas json.RawMessage
}
}
err = json.Unmarshal(b, &obj)
dec := json.NewDecoder(bytes.NewReader(b))
dec.UseNumber()
err = dec.Decode(&obj)
if err != nil {
return nil, fmt.Errorf("failed to unmarshal schema json: %v", err)
}
@@ -109,8 +111,18 @@ type templateData struct {
// -------------------- JSON to Markdown conversion --------------------
// Copied from https://github.com/marcusolsson/json-schema-docs and slightly changed to fit the DocsJenny
type constraints struct {
Pattern string `json:"pattern"`
Maximum json.Number `json:"maximum"`
ExclusiveMinimum bool `json:"exclusiveMinimum"`
Minimum json.Number `json:"minimum"`
ExclusiveMaximum bool `json:"exclusiveMaximum"`
MinLength uint `json:"minLength"`
MaxLength uint `json:"maxLength"`
}
type schema struct {
constraints
ID string `json:"$id,omitempty"`
Ref string `json:"$ref,omitempty"`
Schema string `json:"$schema,omitempty"`
@@ -480,7 +492,14 @@ func makeRows(s *schema) [][]string {
rows := make([][]string, 0, len(s.Properties))
for key, p := range s.Properties {
typeStr := propTypeStr(key, p)
alias := propTypeAlias(p)
var typeStr string
if alias != "" {
typeStr = alias
} else {
typeStr = propTypeStr(key, p)
}
// Emphasize required properties.
var required string
@@ -491,7 +510,6 @@ func makeRows(s *schema) [][]string {
}
var desc string
if p.inheritedFrom != "" {
desc = fmt.Sprintf("*(Inherited from [%s](#%s))*", p.inheritedFrom, strings.ToLower(p.inheritedFrom))
}
@@ -512,6 +530,10 @@ func makeRows(s *schema) [][]string {
desc += fmt.Sprintf(" Default: `%v`.", p.Default)
}
// Render a constraint only if it's not a type alias https://cuelang.org/docs/references/spec/#predeclared-identifiers
if alias == "" {
desc += constraintDescr(p)
}
rows = append(rows, []string{fmt.Sprintf("`%s`", key), typeStr, required, formatForTable(desc)})
}
@@ -528,6 +550,70 @@ func makeRows(s *schema) [][]string {
return rows
}
func propTypeAlias(prop *schema) string {
if prop.Minimum == "" || prop.Maximum == "" {
return ""
}
min := prop.Minimum
max := prop.Maximum
switch {
case min == "0" && max == "255":
return "uint8"
case min == "0" && max == "65535":
return "uint16"
case min == "0" && max == "4294967295":
return "uint32"
case min == "0" && max == "18446744073709551615":
return "uint64"
case min == "-128" && max == "127":
return "int8"
case min == "-32768" && max == "32767":
return "int16"
case min == "-2147483648" && max == "2147483647":
return "int32"
case min == "-9223372036854775808" && max == "9223372036854775807":
return "int64"
default:
return ""
}
}
func constraintDescr(prop *schema) string {
if prop.Minimum != "" && prop.Maximum != "" {
var left, right string
if prop.ExclusiveMinimum {
left = ">" + prop.Minimum.String()
} else {
left = ">=" + prop.Minimum.String()
}
if prop.ExclusiveMaximum {
right = "<" + prop.Maximum.String()
} else {
right = "<=" + prop.Maximum.String()
}
return fmt.Sprintf("\nConstraint: `%s & %s`.", left, right)
}
if prop.MinLength > 0 {
left := fmt.Sprintf(">=%v", prop.MinLength)
right := ""
if prop.MaxLength > 0 {
right = fmt.Sprintf(" && <=%v", prop.MaxLength)
}
return fmt.Sprintf("\nConstraint: `length %s`.", left+right)
}
if prop.Pattern != "" {
return fmt.Sprintf("\nConstraint: must match `%s`.", prop.Pattern)
}
return ""
}
func propTypeStr(propName string, propValue *schema) string {
// If the property has AdditionalProperties, it is most likely a map type
if propValue.AdditionalProperties != nil {