Last active
September 1, 2021 04:39
-
-
Save ajitid/ac920ab9a3f87e0581552ea335c1f043 to your computer and use it in GitHub Desktop.
Parse Markdown links (not safe as its usage might create XSS attack vector)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
interface TextToken { | |
type: 'text'; | |
text: string; | |
} | |
interface LinkToken { | |
type: 'link'; | |
name: string; | |
link: string; | |
} | |
type Token = TextToken | LinkToken; | |
const parseMdLinks = (input: string) => { | |
const texts = []; | |
const links = []; | |
const regex = new RegExp(/\[.+?\]\(.+?\)/); | |
let s = input; | |
let res: RegExpExecArray | null = null; | |
let lastRes: RegExpExecArray | null = null; | |
while (true) { | |
res = regex.exec(s); | |
if (res == null) { | |
if (lastRes == null) { | |
texts.push(s); | |
break; | |
} | |
texts.push(lastRes.input.slice(lastRes.index + lastRes[0].length)); | |
break; | |
} else { | |
texts.push(s.slice(0, res.index)); | |
links.push(res[0]); | |
s = s.slice(res.index + res[0].length); | |
lastRes = res; | |
} | |
} | |
const merged: Token[] = []; | |
for (let i = 0; i < texts.length; ++i) { | |
merged.push({ | |
type: 'text', | |
text: texts[i], | |
}); | |
if (links[i] != null) { | |
let name = links[i]; | |
name = name.match(/\[.+?\]/)![0]; | |
name = name.slice(1, name.length - 1); | |
let link = links[i]; | |
link = link.match(/\(.+?\)/)![0]; | |
link = link.slice(1, link.length - 1); | |
merged.push({ | |
type: 'link', | |
name, | |
link, | |
}); | |
} | |
} | |
return merged; | |
}; | |
export default parseMdLinks; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
export const Message: React.FC = ({ children }) => { | |
const msgTokens = parseMdLinks(children as string); | |
const content = msgTokens.map((t, idx) => { | |
if (t.type === "text") return t.text; | |
else if (t.type === "link") | |
return ( | |
<a | |
key={idx} | |
href={t.link} | |
target="_blank" | |
rel="noopener noreferrer" | |
className="text-brand-blue-700 hover:text-brand-blue-500" | |
> | |
{t.name} | |
<ArrowUpRightIcon | |
size={14} | |
strokeWidth={3} | |
className="text-gray-500 inline-block" | |
/> | |
</a> | |
); | |
else return null; | |
}); | |
return <div>{content}</div>; | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment