Skip to content

Commit

Permalink
feat(load): accept functions as parser presets
Browse files Browse the repository at this point in the history
Previously, `load` could accept `parserPresets` as both values and promises of
values. Per conventional-changelog#2964 however, there was expectations for it to also support
functions returning said values.

This commit enables to specify `parserPresets` in all the same ways as
rules. That is, both commitlint rules and `parserPresets` can be specified as:

- Plain values
- Promises
- Functions returning plain values
- Functions returning promises

Solves conventional-changelog#2964.
  • Loading branch information
Zirak committed Jan 19, 2022
1 parent 0a0848d commit 3790afb
Show file tree
Hide file tree
Showing 4 changed files with 69 additions and 2 deletions.
Expand Up @@ -56,6 +56,7 @@ exports[`validation should fail for parserPreset 1`] = `
"Commitlint configuration in parserPreset.js is invalid:
- Property \\"parserPreset\\" has the wrong type - should be string.
- Property \\"parserPreset\\" has the wrong type - should be object.
- \\"parserPreset\\" should be a function. Value: [].
- \\"parserPreset\\" should match exactly one schema in oneOf. Value: [].
"
`;
Expand Down
3 changes: 2 additions & 1 deletion @commitlint/config-validator/src/commitlint.schema.json
Expand Up @@ -57,7 +57,8 @@
"parserOpts": {}
},
"additionalProperties": true
}
},
{"typeof": "function"}
]
},
"helpUrl": {
Expand Down
55 changes: 55 additions & 0 deletions @commitlint/load/src/utils/load-parser-opts.test.ts
@@ -0,0 +1,55 @@
import {loadParserOpts} from './load-parser-opts';

test('handles a plain preset', async () => {
const preset = {
parserOpts: {},
};

expect(await loadParserOpts(preset)).toEqual(preset);
});

test('handles primitive values', async () => {
expect(await loadParserOpts('')).toEqual(undefined);
expect(await loadParserOpts(undefined)).toEqual(undefined);
});

test('handles an object without any parserOpts', async () => {
const preset = {};
expect(await loadParserOpts(preset)).toEqual(preset);
});

test('handles nested parserOpts', async () => {
const opts = {a: 4};

// plain nested parserOpts
let loaded = await loadParserOpts({
parserOpts: {
parserOpts: opts,
},
});
expect(loaded).toHaveProperty('parserOpts', opts);

// async nested parserOpts
loaded = await loadParserOpts({
parserOpts: Promise.resolve({
parserOpts: opts,
}),
});
expect(loaded).toHaveProperty('parserOpts', opts);
});

test('runs a sync function which returns the preset', async () => {
const preset = {};
const fn = () => preset;
const opts = await loadParserOpts(fn);

expect(opts).toEqual(preset);
});

test('runs an async function which returns the preset', async () => {
const preset = {};
const fn = async () => preset;
const opts = await loadParserOpts(fn);

expect(opts).toEqual(preset);
});
12 changes: 11 additions & 1 deletion @commitlint/load/src/utils/load-parser-opts.ts
@@ -1,5 +1,7 @@
import {ParserPreset} from '@commitlint/types';

type Awaitable<T> = T | PromiseLike<T>;

function isObjectLike(obj: unknown): obj is Record<string, unknown> {
return Boolean(obj) && typeof obj === 'object'; // typeof null === 'object'
}
Expand All @@ -15,8 +17,16 @@ function isParserOptsFunction<T extends ParserPreset>(
}

export async function loadParserOpts(
pendingParser: string | ParserPreset | Promise<ParserPreset> | undefined
pendingParser:
| string
| Awaitable<ParserPreset>
| (() => Awaitable<ParserPreset>)
| undefined
): Promise<ParserPreset | undefined> {
if (typeof pendingParser === 'function') {
return loadParserOpts(pendingParser());
}

if (!pendingParser || typeof pendingParser !== 'object') {
return undefined;
}
Expand Down

0 comments on commit 3790afb

Please sign in to comment.