1
1
import path from 'path' ;
2
2
import executeRule from '@commitlint/execute-rule' ;
3
3
import resolveExtends from '@commitlint/resolve-extends' ;
4
+ import { TargetCaseType } from '@commitlint/ensure' ;
4
5
import cosmiconfig , { CosmiconfigResult } from 'cosmiconfig' ;
5
6
import { toPairs , merge , mergeWith , pick } from 'lodash' ;
6
7
import resolveFrom from 'resolve-from' ;
7
8
import loadPlugin from './utils/loadPlugin' ;
8
9
9
- const w = ( a : any , b : any ) => ( Array . isArray ( b ) ? b : undefined ) ;
10
- const valid = ( input : any ) =>
10
+ export interface LoadOptions {
11
+ cwd ?: string ;
12
+ file ?: string ;
13
+ }
14
+
15
+ export enum RuleSeverity {
16
+ Warning = 1 ,
17
+ Error = 2
18
+ }
19
+
20
+ export type RuleApplication = 'always' | 'never' ;
21
+
22
+ export type RuleConfigTuple < T > = ReadonlyArray <
23
+ T extends void
24
+ ? [ RuleSeverity , RuleApplication ]
25
+ : [ RuleSeverity , RuleApplication , T ]
26
+ > ;
27
+
28
+ export enum RuleConfigQuality {
29
+ User ,
30
+ Qualified
31
+ }
32
+
33
+ export type RuleConfig <
34
+ V = RuleConfigQuality . Qualified ,
35
+ T = void
36
+ > = V extends false
37
+ ? RuleConfigTuple < T >
38
+ :
39
+ | ( ( ) => RuleConfigTuple < T > )
40
+ | ( ( ) => RuleConfigTuple < Promise < T > > )
41
+ | RuleConfigTuple < T > ;
42
+
43
+ export type CaseRuleConfig < V = RuleConfigQuality . User > = RuleConfig <
44
+ V ,
45
+ TargetCaseType
46
+ > ;
47
+ export type LengthRuleConfig < V = RuleConfigQuality . User > = RuleConfig <
48
+ V ,
49
+ number
50
+ > ;
51
+ export type EnumRuleConfig < V = RuleConfigQuality . User > = RuleConfig <
52
+ V ,
53
+ string [ ]
54
+ > ;
55
+
56
+ export type RulesConfig < V = RuleConfigQuality . User > = {
57
+ 'body-case' : CaseRuleConfig < V > ;
58
+ 'body-empty' : RuleConfig < V > ;
59
+ 'body-leading-blank' : RuleConfig < V > ;
60
+ 'body-max-length' : LengthRuleConfig < V > ;
61
+ 'body-max-line-length' : LengthRuleConfig < V > ;
62
+ 'body-min-length' : LengthRuleConfig < V > ;
63
+ 'footer-empty' : RuleConfig < V > ;
64
+ 'footer-leading-blank' : RuleConfig < V > ;
65
+ 'footer-max-length' : LengthRuleConfig < V > ;
66
+ 'footer-max-line-length' : LengthRuleConfig < V > ;
67
+ 'footer-min-length' : LengthRuleConfig < V > ;
68
+ 'header-case' : CaseRuleConfig < V > ;
69
+ 'header-full-stop' : RuleConfig < V > ;
70
+ 'header-max-length' : LengthRuleConfig < V > ;
71
+ 'header-min-length' : LengthRuleConfig < V > ;
72
+ 'references-empty' : RuleConfig < V > ;
73
+ 'scope-case' : CaseRuleConfig < V > ;
74
+ 'scope-empty' : RuleConfig < V > ;
75
+ 'scope-enum' : EnumRuleConfig < V > ;
76
+ 'scope-max-length' : LengthRuleConfig < V > ;
77
+ 'scope-min-length' : LengthRuleConfig < V > ;
78
+ 'signed-off-by' : RuleConfig < V > ;
79
+ 'subject-case' : CaseRuleConfig < V > ;
80
+ 'subject-empty' : RuleConfig < V > ;
81
+ 'subject-full-stop' : RuleConfig < V > ;
82
+ 'subject-max-length' : LengthRuleConfig < V > ;
83
+ 'subject-min-length' : LengthRuleConfig < V > ;
84
+ 'type-case' : CaseRuleConfig < V > ;
85
+ 'type-empty' : RuleConfig < V > ;
86
+ 'type-enum' : EnumRuleConfig < V > ;
87
+ 'type-max-length' : LengthRuleConfig < V > ;
88
+ 'type-min-length' : LengthRuleConfig < V > ;
89
+ } ;
90
+
91
+ export interface UserConfig {
92
+ extends ?: string [ ] ;
93
+ formatter ?: unknown ;
94
+ rules ?: Partial < RulesConfig > ;
95
+ parserPreset ?: string | ParserPreset ;
96
+ ignores ?: ( ( commit : string ) => boolean ) [ ] ;
97
+ defaultIgnores ?: boolean ;
98
+ plugins ?: any [ ] ;
99
+ }
100
+
101
+ export type QualifiedRules = Partial < RulesConfig < RuleConfigQuality . Qualified > > ;
102
+
103
+ export interface QualifiedConfig {
104
+ extends : string [ ] ;
105
+ formatter : unknown ;
106
+ rules : Partial < QualifiedRules > ;
107
+ parserPreset : ParserPreset ;
108
+ ignores : ( ( commit : string ) => boolean ) [ ] ;
109
+ defaultIgnores : boolean ;
110
+ plugins : any [ ] ;
111
+ }
112
+
113
+ export interface ParserPreset {
114
+ name : string ;
115
+ path : string ;
116
+ parserOpts ?: unknown ;
117
+ }
118
+
119
+ const w = < T > ( _ : unknown , b : ArrayLike < T > | null | undefined | false ) =>
120
+ Array . isArray ( b ) ? b : undefined ;
121
+ const valid = ( input : unknown ) : UserConfig =>
11
122
pick (
12
123
input ,
13
124
'extends' ,
@@ -19,13 +130,17 @@ const valid = (input: any) =>
19
130
'defaultIgnores'
20
131
) ;
21
132
22
- export default async ( seed : any = { } , options : any = { cwd : process . cwd ( ) } ) => {
23
- const loaded = await loadConfig ( options . cwd , options . file ) ;
24
- const base =
25
- loaded && loaded . filepath ? path . dirname ( loaded . filepath ) : options . cwd ;
133
+ export default async (
134
+ seed : UserConfig = { } ,
135
+ options : LoadOptions = { }
136
+ ) : Promise < QualifiedConfig > => {
137
+ const cwd = typeof options . cwd === 'undefined' ? process . cwd ( ) : options . cwd ;
138
+ const loaded = await loadConfig ( cwd , options . file ) ;
139
+ const base = loaded && loaded . filepath ? path . dirname ( loaded . filepath ) : cwd ;
26
140
27
141
// Merge passed config with file based options
28
142
const config = valid ( merge ( { } , loaded ? loaded . config : null , seed ) ) ;
143
+
29
144
const opts = merge (
30
145
{ extends : [ ] , rules : { } , formatter : '@commitlint/format' } ,
31
146
pick ( config , 'extends' , 'plugins' , 'ignores' , 'defaultIgnores' )
@@ -50,13 +165,17 @@ export default async (seed: any = {}, options: any = {cwd: process.cwd()}) => {
50
165
} ) ;
51
166
52
167
const preset = valid ( mergeWith ( extended , config , w ) ) ;
168
+ config . extends = Array . isArray ( config . extends ) ? config . extends : [ ] ;
169
+
53
170
// Await parser-preset if applicable
54
171
if (
55
172
typeof preset . parserPreset === 'object' &&
56
- typeof preset . parserPreset . parserOpts === 'object' &&
57
- typeof preset . parserPreset . parserOpts . then === 'function'
173
+ preset . parserPreset !== null &&
174
+ typeof ( preset . parserPreset as any ) . parserOpts === 'object' &&
175
+ ( preset . parserPreset as any ) !== null &&
176
+ typeof ( preset . parserPreset as any ) . parserOpts . then === 'function'
58
177
) {
59
- preset . parserPreset . parserOpts = ( await preset . parserPreset
178
+ ( preset . parserPreset as any ) . parserOpts = ( await ( preset . parserPreset as any )
60
179
. parserOpts ) . parserOpts ;
61
180
}
62
181
@@ -67,41 +186,30 @@ export default async (seed: any = {}, options: any = {cwd: process.cwd()}) => {
67
186
}
68
187
69
188
// resolve plugins
70
- preset . plugins = { } ;
71
- if ( config . plugins && config . plugins . length ) {
189
+ if ( Array . isArray ( config . plugins ) ) {
72
190
config . plugins . forEach ( ( pluginKey : string ) => {
73
191
loadPlugin ( preset . plugins , pluginKey , process . env . DEBUG === 'true' ) ;
74
192
} ) ;
75
193
}
76
194
77
- // Execute rule config functions if needed
78
- const executed = await Promise . all (
79
- [ 'rules' ]
80
- . map ( key => {
81
- return [ key , ( preset as any ) [ key ] ] ;
82
- } )
83
- . map ( async item => {
84
- const [ key , value ] = item ;
85
- const executedValue = await Promise . all (
86
- toPairs ( value || { } ) . map ( entry => executeRule < any > ( entry ) )
87
- ) ;
88
- return [
89
- key ,
90
- executedValue . reduce ( ( registry , item ) => {
91
- const [ key , value ] = item as any ;
92
- ( registry as any ) [ key ] = value ;
93
- return registry ;
94
- } , { } )
95
- ] ;
96
- } )
97
- ) ;
98
-
99
- // Merge executed config keys into preset
100
- return executed . reduce ( ( registry , item ) => {
101
- const [ key , value ] = item ;
195
+ const rules = preset . rules ? preset . rules : { } ;
196
+ const qualifiedRules = ( await Promise . all (
197
+ toPairs ( rules || { } ) . map ( entry => executeRule < any > ( entry ) )
198
+ ) ) . reduce < QualifiedRules > ( ( registry , item ) => {
199
+ const [ key , value ] = item as any ;
102
200
( registry as any ) [ key ] = value ;
103
201
return registry ;
104
- } , preset ) ;
202
+ } , { } ) ;
203
+
204
+ return {
205
+ extends : preset . extends ! ,
206
+ formatter : preset . formatter ! ,
207
+ parserPreset : preset . parserPreset ! as ParserPreset ,
208
+ ignores : preset . ignores ! ,
209
+ defaultIgnores : preset . defaultIgnores ! ,
210
+ plugins : preset . plugins ! ,
211
+ rules : qualifiedRules
212
+ } ;
105
213
} ;
106
214
107
215
async function loadConfig (
0 commit comments