From e9c8edcc5fbe3d2c5b7615bca58f25dcb6eb8780 Mon Sep 17 00:00:00 2001 From: mehboodian Date: Tue, 30 Mar 2021 19:19:34 +0430 Subject: [PATCH 1/4] test: add choicesFactory scope-empty rule tests add tests for commitlint 'scope-empty' rule choice builder --- src/prompts/scope-maker.test.ts | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/src/prompts/scope-maker.test.ts b/src/prompts/scope-maker.test.ts index ba86645..424126c 100644 --- a/src/prompts/scope-maker.test.ts +++ b/src/prompts/scope-maker.test.ts @@ -1,6 +1,6 @@ import { ListQuestion } from 'inquirer'; import { Rule, Case, Level, Rules } from '@commitlint/load'; -import { scopeMaker, filterFactory, validatorFactory } from './scope-maker'; +import { scopeMaker, filterFactory, validatorFactory, choicesFactory } from './scope-maker'; describe('scopeMaker', () => { describe('validatorFactory', () => { @@ -54,7 +54,7 @@ describe('scopeMaker', () => { }); describe('choices', () => { - test('should display choices if array scope enum is present', () => { + it('should display choices if array scope enum is present', () => { const scopeConfig = scopeMaker([], { 'scope-enum': [2, 'always', ['foo', 'bar']] })[0] as ListQuestion; if (scopeConfig.choices) { @@ -76,6 +76,24 @@ describe('scopeMaker', () => { }); }); + describe('choicesFactory', () => { + it('should not allow non-empty scope when empty scope is required', () => { + const scopeConfig = choicesFactory({ + 'scope-empty': [2, 'always', undefined] + }); + + expect(scopeConfig).toEqual([{ name: ':skip', value: '' }]); + }); + + it('should not allow skipping scope when is required', () => { + const scopeConfig = choicesFactory({ + 'scope-empty': [2, 'never', undefined] + }); + + expect(scopeConfig).not.toContainEqual({ name: ':skip', value: '' }); + }); + }); + describe('filterFactory', () => { test.each<[Rule, string, string]>([ [[Level.Error, 'always', 'camel-case'], 'FOO_BAR', 'fooBar'], From a2c2593ed39003a2c7b90470fedaed01b717ceab Mon Sep 17 00:00:00 2001 From: mehboodian Date: Tue, 30 Mar 2021 19:20:31 +0430 Subject: [PATCH 2/4] fix(scope-maker): exclude skip choice when required --- src/prompts/scope-maker.ts | 40 +++++++++++++++++++++++++++++++------- 1 file changed, 33 insertions(+), 7 deletions(-) diff --git a/src/prompts/scope-maker.ts b/src/prompts/scope-maker.ts index 337ea0e..8978cef 100644 --- a/src/prompts/scope-maker.ts +++ b/src/prompts/scope-maker.ts @@ -1,4 +1,4 @@ -import { Rules } from '@commitlint/load'; +import { Rules, Level } from '@commitlint/load'; import { ChoiceOptions } from 'inquirer'; import { whenFactory } from '../when'; import { caseValidator, emptyValidator, maxLengthValidator, minLengthValidator, validate } from '../validators'; @@ -36,13 +36,39 @@ export function validatorFactory(rules: Rules) { }; } -export function choicesFactory(rules: Rules) { - let choices: ChoiceOptions[] | undefined; - if (rules['scope-enum']) { - const [, , scopeEnum] = rules['scope-enum']; - if (scopeEnum && scopeEnum.length > 0) { - choices = [...scopeEnum.map(scope => ({ name: scope, value: scope })), { name: ':skip', value: '' }]; +function parseEmptyScopeRule(rule: Rules['scope-empty']): [boolean, ChoiceOptions | undefined] { + const skipChoice: ChoiceOptions = { name: ':skip', value: '' }; + if (rule !== undefined) { + const [level, applicability] = rule; + if (level === Level.Error) { + if (applicability === 'always') { + return [true, skipChoice]; + } } + return [false, undefined]; + } + return [true, skipChoice]; +} + +function parseScopeEnumRule(rule: Rules['scope-enum']): [boolean, ChoiceOptions[] | undefined] { + if (rule !== undefined) { + const [, , scopeEnum] = rule; + return [true, scopeEnum.map(scope => ({ name: scope, value: scope }))]; + } + return [false, undefined]; +} + +export function choicesFactory(rules: Rules): ChoiceOptions[] | undefined { + const choices: ChoiceOptions[] = []; + + const [containsSkipChoice, skipChoice] = parseEmptyScopeRule(rules['scope-empty']); + if (containsSkipChoice) { + choices.push(skipChoice as ChoiceOptions); + } + + const [containsScopeEnumChoices, scopeEnumChoices] = parseScopeEnumRule(rules['scope-enum']); + if (containsScopeEnumChoices) { + choices.unshift(...(scopeEnumChoices as ChoiceOptions[])); } return choices; From d779043fd9743f90826c9dae1d6d6b2d5a415ef4 Mon Sep 17 00:00:00 2001 From: mehboodian Date: Tue, 30 Mar 2021 19:31:51 +0430 Subject: [PATCH 3/4] test(scope-maker): add scope-empty non-error tests add tests for scope-empty rule with `disabled` and `warn` severity levels --- src/prompts/scope-maker.test.ts | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/prompts/scope-maker.test.ts b/src/prompts/scope-maker.test.ts index 424126c..805b4d5 100644 --- a/src/prompts/scope-maker.test.ts +++ b/src/prompts/scope-maker.test.ts @@ -94,6 +94,20 @@ describe('scopeMaker', () => { }); }); + it('should allow skipping scope when "scope-empty" severity is "warn"', () => { + const scopeConfig = choicesFactory({ + 'scope-empty': [1, 'always', undefined] + }); + + expect(scopeConfig).toContainEqual({ name: ':skip', value: '' }); + }); + + it('should allow skipping scope when "scope-empty" rule is not set', () => { + const scopeConfig = choicesFactory({}); + + expect(scopeConfig).toContainEqual({ name: ':skip', value: '' }); + }); + describe('filterFactory', () => { test.each<[Rule, string, string]>([ [[Level.Error, 'always', 'camel-case'], 'FOO_BAR', 'fooBar'], From de49e6ee3eca333c9f5be48194634719670e9b56 Mon Sep 17 00:00:00 2001 From: mehboodian Date: Tue, 30 Mar 2021 19:32:21 +0430 Subject: [PATCH 4/4] fix(scope-maker): allow skipping scope when rule not set --- src/prompts/scope-maker.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/prompts/scope-maker.ts b/src/prompts/scope-maker.ts index 8978cef..dd0bb63 100644 --- a/src/prompts/scope-maker.ts +++ b/src/prompts/scope-maker.ts @@ -44,8 +44,8 @@ function parseEmptyScopeRule(rule: Rules['scope-empty']): [boolean, ChoiceOption if (applicability === 'always') { return [true, skipChoice]; } + return [false, undefined]; } - return [false, undefined]; } return [true, skipChoice]; }