Skip to content
Merged
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
70 changes: 70 additions & 0 deletions .claude/rules/filters/cross-project-consumers.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
---
paths:
- "src/resources/filters/**"
- "package/src/common/prepare-dist.ts"
- "package/src/common/package-filters.ts"
---

# Filters Consumed by Other Projects (do not delete without checking)

Some Lua filters in `src/resources/filters/` are invoked **standalone** (as bare
`pandoc --lua-filter` / `--defaults` passes, outside Quarto's `render` pipeline)
by **other repositories** that ship or embed Quarto. "Nothing in quarto-cli
references this file" is therefore **not** sufficient proof that a filter is dead
code. Always run the checklist below before removing or renaming anything under
`src/resources/filters/`.

## Cross-project consumers

Both consumers build the crossref/xref index used for visual-editor autocomplete
by calling `pandoc` directly against Quarto's installed share tree
(`QUARTO_SHARE_PATH`), loading these filters:

- `filters/quarto-init/quarto-init.lua`
- `filters/crossref/crossref.lua`
- `filters/qmd-reader.lua` (used as the `--from` reader when present)

with `QUARTO_FILTER_PARAMS` set to `{ "crossref-index-file": ..., "crossref-input-type": "qmd" }`.

| Consumer | File | What it does |
|----------|------|--------------|
| Visual editor (`quarto-dev/quarto`) | `packages/editor-server/src/core/xref.ts` (`indexSourceFile`) | Writes a `defaults.yml` listing `quarto-init.lua` + `crossref.lua`, runs pandoc to emit `index.json`. |
| RStudio (`rstudio/rstudio`) | `src/cpp/session/modules/quarto/SessionQuartoXRefs.cpp` | Same defaults + filters, from the C++ side. |

The visual editor also bundles its **own** unrelated filters
(`parser.lua`, `sourcepos.lua`, `heading-ids.lua` in `editor-server`) — those are
not ours and are not relevant here.

## Why "no in-repo reference" is not enough

The installer does **not** ship `src/resources/filters/` verbatim. In
`package/src/common/prepare-dist.ts`:

1. The copied `share/filters` source tree is **deleted** (`pathsToClean`).
2. `inlineFilters()` rebuilds `share/filters` from a **fixed list**
(`filtersToInline`: `main, pagebreak, quarto-init, crossref, customwriter,
qmd-reader, llms, leveloneanalysis`) plus the `modules/` directory.
`buildFilter` (`package-filters.ts`) inlines every `-- [import]` into one
self-contained file.

So the shipped `crossref/crossref.lua` is already a **standalone, fully-inlined**
bundle — the build auto-generates the standalone crossref filter from
`crossref.lua`. A hand-maintained "standalone" duplicate is redundant. Anything
**not** in the inline list (and not under `modules/`) is never shipped and cannot
be a cross-project dependency via the share path.

## Removal checklist

Before deleting/renaming a filter under `src/resources/filters/`:

1. Is it in the `filtersToInline` list (or reachable via `modules/`) in
`prepare-dist.ts`? If **not**, it was never shipped — confirm it is also unused
at render time before removing.
2. Is it (or its basename) referenced by `quarto-dev/quarto` or
`rstudio/rstudio`? Grep both for the basename and for `filters/<dir>/<name>`.
See `dev-docs/cross-project-dependencies.md`.
3. A GitHub-wide code search for the basename catches extension-ecosystem usage.

Precedent: `crossref-standalone.lua` and `quarto-pre/quarto-pre.lua` were removed
after confirming (a) neither was in the inline list, so neither was ever shipped,
and (b) both consumers use `crossref.lua`/`quarto-init.lua`, not the removed files.
74 changes: 74 additions & 0 deletions dev-docs/cross-project-dependencies.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
# Cross-Project Dependencies

Other Posit repositories embed or ship Quarto and reach directly into
quarto-cli's installed resources and commands. These couplings are **not**
visible from within quarto-cli — nothing here references the consumer — so a
change that looks internal can break the visual editor or RStudio. This file
records the known touch-points so they can be checked before changing the
surfaces involved.

The two consumers are:

- **`quarto-dev/quarto`** — the visual editor / VS Code + Positron tooling
monorepo (`packages/editor-server`, `packages/quarto-core`, `apps/lsp`, ...).
- **`rstudio/rstudio`** — the RStudio IDE (visual editor backend in
`src/cpp/session/modules/`).

> When you change one of the surfaces below, grep the consumer repo(s) for the
> path/basename and coordinate a companion change if needed.

## 1. Standalone crossref/xref filter invocation

To power visual-editor cross-reference autocomplete, both consumers run `pandoc`
directly against Quarto's installed share tree (`QUARTO_SHARE_PATH`) with a
`--defaults` file that loads these filters standalone (outside `quarto render`):

- `filters/quarto-init/quarto-init.lua`
- `filters/crossref/crossref.lua`
- `filters/qmd-reader.lua` (used as `--from` when present)

Environment: `QUARTO_FILTER_PARAMS` = `{ "crossref-index-file": "index.json",
"crossref-input-type": "qmd" }`, `QUARTO_SHARE_PATH` = the resource path.

| Consumer | File |
|----------|------|
| `quarto-dev/quarto` | `packages/editor-server/src/core/xref.ts` (`indexSourceFile`) |
| `rstudio/rstudio` | `src/cpp/session/modules/quarto/SessionQuartoXRefs.cpp` |

**Contract:** the names/relative paths of these filters, their filter-params
protocol, and the `index.json` output shape are a de-facto public API. Renaming,
removing, or moving any of them, or dropping them from the packaging inline list
(see below), breaks both consumers. See
`.claude/rules/filters/cross-project-consumers.md`.

## 2. What actually ships in `share/filters`

`src/resources/filters/` is **not** shipped verbatim. `package/src/common/prepare-dist.ts`
deletes the copied `share/filters` and rebuilds it via `inlineFilters()` from a
fixed list (`filtersToInline`) plus the `modules/` directory; `buildFilter`
(`package-filters.ts`) inlines each `-- [import]` into one self-contained file.
A filter that is **not** in the inline list and **not** under `modules/` is never
installed, so it cannot be a cross-project dependency via the share path — but it
also means "grep finds no reference" does not prove a *shipped* filter is unused.

## 3. Editor support commands

`quarto-core` / the editor tooling also shell out to `quarto` subcommands
(e.g. `quarto editor-support crossref`, implemented in
`src/command/editor-support/crossref.ts`). Changing the CLI surface or output
format of editor-support commands is a cross-project change.

## Checklist when touching a shared surface

1. Identify which consumer(s) use it (tables above).
2. Grep the consumer repo for the path/basename and the CLI/protocol shape.
3. For filters: confirm inline-list membership in `prepare-dist.ts`.
4. Coordinate a companion PR in the consumer if the contract changes.

## History

- Removing `crossref-standalone.lua` and `quarto-pre/quarto-pre.lua`: verified
safe because neither was in the packaging inline list (never shipped) and both
consumers load `crossref.lua`/`quarto-init.lua`, not the removed files. This
doc and the scoped rule were written as part of that investigation so the check
does not have to be re-derived.
65 changes: 0 additions & 65 deletions src/resources/filters/crossref/crossref-standalone.lua

This file was deleted.

155 changes: 0 additions & 155 deletions src/resources/filters/quarto-pre/quarto-pre.lua

This file was deleted.

Loading