Skip to content

Accept (and ignore) static engine declaration keys in the external-engine schema - #14936

Open
gordonwoodhull wants to merge 2 commits into
quarto-dev:mainfrom
gordonwoodhull:external-engine-static-declarations
Open

gordonwoodhull wants to merge 2 commits into
quarto-dev:mainfrom
gordonwoodhull:external-engine-static-declarations

Conversation

@gordonwoodhull

@gordonwoodhull gordonwoodhull commented Sep 23, 2026

Copy link
Copy Markdown
Member

Summary

Loosens the external-engine schema (contributes: engines entries in extension manifests), which was closed around a single required path key, to accept four new optional keys:

  • name: engine name (e.g. julia)
  • claims: languages the engine claims — either an array of language names (shorthand for a primary claim on each) or a map from language name to a claim spec (boolean | number | primary | interop | fallback | { kind, priority, whenClass }, with a special fallback key for otherwise-unclaimed languages)
  • file-extensions: file extensions the engine can handle (e.g. .jl)
  • claims-files: files the engine claims, by extension — each entry may also name a processor (a bare name like spin, or { name, language?, comment? } like { name: percent, language: julia }), the content processor that sniffs and converts matching files

Quarto 1 accepts and ignores these keys. This is pure forward-compatibility: they are reserved for Quarto 2, which resolves engines statically from these declarations without loading the engine module — including claiming files by content (percent/spin/ipynb scripts) via the processor declarations, which Quarto 2 runs natively. There is intentionally no Quarto 1 behavior change — engine loading and execution still key off path alone.

Why accept-and-ignore rather than honoring claims: in Quarto 1?

Quarto 1 already has engine claiming, and its semantics are deliberately conservative: the jupyter engine claims julia so that the old default of preferring jupyter over the julia engine is preserved (src/execute/jupyter/jupyter.ts:113-117):

claimsLanguage: (language: string) => {
  // jupyter has to claim julia so that julia may also claim it without changing the old behavior
  // of preferring jupyter over julia engine by default
  return language.toLowerCase() === "julia";
},

If Quarto 1 started honoring extension-declared claims:, a document with {julia} cells would flip from jupyter to an installed external julia engine — exactly the behavior change that comment guards against. So these keys are validated (malformed values are still rejected) but inert in Quarto 1.

Similarly, file-extensions: here is a per-engine declaration for Quarto 2's resolution; it deliberately does not interact with Quarto 1's global jupyter.notebookExtensions gate.

There is no problem with continuing to check the values at runtime in Quarto 1, because Quarto 1 is already running TS. It's only a concern for Quarto 2 so that it doesn't have to start up Deno in order to process Pass-1.

Consumer

PumasAI/quarto-julia-engine#15 — the Julia engine extension declares name, claims, and file-extensions in its _extension.yml so Quarto 2 can route {julia} cells and .jl files to it. Without this change, Quarto 1 rejects that manifest at validation time, so the extension cannot ship the declarations unconditionally. The processor key on claims-files entries anticipates the next declaration the same engine (and built-ins) will need: content-based claiming and conversion of percent/spin/ipynb scripts.

Empirical before/after

Rendering a document with engine: julia using that manifest:

Before (current schema):

ERROR: YAML Validation Failed
(line 14) property name name is invalid
(line 15) property name claims is invalid
(line 19) property name file-extensions is invalid

After: render succeeds; the Julia engine executes the cell (1 + 1<pre><code>2</code></pre> in the output HTML). The declarations pass through into project metadata but are otherwise ignored.

Changes

  • src/resources/schema/definitions.yml: type the four new keys; new external-engine-language-claim definition for claim specs. Every key's description states that Quarto 1 accepts and ignores it.
  • Regenerated artifacts via dev-call build-artifacts (json-schemas.json, schema-types.ts, zod types, yaml-intelligence resources, vs-code.mjs).
  • Two self-validating schema fixtures exercising all claim value forms, the array-of-strings shorthand, and all processor forms (bare name, map, map with comment).

Tests: unit/schema-validation/schema-files.test.ts and schema-schema.test.ts pass (8 passed, 0 failed), including the new fixtures; empirical render as above.

Known generator limitation (left as-is): the JSON-schema output for claims' object form drops additionalProperties (emits an untyped object); the validator, TS types, and zod types all handle it correctly. It's a generated IDE artifact — the validator is what enforces.

@posit-snyk-bot

posit-snyk-bot commented Sep 23, 2026

Copy link
Copy Markdown
Collaborator

Snyk checks have passed. No issues have been found so far.

Status Scan Engine Critical High Medium Low Total (0)
Open Source Security 0 0 0 0 0 issues
Licenses 0 0 0 0 0 issues

💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse.

The external-engine schema (contributes: engines entries in extension
manifests) was closed around a single required path key. Add four
optional keys -- name, claims, file-extensions, claims-files (with an
optional processor on claims-files entries) -- that Quarto 1 accepts
and ignores, so extensions can declare them for Quarto 2's static
engine resolution without breaking Quarto 1 validation. No Quarto 1
behavior change: engine loading and execution still key off path alone.
@gordonwoodhull
gordonwoodhull force-pushed the external-engine-static-declarations branch from e528b49 to c57d2a4 Compare September 23, 2026 13:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants