feat: implement case-changing utility methods (fixes #15087)

Add the following case conversion methods to the Bun global object:
- Bun.camelCase() - Convert to camelCase
- Bun.pascalCase() - Convert to PascalCase
- Bun.snakeCase() - Convert to snake_case
- Bun.kebabCase() - Convert to kebab-case
- Bun.constantCase() - Convert to CONSTANT_CASE
- Bun.dotCase() - Convert to dot.case
- Bun.capitalCase() - Convert to Capital Case
- Bun.trainCase() - Convert to Train-Case

These utility functions are implemented in Zig for performance and handle:
- Multiple word delimiters (spaces, hyphens, underscores, etc.)
- Case transitions (camelCase, PascalCase detection)
- Numbers adjacent to letters
- UTF-8 string encoding

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Claude Bot
2025-09-13 01:06:33 +00:00
parent 7d5f5ad772
commit d7cf65eb0e
5 changed files with 581 additions and 0 deletions

View File

@@ -44,6 +44,16 @@ pub const BunObject = struct {
pub const zstdDecompressSync = toJSCallback(JSZstd.decompressSync);
pub const zstdCompress = toJSCallback(JSZstd.compress);
pub const zstdDecompress = toJSCallback(JSZstd.decompress);
// Case conversion functions
pub const camelCase = toJSCallback(CaseConvert.jsCamelCase);
pub const pascalCase = toJSCallback(CaseConvert.jsPascalCase);
pub const snakeCase = toJSCallback(CaseConvert.jsSnakeCase);
pub const kebabCase = toJSCallback(CaseConvert.jsKebabCase);
pub const constantCase = toJSCallback(CaseConvert.jsConstantCase);
pub const dotCase = toJSCallback(CaseConvert.jsDotCase);
pub const capitalCase = toJSCallback(CaseConvert.jsCapitalCase);
pub const trainCase = toJSCallback(CaseConvert.jsTrainCase);
// --- Callbacks ---
@@ -180,6 +190,16 @@ pub const BunObject = struct {
@export(&BunObject.zstdDecompressSync, .{ .name = callbackName("zstdDecompressSync") });
@export(&BunObject.zstdCompress, .{ .name = callbackName("zstdCompress") });
@export(&BunObject.zstdDecompress, .{ .name = callbackName("zstdDecompress") });
// Case conversion exports
@export(&BunObject.camelCase, .{ .name = callbackName("camelCase") });
@export(&BunObject.pascalCase, .{ .name = callbackName("pascalCase") });
@export(&BunObject.snakeCase, .{ .name = callbackName("snakeCase") });
@export(&BunObject.kebabCase, .{ .name = callbackName("kebabCase") });
@export(&BunObject.constantCase, .{ .name = callbackName("constantCase") });
@export(&BunObject.dotCase, .{ .name = callbackName("dotCase") });
@export(&BunObject.capitalCase, .{ .name = callbackName("capitalCase") });
@export(&BunObject.trainCase, .{ .name = callbackName("trainCase") });
// --- Callbacks ---
// --- LazyProperty initializers ---
@@ -2070,6 +2090,7 @@ pub fn createBunStdout(globalThis: *jsc.JSGlobalObject) callconv(.C) jsc.JSValue
}
const Braces = @import("../../shell/braces.zig");
const CaseConvert = @import("./CaseConvert.zig");
const Which = @import("../../which.zig");
const options = @import("../../options.zig");
const std = @import("std");

View File

@@ -0,0 +1,378 @@
const std = @import("std");
const bun = @import("bun");
const jsc = bun.jsc;
const JSValue = jsc.JSValue;
/// Check if a character is a word boundary (not alphanumeric)
fn isWordBoundary(c: u8) bool {
return !std.ascii.isAlphanumeric(c);
}
/// Check if character is uppercase
fn isUpper(c: u8) bool {
return c >= 'A' and c <= 'Z';
}
/// Check if character is lowercase
fn isLower(c: u8) bool {
return c >= 'a' and c <= 'z';
}
/// Convert character to uppercase
fn toUpper(c: u8) u8 {
if (isLower(c)) {
return c - 32;
}
return c;
}
/// Convert character to lowercase
fn toLower(c: u8) u8 {
if (isUpper(c)) {
return c + 32;
}
return c;
}
/// Split a string into words based on various delimiters and case changes
fn splitIntoWords(allocator: std.mem.Allocator, input: []const u8) !std.ArrayList([]const u8) {
var words = std.ArrayList([]const u8).init(allocator);
errdefer words.deinit();
if (input.len == 0) return words;
var start: usize = 0;
var i: usize = 0;
while (i < input.len) : (i += 1) {
const c = input[i];
// Skip non-alphanumeric characters
if (!std.ascii.isAlphanumeric(c)) {
if (i > start) {
try words.append(input[start..i]);
}
start = i + 1;
continue;
}
// Handle transitions if we're not at the first character
if (i > 0) {
const prev = input[i - 1];
// Skip if previous was not alphanumeric (already handled above)
if (std.ascii.isAlphanumeric(prev)) {
const prevIsDigit = std.ascii.isDigit(prev);
const currIsDigit = std.ascii.isDigit(c);
// Check for transitions that should cause splits
if (!currIsDigit) {
// Split on digit to uppercase letter transition (test123Case -> test123, Case)
if (prevIsDigit and isUpper(c)) {
if (i > start) {
try words.append(input[start..i]);
}
start = i;
}
// Detect lowercase to uppercase transition (camelCase)
else if (!prevIsDigit and isLower(prev) and isUpper(c)) {
if (i > start) {
try words.append(input[start..i]);
}
start = i;
}
// Detect uppercase sequence ending (XMLParser -> XML, Parser)
else if (!prevIsDigit and i < input.len - 1) {
const next = input[i + 1];
if (isUpper(prev) and isUpper(c) and std.ascii.isAlphanumeric(next) and !std.ascii.isDigit(next) and isLower(next)) {
if (i > start) {
try words.append(input[start..i]);
}
start = i;
}
}
}
}
}
}
// Add the last word if any
if (start < input.len) {
try words.append(input[start..]);
}
return words;
}
/// Convert string to camelCase: "two words" -> "twoWords"
pub fn camelCase(allocator: std.mem.Allocator, input: []const u8) ![]u8 {
const words = try splitIntoWords(allocator, input);
defer words.deinit();
if (words.items.len == 0) return try allocator.alloc(u8, 0);
var result = std.ArrayList(u8).init(allocator);
errdefer result.deinit();
for (words.items, 0..) |word, idx| {
if (word.len == 0) continue;
if (idx == 0) {
// First word is all lowercase
for (word) |c| {
try result.append(toLower(c));
}
} else {
// Subsequent words: capitalize first letter, lowercase rest
try result.append(toUpper(word[0]));
for (word[1..]) |c| {
try result.append(toLower(c));
}
}
}
return result.toOwnedSlice();
}
/// Convert string to PascalCase: "two words" -> "TwoWords"
pub fn pascalCase(allocator: std.mem.Allocator, input: []const u8) ![]u8 {
const words = try splitIntoWords(allocator, input);
defer words.deinit();
if (words.items.len == 0) return try allocator.alloc(u8, 0);
var result = std.ArrayList(u8).init(allocator);
errdefer result.deinit();
for (words.items) |word| {
if (word.len == 0) continue;
// Capitalize first letter, lowercase rest
try result.append(toUpper(word[0]));
for (word[1..]) |c| {
try result.append(toLower(c));
}
}
return result.toOwnedSlice();
}
/// Convert string to snake_case: "two words" -> "two_words"
pub fn snakeCase(allocator: std.mem.Allocator, input: []const u8) ![]u8 {
const words = try splitIntoWords(allocator, input);
defer words.deinit();
if (words.items.len == 0) return try allocator.alloc(u8, 0);
var result = std.ArrayList(u8).init(allocator);
errdefer result.deinit();
for (words.items, 0..) |word, idx| {
if (word.len == 0) continue;
if (idx > 0) {
try result.append('_');
}
for (word) |c| {
try result.append(toLower(c));
}
}
return result.toOwnedSlice();
}
/// Convert string to kebab-case: "two words" -> "two-words"
pub fn kebabCase(allocator: std.mem.Allocator, input: []const u8) ![]u8 {
const words = try splitIntoWords(allocator, input);
defer words.deinit();
if (words.items.len == 0) return try allocator.alloc(u8, 0);
var result = std.ArrayList(u8).init(allocator);
errdefer result.deinit();
for (words.items, 0..) |word, idx| {
if (word.len == 0) continue;
if (idx > 0) {
try result.append('-');
}
for (word) |c| {
try result.append(toLower(c));
}
}
return result.toOwnedSlice();
}
/// Convert string to CONSTANT_CASE: "two words" -> "TWO_WORDS"
pub fn constantCase(allocator: std.mem.Allocator, input: []const u8) ![]u8 {
const words = try splitIntoWords(allocator, input);
defer words.deinit();
if (words.items.len == 0) return try allocator.alloc(u8, 0);
var result = std.ArrayList(u8).init(allocator);
errdefer result.deinit();
for (words.items, 0..) |word, idx| {
if (word.len == 0) continue;
if (idx > 0) {
try result.append('_');
}
for (word) |c| {
try result.append(toUpper(c));
}
}
return result.toOwnedSlice();
}
/// Convert string to dot.case: "two words" -> "two.words"
pub fn dotCase(allocator: std.mem.Allocator, input: []const u8) ![]u8 {
const words = try splitIntoWords(allocator, input);
defer words.deinit();
if (words.items.len == 0) return try allocator.alloc(u8, 0);
var result = std.ArrayList(u8).init(allocator);
errdefer result.deinit();
for (words.items, 0..) |word, idx| {
if (word.len == 0) continue;
if (idx > 0) {
try result.append('.');
}
for (word) |c| {
try result.append(toLower(c));
}
}
return result.toOwnedSlice();
}
/// Convert string to Capital Case: "two words" -> "Two Words"
pub fn capitalCase(allocator: std.mem.Allocator, input: []const u8) ![]u8 {
const words = try splitIntoWords(allocator, input);
defer words.deinit();
if (words.items.len == 0) return try allocator.alloc(u8, 0);
var result = std.ArrayList(u8).init(allocator);
errdefer result.deinit();
for (words.items, 0..) |word, idx| {
if (word.len == 0) continue;
if (idx > 0) {
try result.append(' ');
}
// Capitalize first letter, lowercase rest
try result.append(toUpper(word[0]));
for (word[1..]) |c| {
try result.append(toLower(c));
}
}
return result.toOwnedSlice();
}
/// Convert string to Train-Case: "two words" -> "Two-Words"
pub fn trainCase(allocator: std.mem.Allocator, input: []const u8) ![]u8 {
const words = try splitIntoWords(allocator, input);
defer words.deinit();
if (words.items.len == 0) return try allocator.alloc(u8, 0);
var result = std.ArrayList(u8).init(allocator);
errdefer result.deinit();
for (words.items, 0..) |word, idx| {
if (word.len == 0) continue;
if (idx > 0) {
try result.append('-');
}
// Capitalize first letter, lowercase rest
try result.append(toUpper(word[0]));
for (word[1..]) |c| {
try result.append(toLower(c));
}
}
return result.toOwnedSlice();
}
/// Generic case conversion function that handles string extraction and conversion
fn convertCase(globalThis: *jsc.JSGlobalObject, callFrame: *jsc.CallFrame, comptime converter: fn (std.mem.Allocator, []const u8) anyerror![]u8) bun.JSError!JSValue {
const arguments = callFrame.arguments_old(1);
if (arguments.len < 1) {
return globalThis.throw("expected 1 argument, got 0", .{});
}
const input_value = arguments.ptr[0];
// Convert to string
const bunstr = try input_value.toBunString(globalThis);
if (globalThis.hasException()) return .zero;
defer bunstr.deref();
// Get UTF8 bytes
const allocator = bun.default_allocator;
const utf8_slice = bunstr.toUTF8(allocator);
defer utf8_slice.deinit();
// Apply the conversion
const result_bytes = converter(allocator, utf8_slice.slice()) catch |err| {
if (err == error.OutOfMemory) {
return globalThis.throwOutOfMemory();
}
return globalThis.throw("case conversion failed", .{});
};
defer allocator.free(result_bytes);
// Create a new string from the result
var result_str = bun.String.cloneUTF8(result_bytes);
return result_str.transferToJS(globalThis);
}
// JavaScript-exposed functions
pub fn jsCamelCase(globalThis: *jsc.JSGlobalObject, callFrame: *jsc.CallFrame) bun.JSError!JSValue {
return convertCase(globalThis, callFrame, camelCase);
}
pub fn jsPascalCase(globalThis: *jsc.JSGlobalObject, callFrame: *jsc.CallFrame) bun.JSError!JSValue {
return convertCase(globalThis, callFrame, pascalCase);
}
pub fn jsSnakeCase(globalThis: *jsc.JSGlobalObject, callFrame: *jsc.CallFrame) bun.JSError!JSValue {
return convertCase(globalThis, callFrame, snakeCase);
}
pub fn jsKebabCase(globalThis: *jsc.JSGlobalObject, callFrame: *jsc.CallFrame) bun.JSError!JSValue {
return convertCase(globalThis, callFrame, kebabCase);
}
pub fn jsConstantCase(globalThis: *jsc.JSGlobalObject, callFrame: *jsc.CallFrame) bun.JSError!JSValue {
return convertCase(globalThis, callFrame, constantCase);
}
pub fn jsDotCase(globalThis: *jsc.JSGlobalObject, callFrame: *jsc.CallFrame) bun.JSError!JSValue {
return convertCase(globalThis, callFrame, dotCase);
}
pub fn jsCapitalCase(globalThis: *jsc.JSGlobalObject, callFrame: *jsc.CallFrame) bun.JSError!JSValue {
return convertCase(globalThis, callFrame, capitalCase);
}
pub fn jsTrainCase(globalThis: *jsc.JSGlobalObject, callFrame: *jsc.CallFrame) bun.JSError!JSValue {
return convertCase(globalThis, callFrame, trainCase);
}

View File

@@ -75,6 +75,14 @@
macro(zstdDecompressSync) \
macro(zstdCompress) \
macro(zstdDecompress) \
macro(camelCase) \
macro(pascalCase) \
macro(snakeCase) \
macro(kebabCase) \
macro(constantCase) \
macro(dotCase) \
macro(capitalCase) \
macro(trainCase) \
#define DECLARE_ZIG_BUN_OBJECT_CALLBACK(name) BUN_DECLARE_HOST_FUNCTION(BunObject_callback_##name);
FOR_EACH_CALLBACK(DECLARE_ZIG_BUN_OBJECT_CALLBACK);

View File

@@ -807,6 +807,14 @@ JSC_DEFINE_HOST_FUNCTION(functionFileURLToPath, (JSC::JSGlobalObject * globalObj
zstdDecompressSync BunObject_callback_zstdDecompressSync DontDelete|Function 1
zstdCompress BunObject_callback_zstdCompress DontDelete|Function 1
zstdDecompress BunObject_callback_zstdDecompress DontDelete|Function 1
camelCase BunObject_callback_camelCase DontDelete|Function 1
pascalCase BunObject_callback_pascalCase DontDelete|Function 1
snakeCase BunObject_callback_snakeCase DontDelete|Function 1
kebabCase BunObject_callback_kebabCase DontDelete|Function 1
constantCase BunObject_callback_constantCase DontDelete|Function 1
dotCase BunObject_callback_dotCase DontDelete|Function 1
capitalCase BunObject_callback_capitalCase DontDelete|Function 1
trainCase BunObject_callback_trainCase DontDelete|Function 1
@end
*/

View File

@@ -0,0 +1,166 @@
import { test, expect } from "bun:test";
test("Bun.camelCase", () => {
expect(Bun.camelCase("two words")).toBe("twoWords");
expect(Bun.camelCase("hello world")).toBe("helloWorld");
expect(Bun.camelCase("HELLO_WORLD")).toBe("helloWorld");
expect(Bun.camelCase("kebab-case")).toBe("kebabCase");
expect(Bun.camelCase("snake_case")).toBe("snakeCase");
expect(Bun.camelCase("PascalCase")).toBe("pascalCase");
expect(Bun.camelCase("multiple spaces")).toBe("multipleSpaces");
expect(Bun.camelCase("123-numbers-456")).toBe("123Numbers456");
expect(Bun.camelCase("")).toBe("");
expect(Bun.camelCase("alreadyCamelCase")).toBe("alreadyCamelCase");
expect(Bun.camelCase("XML-Parser")).toBe("xmlParser");
expect(Bun.camelCase("XMLParser")).toBe("xmlParser");
});
test("Bun.pascalCase", () => {
expect(Bun.pascalCase("two words")).toBe("TwoWords");
expect(Bun.pascalCase("hello world")).toBe("HelloWorld");
expect(Bun.pascalCase("HELLO_WORLD")).toBe("HelloWorld");
expect(Bun.pascalCase("kebab-case")).toBe("KebabCase");
expect(Bun.pascalCase("snake_case")).toBe("SnakeCase");
expect(Bun.pascalCase("camelCase")).toBe("CamelCase");
expect(Bun.pascalCase("multiple spaces")).toBe("MultipleSpaces");
expect(Bun.pascalCase("123-numbers-456")).toBe("123Numbers456");
expect(Bun.pascalCase("")).toBe("");
expect(Bun.pascalCase("AlreadyPascalCase")).toBe("AlreadyPascalCase");
expect(Bun.pascalCase("xml-parser")).toBe("XmlParser");
expect(Bun.pascalCase("XMLParser")).toBe("XmlParser");
});
test("Bun.snakeCase", () => {
expect(Bun.snakeCase("two words")).toBe("two_words");
expect(Bun.snakeCase("hello world")).toBe("hello_world");
expect(Bun.snakeCase("HELLO_WORLD")).toBe("hello_world");
expect(Bun.snakeCase("kebab-case")).toBe("kebab_case");
expect(Bun.snakeCase("camelCase")).toBe("camel_case");
expect(Bun.snakeCase("PascalCase")).toBe("pascal_case");
expect(Bun.snakeCase("multiple spaces")).toBe("multiple_spaces");
expect(Bun.snakeCase("123-numbers-456")).toBe("123_numbers_456");
expect(Bun.snakeCase("")).toBe("");
expect(Bun.snakeCase("already_snake_case")).toBe("already_snake_case");
expect(Bun.snakeCase("XMLParser")).toBe("xml_parser");
});
test("Bun.kebabCase", () => {
expect(Bun.kebabCase("two words")).toBe("two-words");
expect(Bun.kebabCase("hello world")).toBe("hello-world");
expect(Bun.kebabCase("HELLO_WORLD")).toBe("hello-world");
expect(Bun.kebabCase("snake_case")).toBe("snake-case");
expect(Bun.kebabCase("camelCase")).toBe("camel-case");
expect(Bun.kebabCase("PascalCase")).toBe("pascal-case");
expect(Bun.kebabCase("multiple spaces")).toBe("multiple-spaces");
expect(Bun.kebabCase("123-numbers-456")).toBe("123-numbers-456");
expect(Bun.kebabCase("")).toBe("");
expect(Bun.kebabCase("already-kebab-case")).toBe("already-kebab-case");
expect(Bun.kebabCase("XMLParser")).toBe("xml-parser");
});
test("Bun.constantCase", () => {
expect(Bun.constantCase("two words")).toBe("TWO_WORDS");
expect(Bun.constantCase("hello world")).toBe("HELLO_WORLD");
expect(Bun.constantCase("hello_world")).toBe("HELLO_WORLD");
expect(Bun.constantCase("kebab-case")).toBe("KEBAB_CASE");
expect(Bun.constantCase("camelCase")).toBe("CAMEL_CASE");
expect(Bun.constantCase("PascalCase")).toBe("PASCAL_CASE");
expect(Bun.constantCase("multiple spaces")).toBe("MULTIPLE_SPACES");
expect(Bun.constantCase("123-numbers-456")).toBe("123_NUMBERS_456");
expect(Bun.constantCase("")).toBe("");
expect(Bun.constantCase("ALREADY_CONSTANT_CASE")).toBe("ALREADY_CONSTANT_CASE");
expect(Bun.constantCase("XMLParser")).toBe("XML_PARSER");
});
test("Bun.dotCase", () => {
expect(Bun.dotCase("two words")).toBe("two.words");
expect(Bun.dotCase("hello world")).toBe("hello.world");
expect(Bun.dotCase("HELLO_WORLD")).toBe("hello.world");
expect(Bun.dotCase("kebab-case")).toBe("kebab.case");
expect(Bun.dotCase("camelCase")).toBe("camel.case");
expect(Bun.dotCase("PascalCase")).toBe("pascal.case");
expect(Bun.dotCase("multiple spaces")).toBe("multiple.spaces");
expect(Bun.dotCase("123-numbers-456")).toBe("123.numbers.456");
expect(Bun.dotCase("")).toBe("");
expect(Bun.dotCase("already.dot.case")).toBe("already.dot.case");
expect(Bun.dotCase("XMLParser")).toBe("xml.parser");
});
test("Bun.capitalCase", () => {
expect(Bun.capitalCase("two words")).toBe("Two Words");
expect(Bun.capitalCase("hello world")).toBe("Hello World");
expect(Bun.capitalCase("HELLO_WORLD")).toBe("Hello World");
expect(Bun.capitalCase("kebab-case")).toBe("Kebab Case");
expect(Bun.capitalCase("camelCase")).toBe("Camel Case");
expect(Bun.capitalCase("PascalCase")).toBe("Pascal Case");
expect(Bun.capitalCase("multiple spaces")).toBe("Multiple Spaces");
expect(Bun.capitalCase("123-numbers-456")).toBe("123 Numbers 456");
expect(Bun.capitalCase("")).toBe("");
expect(Bun.capitalCase("already Capital Case")).toBe("Already Capital Case");
expect(Bun.capitalCase("XMLParser")).toBe("Xml Parser");
});
test("Bun.trainCase", () => {
expect(Bun.trainCase("two words")).toBe("Two-Words");
expect(Bun.trainCase("hello world")).toBe("Hello-World");
expect(Bun.trainCase("HELLO_WORLD")).toBe("Hello-World");
expect(Bun.trainCase("kebab-case")).toBe("Kebab-Case");
expect(Bun.trainCase("camelCase")).toBe("Camel-Case");
expect(Bun.trainCase("PascalCase")).toBe("Pascal-Case");
expect(Bun.trainCase("multiple spaces")).toBe("Multiple-Spaces");
expect(Bun.trainCase("123-numbers-456")).toBe("123-Numbers-456");
expect(Bun.trainCase("")).toBe("");
expect(Bun.trainCase("Already-Train-Case")).toBe("Already-Train-Case");
expect(Bun.trainCase("XMLParser")).toBe("Xml-Parser");
});
test("case conversion with special characters", () => {
const input = "hello@world#test!";
expect(Bun.camelCase(input)).toBe("helloWorldTest");
expect(Bun.pascalCase(input)).toBe("HelloWorldTest");
expect(Bun.snakeCase(input)).toBe("hello_world_test");
expect(Bun.kebabCase(input)).toBe("hello-world-test");
expect(Bun.constantCase(input)).toBe("HELLO_WORLD_TEST");
expect(Bun.dotCase(input)).toBe("hello.world.test");
expect(Bun.capitalCase(input)).toBe("Hello World Test");
expect(Bun.trainCase(input)).toBe("Hello-World-Test");
});
test("case conversion with numbers", () => {
// Numbers stay with adjacent letters unless there's a case change
const input = "test123case456";
expect(Bun.camelCase(input)).toBe("test123case456");
expect(Bun.pascalCase(input)).toBe("Test123case456");
expect(Bun.snakeCase(input)).toBe("test123case456");
expect(Bun.kebabCase(input)).toBe("test123case456");
expect(Bun.constantCase(input)).toBe("TEST123CASE456");
expect(Bun.dotCase(input)).toBe("test123case456");
expect(Bun.capitalCase(input)).toBe("Test123case456");
expect(Bun.trainCase(input)).toBe("Test123case456");
// When there's a case change after numbers, it splits
const input2 = "test123Case456";
expect(Bun.camelCase(input2)).toBe("test123Case456");
expect(Bun.snakeCase(input2)).toBe("test123_case456");
expect(Bun.kebabCase(input2)).toBe("test123-case456");
});
test("case conversion with non-strings", () => {
// Should convert to string first
expect(Bun.camelCase(123)).toBe("123");
expect(Bun.camelCase(true)).toBe("true");
expect(Bun.camelCase(null)).toBe("null");
expect(Bun.camelCase(undefined)).toBe("undefined");
});
test("case conversion error handling", () => {
// Should throw when no arguments provided
expect(() => (Bun as any).camelCase()).toThrow();
expect(() => (Bun as any).pascalCase()).toThrow();
expect(() => (Bun as any).snakeCase()).toThrow();
expect(() => (Bun as any).kebabCase()).toThrow();
expect(() => (Bun as any).constantCase()).toThrow();
expect(() => (Bun as any).dotCase()).toThrow();
expect(() => (Bun as any).capitalCase()).toThrow();
expect(() => (Bun as any).trainCase()).toThrow();
});