Skip to content

Commit b425394

Browse files
committed
upgrade ints and floats in arrays with mixed sizes
1 parent c162664 commit b425394

4 files changed

+94
-0
lines changed

json-to-go.js

+49
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,11 @@ function jsonToGo(json, typename, flatten = true, example = false, allOmitempty
111111
continue
112112
}
113113

114+
// if variable was first detected as int (7) and a second time as float64 (3.14)
115+
// then we want to select float64, not int. Similar for int64 and float64.
116+
if(areSameType(currentValue, 1))
117+
allFields[keyname].value = findBestValueForNumberType(existingValue, currentValue);
118+
114119
if (areObjects(existingValue, currentValue)) {
115120
const comparisonResult = compareObjectKeys(
116121
Object.keys(currentValue),
@@ -389,6 +394,50 @@ function jsonToGo(json, typename, flatten = true, example = false, allOmitempty
389394
}
390395
}
391396

397+
// change the value to expand ints and floats to their larger equivalent
398+
function findBestValueForNumberType(existingValue, newValue) {
399+
if (!areSameType(newValue, 1)) {
400+
console.error(`Error: currentValue ${newValue} is not a number`)
401+
return null // falls back to goType "any"
402+
}
403+
404+
const newGoType = goType(newValue)
405+
const existingGoType = goType(existingValue)
406+
407+
if (newGoType === existingGoType)
408+
return existingValue
409+
410+
// always upgrade float64
411+
if (newGoType === "float64")
412+
return newValue
413+
if (existingGoType === "float64")
414+
return existingValue
415+
416+
// it's too complex to distinguish int types and float32, so we force-upgrade to float64
417+
// if anyone has a better suggestion, PRs are welcome!
418+
if (newGoType.includes("float") && existingGoType.includes("int"))
419+
return Number.MAX_VALUE
420+
if (newGoType.includes("int") && existingGoType.includes("float"))
421+
return Number.MAX_VALUE
422+
423+
if (newGoType.includes("int") && existingGoType.includes("int")) {
424+
const existingValueAbs = Math.abs(existingValue);
425+
const newValueAbs = Math.abs(newValue);
426+
427+
// if the sum is overflowing, it's safe to assume numbers are very large. So we force int64.
428+
if (!isFinite(existingValueAbs + newValueAbs))
429+
return Number.MAX_SAFE_INTEGER
430+
431+
// it's too complex to distinguish int8, int16, int32 and int64, so we just use the sum as best-guess
432+
return existingValueAbs + newValueAbs;
433+
}
434+
435+
// There should be other cases
436+
console.error(`Error: something went wrong with findBestValueForNumberType() using the values: '${newValue}' and '${existingValue}'`)
437+
console.error(" Please report the problem to https://github.com/mholt/json-to-go/issues")
438+
return null // falls back to goType "any"
439+
}
440+
392441
// Given two types, returns the more specific of the two
393442
function mostSpecificPossibleGoType(typ1, typ2)
394443
{

json-to-go.test.js

+1
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,7 @@ function testFiles() {
162162
const testCases = [
163163
"duplicate-top-level-structs",
164164
"double-nested-objects",
165+
"array-with-mixed-float-int",
165166
"array-with-nonmatching-types",
166167
];
167168

tests/array-with-mixed-float-int.go

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
type AutoGenerated struct {
2+
AgeOfTheUniverse []AgeOfTheUniverse `json:"age of the universe"`
3+
AgeOfTheEarth []AgeOfTheEarth `json:"age of the earth"`
4+
Date string `json:"date"`
5+
}
6+
type AgeOfTheUniverse struct {
7+
Name string `json:"name"`
8+
Value float64 `json:"value"`
9+
}
10+
type AgeOfTheEarth struct {
11+
Name string `json:"name"`
12+
Value int64 `json:"value"`
13+
}

tests/array-with-mixed-float-int.json

+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
{
2+
"age of the universe": [
3+
{
4+
"name": "in years",
5+
"value": 1378700000
6+
},
7+
{
8+
"name": "in seconds",
9+
"value": 4.35075327952992e+17
10+
},
11+
{
12+
"name": "in kapla",
13+
"value": 0.31914351851
14+
}
15+
],
16+
"age of the earth": [
17+
{
18+
"name": "in eons (roughly)",
19+
"value": 4
20+
},
21+
{
22+
"name": "in years",
23+
"value": 4.543e9
24+
},
25+
{
26+
"name": "in seconds",
27+
"value": 1.6592953e+12
28+
}
29+
],
30+
"date": "2024-07-25"
31+
}

0 commit comments

Comments
 (0)