I'm currently working with this package for Markdown in my application (https://github.com/Khan/perseus/tree/main/packages/simple-markdown), and in the README.md they describe what their AST looks like for parsing markdown.
I'm currently trying to recurse/iterate through this tree, and find all of the nodes that are of type "em", to replace the content with "this is italics" (basically just to try to make sure I have the right AST).
Problem is, this isn't just like a simple array where I can go one by one - instead, it seems like some contents have more nodes inside of them, and so on?
Could I get some advice how to do this, thanks!
I currently have something like this, but replaces nothing
/*
1. Deep search for all node.type === 'em'
2. Within each spoiler node, find all nodes with type === 'text'
3. Replace the text node content
4. Return the modified AST
*/
const traverse = (node) => {
if (node.type === 'em') {
const children = node.content;
const newChildren = children.map(child => {
if (child.type === 'text') {
return {
...child,
content: 'this is italics',
};
}
return traverse(child);
});
return {
...node,
content: newChildren,
};
}
return node;
};
return myAST.map(traverse);
Example (Nesting can be deeper/varied/split across more nodes)
[
{
"content": [
{
"content": [
{
"content": [
{
"content": "Italic Bold",
"type": "text"
}
],
"type": "strong"
}
],
"type": "italics"
}
],
"type": "paragraph"
}
]
becomes
[
{
"content": [
{
"content": [
{
"content": [
{
"content": "this is italics",
"type": "text"
}
],
"type": "strong"
}
],
"type": "italics"
}
],
"type": "paragraph"
}
]
CodePudding user response:
if (node.content && Array.isArray(node.content)) {
node.content = node.content.map(traverse)
}
You need to recurse through all child nodes. This addition to the top of your function works on my test file.
CodePudding user response:
You are only recursing into em
nodes, but not into other nodes.
It seems like what you want to do instead is
function replaceContent(type, content, inEm) {
if (type === 'em' && Array.isArray(content)) return traverse(content, true);
if (Array.isArray(content)) return traverse(content, inEm);
if (type === 'text' && inEm) return 'this is text in italics';
if (type === 'text') return content;
throw new Error(`unexpected content in ${type}: ${JSON.stringify(content)}`);
// or alternatively just always `return content` unchanged if not known
}
function traverse(content, inEm) {
return content.map(node => {
return {
...node,
content: replaceContent(node.type, node.content, inEm),
};
});
}
return traverse(myAST, false);