Skip to content

Commit cb5a956

Browse files
authored
feat: add no-empty-definitions rule (#364)
* feat: add no-empty-definitions rule * add test
1 parent f2314eb commit cb5a956

File tree

4 files changed

+170
-0
lines changed

4 files changed

+170
-0
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ export default defineConfig([
7676
| [`fenced-code-language`](./docs/rules/fenced-code-language.md) | Require languages for fenced code blocks | yes |
7777
| [`heading-increment`](./docs/rules/heading-increment.md) | Enforce heading levels increment by one | yes |
7878
| [`no-duplicate-headings`](./docs/rules/no-duplicate-headings.md) | Disallow duplicate headings in the same document | no |
79+
| [`no-empty-definitions`](./docs/rules/no-empty-definitions.md) | Disallow empty definitions | yes |
7980
| [`no-empty-images`](./docs/rules/no-empty-images.md) | Disallow empty images | yes |
8081
| [`no-empty-links`](./docs/rules/no-empty-links.md) | Disallow empty links | yes |
8182
| [`no-html`](./docs/rules/no-html.md) | Disallow HTML tags | no |

docs/rules/no-empty-definitions.md

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
# no-empty-definitions
2+
3+
Disallow empty definitions.
4+
5+
## Background
6+
7+
Markdown allows you to specify a label as a placeholder for a URL in both links and images using square brackets, such as:
8+
9+
```markdown
10+
[ESLint][eslint]
11+
12+
[eslint]: https://eslint.org
13+
```
14+
15+
If the definition's URL is empty or only contains an empty fragment (`#`), then it's not providing any useful information and could be a mistake.
16+
17+
## Rule Details
18+
19+
This rule warns when it finds definitions where the URL is either not specified or contains only an empty fragment (`#`).
20+
21+
Examples of incorrect code:
22+
23+
```markdown
24+
[earth]: <>
25+
[earth]: #
26+
```
27+
28+
Examples of correct code:
29+
30+
```markdown
31+
[earth]: https://example.com/earth/
32+
[earth]: #section
33+
```
34+
35+
## When Not to Use It
36+
37+
If you aren't concerned with empty definitions, you can safely disable this rule.
38+
39+
## Prior Art
40+
41+
* [remark-lint-no-empty-url](https://github.com/remarkjs/remark-lint/tree/main/packages/remark-lint-no-empty-url)

src/rules/no-empty-definitions.js

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
/**
2+
* @fileoverview Rule to prevent empty definitions in Markdown.
3+
* @author Pixel998
4+
*/
5+
6+
//-----------------------------------------------------------------------------
7+
// Type Definitions
8+
//-----------------------------------------------------------------------------
9+
10+
/**
11+
* @typedef {import("../types.ts").MarkdownRuleDefinition<{ RuleOptions: []; }>}
12+
* NoEmptyDefinitionsRuleDefinition
13+
*/
14+
15+
//-----------------------------------------------------------------------------
16+
// Rule Definition
17+
//-----------------------------------------------------------------------------
18+
19+
/** @type {NoEmptyDefinitionsRuleDefinition} */
20+
export default {
21+
meta: {
22+
type: "problem",
23+
24+
docs: {
25+
recommended: true,
26+
description: "Disallow empty definitions",
27+
url: "https://github.com/eslint/markdown/blob/main/docs/rules/no-empty-definitions.md",
28+
},
29+
30+
messages: {
31+
emptyDefinition: "Unexpected empty definition found.",
32+
},
33+
},
34+
35+
create(context) {
36+
return {
37+
definition(node) {
38+
if (!node.url || node.url === "#") {
39+
context.report({
40+
loc: node.position,
41+
messageId: "emptyDefinition",
42+
});
43+
}
44+
},
45+
};
46+
},
47+
};
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
/**
2+
* @fileoverview Tests for no-empty-definitions rule.
3+
* @author Pixel998
4+
*/
5+
6+
//------------------------------------------------------------------------------
7+
// Imports
8+
//------------------------------------------------------------------------------
9+
10+
import rule from "../../src/rules/no-empty-definitions.js";
11+
import markdown from "../../src/index.js";
12+
import { RuleTester } from "eslint";
13+
import dedent from "dedent";
14+
15+
//------------------------------------------------------------------------------
16+
// Tests
17+
//------------------------------------------------------------------------------
18+
19+
const ruleTester = new RuleTester({
20+
plugins: {
21+
markdown,
22+
},
23+
language: "markdown/commonmark",
24+
});
25+
26+
ruleTester.run("no-empty-definitions", rule, {
27+
valid: [
28+
"[foo]: bar",
29+
"[foo]: #bar",
30+
"[foo]: http://bar.com",
31+
"[foo]: <https://bar.com>",
32+
],
33+
invalid: [
34+
{
35+
code: "[foo]: #",
36+
errors: [
37+
{
38+
messageId: "emptyDefinition",
39+
line: 1,
40+
column: 1,
41+
endLine: 1,
42+
endColumn: 9,
43+
},
44+
],
45+
},
46+
{
47+
code: "[foo]: <>",
48+
errors: [
49+
{
50+
messageId: "emptyDefinition",
51+
line: 1,
52+
column: 1,
53+
endLine: 1,
54+
endColumn: 10,
55+
},
56+
],
57+
},
58+
{
59+
code: dedent`
60+
[foo]: #
61+
[bar]: <>
62+
`,
63+
errors: [
64+
{
65+
messageId: "emptyDefinition",
66+
line: 1,
67+
column: 1,
68+
endLine: 1,
69+
endColumn: 9,
70+
},
71+
{
72+
messageId: "emptyDefinition",
73+
line: 2,
74+
column: 1,
75+
endLine: 2,
76+
endColumn: 10,
77+
},
78+
],
79+
},
80+
],
81+
});

0 commit comments

Comments
 (0)