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.
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.