From 2a2e926160075a958eae3e2cdbfc25ca991f26bd Mon Sep 17 00:00:00 2001 From: Christophe Dervieux Date: Tue, 21 Oct 2025 18:47:29 +0200 Subject: [PATCH 1/3] Add warning for callouts with invalid ID prefixes instead of failing completely with bad errors and implement test case --- src/resources/filters/customnodes/callout.lua | 13 ++++++-- tests/docs/smoke-all/2025/10/21/13589.qmd | 32 +++++++++++++++++++ 2 files changed, 42 insertions(+), 3 deletions(-) create mode 100644 tests/docs/smoke-all/2025/10/21/13589.qmd diff --git a/src/resources/filters/customnodes/callout.lua b/src/resources/filters/customnodes/callout.lua index 962262c38d..cd10970ddc 100644 --- a/src/resources/filters/customnodes/callout.lua +++ b/src/resources/filters/customnodes/callout.lua @@ -275,7 +275,16 @@ function _callout_main() end end end - if callout.attr.identifier == "" then + -- Check if identifier has a valid crossref category + local ref_type = refType(callout.attr.identifier) + local category = ref_type ~= nil and crossref.categories.by_ref_type[ref_type] or nil + + -- Warn if identifier was provided but category is invalid + if callout.attr.identifier ~= "" and category == nil then + warn("Callout ID '" .. callout.attr.identifier .. "' has unknown reference type '" .. (ref_type or "none") .. "'. Rendering as regular callout without cross-reference support.") + end + + if category == nil then return _quarto.format.typst.function_call("callout", { { "body", _quarto.format.typst.as_typst_content(callout.content) }, { "title", _quarto.format.typst.as_typst_content( @@ -298,8 +307,6 @@ function _callout_main() { "icon", pandoc.RawInline("typst", callout.icon == false and "none" or ("" .. icon .. "()"))}, { "body_background_color", pandoc.RawInline("typst", body_background_color)} }) - - local category = crossref.categories.by_ref_type[refType(callout.attr.identifier)] return make_typst_figure { content = typst_callout, caption_location = "top", diff --git a/tests/docs/smoke-all/2025/10/21/13589.qmd b/tests/docs/smoke-all/2025/10/21/13589.qmd new file mode 100644 index 0000000000..1bb0c5b3f2 --- /dev/null +++ b/tests/docs/smoke-all/2025/10/21/13589.qmd @@ -0,0 +1,32 @@ +--- +title: "Callout with invalid ID prefix" +format: + typst: + keep-typ: true +_quarto: + tests: + typst: + ensureTypstFileRegexMatches: + - ['#callout\('] + - [] + printsMessage: + level: INFO + regex: 'WARNING(.*)Callout ID ''random-id'' has unknown reference type ''random''' + noErrors: true +--- + +## Test callout with invalid crossref ID + +This tests that callouts with invalid ID prefixes (not matching any known crossref category) +should render with a warning instead of crashing. + +::: {#random-id .callout-note} + +## Note with invalid ID + +This callout uses `#random-id` which has an unknown prefix "random". +The valid prefixes are: fig, tbl, lst, nte, wrn, cau, tip, imp, prf, rem, sol. + +This should render successfully with a warning, not crash. + +::: From 6e5e798d48712fd2f618dd9ee32fa47ccce8f902 Mon Sep 17 00:00:00 2001 From: Christophe Dervieux Date: Tue, 21 Oct 2025 19:52:57 +0200 Subject: [PATCH 2/3] Add a test case for the valid callout ID prefix --- .../docs/smoke-all/2025/10/21/13589-valid.qmd | 34 +++++++++++++++++++ tests/docs/smoke-all/2025/10/21/13589.qmd | 22 +++++++----- 2 files changed, 48 insertions(+), 8 deletions(-) create mode 100644 tests/docs/smoke-all/2025/10/21/13589-valid.qmd diff --git a/tests/docs/smoke-all/2025/10/21/13589-valid.qmd b/tests/docs/smoke-all/2025/10/21/13589-valid.qmd new file mode 100644 index 0000000000..0c3b87b318 --- /dev/null +++ b/tests/docs/smoke-all/2025/10/21/13589-valid.qmd @@ -0,0 +1,34 @@ +--- +title: "Callout with valid ID prefix" +format: + typst: + keep-typ: true +_quarto: + tests: + typst: + ensureTypstFileRegexMatches: + - + - '#figure\(\[(\r\n?|\n)#block\[(\r\n?|\n)#callout' + - [] + printsMessage: + level: INFO + regex: 'WARNING(.*)Callout ID(.*)unknown reference type' + negate: true + noErrors: true +--- + +## Test callout with valid crossref ID + +This tests that callouts with valid ID prefixes (matching known crossref categories) +are properly wrapped in figures for cross-reference support. + +::: {#nte-valid .callout-note} + +## Note with valid ID + +This callout uses `#nte-valid` which has the valid prefix "nte" (for notes). +This should be wrapped in a `figure` for cross-referencing support. + +::: + +As mentioned in @nte-valid, valid callout IDs should work correctly. diff --git a/tests/docs/smoke-all/2025/10/21/13589.qmd b/tests/docs/smoke-all/2025/10/21/13589.qmd index 1bb0c5b3f2..68e59902e5 100644 --- a/tests/docs/smoke-all/2025/10/21/13589.qmd +++ b/tests/docs/smoke-all/2025/10/21/13589.qmd @@ -1,5 +1,5 @@ --- -title: "Callout with invalid ID prefix" +title: "Callout with invalid ID prefix (#13589)" format: typst: keep-typ: true @@ -7,8 +7,12 @@ _quarto: tests: typst: ensureTypstFileRegexMatches: - - ['#callout\('] - - [] + - + # Should render as plain callout with body parameter + - '#callout\(\s*body:' + - + # Should NOT be wrapped in figure+block structure + - '#figure\(\[(\r\n?|\n)#block\[(\r\n?|\n)#callout' printsMessage: level: INFO regex: 'WARNING(.*)Callout ID ''random-id'' has unknown reference type ''random''' @@ -17,16 +21,18 @@ _quarto: ## Test callout with invalid crossref ID -This tests that callouts with invalid ID prefixes (not matching any known crossref category) -should render with a warning instead of crashing. +This tests the fix for issue #13589: callouts with invalid ID prefixes +(not matching any known crossref category) should render with a warning +instead of crashing with "attempt to index a nil value". ::: {#random-id .callout-note} ## Note with invalid ID -This callout uses `#random-id` which has an unknown prefix "random". -The valid prefixes are: fig, tbl, lst, nte, wrn, cau, tip, imp, prf, rem, sol. +This callout uses `#random-id` with unknown prefix "random". -This should render successfully with a warning, not crash. +Valid prefixes are: fig, tbl, lst, nte, wrn, cau, tip, imp, prf, rem, sol. + +Expected behavior: renders as plain callout (no figure wrapping) with warning. ::: From 5aa9e94f4fc7b6195fef56817b79e131cc10a76c Mon Sep 17 00:00:00 2001 From: Christophe Dervieux Date: Tue, 21 Oct 2025 20:04:35 +0200 Subject: [PATCH 3/3] Add changelog --- news/changelog-1.9.md | 1 + 1 file changed, 1 insertion(+) diff --git a/news/changelog-1.9.md b/news/changelog-1.9.md index ff2ac63e48..5a16132488 100644 --- a/news/changelog-1.9.md +++ b/news/changelog-1.9.md @@ -30,6 +30,7 @@ All changes included in 1.9: - ([#13452](https://github.com/quarto-dev/quarto-cli/issues/13452)): Wraps subfigure captions generated by `quarto_super()` in `block` function to avoid emitting `par` elements. (author: @christopherkenny) - ([#13474](https://github.com/quarto-dev/quarto-cli/issues/13474)): Heading font for title should default to `mainfont`. - ([#13555](https://github.com/quarto-dev/quarto-cli/issues/13555)): Add support for `icon=false` in callouts when used in `format: typst`. +- ([#13589](https://github.com/quarto-dev/quarto-cli/issues/13589)): Fix callouts with invalid ID prefixes crashing with "attempt to index a nil value". Callouts with unknown reference types now render as non-crossreferenceable callouts with a warning, ignoring the invalid ID. ## Projects