Skip to content

Commit

Permalink
fix(rules): avoid processing strings with case-less Letter category s…
Browse files Browse the repository at this point in the history
…ymbols in `subject-case` (#3586)

* feat(rules): expand Latin-only characters limitation for `subject-case` with Unicode support

* fix(rules): avoid processing strings with case-less Letter category symbols in `subject-case`

Fixes #3585
  • Loading branch information
amariq committed Apr 14, 2023
1 parent 28bc4c7 commit 70a4450
Show file tree
Hide file tree
Showing 2 changed files with 25 additions and 5 deletions.
20 changes: 20 additions & 0 deletions @commitlint/rules/src/subject-case.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ const messages = {
lowercase: 'test: subject',
lowercase_unicode: 'test: тема', // Bulgarian for `subject`
mixedcase: 'test: sUbJeCt',
caseless: 'test: 这是一次提交', // Chinese for `this is a commit`
uppercase: 'test: SUBJECT',
uppercase_unicode: 'test: ÛNDERWERP', // Frisian for `SUBJECT`
camelcase: 'test: subJect',
Expand All @@ -29,6 +30,7 @@ const parsed = {
lowercase: parse(messages.lowercase),
lowercase_unicode: parse(messages.lowercase_unicode),
mixedcase: parse(messages.mixedcase),
caseless: parse(messages.caseless),
uppercase: parse(messages.uppercase),
uppercase_unicode: parse(messages.uppercase_unicode),
camelcase: parse(messages.camelcase),
Expand Down Expand Up @@ -115,6 +117,24 @@ test('with mixedcase subject should fail for "always uppercase"', async () => {
expect(actual).toEqual(expected);
});

test('with caseless subject should succeed for "never sentensecase"', async () => {
const [actual] = subjectCase(await parsed.caseless, 'never', 'sentense-case');
const expected = true;
expect(actual).toEqual(expected);
});

test('with caseless subject should succeed for "never uppercase"', async () => {
const [actual] = subjectCase(await parsed.caseless, 'never', 'upper-case');
const expected = true;
expect(actual).toEqual(expected);
});

test('with caseless subject should succeed for "always uppercase"', async () => {
const [actual] = subjectCase(await parsed.caseless, 'always', 'upper-case');
const expected = true;
expect(actual).toEqual(expected);
});

test('with uppercase subject should fail for "never uppercase"', async () => {
const [actual] = subjectCase(await parsed.uppercase, 'never', 'uppercase');
const expected = false;
Expand Down
10 changes: 5 additions & 5 deletions @commitlint/rules/src/subject-case.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,20 @@ import {TargetCaseType, SyncRule} from '@commitlint/types';

/**
* Since the rule requires first symbol of a subject to be a letter, use
* combination of Unicode `Cased_Letter` and `Other_Letter` categories now to
* allow non-Latin alphabets as well.
* Unicode `Cased_Letter` category now to allow non-Latin alphabets as well.
*
* Do not use `Letter` category directly to avoid capturing `Modifier_Letter`
* (which just modifiers letters, so we probably shouldn't anyway) and to stay
* close to previous implementation.
* (which just modifiers letters, so we probably shouldn't anyway) and
* `Other_Letter` (they actually are case-less, so they can't be validated)
* categories, and to stay close to previous implementation.
*
* Also, typescript does not seem to support almost any longhand category name
* (and even short for `Cased_Letter` too) so list all required letter
* categories manually just to prevent it from complaining about unknown stuff.
*
* @see [Unicode Categories]{@link https://www.regular-expressions.info/unicode.html}
*/
const startsWithLetterRegex = /^[\p{Ll}\p{Lu}\p{Lt}\p{Lo}]/iu;
const startsWithLetterRegex = /^[\p{Ll}\p{Lu}\p{Lt}]/iu;

const negated = (when?: string) => when === 'never';

Expand Down

0 comments on commit 70a4450

Please sign in to comment.