Make transitionCell pure by injecting parseOutline#8729
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
There was a problem hiding this comment.
Pull request overview
This PR refactors how a cell’s outline is derived during runtime state transitions by injecting parseOutline into transitionCell, rather than having transitionCell import DOM-dependent outline parsing directly. This helps keep the cell state transition logic usable in environments that may not support DOM APIs.
Changes:
- Update
transitionCellto accept an optionalparseOutlinefunction via a newoptionsparameter. - Move outline parsing responsibility to the caller (
cells.ts) by passingparseOutlineintotransitionCell.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
frontend/src/core/cells/cells.ts |
Passes parseOutline into transitionCell when handling kernel cell messages. |
frontend/src/core/cells/cell.ts |
Adds an options parameter to transitionCell and only parses outline when provided. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
frontend/src/core/cells/cell.ts
Outdated
| // Derive outline from output | ||
| nextCell.outline = parseOutline(nextCell.output); | ||
| if (options?.parseOutline) { | ||
| nextCell.outline = options.parseOutline(nextCell.output); |
| state, | ||
| cellId, | ||
| cellReducer: (cell) => { | ||
| return transitionCell(cell, message); | ||
| return transitionCell(cell, message, { parseOutline }); | ||
| }, |
There was a problem hiding this comment.
I think there's a similar issue if you import cells/session.ts. It looks like getOutline solves this with
function getOutline(html: string): Outline | null {
// Some JS runtimes (e.g. Node.js for the VSCode extension) do not
// expose DOMParser globally. In those environments parsing isn't
// possible (without a polyfill), so return just return `null`.
if (typeof DOMParser === "undefined") {
return null;
}Could we solve the root cause instead in DOMPurify (core/sanitize.ts)
if (typeof document !== "undefined") {
DOMPurify.addHook("beforeSanitizeAttributes", (node) => { ... });
DOMPurify.addHook("afterSanitizeAttributes", (node) => { ... });
}7655d74 to
0ee6ec5
Compare
0ee6ec5 to
b09fb87
Compare
The marimo-lsp extension imports `transitionCell` from the frontend via `@marimo-team/frontend/unstable_internal`. Previously `cell.ts` directly imported `parseOutline` from `dom/outline.ts`, which transitively pulled in `sanitize.ts`, DOMPurify, jotai atoms, and storage utilities that all assume a browser environment. This caused `ReferenceError: document is not defined` and `window is not defined` in the marimo-lsp Node test suite. Rather than sprinkling `typeof window` guards throughout the codebase, `parseOutline` is now an optional callback on `transitionCell`. The frontend passes it in at the single call site in `cells.ts`, while marimo-lsp callers get a pure function with no browser dependencies.
b09fb87 to
f2db86c
Compare
There was a problem hiding this comment.
any thoughts on the comment i made @manzt ? if not, this approach seems fine :)
The marimo-lsp extension imports `transitionCell` from the frontend, which transitively pulls in `sanitize-html.ts`. The module-level `DOMPurify.addHook` calls blow up with `ReferenceError: document is not defined` in Node.js because DOMPurify touches the DOM at registration time. Rather than injecting `parseOutline` as a callback into `transitionCell` (the previous approach on this branch), this fixes the root cause by wrapping the hooks in a `typeof document !== "undefined"` guard. This matches the existing pattern in `getOutline` which already guards against missing `DOMParser`. The `transitionCell` API stays unchanged and outline parsing continues to work in the browser while gracefully returning `null` in Node.
|
Sorry for the delay here. Your suggestion is much cleaner :) |
|
🚀 Development release published. You may be able to view the changes at https://marimo.app?v=0.21.2-dev16 |
The marimo-lsp extension imports
transitionCellfrom the frontend via@marimo-team/frontend/unstable_internal. Previouslycell.tsdirectly importedparseOutlinefromdom/outline.ts, which transitively pulled insanitize.ts, DOMPurify, jotai atoms, and storage utilities that all assume a browser environment. This causedReferenceError: document is not definedandwindow is not definedin the marimo-lsp Node test suite.Rather than sprinkling
typeof windowguards throughout the codebase,parseOutlineis now an optional callback ontransitionCell. The frontend passes it in at the single call site incells.ts, while marimo-lsp callers get a pure function with no browser dependencies.\