Path: blob/main/src/resources/extensions/quarto/docusaurus/docusaurus.lua
12923 views
-- docusaurus.lua1-- Copyright (C) 2023 Posit Software, PBC23local kQuartoRawHtml = "quartoRawHtml"4local rawHtmlVars = pandoc.List()56local code_block = require('docusaurus_utils').code_block78local reactPreamble = pandoc.List()910local function addPreamble(preamble)11if not reactPreamble:includes(preamble) then12reactPreamble:insert(preamble)13end14end1516local function Pandoc(doc)17-- insert exports at the top if we have them18if #rawHtmlVars > 0 then19local exports = ("export const %s =\n[%s];"):format(kQuartoRawHtml,20table.concat(21rawHtmlVars:map(function(var) return '`'.. var .. '`' end),22","23)24)25doc.blocks:insert(1, pandoc.RawBlock("markdown", exports .. "\n"))26end2728-- insert react preamble if we have it29if #reactPreamble > 0 then30local preamble = table.concat(reactPreamble, "\n")31doc.blocks:insert(1, pandoc.RawBlock("markdown", preamble .. "\n"))32end3334return doc35end3637-- strip image attributes (which may result from38-- fig-format: retina) as they will result in an39-- img tag which won't hit the asset pipeline40local function Image(el)41el.attr = pandoc.Attr()42return el43end4445-- header attributes only support id46local function Header(el)47el.attr = pandoc.Attr(el.identifier)48return el49end5051-- transform 'mdx' into passthrough content, transform 'html'52-- into raw commamark to pass through via dangerouslySetInnerHTML53local function RawBlock(el)54if el.format == 'mdx' then55-- special mdx-code-block is not handled if whitespace is present after backtrick (#8333)56return pandoc.RawBlock("markdown", "````mdx-code-block\n" .. el.text .. "\n````")57elseif el.format == 'html' then58-- track the raw html vars (we'll insert them at the top later on as59-- mdx requires all exports be declared together)60local html = string.gsub(el.text, "\n+", "\n")61rawHtmlVars:insert(html)6263-- generate a div container for the raw html and return it as the block64local html = ("<div dangerouslySetInnerHTML={{ __html: %s[%d] }} />")65:format(kQuartoRawHtml, #rawHtmlVars-1) .. "\n"66return pandoc.RawBlock("html", html)67end68end6970local function DecoratedCodeBlock(node)71local el = node.code_block72return code_block(el, node.filename)73end7475local function jsx(content)76return pandoc.RawBlock("markdown", content)77end7879local function tabset(node)80-- note groupId81local groupId = ""82local group = node.attr.attributes["group"]83if group then84groupId = ([[ groupId="%s"]]):format(group)85end8687-- create tabs88local tabs = pandoc.Div({})89tabs.content:insert(jsx("<Tabs" .. groupId .. ">"))9091-- iterate through content92for i=1,#node.tabs do93local content = node.tabs[i].content94local title = node.tabs[i].title9596tabs.content:insert(jsx(([[<TabItem value="%s">]]):format(pandoc.utils.stringify(title))))97if type(content) == "table" then98tabs.content:extend(content)99else100tabs.content:insert(content)101end102tabs.content:insert(jsx("</TabItem>"))103end104105-- end tab and tabset106tabs.content:insert(jsx("</Tabs>"))107108-- ensure we have required deps109addPreamble("import Tabs from '@theme/Tabs';")110addPreamble("import TabItem from '@theme/TabItem';")111112return tabs113end114115local function Table(tbl)116local out = pandoc.write(pandoc.Pandoc({tbl}), FORMAT, PANDOC_WRITER_OPTIONS)117-- if the table was written in a way that looks like HTML, then wrap it in the right RawBlock way118if string.match(out, "^%s*%<table") then119local unwrapped = pandoc.RawBlock('html', out)120return RawBlock(unwrapped)121end122end123124quarto._quarto.ast.add_renderer("Tabset", function()125return quarto._quarto.format.isDocusaurusOutput()126end, function(node)127return tabset(node)128end)129130quarto._quarto.ast.add_renderer("Callout", function()131return quarto._quarto.format.isDocusaurusOutput()132end, function(node)133local admonition = pandoc.Blocks({})134if node.title then135start = pandoc.Plain({})136start.content:insert(pandoc.RawInline("markdown", ":::" .. node.type .. "["))137start.content:extend(quarto.utils.as_inlines(node.title))138start.content:insert(pandoc.RawInline("markdown", "]\n"))139admonition:insert(start)140else141admonition:insert(pandoc.RawBlock("markdown", ":::" .. node.type))142end143local content = node.content144if type(content) == "table" then145admonition:extend(content)146else147admonition:insert(content)148end149admonition:insert(pandoc.RawBlock("markdown", ":::\n"))150return admonition151end)152153quarto._quarto.ast.add_renderer("DecoratedCodeBlock", function()154return quarto._quarto.format.isDocusaurusOutput()155end, function(node)156local el = node.code_block157return code_block(el, node.filename)158end)159160quarto._quarto.ast.add_renderer("FloatRefTarget", function()161return quarto._quarto.format.isDocusaurusOutput()162end, function(float)163float = quarto.doc.crossref.decorate_caption_with_crossref(float)164if quarto.doc.crossref.cap_location(float) == "top" then165return pandoc.Blocks({166pandoc.RawBlock("markdown", "<div id=\"" .. float.identifier .. "\">"),167pandoc.Div(quarto.utils.as_blocks(float.caption_long)),168pandoc.Div(quarto.utils.as_blocks(float.content)),169pandoc.RawBlock("markdown", "</div>")170})171else172return pandoc.Blocks({173pandoc.RawBlock("markdown", "<div id=\"" .. float.identifier .. "\">"),174pandoc.Div(quarto.utils.as_blocks(float.content)),175pandoc.Div(quarto.utils.as_blocks(float.caption_long)),176pandoc.RawBlock("markdown", "</div>")177})178end179end)180181return {182{183traverse = "topdown",184Image = Image,185Header = Header,186RawBlock = RawBlock,187DecoratedCodeBlock = DecoratedCodeBlock,188CodeBlock = CodeBlock,189Table = Table,190},191{192Pandoc = Pandoc,193}194}195196