quarto-dev / quarto-dev/quarto-cli

default-image-extension: per-image opt-out and existence-based resolution for extensionless sources

Open
#14,635 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

enhancement
Dominant language
JavaScript
Stars
6k
Forks
458
Avg merge
1d 9h
Merged PRs (30d)
41

Description

Follow-up to #6092. PR #14634 fixes the two provably-spurious cases (shortcode double-extension #14583, and empty-filename URLs like https://example.com/), but the original #6092 report — badge / API URLs such as https://bestpractices.coreinfrastructure.org/projects/1882/badge — is deliberately left untouched.

The reason: Quarto sets default-image-extension as a Pandoc reader option, and Pandoc appends it at parse time to any extensionless source that isn't a data: URI (no URL guard in Pandoc). After parsing, .../badge becomes .../badge.png, which is byte-identical to a user-typed .../badge.png pointing at a real file. There is no way to tell the two apart, and a remote URL cannot be stat-checked offline at render time. So auto-detection is not possible for these.

Two complementary opt-in mechanisms could close the remaining gap:

Remote URLs — explicit per-image opt-out

For remote sources where the user knows there is no extension (badges, image APIs, embeds), an explicit marker lets them assert it:

![OpenSSF](https://bestpractices.coreinfrastructure.org/projects/1882/badge){.no-img-ext}

A Lua filter would strip exactly one appended default-image-extension suffix when the marker is present, then consume the marker so it does not leak into output. This is additive and does not change the default, so it is safe outside a release-cycle boundary. Today the only escape is default-image-extension: "", which is document/project-wide and cannot be scoped to a single image in a doc that also relies on the multi-format behaviour.

Local files — resolve by existence (#6092 "option C")

For local sources, the extension could be resolved against the filesystem instead of appended unconditionally: if path/figure.{default} does not exist but path/figure does, use the extensionless file.

This is the long-term direction discussed in #6092. It needs care:

  • Path resolution must use the correct base (project dir, resource paths) — a false "doesn't exist" would strip a working extension and silently regress documents that render fine today.
  • Multi-format targets generated later in the pipeline will not exist when the filter runs, so the strip condition must be conservative (only when the default-extension target is provably absent and the extensionless file provably present).

Per the discussion in #6092, changing this default-adjacent behaviour should land at the start of a release cycle.

Related: #6092, #14583, #14634.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by tracing where Quarto sets the Pandoc default-image-extension reader option and where its Lua filters process images; review #6092, #14583, and #14634 for constraints. Done means supporting the .no-img-ext remote-image opt-out and conservative existence-based local resolution without changing the existing default behavior.

Written by the indexing model from the issue text.

Assessment

Tech stack
javascript, lua, markdown
Domain
cli, tooling
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.