Skip to content

Commit

Permalink
✨ feat: unemojify
Browse files Browse the repository at this point in the history
  • Loading branch information
Rettend committed Nov 26, 2023
1 parent 66f235b commit 381529e
Show file tree
Hide file tree
Showing 3 changed files with 63 additions and 7 deletions.
6 changes: 4 additions & 2 deletions src/commands/run.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { defineCommand } from 'citty'
import { consola } from 'consola'
import { cosmiconfig } from 'cosmiconfig'
import { name } from '../../package.json'
import { eemojify } from '../utils/emoji'
import { eemojify, unemojify } from '../utils/emoji'
import { type Config, ConfigObject } from './../config'

const C = new ConfigObject()
Expand Down Expand Up @@ -49,13 +49,15 @@ export default defineCommand({
if (ctx.args.test) {
commitMessage = await consola.prompt('Commit message:', {
placeholder: 'enter a commit message for testing...',
initial: 'feat: add new feature',
initial: unemojify(fs.readFileSync(ctx.args.commit_file, 'utf-8'), config),
})

if (commitMessage) {
const newCommitMessage = eemojify(commitMessage, config, DEBUG)

consola.log(`\n${newCommitMessage}`)

fs.writeFileSync(ctx.args.commit_file, newCommitMessage)
}
}
else {
Expand Down
27 changes: 26 additions & 1 deletion src/utils/emoji.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,21 @@
import { consola } from 'consola'
import { type Config } from './../config'

/**
* Formats a commit message with an emoji based on the type.
*
* @param text - The whole commit message text.
* @param config - The configuration object containing the format and emojis.
* @param DEBUG - Optional debug level (0=off, 1=some, 2=all)
* @returns The formatted commit message.
* @throws Error if the commit message is invalid or if the emoji for the given type is not found.
* @example
* `feat: add new feature`
*
* becomes
*
* `✨ feat: add new feature`
*/
export function eemojify(text: string, config: Config, DEBUG?: number): string {
// the separator is whatever character remains after removing the format placeholders, or a space
const separator = config.format.replace(/{emoji}|{type}|{subject}/g, '').trim() || ' '
Expand Down Expand Up @@ -47,7 +62,7 @@ function getEmoji(type: string, text: string, config: Config, DEBUG?: number): s
if (!emojiKey)
return undefined

const emoji = config.emojis[emojiKey]
const emoji = config.emojis[emojiKey as keyof Config['emojis']]

if (typeof emoji === 'object') {
if (DEBUG)
Expand All @@ -69,3 +84,13 @@ function getEmoji(type: string, text: string, config: Config, DEBUG?: number): s
return undefined
}
}

export function unemojify(text: string, config: Config): string {
const values = Object.values(config.emojis).flatMap(
value => typeof value === 'object' ? Object.values(value) : value,
).join('|').replace(/,/g, '|')

const regex = new RegExp(`(${values})`, 'gi')

return text.replace(regex, '').trim()
}
37 changes: 33 additions & 4 deletions test/main.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// import the function and the default config
import { describe, expect, test } from 'vitest'
import { eemojify } from '../src/utils/emoji'
import { ConfigObject } from '../src/config'
import { eemojify, unemojify } from '../src/utils/emoji'
import { type Config, ConfigObject } from '../src/config'

const C = new ConfigObject()

Expand All @@ -15,10 +15,17 @@ const customConfig = {
'backend': '🧱',
},
docs: '📚',
test: '🧐',
breaking: '🚨',
test: { // override nested emoji and skip the default (.) emoji
unit: '🧪',
e2e: '⚗️',
},
test2: { // create a nested emoji and skip the default (.) emoji
unit: '🧪',
e2e: '⚗️',
},
},
}
} satisfies Config

describe('eemojify with default config', () => {
test('should return the correct emoji for a feat type', () => {
Expand Down Expand Up @@ -67,6 +74,14 @@ describe('eemojify with custom config', () => {
expect(eemojify('feat(frontend) - add new feature', customConfig)).toBe('feat(frontend) 🪟 - add new feature')
})

test('should return the correct emoji when overriding a nested emoji with a custom object and skipping the default (.) emoji', () => {
expect(eemojify('test(unit) - add new feature', customConfig)).toBe('test(unit) 🧪 - add new feature')
})

test('should throw an error when overriding a nested emoji with a custom object and skipping the default (.) emoji', () => {
expect(() => eemojify('test2 - add new feature', customConfig)).toThrow('Emoji for type "test2" not found.')
})

test('should return the correct emoji for a breaking change type', () => {
expect(eemojify('feat! - remove deprecated feature', customConfig)).toBe('feat! 🚨 - remove deprecated feature')
})
Expand All @@ -79,3 +94,17 @@ describe('eemojify with custom config', () => {
expect(() => eemojify('unknown - do something', customConfig)).toThrow('Emoji for type "unknown" not found.')
})
})

describe('unemojify', () => {
test('should work for a single emoji', () => {
expect(unemojify('🔨 fix: typo in readme', customConfig)).toBe('fix: typo in readme')
})

test('should work for a nested emoji', () => {
expect(unemojify('🚀 fix: typo in readme', customConfig)).toBe('fix: typo in readme')
})

test('should work for multiple emojis', () => {
expect(unemojify('🚀🔨 fix: ty🔨po in🔨 r🔨ea🔨🔨dme', customConfig)).toBe('fix: typo in readme')
})
})

0 comments on commit 381529e

Please sign in to comment.