node.jsyamljsonpointer

Get line and column of YAML element given by JSON Pointer


In a Node project I have a YAML (or subset JSON) document as input and a validation function that returns a JSON Pointer of an element in the parsed document. For instance this YAML document:

a: 1
b:
  - 42
  - foo # comment

Has possible elements /a, /b, /b/0, and /b/1. Given an element pointer, how can I get the line(s) and column(s) of the corresponding element in the input document? For instance element /b/1 is on line 4, columns 4 to 6.


Solution

  • Meanwhile I found a solution like this to get the position of the element value:

    
    import { parseDocument, YAMLSeq, YAMLMap } from "yaml"
    
    // get line and column from character offset
    function lineCol(str, offset) {
      const lines = str.slice(0, offset).split("\n")
      return {
        line: lines.length,
        col: lines[lines.length - 1].length + 1,
      }
    }
    
    export function yamlPosition(doc, path) {
      let node = parseDocument(doc, { keepSourceTokens: true }).contents
    
      // parse JSON Pointer
      path = path.split("/").slice(1).map(s => s.replace(/~1/g, "/").replace(/~0/g, "~"))
    
      while (node && path.length) {
        const elem = path.shift()
        if (node instanceof YAMLSeq) {
          node = node.items[Number(elem)]
        } else if (node instanceof YAMLMap) {
          node = node.get(elem, true)
        } else {
          return // element not found
        }
        if (node && !path.length) {
          return node.range.slice(0,2).map(offset => lineCol(doc, offset))
        }
      }
    }
    
    

    Getting the full element (internal node Pair) requires some change to the function but it is similar.