Skip to content

fix(markdown): preserve pipe characters inside inline code spans in table cells#7884

Open
sahiee-dev wants to merge 2 commits into
ueberdosis:mainfrom
sahiee-dev:fix/table-inline-code-pipe-7858
Open

fix(markdown): preserve pipe characters inside inline code spans in table cells#7884
sahiee-dev wants to merge 2 commits into
ueberdosis:mainfrom
sahiee-dev:fix/table-inline-code-pipe-7858

Conversation

@sahiee-dev
Copy link
Copy Markdown
Contributor

Changes Overview

Fixes a parsing bug where pipe characters (|) inside backtick inline code spans were incorrectly treated as table column delimiters, causing table rows with cells like `||` or `a || b` to split into the wrong number of columns and lose their code formatting.

Implementation Approach

marked's internal splitCells function splits table rows by replacing every | with a split marker, only exempting backslash-escaped pipes (\|). It has no awareness of backtick code spans, so `||` in a table cell was split into multiple columns.

The fix adds a preprocessing step in MarkdownManager.parse(), before the markdown string is passed to marked's lexer, any | characters found inside backtick code spans on table-row lines (lines starting with |) are escaped to \|.

Since splitCells already converts \| back to | after splitting, the cell content is restored correctly with no second pass needed.

The preprocessing handles single, double, and triple backtick spans and is a no-op for lines that are not table rows or contain no backtick spans, so it does not affect any other markdown parsing.

Testing Done

Added 5 tests to packages/extension-table/__tests__/tableMarkdown.spec.ts:

  • Parses `||` in a table cell as a single cell with a code mark
  • Parses a full 3-column row with `||`, or, `a || b` correctly
  • Regression guard for && (was also affected)
  • Full parse → serialize → re-parse roundtrip preserving code marks
  • Guard confirming tables without backtick spans are unaffected

All 6 tests in the file pass (1 pre-existing, 5 new).

Verification Steps

  1. Clone the repo and run:
vitest run packages/extension-table/tests/tableMarkdown.spec.ts
  1. Start the demos dev server (vite from demos/) and open:
/preview/Markdown/Full/React
  1. Paste the following into the markdown input and click Parse Markdown:
| Header | Header | Header |
| ------ | ------ | ------ |
| `||` | or | `a || b` |
| `&&` | and | `a && b` |
  1. Confirm the table renders with 3 columns and inline code formatting on each code span.

  2. Click Extract Markdown and confirm the output preserves the backtick wrappers.

Additional Notes

The root cause is entirely inside marked's splitCells, it is not something Tiptap can fix by overriding the table tokenizer without reimplementing the full table block rule.

The preprocessing approach is the minimal, safe intervention point within Tiptap's own code.

Related Issues

Fixes #7858

…able cells

marked's splitCells only exempts backslash-escaped pipes when splitting
table rows into cells, so `||` or `a || b` inside a table cell was
treated as column delimiters instead of literal content.

Add a preprocessing step in MarkdownManager.parse() that escapes pipe
characters inside backtick code spans on table-row lines before handing
the markdown to marked. marked already converts \| back to | after
splitting, so no post-processing is needed.

Fixes ueberdosis#7858
@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented May 29, 2026

🦋 Changeset detected

Latest commit: e52bcc4

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 72 packages
Name Type
@tiptap/markdown Patch
@tiptap/core Patch
@tiptap/extension-audio Patch
@tiptap/extension-blockquote Patch
@tiptap/extension-bold Patch
@tiptap/extension-bubble-menu Patch
@tiptap/extension-bullet-list Patch
@tiptap/extension-code-block-lowlight Patch
@tiptap/extension-code-block Patch
@tiptap/extension-code Patch
@tiptap/extension-collaboration-caret Patch
@tiptap/extension-collaboration Patch
@tiptap/extension-color Patch
@tiptap/extension-details Patch
@tiptap/extension-document Patch
@tiptap/extension-drag-handle-react Patch
@tiptap/extension-drag-handle-vue-2 Patch
@tiptap/extension-drag-handle-vue-3 Patch
@tiptap/extension-drag-handle Patch
@tiptap/extension-emoji Patch
@tiptap/extension-file-handler Patch
@tiptap/extension-floating-menu Patch
@tiptap/extension-font-family Patch
@tiptap/extension-hard-break Patch
@tiptap/extension-heading Patch
@tiptap/extension-highlight Patch
@tiptap/extension-horizontal-rule Patch
@tiptap/extension-image Patch
@tiptap/extension-invisible-characters Patch
@tiptap/extension-italic Patch
@tiptap/extension-link Patch
@tiptap/extension-list Patch
@tiptap/extension-mathematics Patch
@tiptap/extension-mention Patch
@tiptap/extension-node-range Patch
@tiptap/extension-ordered-list Patch
@tiptap/extension-paragraph Patch
@tiptap/extension-strike Patch
@tiptap/extension-subscript Patch
@tiptap/extension-superscript Patch
@tiptap/extension-table-of-contents Patch
@tiptap/extension-table Patch
@tiptap/extension-text-align Patch
@tiptap/extension-text-style Patch
@tiptap/extension-text Patch
@tiptap/extension-twitch Patch
@tiptap/extension-typography Patch
@tiptap/extension-underline Patch
@tiptap/extension-unique-id Patch
@tiptap/extension-youtube Patch
@tiptap/extensions Patch
@tiptap/html Patch
@tiptap/pm Patch
@tiptap/react Patch
@tiptap/starter-kit Patch
@tiptap/static-renderer Patch
@tiptap/suggestion Patch
@tiptap/vue-2 Patch
@tiptap/vue-3 Patch
@tiptap/extension-character-count Patch
@tiptap/extension-dropcursor Patch
@tiptap/extension-focus Patch
@tiptap/extension-gapcursor Patch
@tiptap/extension-history Patch
@tiptap/extension-list-item Patch
@tiptap/extension-list-keymap Patch
@tiptap/extension-placeholder Patch
@tiptap/extension-table-cell Patch
@tiptap/extension-table-header Patch
@tiptap/extension-table-row Patch
@tiptap/extension-task-item Patch
@tiptap/extension-task-list Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@netlify
Copy link
Copy Markdown

netlify Bot commented May 29, 2026

Deploy Preview for tiptap-embed ready!

Name Link
🔨 Latest commit e52bcc4
🔍 Latest deploy log https://app.netlify.com/projects/tiptap-embed/deploys/6a1dacb667e16a0008844a82
😎 Deploy Preview https://deploy-preview-7884--tiptap-embed.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

Comment thread demos/src/Markdown/Full/React/content.ts Outdated
Comment thread packages/extension-table/__tests__/tableMarkdown.spec.ts Outdated
Comment thread packages/markdown/src/MarkdownManager.ts Outdated
Comment thread packages/markdown/src/MarkdownManager.ts Outdated
@sahiee-dev
Copy link
Copy Markdown
Contributor Author

Updated the PR based on your feedback.

The fix is now entirely inside extension-table via a block-level markdownTokenizer; MarkdownManager is untouched.

I also found and fixed a subtle bug in the first revision: helper.blockTokens was being called on the full remaining source, which caused token.raw to be longer than the original table content and could silently consume characters after the table.

The fix now extracts only the table lines before re-lexing, and I've added a regression test that would have caught this issue.

…izer

The preprocessing logic now lives entirely in extension-table via a
block-level markdownTokenizer, keeping MarkdownManager generic. Also
fixes a subtle raw-field length mismatch where helper.blockTokens was
called on the full remaining source, causing marked to advance its
cursor past the end of the table and silently drop content that followed.
Fix: extract only the table lines before re-lexing so raw always
corresponds to the original source length.
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.

special inline code in table parsing error

2 participants