Skip to content

Commit bce4a90

Browse files
itaisteinherzsindresorhus
authored andcommittedJun 15, 2019
Add awesome/heading rule (#70)
1 parent cf053c4 commit bce4a90

File tree

9 files changed

+121
-0
lines changed

9 files changed

+121
-0
lines changed
 

‎rules/heading.js

+49
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
'use strict';
2+
const rule = require('unified-lint-rule');
3+
const visit = require('unist-util-visit');
4+
const {of: caseOf, title: titleCase} = require('case');
5+
6+
const listHeadingCaseWhitelist = new Set([
7+
'title',
8+
'capital'
9+
]);
10+
11+
module.exports = rule('remark-lint:awesome/heading', (ast, file) => {
12+
let headings = 0;
13+
14+
visit(ast, (node, index) => {
15+
if (node.type !== 'heading') {
16+
return;
17+
}
18+
19+
if (node.depth > 1) {
20+
if (index !== 0) {
21+
return;
22+
}
23+
24+
file.message('Main list heading must be of depth 1', node);
25+
}
26+
27+
for (const child of node.children) {
28+
if (child.type !== 'text') {
29+
continue;
30+
}
31+
32+
const headingText = child.value;
33+
34+
if (!listHeadingCaseWhitelist.has(caseOf(headingText)) && titleCase(headingText) !== headingText) {
35+
file.message('Main heading must be in title case', node);
36+
}
37+
}
38+
39+
headings++;
40+
41+
if (headings > 1) {
42+
file.message('List can only have one heading', node);
43+
}
44+
});
45+
46+
if (headings === 0) {
47+
file.message('Missing main list heading');
48+
}
49+
});

‎rules/index.js

+1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
'use strict';
22

33
module.exports = [
4+
require('./heading'),
45
require('./badge'),
56
require('./contributing'),
67
require('./git-repo-age'),

‎test/fixtures/heading/error0.md

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
> This is an awesome list!

‎test/fixtures/heading/error1.md

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# my-awesome-list
2+
3+
> This is an awesome list!

‎test/fixtures/heading/error2.md

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# Awesome List
2+
3+
# This Is a Really Awesome List

‎test/fixtures/heading/error3.md

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
## Improper Awesome List

‎test/fixtures/heading/success0.md

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# My Awesome List
2+
3+
> This is an awesome list

‎test/fixtures/heading/success1.md

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
# AHA Acronyms Are Allowed

‎test/rules/heading.js

+59
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
import test from 'ava';
2+
import lint from '../_lint';
3+
4+
const config = {
5+
plugins: [
6+
require('remark-lint'),
7+
require('../../rules/heading')
8+
]
9+
};
10+
11+
test('heading - missing', async t => {
12+
const messages = await lint({config, filename: 'test/fixtures/heading/error0.md'});
13+
t.deepEqual(messages, [
14+
{
15+
ruleId: 'awesome/heading',
16+
message: 'Missing main list heading'
17+
}
18+
]);
19+
});
20+
21+
test('heading - not in title case', async t => {
22+
const messages = await lint({config, filename: 'test/fixtures/heading/error1.md'});
23+
t.deepEqual(messages, [
24+
{
25+
ruleId: 'awesome/heading',
26+
message: 'Main heading must be in title case'
27+
}
28+
]);
29+
});
30+
31+
test('heading - more than one heading', async t => {
32+
const messages = await lint({config, filename: 'test/fixtures/heading/error2.md'});
33+
t.deepEqual(messages, [
34+
{
35+
ruleId: 'awesome/heading',
36+
message: 'List can only have one heading'
37+
}
38+
]);
39+
});
40+
41+
test('heading - depth is bigger than 1', async t => {
42+
const messages = await lint({config, filename: 'test/fixtures/heading/error3.md'});
43+
t.deepEqual(messages, [
44+
{
45+
ruleId: 'awesome/heading',
46+
message: 'Main list heading must be of depth 1'
47+
}
48+
]);
49+
});
50+
51+
test('heading - success', async t => {
52+
const messages = await lint({config, filename: 'test/fixtures/heading/success0.md'});
53+
t.deepEqual(messages, []);
54+
});
55+
56+
test('heading - success (with acronyms)', async t => {
57+
const messages = await lint({config, filename: 'test/fixtures/heading/success1.md'});
58+
t.deepEqual(messages, []);
59+
});

0 commit comments

Comments
 (0)
Please sign in to comment.