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
4 changes: 4 additions & 0 deletions news/changelog-1.9.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,10 @@ All changes included in 1.9:

- ([#13722](https://github.com/quarto-dev/quarto-cli/issues/13722)): Fix `light-content` / `dark-content` SCSS rules not included in Reveal.js format. (author: @mcanouil)

### `ipynb`

- ([#13956](https://github.com/quarto-dev/quarto-cli/issues/13956)): Fix crash when rendering to `ipynb` format with figure labels (`#| label: fig-*`) on cells for cross references.

## Projects

- ([#13892](https://github.com/quarto-dev/quarto-cli/issues/13892)): Fix `output-dir: ./` deleting entire project directory. `output-dir` must be a subdirectory of the project directory and check is now better to avoid deleting the project itself when it revolves to the same path.
Expand Down
7 changes: 3 additions & 4 deletions src/resources/filters/customnodes/floatreftarget.lua
Original file line number Diff line number Diff line change
Expand Up @@ -933,10 +933,9 @@ end, function(float)
float.identifier)
end

return pandoc.Div({
float.content,
pandoc.Para(quarto.utils.as_inlines(float.caption_long) or {}),
});
local blocks = pandoc.Blocks(float.content)
blocks:insert(pandoc.Para(quarto.utils.as_inlines(float.caption_long) or {}))
return pandoc.Div(blocks)
end)

-- this should really be "_quarto.format.isEmbedIpynb()" or something like that..
Expand Down
23 changes: 23 additions & 0 deletions tests/docs/smoke-all/2026/01/27/issue-13956.qmd
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
---
title: "Issue 13956"
format: ipynb
_quarto:
tests:
ipynb:
ensureIpynbCellMatches:
cellType: markdown
matches:
- 'Figure\s1'
- '#fig-test'
- 'quarto-xref'
- 'This should render without crashing'
---

Testing crash when using inline `#| label: fig-*` syntax with format: ipynb.

```{python}
#| label: fig-test
print("This should render without crashing")
```

See @fig-test for the output.
2 changes: 2 additions & 0 deletions tests/smoke/smoke-all.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import {
ensureDocxXpath,
ensureFileRegexMatches,
ensureHtmlElements,
ensureIpynbCellMatches,
ensurePdfRegexMatches,
ensurePdfTextPositions,
ensurePdfMetadata,
Expand Down Expand Up @@ -181,6 +182,7 @@ function resolveTestSpecs(
ensureHtmlElementContents,
ensureHtmlElementCount,
ensureFileRegexMatches,
ensureIpynbCellMatches,
ensureLatexFileRegexMatches,
ensureTypstFileRegexMatches,
ensureDocxRegexMatches,
Expand Down
34 changes: 34 additions & 0 deletions tests/verify.ts
Original file line number Diff line number Diff line change
Expand Up @@ -302,6 +302,40 @@ export const validJsonWithFields = (file: string, fields: Record<string, unknown
}
}

export const ensureIpynbCellMatches = (
file: string,
options: {
cellType: "code" | "markdown";
matches?: (string | RegExp)[];
noMatches?: (string | RegExp)[];
}
): Verify => {
const { cellType, matches = [], noMatches = [] } = options;
return {
name: `IPYNB ${file} has ${cellType} cells matching patterns`,
verify: async (_output: ExecuteOutput[]) => {
const jsonStr = Deno.readTextFileSync(file);
const notebook = JSON.parse(jsonStr);
// deno-lint-ignore no-explicit-any
const cells = notebook.cells.filter((c: any) => c.cell_type === cellType);
// deno-lint-ignore no-explicit-any
const content = cells.map((c: any) =>
Array.isArray(c.source) ? c.source.join("") : c.source
).join("\n");

for (const m of matches) {
const regex = typeof m === "string" ? new RegExp(m) : m;
assert(regex.test(content), `Pattern ${m} not found in ${cellType} cells of ${file}`);
}
for (const m of noMatches) {
const regex = typeof m === "string" ? new RegExp(m) : m;
assert(!regex.test(content), `Pattern ${m} should not be in ${cellType} cells of ${file}`);
}
return Promise.resolve();
}
};
};

export const outputCreated = (
input: string,
to: string,
Expand Down
Loading