Initial commit
This commit is contained in:
commit
a6272848f9
379 changed files with 74829 additions and 0 deletions
285
build/dev/javascript/gleam_stdlib/gleam/bit_array.mjs
Normal file
285
build/dev/javascript/gleam_stdlib/gleam/bit_array.mjs
Normal file
|
|
@ -0,0 +1,285 @@
|
|||
import { Ok, toList, bitArraySlice, bitArraySliceToInt } from "../gleam.mjs";
|
||||
import * as $int from "../gleam/int.mjs";
|
||||
import * as $order from "../gleam/order.mjs";
|
||||
import * as $string from "../gleam/string.mjs";
|
||||
import {
|
||||
bit_array_from_string as from_string,
|
||||
bit_array_bit_size as bit_size,
|
||||
bit_array_byte_size as byte_size,
|
||||
bit_array_pad_to_bytes as pad_to_bytes,
|
||||
bit_array_slice as slice,
|
||||
bit_array_concat as concat,
|
||||
base64_encode,
|
||||
base64_decode as decode64,
|
||||
base16_encode,
|
||||
base16_decode,
|
||||
bit_array_to_int_and_size,
|
||||
bit_array_starts_with as starts_with,
|
||||
bit_array_to_string as to_string,
|
||||
} from "../gleam_stdlib.mjs";
|
||||
|
||||
export {
|
||||
base16_decode,
|
||||
base16_encode,
|
||||
base64_encode,
|
||||
bit_size,
|
||||
byte_size,
|
||||
concat,
|
||||
from_string,
|
||||
pad_to_bytes,
|
||||
slice,
|
||||
starts_with,
|
||||
to_string,
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates a new bit array by joining two bit arrays.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* append(to: from_string("butter"), suffix: from_string("fly"))
|
||||
* // -> from_string("butterfly")
|
||||
* ```
|
||||
*/
|
||||
export function append(first, second) {
|
||||
return concat(toList([first, second]));
|
||||
}
|
||||
|
||||
/**
|
||||
* Decodes a base 64 encoded string into a `BitArray`.
|
||||
*/
|
||||
export function base64_decode(encoded) {
|
||||
let _block;
|
||||
let $ = byte_size(from_string(encoded)) % 4;
|
||||
if ($ === 0) {
|
||||
_block = encoded;
|
||||
} else {
|
||||
let n = $;
|
||||
_block = $string.append(encoded, $string.repeat("=", 4 - n));
|
||||
}
|
||||
let padded = _block;
|
||||
return decode64(padded);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes a `BitArray` into a base 64 encoded string with URL and filename
|
||||
* safe alphabet.
|
||||
*
|
||||
* If the bit array does not contain a whole number of bytes then it is padded
|
||||
* with zero bits prior to being encoded.
|
||||
*/
|
||||
export function base64_url_encode(input, padding) {
|
||||
let _pipe = input;
|
||||
let _pipe$1 = base64_encode(_pipe, padding);
|
||||
let _pipe$2 = $string.replace(_pipe$1, "+", "-");
|
||||
return $string.replace(_pipe$2, "/", "_");
|
||||
}
|
||||
|
||||
/**
|
||||
* Decodes a base 64 encoded string with URL and filename safe alphabet into a
|
||||
* `BitArray`.
|
||||
*/
|
||||
export function base64_url_decode(encoded) {
|
||||
let _pipe = encoded;
|
||||
let _pipe$1 = $string.replace(_pipe, "-", "+");
|
||||
let _pipe$2 = $string.replace(_pipe$1, "_", "/");
|
||||
return base64_decode(_pipe$2);
|
||||
}
|
||||
|
||||
function inspect_loop(loop$input, loop$accumulator) {
|
||||
while (true) {
|
||||
let input = loop$input;
|
||||
let accumulator = loop$accumulator;
|
||||
if (input.bitSize === 0) {
|
||||
return accumulator;
|
||||
} else if (input.bitSize === 1) {
|
||||
let x = bitArraySliceToInt(input, 0, 1, true, false);
|
||||
return (accumulator + $int.to_string(x)) + ":size(1)";
|
||||
} else if (input.bitSize === 2) {
|
||||
let x = bitArraySliceToInt(input, 0, 2, true, false);
|
||||
return (accumulator + $int.to_string(x)) + ":size(2)";
|
||||
} else if (input.bitSize === 3) {
|
||||
let x = bitArraySliceToInt(input, 0, 3, true, false);
|
||||
return (accumulator + $int.to_string(x)) + ":size(3)";
|
||||
} else if (input.bitSize === 4) {
|
||||
let x = bitArraySliceToInt(input, 0, 4, true, false);
|
||||
return (accumulator + $int.to_string(x)) + ":size(4)";
|
||||
} else if (input.bitSize === 5) {
|
||||
let x = bitArraySliceToInt(input, 0, 5, true, false);
|
||||
return (accumulator + $int.to_string(x)) + ":size(5)";
|
||||
} else if (input.bitSize === 6) {
|
||||
let x = bitArraySliceToInt(input, 0, 6, true, false);
|
||||
return (accumulator + $int.to_string(x)) + ":size(6)";
|
||||
} else if (input.bitSize === 7) {
|
||||
let x = bitArraySliceToInt(input, 0, 7, true, false);
|
||||
return (accumulator + $int.to_string(x)) + ":size(7)";
|
||||
} else if (input.bitSize >= 8) {
|
||||
let x = input.byteAt(0);
|
||||
let rest = bitArraySlice(input, 8);
|
||||
let _block;
|
||||
if (rest.bitSize === 0) {
|
||||
_block = "";
|
||||
} else {
|
||||
_block = ", ";
|
||||
}
|
||||
let suffix = _block;
|
||||
let accumulator$1 = (accumulator + $int.to_string(x)) + suffix;
|
||||
loop$input = rest;
|
||||
loop$accumulator = accumulator$1;
|
||||
} else {
|
||||
return accumulator;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a bit array to a string containing the decimal value of each byte.
|
||||
*
|
||||
* Use this over `string.inspect` when you have a bit array you want printed
|
||||
* in the array syntax even if it is valid UTF-8.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* inspect(<<0, 20, 0x20, 255>>)
|
||||
* // -> "<<0, 20, 32, 255>>"
|
||||
*
|
||||
* inspect(<<100, 5:3>>)
|
||||
* // -> "<<100, 5:size(3)>>"
|
||||
* ```
|
||||
*/
|
||||
export function inspect(input) {
|
||||
return inspect_loop(input, "<<") + ">>";
|
||||
}
|
||||
|
||||
/**
|
||||
* Compare two bit arrays as sequences of bytes.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* compare(<<1>>, <<2>>)
|
||||
* // -> Lt
|
||||
*
|
||||
* compare(<<"AB":utf8>>, <<"AA":utf8>>)
|
||||
* // -> Gt
|
||||
*
|
||||
* compare(<<1, 2:size(2)>>, with: <<1, 2:size(2)>>)
|
||||
* // -> Eq
|
||||
* ```
|
||||
*/
|
||||
export function compare(loop$a, loop$b) {
|
||||
while (true) {
|
||||
let a = loop$a;
|
||||
let b = loop$b;
|
||||
if (a.bitSize >= 8) {
|
||||
if (b.bitSize >= 8) {
|
||||
let first_byte = a.byteAt(0);
|
||||
let first_rest = bitArraySlice(a, 8);
|
||||
let second_byte = b.byteAt(0);
|
||||
let second_rest = bitArraySlice(b, 8);
|
||||
let f = first_byte;
|
||||
let s = second_byte;
|
||||
if (f > s) {
|
||||
return new $order.Gt();
|
||||
} else {
|
||||
let f$1 = first_byte;
|
||||
let s$1 = second_byte;
|
||||
if (f$1 < s$1) {
|
||||
return new $order.Lt();
|
||||
} else {
|
||||
loop$a = first_rest;
|
||||
loop$b = second_rest;
|
||||
}
|
||||
}
|
||||
} else if (b.bitSize === 0) {
|
||||
return new $order.Gt();
|
||||
} else {
|
||||
let first = a;
|
||||
let second = b;
|
||||
let $ = bit_array_to_int_and_size(first);
|
||||
let $1 = bit_array_to_int_and_size(second);
|
||||
let a$1 = $[0];
|
||||
let b$1 = $1[0];
|
||||
if (a$1 > b$1) {
|
||||
return new $order.Gt();
|
||||
} else {
|
||||
let a$2 = $[0];
|
||||
let b$2 = $1[0];
|
||||
if (a$2 < b$2) {
|
||||
return new $order.Lt();
|
||||
} else {
|
||||
let size_a = $[1];
|
||||
let size_b = $1[1];
|
||||
if (size_a > size_b) {
|
||||
return new $order.Gt();
|
||||
} else {
|
||||
let size_a$1 = $[1];
|
||||
let size_b$1 = $1[1];
|
||||
if (size_a$1 < size_b$1) {
|
||||
return new $order.Lt();
|
||||
} else {
|
||||
return new $order.Eq();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (b.bitSize === 0) {
|
||||
if (a.bitSize === 0) {
|
||||
return new $order.Eq();
|
||||
} else {
|
||||
return new $order.Gt();
|
||||
}
|
||||
} else if (a.bitSize === 0) {
|
||||
return new $order.Lt();
|
||||
} else {
|
||||
let first = a;
|
||||
let second = b;
|
||||
let $ = bit_array_to_int_and_size(first);
|
||||
let $1 = bit_array_to_int_and_size(second);
|
||||
let a$1 = $[0];
|
||||
let b$1 = $1[0];
|
||||
if (a$1 > b$1) {
|
||||
return new $order.Gt();
|
||||
} else {
|
||||
let a$2 = $[0];
|
||||
let b$2 = $1[0];
|
||||
if (a$2 < b$2) {
|
||||
return new $order.Lt();
|
||||
} else {
|
||||
let size_a = $[1];
|
||||
let size_b = $1[1];
|
||||
if (size_a > size_b) {
|
||||
return new $order.Gt();
|
||||
} else {
|
||||
let size_a$1 = $[1];
|
||||
let size_b$1 = $1[1];
|
||||
if (size_a$1 < size_b$1) {
|
||||
return new $order.Lt();
|
||||
} else {
|
||||
return new $order.Eq();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests to see whether a bit array is valid UTF-8.
|
||||
*/
|
||||
export function is_utf8(bits) {
|
||||
return is_utf8_loop(bits);
|
||||
}
|
||||
|
||||
function is_utf8_loop(bits) {
|
||||
let $ = to_string(bits);
|
||||
if ($ instanceof Ok) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
313
build/dev/javascript/gleam_stdlib/gleam/bool.mjs
Normal file
313
build/dev/javascript/gleam_stdlib/gleam/bool.mjs
Normal file
|
|
@ -0,0 +1,313 @@
|
|||
/**
|
||||
* Returns the and of two bools, but it evaluates both arguments.
|
||||
*
|
||||
* It's the function equivalent of the `&&` operator.
|
||||
* This function is useful in higher order functions or pipes.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* and(True, True)
|
||||
* // -> True
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* and(False, True)
|
||||
* // -> False
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* False |> and(True)
|
||||
* // -> False
|
||||
* ```
|
||||
*/
|
||||
export function and(a, b) {
|
||||
return a && b;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the or of two bools, but it evaluates both arguments.
|
||||
*
|
||||
* It's the function equivalent of the `||` operator.
|
||||
* This function is useful in higher order functions or pipes.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* or(True, True)
|
||||
* // -> True
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* or(False, True)
|
||||
* // -> True
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* False |> or(True)
|
||||
* // -> True
|
||||
* ```
|
||||
*/
|
||||
export function or(a, b) {
|
||||
return a || b;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the opposite bool value.
|
||||
*
|
||||
* This is the same as the `!` or `not` operators in some other languages.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* negate(True)
|
||||
* // -> False
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* negate(False)
|
||||
* // -> True
|
||||
* ```
|
||||
*/
|
||||
export function negate(bool) {
|
||||
return !bool;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the nor of two bools.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* nor(False, False)
|
||||
* // -> True
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* nor(False, True)
|
||||
* // -> False
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* nor(True, False)
|
||||
* // -> False
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* nor(True, True)
|
||||
* // -> False
|
||||
* ```
|
||||
*/
|
||||
export function nor(a, b) {
|
||||
return !(a || b);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the nand of two bools.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* nand(False, False)
|
||||
* // -> True
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* nand(False, True)
|
||||
* // -> True
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* nand(True, False)
|
||||
* // -> True
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* nand(True, True)
|
||||
* // -> False
|
||||
* ```
|
||||
*/
|
||||
export function nand(a, b) {
|
||||
return !(a && b);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the exclusive or of two bools.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* exclusive_or(False, False)
|
||||
* // -> False
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* exclusive_or(False, True)
|
||||
* // -> True
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* exclusive_or(True, False)
|
||||
* // -> True
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* exclusive_or(True, True)
|
||||
* // -> False
|
||||
* ```
|
||||
*/
|
||||
export function exclusive_or(a, b) {
|
||||
return a !== b;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the exclusive nor of two bools.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* exclusive_nor(False, False)
|
||||
* // -> True
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* exclusive_nor(False, True)
|
||||
* // -> False
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* exclusive_nor(True, False)
|
||||
* // -> False
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* exclusive_nor(True, True)
|
||||
* // -> True
|
||||
* ```
|
||||
*/
|
||||
export function exclusive_nor(a, b) {
|
||||
return a === b;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string representation of the given bool.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* to_string(True)
|
||||
* // -> "True"
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* to_string(False)
|
||||
* // -> "False"
|
||||
* ```
|
||||
*/
|
||||
export function to_string(bool) {
|
||||
if (bool) {
|
||||
return "True";
|
||||
} else {
|
||||
return "False";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Run a callback function if the given bool is `False`, otherwise return a
|
||||
* default value.
|
||||
*
|
||||
* With a `use` expression this function can simulate the early-return pattern
|
||||
* found in some other programming languages.
|
||||
*
|
||||
* In a procedural language:
|
||||
*
|
||||
* ```js
|
||||
* if (predicate) return value;
|
||||
* // ...
|
||||
* ```
|
||||
*
|
||||
* In Gleam with a `use` expression:
|
||||
*
|
||||
* ```gleam
|
||||
* use <- guard(when: predicate, return: value)
|
||||
* // ...
|
||||
* ```
|
||||
*
|
||||
* Like everything in Gleam `use` is an expression, so it short circuits the
|
||||
* current block, not the entire function. As a result you can assign the value
|
||||
* to a variable:
|
||||
*
|
||||
* ```gleam
|
||||
* let x = {
|
||||
* use <- guard(when: predicate, return: value)
|
||||
* // ...
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* Note that unlike in procedural languages the `return` value is evaluated
|
||||
* even when the predicate is `False`, so it is advisable not to perform
|
||||
* expensive computation nor side-effects there.
|
||||
*
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* let name = ""
|
||||
* use <- guard(when: name == "", return: "Welcome!")
|
||||
* "Hello, " <> name
|
||||
* // -> "Welcome!"
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* let name = "Kamaka"
|
||||
* use <- guard(when: name == "", return: "Welcome!")
|
||||
* "Hello, " <> name
|
||||
* // -> "Hello, Kamaka"
|
||||
* ```
|
||||
*/
|
||||
export function guard(requirement, consequence, alternative) {
|
||||
if (requirement) {
|
||||
return consequence;
|
||||
} else {
|
||||
return alternative();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs a callback function if the given bool is `True`, otherwise runs an
|
||||
* alternative callback function.
|
||||
*
|
||||
* Useful when further computation should be delayed regardless of the given
|
||||
* bool's value.
|
||||
*
|
||||
* See [`guard`](#guard) for more info.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* let name = "Kamaka"
|
||||
* let inquiry = fn() { "How may we address you?" }
|
||||
* use <- lazy_guard(when: name == "", return: inquiry)
|
||||
* "Hello, " <> name
|
||||
* // -> "Hello, Kamaka"
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* import gleam/int
|
||||
*
|
||||
* let name = ""
|
||||
* let greeting = fn() { "Hello, " <> name }
|
||||
* use <- lazy_guard(when: name == "", otherwise: greeting)
|
||||
* let number = int.random(99)
|
||||
* let name = "User " <> int.to_string(number)
|
||||
* "Welcome, " <> name
|
||||
* // -> "Welcome, User 54"
|
||||
* ```
|
||||
*/
|
||||
export function lazy_guard(requirement, consequence, alternative) {
|
||||
if (requirement) {
|
||||
return consequence();
|
||||
} else {
|
||||
return alternative();
|
||||
}
|
||||
}
|
||||
225
build/dev/javascript/gleam_stdlib/gleam/bytes_tree.mjs
Normal file
225
build/dev/javascript/gleam_stdlib/gleam/bytes_tree.mjs
Normal file
|
|
@ -0,0 +1,225 @@
|
|||
import {
|
||||
toList,
|
||||
Empty as $Empty,
|
||||
prepend as listPrepend,
|
||||
CustomType as $CustomType,
|
||||
} from "../gleam.mjs";
|
||||
import * as $bit_array from "../gleam/bit_array.mjs";
|
||||
import * as $list from "../gleam/list.mjs";
|
||||
import * as $string_tree from "../gleam/string_tree.mjs";
|
||||
|
||||
class Bytes extends $CustomType {
|
||||
constructor($0) {
|
||||
super();
|
||||
this[0] = $0;
|
||||
}
|
||||
}
|
||||
|
||||
class Text extends $CustomType {
|
||||
constructor($0) {
|
||||
super();
|
||||
this[0] = $0;
|
||||
}
|
||||
}
|
||||
|
||||
class Many extends $CustomType {
|
||||
constructor($0) {
|
||||
super();
|
||||
this[0] = $0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends a bytes tree onto the end of another.
|
||||
*
|
||||
* Runs in constant time.
|
||||
*/
|
||||
export function append_tree(first, second) {
|
||||
if (second instanceof Bytes) {
|
||||
return new Many(toList([first, second]));
|
||||
} else if (second instanceof Text) {
|
||||
return new Many(toList([first, second]));
|
||||
} else {
|
||||
let trees = second[0];
|
||||
return new Many(listPrepend(first, trees));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepends a bytes tree onto the start of another.
|
||||
*
|
||||
* Runs in constant time.
|
||||
*/
|
||||
export function prepend_tree(second, first) {
|
||||
return append_tree(first, second);
|
||||
}
|
||||
|
||||
/**
|
||||
* Joins a list of bytes trees into a single one.
|
||||
*
|
||||
* Runs in constant time.
|
||||
*/
|
||||
export function concat(trees) {
|
||||
return new Many(trees);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an empty `BytesTree`. Useful as the start of a pipe chaining many
|
||||
* trees together.
|
||||
*/
|
||||
export function new$() {
|
||||
return concat(toList([]));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new bytes tree from a string.
|
||||
*
|
||||
* Runs in constant time when running on Erlang.
|
||||
* Runs in linear time otherwise.
|
||||
*/
|
||||
export function from_string(string) {
|
||||
return new Text($string_tree.from_string(string));
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepends a string onto the start of a bytes tree.
|
||||
*
|
||||
* Runs in constant time when running on Erlang.
|
||||
* Runs in linear time with the length of the string otherwise.
|
||||
*/
|
||||
export function prepend_string(second, first) {
|
||||
return append_tree(from_string(first), second);
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends a string onto the end of a bytes tree.
|
||||
*
|
||||
* Runs in constant time when running on Erlang.
|
||||
* Runs in linear time with the length of the string otherwise.
|
||||
*/
|
||||
export function append_string(first, second) {
|
||||
return append_tree(first, from_string(second));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new bytes tree from a string tree.
|
||||
*
|
||||
* Runs in constant time when running on Erlang.
|
||||
* Runs in linear time otherwise.
|
||||
*/
|
||||
export function from_string_tree(tree) {
|
||||
return new Text(tree);
|
||||
}
|
||||
|
||||
function wrap_list(bits) {
|
||||
return new Bytes(bits);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new bytes tree from a bit array.
|
||||
*
|
||||
* Runs in constant time.
|
||||
*/
|
||||
export function from_bit_array(bits) {
|
||||
let _pipe = bits;
|
||||
let _pipe$1 = $bit_array.pad_to_bytes(_pipe);
|
||||
return wrap_list(_pipe$1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepends a bit array to the start of a bytes tree.
|
||||
*
|
||||
* Runs in constant time.
|
||||
*/
|
||||
export function prepend(second, first) {
|
||||
return append_tree(from_bit_array(first), second);
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends a bit array to the end of a bytes tree.
|
||||
*
|
||||
* Runs in constant time.
|
||||
*/
|
||||
export function append(first, second) {
|
||||
return append_tree(first, from_bit_array(second));
|
||||
}
|
||||
|
||||
/**
|
||||
* Joins a list of bit arrays into a single bytes tree.
|
||||
*
|
||||
* Runs in constant time.
|
||||
*/
|
||||
export function concat_bit_arrays(bits) {
|
||||
let _pipe = bits;
|
||||
let _pipe$1 = $list.map(_pipe, from_bit_array);
|
||||
return concat(_pipe$1);
|
||||
}
|
||||
|
||||
function to_list(loop$stack, loop$acc) {
|
||||
while (true) {
|
||||
let stack = loop$stack;
|
||||
let acc = loop$acc;
|
||||
if (stack instanceof $Empty) {
|
||||
return acc;
|
||||
} else {
|
||||
let $ = stack.head;
|
||||
if ($ instanceof $Empty) {
|
||||
let remaining_stack = stack.tail;
|
||||
loop$stack = remaining_stack;
|
||||
loop$acc = acc;
|
||||
} else {
|
||||
let $1 = $.head;
|
||||
if ($1 instanceof Bytes) {
|
||||
let remaining_stack = stack.tail;
|
||||
let rest = $.tail;
|
||||
let bits = $1[0];
|
||||
loop$stack = listPrepend(rest, remaining_stack);
|
||||
loop$acc = listPrepend(bits, acc);
|
||||
} else if ($1 instanceof Text) {
|
||||
let remaining_stack = stack.tail;
|
||||
let rest = $.tail;
|
||||
let tree = $1[0];
|
||||
let bits = $bit_array.from_string($string_tree.to_string(tree));
|
||||
loop$stack = listPrepend(rest, remaining_stack);
|
||||
loop$acc = listPrepend(bits, acc);
|
||||
} else {
|
||||
let remaining_stack = stack.tail;
|
||||
let rest = $.tail;
|
||||
let trees = $1[0];
|
||||
loop$stack = listPrepend(trees, listPrepend(rest, remaining_stack));
|
||||
loop$acc = acc;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Turns a bytes tree into a bit array.
|
||||
*
|
||||
* Runs in linear time.
|
||||
*
|
||||
* When running on Erlang this function is implemented natively by the
|
||||
* virtual machine and is highly optimised.
|
||||
*/
|
||||
export function to_bit_array(tree) {
|
||||
let _pipe = toList([toList([tree])]);
|
||||
let _pipe$1 = to_list(_pipe, toList([]));
|
||||
let _pipe$2 = $list.reverse(_pipe$1);
|
||||
return $bit_array.concat(_pipe$2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the size of the bytes tree's content in bytes.
|
||||
*
|
||||
* Runs in linear time.
|
||||
*/
|
||||
export function byte_size(tree) {
|
||||
let _pipe = toList([toList([tree])]);
|
||||
let _pipe$1 = to_list(_pipe, toList([]));
|
||||
return $list.fold(
|
||||
_pipe$1,
|
||||
0,
|
||||
(acc, bits) => { return $bit_array.byte_size(bits) + acc; },
|
||||
);
|
||||
}
|
||||
534
build/dev/javascript/gleam_stdlib/gleam/dict.mjs
Normal file
534
build/dev/javascript/gleam_stdlib/gleam/dict.mjs
Normal file
|
|
@ -0,0 +1,534 @@
|
|||
import { Ok, Error, toList, Empty as $Empty, prepend as listPrepend, isEqual } from "../gleam.mjs";
|
||||
import * as $option from "../gleam/option.mjs";
|
||||
import {
|
||||
map_size as size,
|
||||
map_to_list as to_list,
|
||||
new_map as new$,
|
||||
map_get as get,
|
||||
map_insert as do_insert,
|
||||
map_remove as do_delete,
|
||||
} from "../gleam_stdlib.mjs";
|
||||
|
||||
export { get, new$, size, to_list };
|
||||
|
||||
/**
|
||||
* Determines whether or not the dict is empty.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* new() |> is_empty
|
||||
* // -> True
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* new() |> insert("b", 1) |> is_empty
|
||||
* // -> False
|
||||
* ```
|
||||
*/
|
||||
export function is_empty(dict) {
|
||||
return size(dict) === 0;
|
||||
}
|
||||
|
||||
function do_has_key(key, dict) {
|
||||
return !isEqual(get(dict, key), new Error(undefined));
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether or not a value present in the dict for a given key.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* new() |> insert("a", 0) |> has_key("a")
|
||||
* // -> True
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* new() |> insert("a", 0) |> has_key("b")
|
||||
* // -> False
|
||||
* ```
|
||||
*/
|
||||
export function has_key(dict, key) {
|
||||
return do_has_key(key, dict);
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts a value into the dict with the given key.
|
||||
*
|
||||
* If the dict already has a value for the given key then the value is
|
||||
* replaced with the new value.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* new() |> insert("a", 0)
|
||||
* // -> from_list([#("a", 0)])
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* new() |> insert("a", 0) |> insert("a", 5)
|
||||
* // -> from_list([#("a", 5)])
|
||||
* ```
|
||||
*/
|
||||
export function insert(dict, key, value) {
|
||||
return do_insert(key, value, dict);
|
||||
}
|
||||
|
||||
function from_list_loop(loop$list, loop$initial) {
|
||||
while (true) {
|
||||
let list = loop$list;
|
||||
let initial = loop$initial;
|
||||
if (list instanceof $Empty) {
|
||||
return initial;
|
||||
} else {
|
||||
let rest = list.tail;
|
||||
let key = list.head[0];
|
||||
let value = list.head[1];
|
||||
loop$list = rest;
|
||||
loop$initial = insert(initial, key, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a list of 2-element tuples `#(key, value)` to a dict.
|
||||
*
|
||||
* If two tuples have the same key the last one in the list will be the one
|
||||
* that is present in the dict.
|
||||
*/
|
||||
export function from_list(list) {
|
||||
return from_list_loop(list, new$());
|
||||
}
|
||||
|
||||
function reverse_and_concat(loop$remaining, loop$accumulator) {
|
||||
while (true) {
|
||||
let remaining = loop$remaining;
|
||||
let accumulator = loop$accumulator;
|
||||
if (remaining instanceof $Empty) {
|
||||
return accumulator;
|
||||
} else {
|
||||
let first = remaining.head;
|
||||
let rest = remaining.tail;
|
||||
loop$remaining = rest;
|
||||
loop$accumulator = listPrepend(first, accumulator);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function do_keys_loop(loop$list, loop$acc) {
|
||||
while (true) {
|
||||
let list = loop$list;
|
||||
let acc = loop$acc;
|
||||
if (list instanceof $Empty) {
|
||||
return reverse_and_concat(acc, toList([]));
|
||||
} else {
|
||||
let rest = list.tail;
|
||||
let key = list.head[0];
|
||||
loop$list = rest;
|
||||
loop$acc = listPrepend(key, acc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a list of all keys in a given dict.
|
||||
*
|
||||
* Dicts are not ordered so the keys are not returned in any specific order. Do
|
||||
* not write code that relies on the order keys are returned by this function
|
||||
* as it may change in later versions of Gleam or Erlang.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* from_list([#("a", 0), #("b", 1)]) |> keys
|
||||
* // -> ["a", "b"]
|
||||
* ```
|
||||
*/
|
||||
export function keys(dict) {
|
||||
return do_keys_loop(to_list(dict), toList([]));
|
||||
}
|
||||
|
||||
function do_values_loop(loop$list, loop$acc) {
|
||||
while (true) {
|
||||
let list = loop$list;
|
||||
let acc = loop$acc;
|
||||
if (list instanceof $Empty) {
|
||||
return reverse_and_concat(acc, toList([]));
|
||||
} else {
|
||||
let rest = list.tail;
|
||||
let value = list.head[1];
|
||||
loop$list = rest;
|
||||
loop$acc = listPrepend(value, acc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a list of all values in a given dict.
|
||||
*
|
||||
* Dicts are not ordered so the values are not returned in any specific order. Do
|
||||
* not write code that relies on the order values are returned by this function
|
||||
* as it may change in later versions of Gleam or Erlang.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* from_list([#("a", 0), #("b", 1)]) |> values
|
||||
* // -> [0, 1]
|
||||
* ```
|
||||
*/
|
||||
export function values(dict) {
|
||||
let list_of_pairs = to_list(dict);
|
||||
return do_values_loop(list_of_pairs, toList([]));
|
||||
}
|
||||
|
||||
function do_take_loop(loop$dict, loop$desired_keys, loop$acc) {
|
||||
while (true) {
|
||||
let dict = loop$dict;
|
||||
let desired_keys = loop$desired_keys;
|
||||
let acc = loop$acc;
|
||||
let insert$1 = (taken, key) => {
|
||||
let $ = get(dict, key);
|
||||
if ($ instanceof Ok) {
|
||||
let value = $[0];
|
||||
return insert(taken, key, value);
|
||||
} else {
|
||||
return taken;
|
||||
}
|
||||
};
|
||||
if (desired_keys instanceof $Empty) {
|
||||
return acc;
|
||||
} else {
|
||||
let first = desired_keys.head;
|
||||
let rest = desired_keys.tail;
|
||||
loop$dict = dict;
|
||||
loop$desired_keys = rest;
|
||||
loop$acc = insert$1(acc, first);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function do_take(desired_keys, dict) {
|
||||
return do_take_loop(dict, desired_keys, new$());
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new dict from a given dict, only including any entries for which the
|
||||
* keys are in a given list.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* from_list([#("a", 0), #("b", 1)])
|
||||
* |> take(["b"])
|
||||
* // -> from_list([#("b", 1)])
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* from_list([#("a", 0), #("b", 1)])
|
||||
* |> take(["a", "b", "c"])
|
||||
* // -> from_list([#("a", 0), #("b", 1)])
|
||||
* ```
|
||||
*/
|
||||
export function take(dict, desired_keys) {
|
||||
return do_take(desired_keys, dict);
|
||||
}
|
||||
|
||||
function insert_pair(dict, pair) {
|
||||
return insert(dict, pair[0], pair[1]);
|
||||
}
|
||||
|
||||
function fold_inserts(loop$new_entries, loop$dict) {
|
||||
while (true) {
|
||||
let new_entries = loop$new_entries;
|
||||
let dict = loop$dict;
|
||||
if (new_entries instanceof $Empty) {
|
||||
return dict;
|
||||
} else {
|
||||
let first = new_entries.head;
|
||||
let rest = new_entries.tail;
|
||||
loop$new_entries = rest;
|
||||
loop$dict = insert_pair(dict, first);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new dict from a pair of given dicts by combining their entries.
|
||||
*
|
||||
* If there are entries with the same keys in both dicts the entry from the
|
||||
* second dict takes precedence.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* let a = from_list([#("a", 0), #("b", 1)])
|
||||
* let b = from_list([#("b", 2), #("c", 3)])
|
||||
* merge(a, b)
|
||||
* // -> from_list([#("a", 0), #("b", 2), #("c", 3)])
|
||||
* ```
|
||||
*/
|
||||
export function merge(dict, new_entries) {
|
||||
let _pipe = new_entries;
|
||||
let _pipe$1 = to_list(_pipe);
|
||||
return fold_inserts(_pipe$1, dict);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new dict from a given dict with all the same entries except for the
|
||||
* one with a given key, if it exists.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* from_list([#("a", 0), #("b", 1)]) |> delete("a")
|
||||
* // -> from_list([#("b", 1)])
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* from_list([#("a", 0), #("b", 1)]) |> delete("c")
|
||||
* // -> from_list([#("a", 0), #("b", 1)])
|
||||
* ```
|
||||
*/
|
||||
export function delete$(dict, key) {
|
||||
return do_delete(key, dict);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new dict from a given dict with all the same entries except any with
|
||||
* keys found in a given list.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* from_list([#("a", 0), #("b", 1)]) |> drop(["a"])
|
||||
* // -> from_list([#("b", 1)])
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* from_list([#("a", 0), #("b", 1)]) |> drop(["c"])
|
||||
* // -> from_list([#("a", 0), #("b", 1)])
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* from_list([#("a", 0), #("b", 1)]) |> drop(["a", "b", "c"])
|
||||
* // -> from_list([])
|
||||
* ```
|
||||
*/
|
||||
export function drop(loop$dict, loop$disallowed_keys) {
|
||||
while (true) {
|
||||
let dict = loop$dict;
|
||||
let disallowed_keys = loop$disallowed_keys;
|
||||
if (disallowed_keys instanceof $Empty) {
|
||||
return dict;
|
||||
} else {
|
||||
let first = disallowed_keys.head;
|
||||
let rest = disallowed_keys.tail;
|
||||
loop$dict = delete$(dict, first);
|
||||
loop$disallowed_keys = rest;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new dict with one entry inserted or updated using a given function.
|
||||
*
|
||||
* If there was not an entry in the dict for the given key then the function
|
||||
* gets `None` as its argument, otherwise it gets `Some(value)`.
|
||||
*
|
||||
* ## Example
|
||||
*
|
||||
* ```gleam
|
||||
* let dict = from_list([#("a", 0)])
|
||||
* let increment = fn(x) {
|
||||
* case x {
|
||||
* Some(i) -> i + 1
|
||||
* None -> 0
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* upsert(dict, "a", increment)
|
||||
* // -> from_list([#("a", 1)])
|
||||
*
|
||||
* upsert(dict, "b", increment)
|
||||
* // -> from_list([#("a", 0), #("b", 0)])
|
||||
* ```
|
||||
*/
|
||||
export function upsert(dict, key, fun) {
|
||||
let $ = get(dict, key);
|
||||
if ($ instanceof Ok) {
|
||||
let value = $[0];
|
||||
return insert(dict, key, fun(new $option.Some(value)));
|
||||
} else {
|
||||
return insert(dict, key, fun(new $option.None()));
|
||||
}
|
||||
}
|
||||
|
||||
function fold_loop(loop$list, loop$initial, loop$fun) {
|
||||
while (true) {
|
||||
let list = loop$list;
|
||||
let initial = loop$initial;
|
||||
let fun = loop$fun;
|
||||
if (list instanceof $Empty) {
|
||||
return initial;
|
||||
} else {
|
||||
let rest = list.tail;
|
||||
let k = list.head[0];
|
||||
let v = list.head[1];
|
||||
loop$list = rest;
|
||||
loop$initial = fun(initial, k, v);
|
||||
loop$fun = fun;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Combines all entries into a single value by calling a given function on each
|
||||
* one.
|
||||
*
|
||||
* Dicts are not ordered so the values are not returned in any specific order. Do
|
||||
* not write code that relies on the order entries are used by this function
|
||||
* as it may change in later versions of Gleam or Erlang.
|
||||
*
|
||||
* # Examples
|
||||
*
|
||||
* ```gleam
|
||||
* let dict = from_list([#("a", 1), #("b", 3), #("c", 9)])
|
||||
* fold(dict, 0, fn(accumulator, key, value) { accumulator + value })
|
||||
* // -> 13
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* import gleam/string
|
||||
*
|
||||
* let dict = from_list([#("a", 1), #("b", 3), #("c", 9)])
|
||||
* fold(dict, "", fn(accumulator, key, value) {
|
||||
* string.append(accumulator, key)
|
||||
* })
|
||||
* // -> "abc"
|
||||
* ```
|
||||
*/
|
||||
export function fold(dict, initial, fun) {
|
||||
return fold_loop(to_list(dict), initial, fun);
|
||||
}
|
||||
|
||||
function do_map_values(f, dict) {
|
||||
let f$1 = (dict, k, v) => { return insert(dict, k, f(k, v)); };
|
||||
return fold(dict, new$(), f$1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates all values in a given dict by calling a given function on each key
|
||||
* and value.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* from_list([#(3, 3), #(2, 4)])
|
||||
* |> map_values(fn(key, value) { key * value })
|
||||
* // -> from_list([#(3, 9), #(2, 8)])
|
||||
* ```
|
||||
*/
|
||||
export function map_values(dict, fun) {
|
||||
return do_map_values(fun, dict);
|
||||
}
|
||||
|
||||
function do_filter(f, dict) {
|
||||
let insert$1 = (dict, k, v) => {
|
||||
let $ = f(k, v);
|
||||
if ($) {
|
||||
return insert(dict, k, v);
|
||||
} else {
|
||||
return dict;
|
||||
}
|
||||
};
|
||||
return fold(dict, new$(), insert$1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new dict from a given dict, minus any entries that a given function
|
||||
* returns `False` for.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* from_list([#("a", 0), #("b", 1)])
|
||||
* |> filter(fn(key, value) { value != 0 })
|
||||
* // -> from_list([#("b", 1)])
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* from_list([#("a", 0), #("b", 1)])
|
||||
* |> filter(fn(key, value) { True })
|
||||
* // -> from_list([#("a", 0), #("b", 1)])
|
||||
* ```
|
||||
*/
|
||||
export function filter(dict, predicate) {
|
||||
return do_filter(predicate, dict);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls a function for each key and value in a dict, discarding the return
|
||||
* value.
|
||||
*
|
||||
* Useful for producing a side effect for every item of a dict.
|
||||
*
|
||||
* ```gleam
|
||||
* import gleam/io
|
||||
*
|
||||
* let dict = from_list([#("a", "apple"), #("b", "banana"), #("c", "cherry")])
|
||||
*
|
||||
* each(dict, fn(k, v) {
|
||||
* io.println(key <> " => " <> value)
|
||||
* })
|
||||
* // -> Nil
|
||||
* // a => apple
|
||||
* // b => banana
|
||||
* // c => cherry
|
||||
* ```
|
||||
*
|
||||
* The order of elements in the iteration is an implementation detail that
|
||||
* should not be relied upon.
|
||||
*/
|
||||
export function each(dict, fun) {
|
||||
return fold(
|
||||
dict,
|
||||
undefined,
|
||||
(nil, k, v) => {
|
||||
fun(k, v);
|
||||
return nil;
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new dict from a pair of given dicts by combining their entries.
|
||||
*
|
||||
* If there are entries with the same keys in both dicts the given function is
|
||||
* used to determine the new value to use in the resulting dict.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* let a = from_list([#("a", 0), #("b", 1)])
|
||||
* let b = from_list([#("a", 2), #("c", 3)])
|
||||
* combine(a, b, fn(one, other) { one + other })
|
||||
* // -> from_list([#("a", 2), #("b", 1), #("c", 3)])
|
||||
* ```
|
||||
*/
|
||||
export function combine(dict, other, fun) {
|
||||
return fold(
|
||||
dict,
|
||||
other,
|
||||
(acc, key, value) => {
|
||||
let $ = get(acc, key);
|
||||
if ($ instanceof Ok) {
|
||||
let other_value = $[0];
|
||||
return insert(acc, key, fun(value, other_value));
|
||||
} else {
|
||||
return insert(acc, key, value);
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
35
build/dev/javascript/gleam_stdlib/gleam/dynamic.mjs
Normal file
35
build/dev/javascript/gleam_stdlib/gleam/dynamic.mjs
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
import * as $dict from "../gleam/dict.mjs";
|
||||
import {
|
||||
classify_dynamic as classify,
|
||||
identity as bool,
|
||||
identity as string,
|
||||
identity as float,
|
||||
identity as int,
|
||||
identity as bit_array,
|
||||
identity as list,
|
||||
list_to_array as array,
|
||||
identity as cast,
|
||||
} from "../gleam_stdlib.mjs";
|
||||
|
||||
export { array, bit_array, bool, classify, float, int, list, string };
|
||||
|
||||
/**
|
||||
* Create a dynamic value made an unordered series of keys and values, where
|
||||
* the keys are unique.
|
||||
*
|
||||
* On Erlang this will be a map, on JavaScript this will be a Gleam dict
|
||||
* object.
|
||||
*/
|
||||
export function properties(entries) {
|
||||
return cast($dict.from_list(entries));
|
||||
}
|
||||
|
||||
/**
|
||||
* A dynamic value representing nothing.
|
||||
*
|
||||
* On Erlang this will be the atom `nil`, on JavaScript this will be
|
||||
* `undefined`.
|
||||
*/
|
||||
export function nil() {
|
||||
return cast(undefined);
|
||||
}
|
||||
947
build/dev/javascript/gleam_stdlib/gleam/dynamic/decode.mjs
Normal file
947
build/dev/javascript/gleam_stdlib/gleam/dynamic/decode.mjs
Normal file
|
|
@ -0,0 +1,947 @@
|
|||
import {
|
||||
Ok,
|
||||
Error,
|
||||
toList,
|
||||
Empty as $Empty,
|
||||
prepend as listPrepend,
|
||||
CustomType as $CustomType,
|
||||
isEqual,
|
||||
} from "../../gleam.mjs";
|
||||
import * as $bit_array from "../../gleam/bit_array.mjs";
|
||||
import * as $dict from "../../gleam/dict.mjs";
|
||||
import * as $dynamic from "../../gleam/dynamic.mjs";
|
||||
import * as $int from "../../gleam/int.mjs";
|
||||
import * as $list from "../../gleam/list.mjs";
|
||||
import * as $option from "../../gleam/option.mjs";
|
||||
import { None, Some } from "../../gleam/option.mjs";
|
||||
import {
|
||||
index as bare_index,
|
||||
int as dynamic_int,
|
||||
float as dynamic_float,
|
||||
bit_array as dynamic_bit_array,
|
||||
list as decode_list,
|
||||
dict as decode_dict,
|
||||
identity as cast,
|
||||
is_null,
|
||||
string as dynamic_string,
|
||||
} from "../../gleam_stdlib.mjs";
|
||||
|
||||
export class DecodeError extends $CustomType {
|
||||
constructor(expected, found, path) {
|
||||
super();
|
||||
this.expected = expected;
|
||||
this.found = found;
|
||||
this.path = path;
|
||||
}
|
||||
}
|
||||
export const DecodeError$DecodeError = (expected, found, path) =>
|
||||
new DecodeError(expected, found, path);
|
||||
export const DecodeError$isDecodeError = (value) =>
|
||||
value instanceof DecodeError;
|
||||
export const DecodeError$DecodeError$expected = (value) => value.expected;
|
||||
export const DecodeError$DecodeError$0 = (value) => value.expected;
|
||||
export const DecodeError$DecodeError$found = (value) => value.found;
|
||||
export const DecodeError$DecodeError$1 = (value) => value.found;
|
||||
export const DecodeError$DecodeError$path = (value) => value.path;
|
||||
export const DecodeError$DecodeError$2 = (value) => value.path;
|
||||
|
||||
class Decoder extends $CustomType {
|
||||
constructor(function$) {
|
||||
super();
|
||||
this.function = function$;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Run a decoder on a `Dynamic` value, decoding the value if it is of the
|
||||
* desired type, or returning errors.
|
||||
*
|
||||
* # Examples
|
||||
*
|
||||
* ```gleam
|
||||
* let decoder = {
|
||||
* use name <- decode.field("email", decode.string)
|
||||
* use email <- decode.field("password", decode.string)
|
||||
* decode.success(SignUp(name: name, email: email))
|
||||
* }
|
||||
*
|
||||
* decode.run(data, decoder)
|
||||
* ```
|
||||
*/
|
||||
export function run(data, decoder) {
|
||||
let $ = decoder.function(data);
|
||||
let maybe_invalid_data;
|
||||
let errors;
|
||||
maybe_invalid_data = $[0];
|
||||
errors = $[1];
|
||||
if (errors instanceof $Empty) {
|
||||
return new Ok(maybe_invalid_data);
|
||||
} else {
|
||||
return new Error(errors);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Finalise a decoder having successfully extracted a value.
|
||||
*
|
||||
* # Examples
|
||||
*
|
||||
* ```gleam
|
||||
* let data = dynamic.properties([
|
||||
* #(dynamic.string("email"), dynamic.string("lucy@example.com")),
|
||||
* #(dynamic.string("name"), dynamic.string("Lucy")),
|
||||
* ]))
|
||||
*
|
||||
* let decoder = {
|
||||
* use name <- decode.field("name", string)
|
||||
* use email <- decode.field("email", string)
|
||||
* decode.success(SignUp(name: name, email: email))
|
||||
* }
|
||||
*
|
||||
* let result = decode.run(data, decoder)
|
||||
* assert result == Ok(SignUp(name: "Lucy", email: "lucy@example.com"))
|
||||
* ```
|
||||
*/
|
||||
export function success(data) {
|
||||
return new Decoder((_) => { return [data, toList([])]; });
|
||||
}
|
||||
|
||||
function decode_dynamic(data) {
|
||||
return [data, toList([])];
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply a transformation function to any value decoded by the decoder.
|
||||
*
|
||||
* # Examples
|
||||
*
|
||||
* ```gleam
|
||||
* let decoder = decode.int |> decode.map(int.to_string)
|
||||
* let result = decode.run(dynamic.int(1000), decoder)
|
||||
* assert result == Ok("1000")
|
||||
* ```
|
||||
*/
|
||||
export function map(decoder, transformer) {
|
||||
return new Decoder(
|
||||
(d) => {
|
||||
let $ = decoder.function(d);
|
||||
let data;
|
||||
let errors;
|
||||
data = $[0];
|
||||
errors = $[1];
|
||||
return [transformer(data), errors];
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply a transformation function to any errors returned by the decoder.
|
||||
*/
|
||||
export function map_errors(decoder, transformer) {
|
||||
return new Decoder(
|
||||
(d) => {
|
||||
let $ = decoder.function(d);
|
||||
let data;
|
||||
let errors;
|
||||
data = $[0];
|
||||
errors = $[1];
|
||||
return [data, transformer(errors)];
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new decoder based upon the value of a previous decoder.
|
||||
*
|
||||
* This may be useful to run one previous decoder to use in further decoding.
|
||||
*/
|
||||
export function then$(decoder, next) {
|
||||
return new Decoder(
|
||||
(dynamic_data) => {
|
||||
let $ = decoder.function(dynamic_data);
|
||||
let data;
|
||||
let errors;
|
||||
data = $[0];
|
||||
errors = $[1];
|
||||
let decoder$1 = next(data);
|
||||
let $1 = decoder$1.function(dynamic_data);
|
||||
let layer;
|
||||
let data$1;
|
||||
layer = $1;
|
||||
data$1 = $1[0];
|
||||
if (errors instanceof $Empty) {
|
||||
return layer;
|
||||
} else {
|
||||
return [data$1, errors];
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
function run_decoders(loop$data, loop$failure, loop$decoders) {
|
||||
while (true) {
|
||||
let data = loop$data;
|
||||
let failure = loop$failure;
|
||||
let decoders = loop$decoders;
|
||||
if (decoders instanceof $Empty) {
|
||||
return failure;
|
||||
} else {
|
||||
let decoder = decoders.head;
|
||||
let decoders$1 = decoders.tail;
|
||||
let $ = decoder.function(data);
|
||||
let layer;
|
||||
let errors;
|
||||
layer = $;
|
||||
errors = $[1];
|
||||
if (errors instanceof $Empty) {
|
||||
return layer;
|
||||
} else {
|
||||
loop$data = data;
|
||||
loop$failure = failure;
|
||||
loop$decoders = decoders$1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new decoder from several other decoders. Each of the inner
|
||||
* decoders is run in turn, and the value from the first to succeed is used.
|
||||
*
|
||||
* If no decoder succeeds then the errors from the first decoder is used.
|
||||
* If you wish for different errors then you may wish to use the
|
||||
* `collapse_errors` or `map_errors` functions.
|
||||
*
|
||||
* # Examples
|
||||
*
|
||||
* ```gleam
|
||||
* let decoder = decode.one_of(decode.string, or: [
|
||||
* decode.int |> decode.map(int.to_string),
|
||||
* decode.float |> decode.map(float.to_string),
|
||||
* ])
|
||||
* decode.run(dynamic.int(1000), decoder)
|
||||
* // -> Ok("1000")
|
||||
* ```
|
||||
*/
|
||||
export function one_of(first, alternatives) {
|
||||
return new Decoder(
|
||||
(dynamic_data) => {
|
||||
let $ = first.function(dynamic_data);
|
||||
let layer;
|
||||
let errors;
|
||||
layer = $;
|
||||
errors = $[1];
|
||||
if (errors instanceof $Empty) {
|
||||
return layer;
|
||||
} else {
|
||||
return run_decoders(dynamic_data, layer, alternatives);
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a decoder that can refer to itself, useful for decoding deeply
|
||||
* nested data.
|
||||
*
|
||||
* Attempting to create a recursive decoder without this function could result
|
||||
* in an infinite loop. If you are using `field` or other `use`able functions
|
||||
* then you may not need to use this function.
|
||||
*
|
||||
* ```gleam
|
||||
* type Nested {
|
||||
* Nested(List(Nested))
|
||||
* Value(String)
|
||||
* }
|
||||
*
|
||||
* fn nested_decoder() -> decode.Decoder(Nested) {
|
||||
* use <- decode.recursive
|
||||
* decode.one_of(decode.string |> decode.map(Value), [
|
||||
* decode.list(nested_decoder()) |> decode.map(Nested),
|
||||
* ])
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
export function recursive(inner) {
|
||||
return new Decoder(
|
||||
(data) => {
|
||||
let decoder = inner();
|
||||
return decoder.function(data);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* A decoder that decodes nullable values of a type decoded by with a given
|
||||
* decoder.
|
||||
*
|
||||
* This function can handle common representations of null on all runtimes, such as
|
||||
* `nil`, `null`, and `undefined` on Erlang, and `undefined` and `null` on
|
||||
* JavaScript.
|
||||
*
|
||||
* # Examples
|
||||
*
|
||||
* ```gleam
|
||||
* let result = decode.run(dynamic.int(100), decode.optional(decode.int))
|
||||
* assert result == Ok(option.Some(100))
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* let result = decode.run(dynamic.nil(), decode.optional(decode.int))
|
||||
* assert result == Ok(option.None)
|
||||
* ```
|
||||
*/
|
||||
export function optional(inner) {
|
||||
return new Decoder(
|
||||
(data) => {
|
||||
let $ = is_null(data);
|
||||
if ($) {
|
||||
return [new $option.None(), toList([])];
|
||||
} else {
|
||||
let $1 = inner.function(data);
|
||||
let data$1;
|
||||
let errors;
|
||||
data$1 = $1[0];
|
||||
errors = $1[1];
|
||||
return [new $option.Some(data$1), errors];
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* A decoder that decodes `Dynamic` values. This decoder never returns an error.
|
||||
*
|
||||
* # Examples
|
||||
*
|
||||
* ```gleam
|
||||
* let result = decode.run(dynamic.float(3.14), decode.dynamic)
|
||||
* assert result == Ok(dynamic.float(3.14))
|
||||
* ```
|
||||
*/
|
||||
export const dynamic = /* @__PURE__ */ new Decoder(decode_dynamic);
|
||||
|
||||
/**
|
||||
* Construct a decode error for some unexpected dynamic data.
|
||||
*/
|
||||
export function decode_error(expected, found) {
|
||||
return toList([
|
||||
new DecodeError(expected, $dynamic.classify(found), toList([])),
|
||||
]);
|
||||
}
|
||||
|
||||
function run_dynamic_function(data, name, f) {
|
||||
let $ = f(data);
|
||||
if ($ instanceof Ok) {
|
||||
let data$1 = $[0];
|
||||
return [data$1, toList([])];
|
||||
} else {
|
||||
let zero = $[0];
|
||||
return [
|
||||
zero,
|
||||
toList([new DecodeError(name, $dynamic.classify(data), toList([]))]),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
function decode_bool(data) {
|
||||
let $ = isEqual(cast(true), data);
|
||||
if ($) {
|
||||
return [true, toList([])];
|
||||
} else {
|
||||
let $1 = isEqual(cast(false), data);
|
||||
if ($1) {
|
||||
return [false, toList([])];
|
||||
} else {
|
||||
return [false, decode_error("Bool", data)];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function decode_int(data) {
|
||||
return run_dynamic_function(data, "Int", dynamic_int);
|
||||
}
|
||||
|
||||
function decode_float(data) {
|
||||
return run_dynamic_function(data, "Float", dynamic_float);
|
||||
}
|
||||
|
||||
function decode_bit_array(data) {
|
||||
return run_dynamic_function(data, "BitArray", dynamic_bit_array);
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace all errors produced by a decoder with one single error for a named
|
||||
* expected type.
|
||||
*
|
||||
* This function may be useful if you wish to simplify errors before
|
||||
* presenting them to a user, particularly when using the `one_of` function.
|
||||
*
|
||||
* # Examples
|
||||
*
|
||||
* ```gleam
|
||||
* let decoder = decode.string |> decode.collapse_errors("MyThing")
|
||||
* let result = decode.run(dynamic.int(1000), decoder)
|
||||
* assert result == Error([DecodeError("MyThing", "Int", [])])
|
||||
* ```
|
||||
*/
|
||||
export function collapse_errors(decoder, name) {
|
||||
return new Decoder(
|
||||
(dynamic_data) => {
|
||||
let $ = decoder.function(dynamic_data);
|
||||
let layer;
|
||||
let data;
|
||||
let errors;
|
||||
layer = $;
|
||||
data = $[0];
|
||||
errors = $[1];
|
||||
if (errors instanceof $Empty) {
|
||||
return layer;
|
||||
} else {
|
||||
return [data, decode_error(name, dynamic_data)];
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Define a decoder that always fails. The parameter for this function is the
|
||||
* name of the type that has failed to decode.
|
||||
*/
|
||||
export function failure(zero, expected) {
|
||||
return new Decoder((d) => { return [zero, decode_error(expected, d)]; });
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a decoder for a new data type from a decoding function.
|
||||
*
|
||||
* This function is used for new primitive types. For example, you might
|
||||
* define a decoder for Erlang's pid type.
|
||||
*
|
||||
* A default "zero" value is also required to make a decoder. When this
|
||||
* decoder is used as part of a larger decoder this zero value used as
|
||||
* a placeholder so that the rest of the decoder can continue to run and
|
||||
* collect all decoding errors.
|
||||
*
|
||||
* If you were to make a decoder for the `String` type (rather than using the
|
||||
* build-in `string` decoder) you would define it like so:
|
||||
*
|
||||
* ```gleam
|
||||
* pub fn string_decoder() -> decode.Decoder(String) {
|
||||
* let default = ""
|
||||
* decode.new_primitive_decoder("String", fn(data) {
|
||||
* case dynamic.string(data) {
|
||||
* Ok(x) -> Ok(x)
|
||||
* Error(_) -> Error(default)
|
||||
* }
|
||||
* })
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
export function new_primitive_decoder(name, decoding_function) {
|
||||
return new Decoder(
|
||||
(d) => {
|
||||
let $ = decoding_function(d);
|
||||
if ($ instanceof Ok) {
|
||||
let t = $[0];
|
||||
return [t, toList([])];
|
||||
} else {
|
||||
let zero = $[0];
|
||||
return [
|
||||
zero,
|
||||
toList([new DecodeError(name, $dynamic.classify(d), toList([]))]),
|
||||
];
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* A decoder that decodes `Bool` values.
|
||||
*
|
||||
* # Examples
|
||||
*
|
||||
* ```gleam
|
||||
* let result = decode.run(dynamic.bool(True), decode.bool)
|
||||
* assert result == Ok(True)
|
||||
* ```
|
||||
*/
|
||||
export const bool = /* @__PURE__ */ new Decoder(decode_bool);
|
||||
|
||||
/**
|
||||
* A decoder that decodes `Int` values.
|
||||
*
|
||||
* # Examples
|
||||
*
|
||||
* ```gleam
|
||||
* let result = decode.run(dynamic.int(147), decode.int)
|
||||
* assert result == Ok(147)
|
||||
* ```
|
||||
*/
|
||||
export const int = /* @__PURE__ */ new Decoder(decode_int);
|
||||
|
||||
/**
|
||||
* A decoder that decodes `Float` values.
|
||||
*
|
||||
* # Examples
|
||||
*
|
||||
* ```gleam
|
||||
* let result = decode.run(dynamic.float(3.14), decode.float)
|
||||
* assert result == Ok(3.14)
|
||||
* ```
|
||||
*/
|
||||
export const float = /* @__PURE__ */ new Decoder(decode_float);
|
||||
|
||||
/**
|
||||
* A decoder that decodes `BitArray` values. This decoder never returns an error.
|
||||
*
|
||||
* # Examples
|
||||
*
|
||||
* ```gleam
|
||||
* let result = decode.run(dynamic.bit_array(<<5, 7>>), decode.bit_array)
|
||||
* assert result == Ok(<<5, 7>>)
|
||||
* ```
|
||||
*/
|
||||
export const bit_array = /* @__PURE__ */ new Decoder(decode_bit_array);
|
||||
|
||||
function decode_string(data) {
|
||||
return run_dynamic_function(data, "String", dynamic_string);
|
||||
}
|
||||
|
||||
/**
|
||||
* A decoder that decodes `String` values.
|
||||
*
|
||||
* # Examples
|
||||
*
|
||||
* ```gleam
|
||||
* let result = decode.run(dynamic.string("Hello!"), decode.string)
|
||||
* assert result == Ok("Hello!")
|
||||
* ```
|
||||
*/
|
||||
export const string = /* @__PURE__ */ new Decoder(decode_string);
|
||||
|
||||
function fold_dict(acc, key, value, key_decoder, value_decoder) {
|
||||
let $ = key_decoder(key);
|
||||
let $1 = $[1];
|
||||
if ($1 instanceof $Empty) {
|
||||
let key$1 = $[0];
|
||||
let $2 = value_decoder(value);
|
||||
let $3 = $2[1];
|
||||
if ($3 instanceof $Empty) {
|
||||
let value$1 = $2[0];
|
||||
let dict$1 = $dict.insert(acc[0], key$1, value$1);
|
||||
return [dict$1, acc[1]];
|
||||
} else {
|
||||
let errors = $3;
|
||||
return push_path([$dict.new$(), errors], toList(["values"]));
|
||||
}
|
||||
} else {
|
||||
let errors = $1;
|
||||
return push_path([$dict.new$(), errors], toList(["keys"]));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A decoder that decodes dicts where all keys and vales are decoded with
|
||||
* given decoders.
|
||||
*
|
||||
* # Examples
|
||||
*
|
||||
* ```gleam
|
||||
* let values = dynamic.properties([
|
||||
* #(dynamic.string("one"), dynamic.int(1)),
|
||||
* #(dynamic.string("two"), dynamic.int(2)),
|
||||
* ])
|
||||
*
|
||||
* let result =
|
||||
* decode.run(values, decode.dict(decode.string, decode.int))
|
||||
* assert result == Ok(values)
|
||||
* ```
|
||||
*/
|
||||
export function dict(key, value) {
|
||||
return new Decoder(
|
||||
(data) => {
|
||||
let $ = decode_dict(data);
|
||||
if ($ instanceof Ok) {
|
||||
let dict$1 = $[0];
|
||||
return $dict.fold(
|
||||
dict$1,
|
||||
[$dict.new$(), toList([])],
|
||||
(a, k, v) => {
|
||||
let $1 = a[1];
|
||||
if ($1 instanceof $Empty) {
|
||||
return fold_dict(a, k, v, key.function, value.function);
|
||||
} else {
|
||||
return a;
|
||||
}
|
||||
},
|
||||
);
|
||||
} else {
|
||||
return [$dict.new$(), decode_error("Dict", data)];
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* A decoder that decodes lists where all elements are decoded with a given
|
||||
* decoder.
|
||||
*
|
||||
* # Examples
|
||||
*
|
||||
* ```gleam
|
||||
* let result =
|
||||
* [1, 2, 3]
|
||||
* |> list.map(dynamic.int)
|
||||
* |> dynamic.list
|
||||
* |> decode.run(decode.list(of: decode.int))
|
||||
* assert result == Ok([1, 2, 3])
|
||||
* ```
|
||||
*/
|
||||
export function list(inner) {
|
||||
return new Decoder(
|
||||
(data) => {
|
||||
return decode_list(
|
||||
data,
|
||||
inner.function,
|
||||
(p, k) => { return push_path(p, toList([k])); },
|
||||
0,
|
||||
toList([]),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
function push_path(layer, path) {
|
||||
let decoder = one_of(
|
||||
string,
|
||||
toList([
|
||||
(() => {
|
||||
let _pipe = int;
|
||||
return map(_pipe, $int.to_string);
|
||||
})(),
|
||||
]),
|
||||
);
|
||||
let path$1 = $list.map(
|
||||
path,
|
||||
(key) => {
|
||||
let key$1 = cast(key);
|
||||
let $ = run(key$1, decoder);
|
||||
if ($ instanceof Ok) {
|
||||
let key$2 = $[0];
|
||||
return key$2;
|
||||
} else {
|
||||
return ("<" + $dynamic.classify(key$1)) + ">";
|
||||
}
|
||||
},
|
||||
);
|
||||
let errors = $list.map(
|
||||
layer[1],
|
||||
(error) => {
|
||||
return new DecodeError(
|
||||
error.expected,
|
||||
error.found,
|
||||
$list.append(path$1, error.path),
|
||||
);
|
||||
},
|
||||
);
|
||||
return [layer[0], errors];
|
||||
}
|
||||
|
||||
function index(
|
||||
loop$path,
|
||||
loop$position,
|
||||
loop$inner,
|
||||
loop$data,
|
||||
loop$handle_miss
|
||||
) {
|
||||
while (true) {
|
||||
let path = loop$path;
|
||||
let position = loop$position;
|
||||
let inner = loop$inner;
|
||||
let data = loop$data;
|
||||
let handle_miss = loop$handle_miss;
|
||||
if (path instanceof $Empty) {
|
||||
let _pipe = data;
|
||||
let _pipe$1 = inner(_pipe);
|
||||
return push_path(_pipe$1, $list.reverse(position));
|
||||
} else {
|
||||
let key = path.head;
|
||||
let path$1 = path.tail;
|
||||
let $ = bare_index(data, key);
|
||||
if ($ instanceof Ok) {
|
||||
let $1 = $[0];
|
||||
if ($1 instanceof Some) {
|
||||
let data$1 = $1[0];
|
||||
loop$path = path$1;
|
||||
loop$position = listPrepend(key, position);
|
||||
loop$inner = inner;
|
||||
loop$data = data$1;
|
||||
loop$handle_miss = handle_miss;
|
||||
} else {
|
||||
return handle_miss(data, listPrepend(key, position));
|
||||
}
|
||||
} else {
|
||||
let kind = $[0];
|
||||
let $1 = inner(data);
|
||||
let default$;
|
||||
default$ = $1[0];
|
||||
let _pipe = [
|
||||
default$,
|
||||
toList([new DecodeError(kind, $dynamic.classify(data), toList([]))]),
|
||||
];
|
||||
return push_path(_pipe, $list.reverse(position));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The same as [`field`](#field), except taking a path to the value rather
|
||||
* than a field name.
|
||||
*
|
||||
* This function will index into dictionaries with any key type, and if the key is
|
||||
* an int then it'll also index into Erlang tuples and JavaScript arrays, and
|
||||
* the first eight elements of Gleam lists.
|
||||
*
|
||||
* # Examples
|
||||
*
|
||||
* ```gleam
|
||||
* let data = dynamic.properties([
|
||||
* #(dynamic.string("data"), dynamic.properties([
|
||||
* #(dynamic.string("email"), dynamic.string("lucy@example.com")),
|
||||
* #(dynamic.string("name"), dynamic.string("Lucy")),
|
||||
* ])
|
||||
* ]))
|
||||
*
|
||||
* let decoder = {
|
||||
* use name <- decode.subfield(["data", "name"], decode.string)
|
||||
* use email <- decode.subfield(["data", "email"], decode.string)
|
||||
* decode.success(SignUp(name: name, email: email))
|
||||
* }
|
||||
* let result = decode.run(data, decoder)
|
||||
* assert result == Ok(SignUp(name: "Lucy", email: "lucy@example.com"))
|
||||
* ```
|
||||
*/
|
||||
export function subfield(field_path, field_decoder, next) {
|
||||
return new Decoder(
|
||||
(data) => {
|
||||
let $ = index(
|
||||
field_path,
|
||||
toList([]),
|
||||
field_decoder.function,
|
||||
data,
|
||||
(data, position) => {
|
||||
let $1 = field_decoder.function(data);
|
||||
let default$;
|
||||
default$ = $1[0];
|
||||
let _pipe = [
|
||||
default$,
|
||||
toList([new DecodeError("Field", "Nothing", toList([]))]),
|
||||
];
|
||||
return push_path(_pipe, $list.reverse(position));
|
||||
},
|
||||
);
|
||||
let out;
|
||||
let errors1;
|
||||
out = $[0];
|
||||
errors1 = $[1];
|
||||
let $1 = next(out).function(data);
|
||||
let out$1;
|
||||
let errors2;
|
||||
out$1 = $1[0];
|
||||
errors2 = $1[1];
|
||||
return [out$1, $list.append(errors1, errors2)];
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* A decoder that decodes a value that is nested within other values. For
|
||||
* example, decoding a value that is within some deeply nested JSON objects.
|
||||
*
|
||||
* This function will index into dictionaries with any key type, and if the key is
|
||||
* an int then it'll also index into Erlang tuples and JavaScript arrays, and
|
||||
* the first eight elements of Gleam lists.
|
||||
*
|
||||
* # Examples
|
||||
*
|
||||
* ```gleam
|
||||
* let decoder = decode.at(["one", "two"], decode.int)
|
||||
*
|
||||
* let data = dynamic.properties([
|
||||
* #(dynamic.string("one"), dynamic.properties([
|
||||
* #(dynamic.string("two"), dynamic.int(1000)),
|
||||
* ])),
|
||||
* ]))
|
||||
*
|
||||
*
|
||||
* decode.run(data, decoder)
|
||||
* // -> Ok(1000)
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* dynamic.nil()
|
||||
* |> decode.run(decode.optional(decode.int))
|
||||
* // -> Ok(option.None)
|
||||
* ```
|
||||
*/
|
||||
export function at(path, inner) {
|
||||
return new Decoder(
|
||||
(data) => {
|
||||
return index(
|
||||
path,
|
||||
toList([]),
|
||||
inner.function,
|
||||
data,
|
||||
(data, position) => {
|
||||
let $ = inner.function(data);
|
||||
let default$;
|
||||
default$ = $[0];
|
||||
let _pipe = [
|
||||
default$,
|
||||
toList([new DecodeError("Field", "Nothing", toList([]))]),
|
||||
];
|
||||
return push_path(_pipe, $list.reverse(position));
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Run a decoder on a field of a `Dynamic` value, decoding the value if it is
|
||||
* of the desired type, or returning errors. An error is returned if there is
|
||||
* no field for the specified key.
|
||||
*
|
||||
* This function will index into dictionaries with any key type, and if the key is
|
||||
* an int then it'll also index into Erlang tuples and JavaScript arrays, and
|
||||
* the first eight elements of Gleam lists.
|
||||
*
|
||||
* # Examples
|
||||
*
|
||||
* ```gleam
|
||||
* let data = dynamic.properties([
|
||||
* #(dynamic.string("email"), dynamic.string("lucy@example.com")),
|
||||
* #(dynamic.string("name"), dynamic.string("Lucy")),
|
||||
* ]))
|
||||
*
|
||||
* let decoder = {
|
||||
* use name <- decode.field("name", string)
|
||||
* use email <- decode.field("email", string)
|
||||
* decode.success(SignUp(name: name, email: email))
|
||||
* }
|
||||
*
|
||||
* let result = decode.run(data, decoder)
|
||||
* assert result == Ok(SignUp(name: "Lucy", email: "lucy@example.com"))
|
||||
* ```
|
||||
*
|
||||
* If you wish to decode a value that is more deeply nested within the dynamic
|
||||
* data, see [`subfield`](#subfield) and [`at`](#at).
|
||||
*
|
||||
* If you wish to return a default in the event that a field is not present,
|
||||
* see [`optional_field`](#optional_field) and / [`optionally_at`](#optionally_at).
|
||||
*/
|
||||
export function field(field_name, field_decoder, next) {
|
||||
return subfield(toList([field_name]), field_decoder, next);
|
||||
}
|
||||
|
||||
/**
|
||||
* Run a decoder on a field of a `Dynamic` value, decoding the value if it is
|
||||
* of the desired type, or returning errors. The given default value is
|
||||
* returned if there is no field for the specified key.
|
||||
*
|
||||
* This function will index into dictionaries with any key type, and if the key is
|
||||
* an int then it'll also index into Erlang tuples and JavaScript arrays, and
|
||||
* the first eight elements of Gleam lists.
|
||||
*
|
||||
* # Examples
|
||||
*
|
||||
* ```gleam
|
||||
* let data = dynamic.properties([
|
||||
* #(dynamic.string("name"), dynamic.string("Lucy")),
|
||||
* ]))
|
||||
*
|
||||
* let decoder = {
|
||||
* use name <- decode.field("name", string)
|
||||
* use email <- decode.optional_field("email", "n/a", string)
|
||||
* decode.success(SignUp(name: name, email: email))
|
||||
* }
|
||||
*
|
||||
* let result = decode.run(data, decoder)
|
||||
* assert result == Ok(SignUp(name: "Lucy", email: "n/a"))
|
||||
* ```
|
||||
*/
|
||||
export function optional_field(key, default$, field_decoder, next) {
|
||||
return new Decoder(
|
||||
(data) => {
|
||||
let _block;
|
||||
let _block$1;
|
||||
let $1 = bare_index(data, key);
|
||||
if ($1 instanceof Ok) {
|
||||
let $2 = $1[0];
|
||||
if ($2 instanceof Some) {
|
||||
let data$1 = $2[0];
|
||||
_block$1 = field_decoder.function(data$1);
|
||||
} else {
|
||||
_block$1 = [default$, toList([])];
|
||||
}
|
||||
} else {
|
||||
let kind = $1[0];
|
||||
_block$1 = [
|
||||
default$,
|
||||
toList([new DecodeError(kind, $dynamic.classify(data), toList([]))]),
|
||||
];
|
||||
}
|
||||
let _pipe = _block$1;
|
||||
_block = push_path(_pipe, toList([key]));
|
||||
let $ = _block;
|
||||
let out;
|
||||
let errors1;
|
||||
out = $[0];
|
||||
errors1 = $[1];
|
||||
let $2 = next(out).function(data);
|
||||
let out$1;
|
||||
let errors2;
|
||||
out$1 = $2[0];
|
||||
errors2 = $2[1];
|
||||
return [out$1, $list.append(errors1, errors2)];
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* A decoder that decodes a value that is nested within other values. For
|
||||
* example, decoding a value that is within some deeply nested JSON objects.
|
||||
*
|
||||
* This function will index into dictionaries with any key type, and if the key is
|
||||
* an int then it'll also index into Erlang tuples and JavaScript arrays, and
|
||||
* the first eight elements of Gleam lists.
|
||||
*
|
||||
* # Examples
|
||||
*
|
||||
* ```gleam
|
||||
* let decoder = decode.optionally_at(["one", "two"], 100, decode.int)
|
||||
*
|
||||
* let data = dynamic.properties([
|
||||
* #(dynamic.string("one"), dynamic.properties([])),
|
||||
* ]))
|
||||
*
|
||||
*
|
||||
* decode.run(data, decoder)
|
||||
* // -> Ok(100)
|
||||
* ```
|
||||
*/
|
||||
export function optionally_at(path, default$, inner) {
|
||||
return new Decoder(
|
||||
(data) => {
|
||||
return index(
|
||||
path,
|
||||
toList([]),
|
||||
inner.function,
|
||||
data,
|
||||
(_, _1) => { return [default$, toList([])]; },
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
553
build/dev/javascript/gleam_stdlib/gleam/float.mjs
Normal file
553
build/dev/javascript/gleam_stdlib/gleam/float.mjs
Normal file
|
|
@ -0,0 +1,553 @@
|
|||
import { Ok, Error, Empty as $Empty, divideFloat } from "../gleam.mjs";
|
||||
import * as $order from "../gleam/order.mjs";
|
||||
import {
|
||||
parse_float as parse,
|
||||
float_to_string as to_string,
|
||||
ceiling,
|
||||
floor,
|
||||
round as js_round,
|
||||
truncate,
|
||||
identity as do_to_float,
|
||||
power as do_power,
|
||||
random_uniform as random,
|
||||
log as do_log,
|
||||
exp as exponential,
|
||||
} from "../gleam_stdlib.mjs";
|
||||
|
||||
export { ceiling, exponential, floor, parse, random, to_string, truncate };
|
||||
|
||||
/**
|
||||
* Compares two `Float`s, returning an `Order`:
|
||||
* `Lt` for lower than, `Eq` for equals, or `Gt` for greater than.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* compare(2.0, 2.3)
|
||||
* // -> Lt
|
||||
* ```
|
||||
*
|
||||
* To handle
|
||||
* [Floating Point Imprecision](https://en.wikipedia.org/wiki/Floating-point_arithmetic#Accuracy_problems)
|
||||
* you may use [`loosely_compare`](#loosely_compare) instead.
|
||||
*/
|
||||
export function compare(a, b) {
|
||||
let $ = a === b;
|
||||
if ($) {
|
||||
return new $order.Eq();
|
||||
} else {
|
||||
let $1 = a < b;
|
||||
if ($1) {
|
||||
return new $order.Lt();
|
||||
} else {
|
||||
return new $order.Gt();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares two `Float`s, returning the smaller of the two.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* min(2.0, 2.3)
|
||||
* // -> 2.0
|
||||
* ```
|
||||
*/
|
||||
export function min(a, b) {
|
||||
let $ = a < b;
|
||||
if ($) {
|
||||
return a;
|
||||
} else {
|
||||
return b;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares two `Float`s, returning the larger of the two.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* max(2.0, 2.3)
|
||||
* // -> 2.3
|
||||
* ```
|
||||
*/
|
||||
export function max(a, b) {
|
||||
let $ = a > b;
|
||||
if ($) {
|
||||
return a;
|
||||
} else {
|
||||
return b;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Restricts a `Float` between a lower and upper bound.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* clamp(1.2, min: 1.4, max: 1.6)
|
||||
* // -> 1.4
|
||||
* ```
|
||||
*/
|
||||
export function clamp(x, min_bound, max_bound) {
|
||||
let _pipe = x;
|
||||
let _pipe$1 = min(_pipe, max_bound);
|
||||
return max(_pipe$1, min_bound);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the absolute value of the input as a `Float`.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* absolute_value(-12.5)
|
||||
* // -> 12.5
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* absolute_value(10.2)
|
||||
* // -> 10.2
|
||||
* ```
|
||||
*/
|
||||
export function absolute_value(x) {
|
||||
let $ = x >= 0.0;
|
||||
if ($) {
|
||||
return x;
|
||||
} else {
|
||||
return 0.0 - x;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares two `Float`s within a tolerance, returning an `Order`:
|
||||
* `Lt` for lower than, `Eq` for equals, or `Gt` for greater than.
|
||||
*
|
||||
* This function allows Float comparison while handling
|
||||
* [Floating Point Imprecision](https://en.wikipedia.org/wiki/Floating-point_arithmetic#Accuracy_problems).
|
||||
*
|
||||
* Notice: For `Float`s the tolerance won't be exact:
|
||||
* `5.3 - 5.0` is not exactly `0.3`.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* loosely_compare(5.0, with: 5.3, tolerating: 0.5)
|
||||
* // -> Eq
|
||||
* ```
|
||||
*
|
||||
* If you want to check only for equality you may use
|
||||
* [`loosely_equals`](#loosely_equals) instead.
|
||||
*/
|
||||
export function loosely_compare(a, b, tolerance) {
|
||||
let difference = absolute_value(a - b);
|
||||
let $ = difference <= tolerance;
|
||||
if ($) {
|
||||
return new $order.Eq();
|
||||
} else {
|
||||
return compare(a, b);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks for equality of two `Float`s within a tolerance,
|
||||
* returning an `Bool`.
|
||||
*
|
||||
* This function allows Float comparison while handling
|
||||
* [Floating Point Imprecision](https://en.wikipedia.org/wiki/Floating-point_arithmetic#Accuracy_problems).
|
||||
*
|
||||
* Notice: For `Float`s the tolerance won't be exact:
|
||||
* `5.3 - 5.0` is not exactly `0.3`.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* loosely_equals(5.0, with: 5.3, tolerating: 0.5)
|
||||
* // -> True
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* loosely_equals(5.0, with: 5.1, tolerating: 0.1)
|
||||
* // -> False
|
||||
* ```
|
||||
*/
|
||||
export function loosely_equals(a, b, tolerance) {
|
||||
let difference = absolute_value(a - b);
|
||||
return difference <= tolerance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the results of the base being raised to the power of the
|
||||
* exponent, as a `Float`.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* power(2.0, -1.0)
|
||||
* // -> Ok(0.5)
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* power(2.0, 2.0)
|
||||
* // -> Ok(4.0)
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* power(8.0, 1.5)
|
||||
* // -> Ok(22.627416997969522)
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* 4.0 |> power(of: 2.0)
|
||||
* // -> Ok(16.0)
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* power(-1.0, 0.5)
|
||||
* // -> Error(Nil)
|
||||
* ```
|
||||
*/
|
||||
export function power(base, exponent) {
|
||||
let fractional = (ceiling(exponent) - exponent) > 0.0;
|
||||
let $ = ((base < 0.0) && fractional) || ((base === 0.0) && (exponent < 0.0));
|
||||
if ($) {
|
||||
return new Error(undefined);
|
||||
} else {
|
||||
return new Ok(do_power(base, exponent));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the square root of the input as a `Float`.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* square_root(4.0)
|
||||
* // -> Ok(2.0)
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* square_root(-16.0)
|
||||
* // -> Error(Nil)
|
||||
* ```
|
||||
*/
|
||||
export function square_root(x) {
|
||||
return power(x, 0.5);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the negative of the value provided.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* negate(1.0)
|
||||
* // -> -1.0
|
||||
* ```
|
||||
*/
|
||||
export function negate(x) {
|
||||
return -1.0 * x;
|
||||
}
|
||||
|
||||
/**
|
||||
* Rounds the value to the nearest whole number as an `Int`.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* round(2.3)
|
||||
* // -> 2
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* round(2.5)
|
||||
* // -> 3
|
||||
* ```
|
||||
*/
|
||||
export function round(x) {
|
||||
let $ = x >= 0.0;
|
||||
if ($) {
|
||||
return js_round(x);
|
||||
} else {
|
||||
return 0 - js_round(negate(x));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the value to a given precision as a `Float`.
|
||||
* The precision is the number of allowed decimal places.
|
||||
* Negative precisions are allowed and force rounding
|
||||
* to the nearest tenth, hundredth, thousandth etc.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* to_precision(2.43434348473, precision: 2)
|
||||
* // -> 2.43
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* to_precision(547890.453444, precision: -3)
|
||||
* // -> 548000.0
|
||||
* ```
|
||||
*/
|
||||
export function to_precision(x, precision) {
|
||||
let $ = precision <= 0;
|
||||
if ($) {
|
||||
let factor = do_power(10.0, do_to_float(- precision));
|
||||
return do_to_float(round(divideFloat(x, factor))) * factor;
|
||||
} else {
|
||||
let factor = do_power(10.0, do_to_float(precision));
|
||||
return divideFloat(do_to_float(round(x * factor)), factor);
|
||||
}
|
||||
}
|
||||
|
||||
function sum_loop(loop$numbers, loop$initial) {
|
||||
while (true) {
|
||||
let numbers = loop$numbers;
|
||||
let initial = loop$initial;
|
||||
if (numbers instanceof $Empty) {
|
||||
return initial;
|
||||
} else {
|
||||
let first = numbers.head;
|
||||
let rest = numbers.tail;
|
||||
loop$numbers = rest;
|
||||
loop$initial = first + initial;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sums a list of `Float`s.
|
||||
*
|
||||
* ## Example
|
||||
*
|
||||
* ```gleam
|
||||
* sum([1.0, 2.2, 3.3])
|
||||
* // -> 6.5
|
||||
* ```
|
||||
*/
|
||||
export function sum(numbers) {
|
||||
return sum_loop(numbers, 0.0);
|
||||
}
|
||||
|
||||
function product_loop(loop$numbers, loop$initial) {
|
||||
while (true) {
|
||||
let numbers = loop$numbers;
|
||||
let initial = loop$initial;
|
||||
if (numbers instanceof $Empty) {
|
||||
return initial;
|
||||
} else {
|
||||
let first = numbers.head;
|
||||
let rest = numbers.tail;
|
||||
loop$numbers = rest;
|
||||
loop$initial = first * initial;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Multiplies a list of `Float`s and returns the product.
|
||||
*
|
||||
* ## Example
|
||||
*
|
||||
* ```gleam
|
||||
* product([2.5, 3.2, 4.2])
|
||||
* // -> 33.6
|
||||
* ```
|
||||
*/
|
||||
export function product(numbers) {
|
||||
return product_loop(numbers, 1.0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the modulo of an float division of inputs as a `Result`.
|
||||
*
|
||||
* Returns division of the inputs as a `Result`: If the given divisor equals
|
||||
* `0`, this function returns an `Error`.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* modulo(13.3, by: 3.3)
|
||||
* // -> Ok(0.1)
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* modulo(-13.3, by: 3.3)
|
||||
* // -> Ok(3.2)
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* modulo(13.3, by: -3.3)
|
||||
* // -> Ok(-3.2)
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* modulo(-13.3, by: -3.3)
|
||||
* // -> Ok(-0.1)
|
||||
* ```
|
||||
*/
|
||||
export function modulo(dividend, divisor) {
|
||||
if (divisor === 0.0) {
|
||||
return new Error(undefined);
|
||||
} else {
|
||||
return new Ok(dividend - (floor(divideFloat(dividend, divisor)) * divisor));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns division of the inputs as a `Result`.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* divide(0.0, 1.0)
|
||||
* // -> Ok(0.0)
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* divide(1.0, 0.0)
|
||||
* // -> Error(Nil)
|
||||
* ```
|
||||
*/
|
||||
export function divide(a, b) {
|
||||
if (b === 0.0) {
|
||||
return new Error(undefined);
|
||||
} else {
|
||||
let b$1 = b;
|
||||
return new Ok(divideFloat(a, b$1));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds two floats together.
|
||||
*
|
||||
* It's the function equivalent of the `+.` operator.
|
||||
* This function is useful in higher order functions or pipes.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* add(1.0, 2.0)
|
||||
* // -> 3.0
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* import gleam/list
|
||||
*
|
||||
* list.fold([1.0, 2.0, 3.0], 0.0, add)
|
||||
* // -> 6.0
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* 3.0 |> add(2.0)
|
||||
* // -> 5.0
|
||||
* ```
|
||||
*/
|
||||
export function add(a, b) {
|
||||
return a + b;
|
||||
}
|
||||
|
||||
/**
|
||||
* Multiplies two floats together.
|
||||
*
|
||||
* It's the function equivalent of the `*.` operator.
|
||||
* This function is useful in higher order functions or pipes.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* multiply(2.0, 4.0)
|
||||
* // -> 8.0
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* import gleam/list
|
||||
*
|
||||
* list.fold([2.0, 3.0, 4.0], 1.0, multiply)
|
||||
* // -> 24.0
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* 3.0 |> multiply(2.0)
|
||||
* // -> 6.0
|
||||
* ```
|
||||
*/
|
||||
export function multiply(a, b) {
|
||||
return a * b;
|
||||
}
|
||||
|
||||
/**
|
||||
* Subtracts one float from another.
|
||||
*
|
||||
* It's the function equivalent of the `-.` operator.
|
||||
* This function is useful in higher order functions or pipes.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* subtract(3.0, 1.0)
|
||||
* // -> 2.0
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* import gleam/list
|
||||
*
|
||||
* list.fold([1.0, 2.0, 3.0], 10.0, subtract)
|
||||
* // -> 4.0
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* 3.0 |> subtract(_, 2.0)
|
||||
* // -> 1.0
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* 3.0 |> subtract(2.0, _)
|
||||
* // -> -1.0
|
||||
* ```
|
||||
*/
|
||||
export function subtract(a, b) {
|
||||
return a - b;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the natural logarithm (base e) of the given as a `Result`. If the
|
||||
* input is less than or equal to 0, returns `Error(Nil)`.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* logarithm(1.0)
|
||||
* // -> Ok(0.0)
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* logarithm(2.718281828459045) // e
|
||||
* // -> Ok(1.0)
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* logarithm(0.0)
|
||||
* // -> Error(Nil)
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* logarithm(-1.0)
|
||||
* // -> Error(Nil)
|
||||
* ```
|
||||
*/
|
||||
export function logarithm(x) {
|
||||
let $ = x <= 0.0;
|
||||
if ($) {
|
||||
return new Error(undefined);
|
||||
} else {
|
||||
return new Ok(do_log(x));
|
||||
}
|
||||
}
|
||||
17
build/dev/javascript/gleam_stdlib/gleam/function.mjs
Normal file
17
build/dev/javascript/gleam_stdlib/gleam/function.mjs
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
/**
|
||||
* Takes a single argument and always returns its input value.
|
||||
*/
|
||||
export function identity(x) {
|
||||
return x;
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes an argument and a single function, calls that function with that
|
||||
* argument and returns that argument instead of the function return value.
|
||||
*
|
||||
* Useful for running synchronous side effects in a pipeline.
|
||||
*/
|
||||
export function tap(arg, effect) {
|
||||
effect(arg);
|
||||
return arg;
|
||||
}
|
||||
816
build/dev/javascript/gleam_stdlib/gleam/int.mjs
Normal file
816
build/dev/javascript/gleam_stdlib/gleam/int.mjs
Normal file
|
|
@ -0,0 +1,816 @@
|
|||
import {
|
||||
Ok,
|
||||
Error,
|
||||
toList,
|
||||
Empty as $Empty,
|
||||
prepend as listPrepend,
|
||||
remainderInt,
|
||||
divideInt,
|
||||
} from "../gleam.mjs";
|
||||
import * as $float from "../gleam/float.mjs";
|
||||
import * as $order from "../gleam/order.mjs";
|
||||
import {
|
||||
parse_int as parse,
|
||||
int_from_base_string as do_base_parse,
|
||||
to_string,
|
||||
int_to_base_string as do_to_base_string,
|
||||
identity as to_float,
|
||||
bitwise_and,
|
||||
bitwise_not,
|
||||
bitwise_or,
|
||||
bitwise_exclusive_or,
|
||||
bitwise_shift_left,
|
||||
bitwise_shift_right,
|
||||
} from "../gleam_stdlib.mjs";
|
||||
|
||||
export {
|
||||
bitwise_and,
|
||||
bitwise_exclusive_or,
|
||||
bitwise_not,
|
||||
bitwise_or,
|
||||
bitwise_shift_left,
|
||||
bitwise_shift_right,
|
||||
parse,
|
||||
to_float,
|
||||
to_string,
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the absolute value of the input.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* absolute_value(-12)
|
||||
* // -> 12
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* absolute_value(10)
|
||||
* // -> 10
|
||||
* ```
|
||||
*/
|
||||
export function absolute_value(x) {
|
||||
let $ = x >= 0;
|
||||
if ($) {
|
||||
return x;
|
||||
} else {
|
||||
return x * -1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a given string as an int in a given base if possible.
|
||||
* Supports only bases 2 to 36, for values outside of which this function returns an `Error(Nil)`.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* base_parse("10", 2)
|
||||
* // -> Ok(2)
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* base_parse("30", 16)
|
||||
* // -> Ok(48)
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* base_parse("1C", 36)
|
||||
* // -> Ok(48)
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* base_parse("48", 1)
|
||||
* // -> Error(Nil)
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* base_parse("48", 37)
|
||||
* // -> Error(Nil)
|
||||
* ```
|
||||
*/
|
||||
export function base_parse(string, base) {
|
||||
let $ = (base >= 2) && (base <= 36);
|
||||
if ($) {
|
||||
return do_base_parse(string, base);
|
||||
} else {
|
||||
return new Error(undefined);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints a given int to a string using the base number provided.
|
||||
* Supports only bases 2 to 36, for values outside of which this function returns an `Error(Nil)`.
|
||||
* For common bases (2, 8, 16, 36), use the `to_baseN` functions.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* to_base_string(2, 2)
|
||||
* // -> Ok("10")
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* to_base_string(48, 16)
|
||||
* // -> Ok("30")
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* to_base_string(48, 36)
|
||||
* // -> Ok("1C")
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* to_base_string(48, 1)
|
||||
* // -> Error(Nil)
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* to_base_string(48, 37)
|
||||
* // -> Error(Nil)
|
||||
* ```
|
||||
*/
|
||||
export function to_base_string(x, base) {
|
||||
let $ = (base >= 2) && (base <= 36);
|
||||
if ($) {
|
||||
return new Ok(do_to_base_string(x, base));
|
||||
} else {
|
||||
return new Error(undefined);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints a given int to a string using base-2.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* to_base2(2)
|
||||
* // -> "10"
|
||||
* ```
|
||||
*/
|
||||
export function to_base2(x) {
|
||||
return do_to_base_string(x, 2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints a given int to a string using base-8.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* to_base8(15)
|
||||
* // -> "17"
|
||||
* ```
|
||||
*/
|
||||
export function to_base8(x) {
|
||||
return do_to_base_string(x, 8);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints a given int to a string using base-16.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* to_base16(48)
|
||||
* // -> "30"
|
||||
* ```
|
||||
*/
|
||||
export function to_base16(x) {
|
||||
return do_to_base_string(x, 16);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints a given int to a string using base-36.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* to_base36(48)
|
||||
* // -> "1C"
|
||||
* ```
|
||||
*/
|
||||
export function to_base36(x) {
|
||||
return do_to_base_string(x, 36);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the results of the base being raised to the power of the
|
||||
* exponent, as a `Float`.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* power(2, -1.0)
|
||||
* // -> Ok(0.5)
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* power(2, 2.0)
|
||||
* // -> Ok(4.0)
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* power(8, 1.5)
|
||||
* // -> Ok(22.627416997969522)
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* 4 |> power(of: 2.0)
|
||||
* // -> Ok(16.0)
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* power(-1, 0.5)
|
||||
* // -> Error(Nil)
|
||||
* ```
|
||||
*/
|
||||
export function power(base, exponent) {
|
||||
let _pipe = base;
|
||||
let _pipe$1 = to_float(_pipe);
|
||||
return $float.power(_pipe$1, exponent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the square root of the input as a `Float`.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* square_root(4)
|
||||
* // -> Ok(2.0)
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* square_root(-16)
|
||||
* // -> Error(Nil)
|
||||
* ```
|
||||
*/
|
||||
export function square_root(x) {
|
||||
let _pipe = x;
|
||||
let _pipe$1 = to_float(_pipe);
|
||||
return $float.square_root(_pipe$1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares two ints, returning an order.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* compare(2, 3)
|
||||
* // -> Lt
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* compare(4, 3)
|
||||
* // -> Gt
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* compare(3, 3)
|
||||
* // -> Eq
|
||||
* ```
|
||||
*/
|
||||
export function compare(a, b) {
|
||||
let $ = a === b;
|
||||
if ($) {
|
||||
return new $order.Eq();
|
||||
} else {
|
||||
let $1 = a < b;
|
||||
if ($1) {
|
||||
return new $order.Lt();
|
||||
} else {
|
||||
return new $order.Gt();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares two ints, returning the smaller of the two.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* min(2, 3)
|
||||
* // -> 2
|
||||
* ```
|
||||
*/
|
||||
export function min(a, b) {
|
||||
let $ = a < b;
|
||||
if ($) {
|
||||
return a;
|
||||
} else {
|
||||
return b;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares two ints, returning the larger of the two.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* max(2, 3)
|
||||
* // -> 3
|
||||
* ```
|
||||
*/
|
||||
export function max(a, b) {
|
||||
let $ = a > b;
|
||||
if ($) {
|
||||
return a;
|
||||
} else {
|
||||
return b;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Restricts an int between a lower and upper bound.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* clamp(40, min: 50, max: 60)
|
||||
* // -> 50
|
||||
* ```
|
||||
*/
|
||||
export function clamp(x, min_bound, max_bound) {
|
||||
let _pipe = x;
|
||||
let _pipe$1 = min(_pipe, max_bound);
|
||||
return max(_pipe$1, min_bound);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the value provided is even.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* is_even(2)
|
||||
* // -> True
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* is_even(3)
|
||||
* // -> False
|
||||
* ```
|
||||
*/
|
||||
export function is_even(x) {
|
||||
return (x % 2) === 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the value provided is odd.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* is_odd(3)
|
||||
* // -> True
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* is_odd(2)
|
||||
* // -> False
|
||||
* ```
|
||||
*/
|
||||
export function is_odd(x) {
|
||||
return (x % 2) !== 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the negative of the value provided.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* negate(1)
|
||||
* // -> -1
|
||||
* ```
|
||||
*/
|
||||
export function negate(x) {
|
||||
return -1 * x;
|
||||
}
|
||||
|
||||
function sum_loop(loop$numbers, loop$initial) {
|
||||
while (true) {
|
||||
let numbers = loop$numbers;
|
||||
let initial = loop$initial;
|
||||
if (numbers instanceof $Empty) {
|
||||
return initial;
|
||||
} else {
|
||||
let first = numbers.head;
|
||||
let rest = numbers.tail;
|
||||
loop$numbers = rest;
|
||||
loop$initial = first + initial;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sums a list of ints.
|
||||
*
|
||||
* ## Example
|
||||
*
|
||||
* ```gleam
|
||||
* sum([1, 2, 3])
|
||||
* // -> 6
|
||||
* ```
|
||||
*/
|
||||
export function sum(numbers) {
|
||||
return sum_loop(numbers, 0);
|
||||
}
|
||||
|
||||
function product_loop(loop$numbers, loop$initial) {
|
||||
while (true) {
|
||||
let numbers = loop$numbers;
|
||||
let initial = loop$initial;
|
||||
if (numbers instanceof $Empty) {
|
||||
return initial;
|
||||
} else {
|
||||
let first = numbers.head;
|
||||
let rest = numbers.tail;
|
||||
loop$numbers = rest;
|
||||
loop$initial = first * initial;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Multiplies a list of ints and returns the product.
|
||||
*
|
||||
* ## Example
|
||||
*
|
||||
* ```gleam
|
||||
* product([2, 3, 4])
|
||||
* // -> 24
|
||||
* ```
|
||||
*/
|
||||
export function product(numbers) {
|
||||
return product_loop(numbers, 1);
|
||||
}
|
||||
|
||||
function digits_loop(loop$x, loop$base, loop$acc) {
|
||||
while (true) {
|
||||
let x = loop$x;
|
||||
let base = loop$base;
|
||||
let acc = loop$acc;
|
||||
let $ = absolute_value(x) < base;
|
||||
if ($) {
|
||||
return listPrepend(x, acc);
|
||||
} else {
|
||||
loop$x = divideInt(x, base);
|
||||
loop$base = base;
|
||||
loop$acc = listPrepend(remainderInt(x, base), acc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function digits(x, base) {
|
||||
let $ = base < 2;
|
||||
if ($) {
|
||||
return new Error(undefined);
|
||||
} else {
|
||||
return new Ok(digits_loop(x, base, toList([])));
|
||||
}
|
||||
}
|
||||
|
||||
function undigits_loop(loop$numbers, loop$base, loop$acc) {
|
||||
while (true) {
|
||||
let numbers = loop$numbers;
|
||||
let base = loop$base;
|
||||
let acc = loop$acc;
|
||||
if (numbers instanceof $Empty) {
|
||||
return new Ok(acc);
|
||||
} else {
|
||||
let digit = numbers.head;
|
||||
if (digit >= base) {
|
||||
return new Error(undefined);
|
||||
} else {
|
||||
let digit$1 = numbers.head;
|
||||
let rest = numbers.tail;
|
||||
loop$numbers = rest;
|
||||
loop$base = base;
|
||||
loop$acc = acc * base + digit$1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function undigits(numbers, base) {
|
||||
let $ = base < 2;
|
||||
if ($) {
|
||||
return new Error(undefined);
|
||||
} else {
|
||||
return undigits_loop(numbers, base, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a random int between zero and the given maximum.
|
||||
*
|
||||
* The lower number is inclusive, the upper number is exclusive.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* random(10)
|
||||
* // -> 4
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* random(1)
|
||||
* // -> 0
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* random(-1)
|
||||
* // -> -1
|
||||
* ```
|
||||
*/
|
||||
export function random(max) {
|
||||
let _pipe = ($float.random() * to_float(max));
|
||||
let _pipe$1 = $float.floor(_pipe);
|
||||
return $float.round(_pipe$1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs a truncated integer division.
|
||||
*
|
||||
* Returns division of the inputs as a `Result`: If the given divisor equals
|
||||
* `0`, this function returns an `Error`.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* divide(0, 1)
|
||||
* // -> Ok(0)
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* divide(1, 0)
|
||||
* // -> Error(Nil)
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* divide(5, 2)
|
||||
* // -> Ok(2)
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* divide(-99, 2)
|
||||
* // -> Ok(-49)
|
||||
* ```
|
||||
*/
|
||||
export function divide(dividend, divisor) {
|
||||
if (divisor === 0) {
|
||||
return new Error(undefined);
|
||||
} else {
|
||||
let divisor$1 = divisor;
|
||||
return new Ok(divideInt(dividend, divisor$1));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the remainder of an integer division of inputs as a `Result`.
|
||||
*
|
||||
* Returns division of the inputs as a `Result`: If the given divisor equals
|
||||
* `0`, this function returns an `Error`.
|
||||
*
|
||||
* Most the time you will want to use the `%` operator instead of this
|
||||
* function.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* remainder(3, 2)
|
||||
* // -> Ok(1)
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* remainder(1, 0)
|
||||
* // -> Error(Nil)
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* remainder(10, -1)
|
||||
* // -> Ok(0)
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* remainder(13, by: 3)
|
||||
* // -> Ok(1)
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* remainder(-13, by: 3)
|
||||
* // -> Ok(-1)
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* remainder(13, by: -3)
|
||||
* // -> Ok(1)
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* remainder(-13, by: -3)
|
||||
* // -> Ok(-1)
|
||||
* ```
|
||||
*/
|
||||
export function remainder(dividend, divisor) {
|
||||
if (divisor === 0) {
|
||||
return new Error(undefined);
|
||||
} else {
|
||||
let divisor$1 = divisor;
|
||||
return new Ok(remainderInt(dividend, divisor$1));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the modulo of an integer division of inputs as a `Result`.
|
||||
*
|
||||
* Returns division of the inputs as a `Result`: If the given divisor equals
|
||||
* `0`, this function returns an `Error`.
|
||||
*
|
||||
* Most the time you will want to use the `%` operator instead of this
|
||||
* function.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* modulo(3, 2)
|
||||
* // -> Ok(1)
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* modulo(1, 0)
|
||||
* // -> Error(Nil)
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* modulo(10, -1)
|
||||
* // -> Ok(0)
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* modulo(13, by: 3)
|
||||
* // -> Ok(1)
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* modulo(-13, by: 3)
|
||||
* // -> Ok(2)
|
||||
* ```
|
||||
*/
|
||||
export function modulo(dividend, divisor) {
|
||||
if (divisor === 0) {
|
||||
return new Error(undefined);
|
||||
} else {
|
||||
let remainder$1 = remainderInt(dividend, divisor);
|
||||
let $ = remainder$1 * divisor < 0;
|
||||
if ($) {
|
||||
return new Ok(remainder$1 + divisor);
|
||||
} else {
|
||||
return new Ok(remainder$1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs a *floored* integer division, which means that the result will
|
||||
* always be rounded towards negative infinity.
|
||||
*
|
||||
* If you want to perform truncated integer division (rounding towards zero),
|
||||
* use `int.divide()` or the `/` operator instead.
|
||||
*
|
||||
* Returns division of the inputs as a `Result`: If the given divisor equals
|
||||
* `0`, this function returns an `Error`.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* floor_divide(1, 0)
|
||||
* // -> Error(Nil)
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* floor_divide(5, 2)
|
||||
* // -> Ok(2)
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* floor_divide(6, -4)
|
||||
* // -> Ok(-2)
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* floor_divide(-99, 2)
|
||||
* // -> Ok(-50)
|
||||
* ```
|
||||
*/
|
||||
export function floor_divide(dividend, divisor) {
|
||||
if (divisor === 0) {
|
||||
return new Error(undefined);
|
||||
} else {
|
||||
let divisor$1 = divisor;
|
||||
let $ = (dividend * divisor$1 < 0) && ((remainderInt(dividend, divisor$1)) !== 0);
|
||||
if ($) {
|
||||
return new Ok((divideInt(dividend, divisor$1)) - 1);
|
||||
} else {
|
||||
return new Ok(divideInt(dividend, divisor$1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds two integers together.
|
||||
*
|
||||
* It's the function equivalent of the `+` operator.
|
||||
* This function is useful in higher order functions or pipes.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* add(1, 2)
|
||||
* // -> 3
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* import gleam/list
|
||||
* list.fold([1, 2, 3], 0, add)
|
||||
* // -> 6
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* 3 |> add(2)
|
||||
* // -> 5
|
||||
* ```
|
||||
*/
|
||||
export function add(a, b) {
|
||||
return a + b;
|
||||
}
|
||||
|
||||
/**
|
||||
* Multiplies two integers together.
|
||||
*
|
||||
* It's the function equivalent of the `*` operator.
|
||||
* This function is useful in higher order functions or pipes.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* multiply(2, 4)
|
||||
* // -> 8
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* import gleam/list
|
||||
*
|
||||
* list.fold([2, 3, 4], 1, multiply)
|
||||
* // -> 24
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* 3 |> multiply(2)
|
||||
* // -> 6
|
||||
* ```
|
||||
*/
|
||||
export function multiply(a, b) {
|
||||
return a * b;
|
||||
}
|
||||
|
||||
/**
|
||||
* Subtracts one int from another.
|
||||
*
|
||||
* It's the function equivalent of the `-` operator.
|
||||
* This function is useful in higher order functions or pipes.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* subtract(3, 1)
|
||||
* // -> 2
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* import gleam/list
|
||||
*
|
||||
* list.fold([1, 2, 3], 10, subtract)
|
||||
* // -> 4
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* 3 |> subtract(2)
|
||||
* // -> 1
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* 3 |> subtract(2, _)
|
||||
* // -> -1
|
||||
* ```
|
||||
*/
|
||||
export function subtract(a, b) {
|
||||
return a - b;
|
||||
}
|
||||
8
build/dev/javascript/gleam_stdlib/gleam/io.mjs
Normal file
8
build/dev/javascript/gleam_stdlib/gleam/io.mjs
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
import {
|
||||
print,
|
||||
print_error,
|
||||
console_log as println,
|
||||
console_error as println_error,
|
||||
} from "../gleam_stdlib.mjs";
|
||||
|
||||
export { print, print_error, println, println_error };
|
||||
3209
build/dev/javascript/gleam_stdlib/gleam/list.mjs
Normal file
3209
build/dev/javascript/gleam_stdlib/gleam/list.mjs
Normal file
File diff suppressed because it is too large
Load diff
419
build/dev/javascript/gleam_stdlib/gleam/option.mjs
Normal file
419
build/dev/javascript/gleam_stdlib/gleam/option.mjs
Normal file
|
|
@ -0,0 +1,419 @@
|
|||
import {
|
||||
Ok,
|
||||
Error,
|
||||
toList,
|
||||
Empty as $Empty,
|
||||
prepend as listPrepend,
|
||||
CustomType as $CustomType,
|
||||
isEqual,
|
||||
} from "../gleam.mjs";
|
||||
|
||||
export class Some extends $CustomType {
|
||||
constructor($0) {
|
||||
super();
|
||||
this[0] = $0;
|
||||
}
|
||||
}
|
||||
export const Option$Some = ($0) => new Some($0);
|
||||
export const Option$isSome = (value) => value instanceof Some;
|
||||
export const Option$Some$0 = (value) => value[0];
|
||||
|
||||
export class None extends $CustomType {}
|
||||
export const Option$None = () => new None();
|
||||
export const Option$isNone = (value) => value instanceof None;
|
||||
|
||||
function reverse_and_prepend(loop$prefix, loop$suffix) {
|
||||
while (true) {
|
||||
let prefix = loop$prefix;
|
||||
let suffix = loop$suffix;
|
||||
if (prefix instanceof $Empty) {
|
||||
return suffix;
|
||||
} else {
|
||||
let first = prefix.head;
|
||||
let rest = prefix.tail;
|
||||
loop$prefix = rest;
|
||||
loop$suffix = listPrepend(first, suffix);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function reverse(list) {
|
||||
return reverse_and_prepend(list, toList([]));
|
||||
}
|
||||
|
||||
function all_loop(loop$list, loop$acc) {
|
||||
while (true) {
|
||||
let list = loop$list;
|
||||
let acc = loop$acc;
|
||||
if (list instanceof $Empty) {
|
||||
return new Some(reverse(acc));
|
||||
} else {
|
||||
let $ = list.head;
|
||||
if ($ instanceof Some) {
|
||||
let rest = list.tail;
|
||||
let first = $[0];
|
||||
loop$list = rest;
|
||||
loop$acc = listPrepend(first, acc);
|
||||
} else {
|
||||
return new None();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Combines a list of `Option`s into a single `Option`.
|
||||
* If all elements in the list are `Some` then returns a `Some` holding the list of values.
|
||||
* If any element is `None` then returns`None`.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* all([Some(1), Some(2)])
|
||||
* // -> Some([1, 2])
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* all([Some(1), None])
|
||||
* // -> None
|
||||
* ```
|
||||
*/
|
||||
export function all(list) {
|
||||
return all_loop(list, toList([]));
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the `Option` is a `Some` value.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* is_some(Some(1))
|
||||
* // -> True
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* is_some(None)
|
||||
* // -> False
|
||||
* ```
|
||||
*/
|
||||
export function is_some(option) {
|
||||
return !isEqual(option, new None());
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the `Option` is a `None` value.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* is_none(Some(1))
|
||||
* // -> False
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* is_none(None)
|
||||
* // -> True
|
||||
* ```
|
||||
*/
|
||||
export function is_none(option) {
|
||||
return isEqual(option, new None());
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts an `Option` type to a `Result` type.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* to_result(Some(1), "some_error")
|
||||
* // -> Ok(1)
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* to_result(None, "some_error")
|
||||
* // -> Error("some_error")
|
||||
* ```
|
||||
*/
|
||||
export function to_result(option, e) {
|
||||
if (option instanceof Some) {
|
||||
let a = option[0];
|
||||
return new Ok(a);
|
||||
} else {
|
||||
return new Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a `Result` type to an `Option` type.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* from_result(Ok(1))
|
||||
* // -> Some(1)
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* from_result(Error("some_error"))
|
||||
* // -> None
|
||||
* ```
|
||||
*/
|
||||
export function from_result(result) {
|
||||
if (result instanceof Ok) {
|
||||
let a = result[0];
|
||||
return new Some(a);
|
||||
} else {
|
||||
return new None();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the value from an `Option`, returning a default value if there is none.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* unwrap(Some(1), 0)
|
||||
* // -> 1
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* unwrap(None, 0)
|
||||
* // -> 0
|
||||
* ```
|
||||
*/
|
||||
export function unwrap(option, default$) {
|
||||
if (option instanceof Some) {
|
||||
let x = option[0];
|
||||
return x;
|
||||
} else {
|
||||
return default$;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the value from an `Option`, evaluating the default function if the option is `None`.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* lazy_unwrap(Some(1), fn() { 0 })
|
||||
* // -> 1
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* lazy_unwrap(None, fn() { 0 })
|
||||
* // -> 0
|
||||
* ```
|
||||
*/
|
||||
export function lazy_unwrap(option, default$) {
|
||||
if (option instanceof Some) {
|
||||
let x = option[0];
|
||||
return x;
|
||||
} else {
|
||||
return default$();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates a value held within the `Some` of an `Option` by calling a given function
|
||||
* on it.
|
||||
*
|
||||
* If the `Option` is a `None` rather than `Some`, the function is not called and the
|
||||
* `Option` stays the same.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* map(over: Some(1), with: fn(x) { x + 1 })
|
||||
* // -> Some(2)
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* map(over: None, with: fn(x) { x + 1 })
|
||||
* // -> None
|
||||
* ```
|
||||
*/
|
||||
export function map(option, fun) {
|
||||
if (option instanceof Some) {
|
||||
let x = option[0];
|
||||
return new Some(fun(x));
|
||||
} else {
|
||||
return option;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Merges a nested `Option` into a single layer.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* flatten(Some(Some(1)))
|
||||
* // -> Some(1)
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* flatten(Some(None))
|
||||
* // -> None
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* flatten(None)
|
||||
* // -> None
|
||||
* ```
|
||||
*/
|
||||
export function flatten(option) {
|
||||
if (option instanceof Some) {
|
||||
let x = option[0];
|
||||
return x;
|
||||
} else {
|
||||
return option;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates a value held within the `Some` of an `Option` by calling a given function
|
||||
* on it, where the given function also returns an `Option`. The two options are
|
||||
* then merged together into one `Option`.
|
||||
*
|
||||
* If the `Option` is a `None` rather than `Some` the function is not called and the
|
||||
* option stays the same.
|
||||
*
|
||||
* This function is the equivalent of calling `map` followed by `flatten`, and
|
||||
* it is useful for chaining together multiple functions that return `Option`.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* then(Some(1), fn(x) { Some(x + 1) })
|
||||
* // -> Some(2)
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* then(Some(1), fn(x) { Some(#("a", x)) })
|
||||
* // -> Some(#("a", 1))
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* then(Some(1), fn(_) { None })
|
||||
* // -> None
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* then(None, fn(x) { Some(x + 1) })
|
||||
* // -> None
|
||||
* ```
|
||||
*/
|
||||
export function then$(option, fun) {
|
||||
if (option instanceof Some) {
|
||||
let x = option[0];
|
||||
return fun(x);
|
||||
} else {
|
||||
return option;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the first value if it is `Some`, otherwise returns the second value.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* or(Some(1), Some(2))
|
||||
* // -> Some(1)
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* or(Some(1), None)
|
||||
* // -> Some(1)
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* or(None, Some(2))
|
||||
* // -> Some(2)
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* or(None, None)
|
||||
* // -> None
|
||||
* ```
|
||||
*/
|
||||
export function or(first, second) {
|
||||
if (first instanceof Some) {
|
||||
return first;
|
||||
} else {
|
||||
return second;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the first value if it is `Some`, otherwise evaluates the given function for a fallback value.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* lazy_or(Some(1), fn() { Some(2) })
|
||||
* // -> Some(1)
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* lazy_or(Some(1), fn() { None })
|
||||
* // -> Some(1)
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* lazy_or(None, fn() { Some(2) })
|
||||
* // -> Some(2)
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* lazy_or(None, fn() { None })
|
||||
* // -> None
|
||||
* ```
|
||||
*/
|
||||
export function lazy_or(first, second) {
|
||||
if (first instanceof Some) {
|
||||
return first;
|
||||
} else {
|
||||
return second();
|
||||
}
|
||||
}
|
||||
|
||||
function values_loop(loop$list, loop$acc) {
|
||||
while (true) {
|
||||
let list = loop$list;
|
||||
let acc = loop$acc;
|
||||
if (list instanceof $Empty) {
|
||||
return reverse(acc);
|
||||
} else {
|
||||
let $ = list.head;
|
||||
if ($ instanceof Some) {
|
||||
let rest = list.tail;
|
||||
let first = $[0];
|
||||
loop$list = rest;
|
||||
loop$acc = listPrepend(first, acc);
|
||||
} else {
|
||||
let rest = list.tail;
|
||||
loop$list = rest;
|
||||
loop$acc = acc;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a list of `Option`s,
|
||||
* returns only the values inside `Some`.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* values([Some(1), None, Some(3)])
|
||||
* // -> [1, 3]
|
||||
* ```
|
||||
*/
|
||||
export function values(options) {
|
||||
return values_loop(options, toList([]));
|
||||
}
|
||||
178
build/dev/javascript/gleam_stdlib/gleam/order.mjs
Normal file
178
build/dev/javascript/gleam_stdlib/gleam/order.mjs
Normal file
|
|
@ -0,0 +1,178 @@
|
|||
import { CustomType as $CustomType, isEqual } from "../gleam.mjs";
|
||||
|
||||
export class Lt extends $CustomType {}
|
||||
export const Order$Lt = () => new Lt();
|
||||
export const Order$isLt = (value) => value instanceof Lt;
|
||||
|
||||
export class Eq extends $CustomType {}
|
||||
export const Order$Eq = () => new Eq();
|
||||
export const Order$isEq = (value) => value instanceof Eq;
|
||||
|
||||
export class Gt extends $CustomType {}
|
||||
export const Order$Gt = () => new Gt();
|
||||
export const Order$isGt = (value) => value instanceof Gt;
|
||||
|
||||
/**
|
||||
* Inverts an order, so less-than becomes greater-than and greater-than
|
||||
* becomes less-than.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* negate(Lt)
|
||||
* // -> Gt
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* negate(Eq)
|
||||
* // -> Eq
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* negate(Gt)
|
||||
* // -> Lt
|
||||
* ```
|
||||
*/
|
||||
export function negate(order) {
|
||||
if (order instanceof Lt) {
|
||||
return new Gt();
|
||||
} else if (order instanceof Eq) {
|
||||
return order;
|
||||
} else {
|
||||
return new Lt();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Produces a numeric representation of the order.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* to_int(Lt)
|
||||
* // -> -1
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* to_int(Eq)
|
||||
* // -> 0
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* to_int(Gt)
|
||||
* // -> 1
|
||||
* ```
|
||||
*/
|
||||
export function to_int(order) {
|
||||
if (order instanceof Lt) {
|
||||
return -1;
|
||||
} else if (order instanceof Eq) {
|
||||
return 0;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares two `Order` values to one another, producing a new `Order`.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* compare(Eq, with: Lt)
|
||||
* // -> Gt
|
||||
* ```
|
||||
*/
|
||||
export function compare(a, b) {
|
||||
let x = a;
|
||||
let y = b;
|
||||
if (isEqual(x, y)) {
|
||||
return new Eq();
|
||||
} else if (a instanceof Lt) {
|
||||
return new Lt();
|
||||
} else if (a instanceof Eq && b instanceof Gt) {
|
||||
return new Lt();
|
||||
} else {
|
||||
return new Gt();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Inverts an ordering function, so less-than becomes greater-than and greater-than
|
||||
* becomes less-than.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* import gleam/int
|
||||
* import gleam/list
|
||||
*
|
||||
* list.sort([1, 5, 4], by: reverse(int.compare))
|
||||
* // -> [5, 4, 1]
|
||||
* ```
|
||||
*/
|
||||
export function reverse(orderer) {
|
||||
return (a, b) => { return orderer(b, a); };
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a fallback `Order` in case the first argument is `Eq`.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* import gleam/int
|
||||
*
|
||||
* break_tie(in: int.compare(1, 1), with: Lt)
|
||||
* // -> Lt
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* import gleam/int
|
||||
*
|
||||
* break_tie(in: int.compare(1, 0), with: Eq)
|
||||
* // -> Gt
|
||||
* ```
|
||||
*/
|
||||
export function break_tie(order, other) {
|
||||
if (order instanceof Lt) {
|
||||
return order;
|
||||
} else if (order instanceof Eq) {
|
||||
return other;
|
||||
} else {
|
||||
return order;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Invokes a fallback function returning an `Order` in case the first argument
|
||||
* is `Eq`.
|
||||
*
|
||||
* This can be useful when the fallback comparison might be expensive and it
|
||||
* needs to be delayed until strictly necessary.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* import gleam/int
|
||||
*
|
||||
* lazy_break_tie(in: int.compare(1, 1), with: fn() { Lt })
|
||||
* // -> Lt
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* import gleam/int
|
||||
*
|
||||
* lazy_break_tie(in: int.compare(1, 0), with: fn() { Eq })
|
||||
* // -> Gt
|
||||
* ```
|
||||
*/
|
||||
export function lazy_break_tie(order, comparison) {
|
||||
if (order instanceof Lt) {
|
||||
return order;
|
||||
} else if (order instanceof Eq) {
|
||||
return comparison();
|
||||
} else {
|
||||
return order;
|
||||
}
|
||||
}
|
||||
102
build/dev/javascript/gleam_stdlib/gleam/pair.mjs
Normal file
102
build/dev/javascript/gleam_stdlib/gleam/pair.mjs
Normal file
|
|
@ -0,0 +1,102 @@
|
|||
/**
|
||||
* Returns the first element in a pair.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* first(#(1, 2))
|
||||
* // -> 1
|
||||
* ```
|
||||
*/
|
||||
export function first(pair) {
|
||||
let a;
|
||||
a = pair[0];
|
||||
return a;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the second element in a pair.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* second(#(1, 2))
|
||||
* // -> 2
|
||||
* ```
|
||||
*/
|
||||
export function second(pair) {
|
||||
let a;
|
||||
a = pair[1];
|
||||
return a;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new pair with the elements swapped.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* swap(#(1, 2))
|
||||
* // -> #(2, 1)
|
||||
* ```
|
||||
*/
|
||||
export function swap(pair) {
|
||||
let a;
|
||||
let b;
|
||||
a = pair[0];
|
||||
b = pair[1];
|
||||
return [b, a];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new pair with the first element having had `with` applied to
|
||||
* it.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* #(1, 2) |> map_first(fn(n) { n * 2 })
|
||||
* // -> #(2, 2)
|
||||
* ```
|
||||
*/
|
||||
export function map_first(pair, fun) {
|
||||
let a;
|
||||
let b;
|
||||
a = pair[0];
|
||||
b = pair[1];
|
||||
return [fun(a), b];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new pair with the second element having had `with` applied to
|
||||
* it.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* #(1, 2) |> map_second(fn(n) { n * 2 })
|
||||
* // -> #(1, 4)
|
||||
* ```
|
||||
*/
|
||||
export function map_second(pair, fun) {
|
||||
let a;
|
||||
let b;
|
||||
a = pair[0];
|
||||
b = pair[1];
|
||||
return [a, fun(b)];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new pair with the given elements. This can also be done using the dedicated
|
||||
* syntax instead: `new(1, 2) == #(1, 2)`.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* new(1, 2)
|
||||
* // -> #(1, 2)
|
||||
* ```
|
||||
*/
|
||||
export function new$(first, second) {
|
||||
return [first, second];
|
||||
}
|
||||
494
build/dev/javascript/gleam_stdlib/gleam/result.mjs
Normal file
494
build/dev/javascript/gleam_stdlib/gleam/result.mjs
Normal file
|
|
@ -0,0 +1,494 @@
|
|||
import { Ok, Error, toList, Empty as $Empty, prepend as listPrepend } from "../gleam.mjs";
|
||||
import * as $list from "../gleam/list.mjs";
|
||||
|
||||
/**
|
||||
* Checks whether the result is an `Ok` value.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* is_ok(Ok(1))
|
||||
* // -> True
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* is_ok(Error(Nil))
|
||||
* // -> False
|
||||
* ```
|
||||
*/
|
||||
export function is_ok(result) {
|
||||
if (result instanceof Ok) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the result is an `Error` value.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* is_error(Ok(1))
|
||||
* // -> False
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* is_error(Error(Nil))
|
||||
* // -> True
|
||||
* ```
|
||||
*/
|
||||
export function is_error(result) {
|
||||
if (result instanceof Ok) {
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates a value held within the `Ok` of a result by calling a given function
|
||||
* on it.
|
||||
*
|
||||
* If the result is an `Error` rather than `Ok` the function is not called and the
|
||||
* result stays the same.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* map(over: Ok(1), with: fn(x) { x + 1 })
|
||||
* // -> Ok(2)
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* map(over: Error(1), with: fn(x) { x + 1 })
|
||||
* // -> Error(1)
|
||||
* ```
|
||||
*/
|
||||
export function map(result, fun) {
|
||||
if (result instanceof Ok) {
|
||||
let x = result[0];
|
||||
return new Ok(fun(x));
|
||||
} else {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates a value held within the `Error` of a result by calling a given function
|
||||
* on it.
|
||||
*
|
||||
* If the result is `Ok` rather than `Error` the function is not called and the
|
||||
* result stays the same.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* map_error(over: Error(1), with: fn(x) { x + 1 })
|
||||
* // -> Error(2)
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* map_error(over: Ok(1), with: fn(x) { x + 1 })
|
||||
* // -> Ok(1)
|
||||
* ```
|
||||
*/
|
||||
export function map_error(result, fun) {
|
||||
if (result instanceof Ok) {
|
||||
return result;
|
||||
} else {
|
||||
let error = result[0];
|
||||
return new Error(fun(error));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Merges a nested `Result` into a single layer.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* flatten(Ok(Ok(1)))
|
||||
* // -> Ok(1)
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* flatten(Ok(Error("")))
|
||||
* // -> Error("")
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* flatten(Error(Nil))
|
||||
* // -> Error(Nil)
|
||||
* ```
|
||||
*/
|
||||
export function flatten(result) {
|
||||
if (result instanceof Ok) {
|
||||
let x = result[0];
|
||||
return x;
|
||||
} else {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* "Updates" an `Ok` result by passing its value to a function that yields a result,
|
||||
* and returning the yielded result. (This may "replace" the `Ok` with an `Error`.)
|
||||
*
|
||||
* If the input is an `Error` rather than an `Ok`, the function is not called and
|
||||
* the original `Error` is returned.
|
||||
*
|
||||
* This function is the equivalent of calling `map` followed by `flatten`, and
|
||||
* it is useful for chaining together multiple functions that may fail.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* try(Ok(1), fn(x) { Ok(x + 1) })
|
||||
* // -> Ok(2)
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* try(Ok(1), fn(x) { Ok(#("a", x)) })
|
||||
* // -> Ok(#("a", 1))
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* try(Ok(1), fn(_) { Error("Oh no") })
|
||||
* // -> Error("Oh no")
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* try(Error(Nil), fn(x) { Ok(x + 1) })
|
||||
* // -> Error(Nil)
|
||||
* ```
|
||||
*/
|
||||
export function try$(result, fun) {
|
||||
if (result instanceof Ok) {
|
||||
let x = result[0];
|
||||
return fun(x);
|
||||
} else {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
export function then$(result, fun) {
|
||||
return try$(result, fun);
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the `Ok` value from a result, returning a default value if the result
|
||||
* is an `Error`.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* unwrap(Ok(1), 0)
|
||||
* // -> 1
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* unwrap(Error(""), 0)
|
||||
* // -> 0
|
||||
* ```
|
||||
*/
|
||||
export function unwrap(result, default$) {
|
||||
if (result instanceof Ok) {
|
||||
let v = result[0];
|
||||
return v;
|
||||
} else {
|
||||
return default$;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the `Ok` value from a result, evaluating the default function if the result
|
||||
* is an `Error`.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* lazy_unwrap(Ok(1), fn() { 0 })
|
||||
* // -> 1
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* lazy_unwrap(Error(""), fn() { 0 })
|
||||
* // -> 0
|
||||
* ```
|
||||
*/
|
||||
export function lazy_unwrap(result, default$) {
|
||||
if (result instanceof Ok) {
|
||||
let v = result[0];
|
||||
return v;
|
||||
} else {
|
||||
return default$();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the `Error` value from a result, returning a default value if the result
|
||||
* is an `Ok`.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* unwrap_error(Error(1), 0)
|
||||
* // -> 1
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* unwrap_error(Ok(""), 0)
|
||||
* // -> 0
|
||||
* ```
|
||||
*/
|
||||
export function unwrap_error(result, default$) {
|
||||
if (result instanceof Ok) {
|
||||
return default$;
|
||||
} else {
|
||||
let e = result[0];
|
||||
return e;
|
||||
}
|
||||
}
|
||||
|
||||
export function unwrap_both(result) {
|
||||
if (result instanceof Ok) {
|
||||
let a = result[0];
|
||||
return a;
|
||||
} else {
|
||||
let a = result[0];
|
||||
return a;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the first value if it is `Ok`, otherwise returns the second value.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* or(Ok(1), Ok(2))
|
||||
* // -> Ok(1)
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* or(Ok(1), Error("Error 2"))
|
||||
* // -> Ok(1)
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* or(Error("Error 1"), Ok(2))
|
||||
* // -> Ok(2)
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* or(Error("Error 1"), Error("Error 2"))
|
||||
* // -> Error("Error 2")
|
||||
* ```
|
||||
*/
|
||||
export function or(first, second) {
|
||||
if (first instanceof Ok) {
|
||||
return first;
|
||||
} else {
|
||||
return second;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the first value if it is `Ok`, otherwise evaluates the given function for a fallback value.
|
||||
*
|
||||
* If you need access to the initial error value, use `result.try_recover`.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* lazy_or(Ok(1), fn() { Ok(2) })
|
||||
* // -> Ok(1)
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* lazy_or(Ok(1), fn() { Error("Error 2") })
|
||||
* // -> Ok(1)
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* lazy_or(Error("Error 1"), fn() { Ok(2) })
|
||||
* // -> Ok(2)
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* lazy_or(Error("Error 1"), fn() { Error("Error 2") })
|
||||
* // -> Error("Error 2")
|
||||
* ```
|
||||
*/
|
||||
export function lazy_or(first, second) {
|
||||
if (first instanceof Ok) {
|
||||
return first;
|
||||
} else {
|
||||
return second();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Combines a list of results into a single result.
|
||||
* If all elements in the list are `Ok` then returns an `Ok` holding the list of values.
|
||||
* If any element is `Error` then returns the first error.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* all([Ok(1), Ok(2)])
|
||||
* // -> Ok([1, 2])
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* all([Ok(1), Error("e")])
|
||||
* // -> Error("e")
|
||||
* ```
|
||||
*/
|
||||
export function all(results) {
|
||||
return $list.try_map(results, (result) => { return result; });
|
||||
}
|
||||
|
||||
function partition_loop(loop$results, loop$oks, loop$errors) {
|
||||
while (true) {
|
||||
let results = loop$results;
|
||||
let oks = loop$oks;
|
||||
let errors = loop$errors;
|
||||
if (results instanceof $Empty) {
|
||||
return [oks, errors];
|
||||
} else {
|
||||
let $ = results.head;
|
||||
if ($ instanceof Ok) {
|
||||
let rest = results.tail;
|
||||
let a = $[0];
|
||||
loop$results = rest;
|
||||
loop$oks = listPrepend(a, oks);
|
||||
loop$errors = errors;
|
||||
} else {
|
||||
let rest = results.tail;
|
||||
let e = $[0];
|
||||
loop$results = rest;
|
||||
loop$oks = oks;
|
||||
loop$errors = listPrepend(e, errors);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a list of results, returns a pair where the first element is a list
|
||||
* of all the values inside `Ok` and the second element is a list with all the
|
||||
* values inside `Error`. The values in both lists appear in reverse order with
|
||||
* respect to their position in the original list of results.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* partition([Ok(1), Error("a"), Error("b"), Ok(2)])
|
||||
* // -> #([2, 1], ["b", "a"])
|
||||
* ```
|
||||
*/
|
||||
export function partition(results) {
|
||||
return partition_loop(results, toList([]), toList([]));
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace the value within a result
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* replace(Ok(1), Nil)
|
||||
* // -> Ok(Nil)
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* replace(Error(1), Nil)
|
||||
* // -> Error(1)
|
||||
* ```
|
||||
*/
|
||||
export function replace(result, value) {
|
||||
if (result instanceof Ok) {
|
||||
return new Ok(value);
|
||||
} else {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace the error within a result
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* replace_error(Error(1), Nil)
|
||||
* // -> Error(Nil)
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* replace_error(Ok(1), Nil)
|
||||
* // -> Ok(1)
|
||||
* ```
|
||||
*/
|
||||
export function replace_error(result, error) {
|
||||
if (result instanceof Ok) {
|
||||
return result;
|
||||
} else {
|
||||
return new Error(error);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a list of results, returns only the values inside `Ok`.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* values([Ok(1), Error("a"), Ok(3)])
|
||||
* // -> [1, 3]
|
||||
* ```
|
||||
*/
|
||||
export function values(results) {
|
||||
return $list.filter_map(results, (result) => { return result; });
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates a value held within the `Error` of a result by calling a given function
|
||||
* on it, where the given function also returns a result. The two results are
|
||||
* then merged together into one result.
|
||||
*
|
||||
* If the result is an `Ok` rather than `Error` the function is not called and the
|
||||
* result stays the same.
|
||||
*
|
||||
* This function is useful for chaining together computations that may fail
|
||||
* and trying to recover from possible errors.
|
||||
*
|
||||
* If you do not need access to the initial error value, use `result.lazy_or`.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* Ok(1) |> try_recover(with: fn(_) { Error("failed to recover") })
|
||||
* // -> Ok(1)
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* Error(1) |> try_recover(with: fn(error) { Ok(error + 1) })
|
||||
* // -> Ok(2)
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* Error(1) |> try_recover(with: fn(error) { Error("failed to recover") })
|
||||
* // -> Error("failed to recover")
|
||||
* ```
|
||||
*/
|
||||
export function try_recover(result, fun) {
|
||||
if (result instanceof Ok) {
|
||||
return result;
|
||||
} else {
|
||||
let error = result[0];
|
||||
return fun(error);
|
||||
}
|
||||
}
|
||||
412
build/dev/javascript/gleam_stdlib/gleam/set.mjs
Normal file
412
build/dev/javascript/gleam_stdlib/gleam/set.mjs
Normal file
|
|
@ -0,0 +1,412 @@
|
|||
import { CustomType as $CustomType, isEqual } from "../gleam.mjs";
|
||||
import * as $dict from "../gleam/dict.mjs";
|
||||
import * as $list from "../gleam/list.mjs";
|
||||
import * as $result from "../gleam/result.mjs";
|
||||
|
||||
class Set extends $CustomType {
|
||||
constructor(dict) {
|
||||
super();
|
||||
this.dict = dict;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new empty set.
|
||||
*/
|
||||
export function new$() {
|
||||
return new Set($dict.new$());
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the number of members in a set.
|
||||
*
|
||||
* This function runs in constant time.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* new()
|
||||
* |> insert(1)
|
||||
* |> insert(2)
|
||||
* |> size
|
||||
* // -> 2
|
||||
* ```
|
||||
*/
|
||||
export function size(set) {
|
||||
return $dict.size(set.dict);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether or not the set is empty.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* new() |> is_empty
|
||||
* // -> True
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* new() |> insert(1) |> is_empty
|
||||
* // -> False
|
||||
* ```
|
||||
*/
|
||||
export function is_empty(set) {
|
||||
return isEqual(set, new$());
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether a set contains a given member.
|
||||
*
|
||||
* This function runs in logarithmic time.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* new()
|
||||
* |> insert(2)
|
||||
* |> contains(2)
|
||||
* // -> True
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* new()
|
||||
* |> insert(2)
|
||||
* |> contains(1)
|
||||
* // -> False
|
||||
* ```
|
||||
*/
|
||||
export function contains(set, member) {
|
||||
let _pipe = set.dict;
|
||||
let _pipe$1 = $dict.get(_pipe, member);
|
||||
return $result.is_ok(_pipe$1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a member from a set. If the set does not contain the member then
|
||||
* the set is returned unchanged.
|
||||
*
|
||||
* This function runs in logarithmic time.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* new()
|
||||
* |> insert(2)
|
||||
* |> delete(2)
|
||||
* |> contains(1)
|
||||
* // -> False
|
||||
* ```
|
||||
*/
|
||||
export function delete$(set, member) {
|
||||
return new Set($dict.delete$(set.dict, member));
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the set into a list of the contained members.
|
||||
*
|
||||
* The list has no specific ordering, any unintentional ordering may change in
|
||||
* future versions of Gleam or Erlang.
|
||||
*
|
||||
* This function runs in linear time.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* new() |> insert(2) |> to_list
|
||||
* // -> [2]
|
||||
* ```
|
||||
*/
|
||||
export function to_list(set) {
|
||||
return $dict.keys(set.dict);
|
||||
}
|
||||
|
||||
/**
|
||||
* Combines all entries into a single value by calling a given function on each
|
||||
* one.
|
||||
*
|
||||
* Sets are not ordered so the values are not returned in any specific order.
|
||||
* Do not write code that relies on the order entries are used by this
|
||||
* function as it may change in later versions of Gleam or Erlang.
|
||||
*
|
||||
* # Examples
|
||||
*
|
||||
* ```gleam
|
||||
* from_list([1, 3, 9])
|
||||
* |> fold(0, fn(accumulator, member) { accumulator + member })
|
||||
* // -> 13
|
||||
* ```
|
||||
*/
|
||||
export function fold(set, initial, reducer) {
|
||||
return $dict.fold(set.dict, initial, (a, k, _) => { return reducer(a, k); });
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new set from an existing set, minus any members that a given
|
||||
* function returns `False` for.
|
||||
*
|
||||
* This function runs in loglinear time.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* import gleam/int
|
||||
*
|
||||
* from_list([1, 4, 6, 3, 675, 44, 67])
|
||||
* |> filter(keeping: int.is_even)
|
||||
* |> to_list
|
||||
* // -> [4, 6, 44]
|
||||
* ```
|
||||
*/
|
||||
export function filter(set, predicate) {
|
||||
return new Set($dict.filter(set.dict, (m, _) => { return predicate(m); }));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new set from a given set with all the same entries except any
|
||||
* entry found on the given list.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* from_list([1, 2, 3, 4])
|
||||
* |> drop([1, 3])
|
||||
* |> to_list
|
||||
* // -> [2, 4]
|
||||
* ```
|
||||
*/
|
||||
export function drop(set, disallowed) {
|
||||
return $list.fold(disallowed, set, delete$);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new set from a given set, only including any members which are in
|
||||
* a given list.
|
||||
*
|
||||
* This function runs in loglinear time.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* from_list([1, 2, 3])
|
||||
* |> take([1, 3, 5])
|
||||
* |> to_list
|
||||
* // -> [1, 3]
|
||||
* ```
|
||||
*/
|
||||
export function take(set, desired) {
|
||||
return new Set($dict.take(set.dict, desired));
|
||||
}
|
||||
|
||||
function order(first, second) {
|
||||
let $ = $dict.size(first.dict) > $dict.size(second.dict);
|
||||
if ($) {
|
||||
return [first, second];
|
||||
} else {
|
||||
return [second, first];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new set that contains members that are present in both given sets.
|
||||
*
|
||||
* This function runs in loglinear time.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* intersection(from_list([1, 2]), from_list([2, 3])) |> to_list
|
||||
* // -> [2]
|
||||
* ```
|
||||
*/
|
||||
export function intersection(first, second) {
|
||||
let $ = order(first, second);
|
||||
let larger;
|
||||
let smaller;
|
||||
larger = $[0];
|
||||
smaller = $[1];
|
||||
return take(larger, to_list(smaller));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new set that contains members that are present in the first set
|
||||
* but not the second.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* difference(from_list([1, 2]), from_list([2, 3, 4])) |> to_list
|
||||
* // -> [1]
|
||||
* ```
|
||||
*/
|
||||
export function difference(first, second) {
|
||||
return drop(first, to_list(second));
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if a set is fully contained by another.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* is_subset(from_list([1]), from_list([1, 2]))
|
||||
* // -> True
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* is_subset(from_list([1, 2, 3]), from_list([3, 4, 5]))
|
||||
* // -> False
|
||||
* ```
|
||||
*/
|
||||
export function is_subset(first, second) {
|
||||
return isEqual(intersection(first, second), first);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if two sets contain no common members
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* is_disjoint(from_list([1, 2, 3]), from_list([4, 5, 6]))
|
||||
* // -> True
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* is_disjoint(from_list([1, 2, 3]), from_list([3, 4, 5]))
|
||||
* // -> False
|
||||
* ```
|
||||
*/
|
||||
export function is_disjoint(first, second) {
|
||||
return isEqual(intersection(first, second), new$());
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls a function for each member in a set, discarding the return
|
||||
* value.
|
||||
*
|
||||
* Useful for producing a side effect for every item of a set.
|
||||
*
|
||||
* ```gleam
|
||||
* let set = from_list(["apple", "banana", "cherry"])
|
||||
*
|
||||
* each(set, io.println)
|
||||
* // -> Nil
|
||||
* // apple
|
||||
* // banana
|
||||
* // cherry
|
||||
* ```
|
||||
*
|
||||
* The order of elements in the iteration is an implementation detail that
|
||||
* should not be relied upon.
|
||||
*/
|
||||
export function each(set, fun) {
|
||||
return fold(
|
||||
set,
|
||||
undefined,
|
||||
(nil, member) => {
|
||||
fun(member);
|
||||
return nil;
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
const token = undefined;
|
||||
|
||||
/**
|
||||
* Inserts an member into the set.
|
||||
*
|
||||
* This function runs in logarithmic time.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* new()
|
||||
* |> insert(1)
|
||||
* |> insert(2)
|
||||
* |> size
|
||||
* // -> 2
|
||||
* ```
|
||||
*/
|
||||
export function insert(set, member) {
|
||||
return new Set($dict.insert(set.dict, member, token));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new set of the members in a given list.
|
||||
*
|
||||
* This function runs in loglinear time.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* import gleam/int
|
||||
* import gleam/list
|
||||
*
|
||||
* [1, 1, 2, 4, 3, 2] |> from_list |> to_list |> list.sort(by: int.compare)
|
||||
* // -> [1, 2, 3, 4]
|
||||
* ```
|
||||
*/
|
||||
export function from_list(members) {
|
||||
let dict = $list.fold(
|
||||
members,
|
||||
$dict.new$(),
|
||||
(m, k) => { return $dict.insert(m, k, token); },
|
||||
);
|
||||
return new Set(dict);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new set from a given set with the result of applying the given
|
||||
* function to each member.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* from_list([1, 2, 3, 4])
|
||||
* |> map(with: fn(x) { x * 2 })
|
||||
* |> to_list
|
||||
* // -> [2, 4, 6, 8]
|
||||
* ```
|
||||
*/
|
||||
export function map(set, fun) {
|
||||
return fold(
|
||||
set,
|
||||
new$(),
|
||||
(acc, member) => { return insert(acc, fun(member)); },
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new set that contains all members of both given sets.
|
||||
*
|
||||
* This function runs in loglinear time.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* union(from_list([1, 2]), from_list([2, 3])) |> to_list
|
||||
* // -> [1, 2, 3]
|
||||
* ```
|
||||
*/
|
||||
export function union(first, second) {
|
||||
let $ = order(first, second);
|
||||
let larger;
|
||||
let smaller;
|
||||
larger = $[0];
|
||||
smaller = $[1];
|
||||
return fold(smaller, larger, insert);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new set that contains members that are present in either set, but
|
||||
* not both.
|
||||
*
|
||||
* ```gleam
|
||||
* symmetric_difference(from_list([1, 2, 3]), from_list([3, 4])) |> to_list
|
||||
* // -> [1, 2, 4]
|
||||
* ```
|
||||
*/
|
||||
export function symmetric_difference(first, second) {
|
||||
return difference(union(first, second), intersection(first, second));
|
||||
}
|
||||
723
build/dev/javascript/gleam_stdlib/gleam/string.mjs
Normal file
723
build/dev/javascript/gleam_stdlib/gleam/string.mjs
Normal 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,
|
||||
);
|
||||
}
|
||||
}
|
||||
133
build/dev/javascript/gleam_stdlib/gleam/string_tree.mjs
Normal file
133
build/dev/javascript/gleam_stdlib/gleam/string_tree.mjs
Normal file
|
|
@ -0,0 +1,133 @@
|
|||
import { toList, CustomType as $CustomType, isEqual } from "../gleam.mjs";
|
||||
import * as $list from "../gleam/list.mjs";
|
||||
import {
|
||||
add as append_tree,
|
||||
concat as from_strings,
|
||||
concat,
|
||||
identity as from_string,
|
||||
identity as to_string,
|
||||
length as byte_size,
|
||||
lowercase,
|
||||
uppercase,
|
||||
graphemes as do_to_graphemes,
|
||||
split,
|
||||
string_replace as replace,
|
||||
} from "../gleam_stdlib.mjs";
|
||||
|
||||
export {
|
||||
append_tree,
|
||||
byte_size,
|
||||
concat,
|
||||
from_string,
|
||||
from_strings,
|
||||
lowercase,
|
||||
replace,
|
||||
split,
|
||||
to_string,
|
||||
uppercase,
|
||||
};
|
||||
|
||||
class All extends $CustomType {}
|
||||
|
||||
/**
|
||||
* Prepends some `StringTree` onto the start of another.
|
||||
*
|
||||
* Runs in constant time.
|
||||
*/
|
||||
export function prepend_tree(tree, prefix) {
|
||||
return append_tree(prefix, tree);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an empty `StringTree`. Useful as the start of a pipe chaining many
|
||||
* trees together.
|
||||
*/
|
||||
export function new$() {
|
||||
return from_strings(toList([]));
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepends a `String` onto the start of some `StringTree`.
|
||||
*
|
||||
* Runs in constant time.
|
||||
*/
|
||||
export function prepend(tree, prefix) {
|
||||
return append_tree(from_string(prefix), tree);
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends a `String` onto the end of some `StringTree`.
|
||||
*
|
||||
* Runs in constant time.
|
||||
*/
|
||||
export function append(tree, second) {
|
||||
return append_tree(tree, from_string(second));
|
||||
}
|
||||
|
||||
/**
|
||||
* Joins the given trees into a new tree separated with the given string.
|
||||
*/
|
||||
export function join(trees, sep) {
|
||||
let _pipe = trees;
|
||||
let _pipe$1 = $list.intersperse(_pipe, from_string(sep));
|
||||
return concat(_pipe$1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a `StringTree` to a new one with the contents reversed.
|
||||
*/
|
||||
export function reverse(tree) {
|
||||
let _pipe = tree;
|
||||
let _pipe$1 = to_string(_pipe);
|
||||
let _pipe$2 = do_to_graphemes(_pipe$1);
|
||||
let _pipe$3 = $list.reverse(_pipe$2);
|
||||
return from_strings(_pipe$3);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares two string trees to determine if they have the same textual
|
||||
* content.
|
||||
*
|
||||
* Comparing two string trees using the `==` operator may return `False` even
|
||||
* if they have the same content as they may have been build in different ways,
|
||||
* so using this function is often preferred.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* from_strings(["a", "b"]) == from_string("ab")
|
||||
* // -> False
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* is_equal(from_strings(["a", "b"]), from_string("ab"))
|
||||
* // -> True
|
||||
* ```
|
||||
*/
|
||||
export function is_equal(a, b) {
|
||||
return isEqual(a, b);
|
||||
}
|
||||
|
||||
/**
|
||||
* Inspects a `StringTree` to determine if it is equivalent to an empty string.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* from_string("ok") |> is_empty
|
||||
* // -> False
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* from_string("") |> is_empty
|
||||
* // -> True
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* from_strings([]) |> is_empty
|
||||
* // -> True
|
||||
* ```
|
||||
*/
|
||||
export function is_empty(tree) {
|
||||
return isEqual(from_string(""), tree);
|
||||
}
|
||||
1147
build/dev/javascript/gleam_stdlib/gleam/uri.mjs
Normal file
1147
build/dev/javascript/gleam_stdlib/gleam/uri.mjs
Normal file
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue