Skip to content

Commit

Permalink
fix(cz-git,czg): add ignore commitlint warning max length rule #72 (c…
Browse files Browse the repository at this point in the history
…losed #71)

like `'subject-max-length': [1, 'always', 72]`
the array 1 mean warning.commitlint not prevent commit.
so that `cz-git` will just provide prompt expect words msg.

Co-authored-by: JoaoEdu93 <JoaoEdu93@users.noreply.github.com>
Co-authored-by: Zhengqbbb <1074059947@qq.com>
  • Loading branch information
3 people committed Oct 20, 2022
1 parent 2101280 commit 46346b4
Show file tree
Hide file tree
Showing 6 changed files with 143 additions and 91 deletions.
4 changes: 2 additions & 2 deletions packages/cz-git/src/generator/message.ts
Expand Up @@ -5,7 +5,7 @@
*/

import { style } from '@cz-git/inquirer'
import { getCurrentScopes, handleStandardScopes, isSingleItem, wrap } from '../shared'
import { getCurrentScopes, isSingleItem, parseStandardScopes, wrap } from '../shared'
import type { Answers, CommitizenGitOptions } from '../shared'

export const getAliasMessage = (config: CommitizenGitOptions, alias?: string) => {
Expand All @@ -27,7 +27,7 @@ const getSingleParams = (answers: Answers, options: CommitizenGitOptions) => {
singleScope: '',
singeIssuePrefix: '',
}
const scopeList = handleStandardScopes(
const scopeList = parseStandardScopes(
getCurrentScopes(options.scopes, options.scopeOverrides, answers.type),
)
if (isSingleItem(options.allowCustomScopes, options.allowEmptyScopes, scopeList))
Expand Down
4 changes: 4 additions & 0 deletions packages/cz-git/src/generator/option.ts
Expand Up @@ -11,6 +11,7 @@ import {
getEnumList,
getMaxLength,
getMinLength,
ruleIsWarning,
} from '../shared'
import type { CommitizenGitOptions, UserConfig } from '../shared'

Expand Down Expand Up @@ -54,6 +55,9 @@ export const generateOptions = (config: UserConfig): CommitizenGitOptions => {
confirmColorize: promptConfig.confirmColorize ?? defaultConfig.confirmColorize,
maxHeaderLength: promptConfig.maxHeaderLength ?? getMaxLength(config?.rules?.['header-max-length'] as any),
maxSubjectLength: promptConfig.maxSubjectLength ?? getMaxLength(config?.rules?.['subject-max-length'] as any),
isIgnoreCheckMaxSubjectLength: promptConfig.isIgnoreCheckMaxSubjectLength
|| ruleIsWarning(config?.rules?.['subject-max-length'] as any)
|| ruleIsWarning(config?.rules?.['header-max-length'] as any),
minSubjectLength: promptConfig.minSubjectLength ?? getMinLength(config?.rules?.['subject-min-length'] as any),
defaultType: promptConfig.defaultType ?? defaultConfig.defaultType,
defaultScope: promptConfig.defaultScope ?? defaultConfig.defaultScope,
Expand Down
46 changes: 29 additions & 17 deletions packages/cz-git/src/generator/question.ts
Expand Up @@ -10,11 +10,11 @@ import {
getCurrentScopes,
getMaxSubjectLength,
getProcessSubject,
handleCustomTemplate,
handlePinListTop,
handleStandardScopes,
isSingleItem,
log,
parseStandardScopes,
resolveListItemPinTop,
resovleCustomListTemplate,
} from '../shared'
import { generateMessage } from './message'

Expand All @@ -35,7 +35,7 @@ export const generateQuestions = (options: CommitizenGitOptions, cz: any) => {
message: options.messages?.type,
themeColorCode: options?.themeColorCode,
source: (_: unknown, input: string) => {
const typeSource = handlePinListTop(
const typeSource = resolveListItemPinTop(
options.types?.concat(options.typesAppend || []) || [],
options.defaultType,
)
Expand All @@ -53,10 +53,10 @@ export const generateQuestions = (options: CommitizenGitOptions, cz: any) => {
separator: options.scopeEnumSeparator,
source: (answer: Answers, input: string) => {
let scopeSource: Option[] = []
scopeSource = handleStandardScopes(
scopeSource = parseStandardScopes(
getCurrentScopes(options.scopes, options.scopeOverrides, answer.type),
)
scopeSource = handleCustomTemplate(
scopeSource = resovleCustomListTemplate(
scopeSource,
cz,
options.customScopesAlign,
Expand All @@ -82,7 +82,7 @@ export const generateQuestions = (options: CommitizenGitOptions, cz: any) => {
return !isSingleItem(
options.allowCustomScopes,
options.allowEmptyScopes,
handleStandardScopes(
parseStandardScopes(
getCurrentScopes(options.scopes, options.scopeOverrides, answer.type),
),
)
Expand Down Expand Up @@ -126,34 +126,46 @@ export const generateQuestions = (options: CommitizenGitOptions, cz: any) => {
)
}
if (processedSubject.length > maxSubjectLength) {
return style.red(
return options.isIgnoreCheckMaxSubjectLength
? true
: style.red(
`[ERROR]subject length must be less than or equal to ${maxSubjectLength} characters`,
)
)
}
return true
},
transformer: (subject: string, answers: Answers) => {
const { minSubjectLength } = options
const { minSubjectLength, isIgnoreCheckMaxSubjectLength } = options
const subjectLength = subject.length
const maxSubjectLength = getMaxSubjectLength(answers.type, answers.scope, options)
let tooltip
if (minSubjectLength !== undefined && subjectLength < minSubjectLength)
let isWarning = false
if (typeof minSubjectLength === 'number' && subjectLength < minSubjectLength) {
tooltip = `${minSubjectLength - subjectLength} more chars needed`
else if (subjectLength > maxSubjectLength)
tooltip = `${subjectLength - maxSubjectLength} chars over the limit`
else tooltip = `${maxSubjectLength - subjectLength} more chars allowed`
}
else if (subjectLength > maxSubjectLength) {
if (isIgnoreCheckMaxSubjectLength) {
tooltip = `${subjectLength - maxSubjectLength} chars over the expected`
isWarning = true
}
else { tooltip = `${subjectLength - maxSubjectLength} chars over the limit` }
}
else {
tooltip = `${maxSubjectLength - subjectLength} more chars allowed`
}

tooltip
= minSubjectLength !== undefined
&& subjectLength >= minSubjectLength
&& subjectLength <= maxSubjectLength
? style.gray(`[${tooltip}]`)
: style.red(`[${tooltip}]`)
: isWarning ? style.yellow(`[${tooltip}]`) : style.red(`[${tooltip}]`)
subject
= minSubjectLength !== undefined
&& subjectLength >= minSubjectLength
&& subjectLength <= maxSubjectLength
? useThemeCode(subject, options.themeColorCode)
: style.red(subject)
: isWarning ? useThemeCode(subject, options.themeColorCode) : style.red(subject)

return `${tooltip}\n` + ` ${subject}`
},
Expand Down Expand Up @@ -205,7 +217,7 @@ export const generateQuestions = (options: CommitizenGitOptions, cz: any) => {
message: options.messages?.footerPrefixsSelect,
themeColorCode: options?.themeColorCode,
source: (_: Answers, input: string) => {
const issuePrefixSource = handleCustomTemplate(
const issuePrefixSource = resovleCustomListTemplate(
options.issuePrefixs as Option[],
cz,
options.customIssuePrefixsAlign,
Expand Down
9 changes: 9 additions & 0 deletions packages/cz-git/src/shared/types/options.ts
Expand Up @@ -353,6 +353,14 @@ export interface CommitizenGitOptions {
*/
maxSubjectLength?: number

/**
* @description: Is not strict subject rule. Just provide prompt word length warning.
* Effected maxHeader and maxSubject commlitlint
* @example [1, 'always', 80] 1: mean warning. will be true
* @default: false
*/
isIgnoreCheckMaxSubjectLength?: boolean

/**
* @description: Force set header width.
* @note it auto check rule "subject-min-length" set the option with `@commitlint`.
Expand Down Expand Up @@ -470,6 +478,7 @@ export const defaultConfig = Object.freeze({
confirmColorize: true,
maxHeaderLength: Infinity,
maxSubjectLength: Infinity,
isIgnoreCheckMaxSubjectLength: false,
minSubjectLength: 0,
scopeOverrides: undefined,
scopeFilters: ['.DS_Store'],
Expand Down
15 changes: 14 additions & 1 deletion packages/cz-git/src/shared/utils/rule.ts
Expand Up @@ -22,6 +22,19 @@ export function ruleIsDisabled(rule: Rule): rule is Readonly<[RuleConfigSeverity
return false
}

/**
* @description: rule is Warning
* @example: ruleIsDisabled([0]) => false
* @example: ruleIsDisabled([1]) => true
* @example: ruleIsDisabled([2]) => false
*/
export function ruleIsWarning(rule?: Rule): rule is Readonly<[RuleConfigSeverity.Disabled]> {
if (rule && Array.isArray(rule) && rule[0] === RuleConfigSeverity.Warning)
return true

return false
}

/**
* @description: rule is use
* @example: ruleIsActive([0]) => false
Expand Down Expand Up @@ -51,7 +64,7 @@ export function ruleIsNotApplicable(
}

/**
* @description: rule is can ignore
* @description: rule is not can be ignore
*/
export function ruleIsApplicable(
rule: Rule,
Expand Down
156 changes: 85 additions & 71 deletions packages/cz-git/src/shared/utils/util.ts
Expand Up @@ -16,48 +16,18 @@ export function log(type: 'info' | 'warm' | 'err', msg: string) {
console.info(`${colorMapping[type]}[${type}]>>>: ${msg}${colorMapping.reset}`)
}

export const getProcessSubject = (text: string) => {
return text.replace(/(^[\s]+|[\s\.]+$)/g, '') ?? ''
}

const getEmojiStrLength = (options: CommitizenGitOptions, type?: string): number => {
const item = options.types?.find((i: { value?: string }) => i.value === type)
// space
return item?.emoji ? item.emoji.length + 1 : 0
}

/**
* @description: count header length
*
* {2}: mean ': '
*/
const countLength = (target: number, typeLength: number, scope: number, emojiLength: number) =>
target - typeLength - 2 - scope - emojiLength

export const getMaxSubjectLength = (
type: Answers['type'],
scope: Answers['scope'],
options: CommitizenGitOptions,
) => {
let optionMaxLength = Infinity
if (Array.isArray(scope))
scope = scope.join(options.scopeEnumSeparator)
const typeLength = type?.length ? type.length : 0
const scopeLength = scope ? scope.length + 2 : 0
const emojiLength = options.useEmoji ? getEmojiStrLength(options, type) : 0
const maxHeaderLength = options?.maxHeaderLength ? options?.maxHeaderLength : Infinity
const maxSubjectLength = options?.maxSubjectLength ? options?.maxSubjectLength : Infinity
if (options?.maxHeaderLength === 0 || options?.maxSubjectLength === 0) {
return 0
}
else if (maxHeaderLength === Infinity) {
return maxSubjectLength !== Infinity ? maxSubjectLength : Infinity
}
else {
optionMaxLength
= countLength(maxHeaderLength, typeLength, scopeLength, emojiLength) < maxSubjectLength
? maxHeaderLength
: maxSubjectLength
}
return countLength(optionMaxLength, typeLength, scopeLength, emojiLength)
}

export const handlePinListTop = (
/**
* @description: resolve list item pin top
*/
export const resolveListItemPinTop = (
arr: {
name: string
value: any
Expand All @@ -72,6 +42,40 @@ export const handlePinListTop = (
return [arr[index], ...arr.slice(0, index), ...arr.slice(index + 1)]
}

/**
* @description: check scope list and issuePrefix is only single item (scope, issuePrefix)
*/
export const isSingleItem = (allowCustom = true, allowEmpty = true, list: Array<any> = []) =>
!allowCustom && !allowEmpty && Array.isArray(list) && list.length === 1

/**
* @description: parse scope configuration option to standard options
*/
export const parseStandardScopes = (scopes: ScopesType): Option[] => {
return scopes.map((scope) => {
return typeof scope === 'string'
? { name: scope, value: scope }
: !scope.value
? { value: scope.name, ...scope }
: { value: scope.value, name: scope.name }
})
}

export const getCurrentScopes = (
scopes?: any[],
scopeOverrides?: { [x: string]: any[] },
answerType?: string,
) => {
let result = []
if (scopeOverrides && answerType && scopeOverrides[answerType])
result = scopeOverrides[answerType]

else if (Array.isArray(scopes))
result = scopes

return result
}

const filterCustomEmptyByOption = (
target: {
name: string
Expand All @@ -83,11 +87,13 @@ const filterCustomEmptyByOption = (
target = allowCustom ? target : target.filter(i => i.value !== '___CUSTOM___')
return allowEmpty ? target : target.filter(i => i.value !== false)
}

/**
* @description: add separator custom empty
* @description
* Handle custom list template (types, scopes)
*
* Add separator custom empty
*/
export const handleCustomTemplate = (
export const resovleCustomListTemplate = (
target: Array<{ name: string; value: string }>,
cz: any,
align = 'top',
Expand All @@ -108,7 +114,7 @@ export const handleCustomTemplate = (
}
else if (defaultValue !== '') {
// pin the defaultValue to the top
target = handlePinListTop(target, defaultValue)
target = resolveListItemPinTop(target, defaultValue)
}
// prettier-ignore
switch (align) {
Expand Down Expand Up @@ -141,37 +147,45 @@ export const handleCustomTemplate = (
}

/**
* @description: check scope list and issuePrefix is only single item
* @description: get subject word
*/
export const isSingleItem = (allowCustom = true, allowEmpty = true, list: Array<any> = []) =>
!allowCustom && !allowEmpty && Array.isArray(list) && list.length === 1
export const getProcessSubject = (text: string) => {
return text.replace(/(^[\s]+|[\s\.]+$)/g, '') ?? ''
}

/**
* @description: handle scope configuration option into standard options
* @param {ScopesType}
* @returns {Option[]}
*/
export const handleStandardScopes = (scopes: ScopesType): Option[] => {
return scopes.map((scope) => {
return typeof scope === 'string'
? { name: scope, value: scope }
: !scope.value
? { value: scope.name, ...scope }
: { value: scope.value, name: scope.name }
})
const getEmojiStrLength = (options: CommitizenGitOptions, type?: string): number => {
const item = options.types?.find((i: { value?: string }) => i.value === type)
// 1: space
return item?.emoji ? item.emoji.length + 1 : 0
}

export const getCurrentScopes = (
scopes?: any[],
scopeOverrides?: { [x: string]: any[] },
answerType?: string,
/**
* @description: get max subject length
*/
export const getMaxSubjectLength = (
type: Answers['type'],
scope: Answers['scope'],
options: CommitizenGitOptions,
) => {
let result = []
if (scopeOverrides && answerType && scopeOverrides[answerType])
result = scopeOverrides[answerType]

else if (Array.isArray(scopes))
result = scopes

return result
let optionMaxLength = Infinity
if (Array.isArray(scope))
scope = scope.join(options.scopeEnumSeparator)
const typeLength = type?.length ? type.length : 0
const scopeLength = scope ? scope.length + 2 : 0
const emojiLength = options.useEmoji ? getEmojiStrLength(options, type) : 0
const maxHeaderLength = options?.maxHeaderLength ? options?.maxHeaderLength : Infinity
const maxSubjectLength = options?.maxSubjectLength ? options?.maxSubjectLength : Infinity
if (options?.maxHeaderLength === 0 || options?.maxSubjectLength === 0) {
return 0
}
else if (maxHeaderLength === Infinity) {
return maxSubjectLength !== Infinity ? maxSubjectLength : Infinity
}
else {
optionMaxLength
= countLength(maxHeaderLength, typeLength, scopeLength, emojiLength) < maxSubjectLength
? maxHeaderLength
: maxSubjectLength
}
return countLength(optionMaxLength, typeLength, scopeLength, emojiLength)
}

0 comments on commit 46346b4

Please sign in to comment.