Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

string-ts

Package Overview
Dependencies
Maintainers
1
Versions
21
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

string-ts - npm Package Compare versions

Comparing version 1.1.0 to 1.2.0

366

dist/index.d.ts

@@ -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 @@ },

@@ -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

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc