Skip to content

Commit 5048374

Browse files
committed
feat(utils): add type helpers for lower/upper case conversions
1 parent 6261ba2 commit 5048374

File tree

6 files changed

+70
-4
lines changed

6 files changed

+70
-4
lines changed

eslint.config.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,12 @@ export default tseslint.config(
9393
],
9494
},
9595
},
96+
{
97+
files: ['**/*.type.test.ts'],
98+
rules: {
99+
'vitest/expect-expect': 'off',
100+
},
101+
},
96102
{
97103
files: ['**/*.json'],
98104
languageOptions: { parser: jsoncParser },

packages/utils/src/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,10 @@ export {
33
camelCaseToKebabCase,
44
capitalize,
55
kebabCaseToCamelCase,
6+
lowercase,
67
toSentenceCase,
78
toTitleCase,
9+
uppercase,
810
} from './lib/case-conversions.js';
911
export { filesCoverageToTree, type FileCoverage } from './lib/coverage-tree.js';
1012
export { createRunnerFiles } from './lib/create-runner-files.js';

packages/utils/src/lib/case-conversion.type.test.ts

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { assertType, describe, expectTypeOf, it } from 'vitest';
2+
import { lowercase, uppercase } from './case-conversions.js';
23
import type { CamelCaseToKebabCase, KebabCaseToCamelCase } from './types.js';
34

4-
/* eslint-disable vitest/expect-expect */
55
describe('CamelCaseToKebabCase', () => {
66
// ✅ CamelCase → kebab-case Type Tests
77

@@ -60,4 +60,37 @@ describe('CamelCaseToKebabCase', () => {
6060
assertType<KebabCaseToCamelCase<'this-Is-Wrong'>>();
6161
});
6262
});
63-
/* eslint-enable vitest/expect-expect */
63+
64+
describe('lowercase', () => {
65+
it('converts string literal to lowercased literal', () => {
66+
expectTypeOf(lowercase('Warning' as const)).toEqualTypeOf<'warning'>();
67+
});
68+
69+
it('converts enum value to lowercased string literal', () => {
70+
enum Severity {
71+
Warning = 'Warning',
72+
}
73+
expectTypeOf(lowercase(Severity.Warning)).toEqualTypeOf<'warning'>();
74+
});
75+
76+
it('converts string to string', () => {
77+
expectTypeOf(lowercase('hello, world')).toBeString();
78+
});
79+
});
80+
81+
describe('uppercase', () => {
82+
it('converts string literal to uppercased literal', () => {
83+
expectTypeOf(uppercase('Warning' as const)).toEqualTypeOf<'WARNING'>();
84+
});
85+
86+
it('converts enum value to uppercased string literal', () => {
87+
enum Severity {
88+
Warning = 'Warning',
89+
}
90+
expectTypeOf(uppercase(Severity.Warning)).toEqualTypeOf<'WARNING'>();
91+
});
92+
93+
it('converts string to string', () => {
94+
expectTypeOf(uppercase('hello, world')).toBeString();
95+
});
96+
});

packages/utils/src/lib/case-conversions.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,5 +97,13 @@ export function toSentenceCase(input: string): string {
9797
}
9898

9999
export function capitalize<T extends string>(text: T): Capitalize<T> {
100-
return `${text.charAt(0).toLocaleUpperCase()}${text.slice(1).toLowerCase()}` as Capitalize<T>;
100+
return `${text.charAt(0).toUpperCase()}${text.slice(1).toLowerCase()}` as Capitalize<T>;
101+
}
102+
103+
export function lowercase<T extends string>(text: T): Lowercase<T> {
104+
return text.toLowerCase() as Lowercase<T>;
105+
}
106+
107+
export function uppercase<T extends string>(text: T): Uppercase<T> {
108+
return text.toUpperCase() as Uppercase<T>;
101109
}

packages/utils/src/lib/case-conversions.unit.test.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,10 @@ import {
33
camelCaseToKebabCase,
44
capitalize,
55
kebabCaseToCamelCase,
6+
lowercase,
67
toSentenceCase,
78
toTitleCase,
9+
uppercase,
810
} from './case-conversions.js';
911

1012
describe('capitalize', () => {
@@ -25,6 +27,18 @@ describe('capitalize', () => {
2527
});
2628
});
2729

30+
describe('lowercase', () => {
31+
it('should convert string to lower case', () => {
32+
expect(lowercase('Warning')).toBe('warning');
33+
});
34+
});
35+
36+
describe('uppercase', () => {
37+
it('should convert string to upper case', () => {
38+
expect(uppercase('Warning')).toBe('WARNING');
39+
});
40+
});
41+
2842
describe('kebabCaseToCamelCase', () => {
2943
it('should convert simple kebab-case to camelCase', () => {
3044
expect(kebabCaseToCamelCase('hello-world')).toBe('helloWorld');

packages/utils/vitest.unit.config.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,10 @@ export default defineConfig({
1919
exclude: ['mocks/**', 'perf/**', '**/types.ts'],
2020
},
2121
environment: 'node',
22-
include: ['src/**/*.unit.test.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'],
22+
include: ['src/**/*.{unit,type}.test.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'],
23+
typecheck: {
24+
include: ['**/*.type.test.ts'],
25+
},
2326
globalSetup: ['../../global-setup.ts'],
2427
setupFiles: [
2528
'../../testing/test-setup/src/lib/cliui.mock.ts',

0 commit comments

Comments
 (0)