Repository navigation
Copy local files that Markdown links point at into the output (bd-twfep08m) - #967
Merged
Merged
Conversation
…ep08m)
A link such as [Data](data.csv) or [Dashboard](dashboard.json){download=…}
rendered its href unchanged but never copied the file, so websites ported
from Quarto 1 silently lost their downloads. Quarto 1 finds these with an
HTML postprocessor; q2 now finds them on the AST.
LinkResourceDiscoveryTransform (Finalization, just before link-rewrite)
walks Link targets, keeps existing in-project files that are not .qmd,
project inputs, hidden/_freeze paths, files under the output dir, or a
likely render output of a project document (report.pdf beside
report.qmd), and appends them to meta.resources. ResourceReportStage
publishes the survivors of the post filters as the new
ResourceOrigin::AutoDiscovery { via: link }, so a post filter can prune
discovered entries (author-declared ones stay defended, as before).
Images stay on ResourceCollectorTransform.
`resource-discovery: false` (ordinary merged metadata: front matter,
_metadata.yml, _quarto.yml, format blocks, -M, or a pre filter) turns it
off. Any non-boolean value is the new Q-5-52 error and fails the
document, so a typo cannot publish files the author meant to keep out.
AstTransformsStage now passes a transform's QuartoError::Parse through
as PipelineError::Structured so that span resolves into config files.
Plan: claude-notes/plans/2026-10-29-linked-resource-discovery.md
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Contributor
✅ Snyk checks have passed. No issues have been found so far.
💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
A Markdown link to a local file that isn't a document, such as
[Data](data.csv)or[Dashboard](dashboard.json){download="my-dashboard.json"}, rendered with itshrefunchanged, but q2 never copied the file into the output directory. The link was broken on the published site and the render printed nothing. Quarto 1 copies these files, so sites ported from it (for example the Posit Connect docs) silently lost their downloads.What changed
Discovery. A new
LinkResourceDiscoveryTransformruns in the Finalization phase, immediately beforelink-rewrite, so it sees links produced by shortcodes and pre filters while targets are still source-relative. For eachLinktarget it drops any?query/#fragment, percent-decodes the path, and resolves it against the document's directory (a leading/resolves against the project root). It keeps the target if it is an existing file inside the project that is none of the following:.qmdfile or any other project input;_freeze/;report.pdfnext toreport.qmd, which would otherwise overwrite the fresh output with a stale in-place copy.Each kept file is appended to
meta.resources.Attribution and Lua control.
ResourceReportStagepublishes the discovered entries that are still inmeta.resourcesafter the post filters, under a new origin,ResourceOrigin::AutoDiscovery { via: link }. That origin is what appears in.quarto/render-manifest.json. A post filter can therefore remove discovered entries. Entries the author declared in YAML still can't be removed, as before.Opt-out.
resource-discovery: falseis ordinary merged metadata. It works in front matter,_metadata.yml,_quarto.yml, aformat:block,-M, or from a pre filter.New error
Q-5-52. Any value other than a boolean is an error that fails the document, so a typo likeflasecan't publish files the author meant to keep out. To make the error point at the right place,AstTransformsStagenow passes a transform'sQuartoError::Parsethrough asPipelineError::Structured. The span then resolves into_quarto.ymland_metadata.ymlas well as front matter. No transform returned that variant before, so nothing else changes.Images still go through
ResourceCollectorTransform, which Typst needs: images have to be in the output directory beforetypst compileruns.Docs.
paths.qmd: a new section, "Linked files are copied".lua-filters.qmd: a new section onmeta.resources, covering pruning from a post filter and the pre-filter alternative.Q-5-52error page.Plan, with the measured before/after repros and the design decisions:
claude-notes/plans/2026-10-29-linked-resource-discovery.md. Braid:bd-twfep08m.Things worth a look in review
ResourceReportStage, so editingmeta.resourcesthere can't remove anything. The Lua docs tell those users to useresource-discovery: falseinstead.BUCKETS(a shared post-core service) and runs for every format, because the resources channel itself is format-agnostic. It is also registered in the q2-preview profile, likeresource-collector. In preview's VFS-root mode it does nothing.html htm pdf docx pptx odt epub typ texand its path without the extension matches a project input.href:values pointing at files are still not copied (Quarto 1 copies them);bd-mejgdrlh: a body link that climbs above the project root is silently retargeted inside the site.Testing
crates/quarto-core/tests/integration/linked_resources.rshas 17 tests. They cover:%20targets;_metadata.yml, project level, format level), including a document overriding the project;Q-5-52, post-filter pruning combined with the defense of author entries, the pre-filter opt-out, and the manifest origin;output-dir.meta.resources, and the report stage's classification.Q-5-52output for a typo in front matter, in_quarto.ymland via-M(correct spans, exit code 1). I also checked that-M resource-discovery:falsedisables discovery.cargo xtask verifypasses, including the hub-client build and tests.quarto-corecan't be type-checked for Windows from macOS, because the C build scripts of wasmtime and tree-sitter fail. The change adds no platform-specific APIs. Paths go throughPath::join,pathdiffandto_forward_slashes.hub-client/changelog.md, covers hub-client changes, and discovery does nothing in hub-client.🤖 Generated with Claude Code