Pre a bout of covid I had a personal project on, which took javascript code as a text file and syntax highlighted it.
Coming out of covid with brain fog, I abandoned it.
One of the issues I didn’t figure out was how to syntax highlight template string expressions.
I have re-visited it with the following code
function matchExpression (source) {
const matches = [];
// create chunks from string, splitting on braces e.g.
// source: `${fruit.map((fruit, i) => { return `${i}:...`
// result: ['${', 'fruit.map((fruit, i) => ', '{', 'return `', '${', 'i', '}', ':'....]
const chars = source.split(/(\${|[}{])/).filter(x => x);
let exprStart = 0;
let depth = 0;
for (const [i, char] of chars.entries()) {
// test if char matches opening braces for expression
if (char === '${') {
depth += 1;
// if depth is 1 expression starts here
if (depth === 1) {
exprStart = i + 1;
}
}
// if inside of that expression
if (depth >= 1) {
if (char === '{') {
depth += 1;
} else if (char === '}') {
depth -= 1;
// have we balanced the opening braces for expression
if (depth === 0) {
matches.push({ expr: chars.slice(exprStart, i).join('') });
}
}
} else {
// push the non expression chars
matches.push({ text: char });
}
}
return matches;
}
I split the text on braces, I balance those braces using a depth variable and join the expressions.
For example given an input of:
some t{ext here ${items.map((item, i) => { return ${i}:${item}
}).join(‘\n’)} something here ${varname} text here
My output is
Array(7) [
{ text: 'some t' },
{ text: '{' },
{ text: 'ext here ' },
{
expr: "items.map((item, i) => { return `${i}:${item}` }).join('\n')"
},
{ text: ' something here ' },
{ expr: 'varname' },
{ text: ' text here' }
]
My thinking is the expressions could then be passed recursively into the highlighter.
I know it’s flawed in that placing a rogue brace inside of an inner template string will throw it e.g.
...{ return `} ${i}:${item}` }...
I tried asking chatGPT to do a refactor, which was an experience.
Just wondered if anyone had any input. I’m sure what I have done is over engineered.