Skip to content

handle half-complete markdown formatting markers #313

@jinghaihan

Description

@jinghaihan

Bug Description

In intermediate states, there can be a brief moment where a strong token is parsed into the following AST structure. This causes visual flickering on the page.

The scenarios I have identified so far include strong and strikethrough.

This is **bold text*
{
    "type": "root",
    "children": [
        {
            "type": "paragraph",
            "children": [
                {
                    "type": "text",
                    "value": "This is *",
                    "position": {
                        "start": {
                            "line": 1,
                            "column": 1,
                            "offset": 0
                        },
                        "end": {
                            "line": 1,
                            "column": 10,
                            "offset": 9
                        }
                    }
                },
                {
                    "type": "emphasis",
                    "children": [
                        {
                            "type": "text",
                            "value": "bold text",
                            "position": {
                                "start": {
                                    "line": 1,
                                    "column": 11,
                                    "offset": 10
                                },
                                "end": {
                                    "line": 1,
                                    "column": 20,
                                    "offset": 19
                                }
                            }
                        }
                    ],
                    "position": {
                        "start": {
                            "line": 1,
                            "column": 10,
                            "offset": 9
                        },
                        "end": {
                            "line": 1,
                            "column": 21,
                            "offset": 20
                        }
                    }
                }
            ],
            "position": {
                "start": {
                    "line": 1,
                    "column": 1,
                    "offset": 0
                },
                "end": {
                    "line": 1,
                    "column": 21,
                    "offset": 20
                }
            }
        }
    ],
    "position": {
        "start": {
            "line": 1,
            "column": 1,
            "offset": 0
        },
        "end": {
            "line": 1,
            "column": 21,
            "offset": 20
        }
    }
}

I’m working on a similar approach myself, and I’d be glad if this could be useful for Streamdown:
strong

From my perspective, I’d really prefer to see these requirements handled as much as possible within remend, instead of everyone maintaining their own implementations.

Steps to Reproduce

import { describe, expect, it } from "vitest";
import remend from "../src";

describe("half complete", () => {
  it("should handle incomplete bold", () => {
    expect(remend("This is **bold text*")).toBe("This is **bold text**");
  });

  it("should handle incomplete bold", () => {
    expect(remend("This is __bold text_")).toBe("This is __bold text__");
  });

  it("should handle incomplete strikethrough", () => {
    expect(remend("This is ~~bold text~")).toBe("This is ~~bold text~~");
  });
});

Expected Behavior

Expected: "This is bold text"
Expected: "This is bold text"
Expected: "This is bold text"

Actual Behavior

Received: "This is *bold text"
Received: "This is _bold text"
Received: "This is ~~bold text~"

Streamdown Version

latest

React Version

latest

Node.js Version

v24.12.0

Browser(s)

No response

Operating System

None

Additional Context

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions