Add no-unused-definitions rule

This new rule detects unused definitions and warns when they’re found.

Closes GH-34.
This commit is contained in:
Titus Wormer 2016-01-09 21:55:12 +01:00
parent 43042ea6e7
commit bde77abca6
6 changed files with 125 additions and 1 deletions

View File

@ -59,6 +59,7 @@ See the readme for a [list of external rules](https://github.com/wooorm/remark-l
* [no-shortcut-reference-link](#no-shortcut-reference-link)
* [no-table-indentation](#no-table-indentation)
* [no-tabs](#no-tabs)
* [no-unused-definitions](#no-unused-definitions)
* [ordered-list-marker-style](#ordered-list-marker-style)
* [ordered-list-marker-value](#ordered-list-marker-value)
* [rule-style](#rule-style)
@ -1054,6 +1055,20 @@ Options: `boolean`, default: `false`.
Warn when hard-tabs instead of spaces
### no-unused-definitions
```md
<!-- Valid: -->
[foo][]
[foo]: https://example.com
<!-- Invalid: -->
[bar]: https://example.com
```
Warn when unused definitions are found.
### ordered-list-marker-style
```md

View File

@ -69,5 +69,6 @@ module.exports = {
'table-cell-padding': require('./table-cell-padding'),
'table-pipes': require('./table-pipes'),
'no-tabs': require('./no-tabs'),
'unordered-list-marker-style': require('./unordered-list-marker-style')
'unordered-list-marker-style': require('./unordered-list-marker-style'),
'no-unused-definitions': require('./no-unused-definitions.js')
};

View File

@ -0,0 +1,94 @@
/**
* @author Titus Wormer
* @copyright 2016 Titus Wormer
* @license MIT
* @module no-unused-definitions
* @fileoverview
* Warn when unused definitions are found.
* @example
* <!-- Valid: -->
* [foo][]
*
* [foo]: https://example.com
*
* <!-- Invalid: -->
* [bar]: https://example.com
*/
'use strict';
/* eslint-env commonjs */
/*
* Dependencies.
*/
var position = require('mdast-util-position');
var visit = require('unist-util-visit');
/**
* Warn when definitions with equal content are found.
*
* Matches case-insensitive.
*
* @param {Node} ast - Root node.
* @param {File} file - Virtual file.
* @param {*} preferred - Ignored.
* @param {Function} done - Callback.
*/
function noUnusedDefinitions(ast, file, preferred, done) {
var map = {};
var identifier;
/**
* Check `node`.
*
* @param {Node} node - Node.
*/
function find(node) {
if (position.generated(node)) {
return;
}
map[node.identifier.toUpperCase()] = {
'node': node,
'used': false
};
}
/**
* Mark `node`.
*
* @param {Node} node - Node.
*/
function mark(node) {
var info = map[node.identifier.toUpperCase()];
if (position.generated(node) || !info) {
return;
}
info.used = true;
}
visit(ast, 'definition', find);
visit(ast, 'footnoteDefinition', find);
visit(ast, 'imageReference', mark);
visit(ast, 'linkReference', mark);
visit(ast, 'footnoteReference', mark);
for (identifier in map) {
if (!map[identifier].used) {
file.warn('Found unused definition', map[identifier].node);
}
}
done();
}
/*
* Expose.
*/
module.exports = noUnusedDefinitions;

View File

@ -0,0 +1 @@
[bar]: https://example.com

View File

@ -0,0 +1,3 @@
[foo][]
[foo]: https://example.com

View File

@ -1733,6 +1733,16 @@ describe('Rules', function () {
});
});
describeRule('no-unused-definitions', function () {
describeSetting(true, function () {
assertFile('no-unused-definitions-invalid.md', [
'no-unused-definitions-invalid.md:1:1-1:27: Found unused definition'
]);
assertFile('no-unused-definitions-valid.md', []);
});
});
describeRule('fenced-code-marker', function () {
describeSetting(true, function () {
assertFile('fenced-code-marker-tick.md', []);