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: ""}
CodePudding user response:
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; }
CodePudding user response:
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;
}
https://replit.com/@jamiedixon/ParseTree#visitors.js
CodePudding user response:
you can do a recurcive function which loops over your tree and modify in place when it encounters a social_embed
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: ""}]}]}]}]}
function rec(input) {
if (input.type === "social_embed") {
input.children = [{text: input.source_url}]
input.type = "p"
delete input.source_url
}
input.children?.forEach(rec)
}
rec(input)
console.log(JSON.stringify(input, null, 4))
.as-console-wrapper { max-height: 100% !important; top: 0; }
If you prefer to generate a new object and keep the original one intact you can do it like this
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: ""}]}]}]}]}
function rec(input) {
const output = {...input}
if (input.type === "social_embed") {
output.children = [{text: input.source_url}]
output.type = "p"
delete output.source_url
} else if (input.children) {
output.children = input.children.map(rec)
}
return output
}
const output = rec(input)
console.log(JSON.stringify(output, null, 4))
.as-console-wrapper { max-height: 100% !important; top: 0; }