7
7
A simple utility to translate JSON into a Go type definition.
8
8
*/
9
9
10
- function jsonToGo ( json , typename )
10
+ function jsonToGo ( json , typename , flatten = true )
11
11
{
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 = "" ;
16
21
17
22
try
18
23
{
@@ -28,25 +33,29 @@ function jsonToGo(json, typename)
28
33
}
29
34
30
35
typename = format ( typename || "AutoGenerated" ) ;
31
- append ( " type " + typename + " " ) ;
36
+ append ( ` type ${ typename } ` ) ;
32
37
33
38
parseScope ( scope ) ;
34
-
35
- return { go : go } ;
36
39
40
+ return {
41
+ go : flatten
42
+ ? go += accumulator
43
+ : go
44
+ } ;
37
45
38
46
39
- function parseScope ( scope )
47
+ function parseScope ( scope , depth = 0 )
40
48
{
41
49
if ( typeof scope === "object" && scope !== null )
42
50
{
43
51
if ( Array . isArray ( scope ) )
44
52
{
45
- var sliceType , scopeLength = scope . length ;
53
+ let sliceType ;
54
+ const scopeLength = scope . length ;
46
55
47
- for ( var i = 0 ; i < scopeLength ; i ++ )
56
+ for ( let i = 0 ; i < scopeLength ; i ++ )
48
57
{
49
- var thisType = goType ( scope [ i ] ) ;
58
+ const thisType = goType ( scope [ i ] ) ;
50
59
if ( ! sliceType )
51
60
sliceType = thisType ;
52
61
else if ( sliceType != thisType )
@@ -57,17 +66,20 @@ function jsonToGo(json, typename)
57
66
}
58
67
}
59
68
60
- append ( "[]" ) ;
69
+ if ( flatten && depth >= 2 )
70
+ appender ( "[]" ) ;
71
+ else
72
+ append ( "[]" )
61
73
if ( sliceType == "struct" ) {
62
- var allFields = { } ;
74
+ const allFields = { } ;
63
75
64
76
// for each field counts how many times appears
65
- for ( var i = 0 ; i < scopeLength ; i ++ )
77
+ for ( let i = 0 ; i < scopeLength ; i ++ )
66
78
{
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 )
69
81
{
70
- var keyname = keys [ k ] ;
82
+ const keyname = keys [ k ] ;
71
83
if ( ! ( keyname in allFields ) ) {
72
84
allFields [ keyname ] = {
73
85
value : scope [ i ] [ keyname ] ,
@@ -78,61 +90,117 @@ function jsonToGo(json, typename)
78
90
allFields [ keyname ] . count ++ ;
79
91
}
80
92
}
81
-
93
+
82
94
// create a common struct with all fields found in the current array
83
95
// 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 )
86
98
{
87
- var keyname = keys [ k ] , elem = allFields [ keyname ] ;
99
+ const keyname = keys [ k ] , elem = allFields [ keyname ] ;
88
100
89
101
struct [ keyname ] = elem . value ;
90
102
omitempty [ keyname ] = elem . count != scopeLength ;
91
103
}
92
-
93
- parseStruct ( struct , omitempty ) ; // finally parse the struct !!
104
+ parseStruct ( depth + 1 , innerTabs , struct , omitempty ) ; // finally parse the struct !!
94
105
}
95
106
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
+ }
97
115
}
98
- else
99
- append ( sliceType || "interface{}" ) ;
100
116
}
101
117
else
102
118
{
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 ) ) ;
104
136
}
105
137
}
106
- else
107
- append ( goType ( scope ) ) ;
108
138
}
109
139
110
- function parseStruct ( scope , omitempty )
140
+ function parseStruct ( depth , innerTabs , scope , omitempty )
111
141
{
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
+ }
121
149
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 )
124
156
{
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' ) ;
126
193
}
127
- append ( '"`\n' ) ;
194
+ indent ( -- tabs ) ;
195
+ append ( "}" ) ;
128
196
}
129
- indent ( -- tabs ) ;
130
- append ( "}" ) ;
197
+ if ( flatten )
198
+ accumulator += stack . pop ( ) ;
131
199
}
132
200
133
201
function indent ( tabs )
134
202
{
135
- for ( var i = 0 ; i < tabs ; i ++ )
203
+ for ( let i = 0 ; i < tabs ; i ++ )
136
204
go += '\t' ;
137
205
}
138
206
@@ -141,6 +209,17 @@ function jsonToGo(json, typename)
141
209
go += str ;
142
210
}
143
211
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
+
144
223
// Sanitizes and formats a string to make an appropriate identifier in Go
145
224
function format ( str )
146
225
{
@@ -150,7 +229,7 @@ function jsonToGo(json, typename)
150
229
str = "Num" + str ;
151
230
else if ( str . charAt ( 0 ) . match ( / \d / ) )
152
231
{
153
- var numbers = { '0' : "Zero_" , '1' : "One_" , '2' : "Two_" , '3' : "Three_" ,
232
+ const numbers = { '0' : "Zero_" , '1' : "One_" , '2' : "Two_" , '3' : "Three_" ,
154
233
'4' : "Four_" , '5' : "Five_" , '6' : "Six_" , '7' : "Seven_" ,
155
234
'8' : "Eight_" , '9' : "Nine_" } ;
156
235
str = numbers [ str . charAt ( 0 ) ] + str . substr ( 1 ) ;
@@ -163,7 +242,7 @@ function jsonToGo(json, typename)
163
242
{
164
243
if ( val === null )
165
244
return "interface{}" ;
166
-
245
+
167
246
switch ( typeof val )
168
247
{
169
248
case "string" :
@@ -209,10 +288,10 @@ function jsonToGo(json, typename)
209
288
function toProperCase ( str )
210
289
{
211
290
// 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" ,
216
295
"URL" , "UTF8" , "VM" , "XML" , "XSRF" , "XSS"
217
296
] ;
218
297
@@ -235,10 +314,10 @@ function jsonToGo(json, typename)
235
314
if ( typeof module != 'undefined' ) {
236
315
if ( ! module . parent ) {
237
316
process . stdin . on ( 'data' , function ( buf ) {
238
- var json = buf . toString ( 'utf8' )
317
+ const json = buf . toString ( 'utf8' )
239
318
console . log ( jsonToGo ( json ) . go )
240
319
} )
241
320
} else {
242
321
module . exports = jsonToGo
243
322
}
244
- }
323
+ }
0 commit comments