go-loose-json-parser

command module
v0.0.18 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Feb 20, 2023 License: MIT Imports: 0 Imported by: 0

README ΒΆ

Loose JSON + TOML parsers for Go

Super loose JSON + TOML parsers and unmarshaller for Go.

Test release Go version

logo

πŸ“¦ Example app

πŸš€ Getting started

JSON
package main

import (
    "fmt"
    "github.com/shellyln/go-loose-json-parser/jsonlp"
)

func main() {
    // src: Loose JSON
    //
    // plafLb:
    // * Platform-dependent line break.
    //   * `Linebreak_Lf` | `Linebreak_CrLf` | `Linebreak_Cr`
    // * Line break codes in multi-line string are replaced by this specified line break.
    //   (Excluding line breaks by escape sequences)
    //
    // 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.ParseJSON(`{
        // comment
        config: {
            addr: '127.0.0.1',
        }
    }`, jsonlp.Linebreak_Lf, jsonlp.Interop_None)

    if err != nil {
        fmt.Printf("Parse: error = %v\n", err)
        return
    }

    fmt.Printf("Parsed = %v\n", parsed)
}
TOML
package main

import (
    "fmt"
    "github.com/shellyln/go-loose-json-parser/jsonlp"
)

func main() {
    // src: Loose TOML
    //
    // plafLb:
    // * Platform-dependent line break.
    //   * `Linebreak_Lf` | `Linebreak_CrLf` | `Linebreak_Cr`
    // * Line break codes in multi-line string are replaced by this specified line break.
    //   (Excluding line breaks by escape sequences)
    //
    // 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.Linebreak_Lf, jsonlp.Interop_None)

    if err != nil {
        fmt.Printf("Parse: error = %v\n", err)
        return
    }

    fmt.Printf("Parsed = %v\n", parsed)
}
Unmarshal

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
Unmarshal also works well for typed to untyped conversions and as deep cloning.

πŸ₯… Goal

  • 🟨 Can read strict TOML.
  • βœ… Can read loose JSON, JSONC, JSON5, and TOML for configuration files.
  • βœ… Can be mapped to structs, untyped maps/slices, or primitives.
  • βœ… Can read many list and map literals in JavaScript, Python, PHP, Ruby, etc.

🚧 ToDo

APIs
  • βœ… Marshalling from any to typed
TOML
  • βœ… Datetime format with date and time delimited by space (RFC 3339 section 5.6)
    • e.g. 2006-01-02 15:04:05Z
  • βœ… Datetime format without timezone
    • e.g. 2006-01-02T15:04:05
  • Platform-dependent newline in multiline string
  • Error detection when values are overwritten

πŸͺ„ Examples

JSON
# 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

TOML
# 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 = 22

See also: TOML Spec

πŸ“š Syntax

Array
[]
[1]
[1,]
[1, 2]
[1, 2,]
Object
{}
{ "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 } } }
Number
123
-123
-123s64
123u64
-123.45
-1.2345e+6
-123_456_789
-123_456.789_012
0x12345678
0x1234_5678
0o7654_3210
0b0101_0101
0x1p-2
0x1.Fp+0
0X_1_FFF_P-16
NaN
nan
Infinity
+Infinity
-Infinity
inf
+inf
-inf
Complex
1.23 - 34.5i
1.23e+1 - 34.5e-1i
0x1.8p+1 - 0x1.8p-1i
NaN-NaNi
NaN - NaN_i
Infinity-Infinityi
Infinity - Infinity_i
String
"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'
Boolean
true
false
Null, Undefined
null
// -> nil
undefined
// -> nil
None
// -> nil
Comment
# Hash line comment
// Line comment
/*
   Block comment
*/

βš–οΈ License

MIT
Copyright (c) 2023 Shellyl_N and Authors.


Powered by takenoco Parser Combinator Library

Documentation ΒΆ

The Go Gopher

There is no documentation for this package.

Directories ΒΆ

Path Synopsis
cmd
wasm command

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL