From 342ae50a25131b5c71534718b0ba11a55c0283df Mon Sep 17 00:00:00 2001 From: Grische Date: Thu, 25 Jul 2024 19:13:10 +0200 Subject: [PATCH] add support for all basic golang number types this also fixes a bug where an int64 was detected for a number larger than the largest int64 number --- json-to-go.js | 34 +++++++++++++++++++++------- json-to-go.test.js | 29 ++++++++++++------------ tests/double-nested-objects.go | 4 ++-- tests/duplicate-top-level-structs.go | 6 ++--- tests/supported-number-types.go | 17 ++++++++++++++ tests/supported-number-types.json | 16 +++++++++++++ 6 files changed, 79 insertions(+), 27 deletions(-) create mode 100644 tests/supported-number-types.go create mode 100644 tests/supported-number-types.json diff --git a/json-to-go.js b/json-to-go.js index cf4c509..3f7b112 100644 --- a/json-to-go.js +++ b/json-to-go.js @@ -349,6 +349,17 @@ function jsonToGo(json, typename, flatten = true, example = false, allOmitempty // Determines the most appropriate Go type function goType(val) { + Number.prototype.numberOfDecimals = function () { + if(isNaN(this)) return NaN + if(!isFinite(this)) return Infinity + // example: 1 || 1e-1 || 4.361170766e+20 + // try to split by "e" and "." + let exponentialString = this.toExponential().toString() + exponentialString = exponentialString.split("e")[0] || exponentialString + exponentialString = exponentialString.split(".")[1] || exponentialString + return exponentialString.length || 0; + } + if (val === null) return "any"; @@ -360,15 +371,22 @@ function jsonToGo(json, typename, flatten = true, example = false, allOmitempty else return "string"; case "number": - if (val % 1 === 0) - { - if (val > -2147483648 && val < 2147483647) - return "int"; - else - return "int64"; - } - else + // avoid type "int", as its size is platform dependent + if (val % 1 === 0 && val >= -128 && val <= 127) + return "int8" + if (val % 1 === 0 && val >= -32768 && val <= 32767) + return "int16" + if (val % 1 === 0 && val >= -2147483648 && val <= 2147483647) + return "int32" + if (val % 1 === 0 && val >= -9223372036854775808 && val <= 9223372036854775807) + return "int64" + if (val.numberOfDecimals() <= 7 && val > -3.4e+38 && val < 3.4e+38) + return "float32" + if (val.numberOfDecimals() <= 15 && val > -1.7e+308 && val < +1.7e+308) return "float64"; + + console.error(`Warning: can't find matching Golang number type for '${val}'. Falling back to "any".`) + return "any"; case "boolean": return "bool"; case "object": diff --git a/json-to-go.test.js b/json-to-go.test.js index 66cbe55..9e96ef0 100644 --- a/json-to-go.test.js +++ b/json-to-go.test.js @@ -76,51 +76,51 @@ function test(includeExampleData) { { input: '{"age": 46}', expected: - 'type AutoGenerated struct {\n\tAge int `json:"age"`\n}\n', + 'type AutoGenerated struct {\n\tAge int8 `json:"age"`\n}\n', expectedWithExample: - 'type AutoGenerated struct {\n\tAge int `json:"age" example:"46"`\n}\n', + 'type AutoGenerated struct {\n\tAge int8 `json:"age" example:"46"`\n}\n', }, { input: '{"negativeFloat": -1.00}', expected: - 'type AutoGenerated struct {\n\tNegativeFloat float64 `json:"negativeFloat"`\n}\n', + 'type AutoGenerated struct {\n\tNegativeFloat float32 `json:"negativeFloat"`\n}\n', expectedWithExample: - 'type AutoGenerated struct {\n\tNegativeFloat float64 `json:"negativeFloat" example:"-1.1"`\n}\n', + 'type AutoGenerated struct {\n\tNegativeFloat float32 `json:"negativeFloat" example:"-1.1"`\n}\n', }, { input: '{"zeroFloat": 0.00}', expected: - 'type AutoGenerated struct {\n\tZeroFloat float64 `json:"zeroFloat"`\n}\n', + 'type AutoGenerated struct {\n\tZeroFloat float32 `json:"zeroFloat"`\n}\n', expectedWithExample: - 'type AutoGenerated struct {\n\tZeroFloat float64 `json:"zeroFloat" example:"0.1"`\n}\n', + 'type AutoGenerated struct {\n\tZeroFloat float32 `json:"zeroFloat" example:"0.1"`\n}\n', }, { input: '{"positiveFloat": 1.00}', expected: - 'type AutoGenerated struct {\n\tPositiveFloat float64 `json:"positiveFloat"`\n}\n', + 'type AutoGenerated struct {\n\tPositiveFloat float32 `json:"positiveFloat"`\n}\n', expectedWithExample: - 'type AutoGenerated struct {\n\tPositiveFloat float64 `json:"positiveFloat" example:"1.1"`\n}\n', + 'type AutoGenerated struct {\n\tPositiveFloat float32 `json:"positiveFloat" example:"1.1"`\n}\n', }, { input: '{"negativeFloats": [-1.00, -2.00, -3.00]}', expected: - 'type AutoGenerated struct {\n\tNegativeFloats []float64 `json:"negativeFloats"`\n}\n', + 'type AutoGenerated struct {\n\tNegativeFloats []float32 `json:"negativeFloats"`\n}\n', expectedWithExample: - 'type AutoGenerated struct {\n\tNegativeFloats []float64 `json:"negativeFloats"`\n}\n', + 'type AutoGenerated struct {\n\tNegativeFloats []float32 `json:"negativeFloats"`\n}\n', }, { input: '{"zeroFloats": [0.00, 0.00, 0.00]}', expected: - 'type AutoGenerated struct {\n\tZeroFloats []float64 `json:"zeroFloats"`\n}\n', + 'type AutoGenerated struct {\n\tZeroFloats []float32 `json:"zeroFloats"`\n}\n', expectedWithExample: - 'type AutoGenerated struct {\n\tZeroFloats []float64 `json:"zeroFloats"`\n}\n', + 'type AutoGenerated struct {\n\tZeroFloats []float32 `json:"zeroFloats"`\n}\n', }, { input: '{"positiveFloats": [1.00, 2.00, 3.00]}', expected: - 'type AutoGenerated struct {\n\tPositiveFloats []float64 `json:"positiveFloats"`\n}\n', + 'type AutoGenerated struct {\n\tPositiveFloats []float32 `json:"positiveFloats"`\n}\n', expectedWithExample: - 'type AutoGenerated struct {\n\tPositiveFloats []float64 `json:"positiveFloats"`\n}\n', + 'type AutoGenerated struct {\n\tPositiveFloats []float32 `json:"positiveFloats"`\n}\n', }, { input: '{"topLevel": { "secondLevel": "exampleDataHere"} }', @@ -162,6 +162,7 @@ function testFiles() { const testCases = [ "duplicate-top-level-structs", "double-nested-objects", + "supported-number-types", ]; for (const testCase of testCases) { diff --git a/tests/double-nested-objects.go b/tests/double-nested-objects.go index 4c44bb4..6ce933f 100644 --- a/tests/double-nested-objects.go +++ b/tests/double-nested-objects.go @@ -7,13 +7,13 @@ type Type struct { Long string `json:"long"` } type First struct { - ID int `json:"id"` + ID int8 `json:"id"` Type Type `json:"type"` } type SecondType struct { Long string `json:"long"` } type Second struct { - ID int `json:"id"` + ID int8 `json:"id"` SecondType SecondType `json:"type"` } diff --git a/tests/duplicate-top-level-structs.go b/tests/duplicate-top-level-structs.go index c2c7936..88bae51 100644 --- a/tests/duplicate-top-level-structs.go +++ b/tests/duplicate-top-level-structs.go @@ -5,7 +5,7 @@ type AutoGenerated struct { } type Identifier struct { Type string `json:"type"` - ID int `json:"id"` + ID int16 `json:"id"` } type Region struct { Identifier Identifier `json:"identifier"` @@ -20,11 +20,11 @@ type Municipality struct { } type Postal struct { Type string `json:"type"` - ID int `json:"id"` + ID int8 `json:"id"` } type Road struct { Name string `json:"name"` - ID int `json:"id"` + ID int8 `json:"id"` } type BuildingIdentifier struct { Postal Postal `json:"postal"` diff --git a/tests/supported-number-types.go b/tests/supported-number-types.go new file mode 100644 index 0000000..b5ca2fa --- /dev/null +++ b/tests/supported-number-types.go @@ -0,0 +1,17 @@ +type AutoGenerated struct { + Basedonscience bool `json:"basedonscience"` + SecondsPerYear float32 `json:"seconds per year"` + AgeOfTheUniverse AgeOfTheUniverse `json:"age of the universe"` + BasicallyInfinity any `json:"basically infinity"` + Date string `json:"date"` +} +type AgeOfTheUniverse struct { + InPlanckTime float64 `json:"in planck time"` + InVeryPreciseMilliseconds float64 `json:"in very precise milliseconds"` + InMilliseconds float32 `json:"in milliseconds"` + InSeconds int64 `json:"in seconds"` + InYears int64 `json:"in years"` + InMillenia int32 `json:"in millenia"` + InMegaannums int16 `json:"in megaannums"` + InGalacticYears int8 `json:"in galactic years"` +} diff --git a/tests/supported-number-types.json b/tests/supported-number-types.json new file mode 100644 index 0000000..3545798 --- /dev/null +++ b/tests/supported-number-types.json @@ -0,0 +1,16 @@ +{ + "basedonscience": true, + "seconds per year": 3.6524219e+2, + "age of the universe": { + "in planck time": 8.0718985e+60, + "in very precise milliseconds": 4.35075327952992e+20, + "in milliseconds": 4.3507532e+20, + "in seconds": 4.35075327952992e+17, + "in years": 13787000000, + "in millenia": 13787000, + "in megaannums": 13787, + "in galactic years": 60 + }, + "basically infinity": 4.361170766e+400, + "date": "2024-07-25" +}