diff --git a/packages/util/src/string/camelCase.spec.ts b/packages/util/src/string/camelCase.spec.ts index 03cfdcb50..6467e326f 100644 --- a/packages/util/src/string/camelCase.spec.ts +++ b/packages/util/src/string/camelCase.spec.ts @@ -53,6 +53,9 @@ describe('stringCamelCase', (): void => { expect( stringCamelCase('DEDUP_KEY_PREFIX') ).toEqual('dedupKeyPrefix'); + expect( + stringCamelCase(String('DEDUP_KEY_PREFIX')) + ).toEqual('dedupKeyPrefix'); expect( stringCamelCase('SOMETHING') ).toEqual('something'); @@ -109,5 +112,6 @@ describe('stringCamelCase', (): void => { ).toEqual('aBCDef'); }); - performance('stringCamelCase', 100_000, randomWords, stringCamelCase); + performance('stringCamelCase (random)', 100_000, randomWords, stringCamelCase); + performance('stringCamelCase (NFTOrder)', 100_000, [['NFTOrder']], stringCamelCase); }); diff --git a/packages/util/src/string/camelCase.ts b/packages/util/src/string/camelCase.ts index 732f72c97..cce007f11 100644 --- a/packages/util/src/string/camelCase.ts +++ b/packages/util/src/string/camelCase.ts @@ -3,6 +3,18 @@ import type { AnyString } from '../types'; +export const CC_TO_UP = new Array(256); +export const CC_TO_LO = new Array(256); + +for (let i = 0; i < CC_TO_UP.length; i++) { + CC_TO_LO[i] = String.fromCharCode(i).toLowerCase(); + CC_TO_UP[i] = String.fromCharCode(i).toUpperCase(); +} + +function formatRuns (w: string): string { + return w.slice(0, w.length - 1).toLowerCase() + CC_TO_UP[w.charCodeAt(w.length - 1)]; +} + // Inspired from https://stackoverflow.com/a/2970667 // // this is not as optimal as the original answer (we split into multiple), @@ -10,24 +22,22 @@ import type { AnyString } from '../types'; // a major improvement over the original camelcase npm package (at running) // // original: 20.88 μs/op -// this: 1.20 μs/op +// this: 1.09 μs/op // // Caveat of this: only Ascii, but acceptable for the intended usecase function converter (format: (w: string, i: number) => string): (value: AnyString) => string { - const formatRuns = (w: string) => w.slice(0, w.length - 1).toLowerCase() + w.slice(-1).toUpperCase(); - return (value: AnyString): string => { const parts = value - .toString() // replace all seperators (including consequtive) with spaces .replace(/[-_., ]+/g, ' ') // we don't want leading or trailing spaces .trim() // split into words .split(' '); + const count = parts.length; let result = ''; - for (let i = 0; i < parts.length; i++) { + for (let i = 0; i < count; i++) { const w = parts[i]; // apply the formatting @@ -52,7 +62,7 @@ function converter (format: (w: string, i: number) => string): (value: AnyString */ export const stringCamelCase = converter((w, i) => // lowercase for first letter/first word, else uppercase first, rest unchanged - (i ? w[0].toUpperCase() : w[0].toLowerCase()) + w.slice(1) + (i ? CC_TO_UP[w.charCodeAt(0)] : CC_TO_LO[w.charCodeAt(0)]) + w.slice(1) ); /** @@ -61,5 +71,5 @@ export const stringCamelCase = converter((w, i) => */ export const stringPascalCase = converter((w) => // uppercase the first character, leave the rest unchanged - w[0].toUpperCase() + w.slice(1) + CC_TO_UP[w.charCodeAt(0)] + w.slice(1) ); diff --git a/packages/util/src/string/lowerFirst.spec.ts b/packages/util/src/string/lowerFirst.spec.ts index cfe7843f4..a7ef11d32 100644 --- a/packages/util/src/string/lowerFirst.spec.ts +++ b/packages/util/src/string/lowerFirst.spec.ts @@ -1,6 +1,7 @@ // Copyright 2017-2022 @polkadot/util authors & contributors // SPDX-License-Identifier: Apache-2.0 +import { performance } from '../test/performance'; import { stringLowerFirst } from '.'; describe('stringLowerFirst', (): void => { @@ -33,4 +34,6 @@ describe('stringLowerFirst', (): void => { stringLowerFirst(null) ).toBe(''); }); + + performance('stringLowerFirst', 1_000_000, [['HelloWorldSomething']], stringLowerFirst); }); diff --git a/packages/util/src/string/lowerFirst.ts b/packages/util/src/string/lowerFirst.ts index 406cf33e1..69c89a0eb 100644 --- a/packages/util/src/string/lowerFirst.ts +++ b/packages/util/src/string/lowerFirst.ts @@ -3,10 +3,12 @@ import type { AnyString } from '../types'; -function converter (fn: (value: string) => string): (value?: AnyString | null) => string { +import { CC_TO_LO, CC_TO_UP } from './camelCase'; + +function converter (map: string[]): (value?: AnyString | null) => string { return (value?: AnyString | null): string => value - ? fn(value[0]) + value.slice(1) + ? map[value.charCodeAt(0)] + value.slice(1) : ''; } @@ -24,7 +26,7 @@ function converter (fn: (value: string) => string): (value?: AnyString | null) = * stringLowerFirst('ABC'); // => 'aBC' * ``` */ -export const stringLowerFirst = converter((s) => s.toLowerCase()); +export const stringLowerFirst = converter(CC_TO_LO); /** * @name stringUpperFirst @@ -40,4 +42,4 @@ export const stringLowerFirst = converter((s) => s.toLowerCase()); * stringUpperFirst('abc'); // => 'Abc' * ``` */ -export const stringUpperFirst = converter((s) => s.toUpperCase()); +export const stringUpperFirst = converter(CC_TO_UP); diff --git a/packages/util/src/string/upperFirst.spec.ts b/packages/util/src/string/upperFirst.spec.ts index 5bcf43d43..c707f7ce8 100644 --- a/packages/util/src/string/upperFirst.spec.ts +++ b/packages/util/src/string/upperFirst.spec.ts @@ -1,6 +1,7 @@ // Copyright 2017-2022 @polkadot/util authors & contributors // SPDX-License-Identifier: Apache-2.0 +import { performance } from '../test/performance'; import { stringUpperFirst } from '.'; describe('stringUpperFirst', (): void => { @@ -33,4 +34,6 @@ describe('stringUpperFirst', (): void => { stringUpperFirst(null) ).toBe(''); }); + + performance('stringUpperFirst', 1_000_000, [['helloWorldSomething']], stringUpperFirst); });