1
1
import path from 'path' ;
2
- import importFrom from 'import-from' ;
3
2
import { entries , merge , mergeWith , pick } from 'lodash' ;
4
3
import rc from 'rc' ;
4
+ import cosmiconfig from 'cosmiconfig' ;
5
5
import resolveFrom from 'resolve-from' ;
6
+ import up from 'find-up' ;
6
7
7
8
import resolveExtends from './library/resolve-extends' ;
8
9
import executeRule from './library/execute-rule' ;
@@ -12,19 +13,23 @@ const valid = input => pick(input, 'extends', 'rules', 'parserPreset');
12
13
13
14
export default async ( seed = { } ) => {
14
15
// Obtain config from .rc files
15
- const raw = file ( ) ;
16
-
16
+ const raw = await file ( ) ;
17
17
// Merge passed config with file based options
18
18
const config = valid ( merge ( raw , seed ) ) ;
19
19
const opts = merge ( { extends : [ ] , rules : { } } , pick ( config , 'extends' ) ) ;
20
20
21
21
// Resolve parserPreset key
22
22
if ( typeof config . parserPreset === 'string' ) {
23
- const resolvedParserPreset = resolveFrom ( process . cwd ( ) , config . parserPreset ) ;
23
+ const resolvedParserPreset = resolveFrom (
24
+ process . cwd ( ) ,
25
+ config . parserPreset
26
+ ) ;
24
27
25
28
config . parserPreset = {
26
29
name : config . parserPreset ,
27
- path : `./${ path . posix . relative ( process . cwd ( ) , resolvedParserPreset ) } ` . split ( path . sep ) . join ( '/' ) ,
30
+ path : `./${ path . posix . relative ( process . cwd ( ) , resolvedParserPreset ) } `
31
+ . split ( path . sep )
32
+ . join ( '/' ) ,
28
33
opts : require ( resolvedParserPreset )
29
34
} ;
30
35
}
@@ -39,7 +44,10 @@ export default async (seed = {}) => {
39
44
const preset = valid ( mergeWith ( extended , config , w ) ) ;
40
45
41
46
// Await parser-preset if applicable
42
- if ( typeof preset . parserPreset === 'object' && typeof preset . parserPreset . opts === 'object' ) {
47
+ if (
48
+ typeof preset . parserPreset === 'object' &&
49
+ typeof preset . parserPreset . opts === 'object'
50
+ ) {
43
51
preset . parserPreset . opts = await preset . parserPreset . opts ;
44
52
}
45
53
@@ -73,14 +81,16 @@ export default async (seed = {}) => {
73
81
} , preset ) ;
74
82
} ;
75
83
76
- function file ( ) {
84
+ async function file ( ) {
77
85
const legacy = rc ( 'conventional-changelog-lint' ) ;
78
86
const legacyFound = typeof legacy . config === 'string' ;
87
+ const explorer = cosmiconfig ( 'commitlint' , {
88
+ rcExtensions : true ,
89
+ stopDir : await toplevel ( )
90
+ } ) ;
91
+ const config = await explorer . load ( '.' ) ;
79
92
80
- const found = resolveable ( './commitlint.config' ) ;
81
- const raw = found ? importFrom ( process . cwd ( ) , './commitlint.config' ) : { } ;
82
-
83
- if ( legacyFound && ! found ) {
93
+ if ( legacyFound && ! config ) {
84
94
console . warn (
85
95
`Using legacy ${ path . relative (
86
96
process . cwd ( ) ,
@@ -89,7 +99,7 @@ function file() {
89
99
) ;
90
100
}
91
101
92
- if ( legacyFound && found ) {
102
+ if ( legacyFound && config ) {
93
103
console . warn (
94
104
`Ignored legacy ${ path . relative (
95
105
process . cwd ( ) ,
@@ -98,18 +108,21 @@ function file() {
98
108
) ;
99
109
}
100
110
101
- if ( found ) {
102
- return raw ;
111
+ if ( config ) {
112
+ return config . config ;
103
113
}
104
114
105
115
return legacy ;
106
116
}
107
117
108
- function resolveable ( id ) {
109
- try {
110
- resolveFrom ( process . cwd ( ) , id ) ;
111
- return true ;
112
- } catch ( err ) {
113
- return false ;
118
+ // Find the next git root
119
+ // (start: string) => Promise<string | null>
120
+ async function toplevel ( cwd = process . cwd ( ) ) {
121
+ const found = await up ( '.git' , { cwd} ) ;
122
+
123
+ if ( typeof found !== 'string' ) {
124
+ return found ;
114
125
}
126
+
127
+ return path . join ( found , '..' ) ;
115
128
}
0 commit comments