Skip to content

fix: extend filter path resolution to support at/path filters from extensions #13067

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 8 commits into
base: main
Choose a base branch
from
Open
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.8.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
51 changes: 40 additions & 11 deletions src/command/render/filters.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -873,15 +882,35 @@ 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) {
// 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" as "lua" | "json",
path: extFilter,
at: filter.at
};
} else {
return {
...extFilter,
at: filter.at
};
}
});
} else {
return extensionFilters;
}
} else {
return filter;
}
Expand Down
24 changes: 24 additions & 0 deletions tests/docs/smoke-all/2025/07/13/11750.qmd
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
---
title: "Issue 11750"
format: html
filters:
- path: cite
at: post-quarto
_quarto:
tests:
html:
ensureFileRegexMatches:
-
- '<p><a href="#fig-test" class="quarto-xref">Figure&nbsp;1</a></p>'
- '<p><a href="https://github.com/mcanouil">@mcanouil</a></p>'
---

::: {#fig-test}
Not a figure

But a caption
:::

@fig-test

@mcanouil
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
title: Cite
author: Mickaël Canouil
version: 1.0.0
quarto-required: ">=1.8.0"
contributes:
filters:
- cite.lua
3 changes: 3 additions & 0 deletions tests/docs/smoke-all/2025/07/13/_extensions/cite/cite.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
function Cite(cite)
return pandoc.Link(cite.content, "https://github.com/" .. cite.content[1].text:sub(2))
end
Loading