You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
docs(hub-client): consolidate q2-preview branch changelog to user-facing entries
The branch shipped 15+ phase-level entries describing internal
architecture (Plan 2pre / 2A / 2B / 2C / 2D sub-phases, the bd-3gtn
artifact-flush fix, theme-CSS path corrections) that hub-client users
don't see. Replace with two user-facing entries: the new `format:
q2-preview` and the render-components mid-type crash fix. Side effect:
clears the Q-2-7 parse error in the prior 2026-05-10 entry (bd-1qk5)
since the offending text is removed entirely.
Copy file name to clipboardExpand all lines: hub-client/changelog.md
+3-26Lines changed: 3 additions & 26 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -15,32 +15,9 @@ be in reverse chronological order (latest first).
15
15
16
16
### 2026-05-10
17
17
18
-
-[`979982bd`](https://github.com/quarto-dev/q2/commits/979982bd): Custom syntax highlighting now works in Quarto Hub projects (bd-izfv) — user-supplied tree-sitter grammars under `_quarto/grammars/<lang>/` now apply to code blocks even when the qmd file lives under a `_quarto.yml` ancestor, matching the single-file render path.
19
-
-[`c8a684bd`](https://github.com/quarto-dev/q2/commits/c8a684bd): Fix bd-3gtn: WASM artifact-flush loop in `wasm-quarto-hub-client/src/lib.rs` was overwriting user-uploaded image bytes with empty content on every render. `ResourceCollectorTransform` produces manifest-only entries via `Artifact::from_path` whose absolute path collapsed via `Path::join`'s absolute-replace rule onto the user's VFS upload location. Both flush loops now skip empty-content artifacts, preserving manifest semantics for downstream consumers while keeping produced bytes (theme CSS, fonts, future engine-generated images) flowing. Discovered during Plan 2A review (2026-05-07) and routed-around by Plan 2B until now; the test in `assetManifestProject.wasm.test.ts` was reverted to its natural lifecycle (binary upload BEFORE render) for a bug-then-fix walk-through.
20
-
-[`02da39a5`](https://github.com/quarto-dev/q2/commits/02da39a5): Fix iframe-host crash when typing `render-components:\n -` (empty list bullet) into a document's YAML frontmatter. The path-extraction in `ReactRenderer.tsx`'s `componentPathsKey` useMemo yielded `undefined` for the null entry, which then crashed `resolveComponentPath(undefined, …)` with `Cannot read properties of undefined (reading 'startsWith')` — past the local ErrorBoundary (a descendant, not an ancestor of `ReactRenderer`), so the page went blank and the user couldn't finish typing. Now filters extracted paths to keep only non-empty strings; empty entries are skipped silently. Two regression tests cover the `MetaList c: [null]` and `MetaList c: [{t: 'MetaInlines', c: []}]` mid-type shapes.
21
-
- [`3b064478`](https://github.com/quarto-dev/q2/commits/3b064478): Plan 2D q2-preview body container + title block. `PreviewDocument.tsx` now emits the `<div id="quarto-content"><main class="content">` wrapper mirroring `template.rs:185-247`, applies `body-classes` imperatively to `document.body`, and re-implements the Rust `title-block` transform's minimal-mode `<h1>` synthesis React-side (the transform itself stays in `Q2_PREVIEW_TRANSFORM_EXCLUDED`). Iframe `document.title` now tracks `meta.pagetitle ?? meta.title`. New `q2-preview/custom/PreviewTitleBlock.tsx` mirrors `template.rs:211-240` byte-for-byte and is registered under the synthetic `__title_block__` registry key; user TSX overrides can full-replace or compose via the `__Q2_PREVIEW_RENDERER__.PreviewTitleBlock` exposure. Phase 6.0 framework extraction lifts `inlinesToPlainText` / `blocksToPlainText` to `framework/plainText.ts` and adds `framework/meta.ts` (`extractMetaString` / `extractMetaBool` / `extractMetaStringList`); `FormatRegistry` gains typed optional entries for both synthetic keys. The slide renderer's private `extractMetaString` is replaced by the framework helper (deliberate behavior change for inline-markup in slide titles, locked by a regression test); `meta.format` extraction in `ReactRenderer.tsx` and `getQ2Format.ts` consolidates onto the same helper. Tests: 27 framework unit, 18 PreviewDocument integration, 17 PreviewTitleBlock integration (incl. composition idiom), explicit synthetic-key assertion closing a pre-existing `__fallback__` gap; 11 smoke-all q2-preview fixtures (body-container + body-classes + title-block).
22
-
-[`c8a684bd`](https://github.com/quarto-dev/q2/commits/c8a684bd): Fix bd-3gtn: WASM artifact-flush loop in `wasm-quarto-hub-client/src/lib.rs` was overwriting user-uploaded image bytes with empty content on every render. `ResourceCollectorTransform` produces manifest-only entries via `Artifact::from_path` whose absolute path collapsed via the absolute-replace rule of `Path::join` onto the user's VFS upload location. Both flush loops now skip empty-content artifacts, preserving manifest semantics for downstream consumers while keeping produced bytes (theme CSS, fonts, future engine-generated images) flowing. Discovered during Plan 2A review (2026-05-07) and routed-around by Plan 2B until now; the test in `assetManifestProject.wasm.test.ts` was reverted to its natural lifecycle (binary upload BEFORE render) for a bug-then-fix walk-through.
23
-
-[`d91150c4`](https://github.com/quarto-dev/q2/commits/d91150c4): Plan 2B Phase 5.2 and 5.3: smoke-all `q2-preview/image-with-attrs.qmd` fixture (with a 1x1 PNG sibling) and the `assetManifestProject.wasm.test.ts` WASM-bridge safety net. The smoke fixture asserts the parent-side asset walker mints a blob URL, propagates the width attribute, and round-trips alt text. The WASM test mirrors `themeFingerprint.wasm.test.ts` and renders a `_quarto.yml`-rooted project doc with a project-relative Image, then exercises the walker against the parsed AST and project-relative `currentFilePath`. Catches default-project resolution bugs analogous to the Plan 2A theme path mismatch (commit e6381abd). 82/82 WASM tests pass.
24
-
- [`25d98df5`](https://github.com/quarto-dev/q2/commits/25d98df5): Plan 2B Phase 3 and 5.1: built-in registry of Pandoc-base leaves. q2-preview ships 14 Block components and 20 Inline components, replacing the empty Plan 2A registry. Image is a pure AssetManifestContext consumer (no VFS access in the iframe). Math is a near-verbatim port of Elliot Math leaf with two divergences: direct ESM `import katex` (window.katex is only set after LOAD_CUSTOM_COMPONENTS) and an explicit raw-LaTeX fallback on KaTeX error. Note is the JS-side number-with-tooltip-body fallback for `reference-location: block` and `section` (the default `document` configuration runs through FootnotesTransform upstream). New `q2-preview/utils.ts` ships `lookupAssetUrl`, `inlinesToPlainText`, `blocksToPlainText`. New stub `q2-preview/quartoClasses.ts` covers section, footnotes, and appendix constants. The framework dispatch table gains 5 new renderChildrenRegistry entries for Underline, Strikeout, Superscript, Subscript, SmallCaps. Plan 2A empty-registry tests are replaced by 21 new q2-preview integration tests (Pandoc base rendering, gap-fill components, Image edge cases, atomic CustomNode read-only, recursion-contract bypass, class-compatibility); q2-debug gains a parity test for the atomic gate. 688 unit + 112 integration tests pass.
25
-
-[`c002ef7d`](https://github.com/quarto-dev/q2/commits/c002ef7d): Plan 2B pipeline change: include FootnotesTransform and AppendixStructureTransform in q2-preview. Removes "footnotes" and "appendix-structure" from `Q2_PREVIEW_TRANSFORM_EXCLUDED`. Both produce pure Pandoc primitives that q2-preview leaves render natively; the original synthesize-with-no-preimage exclusion rationale does not bite for v1 structural rendering. Effects: footnote numbering is automatic, the footnotes section nests inside the appendix container, and license / copyright / citation YAML metadata renders as small section blocks under the appendix container. `TitleBlockTransform` stays excluded (its is_html() gate makes it a no-op for q2-preview today, and making it useful requires a Rust change beyond Plan 2B). bd-1kly tracks the upstream gap for `reference-location: block` and `section`; until that lands, the q2-preview Note tooltip-body fallback handles those configs.
26
-
- [`d2a6ca77`](https://github.com/quarto-dev/q2/commits/d2a6ca77): Plan 2B Phase 2: asset manifest plumbing for q2-preview. A new parent-side walker (in `q2-preview/assetWalker.ts`) scans the AST for Image nodes, resolves their paths via the now-shared `vfsPaths.ts`, reads VFS bytes, and mints (or reuses cached) blob URLs. Cache identity is the base64 content string itself: synchronous, deterministic, no hash. External URLs (http, https, data, protocol-relative) are filtered out at walk time. A new `q2-preview/AssetManifestContext.tsx` distributes the manifest to iframe consumers. `Q2PreviewIframe.tsx` owns the cache (drained on unmount) and extends the UPDATE_AST payload to include the manifest alongside the AST. The iframe entry forwards the manifest into a context provider alongside PreviewContext, and the SET_AST callback now rewraps JS-native CustomNodes back to wire format before posting. Walker test suite covers cache hit, content-change eviction, image removal, external skipping, VFS failure, N=100 stress, malformed JSON, and nested-container traversal. Q2PreviewIframe integration test grows a third case for the manifest payload and unmount revocation.
27
-
-[`f3c32926`](https://github.com/quarto-dev/q2/commits/f3c32926): Plan 2B Phase 2.1a: extract a shared `utils/vfsPaths.ts`. The helpers `resolveRelativePath`, `normalizePath`, and `guessMimeType` previously had three private copies (in iframePostProcessor, iframeLinkHandlers, and ReactAstSlideRenderer); consolidating to a shared module avoids fanning the duplication out further when the Plan 2B asset walker becomes the fourth consumer. Pure refactor; no behavior change. The new module includes 13 unit tests covering absolute-path passthrough, double-dot traversal, empty segments, the single-leading-slash invariant, past-root traversal swallowing, image and text MIME types, and the octet-stream fallback.
28
-
- [`fc784bb2`](https://github.com/quarto-dev/q2/commits/fc784bb2): Plan 2B Phase 1: framework foundation for the q2-preview built-in components. A new `framework/customNode.ts` ships unwrap and rewrap walks that convert between the wire-format `__quarto_custom_node` Div/Span wrappers and JS-native CustomBlockNode and CustomInlineNode shapes. The walks mirror the Rust JSON writer and reader, and are structural-sharing pure so subtree identity is preserved for the future Note-numbering WeakMap. An atomic-aware gate inside `framework/dispatch.tsx` no-ops setLocalAst for Derived, atomic Synthetic, and atomic CustomNode subtrees: both q2-debug and q2-preview pick it up automatically. `framework/Ast.tsx` accepts a discriminated input (string or pre-parsed AST), unconditionally unwraps custom-node wrappers, and fills the RegistryContext sourceInfoPool value (Plan 2A typed the field but did not fill it). New types: Slot, CustomBlockNode, CustomInlineNode, CiteInline, plus block-level gap-fill types. The framework blockTypes array extends from 11 to 19 entries (LineBlock, DefinitionList, Table for the new leaves; CustomBlock as the post-unwrap discriminator; BlockMetadata, NoteDefinitionPara, NoteDefinitionFencedBlock, CaptionBlock defensively routed as blocks). The renderChildrenRegistry gains CustomBlock and CustomInline entries for the generic slot walk consumed by Plan 2C Fallback. Round-trip property tests cover the six in-tree CustomNode type_name strings plus an IncludeExpansion placeholder, in both directions, with explicit cases for the inline-side no-Plain asymmetry and the walker-purity reference-preservation contract.
29
-
30
-
### 2026-05-09
31
-
32
-
-[`e6381abd`](https://github.com/quarto-dev/q2/commits/e6381abd): Fix q2-preview theme CSS path mismatch in project mode. The pass-2 renderer now writes a copy of the compiled theme CSS at the stable iframe-readable location `/.quarto/project-artifacts/styles.css` regardless of single-doc vs project layout, honoring Plan 1's contract.
33
-
-[`81e48f10`](https://github.com/quarto-dev/q2/commits/81e48f10): Fix `theme_fingerprint` missing on q2-preview renders inside non-website projects. The fingerprint is now captured at the pass-2 renderer level (before `drain_project_scoped`) and stashed on `WasmPassTwoOutput`, so it survives both the default-project flush path and the website-merge path.
34
-
- [`fe40973b`](https://github.com/quarto-dev/q2/commits/fe40973b): Plan 2A — q2-preview iframe foundation. New `q2-preview/` directory ships parallel to `q2-debug/` with `Q2PreviewIframe`, registry skeleton (Block/Inline placeholder dispatchers + `PreviewDocument`), `entry.tsx` with module-top message listener and `__Q2_PREVIEW_RENDERER__` global, and `PreviewContext` for `currentFilePath`. Theme CSS flows as blob URLs (parent reads VFS, mints `URL.createObjectURL`, posts URL string via `UPDATE_THEME`; iframe consumes via `<link rel="stylesheet">`). Three-way `themeFingerprint` (`string | null | undefined`) preserves last-good styling across transient render errors. The combined `ReactRenderer` format branch is split into distinct q2-debug / q2-preview branches; the `render-components` gate is extended to cover q2-preview. Shared utilities added: `iframeLinkHandlers.ts` (event-delegation extraction), `sourceInfo.ts`, `atomicCustomNodes.ts`, `artifactPaths.ts`. The framework `RegistryContext` is extended with `sourceInfoPool?` (Plan 2B atomic-aware gate consumer). The q2-debug global `__REACT_AST_DEBUG_RENDERER__` is hoisted to module top. The iframe boots empty in 2A — every Pandoc node renders as a muted-gray "(not yet implemented)" placeholder. Plan 2B fills the registry with real-HTML leaves.
35
-
36
-
### 2026-05-08
37
-
38
-
- Plan-2pre carve-up of the q2-debug renderer (Phase 1 + Phase 2). The renderer is split into `framework/` (format-agnostic recursive dispatch, types, typed registry contract) and `q2-debug/` (bordered-box leaves, dispatchers, format registry, iframe wrapper, entry point). The iframe route renamed from `/ast-renderer.html` to `/q2-debug.html`; the iframe component from `AstIframe` to `Q2DebugIframe`; the registry from `componentRegistry` to `q2DebugRegistry`. The `__REACT_AST_DEBUG_RENDERER__` window global is preserved for user-TSX consumers. Bordered Figure no longer renders the literal `// TODO:` placeholder text in the DOM. `MathInline` added to the `InlineNode` union. Phase 1 commit: [`8afa8fae`](https://github.com/quarto-dev/q2/commits/8afa8fae). Phase 2 commits: [`59c8f3f5`](https://github.com/quarto-dev/q2/commits/59c8f3f5), [`f182b957`](https://github.com/quarto-dev/q2/commits/f182b957), [`ee4b05cd`](https://github.com/quarto-dev/q2/commits/ee4b05cd), [`44df8fd3`](https://github.com/quarto-dev/q2/commits/44df8fd3), [`d1d01dd9`](https://github.com/quarto-dev/q2/commits/d1d01dd9), [`9bbbaccb`](https://github.com/quarto-dev/q2/commits/9bbbaccb), [`84d0e919`](https://github.com/quarto-dev/q2/commits/84d0e919), [`0998e72d`](https://github.com/quarto-dev/q2/commits/0998e72d), [`becc7789`](https://github.com/quarto-dev/q2/commits/becc7789), [`eda6e152`](https://github.com/quarto-dev/q2/commits/eda6e152), [`5ced2bc4`](https://github.com/quarto-dev/q2/commits/5ced2bc4), [`c2454356`](https://github.com/quarto-dev/q2/commits/c2454356).
39
-
40
-
### 2026-05-06
41
-
42
-
-[`a5e00b20`](https://github.com/quarto-dev/q2/commits/a5e00b20): Setting `format: q2-preview` in a document's YAML frontmatter now drives the live preview through the q2-preview pipeline — full shortcodes, Lua filters, sectionize, crossref, sidebar/navbar metadata, embedded image artifacts — rendered through the AstIframe alongside q2-debug. Read-only in v1: component-driven edits (kanban drag, future comment buttons) silently no-op with a console warning; Plan 7 lifts that guard.
43
-
-[`845e8e71`](https://github.com/quarto-dev/q2/commits/845e8e71): Internal API extension for q2-preview Plan 1 — `RenderResult` gains an optional `ast_json?: string` field (paired with the existing `html?`). No user-visible behavior change yet; consumers of `renderQmd` / `renderPageInProject` see the same JSON envelope for HTML responses.
18
+
-[`68e5ec24`](https://github.com/quarto-dev/q2/commits/68e5ec24): Custom syntax highlighting now works in Quarto Hub projects (bd-izfv) — user-supplied tree-sitter grammars under `_quarto/grammars/<lang>/` now apply to code blocks even when the qmd file lives under a `_quarto.yml` ancestor, matching the single-file render path.
19
+
-[`915f1a3a`](https://github.com/quarto-dev/q2/commits/915f1a3a): New `format: q2-preview` drives the live preview through the q2-preview pipeline — shortcodes, Lua filters, sectionize, crossref, sidebar/navbar metadata, embedded image artifacts, footnote numbering, and appendix structure. Renders through the iframe alongside q2-debug. Read-only in v1: component-driven edits (kanban drag, future comment buttons) silently no-op with a console warning.
20
+
-[`eb07797b`](https://github.com/quarto-dev/q2/commits/eb07797b): Fix iframe-host crash when typing `render-components:\n -` (empty list bullet) into a document's YAML frontmatter; empty entries are now skipped silently.
0 commit comments