Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions news/changelog-1.11.md
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,7 @@ All changes included in 1.11:
## Other fixes and improvements

- ([#9864](https://github.com/quarto-dev/quarto-cli/issues/9864), [#11139](https://github.com/quarto-dev/quarto-cli/issues/11139)): Fix metadata defined both in a document's front matter and in `_quarto.yml`, a directory `_metadata.yml` or `metadata-files` reaching Pandoc templates and Lua filters with only the document's values. The values are now merged, and the document's values still take precedence for single values. Lists are combined instead of replaced, so a document can no longer drop entries that the project, a directory `_metadata.yml` or `metadata-files` add to a list such as `keywords`. (author: @jkrumbiegel)
- ([#14765](https://github.com/quarto-dev/quarto-cli/issues/14765)): Fix content after a `mermaid` diagram disappearing, and `ojs` cells after it not running, when the diagram has its own `---` configuration block. (author: @mcanouil)
- ([#14775](https://github.com/quarto-dev/quarto-cli/issues/14775)): Fix a crash when the `QUARTO_R` environment variable is set to a malformed path. Quarto now warns and falls back to other R lookup methods.
- ([#14865](https://github.com/quarto-dev/quarto-cli/issues/14865)): Fix internal links in a preview being treated as external when the preview is reached through a proxy, such as on Posit Workbench. Links are now classified against the origin the browser sees.
- ([#14878](https://github.com/quarto-dev/quarto-cli/pull/14878)): Add `az` (Azerbaijani) language translation. (author: @abdanar)
Expand Down
30 changes: 15 additions & 15 deletions src/core/handlers/mermaid.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,11 @@ import {
import { Element } from "../deno-dom.ts";
import { convertFromYaml } from "../lib/yaml-schema/from-yaml.ts";
import { readYamlFromString } from "../yaml.ts";
import { pandocHtmlBlock, pandocRawStr } from "../pandoc/codegen.ts";
import {
pandocCode,
pandocHtmlBlock,
pandocRawStr,
} from "../pandoc/codegen.ts";
import { LocalizedError } from "../lib/located-error.ts";
import { info, warning } from "../../deno_ral/log.ts";
import { FormatDependency } from "../../config/types.ts";
Expand Down Expand Up @@ -402,13 +406,6 @@ mermaid.initialize(${JSON.stringify(mermaidOpts)});
// deno-lint-ignore require-await
const makeJs = async () => {
setupMermaidJsRuntime();
// removed until we use mermaid 10.0.0
//
// const { baseName: tooltipName } = handlerContext
// .uniqueFigureName(
// "mermaid-tooltip-",
// "",
// );
const preAttrs = [];
if (options.label) {
preAttrs.push(`label="${options.label}"`);
Expand All @@ -426,16 +423,19 @@ mermaid.initialize(${JSON.stringify(mermaidOpts)});
attrs.reveal = true;
}

// the diagram source is user text emitted verbatim, and can contain lines
// that breakQuartoMd would read as yaml front matter delimiters (mermaid's
// own `---` config block, see https://github.com/quarto-dev/quarto-cli/issues/14765).
// a raw html block keeps the markdown splitter from looking inside it.
const rawHtmlBlock = pandocCode({
language: "=html",
contents: [preEl],
});

return this.build(
handlerContext,
cell,
mappedConcat([
preEl.mappedString(),
// tooltips appear to be broken in mermaid 9.2.2?
// They don't even work on their website: https://mermaid-js.github.io/mermaid/#/flowchart
// we drop them for now.
// `\n<div id="${tooltipName}" class="mermaidTooltip"></div>`,
]),
rawHtmlBlock.mappedString(),
options,
attrs,
new Set([kMermaidFormat]),
Expand Down
8 changes: 6 additions & 2 deletions src/core/pandoc/codegen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -214,8 +214,12 @@ export function pandocBlock(delimiterCharacter: ":" | "`") {
// now find the longest streak of delimiter characters in the innerLs
const longestStreak = Math.max(...innerLs.map((eitherS) => {
const s = asMappedString(eitherS).value;
return s.match(new RegExp(`${delimiterCharacter}+`, "g"))?.[0]
?.length || 0;
const runs = s.match(new RegExp(`${delimiterCharacter}+`, "g")) ??
[];
return runs.reduce(
(longest, run) => Math.max(longest, run.length),
0,
);
}));
const delimiter = delimiterCharacter.repeat(
Math.max(3, longestStreak + 1),
Expand Down
11 changes: 11 additions & 0 deletions tests/docs/playwright/html/mermaid-accessibility.qmd
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
---
title: "Mermaid accessible name and description"
format: html
---

```{mermaid}
flowchart LR
accTitle: Build pipeline
accDescr: Source goes through build to deploy
A[Source] --> B[Build] --> C[Deploy]
```
49 changes: 49 additions & 0 deletions tests/docs/smoke-all/2026/08/12/14765.qmd
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
---
title: "mermaid source that looks like markdown, then ojs"
format: html
_quarto:
tests:
html:
ensureHtmlElements:
- ["pre.mermaid.mermaid-js", "div[id^=\"ojs-cell-\"]"]
- []
ensureHtmlElementCount:
- selectors: ["pre.mermaid.mermaid-js"]
counts: [2]
---

Each `mermaid` cell below is emitted verbatim into the intermediate markdown,
inside a raw HTML block. If anything in the diagram source ends that block early,
the rest of the document is misread, and the `ojs` cell at the end is not
compiled.

The first diagram carries Mermaid's own `---` front matter to set `config`. Its
closing `---` used to be read as the start of a YAML front matter block that
swallowed everything after it.

```{mermaid}
---
config:
look: handDrawn
---
graph LR
A --> B
```

The second diagram uses Mermaid markdown strings. A label with a single backtick
comes first, then a line that starts with three backticks. The raw block fence
must be longer than the longest backtick run, not the first one, or that line
closes the block.

````{mermaid}
graph LR
A["`a tick label`"] --> B["`two
```
lines`"]
````

```{ojs}
//| echo: true
x = 2
x ** 5
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/*
* html-mermaid-accessibility.spec.ts
*
* Copyright (C) 2026 Posit Software, PBC
*/

import { expect, test } from "@playwright/test";

test("mermaid diagram keeps its accessible name and description", async ({ page }) => {
await page.goto("./html/mermaid-accessibility.html");

const svg = page.locator("svg.mermaid-js");
await expect(svg).toHaveAttribute("aria-roledescription", /.+/);
await expect(svg.locator("title")).toHaveText("Build pipeline");
await expect(svg.locator("desc")).toHaveText(
"Source goes through build to deploy",
);
});
42 changes: 42 additions & 0 deletions tests/unit/pandoc-codegen/block-fence.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/*
* block-fence.test.ts
*
* Copyright (C) 2026 Posit Software, PBC
*/

import { unitTest } from "../../test.ts";
import { assertEquals } from "testing/asserts";
import {
pandocCode,
pandocDiv,
pandocRawStr,
} from "../../../src/core/pandoc/codegen.ts";

// deno-lint-ignore require-await
unitTest(
"pandoc-codegen - code fence is longer than the longest backtick run",
async () => {
const block = pandocCode({
language: "=html",
contents: [pandocRawStr("a `b` c\n```\nd\n")],
});
assertEquals(
block.mappedString().value,
"\n````{=html}\na `b` c\n```\nd\n````\n",
);
},
);

// deno-lint-ignore require-await
unitTest(
"pandoc-codegen - div fence is longer than the longest colon run",
async () => {
const block = pandocDiv({
contents: [pandocRawStr("a: b\n:::: {}\n")],
});
assertEquals(
block.mappedString().value,
"\n:::::{}\na: b\n:::: {}\n:::::\n",
);
},
);
Loading