`String.prototype.toCamelCase()` and others

Converting strings to other cases (including "camelCase", "PascalCase", "snake_case", etc.) is a fairly common task, – yet I haven't found any case-related proposals, neither in tc39/proposals GitHub repo, nor here (probably because there are countless npm libraries to do this conversion?).

So, basically, the proposal is trivial: for some cases (to be discussed), adding case-related methods to primitive strings and string instances, – I can think of several of those (the identifiers are also not set in stone):

const string = "hello world";

string.toCamelCase(); // "helloWorld"
string.toPascalCase(); // "HelloWorld"
string.toKebabCase(); // "hello-world"
string.toSnakeCase(); // "hello_world"
string.toConstantCase(); // "HELLO_WORLD"
string.toTitleCase(); // "Hello World"

Or (to avoid using arbitrary namings, such as "kebab" or "snake") this can be a single function, a-la Intl API, – but to me, this seems a bit over the top. If such a function is okay though, putting it statically on the String constructor might be a good choice too:

String.prototype.toCase(params);
String.toCase(string[, params]);
const string = "what a lovely day";

string.toCase();
// "what a lovely day"

string.toCase({ match: "n + 1", separator: "", pattern: "Aa*" }); // camelCase
// "whatALovelyDay"

string.toCase({ match: "n", separator: "_", pattern: "A*"}); // CONSTANT_CASE
// "WHAT_A_LOVELY_DAY"

string.toCase({ match: "n", separator: " ", pattern: "A*" }); // Title Case
// "What A Lovely Day"

string.toCase({ match: "n", separator: " ", pattern: "(Aa)*" });
// "WhAt A LoVeLy DaY"

string.toCase(
  { match: "1 - n", separator: "@", pattern: "a*" }, // first and second words
  { match: "n + 2", separator: "-", pattern: "A*" }, // third and subsequent words
);
// "what@a LOVELY-DAY"

I'm a bit uncertain about how this would work with punctuation, whitespace characters, and other non-word characters, but I guess this can be derived from how .toLowerCase() and .toUpperCase() work?

This seems like a niche issue. In what situation would you need to convert a string to camel-case, or any other case besides upper/lower? I've never come across a scenario where I needed to do that. And even if I did, it wouldn't be too hard to MacGyver a function from scratch to do just that.

this could be mildly useful when message-passing property-names between javascript (camelCase) and python / sql / filesystems (snake_case):

let dataJs = {
    responseText: "hello world",
    statusCode: 200
};

// convert property names from camelCase -> snake_case
// for message-passing compatibility between js <-> python api-endpoints
let dataPython = {};
Object.entries(dataJs).forEach(function ([
    key, val
]) {
    dataPython[key.toSnakeCase()] = val;
});
// dataPython = {"response_text": "hello world", "status_code": 200}

await fetch("https://python_api_server.com/api1", {
    body: JSON.stringify(dataPython)
});

Or just within the web platform:

  • translating between CSS property names (kebab-cased, like flex-grow) to the js version of them on the style object (camel-cased, like flexGrow)
  • translating between HTML data-* attribute names (kebab-cased, like data-foo-bar) and the properties on the dataset object (camel-cased, like el.dataset.fooBar)
2 Likes

Wouldn’t it be easier and more greppable/debuggable for the web to add aliases under the proper casing?

1 Like

To me, this question pops up pretty often during:

  • CI/CD pipeline configurations (e.g., when creating a feature environment based on the name of the feature branch);
  • cloud config (e.g., when creating an ID of an AWS lambda based on the name of a function).

Could you add an example?

The example is in what I'm replying to:

translating between HTML data-* attribute names (kebab-cased, like data-foo-bar) and the properties on the dataset object (camel-cased, like el.dataset.fooBar)

In other words, why not a el.dataset['foo-bar'] getter/setter alongside the fooBar one?

1 Like

I'm extremely in favor of this, at least from the context of CSS, but of course further discussion on that is obviously off-topic here.

Perhaps we need a capitalize method first – string[0].toUpperCase() + string.slice(1) is verbose.