@scalar/code-highlight
Advanced tools
+6
-0
| # @scalar/code-highlight | ||
| ## 0.3.4 | ||
| ### Patch Changes | ||
| - [#8964](https://github.com/scalar/scalar/pull/8964): fix markdown inside HTML text tags like `<p>` so inline formatting is rendered. | ||
| ## 0.3.3 | ||
@@ -4,0 +10,0 @@ |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"markdown.d.ts","sourceRoot":"","sources":["../../src/markdown/markdown.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,eAAe,EAAqB,MAAM,OAAO,CAAA;AAsB9E,YAAY,EAAE,IAAI,EAAE,MAAM,OAAO,CAAA;AAEjC;;GAEG;AACH,eAAO,MAAM,SAAS,GAAI,MAAM,IAAI,KAAG,IAAI,IAAI,OAE9C,CAAA;AAqBD;;GAEG;AACH,wBAAgB,gBAAgB,CAC9B,QAAQ,EAAE,MAAM,EAChB,OAAO,CAAC,EAAE;IACR,UAAU,CAAC,EAAE,MAAM,EAAE,CAAA;IACrB,SAAS,CAAC,EAAE,MAAM,EAAE,CAAA;IACpB,SAAS,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,IAAI,CAAA;IAChC,aAAa,CAAC,EAAE,MAAM,CAAA;CACvB,UAuDF;AASD;;GAEG;AACH,wBAAgB,WAAW,CACzB,QAAQ,EAAE,MAAM,EAChB,KAAK,GAAE,MAAU,GAChB;IACD,KAAK,EAAE,MAAM,CAAA;IACb,KAAK,EAAE,MAAM,CAAA;CACd,EAAE,CAiBF;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,OAAO,GAAG,eAAe,GAAG,MAAM,CAUpE;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,YAgC5C"} | ||
| {"version":3,"file":"markdown.d.ts","sourceRoot":"","sources":["../../src/markdown/markdown.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAsD,IAAI,EAAE,eAAe,EAAE,MAAM,OAAO,CAAA;AAuB/G,YAAY,EAAE,IAAI,EAAE,MAAM,OAAO,CAAA;AAEjC;;GAEG;AACH,eAAO,MAAM,SAAS,GAAI,MAAM,IAAI,KAAG,IAAI,IAAI,OAE9C,CAAA;AAiGD;;GAEG;AACH,wBAAgB,gBAAgB,CAC9B,QAAQ,EAAE,MAAM,EAChB,OAAO,CAAC,EAAE;IACR,UAAU,CAAC,EAAE,MAAM,EAAE,CAAA;IACrB,SAAS,CAAC,EAAE,MAAM,EAAE,CAAA;IACpB,SAAS,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,IAAI,CAAA;IAChC,aAAa,CAAC,EAAE,MAAM,CAAA;CACvB,UAyDF;AASD;;GAEG;AACH,wBAAgB,WAAW,CACzB,QAAQ,EAAE,MAAM,EAChB,KAAK,GAAE,MAAU,GAChB;IACD,KAAK,EAAE,MAAM,CAAA;IACb,KAAK,EAAE,MAAM,CAAA;CACd,EAAE,CAiBF;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,OAAO,GAAG,eAAe,GAAG,MAAM,CAUpE;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,YAgC5C"} |
| import rehypeExternalLinks from 'rehype-external-links'; | ||
| import rehypeFormat from 'rehype-format'; | ||
| import rehypeParse from 'rehype-parse'; | ||
| import rehypeRaw from 'rehype-raw'; | ||
@@ -34,3 +35,66 @@ import rehypeSanitize, { defaultSchema } from 'rehype-sanitize'; | ||
| }; | ||
| const TAGS_WITH_INLINE_MARKDOWN = new Set(['dd', 'dt', 'li', 'p', 'summary', 'td', 'th']); | ||
| const MAY_CONTAIN_INLINE_MARKDOWN = /[`*_\[~]/; | ||
| /** | ||
| * Preserve HTML-like text in inline markdown by turning mdast `html` nodes into text nodes. | ||
| */ | ||
| const preserveHtmlLikeText = () => (tree) => { | ||
| visit(tree, 'html', (node, index, parent) => { | ||
| if (typeof index !== 'number' || !parent || !('children' in parent) || !Array.isArray(parent.children)) { | ||
| return; | ||
| } | ||
| parent.children[index] = { | ||
| type: 'text', | ||
| value: node.value ?? '', | ||
| }; | ||
| }); | ||
| }; | ||
| const inlineMarkdownProcessor = unified().use(remarkParse).use(remarkGfm).use(preserveHtmlLikeText).use(remarkRehype); | ||
| const htmlFragmentParser = unified().use(rehypeParse, { fragment: true }); | ||
| const htmlFragmentStringifier = unified().use(rehypeStringify); | ||
| /** | ||
| * Parse inline markdown and return children from the generated paragraph. | ||
| */ | ||
| const extractInlineChildrenFromMarkdown = (value) => { | ||
| const tree = inlineMarkdownProcessor.runSync(inlineMarkdownProcessor.parse(value)); | ||
| if (tree.children.length !== 1) { | ||
| return []; | ||
| } | ||
| const paragraph = tree.children.at(0); | ||
| if (!paragraph || paragraph.type !== 'element' || paragraph.tagName !== 'p') { | ||
| return []; | ||
| } | ||
| return paragraph.children; | ||
| }; | ||
| /** | ||
| * Re-parses text nodes in selected HTML tags so inline markdown works in tags like <p>. | ||
| */ | ||
| const transformInlineMarkdownInHtml = () => (tree) => { | ||
| visit(tree, 'element', (node) => { | ||
| if (!TAGS_WITH_INLINE_MARKDOWN.has(node.tagName)) { | ||
| return; | ||
| } | ||
| node.children = node.children.flatMap((child) => { | ||
| if (child.type !== 'text' || !MAY_CONTAIN_INLINE_MARKDOWN.test(child.value)) { | ||
| return [child]; | ||
| } | ||
| const markdownChildren = extractInlineChildrenFromMarkdown(child.value); | ||
| return markdownChildren.length ? markdownChildren : [child]; | ||
| }); | ||
| }); | ||
| }; | ||
| /** | ||
| * Rewrites raw HTML strings so inline markdown parsing is only applied to raw HTML input. | ||
| */ | ||
| const transformInlineMarkdownInRawHtml = () => (tree) => { | ||
| visit(tree, 'raw', (node) => { | ||
| if (typeof node.value !== 'string' || !MAY_CONTAIN_INLINE_MARKDOWN.test(node.value)) { | ||
| return; | ||
| } | ||
| const htmlFragmentTree = htmlFragmentParser.parse(node.value); | ||
| transformInlineMarkdownInHtml()(htmlFragmentTree); | ||
| node.value = htmlFragmentStringifier.stringify(htmlFragmentTree); | ||
| }); | ||
| }; | ||
| /** | ||
| * Take a Markdown string and generate HTML from it | ||
@@ -55,3 +119,5 @@ */ | ||
| .use(rehypeAlert) | ||
| // Creates a HTML AST | ||
| // Parse inline markdown only inside raw HTML fragments, not normal markdown output | ||
| .use(transformInlineMarkdownInRawHtml) | ||
| // Creates an HTML AST | ||
| .use(rehypeRaw) | ||
@@ -58,0 +124,0 @@ // Removes disallowed tags |
+1
-1
@@ -19,3 +19,3 @@ { | ||
| ], | ||
| "version": "0.3.3", | ||
| "version": "0.3.4", | ||
| "engines": { | ||
@@ -22,0 +22,0 @@ "node": ">=22" |
56216
5.38%1181
5.92%