diff --git a/doc/rules.md b/doc/rules.md index f8ac9b1..dea5987 100644 --- a/doc/rules.md +++ b/doc/rules.md @@ -2,7 +2,7 @@ # List of Rules -This document describes all (57) +This document describes all (58) available rules, what they check for, examples of what they warn for, and how to fix their warnings. @@ -108,6 +108,7 @@ For example, as follows: - [no-literal-urls](#no-literal-urls) - [no-missing-blank-lines](#no-missing-blank-lines) - [no-multiple-toplevel-headings](#no-multiple-toplevel-headings) +- [no-reference-like-url](#no-reference-like-url) - [no-shell-dollars](#no-shell-dollars) - [no-shortcut-reference-image](#no-shortcut-reference-image) - [no-shortcut-reference-link](#no-shortcut-reference-link) @@ -1906,6 +1907,32 @@ When this rule is `1`, the following file 3:1-3:6: Don’t use multiple top level headings (3:1) ``` +## `no-reference-like-url` + +Warn when URLs are also defined identifiers. + +When this rule is turned on, the following file +`valid.md` is ok: + +```markdown +[Alpha](http://example.com). + +[bravo]: https://example.com +``` + +When this rule is turned on, the following file +`invalid.md` is **not** ok: + +```markdown +[Charlie](delta). + +[delta]: https://example.com +``` + +```text +1:1-1:17: Did you mean to use `[delta]` instead of `(delta)`, a reference? +``` + ## `no-shell-dollars` Warn when shell code is prefixed by dollar-characters. diff --git a/packages/remark-lint/lib/rules.js b/packages/remark-lint/lib/rules.js index dd4d986..217995b 100644 --- a/packages/remark-lint/lib/rules.js +++ b/packages/remark-lint/lib/rules.js @@ -43,6 +43,7 @@ module.exports = { 'no-literal-urls': require('./rules/no-literal-urls.js'), 'no-missing-blank-lines': require('./rules/no-missing-blank-lines.js'), 'no-multiple-toplevel-headings': require('./rules/no-multiple-toplevel-headings.js'), + 'no-reference-like-url': require('./rules/no-reference-like-url.js'), 'no-shell-dollars': require('./rules/no-shell-dollars.js'), 'no-shortcut-reference-image': require('./rules/no-shortcut-reference-image.js'), 'no-shortcut-reference-link': require('./rules/no-shortcut-reference-link.js'), diff --git a/packages/remark-lint/lib/rules/no-reference-like-url.js b/packages/remark-lint/lib/rules/no-reference-like-url.js new file mode 100644 index 0000000..6dc3ed6 --- /dev/null +++ b/packages/remark-lint/lib/rules/no-reference-like-url.js @@ -0,0 +1,70 @@ +/** + * @author Titus Wormer + * @copyright 2016 Titus Wormer + * @license MIT + * @module no-reference-like-url + * @fileoverview + * Warn when URLs are also defined identifiers. + * + * @example {"name": "valid.md"} + * + * [Alpha](http://example.com). + * + * [bravo]: https://example.com + * + * @example {"name": "invalid.md", "label": "input"} + * + * [Charlie](delta). + * + * [delta]: https://example.com + * + * @example {"name": "invalid.md", "label": "output"} + * + * 1:1-1:17: Did you mean to use `[delta]` instead of `(delta)`, a reference? + */ + +'use strict'; + +/* Dependencies. */ +var position = require('unist-util-position'); +var visit = require('unist-util-visit'); + +/* Expose. */ +module.exports = noReferenceLikeURL; + +/** + * Warn when unused definitions are found. + * + * @param {Node} ast - Root node. + * @param {File} file - Virtual file. + */ +function noReferenceLikeURL(tree, file) { + var identifiers = []; + + visit(tree, 'definition', find); + + visit(tree, 'image', check); + visit(tree, 'link', check); + + return; + + /* Find identifiers. */ + function find(node) { + if (!position.generated(node)) { + identifiers.push(node.identifier.toLowerCase()); + } + } + + /* Check `node`. */ + function check(node) { + var url = node.url; + + if (identifiers.indexOf(url.toLowerCase()) !== -1) { + file.message( + 'Did you mean to use `[' + url + ']` instead of ' + + '`(' + url + ')`, a reference?', + node + ); + } + } +}