Comparing version 1.1.0 to 1.2.0
@@ -1,7 +0,29 @@ | ||
type GetTuple<L extends number, result extends any[] = []> = result['length'] extends L ? result : GetTuple<L, [...result, any]>; | ||
/** | ||
* PascalCases all the words in a tuple of strings | ||
*/ | ||
type PascalCaseAll<T extends string[]> = T extends [ | ||
infer head extends string, | ||
...infer rest extends string[] | ||
] ? [Capitalize<Lowercase<head>>, ...PascalCaseAll<rest>] : T; | ||
/** | ||
* Removes all the elements matching the given condition from a tuple. | ||
*/ | ||
type Filter<tuple, cond, output extends any[] = []> = tuple extends [ | ||
infer first, | ||
...infer rest | ||
] ? Filter<rest, cond, first extends cond ? output : [...output, first]> : output; | ||
/** | ||
* Removes the given suffix from a sentence. | ||
*/ | ||
type DropSuffix<sentence extends string, suffix extends string> = sentence extends `${infer rest}${suffix}` ? rest : sentence; | ||
/** | ||
* Returns a tuple of the given length with the given type. | ||
*/ | ||
type TupleOf<L extends number, T = unknown, result extends any[] = []> = result['length'] extends L ? result : TupleOf<L, T, [...result, T]>; | ||
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 Subtract<A extends number, B extends number> = TupleOf<A> extends [...infer U, ...TupleOf<B>] ? U['length'] : 0; | ||
type IsNegative<T extends number> = `${T}` extends `-${number}` ? true : false; | ||
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>>; | ||
type GetPositiveIndex<T extends string, I extends number> = IsNegative<I> extends false ? I : Subtract<Length<T>, Abs<I>>; | ||
} | ||
@@ -36,2 +58,18 @@ | ||
/** | ||
* Checks if a string ends with another string. | ||
* T: The string to check. | ||
* S: The string to check against. | ||
* P: The position the search should end. | ||
*/ | ||
type EndsWith<T extends string, S extends string, P extends number = Length<T>> = Math.IsNegative<P> extends false ? P extends Length<T> ? S extends Slice<T, Math.Subtract<Length<T>, Length<S>>, Length<T>> ? true : false : EndsWith<Slice<T, 0, P>, S, Length<T>> : false; | ||
/** | ||
* A strongly-typed version of `String.prototype.endsWith`. | ||
* @param text the string to search. | ||
* @param search the string to search with. | ||
* @param position the index the search should end at. | ||
* @returns boolean, whether or not the text string ends with the search string. | ||
* @example endsWith('abc', 'c') // true | ||
*/ | ||
declare function endsWith<T extends string, S extends string, P extends number = Length<T>>(text: T, search: S, position?: P): EndsWith<T, S, P>; | ||
/** | ||
* Joins a tuple of strings with the given delimiter. | ||
@@ -65,2 +103,48 @@ * T: The tuple of strings to join. | ||
/** | ||
* Pads a string at the end with another string. | ||
* T: The string to pad. | ||
* times: The number of times to pad. | ||
* pad: The string to pad with. | ||
*/ | ||
type PadEnd<T extends string, times extends number = 0, pad extends string = ' '> = Math.IsNegative<times> extends false ? Math.Subtract<times, Length<T>> extends infer missing extends number ? `${T}${Slice<Repeat<pad, missing>, 0, missing>}` : never : T; | ||
/** | ||
* A strongly-typed version of `String.prototype.padEnd`. | ||
* @param str the string to pad. | ||
* @param length the length to pad. | ||
* @param pad the string to pad with. | ||
* @returns the padded string in both type level and runtime. | ||
* @example padEnd('hello', 10, '=') // 'hello=====' | ||
*/ | ||
declare function padEnd<T extends string, N extends number = 0, U extends string = ' '>(str: T, length?: N, pad?: U): PadEnd<T, N, U>; | ||
/** | ||
* Pads a string at the start with another string. | ||
* T: The string to pad. | ||
* times: The number of times to pad. | ||
* pad: The string to pad with. | ||
*/ | ||
type PadStart<T extends string, times extends number = 0, pad extends string = ' '> = Math.IsNegative<times> extends false ? Math.Subtract<times, Length<T>> extends infer missing extends number ? `${Slice<Repeat<pad, missing>, 0, missing>}${T}` : never : T; | ||
/** | ||
* A strongly-typed version of `String.prototype.padStart`. | ||
* @param str the string to pad. | ||
* @param length the length to pad. | ||
* @param pad the string to pad with. | ||
* @returns the padded string in both type level and runtime. | ||
* @example padStart('hello', 10, '=') // '=====hello' | ||
*/ | ||
declare function padStart<T extends string, N extends number = 0, U extends string = ' '>(str: T, length?: N, pad?: U): PadStart<T, N, U>; | ||
/** | ||
* Repeats a string N times. | ||
* T: The string to repeat. | ||
* N: The number of times to repeat. | ||
*/ | ||
type Repeat<T extends string, times extends number = 0> = times extends 0 ? '' : Math.IsNegative<times> extends false ? Join<TupleOf<times, T>> : never; | ||
/** | ||
* A strongly-typed version of `String.prototype.repeat`. | ||
* @param str the string to repeat. | ||
* @param times the number of times to repeat. | ||
* @returns the repeated string in both type level and runtime. | ||
* @example repeat('hello', 3) // 'hellohellohello' | ||
*/ | ||
declare function repeat<T extends string, N extends number = 0>(str: T, times?: N): Repeat<T, N>; | ||
/** | ||
* Replaces the first occurrence of a string with another string. | ||
@@ -71,3 +155,3 @@ * sentence: The sentence to replace. | ||
*/ | ||
type Replace<sentence extends string, lookup extends string, replacement extends string = ''> = sentence extends `${infer rest}${lookup}${infer rest2}` ? `${rest}${replacement}${rest2}` : sentence; | ||
type Replace<sentence extends string, lookup extends string | RegExp, replacement extends string = ''> = lookup extends string ? sentence extends `${infer rest}${lookup}${infer rest2}` ? `${rest}${replacement}${rest2}` : sentence : string; | ||
/** | ||
@@ -81,3 +165,3 @@ * A strongly-typed version of `String.prototype.replace`. | ||
*/ | ||
declare function replace<T extends string, S extends string, R extends string = ''>(sentence: T, lookup: S, replacement?: R): Replace<T, S, R>; | ||
declare function replace<T extends string, S extends string | RegExp, R extends string = ''>(sentence: T, lookup: S, replacement?: R): Replace<T, S, R>; | ||
/** | ||
@@ -89,3 +173,3 @@ * Replaces all the occurrences of a string with another string. | ||
*/ | ||
type ReplaceAll<sentence extends string, lookup extends string, replacement extends string = ''> = sentence extends `${infer rest}${lookup}${infer rest2}` ? `${rest}${replacement}${ReplaceAll<rest2, lookup, replacement>}` : sentence; | ||
type ReplaceAll<sentence extends string, lookup extends string | RegExp, replacement extends string = ''> = lookup extends string ? sentence extends `${infer rest}${lookup}${infer rest2}` ? `${rest}${replacement}${ReplaceAll<rest2, lookup, replacement>}` : sentence : string; | ||
/** | ||
@@ -99,3 +183,3 @@ * A strongly-typed version of `String.prototype.replaceAll`. | ||
*/ | ||
declare function replaceAll<T extends string, S extends string, R extends string = ''>(sentence: T, lookup: S, replacement?: R): ReplaceAll<T, S, R>; | ||
declare function replaceAll<T extends string, S extends string | RegExp, R extends string = ''>(sentence: T, lookup: S, replacement?: R): ReplaceAll<T, S, R>; | ||
/** | ||
@@ -106,5 +190,4 @@ * Slices a string from a startIndex to an endIndex. | ||
* 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']>}` : ''; | ||
type Slice<T extends string, startIndex extends number = 0, endIndex extends number = Length<T>> = T extends `${infer head}${infer rest}` ? startIndex extends 0 ? endIndex extends 0 ? '' : `${head}${Slice<rest, Math.Subtract<Math.GetPositiveIndex<T, startIndex>, 1>, Math.Subtract<Math.GetPositiveIndex<T, endIndex>, 1>>}` : `${Slice<rest, Math.Subtract<Math.GetPositiveIndex<T, startIndex>, 1>, Math.Subtract<Math.GetPositiveIndex<T, endIndex>, 1>>}` : ''; | ||
/** | ||
@@ -117,5 +200,4 @@ * A strongly-typed version of `String.prototype.slice`. | ||
* @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>; | ||
declare function slice<T extends string, S extends number = 0, E extends number = Length<T>>(str: T, start?: S, end?: E): Slice<T, S, E>; | ||
/** | ||
@@ -136,2 +218,34 @@ * Splits a string into an array of substrings. | ||
/** | ||
* Checks if a string starts with another string. | ||
* T: The string to check. | ||
* S: The string to check against. | ||
* P: The position to start the search. | ||
*/ | ||
type StartsWith<T extends string, S extends string, P extends number = 0> = Math.IsNegative<P> extends false ? P extends 0 ? T extends `${S}${string}` ? true : false : StartsWith<Slice<T, P>, S, 0> : StartsWith<T, S, 0>; | ||
/** | ||
* A strongly-typed version of `String.prototype.startsWith`. | ||
* @param text the string to search. | ||
* @param search the string to search with. | ||
* @param position the index to start search at. | ||
* @returns boolean, whether or not the text string starts with the search string. | ||
* @example startsWith('abc', 'a') // true | ||
*/ | ||
declare function startsWith<T extends string, S extends string, P extends number = 0>(text: T, search: S, position?: P): StartsWith<T, S, P>; | ||
/** | ||
* Checks if a string includes another string. | ||
* T: The string to check. | ||
* S: The string to check against. | ||
* P: The position to start the search. | ||
*/ | ||
type Includes<T extends string, S extends string, P extends number = 0> = Math.IsNegative<P> extends false ? P extends 0 ? T extends `${string}${S}${string}` ? true : false : Includes<Slice<T, P>, S, 0> : Includes<T, S, 0>; | ||
/** | ||
* A strongly-typed version of `String.prototype.includes`. | ||
* @param text the string to search | ||
* @param search the string to search with | ||
* @param position the index to start search at | ||
* @returns boolean, whether or not the text contains the search string. | ||
* @example includes('abcde', 'bcd') // true | ||
*/ | ||
declare function includes<T extends string, S extends string, P extends number = 0>(text: T, search: S, position?: P): Includes<T, S, P>; | ||
/** | ||
* Trims all whitespaces at the start of a string. | ||
@@ -173,27 +287,11 @@ * T: The string to trim. | ||
declare const SEPARATORS: readonly ["[", "]", "{", "}", "(", ")", "|", "/", "-", "\\", " ", "_", "."]; | ||
type Separator = (typeof SEPARATORS)[number]; | ||
/** | ||
* Removes all the elements matching the given condition from a tuple. | ||
* Checks if the given character is a separator. | ||
* E.g. space, underscore, dash, dot, slash. | ||
*/ | ||
type Drop<tuple, cond, output extends any[] = []> = tuple extends [ | ||
infer first, | ||
...infer rest | ||
] ? Drop<rest, cond, first extends cond ? output : [...output, first]> : output; | ||
/** | ||
* Removes the given suffix from a sentence. | ||
*/ | ||
type DropSuffix<sentence extends string, suffix extends string> = sentence extends `${infer rest}${suffix}` ? rest : sentence; | ||
/** | ||
* PascalCases all the words in a tuple of strings | ||
*/ | ||
type PascalCaseAll<T extends string[]> = T extends [ | ||
infer head extends string, | ||
...infer rest extends string[] | ||
] ? [Capitalize<Lowercase<head>>, ...PascalCaseAll<rest>] : T; | ||
type IsSeparator<T extends string> = T extends Separator ? true : false; | ||
type Digit = '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9'; | ||
type Separator = ' ' | '_' | '-' | '.' | '/'; | ||
/** | ||
* Assures the generic matches the given condition. | ||
*/ | ||
type Is<T, cond> = Extract<T, cond>; | ||
type UpperChars = 'A' | 'B' | 'C' | 'D' | 'E' | 'F' | 'G' | 'H' | 'I' | 'J' | 'K' | 'L' | 'M' | 'N' | 'O' | 'P' | 'Q' | 'R' | 'S' | 'T' | 'U' | 'V' | 'W' | 'X' | 'Y' | 'Z'; | ||
@@ -218,7 +316,2 @@ type LowerChars = Lowercase<UpperChars>; | ||
/** | ||
* Checks if the given character is a separator. | ||
* E.g. space, underscore, dash, dot, slash. | ||
*/ | ||
type IsSeparator<T extends string> = T extends Separator ? true : false; | ||
/** | ||
* Checks if the given character is a special character. | ||
@@ -228,2 +321,3 @@ * E.g. not a letter, number, or separator. | ||
type IsSpecial<T extends string> = IsLetter<T> extends true ? false : IsDigit<T> extends true ? false : IsSeparator<T> extends true ? false : true; | ||
/** | ||
@@ -235,3 +329,3 @@ * Splits a string into words. | ||
*/ | ||
type Words<sentence extends string, word extends string = '', prev extends string = ''> = string extends sentence ? string[] : sentence extends `${infer curr}${infer rest}` ? IsSeparator<curr> extends true ? Drop<[word, ...Words<rest>], ''> : prev extends '' ? Drop<Words<rest, curr, curr>, ''> : [false, true] extends [IsDigit<prev>, IsDigit<curr>] ? [ | ||
type Words<sentence extends string, word extends string = '', prev extends string = ''> = string extends sentence ? string[] : sentence extends `${infer curr}${infer rest}` ? IsSeparator<curr> extends true ? Filter<[word, ...Words<rest>], ''> : prev extends '' ? Filter<Words<rest, curr, curr>, ''> : [false, true] extends [IsDigit<prev>, IsDigit<curr>] ? [ | ||
word, | ||
@@ -248,3 +342,3 @@ ...Words<rest, curr, curr> | ||
...Words<rest, curr, curr> | ||
] : [true, true] extends [IsDigit<prev>, IsDigit<curr>] ? Drop<Words<rest, `${word}${curr}`, curr>, ''> : [true, true] extends [IsLower<prev>, IsUpper<curr>] ? [ | ||
] : [true, true] extends [IsDigit<prev>, IsDigit<curr>] ? Filter<Words<rest, `${word}${curr}`, curr>, ''> : [true, true] extends [IsLower<prev>, IsUpper<curr>] ? [ | ||
word, | ||
@@ -255,3 +349,3 @@ ...Words<rest, curr, curr> | ||
...Words<rest, `${prev}${curr}`, curr> | ||
] : Drop<Words<rest, `${word}${curr}`, curr>, ''> : Drop<[word], ''>; | ||
] : Filter<Words<rest, `${word}${curr}`, curr>, ''> : Filter<[word], ''>; | ||
/** | ||
@@ -264,2 +358,17 @@ * A strongly typed function to extract the words from a sentence. | ||
declare function words<T extends string>(sentence: T): Words<T>; | ||
/** | ||
* Truncate a string if it's longer than the given maximum length. | ||
* The last characters of the truncated string are replaced with the omission string which defaults to "...". | ||
*/ | ||
type Truncate<T extends string, Size extends number, Omission extends string = '...'> = Math.IsNegative<Size> extends true ? Omission : Math.Subtract<Length<T>, Size> extends 0 ? T : Join<[Slice<T, 0, Math.Subtract<Size, Length<Omission>>>, Omission]>; | ||
/** | ||
* A strongly typed function to truncate a string if it's longer than the given maximum string length. | ||
* The last characters of the truncated string are replaced with the omission string which defaults to "...". | ||
* @param sentence the sentence to extract the words from. | ||
* @param length the maximum length of the string. | ||
* @param omission the string to append to the end of the truncated string. | ||
* @returns the truncated string | ||
* @example truncate('Hello, World', 8) // 'Hello...' | ||
*/ | ||
declare function truncate<T extends string, S extends number, P extends string = '...'>(sentence: T, length: S, omission?: P): Truncate<T, S, P>; | ||
@@ -374,12 +483,2 @@ /** | ||
/** | ||
* This function is used to transform the keys of an object deeply. | ||
* It will only be transformed at runtime, so it's not type safe. | ||
* @param obj the object to transform. | ||
* @param transform the function to transform the keys from string to string. | ||
* @returns the transformed object. | ||
* @example deepTransformKeys({ 'foo-bar': { 'fizz-buzz': true } }, toCamelCase) | ||
* // { fooBar: { fizzBuzz: true } } | ||
*/ | ||
declare function deepTransformKeys<T>(obj: T, transform: (s: string) => string): T; | ||
/** | ||
* Shallowly transforms the keys of an Record to camelCase. | ||
@@ -389,3 +488,3 @@ * 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]; | ||
[K in keyof T as CamelCase<Extract<K, string>>]: T[K]; | ||
}; | ||
@@ -400,155 +499,166 @@ /** | ||
/** | ||
* Recursively transforms the keys of an Record to camelCase. | ||
* Shallowly transforms the keys of an Record to CONSTANT_CASE. | ||
* T: the type of the Record to transform. | ||
*/ | ||
type DeepCamelKeys<T> = T extends [any, ...any] ? { | ||
[I in keyof T]: DeepCamelKeys<T[I]>; | ||
} : T extends (infer V)[] ? DeepCamelKeys<V>[] : { | ||
[K in keyof T as CamelCase<Is<K, string>>]: DeepCamelKeys<T[K]>; | ||
type ConstantKeys<T> = T extends [] ? T : { | ||
[K in keyof T as ConstantCase<Extract<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>; | ||
/** | ||
* Shallowly transforms the keys of an Record to CONSTANT_CASE. | ||
* 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 ConstantKeys<T> = T extends [] ? T : { | ||
[K in keyof T as ConstantCase<Is<K, string>>]: T[K]; | ||
type DelimiterKeys<T, D extends string> = T extends [] ? T : { | ||
[K in keyof T as DelimiterCase<Extract<K, string>, D>]: T[K]; | ||
}; | ||
/** | ||
* 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. | ||
* 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 constantKeys({ 'foo-bar': { 'fizz-buzz': true } }) // { FOO_BAR: { 'fizz-buzz': true } } | ||
* @example delimiterKeys({ 'foo-bar': { 'fizz-buzz': true } }, '.') // { 'foo.bar': { 'fizz.buzz': true } } | ||
*/ | ||
declare function constantKeys<T>(obj: T): ConstantKeys<T>; | ||
declare function delimiterKeys<T, D extends string>(obj: T, delimiter: D): DelimiterKeys<T, D>; | ||
/** | ||
* Recursively transforms the keys of an Record to CONSTANT_CASE. | ||
* Shallowly transforms the keys of an Record to kebab-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 KebabKeys<T> = T extends [] ? T : { | ||
[K in keyof T as KebabCase<Extract<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 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 deepConstantKeys({ 'foo-bar': { 'fizz-buzz': true } }) // { FOO_BAR: { FIZZ_BUZZ: true } } | ||
* @example kebabKeys({ fooBar: { fizzBuzz: true } }) // { 'foo-bar': { fizzBuzz: true } } | ||
*/ | ||
declare function deepConstantKeys<T>(obj: T): DeepConstantKeys<T>; | ||
declare function kebabKeys<T>(obj: T): KebabKeys<T>; | ||
/** | ||
* Shallowly transforms the keys of an Record to a custom delimiter case. | ||
* Shallowly transforms the keys of an Record to PascalCase. | ||
* 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]; | ||
type PascalKeys<T> = T extends [] ? T : { | ||
[K in keyof T as PascalCase<Extract<K, string>>]: T[K]; | ||
}; | ||
/** | ||
* 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. | ||
* 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. | ||
* @param delimiter the delimiter to use. | ||
* @returns the transformed object. | ||
* @example delimiterKeys({ 'foo-bar': { 'fizz-buzz': true } }, '.') // { 'foo.bar': { 'fizz.buzz': true } } | ||
* @example pascalKeys({ 'foo-bar': { 'fizz-buzz': true } }) // { FooBar: { 'fizz-buzz': true } } | ||
*/ | ||
declare function delimiterKeys<T, D extends string>(obj: T, delimiter: D): DelimiterKeys<T, D>; | ||
declare function pascalKeys<T>(obj: T): PascalKeys<T>; | ||
/** | ||
* Recursively transforms the keys of an Record to a custom delimiter case. | ||
* Shallowly transforms the keys of an Record to snake_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>; | ||
type SnakeKeys<T> = T extends [] ? T : { | ||
[K in keyof T as SnakeCase<Extract<K, string>>]: 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. | ||
* A strongly typed function that shallowly the keys of an object to snake_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 } } | ||
* @example snakeKeys({ 'foo-bar': { 'fizz-buzz': true } }) // { 'foo_bar': { 'fizz-buzz': true } } | ||
*/ | ||
declare function deepDelimiterKeys<T, D extends string>(obj: T, delimiter: D): DeepDelimiterKeys<T, D>; | ||
declare function snakeKeys<T>(obj: T): SnakeKeys<T>; | ||
/** | ||
* Shallowly transforms the keys of an Record to kebab-case. | ||
* This function is used to transform the keys of an object deeply. | ||
* It will only be transformed at runtime, so it's not type safe. | ||
* @param obj the object to transform. | ||
* @param transform the function to transform the keys from string to string. | ||
* @returns the transformed object. | ||
* @example deepTransformKeys({ 'foo-bar': { 'fizz-buzz': true } }, toCamelCase) | ||
* // { fooBar: { fizzBuzz: true } } | ||
*/ | ||
declare function deepTransformKeys<T>(obj: T, transform: (s: string) => string): T; | ||
/** | ||
* Recursively transforms the keys of an Record to camelCase. | ||
* 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]; | ||
type DeepCamelKeys<T> = T extends [any, ...any] ? { | ||
[I in keyof T]: DeepCamelKeys<T[I]>; | ||
} : T extends (infer V)[] ? DeepCamelKeys<V>[] : { | ||
[K in keyof T as CamelCase<Extract<K, string>>]: DeepCamelKeys<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. | ||
* 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 kebabKeys({ fooBar: { fizzBuzz: true } }) // { 'foo-bar': { fizzBuzz: true } } | ||
* @example deepCamelKeys({ 'foo-bar': { 'fizz-buzz': true } }) // { fooBar: { fizzBuzz: true } } | ||
*/ | ||
declare function kebabKeys<T>(obj: T): KebabKeys<T>; | ||
declare function deepCamelKeys<T>(obj: T): DeepCamelKeys<T>; | ||
/** | ||
* Recursively transforms the keys of an Record to kebab-case. | ||
* Recursively transforms the keys of an Record to CONSTANT_CASE. | ||
* T: the type of the Record to transform. | ||
*/ | ||
type DeepKebabKeys<T> = T extends [any, ...any] ? { | ||
[I in keyof T]: DeepKebabKeys<T[I]>; | ||
} : T extends (infer V)[] ? DeepKebabKeys<V>[] : { | ||
[K in keyof T as KebabCase<Is<K, string>>]: DeepKebabKeys<T[K]>; | ||
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<Extract<K, string>>]: DeepConstantKeys<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. | ||
* 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 deepKebabKeys({ 'foo-bar': { 'fizz-buzz': true } }) // { 'foo-bar': { 'fizz-buzz': true } } | ||
* @example deepConstantKeys({ 'foo-bar': { 'fizz-buzz': true } }) // { FOO_BAR: { FIZZ_BUZZ: true } } | ||
*/ | ||
declare function deepKebabKeys<T>(obj: T): DeepKebabKeys<T>; | ||
declare function deepConstantKeys<T>(obj: T): DeepConstantKeys<T>; | ||
/** | ||
* Shallowly transforms the keys of an Record to PascalCase. | ||
* 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<Extract<K, string>, D>]: DeepDelimiterKeys<T[K], 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. | ||
* 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 pascalKeys({ 'foo-bar': { 'fizz-buzz': true } }) // { FooBar: { 'fizz-buzz': true } } | ||
* @example deepDelimiterKeys({ 'foo-bar': { 'fizz-buzz': true } }, '.') // { 'foo.bar': { 'fizz.buzz': true } } | ||
*/ | ||
declare function pascalKeys<T>(obj: T): PascalKeys<T>; | ||
declare function deepDelimiterKeys<T, D extends string>(obj: T, delimiter: D): DeepDelimiterKeys<T, D>; | ||
/** | ||
* Recursively transforms the keys of an Record to PascalCase. | ||
* Recursively transforms the keys of an Record to kebab-case. | ||
* T: the type of the Record to transform. | ||
*/ | ||
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 DeepKebabKeys<T> = T extends [any, ...any] ? { | ||
[I in keyof T]: DeepKebabKeys<T[I]>; | ||
} : T extends (infer V)[] ? DeepKebabKeys<V>[] : { | ||
[K in keyof T as KebabCase<Extract<K, string>>]: DeepKebabKeys<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. | ||
* 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. | ||
* @param obj the object to transform. | ||
* @returns the transformed object. | ||
* @example deepPascalKeys({ 'foo-bar': { 'fizz-buzz': true } }) // { FooBar: { FizzBuzz: true } } | ||
* @example deepKebabKeys({ 'foo-bar': { 'fizz-buzz': true } }) // { 'foo-bar': { 'fizz-buzz': true } } | ||
*/ | ||
declare function deepPascalKeys<T>(obj: T): DeepPascalKeys<T>; | ||
declare function deepKebabKeys<T>(obj: T): DeepKebabKeys<T>; | ||
/** | ||
* Shallowly 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 SnakeKeys<T> = T extends [] ? T : { | ||
[K in keyof T as SnakeCase<Is<K, string>>]: 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<Extract<K, string>>]: DeepPascalKeys<T[K]>; | ||
}; | ||
/** | ||
* A strongly typed function that shallowly the keys of an object to snake_case. The transformation is done both at runtime and type level. | ||
* 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 snakeKeys({ 'foo-bar': { 'fizz-buzz': true } }) // { 'foo_bar': { 'fizz-buzz': true } } | ||
* @example deepPascalKeys({ 'foo-bar': { 'fizz-buzz': true } }) // { FooBar: { FizzBuzz: true } } | ||
*/ | ||
declare function snakeKeys<T>(obj: T): SnakeKeys<T>; | ||
declare function deepPascalKeys<T>(obj: T): DeepPascalKeys<T>; | ||
/** | ||
@@ -561,3 +671,3 @@ * Recursively transforms the keys of an Record to snake_case. | ||
} : T extends (infer V)[] ? DeepSnakeKeys<V>[] : { | ||
[K in keyof T as SnakeCase<Is<K, string>>]: DeepSnakeKeys<T[K]>; | ||
[K in keyof T as SnakeCase<Extract<K, string>>]: DeepSnakeKeys<T[K]>; | ||
}; | ||
@@ -572,2 +682,2 @@ /** | ||
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 }; | ||
export { CamelCase, CamelKeys, CharAt, Concat, ConstantCase, ConstantKeys, DeepCamelKeys, DeepConstantKeys, DeepDelimiterKeys, DeepKebabKeys, DeepPascalKeys, DeepSnakeKeys, DelimiterCase, DelimiterKeys, Digit, EndsWith, Includes, IsDigit, IsLetter, IsLower, IsSeparator, IsSpecial, IsUpper, Join, KebabCase, KebabKeys, Length, PadEnd, PadStart, PascalCase, PascalKeys, Repeat, Replace, ReplaceAll, Separator, Slice, SnakeCase, SnakeKeys, Split, StartsWith, TitleCase, Trim, TrimEnd, TrimStart, Truncate, Words, camelKeys, capitalize, charAt, concat, constantKeys, deepCamelKeys, deepConstantKeys, deepDelimiterKeys, deepKebabKeys, deepPascalKeys, deepSnakeKeys, deepTransformKeys, delimiterKeys, endsWith, includes, join, kebabKeys, length, padEnd, padStart, pascalKeys, repeat, replace, replaceAll, slice, snakeKeys, split, startsWith, toCamelCase, toConstantCase, toDelimiterCase, toKebabCase, toLowerCase, toPascalCase, toSnakeCase, toTitleCase, toUpperCase, trim, trimEnd, trimStart, truncate, uncapitalize, words }; |
@@ -36,6 +36,11 @@ "use strict"; | ||
delimiterKeys: () => delimiterKeys, | ||
endsWith: () => endsWith, | ||
includes: () => includes, | ||
join: () => join, | ||
kebabKeys: () => kebabKeys, | ||
length: () => length, | ||
padEnd: () => padEnd, | ||
padStart: () => padStart, | ||
pascalKeys: () => pascalKeys, | ||
repeat: () => repeat, | ||
replace: () => replace, | ||
@@ -46,2 +51,3 @@ replaceAll: () => replaceAll, | ||
split: () => split, | ||
startsWith: () => startsWith, | ||
toCamelCase: () => toCamelCase, | ||
@@ -59,2 +65,3 @@ toConstantCase: () => toConstantCase, | ||
trimStart: () => trimStart, | ||
truncate: () => truncate, | ||
uncapitalize: () => uncapitalize, | ||
@@ -72,8 +79,20 @@ words: () => words | ||
} | ||
function join(tuple, delimiter) { | ||
return tuple.join(delimiter ?? ""); | ||
function endsWith(text, search, position = text.length) { | ||
return text.endsWith(search, position); | ||
} | ||
function join(tuple, delimiter = "") { | ||
return tuple.join(delimiter); | ||
} | ||
function length(str) { | ||
return str.length; | ||
} | ||
function padEnd(str, length2 = 0, pad = " ") { | ||
return str.padEnd(length2, pad); | ||
} | ||
function padStart(str, length2 = 0, pad = " ") { | ||
return str.padStart(length2, pad); | ||
} | ||
function repeat(str, times = 0) { | ||
return str.repeat(times); | ||
} | ||
function replace(sentence, lookup, replacement = "") { | ||
@@ -90,7 +109,13 @@ return sentence.replace(lookup, replacement); | ||
function slice(str, start = 0, end = str.length) { | ||
return str.slice(start, start < 0 ? void 0 : end); | ||
return str.slice(start, end); | ||
} | ||
function split(str, delimiter) { | ||
return str.split(delimiter ?? ""); | ||
function split(str, delimiter = "") { | ||
return str.split(delimiter); | ||
} | ||
function startsWith(text, search, position = 0) { | ||
return text.startsWith(search, position); | ||
} | ||
function includes(text, search, position = 0) { | ||
return text.includes(search, position); | ||
} | ||
function trimStart(str) { | ||
@@ -106,6 +131,35 @@ return str.trimStart(); | ||
// src/separators.ts | ||
var UNESCAPED_SEPARATORS = [ | ||
"[", | ||
"]", | ||
"{", | ||
"}", | ||
"(", | ||
")", | ||
"|", | ||
"/", | ||
"-", | ||
"\\" | ||
]; | ||
var SEPARATORS = [...UNESCAPED_SEPARATORS, " ", "_", "."]; | ||
function escapeChar(char) { | ||
return UNESCAPED_SEPARATORS.includes(char) ? `\\${char}` : char; | ||
} | ||
var SEPARATOR_REGEX = new RegExp( | ||
`[${SEPARATORS.map(escapeChar).join("")}]`, | ||
"g" | ||
); | ||
// src/utils.ts | ||
function words(sentence) { | ||
return sentence.replace(/[_\-./]/g, " ").replace(/([a-zA-Z])([0-9])/g, "$1 $2").replace(/([0-9])([a-zA-Z])/g, "$1 $2").replace(/([a-zA-Z0-9_\-./])([^a-zA-Z0-9_\-./])/g, "$1 $2").replace(/([^a-zA-Z0-9_\-./])([a-zA-Z0-9_\-./])/g, "$1 $2").replace(/([a-z])([A-Z])/g, "$1 $2").replace(/([A-Z])([A-Z][a-z])/g, "$1 $2").trim().split(/\s+/g); | ||
return sentence.replace(SEPARATOR_REGEX, " ").replace(/([a-zA-Z])([0-9])/g, "$1 $2").replace(/([0-9])([a-zA-Z])/g, "$1 $2").replace(/([a-zA-Z0-9_\-./])([^a-zA-Z0-9_\-./])/g, "$1 $2").replace(/([^a-zA-Z0-9_\-./])([a-zA-Z0-9_\-./])/g, "$1 $2").replace(/([a-z])([A-Z])/g, "$1 $2").replace(/([A-Z])([A-Z][a-z])/g, "$1 $2").trim().split(/\s+/g); | ||
} | ||
function truncate(sentence, length2, omission = "...") { | ||
if (length2 < 0) | ||
return omission; | ||
if (sentence.length <= length2) | ||
return sentence; | ||
return join([sentence.slice(0, length2 - omission.length), omission]); | ||
} | ||
@@ -165,2 +219,22 @@ // src/internals.ts | ||
} | ||
function camelKeys(obj) { | ||
return transformKeys(obj, toCamelCase); | ||
} | ||
function constantKeys(obj) { | ||
return transformKeys(obj, toConstantCase); | ||
} | ||
function delimiterKeys(obj, delimiter) { | ||
return transformKeys(obj, (str) => toDelimiterCase(str, delimiter)); | ||
} | ||
function kebabKeys(obj) { | ||
return transformKeys(obj, toKebabCase); | ||
} | ||
function pascalKeys(obj) { | ||
return transformKeys(obj, toPascalCase); | ||
} | ||
function snakeKeys(obj) { | ||
return transformKeys(obj, toSnakeCase); | ||
} | ||
// src/deep-key-casing.ts | ||
function deepTransformKeys(obj, transform) { | ||
@@ -178,17 +252,8 @@ if (!["object", "array"].includes(typeOf(obj))) | ||
} | ||
function camelKeys(obj) { | ||
return transformKeys(obj, toCamelCase); | ||
} | ||
function deepCamelKeys(obj) { | ||
return deepTransformKeys(obj, toCamelCase); | ||
} | ||
function constantKeys(obj) { | ||
return transformKeys(obj, toConstantCase); | ||
} | ||
function deepConstantKeys(obj) { | ||
return deepTransformKeys(obj, toConstantCase); | ||
} | ||
function delimiterKeys(obj, delimiter) { | ||
return transformKeys(obj, (str) => toDelimiterCase(str, delimiter)); | ||
} | ||
function deepDelimiterKeys(obj, delimiter) { | ||
@@ -200,17 +265,8 @@ return deepTransformKeys( | ||
} | ||
function kebabKeys(obj) { | ||
return transformKeys(obj, toKebabCase); | ||
} | ||
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 deepSnakeKeys(obj) { | ||
@@ -234,6 +290,11 @@ return deepTransformKeys(obj, toSnakeCase); | ||
delimiterKeys, | ||
endsWith, | ||
includes, | ||
join, | ||
kebabKeys, | ||
length, | ||
padEnd, | ||
padStart, | ||
pascalKeys, | ||
repeat, | ||
replace, | ||
@@ -244,2 +305,3 @@ replaceAll, | ||
split, | ||
startsWith, | ||
toCamelCase, | ||
@@ -257,4 +319,5 @@ toConstantCase, | ||
trimStart, | ||
truncate, | ||
uncapitalize, | ||
words | ||
}); |
{ | ||
"name": "string-ts", | ||
"version": "1.1.0", | ||
"version": "1.2.0", | ||
"description": "Strongly-typed string functions.", | ||
@@ -14,3 +14,3 @@ "main": "./dist/index.js", | ||
"lint": "eslint *.ts*", | ||
"tsc": "tsc", | ||
"tsc": "tsc --noEmit", | ||
"test": "vitest run" | ||
@@ -17,0 +17,0 @@ }, |
124
README.md
@@ -34,3 +34,3 @@ # Strongly-typed string functions for all! | ||
## In-depth example | ||
### In-depth example | ||
@@ -86,2 +86,8 @@ In the below example, I want to get a strongly-typed, camel-case version of `process.env`. | ||
## 👌 Supported TypeScript versions | ||
`string-ts` currently only works on TypeScript v5+. | ||
It also only work with common ASCII characters characters. We don't plan to support international characters or emojis. | ||
--- | ||
@@ -97,4 +103,9 @@ | ||
- [concat](#concat) | ||
- [endsWith](#endsWith) | ||
- [includes](#includes) | ||
- [join](#join) | ||
- [length](#length) | ||
- [padEnd](#padend) | ||
- [padStart](#padstart) | ||
- [repeat](#repeat) | ||
- [replace](#replace) | ||
@@ -104,2 +115,3 @@ - [replaceAll](#replaceall) | ||
- [split](#split) | ||
- [startsWith](#startsWith) | ||
- [toLowerCase](#tolowercase) | ||
@@ -118,2 +130,3 @@ - [toUpperCase](#touppercase) | ||
- [toTitleCase](#totitlecase) | ||
- [truncate](#truncate) | ||
- [words](#words) | ||
@@ -195,2 +208,24 @@ - [Strongly-typed shallow transformation of objects](#strongly-typed-shallow-transformation-of-objects) | ||
### endsWith | ||
This function is a strongly-typed counterpart of `String.prototype.endsWith`. | ||
```ts | ||
import { endsWith } from 'string-ts' | ||
const result = endsWith('abc', 'c') | ||
// ^ true | ||
``` | ||
### includes | ||
This function is a strongly-typed counterpart of `String.prototype.includes`. | ||
```ts | ||
import { includes } from 'string-ts' | ||
const result = includes('abcde', 'bcd') | ||
// ^ true | ||
``` | ||
### join | ||
@@ -220,2 +255,38 @@ | ||
### padEnd | ||
This function is a strongly-typed counterpart of `String.prototype.padEnd`. | ||
```ts | ||
import { padEnd } from 'string-ts' | ||
const str = 'hello' | ||
const result = padEnd(str, 10, '=') | ||
// ^ 'hello=====' | ||
``` | ||
### padStart | ||
This function is a strongly-typed counterpart of `String.prototype.padStart`. | ||
```ts | ||
import { padStart } from 'string-ts' | ||
const str = 'hello' | ||
const result = padStart(str, 10, '=') | ||
// ^ '=====hello' | ||
``` | ||
### repeat | ||
This function is a strongly-typed counterpart of `String.prototype.repeat`. | ||
```ts | ||
import { repeat } from 'string-ts' | ||
const str = 'abc' | ||
const result = repeat(str, 3) | ||
// ^ 'abcabcabc' | ||
``` | ||
### replace | ||
@@ -225,3 +296,3 @@ | ||
_Warning: this is a partial implementation as we don't support Regex._ | ||
_Warning: this is a partial implementation, as we don't fully support Regex. Using a RegExp lookup will result in a loose typing._ | ||
@@ -234,2 +305,4 @@ ```ts | ||
// ^ 'hello world-' | ||
const looselyTypedResult = replace(str, /-/, ' ') | ||
// ^ string | ||
``` | ||
@@ -242,3 +315,3 @@ | ||
_Warning: this is a partial implementation as we don't support Regex._ | ||
_Warning: this is a partial implementation, as we don't fully support Regex. Using a RegExp lookup will result in a loose typing._ | ||
@@ -251,2 +324,4 @@ ```ts | ||
// ^ 'hello world ' | ||
const looselyTypedResult = replaceAll(str, /-/g, ' ') | ||
// ^ string | ||
``` | ||
@@ -258,4 +333,2 @@ | ||
_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 | ||
@@ -285,2 +358,13 @@ import { slice } from 'string-ts' | ||
### startsWith | ||
This function is a strongly-typed counterpart of `String.prototype.startsWith`. | ||
```ts | ||
import { startsWith } from 'string-ts' | ||
const result = startsWith('abc', 'a') | ||
// ^ true | ||
``` | ||
### toLowerCase | ||
@@ -432,2 +516,15 @@ | ||
### truncate | ||
This function truncates string if it's longer than the given maximum string length. The last characters of the truncated string are replaced with the omission string which defaults to "...". | ||
```ts | ||
import { truncate } from 'string-ts' | ||
const str = '-20someVery-weird String' | ||
const result = truncate(str, 8) | ||
// ^ '-20so...' | ||
``` | ||
### words | ||
@@ -641,3 +738,3 @@ | ||
## Type Utilities | ||
## Type utilities | ||
@@ -658,3 +755,3 @@ All the functions presented in this API have associated type counterparts. | ||
### General Type utilities from this library | ||
### General type utilities from this library | ||
@@ -664,4 +761,9 @@ ```ts | ||
St.Concat<['a', 'bc', 'def']> // 'abcdef' | ||
St.EndsWith<'abc', 'c'> // true | ||
St.Includes<'abcde', 'bcd'> // true | ||
St.Join<['hello', 'world'], '-'> // 'hello-world' | ||
St.Length<'hello'> // 5 | ||
St.PadEnd<'hello', 10, '='> // 'hello=====' | ||
St.PadStart<'hello', 10, '='> // '=====hello' | ||
St.Repeat<'abc', 3> // 'abcabcabc' | ||
St.Replace<'hello-world', 'l', '1'> // 'he1lo-world' | ||
@@ -672,4 +774,6 @@ St.ReplaceAll<'hello-world', 'l', '1'> // 'he11o-wor1d' | ||
St.Trim<' hello world '> // 'hello world' | ||
St.StartsWith<'abc', 'a'> // true | ||
St.TrimEnd<' hello world '> // ' hello world' | ||
St.TrimStart<' hello world '> // 'hello world ' | ||
St.Truncate<'hello world', 9, '[...]'> // 'hello[...] | ||
St.Words<'hello-world'> // ['hello', 'world'] | ||
@@ -767,8 +871,4 @@ ``` | ||
## Disclaimer | ||
## 🫶 Acknowledgements | ||
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
67930
1199
856