Skip to content

Commit 0f8a4db

Browse files
committed
fix(load): repair botched merge
1 parent ac63645 commit 0f8a4db

File tree

4 files changed

+173
-50
lines changed

4 files changed

+173
-50
lines changed

@commitlint/load/package.json

+1
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
"typescript": "3.5.3"
4343
},
4444
"dependencies": {
45+
"@commitlint/ensure": "^8.2.0",
4546
"@commitlint/execute-rule": "^8.2.0",
4647
"@commitlint/resolve-extends": "^8.2.0",
4748
"chalk": "2.4.2",

@commitlint/load/src/index.ts

+145-37
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,124 @@
11
import path from 'path';
22
import executeRule from '@commitlint/execute-rule';
33
import resolveExtends from '@commitlint/resolve-extends';
4+
import {TargetCaseType} from '@commitlint/ensure';
45
import cosmiconfig, {CosmiconfigResult} from 'cosmiconfig';
56
import {toPairs, merge, mergeWith, pick} from 'lodash';
67
import resolveFrom from 'resolve-from';
78
import loadPlugin from './utils/loadPlugin';
89

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 =>
11122
pick(
12123
input,
13124
'extends',
@@ -19,13 +130,17 @@ const valid = (input: any) =>
19130
'defaultIgnores'
20131
);
21132

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;
26140

27141
// Merge passed config with file based options
28142
const config = valid(merge({}, loaded ? loaded.config : null, seed));
143+
29144
const opts = merge(
30145
{extends: [], rules: {}, formatter: '@commitlint/format'},
31146
pick(config, 'extends', 'plugins', 'ignores', 'defaultIgnores')
@@ -50,13 +165,17 @@ export default async (seed: any = {}, options: any = {cwd: process.cwd()}) => {
50165
});
51166

52167
const preset = valid(mergeWith(extended, config, w));
168+
config.extends = Array.isArray(config.extends) ? config.extends : [];
169+
53170
// Await parser-preset if applicable
54171
if (
55172
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'
58177
) {
59-
preset.parserPreset.parserOpts = (await preset.parserPreset
178+
(preset.parserPreset as any).parserOpts = (await (preset.parserPreset as any)
60179
.parserOpts).parserOpts;
61180
}
62181

@@ -67,41 +186,30 @@ export default async (seed: any = {}, options: any = {cwd: process.cwd()}) => {
67186
}
68187

69188
// resolve plugins
70-
preset.plugins = {};
71-
if (config.plugins && config.plugins.length) {
189+
if (Array.isArray(config.plugins)) {
72190
config.plugins.forEach((pluginKey: string) => {
73191
loadPlugin(preset.plugins, pluginKey, process.env.DEBUG === 'true');
74192
});
75193
}
76194

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;
102200
(registry as any)[key] = value;
103201
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+
};
105213
};
106214

107215
async function loadConfig(

@commitlint/load/tsconfig.json

+18-13
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,20 @@
11
{
2-
"extends": "../../tsconfig.shared.json",
3-
"compilerOptions": {
4-
"composite": true,
5-
"rootDir": "./src",
6-
"outDir": "./lib"
7-
},
8-
"include": [
9-
"./src"
10-
],
11-
"exclude": [
12-
"./src/**/*.test.ts",
13-
"./lib/**/*"
14-
]
2+
"extends": "../../tsconfig.shared.json",
3+
"compilerOptions": {
4+
"composite": true,
5+
"rootDir": "./src",
6+
"outDir": "./lib"
7+
},
8+
"include": [
9+
"./src"
10+
],
11+
"exclude": [
12+
"./src/**/*.test.ts",
13+
"./lib/**/*"
14+
],
15+
"references": [
16+
{ "path": "../ensure" },
17+
{ "path": "../execute-rule" },
18+
{ "path": "../resolve-extends" }
19+
]
1520
}

yarn.lock

+9
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,15 @@
203203
exec-sh "^0.3.2"
204204
minimist "^1.2.0"
205205

206+
"@commitlint/[email protected]":
207+
version "8.0.0"
208+
resolved "https://registry.npmjs.org/@commitlint/test/-/test-8.0.0.tgz#a0609c87e0fce141af1653894a66e1c4c39b5b10"
209+
integrity sha512-OX+K1vn0Mq805yWR6brqUr0QG4zcV4xYjrw5bDlFIM9hE+Nt7knJ4w6ooAcwMIHL7tlcsKHfIdKtNJBZAewpOA==
210+
dependencies:
211+
"@marionebl/sander" "0.6.1"
212+
execa "0.9.0"
213+
pkg-dir "2.0.0"
214+
206215
"@concordance/react@^1.0.0":
207216
version "1.0.0"
208217
resolved "https://registry.npmjs.org/@concordance/react/-/react-1.0.0.tgz#fcf3cad020e5121bfd1c61d05bc3516aac25f734"

0 commit comments

Comments
 (0)