77 A simple utility to translate JSON into a Go type definition.
88*/
99
10- function jsonToGo ( json , typename )
10+ function jsonToGo ( json , typename , flatten = true )
1111{
12- var data ;
13- var scope ;
14- var go = "" ;
15- var tabs = 0 ;
12+ let data ;
13+ let scope ;
14+ let go = "" ;
15+ let tabs = 0 ;
16+
17+ let accumulator = "" ;
18+ let innerTabs = 0 ;
19+ let stack = [ ] ;
20+ let parent = "" ;
1621
1722 try
1823 {
@@ -28,25 +33,29 @@ function jsonToGo(json, typename)
2833 }
2934
3035 typename = format ( typename || "AutoGenerated" ) ;
31- append ( " type " + typename + " " ) ;
36+ append ( ` type ${ typename } ` ) ;
3237
3338 parseScope ( scope ) ;
34-
35- return { go : go } ;
3639
40+ return {
41+ go : flatten
42+ ? go += accumulator
43+ : go
44+ } ;
3745
3846
39- function parseScope ( scope )
47+ function parseScope ( scope , depth = 0 )
4048 {
4149 if ( typeof scope === "object" && scope !== null )
4250 {
4351 if ( Array . isArray ( scope ) )
4452 {
45- var sliceType , scopeLength = scope . length ;
53+ let sliceType ;
54+ const scopeLength = scope . length ;
4655
47- for ( var i = 0 ; i < scopeLength ; i ++ )
56+ for ( let i = 0 ; i < scopeLength ; i ++ )
4857 {
49- var thisType = goType ( scope [ i ] ) ;
58+ const thisType = goType ( scope [ i ] ) ;
5059 if ( ! sliceType )
5160 sliceType = thisType ;
5261 else if ( sliceType != thisType )
@@ -57,17 +66,20 @@ function jsonToGo(json, typename)
5766 }
5867 }
5968
60- append ( "[]" ) ;
69+ if ( flatten && depth >= 2 )
70+ appender ( "[]" ) ;
71+ else
72+ append ( "[]" )
6173 if ( sliceType == "struct" ) {
62- var allFields = { } ;
74+ const allFields = { } ;
6375
6476 // for each field counts how many times appears
65- for ( var i = 0 ; i < scopeLength ; i ++ )
77+ for ( let i = 0 ; i < scopeLength ; i ++ )
6678 {
67- var keys = Object . keys ( scope [ i ] )
68- for ( var k in keys )
79+ const keys = Object . keys ( scope [ i ] )
80+ for ( let k in keys )
6981 {
70- var keyname = keys [ k ] ;
82+ const keyname = keys [ k ] ;
7183 if ( ! ( keyname in allFields ) ) {
7284 allFields [ keyname ] = {
7385 value : scope [ i ] [ keyname ] ,
@@ -78,61 +90,117 @@ function jsonToGo(json, typename)
7890 allFields [ keyname ] . count ++ ;
7991 }
8092 }
81-
93+
8294 // create a common struct with all fields found in the current array
8395 // omitempty dict indicates if a field is optional
84- var keys = Object . keys ( allFields ) , struct = { } , omitempty = { } ;
85- for ( var k in keys )
96+ const keys = Object . keys ( allFields ) , struct = { } , omitempty = { } ;
97+ for ( let k in keys )
8698 {
87- var keyname = keys [ k ] , elem = allFields [ keyname ] ;
99+ const keyname = keys [ k ] , elem = allFields [ keyname ] ;
88100
89101 struct [ keyname ] = elem . value ;
90102 omitempty [ keyname ] = elem . count != scopeLength ;
91103 }
92-
93- parseStruct ( struct , omitempty ) ; // finally parse the struct !!
104+ parseStruct ( depth + 1 , innerTabs , struct , omitempty ) ; // finally parse the struct !!
94105 }
95106 else if ( sliceType == "slice" ) {
96- parseScope ( scope [ 0 ] )
107+ parseScope ( scope [ 0 ] , depth )
108+ }
109+ else {
110+ if ( flatten && depth >= 2 ) {
111+ appender ( sliceType || "interface{}" ) ;
112+ } else {
113+ append ( sliceType || "interface{}" ) ;
114+ }
97115 }
98- else
99- append ( sliceType || "interface{}" ) ;
100116 }
101117 else
102118 {
103- parseStruct ( scope ) ;
119+ if ( flatten ) {
120+ if ( depth >= 2 ) {
121+ appender ( parent )
122+ }
123+ else {
124+ append ( parent )
125+ }
126+ }
127+ parseStruct ( depth + 1 , innerTabs , scope ) ;
128+ }
129+ }
130+ else {
131+ if ( depth >= 2 ) {
132+ appender ( goType ( scope ) ) ;
133+ }
134+ else {
135+ append ( goType ( scope ) ) ;
104136 }
105137 }
106- else
107- append ( goType ( scope ) ) ;
108138 }
109139
110- function parseStruct ( scope , omitempty )
140+ function parseStruct ( depth , innerTabs , scope , omitempty )
111141 {
112- append ( "struct {\n" ) ;
113- ++ tabs ;
114- var keys = Object . keys ( scope ) ;
115- for ( var i in keys )
116- {
117- var keyname = keys [ i ] ;
118- indent ( tabs ) ;
119- append ( format ( keyname ) + " " ) ;
120- parseScope ( scope [ keyname ] ) ;
142+ if ( flatten ) {
143+ stack . push (
144+ depth >= 2
145+ ? "\n"
146+ : ""
147+ )
148+ }
121149
122- append ( ' `json:"' + keyname ) ;
123- if ( omitempty && omitempty [ keyname ] === true )
150+ if ( flatten && depth >= 2 )
151+ {
152+ appender ( `type ${ parent } ` + "struct {\n" ) ;
153+ ++ innerTabs ;
154+ const keys = Object . keys ( scope ) ;
155+ for ( let i in keys )
124156 {
125- append ( ',omitempty' ) ;
157+ const keyname = keys [ i ] ;
158+ indenter ( innerTabs )
159+ const typename = format ( keyname )
160+ appender ( typename + " " ) ;
161+ parent = typename
162+ parseScope ( scope [ keyname ] , depth ) ;
163+ appender ( ' `json:"' + keyname ) ;
164+ if ( omitempty && omitempty [ keyname ] === true )
165+ {
166+ appender ( ',omitempty' ) ;
167+ }
168+ appender ( '"`\n' ) ;
169+ }
170+ indenter ( -- innerTabs ) ;
171+ appender ( "}" ) ;
172+ }
173+ else
174+ {
175+ append ( "struct {\n" ) ;
176+ ++ tabs ;
177+ const keys = Object . keys ( scope ) ;
178+ for ( let i in keys )
179+ {
180+ const keyname = keys [ i ] ;
181+ indent ( tabs ) ;
182+ const typename = format ( keyname ) ;
183+ append ( typename + " " ) ;
184+ parent = typename
185+ parseScope ( scope [ keyname ] , depth ) ;
186+
187+ append ( ' `json:"' + keyname ) ;
188+ if ( omitempty && omitempty [ keyname ] === true )
189+ {
190+ append ( ',omitempty' ) ;
191+ }
192+ append ( '"`\n' ) ;
126193 }
127- append ( '"`\n' ) ;
194+ indent ( -- tabs ) ;
195+ append ( "}" ) ;
128196 }
129- indent ( -- tabs ) ;
130- append ( "}" ) ;
197+ if ( flatten )
198+ accumulator += stack . pop ( ) ;
131199 }
132200
133201 function indent ( tabs )
134202 {
135- for ( var i = 0 ; i < tabs ; i ++ )
203+ for ( let i = 0 ; i < tabs ; i ++ )
136204 go += '\t' ;
137205 }
138206
@@ -141,6 +209,17 @@ function jsonToGo(json, typename)
141209 go += str ;
142210 }
143211
212+ function indenter ( tabs )
213+ {
214+ for ( let i = 0 ; i < tabs ; i ++ )
215+ stack [ stack . length - 1 ] += '\t' ;
216+ }
217+
218+ function appender ( str )
219+ {
220+ stack [ stack . length - 1 ] += str ;
221+ }
222+
144223 // Sanitizes and formats a string to make an appropriate identifier in Go
145224 function format ( str )
146225 {
@@ -150,7 +229,7 @@ function jsonToGo(json, typename)
150229 str = "Num" + str ;
151230 else if ( str . charAt ( 0 ) . match ( / \d / ) )
152231 {
153- var numbers = { '0' : "Zero_" , '1' : "One_" , '2' : "Two_" , '3' : "Three_" ,
232+ const numbers = { '0' : "Zero_" , '1' : "One_" , '2' : "Two_" , '3' : "Three_" ,
154233 '4' : "Four_" , '5' : "Five_" , '6' : "Six_" , '7' : "Seven_" ,
155234 '8' : "Eight_" , '9' : "Nine_" } ;
156235 str = numbers [ str . charAt ( 0 ) ] + str . substr ( 1 ) ;
@@ -163,7 +242,7 @@ function jsonToGo(json, typename)
163242 {
164243 if ( val === null )
165244 return "interface{}" ;
166-
245+
167246 switch ( typeof val )
168247 {
169248 case "string" :
@@ -209,10 +288,10 @@ function jsonToGo(json, typename)
209288 function toProperCase ( str )
210289 {
211290 // https://github.com/golang/lint/blob/39d15d55e9777df34cdffde4f406ab27fd2e60c0/lint.go#L695-L731
212- var commonInitialisms = [
213- "API" , "ASCII" , "CPU" , "CSS" , "DNS" , "EOF" , "GUID" , "HTML" , "HTTP" ,
214- "HTTPS" , "ID" , "IP" , "JSON" , "LHS" , "QPS" , "RAM" , "RHS" , "RPC" , "SLA" ,
215- "SMTP" , "SSH" , "TCP" , "TLS" , "TTL" , "UDP" , "UI" , "UID" , "UUID" , "URI" ,
291+ const commonInitialisms = [
292+ "API" , "ASCII" , "CPU" , "CSS" , "DNS" , "EOF" , "GUID" , "HTML" , "HTTP" ,
293+ "HTTPS" , "ID" , "IP" , "JSON" , "LHS" , "QPS" , "RAM" , "RHS" , "RPC" , "SLA" ,
294+ "SMTP" , "SSH" , "TCP" , "TLS" , "TTL" , "UDP" , "UI" , "UID" , "UUID" , "URI" ,
216295 "URL" , "UTF8" , "VM" , "XML" , "XSRF" , "XSS"
217296 ] ;
218297
@@ -235,10 +314,10 @@ function jsonToGo(json, typename)
235314if ( typeof module != 'undefined' ) {
236315 if ( ! module . parent ) {
237316 process . stdin . on ( 'data' , function ( buf ) {
238- var json = buf . toString ( 'utf8' )
317+ const json = buf . toString ( 'utf8' )
239318 console . log ( jsonToGo ( json ) . go )
240319 } )
241320 } else {
242321 module . exports = jsonToGo
243322 }
244- }
323+ }
0 commit comments