diff --git a/doc/Rules.md b/doc/Rules.md
index fedfaaf0..42d0ad1c 100644
--- a/doc/Rules.md
+++ b/doc/Rules.md
@@ -190,6 +190,31 @@ for the list to fix it:
* Nested Item 3
```
+Sequentially-ordered list markers are usually left-aligned such that all items
+have the same starting column:
+
+```markdown
+...
+8. Item
+9. Item
+10. Item
+11. Item
+...
+```
+
+This rule also supports right-alignment of list markers such that all items have
+the same ending column:
+
+```markdown
+...
+ 8. Item
+ 9. Item
+10. Item
+11. Item
+...
+```
+
+
## MD006 - Consider starting bulleted lists at the beginning of the line
@@ -850,6 +875,17 @@ Example invalid list for all styles:
3. Done.
```
+This rule supports 0-prefixing ordered list items for uniform indentation:
+
+```markdown
+...
+08. Item
+09. Item
+10. Item
+11. Item
+...
+```
+
## MD030 - Spaces after list markers
diff --git a/lib/md005.js b/lib/md005.js
index 0d1c9cf7..5a220bda 100644
--- a/lib/md005.js
+++ b/lib/md005.js
@@ -10,10 +10,32 @@ module.exports = {
"tags": [ "bullet", "ul", "indentation" ],
"function": function MD005(params, onError) {
shared.flattenLists().forEach(function forList(list) {
+ const expectedIndent = list.indent;
+ let expectedEnd = 0;
+ let actualEnd = -1;
+ let endMatching = false;
list.items.forEach(function forItem(item) {
- shared.addErrorDetailIf(onError, item.lineNumber, list.indent,
- shared.indentFor(item), null,
- shared.rangeFromRegExp(item.line, shared.listItemMarkerRe));
+ const actualIndent = shared.indentFor(item);
+ if (list.unordered) {
+ shared.addErrorDetailIf(onError, item.lineNumber,
+ expectedIndent, actualIndent, null,
+ shared.rangeFromRegExp(item.line, shared.listItemMarkerRe));
+ } else {
+ const match = shared.orderedListItemMarkerRe.exec(item.line);
+ actualEnd = match && match[0].length;
+ expectedEnd = expectedEnd || actualEnd;
+ if ((expectedIndent !== actualIndent) || endMatching) {
+ if (expectedEnd === actualEnd) {
+ endMatching = true;
+ } else {
+ const detail = endMatching ?
+ `Expected: (${expectedEnd}); Actual: (${actualEnd})` :
+ `Expected: ${expectedIndent}; Actual: ${actualIndent}`;
+ shared.addError(onError, item.lineNumber, detail, null,
+ shared.rangeFromRegExp(item.line, shared.listItemMarkerRe));
+ }
+ }
+ }
});
});
}
diff --git a/lib/md029.js b/lib/md029.js
index 2015177b..d0f2d2f9 100644
--- a/lib/md029.js
+++ b/lib/md029.js
@@ -4,8 +4,6 @@
const shared = require("./shared");
-const numberRe = /^[\s>]*([^.)]*)[.)]/;
-
module.exports = {
"names": [ "MD029", "ol-prefix" ],
"description": "Ordered list item prefix",
@@ -17,12 +15,12 @@ module.exports = {
let listStyle = style;
if (listStyle === "one_or_ordered") {
const second = (list.items.length > 1) &&
- numberRe.exec(list.items[1].line);
+ shared.orderedListItemMarkerRe.exec(list.items[1].line);
listStyle = (second && (second[1] !== "1")) ? "ordered" : "one";
}
let number = 1;
list.items.forEach(function forItem(item) {
- const match = numberRe.exec(item.line);
+ const match = shared.orderedListItemMarkerRe.exec(item.line);
shared.addErrorDetailIf(onError, item.lineNumber,
String(number), !match || match[1],
"Style: " + (listStyle === "one" ? "1/1/1" : "1/2/3"),
diff --git a/lib/shared.js b/lib/shared.js
index 6af653ad..cbd5e434 100644
--- a/lib/shared.js
+++ b/lib/shared.js
@@ -17,7 +17,8 @@ module.exports.inlineCommentRe = inlineCommentRe;
// Regular expressions for range matching
module.exports.atxHeadingSpaceRe = /^#+\s*\S/;
module.exports.bareUrlRe = /(?:http|ftp)s?:\/\/[^\s]*/i;
-module.exports.listItemMarkerRe = /^[\s>]*(?:[*+-]|\d+\.)\s+/;
+module.exports.listItemMarkerRe = /^[\s>]*(?:[*+-]|\d+[.)])\s+/;
+module.exports.orderedListItemMarkerRe = /^[\s>]*0*(\d+)[.)]/;
// readFile options for reading with the UTF-8 encoding
module.exports.utf8Encoding = { "encoding": "utf8" };
diff --git a/test/detailed-results-MD001-MD010.md b/test/detailed-results-MD001-MD010.md
index 57781ff7..34bafbdb 100644
--- a/test/detailed-results-MD001-MD010.md
+++ b/test/detailed-results-MD001-MD010.md
@@ -15,3 +15,16 @@
Text
Text text
+
+ 1. One
+ 2. Two
+ 3. Three
+ 4. Four
+5. Five
+ 6. Six
+ 7. Seven
+ 8. Eight
+ 9. Nine
+10. Ten
+ 11. Eleven
+12. Twelve
diff --git a/test/detailed-results-MD001-MD010.results.json b/test/detailed-results-MD001-MD010.results.json
index 9c6918e4..832fd993 100644
--- a/test/detailed-results-MD001-MD010.results.json
+++ b/test/detailed-results-MD001-MD010.results.json
@@ -39,6 +39,22 @@
"errorContext": null,
"errorRange": [1, 3]
},
+ {
+ "lineNumber": 23,
+ "ruleNames": [ "MD005", "list-indent" ],
+ "ruleDescription": "Inconsistent indentation for list items at the same level",
+ "errorDetail": "Expected: 1; Actual: 0",
+ "errorContext": null,
+ "errorRange": [1, 3]
+ },
+ {
+ "lineNumber": 29,
+ "ruleNames": [ "MD005", "list-indent" ],
+ "ruleDescription": "Inconsistent indentation for list items at the same level",
+ "errorDetail": "Expected: (3); Actual: (4)",
+ "errorContext": null,
+ "errorRange": [1, 5]
+ },
{
"lineNumber": 12,
"ruleNames": [ "MD006", "ul-start-left" ],
diff --git a/test/list-item-prefix-alignment.md b/test/list-item-prefix-alignment.md
new file mode 100644
index 00000000..fc6677e8
--- /dev/null
+++ b/test/list-item-prefix-alignment.md
@@ -0,0 +1,96 @@
+# List Alignment
+
+## Leading Spaces
+
+ 1. One
+ 2. Two
+ 3. Three
+ 4. Four
+ 5. Five
+ 6. Six
+ 7. Seven
+ 8. Eight
+ 9. Nine
+10. Ten
+11. Eleven
+12. Twelve
+
+## Leading Zeroes
+
+01. One
+02. Two
+03. Three
+04. Four
+05. Five
+06. Six
+07. Seven
+08. Eight
+09. Nine
+10. Ten
+11. Eleven
+12. Twelve
+
+## Double Leading Zeroes
+
+001. One
+002. Two
+003. Three
+
+## Nested Lists
+
+- Item
+- Item
+ 01. One
+ 02. Two
+ 03. Three
+ 04. Four
+ 05. Five
+ 06. Six
+ 07. Seven
+ 08. Eight
+ 09. Nine
+ 10. Ten
+ 11. Eleven
+ 12. Twelve
+- Item
+- Item
+ 1. One
+ 2. Two
+ 3. Three
+ 4. Four
+ 5. Five
+ 6. Six
+ 7. Seven
+ 8. Eight
+ 9. Nine
+ 10. Ten
+ 11. Eleven
+ 12. Twelve
+- Item
+- Item
+
+## Another Nested List
+
+01. One
+02. Two
+ 01. One
+ 02. Two
+03. Three
+04. Four
+
+## Leading Spaces Errors
+
+ 1. One
+ 2. Two
+ 3. Three
+ 4. Four
+ 5. Five {MD005}
+ 6. Six
+ 7. Seven
+ 8. Eight
+ 9. Nine
+ 10. Ten
+ 11. Eleven {MD005}
+ 12. Twelve
+13. Thirteen {MD005}
+ 14. Fourteen