Controlling property names when exporting to JSON in Rascal

I am writing some data to a file with writeJSON from the lang::json::IO module.

Example:

map[str, value] volumeMetrics = ();
map[str path, map[loc location, int lineCount] methods] = ...; // some data
volumeMetrics["files"] = methodLineCountPerFile;

How can I control the names of the properties in the resulting JSON without going through the hierarchy of objects and specifying them manually? In this particular case I would want the JSON objects to have properties named after the labels defined in the map (e.g. "path", "location", "linecount", "methods"). Instead, this data is now directly written as object properties.

(partial) sample output:

  "/src/smallsql/database/ExpressionFunctionUCase.java": [
    [
      {
        "scheme": "java+compilationUnit",
        "authority": "",
        "path": "/src/smallsql/database/ExpressionFunctionUCase.java",
        "offset": 1600,
        "length": 32,
        "begin": [
          47,
          41
        ],
        "end": [
          49,
          2
        ]
      },
      3
    ],
    [
      {
        "scheme": "java+compilationUnit",
        "authority": "",
        "path": "/src/smallsql/database/ExpressionFunctionUCase.java",
        "offset": 1679,
        "length": 80,
        "begin": [
          52,
          41
        ],
        "end": [
          55,
          2
        ]
      },
      4
    ],
    [
      {
        "scheme": "java+compilationUnit",
        "authority": "",
        "path": "/src/smallsql/database/ExpressionFunctionUCase.java",
        "offset": 1810,
        "length": 78,
        "begin": [
          58,
          43
        ],
        "end": [
          61,
          2
        ]
      },
      4
    ],
    [
      {
        "scheme": "java+compilationUnit",
        "authority": "",
        "path": "/src/smallsql/database/ExpressionFunctionUCase.java",
        "offset": 1518,
        "length": 35,
        "begin": [
          42,
          25
        ],
        "end": [
          44,
          2
        ]
      },
      3
    ]
  ],

You can use the data constructors of Rascal to create nested structure, which can then be mapped to JSON structure:

rascal>data Metric = path(int i);
ok
rascal>import lang::json::IO;
Loading module |lib://rascal/lang/json/IO.rsc|
ok
rascal>writeJSON(|home:///test.json|, path(20))
ok
rascal>import IO;
ok
rascal>println(readFile(|home:///test.json|))
{"path":{"i":20}}
ok

So you could create a Metric constructor for every kind of metric you have and work with that, or you can have a single constructor with different fields, like this:

rascal>data Metrics = metrics(int a, int b, int c);
ok
rascal>writeJSON(|home:///test.json|, metrics(1,2,3))
ok
rascal>println(readFile(|home:///test.json|))
{"metrics":{"a":1,"b":2,"c":3}}
ok

Here you use the labels of the fields of the constructors to name the metrics.

PS, the unpackedLocations keyword parameter to writeJSON is useful to make the source locations take up less space.