Skip to content

Commit

Permalink
Add support for task list items (#8)
Browse files Browse the repository at this point in the history
Fixes #7
  • Loading branch information
mattmook authored Apr 10, 2019
1 parent 1beb06b commit 557ec50
Show file tree
Hide file tree
Showing 17 changed files with 195 additions and 7 deletions.
1 change: 1 addition & 0 deletions markdown/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ dependencies {
api("com.vladsch.flexmark:flexmark-ext-tables:0.40.20")
api("com.vladsch.flexmark:flexmark-ext-gfm-strikethrough:0.40.20")
api("com.vladsch.flexmark:flexmark-ext-autolink:0.40.20")
api("com.vladsch.flexmark:flexmark-ext-gfm-tasklist:0.40.20")

testImplementation(kotlin("test"))
testImplementation(gradleTestKit())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import com.vladsch.flexmark.ast.Paragraph
import com.vladsch.flexmark.ast.Reference
import com.vladsch.flexmark.ast.Text
import com.vladsch.flexmark.ast.ThematicBreak
import com.vladsch.flexmark.ext.gfm.tasklist.TaskListItem
import com.vladsch.flexmark.ext.tables.TableBlock
import com.vladsch.flexmark.util.ast.Block
import com.vladsch.flexmark.util.ast.Document
Expand All @@ -39,6 +40,7 @@ class MarkdownDocument(val filename: String, val document: Document) {
val htmlElements: List<Node> by lazy { document.find(HtmlBlock::class, HtmlInline::class) }
val orderedListItems: List<OrderedListItem> by lazy { document.find(OrderedListItem::class) }
val unorderedListItems: List<BulletListItem> by lazy { document.find(BulletListItem::class) }
val taskListItems: List<TaskListItem> by lazy { document.find(TaskListItem::class) }
val listItems: List<ListItem> by lazy { document.find(OrderedListItem::class, BulletListItem::class) }

val listBlocks: List<ListBlock> by lazy { document.find(OrderedList::class, BulletList::class) }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package com.appmattus.markdown.processing

import com.vladsch.flexmark.ext.autolink.AutolinkExtension
import com.vladsch.flexmark.ext.gfm.strikethrough.StrikethroughExtension
import com.vladsch.flexmark.ext.gfm.tasklist.TaskListExtension
import com.vladsch.flexmark.ext.tables.TablesExtension
import com.vladsch.flexmark.parser.Parser
import com.vladsch.flexmark.util.options.MutableDataSet
Expand All @@ -18,7 +19,8 @@ internal object ParserFactory {
listOf(
TablesExtension.create(),
StrikethroughExtension.create(),
AutolinkExtension.create()
AutolinkExtension.create(),
TaskListExtension.create()
)
).build()
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package com.appmattus.markdown.rules

import com.appmattus.markdown.dsl.RuleSetup
import com.appmattus.markdown.errors.ErrorReporter
import com.appmattus.markdown.processing.MarkdownDocument
import com.appmattus.markdown.rules.config.TaskListItemMarkerStyle
import com.appmattus.markdown.rules.extentions.style

/**
* # Task list item marker style
*
* This rule is triggered when the symbols used in the document for task list item markers do not match the configured
* task list item marker style:
*
* - [x]
* - [X]
*
* To fix this issue, use the configured style for task list item markers throughout the document:
*
* - [x]
* - [x]
*
* Note: the configured task list item marker style can be a specific case ([TaskListItemMarkerStyle.Lowercase],
* [TaskListItemMarkerStyle.Uppercase]), or simply require that the usage be
* [TaskListItemMarkerStyle.Consistent] within the document.
*/
class ConsistentTaskListMarkerStyleRule(
private val style: TaskListItemMarkerStyle = TaskListItemMarkerStyle.Lowercase,
override val config: RuleSetup.Builder.() -> Unit = {}
) : Rule() {

override val description = "Task list item marker style"
override val tags = listOf("task-list", "ul")

override fun visitDocument(document: MarkdownDocument, errorReporter: ErrorReporter) {

val doneMarkers = document.taskListItems.filter { it.isItemDoneMarker }

if (doneMarkers.isEmpty()) {
return
}

val docStyle = if (style == TaskListItemMarkerStyle.Consistent) doneMarkers.first().style() else style

doneMarkers.forEach {
if (it.style() != docStyle) {
errorReporter.reportError(it.startOffset, it.endOffset, description)
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -87,10 +87,14 @@ class ListMarkerSpaceRule(
else -> throw IllegalStateException()
}

listBlock.children.forEach {
it as ListItem
if (it.firstChild.startOffset - it.openingMarker.endOffset != indent) {
errorReporter.reportError(it.startOffset, it.endOffset, description)
listBlock.children.forEach { item ->
item as ListItem

// For task lists we look at the marker suffix as the opening content
val startContent = item.markerSuffix.takeIf(CharSequence::isNotEmpty) ?: item.firstChild.chars

if (startContent.startOffset - item.openingMarker.endOffset != indent) {
errorReporter.reportError(item.startOffset, item.endOffset, description)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package com.appmattus.markdown.rules

import com.appmattus.markdown.dsl.RuleSetup
import com.appmattus.markdown.errors.ErrorReporter
import com.appmattus.markdown.processing.MarkdownDocument

/**
* # Spaces after list markers
*
* This rule checks for the number of spaces between a task list marker (e.g. '[ ]', '&#91;x]' or '&#91;X]') and the text of
* the list item.
*
* The number of spaces checked for depends on the document style in use, but the default is 1 space after any task list
* marker:
*
* - [ ] Foo
* - [x] Bar
* - [ ] Baz
*
* To fix this, ensure the correct number of spaces are used after task list markers for your selected document style.
*/
class TaskListMarkerSpaceRule(
private val indent: Int = 1,
override val config: RuleSetup.Builder.() -> Unit = {}
) : Rule() {

override val description = "Spaces after task list markers"
override val tags = listOf("task-list", "ul", "whitespace")

override fun visitDocument(document: MarkdownDocument, errorReporter: ErrorReporter) {

document.taskListItems.forEach { item ->

if (item.firstChild.startOffset - item.markerSuffix.endOffset != indent) {
errorReporter.reportError(item.startOffset, item.endOffset, description)
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package com.appmattus.markdown.rules.config

enum class TaskListItemMarkerStyle {
Consistent, Uppercase, Lowercase
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.appmattus.markdown.rules.extentions

import com.appmattus.markdown.rules.config.TaskListItemMarkerStyle
import com.vladsch.flexmark.ext.gfm.tasklist.TaskListItem

fun TaskListItem.style(): TaskListItemMarkerStyle? {
return when (this.markerSuffix.toString()) {
"[x]" -> TaskListItemMarkerStyle.Lowercase
"[X]" -> TaskListItemMarkerStyle.Uppercase
else -> null
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package com.appmattus.markdown.rules

import com.appmattus.markdown.rules.config.TaskListItemMarkerStyle
import org.spekframework.spek2.Spek
import org.spekframework.spek2.style.gherkin.Feature

object ConsistentTaskListMarkerStyleRuleTest : Spek({
Feature("ConsistentTaskListMarkerStyleRule") {

FileRuleScenario(listOf("task-list-marker.md")) {
ConsistentTaskListMarkerStyleRule(TaskListItemMarkerStyle.Consistent)
}

FileRuleScenario(listOf("task-list-marker.md")) {
ConsistentTaskListMarkerStyleRule(TaskListItemMarkerStyle.Lowercase)
}

FileRuleScenario(listOf("task-list-marker-uppercase.md")) {
ConsistentTaskListMarkerStyleRule(TaskListItemMarkerStyle.Uppercase)
}

FileRuleScenario(listOf("task-list-marker-no-complete.md")) {
ConsistentTaskListMarkerStyleRule(TaskListItemMarkerStyle.Consistent)
}

FileRuleScenario { ConsistentTaskListMarkerStyleRule() }
}
})
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@ package com.appmattus.markdown.rules
import org.spekframework.spek2.Spek
import org.spekframework.spek2.style.gherkin.Feature

object ListMarkerSpaceTest : Spek({
object ListMarkerSpaceRuleTest : Spek({
Feature("ListMarkerSpaceRule") {
FileRuleScenario(listOf("task-list-marker.md")) { ListMarkerSpaceRule() }

FileRuleScenario(listOf("spaces_after_list_marker.md")) { ListMarkerSpaceRule(ulMulti = 3, olMulti = 2) }

FileRuleScenario(exclude = listOf("spaces_after_list_marker.md")) { ListMarkerSpaceRule() }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package com.appmattus.markdown.rules
import org.spekframework.spek2.Spek
import org.spekframework.spek2.style.gherkin.Feature

object NoMissingSpaceClosedAtxTest : Spek({
object NoMissingSpaceClosedAtxRuleTest : Spek({
Feature("NoMissingSpaceClosedAtxRule") {
FileRuleScenario { NoMissingSpaceClosedAtxRule() }
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.appmattus.markdown.rules

import org.spekframework.spek2.Spek
import org.spekframework.spek2.style.gherkin.Feature

object TaskListMarkerSpaceRuleTest : Spek({
Feature("TaskListMarkerSpaceRule") {
FileRuleScenario(listOf("task-list-marker.md")) { TaskListMarkerSpaceRule() }

FileRuleScenario(listOf("task-list-marker-large-indent.md")) { TaskListMarkerSpaceRule(indent = 2) }

FileRuleScenario { TaskListMarkerSpaceRule() }
}
})
8 changes: 8 additions & 0 deletions markdown/src/test/resources/break-all-the-rules.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,3 +79,11 @@ code fence without language {FencedCodeLanguageRule:73}
markdownLint {ProperNamesRule}

![](image.jpg) {MD045}

- [ ] First task item
- [x] Second item {ListMarkerSpaceRule}
- [X] Third inconsistent item {ConsistentTaskListMarkerStyleRule}

- [x] An item
- [x] Another item {TaskListMarkerSpaceRule}
- [x]Not enough space {TaskListMarkerSpaceRule}
6 changes: 6 additions & 0 deletions markdown/src/test/resources/task-list-marker-large-indent.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Ensure task list is okay

- [ ] First task item
- [x]Second item {TaskListMarkerSpaceRule}
- [x] Third item {TaskListMarkerSpaceRule}
- [ ] Fourth item {TaskListMarkerSpaceRule}
4 changes: 4 additions & 0 deletions markdown/src/test/resources/task-list-marker-no-complete.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Ensure task list is okay

- [ ] First task item
- [ ] Second item
5 changes: 5 additions & 0 deletions markdown/src/test/resources/task-list-marker-uppercase.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Ensure task list is okay

- [ ] First task item
- [x] Second item should be uppercase {ConsistentTaskListMarkerStyleRule}
- [X] Third item is okay
5 changes: 5 additions & 0 deletions markdown/src/test/resources/task-list-marker.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Ensure task list is okay

- [ ] First task item {TaskListMarkerSpaceRule}
- [x]Second item {TaskListMarkerSpaceRule}
- [X] Third inconsistent item {ConsistentTaskListMarkerStyleRule}

0 comments on commit 557ec50

Please sign in to comment.