UNPKG

@oazmi/kitchensink

Version:

a collection of personal utility functions

538 lines 22.6 kB
/** utility functions for manipulating, generating, or parsing `string`s. * * @module */ import type { NumericArray } from "./typedefs.js"; /** configuration for customizing the hex-string representation made by {@link hexStringOfArray}. * * the default configuration is: * * ```ts * const default_HexStringReprConfig: HexStringReprConfig = { * sep: ", ", * prefix: "0x", * postfix: "", * trailingSep: false, * bra: "[", * ket: "]", * toUpperCase: true, * radix: 16, * } * ``` */ export interface HexStringReprConfig { /** separator character string between bytes. * * @defaultValue `", "` */ sep: string; /** what string to prefix every hex-string byte with? * * @defaultValue `"0x"` */ prefix: string; /** what string to add to the end of every hex-string byte? * * @defaultValue `""` (an empty string) */ postfix: string; /** specify if you want to include a trailing {@link sep} after the final byte. * * - example output when `true`: `"[0x01, 0x02, 0x03,]"`, * - example output when `false`: `"[0x01, 0x02, 0x03]"`. * * @defaultValue `false` */ trailingSep: boolean; /** the left bracket string. * * @defaultValue `"["` */ bra: string; /** the right bracket string. * * @defaultValue `"]"` */ ket: string; /** specify if you want upper case letters for the hex-string. * * @defaultValue `true` */ toUpperCase: boolean; /** provide an alternate number base to encode the numbers into. * see {@link Number.toString} for more details. * * use `16` for a hex-string, or `2` for binary-string. * accepted values must be between `2` and `36`. * * @defaultValue `16` */ radix: number; } /** convert an array of integer numbers to hex-string, for the sake of easing representation, or for visual purposes. * * to customize the appearance of the hex-string, or to use a different radix, use the {@link HexStringReprConfig} interface to change the default `options`. * * you must make sure that every element of your array `arr` is non-negative, in addition to being less than `options.radix ** 2`. * since the default `options.radix === 16`, each of your number must be smaller than `256` on the default config. * * to invert the operation of this function (i.e. parse an array of integers from a string), use the {@link hexStringToArray} function with the same config `options`. * * @example * ```ts * import { assertEquals as assertEq } from "jsr:@std/assert" * * const * my_binary_code = [1, 2, 3, 125, 126, 127, 192, 225, 255], * my_custom_config: Partial<HexStringReprConfig> = { * sep: ",", * trailingSep: true, * bra: "<", * ket: ">", * } * * const my_binary_code_repr = hexStringOfArray(my_binary_code, my_custom_config) * assertEq(my_binary_code_repr, "<0x01,0x02,0x03,0x7D,0x7E,0x7F,0xC0,0xE1,0xFF,>") * * const my_custom_config2 = { ...my_custom_config, sep: "", trailingSep: false, prefix: "" } * const my_binary_code_repr2 = hexStringOfArray(my_binary_code, my_custom_config2) * assertEq(my_binary_code_repr2, "<0102037D7E7FC0E1FF>") * ``` */ export declare const hexStringOfArray: (arr: NumericArray, options: Partial<HexStringReprConfig>) => string; /** convert hex-string back to an array of integers, * provided that you know the exact {@link HexStringReprConfig} config of your particular hex-string. * * this function performs the inverse operation of {@link hexStringOfArray}, given that you use the same `options`. * * @example * ```ts * import { assertEquals as assertEq } from "jsr:@std/assert" * * const * my_binary_code_repr = "<0x01,0x02,0x03,0x7D,0x7E,0x7F,0xC0,0xE1,0xFF,>", * my_custom_config: Partial<HexStringReprConfig> = { * sep: ",", * trailingSep: true, * bra: "<", * ket: ">", * } * * const my_binary_code: number[] = hexStringToArray(my_binary_code_repr, my_custom_config) * * assertEq(my_binary_code, [1, 2, 3, 125, 126, 127, 192, 225, 255]) * ``` */ export declare const hexStringToArray: (hex_str: string, options: Partial<HexStringReprConfig>) => Array<number>; /** a shorthand function for either getting the upper or lower case of a string `str`, based on the numeric `option`. * * options: * - `option > 0` => input string is turned to uppercase * - `option < 0` => input string is turned to lowercase * - `option = 0` => input string is unmodified */ export declare const toUpperOrLowerCase: (str: string, option: 1 | 0 | -1) => string; /** finds the index of next uppercase character, starting from index `start` and optionally ending at exclusive-index `end`. * if an uppercase character is not found, then `undefined` is returned. */ export declare const findNextUpperCase: (str: string, start?: number, end?: number | undefined) => number | undefined; /** finds the index of next lowercase character, starting from index `start` and optionally ending at exclusive-index `end`. * if a lowercase character is not found, then `undefined` is returned. */ export declare const findNextLowerCase: (str: string, start?: number, end?: number | undefined) => number | undefined; /** find either the next upper or next lower case character index in string `str`, based on the numeric `option`, * starting from index `start` and optionally ending at exclusive-index `end`. * if your selected uppercase/lowercase option is not found, or if your `option === 0`, then `undefined` is returned. * * this function is just a composition of the functions {@link findNextUpperCase} and {@link findNextLowerCase}. */ export declare const findNextUpperOrLowerCase: (str: string, option: 1 | -1, start?: number, end?: number | undefined) => number | undefined; /** this interface is used by various functions in this submodule to parse and unparse word tokens of various styles. * it provides the description of your tokens, so that it can be broken down into words, or vice-versa. * * here is a list of functions that make use of this interface: * - {@link wordsToToken}, {@link tokenToWords}, {@link convertCase}, {@link convertCase_Factory} * * the `NamingCaseTuple` consists of the following configurable options, as an array: * * - index `0`: specifies the `first_letter_upper` option: <br> * _is the first letter an upper case letter?_ * - ` 1` => yes. * - `-1` => no. * - ` 0` => impartial (in other words, it will depend-on/inherit `word_first_letter_upper`). * * - index `1`: specifies the `word_first_letter_upper` option: <br> * _is the first letter of each word an upper case letter?_ * - ` 1` => yes. * - `-1` => no. * - ` 0` => preserve original. * * - index `2`: specifies the `rest_word_letters_upper` option: <br> * _are the remaining letters in each word in upper case?_ * - ` 1` => yes. * - `-1` => no. * - ` 0` => preserve original. * * - index `3`: specifies the `delimiter` option: <br> * _what is the separator between words in a single token (if any)?_ * - ` ""` => (default) indicates that there's no delimiter character. * so we must rely on letter case change to detect word splitting. * this is what is used for camelCase and PascalCase. * - ` "_"` => delimiter is used by snake_case. * - ` "-"` => delimiter is used by kebab-case. * - `string` => define a custom delimiter string. * * - index `4`: specifies the `prefix` option: <br> * _what is the prefix string (if any)?_ * * - index `5`: specifies the `suffix` option: <br> * _what is the suffix string (if any)?_ */ export type NamingCaseTuple = [ first_letter_upper: 1 | 0 | -1, word_first_letter_upper: 1 | 0 | -1, rest_word_letters_upper: 1 | 0 | -1, delimiter?: "" | "_" | "-" | string, prefix?: string, suffix?: string ]; /** convert an array of `words` to a single token, based on the configuration provided in `casetype`. * * to reverse the operation of this function, use the {@link tokenToWords} function with the same `casetype` config that you use here. * * @example * ```ts * import { assertEquals as eq } from "jsr:@std/assert" * * const words = ["convert", "windows", "path", "to", "unix"] * * const * snakeCase: NamingCaseTuple = [-1, -1, -1, "_"], * kebabCase: NamingCaseTuple = [-1, -1, -1, "-"], * camelCase: NamingCaseTuple = [-1, 1, -1, ""], * pascalCase: NamingCaseTuple = [1, 1, -1, ""], * screamingSnakeCase: NamingCaseTuple = [1, 1, 1, "_"], * screamingKebabCase: NamingCaseTuple = [1, 1, 1, "-"] * * eq(wordsToToken(snakeCase, words), "convert_windows_path_to_unix") * eq(wordsToToken(kebabCase, words), "convert-windows-path-to-unix") * eq(wordsToToken(camelCase, words), "convertWindowsPathToUnix") * eq(wordsToToken(pascalCase, words), "ConvertWindowsPathToUnix") * eq(wordsToToken(screamingSnakeCase, words), "CONVERT_WINDOWS_PATH_TO_UNIX") * eq(wordsToToken(screamingKebabCase, words), "CONVERT-WINDOWS-PATH-TO-UNIX") * ``` */ export declare const wordsToToken: (casetype: NamingCaseTuple, words: string[]) => string; /** breakdown a single `token` into its constituent words, based on the configuration provided in `casetype`. * * this function performs the inverse operation of {@link wordsToToken}, provided that you use the same `casetype` config. * * @example * ```ts * import { assertEquals as eq } from "jsr:@std/assert" * * const * snakeCase: NamingCaseTuple = [-1, -1, -1, "_"], * kebabCase: NamingCaseTuple = [-1, -1, -1, "-"], * camelCase: NamingCaseTuple = [-1, 1, -1, ""], * pascalCase: NamingCaseTuple = [1, 1, -1, ""], * screamingSnakeCase: NamingCaseTuple = [1, 1, 1, "_"], * screamingKebabCase: NamingCaseTuple = [1, 1, 1, "-"] * * // the expected list of words that our tokens should breakdown into * const words = ["convert", "windows", "path", "to", "unix"] * * eq(tokenToWords(snakeCase, "convert_windows_path_to_unix"), words) * eq(tokenToWords(kebabCase, "convert-windows-path-to-unix"), words) * eq(tokenToWords(camelCase, "convertWindowsPathToUnix"), words) * eq(tokenToWords(pascalCase, "ConvertWindowsPathToUnix"), words) * eq(tokenToWords(screamingSnakeCase, "CONVERT_WINDOWS_PATH_TO_UNIX"), words) * eq(tokenToWords(screamingKebabCase, "CONVERT-WINDOWS-PATH-TO-UNIX"), words) * ``` */ export declare const tokenToWords: (casetype: NamingCaseTuple, token: string) => string[]; /** converts a string token from one case type to another, * by performing a composition operation of {@link tokenToWords} and {@link wordsToToken}. * * @example * ```ts * import { assertEquals as eq } from "jsr:@std/assert" * * const * snakeCase: NamingCaseTuple = [-1, -1, -1, "_"], * kebabCase: NamingCaseTuple = [-1, -1, -1, "-"], * camelCase: NamingCaseTuple = [-1, 1, -1, ""], * pascalCase: NamingCaseTuple = [1, 1, -1, ""], * screamingSnakeCase: NamingCaseTuple = [1, 1, 1, "_"], * screamingKebabCase: NamingCaseTuple = [1, 1, 1, "-"] * * eq(convertCase( * snakeCase, screamingSnakeCase, * "convert_windows_path_to_unix", * ), "CONVERT_WINDOWS_PATH_TO_UNIX") * * eq(convertCase( * kebabCase, camelCase, * "convert-windows-path-to-unix", * ), "convertWindowsPathToUnix") * * eq(convertCase( * camelCase, kebabCase, * "convertWindowsPathToUnix", * ), "convert-windows-path-to-unix") * * eq(convertCase( * kebabCase, kebabCase, * "convert-windows-path-to-unix", * ), "convert-windows-path-to-unix") * * eq(convertCase( * screamingKebabCase, pascalCase, * "CONVERT-WINDOWS-PATH-TO-UNIX", * ), "ConvertWindowsPathToUnix") * ``` */ export declare const convertCase: (from_casetype: NamingCaseTuple, to_casetype: NamingCaseTuple, token: string) => string; /** generate a specific case converter. convenient for continued use. * * see {@link kebabToCamel} and {@link camelToKebab} as examples that are generated via this function. */ export declare const convertCase_Factory: (from_casetype: NamingCaseTuple, to_casetype: NamingCaseTuple) => ((token: string) => string); /** the token name casing configuration for a "snake_case". */ export declare const snakeCase: NamingCaseTuple; /** the token name casing configuration for a "kebab-case". */ export declare const kebabCase: NamingCaseTuple; /** the token name casing configuration for a "camelCase". */ export declare const camelCase: NamingCaseTuple; /** the token name casing configuration for a "PascalCase". */ export declare const pascalCase: NamingCaseTuple; /** the token name casing configuration for a "SCREAMING_SNAKE_CASE". */ export declare const screamingSnakeCase: NamingCaseTuple; /** the token name casing configuration for a "SCREAMING-SNAKE-CASE". */ export declare const screamingKebabCase: NamingCaseTuple; /** a function to convert snake case token to a kebab case token. */ export declare const snakeToKebab: (token: string) => string; /** a function to convert snake case token to a camel case token. */ export declare const snakeToCamel: (token: string) => string; /** a function to convert snake case token to a pascal case token. */ export declare const snakeToPascal: (token: string) => string; /** a function to convert kebab case token to a snake case token. */ export declare const kebabToSnake: (token: string) => string; /** a function to convert kebab case token to a camel case token. */ export declare const kebabToCamel: (token: string) => string; /** a function to convert kebab case token to a pascal case token. */ export declare const kebabToPascal: (token: string) => string; /** a function to convert camel case token to a snake case token. */ export declare const camelToSnake: (token: string) => string; /** a function to convert camel case token to a kebab case token. */ export declare const camelToKebab: (token: string) => string; /** a function to convert camel case token to a pascal case token. */ export declare const camelToPascal: (token: string) => string; /** a function to convert pascal case token to a snake case token. */ export declare const PascalToSnake: (token: string) => string; /** a function to convert pascal case token to a kebab case token. */ export declare const PascalToKebab: (token: string) => string; /** a function to convert pascal case token to a camel case token. */ export declare const PascalTocamel: (token: string) => string; /** surround a string with double quotation. * * someone should nominate this function for 2025 mathematics nobel prize. */ export declare const quote: (str: string) => string; /** reversing a string is not natively supported by javascript, and performing it is not so trivial when considering that * you can have composite UTF-16 characters (such as emojis and characters with accents). * * see this excellent solution in stackoverflow for reversing a string: [stackoverflow.com/a/60056845](https://stackoverflow.com/a/60056845). * we use the slightly less reliable technique provided by the answer, as it has a better browser support. */ export declare const reverseString: (input: string) => string; /** find the longest common prefix among a list of `inputs`. * * for efficiency, this function starts off by using the shortest string among `inputs`, then performs a binary search. * * @example * ```ts * import { assertEquals as assertEq } from "jsr:@std/assert" * * assertEq(commonPrefix([ * "C:/Hello/World/This/Is/An/Example/Bla.cs", * "C:/Hello/World/This/Is/Not/An/Example/", * "C:/Hello/Earth/Bla/Bla/Bla", * ]), "C:/Hello/") * * assertEq(commonPrefix([ * "C:/Hello/World/This/Is/An/Example/Bla.cs", * "C:/Hello/World/This/is/an/example/bla.cs", * "C:/Hello/World/This/Is/Not/An/Example/", * ]), "C:/Hello/World/This/") * * assertEq(commonPrefix([ * "C:/Hello/World/Users/This/Is/An/Example/Bla.cs", * "C:/Hello/World Users/This/Is/An/example/bla.cs", * "C:/Hello/World-Users/This/Is/Not/An/Example/", * ]), "C:/Hello/World") * ``` */ export declare const commonPrefix: (inputs: string[]) => string; /** find the longest common suffix among a list of `inputs`. * * for efficiency, this function simply reverses the character ordering of each input, and then uses {@link commonPrefix}. * * @example * ```ts * import { assertEquals as assertEq } from "jsr:@std/assert" * * assertEq(commonSuffix([ * "file:///C:/Hello/World/This/Is/An/Example/Bla.cs", * "file:///C:/Hello/Users/This/Is-An/Example/Bla.cs", * "file:///C:/Hello/Users/This/Is/YetAnother-An/Example/Bla.cs", * "file:///C:/Hello/Earth/This/Is/Not/An/Example/Bla.cs", * ]), "An/Example/Bla.cs") * ``` */ export declare const commonSuffix: (inputs: string[]) => string; /** this regex contains all characters that need to be escaped in a regex. * it is basically defined as `/[.*+?^${}()|[\]\\]/g`. */ export declare const escapeLiteralCharsRegex: RegExp; /** escape a string so that it can be matched exactly in a regex constructor. * * @example * ```ts * import { assertEquals as assertEq } from "jsr:@std/assert" * * const * substring = String.raw`(\|[++h.e.\\.o++]|/)`, * substring_escaped = escapeLiteralStringForRegex(substring), * my_regex = new RegExp(`${substring_escaped}\\(world\\)`), * my_string = String.raw`this string consist of (\|[++h.e.\\.o++]|/)(world) positioned somewhere in the middle` * * assertEq(my_regex.test(my_string), true) * ``` */ export declare const escapeLiteralStringForRegex: (str: string) => string; /** replace the `prefix` of of a given `input` string with the given replace `value`. * if a matching prefix is not found, then `undefined` will be returned. * * @param input the input string to apply the prefix replacement to. * @param prefix the prefix string of the input to replace. * @param value the optional value to replace the the prefix with. defaults to `""` (empty string). * @returns if a matching `prefix` is found in the `input`, then it will be replaced with the given `value`. * otherwise, `undefined` will be returned if the `input` does not begin with the `prefix`. * * @example * ```ts * import { assertEquals } from "jsr:@std/assert" * * // aliasing our function for brevity * const * eq = assertEquals, * fn = replacePrefix * * eq(fn("hello-world/abc-123", "hello-", "goodbye-"), "goodbye-world/abc-123") * eq(fn("hello-world/abc-123", "hello-"), "world/abc-123") * eq(fn("hello-world/abc-123", "abc"), undefined) * eq(fn("hello-world/abc-123", ""), "hello-world/abc-123") * eq(fn("hello-world/abc-123", "", "xyz-"), "xyz-hello-world/abc-123") * ``` */ export declare const replacePrefix: (input: string, prefix: string, value?: string) => string | undefined; /** replace the `suffix` of of a given `input` string with the given replace `value`. * if a matching suffix is not found, then `undefined` will be returned. * * @param input the input string to apply the suffix replacement to. * @param suffix the suffix string of the input to replace. * @param value the optional value to replace the the suffix with. defaults to `""` (empty string). * @returns if a matching `suffix` is found in the `input`, then it will be replaced with the given `value`. * otherwise, `undefined` will be returned if the `input` does not begin with the `suffix`. * * @example * ```ts * import { assertEquals } from "jsr:@std/assert" * * // aliasing our function for brevity * const * eq = assertEquals, * fn = replaceSuffix * * eq(fn("hello-world/abc-123", "-123", "-xyz"), "hello-world/abc-xyz") * eq(fn("hello-world/abc-123", "-123"), "hello-world/abc") * eq(fn("hello-world/abc-123", "abc"), undefined) * eq(fn("hello-world/abc-123", ""), "hello-world/abc-123") * eq(fn("hello-world/abc-123", "", "-xyz"), "hello-world/abc-123-xyz") * ``` */ export declare const replaceSuffix: (input: string, suffix: string, value?: string) => string | undefined; /** remove comments and trailing commas from a "jsonc" (json with comments) string. * * in a jsonc-string, there three additional features that supersede a regular json-string: * - inline comments: anything affer a double forward-slash `//` (that is not part of a string) is a comment, until the end of the line. * - multiline comments: anything inside the c-like multiline comment block (`/* ... *\/`) is a comment. * - trailing commas: you can add up to one trailing comma (`,`) after the last element of an array, or the last entry of a dictionary. * * moreover, this function also trims unnecessary whitespaces and newlines outside of string literals. * * once you have converted your jsonc-string to a json-string, you will probably want to use `JSON.parse` to parse the output. * * @param jsonc_string - The jsonc string from which comments need to be removed. * @returns A string representing the jsonc-equivalent content, without comments and trailing commas. * * @example * ```ts * import { assertEquals } from "jsr:@std/assert" * * const my_jsonc = ` * { * // inline comment * "key1": "value1", * /* block comment *\/ "key2": 2, * /* multiline block comment * * hello * * world * *\/ * "key3": { * "//key4": "value4 //", * "jsonInComment": "/* { \\"key\\": \\"value\\" } *\/", * "trickyEscapes": "a string with \\\\\\"escaped quotes\\\\\\" and /* fake comment *\/ inside and \\newline", * }, * "array1": [ * "/* not a comment *\/", * "// also not a comment", * "has a trailing comma" // trailing comma below \t \t tab characters. * , // <-- trailing comma here. and some more \t \t tab characters. * ], * /* Block comment containing JSON: * { "fakeKey": "fakeValue" }, * *\/ * "arr//ay2": [ * true, false, { "1": false, "2": true, }, * 42,7, * // scientific notation * 1e10,], * }` * * const expected_value = { * key1: "value1", * key2: 2, * key3: { * "//key4": "value4 //", * jsonInComment: `/* { "key": "value" } *\/`, * trickyEscapes: `a string with \\"escaped quotes\\" and /* fake comment *\/ inside and \newline`, * }, * array1: [ * "/* not a comment *\/", * "// also not a comment", * "has a trailing comma", * ], * "arr//ay2": [ true, false, { "1": false, "2": true }, 42, 7, 10000000000, ] * } * * const * my_json = jsoncRemoveComments(my_jsonc), * my_parsed_json = JSON.parse(my_json) * * assertEquals(my_parsed_json, expected_value) * ``` */ export declare const jsoncRemoveComments: (jsonc_string: string) => string; //# sourceMappingURL=stringman.d.ts.map