Repository navigation
fix: preserve empty task list items when parsing markdown - #4696
Conversation
There was a problem hiding this comment.
Pull request overview
Fixes Muya’s marked token compatibility layer so empty GFM task list items (e.g. - [ ] / - [x] ) are preserved as task-list items instead of degrading into normal bullet list items containing the literal text [ ] / [x].
Changes:
- Add a normalization step in
compatibleTaskListto detect unordered list items whose raw markdown is only an empty task marker and convert them intotasklist items with empty content. - Add regression tests in
markdownToState.spec.tscovering empty unchecked/checked task items (standalone and following a populated task).
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
| packages/muya/src/utils/marked/compatibleTaskList.ts | Normalizes empty task markers into proper task list item tokens before state conversion. |
| packages/muya/src/state/tests/markdownToState.spec.ts | Adds regression tests ensuring empty task list items become task-list-item states with correct checked meta. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
I can still produce this issue on your branch. |
|
@Jocs So the condition is intentional: it verifies that the list item text is exactly the empty task marker and does not contain real task content before rewriting the token as a task-list item. That said, I agree the inline template expression is easy to misread. I can make it clearer without changing behavior: const marker = `[${matches[1]}]`;
if (text !== marker)
return;I also re-tested the original reported cases on - [ ] a
- [ ] - [ ] - [x]
All three now render as task-list items with checkboxes in If there is another case that still reproduces the issue, please share the exact Markdown input and reproduction steps. I may have missed a different token shape, and I would be happy to add coverage for it. |
Follow-up on empty task list itemsI checked the incomplete cases on top of The first gap is the lazy-continuation shape: - [ ]
textWith the current The original fix only handled the empty-only shape where The follow-up change keeps the original guard narrow: it only normalizes unordered list items whose raw source starts with a valid task marker and whose parsed text contains the matching synthetic marker prefix. It then strips only that synthetic marker from the token text while preserving the continuation content as the task item's paragraph. Invalid forms such as The second gap is editor rendering. Parser-created empty list items had The follow-up now normalizes empty This matches the existing The third gap is serialization. Programmatic or legacy states can still contain empty list items with - [ ] - [ ] The serializer now returns a complete line for empty list items. This covers both empty task items and plain empty bullet items without changing non-empty list item serialization. Expected behavior after the follow-up: - [ ]
textis parsed as one unchecked task item with - [ ] textwhich preserves the Markdown semantics. Regression coverage added: All passed locally. The lint command only reports existing warnings. |
…ist-items # Conflicts: # packages/muya/src/state/__tests__/listSerialization.spec.ts
|
Updated this branch after merging the latest I also folded the plain empty bullet-list regression coverage from the narrower empty-list PR into this PR, as
While resolving the merge, I also fixed two regressions introduced by the interaction with newer
Validation: |
upstream が持ち込んだ主なもの: - list serialization 刷新(空項目保持 marktext#4696/marktext#4697、markerOverride/_isLooseParentList) - code fence 長の保持 marktext#4755、ソースモード undo/redo、math/diagram スクロール - flush()/_flushOperationCache() による pending-edit 同期 marktext#2938 - plain-inline-spaces 保持の paste marktext#4706、大規模依存アップグレード marktext#4597 ほか 採用/保持の判断: - フォーク保持: CLAUDE.md、setWrapCodeBlocks、PDF 描画 - 両立: fence info(フォーク) + fenceLength(upstream)、whole-line paste(フォーク) + plain-inline-spaces(upstream)、@tauri-apps/cli 保持 + upstream バージョンアップ採用 - upstream 採用: flush 機構(フォークの flushPendingChanges / _commitOperationCache / _rafHandle / _isGoing を除去、呼び出し側 editor.vue を flush() に更新) 波及修正: - フォークの空 paragraph 往復保持を top-level (_listType 空) に限定し、upstream の 空リスト項目処理と両立(muya unit 10件の回帰を解消) - pnpm-lock.yaml をマージ後 package.json から再生成 検証(全緑): muya lint:types / check-circular / unit 1397 / conformance 1347、 desktop typecheck / unit 695、build:tauri 成功・実機動作確認 OK Co-Authored-By: Claude Opus 4.8 <[email protected]>

Closes #4680
Summary
Fix Markdown parsing for empty task list items.
Previously, empty task items such as
- [ ]and- [x]were parsed as normal bullet list items whose text was the literal string[ ]or[x]. As a result, MarkText rendered them without a checkbox, and a single task list could be split into a task list plus a normal bullet list.For example:
was parsed as:
- [ ] a[ ]This PR fixes the token compatibility layer so empty checkbox markers are restored as task list items before
markdownToStatebuilds the document state.Type of change
Test plan
develop.Test commands:
Results:
Additional Playwright validation:
- [ ] a\n- [ ] \n,- [ ] \n, and- [x] \ninto the editor.task-list-itemsemantics and the correct checked value.Full
@muyajs/coretest note:The remaining failure was an unrelated existing 5s timeout in
src/ui/tableChessboard/__tests__/tableChessboard.spec.tswhen importing the package entrypoint.Notes for reviewers [optional]
The root cause is in the parsing compatibility path:
packages/muya/src/utils/marked/lexBlock.tspackages/muya/src/utils/marked/compatibleTaskList.tspackages/muya/src/state/markdownToState.tsFor non-empty task items, marked provides
task: true, socompatibleTaskList.tsclassifies the item as a task item.For empty task items such as
- [ ], marked provides a normal list item withtask: falseand text[ ]. Because the compatibility layer only checkeditem.task,markdownToStatehad no way to recover the intended checkbox semantics.This PR adds a narrow normalization step in
compatibleTaskList.ts: if an unordered list item's raw Markdown is only a bullet marker plus an empty task checkbox marker, and the parsed text is only[ ],[x], or[X], it restores the token to a task item and clears the marker text before state conversion.Regression tests cover:
By submitting this pull request, I confirm that my contribution is made under the terms of the MIT license.