diff --git a/plugins/code-syntax-highlight/src/renderers/toHTMLRenderers.ts b/plugins/code-syntax-highlight/src/renderers/toHTMLRenderers.ts index bb8bf495c5..e43158142d 100644 --- a/plugins/code-syntax-highlight/src/renderers/toHTMLRenderers.ts +++ b/plugins/code-syntax-highlight/src/renderers/toHTMLRenderers.ts @@ -1,6 +1,7 @@ import type { MdNode, CodeBlockMdNode } from '@toast-ui/editor'; import type { HTMLToken } from '@toast-ui/toastmark'; import { PrismJs } from '@t/index'; +import { escapeXml } from '@/utils/common'; const BACKTICK_COUNT = 3; @@ -17,6 +18,7 @@ export function getHTMLRenderers(prism: PrismJs) { } let content = node.literal!; + let contentEscaped = false; if (infoWords.length && infoWords[0].length) { const [lang] = infoWords; @@ -28,9 +30,12 @@ export function getHTMLRenderers(prism: PrismJs) { if (registeredLang) { content = prism.highlight(node.literal!, registeredLang, lang); + contentEscaped = true; } } + content = contentEscaped ? content : escapeXml(content); + return [ { type: 'openTag', tagName: 'pre', classNames: preClasses }, { type: 'openTag', tagName: 'code', attributes: codeAttrs }, diff --git a/plugins/code-syntax-highlight/src/utils/common.ts b/plugins/code-syntax-highlight/src/utils/common.ts index 0646d3a8fb..0f224167f0 100644 --- a/plugins/code-syntax-highlight/src/utils/common.ts +++ b/plugins/code-syntax-highlight/src/utils/common.ts @@ -1,3 +1,28 @@ export function flatten(arr: T[]): T[] { return arr.reduce((a, b) => a.concat(Array.isArray(b) ? flatten(b) : b), []); } + +const XMLSPECIAL = '[&<>"]'; +const reXmlSpecial = new RegExp(XMLSPECIAL, 'g'); + +function replaceUnsafeChar(char: string) { + switch (char) { + case '&': + return '&'; + case '<': + return '<'; + case '>': + return '>'; + case '"': + return '"'; + default: + return char; + } +} + +export function escapeXml(text: string) { + if (reXmlSpecial.test(text)) { + return text.replace(reXmlSpecial, replaceUnsafeChar); + } + return text; +}