From 3848b690378a0cd26602c68bab9dca02335f56a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20Canouil?= <8896044+mcanouil@users.noreply.github.com> Date: Sun, 13 Jul 2025 18:15:14 +0200 Subject: [PATCH 1/8] fix: extend resolveFilterExtension() to handle filters with `at: pre-ast` --- src/command/render/filters.ts | 50 +++++++++++++++++++++++++++-------- 1 file changed, 39 insertions(+), 11 deletions(-) diff --git a/src/command/render/filters.ts b/src/command/render/filters.ts index 0c87d1ece77..67870d5f105 100644 --- a/src/command/render/filters.ts +++ b/src/command/render/filters.ts @@ -851,19 +851,28 @@ async function resolveFilterExtension( // Resolve any filters that are provided by an extension const results: (QuartoFilter | QuartoFilter[])[] = []; const getFilter = async (filter: QuartoFilter) => { - // Look for extension names in the filter list and result them + // Look for extension names in the filter list and resolve them // into the filters provided by the extension - if ( - filter !== kQuartoFilterMarker && filter !== kQuartoCiteProcMarker && - typeof filter === "string" - ) { + if (filter === kQuartoFilterMarker || filter === kQuartoCiteProcMarker) { + return filter; + } + + let pathToResolve: string | null = null; + + if (typeof filter === "string") { + pathToResolve = filter; + } else if (typeof filter === "object" && filter.path) { + pathToResolve = filter.path; + } + + if (pathToResolve) { // The filter string points to an executable file which exists - if (existsSync(filter) && !Deno.statSync(filter).isDirectory) { + if (existsSync(pathToResolve) && !Deno.statSync(pathToResolve).isDirectory) { return filter; } const extensions = await options.services.extension?.find( - filter, + pathToResolve, options.source, "filters", options.project?.config, @@ -873,15 +882,34 @@ async function resolveFilterExtension( // Filter this list of extensions const filteredExtensions = filterExtensions( extensions || [], - filter, + pathToResolve, "filter", ); // Return any contributed plugins if (filteredExtensions.length > 0) { // This matches an extension, use the contributed filters - const filters = extensions[0].contributes.filters; - if (filters) { - return filters; + const extensionFilters = extensions[0].contributes.filters; + if (extensionFilters) { + if (typeof filter === "string") { + return extensionFilters; + } else if (isFilterEntryPoint(filter)) { + return extensionFilters.map(extFilter => { + if (typeof extFilter === "string") { + return { + type: extFilter.endsWith(".lua") ? "lua" : "json" as "lua" | "json", + path: extFilter, + at: filter.at + }; + } else { + return { + ...extFilter, + at: filter.at + }; + } + }); + } else { + return extensionFilters; + } } else { return filter; } From 9d6fb7b59a0bf52f0fba79427698a223f9ad90cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20Canouil?= <8896044+mcanouil@users.noreply.github.com> Date: Sun, 13 Jul 2025 18:37:52 +0200 Subject: [PATCH 2/8] test: add tests for filter path resolution from object --- tests/docs/smoke-all/2025/07/13/11750.qmd | 15 +++++++++++++++ .../2025/07/13/_extensions/cite/_extension.yml | 7 +++++++ .../2025/07/13/_extensions/cite/cite.lua | 3 +++ 3 files changed, 25 insertions(+) create mode 100644 tests/docs/smoke-all/2025/07/13/11750.qmd create mode 100644 tests/docs/smoke-all/2025/07/13/_extensions/cite/_extension.yml create mode 100644 tests/docs/smoke-all/2025/07/13/_extensions/cite/cite.lua diff --git a/tests/docs/smoke-all/2025/07/13/11750.qmd b/tests/docs/smoke-all/2025/07/13/11750.qmd new file mode 100644 index 00000000000..696fcdfbf1b --- /dev/null +++ b/tests/docs/smoke-all/2025/07/13/11750.qmd @@ -0,0 +1,15 @@ +--- +title: "Issue 11750" +format: html +filters: + - path: cite + at: post-quarto +_quarto: + tests: + html: + ensureHtmlElements: + - + - '

@mcanouil

' +--- + +@mcanouil diff --git a/tests/docs/smoke-all/2025/07/13/_extensions/cite/_extension.yml b/tests/docs/smoke-all/2025/07/13/_extensions/cite/_extension.yml new file mode 100644 index 00000000000..dced8e560a4 --- /dev/null +++ b/tests/docs/smoke-all/2025/07/13/_extensions/cite/_extension.yml @@ -0,0 +1,7 @@ +title: Cite +author: Mickaƫl Canouil +version: 1.0.0 +quarto-required: ">=1.8.0" +contributes: + filters: + - cite.lua diff --git a/tests/docs/smoke-all/2025/07/13/_extensions/cite/cite.lua b/tests/docs/smoke-all/2025/07/13/_extensions/cite/cite.lua new file mode 100644 index 00000000000..e2c362a123a --- /dev/null +++ b/tests/docs/smoke-all/2025/07/13/_extensions/cite/cite.lua @@ -0,0 +1,3 @@ +function Cite(cite) + return pandoc.Link(cite.content, "https://github.com/" .. cite.content[1].text:sub(2)) +end From 9689c64fe2cf412d17aa76b980b6a5b01ddc7cd5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20Canouil?= <8896044+mcanouil@users.noreply.github.com> Date: Sun, 13 Jul 2025 18:45:55 +0200 Subject: [PATCH 3/8] test: use regexp instead --- tests/docs/smoke-all/2025/07/13/11750.qmd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/docs/smoke-all/2025/07/13/11750.qmd b/tests/docs/smoke-all/2025/07/13/11750.qmd index 696fcdfbf1b..1143e396ffb 100644 --- a/tests/docs/smoke-all/2025/07/13/11750.qmd +++ b/tests/docs/smoke-all/2025/07/13/11750.qmd @@ -7,7 +7,7 @@ filters: _quarto: tests: html: - ensureHtmlElements: + ensureFileRegexMatches: - - '

@mcanouil

' --- From 5bd8ea8c6c659dfadc214f3c78bef582f00beffe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20Canouil?= <8896044+mcanouil@users.noreply.github.com> Date: Sun, 13 Jul 2025 19:13:29 +0200 Subject: [PATCH 4/8] chore: changelog entry --- news/changelog-1.8.md | 1 + 1 file changed, 1 insertion(+) diff --git a/news/changelog-1.8.md b/news/changelog-1.8.md index b292099b967..8915c8f214a 100644 --- a/news/changelog-1.8.md +++ b/news/changelog-1.8.md @@ -72,6 +72,7 @@ All changes included in 1.8: - ([#12727](https://github.com/quarto-dev/quarto-cli/issues/12727)): Do not crash in the presence of malformed tabset contents. - ([#12806](https://github.com/quarto-dev/quarto-cli/pull/12806)): Use pandoc APIs to handle codepage conversion on Windows. - ([#12811](https://github.com/quarto-dev/quarto-cli/pull/12811)): Add support for YouTube Shorts in `video` shortcode. +- ([#11750](https://github.com/quarto-dev/quarto-cli/pull/11750)): Extend filter path resolution to support `at`/`path` filters from extensions. ## Commands From 8cf43498beda38ab0e60b4c011564740a852aa95 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20Canouil?= <8896044+mcanouil@users.noreply.github.com> Date: Tue, 15 Jul 2025 10:45:38 +0200 Subject: [PATCH 5/8] revert: this does not seem to be needed since "path" is given earlier --- src/command/render/filters.ts | 25 +++---------------------- 1 file changed, 3 insertions(+), 22 deletions(-) diff --git a/src/command/render/filters.ts b/src/command/render/filters.ts index 67870d5f105..9eabe60e827 100644 --- a/src/command/render/filters.ts +++ b/src/command/render/filters.ts @@ -888,28 +888,9 @@ async function resolveFilterExtension( // Return any contributed plugins if (filteredExtensions.length > 0) { // This matches an extension, use the contributed filters - const extensionFilters = extensions[0].contributes.filters; - if (extensionFilters) { - if (typeof filter === "string") { - return extensionFilters; - } else if (isFilterEntryPoint(filter)) { - return extensionFilters.map(extFilter => { - if (typeof extFilter === "string") { - return { - type: extFilter.endsWith(".lua") ? "lua" : "json" as "lua" | "json", - path: extFilter, - at: filter.at - }; - } else { - return { - ...extFilter, - at: filter.at - }; - } - }); - } else { - return extensionFilters; - } + const filters = extensions[0].contributes.filters; + if (filters) { + return filters; } else { return filter; } From cb534095b18ca95fb28791108734306b53bb0ec4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20Canouil?= <8896044+mcanouil@users.noreply.github.com> Date: Tue, 15 Jul 2025 11:31:06 +0200 Subject: [PATCH 6/8] test: improve test to also check for "at" --- tests/docs/smoke-all/2025/07/13/11750.qmd | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tests/docs/smoke-all/2025/07/13/11750.qmd b/tests/docs/smoke-all/2025/07/13/11750.qmd index 1143e396ffb..743c01d0c49 100644 --- a/tests/docs/smoke-all/2025/07/13/11750.qmd +++ b/tests/docs/smoke-all/2025/07/13/11750.qmd @@ -9,7 +9,16 @@ _quarto: html: ensureFileRegexMatches: - + - '

Figure 1

' - '

@mcanouil

' --- +::: {#fig-test} +Not a figure + +But a caption +::: + +@fig-test + @mcanouil From 47b4bf017bac5e33e93fd7ef8e7d13e017e0ba58 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20Canouil?= <8896044+mcanouil@users.noreply.github.com> Date: Tue, 15 Jul 2025 11:38:45 +0200 Subject: [PATCH 7/8] fix: preserve "at" after path resolution The "at" resolution actually happens after path resolution. Apply same as in resolveFilters() entryPoints definition --- src/command/render/filters.ts | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/src/command/render/filters.ts b/src/command/render/filters.ts index 9eabe60e827..2a7c5cce26f 100644 --- a/src/command/render/filters.ts +++ b/src/command/render/filters.ts @@ -888,9 +888,29 @@ async function resolveFilterExtension( // Return any contributed plugins if (filteredExtensions.length > 0) { // This matches an extension, use the contributed filters - const filters = extensions[0].contributes.filters; - if (filters) { - return filters; + const extensionFilters = extensions[0].contributes.filters; + if (extensionFilters) { + // After "path" resolution, "at" needs to be preserved + if (typeof filter === "string") { + return extensionFilters; + } else if (isFilterEntryPoint(filter)) { + return extensionFilters.map(extFilter => { + if (typeof extFilter === "string") { + return { + type: extFilter.endsWith(".lua") ? "lua" : "json", + path: extFilter, + at: filter.at + }; + } else { + return { + ...extFilter, + at: filter.at + }; + } + }); + } else { + return extensionFilters; + } } else { return filter; } From b8f2a49429d378a3819c72ea336e9a8392a8cf85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20Canouil?= <8896044+mcanouil@users.noreply.github.com> Date: Tue, 15 Jul 2025 11:44:15 +0200 Subject: [PATCH 8/8] fix: type assertion for "type" of filters --- src/command/render/filters.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/command/render/filters.ts b/src/command/render/filters.ts index 2a7c5cce26f..fdb4281d4f2 100644 --- a/src/command/render/filters.ts +++ b/src/command/render/filters.ts @@ -897,7 +897,7 @@ async function resolveFilterExtension( return extensionFilters.map(extFilter => { if (typeof extFilter === "string") { return { - type: extFilter.endsWith(".lua") ? "lua" : "json", + type: extFilter.endsWith(".lua") ? "lua" : "json" as "lua" | "json", path: extFilter, at: filter.at };