diff --git a/src/cli/commands/commit.js b/src/cli/commands/commit.js index 6fc4928..33eb0b2 100644 --- a/src/cli/commands/commit.js +++ b/src/cli/commands/commit.js @@ -55,6 +55,7 @@ export function createCommitCommand({ config }) { model: config.get('model'), language: config.get('language'), prefixEnabled: config.get('prefixEnabled'), + allowEmojis: config.get('allowEmojis'), }, ) diff --git a/src/cli/commands/emoji.js b/src/cli/commands/emoji.js new file mode 100644 index 0000000..81f4b68 --- /dev/null +++ b/src/cli/commands/emoji.js @@ -0,0 +1,35 @@ +import { select } from '../../services/prompt.js' + +/** + * Create the emoji toggle command handler + * @param {object} deps - Dependencies + * @param {import('../../config/index.js').ConfigManager} deps.config - Config manager + * @returns {Function} The command handler + */ +export function createEmojiCommand({ config }) { + return async function emojiAction() { + const currentEnabled = config.get('allowEmojis') + + console.log( + `Emojis are currently ${currentEnabled ? 'enabled' : 'disabled'}.`, + ) + + const choices = [ + { title: 'Enable emojis 🎉', value: true }, + { title: 'Disable emojis', value: false }, + ] + + const selectedValue = await select( + 'Allow emojis in commit messages?', + choices, + currentEnabled ? 0 : 1, + ) + + if (selectedValue !== undefined) { + config.set('allowEmojis', selectedValue) + console.log( + `Emojis ${selectedValue ? 'enabled' : 'disabled'} and saved to configuration`, + ) + } + } +} diff --git a/src/cli/commands/index.js b/src/cli/commands/index.js index ceafa0d..a4c578a 100644 --- a/src/cli/commands/index.js +++ b/src/cli/commands/index.js @@ -2,5 +2,6 @@ export { createCommitCommand } from './commit.js' export { createModelCommand } from './model.js' export { createLangCommand } from './lang.js' export { createPrefixCommand } from './prefix.js' +export { createEmojiCommand } from './emoji.js' export { createApiKeyCommand } from './apiKey.js' export { createConfigCommand } from './config.js' diff --git a/src/cli/index.js b/src/cli/index.js index 0f6e03a..9c6f46c 100644 --- a/src/cli/index.js +++ b/src/cli/index.js @@ -7,6 +7,7 @@ import { createModelCommand, createLangCommand, createPrefixCommand, + createEmojiCommand, createApiKeyCommand, createConfigCommand, } from './commands/index.js' @@ -49,6 +50,11 @@ export function setupCli(options = {}) { .description('Toggle commit message prefix (e.g., fix:, feat:, refactor:)') .action(createPrefixCommand(deps)) + program + .command('emoji') + .description('Toggle emoji support in commit messages') + .action(createEmojiCommand(deps)) + program .command('open-api-key') .description('Manage your OpenAI API key') diff --git a/src/config/defaults.js b/src/config/defaults.js index ae6bf09..bc7b645 100644 --- a/src/config/defaults.js +++ b/src/config/defaults.js @@ -16,6 +16,7 @@ export const defaults = { model: 'gpt-4o-mini', language: 'English', prefixEnabled: true, + allowEmojis: true, apiKey: null, } diff --git a/src/core/commitGenerator.js b/src/core/commitGenerator.js index a6e1a4d..98c0804 100644 --- a/src/core/commitGenerator.js +++ b/src/core/commitGenerator.js @@ -12,11 +12,12 @@ import { buildMessages } from './messageBuilder.js' * @param {string} options.model - The GPT model to use * @param {string} options.language - The target language * @param {boolean} options.prefixEnabled - Whether to use prefixes + * @param {boolean} [options.allowEmojis=true] - Whether to allow emojis * @returns {Promise} The sanitized commit message */ export async function generateCommitMessage(deps, options) { const { openaiService, client } = deps - const { diff, model, language, prefixEnabled } = options + const { diff, model, language, prefixEnabled, allowEmojis = true } = options const messages = buildMessages({ diff, language, prefixEnabled }) @@ -27,5 +28,5 @@ export async function generateCommitMessage(deps, options) { maxTokens: 200, }) - return sanitizeCommitMessage(rawMessage) + return sanitizeCommitMessage(rawMessage, allowEmojis) } diff --git a/src/utils/sanitizeCommitMessage.js b/src/utils/sanitizeCommitMessage.js index 9a3c279..b73e6f7 100644 --- a/src/utils/sanitizeCommitMessage.js +++ b/src/utils/sanitizeCommitMessage.js @@ -3,12 +3,23 @@ * issues with shell commands. * * Only removes: " (double quote), ' (single quote), ` (backtick) - * All other characters including emojis, symbols, and Unicode are preserved. + * When allowEmojis is false, also removes emoji characters. * * @param {string} message - The commit message to sanitize + * @param {boolean} [allowEmojis=true] - Whether to preserve emoji characters * @returns {string} The sanitized commit message */ -export function sanitizeCommitMessage(message) { - // Remove only quote literals that can cause shell escaping issues - return message.replace(/["'`]/g, '') +export function sanitizeCommitMessage(message, allowEmojis = true) { + // Remove quote literals that can cause shell escaping issues + let result = message.replace(/["'`]/g, '') + + // Strip emojis if disabled + if (!allowEmojis) { + result = result.replace( + /\p{Emoji_Presentation}|\p{Extended_Pictographic}/gu, + '', + ) + } + + return result } diff --git a/utils/sanitizeCommitMessage.test.js b/utils/sanitizeCommitMessage.test.js index bd20ae4..b56076a 100644 --- a/utils/sanitizeCommitMessage.test.js +++ b/utils/sanitizeCommitMessage.test.js @@ -60,10 +60,20 @@ describe('sanitizeCommitMessage', () => { ) }) - it('should allow emojis', () => { + it('should allow emojis by default', () => { expect(sanitizeCommitMessage('fix: bug 🐛🔥💥')).toBe('fix: bug 🐛🔥💥') }) + it('should allow emojis when allowEmojis is true', () => { + expect(sanitizeCommitMessage('fix: bug 🐛🔥💥', true)).toBe( + 'fix: bug 🐛🔥💥', + ) + }) + + it('should strip emojis when allowEmojis is false', () => { + expect(sanitizeCommitMessage('fix: bug 🐛🔥💥', false)).toBe('fix: bug ') + }) + it('should only remove quotes from mixed content', () => { expect( sanitizeCommitMessage('feat(scope)!: add "dark mode" for issue #42 🎨'),