diff --git a/docs/config/engineer.md b/docs/config/engineer.md index 326d63878..b8664f763 100644 --- a/docs/config/engineer.md +++ b/docs/config/engineer.md @@ -173,7 +173,7 @@ export interface GenerateAIPromptType { type: string defaultScope?: string maxSubjectLength?: number - upperCaseSubject?: boolean + upperCaseSubject?: boolean | null diff?: string } ``` @@ -188,8 +188,11 @@ module.exports = { ## upperCaseSubject - **description** : Whether to automatically capitalize the first character of the short description (subject) -- **type** : `boolean` -- **default** : `false` +- **type** : `boolean` | `null` + - `null`: Do not process + - `true`: Automatically capitalize the first letter + - `false`: Automatically lowercase the first letter +- **default** : `null` ## breaklineNumber diff --git a/docs/public/schema/cz-git.json b/docs/public/schema/cz-git.json index 24d047652..30976e03e 100644 --- a/docs/public/schema/cz-git.json +++ b/docs/public/schema/cz-git.json @@ -180,9 +180,12 @@ "default": "empty" }, "upperCaseSubject": { - "type": "boolean", - "description": "Subject is need upper case first.", - "default": false + "type": [ + "boolean", + "null" + ], + "description": "Subject is need upper case first.\n\n- `null`: Do not enforce capitalization of the first letter\n- `true`: Enforce capitalization of the first letter\n- `false`: Enforce lowercase for the first letter", + "default": null }, "markBreakingChangeMode": { "type": "boolean", diff --git a/docs/snippets/.commitlintrc b/docs/snippets/.commitlintrc index 923a32798..ad810b386 100644 --- a/docs/snippets/.commitlintrc +++ b/docs/snippets/.commitlintrc @@ -42,7 +42,7 @@ "customScopesAlign": "bottom", "customScopesAlias": "custom", "emptyScopesAlias": "empty", - "upperCaseSubject": false, + "upperCaseSubject": null, "markBreakingChangeMode": false, "allowBreakingChanges": ["feat", "fix"], "breaklineNumber": 100, diff --git a/docs/snippets/.czrc b/docs/snippets/.czrc index 59f16fc8c..a026b4e34 100644 --- a/docs/snippets/.czrc +++ b/docs/snippets/.czrc @@ -39,7 +39,7 @@ "customScopesAlign": "bottom", "customScopesAlias": "custom", "emptyScopesAlias": "empty", - "upperCaseSubject": false, + "upperCaseSubject": null, "markBreakingChangeMode": false, "allowBreakingChanges": ["feat", "fix"], "breaklineNumber": 100, diff --git a/docs/snippets/commitlint.config.cjs b/docs/snippets/commitlint.config.cjs index 8566e2ea9..dd0bbbf5c 100644 --- a/docs/snippets/commitlint.config.cjs +++ b/docs/snippets/commitlint.config.cjs @@ -44,7 +44,7 @@ module.exports = defineConfig({ customScopesAlign: 'bottom', customScopesAlias: 'custom', emptyScopesAlias: 'empty', - upperCaseSubject: false, + upperCaseSubject: null, markBreakingChangeMode: false, allowBreakingChanges: ['feat', 'fix'], breaklineNumber: 100, diff --git a/docs/snippets/commitlint.config.cn-en.js b/docs/snippets/commitlint.config.cn-en.js index ba954026c..2a9870c31 100644 --- a/docs/snippets/commitlint.config.cn-en.js +++ b/docs/snippets/commitlint.config.cn-en.js @@ -42,7 +42,7 @@ module.exports = defineConfig({ customScopesAlign: 'bottom', customScopesAlias: 'custom', emptyScopesAlias: 'empty', - upperCaseSubject: false, + upperCaseSubject: null, markBreakingChangeMode: false, allowBreakingChanges: ['feat', 'fix'], breaklineNumber: 100, diff --git a/docs/snippets/commitlint.config.cn.js b/docs/snippets/commitlint.config.cn.js index c3e37b1b4..8b0f236d8 100644 --- a/docs/snippets/commitlint.config.cn.js +++ b/docs/snippets/commitlint.config.cn.js @@ -44,7 +44,7 @@ module.exports = defineConfig({ customScopesAlign: 'bottom', customScopesAlias: '以上都不是?我要自定义', emptyScopesAlias: '跳过', - upperCaseSubject: false, + upperCaseSubject: null, markBreakingChangeMode: false, allowBreakingChanges: ['feat', 'fix'], breaklineNumber: 100, diff --git a/docs/snippets/commitlint.config.emoji.js b/docs/snippets/commitlint.config.emoji.js index 7f6b4c83d..d019c2448 100644 --- a/docs/snippets/commitlint.config.emoji.js +++ b/docs/snippets/commitlint.config.emoji.js @@ -44,7 +44,7 @@ module.exports = defineConfig({ customScopesAlign: 'bottom', customScopesAlias: 'custom', emptyScopesAlias: 'empty', - upperCaseSubject: false, + upperCaseSubject: null, markBreakingChangeMode: false, allowBreakingChanges: ['feat', 'fix'], breaklineNumber: 100, diff --git a/docs/snippets/commitlint.config.mjs b/docs/snippets/commitlint.config.mjs index 4fbd4581c..c36ff7b5f 100644 --- a/docs/snippets/commitlint.config.mjs +++ b/docs/snippets/commitlint.config.mjs @@ -44,7 +44,7 @@ export default defineConfig({ customScopesAlign: 'bottom', customScopesAlias: 'custom', emptyScopesAlias: 'empty', - upperCaseSubject: false, + upperCaseSubject: null, markBreakingChangeMode: false, allowBreakingChanges: ['feat', 'fix'], breaklineNumber: 100, diff --git a/docs/snippets/commitlint.config.without-fn.cjs b/docs/snippets/commitlint.config.without-fn.cjs index 46c32a568..cac5fc771 100644 --- a/docs/snippets/commitlint.config.without-fn.cjs +++ b/docs/snippets/commitlint.config.without-fn.cjs @@ -43,7 +43,7 @@ module.exports = { customScopesAlign: 'bottom', customScopesAlias: 'custom', emptyScopesAlias: 'empty', - upperCaseSubject: false, + upperCaseSubject: null, markBreakingChangeMode: false, allowBreakingChanges: ['feat', 'fix'], breaklineNumber: 100, diff --git a/docs/snippets/commitlint.config.without-fn.mjs b/docs/snippets/commitlint.config.without-fn.mjs index 9c517c244..f039cec93 100644 --- a/docs/snippets/commitlint.config.without-fn.mjs +++ b/docs/snippets/commitlint.config.without-fn.mjs @@ -43,7 +43,7 @@ export default { customScopesAlign: 'bottom', customScopesAlias: 'custom', emptyScopesAlias: 'empty', - upperCaseSubject: false, + upperCaseSubject: null, markBreakingChangeMode: false, allowBreakingChanges: ['feat', 'fix'], breaklineNumber: 100, diff --git a/docs/snippets/cz.config.cjs b/docs/snippets/cz.config.cjs index ec64ef037..00923559b 100644 --- a/docs/snippets/cz.config.cjs +++ b/docs/snippets/cz.config.cjs @@ -40,7 +40,7 @@ module.exports = definePrompt({ customScopesAlign: 'bottom', customScopesAlias: 'custom', emptyScopesAlias: 'empty', - upperCaseSubject: false, + upperCaseSubject: null, markBreakingChangeMode: false, allowBreakingChanges: ['feat', 'fix'], breaklineNumber: 100, diff --git a/docs/snippets/cz.config.mjs b/docs/snippets/cz.config.mjs index 6fe0ecc3d..d7b913ebe 100644 --- a/docs/snippets/cz.config.mjs +++ b/docs/snippets/cz.config.mjs @@ -40,7 +40,7 @@ export default definePrompt({ customScopesAlign: 'bottom', customScopesAlias: 'custom', emptyScopesAlias: 'empty', - upperCaseSubject: false, + upperCaseSubject: null, markBreakingChangeMode: false, allowBreakingChanges: ['feat', 'fix'], breaklineNumber: 100, diff --git a/docs/snippets/cz.config.without-fn.cjs b/docs/snippets/cz.config.without-fn.cjs index 859ee0700..fbb92ed95 100644 --- a/docs/snippets/cz.config.without-fn.cjs +++ b/docs/snippets/cz.config.without-fn.cjs @@ -39,7 +39,7 @@ module.exports = { customScopesAlign: 'bottom', customScopesAlias: 'custom', emptyScopesAlias: 'empty', - upperCaseSubject: false, + upperCaseSubject: null, markBreakingChangeMode: false, allowBreakingChanges: ['feat', 'fix'], breaklineNumber: 100, diff --git a/docs/snippets/cz.config.without-fn.mjs b/docs/snippets/cz.config.without-fn.mjs index ea6249174..3517af702 100644 --- a/docs/snippets/cz.config.without-fn.mjs +++ b/docs/snippets/cz.config.without-fn.mjs @@ -39,7 +39,7 @@ export default { customScopesAlign: 'bottom', customScopesAlias: 'custom', emptyScopesAlias: 'empty', - upperCaseSubject: false, + upperCaseSubject: null, markBreakingChangeMode: false, allowBreakingChanges: ['feat', 'fix'], breaklineNumber: 100, diff --git a/docs/zh/config/engineer.md b/docs/zh/config/engineer.md index 281fc8941..2c2cd1cd2 100644 --- a/docs/zh/config/engineer.md +++ b/docs/zh/config/engineer.md @@ -178,7 +178,7 @@ export interface GenerateAIPromptType { type: string defaultScope?: string maxSubjectLength?: number - upperCaseSubject?: boolean + upperCaseSubject?: boolean | null diff?: string } ``` @@ -209,8 +209,11 @@ module.exports = { ## upperCaseSubject - **描述** : 是否自动将 简短描述subject 第一个字符进行大写处理 -- **类型** : `boolean` -- **默认** : `false` +- **类型** : `boolean` | `null` + - `null`: 不进行处理 + - `true`: 首字母自动大写 + - `false`: 首字母自动小写 +- **默认** : `null` ## breaklineNumber diff --git a/packages/cz-git/src/generator/api.ts b/packages/cz-git/src/generator/api.ts index bbb575187..d13e4cbb3 100644 --- a/packages/cz-git/src/generator/api.ts +++ b/packages/cz-git/src/generator/api.ts @@ -2,7 +2,7 @@ import url from 'node:url' import process from 'node:process' import { style } from '@cz-git/inquirer' import HttpsProxyAgent from 'https-proxy-agent' -import { isNodeVersionInRange, log } from '../shared' +import { isNodeVersionInRange, log, transformSubjectCase } from '../shared' import type { CommitizenGitOptions } from '../shared' export async function fetchOpenAIMessage(options: CommitizenGitOptions, prompt: string) { @@ -88,20 +88,14 @@ function useModelStrategy(options: CommitizenGitOptions, prompt: string) { function parseAISubject(options: CommitizenGitOptions, subject?: string) { if (!subject) return '' - - subject = subject - .trim() - .replace(/(\r\n|\n|\r)/g, '') - .replace(/[.。]$/, '') - .replace(/^"|"$/g, '') - let res = subject - if (options.upperCaseSubject) - res = res.charAt(0).toUpperCase() - else - res = res.charAt(0).toLowerCase() - res = res + subject.slice(1) - - return res + return transformSubjectCase( + options, + subject + .trim() + .replace(/(\r\n|\n|\r)/g, '') + .replace(/[.。]$/, '') + .replace(/^"|"$/g, ''), + ) } class APIError extends Error { diff --git a/packages/cz-git/src/generator/question.ts b/packages/cz-git/src/generator/question.ts index 1f0d3425e..875cc88cb 100644 --- a/packages/cz-git/src/generator/question.ts +++ b/packages/cz-git/src/generator/question.ts @@ -19,6 +19,7 @@ import { parseStandardScopes, resolveListItemPinTop, resovleCustomListTemplate, + transformSubjectCase, useThemeCode, } from '../shared' @@ -174,37 +175,28 @@ export function generateQuestions(options: CommitizenGitOptions, cz: any) { tooltip = `${maxSubjectLength - subjectLength} more chars allowed` } - tooltip - = ( - minSubjectLength !== undefined - && subjectLength >= minSubjectLength - && subjectLength <= maxSubjectLength - ) - ? style.gray(`[${tooltip}]`) - : isWarning - ? style.yellow(`[${tooltip}]`) - : style.red(`[${tooltip}]`) - subject - = ( - minSubjectLength !== undefined - && subjectLength >= minSubjectLength - && subjectLength <= maxSubjectLength - ) + tooltip = ( + minSubjectLength !== undefined + && subjectLength >= minSubjectLength + && subjectLength <= maxSubjectLength + ) + ? style.gray(`[${tooltip}]`) + : isWarning + ? style.yellow(`[${tooltip}]`) + : style.red(`[${tooltip}]`) + subject = ( + minSubjectLength !== undefined + && subjectLength >= minSubjectLength + && subjectLength <= maxSubjectLength + ) + ? useThemeCode(subject, options.themeColorCode) + : isWarning ? useThemeCode(subject, options.themeColorCode) - : isWarning - ? useThemeCode(subject, options.themeColorCode) - : style.red(subject) + : style.red(subject) return `${tooltip}\n` + ` ${subject}` }, - filter: (subject: string) => { - const upperCaseSubject = options.upperCaseSubject || false - - return ( - (upperCaseSubject ? subject.charAt(0).toUpperCase() : subject.charAt(0).toLowerCase()) - + subject.slice(1) - ) - }, + filter: (subject: string) => transformSubjectCase(options, subject), }, { type: 'complete-input', diff --git a/packages/cz-git/src/shared/types/options.ts b/packages/cz-git/src/shared/types/options.ts index d793edc69..ea368ee99 100644 --- a/packages/cz-git/src/shared/types/options.ts +++ b/packages/cz-git/src/shared/types/options.ts @@ -171,7 +171,7 @@ export interface GenerateAIPromptType { type?: string defaultScope?: string | string[] maxSubjectLength?: number - upperCaseSubject?: boolean + upperCaseSubject?: boolean | null diff?: string } @@ -390,9 +390,12 @@ export interface CommitizenGitOptions { /** * Subject is need upper case first. * - * @default false + * - `null`: Do not process + * - `true`: Automatically capitalize the first letter + * - `false`: Automatically lowercase the first letter + * @default null */ - upperCaseSubject?: boolean + upperCaseSubject?: boolean | null /** * Whether to add extra prompt BREAKCHANGE ask. to add an extra "!" to the header @@ -653,7 +656,7 @@ export const defaultConfig = Object.freeze({ customScopesAlign: 'bottom', customScopesAlias: 'custom', emptyScopesAlias: 'empty', - upperCaseSubject: false, + upperCaseSubject: null, markBreakingChangeMode: false, allowBreakingChanges: ['feat', 'fix'], breaklineNumber: 100, diff --git a/packages/cz-git/src/shared/utils/util.ts b/packages/cz-git/src/shared/utils/util.ts index 4ea4ecc6c..ed44144e7 100644 --- a/packages/cz-git/src/shared/utils/util.ts +++ b/packages/cz-git/src/shared/utils/util.ts @@ -86,6 +86,7 @@ export function parseStandardScopes(scopes: ScopesType): Option[] { : { value: scope.value, name: scope.name } }) } + /** * To get a list of scopes * @@ -197,6 +198,18 @@ export function getProcessSubject(text: string) { return text.replace(/(^\s+|[\s.]+$)/g, '') ?? '' } +export function transformSubjectCase(options: CommitizenGitOptions, subject: string) { + if (!subject || options.upperCaseSubject === null) + return subject + + const firstChar = subject[0] + const rest = subject.slice(1) + + return options.upperCaseSubject + ? firstChar.toUpperCase() + rest + : firstChar.toLowerCase() + rest +} + function getEmojiStrLength(options: CommitizenGitOptions, type?: string): number { const item = options.types?.find((i: { value?: string }) => i.value === type) // 1: space diff --git a/scripts/czrc-schema.d.ts b/scripts/czrc-schema.d.ts index 5efd038cd..6f63956dd 100644 --- a/scripts/czrc-schema.d.ts +++ b/scripts/czrc-schema.d.ts @@ -182,9 +182,12 @@ export interface CommitizenGitOptions { /** * Subject is need upper case first. * - * @default false + * - `null`: Do not process + * - `true`: Automatically capitalize the first letter + * - `false`: Automatically lowercase the first letter + * @default null */ - upperCaseSubject?: boolean + upperCaseSubject?: boolean | null /** * Whether to add extra prompt BREAKCHANGE ask. to add an extra "!" to the header