Nice JSON!

This is a simple little library for printing human-readable JSON that looks a little bit nicer than the stuff you get out of the default encoder.

The Problem


The behaviour of the standard json encoder can often lead to sprawling files full of newlines and single integers on lines, for example:

final data = {
  'a': [0, 1],
  'b': [
    [0, 1],
    [2, 3]
  ]
};
String json = JsonEncoder.withIndent(' ').convert(data);
print(json);

Gives you something like this:

{
 "a": [
  0,
  1
 ],
 "b": [
  [
   0,
   1
  ],
  [
   2,
   3
  ]
 ]
}

This is obviously valid json, but not much fun to read.

The Solution


How about this instead:

String json = niceJson(data);
print(json);

->

{
 "a": [0, 1],
 "b": [[0, 1], [2, 3]]
}

Nice JSON!

Features & Parameters


Max Content Length & Max Line Length

These are pretty straightforward. maxContentLength defines the maximum length a single entry's value can be. maxLineLength defines the maximum length an entire line can be, including indent and key. If either of these is exceeded when building the compressed encoding of a value, it will be expanded.

Minimum Depth

minDepth is the minimum depth that must be reached before values start getting compressed. By default, this is 1, meaning the whole JSON representation cannot simply be a single line, but anything after the root level is compressed. If you set this to 2, for example, you can achieve this behaviour:

final data = {
  'a': {'hello': 'world'},
  'foo': {'bar': 1, 'baz': 2},
  'b': [
    [0, 1],
    2,
    3,
  ],
};
String json = niceJson(data, minDepth: 2);

->

{
 "a": {
  "hello": "world"
 },
 "foo": {
  "bar": 1,
  "baz": 2
 },
 "b": [
  [0, 1],
  2,
  3
 ]
}

Instead of what you would get with minDepth: 1:

{
 "a": {"hello": "world"},
 "foo": {"bar": 1, "baz": 2},
 "b": [[0, 1], 2, 3]
}

Always Expand Specific Keys

alwaysExpandKeys takes a List<String> of key names that should always have their values expanded, regardless of length.

e.g.:

final data = {
  'a': {'hello': 'world'},
  'b': {'foo': 'bar'},
};
String json = niceJson(data, alwaysExpandKeys: ['b']);

->

{
 "a": {"hello": "world"},
 "b": {
  "foo": "bar"
 }
}

Instead of:

{
 "a": {"hello": "world"},
 "b": {"foo": "bar"}
}

It's possible to access nested keys with dot notation too. Take this data:

Map<String, dynamic> data = {
  'a': {
    'x': [1, 2],
    'y': [3, 4],
  },
  'b': {
    'x': [5, 6],
    'y': [7, 8],
  },
};
String json = niceJson(data, minDepth: 2, alwaysExpandKeys: ['a.x']);

->

{
 "a": {
  "x": [
   1,
   2
  ],
  "y": [3, 4]
 },
 "b": {
  "x": [5, 6],
  "y": [7, 8]
 }
}

Or with a wildcard:

String json = niceJson(data, minDepth: 2, alwaysExpandKeys: ['*.x']);

->

{
 "a": {
  "x": [
   1,
   2
  ],
  "y": [3, 4]
 },
 "b": {
  "x": [
   5,
   6
  ],
  "y": [7, 8]
 }
}

A double wildcard (**) can be used to match multiple levels. For example, a.*.e would not match a.b.c.d.e, but a.**.e would.

List indices also work:

Map<String, dynamic> data = {
  'a': [
    [0, 1, 2],
    [3, 4, 5],
  ],
  'b': [
    [0, 1],
    [2, 3],
  ],
};
String json = niceJson(data, minDepth: 2, alwaysExpandKeys: ['*.0']);

->

{
 "a": [
  [
   0,
   1,
   2
  ],
  [3, 4, 5]
 ],
 "b": [
  [
   0,
   1
  ],
  [2, 3]
 ]
}

Upcoming Features


Maximum Nesting

A desirable feature would be to only allow a certain amount of nesting on a single line, for example:

{
 "a": [0, 1],
 "b": [
  [0, 1],
  [2, 3]
 ]
}

This will probably be added after Dart 3.0 because it would be nice to do this sort of thing with records.

Libraries

nice_json