Is it possible to create CST Tokens for block-map and block-seq? #633
Replies: 2 comments
-
|
It's certainly "possible", but tbh even I'd need to spend quite some time figuring out exactly how. In your position, I would:
|
Beta Was this translation helpful? Give feedback.
-
|
I ended up deciding it was not necessary to keep the source yaml, but while playing around I ended up with a solution I am not entirely unhappy with, so I thought it was worth sharing. There is probably more testing that needs to be done here, but for most docker-compose files I found it worked pretty well. It does lose some comments in some cases but for the majority of stuff I liked how it worked. Additionally it only works on files with indents of 2 spaces. Also I don't think it will create a new node if it does not exist as a collection but that is fixable too. import { CST, parseDocument, Parser } from "yaml";
export function setValue(yaml: string, path: string[], value: any){
const doc = parseDocument(yaml)
const CSTree = getFirstDocument(new Parser().parse(yaml))
let existingPath: string[] = []
for(let i = path.length; i > 0; i--){
if(doc.hasIn(path.slice(0, i))){
existingPath = path.slice(0, i)
break;
}
}
doc.setIn(path, value)
const newCSTree = getFirstDocument(new Parser().parse(doc.toString()))
copyNode(newCSTree, CSTree, existingPath)
return CST.stringify(CSTree)
}
function copyNode(source: CST.Document, target: CST.Document, path: string[]){
const sourceNode = getNodeAtPath(source, path)
setNodeAtPath(target, path, sourceNode)
}
function setNodeAtPath(document: CST.Document, path: string[], node: CST.Token){
let here = document.value
if(!here){
throw "Document must have a child"
}
for(const i in path){
const name = path[i]
if(here?.type !== "block-map"){
throw `Can't navigate into type ${here.type}`
}
let found = false
for(const item of here.items){
if(Number(i) == path.length - 1){
if(item.key?.type == "scalar" && item.key?.source == name && item.value){
item.value = node
return
}
} else if(item.key?.type == "scalar" && item.key?.source == name && item.value){
here = item.value
found = true
break;
}
}
if(!found){
throw `Can't find key with name: ${name}`
}
}
}
function getNodeAtPath(document: CST.Document, path: string[]): CST.Token{
let here = document.value
if(!here){
throw "Document must have a child"
}
for(const name of path){
if(here.type !== "block-map"){
throw `Can't navigate into type ${here.type}`
}
let found = false
for(const item of here.items){
if(item.key?.type == "scalar" && item.key?.source == name && item.value){
here = item.value
found = true
break;
}
}
if(!found){
throw `Can't find key with name: ${name}`
}
}
return here
}
function getFirstDocument(tokens: Iterable<CST.Token>){
for(const token of tokens){
if(token.type == "document"){
return token
}
}
throw "No Document"
} |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
I'm interested in modifying existing YAML with new fields while preserving as much of the original comments and formatting as possible. It looks like using the CST I should be able to do this and I see that in the docs we can create scalar tokens using
CST.createScalarTokenbut did not see anything to create non scalar tokens. I have this rough draft a function that attempts to traverse a document building up block-maps until an end point where it creates a block-seq:But this does not stringify properly as I am not sure how to set the
sepproperty correctly, or if something like this is even possible.Here is an example of the type of thing I am trying to accomplish:
Turning this:
Into this:
Beta Was this translation helpful? Give feedback.
All reactions