From e687ef9e0c64a9ab98195e98f05ea56b857c7949 Mon Sep 17 00:00:00 2001 From: dayongkr Date: Sat, 24 Oct 2026 18:45:16 +0900 Subject: [PATCH] fix[startCase]: only uppercase the first letter of each word like lodash MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `startCase` lowercased the rest of every word that was not all uppercase. Since #2097, `words` keeps camel humps in non-Latin scripts together like lodash, so `startCase('ПриветМир')` turned into `'Приветмир'` instead of lodash's `'ПриветМир'`. lodash only applies `upperFirst` to each word, and it does so by code point. Do the same, so astral first letters such as `'𐐨'` are uppercased too. --- src/compat/string/startCase.spec.ts | 11 +++++++++++ src/compat/string/startCase.ts | 10 ++++++---- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/src/compat/string/startCase.spec.ts b/src/compat/string/startCase.spec.ts index 8f4aa839a..0afc0ea8d 100644 --- a/src/compat/string/startCase.spec.ts +++ b/src/compat/string/startCase.spec.ts @@ -66,4 +66,15 @@ describe('startCase', () => { expect(startCase('top10th')).toBe('Top 10th'); expect(startCase('1st place 2nd 3rd 4th')).toBe('1st Place 2nd 3rd 4th'); }); + + it('should only uppercase the first letter of each word', () => { + expect(startCase('ПриветМир')).toBe('ПриветМир'); + expect(startCase('αβγΔεζ')).toBe('ΑβγΔεζ'); + expect(startCase('fooBAR')).toBe('Foo BAR'); + expect(startCase('mIxEd CaSe')).toBe('M Ix Ed Ca Se'); + }); + + it('should uppercase a first letter outside the Basic Multilingual Plane', () => { + expect(startCase('𐐨𐐩 deseret')).toBe('𐐀 𐐁 Deseret'); + }); }); diff --git a/src/compat/string/startCase.ts b/src/compat/string/startCase.ts index 0b8742480..f0c6679e6 100644 --- a/src/compat/string/startCase.ts +++ b/src/compat/string/startCase.ts @@ -27,11 +27,13 @@ export function startCase(str?: string): string { result += ' '; } - if (word === word.toUpperCase()) { - result += word; - } else { - result += word[0].toUpperCase() + word.slice(1).toLowerCase(); + let firstLength = 1; + + if (word.codePointAt(0)! > 0xffff) { + firstLength = 2; } + + result += word.slice(0, firstLength).toUpperCase() + word.slice(firstLength); } return result;