@@ -169,6 +169,8 @@ function jsonToGo(json, typename, flatten = true)
169169 )
170170 }
171171
172+ const seenTypeNames = [ ] ;
173+
172174 if ( flatten && depth >= 2 )
173175 {
174176 const parentType = `type ${ parent } ` ;
@@ -190,7 +192,9 @@ function jsonToGo(json, typename, flatten = true)
190192 {
191193 const keyname = getOriginalName ( keys [ i ] ) ;
192194 indenter ( innerTabs )
193- const typename = format ( keyname )
195+ const typename = uniqueTypeName ( format ( keyname ) , seenTypeNames )
196+ seenTypeNames . push ( typename )
197+
194198 appender ( typename + " " ) ;
195199 parent = typename
196200 parseScope ( scope [ keys [ i ] ] , depth ) ;
@@ -213,7 +217,8 @@ function jsonToGo(json, typename, flatten = true)
213217 {
214218 const keyname = getOriginalName ( keys [ i ] ) ;
215219 indent ( tabs ) ;
216- const typename = format ( keyname ) ;
220+ const typename = uniqueTypeName ( format ( keyname ) , seenTypeNames )
221+ seenTypeNames . push ( typename )
217222 append ( typename + " " ) ;
218223 parent = typename
219224 parseScope ( scope [ keys [ i ] ] , depth ) ;
@@ -253,9 +258,41 @@ function jsonToGo(json, typename, flatten = true)
253258 stack [ stack . length - 1 ] += str ;
254259 }
255260
261+ // Generate a unique name to avoid duplicate struct field names.
262+ // This function appends a number at the end of the field name.
263+ function uniqueTypeName ( name , seen ) {
264+ if ( seen . indexOf ( name ) === - 1 ) {
265+ return name ;
266+ }
267+
268+ let i = 0 ;
269+ while ( true ) {
270+ let newName = name + i . toString ( ) ;
271+ if ( seen . indexOf ( newName ) === - 1 ) {
272+ return newName ;
273+ }
274+
275+ i ++ ;
276+ }
277+ }
278+
256279 // Sanitizes and formats a string to make an appropriate identifier in Go
257280 function format ( str )
258281 {
282+ str = formatNumber ( str ) ;
283+
284+ let sanitized = toProperCase ( str ) . replace ( / [ ^ a - z 0 - 9 ] / ig, "" )
285+ if ( ! sanitized ) {
286+ return "NAMING_FAILED" ;
287+ }
288+
289+ // After sanitizing the remaining characters can start with a number.
290+ // Run the sanitized string again trough formatNumber to make sure the identifier is Num[0-9] or Zero_... instead of 1.
291+ return formatNumber ( sanitized )
292+ }
293+
294+ // Adds a prefix to a number to make an appropriate identifier in Go
295+ function formatNumber ( str ) {
259296 if ( ! str )
260297 return "" ;
261298 else if ( str . match ( / ^ \d + $ / ) )
@@ -267,7 +304,8 @@ function jsonToGo(json, typename, flatten = true)
267304 '8' : "Eight_" , '9' : "Nine_" } ;
268305 str = numbers [ str . charAt ( 0 ) ] + str . substr ( 1 ) ;
269306 }
270- return toProperCase ( str ) . replace ( / [ ^ a - z 0 - 9 ] / ig, "" ) || "NAMING_FAILED" ;
307+
308+ return str ;
271309 }
272310
273311 // Determines the most appropriate Go type
@@ -324,12 +362,12 @@ function jsonToGo(json, typename, flatten = true)
324362 if ( str . match ( / ^ [ _ A - Z 0 - 9 ] + $ / ) ) {
325363 str = str . toLowerCase ( ) ;
326364 }
327-
365+
328366 // https://github.com/golang/lint/blob/5614ed5bae6fb75893070bdc0996a68765fdd275/lint.go#L771-L810
329367 const commonInitialisms = [
330- "ACL" , "API" , "ASCII" , "CPU" , "CSS" , "DNS" , "EOF" , "GUID" , "HTML" , "HTTP" ,
331- "HTTPS" , "ID" , "IP" , "JSON" , "LHS" , "QPS" , "RAM" , "RHS" , "RPC" , "SLA" ,
332- "SMTP" , "SQL" , "SSH" , "TCP" , "TLS" , "TTL" , "UDP" , "UI" , "UID" , "UUID" ,
368+ "ACL" , "API" , "ASCII" , "CPU" , "CSS" , "DNS" , "EOF" , "GUID" , "HTML" , "HTTP" ,
369+ "HTTPS" , "ID" , "IP" , "JSON" , "LHS" , "QPS" , "RAM" , "RHS" , "RPC" , "SLA" ,
370+ "SMTP" , "SQL" , "SSH" , "TCP" , "TLS" , "TTL" , "UDP" , "UI" , "UID" , "UUID" ,
333371 "URI" , "URL" , "UTF8" , "VM" , "XML" , "XMPP" , "XSRF" , "XSS"
334372 ] ;
335373
0 commit comments