Initial commit

This commit is contained in:
Hugo Mårdbrink 2025-11-30 15:44:22 +01:00
commit a6272848f9
379 changed files with 74829 additions and 0 deletions

View file

@ -0,0 +1,723 @@
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 <https://en.wikipedia.org/wiki/Code_point> and
* <https://en.wikipedia.org/wiki/Unicode#Codespace_and_Code_Points> 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,
);
}
}