Repository navigation
Description
Version: @nevware21/ts-utils 0.16.0 (0.15.0 gives the same output for the inputs checked)
Environment: Node v22.23.4, the package's dist/es5/mod build
Summary
All four helpers are built on two regular expressions:
_convertCase:/((_|\W)+(\w){0,1}|([a-z])([A-Z]))/gstrLetterCase:/(_|\b)\w/g
Without the u flag, \w, \W and \b cover ASCII only, and the conversion only rewrites the character after a boundary. That causes the five behaviours below. Sections 1, 3 and 4 look like bugs; section 2 is a word-boundary rule worth deciding; section 5 is a question. Every "Actual" value comes from running 0.16.0. The "Suggested" column is a proposal, not a claim about intended behaviour.
1. Bug: strCamelCase does not normalise the case inside a word
| Call | Actual | Suggested |
|---|---|---|
strCamelCase("hELLo dARKness-my old_friend") |
hELLoDARKnessMyOldFriend |
helloDarknessMyOldFriend |
strCamelCase("ABC def") |
aBCDef |
abcDef |
strCamelCase("HELLO WORLD") |
hELLOWORLD |
helloWorld |
strCamelCase("EFTPOS PURCHASE 1234") |
eFTPOSPURCHASE1234 |
eftposPurchase1234 |
Only the first character is lower-cased (/^\w/) and each later word's first letter upper-cased. The rest of each word keeps its case, so all-caps input loses its word boundaries entirely (hELLOWORLD).
2. Word boundaries inside a word are found inconsistently (kebab and snake case)
| Call | Actual | Suggested |
|---|---|---|
strKebabCase("hELLo dARKness-my old_friend") |
h-ello-darkness-my-old-friend |
hello-darkness-my-old-friend |
strKebabCase("ABCDef") |
abcdef |
abc-def |
strKebabCase("XMLHttpRequest") |
xmlhttp-request |
xml-http-request |
strKebabCase("fooBar2Baz") |
foo-bar2baz |
foo-bar2-baz |
([a-z])([A-Z])splits after a lone lower-case letter (h+ELLo).- It never splits an acronym from the word after it (
ABCDef,XMLHttp). - It never splits a digit from an upper-case letter (
2Baz). strCamelCaseon the samehELLoinput does not split there at all, so camel case and kebab case disagree about where the words are.
3. Bug: letters outside ASCII are treated as separators and dropped
| Call | Actual | Suggested |
|---|---|---|
strCamelCase("café crème") |
cafCrMe |
caféCrème |
strKebabCase("café crème") |
caf-cr-me |
café-crème |
strCamelCase("über straße") |
berStraE |
überStraße |
strCapitalizeWords("café crème") |
Café CrèMe |
Café Crème |
é, è, ü and ß match \W, so camel, kebab and snake case replace them with the separator and lose them. \b sees a word boundary after them, so capitalise-words capitalises the next letter (CrèMe). Unicode property escapes ([\p{L}\p{N}] with the u flag) would keep them. They need ES2018, which may not fit the ES5 build, so a character-class alternative or an option may be needed there.
4. Bug: leading and trailing separators become a dangling separator
| Call | Actual | Suggested |
|---|---|---|
strKebabCase("__init__") |
-init- |
init |
strKebabCase("--foo--") |
-foo- |
foo |
strSnakeCase("O'Brien & Sons, Ltd.") |
o_brien_sons_ltd_ |
o_brien_sons_ltd |
strCamelCase("O'Brien & Sons, Ltd.") |
oBrienSonsLtd |
(as is) |
Only whitespace is trimmed before conversion, so any other leading or trailing punctuation becomes a separator at the edge. Camel case drops it, so camel case and kebab/snake case disagree here too.
5. Question: should strCapitalizeWords keep camel-case word boundaries?
| Call | Actual |
|---|---|
strCapitalizeWords("fooBarBaz") |
Foobarbaz |
strCapitalizeWords("foo_bar-baz qux") |
Foo_Bar-Baz Qux |
It lower-cases everything before capitalising, so camel-case input becomes a single word. This may be intended; if so, it would help to document it.
Repro
const { strCamelCase, strKebabCase, strSnakeCase, strCapitalizeWords } = require("@nevware21/ts-utils");
console.log(strCamelCase("hELLo dARKness-my old_friend")); // hELLoDARKnessMyOldFriend
console.log(strCamelCase("HELLO WORLD")); // hELLOWORLD
console.log(strKebabCase("hELLo dARKness-my old_friend")); // h-ello-darkness-my-old-friend
console.log(strKebabCase("XMLHttpRequest")); // xmlhttp-request
console.log(strKebabCase("fooBar2Baz")); // foo-bar2baz
console.log(strCamelCase("café crème")); // cafCrMe
console.log(strCapitalizeWords("café crème")); // Café CrèMe
console.log(strKebabCase("__init__")); // -init-
console.log(strSnakeCase("O'Brien & Sons, Ltd.")); // o_brien_sons_ltd_
console.log(strCapitalizeWords("fooBarBaz")); // FoobarbazCompatibility
Any of these fixes changes output that existing callers may rely on, including code that ports these helpers and must match them output for output. A changelog entry, or an option on each helper that selects the new rules, would let callers move deliberately.
Activity
[Bug] Case helpers (strCamelCase, strKebabCase, strSnakeCase, strCapi…
[Bug] Case helpers (strCamelCase, strKebabCase, strSnakeCase, strCapi…
[Bug] Case helpers (strCamelCase, strKebabCase, strSnakeCase, strCapi…
[Bug] Case helpers (strCamelCase, strKebabCase, strSnakeCase, ...) (#636