Help Jason format his JSON Jason has a big JSON but it's unreadable, so he needs to prettify it.

Formatting Spec

The JSON has 4 different types:


Numbers; Just 0-9
Strings; Double quoted " strings escaped with \
Arrays; Delimited by [], with items separated by ,, items can be any of these types
Objects; Delimited by {}, format is key: value where key is a string and value is any of these types


Spacing


Arrays should have exactly one space after the commas between items
Objects should have have just one space between the key and the value, after the :


Indentation


Each nesting level is indented 2 more than the previous
Each object key/value pair is always on its own line. Objects are indented
An array is indented across multiple lines if it contains another array or object. Otherwise the array remains on one line


Rules


Built-ins which trivialize this task are not allowed.
As always standard loopholes are disallowed


Examples

[1,2,3]
[1, 2, 3]




{"a":1,"b":4}
{
  "a": 1,
  "b": 4
}




"foo"
"foo"




56
56




{"a":[{"b":1,"c":"foo"},{"d":[2,3,4,1], "a":["abc","def",{"d":{"f":[3,4]}}]}]}
{
  "a": [
    {
      "b": 1,
      "c": "foo"
    },
    {
      "d": [2, 3, 4, 1],
      "a": [
        "abc",
        "def",
        {
          "d": {
            "f": [3, 4]
          }
        }
      ]
    }
  ]
}




[2,["foo123 ' bar \" baz\\", [1,2,3]]]
[
  2,
  [
    "foo123 ' bar \" baz\\",
    [1, 2, 3]
  ]
]




[1,2,3,"4[4,5]"]
[1, 2, 3, "4[4,5]"]




[1,2,3,{"b":["{\"c\":[2,5,6]}",4,5]}]
[
  1,
  2,
  3,
  {
    "b": ["{\"c\":[2,5,6]}", 4, 5]
  }
]
JavaScript (ES6), 368 bytes

f=(s,r=[],i='',j=i+'  ',a=[])=&gt;s&lt;'['?([,,r[0]]=s.match(s&lt;'0'?/("(?:\\.|[^"])*")(.*)/:/(\d+)(.*)/))[1]:s&lt;'{'?(_=&gt;{for(;s&lt;']';s=r[0])a.push(f(s.slice(1),r,j));r[0]=s.slice(1)})()||/\n/.test(a)?`[
${j+a.join(`,
`+j)}
${i}]`:`[${a.join`, `}]`:(_=&gt;{for(a=[];s&lt;'}';s=r[0])a.push(f(s.slice(1),r,j)+': '+f(r[0].slice(1),r,j));r[0]=s.slice(1)})()||`{
${j+a.join(`,
`+j)}
${i}}`


Less golfed:

function j(s, r=[], i='') { // default to no indentation
    if (s &lt; '0') { // string
        let a = s.match(/("(?:\\.|[^"])*")(.*)/);
        r[0] = a[2]; // pass the part after the string back to the caller
        return a[1];
    } else if (s &lt; '[') { // number
        let a = s.match(/(\d+)(.*)/);
        r[0] = a[2]; // pass the part after the string back to the caller
        return a[1];
    } else if (s &lt; '{') { // array
        let a = [];
        while (s &lt; ']') { // until we see the end of the array
            s = s.slice(1);
            a.push(j(s, r, i + '  ')); // recurse with increased indentation
            s = r[0]; // retrieve the rest of the string
        }
        r[0] = s.slice(1); // pass the part after the string back to the caller
        if (/\n/.test(a.join())) { // array contained object
            return '[\n  ' + i + a.join(',\n  ' + i) + '\n' + i + ']';
        } else {
            return '[' + a.join(', ') + ']';
        }
    } else { // object
        let a = [];
        while (s &lt; '}') { // until we see the end of the object
            s = s.slice(1);
            let n = j(s, r, i + '  ');
            s = r[0].slice(1);
            let v = j(s, r, i + '  ');
            a.push(n + ': ' + v);
            s = r[0]; // retrieve the rest of the string
        }
        r[0] = s.slice(1); // pass the part after the string back to the caller
        return '{\n  ' + i + a.join(',\n  ' + i) + '\n' + i + '}';
    }
}