Skip to content

Make transitionCell pure by injecting parseOutline#8729

Merged
manzt merged 2 commits intomainfrom
push-rutuqpqqzuzy
Mar 20, 2026
Merged

Make transitionCell pure by injecting parseOutline#8729
manzt merged 2 commits intomainfrom
push-rutuqpqqzuzy

Conversation

@manzt
Copy link
Copy Markdown
Collaborator

@manzt manzt commented Mar 17, 2026

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.

\

@manzt manzt requested a review from Light2Dark as a code owner March 17, 2026 03:05
Copilot AI review requested due to automatic review settings March 17, 2026 03:05
@vercel
Copy link
Copy Markdown

vercel bot commented Mar 17, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
marimo-docs Ready Ready Preview, Comment Mar 20, 2026 3:45pm

Request Review

@manzt manzt added the internal A refactor or improvement that is not user facing label Mar 17, 2026
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 transitionCell to accept an optional parseOutline function via a new options parameter.
  • Move outline parsing responsibility to the caller (cells.ts) by passing parseOutline into transitionCell.

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.

// Derive outline from output
nextCell.outline = parseOutline(nextCell.output);
if (options?.parseOutline) {
nextCell.outline = options.parseOutline(nextCell.output);
Comment on lines 760 to 764
state,
cellId,
cellReducer: (cell) => {
return transitionCell(cell, message);
return transitionCell(cell, message, { parseOutline });
},
Copy link
Copy Markdown
Collaborator

@Light2Dark Light2Dark left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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) => { ... });
}

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.
Light2Dark
Light2Dark previously approved these changes Mar 19, 2026
Copy link
Copy Markdown
Collaborator

@Light2Dark Light2Dark left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.
@manzt
Copy link
Copy Markdown
Collaborator Author

manzt commented Mar 20, 2026

Sorry for the delay here. Your suggestion is much cleaner :)

@manzt manzt merged commit c579e7f into main Mar 20, 2026
28 checks passed
@manzt manzt deleted the push-rutuqpqqzuzy branch March 20, 2026 15:50
@github-actions
Copy link
Copy Markdown

🚀 Development release published. You may be able to view the changes at https://marimo.app?v=0.21.2-dev16

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

internal A refactor or improvement that is not user facing marimo-lsp

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants