Skip to content

Commit 8a8384f

Browse files
authoredNov 16, 2021
feat: simplify config resolution (#2398)
* feat: basic user config validation * fix: simplify config resolution and fix issue #327 * fix: remove no longer needed function * fix: disable some unwanted validations * fix: improve config validation * fix: remove redundant validation * fix: use reduceRight instead of reverse * fix: rollback some code * fix: drop invalid type casts * fix: rollback unnecessary changes * fix: rollback config validation * fix: add missing type-guards and restore order * fix: one more order change * fix: add one more missing type guard * fix: remove unused types reference * fix: add additional unit tests * fix: add additional regression tests - remove also unnecessary type check * fix: remove more unnecessary code changes * fix: correct order of merging plugins * fix: add missing type check * fix: remove invalid type check * fix: remove redundant code * fix: rollback some unnecessary changes * fix: optimize loadParserOpts
1 parent c33d493 commit 8a8384f

File tree

8 files changed

+322
-126
lines changed

8 files changed

+322
-126
lines changed
 

‎@commitlint/cli/src/cli.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -373,7 +373,7 @@ function getSeed(flags: CliFlags): Seed {
373373
: {parserPreset: flags['parser-preset']};
374374
}
375375

376-
function selectParserOpts(parserPreset: ParserPreset) {
376+
function selectParserOpts(parserPreset: ParserPreset | undefined) {
377377
if (typeof parserPreset !== 'object') {
378378
return undefined;
379379
}

‎@commitlint/load/src/load.test.ts

+26-18
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ test('extends-empty should have no rules', async () => {
2121
const actual = await load({}, {cwd});
2222

2323
expect(actual.rules).toMatchObject({});
24+
expect(actual.parserPreset).not.toBeDefined();
2425
});
2526

2627
test('uses seed as configured', async () => {
@@ -127,8 +128,9 @@ test('uses seed with parserPreset', async () => {
127128
{cwd}
128129
);
129130

130-
expect(actual.name).toBe('./conventional-changelog-custom');
131-
expect(actual.parserOpts).toMatchObject({
131+
expect(actual).toBeDefined();
132+
expect(actual!.name).toBe('./conventional-changelog-custom');
133+
expect(actual!.parserOpts).toMatchObject({
132134
headerPattern: /^(\w*)(?:\((.*)\))?-(.*)$/,
133135
});
134136
});
@@ -268,8 +270,9 @@ test('parser preset overwrites completely instead of merging', async () => {
268270
const cwd = await gitBootstrap('fixtures/parser-preset-override');
269271
const actual = await load({}, {cwd});
270272

271-
expect(actual.parserPreset.name).toBe('./custom');
272-
expect(actual.parserPreset.parserOpts).toMatchObject({
273+
expect(actual.parserPreset).toBeDefined();
274+
expect(actual.parserPreset!.name).toBe('./custom');
275+
expect(actual.parserPreset!.parserOpts).toMatchObject({
273276
headerPattern: /.*/,
274277
});
275278
});
@@ -278,8 +281,9 @@ test('recursive extends with parserPreset', async () => {
278281
const cwd = await gitBootstrap('fixtures/recursive-parser-preset');
279282
const actual = await load({}, {cwd});
280283

281-
expect(actual.parserPreset.name).toBe('./conventional-changelog-custom');
282-
expect(actual.parserPreset.parserOpts).toMatchObject({
284+
expect(actual.parserPreset).toBeDefined();
285+
expect(actual.parserPreset!.name).toBe('./conventional-changelog-custom');
286+
expect(actual.parserPreset!.parserOpts).toMatchObject({
283287
headerPattern: /^(\w*)(?:\((.*)\))?-(.*)$/,
284288
});
285289
});
@@ -402,11 +406,12 @@ test('resolves parser preset from conventional commits', async () => {
402406
const cwd = await npmBootstrap('fixtures/parser-preset-conventionalcommits');
403407
const actual = await load({}, {cwd});
404408

405-
expect(actual.parserPreset.name).toBe(
409+
expect(actual.parserPreset).toBeDefined();
410+
expect(actual.parserPreset!.name).toBe(
406411
'conventional-changelog-conventionalcommits'
407412
);
408-
expect(typeof actual.parserPreset.parserOpts).toBe('object');
409-
expect((actual.parserPreset.parserOpts as any).headerPattern).toEqual(
413+
expect(typeof actual.parserPreset!.parserOpts).toBe('object');
414+
expect((actual.parserPreset!.parserOpts as any).headerPattern).toEqual(
410415
/^(\w*)(?:\((.*)\))?!?: (.*)$/
411416
);
412417
});
@@ -415,9 +420,10 @@ test('resolves parser preset from conventional angular', async () => {
415420
const cwd = await npmBootstrap('fixtures/parser-preset-angular');
416421
const actual = await load({}, {cwd});
417422

418-
expect(actual.parserPreset.name).toBe('conventional-changelog-angular');
419-
expect(typeof actual.parserPreset.parserOpts).toBe('object');
420-
expect((actual.parserPreset.parserOpts as any).headerPattern).toEqual(
423+
expect(actual.parserPreset).toBeDefined();
424+
expect(actual.parserPreset!.name).toBe('conventional-changelog-angular');
425+
expect(typeof actual.parserPreset!.parserOpts).toBe('object');
426+
expect((actual.parserPreset!.parserOpts as any).headerPattern).toEqual(
421427
/^(\w*)(?:\((.*)\))?: (.*)$/
422428
);
423429
});
@@ -432,9 +438,10 @@ test('recursive resolves parser preset from conventional atom', async () => {
432438

433439
const actual = await load({}, {cwd});
434440

435-
expect(actual.parserPreset.name).toBe('conventional-changelog-atom');
436-
expect(typeof actual.parserPreset.parserOpts).toBe('object');
437-
expect((actual.parserPreset.parserOpts as any).headerPattern).toEqual(
441+
expect(actual.parserPreset).toBeDefined();
442+
expect(actual.parserPreset!.name).toBe('conventional-changelog-atom');
443+
expect(typeof actual.parserPreset!.parserOpts).toBe('object');
444+
expect((actual.parserPreset!.parserOpts as any).headerPattern).toEqual(
438445
/^(:.*?:) (.*)$/
439446
);
440447
});
@@ -445,11 +452,12 @@ test('resolves parser preset from conventional commits without factory support',
445452
);
446453
const actual = await load({}, {cwd});
447454

448-
expect(actual.parserPreset.name).toBe(
455+
expect(actual.parserPreset).toBeDefined();
456+
expect(actual.parserPreset!.name).toBe(
449457
'conventional-changelog-conventionalcommits'
450458
);
451-
expect(typeof actual.parserPreset.parserOpts).toBe('object');
452-
expect((actual.parserPreset.parserOpts as any).headerPattern).toEqual(
459+
expect(typeof actual.parserPreset!.parserOpts).toBe('object');
460+
expect((actual.parserPreset!.parserOpts as any).headerPattern).toEqual(
453461
/^(\w*)(?:\((.*)\))?!?: (.*)$/
454462
);
455463
});

‎@commitlint/load/src/load.ts

+41-59
Original file line numberDiff line numberDiff line change
@@ -2,27 +2,21 @@ import executeRule from '@commitlint/execute-rule';
22
import resolveExtends from '@commitlint/resolve-extends';
33
import {
44
LoadOptions,
5-
ParserPreset,
65
QualifiedConfig,
76
QualifiedRules,
7+
PluginRecords,
88
UserConfig,
9-
UserPreset,
109
} from '@commitlint/types';
1110
import isPlainObject from 'lodash/isPlainObject';
1211
import merge from 'lodash/merge';
13-
import mergeWith from 'lodash/mergeWith';
14-
import pick from 'lodash/pick';
15-
import union from 'lodash/union';
12+
import uniq from 'lodash/uniq';
1613
import Path from 'path';
1714
import resolveFrom from 'resolve-from';
1815
import {loadConfig} from './utils/load-config';
1916
import {loadParserOpts} from './utils/load-parser-opts';
2017
import loadPlugin from './utils/load-plugin';
2118
import {pickConfig} from './utils/pick-config';
2219

23-
const w = <T>(_: unknown, b: ArrayLike<T> | null | undefined | false) =>
24-
Array.isArray(b) ? b : undefined;
25-
2620
export default async function load(
2721
seed: UserConfig = {},
2822
options: LoadOptions = {}
@@ -35,11 +29,16 @@ export default async function load(
3529
// Might amount to breaking changes, defer until 9.0.0
3630

3731
// Merge passed config with file based options
38-
const config = pickConfig(merge({}, loaded ? loaded.config : null, seed));
39-
40-
const opts = merge(
41-
{extends: [], rules: {}, formatter: '@commitlint/format'},
42-
pick(config, 'extends', 'plugins', 'ignores', 'defaultIgnores')
32+
const config = pickConfig(
33+
merge(
34+
{
35+
extends: [],
36+
plugins: [],
37+
rules: {},
38+
},
39+
loaded ? loaded.config : null,
40+
seed
41+
)
4342
);
4443

4544
// Resolve parserPreset key
@@ -54,59 +53,35 @@ export default async function load(
5453
}
5554

5655
// Resolve extends key
57-
const extended = resolveExtends(opts, {
56+
const extended = resolveExtends(config, {
5857
prefix: 'commitlint-config',
5958
cwd: base,
6059
parserPreset: config.parserPreset,
61-
});
62-
63-
const preset = pickConfig(
64-
mergeWith(extended, config, w)
65-
) as unknown as UserPreset;
66-
preset.plugins = {};
67-
68-
// TODO: check if this is still necessary with the new factory based conventional changelog parsers
69-
// config.extends = Array.isArray(config.extends) ? config.extends : [];
60+
}) as unknown as UserConfig;
7061

71-
// Resolve parser-opts from preset
72-
if (typeof preset.parserPreset === 'object') {
73-
preset.parserPreset.parserOpts = await loadParserOpts(
74-
preset.parserPreset.name,
75-
// TODO: fix the types for factory based conventional changelog parsers
76-
preset.parserPreset as any
77-
);
62+
if (!extended.formatter || typeof extended.formatter !== 'string') {
63+
extended.formatter = '@commitlint/format';
7864
}
7965

80-
// Resolve config-relative formatter module
81-
if (typeof config.formatter === 'string') {
82-
preset.formatter =
83-
resolveFrom.silent(base, config.formatter) || config.formatter;
84-
}
85-
86-
// Read plugins from extends
66+
let plugins: PluginRecords = {};
8767
if (Array.isArray(extended.plugins)) {
88-
config.plugins = union(config.plugins, extended.plugins || []);
89-
}
90-
91-
// resolve plugins
92-
if (Array.isArray(config.plugins)) {
93-
config.plugins.forEach((plugin) => {
68+
uniq(extended.plugins || []).forEach((plugin) => {
9469
if (typeof plugin === 'string') {
95-
loadPlugin(preset.plugins, plugin, process.env.DEBUG === 'true');
70+
plugins = loadPlugin(plugins, plugin, process.env.DEBUG === 'true');
9671
} else {
97-
preset.plugins.local = plugin;
72+
plugins.local = plugin;
9873
}
9974
});
10075
}
10176

102-
const rules = preset.rules ? preset.rules : {};
103-
const qualifiedRules = (
77+
const rules = (
10478
await Promise.all(
105-
Object.entries(rules || {}).map((entry) => executeRule<any>(entry))
79+
Object.entries(extended.rules || {}).map((entry) => executeRule(entry))
10680
)
10781
).reduce<QualifiedRules>((registry, item) => {
108-
const [key, value] = item as any;
109-
(registry as any)[key] = value;
82+
// type of `item` can be null, but Object.entries always returns key pair
83+
const [key, value] = item!;
84+
registry[key] = value;
11085
return registry;
11186
}, {});
11287

@@ -118,17 +93,24 @@ export default async function load(
11893
: 'https://github.com/conventional-changelog/commitlint/#what-is-commitlint';
11994

12095
const prompt =
121-
preset.prompt && isPlainObject(preset.prompt) ? preset.prompt : {};
96+
extended.prompt && isPlainObject(extended.prompt) ? extended.prompt : {};
12297

12398
return {
124-
extends: preset.extends!,
125-
formatter: preset.formatter!,
126-
parserPreset: preset.parserPreset! as ParserPreset,
127-
ignores: preset.ignores!,
128-
defaultIgnores: preset.defaultIgnores!,
129-
plugins: preset.plugins!,
130-
rules: qualifiedRules,
131-
helpUrl,
99+
extends: Array.isArray(extended.extends)
100+
? extended.extends
101+
: typeof extended.extends === 'string'
102+
? [extended.extends]
103+
: [],
104+
// Resolve config-relative formatter module
105+
formatter:
106+
resolveFrom.silent(base, extended.formatter) || extended.formatter,
107+
// Resolve parser-opts from preset
108+
parserPreset: await loadParserOpts(extended.parserPreset),
109+
ignores: extended.ignores,
110+
defaultIgnores: extended.defaultIgnores,
111+
plugins: plugins,
112+
rules: rules,
113+
helpUrl: helpUrl,
132114
prompt,
133115
};
134116
}
+50-27
Original file line numberDiff line numberDiff line change
@@ -1,48 +1,71 @@
1+
import {ParserPreset} from '@commitlint/types';
2+
3+
function isObjectLike(obj: unknown): obj is Record<string, unknown> {
4+
return Boolean(obj) && typeof obj === 'object'; // typeof null === 'object'
5+
}
6+
7+
function isParserOptsFunction<T extends ParserPreset>(
8+
obj: T
9+
): obj is T & {
10+
parserOpts: (...args: any[]) => any;
11+
} {
12+
return typeof obj.parserOpts === 'function';
13+
}
14+
115
export async function loadParserOpts(
2-
parserName: string,
3-
pendingParser: Promise<any>
4-
) {
16+
pendingParser: string | ParserPreset | Promise<ParserPreset> | undefined
17+
): Promise<ParserPreset | undefined> {
18+
if (!pendingParser || typeof pendingParser !== 'object') {
19+
return undefined;
20+
}
521
// Await for the module, loaded with require
622
const parser = await pendingParser;
723

8-
// Await parser opts if applicable
9-
if (
10-
typeof parser === 'object' &&
11-
typeof parser.parserOpts === 'object' &&
12-
typeof parser.parserOpts.then === 'function'
13-
) {
14-
return (await parser.parserOpts).parserOpts;
24+
// exit early, no opts to resolve
25+
if (!parser.parserOpts) {
26+
return parser;
27+
}
28+
29+
// Pull nested parserOpts, might happen if overwritten with a module in main config
30+
if (typeof parser.parserOpts === 'object') {
31+
// Await parser opts if applicable
32+
parser.parserOpts = await parser.parserOpts;
33+
if (
34+
isObjectLike(parser.parserOpts) &&
35+
isObjectLike(parser.parserOpts.parserOpts)
36+
) {
37+
parser.parserOpts = parser.parserOpts.parserOpts;
38+
}
39+
return parser;
1540
}
1641

1742
// Create parser opts from factory
1843
if (
19-
typeof parser === 'object' &&
20-
typeof parser.parserOpts === 'function' &&
21-
parserName.startsWith('conventional-changelog-')
44+
isParserOptsFunction(parser) &&
45+
typeof parser.name === 'string' &&
46+
parser.name.startsWith('conventional-changelog-')
2247
) {
23-
return await new Promise((resolve) => {
24-
const result = parser.parserOpts((_: never, opts: {parserOpts: any}) => {
25-
resolve(opts.parserOpts);
48+
return new Promise((resolve) => {
49+
const result = parser.parserOpts((_: never, opts: any) => {
50+
resolve({
51+
...parser,
52+
parserOpts: opts?.parserOpts,
53+
});
2654
});
2755

2856
// If result has data or a promise, the parser doesn't support factory-init
2957
// due to https://github.com/nodejs/promises-debugging/issues/16 it just quits, so let's use this fallback
3058
if (result) {
3159
Promise.resolve(result).then((opts) => {
32-
resolve(opts.parserOpts);
60+
resolve({
61+
...parser,
62+
parserOpts: opts?.parserOpts,
63+
});
3364
});
3465
}
66+
return;
3567
});
3668
}
3769

38-
// Pull nested paserOpts, might happen if overwritten with a module in main config
39-
if (
40-
typeof parser === 'object' &&
41-
typeof parser.parserOpts === 'object' &&
42-
typeof parser.parserOpts.parserOpts === 'object'
43-
) {
44-
return parser.parserOpts.parserOpts;
45-
}
46-
47-
return parser.parserOpts;
70+
return parser;
4871
}

‎@commitlint/load/src/utils/pick-config.ts

+1-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
1-
import {UserConfig} from '@commitlint/types';
21
import pick from 'lodash/pick';
32

4-
export const pickConfig = (input: unknown): UserConfig =>
3+
export const pickConfig = (input: unknown): Record<string, unknown> =>
54
pick(
65
input,
76
'extends',

‎@commitlint/resolve-extends/src/index.test.ts

+186-5
Original file line numberDiff line numberDiff line change
@@ -321,11 +321,7 @@ test('should fall back to conventional-changelog-lint-config prefix', () => {
321321
const require = (id: string) => {
322322
switch (id) {
323323
case 'conventional-changelog-lint-config-extender-name':
324-
return {
325-
rules: {
326-
fallback: true,
327-
},
328-
};
324+
return {rules: {fallback: true}};
329325
default:
330326
return {};
331327
}
@@ -348,3 +344,188 @@ test('should fall back to conventional-changelog-lint-config prefix', () => {
348344
},
349345
});
350346
});
347+
348+
test('plugins should be merged correctly', () => {
349+
const input = {extends: ['extender-name'], zero: 'root'};
350+
351+
const require = (id: string) => {
352+
switch (id) {
353+
case 'extender-name':
354+
return {extends: ['recursive-extender-name'], plugins: ['test']};
355+
case 'recursive-extender-name':
356+
return {
357+
extends: ['second-recursive-extender-name'],
358+
plugins: ['test2'],
359+
};
360+
case 'second-recursive-extender-name':
361+
return {plugins: ['test3']};
362+
default:
363+
return {};
364+
}
365+
};
366+
367+
const ctx = {resolve: id, require: jest.fn(require)} as ResolveExtendsContext;
368+
369+
const actual = resolveExtends(input, ctx);
370+
371+
const expected = {
372+
extends: ['extender-name'],
373+
plugins: ['test3', 'test2', 'test'],
374+
zero: 'root',
375+
};
376+
377+
expect(actual).toEqual(expected);
378+
});
379+
380+
test('rules should be merged correctly', () => {
381+
const input = {extends: ['extender-name'], rules: {test1: ['base', '1']}};
382+
383+
const require = (id: string) => {
384+
switch (id) {
385+
case 'extender-name':
386+
return {
387+
extends: ['recursive-extender-name'],
388+
rules: {test2: [id, '2']},
389+
};
390+
case 'recursive-extender-name':
391+
return {
392+
extends: ['second-recursive-extender-name'],
393+
rules: {test1: [id, '3']},
394+
};
395+
case 'second-recursive-extender-name':
396+
return {rules: {test2: [id, '4']}};
397+
default:
398+
return {};
399+
}
400+
};
401+
402+
const ctx = {resolve: id, require: jest.fn(require)} as ResolveExtendsContext;
403+
404+
const actual = resolveExtends(input, ctx);
405+
406+
const expected = {
407+
extends: ['extender-name'],
408+
rules: {
409+
test1: ['base', '1'],
410+
test2: ['extender-name', '2'],
411+
},
412+
};
413+
414+
expect(actual).toEqual(expected);
415+
});
416+
417+
// https://github.com/conventional-changelog/commitlint/issues/327
418+
test('parserPreset should resolve correctly in extended configuration', () => {
419+
const input = {extends: ['extender-name'], zero: 'root'};
420+
421+
const require = (id: string) => {
422+
switch (id) {
423+
case 'extender-name':
424+
return {
425+
extends: ['recursive-extender-name'],
426+
parserPreset: {
427+
parserOpts: {
428+
issuePrefixes: ['#', '!', '&', 'no-references'],
429+
referenceActions: null,
430+
},
431+
},
432+
};
433+
case 'recursive-extender-name':
434+
return {parserPreset: {parserOpts: {issuePrefixes: ['#', '!']}}};
435+
default:
436+
return {};
437+
}
438+
};
439+
440+
const ctx = {resolve: id, require: jest.fn(require)} as ResolveExtendsContext;
441+
442+
const actual = resolveExtends(input, ctx);
443+
444+
const expected = {
445+
extends: ['extender-name'],
446+
parserPreset: {
447+
parserOpts: {
448+
issuePrefixes: ['#', '!', '&', 'no-references'],
449+
referenceActions: null,
450+
},
451+
},
452+
zero: 'root',
453+
};
454+
455+
expect(actual).toEqual(expected);
456+
});
457+
458+
test('parserPreset should be merged correctly', () => {
459+
const input = {extends: ['extender-name'], zero: 'root'};
460+
461+
const require = (id: string) => {
462+
switch (id) {
463+
case 'extender-name':
464+
return {
465+
extends: ['recursive-extender-name'],
466+
parserPreset: {
467+
parserOpts: {
468+
referenceActions: null,
469+
},
470+
},
471+
};
472+
case 'recursive-extender-name':
473+
return {parserPreset: {parserOpts: {issuePrefixes: ['#', '!']}}};
474+
default:
475+
return {};
476+
}
477+
};
478+
479+
const ctx = {resolve: id, require: jest.fn(require)} as ResolveExtendsContext;
480+
481+
const actual = resolveExtends(input, ctx);
482+
483+
const expected = {
484+
extends: ['extender-name'],
485+
parserPreset: {
486+
parserOpts: {
487+
issuePrefixes: ['#', '!'],
488+
referenceActions: null,
489+
},
490+
},
491+
zero: 'root',
492+
};
493+
494+
expect(actual).toEqual(expected);
495+
});
496+
497+
test('should correctly merge nested configs', () => {
498+
const input = {extends: ['extender-1']};
499+
500+
const require = (id: string) => {
501+
switch (id) {
502+
case 'extender-1':
503+
return {extends: ['extender-3', 'extender-2']};
504+
case 'extender-2':
505+
return {extends: ['extender-4']};
506+
case 'extender-3':
507+
return {rules: {test: 3}};
508+
case 'extender-4':
509+
return {extends: ['extender-5', 'extender-6'], rules: {test: 4}};
510+
case 'extender-5':
511+
return {rules: {test: 5}};
512+
case 'extender-6':
513+
return {rules: {test: 6}};
514+
default:
515+
return {};
516+
}
517+
};
518+
519+
const ctx = {resolve: id, require: jest.fn(require)} as ResolveExtendsContext;
520+
521+
const actual = resolveExtends(input, ctx);
522+
523+
const expected = {
524+
extends: ['extender-1'],
525+
rules: {
526+
test: 4,
527+
},
528+
};
529+
530+
expect(actual).toEqual(expected);
531+
});

‎@commitlint/resolve-extends/src/index.ts

+10-7
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ export interface ResolvedConfig {
1313
}
1414

1515
export interface ResolveExtendsConfig {
16-
parserPreset?: unknown;
1716
extends?: string | string[];
1817
helpUrl?: string;
1918
[key: string]: unknown;
@@ -31,19 +30,23 @@ export interface ResolveExtendsContext {
3130
export default function resolveExtends(
3231
config: ResolveExtendsConfig = {},
3332
context: ResolveExtendsContext = {}
34-
) {
33+
): ResolvedConfig {
3534
const {extends: e} = config;
36-
const extended = loadExtends(config, context).reduce(
35+
const extended = loadExtends(config, context);
36+
extended.push(config);
37+
return extended.reduce(
3738
(r, {extends: _, ...c}) =>
38-
mergeWith(r, c, (objValue, srcValue) => {
39-
if (Array.isArray(objValue)) {
39+
mergeWith(r, c, (objValue, srcValue, key) => {
40+
if (key === 'plugins') {
41+
if (Array.isArray(objValue)) {
42+
return objValue.concat(srcValue);
43+
}
44+
} else if (Array.isArray(objValue)) {
4045
return srcValue;
4146
}
4247
}),
4348
e ? {extends: e} : {}
4449
);
45-
46-
return merge({}, extended, config);
4750
}
4851

4952
function loadExtends(

‎@commitlint/types/src/load.ts

+7-7
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,10 @@ export interface LoadOptions {
2121
}
2222

2323
export interface UserConfig {
24-
extends?: string[];
24+
extends?: string | string[];
2525
formatter?: string;
2626
rules?: Partial<RulesConfig>;
27-
parserPreset?: string | ParserPreset;
27+
parserPreset?: string | ParserPreset | Promise<ParserPreset>;
2828
ignores?: ((commit: string) => boolean)[];
2929
defaultIgnores?: boolean;
3030
plugins?: (string | Plugin)[];
@@ -49,16 +49,16 @@ export interface QualifiedConfig {
4949
extends: string[];
5050
formatter: string;
5151
rules: QualifiedRules;
52-
parserPreset: ParserPreset;
53-
ignores: ((commit: string) => boolean)[];
54-
defaultIgnores: boolean;
52+
parserPreset?: ParserPreset;
53+
ignores?: ((commit: string) => boolean)[];
54+
defaultIgnores?: boolean;
5555
plugins: PluginRecords;
5656
helpUrl: string;
5757
prompt: UserPromptConfig;
5858
}
5959

6060
export interface ParserPreset {
61-
name: string;
62-
path: string;
61+
name?: string;
62+
path?: string;
6363
parserOpts?: unknown;
6464
}

0 commit comments

Comments
 (0)
Please sign in to comment.