Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 72496eb

Browse files
committedJan 27, 2019
feat: create header-case rule
1 parent e68e8b2 commit 72496eb

File tree

3 files changed

+379
-0
lines changed

3 files changed

+379
-0
lines changed
 

‎@commitlint/rules/src/header-case.js

+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import * as ensure from '@commitlint/ensure';
2+
import message from '@commitlint/message';
3+
4+
const negated = when => when === 'never';
5+
6+
export default (parsed, when, value) => {
7+
const {header} = parsed;
8+
9+
if (typeof header !== 'string' || !header.match(/^[a-z]/i)) {
10+
return [true];
11+
}
12+
13+
const checks = (Array.isArray(value) ? value : [value]).map(check => {
14+
if (typeof check === 'string') {
15+
return {
16+
when: 'always',
17+
case: check
18+
};
19+
}
20+
return check;
21+
});
22+
23+
const result = checks.some(check => {
24+
const r = ensure.case(header, check.case);
25+
return negated(check.when) ? !r : r;
26+
});
27+
28+
const list = checks.map(c => c.case).join(', ');
29+
30+
return [
31+
negated(when) ? !result : result,
32+
message([`header must`, negated(when) ? `not` : null, `be ${list}`])
33+
];
34+
};
+344
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,344 @@
1+
import test from 'ava';
2+
import parse from '@commitlint/parse';
3+
import headerCase from './header-case';
4+
5+
const messages = {
6+
empty: '\n',
7+
numeric: '1.0.0',
8+
lowercase: 'header test',
9+
mixedcase: 'hEaDeR tEsT',
10+
uppercase: 'HEADER TEST',
11+
camelcase: 'heaDer teSt',
12+
kebabcase: 'hea-der te-st',
13+
pascalcase: 'HeaDer TeSt',
14+
snakecase: 'hea_der te_st',
15+
startcase: 'Hea Der Te St'
16+
};
17+
18+
const parsed = {
19+
empty: parse(messages.empty),
20+
numeric: parse(messages.numeric),
21+
lowercase: parse(messages.lowercase),
22+
mixedcase: parse(messages.mixedcase),
23+
uppercase: parse(messages.uppercase),
24+
camelcase: parse(messages.camelcase),
25+
kebabcase: parse(messages.kebabcase),
26+
pascalcase: parse(messages.pascalcase),
27+
snakecase: parse(messages.snakecase),
28+
startcase: parse(messages.startcase)
29+
};
30+
31+
test('with empty header should succeed for "never lowercase"', async t => {
32+
const [actual] = headerCase(await parsed.empty, 'never', 'lowercase');
33+
const expected = true;
34+
t.is(actual, expected);
35+
});
36+
37+
test('with empty header should succeed for "always lowercase"', async t => {
38+
const [actual] = headerCase(await parsed.empty, 'always', 'lowercase');
39+
const expected = true;
40+
t.is(actual, expected);
41+
});
42+
43+
test('with empty header should succeed for "never uppercase"', async t => {
44+
const [actual] = headerCase(await parsed.empty, 'never', 'uppercase');
45+
const expected = true;
46+
t.is(actual, expected);
47+
});
48+
49+
test('with empty header should succeed for "always uppercase"', async t => {
50+
const [actual] = headerCase(await parsed.empty, 'always', 'uppercase');
51+
const expected = true;
52+
t.is(actual, expected);
53+
});
54+
55+
test('with lowercase header should fail for "never lowercase"', async t => {
56+
const [actual] = headerCase(await parsed.lowercase, 'never', 'lowercase');
57+
const expected = false;
58+
t.is(actual, expected);
59+
});
60+
61+
test('with lowercase header should succeed for "always lowercase"', async t => {
62+
const [actual] = headerCase(await parsed.lowercase, 'always', 'lowercase');
63+
const expected = true;
64+
t.is(actual, expected);
65+
});
66+
67+
test('with mixedcase header should succeed for "never lowercase"', async t => {
68+
const [actual] = headerCase(await parsed.mixedcase, 'never', 'lowercase');
69+
const expected = true;
70+
t.is(actual, expected);
71+
});
72+
73+
test('with mixedcase header should fail for "always lowercase"', async t => {
74+
const [actual] = headerCase(await parsed.mixedcase, 'always', 'lowercase');
75+
const expected = false;
76+
t.is(actual, expected);
77+
});
78+
79+
test('with mixedcase header should succeed for "never uppercase"', async t => {
80+
const [actual] = headerCase(await parsed.mixedcase, 'never', 'uppercase');
81+
const expected = true;
82+
t.is(actual, expected);
83+
});
84+
85+
test('with mixedcase header should fail for "always uppercase"', async t => {
86+
const [actual] = headerCase(await parsed.mixedcase, 'always', 'uppercase');
87+
const expected = false;
88+
t.is(actual, expected);
89+
});
90+
91+
test('with uppercase header should fail for "never uppercase"', async t => {
92+
const [actual] = headerCase(await parsed.uppercase, 'never', 'uppercase');
93+
const expected = false;
94+
t.is(actual, expected);
95+
});
96+
97+
test('with lowercase header should succeed for "always uppercase"', async t => {
98+
const [actual] = headerCase(await parsed.uppercase, 'always', 'uppercase');
99+
const expected = true;
100+
t.is(actual, expected);
101+
});
102+
103+
test('with camelcase header should fail for "always uppercase"', async t => {
104+
const [actual] = headerCase(await parsed.camelcase, 'always', 'uppercase');
105+
const expected = false;
106+
t.is(actual, expected);
107+
});
108+
109+
test('with camelcase header should succeed for "never uppercase"', async t => {
110+
const [actual] = headerCase(await parsed.camelcase, 'never', 'uppercase');
111+
const expected = true;
112+
t.is(actual, expected);
113+
});
114+
115+
test('with camelcase header should fail for "always pascalcase"', async t => {
116+
const [actual] = headerCase(await parsed.camelcase, 'always', 'pascal-case');
117+
const expected = false;
118+
t.is(actual, expected);
119+
});
120+
121+
test('with camelcase header should fail for "always kebabcase"', async t => {
122+
const [actual] = headerCase(await parsed.camelcase, 'always', 'kebab-case');
123+
const expected = false;
124+
t.is(actual, expected);
125+
});
126+
127+
test('with camelcase header should fail for "always snakecase"', async t => {
128+
const [actual] = headerCase(await parsed.camelcase, 'always', 'snake-case');
129+
const expected = false;
130+
t.is(actual, expected);
131+
});
132+
133+
test('with camelcase header should succeed for "always camelcase"', async t => {
134+
const [actual] = headerCase(await parsed.camelcase, 'always', 'camel-case');
135+
const expected = true;
136+
t.is(actual, expected);
137+
});
138+
139+
test('with pascalcase header should fail for "always uppercase"', async t => {
140+
const [actual] = headerCase(await parsed.pascalcase, 'always', 'uppercase');
141+
const expected = false;
142+
t.is(actual, expected);
143+
});
144+
145+
test('with pascalcase header should succeed for "never uppercase"', async t => {
146+
const [actual] = headerCase(await parsed.pascalcase, 'never', 'uppercase');
147+
const expected = true;
148+
t.is(actual, expected);
149+
});
150+
151+
test('with pascalcase header should succeed for "always pascalcase"', async t => {
152+
const [actual] = headerCase(await parsed.pascalcase, 'always', 'pascal-case');
153+
const expected = true;
154+
t.is(actual, expected);
155+
});
156+
157+
test('with pascalcase header should fail for "always kebabcase"', async t => {
158+
const [actual] = headerCase(await parsed.pascalcase, 'always', 'kebab-case');
159+
const expected = false;
160+
t.is(actual, expected);
161+
});
162+
163+
test('with pascalcase header should fail for "always snakecase"', async t => {
164+
const [actual] = headerCase(await parsed.pascalcase, 'always', 'snake-case');
165+
const expected = false;
166+
t.is(actual, expected);
167+
});
168+
169+
test('with pascalcase header should fail for "always camelcase"', async t => {
170+
const [actual] = headerCase(await parsed.pascalcase, 'always', 'camel-case');
171+
const expected = false;
172+
t.is(actual, expected);
173+
});
174+
175+
test('with snakecase header should fail for "always uppercase"', async t => {
176+
const [actual] = headerCase(await parsed.snakecase, 'always', 'uppercase');
177+
const expected = false;
178+
t.is(actual, expected);
179+
});
180+
181+
test('with snakecase header should succeed for "never uppercase"', async t => {
182+
const [actual] = headerCase(await parsed.snakecase, 'never', 'uppercase');
183+
const expected = true;
184+
t.is(actual, expected);
185+
});
186+
187+
test('with snakecase header should fail for "always pascalcase"', async t => {
188+
const [actual] = headerCase(await parsed.snakecase, 'always', 'pascal-case');
189+
const expected = false;
190+
t.is(actual, expected);
191+
});
192+
193+
test('with snakecase header should fail for "always kebabcase"', async t => {
194+
const [actual] = headerCase(await parsed.snakecase, 'always', 'kebab-case');
195+
const expected = false;
196+
t.is(actual, expected);
197+
});
198+
199+
test('with snakecase header should succeed for "always snakecase"', async t => {
200+
const [actual] = headerCase(await parsed.snakecase, 'always', 'snake-case');
201+
const expected = true;
202+
t.is(actual, expected);
203+
});
204+
205+
test('with snakecase header should fail for "always camelcase"', async t => {
206+
const [actual] = headerCase(await parsed.snakecase, 'always', 'camel-case');
207+
const expected = false;
208+
t.is(actual, expected);
209+
});
210+
211+
test('with startcase header should fail for "always uppercase"', async t => {
212+
const [actual] = headerCase(await parsed.startcase, 'always', 'uppercase');
213+
const expected = false;
214+
t.is(actual, expected);
215+
});
216+
217+
test('with startcase header should succeed for "never uppercase"', async t => {
218+
const [actual] = headerCase(await parsed.startcase, 'never', 'uppercase');
219+
const expected = true;
220+
t.is(actual, expected);
221+
});
222+
223+
test('with startcase header should fail for "always pascalcase"', async t => {
224+
const [actual] = headerCase(await parsed.startcase, 'always', 'pascal-case');
225+
const expected = false;
226+
t.is(actual, expected);
227+
});
228+
229+
test('with startcase header should fail for "always kebabcase"', async t => {
230+
const [actual] = headerCase(await parsed.startcase, 'always', 'kebab-case');
231+
const expected = false;
232+
t.is(actual, expected);
233+
});
234+
235+
test('with startcase header should fail for "always snakecase"', async t => {
236+
const [actual] = headerCase(await parsed.startcase, 'always', 'snake-case');
237+
const expected = false;
238+
t.is(actual, expected);
239+
});
240+
241+
test('with startcase header should fail for "always camelcase"', async t => {
242+
const [actual] = headerCase(await parsed.startcase, 'always', 'camel-case');
243+
const expected = false;
244+
t.is(actual, expected);
245+
});
246+
247+
test('with startcase header should succeed for "always startcase"', async t => {
248+
const [actual] = headerCase(await parsed.startcase, 'always', 'start-case');
249+
const expected = true;
250+
t.is(actual, expected);
251+
});
252+
253+
test('should use expected message with "always"', async t => {
254+
const [, message] = headerCase(
255+
await parsed.uppercase,
256+
'always',
257+
'lower-case'
258+
);
259+
t.true(message.indexOf('must be lower-case') > -1);
260+
});
261+
262+
test('should use expected message with "never"', async t => {
263+
const [, message] = headerCase(await parsed.uppercase, 'never', 'upper-case');
264+
t.true(message.indexOf('must not be upper-case') > -1);
265+
});
266+
267+
test('with uppercase scope should succeed for "always [uppercase, lowercase]"', async t => {
268+
const [actual] = headerCase(await parsed.uppercase, 'always', [
269+
'uppercase',
270+
'lowercase'
271+
]);
272+
const expected = true;
273+
t.is(actual, expected);
274+
});
275+
276+
test('with lowercase header should succeed for "always [uppercase, lowercase]"', async t => {
277+
const [actual] = headerCase(await parsed.lowercase, 'always', [
278+
'uppercase',
279+
'lowercase'
280+
]);
281+
const expected = true;
282+
t.is(actual, expected);
283+
});
284+
285+
test('with mixedcase header should fail for "always [uppercase, lowercase]"', async t => {
286+
const [actual] = headerCase(await parsed.mixedcase, 'always', [
287+
'uppercase',
288+
'lowercase'
289+
]);
290+
const expected = false;
291+
t.is(actual, expected);
292+
});
293+
294+
test('with mixedcase header should pass for "always [uppercase, lowercase, camel-case]"', async t => {
295+
const [actual] = headerCase(await parsed.mixedcase, 'always', [
296+
'uppercase',
297+
'lowercase',
298+
'camel-case'
299+
]);
300+
const expected = true;
301+
t.is(actual, expected);
302+
});
303+
304+
test('with mixedcase scope should pass for "never [uppercase, lowercase]"', async t => {
305+
const [actual] = headerCase(await parsed.mixedcase, 'never', [
306+
'uppercase',
307+
'lowercase'
308+
]);
309+
const expected = true;
310+
t.is(actual, expected);
311+
});
312+
313+
test('with uppercase scope should fail for "never [uppercase, lowercase]"', async t => {
314+
const [actual] = headerCase(await parsed.uppercase, 'never', [
315+
'uppercase',
316+
'lowercase'
317+
]);
318+
const expected = false;
319+
t.is(actual, expected);
320+
});
321+
322+
test('with numeric header should succeed for "never lowercase"', async t => {
323+
const [actual] = headerCase(await parsed.numeric, 'never', 'lowercase');
324+
const expected = true;
325+
t.is(actual, expected);
326+
});
327+
328+
test('with numeric header should succeed for "always lowercase"', async t => {
329+
const [actual] = headerCase(await parsed.numeric, 'always', 'lowercase');
330+
const expected = true;
331+
t.is(actual, expected);
332+
});
333+
334+
test('with numeric header should succeed for "never uppercase"', async t => {
335+
const [actual] = headerCase(await parsed.numeric, 'never', 'uppercase');
336+
const expected = true;
337+
t.is(actual, expected);
338+
});
339+
340+
test('with numeric header should succeed for "always uppercase"', async t => {
341+
const [actual] = headerCase(await parsed.numeric, 'always', 'uppercase');
342+
const expected = true;
343+
t.is(actual, expected);
344+
});

‎@commitlint/rules/src/index.js

+1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ export default {
1010
'footer-max-length': require('./footer-max-length'),
1111
'footer-max-line-length': require('./footer-max-line-length'),
1212
'footer-min-length': require('./footer-min-length'),
13+
'header-case': require('./header-case'),
1314
'header-full-stop': require('./header-full-stop'),
1415
'header-max-length': require('./header-max-length'),
1516
'header-min-length': require('./header-min-length'),

0 commit comments

Comments
 (0)
Please sign in to comment.