Skip to content

Commit e75ce8d

Browse files
committed
refactor(prompt): refactor prompt cli to use utils
1 parent a7883ef commit e75ce8d

13 files changed

+397
-193
lines changed

@commitlint/prompt/src/index.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ type Commit = (input: string) => void;
1111
* @param commit callback to execute with complete commit message
1212
* @return generated commit message
1313
*/
14-
export const prompter = async (_: unknown, commit: Commit): Promise<void> => {
14+
export async function prompter(_: unknown, commit: Commit): Promise<void> {
1515
const message = await input(vorpal);
1616
commit(message);
17-
};
17+
}

@commitlint/prompt/src/input.ts

+14-44
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,10 @@ import load from '@commitlint/load';
22
import throat from 'throat';
33

44
import format from './library/format';
5-
import getHasName from './library/get-has-name';
65
import getPrompt from './library/get-prompt';
76
import settings from './settings';
8-
import {InputSetting, Prompter, Result, RuleEntry} from './library/types';
9-
import {QualifiedRules} from '@commitlint/types';
7+
import {InputSetting, Prompter, Result} from './library/types';
8+
import {getHasName, getMaxLength, getRules} from './library/utils';
109

1110
export default input;
1211

@@ -26,30 +25,24 @@ async function input(prompter: () => Prompter): Promise<string> {
2625
};
2726

2827
const {rules} = await load();
28+
const parts = ['type', 'scope', 'subject', 'body', 'footer'] as const;
29+
const headerParts = ['type', 'scope', 'subject'];
30+
31+
const headerLengthRule = getRules('header', rules).find(
32+
getHasName('max-length')
33+
);
34+
const maxLength = getMaxLength(headerLengthRule);
2935

3036
await Promise.all(
31-
(['type', 'scope', 'subject', 'body', 'footer'] as const).map(
37+
parts.map(
3238
throat(1, async (input) => {
3339
const inputRules = getRules(input, rules);
3440
const inputSettings: InputSetting = settings[input];
3541

36-
const isHeader = ['type', 'scope', 'subject'].indexOf(input) > -1;
37-
38-
const headerLengthRule = getRules('header', rules).find(
39-
getHasName('max-length')
40-
);
41-
42-
if (isHeader && headerLengthRule) {
43-
const [, [severity, applicable, length]] = headerLengthRule;
44-
if (
45-
severity > 0 &&
46-
applicable === 'always' &&
47-
typeof length === 'number'
48-
) {
49-
inputSettings.header = {
50-
length,
51-
};
52-
}
42+
if (headerParts.includes(input) && maxLength < Infinity) {
43+
inputSettings.header = {
44+
length: maxLength,
45+
};
5346
}
5447

5548
results[input] = await getPrompt(input, {
@@ -68,26 +61,3 @@ async function input(prompter: () => Prompter): Promise<string> {
6861
// Return the results
6962
return format(results);
7063
}
71-
72-
/**
73-
* Get prefix for a given rule id
74-
* @param id of the rule
75-
* @return prefix of the rule
76-
*/
77-
function getRulePrefix(id: string) {
78-
const fragments = id.split('-');
79-
const [prefix] = fragments;
80-
return fragments.length > 1 ? prefix : null;
81-
}
82-
83-
/**
84-
* Get rules for a given prefix
85-
* @param prefix to search in rule names
86-
* @param rules rules to search in
87-
* @return rules matching the prefix search
88-
*/
89-
function getRules(prefix: string, rules: QualifiedRules) {
90-
return Object.entries(rules).filter(
91-
(rule): rule is RuleEntry => getRulePrefix(rule[0]) === prefix
92-
);
93-
}

@commitlint/prompt/src/library/enum-rule-is-active.ts

-20
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
import {RuleConfigSeverity} from '@commitlint/types';
2+
3+
import getForcedCaseFn from './get-forced-case-fn';
4+
5+
test('should not apply', () => {
6+
let rule = getForcedCaseFn(['name', [RuleConfigSeverity.Disabled]]);
7+
expect(rule('test')).toBe('test');
8+
expect(rule('test-foo')).toBe('test-foo');
9+
expect(rule('testFoo')).toBe('testFoo');
10+
expect(rule('TEST_FOO')).toBe('TEST_FOO');
11+
12+
rule = getForcedCaseFn();
13+
expect(rule('test')).toBe('test');
14+
expect(rule('test-foo')).toBe('test-foo');
15+
expect(rule('testFoo')).toBe('testFoo');
16+
expect(rule('TEST_FOO')).toBe('TEST_FOO');
17+
18+
rule = getForcedCaseFn(['name', [RuleConfigSeverity.Warning, 'never']]);
19+
expect(rule('test')).toBe('test');
20+
expect(rule('test-foo')).toBe('test-foo');
21+
expect(rule('testFoo')).toBe('testFoo');
22+
expect(rule('TEST_FOO')).toBe('TEST_FOO');
23+
24+
rule = getForcedCaseFn([
25+
'name',
26+
[RuleConfigSeverity.Warning, 'always', ['camel-case', 'lowercase']],
27+
]);
28+
expect(rule('test')).toBe('test');
29+
expect(rule('test-foo')).toBe('test-foo');
30+
expect(rule('testFoo')).toBe('testFoo');
31+
expect(rule('TEST_FOO')).toBe('TEST_FOO');
32+
});
33+
34+
test('should throw error on invalid casing', () => {
35+
expect(() =>
36+
getForcedCaseFn(['name', [RuleConfigSeverity.Warning, 'always']])
37+
).toThrow('Unknown target case "undefined"');
38+
39+
expect(() =>
40+
getForcedCaseFn(['name', [RuleConfigSeverity.Warning, 'always', 'foo']])
41+
).toThrow('Unknown target case "foo"');
42+
});
43+
44+
test('should convert text correctly', () => {
45+
let rule = getForcedCaseFn([
46+
'name',
47+
[RuleConfigSeverity.Warning, 'always', 'camel-case'],
48+
]);
49+
expect(rule('TEST_FOOBar-baz baz')).toBe('testFooBarBazBaz');
50+
51+
rule = getForcedCaseFn([
52+
'name',
53+
[RuleConfigSeverity.Warning, 'always', 'kebab-case'],
54+
]);
55+
expect(rule('TEST_FOOBar-baz baz')).toBe('test-foo-bar-baz-baz');
56+
57+
rule = getForcedCaseFn([
58+
'name',
59+
[RuleConfigSeverity.Warning, 'always', 'snake-case'],
60+
]);
61+
expect(rule('TEST_FOOBar-baz baz')).toBe('test_foo_bar_baz_baz');
62+
63+
rule = getForcedCaseFn([
64+
'name',
65+
[RuleConfigSeverity.Warning, 'always', 'pascal-case'],
66+
]);
67+
expect(rule('TEST_FOOBar-baz baz')).toBe('TestFooBarBazBaz');
68+
69+
rule = getForcedCaseFn([
70+
'name',
71+
[RuleConfigSeverity.Warning, 'always', 'start-case'],
72+
]);
73+
expect(rule('TEST_FOOBar-baz baz')).toBe('TEST FOO Bar Baz Baz');
74+
75+
rule = getForcedCaseFn([
76+
'name',
77+
[RuleConfigSeverity.Warning, 'always', 'upper-case'],
78+
]);
79+
expect(rule('TEST_FOOBar-baz baz')).toBe('TEST_FOOBAR-BAZ BAZ');
80+
81+
rule = getForcedCaseFn([
82+
'name',
83+
[RuleConfigSeverity.Warning, 'always', 'uppercase'],
84+
]);
85+
expect(rule('TEST_FOOBar-baz baz')).toBe('TEST_FOOBAR-BAZ BAZ');
86+
87+
rule = getForcedCaseFn([
88+
'name',
89+
[RuleConfigSeverity.Warning, 'always', 'sentence-case'],
90+
]);
91+
expect(rule('TEST_FOOBar-baz baz')).toBe('Test_foobar-baz baz');
92+
93+
rule = getForcedCaseFn([
94+
'name',
95+
[RuleConfigSeverity.Warning, 'always', 'sentencecase'],
96+
]);
97+
expect(rule('TEST_FOOBar-baz baz')).toBe('Test_foobar-baz baz');
98+
99+
rule = getForcedCaseFn([
100+
'name',
101+
[RuleConfigSeverity.Warning, 'always', 'lower-case'],
102+
]);
103+
expect(rule('TEST_FOOBar-baz baz')).toBe('test_foobar-baz baz');
104+
105+
rule = getForcedCaseFn([
106+
'name',
107+
[RuleConfigSeverity.Warning, 'always', 'lowercase'],
108+
]);
109+
expect(rule('TEST_FOOBar-baz baz')).toBe('test_foobar-baz baz');
110+
111+
rule = getForcedCaseFn([
112+
'name',
113+
[RuleConfigSeverity.Warning, 'always', 'lowerCase'],
114+
]);
115+
expect(rule('TEST_FOOBar-baz baz')).toBe('test_foobar-baz baz');
116+
});

@commitlint/prompt/src/library/get-forced-case-fn.ts

+3-20
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import snakeCase from 'lodash/snakeCase';
44
import upperFirst from 'lodash/upperFirst';
55
import startCase from 'lodash/startCase';
66
import {RuleEntry} from './types';
7+
import {ruleIsActive, ruleIsNotApplicable} from './utils';
78

89
/**
910
* Get forced case for rule
@@ -15,29 +16,11 @@ export default function getForcedCaseFn(
1516
): (input: string) => string {
1617
const noop = (input: string) => input;
1718

18-
if (!rule) {
19+
if (!rule || !ruleIsActive(rule) || ruleIsNotApplicable(rule)) {
1920
return noop;
2021
}
2122

22-
const [config] = rule;
23-
24-
if (!Array.isArray(config)) {
25-
return noop;
26-
}
27-
28-
const [level] = config;
29-
30-
if (level === 0) {
31-
return noop;
32-
}
33-
34-
const [, when] = config;
35-
36-
if (when === 'never') {
37-
return noop;
38-
}
39-
40-
const [, , target] = config;
23+
const target = rule[1][2];
4124

4225
if (Array.isArray(target)) {
4326
return noop;
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import {RuleEntry} from './types';
2+
import {ruleIsActive, ruleIsNotApplicable} from './utils';
23

34
/**
45
* Get forced leading for rule
@@ -8,7 +9,10 @@ import {RuleEntry} from './types';
89
export default function getForcedLeadingFn(
910
rule?: RuleEntry
1011
): (input: string) => string {
11-
const noop = (input: string): string => input;
12+
if (!rule || !ruleIsActive(rule)) {
13+
return (input: string): string => input;
14+
}
15+
1216
const remove = (input: string): string => {
1317
const fragments = input.split('\n');
1418
return fragments[0] === '' ? fragments.slice(1).join('\n') : input;
@@ -18,35 +22,5 @@ export default function getForcedLeadingFn(
1822
return fragments[0] === '' ? input : ['', ...fragments].join('\n');
1923
};
2024

21-
if (!rule) {
22-
return noop;
23-
}
24-
25-
const leading = getForcedLeading(rule);
26-
27-
if (leading === null) {
28-
return noop;
29-
}
30-
31-
return leading ? lead : remove;
32-
}
33-
34-
/**
35-
* Get forced leading for rule
36-
* @param {object} rule to parse
37-
* @return {boolean|null} transform function applying the leading
38-
*/
39-
function getForcedLeading(rule: RuleEntry) {
40-
if (!rule) {
41-
return null;
42-
}
43-
44-
const [, [severity, applicable]] = rule;
45-
const negated = applicable === 'never';
46-
47-
if (severity === 0) {
48-
return null;
49-
}
50-
51-
return !negated;
25+
return !ruleIsNotApplicable(rule) ? lead : remove;
5226
}

@commitlint/prompt/src/library/get-has-name.ts

-11
This file was deleted.

0 commit comments

Comments
 (0)