This is the desired string rendered

Suppose you have an Array of Objects representing different attributes of the string:
[{
"isBold": false,
"isCode": true,
"isItalic": false,
"isStrikethrough": false,
"range": [
42,
8
]
},
{
"isBold": false,
"isCode": false,
"isItalic": true,
"isStrikethrough": false,
"range": [
19,
10
]
},
{
"isBold": false,
"isCode": false,
"isItalic": false,
"isStrikethrough": true,
"range": [
46,
11
]
},
{
"isBold": true,
"isCode": false,
"isItalic": false,
"isStrikethrough": false,
"range": [
27,
12
],
"nested": [
{
"isBold": false,
"isCode": true,
"isItalic": false,
"isStrikethrough": false,
"range": [
28,
7
]
}
]
},
{
"highlightColor": "#fff100 #fff432",
"isBold": false,
"isCode": false,
"isItalic": false,
"isStrikethrough": false,
"range": [
1,
15
]
},
{
"isBold": false,
"isCode": false,
"isItalic": false,
"isStrikethrough": false,
"linkURL": "www.google.com",
"range": [
5,
29
],
"nested": [
{
"isBold": false,
"isCode": false,
"isItalic": true,
"isStrikethrough": false,
"range": [
19,
10
]
}
]
}]
Any suggestions on how you would go about rendering something like this?
The nested ranges and different attributes has me completely stuck... I tried going through the string char by char and collecting which attributes belong to each char – I'm close, but I'm not rendering links correctly and the code attributes get split up instead of wrapping their entire text:
Render of my attempt to parse

function renderTextAttributes(content, textAttributes)
let attributes = []
let currentAttributes, start, end
for (let i = 0; i < content.length; i++) {
if (i === content.length - 1) {
attributes.push({
attributes: currentAttributes,
content:
currentAttributes.length > 0
? `<span class="${currentAttributes.join(' ')}">${content.slice(
Math.max(0, start)
)}</span>`
: content.slice(Math.max(0, start)),
end,
start
})
} else if (currentAttributes) {
let charAttributes = []
for (const attribute of textAttributes) {
if (
i >= attribute.range[0] &&
i <= attribute.range[0] + attribute.range[1]
) {
charAttributes = [
...new Set([...charAttributes, ...findAttributes(attribute)])
]
}
}
if (
JSON.stringify(charAttributes) === JSON.stringify(currentAttributes)
) {
end = i
} else {
attributes.push({
attributes: currentAttributes,
content:
currentAttributes.length > 0
? `<span class="${currentAttributes.join(
' '
)}">${content.substring(start, end)}</span>`
: content.substring(start, end),
end,
start
})
currentAttributes = null
i--
}
} else {
currentAttributes = []
start = i
end = i + 1
for (const attribute of textAttributes) {
if (
i >= attribute.range[0] &&
i <= attribute.range[0] + attribute.range[1]
) {
currentAttributes = [
...new Set([...currentAttributes, ...findAttributes(attribute)])
]
}
}
}
}
let newContent = ''
for (const attribute of attributes) {
newContent += attribute.content
}
return newContent
}