1
1
import util from 'util' ;
2
2
import isIgnored from '@commitlint/is-ignored' ;
3
3
import parse from '@commitlint/parse' ;
4
- import implementations from '@commitlint/rules' ;
4
+ import defaultRules from '@commitlint/rules' ;
5
5
import toPairs from 'lodash/toPairs' ;
6
6
import values from 'lodash/values' ;
7
+ import { buildCommitMesage } from './commit-message' ;
8
+ import {
9
+ LintRuleConfig ,
10
+ LintOptions ,
11
+ LintRuleOutcome ,
12
+ Rule ,
13
+ Plugin ,
14
+ RuleSeverity
15
+ } from '@commitlint/types' ;
16
+
17
+ export default async function lint (
18
+ message : string ,
19
+ rawRulesConfig ?: LintRuleConfig ,
20
+ rawOpts ?: LintOptions
21
+ ) {
22
+ const opts = rawOpts
23
+ ? rawOpts
24
+ : { defaultIgnores : undefined , ignores : undefined } ;
25
+ const rulesConfig = rawRulesConfig || { } ;
7
26
8
- const buildCommitMesage = ( { header, body, footer} ) => {
9
- let message = header ;
10
-
11
- message = body ? `${ message } \n\n${ body } ` : message ;
12
- message = footer ? `${ message } \n\n${ footer } ` : message ;
13
-
14
- return message ;
15
- } ;
16
-
17
- export default async ( message , rules = { } , opts = { } ) => {
18
27
// Found a wildcard match, skip
19
28
if (
20
29
isIgnored ( message , { defaults : opts . defaultIgnores , ignores : opts . ignores } )
@@ -29,33 +38,35 @@ export default async (message, rules = {}, opts = {}) => {
29
38
30
39
// Parse the commit message
31
40
const parsed = await parse ( message , undefined , opts . parserOpts ) ;
41
+ const allRules : Map < string , Rule < unknown > | Rule < never > > = new Map (
42
+ Object . entries ( defaultRules )
43
+ ) ;
32
44
33
- const mergedImplementations = Object . assign ( { } , implementations ) ;
34
45
if ( opts . plugins ) {
35
- values ( opts . plugins ) . forEach ( plugin => {
46
+ values ( opts . plugins ) . forEach ( ( plugin : Plugin ) => {
36
47
if ( plugin . rules ) {
37
- Object . keys ( plugin . rules ) . forEach ( ruleKey => {
38
- mergedImplementations [ ruleKey ] = plugin . rules [ ruleKey ] ;
39
- } ) ;
48
+ Object . keys ( plugin . rules ) . forEach ( ruleKey =>
49
+ allRules . set ( ruleKey , plugin . rules [ ruleKey ] )
50
+ ) ;
40
51
}
41
52
} ) ;
42
53
}
43
54
44
55
// Find invalid rules configs
45
- const missing = Object . keys ( rules ) . filter (
46
- name => typeof mergedImplementations [ name ] !== 'function'
56
+ const missing = Object . keys ( rulesConfig ) . filter (
57
+ name => typeof allRules . get ( name ) !== 'function'
47
58
) ;
48
59
49
60
if ( missing . length > 0 ) {
50
- const names = Object . keys ( mergedImplementations ) ;
61
+ const names = [ ... allRules . keys ( ) ] ;
51
62
throw new RangeError (
52
63
`Found invalid rule names: ${ missing . join (
53
64
', '
54
65
) } . Supported rule names are: ${ names . join ( ', ' ) } `
55
66
) ;
56
67
}
57
68
58
- const invalid = toPairs ( rules )
69
+ const invalid = toPairs ( rulesConfig )
59
70
. map ( ( [ name , config ] ) => {
60
71
if ( ! Array . isArray ( config ) ) {
61
72
return new Error (
@@ -65,7 +76,13 @@ export default async (message, rules = {}, opts = {}) => {
65
76
) ;
66
77
}
67
78
68
- const [ level , when ] = config ;
79
+ const [ level ] = config ;
80
+
81
+ if ( level === RuleSeverity . Disabled && config . length === 1 ) {
82
+ return null ;
83
+ }
84
+
85
+ const [ , when ] = config ;
69
86
70
87
if ( typeof level !== 'number' || isNaN ( level ) ) {
71
88
return new Error (
@@ -75,10 +92,6 @@ export default async (message, rules = {}, opts = {}) => {
75
92
) ;
76
93
}
77
94
78
- if ( level === 0 && config . length === 1 ) {
79
- return null ;
80
- }
81
-
82
95
if ( config . length !== 2 && config . length !== 3 ) {
83
96
return new Error (
84
97
`config for rule ${ name } must be 2 or 3 items long, received ${ util . inspect (
@@ -113,18 +126,15 @@ export default async (message, rules = {}, opts = {}) => {
113
126
114
127
return null ;
115
128
} )
116
- . filter ( item => item instanceof Error ) ;
129
+ . filter ( ( item ) : item is Error => item instanceof Error ) ;
117
130
118
131
if ( invalid . length > 0 ) {
119
132
throw new Error ( invalid . map ( i => i . message ) . join ( '\n' ) ) ;
120
133
}
121
134
122
135
// Validate against all rules
123
- const results = toPairs ( rules )
124
- . filter ( entry => {
125
- const [ , [ level ] ] = toPairs ( entry ) ;
126
- return level > 0 ;
127
- } )
136
+ const results = toPairs ( rulesConfig )
137
+ . filter ( ( [ , [ level ] ] ) => level > 0 )
128
138
. map ( entry => {
129
139
const [ name , config ] = entry ;
130
140
const [ level , when , value ] = config ;
@@ -134,9 +144,14 @@ export default async (message, rules = {}, opts = {}) => {
134
144
return null ;
135
145
}
136
146
137
- const rule = mergedImplementations [ name ] ;
147
+ const rule = allRules . get ( name ) ;
148
+
149
+ if ( ! rule ) {
150
+ throw new Error ( `Could not find rule implementation for ${ name } ` ) ;
151
+ }
138
152
139
- const [ valid , message ] = rule ( parsed , when , value ) ;
153
+ const executableRule = rule as Rule < unknown > ;
154
+ const [ valid , message ] = executableRule ( parsed , when , value ) ;
140
155
141
156
return {
142
157
level,
@@ -145,7 +160,7 @@ export default async (message, rules = {}, opts = {}) => {
145
160
message
146
161
} ;
147
162
} )
148
- . filter ( Boolean ) ;
163
+ . filter ( ( result ) : result is LintRuleOutcome => result !== null ) ;
149
164
150
165
const errors = results . filter ( result => result . level === 2 && ! result . valid ) ;
151
166
const warnings = results . filter (
@@ -160,4 +175,4 @@ export default async (message, rules = {}, opts = {}) => {
160
175
warnings,
161
176
input : buildCommitMesage ( parsed )
162
177
} ;
163
- } ;
178
+ }
0 commit comments