From 5c14167b26682171efa062010c4657506b7d7e18 Mon Sep 17 00:00:00 2001 From: Christophe Dervieux Date: Thu, 15 Oct 2026 13:25:34 +0200 Subject: [PATCH 1/5] Add llm-doc for the OJS architecture OJS had no architecture doc, so agents had to rediscover the compile path, the inline-vs-linked runtime injection, and which files under src/resources/formats/html/ojs are generated. Now that the runtime sources live in packages/ojs, the rebuild rule (change the source, rebuild both bundles, commit them together) is also something an agent needs up front. The doc records the invariant that the bundle must not contain a closing script tag, since self-contained renders inline it unescaped, and notes that only the unminified bundle is referenced by quarto-cli. --- llm-docs/ojs-architecture.md | 142 +++++++++++++++++++++++++++++++++++ 1 file changed, 142 insertions(+) create mode 100644 llm-docs/ojs-architecture.md diff --git a/llm-docs/ojs-architecture.md b/llm-docs/ojs-architecture.md new file mode 100644 index 0000000000..fb9c9a341f --- /dev/null +++ b/llm-docs/ojs-architecture.md @@ -0,0 +1,142 @@ +--- +main_commit: fa5267fa0 +analyzed_date: 2026-10-15 +key_files: + - src/execute/ojs/compile.ts + - src/execute/ojs/extract-resources.ts + - src/command/render/render-files.ts + - src/command/render/pandoc.ts + - src/command/render/resources.ts + - src/resources/filters/quarto-post/ojs.lua + - src/core/jupyter/jupyter.ts + - src/resources/rmd/ojs.R + - src/resources/jupyter/lang/python/setup.py + - packages/ojs/package.json + - packages/ojs/quarto-ojs-runtime/rollup.config.js + - packages/ojs/quarto-ojs-runtime/src/quarto-ojs.js + - package/src/common/prepare-dist.ts + - .github/workflows/test-ojs-runtime.yml +--- + +# OJS Architecture + +How `{ojs}` cells become Observable JavaScript in an HTML page: the render-time compile step in TypeScript, the Lua filter for inline `${...}` expressions, and the browser runtime built from `packages/ojs`. + +## Entry Points + +- `src/command/render/render-files.ts` calls `ojsExecuteResult()` after the engine has executed the document's other cells. +- `ojsExecuteResult()` (`src/execute/ojs/compile.ts`) wraps `ojsCompile()` and merges its markdown, includes, and filters into the execute result. +- `ojsCompile()` (same file) does the work: it rewrites `{ojs}` cells into placeholder divs and builds the scripts that hand the cell sources to the runtime. +- `src/command/render/resources.ts` calls `extractResolvedResourceFilenamesFromQmd()` (`src/execute/ojs/extract-resources.ts`) so files referenced by OJS code are copied as render resources. + +## When OJS Runs + +`ojsCompile()` returns the markdown untouched unless all of these hold: + +1. `isJavascriptCompatible(format)` (`src/config/format.ts`) is true: HTML-compatible output (`isHtmlCompatible`) except EPUB. +2. `ojs-engine` metadata is not `false`. +3. The document has an `ojs` cell, contains the text `ojs_define`, or sets `ojs-engine: true`. + +The `ojs_define` check is a plain substring search over the markdown, because the R/Python/Julia cells have already executed by this point and their outputs are no longer cells. + +## Compile Output + +For each `{ojs}` cell, `ojsCompile()` emits a div with an `ojs-cell-` id and collects the cell source. It then writes an include-after-body file containing: + +- `` inside an include-in-header file. The code carries an open `FIXME` asking whether `sharePath()` is the right way to locate the resource. + +Invariant: the inlined bundle is not escaped, so `quarto-ojs-runtime.js` must never contain the text ``) and appends a hidden `ojs-auto-generated` div holding its own base64 `ojs-module-contents` script, which `interpretFromScriptTags()` picks up alongside the compile output. + +Other Lua touch points: + +- `quarto-pre/outputs.lua` and `layout/hugo.lua` recognise `ojs-cell-` ids so Hugo output keeps OJS cell divs. +- `modules/constants.lua` lists `//` as the `ojs` comment syntax. + +## `ojs_define` (engine side) + +`ojs_define()` passes data from R, Python, or Julia to OJS by emitting `