Skip to content

Commit

Permalink
feat(rehype): Support fallbackLanguage on lazy mode (#912)
Browse files Browse the repository at this point in the history
  • Loading branch information
fuma-nama authored Jan 30, 2025
1 parent c55865f commit 6a85269
Show file tree
Hide file tree
Showing 5 changed files with 54 additions and 19 deletions.
41 changes: 25 additions & 16 deletions packages/rehype/src/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,30 +98,29 @@ function rehypeShikiFromHighlighter(
if (node.tagName === 'pre') {
handler = PreHandler
}

if (node.tagName === 'code' && inline) {
else if (node.tagName === 'code' && inline) {
handler = InlineCodeHandlers[inline]
}

if (!handler)
else {
return
}

const res = handler(tree, node)
if (!res)
const parsed = handler(tree, node)
if (!parsed)
return

let lang: string | undefined
let lazyLoad = false

if (!res.lang) {
if (!parsed.lang) {
lang = defaultLanguage
}
else if (highlighter.getLoadedLanguages().includes(res.lang) || isSpecialLang(res.lang)) {
lang = res.lang
else if (highlighter.getLoadedLanguages().includes(parsed.lang) || isSpecialLang(parsed.lang)) {
lang = parsed.lang
}
else if (lazy) {
lazyLoad = true
lang = res.lang
lang = parsed.lang
}
else if (fallbackLanguage) {
lang = fallbackLanguage
Expand All @@ -130,14 +129,14 @@ function rehypeShikiFromHighlighter(
if (!lang)
return

const processNode = (): void => {
const meta = res.meta ? parseMetaString?.(res.meta, node, tree) : undefined
const meta = parsed.meta ? parseMetaString?.(parsed.meta, node, tree) : undefined

const fragment = highlight(lang, res.code, res.meta, meta ?? {})
const processNode = (targetLang: string): void => {
const fragment = highlight(targetLang, parsed.code, parsed.meta, meta ?? {})
if (!fragment)
return

if (res.type === 'inline') {
if (parsed.type === 'inline') {
const head = fragment.children[0]
if (head.type === 'element' && head.tagName === 'pre') {
head.tagName = 'span'
Expand All @@ -148,10 +147,20 @@ function rehypeShikiFromHighlighter(
}

if (lazyLoad) {
queue.push(highlighter.loadLanguage(lang).then(() => processNode()))
try {
// passed language is checked in sync, promise `.catch()` wouldn't work
queue.push(highlighter.loadLanguage(lang).then(() => processNode(lang)))
}
catch (error) {
if (fallbackLanguage)
return processNode(fallbackLanguage)
else if (onError)
onError(error)
else throw error
}
}
else {
processNode()
processNode(lang)
}

// don't visit processed nodes
Expand Down
4 changes: 1 addition & 3 deletions packages/rehype/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,7 @@ export interface RehypeShikiExtraOptions {
defaultLanguage?: string

/**
* The fallback language to use when specified language is not loaded
*
* Ignored if `lazy` is enabled
* The fallback language to use when specified language is not loaded, or not included in the bundle
*/
fallbackLanguage?: string

Expand Down
24 changes: 24 additions & 0 deletions packages/rehype/test/core.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,3 +99,27 @@ it('run with rehype-raw', async () => {

await expect(file.toString()).toMatchFileSnapshot('./fixtures/a.core.out.html')
})

it('run with lazy + fallback language', async () => {
const highlighter = await createHighlighter({
themes: [
'vitesse-light',
],
langs: [],
})

const file = await unified()
.use(remarkParse)
.use(remarkRehype)
.use(rehypeShikiFromHighlighter, highlighter, {
lazy: true,
theme: 'vitesse-light',
defaultLanguage: 'text',
fallbackLanguage: 'text',
langs: [],
})
.use(rehypeStringify)
.process(await fs.readFile(new URL('./fixtures/d.md', import.meta.url)))

await expect(file.toString()).toMatchFileSnapshot('./fixtures/d.out.html')
})
3 changes: 3 additions & 0 deletions packages/rehype/test/fixtures/d.md

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions packages/rehype/test/fixtures/d.out.html

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 6a85269

Please sign in to comment.