CJK autolink boundary handling keeps `**` in the URL when a bold URL is followed by CJK punctuation
Los mantenedores suelen responder en 1 día
Evaluación
- Dificultad
- 3/5
- Tiempo estimado
- Medio día
- Aptitud para principiantes
- 50/100
- Tipo de issue
- Error
- Claridad
- Bastante claro
- Estado de actividad
- Activo
- Stack tecnológico
- react, typescript
- Área
- frontend, internationalization
Línea de trabajo
Start with the @streamdown/cjk autolink split introduced for #327 and check where it cuts the URL at fullwidth punctuation. Reproduce with the four table inputs, which should show bold plus a link to https://example.com/ for the spaced cases and no bold for the unspaced ones. Done means **https://example.com/**、英語版 renders a span wrapping the link, with no ** in the href, while the #326 and #327 cases still pass.
Escrito por el modelo de indexación a partir del texto del issue.
Descripción
Bug Description
With @streamdown/cjk enabled, a bare URL wrapped in ** and immediately followed by fullwidth punctuation (e.g. 、, U+3001) renders with ** included in the link URL, and the bold is not applied.
@streamdown/cjk already cuts the autolink at the fullwidth punctuation (#327, fixing #326), so the rest of the sentence is no longer swallowed. However, the closing ** stays inside the link, so the emphasis is never formed. This looks like another case not covered by #327, similar to #623.
The underlying behavior is GFM's autolink literal rule, which remark-gfm follows as specified:
- The URL extends until whitespace or the end of the text.
- Only trailing ASCII punctuation (
?,!,.,,,:,*,_,~) is trimmed from the end of that range.
In English this only happens when the space after the punctuation is missing (**URL**,then), which is rare. In CJK text, punctuation is not followed by a space, so it happens almost every time a bold URL is followed by a comma or period. Fullwidth punctuation is also not in the trimmed set, so adding a space after 、 does not help either.
Steps to Reproduce
Render the code sample below. mode="static" and mode="streaming" produce the same HTML, so this is not related to remend's incomplete-markdown handling.
Expected Behavior
The same output as when there is a space before 、 (attributes stripped; Streamdown renders bold as a span):
<p>日本語版は <span><a href="https://example.com/">https://example.com/</a></span>、英語版は別ページです。</p>
- The link points to
https://example.com/. - The bold is applied to the link.
、英語版は別ページです。is plain text.
Actual Behavior
With @streamdown/cjk (attributes stripped for readability):
<p>日本語版は **<a href="https://example.com/**">https://example.com/**</a>、英語版は別ページです。</p>
Without @streamdown/cjk, the link swallows the rest of the sentence (the #326 behavior):
<p>日本語版は **<a href="https://example.com/**%E3%80%81...">https://example.com/**、英語版は別ページです。</a></p>
The same rule applied to other inputs:
| Input | Result |
|---|---|
See **https://example.com/**, then more |
bold + link to https://example.com/ |
See **https://example.com/**,then more |
link to https://example.com/**,then, no bold |
日本語版は **https://example.com/** 、英語版 |
bold + link to https://example.com/ |
日本語版は **https://example.com/**、 英語版 |
link to https://example.com/**, no bold |
Code Sample
import { Streamdown } from 'streamdown';
import { cjk } from '@streamdown/cjk';
const markdown = '日本語版は **https://example.com/**、英語版は別ページです。';
export default function App() {
return <Streamdown plugins={{ cjk }}>{markdown}</Streamdown>;
}
Streamdown Version
streamdown 2.7.0; @streamdown/cjk 1.0.4
React Version
19.3.0
Node.js Version
24.21.0
Browser(s)
No response
Operating System
None
Additional Context
A possible fix in the autolink split from #327: when the URL is cut at fullwidth punctuation, also trim trailing * / _ / ~ from the URL and let the emphasis be formed, as GFM does for ASCII punctuation. Adding fullwidth punctuation to the trimmed set would also cover the case with a space after 、.
LLM output often bolds URLs in Japanese and Chinese, so this shows up regularly in chat UIs.
- Lenguaje dominante
- TypeScript
- Estrellas
- 5.7k
- Forks
- 307
- Merge medio
- 1 d 22 h
- PR fusionados (30 d)
- 22
Preparar el entorno
- Sin Dockerfile ni archivo de Docker Compose
- Tiene una plantilla de pull request
- Leer la guía de contribución
Primeros pasos
- Lee el issue completo y luego la guía de contribución del proyecto.
- Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
- Haz un fork del repositorio y trabaja en una rama.
- Abre un pull request que haga referencia al número del issue.
Más de vercel/streamdown
-
`mode="static"` parses the whole document twice on mount (since the caret host in 2.7)Posiblemente ocupada @akhil9tiet la tomó hace 1 día. Abiertobug
Dificultad 2/5 1-3 horas Aptitud para principiantes 72/100
vercel/streamdown#673 · 3 comentarios · 2 reacciones ·
Los mantenedores suelen responder en 1 día
-
remend: unclosed `$$` in a table cell is closed on a new line when an earlier line has mathPosiblemente ocupada @orinnz la tomó hace 12 días. Abierto
Dificultad 2/5 1-3 horas Aptitud para principiantes 85/100
vercel/streamdown#652 ·
Los mantenedores suelen responder en 1 día
-
`data-*` and `aria-*` props passed to `<Streamdown>` are never set on its root elementPosiblemente ocupada @xyrolle la tomó hoy. Abierto
Dificultad 3/5 Medio día Aptitud para principiantes 55/100
vercel/streamdown#675 ·
Los mantenedores suelen responder en 1 día
-
Dificultad 4/5 3-5 días Aptitud para principiantes 35/100
vercel/streamdown#669 ·
Los mantenedores suelen responder en 1 día
-
Mermaid shows an error for a partial chart while its fence is still streamingPosiblemente ocupada @slavco86 la tomó hace 2 días. Abierto
Dificultad 2/5 1-3 horas Aptitud para principiantes 25/100
vercel/streamdown#667 · 1 comentario ·
Los mantenedores suelen responder en 1 día
Todos los issues de vercel/streamdown
Issues similares
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 68/100
apache/rocketmq-dashboard#6872 ·
Los mantenedores suelen responder en 3 días
-
bug
Dificultad 2/5 1-3 horas Aptitud para principiantes 70/100
fab-geocommuns/RNB-site#539 ·
Los mantenedores suelen responder en 2 días
-
Guest multiview tile label leaks raw virtual-source-id "Whip" instead of the guest name / slot labelAbierto
Dificultad 2/5 1-3 horas Aptitud para principiantes 62/100
Eyevinn/open-live-studio#211 ·
Los mantenedores suelen responder en 1 día
-
documentation good first issue
Dificultad 2/5 Medio día Aptitud para principiantes 72/100
sujithputta02/Esapay#13 ·
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 65/100
ehmpathy/rhachet-roles-bhuild#468 ·
Los mantenedores suelen responder en 1 día