@@ -3,27 +3,33 @@ package main
33import (
44 "bytes"
55 "encoding/json"
6+ "errors"
67 "fmt"
78 "io"
89 "io/ioutil"
910 "sort"
1011 "strings"
1112
13+ "github.com/bitly/go-simplejson"
1214 "github.com/olekukonko/tablewriter"
1315)
1416
17+ var errCrossSchemaReference = errors .New ("cross-schema reference" )
18+
1519type schema struct {
16- ID string `json:"$id"`
17- Schema string `json:"$schema"`
18- Title string `json:"title"`
19- Description string `json:"description"`
20- Required []string `json:"required"`
21- Type string `json:"type"`
22- Properties map [string ]schema `json:"properties"`
23- Items * schema `json:"items"`
20+ ID string `json:"$id,omitempty"`
21+ Ref string `json:"$ref,omitempty"`
22+ Schema string `json:"$schema,omitempty"`
23+ Title string `json:"title,omitempty"`
24+ Description string `json:"description,omitempty"`
25+ Required []string `json:"required,omitempty"`
26+ Type string `json:"type,omitempty"`
27+ Properties map [string ]* schema `json:"properties,omitempty"`
28+ Items * schema `json:"items,omitempty"`
29+ Definitions map [string ]* schema `json:"definitions,omitempty"`
2430}
2531
26- func newSchema (r io.Reader ) (* schema , error ) {
32+ func newSchema (r io.Reader , workingDir string ) (* schema , error ) {
2733 b , err := ioutil .ReadAll (r )
2834 if err != nil {
2935 return nil , err
@@ -34,7 +40,13 @@ func newSchema(r io.Reader) (*schema, error) {
3440 return nil , err
3541 }
3642
37- return & data , nil
43+ // Needed for resolving in-schema references.
44+ root , err := simplejson .NewJson (b )
45+ if err != nil {
46+ return nil , err
47+ }
48+
49+ return resolveSchema (& data , workingDir , root )
3850}
3951
4052// Markdown returns the Markdown representation of the schema.
@@ -63,20 +75,22 @@ func (s schema) Markdown(level int) string {
6375 fmt .Fprintln (& buf )
6476 }
6577
66- table := tablewriter .NewWriter (& buf )
67- table .SetHeader ([]string {"Property" , "Type" , "Required" , "Description" })
68- table .SetBorders (tablewriter.Border {Left : true , Top : false , Right : true , Bottom : false })
69- table .SetCenterSeparator ("|" )
70- table .SetAutoFormatHeaders (false )
71- table .SetHeaderAlignment (tablewriter .ALIGN_LEFT )
72- table .SetAutoWrapText (false )
78+ printProperties (& buf , & s )
79+
80+ // Add padding.
81+ fmt .Fprintln (& buf )
7382
83+ for _ , obj := range findDefinitions (& s ) {
84+ fmt .Fprintf (& buf , obj .Markdown (level + 1 ))
85+ }
86+
87+ return buf .String ()
88+ }
89+
90+ func findDefinitions (s * schema ) []* schema {
7491 // Gather all properties of object type so that we can generate the
7592 // properties for them recursively.
76- var objs []schema
77-
78- // Buffer all property rows so that we can sort them before printing them.
79- var rows [][]string
93+ var objs []* schema
8094
8195 for k , p := range s .Properties {
8296 // Use the identifier as the title.
@@ -87,21 +101,49 @@ func (s schema) Markdown(level int) string {
87101
88102 // If the property is an array of objects, use the name of the array
89103 // property as the title.
90- if p .Type == "array" && p .Items != nil {
91- if p .Items .Type == "object" {
92- p .Items .Title = k
93- objs = append (objs , * p .Items )
104+ if p .Type == "array" {
105+ if p .Items != nil {
106+ if p .Items .Type == "object" {
107+ p .Items .Title = k
108+ objs = append (objs , p .Items )
109+ }
94110 }
95111 }
112+ }
96113
114+ // Sort the object schemas.
115+ sort .Slice (objs , func (i , j int ) bool {
116+ return objs [i ].Title < objs [j ].Title
117+ })
118+
119+ return objs
120+ }
121+
122+ func printProperties (w io.Writer , s * schema ) {
123+ table := tablewriter .NewWriter (w )
124+ table .SetHeader ([]string {"Property" , "Type" , "Required" , "Description" })
125+ table .SetBorders (tablewriter.Border {Left : true , Top : false , Right : true , Bottom : false })
126+ table .SetCenterSeparator ("|" )
127+ table .SetAutoFormatHeaders (false )
128+ table .SetHeaderAlignment (tablewriter .ALIGN_LEFT )
129+ table .SetAutoWrapText (false )
130+
131+ // Buffer all property rows so that we can sort them before printing them.
132+ var rows [][]string
133+
134+ for k , p := range s .Properties {
97135 // Generate relative links for objects and arrays of objects.
98136 var propType string
99137 switch p .Type {
100138 case "object" :
101139 propType = fmt .Sprintf ("[%s](#%s)" , p .Type , strings .ToLower (k ))
102140 case "array" :
103141 if p .Items != nil {
104- propType = fmt .Sprintf ("[%s](#%s)" , p .Type , strings .ToLower (k ))
142+ if p .Items .Type == "object" {
143+ propType = fmt .Sprintf ("[%s](#%s)[]" , p .Items .Type , strings .ToLower (k ))
144+ } else {
145+ propType = fmt .Sprintf ("%s[]" , p .Items .Type )
146+ }
105147 } else {
106148 propType = p .Type
107149 }
@@ -133,19 +175,6 @@ func (s schema) Markdown(level int) string {
133175
134176 table .AppendBulk (rows )
135177 table .Render ()
136-
137- // Add padding.
138- fmt .Fprintln (& buf )
139-
140- // Sort the object schemas before recursing.
141- sort .Slice (objs , func (i , j int ) bool {
142- return objs [i ].Title < objs [j ].Title
143- })
144- for _ , obj := range objs {
145- fmt .Fprintf (& buf , obj .Markdown (level + 1 ))
146- }
147-
148- return buf .String ()
149178}
150179
151180// in returns true if a string slice contains a specific string.
0 commit comments