I'm trying to parse a JSON structure, The json structure looks something like this:
{
children: [
{
type: "p",
children: [{
text: ""
}]
},
{
type: "social_embed",
children: [{
text: ""
}]
source_url: "some_url"
},
{
type: "p",
children: [{
type: "p",
children: [{
type: "p",
children: [{
text: ""
}]
}]
}]
},
]
}
The output will look like:
{
children: [
{
type: "p",
children: [{
text: ""
}]
},
{
type: "p",
children: [{
text: "some_url"
}]
},
{
type: "p",
children: [{
type: "p",
children: [{
type: "p",
children: [{
text: ""
}]
}]
}]
},
]
}
This is the code I'm trying:
if (currentBlock.type == "card" || currentBlock.type =="card_body")
{
parsedBlocks.map((block: any, index: any) => {
block.children = parseBlocks(block.children)
})
console.log("Blocks after parsing", parsedBlocks)
editor.insertFragment(parsedBlocks);
return true
}
const parseBlocks = (blocks: any): any => {
blocks.forEach((block: any) => {
console.log("Block ", block)
if (block.type == "social_embed") {
const newBlock = {
type: "p",
children: [
{
text: block.source_url
}
]
}
blocks[blocks.indexOf(block)] = newBlock
}
if (block.children) {
return parseBlocks(block.children)
}
})
return blocks
}
I want to recursively traverse all children until there is no children property in the object and when I encounter the object with type: "social_embed" I want to replace it with type : "p" and the text as source_url and modify the entire array, The children can have unlimited nesting but the social_embed can't have anything inside it's children other than {text: ""}
How about something like this:
const parse = node => {
if (node.type === "social_embed") {
return {
type: "p",
children: [{ text: node.source_url}]
}
}
return node.children ? {
...node,
children: node.children.map(parse)
} : node;
}
https://replit.com/@jamiedixon/ParseTree#index.js
If you want to go one step further you could define visitors for the nodes based on the type and process them that way.
const socialEmbed = node => ({
type: "p",
children: [{ text: node.source_url }]
})
const visitors = {
"social_embed": [socialEmbed]
}
const parse = node => {
const _visitors = visitors[node.type] || [x => x];
const result = _visitors.reduce((agg, fn) => fn(agg), node);
return result.children ? {
...result,
children: result.children.map(parse)
} : result;
}
You could map new object to the children and take either a new object of the old one.
const
update = ({ children = [], ...object }) => {
if (object.type === "social_embed") {
const
type= 'p',
text = object.source_url;
return { type, children: [{ text }] };
}
children = children.map(update);
return children.length
? { ...object, children }
: object;
},
tree = { children: [{ type: "p", children: [{ text: "" }] }, { type: "social_embed", children: [{ text: "" }], source_url: "some_url" }, { type: "p", children: [{ type: "p", children: [{ type: "p", children: [{ text: "" }] }] }] }] };
tree.children = tree.children.map(update);
console.log(tree);
.as-console-wrapper { max-height: 100% !important; top: 0; }
An approach similar to those from Nina and Jamie, but written in a somewhat different coding style:
const transform = ({type, children = [], source_url, ...rest}) =>
type == 'social_embed'
? {type:'p', children: [{text: source_url}]}
: {type, ...rest, ...(children.length ? {children : children .map (transform)} : {})}
const input = {children: [{type: "p", children: [{text: ""}]}, {type: "social_embed", children: [{text: ""}], source_url: "some_url"}, {type: "p", children: [{type: "p", children: [{type: "p", children: [{text: ""}]}]}]}]}
console .log (transform (input))
.as-console-wrapper {max-height: 100% !important; top: 0}