Skip to content

Commit 26b3e4e

Browse files
committed
refactor: updated toPascalCase()
1 parent 8904840 commit 26b3e4e

2 files changed

Lines changed: 52 additions & 26 deletions

File tree

src/toPascalCase.ts

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,14 @@ import type { PascalCase } from './types/strings.js';
55
import type { KeyValueTuple } from './types/tuples.js';
66

77
export function toPascalCase<Type extends string>(text: Type, customWords?: StringRecord): PascalCase<Type> {
8-
const words = String(text).match(/[A-Z][a-z']*|[a-z']+|\d+|[A-Z]+(?![a-z])/g);
8+
let words: string[] = String(text)
9+
.replaceAll(/['.]/g, '')
10+
.replaceAll(/[^a-z0-9]/gi, ' ')
11+
.split(/(\s+)|(?<=\d)(?=[a-z])|(?<=[a-z])(?=\d)/i)
12+
.filter((word: string | undefined) => word?.trim().length)
13+
.map(capitalize);
914

10-
let fixedWords = words?.map<string>((word) => capitalize(word.replace(/'/g, '')));
11-
12-
if (fixedWords && customWords && typeof customWords === 'object') {
15+
if (words && customWords && typeof customWords === 'object') {
1316
const replacements = new Map(
1417
Object.entries(customWords).map<KeyValueTuple<string, string>>(([key, value]) => [key.toLowerCase(), value]),
1518
);
@@ -18,9 +21,9 @@ export function toPascalCase<Type extends string>(text: Type, customWords?: Stri
1821
// This takes a single word and returns the first matching replacement, if any.
1922
const replaceCustomWords = (word: string): string => replacements.get(word.toLowerCase()) ?? word;
2023

21-
fixedWords = fixedWords.map(replaceCustomWords);
24+
words = words.map(replaceCustomWords);
2225
}
2326
}
2427

25-
return (fixedWords ? fixedWords.join('') : '') as PascalCase<Type>;
28+
return words.join('') as PascalCase<Type>;
2629
}

test/toPascalCase.test.ts

Lines changed: 43 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -3,42 +3,65 @@ import { describe, it, expect } from 'vitest';
33
import { toPascalCase } from '../src/toPascalCase.js';
44

55
describe('toPascalCase()', () => {
6-
it('Removes non alphanumeric', () => {
7-
expect(toPascalCase('!@#$%^&*()')).toBe('');
6+
it.each([
7+
['!@#$%^&*()', ''],
8+
['This is important!!!', 'ThisIsImportant'],
9+
])('Removes non alphanumeric: "%s" => "%s"', (input, expected) => {
10+
expect(toPascalCase(input)).toBe(expected);
811
});
912

10-
it('Handles one lowercase word', () => {
11-
expect(toPascalCase('a')).toBe('A');
12-
expect(toPascalCase('word')).toBe('Word');
13+
it.each([
14+
['abc', 'Abc'],
15+
['abc def', 'AbcDef'],
16+
])('Handles one lowercase word: "%s" => "%s"', (input, expected) => {
17+
expect(toPascalCase(input)).toBe(expected);
1318
});
1419

15-
it('Handles uppercase words', () => {
16-
expect(toPascalCase('SomeDLQ')).toBe('SomeDLQ');
17-
expect(toPascalCase('some UPPERCASE words')).toBe('SomeUPPERCASEWords');
18-
expect(toPascalCase('abc123DEF456')).toBe('Abc123DEF456');
20+
it.each([
21+
['SomeDLQ', 'SomeDLQ'],
22+
['some UPPERCASE words', 'SomeUPPERCASEWords'],
23+
['abc123DEF456', 'Abc123DEF456'],
24+
])('Handles uppercase words: "%s" => "%s"', (input, expected) => {
25+
expect(toPascalCase(input)).toBe(expected);
1926
});
2027

21-
it('Handles snake case', () => {
22-
expect(toPascalCase('do_something_cool')).toBe('DoSomethingCool');
28+
it.each([
29+
['something_happens_at_1200', 'SomethingHappensAt1200'],
30+
['do_something_cool', 'DoSomethingCool'],
31+
])('Handles snake case: "%s" => "%s"', (input, expected) => {
32+
expect(toPascalCase(input)).toBe(expected);
2333
});
2434

25-
it('Handles camel case', () => {
26-
expect(toPascalCase('doSomethingCool')).toBe('DoSomethingCool');
35+
it.each([
36+
['Bender: do a flip!', 'BenderDoAFlip'],
37+
['doSomethingCool', 'DoSomethingCool'],
38+
])('Handles camel case: "%s" => "%s"', (input, expected) => {
39+
expect(toPascalCase(input)).toBe(expected);
2740
});
2841

29-
it('Handles complex sentences', () => {
30-
expect(toPascalCase('Hello world! How are you today?')).toBe('HelloWorldHowAreYouToday');
42+
it.each([
43+
['The quick brown fox jumps over the lazy dog.', 'TheQuickBrownFoxJumpsOverTheLazyDog'],
44+
['Hello world! How are you today?', 'HelloWorldHowAreYouToday'],
45+
])('Handles complex sentences: "%s" => "%s"', (input, expected) => {
46+
expect(toPascalCase(input)).toBe(expected);
3147
});
3248

33-
it('Handles numbers', () => {
34-
expect(toPascalCase('abc123def')).toBe('Abc123Def');
49+
it.each([
50+
['abc123def', 'Abc123Def'],
51+
['123abc456def', '123Abc456Def'],
52+
])('Handles numbers: "%s" => "%s"', (input, expected) => {
53+
expect(toPascalCase(input)).toBe(expected);
3554
});
3655

37-
it('Handles apostrophe', () => {
56+
it.each([
3857
// cspell:disable-next-line
39-
expect(toPascalCase("Didn't can't isn't would've")).toBe('DidntCantIsntWouldve');
58+
["Didn't can't isn't would've", 'DidntCantIsntWouldve'],
4059
// cSpell:ignore TwasntShouldntve
41-
expect(toPascalCase("'twasn't shouldn't've")).toBe('TwasntShouldntve');
60+
["'twasn't shouldn't've", 'TwasntShouldntve'],
61+
// cSpell:ignore Twasnt123Shouldntve456
62+
["'twasn't123shouldn't've!456", 'Twasnt123Shouldntve456'],
63+
])('Handles apostrophe: "%s" => "%s"', (input, expected) => {
64+
expect(toPascalCase(input)).toBe(expected);
4265
});
4366

4467
it('Supports custom word mapping', () => {

0 commit comments

Comments
 (0)