Comparing version 1.0.0 to 1.1.0
@@ -0,1 +1,9 @@ | ||
type GetTuple<L extends number, result extends any[] = []> = result['length'] extends L ? result : GetTuple<L, [...result, any]>; | ||
declare namespace Math { | ||
type Subtract<A extends number, B extends number> = GetTuple<A> extends [...infer U, ...GetTuple<B>] ? U['length'] : 0; | ||
type IsPositive<T extends number> = `${T}` extends `-${number}` ? false : true; | ||
type Abs<T extends number> = `${T}` extends `-${infer U extends number}` ? U : T; | ||
type GetPositiveIndex<T extends string, I extends number> = IsPositive<I> extends true ? I : Subtract<Length<T>, Abs<I>>; | ||
} | ||
/** | ||
@@ -6,5 +14,5 @@ * Gets the character at the given index. | ||
*/ | ||
type CharAt<T extends string, index extends number> = Split<T, ''>[index]; | ||
type CharAt<T extends string, index extends number> = Split<T>[index]; | ||
/** | ||
* A strongly typed version of `String.prototype.charAt`. | ||
* A strongly-typed version of `String.prototype.charAt`. | ||
* @param str the string to get the character from. | ||
@@ -17,2 +25,14 @@ * @param index the index of the character. | ||
/** | ||
* Concatenates a tuple of strings. | ||
* T: The tuple of strings to concatenate. | ||
*/ | ||
type Concat<T extends string[]> = Join<T>; | ||
/** | ||
* A strongly-typed version of `String.prototype.concat`. | ||
* @param strings the tuple of strings to concatenate. | ||
* @returns the concatenated string in both type level and runtime. | ||
* @example concat('a', 'bc', 'def') // 'abcdef' | ||
*/ | ||
declare function concat<T extends string[]>(...strings: T): Concat<T>; | ||
/** | ||
* Joins a tuple of strings with the given delimiter. | ||
@@ -27,3 +47,3 @@ * T: The tuple of strings to join. | ||
/** | ||
* A strongly typed version of `Array.prototype.join`. | ||
* A strongly-typed version of `Array.prototype.join`. | ||
* @param tuple the tuple of strings to join. | ||
@@ -36,2 +56,13 @@ * @param delimiter the delimiter. | ||
/** | ||
* Gets the length of a string. | ||
*/ | ||
type Length<T extends string> = Split<T>['length']; | ||
/** | ||
* A strongly-typed version of `String.prototype.length`. | ||
* @param str the string to get the length from. | ||
* @returns the length of the string in both type level and runtime. | ||
* @example length('hello world') // 11 | ||
*/ | ||
declare function length<T extends string>(str: T): Length<T>; | ||
/** | ||
* Replaces the first occurrence of a string with another string. | ||
@@ -44,3 +75,3 @@ * sentence: The sentence to replace. | ||
/** | ||
* A strongly typed version of `String.prototype.replace`. | ||
* A strongly-typed version of `String.prototype.replace`. | ||
* @param sentence the sentence to replace. | ||
@@ -61,3 +92,3 @@ * @param lookup the lookup string to be replaced. | ||
/** | ||
* A strongly typed version of `String.prototype.replaceAll`. | ||
* A strongly-typed version of `String.prototype.replaceAll`. | ||
* @param sentence the sentence to replace. | ||
@@ -71,2 +102,20 @@ * @param lookup the lookup string to be replaced. | ||
/** | ||
* Slices a string from a startIndex to an endIndex. | ||
* T: The string to slice. | ||
* startIndex: The start index. | ||
* endIndex: The end index. | ||
* @warning 🚨 it doesn't work exactly like the native slice as it will ignore the end index if start index is negative | ||
*/ | ||
type Slice<T extends string, startIndex extends number = 0, endIndex extends number = Split<T>['length']> = T extends `${infer head}${infer rest}` ? startIndex extends 0 ? endIndex extends 0 ? '' : `${head}${Slice<rest, 0, endIndex extends -1 ? -1 : Math.Subtract<endIndex, 1>>}` : `${Slice<rest, Math.Subtract<Math.GetPositiveIndex<T, startIndex>, 1>, Math.IsPositive<startIndex> extends true ? Math.Subtract<endIndex, 1> : Split<T>['length']>}` : ''; | ||
/** | ||
* A strongly-typed version of `String.prototype.slice`. | ||
* @param str the string to slice. | ||
* @param start the start index. | ||
* @param end the end index. | ||
* @returns the sliced string in both type level and runtime. | ||
* @example slice('hello world', 6) // 'world' | ||
* @warning 🚨 it doesn't work exactly like the native slice as it will ignore the end index if start index is negative | ||
*/ | ||
declare function slice<T extends string, const S extends number = 0, const E extends number = Split<T>['length']>(str: T, start?: S, end?: E): Slice<T, S, E>; | ||
/** | ||
* Splits a string into an array of substrings. | ||
@@ -78,3 +127,3 @@ * T: The string to split. | ||
/** | ||
* A strongly typed version of `String.prototype.split`. | ||
* A strongly-typed version of `String.prototype.split`. | ||
* @param str the string to split. | ||
@@ -92,3 +141,3 @@ * @param delimiter the delimiter. | ||
/** | ||
* A strongly typed version of `String.prototype.trimStart`. | ||
* A strongly-typed version of `String.prototype.trimStart`. | ||
* @param str the string to trim. | ||
@@ -105,3 +154,3 @@ * @returns the trimmed string in both type level and runtime. | ||
/** | ||
* A strongly typed version of `String.prototype.trimEnd`. | ||
* A strongly-typed version of `String.prototype.trimEnd`. | ||
* @param str the string to trim. | ||
@@ -118,3 +167,3 @@ * @returns the trimmed string in both type level and runtime. | ||
/** | ||
* A strongly typed version of `String.prototype.trim`. | ||
* A strongly-typed version of `String.prototype.trim`. | ||
* @param str the string to trim. | ||
@@ -140,6 +189,6 @@ * @returns the trimmed string in both type level and runtime. | ||
*/ | ||
type PascalCaseAll<T extends string[]> = T extends [infer First, ...infer Rest] ? [ | ||
Capitalize<Lowercase<Is<First, string>>>, | ||
...PascalCaseAll<Is<Rest, string[]>> | ||
] : T; | ||
type PascalCaseAll<T extends string[]> = T extends [ | ||
infer head extends string, | ||
...infer rest extends string[] | ||
] ? [Capitalize<Lowercase<head>>, ...PascalCaseAll<rest>] : T; | ||
@@ -214,2 +263,9 @@ type Digit = '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9'; | ||
/** | ||
* Capitalizes the first letter of a string. This is a runtime counterpart of `Capitalize<T>` from `src/types.d.ts`. | ||
* @param str the string to capitalize. | ||
* @returns the capitalized string. | ||
* @example capitalize('hello world') // 'Hello world' | ||
*/ | ||
declare function capitalize<T extends string>(str: T): Capitalize<T>; | ||
/** | ||
* This function is a strongly-typed counterpart of String.prototype.toLowerCase. | ||
@@ -229,8 +285,8 @@ * @param str the string to make lowercase. | ||
/** | ||
* Capitalizes the first letter of a string. This is a runtime counterpart of `Capitalize<T>` from `src/types.d.ts`. | ||
* @param str the string to capitalize. | ||
* @returns the capitalized string. | ||
* @example capitalize('hello world') // 'Hello world' | ||
* Uncapitalizes the first letter of a string. This is a runtime counterpart of `Uncapitalize<T>` from `src/types.d.ts`. | ||
* @param str the string to uncapitalize. | ||
* @returns the uncapitalized string. | ||
* @example uncapitalize('Hello world') // 'hello world' | ||
*/ | ||
declare function capitalize<T extends string>(str: T): Capitalize<T>; | ||
declare function uncapitalize<T extends string>(str: T): Uncapitalize<T>; | ||
/** | ||
@@ -251,3 +307,3 @@ * Transforms a string with the specified separator (delimiter). | ||
*/ | ||
type CamelCase<T extends string> = T extends unknown ? PascalCase<T> extends `${infer first}${infer rest}` ? `${Lowercase<first>}${rest}` : T : never; | ||
type CamelCase<T extends string> = Uncapitalize<PascalCase<T>>; | ||
/** | ||
@@ -263,3 +319,3 @@ * A strongly typed version of `toCamelCase` that works in both runtime and type level. | ||
*/ | ||
type PascalCase<T extends string> = Join<PascalCaseAll<Is<Words<T>, string[]>>>; | ||
type PascalCase<T extends string> = Join<PascalCaseAll<Words<T>>>; | ||
/** | ||
@@ -328,2 +384,16 @@ * A strongly typed version of `toPascalCase` that works in both runtime and type level. | ||
/** | ||
* Shallowly transforms the keys of an Record to camelCase. | ||
* T: the type of the Record to transform. | ||
*/ | ||
type CamelKeys<T> = T extends [] ? T : { | ||
[K in keyof T as CamelCase<Is<K, string>>]: T[K]; | ||
}; | ||
/** | ||
* A strongly typed function that shallowly transforms the keys of an object to camelCase. The transformation is done both at runtime and type level. | ||
* @param obj the object to transform. | ||
* @returns the transformed object. | ||
* @example camelKeys({ 'foo-bar': { 'fizz-buzz': true } }) // { fooBar: { 'fizz-buz': true } } | ||
*/ | ||
declare function camelKeys<T>(obj: T): CamelKeys<T>; | ||
/** | ||
* Recursively transforms the keys of an Record to camelCase. | ||
@@ -338,52 +408,86 @@ * T: the type of the Record to transform. | ||
/** | ||
* Shallowly transforms the keys of an Record to camelCase. | ||
* A strongly typed function that recursively transforms the keys of an object to camelCase. The transformation is done both at runtime and type level. | ||
* @param obj the object to transform. | ||
* @returns the transformed object. | ||
* @example deepCamelKeys({ 'foo-bar': { 'fizz-buzz': true } }) // { fooBar: { fizzBuzz: true } } | ||
*/ | ||
declare function deepCamelKeys<T>(obj: T): DeepCamelKeys<T>; | ||
/** | ||
* Shallowly transforms the keys of an Record to CONSTANT_CASE. | ||
* T: the type of the Record to transform. | ||
*/ | ||
type CamelKeys<T> = T extends [] ? T : { | ||
[K in keyof T as CamelCase<Is<K, string>>]: T[K]; | ||
type ConstantKeys<T> = T extends [] ? T : { | ||
[K in keyof T as ConstantCase<Is<K, string>>]: T[K]; | ||
}; | ||
/** | ||
* A strongly typed function that recursively transforms the keys of an object to camelCase. The transformation is done both at runtime and type level. | ||
* A strongly typed function that shallowly transforms the keys of an object to CONSTANT_CASE. The transformation is done both at runtime and type level. | ||
* @param obj the object to transform. | ||
* @returns the transformed object. | ||
* @example deepCamelKeys({ 'foo-bar': { 'fizz-buzz': true } }) // { fooBar: { fizzBuzz: true } } | ||
* @example constantKeys({ 'foo-bar': { 'fizz-buzz': true } }) // { FOO_BAR: { 'fizz-buzz': true } } | ||
*/ | ||
declare function deepCamelKeys<T>(obj: T): DeepCamelKeys<T>; | ||
declare function constantKeys<T>(obj: T): ConstantKeys<T>; | ||
/** | ||
* A strongly typed function that shallowly transforms the keys of an object to camelCase. The transformation is done both at runtime and type level. | ||
* Recursively transforms the keys of an Record to CONSTANT_CASE. | ||
* T: the type of the Record to transform. | ||
*/ | ||
type DeepConstantKeys<T> = T extends [any, ...any] ? { | ||
[I in keyof T]: DeepConstantKeys<T[I]>; | ||
} : T extends (infer V)[] ? DeepConstantKeys<V>[] : { | ||
[K in keyof T as ConstantCase<Is<K, string>>]: DeepConstantKeys<T[K]>; | ||
}; | ||
/** | ||
* A strongly typed function that recursively transforms the keys of an object to CONSTANT_CASE. The transformation is done both at runtime and type level. | ||
* @param obj the object to transform. | ||
* @returns the transformed object. | ||
* @example camelKeys({ 'foo-bar': { 'fizz-buzz': true } }) // { fooBar: { 'fizz-buz': true } } | ||
* @example deepConstantKeys({ 'foo-bar': { 'fizz-buzz': true } }) // { FOO_BAR: { FIZZ_BUZZ: true } } | ||
*/ | ||
declare function camelKeys<T>(obj: T): CamelKeys<T>; | ||
declare function deepConstantKeys<T>(obj: T): DeepConstantKeys<T>; | ||
/** | ||
* Recursively transforms the keys of an Record to PascalCase. | ||
* Shallowly transforms the keys of an Record to a custom delimiter case. | ||
* T: the type of the Record to transform. | ||
* D: the delimiter to use. | ||
*/ | ||
type DeepPascalKeys<T> = T extends [any, ...any] ? { | ||
[I in keyof T]: DeepPascalKeys<T[I]>; | ||
} : T extends (infer V)[] ? DeepPascalKeys<V>[] : { | ||
[K in keyof T as PascalCase<Is<K, string>>]: DeepPascalKeys<T[K]>; | ||
type DelimiterKeys<T, D extends string> = T extends [] ? T : { | ||
[K in keyof T as DelimiterCase<Is<K, string>, D>]: T[K]; | ||
}; | ||
/** | ||
* Shallowly transforms the keys of an Record to PascalCase. | ||
* A strongly typed function that shallowly transforms the keys of an object to a custom delimiter case. The transformation is done both at runtime and type level. | ||
* @param obj the object to transform. | ||
* @param delimiter the delimiter to use. | ||
* @returns the transformed object. | ||
* @example delimiterKeys({ 'foo-bar': { 'fizz-buzz': true } }, '.') // { 'foo.bar': { 'fizz.buzz': true } } | ||
*/ | ||
declare function delimiterKeys<T, D extends string>(obj: T, delimiter: D): DelimiterKeys<T, D>; | ||
/** | ||
* Recursively transforms the keys of an Record to a custom delimiter case. | ||
* T: the type of the Record to transform. | ||
* D: the delimiter to use. | ||
*/ | ||
type PascalKeys<T> = T extends [] ? T : { | ||
[K in keyof T as PascalCase<Is<K, string>>]: T[K]; | ||
type DeepDelimiterKeys<T, D extends string> = T extends [any, ...any] ? { | ||
[I in keyof T]: DeepDelimiterKeys<T[I], D>; | ||
} : T extends (infer V)[] ? DeepDelimiterKeys<V, D>[] : { | ||
[K in keyof T as DelimiterCase<Is<K, string>, D>]: DeepDelimiterKeys<T[K], D>; | ||
}; | ||
/** | ||
* A strongly typed function that recursively transforms the keys of an object to pascal case. The transformation is done both at runtime and type level. | ||
* A strongly typed function that recursively transforms the keys of an object to a custom delimiter case. The transformation is done both at runtime and type level. | ||
* @param obj the object to transform. | ||
* @param delimiter the delimiter to use. | ||
* @returns the transformed object. | ||
* @example deepPascalKeys({ 'foo-bar': { 'fizz-buzz': true } }) // { FooBar: { FizzBuzz: true } } | ||
* @example deepDelimiterKeys({ 'foo-bar': { 'fizz-buzz': true } }, '.') // { 'foo.bar': { 'fizz.buzz': true } } | ||
*/ | ||
declare function deepPascalKeys<T>(obj: T): DeepPascalKeys<T>; | ||
declare function deepDelimiterKeys<T, D extends string>(obj: T, delimiter: D): DeepDelimiterKeys<T, D>; | ||
/** | ||
* A strongly typed function that shallowly transforms the keys of an object to pascal case. The transformation is done both at runtime and type level. | ||
* Shallowly transforms the keys of an Record to kebab-case. | ||
* T: the type of the Record to transform. | ||
*/ | ||
type KebabKeys<T> = T extends [] ? T : { | ||
[K in keyof T as KebabCase<Is<K, string>>]: T[K]; | ||
}; | ||
/** | ||
* A strongly typed function that shallowly transforms the keys of an object to kebab-case. The transformation is done both at runtime and type level. | ||
* @param obj the object to transform. | ||
* @returns the transformed object. | ||
* @example pascalKeys({ 'foo-bar': { 'fizz-buzz': true } }) // { FooBar: { 'fizz-buzz': true } } | ||
* @example kebabKeys({ fooBar: { fizzBuzz: true } }) // { 'foo-bar': { fizzBuzz: true } } | ||
*/ | ||
declare function pascalKeys<T>(obj: T): PascalKeys<T>; | ||
declare function kebabKeys<T>(obj: T): KebabKeys<T>; | ||
/** | ||
@@ -399,9 +503,2 @@ * Recursively transforms the keys of an Record to kebab-case. | ||
/** | ||
* Shallowly transforms the keys of an Record to kebab-case. | ||
* T: the type of the Record to transform. | ||
*/ | ||
type KebabKeys<T> = T extends [] ? T : { | ||
[K in keyof T as KebabCase<Is<K, string>>]: T[K]; | ||
}; | ||
/** | ||
* A strongly typed function that recursively transforms the keys of an object to kebab-case. The transformation is done both at runtime and type level. | ||
@@ -414,18 +511,32 @@ * @param obj the object to transform. | ||
/** | ||
* A strongly typed function that shallowly transforms the keys of an object to kebab-case. The transformation is done both at runtime and type level. | ||
* Shallowly transforms the keys of an Record to PascalCase. | ||
* T: the type of the Record to transform. | ||
*/ | ||
type PascalKeys<T> = T extends [] ? T : { | ||
[K in keyof T as PascalCase<Is<K, string>>]: T[K]; | ||
}; | ||
/** | ||
* A strongly typed function that shallowly transforms the keys of an object to pascal case. The transformation is done both at runtime and type level. | ||
* @param obj the object to transform. | ||
* @returns the transformed object. | ||
* @example kebabKeys({ fooBar: { fizzBuzz: true } }) // { 'foo-bar': { fizzBuzz: true } } | ||
* @example pascalKeys({ 'foo-bar': { 'fizz-buzz': true } }) // { FooBar: { 'fizz-buzz': true } } | ||
*/ | ||
declare function kebabKeys<T>(obj: T): KebabKeys<T>; | ||
declare function pascalKeys<T>(obj: T): PascalKeys<T>; | ||
/** | ||
* Recursively transforms the keys of an Record to snake_case. | ||
* Recursively transforms the keys of an Record to PascalCase. | ||
* T: the type of the Record to transform. | ||
*/ | ||
type DeepSnakeKeys<T> = T extends [any, ...any] ? { | ||
[I in keyof T]: DeepSnakeKeys<T[I]>; | ||
} : T extends (infer V)[] ? DeepSnakeKeys<V>[] : { | ||
[K in keyof T as SnakeCase<Is<K, string>>]: DeepSnakeKeys<T[K]>; | ||
type DeepPascalKeys<T> = T extends [any, ...any] ? { | ||
[I in keyof T]: DeepPascalKeys<T[I]>; | ||
} : T extends (infer V)[] ? DeepPascalKeys<V>[] : { | ||
[K in keyof T as PascalCase<Is<K, string>>]: DeepPascalKeys<T[K]>; | ||
}; | ||
/** | ||
* A strongly typed function that recursively transforms the keys of an object to pascal case. The transformation is done both at runtime and type level. | ||
* @param obj the object to transform. | ||
* @returns the transformed object. | ||
* @example deepPascalKeys({ 'foo-bar': { 'fizz-buzz': true } }) // { FooBar: { FizzBuzz: true } } | ||
*/ | ||
declare function deepPascalKeys<T>(obj: T): DeepPascalKeys<T>; | ||
/** | ||
* Shallowly transforms the keys of an Record to snake_case. | ||
@@ -438,9 +549,2 @@ * T: the type of the Record to transform. | ||
/** | ||
* A strongly typed function that recursively transforms the keys of an object to snake_case. The transformation is done both at runtime and type level. | ||
* @param obj the object to transform. | ||
* @returns the transformed object. | ||
* @example deepSnakeKeys({ 'foo-bar': { 'fizz-buzz': true } }) // { 'foo_bar': { 'fizz_buzz': true } } | ||
*/ | ||
declare function deepSnakeKeys<T>(obj: T): DeepSnakeKeys<T>; | ||
/** | ||
* A strongly typed function that shallowly the keys of an object to snake_case. The transformation is done both at runtime and type level. | ||
@@ -453,66 +557,18 @@ * @param obj the object to transform. | ||
/** | ||
* Recursively transforms the keys of an Record to CONSTANT_CASE. | ||
* Recursively transforms the keys of an Record to snake_case. | ||
* T: the type of the Record to transform. | ||
*/ | ||
type DeepConstantKeys<T> = T extends [any, ...any] ? { | ||
[I in keyof T]: DeepConstantKeys<T[I]>; | ||
} : T extends (infer V)[] ? DeepConstantKeys<V>[] : { | ||
[K in keyof T as ConstantCase<Is<K, string>>]: DeepConstantKeys<T[K]>; | ||
type DeepSnakeKeys<T> = T extends [any, ...any] ? { | ||
[I in keyof T]: DeepSnakeKeys<T[I]>; | ||
} : T extends (infer V)[] ? DeepSnakeKeys<V>[] : { | ||
[K in keyof T as SnakeCase<Is<K, string>>]: DeepSnakeKeys<T[K]>; | ||
}; | ||
/** | ||
* Shallowly transforms the keys of an Record to CONSTANT_CASE. | ||
* T: the type of the Record to transform. | ||
*/ | ||
type ConstantKeys<T> = T extends [] ? T : { | ||
[K in keyof T as ConstantCase<Is<K, string>>]: T[K]; | ||
}; | ||
/** | ||
* A strongly typed function that recursively transforms the keys of an object to CONSTANT_CASE. The transformation is done both at runtime and type level. | ||
* A strongly typed function that recursively transforms the keys of an object to snake_case. The transformation is done both at runtime and type level. | ||
* @param obj the object to transform. | ||
* @returns the transformed object. | ||
* @example deepConstantKeys({ 'foo-bar': { 'fizz-buzz': true } }) // { FOO_BAR: { FIZZ_BUZZ: true } } | ||
* @example deepSnakeKeys({ 'foo-bar': { 'fizz-buzz': true } }) // { 'foo_bar': { 'fizz_buzz': true } } | ||
*/ | ||
declare function deepConstantKeys<T>(obj: T): DeepConstantKeys<T>; | ||
/** | ||
* A strongly typed function that shallowly transforms the keys of an object to CONSTANT_CASE. The transformation is done both at runtime and type level. | ||
* @param obj the object to transform. | ||
* @returns the transformed object. | ||
* @example constantKeys({ 'foo-bar': { 'fizz-buzz': true } }) // { FOO_BAR: { 'fizz-buzz': true } } | ||
*/ | ||
declare function constantKeys<T>(obj: T): ConstantKeys<T>; | ||
/** | ||
* Recursively transforms the keys of an Record to a custom delimiter case. | ||
* T: the type of the Record to transform. | ||
* D: the delimiter to use. | ||
*/ | ||
type DeepDelimiterKeys<T, D extends string> = T extends [any, ...any] ? { | ||
[I in keyof T]: DeepDelimiterKeys<T[I], D>; | ||
} : T extends (infer V)[] ? DeepDelimiterKeys<V, D>[] : { | ||
[K in keyof T as DelimiterCase<Is<K, string>, D>]: DeepDelimiterKeys<T[K], D>; | ||
}; | ||
/** | ||
* Shallowly transforms the keys of an Record to a custom delimiter case. | ||
* T: the type of the Record to transform. | ||
* D: the delimiter to use. | ||
*/ | ||
type DelimiterKeys<T, D extends string> = T extends [] ? T : { | ||
[K in keyof T as DelimiterCase<Is<K, string>, D>]: T[K]; | ||
}; | ||
/** | ||
* A strongly typed function that recursively transforms the keys of an object to a custom delimiter case. The transformation is done both at runtime and type level. | ||
* @param obj the object to transform. | ||
* @param delimiter the delimiter to use. | ||
* @returns the transformed object. | ||
* @example deepDelimiterKeys({ 'foo-bar': { 'fizz-buzz': true } }, '.') // { 'foo.bar': { 'fizz.buzz': true } } | ||
*/ | ||
declare function deepDelimiterKeys<T, D extends string>(obj: T, delimiter: D): DeepDelimiterKeys<T, D>; | ||
/** | ||
* A strongly typed function that shallowly transforms the keys of an object to a custom delimiter case. The transformation is done both at runtime and type level. | ||
* @param obj the object to transform. | ||
* @param delimiter the delimiter to use. | ||
* @returns the transformed object. | ||
* @example delimiterKeys({ 'foo-bar': { 'fizz-buzz': true } }, '.') // { 'foo.bar': { 'fizz.buzz': true } } | ||
*/ | ||
declare function delimiterKeys<T, D extends string>(obj: T, delimiter: D): DelimiterKeys<T, D>; | ||
declare function deepSnakeKeys<T>(obj: T): DeepSnakeKeys<T>; | ||
export { CamelCase, CamelKeys, CharAt, ConstantCase, ConstantKeys, DeepCamelKeys, DeepConstantKeys, DeepDelimiterKeys, DeepKebabKeys, DeepPascalKeys, DeepSnakeKeys, DelimiterCase, DelimiterKeys, Digit, Is, IsDigit, IsLetter, IsLower, IsSeparator, IsSpecial, IsUpper, Join, KebabCase, KebabKeys, PascalCase, PascalKeys, Replace, ReplaceAll, Separator, SnakeCase, SnakeKeys, Split, TitleCase, Trim, TrimEnd, TrimStart, Words, camelKeys, capitalize, charAt, constantKeys, deepCamelKeys, deepConstantKeys, deepDelimiterKeys, deepKebabKeys, deepPascalKeys, deepSnakeKeys, deepTransformKeys, delimiterKeys, join, kebabKeys, pascalKeys, replace, replaceAll, snakeKeys, split, toCamelCase, toConstantCase, toDelimiterCase, toKebabCase, toLowerCase, toPascalCase, toSnakeCase, toTitleCase, toUpperCase, trim, trimEnd, trimStart, words }; | ||
export { CamelCase, CamelKeys, CharAt, Concat, ConstantCase, ConstantKeys, DeepCamelKeys, DeepConstantKeys, DeepDelimiterKeys, DeepKebabKeys, DeepPascalKeys, DeepSnakeKeys, DelimiterCase, DelimiterKeys, Digit, IsDigit, IsLetter, IsLower, IsSeparator, IsSpecial, IsUpper, Join, KebabCase, KebabKeys, Length, PascalCase, PascalKeys, Replace, ReplaceAll, Separator, Slice, SnakeCase, SnakeKeys, Split, TitleCase, Trim, TrimEnd, TrimStart, Words, camelKeys, capitalize, charAt, concat, constantKeys, deepCamelKeys, deepConstantKeys, deepDelimiterKeys, deepKebabKeys, deepPascalKeys, deepSnakeKeys, deepTransformKeys, delimiterKeys, join, kebabKeys, length, pascalKeys, replace, replaceAll, slice, snakeKeys, split, toCamelCase, toConstantCase, toDelimiterCase, toKebabCase, toLowerCase, toPascalCase, toSnakeCase, toTitleCase, toUpperCase, trim, trimEnd, trimStart, uncapitalize, words }; |
@@ -26,2 +26,3 @@ "use strict"; | ||
charAt: () => charAt, | ||
concat: () => concat, | ||
constantKeys: () => constantKeys, | ||
@@ -38,5 +39,7 @@ deepCamelKeys: () => deepCamelKeys, | ||
kebabKeys: () => kebabKeys, | ||
length: () => length, | ||
pascalKeys: () => pascalKeys, | ||
replace: () => replace, | ||
replaceAll: () => replaceAll, | ||
slice: () => slice, | ||
snakeKeys: () => snakeKeys, | ||
@@ -56,2 +59,3 @@ split: () => split, | ||
trimStart: () => trimStart, | ||
uncapitalize: () => uncapitalize, | ||
words: () => words | ||
@@ -65,14 +69,24 @@ }); | ||
} | ||
function concat(...strings) { | ||
return join(strings); | ||
} | ||
function join(tuple, delimiter) { | ||
return tuple.join(delimiter ?? ""); | ||
} | ||
function replace(sentence, lookup, replacement) { | ||
return sentence.replace(lookup, replacement ?? ""); | ||
function length(str) { | ||
return str.length; | ||
} | ||
function replaceAll(sentence, lookup, replacement) { | ||
return sentence.replaceAll( | ||
lookup, | ||
replacement ?? "" | ||
); | ||
function replace(sentence, lookup, replacement = "") { | ||
return sentence.replace(lookup, replacement); | ||
} | ||
function replaceAll(sentence, lookup, replacement = "") { | ||
if (typeof sentence.replaceAll === "function") { | ||
return sentence.replaceAll(lookup, replacement); | ||
} | ||
const regex = new RegExp(lookup, "g"); | ||
return sentence.replace(regex, replacement); | ||
} | ||
function slice(str, start = 0, end = str.length) { | ||
return str.slice(start, start < 0 ? void 0 : end); | ||
} | ||
function split(str, delimiter) { | ||
@@ -96,3 +110,14 @@ return str.split(delimiter ?? ""); | ||
// src/internals.ts | ||
function typeOf(t) { | ||
return Object.prototype.toString.call(t).replace(/^\[object (.+)\]$/, "$1").toLowerCase(); | ||
} | ||
function pascalCaseAll(words2) { | ||
return words2.map((v) => capitalize(toLowerCase(v))); | ||
} | ||
// src/casing.ts | ||
function capitalize(str) { | ||
return join([toUpperCase(charAt(str, 0)), slice(str, 1)]); | ||
} | ||
function toLowerCase(str) { | ||
@@ -104,4 +129,4 @@ return str.toLowerCase(); | ||
} | ||
function capitalize(str) { | ||
return toUpperCase(str.charAt(0)) + str.slice(1); | ||
function uncapitalize(str) { | ||
return join([toLowerCase(charAt(str, 0)), slice(str, 1)]); | ||
} | ||
@@ -112,7 +137,6 @@ function toDelimiterCase(str, delimiter) { | ||
function toCamelCase(str) { | ||
const res = toPascalCase(str); | ||
return res.slice(0, 1).toLowerCase() + res.slice(1); | ||
return uncapitalize(toPascalCase(str)); | ||
} | ||
function toPascalCase(str) { | ||
return words(str).map((v) => capitalize(toLowerCase(v))).join(""); | ||
return join(pascalCaseAll(words(str))); | ||
} | ||
@@ -132,8 +156,12 @@ function toKebabCase(str) { | ||
// src/internals.ts | ||
function typeOf(t) { | ||
return Object.prototype.toString.call(t).replace(/^\[object (.+)\]$/, "$1").toLowerCase(); | ||
// src/key-casing.ts | ||
function transformKeys(obj, transform) { | ||
if (typeOf(obj) !== "object") | ||
return obj; | ||
const res = {}; | ||
for (const key in obj) { | ||
res[transform(key)] = obj[key]; | ||
} | ||
return res; | ||
} | ||
// src/key-casing.ts | ||
function deepTransformKeys(obj, transform) { | ||
@@ -151,10 +179,4 @@ if (!["object", "array"].includes(typeOf(obj))) | ||
} | ||
function transformKeys(obj, transform) { | ||
if (typeOf(obj) !== "object") | ||
return obj; | ||
const res = {}; | ||
for (const key in obj) { | ||
res[transform(key)] = obj[key]; | ||
} | ||
return res; | ||
function camelKeys(obj) { | ||
return transformKeys(obj, toCamelCase); | ||
} | ||
@@ -164,13 +186,16 @@ function deepCamelKeys(obj) { | ||
} | ||
function camelKeys(obj) { | ||
return transformKeys(obj, toCamelCase); | ||
function constantKeys(obj) { | ||
return transformKeys(obj, toConstantCase); | ||
} | ||
function deepPascalKeys(obj) { | ||
return deepTransformKeys(obj, toPascalCase); | ||
function deepConstantKeys(obj) { | ||
return deepTransformKeys(obj, toConstantCase); | ||
} | ||
function pascalKeys(obj) { | ||
return transformKeys(obj, toPascalCase); | ||
function delimiterKeys(obj, delimiter) { | ||
return transformKeys(obj, (str) => toDelimiterCase(str, delimiter)); | ||
} | ||
function deepKebabKeys(obj) { | ||
return deepTransformKeys(obj, toKebabCase); | ||
function deepDelimiterKeys(obj, delimiter) { | ||
return deepTransformKeys( | ||
obj, | ||
(str) => toDelimiterCase(str, delimiter) | ||
); | ||
} | ||
@@ -180,23 +205,17 @@ function kebabKeys(obj) { | ||
} | ||
function deepSnakeKeys(obj) { | ||
return deepTransformKeys(obj, toSnakeCase); | ||
function deepKebabKeys(obj) { | ||
return deepTransformKeys(obj, toKebabCase); | ||
} | ||
function pascalKeys(obj) { | ||
return transformKeys(obj, toPascalCase); | ||
} | ||
function deepPascalKeys(obj) { | ||
return deepTransformKeys(obj, toPascalCase); | ||
} | ||
function snakeKeys(obj) { | ||
return transformKeys(obj, toSnakeCase); | ||
} | ||
function deepConstantKeys(obj) { | ||
return deepTransformKeys(obj, toConstantCase); | ||
function deepSnakeKeys(obj) { | ||
return deepTransformKeys(obj, toSnakeCase); | ||
} | ||
function constantKeys(obj) { | ||
return transformKeys(obj, toConstantCase); | ||
} | ||
function deepDelimiterKeys(obj, delimiter) { | ||
return deepTransformKeys( | ||
obj, | ||
(str) => toDelimiterCase(str, delimiter) | ||
); | ||
} | ||
function delimiterKeys(obj, delimiter) { | ||
return transformKeys(obj, (str) => toDelimiterCase(str, delimiter)); | ||
} | ||
// Annotate the CommonJS export names for ESM import in node: | ||
@@ -207,2 +226,3 @@ 0 && (module.exports = { | ||
charAt, | ||
concat, | ||
constantKeys, | ||
@@ -219,5 +239,7 @@ deepCamelKeys, | ||
kebabKeys, | ||
length, | ||
pascalKeys, | ||
replace, | ||
replaceAll, | ||
slice, | ||
snakeKeys, | ||
@@ -237,3 +259,4 @@ split, | ||
trimStart, | ||
uncapitalize, | ||
words | ||
}); |
{ | ||
"name": "string-ts", | ||
"version": "1.0.0", | ||
"version": "1.1.0", | ||
"description": "Strongly-typed string functions.", | ||
@@ -5,0 +5,0 @@ "main": "./dist/index.js", |
493
README.md
# Strongly-typed string functions for all! | ||
![A demonstration of string-ts](https://github.com/gustavoguichard/string-ts/assets/566971/0aa5603f-871d-4eb7-8ace-6a73466cec4d) | ||
## 😬 The problem | ||
@@ -37,3 +39,2 @@ | ||
This example should illustrate the highly-specific and flexible nature of `string-ts`. | ||
_Note: All types in this example could be inferred, but are included for demonstrative purposes._ | ||
@@ -43,6 +44,5 @@ ```ts | ||
import { camelCase, mapKeys } from 'lodash-es' | ||
import type { Dictionary } from 'lodash' | ||
import z from 'zod' | ||
export const EnvSchema = z.object({ | ||
const EnvSchema = z.object({ | ||
NODE_ENV: z.string(), | ||
@@ -52,7 +52,9 @@ }) | ||
function getEnvLoose() { | ||
const rawEnv: { NODE_ENV: string } = EnvSchema.parse(process.env) | ||
const env: Dictionary<string> = mapKeys(rawEnv, (_v, k) => camelCase(k)) | ||
const rawEnv = EnvSchema.parse(process.env) | ||
const env = mapKeys(rawEnv, (_v, k) => camelCase(k)) | ||
// ^? Dictionary<string> | ||
// `Dictionary<string>` is too loose | ||
// TypeScript is okay with this, 'abc' will be of type `string` | ||
// TypeScript is okay with this, 'abc' is expected to be of type `string` | ||
// This will have unexpected behavior at runtime | ||
console.log(env.abc) | ||
@@ -62,7 +64,9 @@ } | ||
function getEnvPrecise() { | ||
const rawEnv: { NODE_ENV: string } = EnvSchema.parse(process.env) | ||
const env: { nodeEnv: string } = deepCamelKeys(rawEnv) | ||
const rawEnv = EnvSchema.parse(process.env) | ||
const env = deepCamelKeys(rawEnv) | ||
// ^? { nodeEnv: string } | ||
// Error: Property 'abc' does not exist on type '{ nodeEnv: string; }' | ||
// Our type is more specific, so TypeScript catches this error. | ||
// This mistake will be caught at compile time | ||
console.log(env.abc) | ||
@@ -91,36 +95,40 @@ } | ||
- [capitalize](#capitalize) | ||
- [uncapitalize](#uncapitalize) | ||
- [Strongly-typed alternatives to native runtime utilities](#strongly-typed-alternatives-to-native-runtime-utilities) | ||
- [toUpperCase](#touppercase) | ||
- [toLowerCase](#tolowercase) | ||
- [trim](#trim) | ||
- [trimStart](#trimstart) | ||
- [trimEnd](#trimend) | ||
- [chartAt](#charat) | ||
- [charAt](#charat) | ||
- [concat](#concat) | ||
- [join](#join) | ||
- [length](#length) | ||
- [replace](#replace) | ||
- [replaceAll](#replaceall) | ||
- [slice](#slice) | ||
- [split](#split) | ||
- [toLowerCase](#tolowercase) | ||
- [toUpperCase](#touppercase) | ||
- [trim](#trim) | ||
- [trimEnd](#trimend) | ||
- [trimStart](#trimstart) | ||
- [Strongly-typed alternatives to common loosely-typed functions](#strongly-typed-alternatives-to-common-loosely-typed-functions) | ||
- [words](#words) | ||
- [toCamelCase](#tocamelcase) | ||
- [toConstantCase](#toconstantcase) | ||
- [toDelimiterCase](#todelimitercase) | ||
- [toCamelCase](#tocamelcase) | ||
- [toKebabCase](#tokebabcase) | ||
- [toPascalCase](#topascalcase) | ||
- [toKebabCase](#tokebabcase) | ||
- [toSnakeCase](#tosnakecase) | ||
- [toConstantCase](#toconstantcase) | ||
- [toTitleCase](#totitlecase) | ||
- [words](#words) | ||
- [Strongly-typed shallow transformation of objects](#strongly-typed-shallow-transformation-of-objects) | ||
- [DelimiterKeys](#delimiterkeys) | ||
- [CamelKeys](#camelkeys) | ||
- [PascalKeys](#pascalkeys) | ||
- [KebabKeys](#kebabkeys) | ||
- [SnakeKeys](#snakekeys) | ||
- [ConstantKeys](#constantkeys) | ||
- [camelKeys](#camelkeys) | ||
- [constantKeys](#constantkeys) | ||
- [delimiterKeys](#delimiterkeys) | ||
- [kebabKeys](#kebabkeys) | ||
- [pascalKeys](#pascalkeys) | ||
- [snakeKeys](#snakekeys) | ||
- [Strongly-typed deep transformation of objects](#strongly-typed-deep-transformation-of-objects) | ||
- [deepCamelKeys](#deepcamelkeys) | ||
- [deepConstantKeys](#deepconstantkeys) | ||
- [deepDelimiterKeys](#deepdelimiterkeys) | ||
- [deepCamelKeys](#deepcamelkeys) | ||
- [deepKebabKeys](#deepkebabkeys) | ||
- [deepPascalKeys](#deeppascalkeys) | ||
- [deepKebabKeys](#deepkebabkeys) | ||
- [deepSnakeKeys](#deepsnakekeys) | ||
- [deepConstantKeys](#deepconstantkeys) | ||
- [Type Utilities](#type-utilities) | ||
@@ -150,86 +158,61 @@ - [Native TS type utilities](#native-ts-type-utilities) | ||
## Strongly-typed alternatives to native runtime utilities | ||
### uncapitalize | ||
### toUpperCase | ||
Uncapitalizes the first letter of a string. This is a runtime counterpart of `Uncapitalize<T>` from `src/types.d.ts`. | ||
This function is a strongly-typed counterpart of `String.prototype.toUpperCase`. | ||
```ts | ||
import { toUpperCase } from 'string-ts' | ||
import { uncapitalize } from 'string-ts' | ||
const str = 'hello world' | ||
const result = toUpperCase(str) | ||
// ^ 'HELLO WORLD' | ||
``` | ||
### toLowerCase | ||
This function is a strongly-typed counterpart of `String.prototype.toLowerCase`. | ||
```ts | ||
import { toLowerCase } from 'string-ts' | ||
const str = 'HELLO WORLD' | ||
const result = toLowerCase(str) | ||
const str = 'Hello world' | ||
const result = uncapitalize(str) | ||
// ^ 'hello world' | ||
``` | ||
### trim | ||
## Strongly-typed alternatives to native runtime utilities | ||
This function is a strongly-typed counterpart of `String.prototype.trim`. | ||
### charAt | ||
```ts | ||
import { trim } from 'string-ts' | ||
This function is a strongly-typed counterpart of `String.prototype.charAt`. | ||
const str = ' hello world ' | ||
const result = trim(str) | ||
// ^ 'hello world' | ||
``` | ||
### trimStart | ||
This function is a strongly-typed counterpart of `String.prototype.trimStart`. | ||
```ts | ||
import { trimStart } from 'string-ts' | ||
import { charAt } from 'string-ts' | ||
const str = ' hello world ' | ||
const result = trimStart(str) | ||
// ^ 'hello world ' | ||
const str = 'hello world' | ||
const result = charAt(str, 6) | ||
// ^ 'w' | ||
``` | ||
### trimEnd | ||
### concat | ||
This function is a strongly-typed counterpart of `String.prototype.trimEnd`. | ||
This function is a strongly-typed counterpart of `String.prototype.concat`. | ||
```ts | ||
import { trimEnd } from 'string-ts' | ||
import { concat } from 'string-ts' | ||
const str = ' hello world ' | ||
const result = trimEnd(str) | ||
// ^ ' hello world' | ||
const result = concat('a', 'bc', 'def') | ||
// ^ 'abcdef' | ||
``` | ||
### charAt | ||
### join | ||
This function is a strongly-typed counterpart of `String.prototype.charAt`. | ||
This function is a strongly-typed counterpart of `Array.prototype.join`. | ||
```ts | ||
import { charAt } from 'string-ts' | ||
import { join } from 'string-ts' | ||
const str = 'hello world' | ||
const result = charAt(str, 6) | ||
// ^ 'w' | ||
const str = ['hello', 'world'] | ||
const result = join(str, ' ') | ||
// ^ 'hello world' | ||
``` | ||
### join | ||
### length | ||
This function is a strongly-typed counterpart of `Array.prototype.join`. | ||
This function is a strongly-typed counterpart of `String.prototype.length`. | ||
```ts | ||
import { join } from 'string-ts' | ||
import { length } from 'string-ts' | ||
const str = ['hello', 'world'] as const | ||
const result = join(str, ' ') | ||
// ^ 'hello world' | ||
const str = 'hello' | ||
const result = length(str) | ||
// ^ 5 | ||
``` | ||
@@ -241,2 +224,4 @@ | ||
_Warning: this is a partial implementation as we don't support Regex._ | ||
```ts | ||
@@ -253,3 +238,6 @@ import { replace } from 'string-ts' | ||
This function is a strongly-typed counterpart of `String.prototype.replaceAll`. | ||
It also has a polyfill for runtimes older than ES2021. | ||
_Warning: this is a partial implementation as we don't support Regex._ | ||
```ts | ||
@@ -263,2 +251,20 @@ import { replaceAll } from 'string-ts' | ||
### slice | ||
This function is a strongly-typed counterpart of `String.prototype.slice`. | ||
_Warning: this is a partial implementation. For now we ignore the second argument (endIndex) if the first (startIndex) is negative and we also don't support a negative endIndex._ | ||
```ts | ||
import { slice } from 'string-ts' | ||
const str = 'hello-world' | ||
const result = slice(str, 6) | ||
// ^ 'world' | ||
const result2 = slice(str, 1, 5) | ||
// ^ 'ello' | ||
const result3 = slice(str, -5) | ||
// ^ 'world' | ||
``` | ||
### split | ||
@@ -276,28 +282,64 @@ | ||
## Strongly-typed alternatives to common loosely-typed functions | ||
### toLowerCase | ||
### words | ||
This function is a strongly-typed counterpart of `String.prototype.toLowerCase`. | ||
This function identifies the words in a string and returns a tuple of words split by separators, differences in casing, numbers, and etc. | ||
```ts | ||
import { toLowerCase } from 'string-ts' | ||
const str = 'HELLO WORLD' | ||
const result = toLowerCase(str) | ||
// ^ 'hello world' | ||
``` | ||
### toUpperCase | ||
This function is a strongly-typed counterpart of `String.prototype.toUpperCase`. | ||
```ts | ||
import { words } from 'string-ts' | ||
import { toUpperCase } from 'string-ts' | ||
const str = '-20someVery-weird String' | ||
const result = words(str) | ||
// ^ ['20', 'some', 'Very', 'weird', 'String'] | ||
const str = 'hello world' | ||
const result = toUpperCase(str) | ||
// ^ 'HELLO WORLD' | ||
``` | ||
### toDelimiterCase | ||
### trim | ||
This function converts a string to a new case with a custom delimiter at both runtime and type levels. | ||
This function is a strongly-typed counterpart of `String.prototype.trim`. | ||
```ts | ||
import { toDelimiterCase } from 'string-ts' | ||
import { trim } from 'string-ts' | ||
const str = 'helloWorld' | ||
const result = toDelimiterCase(str, '.') | ||
// ^ 'hello.World' | ||
const str = ' hello world ' | ||
const result = trim(str) | ||
// ^ 'hello world' | ||
``` | ||
### trimEnd | ||
This function is a strongly-typed counterpart of `String.prototype.trimEnd`. | ||
```ts | ||
import { trimEnd } from 'string-ts' | ||
const str = ' hello world ' | ||
const result = trimEnd(str) | ||
// ^ ' hello world' | ||
``` | ||
### trimStart | ||
This function is a strongly-typed counterpart of `String.prototype.trimStart`. | ||
```ts | ||
import { trimStart } from 'string-ts' | ||
const str = ' hello world ' | ||
const result = trimStart(str) | ||
// ^ 'hello world ' | ||
``` | ||
## Strongly-typed alternatives to common loosely-typed functions | ||
### toCamelCase | ||
@@ -315,14 +357,26 @@ | ||
### toPascalCase | ||
### toConstantCase | ||
This function converts a string to `PascalCase` at both runtime and type levels. | ||
This function converts a string to `CONSTANT_CASE` at both runtime and type levels. | ||
```ts | ||
import { toPascalCase } from 'string-ts' | ||
import { toConstantCase } from 'string-ts' | ||
const str = 'hello-world' | ||
const result = toPascalCase(str) | ||
// ^ 'HelloWorld' | ||
const str = 'helloWorld' | ||
const result = toConstantCase(str) | ||
// ^ 'HELLO_WORLD' | ||
``` | ||
### toDelimiterCase | ||
This function converts a string to a new case with a custom delimiter at both runtime and type levels. | ||
```ts | ||
import { toDelimiterCase } from 'string-ts' | ||
const str = 'helloWorld' | ||
const result = toDelimiterCase(str, '.') | ||
// ^ 'hello.World' | ||
``` | ||
### toKebabCase | ||
@@ -340,24 +394,24 @@ | ||
### toSnakeCase | ||
### toPascalCase | ||
This function converts a string to `snake_case` at both runtime and type levels. | ||
This function converts a string to `PascalCase` at both runtime and type levels. | ||
```ts | ||
import { toSnakeCase } from 'string-ts' | ||
import { toPascalCase } from 'string-ts' | ||
const str = 'helloWorld' | ||
const result = toSnakeCase(str) | ||
// ^ 'hello_world' | ||
const str = 'hello-world' | ||
const result = toPascalCase(str) | ||
// ^ 'HelloWorld' | ||
``` | ||
### toConstantCase | ||
### toSnakeCase | ||
This function converts a string to `CONSTANT_CASE` at both runtime and type levels. | ||
This function converts a string to `snake_case` at both runtime and type levels. | ||
```ts | ||
import { toConstantCase } from 'string-ts' | ||
import { toSnakeCase } from 'string-ts' | ||
const str = 'helloWorld' | ||
const result = toConstantCase(str) | ||
// ^ 'HELLO_WORLD' | ||
const result = toSnakeCase(str) | ||
// ^ 'hello_world' | ||
``` | ||
@@ -377,24 +431,22 @@ | ||
## Strongly-typed shallow transformation of objects | ||
### words | ||
### delimiterKeys | ||
This function shallowly converts the keys of an object to a new case with a custom delimiter at both runtime and type levels. | ||
This function identifies the words in a string and returns a tuple of words split by separators, differences in casing, numbers, and etc. | ||
```ts | ||
import { delimiterKeys } from 'string-ts'; | ||
import { words } from 'string-ts' | ||
const data = { | ||
'hello-world': { | ||
'foo-bar': 'baz', | ||
}, | ||
} as const; | ||
const result = delimiterKeys(data, '.'); | ||
// ^ { 'hello.world': { 'foo-bar': 'baz' } } | ||
const str = '-20someVery-weird String' | ||
const result = words(str) | ||
// ^ ['20', 'some', 'Very', 'weird', 'String'] | ||
``` | ||
## Strongly-typed shallow transformation of objects | ||
### camelKeys | ||
This function shallowly converts the keys of an object to `camelCase` at both runtime and type levels. | ||
```ts | ||
import { camelKeys } from 'string-ts'; | ||
import { camelKeys } from 'string-ts' | ||
@@ -405,65 +457,85 @@ const data = { | ||
}, | ||
} as const; | ||
const result = camelKeys(data); | ||
} as const | ||
const result = camelKeys(data) | ||
// ^ { helloWorld: { 'foo-bar': 'baz' } } | ||
``` | ||
### pascalKeys | ||
This function shallowly converts the keys of an object to `PascalCase` at both runtime and type levels. | ||
### constantKeys | ||
This function shallowly converts the keys of an object to `CONSTANT_CASE` at both runtime and type levels. | ||
```ts | ||
import { pascalKeys } from 'string-ts'; | ||
import { constantKeys } from 'string-ts' | ||
const data = { | ||
helloWorld: { | ||
fooBar: 'baz', | ||
}, | ||
} as const | ||
const result = constantKeys(data) | ||
// ^ { 'HELLO_WORLD': { 'fooBar': 'baz' } } | ||
``` | ||
### delimiterKeys | ||
This function shallowly converts the keys of an object to a new case with a custom delimiter at both runtime and type levels. | ||
```ts | ||
import { delimiterKeys } from 'string-ts' | ||
const data = { | ||
'hello-world': { | ||
'foo-bar': 'baz', | ||
}, | ||
} as const; | ||
const result = pascalKeys(data); | ||
// ^ { HelloWorld: { FooBar: 'baz' } } | ||
} as const | ||
const result = delimiterKeys(data, '.') | ||
// ^ { 'hello.world': { 'foo-bar': 'baz' } } | ||
``` | ||
### kebabKeys | ||
This function shallowly converts the keys of an object to `kebab-case` at both runtime and type levels. | ||
```ts | ||
import { kebabKeys } from 'string-ts'; | ||
import { kebabKeys } from 'string-ts' | ||
const data = { | ||
'helloWorld': { | ||
'fooBar': 'baz', | ||
helloWorld: { | ||
fooBar: 'baz', | ||
}, | ||
} as const; | ||
const result = kebabKeys(data); | ||
} as const | ||
const result = kebabKeys(data) | ||
// ^ { 'hello-world': { fooBar: 'baz' } } | ||
``` | ||
### snakeKeys | ||
This function shallowly converts the keys of an object to `snake_case` at both runtime and type levels. | ||
### pascalKeys | ||
This function shallowly converts the keys of an object to `PascalCase` at both runtime and type levels. | ||
```ts | ||
import { snakeKeys } from 'string-ts'; | ||
import { pascalKeys } from 'string-ts' | ||
const data = { | ||
'helloWorld': { | ||
'fooBar': 'baz', | ||
'hello-world': { | ||
'foo-bar': 'baz', | ||
}, | ||
} as const; | ||
const result = snakeKeys(data); | ||
// ^ { 'hello_world': { 'fooBar': 'baz' } } | ||
} as const | ||
const result = pascalKeys(data) | ||
// ^ { HelloWorld: { FooBar: 'baz' } } | ||
``` | ||
### constantKeys | ||
This function shallowly converts the keys of an object to `CONSTANT_CASE` at both runtime and type levels. | ||
### snakeKeys | ||
This function shallowly converts the keys of an object to `snake_case` at both runtime and type levels. | ||
```ts | ||
import { constantKeys } from 'string-ts'; | ||
import { snakeKeys } from 'string-ts' | ||
const data = { | ||
'helloWorld': { | ||
'fooBar': 'baz', | ||
helloWorld: { | ||
fooBar: 'baz', | ||
}, | ||
} as const; | ||
const result = constantKeys(data); | ||
// ^ { 'HELLO_WORLD': { 'fooBar': 'baz' } } | ||
} as const | ||
const result = snakeKeys(data) | ||
// ^ { 'hello_world': { 'fooBar': 'baz' } } | ||
``` | ||
@@ -473,8 +545,8 @@ | ||
### deepDelimiterKeys | ||
### deepCamelKeys | ||
This function recursively converts the keys of an object to a new case with a custom delimiter at both runtime and type levels. | ||
This function recursively converts the keys of an object to `camelCase` at both runtime and type levels. | ||
```ts | ||
import { deepDelimiterKeys } from 'string-ts' | ||
import { deepCamelKeys } from 'string-ts' | ||
@@ -486,28 +558,28 @@ const data = { | ||
} as const | ||
const result = deepDelimiterKeys(data, '.') | ||
// ^ { 'hello.world': { 'foo.bar': 'baz' } } | ||
const result = deepCamelKeys(data) | ||
// ^ { helloWorld: { fooBar: 'baz' } } | ||
``` | ||
### deepCamelKeys | ||
### deepConstantKeys | ||
This function recursively converts the keys of an object to `camelCase` at both runtime and type levels. | ||
This function recursively converts the keys of an object to `CONSTANT_CASE` at both runtime and type levels. | ||
```ts | ||
import { deepCamelKeys } from 'string-ts' | ||
import { deepConstantKeys } from 'string-ts' | ||
const data = { | ||
'hello-world': { | ||
'foo-bar': 'baz', | ||
helloWorld: { | ||
fooBar: 'baz', | ||
}, | ||
} as const | ||
const result = deepCamelKeys(data) | ||
// ^ { helloWorld: { fooBar: 'baz' } } | ||
const result = deepConstantKeys(data) | ||
// ^ { 'HELLO_WORLD': { 'FOO_BAR': 'baz' } } | ||
``` | ||
### deepPascalKeys | ||
### deepDelimiterKeys | ||
This function recursively converts the keys of an object to `PascalCase` at both runtime and type levels. | ||
This function recursively converts the keys of an object to a new case with a custom delimiter at both runtime and type levels. | ||
```ts | ||
import { deepPascalKeys } from 'string-ts' | ||
import { deepDelimiterKeys } from 'string-ts' | ||
@@ -519,4 +591,4 @@ const data = { | ||
} as const | ||
const result = deepPascalKeys(data) | ||
// ^ { HelloWorld: { FooBar: 'baz' } } | ||
const result = deepDelimiterKeys(data, '.') | ||
// ^ { 'hello.world': { 'foo.bar': 'baz' } } | ||
``` | ||
@@ -540,24 +612,24 @@ | ||
### deepSnakeKeys | ||
### deepPascalKeys | ||
This function recursively converts the keys of an object to `snake_case` at both runtime and type levels. | ||
This function recursively converts the keys of an object to `PascalCase` at both runtime and type levels. | ||
```ts | ||
import { deepSnakeKeys } from 'string-ts' | ||
import { deepPascalKeys } from 'string-ts' | ||
const data = { | ||
helloWorld: { | ||
fooBar: 'baz', | ||
'hello-world': { | ||
'foo-bar': 'baz', | ||
}, | ||
} as const | ||
const result = deepSnakeKeys(data) | ||
// ^ { 'hello_world': { 'foo_bar': 'baz' } } | ||
const result = deepPascalKeys(data) | ||
// ^ { HelloWorld: { FooBar: 'baz' } } | ||
``` | ||
### deepConstantKeys | ||
### deepSnakeKeys | ||
This function recursively converts the keys of an object to `CONSTANT_CASE` at both runtime and type levels. | ||
This function recursively converts the keys of an object to `snake_case` at both runtime and type levels. | ||
```ts | ||
import { deepConstantKeys } from 'string-ts' | ||
import { deepSnakeKeys } from 'string-ts' | ||
@@ -569,4 +641,4 @@ const data = { | ||
} as const | ||
const result = deepConstantKeys(data) | ||
// ^ { 'HELLO_WORLD': { 'FOO_BAR': 'baz' } } | ||
const result = deepSnakeKeys(data) | ||
// ^ { 'hello_world': { 'foo_bar': 'baz' } } | ||
``` | ||
@@ -593,11 +665,14 @@ | ||
```ts | ||
St.Words<'hello-world'> // ['hello', 'world'] | ||
St.CharAt<'hello world', 6> // 'w' | ||
St.Concat<['a', 'bc', 'def']> // 'abcdef' | ||
St.Join<['hello', 'world'], '-'> // 'hello-world' | ||
St.Length<'hello'> // 5 | ||
St.Replace<'hello-world', 'l', '1'> // 'he1lo-world' | ||
St.ReplaceAll<'hello-world', 'l', '1'> // 'he11o-wor1d' | ||
St.Slice<'hello-world', -5> // 'world' | ||
St.Split<'hello-world', '-'> // ['hello', 'world'] | ||
St.Trim<' hello world '> // 'hello world' | ||
St.TrimEnd<' hello world '> // ' hello world' | ||
St.TrimStart<' hello world '> // 'hello world ' | ||
St.TrimEnd<' hello world '> // ' hello world' | ||
St.Trim<' hello world '> // 'hello world' | ||
St.Words<'hello-world'> // ['hello', 'world'] | ||
``` | ||
@@ -609,9 +684,35 @@ | ||
St.CamelCase<'hello-world'> // 'helloWorld' | ||
St.ConstantCase<'helloWorld'> // 'HELLO_WORLD' | ||
St.DelimiterCase<'hello world', '.'> // 'hello.world' | ||
St.KebabCase<'helloWorld'> // 'hello-world' | ||
St.PascalCase<'hello-world'> // 'HelloWorld' | ||
St.KebabCase<'helloWorld'> // 'hello-world' | ||
St.SnakeCase<'helloWorld'> // 'hello_world' | ||
St.ConstantCase<'helloWorld'> // 'HELLO_WORLD' | ||
St.TitleCase<'helloWorld'> // 'Hello World' | ||
St.DelimiterCase<'hello world', '.'> // 'hello.world' | ||
// SHALLOW OBJECT KEY TRANSFORMATION | ||
St.CamelKeys<{ | ||
'hello-world': { 'foo-bar': 'baz' } | ||
}> // { helloWorld: { 'foo-bar': 'baz' } } | ||
St.ConstantKeys<{ | ||
helloWorld: { fooBar: 'baz' } | ||
}> // { 'HELLO_WORLD': { fooBar: 'baz' } } | ||
St.DelimiterKeys<{ 'hello-world': { 'foo-bar': 'baz' } }, '.'> | ||
// { 'hello.world': { 'foo-bar': 'baz' } } | ||
St.KebabKeys<{ | ||
helloWorld: { fooBar: 'baz' } | ||
}> // { 'hello-world': { fooBar: 'baz' } } | ||
St.PascalKeys<{ | ||
'hello-world': { 'foo-bar': 'baz' } | ||
}> // { HelloWorld: { 'foo-bar': 'baz' } } | ||
St.SnakeKeys<{ | ||
helloWorld: { fooBar: 'baz' } | ||
}> // { 'hello_world': { fooBar: 'baz' } } | ||
// DEEP OBJECT KEY TRANSFORMATION | ||
St.DeepCamelKeys<{ | ||
'hello-world': { 'foo-bar': 'baz' } | ||
}> // { helloWorld: { fooBar: 'baz' } } | ||
St.DeepConstantKeys<{ | ||
helloWorld: { fooBar: 'baz' } | ||
}> // { 'HELLO_WORLD': { 'FOO_BAR': 'baz' } } | ||
St.DeepDelimiterKeys< | ||
@@ -623,17 +724,11 @@ { | ||
> // { 'hello.world': { 'foo.bar': 'baz' } } | ||
St.DeepCamelKeys<{ | ||
'hello-world': { 'foo-bar': 'baz' } | ||
}> // { helloWorld: { fooBar: 'baz' } } | ||
St.DeepKebabKeys<{ | ||
helloWorld: { fooBar: 'baz' } | ||
}> // { 'hello-world': { 'foo-bar': 'baz' } } | ||
St.DeepPascalKeys<{ | ||
'hello-world': { 'foo-bar': 'baz' } | ||
}> // { HelloWorld: { FooBar: 'baz' } } | ||
St.DeepKebabKeys<{ | ||
helloWorld: { fooBar: 'baz' } | ||
}> // { 'hello-world': { 'foo-bar': 'baz' } } | ||
St.DeepSnakeKeys<{ | ||
helloWorld: { fooBar: 'baz' } | ||
}> // { 'hello_world': { 'foo_bar': 'baz' } } | ||
St.DeepConstantKeys<{ | ||
helloWorld: { fooBar: 'baz' } | ||
}> // { 'HELLO_WORLD': { 'FOO_BAR': 'baz' } } | ||
``` | ||
@@ -678,2 +773,6 @@ | ||
This library doesn't support every internal character for the sake of keeping the maintainer's sanity. | ||
We don't plan to support international characters. | ||
## Aknowledgements | ||
This library got a lot of inspiration from libraries such as [lodash](https://github.com/lodash/lodash), [ts-reset](https://github.com/total-typescript/ts-reset), [type-fest](https://github.com/sindresorhus/type-fest), [HOTScript](https://github.com/gvergnaud/hotscript), and many others. |
Sorry, the diff of this file is not supported yet
56954
977
756