Super loose JSON + TOML parsers and unmarshaller for Go.
- Loose JSON | TOML normalizer (WebAssembly)
- Normalize loose JSON | TOML to strict JSON
- Code
package main import ( "fmt" "github.com/shellyln/go-loose-json-parser/jsonlp" ) func main() { // src: Loose JSON // // interop: // * If `Interop_JSON` is set, // replace NaN, Infinity, complex number // by `{nan:true}`, `{inf:+/-1}`, `{re:re,im:im}` . // * If `Interop_TOML` is set, // replace complex number by `{re:re,im:im}` . // * If `Interop_JSON_AsNull` is set, // replace NaN, Infinity, complex number by null. // * If `Interop_TOML_AsNull` is set, // replace complex number by null. // // parsed: // nil | []any | map[string]any | // float64 | int64 | uint64 | complex128 | // string | bool | time.Time parsed, err := jsonlp.Parse(`{ // comment config: { addr: '127.0.0.1', } }`, jsonlp.Interop_None) if err != nil { fmt.Printf("Parse: error = %v\n", err) return } fmt.Printf("Parsed = %v\n", parsed) }package main import ( "fmt" "github.com/shellyln/go-loose-json-parser/jsonlp" ) func main() { // src: Loose TOML // // interop: // * If `Interop_JSON` is set, // replace NaN, Infinity, complex number // by `{nan:true}`, `{inf:+/-1}`, `{re:re,im:im}` . // * If `Interop_TOML` is set, // replace complex number by `{re:re,im:im}` . // * If `Interop_JSON_AsNull` is set, // replace NaN, Infinity, complex number by null. // * If `Interop_TOML_AsNull` is set, // replace complex number by null. // // parsed: // nil | []any | map[string]any | // float64 | int64 | uint64 | complex128 | // string | bool | time.Time parsed, err := jsonlp.ParseTOML(` # comment [config] addr = '127.0.0.1' `, jsonlp.Interop_None) if err != nil { fmt.Printf("Parse: error = %v\n", err) return } fmt.Printf("Parsed = %v\n", parsed) }Mapping untyped data to a typed variable.
package main import ( "fmt" "github.com/shellyln/go-loose-json-parser/jsonlp" "github.com/shellyln/go-loose-json-parser/marshal" ) type config struct { Addr string `json:"addr"` } type response struct { Config config `json:"config"` } func main() { parsed, err := jsonlp.Parse(`{ // comment config: { addr: '127.0.0.1', } }`, jsonlp.Interop_None) if err != nil { fmt.Printf("Parse: error = %v\n", err) return } var typed response // src: Source data. Untyped in typical use. // dst: Pointer to result data. Typed in typical use. // opts: Pointer to struct of the `Unmarshal` options. If nil, use default. // Default options are { // TagName: "json", // Tag name of the struct fields // NoCopyUnexportedFields: false, // If true, no shallow copying of unexported fields // NoCustomMarshaller: false, // If true, IMarshal and IUnmarshal are not used // } if err := marshal.Unmarshal(parsed, &typed, nil); err != nil { fmt.Printf("Unmarshal: error = %v\n", err) return } fmt.Printf("Typed = %v\n", typed) }Note
Unmarshalalso works well for typed to untyped conversions and as deep cloning.
- ✅
Marshalling from any to typed
- Datetime format with date and time delimited by space (RFC 3339 section 5.6)
- e.g.
2006-01-02 15:04:05Z
- e.g.
- Datetime format without timezone
- e.g.
2006-01-02T15:04:05
- e.g.
- Platform-dependent newline in multiline string
- Error detection when values are overwritten
# Hash comment { // Line comment /* Block comment */ // Object keys can be enclosed in either double-quote, single-quote, back-quote. // It is also allowed not to enclose them. "foo": [ 123, // -> float64(123) -123.45, // -> float64(-123.45) -1.2345e+6, // -> float64(-1234500) -123_456_789, // -> float64(-123456789) 0x12345678, // -> float64(305419896) 0x1234_5678, // -> float64(305419896) 0o7654_3210, // -> float64(16434824) 0b0101_0101, // -> float64(85) ], 'bar': null, // -> nil baz: undefined, // -> nil "qux": -Infinity, // -> -Inf // Infinity, +Infinity are also available "quux": NaN, // -> NaN // Non-ASCII identifiers can also be used. あいうえお: { key: "value1", bare_key: "value2", bare-key: "value3", // Keys containing hyphens are allowed. 1234: "value4", // Keys starting with a number are allowed. -3.14: "value5", // "-3": { "14": "value5" } }, "corge": [ // Escape sequences are available 'Hello, World!\r\n', // Unicode escape sequences (\uXXXX and \u{XXXXXX}) are available "\u0048\u0065\u006c\u006c\u006f\u002c\u0020\u0057\u006f\u0072\u006c\u0064\u0021", // Byte escape sequence is also available "\x48\x65\x6c\x6c\x6f\x2c\x20\x57\x6f\x72\x6c\x64\x21", // Multiline string literal `Tempor adipiscing amet velit ipsum diam ut ea takimata lorem gubergren sed laoreet. Congue possim facilisis sea justo dolore amet eos dolores est magna.` ], "grault": [ // Date, Time, DateTime literals are available 2020-12-31, // -> time.Time 2020-12-31:00:00.000Z 18:20:30.001, // -> time.Time 1870-01-01T18:20:30.001Z 2020-12-31T18:20:30.001Z // -> time.Time 2020-12-31:20:30.001Z ], // "key = value" syntax is allowed garply = true, // "key => value" syntax is allowed waldo => false, // Trailing commas are allowed. fred: 10, }See also: Introducing JSON, JSON5 Spec
# Hash comment // Line comment (non-standard) /* Block comment (non-standard) */ "quoted-key" = "value0" key = "value1" bare_key = "value2" bare-key = "value3" # Keys containing hyphens are allowed. 1234 = "value4" # Keys starting with a number are allowed. -3.14 = "value5" # "-3": { "14": "value5" } あいうえお = "value6" # // Non-ASCII identifiers are allowed. (non-standard) [table-A] item-a = 1 item-b = 2 item-c = "standard\n string" item-d = '\literal string' item-e = """\ Multiline \ standard string""" item-f = ''' Multiline literal string''' "\t" '''!!''' [table-A.sub-table-P] item-m = 11 item-n = 12 sub-table-X.sub-table-Y = 111 [[array-of-table-U]] foo = 1 [array-of-table-U.sub-table-V] bar = 11 [[array-of-table-U]] foo = 2 [array-of-table-U.sub-table-V] bar = 22See also: TOML Spec
[][1][1,][1, 2][1, 2,]{}{ "foo": 1 }{ "foo": 1, }{ 'foo': 1, }{ `foo`: 1, }{ foo: 1, }{ "foo": 1, "bar": 2, }{ "foo" => 1 }{ "foo" = 1 }{ foo.bar.baz = 1 } // -> { "foo": { "bar": { "baz": 1 } } }{ "foo".bar."baz" = 1 } // -> { "foo": { "bar": { "baz": 1 } } }123-123-123s64123u64-123.45-1.2345e+6-123_456_789-123_456.789_0120x123456780x1234_56780o7654_32100b0101_01010x1p-20x1.Fp+00X_1_FFF_P-16NaNnanInfinity+Infinity-Infinityinf+inf-inf1.23 - 34.5i1.23e+1 - 34.5e-1i0x1.8p+1 - 0x1.8p-1iNaN-NaNiNaN - NaN_iInfinity-InfinityiInfinity - Infinity_i"foobar"'foobar'`foo bar`"""foo bar"""'''foo bar'''"Hello\n\r\v\t\b\fWorld!""\u0048\u0065\u006c\u006c\u006f\u002c\u0020\u0057\u006f\u0072\u006c\u0064\u0021""\u{000048}\u{000065}\u{00006c}\u{00006c}\u{00006f}\u{00002c}\u{000020}\u{000057}\u{00006f}\u{000072}\u{00006c}\u{000064}\u{000021}""\x48\x65\x6c\x6c\x6f\x2c\x20\x57\x6f\x72\x6c\x64\x21""foo" "bar" // -> "foobar"'foo' 'bar' // -> 'foobar'truefalsenullundefined# Hash line comment// Line comment/* Block comment */MIT
Copyright (c) 2023 Shellyl_N and Authors.
Powered by takenoco Parser Combinator Library