import { Ok, Error, Empty as $Empty, prepend as listPrepend, CustomType as $CustomType, remainderInt, divideInt, } from "../gleam.mjs"; import * as $list from "../gleam/list.mjs"; import * as $option from "../gleam/option.mjs"; import { None, Some } from "../gleam/option.mjs"; import * as $order from "../gleam/order.mjs"; import * as $string_tree from "../gleam/string_tree.mjs"; import { string_length as length, lowercase, uppercase, less_than, string_grapheme_slice as grapheme_slice, string_byte_slice as unsafe_byte_slice, crop_string as crop, contains_string as contains, starts_with, ends_with, split_once, trim_start, trim_end, pop_grapheme, graphemes as to_graphemes, codepoint as unsafe_int_to_utf_codepoint, string_to_codepoint_integer_list, utf_codepoint_list_to_string as from_utf_codepoints, utf_codepoint_to_int, inspect as do_inspect, byte_size, } from "../gleam_stdlib.mjs"; export { byte_size, contains, crop, ends_with, from_utf_codepoints, length, lowercase, pop_grapheme, split_once, starts_with, to_graphemes, trim_end, trim_start, uppercase, utf_codepoint_to_int, }; class Leading extends $CustomType {} class Trailing extends $CustomType {} /** * Determines if a `String` is empty. * * ## Examples * * ```gleam * is_empty("") * // -> True * ``` * * ```gleam * is_empty("the world") * // -> False * ``` */ export function is_empty(str) { return str === ""; } /** * Reverses a `String`. * * This function has to iterate across the whole `String` so it runs in linear * time. Avoid using this in a loop. * * ## Examples * * ```gleam * reverse("stressed") * // -> "desserts" * ``` */ export function reverse(string) { let _pipe = string; let _pipe$1 = $string_tree.from_string(_pipe); let _pipe$2 = $string_tree.reverse(_pipe$1); return $string_tree.to_string(_pipe$2); } /** * Creates a new `String` by replacing all occurrences of a given substring. * * ## Examples * * ```gleam * replace("www.example.com", each: ".", with: "-") * // -> "www-example-com" * ``` * * ```gleam * replace("a,b,c,d,e", each: ",", with: "/") * // -> "a/b/c/d/e" * ``` */ export function replace(string, pattern, substitute) { let _pipe = string; let _pipe$1 = $string_tree.from_string(_pipe); let _pipe$2 = $string_tree.replace(_pipe$1, pattern, substitute); return $string_tree.to_string(_pipe$2); } /** * Compares two `String`s to see which is "larger" by comparing their graphemes. * * This does not compare the size or length of the given `String`s. * * ## Examples * * ```gleam * compare("Anthony", "Anthony") * // -> order.Eq * ``` * * ```gleam * compare("A", "B") * // -> order.Lt * ``` */ export function compare(a, b) { let $ = a === b; if ($) { return new $order.Eq(); } else { let $1 = less_than(a, b); if ($1) { return new $order.Lt(); } else { return new $order.Gt(); } } } /** * Takes a substring given a start grapheme index and a length. Negative indexes * are taken starting from the *end* of the list. * * This function runs in linear time with the size of the index and the * length. Negative indexes are linear with the size of the input string in * addition to the other costs. * * ## Examples * * ```gleam * slice(from: "gleam", at_index: 1, length: 2) * // -> "le" * ``` * * ```gleam * slice(from: "gleam", at_index: 1, length: 10) * // -> "leam" * ``` * * ```gleam * slice(from: "gleam", at_index: 10, length: 3) * // -> "" * ``` * * ```gleam * slice(from: "gleam", at_index: -2, length: 2) * // -> "am" * ``` * * ```gleam * slice(from: "gleam", at_index: -12, length: 2) * // -> "" * ``` */ export function slice(string, idx, len) { let $ = len <= 0; if ($) { return ""; } else { let $1 = idx < 0; if ($1) { let translated_idx = length(string) + idx; let $2 = translated_idx < 0; if ($2) { return ""; } else { return grapheme_slice(string, translated_idx, len); } } else { return grapheme_slice(string, idx, len); } } } /** * Drops *n* graphemes from the end of a `String`. * * This function traverses the full string, so it runs in linear time with the * size of the string. Avoid using this in a loop. * * ## Examples * * ```gleam * drop_end(from: "Cigarette Smoking Man", up_to: 2) * // -> "Cigarette Smoking M" * ``` */ export function drop_end(string, num_graphemes) { let $ = num_graphemes <= 0; if ($) { return string; } else { return slice(string, 0, length(string) - num_graphemes); } } /** * Creates a new `String` by joining two `String`s together. * * This function typically copies both `String`s and runs in linear time, but * the exact behaviour will depend on how the runtime you are using optimises * your code. Benchmark and profile your code if you need to understand its * performance better. * * If you are joining together large string and want to avoid copying any data * you may want to investigate using the [`string_tree`](../gleam/string_tree.html) * module. * * ## Examples * * ```gleam * append(to: "butter", suffix: "fly") * // -> "butterfly" * ``` */ export function append(first, second) { return first + second; } function concat_loop(loop$strings, loop$accumulator) { while (true) { let strings = loop$strings; let accumulator = loop$accumulator; if (strings instanceof $Empty) { return accumulator; } else { let string = strings.head; let strings$1 = strings.tail; loop$strings = strings$1; loop$accumulator = accumulator + string; } } } /** * Creates a new `String` by joining many `String`s together. * * This function copies all the `String`s and runs in linear time. * * ## Examples * * ```gleam * concat(["never", "the", "less"]) * // -> "nevertheless" * ``` */ export function concat(strings) { return concat_loop(strings, ""); } function repeat_loop(loop$times, loop$doubling_acc, loop$acc) { while (true) { let times = loop$times; let doubling_acc = loop$doubling_acc; let acc = loop$acc; let _block; let $ = times % 2; if ($ === 0) { _block = acc; } else { _block = acc + doubling_acc; } let acc$1 = _block; let times$1 = globalThis.Math.trunc(times / 2); let $1 = times$1 <= 0; if ($1) { return acc$1; } else { loop$times = times$1; loop$doubling_acc = doubling_acc + doubling_acc; loop$acc = acc$1; } } } /** * Creates a new `String` by repeating a `String` a given number of times. * * This function runs in loglinear time. * * ## Examples * * ```gleam * repeat("ha", times: 3) * // -> "hahaha" * ``` */ export function repeat(string, times) { let $ = times <= 0; if ($) { return ""; } else { return repeat_loop(times, string, ""); } } function join_loop(loop$strings, loop$separator, loop$accumulator) { while (true) { let strings = loop$strings; let separator = loop$separator; let accumulator = loop$accumulator; if (strings instanceof $Empty) { return accumulator; } else { let string = strings.head; let strings$1 = strings.tail; loop$strings = strings$1; loop$separator = separator; loop$accumulator = (accumulator + separator) + string; } } } /** * Joins many `String`s together with a given separator. * * This function runs in linear time. * * ## Examples * * ```gleam * join(["home","evan","Desktop"], with: "/") * // -> "home/evan/Desktop" * ``` */ export function join(strings, separator) { if (strings instanceof $Empty) { return ""; } else { let first$1 = strings.head; let rest = strings.tail; return join_loop(rest, separator, first$1); } } function padding(size, pad_string) { let pad_string_length = length(pad_string); let num_pads = divideInt(size, pad_string_length); let extra = remainderInt(size, pad_string_length); return repeat(pad_string, num_pads) + slice(pad_string, 0, extra); } /** * Pads the start of a `String` until it has a given length. * * ## Examples * * ```gleam * pad_start("121", to: 5, with: ".") * // -> "..121" * ``` * * ```gleam * pad_start("121", to: 3, with: ".") * // -> "121" * ``` * * ```gleam * pad_start("121", to: 2, with: ".") * // -> "121" * ``` */ export function pad_start(string, desired_length, pad_string) { let current_length = length(string); let to_pad_length = desired_length - current_length; let $ = to_pad_length <= 0; if ($) { return string; } else { return padding(to_pad_length, pad_string) + string; } } /** * Pads the end of a `String` until it has a given length. * * ## Examples * * ```gleam * pad_end("123", to: 5, with: ".") * // -> "123.." * ``` * * ```gleam * pad_end("123", to: 3, with: ".") * // -> "123" * ``` * * ```gleam * pad_end("123", to: 2, with: ".") * // -> "123" * ``` */ export function pad_end(string, desired_length, pad_string) { let current_length = length(string); let to_pad_length = desired_length - current_length; let $ = to_pad_length <= 0; if ($) { return string; } else { return string + padding(to_pad_length, pad_string); } } /** * Removes whitespace on both sides of a `String`. * * Whitespace in this function is the set of nonbreakable whitespace * codepoints, defined as Pattern_White_Space in [Unicode Standard Annex #31][1]. * * [1]: https://unicode.org/reports/tr31/ * * ## Examples * * ```gleam * trim(" hats \n") * // -> "hats" * ``` */ export function trim(string) { let _pipe = string; let _pipe$1 = trim_start(_pipe); return trim_end(_pipe$1); } function to_graphemes_loop(loop$string, loop$acc) { while (true) { let string = loop$string; let acc = loop$acc; let $ = pop_grapheme(string); if ($ instanceof Ok) { let grapheme = $[0][0]; let rest = $[0][1]; loop$string = rest; loop$acc = listPrepend(grapheme, acc); } else { return acc; } } } /** * Creates a list of `String`s by splitting a given string on a given substring. * * ## Examples * * ```gleam * split("home/gleam/desktop/", on: "/") * // -> ["home", "gleam", "desktop", ""] * ``` */ export function split(x, substring) { if (substring === "") { return to_graphemes(x); } else { let _pipe = x; let _pipe$1 = $string_tree.from_string(_pipe); let _pipe$2 = $string_tree.split(_pipe$1, substring); return $list.map(_pipe$2, $string_tree.to_string); } } function do_to_utf_codepoints(string) { let _pipe = string; let _pipe$1 = string_to_codepoint_integer_list(_pipe); return $list.map(_pipe$1, unsafe_int_to_utf_codepoint); } /** * Converts a `String` to a `List` of `UtfCodepoint`. * * See and * for an * explanation on code points. * * ## Examples * * ```gleam * "a" |> to_utf_codepoints * // -> [UtfCodepoint(97)] * ``` * * ```gleam * // Semantically the same as: * // ["🏳", "️", "‍", "🌈"] or: * // [waving_white_flag, variant_selector_16, zero_width_joiner, rainbow] * "🏳️‍🌈" |> to_utf_codepoints * // -> [ * // UtfCodepoint(127987), * // UtfCodepoint(65039), * // UtfCodepoint(8205), * // UtfCodepoint(127752), * // ] * ``` */ export function to_utf_codepoints(string) { return do_to_utf_codepoints(string); } /** * Converts an integer to a `UtfCodepoint`. * * Returns an `Error` if the integer does not represent a valid UTF codepoint. */ export function utf_codepoint(value) { let i = value; if (i > 1_114_111) { return new Error(undefined); } else { let i$1 = value; if ((i$1 >= 55_296) && (i$1 <= 57_343)) { return new Error(undefined); } else { let i$2 = value; if (i$2 < 0) { return new Error(undefined); } else { let i$3 = value; return new Ok(unsafe_int_to_utf_codepoint(i$3)); } } } } /** * Converts a `String` into `Option(String)` where an empty `String` becomes * `None`. * * ## Examples * * ```gleam * to_option("") * // -> None * ``` * * ```gleam * to_option("hats") * // -> Some("hats") * ``` */ export function to_option(string) { if (string === "") { return new None(); } else { return new Some(string); } } /** * Returns the first grapheme cluster in a given `String` and wraps it in a * `Result(String, Nil)`. If the `String` is empty, it returns `Error(Nil)`. * Otherwise, it returns `Ok(String)`. * * ## Examples * * ```gleam * first("") * // -> Error(Nil) * ``` * * ```gleam * first("icecream") * // -> Ok("i") * ``` */ export function first(string) { let $ = pop_grapheme(string); if ($ instanceof Ok) { let first$1 = $[0][0]; return new Ok(first$1); } else { return $; } } /** * Returns the last grapheme cluster in a given `String` and wraps it in a * `Result(String, Nil)`. If the `String` is empty, it returns `Error(Nil)`. * Otherwise, it returns `Ok(String)`. * * This function traverses the full string, so it runs in linear time with the * length of the string. Avoid using this in a loop. * * ## Examples * * ```gleam * last("") * // -> Error(Nil) * ``` * * ```gleam * last("icecream") * // -> Ok("m") * ``` */ export function last(string) { let $ = pop_grapheme(string); if ($ instanceof Ok) { let $1 = $[0][1]; if ($1 === "") { let first$1 = $[0][0]; return new Ok(first$1); } else { let rest = $1; return new Ok(slice(rest, -1, 1)); } } else { return $; } } /** * Creates a new `String` with the first grapheme in the input `String` * converted to uppercase and the remaining graphemes to lowercase. * * ## Examples * * ```gleam * capitalise("mamouna") * // -> "Mamouna" * ``` */ export function capitalise(string) { let $ = pop_grapheme(string); if ($ instanceof Ok) { let first$1 = $[0][0]; let rest = $[0][1]; return append(uppercase(first$1), lowercase(rest)); } else { return ""; } } /** * Returns a `String` representation of a term in Gleam syntax. * * This may be occasionally useful for quick-and-dirty printing of values in * scripts. For error reporting and other uses prefer constructing strings by * pattern matching on the values. * * ## Limitations * * The output format of this function is not stable and could change at any * time. The output is not suitable for parsing. * * This function works using runtime reflection, so the output may not be * perfectly accurate for data structures where the runtime structure doesn't * hold enough information to determine the original syntax. For example, * tuples with an Erlang atom in the first position will be mistaken for Gleam * records. * * ## Security and safety * * There is no limit to how large the strings that this function can produce. * Be careful not to call this function with large data structures or you * could use very large amounts of memory, potentially causing runtime * problems. */ export function inspect(term) { let _pipe = term; let _pipe$1 = do_inspect(_pipe); return $string_tree.to_string(_pipe$1); } /** * Drops *n* graphemes from the start of a `String`. * * This function runs in linear time with the number of graphemes to drop. * * ## Examples * * ```gleam * drop_start(from: "The Lone Gunmen", up_to: 2) * // -> "e Lone Gunmen" * ``` */ export function drop_start(string, num_graphemes) { let $ = num_graphemes <= 0; if ($) { return string; } else { let prefix = grapheme_slice(string, 0, num_graphemes); let prefix_size = byte_size(prefix); return unsafe_byte_slice( string, prefix_size, byte_size(string) - prefix_size, ); } }