diff --git a/rules/list-item.js b/rules/list-item.js index 3316572..805c25b 100644 --- a/rules/list-item.js +++ b/rules/list-item.js @@ -102,21 +102,49 @@ function validateList(list, file) { continue; } - const [link, ...description] = paragraph.children; - - if (link.type === 'text') { + if (paragraph.children[0].type === 'text') { continue; } + let [link, ...description] = paragraph.children; + + // Might have children like: '{image} {text} {link} { - description}' + // Keep discarding prefix elements until we find something link-like. + while (link.type !== 'linkReference' && link.type !== 'link' && description.length > 1) { + link = description[0]; + description = description.slice(1); + } + if (!validateListItemLink(link, file)) { continue; } + if (!validateListItemLinkChildren(link, file)) { + continue; + } + validateListItemDescription(description, file); } } +function validateListItemLinkChildren(link, file) { + for (const node of link.children) { + if (!listItemLinkNodeAllowList.has(node.type)) { + file.message('Invalid list item link', node); + return false; + } + } + + return true; +} + function validateListItemLink(link, file) { + // NB. We need remark-lint-no-undefined-references separately + // to catch if this is a valid reference. Here we only care that it exists. + if (link.type === 'linkReference') { + return true; + } + if (link.type !== 'link') { file.message('Invalid list item link', link); return false; @@ -133,13 +161,6 @@ function validateListItemLink(link, file) { return false; } - for (const node of link.children) { - if (!listItemLinkNodeAllowList.has(node.type)) { - file.message('Invalid list item link', node); - return false; - } - } - return true; } @@ -168,11 +189,18 @@ function validateListItemDescription(description, file) { return false; } - if (/^\s*β€”/.test(prefixText)) { - file.message('List item link and description separated by invalid en-dash', prefix); + // Some editors auto-correct ' - ' to – (en-dash). Also avoid β€” (em-dash). + if (/^\s*[/\u{02013}\u{02014}]/u.test(prefixText)) { + file.message('List item link and description separated by invalid en-dash or em-dash', prefix); return false; } + // Might have image and link on left side before description. + // Assume a hyphen with spaces in the description is good enough. + if (/ - [A-Z]/.test(descriptionText)) { + return true; + } + file.message('List item link and description must be separated with a dash', prefix); return false; } diff --git a/test/fixtures/list-item/0.md b/test/fixtures/list-item/0.md index aa5ed77..a68d494 100644 --- a/test/fixtures/list-item/0.md +++ b/test/fixtures/list-item/0.md @@ -24,7 +24,9 @@ All list-items in this document should be linted as **valid**. - [foo](https://foo.com) - Valid sub-item. - [foo](https://foo.com) - Valid sub-item. - [foo](https://foo.com) - Valid sub-sub-item!!!!! -- [foo](https://foo.com) - GitHub's descriptions can also be valid. +- [foo](https://foo.com) - GitHub's descriptions can also be valid. +- [foo-bar](https://foo-bar.com) - Valid description. +- πŸ‘ [foo](https://foo-bar.com) - Valid description. ## Tutorials @@ -133,9 +135,17 @@ These sub-lists use mixed indentation (spaces and tabs). - [why-is-node-running](https://github.com/mafintosh/why-is-node-running) - Node.js is running but you don't know why? - + +[gtkada]: https://github.com/AdaCore/gtkada +[exampleref]: https://example.com diff --git a/test/fixtures/list-item/1.md b/test/fixtures/list-item/1.md index fbc00b8..48ded26 100644 --- a/test/fixtures/list-item/1.md +++ b/test/fixtures/list-item/1.md @@ -70,3 +70,7 @@ Test description's ending punctuation. - [foo](https://foo.com) - Quote-inducing double punctuation β€œend…”??! - [foo](https://foo.com) - Quote-inducing double punctuation β€œend?…...”…...? +- [gtkada] - Reference link with no reference. +- [*example* ![img](https://image.img)][exampleref] - Another linkref but with a bad child. + +[exampleref]: https://ref.com diff --git a/test/rules/snapshots/list-item.js.md b/test/rules/snapshots/list-item.js.md index fa75ba2..35b3d74 100644 --- a/test/rules/snapshots/list-item.js.md +++ b/test/rules/snapshots/list-item.js.md @@ -46,7 +46,7 @@ Generated by [AVA](https://avajs.dev). }, { line: 13, - message: 'List item link and description separated by invalid en-dash', + message: 'List item link and description separated by invalid en-dash or em-dash', ruleId: 'awesome-list-item', }, { @@ -279,6 +279,11 @@ Generated by [AVA](https://avajs.dev). message: 'List item description must end with proper punctuation', ruleId: 'awesome-list-item', }, + { + line: 74, + message: 'Invalid list item link', + ruleId: 'awesome-list-item', + }, ] ## list-item - invalid sublist punctuation diff --git a/test/rules/snapshots/list-item.js.snap b/test/rules/snapshots/list-item.js.snap index 3d2b7ba..021af8e 100644 Binary files a/test/rules/snapshots/list-item.js.snap and b/test/rules/snapshots/list-item.js.snap differ