pastudan
pastudan

Reputation: 131

Is line number mapping possible with js-yaml?

Say I have a YAML document like this:

valid_true:
  - true
  - True
  - TRUE

valid_false:
  - false
  - False
  - FALSE

I'd like to end up with an object that correlates the parsed object keys to the line numbers from the YAML document that defined them. An output like this might work:

{
  "valid_true": {
    "value": [
      {"value": true, line: 2},
      {"value": true, line: 3},
      {"value": true, line: 4}
    ],
    "line": 1
  },
  "valid_false": {
    "value": [
      {"value": false, line: 7},
      {"value": false, line: 8},
      {"value": false, line: 9}
    ],
    "line": 6
  }
}

Is this possible with this library? Or will I need to fork / modify it?

Upvotes: 3

Views: 748

Answers (2)

Pranavan
Pranavan

Reputation: 1405

You can use js-yaml-source-map for this.

import fs from "fs";
import yaml from "js-yaml";
import SourceMap from "js-yaml-source-map";

const data = fs.readFileSync("./example.yaml", "utf8");

const map = new SourceMap();
// pass map.listen() to the listener option
const loaded = yaml.load(data, { listener: map.listen() });

Upvotes: 1

Anthon
Anthon

Reputation: 76722

Many YAML libraries peform the task of loading in multiple stages:

  1. scanning document sources into tokens
  2. composing the tokens into nodes (tagged scalars, sequences, mappings)
  3. constructing the language specific objects from the nodes

After the last step the line information that you seek is normally no longer available. As long as you can hook into the loading task, by either influencing the construction of objects or by building on top of an exposed node structure, then what you want is relatively easy to do.

That is e.g. the case in PyYAML, the YAML 1.1 loader/dumper on which js-yaml originally was based. But js-yaml has been rewritten to support YAML 1.2 since then and the API, doesn't seem to have any options to "interfere" as described in the previous paragraph.

You might want to look into older (PyYAML based) versions of the library, to see if the API for them is more flexible. I have not looked at the details of the implementation, but my impression is that the rewrite did away with flexibility in favour of speed (not in itself a bad decision, but not something that helps use cases like yours).

If you are not restricted by javascript, then you might want to look at the NimYaml or my own ruamel.yaml (for Python). Those are YAML 1.2 loader/dumpers where I know for sure you can hook into the loading process as you'll need to do.

ruamel.yaml, when used in the default round-trip mode, has line/column information already assigned to the objects constructed from YAML mappings and sequences and this can be relatively easily be extended to the available special scalar types used in round-tripping (these include most types including booleans). Alternatively, if your input is guaranteed to have whitespace and/or comment-only lines after the keys, as your example has, the actual linenumber of an item can of course be calculated on the basis of the start of the list.

Upvotes: 1

Related Questions