Skip to content

Commit a4abd6b

Browse files
committed
feat(parser): add GitHub-style TODO support in MarkdownPlanParser #331
- Added support for parsing GitHub-style TODO items with checkboxes. - Skip recursive processing for list nodes to avoid double-processing. - Updated task completion status check to include GitHub-style checkboxes. - Added corresponding unit tests for the new functionality.
1 parent 0ddbc88 commit a4abd6b

File tree

2 files changed

+76
-7
lines changed

2 files changed

+76
-7
lines changed

core/src/main/kotlin/cc/unitmesh/devti/sketch/ui/plan/MarkdownPlanParser.kt

Lines changed: 33 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ object MarkdownPlanParser {
2727
private val LOG = logger<MarkdownPlanParser>()
2828
private val ROOT_ELEMENT_TYPE = IElementType("ROOT")
2929
private val CHECKMARK = ""
30+
private val GITHUB_TODO_PATTERN = Regex("^\\s*-\\s*\\[\\s*([xX]?)\\s*\\]\\s*(.*)")
31+
private val GITHUB_TODO_CHECKED = listOf("x", "X")
3032

3133
/**
3234
* 解析markdown文本为计划项列表
@@ -131,13 +133,19 @@ object MarkdownPlanParser {
131133
}
132134
}
133135
}
136+
// Skip recursive processing for ORDERED_LIST nodes since we've already processed them
137+
// Don't call super.visitNode for this type to avoid double-processing
134138
}
135139
MarkdownElementTypes.UNORDERED_LIST -> {
136140
processTaskItems(node, content, currentSectionItems)
141+
// Skip recursive processing for UNORDERED_LIST nodes
142+
// Don't call super.visitNode for this type to avoid double-processing
143+
}
144+
else -> {
145+
// Only continue recursion for other node types
146+
super.visitNode(node)
137147
}
138148
}
139-
140-
super.visitNode(node)
141149
}
142150
})
143151

@@ -179,10 +187,28 @@ object MarkdownPlanParser {
179187
taskText
180188
}
181189

182-
// Process task text and retain the checkmark in the text
183-
val cleanTaskText = taskFirstLine.replace(Regex("^[\\-\\*]\\s+"), "").trim()
184-
if (cleanTaskText.isNotEmpty()) {
185-
itemsList.add(cleanTaskText)
190+
// Check for GitHub style TODO
191+
val githubTodoMatch = GITHUB_TODO_PATTERN.find(taskFirstLine)
192+
if (githubTodoMatch != null) {
193+
// Extract the task text and preserve the checkbox status
194+
val checkState = githubTodoMatch.groupValues[1]
195+
val todoText = githubTodoMatch.groupValues[2].trim()
196+
val isCompleted = checkState in GITHUB_TODO_CHECKED
197+
198+
// Add the task with the proper completion marker
199+
val formattedTask = if (isCompleted) {
200+
"[$CHECKMARK] $todoText"
201+
} else {
202+
"[ ] $todoText"
203+
}
204+
205+
itemsList.add(formattedTask)
206+
} else {
207+
// Process task text and retain the checkmark in the text (original behavior)
208+
val cleanTaskText = taskFirstLine.replace(Regex("^[\\-\\*]\\s+"), "").trim()
209+
if (cleanTaskText.isNotEmpty()) {
210+
itemsList.add(cleanTaskText)
211+
}
186212
}
187213
}
188214
}
@@ -206,7 +232,7 @@ data class PlanItem(
206232
init {
207233
// Parse task completion status for each task
208234
tasks.forEachIndexed { index, task ->
209-
taskCompleted[index] = task.contains("")
235+
taskCompleted[index] = task.contains("") || Regex("\\[\\s*([xX])\\s*\\]").containsMatchIn(task)
210236
}
211237
}
212238
}

core/src/test/kotlin/cc/unitmesh/devti/sketch/ui/plan/MarkdownPlanParserTest.kt

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,4 +143,47 @@ class MarkdownPlanParserTest {
143143
"控制层:BlogController添加新端点 ✓"
144144
)
145145
}
146+
147+
@Test
148+
fun should_return_correct_items() {
149+
// Given
150+
val markdownContent = """
151+
1. **分析现有代码结构**:
152+
- BlogService 中的 `deleteBlog` 方法目前只支持按 ID 删除
153+
- BlogPost 实体类中的 author 字段类型为 String,但 DTO 中的 author 是 Author 对象类型,存在映射不一致
154+
- Repository 层使用 CrudRepository 需要扩展自定义删除方法
155+
156+
2. **数据库字段确认**:
157+
- 需要确认 BlogPost 表实际存储的 author 字段类型(当前代码显示为 String 类型)
158+
159+
3. **功能实现步骤**:
160+
- [ ] 在 BlogRepository 添加按作者删除的方法
161+
- [ ] 扩展 BlogService 添加 deleteByAuthor 方法
162+
- [ ] 在 BlogController 添加新的 DELETE 端点
163+
- [ ] 修复 DTO 与实体类的 author 字段类型一致性
164+
- [ ] 添加 Swagger 接口文档注解
165+
- [ ] 补充单元测试
166+
167+
4. **异常处理**:
168+
- 处理不存在的作者删除请求
169+
- 添加事务管理注解
170+
- 统一返回结果格式
171+
""".trimIndent()
172+
173+
// When
174+
val planItems = MarkdownPlanParser.parse(markdownContent)
175+
176+
// Then
177+
assertThat(planItems).hasSize(4)
178+
assertThat(planItems[0].title).isEqualTo("**分析现有代码结构**:")
179+
// test markdown
180+
assertThat(planItems[2].tasks).containsExactly(
181+
"[ ] 在 BlogRepository 添加按作者删除的方法",
182+
"[ ] 扩展 BlogService 添加 deleteByAuthor 方法",
183+
"[ ] 在 BlogController 添加新的 DELETE 端点",
184+
"[ ] 修复 DTO 与实体类的 author 字段类型一致性",
185+
"[ ] 添加 Swagger 接口文档注解",
186+
"[ ] 补充单元测试"
187+
)
188+
}
146189
}

0 commit comments

Comments
 (0)