diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..796b96d --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/build diff --git a/README.md b/README.md index e63a703..676d334 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,8 @@ -# Stellar prune +# Stellar prune A clicking game where you prune stars and diamonds from the cosmos. Built with Gleam for the gleam game jam of 2025. +![Demo](demo.gif) + ## How to Play - Click on stars and diamonds as jump up - Avoid the volatile rockets! diff --git a/build/dev/javascript/gleam_community_colour/_gleam_artefacts/gleam_community@colour.cache b/build/dev/javascript/gleam_community_colour/_gleam_artefacts/gleam_community@colour.cache deleted file mode 100644 index 1c43dda..0000000 Binary files a/build/dev/javascript/gleam_community_colour/_gleam_artefacts/gleam_community@colour.cache and /dev/null differ diff --git a/build/dev/javascript/gleam_community_colour/_gleam_artefacts/gleam_community@colour.cache_inline b/build/dev/javascript/gleam_community_colour/_gleam_artefacts/gleam_community@colour.cache_inline deleted file mode 100644 index 1b1cb4d..0000000 Binary files a/build/dev/javascript/gleam_community_colour/_gleam_artefacts/gleam_community@colour.cache_inline and /dev/null differ diff --git a/build/dev/javascript/gleam_community_colour/_gleam_artefacts/gleam_community@colour.cache_meta b/build/dev/javascript/gleam_community_colour/_gleam_artefacts/gleam_community@colour.cache_meta deleted file mode 100644 index 963c8c5..0000000 Binary files a/build/dev/javascript/gleam_community_colour/_gleam_artefacts/gleam_community@colour.cache_meta and /dev/null differ diff --git a/build/dev/javascript/gleam_community_colour/_gleam_artefacts/gleam_community@colour@accessibility.cache b/build/dev/javascript/gleam_community_colour/_gleam_artefacts/gleam_community@colour@accessibility.cache deleted file mode 100644 index 5a927a8..0000000 Binary files a/build/dev/javascript/gleam_community_colour/_gleam_artefacts/gleam_community@colour@accessibility.cache and /dev/null differ diff --git a/build/dev/javascript/gleam_community_colour/_gleam_artefacts/gleam_community@colour@accessibility.cache_inline b/build/dev/javascript/gleam_community_colour/_gleam_artefacts/gleam_community@colour@accessibility.cache_inline deleted file mode 100644 index 1b1cb4d..0000000 Binary files a/build/dev/javascript/gleam_community_colour/_gleam_artefacts/gleam_community@colour@accessibility.cache_inline and /dev/null differ diff --git a/build/dev/javascript/gleam_community_colour/_gleam_artefacts/gleam_community@colour@accessibility.cache_meta b/build/dev/javascript/gleam_community_colour/_gleam_artefacts/gleam_community@colour@accessibility.cache_meta deleted file mode 100644 index b367370..0000000 Binary files a/build/dev/javascript/gleam_community_colour/_gleam_artefacts/gleam_community@colour@accessibility.cache_meta and /dev/null differ diff --git a/build/dev/javascript/gleam_community_colour/gleam.mjs b/build/dev/javascript/gleam_community_colour/gleam.mjs deleted file mode 100644 index 197cbbc..0000000 --- a/build/dev/javascript/gleam_community_colour/gleam.mjs +++ /dev/null @@ -1 +0,0 @@ -export * from "../prelude.mjs"; diff --git a/build/dev/javascript/gleam_community_colour/gleam_community/colour.mjs b/build/dev/javascript/gleam_community_colour/gleam_community/colour.mjs deleted file mode 100644 index 164bd50..0000000 --- a/build/dev/javascript/gleam_community_colour/gleam_community/colour.mjs +++ /dev/null @@ -1,1444 +0,0 @@ -import * as $json from "../../gleam_json/gleam/json.mjs"; -import * as $decode from "../../gleam_stdlib/gleam/dynamic/decode.mjs"; -import * as $float from "../../gleam_stdlib/gleam/float.mjs"; -import * as $int from "../../gleam_stdlib/gleam/int.mjs"; -import * as $list from "../../gleam_stdlib/gleam/list.mjs"; -import * as $result from "../../gleam_stdlib/gleam/result.mjs"; -import * as $string from "../../gleam_stdlib/gleam/string.mjs"; -import { Ok, Error, toList, CustomType as $CustomType, makeError, divideFloat } from "../gleam.mjs"; - -const FILEPATH = "src/gleam_community/colour.gleam"; - -class Rgba extends $CustomType { - constructor(r, g, b, a) { - super(); - this.r = r; - this.g = g; - this.b = b; - this.a = a; - } -} - -class Hsla extends $CustomType { - constructor(h, s, l, a) { - super(); - this.h = h; - this.s = s; - this.l = l; - this.a = a; - } -} - -function valid_colour_value(c) { - let $ = (c > 1.0) || (c < 0.0); - if ($) { - return new Error(undefined); - } else { - return new Ok(c); - } -} - -function hue_to_rgb(hue, m1, m2) { - let _block; - if (hue < 0.0) { - _block = hue + 1.0; - } else if (hue > 1.0) { - _block = hue - 1.0; - } else { - _block = hue; - } - let h = _block; - let h_t_6 = h * 6.0; - let h_t_2 = h * 2.0; - let h_t_3 = h * 3.0; - if (h_t_6 < 1.0) { - return m1 + (((m2 - m1) * h) * 6.0); - } else if (h_t_2 < 1.0) { - return m2; - } else if (h_t_3 < 2.0) { - return m1 + (((m2 - m1) * ((2.0 / 3.0) - h)) * 6.0); - } else { - return m1; - } -} - -function hex_string_to_int(hex_string) { - let _block; - if (hex_string.startsWith("#")) { - let hex_number = hex_string.slice(1); - _block = hex_number; - } else if (hex_string.startsWith("0x")) { - let hex_number = hex_string.slice(2); - _block = hex_number; - } else { - _block = hex_string; - } - let hex = _block; - let _pipe = hex; - let _pipe$1 = $string.lowercase(_pipe); - let _pipe$2 = $string.to_graphemes(_pipe$1); - let _pipe$3 = $list.reverse(_pipe$2); - return $list.index_fold( - _pipe$3, - new Ok(0), - (total, char, index) => { - if (total instanceof Ok) { - let v = total[0]; - return $result.try$( - (() => { - if (char === "a") { - return new Ok(10); - } else if (char === "b") { - return new Ok(11); - } else if (char === "c") { - return new Ok(12); - } else if (char === "d") { - return new Ok(13); - } else if (char === "e") { - return new Ok(14); - } else if (char === "f") { - return new Ok(15); - } else { - return $int.parse(char); - } - })(), - (num) => { - return $result.try$( - $int.power(16, $int.to_float(index)), - (base) => { - return new Ok(v + $float.round($int.to_float(num) * base)); - }, - ); - }, - ); - } else { - return total; - } - }, - ); -} - -function hsla_to_rgba(h, s, l, a) { - let _block; - let $ = l <= 0.5; - if ($) { - _block = l * (s + 1.0); - } else { - _block = (l + s) - (l * s); - } - let m2 = _block; - let m1 = (l * 2.0) - m2; - let r = hue_to_rgb(h + (1.0 / 3.0), m1, m2); - let g = hue_to_rgb(h, m1, m2); - let b = hue_to_rgb(h - (1.0 / 3.0), m1, m2); - return [r, g, b, a]; -} - -function rgba_to_hsla(r, g, b, a) { - let min_colour = $float.min(r, $float.min(g, b)); - let max_colour = $float.max(r, $float.max(g, b)); - let _block; - let $ = true; - if (max_colour === r) { - _block = $float.divide(g - b, max_colour - min_colour); - } else if (max_colour === g) { - let _pipe = $float.divide(b - r, max_colour - min_colour); - _block = $result.try$(_pipe, (d) => { return new Ok(2.0 + d); }); - } else { - let _pipe = $float.divide(r - g, max_colour - min_colour); - _block = $result.try$(_pipe, (d) => { return new Ok(4.0 + d); }); - } - let h1 = _block; - let _block$1; - if (h1 instanceof Ok) { - let v = h1[0]; - _block$1 = new Ok(v * (1.0 / 6.0)); - } else { - _block$1 = h1; - } - let h2 = _block$1; - let _block$2; - if (h2 instanceof Ok) { - let v = h2[0]; - if (v < 0.0) { - _block$2 = v + 1.0; - } else { - let v$1 = h2[0]; - _block$2 = v$1; - } - } else { - _block$2 = 0.0; - } - let h3 = _block$2; - let l = (min_colour + max_colour) / 2.0; - let _block$3; - let $1 = true; - if (min_colour === max_colour) { - _block$3 = 0.0; - } else if (l < 0.5) { - _block$3 = divideFloat((max_colour - min_colour), (max_colour + min_colour)); - } else { - _block$3 = divideFloat( - (max_colour - min_colour), - ((2.0 - max_colour) - min_colour) - ); - } - let s = _block$3; - return [h3, s, l, a]; -} - -/** - * Returns a `Result(Colour)` created from the given 8 bit RGB values. - * - * Returns `Error(Nil)` if the supplied RGB values are greater than 255 or less than 0. - * - *
- * Example: - * - * ```gleam - * fn example() { - * assert Ok(red) = from_rgb255(255, 0, 0) - * } - * ``` - *
- * - *
- * - * Spot a typo? Open an issue! - * - * - * Back to top ↑ - * - *
- */ -export function from_rgb255(red, green, blue) { - return $result.try$( - (() => { - let _pipe = red; - let _pipe$1 = $int.to_float(_pipe); - let _pipe$2 = $float.divide(_pipe$1, 255.0); - return $result.try$(_pipe$2, valid_colour_value); - })(), - (r) => { - return $result.try$( - (() => { - let _pipe = green; - let _pipe$1 = $int.to_float(_pipe); - let _pipe$2 = $float.divide(_pipe$1, 255.0); - return $result.try$(_pipe$2, valid_colour_value); - })(), - (g) => { - return $result.try$( - (() => { - let _pipe = blue; - let _pipe$1 = $int.to_float(_pipe); - let _pipe$2 = $float.divide(_pipe$1, 255.0); - return $result.try$(_pipe$2, valid_colour_value); - })(), - (b) => { return new Ok(new Rgba(r, g, b, 1.0)); }, - ); - }, - ); - }, - ); -} - -/** - * Returns `Result(Colour)` created from the given RGB values. - * - * If the supplied RGB values are greater than 1.0 or less than 0.0 returns `Error(Nil)` - * - *
- * Example: - * - * ```gleam - * fn example() { - * assert Ok(red) = from_rgb(1.0, 0.0, 0.0) - * } - * ``` - *
- * - *
- * - * Spot a typo? Open an issue! - * - * - * Back to top ↑ - * - *
- */ -export function from_rgb(red, green, blue) { - return $result.try$( - valid_colour_value(red), - (r) => { - return $result.try$( - valid_colour_value(green), - (g) => { - return $result.try$( - valid_colour_value(blue), - (b) => { return new Ok(new Rgba(r, g, b, 1.0)); }, - ); - }, - ); - }, - ); -} - -/** - * Returns `Result(Colour)` created from the given RGBA values. - * - * Returns `Error(Nil)` if the supplied RGBA values are greater than 1.0 or less than 0.0. - * - *
- * Example: - * - * ```gleam - * fn example() { - * assert Ok(red_half_opacity) = from_rbga(1.0, 0.0, 0.0, 0.5) - * } - * ``` - *
- * - *
- * - * Spot a typo? Open an issue! - * - * - * Back to top ↑ - * - *
- */ -export function from_rgba(red, green, blue, alpha) { - return $result.try$( - valid_colour_value(red), - (r) => { - return $result.try$( - valid_colour_value(green), - (g) => { - return $result.try$( - valid_colour_value(blue), - (b) => { - return $result.try$( - valid_colour_value(alpha), - (a) => { return new Ok(new Rgba(r, g, b, a)); }, - ); - }, - ); - }, - ); - }, - ); -} - -/** - * Returns `Result(Colour)` created from the given HSLA values. - * - * Returns `Error(Nil)`f the supplied HSLA values are greater than 1.0 or less than 0.0. - * - *
- * Example: - * - * ```gleam - * fn example() { - * assert Ok(red_half_opacity) = from_hsla(0.0, 1.0, 0.5, 0.5) - * } - * ``` - *
- * - *
- * - * Spot a typo? Open an issue! - * - * - * Back to top ↑ - * - *
- */ -export function from_hsla(hue, saturation, lightness, alpha) { - return $result.try$( - valid_colour_value(hue), - (h) => { - return $result.try$( - valid_colour_value(saturation), - (s) => { - return $result.try$( - valid_colour_value(lightness), - (l) => { - return $result.try$( - valid_colour_value(alpha), - (a) => { return new Ok(new Hsla(h, s, l, a)); }, - ); - }, - ); - }, - ); - }, - ); -} - -/** - * Returns `Result(Colour)` created from the given HSL values. - * - * Returns `Error(Nil)` if the supplied HSL values are greater than 1.0 or less than 0.0. - * - *
- * Example: - * - * ```gleam - * fn example() { - * assert Ok(red) = from_hsla(0.0, 1.0, 0.5) - * } - * ``` - *
- * - *
- * - * Spot a typo? Open an issue! - * - * - * Back to top ↑ - * - *
- */ -export function from_hsl(hue, saturation, lightness) { - return from_hsla(hue, saturation, lightness, 1.0); -} - -/** - * Returns a `Result(Colour)` created from the given hex `Int`. - * - * Returns `Error(Nil)` if the supplied hex `Int is greater than 0xffffff or less than 0x0. - * - *
- * Example: - * - * ```gleam - * fn example() { - * assert Ok(red) = from_rgb_hex(0xff0000) - * } - * ``` - *
- * - *
- * - * Spot a typo? Open an issue! - * - * - * Back to top ↑ - * - *
- */ -export function from_rgb_hex(hex) { - let $ = (hex > 0xffffff) || (hex < 0); - if ($) { - return new Error(undefined); - } else { - let _block; - let _pipe = $int.bitwise_shift_right(hex, 16); - _block = $int.bitwise_and(_pipe, 0xff); - let r = _block; - let _block$1; - let _pipe$1 = $int.bitwise_shift_right(hex, 8); - _block$1 = $int.bitwise_and(_pipe$1, 0xff); - let g = _block$1; - let b = $int.bitwise_and(hex, 0xff); - return from_rgb255(r, g, b); - } -} - -/** - * Returns a `Result(Colour)` created from the given RGB hex `String`. - * - * Returns `Error(Nil)` if the supplied hex `String` is invalid, or greater than `"#ffffff" or less than `"#0"` - * - *
- * Example: - * - * ```gleam - * fn example() { - * assert Ok(red) = from_rgb_hex_string("#ff0000") - * } - * ``` - *
- * - *
- * - * Spot a typo? Open an issue! - * - * - * Back to top ↑ - * - *
- */ -export function from_rgb_hex_string(hex_string) { - return $result.try$( - hex_string_to_int(hex_string), - (hex_int) => { return from_rgb_hex(hex_int); }, - ); -} - -/** - * Returns a `Result(Colour)` created from the given hex `Int`. - * - * Returns `Error(Nil)` if the supplied hex `Int is greater than 0xffffffff or less than 0x0. - * - *
- * Example: - * - * ```gleam - * fn example() { - * assert Ok(red_half_opacity) = from_rgba_hex(0xff00007f) - * } - * ``` - *
- * - *
- * - * Spot a typo? Open an issue! - * - * - * Back to top ↑ - * - *
- */ -export function from_rgba_hex(hex) { - let $ = (hex > 0xffffffff) || (hex < 0); - if ($) { - return new Error(undefined); - } else { - let _block; - let _pipe = $int.bitwise_shift_right(hex, 24); - let _pipe$1 = $int.bitwise_and(_pipe, 0xff); - let _pipe$2 = $int.to_float(_pipe$1); - _block = $float.divide(_pipe$2, 255.0); - let $1 = _block; - let r; - if ($1 instanceof Ok) { - r = $1[0]; - } else { - throw makeError( - "let_assert", - FILEPATH, - "gleam_community/colour", - 590, - "from_rgba_hex", - "Pattern match failed, no pattern matched the value.", - { - value: $1, - start: 17111, - end: 17260, - pattern_start: 17122, - pattern_end: 17127 - } - ) - } - let _block$1; - let _pipe$3 = $int.bitwise_shift_right(hex, 16); - let _pipe$4 = $int.bitwise_and(_pipe$3, 0xff); - let _pipe$5 = $int.to_float(_pipe$4); - _block$1 = $float.divide(_pipe$5, 255.0); - let $2 = _block$1; - let g; - if ($2 instanceof Ok) { - g = $2[0]; - } else { - throw makeError( - "let_assert", - FILEPATH, - "gleam_community/colour", - 596, - "from_rgba_hex", - "Pattern match failed, no pattern matched the value.", - { - value: $2, - start: 17332, - end: 17481, - pattern_start: 17343, - pattern_end: 17348 - } - ) - } - let _block$2; - let _pipe$6 = $int.bitwise_shift_right(hex, 8); - let _pipe$7 = $int.bitwise_and(_pipe$6, 0xff); - let _pipe$8 = $int.to_float(_pipe$7); - _block$2 = $float.divide(_pipe$8, 255.0); - let $3 = _block$2; - let b; - if ($3 instanceof Ok) { - b = $3[0]; - } else { - throw makeError( - "let_assert", - FILEPATH, - "gleam_community/colour", - 602, - "from_rgba_hex", - "Pattern match failed, no pattern matched the value.", - { - value: $3, - start: 17553, - end: 17701, - pattern_start: 17564, - pattern_end: 17569 - } - ) - } - let _block$3; - let _pipe$9 = $int.bitwise_and(hex, 0xff); - let _pipe$10 = $int.to_float(_pipe$9); - _block$3 = $float.divide(_pipe$10, 255.0); - let $4 = _block$3; - let a; - if ($4 instanceof Ok) { - a = $4[0]; - } else { - throw makeError( - "let_assert", - FILEPATH, - "gleam_community/colour", - 608, - "from_rgba_hex", - "Pattern match failed, no pattern matched the value.", - { - value: $4, - start: 17773, - end: 17883, - pattern_start: 17784, - pattern_end: 17789 - } - ) - } - return from_rgba(r, g, b, a); - } -} - -/** - * Returns a `Result(Colour)` created from the given RGBA hex `String`. - * - * Returns `Error(Nil)` if the supplied hex `String` is invalid, or greater than `"#ffffffff" or less than `"#0"` - * - *
- * Example: - * - * ```gleam - * fn example() { - * assert Ok(red_half_opacity) = from_rgba_hex_string("#ff00007f") - * } - * ``` - *
- * - *
- * - * Spot a typo? Open an issue! - * - * - * Back to top ↑ - * - *
- */ -export function from_rgba_hex_string(hex_string) { - return $result.try$( - hex_string_to_int(hex_string), - (hex_int) => { return from_rgba_hex(hex_int); }, - ); -} - -/** - * Returns `#(Float, Float, Float, Float)` representing the given `Colour`'s - * R, G, B, and A values respectively. - * - *
- * Example: - * - * ```gleam - * fn example() { - * assert Ok(red) = from_rgb255(255, 0, 0) - * let #(r, g, b, a) = to_rgba(red) - * } - * ``` - *
- * - *
- * - * Spot a typo? Open an issue! - * - * - * Back to top ↑ - * - *
- */ -export function to_rgba(colour) { - if (colour instanceof Rgba) { - let r = colour.r; - let g = colour.g; - let b = colour.b; - let a = colour.a; - return [r, g, b, a]; - } else { - let h = colour.h; - let s = colour.s; - let l = colour.l; - let a = colour.a; - return hsla_to_rgba(h, s, l, a); - } -} - -/** - * Returns `#(Float, Float, Float, Float)` representing the given `Colour`'s - * H, S, L, and A values respectively. - * - *
- * Example: - * - * ```gleam - * fn example() { - * assert Ok(red) = from_rgb255(255, 0, 0) - * let #(h, s, l, a) = to_hsla(red) - * } - * ``` - *
- * - *
- * - * Spot a typo? Open an issue! - * - * - * Back to top ↑ - * - *
- */ -export function to_hsla(colour) { - if (colour instanceof Rgba) { - let r = colour.r; - let g = colour.g; - let b = colour.b; - let a = colour.a; - return rgba_to_hsla(r, g, b, a); - } else { - let h = colour.h; - let s = colour.s; - let l = colour.l; - let a = colour.a; - return [h, s, l, a]; - } -} - -/** - * Returns an rgba formatted CSS `String` created from the given `Colour`. - * - *
- * Example: - * - * ```gleam - * fn example() { - * assert Ok(red) = from_rgb255(255, 0, 0) - * let css_red = to_css_rgba_string(red) - * } - * ``` - *
- * - *
- * - * Spot a typo? Open an issue! - * - * - * Back to top ↑ - * - *
- */ -export function to_css_rgba_string(colour) { - let $ = to_rgba(colour); - let r; - let g; - let b; - let a; - r = $[0]; - g = $[1]; - b = $[2]; - a = $[3]; - let percent = (x) => { - let _block; - let _pipe = x; - let _pipe$1 = $float.multiply(_pipe, 10_000.0); - let _pipe$2 = $float.round(_pipe$1); - let _pipe$3 = $int.to_float(_pipe$2); - _block = $float.divide(_pipe$3, 100.0); - let $1 = _block; - let p; - if ($1 instanceof Ok) { - p = $1[0]; - } else { - throw makeError( - "let_assert", - FILEPATH, - "gleam_community/colour", - 706, - "to_css_rgba_string", - "Pattern match failed, no pattern matched the value.", - { - value: $1, - start: 20510, - end: 20646, - pattern_start: 20521, - pattern_end: 20526 - } - ) - } - return p; - }; - let round_to = (x) => { - let _block; - let _pipe = x; - let _pipe$1 = $float.multiply(_pipe, 1000.0); - let _pipe$2 = $float.round(_pipe$1); - let _pipe$3 = $int.to_float(_pipe$2); - _block = $float.divide(_pipe$3, 1000.0); - let $1 = _block; - let r$1; - if ($1 instanceof Ok) { - r$1 = $1[0]; - } else { - throw makeError( - "let_assert", - FILEPATH, - "gleam_community/colour", - 718, - "to_css_rgba_string", - "Pattern match failed, no pattern matched the value.", - { - value: $1, - start: 20768, - end: 20903, - pattern_start: 20779, - pattern_end: 20784 - } - ) - } - return r$1; - }; - return $string.join( - toList([ - "rgba(", - $float.to_string(percent(r)) + "%,", - $float.to_string(percent(g)) + "%,", - $float.to_string(percent(b)) + "%,", - $float.to_string(round_to(a)), - ")", - ]), - "", - ); -} - -/** - * Returns an hex `Int` created from the given `Colour`. - * - *
- * Example: - * - * ```gleam - * fn example() { - * assert Ok(red) = from_rgba(1.0, 0.0, 0.0, 1.0) - * let red_hex_int = to_rgba_hex(red) - * } - * ``` - *
- * - *
- * - * Spot a typo? Open an issue! - * - * - * Back to top ↑ - * - *
- */ -export function to_rgba_hex(colour) { - let $ = to_rgba(colour); - let r; - let g; - let b; - let a; - r = $[0]; - g = $[1]; - b = $[2]; - a = $[3]; - let _block; - let _pipe = r * 255.0; - let _pipe$1 = $float.round(_pipe); - _block = $int.bitwise_shift_left(_pipe$1, 24); - let red$1 = _block; - let _block$1; - let _pipe$2 = g * 255.0; - let _pipe$3 = $float.round(_pipe$2); - _block$1 = $int.bitwise_shift_left(_pipe$3, 16); - let green$1 = _block$1; - let _block$2; - let _pipe$4 = b * 255.0; - let _pipe$5 = $float.round(_pipe$4); - _block$2 = $int.bitwise_shift_left(_pipe$5, 8); - let blue$1 = _block$2; - let _block$3; - let _pipe$6 = a * 255.0; - _block$3 = $float.round(_pipe$6); - let alpha = _block$3; - return ((red$1 + green$1) + blue$1) + alpha; -} - -/** - * Returns an rgba hex formatted `String` created from the given `Colour`. - * - *
- * Example: - * - * ```gleam - * fn example() { - * assert Ok(red) = from_rgba(1.0, 0.0, 0.0, 1.0) - * let red_hex = to_rgba_hex_string(red) - * } - * ``` - *
- * - *
- * - * Spot a typo? Open an issue! - * - * - * Back to top ↑ - * - *
- */ -export function to_rgba_hex_string(colour) { - let _block; - let _pipe = to_rgba_hex(colour); - _block = $int.to_base16(_pipe); - let hex_string = _block; - let $ = $string.length(hex_string); - if ($ === 8) { - return hex_string; - } else { - let l = $; - return $string.repeat("0", 8 - l) + hex_string; - } -} - -/** - * Returns a rgb hex `Int` created from the given `Colour`. - * - *
- * Example: - * - * ```gleam - * fn example() { - * assert Ok(red) = from_rgba(255, 0, 0) - * let red_hex_int = to_rgb_hex(red) - * } - * ``` - *
- * - *
- * - * Spot a typo? Open an issue! - * - * - * Back to top ↑ - * - *
- */ -export function to_rgb_hex(colour) { - let $ = to_rgba(colour); - let r; - let g; - let b; - r = $[0]; - g = $[1]; - b = $[2]; - let _block; - let _pipe = r * 255.0; - let _pipe$1 = $float.round(_pipe); - _block = $int.bitwise_shift_left(_pipe$1, 16); - let red$1 = _block; - let _block$1; - let _pipe$2 = g * 255.0; - let _pipe$3 = $float.round(_pipe$2); - _block$1 = $int.bitwise_shift_left(_pipe$3, 8); - let green$1 = _block$1; - let _block$2; - let _pipe$4 = b * 255.0; - _block$2 = $float.round(_pipe$4); - let blue$1 = _block$2; - return (red$1 + green$1) + blue$1; -} - -/** - * Returns an rgb hex formatted `String` created from the given `Colour`. - * - *
- * Example: - * - * ```gleam - * fn example() { - * assert Ok(red) = from_rgba(255, 0, 0) - * let red_hex = to_rgb_hex_string(red) - * } - * ``` - *
- * - *
- * - * Spot a typo? Open an issue! - * - * - * Back to top ↑ - * - *
- */ -export function to_rgb_hex_string(colour) { - let _block; - let _pipe = to_rgb_hex(colour); - _block = $int.to_base16(_pipe); - let hex_string = _block; - let $ = $string.length(hex_string); - if ($ === 6) { - return hex_string; - } else { - let l = $; - return $string.repeat("0", 6 - l) + hex_string; - } -} - -function encode_rgba(r, g, b, a) { - return $json.object( - toList([ - ["r", $json.float(r)], - ["g", $json.float(g)], - ["b", $json.float(b)], - ["a", $json.float(a)], - ]), - ); -} - -function encode_hsla(h, s, l, a) { - return $json.object( - toList([ - ["h", $json.float(h)], - ["s", $json.float(s)], - ["l", $json.float(l)], - ["a", $json.float(a)], - ]), - ); -} - -/** - * Encodes a `Colour` value as a Gleam [`Json`](https://hexdocs.pm/gleam_json/gleam/json.html#Json) - * value. You'll need this if you want to send a `Colour` value over the network - * in a HTTP request or response, for example. - * - *
- * - * Spot a typo? Open an issue! - * - * - * Back to top ↑ - * - *
- */ -export function encode(colour) { - if (colour instanceof Rgba) { - let r = colour.r; - let g = colour.g; - let b = colour.b; - let a = colour.a; - return encode_rgba(r, g, b, a); - } else { - let h = colour.h; - let s = colour.s; - let l = colour.l; - let a = colour.a; - return encode_hsla(h, s, l, a); - } -} - -function rgba_decoder() { - return $decode.field( - "r", - $decode.float, - (r) => { - return $decode.field( - "g", - $decode.float, - (g) => { - return $decode.field( - "b", - $decode.float, - (b) => { - return $decode.field( - "a", - $decode.float, - (a) => { return $decode.success(new Rgba(r, g, b, a)); }, - ); - }, - ); - }, - ); - }, - ); -} - -function hsla_decoder() { - return $decode.field( - "h", - $decode.float, - (h) => { - return $decode.field( - "s", - $decode.float, - (s) => { - return $decode.field( - "l", - $decode.float, - (l) => { - return $decode.field( - "a", - $decode.float, - (a) => { return $decode.success(new Hsla(h, s, l, a)); }, - ); - }, - ); - }, - ); - }, - ); -} - -/** - * Attempt to decode some [`Dynamic`](https://hexdocs.pm/gleam_stdlib/gleam/dynamic.html#Dynamic) - * value into a `Colour`. Most often you'll use this to decode some JSON. - * - *
- * - * Spot a typo? Open an issue! - * - * - * Back to top ↑ - * - *
- */ -export function decoder() { - return $decode.one_of(rgba_decoder(), toList([hsla_decoder()])); -} - -/** - * A `Colour` reprsenting the colour RGBA(239, 41, 41, 1.0) - */ -export const light_red = /* @__PURE__ */ new Rgba( - 0.9372549019607843, - 0.1607843137254902, - 0.1607843137254902, - 1.0, -); - -/** - * A `Colour` reprsenting the colour RGBA(204, 0, 0, 1.0) - */ -export const red = /* @__PURE__ */ new Rgba(0.8, 0.0, 0.0, 1.0); - -/** - * A `Colour` reprsenting the colour RGBA(164, 0, 0, 1.0) - */ -export const dark_red = /* @__PURE__ */ new Rgba( - 0.6431372549019608, - 0.0, - 0.0, - 1.0, -); - -/** - * A `Colour` reprsenting the colour RGBA(252, 175, 62, 1.0) - */ -export const light_orange = /* @__PURE__ */ new Rgba( - 0.9882352941176471, - 0.6862745098039216, - 0.24313725490196078, - 1.0, -); - -/** - * A `Colour` reprsenting the colour RGBA(245, 121, 0, 1.0) - */ -export const orange = /* @__PURE__ */ new Rgba( - 0.9607843137254902, - 0.4745098039215686, - 0.0, - 1.0, -); - -/** - * A `Colour` reprsenting the colour RGBA(206, 92, 0, 1.0) - */ -export const dark_orange = /* @__PURE__ */ new Rgba( - 0.807843137254902, - 0.3607843137254902, - 0.0, - 1.0, -); - -/** - * A `Colour` reprsenting the colour RGBA(255, 233, 79, 1.0) - */ -export const light_yellow = /* @__PURE__ */ new Rgba( - 1.0, - 0.9137254901960784, - 0.30980392156862746, - 1.0, -); - -/** - * A `Colour` reprsenting the colour RGBA(237, 212, 0, 1.0) - */ -export const yellow = /* @__PURE__ */ new Rgba( - 0.9294117647058824, - 0.8313725490196079, - 0.0, - 1.0, -); - -/** - * A `Colour` reprsenting the colour RGBA(196, 160, 0, 1.0) - */ -export const dark_yellow = /* @__PURE__ */ new Rgba( - 0.7686274509803922, - 0.6274509803921569, - 0.0, - 1.0, -); - -/** - * A `Colour` reprsenting the colour RGBA(138, 226, 52, 1.0) - */ -export const light_green = /* @__PURE__ */ new Rgba( - 0.5411764705882353, - 0.8862745098039215, - 0.20392156862745098, - 1.0, -); - -/** - * A `Colour` reprsenting the colour RGBA(115, 210, 22, 1.0) - */ -export const green = /* @__PURE__ */ new Rgba( - 0.45098039215686275, - 0.8235294117647058, - 0.08627450980392157, - 1.0, -); - -/** - * A `Colour` reprsenting the colour RGBA(78, 154, 6, 1.0) - */ -export const dark_green = /* @__PURE__ */ new Rgba( - 0.3058823529411765, - 0.6039215686274509, - 0.023529411764705882, - 1.0, -); - -/** - * A `Colour` reprsenting the colour RGBA(114, 159, 207, 1.0) - */ -export const light_blue = /* @__PURE__ */ new Rgba( - 0.4470588235294118, - 0.6235294117647059, - 0.8117647058823529, - 1.0, -); - -/** - * A `Colour` reprsenting the colour RGBA(52, 101, 164, 1.0) - */ -export const blue = /* @__PURE__ */ new Rgba( - 0.20392156862745098, - 0.396078431372549, - 0.6431372549019608, - 1.0, -); - -/** - * A `Colour` reprsenting the colour RGBA(32, 74, 135, 1.0) - */ -export const dark_blue = /* @__PURE__ */ new Rgba( - 0.12549019607843137, - 0.2901960784313726, - 0.5294117647058824, - 1.0, -); - -/** - * A `Colour` reprsenting the colour RGBA(173, 127, 168, 1.0) - */ -export const light_purple = /* @__PURE__ */ new Rgba( - 0.6784313725490196, - 0.4980392156862745, - 0.6588235294117647, - 1.0, -); - -/** - * A `Colour` reprsenting the colour RGBA(117, 80, 123, 1.0) - */ -export const purple = /* @__PURE__ */ new Rgba( - 0.4588235294117647, - 0.3137254901960784, - 0.4823529411764706, - 1.0, -); - -/** - * A `Colour` reprsenting the colour RGBA(92, 53, 102, 1.0) - */ -export const dark_purple = /* @__PURE__ */ new Rgba( - 0.3607843137254902, - 0.20784313725490197, - 0.4, - 1.0, -); - -/** - * A `Colour` reprsenting the colour RGBA(233, 185, 110, 1.0) - */ -export const light_brown = /* @__PURE__ */ new Rgba( - 0.9137254901960784, - 0.7254901960784313, - 0.43137254901960786, - 1.0, -); - -/** - * A `Colour` reprsenting the colour RGBA(193, 125, 17, 1.0) - */ -export const brown = /* @__PURE__ */ new Rgba( - 0.7568627450980392, - 0.49019607843137253, - 0.06666666666666667, - 1.0, -); - -/** - * A `Colour` reprsenting the colour RGBA(143, 89, 2, 1.0) - */ -export const dark_brown = /* @__PURE__ */ new Rgba( - 0.5607843137254902, - 0.34901960784313724, - 0.00784313725490196, - 1.0, -); - -/** - * A `Colour` reprsenting the colour RGBA(0, 0, 0, 1.0) - */ -export const black = /* @__PURE__ */ new Rgba(0.0, 0.0, 0.0, 1.0); - -/** - * A `Colour` reprsenting the colour RGBA(255, 255, 255, 1.0) - */ -export const white = /* @__PURE__ */ new Rgba(1.0, 1.0, 1.0, 1.0); - -/** - * A `Colour` reprsenting the colour RGBA(238, 238, 236, 1.0) - */ -export const light_grey = /* @__PURE__ */ new Rgba( - 0.9333333333333333, - 0.9333333333333333, - 0.9254901960784314, - 1.0, -); - -/** - * A `Colour` reprsenting the colour RGBA(211, 215, 207, 1.0) - */ -export const grey = /* @__PURE__ */ new Rgba( - 0.8274509803921568, - 0.8431372549019608, - 0.8117647058823529, - 1.0, -); - -/** - * A `Colour` reprsenting the colour RGBA(186, 189, 182, 1.0) - */ -export const dark_grey = /* @__PURE__ */ new Rgba( - 0.7294117647058823, - 0.7411764705882353, - 0.7137254901960784, - 1.0, -); - -/** - * A `Colour` reprsenting the colour RGBA(238, 238, 236, 1.0) - */ -export const light_gray = /* @__PURE__ */ new Rgba( - 0.9333333333333333, - 0.9333333333333333, - 0.9254901960784314, - 1.0, -); - -/** - * A `Colour` reprsenting the colour RGBA(211, 215, 207, 1.0) - */ -export const gray = /* @__PURE__ */ new Rgba( - 0.8274509803921568, - 0.8431372549019608, - 0.8117647058823529, - 1.0, -); - -/** - * A `Colour` reprsenting the colour RGBA(186, 189, 182, 1.0) - */ -export const dark_gray = /* @__PURE__ */ new Rgba( - 0.7294117647058823, - 0.7411764705882353, - 0.7137254901960784, - 1.0, -); - -/** - * A `Colour` reprsenting the colour RGBA(136, 138, 133, 1.0) - */ -export const light_charcoal = /* @__PURE__ */ new Rgba( - 0.5333333333333333, - 0.5411764705882353, - 0.5215686274509804, - 1.0, -); - -/** - * A `Colour` reprsenting the colour RGBA(85, 87, 83, 1.0) - */ -export const charcoal = /* @__PURE__ */ new Rgba( - 0.3333333333333333, - 0.3411764705882353, - 0.3254901960784314, - 1.0, -); - -/** - * A `Colour` reprsenting the colour RGBA(46, 52, 54, 1.0) - */ -export const dark_charcoal = /* @__PURE__ */ new Rgba( - 0.1803921568627451, - 0.20392156862745098, - 0.21176470588235294, - 1.0, -); - -/** - * A `Colour` reprsenting the colour RGBA(255, 175, 243, 1.0) - */ -export const pink = /* @__PURE__ */ new Rgba( - 1.0, - 0.6862745098039216, - 0.9529411764705882, - 1.0, -); diff --git a/build/dev/javascript/gleam_community_colour/gleam_community/colour/accessibility.mjs b/build/dev/javascript/gleam_community_colour/gleam_community/colour/accessibility.mjs deleted file mode 100644 index 0c56e21..0000000 --- a/build/dev/javascript/gleam_community_colour/gleam_community/colour/accessibility.mjs +++ /dev/null @@ -1,146 +0,0 @@ -import * as $float from "../../../gleam_stdlib/gleam/float.mjs"; -import * as $list from "../../../gleam_stdlib/gleam/list.mjs"; -import { Ok, makeError, divideFloat } from "../../gleam.mjs"; -import * as $colour from "../../gleam_community/colour.mjs"; - -const FILEPATH = "src/gleam_community/colour/accessibility.gleam"; - -function intensity(colour_value) { - let $ = true; - if (colour_value <= 0.03928) { - return colour_value / 12.92; - } else { - let $1 = $float.power((colour_value + 0.055) / 1.055, 2.4); - let i; - if ($1 instanceof Ok) { - i = $1[0]; - } else { - throw makeError( - "let_assert", - FILEPATH, - "gleam_community/colour/accessibility", - 62, - "intensity", - "Pattern match failed, no pattern matched the value.", - { - value: $1, - start: 2399, - end: 2470, - pattern_start: 2410, - pattern_end: 2415 - } - ) - } - return i; - } -} - -/** - * Returns the relative brightness of the given `Colour` as a `Float` between - * 0.0, and 1.0 with 0.0 being the darkest possible colour and 1.0 being the lightest. - * - *
- * Example: - * - * ```gleam - * fn example() { - * luminance(colour.white) // 1.0 - * } - * ``` - *
- * - *
- * - * Spot a typo? Open an issue! - * - * - * Back to top ↑ - * - *
- */ -export function luminance(colour) { - let $ = $colour.to_rgba(colour); - let r; - let g; - let b; - r = $[0]; - g = $[1]; - b = $[2]; - let r_intensity = intensity(r); - let g_intensity = intensity(g); - let b_intensity = intensity(b); - return ((0.2126 * r_intensity) + (0.7152 * g_intensity)) + (0.0722 * b_intensity); -} - -/** - * Returns the contrast between two `Colour` values as a `Float` between 1.0, - * and 21.0 with 1.0 being no contrast and, 21.0 being the highest possible contrast. - * - *
- * Example: - * - * ```gleam - * fn example() { - * contrast_ratio(between: colour.white, and: colour.black) // 21.0 - * } - * ``` - *
- * - *
- * - * Spot a typo? Open an issue! - * - * - * Back to top ↑ - * - *
- */ -export function contrast_ratio(colour_a, colour_b) { - let luminance_a = luminance(colour_a) + 0.05; - let luminance_b = luminance(colour_b) + 0.05; - let $ = luminance_a > luminance_b; - if ($) { - return divideFloat(luminance_a, luminance_b); - } else { - return divideFloat(luminance_b, luminance_a); - } -} - -/** - * Returns the `Colour` with the highest contrast between the base `Colour`, - * and and the other provided `Colour` values. - * - *
- * Example: - * - * ```gleam - * fn example() { - * maximum_contrast( - * colour.yellow, - * [colour.white, colour.dark_blue, colour.green], - * ) - * } - * ``` - *
- * - *
- * - * Spot a typo? Open an issue! - * - * - * Back to top ↑ - * - *
- */ -export function maximum_contrast(base, colours) { - let _pipe = colours; - let _pipe$1 = $list.sort( - _pipe, - (colour_a, colour_b) => { - let contrast_a = contrast_ratio(base, colour_a); - let contrast_b = contrast_ratio(base, colour_b); - return $float.compare(contrast_b, contrast_a); - }, - ); - return $list.first(_pipe$1); -} diff --git a/build/dev/javascript/gleam_community_colour/gleam_community@colour.erl b/build/dev/javascript/gleam_community_colour/gleam_community@colour.erl deleted file mode 100644 index faee070..0000000 --- a/build/dev/javascript/gleam_community_colour/gleam_community@colour.erl +++ /dev/null @@ -1,1199 +0,0 @@ --module(gleam_community@colour). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch]). --define(FILEPATH, "src/gleam_community/colour.gleam"). --export([from_rgb255/3, from_rgb/3, from_rgba/4, from_hsla/4, from_hsl/3, from_rgb_hex/1, from_rgb_hex_string/1, from_rgba_hex/1, from_rgba_hex_string/1, to_rgba/1, to_hsla/1, to_css_rgba_string/1, to_rgba_hex/1, to_rgba_hex_string/1, to_rgb_hex/1, to_rgb_hex_string/1, encode/1, decoder/0]). --export_type([colour/0]). - --if(?OTP_RELEASE >= 27). --define(MODULEDOC(Str), -moduledoc(Str)). --define(DOC(Str), -doc(Str)). --else. --define(MODULEDOC(Str), -compile([])). --define(DOC(Str), -compile([])). --endif. - -?MODULEDOC( - "\n" - " - **Types**\n" - " - [`Colour`](#Colour)\n" - " - [`Color`](#Color)\n" - " - **Constructors**\n" - " - [`from_rgb255`](#from_rgb255)\n" - " - [`from_rgb`](#from_rgb)\n" - " - [`from_rgba`](#from_rgba)\n" - " - [`from_hsl`](#from_hsl)\n" - " - [`from_hsla`](#from_hsla)\n" - " - [`from_rgb_hex`](#from_rgb_hex)\n" - " - [`from_rgba_hex`](#from_rgba_hex)\n" - " - [`from_rgb_hex_string`](#from_rgb_hex_string)\n" - " - [`from_rgba_hex_string`](#from_rgba_hex_string)\n" - " - **Conversions**\n" - " - [`to_rgba`](#to_rgba)\n" - " - [`to_hsla`](#hsla)\n" - " - [`to_css_rgba_string`](#to_css_rgba_string)\n" - " - [`to_rgba_hex_string`](#to_rgba_hex_string)\n" - " - [`to_rgb_hex_string`](#to_rgb_hex_string)\n" - " - [`to_rgba_hex`](#to_rgba_hex)\n" - " - [`to_rgb_hex`](#to_rgb_hex)\n" - " - **JSON**\n" - " - [`encode`](#encode)\n" - " - [`decoder`](#decoder)\n" - " - **Colours**\n" - " - [`light_red`](#light_red)\n" - " - [`red`](#red)\n" - " - [`dark_red`](#dark_red)\n" - " - [`light_orange`](#light_orange)\n" - " - [`orange`](#orange)\n" - " - [`dark_orange`](#dark_orange)\n" - " - [`light_yellow`](#light_yellow)\n" - " - [`yellow`](#yellow)\n" - " - [`dark_yellow`](#dark_yellow)\n" - " - [`light_green`](#light_green)\n" - " - [`green`](#green)\n" - " - [`dark_green`](#dark_green)\n" - " - [`light_blue`](#light_blue)\n" - " - [`blue`](#blue)\n" - " - [`dark_blue`](#dark_blue)\n" - " - [`light_purple`](#light_purple)\n" - " - [`purple`](#purple)\n" - " - [`dark_purple`](#dark_purple)\n" - " - [`light_brown`](#light_brown)\n" - " - [`brown`](#brown)\n" - " - [`dark_brown`](#dark_brown)\n" - " - [`black`](#black)\n" - " - [`white`](#white)\n" - " - [`light_grey`](#light_grey)\n" - " - [`grey`](#grey)\n" - " - [`dark_grey`](#dark_grey)\n" - " - [`light_gray`](#light_gray)\n" - " - [`gray`](#gray)\n" - " - [`dark_gray`](#dark_gray)\n" - " - [`light_charcoal`](#light_charcoal)\n" - " - [`charcoal`](#charcoal)\n" - " - [`dark_charcoal`](#dark_charcoal)\n" - " - [`pink`](#pink)\n" - "\n" - " ---\n" - "\n" - " This package was heavily inspired by the `elm-color` module.\n" - " The original source code can be found\n" - " here.\n" - "\n" - "
\n" - " The license of that package is produced below:\n" - "\n" - "\n" - " > MIT License\n" - "\n" - " > Copyright 2018 Aaron VonderHaar\n" - "\n" - " > Redistribution and use in source and binary forms, with or without modification,\n" - " are permitted provided that the following conditions are met:\n" - "\n" - " 1. Redistributions of source code must retain the above copyright notice,\n" - " this list of conditions and the following disclaimer.\n" - "\n" - " 2. Redistributions in binary form must reproduce the above copyright notice,\n" - " this list of conditions and the following disclaimer in the documentation\n" - " and/or other materials provided with the distribution.\n" - "\n" - " 3. Neither the name of the copyright holder nor the names of its contributors\n" - " may be used to endorse or promote products derived from this software without\n" - " specific prior written permission.\n" - "\n" - " > THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\n" - " ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\n" - " OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL\n" - " THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n" - " EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n" - " OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n" - " THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n" - " ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n" - "\n" - " > The above copyright notice and this permission notice shall be included in all\n" - " copies or substantial portions of the Software.\n" - "
\n" - "\n" -). - --opaque colour() :: {rgba, float(), float(), float(), float()} | - {hsla, float(), float(), float(), float()}. - --file("src/gleam_community/colour.gleam", 155). --spec valid_colour_value(float()) -> {ok, float()} | {error, nil}. -valid_colour_value(C) -> - case (C > 1.0) orelse (C < +0.0) of - true -> - {error, nil}; - - false -> - {ok, C} - end. - --file("src/gleam_community/colour.gleam", 162). --spec hue_to_rgb(float(), float(), float()) -> float(). -hue_to_rgb(Hue, M1, M2) -> - H = case Hue of - _ when Hue < +0.0 -> - Hue + 1.0; - - _ when Hue > 1.0 -> - Hue - 1.0; - - _ -> - Hue - end, - H_t_6 = H * 6.0, - H_t_2 = H * 2.0, - H_t_3 = H * 3.0, - case H of - _ when H_t_6 < 1.0 -> - M1 + (((M2 - M1) * H) * 6.0); - - _ when H_t_2 < 1.0 -> - M2; - - _ when H_t_3 < 2.0 -> - M1 + (((M2 - M1) * ((2.0 / 3.0) - H)) * 6.0); - - _ -> - M1 - end. - --file("src/gleam_community/colour.gleam", 181). --spec hex_string_to_int(binary()) -> {ok, integer()} | {error, nil}. -hex_string_to_int(Hex_string) -> - Hex = case Hex_string of - <<"#"/utf8, Hex_number/binary>> -> - Hex_number; - - <<"0x"/utf8, Hex_number@1/binary>> -> - Hex_number@1; - - _ -> - Hex_string - end, - _pipe = Hex, - _pipe@1 = string:lowercase(_pipe), - _pipe@2 = gleam@string:to_graphemes(_pipe@1), - _pipe@3 = lists:reverse(_pipe@2), - gleam@list:index_fold( - _pipe@3, - {ok, 0}, - fun(Total, Char, Index) -> case Total of - {error, nil} -> - {error, nil}; - - {ok, V} -> - gleam@result:'try'(case Char of - <<"a"/utf8>> -> - {ok, 10}; - - <<"b"/utf8>> -> - {ok, 11}; - - <<"c"/utf8>> -> - {ok, 12}; - - <<"d"/utf8>> -> - {ok, 13}; - - <<"e"/utf8>> -> - {ok, 14}; - - <<"f"/utf8>> -> - {ok, 15}; - - _ -> - gleam_stdlib:parse_int(Char) - end, fun(Num) -> - gleam@result:'try'( - gleam@int:power(16, erlang:float(Index)), - fun(Base) -> - {ok, - V + erlang:round( - erlang:float(Num) * Base - )} - end - ) - end) - end end - ). - --file("src/gleam_community/colour.gleam", 212). --spec hsla_to_rgba(float(), float(), float(), float()) -> {float(), - float(), - float(), - float()}. -hsla_to_rgba(H, S, L, A) -> - M2 = case L =< 0.5 of - true -> - L * (S + 1.0); - - false -> - (L + S) - (L * S) - end, - M1 = (L * 2.0) - M2, - R = hue_to_rgb(H + (1.0 / 3.0), M1, M2), - G = hue_to_rgb(H, M1, M2), - B = hue_to_rgb(H - (1.0 / 3.0), M1, M2), - {R, G, B, A}. - --file("src/gleam_community/colour.gleam", 232). --spec rgba_to_hsla(float(), float(), float(), float()) -> {float(), - float(), - float(), - float()}. -rgba_to_hsla(R, G, B, A) -> - Min_colour = gleam@float:min(R, gleam@float:min(G, B)), - Max_colour = gleam@float:max(R, gleam@float:max(G, B)), - H1 = case true of - _ when Max_colour =:= R -> - gleam@float:divide(G - B, Max_colour - Min_colour); - - _ when Max_colour =:= G -> - _pipe = gleam@float:divide(B - R, Max_colour - Min_colour), - gleam@result:'try'(_pipe, fun(D) -> {ok, 2.0 + D} end); - - _ -> - _pipe@1 = gleam@float:divide(R - G, Max_colour - Min_colour), - gleam@result:'try'(_pipe@1, fun(D@1) -> {ok, 4.0 + D@1} end) - end, - H2 = case H1 of - {ok, V} -> - {ok, V * (1.0 / 6.0)}; - - _ -> - H1 - end, - H3 = case H2 of - {ok, V@1} when V@1 < +0.0 -> - V@1 + 1.0; - - {ok, V@2} -> - V@2; - - _ -> - +0.0 - end, - L = (Min_colour + Max_colour) / 2.0, - S = case true of - _ when Min_colour =:= Max_colour -> - +0.0; - - _ when L < 0.5 -> - case (Max_colour + Min_colour) of - +0.0 -> +0.0; - -0.0 -> -0.0; - Gleam@denominator -> (Max_colour - Min_colour) / Gleam@denominator - end; - - _ -> - case ((2.0 - Max_colour) - Min_colour) of - +0.0 -> +0.0; - -0.0 -> -0.0; - Gleam@denominator@1 -> (Max_colour - Min_colour) / Gleam@denominator@1 - end - end, - {H3, S, L, A}. - --file("src/gleam_community/colour.gleam", 300). -?DOC( - " Returns a `Result(Colour)` created from the given 8 bit RGB values.\n" - "\n" - " Returns `Error(Nil)` if the supplied RGB values are greater than 255 or less than 0.\n" - "\n" - "
\n" - " Example:\n" - "\n" - " ```gleam\n" - " fn example() {\n" - " assert Ok(red) = from_rgb255(255, 0, 0)\n" - " }\n" - " ```\n" - "
\n" - "\n" - "
\n" - " \n" - " Spot a typo? Open an issue!\n" - " \n" - " \n" - " Back to top ↑\n" - " \n" - "
\n" -). --spec from_rgb255(integer(), integer(), integer()) -> {ok, colour()} | - {error, nil}. -from_rgb255(Red, Green, Blue) -> - gleam@result:'try'( - begin - _pipe = Red, - _pipe@1 = erlang:float(_pipe), - _pipe@2 = gleam@float:divide(_pipe@1, 255.0), - gleam@result:'try'(_pipe@2, fun valid_colour_value/1) - end, - fun(R) -> - gleam@result:'try'( - begin - _pipe@3 = Green, - _pipe@4 = erlang:float(_pipe@3), - _pipe@5 = gleam@float:divide(_pipe@4, 255.0), - gleam@result:'try'(_pipe@5, fun valid_colour_value/1) - end, - fun(G) -> - gleam@result:'try'( - begin - _pipe@6 = Blue, - _pipe@7 = erlang:float(_pipe@6), - _pipe@8 = gleam@float:divide(_pipe@7, 255.0), - gleam@result:'try'( - _pipe@8, - fun valid_colour_value/1 - ) - end, - fun(B) -> {ok, {rgba, R, G, B, 1.0}} end - ) - end - ) - end - ). - --file("src/gleam_community/colour.gleam", 348). -?DOC( - " Returns `Result(Colour)` created from the given RGB values.\n" - "\n" - " If the supplied RGB values are greater than 1.0 or less than 0.0 returns `Error(Nil)`\n" - "\n" - "
\n" - " Example:\n" - "\n" - " ```gleam\n" - " fn example() {\n" - " assert Ok(red) = from_rgb(1.0, 0.0, 0.0)\n" - " }\n" - " ```\n" - "
\n" - "\n" - "
\n" - " \n" - " Spot a typo? Open an issue!\n" - " \n" - " \n" - " Back to top ↑\n" - " \n" - "
\n" -). --spec from_rgb(float(), float(), float()) -> {ok, colour()} | {error, nil}. -from_rgb(Red, Green, Blue) -> - gleam@result:'try'( - valid_colour_value(Red), - fun(R) -> - gleam@result:'try'( - valid_colour_value(Green), - fun(G) -> - gleam@result:'try'( - valid_colour_value(Blue), - fun(B) -> {ok, {rgba, R, G, B, 1.0}} end - ) - end - ) - end - ). - --file("src/gleam_community/colour.gleam", 383). -?DOC( - " Returns `Result(Colour)` created from the given RGBA values.\n" - "\n" - " Returns `Error(Nil)` if the supplied RGBA values are greater than 1.0 or less than 0.0.\n" - "\n" - "
\n" - " Example:\n" - "\n" - " ```gleam\n" - " fn example() {\n" - " assert Ok(red_half_opacity) = from_rbga(1.0, 0.0, 0.0, 0.5)\n" - " }\n" - " ```\n" - "
\n" - "\n" - "
\n" - " \n" - " Spot a typo? Open an issue!\n" - " \n" - " \n" - " Back to top ↑\n" - " \n" - "
\n" -). --spec from_rgba(float(), float(), float(), float()) -> {ok, colour()} | - {error, nil}. -from_rgba(Red, Green, Blue, Alpha) -> - gleam@result:'try'( - valid_colour_value(Red), - fun(R) -> - gleam@result:'try'( - valid_colour_value(Green), - fun(G) -> - gleam@result:'try'( - valid_colour_value(Blue), - fun(B) -> - gleam@result:'try'( - valid_colour_value(Alpha), - fun(A) -> {ok, {rgba, R, G, B, A}} end - ) - end - ) - end - ) - end - ). - --file("src/gleam_community/colour.gleam", 420). -?DOC( - " Returns `Result(Colour)` created from the given HSLA values.\n" - "\n" - " Returns `Error(Nil)`f the supplied HSLA values are greater than 1.0 or less than 0.0.\n" - "\n" - "
\n" - " Example:\n" - "\n" - " ```gleam\n" - " fn example() {\n" - " assert Ok(red_half_opacity) = from_hsla(0.0, 1.0, 0.5, 0.5)\n" - " }\n" - " ```\n" - "
\n" - "\n" - "
\n" - " \n" - " Spot a typo? Open an issue!\n" - " \n" - " \n" - " Back to top ↑\n" - " \n" - "
\n" -). --spec from_hsla(float(), float(), float(), float()) -> {ok, colour()} | - {error, nil}. -from_hsla(Hue, Saturation, Lightness, Alpha) -> - gleam@result:'try'( - valid_colour_value(Hue), - fun(H) -> - gleam@result:'try'( - valid_colour_value(Saturation), - fun(S) -> - gleam@result:'try'( - valid_colour_value(Lightness), - fun(L) -> - gleam@result:'try'( - valid_colour_value(Alpha), - fun(A) -> {ok, {hsla, H, S, L, A}} end - ) - end - ) - end - ) - end - ). - --file("src/gleam_community/colour.gleam", 457). -?DOC( - " Returns `Result(Colour)` created from the given HSL values.\n" - "\n" - " Returns `Error(Nil)` if the supplied HSL values are greater than 1.0 or less than 0.0.\n" - "\n" - "
\n" - " Example:\n" - "\n" - " ```gleam\n" - " fn example() {\n" - " assert Ok(red) = from_hsla(0.0, 1.0, 0.5)\n" - " }\n" - " ```\n" - "
\n" - "\n" - "
\n" - " \n" - " Spot a typo? Open an issue!\n" - " \n" - " \n" - " Back to top ↑\n" - " \n" - "
\n" -). --spec from_hsl(float(), float(), float()) -> {ok, colour()} | {error, nil}. -from_hsl(Hue, Saturation, Lightness) -> - from_hsla(Hue, Saturation, Lightness, 1.0). - --file("src/gleam_community/colour.gleam", 488). -?DOC( - " Returns a `Result(Colour)` created from the given hex `Int`.\n" - "\n" - " Returns `Error(Nil)` if the supplied hex `Int is greater than 0xffffff or less than 0x0.\n" - "\n" - "
\n" - " Example:\n" - "\n" - " ```gleam\n" - " fn example() {\n" - " assert Ok(red) = from_rgb_hex(0xff0000)\n" - " }\n" - " ```\n" - "
\n" - "\n" - "
\n" - " \n" - " Spot a typo? Open an issue!\n" - " \n" - " \n" - " Back to top ↑\n" - " \n" - "
\n" -). --spec from_rgb_hex(integer()) -> {ok, colour()} | {error, nil}. -from_rgb_hex(Hex) -> - case (Hex > 16#ffffff) orelse (Hex < 0) of - true -> - {error, nil}; - - false -> - R = begin - _pipe = erlang:'bsr'(Hex, 16), - erlang:'band'(_pipe, 16#ff) - end, - G = begin - _pipe@1 = erlang:'bsr'(Hex, 8), - erlang:'band'(_pipe@1, 16#ff) - end, - B = erlang:'band'(Hex, 16#ff), - from_rgb255(R, G, B) - end. - --file("src/gleam_community/colour.gleam", 527). -?DOC( - " Returns a `Result(Colour)` created from the given RGB hex `String`.\n" - "\n" - " Returns `Error(Nil)` if the supplied hex `String` is invalid, or greater than `\"#ffffff\" or less than `\"#0\"`\n" - "\n" - "
\n" - " Example:\n" - "\n" - " ```gleam\n" - " fn example() {\n" - " assert Ok(red) = from_rgb_hex_string(\"#ff0000\")\n" - " }\n" - " ```\n" - "
\n" - "\n" - "
\n" - " \n" - " Spot a typo? Open an issue!\n" - " \n" - " \n" - " Back to top ↑\n" - " \n" - "
\n" -). --spec from_rgb_hex_string(binary()) -> {ok, colour()} | {error, nil}. -from_rgb_hex_string(Hex_string) -> - gleam@result:'try'( - hex_string_to_int(Hex_string), - fun(Hex_int) -> from_rgb_hex(Hex_int) end - ). - --file("src/gleam_community/colour.gleam", 585). -?DOC( - " Returns a `Result(Colour)` created from the given hex `Int`.\n" - "\n" - " Returns `Error(Nil)` if the supplied hex `Int is greater than 0xffffffff or less than 0x0.\n" - "\n" - "
\n" - " Example:\n" - "\n" - " ```gleam\n" - " fn example() {\n" - " assert Ok(red_half_opacity) = from_rgba_hex(0xff00007f)\n" - " }\n" - " ```\n" - "
\n" - "\n" - "
\n" - " \n" - " Spot a typo? Open an issue!\n" - " \n" - " \n" - " Back to top ↑\n" - " \n" - "
\n" -). --spec from_rgba_hex(integer()) -> {ok, colour()} | {error, nil}. -from_rgba_hex(Hex) -> - case (Hex > 16#ffffffff) orelse (Hex < 0) of - true -> - {error, nil}; - - false -> - R@1 = case begin - _pipe = erlang:'bsr'(Hex, 24), - _pipe@1 = erlang:'band'(_pipe, 16#ff), - _pipe@2 = erlang:float(_pipe@1), - gleam@float:divide(_pipe@2, 255.0) - end of - {ok, R} -> R; - _assert_fail -> - erlang:error(#{gleam_error => let_assert, - message => <<"Pattern match failed, no pattern matched the value."/utf8>>, - file => <>, - module => <<"gleam_community/colour"/utf8>>, - function => <<"from_rgba_hex"/utf8>>, - line => 590, - value => _assert_fail, - start => 17111, - 'end' => 17260, - pattern_start => 17122, - pattern_end => 17127}) - end, - G@1 = case begin - _pipe@3 = erlang:'bsr'(Hex, 16), - _pipe@4 = erlang:'band'(_pipe@3, 16#ff), - _pipe@5 = erlang:float(_pipe@4), - gleam@float:divide(_pipe@5, 255.0) - end of - {ok, G} -> G; - _assert_fail@1 -> - erlang:error(#{gleam_error => let_assert, - message => <<"Pattern match failed, no pattern matched the value."/utf8>>, - file => <>, - module => <<"gleam_community/colour"/utf8>>, - function => <<"from_rgba_hex"/utf8>>, - line => 596, - value => _assert_fail@1, - start => 17332, - 'end' => 17481, - pattern_start => 17343, - pattern_end => 17348}) - end, - B@1 = case begin - _pipe@6 = erlang:'bsr'(Hex, 8), - _pipe@7 = erlang:'band'(_pipe@6, 16#ff), - _pipe@8 = erlang:float(_pipe@7), - gleam@float:divide(_pipe@8, 255.0) - end of - {ok, B} -> B; - _assert_fail@2 -> - erlang:error(#{gleam_error => let_assert, - message => <<"Pattern match failed, no pattern matched the value."/utf8>>, - file => <>, - module => <<"gleam_community/colour"/utf8>>, - function => <<"from_rgba_hex"/utf8>>, - line => 602, - value => _assert_fail@2, - start => 17553, - 'end' => 17701, - pattern_start => 17564, - pattern_end => 17569}) - end, - A@1 = case begin - _pipe@9 = erlang:'band'(Hex, 16#ff), - _pipe@10 = erlang:float(_pipe@9), - gleam@float:divide(_pipe@10, 255.0) - end of - {ok, A} -> A; - _assert_fail@3 -> - erlang:error(#{gleam_error => let_assert, - message => <<"Pattern match failed, no pattern matched the value."/utf8>>, - file => <>, - module => <<"gleam_community/colour"/utf8>>, - function => <<"from_rgba_hex"/utf8>>, - line => 608, - value => _assert_fail@3, - start => 17773, - 'end' => 17883, - pattern_start => 17784, - pattern_end => 17789}) - end, - from_rgba(R@1, G@1, B@1, A@1) - end. - --file("src/gleam_community/colour.gleam", 556). -?DOC( - " Returns a `Result(Colour)` created from the given RGBA hex `String`.\n" - "\n" - " Returns `Error(Nil)` if the supplied hex `String` is invalid, or greater than `\"#ffffffff\" or less than `\"#0\"`\n" - "\n" - "
\n" - " Example:\n" - "\n" - " ```gleam\n" - " fn example() {\n" - " assert Ok(red_half_opacity) = from_rgba_hex_string(\"#ff00007f\")\n" - " }\n" - " ```\n" - "
\n" - "\n" - "
\n" - " \n" - " Spot a typo? Open an issue!\n" - " \n" - " \n" - " Back to top ↑\n" - " \n" - "
\n" -). --spec from_rgba_hex_string(binary()) -> {ok, colour()} | {error, nil}. -from_rgba_hex_string(Hex_string) -> - gleam@result:'try'( - hex_string_to_int(Hex_string), - fun(Hex_int) -> from_rgba_hex(Hex_int) end - ). - --file("src/gleam_community/colour.gleam", 642). -?DOC( - " Returns `#(Float, Float, Float, Float)` representing the given `Colour`'s\n" - " R, G, B, and A values respectively.\n" - "\n" - "
\n" - " Example:\n" - "\n" - " ```gleam\n" - " fn example() {\n" - " assert Ok(red) = from_rgb255(255, 0, 0)\n" - " let #(r, g, b, a) = to_rgba(red)\n" - " }\n" - " ```\n" - "
\n" - "\n" - "
\n" - " \n" - " Spot a typo? Open an issue!\n" - " \n" - " \n" - " Back to top ↑\n" - " \n" - "
\n" -). --spec to_rgba(colour()) -> {float(), float(), float(), float()}. -to_rgba(Colour) -> - case Colour of - {rgba, R, G, B, A} -> - {R, G, B, A}; - - {hsla, H, S, L, A@1} -> - hsla_to_rgba(H, S, L, A@1) - end. - --file("src/gleam_community/colour.gleam", 672). -?DOC( - " Returns `#(Float, Float, Float, Float)` representing the given `Colour`'s\n" - " H, S, L, and A values respectively.\n" - "\n" - "
\n" - " Example:\n" - "\n" - " ```gleam\n" - " fn example() {\n" - " assert Ok(red) = from_rgb255(255, 0, 0)\n" - " let #(h, s, l, a) = to_hsla(red)\n" - " }\n" - " ```\n" - "
\n" - "\n" - "
\n" - " \n" - " Spot a typo? Open an issue!\n" - " \n" - " \n" - " Back to top ↑\n" - " \n" - "
\n" -). --spec to_hsla(colour()) -> {float(), float(), float(), float()}. -to_hsla(Colour) -> - case Colour of - {hsla, H, S, L, A} -> - {H, S, L, A}; - - {rgba, R, G, B, A@1} -> - rgba_to_hsla(R, G, B, A@1) - end. - --file("src/gleam_community/colour.gleam", 701). -?DOC( - " Returns an rgba formatted CSS `String` created from the given `Colour`.\n" - "\n" - "
\n" - " Example:\n" - "\n" - " ```gleam\n" - " fn example() {\n" - " assert Ok(red) = from_rgb255(255, 0, 0)\n" - " let css_red = to_css_rgba_string(red)\n" - " }\n" - " ```\n" - "
\n" - "\n" - "
\n" - " \n" - " Spot a typo? Open an issue!\n" - " \n" - " \n" - " Back to top ↑\n" - " \n" - "
\n" -). --spec to_css_rgba_string(colour()) -> binary(). -to_css_rgba_string(Colour) -> - {R, G, B, A} = to_rgba(Colour), - Percent = fun(X) -> - P@1 = case begin - _pipe = X, - _pipe@1 = gleam@float:multiply(_pipe, 10000.0), - _pipe@2 = erlang:round(_pipe@1), - _pipe@3 = erlang:float(_pipe@2), - gleam@float:divide(_pipe@3, 100.0) - end of - {ok, P} -> P; - _assert_fail -> - erlang:error(#{gleam_error => let_assert, - message => <<"Pattern match failed, no pattern matched the value."/utf8>>, - file => <>, - module => <<"gleam_community/colour"/utf8>>, - function => <<"to_css_rgba_string"/utf8>>, - line => 706, - value => _assert_fail, - start => 20510, - 'end' => 20646, - pattern_start => 20521, - pattern_end => 20526}) - end, - P@1 - end, - Round_to = fun(X@1) -> - R@2 = case begin - _pipe@4 = X@1, - _pipe@5 = gleam@float:multiply(_pipe@4, 1000.0), - _pipe@6 = erlang:round(_pipe@5), - _pipe@7 = erlang:float(_pipe@6), - gleam@float:divide(_pipe@7, 1000.0) - end of - {ok, R@1} -> R@1; - _assert_fail@1 -> - erlang:error(#{gleam_error => let_assert, - message => <<"Pattern match failed, no pattern matched the value."/utf8>>, - file => <>, - module => <<"gleam_community/colour"/utf8>>, - function => <<"to_css_rgba_string"/utf8>>, - line => 718, - value => _assert_fail@1, - start => 20768, - 'end' => 20903, - pattern_start => 20779, - pattern_end => 20784}) - end, - R@2 - end, - gleam@string:join( - [<<"rgba("/utf8>>, - <<(gleam_stdlib:float_to_string(Percent(R)))/binary, "%,"/utf8>>, - <<(gleam_stdlib:float_to_string(Percent(G)))/binary, "%,"/utf8>>, - <<(gleam_stdlib:float_to_string(Percent(B)))/binary, "%,"/utf8>>, - gleam_stdlib:float_to_string(Round_to(A)), - <<")"/utf8>>], - <<""/utf8>> - ). - --file("src/gleam_community/colour.gleam", 829). -?DOC( - " Returns an hex `Int` created from the given `Colour`.\n" - "\n" - "
\n" - " Example:\n" - "\n" - " ```gleam\n" - " fn example() {\n" - " assert Ok(red) = from_rgba(1.0, 0.0, 0.0, 1.0)\n" - " let red_hex_int = to_rgba_hex(red)\n" - " }\n" - " ```\n" - "
\n" - "\n" - "
\n" - " \n" - " Spot a typo? Open an issue!\n" - " \n" - " \n" - " Back to top ↑\n" - " \n" - "
\n" -). --spec to_rgba_hex(colour()) -> integer(). -to_rgba_hex(Colour) -> - {R, G, B, A} = to_rgba(Colour), - Red = begin - _pipe = R * 255.0, - _pipe@1 = erlang:round(_pipe), - erlang:'bsl'(_pipe@1, 24) - end, - Green = begin - _pipe@2 = G * 255.0, - _pipe@3 = erlang:round(_pipe@2), - erlang:'bsl'(_pipe@3, 16) - end, - Blue = begin - _pipe@4 = B * 255.0, - _pipe@5 = erlang:round(_pipe@4), - erlang:'bsl'(_pipe@5, 8) - end, - Alpha = begin - _pipe@6 = A * 255.0, - erlang:round(_pipe@6) - end, - ((Red + Green) + Blue) + Alpha. - --file("src/gleam_community/colour.gleam", 763). -?DOC( - " Returns an rgba hex formatted `String` created from the given `Colour`.\n" - "\n" - "
\n" - " Example:\n" - "\n" - " ```gleam\n" - " fn example() {\n" - " assert Ok(red) = from_rgba(1.0, 0.0, 0.0, 1.0)\n" - " let red_hex = to_rgba_hex_string(red)\n" - " }\n" - " ```\n" - "
\n" - "\n" - "
\n" - " \n" - " Spot a typo? Open an issue!\n" - " \n" - " \n" - " Back to top ↑\n" - " \n" - "
\n" -). --spec to_rgba_hex_string(colour()) -> binary(). -to_rgba_hex_string(Colour) -> - Hex_string = begin - _pipe = to_rgba_hex(Colour), - gleam@int:to_base16(_pipe) - end, - case string:length(Hex_string) of - 8 -> - Hex_string; - - L -> - <<(gleam@string:repeat(<<"0"/utf8>>, 8 - L))/binary, - Hex_string/binary>> - end. - --file("src/gleam_community/colour.gleam", 876). -?DOC( - " Returns a rgb hex `Int` created from the given `Colour`.\n" - "\n" - "
\n" - " Example:\n" - "\n" - " ```gleam\n" - " fn example() {\n" - " assert Ok(red) = from_rgba(255, 0, 0)\n" - " let red_hex_int = to_rgb_hex(red)\n" - " }\n" - " ```\n" - "
\n" - "\n" - "
\n" - " \n" - " Spot a typo? Open an issue!\n" - " \n" - " \n" - " Back to top ↑\n" - " \n" - "
\n" -). --spec to_rgb_hex(colour()) -> integer(). -to_rgb_hex(Colour) -> - {R, G, B, _} = to_rgba(Colour), - Red = begin - _pipe = R * 255.0, - _pipe@1 = erlang:round(_pipe), - erlang:'bsl'(_pipe@1, 16) - end, - Green = begin - _pipe@2 = G * 255.0, - _pipe@3 = erlang:round(_pipe@2), - erlang:'bsl'(_pipe@3, 8) - end, - Blue = begin - _pipe@4 = B * 255.0, - erlang:round(_pipe@4) - end, - (Red + Green) + Blue. - --file("src/gleam_community/colour.gleam", 796). -?DOC( - " Returns an rgb hex formatted `String` created from the given `Colour`.\n" - "\n" - "
\n" - " Example:\n" - "\n" - " ```gleam\n" - " fn example() {\n" - " assert Ok(red) = from_rgba(255, 0, 0)\n" - " let red_hex = to_rgb_hex_string(red)\n" - " }\n" - " ```\n" - "
\n" - "\n" - "
\n" - " \n" - " Spot a typo? Open an issue!\n" - " \n" - " \n" - " Back to top ↑\n" - " \n" - "
\n" -). --spec to_rgb_hex_string(colour()) -> binary(). -to_rgb_hex_string(Colour) -> - Hex_string = begin - _pipe = to_rgb_hex(Colour), - gleam@int:to_base16(_pipe) - end, - case string:length(Hex_string) of - 6 -> - Hex_string; - - L -> - <<(gleam@string:repeat(<<"0"/utf8>>, 6 - L))/binary, - Hex_string/binary>> - end. - --file("src/gleam_community/colour.gleam", 918). --spec encode_rgba(float(), float(), float(), float()) -> gleam@json:json(). -encode_rgba(R, G, B, A) -> - gleam@json:object( - [{<<"r"/utf8>>, gleam@json:float(R)}, - {<<"g"/utf8>>, gleam@json:float(G)}, - {<<"b"/utf8>>, gleam@json:float(B)}, - {<<"a"/utf8>>, gleam@json:float(A)}] - ). - --file("src/gleam_community/colour.gleam", 927). --spec encode_hsla(float(), float(), float(), float()) -> gleam@json:json(). -encode_hsla(H, S, L, A) -> - gleam@json:object( - [{<<"h"/utf8>>, gleam@json:float(H)}, - {<<"s"/utf8>>, gleam@json:float(S)}, - {<<"l"/utf8>>, gleam@json:float(L)}, - {<<"a"/utf8>>, gleam@json:float(A)}] - ). - --file("src/gleam_community/colour.gleam", 911). -?DOC( - " Encodes a `Colour` value as a Gleam [`Json`](https://hexdocs.pm/gleam_json/gleam/json.html#Json)\n" - " value. You'll need this if you want to send a `Colour` value over the network\n" - " in a HTTP request or response, for example.\n" - "\n" - "
\n" - " \n" - " Spot a typo? Open an issue!\n" - " \n" - " \n" - " Back to top ↑\n" - " \n" - "
\n" -). --spec encode(colour()) -> gleam@json:json(). -encode(Colour) -> - case Colour of - {rgba, R, G, B, A} -> - encode_rgba(R, G, B, A); - - {hsla, H, S, L, A@1} -> - encode_hsla(H, S, L, A@1) - end. - --file("src/gleam_community/colour.gleam", 952). --spec rgba_decoder() -> gleam@dynamic@decode:decoder(colour()). -rgba_decoder() -> - gleam@dynamic@decode:field( - <<"r"/utf8>>, - {decoder, fun gleam@dynamic@decode:decode_float/1}, - fun(R) -> - gleam@dynamic@decode:field( - <<"g"/utf8>>, - {decoder, fun gleam@dynamic@decode:decode_float/1}, - fun(G) -> - gleam@dynamic@decode:field( - <<"b"/utf8>>, - {decoder, fun gleam@dynamic@decode:decode_float/1}, - fun(B) -> - gleam@dynamic@decode:field( - <<"a"/utf8>>, - {decoder, - fun gleam@dynamic@decode:decode_float/1}, - fun(A) -> - gleam@dynamic@decode:success( - {rgba, R, G, B, A} - ) - end - ) - end - ) - end - ) - end - ). - --file("src/gleam_community/colour.gleam", 961). --spec hsla_decoder() -> gleam@dynamic@decode:decoder(colour()). -hsla_decoder() -> - gleam@dynamic@decode:field( - <<"h"/utf8>>, - {decoder, fun gleam@dynamic@decode:decode_float/1}, - fun(H) -> - gleam@dynamic@decode:field( - <<"s"/utf8>>, - {decoder, fun gleam@dynamic@decode:decode_float/1}, - fun(S) -> - gleam@dynamic@decode:field( - <<"l"/utf8>>, - {decoder, fun gleam@dynamic@decode:decode_float/1}, - fun(L) -> - gleam@dynamic@decode:field( - <<"a"/utf8>>, - {decoder, - fun gleam@dynamic@decode:decode_float/1}, - fun(A) -> - gleam@dynamic@decode:success( - {hsla, H, S, L, A} - ) - end - ) - end - ) - end - ) - end - ). - --file("src/gleam_community/colour.gleam", 948). -?DOC( - " Attempt to decode some [`Dynamic`](https://hexdocs.pm/gleam_stdlib/gleam/dynamic.html#Dynamic)\n" - " value into a `Colour`. Most often you'll use this to decode some JSON.\n" - "\n" - "
\n" - " \n" - " Spot a typo? Open an issue!\n" - " \n" - " \n" - " Back to top ↑\n" - " \n" - "
\n" -). --spec decoder() -> gleam@dynamic@decode:decoder(colour()). -decoder() -> - gleam@dynamic@decode:one_of(rgba_decoder(), [hsla_decoder()]). diff --git a/build/dev/javascript/gleam_community_colour/gleam_community@colour@accessibility.erl b/build/dev/javascript/gleam_community_colour/gleam_community@colour@accessibility.erl deleted file mode 100644 index 35c1d67..0000000 --- a/build/dev/javascript/gleam_community_colour/gleam_community@colour@accessibility.erl +++ /dev/null @@ -1,203 +0,0 @@ --module(gleam_community@colour@accessibility). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch]). --define(FILEPATH, "src/gleam_community/colour/accessibility.gleam"). --export([luminance/1, contrast_ratio/2, maximum_contrast/2]). - --if(?OTP_RELEASE >= 27). --define(MODULEDOC(Str), -moduledoc(Str)). --define(DOC(Str), -doc(Str)). --else. --define(MODULEDOC(Str), -compile([])). --define(DOC(Str), -compile([])). --endif. - -?MODULEDOC( - " \n" - " - **Accessibility**\n" - " - [`luminance`](#luminance)\n" - " - [`contrast_ratio`](#contrast_ratio)\n" - " - [`maximum_contrast`](#maximum_contrast)\n" - "\n" - " ---\n" - "\n" - " This package was heavily inspired by the `elm-color-extra` module.\n" - " The original source code can be found\n" - " here.\n" - "\n" - "
\n" - " The license of that package is produced below:\n" - " \n" - " \n" - " > MIT License\n" - "\n" - " > Copyright (c) 2016 Andreas Köberle\n" - "\n" - " > Permission is hereby granted, free of charge, to any person obtaining a copy\n" - " of this software and associated documentation files (the \"Software\"), to deal\n" - " in the Software without restriction, including without limitation the rights\n" - " to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n" - " copies of the Software, and to permit persons to whom the Software is\n" - " furnished to do so, subject to the following conditions:\n" - "\n" - " > The above copyright notice and this permission notice shall be included in all\n" - " copies or substantial portions of the Software.\n" - "\n" - " > THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n" - " IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n" - " FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n" - " AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n" - " LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n" - " OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n" - " SOFTWARE.\n" - "\n" - "
\n" - "\n" -). - --file("src/gleam_community/colour/accessibility.gleam", 56). --spec intensity(float()) -> float(). -intensity(Colour_value) -> - case true of - _ when Colour_value =< 0.03928 -> - Colour_value / 12.92; - - _ -> - I@1 = case gleam@float:power((Colour_value + 0.055) / 1.055, 2.4) of - {ok, I} -> I; - _assert_fail -> - erlang:error(#{gleam_error => let_assert, - message => <<"Pattern match failed, no pattern matched the value."/utf8>>, - file => <>, - module => <<"gleam_community/colour/accessibility"/utf8>>, - function => <<"intensity"/utf8>>, - line => 62, - value => _assert_fail, - start => 2399, - 'end' => 2470, - pattern_start => 2410, - pattern_end => 2415}) - end, - I@1 - end. - --file("src/gleam_community/colour/accessibility.gleam", 92). -?DOC( - " Returns the relative brightness of the given `Colour` as a `Float` between\n" - " 0.0, and 1.0 with 0.0 being the darkest possible colour and 1.0 being the lightest.\n" - "\n" - "
\n" - " Example:\n" - "\n" - " ```gleam\n" - " fn example() {\n" - " luminance(colour.white) // 1.0\n" - " }\n" - " ```\n" - "
\n" - "\n" - "
\n" - " \n" - " Spot a typo? Open an issue!\n" - " \n" - " \n" - " Back to top ↑\n" - " \n" - "
\n" -). --spec luminance(gleam_community@colour:colour()) -> float(). -luminance(Colour) -> - {R, G, B, _} = gleam_community@colour:to_rgba(Colour), - R_intensity = intensity(R), - G_intensity = intensity(G), - B_intensity = intensity(B), - ((0.2126 * R_intensity) + (0.7152 * G_intensity)) + (0.0722 * B_intensity). - --file("src/gleam_community/colour/accessibility.gleam", 125). -?DOC( - " Returns the contrast between two `Colour` values as a `Float` between 1.0,\n" - " and 21.0 with 1.0 being no contrast and, 21.0 being the highest possible contrast.\n" - "\n" - "
\n" - " Example:\n" - "\n" - " ```gleam\n" - " fn example() {\n" - " contrast_ratio(between: colour.white, and: colour.black) // 21.0\n" - " }\n" - " ```\n" - "
\n" - "\n" - "
\n" - " \n" - " Spot a typo? Open an issue!\n" - " \n" - " \n" - " Back to top ↑\n" - " \n" - "
\n" -). --spec contrast_ratio( - gleam_community@colour:colour(), - gleam_community@colour:colour() -) -> float(). -contrast_ratio(Colour_a, Colour_b) -> - Luminance_a = luminance(Colour_a) + 0.05, - Luminance_b = luminance(Colour_b) + 0.05, - case Luminance_a > Luminance_b of - true -> - case Luminance_b of - +0.0 -> +0.0; - -0.0 -> -0.0; - Gleam@denominator -> Luminance_a / Gleam@denominator - end; - - false -> - case Luminance_a of - +0.0 -> +0.0; - -0.0 -> -0.0; - Gleam@denominator@1 -> Luminance_b / Gleam@denominator@1 - end - end. - --file("src/gleam_community/colour/accessibility.gleam", 161). -?DOC( - " Returns the `Colour` with the highest contrast between the base `Colour`,\n" - " and and the other provided `Colour` values.\n" - "\n" - "
\n" - " Example:\n" - "\n" - " ```gleam\n" - " fn example() {\n" - " maximum_contrast(\n" - " colour.yellow,\n" - " [colour.white, colour.dark_blue, colour.green],\n" - " )\n" - " }\n" - " ```\n" - "
\n" - "\n" - "
\n" - " \n" - " Spot a typo? Open an issue!\n" - " \n" - " \n" - " Back to top ↑\n" - " \n" - "
\n" -). --spec maximum_contrast( - gleam_community@colour:colour(), - list(gleam_community@colour:colour()) -) -> {ok, gleam_community@colour:colour()} | {error, nil}. -maximum_contrast(Base, Colours) -> - _pipe = Colours, - _pipe@1 = gleam@list:sort( - _pipe, - fun(Colour_a, Colour_b) -> - Contrast_a = contrast_ratio(Base, Colour_a), - Contrast_b = contrast_ratio(Base, Colour_b), - gleam@float:compare(Contrast_b, Contrast_a) - end - ), - gleam@list:first(_pipe@1). diff --git a/build/dev/javascript/gleam_json/_gleam_artefacts/gleam@json.cache b/build/dev/javascript/gleam_json/_gleam_artefacts/gleam@json.cache deleted file mode 100644 index a74dd80..0000000 Binary files a/build/dev/javascript/gleam_json/_gleam_artefacts/gleam@json.cache and /dev/null differ diff --git a/build/dev/javascript/gleam_json/_gleam_artefacts/gleam@json.cache_inline b/build/dev/javascript/gleam_json/_gleam_artefacts/gleam@json.cache_inline deleted file mode 100644 index 1b1cb4d..0000000 Binary files a/build/dev/javascript/gleam_json/_gleam_artefacts/gleam@json.cache_inline and /dev/null differ diff --git a/build/dev/javascript/gleam_json/_gleam_artefacts/gleam@json.cache_meta b/build/dev/javascript/gleam_json/_gleam_artefacts/gleam@json.cache_meta deleted file mode 100644 index 00dd819..0000000 Binary files a/build/dev/javascript/gleam_json/_gleam_artefacts/gleam@json.cache_meta and /dev/null differ diff --git a/build/dev/javascript/gleam_json/gleam.mjs b/build/dev/javascript/gleam_json/gleam.mjs deleted file mode 100644 index 197cbbc..0000000 --- a/build/dev/javascript/gleam_json/gleam.mjs +++ /dev/null @@ -1 +0,0 @@ -export * from "../prelude.mjs"; diff --git a/build/dev/javascript/gleam_json/gleam/json.mjs b/build/dev/javascript/gleam_json/gleam/json.mjs deleted file mode 100644 index 3111ddc..0000000 --- a/build/dev/javascript/gleam_json/gleam/json.mjs +++ /dev/null @@ -1,325 +0,0 @@ -import * as $bit_array from "../../gleam_stdlib/gleam/bit_array.mjs"; -import * as $dict from "../../gleam_stdlib/gleam/dict.mjs"; -import * as $dynamic from "../../gleam_stdlib/gleam/dynamic.mjs"; -import * as $decode from "../../gleam_stdlib/gleam/dynamic/decode.mjs"; -import * as $list from "../../gleam_stdlib/gleam/list.mjs"; -import * as $option from "../../gleam_stdlib/gleam/option.mjs"; -import { None, Some } from "../../gleam_stdlib/gleam/option.mjs"; -import * as $result from "../../gleam_stdlib/gleam/result.mjs"; -import * as $string_tree from "../../gleam_stdlib/gleam/string_tree.mjs"; -import { Ok, Error, toList, prepend as listPrepend, CustomType as $CustomType } from "../gleam.mjs"; -import { - decode as decode_string, - json_to_string as do_to_string, - json_to_string as to_string_tree, - identity as do_string, - identity as do_bool, - identity as do_int, - identity as do_float, - do_null, - object as do_object, - array as do_preprocessed_array, -} from "../gleam_json_ffi.mjs"; - -export { to_string_tree }; - -export class UnexpectedEndOfInput extends $CustomType {} -export const DecodeError$UnexpectedEndOfInput = () => - new UnexpectedEndOfInput(); -export const DecodeError$isUnexpectedEndOfInput = (value) => - value instanceof UnexpectedEndOfInput; - -export class UnexpectedByte extends $CustomType { - constructor($0) { - super(); - this[0] = $0; - } -} -export const DecodeError$UnexpectedByte = ($0) => new UnexpectedByte($0); -export const DecodeError$isUnexpectedByte = (value) => - value instanceof UnexpectedByte; -export const DecodeError$UnexpectedByte$0 = (value) => value[0]; - -export class UnexpectedSequence extends $CustomType { - constructor($0) { - super(); - this[0] = $0; - } -} -export const DecodeError$UnexpectedSequence = ($0) => - new UnexpectedSequence($0); -export const DecodeError$isUnexpectedSequence = (value) => - value instanceof UnexpectedSequence; -export const DecodeError$UnexpectedSequence$0 = (value) => value[0]; - -export class UnableToDecode extends $CustomType { - constructor($0) { - super(); - this[0] = $0; - } -} -export const DecodeError$UnableToDecode = ($0) => new UnableToDecode($0); -export const DecodeError$isUnableToDecode = (value) => - value instanceof UnableToDecode; -export const DecodeError$UnableToDecode$0 = (value) => value[0]; - -function do_parse(json, decoder) { - return $result.try$( - decode_string(json), - (dynamic_value) => { - let _pipe = $decode.run(dynamic_value, decoder); - return $result.map_error( - _pipe, - (var0) => { return new UnableToDecode(var0); }, - ); - }, - ); -} - -/** - * Decode a JSON string into dynamically typed data which can be decoded into - * typed data with the `gleam/dynamic` module. - * - * ## Examples - * - * ```gleam - * > parse("[1,2,3]", decode.list(of: decode.int)) - * Ok([1, 2, 3]) - * ``` - * - * ```gleam - * > parse("[", decode.list(of: decode.int)) - * Error(UnexpectedEndOfInput) - * ``` - * - * ```gleam - * > parse("1", decode.string) - * Error(UnableToDecode([decode.DecodeError("String", "Int", [])])) - * ``` - */ -export function parse(json, decoder) { - return do_parse(json, decoder); -} - -function decode_to_dynamic(json) { - let $ = $bit_array.to_string(json); - if ($ instanceof Ok) { - let string$1 = $[0]; - return decode_string(string$1); - } else { - return new Error(new UnexpectedByte("")); - } -} - -/** - * Decode a JSON bit string into dynamically typed data which can be decoded - * into typed data with the `gleam/dynamic` module. - * - * ## Examples - * - * ```gleam - * > parse_bits(<<"[1,2,3]">>, decode.list(of: decode.int)) - * Ok([1, 2, 3]) - * ``` - * - * ```gleam - * > parse_bits(<<"[">>, decode.list(of: decode.int)) - * Error(UnexpectedEndOfInput) - * ``` - * - * ```gleam - * > parse_bits(<<"1">>, decode.string) - * Error(UnableToDecode([decode.DecodeError("String", "Int", [])])), - * ``` - */ -export function parse_bits(json, decoder) { - return $result.try$( - decode_to_dynamic(json), - (dynamic_value) => { - let _pipe = $decode.run(dynamic_value, decoder); - return $result.map_error( - _pipe, - (var0) => { return new UnableToDecode(var0); }, - ); - }, - ); -} - -/** - * Convert a JSON value into a string. - * - * Where possible prefer the `to_string_tree` function as it is faster than - * this function, and BEAM VM IO is optimised for sending `StringTree` data. - * - * ## Examples - * - * ```gleam - * > to_string(array([1, 2, 3], of: int)) - * "[1,2,3]" - * ``` - */ -export function to_string(json) { - return do_to_string(json); -} - -/** - * Encode a string into JSON, using normal JSON escaping. - * - * ## Examples - * - * ```gleam - * > to_string(string("Hello!")) - * "\"Hello!\"" - * ``` - */ -export function string(input) { - return do_string(input); -} - -/** - * Encode a bool into JSON. - * - * ## Examples - * - * ```gleam - * > to_string(bool(False)) - * "false" - * ``` - */ -export function bool(input) { - return do_bool(input); -} - -/** - * Encode an int into JSON. - * - * ## Examples - * - * ```gleam - * > to_string(int(50)) - * "50" - * ``` - */ -export function int(input) { - return do_int(input); -} - -/** - * Encode a float into JSON. - * - * ## Examples - * - * ```gleam - * > to_string(float(4.7)) - * "4.7" - * ``` - */ -export function float(input) { - return do_float(input); -} - -/** - * The JSON value null. - * - * ## Examples - * - * ```gleam - * > to_string(null()) - * "null" - * ``` - */ -export function null$() { - return do_null(); -} - -/** - * Encode an optional value into JSON, using null if it is the `None` variant. - * - * ## Examples - * - * ```gleam - * > to_string(nullable(Some(50), of: int)) - * "50" - * ``` - * - * ```gleam - * > to_string(nullable(None, of: int)) - * "null" - * ``` - */ -export function nullable(input, inner_type) { - if (input instanceof Some) { - let value = input[0]; - return inner_type(value); - } else { - return null$(); - } -} - -/** - * Encode a list of key-value pairs into a JSON object. - * - * ## Examples - * - * ```gleam - * > to_string(object([ - * #("game", string("Pac-Man")), - * #("score", int(3333360)), - * ])) - * "{\"game\":\"Pac-Mac\",\"score\":3333360}" - * ``` - */ -export function object(entries) { - return do_object(entries); -} - -/** - * Encode a list of JSON values into a JSON array. - * - * ## Examples - * - * ```gleam - * > to_string(preprocessed_array([int(1), float(2.0), string("3")])) - * "[1, 2.0, \"3\"]" - * ``` - */ -export function preprocessed_array(from) { - return do_preprocessed_array(from); -} - -/** - * Encode a list into a JSON array. - * - * ## Examples - * - * ```gleam - * > to_string(array([1, 2, 3], of: int)) - * "[1, 2, 3]" - * ``` - */ -export function array(entries, inner_type) { - let _pipe = entries; - let _pipe$1 = $list.map(_pipe, inner_type); - return preprocessed_array(_pipe$1); -} - -/** - * Encode a Dict into a JSON object using the supplied functions to encode - * the keys and the values respectively. - * - * ## Examples - * - * ```gleam - * > to_string(dict(dict.from_list([ #(3, 3.0), #(4, 4.0)]), int.to_string, float) - * "{\"3\": 3.0, \"4\": 4.0}" - * ``` - */ -export function dict(dict, keys, values) { - return object( - $dict.fold( - dict, - toList([]), - (acc, k, v) => { return listPrepend([keys(k), values(v)], acc); }, - ), - ); -} diff --git a/build/dev/javascript/gleam_json/gleam@json.erl b/build/dev/javascript/gleam_json/gleam@json.erl deleted file mode 100644 index 8a33e49..0000000 --- a/build/dev/javascript/gleam_json/gleam@json.erl +++ /dev/null @@ -1,304 +0,0 @@ --module(gleam@json). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "src/gleam/json.gleam"). --export([parse_bits/2, parse/2, to_string/1, to_string_tree/1, string/1, bool/1, int/1, float/1, null/0, nullable/2, object/1, preprocessed_array/1, array/2, dict/3]). --export_type([json/0, decode_error/0]). - --if(?OTP_RELEASE >= 27). --define(MODULEDOC(Str), -moduledoc(Str)). --define(DOC(Str), -doc(Str)). --else. --define(MODULEDOC(Str), -compile([])). --define(DOC(Str), -compile([])). --endif. - --type json() :: any(). - --type decode_error() :: unexpected_end_of_input | - {unexpected_byte, binary()} | - {unexpected_sequence, binary()} | - {unable_to_decode, list(gleam@dynamic@decode:decode_error())}. - --file("src/gleam/json.gleam", 88). -?DOC( - " Decode a JSON bit string into dynamically typed data which can be decoded\n" - " into typed data with the `gleam/dynamic` module.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " > parse_bits(<<\"[1,2,3]\">>, decode.list(of: decode.int))\n" - " Ok([1, 2, 3])\n" - " ```\n" - "\n" - " ```gleam\n" - " > parse_bits(<<\"[\">>, decode.list(of: decode.int))\n" - " Error(UnexpectedEndOfInput)\n" - " ```\n" - "\n" - " ```gleam\n" - " > parse_bits(<<\"1\">>, decode.string)\n" - " Error(UnableToDecode([decode.DecodeError(\"String\", \"Int\", [])])),\n" - " ```\n" -). --spec parse_bits(bitstring(), gleam@dynamic@decode:decoder(DNO)) -> {ok, DNO} | - {error, decode_error()}. -parse_bits(Json, Decoder) -> - gleam@result:'try'( - gleam_json_ffi:decode(Json), - fun(Dynamic_value) -> - _pipe = gleam@dynamic@decode:run(Dynamic_value, Decoder), - gleam@result:map_error( - _pipe, - fun(Field@0) -> {unable_to_decode, Field@0} end - ) - end - ). - --file("src/gleam/json.gleam", 47). --spec do_parse(binary(), gleam@dynamic@decode:decoder(DNI)) -> {ok, DNI} | - {error, decode_error()}. -do_parse(Json, Decoder) -> - Bits = gleam_stdlib:identity(Json), - parse_bits(Bits, Decoder). - --file("src/gleam/json.gleam", 39). -?DOC( - " Decode a JSON string into dynamically typed data which can be decoded into\n" - " typed data with the `gleam/dynamic` module.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " > parse(\"[1,2,3]\", decode.list(of: decode.int))\n" - " Ok([1, 2, 3])\n" - " ```\n" - "\n" - " ```gleam\n" - " > parse(\"[\", decode.list(of: decode.int))\n" - " Error(UnexpectedEndOfInput)\n" - " ```\n" - "\n" - " ```gleam\n" - " > parse(\"1\", decode.string)\n" - " Error(UnableToDecode([decode.DecodeError(\"String\", \"Int\", [])]))\n" - " ```\n" -). --spec parse(binary(), gleam@dynamic@decode:decoder(DNE)) -> {ok, DNE} | - {error, decode_error()}. -parse(Json, Decoder) -> - do_parse(Json, Decoder). - --file("src/gleam/json.gleam", 117). -?DOC( - " Convert a JSON value into a string.\n" - "\n" - " Where possible prefer the `to_string_tree` function as it is faster than\n" - " this function, and BEAM VM IO is optimised for sending `StringTree` data.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " > to_string(array([1, 2, 3], of: int))\n" - " \"[1,2,3]\"\n" - " ```\n" -). --spec to_string(json()) -> binary(). -to_string(Json) -> - gleam_json_ffi:json_to_string(Json). - --file("src/gleam/json.gleam", 140). -?DOC( - " Convert a JSON value into a string tree.\n" - "\n" - " Where possible prefer this function to the `to_string` function as it is\n" - " slower than this function, and BEAM VM IO is optimised for sending\n" - " `StringTree` data.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " > to_string_tree(array([1, 2, 3], of: int))\n" - " string_tree.from_string(\"[1,2,3]\")\n" - " ```\n" -). --spec to_string_tree(json()) -> gleam@string_tree:string_tree(). -to_string_tree(Json) -> - gleam_json_ffi:json_to_iodata(Json). - --file("src/gleam/json.gleam", 151). -?DOC( - " Encode a string into JSON, using normal JSON escaping.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " > to_string(string(\"Hello!\"))\n" - " \"\\\"Hello!\\\"\"\n" - " ```\n" -). --spec string(binary()) -> json(). -string(Input) -> - gleam_json_ffi:string(Input). - --file("src/gleam/json.gleam", 168). -?DOC( - " Encode a bool into JSON.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " > to_string(bool(False))\n" - " \"false\"\n" - " ```\n" -). --spec bool(boolean()) -> json(). -bool(Input) -> - gleam_json_ffi:bool(Input). - --file("src/gleam/json.gleam", 185). -?DOC( - " Encode an int into JSON.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " > to_string(int(50))\n" - " \"50\"\n" - " ```\n" -). --spec int(integer()) -> json(). -int(Input) -> - gleam_json_ffi:int(Input). - --file("src/gleam/json.gleam", 202). -?DOC( - " Encode a float into JSON.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " > to_string(float(4.7))\n" - " \"4.7\"\n" - " ```\n" -). --spec float(float()) -> json(). -float(Input) -> - gleam_json_ffi:float(Input). - --file("src/gleam/json.gleam", 219). -?DOC( - " The JSON value null.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " > to_string(null())\n" - " \"null\"\n" - " ```\n" -). --spec null() -> json(). -null() -> - gleam_json_ffi:null(). - --file("src/gleam/json.gleam", 241). -?DOC( - " Encode an optional value into JSON, using null if it is the `None` variant.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " > to_string(nullable(Some(50), of: int))\n" - " \"50\"\n" - " ```\n" - "\n" - " ```gleam\n" - " > to_string(nullable(None, of: int))\n" - " \"null\"\n" - " ```\n" -). --spec nullable(gleam@option:option(DNU), fun((DNU) -> json())) -> json(). -nullable(Input, Inner_type) -> - case Input of - {some, Value} -> - Inner_type(Value); - - none -> - null() - end. - --file("src/gleam/json.gleam", 260). -?DOC( - " Encode a list of key-value pairs into a JSON object.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " > to_string(object([\n" - " #(\"game\", string(\"Pac-Man\")),\n" - " #(\"score\", int(3333360)),\n" - " ]))\n" - " \"{\\\"game\\\":\\\"Pac-Mac\\\",\\\"score\\\":3333360}\"\n" - " ```\n" -). --spec object(list({binary(), json()})) -> json(). -object(Entries) -> - gleam_json_ffi:object(Entries). - --file("src/gleam/json.gleam", 292). -?DOC( - " Encode a list of JSON values into a JSON array.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " > to_string(preprocessed_array([int(1), float(2.0), string(\"3\")]))\n" - " \"[1, 2.0, \\\"3\\\"]\"\n" - " ```\n" -). --spec preprocessed_array(list(json())) -> json(). -preprocessed_array(From) -> - gleam_json_ffi:array(From). - --file("src/gleam/json.gleam", 277). -?DOC( - " Encode a list into a JSON array.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " > to_string(array([1, 2, 3], of: int))\n" - " \"[1, 2, 3]\"\n" - " ```\n" -). --spec array(list(DNY), fun((DNY) -> json())) -> json(). -array(Entries, Inner_type) -> - _pipe = Entries, - _pipe@1 = gleam@list:map(_pipe, Inner_type), - preprocessed_array(_pipe@1). - --file("src/gleam/json.gleam", 310). -?DOC( - " Encode a Dict into a JSON object using the supplied functions to encode\n" - " the keys and the values respectively.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " > to_string(dict(dict.from_list([ #(3, 3.0), #(4, 4.0)]), int.to_string, float)\n" - " \"{\\\"3\\\": 3.0, \\\"4\\\": 4.0}\"\n" - " ```\n" -). --spec dict( - gleam@dict:dict(DOC, DOD), - fun((DOC) -> binary()), - fun((DOD) -> json()) -) -> json(). -dict(Dict, Keys, Values) -> - object( - gleam@dict:fold( - Dict, - [], - fun(Acc, K, V) -> [{Keys(K), Values(V)} | Acc] end - ) - ). diff --git a/build/dev/javascript/gleam_json/gleam_json_ffi.erl b/build/dev/javascript/gleam_json/gleam_json_ffi.erl deleted file mode 100644 index 06a26a0..0000000 --- a/build/dev/javascript/gleam_json/gleam_json_ffi.erl +++ /dev/null @@ -1,66 +0,0 @@ --module(gleam_json_ffi). - --export([ - decode/1, json_to_iodata/1, json_to_string/1, int/1, float/1, string/1, - bool/1, null/0, array/1, object/1 -]). - --if(?OTP_RELEASE < 27). --define(bad_version, - error({erlang_otp_27_required, << "Insufficient Erlang/OTP version. - -`gleam_json` uses the Erlang `json` module introduced in Erlang/OTP 27. -You are using Erlang/OTP "/utf8, (integer_to_binary(?OTP_RELEASE))/binary, " -Please upgrade your Erlang install or downgrade to `gleam_json` v1.0.1. -"/utf8>>})). - -decode(_) -> ?bad_version. -json_to_iodata(_) -> ?bad_version. -json_to_string(_) -> ?bad_version. -int(_) -> ?bad_version. -float(_) -> ?bad_version. -string(_) -> ?bad_version. -bool(_) -> ?bad_version. -array(_) -> ?bad_version. -object(_) -> ?bad_version. -null() -> ?bad_version. --else. - -decode(Json) -> - try - {ok, json:decode(Json)} - catch - error:unexpected_end -> {error, unexpected_end_of_input}; - error:{invalid_byte, Byte} -> {error, {unexpected_byte, hex(Byte)}}; - error:{unexpected_sequence, Byte} -> {error, {unexpected_sequence, Byte}} - end. - -hex(I) -> - H = list_to_binary(integer_to_list(I, 16)), - <<"0x"/utf8, H/binary>>. - -json_to_iodata(Json) -> - Json. - -json_to_string(Json) when is_binary(Json) -> - Json; -json_to_string(Json) when is_list(Json) -> - list_to_binary(Json). - -null() -> <<"null">>. -bool(true) -> <<"true">>; -bool(false) -> <<"false">>. -int(X) -> json:encode_integer(X). -float(X) -> json:encode_float(X). -string(X) -> json:encode_binary(X). - -array([]) -> <<"[]">>; -array([First | Rest]) -> [$[, First | array_loop(Rest)]. -array_loop([]) -> "]"; -array_loop([Elem | Rest]) -> [$,, Elem | array_loop(Rest)]. - -object(List) -> encode_object([[$,, string(Key), $: | Value] || {Key, Value} <- List]). -encode_object([]) -> <<"{}">>; -encode_object([[_Comma | Entry] | Rest]) -> ["{", Entry, Rest, "}"]. - --endif. diff --git a/build/dev/javascript/gleam_json/gleam_json_ffi.mjs b/build/dev/javascript/gleam_json/gleam_json_ffi.mjs deleted file mode 100644 index 1d8d3ff..0000000 --- a/build/dev/javascript/gleam_json/gleam_json_ffi.mjs +++ /dev/null @@ -1,201 +0,0 @@ -import { - Result$Ok, - Result$Error, - List$isNonEmpty, - List$NonEmpty$first, - List$NonEmpty$rest, -} from "./gleam.mjs"; -import { - DecodeError$UnexpectedByte, - DecodeError$UnexpectedEndOfInput, -} from "./gleam/json.mjs"; - -export function json_to_string(json) { - return JSON.stringify(json); -} - -export function object(entries) { - return Object.fromEntries(entries); -} - -export function identity(x) { - return x; -} - -export function array(list) { - const array = []; - while (List$isNonEmpty(list)) { - array.push(List$NonEmpty$first(list)); - list = List$NonEmpty$rest(list); - } - return array; -} - -export function do_null() { - return null; -} - -export function decode(string) { - try { - const result = JSON.parse(string); - return Result$Ok(result); - } catch (err) { - return Result$Error(getJsonDecodeError(err, string)); - } -} - -export function getJsonDecodeError(stdErr, json) { - if (isUnexpectedEndOfInput(stdErr)) return DecodeError$UnexpectedEndOfInput(); - return toUnexpectedByteError(stdErr, json); -} - -/** - * Matches unexpected end of input messages in: - * - Chromium (edge, chrome, node) - * - Spidermonkey (firefox) - * - JavascriptCore (safari) - * - * Note that Spidermonkey and JavascriptCore will both incorrectly report some - * UnexpectedByte errors as UnexpectedEndOfInput errors. For example: - * - * @example - * // in JavascriptCore - * JSON.parse('{"a"]: "b"}) - * // => JSON Parse error: Expected ':' before value - * - * JSON.parse('{"a"') - * // => JSON Parse error: Expected ':' before value - * - * // in Chromium (correct) - * JSON.parse('{"a"]: "b"}) - * // => Unexpected token ] in JSON at position 4 - * - * JSON.parse('{"a"') - * // => Unexpected end of JSON input - */ -function isUnexpectedEndOfInput(err) { - const unexpectedEndOfInputRegex = - /((unexpected (end|eof))|(end of data)|(unterminated string)|(json( parse error|\.parse)\: expected '(\:|\}|\])'))/i; - return unexpectedEndOfInputRegex.test(err.message); -} - -/** - * Converts a SyntaxError to an UnexpectedByte error based on the JS runtime. - * - * For Chromium, the unexpected byte and position are reported by the runtime. - * - * For JavascriptCore, only the unexpected byte is reported by the runtime, so - * there is no way to know which position that character is in unless we then - * parse the string again ourselves. So instead, the position is reported as 0. - * - * For Spidermonkey, the position is reported by the runtime as a line and column number - * and the unexpected byte is found using those coordinates. - */ -function toUnexpectedByteError(err, json) { - let converters = [ - v8UnexpectedByteError, - oldV8UnexpectedByteError, - jsCoreUnexpectedByteError, - spidermonkeyUnexpectedByteError, - ]; - - for (let converter of converters) { - let result = converter(err, json); - if (result) return result; - } - - return DecodeError$UnexpectedByte(""); -} - -/** - * Matches unexpected byte messages in: - * - V8 (edge, chrome, node) - * - * Matches the character but not the position as this is no longer reported by - * V8. Boo! - */ -function v8UnexpectedByteError(err) { - const regex = /unexpected token '(.)', ".+" is not valid JSON/i; - const match = regex.exec(err.message); - if (!match) return null; - const byte = toHex(match[1]); - return DecodeError$UnexpectedByte(byte); -} - -/** - * Matches unexpected byte messages in: - * - V8 (edge, chrome, node) - * - * No longer works in current versions of V8. - * - * Matches the character and its position. - */ -function oldV8UnexpectedByteError(err) { - const regex = /unexpected token (.) in JSON at position (\d+)/i; - const match = regex.exec(err.message); - if (!match) return null; - const byte = toHex(match[1]); - return DecodeError$UnexpectedByte(byte); -} - -/** - * Matches unexpected byte messages in: - * - Spidermonkey (firefox) - * - * Matches the position in a 2d grid only and not the character. - */ -function spidermonkeyUnexpectedByteError(err, json) { - const regex = - /(unexpected character|expected .*) at line (\d+) column (\d+)/i; - const match = regex.exec(err.message); - if (!match) return null; - const line = Number(match[2]); - const column = Number(match[3]); - const position = getPositionFromMultiline(line, column, json); - const byte = toHex(json[position]); - return DecodeError$UnexpectedByte(byte); -} - -/** - * Matches unexpected byte messages in: - * - JavascriptCore (safari) - * - * JavascriptCore only reports what the character is and not its position. - */ -function jsCoreUnexpectedByteError(err) { - const regex = /unexpected (identifier|token) "(.)"/i; - const match = regex.exec(err.message); - if (!match) return null; - const byte = toHex(match[2]); - return DecodeError$UnexpectedByte(byte); -} - -function toHex(char) { - return "0x" + char.charCodeAt(0).toString(16).toUpperCase(); -} - -/** - * Gets the position of a character in a flattened (i.e. single line) string - * from a line and column number. Note that the position is 0-indexed and - * the line and column numbers are 1-indexed. - * - * @param {number} line - * @param {number} column - * @param {string} string - */ -function getPositionFromMultiline(line, column, string) { - if (line === 1) return column - 1; - - let currentLn = 1; - let position = 0; - string.split("").find((char, idx) => { - if (char === "\n") currentLn += 1; - if (currentLn === line) { - position = idx + column; - return true; - } - return false; - }); - - return position; -} diff --git a/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@bit_array.cache b/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@bit_array.cache deleted file mode 100644 index 8c670b6..0000000 Binary files a/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@bit_array.cache and /dev/null differ diff --git a/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@bit_array.cache_inline b/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@bit_array.cache_inline deleted file mode 100644 index 1b1cb4d..0000000 Binary files a/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@bit_array.cache_inline and /dev/null differ diff --git a/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@bit_array.cache_meta b/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@bit_array.cache_meta deleted file mode 100644 index 35d8d57..0000000 Binary files a/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@bit_array.cache_meta and /dev/null differ diff --git a/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@bool.cache b/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@bool.cache deleted file mode 100644 index 23c6ee1..0000000 Binary files a/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@bool.cache and /dev/null differ diff --git a/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@bool.cache_inline b/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@bool.cache_inline deleted file mode 100644 index 52a93fa..0000000 Binary files a/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@bool.cache_inline and /dev/null differ diff --git a/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@bool.cache_meta b/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@bool.cache_meta deleted file mode 100644 index c6b30c1..0000000 Binary files a/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@bool.cache_meta and /dev/null differ diff --git a/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@bytes_tree.cache b/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@bytes_tree.cache deleted file mode 100644 index e7446ce..0000000 Binary files a/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@bytes_tree.cache and /dev/null differ diff --git a/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@bytes_tree.cache_inline b/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@bytes_tree.cache_inline deleted file mode 100644 index 1b1cb4d..0000000 Binary files a/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@bytes_tree.cache_inline and /dev/null differ diff --git a/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@bytes_tree.cache_meta b/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@bytes_tree.cache_meta deleted file mode 100644 index b00ed33..0000000 Binary files a/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@bytes_tree.cache_meta and /dev/null differ diff --git a/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@dict.cache b/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@dict.cache deleted file mode 100644 index 8c73d9f..0000000 Binary files a/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@dict.cache and /dev/null differ diff --git a/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@dict.cache_inline b/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@dict.cache_inline deleted file mode 100644 index 1b1cb4d..0000000 Binary files a/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@dict.cache_inline and /dev/null differ diff --git a/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@dict.cache_meta b/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@dict.cache_meta deleted file mode 100644 index db29c27..0000000 Binary files a/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@dict.cache_meta and /dev/null differ diff --git a/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@dynamic.cache b/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@dynamic.cache deleted file mode 100644 index bbe4a32..0000000 Binary files a/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@dynamic.cache and /dev/null differ diff --git a/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@dynamic.cache_inline b/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@dynamic.cache_inline deleted file mode 100644 index 1b1cb4d..0000000 Binary files a/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@dynamic.cache_inline and /dev/null differ diff --git a/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@dynamic.cache_meta b/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@dynamic.cache_meta deleted file mode 100644 index 28bcb8b..0000000 Binary files a/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@dynamic.cache_meta and /dev/null differ diff --git a/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@dynamic@decode.cache b/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@dynamic@decode.cache deleted file mode 100644 index 3035efb..0000000 Binary files a/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@dynamic@decode.cache and /dev/null differ diff --git a/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@dynamic@decode.cache_inline b/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@dynamic@decode.cache_inline deleted file mode 100644 index 1b1cb4d..0000000 Binary files a/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@dynamic@decode.cache_inline and /dev/null differ diff --git a/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@dynamic@decode.cache_meta b/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@dynamic@decode.cache_meta deleted file mode 100644 index cf83b53..0000000 Binary files a/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@dynamic@decode.cache_meta and /dev/null differ diff --git a/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@float.cache b/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@float.cache deleted file mode 100644 index ec9449c..0000000 Binary files a/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@float.cache and /dev/null differ diff --git a/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@float.cache_inline b/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@float.cache_inline deleted file mode 100644 index 1b1cb4d..0000000 Binary files a/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@float.cache_inline and /dev/null differ diff --git a/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@float.cache_meta b/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@float.cache_meta deleted file mode 100644 index 604414b..0000000 Binary files a/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@float.cache_meta and /dev/null differ diff --git a/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@function.cache b/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@function.cache deleted file mode 100644 index 4664383..0000000 Binary files a/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@function.cache and /dev/null differ diff --git a/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@function.cache_inline b/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@function.cache_inline deleted file mode 100644 index 1b1cb4d..0000000 Binary files a/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@function.cache_inline and /dev/null differ diff --git a/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@function.cache_meta b/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@function.cache_meta deleted file mode 100644 index 1f87f09..0000000 Binary files a/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@function.cache_meta and /dev/null differ diff --git a/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@int.cache b/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@int.cache deleted file mode 100644 index 4224cad..0000000 Binary files a/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@int.cache and /dev/null differ diff --git a/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@int.cache_inline b/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@int.cache_inline deleted file mode 100644 index 1b1cb4d..0000000 Binary files a/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@int.cache_inline and /dev/null differ diff --git a/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@int.cache_meta b/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@int.cache_meta deleted file mode 100644 index 8730828..0000000 Binary files a/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@int.cache_meta and /dev/null differ diff --git a/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@io.cache b/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@io.cache deleted file mode 100644 index fb831f1..0000000 Binary files a/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@io.cache and /dev/null differ diff --git a/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@io.cache_inline b/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@io.cache_inline deleted file mode 100644 index 1b1cb4d..0000000 Binary files a/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@io.cache_inline and /dev/null differ diff --git a/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@io.cache_meta b/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@io.cache_meta deleted file mode 100644 index b6b0435..0000000 Binary files a/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@io.cache_meta and /dev/null differ diff --git a/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@list.cache b/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@list.cache deleted file mode 100644 index 7513b89..0000000 Binary files a/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@list.cache and /dev/null differ diff --git a/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@list.cache_inline b/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@list.cache_inline deleted file mode 100644 index 1b1cb4d..0000000 Binary files a/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@list.cache_inline and /dev/null differ diff --git a/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@list.cache_meta b/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@list.cache_meta deleted file mode 100644 index 78ca370..0000000 Binary files a/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@list.cache_meta and /dev/null differ diff --git a/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@option.cache b/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@option.cache deleted file mode 100644 index 76a7836..0000000 Binary files a/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@option.cache and /dev/null differ diff --git a/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@option.cache_inline b/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@option.cache_inline deleted file mode 100644 index 1b1cb4d..0000000 Binary files a/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@option.cache_inline and /dev/null differ diff --git a/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@option.cache_meta b/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@option.cache_meta deleted file mode 100644 index 8656c26..0000000 Binary files a/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@option.cache_meta and /dev/null differ diff --git a/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@order.cache b/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@order.cache deleted file mode 100644 index ad64dbc..0000000 Binary files a/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@order.cache and /dev/null differ diff --git a/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@order.cache_inline b/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@order.cache_inline deleted file mode 100644 index 1b1cb4d..0000000 Binary files a/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@order.cache_inline and /dev/null differ diff --git a/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@order.cache_meta b/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@order.cache_meta deleted file mode 100644 index 4404517..0000000 Binary files a/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@order.cache_meta and /dev/null differ diff --git a/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@pair.cache b/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@pair.cache deleted file mode 100644 index 7032bdd..0000000 Binary files a/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@pair.cache and /dev/null differ diff --git a/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@pair.cache_inline b/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@pair.cache_inline deleted file mode 100644 index 1b1cb4d..0000000 Binary files a/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@pair.cache_inline and /dev/null differ diff --git a/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@pair.cache_meta b/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@pair.cache_meta deleted file mode 100644 index daa77fc..0000000 Binary files a/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@pair.cache_meta and /dev/null differ diff --git a/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@result.cache b/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@result.cache deleted file mode 100644 index 3e0c211..0000000 Binary files a/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@result.cache and /dev/null differ diff --git a/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@result.cache_inline b/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@result.cache_inline deleted file mode 100644 index 3d06590..0000000 Binary files a/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@result.cache_inline and /dev/null differ diff --git a/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@result.cache_meta b/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@result.cache_meta deleted file mode 100644 index b023748..0000000 Binary files a/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@result.cache_meta and /dev/null differ diff --git a/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@set.cache b/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@set.cache deleted file mode 100644 index 12a446a..0000000 Binary files a/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@set.cache and /dev/null differ diff --git a/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@set.cache_inline b/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@set.cache_inline deleted file mode 100644 index 1b1cb4d..0000000 Binary files a/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@set.cache_inline and /dev/null differ diff --git a/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@set.cache_meta b/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@set.cache_meta deleted file mode 100644 index e5bd75e..0000000 Binary files a/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@set.cache_meta and /dev/null differ diff --git a/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@string.cache b/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@string.cache deleted file mode 100644 index f316fb5..0000000 Binary files a/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@string.cache and /dev/null differ diff --git a/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@string.cache_inline b/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@string.cache_inline deleted file mode 100644 index 1b1cb4d..0000000 Binary files a/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@string.cache_inline and /dev/null differ diff --git a/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@string.cache_meta b/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@string.cache_meta deleted file mode 100644 index 09ee85c..0000000 Binary files a/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@string.cache_meta and /dev/null differ diff --git a/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@string_tree.cache b/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@string_tree.cache deleted file mode 100644 index 93d3cc1..0000000 Binary files a/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@string_tree.cache and /dev/null differ diff --git a/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@string_tree.cache_inline b/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@string_tree.cache_inline deleted file mode 100644 index 1b1cb4d..0000000 Binary files a/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@string_tree.cache_inline and /dev/null differ diff --git a/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@string_tree.cache_meta b/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@string_tree.cache_meta deleted file mode 100644 index abfcf6a..0000000 Binary files a/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@string_tree.cache_meta and /dev/null differ diff --git a/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@uri.cache b/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@uri.cache deleted file mode 100644 index f51ee88..0000000 Binary files a/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@uri.cache and /dev/null differ diff --git a/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@uri.cache_inline b/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@uri.cache_inline deleted file mode 100644 index 1b1cb4d..0000000 Binary files a/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@uri.cache_inline and /dev/null differ diff --git a/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@uri.cache_meta b/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@uri.cache_meta deleted file mode 100644 index a2b0e30..0000000 Binary files a/build/dev/javascript/gleam_stdlib/_gleam_artefacts/gleam@uri.cache_meta and /dev/null differ diff --git a/build/dev/javascript/gleam_stdlib/dict.mjs b/build/dev/javascript/gleam_stdlib/dict.mjs deleted file mode 100644 index f39cd54..0000000 --- a/build/dev/javascript/gleam_stdlib/dict.mjs +++ /dev/null @@ -1,993 +0,0 @@ -/** - * This file uses jsdoc to annotate types. - * These types can be checked using the typescript compiler with "checkjs" option. - */ - -import { isEqual } from "./gleam.mjs"; - -const referenceMap = /* @__PURE__ */ new WeakMap(); -const tempDataView = /* @__PURE__ */ new DataView( - /* @__PURE__ */ new ArrayBuffer(8), -); -let referenceUID = 0; -/** - * hash the object by reference using a weak map and incrementing uid - * @param {any} o - * @returns {number} - */ -function hashByReference(o) { - const known = referenceMap.get(o); - if (known !== undefined) { - return known; - } - const hash = referenceUID++; - if (referenceUID === 0x7fffffff) { - referenceUID = 0; - } - referenceMap.set(o, hash); - return hash; -} - -/** - * merge two hashes in an order sensitive way - * @param {number} a - * @param {number} b - * @returns {number} - */ -function hashMerge(a, b) { - return (a ^ (b + 0x9e3779b9 + (a << 6) + (a >> 2))) | 0; -} - -/** - * standard string hash popularised by java - * @param {string} s - * @returns {number} - */ -function hashString(s) { - let hash = 0; - const len = s.length; - for (let i = 0; i < len; i++) { - hash = (Math.imul(31, hash) + s.charCodeAt(i)) | 0; - } - return hash; -} - -/** - * hash a number by converting to two integers and do some jumbling - * @param {number} n - * @returns {number} - */ -function hashNumber(n) { - tempDataView.setFloat64(0, n); - const i = tempDataView.getInt32(0); - const j = tempDataView.getInt32(4); - return Math.imul(0x45d9f3b, (i >> 16) ^ i) ^ j; -} - -/** - * hash a BigInt by converting it to a string and hashing that - * @param {BigInt} n - * @returns {number} - */ -function hashBigInt(n) { - return hashString(n.toString()); -} - -/** - * hash any js object - * @param {any} o - * @returns {number} - */ -function hashObject(o) { - const proto = Object.getPrototypeOf(o); - if (proto !== null && typeof proto.hashCode === "function") { - try { - const code = o.hashCode(o); - if (typeof code === "number") { - return code; - } - } catch {} - } - if (o instanceof Promise || o instanceof WeakSet || o instanceof WeakMap) { - return hashByReference(o); - } - if (o instanceof Date) { - return hashNumber(o.getTime()); - } - let h = 0; - if (o instanceof ArrayBuffer) { - o = new Uint8Array(o); - } - if (Array.isArray(o) || o instanceof Uint8Array) { - for (let i = 0; i < o.length; i++) { - h = (Math.imul(31, h) + getHash(o[i])) | 0; - } - } else if (o instanceof Set) { - o.forEach((v) => { - h = (h + getHash(v)) | 0; - }); - } else if (o instanceof Map) { - o.forEach((v, k) => { - h = (h + hashMerge(getHash(v), getHash(k))) | 0; - }); - } else { - const keys = Object.keys(o); - for (let i = 0; i < keys.length; i++) { - const k = keys[i]; - const v = o[k]; - h = (h + hashMerge(getHash(v), hashString(k))) | 0; - } - } - return h; -} - -/** - * hash any js value - * @param {any} u - * @returns {number} - */ -export function getHash(u) { - if (u === null) return 0x42108422; - if (u === undefined) return 0x42108423; - if (u === true) return 0x42108421; - if (u === false) return 0x42108420; - switch (typeof u) { - case "number": - return hashNumber(u); - case "string": - return hashString(u); - case "bigint": - return hashBigInt(u); - case "object": - return hashObject(u); - case "symbol": - return hashByReference(u); - case "function": - return hashByReference(u); - default: - return 0; // should be unreachable - } -} - -/** - * @template K,V - * @typedef {ArrayNode | IndexNode | CollisionNode} Node - */ -/** - * @template K,V - * @typedef {{ type: typeof ENTRY, k: K, v: V }} Entry - */ -/** - * @template K,V - * @typedef {{ type: typeof ARRAY_NODE, size: number, array: (undefined | Entry | Node)[] }} ArrayNode - */ -/** - * @template K,V - * @typedef {{ type: typeof INDEX_NODE, bitmap: number, array: (Entry | Node)[] }} IndexNode - */ -/** - * @template K,V - * @typedef {{ type: typeof COLLISION_NODE, hash: number, array: Entry[] }} CollisionNode - */ -/** - * @typedef {{ val: boolean }} Flag - */ -const SHIFT = 5; // number of bits you need to shift by to get the next bucket -const BUCKET_SIZE = Math.pow(2, SHIFT); -const MASK = BUCKET_SIZE - 1; // used to zero out all bits not in the bucket -const MAX_INDEX_NODE = BUCKET_SIZE / 2; // when does index node grow into array node -const MIN_ARRAY_NODE = BUCKET_SIZE / 4; // when does array node shrink to index node -const ENTRY = 0; -const ARRAY_NODE = 1; -const INDEX_NODE = 2; -const COLLISION_NODE = 3; - -/** @type {IndexNode} */ -const EMPTY = { - type: INDEX_NODE, - bitmap: 0, - array: [], -}; -/** - * Mask the hash to get only the bucket corresponding to shift - * @param {number} hash - * @param {number} shift - * @returns {number} - */ -function mask(hash, shift) { - return (hash >>> shift) & MASK; -} - -/** - * Set only the Nth bit where N is the masked hash - * @param {number} hash - * @param {number} shift - * @returns {number} - */ -function bitpos(hash, shift) { - return 1 << mask(hash, shift); -} - -/** - * Count the number of 1 bits in a number - * @param {number} x - * @returns {number} - */ -function bitcount(x) { - x -= (x >> 1) & 0x55555555; - x = (x & 0x33333333) + ((x >> 2) & 0x33333333); - x = (x + (x >> 4)) & 0x0f0f0f0f; - x += x >> 8; - x += x >> 16; - return x & 0x7f; -} - -/** - * Calculate the array index of an item in a bitmap index node - * @param {number} bitmap - * @param {number} bit - * @returns {number} - */ -function index(bitmap, bit) { - return bitcount(bitmap & (bit - 1)); -} - -/** - * Efficiently copy an array and set one value at an index - * @template T - * @param {T[]} arr - * @param {number} at - * @param {T} val - * @returns {T[]} - */ -function cloneAndSet(arr, at, val) { - const len = arr.length; - const out = new Array(len); - for (let i = 0; i < len; ++i) { - out[i] = arr[i]; - } - out[at] = val; - return out; -} - -/** - * Efficiently copy an array and insert one value at an index - * @template T - * @param {T[]} arr - * @param {number} at - * @param {T} val - * @returns {T[]} - */ -function spliceIn(arr, at, val) { - const len = arr.length; - const out = new Array(len + 1); - let i = 0; - let g = 0; - while (i < at) { - out[g++] = arr[i++]; - } - out[g++] = val; - while (i < len) { - out[g++] = arr[i++]; - } - return out; -} - -/** - * Efficiently copy an array and remove one value at an index - * @template T - * @param {T[]} arr - * @param {number} at - * @returns {T[]} - */ -function spliceOut(arr, at) { - const len = arr.length; - const out = new Array(len - 1); - let i = 0; - let g = 0; - while (i < at) { - out[g++] = arr[i++]; - } - ++i; - while (i < len) { - out[g++] = arr[i++]; - } - return out; -} - -/** - * Create a new node containing two entries - * @template K,V - * @param {number} shift - * @param {K} key1 - * @param {V} val1 - * @param {number} key2hash - * @param {K} key2 - * @param {V} val2 - * @returns {Node} - */ -function createNode(shift, key1, val1, key2hash, key2, val2) { - const key1hash = getHash(key1); - if (key1hash === key2hash) { - return { - type: COLLISION_NODE, - hash: key1hash, - array: [ - { type: ENTRY, k: key1, v: val1 }, - { type: ENTRY, k: key2, v: val2 }, - ], - }; - } - const addedLeaf = { val: false }; - return assoc( - assocIndex(EMPTY, shift, key1hash, key1, val1, addedLeaf), - shift, - key2hash, - key2, - val2, - addedLeaf, - ); -} - -/** - * @template T,K,V - * @callback AssocFunction - * @param {T} root - * @param {number} shift - * @param {number} hash - * @param {K} key - * @param {V} val - * @param {Flag} addedLeaf - * @returns {Node} - */ -/** - * Associate a node with a new entry, creating a new node - * @template T,K,V - * @type {AssocFunction,K,V>} - */ -function assoc(root, shift, hash, key, val, addedLeaf) { - switch (root.type) { - case ARRAY_NODE: - return assocArray(root, shift, hash, key, val, addedLeaf); - case INDEX_NODE: - return assocIndex(root, shift, hash, key, val, addedLeaf); - case COLLISION_NODE: - return assocCollision(root, shift, hash, key, val, addedLeaf); - } -} -/** - * @template T,K,V - * @type {AssocFunction,K,V>} - */ -function assocArray(root, shift, hash, key, val, addedLeaf) { - const idx = mask(hash, shift); - const node = root.array[idx]; - // if the corresponding index is empty set the index to a newly created node - if (node === undefined) { - addedLeaf.val = true; - return { - type: ARRAY_NODE, - size: root.size + 1, - array: cloneAndSet(root.array, idx, { type: ENTRY, k: key, v: val }), - }; - } - if (node.type === ENTRY) { - // if keys are equal replace the entry - if (isEqual(key, node.k)) { - if (val === node.v) { - return root; - } - return { - type: ARRAY_NODE, - size: root.size, - array: cloneAndSet(root.array, idx, { - type: ENTRY, - k: key, - v: val, - }), - }; - } - // otherwise upgrade the entry to a node and insert - addedLeaf.val = true; - return { - type: ARRAY_NODE, - size: root.size, - array: cloneAndSet( - root.array, - idx, - createNode(shift + SHIFT, node.k, node.v, hash, key, val), - ), - }; - } - // otherwise call assoc on the child node - const n = assoc(node, shift + SHIFT, hash, key, val, addedLeaf); - // if the child node hasn't changed just return the old root - if (n === node) { - return root; - } - // otherwise set the index to the new node - return { - type: ARRAY_NODE, - size: root.size, - array: cloneAndSet(root.array, idx, n), - }; -} -/** - * @template T,K,V - * @type {AssocFunction,K,V>} - */ -function assocIndex(root, shift, hash, key, val, addedLeaf) { - const bit = bitpos(hash, shift); - const idx = index(root.bitmap, bit); - // if there is already a item at this hash index.. - if ((root.bitmap & bit) !== 0) { - // if there is a node at the index (not an entry), call assoc on the child node - const node = root.array[idx]; - if (node.type !== ENTRY) { - const n = assoc(node, shift + SHIFT, hash, key, val, addedLeaf); - if (n === node) { - return root; - } - return { - type: INDEX_NODE, - bitmap: root.bitmap, - array: cloneAndSet(root.array, idx, n), - }; - } - // otherwise there is an entry at the index - // if the keys are equal replace the entry with the updated value - const nodeKey = node.k; - if (isEqual(key, nodeKey)) { - if (val === node.v) { - return root; - } - return { - type: INDEX_NODE, - bitmap: root.bitmap, - array: cloneAndSet(root.array, idx, { - type: ENTRY, - k: key, - v: val, - }), - }; - } - // if the keys are not equal, replace the entry with a new child node - addedLeaf.val = true; - return { - type: INDEX_NODE, - bitmap: root.bitmap, - array: cloneAndSet( - root.array, - idx, - createNode(shift + SHIFT, nodeKey, node.v, hash, key, val), - ), - }; - } else { - // else there is currently no item at the hash index - const n = root.array.length; - // if the number of nodes is at the maximum, expand this node into an array node - if (n >= MAX_INDEX_NODE) { - // create a 32 length array for the new array node (one for each bit in the hash) - const nodes = new Array(32); - // create and insert a node for the new entry - const jdx = mask(hash, shift); - nodes[jdx] = assocIndex(EMPTY, shift + SHIFT, hash, key, val, addedLeaf); - let j = 0; - let bitmap = root.bitmap; - // place each item in the index node into the correct spot in the array node - // loop through all 32 bits / array positions - for (let i = 0; i < 32; i++) { - if ((bitmap & 1) !== 0) { - const node = root.array[j++]; - nodes[i] = node; - } - // shift the bitmap to process the next bit - bitmap = bitmap >>> 1; - } - return { - type: ARRAY_NODE, - size: n + 1, - array: nodes, - }; - } else { - // else there is still space in this index node - // simply insert a new entry at the hash index - const newArray = spliceIn(root.array, idx, { - type: ENTRY, - k: key, - v: val, - }); - addedLeaf.val = true; - return { - type: INDEX_NODE, - bitmap: root.bitmap | bit, - array: newArray, - }; - } - } -} -/** - * @template T,K,V - * @type {AssocFunction,K,V>} - */ -function assocCollision(root, shift, hash, key, val, addedLeaf) { - // if there is a hash collision - if (hash === root.hash) { - const idx = collisionIndexOf(root, key); - // if this key already exists replace the entry with the new value - if (idx !== -1) { - const entry = root.array[idx]; - if (entry.v === val) { - return root; - } - return { - type: COLLISION_NODE, - hash: hash, - array: cloneAndSet(root.array, idx, { type: ENTRY, k: key, v: val }), - }; - } - // otherwise insert the entry at the end of the array - const size = root.array.length; - addedLeaf.val = true; - return { - type: COLLISION_NODE, - hash: hash, - array: cloneAndSet(root.array, size, { type: ENTRY, k: key, v: val }), - }; - } - // if there is no hash collision, upgrade to an index node - return assoc( - { - type: INDEX_NODE, - bitmap: bitpos(root.hash, shift), - array: [root], - }, - shift, - hash, - key, - val, - addedLeaf, - ); -} -/** - * Find the index of a key in the collision node's array - * @template K,V - * @param {CollisionNode} root - * @param {K} key - * @returns {number} - */ -function collisionIndexOf(root, key) { - const size = root.array.length; - for (let i = 0; i < size; i++) { - if (isEqual(key, root.array[i].k)) { - return i; - } - } - return -1; -} -/** - * @template T,K,V - * @callback FindFunction - * @param {T} root - * @param {number} shift - * @param {number} hash - * @param {K} key - * @returns {undefined | Entry} - */ -/** - * Return the found entry or undefined if not present in the root - * @template K,V - * @type {FindFunction,K,V>} - */ -function find(root, shift, hash, key) { - switch (root.type) { - case ARRAY_NODE: - return findArray(root, shift, hash, key); - case INDEX_NODE: - return findIndex(root, shift, hash, key); - case COLLISION_NODE: - return findCollision(root, key); - } -} -/** - * @template K,V - * @type {FindFunction,K,V>} - */ -function findArray(root, shift, hash, key) { - const idx = mask(hash, shift); - const node = root.array[idx]; - if (node === undefined) { - return undefined; - } - if (node.type !== ENTRY) { - return find(node, shift + SHIFT, hash, key); - } - if (isEqual(key, node.k)) { - return node; - } - return undefined; -} -/** - * @template K,V - * @type {FindFunction,K,V>} - */ -function findIndex(root, shift, hash, key) { - const bit = bitpos(hash, shift); - if ((root.bitmap & bit) === 0) { - return undefined; - } - const idx = index(root.bitmap, bit); - const node = root.array[idx]; - if (node.type !== ENTRY) { - return find(node, shift + SHIFT, hash, key); - } - if (isEqual(key, node.k)) { - return node; - } - return undefined; -} -/** - * @template K,V - * @param {CollisionNode} root - * @param {K} key - * @returns {undefined | Entry} - */ -function findCollision(root, key) { - const idx = collisionIndexOf(root, key); - if (idx < 0) { - return undefined; - } - return root.array[idx]; -} -/** - * @template T,K,V - * @callback WithoutFunction - * @param {T} root - * @param {number} shift - * @param {number} hash - * @param {K} key - * @returns {undefined | Node} - */ -/** - * Remove an entry from the root, returning the updated root. - * Returns undefined if the node should be removed from the parent. - * @template K,V - * @type {WithoutFunction,K,V>} - * */ -function without(root, shift, hash, key) { - switch (root.type) { - case ARRAY_NODE: - return withoutArray(root, shift, hash, key); - case INDEX_NODE: - return withoutIndex(root, shift, hash, key); - case COLLISION_NODE: - return withoutCollision(root, key); - } -} -/** - * @template K,V - * @type {WithoutFunction,K,V>} - */ -function withoutArray(root, shift, hash, key) { - const idx = mask(hash, shift); - const node = root.array[idx]; - if (node === undefined) { - return root; // already empty - } - let n = undefined; - // if node is an entry and the keys are not equal there is nothing to remove - // if node is not an entry do a recursive call - if (node.type === ENTRY) { - if (!isEqual(node.k, key)) { - return root; // no changes - } - } else { - n = without(node, shift + SHIFT, hash, key); - if (n === node) { - return root; // no changes - } - } - // if the recursive call returned undefined the node should be removed - if (n === undefined) { - // if the number of child nodes is at the minimum, pack into an index node - if (root.size <= MIN_ARRAY_NODE) { - const arr = root.array; - const out = new Array(root.size - 1); - let i = 0; - let j = 0; - let bitmap = 0; - while (i < idx) { - const nv = arr[i]; - if (nv !== undefined) { - out[j] = nv; - bitmap |= 1 << i; - ++j; - } - ++i; - } - ++i; // skip copying the removed node - while (i < arr.length) { - const nv = arr[i]; - if (nv !== undefined) { - out[j] = nv; - bitmap |= 1 << i; - ++j; - } - ++i; - } - return { - type: INDEX_NODE, - bitmap: bitmap, - array: out, - }; - } - return { - type: ARRAY_NODE, - size: root.size - 1, - array: cloneAndSet(root.array, idx, n), - }; - } - return { - type: ARRAY_NODE, - size: root.size, - array: cloneAndSet(root.array, idx, n), - }; -} -/** - * @template K,V - * @type {WithoutFunction,K,V>} - */ -function withoutIndex(root, shift, hash, key) { - const bit = bitpos(hash, shift); - if ((root.bitmap & bit) === 0) { - return root; // already empty - } - const idx = index(root.bitmap, bit); - const node = root.array[idx]; - // if the item is not an entry - if (node.type !== ENTRY) { - const n = without(node, shift + SHIFT, hash, key); - if (n === node) { - return root; // no changes - } - // if not undefined, the child node still has items, so update it - if (n !== undefined) { - return { - type: INDEX_NODE, - bitmap: root.bitmap, - array: cloneAndSet(root.array, idx, n), - }; - } - // otherwise the child node should be removed - // if it was the only child node, remove this node from the parent - if (root.bitmap === bit) { - return undefined; - } - // otherwise just remove the child node - return { - type: INDEX_NODE, - bitmap: root.bitmap ^ bit, - array: spliceOut(root.array, idx), - }; - } - // otherwise the item is an entry, remove it if the key matches - if (isEqual(key, node.k)) { - if (root.bitmap === bit) { - return undefined; - } - return { - type: INDEX_NODE, - bitmap: root.bitmap ^ bit, - array: spliceOut(root.array, idx), - }; - } - return root; -} -/** - * @template K,V - * @param {CollisionNode} root - * @param {K} key - * @returns {undefined | Node} - */ -function withoutCollision(root, key) { - const idx = collisionIndexOf(root, key); - // if the key not found, no changes - if (idx < 0) { - return root; - } - // otherwise the entry was found, remove it - // if it was the only entry in this node, remove the whole node - if (root.array.length === 1) { - return undefined; - } - // otherwise just remove the entry - return { - type: COLLISION_NODE, - hash: root.hash, - array: spliceOut(root.array, idx), - }; -} -/** - * @template K,V - * @param {undefined | Node} root - * @param {(value:V,key:K)=>void} fn - * @returns {void} - */ -function forEach(root, fn) { - if (root === undefined) { - return; - } - const items = root.array; - const size = items.length; - for (let i = 0; i < size; i++) { - const item = items[i]; - if (item === undefined) { - continue; - } - if (item.type === ENTRY) { - fn(item.v, item.k); - continue; - } - forEach(item, fn); - } -} - -/** - * Extra wrapper to keep track of Dict size and clean up the API - * @template K,V - */ -export default class Dict { - /** - * @template V - * @param {Record} o - * @returns {Dict} - */ - static fromObject(o) { - const keys = Object.keys(o); - /** @type Dict */ - let m = Dict.new(); - for (let i = 0; i < keys.length; i++) { - const k = keys[i]; - m = m.set(k, o[k]); - } - return m; - } - - /** - * @template K,V - * @param {Map} o - * @returns {Dict} - */ - static fromMap(o) { - /** @type Dict */ - let m = Dict.new(); - o.forEach((v, k) => { - m = m.set(k, v); - }); - return m; - } - - static new() { - return new Dict(undefined, 0); - } - - /** - * @param {undefined | Node} root - * @param {number} size - */ - constructor(root, size) { - this.root = root; - this.size = size; - } - /** - * @template NotFound - * @param {K} key - * @param {NotFound} notFound - * @returns {NotFound | V} - */ - get(key, notFound) { - if (this.root === undefined) { - return notFound; - } - const found = find(this.root, 0, getHash(key), key); - if (found === undefined) { - return notFound; - } - return found.v; - } - /** - * @param {K} key - * @param {V} val - * @returns {Dict} - */ - set(key, val) { - const addedLeaf = { val: false }; - const root = this.root === undefined ? EMPTY : this.root; - const newRoot = assoc(root, 0, getHash(key), key, val, addedLeaf); - if (newRoot === this.root) { - return this; - } - return new Dict(newRoot, addedLeaf.val ? this.size + 1 : this.size); - } - /** - * @param {K} key - * @returns {Dict} - */ - delete(key) { - if (this.root === undefined) { - return this; - } - const newRoot = without(this.root, 0, getHash(key), key); - if (newRoot === this.root) { - return this; - } - if (newRoot === undefined) { - return Dict.new(); - } - return new Dict(newRoot, this.size - 1); - } - /** - * @param {K} key - * @returns {boolean} - */ - has(key) { - if (this.root === undefined) { - return false; - } - return find(this.root, 0, getHash(key), key) !== undefined; - } - /** - * @returns {[K,V][]} - */ - entries() { - if (this.root === undefined) { - return []; - } - /** @type [K,V][] */ - const result = []; - this.forEach((v, k) => result.push([k, v])); - return result; - } - /** - * - * @param {(val:V,key:K)=>void} fn - */ - forEach(fn) { - forEach(this.root, fn); - } - hashCode() { - let h = 0; - this.forEach((v, k) => { - h = (h + hashMerge(getHash(v), getHash(k))) | 0; - }); - return h; - } - /** - * @param {unknown} o - * @returns {boolean} - */ - equals(o) { - if (!(o instanceof Dict) || this.size !== o.size) { - return false; - } - - try { - this.forEach((v, k) => { - if (!isEqual(o.get(k, !v), v)) { - throw unequalDictSymbol; - } - }); - return true; - } catch (e) { - if (e === unequalDictSymbol) { - return false; - } - - throw e; - } - } -} - -// This is thrown internally in Dict.equals() so that it returns false as soon -// as a non-matching key is found -const unequalDictSymbol = /* @__PURE__ */ Symbol(); diff --git a/build/dev/javascript/gleam_stdlib/gleam.mjs b/build/dev/javascript/gleam_stdlib/gleam.mjs deleted file mode 100644 index 197cbbc..0000000 --- a/build/dev/javascript/gleam_stdlib/gleam.mjs +++ /dev/null @@ -1 +0,0 @@ -export * from "../prelude.mjs"; diff --git a/build/dev/javascript/gleam_stdlib/gleam/bit_array.mjs b/build/dev/javascript/gleam_stdlib/gleam/bit_array.mjs deleted file mode 100644 index e6c1a3a..0000000 --- a/build/dev/javascript/gleam_stdlib/gleam/bit_array.mjs +++ /dev/null @@ -1,285 +0,0 @@ -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; - } -} diff --git a/build/dev/javascript/gleam_stdlib/gleam/bool.mjs b/build/dev/javascript/gleam_stdlib/gleam/bool.mjs deleted file mode 100644 index 1a761a2..0000000 --- a/build/dev/javascript/gleam_stdlib/gleam/bool.mjs +++ /dev/null @@ -1,313 +0,0 @@ -/** - * 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(); - } -} diff --git a/build/dev/javascript/gleam_stdlib/gleam/bytes_tree.mjs b/build/dev/javascript/gleam_stdlib/gleam/bytes_tree.mjs deleted file mode 100644 index 517efd0..0000000 --- a/build/dev/javascript/gleam_stdlib/gleam/bytes_tree.mjs +++ /dev/null @@ -1,225 +0,0 @@ -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; }, - ); -} diff --git a/build/dev/javascript/gleam_stdlib/gleam/dict.mjs b/build/dev/javascript/gleam_stdlib/gleam/dict.mjs deleted file mode 100644 index aa206af..0000000 --- a/build/dev/javascript/gleam_stdlib/gleam/dict.mjs +++ /dev/null @@ -1,534 +0,0 @@ -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); - } - }, - ); -} diff --git a/build/dev/javascript/gleam_stdlib/gleam/dynamic.mjs b/build/dev/javascript/gleam_stdlib/gleam/dynamic.mjs deleted file mode 100644 index 3c67bbb..0000000 --- a/build/dev/javascript/gleam_stdlib/gleam/dynamic.mjs +++ /dev/null @@ -1,35 +0,0 @@ -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); -} diff --git a/build/dev/javascript/gleam_stdlib/gleam/dynamic/decode.mjs b/build/dev/javascript/gleam_stdlib/gleam/dynamic/decode.mjs deleted file mode 100644 index 25c8902..0000000 --- a/build/dev/javascript/gleam_stdlib/gleam/dynamic/decode.mjs +++ /dev/null @@ -1,947 +0,0 @@ -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([])]; }, - ); - }, - ); -} diff --git a/build/dev/javascript/gleam_stdlib/gleam/float.mjs b/build/dev/javascript/gleam_stdlib/gleam/float.mjs deleted file mode 100644 index 4f3aaa6..0000000 --- a/build/dev/javascript/gleam_stdlib/gleam/float.mjs +++ /dev/null @@ -1,553 +0,0 @@ -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)); - } -} diff --git a/build/dev/javascript/gleam_stdlib/gleam/function.mjs b/build/dev/javascript/gleam_stdlib/gleam/function.mjs deleted file mode 100644 index 2292fbc..0000000 --- a/build/dev/javascript/gleam_stdlib/gleam/function.mjs +++ /dev/null @@ -1,17 +0,0 @@ -/** - * 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; -} diff --git a/build/dev/javascript/gleam_stdlib/gleam/int.mjs b/build/dev/javascript/gleam_stdlib/gleam/int.mjs deleted file mode 100644 index 5824eb6..0000000 --- a/build/dev/javascript/gleam_stdlib/gleam/int.mjs +++ /dev/null @@ -1,816 +0,0 @@ -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; -} diff --git a/build/dev/javascript/gleam_stdlib/gleam/io.mjs b/build/dev/javascript/gleam_stdlib/gleam/io.mjs deleted file mode 100644 index ddab435..0000000 --- a/build/dev/javascript/gleam_stdlib/gleam/io.mjs +++ /dev/null @@ -1,8 +0,0 @@ -import { - print, - print_error, - console_log as println, - console_error as println_error, -} from "../gleam_stdlib.mjs"; - -export { print, print_error, println, println_error }; diff --git a/build/dev/javascript/gleam_stdlib/gleam/list.mjs b/build/dev/javascript/gleam_stdlib/gleam/list.mjs deleted file mode 100644 index 2ea158e..0000000 --- a/build/dev/javascript/gleam_stdlib/gleam/list.mjs +++ /dev/null @@ -1,3209 +0,0 @@ -import { - Ok, - Error, - toList, - Empty as $Empty, - prepend as listPrepend, - CustomType as $CustomType, - makeError, - divideFloat, - isEqual, -} from "../gleam.mjs"; -import * as $dict from "../gleam/dict.mjs"; -import * as $float from "../gleam/float.mjs"; -import * as $int from "../gleam/int.mjs"; -import * as $order from "../gleam/order.mjs"; - -const FILEPATH = "src/gleam/list.gleam"; - -export class Continue extends $CustomType { - constructor($0) { - super(); - this[0] = $0; - } -} -export const ContinueOrStop$Continue = ($0) => new Continue($0); -export const ContinueOrStop$isContinue = (value) => value instanceof Continue; -export const ContinueOrStop$Continue$0 = (value) => value[0]; - -export class Stop extends $CustomType { - constructor($0) { - super(); - this[0] = $0; - } -} -export const ContinueOrStop$Stop = ($0) => new Stop($0); -export const ContinueOrStop$isStop = (value) => value instanceof Stop; -export const ContinueOrStop$Stop$0 = (value) => value[0]; - -class Ascending extends $CustomType {} - -class Descending extends $CustomType {} - -function length_loop(loop$list, loop$count) { - while (true) { - let list = loop$list; - let count = loop$count; - if (list instanceof $Empty) { - return count; - } else { - let list$1 = list.tail; - loop$list = list$1; - loop$count = count + 1; - } - } -} - -/** - * Counts the number of elements in a given list. - * - * This function has to traverse the list to determine the number of elements, - * so it runs in linear time. - * - * This function is natively implemented by the virtual machine and is highly - * optimised. - * - * ## Examples - * - * ```gleam - * length([]) - * // -> 0 - * ``` - * - * ```gleam - * length([1]) - * // -> 1 - * ``` - * - * ```gleam - * length([1, 2]) - * // -> 2 - * ``` - */ -export function length(list) { - return length_loop(list, 0); -} - -function count_loop(loop$list, loop$predicate, loop$acc) { - while (true) { - let list = loop$list; - let predicate = loop$predicate; - let acc = loop$acc; - if (list instanceof $Empty) { - return acc; - } else { - let first$1 = list.head; - let rest$1 = list.tail; - let $ = predicate(first$1); - if ($) { - loop$list = rest$1; - loop$predicate = predicate; - loop$acc = acc + 1; - } else { - loop$list = rest$1; - loop$predicate = predicate; - loop$acc = acc; - } - } - } -} - -/** - * Counts the number of elements in a given list satisfying a given predicate. - * - * This function has to traverse the list to determine the number of elements, - * so it runs in linear time. - * - * ## Examples - * - * ```gleam - * count([], fn(a) { a > 0 }) - * // -> 0 - * ``` - * - * ```gleam - * count([1], fn(a) { a > 0 }) - * // -> 1 - * ``` - * - * ```gleam - * count([1, 2, 3], int.is_odd) - * // -> 2 - * ``` - */ -export function count(list, predicate) { - return count_loop(list, predicate, 0); -} - -/** - * Reverses a list and prepends it to another list. - * This function runs in linear time, proportional to the length of the list - * to prepend. - * - * @ignore - */ -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$1 = prefix.head; - let rest$1 = prefix.tail; - loop$prefix = rest$1; - loop$suffix = listPrepend(first$1, suffix); - } - } -} - -/** - * Creates a new list from a given list containing the same elements but in the - * opposite order. - * - * This function has to traverse the list to create the new reversed list, so - * it runs in linear time. - * - * This function is natively implemented by the virtual machine and is highly - * optimised. - * - * ## Examples - * - * ```gleam - * reverse([]) - * // -> [] - * ``` - * - * ```gleam - * reverse([1]) - * // -> [1] - * ``` - * - * ```gleam - * reverse([1, 2]) - * // -> [2, 1] - * ``` - */ -export function reverse(list) { - return reverse_and_prepend(list, toList([])); -} - -/** - * Determines whether or not the list is empty. - * - * This function runs in constant time. - * - * ## Examples - * - * ```gleam - * is_empty([]) - * // -> True - * ``` - * - * ```gleam - * is_empty([1]) - * // -> False - * ``` - * - * ```gleam - * is_empty([1, 1]) - * // -> False - * ``` - */ -export function is_empty(list) { - return isEqual(list, toList([])); -} - -/** - * Determines whether or not a given element exists within a given list. - * - * This function traverses the list to find the element, so it runs in linear - * time. - * - * ## Examples - * - * ```gleam - * [] |> contains(any: 0) - * // -> False - * ``` - * - * ```gleam - * [0] |> contains(any: 0) - * // -> True - * ``` - * - * ```gleam - * [1] |> contains(any: 0) - * // -> False - * ``` - * - * ```gleam - * [1, 1] |> contains(any: 0) - * // -> False - * ``` - * - * ```gleam - * [1, 0] |> contains(any: 0) - * // -> True - * ``` - */ -export function contains(loop$list, loop$elem) { - while (true) { - let list = loop$list; - let elem = loop$elem; - if (list instanceof $Empty) { - return false; - } else { - let first$1 = list.head; - if (isEqual(first$1, elem)) { - return true; - } else { - let rest$1 = list.tail; - loop$list = rest$1; - loop$elem = elem; - } - } - } -} - -/** - * Gets the first element from the start of the list, if there is one. - * - * ## Examples - * - * ```gleam - * first([]) - * // -> Error(Nil) - * ``` - * - * ```gleam - * first([0]) - * // -> Ok(0) - * ``` - * - * ```gleam - * first([1, 2]) - * // -> Ok(1) - * ``` - */ -export function first(list) { - if (list instanceof $Empty) { - return new Error(undefined); - } else { - let first$1 = list.head; - return new Ok(first$1); - } -} - -/** - * Returns the list minus the first element. If the list is empty, `Error(Nil)` is - * returned. - * - * This function runs in constant time and does not make a copy of the list. - * - * ## Examples - * - * ```gleam - * rest([]) - * // -> Error(Nil) - * ``` - * - * ```gleam - * rest([0]) - * // -> Ok([]) - * ``` - * - * ```gleam - * rest([1, 2]) - * // -> Ok([2]) - * ``` - */ -export function rest(list) { - if (list instanceof $Empty) { - return new Error(undefined); - } else { - let rest$1 = list.tail; - return new Ok(rest$1); - } -} - -function group_loop(loop$list, loop$to_key, loop$groups) { - while (true) { - let list = loop$list; - let to_key = loop$to_key; - let groups = loop$groups; - if (list instanceof $Empty) { - return groups; - } else { - let first$1 = list.head; - let rest$1 = list.tail; - let key = to_key(first$1); - let _block; - let $ = $dict.get(groups, key); - if ($ instanceof Ok) { - let existing = $[0]; - _block = $dict.insert(groups, key, listPrepend(first$1, existing)); - } else { - _block = $dict.insert(groups, key, toList([first$1])); - } - let groups$1 = _block; - loop$list = rest$1; - loop$to_key = to_key; - loop$groups = groups$1; - } - } -} - -/** - * Groups the elements from the given list by the given key function. - * - * Does not preserve the initial value order. - * - * ## Examples - * - * ```gleam - * import gleam/dict - * - * [Ok(3), Error("Wrong"), Ok(200), Ok(73)] - * |> group(by: fn(i) { - * case i { - * Ok(_) -> "Successful" - * Error(_) -> "Failed" - * } - * }) - * |> dict.to_list - * // -> [ - * // #("Failed", [Error("Wrong")]), - * // #("Successful", [Ok(73), Ok(200), Ok(3)]) - * // ] - * ``` - * - * ```gleam - * import gleam/dict - * - * group([1,2,3,4,5], by: fn(i) { i - i / 3 * 3 }) - * |> dict.to_list - * // -> [#(0, [3]), #(1, [4, 1]), #(2, [5, 2])] - * ``` - */ -export function group(list, key) { - return group_loop(list, key, $dict.new$()); -} - -function filter_loop(loop$list, loop$fun, loop$acc) { - while (true) { - let list = loop$list; - let fun = loop$fun; - let acc = loop$acc; - if (list instanceof $Empty) { - return reverse(acc); - } else { - let first$1 = list.head; - let rest$1 = list.tail; - let _block; - let $ = fun(first$1); - if ($) { - _block = listPrepend(first$1, acc); - } else { - _block = acc; - } - let new_acc = _block; - loop$list = rest$1; - loop$fun = fun; - loop$acc = new_acc; - } - } -} - -/** - * Returns a new list containing only the elements from the first list for - * which the given functions returns `True`. - * - * ## Examples - * - * ```gleam - * filter([2, 4, 6, 1], fn(x) { x > 2 }) - * // -> [4, 6] - * ``` - * - * ```gleam - * filter([2, 4, 6, 1], fn(x) { x > 6 }) - * // -> [] - * ``` - */ -export function filter(list, predicate) { - return filter_loop(list, predicate, toList([])); -} - -function filter_map_loop(loop$list, loop$fun, loop$acc) { - while (true) { - let list = loop$list; - let fun = loop$fun; - let acc = loop$acc; - if (list instanceof $Empty) { - return reverse(acc); - } else { - let first$1 = list.head; - let rest$1 = list.tail; - let _block; - let $ = fun(first$1); - if ($ instanceof Ok) { - let first$2 = $[0]; - _block = listPrepend(first$2, acc); - } else { - _block = acc; - } - let new_acc = _block; - loop$list = rest$1; - loop$fun = fun; - loop$acc = new_acc; - } - } -} - -/** - * Returns a new list containing only the elements from the first list for - * which the given functions returns `Ok(_)`. - * - * ## Examples - * - * ```gleam - * filter_map([2, 4, 6, 1], Error) - * // -> [] - * ``` - * - * ```gleam - * filter_map([2, 4, 6, 1], fn(x) { Ok(x + 1) }) - * // -> [3, 5, 7, 2] - * ``` - */ -export function filter_map(list, fun) { - return filter_map_loop(list, fun, toList([])); -} - -function map_loop(loop$list, loop$fun, loop$acc) { - while (true) { - let list = loop$list; - let fun = loop$fun; - let acc = loop$acc; - if (list instanceof $Empty) { - return reverse(acc); - } else { - let first$1 = list.head; - let rest$1 = list.tail; - loop$list = rest$1; - loop$fun = fun; - loop$acc = listPrepend(fun(first$1), acc); - } - } -} - -/** - * Returns a new list containing only the elements of the first list after the - * function has been applied to each one. - * - * ## Examples - * - * ```gleam - * map([2, 4, 6], fn(x) { x * 2 }) - * // -> [4, 8, 12] - * ``` - */ -export function map(list, fun) { - return map_loop(list, fun, toList([])); -} - -function map2_loop(loop$list1, loop$list2, loop$fun, loop$acc) { - while (true) { - let list1 = loop$list1; - let list2 = loop$list2; - let fun = loop$fun; - let acc = loop$acc; - if (list1 instanceof $Empty) { - return reverse(acc); - } else if (list2 instanceof $Empty) { - return reverse(acc); - } else { - let a = list1.head; - let as_ = list1.tail; - let b = list2.head; - let bs = list2.tail; - loop$list1 = as_; - loop$list2 = bs; - loop$fun = fun; - loop$acc = listPrepend(fun(a, b), acc); - } - } -} - -/** - * Combines two lists into a single list using the given function. - * - * If a list is longer than the other the extra elements are dropped. - * - * ## Examples - * - * ```gleam - * map2([1, 2, 3], [4, 5, 6], fn(x, y) { x + y }) - * // -> [5, 7, 9] - * ``` - * - * ```gleam - * map2([1, 2], ["a", "b", "c"], fn(i, x) { #(i, x) }) - * // -> [#(1, "a"), #(2, "b")] - * ``` - */ -export function map2(list1, list2, fun) { - return map2_loop(list1, list2, fun, toList([])); -} - -function map_fold_loop(loop$list, loop$fun, loop$acc, loop$list_acc) { - while (true) { - let list = loop$list; - let fun = loop$fun; - let acc = loop$acc; - let list_acc = loop$list_acc; - if (list instanceof $Empty) { - return [acc, reverse(list_acc)]; - } else { - let first$1 = list.head; - let rest$1 = list.tail; - let $ = fun(acc, first$1); - let acc$1; - let first$2; - acc$1 = $[0]; - first$2 = $[1]; - loop$list = rest$1; - loop$fun = fun; - loop$acc = acc$1; - loop$list_acc = listPrepend(first$2, list_acc); - } - } -} - -/** - * Similar to `map` but also lets you pass around an accumulated value. - * - * ## Examples - * - * ```gleam - * map_fold( - * over: [1, 2, 3], - * from: 100, - * with: fn(memo, i) { #(memo + i, i * 2) } - * ) - * // -> #(106, [2, 4, 6]) - * ``` - */ -export function map_fold(list, initial, fun) { - return map_fold_loop(list, fun, initial, toList([])); -} - -function index_map_loop(loop$list, loop$fun, loop$index, loop$acc) { - while (true) { - let list = loop$list; - let fun = loop$fun; - let index = loop$index; - let acc = loop$acc; - if (list instanceof $Empty) { - return reverse(acc); - } else { - let first$1 = list.head; - let rest$1 = list.tail; - let acc$1 = listPrepend(fun(first$1, index), acc); - loop$list = rest$1; - loop$fun = fun; - loop$index = index + 1; - loop$acc = acc$1; - } - } -} - -/** - * Returns a new list containing only the elements of the first list after the - * function has been applied to each one and their index. - * - * The index starts at 0, so the first element is 0, the second is 1, and so - * on. - * - * ## Examples - * - * ```gleam - * index_map(["a", "b"], fn(x, i) { #(i, x) }) - * // -> [#(0, "a"), #(1, "b")] - * ``` - */ -export function index_map(list, fun) { - return index_map_loop(list, fun, 0, toList([])); -} - -function try_map_loop(loop$list, loop$fun, loop$acc) { - while (true) { - let list = loop$list; - let fun = loop$fun; - let acc = loop$acc; - if (list instanceof $Empty) { - return new Ok(reverse(acc)); - } else { - let first$1 = list.head; - let rest$1 = list.tail; - let $ = fun(first$1); - if ($ instanceof Ok) { - let first$2 = $[0]; - loop$list = rest$1; - loop$fun = fun; - loop$acc = listPrepend(first$2, acc); - } else { - return $; - } - } - } -} - -/** - * Takes a function that returns a `Result` and applies it to each element in a - * given list in turn. - * - * If the function returns `Ok(new_value)` for all elements in the list then a - * list of the new values is returned. - * - * If the function returns `Error(reason)` for any of the elements then it is - * returned immediately. None of the elements in the list are processed after - * one returns an `Error`. - * - * ## Examples - * - * ```gleam - * try_map([1, 2, 3], fn(x) { Ok(x + 2) }) - * // -> Ok([3, 4, 5]) - * ``` - * - * ```gleam - * try_map([1, 2, 3], fn(_) { Error(0) }) - * // -> Error(0) - * ``` - * - * ```gleam - * try_map([[1], [2, 3]], first) - * // -> Ok([1, 2]) - * ``` - * - * ```gleam - * try_map([[1], [], [2]], first) - * // -> Error(Nil) - * ``` - */ -export function try_map(list, fun) { - return try_map_loop(list, fun, toList([])); -} - -/** - * Returns a list that is the given list with up to the given number of - * elements removed from the front of the list. - * - * If the element has less than the number of elements an empty list is - * returned. - * - * This function runs in linear time but does not copy the list. - * - * ## Examples - * - * ```gleam - * drop([1, 2, 3, 4], 2) - * // -> [3, 4] - * ``` - * - * ```gleam - * drop([1, 2, 3, 4], 9) - * // -> [] - * ``` - */ -export function drop(loop$list, loop$n) { - while (true) { - let list = loop$list; - let n = loop$n; - let $ = n <= 0; - if ($) { - return list; - } else { - if (list instanceof $Empty) { - return list; - } else { - let rest$1 = list.tail; - loop$list = rest$1; - loop$n = n - 1; - } - } - } -} - -function take_loop(loop$list, loop$n, loop$acc) { - while (true) { - let list = loop$list; - let n = loop$n; - let acc = loop$acc; - let $ = n <= 0; - if ($) { - return reverse(acc); - } else { - if (list instanceof $Empty) { - return reverse(acc); - } else { - let first$1 = list.head; - let rest$1 = list.tail; - loop$list = rest$1; - loop$n = n - 1; - loop$acc = listPrepend(first$1, acc); - } - } - } -} - -/** - * Returns a list containing the first given number of elements from the given - * list. - * - * If the element has less than the number of elements then the full list is - * returned. - * - * This function runs in linear time. - * - * ## Examples - * - * ```gleam - * take([1, 2, 3, 4], 2) - * // -> [1, 2] - * ``` - * - * ```gleam - * take([1, 2, 3, 4], 9) - * // -> [1, 2, 3, 4] - * ``` - */ -export function take(list, n) { - return take_loop(list, n, toList([])); -} - -/** - * Returns a new empty list. - * - * ## Examples - * - * ```gleam - * new() - * // -> [] - * ``` - */ -export function new$() { - return toList([]); -} - -/** - * Returns the given item wrapped in a list. - * - * ## Examples - * - * ```gleam - * wrap(1) - * // -> [1] - * - * wrap(["a", "b", "c"]) - * // -> [["a", "b", "c"]] - * - * wrap([[]]) - * // -> [[[]]] - * ``` - */ -export function wrap(item) { - return toList([item]); -} - -function append_loop(loop$first, loop$second) { - while (true) { - let first = loop$first; - let second = loop$second; - if (first instanceof $Empty) { - return second; - } else { - let first$1 = first.head; - let rest$1 = first.tail; - loop$first = rest$1; - loop$second = listPrepend(first$1, second); - } - } -} - -/** - * Joins one list onto the end of another. - * - * This function runs in linear time, and it traverses and copies the first - * list. - * - * ## Examples - * - * ```gleam - * append([1, 2], [3]) - * // -> [1, 2, 3] - * ``` - */ -export function append(first, second) { - return append_loop(reverse(first), second); -} - -/** - * Prefixes an item to a list. This can also be done using the dedicated - * syntax instead - * - * ```gleam - * let existing_list = [2, 3, 4] - * - * [1, ..existing_list] - * // -> [1, 2, 3, 4] - * - * prepend(to: existing_list, this: 1) - * // -> [1, 2, 3, 4] - * ``` - */ -export function prepend(list, item) { - return listPrepend(item, list); -} - -function flatten_loop(loop$lists, loop$acc) { - while (true) { - let lists = loop$lists; - let acc = loop$acc; - if (lists instanceof $Empty) { - return reverse(acc); - } else { - let list = lists.head; - let further_lists = lists.tail; - loop$lists = further_lists; - loop$acc = reverse_and_prepend(list, acc); - } - } -} - -/** - * Joins a list of lists into a single list. - * - * This function traverses all elements twice on the JavaScript target. - * This function traverses all elements once on the Erlang target. - * - * ## Examples - * - * ```gleam - * flatten([[1], [2, 3], []]) - * // -> [1, 2, 3] - * ``` - */ -export function flatten(lists) { - return flatten_loop(lists, toList([])); -} - -/** - * Maps the list with the given function into a list of lists, and then flattens it. - * - * ## Examples - * - * ```gleam - * flat_map([2, 4, 6], fn(x) { [x, x + 1] }) - * // -> [2, 3, 4, 5, 6, 7] - * ``` - */ -export function flat_map(list, fun) { - return flatten(map(list, fun)); -} - -/** - * Reduces a list of elements into a single value by calling a given function - * on each element, going from left to right. - * - * `fold([1, 2, 3], 0, add)` is the equivalent of - * `add(add(add(0, 1), 2), 3)`. - * - * This function runs in linear time. - */ -export function fold(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 first$1 = list.head; - let rest$1 = list.tail; - loop$list = rest$1; - loop$initial = fun(initial, first$1); - loop$fun = fun; - } - } -} - -/** - * Reduces a list of elements into a single value by calling a given function - * on each element, going from right to left. - * - * `fold_right([1, 2, 3], 0, add)` is the equivalent of - * `add(add(add(0, 3), 2), 1)`. - * - * This function runs in linear time. - * - * Unlike `fold` this function is not tail recursive. Where possible use - * `fold` instead as it will use less memory. - */ -export function fold_right(list, initial, fun) { - if (list instanceof $Empty) { - return initial; - } else { - let first$1 = list.head; - let rest$1 = list.tail; - return fun(fold_right(rest$1, initial, fun), first$1); - } -} - -function index_fold_loop(loop$over, loop$acc, loop$with, loop$index) { - while (true) { - let over = loop$over; - let acc = loop$acc; - let with$ = loop$with; - let index = loop$index; - if (over instanceof $Empty) { - return acc; - } else { - let first$1 = over.head; - let rest$1 = over.tail; - loop$over = rest$1; - loop$acc = with$(acc, first$1, index); - loop$with = with$; - loop$index = index + 1; - } - } -} - -/** - * Like fold but the folding function also receives the index of the current element. - * - * ## Examples - * - * ```gleam - * ["a", "b", "c"] - * |> index_fold("", fn(acc, item, index) { - * acc <> int.to_string(index) <> ":" <> item <> " " - * }) - * // -> "0:a 1:b 2:c" - * ``` - * - * ```gleam - * [10, 20, 30] - * |> index_fold(0, fn(acc, item, index) { acc + item * index }) - * // -> 80 - * ``` - */ -export function index_fold(list, initial, fun) { - return index_fold_loop(list, initial, fun, 0); -} - -/** - * A variant of fold that might fail. - * - * The folding function should return `Result(accumulator, error)`. - * If the returned value is `Ok(accumulator)` try_fold will try the next value in the list. - * If the returned value is `Error(error)` try_fold will stop and return that error. - * - * ## Examples - * - * ```gleam - * [1, 2, 3, 4] - * |> try_fold(0, fn(acc, i) { - * case i < 3 { - * True -> Ok(acc + i) - * False -> Error(Nil) - * } - * }) - * // -> Error(Nil) - * ``` - */ -export function try_fold(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 new Ok(initial); - } else { - let first$1 = list.head; - let rest$1 = list.tail; - let $ = fun(initial, first$1); - if ($ instanceof Ok) { - let result = $[0]; - loop$list = rest$1; - loop$initial = result; - loop$fun = fun; - } else { - return $; - } - } - } -} - -/** - * A variant of fold that allows to stop folding earlier. - * - * The folding function should return `ContinueOrStop(accumulator)`. - * If the returned value is `Continue(accumulator)` fold_until will try the next value in the list. - * If the returned value is `Stop(accumulator)` fold_until will stop and return that accumulator. - * - * ## Examples - * - * ```gleam - * [1, 2, 3, 4] - * |> fold_until(0, fn(acc, i) { - * case i < 3 { - * True -> Continue(acc + i) - * False -> Stop(acc) - * } - * }) - * // -> 3 - * ``` - */ -export function fold_until(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 first$1 = list.head; - let rest$1 = list.tail; - let $ = fun(initial, first$1); - if ($ instanceof Continue) { - let next_accumulator = $[0]; - loop$list = rest$1; - loop$initial = next_accumulator; - loop$fun = fun; - } else { - let b = $[0]; - return b; - } - } - } -} - -/** - * Finds the first element in a given list for which the given function returns - * `True`. - * - * Returns `Error(Nil)` if no such element is found. - * - * ## Examples - * - * ```gleam - * find([1, 2, 3], fn(x) { x > 2 }) - * // -> Ok(3) - * ``` - * - * ```gleam - * find([1, 2, 3], fn(x) { x > 4 }) - * // -> Error(Nil) - * ``` - * - * ```gleam - * find([], fn(_) { True }) - * // -> Error(Nil) - * ``` - */ -export function find(loop$list, loop$is_desired) { - while (true) { - let list = loop$list; - let is_desired = loop$is_desired; - if (list instanceof $Empty) { - return new Error(undefined); - } else { - let first$1 = list.head; - let rest$1 = list.tail; - let $ = is_desired(first$1); - if ($) { - return new Ok(first$1); - } else { - loop$list = rest$1; - loop$is_desired = is_desired; - } - } - } -} - -/** - * Finds the first element in a given list for which the given function returns - * `Ok(new_value)`, then returns the wrapped `new_value`. - * - * Returns `Error(Nil)` if no such element is found. - * - * ## Examples - * - * ```gleam - * find_map([[], [2], [3]], first) - * // -> Ok(2) - * ``` - * - * ```gleam - * find_map([[], []], first) - * // -> Error(Nil) - * ``` - * - * ```gleam - * find_map([], first) - * // -> Error(Nil) - * ``` - */ -export function find_map(loop$list, loop$fun) { - while (true) { - let list = loop$list; - let fun = loop$fun; - if (list instanceof $Empty) { - return new Error(undefined); - } else { - let first$1 = list.head; - let rest$1 = list.tail; - let $ = fun(first$1); - if ($ instanceof Ok) { - return $; - } else { - loop$list = rest$1; - loop$fun = fun; - } - } - } -} - -/** - * Returns `True` if the given function returns `True` for all the elements in - * the given list. If the function returns `False` for any of the elements it - * immediately returns `False` without checking the rest of the list. - * - * ## Examples - * - * ```gleam - * all([], fn(x) { x > 3 }) - * // -> True - * ``` - * - * ```gleam - * all([4, 5], fn(x) { x > 3 }) - * // -> True - * ``` - * - * ```gleam - * all([4, 3], fn(x) { x > 3 }) - * // -> False - * ``` - */ -export function all(loop$list, loop$predicate) { - while (true) { - let list = loop$list; - let predicate = loop$predicate; - if (list instanceof $Empty) { - return true; - } else { - let first$1 = list.head; - let rest$1 = list.tail; - let $ = predicate(first$1); - if ($) { - loop$list = rest$1; - loop$predicate = predicate; - } else { - return $; - } - } - } -} - -/** - * Returns `True` if the given function returns `True` for any the elements in - * the given list. If the function returns `True` for any of the elements it - * immediately returns `True` without checking the rest of the list. - * - * ## Examples - * - * ```gleam - * any([], fn(x) { x > 3 }) - * // -> False - * ``` - * - * ```gleam - * any([4, 5], fn(x) { x > 3 }) - * // -> True - * ``` - * - * ```gleam - * any([4, 3], fn(x) { x > 4 }) - * // -> False - * ``` - * - * ```gleam - * any([3, 4], fn(x) { x > 3 }) - * // -> True - * ``` - */ -export function any(loop$list, loop$predicate) { - while (true) { - let list = loop$list; - let predicate = loop$predicate; - if (list instanceof $Empty) { - return false; - } else { - let first$1 = list.head; - let rest$1 = list.tail; - let $ = predicate(first$1); - if ($) { - return $; - } else { - loop$list = rest$1; - loop$predicate = predicate; - } - } - } -} - -function zip_loop(loop$one, loop$other, loop$acc) { - while (true) { - let one = loop$one; - let other = loop$other; - let acc = loop$acc; - if (one instanceof $Empty) { - return reverse(acc); - } else if (other instanceof $Empty) { - return reverse(acc); - } else { - let first_one = one.head; - let rest_one = one.tail; - let first_other = other.head; - let rest_other = other.tail; - loop$one = rest_one; - loop$other = rest_other; - loop$acc = listPrepend([first_one, first_other], acc); - } - } -} - -/** - * Takes two lists and returns a single list of 2-element tuples. - * - * If one of the lists is longer than the other, the remaining elements from - * the longer list are not used. - * - * ## Examples - * - * ```gleam - * zip([], []) - * // -> [] - * ``` - * - * ```gleam - * zip([1, 2], [3]) - * // -> [#(1, 3)] - * ``` - * - * ```gleam - * zip([1], [3, 4]) - * // -> [#(1, 3)] - * ``` - * - * ```gleam - * zip([1, 2], [3, 4]) - * // -> [#(1, 3), #(2, 4)] - * ``` - */ -export function zip(list, other) { - return zip_loop(list, other, toList([])); -} - -function strict_zip_loop(loop$one, loop$other, loop$acc) { - while (true) { - let one = loop$one; - let other = loop$other; - let acc = loop$acc; - if (one instanceof $Empty) { - if (other instanceof $Empty) { - return new Ok(reverse(acc)); - } else { - return new Error(undefined); - } - } else if (other instanceof $Empty) { - return new Error(undefined); - } else { - let first_one = one.head; - let rest_one = one.tail; - let first_other = other.head; - let rest_other = other.tail; - loop$one = rest_one; - loop$other = rest_other; - loop$acc = listPrepend([first_one, first_other], acc); - } - } -} - -/** - * Takes two lists and returns a single list of 2-element tuples. - * - * If one of the lists is longer than the other, an `Error` is returned. - * - * ## Examples - * - * ```gleam - * strict_zip([], []) - * // -> Ok([]) - * ``` - * - * ```gleam - * strict_zip([1, 2], [3]) - * // -> Error(Nil) - * ``` - * - * ```gleam - * strict_zip([1], [3, 4]) - * // -> Error(Nil) - * ``` - * - * ```gleam - * strict_zip([1, 2], [3, 4]) - * // -> Ok([#(1, 3), #(2, 4)]) - * ``` - */ -export function strict_zip(list, other) { - return strict_zip_loop(list, other, toList([])); -} - -function unzip_loop(loop$input, loop$one, loop$other) { - while (true) { - let input = loop$input; - let one = loop$one; - let other = loop$other; - if (input instanceof $Empty) { - return [reverse(one), reverse(other)]; - } else { - let rest$1 = input.tail; - let first_one = input.head[0]; - let first_other = input.head[1]; - loop$input = rest$1; - loop$one = listPrepend(first_one, one); - loop$other = listPrepend(first_other, other); - } - } -} - -/** - * Takes a single list of 2-element tuples and returns two lists. - * - * ## Examples - * - * ```gleam - * unzip([#(1, 2), #(3, 4)]) - * // -> #([1, 3], [2, 4]) - * ``` - * - * ```gleam - * unzip([]) - * // -> #([], []) - * ``` - */ -export function unzip(input) { - return unzip_loop(input, toList([]), toList([])); -} - -function intersperse_loop(loop$list, loop$separator, loop$acc) { - while (true) { - let list = loop$list; - let separator = loop$separator; - let acc = loop$acc; - if (list instanceof $Empty) { - return reverse(acc); - } else { - let first$1 = list.head; - let rest$1 = list.tail; - loop$list = rest$1; - loop$separator = separator; - loop$acc = listPrepend(first$1, listPrepend(separator, acc)); - } - } -} - -/** - * Inserts a given value between each existing element in a given list. - * - * This function runs in linear time and copies the list. - * - * ## Examples - * - * ```gleam - * intersperse([1, 1, 1], 2) - * // -> [1, 2, 1, 2, 1] - * ``` - * - * ```gleam - * intersperse([], 2) - * // -> [] - * ``` - */ -export function intersperse(list, elem) { - if (list instanceof $Empty) { - return list; - } else { - let $ = list.tail; - if ($ instanceof $Empty) { - return list; - } else { - let first$1 = list.head; - let rest$1 = $; - return intersperse_loop(rest$1, elem, toList([first$1])); - } - } -} - -function unique_loop(loop$list, loop$seen, loop$acc) { - while (true) { - let list = loop$list; - let seen = loop$seen; - let acc = loop$acc; - if (list instanceof $Empty) { - return reverse(acc); - } else { - let first$1 = list.head; - let rest$1 = list.tail; - let $ = $dict.has_key(seen, first$1); - if ($) { - loop$list = rest$1; - loop$seen = seen; - loop$acc = acc; - } else { - loop$list = rest$1; - loop$seen = $dict.insert(seen, first$1, undefined); - loop$acc = listPrepend(first$1, acc); - } - } - } -} - -/** - * Removes any duplicate elements from a given list. - * - * This function returns in loglinear time. - * - * ## Examples - * - * ```gleam - * unique([1, 1, 1, 4, 7, 3, 3, 4]) - * // -> [1, 4, 7, 3] - * ``` - */ -export function unique(list) { - return unique_loop(list, $dict.new$(), toList([])); -} - -/** - * Given a list it returns slices of it that are locally sorted in ascending - * order. - * - * Imagine you have this list: - * - * ``` - * [1, 2, 3, 2, 1, 0] - * ^^^^^^^ ^^^^^^^ This is a slice in descending order - * | - * | This is a slice that is sorted in ascending order - * ``` - * - * So the produced result will contain these two slices, each one sorted in - * ascending order: `[[1, 2, 3], [0, 1, 2]]`. - * - * - `growing` is an accumulator with the current slice being grown - * - `direction` is the growing direction of the slice being grown, it could - * either be ascending or strictly descending - * - `prev` is the previous element that needs to be added to the growing slice - * it is carried around to check whether we have to keep growing the current - * slice or not - * - `acc` is the accumulator containing the slices sorted in ascending order - * - * @ignore - */ -function sequences( - loop$list, - loop$compare, - loop$growing, - loop$direction, - loop$prev, - loop$acc -) { - while (true) { - let list = loop$list; - let compare = loop$compare; - let growing = loop$growing; - let direction = loop$direction; - let prev = loop$prev; - let acc = loop$acc; - let growing$1 = listPrepend(prev, growing); - if (list instanceof $Empty) { - if (direction instanceof Ascending) { - return listPrepend(reverse(growing$1), acc); - } else { - return listPrepend(growing$1, acc); - } - } else { - let new$1 = list.head; - let rest$1 = list.tail; - let $ = compare(prev, new$1); - if (direction instanceof Ascending) { - if ($ instanceof $order.Lt) { - loop$list = rest$1; - loop$compare = compare; - loop$growing = growing$1; - loop$direction = direction; - loop$prev = new$1; - loop$acc = acc; - } else if ($ instanceof $order.Eq) { - loop$list = rest$1; - loop$compare = compare; - loop$growing = growing$1; - loop$direction = direction; - loop$prev = new$1; - loop$acc = acc; - } else { - let _block; - if (direction instanceof Ascending) { - _block = listPrepend(reverse(growing$1), acc); - } else { - _block = listPrepend(growing$1, acc); - } - let acc$1 = _block; - if (rest$1 instanceof $Empty) { - return listPrepend(toList([new$1]), acc$1); - } else { - let next = rest$1.head; - let rest$2 = rest$1.tail; - let _block$1; - let $1 = compare(new$1, next); - if ($1 instanceof $order.Lt) { - _block$1 = new Ascending(); - } else if ($1 instanceof $order.Eq) { - _block$1 = new Ascending(); - } else { - _block$1 = new Descending(); - } - let direction$1 = _block$1; - loop$list = rest$2; - loop$compare = compare; - loop$growing = toList([new$1]); - loop$direction = direction$1; - loop$prev = next; - loop$acc = acc$1; - } - } - } else if ($ instanceof $order.Lt) { - let _block; - if (direction instanceof Ascending) { - _block = listPrepend(reverse(growing$1), acc); - } else { - _block = listPrepend(growing$1, acc); - } - let acc$1 = _block; - if (rest$1 instanceof $Empty) { - return listPrepend(toList([new$1]), acc$1); - } else { - let next = rest$1.head; - let rest$2 = rest$1.tail; - let _block$1; - let $1 = compare(new$1, next); - if ($1 instanceof $order.Lt) { - _block$1 = new Ascending(); - } else if ($1 instanceof $order.Eq) { - _block$1 = new Ascending(); - } else { - _block$1 = new Descending(); - } - let direction$1 = _block$1; - loop$list = rest$2; - loop$compare = compare; - loop$growing = toList([new$1]); - loop$direction = direction$1; - loop$prev = next; - loop$acc = acc$1; - } - } else if ($ instanceof $order.Eq) { - let _block; - if (direction instanceof Ascending) { - _block = listPrepend(reverse(growing$1), acc); - } else { - _block = listPrepend(growing$1, acc); - } - let acc$1 = _block; - if (rest$1 instanceof $Empty) { - return listPrepend(toList([new$1]), acc$1); - } else { - let next = rest$1.head; - let rest$2 = rest$1.tail; - let _block$1; - let $1 = compare(new$1, next); - if ($1 instanceof $order.Lt) { - _block$1 = new Ascending(); - } else if ($1 instanceof $order.Eq) { - _block$1 = new Ascending(); - } else { - _block$1 = new Descending(); - } - let direction$1 = _block$1; - loop$list = rest$2; - loop$compare = compare; - loop$growing = toList([new$1]); - loop$direction = direction$1; - loop$prev = next; - loop$acc = acc$1; - } - } else { - loop$list = rest$1; - loop$compare = compare; - loop$growing = growing$1; - loop$direction = direction; - loop$prev = new$1; - loop$acc = acc; - } - } - } -} - -/** - * Merges two lists sorted in ascending order into a single list sorted in - * descending order according to the given comparator function. - * - * This reversing of the sort order is not avoidable if we want to implement - * merge as a tail recursive function. We could reverse the accumulator before - * returning it but that would end up being less efficient; so the merging - * algorithm has to play around this. - * - * @ignore - */ -function merge_ascendings(loop$list1, loop$list2, loop$compare, loop$acc) { - while (true) { - let list1 = loop$list1; - let list2 = loop$list2; - let compare = loop$compare; - let acc = loop$acc; - if (list1 instanceof $Empty) { - let list = list2; - return reverse_and_prepend(list, acc); - } else if (list2 instanceof $Empty) { - let list = list1; - return reverse_and_prepend(list, acc); - } else { - let first1 = list1.head; - let rest1 = list1.tail; - let first2 = list2.head; - let rest2 = list2.tail; - let $ = compare(first1, first2); - if ($ instanceof $order.Lt) { - loop$list1 = rest1; - loop$list2 = list2; - loop$compare = compare; - loop$acc = listPrepend(first1, acc); - } else if ($ instanceof $order.Eq) { - loop$list1 = list1; - loop$list2 = rest2; - loop$compare = compare; - loop$acc = listPrepend(first2, acc); - } else { - loop$list1 = list1; - loop$list2 = rest2; - loop$compare = compare; - loop$acc = listPrepend(first2, acc); - } - } - } -} - -/** - * Given a list of ascending lists, it merges adjacent pairs into a single - * descending list, halving their number. - * It returns a list of the remaining descending lists. - * - * @ignore - */ -function merge_ascending_pairs(loop$sequences, loop$compare, loop$acc) { - while (true) { - let sequences = loop$sequences; - let compare = loop$compare; - let acc = loop$acc; - if (sequences instanceof $Empty) { - return reverse(acc); - } else { - let $ = sequences.tail; - if ($ instanceof $Empty) { - let sequence = sequences.head; - return reverse(listPrepend(reverse(sequence), acc)); - } else { - let ascending1 = sequences.head; - let ascending2 = $.head; - let rest$1 = $.tail; - let descending = merge_ascendings( - ascending1, - ascending2, - compare, - toList([]), - ); - loop$sequences = rest$1; - loop$compare = compare; - loop$acc = listPrepend(descending, acc); - } - } - } -} - -/** - * This is exactly the same as merge_ascendings but mirrored: it merges two - * lists sorted in descending order into a single list sorted in ascending - * order according to the given comparator function. - * - * This reversing of the sort order is not avoidable if we want to implement - * merge as a tail recursive function. We could reverse the accumulator before - * returning it but that would end up being less efficient; so the merging - * algorithm has to play around this. - * - * @ignore - */ -function merge_descendings(loop$list1, loop$list2, loop$compare, loop$acc) { - while (true) { - let list1 = loop$list1; - let list2 = loop$list2; - let compare = loop$compare; - let acc = loop$acc; - if (list1 instanceof $Empty) { - let list = list2; - return reverse_and_prepend(list, acc); - } else if (list2 instanceof $Empty) { - let list = list1; - return reverse_and_prepend(list, acc); - } else { - let first1 = list1.head; - let rest1 = list1.tail; - let first2 = list2.head; - let rest2 = list2.tail; - let $ = compare(first1, first2); - if ($ instanceof $order.Lt) { - loop$list1 = list1; - loop$list2 = rest2; - loop$compare = compare; - loop$acc = listPrepend(first2, acc); - } else if ($ instanceof $order.Eq) { - loop$list1 = rest1; - loop$list2 = list2; - loop$compare = compare; - loop$acc = listPrepend(first1, acc); - } else { - loop$list1 = rest1; - loop$list2 = list2; - loop$compare = compare; - loop$acc = listPrepend(first1, acc); - } - } - } -} - -/** - * This is the same as merge_ascending_pairs but flipped for descending lists. - * - * @ignore - */ -function merge_descending_pairs(loop$sequences, loop$compare, loop$acc) { - while (true) { - let sequences = loop$sequences; - let compare = loop$compare; - let acc = loop$acc; - if (sequences instanceof $Empty) { - return reverse(acc); - } else { - let $ = sequences.tail; - if ($ instanceof $Empty) { - let sequence = sequences.head; - return reverse(listPrepend(reverse(sequence), acc)); - } else { - let descending1 = sequences.head; - let descending2 = $.head; - let rest$1 = $.tail; - let ascending = merge_descendings( - descending1, - descending2, - compare, - toList([]), - ); - loop$sequences = rest$1; - loop$compare = compare; - loop$acc = listPrepend(ascending, acc); - } - } - } -} - -/** - * Given some some sorted sequences (assumed to be sorted in `direction`) it - * merges them all together until we're left with just a list sorted in - * ascending order. - * - * @ignore - */ -function merge_all(loop$sequences, loop$direction, loop$compare) { - while (true) { - let sequences = loop$sequences; - let direction = loop$direction; - let compare = loop$compare; - if (sequences instanceof $Empty) { - return sequences; - } else if (direction instanceof Ascending) { - let $ = sequences.tail; - if ($ instanceof $Empty) { - let sequence = sequences.head; - return sequence; - } else { - let sequences$1 = merge_ascending_pairs(sequences, compare, toList([])); - loop$sequences = sequences$1; - loop$direction = new Descending(); - loop$compare = compare; - } - } else { - let $ = sequences.tail; - if ($ instanceof $Empty) { - let sequence = sequences.head; - return reverse(sequence); - } else { - let sequences$1 = merge_descending_pairs(sequences, compare, toList([])); - loop$sequences = sequences$1; - loop$direction = new Ascending(); - loop$compare = compare; - } - } - } -} - -/** - * Sorts from smallest to largest based upon the ordering specified by a given - * function. - * - * ## Examples - * - * ```gleam - * import gleam/int - * - * sort([4, 3, 6, 5, 4, 1, 2], by: int.compare) - * // -> [1, 2, 3, 4, 4, 5, 6] - * ``` - */ -export function sort(list, compare) { - if (list instanceof $Empty) { - return list; - } else { - let $ = list.tail; - if ($ instanceof $Empty) { - return list; - } else { - let x = list.head; - let y = $.head; - let rest$1 = $.tail; - let _block; - let $1 = compare(x, y); - if ($1 instanceof $order.Lt) { - _block = new Ascending(); - } else if ($1 instanceof $order.Eq) { - _block = new Ascending(); - } else { - _block = new Descending(); - } - let direction = _block; - let sequences$1 = sequences( - rest$1, - compare, - toList([x]), - direction, - y, - toList([]), - ); - return merge_all(sequences$1, new Ascending(), compare); - } - } -} - -function range_loop(loop$start, loop$stop, loop$acc) { - while (true) { - let start = loop$start; - let stop = loop$stop; - let acc = loop$acc; - let $ = $int.compare(start, stop); - if ($ instanceof $order.Lt) { - loop$start = start; - loop$stop = stop - 1; - loop$acc = listPrepend(stop, acc); - } else if ($ instanceof $order.Eq) { - return listPrepend(stop, acc); - } else { - loop$start = start; - loop$stop = stop + 1; - loop$acc = listPrepend(stop, acc); - } - } -} - -/** - * Creates a list of ints ranging from a given start and finish. - * - * ## Examples - * - * ```gleam - * range(0, 0) - * // -> [0] - * ``` - * - * ```gleam - * range(0, 5) - * // -> [0, 1, 2, 3, 4, 5] - * ``` - * - * ```gleam - * range(1, -5) - * // -> [1, 0, -1, -2, -3, -4, -5] - * ``` - */ -export function range(start, stop) { - return range_loop(start, stop, toList([])); -} - -function repeat_loop(loop$item, loop$times, loop$acc) { - while (true) { - let item = loop$item; - let times = loop$times; - let acc = loop$acc; - let $ = times <= 0; - if ($) { - return acc; - } else { - loop$item = item; - loop$times = times - 1; - loop$acc = listPrepend(item, acc); - } - } -} - -/** - * Builds a list of a given value a given number of times. - * - * ## Examples - * - * ```gleam - * repeat("a", times: 0) - * // -> [] - * ``` - * - * ```gleam - * repeat("a", times: 5) - * // -> ["a", "a", "a", "a", "a"] - * ``` - */ -export function repeat(a, times) { - return repeat_loop(a, times, toList([])); -} - -function split_loop(loop$list, loop$n, loop$taken) { - while (true) { - let list = loop$list; - let n = loop$n; - let taken = loop$taken; - let $ = n <= 0; - if ($) { - return [reverse(taken), list]; - } else { - if (list instanceof $Empty) { - return [reverse(taken), toList([])]; - } else { - let first$1 = list.head; - let rest$1 = list.tail; - loop$list = rest$1; - loop$n = n - 1; - loop$taken = listPrepend(first$1, taken); - } - } - } -} - -/** - * Splits a list in two before the given index. - * - * If the list is not long enough to have the given index the before list will - * be the input list, and the after list will be empty. - * - * ## Examples - * - * ```gleam - * split([6, 7, 8, 9], 0) - * // -> #([], [6, 7, 8, 9]) - * ``` - * - * ```gleam - * split([6, 7, 8, 9], 2) - * // -> #([6, 7], [8, 9]) - * ``` - * - * ```gleam - * split([6, 7, 8, 9], 4) - * // -> #([6, 7, 8, 9], []) - * ``` - */ -export function split(list, index) { - return split_loop(list, index, toList([])); -} - -function split_while_loop(loop$list, loop$f, loop$acc) { - while (true) { - let list = loop$list; - let f = loop$f; - let acc = loop$acc; - if (list instanceof $Empty) { - return [reverse(acc), toList([])]; - } else { - let first$1 = list.head; - let rest$1 = list.tail; - let $ = f(first$1); - if ($) { - loop$list = rest$1; - loop$f = f; - loop$acc = listPrepend(first$1, acc); - } else { - return [reverse(acc), list]; - } - } - } -} - -/** - * Splits a list in two before the first element that a given function returns - * `False` for. - * - * If the function returns `True` for all elements the first list will be the - * input list, and the second list will be empty. - * - * ## Examples - * - * ```gleam - * split_while([1, 2, 3, 4, 5], fn(x) { x <= 3 }) - * // -> #([1, 2, 3], [4, 5]) - * ``` - * - * ```gleam - * split_while([1, 2, 3, 4, 5], fn(x) { x <= 5 }) - * // -> #([1, 2, 3, 4, 5], []) - * ``` - */ -export function split_while(list, predicate) { - return split_while_loop(list, predicate, toList([])); -} - -/** - * Given a list of 2-element tuples, finds the first tuple that has a given - * key as the first element and returns the second element. - * - * If no tuple is found with the given key then `Error(Nil)` is returned. - * - * This function may be useful for interacting with Erlang code where lists of - * tuples are common. - * - * ## Examples - * - * ```gleam - * key_find([#("a", 0), #("b", 1)], "a") - * // -> Ok(0) - * ``` - * - * ```gleam - * key_find([#("a", 0), #("b", 1)], "b") - * // -> Ok(1) - * ``` - * - * ```gleam - * key_find([#("a", 0), #("b", 1)], "c") - * // -> Error(Nil) - * ``` - */ -export function key_find(keyword_list, desired_key) { - return find_map( - keyword_list, - (keyword) => { - let key; - let value; - key = keyword[0]; - value = keyword[1]; - let $ = isEqual(key, desired_key); - if ($) { - return new Ok(value); - } else { - return new Error(undefined); - } - }, - ); -} - -/** - * Given a list of 2-element tuples, finds all tuples that have a given - * key as the first element and returns the second element. - * - * This function may be useful for interacting with Erlang code where lists of - * tuples are common. - * - * ## Examples - * - * ```gleam - * key_filter([#("a", 0), #("b", 1), #("a", 2)], "a") - * // -> [0, 2] - * ``` - * - * ```gleam - * key_filter([#("a", 0), #("b", 1)], "c") - * // -> [] - * ``` - */ -export function key_filter(keyword_list, desired_key) { - return filter_map( - keyword_list, - (keyword) => { - let key; - let value; - key = keyword[0]; - value = keyword[1]; - let $ = isEqual(key, desired_key); - if ($) { - return new Ok(value); - } else { - return new Error(undefined); - } - }, - ); -} - -function key_pop_loop(loop$list, loop$key, loop$checked) { - while (true) { - let list = loop$list; - let key = loop$key; - let checked = loop$checked; - if (list instanceof $Empty) { - return new Error(undefined); - } else { - let k = list.head[0]; - if (isEqual(k, key)) { - let rest$1 = list.tail; - let v = list.head[1]; - return new Ok([v, reverse_and_prepend(checked, rest$1)]); - } else { - let first$1 = list.head; - let rest$1 = list.tail; - loop$list = rest$1; - loop$key = key; - loop$checked = listPrepend(first$1, checked); - } - } - } -} - -/** - * Given a list of 2-element tuples, finds the first tuple that has a given - * key as the first element. This function will return the second element - * of the found tuple and list with tuple removed. - * - * If no tuple is found with the given key then `Error(Nil)` is returned. - * - * ## Examples - * - * ```gleam - * key_pop([#("a", 0), #("b", 1)], "a") - * // -> Ok(#(0, [#("b", 1)])) - * ``` - * - * ```gleam - * key_pop([#("a", 0), #("b", 1)], "b") - * // -> Ok(#(1, [#("a", 0)])) - * ``` - * - * ```gleam - * key_pop([#("a", 0), #("b", 1)], "c") - * // -> Error(Nil) - * ``` - */ -export function key_pop(list, key) { - return key_pop_loop(list, key, toList([])); -} - -function key_set_loop(loop$list, loop$key, loop$value, loop$inspected) { - while (true) { - let list = loop$list; - let key = loop$key; - let value = loop$value; - let inspected = loop$inspected; - if (list instanceof $Empty) { - return reverse(listPrepend([key, value], inspected)); - } else { - let k = list.head[0]; - if (isEqual(k, key)) { - let rest$1 = list.tail; - return reverse_and_prepend(inspected, listPrepend([k, value], rest$1)); - } else { - let first$1 = list.head; - let rest$1 = list.tail; - loop$list = rest$1; - loop$key = key; - loop$value = value; - loop$inspected = listPrepend(first$1, inspected); - } - } - } -} - -/** - * Given a list of 2-element tuples, inserts a key and value into the list. - * - * If there was already a tuple with the key then it is replaced, otherwise it - * is added to the end of the list. - * - * ## Examples - * - * ```gleam - * key_set([#(5, 0), #(4, 1)], 4, 100) - * // -> [#(5, 0), #(4, 100)] - * ``` - * - * ```gleam - * key_set([#(5, 0), #(4, 1)], 1, 100) - * // -> [#(5, 0), #(4, 1), #(1, 100)] - * ``` - */ -export function key_set(list, key, value) { - return key_set_loop(list, key, value, toList([])); -} - -/** - * Calls a function for each element in a list, discarding the return value. - * - * Useful for calling a side effect for every item of a list. - * - * ```gleam - * import gleam/io - * - * each(["1", "2", "3"], io.println) - * // -> Nil - * // 1 - * // 2 - * // 3 - * ``` - */ -export function each(loop$list, loop$f) { - while (true) { - let list = loop$list; - let f = loop$f; - if (list instanceof $Empty) { - return undefined; - } else { - let first$1 = list.head; - let rest$1 = list.tail; - f(first$1); - loop$list = rest$1; - loop$f = f; - } - } -} - -/** - * Calls a `Result` returning function for each element in a list, discarding - * the return value. If the function returns `Error` then the iteration is - * stopped and the error is returned. - * - * Useful for calling a side effect for every item of a list. - * - * ## Examples - * - * ```gleam - * try_each( - * over: [1, 2, 3], - * with: function_that_might_fail, - * ) - * // -> Ok(Nil) - * ``` - */ -export function try_each(loop$list, loop$fun) { - while (true) { - let list = loop$list; - let fun = loop$fun; - if (list instanceof $Empty) { - return new Ok(undefined); - } else { - let first$1 = list.head; - let rest$1 = list.tail; - let $ = fun(first$1); - if ($ instanceof Ok) { - loop$list = rest$1; - loop$fun = fun; - } else { - return $; - } - } - } -} - -function partition_loop(loop$list, loop$categorise, loop$trues, loop$falses) { - while (true) { - let list = loop$list; - let categorise = loop$categorise; - let trues = loop$trues; - let falses = loop$falses; - if (list instanceof $Empty) { - return [reverse(trues), reverse(falses)]; - } else { - let first$1 = list.head; - let rest$1 = list.tail; - let $ = categorise(first$1); - if ($) { - loop$list = rest$1; - loop$categorise = categorise; - loop$trues = listPrepend(first$1, trues); - loop$falses = falses; - } else { - loop$list = rest$1; - loop$categorise = categorise; - loop$trues = trues; - loop$falses = listPrepend(first$1, falses); - } - } - } -} - -/** - * Partitions a list into a tuple/pair of lists - * by a given categorisation function. - * - * ## Examples - * - * ```gleam - * import gleam/int - * - * [1, 2, 3, 4, 5] |> partition(int.is_odd) - * // -> #([1, 3, 5], [2, 4]) - * ``` - */ -export function partition(list, categorise) { - return partition_loop(list, categorise, toList([]), toList([])); -} - -function window_loop(loop$acc, loop$list, loop$n) { - while (true) { - let acc = loop$acc; - let list = loop$list; - let n = loop$n; - let window$1 = take(list, n); - let $ = length(window$1) === n; - if ($) { - loop$acc = listPrepend(window$1, acc); - loop$list = drop(list, 1); - loop$n = n; - } else { - return reverse(acc); - } - } -} - -/** - * Returns a list of sliding windows. - * - * ## Examples - * - * ```gleam - * window([1,2,3,4,5], 3) - * // -> [[1, 2, 3], [2, 3, 4], [3, 4, 5]] - * ``` - * - * ```gleam - * window([1, 2], 4) - * // -> [] - * ``` - */ -export function window(list, n) { - let $ = n <= 0; - if ($) { - return toList([]); - } else { - return window_loop(toList([]), list, n); - } -} - -/** - * Returns a list of tuples containing two contiguous elements. - * - * ## Examples - * - * ```gleam - * window_by_2([1,2,3,4]) - * // -> [#(1, 2), #(2, 3), #(3, 4)] - * ``` - * - * ```gleam - * window_by_2([1]) - * // -> [] - * ``` - */ -export function window_by_2(list) { - return zip(list, drop(list, 1)); -} - -/** - * Drops the first elements in a given list for which the predicate function returns `True`. - * - * ## Examples - * - * ```gleam - * drop_while([1, 2, 3, 4], fn (x) { x < 3 }) - * // -> [3, 4] - * ``` - */ -export function drop_while(loop$list, loop$predicate) { - while (true) { - let list = loop$list; - let predicate = loop$predicate; - if (list instanceof $Empty) { - return list; - } else { - let first$1 = list.head; - let rest$1 = list.tail; - let $ = predicate(first$1); - if ($) { - loop$list = rest$1; - loop$predicate = predicate; - } else { - return listPrepend(first$1, rest$1); - } - } - } -} - -function take_while_loop(loop$list, loop$predicate, loop$acc) { - while (true) { - let list = loop$list; - let predicate = loop$predicate; - let acc = loop$acc; - if (list instanceof $Empty) { - return reverse(acc); - } else { - let first$1 = list.head; - let rest$1 = list.tail; - let $ = predicate(first$1); - if ($) { - loop$list = rest$1; - loop$predicate = predicate; - loop$acc = listPrepend(first$1, acc); - } else { - return reverse(acc); - } - } - } -} - -/** - * Takes the first elements in a given list for which the predicate function returns `True`. - * - * ## Examples - * - * ```gleam - * take_while([1, 2, 3, 2, 4], fn (x) { x < 3 }) - * // -> [1, 2] - * ``` - */ -export function take_while(list, predicate) { - return take_while_loop(list, predicate, toList([])); -} - -function chunk_loop( - loop$list, - loop$f, - loop$previous_key, - loop$current_chunk, - loop$acc -) { - while (true) { - let list = loop$list; - let f = loop$f; - let previous_key = loop$previous_key; - let current_chunk = loop$current_chunk; - let acc = loop$acc; - if (list instanceof $Empty) { - return reverse(listPrepend(reverse(current_chunk), acc)); - } else { - let first$1 = list.head; - let rest$1 = list.tail; - let key = f(first$1); - let $ = isEqual(key, previous_key); - if ($) { - loop$list = rest$1; - loop$f = f; - loop$previous_key = key; - loop$current_chunk = listPrepend(first$1, current_chunk); - loop$acc = acc; - } else { - let new_acc = listPrepend(reverse(current_chunk), acc); - loop$list = rest$1; - loop$f = f; - loop$previous_key = key; - loop$current_chunk = toList([first$1]); - loop$acc = new_acc; - } - } - } -} - -/** - * Returns a list of chunks in which - * the return value of calling `f` on each element is the same. - * - * ## Examples - * - * ```gleam - * [1, 2, 2, 3, 4, 4, 6, 7, 7] |> chunk(by: fn(n) { n % 2 }) - * // -> [[1], [2, 2], [3], [4, 4, 6], [7, 7]] - * ``` - */ -export function chunk(list, f) { - if (list instanceof $Empty) { - return list; - } else { - let first$1 = list.head; - let rest$1 = list.tail; - return chunk_loop(rest$1, f, f(first$1), toList([first$1]), toList([])); - } -} - -function sized_chunk_loop( - loop$list, - loop$count, - loop$left, - loop$current_chunk, - loop$acc -) { - while (true) { - let list = loop$list; - let count = loop$count; - let left = loop$left; - let current_chunk = loop$current_chunk; - let acc = loop$acc; - if (list instanceof $Empty) { - if (current_chunk instanceof $Empty) { - return reverse(acc); - } else { - let remaining = current_chunk; - return reverse(listPrepend(reverse(remaining), acc)); - } - } else { - let first$1 = list.head; - let rest$1 = list.tail; - let chunk$1 = listPrepend(first$1, current_chunk); - let $ = left > 1; - if ($) { - loop$list = rest$1; - loop$count = count; - loop$left = left - 1; - loop$current_chunk = chunk$1; - loop$acc = acc; - } else { - loop$list = rest$1; - loop$count = count; - loop$left = count; - loop$current_chunk = toList([]); - loop$acc = listPrepend(reverse(chunk$1), acc); - } - } - } -} - -/** - * Returns a list of chunks containing `count` elements each. - * - * If the last chunk does not have `count` elements, it is instead - * a partial chunk, with less than `count` elements. - * - * For any `count` less than 1 this function behaves as if it was set to 1. - * - * ## Examples - * - * ```gleam - * [1, 2, 3, 4, 5, 6] |> sized_chunk(into: 2) - * // -> [[1, 2], [3, 4], [5, 6]] - * ``` - * - * ```gleam - * [1, 2, 3, 4, 5, 6, 7, 8] |> sized_chunk(into: 3) - * // -> [[1, 2, 3], [4, 5, 6], [7, 8]] - * ``` - */ -export function sized_chunk(list, count) { - return sized_chunk_loop(list, count, count, toList([]), toList([])); -} - -/** - * This function acts similar to fold, but does not take an initial state. - * Instead, it starts from the first element in the list - * and combines it with each subsequent element in turn using the given - * function. The function is called as `fun(accumulator, current_element)`. - * - * Returns `Ok` to indicate a successful run, and `Error` if called on an - * empty list. - * - * ## Examples - * - * ```gleam - * [] |> reduce(fn(acc, x) { acc + x }) - * // -> Error(Nil) - * ``` - * - * ```gleam - * [1, 2, 3, 4, 5] |> reduce(fn(acc, x) { acc + x }) - * // -> Ok(15) - * ``` - */ -export function reduce(list, fun) { - if (list instanceof $Empty) { - return new Error(undefined); - } else { - let first$1 = list.head; - let rest$1 = list.tail; - return new Ok(fold(rest$1, first$1, fun)); - } -} - -function scan_loop(loop$list, loop$accumulator, loop$accumulated, loop$fun) { - while (true) { - let list = loop$list; - let accumulator = loop$accumulator; - let accumulated = loop$accumulated; - let fun = loop$fun; - if (list instanceof $Empty) { - return reverse(accumulated); - } else { - let first$1 = list.head; - let rest$1 = list.tail; - let next = fun(accumulator, first$1); - loop$list = rest$1; - loop$accumulator = next; - loop$accumulated = listPrepend(next, accumulated); - loop$fun = fun; - } - } -} - -/** - * Similar to `fold`, but yields the state of the accumulator at each stage. - * - * ## Examples - * - * ```gleam - * scan(over: [1, 2, 3], from: 100, with: fn(acc, i) { acc + i }) - * // -> [101, 103, 106] - * ``` - */ -export function scan(list, initial, fun) { - return scan_loop(list, initial, toList([]), fun); -} - -/** - * Returns the last element in the given list. - * - * Returns `Error(Nil)` if the list is empty. - * - * This function runs in linear time. - * - * ## Examples - * - * ```gleam - * last([]) - * // -> Error(Nil) - * ``` - * - * ```gleam - * last([1, 2, 3, 4, 5]) - * // -> Ok(5) - * ``` - */ -export function last(loop$list) { - while (true) { - let list = loop$list; - if (list instanceof $Empty) { - return new Error(undefined); - } else { - let $ = list.tail; - if ($ instanceof $Empty) { - let last$1 = list.head; - return new Ok(last$1); - } else { - let rest$1 = $; - loop$list = rest$1; - } - } - } -} - -/** - * Return unique combinations of elements in the list. - * - * ## Examples - * - * ```gleam - * combinations([1, 2, 3], 2) - * // -> [[1, 2], [1, 3], [2, 3]] - * ``` - * - * ```gleam - * combinations([1, 2, 3, 4], 3) - * // -> [[1, 2, 3], [1, 2, 4], [1, 3, 4], [2, 3, 4]] - * ``` - */ -export function combinations(items, n) { - if (n === 0) { - return toList([toList([])]); - } else if (items instanceof $Empty) { - return items; - } else { - let first$1 = items.head; - let rest$1 = items.tail; - let _pipe = rest$1; - let _pipe$1 = combinations(_pipe, n - 1); - let _pipe$2 = map( - _pipe$1, - (combination) => { return listPrepend(first$1, combination); }, - ); - let _pipe$3 = reverse(_pipe$2); - return fold( - _pipe$3, - combinations(rest$1, n), - (acc, c) => { return listPrepend(c, acc); }, - ); - } -} - -function combination_pairs_loop(loop$items, loop$acc) { - while (true) { - let items = loop$items; - let acc = loop$acc; - if (items instanceof $Empty) { - return reverse(acc); - } else { - let first$1 = items.head; - let rest$1 = items.tail; - let first_combinations = map( - rest$1, - (other) => { return [first$1, other]; }, - ); - let acc$1 = reverse_and_prepend(first_combinations, acc); - loop$items = rest$1; - loop$acc = acc$1; - } - } -} - -/** - * Return unique pair combinations of elements in the list. - * - * ## Examples - * - * ```gleam - * combination_pairs([1, 2, 3]) - * // -> [#(1, 2), #(1, 3), #(2, 3)] - * ``` - */ -export function combination_pairs(items) { - return combination_pairs_loop(items, toList([])); -} - -function take_firsts(loop$rows, loop$column, loop$remaining_rows) { - while (true) { - let rows = loop$rows; - let column = loop$column; - let remaining_rows = loop$remaining_rows; - if (rows instanceof $Empty) { - return [reverse(column), reverse(remaining_rows)]; - } else { - let $ = rows.head; - if ($ instanceof $Empty) { - let rest$1 = rows.tail; - loop$rows = rest$1; - loop$column = column; - loop$remaining_rows = remaining_rows; - } else { - let rest_rows = rows.tail; - let first$1 = $.head; - let remaining_row = $.tail; - let remaining_rows$1 = listPrepend(remaining_row, remaining_rows); - loop$rows = rest_rows; - loop$column = listPrepend(first$1, column); - loop$remaining_rows = remaining_rows$1; - } - } - } -} - -function transpose_loop(loop$rows, loop$columns) { - while (true) { - let rows = loop$rows; - let columns = loop$columns; - if (rows instanceof $Empty) { - return reverse(columns); - } else { - let $ = take_firsts(rows, toList([]), toList([])); - let column; - let rest$1; - column = $[0]; - rest$1 = $[1]; - if (column instanceof $Empty) { - loop$rows = rest$1; - loop$columns = columns; - } else { - loop$rows = rest$1; - loop$columns = listPrepend(column, columns); - } - } - } -} - -/** - * Transpose rows and columns of the list of lists. - * - * Notice: This function is not tail recursive, - * and thus may exceed stack size if called, - * with large lists (on the JavaScript target). - * - * ## Examples - * - * ```gleam - * transpose([[1, 2, 3], [101, 102, 103]]) - * // -> [[1, 101], [2, 102], [3, 103]] - * ``` - */ -export function transpose(list_of_lists) { - return transpose_loop(list_of_lists, toList([])); -} - -/** - * Make a list alternating the elements from the given lists - * - * ## Examples - * - * ```gleam - * interleave([[1, 2], [101, 102], [201, 202]]) - * // -> [1, 101, 201, 2, 102, 202] - * ``` - */ -export function interleave(list) { - let _pipe = list; - let _pipe$1 = transpose(_pipe); - return flatten(_pipe$1); -} - -function shuffle_pair_unwrap_loop(loop$list, loop$acc) { - while (true) { - let list = loop$list; - let acc = loop$acc; - if (list instanceof $Empty) { - return acc; - } else { - let elem_pair = list.head; - let enumerable = list.tail; - loop$list = enumerable; - loop$acc = listPrepend(elem_pair[1], acc); - } - } -} - -function do_shuffle_by_pair_indexes(list_of_pairs) { - return sort( - list_of_pairs, - (a_pair, b_pair) => { return $float.compare(a_pair[0], b_pair[0]); }, - ); -} - -/** - * Takes a list, randomly sorts all items and returns the shuffled list. - * - * This function uses `float.random` to decide the order of the elements. - * - * ## Example - * - * ```gleam - * range(1, 10) |> shuffle() - * // -> [1, 6, 9, 10, 3, 8, 4, 2, 7, 5] - * ``` - */ -export function shuffle(list) { - let _pipe = list; - let _pipe$1 = fold( - _pipe, - toList([]), - (acc, a) => { return listPrepend([$float.random(), a], acc); }, - ); - let _pipe$2 = do_shuffle_by_pair_indexes(_pipe$1); - return shuffle_pair_unwrap_loop(_pipe$2, toList([])); -} - -function max_loop(loop$list, loop$compare, loop$max) { - while (true) { - let list = loop$list; - let compare = loop$compare; - let max = loop$max; - if (list instanceof $Empty) { - return max; - } else { - let first$1 = list.head; - let rest$1 = list.tail; - let $ = compare(first$1, max); - if ($ instanceof $order.Lt) { - loop$list = rest$1; - loop$compare = compare; - loop$max = max; - } else if ($ instanceof $order.Eq) { - loop$list = rest$1; - loop$compare = compare; - loop$max = max; - } else { - loop$list = rest$1; - loop$compare = compare; - loop$max = first$1; - } - } - } -} - -/** - * Takes a list and a comparator, and returns the maximum element in the list - * - * - * ## Example - * - * ```gleam - * range(1, 10) |> list.max(int.compare) - * // -> Ok(10) - * ``` - * - * ```gleam - * ["a", "c", "b"] |> list.max(string.compare) - * // -> Ok("c") - * ``` - */ -export function max(list, compare) { - if (list instanceof $Empty) { - return new Error(undefined); - } else { - let first$1 = list.head; - let rest$1 = list.tail; - return new Ok(max_loop(rest$1, compare, first$1)); - } -} - -function build_reservoir_loop(loop$list, loop$size, loop$reservoir) { - while (true) { - let list = loop$list; - let size = loop$size; - let reservoir = loop$reservoir; - let reservoir_size = $dict.size(reservoir); - let $ = reservoir_size >= size; - if ($) { - return [reservoir, list]; - } else { - if (list instanceof $Empty) { - return [reservoir, toList([])]; - } else { - let first$1 = list.head; - let rest$1 = list.tail; - let reservoir$1 = $dict.insert(reservoir, reservoir_size, first$1); - loop$list = rest$1; - loop$size = size; - loop$reservoir = reservoir$1; - } - } - } -} - -/** - * Builds the initial reservoir used by Algorithm L. - * This is a dictionary with keys ranging from `0` up to `n - 1` where each - * value is the corresponding element at that position in `list`. - * - * This also returns the remaining elements of `list` that didn't end up in - * the reservoir. - * - * @ignore - */ -function build_reservoir(list, n) { - return build_reservoir_loop(list, n, $dict.new$()); -} - -const min_positive = 2.2250738585072014e-308; - -function log_random() { - let $ = $float.logarithm($float.random() + min_positive); - let random; - if ($ instanceof Ok) { - random = $[0]; - } else { - throw makeError( - "let_assert", - FILEPATH, - "gleam/list", - 2391, - "log_random", - "Pattern match failed, no pattern matched the value.", - { - value: $, - start: 56078, - end: 56149, - pattern_start: 56089, - pattern_end: 56099 - } - ) - } - return random; -} - -function sample_loop(loop$list, loop$reservoir, loop$n, loop$w) { - while (true) { - let list = loop$list; - let reservoir = loop$reservoir; - let n = loop$n; - let w = loop$w; - let _block; - { - let $ = $float.logarithm(1.0 - w); - let log; - if ($ instanceof Ok) { - log = $[0]; - } else { - throw makeError( - "let_assert", - FILEPATH, - "gleam/list", - 2374, - "sample_loop", - "Pattern match failed, no pattern matched the value.", - { - value: $, - start: 55639, - end: 55685, - pattern_start: 55650, - pattern_end: 55657 - } - ) - } - _block = $float.round($float.floor(divideFloat(log_random(), log))); - } - let skip = _block; - let $ = drop(list, skip); - if ($ instanceof $Empty) { - return reservoir; - } else { - let first$1 = $.head; - let rest$1 = $.tail; - let reservoir$1 = $dict.insert(reservoir, $int.random(n), first$1); - let w$1 = w * $float.exponential( - divideFloat(log_random(), $int.to_float(n)), - ); - loop$list = rest$1; - loop$reservoir = reservoir$1; - loop$n = n; - loop$w = w$1; - } - } -} - -/** - * Returns a random sample of up to n elements from a list using reservoir - * sampling via [Algorithm L](https://en.wikipedia.org/wiki/Reservoir_sampling#Optimal:_Algorithm_L). - * Returns an empty list if the sample size is less than or equal to 0. - * - * Order is not random, only selection is. - * - * ## Examples - * - * ```gleam - * reservoir_sample([1, 2, 3, 4, 5], 3) - * // -> [2, 4, 5] // A random sample of 3 items - * ``` - */ -export function sample(list, n) { - let $ = build_reservoir(list, n); - let reservoir; - let rest$1; - reservoir = $[0]; - rest$1 = $[1]; - let $1 = $dict.is_empty(reservoir); - if ($1) { - return toList([]); - } else { - let w = $float.exponential(divideFloat(log_random(), $int.to_float(n))); - return $dict.values(sample_loop(rest$1, reservoir, n, w)); - } -} - -function permutation_zip(list, rest, acc) { - if (list instanceof $Empty) { - return reverse(acc); - } else { - let head = list.head; - let tail = list.tail; - return permutation_prepend( - head, - permutations(reverse_and_prepend(rest, tail)), - tail, - listPrepend(head, rest), - acc, - ); - } -} - -function permutation_prepend( - loop$el, - loop$permutations, - loop$list_1, - loop$list_2, - loop$acc -) { - while (true) { - let el = loop$el; - let permutations = loop$permutations; - let list_1 = loop$list_1; - let list_2 = loop$list_2; - let acc = loop$acc; - if (permutations instanceof $Empty) { - return permutation_zip(list_1, list_2, acc); - } else { - let head = permutations.head; - let tail = permutations.tail; - loop$el = el; - loop$permutations = tail; - loop$list_1 = list_1; - loop$list_2 = list_2; - loop$acc = listPrepend(listPrepend(el, head), acc); - } - } -} - -/** - * Returns all the permutations of a list. - * - * ## Examples - * - * ```gleam - * permutations([1, 2]) - * // -> [[1, 2], [2, 1]] - * ``` - */ -export function permutations(list) { - if (list instanceof $Empty) { - return toList([toList([])]); - } else { - let l = list; - return permutation_zip(l, toList([]), toList([])); - } -} diff --git a/build/dev/javascript/gleam_stdlib/gleam/option.mjs b/build/dev/javascript/gleam_stdlib/gleam/option.mjs deleted file mode 100644 index 5e820a3..0000000 --- a/build/dev/javascript/gleam_stdlib/gleam/option.mjs +++ /dev/null @@ -1,419 +0,0 @@ -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([])); -} diff --git a/build/dev/javascript/gleam_stdlib/gleam/order.mjs b/build/dev/javascript/gleam_stdlib/gleam/order.mjs deleted file mode 100644 index 617938c..0000000 --- a/build/dev/javascript/gleam_stdlib/gleam/order.mjs +++ /dev/null @@ -1,178 +0,0 @@ -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; - } -} diff --git a/build/dev/javascript/gleam_stdlib/gleam/pair.mjs b/build/dev/javascript/gleam_stdlib/gleam/pair.mjs deleted file mode 100644 index 13f0cd5..0000000 --- a/build/dev/javascript/gleam_stdlib/gleam/pair.mjs +++ /dev/null @@ -1,102 +0,0 @@ -/** - * 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]; -} diff --git a/build/dev/javascript/gleam_stdlib/gleam/result.mjs b/build/dev/javascript/gleam_stdlib/gleam/result.mjs deleted file mode 100644 index 527de4f..0000000 --- a/build/dev/javascript/gleam_stdlib/gleam/result.mjs +++ /dev/null @@ -1,494 +0,0 @@ -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); - } -} diff --git a/build/dev/javascript/gleam_stdlib/gleam/set.mjs b/build/dev/javascript/gleam_stdlib/gleam/set.mjs deleted file mode 100644 index dc1ae52..0000000 --- a/build/dev/javascript/gleam_stdlib/gleam/set.mjs +++ /dev/null @@ -1,412 +0,0 @@ -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)); -} diff --git a/build/dev/javascript/gleam_stdlib/gleam/string.mjs b/build/dev/javascript/gleam_stdlib/gleam/string.mjs deleted file mode 100644 index d15468e..0000000 --- a/build/dev/javascript/gleam_stdlib/gleam/string.mjs +++ /dev/null @@ -1,723 +0,0 @@ -import { - Ok, - Error, - Empty as $Empty, - prepend as listPrepend, - CustomType as $CustomType, - remainderInt, - divideInt, -} from "../gleam.mjs"; -import * as $list from "../gleam/list.mjs"; -import * as $option from "../gleam/option.mjs"; -import { None, Some } from "../gleam/option.mjs"; -import * as $order from "../gleam/order.mjs"; -import * as $string_tree from "../gleam/string_tree.mjs"; -import { - string_length as length, - lowercase, - uppercase, - less_than, - string_grapheme_slice as grapheme_slice, - string_byte_slice as unsafe_byte_slice, - crop_string as crop, - contains_string as contains, - starts_with, - ends_with, - split_once, - trim_start, - trim_end, - pop_grapheme, - graphemes as to_graphemes, - codepoint as unsafe_int_to_utf_codepoint, - string_to_codepoint_integer_list, - utf_codepoint_list_to_string as from_utf_codepoints, - utf_codepoint_to_int, - inspect as do_inspect, - byte_size, -} from "../gleam_stdlib.mjs"; - -export { - byte_size, - contains, - crop, - ends_with, - from_utf_codepoints, - length, - lowercase, - pop_grapheme, - split_once, - starts_with, - to_graphemes, - trim_end, - trim_start, - uppercase, - utf_codepoint_to_int, -}; - -class Leading extends $CustomType {} - -class Trailing extends $CustomType {} - -/** - * Determines if a `String` is empty. - * - * ## Examples - * - * ```gleam - * is_empty("") - * // -> True - * ``` - * - * ```gleam - * is_empty("the world") - * // -> False - * ``` - */ -export function is_empty(str) { - return str === ""; -} - -/** - * Reverses a `String`. - * - * This function has to iterate across the whole `String` so it runs in linear - * time. Avoid using this in a loop. - * - * ## Examples - * - * ```gleam - * reverse("stressed") - * // -> "desserts" - * ``` - */ -export function reverse(string) { - let _pipe = string; - let _pipe$1 = $string_tree.from_string(_pipe); - let _pipe$2 = $string_tree.reverse(_pipe$1); - return $string_tree.to_string(_pipe$2); -} - -/** - * Creates a new `String` by replacing all occurrences of a given substring. - * - * ## Examples - * - * ```gleam - * replace("www.example.com", each: ".", with: "-") - * // -> "www-example-com" - * ``` - * - * ```gleam - * replace("a,b,c,d,e", each: ",", with: "/") - * // -> "a/b/c/d/e" - * ``` - */ -export function replace(string, pattern, substitute) { - let _pipe = string; - let _pipe$1 = $string_tree.from_string(_pipe); - let _pipe$2 = $string_tree.replace(_pipe$1, pattern, substitute); - return $string_tree.to_string(_pipe$2); -} - -/** - * Compares two `String`s to see which is "larger" by comparing their graphemes. - * - * This does not compare the size or length of the given `String`s. - * - * ## Examples - * - * ```gleam - * compare("Anthony", "Anthony") - * // -> order.Eq - * ``` - * - * ```gleam - * compare("A", "B") - * // -> order.Lt - * ``` - */ -export function compare(a, b) { - let $ = a === b; - if ($) { - return new $order.Eq(); - } else { - let $1 = less_than(a, b); - if ($1) { - return new $order.Lt(); - } else { - return new $order.Gt(); - } - } -} - -/** - * Takes a substring given a start grapheme index and a length. Negative indexes - * are taken starting from the *end* of the list. - * - * This function runs in linear time with the size of the index and the - * length. Negative indexes are linear with the size of the input string in - * addition to the other costs. - * - * ## Examples - * - * ```gleam - * slice(from: "gleam", at_index: 1, length: 2) - * // -> "le" - * ``` - * - * ```gleam - * slice(from: "gleam", at_index: 1, length: 10) - * // -> "leam" - * ``` - * - * ```gleam - * slice(from: "gleam", at_index: 10, length: 3) - * // -> "" - * ``` - * - * ```gleam - * slice(from: "gleam", at_index: -2, length: 2) - * // -> "am" - * ``` - * - * ```gleam - * slice(from: "gleam", at_index: -12, length: 2) - * // -> "" - * ``` - */ -export function slice(string, idx, len) { - let $ = len <= 0; - if ($) { - return ""; - } else { - let $1 = idx < 0; - if ($1) { - let translated_idx = length(string) + idx; - let $2 = translated_idx < 0; - if ($2) { - return ""; - } else { - return grapheme_slice(string, translated_idx, len); - } - } else { - return grapheme_slice(string, idx, len); - } - } -} - -/** - * Drops *n* graphemes from the end of a `String`. - * - * This function traverses the full string, so it runs in linear time with the - * size of the string. Avoid using this in a loop. - * - * ## Examples - * - * ```gleam - * drop_end(from: "Cigarette Smoking Man", up_to: 2) - * // -> "Cigarette Smoking M" - * ``` - */ -export function drop_end(string, num_graphemes) { - let $ = num_graphemes <= 0; - if ($) { - return string; - } else { - return slice(string, 0, length(string) - num_graphemes); - } -} - -/** - * Creates a new `String` by joining two `String`s together. - * - * This function typically copies both `String`s and runs in linear time, but - * the exact behaviour will depend on how the runtime you are using optimises - * your code. Benchmark and profile your code if you need to understand its - * performance better. - * - * If you are joining together large string and want to avoid copying any data - * you may want to investigate using the [`string_tree`](../gleam/string_tree.html) - * module. - * - * ## Examples - * - * ```gleam - * append(to: "butter", suffix: "fly") - * // -> "butterfly" - * ``` - */ -export function append(first, second) { - return first + second; -} - -function concat_loop(loop$strings, loop$accumulator) { - while (true) { - let strings = loop$strings; - let accumulator = loop$accumulator; - if (strings instanceof $Empty) { - return accumulator; - } else { - let string = strings.head; - let strings$1 = strings.tail; - loop$strings = strings$1; - loop$accumulator = accumulator + string; - } - } -} - -/** - * Creates a new `String` by joining many `String`s together. - * - * This function copies all the `String`s and runs in linear time. - * - * ## Examples - * - * ```gleam - * concat(["never", "the", "less"]) - * // -> "nevertheless" - * ``` - */ -export function concat(strings) { - return concat_loop(strings, ""); -} - -function repeat_loop(loop$times, loop$doubling_acc, loop$acc) { - while (true) { - let times = loop$times; - let doubling_acc = loop$doubling_acc; - let acc = loop$acc; - let _block; - let $ = times % 2; - if ($ === 0) { - _block = acc; - } else { - _block = acc + doubling_acc; - } - let acc$1 = _block; - let times$1 = globalThis.Math.trunc(times / 2); - let $1 = times$1 <= 0; - if ($1) { - return acc$1; - } else { - loop$times = times$1; - loop$doubling_acc = doubling_acc + doubling_acc; - loop$acc = acc$1; - } - } -} - -/** - * Creates a new `String` by repeating a `String` a given number of times. - * - * This function runs in loglinear time. - * - * ## Examples - * - * ```gleam - * repeat("ha", times: 3) - * // -> "hahaha" - * ``` - */ -export function repeat(string, times) { - let $ = times <= 0; - if ($) { - return ""; - } else { - return repeat_loop(times, string, ""); - } -} - -function join_loop(loop$strings, loop$separator, loop$accumulator) { - while (true) { - let strings = loop$strings; - let separator = loop$separator; - let accumulator = loop$accumulator; - if (strings instanceof $Empty) { - return accumulator; - } else { - let string = strings.head; - let strings$1 = strings.tail; - loop$strings = strings$1; - loop$separator = separator; - loop$accumulator = (accumulator + separator) + string; - } - } -} - -/** - * Joins many `String`s together with a given separator. - * - * This function runs in linear time. - * - * ## Examples - * - * ```gleam - * join(["home","evan","Desktop"], with: "/") - * // -> "home/evan/Desktop" - * ``` - */ -export function join(strings, separator) { - if (strings instanceof $Empty) { - return ""; - } else { - let first$1 = strings.head; - let rest = strings.tail; - return join_loop(rest, separator, first$1); - } -} - -function padding(size, pad_string) { - let pad_string_length = length(pad_string); - let num_pads = divideInt(size, pad_string_length); - let extra = remainderInt(size, pad_string_length); - return repeat(pad_string, num_pads) + slice(pad_string, 0, extra); -} - -/** - * Pads the start of a `String` until it has a given length. - * - * ## Examples - * - * ```gleam - * pad_start("121", to: 5, with: ".") - * // -> "..121" - * ``` - * - * ```gleam - * pad_start("121", to: 3, with: ".") - * // -> "121" - * ``` - * - * ```gleam - * pad_start("121", to: 2, with: ".") - * // -> "121" - * ``` - */ -export function pad_start(string, desired_length, pad_string) { - let current_length = length(string); - let to_pad_length = desired_length - current_length; - let $ = to_pad_length <= 0; - if ($) { - return string; - } else { - return padding(to_pad_length, pad_string) + string; - } -} - -/** - * Pads the end of a `String` until it has a given length. - * - * ## Examples - * - * ```gleam - * pad_end("123", to: 5, with: ".") - * // -> "123.." - * ``` - * - * ```gleam - * pad_end("123", to: 3, with: ".") - * // -> "123" - * ``` - * - * ```gleam - * pad_end("123", to: 2, with: ".") - * // -> "123" - * ``` - */ -export function pad_end(string, desired_length, pad_string) { - let current_length = length(string); - let to_pad_length = desired_length - current_length; - let $ = to_pad_length <= 0; - if ($) { - return string; - } else { - return string + padding(to_pad_length, pad_string); - } -} - -/** - * Removes whitespace on both sides of a `String`. - * - * Whitespace in this function is the set of nonbreakable whitespace - * codepoints, defined as Pattern_White_Space in [Unicode Standard Annex #31][1]. - * - * [1]: https://unicode.org/reports/tr31/ - * - * ## Examples - * - * ```gleam - * trim(" hats \n") - * // -> "hats" - * ``` - */ -export function trim(string) { - let _pipe = string; - let _pipe$1 = trim_start(_pipe); - return trim_end(_pipe$1); -} - -function to_graphemes_loop(loop$string, loop$acc) { - while (true) { - let string = loop$string; - let acc = loop$acc; - let $ = pop_grapheme(string); - if ($ instanceof Ok) { - let grapheme = $[0][0]; - let rest = $[0][1]; - loop$string = rest; - loop$acc = listPrepend(grapheme, acc); - } else { - return acc; - } - } -} - -/** - * Creates a list of `String`s by splitting a given string on a given substring. - * - * ## Examples - * - * ```gleam - * split("home/gleam/desktop/", on: "/") - * // -> ["home", "gleam", "desktop", ""] - * ``` - */ -export function split(x, substring) { - if (substring === "") { - return to_graphemes(x); - } else { - let _pipe = x; - let _pipe$1 = $string_tree.from_string(_pipe); - let _pipe$2 = $string_tree.split(_pipe$1, substring); - return $list.map(_pipe$2, $string_tree.to_string); - } -} - -function do_to_utf_codepoints(string) { - let _pipe = string; - let _pipe$1 = string_to_codepoint_integer_list(_pipe); - return $list.map(_pipe$1, unsafe_int_to_utf_codepoint); -} - -/** - * Converts a `String` to a `List` of `UtfCodepoint`. - * - * See and - * for an - * explanation on code points. - * - * ## Examples - * - * ```gleam - * "a" |> to_utf_codepoints - * // -> [UtfCodepoint(97)] - * ``` - * - * ```gleam - * // Semantically the same as: - * // ["🏳", "️", "‍", "🌈"] or: - * // [waving_white_flag, variant_selector_16, zero_width_joiner, rainbow] - * "🏳️‍🌈" |> to_utf_codepoints - * // -> [ - * // UtfCodepoint(127987), - * // UtfCodepoint(65039), - * // UtfCodepoint(8205), - * // UtfCodepoint(127752), - * // ] - * ``` - */ -export function to_utf_codepoints(string) { - return do_to_utf_codepoints(string); -} - -/** - * Converts an integer to a `UtfCodepoint`. - * - * Returns an `Error` if the integer does not represent a valid UTF codepoint. - */ -export function utf_codepoint(value) { - let i = value; - if (i > 1_114_111) { - return new Error(undefined); - } else { - let i$1 = value; - if ((i$1 >= 55_296) && (i$1 <= 57_343)) { - return new Error(undefined); - } else { - let i$2 = value; - if (i$2 < 0) { - return new Error(undefined); - } else { - let i$3 = value; - return new Ok(unsafe_int_to_utf_codepoint(i$3)); - } - } - } -} - -/** - * Converts a `String` into `Option(String)` where an empty `String` becomes - * `None`. - * - * ## Examples - * - * ```gleam - * to_option("") - * // -> None - * ``` - * - * ```gleam - * to_option("hats") - * // -> Some("hats") - * ``` - */ -export function to_option(string) { - if (string === "") { - return new None(); - } else { - return new Some(string); - } -} - -/** - * Returns the first grapheme cluster in a given `String` and wraps it in a - * `Result(String, Nil)`. If the `String` is empty, it returns `Error(Nil)`. - * Otherwise, it returns `Ok(String)`. - * - * ## Examples - * - * ```gleam - * first("") - * // -> Error(Nil) - * ``` - * - * ```gleam - * first("icecream") - * // -> Ok("i") - * ``` - */ -export function first(string) { - let $ = pop_grapheme(string); - if ($ instanceof Ok) { - let first$1 = $[0][0]; - return new Ok(first$1); - } else { - return $; - } -} - -/** - * Returns the last grapheme cluster in a given `String` and wraps it in a - * `Result(String, Nil)`. If the `String` is empty, it returns `Error(Nil)`. - * Otherwise, it returns `Ok(String)`. - * - * This function traverses the full string, so it runs in linear time with the - * length of the string. Avoid using this in a loop. - * - * ## Examples - * - * ```gleam - * last("") - * // -> Error(Nil) - * ``` - * - * ```gleam - * last("icecream") - * // -> Ok("m") - * ``` - */ -export function last(string) { - let $ = pop_grapheme(string); - if ($ instanceof Ok) { - let $1 = $[0][1]; - if ($1 === "") { - let first$1 = $[0][0]; - return new Ok(first$1); - } else { - let rest = $1; - return new Ok(slice(rest, -1, 1)); - } - } else { - return $; - } -} - -/** - * Creates a new `String` with the first grapheme in the input `String` - * converted to uppercase and the remaining graphemes to lowercase. - * - * ## Examples - * - * ```gleam - * capitalise("mamouna") - * // -> "Mamouna" - * ``` - */ -export function capitalise(string) { - let $ = pop_grapheme(string); - if ($ instanceof Ok) { - let first$1 = $[0][0]; - let rest = $[0][1]; - return append(uppercase(first$1), lowercase(rest)); - } else { - return ""; - } -} - -/** - * Returns a `String` representation of a term in Gleam syntax. - * - * This may be occasionally useful for quick-and-dirty printing of values in - * scripts. For error reporting and other uses prefer constructing strings by - * pattern matching on the values. - * - * ## Limitations - * - * The output format of this function is not stable and could change at any - * time. The output is not suitable for parsing. - * - * This function works using runtime reflection, so the output may not be - * perfectly accurate for data structures where the runtime structure doesn't - * hold enough information to determine the original syntax. For example, - * tuples with an Erlang atom in the first position will be mistaken for Gleam - * records. - * - * ## Security and safety - * - * There is no limit to how large the strings that this function can produce. - * Be careful not to call this function with large data structures or you - * could use very large amounts of memory, potentially causing runtime - * problems. - */ -export function inspect(term) { - let _pipe = term; - let _pipe$1 = do_inspect(_pipe); - return $string_tree.to_string(_pipe$1); -} - -/** - * Drops *n* graphemes from the start of a `String`. - * - * This function runs in linear time with the number of graphemes to drop. - * - * ## Examples - * - * ```gleam - * drop_start(from: "The Lone Gunmen", up_to: 2) - * // -> "e Lone Gunmen" - * ``` - */ -export function drop_start(string, num_graphemes) { - let $ = num_graphemes <= 0; - if ($) { - return string; - } else { - let prefix = grapheme_slice(string, 0, num_graphemes); - let prefix_size = byte_size(prefix); - return unsafe_byte_slice( - string, - prefix_size, - byte_size(string) - prefix_size, - ); - } -} diff --git a/build/dev/javascript/gleam_stdlib/gleam/string_tree.mjs b/build/dev/javascript/gleam_stdlib/gleam/string_tree.mjs deleted file mode 100644 index a8b24ce..0000000 --- a/build/dev/javascript/gleam_stdlib/gleam/string_tree.mjs +++ /dev/null @@ -1,133 +0,0 @@ -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); -} diff --git a/build/dev/javascript/gleam_stdlib/gleam/uri.mjs b/build/dev/javascript/gleam_stdlib/gleam/uri.mjs deleted file mode 100644 index 01f4bba..0000000 --- a/build/dev/javascript/gleam_stdlib/gleam/uri.mjs +++ /dev/null @@ -1,1147 +0,0 @@ -import { - Ok, - Error, - toList, - Empty as $Empty, - prepend as listPrepend, - CustomType as $CustomType, - isEqual, -} from "../gleam.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 * as $string from "../gleam/string.mjs"; -import * as $string_tree from "../gleam/string_tree.mjs"; -import { - pop_codeunit, - string_codeunit_slice as codeunit_slice, - parse_query, - percent_encode, - percent_decode, -} from "../gleam_stdlib.mjs"; - -export { parse_query, percent_decode, percent_encode }; - -export class Uri extends $CustomType { - constructor(scheme, userinfo, host, port, path, query, fragment) { - super(); - this.scheme = scheme; - this.userinfo = userinfo; - this.host = host; - this.port = port; - this.path = path; - this.query = query; - this.fragment = fragment; - } -} -export const Uri$Uri = (scheme, userinfo, host, port, path, query, fragment) => - new Uri(scheme, userinfo, host, port, path, query, fragment); -export const Uri$isUri = (value) => value instanceof Uri; -export const Uri$Uri$scheme = (value) => value.scheme; -export const Uri$Uri$0 = (value) => value.scheme; -export const Uri$Uri$userinfo = (value) => value.userinfo; -export const Uri$Uri$1 = (value) => value.userinfo; -export const Uri$Uri$host = (value) => value.host; -export const Uri$Uri$2 = (value) => value.host; -export const Uri$Uri$port = (value) => value.port; -export const Uri$Uri$3 = (value) => value.port; -export const Uri$Uri$path = (value) => value.path; -export const Uri$Uri$4 = (value) => value.path; -export const Uri$Uri$query = (value) => value.query; -export const Uri$Uri$5 = (value) => value.query; -export const Uri$Uri$fragment = (value) => value.fragment; -export const Uri$Uri$6 = (value) => value.fragment; - -function is_valid_host_within_brackets_char(char) { - return (((((48 >= char) && (char <= 57)) || ((65 >= char) && (char <= 90))) || ((97 >= char) && (char <= 122))) || (char === 58)) || (char === 46); -} - -function parse_fragment(rest, pieces) { - return new Ok( - new Uri( - pieces.scheme, - pieces.userinfo, - pieces.host, - pieces.port, - pieces.path, - pieces.query, - new Some(rest), - ), - ); -} - -function parse_query_with_question_mark_loop( - loop$original, - loop$uri_string, - loop$pieces, - loop$size -) { - while (true) { - let original = loop$original; - let uri_string = loop$uri_string; - let pieces = loop$pieces; - let size = loop$size; - if (uri_string.startsWith("#")) { - if (size === 0) { - let rest = uri_string.slice(1); - return parse_fragment(rest, pieces); - } else { - let rest = uri_string.slice(1); - let query = codeunit_slice(original, 0, size); - let pieces$1 = new Uri( - pieces.scheme, - pieces.userinfo, - pieces.host, - pieces.port, - pieces.path, - new Some(query), - pieces.fragment, - ); - return parse_fragment(rest, pieces$1); - } - } else if (uri_string === "") { - return new Ok( - new Uri( - pieces.scheme, - pieces.userinfo, - pieces.host, - pieces.port, - pieces.path, - new Some(original), - pieces.fragment, - ), - ); - } else { - let $ = pop_codeunit(uri_string); - let rest; - rest = $[1]; - loop$original = original; - loop$uri_string = rest; - loop$pieces = pieces; - loop$size = size + 1; - } - } -} - -function parse_query_with_question_mark(uri_string, pieces) { - return parse_query_with_question_mark_loop(uri_string, uri_string, pieces, 0); -} - -function parse_path_loop(loop$original, loop$uri_string, loop$pieces, loop$size) { - while (true) { - let original = loop$original; - let uri_string = loop$uri_string; - let pieces = loop$pieces; - let size = loop$size; - if (uri_string.startsWith("?")) { - let rest = uri_string.slice(1); - let path = codeunit_slice(original, 0, size); - let pieces$1 = new Uri( - pieces.scheme, - pieces.userinfo, - pieces.host, - pieces.port, - path, - pieces.query, - pieces.fragment, - ); - return parse_query_with_question_mark(rest, pieces$1); - } else if (uri_string.startsWith("#")) { - let rest = uri_string.slice(1); - let path = codeunit_slice(original, 0, size); - let pieces$1 = new Uri( - pieces.scheme, - pieces.userinfo, - pieces.host, - pieces.port, - path, - pieces.query, - pieces.fragment, - ); - return parse_fragment(rest, pieces$1); - } else if (uri_string === "") { - return new Ok( - new Uri( - pieces.scheme, - pieces.userinfo, - pieces.host, - pieces.port, - original, - pieces.query, - pieces.fragment, - ), - ); - } else { - let $ = pop_codeunit(uri_string); - let rest; - rest = $[1]; - loop$original = original; - loop$uri_string = rest; - loop$pieces = pieces; - loop$size = size + 1; - } - } -} - -function parse_path(uri_string, pieces) { - return parse_path_loop(uri_string, uri_string, pieces, 0); -} - -function parse_port_loop(loop$uri_string, loop$pieces, loop$port) { - while (true) { - let uri_string = loop$uri_string; - let pieces = loop$pieces; - let port = loop$port; - if (uri_string.startsWith("0")) { - let rest = uri_string.slice(1); - loop$uri_string = rest; - loop$pieces = pieces; - loop$port = port * 10; - } else if (uri_string.startsWith("1")) { - let rest = uri_string.slice(1); - loop$uri_string = rest; - loop$pieces = pieces; - loop$port = port * 10 + 1; - } else if (uri_string.startsWith("2")) { - let rest = uri_string.slice(1); - loop$uri_string = rest; - loop$pieces = pieces; - loop$port = port * 10 + 2; - } else if (uri_string.startsWith("3")) { - let rest = uri_string.slice(1); - loop$uri_string = rest; - loop$pieces = pieces; - loop$port = port * 10 + 3; - } else if (uri_string.startsWith("4")) { - let rest = uri_string.slice(1); - loop$uri_string = rest; - loop$pieces = pieces; - loop$port = port * 10 + 4; - } else if (uri_string.startsWith("5")) { - let rest = uri_string.slice(1); - loop$uri_string = rest; - loop$pieces = pieces; - loop$port = port * 10 + 5; - } else if (uri_string.startsWith("6")) { - let rest = uri_string.slice(1); - loop$uri_string = rest; - loop$pieces = pieces; - loop$port = port * 10 + 6; - } else if (uri_string.startsWith("7")) { - let rest = uri_string.slice(1); - loop$uri_string = rest; - loop$pieces = pieces; - loop$port = port * 10 + 7; - } else if (uri_string.startsWith("8")) { - let rest = uri_string.slice(1); - loop$uri_string = rest; - loop$pieces = pieces; - loop$port = port * 10 + 8; - } else if (uri_string.startsWith("9")) { - let rest = uri_string.slice(1); - loop$uri_string = rest; - loop$pieces = pieces; - loop$port = port * 10 + 9; - } else if (uri_string.startsWith("?")) { - let rest = uri_string.slice(1); - let pieces$1 = new Uri( - pieces.scheme, - pieces.userinfo, - pieces.host, - new Some(port), - pieces.path, - pieces.query, - pieces.fragment, - ); - return parse_query_with_question_mark(rest, pieces$1); - } else if (uri_string.startsWith("#")) { - let rest = uri_string.slice(1); - let pieces$1 = new Uri( - pieces.scheme, - pieces.userinfo, - pieces.host, - new Some(port), - pieces.path, - pieces.query, - pieces.fragment, - ); - return parse_fragment(rest, pieces$1); - } else if (uri_string.startsWith("/")) { - let pieces$1 = new Uri( - pieces.scheme, - pieces.userinfo, - pieces.host, - new Some(port), - pieces.path, - pieces.query, - pieces.fragment, - ); - return parse_path(uri_string, pieces$1); - } else if (uri_string === "") { - return new Ok( - new Uri( - pieces.scheme, - pieces.userinfo, - pieces.host, - new Some(port), - pieces.path, - pieces.query, - pieces.fragment, - ), - ); - } else { - return new Error(undefined); - } - } -} - -function parse_port(uri_string, pieces) { - if (uri_string.startsWith(":0")) { - let rest = uri_string.slice(2); - return parse_port_loop(rest, pieces, 0); - } else if (uri_string.startsWith(":1")) { - let rest = uri_string.slice(2); - return parse_port_loop(rest, pieces, 1); - } else if (uri_string.startsWith(":2")) { - let rest = uri_string.slice(2); - return parse_port_loop(rest, pieces, 2); - } else if (uri_string.startsWith(":3")) { - let rest = uri_string.slice(2); - return parse_port_loop(rest, pieces, 3); - } else if (uri_string.startsWith(":4")) { - let rest = uri_string.slice(2); - return parse_port_loop(rest, pieces, 4); - } else if (uri_string.startsWith(":5")) { - let rest = uri_string.slice(2); - return parse_port_loop(rest, pieces, 5); - } else if (uri_string.startsWith(":6")) { - let rest = uri_string.slice(2); - return parse_port_loop(rest, pieces, 6); - } else if (uri_string.startsWith(":7")) { - let rest = uri_string.slice(2); - return parse_port_loop(rest, pieces, 7); - } else if (uri_string.startsWith(":8")) { - let rest = uri_string.slice(2); - return parse_port_loop(rest, pieces, 8); - } else if (uri_string.startsWith(":9")) { - let rest = uri_string.slice(2); - return parse_port_loop(rest, pieces, 9); - } else if (uri_string === ":") { - return new Ok(pieces); - } else if (uri_string === "") { - return new Ok(pieces); - } else if (uri_string.startsWith("?")) { - let rest = uri_string.slice(1); - return parse_query_with_question_mark(rest, pieces); - } else if (uri_string.startsWith(":?")) { - let rest = uri_string.slice(2); - return parse_query_with_question_mark(rest, pieces); - } else if (uri_string.startsWith("#")) { - let rest = uri_string.slice(1); - return parse_fragment(rest, pieces); - } else if (uri_string.startsWith(":#")) { - let rest = uri_string.slice(2); - return parse_fragment(rest, pieces); - } else if (uri_string.startsWith("/")) { - return parse_path(uri_string, pieces); - } else if (uri_string.startsWith(":")) { - let rest = uri_string.slice(1); - if (rest.startsWith("/")) { - return parse_path(rest, pieces); - } else { - return new Error(undefined); - } - } else { - return new Error(undefined); - } -} - -function parse_host_outside_of_brackets_loop( - loop$original, - loop$uri_string, - loop$pieces, - loop$size -) { - while (true) { - let original = loop$original; - let uri_string = loop$uri_string; - let pieces = loop$pieces; - let size = loop$size; - if (uri_string === "") { - return new Ok( - new Uri( - pieces.scheme, - pieces.userinfo, - new Some(original), - pieces.port, - pieces.path, - pieces.query, - pieces.fragment, - ), - ); - } else if (uri_string.startsWith(":")) { - let host = codeunit_slice(original, 0, size); - let pieces$1 = new Uri( - pieces.scheme, - pieces.userinfo, - new Some(host), - pieces.port, - pieces.path, - pieces.query, - pieces.fragment, - ); - return parse_port(uri_string, pieces$1); - } else if (uri_string.startsWith("/")) { - let host = codeunit_slice(original, 0, size); - let pieces$1 = new Uri( - pieces.scheme, - pieces.userinfo, - new Some(host), - pieces.port, - pieces.path, - pieces.query, - pieces.fragment, - ); - return parse_path(uri_string, pieces$1); - } else if (uri_string.startsWith("?")) { - let rest = uri_string.slice(1); - let host = codeunit_slice(original, 0, size); - let pieces$1 = new Uri( - pieces.scheme, - pieces.userinfo, - new Some(host), - pieces.port, - pieces.path, - pieces.query, - pieces.fragment, - ); - return parse_query_with_question_mark(rest, pieces$1); - } else if (uri_string.startsWith("#")) { - let rest = uri_string.slice(1); - let host = codeunit_slice(original, 0, size); - let pieces$1 = new Uri( - pieces.scheme, - pieces.userinfo, - new Some(host), - pieces.port, - pieces.path, - pieces.query, - pieces.fragment, - ); - return parse_fragment(rest, pieces$1); - } else { - let $ = pop_codeunit(uri_string); - let rest; - rest = $[1]; - loop$original = original; - loop$uri_string = rest; - loop$pieces = pieces; - loop$size = size + 1; - } - } -} - -function parse_host_within_brackets_loop( - loop$original, - loop$uri_string, - loop$pieces, - loop$size -) { - while (true) { - let original = loop$original; - let uri_string = loop$uri_string; - let pieces = loop$pieces; - let size = loop$size; - if (uri_string === "") { - return new Ok( - new Uri( - pieces.scheme, - pieces.userinfo, - new Some(uri_string), - pieces.port, - pieces.path, - pieces.query, - pieces.fragment, - ), - ); - } else if (uri_string.startsWith("]")) { - if (size === 0) { - let rest = uri_string.slice(1); - return parse_port(rest, pieces); - } else { - let rest = uri_string.slice(1); - let host = codeunit_slice(original, 0, size + 1); - let pieces$1 = new Uri( - pieces.scheme, - pieces.userinfo, - new Some(host), - pieces.port, - pieces.path, - pieces.query, - pieces.fragment, - ); - return parse_port(rest, pieces$1); - } - } else if (uri_string.startsWith("/")) { - if (size === 0) { - return parse_path(uri_string, pieces); - } else { - let host = codeunit_slice(original, 0, size); - let pieces$1 = new Uri( - pieces.scheme, - pieces.userinfo, - new Some(host), - pieces.port, - pieces.path, - pieces.query, - pieces.fragment, - ); - return parse_path(uri_string, pieces$1); - } - } else if (uri_string.startsWith("?")) { - if (size === 0) { - let rest = uri_string.slice(1); - return parse_query_with_question_mark(rest, pieces); - } else { - let rest = uri_string.slice(1); - let host = codeunit_slice(original, 0, size); - let pieces$1 = new Uri( - pieces.scheme, - pieces.userinfo, - new Some(host), - pieces.port, - pieces.path, - pieces.query, - pieces.fragment, - ); - return parse_query_with_question_mark(rest, pieces$1); - } - } else if (uri_string.startsWith("#")) { - if (size === 0) { - let rest = uri_string.slice(1); - return parse_fragment(rest, pieces); - } else { - let rest = uri_string.slice(1); - let host = codeunit_slice(original, 0, size); - let pieces$1 = new Uri( - pieces.scheme, - pieces.userinfo, - new Some(host), - pieces.port, - pieces.path, - pieces.query, - pieces.fragment, - ); - return parse_fragment(rest, pieces$1); - } - } else { - let $ = pop_codeunit(uri_string); - let char; - let rest; - char = $[0]; - rest = $[1]; - let $1 = is_valid_host_within_brackets_char(char); - if ($1) { - loop$original = original; - loop$uri_string = rest; - loop$pieces = pieces; - loop$size = size + 1; - } else { - return parse_host_outside_of_brackets_loop( - original, - original, - pieces, - 0, - ); - } - } - } -} - -function parse_host_within_brackets(uri_string, pieces) { - return parse_host_within_brackets_loop(uri_string, uri_string, pieces, 0); -} - -function parse_host_outside_of_brackets(uri_string, pieces) { - return parse_host_outside_of_brackets_loop(uri_string, uri_string, pieces, 0); -} - -function parse_host(uri_string, pieces) { - if (uri_string.startsWith("[")) { - return parse_host_within_brackets(uri_string, pieces); - } else if (uri_string.startsWith(":")) { - let pieces$1 = new Uri( - pieces.scheme, - pieces.userinfo, - new Some(""), - pieces.port, - pieces.path, - pieces.query, - pieces.fragment, - ); - return parse_port(uri_string, pieces$1); - } else if (uri_string === "") { - return new Ok( - new Uri( - pieces.scheme, - pieces.userinfo, - new Some(""), - pieces.port, - pieces.path, - pieces.query, - pieces.fragment, - ), - ); - } else { - return parse_host_outside_of_brackets(uri_string, pieces); - } -} - -function parse_userinfo_loop( - loop$original, - loop$uri_string, - loop$pieces, - loop$size -) { - while (true) { - let original = loop$original; - let uri_string = loop$uri_string; - let pieces = loop$pieces; - let size = loop$size; - if (uri_string.startsWith("@")) { - if (size === 0) { - let rest = uri_string.slice(1); - return parse_host(rest, pieces); - } else { - let rest = uri_string.slice(1); - let userinfo = codeunit_slice(original, 0, size); - let pieces$1 = new Uri( - pieces.scheme, - new Some(userinfo), - pieces.host, - pieces.port, - pieces.path, - pieces.query, - pieces.fragment, - ); - return parse_host(rest, pieces$1); - } - } else if (uri_string === "") { - return parse_host(original, pieces); - } else if (uri_string.startsWith("/")) { - return parse_host(original, pieces); - } else if (uri_string.startsWith("?")) { - return parse_host(original, pieces); - } else if (uri_string.startsWith("#")) { - return parse_host(original, pieces); - } else { - let $ = pop_codeunit(uri_string); - let rest; - rest = $[1]; - loop$original = original; - loop$uri_string = rest; - loop$pieces = pieces; - loop$size = size + 1; - } - } -} - -function parse_authority_pieces(string, pieces) { - return parse_userinfo_loop(string, string, pieces, 0); -} - -function parse_authority_with_slashes(uri_string, pieces) { - if (uri_string === "//") { - return new Ok( - new Uri( - pieces.scheme, - pieces.userinfo, - new Some(""), - pieces.port, - pieces.path, - pieces.query, - pieces.fragment, - ), - ); - } else if (uri_string.startsWith("//")) { - let rest = uri_string.slice(2); - return parse_authority_pieces(rest, pieces); - } else { - return parse_path(uri_string, pieces); - } -} - -function parse_scheme_loop( - loop$original, - loop$uri_string, - loop$pieces, - loop$size -) { - while (true) { - let original = loop$original; - let uri_string = loop$uri_string; - let pieces = loop$pieces; - let size = loop$size; - if (uri_string.startsWith("/")) { - if (size === 0) { - return parse_authority_with_slashes(uri_string, pieces); - } else { - let scheme = codeunit_slice(original, 0, size); - let pieces$1 = new Uri( - new Some($string.lowercase(scheme)), - pieces.userinfo, - pieces.host, - pieces.port, - pieces.path, - pieces.query, - pieces.fragment, - ); - return parse_authority_with_slashes(uri_string, pieces$1); - } - } else if (uri_string.startsWith("?")) { - if (size === 0) { - let rest = uri_string.slice(1); - return parse_query_with_question_mark(rest, pieces); - } else { - let rest = uri_string.slice(1); - let scheme = codeunit_slice(original, 0, size); - let pieces$1 = new Uri( - new Some($string.lowercase(scheme)), - pieces.userinfo, - pieces.host, - pieces.port, - pieces.path, - pieces.query, - pieces.fragment, - ); - return parse_query_with_question_mark(rest, pieces$1); - } - } else if (uri_string.startsWith("#")) { - if (size === 0) { - let rest = uri_string.slice(1); - return parse_fragment(rest, pieces); - } else { - let rest = uri_string.slice(1); - let scheme = codeunit_slice(original, 0, size); - let pieces$1 = new Uri( - new Some($string.lowercase(scheme)), - pieces.userinfo, - pieces.host, - pieces.port, - pieces.path, - pieces.query, - pieces.fragment, - ); - return parse_fragment(rest, pieces$1); - } - } else if (uri_string.startsWith(":")) { - if (size === 0) { - return new Error(undefined); - } else { - let rest = uri_string.slice(1); - let scheme = codeunit_slice(original, 0, size); - let pieces$1 = new Uri( - new Some($string.lowercase(scheme)), - pieces.userinfo, - pieces.host, - pieces.port, - pieces.path, - pieces.query, - pieces.fragment, - ); - return parse_authority_with_slashes(rest, pieces$1); - } - } else if (uri_string === "") { - return new Ok( - new Uri( - pieces.scheme, - pieces.userinfo, - pieces.host, - pieces.port, - original, - pieces.query, - pieces.fragment, - ), - ); - } else { - let $ = pop_codeunit(uri_string); - let rest; - rest = $[1]; - loop$original = original; - loop$uri_string = rest; - loop$pieces = pieces; - loop$size = size + 1; - } - } -} - -function query_pair(pair) { - return $string_tree.from_strings( - toList([percent_encode(pair[0]), "=", percent_encode(pair[1])]), - ); -} - -/** - * Encodes a list of key value pairs as a URI query string. - * - * The opposite operation is `uri.parse_query`. - * - * ## Examples - * - * ```gleam - * query_to_string([#("a", "1"), #("b", "2")]) - * // -> "a=1&b=2" - * ``` - */ -export function query_to_string(query) { - let _pipe = query; - let _pipe$1 = $list.map(_pipe, query_pair); - let _pipe$2 = $list.intersperse(_pipe$1, $string_tree.from_string("&")); - let _pipe$3 = $string_tree.concat(_pipe$2); - return $string_tree.to_string(_pipe$3); -} - -function remove_dot_segments_loop(loop$input, loop$accumulator) { - while (true) { - let input = loop$input; - let accumulator = loop$accumulator; - if (input instanceof $Empty) { - return $list.reverse(accumulator); - } else { - let segment = input.head; - let rest = input.tail; - let _block; - if (segment === "") { - _block = accumulator; - } else if (segment === ".") { - _block = accumulator; - } else if (segment === "..") { - if (accumulator instanceof $Empty) { - _block = accumulator; - } else { - let accumulator$1 = accumulator.tail; - _block = accumulator$1; - } - } else { - let segment$1 = segment; - let accumulator$1 = accumulator; - _block = listPrepend(segment$1, accumulator$1); - } - let accumulator$1 = _block; - loop$input = rest; - loop$accumulator = accumulator$1; - } - } -} - -function remove_dot_segments(input) { - return remove_dot_segments_loop(input, toList([])); -} - -/** - * Splits the path section of a URI into it's constituent segments. - * - * Removes empty segments and resolves dot-segments as specified in - * [section 5.2](https://www.ietf.org/rfc/rfc3986.html#section-5.2) of the RFC. - * - * ## Examples - * - * ```gleam - * path_segments("/users/1") - * // -> ["users" ,"1"] - * ``` - */ -export function path_segments(path) { - return remove_dot_segments($string.split(path, "/")); -} - -/** - * Encodes a `Uri` value as a URI string. - * - * The opposite operation is `uri.parse`. - * - * ## Examples - * - * ```gleam - * let uri = Uri(..empty, scheme: Some("https"), host: Some("example.com")) - * to_string(uri) - * // -> "https://example.com" - * ``` - */ -export function to_string(uri) { - let _block; - let $ = uri.fragment; - if ($ instanceof Some) { - let fragment = $[0]; - _block = toList(["#", fragment]); - } else { - _block = toList([]); - } - let parts = _block; - let _block$1; - let $1 = uri.query; - if ($1 instanceof Some) { - let query = $1[0]; - _block$1 = listPrepend("?", listPrepend(query, parts)); - } else { - _block$1 = parts; - } - let parts$1 = _block$1; - let parts$2 = listPrepend(uri.path, parts$1); - let _block$2; - let $2 = uri.host; - let $3 = $string.starts_with(uri.path, "/"); - if ($2 instanceof Some && !$3) { - let host = $2[0]; - if (host !== "") { - _block$2 = listPrepend("/", parts$2); - } else { - _block$2 = parts$2; - } - } else { - _block$2 = parts$2; - } - let parts$3 = _block$2; - let _block$3; - let $4 = uri.host; - let $5 = uri.port; - if ($4 instanceof Some && $5 instanceof Some) { - let port = $5[0]; - _block$3 = listPrepend(":", listPrepend($int.to_string(port), parts$3)); - } else { - _block$3 = parts$3; - } - let parts$4 = _block$3; - let _block$4; - let $6 = uri.scheme; - let $7 = uri.userinfo; - let $8 = uri.host; - if ($6 instanceof Some) { - if ($7 instanceof Some) { - if ($8 instanceof Some) { - let s = $6[0]; - let u = $7[0]; - let h = $8[0]; - _block$4 = listPrepend( - s, - listPrepend( - "://", - listPrepend(u, listPrepend("@", listPrepend(h, parts$4))), - ), - ); - } else { - let s = $6[0]; - _block$4 = listPrepend(s, listPrepend(":", parts$4)); - } - } else if ($8 instanceof Some) { - let s = $6[0]; - let h = $8[0]; - _block$4 = listPrepend(s, listPrepend("://", listPrepend(h, parts$4))); - } else { - let s = $6[0]; - _block$4 = listPrepend(s, listPrepend(":", parts$4)); - } - } else if ($7 instanceof None && $8 instanceof Some) { - let h = $8[0]; - _block$4 = listPrepend("//", listPrepend(h, parts$4)); - } else { - _block$4 = parts$4; - } - let parts$5 = _block$4; - return $string.concat(parts$5); -} - -/** - * Fetches the origin of a URI. - * - * Returns the origin of a uri as defined in - * [RFC 6454](https://tools.ietf.org/html/rfc6454) - * - * The supported URI schemes are `http` and `https`. - * URLs without a scheme will return `Error`. - * - * ## Examples - * - * ```gleam - * let assert Ok(uri) = parse("https://example.com/path?foo#bar") - * origin(uri) - * // -> Ok("https://example.com") - * ``` - */ -export function origin(uri) { - let scheme; - let host; - let port; - scheme = uri.scheme; - host = uri.host; - port = uri.port; - if (host instanceof Some && scheme instanceof Some) { - let $ = scheme[0]; - if ($ === "https" && isEqual(port, new Some(443))) { - let h = host[0]; - return new Ok($string.concat(toList(["https://", h]))); - } else if ($ === "http" && isEqual(port, new Some(80))) { - let h = host[0]; - return new Ok($string.concat(toList(["http://", h]))); - } else { - let s = $; - if ((s === "http") || (s === "https")) { - let h = host[0]; - if (port instanceof Some) { - let p = port[0]; - return new Ok( - $string.concat(toList([s, "://", h, ":", $int.to_string(p)])), - ); - } else { - return new Ok($string.concat(toList([s, "://", h]))); - } - } else { - return new Error(undefined); - } - } - } else { - return new Error(undefined); - } -} - -function drop_last(elements) { - return $list.take(elements, $list.length(elements) - 1); -} - -function join_segments(segments) { - return $string.join(listPrepend("", segments), "/"); -} - -/** - * Resolves a URI with respect to the given base URI. - * - * The base URI must be an absolute URI or this function will return an error. - * The algorithm for merging uris is described in - * [RFC 3986](https://tools.ietf.org/html/rfc3986#section-5.2). - */ -export function merge(base, relative) { - let $ = base.scheme; - if ($ instanceof Some) { - let $1 = base.host; - if ($1 instanceof Some) { - let $2 = relative.host; - if ($2 instanceof Some) { - let _block; - let _pipe = relative.path; - let _pipe$1 = $string.split(_pipe, "/"); - let _pipe$2 = remove_dot_segments(_pipe$1); - _block = join_segments(_pipe$2); - let path = _block; - let resolved = new Uri( - $option.or(relative.scheme, base.scheme), - new None(), - relative.host, - $option.or(relative.port, base.port), - path, - relative.query, - relative.fragment, - ); - return new Ok(resolved); - } else { - let _block; - let $4 = relative.path; - if ($4 === "") { - _block = [base.path, $option.or(relative.query, base.query)]; - } else { - let _block$1; - let $5 = $string.starts_with(relative.path, "/"); - if ($5) { - _block$1 = $string.split(relative.path, "/"); - } else { - let _pipe = base.path; - let _pipe$1 = $string.split(_pipe, "/"); - let _pipe$2 = drop_last(_pipe$1); - _block$1 = $list.append(_pipe$2, $string.split(relative.path, "/")); - } - let path_segments$1 = _block$1; - let _block$2; - let _pipe = path_segments$1; - let _pipe$1 = remove_dot_segments(_pipe); - _block$2 = join_segments(_pipe$1); - let path = _block$2; - _block = [path, relative.query]; - } - let $3 = _block; - let new_path; - let new_query; - new_path = $3[0]; - new_query = $3[1]; - let resolved = new Uri( - base.scheme, - new None(), - base.host, - base.port, - new_path, - new_query, - relative.fragment, - ); - return new Ok(resolved); - } - } else { - return new Error(undefined); - } - } else { - return new Error(undefined); - } -} - -/** - * Constant representing an empty URI, equivalent to "". - * - * ## Examples - * - * ```gleam - * let uri = Uri(..empty, scheme: Some("https"), host: Some("example.com")) - * // -> Uri( - * // scheme: Some("https"), - * // userinfo: None, - * // host: Some("example.com"), - * // port: None, - * // path: "", - * // query: None, - * // fragment: None, - * // ) - * ``` - */ -export const empty = /* @__PURE__ */ new Uri( - /* @__PURE__ */ new None(), - /* @__PURE__ */ new None(), - /* @__PURE__ */ new None(), - /* @__PURE__ */ new None(), - "", - /* @__PURE__ */ new None(), - /* @__PURE__ */ new None(), -); - -/** - * Parses a compliant URI string into the `Uri` Type. - * If the string is not a valid URI string then an error is returned. - * - * The opposite operation is `uri.to_string`. - * - * ## Examples - * - * ```gleam - * parse("https://example.com:1234/a/b?query=true#fragment") - * // -> Ok( - * // Uri( - * // scheme: Some("https"), - * // userinfo: None, - * // host: Some("example.com"), - * // port: Some(1234), - * // path: "/a/b", - * // query: Some("query=true"), - * // fragment: Some("fragment") - * // ) - * // ) - * ``` - */ -export function parse(uri_string) { - return parse_scheme_loop(uri_string, uri_string, empty, 0); -} diff --git a/build/dev/javascript/gleam_stdlib/gleam@bit_array.erl b/build/dev/javascript/gleam_stdlib/gleam@bit_array.erl deleted file mode 100644 index 7df56ce..0000000 --- a/build/dev/javascript/gleam_stdlib/gleam@bit_array.erl +++ /dev/null @@ -1,347 +0,0 @@ --module(gleam@bit_array). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "src/gleam/bit_array.gleam"). --export([from_string/1, bit_size/1, byte_size/1, pad_to_bytes/1, slice/3, is_utf8/1, to_string/1, concat/1, append/2, base64_encode/2, base64_decode/1, base64_url_encode/2, base64_url_decode/1, base16_encode/1, base16_decode/1, inspect/1, compare/2, starts_with/2]). - --if(?OTP_RELEASE >= 27). --define(MODULEDOC(Str), -moduledoc(Str)). --define(DOC(Str), -doc(Str)). --else. --define(MODULEDOC(Str), -compile([])). --define(DOC(Str), -compile([])). --endif. - -?MODULEDOC(" BitArrays are a sequence of binary data of any length.\n"). - --file("src/gleam/bit_array.gleam", 11). -?DOC(" Converts a UTF-8 `String` type into a `BitArray`.\n"). --spec from_string(binary()) -> bitstring(). -from_string(X) -> - gleam_stdlib:identity(X). - --file("src/gleam/bit_array.gleam", 17). -?DOC(" Returns an integer which is the number of bits in the bit array.\n"). --spec bit_size(bitstring()) -> integer(). -bit_size(X) -> - erlang:bit_size(X). - --file("src/gleam/bit_array.gleam", 23). -?DOC(" Returns an integer which is the number of bytes in the bit array.\n"). --spec byte_size(bitstring()) -> integer(). -byte_size(X) -> - erlang:byte_size(X). - --file("src/gleam/bit_array.gleam", 29). -?DOC(" Pads a bit array with zeros so that it is a whole number of bytes.\n"). --spec pad_to_bytes(bitstring()) -> bitstring(). -pad_to_bytes(X) -> - gleam_stdlib:bit_array_pad_to_bytes(X). - --file("src/gleam/bit_array.gleam", 54). -?DOC( - " Extracts a sub-section of a bit array.\n" - "\n" - " The slice will start at given position and continue up to specified\n" - " length.\n" - " A negative length can be used to extract bytes at the end of a bit array.\n" - "\n" - " This function runs in constant time.\n" -). --spec slice(bitstring(), integer(), integer()) -> {ok, bitstring()} | - {error, nil}. -slice(String, Position, Length) -> - gleam_stdlib:bit_array_slice(String, Position, Length). - --file("src/gleam/bit_array.gleam", 67). --spec is_utf8_loop(bitstring()) -> boolean(). -is_utf8_loop(Bits) -> - case Bits of - <<>> -> - true; - - <<_/utf8, Rest/binary>> -> - is_utf8_loop(Rest); - - _ -> - false - end. - --file("src/gleam/bit_array.gleam", 62). -?DOC(" Tests to see whether a bit array is valid UTF-8.\n"). --spec is_utf8(bitstring()) -> boolean(). -is_utf8(Bits) -> - is_utf8_loop(Bits). - --file("src/gleam/bit_array.gleam", 88). -?DOC( - " Converts a bit array to a string.\n" - "\n" - " Returns an error if the bit array is invalid UTF-8 data.\n" -). --spec to_string(bitstring()) -> {ok, binary()} | {error, nil}. -to_string(Bits) -> - case is_utf8(Bits) of - true -> - {ok, gleam_stdlib:identity(Bits)}; - - false -> - {error, nil} - end. - --file("src/gleam/bit_array.gleam", 109). -?DOC( - " Creates a new bit array by joining multiple binaries.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " concat([from_string(\"butter\"), from_string(\"fly\")])\n" - " // -> from_string(\"butterfly\")\n" - " ```\n" -). --spec concat(list(bitstring())) -> bitstring(). -concat(Bit_arrays) -> - gleam_stdlib:bit_array_concat(Bit_arrays). - --file("src/gleam/bit_array.gleam", 40). -?DOC( - " Creates a new bit array by joining two bit arrays.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " append(to: from_string(\"butter\"), suffix: from_string(\"fly\"))\n" - " // -> from_string(\"butterfly\")\n" - " ```\n" -). --spec append(bitstring(), bitstring()) -> bitstring(). -append(First, Second) -> - gleam_stdlib:bit_array_concat([First, Second]). - --file("src/gleam/bit_array.gleam", 118). -?DOC( - " Encodes a BitArray into a base 64 encoded string.\n" - "\n" - " If the bit array does not contain a whole number of bytes then it is padded\n" - " with zero bits prior to being encoded.\n" -). --spec base64_encode(bitstring(), boolean()) -> binary(). -base64_encode(Input, Padding) -> - gleam_stdlib:base64_encode(Input, Padding). - --file("src/gleam/bit_array.gleam", 122). -?DOC(" Decodes a base 64 encoded string into a `BitArray`.\n"). --spec base64_decode(binary()) -> {ok, bitstring()} | {error, nil}. -base64_decode(Encoded) -> - Padded = case erlang:byte_size(gleam_stdlib:identity(Encoded)) rem 4 of - 0 -> - Encoded; - - N -> - gleam@string:append( - Encoded, - gleam@string:repeat(<<"="/utf8>>, 4 - N) - ) - end, - gleam_stdlib:base64_decode(Padded). - --file("src/gleam/bit_array.gleam", 140). -?DOC( - " Encodes a `BitArray` into a base 64 encoded string with URL and filename\n" - " safe alphabet.\n" - "\n" - " If the bit array does not contain a whole number of bytes then it is padded\n" - " with zero bits prior to being encoded.\n" -). --spec base64_url_encode(bitstring(), boolean()) -> binary(). -base64_url_encode(Input, Padding) -> - _pipe = Input, - _pipe@1 = gleam_stdlib:base64_encode(_pipe, Padding), - _pipe@2 = gleam@string:replace(_pipe@1, <<"+"/utf8>>, <<"-"/utf8>>), - gleam@string:replace(_pipe@2, <<"/"/utf8>>, <<"_"/utf8>>). - --file("src/gleam/bit_array.gleam", 150). -?DOC( - " Decodes a base 64 encoded string with URL and filename safe alphabet into a\n" - " `BitArray`.\n" -). --spec base64_url_decode(binary()) -> {ok, bitstring()} | {error, nil}. -base64_url_decode(Encoded) -> - _pipe = Encoded, - _pipe@1 = gleam@string:replace(_pipe, <<"-"/utf8>>, <<"+"/utf8>>), - _pipe@2 = gleam@string:replace(_pipe@1, <<"_"/utf8>>, <<"/"/utf8>>), - base64_decode(_pipe@2). - --file("src/gleam/bit_array.gleam", 164). -?DOC( - " Encodes a `BitArray` into a base 16 encoded string.\n" - "\n" - " If the bit array does not contain a whole number of bytes then it is padded\n" - " with zero bits prior to being encoded.\n" -). --spec base16_encode(bitstring()) -> binary(). -base16_encode(Input) -> - gleam_stdlib:base16_encode(Input). - --file("src/gleam/bit_array.gleam", 170). -?DOC(" Decodes a base 16 encoded string into a `BitArray`.\n"). --spec base16_decode(binary()) -> {ok, bitstring()} | {error, nil}. -base16_decode(Input) -> - gleam_stdlib:base16_decode(Input). - --file("src/gleam/bit_array.gleam", 191). --spec inspect_loop(bitstring(), binary()) -> binary(). -inspect_loop(Input, Accumulator) -> - case Input of - <<>> -> - Accumulator; - - <> -> - <<<>/binary, - ":size(1)"/utf8>>; - - <> -> - <<<>/binary, - ":size(2)"/utf8>>; - - <> -> - <<<>/binary, - ":size(3)"/utf8>>; - - <> -> - <<<>/binary, - ":size(4)"/utf8>>; - - <> -> - <<<>/binary, - ":size(5)"/utf8>>; - - <> -> - <<<>/binary, - ":size(6)"/utf8>>; - - <> -> - <<<>/binary, - ":size(7)"/utf8>>; - - <> -> - Suffix = case Rest of - <<>> -> - <<""/utf8>>; - - _ -> - <<", "/utf8>> - end, - Accumulator@1 = <<<>/binary, - Suffix/binary>>, - inspect_loop(Rest, Accumulator@1); - - _ -> - Accumulator - end. - --file("src/gleam/bit_array.gleam", 187). -?DOC( - " Converts a bit array to a string containing the decimal value of each byte.\n" - "\n" - " Use this over `string.inspect` when you have a bit array you want printed\n" - " in the array syntax even if it is valid UTF-8.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " inspect(<<0, 20, 0x20, 255>>)\n" - " // -> \"<<0, 20, 32, 255>>\"\n" - "\n" - " inspect(<<100, 5:3>>)\n" - " // -> \"<<100, 5:size(3)>>\"\n" - " ```\n" -). --spec inspect(bitstring()) -> binary(). -inspect(Input) -> - <<(inspect_loop(Input, <<"<<"/utf8>>))/binary, ">>"/utf8>>. - --file("src/gleam/bit_array.gleam", 232). -?DOC( - " Compare two bit arrays as sequences of bytes.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " compare(<<1>>, <<2>>)\n" - " // -> Lt\n" - "\n" - " compare(<<\"AB\":utf8>>, <<\"AA\":utf8>>)\n" - " // -> Gt\n" - "\n" - " compare(<<1, 2:size(2)>>, with: <<1, 2:size(2)>>)\n" - " // -> Eq\n" - " ```\n" -). --spec compare(bitstring(), bitstring()) -> gleam@order:order(). -compare(A, B) -> - case {A, B} of - {<>, - <>} -> - case {First_byte, Second_byte} of - {F, S} when F > S -> - gt; - - {F@1, S@1} when F@1 < S@1 -> - lt; - - {_, _} -> - compare(First_rest, Second_rest) - end; - - {<<>>, <<>>} -> - eq; - - {_, <<>>} -> - gt; - - {<<>>, _} -> - lt; - - {First, Second} -> - case {gleam_stdlib:bit_array_to_int_and_size(First), - gleam_stdlib:bit_array_to_int_and_size(Second)} of - {{A@1, _}, {B@1, _}} when A@1 > B@1 -> - gt; - - {{A@2, _}, {B@2, _}} when A@2 < B@2 -> - lt; - - {{_, Size_a}, {_, Size_b}} when Size_a > Size_b -> - gt; - - {{_, Size_a@1}, {_, Size_b@1}} when Size_a@1 < Size_b@1 -> - lt; - - {_, _} -> - eq - end - end. - --file("src/gleam/bit_array.gleam", 273). -?DOC( - " Checks whether the first `BitArray` starts with the second one.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " starts_with(<<1, 2, 3, 4>>, <<1, 2>>)\n" - " // -> True\n" - " ```\n" -). --spec starts_with(bitstring(), bitstring()) -> boolean(). -starts_with(Bits, Prefix) -> - Prefix_size = erlang:bit_size(Prefix), - case Bits of - <> when Pref =:= Prefix -> - true; - - _ -> - false - end. diff --git a/build/dev/javascript/gleam_stdlib/gleam@bool.erl b/build/dev/javascript/gleam_stdlib/gleam@bool.erl deleted file mode 100644 index 01307b3..0000000 --- a/build/dev/javascript/gleam_stdlib/gleam@bool.erl +++ /dev/null @@ -1,352 +0,0 @@ --module(gleam@bool). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "src/gleam/bool.gleam"). --export(['and'/2, 'or'/2, negate/1, nor/2, nand/2, exclusive_or/2, exclusive_nor/2, to_string/1, guard/3, lazy_guard/3]). - --if(?OTP_RELEASE >= 27). --define(MODULEDOC(Str), -moduledoc(Str)). --define(DOC(Str), -doc(Str)). --else. --define(MODULEDOC(Str), -compile([])). --define(DOC(Str), -compile([])). --endif. - -?MODULEDOC( - " A type with two possible values, `True` and `False`. Used to indicate whether\n" - " things are... true or false!\n" - "\n" - " Often is it clearer and offers more type safety to define a custom type\n" - " than to use `Bool`. For example, rather than having a `is_teacher: Bool`\n" - " field consider having a `role: SchoolRole` field where `SchoolRole` is a custom\n" - " type that can be either `Student` or `Teacher`.\n" -). - --file("src/gleam/bool.gleam", 31). -?DOC( - " Returns the and of two bools, but it evaluates both arguments.\n" - "\n" - " It's the function equivalent of the `&&` operator.\n" - " This function is useful in higher order functions or pipes.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " and(True, True)\n" - " // -> True\n" - " ```\n" - "\n" - " ```gleam\n" - " and(False, True)\n" - " // -> False\n" - " ```\n" - "\n" - " ```gleam\n" - " False |> and(True)\n" - " // -> False\n" - " ```\n" -). --spec 'and'(boolean(), boolean()) -> boolean(). -'and'(A, B) -> - A andalso B. - --file("src/gleam/bool.gleam", 57). -?DOC( - " Returns the or of two bools, but it evaluates both arguments.\n" - "\n" - " It's the function equivalent of the `||` operator.\n" - " This function is useful in higher order functions or pipes.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " or(True, True)\n" - " // -> True\n" - " ```\n" - "\n" - " ```gleam\n" - " or(False, True)\n" - " // -> True\n" - " ```\n" - "\n" - " ```gleam\n" - " False |> or(True)\n" - " // -> True\n" - " ```\n" -). --spec 'or'(boolean(), boolean()) -> boolean(). -'or'(A, B) -> - A orelse B. - --file("src/gleam/bool.gleam", 77). -?DOC( - " Returns the opposite bool value.\n" - "\n" - " This is the same as the `!` or `not` operators in some other languages.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " negate(True)\n" - " // -> False\n" - " ```\n" - "\n" - " ```gleam\n" - " negate(False)\n" - " // -> True\n" - " ```\n" -). --spec negate(boolean()) -> boolean(). -negate(Bool) -> - not Bool. - --file("src/gleam/bool.gleam", 105). -?DOC( - " Returns the nor of two bools.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " nor(False, False)\n" - " // -> True\n" - " ```\n" - "\n" - " ```gleam\n" - " nor(False, True)\n" - " // -> False\n" - " ```\n" - "\n" - " ```gleam\n" - " nor(True, False)\n" - " // -> False\n" - " ```\n" - "\n" - " ```gleam\n" - " nor(True, True)\n" - " // -> False\n" - " ```\n" -). --spec nor(boolean(), boolean()) -> boolean(). -nor(A, B) -> - not (A orelse B). - --file("src/gleam/bool.gleam", 133). -?DOC( - " Returns the nand of two bools.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " nand(False, False)\n" - " // -> True\n" - " ```\n" - "\n" - " ```gleam\n" - " nand(False, True)\n" - " // -> True\n" - " ```\n" - "\n" - " ```gleam\n" - " nand(True, False)\n" - " // -> True\n" - " ```\n" - "\n" - " ```gleam\n" - " nand(True, True)\n" - " // -> False\n" - " ```\n" -). --spec nand(boolean(), boolean()) -> boolean(). -nand(A, B) -> - not (A andalso B). - --file("src/gleam/bool.gleam", 161). -?DOC( - " Returns the exclusive or of two bools.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " exclusive_or(False, False)\n" - " // -> False\n" - " ```\n" - "\n" - " ```gleam\n" - " exclusive_or(False, True)\n" - " // -> True\n" - " ```\n" - "\n" - " ```gleam\n" - " exclusive_or(True, False)\n" - " // -> True\n" - " ```\n" - "\n" - " ```gleam\n" - " exclusive_or(True, True)\n" - " // -> False\n" - " ```\n" -). --spec exclusive_or(boolean(), boolean()) -> boolean(). -exclusive_or(A, B) -> - A /= B. - --file("src/gleam/bool.gleam", 189). -?DOC( - " Returns the exclusive nor of two bools.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " exclusive_nor(False, False)\n" - " // -> True\n" - " ```\n" - "\n" - " ```gleam\n" - " exclusive_nor(False, True)\n" - " // -> False\n" - " ```\n" - "\n" - " ```gleam\n" - " exclusive_nor(True, False)\n" - " // -> False\n" - " ```\n" - "\n" - " ```gleam\n" - " exclusive_nor(True, True)\n" - " // -> True\n" - " ```\n" -). --spec exclusive_nor(boolean(), boolean()) -> boolean(). -exclusive_nor(A, B) -> - A =:= B. - --file("src/gleam/bool.gleam", 207). -?DOC( - " Returns a string representation of the given bool.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " to_string(True)\n" - " // -> \"True\"\n" - " ```\n" - "\n" - " ```gleam\n" - " to_string(False)\n" - " // -> \"False\"\n" - " ```\n" -). --spec to_string(boolean()) -> binary(). -to_string(Bool) -> - case Bool of - false -> - <<"False"/utf8>>; - - true -> - <<"True"/utf8>> - end. - --file("src/gleam/bool.gleam", 266). -?DOC( - " Run a callback function if the given bool is `False`, otherwise return a\n" - " default value.\n" - "\n" - " With a `use` expression this function can simulate the early-return pattern\n" - " found in some other programming languages.\n" - "\n" - " In a procedural language:\n" - "\n" - " ```js\n" - " if (predicate) return value;\n" - " // ...\n" - " ```\n" - "\n" - " In Gleam with a `use` expression:\n" - "\n" - " ```gleam\n" - " use <- guard(when: predicate, return: value)\n" - " // ...\n" - " ```\n" - "\n" - " Like everything in Gleam `use` is an expression, so it short circuits the\n" - " current block, not the entire function. As a result you can assign the value\n" - " to a variable:\n" - "\n" - " ```gleam\n" - " let x = {\n" - " use <- guard(when: predicate, return: value)\n" - " // ...\n" - " }\n" - " ```\n" - "\n" - " Note that unlike in procedural languages the `return` value is evaluated\n" - " even when the predicate is `False`, so it is advisable not to perform\n" - " expensive computation nor side-effects there.\n" - "\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " let name = \"\"\n" - " use <- guard(when: name == \"\", return: \"Welcome!\")\n" - " \"Hello, \" <> name\n" - " // -> \"Welcome!\"\n" - " ```\n" - "\n" - " ```gleam\n" - " let name = \"Kamaka\"\n" - " use <- guard(when: name == \"\", return: \"Welcome!\")\n" - " \"Hello, \" <> name\n" - " // -> \"Hello, Kamaka\"\n" - " ```\n" -). --spec guard(boolean(), BSY, fun(() -> BSY)) -> BSY. -guard(Requirement, Consequence, Alternative) -> - case Requirement of - true -> - Consequence; - - false -> - Alternative() - end. - --file("src/gleam/bool.gleam", 307). -?DOC( - " Runs a callback function if the given bool is `True`, otherwise runs an\n" - " alternative callback function.\n" - "\n" - " Useful when further computation should be delayed regardless of the given\n" - " bool's value.\n" - "\n" - " See [`guard`](#guard) for more info.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " let name = \"Kamaka\"\n" - " let inquiry = fn() { \"How may we address you?\" }\n" - " use <- lazy_guard(when: name == \"\", return: inquiry)\n" - " \"Hello, \" <> name\n" - " // -> \"Hello, Kamaka\"\n" - " ```\n" - "\n" - " ```gleam\n" - " import gleam/int\n" - "\n" - " let name = \"\"\n" - " let greeting = fn() { \"Hello, \" <> name }\n" - " use <- lazy_guard(when: name == \"\", otherwise: greeting)\n" - " let number = int.random(99)\n" - " let name = \"User \" <> int.to_string(number)\n" - " \"Welcome, \" <> name\n" - " // -> \"Welcome, User 54\"\n" - " ```\n" -). --spec lazy_guard(boolean(), fun(() -> BSZ), fun(() -> BSZ)) -> BSZ. -lazy_guard(Requirement, Consequence, Alternative) -> - case Requirement of - true -> - Consequence(); - - false -> - Alternative() - end. diff --git a/build/dev/javascript/gleam_stdlib/gleam@bytes_tree.erl b/build/dev/javascript/gleam_stdlib/gleam@bytes_tree.erl deleted file mode 100644 index a96eaa2..0000000 --- a/build/dev/javascript/gleam_stdlib/gleam@bytes_tree.erl +++ /dev/null @@ -1,211 +0,0 @@ --module(gleam@bytes_tree). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "src/gleam/bytes_tree.gleam"). --export([append_tree/2, prepend_tree/2, concat/1, new/0, from_string/1, prepend_string/2, append_string/2, from_string_tree/1, from_bit_array/1, prepend/2, append/2, concat_bit_arrays/1, to_bit_array/1, byte_size/1]). --export_type([bytes_tree/0]). - --if(?OTP_RELEASE >= 27). --define(MODULEDOC(Str), -moduledoc(Str)). --define(DOC(Str), -doc(Str)). --else. --define(MODULEDOC(Str), -compile([])). --define(DOC(Str), -compile([])). --endif. - -?MODULEDOC( - " `BytesTree` is a type used for efficiently building binary content to be\n" - " written to a file or a socket. Internally it is represented as tree so to\n" - " append or prepend to a bytes tree is a constant time operation that\n" - " allocates a new node in the tree without copying any of the content. When\n" - " writing to an output stream the tree is traversed and the content is sent\n" - " directly rather than copying it into a single buffer beforehand.\n" - "\n" - " If we append one bit array to another the bit arrays must be copied to a\n" - " new location in memory so that they can sit together. This behaviour\n" - " enables efficient reading of the data but copying can be expensive,\n" - " especially if we want to join many bit arrays together.\n" - "\n" - " BytesTree is different in that it can be joined together in constant\n" - " time using minimal memory, and then can be efficiently converted to a\n" - " bit array using the `to_bit_array` function.\n" - "\n" - " Byte trees are always byte aligned, so that a number of bits that is not\n" - " divisible by 8 will be padded with 0s.\n" - "\n" - " On Erlang this type is compatible with Erlang's iolists.\n" -). - --opaque bytes_tree() :: {bytes, bitstring()} | - {text, gleam@string_tree:string_tree()} | - {many, list(bytes_tree())}. - --file("src/gleam/bytes_tree.gleam", 68). -?DOC( - " Appends a bytes tree onto the end of another.\n" - "\n" - " Runs in constant time.\n" -). --spec append_tree(bytes_tree(), bytes_tree()) -> bytes_tree(). -append_tree(First, Second) -> - gleam_stdlib:iodata_append(First, Second). - --file("src/gleam/bytes_tree.gleam", 59). -?DOC( - " Prepends a bytes tree onto the start of another.\n" - "\n" - " Runs in constant time.\n" -). --spec prepend_tree(bytes_tree(), bytes_tree()) -> bytes_tree(). -prepend_tree(Second, First) -> - gleam_stdlib:iodata_append(First, Second). - --file("src/gleam/bytes_tree.gleam", 98). -?DOC( - " Joins a list of bytes trees into a single one.\n" - "\n" - " Runs in constant time.\n" -). --spec concat(list(bytes_tree())) -> bytes_tree(). -concat(Trees) -> - gleam_stdlib:identity(Trees). - --file("src/gleam/bytes_tree.gleam", 35). -?DOC( - " Create an empty `BytesTree`. Useful as the start of a pipe chaining many\n" - " trees together.\n" -). --spec new() -> bytes_tree(). -new() -> - gleam_stdlib:identity([]). - --file("src/gleam/bytes_tree.gleam", 118). -?DOC( - " Creates a new bytes tree from a string.\n" - "\n" - " Runs in constant time when running on Erlang.\n" - " Runs in linear time otherwise.\n" -). --spec from_string(binary()) -> bytes_tree(). -from_string(String) -> - gleam_stdlib:wrap_list(String). - --file("src/gleam/bytes_tree.gleam", 80). -?DOC( - " Prepends a string onto the start of a bytes tree.\n" - "\n" - " Runs in constant time when running on Erlang.\n" - " Runs in linear time with the length of the string otherwise.\n" -). --spec prepend_string(bytes_tree(), binary()) -> bytes_tree(). -prepend_string(Second, First) -> - gleam_stdlib:iodata_append(gleam_stdlib:wrap_list(First), Second). - --file("src/gleam/bytes_tree.gleam", 89). -?DOC( - " Appends a string onto the end of a bytes tree.\n" - "\n" - " Runs in constant time when running on Erlang.\n" - " Runs in linear time with the length of the string otherwise.\n" -). --spec append_string(bytes_tree(), binary()) -> bytes_tree(). -append_string(First, Second) -> - gleam_stdlib:iodata_append(First, gleam_stdlib:wrap_list(Second)). - --file("src/gleam/bytes_tree.gleam", 128). -?DOC( - " Creates a new bytes tree from a string tree.\n" - "\n" - " Runs in constant time when running on Erlang.\n" - " Runs in linear time otherwise.\n" -). --spec from_string_tree(gleam@string_tree:string_tree()) -> bytes_tree(). -from_string_tree(Tree) -> - gleam_stdlib:wrap_list(Tree). - --file("src/gleam/bytes_tree.gleam", 136). -?DOC( - " Creates a new bytes tree from a bit array.\n" - "\n" - " Runs in constant time.\n" -). --spec from_bit_array(bitstring()) -> bytes_tree(). -from_bit_array(Bits) -> - _pipe = Bits, - _pipe@1 = gleam_stdlib:bit_array_pad_to_bytes(_pipe), - gleam_stdlib:wrap_list(_pipe@1). - --file("src/gleam/bytes_tree.gleam", 43). -?DOC( - " Prepends a bit array to the start of a bytes tree.\n" - "\n" - " Runs in constant time.\n" -). --spec prepend(bytes_tree(), bitstring()) -> bytes_tree(). -prepend(Second, First) -> - gleam_stdlib:iodata_append(from_bit_array(First), Second). - --file("src/gleam/bytes_tree.gleam", 51). -?DOC( - " Appends a bit array to the end of a bytes tree.\n" - "\n" - " Runs in constant time.\n" -). --spec append(bytes_tree(), bitstring()) -> bytes_tree(). -append(First, Second) -> - gleam_stdlib:iodata_append(First, from_bit_array(Second)). - --file("src/gleam/bytes_tree.gleam", 106). -?DOC( - " Joins a list of bit arrays into a single bytes tree.\n" - "\n" - " Runs in constant time.\n" -). --spec concat_bit_arrays(list(bitstring())) -> bytes_tree(). -concat_bit_arrays(Bits) -> - _pipe = Bits, - _pipe@1 = gleam@list:map(_pipe, fun from_bit_array/1), - gleam_stdlib:identity(_pipe@1). - --file("src/gleam/bytes_tree.gleam", 162). --spec to_list(list(list(bytes_tree())), list(bitstring())) -> list(bitstring()). -to_list(Stack, Acc) -> - case Stack of - [] -> - Acc; - - [[] | Remaining_stack] -> - to_list(Remaining_stack, Acc); - - [[{bytes, Bits} | Rest] | Remaining_stack@1] -> - to_list([Rest | Remaining_stack@1], [Bits | Acc]); - - [[{text, Tree} | Rest@1] | Remaining_stack@2] -> - Bits@1 = gleam_stdlib:identity(unicode:characters_to_binary(Tree)), - to_list([Rest@1 | Remaining_stack@2], [Bits@1 | Acc]); - - [[{many, Trees} | Rest@2] | Remaining_stack@3] -> - to_list([Trees, Rest@2 | Remaining_stack@3], Acc) - end. - --file("src/gleam/bytes_tree.gleam", 155). -?DOC( - " Turns a bytes tree into a bit array.\n" - "\n" - " Runs in linear time.\n" - "\n" - " When running on Erlang this function is implemented natively by the\n" - " virtual machine and is highly optimised.\n" -). --spec to_bit_array(bytes_tree()) -> bitstring(). -to_bit_array(Tree) -> - erlang:list_to_bitstring(Tree). - --file("src/gleam/bytes_tree.gleam", 186). -?DOC( - " Returns the size of the bytes tree's content in bytes.\n" - "\n" - " Runs in linear time.\n" -). --spec byte_size(bytes_tree()) -> integer(). -byte_size(Tree) -> - erlang:iolist_size(Tree). diff --git a/build/dev/javascript/gleam_stdlib/gleam@dict.erl b/build/dev/javascript/gleam_stdlib/gleam@dict.erl deleted file mode 100644 index d496afb..0000000 --- a/build/dev/javascript/gleam_stdlib/gleam@dict.erl +++ /dev/null @@ -1,561 +0,0 @@ --module(gleam@dict). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "src/gleam/dict.gleam"). --export([size/1, is_empty/1, to_list/1, new/0, get/2, has_key/2, insert/3, from_list/1, keys/1, values/1, take/2, merge/2, delete/2, drop/2, upsert/3, fold/3, map_values/2, filter/2, each/2, combine/3]). --export_type([dict/2]). - --if(?OTP_RELEASE >= 27). --define(MODULEDOC(Str), -moduledoc(Str)). --define(DOC(Str), -doc(Str)). --else. --define(MODULEDOC(Str), -compile([])). --define(DOC(Str), -compile([])). --endif. - --type dict(KG, KH) :: any() | {gleam_phantom, KG, KH}. - --file("src/gleam/dict.gleam", 36). -?DOC( - " Determines the number of key-value pairs in the dict.\n" - " This function runs in constant time and does not need to iterate the dict.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " new() |> size\n" - " // -> 0\n" - " ```\n" - "\n" - " ```gleam\n" - " new() |> insert(\"key\", \"value\") |> size\n" - " // -> 1\n" - " ```\n" -). --spec size(dict(any(), any())) -> integer(). -size(Dict) -> - maps:size(Dict). - --file("src/gleam/dict.gleam", 52). -?DOC( - " Determines whether or not the dict is empty.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " new() |> is_empty\n" - " // -> True\n" - " ```\n" - "\n" - " ```gleam\n" - " new() |> insert(\"b\", 1) |> is_empty\n" - " // -> False\n" - " ```\n" -). --spec is_empty(dict(any(), any())) -> boolean(). -is_empty(Dict) -> - maps:size(Dict) =:= 0. - --file("src/gleam/dict.gleam", 80). -?DOC( - " Converts the dict to a list of 2-element tuples `#(key, value)`, one for\n" - " each key-value pair in the dict.\n" - "\n" - " The tuples in the list have no specific order.\n" - "\n" - " ## Examples\n" - "\n" - " Calling `to_list` on an empty `dict` returns an empty list.\n" - "\n" - " ```gleam\n" - " new() |> to_list\n" - " // -> []\n" - " ```\n" - "\n" - " The ordering of elements in the resulting list is an implementation detail\n" - " that should not be relied upon.\n" - "\n" - " ```gleam\n" - " new() |> insert(\"b\", 1) |> insert(\"a\", 0) |> insert(\"c\", 2) |> to_list\n" - " // -> [#(\"a\", 0), #(\"b\", 1), #(\"c\", 2)]\n" - " ```\n" -). --spec to_list(dict(KQ, KR)) -> list({KQ, KR}). -to_list(Dict) -> - maps:to_list(Dict). - --file("src/gleam/dict.gleam", 129). -?DOC(" Creates a fresh dict that contains no values.\n"). --spec new() -> dict(any(), any()). -new() -> - maps:new(). - --file("src/gleam/dict.gleam", 150). -?DOC( - " Fetches a value from a dict for a given key.\n" - "\n" - " The dict may not have a value for the key, so the value is wrapped in a\n" - " `Result`.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " new() |> insert(\"a\", 0) |> get(\"a\")\n" - " // -> Ok(0)\n" - " ```\n" - "\n" - " ```gleam\n" - " new() |> insert(\"a\", 0) |> get(\"b\")\n" - " // -> Error(Nil)\n" - " ```\n" -). --spec get(dict(LT, LU), LT) -> {ok, LU} | {error, nil}. -get(From, Get) -> - gleam_stdlib:map_get(From, Get). - --file("src/gleam/dict.gleam", 116). -?DOC( - " Determines whether or not a value present in the dict for a given key.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " new() |> insert(\"a\", 0) |> has_key(\"a\")\n" - " // -> True\n" - " ```\n" - "\n" - " ```gleam\n" - " new() |> insert(\"a\", 0) |> has_key(\"b\")\n" - " // -> False\n" - " ```\n" -). --spec has_key(dict(LH, any()), LH) -> boolean(). -has_key(Dict, Key) -> - maps:is_key(Key, Dict). - --file("src/gleam/dict.gleam", 169). -?DOC( - " Inserts a value into the dict with the given key.\n" - "\n" - " If the dict already has a value for the given key then the value is\n" - " replaced with the new value.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " new() |> insert(\"a\", 0)\n" - " // -> from_list([#(\"a\", 0)])\n" - " ```\n" - "\n" - " ```gleam\n" - " new() |> insert(\"a\", 0) |> insert(\"a\", 5)\n" - " // -> from_list([#(\"a\", 5)])\n" - " ```\n" -). --spec insert(dict(LZ, MA), LZ, MA) -> dict(LZ, MA). -insert(Dict, Key, Value) -> - maps:put(Key, Value, Dict). - --file("src/gleam/dict.gleam", 92). --spec from_list_loop(list({LA, LB}), dict(LA, LB)) -> dict(LA, LB). -from_list_loop(List, Initial) -> - case List of - [] -> - Initial; - - [{Key, Value} | Rest] -> - from_list_loop(Rest, insert(Initial, Key, Value)) - end. - --file("src/gleam/dict.gleam", 88). -?DOC( - " Converts a list of 2-element tuples `#(key, value)` to a dict.\n" - "\n" - " If two tuples have the same key the last one in the list will be the one\n" - " that is present in the dict.\n" -). --spec from_list(list({KV, KW})) -> dict(KV, KW). -from_list(List) -> - maps:from_list(List). - --file("src/gleam/dict.gleam", 223). --spec reverse_and_concat(list(NJ), list(NJ)) -> list(NJ). -reverse_and_concat(Remaining, Accumulator) -> - case Remaining of - [] -> - Accumulator; - - [First | Rest] -> - reverse_and_concat(Rest, [First | Accumulator]) - end. - --file("src/gleam/dict.gleam", 216). --spec do_keys_loop(list({NE, any()}), list(NE)) -> list(NE). -do_keys_loop(List, Acc) -> - case List of - [] -> - reverse_and_concat(Acc, []); - - [{Key, _} | Rest] -> - do_keys_loop(Rest, [Key | Acc]) - end. - --file("src/gleam/dict.gleam", 212). -?DOC( - " Gets a list of all keys in a given dict.\n" - "\n" - " Dicts are not ordered so the keys are not returned in any specific order. Do\n" - " not write code that relies on the order keys are returned by this function\n" - " as it may change in later versions of Gleam or Erlang.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " from_list([#(\"a\", 0), #(\"b\", 1)]) |> keys\n" - " // -> [\"a\", \"b\"]\n" - " ```\n" -). --spec keys(dict(MZ, any())) -> list(MZ). -keys(Dict) -> - maps:keys(Dict). - --file("src/gleam/dict.gleam", 249). --spec do_values_loop(list({any(), NT}), list(NT)) -> list(NT). -do_values_loop(List, Acc) -> - case List of - [] -> - reverse_and_concat(Acc, []); - - [{_, Value} | Rest] -> - do_values_loop(Rest, [Value | Acc]) - end. - --file("src/gleam/dict.gleam", 244). -?DOC( - " Gets a list of all values in a given dict.\n" - "\n" - " Dicts are not ordered so the values are not returned in any specific order. Do\n" - " not write code that relies on the order values are returned by this function\n" - " as it may change in later versions of Gleam or Erlang.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " from_list([#(\"a\", 0), #(\"b\", 1)]) |> values\n" - " // -> [0, 1]\n" - " ```\n" -). --spec values(dict(any(), NO)) -> list(NO). -values(Dict) -> - maps:values(Dict). - --file("src/gleam/dict.gleam", 318). --spec do_take_loop(dict(OX, OY), list(OX), dict(OX, OY)) -> dict(OX, OY). -do_take_loop(Dict, Desired_keys, Acc) -> - Insert = fun(Taken, Key) -> case gleam_stdlib:map_get(Dict, Key) of - {ok, Value} -> - insert(Taken, Key, Value); - - {error, _} -> - Taken - end end, - case Desired_keys of - [] -> - Acc; - - [First | Rest] -> - do_take_loop(Dict, Rest, Insert(Acc, First)) - end. - --file("src/gleam/dict.gleam", 309). -?DOC( - " Creates a new dict from a given dict, only including any entries for which the\n" - " keys are in a given list.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " from_list([#(\"a\", 0), #(\"b\", 1)])\n" - " |> take([\"b\"])\n" - " // -> from_list([#(\"b\", 1)])\n" - " ```\n" - "\n" - " ```gleam\n" - " from_list([#(\"a\", 0), #(\"b\", 1)])\n" - " |> take([\"a\", \"b\", \"c\"])\n" - " // -> from_list([#(\"a\", 0), #(\"b\", 1)])\n" - " ```\n" -). --spec take(dict(OJ, OK), list(OJ)) -> dict(OJ, OK). -take(Dict, Desired_keys) -> - maps:with(Desired_keys, Dict). - --file("src/gleam/dict.gleam", 363). --spec insert_pair(dict(PV, PW), {PV, PW}) -> dict(PV, PW). -insert_pair(Dict, Pair) -> - insert(Dict, erlang:element(1, Pair), erlang:element(2, Pair)). - --file("src/gleam/dict.gleam", 356). --spec fold_inserts(list({PO, PP}), dict(PO, PP)) -> dict(PO, PP). -fold_inserts(New_entries, Dict) -> - case New_entries of - [] -> - Dict; - - [First | Rest] -> - fold_inserts(Rest, insert_pair(Dict, First)) - end. - --file("src/gleam/dict.gleam", 350). -?DOC( - " Creates a new dict from a pair of given dicts by combining their entries.\n" - "\n" - " If there are entries with the same keys in both dicts the entry from the\n" - " second dict takes precedence.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " let a = from_list([#(\"a\", 0), #(\"b\", 1)])\n" - " let b = from_list([#(\"b\", 2), #(\"c\", 3)])\n" - " merge(a, b)\n" - " // -> from_list([#(\"a\", 0), #(\"b\", 2), #(\"c\", 3)])\n" - " ```\n" -). --spec merge(dict(PG, PH), dict(PG, PH)) -> dict(PG, PH). -merge(Dict, New_entries) -> - maps:merge(Dict, New_entries). - --file("src/gleam/dict.gleam", 382). -?DOC( - " Creates a new dict from a given dict with all the same entries except for the\n" - " one with a given key, if it exists.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " from_list([#(\"a\", 0), #(\"b\", 1)]) |> delete(\"a\")\n" - " // -> from_list([#(\"b\", 1)])\n" - " ```\n" - "\n" - " ```gleam\n" - " from_list([#(\"a\", 0), #(\"b\", 1)]) |> delete(\"c\")\n" - " // -> from_list([#(\"a\", 0), #(\"b\", 1)])\n" - " ```\n" -). --spec delete(dict(QB, QC), QB) -> dict(QB, QC). -delete(Dict, Key) -> - maps:remove(Key, Dict). - --file("src/gleam/dict.gleam", 410). -?DOC( - " Creates a new dict from a given dict with all the same entries except any with\n" - " keys found in a given list.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " from_list([#(\"a\", 0), #(\"b\", 1)]) |> drop([\"a\"])\n" - " // -> from_list([#(\"b\", 1)])\n" - " ```\n" - "\n" - " ```gleam\n" - " from_list([#(\"a\", 0), #(\"b\", 1)]) |> drop([\"c\"])\n" - " // -> from_list([#(\"a\", 0), #(\"b\", 1)])\n" - " ```\n" - "\n" - " ```gleam\n" - " from_list([#(\"a\", 0), #(\"b\", 1)]) |> drop([\"a\", \"b\", \"c\"])\n" - " // -> from_list([])\n" - " ```\n" -). --spec drop(dict(QN, QO), list(QN)) -> dict(QN, QO). -drop(Dict, Disallowed_keys) -> - case Disallowed_keys of - [] -> - Dict; - - [First | Rest] -> - drop(delete(Dict, First), Rest) - end. - --file("src/gleam/dict.gleam", 440). -?DOC( - " Creates a new dict with one entry inserted or updated using a given function.\n" - "\n" - " If there was not an entry in the dict for the given key then the function\n" - " gets `None` as its argument, otherwise it gets `Some(value)`.\n" - "\n" - " ## Example\n" - "\n" - " ```gleam\n" - " let dict = from_list([#(\"a\", 0)])\n" - " let increment = fn(x) {\n" - " case x {\n" - " Some(i) -> i + 1\n" - " None -> 0\n" - " }\n" - " }\n" - "\n" - " upsert(dict, \"a\", increment)\n" - " // -> from_list([#(\"a\", 1)])\n" - "\n" - " upsert(dict, \"b\", increment)\n" - " // -> from_list([#(\"a\", 0), #(\"b\", 0)])\n" - " ```\n" -). --spec upsert(dict(QU, QV), QU, fun((gleam@option:option(QV)) -> QV)) -> dict(QU, QV). -upsert(Dict, Key, Fun) -> - case gleam_stdlib:map_get(Dict, Key) of - {ok, Value} -> - insert(Dict, Key, Fun({some, Value})); - - {error, _} -> - insert(Dict, Key, Fun(none)) - end. - --file("src/gleam/dict.gleam", 484). --spec fold_loop(list({RG, RH}), RJ, fun((RJ, RG, RH) -> RJ)) -> RJ. -fold_loop(List, Initial, Fun) -> - case List of - [] -> - Initial; - - [{K, V} | Rest] -> - fold_loop(Rest, Fun(Initial, K, V), Fun) - end. - --file("src/gleam/dict.gleam", 476). -?DOC( - " Combines all entries into a single value by calling a given function on each\n" - " one.\n" - "\n" - " Dicts are not ordered so the values are not returned in any specific order. Do\n" - " not write code that relies on the order entries are used by this function\n" - " as it may change in later versions of Gleam or Erlang.\n" - "\n" - " # Examples\n" - "\n" - " ```gleam\n" - " let dict = from_list([#(\"a\", 1), #(\"b\", 3), #(\"c\", 9)])\n" - " fold(dict, 0, fn(accumulator, key, value) { accumulator + value })\n" - " // -> 13\n" - " ```\n" - "\n" - " ```gleam\n" - " import gleam/string\n" - "\n" - " let dict = from_list([#(\"a\", 1), #(\"b\", 3), #(\"c\", 9)])\n" - " fold(dict, \"\", fn(accumulator, key, value) {\n" - " string.append(accumulator, key)\n" - " })\n" - " // -> \"abc\"\n" - " ```\n" -). --spec fold(dict(RB, RC), RF, fun((RF, RB, RC) -> RF)) -> RF. -fold(Dict, Initial, Fun) -> - fold_loop(maps:to_list(Dict), Initial, Fun). - --file("src/gleam/dict.gleam", 188). -?DOC( - " Updates all values in a given dict by calling a given function on each key\n" - " and value.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " from_list([#(3, 3), #(2, 4)])\n" - " |> map_values(fn(key, value) { key * value })\n" - " // -> from_list([#(3, 9), #(2, 8)])\n" - " ```\n" -). --spec map_values(dict(ML, MM), fun((ML, MM) -> MP)) -> dict(ML, MP). -map_values(Dict, Fun) -> - maps:map(Fun, Dict). - --file("src/gleam/dict.gleam", 273). -?DOC( - " Creates a new dict from a given dict, minus any entries that a given function\n" - " returns `False` for.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " from_list([#(\"a\", 0), #(\"b\", 1)])\n" - " |> filter(fn(key, value) { value != 0 })\n" - " // -> from_list([#(\"b\", 1)])\n" - " ```\n" - "\n" - " ```gleam\n" - " from_list([#(\"a\", 0), #(\"b\", 1)])\n" - " |> filter(fn(key, value) { True })\n" - " // -> from_list([#(\"a\", 0), #(\"b\", 1)])\n" - " ```\n" -). --spec filter(dict(NX, NY), fun((NX, NY) -> boolean())) -> dict(NX, NY). -filter(Dict, Predicate) -> - maps:filter(Predicate, Dict). - --file("src/gleam/dict.gleam", 517). -?DOC( - " Calls a function for each key and value in a dict, discarding the return\n" - " value.\n" - "\n" - " Useful for producing a side effect for every item of a dict.\n" - "\n" - " ```gleam\n" - " import gleam/io\n" - "\n" - " let dict = from_list([#(\"a\", \"apple\"), #(\"b\", \"banana\"), #(\"c\", \"cherry\")])\n" - "\n" - " each(dict, fn(k, v) {\n" - " io.println(key <> \" => \" <> value)\n" - " })\n" - " // -> Nil\n" - " // a => apple\n" - " // b => banana\n" - " // c => cherry\n" - " ```\n" - "\n" - " The order of elements in the iteration is an implementation detail that\n" - " should not be relied upon.\n" -). --spec each(dict(RK, RL), fun((RK, RL) -> any())) -> nil. -each(Dict, Fun) -> - fold( - Dict, - nil, - fun(Nil, K, V) -> - Fun(K, V), - Nil - end - ). - --file("src/gleam/dict.gleam", 538). -?DOC( - " Creates a new dict from a pair of given dicts by combining their entries.\n" - "\n" - " If there are entries with the same keys in both dicts the given function is\n" - " used to determine the new value to use in the resulting dict.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " let a = from_list([#(\"a\", 0), #(\"b\", 1)])\n" - " let b = from_list([#(\"a\", 2), #(\"c\", 3)])\n" - " combine(a, b, fn(one, other) { one + other })\n" - " // -> from_list([#(\"a\", 2), #(\"b\", 1), #(\"c\", 3)])\n" - " ```\n" -). --spec combine(dict(RP, RQ), dict(RP, RQ), fun((RQ, RQ) -> RQ)) -> dict(RP, RQ). -combine(Dict, Other, Fun) -> - fold( - Dict, - Other, - fun(Acc, Key, Value) -> case gleam_stdlib:map_get(Acc, Key) of - {ok, Other_value} -> - insert(Acc, Key, Fun(Value, Other_value)); - - {error, _} -> - insert(Acc, Key, Value) - end end - ). diff --git a/build/dev/javascript/gleam_stdlib/gleam@dynamic.erl b/build/dev/javascript/gleam_stdlib/gleam@dynamic.erl deleted file mode 100644 index f057ca2..0000000 --- a/build/dev/javascript/gleam_stdlib/gleam@dynamic.erl +++ /dev/null @@ -1,106 +0,0 @@ --module(gleam@dynamic). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "src/gleam/dynamic.gleam"). --export([classify/1, bool/1, string/1, float/1, int/1, bit_array/1, list/1, array/1, properties/1, nil/0]). --export_type([dynamic_/0]). - --if(?OTP_RELEASE >= 27). --define(MODULEDOC(Str), -moduledoc(Str)). --define(DOC(Str), -doc(Str)). --else. --define(MODULEDOC(Str), -compile([])). --define(DOC(Str), -compile([])). --endif. - --type dynamic_() :: any(). - --file("src/gleam/dynamic.gleam", 30). -?DOC( - " Return a string indicating the type of the dynamic value.\n" - "\n" - " This function may be useful for constructing error messages or logs. If you\n" - " want to turn dynamic data into well typed data then you want the\n" - " `gleam/dynamic/decode` module.\n" - "\n" - " ```gleam\n" - " classify(string(\"Hello\"))\n" - " // -> \"String\"\n" - " ```\n" -). --spec classify(dynamic_()) -> binary(). -classify(Data) -> - gleam_stdlib:classify_dynamic(Data). - --file("src/gleam/dynamic.gleam", 36). -?DOC(" Create a dynamic value from a bool.\n"). --spec bool(boolean()) -> dynamic_(). -bool(A) -> - gleam_stdlib:identity(A). - --file("src/gleam/dynamic.gleam", 44). -?DOC( - " Create a dynamic value from a string.\n" - "\n" - " On Erlang this will be a binary string rather than a character list.\n" -). --spec string(binary()) -> dynamic_(). -string(A) -> - gleam_stdlib:identity(A). - --file("src/gleam/dynamic.gleam", 50). -?DOC(" Create a dynamic value from a float.\n"). --spec float(float()) -> dynamic_(). -float(A) -> - gleam_stdlib:identity(A). - --file("src/gleam/dynamic.gleam", 56). -?DOC(" Create a dynamic value from an int.\n"). --spec int(integer()) -> dynamic_(). -int(A) -> - gleam_stdlib:identity(A). - --file("src/gleam/dynamic.gleam", 62). -?DOC(" Create a dynamic value from a bit array.\n"). --spec bit_array(bitstring()) -> dynamic_(). -bit_array(A) -> - gleam_stdlib:identity(A). - --file("src/gleam/dynamic.gleam", 68). -?DOC(" Create a dynamic value from a list.\n"). --spec list(list(dynamic_())) -> dynamic_(). -list(A) -> - gleam_stdlib:identity(A). - --file("src/gleam/dynamic.gleam", 77). -?DOC( - " Create a dynamic value from a list, converting it to a sequential runtime\n" - " format rather than the regular list format.\n" - "\n" - " On Erlang this will be a tuple, on JavaScript this will be an array.\n" -). --spec array(list(dynamic_())) -> dynamic_(). -array(A) -> - erlang:list_to_tuple(A). - --file("src/gleam/dynamic.gleam", 85). -?DOC( - " Create a dynamic value made an unordered series of keys and values, where\n" - " the keys are unique.\n" - "\n" - " On Erlang this will be a map, on JavaScript this will be a Gleam dict\n" - " object.\n" -). --spec properties(list({dynamic_(), dynamic_()})) -> dynamic_(). -properties(Entries) -> - gleam_stdlib:identity(maps:from_list(Entries)). - --file("src/gleam/dynamic.gleam", 94). -?DOC( - " A dynamic value representing nothing.\n" - "\n" - " On Erlang this will be the atom `nil`, on JavaScript this will be\n" - " `undefined`.\n" -). --spec nil() -> dynamic_(). -nil() -> - gleam_stdlib:identity(nil). diff --git a/build/dev/javascript/gleam_stdlib/gleam@dynamic@decode.erl b/build/dev/javascript/gleam_stdlib/gleam@dynamic@decode.erl deleted file mode 100644 index bf4b951..0000000 --- a/build/dev/javascript/gleam_stdlib/gleam@dynamic@decode.erl +++ /dev/null @@ -1,1088 +0,0 @@ --module(gleam@dynamic@decode). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "src/gleam/dynamic/decode.gleam"). --export([run/2, success/1, decode_dynamic/1, map/2, map_errors/2, then/2, one_of/2, recursive/1, optional/1, decode_error/2, decode_bool/1, decode_int/1, decode_float/1, decode_bit_array/1, collapse_errors/2, failure/2, new_primitive_decoder/2, decode_string/1, dict/2, list/1, subfield/3, at/2, field/3, optional_field/4, optionally_at/3]). --export_type([decode_error/0, decoder/1]). - --if(?OTP_RELEASE >= 27). --define(MODULEDOC(Str), -moduledoc(Str)). --define(DOC(Str), -doc(Str)). --else. --define(MODULEDOC(Str), -compile([])). --define(DOC(Str), -compile([])). --endif. - -?MODULEDOC( - " The `Dynamic` type is used to represent dynamically typed data. That is, data\n" - " that we don't know the precise type of yet, so we need to introspect the data to\n" - " see if it is of the desired type before we can use it. Typically data like this\n" - " would come from user input or from untyped languages such as Erlang or JavaScript.\n" - "\n" - " This module provides the `Decoder` type and associated functions, which provides\n" - " a type-safe and composable way to convert dynamic data into some desired type,\n" - " or into errors if the data doesn't have the desired structure.\n" - "\n" - " The `Decoder` type is generic and has 1 type parameter, which is the type that\n" - " it attempts to decode. A `Decoder(String)` can be used to decode strings, and a\n" - " `Decoder(Option(Int))` can be used to decode `Option(Int)`s\n" - "\n" - " Decoders work using _runtime reflection_ and the data structures of the target\n" - " platform. Differences between Erlang and JavaScript data structures may impact\n" - " your decoders, so it is important to test your decoders on all supported\n" - " platforms.\n" - "\n" - " The decoding technique used by this module was inspired by Juraj Petráš'\n" - " [Toy](https://github.com/Hackder/toy), Go's `encoding/json`, and Elm's\n" - " `Json.Decode`. Thank you to them!\n" - "\n" - " # Examples\n" - "\n" - " Dynamic data may come from various sources and so many different syntaxes could\n" - " be used to describe or construct them. In these examples a pseudocode\n" - " syntax is used to describe the data.\n" - "\n" - " ## Simple types\n" - "\n" - " This module defines decoders for simple data types such as [`string`](#string),\n" - " [`int`](#int), [`float`](#float), [`bit_array`](#bit_array), and [`bool`](#bool).\n" - "\n" - " ```gleam\n" - " // Data:\n" - " // \"Hello, Joe!\"\n" - "\n" - " let result = decode.run(data, decode.string)\n" - " assert result == Ok(\"Hello, Joe!\")\n" - " ```\n" - "\n" - " ## Lists\n" - "\n" - " The [`list`](#list) decoder decodes `List`s. To use it you must construct it by\n" - " passing in another decoder into the `list` function, which is the decoder that\n" - " is to be used for the elements of the list, type checking both the list and its\n" - " elements.\n" - "\n" - " ```gleam\n" - " // Data:\n" - " // [1, 2, 3, 4]\n" - "\n" - " let result = decode.run(data, decode.list(decode.int))\n" - " assert result == Ok([1, 2, 3, 4])\n" - " ```\n" - "\n" - " On Erlang this decoder can decode from lists, and on JavaScript it can\n" - " decode from lists as well as JavaScript arrays.\n" - "\n" - " ## Options\n" - "\n" - " The [`optional`](#optional) decoder is used to decode values that may or may not\n" - " be present. In other environment these might be called \"nullable\" values.\n" - "\n" - " Like the `list` decoder, the `optional` decoder takes another decoder,\n" - " which is used to decode the value if it is present.\n" - "\n" - " ```gleam\n" - " // Data:\n" - " // 12.45\n" - "\n" - " let result = decode.run(data, decode.optional(decode.float))\n" - " assert result == Ok(option.Some(12.45))\n" - " ```\n" - " ```gleam\n" - " // Data:\n" - " // null\n" - "\n" - " let result = decode.run(data, decode.optional(decode.int))\n" - " assert result == Ok(option.None)\n" - " ```\n" - "\n" - " This decoder knows how to handle multiple different runtime representations of\n" - " absent values, including `Nil`, `None`, `null`, and `undefined`.\n" - "\n" - " ## Dicts\n" - "\n" - " The [`dict`](#dict) decoder decodes `Dicts` and contains two other decoders, one\n" - " for the keys, one for the values.\n" - "\n" - " ```gleam\n" - " // Data:\n" - " // { \"Lucy\" -> 10, \"Nubi\" -> 20 }\n" - "\n" - " let result = decode.run(data, decode.dict(decode.string, decode.int))\n" - " assert result == Ok(dict.from_list([\n" - " #(\"Lucy\", 10),\n" - " #(\"Nubi\", 20),\n" - " ]))\n" - " ```\n" - "\n" - " ## Indexing objects\n" - "\n" - " The [`at`](#at) decoder can be used to decode a value that is nested within\n" - " key-value containers such as Gleam dicts, Erlang maps, or JavaScript objects.\n" - "\n" - " ```gleam\n" - " // Data:\n" - " // { \"one\" -> { \"two\" -> 123 } }\n" - "\n" - " let result = decode.run(data, decode.at([\"one\", \"two\"], decode.int))\n" - " assert result == Ok(123)\n" - " ```\n" - "\n" - " ## Indexing arrays\n" - "\n" - " If you use ints as keys then the [`at`](#at) decoder can be used to index into\n" - " array-like containers such as Gleam or Erlang tuples, or JavaScript arrays.\n" - "\n" - " ```gleam\n" - " // Data:\n" - " // [\"one\", \"two\", \"three\"]\n" - "\n" - " let result = decode.run(data, decode.at([1], decode.string))\n" - " assert result == Ok(\"two\")\n" - " ```\n" - "\n" - " ## Records\n" - "\n" - " Decoding records from dynamic data is more complex and requires combining a\n" - " decoder for each field and a special constructor that builds your records with\n" - " the decoded field values.\n" - "\n" - " ```gleam\n" - " // Data:\n" - " // {\n" - " // \"score\" -> 180,\n" - " // \"name\" -> \"Mel Smith\",\n" - " // \"is-admin\" -> false,\n" - " // \"enrolled\" -> true,\n" - " // \"colour\" -> \"Red\",\n" - " // }\n" - "\n" - " let decoder = {\n" - " use name <- decode.field(\"name\", decode.string)\n" - " use score <- decode.field(\"score\", decode.int)\n" - " use colour <- decode.field(\"colour\", decode.string)\n" - " use enrolled <- decode.field(\"enrolled\", decode.bool)\n" - " decode.success(Player(name:, score:, colour:, enrolled:))\n" - " }\n" - "\n" - " let result = decode.run(data, decoder)\n" - " assert result == Ok(Player(\"Mel Smith\", 180, \"Red\", True))\n" - " ```\n" - "\n" - " ## Enum variants\n" - "\n" - " Imagine you have a custom type where all the variants do not contain any values.\n" - "\n" - " ```gleam\n" - " pub type PocketMonsterType {\n" - " Fire\n" - " Water\n" - " Grass\n" - " Electric\n" - " }\n" - " ```\n" - "\n" - " You might choose to encode these variants as strings, `\"fire\"` for `Fire`,\n" - " `\"water\"` for `Water`, and so on. To decode them you'll need to decode the dynamic\n" - " data as a string, but then you'll need to decode it further still as not all\n" - " strings are valid values for the enum. This can be done with the `then`\n" - " function, which enables running a second decoder after the first one\n" - " succeeds.\n" - "\n" - " ```gleam\n" - " let decoder = {\n" - " use decoded_string <- decode.then(decode.string)\n" - " case decoded_string {\n" - " // Return succeeding decoders for valid strings\n" - " \"fire\" -> decode.success(Fire)\n" - " \"water\" -> decode.success(Water)\n" - " \"grass\" -> decode.success(Grass)\n" - " \"electric\" -> decode.success(Electric)\n" - " // Return a failing decoder for any other strings\n" - " _ -> decode.failure(Fire, \"PocketMonsterType\")\n" - " }\n" - " }\n" - "\n" - " let result = decode.run(dynamic.string(\"water\"), decoder)\n" - " assert result == Ok(Water)\n" - "\n" - " let result = decode.run(dynamic.string(\"wobble\"), decoder)\n" - " assert result == Error([DecodeError(\"PocketMonsterType\", \"String\", [])])\n" - " ```\n" - "\n" - " ## Record variants\n" - "\n" - " Decoding type variants that contain other values is done by combining the\n" - " techniques from the \"enum variants\" and \"records\" examples. Imagine you have\n" - " this custom type that you want to decode:\n" - "\n" - " ```gleam\n" - " pub type PocketMonsterPerson {\n" - " Trainer(name: String, badge_count: Int)\n" - " GymLeader(name: String, speciality: PocketMonsterType)\n" - " }\n" - " ```\n" - " And you would like to be able to decode these from dynamic data like this:\n" - " ```erlang\n" - " {\n" - " \"type\" -> \"trainer\",\n" - " \"name\" -> \"Ash\",\n" - " \"badge-count\" -> 1,\n" - " }\n" - " ```\n" - " ```erlang\n" - " {\n" - " \"type\" -> \"gym-leader\",\n" - " \"name\" -> \"Misty\",\n" - " \"speciality\" -> \"water\",\n" - " }\n" - " ```\n" - "\n" - " Notice how both documents have a `\"type\"` field, which is used to indicate which\n" - " variant the data is for.\n" - "\n" - " First, define decoders for each of the variants:\n" - "\n" - " ```gleam\n" - " let trainer_decoder = {\n" - " use name <- decode.field(\"name\", decode.string)\n" - " use badge_count <- decode.field(\"badge-count\", decode.int)\n" - " decode.success(Trainer(name, badge_count))\n" - " }\n" - "\n" - " let gym_leader_decoder = {\n" - " use name <- decode.field(\"name\", decode.string)\n" - " use speciality <- decode.field(\"speciality\", pocket_monster_type_decoder)\n" - " decode.success(GymLeader(name, speciality))\n" - " }\n" - " ```\n" - "\n" - " A third decoder can be used to extract and decode the `\"type\"` field, and the\n" - " expression can evaluate to whichever decoder is suitable for the document.\n" - "\n" - " ```gleam\n" - " // Data:\n" - " // {\n" - " // \"type\" -> \"gym-leader\",\n" - " // \"name\" -> \"Misty\",\n" - " // \"speciality\" -> \"water\",\n" - " // }\n" - "\n" - " let decoder = {\n" - " use tag <- decode.field(\"type\", decode.string)\n" - " case tag {\n" - " \"gym-leader\" -> gym_leader_decoder\n" - " _ -> trainer_decoder\n" - " }\n" - " }\n" - "\n" - " let result = decode.run(data, decoder)\n" - " assert result == Ok(GymLeader(\"Misty\", Water))\n" - " ```\n" -). - --type decode_error() :: {decode_error, binary(), binary(), list(binary())}. - --opaque decoder(BUW) :: {decoder, - fun((gleam@dynamic:dynamic_()) -> {BUW, list(decode_error())})}. - --file("src/gleam/dynamic/decode.gleam", 356). -?DOC( - " Run a decoder on a `Dynamic` value, decoding the value if it is of the\n" - " desired type, or returning errors.\n" - "\n" - " # Examples\n" - "\n" - " ```gleam\n" - " let decoder = {\n" - " use name <- decode.field(\"email\", decode.string)\n" - " use email <- decode.field(\"password\", decode.string)\n" - " decode.success(SignUp(name: name, email: email))\n" - " }\n" - "\n" - " decode.run(data, decoder)\n" - " ```\n" -). --spec run(gleam@dynamic:dynamic_(), decoder(BVE)) -> {ok, BVE} | - {error, list(decode_error())}. -run(Data, Decoder) -> - {Maybe_invalid_data, Errors} = (erlang:element(2, Decoder))(Data), - case Errors of - [] -> - {ok, Maybe_invalid_data}; - - [_ | _] -> - {error, Errors} - end. - --file("src/gleam/dynamic/decode.gleam", 479). -?DOC( - " Finalise a decoder having successfully extracted a value.\n" - "\n" - " # Examples\n" - "\n" - " ```gleam\n" - " let data = dynamic.properties([\n" - " #(dynamic.string(\"email\"), dynamic.string(\"lucy@example.com\")),\n" - " #(dynamic.string(\"name\"), dynamic.string(\"Lucy\")),\n" - " ]))\n" - "\n" - " let decoder = {\n" - " use name <- decode.field(\"name\", string)\n" - " use email <- decode.field(\"email\", string)\n" - " decode.success(SignUp(name: name, email: email))\n" - " }\n" - "\n" - " let result = decode.run(data, decoder)\n" - " assert result == Ok(SignUp(name: \"Lucy\", email: \"lucy@example.com\"))\n" - " ```\n" -). --spec success(BWF) -> decoder(BWF). -success(Data) -> - {decoder, fun(_) -> {Data, []} end}. - --file("src/gleam/dynamic/decode.gleam", 718). --spec decode_dynamic(gleam@dynamic:dynamic_()) -> {gleam@dynamic:dynamic_(), - list(decode_error())}. -decode_dynamic(Data) -> - {Data, []}. - --file("src/gleam/dynamic/decode.gleam", 875). -?DOC( - " Apply a transformation function to any value decoded by the decoder.\n" - "\n" - " # Examples\n" - "\n" - " ```gleam\n" - " let decoder = decode.int |> decode.map(int.to_string)\n" - " let result = decode.run(dynamic.int(1000), decoder)\n" - " assert result == Ok(\"1000\")\n" - " ```\n" -). --spec map(decoder(BZC), fun((BZC) -> BZE)) -> decoder(BZE). -map(Decoder, Transformer) -> - {decoder, - fun(D) -> - {Data, Errors} = (erlang:element(2, Decoder))(D), - {Transformer(Data), Errors} - end}. - --file("src/gleam/dynamic/decode.gleam", 884). -?DOC(" Apply a transformation function to any errors returned by the decoder.\n"). --spec map_errors( - decoder(BZG), - fun((list(decode_error())) -> list(decode_error())) -) -> decoder(BZG). -map_errors(Decoder, Transformer) -> - {decoder, - fun(D) -> - {Data, Errors} = (erlang:element(2, Decoder))(D), - {Data, Transformer(Errors)} - end}. - --file("src/gleam/dynamic/decode.gleam", 922). -?DOC( - " Create a new decoder based upon the value of a previous decoder.\n" - "\n" - " This may be useful to run one previous decoder to use in further decoding.\n" -). --spec then(decoder(BZO), fun((BZO) -> decoder(BZQ))) -> decoder(BZQ). -then(Decoder, Next) -> - {decoder, - fun(Dynamic_data) -> - {Data, Errors} = (erlang:element(2, Decoder))(Dynamic_data), - Decoder@1 = Next(Data), - {Data@1, _} = Layer = (erlang:element(2, Decoder@1))(Dynamic_data), - case Errors of - [] -> - Layer; - - [_ | _] -> - {Data@1, Errors} - end - end}. - --file("src/gleam/dynamic/decode.gleam", 965). --spec run_decoders( - gleam@dynamic:dynamic_(), - {BZY, list(decode_error())}, - list(decoder(BZY)) -) -> {BZY, list(decode_error())}. -run_decoders(Data, Failure, Decoders) -> - case Decoders of - [] -> - Failure; - - [Decoder | Decoders@1] -> - {_, Errors} = Layer = (erlang:element(2, Decoder))(Data), - case Errors of - [] -> - Layer; - - [_ | _] -> - run_decoders(Data, Failure, Decoders@1) - end - end. - --file("src/gleam/dynamic/decode.gleam", 952). -?DOC( - " Create a new decoder from several other decoders. Each of the inner\n" - " decoders is run in turn, and the value from the first to succeed is used.\n" - "\n" - " If no decoder succeeds then the errors from the first decoder is used.\n" - " If you wish for different errors then you may wish to use the\n" - " `collapse_errors` or `map_errors` functions.\n" - "\n" - " # Examples\n" - "\n" - " ```gleam\n" - " let decoder = decode.one_of(decode.string, or: [\n" - " decode.int |> decode.map(int.to_string),\n" - " decode.float |> decode.map(float.to_string),\n" - " ])\n" - " decode.run(dynamic.int(1000), decoder)\n" - " // -> Ok(\"1000\")\n" - " ```\n" -). --spec one_of(decoder(BZT), list(decoder(BZT))) -> decoder(BZT). -one_of(First, Alternatives) -> - {decoder, - fun(Dynamic_data) -> - {_, Errors} = Layer = (erlang:element(2, First))(Dynamic_data), - case Errors of - [] -> - Layer; - - [_ | _] -> - run_decoders(Dynamic_data, Layer, Alternatives) - end - end}. - --file("src/gleam/dynamic/decode.gleam", 1048). -?DOC( - " Create a decoder that can refer to itself, useful for decoding deeply\n" - " nested data.\n" - "\n" - " Attempting to create a recursive decoder without this function could result\n" - " in an infinite loop. If you are using `field` or other `use`able functions\n" - " then you may not need to use this function.\n" - "\n" - " ```gleam\n" - " type Nested {\n" - " Nested(List(Nested))\n" - " Value(String)\n" - " }\n" - "\n" - " fn nested_decoder() -> decode.Decoder(Nested) {\n" - " use <- decode.recursive\n" - " decode.one_of(decode.string |> decode.map(Value), [\n" - " decode.list(nested_decoder()) |> decode.map(Nested),\n" - " ])\n" - " }\n" - " ```\n" -). --spec recursive(fun(() -> decoder(CAJ))) -> decoder(CAJ). -recursive(Inner) -> - {decoder, - fun(Data) -> - Decoder = Inner(), - (erlang:element(2, Decoder))(Data) - end}. - --file("src/gleam/dynamic/decode.gleam", 853). -?DOC( - " A decoder that decodes nullable values of a type decoded by with a given\n" - " decoder.\n" - "\n" - " This function can handle common representations of null on all runtimes, such as\n" - " `nil`, `null`, and `undefined` on Erlang, and `undefined` and `null` on\n" - " JavaScript.\n" - "\n" - " # Examples\n" - "\n" - " ```gleam\n" - " let result = decode.run(dynamic.int(100), decode.optional(decode.int))\n" - " assert result == Ok(option.Some(100))\n" - " ```\n" - "\n" - " ```gleam\n" - " let result = decode.run(dynamic.nil(), decode.optional(decode.int))\n" - " assert result == Ok(option.None)\n" - " ```\n" -). --spec optional(decoder(BYY)) -> decoder(gleam@option:option(BYY)). -optional(Inner) -> - {decoder, fun(Data) -> case gleam_stdlib:is_null(Data) of - true -> - {none, []}; - - false -> - {Data@1, Errors} = (erlang:element(2, Inner))(Data), - {{some, Data@1}, Errors} - end end}. - --file("src/gleam/dynamic/decode.gleam", 485). -?DOC(" Construct a decode error for some unexpected dynamic data.\n"). --spec decode_error(binary(), gleam@dynamic:dynamic_()) -> list(decode_error()). -decode_error(Expected, Found) -> - [{decode_error, Expected, gleam_stdlib:classify_dynamic(Found), []}]. - --file("src/gleam/dynamic/decode.gleam", 609). --spec run_dynamic_function( - gleam@dynamic:dynamic_(), - binary(), - fun((gleam@dynamic:dynamic_()) -> {ok, BWZ} | {error, BWZ}) -) -> {BWZ, list(decode_error())}. -run_dynamic_function(Data, Name, F) -> - case F(Data) of - {ok, Data@1} -> - {Data@1, []}; - - {error, Zero} -> - {Zero, - [{decode_error, Name, gleam_stdlib:classify_dynamic(Data), []}]} - end. - --file("src/gleam/dynamic/decode.gleam", 658). --spec decode_bool(gleam@dynamic:dynamic_()) -> {boolean(), list(decode_error())}. -decode_bool(Data) -> - case gleam_stdlib:identity(true) =:= Data of - true -> - {true, []}; - - false -> - case gleam_stdlib:identity(false) =:= Data of - true -> - {false, []}; - - false -> - {false, decode_error(<<"Bool"/utf8>>, Data)} - end - end. - --file("src/gleam/dynamic/decode.gleam", 680). --spec decode_int(gleam@dynamic:dynamic_()) -> {integer(), list(decode_error())}. -decode_int(Data) -> - run_dynamic_function(Data, <<"Int"/utf8>>, fun gleam_stdlib:int/1). - --file("src/gleam/dynamic/decode.gleam", 699). --spec decode_float(gleam@dynamic:dynamic_()) -> {float(), list(decode_error())}. -decode_float(Data) -> - run_dynamic_function(Data, <<"Float"/utf8>>, fun gleam_stdlib:float/1). - --file("src/gleam/dynamic/decode.gleam", 733). --spec decode_bit_array(gleam@dynamic:dynamic_()) -> {bitstring(), - list(decode_error())}. -decode_bit_array(Data) -> - run_dynamic_function( - Data, - <<"BitArray"/utf8>>, - fun gleam_stdlib:bit_array/1 - ). - --file("src/gleam/dynamic/decode.gleam", 908). -?DOC( - " Replace all errors produced by a decoder with one single error for a named\n" - " expected type.\n" - "\n" - " This function may be useful if you wish to simplify errors before\n" - " presenting them to a user, particularly when using the `one_of` function.\n" - "\n" - " # Examples\n" - "\n" - " ```gleam\n" - " let decoder = decode.string |> decode.collapse_errors(\"MyThing\")\n" - " let result = decode.run(dynamic.int(1000), decoder)\n" - " assert result == Error([DecodeError(\"MyThing\", \"Int\", [])])\n" - " ```\n" -). --spec collapse_errors(decoder(BZL), binary()) -> decoder(BZL). -collapse_errors(Decoder, Name) -> - {decoder, - fun(Dynamic_data) -> - {Data, Errors} = Layer = (erlang:element(2, Decoder))(Dynamic_data), - case Errors of - [] -> - Layer; - - [_ | _] -> - {Data, decode_error(Name, Dynamic_data)} - end - end}. - --file("src/gleam/dynamic/decode.gleam", 986). -?DOC( - " Define a decoder that always fails. The parameter for this function is the\n" - " name of the type that has failed to decode.\n" -). --spec failure(CAD, binary()) -> decoder(CAD). -failure(Zero, Expected) -> - {decoder, fun(D) -> {Zero, decode_error(Expected, D)} end}. - --file("src/gleam/dynamic/decode.gleam", 1015). -?DOC( - " Create a decoder for a new data type from a decoding function.\n" - "\n" - " This function is used for new primitive types. For example, you might\n" - " define a decoder for Erlang's pid type.\n" - "\n" - " A default \"zero\" value is also required to make a decoder. When this\n" - " decoder is used as part of a larger decoder this zero value used as\n" - " a placeholder so that the rest of the decoder can continue to run and\n" - " collect all decoding errors.\n" - "\n" - " If you were to make a decoder for the `String` type (rather than using the\n" - " build-in `string` decoder) you would define it like so:\n" - "\n" - " ```gleam\n" - " pub fn string_decoder() -> decode.Decoder(String) {\n" - " let default = \"\"\n" - " decode.new_primitive_decoder(\"String\", fn(data) {\n" - " case dynamic.string(data) {\n" - " Ok(x) -> Ok(x)\n" - " Error(_) -> Error(default)\n" - " }\n" - " })\n" - " }\n" - " ```\n" -). --spec new_primitive_decoder( - binary(), - fun((gleam@dynamic:dynamic_()) -> {ok, CAF} | {error, CAF}) -) -> decoder(CAF). -new_primitive_decoder(Name, Decoding_function) -> - {decoder, fun(D) -> case Decoding_function(D) of - {ok, T} -> - {T, []}; - - {error, Zero} -> - {Zero, - [{decode_error, - Name, - gleam_stdlib:classify_dynamic(D), - []}]} - end end}. - --file("src/gleam/dynamic/decode.gleam", 636). --spec dynamic_string(gleam@dynamic:dynamic_()) -> {ok, binary()} | - {error, binary()}. -dynamic_string(Data) -> - case gleam_stdlib:bit_array(Data) of - {ok, Data@1} -> - case gleam@bit_array:to_string(Data@1) of - {ok, String} -> - {ok, String}; - - {error, _} -> - {error, <<""/utf8>>} - end; - - {error, _} -> - {error, <<""/utf8>>} - end. - --file("src/gleam/dynamic/decode.gleam", 631). --spec decode_string(gleam@dynamic:dynamic_()) -> {binary(), - list(decode_error())}. -decode_string(Data) -> - run_dynamic_function(Data, <<"String"/utf8>>, fun dynamic_string/1). - --file("src/gleam/dynamic/decode.gleam", 807). --spec fold_dict( - {gleam@dict:dict(BYK, BYL), list(decode_error())}, - gleam@dynamic:dynamic_(), - gleam@dynamic:dynamic_(), - fun((gleam@dynamic:dynamic_()) -> {BYK, list(decode_error())}), - fun((gleam@dynamic:dynamic_()) -> {BYL, list(decode_error())}) -) -> {gleam@dict:dict(BYK, BYL), list(decode_error())}. -fold_dict(Acc, Key, Value, Key_decoder, Value_decoder) -> - case Key_decoder(Key) of - {Key@1, []} -> - case Value_decoder(Value) of - {Value@1, []} -> - Dict = gleam@dict:insert( - erlang:element(1, Acc), - Key@1, - Value@1 - ), - {Dict, erlang:element(2, Acc)}; - - {_, Errors} -> - push_path({maps:new(), Errors}, [<<"values"/utf8>>]) - end; - - {_, Errors@1} -> - push_path({maps:new(), Errors@1}, [<<"keys"/utf8>>]) - end. - --file("src/gleam/dynamic/decode.gleam", 787). -?DOC( - " A decoder that decodes dicts where all keys and vales are decoded with\n" - " given decoders.\n" - "\n" - " # Examples\n" - "\n" - " ```gleam\n" - " let values = dynamic.properties([\n" - " #(dynamic.string(\"one\"), dynamic.int(1)),\n" - " #(dynamic.string(\"two\"), dynamic.int(2)),\n" - " ])\n" - "\n" - " let result =\n" - " decode.run(values, decode.dict(decode.string, decode.int))\n" - " assert result == Ok(values)\n" - " ```\n" -). --spec dict(decoder(BYD), decoder(BYF)) -> decoder(gleam@dict:dict(BYD, BYF)). -dict(Key, Value) -> - {decoder, fun(Data) -> case gleam_stdlib:dict(Data) of - {error, _} -> - {maps:new(), decode_error(<<"Dict"/utf8>>, Data)}; - - {ok, Dict} -> - gleam@dict:fold( - Dict, - {maps:new(), []}, - fun(A, K, V) -> case erlang:element(2, A) of - [] -> - fold_dict( - A, - K, - V, - erlang:element(2, Key), - erlang:element(2, Value) - ); - - [_ | _] -> - A - end end - ) - end end}. - --file("src/gleam/dynamic/decode.gleam", 755). -?DOC( - " A decoder that decodes lists where all elements are decoded with a given\n" - " decoder.\n" - "\n" - " # Examples\n" - "\n" - " ```gleam\n" - " let result =\n" - " [1, 2, 3]\n" - " |> list.map(dynamic.int)\n" - " |> dynamic.list\n" - " |> decode.run(decode.list(of: decode.int))\n" - " assert result == Ok([1, 2, 3])\n" - " ```\n" -). --spec list(decoder(BXR)) -> decoder(list(BXR)). -list(Inner) -> - {decoder, - fun(Data) -> - gleam_stdlib:list( - Data, - erlang:element(2, Inner), - fun(P, K) -> push_path(P, [K]) end, - 0, - [] - ) - end}. - --file("src/gleam/dynamic/decode.gleam", 439). --spec push_path({BWA, list(decode_error())}, list(any())) -> {BWA, - list(decode_error())}. -push_path(Layer, Path) -> - Decoder = one_of( - {decoder, fun decode_string/1}, - [begin - _pipe = {decoder, fun decode_int/1}, - map(_pipe, fun erlang:integer_to_binary/1) - end] - ), - Path@1 = gleam@list:map( - Path, - fun(Key) -> - Key@1 = gleam_stdlib:identity(Key), - case run(Key@1, Decoder) of - {ok, Key@2} -> - Key@2; - - {error, _} -> - <<<<"<"/utf8, - (gleam_stdlib:classify_dynamic(Key@1))/binary>>/binary, - ">"/utf8>> - end - end - ), - Errors = gleam@list:map( - erlang:element(2, Layer), - fun(Error) -> - {decode_error, - erlang:element(2, Error), - erlang:element(3, Error), - lists:append(Path@1, erlang:element(4, Error))} - end - ), - {erlang:element(1, Layer), Errors}. - --file("src/gleam/dynamic/decode.gleam", 403). --spec index( - list(BVO), - list(BVO), - fun((gleam@dynamic:dynamic_()) -> {BVR, list(decode_error())}), - gleam@dynamic:dynamic_(), - fun((gleam@dynamic:dynamic_(), list(BVO)) -> {BVR, list(decode_error())}) -) -> {BVR, list(decode_error())}. -index(Path, Position, Inner, Data, Handle_miss) -> - case Path of - [] -> - _pipe = Data, - _pipe@1 = Inner(_pipe), - push_path(_pipe@1, lists:reverse(Position)); - - [Key | Path@1] -> - case gleam_stdlib:index(Data, Key) of - {ok, {some, Data@1}} -> - index(Path@1, [Key | Position], Inner, Data@1, Handle_miss); - - {ok, none} -> - Handle_miss(Data, [Key | Position]); - - {error, Kind} -> - {Default, _} = Inner(Data), - _pipe@2 = {Default, - [{decode_error, - Kind, - gleam_stdlib:classify_dynamic(Data), - []}]}, - push_path(_pipe@2, lists:reverse(Position)) - end - end. - --file("src/gleam/dynamic/decode.gleam", 324). -?DOC( - " The same as [`field`](#field), except taking a path to the value rather\n" - " than a field name.\n" - "\n" - " This function will index into dictionaries with any key type, and if the key is\n" - " an int then it'll also index into Erlang tuples and JavaScript arrays, and\n" - " the first eight elements of Gleam lists.\n" - "\n" - " # Examples\n" - "\n" - " ```gleam\n" - " let data = dynamic.properties([\n" - " #(dynamic.string(\"data\"), dynamic.properties([\n" - " #(dynamic.string(\"email\"), dynamic.string(\"lucy@example.com\")),\n" - " #(dynamic.string(\"name\"), dynamic.string(\"Lucy\")),\n" - " ])\n" - " ]))\n" - "\n" - " let decoder = {\n" - " use name <- decode.subfield([\"data\", \"name\"], decode.string)\n" - " use email <- decode.subfield([\"data\", \"email\"], decode.string)\n" - " decode.success(SignUp(name: name, email: email))\n" - " }\n" - " let result = decode.run(data, decoder)\n" - " assert result == Ok(SignUp(name: \"Lucy\", email: \"lucy@example.com\"))\n" - " ```\n" -). --spec subfield(list(any()), decoder(BUZ), fun((BUZ) -> decoder(BVB))) -> decoder(BVB). -subfield(Field_path, Field_decoder, Next) -> - {decoder, - fun(Data) -> - {Out, Errors1} = index( - Field_path, - [], - erlang:element(2, Field_decoder), - Data, - fun(Data@1, Position) -> - {Default, _} = (erlang:element(2, Field_decoder))(Data@1), - _pipe = {Default, - [{decode_error, - <<"Field"/utf8>>, - <<"Nothing"/utf8>>, - []}]}, - push_path(_pipe, lists:reverse(Position)) - end - ), - {Out@1, Errors2} = (erlang:element(2, Next(Out)))(Data), - {Out@1, lists:append(Errors1, Errors2)} - end}. - --file("src/gleam/dynamic/decode.gleam", 393). -?DOC( - " A decoder that decodes a value that is nested within other values. For\n" - " example, decoding a value that is within some deeply nested JSON objects.\n" - "\n" - " This function will index into dictionaries with any key type, and if the key is\n" - " an int then it'll also index into Erlang tuples and JavaScript arrays, and\n" - " the first eight elements of Gleam lists.\n" - "\n" - " # Examples\n" - "\n" - " ```gleam\n" - " let decoder = decode.at([\"one\", \"two\"], decode.int)\n" - "\n" - " let data = dynamic.properties([\n" - " #(dynamic.string(\"one\"), dynamic.properties([\n" - " #(dynamic.string(\"two\"), dynamic.int(1000)),\n" - " ])),\n" - " ]))\n" - "\n" - "\n" - " decode.run(data, decoder)\n" - " // -> Ok(1000)\n" - " ```\n" - "\n" - " ```gleam\n" - " dynamic.nil()\n" - " |> decode.run(decode.optional(decode.int))\n" - " // -> Ok(option.None)\n" - " ```\n" -). --spec at(list(any()), decoder(BVL)) -> decoder(BVL). -at(Path, Inner) -> - {decoder, - fun(Data) -> - index( - Path, - [], - erlang:element(2, Inner), - Data, - fun(Data@1, Position) -> - {Default, _} = (erlang:element(2, Inner))(Data@1), - _pipe = {Default, - [{decode_error, - <<"Field"/utf8>>, - <<"Nothing"/utf8>>, - []}]}, - push_path(_pipe, lists:reverse(Position)) - end - ) - end}. - --file("src/gleam/dynamic/decode.gleam", 524). -?DOC( - " Run a decoder on a field of a `Dynamic` value, decoding the value if it is\n" - " of the desired type, or returning errors. An error is returned if there is\n" - " no field for the specified key.\n" - "\n" - " This function will index into dictionaries with any key type, and if the key is\n" - " an int then it'll also index into Erlang tuples and JavaScript arrays, and\n" - " the first eight elements of Gleam lists.\n" - "\n" - " # Examples\n" - "\n" - " ```gleam\n" - " let data = dynamic.properties([\n" - " #(dynamic.string(\"email\"), dynamic.string(\"lucy@example.com\")),\n" - " #(dynamic.string(\"name\"), dynamic.string(\"Lucy\")),\n" - " ]))\n" - "\n" - " let decoder = {\n" - " use name <- decode.field(\"name\", string)\n" - " use email <- decode.field(\"email\", string)\n" - " decode.success(SignUp(name: name, email: email))\n" - " }\n" - "\n" - " let result = decode.run(data, decoder)\n" - " assert result == Ok(SignUp(name: \"Lucy\", email: \"lucy@example.com\"))\n" - " ```\n" - "\n" - " If you wish to decode a value that is more deeply nested within the dynamic\n" - " data, see [`subfield`](#subfield) and [`at`](#at).\n" - "\n" - " If you wish to return a default in the event that a field is not present,\n" - " see [`optional_field`](#optional_field) and / [`optionally_at`](#optionally_at).\n" -). --spec field(any(), decoder(BWJ), fun((BWJ) -> decoder(BWL))) -> decoder(BWL). -field(Field_name, Field_decoder, Next) -> - subfield([Field_name], Field_decoder, Next). - --file("src/gleam/dynamic/decode.gleam", 557). -?DOC( - " Run a decoder on a field of a `Dynamic` value, decoding the value if it is\n" - " of the desired type, or returning errors. The given default value is\n" - " returned if there is no field for the specified key.\n" - "\n" - " This function will index into dictionaries with any key type, and if the key is\n" - " an int then it'll also index into Erlang tuples and JavaScript arrays, and\n" - " the first eight elements of Gleam lists.\n" - "\n" - " # Examples\n" - "\n" - " ```gleam\n" - " let data = dynamic.properties([\n" - " #(dynamic.string(\"name\"), dynamic.string(\"Lucy\")),\n" - " ]))\n" - "\n" - " let decoder = {\n" - " use name <- decode.field(\"name\", string)\n" - " use email <- decode.optional_field(\"email\", \"n/a\", string)\n" - " decode.success(SignUp(name: name, email: email))\n" - " }\n" - "\n" - " let result = decode.run(data, decoder)\n" - " assert result == Ok(SignUp(name: \"Lucy\", email: \"n/a\"))\n" - " ```\n" -). --spec optional_field(any(), BWP, decoder(BWP), fun((BWP) -> decoder(BWR))) -> decoder(BWR). -optional_field(Key, Default, Field_decoder, Next) -> - {decoder, - fun(Data) -> - {Out, Errors1} = begin - _pipe = case gleam_stdlib:index(Data, Key) of - {ok, {some, Data@1}} -> - (erlang:element(2, Field_decoder))(Data@1); - - {ok, none} -> - {Default, []}; - - {error, Kind} -> - {Default, - [{decode_error, - Kind, - gleam_stdlib:classify_dynamic(Data), - []}]} - end, - push_path(_pipe, [Key]) - end, - {Out@1, Errors2} = (erlang:element(2, Next(Out)))(Data), - {Out@1, lists:append(Errors1, Errors2)} - end}. - --file("src/gleam/dynamic/decode.gleam", 599). -?DOC( - " A decoder that decodes a value that is nested within other values. For\n" - " example, decoding a value that is within some deeply nested JSON objects.\n" - "\n" - " This function will index into dictionaries with any key type, and if the key is\n" - " an int then it'll also index into Erlang tuples and JavaScript arrays, and\n" - " the first eight elements of Gleam lists.\n" - "\n" - " # Examples\n" - "\n" - " ```gleam\n" - " let decoder = decode.optionally_at([\"one\", \"two\"], 100, decode.int)\n" - "\n" - " let data = dynamic.properties([\n" - " #(dynamic.string(\"one\"), dynamic.properties([])),\n" - " ]))\n" - "\n" - "\n" - " decode.run(data, decoder)\n" - " // -> Ok(100)\n" - " ```\n" -). --spec optionally_at(list(any()), BWW, decoder(BWW)) -> decoder(BWW). -optionally_at(Path, Default, Inner) -> - {decoder, - fun(Data) -> - index( - Path, - [], - erlang:element(2, Inner), - Data, - fun(_, _) -> {Default, []} end - ) - end}. diff --git a/build/dev/javascript/gleam_stdlib/gleam@float.erl b/build/dev/javascript/gleam_stdlib/gleam@float.erl deleted file mode 100644 index 6b55b47..0000000 --- a/build/dev/javascript/gleam_stdlib/gleam@float.erl +++ /dev/null @@ -1,744 +0,0 @@ --module(gleam@float). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "src/gleam/float.gleam"). --export([parse/1, to_string/1, compare/2, min/2, max/2, clamp/3, ceiling/1, floor/1, truncate/1, absolute_value/1, loosely_compare/3, loosely_equals/3, power/2, square_root/1, negate/1, round/1, to_precision/2, sum/1, product/1, random/0, modulo/2, divide/2, add/2, multiply/2, subtract/2, logarithm/1, exponential/1]). - --if(?OTP_RELEASE >= 27). --define(MODULEDOC(Str), -moduledoc(Str)). --define(DOC(Str), -doc(Str)). --else. --define(MODULEDOC(Str), -compile([])). --define(DOC(Str), -compile([])). --endif. - -?MODULEDOC( - " Functions for working with floats.\n" - "\n" - " ## Float representation\n" - "\n" - " Floats are represented as 64 bit floating point numbers on both the Erlang\n" - " and JavaScript runtimes. The floating point behaviour is native to their\n" - " respective runtimes, so their exact behaviour will be slightly different on\n" - " the two runtimes.\n" - "\n" - " ### Infinity and NaN\n" - "\n" - " Under the JavaScript runtime, exceeding the maximum (or minimum)\n" - " representable value for a floating point value will result in Infinity (or\n" - " -Infinity). Should you try to divide two infinities you will get NaN as a\n" - " result.\n" - "\n" - " When running on BEAM, exceeding the maximum (or minimum) representable\n" - " value for a floating point value will raise an error.\n" - "\n" - " ## Division by zero\n" - "\n" - " Gleam runs on the Erlang virtual machine, which does not follow the IEEE\n" - " 754 standard for floating point arithmetic and does not have an `Infinity`\n" - " value. In Erlang division by zero results in a crash, however Gleam does\n" - " not have partial functions and operators in core so instead division by zero\n" - " returns zero, a behaviour taken from Pony, Coq, and Lean.\n" - "\n" - " This may seem unexpected at first, but it is no less mathematically valid\n" - " than crashing or returning a special value. Division by zero is undefined\n" - " in mathematics.\n" -). - --file("src/gleam/float.gleam", 51). -?DOC( - " Attempts to parse a string as a `Float`, returning `Error(Nil)` if it was\n" - " not possible.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " parse(\"2.3\")\n" - " // -> Ok(2.3)\n" - " ```\n" - "\n" - " ```gleam\n" - " parse(\"ABC\")\n" - " // -> Error(Nil)\n" - " ```\n" -). --spec parse(binary()) -> {ok, float()} | {error, nil}. -parse(String) -> - gleam_stdlib:parse_float(String). - --file("src/gleam/float.gleam", 64). -?DOC( - " Returns the string representation of the provided `Float`.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " to_string(2.3)\n" - " // -> \"2.3\"\n" - " ```\n" -). --spec to_string(float()) -> binary(). -to_string(X) -> - gleam_stdlib:float_to_string(X). - --file("src/gleam/float.gleam", 95). -?DOC( - " Compares two `Float`s, returning an `Order`:\n" - " `Lt` for lower than, `Eq` for equals, or `Gt` for greater than.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " compare(2.0, 2.3)\n" - " // -> Lt\n" - " ```\n" - "\n" - " To handle\n" - " [Floating Point Imprecision](https://en.wikipedia.org/wiki/Floating-point_arithmetic#Accuracy_problems)\n" - " you may use [`loosely_compare`](#loosely_compare) instead.\n" -). --spec compare(float(), float()) -> gleam@order:order(). -compare(A, B) -> - case A =:= B of - true -> - eq; - - false -> - case A < B of - true -> - lt; - - false -> - gt - end - end. - --file("src/gleam/float.gleam", 176). -?DOC( - " Compares two `Float`s, returning the smaller of the two.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " min(2.0, 2.3)\n" - " // -> 2.0\n" - " ```\n" -). --spec min(float(), float()) -> float(). -min(A, B) -> - case A < B of - true -> - A; - - false -> - B - end. - --file("src/gleam/float.gleam", 192). -?DOC( - " Compares two `Float`s, returning the larger of the two.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " max(2.0, 2.3)\n" - " // -> 2.3\n" - " ```\n" -). --spec max(float(), float()) -> float(). -max(A, B) -> - case A > B of - true -> - A; - - false -> - B - end. - --file("src/gleam/float.gleam", 75). -?DOC( - " Restricts a `Float` between a lower and upper bound.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " clamp(1.2, min: 1.4, max: 1.6)\n" - " // -> 1.4\n" - " ```\n" -). --spec clamp(float(), float(), float()) -> float(). -clamp(X, Min_bound, Max_bound) -> - _pipe = X, - _pipe@1 = min(_pipe, Max_bound), - max(_pipe@1, Min_bound). - --file("src/gleam/float.gleam", 210). -?DOC( - " Rounds the value to the next highest whole number as a `Float`.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " ceiling(2.3)\n" - " // -> 3.0\n" - " ```\n" -). --spec ceiling(float()) -> float(). -ceiling(X) -> - math:ceil(X). - --file("src/gleam/float.gleam", 223). -?DOC( - " Rounds the value to the next lowest whole number as a `Float`.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " floor(2.3)\n" - " // -> 2.0\n" - " ```\n" -). --spec floor(float()) -> float(). -floor(X) -> - math:floor(X). - --file("src/gleam/float.gleam", 261). -?DOC( - " Returns the value as an `Int`, truncating all decimal digits.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " truncate(2.4343434847383438)\n" - " // -> 2\n" - " ```\n" -). --spec truncate(float()) -> integer(). -truncate(X) -> - erlang:trunc(X). - --file("src/gleam/float.gleam", 311). -?DOC( - " Returns the absolute value of the input as a `Float`.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " absolute_value(-12.5)\n" - " // -> 12.5\n" - " ```\n" - "\n" - " ```gleam\n" - " absolute_value(10.2)\n" - " // -> 10.2\n" - " ```\n" -). --spec absolute_value(float()) -> float(). -absolute_value(X) -> - case X >= +0.0 of - true -> - X; - - false -> - +0.0 - X - end. - --file("src/gleam/float.gleam", 125). -?DOC( - " Compares two `Float`s within a tolerance, returning an `Order`:\n" - " `Lt` for lower than, `Eq` for equals, or `Gt` for greater than.\n" - "\n" - " This function allows Float comparison while handling\n" - " [Floating Point Imprecision](https://en.wikipedia.org/wiki/Floating-point_arithmetic#Accuracy_problems).\n" - "\n" - " Notice: For `Float`s the tolerance won't be exact:\n" - " `5.3 - 5.0` is not exactly `0.3`.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " loosely_compare(5.0, with: 5.3, tolerating: 0.5)\n" - " // -> Eq\n" - " ```\n" - "\n" - " If you want to check only for equality you may use\n" - " [`loosely_equals`](#loosely_equals) instead.\n" -). --spec loosely_compare(float(), float(), float()) -> gleam@order:order(). -loosely_compare(A, B, Tolerance) -> - Difference = absolute_value(A - B), - case Difference =< Tolerance of - true -> - eq; - - false -> - compare(A, B) - end. - --file("src/gleam/float.gleam", 158). -?DOC( - " Checks for equality of two `Float`s within a tolerance,\n" - " returning an `Bool`.\n" - "\n" - " This function allows Float comparison while handling\n" - " [Floating Point Imprecision](https://en.wikipedia.org/wiki/Floating-point_arithmetic#Accuracy_problems).\n" - "\n" - " Notice: For `Float`s the tolerance won't be exact:\n" - " `5.3 - 5.0` is not exactly `0.3`.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " loosely_equals(5.0, with: 5.3, tolerating: 0.5)\n" - " // -> True\n" - " ```\n" - "\n" - " ```gleam\n" - " loosely_equals(5.0, with: 5.1, tolerating: 0.1)\n" - " // -> False\n" - " ```\n" -). --spec loosely_equals(float(), float(), float()) -> boolean(). -loosely_equals(A, B, Tolerance) -> - Difference = absolute_value(A - B), - Difference =< Tolerance. - --file("src/gleam/float.gleam", 348). -?DOC( - " Returns the results of the base being raised to the power of the\n" - " exponent, as a `Float`.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " power(2.0, -1.0)\n" - " // -> Ok(0.5)\n" - " ```\n" - "\n" - " ```gleam\n" - " power(2.0, 2.0)\n" - " // -> Ok(4.0)\n" - " ```\n" - "\n" - " ```gleam\n" - " power(8.0, 1.5)\n" - " // -> Ok(22.627416997969522)\n" - " ```\n" - "\n" - " ```gleam\n" - " 4.0 |> power(of: 2.0)\n" - " // -> Ok(16.0)\n" - " ```\n" - "\n" - " ```gleam\n" - " power(-1.0, 0.5)\n" - " // -> Error(Nil)\n" - " ```\n" -). --spec power(float(), float()) -> {ok, float()} | {error, nil}. -power(Base, Exponent) -> - Fractional = (math:ceil(Exponent) - Exponent) > +0.0, - case ((Base < +0.0) andalso Fractional) orelse ((Base =:= +0.0) andalso (Exponent - < +0.0)) of - true -> - {error, nil}; - - false -> - {ok, math:pow(Base, Exponent)} - end. - --file("src/gleam/float.gleam", 380). -?DOC( - " Returns the square root of the input as a `Float`.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " square_root(4.0)\n" - " // -> Ok(2.0)\n" - " ```\n" - "\n" - " ```gleam\n" - " square_root(-16.0)\n" - " // -> Error(Nil)\n" - " ```\n" -). --spec square_root(float()) -> {ok, float()} | {error, nil}. -square_root(X) -> - power(X, 0.5). - --file("src/gleam/float.gleam", 393). -?DOC( - " Returns the negative of the value provided.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " negate(1.0)\n" - " // -> -1.0\n" - " ```\n" -). --spec negate(float()) -> float(). -negate(X) -> - -1.0 * X. - --file("src/gleam/float.gleam", 240). -?DOC( - " Rounds the value to the nearest whole number as an `Int`.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " round(2.3)\n" - " // -> 2\n" - " ```\n" - "\n" - " ```gleam\n" - " round(2.5)\n" - " // -> 3\n" - " ```\n" -). --spec round(float()) -> integer(). -round(X) -> - erlang:round(X). - --file("src/gleam/float.gleam", 280). -?DOC( - " Converts the value to a given precision as a `Float`.\n" - " The precision is the number of allowed decimal places.\n" - " Negative precisions are allowed and force rounding\n" - " to the nearest tenth, hundredth, thousandth etc.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " to_precision(2.43434348473, precision: 2)\n" - " // -> 2.43\n" - " ```\n" - "\n" - " ```gleam\n" - " to_precision(547890.453444, precision: -3)\n" - " // -> 548000.0\n" - " ```\n" -). --spec to_precision(float(), integer()) -> float(). -to_precision(X, Precision) -> - case Precision =< 0 of - true -> - Factor = math:pow(10.0, erlang:float(- Precision)), - erlang:float(erlang:round(case Factor of - +0.0 -> +0.0; - -0.0 -> -0.0; - Gleam@denominator -> X / Gleam@denominator - end)) * Factor; - - false -> - Factor@1 = math:pow(10.0, erlang:float(Precision)), - case Factor@1 of - +0.0 -> +0.0; - -0.0 -> -0.0; - Gleam@denominator@1 -> erlang:float(erlang:round(X * Factor@1)) - / Gleam@denominator@1 - end - end. - --file("src/gleam/float.gleam", 410). --spec sum_loop(list(float()), float()) -> float(). -sum_loop(Numbers, Initial) -> - case Numbers of - [First | Rest] -> - sum_loop(Rest, First + Initial); - - [] -> - Initial - end. - --file("src/gleam/float.gleam", 406). -?DOC( - " Sums a list of `Float`s.\n" - "\n" - " ## Example\n" - "\n" - " ```gleam\n" - " sum([1.0, 2.2, 3.3])\n" - " // -> 6.5\n" - " ```\n" -). --spec sum(list(float())) -> float(). -sum(Numbers) -> - sum_loop(Numbers, +0.0). - --file("src/gleam/float.gleam", 430). --spec product_loop(list(float()), float()) -> float(). -product_loop(Numbers, Initial) -> - case Numbers of - [First | Rest] -> - product_loop(Rest, First * Initial); - - [] -> - Initial - end. - --file("src/gleam/float.gleam", 426). -?DOC( - " Multiplies a list of `Float`s and returns the product.\n" - "\n" - " ## Example\n" - "\n" - " ```gleam\n" - " product([2.5, 3.2, 4.2])\n" - " // -> 33.6\n" - " ```\n" -). --spec product(list(float())) -> float(). -product(Numbers) -> - product_loop(Numbers, 1.0). - --file("src/gleam/float.gleam", 452). -?DOC( - " Generates a random float between the given zero (inclusive) and one\n" - " (exclusive).\n" - "\n" - " On Erlang this updates the random state in the process dictionary.\n" - " See: \n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " random()\n" - " // -> 0.646355926896028\n" - " ```\n" -). --spec random() -> float(). -random() -> - rand:uniform(). - --file("src/gleam/float.gleam", 481). -?DOC( - " Computes the modulo of an float division of inputs as a `Result`.\n" - "\n" - " Returns division of the inputs as a `Result`: If the given divisor equals\n" - " `0`, this function returns an `Error`.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " modulo(13.3, by: 3.3)\n" - " // -> Ok(0.1)\n" - " ```\n" - "\n" - " ```gleam\n" - " modulo(-13.3, by: 3.3)\n" - " // -> Ok(3.2)\n" - " ```\n" - "\n" - " ```gleam\n" - " modulo(13.3, by: -3.3)\n" - " // -> Ok(-3.2)\n" - " ```\n" - "\n" - " ```gleam\n" - " modulo(-13.3, by: -3.3)\n" - " // -> Ok(-0.1)\n" - " ```\n" -). --spec modulo(float(), float()) -> {ok, float()} | {error, nil}. -modulo(Dividend, Divisor) -> - case Divisor of - +0.0 -> - {error, nil}; - - _ -> - {ok, Dividend - (math:floor(case Divisor of - +0.0 -> +0.0; - -0.0 -> -0.0; - Gleam@denominator -> Dividend / Gleam@denominator - end) * Divisor)} - end. - --file("src/gleam/float.gleam", 502). -?DOC( - " Returns division of the inputs as a `Result`.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " divide(0.0, 1.0)\n" - " // -> Ok(0.0)\n" - " ```\n" - "\n" - " ```gleam\n" - " divide(1.0, 0.0)\n" - " // -> Error(Nil)\n" - " ```\n" -). --spec divide(float(), float()) -> {ok, float()} | {error, nil}. -divide(A, B) -> - case B of - +0.0 -> - {error, nil}; - - B@1 -> - {ok, case B@1 of - +0.0 -> +0.0; - -0.0 -> -0.0; - Gleam@denominator -> A / Gleam@denominator - end} - end. - --file("src/gleam/float.gleam", 533). -?DOC( - " Adds two floats together.\n" - "\n" - " It's the function equivalent of the `+.` operator.\n" - " This function is useful in higher order functions or pipes.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " add(1.0, 2.0)\n" - " // -> 3.0\n" - " ```\n" - "\n" - " ```gleam\n" - " import gleam/list\n" - "\n" - " list.fold([1.0, 2.0, 3.0], 0.0, add)\n" - " // -> 6.0\n" - " ```\n" - "\n" - " ```gleam\n" - " 3.0 |> add(2.0)\n" - " // -> 5.0\n" - " ```\n" -). --spec add(float(), float()) -> float(). -add(A, B) -> - A + B. - --file("src/gleam/float.gleam", 561). -?DOC( - " Multiplies two floats together.\n" - "\n" - " It's the function equivalent of the `*.` operator.\n" - " This function is useful in higher order functions or pipes.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " multiply(2.0, 4.0)\n" - " // -> 8.0\n" - " ```\n" - "\n" - " ```gleam\n" - " import gleam/list\n" - "\n" - " list.fold([2.0, 3.0, 4.0], 1.0, multiply)\n" - " // -> 24.0\n" - " ```\n" - "\n" - " ```gleam\n" - " 3.0 |> multiply(2.0)\n" - " // -> 6.0\n" - " ```\n" -). --spec multiply(float(), float()) -> float(). -multiply(A, B) -> - A * B. - --file("src/gleam/float.gleam", 594). -?DOC( - " Subtracts one float from another.\n" - "\n" - " It's the function equivalent of the `-.` operator.\n" - " This function is useful in higher order functions or pipes.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " subtract(3.0, 1.0)\n" - " // -> 2.0\n" - " ```\n" - "\n" - " ```gleam\n" - " import gleam/list\n" - "\n" - " list.fold([1.0, 2.0, 3.0], 10.0, subtract)\n" - " // -> 4.0\n" - " ```\n" - "\n" - " ```gleam\n" - " 3.0 |> subtract(_, 2.0)\n" - " // -> 1.0\n" - " ```\n" - "\n" - " ```gleam\n" - " 3.0 |> subtract(2.0, _)\n" - " // -> -1.0\n" - " ```\n" -). --spec subtract(float(), float()) -> float(). -subtract(A, B) -> - A - B. - --file("src/gleam/float.gleam", 623). -?DOC( - " Returns the natural logarithm (base e) of the given as a `Result`. If the\n" - " input is less than or equal to 0, returns `Error(Nil)`.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " logarithm(1.0)\n" - " // -> Ok(0.0)\n" - " ```\n" - "\n" - " ```gleam\n" - " logarithm(2.718281828459045) // e\n" - " // -> Ok(1.0)\n" - " ```\n" - "\n" - " ```gleam\n" - " logarithm(0.0)\n" - " // -> Error(Nil)\n" - " ```\n" - "\n" - " ```gleam\n" - " logarithm(-1.0)\n" - " // -> Error(Nil)\n" - " ```\n" -). --spec logarithm(float()) -> {ok, float()} | {error, nil}. -logarithm(X) -> - case X =< +0.0 of - true -> - {error, nil}; - - false -> - {ok, math:log(X)} - end. - --file("src/gleam/float.gleam", 661). -?DOC( - " Returns e (Euler's number) raised to the power of the given exponent, as\n" - " a `Float`.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " exponential(0.0)\n" - " // -> Ok(1.0)\n" - " ```\n" - "\n" - " ```gleam\n" - " exponential(1.0)\n" - " // -> Ok(2.718281828459045)\n" - " ```\n" - "\n" - " ```gleam\n" - " exponential(-1.0)\n" - " // -> Ok(0.36787944117144233)\n" - " ```\n" -). --spec exponential(float()) -> float(). -exponential(X) -> - math:exp(X). diff --git a/build/dev/javascript/gleam_stdlib/gleam@function.erl b/build/dev/javascript/gleam_stdlib/gleam@function.erl deleted file mode 100644 index a6dec81..0000000 --- a/build/dev/javascript/gleam_stdlib/gleam@function.erl +++ /dev/null @@ -1,30 +0,0 @@ --module(gleam@function). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "src/gleam/function.gleam"). --export([identity/1, tap/2]). - --if(?OTP_RELEASE >= 27). --define(MODULEDOC(Str), -moduledoc(Str)). --define(DOC(Str), -doc(Str)). --else. --define(MODULEDOC(Str), -compile([])). --define(DOC(Str), -compile([])). --endif. - --file("src/gleam/function.gleam", 3). -?DOC(" Takes a single argument and always returns its input value.\n"). --spec identity(CLA) -> CLA. -identity(X) -> - X. - --file("src/gleam/function.gleam", 12). -?DOC( - " Takes an argument and a single function, calls that function with that\n" - " argument and returns that argument instead of the function return value.\n" - "\n" - " Useful for running synchronous side effects in a pipeline.\n" -). --spec tap(CLB, fun((CLB) -> any())) -> CLB. -tap(Arg, Effect) -> - Effect(Arg), - Arg. diff --git a/build/dev/javascript/gleam_stdlib/gleam@int.erl b/build/dev/javascript/gleam_stdlib/gleam@int.erl deleted file mode 100644 index 5e298da..0000000 --- a/build/dev/javascript/gleam_stdlib/gleam@int.erl +++ /dev/null @@ -1,986 +0,0 @@ --module(gleam@int). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "src/gleam/int.gleam"). --export([absolute_value/1, parse/1, base_parse/2, to_string/1, to_base_string/2, to_base2/1, to_base8/1, to_base16/1, to_base36/1, to_float/1, power/2, square_root/1, compare/2, min/2, max/2, clamp/3, is_even/1, is_odd/1, negate/1, sum/1, product/1, digits/2, undigits/2, random/1, divide/2, remainder/2, modulo/2, floor_divide/2, add/2, multiply/2, subtract/2, bitwise_and/2, bitwise_not/1, bitwise_or/2, bitwise_exclusive_or/2, bitwise_shift_left/2, bitwise_shift_right/2]). - --if(?OTP_RELEASE >= 27). --define(MODULEDOC(Str), -moduledoc(Str)). --define(DOC(Str), -doc(Str)). --else. --define(MODULEDOC(Str), -compile([])). --define(DOC(Str), -compile([])). --endif. - -?MODULEDOC( - " Functions for working with integers.\n" - "\n" - " ## Division by zero\n" - "\n" - " In Erlang division by zero results in a crash, however Gleam does not have\n" - " partial functions and operators in core so instead division by zero returns\n" - " zero, a behaviour taken from Pony, Coq, and Lean.\n" - "\n" - " This may seem unexpected at first, but it is no less mathematically valid\n" - " than crashing or returning a special value. Division by zero is undefined\n" - " in mathematics.\n" -). - --file("src/gleam/int.gleam", 30). -?DOC( - " Returns the absolute value of the input.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " absolute_value(-12)\n" - " // -> 12\n" - " ```\n" - "\n" - " ```gleam\n" - " absolute_value(10)\n" - " // -> 10\n" - " ```\n" -). --spec absolute_value(integer()) -> integer(). -absolute_value(X) -> - case X >= 0 of - true -> - X; - - false -> - X * -1 - end. - --file("src/gleam/int.gleam", 109). -?DOC( - " Parses a given string as an int if possible.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " parse(\"2\")\n" - " // -> Ok(2)\n" - " ```\n" - "\n" - " ```gleam\n" - " parse(\"ABC\")\n" - " // -> Error(Nil)\n" - " ```\n" -). --spec parse(binary()) -> {ok, integer()} | {error, nil}. -parse(String) -> - gleam_stdlib:parse_int(String). - --file("src/gleam/int.gleam", 141). -?DOC( - " Parses a given string as an int in a given base if possible.\n" - " Supports only bases 2 to 36, for values outside of which this function returns an `Error(Nil)`.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " base_parse(\"10\", 2)\n" - " // -> Ok(2)\n" - " ```\n" - "\n" - " ```gleam\n" - " base_parse(\"30\", 16)\n" - " // -> Ok(48)\n" - " ```\n" - "\n" - " ```gleam\n" - " base_parse(\"1C\", 36)\n" - " // -> Ok(48)\n" - " ```\n" - "\n" - " ```gleam\n" - " base_parse(\"48\", 1)\n" - " // -> Error(Nil)\n" - " ```\n" - "\n" - " ```gleam\n" - " base_parse(\"48\", 37)\n" - " // -> Error(Nil)\n" - " ```\n" -). --spec base_parse(binary(), integer()) -> {ok, integer()} | {error, nil}. -base_parse(String, Base) -> - case (Base >= 2) andalso (Base =< 36) of - true -> - gleam_stdlib:int_from_base_string(String, Base); - - false -> - {error, nil} - end. - --file("src/gleam/int.gleam", 163). -?DOC( - " Prints a given int to a string.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " to_string(2)\n" - " // -> \"2\"\n" - " ```\n" -). --spec to_string(integer()) -> binary(). -to_string(X) -> - erlang:integer_to_binary(X). - --file("src/gleam/int.gleam", 196). -?DOC( - " Prints a given int to a string using the base number provided.\n" - " Supports only bases 2 to 36, for values outside of which this function returns an `Error(Nil)`.\n" - " For common bases (2, 8, 16, 36), use the `to_baseN` functions.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " to_base_string(2, 2)\n" - " // -> Ok(\"10\")\n" - " ```\n" - "\n" - " ```gleam\n" - " to_base_string(48, 16)\n" - " // -> Ok(\"30\")\n" - " ```\n" - "\n" - " ```gleam\n" - " to_base_string(48, 36)\n" - " // -> Ok(\"1C\")\n" - " ```\n" - "\n" - " ```gleam\n" - " to_base_string(48, 1)\n" - " // -> Error(Nil)\n" - " ```\n" - "\n" - " ```gleam\n" - " to_base_string(48, 37)\n" - " // -> Error(Nil)\n" - " ```\n" -). --spec to_base_string(integer(), integer()) -> {ok, binary()} | {error, nil}. -to_base_string(X, Base) -> - case (Base >= 2) andalso (Base =< 36) of - true -> - {ok, erlang:integer_to_binary(X, Base)}; - - false -> - {error, nil} - end. - --file("src/gleam/int.gleam", 216). -?DOC( - " Prints a given int to a string using base-2.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " to_base2(2)\n" - " // -> \"10\"\n" - " ```\n" -). --spec to_base2(integer()) -> binary(). -to_base2(X) -> - erlang:integer_to_binary(X, 2). - --file("src/gleam/int.gleam", 229). -?DOC( - " Prints a given int to a string using base-8.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " to_base8(15)\n" - " // -> \"17\"\n" - " ```\n" -). --spec to_base8(integer()) -> binary(). -to_base8(X) -> - erlang:integer_to_binary(X, 8). - --file("src/gleam/int.gleam", 242). -?DOC( - " Prints a given int to a string using base-16.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " to_base16(48)\n" - " // -> \"30\"\n" - " ```\n" -). --spec to_base16(integer()) -> binary(). -to_base16(X) -> - erlang:integer_to_binary(X, 16). - --file("src/gleam/int.gleam", 255). -?DOC( - " Prints a given int to a string using base-36.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " to_base36(48)\n" - " // -> \"1C\"\n" - " ```\n" -). --spec to_base36(integer()) -> binary(). -to_base36(X) -> - erlang:integer_to_binary(X, 36). - --file("src/gleam/int.gleam", 280). -?DOC( - " Takes an int and returns its value as a float.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " to_float(5)\n" - " // -> 5.0\n" - " ```\n" - "\n" - " ```gleam\n" - " to_float(0)\n" - " // -> 0.0\n" - " ```\n" - "\n" - " ```gleam\n" - " to_float(-3)\n" - " // -> -3.0\n" - " ```\n" -). --spec to_float(integer()) -> float(). -to_float(X) -> - erlang:float(X). - --file("src/gleam/int.gleam", 67). -?DOC( - " Returns the results of the base being raised to the power of the\n" - " exponent, as a `Float`.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " power(2, -1.0)\n" - " // -> Ok(0.5)\n" - " ```\n" - "\n" - " ```gleam\n" - " power(2, 2.0)\n" - " // -> Ok(4.0)\n" - " ```\n" - "\n" - " ```gleam\n" - " power(8, 1.5)\n" - " // -> Ok(22.627416997969522)\n" - " ```\n" - "\n" - " ```gleam\n" - " 4 |> power(of: 2.0)\n" - " // -> Ok(16.0)\n" - " ```\n" - "\n" - " ```gleam\n" - " power(-1, 0.5)\n" - " // -> Error(Nil)\n" - " ```\n" -). --spec power(integer(), float()) -> {ok, float()} | {error, nil}. -power(Base, Exponent) -> - _pipe = Base, - _pipe@1 = erlang:float(_pipe), - gleam@float:power(_pipe@1, Exponent). - --file("src/gleam/int.gleam", 87). -?DOC( - " Returns the square root of the input as a `Float`.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " square_root(4)\n" - " // -> Ok(2.0)\n" - " ```\n" - "\n" - " ```gleam\n" - " square_root(-16)\n" - " // -> Error(Nil)\n" - " ```\n" -). --spec square_root(integer()) -> {ok, float()} | {error, nil}. -square_root(X) -> - _pipe = X, - _pipe@1 = erlang:float(_pipe), - gleam@float:square_root(_pipe@1). - --file("src/gleam/int.gleam", 316). -?DOC( - " Compares two ints, returning an order.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " compare(2, 3)\n" - " // -> Lt\n" - " ```\n" - "\n" - " ```gleam\n" - " compare(4, 3)\n" - " // -> Gt\n" - " ```\n" - "\n" - " ```gleam\n" - " compare(3, 3)\n" - " // -> Eq\n" - " ```\n" -). --spec compare(integer(), integer()) -> gleam@order:order(). -compare(A, B) -> - case A =:= B of - true -> - eq; - - false -> - case A < B of - true -> - lt; - - false -> - gt - end - end. - --file("src/gleam/int.gleam", 336). -?DOC( - " Compares two ints, returning the smaller of the two.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " min(2, 3)\n" - " // -> 2\n" - " ```\n" -). --spec min(integer(), integer()) -> integer(). -min(A, B) -> - case A < B of - true -> - A; - - false -> - B - end. - --file("src/gleam/int.gleam", 352). -?DOC( - " Compares two ints, returning the larger of the two.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " max(2, 3)\n" - " // -> 3\n" - " ```\n" -). --spec max(integer(), integer()) -> integer(). -max(A, B) -> - case A > B of - true -> - A; - - false -> - B - end. - --file("src/gleam/int.gleam", 291). -?DOC( - " Restricts an int between a lower and upper bound.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " clamp(40, min: 50, max: 60)\n" - " // -> 50\n" - " ```\n" -). --spec clamp(integer(), integer(), integer()) -> integer(). -clamp(X, Min_bound, Max_bound) -> - _pipe = X, - _pipe@1 = min(_pipe, Max_bound), - max(_pipe@1, Min_bound). - --file("src/gleam/int.gleam", 373). -?DOC( - " Returns whether the value provided is even.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " is_even(2)\n" - " // -> True\n" - " ```\n" - "\n" - " ```gleam\n" - " is_even(3)\n" - " // -> False\n" - " ```\n" -). --spec is_even(integer()) -> boolean(). -is_even(X) -> - (X rem 2) =:= 0. - --file("src/gleam/int.gleam", 391). -?DOC( - " Returns whether the value provided is odd.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " is_odd(3)\n" - " // -> True\n" - " ```\n" - "\n" - " ```gleam\n" - " is_odd(2)\n" - " // -> False\n" - " ```\n" -). --spec is_odd(integer()) -> boolean(). -is_odd(X) -> - (X rem 2) /= 0. - --file("src/gleam/int.gleam", 404). -?DOC( - " Returns the negative of the value provided.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " negate(1)\n" - " // -> -1\n" - " ```\n" -). --spec negate(integer()) -> integer(). -negate(X) -> - -1 * X. - --file("src/gleam/int.gleam", 421). --spec sum_loop(list(integer()), integer()) -> integer(). -sum_loop(Numbers, Initial) -> - case Numbers of - [First | Rest] -> - sum_loop(Rest, First + Initial); - - [] -> - Initial - end. - --file("src/gleam/int.gleam", 417). -?DOC( - " Sums a list of ints.\n" - "\n" - " ## Example\n" - "\n" - " ```gleam\n" - " sum([1, 2, 3])\n" - " // -> 6\n" - " ```\n" -). --spec sum(list(integer())) -> integer(). -sum(Numbers) -> - sum_loop(Numbers, 0). - --file("src/gleam/int.gleam", 441). --spec product_loop(list(integer()), integer()) -> integer(). -product_loop(Numbers, Initial) -> - case Numbers of - [First | Rest] -> - product_loop(Rest, First * Initial); - - [] -> - Initial - end. - --file("src/gleam/int.gleam", 437). -?DOC( - " Multiplies a list of ints and returns the product.\n" - "\n" - " ## Example\n" - "\n" - " ```gleam\n" - " product([2, 3, 4])\n" - " // -> 24\n" - " ```\n" -). --spec product(list(integer())) -> integer(). -product(Numbers) -> - product_loop(Numbers, 1). - --file("src/gleam/int.gleam", 456). --spec digits_loop(integer(), integer(), list(integer())) -> list(integer()). -digits_loop(X, Base, Acc) -> - case absolute_value(X) < Base of - true -> - [X | Acc]; - - false -> - digits_loop(case Base of - 0 -> 0; - Gleam@denominator -> X div Gleam@denominator - end, Base, [case Base of - 0 -> 0; - Gleam@denominator@1 -> X rem Gleam@denominator@1 - end | Acc]) - end. - --file("src/gleam/int.gleam", 449). --spec digits(integer(), integer()) -> {ok, list(integer())} | {error, nil}. -digits(X, Base) -> - case Base < 2 of - true -> - {error, nil}; - - false -> - {ok, digits_loop(X, Base, [])} - end. - --file("src/gleam/int.gleam", 471). --spec undigits_loop(list(integer()), integer(), integer()) -> {ok, integer()} | - {error, nil}. -undigits_loop(Numbers, Base, Acc) -> - case Numbers of - [] -> - {ok, Acc}; - - [Digit | _] when Digit >= Base -> - {error, nil}; - - [Digit@1 | Rest] -> - undigits_loop(Rest, Base, (Acc * Base) + Digit@1) - end. - --file("src/gleam/int.gleam", 464). --spec undigits(list(integer()), integer()) -> {ok, integer()} | {error, nil}. -undigits(Numbers, Base) -> - case Base < 2 of - true -> - {error, nil}; - - false -> - undigits_loop(Numbers, Base, 0) - end. - --file("src/gleam/int.gleam", 500). -?DOC( - " Generates a random int between zero and the given maximum.\n" - "\n" - " The lower number is inclusive, the upper number is exclusive.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " random(10)\n" - " // -> 4\n" - " ```\n" - "\n" - " ```gleam\n" - " random(1)\n" - " // -> 0\n" - " ```\n" - "\n" - " ```gleam\n" - " random(-1)\n" - " // -> -1\n" - " ```\n" -). --spec random(integer()) -> integer(). -random(Max) -> - _pipe = (rand:uniform() * erlang:float(Max)), - _pipe@1 = math:floor(_pipe), - erlang:round(_pipe@1). - --file("src/gleam/int.gleam", 533). -?DOC( - " Performs a truncated integer division.\n" - "\n" - " Returns division of the inputs as a `Result`: If the given divisor equals\n" - " `0`, this function returns an `Error`.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " divide(0, 1)\n" - " // -> Ok(0)\n" - " ```\n" - "\n" - " ```gleam\n" - " divide(1, 0)\n" - " // -> Error(Nil)\n" - " ```\n" - "\n" - " ```gleam\n" - " divide(5, 2)\n" - " // -> Ok(2)\n" - " ```\n" - "\n" - " ```gleam\n" - " divide(-99, 2)\n" - " // -> Ok(-49)\n" - " ```\n" -). --spec divide(integer(), integer()) -> {ok, integer()} | {error, nil}. -divide(Dividend, Divisor) -> - case Divisor of - 0 -> - {error, nil}; - - Divisor@1 -> - {ok, case Divisor@1 of - 0 -> 0; - Gleam@denominator -> Dividend div Gleam@denominator - end} - end. - --file("src/gleam/int.gleam", 585). -?DOC( - " Computes the remainder of an integer division of inputs as a `Result`.\n" - "\n" - " Returns division of the inputs as a `Result`: If the given divisor equals\n" - " `0`, this function returns an `Error`.\n" - "\n" - " Most the time you will want to use the `%` operator instead of this\n" - " function.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " remainder(3, 2)\n" - " // -> Ok(1)\n" - " ```\n" - "\n" - " ```gleam\n" - " remainder(1, 0)\n" - " // -> Error(Nil)\n" - " ```\n" - "\n" - " ```gleam\n" - " remainder(10, -1)\n" - " // -> Ok(0)\n" - " ```\n" - "\n" - " ```gleam\n" - " remainder(13, by: 3)\n" - " // -> Ok(1)\n" - " ```\n" - "\n" - " ```gleam\n" - " remainder(-13, by: 3)\n" - " // -> Ok(-1)\n" - " ```\n" - "\n" - " ```gleam\n" - " remainder(13, by: -3)\n" - " // -> Ok(1)\n" - " ```\n" - "\n" - " ```gleam\n" - " remainder(-13, by: -3)\n" - " // -> Ok(-1)\n" - " ```\n" -). --spec remainder(integer(), integer()) -> {ok, integer()} | {error, nil}. -remainder(Dividend, Divisor) -> - case Divisor of - 0 -> - {error, nil}; - - Divisor@1 -> - {ok, case Divisor@1 of - 0 -> 0; - Gleam@denominator -> Dividend rem Gleam@denominator - end} - end. - --file("src/gleam/int.gleam", 627). -?DOC( - " Computes the modulo of an integer division of inputs as a `Result`.\n" - "\n" - " Returns division of the inputs as a `Result`: If the given divisor equals\n" - " `0`, this function returns an `Error`.\n" - "\n" - " Most the time you will want to use the `%` operator instead of this\n" - " function.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " modulo(3, 2)\n" - " // -> Ok(1)\n" - " ```\n" - "\n" - " ```gleam\n" - " modulo(1, 0)\n" - " // -> Error(Nil)\n" - " ```\n" - "\n" - " ```gleam\n" - " modulo(10, -1)\n" - " // -> Ok(0)\n" - " ```\n" - "\n" - " ```gleam\n" - " modulo(13, by: 3)\n" - " // -> Ok(1)\n" - " ```\n" - "\n" - " ```gleam\n" - " modulo(-13, by: 3)\n" - " // -> Ok(2)\n" - " ```\n" -). --spec modulo(integer(), integer()) -> {ok, integer()} | {error, nil}. -modulo(Dividend, Divisor) -> - case Divisor of - 0 -> - {error, nil}; - - _ -> - Remainder = case Divisor of - 0 -> 0; - Gleam@denominator -> Dividend rem Gleam@denominator - end, - case (Remainder * Divisor) < 0 of - true -> - {ok, Remainder + Divisor}; - - false -> - {ok, Remainder} - end - end. - --file("src/gleam/int.gleam", 671). -?DOC( - " Performs a *floored* integer division, which means that the result will\n" - " always be rounded towards negative infinity.\n" - "\n" - " If you want to perform truncated integer division (rounding towards zero),\n" - " use `int.divide()` or the `/` operator instead.\n" - "\n" - " Returns division of the inputs as a `Result`: If the given divisor equals\n" - " `0`, this function returns an `Error`.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " floor_divide(1, 0)\n" - " // -> Error(Nil)\n" - " ```\n" - "\n" - " ```gleam\n" - " floor_divide(5, 2)\n" - " // -> Ok(2)\n" - " ```\n" - "\n" - " ```gleam\n" - " floor_divide(6, -4)\n" - " // -> Ok(-2)\n" - " ```\n" - "\n" - " ```gleam\n" - " floor_divide(-99, 2)\n" - " // -> Ok(-50)\n" - " ```\n" -). --spec floor_divide(integer(), integer()) -> {ok, integer()} | {error, nil}. -floor_divide(Dividend, Divisor) -> - case Divisor of - 0 -> - {error, nil}; - - Divisor@1 -> - case ((Dividend * Divisor@1) < 0) andalso ((case Divisor@1 of - 0 -> 0; - Gleam@denominator -> Dividend rem Gleam@denominator - end) /= 0) of - true -> - {ok, (case Divisor@1 of - 0 -> 0; - Gleam@denominator@1 -> Dividend div Gleam@denominator@1 - end) - 1}; - - false -> - {ok, case Divisor@1 of - 0 -> 0; - Gleam@denominator@2 -> Dividend div Gleam@denominator@2 - end} - end - end. - --file("src/gleam/int.gleam", 705). -?DOC( - " Adds two integers together.\n" - "\n" - " It's the function equivalent of the `+` operator.\n" - " This function is useful in higher order functions or pipes.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " add(1, 2)\n" - " // -> 3\n" - " ```\n" - "\n" - " ```gleam\n" - " import gleam/list\n" - " list.fold([1, 2, 3], 0, add)\n" - " // -> 6\n" - " ```\n" - "\n" - " ```gleam\n" - " 3 |> add(2)\n" - " // -> 5\n" - " ```\n" -). --spec add(integer(), integer()) -> integer(). -add(A, B) -> - A + B. - --file("src/gleam/int.gleam", 733). -?DOC( - " Multiplies two integers together.\n" - "\n" - " It's the function equivalent of the `*` operator.\n" - " This function is useful in higher order functions or pipes.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " multiply(2, 4)\n" - " // -> 8\n" - " ```\n" - "\n" - " ```gleam\n" - " import gleam/list\n" - "\n" - " list.fold([2, 3, 4], 1, multiply)\n" - " // -> 24\n" - " ```\n" - "\n" - " ```gleam\n" - " 3 |> multiply(2)\n" - " // -> 6\n" - " ```\n" -). --spec multiply(integer(), integer()) -> integer(). -multiply(A, B) -> - A * B. - --file("src/gleam/int.gleam", 766). -?DOC( - " Subtracts one int from another.\n" - "\n" - " It's the function equivalent of the `-` operator.\n" - " This function is useful in higher order functions or pipes.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " subtract(3, 1)\n" - " // -> 2\n" - " ```\n" - "\n" - " ```gleam\n" - " import gleam/list\n" - "\n" - " list.fold([1, 2, 3], 10, subtract)\n" - " // -> 4\n" - " ```\n" - "\n" - " ```gleam\n" - " 3 |> subtract(2)\n" - " // -> 1\n" - " ```\n" - "\n" - " ```gleam\n" - " 3 |> subtract(2, _)\n" - " // -> -1\n" - " ```\n" -). --spec subtract(integer(), integer()) -> integer(). -subtract(A, B) -> - A - B. - --file("src/gleam/int.gleam", 778). -?DOC( - " Calculates the bitwise AND of its arguments.\n" - "\n" - " The exact behaviour of this function depends on the target platform.\n" - " On Erlang it is equivalent to bitwise operations on ints, on JavaScript it\n" - " is equivalent to bitwise operations on big-ints.\n" -). --spec bitwise_and(integer(), integer()) -> integer(). -bitwise_and(X, Y) -> - erlang:'band'(X, Y). - --file("src/gleam/int.gleam", 788). -?DOC( - " Calculates the bitwise NOT of its argument.\n" - "\n" - " The exact behaviour of this function depends on the target platform.\n" - " On Erlang it is equivalent to bitwise operations on ints, on JavaScript it\n" - " is equivalent to bitwise operations on big-ints.\n" -). --spec bitwise_not(integer()) -> integer(). -bitwise_not(X) -> - erlang:'bnot'(X). - --file("src/gleam/int.gleam", 798). -?DOC( - " Calculates the bitwise OR of its arguments.\n" - "\n" - " The exact behaviour of this function depends on the target platform.\n" - " On Erlang it is equivalent to bitwise operations on ints, on JavaScript it\n" - " is equivalent to bitwise operations on big-ints.\n" -). --spec bitwise_or(integer(), integer()) -> integer(). -bitwise_or(X, Y) -> - erlang:'bor'(X, Y). - --file("src/gleam/int.gleam", 808). -?DOC( - " Calculates the bitwise XOR of its arguments.\n" - "\n" - " The exact behaviour of this function depends on the target platform.\n" - " On Erlang it is equivalent to bitwise operations on ints, on JavaScript it\n" - " is equivalent to bitwise operations on big-ints.\n" -). --spec bitwise_exclusive_or(integer(), integer()) -> integer(). -bitwise_exclusive_or(X, Y) -> - erlang:'bxor'(X, Y). - --file("src/gleam/int.gleam", 818). -?DOC( - " Calculates the result of an arithmetic left bitshift.\n" - "\n" - " The exact behaviour of this function depends on the target platform.\n" - " On Erlang it is equivalent to bitwise operations on ints, on JavaScript it\n" - " is equivalent to bitwise operations on big-ints.\n" -). --spec bitwise_shift_left(integer(), integer()) -> integer(). -bitwise_shift_left(X, Y) -> - erlang:'bsl'(X, Y). - --file("src/gleam/int.gleam", 828). -?DOC( - " Calculates the result of an arithmetic right bitshift.\n" - "\n" - " The exact behaviour of this function depends on the target platform.\n" - " On Erlang it is equivalent to bitwise operations on ints, on JavaScript it\n" - " is equivalent to bitwise operations on big-ints.\n" -). --spec bitwise_shift_right(integer(), integer()) -> integer(). -bitwise_shift_right(X, Y) -> - erlang:'bsr'(X, Y). diff --git a/build/dev/javascript/gleam_stdlib/gleam@io.erl b/build/dev/javascript/gleam_stdlib/gleam@io.erl deleted file mode 100644 index e60295e..0000000 --- a/build/dev/javascript/gleam_stdlib/gleam@io.erl +++ /dev/null @@ -1,80 +0,0 @@ --module(gleam@io). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "src/gleam/io.gleam"). --export([print/1, print_error/1, println/1, println_error/1]). - --if(?OTP_RELEASE >= 27). --define(MODULEDOC(Str), -moduledoc(Str)). --define(DOC(Str), -doc(Str)). --else. --define(MODULEDOC(Str), -compile([])). --define(DOC(Str), -compile([])). --endif. - --file("src/gleam/io.gleam", 15). -?DOC( - " Writes a string to standard output (stdout).\n" - "\n" - " If you want your output to be printed on its own line see `println`.\n" - "\n" - " ## Example\n" - "\n" - " ```gleam\n" - " io.print(\"Hi mum\")\n" - " // -> Nil\n" - " // Hi mum\n" - " ```\n" -). --spec print(binary()) -> nil. -print(String) -> - gleam_stdlib:print(String). - --file("src/gleam/io.gleam", 31). -?DOC( - " Writes a string to standard error (stderr).\n" - "\n" - " If you want your output to be printed on its own line see `println_error`.\n" - "\n" - " ## Example\n" - "\n" - " ```\n" - " io.print_error(\"Hi pop\")\n" - " // -> Nil\n" - " // Hi pop\n" - " ```\n" -). --spec print_error(binary()) -> nil. -print_error(String) -> - gleam_stdlib:print_error(String). - --file("src/gleam/io.gleam", 45). -?DOC( - " Writes a string to standard output (stdout), appending a newline to the end.\n" - "\n" - " ## Example\n" - "\n" - " ```gleam\n" - " io.println(\"Hi mum\")\n" - " // -> Nil\n" - " // Hi mum\n" - " ```\n" -). --spec println(binary()) -> nil. -println(String) -> - gleam_stdlib:println(String). - --file("src/gleam/io.gleam", 59). -?DOC( - " Writes a string to standard error (stderr), appending a newline to the end.\n" - "\n" - " ## Example\n" - "\n" - " ```gleam\n" - " io.println_error(\"Hi pop\")\n" - " // -> Nil\n" - " // Hi pop\n" - " ```\n" -). --spec println_error(binary()) -> nil. -println_error(String) -> - gleam_stdlib:println_error(String). diff --git a/build/dev/javascript/gleam_stdlib/gleam@list.erl b/build/dev/javascript/gleam_stdlib/gleam@list.erl deleted file mode 100644 index 0c96ecb..0000000 --- a/build/dev/javascript/gleam_stdlib/gleam@list.erl +++ /dev/null @@ -1,2873 +0,0 @@ --module(gleam@list). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "src/gleam/list.gleam"). --export([length/1, count/2, reverse/1, is_empty/1, contains/2, first/1, rest/1, group/2, filter/2, filter_map/2, map/2, map2/3, map_fold/3, index_map/2, try_map/2, drop/2, take/2, new/0, wrap/1, append/2, prepend/2, flatten/1, flat_map/2, fold/3, fold_right/3, index_fold/3, try_fold/3, fold_until/3, find/2, find_map/2, all/2, any/2, zip/2, strict_zip/2, unzip/1, intersperse/2, unique/1, sort/2, range/2, repeat/2, split/2, split_while/2, key_find/2, key_filter/2, key_pop/2, key_set/3, each/2, try_each/2, partition/2, window/2, window_by_2/1, drop_while/2, take_while/2, chunk/2, sized_chunk/2, reduce/2, scan/3, last/1, combinations/2, combination_pairs/1, transpose/1, interleave/1, shuffle/1, max/2, sample/2, permutations/1]). --export_type([continue_or_stop/1, sorting/0]). - --if(?OTP_RELEASE >= 27). --define(MODULEDOC(Str), -moduledoc(Str)). --define(DOC(Str), -doc(Str)). --else. --define(MODULEDOC(Str), -compile([])). --define(DOC(Str), -compile([])). --endif. - -?MODULEDOC( - " Lists are an ordered sequence of elements and are one of the most common\n" - " data types in Gleam.\n" - "\n" - " New elements can be added and removed from the front of a list in\n" - " constant time, while adding and removing from the end requires traversing\n" - " and copying the whole list, so keep this in mind when designing your\n" - " programs.\n" - "\n" - " There is a dedicated syntax for prefixing to a list:\n" - "\n" - " ```gleam\n" - " let new_list = [1, 2, ..existing_list]\n" - " ```\n" - "\n" - " And a matching syntax for getting the first elements of a list:\n" - "\n" - " ```gleam\n" - " case list {\n" - " [first_element, ..rest] -> first_element\n" - " _ -> \"this pattern matches when the list is empty\"\n" - " }\n" - " ```\n" - "\n" -). - --type continue_or_stop(XG) :: {continue, XG} | {stop, XG}. - --type sorting() :: ascending | descending. - --file("src/gleam/list.gleam", 60). --spec length_loop(list(any()), integer()) -> integer(). -length_loop(List, Count) -> - case List of - [_ | List@1] -> - length_loop(List@1, Count + 1); - - [] -> - Count - end. - --file("src/gleam/list.gleam", 56). -?DOC( - " Counts the number of elements in a given list.\n" - "\n" - " This function has to traverse the list to determine the number of elements,\n" - " so it runs in linear time.\n" - "\n" - " This function is natively implemented by the virtual machine and is highly\n" - " optimised.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " length([])\n" - " // -> 0\n" - " ```\n" - "\n" - " ```gleam\n" - " length([1])\n" - " // -> 1\n" - " ```\n" - "\n" - " ```gleam\n" - " length([1, 2])\n" - " // -> 2\n" - " ```\n" -). --spec length(list(any())) -> integer(). -length(List) -> - erlang:length(List). - --file("src/gleam/list.gleam", 93). --spec count_loop(list(XN), fun((XN) -> boolean()), integer()) -> integer(). -count_loop(List, Predicate, Acc) -> - case List of - [] -> - Acc; - - [First | Rest] -> - case Predicate(First) of - true -> - count_loop(Rest, Predicate, Acc + 1); - - false -> - count_loop(Rest, Predicate, Acc) - end - end. - --file("src/gleam/list.gleam", 89). -?DOC( - " Counts the number of elements in a given list satisfying a given predicate.\n" - "\n" - " This function has to traverse the list to determine the number of elements,\n" - " so it runs in linear time.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " count([], fn(a) { a > 0 })\n" - " // -> 0\n" - " ```\n" - "\n" - " ```gleam\n" - " count([1], fn(a) { a > 0 })\n" - " // -> 1\n" - " ```\n" - "\n" - " ```gleam\n" - " count([1, 2, 3], int.is_odd)\n" - " // -> 2\n" - " ```\n" -). --spec count(list(XL), fun((XL) -> boolean())) -> integer(). -count(List, Predicate) -> - count_loop(List, Predicate, 0). - --file("src/gleam/list.gleam", 131). -?DOC( - " Creates a new list from a given list containing the same elements but in the\n" - " opposite order.\n" - "\n" - " This function has to traverse the list to create the new reversed list, so\n" - " it runs in linear time.\n" - "\n" - " This function is natively implemented by the virtual machine and is highly\n" - " optimised.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " reverse([])\n" - " // -> []\n" - " ```\n" - "\n" - " ```gleam\n" - " reverse([1])\n" - " // -> [1]\n" - " ```\n" - "\n" - " ```gleam\n" - " reverse([1, 2])\n" - " // -> [2, 1]\n" - " ```\n" -). --spec reverse(list(XP)) -> list(XP). -reverse(List) -> - lists:reverse(List). - --file("src/gleam/list.gleam", 168). -?DOC( - " Determines whether or not the list is empty.\n" - "\n" - " This function runs in constant time.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " is_empty([])\n" - " // -> True\n" - " ```\n" - "\n" - " ```gleam\n" - " is_empty([1])\n" - " // -> False\n" - " ```\n" - "\n" - " ```gleam\n" - " is_empty([1, 1])\n" - " // -> False\n" - " ```\n" -). --spec is_empty(list(any())) -> boolean(). -is_empty(List) -> - List =:= []. - --file("src/gleam/list.gleam", 204). -?DOC( - " Determines whether or not a given element exists within a given list.\n" - "\n" - " This function traverses the list to find the element, so it runs in linear\n" - " time.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " [] |> contains(any: 0)\n" - " // -> False\n" - " ```\n" - "\n" - " ```gleam\n" - " [0] |> contains(any: 0)\n" - " // -> True\n" - " ```\n" - "\n" - " ```gleam\n" - " [1] |> contains(any: 0)\n" - " // -> False\n" - " ```\n" - "\n" - " ```gleam\n" - " [1, 1] |> contains(any: 0)\n" - " // -> False\n" - " ```\n" - "\n" - " ```gleam\n" - " [1, 0] |> contains(any: 0)\n" - " // -> True\n" - " ```\n" -). --spec contains(list(XY), XY) -> boolean(). -contains(List, Elem) -> - case List of - [] -> - false; - - [First | _] when First =:= Elem -> - true; - - [_ | Rest] -> - contains(Rest, Elem) - end. - --file("src/gleam/list.gleam", 231). -?DOC( - " Gets the first element from the start of the list, if there is one.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " first([])\n" - " // -> Error(Nil)\n" - " ```\n" - "\n" - " ```gleam\n" - " first([0])\n" - " // -> Ok(0)\n" - " ```\n" - "\n" - " ```gleam\n" - " first([1, 2])\n" - " // -> Ok(1)\n" - " ```\n" -). --spec first(list(YA)) -> {ok, YA} | {error, nil}. -first(List) -> - case List of - [] -> - {error, nil}; - - [First | _] -> - {ok, First} - end. - --file("src/gleam/list.gleam", 260). -?DOC( - " Returns the list minus the first element. If the list is empty, `Error(Nil)` is\n" - " returned.\n" - "\n" - " This function runs in constant time and does not make a copy of the list.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " rest([])\n" - " // -> Error(Nil)\n" - " ```\n" - "\n" - " ```gleam\n" - " rest([0])\n" - " // -> Ok([])\n" - " ```\n" - "\n" - " ```gleam\n" - " rest([1, 2])\n" - " // -> Ok([2])\n" - " ```\n" -). --spec rest(list(YE)) -> {ok, list(YE)} | {error, nil}. -rest(List) -> - case List of - [] -> - {error, nil}; - - [_ | Rest] -> - {ok, Rest} - end. - --file("src/gleam/list.gleam", 302). --spec group_loop(list(YP), fun((YP) -> YR), gleam@dict:dict(YR, list(YP))) -> gleam@dict:dict(YR, list(YP)). -group_loop(List, To_key, Groups) -> - case List of - [] -> - Groups; - - [First | Rest] -> - Key = To_key(First), - Groups@1 = case gleam_stdlib:map_get(Groups, Key) of - {error, _} -> - gleam@dict:insert(Groups, Key, [First]); - - {ok, Existing} -> - gleam@dict:insert(Groups, Key, [First | Existing]) - end, - group_loop(Rest, To_key, Groups@1) - end. - --file("src/gleam/list.gleam", 298). -?DOC( - " Groups the elements from the given list by the given key function.\n" - "\n" - " Does not preserve the initial value order.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " import gleam/dict\n" - "\n" - " [Ok(3), Error(\"Wrong\"), Ok(200), Ok(73)]\n" - " |> group(by: fn(i) {\n" - " case i {\n" - " Ok(_) -> \"Successful\"\n" - " Error(_) -> \"Failed\"\n" - " }\n" - " })\n" - " |> dict.to_list\n" - " // -> [\n" - " // #(\"Failed\", [Error(\"Wrong\")]),\n" - " // #(\"Successful\", [Ok(73), Ok(200), Ok(3)])\n" - " // ]\n" - " ```\n" - "\n" - " ```gleam\n" - " import gleam/dict\n" - "\n" - " group([1,2,3,4,5], by: fn(i) { i - i / 3 * 3 })\n" - " |> dict.to_list\n" - " // -> [#(0, [3]), #(1, [4, 1]), #(2, [5, 2])]\n" - " ```\n" -). --spec group(list(YJ), fun((YJ) -> YL)) -> gleam@dict:dict(YL, list(YJ)). -group(List, Key) -> - group_loop(List, Key, maps:new()). - --file("src/gleam/list.gleam", 339). --spec filter_loop(list(AAB), fun((AAB) -> boolean()), list(AAB)) -> list(AAB). -filter_loop(List, Fun, Acc) -> - case List of - [] -> - lists:reverse(Acc); - - [First | Rest] -> - New_acc = case Fun(First) of - true -> - [First | Acc]; - - false -> - Acc - end, - filter_loop(Rest, Fun, New_acc) - end. - --file("src/gleam/list.gleam", 335). -?DOC( - " Returns a new list containing only the elements from the first list for\n" - " which the given functions returns `True`.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " filter([2, 4, 6, 1], fn(x) { x > 2 })\n" - " // -> [4, 6]\n" - " ```\n" - "\n" - " ```gleam\n" - " filter([2, 4, 6, 1], fn(x) { x > 6 })\n" - " // -> []\n" - " ```\n" -). --spec filter(list(YY), fun((YY) -> boolean())) -> list(YY). -filter(List, Predicate) -> - filter_loop(List, Predicate, []). - --file("src/gleam/list.gleam", 371). --spec filter_map_loop( - list(AAM), - fun((AAM) -> {ok, AAO} | {error, any()}), - list(AAO) -) -> list(AAO). -filter_map_loop(List, Fun, Acc) -> - case List of - [] -> - lists:reverse(Acc); - - [First | Rest] -> - New_acc = case Fun(First) of - {ok, First@1} -> - [First@1 | Acc]; - - {error, _} -> - Acc - end, - filter_map_loop(Rest, Fun, New_acc) - end. - --file("src/gleam/list.gleam", 367). -?DOC( - " Returns a new list containing only the elements from the first list for\n" - " which the given functions returns `Ok(_)`.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " filter_map([2, 4, 6, 1], Error)\n" - " // -> []\n" - " ```\n" - "\n" - " ```gleam\n" - " filter_map([2, 4, 6, 1], fn(x) { Ok(x + 1) })\n" - " // -> [3, 5, 7, 2]\n" - " ```\n" -). --spec filter_map(list(AAF), fun((AAF) -> {ok, AAH} | {error, any()})) -> list(AAH). -filter_map(List, Fun) -> - filter_map_loop(List, Fun, []). - --file("src/gleam/list.gleam", 402). --spec map_loop(list(AAY), fun((AAY) -> ABA), list(ABA)) -> list(ABA). -map_loop(List, Fun, Acc) -> - case List of - [] -> - lists:reverse(Acc); - - [First | Rest] -> - map_loop(Rest, Fun, [Fun(First) | Acc]) - end. - --file("src/gleam/list.gleam", 398). -?DOC( - " Returns a new list containing only the elements of the first list after the\n" - " function has been applied to each one.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " map([2, 4, 6], fn(x) { x * 2 })\n" - " // -> [4, 8, 12]\n" - " ```\n" -). --spec map(list(AAU), fun((AAU) -> AAW)) -> list(AAW). -map(List, Fun) -> - map_loop(List, Fun, []). - --file("src/gleam/list.gleam", 429). --spec map2_loop(list(ABJ), list(ABL), fun((ABJ, ABL) -> ABN), list(ABN)) -> list(ABN). -map2_loop(List1, List2, Fun, Acc) -> - case {List1, List2} of - {[], _} -> - lists:reverse(Acc); - - {_, []} -> - lists:reverse(Acc); - - {[A | As_], [B | Bs]} -> - map2_loop(As_, Bs, Fun, [Fun(A, B) | Acc]) - end. - --file("src/gleam/list.gleam", 425). -?DOC( - " Combines two lists into a single list using the given function.\n" - "\n" - " If a list is longer than the other the extra elements are dropped.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " map2([1, 2, 3], [4, 5, 6], fn(x, y) { x + y })\n" - " // -> [5, 7, 9]\n" - " ```\n" - "\n" - " ```gleam\n" - " map2([1, 2], [\"a\", \"b\", \"c\"], fn(i, x) { #(i, x) })\n" - " // -> [#(1, \"a\"), #(2, \"b\")]\n" - " ```\n" -). --spec map2(list(ABD), list(ABF), fun((ABD, ABF) -> ABH)) -> list(ABH). -map2(List1, List2, Fun) -> - map2_loop(List1, List2, Fun, []). - --file("src/gleam/list.gleam", 462). --spec map_fold_loop(list(ABV), fun((ABX, ABV) -> {ABX, ABY}), ABX, list(ABY)) -> {ABX, - list(ABY)}. -map_fold_loop(List, Fun, Acc, List_acc) -> - case List of - [] -> - {Acc, lists:reverse(List_acc)}; - - [First | Rest] -> - {Acc@1, First@1} = Fun(Acc, First), - map_fold_loop(Rest, Fun, Acc@1, [First@1 | List_acc]) - end. - --file("src/gleam/list.gleam", 454). -?DOC( - " Similar to `map` but also lets you pass around an accumulated value.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " map_fold(\n" - " over: [1, 2, 3],\n" - " from: 100,\n" - " with: fn(memo, i) { #(memo + i, i * 2) }\n" - " )\n" - " // -> #(106, [2, 4, 6])\n" - " ```\n" -). --spec map_fold(list(ABQ), ABS, fun((ABS, ABQ) -> {ABS, ABT})) -> {ABS, - list(ABT)}. -map_fold(List, Initial, Fun) -> - map_fold_loop(List, Fun, Initial, []). - --file("src/gleam/list.gleam", 494). --spec index_map_loop( - list(ACF), - fun((ACF, integer()) -> ACH), - integer(), - list(ACH) -) -> list(ACH). -index_map_loop(List, Fun, Index, Acc) -> - case List of - [] -> - lists:reverse(Acc); - - [First | Rest] -> - Acc@1 = [Fun(First, Index) | Acc], - index_map_loop(Rest, Fun, Index + 1, Acc@1) - end. - --file("src/gleam/list.gleam", 490). -?DOC( - " Returns a new list containing only the elements of the first list after the\n" - " function has been applied to each one and their index.\n" - "\n" - " The index starts at 0, so the first element is 0, the second is 1, and so\n" - " on.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " index_map([\"a\", \"b\"], fn(x, i) { #(i, x) })\n" - " // -> [#(0, \"a\"), #(1, \"b\")]\n" - " ```\n" -). --spec index_map(list(ACB), fun((ACB, integer()) -> ACD)) -> list(ACD). -index_map(List, Fun) -> - index_map_loop(List, Fun, 0, []). - --file("src/gleam/list.gleam", 548). --spec try_map_loop(list(ACT), fun((ACT) -> {ok, ACV} | {error, ACW}), list(ACV)) -> {ok, - list(ACV)} | - {error, ACW}. -try_map_loop(List, Fun, Acc) -> - case List of - [] -> - {ok, lists:reverse(Acc)}; - - [First | Rest] -> - case Fun(First) of - {ok, First@1} -> - try_map_loop(Rest, Fun, [First@1 | Acc]); - - {error, Error} -> - {error, Error} - end - end. - --file("src/gleam/list.gleam", 541). -?DOC( - " Takes a function that returns a `Result` and applies it to each element in a\n" - " given list in turn.\n" - "\n" - " If the function returns `Ok(new_value)` for all elements in the list then a\n" - " list of the new values is returned.\n" - "\n" - " If the function returns `Error(reason)` for any of the elements then it is\n" - " returned immediately. None of the elements in the list are processed after\n" - " one returns an `Error`.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " try_map([1, 2, 3], fn(x) { Ok(x + 2) })\n" - " // -> Ok([3, 4, 5])\n" - " ```\n" - "\n" - " ```gleam\n" - " try_map([1, 2, 3], fn(_) { Error(0) })\n" - " // -> Error(0)\n" - " ```\n" - "\n" - " ```gleam\n" - " try_map([[1], [2, 3]], first)\n" - " // -> Ok([1, 2])\n" - " ```\n" - "\n" - " ```gleam\n" - " try_map([[1], [], [2]], first)\n" - " // -> Error(Nil)\n" - " ```\n" -). --spec try_map(list(ACK), fun((ACK) -> {ok, ACM} | {error, ACN})) -> {ok, - list(ACM)} | - {error, ACN}. -try_map(List, Fun) -> - try_map_loop(List, Fun, []). - --file("src/gleam/list.gleam", 583). -?DOC( - " Returns a list that is the given list with up to the given number of\n" - " elements removed from the front of the list.\n" - "\n" - " If the element has less than the number of elements an empty list is\n" - " returned.\n" - "\n" - " This function runs in linear time but does not copy the list.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " drop([1, 2, 3, 4], 2)\n" - " // -> [3, 4]\n" - " ```\n" - "\n" - " ```gleam\n" - " drop([1, 2, 3, 4], 9)\n" - " // -> []\n" - " ```\n" -). --spec drop(list(ADD), integer()) -> list(ADD). -drop(List, N) -> - case N =< 0 of - true -> - List; - - false -> - case List of - [] -> - []; - - [_ | Rest] -> - drop(Rest, N - 1) - end - end. - --file("src/gleam/list.gleam", 618). --spec take_loop(list(ADJ), integer(), list(ADJ)) -> list(ADJ). -take_loop(List, N, Acc) -> - case N =< 0 of - true -> - lists:reverse(Acc); - - false -> - case List of - [] -> - lists:reverse(Acc); - - [First | Rest] -> - take_loop(Rest, N - 1, [First | Acc]) - end - end. - --file("src/gleam/list.gleam", 614). -?DOC( - " Returns a list containing the first given number of elements from the given\n" - " list.\n" - "\n" - " If the element has less than the number of elements then the full list is\n" - " returned.\n" - "\n" - " This function runs in linear time.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " take([1, 2, 3, 4], 2)\n" - " // -> [1, 2]\n" - " ```\n" - "\n" - " ```gleam\n" - " take([1, 2, 3, 4], 9)\n" - " // -> [1, 2, 3, 4]\n" - " ```\n" -). --spec take(list(ADG), integer()) -> list(ADG). -take(List, N) -> - take_loop(List, N, []). - --file("src/gleam/list.gleam", 638). -?DOC( - " Returns a new empty list.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " new()\n" - " // -> []\n" - " ```\n" -). --spec new() -> list(any()). -new() -> - []. - --file("src/gleam/list.gleam", 658). -?DOC( - " Returns the given item wrapped in a list.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " wrap(1)\n" - " // -> [1]\n" - "\n" - " wrap([\"a\", \"b\", \"c\"])\n" - " // -> [[\"a\", \"b\", \"c\"]]\n" - "\n" - " wrap([[]])\n" - " // -> [[[]]]\n" - " ```\n" -). --spec wrap(ADP) -> list(ADP). -wrap(Item) -> - [Item]. - --file("src/gleam/list.gleam", 679). --spec append_loop(list(ADV), list(ADV)) -> list(ADV). -append_loop(First, Second) -> - case First of - [] -> - Second; - - [First@1 | Rest] -> - append_loop(Rest, [First@1 | Second]) - end. - --file("src/gleam/list.gleam", 675). -?DOC( - " Joins one list onto the end of another.\n" - "\n" - " This function runs in linear time, and it traverses and copies the first\n" - " list.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " append([1, 2], [3])\n" - " // -> [1, 2, 3]\n" - " ```\n" -). --spec append(list(ADR), list(ADR)) -> list(ADR). -append(First, Second) -> - lists:append(First, Second). - --file("src/gleam/list.gleam", 699). -?DOC( - " Prefixes an item to a list. This can also be done using the dedicated\n" - " syntax instead\n" - "\n" - " ```gleam\n" - " let existing_list = [2, 3, 4]\n" - "\n" - " [1, ..existing_list]\n" - " // -> [1, 2, 3, 4]\n" - "\n" - " prepend(to: existing_list, this: 1)\n" - " // -> [1, 2, 3, 4]\n" - " ```\n" -). --spec prepend(list(ADZ), ADZ) -> list(ADZ). -prepend(List, Item) -> - [Item | List]. - --file("src/gleam/list.gleam", 720). --spec flatten_loop(list(list(AEG)), list(AEG)) -> list(AEG). -flatten_loop(Lists, Acc) -> - case Lists of - [] -> - lists:reverse(Acc); - - [List | Further_lists] -> - flatten_loop(Further_lists, lists:reverse(List, Acc)) - end. - --file("src/gleam/list.gleam", 716). -?DOC( - " Joins a list of lists into a single list.\n" - "\n" - " This function traverses all elements twice on the JavaScript target.\n" - " This function traverses all elements once on the Erlang target.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " flatten([[1], [2, 3], []])\n" - " // -> [1, 2, 3]\n" - " ```\n" -). --spec flatten(list(list(AEC))) -> list(AEC). -flatten(Lists) -> - lists:append(Lists). - --file("src/gleam/list.gleam", 737). -?DOC( - " Maps the list with the given function into a list of lists, and then flattens it.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " flat_map([2, 4, 6], fn(x) { [x, x + 1] })\n" - " // -> [2, 3, 4, 5, 6, 7]\n" - " ```\n" -). --spec flat_map(list(AEL), fun((AEL) -> list(AEN))) -> list(AEN). -flat_map(List, Fun) -> - lists:append(map(List, Fun)). - --file("src/gleam/list.gleam", 749). -?DOC( - " Reduces a list of elements into a single value by calling a given function\n" - " on each element, going from left to right.\n" - "\n" - " `fold([1, 2, 3], 0, add)` is the equivalent of\n" - " `add(add(add(0, 1), 2), 3)`.\n" - "\n" - " This function runs in linear time.\n" -). --spec fold(list(AEQ), AES, fun((AES, AEQ) -> AES)) -> AES. -fold(List, Initial, Fun) -> - case List of - [] -> - Initial; - - [First | Rest] -> - fold(Rest, Fun(Initial, First), Fun) - end. - --file("src/gleam/list.gleam", 771). -?DOC( - " Reduces a list of elements into a single value by calling a given function\n" - " on each element, going from right to left.\n" - "\n" - " `fold_right([1, 2, 3], 0, add)` is the equivalent of\n" - " `add(add(add(0, 3), 2), 1)`.\n" - "\n" - " This function runs in linear time.\n" - "\n" - " Unlike `fold` this function is not tail recursive. Where possible use\n" - " `fold` instead as it will use less memory.\n" -). --spec fold_right(list(AET), AEV, fun((AEV, AET) -> AEV)) -> AEV. -fold_right(List, Initial, Fun) -> - case List of - [] -> - Initial; - - [First | Rest] -> - Fun(fold_right(Rest, Initial, Fun), First) - end. - --file("src/gleam/list.gleam", 808). --spec index_fold_loop( - list(AEZ), - AFB, - fun((AFB, AEZ, integer()) -> AFB), - integer() -) -> AFB. -index_fold_loop(Over, Acc, With, Index) -> - case Over of - [] -> - Acc; - - [First | Rest] -> - index_fold_loop(Rest, With(Acc, First, Index), With, Index + 1) - end. - --file("src/gleam/list.gleam", 800). -?DOC( - " Like fold but the folding function also receives the index of the current element.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " [\"a\", \"b\", \"c\"]\n" - " |> index_fold(\"\", fn(acc, item, index) {\n" - " acc <> int.to_string(index) <> \":\" <> item <> \" \"\n" - " })\n" - " // -> \"0:a 1:b 2:c\"\n" - " ```\n" - "\n" - " ```gleam\n" - " [10, 20, 30]\n" - " |> index_fold(0, fn(acc, item, index) { acc + item * index })\n" - " // -> 80\n" - " ```\n" -). --spec index_fold(list(AEW), AEY, fun((AEY, AEW, integer()) -> AEY)) -> AEY. -index_fold(List, Initial, Fun) -> - index_fold_loop(List, Initial, Fun, 0). - --file("src/gleam/list.gleam", 840). -?DOC( - " A variant of fold that might fail.\n" - "\n" - " The folding function should return `Result(accumulator, error)`.\n" - " If the returned value is `Ok(accumulator)` try_fold will try the next value in the list.\n" - " If the returned value is `Error(error)` try_fold will stop and return that error.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " [1, 2, 3, 4]\n" - " |> try_fold(0, fn(acc, i) {\n" - " case i < 3 {\n" - " True -> Ok(acc + i)\n" - " False -> Error(Nil)\n" - " }\n" - " })\n" - " // -> Error(Nil)\n" - " ```\n" -). --spec try_fold(list(AFC), AFE, fun((AFE, AFC) -> {ok, AFE} | {error, AFF})) -> {ok, - AFE} | - {error, AFF}. -try_fold(List, Initial, Fun) -> - case List of - [] -> - {ok, Initial}; - - [First | Rest] -> - case Fun(Initial, First) of - {ok, Result} -> - try_fold(Rest, Result, Fun); - - {error, _} = Error -> - Error - end - end. - --file("src/gleam/list.gleam", 879). -?DOC( - " A variant of fold that allows to stop folding earlier.\n" - "\n" - " The folding function should return `ContinueOrStop(accumulator)`.\n" - " If the returned value is `Continue(accumulator)` fold_until will try the next value in the list.\n" - " If the returned value is `Stop(accumulator)` fold_until will stop and return that accumulator.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " [1, 2, 3, 4]\n" - " |> fold_until(0, fn(acc, i) {\n" - " case i < 3 {\n" - " True -> Continue(acc + i)\n" - " False -> Stop(acc)\n" - " }\n" - " })\n" - " // -> 3\n" - " ```\n" -). --spec fold_until(list(AFK), AFM, fun((AFM, AFK) -> continue_or_stop(AFM))) -> AFM. -fold_until(List, Initial, Fun) -> - case List of - [] -> - Initial; - - [First | Rest] -> - case Fun(Initial, First) of - {continue, Next_accumulator} -> - fold_until(Rest, Next_accumulator, Fun); - - {stop, B} -> - B - end - end. - --file("src/gleam/list.gleam", 916). -?DOC( - " Finds the first element in a given list for which the given function returns\n" - " `True`.\n" - "\n" - " Returns `Error(Nil)` if no such element is found.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " find([1, 2, 3], fn(x) { x > 2 })\n" - " // -> Ok(3)\n" - " ```\n" - "\n" - " ```gleam\n" - " find([1, 2, 3], fn(x) { x > 4 })\n" - " // -> Error(Nil)\n" - " ```\n" - "\n" - " ```gleam\n" - " find([], fn(_) { True })\n" - " // -> Error(Nil)\n" - " ```\n" -). --spec find(list(AFO), fun((AFO) -> boolean())) -> {ok, AFO} | {error, nil}. -find(List, Is_desired) -> - case List of - [] -> - {error, nil}; - - [First | Rest] -> - case Is_desired(First) of - true -> - {ok, First}; - - false -> - find(Rest, Is_desired) - end - end. - --file("src/gleam/list.gleam", 952). -?DOC( - " Finds the first element in a given list for which the given function returns\n" - " `Ok(new_value)`, then returns the wrapped `new_value`.\n" - "\n" - " Returns `Error(Nil)` if no such element is found.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " find_map([[], [2], [3]], first)\n" - " // -> Ok(2)\n" - " ```\n" - "\n" - " ```gleam\n" - " find_map([[], []], first)\n" - " // -> Error(Nil)\n" - " ```\n" - "\n" - " ```gleam\n" - " find_map([], first)\n" - " // -> Error(Nil)\n" - " ```\n" -). --spec find_map(list(AFS), fun((AFS) -> {ok, AFU} | {error, any()})) -> {ok, AFU} | - {error, nil}. -find_map(List, Fun) -> - case List of - [] -> - {error, nil}; - - [First | Rest] -> - case Fun(First) of - {ok, First@1} -> - {ok, First@1}; - - {error, _} -> - find_map(Rest, Fun) - end - end. - --file("src/gleam/list.gleam", 987). -?DOC( - " Returns `True` if the given function returns `True` for all the elements in\n" - " the given list. If the function returns `False` for any of the elements it\n" - " immediately returns `False` without checking the rest of the list.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " all([], fn(x) { x > 3 })\n" - " // -> True\n" - " ```\n" - "\n" - " ```gleam\n" - " all([4, 5], fn(x) { x > 3 })\n" - " // -> True\n" - " ```\n" - "\n" - " ```gleam\n" - " all([4, 3], fn(x) { x > 3 })\n" - " // -> False\n" - " ```\n" -). --spec all(list(AGA), fun((AGA) -> boolean())) -> boolean(). -all(List, Predicate) -> - case List of - [] -> - true; - - [First | Rest] -> - case Predicate(First) of - true -> - all(Rest, Predicate); - - false -> - false - end - end. - --file("src/gleam/list.gleam", 1024). -?DOC( - " Returns `True` if the given function returns `True` for any the elements in\n" - " the given list. If the function returns `True` for any of the elements it\n" - " immediately returns `True` without checking the rest of the list.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " any([], fn(x) { x > 3 })\n" - " // -> False\n" - " ```\n" - "\n" - " ```gleam\n" - " any([4, 5], fn(x) { x > 3 })\n" - " // -> True\n" - " ```\n" - "\n" - " ```gleam\n" - " any([4, 3], fn(x) { x > 4 })\n" - " // -> False\n" - " ```\n" - "\n" - " ```gleam\n" - " any([3, 4], fn(x) { x > 3 })\n" - " // -> True\n" - " ```\n" -). --spec any(list(AGC), fun((AGC) -> boolean())) -> boolean(). -any(List, Predicate) -> - case List of - [] -> - false; - - [First | Rest] -> - case Predicate(First) of - true -> - true; - - false -> - any(Rest, Predicate) - end - end. - --file("src/gleam/list.gleam", 1066). --spec zip_loop(list(AGJ), list(AGL), list({AGJ, AGL})) -> list({AGJ, AGL}). -zip_loop(One, Other, Acc) -> - case {One, Other} of - {[First_one | Rest_one], [First_other | Rest_other]} -> - zip_loop(Rest_one, Rest_other, [{First_one, First_other} | Acc]); - - {_, _} -> - lists:reverse(Acc) - end. - --file("src/gleam/list.gleam", 1062). -?DOC( - " Takes two lists and returns a single list of 2-element tuples.\n" - "\n" - " If one of the lists is longer than the other, the remaining elements from\n" - " the longer list are not used.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " zip([], [])\n" - " // -> []\n" - " ```\n" - "\n" - " ```gleam\n" - " zip([1, 2], [3])\n" - " // -> [#(1, 3)]\n" - " ```\n" - "\n" - " ```gleam\n" - " zip([1], [3, 4])\n" - " // -> [#(1, 3)]\n" - " ```\n" - "\n" - " ```gleam\n" - " zip([1, 2], [3, 4])\n" - " // -> [#(1, 3), #(2, 4)]\n" - " ```\n" -). --spec zip(list(AGE), list(AGG)) -> list({AGE, AGG}). -zip(List, Other) -> - zip_loop(List, Other, []). - --file("src/gleam/list.gleam", 1107). --spec strict_zip_loop(list(AGW), list(AGY), list({AGW, AGY})) -> {ok, - list({AGW, AGY})} | - {error, nil}. -strict_zip_loop(One, Other, Acc) -> - case {One, Other} of - {[], []} -> - {ok, lists:reverse(Acc)}; - - {[], _} -> - {error, nil}; - - {_, []} -> - {error, nil}; - - {[First_one | Rest_one], [First_other | Rest_other]} -> - strict_zip_loop( - Rest_one, - Rest_other, - [{First_one, First_other} | Acc] - ) - end. - --file("src/gleam/list.gleam", 1100). -?DOC( - " Takes two lists and returns a single list of 2-element tuples.\n" - "\n" - " If one of the lists is longer than the other, an `Error` is returned.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " strict_zip([], [])\n" - " // -> Ok([])\n" - " ```\n" - "\n" - " ```gleam\n" - " strict_zip([1, 2], [3])\n" - " // -> Error(Nil)\n" - " ```\n" - "\n" - " ```gleam\n" - " strict_zip([1], [3, 4])\n" - " // -> Error(Nil)\n" - " ```\n" - "\n" - " ```gleam\n" - " strict_zip([1, 2], [3, 4])\n" - " // -> Ok([#(1, 3), #(2, 4)])\n" - " ```\n" -). --spec strict_zip(list(AGP), list(AGR)) -> {ok, list({AGP, AGR})} | {error, nil}. -strict_zip(List, Other) -> - strict_zip_loop(List, Other, []). - --file("src/gleam/list.gleam", 1138). --spec unzip_loop(list({AHJ, AHK}), list(AHJ), list(AHK)) -> {list(AHJ), - list(AHK)}. -unzip_loop(Input, One, Other) -> - case Input of - [] -> - {lists:reverse(One), lists:reverse(Other)}; - - [{First_one, First_other} | Rest] -> - unzip_loop(Rest, [First_one | One], [First_other | Other]) - end. - --file("src/gleam/list.gleam", 1134). -?DOC( - " Takes a single list of 2-element tuples and returns two lists.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " unzip([#(1, 2), #(3, 4)])\n" - " // -> #([1, 3], [2, 4])\n" - " ```\n" - "\n" - " ```gleam\n" - " unzip([])\n" - " // -> #([], [])\n" - " ```\n" -). --spec unzip(list({AHE, AHF})) -> {list(AHE), list(AHF)}. -unzip(Input) -> - unzip_loop(Input, [], []). - --file("src/gleam/list.gleam", 1173). --spec intersperse_loop(list(AHT), AHT, list(AHT)) -> list(AHT). -intersperse_loop(List, Separator, Acc) -> - case List of - [] -> - lists:reverse(Acc); - - [First | Rest] -> - intersperse_loop(Rest, Separator, [First, Separator | Acc]) - end. - --file("src/gleam/list.gleam", 1166). -?DOC( - " Inserts a given value between each existing element in a given list.\n" - "\n" - " This function runs in linear time and copies the list.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " intersperse([1, 1, 1], 2)\n" - " // -> [1, 2, 1, 2, 1]\n" - " ```\n" - "\n" - " ```gleam\n" - " intersperse([], 2)\n" - " // -> []\n" - " ```\n" -). --spec intersperse(list(AHQ), AHQ) -> list(AHQ). -intersperse(List, Elem) -> - case List of - [] -> - List; - - [_] -> - List; - - [First | Rest] -> - intersperse_loop(Rest, Elem, [First]) - end. - --file("src/gleam/list.gleam", 1196). --spec unique_loop(list(AIA), gleam@dict:dict(AIA, nil), list(AIA)) -> list(AIA). -unique_loop(List, Seen, Acc) -> - case List of - [] -> - lists:reverse(Acc); - - [First | Rest] -> - case gleam@dict:has_key(Seen, First) of - true -> - unique_loop(Rest, Seen, Acc); - - false -> - unique_loop( - Rest, - gleam@dict:insert(Seen, First, nil), - [First | Acc] - ) - end - end. - --file("src/gleam/list.gleam", 1192). -?DOC( - " Removes any duplicate elements from a given list.\n" - "\n" - " This function returns in loglinear time.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " unique([1, 1, 1, 4, 7, 3, 3, 4])\n" - " // -> [1, 4, 7, 3]\n" - " ```\n" -). --spec unique(list(AHX)) -> list(AHX). -unique(List) -> - unique_loop(List, maps:new(), []). - --file("src/gleam/list.gleam", 1282). -?DOC( - " Given a list it returns slices of it that are locally sorted in ascending\n" - " order.\n" - "\n" - " Imagine you have this list:\n" - "\n" - " ```\n" - " [1, 2, 3, 2, 1, 0]\n" - " ^^^^^^^ ^^^^^^^ This is a slice in descending order\n" - " |\n" - " | This is a slice that is sorted in ascending order\n" - " ```\n" - "\n" - " So the produced result will contain these two slices, each one sorted in\n" - " ascending order: `[[1, 2, 3], [0, 1, 2]]`.\n" - "\n" - " - `growing` is an accumulator with the current slice being grown\n" - " - `direction` is the growing direction of the slice being grown, it could\n" - " either be ascending or strictly descending\n" - " - `prev` is the previous element that needs to be added to the growing slice\n" - " it is carried around to check whether we have to keep growing the current\n" - " slice or not\n" - " - `acc` is the accumulator containing the slices sorted in ascending order\n" -). --spec sequences( - list(AIJ), - fun((AIJ, AIJ) -> gleam@order:order()), - list(AIJ), - sorting(), - AIJ, - list(list(AIJ)) -) -> list(list(AIJ)). -sequences(List, Compare, Growing, Direction, Prev, Acc) -> - Growing@1 = [Prev | Growing], - case List of - [] -> - case Direction of - ascending -> - [lists:reverse(Growing@1) | Acc]; - - descending -> - [Growing@1 | Acc] - end; - - [New | Rest] -> - case {Compare(Prev, New), Direction} of - {gt, descending} -> - sequences(Rest, Compare, Growing@1, Direction, New, Acc); - - {lt, ascending} -> - sequences(Rest, Compare, Growing@1, Direction, New, Acc); - - {eq, ascending} -> - sequences(Rest, Compare, Growing@1, Direction, New, Acc); - - {gt, ascending} -> - Acc@1 = case Direction of - ascending -> - [lists:reverse(Growing@1) | Acc]; - - descending -> - [Growing@1 | Acc] - end, - case Rest of - [] -> - [[New] | Acc@1]; - - [Next | Rest@1] -> - Direction@1 = case Compare(New, Next) of - lt -> - ascending; - - eq -> - ascending; - - gt -> - descending - end, - sequences( - Rest@1, - Compare, - [New], - Direction@1, - Next, - Acc@1 - ) - end; - - {lt, descending} -> - Acc@1 = case Direction of - ascending -> - [lists:reverse(Growing@1) | Acc]; - - descending -> - [Growing@1 | Acc] - end, - case Rest of - [] -> - [[New] | Acc@1]; - - [Next | Rest@1] -> - Direction@1 = case Compare(New, Next) of - lt -> - ascending; - - eq -> - ascending; - - gt -> - descending - end, - sequences( - Rest@1, - Compare, - [New], - Direction@1, - Next, - Acc@1 - ) - end; - - {eq, descending} -> - Acc@1 = case Direction of - ascending -> - [lists:reverse(Growing@1) | Acc]; - - descending -> - [Growing@1 | Acc] - end, - case Rest of - [] -> - [[New] | Acc@1]; - - [Next | Rest@1] -> - Direction@1 = case Compare(New, Next) of - lt -> - ascending; - - eq -> - ascending; - - gt -> - descending - end, - sequences( - Rest@1, - Compare, - [New], - Direction@1, - Next, - Acc@1 - ) - end - end - end. - --file("src/gleam/list.gleam", 1430). -?DOC( - " Merges two lists sorted in ascending order into a single list sorted in\n" - " descending order according to the given comparator function.\n" - "\n" - " This reversing of the sort order is not avoidable if we want to implement\n" - " merge as a tail recursive function. We could reverse the accumulator before\n" - " returning it but that would end up being less efficient; so the merging\n" - " algorithm has to play around this.\n" -). --spec merge_ascendings( - list(AJG), - list(AJG), - fun((AJG, AJG) -> gleam@order:order()), - list(AJG) -) -> list(AJG). -merge_ascendings(List1, List2, Compare, Acc) -> - case {List1, List2} of - {[], List} -> - lists:reverse(List, Acc); - - {List, []} -> - lists:reverse(List, Acc); - - {[First1 | Rest1], [First2 | Rest2]} -> - case Compare(First1, First2) of - lt -> - merge_ascendings(Rest1, List2, Compare, [First1 | Acc]); - - gt -> - merge_ascendings(List1, Rest2, Compare, [First2 | Acc]); - - eq -> - merge_ascendings(List1, Rest2, Compare, [First2 | Acc]) - end - end. - --file("src/gleam/list.gleam", 1383). -?DOC( - " Given a list of ascending lists, it merges adjacent pairs into a single\n" - " descending list, halving their number.\n" - " It returns a list of the remaining descending lists.\n" -). --spec merge_ascending_pairs( - list(list(AIU)), - fun((AIU, AIU) -> gleam@order:order()), - list(list(AIU)) -) -> list(list(AIU)). -merge_ascending_pairs(Sequences, Compare, Acc) -> - case Sequences of - [] -> - lists:reverse(Acc); - - [Sequence] -> - lists:reverse([lists:reverse(Sequence) | Acc]); - - [Ascending1, Ascending2 | Rest] -> - Descending = merge_ascendings(Ascending1, Ascending2, Compare, []), - merge_ascending_pairs(Rest, Compare, [Descending | Acc]) - end. - --file("src/gleam/list.gleam", 1457). -?DOC( - " This is exactly the same as merge_ascendings but mirrored: it merges two\n" - " lists sorted in descending order into a single list sorted in ascending\n" - " order according to the given comparator function.\n" - "\n" - " This reversing of the sort order is not avoidable if we want to implement\n" - " merge as a tail recursive function. We could reverse the accumulator before\n" - " returning it but that would end up being less efficient; so the merging\n" - " algorithm has to play around this.\n" -). --spec merge_descendings( - list(AJL), - list(AJL), - fun((AJL, AJL) -> gleam@order:order()), - list(AJL) -) -> list(AJL). -merge_descendings(List1, List2, Compare, Acc) -> - case {List1, List2} of - {[], List} -> - lists:reverse(List, Acc); - - {List, []} -> - lists:reverse(List, Acc); - - {[First1 | Rest1], [First2 | Rest2]} -> - case Compare(First1, First2) of - lt -> - merge_descendings(List1, Rest2, Compare, [First2 | Acc]); - - gt -> - merge_descendings(Rest1, List2, Compare, [First1 | Acc]); - - eq -> - merge_descendings(Rest1, List2, Compare, [First1 | Acc]) - end - end. - --file("src/gleam/list.gleam", 1405). -?DOC(" This is the same as merge_ascending_pairs but flipped for descending lists.\n"). --spec merge_descending_pairs( - list(list(AJA)), - fun((AJA, AJA) -> gleam@order:order()), - list(list(AJA)) -) -> list(list(AJA)). -merge_descending_pairs(Sequences, Compare, Acc) -> - case Sequences of - [] -> - lists:reverse(Acc); - - [Sequence] -> - lists:reverse([lists:reverse(Sequence) | Acc]); - - [Descending1, Descending2 | Rest] -> - Ascending = merge_descendings(Descending1, Descending2, Compare, []), - merge_descending_pairs(Rest, Compare, [Ascending | Acc]) - end. - --file("src/gleam/list.gleam", 1349). -?DOC( - " Given some some sorted sequences (assumed to be sorted in `direction`) it\n" - " merges them all together until we're left with just a list sorted in\n" - " ascending order.\n" -). --spec merge_all( - list(list(AIQ)), - sorting(), - fun((AIQ, AIQ) -> gleam@order:order()) -) -> list(AIQ). -merge_all(Sequences, Direction, Compare) -> - case {Sequences, Direction} of - {[], _} -> - []; - - {[Sequence], ascending} -> - Sequence; - - {[Sequence@1], descending} -> - lists:reverse(Sequence@1); - - {_, ascending} -> - Sequences@1 = merge_ascending_pairs(Sequences, Compare, []), - merge_all(Sequences@1, descending, Compare); - - {_, descending} -> - Sequences@2 = merge_descending_pairs(Sequences, Compare, []), - merge_all(Sequences@2, ascending, Compare) - end. - --file("src/gleam/list.gleam", 1220). -?DOC( - " Sorts from smallest to largest based upon the ordering specified by a given\n" - " function.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " import gleam/int\n" - "\n" - " sort([4, 3, 6, 5, 4, 1, 2], by: int.compare)\n" - " // -> [1, 2, 3, 4, 4, 5, 6]\n" - " ```\n" -). --spec sort(list(AIG), fun((AIG, AIG) -> gleam@order:order())) -> list(AIG). -sort(List, Compare) -> - case List of - [] -> - []; - - [X] -> - [X]; - - [X@1, Y | Rest] -> - Direction = case Compare(X@1, Y) of - lt -> - ascending; - - eq -> - ascending; - - gt -> - descending - end, - Sequences = sequences(Rest, Compare, [X@1], Direction, Y, []), - merge_all(Sequences, ascending, Compare) - end. - --file("src/gleam/list.gleam", 1497). --spec range_loop(integer(), integer(), list(integer())) -> list(integer()). -range_loop(Start, Stop, Acc) -> - case gleam@int:compare(Start, Stop) of - eq -> - [Stop | Acc]; - - gt -> - range_loop(Start, Stop + 1, [Stop | Acc]); - - lt -> - range_loop(Start, Stop - 1, [Stop | Acc]) - end. - --file("src/gleam/list.gleam", 1493). -?DOC( - " Creates a list of ints ranging from a given start and finish.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " range(0, 0)\n" - " // -> [0]\n" - " ```\n" - "\n" - " ```gleam\n" - " range(0, 5)\n" - " // -> [0, 1, 2, 3, 4, 5]\n" - " ```\n" - "\n" - " ```gleam\n" - " range(1, -5)\n" - " // -> [1, 0, -1, -2, -3, -4, -5]\n" - " ```\n" -). --spec range(integer(), integer()) -> list(integer()). -range(Start, Stop) -> - range_loop(Start, Stop, []). - --file("src/gleam/list.gleam", 1523). --spec repeat_loop(AJV, integer(), list(AJV)) -> list(AJV). -repeat_loop(Item, Times, Acc) -> - case Times =< 0 of - true -> - Acc; - - false -> - repeat_loop(Item, Times - 1, [Item | Acc]) - end. - --file("src/gleam/list.gleam", 1519). -?DOC( - " Builds a list of a given value a given number of times.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " repeat(\"a\", times: 0)\n" - " // -> []\n" - " ```\n" - "\n" - " ```gleam\n" - " repeat(\"a\", times: 5)\n" - " // -> [\"a\", \"a\", \"a\", \"a\", \"a\"]\n" - " ```\n" -). --spec repeat(AJT, integer()) -> list(AJT). -repeat(A, Times) -> - repeat_loop(A, Times, []). - --file("src/gleam/list.gleam", 1556). --spec split_loop(list(AKC), integer(), list(AKC)) -> {list(AKC), list(AKC)}. -split_loop(List, N, Taken) -> - case N =< 0 of - true -> - {lists:reverse(Taken), List}; - - false -> - case List of - [] -> - {lists:reverse(Taken), []}; - - [First | Rest] -> - split_loop(Rest, N - 1, [First | Taken]) - end - end. - --file("src/gleam/list.gleam", 1552). -?DOC( - " Splits a list in two before the given index.\n" - "\n" - " If the list is not long enough to have the given index the before list will\n" - " be the input list, and the after list will be empty.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " split([6, 7, 8, 9], 0)\n" - " // -> #([], [6, 7, 8, 9])\n" - " ```\n" - "\n" - " ```gleam\n" - " split([6, 7, 8, 9], 2)\n" - " // -> #([6, 7], [8, 9])\n" - " ```\n" - "\n" - " ```gleam\n" - " split([6, 7, 8, 9], 4)\n" - " // -> #([6, 7, 8, 9], [])\n" - " ```\n" -). --spec split(list(AJY), integer()) -> {list(AJY), list(AJY)}. -split(List, Index) -> - split_loop(List, Index, []). - --file("src/gleam/list.gleam", 1592). --spec split_while_loop(list(AKL), fun((AKL) -> boolean()), list(AKL)) -> {list(AKL), - list(AKL)}. -split_while_loop(List, F, Acc) -> - case List of - [] -> - {lists:reverse(Acc), []}; - - [First | Rest] -> - case F(First) of - true -> - split_while_loop(Rest, F, [First | Acc]); - - false -> - {lists:reverse(Acc), List} - end - end. - --file("src/gleam/list.gleam", 1585). -?DOC( - " Splits a list in two before the first element that a given function returns\n" - " `False` for.\n" - "\n" - " If the function returns `True` for all elements the first list will be the\n" - " input list, and the second list will be empty.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " split_while([1, 2, 3, 4, 5], fn(x) { x <= 3 })\n" - " // -> #([1, 2, 3], [4, 5])\n" - " ```\n" - "\n" - " ```gleam\n" - " split_while([1, 2, 3, 4, 5], fn(x) { x <= 5 })\n" - " // -> #([1, 2, 3, 4, 5], [])\n" - " ```\n" -). --spec split_while(list(AKH), fun((AKH) -> boolean())) -> {list(AKH), list(AKH)}. -split_while(List, Predicate) -> - split_while_loop(List, Predicate, []). - --file("src/gleam/list.gleam", 1632). -?DOC( - " Given a list of 2-element tuples, finds the first tuple that has a given\n" - " key as the first element and returns the second element.\n" - "\n" - " If no tuple is found with the given key then `Error(Nil)` is returned.\n" - "\n" - " This function may be useful for interacting with Erlang code where lists of\n" - " tuples are common.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " key_find([#(\"a\", 0), #(\"b\", 1)], \"a\")\n" - " // -> Ok(0)\n" - " ```\n" - "\n" - " ```gleam\n" - " key_find([#(\"a\", 0), #(\"b\", 1)], \"b\")\n" - " // -> Ok(1)\n" - " ```\n" - "\n" - " ```gleam\n" - " key_find([#(\"a\", 0), #(\"b\", 1)], \"c\")\n" - " // -> Error(Nil)\n" - " ```\n" -). --spec key_find(list({AKQ, AKR}), AKQ) -> {ok, AKR} | {error, nil}. -key_find(Keyword_list, Desired_key) -> - find_map( - Keyword_list, - fun(Keyword) -> - {Key, Value} = Keyword, - case Key =:= Desired_key of - true -> - {ok, Value}; - - false -> - {error, nil} - end - end - ). - --file("src/gleam/list.gleam", 1663). -?DOC( - " Given a list of 2-element tuples, finds all tuples that have a given\n" - " key as the first element and returns the second element.\n" - "\n" - " This function may be useful for interacting with Erlang code where lists of\n" - " tuples are common.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " key_filter([#(\"a\", 0), #(\"b\", 1), #(\"a\", 2)], \"a\")\n" - " // -> [0, 2]\n" - " ```\n" - "\n" - " ```gleam\n" - " key_filter([#(\"a\", 0), #(\"b\", 1)], \"c\")\n" - " // -> []\n" - " ```\n" -). --spec key_filter(list({AKV, AKW}), AKV) -> list(AKW). -key_filter(Keyword_list, Desired_key) -> - filter_map( - Keyword_list, - fun(Keyword) -> - {Key, Value} = Keyword, - case Key =:= Desired_key of - true -> - {ok, Value}; - - false -> - {error, nil} - end - end - ). - --file("src/gleam/list.gleam", 1703). --spec key_pop_loop(list({ALF, ALG}), ALF, list({ALF, ALG})) -> {ok, - {ALG, list({ALF, ALG})}} | - {error, nil}. -key_pop_loop(List, Key, Checked) -> - case List of - [] -> - {error, nil}; - - [{K, V} | Rest] when K =:= Key -> - {ok, {V, lists:reverse(Checked, Rest)}}; - - [First | Rest@1] -> - key_pop_loop(Rest@1, Key, [First | Checked]) - end. - --file("src/gleam/list.gleam", 1699). -?DOC( - " Given a list of 2-element tuples, finds the first tuple that has a given\n" - " key as the first element. This function will return the second element\n" - " of the found tuple and list with tuple removed.\n" - "\n" - " If no tuple is found with the given key then `Error(Nil)` is returned.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " key_pop([#(\"a\", 0), #(\"b\", 1)], \"a\")\n" - " // -> Ok(#(0, [#(\"b\", 1)]))\n" - " ```\n" - "\n" - " ```gleam\n" - " key_pop([#(\"a\", 0), #(\"b\", 1)], \"b\")\n" - " // -> Ok(#(1, [#(\"a\", 0)]))\n" - " ```\n" - "\n" - " ```gleam\n" - " key_pop([#(\"a\", 0), #(\"b\", 1)], \"c\")\n" - " // -> Error(Nil)\n" - " ```\n" -). --spec key_pop(list({AKZ, ALA}), AKZ) -> {ok, {ALA, list({AKZ, ALA})}} | - {error, nil}. -key_pop(List, Key) -> - key_pop_loop(List, Key, []). - --file("src/gleam/list.gleam", 1737). --spec key_set_loop(list({ALQ, ALR}), ALQ, ALR, list({ALQ, ALR})) -> list({ALQ, - ALR}). -key_set_loop(List, Key, Value, Inspected) -> - case List of - [{K, _} | Rest] when K =:= Key -> - lists:reverse(Inspected, [{K, Value} | Rest]); - - [First | Rest@1] -> - key_set_loop(Rest@1, Key, Value, [First | Inspected]); - - [] -> - lists:reverse([{Key, Value} | Inspected]) - end. - --file("src/gleam/list.gleam", 1733). -?DOC( - " Given a list of 2-element tuples, inserts a key and value into the list.\n" - "\n" - " If there was already a tuple with the key then it is replaced, otherwise it\n" - " is added to the end of the list.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " key_set([#(5, 0), #(4, 1)], 4, 100)\n" - " // -> [#(5, 0), #(4, 100)]\n" - " ```\n" - "\n" - " ```gleam\n" - " key_set([#(5, 0), #(4, 1)], 1, 100)\n" - " // -> [#(5, 0), #(4, 1), #(1, 100)]\n" - " ```\n" -). --spec key_set(list({ALM, ALN}), ALM, ALN) -> list({ALM, ALN}). -key_set(List, Key, Value) -> - key_set_loop(List, Key, Value, []). - --file("src/gleam/list.gleam", 1765). -?DOC( - " Calls a function for each element in a list, discarding the return value.\n" - "\n" - " Useful for calling a side effect for every item of a list.\n" - "\n" - " ```gleam\n" - " import gleam/io\n" - "\n" - " each([\"1\", \"2\", \"3\"], io.println)\n" - " // -> Nil\n" - " // 1\n" - " // 2\n" - " // 3\n" - " ```\n" -). --spec each(list(ALV), fun((ALV) -> any())) -> nil. -each(List, F) -> - case List of - [] -> - nil; - - [First | Rest] -> - F(First), - each(Rest, F) - end. - --file("src/gleam/list.gleam", 1791). -?DOC( - " Calls a `Result` returning function for each element in a list, discarding\n" - " the return value. If the function returns `Error` then the iteration is\n" - " stopped and the error is returned.\n" - "\n" - " Useful for calling a side effect for every item of a list.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " try_each(\n" - " over: [1, 2, 3],\n" - " with: function_that_might_fail,\n" - " )\n" - " // -> Ok(Nil)\n" - " ```\n" -). --spec try_each(list(ALY), fun((ALY) -> {ok, any()} | {error, AMB})) -> {ok, nil} | - {error, AMB}. -try_each(List, Fun) -> - case List of - [] -> - {ok, nil}; - - [First | Rest] -> - case Fun(First) of - {ok, _} -> - try_each(Rest, Fun); - - {error, E} -> - {error, E} - end - end. - --file("src/gleam/list.gleam", 1824). --spec partition_loop(list(BFR), fun((BFR) -> boolean()), list(BFR), list(BFR)) -> {list(BFR), - list(BFR)}. -partition_loop(List, Categorise, Trues, Falses) -> - case List of - [] -> - {lists:reverse(Trues), lists:reverse(Falses)}; - - [First | Rest] -> - case Categorise(First) of - true -> - partition_loop(Rest, Categorise, [First | Trues], Falses); - - false -> - partition_loop(Rest, Categorise, Trues, [First | Falses]) - end - end. - --file("src/gleam/list.gleam", 1817). -?DOC( - " Partitions a list into a tuple/pair of lists\n" - " by a given categorisation function.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " import gleam/int\n" - "\n" - " [1, 2, 3, 4, 5] |> partition(int.is_odd)\n" - " // -> #([1, 3, 5], [2, 4])\n" - " ```\n" -). --spec partition(list(AMG), fun((AMG) -> boolean())) -> {list(AMG), list(AMG)}. -partition(List, Categorise) -> - partition_loop(List, Categorise, [], []). - --file("src/gleam/list.gleam", 1904). --spec window_loop(list(list(ANN)), list(ANN), integer()) -> list(list(ANN)). -window_loop(Acc, List, N) -> - Window = take(List, N), - case erlang:length(Window) =:= N of - true -> - window_loop([Window | Acc], drop(List, 1), N); - - false -> - lists:reverse(Acc) - end. - --file("src/gleam/list.gleam", 1897). -?DOC( - " Returns a list of sliding windows.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " window([1,2,3,4,5], 3)\n" - " // -> [[1, 2, 3], [2, 3, 4], [3, 4, 5]]\n" - " ```\n" - "\n" - " ```gleam\n" - " window([1, 2], 4)\n" - " // -> []\n" - " ```\n" -). --spec window(list(ANJ), integer()) -> list(list(ANJ)). -window(List, N) -> - case N =< 0 of - true -> - []; - - false -> - window_loop([], List, N) - end. - --file("src/gleam/list.gleam", 1927). -?DOC( - " Returns a list of tuples containing two contiguous elements.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " window_by_2([1,2,3,4])\n" - " // -> [#(1, 2), #(2, 3), #(3, 4)]\n" - " ```\n" - "\n" - " ```gleam\n" - " window_by_2([1])\n" - " // -> []\n" - " ```\n" -). --spec window_by_2(list(ANT)) -> list({ANT, ANT}). -window_by_2(List) -> - zip(List, drop(List, 1)). - --file("src/gleam/list.gleam", 1940). -?DOC( - " Drops the first elements in a given list for which the predicate function returns `True`.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " drop_while([1, 2, 3, 4], fn (x) { x < 3 })\n" - " // -> [3, 4]\n" - " ```\n" -). --spec drop_while(list(ANW), fun((ANW) -> boolean())) -> list(ANW). -drop_while(List, Predicate) -> - case List of - [] -> - []; - - [First | Rest] -> - case Predicate(First) of - true -> - drop_while(Rest, Predicate); - - false -> - [First | Rest] - end - end. - --file("src/gleam/list.gleam", 1970). --spec take_while_loop(list(AOC), fun((AOC) -> boolean()), list(AOC)) -> list(AOC). -take_while_loop(List, Predicate, Acc) -> - case List of - [] -> - lists:reverse(Acc); - - [First | Rest] -> - case Predicate(First) of - true -> - take_while_loop(Rest, Predicate, [First | Acc]); - - false -> - lists:reverse(Acc) - end - end. - --file("src/gleam/list.gleam", 1963). -?DOC( - " Takes the first elements in a given list for which the predicate function returns `True`.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " take_while([1, 2, 3, 2, 4], fn (x) { x < 3 })\n" - " // -> [1, 2]\n" - " ```\n" -). --spec take_while(list(ANZ), fun((ANZ) -> boolean())) -> list(ANZ). -take_while(List, Predicate) -> - take_while_loop(List, Predicate, []). - --file("src/gleam/list.gleam", 2002). --spec chunk_loop(list(AOL), fun((AOL) -> AON), AON, list(AOL), list(list(AOL))) -> list(list(AOL)). -chunk_loop(List, F, Previous_key, Current_chunk, Acc) -> - case List of - [First | Rest] -> - Key = F(First), - case Key =:= Previous_key of - true -> - chunk_loop(Rest, F, Key, [First | Current_chunk], Acc); - - false -> - New_acc = [lists:reverse(Current_chunk) | Acc], - chunk_loop(Rest, F, Key, [First], New_acc) - end; - - [] -> - lists:reverse([lists:reverse(Current_chunk) | Acc]) - end. - --file("src/gleam/list.gleam", 1995). -?DOC( - " Returns a list of chunks in which\n" - " the return value of calling `f` on each element is the same.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " [1, 2, 2, 3, 4, 4, 6, 7, 7] |> chunk(by: fn(n) { n % 2 })\n" - " // -> [[1], [2, 2], [3], [4, 4, 6], [7, 7]]\n" - " ```\n" -). --spec chunk(list(AOG), fun((AOG) -> any())) -> list(list(AOG)). -chunk(List, F) -> - case List of - [] -> - []; - - [First | Rest] -> - chunk_loop(Rest, F, F(First), [First], []) - end. - --file("src/gleam/list.gleam", 2047). --spec sized_chunk_loop( - list(AOX), - integer(), - integer(), - list(AOX), - list(list(AOX)) -) -> list(list(AOX)). -sized_chunk_loop(List, Count, Left, Current_chunk, Acc) -> - case List of - [] -> - case Current_chunk of - [] -> - lists:reverse(Acc); - - Remaining -> - lists:reverse([lists:reverse(Remaining) | Acc]) - end; - - [First | Rest] -> - Chunk = [First | Current_chunk], - case Left > 1 of - true -> - sized_chunk_loop(Rest, Count, Left - 1, Chunk, Acc); - - false -> - sized_chunk_loop( - Rest, - Count, - Count, - [], - [lists:reverse(Chunk) | Acc] - ) - end - end. - --file("src/gleam/list.gleam", 2043). -?DOC( - " Returns a list of chunks containing `count` elements each.\n" - "\n" - " If the last chunk does not have `count` elements, it is instead\n" - " a partial chunk, with less than `count` elements.\n" - "\n" - " For any `count` less than 1 this function behaves as if it was set to 1.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " [1, 2, 3, 4, 5, 6] |> sized_chunk(into: 2)\n" - " // -> [[1, 2], [3, 4], [5, 6]]\n" - " ```\n" - "\n" - " ```gleam\n" - " [1, 2, 3, 4, 5, 6, 7, 8] |> sized_chunk(into: 3)\n" - " // -> [[1, 2, 3], [4, 5, 6], [7, 8]]\n" - " ```\n" -). --spec sized_chunk(list(AOT), integer()) -> list(list(AOT)). -sized_chunk(List, Count) -> - sized_chunk_loop(List, Count, Count, [], []). - --file("src/gleam/list.gleam", 2091). -?DOC( - " This function acts similar to fold, but does not take an initial state.\n" - " Instead, it starts from the first element in the list\n" - " and combines it with each subsequent element in turn using the given\n" - " function. The function is called as `fun(accumulator, current_element)`.\n" - "\n" - " Returns `Ok` to indicate a successful run, and `Error` if called on an\n" - " empty list.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " [] |> reduce(fn(acc, x) { acc + x })\n" - " // -> Error(Nil)\n" - " ```\n" - "\n" - " ```gleam\n" - " [1, 2, 3, 4, 5] |> reduce(fn(acc, x) { acc + x })\n" - " // -> Ok(15)\n" - " ```\n" -). --spec reduce(list(APE), fun((APE, APE) -> APE)) -> {ok, APE} | {error, nil}. -reduce(List, Fun) -> - case List of - [] -> - {error, nil}; - - [First | Rest] -> - {ok, fold(Rest, First, Fun)} - end. - --file("src/gleam/list.gleam", 2115). --spec scan_loop(list(APM), APO, list(APO), fun((APO, APM) -> APO)) -> list(APO). -scan_loop(List, Accumulator, Accumulated, Fun) -> - case List of - [] -> - lists:reverse(Accumulated); - - [First | Rest] -> - Next = Fun(Accumulator, First), - scan_loop(Rest, Next, [Next | Accumulated], Fun) - end. - --file("src/gleam/list.gleam", 2107). -?DOC( - " Similar to `fold`, but yields the state of the accumulator at each stage.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " scan(over: [1, 2, 3], from: 100, with: fn(acc, i) { acc + i })\n" - " // -> [101, 103, 106]\n" - " ```\n" -). --spec scan(list(API), APK, fun((APK, API) -> APK)) -> list(APK). -scan(List, Initial, Fun) -> - scan_loop(List, Initial, [], Fun). - --file("src/gleam/list.gleam", 2148). -?DOC( - " Returns the last element in the given list.\n" - "\n" - " Returns `Error(Nil)` if the list is empty.\n" - "\n" - " This function runs in linear time.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " last([])\n" - " // -> Error(Nil)\n" - " ```\n" - "\n" - " ```gleam\n" - " last([1, 2, 3, 4, 5])\n" - " // -> Ok(5)\n" - " ```\n" -). --spec last(list(APR)) -> {ok, APR} | {error, nil}. -last(List) -> - case List of - [] -> - {error, nil}; - - [Last] -> - {ok, Last}; - - [_ | Rest] -> - last(Rest) - end. - --file("src/gleam/list.gleam", 2170). -?DOC( - " Return unique combinations of elements in the list.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " combinations([1, 2, 3], 2)\n" - " // -> [[1, 2], [1, 3], [2, 3]]\n" - " ```\n" - "\n" - " ```gleam\n" - " combinations([1, 2, 3, 4], 3)\n" - " // -> [[1, 2, 3], [1, 2, 4], [1, 3, 4], [2, 3, 4]]\n" - " ```\n" -). --spec combinations(list(APV), integer()) -> list(list(APV)). -combinations(Items, N) -> - case {N, Items} of - {0, _} -> - [[]]; - - {_, []} -> - []; - - {_, [First | Rest]} -> - _pipe = Rest, - _pipe@1 = combinations(_pipe, N - 1), - _pipe@2 = map( - _pipe@1, - fun(Combination) -> [First | Combination] end - ), - _pipe@3 = lists:reverse(_pipe@2), - fold(_pipe@3, combinations(Rest, N), fun(Acc, C) -> [C | Acc] end) - end. - --file("src/gleam/list.gleam", 2196). --spec combination_pairs_loop(list(AQC), list({AQC, AQC})) -> list({AQC, AQC}). -combination_pairs_loop(Items, Acc) -> - case Items of - [] -> - lists:reverse(Acc); - - [First | Rest] -> - First_combinations = map(Rest, fun(Other) -> {First, Other} end), - Acc@1 = lists:reverse(First_combinations, Acc), - combination_pairs_loop(Rest, Acc@1) - end. - --file("src/gleam/list.gleam", 2192). -?DOC( - " Return unique pair combinations of elements in the list.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " combination_pairs([1, 2, 3])\n" - " // -> [#(1, 2), #(1, 3), #(2, 3)]\n" - " ```\n" -). --spec combination_pairs(list(APZ)) -> list({APZ, APZ}). -combination_pairs(Items) -> - combination_pairs_loop(Items, []). - --file("src/gleam/list.gleam", 2252). --spec take_firsts(list(list(AQW)), list(AQW), list(list(AQW))) -> {list(AQW), - list(list(AQW))}. -take_firsts(Rows, Column, Remaining_rows) -> - case Rows of - [] -> - {lists:reverse(Column), lists:reverse(Remaining_rows)}; - - [[] | Rest] -> - take_firsts(Rest, Column, Remaining_rows); - - [[First | Remaining_row] | Rest_rows] -> - Remaining_rows@1 = [Remaining_row | Remaining_rows], - take_firsts(Rest_rows, [First | Column], Remaining_rows@1) - end. - --file("src/gleam/list.gleam", 2239). --spec transpose_loop(list(list(AQP)), list(list(AQP))) -> list(list(AQP)). -transpose_loop(Rows, Columns) -> - case Rows of - [] -> - lists:reverse(Columns); - - _ -> - {Column, Rest} = take_firsts(Rows, [], []), - case Column of - [_ | _] -> - transpose_loop(Rest, [Column | Columns]); - - [] -> - transpose_loop(Rest, Columns) - end - end. - --file("src/gleam/list.gleam", 2235). -?DOC( - " Transpose rows and columns of the list of lists.\n" - "\n" - " Notice: This function is not tail recursive,\n" - " and thus may exceed stack size if called,\n" - " with large lists (on the JavaScript target).\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " transpose([[1, 2, 3], [101, 102, 103]])\n" - " // -> [[1, 101], [2, 102], [3, 103]]\n" - " ```\n" -). --spec transpose(list(list(AQK))) -> list(list(AQK)). -transpose(List_of_lists) -> - transpose_loop(List_of_lists, []). - --file("src/gleam/list.gleam", 2216). -?DOC( - " Make a list alternating the elements from the given lists\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " interleave([[1, 2], [101, 102], [201, 202]])\n" - " // -> [1, 101, 201, 2, 102, 202]\n" - " ```\n" -). --spec interleave(list(list(AQG))) -> list(AQG). -interleave(List) -> - _pipe = List, - _pipe@1 = transpose(_pipe), - lists:append(_pipe@1). - --file("src/gleam/list.gleam", 2285). --spec shuffle_pair_unwrap_loop(list({float(), ARI}), list(ARI)) -> list(ARI). -shuffle_pair_unwrap_loop(List, Acc) -> - case List of - [] -> - Acc; - - [Elem_pair | Enumerable] -> - shuffle_pair_unwrap_loop( - Enumerable, - [erlang:element(2, Elem_pair) | Acc] - ) - end. - --file("src/gleam/list.gleam", 2293). --spec do_shuffle_by_pair_indexes(list({float(), ARM})) -> list({float(), ARM}). -do_shuffle_by_pair_indexes(List_of_pairs) -> - sort( - List_of_pairs, - fun(A_pair, B_pair) -> - gleam@float:compare( - erlang:element(1, A_pair), - erlang:element(1, B_pair) - ) - end - ). - --file("src/gleam/list.gleam", 2278). -?DOC( - " Takes a list, randomly sorts all items and returns the shuffled list.\n" - "\n" - " This function uses `float.random` to decide the order of the elements.\n" - "\n" - " ## Example\n" - "\n" - " ```gleam\n" - " range(1, 10) |> shuffle()\n" - " // -> [1, 6, 9, 10, 3, 8, 4, 2, 7, 5]\n" - " ```\n" -). --spec shuffle(list(ARF)) -> list(ARF). -shuffle(List) -> - _pipe = List, - _pipe@1 = fold(_pipe, [], fun(Acc, A) -> [{rand:uniform(), A} | Acc] end), - _pipe@2 = do_shuffle_by_pair_indexes(_pipe@1), - shuffle_pair_unwrap_loop(_pipe@2, []). - --file("src/gleam/list.gleam", 2325). --spec max_loop(list(ARW), fun((ARW, ARW) -> gleam@order:order()), ARW) -> ARW. -max_loop(List, Compare, Max) -> - case List of - [] -> - Max; - - [First | Rest] -> - case Compare(First, Max) of - gt -> - max_loop(Rest, Compare, First); - - lt -> - max_loop(Rest, Compare, Max); - - eq -> - max_loop(Rest, Compare, Max) - end - end. - --file("src/gleam/list.gleam", 2315). -?DOC( - " Takes a list and a comparator, and returns the maximum element in the list\n" - "\n" - "\n" - " ## Example\n" - "\n" - " ```gleam\n" - " range(1, 10) |> list.max(int.compare)\n" - " // -> Ok(10)\n" - " ```\n" - "\n" - " ```gleam\n" - " [\"a\", \"c\", \"b\"] |> list.max(string.compare)\n" - " // -> Ok(\"c\")\n" - " ```\n" -). --spec max(list(ARP), fun((ARP, ARP) -> gleam@order:order())) -> {ok, ARP} | - {error, nil}. -max(List, Compare) -> - case List of - [] -> - {error, nil}; - - [First | Rest] -> - {ok, max_loop(Rest, Compare, First)} - end. - --file("src/gleam/list.gleam", 2406). --spec build_reservoir_loop( - list(ASL), - integer(), - gleam@dict:dict(integer(), ASL) -) -> {gleam@dict:dict(integer(), ASL), list(ASL)}. -build_reservoir_loop(List, Size, Reservoir) -> - Reservoir_size = maps:size(Reservoir), - case Reservoir_size >= Size of - true -> - {Reservoir, List}; - - false -> - case List of - [] -> - {Reservoir, []}; - - [First | Rest] -> - Reservoir@1 = gleam@dict:insert( - Reservoir, - Reservoir_size, - First - ), - build_reservoir_loop(Rest, Size, Reservoir@1) - end - end. - --file("src/gleam/list.gleam", 2402). -?DOC( - " Builds the initial reservoir used by Algorithm L.\n" - " This is a dictionary with keys ranging from `0` up to `n - 1` where each\n" - " value is the corresponding element at that position in `list`.\n" - "\n" - " This also returns the remaining elements of `list` that didn't end up in\n" - " the reservoir.\n" -). --spec build_reservoir(list(ASG), integer()) -> {gleam@dict:dict(integer(), ASG), - list(ASG)}. -build_reservoir(List, N) -> - build_reservoir_loop(List, N, maps:new()). - --file("src/gleam/list.gleam", 2390). --spec log_random() -> float(). -log_random() -> - Random@1 = case gleam@float:logarithm( - rand:uniform() + 2.2250738585072014e-308 - ) of - {ok, Random} -> Random; - _assert_fail -> - erlang:error(#{gleam_error => let_assert, - message => <<"Pattern match failed, no pattern matched the value."/utf8>>, - file => <>, - module => <<"gleam/list"/utf8>>, - function => <<"log_random"/utf8>>, - line => 2391, - value => _assert_fail, - start => 56078, - 'end' => 56149, - pattern_start => 56089, - pattern_end => 56099}) - end, - Random@1. - --file("src/gleam/list.gleam", 2367). --spec sample_loop( - list(ASA), - gleam@dict:dict(integer(), ASA), - integer(), - float() -) -> gleam@dict:dict(integer(), ASA). -sample_loop(List, Reservoir, N, W) -> - Skip = begin - Log@1 = case gleam@float:logarithm(1.0 - W) of - {ok, Log} -> Log; - _assert_fail -> - erlang:error(#{gleam_error => let_assert, - message => <<"Pattern match failed, no pattern matched the value."/utf8>>, - file => <>, - module => <<"gleam/list"/utf8>>, - function => <<"sample_loop"/utf8>>, - line => 2374, - value => _assert_fail, - start => 55639, - 'end' => 55685, - pattern_start => 55650, - pattern_end => 55657}) - end, - erlang:round(math:floor(case Log@1 of - +0.0 -> +0.0; - -0.0 -> -0.0; - Gleam@denominator -> log_random() / Gleam@denominator - end)) - end, - case drop(List, Skip) of - [] -> - Reservoir; - - [First | Rest] -> - Reservoir@1 = gleam@dict:insert( - Reservoir, - gleam@int:random(N), - First - ), - W@1 = W * math:exp(case erlang:float(N) of - +0.0 -> +0.0; - -0.0 -> -0.0; - Gleam@denominator@1 -> log_random() / Gleam@denominator@1 - end), - sample_loop(Rest, Reservoir@1, N, W@1) - end. - --file("src/gleam/list.gleam", 2349). -?DOC( - " Returns a random sample of up to n elements from a list using reservoir\n" - " sampling via [Algorithm L](https://en.wikipedia.org/wiki/Reservoir_sampling#Optimal:_Algorithm_L).\n" - " Returns an empty list if the sample size is less than or equal to 0.\n" - "\n" - " Order is not random, only selection is.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " reservoir_sample([1, 2, 3, 4, 5], 3)\n" - " // -> [2, 4, 5] // A random sample of 3 items\n" - " ```\n" -). --spec sample(list(ARX), integer()) -> list(ARX). -sample(List, N) -> - {Reservoir, Rest} = build_reservoir(List, N), - case gleam@dict:is_empty(Reservoir) of - true -> - []; - - false -> - W = math:exp(case erlang:float(N) of - +0.0 -> +0.0; - -0.0 -> -0.0; - Gleam@denominator -> log_random() / Gleam@denominator - end), - maps:values(sample_loop(Rest, Reservoir, N, W)) - end. - --file("src/gleam/list.gleam", 1851). --spec permutation_zip(list(AMT), list(AMT), list(list(AMT))) -> list(list(AMT)). -permutation_zip(List, Rest, Acc) -> - case List of - [] -> - lists:reverse(Acc); - - [Head | Tail] -> - permutation_prepend( - Head, - permutations(lists:reverse(Rest, Tail)), - Tail, - [Head | Rest], - Acc - ) - end. - --file("src/gleam/list.gleam", 1869). --spec permutation_prepend( - ANA, - list(list(ANA)), - list(ANA), - list(ANA), - list(list(ANA)) -) -> list(list(ANA)). -permutation_prepend(El, Permutations, List_1, List_2, Acc) -> - case Permutations of - [] -> - permutation_zip(List_1, List_2, Acc); - - [Head | Tail] -> - permutation_prepend(El, Tail, List_1, List_2, [[El | Head] | Acc]) - end. - --file("src/gleam/list.gleam", 1844). -?DOC( - " Returns all the permutations of a list.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " permutations([1, 2])\n" - " // -> [[1, 2], [2, 1]]\n" - " ```\n" -). --spec permutations(list(AMP)) -> list(list(AMP)). -permutations(List) -> - case List of - [] -> - [[]]; - - L -> - permutation_zip(L, [], []) - end. diff --git a/build/dev/javascript/gleam_stdlib/gleam@option.erl b/build/dev/javascript/gleam_stdlib/gleam@option.erl deleted file mode 100644 index 8e86a8e..0000000 --- a/build/dev/javascript/gleam_stdlib/gleam@option.erl +++ /dev/null @@ -1,413 +0,0 @@ --module(gleam@option). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "src/gleam/option.gleam"). --export([all/1, is_some/1, is_none/1, to_result/2, from_result/1, unwrap/2, lazy_unwrap/2, map/2, flatten/1, then/2, 'or'/2, lazy_or/2, values/1]). --export_type([option/1]). - --if(?OTP_RELEASE >= 27). --define(MODULEDOC(Str), -moduledoc(Str)). --define(DOC(Str), -doc(Str)). --else. --define(MODULEDOC(Str), -compile([])). --define(DOC(Str), -compile([])). --endif. - --type option(FG) :: {some, FG} | none. - --file("src/gleam/option.gleam", 59). --spec reverse_and_prepend(list(FV), list(FV)) -> list(FV). -reverse_and_prepend(Prefix, Suffix) -> - case Prefix of - [] -> - Suffix; - - [First | Rest] -> - reverse_and_prepend(Rest, [First | Suffix]) - end. - --file("src/gleam/option.gleam", 44). --spec all_loop(list(option(FM)), list(FM)) -> option(list(FM)). -all_loop(List, Acc) -> - case List of - [] -> - {some, lists:reverse(Acc)}; - - [none | _] -> - none; - - [{some, First} | Rest] -> - all_loop(Rest, [First | Acc]) - end. - --file("src/gleam/option.gleam", 40). -?DOC( - " Combines a list of `Option`s into a single `Option`.\n" - " If all elements in the list are `Some` then returns a `Some` holding the list of values.\n" - " If any element is `None` then returns`None`.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " all([Some(1), Some(2)])\n" - " // -> Some([1, 2])\n" - " ```\n" - "\n" - " ```gleam\n" - " all([Some(1), None])\n" - " // -> None\n" - " ```\n" -). --spec all(list(option(FH))) -> option(list(FH)). -all(List) -> - all_loop(List, []). - --file("src/gleam/option.gleam", 80). -?DOC( - " Checks whether the `Option` is a `Some` value.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " is_some(Some(1))\n" - " // -> True\n" - " ```\n" - "\n" - " ```gleam\n" - " is_some(None)\n" - " // -> False\n" - " ```\n" -). --spec is_some(option(any())) -> boolean(). -is_some(Option) -> - Option /= none. - --file("src/gleam/option.gleam", 98). -?DOC( - " Checks whether the `Option` is a `None` value.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " is_none(Some(1))\n" - " // -> False\n" - " ```\n" - "\n" - " ```gleam\n" - " is_none(None)\n" - " // -> True\n" - " ```\n" -). --spec is_none(option(any())) -> boolean(). -is_none(Option) -> - Option =:= none. - --file("src/gleam/option.gleam", 116). -?DOC( - " Converts an `Option` type to a `Result` type.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " to_result(Some(1), \"some_error\")\n" - " // -> Ok(1)\n" - " ```\n" - "\n" - " ```gleam\n" - " to_result(None, \"some_error\")\n" - " // -> Error(\"some_error\")\n" - " ```\n" -). --spec to_result(option(GD), GG) -> {ok, GD} | {error, GG}. -to_result(Option, E) -> - case Option of - {some, A} -> - {ok, A}; - - none -> - {error, E} - end. - --file("src/gleam/option.gleam", 137). -?DOC( - " Converts a `Result` type to an `Option` type.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " from_result(Ok(1))\n" - " // -> Some(1)\n" - " ```\n" - "\n" - " ```gleam\n" - " from_result(Error(\"some_error\"))\n" - " // -> None\n" - " ```\n" -). --spec from_result({ok, GJ} | {error, any()}) -> option(GJ). -from_result(Result) -> - case Result of - {ok, A} -> - {some, A}; - - {error, _} -> - none - end. - --file("src/gleam/option.gleam", 158). -?DOC( - " Extracts the value from an `Option`, returning a default value if there is none.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " unwrap(Some(1), 0)\n" - " // -> 1\n" - " ```\n" - "\n" - " ```gleam\n" - " unwrap(None, 0)\n" - " // -> 0\n" - " ```\n" -). --spec unwrap(option(GO), GO) -> GO. -unwrap(Option, Default) -> - case Option of - {some, X} -> - X; - - none -> - Default - end. - --file("src/gleam/option.gleam", 179). -?DOC( - " Extracts the value from an `Option`, evaluating the default function if the option is `None`.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " lazy_unwrap(Some(1), fn() { 0 })\n" - " // -> 1\n" - " ```\n" - "\n" - " ```gleam\n" - " lazy_unwrap(None, fn() { 0 })\n" - " // -> 0\n" - " ```\n" -). --spec lazy_unwrap(option(GQ), fun(() -> GQ)) -> GQ. -lazy_unwrap(Option, Default) -> - case Option of - {some, X} -> - X; - - none -> - Default() - end. - --file("src/gleam/option.gleam", 204). -?DOC( - " Updates a value held within the `Some` of an `Option` by calling a given function\n" - " on it.\n" - "\n" - " If the `Option` is a `None` rather than `Some`, the function is not called and the\n" - " `Option` stays the same.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " map(over: Some(1), with: fn(x) { x + 1 })\n" - " // -> Some(2)\n" - " ```\n" - "\n" - " ```gleam\n" - " map(over: None, with: fn(x) { x + 1 })\n" - " // -> None\n" - " ```\n" -). --spec map(option(GS), fun((GS) -> GU)) -> option(GU). -map(Option, Fun) -> - case Option of - {some, X} -> - {some, Fun(X)}; - - none -> - none - end. - --file("src/gleam/option.gleam", 230). -?DOC( - " Merges a nested `Option` into a single layer.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " flatten(Some(Some(1)))\n" - " // -> Some(1)\n" - " ```\n" - "\n" - " ```gleam\n" - " flatten(Some(None))\n" - " // -> None\n" - " ```\n" - "\n" - " ```gleam\n" - " flatten(None)\n" - " // -> None\n" - " ```\n" -). --spec flatten(option(option(GW))) -> option(GW). -flatten(Option) -> - case Option of - {some, X} -> - X; - - none -> - none - end. - --file("src/gleam/option.gleam", 269). -?DOC( - " Updates a value held within the `Some` of an `Option` by calling a given function\n" - " on it, where the given function also returns an `Option`. The two options are\n" - " then merged together into one `Option`.\n" - "\n" - " If the `Option` is a `None` rather than `Some` the function is not called and the\n" - " option stays the same.\n" - "\n" - " This function is the equivalent of calling `map` followed by `flatten`, and\n" - " it is useful for chaining together multiple functions that return `Option`.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " then(Some(1), fn(x) { Some(x + 1) })\n" - " // -> Some(2)\n" - " ```\n" - "\n" - " ```gleam\n" - " then(Some(1), fn(x) { Some(#(\"a\", x)) })\n" - " // -> Some(#(\"a\", 1))\n" - " ```\n" - "\n" - " ```gleam\n" - " then(Some(1), fn(_) { None })\n" - " // -> None\n" - " ```\n" - "\n" - " ```gleam\n" - " then(None, fn(x) { Some(x + 1) })\n" - " // -> None\n" - " ```\n" -). --spec then(option(HA), fun((HA) -> option(HC))) -> option(HC). -then(Option, Fun) -> - case Option of - {some, X} -> - Fun(X); - - none -> - none - end. - --file("src/gleam/option.gleam", 300). -?DOC( - " Returns the first value if it is `Some`, otherwise returns the second value.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " or(Some(1), Some(2))\n" - " // -> Some(1)\n" - " ```\n" - "\n" - " ```gleam\n" - " or(Some(1), None)\n" - " // -> Some(1)\n" - " ```\n" - "\n" - " ```gleam\n" - " or(None, Some(2))\n" - " // -> Some(2)\n" - " ```\n" - "\n" - " ```gleam\n" - " or(None, None)\n" - " // -> None\n" - " ```\n" -). --spec 'or'(option(HF), option(HF)) -> option(HF). -'or'(First, Second) -> - case First of - {some, _} -> - First; - - none -> - Second - end. - --file("src/gleam/option.gleam", 331). -?DOC( - " Returns the first value if it is `Some`, otherwise evaluates the given function for a fallback value.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " lazy_or(Some(1), fn() { Some(2) })\n" - " // -> Some(1)\n" - " ```\n" - "\n" - " ```gleam\n" - " lazy_or(Some(1), fn() { None })\n" - " // -> Some(1)\n" - " ```\n" - "\n" - " ```gleam\n" - " lazy_or(None, fn() { Some(2) })\n" - " // -> Some(2)\n" - " ```\n" - "\n" - " ```gleam\n" - " lazy_or(None, fn() { None })\n" - " // -> None\n" - " ```\n" -). --spec lazy_or(option(HJ), fun(() -> option(HJ))) -> option(HJ). -lazy_or(First, Second) -> - case First of - {some, _} -> - First; - - none -> - Second() - end. - --file("src/gleam/option.gleam", 352). --spec values_loop(list(option(HR)), list(HR)) -> list(HR). -values_loop(List, Acc) -> - case List of - [] -> - lists:reverse(Acc); - - [none | Rest] -> - values_loop(Rest, Acc); - - [{some, First} | Rest@1] -> - values_loop(Rest@1, [First | Acc]) - end. - --file("src/gleam/option.gleam", 348). -?DOC( - " Given a list of `Option`s,\n" - " returns only the values inside `Some`.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " values([Some(1), None, Some(3)])\n" - " // -> [1, 3]\n" - " ```\n" -). --spec values(list(option(HN))) -> list(HN). -values(Options) -> - values_loop(Options, []). diff --git a/build/dev/javascript/gleam_stdlib/gleam@order.erl b/build/dev/javascript/gleam_stdlib/gleam@order.erl deleted file mode 100644 index ec2bb84..0000000 --- a/build/dev/javascript/gleam_stdlib/gleam@order.erl +++ /dev/null @@ -1,200 +0,0 @@ --module(gleam@order). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "src/gleam/order.gleam"). --export([negate/1, to_int/1, compare/2, reverse/1, break_tie/2, lazy_break_tie/2]). --export_type([order/0]). - --if(?OTP_RELEASE >= 27). --define(MODULEDOC(Str), -moduledoc(Str)). --define(DOC(Str), -doc(Str)). --else. --define(MODULEDOC(Str), -compile([])). --define(DOC(Str), -compile([])). --endif. - --type order() :: lt | eq | gt. - --file("src/gleam/order.gleam", 35). -?DOC( - " Inverts an order, so less-than becomes greater-than and greater-than\n" - " becomes less-than.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " negate(Lt)\n" - " // -> Gt\n" - " ```\n" - "\n" - " ```gleam\n" - " negate(Eq)\n" - " // -> Eq\n" - " ```\n" - "\n" - " ```gleam\n" - " negate(Gt)\n" - " // -> Lt\n" - " ```\n" -). --spec negate(order()) -> order(). -negate(Order) -> - case Order of - lt -> - gt; - - eq -> - eq; - - gt -> - lt - end. - --file("src/gleam/order.gleam", 62). -?DOC( - " Produces a numeric representation of the order.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " to_int(Lt)\n" - " // -> -1\n" - " ```\n" - "\n" - " ```gleam\n" - " to_int(Eq)\n" - " // -> 0\n" - " ```\n" - "\n" - " ```gleam\n" - " to_int(Gt)\n" - " // -> 1\n" - " ```\n" -). --spec to_int(order()) -> integer(). -to_int(Order) -> - case Order of - lt -> - -1; - - eq -> - 0; - - gt -> - 1 - end. - --file("src/gleam/order.gleam", 79). -?DOC( - " Compares two `Order` values to one another, producing a new `Order`.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " compare(Eq, with: Lt)\n" - " // -> Gt\n" - " ```\n" -). --spec compare(order(), order()) -> order(). -compare(A, B) -> - case {A, B} of - {X, Y} when X =:= Y -> - eq; - - {lt, _} -> - lt; - - {eq, gt} -> - lt; - - {_, _} -> - gt - end. - --file("src/gleam/order.gleam", 100). -?DOC( - " Inverts an ordering function, so less-than becomes greater-than and greater-than\n" - " becomes less-than.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " import gleam/int\n" - " import gleam/list\n" - "\n" - " list.sort([1, 5, 4], by: reverse(int.compare))\n" - " // -> [5, 4, 1]\n" - " ```\n" -). --spec reverse(fun((I, I) -> order())) -> fun((I, I) -> order()). -reverse(Orderer) -> - fun(A, B) -> Orderer(B, A) end. - --file("src/gleam/order.gleam", 122). -?DOC( - " Return a fallback `Order` in case the first argument is `Eq`.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " import gleam/int\n" - "\n" - " break_tie(in: int.compare(1, 1), with: Lt)\n" - " // -> Lt\n" - " ```\n" - "\n" - " ```gleam\n" - " import gleam/int\n" - "\n" - " break_tie(in: int.compare(1, 0), with: Eq)\n" - " // -> Gt\n" - " ```\n" -). --spec break_tie(order(), order()) -> order(). -break_tie(Order, Other) -> - case Order of - lt -> - Order; - - gt -> - Order; - - eq -> - Other - end. - --file("src/gleam/order.gleam", 151). -?DOC( - " Invokes a fallback function returning an `Order` in case the first argument\n" - " is `Eq`.\n" - "\n" - " This can be useful when the fallback comparison might be expensive and it\n" - " needs to be delayed until strictly necessary.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " import gleam/int\n" - "\n" - " lazy_break_tie(in: int.compare(1, 1), with: fn() { Lt })\n" - " // -> Lt\n" - " ```\n" - "\n" - " ```gleam\n" - " import gleam/int\n" - "\n" - " lazy_break_tie(in: int.compare(1, 0), with: fn() { Eq })\n" - " // -> Gt\n" - " ```\n" -). --spec lazy_break_tie(order(), fun(() -> order())) -> order(). -lazy_break_tie(Order, Comparison) -> - case Order of - lt -> - Order; - - gt -> - Order; - - eq -> - Comparison() - end. diff --git a/build/dev/javascript/gleam_stdlib/gleam@pair.erl b/build/dev/javascript/gleam_stdlib/gleam@pair.erl deleted file mode 100644 index cb18264..0000000 --- a/build/dev/javascript/gleam_stdlib/gleam@pair.erl +++ /dev/null @@ -1,110 +0,0 @@ --module(gleam@pair). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "src/gleam/pair.gleam"). --export([first/1, second/1, swap/1, map_first/2, map_second/2, new/2]). - --if(?OTP_RELEASE >= 27). --define(MODULEDOC(Str), -moduledoc(Str)). --define(DOC(Str), -doc(Str)). --else. --define(MODULEDOC(Str), -compile([])). --define(DOC(Str), -compile([])). --endif. - --file("src/gleam/pair.gleam", 10). -?DOC( - " Returns the first element in a pair.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " first(#(1, 2))\n" - " // -> 1\n" - " ```\n" -). --spec first({CLF, any()}) -> CLF. -first(Pair) -> - {A, _} = Pair, - A. - --file("src/gleam/pair.gleam", 24). -?DOC( - " Returns the second element in a pair.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " second(#(1, 2))\n" - " // -> 2\n" - " ```\n" -). --spec second({any(), CLI}) -> CLI. -second(Pair) -> - {_, A} = Pair, - A. - --file("src/gleam/pair.gleam", 38). -?DOC( - " Returns a new pair with the elements swapped.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " swap(#(1, 2))\n" - " // -> #(2, 1)\n" - " ```\n" -). --spec swap({CLJ, CLK}) -> {CLK, CLJ}. -swap(Pair) -> - {A, B} = Pair, - {B, A}. - --file("src/gleam/pair.gleam", 53). -?DOC( - " Returns a new pair with the first element having had `with` applied to\n" - " it.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " #(1, 2) |> map_first(fn(n) { n * 2 })\n" - " // -> #(2, 2)\n" - " ```\n" -). --spec map_first({CLL, CLM}, fun((CLL) -> CLN)) -> {CLN, CLM}. -map_first(Pair, Fun) -> - {A, B} = Pair, - {Fun(A), B}. - --file("src/gleam/pair.gleam", 68). -?DOC( - " Returns a new pair with the second element having had `with` applied to\n" - " it.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " #(1, 2) |> map_second(fn(n) { n * 2 })\n" - " // -> #(1, 4)\n" - " ```\n" -). --spec map_second({CLO, CLP}, fun((CLP) -> CLQ)) -> {CLO, CLQ}. -map_second(Pair, Fun) -> - {A, B} = Pair, - {A, Fun(B)}. - --file("src/gleam/pair.gleam", 83). -?DOC( - " Returns a new pair with the given elements. This can also be done using the dedicated\n" - " syntax instead: `new(1, 2) == #(1, 2)`.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " new(1, 2)\n" - " // -> #(1, 2)\n" - " ```\n" -). --spec new(CLR, CLS) -> {CLR, CLS}. -new(First, Second) -> - {First, Second}. diff --git a/build/dev/javascript/gleam_stdlib/gleam@result.erl b/build/dev/javascript/gleam_stdlib/gleam@result.erl deleted file mode 100644 index 9d89ff7..0000000 --- a/build/dev/javascript/gleam_stdlib/gleam@result.erl +++ /dev/null @@ -1,550 +0,0 @@ --module(gleam@result). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "src/gleam/result.gleam"). --export([is_ok/1, is_error/1, map/2, map_error/2, flatten/1, 'try'/2, then/2, unwrap/2, lazy_unwrap/2, unwrap_error/2, unwrap_both/1, 'or'/2, lazy_or/2, all/1, partition/1, replace/2, replace_error/2, values/1, try_recover/2]). - --if(?OTP_RELEASE >= 27). --define(MODULEDOC(Str), -moduledoc(Str)). --define(DOC(Str), -doc(Str)). --else. --define(MODULEDOC(Str), -compile([])). --define(DOC(Str), -compile([])). --endif. - -?MODULEDOC( - " Result represents the result of something that may succeed or not.\n" - " `Ok` means it was successful, `Error` means it was not successful.\n" -). - --file("src/gleam/result.gleam", 20). -?DOC( - " Checks whether the result is an `Ok` value.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " is_ok(Ok(1))\n" - " // -> True\n" - " ```\n" - "\n" - " ```gleam\n" - " is_ok(Error(Nil))\n" - " // -> False\n" - " ```\n" -). --spec is_ok({ok, any()} | {error, any()}) -> boolean(). -is_ok(Result) -> - case Result of - {error, _} -> - false; - - {ok, _} -> - true - end. - --file("src/gleam/result.gleam", 41). -?DOC( - " Checks whether the result is an `Error` value.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " is_error(Ok(1))\n" - " // -> False\n" - " ```\n" - "\n" - " ```gleam\n" - " is_error(Error(Nil))\n" - " // -> True\n" - " ```\n" -). --spec is_error({ok, any()} | {error, any()}) -> boolean(). -is_error(Result) -> - case Result of - {ok, _} -> - false; - - {error, _} -> - true - end. - --file("src/gleam/result.gleam", 66). -?DOC( - " Updates a value held within the `Ok` of a result by calling a given function\n" - " on it.\n" - "\n" - " If the result is an `Error` rather than `Ok` the function is not called and the\n" - " result stays the same.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " map(over: Ok(1), with: fn(x) { x + 1 })\n" - " // -> Ok(2)\n" - " ```\n" - "\n" - " ```gleam\n" - " map(over: Error(1), with: fn(x) { x + 1 })\n" - " // -> Error(1)\n" - " ```\n" -). --spec map({ok, CMC} | {error, CMD}, fun((CMC) -> CMG)) -> {ok, CMG} | - {error, CMD}. -map(Result, Fun) -> - case Result of - {ok, X} -> - {ok, Fun(X)}; - - {error, E} -> - {error, E} - end. - --file("src/gleam/result.gleam", 91). -?DOC( - " Updates a value held within the `Error` of a result by calling a given function\n" - " on it.\n" - "\n" - " If the result is `Ok` rather than `Error` the function is not called and the\n" - " result stays the same.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " map_error(over: Error(1), with: fn(x) { x + 1 })\n" - " // -> Error(2)\n" - " ```\n" - "\n" - " ```gleam\n" - " map_error(over: Ok(1), with: fn(x) { x + 1 })\n" - " // -> Ok(1)\n" - " ```\n" -). --spec map_error({ok, CMJ} | {error, CMK}, fun((CMK) -> CMN)) -> {ok, CMJ} | - {error, CMN}. -map_error(Result, Fun) -> - case Result of - {ok, X} -> - {ok, X}; - - {error, Error} -> - {error, Fun(Error)} - end. - --file("src/gleam/result.gleam", 120). -?DOC( - " Merges a nested `Result` into a single layer.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " flatten(Ok(Ok(1)))\n" - " // -> Ok(1)\n" - " ```\n" - "\n" - " ```gleam\n" - " flatten(Ok(Error(\"\")))\n" - " // -> Error(\"\")\n" - " ```\n" - "\n" - " ```gleam\n" - " flatten(Error(Nil))\n" - " // -> Error(Nil)\n" - " ```\n" -). --spec flatten({ok, {ok, CMQ} | {error, CMR}} | {error, CMR}) -> {ok, CMQ} | - {error, CMR}. -flatten(Result) -> - case Result of - {ok, X} -> - X; - - {error, Error} -> - {error, Error} - end. - --file("src/gleam/result.gleam", 158). -?DOC( - " \"Updates\" an `Ok` result by passing its value to a function that yields a result,\n" - " and returning the yielded result. (This may \"replace\" the `Ok` with an `Error`.)\n" - "\n" - " If the input is an `Error` rather than an `Ok`, the function is not called and\n" - " the original `Error` is returned.\n" - "\n" - " This function is the equivalent of calling `map` followed by `flatten`, and\n" - " it is useful for chaining together multiple functions that may fail.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " try(Ok(1), fn(x) { Ok(x + 1) })\n" - " // -> Ok(2)\n" - " ```\n" - "\n" - " ```gleam\n" - " try(Ok(1), fn(x) { Ok(#(\"a\", x)) })\n" - " // -> Ok(#(\"a\", 1))\n" - " ```\n" - "\n" - " ```gleam\n" - " try(Ok(1), fn(_) { Error(\"Oh no\") })\n" - " // -> Error(\"Oh no\")\n" - " ```\n" - "\n" - " ```gleam\n" - " try(Error(Nil), fn(x) { Ok(x + 1) })\n" - " // -> Error(Nil)\n" - " ```\n" -). --spec 'try'({ok, CMY} | {error, CMZ}, fun((CMY) -> {ok, CNC} | {error, CMZ})) -> {ok, - CNC} | - {error, CMZ}. -'try'(Result, Fun) -> - case Result of - {ok, X} -> - Fun(X); - - {error, E} -> - {error, E} - end. - --file("src/gleam/result.gleam", 169). --spec then({ok, CNH} | {error, CNI}, fun((CNH) -> {ok, CNL} | {error, CNI})) -> {ok, - CNL} | - {error, CNI}. -then(Result, Fun) -> - 'try'(Result, Fun). - --file("src/gleam/result.gleam", 191). -?DOC( - " Extracts the `Ok` value from a result, returning a default value if the result\n" - " is an `Error`.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " unwrap(Ok(1), 0)\n" - " // -> 1\n" - " ```\n" - "\n" - " ```gleam\n" - " unwrap(Error(\"\"), 0)\n" - " // -> 0\n" - " ```\n" -). --spec unwrap({ok, CNQ} | {error, any()}, CNQ) -> CNQ. -unwrap(Result, Default) -> - case Result of - {ok, V} -> - V; - - {error, _} -> - Default - end. - --file("src/gleam/result.gleam", 213). -?DOC( - " Extracts the `Ok` value from a result, evaluating the default function if the result\n" - " is an `Error`.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " lazy_unwrap(Ok(1), fn() { 0 })\n" - " // -> 1\n" - " ```\n" - "\n" - " ```gleam\n" - " lazy_unwrap(Error(\"\"), fn() { 0 })\n" - " // -> 0\n" - " ```\n" -). --spec lazy_unwrap({ok, CNU} | {error, any()}, fun(() -> CNU)) -> CNU. -lazy_unwrap(Result, Default) -> - case Result of - {ok, V} -> - V; - - {error, _} -> - Default() - end. - --file("src/gleam/result.gleam", 235). -?DOC( - " Extracts the `Error` value from a result, returning a default value if the result\n" - " is an `Ok`.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " unwrap_error(Error(1), 0)\n" - " // -> 1\n" - " ```\n" - "\n" - " ```gleam\n" - " unwrap_error(Ok(\"\"), 0)\n" - " // -> 0\n" - " ```\n" -). --spec unwrap_error({ok, any()} | {error, CNZ}, CNZ) -> CNZ. -unwrap_error(Result, Default) -> - case Result of - {ok, _} -> - Default; - - {error, E} -> - E - end. - --file("src/gleam/result.gleam", 243). --spec unwrap_both({ok, COC} | {error, COC}) -> COC. -unwrap_both(Result) -> - case Result of - {ok, A} -> - A; - - {error, A@1} -> - A@1 - end. - --file("src/gleam/result.gleam", 274). -?DOC( - " Returns the first value if it is `Ok`, otherwise returns the second value.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " or(Ok(1), Ok(2))\n" - " // -> Ok(1)\n" - " ```\n" - "\n" - " ```gleam\n" - " or(Ok(1), Error(\"Error 2\"))\n" - " // -> Ok(1)\n" - " ```\n" - "\n" - " ```gleam\n" - " or(Error(\"Error 1\"), Ok(2))\n" - " // -> Ok(2)\n" - " ```\n" - "\n" - " ```gleam\n" - " or(Error(\"Error 1\"), Error(\"Error 2\"))\n" - " // -> Error(\"Error 2\")\n" - " ```\n" -). --spec 'or'({ok, COF} | {error, COG}, {ok, COF} | {error, COG}) -> {ok, COF} | - {error, COG}. -'or'(First, Second) -> - case First of - {ok, _} -> - First; - - {error, _} -> - Second - end. - --file("src/gleam/result.gleam", 307). -?DOC( - " Returns the first value if it is `Ok`, otherwise evaluates the given function for a fallback value.\n" - "\n" - " If you need access to the initial error value, use `result.try_recover`.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " lazy_or(Ok(1), fn() { Ok(2) })\n" - " // -> Ok(1)\n" - " ```\n" - "\n" - " ```gleam\n" - " lazy_or(Ok(1), fn() { Error(\"Error 2\") })\n" - " // -> Ok(1)\n" - " ```\n" - "\n" - " ```gleam\n" - " lazy_or(Error(\"Error 1\"), fn() { Ok(2) })\n" - " // -> Ok(2)\n" - " ```\n" - "\n" - " ```gleam\n" - " lazy_or(Error(\"Error 1\"), fn() { Error(\"Error 2\") })\n" - " // -> Error(\"Error 2\")\n" - " ```\n" -). --spec lazy_or({ok, CON} | {error, COO}, fun(() -> {ok, CON} | {error, COO})) -> {ok, - CON} | - {error, COO}. -lazy_or(First, Second) -> - case First of - {ok, _} -> - First; - - {error, _} -> - Second() - end. - --file("src/gleam/result.gleam", 333). -?DOC( - " Combines a list of results into a single result.\n" - " If all elements in the list are `Ok` then returns an `Ok` holding the list of values.\n" - " If any element is `Error` then returns the first error.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " all([Ok(1), Ok(2)])\n" - " // -> Ok([1, 2])\n" - " ```\n" - "\n" - " ```gleam\n" - " all([Ok(1), Error(\"e\")])\n" - " // -> Error(\"e\")\n" - " ```\n" -). --spec all(list({ok, COV} | {error, COW})) -> {ok, list(COV)} | {error, COW}. -all(Results) -> - gleam@list:try_map(Results, fun(Result) -> Result end). - --file("src/gleam/result.gleam", 353). --spec partition_loop(list({ok, CPK} | {error, CPL}), list(CPK), list(CPL)) -> {list(CPK), - list(CPL)}. -partition_loop(Results, Oks, Errors) -> - case Results of - [] -> - {Oks, Errors}; - - [{ok, A} | Rest] -> - partition_loop(Rest, [A | Oks], Errors); - - [{error, E} | Rest@1] -> - partition_loop(Rest@1, Oks, [E | Errors]) - end. - --file("src/gleam/result.gleam", 349). -?DOC( - " Given a list of results, returns a pair where the first element is a list\n" - " of all the values inside `Ok` and the second element is a list with all the\n" - " values inside `Error`. The values in both lists appear in reverse order with\n" - " respect to their position in the original list of results.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " partition([Ok(1), Error(\"a\"), Error(\"b\"), Ok(2)])\n" - " // -> #([2, 1], [\"b\", \"a\"])\n" - " ```\n" -). --spec partition(list({ok, CPD} | {error, CPE})) -> {list(CPD), list(CPE)}. -partition(Results) -> - partition_loop(Results, [], []). - --file("src/gleam/result.gleam", 375). -?DOC( - " Replace the value within a result\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " replace(Ok(1), Nil)\n" - " // -> Ok(Nil)\n" - " ```\n" - "\n" - " ```gleam\n" - " replace(Error(1), Nil)\n" - " // -> Error(1)\n" - " ```\n" -). --spec replace({ok, any()} | {error, CPT}, CPW) -> {ok, CPW} | {error, CPT}. -replace(Result, Value) -> - case Result of - {ok, _} -> - {ok, Value}; - - {error, Error} -> - {error, Error} - end. - --file("src/gleam/result.gleam", 396). -?DOC( - " Replace the error within a result\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " replace_error(Error(1), Nil)\n" - " // -> Error(Nil)\n" - " ```\n" - "\n" - " ```gleam\n" - " replace_error(Ok(1), Nil)\n" - " // -> Ok(1)\n" - " ```\n" -). --spec replace_error({ok, CPZ} | {error, any()}, CQD) -> {ok, CPZ} | {error, CQD}. -replace_error(Result, Error) -> - case Result of - {ok, X} -> - {ok, X}; - - {error, _} -> - {error, Error} - end. - --file("src/gleam/result.gleam", 412). -?DOC( - " Given a list of results, returns only the values inside `Ok`.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " values([Ok(1), Error(\"a\"), Ok(3)])\n" - " // -> [1, 3]\n" - " ```\n" -). --spec values(list({ok, CQG} | {error, any()})) -> list(CQG). -values(Results) -> - gleam@list:filter_map(Results, fun(Result) -> Result end). - --file("src/gleam/result.gleam", 445). -?DOC( - " Updates a value held within the `Error` of a result by calling a given function\n" - " on it, where the given function also returns a result. The two results are\n" - " then merged together into one result.\n" - "\n" - " If the result is an `Ok` rather than `Error` the function is not called and the\n" - " result stays the same.\n" - "\n" - " This function is useful for chaining together computations that may fail\n" - " and trying to recover from possible errors.\n" - "\n" - " If you do not need access to the initial error value, use `result.lazy_or`.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " Ok(1) |> try_recover(with: fn(_) { Error(\"failed to recover\") })\n" - " // -> Ok(1)\n" - " ```\n" - "\n" - " ```gleam\n" - " Error(1) |> try_recover(with: fn(error) { Ok(error + 1) })\n" - " // -> Ok(2)\n" - " ```\n" - "\n" - " ```gleam\n" - " Error(1) |> try_recover(with: fn(error) { Error(\"failed to recover\") })\n" - " // -> Error(\"failed to recover\")\n" - " ```\n" -). --spec try_recover( - {ok, CQM} | {error, CQN}, - fun((CQN) -> {ok, CQM} | {error, CQQ}) -) -> {ok, CQM} | {error, CQQ}. -try_recover(Result, Fun) -> - case Result of - {ok, Value} -> - {ok, Value}; - - {error, Error} -> - Fun(Error) - end. diff --git a/build/dev/javascript/gleam_stdlib/gleam@set.erl b/build/dev/javascript/gleam_stdlib/gleam@set.erl deleted file mode 100644 index bb3c417..0000000 --- a/build/dev/javascript/gleam_stdlib/gleam@set.erl +++ /dev/null @@ -1,429 +0,0 @@ --module(gleam@set). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "src/gleam/set.gleam"). --export([new/0, size/1, is_empty/1, contains/2, delete/2, to_list/1, fold/3, filter/2, drop/2, take/2, intersection/2, difference/2, is_subset/2, is_disjoint/2, each/2, insert/2, from_list/1, map/2, union/2, symmetric_difference/2]). --export_type([set/1]). - --if(?OTP_RELEASE >= 27). --define(MODULEDOC(Str), -moduledoc(Str)). --define(DOC(Str), -doc(Str)). --else. --define(MODULEDOC(Str), -compile([])). --define(DOC(Str), -compile([])). --endif. - --opaque set(CVL) :: {set, gleam@dict:dict(CVL, list(nil))}. - --file("src/gleam/set.gleam", 32). -?DOC(" Creates a new empty set.\n"). --spec new() -> set(any()). -new() -> - {set, maps:new()}. - --file("src/gleam/set.gleam", 50). -?DOC( - " Gets the number of members in a set.\n" - "\n" - " This function runs in constant time.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " new()\n" - " |> insert(1)\n" - " |> insert(2)\n" - " |> size\n" - " // -> 2\n" - " ```\n" -). --spec size(set(any())) -> integer(). -size(Set) -> - maps:size(erlang:element(2, Set)). - --file("src/gleam/set.gleam", 68). -?DOC( - " Determines whether or not the set is empty.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " new() |> is_empty\n" - " // -> True\n" - " ```\n" - "\n" - " ```gleam\n" - " new() |> insert(1) |> is_empty\n" - " // -> False\n" - " ```\n" -). --spec is_empty(set(any())) -> boolean(). -is_empty(Set) -> - Set =:= new(). - --file("src/gleam/set.gleam", 110). -?DOC( - " Checks whether a set contains a given member.\n" - "\n" - " This function runs in logarithmic time.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " new()\n" - " |> insert(2)\n" - " |> contains(2)\n" - " // -> True\n" - " ```\n" - "\n" - " ```gleam\n" - " new()\n" - " |> insert(2)\n" - " |> contains(1)\n" - " // -> False\n" - " ```\n" -). --spec contains(set(CVW), CVW) -> boolean(). -contains(Set, Member) -> - _pipe = erlang:element(2, Set), - _pipe@1 = gleam_stdlib:map_get(_pipe, Member), - gleam@result:is_ok(_pipe@1). - --file("src/gleam/set.gleam", 131). -?DOC( - " Removes a member from a set. If the set does not contain the member then\n" - " the set is returned unchanged.\n" - "\n" - " This function runs in logarithmic time.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " new()\n" - " |> insert(2)\n" - " |> delete(2)\n" - " |> contains(1)\n" - " // -> False\n" - " ```\n" -). --spec delete(set(CVY), CVY) -> set(CVY). -delete(Set, Member) -> - {set, gleam@dict:delete(erlang:element(2, Set), Member)}. - --file("src/gleam/set.gleam", 149). -?DOC( - " Converts the set into a list of the contained members.\n" - "\n" - " The list has no specific ordering, any unintentional ordering may change in\n" - " future versions of Gleam or Erlang.\n" - "\n" - " This function runs in linear time.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " new() |> insert(2) |> to_list\n" - " // -> [2]\n" - " ```\n" -). --spec to_list(set(CWB)) -> list(CWB). -to_list(Set) -> - maps:keys(erlang:element(2, Set)). - --file("src/gleam/set.gleam", 190). -?DOC( - " Combines all entries into a single value by calling a given function on each\n" - " one.\n" - "\n" - " Sets are not ordered so the values are not returned in any specific order.\n" - " Do not write code that relies on the order entries are used by this\n" - " function as it may change in later versions of Gleam or Erlang.\n" - "\n" - " # Examples\n" - "\n" - " ```gleam\n" - " from_list([1, 3, 9])\n" - " |> fold(0, fn(accumulator, member) { accumulator + member })\n" - " // -> 13\n" - " ```\n" -). --spec fold(set(CWH), CWJ, fun((CWJ, CWH) -> CWJ)) -> CWJ. -fold(Set, Initial, Reducer) -> - gleam@dict:fold( - erlang:element(2, Set), - Initial, - fun(A, K, _) -> Reducer(A, K) end - ). - --file("src/gleam/set.gleam", 214). -?DOC( - " Creates a new set from an existing set, minus any members that a given\n" - " function returns `False` for.\n" - "\n" - " This function runs in loglinear time.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " import gleam/int\n" - "\n" - " from_list([1, 4, 6, 3, 675, 44, 67])\n" - " |> filter(keeping: int.is_even)\n" - " |> to_list\n" - " // -> [4, 6, 44]\n" - " ```\n" -). --spec filter(set(CWK), fun((CWK) -> boolean())) -> set(CWK). -filter(Set, Predicate) -> - {set, - gleam@dict:filter(erlang:element(2, Set), fun(M, _) -> Predicate(M) end)}. - --file("src/gleam/set.gleam", 249). -?DOC( - " Creates a new set from a given set with all the same entries except any\n" - " entry found on the given list.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " from_list([1, 2, 3, 4])\n" - " |> drop([1, 3])\n" - " |> to_list\n" - " // -> [2, 4]\n" - " ```\n" -). --spec drop(set(CWR), list(CWR)) -> set(CWR). -drop(Set, Disallowed) -> - gleam@list:fold(Disallowed, Set, fun delete/2). - --file("src/gleam/set.gleam", 267). -?DOC( - " Creates a new set from a given set, only including any members which are in\n" - " a given list.\n" - "\n" - " This function runs in loglinear time.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " from_list([1, 2, 3])\n" - " |> take([1, 3, 5])\n" - " |> to_list\n" - " // -> [1, 3]\n" - " ```\n" -). --spec take(set(CWV), list(CWV)) -> set(CWV). -take(Set, Desired) -> - {set, gleam@dict:take(erlang:element(2, Set), Desired)}. - --file("src/gleam/set.gleam", 287). --spec order(set(CXD), set(CXD)) -> {set(CXD), set(CXD)}. -order(First, Second) -> - case maps:size(erlang:element(2, First)) > maps:size( - erlang:element(2, Second) - ) of - true -> - {First, Second}; - - false -> - {Second, First} - end. - --file("src/gleam/set.gleam", 305). -?DOC( - " Creates a new set that contains members that are present in both given sets.\n" - "\n" - " This function runs in loglinear time.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " intersection(from_list([1, 2]), from_list([2, 3])) |> to_list\n" - " // -> [2]\n" - " ```\n" -). --spec intersection(set(CXI), set(CXI)) -> set(CXI). -intersection(First, Second) -> - {Larger, Smaller} = order(First, Second), - take(Larger, to_list(Smaller)). - --file("src/gleam/set.gleam", 323). -?DOC( - " Creates a new set that contains members that are present in the first set\n" - " but not the second.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " difference(from_list([1, 2]), from_list([2, 3, 4])) |> to_list\n" - " // -> [1]\n" - " ```\n" -). --spec difference(set(CXM), set(CXM)) -> set(CXM). -difference(First, Second) -> - drop(First, to_list(Second)). - --file("src/gleam/set.gleam", 344). -?DOC( - " Determines if a set is fully contained by another.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " is_subset(from_list([1]), from_list([1, 2]))\n" - " // -> True\n" - " ```\n" - "\n" - " ```gleam\n" - " is_subset(from_list([1, 2, 3]), from_list([3, 4, 5]))\n" - " // -> False\n" - " ```\n" -). --spec is_subset(set(CXQ), set(CXQ)) -> boolean(). -is_subset(First, Second) -> - intersection(First, Second) =:= First. - --file("src/gleam/set.gleam", 362). -?DOC( - " Determines if two sets contain no common members\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " is_disjoint(from_list([1, 2, 3]), from_list([4, 5, 6]))\n" - " // -> True\n" - " ```\n" - "\n" - " ```gleam\n" - " is_disjoint(from_list([1, 2, 3]), from_list([3, 4, 5]))\n" - " // -> False\n" - " ```\n" -). --spec is_disjoint(set(CXT), set(CXT)) -> boolean(). -is_disjoint(First, Second) -> - intersection(First, Second) =:= new(). - --file("src/gleam/set.gleam", 402). -?DOC( - " Calls a function for each member in a set, discarding the return\n" - " value.\n" - "\n" - " Useful for producing a side effect for every item of a set.\n" - "\n" - " ```gleam\n" - " let set = from_list([\"apple\", \"banana\", \"cherry\"])\n" - "\n" - " each(set, io.println)\n" - " // -> Nil\n" - " // apple\n" - " // banana\n" - " // cherry\n" - " ```\n" - "\n" - " The order of elements in the iteration is an implementation detail that\n" - " should not be relied upon.\n" -). --spec each(set(CYA), fun((CYA) -> any())) -> nil. -each(Set, Fun) -> - fold( - Set, - nil, - fun(Nil, Member) -> - Fun(Member), - Nil - end - ). - --file("src/gleam/set.gleam", 86). -?DOC( - " Inserts an member into the set.\n" - "\n" - " This function runs in logarithmic time.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " new()\n" - " |> insert(1)\n" - " |> insert(2)\n" - " |> size\n" - " // -> 2\n" - " ```\n" -). --spec insert(set(CVT), CVT) -> set(CVT). -insert(Set, Member) -> - {set, gleam@dict:insert(erlang:element(2, Set), Member, [])}. - --file("src/gleam/set.gleam", 167). -?DOC( - " Creates a new set of the members in a given list.\n" - "\n" - " This function runs in loglinear time.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " import gleam/int\n" - " import gleam/list\n" - "\n" - " [1, 1, 2, 4, 3, 2] |> from_list |> to_list |> list.sort(by: int.compare)\n" - " // -> [1, 2, 3, 4]\n" - " ```\n" -). --spec from_list(list(CWE)) -> set(CWE). -from_list(Members) -> - Dict = gleam@list:fold( - Members, - maps:new(), - fun(M, K) -> gleam@dict:insert(M, K, []) end - ), - {set, Dict}. - --file("src/gleam/set.gleam", 232). -?DOC( - " Creates a new set from a given set with the result of applying the given\n" - " function to each member.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " from_list([1, 2, 3, 4])\n" - " |> map(with: fn(x) { x * 2 })\n" - " |> to_list\n" - " // -> [2, 4, 6, 8]\n" - " ```\n" -). --spec map(set(CWN), fun((CWN) -> CWP)) -> set(CWP). -map(Set, Fun) -> - fold(Set, new(), fun(Acc, Member) -> insert(Acc, Fun(Member)) end). - --file("src/gleam/set.gleam", 282). -?DOC( - " Creates a new set that contains all members of both given sets.\n" - "\n" - " This function runs in loglinear time.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " union(from_list([1, 2]), from_list([2, 3])) |> to_list\n" - " // -> [1, 2, 3]\n" - " ```\n" -). --spec union(set(CWZ), set(CWZ)) -> set(CWZ). -union(First, Second) -> - {Larger, Smaller} = order(First, Second), - fold(Smaller, Larger, fun insert/2). - --file("src/gleam/set.gleam", 374). -?DOC( - " Creates a new set that contains members that are present in either set, but\n" - " not both.\n" - "\n" - " ```gleam\n" - " symmetric_difference(from_list([1, 2, 3]), from_list([3, 4])) |> to_list\n" - " // -> [1, 2, 4]\n" - " ```\n" -). --spec symmetric_difference(set(CXW), set(CXW)) -> set(CXW). -symmetric_difference(First, Second) -> - difference(union(First, Second), intersection(First, Second)). diff --git a/build/dev/javascript/gleam_stdlib/gleam@string.erl b/build/dev/javascript/gleam_stdlib/gleam@string.erl deleted file mode 100644 index 63006b8..0000000 --- a/build/dev/javascript/gleam_stdlib/gleam@string.erl +++ /dev/null @@ -1,1012 +0,0 @@ --module(gleam@string). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "src/gleam/string.gleam"). --export([is_empty/1, length/1, reverse/1, replace/3, lowercase/1, uppercase/1, compare/2, slice/3, crop/2, drop_end/2, contains/2, starts_with/2, ends_with/2, split_once/2, append/2, concat/1, repeat/2, join/2, pad_start/3, pad_end/3, trim_start/1, trim_end/1, trim/1, pop_grapheme/1, to_graphemes/1, split/2, to_utf_codepoints/1, from_utf_codepoints/1, utf_codepoint/1, utf_codepoint_to_int/1, to_option/1, first/1, last/1, capitalise/1, inspect/1, byte_size/1, drop_start/2]). --export_type([direction/0]). - --if(?OTP_RELEASE >= 27). --define(MODULEDOC(Str), -moduledoc(Str)). --define(DOC(Str), -doc(Str)). --else. --define(MODULEDOC(Str), -compile([])). --define(DOC(Str), -compile([])). --endif. - -?MODULEDOC( - " Strings in Gleam are UTF-8 binaries. They can be written in your code as\n" - " text surrounded by `\"double quotes\"`.\n" -). - --type direction() :: leading | trailing. - --file("src/gleam/string.gleam", 23). -?DOC( - " Determines if a `String` is empty.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " is_empty(\"\")\n" - " // -> True\n" - " ```\n" - "\n" - " ```gleam\n" - " is_empty(\"the world\")\n" - " // -> False\n" - " ```\n" -). --spec is_empty(binary()) -> boolean(). -is_empty(Str) -> - Str =:= <<""/utf8>>. - --file("src/gleam/string.gleam", 51). -?DOC( - " Gets the number of grapheme clusters in a given `String`.\n" - "\n" - " This function has to iterate across the whole string to count the number of\n" - " graphemes, so it runs in linear time. Avoid using this in a loop.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " length(\"Gleam\")\n" - " // -> 5\n" - " ```\n" - "\n" - " ```gleam\n" - " length(\"ß↑e̊\")\n" - " // -> 3\n" - " ```\n" - "\n" - " ```gleam\n" - " length(\"\")\n" - " // -> 0\n" - " ```\n" -). --spec length(binary()) -> integer(). -length(String) -> - string:length(String). - --file("src/gleam/string.gleam", 65). -?DOC( - " Reverses a `String`.\n" - "\n" - " This function has to iterate across the whole `String` so it runs in linear\n" - " time. Avoid using this in a loop.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " reverse(\"stressed\")\n" - " // -> \"desserts\"\n" - " ```\n" -). --spec reverse(binary()) -> binary(). -reverse(String) -> - _pipe = String, - _pipe@1 = gleam_stdlib:identity(_pipe), - _pipe@2 = string:reverse(_pipe@1), - unicode:characters_to_binary(_pipe@2). - --file("src/gleam/string.gleam", 86). -?DOC( - " Creates a new `String` by replacing all occurrences of a given substring.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " replace(\"www.example.com\", each: \".\", with: \"-\")\n" - " // -> \"www-example-com\"\n" - " ```\n" - "\n" - " ```gleam\n" - " replace(\"a,b,c,d,e\", each: \",\", with: \"/\")\n" - " // -> \"a/b/c/d/e\"\n" - " ```\n" -). --spec replace(binary(), binary(), binary()) -> binary(). -replace(String, Pattern, Substitute) -> - _pipe = String, - _pipe@1 = gleam_stdlib:identity(_pipe), - _pipe@2 = gleam_stdlib:string_replace(_pipe@1, Pattern, Substitute), - unicode:characters_to_binary(_pipe@2). - --file("src/gleam/string.gleam", 111). -?DOC( - " Creates a new `String` with all the graphemes in the input `String` converted to\n" - " lowercase.\n" - "\n" - " Useful for case-insensitive comparisons.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " lowercase(\"X-FILES\")\n" - " // -> \"x-files\"\n" - " ```\n" -). --spec lowercase(binary()) -> binary(). -lowercase(String) -> - string:lowercase(String). - --file("src/gleam/string.gleam", 127). -?DOC( - " Creates a new `String` with all the graphemes in the input `String` converted to\n" - " uppercase.\n" - "\n" - " Useful for case-insensitive comparisons and VIRTUAL YELLING.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " uppercase(\"skinner\")\n" - " // -> \"SKINNER\"\n" - " ```\n" -). --spec uppercase(binary()) -> binary(). -uppercase(String) -> - string:uppercase(String). - --file("src/gleam/string.gleam", 145). -?DOC( - " Compares two `String`s to see which is \"larger\" by comparing their graphemes.\n" - "\n" - " This does not compare the size or length of the given `String`s.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " compare(\"Anthony\", \"Anthony\")\n" - " // -> order.Eq\n" - " ```\n" - "\n" - " ```gleam\n" - " compare(\"A\", \"B\")\n" - " // -> order.Lt\n" - " ```\n" -). --spec compare(binary(), binary()) -> gleam@order:order(). -compare(A, B) -> - case A =:= B of - true -> - eq; - - _ -> - case gleam_stdlib:less_than(A, B) of - true -> - lt; - - false -> - gt - end - end. - --file("src/gleam/string.gleam", 194). -?DOC( - " Takes a substring given a start grapheme index and a length. Negative indexes\n" - " are taken starting from the *end* of the list.\n" - "\n" - " This function runs in linear time with the size of the index and the\n" - " length. Negative indexes are linear with the size of the input string in\n" - " addition to the other costs.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " slice(from: \"gleam\", at_index: 1, length: 2)\n" - " // -> \"le\"\n" - " ```\n" - "\n" - " ```gleam\n" - " slice(from: \"gleam\", at_index: 1, length: 10)\n" - " // -> \"leam\"\n" - " ```\n" - "\n" - " ```gleam\n" - " slice(from: \"gleam\", at_index: 10, length: 3)\n" - " // -> \"\"\n" - " ```\n" - "\n" - " ```gleam\n" - " slice(from: \"gleam\", at_index: -2, length: 2)\n" - " // -> \"am\"\n" - " ```\n" - "\n" - " ```gleam\n" - " slice(from: \"gleam\", at_index: -12, length: 2)\n" - " // -> \"\"\n" - " ```\n" -). --spec slice(binary(), integer(), integer()) -> binary(). -slice(String, Idx, Len) -> - case Len =< 0 of - true -> - <<""/utf8>>; - - false -> - case Idx < 0 of - true -> - Translated_idx = string:length(String) + Idx, - case Translated_idx < 0 of - true -> - <<""/utf8>>; - - false -> - gleam_stdlib:slice(String, Translated_idx, Len) - end; - - false -> - gleam_stdlib:slice(String, Idx, Len) - end - end. - --file("src/gleam/string.gleam", 232). -?DOC( - " Drops contents of the first `String` that occur before the second `String`.\n" - " If the `from` string does not contain the `before` string, `from` is\n" - " returned unchanged.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " crop(from: \"The Lone Gunmen\", before: \"Lone\")\n" - " // -> \"Lone Gunmen\"\n" - " ```\n" -). --spec crop(binary(), binary()) -> binary(). -crop(String, Substring) -> - gleam_stdlib:crop_string(String, Substring). - --file("src/gleam/string.gleam", 268). -?DOC( - " Drops *n* graphemes from the end of a `String`.\n" - "\n" - " This function traverses the full string, so it runs in linear time with the\n" - " size of the string. Avoid using this in a loop.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " drop_end(from: \"Cigarette Smoking Man\", up_to: 2)\n" - " // -> \"Cigarette Smoking M\"\n" - " ```\n" -). --spec drop_end(binary(), integer()) -> binary(). -drop_end(String, Num_graphemes) -> - case Num_graphemes =< 0 of - true -> - String; - - false -> - slice(String, 0, string:length(String) - Num_graphemes) - end. - --file("src/gleam/string.gleam", 296). -?DOC( - " Checks if the first `String` contains the second.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " contains(does: \"theory\", contain: \"ory\")\n" - " // -> True\n" - " ```\n" - "\n" - " ```gleam\n" - " contains(does: \"theory\", contain: \"the\")\n" - " // -> True\n" - " ```\n" - "\n" - " ```gleam\n" - " contains(does: \"theory\", contain: \"THE\")\n" - " // -> False\n" - " ```\n" -). --spec contains(binary(), binary()) -> boolean(). -contains(Haystack, Needle) -> - gleam_stdlib:contains_string(Haystack, Needle). - --file("src/gleam/string.gleam", 309). -?DOC( - " Checks whether the first `String` starts with the second one.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " starts_with(\"theory\", \"ory\")\n" - " // -> False\n" - " ```\n" -). --spec starts_with(binary(), binary()) -> boolean(). -starts_with(String, Prefix) -> - gleam_stdlib:string_starts_with(String, Prefix). - --file("src/gleam/string.gleam", 322). -?DOC( - " Checks whether the first `String` ends with the second one.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " ends_with(\"theory\", \"ory\")\n" - " // -> True\n" - " ```\n" -). --spec ends_with(binary(), binary()) -> boolean(). -ends_with(String, Suffix) -> - gleam_stdlib:string_ends_with(String, Suffix). - --file("src/gleam/string.gleam", 361). -?DOC( - " Splits a `String` a single time on the given substring.\n" - "\n" - " Returns an `Error` if substring not present.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " split_once(\"home/gleam/desktop/\", on: \"/\")\n" - " // -> Ok(#(\"home\", \"gleam/desktop/\"))\n" - " ```\n" - "\n" - " ```gleam\n" - " split_once(\"home/gleam/desktop/\", on: \"?\")\n" - " // -> Error(Nil)\n" - " ```\n" -). --spec split_once(binary(), binary()) -> {ok, {binary(), binary()}} | - {error, nil}. -split_once(String, Substring) -> - case string:split(String, Substring) of - [First, Rest] -> - {ok, {First, Rest}}; - - _ -> - {error, nil} - end. - --file("src/gleam/string.gleam", 392). -?DOC( - " Creates a new `String` by joining two `String`s together.\n" - "\n" - " This function typically copies both `String`s and runs in linear time, but\n" - " the exact behaviour will depend on how the runtime you are using optimises\n" - " your code. Benchmark and profile your code if you need to understand its\n" - " performance better.\n" - "\n" - " If you are joining together large string and want to avoid copying any data\n" - " you may want to investigate using the [`string_tree`](../gleam/string_tree.html)\n" - " module.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " append(to: \"butter\", suffix: \"fly\")\n" - " // -> \"butterfly\"\n" - " ```\n" -). --spec append(binary(), binary()) -> binary(). -append(First, Second) -> - <>. - --file("src/gleam/string.gleam", 412). --spec concat_loop(list(binary()), binary()) -> binary(). -concat_loop(Strings, Accumulator) -> - case Strings of - [String | Strings@1] -> - concat_loop(Strings@1, <>); - - [] -> - Accumulator - end. - --file("src/gleam/string.gleam", 408). -?DOC( - " Creates a new `String` by joining many `String`s together.\n" - "\n" - " This function copies all the `String`s and runs in linear time.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " concat([\"never\", \"the\", \"less\"])\n" - " // -> \"nevertheless\"\n" - " ```\n" -). --spec concat(list(binary())) -> binary(). -concat(Strings) -> - erlang:list_to_binary(Strings). - --file("src/gleam/string.gleam", 437). --spec repeat_loop(integer(), binary(), binary()) -> binary(). -repeat_loop(Times, Doubling_acc, Acc) -> - Acc@1 = case Times rem 2 of - 0 -> - Acc; - - _ -> - <> - end, - Times@1 = Times div 2, - case Times@1 =< 0 of - true -> - Acc@1; - - false -> - repeat_loop( - Times@1, - <>, - Acc@1 - ) - end. - --file("src/gleam/string.gleam", 430). -?DOC( - " Creates a new `String` by repeating a `String` a given number of times.\n" - "\n" - " This function runs in loglinear time.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " repeat(\"ha\", times: 3)\n" - " // -> \"hahaha\"\n" - " ```\n" -). --spec repeat(binary(), integer()) -> binary(). -repeat(String, Times) -> - case Times =< 0 of - true -> - <<""/utf8>>; - - false -> - repeat_loop(Times, String, <<""/utf8>>) - end. - --file("src/gleam/string.gleam", 467). --spec join_loop(list(binary()), binary(), binary()) -> binary(). -join_loop(Strings, Separator, Accumulator) -> - case Strings of - [] -> - Accumulator; - - [String | Strings@1] -> - join_loop( - Strings@1, - Separator, - <<<>/binary, - String/binary>> - ) - end. - --file("src/gleam/string.gleam", 460). -?DOC( - " Joins many `String`s together with a given separator.\n" - "\n" - " This function runs in linear time.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " join([\"home\",\"evan\",\"Desktop\"], with: \"/\")\n" - " // -> \"home/evan/Desktop\"\n" - " ```\n" -). --spec join(list(binary()), binary()) -> binary(). -join(Strings, Separator) -> - case Strings of - [] -> - <<""/utf8>>; - - [First | Rest] -> - join_loop(Rest, Separator, First) - end. - --file("src/gleam/string.gleam", 545). --spec padding(integer(), binary()) -> binary(). -padding(Size, Pad_string) -> - Pad_string_length = string:length(Pad_string), - Num_pads = case Pad_string_length of - 0 -> 0; - Gleam@denominator -> Size div Gleam@denominator - end, - Extra = case Pad_string_length of - 0 -> 0; - Gleam@denominator@1 -> Size rem Gleam@denominator@1 - end, - <<(repeat(Pad_string, Num_pads))/binary, - (slice(Pad_string, 0, Extra))/binary>>. - --file("src/gleam/string.gleam", 498). -?DOC( - " Pads the start of a `String` until it has a given length.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " pad_start(\"121\", to: 5, with: \".\")\n" - " // -> \"..121\"\n" - " ```\n" - "\n" - " ```gleam\n" - " pad_start(\"121\", to: 3, with: \".\")\n" - " // -> \"121\"\n" - " ```\n" - "\n" - " ```gleam\n" - " pad_start(\"121\", to: 2, with: \".\")\n" - " // -> \"121\"\n" - " ```\n" -). --spec pad_start(binary(), integer(), binary()) -> binary(). -pad_start(String, Desired_length, Pad_string) -> - Current_length = string:length(String), - To_pad_length = Desired_length - Current_length, - case To_pad_length =< 0 of - true -> - String; - - false -> - <<(padding(To_pad_length, Pad_string))/binary, String/binary>> - end. - --file("src/gleam/string.gleam", 531). -?DOC( - " Pads the end of a `String` until it has a given length.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " pad_end(\"123\", to: 5, with: \".\")\n" - " // -> \"123..\"\n" - " ```\n" - "\n" - " ```gleam\n" - " pad_end(\"123\", to: 3, with: \".\")\n" - " // -> \"123\"\n" - " ```\n" - "\n" - " ```gleam\n" - " pad_end(\"123\", to: 2, with: \".\")\n" - " // -> \"123\"\n" - " ```\n" -). --spec pad_end(binary(), integer(), binary()) -> binary(). -pad_end(String, Desired_length, Pad_string) -> - Current_length = string:length(String), - To_pad_length = Desired_length - Current_length, - case To_pad_length =< 0 of - true -> - String; - - false -> - <> - end. - --file("src/gleam/string.gleam", 589). -?DOC( - " Removes whitespace at the start of a `String`.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " trim_start(\" hats \\n\")\n" - " // -> \"hats \\n\"\n" - " ```\n" -). --spec trim_start(binary()) -> binary(). -trim_start(String) -> - string:trim(String, leading). - --file("src/gleam/string.gleam", 603). -?DOC( - " Removes whitespace at the end of a `String`.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " trim_end(\" hats \\n\")\n" - " // -> \" hats\"\n" - " ```\n" -). --spec trim_end(binary()) -> binary(). -trim_end(String) -> - string:trim(String, trailing). - --file("src/gleam/string.gleam", 567). -?DOC( - " Removes whitespace on both sides of a `String`.\n" - "\n" - " Whitespace in this function is the set of nonbreakable whitespace\n" - " codepoints, defined as Pattern_White_Space in [Unicode Standard Annex #31][1].\n" - "\n" - " [1]: https://unicode.org/reports/tr31/\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " trim(\" hats \\n\")\n" - " // -> \"hats\"\n" - " ```\n" -). --spec trim(binary()) -> binary(). -trim(String) -> - _pipe = String, - _pipe@1 = trim_start(_pipe), - trim_end(_pipe@1). - --file("src/gleam/string.gleam", 630). -?DOC( - " Splits a non-empty `String` into its first element (head) and rest (tail).\n" - " This lets you pattern match on `String`s exactly as you would with lists.\n" - "\n" - " ## Performance\n" - "\n" - " There is a notable overhead to using this function, so you may not want to\n" - " use it in a tight loop. If you wish to efficiently parse a string you may\n" - " want to use alternatives such as the [splitter package](https://hex.pm/packages/splitter).\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " pop_grapheme(\"gleam\")\n" - " // -> Ok(#(\"g\", \"leam\"))\n" - " ```\n" - "\n" - " ```gleam\n" - " pop_grapheme(\"\")\n" - " // -> Error(Nil)\n" - " ```\n" -). --spec pop_grapheme(binary()) -> {ok, {binary(), binary()}} | {error, nil}. -pop_grapheme(String) -> - gleam_stdlib:string_pop_grapheme(String). - --file("src/gleam/string.gleam", 647). --spec to_graphemes_loop(binary(), list(binary())) -> list(binary()). -to_graphemes_loop(String, Acc) -> - case gleam_stdlib:string_pop_grapheme(String) of - {ok, {Grapheme, Rest}} -> - to_graphemes_loop(Rest, [Grapheme | Acc]); - - {error, _} -> - Acc - end. - --file("src/gleam/string.gleam", 641). -?DOC( - " Converts a `String` to a list of\n" - " [graphemes](https://en.wikipedia.org/wiki/Grapheme).\n" - "\n" - " ```gleam\n" - " to_graphemes(\"abc\")\n" - " // -> [\"a\", \"b\", \"c\"]\n" - " ```\n" -). --spec to_graphemes(binary()) -> list(binary()). -to_graphemes(String) -> - _pipe = String, - _pipe@1 = to_graphemes_loop(_pipe, []), - lists:reverse(_pipe@1). - --file("src/gleam/string.gleam", 333). -?DOC( - " Creates a list of `String`s by splitting a given string on a given substring.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " split(\"home/gleam/desktop/\", on: \"/\")\n" - " // -> [\"home\", \"gleam\", \"desktop\", \"\"]\n" - " ```\n" -). --spec split(binary(), binary()) -> list(binary()). -split(X, Substring) -> - case Substring of - <<""/utf8>> -> - to_graphemes(X); - - _ -> - _pipe = X, - _pipe@1 = gleam_stdlib:identity(_pipe), - _pipe@2 = gleam@string_tree:split(_pipe@1, Substring), - gleam@list:map(_pipe@2, fun unicode:characters_to_binary/1) - end. - --file("src/gleam/string.gleam", 694). --spec to_utf_codepoints_loop(bitstring(), list(integer())) -> list(integer()). -to_utf_codepoints_loop(Bit_array, Acc) -> - case Bit_array of - <> -> - to_utf_codepoints_loop(Rest, [First | Acc]); - - _ -> - lists:reverse(Acc) - end. - --file("src/gleam/string.gleam", 689). --spec do_to_utf_codepoints(binary()) -> list(integer()). -do_to_utf_codepoints(String) -> - to_utf_codepoints_loop(<>, []). - --file("src/gleam/string.gleam", 684). -?DOC( - " Converts a `String` to a `List` of `UtfCodepoint`.\n" - "\n" - " See and\n" - " for an\n" - " explanation on code points.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " \"a\" |> to_utf_codepoints\n" - " // -> [UtfCodepoint(97)]\n" - " ```\n" - "\n" - " ```gleam\n" - " // Semantically the same as:\n" - " // [\"🏳\", \"️\", \"‍\", \"🌈\"] or:\n" - " // [waving_white_flag, variant_selector_16, zero_width_joiner, rainbow]\n" - " \"🏳️‍🌈\" |> to_utf_codepoints\n" - " // -> [\n" - " // UtfCodepoint(127987),\n" - " // UtfCodepoint(65039),\n" - " // UtfCodepoint(8205),\n" - " // UtfCodepoint(127752),\n" - " // ]\n" - " ```\n" -). --spec to_utf_codepoints(binary()) -> list(integer()). -to_utf_codepoints(String) -> - do_to_utf_codepoints(String). - --file("src/gleam/string.gleam", 734). -?DOC( - " Converts a `List` of `UtfCodepoint`s to a `String`.\n" - "\n" - " See and\n" - " for an\n" - " explanation on code points.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " let assert Ok(a) = utf_codepoint(97)\n" - " let assert Ok(b) = utf_codepoint(98)\n" - " let assert Ok(c) = utf_codepoint(99)\n" - " from_utf_codepoints([a, b, c])\n" - " // -> \"abc\"\n" - " ```\n" -). --spec from_utf_codepoints(list(integer())) -> binary(). -from_utf_codepoints(Utf_codepoints) -> - gleam_stdlib:utf_codepoint_list_to_string(Utf_codepoints). - --file("src/gleam/string.gleam", 740). -?DOC( - " Converts an integer to a `UtfCodepoint`.\n" - "\n" - " Returns an `Error` if the integer does not represent a valid UTF codepoint.\n" -). --spec utf_codepoint(integer()) -> {ok, integer()} | {error, nil}. -utf_codepoint(Value) -> - case Value of - I when I > 1114111 -> - {error, nil}; - - I@1 when (I@1 >= 55296) andalso (I@1 =< 57343) -> - {error, nil}; - - I@2 when I@2 < 0 -> - {error, nil}; - - I@3 -> - {ok, gleam_stdlib:identity(I@3)} - end. - --file("src/gleam/string.gleam", 761). -?DOC( - " Converts an UtfCodepoint to its ordinal code point value.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " let assert [utf_codepoint, ..] = to_utf_codepoints(\"💜\")\n" - " utf_codepoint_to_int(utf_codepoint)\n" - " // -> 128156\n" - " ```\n" -). --spec utf_codepoint_to_int(integer()) -> integer(). -utf_codepoint_to_int(Cp) -> - gleam_stdlib:identity(Cp). - --file("src/gleam/string.gleam", 778). -?DOC( - " Converts a `String` into `Option(String)` where an empty `String` becomes\n" - " `None`.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " to_option(\"\")\n" - " // -> None\n" - " ```\n" - "\n" - " ```gleam\n" - " to_option(\"hats\")\n" - " // -> Some(\"hats\")\n" - " ```\n" -). --spec to_option(binary()) -> gleam@option:option(binary()). -to_option(String) -> - case String of - <<""/utf8>> -> - none; - - _ -> - {some, String} - end. - --file("src/gleam/string.gleam", 801). -?DOC( - " Returns the first grapheme cluster in a given `String` and wraps it in a\n" - " `Result(String, Nil)`. If the `String` is empty, it returns `Error(Nil)`.\n" - " Otherwise, it returns `Ok(String)`.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " first(\"\")\n" - " // -> Error(Nil)\n" - " ```\n" - "\n" - " ```gleam\n" - " first(\"icecream\")\n" - " // -> Ok(\"i\")\n" - " ```\n" -). --spec first(binary()) -> {ok, binary()} | {error, nil}. -first(String) -> - case gleam_stdlib:string_pop_grapheme(String) of - {ok, {First, _}} -> - {ok, First}; - - {error, E} -> - {error, E} - end. - --file("src/gleam/string.gleam", 827). -?DOC( - " Returns the last grapheme cluster in a given `String` and wraps it in a\n" - " `Result(String, Nil)`. If the `String` is empty, it returns `Error(Nil)`.\n" - " Otherwise, it returns `Ok(String)`.\n" - "\n" - " This function traverses the full string, so it runs in linear time with the\n" - " length of the string. Avoid using this in a loop.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " last(\"\")\n" - " // -> Error(Nil)\n" - " ```\n" - "\n" - " ```gleam\n" - " last(\"icecream\")\n" - " // -> Ok(\"m\")\n" - " ```\n" -). --spec last(binary()) -> {ok, binary()} | {error, nil}. -last(String) -> - case gleam_stdlib:string_pop_grapheme(String) of - {ok, {First, <<""/utf8>>}} -> - {ok, First}; - - {ok, {_, Rest}} -> - {ok, slice(Rest, -1, 1)}; - - {error, E} -> - {error, E} - end. - --file("src/gleam/string.gleam", 845). -?DOC( - " Creates a new `String` with the first grapheme in the input `String`\n" - " converted to uppercase and the remaining graphemes to lowercase.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " capitalise(\"mamouna\")\n" - " // -> \"Mamouna\"\n" - " ```\n" -). --spec capitalise(binary()) -> binary(). -capitalise(String) -> - case gleam_stdlib:string_pop_grapheme(String) of - {ok, {First, Rest}} -> - append(string:uppercase(First), string:lowercase(Rest)); - - {error, _} -> - <<""/utf8>> - end. - --file("src/gleam/string.gleam", 876). -?DOC( - " Returns a `String` representation of a term in Gleam syntax.\n" - "\n" - " This may be occasionally useful for quick-and-dirty printing of values in\n" - " scripts. For error reporting and other uses prefer constructing strings by\n" - " pattern matching on the values.\n" - "\n" - " ## Limitations\n" - "\n" - " The output format of this function is not stable and could change at any\n" - " time. The output is not suitable for parsing.\n" - "\n" - " This function works using runtime reflection, so the output may not be\n" - " perfectly accurate for data structures where the runtime structure doesn't\n" - " hold enough information to determine the original syntax. For example,\n" - " tuples with an Erlang atom in the first position will be mistaken for Gleam\n" - " records.\n" - "\n" - " ## Security and safety\n" - "\n" - " There is no limit to how large the strings that this function can produce.\n" - " Be careful not to call this function with large data structures or you\n" - " could use very large amounts of memory, potentially causing runtime\n" - " problems.\n" -). --spec inspect(any()) -> binary(). -inspect(Term) -> - _pipe = Term, - _pipe@1 = gleam_stdlib:inspect(_pipe), - unicode:characters_to_binary(_pipe@1). - --file("src/gleam/string.gleam", 900). -?DOC( - " Returns the number of bytes in a `String`.\n" - "\n" - " This function runs in constant time on Erlang and in linear time on\n" - " JavaScript.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " byte_size(\"🏳️‍⚧️🏳️‍🌈👩🏾‍❤️‍👨🏻\")\n" - " // -> 58\n" - " ```\n" -). --spec byte_size(binary()) -> integer(). -byte_size(String) -> - erlang:byte_size(String). - --file("src/gleam/string.gleam", 245). -?DOC( - " Drops *n* graphemes from the start of a `String`.\n" - "\n" - " This function runs in linear time with the number of graphemes to drop.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " drop_start(from: \"The Lone Gunmen\", up_to: 2)\n" - " // -> \"e Lone Gunmen\"\n" - " ```\n" -). --spec drop_start(binary(), integer()) -> binary(). -drop_start(String, Num_graphemes) -> - case Num_graphemes =< 0 of - true -> - String; - - false -> - Prefix = gleam_stdlib:slice(String, 0, Num_graphemes), - Prefix_size = erlang:byte_size(Prefix), - binary:part( - String, - Prefix_size, - erlang:byte_size(String) - Prefix_size - ) - end. diff --git a/build/dev/javascript/gleam_stdlib/gleam@string_tree.erl b/build/dev/javascript/gleam_stdlib/gleam@string_tree.erl deleted file mode 100644 index 0d72b4d..0000000 --- a/build/dev/javascript/gleam_stdlib/gleam@string_tree.erl +++ /dev/null @@ -1,207 +0,0 @@ --module(gleam@string_tree). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "src/gleam/string_tree.gleam"). --export([append_tree/2, prepend_tree/2, from_strings/1, new/0, concat/1, from_string/1, prepend/2, append/2, to_string/1, byte_size/1, join/2, lowercase/1, uppercase/1, reverse/1, split/2, replace/3, is_equal/2, is_empty/1]). --export_type([string_tree/0, direction/0]). - --if(?OTP_RELEASE >= 27). --define(MODULEDOC(Str), -moduledoc(Str)). --define(DOC(Str), -doc(Str)). --else. --define(MODULEDOC(Str), -compile([])). --define(DOC(Str), -compile([])). --endif. - --type string_tree() :: any(). - --type direction() :: all. - --file("src/gleam/string_tree.gleam", 61). -?DOC( - " Appends some `StringTree` onto the end of another.\n" - "\n" - " Runs in constant time.\n" -). --spec append_tree(string_tree(), string_tree()) -> string_tree(). -append_tree(Tree, Suffix) -> - gleam_stdlib:iodata_append(Tree, Suffix). - --file("src/gleam/string_tree.gleam", 48). -?DOC( - " Prepends some `StringTree` onto the start of another.\n" - "\n" - " Runs in constant time.\n" -). --spec prepend_tree(string_tree(), string_tree()) -> string_tree(). -prepend_tree(Tree, Prefix) -> - gleam_stdlib:iodata_append(Prefix, Tree). - --file("src/gleam/string_tree.gleam", 69). -?DOC( - " Converts a list of strings into a `StringTree`.\n" - "\n" - " Runs in constant time.\n" -). --spec from_strings(list(binary())) -> string_tree(). -from_strings(Strings) -> - gleam_stdlib:identity(Strings). - --file("src/gleam/string_tree.gleam", 24). -?DOC( - " Create an empty `StringTree`. Useful as the start of a pipe chaining many\n" - " trees together.\n" -). --spec new() -> string_tree(). -new() -> - gleam_stdlib:identity([]). - --file("src/gleam/string_tree.gleam", 77). -?DOC( - " Joins a list of trees into a single tree.\n" - "\n" - " Runs in constant time.\n" -). --spec concat(list(string_tree())) -> string_tree(). -concat(Trees) -> - gleam_stdlib:identity(Trees). - --file("src/gleam/string_tree.gleam", 85). -?DOC( - " Converts a string into a `StringTree`.\n" - "\n" - " Runs in constant time.\n" -). --spec from_string(binary()) -> string_tree(). -from_string(String) -> - gleam_stdlib:identity(String). - --file("src/gleam/string_tree.gleam", 32). -?DOC( - " Prepends a `String` onto the start of some `StringTree`.\n" - "\n" - " Runs in constant time.\n" -). --spec prepend(string_tree(), binary()) -> string_tree(). -prepend(Tree, Prefix) -> - gleam_stdlib:iodata_append(gleam_stdlib:identity(Prefix), Tree). - --file("src/gleam/string_tree.gleam", 40). -?DOC( - " Appends a `String` onto the end of some `StringTree`.\n" - "\n" - " Runs in constant time.\n" -). --spec append(string_tree(), binary()) -> string_tree(). -append(Tree, Second) -> - gleam_stdlib:iodata_append(Tree, gleam_stdlib:identity(Second)). - --file("src/gleam/string_tree.gleam", 94). -?DOC( - " Turns a `StringTree` into a `String`\n" - "\n" - " This function is implemented natively by the virtual machine and is highly\n" - " optimised.\n" -). --spec to_string(string_tree()) -> binary(). -to_string(Tree) -> - unicode:characters_to_binary(Tree). - --file("src/gleam/string_tree.gleam", 100). -?DOC(" Returns the size of the `StringTree` in bytes.\n"). --spec byte_size(string_tree()) -> integer(). -byte_size(Tree) -> - erlang:iolist_size(Tree). - --file("src/gleam/string_tree.gleam", 104). -?DOC(" Joins the given trees into a new tree separated with the given string.\n"). --spec join(list(string_tree()), binary()) -> string_tree(). -join(Trees, Sep) -> - _pipe = Trees, - _pipe@1 = gleam@list:intersperse(_pipe, gleam_stdlib:identity(Sep)), - gleam_stdlib:identity(_pipe@1). - --file("src/gleam/string_tree.gleam", 115). -?DOC( - " Converts a `StringTree` to a new one where the contents have been\n" - " lowercased.\n" -). --spec lowercase(string_tree()) -> string_tree(). -lowercase(Tree) -> - string:lowercase(Tree). - --file("src/gleam/string_tree.gleam", 122). -?DOC( - " Converts a `StringTree` to a new one where the contents have been\n" - " uppercased.\n" -). --spec uppercase(string_tree()) -> string_tree(). -uppercase(Tree) -> - string:uppercase(Tree). - --file("src/gleam/string_tree.gleam", 127). -?DOC(" Converts a `StringTree` to a new one with the contents reversed.\n"). --spec reverse(string_tree()) -> string_tree(). -reverse(Tree) -> - string:reverse(Tree). - --file("src/gleam/string_tree.gleam", 145). -?DOC(" Splits a `StringTree` on a given pattern into a list of trees.\n"). --spec split(string_tree(), binary()) -> list(string_tree()). -split(Tree, Pattern) -> - string:split(Tree, Pattern, all). - --file("src/gleam/string_tree.gleam", 156). -?DOC(" Replaces all instances of a pattern with a given string substitute.\n"). --spec replace(string_tree(), binary(), binary()) -> string_tree(). -replace(Tree, Pattern, Substitute) -> - gleam_stdlib:string_replace(Tree, Pattern, Substitute). - --file("src/gleam/string_tree.gleam", 182). -?DOC( - " Compares two string trees to determine if they have the same textual\n" - " content.\n" - "\n" - " Comparing two string trees using the `==` operator may return `False` even\n" - " if they have the same content as they may have been build in different ways,\n" - " so using this function is often preferred.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " from_strings([\"a\", \"b\"]) == from_string(\"ab\")\n" - " // -> False\n" - " ```\n" - "\n" - " ```gleam\n" - " is_equal(from_strings([\"a\", \"b\"]), from_string(\"ab\"))\n" - " // -> True\n" - " ```\n" -). --spec is_equal(string_tree(), string_tree()) -> boolean(). -is_equal(A, B) -> - string:equal(A, B). - --file("src/gleam/string_tree.gleam", 206). -?DOC( - " Inspects a `StringTree` to determine if it is equivalent to an empty string.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " from_string(\"ok\") |> is_empty\n" - " // -> False\n" - " ```\n" - "\n" - " ```gleam\n" - " from_string(\"\") |> is_empty\n" - " // -> True\n" - " ```\n" - "\n" - " ```gleam\n" - " from_strings([]) |> is_empty\n" - " // -> True\n" - " ```\n" -). --spec is_empty(string_tree()) -> boolean(). -is_empty(Tree) -> - string:is_empty(Tree). diff --git a/build/dev/javascript/gleam_stdlib/gleam@uri.erl b/build/dev/javascript/gleam_stdlib/gleam@uri.erl deleted file mode 100644 index 0819463..0000000 --- a/build/dev/javascript/gleam_stdlib/gleam@uri.erl +++ /dev/null @@ -1,1044 +0,0 @@ --module(gleam@uri). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "src/gleam/uri.gleam"). --export([parse_query/1, percent_encode/1, query_to_string/1, percent_decode/1, path_segments/1, to_string/1, origin/1, merge/2, parse/1]). --export_type([uri/0]). - --if(?OTP_RELEASE >= 27). --define(MODULEDOC(Str), -moduledoc(Str)). --define(DOC(Str), -doc(Str)). --else. --define(MODULEDOC(Str), -compile([])). --define(DOC(Str), -compile([])). --endif. - -?MODULEDOC( - " Utilities for working with URIs\n" - "\n" - " This module provides functions for working with URIs (for example, parsing\n" - " URIs or encoding query strings). The functions in this module are implemented\n" - " according to [RFC 3986](https://tools.ietf.org/html/rfc3986).\n" - "\n" - " Query encoding (Form encoding) is defined in the\n" - " [W3C specification](https://www.w3.org/TR/html52/sec-forms.html#urlencoded-form-data).\n" -). - --type uri() :: {uri, - gleam@option:option(binary()), - gleam@option:option(binary()), - gleam@option:option(binary()), - gleam@option:option(integer()), - binary(), - gleam@option:option(binary()), - gleam@option:option(binary())}. - --file("src/gleam/uri.gleam", 289). --spec is_valid_host_within_brackets_char(integer()) -> boolean(). -is_valid_host_within_brackets_char(Char) -> - (((((48 >= Char) andalso (Char =< 57)) orelse ((65 >= Char) andalso (Char =< 90))) - orelse ((97 >= Char) andalso (Char =< 122))) - orelse (Char =:= 58)) - orelse (Char =:= 46). - --file("src/gleam/uri.gleam", 506). --spec parse_fragment(binary(), uri()) -> {ok, uri()} | {error, nil}. -parse_fragment(Rest, Pieces) -> - {ok, - {uri, - erlang:element(2, Pieces), - erlang:element(3, Pieces), - erlang:element(4, Pieces), - erlang:element(5, Pieces), - erlang:element(6, Pieces), - erlang:element(7, Pieces), - {some, Rest}}}. - --file("src/gleam/uri.gleam", 478). --spec parse_query_with_question_mark_loop(binary(), binary(), uri(), integer()) -> {ok, - uri()} | - {error, nil}. -parse_query_with_question_mark_loop(Original, Uri_string, Pieces, Size) -> - case Uri_string of - <<"#"/utf8, Rest/binary>> when Size =:= 0 -> - parse_fragment(Rest, Pieces); - - <<"#"/utf8, Rest@1/binary>> -> - Query = binary:part(Original, 0, Size), - Pieces@1 = {uri, - erlang:element(2, Pieces), - erlang:element(3, Pieces), - erlang:element(4, Pieces), - erlang:element(5, Pieces), - erlang:element(6, Pieces), - {some, Query}, - erlang:element(8, Pieces)}, - parse_fragment(Rest@1, Pieces@1); - - <<""/utf8>> -> - {ok, - {uri, - erlang:element(2, Pieces), - erlang:element(3, Pieces), - erlang:element(4, Pieces), - erlang:element(5, Pieces), - erlang:element(6, Pieces), - {some, Original}, - erlang:element(8, Pieces)}}; - - _ -> - {_, Rest@2} = gleam_stdlib:string_pop_codeunit(Uri_string), - parse_query_with_question_mark_loop( - Original, - Rest@2, - Pieces, - Size + 1 - ) - end. - --file("src/gleam/uri.gleam", 471). --spec parse_query_with_question_mark(binary(), uri()) -> {ok, uri()} | - {error, nil}. -parse_query_with_question_mark(Uri_string, Pieces) -> - parse_query_with_question_mark_loop(Uri_string, Uri_string, Pieces, 0). - --file("src/gleam/uri.gleam", 437). --spec parse_path_loop(binary(), binary(), uri(), integer()) -> {ok, uri()} | - {error, nil}. -parse_path_loop(Original, Uri_string, Pieces, Size) -> - case Uri_string of - <<"?"/utf8, Rest/binary>> -> - Path = binary:part(Original, 0, Size), - Pieces@1 = {uri, - erlang:element(2, Pieces), - erlang:element(3, Pieces), - erlang:element(4, Pieces), - erlang:element(5, Pieces), - Path, - erlang:element(7, Pieces), - erlang:element(8, Pieces)}, - parse_query_with_question_mark(Rest, Pieces@1); - - <<"#"/utf8, Rest@1/binary>> -> - Path@1 = binary:part(Original, 0, Size), - Pieces@2 = {uri, - erlang:element(2, Pieces), - erlang:element(3, Pieces), - erlang:element(4, Pieces), - erlang:element(5, Pieces), - Path@1, - erlang:element(7, Pieces), - erlang:element(8, Pieces)}, - parse_fragment(Rest@1, Pieces@2); - - <<""/utf8>> -> - {ok, - {uri, - erlang:element(2, Pieces), - erlang:element(3, Pieces), - erlang:element(4, Pieces), - erlang:element(5, Pieces), - Original, - erlang:element(7, Pieces), - erlang:element(8, Pieces)}}; - - _ -> - {_, Rest@2} = gleam_stdlib:string_pop_codeunit(Uri_string), - parse_path_loop(Original, Rest@2, Pieces, Size + 1) - end. - --file("src/gleam/uri.gleam", 433). --spec parse_path(binary(), uri()) -> {ok, uri()} | {error, nil}. -parse_path(Uri_string, Pieces) -> - parse_path_loop(Uri_string, Uri_string, Pieces, 0). - --file("src/gleam/uri.gleam", 388). --spec parse_port_loop(binary(), uri(), integer()) -> {ok, uri()} | {error, nil}. -parse_port_loop(Uri_string, Pieces, Port) -> - case Uri_string of - <<"0"/utf8, Rest/binary>> -> - parse_port_loop(Rest, Pieces, Port * 10); - - <<"1"/utf8, Rest@1/binary>> -> - parse_port_loop(Rest@1, Pieces, (Port * 10) + 1); - - <<"2"/utf8, Rest@2/binary>> -> - parse_port_loop(Rest@2, Pieces, (Port * 10) + 2); - - <<"3"/utf8, Rest@3/binary>> -> - parse_port_loop(Rest@3, Pieces, (Port * 10) + 3); - - <<"4"/utf8, Rest@4/binary>> -> - parse_port_loop(Rest@4, Pieces, (Port * 10) + 4); - - <<"5"/utf8, Rest@5/binary>> -> - parse_port_loop(Rest@5, Pieces, (Port * 10) + 5); - - <<"6"/utf8, Rest@6/binary>> -> - parse_port_loop(Rest@6, Pieces, (Port * 10) + 6); - - <<"7"/utf8, Rest@7/binary>> -> - parse_port_loop(Rest@7, Pieces, (Port * 10) + 7); - - <<"8"/utf8, Rest@8/binary>> -> - parse_port_loop(Rest@8, Pieces, (Port * 10) + 8); - - <<"9"/utf8, Rest@9/binary>> -> - parse_port_loop(Rest@9, Pieces, (Port * 10) + 9); - - <<"?"/utf8, Rest@10/binary>> -> - Pieces@1 = {uri, - erlang:element(2, Pieces), - erlang:element(3, Pieces), - erlang:element(4, Pieces), - {some, Port}, - erlang:element(6, Pieces), - erlang:element(7, Pieces), - erlang:element(8, Pieces)}, - parse_query_with_question_mark(Rest@10, Pieces@1); - - <<"#"/utf8, Rest@11/binary>> -> - Pieces@2 = {uri, - erlang:element(2, Pieces), - erlang:element(3, Pieces), - erlang:element(4, Pieces), - {some, Port}, - erlang:element(6, Pieces), - erlang:element(7, Pieces), - erlang:element(8, Pieces)}, - parse_fragment(Rest@11, Pieces@2); - - <<"/"/utf8, _/binary>> -> - Pieces@3 = {uri, - erlang:element(2, Pieces), - erlang:element(3, Pieces), - erlang:element(4, Pieces), - {some, Port}, - erlang:element(6, Pieces), - erlang:element(7, Pieces), - erlang:element(8, Pieces)}, - parse_path(Uri_string, Pieces@3); - - <<""/utf8>> -> - {ok, - {uri, - erlang:element(2, Pieces), - erlang:element(3, Pieces), - erlang:element(4, Pieces), - {some, Port}, - erlang:element(6, Pieces), - erlang:element(7, Pieces), - erlang:element(8, Pieces)}}; - - _ -> - {error, nil} - end. - --file("src/gleam/uri.gleam", 353). --spec parse_port(binary(), uri()) -> {ok, uri()} | {error, nil}. -parse_port(Uri_string, Pieces) -> - case Uri_string of - <<":0"/utf8, Rest/binary>> -> - parse_port_loop(Rest, Pieces, 0); - - <<":1"/utf8, Rest@1/binary>> -> - parse_port_loop(Rest@1, Pieces, 1); - - <<":2"/utf8, Rest@2/binary>> -> - parse_port_loop(Rest@2, Pieces, 2); - - <<":3"/utf8, Rest@3/binary>> -> - parse_port_loop(Rest@3, Pieces, 3); - - <<":4"/utf8, Rest@4/binary>> -> - parse_port_loop(Rest@4, Pieces, 4); - - <<":5"/utf8, Rest@5/binary>> -> - parse_port_loop(Rest@5, Pieces, 5); - - <<":6"/utf8, Rest@6/binary>> -> - parse_port_loop(Rest@6, Pieces, 6); - - <<":7"/utf8, Rest@7/binary>> -> - parse_port_loop(Rest@7, Pieces, 7); - - <<":8"/utf8, Rest@8/binary>> -> - parse_port_loop(Rest@8, Pieces, 8); - - <<":9"/utf8, Rest@9/binary>> -> - parse_port_loop(Rest@9, Pieces, 9); - - <<":"/utf8>> -> - {ok, Pieces}; - - <<""/utf8>> -> - {ok, Pieces}; - - <<"?"/utf8, Rest@10/binary>> -> - parse_query_with_question_mark(Rest@10, Pieces); - - <<":?"/utf8, Rest@10/binary>> -> - parse_query_with_question_mark(Rest@10, Pieces); - - <<"#"/utf8, Rest@11/binary>> -> - parse_fragment(Rest@11, Pieces); - - <<":#"/utf8, Rest@11/binary>> -> - parse_fragment(Rest@11, Pieces); - - <<"/"/utf8, _/binary>> -> - parse_path(Uri_string, Pieces); - - <<":"/utf8, Rest@12/binary>> -> - case Rest@12 of - <<"/"/utf8, _/binary>> -> - parse_path(Rest@12, Pieces); - - _ -> - {error, nil} - end; - - _ -> - {error, nil} - end. - --file("src/gleam/uri.gleam", 309). --spec parse_host_outside_of_brackets_loop(binary(), binary(), uri(), integer()) -> {ok, - uri()} | - {error, nil}. -parse_host_outside_of_brackets_loop(Original, Uri_string, Pieces, Size) -> - case Uri_string of - <<""/utf8>> -> - {ok, - {uri, - erlang:element(2, Pieces), - erlang:element(3, Pieces), - {some, Original}, - erlang:element(5, Pieces), - erlang:element(6, Pieces), - erlang:element(7, Pieces), - erlang:element(8, Pieces)}}; - - <<":"/utf8, _/binary>> -> - Host = binary:part(Original, 0, Size), - Pieces@1 = {uri, - erlang:element(2, Pieces), - erlang:element(3, Pieces), - {some, Host}, - erlang:element(5, Pieces), - erlang:element(6, Pieces), - erlang:element(7, Pieces), - erlang:element(8, Pieces)}, - parse_port(Uri_string, Pieces@1); - - <<"/"/utf8, _/binary>> -> - Host@1 = binary:part(Original, 0, Size), - Pieces@2 = {uri, - erlang:element(2, Pieces), - erlang:element(3, Pieces), - {some, Host@1}, - erlang:element(5, Pieces), - erlang:element(6, Pieces), - erlang:element(7, Pieces), - erlang:element(8, Pieces)}, - parse_path(Uri_string, Pieces@2); - - <<"?"/utf8, Rest/binary>> -> - Host@2 = binary:part(Original, 0, Size), - Pieces@3 = {uri, - erlang:element(2, Pieces), - erlang:element(3, Pieces), - {some, Host@2}, - erlang:element(5, Pieces), - erlang:element(6, Pieces), - erlang:element(7, Pieces), - erlang:element(8, Pieces)}, - parse_query_with_question_mark(Rest, Pieces@3); - - <<"#"/utf8, Rest@1/binary>> -> - Host@3 = binary:part(Original, 0, Size), - Pieces@4 = {uri, - erlang:element(2, Pieces), - erlang:element(3, Pieces), - {some, Host@3}, - erlang:element(5, Pieces), - erlang:element(6, Pieces), - erlang:element(7, Pieces), - erlang:element(8, Pieces)}, - parse_fragment(Rest@1, Pieces@4); - - _ -> - {_, Rest@2} = gleam_stdlib:string_pop_codeunit(Uri_string), - parse_host_outside_of_brackets_loop( - Original, - Rest@2, - Pieces, - Size + 1 - ) - end. - --file("src/gleam/uri.gleam", 229). --spec parse_host_within_brackets_loop(binary(), binary(), uri(), integer()) -> {ok, - uri()} | - {error, nil}. -parse_host_within_brackets_loop(Original, Uri_string, Pieces, Size) -> - case Uri_string of - <<""/utf8>> -> - {ok, - {uri, - erlang:element(2, Pieces), - erlang:element(3, Pieces), - {some, Uri_string}, - erlang:element(5, Pieces), - erlang:element(6, Pieces), - erlang:element(7, Pieces), - erlang:element(8, Pieces)}}; - - <<"]"/utf8, Rest/binary>> when Size =:= 0 -> - parse_port(Rest, Pieces); - - <<"]"/utf8, Rest@1/binary>> -> - Host = binary:part(Original, 0, Size + 1), - Pieces@1 = {uri, - erlang:element(2, Pieces), - erlang:element(3, Pieces), - {some, Host}, - erlang:element(5, Pieces), - erlang:element(6, Pieces), - erlang:element(7, Pieces), - erlang:element(8, Pieces)}, - parse_port(Rest@1, Pieces@1); - - <<"/"/utf8, _/binary>> when Size =:= 0 -> - parse_path(Uri_string, Pieces); - - <<"/"/utf8, _/binary>> -> - Host@1 = binary:part(Original, 0, Size), - Pieces@2 = {uri, - erlang:element(2, Pieces), - erlang:element(3, Pieces), - {some, Host@1}, - erlang:element(5, Pieces), - erlang:element(6, Pieces), - erlang:element(7, Pieces), - erlang:element(8, Pieces)}, - parse_path(Uri_string, Pieces@2); - - <<"?"/utf8, Rest@2/binary>> when Size =:= 0 -> - parse_query_with_question_mark(Rest@2, Pieces); - - <<"?"/utf8, Rest@3/binary>> -> - Host@2 = binary:part(Original, 0, Size), - Pieces@3 = {uri, - erlang:element(2, Pieces), - erlang:element(3, Pieces), - {some, Host@2}, - erlang:element(5, Pieces), - erlang:element(6, Pieces), - erlang:element(7, Pieces), - erlang:element(8, Pieces)}, - parse_query_with_question_mark(Rest@3, Pieces@3); - - <<"#"/utf8, Rest@4/binary>> when Size =:= 0 -> - parse_fragment(Rest@4, Pieces); - - <<"#"/utf8, Rest@5/binary>> -> - Host@3 = binary:part(Original, 0, Size), - Pieces@4 = {uri, - erlang:element(2, Pieces), - erlang:element(3, Pieces), - {some, Host@3}, - erlang:element(5, Pieces), - erlang:element(6, Pieces), - erlang:element(7, Pieces), - erlang:element(8, Pieces)}, - parse_fragment(Rest@5, Pieces@4); - - _ -> - {Char, Rest@6} = gleam_stdlib:string_pop_codeunit(Uri_string), - case is_valid_host_within_brackets_char(Char) of - true -> - parse_host_within_brackets_loop( - Original, - Rest@6, - Pieces, - Size + 1 - ); - - false -> - parse_host_outside_of_brackets_loop( - Original, - Original, - Pieces, - 0 - ) - end - end. - --file("src/gleam/uri.gleam", 222). --spec parse_host_within_brackets(binary(), uri()) -> {ok, uri()} | {error, nil}. -parse_host_within_brackets(Uri_string, Pieces) -> - parse_host_within_brackets_loop(Uri_string, Uri_string, Pieces, 0). - --file("src/gleam/uri.gleam", 302). --spec parse_host_outside_of_brackets(binary(), uri()) -> {ok, uri()} | - {error, nil}. -parse_host_outside_of_brackets(Uri_string, Pieces) -> - parse_host_outside_of_brackets_loop(Uri_string, Uri_string, Pieces, 0). - --file("src/gleam/uri.gleam", 199). --spec parse_host(binary(), uri()) -> {ok, uri()} | {error, nil}. -parse_host(Uri_string, Pieces) -> - case Uri_string of - <<"["/utf8, _/binary>> -> - parse_host_within_brackets(Uri_string, Pieces); - - <<":"/utf8, _/binary>> -> - Pieces@1 = {uri, - erlang:element(2, Pieces), - erlang:element(3, Pieces), - {some, <<""/utf8>>}, - erlang:element(5, Pieces), - erlang:element(6, Pieces), - erlang:element(7, Pieces), - erlang:element(8, Pieces)}, - parse_port(Uri_string, Pieces@1); - - <<""/utf8>> -> - {ok, - {uri, - erlang:element(2, Pieces), - erlang:element(3, Pieces), - {some, <<""/utf8>>}, - erlang:element(5, Pieces), - erlang:element(6, Pieces), - erlang:element(7, Pieces), - erlang:element(8, Pieces)}}; - - _ -> - parse_host_outside_of_brackets(Uri_string, Pieces) - end. - --file("src/gleam/uri.gleam", 167). --spec parse_userinfo_loop(binary(), binary(), uri(), integer()) -> {ok, uri()} | - {error, nil}. -parse_userinfo_loop(Original, Uri_string, Pieces, Size) -> - case Uri_string of - <<"@"/utf8, Rest/binary>> when Size =:= 0 -> - parse_host(Rest, Pieces); - - <<"@"/utf8, Rest@1/binary>> -> - Userinfo = binary:part(Original, 0, Size), - Pieces@1 = {uri, - erlang:element(2, Pieces), - {some, Userinfo}, - erlang:element(4, Pieces), - erlang:element(5, Pieces), - erlang:element(6, Pieces), - erlang:element(7, Pieces), - erlang:element(8, Pieces)}, - parse_host(Rest@1, Pieces@1); - - <<""/utf8>> -> - parse_host(Original, Pieces); - - <<"/"/utf8, _/binary>> -> - parse_host(Original, Pieces); - - <<"?"/utf8, _/binary>> -> - parse_host(Original, Pieces); - - <<"#"/utf8, _/binary>> -> - parse_host(Original, Pieces); - - _ -> - {_, Rest@2} = gleam_stdlib:string_pop_codeunit(Uri_string), - parse_userinfo_loop(Original, Rest@2, Pieces, Size + 1) - end. - --file("src/gleam/uri.gleam", 163). --spec parse_authority_pieces(binary(), uri()) -> {ok, uri()} | {error, nil}. -parse_authority_pieces(String, Pieces) -> - parse_userinfo_loop(String, String, Pieces, 0). - --file("src/gleam/uri.gleam", 150). --spec parse_authority_with_slashes(binary(), uri()) -> {ok, uri()} | - {error, nil}. -parse_authority_with_slashes(Uri_string, Pieces) -> - case Uri_string of - <<"//"/utf8>> -> - {ok, - {uri, - erlang:element(2, Pieces), - erlang:element(3, Pieces), - {some, <<""/utf8>>}, - erlang:element(5, Pieces), - erlang:element(6, Pieces), - erlang:element(7, Pieces), - erlang:element(8, Pieces)}}; - - <<"//"/utf8, Rest/binary>> -> - parse_authority_pieces(Rest, Pieces); - - _ -> - parse_path(Uri_string, Pieces) - end. - --file("src/gleam/uri.gleam", 91). --spec parse_scheme_loop(binary(), binary(), uri(), integer()) -> {ok, uri()} | - {error, nil}. -parse_scheme_loop(Original, Uri_string, Pieces, Size) -> - case Uri_string of - <<"/"/utf8, _/binary>> when Size =:= 0 -> - parse_authority_with_slashes(Uri_string, Pieces); - - <<"/"/utf8, _/binary>> -> - Scheme = binary:part(Original, 0, Size), - Pieces@1 = {uri, - {some, string:lowercase(Scheme)}, - erlang:element(3, Pieces), - erlang:element(4, Pieces), - erlang:element(5, Pieces), - erlang:element(6, Pieces), - erlang:element(7, Pieces), - erlang:element(8, Pieces)}, - parse_authority_with_slashes(Uri_string, Pieces@1); - - <<"?"/utf8, Rest/binary>> when Size =:= 0 -> - parse_query_with_question_mark(Rest, Pieces); - - <<"?"/utf8, Rest@1/binary>> -> - Scheme@1 = binary:part(Original, 0, Size), - Pieces@2 = {uri, - {some, string:lowercase(Scheme@1)}, - erlang:element(3, Pieces), - erlang:element(4, Pieces), - erlang:element(5, Pieces), - erlang:element(6, Pieces), - erlang:element(7, Pieces), - erlang:element(8, Pieces)}, - parse_query_with_question_mark(Rest@1, Pieces@2); - - <<"#"/utf8, Rest@2/binary>> when Size =:= 0 -> - parse_fragment(Rest@2, Pieces); - - <<"#"/utf8, Rest@3/binary>> -> - Scheme@2 = binary:part(Original, 0, Size), - Pieces@3 = {uri, - {some, string:lowercase(Scheme@2)}, - erlang:element(3, Pieces), - erlang:element(4, Pieces), - erlang:element(5, Pieces), - erlang:element(6, Pieces), - erlang:element(7, Pieces), - erlang:element(8, Pieces)}, - parse_fragment(Rest@3, Pieces@3); - - <<":"/utf8, _/binary>> when Size =:= 0 -> - {error, nil}; - - <<":"/utf8, Rest@4/binary>> -> - Scheme@3 = binary:part(Original, 0, Size), - Pieces@4 = {uri, - {some, string:lowercase(Scheme@3)}, - erlang:element(3, Pieces), - erlang:element(4, Pieces), - erlang:element(5, Pieces), - erlang:element(6, Pieces), - erlang:element(7, Pieces), - erlang:element(8, Pieces)}, - parse_authority_with_slashes(Rest@4, Pieces@4); - - <<""/utf8>> -> - {ok, - {uri, - erlang:element(2, Pieces), - erlang:element(3, Pieces), - erlang:element(4, Pieces), - erlang:element(5, Pieces), - Original, - erlang:element(7, Pieces), - erlang:element(8, Pieces)}}; - - _ -> - {_, Rest@5} = gleam_stdlib:string_pop_codeunit(Uri_string), - parse_scheme_loop(Original, Rest@5, Pieces, Size + 1) - end. - --file("src/gleam/uri.gleam", 537). -?DOC( - " Parses an urlencoded query string into a list of key value pairs.\n" - " Returns an error for invalid encoding.\n" - "\n" - " The opposite operation is `uri.query_to_string`.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " parse_query(\"a=1&b=2\")\n" - " // -> Ok([#(\"a\", \"1\"), #(\"b\", \"2\")])\n" - " ```\n" -). --spec parse_query(binary()) -> {ok, list({binary(), binary()})} | {error, nil}. -parse_query(Query) -> - gleam_stdlib:parse_query(Query). - --file("src/gleam/uri.gleam", 573). -?DOC( - " Encodes a string into a percent encoded representation.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " percent_encode(\"100% great\")\n" - " // -> \"100%25%20great\"\n" - " ```\n" -). --spec percent_encode(binary()) -> binary(). -percent_encode(Value) -> - gleam_stdlib:percent_encode(Value). - --file("src/gleam/uri.gleam", 558). --spec query_pair({binary(), binary()}) -> gleam@string_tree:string_tree(). -query_pair(Pair) -> - gleam_stdlib:identity( - [gleam_stdlib:percent_encode(erlang:element(1, Pair)), - <<"="/utf8>>, - gleam_stdlib:percent_encode(erlang:element(2, Pair))] - ). - --file("src/gleam/uri.gleam", 550). -?DOC( - " Encodes a list of key value pairs as a URI query string.\n" - "\n" - " The opposite operation is `uri.parse_query`.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " query_to_string([#(\"a\", \"1\"), #(\"b\", \"2\")])\n" - " // -> \"a=1&b=2\"\n" - " ```\n" -). --spec query_to_string(list({binary(), binary()})) -> binary(). -query_to_string(Query) -> - _pipe = Query, - _pipe@1 = gleam@list:map(_pipe, fun query_pair/1), - _pipe@2 = gleam@list:intersperse( - _pipe@1, - gleam_stdlib:identity(<<"&"/utf8>>) - ), - _pipe@3 = gleam_stdlib:identity(_pipe@2), - unicode:characters_to_binary(_pipe@3). - --file("src/gleam/uri.gleam", 586). -?DOC( - " Decodes a percent encoded string.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " percent_decode(\"100%25%20great+fun\")\n" - " // -> Ok(\"100% great+fun\")\n" - " ```\n" -). --spec percent_decode(binary()) -> {ok, binary()} | {error, nil}. -percent_decode(Value) -> - gleam_stdlib:percent_decode(Value). - --file("src/gleam/uri.gleam", 608). --spec remove_dot_segments_loop(list(binary()), list(binary())) -> list(binary()). -remove_dot_segments_loop(Input, Accumulator) -> - case Input of - [] -> - lists:reverse(Accumulator); - - [Segment | Rest] -> - Accumulator@5 = case {Segment, Accumulator} of - {<<""/utf8>>, Accumulator@1} -> - Accumulator@1; - - {<<"."/utf8>>, Accumulator@2} -> - Accumulator@2; - - {<<".."/utf8>>, []} -> - []; - - {<<".."/utf8>>, [_ | Accumulator@3]} -> - Accumulator@3; - - {Segment@1, Accumulator@4} -> - [Segment@1 | Accumulator@4] - end, - remove_dot_segments_loop(Rest, Accumulator@5) - end. - --file("src/gleam/uri.gleam", 604). --spec remove_dot_segments(list(binary())) -> list(binary()). -remove_dot_segments(Input) -> - remove_dot_segments_loop(Input, []). - --file("src/gleam/uri.gleam", 600). -?DOC( - " Splits the path section of a URI into it's constituent segments.\n" - "\n" - " Removes empty segments and resolves dot-segments as specified in\n" - " [section 5.2](https://www.ietf.org/rfc/rfc3986.html#section-5.2) of the RFC.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " path_segments(\"/users/1\")\n" - " // -> [\"users\" ,\"1\"]\n" - " ```\n" -). --spec path_segments(binary()) -> list(binary()). -path_segments(Path) -> - remove_dot_segments(gleam@string:split(Path, <<"/"/utf8>>)). - --file("src/gleam/uri.gleam", 639). -?DOC( - " Encodes a `Uri` value as a URI string.\n" - "\n" - " The opposite operation is `uri.parse`.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " let uri = Uri(..empty, scheme: Some(\"https\"), host: Some(\"example.com\"))\n" - " to_string(uri)\n" - " // -> \"https://example.com\"\n" - " ```\n" -). --spec to_string(uri()) -> binary(). -to_string(Uri) -> - Parts = case erlang:element(8, Uri) of - {some, Fragment} -> - [<<"#"/utf8>>, Fragment]; - - none -> - [] - end, - Parts@1 = case erlang:element(7, Uri) of - {some, Query} -> - [<<"?"/utf8>>, Query | Parts]; - - none -> - Parts - end, - Parts@2 = [erlang:element(6, Uri) | Parts@1], - Parts@3 = case {erlang:element(4, Uri), - gleam_stdlib:string_starts_with(erlang:element(6, Uri), <<"/"/utf8>>)} of - {{some, Host}, false} when Host =/= <<""/utf8>> -> - [<<"/"/utf8>> | Parts@2]; - - {_, _} -> - Parts@2 - end, - Parts@4 = case {erlang:element(4, Uri), erlang:element(5, Uri)} of - {{some, _}, {some, Port}} -> - [<<":"/utf8>>, erlang:integer_to_binary(Port) | Parts@3]; - - {_, _} -> - Parts@3 - end, - Parts@5 = case {erlang:element(2, Uri), - erlang:element(3, Uri), - erlang:element(4, Uri)} of - {{some, S}, {some, U}, {some, H}} -> - [S, <<"://"/utf8>>, U, <<"@"/utf8>>, H | Parts@4]; - - {{some, S@1}, none, {some, H@1}} -> - [S@1, <<"://"/utf8>>, H@1 | Parts@4]; - - {{some, S@2}, {some, _}, none} -> - [S@2, <<":"/utf8>> | Parts@4]; - - {{some, S@2}, none, none} -> - [S@2, <<":"/utf8>> | Parts@4]; - - {none, none, {some, H@2}} -> - [<<"//"/utf8>>, H@2 | Parts@4]; - - {_, _, _} -> - Parts@4 - end, - erlang:list_to_binary(Parts@5). - --file("src/gleam/uri.gleam", 683). -?DOC( - " Fetches the origin of a URI.\n" - "\n" - " Returns the origin of a uri as defined in\n" - " [RFC 6454](https://tools.ietf.org/html/rfc6454)\n" - "\n" - " The supported URI schemes are `http` and `https`.\n" - " URLs without a scheme will return `Error`.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " let assert Ok(uri) = parse(\"https://example.com/path?foo#bar\")\n" - " origin(uri)\n" - " // -> Ok(\"https://example.com\")\n" - " ```\n" -). --spec origin(uri()) -> {ok, binary()} | {error, nil}. -origin(Uri) -> - {uri, Scheme, _, Host, Port, _, _, _} = Uri, - case {Host, Scheme} of - {{some, H}, {some, <<"https"/utf8>>}} when Port =:= {some, 443} -> - {ok, erlang:list_to_binary([<<"https://"/utf8>>, H])}; - - {{some, H@1}, {some, <<"http"/utf8>>}} when Port =:= {some, 80} -> - {ok, erlang:list_to_binary([<<"http://"/utf8>>, H@1])}; - - {{some, H@2}, {some, S}} when (S =:= <<"http"/utf8>>) orelse (S =:= <<"https"/utf8>>) -> - case Port of - {some, P} -> - {ok, - erlang:list_to_binary( - [S, - <<"://"/utf8>>, - H@2, - <<":"/utf8>>, - erlang:integer_to_binary(P)] - )}; - - none -> - {ok, erlang:list_to_binary([S, <<"://"/utf8>>, H@2])} - end; - - {_, _} -> - {error, nil} - end. - --file("src/gleam/uri.gleam", 764). --spec drop_last(list(DDO)) -> list(DDO). -drop_last(Elements) -> - gleam@list:take(Elements, erlang:length(Elements) - 1). - --file("src/gleam/uri.gleam", 768). --spec join_segments(list(binary())) -> binary(). -join_segments(Segments) -> - gleam@string:join([<<""/utf8>> | Segments], <<"/"/utf8>>). - --file("src/gleam/uri.gleam", 706). -?DOC( - " Resolves a URI with respect to the given base URI.\n" - "\n" - " The base URI must be an absolute URI or this function will return an error.\n" - " The algorithm for merging uris is described in\n" - " [RFC 3986](https://tools.ietf.org/html/rfc3986#section-5.2).\n" -). --spec merge(uri(), uri()) -> {ok, uri()} | {error, nil}. -merge(Base, Relative) -> - case Base of - {uri, {some, _}, _, {some, _}, _, _, _, _} -> - case Relative of - {uri, _, _, {some, _}, _, _, _, _} -> - Path = begin - _pipe = erlang:element(6, Relative), - _pipe@1 = gleam@string:split(_pipe, <<"/"/utf8>>), - _pipe@2 = remove_dot_segments(_pipe@1), - join_segments(_pipe@2) - end, - Resolved = {uri, - gleam@option:'or'( - erlang:element(2, Relative), - erlang:element(2, Base) - ), - none, - erlang:element(4, Relative), - gleam@option:'or'( - erlang:element(5, Relative), - erlang:element(5, Base) - ), - Path, - erlang:element(7, Relative), - erlang:element(8, Relative)}, - {ok, Resolved}; - - _ -> - {New_path, New_query} = case erlang:element(6, Relative) of - <<""/utf8>> -> - {erlang:element(6, Base), - gleam@option:'or'( - erlang:element(7, Relative), - erlang:element(7, Base) - )}; - - _ -> - Path_segments = case gleam_stdlib:string_starts_with( - erlang:element(6, Relative), - <<"/"/utf8>> - ) of - true -> - gleam@string:split( - erlang:element(6, Relative), - <<"/"/utf8>> - ); - - false -> - _pipe@3 = erlang:element(6, Base), - _pipe@4 = gleam@string:split( - _pipe@3, - <<"/"/utf8>> - ), - _pipe@5 = drop_last(_pipe@4), - lists:append( - _pipe@5, - gleam@string:split( - erlang:element(6, Relative), - <<"/"/utf8>> - ) - ) - end, - Path@1 = begin - _pipe@6 = Path_segments, - _pipe@7 = remove_dot_segments(_pipe@6), - join_segments(_pipe@7) - end, - {Path@1, erlang:element(7, Relative)} - end, - Resolved@1 = {uri, - erlang:element(2, Base), - none, - erlang:element(4, Base), - erlang:element(5, Base), - New_path, - New_query, - erlang:element(8, Relative)}, - {ok, Resolved@1} - end; - - _ -> - {error, nil} - end. - --file("src/gleam/uri.gleam", 81). -?DOC( - " Parses a compliant URI string into the `Uri` Type.\n" - " If the string is not a valid URI string then an error is returned.\n" - "\n" - " The opposite operation is `uri.to_string`.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " parse(\"https://example.com:1234/a/b?query=true#fragment\")\n" - " // -> Ok(\n" - " // Uri(\n" - " // scheme: Some(\"https\"),\n" - " // userinfo: None,\n" - " // host: Some(\"example.com\"),\n" - " // port: Some(1234),\n" - " // path: \"/a/b\",\n" - " // query: Some(\"query=true\"),\n" - " // fragment: Some(\"fragment\")\n" - " // )\n" - " // )\n" - " ```\n" -). --spec parse(binary()) -> {ok, uri()} | {error, nil}. -parse(Uri_string) -> - gleam_stdlib:uri_parse(Uri_string). diff --git a/build/dev/javascript/gleam_stdlib/gleam_stdlib.erl b/build/dev/javascript/gleam_stdlib/gleam_stdlib.erl deleted file mode 100644 index 2c416f4..0000000 --- a/build/dev/javascript/gleam_stdlib/gleam_stdlib.erl +++ /dev/null @@ -1,534 +0,0 @@ --module(gleam_stdlib). - --export([ - map_get/2, iodata_append/2, identity/1, parse_int/1, parse_float/1, - less_than/2, string_pop_grapheme/1, string_pop_codeunit/1, - string_starts_with/2, wrap_list/1, string_ends_with/2, string_pad/4, - uri_parse/1, bit_array_slice/3, percent_encode/1, percent_decode/1, - base64_decode/1, parse_query/1, bit_array_concat/1, - base64_encode/2, tuple_get/2, classify_dynamic/1, print/1, - println/1, print_error/1, println_error/1, inspect/1, float_to_string/1, - int_from_base_string/2, utf_codepoint_list_to_string/1, contains_string/2, - crop_string/2, base16_encode/1, base16_decode/1, string_replace/3, slice/3, - bit_array_to_int_and_size/1, bit_array_pad_to_bytes/1, index/2, list/5, - dict/1, int/1, float/1, bit_array/1, is_null/1 -]). - -%% Taken from OTP's uri_string module --define(DEC2HEX(X), - if ((X) >= 0) andalso ((X) =< 9) -> (X) + $0; - ((X) >= 10) andalso ((X) =< 15) -> (X) + $A - 10 - end). - -%% Taken from OTP's uri_string module --define(HEX2DEC(X), - if ((X) >= $0) andalso ((X) =< $9) -> (X) - $0; - ((X) >= $A) andalso ((X) =< $F) -> (X) - $A + 10; - ((X) >= $a) andalso ((X) =< $f) -> (X) - $a + 10 - end). - --define(is_lowercase_char(X), - (X > 96 andalso X < 123)). --define(is_underscore_char(X), - (X == 95)). --define(is_digit_char(X), - (X > 47 andalso X < 58)). --define(is_ascii_character(X), - (erlang:is_integer(X) andalso X >= 32 andalso X =< 126)). - -uppercase(X) -> X - 32. - -map_get(Map, Key) -> - case maps:find(Key, Map) of - error -> {error, nil}; - OkFound -> OkFound - end. - -iodata_append(Iodata, String) -> [Iodata, String]. - -identity(X) -> X. - -classify_dynamic(nil) -> <<"Nil">>; -classify_dynamic(null) -> <<"Nil">>; -classify_dynamic(undefined) -> <<"Nil">>; -classify_dynamic(X) when is_boolean(X) -> <<"Bool">>; -classify_dynamic(X) when is_atom(X) -> <<"Atom">>; -classify_dynamic(X) when is_binary(X) -> <<"String">>; -classify_dynamic(X) when is_bitstring(X) -> <<"BitArray">>; -classify_dynamic(X) when is_integer(X) -> <<"Int">>; -classify_dynamic(X) when is_float(X) -> <<"Float">>; -classify_dynamic(X) when is_list(X) -> <<"List">>; -classify_dynamic(X) when is_map(X) -> <<"Dict">>; -classify_dynamic(X) when is_tuple(X) -> <<"Array">>; -classify_dynamic(X) when is_reference(X) -> <<"Reference">>; -classify_dynamic(X) when is_pid(X) -> <<"Pid">>; -classify_dynamic(X) when is_port(X) -> <<"Port">>; -classify_dynamic(X) when - is_function(X, 0) orelse is_function(X, 1) orelse is_function(X, 2) orelse - is_function(X, 3) orelse is_function(X, 4) orelse is_function(X, 5) orelse - is_function(X, 6) orelse is_function(X, 7) orelse is_function(X, 8) orelse - is_function(X, 9) orelse is_function(X, 10) orelse is_function(X, 11) orelse - is_function(X, 12) -> <<"Function">>; -classify_dynamic(_) -> <<"Unknown">>. - -tuple_get(_tup, Index) when Index < 0 -> {error, nil}; -tuple_get(Data, Index) when Index >= tuple_size(Data) -> {error, nil}; -tuple_get(Data, Index) -> {ok, element(Index + 1, Data)}. - -int_from_base_string(String, Base) -> - case catch binary_to_integer(String, Base) of - Int when is_integer(Int) -> {ok, Int}; - _ -> {error, nil} - end. - -parse_int(String) -> - case catch binary_to_integer(String) of - Int when is_integer(Int) -> {ok, Int}; - _ -> {error, nil} - end. - -parse_float(String) -> - case catch binary_to_float(String) of - Float when is_float(Float) -> {ok, Float}; - _ -> {error, nil} - end. - -less_than(Lhs, Rhs) -> - Lhs < Rhs. - -string_starts_with(_, <<>>) -> true; -string_starts_with(String, Prefix) when byte_size(Prefix) > byte_size(String) -> false; -string_starts_with(String, Prefix) -> - PrefixSize = byte_size(Prefix), - Prefix == binary_part(String, 0, PrefixSize). - -string_ends_with(_, <<>>) -> true; -string_ends_with(String, Suffix) when byte_size(Suffix) > byte_size(String) -> false; -string_ends_with(String, Suffix) -> - SuffixSize = byte_size(Suffix), - Suffix == binary_part(String, byte_size(String) - SuffixSize, SuffixSize). - -string_pad(String, Length, Dir, PadString) -> - Chars = string:pad(String, Length, Dir, binary_to_list(PadString)), - case unicode:characters_to_binary(Chars) of - Bin when is_binary(Bin) -> Bin; - Error -> erlang:error({gleam_error, {string_invalid_utf8, Error}}) - end. - -string_pop_grapheme(String) -> - case string:next_grapheme(String) of - [ Next | Rest ] when is_binary(Rest) -> - {ok, {unicode:characters_to_binary([Next]), Rest}}; - - [ Next | Rest ] -> - {ok, {unicode:characters_to_binary([Next]), unicode:characters_to_binary(Rest)}}; - - _ -> {error, nil} - end. - -string_pop_codeunit(<>) -> {Cp, Rest}; -string_pop_codeunit(Binary) -> {0, Binary}. - -bit_array_pad_to_bytes(Bin) -> - case erlang:bit_size(Bin) rem 8 of - 0 -> Bin; - TrailingBits -> - PaddingBits = 8 - TrailingBits, - <> - end. - -bit_array_concat(BitArrays) -> - list_to_bitstring(BitArrays). - --if(?OTP_RELEASE >= 26). -base64_encode(Bin, Padding) -> - PaddedBin = bit_array_pad_to_bytes(Bin), - base64:encode(PaddedBin, #{padding => Padding}). --else. -base64_encode(_Bin, _Padding) -> - erlang:error(<<"Erlang OTP/26 or higher is required to use base64:encode">>). --endif. - -bit_array_slice(Bin, Pos, Len) -> - try {ok, binary:part(Bin, Pos, Len)} - catch error:badarg -> {error, nil} - end. - -base64_decode(S) -> - try {ok, base64:decode(S)} - catch error:_ -> {error, nil} - end. - -wrap_list(X) when is_list(X) -> X; -wrap_list(X) -> [X]. - -parse_query(Query) -> - case uri_string:dissect_query(Query) of - {error, _, _} -> {error, nil}; - Pairs -> - Pairs1 = lists:map(fun - ({K, true}) -> {K, <<"">>}; - (Pair) -> Pair - end, Pairs), - {ok, Pairs1} - end. - -percent_encode(B) -> percent_encode(B, <<>>). -percent_encode(<<>>, Acc) -> - Acc; -percent_encode(<>, Acc) -> - case percent_ok(H) of - true -> - percent_encode(T, <>); - false -> - <> = <>, - percent_encode(T, <>) - end. - -percent_decode(Cs) -> percent_decode(Cs, <<>>). -percent_decode(<<$%, C0, C1, Cs/binary>>, Acc) -> - case is_hex_digit(C0) andalso is_hex_digit(C1) of - true -> - B = ?HEX2DEC(C0)*16+?HEX2DEC(C1), - percent_decode(Cs, <>); - false -> - {error, nil} - end; -percent_decode(<>, Acc) -> - percent_decode(Cs, <>); -percent_decode(<<>>, Acc) -> - check_utf8(Acc). - -percent_ok($!) -> true; -percent_ok($$) -> true; -percent_ok($') -> true; -percent_ok($() -> true; -percent_ok($)) -> true; -percent_ok($*) -> true; -percent_ok($+) -> true; -percent_ok($-) -> true; -percent_ok($.) -> true; -percent_ok($_) -> true; -percent_ok($~) -> true; -percent_ok(C) when $0 =< C, C =< $9 -> true; -percent_ok(C) when $A =< C, C =< $Z -> true; -percent_ok(C) when $a =< C, C =< $z -> true; -percent_ok(_) -> false. - -is_hex_digit(C) -> - ($0 =< C andalso C =< $9) orelse ($a =< C andalso C =< $f) orelse ($A =< C andalso C =< $F). - -check_utf8(Cs) -> - case unicode:characters_to_list(Cs) of - {incomplete, _, _} -> {error, nil}; - {error, _, _} -> {error, nil}; - _ -> {ok, Cs} - end. - -uri_parse(String) -> - case uri_string:parse(String) of - {error, _, _} -> {error, nil}; - Uri -> - Port = - try maps:get(port, Uri) of - undefined -> none; - Value -> {some, Value} - catch _:_ -> none - end, - {ok, {uri, - maps_get_optional(Uri, scheme), - maps_get_optional(Uri, userinfo), - maps_get_optional(Uri, host), - Port, - maps_get_or(Uri, path, <<>>), - maps_get_optional(Uri, query), - maps_get_optional(Uri, fragment) - }} - end. - -maps_get_optional(Map, Key) -> - try {some, maps:get(Key, Map)} - catch _:_ -> none - end. - -maps_get_or(Map, Key, Default) -> - try maps:get(Key, Map) - catch _:_ -> Default - end. - -print(String) -> - io:put_chars(String), - nil. - -println(String) -> - io:put_chars([String, $\n]), - nil. - -print_error(String) -> - io:put_chars(standard_error, String), - nil. - -println_error(String) -> - io:put_chars(standard_error, [String, $\n]), - nil. - -inspect(true) -> - "True"; -inspect(false) -> - "False"; -inspect(nil) -> - "Nil"; -inspect(Data) when is_map(Data) -> - Fields = [ - [<<"#(">>, inspect(Key), <<", ">>, inspect(Value), <<")">>] - || {Key, Value} <- maps:to_list(Data) - ], - ["dict.from_list([", lists:join(", ", Fields), "])"]; -inspect(Atom) when is_atom(Atom) -> - erlang:element(2, inspect_atom(Atom)); -inspect(Any) when is_integer(Any) -> - erlang:integer_to_list(Any); -inspect(Any) when is_float(Any) -> - io_lib_format:fwrite_g(Any); -inspect(Binary) when is_binary(Binary) -> - case inspect_maybe_utf8_string(Binary, <<>>) of - {ok, InspectedUtf8String} -> InspectedUtf8String; - {error, not_a_utf8_string} -> - Segments = [erlang:integer_to_list(X) || <> <= Binary], - ["<<", lists:join(", ", Segments), ">>"] - end; -inspect(Bits) when is_bitstring(Bits) -> - inspect_bit_array(Bits); -inspect(List) when is_list(List) -> - case inspect_list(List, true) of - {charlist, _} -> ["charlist.from_string(\"", list_to_binary(List), "\")"]; - {proper, Elements} -> ["[", Elements, "]"]; - {improper, Elements} -> ["//erl([", Elements, "])"] - end; -inspect(Any) when is_tuple(Any) % Record constructors - andalso is_atom(element(1, Any)) - andalso element(1, Any) =/= false - andalso element(1, Any) =/= true - andalso element(1, Any) =/= nil --> - [Atom | ArgsList] = erlang:tuple_to_list(Any), - InspectedArgs = lists:map(fun inspect/1, ArgsList), - case inspect_atom(Atom) of - {gleam_atom, GleamAtom} -> - Args = lists:join(<<", ">>, InspectedArgs), - [GleamAtom, "(", Args, ")"]; - {erlang_atom, ErlangAtom} -> - Args = lists:join(<<", ">>, [ErlangAtom | InspectedArgs]), - ["#(", Args, ")"] - end; -inspect(Tuple) when is_tuple(Tuple) -> - Elements = lists:map(fun inspect/1, erlang:tuple_to_list(Tuple)), - ["#(", lists:join(", ", Elements), ")"]; -inspect(Any) when is_function(Any) -> - {arity, Arity} = erlang:fun_info(Any, arity), - ArgsAsciiCodes = lists:seq($a, $a + Arity - 1), - Args = lists:join(<<", ">>, - lists:map(fun(Arg) -> <> end, ArgsAsciiCodes) - ), - ["//fn(", Args, ") { ... }"]; -inspect(Any) -> - ["//erl(", io_lib:format("~p", [Any]), ")"]. - -inspect_atom(Atom) -> - Binary = erlang:atom_to_binary(Atom), - case inspect_maybe_gleam_atom(Binary, none, <<>>) of - {ok, Inspected} -> {gleam_atom, Inspected}; - {error, _} -> {erlang_atom, ["atom.create(\"", Binary, "\")"]} - end. - -inspect_maybe_gleam_atom(<<>>, none, _) -> - {error, nil}; -inspect_maybe_gleam_atom(<>, none, _) when ?is_digit_char(First) -> - {error, nil}; -inspect_maybe_gleam_atom(<<"_", _Rest/binary>>, none, _) -> - {error, nil}; -inspect_maybe_gleam_atom(<<"_">>, _PrevChar, _Acc) -> - {error, nil}; -inspect_maybe_gleam_atom(<<"_", _Rest/binary>>, $_, _Acc) -> - {error, nil}; -inspect_maybe_gleam_atom(<>, _PrevChar, _Acc) - when not (?is_lowercase_char(First) orelse ?is_underscore_char(First) orelse ?is_digit_char(First)) -> - {error, nil}; -inspect_maybe_gleam_atom(<>, none, Acc) -> - inspect_maybe_gleam_atom(Rest, First, <>); -inspect_maybe_gleam_atom(<<"_", Rest/binary>>, _PrevChar, Acc) -> - inspect_maybe_gleam_atom(Rest, $_, Acc); -inspect_maybe_gleam_atom(<>, $_, Acc) -> - inspect_maybe_gleam_atom(Rest, First, <>); -inspect_maybe_gleam_atom(<>, _PrevChar, Acc) -> - inspect_maybe_gleam_atom(Rest, First, <>); -inspect_maybe_gleam_atom(<<>>, _PrevChar, Acc) -> - {ok, Acc}; -inspect_maybe_gleam_atom(A, B, C) -> - erlang:display({A, B, C}), - throw({gleam_error, A, B, C}). - -inspect_list([], _) -> - {proper, []}; -inspect_list([First], true) when ?is_ascii_character(First) -> - {charlist, nil}; -inspect_list([First], _) -> - {proper, [inspect(First)]}; -inspect_list([First | Rest], ValidCharlist) when is_list(Rest) -> - StillValidCharlist = ValidCharlist andalso ?is_ascii_character(First), - {Kind, Inspected} = inspect_list(Rest, StillValidCharlist), - {Kind, [inspect(First), <<", ">> | Inspected]}; -inspect_list([First | ImproperTail], _) -> - {improper, [inspect(First), <<" | ">>, inspect(ImproperTail)]}. - -inspect_bit_array(Bits) -> - Text = inspect_bit_array(Bits, <<"<<">>), - <>">>. - -inspect_bit_array(<<>>, Acc) -> - Acc; -inspect_bit_array(<>, Acc) -> - inspect_bit_array(Rest, append_segment(Acc, erlang:integer_to_binary(X))); -inspect_bit_array(Rest, Acc) -> - Size = bit_size(Rest), - <> = Rest, - X1 = erlang:integer_to_binary(X), - Size1 = erlang:integer_to_binary(Size), - Segment = <>, - inspect_bit_array(<<>>, append_segment(Acc, Segment)). - -bit_array_to_int_and_size(A) -> - Size = bit_size(A), - <> = A, - {A1, Size}. - -append_segment(<<"<<">>, Segment) -> - <<"<<", Segment/binary>>; -append_segment(Acc, Segment) -> - <>. - - -inspect_maybe_utf8_string(Binary, Acc) -> - case Binary of - <<>> -> {ok, <<$", Acc/binary, $">>}; - <> -> - Escaped = case First of - $" -> <<$\\, $">>; - $\\ -> <<$\\, $\\>>; - $\r -> <<$\\, $r>>; - $\n -> <<$\\, $n>>; - $\t -> <<$\\, $t>>; - $\f -> <<$\\, $f>>; - X when X > 126, X < 160 -> convert_to_u(X); - X when X < 32 -> convert_to_u(X); - Other -> <> - end, - inspect_maybe_utf8_string(Rest, <>); - _ -> {error, not_a_utf8_string} - end. - -convert_to_u(Code) -> - list_to_binary(io_lib:format("\\u{~4.16.0B}", [Code])). - -float_to_string(Float) when is_float(Float) -> - erlang:iolist_to_binary(io_lib_format:fwrite_g(Float)). - -utf_codepoint_list_to_string(List) -> - case unicode:characters_to_binary(List) of - {error, _} -> erlang:error({gleam_error, {string_invalid_utf8, List}}); - Binary -> Binary - end. - -crop_string(String, Prefix) -> - case string:find(String, Prefix) of - nomatch -> String; - New -> New - end. - -contains_string(String, Substring) -> - is_bitstring(string:find(String, Substring)). - -base16_encode(Bin) -> - PaddedBin = bit_array_pad_to_bytes(Bin), - binary:encode_hex(PaddedBin). - -base16_decode(String) -> - try - {ok, binary:decode_hex(String)} - catch - _:_ -> {error, nil} - end. - -string_replace(String, Pattern, Replacement) -> - string:replace(String, Pattern, Replacement, all). - -slice(String, Index, Length) -> - case string:slice(String, Index, Length) of - X when is_binary(X) -> X; - X when is_list(X) -> unicode:characters_to_binary(X) - end. - -index([X | _], 0) -> - {ok, {some, X}}; -index([_, X | _], 1) -> - {ok, {some, X}}; -index([_, _, X | _], 2) -> - {ok, {some, X}}; -index([_, _, _, X | _], 3) -> - {ok, {some, X}}; -index([_, _, _, _, X | _], 4) -> - {ok, {some, X}}; -index([_, _, _, _, _, X | _], 5) -> - {ok, {some, X}}; -index([_, _, _, _, _, _, X | _], 6) -> - {ok, {some, X}}; -index([_, _, _, _, _, _, _, X | _], 7) -> - {ok, {some, X}}; -index(Tuple, Index) when is_tuple(Tuple) andalso is_integer(Index) -> - {ok, try - {some, element(Index + 1, Tuple)} - catch _:_ -> - none - end}; -index(Map, Key) when is_map(Map) -> - {ok, try - {some, maps:get(Key, Map)} - catch _:_ -> - none - end}; -index(_, Index) when is_integer(Index) -> - {error, <<"Indexable">>}; -index(_, _) -> - {error, <<"Dict">>}. - -list(T, A, B, C, D) when is_tuple(T) -> - list(tuple_to_list(T), A, B, C, D); -list([], _, _, _, Acc) -> - {lists:reverse(Acc), []}; -list([X | Xs], Decode, PushPath, Index, Acc) -> - {Out, Errors} = Decode(X), - case Errors of - [] -> list(Xs, Decode, PushPath, Index + 1, [Out | Acc]); - _ -> PushPath({[], Errors}, integer_to_binary(Index)) - end; -list(Unexpected, _, _, _, []) -> - Found = gleam@dynamic:classify(Unexpected), - Error = {decode_error, <<"List"/utf8>>, Found, []}, - {[], [Error]}; -list(_, _, _, _, Acc) -> - {lists:reverse(Acc), []}. - -dict(#{} = Data) -> {ok, Data}; -dict(_) -> {error, nil}. - -int(I) when is_integer(I) -> {ok, I}; -int(_) -> {error, 0}. - -float(F) when is_float(F) -> {ok, F}; -float(_) -> {error, 0.0}. - -bit_array(B) when is_bitstring(B) -> {ok, B}; -bit_array(_) -> {error, <<>>}. - -is_null(X) -> - X =:= undefined orelse X =:= null orelse X =:= nil. diff --git a/build/dev/javascript/gleam_stdlib/gleam_stdlib.mjs b/build/dev/javascript/gleam_stdlib/gleam_stdlib.mjs deleted file mode 100644 index ebac45f..0000000 --- a/build/dev/javascript/gleam_stdlib/gleam_stdlib.mjs +++ /dev/null @@ -1,1048 +0,0 @@ -import { - BitArray, - Error, - List, - Ok, - Result, - UtfCodepoint, - stringBits, - toBitArray, - bitArraySlice, - NonEmpty, - Empty, - CustomType, -} from "./gleam.mjs"; -import { Some, None } from "./gleam/option.mjs"; -import Dict from "./dict.mjs"; -import { classify } from "./gleam/dynamic.mjs"; -import { DecodeError } from "./gleam/dynamic/decode.mjs"; - -const Nil = undefined; -const NOT_FOUND = {}; - -export function identity(x) { - return x; -} - -export function parse_int(value) { - if (/^[-+]?(\d+)$/.test(value)) { - return new Ok(parseInt(value)); - } else { - return new Error(Nil); - } -} - -export function parse_float(value) { - if (/^[-+]?(\d+)\.(\d+)([eE][-+]?\d+)?$/.test(value)) { - return new Ok(parseFloat(value)); - } else { - return new Error(Nil); - } -} - -export function to_string(term) { - return term.toString(); -} - -export function int_to_base_string(int, base) { - return int.toString(base).toUpperCase(); -} - -const int_base_patterns = { - 2: /[^0-1]/, - 3: /[^0-2]/, - 4: /[^0-3]/, - 5: /[^0-4]/, - 6: /[^0-5]/, - 7: /[^0-6]/, - 8: /[^0-7]/, - 9: /[^0-8]/, - 10: /[^0-9]/, - 11: /[^0-9a]/, - 12: /[^0-9a-b]/, - 13: /[^0-9a-c]/, - 14: /[^0-9a-d]/, - 15: /[^0-9a-e]/, - 16: /[^0-9a-f]/, - 17: /[^0-9a-g]/, - 18: /[^0-9a-h]/, - 19: /[^0-9a-i]/, - 20: /[^0-9a-j]/, - 21: /[^0-9a-k]/, - 22: /[^0-9a-l]/, - 23: /[^0-9a-m]/, - 24: /[^0-9a-n]/, - 25: /[^0-9a-o]/, - 26: /[^0-9a-p]/, - 27: /[^0-9a-q]/, - 28: /[^0-9a-r]/, - 29: /[^0-9a-s]/, - 30: /[^0-9a-t]/, - 31: /[^0-9a-u]/, - 32: /[^0-9a-v]/, - 33: /[^0-9a-w]/, - 34: /[^0-9a-x]/, - 35: /[^0-9a-y]/, - 36: /[^0-9a-z]/, -}; - -export function int_from_base_string(string, base) { - if (int_base_patterns[base].test(string.replace(/^-/, "").toLowerCase())) { - return new Error(Nil); - } - - const result = parseInt(string, base); - - if (isNaN(result)) { - return new Error(Nil); - } - - return new Ok(result); -} - -export function string_replace(string, target, substitute) { - return string.replaceAll(target, substitute); -} - -export function string_reverse(string) { - return [...string].reverse().join(""); -} - -export function string_length(string) { - if (string === "") { - return 0; - } - const iterator = graphemes_iterator(string); - if (iterator) { - let i = 0; - for (const _ of iterator) { - i++; - } - return i; - } else { - return string.match(/./gsu).length; - } -} - -export function graphemes(string) { - const iterator = graphemes_iterator(string); - if (iterator) { - return List.fromArray(Array.from(iterator).map((item) => item.segment)); - } else { - return List.fromArray(string.match(/./gsu)); - } -} - -let segmenter = undefined; - -function graphemes_iterator(string) { - if (globalThis.Intl && Intl.Segmenter) { - segmenter ||= new Intl.Segmenter(); - return segmenter.segment(string)[Symbol.iterator](); - } -} - -export function pop_grapheme(string) { - let first; - const iterator = graphemes_iterator(string); - if (iterator) { - first = iterator.next().value?.segment; - } else { - first = string.match(/./su)?.[0]; - } - if (first) { - return new Ok([first, string.slice(first.length)]); - } else { - return new Error(Nil); - } -} - -export function pop_codeunit(str) { - return [str.charCodeAt(0) | 0, str.slice(1)]; -} - -export function lowercase(string) { - return string.toLowerCase(); -} - -export function uppercase(string) { - return string.toUpperCase(); -} - -export function less_than(a, b) { - return a < b; -} - -export function add(a, b) { - return a + b; -} - -export function split(xs, pattern) { - return List.fromArray(xs.split(pattern)); -} - -export function concat(xs) { - let result = ""; - for (const x of xs) { - result = result + x; - } - return result; -} - -export function length(data) { - return data.length; -} - -export function string_byte_slice(string, index, length) { - return string.slice(index, index + length); -} - -export function string_grapheme_slice(string, idx, len) { - if (len <= 0 || idx >= string.length) { - return ""; - } - - const iterator = graphemes_iterator(string); - if (iterator) { - while (idx-- > 0) { - iterator.next(); - } - - let result = ""; - - while (len-- > 0) { - const v = iterator.next().value; - if (v === undefined) { - break; - } - - result += v.segment; - } - - return result; - } else { - return string - .match(/./gsu) - .slice(idx, idx + len) - .join(""); - } -} - -export function string_codeunit_slice(str, from, length) { - return str.slice(from, from + length); -} -export function crop_string(string, substring) { - return string.substring(string.indexOf(substring)); -} - -export function contains_string(haystack, needle) { - return haystack.indexOf(needle) >= 0; -} - -export function starts_with(haystack, needle) { - return haystack.startsWith(needle); -} - -export function ends_with(haystack, needle) { - return haystack.endsWith(needle); -} - -export function split_once(haystack, needle) { - const index = haystack.indexOf(needle); - if (index >= 0) { - const before = haystack.slice(0, index); - const after = haystack.slice(index + needle.length); - return new Ok([before, after]); - } else { - return new Error(Nil); - } -} - -const unicode_whitespaces = [ - "\u0020", // Space - "\u0009", // Horizontal tab - "\u000A", // Line feed - "\u000B", // Vertical tab - "\u000C", // Form feed - "\u000D", // Carriage return - "\u0085", // Next line - "\u2028", // Line separator - "\u2029", // Paragraph separator -].join(""); - -const trim_start_regex = /* @__PURE__ */ new RegExp( - `^[${unicode_whitespaces}]*`, -); -const trim_end_regex = /* @__PURE__ */ new RegExp(`[${unicode_whitespaces}]*$`); - -export function trim_start(string) { - return string.replace(trim_start_regex, ""); -} - -export function trim_end(string) { - return string.replace(trim_end_regex, ""); -} - -export function bit_array_from_string(string) { - return toBitArray([stringBits(string)]); -} - -export function bit_array_bit_size(bit_array) { - return bit_array.bitSize; -} - -export function bit_array_byte_size(bit_array) { - return bit_array.byteSize; -} - -export function bit_array_pad_to_bytes(bit_array) { - const trailingBitsCount = bit_array.bitSize % 8; - - // If the bit array is a whole number of bytes it can be returned unchanged - if (trailingBitsCount === 0) { - return bit_array; - } - - const finalByte = bit_array.byteAt(bit_array.byteSize - 1); - - // The required final byte has its unused trailing bits set to zero - const unusedBitsCount = 8 - trailingBitsCount; - const correctFinalByte = (finalByte >> unusedBitsCount) << unusedBitsCount; - - // If the unused bits in the final byte are already set to zero then the - // existing buffer can be re-used, avoiding a copy - if (finalByte === correctFinalByte) { - return new BitArray( - bit_array.rawBuffer, - bit_array.byteSize * 8, - bit_array.bitOffset, - ); - } - - // Copy the bit array into a new aligned buffer and set the correct final byte - const buffer = new Uint8Array(bit_array.byteSize); - for (let i = 0; i < buffer.length - 1; i++) { - buffer[i] = bit_array.byteAt(i); - } - buffer[buffer.length - 1] = correctFinalByte; - - return new BitArray(buffer); -} - -export function bit_array_concat(bit_arrays) { - return toBitArray(bit_arrays.toArray()); -} - -export function console_log(term) { - console.log(term); -} - -export function console_error(term) { - console.error(term); -} - -export function crash(message) { - throw new globalThis.Error(message); -} - -export function bit_array_to_string(bit_array) { - // If the bit array isn't a whole number of bytes then return an error - if (bit_array.bitSize % 8 !== 0) { - return new Error(Nil); - } - - try { - const decoder = new TextDecoder("utf-8", { fatal: true }); - - if (bit_array.bitOffset === 0) { - return new Ok(decoder.decode(bit_array.rawBuffer)); - } else { - // The input data isn't aligned, so copy it into a new aligned buffer so - // that TextDecoder can be used - const buffer = new Uint8Array(bit_array.byteSize); - for (let i = 0; i < buffer.length; i++) { - buffer[i] = bit_array.byteAt(i); - } - return new Ok(decoder.decode(buffer)); - } - } catch { - return new Error(Nil); - } -} - -export function print(string) { - if (typeof process === "object" && process.stdout?.write) { - process.stdout.write(string); // We can write without a trailing newline - } else if (typeof Deno === "object") { - Deno.stdout.writeSync(new TextEncoder().encode(string)); // We can write without a trailing newline - } else { - console.log(string); // We're in a browser. Newlines are mandated - } -} - -export function print_error(string) { - if (typeof process === "object" && process.stderr?.write) { - process.stderr.write(string); // We can write without a trailing newline - } else if (typeof Deno === "object") { - Deno.stderr.writeSync(new TextEncoder().encode(string)); // We can write without a trailing newline - } else { - console.error(string); // We're in a browser. Newlines are mandated - } -} - -export function print_debug(string) { - if (typeof process === "object" && process.stderr?.write) { - process.stderr.write(string + "\n"); // If we're in Node.js, use `stderr` - } else if (typeof Deno === "object") { - Deno.stderr.writeSync(new TextEncoder().encode(string + "\n")); // If we're in Deno, use `stderr` - } else { - console.log(string); // Otherwise, use `console.log` (so that it doesn't look like an error) - } -} - -export function ceiling(float) { - return Math.ceil(float); -} - -export function floor(float) { - return Math.floor(float); -} - -export function round(float) { - return Math.round(float); -} - -export function truncate(float) { - return Math.trunc(float); -} - -export function power(base, exponent) { - // It is checked in Gleam that: - // - The base is non-negative and that the exponent is not fractional. - // - The base is non-zero and the exponent is non-negative (otherwise - // the result will essentially be division by zero). - // It can thus be assumed that valid input is passed to the Math.pow - // function and a NaN or Infinity value will not be produced. - return Math.pow(base, exponent); -} - -export function random_uniform() { - const random_uniform_result = Math.random(); - // With round-to-nearest-even behavior, the ranges claimed for the functions below - // (excluding the one for Math.random() itself) aren't exact. - // If extremely large bounds are chosen (2^53 or higher), - // it's possible in extremely rare cases to calculate the usually-excluded upper bound. - // Note that as numbers in JavaScript are IEEE 754 floating point numbers - // See: - // Because of this, we just loop 'until' we get a valid result where 0.0 <= x < 1.0: - if (random_uniform_result === 1.0) { - return random_uniform(); - } - return random_uniform_result; -} - -export function bit_array_slice(bits, position, length) { - const start = Math.min(position, position + length); - const end = Math.max(position, position + length); - - if (start < 0 || end * 8 > bits.bitSize) { - return new Error(Nil); - } - - return new Ok(bitArraySlice(bits, start * 8, end * 8)); -} - -export function codepoint(int) { - return new UtfCodepoint(int); -} - -export function string_to_codepoint_integer_list(string) { - return List.fromArray(Array.from(string).map((item) => item.codePointAt(0))); -} - -export function utf_codepoint_list_to_string(utf_codepoint_integer_list) { - return utf_codepoint_integer_list - .toArray() - .map((x) => String.fromCodePoint(x.value)) - .join(""); -} - -export function utf_codepoint_to_int(utf_codepoint) { - return utf_codepoint.value; -} - -export function new_map() { - return Dict.new(); -} - -export function map_size(map) { - return map.size; -} - -export function map_to_list(map) { - return List.fromArray(map.entries()); -} - -export function map_remove(key, map) { - return map.delete(key); -} - -export function map_get(map, key) { - const value = map.get(key, NOT_FOUND); - if (value === NOT_FOUND) { - return new Error(Nil); - } - return new Ok(value); -} - -export function map_insert(key, value, map) { - return map.set(key, value); -} - -function unsafe_percent_decode(string) { - return decodeURIComponent(string || ""); -} - -function unsafe_percent_decode_query(string) { - return decodeURIComponent((string || "").replace("+", " ")); -} - -export function percent_decode(string) { - try { - return new Ok(unsafe_percent_decode(string)); - } catch { - return new Error(Nil); - } -} - -export function percent_encode(string) { - return encodeURIComponent(string).replace("%2B", "+"); -} - -export function parse_query(query) { - try { - const pairs = []; - for (const section of query.split("&")) { - const [key, value] = section.split("="); - if (!key) continue; - - const decodedKey = unsafe_percent_decode_query(key); - const decodedValue = unsafe_percent_decode_query(value); - pairs.push([decodedKey, decodedValue]); - } - return new Ok(List.fromArray(pairs)); - } catch { - return new Error(Nil); - } -} - -const b64EncodeLookup = [ - 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, - 84, 85, 86, 87, 88, 89, 90, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, - 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, - 122, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 43, 47, -]; - -let b64TextDecoder; - -// Implementation based on https://github.com/mitschabaude/fast-base64/blob/main/js.js -export function base64_encode(bit_array, padding) { - b64TextDecoder ??= new TextDecoder(); - - bit_array = bit_array_pad_to_bytes(bit_array); - - const m = bit_array.byteSize; - const k = m % 3; - const n = Math.floor(m / 3) * 4 + (k && k + 1); - const N = Math.ceil(m / 3) * 4; - const encoded = new Uint8Array(N); - - for (let i = 0, j = 0; j < m; i += 4, j += 3) { - const y = - (bit_array.byteAt(j) << 16) + - (bit_array.byteAt(j + 1) << 8) + - (bit_array.byteAt(j + 2) | 0); - - encoded[i] = b64EncodeLookup[y >> 18]; - encoded[i + 1] = b64EncodeLookup[(y >> 12) & 0x3f]; - encoded[i + 2] = b64EncodeLookup[(y >> 6) & 0x3f]; - encoded[i + 3] = b64EncodeLookup[y & 0x3f]; - } - - let base64 = b64TextDecoder.decode(new Uint8Array(encoded.buffer, 0, n)); - - if (padding) { - if (k === 1) { - base64 += "=="; - } else if (k === 2) { - base64 += "="; - } - } - - return base64; -} - -// From https://developer.mozilla.org/en-US/docs/Glossary/Base64 -export function base64_decode(sBase64) { - try { - const binString = atob(sBase64); - const length = binString.length; - const array = new Uint8Array(length); - for (let i = 0; i < length; i++) { - array[i] = binString.charCodeAt(i); - } - return new Ok(new BitArray(array)); - } catch { - return new Error(Nil); - } -} - -export function classify_dynamic(data) { - if (typeof data === "string") { - return "String"; - } else if (typeof data === "boolean") { - return "Bool"; - } else if (data instanceof Result) { - return "Result"; - } else if (data instanceof List) { - return "List"; - } else if (data instanceof BitArray) { - return "BitArray"; - } else if (data instanceof Dict) { - return "Dict"; - } else if (Number.isInteger(data)) { - return "Int"; - } else if (Array.isArray(data)) { - return `Array`; - } else if (typeof data === "number") { - return "Float"; - } else if (data === null) { - return "Nil"; - } else if (data === undefined) { - return "Nil"; - } else { - const type = typeof data; - return type.charAt(0).toUpperCase() + type.slice(1); - } -} - -export function byte_size(string) { - return new TextEncoder().encode(string).length; -} - -// In JavaScript bitwise operations convert numbers to a sequence of 32 bits -// while Erlang uses arbitrary precision. -// To get around this problem and get consistent results use BigInt and then -// downcast the value back to a Number value. - -export function bitwise_and(x, y) { - return Number(BigInt(x) & BigInt(y)); -} - -export function bitwise_not(x) { - return Number(~BigInt(x)); -} - -export function bitwise_or(x, y) { - return Number(BigInt(x) | BigInt(y)); -} - -export function bitwise_exclusive_or(x, y) { - return Number(BigInt(x) ^ BigInt(y)); -} - -export function bitwise_shift_left(x, y) { - return Number(BigInt(x) << BigInt(y)); -} - -export function bitwise_shift_right(x, y) { - return Number(BigInt(x) >> BigInt(y)); -} - -export function inspect(v) { - return new Inspector().inspect(v); -} - -export function float_to_string(float) { - const string = float.toString().replace("+", ""); - if (string.indexOf(".") >= 0) { - return string; - } else { - const index = string.indexOf("e"); - if (index >= 0) { - return string.slice(0, index) + ".0" + string.slice(index); - } else { - return string + ".0"; - } - } -} - -class Inspector { - #references = new Set(); - - inspect(v) { - const t = typeof v; - if (v === true) return "True"; - if (v === false) return "False"; - if (v === null) return "//js(null)"; - if (v === undefined) return "Nil"; - if (t === "string") return this.#string(v); - if (t === "bigint" || Number.isInteger(v)) return v.toString(); - if (t === "number") return float_to_string(v); - if (v instanceof UtfCodepoint) return this.#utfCodepoint(v); - if (v instanceof BitArray) return this.#bit_array(v); - if (v instanceof RegExp) return `//js(${v})`; - if (v instanceof Date) return `//js(Date("${v.toISOString()}"))`; - if (v instanceof globalThis.Error) return `//js(${v.toString()})`; - if (v instanceof Function) { - const args = []; - for (const i of Array(v.length).keys()) - args.push(String.fromCharCode(i + 97)); - return `//fn(${args.join(", ")}) { ... }`; - } - - if (this.#references.size === this.#references.add(v).size) { - return "//js(circular reference)"; - } - - let printed; - if (Array.isArray(v)) { - printed = `#(${v.map((v) => this.inspect(v)).join(", ")})`; - } else if (v instanceof List) { - printed = this.#list(v); - } else if (v instanceof CustomType) { - printed = this.#customType(v); - } else if (v instanceof Dict) { - printed = this.#dict(v); - } else if (v instanceof Set) { - return `//js(Set(${[...v].map((v) => this.inspect(v)).join(", ")}))`; - } else { - printed = this.#object(v); - } - this.#references.delete(v); - return printed; - } - - #object(v) { - const name = Object.getPrototypeOf(v)?.constructor?.name || "Object"; - const props = []; - for (const k of Object.keys(v)) { - props.push(`${this.inspect(k)}: ${this.inspect(v[k])}`); - } - const body = props.length ? " " + props.join(", ") + " " : ""; - const head = name === "Object" ? "" : name + " "; - return `//js(${head}{${body}})`; - } - - #dict(map) { - let body = "dict.from_list(["; - let first = true; - map.forEach((value, key) => { - if (!first) body = body + ", "; - body = body + "#(" + this.inspect(key) + ", " + this.inspect(value) + ")"; - first = false; - }); - return body + "])"; - } - - #customType(record) { - const props = Object.keys(record) - .map((label) => { - const value = this.inspect(record[label]); - return isNaN(parseInt(label)) ? `${label}: ${value}` : value; - }) - .join(", "); - return props - ? `${record.constructor.name}(${props})` - : record.constructor.name; - } - - #list(list) { - if (list instanceof Empty) { - return "[]"; - } - - let char_out = 'charlist.from_string("'; - let list_out = "["; - - let current = list; - while (current instanceof NonEmpty) { - let element = current.head; - current = current.tail; - - if (list_out !== "[") { - list_out += ", "; - } - list_out += this.inspect(element); - - if (char_out) { - if (Number.isInteger(element) && element >= 32 && element <= 126) { - char_out += String.fromCharCode(element); - } else { - char_out = null; - } - } - } - - if (char_out) { - return char_out + '")'; - } else { - return list_out + "]"; - } - } - - #string(str) { - let new_str = '"'; - for (let i = 0; i < str.length; i++) { - const char = str[i]; - switch (char) { - case "\n": - new_str += "\\n"; - break; - case "\r": - new_str += "\\r"; - break; - case "\t": - new_str += "\\t"; - break; - case "\f": - new_str += "\\f"; - break; - case "\\": - new_str += "\\\\"; - break; - case '"': - new_str += '\\"'; - break; - default: - if (char < " " || (char > "~" && char < "\u{00A0}")) { - new_str += - "\\u{" + - char.charCodeAt(0).toString(16).toUpperCase().padStart(4, "0") + - "}"; - } else { - new_str += char; - } - } - } - new_str += '"'; - return new_str; - } - - #utfCodepoint(codepoint) { - return `//utfcodepoint(${String.fromCodePoint(codepoint.value)})`; - } - - #bit_array(bits) { - if (bits.bitSize === 0) { - return "<<>>"; - } - - let acc = "<<"; - - for (let i = 0; i < bits.byteSize - 1; i++) { - acc += bits.byteAt(i).toString(); - acc += ", "; - } - - if (bits.byteSize * 8 === bits.bitSize) { - acc += bits.byteAt(bits.byteSize - 1).toString(); - } else { - const trailingBitsCount = bits.bitSize % 8; - acc += bits.byteAt(bits.byteSize - 1) >> (8 - trailingBitsCount); - acc += `:size(${trailingBitsCount})`; - } - - acc += ">>"; - return acc; - } -} - -export function base16_encode(bit_array) { - const trailingBitsCount = bit_array.bitSize % 8; - - let result = ""; - - for (let i = 0; i < bit_array.byteSize; i++) { - let byte = bit_array.byteAt(i); - - if (i === bit_array.byteSize - 1 && trailingBitsCount !== 0) { - const unusedBitsCount = 8 - trailingBitsCount; - byte = (byte >> unusedBitsCount) << unusedBitsCount; - } - - result += byte.toString(16).padStart(2, "0").toUpperCase(); - } - - return result; -} - -export function base16_decode(string) { - const bytes = new Uint8Array(string.length / 2); - for (let i = 0; i < string.length; i += 2) { - const a = parseInt(string[i], 16); - const b = parseInt(string[i + 1], 16); - if (isNaN(a) || isNaN(b)) return new Error(Nil); - bytes[i / 2] = a * 16 + b; - } - return new Ok(new BitArray(bytes)); -} - -export function bit_array_to_int_and_size(bits) { - const trailingBitsCount = bits.bitSize % 8; - const unusedBitsCount = trailingBitsCount === 0 ? 0 : 8 - trailingBitsCount; - - return [bits.byteAt(0) >> unusedBitsCount, bits.bitSize]; -} - -export function bit_array_starts_with(bits, prefix) { - if (prefix.bitSize > bits.bitSize) { - return false; - } - - // Check any whole bytes - const byteCount = Math.trunc(prefix.bitSize / 8); - for (let i = 0; i < byteCount; i++) { - if (bits.byteAt(i) !== prefix.byteAt(i)) { - return false; - } - } - - // Check any trailing bits at the end of the prefix - if (prefix.bitSize % 8 !== 0) { - const unusedBitsCount = 8 - (prefix.bitSize % 8); - if ( - bits.byteAt(byteCount) >> unusedBitsCount !== - prefix.byteAt(byteCount) >> unusedBitsCount - ) { - return false; - } - } - - return true; -} - -export function log(x) { - // It is checked in Gleam that: - // - The input is strictly positive (x > 0) - // - This ensures that Math.log will never return NaN or -Infinity - // The function can thus safely pass the input to Math.log - // and a valid finite float will always be produced. - return Math.log(x); -} - -export function exp(x) { - return Math.exp(x); -} - -export function list_to_array(list) { - let current = list; - let array = []; - while (current instanceof NonEmpty) { - array.push(current.head); - current = current.tail; - } - return array; -} - -export function index(data, key) { - // Dictionaries and dictionary-like objects can be indexed - if (data instanceof Dict || data instanceof WeakMap || data instanceof Map) { - const token = {}; - const entry = data.get(key, token); - if (entry === token) return new Ok(new None()); - return new Ok(new Some(entry)); - } - - const key_is_int = Number.isInteger(key); - - // Only elements 0-7 of lists can be indexed, negative indices are not allowed - if (key_is_int && key >= 0 && key < 8 && data instanceof List) { - let i = 0; - for (const value of data) { - if (i === key) return new Ok(new Some(value)); - i++; - } - return new Error("Indexable"); - } - - // Arrays and objects can be indexed - if ( - (key_is_int && Array.isArray(data)) || - (data && typeof data === "object") || - (data && Object.getPrototypeOf(data) === Object.prototype) - ) { - if (key in data) return new Ok(new Some(data[key])); - return new Ok(new None()); - } - - return new Error(key_is_int ? "Indexable" : "Dict"); -} - -export function list(data, decode, pushPath, index, emptyList) { - if (!(data instanceof List || Array.isArray(data))) { - const error = new DecodeError("List", classify(data), emptyList); - return [emptyList, List.fromArray([error])]; - } - - const decoded = []; - - for (const element of data) { - const layer = decode(element); - const [out, errors] = layer; - - if (errors instanceof NonEmpty) { - const [_, errors] = pushPath(layer, index.toString()); - return [emptyList, errors]; - } - decoded.push(out); - index++; - } - - return [List.fromArray(decoded), emptyList]; -} - -export function dict(data) { - if (data instanceof Dict) { - return new Ok(data); - } - if (data instanceof Map || data instanceof WeakMap) { - return new Ok(Dict.fromMap(data)); - } - if (data == null) { - return new Error("Dict"); - } - if (typeof data !== "object") { - return new Error("Dict"); - } - const proto = Object.getPrototypeOf(data); - if (proto === Object.prototype || proto === null) { - return new Ok(Dict.fromObject(data)); - } - return new Error("Dict"); -} - -export function bit_array(data) { - if (data instanceof BitArray) return new Ok(data); - if (data instanceof Uint8Array) return new Ok(new BitArray(data)); - return new Error(new BitArray(new Uint8Array())); -} - -export function float(data) { - if (typeof data === "number") return new Ok(data); - return new Error(0.0); -} - -export function int(data) { - if (Number.isInteger(data)) return new Ok(data); - return new Error(0); -} - -export function string(data) { - if (typeof data === "string") return new Ok(data); - return new Error(""); -} - -export function is_null(data) { - return data === null || data === undefined; -} diff --git a/build/dev/javascript/gleam_time/_gleam_artefacts/gleam@time@calendar.cache b/build/dev/javascript/gleam_time/_gleam_artefacts/gleam@time@calendar.cache deleted file mode 100644 index b3da925..0000000 Binary files a/build/dev/javascript/gleam_time/_gleam_artefacts/gleam@time@calendar.cache and /dev/null differ diff --git a/build/dev/javascript/gleam_time/_gleam_artefacts/gleam@time@calendar.cache_inline b/build/dev/javascript/gleam_time/_gleam_artefacts/gleam@time@calendar.cache_inline deleted file mode 100644 index 1b1cb4d..0000000 Binary files a/build/dev/javascript/gleam_time/_gleam_artefacts/gleam@time@calendar.cache_inline and /dev/null differ diff --git a/build/dev/javascript/gleam_time/_gleam_artefacts/gleam@time@calendar.cache_meta b/build/dev/javascript/gleam_time/_gleam_artefacts/gleam@time@calendar.cache_meta deleted file mode 100644 index e65ddb6..0000000 Binary files a/build/dev/javascript/gleam_time/_gleam_artefacts/gleam@time@calendar.cache_meta and /dev/null differ diff --git a/build/dev/javascript/gleam_time/_gleam_artefacts/gleam@time@duration.cache b/build/dev/javascript/gleam_time/_gleam_artefacts/gleam@time@duration.cache deleted file mode 100644 index 6600435..0000000 Binary files a/build/dev/javascript/gleam_time/_gleam_artefacts/gleam@time@duration.cache and /dev/null differ diff --git a/build/dev/javascript/gleam_time/_gleam_artefacts/gleam@time@duration.cache_inline b/build/dev/javascript/gleam_time/_gleam_artefacts/gleam@time@duration.cache_inline deleted file mode 100644 index 1b1cb4d..0000000 Binary files a/build/dev/javascript/gleam_time/_gleam_artefacts/gleam@time@duration.cache_inline and /dev/null differ diff --git a/build/dev/javascript/gleam_time/_gleam_artefacts/gleam@time@duration.cache_meta b/build/dev/javascript/gleam_time/_gleam_artefacts/gleam@time@duration.cache_meta deleted file mode 100644 index 63b7b08..0000000 Binary files a/build/dev/javascript/gleam_time/_gleam_artefacts/gleam@time@duration.cache_meta and /dev/null differ diff --git a/build/dev/javascript/gleam_time/_gleam_artefacts/gleam@time@timestamp.cache b/build/dev/javascript/gleam_time/_gleam_artefacts/gleam@time@timestamp.cache deleted file mode 100644 index cbc5fca..0000000 Binary files a/build/dev/javascript/gleam_time/_gleam_artefacts/gleam@time@timestamp.cache and /dev/null differ diff --git a/build/dev/javascript/gleam_time/_gleam_artefacts/gleam@time@timestamp.cache_inline b/build/dev/javascript/gleam_time/_gleam_artefacts/gleam@time@timestamp.cache_inline deleted file mode 100644 index 1b1cb4d..0000000 Binary files a/build/dev/javascript/gleam_time/_gleam_artefacts/gleam@time@timestamp.cache_inline and /dev/null differ diff --git a/build/dev/javascript/gleam_time/_gleam_artefacts/gleam@time@timestamp.cache_meta b/build/dev/javascript/gleam_time/_gleam_artefacts/gleam@time@timestamp.cache_meta deleted file mode 100644 index 9212c72..0000000 Binary files a/build/dev/javascript/gleam_time/_gleam_artefacts/gleam@time@timestamp.cache_meta and /dev/null differ diff --git a/build/dev/javascript/gleam_time/gleam.mjs b/build/dev/javascript/gleam_time/gleam.mjs deleted file mode 100644 index 197cbbc..0000000 --- a/build/dev/javascript/gleam_time/gleam.mjs +++ /dev/null @@ -1 +0,0 @@ -export * from "../prelude.mjs"; diff --git a/build/dev/javascript/gleam_time/gleam/time/calendar.mjs b/build/dev/javascript/gleam_time/gleam/time/calendar.mjs deleted file mode 100644 index 65048b8..0000000 --- a/build/dev/javascript/gleam_time/gleam/time/calendar.mjs +++ /dev/null @@ -1,391 +0,0 @@ -import * as $int from "../../../gleam_stdlib/gleam/int.mjs"; -import * as $order from "../../../gleam_stdlib/gleam/order.mjs"; -import { Ok, Error, CustomType as $CustomType } from "../../gleam.mjs"; -import * as $duration from "../../gleam/time/duration.mjs"; -import { local_time_offset_seconds } from "../../gleam_time_ffi.mjs"; - -export class Date extends $CustomType { - constructor(year, month, day) { - super(); - this.year = year; - this.month = month; - this.day = day; - } -} -export const Date$Date = (year, month, day) => new Date(year, month, day); -export const Date$isDate = (value) => value instanceof Date; -export const Date$Date$year = (value) => value.year; -export const Date$Date$0 = (value) => value.year; -export const Date$Date$month = (value) => value.month; -export const Date$Date$1 = (value) => value.month; -export const Date$Date$day = (value) => value.day; -export const Date$Date$2 = (value) => value.day; - -export class TimeOfDay extends $CustomType { - constructor(hours, minutes, seconds, nanoseconds) { - super(); - this.hours = hours; - this.minutes = minutes; - this.seconds = seconds; - this.nanoseconds = nanoseconds; - } -} -export const TimeOfDay$TimeOfDay = (hours, minutes, seconds, nanoseconds) => - new TimeOfDay(hours, minutes, seconds, nanoseconds); -export const TimeOfDay$isTimeOfDay = (value) => value instanceof TimeOfDay; -export const TimeOfDay$TimeOfDay$hours = (value) => value.hours; -export const TimeOfDay$TimeOfDay$0 = (value) => value.hours; -export const TimeOfDay$TimeOfDay$minutes = (value) => value.minutes; -export const TimeOfDay$TimeOfDay$1 = (value) => value.minutes; -export const TimeOfDay$TimeOfDay$seconds = (value) => value.seconds; -export const TimeOfDay$TimeOfDay$2 = (value) => value.seconds; -export const TimeOfDay$TimeOfDay$nanoseconds = (value) => value.nanoseconds; -export const TimeOfDay$TimeOfDay$3 = (value) => value.nanoseconds; - -export class January extends $CustomType {} -export const Month$January = () => new January(); -export const Month$isJanuary = (value) => value instanceof January; - -export class February extends $CustomType {} -export const Month$February = () => new February(); -export const Month$isFebruary = (value) => value instanceof February; - -export class March extends $CustomType {} -export const Month$March = () => new March(); -export const Month$isMarch = (value) => value instanceof March; - -export class April extends $CustomType {} -export const Month$April = () => new April(); -export const Month$isApril = (value) => value instanceof April; - -export class May extends $CustomType {} -export const Month$May = () => new May(); -export const Month$isMay = (value) => value instanceof May; - -export class June extends $CustomType {} -export const Month$June = () => new June(); -export const Month$isJune = (value) => value instanceof June; - -export class July extends $CustomType {} -export const Month$July = () => new July(); -export const Month$isJuly = (value) => value instanceof July; - -export class August extends $CustomType {} -export const Month$August = () => new August(); -export const Month$isAugust = (value) => value instanceof August; - -export class September extends $CustomType {} -export const Month$September = () => new September(); -export const Month$isSeptember = (value) => value instanceof September; - -export class October extends $CustomType {} -export const Month$October = () => new October(); -export const Month$isOctober = (value) => value instanceof October; - -export class November extends $CustomType {} -export const Month$November = () => new November(); -export const Month$isNovember = (value) => value instanceof November; - -export class December extends $CustomType {} -export const Month$December = () => new December(); -export const Month$isDecember = (value) => value instanceof December; - -/** - * Get the offset for the computer's currently configured time zone. - * - * Note this may not be the time zone that is correct to use for your user. - * For example, if you are making a web application that runs on a server you - * want _their_ computer's time zone, not yours. - * - * This is the _current local_ offset, not the current local time zone. This - * means that while it will result in the expected outcome for the current - * time, it may result in unexpected output if used with other timestamps. For - * example: a timestamp that would locally be during daylight savings time if - * is it not currently daylight savings time when this function is called. - */ -export function local_offset() { - return $duration.seconds(local_time_offset_seconds()); -} - -/** - * Returns the English name for a month. - * - * # Examples - * - * ```gleam - * month_to_string(April) - * // -> "April" - * ``` - */ -export function month_to_string(month) { - if (month instanceof January) { - return "January"; - } else if (month instanceof February) { - return "February"; - } else if (month instanceof March) { - return "March"; - } else if (month instanceof April) { - return "April"; - } else if (month instanceof May) { - return "May"; - } else if (month instanceof June) { - return "June"; - } else if (month instanceof July) { - return "July"; - } else if (month instanceof August) { - return "August"; - } else if (month instanceof September) { - return "September"; - } else if (month instanceof October) { - return "October"; - } else if (month instanceof November) { - return "November"; - } else { - return "December"; - } -} - -/** - * Returns the number for the month, where January is 1 and December is 12. - * - * # Examples - * - * ```gleam - * month_to_int(January) - * // -> 1 - * ``` - */ -export function month_to_int(month) { - if (month instanceof January) { - return 1; - } else if (month instanceof February) { - return 2; - } else if (month instanceof March) { - return 3; - } else if (month instanceof April) { - return 4; - } else if (month instanceof May) { - return 5; - } else if (month instanceof June) { - return 6; - } else if (month instanceof July) { - return 7; - } else if (month instanceof August) { - return 8; - } else if (month instanceof September) { - return 9; - } else if (month instanceof October) { - return 10; - } else if (month instanceof November) { - return 11; - } else { - return 12; - } -} - -/** - * Returns the month for a given number, where January is 1 and December is 12. - * - * # Examples - * - * ```gleam - * month_from_int(1) - * // -> Ok(January) - * ``` - */ -export function month_from_int(month) { - if (month === 1) { - return new Ok(new January()); - } else if (month === 2) { - return new Ok(new February()); - } else if (month === 3) { - return new Ok(new March()); - } else if (month === 4) { - return new Ok(new April()); - } else if (month === 5) { - return new Ok(new May()); - } else if (month === 6) { - return new Ok(new June()); - } else if (month === 7) { - return new Ok(new July()); - } else if (month === 8) { - return new Ok(new August()); - } else if (month === 9) { - return new Ok(new September()); - } else if (month === 10) { - return new Ok(new October()); - } else if (month === 11) { - return new Ok(new November()); - } else if (month === 12) { - return new Ok(new December()); - } else { - return new Error(undefined); - } -} - -/** - * Determines if a given year is a leap year. - * - * A leap year occurs every 4 years, except for years divisible by 100, - * unless they are also divisible by 400. - * - * # Examples - * - * ```gleam - * is_leap_year(2024) - * // -> True - * ``` - * - * ```gleam - * is_leap_year(2023) - * // -> False - * ``` - */ -export function is_leap_year(year) { - let $ = (year % 400) === 0; - if ($) { - return $; - } else { - let $1 = (year % 100) === 0; - if ($1) { - return false; - } else { - return (year % 4) === 0; - } - } -} - -/** - * Checks if a given date is valid. - * - * This function properly accounts for leap years when validating February days. - * A leap year occurs every 4 years, except for years divisible by 100, - * unless they are also divisible by 400. - * - * # Examples - * - * ```gleam - * is_valid_date(Date(2023, April, 15)) - * // -> True - * ``` - * - * ```gleam - * is_valid_date(Date(2023, April, 31)) - * // -> False - * ``` - * - * ```gleam - * is_valid_date(Date(2024, February, 29)) - * // -> True (2024 is a leap year) - * ``` - */ -export function is_valid_date(date) { - let year; - let month; - let day; - year = date.year; - month = date.month; - day = date.day; - let $ = day < 1; - if ($) { - return false; - } else { - if (month instanceof January) { - return day <= 31; - } else if (month instanceof February) { - let _block; - let $1 = is_leap_year(year); - if ($1) { - _block = 29; - } else { - _block = 28; - } - let max_february_days = _block; - return day <= max_february_days; - } else if (month instanceof March) { - return day <= 31; - } else if (month instanceof April) { - return day <= 30; - } else if (month instanceof May) { - return day <= 31; - } else if (month instanceof June) { - return day <= 30; - } else if (month instanceof July) { - return day <= 31; - } else if (month instanceof August) { - return day <= 31; - } else if (month instanceof September) { - return day <= 30; - } else if (month instanceof October) { - return day <= 31; - } else if (month instanceof November) { - return day <= 30; - } else { - return day <= 31; - } - } -} - -/** - * Checks if a time of day is valid. - * - * Validates that hours are 0-23, minutes are 0-59, seconds are 0-59, - * and nanoseconds are 0-999,999,999. - * - * # Examples - * - * ```gleam - * is_valid_time_of_day(TimeOfDay(12, 30, 45, 123456789)) - * // -> True - * ``` - */ -export function is_valid_time_of_day(time) { - let hours; - let minutes; - let seconds; - let nanoseconds; - hours = time.hours; - minutes = time.minutes; - seconds = time.seconds; - nanoseconds = time.nanoseconds; - return (((((((hours >= 0) && (hours <= 23)) && (minutes >= 0)) && (minutes <= 59)) && (seconds >= 0)) && (seconds <= 59)) && (nanoseconds >= 0)) && (nanoseconds <= 999_999_999); -} - -/** - * Naively compares two dates without any time zone information, returning an - * order. - * - * ## Correctness - * - * This function compares dates without any time zone information, only using - * the rules for the gregorian calendar. This is typically sufficient, but be - * aware that in reality some time zones will change their calendar date - * occasionally. This can result in days being skipped, out of order, or - * happening multiple times. - * - * If you need real-world correct time ordering then use the - * `gleam/time/timestamp` module instead. - */ -export function naive_date_compare(one, other) { - let _pipe = $int.compare(one.year, other.year); - let _pipe$1 = $order.lazy_break_tie( - _pipe, - () => { - return $int.compare(month_to_int(one.month), month_to_int(other.month)); - }, - ); - return $order.lazy_break_tie( - _pipe$1, - () => { return $int.compare(one.day, other.day); }, - ); -} - -/** - * The offset for the [Coordinated Universal Time (UTC)](https://en.wikipedia.org/wiki/Coordinated_Universal_Time) - * time zone. - * - * The utc zone has no time adjustments, it is always zero. It never observes - * daylight-saving time and it never shifts around based on political - * restructuring. - */ -export const utc_offset = $duration.empty; diff --git a/build/dev/javascript/gleam_time/gleam/time/duration.mjs b/build/dev/javascript/gleam_time/gleam/time/duration.mjs deleted file mode 100644 index 53657d0..0000000 --- a/build/dev/javascript/gleam_time/gleam/time/duration.mjs +++ /dev/null @@ -1,382 +0,0 @@ -import * as $bool from "../../../gleam_stdlib/gleam/bool.mjs"; -import * as $int from "../../../gleam_stdlib/gleam/int.mjs"; -import * as $order from "../../../gleam_stdlib/gleam/order.mjs"; -import * as $string from "../../../gleam_stdlib/gleam/string.mjs"; -import { CustomType as $CustomType, remainderInt, divideInt, isEqual } from "../../gleam.mjs"; - -class Duration extends $CustomType { - constructor(seconds, nanoseconds) { - super(); - this.seconds = seconds; - this.nanoseconds = nanoseconds; - } -} - -export class Nanosecond extends $CustomType {} -export const Unit$Nanosecond = () => new Nanosecond(); -export const Unit$isNanosecond = (value) => value instanceof Nanosecond; - -export class Microsecond extends $CustomType {} -export const Unit$Microsecond = () => new Microsecond(); -export const Unit$isMicrosecond = (value) => value instanceof Microsecond; - -export class Millisecond extends $CustomType {} -export const Unit$Millisecond = () => new Millisecond(); -export const Unit$isMillisecond = (value) => value instanceof Millisecond; - -export class Second extends $CustomType {} -export const Unit$Second = () => new Second(); -export const Unit$isSecond = (value) => value instanceof Second; - -export class Minute extends $CustomType {} -export const Unit$Minute = () => new Minute(); -export const Unit$isMinute = (value) => value instanceof Minute; - -export class Hour extends $CustomType {} -export const Unit$Hour = () => new Hour(); -export const Unit$isHour = (value) => value instanceof Hour; - -export class Day extends $CustomType {} -export const Unit$Day = () => new Day(); -export const Unit$isDay = (value) => value instanceof Day; - -export class Week extends $CustomType {} -export const Unit$Week = () => new Week(); -export const Unit$isWeek = (value) => value instanceof Week; - -export class Month extends $CustomType {} -export const Unit$Month = () => new Month(); -export const Unit$isMonth = (value) => value instanceof Month; - -export class Year extends $CustomType {} -export const Unit$Year = () => new Year(); -export const Unit$isYear = (value) => value instanceof Year; - -/** - * Ensure the duration is represented with `nanoseconds` being positive and - * less than 1 second. - * - * This function does not change the amount of time that the duratoin refers - * to, it only adjusts the values used to represent the time. - * - * @ignore - */ -function normalise(duration) { - let multiplier = 1_000_000_000; - let nanoseconds$1 = remainderInt(duration.nanoseconds, multiplier); - let overflow = duration.nanoseconds - nanoseconds$1; - let seconds$1 = duration.seconds + (divideInt(overflow, multiplier)); - let $ = nanoseconds$1 >= 0; - if ($) { - return new Duration(seconds$1, nanoseconds$1); - } else { - return new Duration(seconds$1 - 1, multiplier + nanoseconds$1); - } -} - -/** - * Convert a duration to a number of the largest number of a unit, serving as - * a rough description of the duration that a human can understand. - * - * The size used for each unit are described in the documentation for the - * `Unit` type. - * - * ```gleam - * seconds(125) - * |> approximate - * // -> #(2, Minute) - * ``` - * - * This function rounds _towards zero_. This means that if a duration is just - * short of 2 days then it will approximate to 1 day. - * - * ```gleam - * hours(47) - * |> approximate - * // -> #(1, Day) - * ``` - */ -export function approximate(duration) { - let s; - let ns; - s = duration.seconds; - ns = duration.nanoseconds; - let minute = 60; - let hour = minute * 60; - let day = hour * 24; - let week = day * 7; - let year = day * 365 + hour * 6; - let month = globalThis.Math.trunc(year / 12); - let microsecond = 1000; - let millisecond = microsecond * 1000; - let $ = undefined; - if (s < 0) { - let _block; - let _pipe = new Duration(- s, - ns); - let _pipe$1 = normalise(_pipe); - _block = approximate(_pipe$1); - let $1 = _block; - let amount; - let unit; - amount = $1[0]; - unit = $1[1]; - return [- amount, unit]; - } else if (s >= year) { - return [divideInt(s, year), new Year()]; - } else if (s >= month) { - return [divideInt(s, month), new Month()]; - } else if (s >= week) { - return [divideInt(s, week), new Week()]; - } else if (s >= day) { - return [divideInt(s, day), new Day()]; - } else if (s >= hour) { - return [divideInt(s, hour), new Hour()]; - } else if (s >= minute) { - return [divideInt(s, minute), new Minute()]; - } else if (s > 0) { - return [s, new Second()]; - } else if (ns >= millisecond) { - return [divideInt(ns, millisecond), new Millisecond()]; - } else if (ns >= microsecond) { - return [divideInt(ns, microsecond), new Microsecond()]; - } else { - return [ns, new Nanosecond()]; - } -} - -/** - * Compare one duration to another, indicating whether the first spans a - * larger amount of time (and so is greater) or smaller amount of time (and so - * is lesser) than the second. - * - * # Examples - * - * ```gleam - * compare(seconds(1), seconds(2)) - * // -> order.Lt - * ``` - * - * Whether a duration is negative or positive doesn't matter for comparing - * them, only the amount of time spanned matters. - * - * ```gleam - * compare(seconds(-2), seconds(1)) - * // -> order.Gt - * ``` - */ -export function compare(left, right) { - let parts = (x) => { - let $ = x.seconds >= 0; - if ($) { - return [x.seconds, x.nanoseconds]; - } else { - return [x.seconds * -1 - 1, 1_000_000_000 - x.nanoseconds]; - } - }; - let $ = parts(left); - let ls; - let lns; - ls = $[0]; - lns = $[1]; - let $1 = parts(right); - let rs; - let rns; - rs = $1[0]; - rns = $1[1]; - let _pipe = $int.compare(ls, rs); - return $order.break_tie(_pipe, $int.compare(lns, rns)); -} - -/** - * Calculate the difference between two durations. - * - * This is effectively substracting the first duration from the second. - * - * # Examples - * - * ```gleam - * difference(seconds(1), seconds(5)) - * // -> seconds(4) - * ``` - */ -export function difference(left, right) { - let _pipe = new Duration( - right.seconds - left.seconds, - right.nanoseconds - left.nanoseconds, - ); - return normalise(_pipe); -} - -/** - * Add two durations together. - * - * # Examples - * - * ```gleam - * add(seconds(1), seconds(5)) - * // -> seconds(6) - * ``` - */ -export function add(left, right) { - let _pipe = new Duration( - left.seconds + right.seconds, - left.nanoseconds + right.nanoseconds, - ); - return normalise(_pipe); -} - -function nanosecond_digits(loop$n, loop$position, loop$acc) { - while (true) { - let n = loop$n; - let position = loop$position; - let acc = loop$acc; - if (position === 9) { - return acc; - } else if ((acc === "") && ((remainderInt(n, 10)) === 0)) { - loop$n = globalThis.Math.trunc(n / 10); - loop$position = position + 1; - loop$acc = acc; - } else { - let acc$1 = $int.to_string(n % 10) + acc; - loop$n = globalThis.Math.trunc(n / 10); - loop$position = position + 1; - loop$acc = acc$1; - } - } -} - -/** - * Create a duration of a number of seconds. - */ -export function seconds(amount) { - return new Duration(amount, 0); -} - -/** - * Create a duration of a number of minutes. - */ -export function minutes(amount) { - return seconds(amount * 60); -} - -/** - * Create a duration of a number of hours. - */ -export function hours(amount) { - return seconds(amount * 60 * 60); -} - -/** - * Create a duration of a number of milliseconds. - */ -export function milliseconds(amount) { - let remainder = amount % 1000; - let overflow = amount - remainder; - let nanoseconds$1 = remainder * 1_000_000; - let seconds$1 = globalThis.Math.trunc(overflow / 1000); - let _pipe = new Duration(seconds$1, nanoseconds$1); - return normalise(_pipe); -} - -/** - * Create a duration of a number of nanoseconds. - * - * # JavaScript int limitations - * - * Remember that JavaScript can only perfectly represent ints between positive - * and negative 9,007,199,254,740,991! If you use a single call to this - * function to create durations larger than that number of nanoseconds then - * you will likely not get exactly the value you expect. Use `seconds` and - * `milliseconds` as much as possible for large durations. - */ -export function nanoseconds(amount) { - let _pipe = new Duration(0, amount); - return normalise(_pipe); -} - -/** - * Convert the duration to a number of seconds. - * - * There may be some small loss of precision due to `Duration` being - * nanosecond accurate and `Float` not being able to represent this. - */ -export function to_seconds(duration) { - let seconds$1 = $int.to_float(duration.seconds); - let nanoseconds$1 = $int.to_float(duration.nanoseconds); - return seconds$1 + (nanoseconds$1 / 1_000_000_000.0); -} - -/** - * Convert the duration to a number of seconds and nanoseconds. There is no - * loss of precision with this conversion on any target. - */ -export function to_seconds_and_nanoseconds(duration) { - return [duration.seconds, duration.nanoseconds]; -} - -export const empty = /* @__PURE__ */ new Duration(0, 0); - -/** - * Convert the duration to an [ISO8601][1] formatted duration string. - * - * The ISO8601 duration format is ambiguous without context due to months and - * years having different lengths, and because of leap seconds. This function - * encodes the duration as days, hours, and seconds without any leap seconds. - * Be sure to take this into account when using the duration strings. - * - * [1]: https://en.wikipedia.org/wiki/ISO_8601#Durations - */ -export function to_iso8601_string(duration) { - return $bool.guard( - isEqual(duration, empty), - "PT0S", - () => { - let split = (total, limit) => { - let amount = remainderInt(total, limit); - let remainder = divideInt((total - amount), limit); - return [amount, remainder]; - }; - let $ = split(duration.seconds, 60); - let seconds$1; - let rest; - seconds$1 = $[0]; - rest = $[1]; - let $1 = split(rest, 60); - let minutes$1; - let rest$1; - minutes$1 = $1[0]; - rest$1 = $1[1]; - let $2 = split(rest$1, 24); - let hours$1; - let rest$2; - hours$1 = $2[0]; - rest$2 = $2[1]; - let days = rest$2; - let add$1 = (out, value, unit) => { - if (value === 0) { - return out; - } else { - return (out + $int.to_string(value)) + unit; - } - }; - let _block; - let _pipe = "P"; - let _pipe$1 = add$1(_pipe, days, "D"); - let _pipe$2 = $string.append(_pipe$1, "T"); - let _pipe$3 = add$1(_pipe$2, hours$1, "H"); - _block = add$1(_pipe$3, minutes$1, "M"); - let output = _block; - let $3 = duration.nanoseconds; - if ($3 === 0) { - if (seconds$1 === 0) { - return output; - } else { - return (output + $int.to_string(seconds$1)) + "S"; - } - } else { - let f = nanosecond_digits(duration.nanoseconds, 0, ""); - return (((output + $int.to_string(seconds$1)) + ".") + f) + "S"; - } - }, - ); -} diff --git a/build/dev/javascript/gleam_time/gleam/time/timestamp.mjs b/build/dev/javascript/gleam_time/gleam/time/timestamp.mjs deleted file mode 100644 index 2f3ec9b..0000000 --- a/build/dev/javascript/gleam_time/gleam/time/timestamp.mjs +++ /dev/null @@ -1,1215 +0,0 @@ -import * as $bit_array from "../../../gleam_stdlib/gleam/bit_array.mjs"; -import * as $float from "../../../gleam_stdlib/gleam/float.mjs"; -import * as $int from "../../../gleam_stdlib/gleam/int.mjs"; -import * as $list from "../../../gleam_stdlib/gleam/list.mjs"; -import * as $order from "../../../gleam_stdlib/gleam/order.mjs"; -import * as $result from "../../../gleam_stdlib/gleam/result.mjs"; -import * as $string from "../../../gleam_stdlib/gleam/string.mjs"; -import { - Ok, - Error, - toList, - Empty as $Empty, - prepend as listPrepend, - CustomType as $CustomType, - remainderInt, - divideFloat, - divideInt, - toBitArray, - bitArraySlice, -} from "../../gleam.mjs"; -import * as $calendar from "../../gleam/time/calendar.mjs"; -import * as $duration from "../../gleam/time/duration.mjs"; -import { system_time as get_system_time } from "../../gleam_time_ffi.mjs"; - -class Timestamp extends $CustomType { - constructor(seconds, nanoseconds) { - super(); - this.seconds = seconds; - this.nanoseconds = nanoseconds; - } -} - -/** - * Ensure the time is represented with `nanoseconds` being positive and less - * than 1 second. - * - * This function does not change the time that the timestamp refers to, it - * only adjusts the values used to represent the time. - * - * @ignore - */ -function normalise(timestamp) { - let multiplier = 1_000_000_000; - let nanoseconds = remainderInt(timestamp.nanoseconds, multiplier); - let overflow = timestamp.nanoseconds - nanoseconds; - let seconds = timestamp.seconds + (divideInt(overflow, multiplier)); - let $ = nanoseconds >= 0; - if ($) { - return new Timestamp(seconds, nanoseconds); - } else { - return new Timestamp(seconds - 1, multiplier + nanoseconds); - } -} - -/** - * Compare one timestamp to another, indicating whether the first is further - * into the future (greater) or further into the past (lesser) than the - * second. - * - * # Examples - * - * ```gleam - * compare(from_unix_seconds(1), from_unix_seconds(2)) - * // -> order.Lt - * ``` - */ -export function compare(left, right) { - return $order.break_tie( - $int.compare(left.seconds, right.seconds), - $int.compare(left.nanoseconds, right.nanoseconds), - ); -} - -/** - * Get the current system time. - * - * Note this time is not unique or monotonic, it could change at any time or - * even go backwards! The exact behaviour will depend on the runtime used. See - * the module documentation for more information. - * - * On Erlang this uses [`erlang:system_time/1`][1]. On JavaScript this uses - * [`Date.now`][2]. - * - * [1]: https://www.erlang.org/doc/apps/erts/erlang#system_time/1 - * [2]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/now - */ -export function system_time() { - let $ = get_system_time(); - let seconds; - let nanoseconds; - seconds = $[0]; - nanoseconds = $[1]; - return normalise(new Timestamp(seconds, nanoseconds)); -} - -/** - * Calculate the difference between two timestamps. - * - * This is effectively substracting the first timestamp from the second. - * - * # Examples - * - * ```gleam - * difference(from_unix_seconds(1), from_unix_seconds(5)) - * // -> duration.seconds(4) - * ``` - */ -export function difference(left, right) { - let seconds = $duration.seconds(right.seconds - left.seconds); - let nanoseconds = $duration.nanoseconds(right.nanoseconds - left.nanoseconds); - return $duration.add(seconds, nanoseconds); -} - -/** - * Add a duration to a timestamp. - * - * # Examples - * - * ```gleam - * add(from_unix_seconds(1000), duration.seconds(5)) - * // -> from_unix_seconds(1005) - * ``` - */ -export function add(timestamp, duration) { - let $ = $duration.to_seconds_and_nanoseconds(duration); - let seconds; - let nanoseconds; - seconds = $[0]; - nanoseconds = $[1]; - let _pipe = new Timestamp( - timestamp.seconds + seconds, - timestamp.nanoseconds + nanoseconds, - ); - return normalise(_pipe); -} - -function pad_digit(digit, desired_length) { - let _pipe = $int.to_string(digit); - return $string.pad_start(_pipe, desired_length, "0"); -} - -function duration_to_minutes(duration) { - return $float.round($duration.to_seconds(duration) / 60.0); -} - -function modulo(n, m) { - let $ = $int.modulo(n, m); - if ($ instanceof Ok) { - let n$1 = $[0]; - return n$1; - } else { - return 0; - } -} - -function floored_div(numerator, denominator) { - let n = divideFloat($int.to_float(numerator), denominator); - return $float.round($float.floor(n)); -} - -function to_civil(minutes) { - let raw_day = floored_div(minutes, (60.0 * 24.0)) + 719_468; - let _block; - let $ = raw_day >= 0; - if ($) { - _block = globalThis.Math.trunc(raw_day / 146_097); - } else { - _block = globalThis.Math.trunc((raw_day - 146_096) / 146_097); - } - let era = _block; - let day_of_era = raw_day - era * 146_097; - let year_of_era = globalThis.Math.trunc( - (((day_of_era - (globalThis.Math.trunc(day_of_era / 1460))) + (globalThis.Math.trunc( - day_of_era / 36_524 - ))) - (globalThis.Math.trunc(day_of_era / 146_096))) / 365 - ); - let year = year_of_era + era * 400; - let day_of_year = day_of_era - ((365 * year_of_era + (globalThis.Math.trunc( - year_of_era / 4 - ))) - (globalThis.Math.trunc(year_of_era / 100))); - let mp = globalThis.Math.trunc((5 * day_of_year + 2) / 153); - let _block$1; - let $1 = mp < 10; - if ($1) { - _block$1 = mp + 3; - } else { - _block$1 = mp - 9; - } - let month = _block$1; - let day = (day_of_year - (globalThis.Math.trunc((153 * mp + 2) / 5))) + 1; - let _block$2; - let $2 = month <= 2; - if ($2) { - _block$2 = year + 1; - } else { - _block$2 = year; - } - let year$1 = _block$2; - return [year$1, month, day]; -} - -function to_calendar_from_offset(timestamp, offset) { - let total = timestamp.seconds + offset * 60; - let seconds = modulo(total, 60); - let total_minutes = floored_div(total, 60.0); - let minutes = globalThis.Math.trunc(modulo(total, 60 * 60) / 60); - let hours = divideInt(modulo(total, 24 * 60 * 60), 60 * 60); - let $ = to_civil(total_minutes); - let year; - let month; - let day; - year = $[0]; - month = $[1]; - day = $[2]; - return [year, month, day, hours, minutes, seconds]; -} - -/** - * Convert a `Timestamp` to calendar time, suitable for presenting to a human - * to read. - * - * If you want a machine to use the time value then you should not use this - * function and should instead keep it as a timestamp. See the documentation - * for the `gleam/time/calendar` module for more information. - * - * # Examples - * - * ```gleam - * timestamp.from_unix_seconds(0) - * |> timestamp.to_calendar(calendar.utc_offset) - * // -> #(Date(1970, January, 1), TimeOfDay(0, 0, 0, 0)) - * ``` - */ -export function to_calendar(timestamp, offset) { - let offset$1 = duration_to_minutes(offset); - let $ = to_calendar_from_offset(timestamp, offset$1); - let year; - let month; - let day; - let hours; - let minutes; - let seconds; - year = $[0]; - month = $[1]; - day = $[2]; - hours = $[3]; - minutes = $[4]; - seconds = $[5]; - let _block; - if (month === 1) { - _block = new $calendar.January(); - } else if (month === 2) { - _block = new $calendar.February(); - } else if (month === 3) { - _block = new $calendar.March(); - } else if (month === 4) { - _block = new $calendar.April(); - } else if (month === 5) { - _block = new $calendar.May(); - } else if (month === 6) { - _block = new $calendar.June(); - } else if (month === 7) { - _block = new $calendar.July(); - } else if (month === 8) { - _block = new $calendar.August(); - } else if (month === 9) { - _block = new $calendar.September(); - } else if (month === 10) { - _block = new $calendar.October(); - } else if (month === 11) { - _block = new $calendar.November(); - } else { - _block = new $calendar.December(); - } - let month$1 = _block; - let nanoseconds = timestamp.nanoseconds; - let date = new $calendar.Date(year, month$1, day); - let time = new $calendar.TimeOfDay(hours, minutes, seconds, nanoseconds); - return [date, time]; -} - -function do_remove_trailing_zeros(loop$reversed_digits) { - while (true) { - let reversed_digits = loop$reversed_digits; - if (reversed_digits instanceof $Empty) { - return reversed_digits; - } else { - let digit = reversed_digits.head; - if (digit === 0) { - let digits = reversed_digits.tail; - loop$reversed_digits = digits; - } else { - let reversed_digits$1 = reversed_digits; - return $list.reverse(reversed_digits$1); - } - } - } -} - -/** - * Given a list of digits, return new list with any trailing zeros removed. - * - * @ignore - */ -function remove_trailing_zeros(digits) { - let reversed_digits = $list.reverse(digits); - return do_remove_trailing_zeros(reversed_digits); -} - -function do_get_zero_padded_digits(loop$number, loop$digits, loop$count) { - while (true) { - let number = loop$number; - let digits = loop$digits; - let count = loop$count; - let number$1 = number; - if ((number$1 <= 0) && (count >= 9)) { - return digits; - } else { - let number$2 = number; - if (number$2 <= 0) { - loop$number = number$2; - loop$digits = listPrepend(0, digits); - loop$count = count + 1; - } else { - let number$3 = number; - let digit = number$3 % 10; - let number$4 = floored_div(number$3, 10.0); - loop$number = number$4; - loop$digits = listPrepend(digit, digits); - loop$count = count + 1; - } - } - } -} - -/** - * Returns the list of digits of `number`. If the number of digits is less - * than 9, the result is zero-padded at the front. - * - * @ignore - */ -function get_zero_padded_digits(number) { - return do_get_zero_padded_digits(number, toList([]), 0); -} - -/** - * Converts nanoseconds into a `String` representation of fractional seconds. - * - * Assumes that `nanoseconds < 1_000_000_000`, which will be true for any - * normalised timestamp. - * - * @ignore - */ -function show_second_fraction(nanoseconds) { - let $ = $int.compare(nanoseconds, 0); - if ($ instanceof $order.Lt) { - return ""; - } else if ($ instanceof $order.Eq) { - return ""; - } else { - let _block; - let _pipe = nanoseconds; - let _pipe$1 = get_zero_padded_digits(_pipe); - let _pipe$2 = remove_trailing_zeros(_pipe$1); - let _pipe$3 = $list.map(_pipe$2, $int.to_string); - _block = $string.join(_pipe$3, ""); - let second_fraction_part = _block; - return "." + second_fraction_part; - } -} - -/** - * Convert a timestamp to a RFC 3339 formatted time string, with an offset - * supplied as an additional argument. - * - * The output of this function is also ISO 8601 compatible so long as the - * offset not negative. Offsets have at-most minute precision, so an offset - * with higher precision will be rounded to the nearest minute. - * - * If you are making an API such as a HTTP JSON API you are encouraged to use - * Unix timestamps instead of this format or ISO 8601. Unix timestamps are a - * better choice as they don't contain offset information. Consider: - * - * - UTC offsets are not time zones. This does not and cannot tell us the time - * zone in which the date was recorded. So what are we supposed to do with - * this information? - * - Users typically want dates formatted according to their local time zone. - * What if the provided UTC offset is different from the current user's time - * zone? What are we supposed to do with it then? - * - Despite it being useless (or worse, a source of bugs), the UTC offset - * creates a larger payload to transfer. - * - * They also uses more memory than a unix timestamp. The way they are better - * than Unix timestamp is that it is easier for a human to read them, but - * this is a hinderance that tooling can remedy, and APIs are not primarily - * for humans. - * - * # Examples - * - * ```gleam - * timestamp.from_unix_seconds_and_nanoseconds(1000, 123_000_000) - * |> to_rfc3339(calendar.utc_offset) - * // -> "1970-01-01T00:16:40.123Z" - * ``` - * - * ```gleam - * timestamp.from_unix_seconds(1000) - * |> to_rfc3339(duration.seconds(3600)) - * // -> "1970-01-01T01:16:40+01:00" - * ``` - */ -export function to_rfc3339(timestamp, offset) { - let offset$1 = duration_to_minutes(offset); - let $ = to_calendar_from_offset(timestamp, offset$1); - let years; - let months; - let days; - let hours; - let minutes; - let seconds; - years = $[0]; - months = $[1]; - days = $[2]; - hours = $[3]; - minutes = $[4]; - seconds = $[5]; - let offset_minutes = modulo(offset$1, 60); - let offset_hours = $int.absolute_value(floored_div(offset$1, 60.0)); - let n2 = (_capture) => { return pad_digit(_capture, 2); }; - let n4 = (_capture) => { return pad_digit(_capture, 4); }; - let out = ""; - let out$1 = ((((out + n4(years)) + "-") + n2(months)) + "-") + n2(days); - let out$2 = out$1 + "T"; - let out$3 = ((((out$2 + n2(hours)) + ":") + n2(minutes)) + ":") + n2(seconds); - let out$4 = out$3 + show_second_fraction(timestamp.nanoseconds); - let $1 = $int.compare(offset$1, 0); - if ($1 instanceof $order.Lt) { - return (((out$4 + "-") + n2(offset_hours)) + ":") + n2(offset_minutes); - } else if ($1 instanceof $order.Eq) { - return out$4 + "Z"; - } else { - return (((out$4 + "+") + n2(offset_hours)) + ":") + n2(offset_minutes); - } -} - -function is_leap_year(year) { - return ((year % 4) === 0) && (((year % 100) !== 0) || ((year % 400) === 0)); -} - -function parse_sign(bytes) { - if (bytes.bitSize >= 8) { - if (bytes.byteAt(0) === 43) { - if ((bytes.bitSize - 8) % 8 === 0) { - let remaining_bytes = bitArraySlice(bytes, 8); - return new Ok(["+", remaining_bytes]); - } else { - return new Error(undefined); - } - } else if (bytes.byteAt(0) === 45 && (bytes.bitSize - 8) % 8 === 0) { - let remaining_bytes = bitArraySlice(bytes, 8); - return new Ok(["-", remaining_bytes]); - } else { - return new Error(undefined); - } - } else { - return new Error(undefined); - } -} - -/** - * Accept the given value from `bytes` and move past it if found. - * - * @ignore - */ -function accept_byte(bytes, value) { - if (bytes.bitSize >= 8 && (bytes.bitSize - 8) % 8 === 0) { - let byte = bytes.byteAt(0); - if (byte === value) { - let remaining_bytes = bitArraySlice(bytes, 8); - return new Ok(remaining_bytes); - } else { - return new Error(undefined); - } - } else { - return new Error(undefined); - } -} - -function accept_empty(bytes) { - if (bytes.bitSize === 0) { - return new Ok(undefined); - } else { - return new Error(undefined); - } -} - -/** - * Note: It is the callers responsibility to ensure the inputs are valid. - * - * See https://www.tondering.dk/claus/cal/julperiod.php#formula - * - * @ignore - */ -function julian_day_from_ymd(year, month, day) { - let adjustment = globalThis.Math.trunc((14 - month) / 12); - let adjusted_year = (year + 4800) - adjustment; - let adjusted_month = (month + 12 * adjustment) - 3; - return (((((day + (globalThis.Math.trunc((153 * adjusted_month + 2) / 5))) + 365 * adjusted_year) + (globalThis.Math.trunc( - adjusted_year / 4 - ))) - (globalThis.Math.trunc(adjusted_year / 100))) + (globalThis.Math.trunc( - adjusted_year / 400 - ))) - 32_045; -} - -/** - * Create a timestamp from a number of seconds since 00:00:00 UTC on 1 January - * 1970. - */ -export function from_unix_seconds(seconds) { - return new Timestamp(seconds, 0); -} - -/** - * Create a timestamp from a number of seconds and nanoseconds since 00:00:00 - * UTC on 1 January 1970. - * - * # JavaScript int limitations - * - * Remember that JavaScript can only perfectly represent ints between positive - * and negative 9,007,199,254,740,991! If you only use the nanosecond field - * then you will almost certainly not get the date value you want due to this - * loss of precision. Always use seconds primarily and then use nanoseconds - * for the final sub-second adjustment. - */ -export function from_unix_seconds_and_nanoseconds(seconds, nanoseconds) { - let _pipe = new Timestamp(seconds, nanoseconds); - return normalise(_pipe); -} - -/** - * Convert the timestamp to a number of seconds since 00:00:00 UTC on 1 - * January 1970. - * - * There may be some small loss of precision due to `Timestamp` being - * nanosecond accurate and `Float` not being able to represent this. - */ -export function to_unix_seconds(timestamp) { - let seconds = $int.to_float(timestamp.seconds); - let nanoseconds = $int.to_float(timestamp.nanoseconds); - return seconds + (nanoseconds / 1_000_000_000.0); -} - -/** - * Convert the timestamp to a number of seconds and nanoseconds since 00:00:00 - * UTC on 1 January 1970. There is no loss of precision with this conversion - * on any target. - */ -export function to_unix_seconds_and_nanoseconds(timestamp) { - return [timestamp.seconds, timestamp.nanoseconds]; -} - -const seconds_per_day = 86_400; - -const seconds_per_hour = 3600; - -const seconds_per_minute = 60; - -function offset_to_seconds(sign, hours, minutes) { - let abs_seconds = hours * seconds_per_hour + minutes * seconds_per_minute; - if (sign === "-") { - return - abs_seconds; - } else { - return abs_seconds; - } -} - -/** - * `julian_seconds_from_parts(year, month, day, hours, minutes, seconds)` - * returns the number of Julian - * seconds represented by the given arguments. - * - * Note: It is the callers responsibility to ensure the inputs are valid. - * - * See https://www.tondering.dk/claus/cal/julperiod.php#formula - * - * @ignore - */ -function julian_seconds_from_parts(year, month, day, hours, minutes, seconds) { - let julian_day_seconds = julian_day_from_ymd(year, month, day) * seconds_per_day; - return ((julian_day_seconds + hours * seconds_per_hour) + minutes * seconds_per_minute) + seconds; -} - -const nanoseconds_per_second = 1_000_000_000; - -/** - * The `:` character as a byte - * - * @ignore - */ -const byte_colon = 0x3A; - -/** - * The `-` character as a byte - * - * @ignore - */ -const byte_minus = 0x2D; - -/** - * The `0` character as a byte - * - * @ignore - */ -const byte_zero = 0x30; - -/** - * The `9` character as a byte - * - * @ignore - */ -const byte_nine = 0x39; - -function do_parse_second_fraction_as_nanoseconds( - loop$bytes, - loop$acc, - loop$power -) { - while (true) { - let bytes = loop$bytes; - let acc = loop$acc; - let power = loop$power; - let power$1 = globalThis.Math.trunc(power / 10); - if (bytes.bitSize >= 8 && (bytes.bitSize - 8) % 8 === 0) { - let byte = bytes.byteAt(0); - if (((0x30 <= byte) && (byte <= 0x39)) && (power$1 < 1)) { - let remaining_bytes = bitArraySlice(bytes, 8); - loop$bytes = remaining_bytes; - loop$acc = acc; - loop$power = power$1; - } else { - let byte$1 = bytes.byteAt(0); - if ((0x30 <= byte$1) && (byte$1 <= 0x39)) { - let remaining_bytes = bitArraySlice(bytes, 8); - let digit = byte$1 - 0x30; - loop$bytes = remaining_bytes; - loop$acc = acc + digit * power$1; - loop$power = power$1; - } else { - return new Ok([acc, bytes]); - } - } - } else { - return new Ok([acc, bytes]); - } - } -} - -function parse_second_fraction_as_nanoseconds(bytes) { - if (bytes.bitSize >= 8 && bytes.byteAt(0) === 46) { - if (bytes.bitSize >= 16 && (bytes.bitSize - 16) % 8 === 0) { - let byte = bytes.byteAt(1); - if ((0x30 <= byte) && (byte <= 0x39)) { - let remaining_bytes = bitArraySlice(bytes, 16); - return do_parse_second_fraction_as_nanoseconds( - toBitArray([byte, remaining_bytes]), - 0, - nanoseconds_per_second, - ); - } else if ((bytes.bitSize - 8) % 8 === 0) { - return new Error(undefined); - } else { - return new Ok([0, bytes]); - } - } else if ((bytes.bitSize - 8) % 8 === 0) { - return new Error(undefined); - } else { - return new Ok([0, bytes]); - } - } else { - return new Ok([0, bytes]); - } -} - -function do_parse_digits(loop$bytes, loop$count, loop$acc, loop$k) { - while (true) { - let bytes = loop$bytes; - let count = loop$count; - let acc = loop$acc; - let k = loop$k; - if (k >= count) { - return new Ok([acc, bytes]); - } else if (bytes.bitSize >= 8 && (bytes.bitSize - 8) % 8 === 0) { - let byte = bytes.byteAt(0); - if ((0x30 <= byte) && (byte <= 0x39)) { - let remaining_bytes = bitArraySlice(bytes, 8); - loop$bytes = remaining_bytes; - loop$count = count; - loop$acc = acc * 10 + (byte - 0x30); - loop$k = k + 1; - } else { - return new Error(undefined); - } - } else { - return new Error(undefined); - } - } -} - -/** - * Parse and return the given number of digits from the given bytes. - * - * @ignore - */ -function parse_digits(bytes, count) { - return do_parse_digits(bytes, count, 0, 0); -} - -function parse_year(bytes) { - return parse_digits(bytes, 4); -} - -function parse_month(bytes) { - return $result.try$( - parse_digits(bytes, 2), - (_use0) => { - let month; - let bytes$1; - month = _use0[0]; - bytes$1 = _use0[1]; - let $ = (1 <= month) && (month <= 12); - if ($) { - return new Ok([month, bytes$1]); - } else { - return new Error(undefined); - } - }, - ); -} - -function parse_day(bytes, year, month) { - return $result.try$( - parse_digits(bytes, 2), - (_use0) => { - let day; - let bytes$1; - day = _use0[0]; - bytes$1 = _use0[1]; - return $result.try$( - (() => { - if (month === 1) { - return new Ok(31); - } else if (month === 3) { - return new Ok(31); - } else if (month === 5) { - return new Ok(31); - } else if (month === 7) { - return new Ok(31); - } else if (month === 8) { - return new Ok(31); - } else if (month === 10) { - return new Ok(31); - } else if (month === 12) { - return new Ok(31); - } else if (month === 4) { - return new Ok(30); - } else if (month === 6) { - return new Ok(30); - } else if (month === 9) { - return new Ok(30); - } else if (month === 11) { - return new Ok(30); - } else if (month === 2) { - let $ = is_leap_year(year); - if ($) { - return new Ok(29); - } else { - return new Ok(28); - } - } else { - return new Error(undefined); - } - })(), - (max_day) => { - let $ = (1 <= day) && (day <= max_day); - if ($) { - return new Ok([day, bytes$1]); - } else { - return new Error(undefined); - } - }, - ); - }, - ); -} - -function parse_hours(bytes) { - return $result.try$( - parse_digits(bytes, 2), - (_use0) => { - let hours; - let bytes$1; - hours = _use0[0]; - bytes$1 = _use0[1]; - let $ = (0 <= hours) && (hours <= 23); - if ($) { - return new Ok([hours, bytes$1]); - } else { - return new Error(undefined); - } - }, - ); -} - -function parse_minutes(bytes) { - return $result.try$( - parse_digits(bytes, 2), - (_use0) => { - let minutes; - let bytes$1; - minutes = _use0[0]; - bytes$1 = _use0[1]; - let $ = (0 <= minutes) && (minutes <= 59); - if ($) { - return new Ok([minutes, bytes$1]); - } else { - return new Error(undefined); - } - }, - ); -} - -function parse_seconds(bytes) { - return $result.try$( - parse_digits(bytes, 2), - (_use0) => { - let seconds; - let bytes$1; - seconds = _use0[0]; - bytes$1 = _use0[1]; - let $ = (0 <= seconds) && (seconds <= 60); - if ($) { - return new Ok([seconds, bytes$1]); - } else { - return new Error(undefined); - } - }, - ); -} - -function parse_numeric_offset(bytes) { - return $result.try$( - parse_sign(bytes), - (_use0) => { - let sign; - let bytes$1; - sign = _use0[0]; - bytes$1 = _use0[1]; - return $result.try$( - parse_hours(bytes$1), - (_use0) => { - let hours; - let bytes$2; - hours = _use0[0]; - bytes$2 = _use0[1]; - return $result.try$( - accept_byte(bytes$2, byte_colon), - (bytes) => { - return $result.try$( - parse_minutes(bytes), - (_use0) => { - let minutes; - let bytes$1; - minutes = _use0[0]; - bytes$1 = _use0[1]; - let offset_seconds = offset_to_seconds(sign, hours, minutes); - return new Ok([offset_seconds, bytes$1]); - }, - ); - }, - ); - }, - ); - }, - ); -} - -function parse_offset(bytes) { - if (bytes.bitSize >= 8) { - if (bytes.byteAt(0) === 90) { - if ((bytes.bitSize - 8) % 8 === 0) { - let remaining_bytes = bitArraySlice(bytes, 8); - return new Ok([0, remaining_bytes]); - } else { - return parse_numeric_offset(bytes); - } - } else if (bytes.byteAt(0) === 122 && (bytes.bitSize - 8) % 8 === 0) { - let remaining_bytes = bitArraySlice(bytes, 8); - return new Ok([0, remaining_bytes]); - } else { - return parse_numeric_offset(bytes); - } - } else { - return parse_numeric_offset(bytes); - } -} - -/** - * The `t` character as a byte - * - * @ignore - */ -const byte_t_lowercase = 0x74; - -/** - * The `T` character as a byte - * - * @ignore - */ -const byte_t_uppercase = 0x54; - -/** - * The `T` character as a byte - * - * @ignore - */ -const byte_space = 0x20; - -function accept_date_time_separator(bytes) { - if (bytes.bitSize >= 8 && (bytes.bitSize - 8) % 8 === 0) { - let byte = bytes.byteAt(0); - if (((byte === 0x54) || (byte === 0x74)) || (byte === 0x20)) { - let remaining_bytes = bitArraySlice(bytes, 8); - return new Ok(remaining_bytes); - } else { - return new Error(undefined); - } - } else { - return new Error(undefined); - } -} - -/** - * The Julian seconds of the UNIX epoch (Julian day is 2_440_588) - * - * @ignore - */ -const julian_seconds_unix_epoch = 210_866_803_200; - -/** - * Note: The caller of this function must ensure that all inputs are valid. - * - * @ignore - */ -function from_date_time( - year, - month, - day, - hours, - minutes, - seconds, - second_fraction_as_nanoseconds, - offset_seconds -) { - let julian_seconds = julian_seconds_from_parts( - year, - month, - day, - hours, - minutes, - seconds, - ); - let julian_seconds_since_epoch = julian_seconds - julian_seconds_unix_epoch; - let _pipe = new Timestamp( - julian_seconds_since_epoch - offset_seconds, - second_fraction_as_nanoseconds, - ); - return normalise(_pipe); -} - -/** - * Create a `Timestamp` from a human-readable calendar time. - * - * # Examples - * - * ```gleam - * timestamp.from_calendar( - * date: calendar.Date(2024, calendar.December, 25), - * time: calendar.TimeOfDay(12, 30, 50, 0), - * offset: calendar.utc_offset, - * ) - * |> timestamp.to_rfc3339(calendar.utc_offset) - * // -> "2024-12-25T12:30:50Z" - * ``` - */ -export function from_calendar(date, time, offset) { - let _block; - let $ = date.month; - if ($ instanceof $calendar.January) { - _block = 1; - } else if ($ instanceof $calendar.February) { - _block = 2; - } else if ($ instanceof $calendar.March) { - _block = 3; - } else if ($ instanceof $calendar.April) { - _block = 4; - } else if ($ instanceof $calendar.May) { - _block = 5; - } else if ($ instanceof $calendar.June) { - _block = 6; - } else if ($ instanceof $calendar.July) { - _block = 7; - } else if ($ instanceof $calendar.August) { - _block = 8; - } else if ($ instanceof $calendar.September) { - _block = 9; - } else if ($ instanceof $calendar.October) { - _block = 10; - } else if ($ instanceof $calendar.November) { - _block = 11; - } else { - _block = 12; - } - let month = _block; - return from_date_time( - date.year, - month, - date.day, - time.hours, - time.minutes, - time.seconds, - time.nanoseconds, - $float.round($duration.to_seconds(offset)), - ); -} - -/** - * Parses an [RFC 3339 formatted time string][spec] into a `Timestamp`. - * - * [spec]: https://datatracker.ietf.org/doc/html/rfc3339#section-5.6 - * - * # Examples - * - * ```gleam - * let assert Ok(ts) = timestamp.parse_rfc3339("1970-01-01T00:00:01Z") - * timestamp.to_unix_seconds_and_nanoseconds(ts) - * // -> #(1, 0) - * ``` - * - * Parsing an invalid timestamp returns an error. - * - * ```gleam - * let assert Error(Nil) = timestamp.parse_rfc3339("1995-10-31") - * ``` - * - * ## Time zones - * - * It may at first seem that the RFC 3339 format includes timezone - * information, as it can specify an offset such as `Z` or `+3`, so why does - * this function not return calendar time with a time zone? There are multiple - * reasons: - * - * - RFC 3339's timestamp format is based on calendar time, but it is - * unambigous, so it can be converted into epoch time when being parsed. It - * is always better to internally use epoch time to represent unambiguous - * points in time, so we perform that conversion as a convenience and to - * ensure that programmers with less time experience don't accidentally use - * a less suitable time representation. - * - * - RFC 3339's contains _calendar time offset_ information, not time zone - * information. This is enough to convert it to an unambiguous timestamp, - * but it is not enough information to reliably work with calendar time. - * Without the time zone and the time zone database it's not possible to - * know what time period that offset is valid for, so it cannot be used - * without risk of bugs. - * - * ## Behaviour details - * - * - Follows the grammar specified in section 5.6 Internet Date/Time Format of - * RFC 3339 . - * - The `T` and `Z` characters may alternatively be lower case `t` or `z`, - * respectively. - * - Full dates and full times must be separated by `T` or `t`. A space is also - * permitted. - * - Leap seconds rules are not considered. That is, any timestamp may - * specify digts `00` - `60` for the seconds. - * - Any part of a fractional second that cannot be represented in the - * nanosecond precision is tructated. That is, for the time string, - * `"1970-01-01T00:00:00.1234567899Z"`, the fractional second `.1234567899` - * will be represented as `123_456_789` in the `Timestamp`. - */ -export function parse_rfc3339(input) { - let bytes = $bit_array.from_string(input); - return $result.try$( - parse_year(bytes), - (_use0) => { - let year; - let bytes$1; - year = _use0[0]; - bytes$1 = _use0[1]; - return $result.try$( - accept_byte(bytes$1, byte_minus), - (bytes) => { - return $result.try$( - parse_month(bytes), - (_use0) => { - let month; - let bytes$1; - month = _use0[0]; - bytes$1 = _use0[1]; - return $result.try$( - accept_byte(bytes$1, byte_minus), - (bytes) => { - return $result.try$( - parse_day(bytes, year, month), - (_use0) => { - let day; - let bytes$1; - day = _use0[0]; - bytes$1 = _use0[1]; - return $result.try$( - accept_date_time_separator(bytes$1), - (bytes) => { - return $result.try$( - parse_hours(bytes), - (_use0) => { - let hours; - let bytes$1; - hours = _use0[0]; - bytes$1 = _use0[1]; - return $result.try$( - accept_byte(bytes$1, byte_colon), - (bytes) => { - return $result.try$( - parse_minutes(bytes), - (_use0) => { - let minutes; - let bytes$1; - minutes = _use0[0]; - bytes$1 = _use0[1]; - return $result.try$( - accept_byte(bytes$1, byte_colon), - (bytes) => { - return $result.try$( - parse_seconds(bytes), - (_use0) => { - let seconds; - let bytes$1; - seconds = _use0[0]; - bytes$1 = _use0[1]; - return $result.try$( - parse_second_fraction_as_nanoseconds( - bytes$1, - ), - (_use0) => { - let second_fraction_as_nanoseconds; - let bytes$2; - second_fraction_as_nanoseconds = _use0[0]; - bytes$2 = _use0[1]; - return $result.try$( - parse_offset(bytes$2), - (_use0) => { - let offset_seconds; - let bytes$3; - offset_seconds = _use0[0]; - bytes$3 = _use0[1]; - return $result.try$( - accept_empty(bytes$3), - (_use0) => { - - return new Ok( - from_date_time( - year, - month, - day, - hours, - minutes, - seconds, - second_fraction_as_nanoseconds, - offset_seconds, - ), - ); - }, - ); - }, - ); - }, - ); - }, - ); - }, - ); - }, - ); - }, - ); - }, - ); - }, - ); - }, - ); - }, - ); - }, - ); - }, - ); - }, - ); -} - -/** - * The epoch of Unix time, which is 00:00:00 UTC on 1 January 1970. - */ -export const unix_epoch = /* @__PURE__ */ new Timestamp(0, 0); diff --git a/build/dev/javascript/gleam_time/gleam@time@calendar.erl b/build/dev/javascript/gleam_time/gleam@time@calendar.erl deleted file mode 100644 index e295d09..0000000 --- a/build/dev/javascript/gleam_time/gleam@time@calendar.erl +++ /dev/null @@ -1,468 +0,0 @@ --module(gleam@time@calendar). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "src/gleam/time/calendar.gleam"). --export([local_offset/0, month_to_string/1, month_to_int/1, month_from_int/1, is_leap_year/1, is_valid_date/1, is_valid_time_of_day/1, naive_date_compare/2]). --export_type([date/0, time_of_day/0, month/0]). - --if(?OTP_RELEASE >= 27). --define(MODULEDOC(Str), -moduledoc(Str)). --define(DOC(Str), -doc(Str)). --else. --define(MODULEDOC(Str), -compile([])). --define(DOC(Str), -compile([])). --endif. - -?MODULEDOC( - " This module is for working with the Gregorian calendar, established by\n" - " Pope Gregory XIII in 1582!\n" - "\n" - " ## When should you use this module?\n" - "\n" - " > **tldr:** You probably want to use [`gleam/time/timestamp`](./timestamp.html)\n" - " > instead!\n" - "\n" - " Calendar time is difficult to work with programmatically, it is the source\n" - " of most time-related bugs in software. Compared to _epoch time_, which the\n" - " `gleam/time/timestamp` module uses, there are many disadvantages to\n" - " calendar time:\n" - "\n" - " - They are ambiguous if you don't know what time-zone is being used.\n" - "\n" - " - A time-zone database is required to understand calendar time even when\n" - " you have the time zone. These are large and your program has to\n" - " continously be updated as new versions of the database are published.\n" - "\n" - " - The type permits invalid states. e.g. `days` could be set to the number\n" - " 32, but this should not be possible!\n" - "\n" - " - There is not a single unique canonical value for each point in time,\n" - " thanks to time zones. Two different `Date` + `TimeOfDay` value pairs\n" - " could represent the same point in time. This means that you can't check\n" - " for time equality with `==` when using calendar types.\n" - "\n" - " - They are computationally complex, using a more memory to represent and\n" - " requiring a lot more CPU time to manipulate.\n" - "\n" - " There are also advantages to calendar time:\n" - "\n" - " - Calendar time is how human's talk about time, so if you want to show a\n" - " time or take a time from a human user then calendar time will make it\n" - " easier for them.\n" - "\n" - " - They can represent more abstract time periods such as \"New Year's Day\".\n" - " This may seem like an exact window of time at first, but really the\n" - " definition of \"New Year's Day\" is more fuzzy than that. When it starts\n" - " and ends will depend where in the world you are, so if you want to refer\n" - " to a day as a global concept instead of a fixed window of time for that\n" - " day in a specific location, then calendar time can represent that.\n" - "\n" - " So when should you use calendar time? These are our recommendations:\n" - "\n" - " - Default to `gleam/time/timestamp`, which is epoch time. It is\n" - " unambiguous, efficient, and significantly less likely to result in logic\n" - " bugs.\n" - "\n" - " - When writing time to a database or other data storage use epoch time,\n" - " using whatever epoch format it supports. For example, PostgreSQL\n" - " `timestamp` and `timestampz` are both epoch time, and `timestamp` is\n" - " preferred as it is more straightforward to use as your application is\n" - " also using epoch time.\n" - "\n" - " - When communicating with other computer systems continue to use epoch\n" - " time. For example, when sending times to another program you could\n" - " encode time as UNIX timestamps (seconds since 00:00:00 UTC on 1 January\n" - " 1970).\n" - "\n" - " - When communicating with humans use epoch time internally, and convert\n" - " to-and-from calendar time at the last moment, when iteracting with the\n" - " human user. It may also help the users to also show the time as a fuzzy\n" - " duration from the present time, such as \"about 4 days ago\".\n" - "\n" - " - When representing \"fuzzy\" human time concepts that don't exact periods\n" - " in time, such as \"one month\" (varies depending on which month, which\n" - " year, and in which time zone) and \"Christmas Day\" (varies depending on\n" - " which year and time zone) then use calendar time.\n" - "\n" - " Any time you do use calendar time you should be extra careful! It is very\n" - " easy to make mistake with. Avoid it where possible.\n" - "\n" - " ## Time zone offsets\n" - "\n" - " This package includes the `utc_offset` value and the `local_offset`\n" - " function, which are the offset for the UTC time zone and get the time\n" - " offset the computer running the program is configured to respectively.\n" - "\n" - " If you need to use other offsets in your program then you will need to get\n" - " them from somewhere else, such as from a package which loads the\n" - " [IANA Time Zone Database](https://www.iana.org/time-zones), or from the\n" - " website visitor's web browser, which your frontend can send for you.\n" - "\n" - " ## Use in APIs\n" - "\n" - " If you are making an API such as a HTTP JSON API you are encouraged to use\n" - " Unix timestamps instead of calendar times.\n" -). - --type date() :: {date, integer(), month(), integer()}. - --type time_of_day() :: {time_of_day, integer(), integer(), integer(), integer()}. - --type month() :: january | - february | - march | - april | - may | - june | - july | - august | - september | - october | - november | - december. - --file("src/gleam/time/calendar.gleam", 147). -?DOC( - " Get the offset for the computer's currently configured time zone.\n" - "\n" - " Note this may not be the time zone that is correct to use for your user.\n" - " For example, if you are making a web application that runs on a server you\n" - " want _their_ computer's time zone, not yours.\n" - "\n" - " This is the _current local_ offset, not the current local time zone. This\n" - " means that while it will result in the expected outcome for the current\n" - " time, it may result in unexpected output if used with other timestamps. For\n" - " example: a timestamp that would locally be during daylight savings time if\n" - " is it not currently daylight savings time when this function is called.\n" -). --spec local_offset() -> gleam@time@duration:duration(). -local_offset() -> - gleam@time@duration:seconds(gleam_time_ffi:local_time_offset_seconds()). - --file("src/gleam/time/calendar.gleam", 163). -?DOC( - " Returns the English name for a month.\n" - "\n" - " # Examples\n" - "\n" - " ```gleam\n" - " month_to_string(April)\n" - " // -> \"April\"\n" - " ```\n" -). --spec month_to_string(month()) -> binary(). -month_to_string(Month) -> - case Month of - january -> - <<"January"/utf8>>; - - february -> - <<"February"/utf8>>; - - march -> - <<"March"/utf8>>; - - april -> - <<"April"/utf8>>; - - may -> - <<"May"/utf8>>; - - june -> - <<"June"/utf8>>; - - july -> - <<"July"/utf8>>; - - august -> - <<"August"/utf8>>; - - september -> - <<"September"/utf8>>; - - october -> - <<"October"/utf8>>; - - november -> - <<"November"/utf8>>; - - december -> - <<"December"/utf8>> - end. - --file("src/gleam/time/calendar.gleam", 188). -?DOC( - " Returns the number for the month, where January is 1 and December is 12.\n" - "\n" - " # Examples\n" - "\n" - " ```gleam\n" - " month_to_int(January)\n" - " // -> 1\n" - " ```\n" -). --spec month_to_int(month()) -> integer(). -month_to_int(Month) -> - case Month of - january -> - 1; - - february -> - 2; - - march -> - 3; - - april -> - 4; - - may -> - 5; - - june -> - 6; - - july -> - 7; - - august -> - 8; - - september -> - 9; - - october -> - 10; - - november -> - 11; - - december -> - 12 - end. - --file("src/gleam/time/calendar.gleam", 213). -?DOC( - " Returns the month for a given number, where January is 1 and December is 12.\n" - "\n" - " # Examples\n" - "\n" - " ```gleam\n" - " month_from_int(1)\n" - " // -> Ok(January)\n" - " ```\n" -). --spec month_from_int(integer()) -> {ok, month()} | {error, nil}. -month_from_int(Month) -> - case Month of - 1 -> - {ok, january}; - - 2 -> - {ok, february}; - - 3 -> - {ok, march}; - - 4 -> - {ok, april}; - - 5 -> - {ok, may}; - - 6 -> - {ok, june}; - - 7 -> - {ok, july}; - - 8 -> - {ok, august}; - - 9 -> - {ok, september}; - - 10 -> - {ok, october}; - - 11 -> - {ok, november}; - - 12 -> - {ok, december}; - - _ -> - {error, nil} - end. - --file("src/gleam/time/calendar.gleam", 290). -?DOC( - " Determines if a given year is a leap year.\n" - "\n" - " A leap year occurs every 4 years, except for years divisible by 100,\n" - " unless they are also divisible by 400.\n" - "\n" - " # Examples\n" - "\n" - " ```gleam\n" - " is_leap_year(2024)\n" - " // -> True\n" - " ```\n" - "\n" - " ```gleam\n" - " is_leap_year(2023)\n" - " // -> False\n" - " ```\n" -). --spec is_leap_year(integer()) -> boolean(). -is_leap_year(Year) -> - case (Year rem 400) =:= 0 of - true -> - true; - - false -> - case (Year rem 100) =:= 0 of - true -> - false; - - false -> - (Year rem 4) =:= 0 - end - end. - --file("src/gleam/time/calendar.gleam", 254). -?DOC( - " Checks if a given date is valid.\n" - "\n" - " This function properly accounts for leap years when validating February days.\n" - " A leap year occurs every 4 years, except for years divisible by 100,\n" - " unless they are also divisible by 400.\n" - "\n" - " # Examples\n" - "\n" - " ```gleam\n" - " is_valid_date(Date(2023, April, 15))\n" - " // -> True\n" - " ```\n" - "\n" - " ```gleam\n" - " is_valid_date(Date(2023, April, 31))\n" - " // -> False\n" - " ```\n" - "\n" - " ```gleam\n" - " is_valid_date(Date(2024, February, 29))\n" - " // -> True (2024 is a leap year)\n" - " ```\n" -). --spec is_valid_date(date()) -> boolean(). -is_valid_date(Date) -> - {date, Year, Month, Day} = Date, - case Day < 1 of - true -> - false; - - false -> - case Month of - january -> - Day =< 31; - - march -> - Day =< 31; - - may -> - Day =< 31; - - july -> - Day =< 31; - - august -> - Day =< 31; - - october -> - Day =< 31; - - december -> - Day =< 31; - - april -> - Day =< 30; - - june -> - Day =< 30; - - september -> - Day =< 30; - - november -> - Day =< 30; - - february -> - Max_february_days = case is_leap_year(Year) of - true -> - 29; - - false -> - 28 - end, - Day =< Max_february_days - end - end. - --file("src/gleam/time/calendar.gleam", 313). -?DOC( - " Checks if a time of day is valid.\n" - "\n" - " Validates that hours are 0-23, minutes are 0-59, seconds are 0-59,\n" - " and nanoseconds are 0-999,999,999.\n" - "\n" - " # Examples\n" - "\n" - " ```gleam\n" - " is_valid_time_of_day(TimeOfDay(12, 30, 45, 123456789))\n" - " // -> True\n" - " ```\n" -). --spec is_valid_time_of_day(time_of_day()) -> boolean(). -is_valid_time_of_day(Time) -> - {time_of_day, Hours, Minutes, Seconds, Nanoseconds} = Time, - (((((((Hours >= 0) andalso (Hours =< 23)) andalso (Minutes >= 0)) andalso (Minutes - =< 59)) - andalso (Seconds >= 0)) - andalso (Seconds =< 59)) - andalso (Nanoseconds >= 0)) - andalso (Nanoseconds =< 999999999). - --file("src/gleam/time/calendar.gleam", 340). -?DOC( - " Naively compares two dates without any time zone information, returning an\n" - " order.\n" - "\n" - " ## Correctness\n" - "\n" - " This function compares dates without any time zone information, only using\n" - " the rules for the gregorian calendar. This is typically sufficient, but be\n" - " aware that in reality some time zones will change their calendar date\n" - " occasionally. This can result in days being skipped, out of order, or\n" - " happening multiple times.\n" - "\n" - " If you need real-world correct time ordering then use the\n" - " `gleam/time/timestamp` module instead.\n" -). --spec naive_date_compare(date(), date()) -> gleam@order:order(). -naive_date_compare(One, Other) -> - _pipe = gleam@int:compare(erlang:element(2, One), erlang:element(2, Other)), - _pipe@1 = gleam@order:lazy_break_tie( - _pipe, - fun() -> - gleam@int:compare( - month_to_int(erlang:element(3, One)), - month_to_int(erlang:element(3, Other)) - ) - end - ), - gleam@order:lazy_break_tie( - _pipe@1, - fun() -> - gleam@int:compare(erlang:element(4, One), erlang:element(4, Other)) - end - ). diff --git a/build/dev/javascript/gleam_time/gleam@time@duration.erl b/build/dev/javascript/gleam_time/gleam@time@duration.erl deleted file mode 100644 index 7ba7ad2..0000000 --- a/build/dev/javascript/gleam_time/gleam@time@duration.erl +++ /dev/null @@ -1,381 +0,0 @@ --module(gleam@time@duration). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "src/gleam/time/duration.gleam"). --export([approximate/1, compare/2, difference/2, add/2, seconds/1, minutes/1, hours/1, milliseconds/1, nanoseconds/1, to_seconds/1, to_seconds_and_nanoseconds/1, to_iso8601_string/1]). --export_type([duration/0, unit/0]). - --if(?OTP_RELEASE >= 27). --define(MODULEDOC(Str), -moduledoc(Str)). --define(DOC(Str), -doc(Str)). --else. --define(MODULEDOC(Str), -compile([])). --define(DOC(Str), -compile([])). --endif. - --opaque duration() :: {duration, integer(), integer()}. - --type unit() :: nanosecond | - microsecond | - millisecond | - second | - minute | - hour | - day | - week | - month | - year. - --file("src/gleam/time/duration.gleam", 110). -?DOC( - " Ensure the duration is represented with `nanoseconds` being positive and\n" - " less than 1 second.\n" - "\n" - " This function does not change the amount of time that the duratoin refers\n" - " to, it only adjusts the values used to represent the time.\n" -). --spec normalise(duration()) -> duration(). -normalise(Duration) -> - Multiplier = 1000000000, - Nanoseconds = case Multiplier of - 0 -> 0; - Gleam@denominator -> erlang:element(3, Duration) rem Gleam@denominator - end, - Overflow = erlang:element(3, Duration) - Nanoseconds, - Seconds = erlang:element(2, Duration) + (case Multiplier of - 0 -> 0; - Gleam@denominator@1 -> Overflow div Gleam@denominator@1 - end), - case Nanoseconds >= 0 of - true -> - {duration, Seconds, Nanoseconds}; - - false -> - {duration, Seconds - 1, Multiplier + Nanoseconds} - end. - --file("src/gleam/time/duration.gleam", 76). -?DOC( - " Convert a duration to a number of the largest number of a unit, serving as\n" - " a rough description of the duration that a human can understand.\n" - "\n" - " The size used for each unit are described in the documentation for the\n" - " `Unit` type.\n" - "\n" - " ```gleam\n" - " seconds(125)\n" - " |> approximate\n" - " // -> #(2, Minute)\n" - " ```\n" - "\n" - " This function rounds _towards zero_. This means that if a duration is just\n" - " short of 2 days then it will approximate to 1 day.\n" - "\n" - " ```gleam\n" - " hours(47)\n" - " |> approximate\n" - " // -> #(1, Day)\n" - " ```\n" -). --spec approximate(duration()) -> {integer(), unit()}. -approximate(Duration) -> - {duration, S, Ns} = Duration, - Minute = 60, - Hour = Minute * 60, - Day = Hour * 24, - Week = Day * 7, - Year = (Day * 365) + (Hour * 6), - Month = Year div 12, - Microsecond = 1000, - Millisecond = Microsecond * 1000, - case nil of - _ when S < 0 -> - {Amount, Unit} = begin - _pipe = {duration, - S, - Ns}, - _pipe@1 = normalise(_pipe), - approximate(_pipe@1) - end, - {- Amount, Unit}; - - _ when S >= Year -> - {case Year of - 0 -> 0; - Gleam@denominator -> S div Gleam@denominator - end, year}; - - _ when S >= Month -> - {case Month of - 0 -> 0; - Gleam@denominator@1 -> S div Gleam@denominator@1 - end, month}; - - _ when S >= Week -> - {case Week of - 0 -> 0; - Gleam@denominator@2 -> S div Gleam@denominator@2 - end, week}; - - _ when S >= Day -> - {case Day of - 0 -> 0; - Gleam@denominator@3 -> S div Gleam@denominator@3 - end, day}; - - _ when S >= Hour -> - {case Hour of - 0 -> 0; - Gleam@denominator@4 -> S div Gleam@denominator@4 - end, hour}; - - _ when S >= Minute -> - {case Minute of - 0 -> 0; - Gleam@denominator@5 -> S div Gleam@denominator@5 - end, minute}; - - _ when S > 0 -> - {S, second}; - - _ when Ns >= Millisecond -> - {case Millisecond of - 0 -> 0; - Gleam@denominator@6 -> Ns div Gleam@denominator@6 - end, millisecond}; - - _ when Ns >= Microsecond -> - {case Microsecond of - 0 -> 0; - Gleam@denominator@7 -> Ns div Gleam@denominator@7 - end, microsecond}; - - _ -> - {Ns, nanosecond} - end. - --file("src/gleam/time/duration.gleam", 140). -?DOC( - " Compare one duration to another, indicating whether the first spans a\n" - " larger amount of time (and so is greater) or smaller amount of time (and so\n" - " is lesser) than the second.\n" - "\n" - " # Examples\n" - "\n" - " ```gleam\n" - " compare(seconds(1), seconds(2))\n" - " // -> order.Lt\n" - " ```\n" - "\n" - " Whether a duration is negative or positive doesn't matter for comparing\n" - " them, only the amount of time spanned matters.\n" - "\n" - " ```gleam\n" - " compare(seconds(-2), seconds(1))\n" - " // -> order.Gt\n" - " ```\n" -). --spec compare(duration(), duration()) -> gleam@order:order(). -compare(Left, Right) -> - Parts = fun(X) -> case erlang:element(2, X) >= 0 of - true -> - {erlang:element(2, X), erlang:element(3, X)}; - - false -> - {(erlang:element(2, X) * -1) - 1, - 1000000000 - erlang:element(3, X)} - end end, - {Ls, Lns} = Parts(Left), - {Rs, Rns} = Parts(Right), - _pipe = gleam@int:compare(Ls, Rs), - gleam@order:break_tie(_pipe, gleam@int:compare(Lns, Rns)). - --file("src/gleam/time/duration.gleam", 164). -?DOC( - " Calculate the difference between two durations.\n" - "\n" - " This is effectively substracting the first duration from the second.\n" - "\n" - " # Examples\n" - "\n" - " ```gleam\n" - " difference(seconds(1), seconds(5))\n" - " // -> seconds(4)\n" - " ```\n" -). --spec difference(duration(), duration()) -> duration(). -difference(Left, Right) -> - _pipe = {duration, - erlang:element(2, Right) - erlang:element(2, Left), - erlang:element(3, Right) - erlang:element(3, Left)}, - normalise(_pipe). - --file("src/gleam/time/duration.gleam", 178). -?DOC( - " Add two durations together.\n" - "\n" - " # Examples\n" - "\n" - " ```gleam\n" - " add(seconds(1), seconds(5))\n" - " // -> seconds(6)\n" - " ```\n" -). --spec add(duration(), duration()) -> duration(). -add(Left, Right) -> - _pipe = {duration, - erlang:element(2, Left) + erlang:element(2, Right), - erlang:element(3, Left) + erlang:element(3, Right)}, - normalise(_pipe). - --file("src/gleam/time/duration.gleam", 225). --spec nanosecond_digits(integer(), integer(), binary()) -> binary(). -nanosecond_digits(N, Position, Acc) -> - case Position of - 9 -> - Acc; - - _ when (Acc =:= <<""/utf8>>) andalso ((N rem 10) =:= 0) -> - nanosecond_digits(N div 10, Position + 1, Acc); - - _ -> - Acc@1 = <<(erlang:integer_to_binary(N rem 10))/binary, Acc/binary>>, - nanosecond_digits(N div 10, Position + 1, Acc@1) - end. - --file("src/gleam/time/duration.gleam", 239). -?DOC(" Create a duration of a number of seconds.\n"). --spec seconds(integer()) -> duration(). -seconds(Amount) -> - {duration, Amount, 0}. - --file("src/gleam/time/duration.gleam", 244). -?DOC(" Create a duration of a number of minutes.\n"). --spec minutes(integer()) -> duration(). -minutes(Amount) -> - seconds(Amount * 60). - --file("src/gleam/time/duration.gleam", 249). -?DOC(" Create a duration of a number of hours.\n"). --spec hours(integer()) -> duration(). -hours(Amount) -> - seconds((Amount * 60) * 60). - --file("src/gleam/time/duration.gleam", 254). -?DOC(" Create a duration of a number of milliseconds.\n"). --spec milliseconds(integer()) -> duration(). -milliseconds(Amount) -> - Remainder = Amount rem 1000, - Overflow = Amount - Remainder, - Nanoseconds = Remainder * 1000000, - Seconds = Overflow div 1000, - _pipe = {duration, Seconds, Nanoseconds}, - normalise(_pipe). - --file("src/gleam/time/duration.gleam", 273). -?DOC( - " Create a duration of a number of nanoseconds.\n" - "\n" - " # JavaScript int limitations\n" - "\n" - " Remember that JavaScript can only perfectly represent ints between positive\n" - " and negative 9,007,199,254,740,991! If you use a single call to this\n" - " function to create durations larger than that number of nanoseconds then\n" - " you will likely not get exactly the value you expect. Use `seconds` and\n" - " `milliseconds` as much as possible for large durations.\n" -). --spec nanoseconds(integer()) -> duration(). -nanoseconds(Amount) -> - _pipe = {duration, 0, Amount}, - normalise(_pipe). - --file("src/gleam/time/duration.gleam", 283). -?DOC( - " Convert the duration to a number of seconds.\n" - "\n" - " There may be some small loss of precision due to `Duration` being\n" - " nanosecond accurate and `Float` not being able to represent this.\n" -). --spec to_seconds(duration()) -> float(). -to_seconds(Duration) -> - Seconds = erlang:float(erlang:element(2, Duration)), - Nanoseconds = erlang:float(erlang:element(3, Duration)), - Seconds + (Nanoseconds / 1000000000.0). - --file("src/gleam/time/duration.gleam", 292). -?DOC( - " Convert the duration to a number of seconds and nanoseconds. There is no\n" - " loss of precision with this conversion on any target.\n" -). --spec to_seconds_and_nanoseconds(duration()) -> {integer(), integer()}. -to_seconds_and_nanoseconds(Duration) -> - {erlang:element(2, Duration), erlang:element(3, Duration)}. - --file("src/gleam/time/duration.gleam", 192). -?DOC( - " Convert the duration to an [ISO8601][1] formatted duration string.\n" - "\n" - " The ISO8601 duration format is ambiguous without context due to months and\n" - " years having different lengths, and because of leap seconds. This function\n" - " encodes the duration as days, hours, and seconds without any leap seconds.\n" - " Be sure to take this into account when using the duration strings.\n" - "\n" - " [1]: https://en.wikipedia.org/wiki/ISO_8601#Durations\n" -). --spec to_iso8601_string(duration()) -> binary(). -to_iso8601_string(Duration) -> - gleam@bool:guard( - Duration =:= {duration, 0, 0}, - <<"PT0S"/utf8>>, - fun() -> - Split = fun(Total, Limit) -> - Amount = case Limit of - 0 -> 0; - Gleam@denominator -> Total rem Gleam@denominator - end, - Remainder = case Limit of - 0 -> 0; - Gleam@denominator@1 -> (Total - Amount) div Gleam@denominator@1 - end, - {Amount, Remainder} - end, - {Seconds, Rest} = Split(erlang:element(2, Duration), 60), - {Minutes, Rest@1} = Split(Rest, 60), - {Hours, Rest@2} = Split(Rest@1, 24), - Days = Rest@2, - Add = fun(Out, Value, Unit) -> case Value of - 0 -> - Out; - - _ -> - <<<>/binary, - Unit/binary>> - end end, - Output = begin - _pipe = <<"P"/utf8>>, - _pipe@1 = Add(_pipe, Days, <<"D"/utf8>>), - _pipe@2 = gleam@string:append(_pipe@1, <<"T"/utf8>>), - _pipe@3 = Add(_pipe@2, Hours, <<"H"/utf8>>), - Add(_pipe@3, Minutes, <<"M"/utf8>>) - end, - case {Seconds, erlang:element(3, Duration)} of - {0, 0} -> - Output; - - {_, 0} -> - <<<>/binary, - "S"/utf8>>; - - {_, _} -> - F = nanosecond_digits( - erlang:element(3, Duration), - 0, - <<""/utf8>> - ), - <<<<<<<>/binary, - "."/utf8>>/binary, - F/binary>>/binary, - "S"/utf8>> - end - end - ). diff --git a/build/dev/javascript/gleam_time/gleam@time@timestamp.erl b/build/dev/javascript/gleam_time/gleam@time@timestamp.erl deleted file mode 100644 index 0d7413a..0000000 --- a/build/dev/javascript/gleam_time/gleam@time@timestamp.erl +++ /dev/null @@ -1,1188 +0,0 @@ --module(gleam@time@timestamp). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "src/gleam/time/timestamp.gleam"). --export([compare/2, system_time/0, difference/2, add/2, to_calendar/2, to_rfc3339/2, from_unix_seconds/1, from_unix_seconds_and_nanoseconds/2, to_unix_seconds/1, to_unix_seconds_and_nanoseconds/1, from_calendar/3, parse_rfc3339/1]). --export_type([timestamp/0]). - --if(?OTP_RELEASE >= 27). --define(MODULEDOC(Str), -moduledoc(Str)). --define(DOC(Str), -doc(Str)). --else. --define(MODULEDOC(Str), -compile([])). --define(DOC(Str), -compile([])). --endif. - -?MODULEDOC( - " Welcome to the timestamp module! This module and its `Timestamp` type are\n" - " what you will be using most commonly when working with time in Gleam.\n" - "\n" - " A timestamp represents a moment in time, represented as an amount of time\n" - " since the calendar time 00:00:00 UTC on 1 January 1970, also known as the\n" - " _Unix epoch_.\n" - "\n" - " # Wall clock time and monotonicity\n" - "\n" - " Time is very complicated, especially on computers! While they generally do\n" - " a good job of keeping track of what the time is, computers can get\n" - " out-of-sync and start to report a time that is too late or too early. Most\n" - " computers use \"network time protocol\" to tell each other what they think\n" - " the time is, and computers that realise they are running too fast or too\n" - " slow will adjust their clock to correct it. When this happens it can seem\n" - " to your program that the current time has changed, and it may have even\n" - " jumped backwards in time!\n" - "\n" - " This measure of time is called _wall clock time_, and it is what people\n" - " commonly think of when they think of time. It is important to be aware that\n" - " it can go backwards, and your program must not rely on it only ever going\n" - " forwards at a steady rate. For example, for tracking what order events happen\n" - " in. \n" - "\n" - " This module uses wall clock time. If your program needs time values to always\n" - " increase you will need a _monotonic_ time instead. It's uncommon that you\n" - " would need monotonic time, one example might be if you're making a\n" - " benchmarking framework.\n" - "\n" - " The exact way that time works will depend on what runtime you use. The\n" - " Erlang documentation on time has a lot of detail about time generally as well\n" - " as how it works on the BEAM, it is worth reading.\n" - " .\n" - "\n" - " # Converting to local calendar time\n" - "\n" - " Timestamps don't take into account time zones, so a moment in time will\n" - " have the same timestamp value regardless of where you are in the world. To\n" - " convert them to local time you will need to know the offset for the time\n" - " zone you wish to use, likely from a time zone database. See the\n" - " `gleam/time/calendar` module for more information.\n" - "\n" -). - --opaque timestamp() :: {timestamp, integer(), integer()}. - --file("src/gleam/time/timestamp.gleam", 119). -?DOC( - " Ensure the time is represented with `nanoseconds` being positive and less\n" - " than 1 second.\n" - "\n" - " This function does not change the time that the timestamp refers to, it\n" - " only adjusts the values used to represent the time.\n" -). --spec normalise(timestamp()) -> timestamp(). -normalise(Timestamp) -> - Multiplier = 1000000000, - Nanoseconds = case Multiplier of - 0 -> 0; - Gleam@denominator -> erlang:element(3, Timestamp) rem Gleam@denominator - end, - Overflow = erlang:element(3, Timestamp) - Nanoseconds, - Seconds = erlang:element(2, Timestamp) + (case Multiplier of - 0 -> 0; - Gleam@denominator@1 -> Overflow div Gleam@denominator@1 - end), - case Nanoseconds >= 0 of - true -> - {timestamp, Seconds, Nanoseconds}; - - false -> - {timestamp, Seconds - 1, Multiplier + Nanoseconds} - end. - --file("src/gleam/time/timestamp.gleam", 141). -?DOC( - " Compare one timestamp to another, indicating whether the first is further\n" - " into the future (greater) or further into the past (lesser) than the\n" - " second.\n" - "\n" - " # Examples\n" - "\n" - " ```gleam\n" - " compare(from_unix_seconds(1), from_unix_seconds(2))\n" - " // -> order.Lt\n" - " ```\n" -). --spec compare(timestamp(), timestamp()) -> gleam@order:order(). -compare(Left, Right) -> - gleam@order:break_tie( - gleam@int:compare(erlang:element(2, Left), erlang:element(2, Right)), - gleam@int:compare(erlang:element(3, Left), erlang:element(3, Right)) - ). - --file("src/gleam/time/timestamp.gleam", 160). -?DOC( - " Get the current system time.\n" - "\n" - " Note this time is not unique or monotonic, it could change at any time or\n" - " even go backwards! The exact behaviour will depend on the runtime used. See\n" - " the module documentation for more information.\n" - "\n" - " On Erlang this uses [`erlang:system_time/1`][1]. On JavaScript this uses\n" - " [`Date.now`][2].\n" - "\n" - " [1]: https://www.erlang.org/doc/apps/erts/erlang#system_time/1\n" - " [2]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/now\n" -). --spec system_time() -> timestamp(). -system_time() -> - {Seconds, Nanoseconds} = gleam_time_ffi:system_time(), - normalise({timestamp, Seconds, Nanoseconds}). - --file("src/gleam/time/timestamp.gleam", 180). -?DOC( - " Calculate the difference between two timestamps.\n" - "\n" - " This is effectively substracting the first timestamp from the second.\n" - "\n" - " # Examples\n" - "\n" - " ```gleam\n" - " difference(from_unix_seconds(1), from_unix_seconds(5))\n" - " // -> duration.seconds(4)\n" - " ```\n" -). --spec difference(timestamp(), timestamp()) -> gleam@time@duration:duration(). -difference(Left, Right) -> - Seconds = gleam@time@duration:seconds( - erlang:element(2, Right) - erlang:element(2, Left) - ), - Nanoseconds = gleam@time@duration:nanoseconds( - erlang:element(3, Right) - erlang:element(3, Left) - ), - gleam@time@duration:add(Seconds, Nanoseconds). - --file("src/gleam/time/timestamp.gleam", 195). -?DOC( - " Add a duration to a timestamp.\n" - "\n" - " # Examples\n" - "\n" - " ```gleam\n" - " add(from_unix_seconds(1000), duration.seconds(5))\n" - " // -> from_unix_seconds(1005)\n" - " ```\n" -). --spec add(timestamp(), gleam@time@duration:duration()) -> timestamp(). -add(Timestamp, Duration) -> - {Seconds, Nanoseconds} = gleam@time@duration:to_seconds_and_nanoseconds( - Duration - ), - _pipe = {timestamp, - erlang:element(2, Timestamp) + Seconds, - erlang:element(3, Timestamp) + Nanoseconds}, - normalise(_pipe). - --file("src/gleam/time/timestamp.gleam", 262). --spec pad_digit(integer(), integer()) -> binary(). -pad_digit(Digit, Desired_length) -> - _pipe = erlang:integer_to_binary(Digit), - gleam@string:pad_start(_pipe, Desired_length, <<"0"/utf8>>). - --file("src/gleam/time/timestamp.gleam", 308). --spec duration_to_minutes(gleam@time@duration:duration()) -> integer(). -duration_to_minutes(Duration) -> - erlang:round(gleam@time@duration:to_seconds(Duration) / 60.0). - --file("src/gleam/time/timestamp.gleam", 370). --spec modulo(integer(), integer()) -> integer(). -modulo(N, M) -> - case gleam@int:modulo(N, M) of - {ok, N@1} -> - N@1; - - {error, _} -> - 0 - end. - --file("src/gleam/time/timestamp.gleam", 377). --spec floored_div(integer(), float()) -> integer(). -floored_div(Numerator, Denominator) -> - N = case Denominator of - +0.0 -> +0.0; - -0.0 -> -0.0; - Gleam@denominator -> erlang:float(Numerator) / Gleam@denominator - end, - erlang:round(math:floor(N)). - --file("src/gleam/time/timestamp.gleam", 383). --spec to_civil(integer()) -> {integer(), integer(), integer()}. -to_civil(Minutes) -> - Raw_day = floored_div(Minutes, (60.0 * 24.0)) + 719468, - Era = case Raw_day >= 0 of - true -> - Raw_day div 146097; - - false -> - (Raw_day - 146096) div 146097 - end, - Day_of_era = Raw_day - (Era * 146097), - Year_of_era = (((Day_of_era - (Day_of_era div 1460)) + (Day_of_era div 36524)) - - (Day_of_era div 146096)) - div 365, - Year = Year_of_era + (Era * 400), - Day_of_year = Day_of_era - (((365 * Year_of_era) + (Year_of_era div 4)) - (Year_of_era - div 100)), - Mp = ((5 * Day_of_year) + 2) div 153, - Month = case Mp < 10 of - true -> - Mp + 3; - - false -> - Mp - 9 - end, - Day = (Day_of_year - (((153 * Mp) + 2) div 5)) + 1, - Year@1 = case Month =< 2 of - true -> - Year + 1; - - false -> - Year - end, - {Year@1, Month, Day}. - --file("src/gleam/time/timestamp.gleam", 312). --spec to_calendar_from_offset(timestamp(), integer()) -> {integer(), - integer(), - integer(), - integer(), - integer(), - integer()}. -to_calendar_from_offset(Timestamp, Offset) -> - Total = erlang:element(2, Timestamp) + (Offset * 60), - Seconds = modulo(Total, 60), - Total_minutes = floored_div(Total, 60.0), - Minutes = modulo(Total, 60 * 60) div 60, - Hours = case (60 * 60) of - 0 -> 0; - Gleam@denominator -> modulo(Total, (24 * 60) * 60) div Gleam@denominator - end, - {Year, Month, Day} = to_civil(Total_minutes), - {Year, Month, Day, Hours, Minutes, Seconds}. - --file("src/gleam/time/timestamp.gleam", 281). -?DOC( - " Convert a `Timestamp` to calendar time, suitable for presenting to a human\n" - " to read.\n" - "\n" - " If you want a machine to use the time value then you should not use this\n" - " function and should instead keep it as a timestamp. See the documentation\n" - " for the `gleam/time/calendar` module for more information.\n" - "\n" - " # Examples\n" - "\n" - " ```gleam\n" - " timestamp.from_unix_seconds(0)\n" - " |> timestamp.to_calendar(calendar.utc_offset)\n" - " // -> #(Date(1970, January, 1), TimeOfDay(0, 0, 0, 0))\n" - " ```\n" -). --spec to_calendar(timestamp(), gleam@time@duration:duration()) -> {gleam@time@calendar:date(), - gleam@time@calendar:time_of_day()}. -to_calendar(Timestamp, Offset) -> - Offset@1 = duration_to_minutes(Offset), - {Year, Month, Day, Hours, Minutes, Seconds} = to_calendar_from_offset( - Timestamp, - Offset@1 - ), - Month@1 = case Month of - 1 -> - january; - - 2 -> - february; - - 3 -> - march; - - 4 -> - april; - - 5 -> - may; - - 6 -> - june; - - 7 -> - july; - - 8 -> - august; - - 9 -> - september; - - 10 -> - october; - - 11 -> - november; - - _ -> - december - end, - Nanoseconds = erlang:element(3, Timestamp), - Date = {date, Year, Month@1, Day}, - Time = {time_of_day, Hours, Minutes, Seconds, Nanoseconds}, - {Date, Time}. - --file("src/gleam/time/timestamp.gleam", 446). --spec do_remove_trailing_zeros(list(integer())) -> list(integer()). -do_remove_trailing_zeros(Reversed_digits) -> - case Reversed_digits of - [] -> - []; - - [Digit | Digits] when Digit =:= 0 -> - do_remove_trailing_zeros(Digits); - - Reversed_digits@1 -> - lists:reverse(Reversed_digits@1) - end. - --file("src/gleam/time/timestamp.gleam", 440). -?DOC(" Given a list of digits, return new list with any trailing zeros removed.\n"). --spec remove_trailing_zeros(list(integer())) -> list(integer()). -remove_trailing_zeros(Digits) -> - Reversed_digits = lists:reverse(Digits), - do_remove_trailing_zeros(Reversed_digits). - --file("src/gleam/time/timestamp.gleam", 461). --spec do_get_zero_padded_digits(integer(), list(integer()), integer()) -> list(integer()). -do_get_zero_padded_digits(Number, Digits, Count) -> - case Number of - Number@1 when (Number@1 =< 0) andalso (Count >= 9) -> - Digits; - - Number@2 when Number@2 =< 0 -> - do_get_zero_padded_digits(Number@2, [0 | Digits], Count + 1); - - Number@3 -> - Digit = Number@3 rem 10, - Number@4 = floored_div(Number@3, 10.0), - do_get_zero_padded_digits(Number@4, [Digit | Digits], Count + 1) - end. - --file("src/gleam/time/timestamp.gleam", 457). -?DOC( - " Returns the list of digits of `number`. If the number of digits is less \n" - " than 9, the result is zero-padded at the front.\n" -). --spec get_zero_padded_digits(integer()) -> list(integer()). -get_zero_padded_digits(Number) -> - do_get_zero_padded_digits(Number, [], 0). - --file("src/gleam/time/timestamp.gleam", 420). -?DOC( - " Converts nanoseconds into a `String` representation of fractional seconds.\n" - " \n" - " Assumes that `nanoseconds < 1_000_000_000`, which will be true for any \n" - " normalised timestamp.\n" -). --spec show_second_fraction(integer()) -> binary(). -show_second_fraction(Nanoseconds) -> - case gleam@int:compare(Nanoseconds, 0) of - lt -> - <<""/utf8>>; - - eq -> - <<""/utf8>>; - - gt -> - Second_fraction_part = begin - _pipe = Nanoseconds, - _pipe@1 = get_zero_padded_digits(_pipe), - _pipe@2 = remove_trailing_zeros(_pipe@1), - _pipe@3 = gleam@list:map( - _pipe@2, - fun erlang:integer_to_binary/1 - ), - gleam@string:join(_pipe@3, <<""/utf8>>) - end, - <<"."/utf8, Second_fraction_part/binary>> - end. - --file("src/gleam/time/timestamp.gleam", 240). -?DOC( - " Convert a timestamp to a RFC 3339 formatted time string, with an offset\n" - " supplied as an additional argument.\n" - "\n" - " The output of this function is also ISO 8601 compatible so long as the\n" - " offset not negative. Offsets have at-most minute precision, so an offset\n" - " with higher precision will be rounded to the nearest minute.\n" - "\n" - " If you are making an API such as a HTTP JSON API you are encouraged to use\n" - " Unix timestamps instead of this format or ISO 8601. Unix timestamps are a\n" - " better choice as they don't contain offset information. Consider:\n" - "\n" - " - UTC offsets are not time zones. This does not and cannot tell us the time\n" - " zone in which the date was recorded. So what are we supposed to do with\n" - " this information?\n" - " - Users typically want dates formatted according to their local time zone.\n" - " What if the provided UTC offset is different from the current user's time\n" - " zone? What are we supposed to do with it then?\n" - " - Despite it being useless (or worse, a source of bugs), the UTC offset\n" - " creates a larger payload to transfer.\n" - "\n" - " They also uses more memory than a unix timestamp. The way they are better\n" - " than Unix timestamp is that it is easier for a human to read them, but\n" - " this is a hinderance that tooling can remedy, and APIs are not primarily\n" - " for humans.\n" - "\n" - " # Examples\n" - "\n" - " ```gleam\n" - " timestamp.from_unix_seconds_and_nanoseconds(1000, 123_000_000)\n" - " |> to_rfc3339(calendar.utc_offset)\n" - " // -> \"1970-01-01T00:16:40.123Z\"\n" - " ```\n" - "\n" - " ```gleam\n" - " timestamp.from_unix_seconds(1000)\n" - " |> to_rfc3339(duration.seconds(3600))\n" - " // -> \"1970-01-01T01:16:40+01:00\"\n" - " ```\n" -). --spec to_rfc3339(timestamp(), gleam@time@duration:duration()) -> binary(). -to_rfc3339(Timestamp, Offset) -> - Offset@1 = duration_to_minutes(Offset), - {Years, Months, Days, Hours, Minutes, Seconds} = to_calendar_from_offset( - Timestamp, - Offset@1 - ), - Offset_minutes = modulo(Offset@1, 60), - Offset_hours = gleam@int:absolute_value(floored_div(Offset@1, 60.0)), - N2 = fun(_capture) -> pad_digit(_capture, 2) end, - N4 = fun(_capture@1) -> pad_digit(_capture@1, 4) end, - Out = <<""/utf8>>, - Out@1 = <<<<<<<<<>/binary, "-"/utf8>>/binary, - (N2(Months))/binary>>/binary, - "-"/utf8>>/binary, - (N2(Days))/binary>>, - Out@2 = <>, - Out@3 = <<<<<<<<<>/binary, ":"/utf8>>/binary, - (N2(Minutes))/binary>>/binary, - ":"/utf8>>/binary, - (N2(Seconds))/binary>>, - Out@4 = <>, - case gleam@int:compare(Offset@1, 0) of - eq -> - <>; - - gt -> - <<<<<<<>/binary, (N2(Offset_hours))/binary>>/binary, - ":"/utf8>>/binary, - (N2(Offset_minutes))/binary>>; - - lt -> - <<<<<<<>/binary, (N2(Offset_hours))/binary>>/binary, - ":"/utf8>>/binary, - (N2(Offset_minutes))/binary>> - end. - --file("src/gleam/time/timestamp.gleam", 611). --spec is_leap_year(integer()) -> boolean(). -is_leap_year(Year) -> - ((Year rem 4) =:= 0) andalso (((Year rem 100) /= 0) orelse ((Year rem 400) - =:= 0)). - --file("src/gleam/time/timestamp.gleam", 715). --spec parse_sign(bitstring()) -> {ok, {binary(), bitstring()}} | {error, nil}. -parse_sign(Bytes) -> - case Bytes of - <<"+"/utf8, Remaining_bytes/binary>> -> - {ok, {<<"+"/utf8>>, Remaining_bytes}}; - - <<"-"/utf8, Remaining_bytes@1/binary>> -> - {ok, {<<"-"/utf8>>, Remaining_bytes@1}}; - - _ -> - {error, nil} - end. - --file("src/gleam/time/timestamp.gleam", 762). -?DOC(" Accept the given value from `bytes` and move past it if found.\n"). --spec accept_byte(bitstring(), integer()) -> {ok, bitstring()} | {error, nil}. -accept_byte(Bytes, Value) -> - case Bytes of - <> when Byte =:= Value -> - {ok, Remaining_bytes}; - - _ -> - {error, nil} - end. - --file("src/gleam/time/timestamp.gleam", 780). --spec accept_empty(bitstring()) -> {ok, nil} | {error, nil}. -accept_empty(Bytes) -> - case Bytes of - <<>> -> - {ok, nil}; - - _ -> - {error, nil} - end. - --file("src/gleam/time/timestamp.gleam", 840). -?DOC( - " Note: It is the callers responsibility to ensure the inputs are valid.\n" - " \n" - " See https://www.tondering.dk/claus/cal/julperiod.php#formula\n" -). --spec julian_day_from_ymd(integer(), integer(), integer()) -> integer(). -julian_day_from_ymd(Year, Month, Day) -> - Adjustment = (14 - Month) div 12, - Adjusted_year = (Year + 4800) - Adjustment, - Adjusted_month = (Month + (12 * Adjustment)) - 3, - (((((Day + (((153 * Adjusted_month) + 2) div 5)) + (365 * Adjusted_year)) + (Adjusted_year - div 4)) - - (Adjusted_year div 100)) - + (Adjusted_year div 400)) - - 32045. - --file("src/gleam/time/timestamp.gleam", 859). -?DOC( - " Create a timestamp from a number of seconds since 00:00:00 UTC on 1 January\n" - " 1970.\n" -). --spec from_unix_seconds(integer()) -> timestamp(). -from_unix_seconds(Seconds) -> - {timestamp, Seconds, 0}. - --file("src/gleam/time/timestamp.gleam", 874). -?DOC( - " Create a timestamp from a number of seconds and nanoseconds since 00:00:00\n" - " UTC on 1 January 1970.\n" - "\n" - " # JavaScript int limitations\n" - "\n" - " Remember that JavaScript can only perfectly represent ints between positive\n" - " and negative 9,007,199,254,740,991! If you only use the nanosecond field\n" - " then you will almost certainly not get the date value you want due to this\n" - " loss of precision. Always use seconds primarily and then use nanoseconds\n" - " for the final sub-second adjustment.\n" -). --spec from_unix_seconds_and_nanoseconds(integer(), integer()) -> timestamp(). -from_unix_seconds_and_nanoseconds(Seconds, Nanoseconds) -> - _pipe = {timestamp, Seconds, Nanoseconds}, - normalise(_pipe). - --file("src/gleam/time/timestamp.gleam", 888). -?DOC( - " Convert the timestamp to a number of seconds since 00:00:00 UTC on 1\n" - " January 1970.\n" - "\n" - " There may be some small loss of precision due to `Timestamp` being\n" - " nanosecond accurate and `Float` not being able to represent this.\n" -). --spec to_unix_seconds(timestamp()) -> float(). -to_unix_seconds(Timestamp) -> - Seconds = erlang:float(erlang:element(2, Timestamp)), - Nanoseconds = erlang:float(erlang:element(3, Timestamp)), - Seconds + (Nanoseconds / 1000000000.0). - --file("src/gleam/time/timestamp.gleam", 897). -?DOC( - " Convert the timestamp to a number of seconds and nanoseconds since 00:00:00\n" - " UTC on 1 January 1970. There is no loss of precision with this conversion\n" - " on any target.\n" -). --spec to_unix_seconds_and_nanoseconds(timestamp()) -> {integer(), integer()}. -to_unix_seconds_and_nanoseconds(Timestamp) -> - {erlang:element(2, Timestamp), erlang:element(3, Timestamp)}. - --file("src/gleam/time/timestamp.gleam", 723). --spec offset_to_seconds(binary(), integer(), integer()) -> integer(). -offset_to_seconds(Sign, Hours, Minutes) -> - Abs_seconds = (Hours * 3600) + (Minutes * 60), - case Sign of - <<"-"/utf8>> -> - - Abs_seconds; - - _ -> - Abs_seconds - end. - --file("src/gleam/time/timestamp.gleam", 819). -?DOC( - " `julian_seconds_from_parts(year, month, day, hours, minutes, seconds)` \n" - " returns the number of Julian \n" - " seconds represented by the given arguments.\n" - " \n" - " Note: It is the callers responsibility to ensure the inputs are valid.\n" - " \n" - " See https://www.tondering.dk/claus/cal/julperiod.php#formula\n" -). --spec julian_seconds_from_parts( - integer(), - integer(), - integer(), - integer(), - integer(), - integer() -) -> integer(). -julian_seconds_from_parts(Year, Month, Day, Hours, Minutes, Seconds) -> - Julian_day_seconds = julian_day_from_ymd(Year, Month, Day) * 86400, - ((Julian_day_seconds + (Hours * 3600)) + (Minutes * 60)) + Seconds. - --file("src/gleam/time/timestamp.gleam", 662). --spec do_parse_second_fraction_as_nanoseconds(bitstring(), integer(), integer()) -> {ok, - {integer(), bitstring()}} | - {error, any()}. -do_parse_second_fraction_as_nanoseconds(Bytes, Acc, Power) -> - Power@1 = Power div 10, - case Bytes of - <> when ((16#30 =< Byte) andalso (Byte =< 16#39)) andalso (Power@1 < 1) -> - do_parse_second_fraction_as_nanoseconds( - Remaining_bytes, - Acc, - Power@1 - ); - - <> when (16#30 =< Byte@1) andalso (Byte@1 =< 16#39) -> - Digit = Byte@1 - 16#30, - do_parse_second_fraction_as_nanoseconds( - Remaining_bytes@1, - Acc + (Digit * Power@1), - Power@1 - ); - - _ -> - {ok, {Acc, Bytes}} - end. - --file("src/gleam/time/timestamp.gleam", 642). --spec parse_second_fraction_as_nanoseconds(bitstring()) -> {ok, - {integer(), bitstring()}} | - {error, nil}. -parse_second_fraction_as_nanoseconds(Bytes) -> - case Bytes of - <<"."/utf8, Byte, Remaining_bytes/binary>> when (16#30 =< Byte) andalso (Byte =< 16#39) -> - do_parse_second_fraction_as_nanoseconds( - <>, - 0, - 1000000000 - ); - - <<"."/utf8, _/binary>> -> - {error, nil}; - - _ -> - {ok, {0, Bytes}} - end. - --file("src/gleam/time/timestamp.gleam", 741). --spec do_parse_digits(bitstring(), integer(), integer(), integer()) -> {ok, - {integer(), bitstring()}} | - {error, nil}. -do_parse_digits(Bytes, Count, Acc, K) -> - case Bytes of - _ when K >= Count -> - {ok, {Acc, Bytes}}; - - <> when (16#30 =< Byte) andalso (Byte =< 16#39) -> - do_parse_digits( - Remaining_bytes, - Count, - (Acc * 10) + (Byte - 16#30), - K + 1 - ); - - _ -> - {error, nil} - end. - --file("src/gleam/time/timestamp.gleam", 734). -?DOC(" Parse and return the given number of digits from the given bytes.\n"). --spec parse_digits(bitstring(), integer()) -> {ok, {integer(), bitstring()}} | - {error, nil}. -parse_digits(Bytes, Count) -> - do_parse_digits(Bytes, Count, 0, 0). - --file("src/gleam/time/timestamp.gleam", 573). --spec parse_year(bitstring()) -> {ok, {integer(), bitstring()}} | {error, nil}. -parse_year(Bytes) -> - parse_digits(Bytes, 4). - --file("src/gleam/time/timestamp.gleam", 577). --spec parse_month(bitstring()) -> {ok, {integer(), bitstring()}} | {error, nil}. -parse_month(Bytes) -> - gleam@result:'try'( - parse_digits(Bytes, 2), - fun(_use0) -> - {Month, Bytes@1} = _use0, - case (1 =< Month) andalso (Month =< 12) of - true -> - {ok, {Month, Bytes@1}}; - - false -> - {error, nil} - end - end - ). - --file("src/gleam/time/timestamp.gleam", 585). --spec parse_day(bitstring(), integer(), integer()) -> {ok, - {integer(), bitstring()}} | - {error, nil}. -parse_day(Bytes, Year, Month) -> - gleam@result:'try'( - parse_digits(Bytes, 2), - fun(_use0) -> - {Day, Bytes@1} = _use0, - gleam@result:'try'(case Month of - 1 -> - {ok, 31}; - - 3 -> - {ok, 31}; - - 5 -> - {ok, 31}; - - 7 -> - {ok, 31}; - - 8 -> - {ok, 31}; - - 10 -> - {ok, 31}; - - 12 -> - {ok, 31}; - - 4 -> - {ok, 30}; - - 6 -> - {ok, 30}; - - 9 -> - {ok, 30}; - - 11 -> - {ok, 30}; - - 2 -> - case is_leap_year(Year) of - true -> - {ok, 29}; - - false -> - {ok, 28} - end; - - _ -> - {error, nil} - end, fun(Max_day) -> case (1 =< Day) andalso (Day =< Max_day) of - true -> - {ok, {Day, Bytes@1}}; - - false -> - {error, nil} - end end) - end - ). - --file("src/gleam/time/timestamp.gleam", 615). --spec parse_hours(bitstring()) -> {ok, {integer(), bitstring()}} | {error, nil}. -parse_hours(Bytes) -> - gleam@result:'try'( - parse_digits(Bytes, 2), - fun(_use0) -> - {Hours, Bytes@1} = _use0, - case (0 =< Hours) andalso (Hours =< 23) of - true -> - {ok, {Hours, Bytes@1}}; - - false -> - {error, nil} - end - end - ). - --file("src/gleam/time/timestamp.gleam", 623). --spec parse_minutes(bitstring()) -> {ok, {integer(), bitstring()}} | - {error, nil}. -parse_minutes(Bytes) -> - gleam@result:'try'( - parse_digits(Bytes, 2), - fun(_use0) -> - {Minutes, Bytes@1} = _use0, - case (0 =< Minutes) andalso (Minutes =< 59) of - true -> - {ok, {Minutes, Bytes@1}}; - - false -> - {error, nil} - end - end - ). - --file("src/gleam/time/timestamp.gleam", 631). --spec parse_seconds(bitstring()) -> {ok, {integer(), bitstring()}} | - {error, nil}. -parse_seconds(Bytes) -> - gleam@result:'try'( - parse_digits(Bytes, 2), - fun(_use0) -> - {Seconds, Bytes@1} = _use0, - case (0 =< Seconds) andalso (Seconds =< 60) of - true -> - {ok, {Seconds, Bytes@1}}; - - false -> - {error, nil} - end - end - ). - --file("src/gleam/time/timestamp.gleam", 704). --spec parse_numeric_offset(bitstring()) -> {ok, {integer(), bitstring()}} | - {error, nil}. -parse_numeric_offset(Bytes) -> - gleam@result:'try'( - parse_sign(Bytes), - fun(_use0) -> - {Sign, Bytes@1} = _use0, - gleam@result:'try'( - parse_hours(Bytes@1), - fun(_use0@1) -> - {Hours, Bytes@2} = _use0@1, - gleam@result:'try'( - accept_byte(Bytes@2, 16#3A), - fun(Bytes@3) -> - gleam@result:'try'( - parse_minutes(Bytes@3), - fun(_use0@2) -> - {Minutes, Bytes@4} = _use0@2, - Offset_seconds = offset_to_seconds( - Sign, - Hours, - Minutes - ), - {ok, {Offset_seconds, Bytes@4}} - end - ) - end - ) - end - ) - end - ). - --file("src/gleam/time/timestamp.gleam", 696). --spec parse_offset(bitstring()) -> {ok, {integer(), bitstring()}} | {error, nil}. -parse_offset(Bytes) -> - case Bytes of - <<"Z"/utf8, Remaining_bytes/binary>> -> - {ok, {0, Remaining_bytes}}; - - <<"z"/utf8, Remaining_bytes/binary>> -> - {ok, {0, Remaining_bytes}}; - - _ -> - parse_numeric_offset(Bytes) - end. - --file("src/gleam/time/timestamp.gleam", 769). --spec accept_date_time_separator(bitstring()) -> {ok, bitstring()} | - {error, nil}. -accept_date_time_separator(Bytes) -> - case Bytes of - <> when ((Byte =:= 16#54) orelse (Byte =:= 16#74)) orelse (Byte =:= 16#20) -> - {ok, Remaining_bytes}; - - _ -> - {error, nil} - end. - --file("src/gleam/time/timestamp.gleam", 789). -?DOC(" Note: The caller of this function must ensure that all inputs are valid.\n"). --spec from_date_time( - integer(), - integer(), - integer(), - integer(), - integer(), - integer(), - integer(), - integer() -) -> timestamp(). -from_date_time( - Year, - Month, - Day, - Hours, - Minutes, - Seconds, - Second_fraction_as_nanoseconds, - Offset_seconds -) -> - Julian_seconds = julian_seconds_from_parts( - Year, - Month, - Day, - Hours, - Minutes, - Seconds - ), - Julian_seconds_since_epoch = Julian_seconds - 210866803200, - _pipe = {timestamp, - Julian_seconds_since_epoch - Offset_seconds, - Second_fraction_as_nanoseconds}, - normalise(_pipe). - --file("src/gleam/time/timestamp.gleam", 339). -?DOC( - " Create a `Timestamp` from a human-readable calendar time.\n" - "\n" - " # Examples\n" - "\n" - " ```gleam\n" - " timestamp.from_calendar(\n" - " date: calendar.Date(2024, calendar.December, 25),\n" - " time: calendar.TimeOfDay(12, 30, 50, 0),\n" - " offset: calendar.utc_offset,\n" - " )\n" - " |> timestamp.to_rfc3339(calendar.utc_offset)\n" - " // -> \"2024-12-25T12:30:50Z\"\n" - " ```\n" -). --spec from_calendar( - gleam@time@calendar:date(), - gleam@time@calendar:time_of_day(), - gleam@time@duration:duration() -) -> timestamp(). -from_calendar(Date, Time, Offset) -> - Month = case erlang:element(3, Date) of - january -> - 1; - - february -> - 2; - - march -> - 3; - - april -> - 4; - - may -> - 5; - - june -> - 6; - - july -> - 7; - - august -> - 8; - - september -> - 9; - - october -> - 10; - - november -> - 11; - - december -> - 12 - end, - from_date_time( - erlang:element(2, Date), - Month, - erlang:element(4, Date), - erlang:element(2, Time), - erlang:element(3, Time), - erlang:element(4, Time), - erlang:element(5, Time), - erlang:round(gleam@time@duration:to_seconds(Offset)) - ). - --file("src/gleam/time/timestamp.gleam", 533). -?DOC( - " Parses an [RFC 3339 formatted time string][spec] into a `Timestamp`.\n" - "\n" - " [spec]: https://datatracker.ietf.org/doc/html/rfc3339#section-5.6\n" - " \n" - " # Examples\n" - "\n" - " ```gleam\n" - " let assert Ok(ts) = timestamp.parse_rfc3339(\"1970-01-01T00:00:01Z\")\n" - " timestamp.to_unix_seconds_and_nanoseconds(ts)\n" - " // -> #(1, 0)\n" - " ```\n" - " \n" - " Parsing an invalid timestamp returns an error.\n" - " \n" - " ```gleam\n" - " let assert Error(Nil) = timestamp.parse_rfc3339(\"1995-10-31\")\n" - " ```\n" - "\n" - " ## Time zones\n" - "\n" - " It may at first seem that the RFC 3339 format includes timezone\n" - " information, as it can specify an offset such as `Z` or `+3`, so why does\n" - " this function not return calendar time with a time zone? There are multiple\n" - " reasons:\n" - "\n" - " - RFC 3339's timestamp format is based on calendar time, but it is\n" - " unambigous, so it can be converted into epoch time when being parsed. It\n" - " is always better to internally use epoch time to represent unambiguous\n" - " points in time, so we perform that conversion as a convenience and to\n" - " ensure that programmers with less time experience don't accidentally use\n" - " a less suitable time representation.\n" - "\n" - " - RFC 3339's contains _calendar time offset_ information, not time zone\n" - " information. This is enough to convert it to an unambiguous timestamp,\n" - " but it is not enough information to reliably work with calendar time.\n" - " Without the time zone and the time zone database it's not possible to\n" - " know what time period that offset is valid for, so it cannot be used\n" - " without risk of bugs.\n" - "\n" - " ## Behaviour details\n" - " \n" - " - Follows the grammar specified in section 5.6 Internet Date/Time Format of \n" - " RFC 3339 .\n" - " - The `T` and `Z` characters may alternatively be lower case `t` or `z`, \n" - " respectively.\n" - " - Full dates and full times must be separated by `T` or `t`. A space is also \n" - " permitted.\n" - " - Leap seconds rules are not considered. That is, any timestamp may \n" - " specify digts `00` - `60` for the seconds.\n" - " - Any part of a fractional second that cannot be represented in the \n" - " nanosecond precision is tructated. That is, for the time string, \n" - " `\"1970-01-01T00:00:00.1234567899Z\"`, the fractional second `.1234567899` \n" - " will be represented as `123_456_789` in the `Timestamp`.\n" -). --spec parse_rfc3339(binary()) -> {ok, timestamp()} | {error, nil}. -parse_rfc3339(Input) -> - Bytes = gleam_stdlib:identity(Input), - gleam@result:'try'( - parse_year(Bytes), - fun(_use0) -> - {Year, Bytes@1} = _use0, - gleam@result:'try'( - accept_byte(Bytes@1, 16#2D), - fun(Bytes@2) -> - gleam@result:'try'( - parse_month(Bytes@2), - fun(_use0@1) -> - {Month, Bytes@3} = _use0@1, - gleam@result:'try'( - accept_byte(Bytes@3, 16#2D), - fun(Bytes@4) -> - gleam@result:'try'( - parse_day(Bytes@4, Year, Month), - fun(_use0@2) -> - {Day, Bytes@5} = _use0@2, - gleam@result:'try'( - accept_date_time_separator( - Bytes@5 - ), - fun(Bytes@6) -> - gleam@result:'try'( - parse_hours(Bytes@6), - fun(_use0@3) -> - {Hours, Bytes@7} = _use0@3, - gleam@result:'try'( - accept_byte( - Bytes@7, - 16#3A - ), - fun(Bytes@8) -> - gleam@result:'try'( - parse_minutes( - Bytes@8 - ), - fun( - _use0@4 - ) -> - {Minutes, - Bytes@9} = _use0@4, - gleam@result:'try'( - accept_byte( - Bytes@9, - 16#3A - ), - fun( - Bytes@10 - ) -> - gleam@result:'try'( - parse_seconds( - Bytes@10 - ), - fun( - _use0@5 - ) -> - {Seconds, - Bytes@11} = _use0@5, - gleam@result:'try'( - parse_second_fraction_as_nanoseconds( - Bytes@11 - ), - fun( - _use0@6 - ) -> - {Second_fraction_as_nanoseconds, - Bytes@12} = _use0@6, - gleam@result:'try'( - parse_offset( - Bytes@12 - ), - fun( - _use0@7 - ) -> - {Offset_seconds, - Bytes@13} = _use0@7, - gleam@result:'try'( - accept_empty( - Bytes@13 - ), - fun( - _use0@8 - ) -> - nil = _use0@8, - {ok, - from_date_time( - Year, - Month, - Day, - Hours, - Minutes, - Seconds, - Second_fraction_as_nanoseconds, - Offset_seconds - )} - end - ) - end - ) - end - ) - end - ) - end - ) - end - ) - end - ) - end - ) - end - ) - end - ) - end - ) - end - ) - end - ) - end - ). diff --git a/build/dev/javascript/gleam_time/gleam_time_ffi.erl b/build/dev/javascript/gleam_time/gleam_time_ffi.erl deleted file mode 100644 index 34d8c88..0000000 --- a/build/dev/javascript/gleam_time/gleam_time_ffi.erl +++ /dev/null @@ -1,12 +0,0 @@ --module(gleam_time_ffi). --export([system_time/0, local_time_offset_seconds/0]). - -system_time() -> - {0, erlang:system_time(nanosecond)}. - -local_time_offset_seconds() -> - Utc = calendar:universal_time(), - Local = calendar:local_time(), - UtcSeconds = calendar:datetime_to_gregorian_seconds(Utc), - LocalSeconds = calendar:datetime_to_gregorian_seconds(Local), - LocalSeconds - UtcSeconds. diff --git a/build/dev/javascript/gleam_time/gleam_time_ffi.mjs b/build/dev/javascript/gleam_time/gleam_time_ffi.mjs deleted file mode 100644 index 27d09aa..0000000 --- a/build/dev/javascript/gleam_time/gleam_time_ffi.mjs +++ /dev/null @@ -1,11 +0,0 @@ -export function system_time() { - const now = Date.now(); - const milliseconds = now % 1_000; - const nanoseconds = milliseconds * 1000_000; - const seconds = (now - milliseconds) / 1_000; - return [seconds, nanoseconds]; -} - -export function local_time_offset_seconds() { - return new Date().getTimezoneOffset() * -60; -} diff --git a/build/dev/javascript/gleam_version b/build/dev/javascript/gleam_version deleted file mode 100644 index f88cf52..0000000 --- a/build/dev/javascript/gleam_version +++ /dev/null @@ -1 +0,0 @@ -1.13.0 \ No newline at end of file diff --git a/build/dev/javascript/gleeunit/_gleam_artefacts/gleeunit.cache b/build/dev/javascript/gleeunit/_gleam_artefacts/gleeunit.cache deleted file mode 100644 index b226414..0000000 Binary files a/build/dev/javascript/gleeunit/_gleam_artefacts/gleeunit.cache and /dev/null differ diff --git a/build/dev/javascript/gleeunit/_gleam_artefacts/gleeunit.cache_inline b/build/dev/javascript/gleeunit/_gleam_artefacts/gleeunit.cache_inline deleted file mode 100644 index 1b1cb4d..0000000 Binary files a/build/dev/javascript/gleeunit/_gleam_artefacts/gleeunit.cache_inline and /dev/null differ diff --git a/build/dev/javascript/gleeunit/_gleam_artefacts/gleeunit.cache_meta b/build/dev/javascript/gleeunit/_gleam_artefacts/gleeunit.cache_meta deleted file mode 100644 index 5c75cc9..0000000 Binary files a/build/dev/javascript/gleeunit/_gleam_artefacts/gleeunit.cache_meta and /dev/null differ diff --git a/build/dev/javascript/gleeunit/_gleam_artefacts/gleeunit@internal@gleam_panic.cache b/build/dev/javascript/gleeunit/_gleam_artefacts/gleeunit@internal@gleam_panic.cache deleted file mode 100644 index 1f02d43..0000000 Binary files a/build/dev/javascript/gleeunit/_gleam_artefacts/gleeunit@internal@gleam_panic.cache and /dev/null differ diff --git a/build/dev/javascript/gleeunit/_gleam_artefacts/gleeunit@internal@gleam_panic.cache_inline b/build/dev/javascript/gleeunit/_gleam_artefacts/gleeunit@internal@gleam_panic.cache_inline deleted file mode 100644 index 1b1cb4d..0000000 Binary files a/build/dev/javascript/gleeunit/_gleam_artefacts/gleeunit@internal@gleam_panic.cache_inline and /dev/null differ diff --git a/build/dev/javascript/gleeunit/_gleam_artefacts/gleeunit@internal@gleam_panic.cache_meta b/build/dev/javascript/gleeunit/_gleam_artefacts/gleeunit@internal@gleam_panic.cache_meta deleted file mode 100644 index 8e2ed2a..0000000 Binary files a/build/dev/javascript/gleeunit/_gleam_artefacts/gleeunit@internal@gleam_panic.cache_meta and /dev/null differ diff --git a/build/dev/javascript/gleeunit/_gleam_artefacts/gleeunit@internal@reporting.cache b/build/dev/javascript/gleeunit/_gleam_artefacts/gleeunit@internal@reporting.cache deleted file mode 100644 index 7f17018..0000000 Binary files a/build/dev/javascript/gleeunit/_gleam_artefacts/gleeunit@internal@reporting.cache and /dev/null differ diff --git a/build/dev/javascript/gleeunit/_gleam_artefacts/gleeunit@internal@reporting.cache_inline b/build/dev/javascript/gleeunit/_gleam_artefacts/gleeunit@internal@reporting.cache_inline deleted file mode 100644 index 1b1cb4d..0000000 Binary files a/build/dev/javascript/gleeunit/_gleam_artefacts/gleeunit@internal@reporting.cache_inline and /dev/null differ diff --git a/build/dev/javascript/gleeunit/_gleam_artefacts/gleeunit@internal@reporting.cache_meta b/build/dev/javascript/gleeunit/_gleam_artefacts/gleeunit@internal@reporting.cache_meta deleted file mode 100644 index 34ab986..0000000 Binary files a/build/dev/javascript/gleeunit/_gleam_artefacts/gleeunit@internal@reporting.cache_meta and /dev/null differ diff --git a/build/dev/javascript/gleeunit/_gleam_artefacts/gleeunit@should.cache b/build/dev/javascript/gleeunit/_gleam_artefacts/gleeunit@should.cache deleted file mode 100644 index 8c8ecf7..0000000 Binary files a/build/dev/javascript/gleeunit/_gleam_artefacts/gleeunit@should.cache and /dev/null differ diff --git a/build/dev/javascript/gleeunit/_gleam_artefacts/gleeunit@should.cache_inline b/build/dev/javascript/gleeunit/_gleam_artefacts/gleeunit@should.cache_inline deleted file mode 100644 index 1b1cb4d..0000000 Binary files a/build/dev/javascript/gleeunit/_gleam_artefacts/gleeunit@should.cache_inline and /dev/null differ diff --git a/build/dev/javascript/gleeunit/_gleam_artefacts/gleeunit@should.cache_meta b/build/dev/javascript/gleeunit/_gleam_artefacts/gleeunit@should.cache_meta deleted file mode 100644 index 4989b1e..0000000 Binary files a/build/dev/javascript/gleeunit/_gleam_artefacts/gleeunit@should.cache_meta and /dev/null differ diff --git a/build/dev/javascript/gleeunit/gleam.mjs b/build/dev/javascript/gleeunit/gleam.mjs deleted file mode 100644 index 197cbbc..0000000 --- a/build/dev/javascript/gleeunit/gleam.mjs +++ /dev/null @@ -1 +0,0 @@ -export * from "../prelude.mjs"; diff --git a/build/dev/javascript/gleeunit/gleeunit.erl b/build/dev/javascript/gleeunit/gleeunit.erl deleted file mode 100644 index bcb58b6..0000000 --- a/build/dev/javascript/gleeunit/gleeunit.erl +++ /dev/null @@ -1,89 +0,0 @@ --module(gleeunit). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "src/gleeunit.gleam"). --export([main/0]). --export_type([atom_/0, encoding/0, report_module_name/0, gleeunit_progress_option/0, eunit_option/0]). - --if(?OTP_RELEASE >= 27). --define(MODULEDOC(Str), -moduledoc(Str)). --define(DOC(Str), -doc(Str)). --else. --define(MODULEDOC(Str), -compile([])). --define(DOC(Str), -compile([])). --endif. - --type atom_() :: any(). - --type encoding() :: utf8. - --type report_module_name() :: gleeunit_progress. - --type gleeunit_progress_option() :: {colored, boolean()}. - --type eunit_option() :: verbose | - no_tty | - {report, {report_module_name(), list(gleeunit_progress_option())}} | - {scale_timeouts, integer()}. - --file("src/gleeunit.gleam", 42). --spec gleam_to_erlang_module_name(binary()) -> binary(). -gleam_to_erlang_module_name(Path) -> - case gleam_stdlib:string_ends_with(Path, <<".gleam"/utf8>>) of - true -> - _pipe = Path, - _pipe@1 = gleam@string:replace( - _pipe, - <<".gleam"/utf8>>, - <<""/utf8>> - ), - gleam@string:replace(_pipe@1, <<"/"/utf8>>, <<"@"/utf8>>); - - false -> - _pipe@2 = Path, - _pipe@3 = gleam@string:split(_pipe@2, <<"/"/utf8>>), - _pipe@4 = gleam@list:last(_pipe@3), - _pipe@5 = gleam@result:unwrap(_pipe@4, Path), - gleam@string:replace(_pipe@5, <<".erl"/utf8>>, <<""/utf8>>) - end. - --file("src/gleeunit.gleam", 18). --spec do_main() -> nil. -do_main() -> - Options = [verbose, - no_tty, - {report, {gleeunit_progress, [{colored, true}]}}, - {scale_timeouts, 10}], - Result = begin - _pipe = gleeunit_ffi:find_files( - <<"**/*.{erl,gleam}"/utf8>>, - <<"test"/utf8>> - ), - _pipe@1 = gleam@list:map(_pipe, fun gleam_to_erlang_module_name/1), - _pipe@2 = gleam@list:map( - _pipe@1, - fun(_capture) -> erlang:binary_to_atom(_capture, utf8) end - ), - gleeunit_ffi:run_eunit(_pipe@2, Options) - end, - Code = case Result of - {ok, _} -> - 0; - - {error, _} -> - 1 - end, - erlang:halt(Code). - --file("src/gleeunit.gleam", 13). -?DOC( - " Find and run all test functions for the current project using Erlang's EUnit\n" - " test framework, or a custom JavaScript test runner.\n" - "\n" - " Any Erlang or Gleam function in the `test` directory with a name ending in\n" - " `_test` is considered a test function and will be run.\n" - "\n" - " A test that panics is considered a failure.\n" -). --spec main() -> nil. -main() -> - do_main(). diff --git a/build/dev/javascript/gleeunit/gleeunit.mjs b/build/dev/javascript/gleeunit/gleeunit.mjs deleted file mode 100644 index 83018dd..0000000 --- a/build/dev/javascript/gleeunit/gleeunit.mjs +++ /dev/null @@ -1,62 +0,0 @@ -import * as $list from "../gleam_stdlib/gleam/list.mjs"; -import * as $result from "../gleam_stdlib/gleam/result.mjs"; -import * as $string from "../gleam_stdlib/gleam/string.mjs"; -import { CustomType as $CustomType } from "./gleam.mjs"; -import { main as do_main } from "./gleeunit_ffi.mjs"; - -class Utf8 extends $CustomType {} - -class GleeunitProgress extends $CustomType {} - -class Colored extends $CustomType { - constructor($0) { - super(); - this[0] = $0; - } -} - -class Verbose extends $CustomType {} - -class NoTty extends $CustomType {} - -class Report extends $CustomType { - constructor($0) { - super(); - this[0] = $0; - } -} - -class ScaleTimeouts extends $CustomType { - constructor($0) { - super(); - this[0] = $0; - } -} - -function gleam_to_erlang_module_name(path) { - let $ = $string.ends_with(path, ".gleam"); - if ($) { - let _pipe = path; - let _pipe$1 = $string.replace(_pipe, ".gleam", ""); - return $string.replace(_pipe$1, "/", "@"); - } else { - let _pipe = path; - let _pipe$1 = $string.split(_pipe, "/"); - let _pipe$2 = $list.last(_pipe$1); - let _pipe$3 = $result.unwrap(_pipe$2, path); - return $string.replace(_pipe$3, ".erl", ""); - } -} - -/** - * Find and run all test functions for the current project using Erlang's EUnit - * test framework, or a custom JavaScript test runner. - * - * Any Erlang or Gleam function in the `test` directory with a name ending in - * `_test` is considered a test function and will be run. - * - * A test that panics is considered a failure. - */ -export function main() { - return do_main(); -} diff --git a/build/dev/javascript/gleeunit/gleeunit/internal/gleam_panic.mjs b/build/dev/javascript/gleeunit/gleeunit/internal/gleam_panic.mjs deleted file mode 100644 index f6af89d..0000000 --- a/build/dev/javascript/gleeunit/gleeunit/internal/gleam_panic.mjs +++ /dev/null @@ -1,180 +0,0 @@ -import * as $dynamic from "../../../gleam_stdlib/gleam/dynamic.mjs"; -import { CustomType as $CustomType } from "../../gleam.mjs"; -import { from_dynamic } from "./gleeunit_gleam_panic_ffi.mjs"; - -export { from_dynamic }; - -export class GleamPanic extends $CustomType { - constructor(message, file, module, function$, line, kind) { - super(); - this.message = message; - this.file = file; - this.module = module; - this.function = function$; - this.line = line; - this.kind = kind; - } -} -export const GleamPanic$GleamPanic = (message, file, module, function$, line, kind) => - new GleamPanic(message, file, module, function$, line, kind); -export const GleamPanic$isGleamPanic = (value) => value instanceof GleamPanic; -export const GleamPanic$GleamPanic$message = (value) => value.message; -export const GleamPanic$GleamPanic$0 = (value) => value.message; -export const GleamPanic$GleamPanic$file = (value) => value.file; -export const GleamPanic$GleamPanic$1 = (value) => value.file; -export const GleamPanic$GleamPanic$module = (value) => value.module; -export const GleamPanic$GleamPanic$2 = (value) => value.module; -export const GleamPanic$GleamPanic$function = (value) => value.function; -export const GleamPanic$GleamPanic$3 = (value) => value.function; -export const GleamPanic$GleamPanic$line = (value) => value.line; -export const GleamPanic$GleamPanic$4 = (value) => value.line; -export const GleamPanic$GleamPanic$kind = (value) => value.kind; -export const GleamPanic$GleamPanic$5 = (value) => value.kind; - -export class Todo extends $CustomType {} -export const PanicKind$Todo = () => new Todo(); -export const PanicKind$isTodo = (value) => value instanceof Todo; - -export class Panic extends $CustomType {} -export const PanicKind$Panic = () => new Panic(); -export const PanicKind$isPanic = (value) => value instanceof Panic; - -export class LetAssert extends $CustomType { - constructor(start, end, pattern_start, pattern_end, value) { - super(); - this.start = start; - this.end = end; - this.pattern_start = pattern_start; - this.pattern_end = pattern_end; - this.value = value; - } -} -export const PanicKind$LetAssert = (start, end, pattern_start, pattern_end, value) => - new LetAssert(start, end, pattern_start, pattern_end, value); -export const PanicKind$isLetAssert = (value) => value instanceof LetAssert; -export const PanicKind$LetAssert$start = (value) => value.start; -export const PanicKind$LetAssert$0 = (value) => value.start; -export const PanicKind$LetAssert$end = (value) => value.end; -export const PanicKind$LetAssert$1 = (value) => value.end; -export const PanicKind$LetAssert$pattern_start = (value) => value.pattern_start; -export const PanicKind$LetAssert$2 = (value) => value.pattern_start; -export const PanicKind$LetAssert$pattern_end = (value) => value.pattern_end; -export const PanicKind$LetAssert$3 = (value) => value.pattern_end; -export const PanicKind$LetAssert$value = (value) => value.value; -export const PanicKind$LetAssert$4 = (value) => value.value; - -export class Assert extends $CustomType { - constructor(start, end, expression_start, kind) { - super(); - this.start = start; - this.end = end; - this.expression_start = expression_start; - this.kind = kind; - } -} -export const PanicKind$Assert = (start, end, expression_start, kind) => - new Assert(start, end, expression_start, kind); -export const PanicKind$isAssert = (value) => value instanceof Assert; -export const PanicKind$Assert$start = (value) => value.start; -export const PanicKind$Assert$0 = (value) => value.start; -export const PanicKind$Assert$end = (value) => value.end; -export const PanicKind$Assert$1 = (value) => value.end; -export const PanicKind$Assert$expression_start = (value) => - value.expression_start; -export const PanicKind$Assert$2 = (value) => value.expression_start; -export const PanicKind$Assert$kind = (value) => value.kind; -export const PanicKind$Assert$3 = (value) => value.kind; - -export class BinaryOperator extends $CustomType { - constructor(operator, left, right) { - super(); - this.operator = operator; - this.left = left; - this.right = right; - } -} -export const AssertKind$BinaryOperator = (operator, left, right) => - new BinaryOperator(operator, left, right); -export const AssertKind$isBinaryOperator = (value) => - value instanceof BinaryOperator; -export const AssertKind$BinaryOperator$operator = (value) => value.operator; -export const AssertKind$BinaryOperator$0 = (value) => value.operator; -export const AssertKind$BinaryOperator$left = (value) => value.left; -export const AssertKind$BinaryOperator$1 = (value) => value.left; -export const AssertKind$BinaryOperator$right = (value) => value.right; -export const AssertKind$BinaryOperator$2 = (value) => value.right; - -export class FunctionCall extends $CustomType { - constructor(arguments$) { - super(); - this.arguments = arguments$; - } -} -export const AssertKind$FunctionCall = (arguments$) => - new FunctionCall(arguments$); -export const AssertKind$isFunctionCall = (value) => - value instanceof FunctionCall; -export const AssertKind$FunctionCall$arguments = (value) => value.arguments; -export const AssertKind$FunctionCall$0 = (value) => value.arguments; - -export class OtherExpression extends $CustomType { - constructor(expression) { - super(); - this.expression = expression; - } -} -export const AssertKind$OtherExpression = (expression) => - new OtherExpression(expression); -export const AssertKind$isOtherExpression = (value) => - value instanceof OtherExpression; -export const AssertKind$OtherExpression$expression = (value) => - value.expression; -export const AssertKind$OtherExpression$0 = (value) => value.expression; - -export class AssertedExpression extends $CustomType { - constructor(start, end, kind) { - super(); - this.start = start; - this.end = end; - this.kind = kind; - } -} -export const AssertedExpression$AssertedExpression = (start, end, kind) => - new AssertedExpression(start, end, kind); -export const AssertedExpression$isAssertedExpression = (value) => - value instanceof AssertedExpression; -export const AssertedExpression$AssertedExpression$start = (value) => - value.start; -export const AssertedExpression$AssertedExpression$0 = (value) => value.start; -export const AssertedExpression$AssertedExpression$end = (value) => value.end; -export const AssertedExpression$AssertedExpression$1 = (value) => value.end; -export const AssertedExpression$AssertedExpression$kind = (value) => value.kind; -export const AssertedExpression$AssertedExpression$2 = (value) => value.kind; - -export class Literal extends $CustomType { - constructor(value) { - super(); - this.value = value; - } -} -export const ExpressionKind$Literal = (value) => new Literal(value); -export const ExpressionKind$isLiteral = (value) => value instanceof Literal; -export const ExpressionKind$Literal$value = (value) => value.value; -export const ExpressionKind$Literal$0 = (value) => value.value; - -export class Expression extends $CustomType { - constructor(value) { - super(); - this.value = value; - } -} -export const ExpressionKind$Expression = (value) => new Expression(value); -export const ExpressionKind$isExpression = (value) => - value instanceof Expression; -export const ExpressionKind$Expression$value = (value) => value.value; -export const ExpressionKind$Expression$0 = (value) => value.value; - -export class Unevaluated extends $CustomType {} -export const ExpressionKind$Unevaluated = () => new Unevaluated(); -export const ExpressionKind$isUnevaluated = (value) => - value instanceof Unevaluated; diff --git a/build/dev/javascript/gleeunit/gleeunit/internal/gleeunit_gleam_panic_ffi.erl b/build/dev/javascript/gleeunit/gleeunit/internal/gleeunit_gleam_panic_ffi.erl deleted file mode 100644 index d78f5e5..0000000 --- a/build/dev/javascript/gleeunit/gleeunit/internal/gleeunit_gleam_panic_ffi.erl +++ /dev/null @@ -1,49 +0,0 @@ --module(gleeunit_gleam_panic_ffi). --export([from_dynamic/1]). - -from_dynamic(#{ - gleam_error := assert, - start := Start, - 'end' := End, - expression_start := EStart -} = E) -> - wrap(E, {assert, Start, End, EStart, assert_kind(E)}); -from_dynamic(#{ - gleam_error := let_assert, - start := Start, - 'end' := End, - pattern_start := PStart, - pattern_end := PEnd, - value := Value -} = E) -> - wrap(E, {let_assert, Start, End, PStart, PEnd, Value}); -from_dynamic(#{gleam_error := panic} = E) -> - wrap(E, panic); -from_dynamic(#{gleam_error := todo} = E) -> - wrap(E, todo); -from_dynamic(_) -> - {error, nil}. - -assert_kind(#{kind := binary_operator, left := L, right := R, operator := O}) -> - {binary_operator, atom_to_binary(O), expression(L), expression(R)}; -assert_kind(#{kind := function_call, arguments := Arguments}) -> - {function_call, lists:map(fun expression/1, Arguments)}; -assert_kind(#{kind := expression, expression := Expression}) -> - {other_expression, expression(Expression)}. - -expression(#{start := S, 'end' := E, kind := literal, value := Value}) -> - {asserted_expression, S, E, {literal, Value}}; -expression(#{start := S, 'end' := E, kind := expression, value := Value}) -> - {asserted_expression, S, E, {expression, Value}}; -expression(#{start := S, 'end' := E, kind := unevaluated}) -> - {asserted_expression, S, E, unevaluated}. - -wrap(#{ - gleam_error := _, - file := File, - message := Message, - module := Module, - function := Function, - line := Line -}, Kind) -> - {ok, {gleam_panic, Message, File, Module, Function, Line, Kind}}. diff --git a/build/dev/javascript/gleeunit/gleeunit/internal/gleeunit_gleam_panic_ffi.mjs b/build/dev/javascript/gleeunit/gleeunit/internal/gleeunit_gleam_panic_ffi.mjs deleted file mode 100644 index 03f6025..0000000 --- a/build/dev/javascript/gleeunit/gleeunit/internal/gleeunit_gleam_panic_ffi.mjs +++ /dev/null @@ -1,91 +0,0 @@ -import { Result$Ok, Result$Error, List$Empty, List$NonEmpty } from "../../gleam.mjs"; -import { - GleamPanic$GleamPanic, - PanicKind$Todo, - PanicKind$Panic, - PanicKind$LetAssert, - PanicKind$Assert, - AssertKind$BinaryOperator, - AssertKind$FunctionCall, - AssertKind$OtherExpression, - AssertedExpression$AssertedExpression, - ExpressionKind$Literal, - ExpressionKind$Expression, - ExpressionKind$Unevaluated, -} from "./gleam_panic.mjs"; - -export function from_dynamic(error) { - if (!(error instanceof globalThis.Error) || !error.gleam_error) { - return Result$Error(undefined); - } - - if (error.gleam_error === "todo") { - return wrap(error, PanicKind$Todo()); - } - - if (error.gleam_error === "panic") { - return wrap(error, PanicKind$Panic()); - } - - if (error.gleam_error === "let_assert") { - let kind = PanicKind$LetAssert( - error.start, - error.end, - error.pattern_start, - error.pattern_end, - error.value, - ); - return wrap(error, kind); - } - - if (error.gleam_error === "assert") { - let kind = PanicKind$Assert( - error.start, - error.end, - error.expression_start, - assert_kind(error), - ); - return wrap(error, kind); - } - - return Result$Error(undefined); -} - -function assert_kind(error) { - if (error.kind == "binary_operator") { - return AssertKind$BinaryOperator( - error.operator, - expression(error.left), - expression(error.right), - ); - } - - if (error.kind == "function_call") { - let list = List$Empty(); - let i = error.arguments.length; - while (i--) { - list = List$NonEmpty(expression(error.arguments[i]), list); - } - return AssertKind$FunctionCall(list); - } - - return AssertKind$OtherExpression(expression(error.expression)); -} - -function expression(data) { - const expression = AssertedExpression$AssertedExpression(data.start, data.end, undefined); - if (data.kind == "literal") { - expression.kind = ExpressionKind$Literal(data.value); - } else if (data.kind == "expression") { - expression.kind = ExpressionKind$Expression(data.value); - } else { - expression.kind = ExpressionKind$Unevaluated(); - } - return expression; -} - -function wrap(e, kind) { - return Result$Ok( - GleamPanic$GleamPanic(e.message, e.file, e.module, e.function, e.line, kind), - ); -} diff --git a/build/dev/javascript/gleeunit/gleeunit/internal/reporting.mjs b/build/dev/javascript/gleeunit/gleeunit/internal/reporting.mjs deleted file mode 100644 index 8ebf9a2..0000000 --- a/build/dev/javascript/gleeunit/gleeunit/internal/reporting.mjs +++ /dev/null @@ -1,256 +0,0 @@ -import * as $bit_array from "../../../gleam_stdlib/gleam/bit_array.mjs"; -import * as $dynamic from "../../../gleam_stdlib/gleam/dynamic.mjs"; -import * as $int from "../../../gleam_stdlib/gleam/int.mjs"; -import * as $io from "../../../gleam_stdlib/gleam/io.mjs"; -import * as $list from "../../../gleam_stdlib/gleam/list.mjs"; -import * as $option from "../../../gleam_stdlib/gleam/option.mjs"; -import * as $result from "../../../gleam_stdlib/gleam/result.mjs"; -import * as $string from "../../../gleam_stdlib/gleam/string.mjs"; -import { Ok, Error, toList, CustomType as $CustomType } from "../../gleam.mjs"; -import * as $gleam_panic from "../../gleeunit/internal/gleam_panic.mjs"; -import { read_file as read_file_text } from "../../gleeunit_ffi.mjs"; - -export class State extends $CustomType { - constructor(passed, failed, skipped) { - super(); - this.passed = passed; - this.failed = failed; - this.skipped = skipped; - } -} -export const State$State = (passed, failed, skipped) => - new State(passed, failed, skipped); -export const State$isState = (value) => value instanceof State; -export const State$State$passed = (value) => value.passed; -export const State$State$0 = (value) => value.passed; -export const State$State$failed = (value) => value.failed; -export const State$State$1 = (value) => value.failed; -export const State$State$skipped = (value) => value.skipped; -export const State$State$2 = (value) => value.skipped; - -export function new_state() { - return new State(0, 0, 0); -} - -function bold(text) { - return ("\u{001b}[1m" + text) + "\u{001b}[22m"; -} - -function cyan(text) { - return ("\u{001b}[36m" + text) + "\u{001b}[39m"; -} - -function code_snippet(src, start, end) { - let _pipe = $result.try$( - $option.to_result(src, undefined), - (src) => { - return $result.try$( - $bit_array.slice(src, start, end - start), - (snippet) => { - return $result.try$( - $bit_array.to_string(snippet), - (snippet) => { - let snippet$1 = ((cyan(" code") + ": ") + snippet) + "\n"; - return new Ok(snippet$1); - }, - ); - }, - ); - }, - ); - return $result.unwrap(_pipe, ""); -} - -function yellow(text) { - return ("\u{001b}[33m" + text) + "\u{001b}[39m"; -} - -export function test_skipped(state, module, function$) { - $io.print(((("\n" + module) + ".") + function$) + yellow(" skipped")); - return new State(state.passed, state.failed, state.skipped + 1); -} - -function green(text) { - return ("\u{001b}[32m" + text) + "\u{001b}[39m"; -} - -export function test_passed(state) { - $io.print(green(".")); - return new State(state.passed + 1, state.failed, state.skipped); -} - -function red(text) { - return ("\u{001b}[31m" + text) + "\u{001b}[39m"; -} - -export function finished(state) { - let $ = state.failed; - if ($ === 0) { - let $1 = state.skipped; - if ($1 === 0) { - let $2 = state.passed; - if ($2 === 0) { - $io.println("\nNo tests found!"); - return 1; - } else { - let message = ("\n" + $int.to_string(state.passed)) + " passed, no failures"; - $io.println(green(message)); - return 0; - } - } else { - let message = ((("\n" + $int.to_string(state.passed)) + " passed, 0 failures, ") + $int.to_string( - state.skipped, - )) + " skipped"; - $io.println(yellow(message)); - return 1; - } - } else { - let $1 = state.skipped; - if ($1 === 0) { - let message = ((("\n" + $int.to_string(state.passed)) + " passed, ") + $int.to_string( - state.failed, - )) + " failures"; - $io.println(red(message)); - return 1; - } else { - let message = ((((("\n" + $int.to_string(state.passed)) + " passed, ") + $int.to_string( - state.failed, - )) + " failures, ") + $int.to_string(state.skipped)) + " skipped"; - $io.println(red(message)); - return 1; - } - } -} - -export function eunit_missing() { - let message = bold(red("Error")) + ": EUnit libraries not found.\n\nYour Erlang installation seems to be incomplete. If you installed Erlang using\na package manager ensure that you have installed the full Erlang\ndistribution instead of a stripped-down version.\n"; - $io.print_error(message); - return new Error(undefined); -} - -function grey(text) { - return ("\u{001b}[90m" + text) + "\u{001b}[39m"; -} - -function format_unknown(module, function$, error) { - return $string.concat( - toList([ - grey((module + ".") + function$) + "\n", - "An unexpected error occurred:\n", - "\n", - (" " + $string.inspect(error)) + "\n", - ]), - ); -} - -function inspect_value(value) { - let $ = value.kind; - if ($ instanceof $gleam_panic.Literal) { - return grey("literal"); - } else if ($ instanceof $gleam_panic.Expression) { - let value$1 = $.value; - return $string.inspect(value$1); - } else { - return grey("unevaluated"); - } -} - -function assert_value(name, value) { - return ((cyan(name) + ": ") + inspect_value(value)) + "\n"; -} - -function assert_info(kind) { - if (kind instanceof $gleam_panic.BinaryOperator) { - let left = kind.left; - let right = kind.right; - return $string.concat( - toList([assert_value(" left", left), assert_value("right", right)]), - ); - } else if (kind instanceof $gleam_panic.FunctionCall) { - let arguments$ = kind.arguments; - let _pipe = arguments$; - let _pipe$1 = $list.index_map( - _pipe, - (e, i) => { - let number = $string.pad_start($int.to_string(i), 5, " "); - return assert_value(number, e); - }, - ); - return $string.concat(_pipe$1); - } else { - return ""; - } -} - -function format_gleam_error(error, module, function$, src) { - let location = grey((error.file + ":") + $int.to_string(error.line)); - let $ = error.kind; - if ($ instanceof $gleam_panic.Todo) { - return $string.concat( - toList([ - ((bold(yellow("todo")) + " ") + location) + "\n", - ((((cyan(" test") + ": ") + module) + ".") + function$) + "\n", - ((cyan(" info") + ": ") + error.message) + "\n", - ]), - ); - } else if ($ instanceof $gleam_panic.Panic) { - return $string.concat( - toList([ - ((bold(red("panic")) + " ") + location) + "\n", - ((((cyan(" test") + ": ") + module) + ".") + function$) + "\n", - ((cyan(" info") + ": ") + error.message) + "\n", - ]), - ); - } else if ($ instanceof $gleam_panic.LetAssert) { - let start = $.start; - let end = $.end; - let value = $.value; - return $string.concat( - toList([ - ((bold(red("let assert")) + " ") + location) + "\n", - ((((cyan(" test") + ": ") + module) + ".") + function$) + "\n", - code_snippet(src, start, end), - ((cyan("value") + ": ") + $string.inspect(value)) + "\n", - ((cyan(" info") + ": ") + error.message) + "\n", - ]), - ); - } else { - let start = $.start; - let end = $.end; - let kind = $.kind; - return $string.concat( - toList([ - ((bold(red("assert")) + " ") + location) + "\n", - ((((cyan(" test") + ": ") + module) + ".") + function$) + "\n", - code_snippet(src, start, end), - assert_info(kind), - ((cyan(" info") + ": ") + error.message) + "\n", - ]), - ); - } -} - -function read_file(path) { - let $ = read_file_text(path); - if ($ instanceof Ok) { - let text = $[0]; - return new Ok($bit_array.from_string(text)); - } else { - return $; - } -} - -export function test_failed(state, module, function$, error) { - let _block; - let $ = $gleam_panic.from_dynamic(error); - if ($ instanceof Ok) { - let error$1 = $[0]; - let src = $option.from_result(read_file(error$1.file)); - _block = format_gleam_error(error$1, module, function$, src); - } else { - _block = format_unknown(module, function$, error); - } - let message = _block; - $io.print("\n" + message); - return new State(state.passed, state.failed + 1, state.skipped); -} diff --git a/build/dev/javascript/gleeunit/gleeunit/should.mjs b/build/dev/javascript/gleeunit/gleeunit/should.mjs deleted file mode 100644 index c34c700..0000000 --- a/build/dev/javascript/gleeunit/gleeunit/should.mjs +++ /dev/null @@ -1,135 +0,0 @@ -import * as $option from "../../gleam_stdlib/gleam/option.mjs"; -import { None, Some } from "../../gleam_stdlib/gleam/option.mjs"; -import * as $string from "../../gleam_stdlib/gleam/string.mjs"; -import { Ok, Error, toList, makeError, isEqual } from "../gleam.mjs"; - -const FILEPATH = "src/gleeunit/should.gleam"; - -export function equal(a, b) { - let $ = isEqual(a, b); - if ($) { - return undefined; - } else { - throw makeError( - "panic", - FILEPATH, - "gleeunit/should", - 10, - "equal", - $string.concat( - toList([ - "\n", - $string.inspect(a), - "\nshould equal\n", - $string.inspect(b), - ]), - ), - {} - ) - } -} - -export function not_equal(a, b) { - let $ = !isEqual(a, b); - if ($) { - return undefined; - } else { - throw makeError( - "panic", - FILEPATH, - "gleeunit/should", - 23, - "not_equal", - $string.concat( - toList([ - "\n", - $string.inspect(a), - "\nshould not equal\n", - $string.inspect(b), - ]), - ), - {} - ) - } -} - -export function be_ok(a) { - if (a instanceof Ok) { - let value = a[0]; - return value; - } else { - throw makeError( - "panic", - FILEPATH, - "gleeunit/should", - 35, - "be_ok", - $string.concat(toList(["\n", $string.inspect(a), "\nshould be ok"])), - {} - ) - } -} - -export function be_error(a) { - if (a instanceof Error) { - let error = a[0]; - return error; - } else { - throw makeError( - "panic", - FILEPATH, - "gleeunit/should", - 42, - "be_error", - $string.concat(toList(["\n", $string.inspect(a), "\nshould be error"])), - {} - ) - } -} - -export function be_some(a) { - if (a instanceof Some) { - let value = a[0]; - return value; - } else { - throw makeError( - "panic", - FILEPATH, - "gleeunit/should", - 49, - "be_some", - $string.concat(toList(["\n", $string.inspect(a), "\nshould be some"])), - {} - ) - } -} - -export function be_none(a) { - if (a instanceof None) { - return undefined; - } else { - throw makeError( - "panic", - FILEPATH, - "gleeunit/should", - 56, - "be_none", - $string.concat(toList(["\n", $string.inspect(a), "\nshould be none"])), - {} - ) - } -} - -export function be_true(actual) { - let _pipe = actual; - return equal(_pipe, true); -} - -export function be_false(actual) { - let _pipe = actual; - return equal(_pipe, false); -} - -export function fail() { - return be_true(false); -} diff --git a/build/dev/javascript/gleeunit/gleeunit@internal@gleam_panic.erl b/build/dev/javascript/gleeunit/gleeunit@internal@gleam_panic.erl deleted file mode 100644 index 398ea7d..0000000 --- a/build/dev/javascript/gleeunit/gleeunit@internal@gleam_panic.erl +++ /dev/null @@ -1,56 +0,0 @@ --module(gleeunit@internal@gleam_panic). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "src/gleeunit/internal/gleam_panic.gleam"). --export([from_dynamic/1]). --export_type([gleam_panic/0, panic_kind/0, assert_kind/0, asserted_expression/0, expression_kind/0]). - --if(?OTP_RELEASE >= 27). --define(MODULEDOC(Str), -moduledoc(Str)). --define(DOC(Str), -doc(Str)). --else. --define(MODULEDOC(Str), -compile([])). --define(DOC(Str), -compile([])). --endif. - -?MODULEDOC(false). - --type gleam_panic() :: {gleam_panic, - binary(), - binary(), - binary(), - binary(), - integer(), - panic_kind()}. - --type panic_kind() :: todo | - panic | - {let_assert, - integer(), - integer(), - integer(), - integer(), - gleam@dynamic:dynamic_()} | - {assert, integer(), integer(), integer(), assert_kind()}. - --type assert_kind() :: {binary_operator, - binary(), - asserted_expression(), - asserted_expression()} | - {function_call, list(asserted_expression())} | - {other_expression, asserted_expression()}. - --type asserted_expression() :: {asserted_expression, - integer(), - integer(), - expression_kind()}. - --type expression_kind() :: {literal, gleam@dynamic:dynamic_()} | - {expression, gleam@dynamic:dynamic_()} | - unevaluated. - --file("src/gleeunit/internal/gleam_panic.gleam", 49). -?DOC(false). --spec from_dynamic(gleam@dynamic:dynamic_()) -> {ok, gleam_panic()} | - {error, nil}. -from_dynamic(Data) -> - gleeunit_gleam_panic_ffi:from_dynamic(Data). diff --git a/build/dev/javascript/gleeunit/gleeunit@internal@reporting.erl b/build/dev/javascript/gleeunit/gleeunit@internal@reporting.erl deleted file mode 100644 index 8c37c79..0000000 --- a/build/dev/javascript/gleeunit/gleeunit@internal@reporting.erl +++ /dev/null @@ -1,343 +0,0 @@ --module(gleeunit@internal@reporting). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "src/gleeunit/internal/reporting.gleam"). --export([new_state/0, test_skipped/3, test_passed/1, finished/1, eunit_missing/0, test_failed/4]). --export_type([state/0]). - --if(?OTP_RELEASE >= 27). --define(MODULEDOC(Str), -moduledoc(Str)). --define(DOC(Str), -doc(Str)). --else. --define(MODULEDOC(Str), -compile([])). --define(DOC(Str), -compile([])). --endif. - -?MODULEDOC(false). - --type state() :: {state, integer(), integer(), integer()}. - --file("src/gleeunit/internal/reporting.gleam", 15). -?DOC(false). --spec new_state() -> state(). -new_state() -> - {state, 0, 0, 0}. - --file("src/gleeunit/internal/reporting.gleam", 207). -?DOC(false). --spec bold(binary()) -> binary(). -bold(Text) -> - <<<<"\x{001b}[1m"/utf8, Text/binary>>/binary, "\x{001b}[22m"/utf8>>. - --file("src/gleeunit/internal/reporting.gleam", 211). -?DOC(false). --spec cyan(binary()) -> binary(). -cyan(Text) -> - <<<<"\x{001b}[36m"/utf8, Text/binary>>/binary, "\x{001b}[39m"/utf8>>. - --file("src/gleeunit/internal/reporting.gleam", 191). -?DOC(false). --spec code_snippet(gleam@option:option(bitstring()), integer(), integer()) -> binary(). -code_snippet(Src, Start, End) -> - _pipe = begin - gleam@result:'try'( - gleam@option:to_result(Src, nil), - fun(Src@1) -> - gleam@result:'try'( - gleam_stdlib:bit_array_slice(Src@1, Start, End - Start), - fun(Snippet) -> - gleam@result:'try'( - gleam@bit_array:to_string(Snippet), - fun(Snippet@1) -> - Snippet@2 = <<<<<<(cyan(<<" code"/utf8>>))/binary, - ": "/utf8>>/binary, - Snippet@1/binary>>/binary, - "\n"/utf8>>, - {ok, Snippet@2} - end - ) - end - ) - end - ) - end, - gleam@result:unwrap(_pipe, <<""/utf8>>). - --file("src/gleeunit/internal/reporting.gleam", 215). -?DOC(false). --spec yellow(binary()) -> binary(). -yellow(Text) -> - <<<<"\x{001b}[33m"/utf8, Text/binary>>/binary, "\x{001b}[39m"/utf8>>. - --file("src/gleeunit/internal/reporting.gleam", 202). -?DOC(false). --spec test_skipped(state(), binary(), binary()) -> state(). -test_skipped(State, Module, Function) -> - gleam_stdlib:print( - <<<<<<<<"\n"/utf8, Module/binary>>/binary, "."/utf8>>/binary, - Function/binary>>/binary, - (yellow(<<" skipped"/utf8>>))/binary>> - ), - {state, - erlang:element(2, State), - erlang:element(3, State), - erlang:element(4, State) + 1}. - --file("src/gleeunit/internal/reporting.gleam", 219). -?DOC(false). --spec green(binary()) -> binary(). -green(Text) -> - <<<<"\x{001b}[32m"/utf8, Text/binary>>/binary, "\x{001b}[39m"/utf8>>. - --file("src/gleeunit/internal/reporting.gleam", 66). -?DOC(false). --spec test_passed(state()) -> state(). -test_passed(State) -> - gleam_stdlib:print(green(<<"."/utf8>>)), - {state, - erlang:element(2, State) + 1, - erlang:element(3, State), - erlang:element(4, State)}. - --file("src/gleeunit/internal/reporting.gleam", 223). -?DOC(false). --spec red(binary()) -> binary(). -red(Text) -> - <<<<"\x{001b}[31m"/utf8, Text/binary>>/binary, "\x{001b}[39m"/utf8>>. - --file("src/gleeunit/internal/reporting.gleam", 19). -?DOC(false). --spec finished(state()) -> integer(). -finished(State) -> - case State of - {state, 0, 0, 0} -> - gleam_stdlib:println(<<"\nNo tests found!"/utf8>>), - 1; - - {state, _, 0, 0} -> - Message = <<<<"\n"/utf8, - (erlang:integer_to_binary(erlang:element(2, State)))/binary>>/binary, - " passed, no failures"/utf8>>, - gleam_stdlib:println(green(Message)), - 0; - - {state, _, _, 0} -> - Message@1 = <<<<<<<<"\n"/utf8, - (erlang:integer_to_binary(erlang:element(2, State)))/binary>>/binary, - " passed, "/utf8>>/binary, - (erlang:integer_to_binary(erlang:element(3, State)))/binary>>/binary, - " failures"/utf8>>, - gleam_stdlib:println(red(Message@1)), - 1; - - {state, _, 0, _} -> - Message@2 = <<<<<<<<"\n"/utf8, - (erlang:integer_to_binary(erlang:element(2, State)))/binary>>/binary, - " passed, 0 failures, "/utf8>>/binary, - (erlang:integer_to_binary(erlang:element(4, State)))/binary>>/binary, - " skipped"/utf8>>, - gleam_stdlib:println(yellow(Message@2)), - 1; - - {state, _, _, _} -> - Message@3 = <<<<<<<<<<<<"\n"/utf8, - (erlang:integer_to_binary( - erlang:element(2, State) - ))/binary>>/binary, - " passed, "/utf8>>/binary, - (erlang:integer_to_binary(erlang:element(3, State)))/binary>>/binary, - " failures, "/utf8>>/binary, - (erlang:integer_to_binary(erlang:element(4, State)))/binary>>/binary, - " skipped"/utf8>>, - gleam_stdlib:println(red(Message@3)), - 1 - end. - --file("src/gleeunit/internal/reporting.gleam", 89). -?DOC(false). --spec eunit_missing() -> {ok, any()} | {error, nil}. -eunit_missing() -> - Message = <<(bold(red(<<"Error"/utf8>>)))/binary, - ": EUnit libraries not found. - -Your Erlang installation seems to be incomplete. If you installed Erlang using -a package manager ensure that you have installed the full Erlang -distribution instead of a stripped-down version. -"/utf8>>, - gleam_stdlib:print_error(Message), - {error, nil}. - --file("src/gleeunit/internal/reporting.gleam", 227). -?DOC(false). --spec grey(binary()) -> binary(). -grey(Text) -> - <<<<"\x{001b}[90m"/utf8, Text/binary>>/binary, "\x{001b}[39m"/utf8>>. - --file("src/gleeunit/internal/reporting.gleam", 100). -?DOC(false). --spec format_unknown(binary(), binary(), gleam@dynamic:dynamic_()) -> binary(). -format_unknown(Module, Function, Error) -> - erlang:list_to_binary( - [<<(grey(<<<>/binary, Function/binary>>))/binary, - "\n"/utf8>>, - <<"An unexpected error occurred:\n"/utf8>>, - <<"\n"/utf8>>, - <<<<" "/utf8, (gleam@string:inspect(Error))/binary>>/binary, - "\n"/utf8>>] - ). - --file("src/gleeunit/internal/reporting.gleam", 183). -?DOC(false). --spec inspect_value(gleeunit@internal@gleam_panic:asserted_expression()) -> binary(). -inspect_value(Value) -> - case erlang:element(4, Value) of - unevaluated -> - grey(<<"unevaluated"/utf8>>); - - {literal, _} -> - grey(<<"literal"/utf8>>); - - {expression, Value@1} -> - gleam@string:inspect(Value@1) - end. - --file("src/gleeunit/internal/reporting.gleam", 179). -?DOC(false). --spec assert_value( - binary(), - gleeunit@internal@gleam_panic:asserted_expression() -) -> binary(). -assert_value(Name, Value) -> - <<<<<<(cyan(Name))/binary, ": "/utf8>>/binary, - (inspect_value(Value))/binary>>/binary, - "\n"/utf8>>. - --file("src/gleeunit/internal/reporting.gleam", 160). -?DOC(false). --spec assert_info(gleeunit@internal@gleam_panic:assert_kind()) -> binary(). -assert_info(Kind) -> - case Kind of - {binary_operator, _, Left, Right} -> - erlang:list_to_binary( - [assert_value(<<" left"/utf8>>, Left), - assert_value(<<"right"/utf8>>, Right)] - ); - - {function_call, Arguments} -> - _pipe = Arguments, - _pipe@1 = gleam@list:index_map( - _pipe, - fun(E, I) -> - Number = gleam@string:pad_start( - erlang:integer_to_binary(I), - 5, - <<" "/utf8>> - ), - assert_value(Number, E) - end - ), - erlang:list_to_binary(_pipe@1); - - {other_expression, _} -> - <<""/utf8>> - end. - --file("src/gleeunit/internal/reporting.gleam", 113). -?DOC(false). --spec format_gleam_error( - gleeunit@internal@gleam_panic:gleam_panic(), - binary(), - binary(), - gleam@option:option(bitstring()) -) -> binary(). -format_gleam_error(Error, Module, Function, Src) -> - Location = grey( - <<<<(erlang:element(3, Error))/binary, ":"/utf8>>/binary, - (erlang:integer_to_binary(erlang:element(6, Error)))/binary>> - ), - case erlang:element(7, Error) of - panic -> - erlang:list_to_binary( - [<<<<<<(bold(red(<<"panic"/utf8>>)))/binary, " "/utf8>>/binary, - Location/binary>>/binary, - "\n"/utf8>>, - <<<<<<<<<<(cyan(<<" test"/utf8>>))/binary, ": "/utf8>>/binary, - Module/binary>>/binary, - "."/utf8>>/binary, - Function/binary>>/binary, - "\n"/utf8>>, - <<<<<<(cyan(<<" info"/utf8>>))/binary, ": "/utf8>>/binary, - (erlang:element(2, Error))/binary>>/binary, - "\n"/utf8>>] - ); - - todo -> - erlang:list_to_binary( - [<<<<<<(bold(yellow(<<"todo"/utf8>>)))/binary, " "/utf8>>/binary, - Location/binary>>/binary, - "\n"/utf8>>, - <<<<<<<<<<(cyan(<<" test"/utf8>>))/binary, ": "/utf8>>/binary, - Module/binary>>/binary, - "."/utf8>>/binary, - Function/binary>>/binary, - "\n"/utf8>>, - <<<<<<(cyan(<<" info"/utf8>>))/binary, ": "/utf8>>/binary, - (erlang:element(2, Error))/binary>>/binary, - "\n"/utf8>>] - ); - - {assert, Start, End, _, Kind} -> - erlang:list_to_binary( - [<<<<<<(bold(red(<<"assert"/utf8>>)))/binary, " "/utf8>>/binary, - Location/binary>>/binary, - "\n"/utf8>>, - <<<<<<<<<<(cyan(<<" test"/utf8>>))/binary, ": "/utf8>>/binary, - Module/binary>>/binary, - "."/utf8>>/binary, - Function/binary>>/binary, - "\n"/utf8>>, - code_snippet(Src, Start, End), - assert_info(Kind), - <<<<<<(cyan(<<" info"/utf8>>))/binary, ": "/utf8>>/binary, - (erlang:element(2, Error))/binary>>/binary, - "\n"/utf8>>] - ); - - {let_assert, Start@1, End@1, _, _, Value} -> - erlang:list_to_binary( - [<<<<<<(bold(red(<<"let assert"/utf8>>)))/binary, " "/utf8>>/binary, - Location/binary>>/binary, - "\n"/utf8>>, - <<<<<<<<<<(cyan(<<" test"/utf8>>))/binary, ": "/utf8>>/binary, - Module/binary>>/binary, - "."/utf8>>/binary, - Function/binary>>/binary, - "\n"/utf8>>, - code_snippet(Src, Start@1, End@1), - <<<<<<(cyan(<<"value"/utf8>>))/binary, ": "/utf8>>/binary, - (gleam@string:inspect(Value))/binary>>/binary, - "\n"/utf8>>, - <<<<<<(cyan(<<" info"/utf8>>))/binary, ": "/utf8>>/binary, - (erlang:element(2, Error))/binary>>/binary, - "\n"/utf8>>] - ) - end. - --file("src/gleeunit/internal/reporting.gleam", 71). -?DOC(false). --spec test_failed(state(), binary(), binary(), gleam@dynamic:dynamic_()) -> state(). -test_failed(State, Module, Function, Error) -> - Message = case gleeunit_gleam_panic_ffi:from_dynamic(Error) of - {ok, Error@1} -> - Src = gleam@option:from_result( - file:read_file(erlang:element(3, Error@1)) - ), - format_gleam_error(Error@1, Module, Function, Src); - - {error, _} -> - format_unknown(Module, Function, Error) - end, - gleam_stdlib:print(<<"\n"/utf8, Message/binary>>), - {state, - erlang:element(2, State), - erlang:element(3, State) + 1, - erlang:element(4, State)}. diff --git a/build/dev/javascript/gleeunit/gleeunit@should.erl b/build/dev/javascript/gleeunit/gleeunit@should.erl deleted file mode 100644 index 81048de..0000000 --- a/build/dev/javascript/gleeunit/gleeunit@should.erl +++ /dev/null @@ -1,153 +0,0 @@ --module(gleeunit@should). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "src/gleeunit/should.gleam"). --export([equal/2, not_equal/2, be_ok/1, be_error/1, be_some/1, be_none/1, be_true/1, be_false/1, fail/0]). - --if(?OTP_RELEASE >= 27). --define(MODULEDOC(Str), -moduledoc(Str)). --define(DOC(Str), -doc(Str)). --else. --define(MODULEDOC(Str), -compile([])). --define(DOC(Str), -compile([])). --endif. - -?MODULEDOC(" Use the `assert` keyword instead of this module.\n"). - --file("src/gleeunit/should.gleam", 6). --spec equal(DOF, DOF) -> nil. -equal(A, B) -> - case A =:= B of - true -> - nil; - - _ -> - erlang:error(#{gleam_error => panic, - message => erlang:list_to_binary( - [<<"\n"/utf8>>, - gleam@string:inspect(A), - <<"\nshould equal\n"/utf8>>, - gleam@string:inspect(B)] - ), - file => <>, - module => <<"gleeunit/should"/utf8>>, - function => <<"equal"/utf8>>, - line => 10}) - end. - --file("src/gleeunit/should.gleam", 19). --spec not_equal(DOG, DOG) -> nil. -not_equal(A, B) -> - case A /= B of - true -> - nil; - - _ -> - erlang:error(#{gleam_error => panic, - message => erlang:list_to_binary( - [<<"\n"/utf8>>, - gleam@string:inspect(A), - <<"\nshould not equal\n"/utf8>>, - gleam@string:inspect(B)] - ), - file => <>, - module => <<"gleeunit/should"/utf8>>, - function => <<"not_equal"/utf8>>, - line => 23}) - end. - --file("src/gleeunit/should.gleam", 32). --spec be_ok({ok, DOH} | {error, any()}) -> DOH. -be_ok(A) -> - case A of - {ok, Value} -> - Value; - - _ -> - erlang:error(#{gleam_error => panic, - message => erlang:list_to_binary( - [<<"\n"/utf8>>, - gleam@string:inspect(A), - <<"\nshould be ok"/utf8>>] - ), - file => <>, - module => <<"gleeunit/should"/utf8>>, - function => <<"be_ok"/utf8>>, - line => 35}) - end. - --file("src/gleeunit/should.gleam", 39). --spec be_error({ok, any()} | {error, DOM}) -> DOM. -be_error(A) -> - case A of - {error, Error} -> - Error; - - _ -> - erlang:error(#{gleam_error => panic, - message => erlang:list_to_binary( - [<<"\n"/utf8>>, - gleam@string:inspect(A), - <<"\nshould be error"/utf8>>] - ), - file => <>, - module => <<"gleeunit/should"/utf8>>, - function => <<"be_error"/utf8>>, - line => 42}) - end. - --file("src/gleeunit/should.gleam", 46). --spec be_some(gleam@option:option(DOP)) -> DOP. -be_some(A) -> - case A of - {some, Value} -> - Value; - - _ -> - erlang:error(#{gleam_error => panic, - message => erlang:list_to_binary( - [<<"\n"/utf8>>, - gleam@string:inspect(A), - <<"\nshould be some"/utf8>>] - ), - file => <>, - module => <<"gleeunit/should"/utf8>>, - function => <<"be_some"/utf8>>, - line => 49}) - end. - --file("src/gleeunit/should.gleam", 53). --spec be_none(gleam@option:option(any())) -> nil. -be_none(A) -> - case A of - none -> - nil; - - _ -> - erlang:error(#{gleam_error => panic, - message => erlang:list_to_binary( - [<<"\n"/utf8>>, - gleam@string:inspect(A), - <<"\nshould be none"/utf8>>] - ), - file => <>, - module => <<"gleeunit/should"/utf8>>, - function => <<"be_none"/utf8>>, - line => 56}) - end. - --file("src/gleeunit/should.gleam", 60). --spec be_true(boolean()) -> nil. -be_true(Actual) -> - _pipe = Actual, - equal(_pipe, true). - --file("src/gleeunit/should.gleam", 65). --spec be_false(boolean()) -> nil. -be_false(Actual) -> - _pipe = Actual, - equal(_pipe, false). - --file("src/gleeunit/should.gleam", 70). --spec fail() -> nil. -fail() -> - be_true(false). diff --git a/build/dev/javascript/gleeunit/gleeunit_ffi.erl b/build/dev/javascript/gleeunit/gleeunit_ffi.erl deleted file mode 100644 index 05c7490..0000000 --- a/build/dev/javascript/gleeunit/gleeunit_ffi.erl +++ /dev/null @@ -1,21 +0,0 @@ --module(gleeunit_ffi). - --export([find_files/2, run_eunit/2]). - -find_files(Pattern, In) -> - Results = filelib:wildcard(binary_to_list(Pattern), binary_to_list(In)), - lists:map(fun list_to_binary/1, Results). - -run_eunit(Tests, Options) -> - case code:which(eunit) of - non_existing -> - gleeunit@internal@reporting:eunit_missing(); - - _ -> - case eunit:test(Tests, Options) of - ok -> {ok, nil}; - error -> {error, nil}; - {error, Term} -> {error, Term} - end - end. - diff --git a/build/dev/javascript/gleeunit/gleeunit_ffi.mjs b/build/dev/javascript/gleeunit/gleeunit_ffi.mjs deleted file mode 100644 index 7bdc071..0000000 --- a/build/dev/javascript/gleeunit/gleeunit_ffi.mjs +++ /dev/null @@ -1,100 +0,0 @@ -import { readFileSync } from "node:fs"; -import { Result$Ok, Result$Error } from "./gleam.mjs"; -import * as reporting from "./gleeunit/internal/reporting.mjs"; - -export function read_file(path) { - try { - return Result$Ok(readFileSync(path)); - } catch { - return Result$Error(undefined); - } -} - -async function* gleamFiles(directory) { - for (let entry of await read_dir(directory)) { - let path = join_path(directory, entry); - if (path.endsWith(".gleam")) { - yield path; - } else { - try { - yield* gleamFiles(path); - } catch (error) { - // Could not read directory, assume it's a file - } - } - } -} - -async function readRootPackageName() { - let toml = await async_read_file("gleam.toml", "utf-8"); - for (let line of toml.split("\n")) { - let matches = line.match(/\s*name\s*=\s*"([a-z][a-z0-9_]*)"/); // Match regexp in compiler-cli/src/new.rs in validate_name() - if (matches) return matches[1]; - } - throw new Error("Could not determine package name from gleam.toml"); -} - -export async function main() { - let state = reporting.new_state(); - - let packageName = await readRootPackageName(); - let dist = `../${packageName}/`; - - for await (let path of await gleamFiles("test")) { - let js_path = path.slice("test/".length).replace(".gleam", ".mjs"); - let module = await import(join_path(dist, js_path)); - for (let fnName of Object.keys(module)) { - if (!fnName.endsWith("_test")) continue; - try { - await module[fnName](); - state = reporting.test_passed(state); - } catch (error) { - let moduleName = js_path.slice(0, -4); - state = reporting.test_failed(state, moduleName, fnName, error); - } - } - } - - const status = reporting.finished(state); - exit(status); -} - -export function crash(message) { - throw new Error(message); -} - -function exit(code) { - if (globalThis.Deno) { - Deno.exit(code); - } else { - process.exit(code); - } -} - -async function read_dir(path) { - if (globalThis.Deno) { - let items = []; - for await (let item of Deno.readDir(path, { withFileTypes: true })) { - items.push(item.name); - } - return items; - } else { - let { readdir } = await import("node:fs/promises"); - return readdir(path); - } -} - -function join_path(a, b) { - if (a.endsWith("/")) return a + b; - return a + "/" + b; -} - -async function async_read_file(path) { - if (globalThis.Deno) { - return Deno.readTextFile(path); - } else { - let { readFile } = await import("node:fs/promises"); - let contents = await readFile(path); - return contents.toString(); - } -} diff --git a/build/dev/javascript/gleeunit/gleeunit_progress.erl b/build/dev/javascript/gleeunit/gleeunit_progress.erl deleted file mode 100644 index e6576a5..0000000 --- a/build/dev/javascript/gleeunit/gleeunit_progress.erl +++ /dev/null @@ -1,72 +0,0 @@ -%% A formatter adapted from Sean Cribb's https://github.com/seancribbs/eunit_formatters - --module(gleeunit_progress). --define(NOTEST, true). - -%% eunit_listener callbacks --export([ - init/1, handle_begin/3, handle_end/3, handle_cancel/3, terminate/2, - start/0, start/1 -]). - --define(reporting, gleeunit@internal@reporting). - -start() -> - start([]). - -start(Options) -> - eunit_listener:start(?MODULE, Options). - -init(_Options) -> - ?reporting:new_state(). - -handle_begin(_test_or_group, _data, State) -> - State. - -handle_end(group, _data, State) -> - State; -handle_end(test, Data, State) -> - {AtomModule, AtomFunction, _Arity} = proplists:get_value(source, Data), - Module = erlang:atom_to_binary(AtomModule), - Function = erlang:atom_to_binary(AtomFunction), - - % EUnit swallows stdout, so print it to make debugging easier. - case proplists:get_value(output, Data) of - undefined -> ok; - <<>> -> ok; - Out -> gleam@io:print(Out) - end, - - case proplists:get_value(status, Data) of - ok -> - ?reporting:test_passed(State); - {skipped, _Reason} -> - ?reporting:test_skipped(State, Module, Function); - {error, {_, Exception, _Stack}} -> - ?reporting:test_failed(State, Module, Function, Exception) - end. - - -handle_cancel(_test_or_group, Data, State) -> - ?reporting:test_failed(State, <<"gleeunit">>, <<"main">>, Data). - -terminate({ok, _Data}, State) -> - ?reporting:finished(State), - ok; -terminate({error, Reason}, State) -> - ?reporting:finished(State), - io:fwrite(" -Eunit failed: - -~80p - -This is probably a bug in gleeunit. Please report it. -", [Reason]), - sync_end(error). - -sync_end(Result) -> - receive - {stop, Reference, ReplyTo} -> - ReplyTo ! {result, Reference, Result}, - ok - end. diff --git a/build/dev/javascript/paint/_gleam_artefacts/paint.cache b/build/dev/javascript/paint/_gleam_artefacts/paint.cache deleted file mode 100644 index 1855215..0000000 Binary files a/build/dev/javascript/paint/_gleam_artefacts/paint.cache and /dev/null differ diff --git a/build/dev/javascript/paint/_gleam_artefacts/paint.cache_inline b/build/dev/javascript/paint/_gleam_artefacts/paint.cache_inline deleted file mode 100644 index 1b1cb4d..0000000 Binary files a/build/dev/javascript/paint/_gleam_artefacts/paint.cache_inline and /dev/null differ diff --git a/build/dev/javascript/paint/_gleam_artefacts/paint.cache_meta b/build/dev/javascript/paint/_gleam_artefacts/paint.cache_meta deleted file mode 100644 index 10507bd..0000000 Binary files a/build/dev/javascript/paint/_gleam_artefacts/paint.cache_meta and /dev/null differ diff --git a/build/dev/javascript/paint/_gleam_artefacts/paint@canvas.cache b/build/dev/javascript/paint/_gleam_artefacts/paint@canvas.cache deleted file mode 100644 index 315922b..0000000 Binary files a/build/dev/javascript/paint/_gleam_artefacts/paint@canvas.cache and /dev/null differ diff --git a/build/dev/javascript/paint/_gleam_artefacts/paint@canvas.cache_inline b/build/dev/javascript/paint/_gleam_artefacts/paint@canvas.cache_inline deleted file mode 100644 index 1b1cb4d..0000000 Binary files a/build/dev/javascript/paint/_gleam_artefacts/paint@canvas.cache_inline and /dev/null differ diff --git a/build/dev/javascript/paint/_gleam_artefacts/paint@canvas.cache_meta b/build/dev/javascript/paint/_gleam_artefacts/paint@canvas.cache_meta deleted file mode 100644 index 25fa8d6..0000000 Binary files a/build/dev/javascript/paint/_gleam_artefacts/paint@canvas.cache_meta and /dev/null differ diff --git a/build/dev/javascript/paint/_gleam_artefacts/paint@encode.cache b/build/dev/javascript/paint/_gleam_artefacts/paint@encode.cache deleted file mode 100644 index ab7aec2..0000000 Binary files a/build/dev/javascript/paint/_gleam_artefacts/paint@encode.cache and /dev/null differ diff --git a/build/dev/javascript/paint/_gleam_artefacts/paint@encode.cache_inline b/build/dev/javascript/paint/_gleam_artefacts/paint@encode.cache_inline deleted file mode 100644 index 1b1cb4d..0000000 Binary files a/build/dev/javascript/paint/_gleam_artefacts/paint@encode.cache_inline and /dev/null differ diff --git a/build/dev/javascript/paint/_gleam_artefacts/paint@encode.cache_meta b/build/dev/javascript/paint/_gleam_artefacts/paint@encode.cache_meta deleted file mode 100644 index a0d8583..0000000 Binary files a/build/dev/javascript/paint/_gleam_artefacts/paint@encode.cache_meta and /dev/null differ diff --git a/build/dev/javascript/paint/_gleam_artefacts/paint@event.cache b/build/dev/javascript/paint/_gleam_artefacts/paint@event.cache deleted file mode 100644 index 787d70d..0000000 Binary files a/build/dev/javascript/paint/_gleam_artefacts/paint@event.cache and /dev/null differ diff --git a/build/dev/javascript/paint/_gleam_artefacts/paint@event.cache_inline b/build/dev/javascript/paint/_gleam_artefacts/paint@event.cache_inline deleted file mode 100644 index 1b1cb4d..0000000 Binary files a/build/dev/javascript/paint/_gleam_artefacts/paint@event.cache_inline and /dev/null differ diff --git a/build/dev/javascript/paint/_gleam_artefacts/paint@event.cache_meta b/build/dev/javascript/paint/_gleam_artefacts/paint@event.cache_meta deleted file mode 100644 index 6aaec3a..0000000 Binary files a/build/dev/javascript/paint/_gleam_artefacts/paint@event.cache_meta and /dev/null differ diff --git a/build/dev/javascript/paint/_gleam_artefacts/paint@internal@impl_canvas.cache b/build/dev/javascript/paint/_gleam_artefacts/paint@internal@impl_canvas.cache deleted file mode 100644 index f7d3a72..0000000 Binary files a/build/dev/javascript/paint/_gleam_artefacts/paint@internal@impl_canvas.cache and /dev/null differ diff --git a/build/dev/javascript/paint/_gleam_artefacts/paint@internal@impl_canvas.cache_inline b/build/dev/javascript/paint/_gleam_artefacts/paint@internal@impl_canvas.cache_inline deleted file mode 100644 index 1b1cb4d..0000000 Binary files a/build/dev/javascript/paint/_gleam_artefacts/paint@internal@impl_canvas.cache_inline and /dev/null differ diff --git a/build/dev/javascript/paint/_gleam_artefacts/paint@internal@impl_canvas.cache_meta b/build/dev/javascript/paint/_gleam_artefacts/paint@internal@impl_canvas.cache_meta deleted file mode 100644 index db2fae1..0000000 Binary files a/build/dev/javascript/paint/_gleam_artefacts/paint@internal@impl_canvas.cache_meta and /dev/null differ diff --git a/build/dev/javascript/paint/_gleam_artefacts/paint@internal@types.cache b/build/dev/javascript/paint/_gleam_artefacts/paint@internal@types.cache deleted file mode 100644 index 72e9025..0000000 Binary files a/build/dev/javascript/paint/_gleam_artefacts/paint@internal@types.cache and /dev/null differ diff --git a/build/dev/javascript/paint/_gleam_artefacts/paint@internal@types.cache_inline b/build/dev/javascript/paint/_gleam_artefacts/paint@internal@types.cache_inline deleted file mode 100644 index 1b1cb4d..0000000 Binary files a/build/dev/javascript/paint/_gleam_artefacts/paint@internal@types.cache_inline and /dev/null differ diff --git a/build/dev/javascript/paint/_gleam_artefacts/paint@internal@types.cache_meta b/build/dev/javascript/paint/_gleam_artefacts/paint@internal@types.cache_meta deleted file mode 100644 index b521eae..0000000 Binary files a/build/dev/javascript/paint/_gleam_artefacts/paint@internal@types.cache_meta and /dev/null differ diff --git a/build/dev/javascript/paint/gleam.mjs b/build/dev/javascript/paint/gleam.mjs deleted file mode 100644 index 197cbbc..0000000 --- a/build/dev/javascript/paint/gleam.mjs +++ /dev/null @@ -1 +0,0 @@ -export * from "../prelude.mjs"; diff --git a/build/dev/javascript/paint/impl_canvas_bindings.mjs b/build/dev/javascript/paint/impl_canvas_bindings.mjs deleted file mode 100644 index 5fed16a..0000000 --- a/build/dev/javascript/paint/impl_canvas_bindings.mjs +++ /dev/null @@ -1,271 +0,0 @@ -import { Ok, Error } from "./gleam.mjs"; - -class PaintCanvas extends HTMLElement { - // Open an issue if you are in need of any other attributes :) - static observedAttributes = ["width", "height", "style", "picture"]; - - constructor() { - super(); - // Create a canvas - this.canvas = document.createElement("canvas"); - const style = document.createElement("style"); - style.textContent = ` - :host { - display: inline-block; - } - `; - this.shadow = this.attachShadow({ mode: "open" }); - this.shadow.appendChild(style); - this.shadow.appendChild(this.canvas); - this.ctx = this.canvas.getContext("2d"); - } - - attributeChangedCallback(name, _oldValue, newValue) { - if (name === "picture") { - this.picture = newValue; - return; - } else if (name === "width") { - this.width = newValue; - } else if (name === "height") { - this.height = newValue; - } - } - - drawPicture() { - if (!this.pictureString) { - return; - } - - this.ctx.reset(); - const display = - window.PAINT_STATE[ - "display_on_rendering_context_with_default_drawing_state" - ]; - - display(this.pictureString, this.ctx); - } - - set picture(value) { - this.pictureString = value; - this.drawPicture(); - } - - set width(value) { - this.canvas.width = value; - this.drawPicture(); - } - - set height(value) { - this.canvas.height = value; - this.drawPicture(); - } - - get width() { - return this.canvas.width; - } - - get height() { - return this.canvas.height; - } -} - -export function define_web_component() { - window.customElements.define("paint-canvas", PaintCanvas); -} - -export function get_rendering_context(selector) { - // TODO: Handle the case where the canvas element is not found. - return document.querySelector(selector).getContext("2d"); -} - -export function setup_request_animation_frame(callback) { - window.requestAnimationFrame((time) => { - callback(time); - }); -} - -export function setup_input_handler(event_name, callback) { - window.addEventListener(event_name, callback); -} - -export function get_key_code(event) { - return event.keyCode; -} - -export function set_global(state, id) { - if (typeof window.PAINT_STATE == "undefined") { - window.PAINT_STATE = {}; - } - window.PAINT_STATE[id] = state; -} - -export function get_global(id) { - if (!window.PAINT_STATE) { - return new Error(undefined); - } - if (!(id in window.PAINT_STATE)) { - return new Error(undefined); - } - return new Ok(window.PAINT_STATE[id]); -} - -export function get_width(ctx) { - return ctx.canvas.clientWidth; -} - -export function get_height(ctx) { - return ctx.canvas.clientHeight; -} - -// Based on https://stackoverflow.com/questions/17130395/real-mouse-position-in-canvas -export function mouse_pos(ctx, event) { - // Calculate the scaling of the canvas vs its content - const rect = ctx.canvas.getBoundingClientRect(); - const scaleX = ctx.canvas.width / rect.width; - const scaleY = ctx.canvas.height / rect.height; - - return [ - (event.clientX - rect.left) * scaleX, - (event.clientY - rect.top) * scaleY, - ]; -} - -// if check_pressed is true, the function will return true if the button was pressed -// if check_pressed is false, the function will return true if the button was released -export function check_mouse_button( - event, - previous_event, - button_index, - check_pressed, -) { - let previous_buttons = previous_event?.buttons ?? 0; - let current_buttons = event.buttons; - - // ~001 && - // 011 - // ----- - // 010 found the newly pressed! - // - // 011 && - // ~001 - // ----- - // 010 found the newly released! - if (check_pressed) { - previous_buttons = ~previous_buttons; - } else { - current_buttons = ~current_buttons; - } - - let button = previous_buttons & current_buttons & (1 << button_index); - return !!button; -} - -export function reset(ctx) { - ctx.reset(); -} - -export function arc(ctx, radius, start, end, fill, stroke) { - ctx.beginPath(); - ctx.arc(0, 0, radius, start, end); - if (fill) { - ctx.fill(); - } - if (stroke) { - ctx.stroke(); - } -} - -export function polygon(ctx, points, closed, fill, stroke) { - ctx.beginPath(); - ctx.moveTo(0, 0); - let started = false; - for (const point of points) { - let x = point[0]; - let y = point[1]; - if (started) { - ctx.lineTo(x, y); - } else { - ctx.moveTo(x, y); - started = true; - } - } - - if (closed) { - ctx.closePath(); - } - - if (fill && closed) { - ctx.fill(); - } - - if (stroke) { - ctx.stroke(); - } -} - -export function text(ctx, text, style) { - ctx.font = style; - ctx.fillText(text, 0, 0); -} - -export function save(ctx) { - ctx.save(); -} - -export function restore(ctx) { - ctx.restore(); -} - -export function set_fill_colour(ctx, css_colour) { - ctx.fillStyle = css_colour; -} - -export function set_stroke_color(ctx, css_color) { - ctx.strokeStyle = css_color; -} - -export function set_line_width(ctx, width) { - ctx.lineWidth = width; -} - -export function translate(ctx, x, y) { - ctx.translate(x, y); -} - -export function scale(ctx, x, y) { - ctx.scale(x, y); -} - -export function rotate(ctx, radians) { - ctx.rotate(radians); -} - -export function reset_transform(ctx) { - ctx.resetTransform(); -} - -export function draw_image(ctx, image, width_px, height_px) { - ctx.drawImage(image, 0, 0, width_px, height_px); -} - -export function image_from_query(selector) { - return document.querySelector(selector); -} - -export function image_from_src(src) { - const image = new Image(); - image.src = src; - return image; -} - -export function on_image_load(image, callback) { - if (image.complete) { - callback(); - } else { - image.addEventListener("load", callback); - } -} - -export function set_image_smoothing_enabled(ctx, value) { - ctx.imageSmoothingEnabled = value; -} diff --git a/build/dev/javascript/paint/numbers_ffi.mjs b/build/dev/javascript/paint/numbers_ffi.mjs deleted file mode 100644 index 0e6e6d3..0000000 --- a/build/dev/javascript/paint/numbers_ffi.mjs +++ /dev/null @@ -1,3 +0,0 @@ -export function pi() { - return Math.PI; -} diff --git a/build/dev/javascript/paint/paint.mjs b/build/dev/javascript/paint/paint.mjs deleted file mode 100644 index ba06945..0000000 --- a/build/dev/javascript/paint/paint.mjs +++ /dev/null @@ -1,246 +0,0 @@ -import * as $colour from "../gleam_community_colour/gleam_community/colour.mjs"; -import * as $result from "../gleam_stdlib/gleam/result.mjs"; -import { toList, makeError } from "./gleam.mjs"; -import { pi } from "./numbers_ffi.mjs"; -import * as $internal_implementation from "./paint/internal/types.mjs"; - -const FILEPATH = "src/paint.gleam"; - -/** - * Create an angle expressed in radians - */ -export function angle_rad(radians) { - return new $internal_implementation.Radians(radians); -} - -/** - * A utility around [colour.from_rgb_hex_string](https://hexdocs.pm/gleam_community_colour/gleam_community/colour.html#from_rgb_hex_string) - * (from `gleam_community/colour`) that **panics** on an invalid hex code. - */ -export function colour_hex(string) { - return $result.lazy_unwrap( - $colour.from_rgb_hex_string(string), - () => { - throw makeError( - "panic", - FILEPATH, - "paint", - 47, - "colour_hex", - "Failed to parse hex code", - {} - ) - }, - ); -} - -/** - * A utility around [colour.from_rgb255](https://hexdocs.pm/gleam_community_colour/gleam_community/colour.html#from_rgb255) - * (from `gleam_community/colour`) that **panics** if the values are outside of the allowed range. - */ -export function colour_rgb(red, green, blue) { - return $result.lazy_unwrap( - $colour.from_rgb255(red, green, blue), - () => { - throw makeError( - "panic", - FILEPATH, - "paint", - 55, - "colour_rgb", - "The value was not inside of the valid range [0-255]", - {} - ) - }, - ); -} - -/** - * A blank picture - */ -export function blank() { - return new $internal_implementation.Blank(); -} - -/** - * An arc with some radius going from some - * starting angle to some other angle in clock-wise direction - */ -export function arc(radius, start, end) { - return new $internal_implementation.Arc(radius, start, end); -} - -/** - * A polygon consisting of a list of 2d points - */ -export function polygon(points) { - return new $internal_implementation.Polygon(points, true); -} - -/** - * Lines (same as a polygon but not a closed shape) - */ -export function lines(points) { - return new $internal_implementation.Polygon(points, false); -} - -/** - * A rectangle with some given width and height - */ -export function rectangle(width, height) { - return polygon( - toList([[0.0, 0.0], [width, 0.0], [width, height], [0.0, height]]), - ); -} - -/** - * A square - */ -export function square(length) { - return rectangle(length, length); -} - -/** - * Draw an image such as a PNG, JPEG or an SVG. See the `canvas` back-end for more details on how to load images. - */ -export function image(image, width_px, height_px) { - return new $internal_implementation.ImageRef(image, width_px, height_px); -} - -/** - * Set image scaling to be smooth (this is the default behaviour) - */ -export function image_scaling_smooth(picture) { - return new $internal_implementation.ImageScalingBehaviour( - picture, - new $internal_implementation.ScalingSmooth(), - ); -} - -/** - * Disable smooth image scaling, suitable for pixel art. - */ -export function image_scaling_pixelated(picture) { - return new $internal_implementation.ImageScalingBehaviour( - picture, - new $internal_implementation.ScalingPixelated(), - ); -} - -/** - * Text with some given font size - */ -export function text(text, font_size) { - return new $internal_implementation.Text( - text, - new $internal_implementation.FontProperties(font_size, "sans-serif"), - ); -} - -/** - * Translate a picture in horizontal and vertical direction - */ -export function translate_xy(picture, x, y) { - return new $internal_implementation.Translate(picture, [x, y]); -} - -/** - * Translate a picture in the horizontal direction - */ -export function translate_x(picture, x) { - return translate_xy(picture, x, 0.0); -} - -/** - * Translate a picture in the vertical direction - */ -export function translate_y(picture, y) { - return translate_xy(picture, 0.0, y); -} - -/** - * Scale the picture in the horizontal direction - */ -export function scale_x(picture, factor) { - return new $internal_implementation.Scale(picture, [factor, 1.0]); -} - -/** - * Scale the picture in the vertical direction - */ -export function scale_y(picture, factor) { - return new $internal_implementation.Scale(picture, [1.0, factor]); -} - -/** - * Scale the picture uniformly in horizontal and vertical direction - */ -export function scale_uniform(picture, factor) { - return new $internal_implementation.Scale(picture, [factor, factor]); -} - -/** - * Rotate the picture in a clock-wise direction - */ -export function rotate(picture, angle) { - return new $internal_implementation.Rotate(picture, angle); -} - -/** - * Fill a picture with some given colour, see `Colour`. - */ -export function fill(picture, colour) { - return new $internal_implementation.Fill(picture, colour); -} - -/** - * Set a solid stroke with some given colour and width - */ -export function stroke(picture, colour, width) { - return new $internal_implementation.Stroke( - picture, - new $internal_implementation.SolidStroke(colour, width), - ); -} - -/** - * Remove the stroke of the given picture - */ -export function stroke_none(picture) { - return new $internal_implementation.Stroke( - picture, - new $internal_implementation.NoStroke(), - ); -} - -/** - * Combine multiple pictures into one - */ -export function combine(pictures) { - return new $internal_implementation.Combine(pictures); -} - -/** - * Concatenate two pictures - */ -export function concat(picture, another_picture) { - return combine(toList([picture, another_picture])); -} - -/** - * Create an angle expressed in degrees - */ -export function angle_deg(degrees) { - return new $internal_implementation.Radians(((degrees * pi())) / 180.0); -} - -/** - * A circle with some given radius - */ -export function circle(radius) { - return new $internal_implementation.Arc( - radius, - new $internal_implementation.Radians(0.0), - new $internal_implementation.Radians(2.0 * pi()), - ); -} diff --git a/build/dev/javascript/paint/paint/canvas.mjs b/build/dev/javascript/paint/paint/canvas.mjs deleted file mode 100644 index 1bb61c7..0000000 --- a/build/dev/javascript/paint/paint/canvas.mjs +++ /dev/null @@ -1,655 +0,0 @@ -import * as $colour from "../../gleam_community_colour/gleam_community/colour.mjs"; -import * as $int from "../../gleam_stdlib/gleam/int.mjs"; -import * as $option from "../../gleam_stdlib/gleam/option.mjs"; -import { None, Some } from "../../gleam_stdlib/gleam/option.mjs"; -import { Ok, Empty as $Empty, CustomType as $CustomType, makeError } from "../gleam.mjs"; -import * as $paint from "../paint.mjs"; -import { translate_xy } from "../paint.mjs"; -import * as $encode from "../paint/encode.mjs"; -import * as $event from "../paint/event.mjs"; -import * as $impl_canvas from "../paint/internal/impl_canvas.mjs"; -import * as $types from "../paint/internal/types.mjs"; -import { - Arc, - Blank, - Combine, - Fill, - FontProperties, - Image, - NoStroke, - Polygon, - Radians, - Rotate, - Scale, - SolidStroke, - Stroke, - Text, - Translate, -} from "../paint/internal/types.mjs"; - -const FILEPATH = "src/paint/canvas.gleam"; - -export class Config extends $CustomType { - constructor(width, height) { - super(); - this.width = width; - this.height = height; - } -} -export const Config$Config = (width, height) => new Config(width, height); -export const Config$isConfig = (value) => value instanceof Config; -export const Config$Config$width = (value) => value.width; -export const Config$Config$0 = (value) => value.width; -export const Config$Config$height = (value) => value.height; -export const Config$Config$1 = (value) => value.height; - -class DrawingState extends $CustomType { - constructor(fill, stroke) { - super(); - this.fill = fill; - this.stroke = stroke; - } -} - -/** - * Create a reference to an image using a CSS query selector. For example: - * ``` - * fn kitten() { - * canvas.image_from_query("#kitten") - * } - * // In the HTML file: - * // - * ``` - * - * > [!WARNING] - * > **Important**: Make sure the image has loaded before trying to draw a pictures referencing it. - * > You can do this using `canvas.wait_until_loaded` function. - */ -export function image_from_query(selector) { - let id = "image-selector-" + selector; - let $ = $impl_canvas.get_global(id); - if ($ instanceof Ok) { - undefined - } else { - let image = $impl_canvas.image_from_query(selector); - $impl_canvas.set_global(image, id) - } - return new Image(id); -} - -/** - * Create a reference to an image using a source path. - * ``` - * fn my_logo_image() { - * canvas.image_from_src("./priv/static/logo.svg") - * } - * ``` - * - * > [!WARNING] - * > **Important**: Make sure the image has loaded before trying to draw a pictures referencing it. - * > You can do this using `canvas.wait_until_loaded` function. - */ -export function image_from_src(src) { - let id = "image-src-" + src; - let $ = $impl_canvas.get_global(id); - if ($ instanceof Ok) { - undefined - } else { - let image = $impl_canvas.image_from_src(src); - $impl_canvas.set_global(image, id) - } - return new Image(id); -} - -/** - * Wait until a list of images have all been loaded, for example: - * ``` - * fn lucy() { - * canvas.image_from_query("#lucy") - * } - * - * fn cat() { - * canvas.image_from_src("./path/to/kitten.png") - * } - * - * pub fn main() { - * use <- canvas.wait_until_loaded([lucy(), kitten()]) - * // It is now safe to draw Pictures containing the images lucy and kitten :) - * } - * ``` - */ -export function wait_until_loaded(images, on_loaded) { - if (images instanceof $Empty) { - return on_loaded(); - } else { - let image = images.head; - let rest = images.tail; - let id; - id = image.id; - let $ = $impl_canvas.get_global(id); - let js_image; - if ($ instanceof Ok) { - js_image = $[0]; - } else { - throw makeError( - "let_assert", - FILEPATH, - "paint/canvas", - 101, - "wait_until_loaded", - "Pattern match failed, no pattern matched the value.", - { - value: $, - start: 3025, - end: 3077, - pattern_start: 3036, - pattern_end: 3048 - } - ) - } - return $impl_canvas.on_image_load( - js_image, - () => { return wait_until_loaded(rest, on_loaded); }, - ); - } -} - -function display_on_rendering_context(loop$picture, loop$ctx, loop$state) { - while (true) { - let picture = loop$picture; - let ctx = loop$ctx; - let state = loop$state; - if (picture instanceof Blank) { - return undefined; - } else if (picture instanceof Polygon) { - let points = picture[0]; - let closed = picture.closed; - return $impl_canvas.polygon(ctx, points, closed, state.fill, state.stroke); - } else if (picture instanceof Arc) { - let radius = picture.radius; - let start = picture.start; - let end = picture.end; - let start_radians; - start_radians = start[0]; - let end_radians; - end_radians = end[0]; - return $impl_canvas.arc( - ctx, - radius, - start_radians, - end_radians, - state.fill, - state.stroke, - ); - } else if (picture instanceof Text) { - let text = picture.text; - let properties = picture.style; - let size_px; - let font_family; - size_px = properties.size_px; - font_family = properties.font_family; - $impl_canvas.save(ctx); - $impl_canvas.text( - ctx, - text, - ($int.to_string(size_px) + "px ") + font_family, - ); - return $impl_canvas.restore(ctx); - } else if (picture instanceof $types.ImageRef) { - let width_px = picture.width_px; - let height_px = picture.height_px; - let id = picture[0].id; - let $ = $impl_canvas.get_global(id); - let image; - if ($ instanceof Ok) { - image = $[0]; - } else { - throw makeError( - "let_assert", - FILEPATH, - "paint/canvas", - 231, - "display_on_rendering_context", - "Pattern match failed, no pattern matched the value.", - { - value: $, - start: 6608, - end: 6657, - pattern_start: 6619, - pattern_end: 6628 - } - ) - } - return $impl_canvas.draw_image(ctx, image, width_px, height_px); - } else if (picture instanceof Fill) { - let p = picture[0]; - let colour = picture[1]; - $impl_canvas.save(ctx); - $impl_canvas.set_fill_colour(ctx, $colour.to_css_rgba_string(colour)); - display_on_rendering_context(p, ctx, new DrawingState(true, state.stroke)); - return $impl_canvas.restore(ctx); - } else if (picture instanceof Stroke) { - let p = picture[0]; - let stroke = picture[1]; - if (stroke instanceof NoStroke) { - loop$picture = p; - loop$ctx = ctx; - loop$state = new DrawingState(state.fill, false); - } else { - let color = stroke[0]; - let width = stroke[1]; - $impl_canvas.save(ctx); - $impl_canvas.set_stroke_color(ctx, $colour.to_css_rgba_string(color)); - $impl_canvas.set_line_width(ctx, width); - display_on_rendering_context(p, ctx, new DrawingState(state.fill, true)); - return $impl_canvas.restore(ctx); - } - } else if (picture instanceof $types.ImageScalingBehaviour) { - let p = picture[0]; - let behaviour = picture[1]; - $impl_canvas.save(ctx); - $impl_canvas.set_image_smoothing_enabled( - ctx, - (() => { - if (behaviour instanceof $types.ScalingSmooth) { - return true; - } else { - return false; - } - })(), - ); - display_on_rendering_context(p, ctx, state); - return $impl_canvas.restore(ctx); - } else if (picture instanceof Translate) { - let p = picture[0]; - let vec = picture[1]; - let x; - let y; - x = vec[0]; - y = vec[1]; - $impl_canvas.save(ctx); - $impl_canvas.translate(ctx, x, y); - display_on_rendering_context(p, ctx, state); - return $impl_canvas.restore(ctx); - } else if (picture instanceof Scale) { - let p = picture[0]; - let vec = picture[1]; - let x; - let y; - x = vec[0]; - y = vec[1]; - $impl_canvas.save(ctx); - $impl_canvas.scale(ctx, x, y); - display_on_rendering_context(p, ctx, state); - return $impl_canvas.restore(ctx); - } else if (picture instanceof Rotate) { - let p = picture[0]; - let angle = picture[1]; - let rad; - rad = angle[0]; - $impl_canvas.save(ctx); - $impl_canvas.rotate(ctx, rad); - display_on_rendering_context(p, ctx, state); - return $impl_canvas.restore(ctx); - } else { - let pictures = picture[0]; - if (pictures instanceof $Empty) { - return undefined; - } else { - let p = pictures.head; - let ps = pictures.tail; - display_on_rendering_context(p, ctx, state); - loop$picture = new Combine(ps); - loop$ctx = ctx; - loop$state = state; - } - } - } -} - -function parse_key_code(key_code) { - if (key_code === 32) { - return new Some(new $event.KeySpace()); - } else if (key_code === 37) { - return new Some(new $event.KeyLeftArrow()); - } else if (key_code === 38) { - return new Some(new $event.KeyUpArrow()); - } else if (key_code === 39) { - return new Some(new $event.KeyRightArrow()); - } else if (key_code === 40) { - return new Some(new $event.KeyDownArrow()); - } else if (key_code === 87) { - return new Some(new $event.KeyW()); - } else if (key_code === 65) { - return new Some(new $event.KeyA()); - } else if (key_code === 83) { - return new Some(new $event.KeyS()); - } else if (key_code === 68) { - return new Some(new $event.KeyD()); - } else if (key_code === 90) { - return new Some(new $event.KeyZ()); - } else if (key_code === 88) { - return new Some(new $event.KeyX()); - } else if (key_code === 67) { - return new Some(new $event.KeyC()); - } else if (key_code === 18) { - return new Some(new $event.KeyEnter()); - } else if (key_code === 27) { - return new Some(new $event.KeyEscape()); - } else if (key_code === 8) { - return new Some(new $event.KeyBackspace()); - } else { - return new None(); - } -} - -/** - * Utility to set the origin in the center of the canvas - */ -export function center(picture) { - return (config) => { - let width; - let height; - width = config.width; - height = config.height; - let _pipe = picture; - return translate_xy(_pipe, width * 0.5, height * 0.5); - }; -} - -const default_drawing_state = /* @__PURE__ */ new DrawingState(false, true); - -/** - * Display a picture on a HTML canvas element - * (specified by some [CSS Selector](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_selectors)). - * ``` - * canvas.display(fn (_: canvas.Config) { circle(50.0) }, "#mycanvas") - * ``` - */ -export function display(init, selector) { - let ctx = $impl_canvas.get_rendering_context(selector); - $impl_canvas.reset(ctx); - let picture = init( - new Config($impl_canvas.get_width(ctx), $impl_canvas.get_height(ctx)), - ); - return display_on_rendering_context(picture, ctx, default_drawing_state); -} - -function get_tick_func(ctx, view, update, selector) { - return (time) => { - let $ = $impl_canvas.get_global(selector); - let current_state; - if ($ instanceof Ok) { - current_state = $[0]; - } else { - throw makeError( - "let_assert", - FILEPATH, - "paint/canvas", - 399, - "get_tick_func", - "Pattern match failed, no pattern matched the value.", - { - value: $, - start: 11581, - end: 11644, - pattern_start: 11592, - pattern_end: 11609 - } - ) - } - let new_state = update(current_state, new $event.Tick(time)); - $impl_canvas.set_global(new_state, selector); - let picture = view(new_state); - $impl_canvas.reset(ctx); - display_on_rendering_context(picture, ctx, default_drawing_state); - return $impl_canvas.setup_request_animation_frame( - get_tick_func(ctx, view, update, selector), - ); - }; -} - -/** - * Animations, interactive applications and tiny games can be built using the - * `interact` function. It roughly follows the [Elm architecture](https://guide.elm-lang.org/architecture/). - * Here is a short example: - * ``` - * type State = - * Int - * - * fn init(_: canvas.Config) -> State { - * 0 - * } - * - * fn update(state: State, event: event.Event) -> State { - * case event { - * event.Tick(_) -> state + 1 - * _ -> state - * } - * } - * - * fn view(state: State) -> Picture { - * paint.circle(int.to_float(state)) - * } - * - * fn main() { - * interact(init, update, view, "#mycanvas") - * } - * ``` - */ -export function interact(init, update, view, selector) { - let ctx = $impl_canvas.get_rendering_context(selector); - let initial_state = init( - new Config($impl_canvas.get_width(ctx), $impl_canvas.get_height(ctx)), - ); - $impl_canvas.set_global(initial_state, selector); - let create_key_handler = (event_name, constructor) => { - return $impl_canvas.setup_input_handler( - event_name, - (event) => { - let key = parse_key_code($impl_canvas.get_key_code(event)); - if (key instanceof Some) { - let key$1 = key[0]; - let $ = $impl_canvas.get_global(selector); - let old_state; - if ($ instanceof Ok) { - old_state = $[0]; - } else { - throw makeError( - "let_assert", - FILEPATH, - "paint/canvas", - 292, - "interact", - "Pattern match failed, no pattern matched the value.", - { - value: $, - start: 8332, - end: 8391, - pattern_start: 8343, - pattern_end: 8356 - } - ) - } - let new_state = update(old_state, constructor(key$1)); - return $impl_canvas.set_global(new_state, selector); - } else { - return undefined; - } - }, - ); - }; - create_key_handler( - "keydown", - (var0) => { return new $event.KeyboardPressed(var0); }, - ); - create_key_handler( - "keyup", - (var0) => { return new $event.KeyboardRelased(var0); }, - ); - $impl_canvas.setup_input_handler( - "mousemove", - (event) => { - let $ = $impl_canvas.mouse_pos(ctx, event); - let x; - let y; - x = $[0]; - y = $[1]; - let $1 = $impl_canvas.get_global(selector); - let old_state; - if ($1 instanceof Ok) { - old_state = $1[0]; - } else { - throw makeError( - "let_assert", - FILEPATH, - "paint/canvas", - 309, - "interact", - "Pattern match failed, no pattern matched the value.", - { - value: $1, - start: 8863, - end: 8922, - pattern_start: 8874, - pattern_end: 8887 - } - ) - } - let new_state = update(old_state, new $event.MouseMoved(x, y)); - $impl_canvas.set_global(new_state, selector); - return undefined; - }, - ); - let create_mouse_button_handler = (event_name, constructor, check_pressed) => { - return $impl_canvas.setup_input_handler( - event_name, - (event) => { - let previous_event_id = "PAINT_PREVIOUS_MOUSE_INPUT_FOR_" + selector; - let previous_event = $impl_canvas.get_global(previous_event_id); - $impl_canvas.set_global(event, previous_event_id); - let check_button = (i) => { - return $impl_canvas.check_mouse_button( - event, - previous_event, - i, - check_pressed, - ); - }; - let trigger_update = (button) => { - let $ = $impl_canvas.get_global(selector); - let old_state; - if ($ instanceof Ok) { - old_state = $[0]; - } else { - throw makeError( - "let_assert", - FILEPATH, - "paint/canvas", - 338, - "interact", - "Pattern match failed, no pattern matched the value.", - { - value: $, - start: 9856, - end: 9915, - pattern_start: 9867, - pattern_end: 9880 - } - ) - } - let new_state = update(old_state, constructor(button)); - return $impl_canvas.set_global(new_state, selector); - }; - let $ = check_button(0); - if ($) { - trigger_update(new $event.MouseButtonLeft()) - } else { - undefined - } - let $1 = check_button(1); - if ($1) { - trigger_update(new $event.MouseButtonRight()) - } else { - undefined - } - let $2 = check_button(2); - if ($2) { - trigger_update(new $event.MouseButtonMiddle()) - } else { - undefined - } - return undefined; - }, - ); - }; - create_mouse_button_handler( - "mousedown", - (var0) => { return new $event.MousePressed(var0); }, - true, - ); - create_mouse_button_handler( - "mouseup", - (var0) => { return new $event.MouseReleased(var0); }, - false, - ); - return $impl_canvas.setup_request_animation_frame( - get_tick_func(ctx, view, update, selector), - ); -} - -/** - * If you are using [Lustre](https://github.com/lustre-labs/lustre) or some other framework to build - * your web application you may prefer to use the [web components](https://developer.mozilla.org/en-US/docs/Web/API/Web_components) API - * and the `define_web_component` function. - * ``` - * // Call this function once to register a custom HTML element - * canvas.define_web_component() - * // You can then display your picture by setting the "picture" - * // property or attribute on the element. - * - * // In Lustre it would look something like this: - * fn canvas(picture: paint.Picture, attributes: List(attribute.Attribute(a))) { - * element.element( - * "paint-canvas", - * [attribute.attribute("picture", encode.to_string(picture)), ..attributes], - * [], - * ) - *} - * ``` - * A more detailed example for using this API can be found in the `demos/with_lustre` directory. - */ -export function define_web_component() { - $impl_canvas.define_web_component(); - return $impl_canvas.set_global( - (encoded_picture, ctx) => { - let $ = $encode.from_string(encoded_picture); - let picture; - if ($ instanceof Ok) { - picture = $[0]; - } else { - throw makeError( - "let_assert", - FILEPATH, - "paint/canvas", - 447, - "define_web_component", - "Invalid picture provided to web component", - { - value: $, - start: 13602, - end: 13662, - pattern_start: 13613, - pattern_end: 13624 - } - ) - } - return display_on_rendering_context(picture, ctx, default_drawing_state); - }, - "display_on_rendering_context_with_default_drawing_state", - ); -} diff --git a/build/dev/javascript/paint/paint/encode.mjs b/build/dev/javascript/paint/paint/encode.mjs deleted file mode 100644 index f9b88f3..0000000 --- a/build/dev/javascript/paint/paint/encode.mjs +++ /dev/null @@ -1,506 +0,0 @@ -import * as $colour from "../../gleam_community_colour/gleam_community/colour.mjs"; -import * as $json from "../../gleam_json/gleam/json.mjs"; -import * as $decode from "../../gleam_stdlib/gleam/dynamic/decode.mjs"; -import { toList } from "../gleam.mjs"; -import * as $paint from "../paint.mjs"; -import * as $types from "../paint/internal/types.mjs"; -import { FontProperties, NoStroke, Radians, SolidStroke } from "../paint/internal/types.mjs"; - -function decode_angle() { - return $decode.field( - "radians", - $decode.float, - (radians) => { return $decode.success(new Radians(radians)); }, - ); -} - -function decode_font() { - return $decode.field( - "sizePx", - $decode.int, - (size_px) => { - return $decode.field( - "fontFamily", - $decode.string, - (font_family) => { - return $decode.success(new FontProperties(size_px, font_family)); - }, - ); - }, - ); -} - -function decode_stroke() { - return $decode.field( - "type", - $decode.string, - (stroke_type) => { - if (stroke_type === "noStroke") { - return $decode.success(new NoStroke()); - } else if (stroke_type === "solidStroke") { - return $decode.field( - "colour", - $colour.decoder(), - (colour) => { - return $decode.field( - "thickness", - $decode.float, - (thickness) => { - return $decode.success(new SolidStroke(colour, thickness)); - }, - ); - }, - ); - } else { - return $decode.failure(new NoStroke(), "StrokeProperties"); - } - }, - ); -} - -function decode_vec2() { - return $decode.field( - "x", - $decode.float, - (x) => { - return $decode.field( - "y", - $decode.float, - (y) => { return $decode.success([x, y]); }, - ); - }, - ); -} - -function decode_picture() { - return $decode.recursive( - () => { - return $decode.field( - "type", - $decode.string, - (ty) => { - if (ty === "arc") { - return $decode.field( - "radius", - $decode.float, - (radius) => { - return $decode.field( - "start", - decode_angle(), - (start) => { - return $decode.field( - "end", - decode_angle(), - (end) => { - return $decode.success( - new $types.Arc(radius, start, end), - ); - }, - ); - }, - ); - }, - ); - } else if (ty === "blank") { - return $decode.success(new $types.Blank()); - } else if (ty === "combine") { - return $decode.field( - "pictures", - $decode.list(decode_picture()), - (pictures) => { - return $decode.success(new $types.Combine(pictures)); - }, - ); - } else if (ty === "fill") { - return $decode.field( - "picture", - decode_picture(), - (picture) => { - return $decode.field( - "colour", - $colour.decoder(), - (colour) => { - return $decode.success(new $types.Fill(picture, colour)); - }, - ); - }, - ); - } else if (ty === "polygon") { - return $decode.field( - "points", - $decode.list(decode_vec2()), - (points) => { - return $decode.field( - "closed", - $decode.bool, - (closed) => { - return $decode.success(new $types.Polygon(points, closed)); - }, - ); - }, - ); - } else if (ty === "rotate") { - return $decode.field( - "angle", - decode_angle(), - (angle) => { - return $decode.field( - "picture", - decode_picture(), - (picture) => { - return $decode.success(new $types.Rotate(picture, angle)); - }, - ); - }, - ); - } else if (ty === "scale") { - return $decode.field( - "x", - $decode.float, - (x) => { - return $decode.field( - "y", - $decode.float, - (y) => { - return $decode.field( - "picture", - decode_picture(), - (picture) => { - return $decode.success( - new $types.Scale(picture, [x, y]), - ); - }, - ); - }, - ); - }, - ); - } else if (ty === "stroke") { - return $decode.field( - "stroke", - decode_stroke(), - (stroke) => { - return $decode.field( - "picture", - decode_picture(), - (picture) => { - return $decode.success(new $types.Stroke(picture, stroke)); - }, - ); - }, - ); - } else if (ty === "text") { - return $decode.field( - "text", - $decode.string, - (text) => { - return $decode.field( - "style", - decode_font(), - (style) => { - return $decode.success(new $types.Text(text, style)); - }, - ); - }, - ); - } else if (ty === "translate") { - return $decode.field( - "x", - $decode.float, - (x) => { - return $decode.field( - "y", - $decode.float, - (y) => { - return $decode.field( - "picture", - decode_picture(), - (picture) => { - return $decode.success( - new $types.Translate(picture, [x, y]), - ); - }, - ); - }, - ); - }, - ); - } else if (ty === "image") { - return $decode.field( - "id", - $decode.string, - (id) => { - return $decode.field( - "width_px", - $decode.int, - (width_px) => { - return $decode.field( - "height_px", - $decode.int, - (height_px) => { - return $decode.success( - new $types.ImageRef( - new $types.Image(id), - width_px, - height_px, - ), - ); - }, - ); - }, - ); - }, - ); - } else if (ty === "image_scaling_behaviour") { - return $decode.field( - "behaviour", - $decode.string, - (behaviour) => { - return $decode.field( - "picture", - decode_picture(), - (picture) => { - if (behaviour === "smooth") { - return $decode.success( - new $types.ImageScalingBehaviour( - picture, - new $types.ScalingSmooth(), - ), - ); - } else if (behaviour === "pixelated") { - return $decode.success( - new $types.ImageScalingBehaviour( - picture, - new $types.ScalingPixelated(), - ), - ); - } else { - return $decode.failure(new $types.Blank(), "Picture"); - } - }, - ); - }, - ); - } else { - return $decode.failure(new $types.Blank(), "Picture"); - } - }, - ); - }, - ); -} - -/** - * Attempt to deserialize a `Picture` - */ -export function from_string(string) { - let decoder = $decode.field( - "picture", - decode_picture(), - (picture) => { return $decode.success(picture); }, - ); - return $json.parse(string, decoder); -} - -function font_to_json(font) { - let size_px; - let font_family; - size_px = font.size_px; - font_family = font.font_family; - return $json.object( - toList([ - ["sizePx", $json.int(size_px)], - ["fontFamily", $json.string(font_family)], - ]), - ); -} - -function stroke_to_json(stroke) { - if (stroke instanceof NoStroke) { - return $json.object(toList([["type", $json.string("noStroke")]])); - } else { - let colour = stroke[0]; - let thickness = stroke[1]; - return $json.object( - toList([ - ["type", $json.string("solidStroke")], - ["colour", $colour.encode(colour)], - ["thickness", $json.float(thickness)], - ]), - ); - } -} - -function angle_to_json(angle) { - let rad; - rad = angle[0]; - return $json.object(toList([["radians", $json.float(rad)]])); -} - -function picture_to_json(picture) { - if (picture instanceof $types.Blank) { - return $json.object(toList([["type", $json.string("blank")]])); - } else if (picture instanceof $types.Polygon) { - let points = picture[0]; - let closed = picture.closed; - return $json.object( - toList([ - ["type", $json.string("polygon")], - [ - "points", - $json.array( - points, - (point) => { - let x; - let y; - x = point[0]; - y = point[1]; - return $json.object( - toList([["x", $json.float(x)], ["y", $json.float(y)]]), - ); - }, - ), - ], - ["closed", $json.bool(closed)], - ]), - ); - } else if (picture instanceof $types.Arc) { - let radius = picture.radius; - let start = picture.start; - let end = picture.end; - return $json.object( - toList([ - ["type", $json.string("arc")], - ["radius", $json.float(radius)], - ["start", angle_to_json(start)], - ["end", angle_to_json(end)], - ]), - ); - } else if (picture instanceof $types.Text) { - let text = picture.text; - let style = picture.style; - return $json.object( - toList([ - ["type", $json.string("text")], - ["text", $json.string(text)], - ["style", font_to_json(style)], - ]), - ); - } else if (picture instanceof $types.ImageRef) { - let width_px = picture.width_px; - let height_px = picture.height_px; - let id = picture[0].id; - return $json.object( - toList([ - ["type", $json.string("image")], - ["id", $json.string(id)], - ["width_px", $json.int(width_px)], - ["height_px", $json.int(height_px)], - ]), - ); - } else if (picture instanceof $types.Fill) { - let picture$1 = picture[0]; - let colour = picture[1]; - return $json.object( - toList([ - ["type", $json.string("fill")], - ["colour", $colour.encode(colour)], - ["picture", picture_to_json(picture$1)], - ]), - ); - } else if (picture instanceof $types.Stroke) { - let picture$1 = picture[0]; - let stroke = picture[1]; - return $json.object( - toList([ - ["type", $json.string("stroke")], - ["stroke", stroke_to_json(stroke)], - ["picture", picture_to_json(picture$1)], - ]), - ); - } else if (picture instanceof $types.ImageScalingBehaviour) { - let picture$1 = picture[0]; - let behaviour = picture[1]; - return $json.object( - toList([ - ["type", $json.string("image_scaling_behaviour")], - [ - "behaviour", - $json.string( - (() => { - if (behaviour instanceof $types.ScalingSmooth) { - return "smooth"; - } else { - return "pixelated"; - } - })(), - ), - ], - ["picture", picture_to_json(picture$1)], - ]), - ); - } else if (picture instanceof $types.Translate) { - let picture$1 = picture[0]; - let x = picture[1][0]; - let y = picture[1][1]; - return $json.object( - toList([ - ["type", $json.string("translate")], - ["x", $json.float(x)], - ["y", $json.float(y)], - ["picture", picture_to_json(picture$1)], - ]), - ); - } else if (picture instanceof $types.Scale) { - let picture$1 = picture[0]; - let x = picture[1][0]; - let y = picture[1][1]; - return $json.object( - toList([ - ["type", $json.string("scale")], - ["x", $json.float(x)], - ["y", $json.float(y)], - ["picture", picture_to_json(picture$1)], - ]), - ); - } else if (picture instanceof $types.Rotate) { - let picture$1 = picture[0]; - let angle = picture[1]; - return $json.object( - toList([ - ["type", $json.string("rotate")], - ["angle", angle_to_json(angle)], - ["picture", picture_to_json(picture$1)], - ]), - ); - } else { - let from = picture[0]; - return $json.object( - toList([ - ["type", $json.string("combine")], - ["pictures", $json.array(from, picture_to_json)], - ]), - ); - } -} - -/** - * Serialize a `Picture` to a string. - * - * Note, serializing an `Image` texture will only store an ID referencing the image. This means that if you deserialize a Picture containing - * references to images, you are responsible for making sure all images are loaded before drawing the picture. - * More advanced APIs to support use cases such as these are planned for a future release. - * - * Also, if you wish to store the serialized data, remember that the library currently makes no stability guarantee that - * the data can be deserialized by *future* versions of the library. - */ -export function to_string(picture) { - let version = "paint:unstable"; - let _pipe = $json.object( - toList([ - ["version", $json.string(version)], - ["picture", picture_to_json(picture)], - ]), - ); - return $json.to_string(_pipe); -} diff --git a/build/dev/javascript/paint/paint/event.mjs b/build/dev/javascript/paint/paint/event.mjs deleted file mode 100644 index 86faa42..0000000 --- a/build/dev/javascript/paint/paint/event.mjs +++ /dev/null @@ -1,163 +0,0 @@ -import { CustomType as $CustomType } from "../gleam.mjs"; - -/** - * Triggered before drawing. Contains the number of milliseconds elapsed. - */ -export class Tick extends $CustomType { - constructor($0) { - super(); - this[0] = $0; - } -} -export const Event$Tick = ($0) => new Tick($0); -export const Event$isTick = (value) => value instanceof Tick; -export const Event$Tick$0 = (value) => value[0]; - -/** - * Triggered when a key is pressed - */ -export class KeyboardPressed extends $CustomType { - constructor($0) { - super(); - this[0] = $0; - } -} -export const Event$KeyboardPressed = ($0) => new KeyboardPressed($0); -export const Event$isKeyboardPressed = (value) => - value instanceof KeyboardPressed; -export const Event$KeyboardPressed$0 = (value) => value[0]; - -/** - * Triggered when a key is released - */ -export class KeyboardRelased extends $CustomType { - constructor($0) { - super(); - this[0] = $0; - } -} -export const Event$KeyboardRelased = ($0) => new KeyboardRelased($0); -export const Event$isKeyboardRelased = (value) => - value instanceof KeyboardRelased; -export const Event$KeyboardRelased$0 = (value) => value[0]; - -/** - * Triggered when the mouse is moved. Contains - * the `x` and `y` value for the mouse position. - */ -export class MouseMoved extends $CustomType { - constructor($0, $1) { - super(); - this[0] = $0; - this[1] = $1; - } -} -export const Event$MouseMoved = ($0, $1) => new MouseMoved($0, $1); -export const Event$isMouseMoved = (value) => value instanceof MouseMoved; -export const Event$MouseMoved$0 = (value) => value[0]; -export const Event$MouseMoved$1 = (value) => value[1]; - -/** - * Triggered when a mouse button is pressed - */ -export class MousePressed extends $CustomType { - constructor($0) { - super(); - this[0] = $0; - } -} -export const Event$MousePressed = ($0) => new MousePressed($0); -export const Event$isMousePressed = (value) => value instanceof MousePressed; -export const Event$MousePressed$0 = (value) => value[0]; - -/** - * Triggered when a mouse button is released. - * - * Note, on the web you might encounter issues where the - * release event for the right mouse button is not triggered - * because of the context menu. - */ -export class MouseReleased extends $CustomType { - constructor($0) { - super(); - this[0] = $0; - } -} -export const Event$MouseReleased = ($0) => new MouseReleased($0); -export const Event$isMouseReleased = (value) => value instanceof MouseReleased; -export const Event$MouseReleased$0 = (value) => value[0]; - -export class KeyLeftArrow extends $CustomType {} -export const Key$KeyLeftArrow = () => new KeyLeftArrow(); -export const Key$isKeyLeftArrow = (value) => value instanceof KeyLeftArrow; - -export class KeyRightArrow extends $CustomType {} -export const Key$KeyRightArrow = () => new KeyRightArrow(); -export const Key$isKeyRightArrow = (value) => value instanceof KeyRightArrow; - -export class KeyUpArrow extends $CustomType {} -export const Key$KeyUpArrow = () => new KeyUpArrow(); -export const Key$isKeyUpArrow = (value) => value instanceof KeyUpArrow; - -export class KeyDownArrow extends $CustomType {} -export const Key$KeyDownArrow = () => new KeyDownArrow(); -export const Key$isKeyDownArrow = (value) => value instanceof KeyDownArrow; - -export class KeySpace extends $CustomType {} -export const Key$KeySpace = () => new KeySpace(); -export const Key$isKeySpace = (value) => value instanceof KeySpace; - -export class KeyW extends $CustomType {} -export const Key$KeyW = () => new KeyW(); -export const Key$isKeyW = (value) => value instanceof KeyW; - -export class KeyA extends $CustomType {} -export const Key$KeyA = () => new KeyA(); -export const Key$isKeyA = (value) => value instanceof KeyA; - -export class KeyS extends $CustomType {} -export const Key$KeyS = () => new KeyS(); -export const Key$isKeyS = (value) => value instanceof KeyS; - -export class KeyD extends $CustomType {} -export const Key$KeyD = () => new KeyD(); -export const Key$isKeyD = (value) => value instanceof KeyD; - -export class KeyZ extends $CustomType {} -export const Key$KeyZ = () => new KeyZ(); -export const Key$isKeyZ = (value) => value instanceof KeyZ; - -export class KeyX extends $CustomType {} -export const Key$KeyX = () => new KeyX(); -export const Key$isKeyX = (value) => value instanceof KeyX; - -export class KeyC extends $CustomType {} -export const Key$KeyC = () => new KeyC(); -export const Key$isKeyC = (value) => value instanceof KeyC; - -export class KeyEnter extends $CustomType {} -export const Key$KeyEnter = () => new KeyEnter(); -export const Key$isKeyEnter = (value) => value instanceof KeyEnter; - -export class KeyEscape extends $CustomType {} -export const Key$KeyEscape = () => new KeyEscape(); -export const Key$isKeyEscape = (value) => value instanceof KeyEscape; - -export class KeyBackspace extends $CustomType {} -export const Key$KeyBackspace = () => new KeyBackspace(); -export const Key$isKeyBackspace = (value) => value instanceof KeyBackspace; - -export class MouseButtonLeft extends $CustomType {} -export const MouseButton$MouseButtonLeft = () => new MouseButtonLeft(); -export const MouseButton$isMouseButtonLeft = (value) => - value instanceof MouseButtonLeft; - -export class MouseButtonRight extends $CustomType {} -export const MouseButton$MouseButtonRight = () => new MouseButtonRight(); -export const MouseButton$isMouseButtonRight = (value) => - value instanceof MouseButtonRight; - -export class MouseButtonMiddle extends $CustomType {} -export const MouseButton$MouseButtonMiddle = () => new MouseButtonMiddle(); -export const MouseButton$isMouseButtonMiddle = (value) => - value instanceof MouseButtonMiddle; diff --git a/build/dev/javascript/paint/paint/internal/impl_canvas.mjs b/build/dev/javascript/paint/paint/internal/impl_canvas.mjs deleted file mode 100644 index 10ddff7..0000000 --- a/build/dev/javascript/paint/paint/internal/impl_canvas.mjs +++ /dev/null @@ -1,65 +0,0 @@ -import { - setup_input_handler, - get_width, - get_height, - set_global, - get_global, - reset, - save, - restore, - translate, - scale, - rotate, - reset_transform, - set_fill_colour, - set_stroke_color, - set_line_width, - set_image_smoothing_enabled, - arc, - polygon, - text, - draw_image, - image_from_query, - image_from_src, - on_image_load, -} from "../../impl_canvas_bindings.mjs"; -import { - define_web_component, - setup_request_animation_frame, - get_rendering_context, - get_key_code, - mouse_pos, - check_mouse_button, -} from "./../../impl_canvas_bindings.mjs"; - -export { - arc, - check_mouse_button, - define_web_component, - draw_image, - get_global, - get_height, - get_key_code, - get_rendering_context, - get_width, - image_from_query, - image_from_src, - mouse_pos, - on_image_load, - polygon, - reset, - reset_transform, - restore, - rotate, - save, - scale, - set_fill_colour, - set_global, - set_image_smoothing_enabled, - set_line_width, - set_stroke_color, - setup_input_handler, - setup_request_animation_frame, - text, - translate, -}; diff --git a/build/dev/javascript/paint/paint/internal/types.mjs b/build/dev/javascript/paint/paint/internal/types.mjs deleted file mode 100644 index 7e53029..0000000 --- a/build/dev/javascript/paint/paint/internal/types.mjs +++ /dev/null @@ -1,217 +0,0 @@ -import * as $colour from "../../../gleam_community_colour/gleam_community/colour.mjs"; -import { CustomType as $CustomType } from "../../gleam.mjs"; - -export class Blank extends $CustomType {} -export const Picture$Blank = () => new Blank(); -export const Picture$isBlank = (value) => value instanceof Blank; - -export class Polygon extends $CustomType { - constructor($0, closed) { - super(); - this[0] = $0; - this.closed = closed; - } -} -export const Picture$Polygon = ($0, closed) => new Polygon($0, closed); -export const Picture$isPolygon = (value) => value instanceof Polygon; -export const Picture$Polygon$0 = (value) => value[0]; -export const Picture$Polygon$closed = (value) => value.closed; -export const Picture$Polygon$1 = (value) => value.closed; - -export class Arc extends $CustomType { - constructor(radius, start, end) { - super(); - this.radius = radius; - this.start = start; - this.end = end; - } -} -export const Picture$Arc = (radius, start, end) => new Arc(radius, start, end); -export const Picture$isArc = (value) => value instanceof Arc; -export const Picture$Arc$radius = (value) => value.radius; -export const Picture$Arc$0 = (value) => value.radius; -export const Picture$Arc$start = (value) => value.start; -export const Picture$Arc$1 = (value) => value.start; -export const Picture$Arc$end = (value) => value.end; -export const Picture$Arc$2 = (value) => value.end; - -export class Text extends $CustomType { - constructor(text, style) { - super(); - this.text = text; - this.style = style; - } -} -export const Picture$Text = (text, style) => new Text(text, style); -export const Picture$isText = (value) => value instanceof Text; -export const Picture$Text$text = (value) => value.text; -export const Picture$Text$0 = (value) => value.text; -export const Picture$Text$style = (value) => value.style; -export const Picture$Text$1 = (value) => value.style; - -export class ImageRef extends $CustomType { - constructor($0, width_px, height_px) { - super(); - this[0] = $0; - this.width_px = width_px; - this.height_px = height_px; - } -} -export const Picture$ImageRef = ($0, width_px, height_px) => - new ImageRef($0, width_px, height_px); -export const Picture$isImageRef = (value) => value instanceof ImageRef; -export const Picture$ImageRef$0 = (value) => value[0]; -export const Picture$ImageRef$width_px = (value) => value.width_px; -export const Picture$ImageRef$1 = (value) => value.width_px; -export const Picture$ImageRef$height_px = (value) => value.height_px; -export const Picture$ImageRef$2 = (value) => value.height_px; - -export class Fill extends $CustomType { - constructor($0, $1) { - super(); - this[0] = $0; - this[1] = $1; - } -} -export const Picture$Fill = ($0, $1) => new Fill($0, $1); -export const Picture$isFill = (value) => value instanceof Fill; -export const Picture$Fill$0 = (value) => value[0]; -export const Picture$Fill$1 = (value) => value[1]; - -export class Stroke extends $CustomType { - constructor($0, $1) { - super(); - this[0] = $0; - this[1] = $1; - } -} -export const Picture$Stroke = ($0, $1) => new Stroke($0, $1); -export const Picture$isStroke = (value) => value instanceof Stroke; -export const Picture$Stroke$0 = (value) => value[0]; -export const Picture$Stroke$1 = (value) => value[1]; - -export class ImageScalingBehaviour extends $CustomType { - constructor($0, $1) { - super(); - this[0] = $0; - this[1] = $1; - } -} -export const Picture$ImageScalingBehaviour = ($0, $1) => - new ImageScalingBehaviour($0, $1); -export const Picture$isImageScalingBehaviour = (value) => - value instanceof ImageScalingBehaviour; -export const Picture$ImageScalingBehaviour$0 = (value) => value[0]; -export const Picture$ImageScalingBehaviour$1 = (value) => value[1]; - -export class Translate extends $CustomType { - constructor($0, $1) { - super(); - this[0] = $0; - this[1] = $1; - } -} -export const Picture$Translate = ($0, $1) => new Translate($0, $1); -export const Picture$isTranslate = (value) => value instanceof Translate; -export const Picture$Translate$0 = (value) => value[0]; -export const Picture$Translate$1 = (value) => value[1]; - -export class Scale extends $CustomType { - constructor($0, $1) { - super(); - this[0] = $0; - this[1] = $1; - } -} -export const Picture$Scale = ($0, $1) => new Scale($0, $1); -export const Picture$isScale = (value) => value instanceof Scale; -export const Picture$Scale$0 = (value) => value[0]; -export const Picture$Scale$1 = (value) => value[1]; - -export class Rotate extends $CustomType { - constructor($0, $1) { - super(); - this[0] = $0; - this[1] = $1; - } -} -export const Picture$Rotate = ($0, $1) => new Rotate($0, $1); -export const Picture$isRotate = (value) => value instanceof Rotate; -export const Picture$Rotate$0 = (value) => value[0]; -export const Picture$Rotate$1 = (value) => value[1]; - -export class Combine extends $CustomType { - constructor($0) { - super(); - this[0] = $0; - } -} -export const Picture$Combine = ($0) => new Combine($0); -export const Picture$isCombine = (value) => value instanceof Combine; -export const Picture$Combine$0 = (value) => value[0]; - -export class Image extends $CustomType { - constructor(id) { - super(); - this.id = id; - } -} -export const Image$Image = (id) => new Image(id); -export const Image$isImage = (value) => value instanceof Image; -export const Image$Image$id = (value) => value.id; -export const Image$Image$0 = (value) => value.id; - -export class ScalingSmooth extends $CustomType {} -export const ImageScalingBehaviour$ScalingSmooth = () => new ScalingSmooth(); -export const ImageScalingBehaviour$isScalingSmooth = (value) => - value instanceof ScalingSmooth; - -export class ScalingPixelated extends $CustomType {} -export const ImageScalingBehaviour$ScalingPixelated = () => - new ScalingPixelated(); -export const ImageScalingBehaviour$isScalingPixelated = (value) => - value instanceof ScalingPixelated; - -export class NoStroke extends $CustomType {} -export const StrokeProperties$NoStroke = () => new NoStroke(); -export const StrokeProperties$isNoStroke = (value) => value instanceof NoStroke; - -export class SolidStroke extends $CustomType { - constructor($0, $1) { - super(); - this[0] = $0; - this[1] = $1; - } -} -export const StrokeProperties$SolidStroke = ($0, $1) => new SolidStroke($0, $1); -export const StrokeProperties$isSolidStroke = (value) => - value instanceof SolidStroke; -export const StrokeProperties$SolidStroke$0 = (value) => value[0]; -export const StrokeProperties$SolidStroke$1 = (value) => value[1]; - -export class FontProperties extends $CustomType { - constructor(size_px, font_family) { - super(); - this.size_px = size_px; - this.font_family = font_family; - } -} -export const FontProperties$FontProperties = (size_px, font_family) => - new FontProperties(size_px, font_family); -export const FontProperties$isFontProperties = (value) => - value instanceof FontProperties; -export const FontProperties$FontProperties$size_px = (value) => value.size_px; -export const FontProperties$FontProperties$0 = (value) => value.size_px; -export const FontProperties$FontProperties$font_family = (value) => - value.font_family; -export const FontProperties$FontProperties$1 = (value) => value.font_family; - -export class Radians extends $CustomType { - constructor($0) { - super(); - this[0] = $0; - } -} -export const Angle$Radians = ($0) => new Radians($0); -export const Angle$isRadians = (value) => value instanceof Radians; -export const Angle$Radians$0 = (value) => value[0]; diff --git a/build/dev/javascript/prelude.mjs b/build/dev/javascript/prelude.mjs deleted file mode 100644 index 6acd225..0000000 --- a/build/dev/javascript/prelude.mjs +++ /dev/null @@ -1,1575 +0,0 @@ -export class CustomType { - withFields(fields) { - let properties = Object.keys(this).map((label) => - label in fields ? fields[label] : this[label], - ); - return new this.constructor(...properties); - } -} - -export class List { - static fromArray(array, tail) { - let t = tail || new Empty(); - for (let i = array.length - 1; i >= 0; --i) { - t = new NonEmpty(array[i], t); - } - return t; - } - - [Symbol.iterator]() { - return new ListIterator(this); - } - - toArray() { - return [...this]; - } - - atLeastLength(desired) { - let current = this; - while (desired-- > 0 && current) current = current.tail; - return current !== undefined; - } - - hasLength(desired) { - let current = this; - while (desired-- > 0 && current) current = current.tail; - return desired === -1 && current instanceof Empty; - } - - countLength() { - let current = this; - let length = 0; - while (current) { - current = current.tail; - length++; - } - return length - 1; - } -} - -export function prepend(element, tail) { - return new NonEmpty(element, tail); -} - -export function toList(elements, tail) { - return List.fromArray(elements, tail); -} - -class ListIterator { - #current; - - constructor(current) { - this.#current = current; - } - - next() { - if (this.#current instanceof Empty) { - return { done: true }; - } else { - let { head, tail } = this.#current; - this.#current = tail; - return { value: head, done: false }; - } - } -} - -export class Empty extends List {} -export const List$Empty = () => new Empty(); -export const List$isEmpty = (value) => value instanceof Empty; - -export class NonEmpty extends List { - constructor(head, tail) { - super(); - this.head = head; - this.tail = tail; - } -} -export const List$NonEmpty = (head, tail) => new NonEmpty(head, tail); -export const List$isNonEmpty = (value) => value instanceof NonEmpty; - -export const List$NonEmpty$first = (value) => value.head; -export const List$NonEmpty$rest = (value) => value.tail; - -/** - * A bit array is a contiguous sequence of bits similar to Erlang's Binary type. - */ -export class BitArray { - /** - * The size in bits of this bit array's data. - * - * @type {number} - */ - bitSize; - - /** - * The size in bytes of this bit array's data. If this bit array doesn't store - * a whole number of bytes then this value is rounded up. - * - * @type {number} - */ - byteSize; - - /** - * The number of unused high bits in the first byte of this bit array's - * buffer prior to the start of its data. The value of any unused high bits is - * undefined. - * - * The bit offset will be in the range 0-7. - * - * @type {number} - */ - bitOffset; - - /** - * The raw bytes that hold this bit array's data. - * - * If `bitOffset` is not zero then there are unused high bits in the first - * byte of this buffer. - * - * If `bitOffset + bitSize` is not a multiple of 8 then there are unused low - * bits in the last byte of this buffer. - * - * @type {Uint8Array} - */ - rawBuffer; - - /** - * Constructs a new bit array from a `Uint8Array`, an optional size in - * bits, and an optional bit offset. - * - * If no bit size is specified it is taken as `buffer.length * 8`, i.e. all - * bytes in the buffer make up the new bit array's data. - * - * If no bit offset is specified it defaults to zero, i.e. there are no unused - * high bits in the first byte of the buffer. - * - * @param {Uint8Array} buffer - * @param {number} [bitSize] - * @param {number} [bitOffset] - */ - constructor(buffer, bitSize, bitOffset) { - if (!(buffer instanceof Uint8Array)) { - throw globalThis.Error( - "BitArray can only be constructed from a Uint8Array", - ); - } - - this.bitSize = bitSize ?? buffer.length * 8; - this.byteSize = Math.trunc((this.bitSize + 7) / 8); - this.bitOffset = bitOffset ?? 0; - - // Validate the bit size - if (this.bitSize < 0) { - throw globalThis.Error(`BitArray bit size is invalid: ${this.bitSize}`); - } - - // Validate the bit offset - if (this.bitOffset < 0 || this.bitOffset > 7) { - throw globalThis.Error( - `BitArray bit offset is invalid: ${this.bitOffset}`, - ); - } - - // Validate the length of the buffer - if (buffer.length !== Math.trunc((this.bitOffset + this.bitSize + 7) / 8)) { - throw globalThis.Error("BitArray buffer length is invalid"); - } - - this.rawBuffer = buffer; - } - - /** - * Returns a specific byte in this bit array. If the byte index is out of - * range then `undefined` is returned. - * - * When returning the final byte of a bit array with a bit size that's not a - * multiple of 8, the content of the unused low bits are undefined. - * - * @param {number} index - * @returns {number | undefined} - */ - byteAt(index) { - if (index < 0 || index >= this.byteSize) { - return undefined; - } - - return bitArrayByteAt(this.rawBuffer, this.bitOffset, index); - } - - equals(other) { - if (this.bitSize !== other.bitSize) { - return false; - } - - const wholeByteCount = Math.trunc(this.bitSize / 8); - - // If both bit offsets are zero do a byte-aligned equality check which is - // faster - if (this.bitOffset === 0 && other.bitOffset === 0) { - // Compare any whole bytes - for (let i = 0; i < wholeByteCount; i++) { - if (this.rawBuffer[i] !== other.rawBuffer[i]) { - return false; - } - } - - // Compare any trailing bits, excluding unused low bits - const trailingBitsCount = this.bitSize % 8; - if (trailingBitsCount) { - const unusedLowBitCount = 8 - trailingBitsCount; - if ( - this.rawBuffer[wholeByteCount] >> unusedLowBitCount !== - other.rawBuffer[wholeByteCount] >> unusedLowBitCount - ) { - return false; - } - } - } else { - // Compare any whole bytes - for (let i = 0; i < wholeByteCount; i++) { - const a = bitArrayByteAt(this.rawBuffer, this.bitOffset, i); - const b = bitArrayByteAt(other.rawBuffer, other.bitOffset, i); - - if (a !== b) { - return false; - } - } - - // Compare any trailing bits - const trailingBitsCount = this.bitSize % 8; - if (trailingBitsCount) { - const a = bitArrayByteAt( - this.rawBuffer, - this.bitOffset, - wholeByteCount, - ); - const b = bitArrayByteAt( - other.rawBuffer, - other.bitOffset, - wholeByteCount, - ); - - const unusedLowBitCount = 8 - trailingBitsCount; - if (a >> unusedLowBitCount !== b >> unusedLowBitCount) { - return false; - } - } - } - - return true; - } - - /** - * Returns this bit array's internal buffer. - * - * @deprecated Use `BitArray.byteAt()` or `BitArray.rawBuffer` instead. - * - * @returns {Uint8Array} - */ - get buffer() { - bitArrayPrintDeprecationWarning( - "buffer", - "Use BitArray.byteAt() or BitArray.rawBuffer instead", - ); - - if (this.bitOffset !== 0 || this.bitSize % 8 !== 0) { - throw new globalThis.Error( - "BitArray.buffer does not support unaligned bit arrays", - ); - } - - return this.rawBuffer; - } - - /** - * Returns the length in bytes of this bit array's internal buffer. - * - * @deprecated Use `BitArray.bitSize` or `BitArray.byteSize` instead. - * - * @returns {number} - */ - get length() { - bitArrayPrintDeprecationWarning( - "length", - "Use BitArray.bitSize or BitArray.byteSize instead", - ); - - if (this.bitOffset !== 0 || this.bitSize % 8 !== 0) { - throw new globalThis.Error( - "BitArray.length does not support unaligned bit arrays", - ); - } - - return this.rawBuffer.length; - } -} - -export const BitArray$BitArray = (buffer, bitSize, bitOffset) => - new BitArray(buffer, bitSize, bitOffset); - -/** - * Returns the nth byte in the given buffer, after applying the specified bit - * offset. If the index is out of bounds then zero is returned. - * - * @param {Uint8Array} buffer - * @param {number} bitOffset - * @param {number} index - * @returns {number} - */ -function bitArrayByteAt(buffer, bitOffset, index) { - if (bitOffset === 0) { - return buffer[index] ?? 0; - } else { - const a = (buffer[index] << bitOffset) & 0xff; - const b = buffer[index + 1] >> (8 - bitOffset); - - return a | b; - } -} - -export class UtfCodepoint { - constructor(value) { - this.value = value; - } -} - -const isBitArrayDeprecationMessagePrinted = {}; -function bitArrayPrintDeprecationWarning(name, message) { - if (isBitArrayDeprecationMessagePrinted[name]) { - return; - } - - console.warn( - `Deprecated BitArray.${name} property used in JavaScript FFI code. ${message}.`, - ); - - isBitArrayDeprecationMessagePrinted[name] = true; -} - -/** - * Slices a bit array to produce a new bit array. If `end` is not supplied then - * all bits from `start` onward are returned. - * - * If the slice is out of bounds then an exception is thrown. - * - * @param {BitArray} bitArray - * @param {number} start - * @param {number} [end] - * @returns {BitArray} - */ -export function bitArraySlice(bitArray, start, end) { - end ??= bitArray.bitSize; - - bitArrayValidateRange(bitArray, start, end); - - // Handle zero-length slices - if (start === end) { - return new BitArray(new Uint8Array()); - } - - // Early return for slices that cover the whole bit array - if (start === 0 && end === bitArray.bitSize) { - return bitArray; - } - - start += bitArray.bitOffset; - end += bitArray.bitOffset; - - const startByteIndex = Math.trunc(start / 8); - const endByteIndex = Math.trunc((end + 7) / 8); - const byteLength = endByteIndex - startByteIndex; - - // Avoid creating a new Uint8Array if the view of the underlying ArrayBuffer - // is the same. This can occur when slicing off just the first or last bit of - // a bit array, i.e. when only the bit offset or bit size need to be updated. - let buffer; - if (startByteIndex === 0 && byteLength === bitArray.rawBuffer.byteLength) { - buffer = bitArray.rawBuffer; - } else { - buffer = new Uint8Array( - bitArray.rawBuffer.buffer, - bitArray.rawBuffer.byteOffset + startByteIndex, - byteLength, - ); - } - - return new BitArray(buffer, end - start, start % 8); -} - -/** - * Interprets a slice of this bit array as a floating point number, either - * 32-bit or 64-bit, with the specified endianness. - * - * The value of `end - start` must be exactly 32 or 64, otherwise an exception - * will be thrown. - * - * @param {BitArray} bitArray - * @param {number} start - * @param {number} end - * @param {boolean} isBigEndian - * @returns {number} - */ -export function bitArraySliceToFloat(bitArray, start, end, isBigEndian) { - bitArrayValidateRange(bitArray, start, end); - - const floatSize = end - start; - - // Check size is valid - if (floatSize !== 16 && floatSize !== 32 && floatSize !== 64) { - const msg = - `Sized floats must be 16-bit, 32-bit or 64-bit, got size of ` + - `${floatSize} bits`; - throw new globalThis.Error(msg); - } - - start += bitArray.bitOffset; - - const isStartByteAligned = start % 8 === 0; - - // If the bit range is byte aligned then the float can be read directly out - // of the existing buffer - if (isStartByteAligned) { - const view = new DataView( - bitArray.rawBuffer.buffer, - bitArray.rawBuffer.byteOffset + start / 8, - ); - - if (floatSize === 64) { - return view.getFloat64(0, !isBigEndian); - } else if (floatSize === 32) { - return view.getFloat32(0, !isBigEndian); - } else if (floatSize === 16) { - return fp16UintToNumber(view.getUint16(0, !isBigEndian)); - } - } - - // Copy the unaligned bytes into an aligned array so a DataView can be used - const alignedBytes = new Uint8Array(floatSize / 8); - const byteOffset = Math.trunc(start / 8); - for (let i = 0; i < alignedBytes.length; i++) { - alignedBytes[i] = bitArrayByteAt( - bitArray.rawBuffer, - start % 8, - byteOffset + i, - ); - } - - // Read the float out of the aligned buffer - const view = new DataView(alignedBytes.buffer); - if (floatSize === 64) { - return view.getFloat64(0, !isBigEndian); - } else if (floatSize === 32) { - return view.getFloat32(0, !isBigEndian); - } else { - return fp16UintToNumber(view.getUint16(0, !isBigEndian)); - } -} - -/** - * Interprets a slice of this bit array as a signed or unsigned integer with the - * specified endianness. - * - * @param {BitArray} bitArray - * @param {number} start - * @param {number} end - * @param {boolean} isBigEndian - * @param {boolean} isSigned - * @returns {number} - */ -export function bitArraySliceToInt( - bitArray, - start, - end, - isBigEndian, - isSigned, -) { - bitArrayValidateRange(bitArray, start, end); - - if (start === end) { - return 0; - } - - start += bitArray.bitOffset; - end += bitArray.bitOffset; - - const isStartByteAligned = start % 8 === 0; - const isEndByteAligned = end % 8 === 0; - - // If the slice is byte-aligned then there is no need to handle unaligned - // slices, meaning a simpler and faster implementation can be used instead - if (isStartByteAligned && isEndByteAligned) { - return intFromAlignedSlice( - bitArray, - start / 8, - end / 8, - isBigEndian, - isSigned, - ); - } - - const size = end - start; - - const startByteIndex = Math.trunc(start / 8); - const endByteIndex = Math.trunc((end - 1) / 8); - - // Handle the case of the slice being completely contained in a single byte - if (startByteIndex == endByteIndex) { - const mask = 0xff >> start % 8; - const unusedLowBitCount = (8 - (end % 8)) % 8; - - let value = - (bitArray.rawBuffer[startByteIndex] & mask) >> unusedLowBitCount; - - // For signed integers, if the high bit is set reinterpret as two's - // complement - if (isSigned) { - const highBit = 2 ** (size - 1); - if (value >= highBit) { - value -= highBit * 2; - } - } - - return value; - } - - // The integer value to be read is not aligned and crosses at least one byte - // boundary in the input array - - if (size <= 53) { - return intFromUnalignedSliceUsingNumber( - bitArray.rawBuffer, - start, - end, - isBigEndian, - isSigned, - ); - } else { - return intFromUnalignedSliceUsingBigInt( - bitArray.rawBuffer, - start, - end, - isBigEndian, - isSigned, - ); - } -} - -/** - * Joins the given segments into a new bit array, tightly packing them together. - * Each segment must be one of the following types: - * - * - A `number`: A single byte value in the range 0-255. Values outside this - * range will be wrapped. - * - A `Uint8Array`: A sequence of byte values of any length. - * - A `BitArray`: A sequence of bits of any length, which may not be byte - * aligned. - * - * The bit size of the returned bit array will be the sum of the size in bits - * of the input segments. - * - * @param {(number | Uint8Array | BitArray)[]} segments - * @returns {BitArray} - */ -export function toBitArray(segments) { - if (segments.length === 0) { - return new BitArray(new Uint8Array()); - } - - if (segments.length === 1) { - const segment = segments[0]; - - // When there is a single BitArray segment it can be returned as-is - if (segment instanceof BitArray) { - return segment; - } - - // When there is a single Uint8Array segment, pass it directly to the bit - // array constructor to avoid a copy - if (segment instanceof Uint8Array) { - return new BitArray(segment); - } - - return new BitArray(new Uint8Array(/** @type {number[]} */ (segments))); - } - - // Count the total number of bits and check if all segments are numbers, i.e. - // single bytes - let bitSize = 0; - let areAllSegmentsNumbers = true; - for (const segment of segments) { - if (segment instanceof BitArray) { - bitSize += segment.bitSize; - areAllSegmentsNumbers = false; - } else if (segment instanceof Uint8Array) { - bitSize += segment.byteLength * 8; - areAllSegmentsNumbers = false; - } else { - bitSize += 8; - } - } - - // If all segments are numbers then pass the segments array directly to the - // Uint8Array constructor - if (areAllSegmentsNumbers) { - return new BitArray(new Uint8Array(/** @type {number[]} */ (segments))); - } - - // Pack the segments into a Uint8Array - const buffer = new Uint8Array(Math.trunc((bitSize + 7) / 8)); - - // The current write position in bits into the above array. Byte-aligned - // segments, i.e. when the cursor is a multiple of 8, are able to be processed - // faster due to being able to copy bytes directly. - let cursor = 0; - - for (let segment of segments) { - const isCursorByteAligned = cursor % 8 === 0; - - if (segment instanceof BitArray) { - if (isCursorByteAligned && segment.bitOffset === 0) { - buffer.set(segment.rawBuffer, cursor / 8); - cursor += segment.bitSize; - - // Zero any unused bits in the last byte of the buffer. Their content is - // undefined and shouldn't be included in the output. - const trailingBitsCount = segment.bitSize % 8; - if (trailingBitsCount !== 0) { - const lastByteIndex = Math.trunc(cursor / 8); - buffer[lastByteIndex] >>= 8 - trailingBitsCount; - buffer[lastByteIndex] <<= 8 - trailingBitsCount; - } - } else { - appendUnalignedBits( - segment.rawBuffer, - segment.bitSize, - segment.bitOffset, - ); - } - } else if (segment instanceof Uint8Array) { - if (isCursorByteAligned) { - buffer.set(segment, cursor / 8); - cursor += segment.byteLength * 8; - } else { - appendUnalignedBits(segment, segment.byteLength * 8, 0); - } - } else { - if (isCursorByteAligned) { - buffer[cursor / 8] = segment; - cursor += 8; - } else { - appendUnalignedBits(new Uint8Array([segment]), 8, 0); - } - } - } - - function appendUnalignedBits(unalignedBits, size, offset) { - if (size === 0) { - return; - } - - const byteSize = Math.trunc(size + 7 / 8); - - const highBitsCount = cursor % 8; - const lowBitsCount = 8 - highBitsCount; - - let byteIndex = Math.trunc(cursor / 8); - - for (let i = 0; i < byteSize; i++) { - let byte = bitArrayByteAt(unalignedBits, offset, i); - - // If this is a partial byte then zero out the trailing bits as their - // content is undefined and shouldn't be included in the output - if (size < 8) { - byte >>= 8 - size; - byte <<= 8 - size; - } - - // Copy the high bits of the input byte to the low bits of the current - // output byte - buffer[byteIndex] |= byte >> highBitsCount; - - let appendedBitsCount = size - Math.max(0, size - lowBitsCount); - size -= appendedBitsCount; - cursor += appendedBitsCount; - - if (size === 0) { - break; - } - - // Copy the low bits of the input byte to the high bits of the next output - // byte - buffer[++byteIndex] = byte << lowBitsCount; - appendedBitsCount = size - Math.max(0, size - highBitsCount); - size -= appendedBitsCount; - cursor += appendedBitsCount; - } - } - - return new BitArray(buffer, bitSize); -} - -/** - * Encodes a floating point value into a `Uint8Array`. This is used to create - * float segments that are part of bit array expressions. - * - * @param {number} value - * @param {number} size - * @param {boolean} isBigEndian - * @returns {Uint8Array} - */ -export function sizedFloat(value, size, isBigEndian) { - if (size !== 16 && size !== 32 && size !== 64) { - const msg = `Sized floats must be 16-bit, 32-bit or 64-bit, got size of ${size} bits`; - throw new globalThis.Error(msg); - } - - if (size === 16) { - return numberToFp16Uint(value, isBigEndian); - } - - const buffer = new Uint8Array(size / 8); - - const view = new DataView(buffer.buffer); - - if (size == 64) { - view.setFloat64(0, value, !isBigEndian); - } else { - view.setFloat32(0, value, !isBigEndian); - } - - return buffer; -} - -/** - * Encodes an integer value into a `Uint8Array`, or a `BitArray` if the size in - * bits is not a multiple of 8. This is used to create integer segments used in - * bit array expressions. - * - * @param {number} value - * @param {number} size - * @param {boolean} isBigEndian - * @returns {Uint8Array | BitArray} - */ -export function sizedInt(value, size, isBigEndian) { - if (size <= 0) { - return new Uint8Array(); - } - - // Fast path when size is 8 bits. This relies on the rounding behavior of the - // Uint8Array constructor. - if (size === 8) { - return new Uint8Array([value]); - } - - // Fast path when size is less than 8 bits: shift the value up to the high - // bits - if (size < 8) { - value <<= 8 - size; - return new BitArray(new Uint8Array([value]), size); - } - - // Allocate output buffer - const buffer = new Uint8Array(Math.trunc((size + 7) / 8)); - - // The number of trailing bits in the final byte. Will be zero if the size is - // an exact number of bytes. - const trailingBitsCount = size % 8; - - // The number of unused bits in the final byte of the buffer - const unusedBitsCount = 8 - trailingBitsCount; - - // For output sizes not exceeding 32 bits the number type is used. For larger - // output sizes the BigInt type is needed. - // - // The code in each of these two paths must be kept in sync. - if (size <= 32) { - if (isBigEndian) { - let i = buffer.length - 1; - - // Set the trailing bits at the end of the output buffer - if (trailingBitsCount) { - buffer[i--] = (value << unusedBitsCount) & 0xff; - value >>= trailingBitsCount; - } - - for (; i >= 0; i--) { - buffer[i] = value; - value >>= 8; - } - } else { - let i = 0; - - const wholeByteCount = Math.trunc(size / 8); - for (; i < wholeByteCount; i++) { - buffer[i] = value; - value >>= 8; - } - - // Set the trailing bits at the end of the output buffer - if (trailingBitsCount) { - buffer[i] = value << unusedBitsCount; - } - } - } else { - const bigTrailingBitsCount = BigInt(trailingBitsCount); - const bigUnusedBitsCount = BigInt(unusedBitsCount); - - let bigValue = BigInt(value); - - if (isBigEndian) { - let i = buffer.length - 1; - - // Set the trailing bits at the end of the output buffer - if (trailingBitsCount) { - buffer[i--] = Number(bigValue << bigUnusedBitsCount); - bigValue >>= bigTrailingBitsCount; - } - - for (; i >= 0; i--) { - buffer[i] = Number(bigValue); - bigValue >>= 8n; - } - } else { - let i = 0; - - const wholeByteCount = Math.trunc(size / 8); - for (; i < wholeByteCount; i++) { - buffer[i] = Number(bigValue); - bigValue >>= 8n; - } - - // Set the trailing bits at the end of the output buffer - if (trailingBitsCount) { - buffer[i] = Number(bigValue << bigUnusedBitsCount); - } - } - } - - // Integers that aren't a whole number of bytes are returned as a BitArray so - // their size in bits is tracked - if (trailingBitsCount) { - return new BitArray(buffer, size); - } - - return buffer; -} - -/** - * Reads an aligned slice of any size as an integer. - * - * @param {BitArray} bitArray - * @param {number} start - * @param {number} end - * @param {boolean} isBigEndian - * @param {boolean} isSigned - * @returns {number} - */ -function intFromAlignedSlice(bitArray, start, end, isBigEndian, isSigned) { - const byteSize = end - start; - - if (byteSize <= 6) { - return intFromAlignedSliceUsingNumber( - bitArray.rawBuffer, - start, - end, - isBigEndian, - isSigned, - ); - } else { - return intFromAlignedSliceUsingBigInt( - bitArray.rawBuffer, - start, - end, - isBigEndian, - isSigned, - ); - } -} - -/** - * Reads an aligned slice up to 48 bits in size as an integer. Uses the - * JavaScript `number` type internally. - * - * @param {Uint8Array} buffer - * @param {number} start - * @param {number} end - * @param {boolean} isBigEndian - * @param {boolean} isSigned - * @returns {number} - */ -function intFromAlignedSliceUsingNumber( - buffer, - start, - end, - isBigEndian, - isSigned, -) { - const byteSize = end - start; - - let value = 0; - - // Read bytes as an unsigned integer - if (isBigEndian) { - for (let i = start; i < end; i++) { - value *= 256; - value += buffer[i]; - } - } else { - for (let i = end - 1; i >= start; i--) { - value *= 256; - value += buffer[i]; - } - } - - // For signed integers, if the high bit is set reinterpret as two's - // complement - if (isSigned) { - const highBit = 2 ** (byteSize * 8 - 1); - if (value >= highBit) { - value -= highBit * 2; - } - } - - return value; -} - -/** - * Reads an aligned slice of any size as an integer. Uses the JavaScript - * `BigInt` type internally. - * - * @param {Uint8Array} buffer - * @param {number} start - * @param {number} end - * @param {boolean} isBigEndian - * @param {boolean} isSigned - * @returns {number} - */ -function intFromAlignedSliceUsingBigInt( - buffer, - start, - end, - isBigEndian, - isSigned, -) { - const byteSize = end - start; - - let value = 0n; - - // Read bytes as an unsigned integer value - if (isBigEndian) { - for (let i = start; i < end; i++) { - value *= 256n; - value += BigInt(buffer[i]); - } - } else { - for (let i = end - 1; i >= start; i--) { - value *= 256n; - value += BigInt(buffer[i]); - } - } - - // For signed integers, if the high bit is set reinterpret as two's - // complement - if (isSigned) { - const highBit = 1n << BigInt(byteSize * 8 - 1); - if (value >= highBit) { - value -= highBit * 2n; - } - } - - // Convert the result into a JS number. This may cause quantizing/error on - // values outside JavaScript's safe integer range. - return Number(value); -} - -/** - * Reads an unaligned slice up to 53 bits in size as an integer. Uses the - * JavaScript `number` type internally. - * - * This function assumes that the slice crosses at least one byte boundary in - * the input. - * - * @param {Uint8Array} buffer - * @param {number} start - * @param {number} end - * @param {boolean} isBigEndian - * @param {boolean} isSigned - * @returns {number} - */ -function intFromUnalignedSliceUsingNumber( - buffer, - start, - end, - isBigEndian, - isSigned, -) { - const isStartByteAligned = start % 8 === 0; - - let size = end - start; - let byteIndex = Math.trunc(start / 8); - - let value = 0; - - if (isBigEndian) { - // Read any leading bits - if (!isStartByteAligned) { - const leadingBitsCount = 8 - (start % 8); - value = buffer[byteIndex++] & ((1 << leadingBitsCount) - 1); - size -= leadingBitsCount; - } - - // Read any whole bytes - while (size >= 8) { - value *= 256; - value += buffer[byteIndex++]; - size -= 8; - } - - // Read any trailing bits - if (size > 0) { - value *= 2 ** size; - value += buffer[byteIndex] >> (8 - size); - } - } else { - // For little endian, if the start is aligned then whole bytes can be read - // directly out of the input array, with the trailing bits handled at the - // end - if (isStartByteAligned) { - let size = end - start; - let scale = 1; - - // Read whole bytes - while (size >= 8) { - value += buffer[byteIndex++] * scale; - scale *= 256; - size -= 8; - } - - // Read trailing bits - value += (buffer[byteIndex] >> (8 - size)) * scale; - } else { - // Read little endian data where the start is not byte-aligned. This is - // done by reading whole bytes that cross a byte boundary in the input - // data, then reading any trailing bits. - - const highBitsCount = start % 8; - const lowBitsCount = 8 - highBitsCount; - - let size = end - start; - let scale = 1; - - // Extract whole bytes - while (size >= 8) { - const byte = - (buffer[byteIndex] << highBitsCount) | - (buffer[byteIndex + 1] >> lowBitsCount); - - value += (byte & 0xff) * scale; - - scale *= 256; - size -= 8; - byteIndex++; - } - - // Read any trailing bits. These trailing bits may cross a byte boundary - // in the input buffer. - if (size > 0) { - const lowBitsUsed = size - Math.max(0, size - lowBitsCount); - - let trailingByte = - (buffer[byteIndex] & ((1 << lowBitsCount) - 1)) >> - (lowBitsCount - lowBitsUsed); - - size -= lowBitsUsed; - - if (size > 0) { - trailingByte *= 2 ** size; - trailingByte += buffer[byteIndex + 1] >> (8 - size); - } - - value += trailingByte * scale; - } - } - } - - // For signed integers, if the high bit is set reinterpret as two's - // complement - if (isSigned) { - const highBit = 2 ** (end - start - 1); - if (value >= highBit) { - value -= highBit * 2; - } - } - - return value; -} - -/** - * Reads an unaligned slice of any size as an integer. Uses the JavaScript - * `BigInt` type internally. - * - * This function assumes that the slice crosses at least one byte boundary in - * the input. - * - * @param {Uint8Array} buffer - * @param {number} start - * @param {number} end - * @param {boolean} isBigEndian - * @param {boolean} isSigned - * @returns {number} - */ -function intFromUnalignedSliceUsingBigInt( - buffer, - start, - end, - isBigEndian, - isSigned, -) { - const isStartByteAligned = start % 8 === 0; - - let size = end - start; - let byteIndex = Math.trunc(start / 8); - - let value = 0n; - - if (isBigEndian) { - // Read any leading bits - if (!isStartByteAligned) { - const leadingBitsCount = 8 - (start % 8); - value = BigInt(buffer[byteIndex++] & ((1 << leadingBitsCount) - 1)); - size -= leadingBitsCount; - } - - // Read any whole bytes - while (size >= 8) { - value *= 256n; - value += BigInt(buffer[byteIndex++]); - size -= 8; - } - - // Read any trailing bits - if (size > 0) { - value <<= BigInt(size); - value += BigInt(buffer[byteIndex] >> (8 - size)); - } - } else { - // For little endian, if the start is aligned then whole bytes can be read - // directly out of the input array, with the trailing bits handled at the - // end - if (isStartByteAligned) { - let size = end - start; - let shift = 0n; - - // Read whole bytes - while (size >= 8) { - value += BigInt(buffer[byteIndex++]) << shift; - shift += 8n; - size -= 8; - } - - // Read trailing bits - value += BigInt(buffer[byteIndex] >> (8 - size)) << shift; - } else { - // Read little endian data where the start is not byte-aligned. This is - // done by reading whole bytes that cross a byte boundary in the input - // data, then reading any trailing bits. - - const highBitsCount = start % 8; - const lowBitsCount = 8 - highBitsCount; - - let size = end - start; - let shift = 0n; - - // Extract whole bytes - while (size >= 8) { - const byte = - (buffer[byteIndex] << highBitsCount) | - (buffer[byteIndex + 1] >> lowBitsCount); - - value += BigInt(byte & 0xff) << shift; - - shift += 8n; - size -= 8; - byteIndex++; - } - - // Read any trailing bits. These trailing bits may cross a byte boundary - // in the input buffer. - if (size > 0) { - const lowBitsUsed = size - Math.max(0, size - lowBitsCount); - - let trailingByte = - (buffer[byteIndex] & ((1 << lowBitsCount) - 1)) >> - (lowBitsCount - lowBitsUsed); - - size -= lowBitsUsed; - - if (size > 0) { - trailingByte <<= size; - trailingByte += buffer[byteIndex + 1] >> (8 - size); - } - - value += BigInt(trailingByte) << shift; - } - } - } - - // For signed integers, if the high bit is set reinterpret as two's - // complement - if (isSigned) { - const highBit = 2n ** BigInt(end - start - 1); - if (value >= highBit) { - value -= highBit * 2n; - } - } - - // Convert the result into a JS number. This may cause quantizing/error on - // values outside JavaScript's safe integer range. - return Number(value); -} - -/** - * Interprets a 16-bit unsigned integer value as a 16-bit floating point value. - * - * @param {number} intValue - * @returns {number} - */ -function fp16UintToNumber(intValue) { - const sign = intValue >= 0x8000 ? -1 : 1; - const exponent = (intValue & 0x7c00) >> 10; - const fraction = intValue & 0x03ff; - - let value; - if (exponent === 0) { - value = 6.103515625e-5 * (fraction / 0x400); - } else if (exponent === 0x1f) { - value = fraction === 0 ? Infinity : NaN; - } else { - value = Math.pow(2, exponent - 15) * (1 + fraction / 0x400); - } - - return sign * value; -} - -/** - * Converts a floating point number to bytes for a 16-bit floating point value. - * - * @param {number} intValue - * @param {boolean} isBigEndian - * @returns {Uint8Array} - */ -function numberToFp16Uint(value, isBigEndian) { - const buffer = new Uint8Array(2); - - if (isNaN(value)) { - buffer[1] = 0x7e; - } else if (value === Infinity) { - buffer[1] = 0x7c; - } else if (value === -Infinity) { - buffer[1] = 0xfc; - } else if (value === 0) { - // Both values are already zero - } else { - const sign = value < 0 ? 1 : 0; - value = Math.abs(value); - - let exponent = Math.floor(Math.log2(value)); - let fraction = value / Math.pow(2, exponent) - 1; - - exponent += 15; - - if (exponent <= 0) { - exponent = 0; - fraction = value / Math.pow(2, -14); - } else if (exponent >= 31) { - exponent = 31; - fraction = 0; - } - - fraction = Math.round(fraction * 1024); - - buffer[1] = - (sign << 7) | ((exponent & 0x1f) << 2) | ((fraction >> 8) & 0x03); - buffer[0] = fraction & 0xff; - } - - if (isBigEndian) { - const a = buffer[0]; - buffer[0] = buffer[1]; - buffer[1] = a; - } - - return buffer; -} - -/** - * Throws an exception if the given start and end values are out of bounds for - * a bit array. - * - * @param {BitArray} bitArray - * @param {number} start - * @param {number} end - */ -function bitArrayValidateRange(bitArray, start, end) { - if ( - start < 0 || - start > bitArray.bitSize || - end < start || - end > bitArray.bitSize - ) { - const msg = - `Invalid bit array slice: start = ${start}, end = ${end}, ` + - `bit size = ${bitArray.bitSize}`; - throw new globalThis.Error(msg); - } -} - -/** @type {TextEncoder | undefined} */ -let utf8Encoder; - -/** - * Returns the UTF-8 bytes for a string. - * - * @param {string} string - * @returns {Uint8Array} - */ -export function stringBits(string) { - utf8Encoder ??= new TextEncoder(); - return utf8Encoder.encode(string); -} - -/** - * Returns the UTF-8 bytes for a single UTF codepoint. - * - * @param {UtfCodepoint} codepoint - * @returns {Uint8Array} - */ -export function codepointBits(codepoint) { - return stringBits(String.fromCodePoint(codepoint.value)); -} - -/** - * Returns the UTF-16 bytes for a string. - * - * @param {string} string - * @param {boolean} isBigEndian - * @returns {Uint8Array} - */ -export function stringToUtf16(string, isBigEndian) { - const buffer = new ArrayBuffer(string.length * 2); - const bufferView = new DataView(buffer); - - for (let i = 0; i < string.length; i++) { - bufferView.setUint16(i * 2, string.charCodeAt(i), !isBigEndian); - } - - return new Uint8Array(buffer); -} - -/** - * Returns the UTF-16 bytes for a single UTF codepoint. - * - * @param {UtfCodepoint} codepoint - * @param {boolean} isBigEndian - * @returns {Uint8Array} - */ -export function codepointToUtf16(codepoint, isBigEndian) { - return stringToUtf16(String.fromCodePoint(codepoint.value), isBigEndian); -} - -/** - * Returns the UTF-32 bytes for a string. - * - * @param {string} string - * @param {boolean} isBigEndian - * @returns {Uint8Array} - */ -export function stringToUtf32(string, isBigEndian) { - const buffer = new ArrayBuffer(string.length * 4); - const bufferView = new DataView(buffer); - let length = 0; - - for (let i = 0; i < string.length; i++) { - const codepoint = string.codePointAt(i); - - bufferView.setUint32(length * 4, codepoint, !isBigEndian); - length++; - - if (codepoint > 0xffff) { - i++; - } - } - - return new Uint8Array(buffer.slice(0, length * 4)); -} - -/** - * Returns the UTF-32 bytes for a single UTF codepoint. - * - * @param {UtfCodepoint} codepoint - * @param {boolean} isBigEndian - * @returns {Uint8Array} - */ -export function codepointToUtf32(codepoint, isBigEndian) { - return stringToUtf32(String.fromCodePoint(codepoint.value), isBigEndian); -} - -export class Result extends CustomType { - static isResult(data) { - return data instanceof Result; - } -} - -export class Ok extends Result { - constructor(value) { - super(); - this[0] = value; - } - - isOk() { - return true; - } -} -export const Result$Ok = (value) => new Ok(value); -export const Result$isOk = (value) => value instanceof Ok; -export const Result$Ok$0 = (value) => value[0]; - -export class Error extends Result { - constructor(detail) { - super(); - this[0] = detail; - } - - isOk() { - return false; - } -} -export const Result$Error = (detail) => new Error(detail); -export const Result$isError = (value) => value instanceof Error; -export const Result$Error$0 = (value) => value[0]; - -export function isEqual(x, y) { - let values = [x, y]; - - while (values.length) { - let a = values.pop(); - let b = values.pop(); - if (a === b) continue; - - if (!isObject(a) || !isObject(b)) return false; - let unequal = - !structurallyCompatibleObjects(a, b) || - unequalDates(a, b) || - unequalBuffers(a, b) || - unequalArrays(a, b) || - unequalMaps(a, b) || - unequalSets(a, b) || - unequalRegExps(a, b); - if (unequal) return false; - - const proto = Object.getPrototypeOf(a); - if (proto !== null && typeof proto.equals === "function") { - try { - if (a.equals(b)) continue; - else return false; - } catch {} - } - - let [keys, get] = getters(a); - const ka = keys(a); - const kb = keys(b); - if (ka.length !== kb.length) return false; - for (let k of ka) { - values.push(get(a, k), get(b, k)); - } - } - - return true; -} - -function getters(object) { - if (object instanceof Map) { - return [(x) => x.keys(), (x, y) => x.get(y)]; - } else { - let extra = object instanceof globalThis.Error ? ["message"] : []; - return [(x) => [...extra, ...Object.keys(x)], (x, y) => x[y]]; - } -} - -function unequalDates(a, b) { - return a instanceof Date && (a > b || a < b); -} - -function unequalBuffers(a, b) { - return ( - !(a instanceof BitArray) && - a.buffer instanceof ArrayBuffer && - a.BYTES_PER_ELEMENT && - !(a.byteLength === b.byteLength && a.every((n, i) => n === b[i])) - ); -} - -function unequalArrays(a, b) { - return Array.isArray(a) && a.length !== b.length; -} - -function unequalMaps(a, b) { - return a instanceof Map && a.size !== b.size; -} - -function unequalSets(a, b) { - return ( - a instanceof Set && (a.size != b.size || [...a].some((e) => !b.has(e))) - ); -} - -function unequalRegExps(a, b) { - return a instanceof RegExp && (a.source !== b.source || a.flags !== b.flags); -} - -function isObject(a) { - return typeof a === "object" && a !== null; -} - -function structurallyCompatibleObjects(a, b) { - if (typeof a !== "object" && typeof b !== "object" && (!a || !b)) - return false; - - let nonstructural = [Promise, WeakSet, WeakMap, Function]; - if (nonstructural.some((c) => a instanceof c)) return false; - - return a.constructor === b.constructor; -} - -export function remainderInt(a, b) { - if (b === 0) { - return 0; - } else { - return a % b; - } -} - -export function divideInt(a, b) { - return Math.trunc(divideFloat(a, b)); -} - -export function divideFloat(a, b) { - if (b === 0) { - return 0; - } else { - return a / b; - } -} - -export function makeError(variant, file, module, line, fn, message, extra) { - let error = new globalThis.Error(message); - error.gleam_error = variant; - error.file = file; - error.module = module; - error.line = line; - error.function = fn; - // TODO: Remove this with Gleam v2.0.0 - error.fn = fn; - for (let k in extra) error[k] = extra[k]; - return error; -} diff --git a/build/dev/javascript/stellar_prune/_gleam_artefacts/game.cache b/build/dev/javascript/stellar_prune/_gleam_artefacts/game.cache deleted file mode 100644 index 40230af..0000000 Binary files a/build/dev/javascript/stellar_prune/_gleam_artefacts/game.cache and /dev/null differ diff --git a/build/dev/javascript/stellar_prune/_gleam_artefacts/game.cache_inline b/build/dev/javascript/stellar_prune/_gleam_artefacts/game.cache_inline deleted file mode 100644 index 1b1cb4d..0000000 Binary files a/build/dev/javascript/stellar_prune/_gleam_artefacts/game.cache_inline and /dev/null differ diff --git a/build/dev/javascript/stellar_prune/_gleam_artefacts/game.cache_meta b/build/dev/javascript/stellar_prune/_gleam_artefacts/game.cache_meta deleted file mode 100644 index 6cd0de3..0000000 Binary files a/build/dev/javascript/stellar_prune/_gleam_artefacts/game.cache_meta and /dev/null differ diff --git a/build/dev/javascript/stellar_prune/_gleam_artefacts/game.cache_warnings b/build/dev/javascript/stellar_prune/_gleam_artefacts/game.cache_warnings deleted file mode 100644 index 1b1cb4d..0000000 Binary files a/build/dev/javascript/stellar_prune/_gleam_artefacts/game.cache_warnings and /dev/null differ diff --git a/build/dev/javascript/stellar_prune/_gleam_artefacts/hud.cache b/build/dev/javascript/stellar_prune/_gleam_artefacts/hud.cache deleted file mode 100644 index 7e8f299..0000000 Binary files a/build/dev/javascript/stellar_prune/_gleam_artefacts/hud.cache and /dev/null differ diff --git a/build/dev/javascript/stellar_prune/_gleam_artefacts/hud.cache_inline b/build/dev/javascript/stellar_prune/_gleam_artefacts/hud.cache_inline deleted file mode 100644 index 1b1cb4d..0000000 Binary files a/build/dev/javascript/stellar_prune/_gleam_artefacts/hud.cache_inline and /dev/null differ diff --git a/build/dev/javascript/stellar_prune/_gleam_artefacts/hud.cache_meta b/build/dev/javascript/stellar_prune/_gleam_artefacts/hud.cache_meta deleted file mode 100644 index 0ed27b2..0000000 Binary files a/build/dev/javascript/stellar_prune/_gleam_artefacts/hud.cache_meta and /dev/null differ diff --git a/build/dev/javascript/stellar_prune/_gleam_artefacts/hud.cache_warnings b/build/dev/javascript/stellar_prune/_gleam_artefacts/hud.cache_warnings deleted file mode 100644 index 1b1cb4d..0000000 Binary files a/build/dev/javascript/stellar_prune/_gleam_artefacts/hud.cache_warnings and /dev/null differ diff --git a/build/dev/javascript/stellar_prune/_gleam_artefacts/math@math.cache b/build/dev/javascript/stellar_prune/_gleam_artefacts/math@math.cache deleted file mode 100644 index cb4cbb8..0000000 Binary files a/build/dev/javascript/stellar_prune/_gleam_artefacts/math@math.cache and /dev/null differ diff --git a/build/dev/javascript/stellar_prune/_gleam_artefacts/math@math.cache_inline b/build/dev/javascript/stellar_prune/_gleam_artefacts/math@math.cache_inline deleted file mode 100644 index 1b1cb4d..0000000 Binary files a/build/dev/javascript/stellar_prune/_gleam_artefacts/math@math.cache_inline and /dev/null differ diff --git a/build/dev/javascript/stellar_prune/_gleam_artefacts/math@math.cache_meta b/build/dev/javascript/stellar_prune/_gleam_artefacts/math@math.cache_meta deleted file mode 100644 index e0a618d..0000000 Binary files a/build/dev/javascript/stellar_prune/_gleam_artefacts/math@math.cache_meta and /dev/null differ diff --git a/build/dev/javascript/stellar_prune/_gleam_artefacts/math@math.cache_warnings b/build/dev/javascript/stellar_prune/_gleam_artefacts/math@math.cache_warnings deleted file mode 100644 index 1b1cb4d..0000000 Binary files a/build/dev/javascript/stellar_prune/_gleam_artefacts/math@math.cache_warnings and /dev/null differ diff --git a/build/dev/javascript/stellar_prune/_gleam_artefacts/physics.cache b/build/dev/javascript/stellar_prune/_gleam_artefacts/physics.cache deleted file mode 100644 index 7879101..0000000 Binary files a/build/dev/javascript/stellar_prune/_gleam_artefacts/physics.cache and /dev/null differ diff --git a/build/dev/javascript/stellar_prune/_gleam_artefacts/physics.cache_inline b/build/dev/javascript/stellar_prune/_gleam_artefacts/physics.cache_inline deleted file mode 100644 index 1b1cb4d..0000000 Binary files a/build/dev/javascript/stellar_prune/_gleam_artefacts/physics.cache_inline and /dev/null differ diff --git a/build/dev/javascript/stellar_prune/_gleam_artefacts/physics.cache_meta b/build/dev/javascript/stellar_prune/_gleam_artefacts/physics.cache_meta deleted file mode 100644 index 32f8c5f..0000000 Binary files a/build/dev/javascript/stellar_prune/_gleam_artefacts/physics.cache_meta and /dev/null differ diff --git a/build/dev/javascript/stellar_prune/_gleam_artefacts/physics.cache_warnings b/build/dev/javascript/stellar_prune/_gleam_artefacts/physics.cache_warnings deleted file mode 100644 index 1b1cb4d..0000000 Binary files a/build/dev/javascript/stellar_prune/_gleam_artefacts/physics.cache_warnings and /dev/null differ diff --git a/build/dev/javascript/stellar_prune/_gleam_artefacts/rendering.cache b/build/dev/javascript/stellar_prune/_gleam_artefacts/rendering.cache deleted file mode 100644 index 876474c..0000000 Binary files a/build/dev/javascript/stellar_prune/_gleam_artefacts/rendering.cache and /dev/null differ diff --git a/build/dev/javascript/stellar_prune/_gleam_artefacts/rendering.cache_inline b/build/dev/javascript/stellar_prune/_gleam_artefacts/rendering.cache_inline deleted file mode 100644 index 1b1cb4d..0000000 Binary files a/build/dev/javascript/stellar_prune/_gleam_artefacts/rendering.cache_inline and /dev/null differ diff --git a/build/dev/javascript/stellar_prune/_gleam_artefacts/rendering.cache_meta b/build/dev/javascript/stellar_prune/_gleam_artefacts/rendering.cache_meta deleted file mode 100644 index 3cec355..0000000 Binary files a/build/dev/javascript/stellar_prune/_gleam_artefacts/rendering.cache_meta and /dev/null differ diff --git a/build/dev/javascript/stellar_prune/_gleam_artefacts/rendering.cache_warnings b/build/dev/javascript/stellar_prune/_gleam_artefacts/rendering.cache_warnings deleted file mode 100644 index 1b1cb4d..0000000 Binary files a/build/dev/javascript/stellar_prune/_gleam_artefacts/rendering.cache_warnings and /dev/null differ diff --git a/build/dev/javascript/stellar_prune/_gleam_artefacts/target.cache b/build/dev/javascript/stellar_prune/_gleam_artefacts/target.cache deleted file mode 100644 index fc7937e..0000000 Binary files a/build/dev/javascript/stellar_prune/_gleam_artefacts/target.cache and /dev/null differ diff --git a/build/dev/javascript/stellar_prune/_gleam_artefacts/target.cache_inline b/build/dev/javascript/stellar_prune/_gleam_artefacts/target.cache_inline deleted file mode 100644 index 1b1cb4d..0000000 Binary files a/build/dev/javascript/stellar_prune/_gleam_artefacts/target.cache_inline and /dev/null differ diff --git a/build/dev/javascript/stellar_prune/_gleam_artefacts/target.cache_meta b/build/dev/javascript/stellar_prune/_gleam_artefacts/target.cache_meta deleted file mode 100644 index 7ebe7d5..0000000 Binary files a/build/dev/javascript/stellar_prune/_gleam_artefacts/target.cache_meta and /dev/null differ diff --git a/build/dev/javascript/stellar_prune/_gleam_artefacts/target.cache_warnings b/build/dev/javascript/stellar_prune/_gleam_artefacts/target.cache_warnings deleted file mode 100644 index 1b1cb4d..0000000 Binary files a/build/dev/javascript/stellar_prune/_gleam_artefacts/target.cache_warnings and /dev/null differ diff --git a/build/dev/javascript/stellar_prune/_gleam_artefacts/types.cache b/build/dev/javascript/stellar_prune/_gleam_artefacts/types.cache deleted file mode 100644 index 989e47c..0000000 Binary files a/build/dev/javascript/stellar_prune/_gleam_artefacts/types.cache and /dev/null differ diff --git a/build/dev/javascript/stellar_prune/_gleam_artefacts/types.cache_inline b/build/dev/javascript/stellar_prune/_gleam_artefacts/types.cache_inline deleted file mode 100644 index 1b1cb4d..0000000 Binary files a/build/dev/javascript/stellar_prune/_gleam_artefacts/types.cache_inline and /dev/null differ diff --git a/build/dev/javascript/stellar_prune/_gleam_artefacts/types.cache_meta b/build/dev/javascript/stellar_prune/_gleam_artefacts/types.cache_meta deleted file mode 100644 index 63d7ea9..0000000 Binary files a/build/dev/javascript/stellar_prune/_gleam_artefacts/types.cache_meta and /dev/null differ diff --git a/build/dev/javascript/stellar_prune/_gleam_artefacts/types.cache_warnings b/build/dev/javascript/stellar_prune/_gleam_artefacts/types.cache_warnings deleted file mode 100644 index 1b1cb4d..0000000 Binary files a/build/dev/javascript/stellar_prune/_gleam_artefacts/types.cache_warnings and /dev/null differ diff --git a/build/dev/javascript/stellar_prune/browser_ffi.mjs b/build/dev/javascript/stellar_prune/browser_ffi.mjs deleted file mode 100644 index ef62a4c..0000000 --- a/build/dev/javascript/stellar_prune/browser_ffi.mjs +++ /dev/null @@ -1,40 +0,0 @@ -let mouseX = 0; -let mouseY = 0; -let mousePressed = false; - -if (typeof window !== 'undefined') { - const canvas = document.getElementById('canvas'); - - window.addEventListener('mousemove', (e) => { - if (canvas) { - const rect = canvas.getBoundingClientRect(); - const scaleX = canvas.width / rect.width; - const scaleY = canvas.height / rect.height; - mouseX = (e.clientX - rect.left) * scaleX; - mouseY = (e.clientY - rect.top) * scaleY; - } else { - mouseX = e.clientX; - mouseY = e.clientY; - } - }); - - window.addEventListener('mousedown', () => { - mousePressed = true; - }); - - window.addEventListener('mouseup', () => { - mousePressed = false; - }); -} - -export function request_animation_frame(callback) { - requestAnimationFrame(() => callback()); -} - -export function get_mouse_position() { - return { x: mouseX, y: mouseY }; -} - -export function is_mouse_pressed() { - return mousePressed; -} diff --git a/build/dev/javascript/stellar_prune/game.mjs b/build/dev/javascript/stellar_prune/game.mjs deleted file mode 100644 index 7410e69..0000000 --- a/build/dev/javascript/stellar_prune/game.mjs +++ /dev/null @@ -1,325 +0,0 @@ -import * as $list from "../gleam_stdlib/gleam/list.mjs"; -import * as $paint from "../paint/paint.mjs"; -import { request_animation_frame, get_mouse_position, is_mouse_pressed } from "./browser_ffi.mjs"; -import { Ok, toList, prepend as listPrepend, CustomType as $CustomType, isEqual } from "./gleam.mjs"; -import * as $hud from "./hud.mjs"; -import { CrossHair, Health, Hud, Score } from "./hud.mjs"; -import * as $physics from "./physics.mjs"; -import { Gravity, Physics, Vec2 } from "./physics.mjs"; -import * as $rendering from "./rendering.mjs"; -import * as $target from "./target.mjs"; -import { Diamond, Lucy, Rocket } from "./target.mjs"; -import * as $types from "./types.mjs"; -import { GameOver, MainMenu, Playing, PlayingState } from "./types.mjs"; - -export { is_mouse_pressed, request_animation_frame }; - -export class TargetClickEffect extends $CustomType { - constructor(score_change, health_change) { - super(); - this.score_change = score_change; - this.health_change = health_change; - } -} -export const TargetClickEffect$TargetClickEffect = (score_change, health_change) => - new TargetClickEffect(score_change, health_change); -export const TargetClickEffect$isTargetClickEffect = (value) => - value instanceof TargetClickEffect; -export const TargetClickEffect$TargetClickEffect$score_change = (value) => - value.score_change; -export const TargetClickEffect$TargetClickEffect$0 = (value) => - value.score_change; -export const TargetClickEffect$TargetClickEffect$health_change = (value) => - value.health_change; -export const TargetClickEffect$TargetClickEffect$1 = (value) => - value.health_change; - -export class TargetFilterResult extends $CustomType { - constructor(remaining_targets, health_loss) { - super(); - this.remaining_targets = remaining_targets; - this.health_loss = health_loss; - } -} -export const TargetFilterResult$TargetFilterResult = (remaining_targets, health_loss) => - new TargetFilterResult(remaining_targets, health_loss); -export const TargetFilterResult$isTargetFilterResult = (value) => - value instanceof TargetFilterResult; -export const TargetFilterResult$TargetFilterResult$remaining_targets = (value) => - value.remaining_targets; -export const TargetFilterResult$TargetFilterResult$0 = (value) => - value.remaining_targets; -export const TargetFilterResult$TargetFilterResult$health_loss = (value) => - value.health_loss; -export const TargetFilterResult$TargetFilterResult$1 = (value) => - value.health_loss; - -export class SpawnResult extends $CustomType { - constructor(targets, spawn_timer) { - super(); - this.targets = targets; - this.spawn_timer = spawn_timer; - } -} -export const SpawnResult$SpawnResult = (targets, spawn_timer) => - new SpawnResult(targets, spawn_timer); -export const SpawnResult$isSpawnResult = (value) => - value instanceof SpawnResult; -export const SpawnResult$SpawnResult$targets = (value) => value.targets; -export const SpawnResult$SpawnResult$0 = (value) => value.targets; -export const SpawnResult$SpawnResult$spawn_timer = (value) => value.spawn_timer; -export const SpawnResult$SpawnResult$1 = (value) => value.spawn_timer; - -function init_playing_state() { - return new PlayingState( - toList([]), - new Physics(new Gravity(new Vec2(0.0, 0.08))), - new Hud( - new Score( - new Vec2(1050.0, 70.0), - new $target.Colorable($paint.colour_hex("#ffffff")), - 0, - ), - new CrossHair( - new Vec2(0.0, 0.0), - new $target.Colorable($paint.colour_hex("#ffffff")), - 5.0, - ), - new Health(new Vec2(30.0, 30.0), 120.0, 3, 3), - ), - new Vec2(0.0, 0.0), - 0.0, - ); -} - -function get_target_click_effects(kind) { - if (kind instanceof Lucy) { - return new TargetClickEffect(1, 0); - } else if (kind instanceof Diamond) { - let points_value = kind.points_value; - return new TargetClickEffect(points_value, 0); - } else { - return new TargetClickEffect(0, -1); - } -} - -function filter_out_of_bounds_targets(targets) { - return $list.fold( - targets, - new TargetFilterResult(toList([]), 0), - (acc, target) => { - let $ = target.position.y > 900.0; - if ($) { - let $1 = target.kind; - if ($1 instanceof Rocket) { - return acc; - } else { - return new TargetFilterResult( - acc.remaining_targets, - acc.health_loss + 1, - ); - } - } else { - return new TargetFilterResult( - listPrepend(target, acc.remaining_targets), - acc.health_loss, - ); - } - }, - ); -} - -function should_spawn_new_target(spawn_timer, active_targets, score) { - let spawn_interval = 60.0; - let max_targets = 1 + (globalThis.Math.trunc(score / 5)); - return (spawn_timer >= spawn_interval) && ($list.length(active_targets) < max_targets); -} - -function handle_target_click(playing_state, clicked_target) { - let new_targets = $list.filter( - playing_state.targets, - (target) => { return !isEqual(target, clicked_target); }, - ); - let effect = get_target_click_effects(clicked_target.kind); - return new PlayingState( - new_targets, - playing_state.physics, - (() => { - let _record = playing_state.hud; - return new Hud( - (() => { - let _record$1 = playing_state.hud.score; - return new Score( - _record$1.position, - _record$1.colorable, - playing_state.hud.score.score + effect.score_change, - ); - })(), - _record.cross_hair, - (() => { - let _record$1 = playing_state.hud.health; - return new Health( - _record$1.position, - _record$1.size, - playing_state.hud.health.amount + effect.health_change, - _record$1.max_health, - ); - })(), - ); - })(), - playing_state.mouse, - playing_state.spawn_timer, - ); -} - -function update_playing_state(playing_state) { - let $ = playing_state.physics; - let gravity; - gravity = $.gravity; - let updated_targets = $list.map( - playing_state.targets, - (target) => { return $target.update_target(target, gravity.acceleration); }, - ); - let filter_result = filter_out_of_bounds_targets(updated_targets); - let new_spawn_timer = playing_state.spawn_timer + 1.0; - let _block; - let $1 = should_spawn_new_target( - new_spawn_timer, - filter_result.remaining_targets, - playing_state.hud.score.score, - ); - if ($1) { - _block = new SpawnResult( - listPrepend($target.create_target(), filter_result.remaining_targets), - 0.0, - ); - } else { - _block = new SpawnResult(filter_result.remaining_targets, new_spawn_timer); - } - let spawn_result = _block; - let new_mouse = get_mouse_position(); - return new PlayingState( - spawn_result.targets, - playing_state.physics, - (() => { - let _record = playing_state.hud; - return new Hud( - _record.score, - (() => { - let _record$1 = playing_state.hud.cross_hair; - return new CrossHair(new_mouse, _record$1.colorable, _record$1.size); - })(), - (() => { - let _record$1 = playing_state.hud.health; - return new Health( - _record$1.position, - _record$1.size, - playing_state.hud.health.amount - filter_result.health_loss, - _record$1.max_health, - ); - })(), - ); - })(), - new_mouse, - spawn_result.spawn_timer, - ); -} - -function update_state(state) { - if (state instanceof MainMenu) { - return state; - } else if (state instanceof Playing) { - let playing_state = state.state; - let prev_mouse = state.previous_mouse_pressed; - return new Playing(update_playing_state(playing_state), prev_mouse); - } else { - return state; - } -} - -function find_clicked_target(mouse, targets) { - return $list.find( - targets, - (target) => { return $target.is_point_in_target(mouse, target); }, - ); -} - -function handle_playing_click(playing_state) { - let $ = find_clicked_target(playing_state.mouse, playing_state.targets); - if ($ instanceof Ok) { - let clicked_target = $[0]; - return handle_target_click(playing_state, clicked_target); - } else { - return playing_state; - } -} - -function handle_main_menu_click(mouse_pressed) { - if (mouse_pressed) { - return new Playing(init_playing_state(), false); - } else { - return new MainMenu(); - } -} - -function handle_playing_state(playing_state, mouse_pressed) { - let _block; - if (mouse_pressed) { - _block = handle_playing_click(playing_state); - } else { - _block = playing_state; - } - let new_state = _block; - let $ = new_state.hud.health.amount <= 0; - if ($) { - return new GameOver(new_state.hud.score.score, mouse_pressed); - } else { - return new Playing(new_state, mouse_pressed); - } -} - -function handle_game_over_click( - final_score, - mouse_pressed, - previous_mouse_pressed -) { - let just_clicked = mouse_pressed && !previous_mouse_pressed; - if (just_clicked) { - return new Playing(init_playing_state(), false); - } else { - return new GameOver(final_score, mouse_pressed); - } -} - -function handle_events(state) { - let current_mouse_pressed = is_mouse_pressed(); - if (state instanceof MainMenu) { - return handle_main_menu_click(current_mouse_pressed); - } else if (state instanceof Playing) { - let playing_state = state.state; - return handle_playing_state(playing_state, current_mouse_pressed); - } else { - let final_score = state.final_score; - let previous_mouse_pressed = state.previous_mouse_pressed; - return handle_game_over_click( - final_score, - current_mouse_pressed, - previous_mouse_pressed, - ); - } -} - -function game_loop(state) { - $rendering.render(state); - return request_animation_frame( - () => { - let _pipe = handle_events(state); - let _pipe$1 = update_state(_pipe); - return game_loop(_pipe$1); - }, - ); -} - -export function main() { - return game_loop(new MainMenu()); -} diff --git a/build/dev/javascript/stellar_prune/gleam.mjs b/build/dev/javascript/stellar_prune/gleam.mjs deleted file mode 100644 index 197cbbc..0000000 --- a/build/dev/javascript/stellar_prune/gleam.mjs +++ /dev/null @@ -1 +0,0 @@ -export * from "../prelude.mjs"; diff --git a/build/dev/javascript/stellar_prune/hud.mjs b/build/dev/javascript/stellar_prune/hud.mjs deleted file mode 100644 index fafec79..0000000 --- a/build/dev/javascript/stellar_prune/hud.mjs +++ /dev/null @@ -1,153 +0,0 @@ -import * as $float from "../gleam_stdlib/gleam/float.mjs"; -import * as $int from "../gleam_stdlib/gleam/int.mjs"; -import * as $paint from "../paint/paint.mjs"; -import * as $canvas from "../paint/paint/canvas.mjs"; -import { toList, CustomType as $CustomType } from "./gleam.mjs"; -import * as $physics from "./physics.mjs"; -import { Vec2 } from "./physics.mjs"; -import * as $target from "./target.mjs"; -import { Colorable } from "./target.mjs"; - -export class Score extends $CustomType { - constructor(position, colorable, score) { - super(); - this.position = position; - this.colorable = colorable; - this.score = score; - } -} -export const Score$Score = (position, colorable, score) => - new Score(position, colorable, score); -export const Score$isScore = (value) => value instanceof Score; -export const Score$Score$position = (value) => value.position; -export const Score$Score$0 = (value) => value.position; -export const Score$Score$colorable = (value) => value.colorable; -export const Score$Score$1 = (value) => value.colorable; -export const Score$Score$score = (value) => value.score; -export const Score$Score$2 = (value) => value.score; - -export class CrossHair extends $CustomType { - constructor(position, colorable, size) { - super(); - this.position = position; - this.colorable = colorable; - this.size = size; - } -} -export const CrossHair$CrossHair = (position, colorable, size) => - new CrossHair(position, colorable, size); -export const CrossHair$isCrossHair = (value) => value instanceof CrossHair; -export const CrossHair$CrossHair$position = (value) => value.position; -export const CrossHair$CrossHair$0 = (value) => value.position; -export const CrossHair$CrossHair$colorable = (value) => value.colorable; -export const CrossHair$CrossHair$1 = (value) => value.colorable; -export const CrossHair$CrossHair$size = (value) => value.size; -export const CrossHair$CrossHair$2 = (value) => value.size; - -export class Health extends $CustomType { - constructor(position, size, amount, max_health) { - super(); - this.position = position; - this.size = size; - this.amount = amount; - this.max_health = max_health; - } -} -export const Health$Health = (position, size, amount, max_health) => - new Health(position, size, amount, max_health); -export const Health$isHealth = (value) => value instanceof Health; -export const Health$Health$position = (value) => value.position; -export const Health$Health$0 = (value) => value.position; -export const Health$Health$size = (value) => value.size; -export const Health$Health$1 = (value) => value.size; -export const Health$Health$amount = (value) => value.amount; -export const Health$Health$2 = (value) => value.amount; -export const Health$Health$max_health = (value) => value.max_health; -export const Health$Health$3 = (value) => value.max_health; - -export class Hud extends $CustomType { - constructor(score, cross_hair, health) { - super(); - this.score = score; - this.cross_hair = cross_hair; - this.health = health; - } -} -export const Hud$Hud = (score, cross_hair, health) => - new Hud(score, cross_hair, health); -export const Hud$isHud = (value) => value instanceof Hud; -export const Hud$Hud$score = (value) => value.score; -export const Hud$Hud$0 = (value) => value.score; -export const Hud$Hud$cross_hair = (value) => value.cross_hair; -export const Hud$Hud$1 = (value) => value.cross_hair; -export const Hud$Hud$health = (value) => value.health; -export const Hud$Hud$2 = (value) => value.health; - -export function score_to_picture(score) { - let position; - let color; - let score$1; - position = score.position; - score$1 = score.score; - color = score.colorable.color; - let _pipe = $paint.text("Score: " + $int.to_string(score$1), 32); - let _pipe$1 = $paint.translate_xy(_pipe, position.x, position.y); - return $paint.fill(_pipe$1, color); -} - -export function cross_hair_to_picture(cross_hair) { - let x; - let y; - let color; - let size; - size = cross_hair.size; - x = cross_hair.position.x; - y = cross_hair.position.y; - color = cross_hair.colorable.color; - let _pipe = $paint.circle(size); - let _pipe$1 = $paint.stroke(_pipe, color, 5.0); - return $paint.translate_xy(_pipe$1, x, y); -} - -function health_to_picture_helper(loop$health, loop$acc, loop$count) { - while (true) { - let health = loop$health; - let acc = loop$acc; - let count = loop$count; - let $ = count < health.max_health; - if ($) { - let _block; - let $1 = count < health.amount; - if ($1) { - _block = $canvas.image_from_src("../res/heart.svg"); - } else { - _block = $canvas.image_from_src("../res/no-heart.svg"); - } - let heart_image = _block; - let size = $float.round(health.size); - loop$health = health; - loop$acc = $paint.combine( - toList([ - acc, - (() => { - let _pipe = $paint.image(heart_image, size, size); - let _pipe$1 = $paint.image_scaling_pixelated(_pipe); - return $paint.translate_xy( - _pipe$1, - $int.to_float(count) * (health.size + 10.0), - 0.0, - ); - })(), - ]), - ); - loop$count = count + 1; - } else { - return acc; - } - } -} - -export function health_to_picture(health) { - let _pipe = health_to_picture_helper(health, $paint.blank(), 0); - return $paint.translate_xy(_pipe, health.position.x, health.position.y); -} diff --git a/build/dev/javascript/stellar_prune/math/math.mjs b/build/dev/javascript/stellar_prune/math/math.mjs deleted file mode 100644 index cbe2232..0000000 --- a/build/dev/javascript/stellar_prune/math/math.mjs +++ /dev/null @@ -1,3 +0,0 @@ -import { sin, cos, tan, atan2, floor, ceil, round, random, pi } from "./math_ffi.mjs"; - -export { atan2, ceil, cos, floor, pi, random, round, sin, tan }; diff --git a/build/dev/javascript/stellar_prune/math/math_ffi.mjs b/build/dev/javascript/stellar_prune/math/math_ffi.mjs deleted file mode 100644 index 8736bc2..0000000 --- a/build/dev/javascript/stellar_prune/math/math_ffi.mjs +++ /dev/null @@ -1,35 +0,0 @@ -export function sin(x) { - return Math.sin(x); -} - -export function cos(x) { - return Math.cos(x); -} - -export function tan(x) { - return Math.tan(x); -} - -export function atan2(y, x) { - return Math.atan2(y, x); -} - -export function floor(x) { - return Math.floor(x); -} - -export function ceil(x) { - return Math.ceil(x); -} - -export function round(x) { - return Math.round(x); -} - -export function random() { - return Math.random(); -} - -export function pi() { - return Math.PI; -} diff --git a/build/dev/javascript/stellar_prune/physics.mjs b/build/dev/javascript/stellar_prune/physics.mjs deleted file mode 100644 index d0eb5a4..0000000 --- a/build/dev/javascript/stellar_prune/physics.mjs +++ /dev/null @@ -1,63 +0,0 @@ -import { CustomType as $CustomType } from "./gleam.mjs"; - -export class Vec2 extends $CustomType { - constructor(x, y) { - super(); - this.x = x; - this.y = y; - } -} -export const Vec2$Vec2 = (x, y) => new Vec2(x, y); -export const Vec2$isVec2 = (value) => value instanceof Vec2; -export const Vec2$Vec2$x = (value) => value.x; -export const Vec2$Vec2$0 = (value) => value.x; -export const Vec2$Vec2$y = (value) => value.y; -export const Vec2$Vec2$1 = (value) => value.y; - -export class RigidBody extends $CustomType { - constructor(velocity, acceleration, rotation, rotation_velocity) { - super(); - this.velocity = velocity; - this.acceleration = acceleration; - this.rotation = rotation; - this.rotation_velocity = rotation_velocity; - } -} -export const RigidBody$RigidBody = (velocity, acceleration, rotation, rotation_velocity) => - new RigidBody(velocity, acceleration, rotation, rotation_velocity); -export const RigidBody$isRigidBody = (value) => value instanceof RigidBody; -export const RigidBody$RigidBody$velocity = (value) => value.velocity; -export const RigidBody$RigidBody$0 = (value) => value.velocity; -export const RigidBody$RigidBody$acceleration = (value) => value.acceleration; -export const RigidBody$RigidBody$1 = (value) => value.acceleration; -export const RigidBody$RigidBody$rotation = (value) => value.rotation; -export const RigidBody$RigidBody$2 = (value) => value.rotation; -export const RigidBody$RigidBody$rotation_velocity = (value) => - value.rotation_velocity; -export const RigidBody$RigidBody$3 = (value) => value.rotation_velocity; - -export class Gravity extends $CustomType { - constructor(acceleration) { - super(); - this.acceleration = acceleration; - } -} -export const Gravity$Gravity = (acceleration) => new Gravity(acceleration); -export const Gravity$isGravity = (value) => value instanceof Gravity; -export const Gravity$Gravity$acceleration = (value) => value.acceleration; -export const Gravity$Gravity$0 = (value) => value.acceleration; - -export class Physics extends $CustomType { - constructor(gravity) { - super(); - this.gravity = gravity; - } -} -export const Physics$Physics = (gravity) => new Physics(gravity); -export const Physics$isPhysics = (value) => value instanceof Physics; -export const Physics$Physics$gravity = (value) => value.gravity; -export const Physics$Physics$0 = (value) => value.gravity; - -export function add_vec2(v1, v2) { - return new Vec2(v1.x + v2.x, v1.y + v2.y); -} diff --git a/build/dev/javascript/stellar_prune/rendering.mjs b/build/dev/javascript/stellar_prune/rendering.mjs deleted file mode 100644 index 457b2f8..0000000 --- a/build/dev/javascript/stellar_prune/rendering.mjs +++ /dev/null @@ -1,155 +0,0 @@ -import * as $int from "../gleam_stdlib/gleam/int.mjs"; -import * as $list from "../gleam_stdlib/gleam/list.mjs"; -import * as $paint from "../paint/paint.mjs"; -import * as $canvas from "../paint/paint/canvas.mjs"; -import { toList, prepend as listPrepend } from "./gleam.mjs"; -import * as $hud from "./hud.mjs"; -import * as $target from "./target.mjs"; -import * as $types from "./types.mjs"; -import { GameOver, MainMenu, Playing } from "./types.mjs"; - -function draw_main_menu() { - let lucy_image = $canvas.image_from_src("../res/lucy.svg"); - let diamond_image = $canvas.image_from_src("../res/diamond.svg"); - let rocket_image = $canvas.image_from_src("../res/rocket.svg"); - return $paint.combine( - toList([ - (() => { - let _pipe = $paint.text("Stellar prune", 72); - let _pipe$1 = $paint.translate_xy(_pipe, 300.0, 100.0); - let _pipe$2 = $paint.fill(_pipe$1, $paint.colour_hex("#ffffff")); - return $paint.image_scaling_pixelated(_pipe$2); - })(), - (() => { - let _pipe = $paint.text("Click/swipe the targets to score points!", 28); - let _pipe$1 = $paint.translate_xy(_pipe, 320.0, 200.0); - let _pipe$2 = $paint.fill(_pipe$1, $paint.colour_hex("#aaaaaa")); - return $paint.image_scaling_pixelated(_pipe$2); - })(), - (() => { - let _pipe = $paint.text( - "Don't let them escape or you'll lose health!", - 28, - ); - let _pipe$1 = $paint.translate_xy(_pipe, 320.0, 240.0); - let _pipe$2 = $paint.fill(_pipe$1, $paint.colour_hex("#aaaaaa")); - return $paint.image_scaling_pixelated(_pipe$2); - })(), - (() => { - let _pipe = $paint.image(lucy_image, 80, 80); - let _pipe$1 = $paint.image_scaling_pixelated(_pipe); - return $paint.translate_xy(_pipe$1, 320.0, 320.0); - })(), - (() => { - let _pipe = $paint.text("Lucy - Click for 1 point.", 24); - let _pipe$1 = $paint.translate_xy(_pipe, 420.0, 370.0); - let _pipe$2 = $paint.fill(_pipe$1, $paint.colour_hex("#ffffff")); - return $paint.image_scaling_pixelated(_pipe$2); - })(), - (() => { - let _pipe = $paint.image(diamond_image, 80, 80); - let _pipe$1 = $paint.image_scaling_pixelated(_pipe); - return $paint.translate_xy(_pipe$1, 320.0, 420.0); - })(), - (() => { - let _pipe = $paint.text("Diamond - Click for 3 points!", 24); - let _pipe$1 = $paint.translate_xy(_pipe, 420.0, 460.0); - let _pipe$2 = $paint.fill(_pipe$1, $paint.colour_hex("#ffffff")); - return $paint.image_scaling_pixelated(_pipe$2); - })(), - (() => { - let _pipe = $paint.image(rocket_image, 80, 80); - let _pipe$1 = $paint.image_scaling_pixelated(_pipe); - return $paint.translate_xy(_pipe$1, 320.0, 520.0); - })(), - (() => { - let _pipe = $paint.text("Rocket - AVOID! Loses 1 health", 24); - let _pipe$1 = $paint.translate_xy(_pipe, 420.0, 560.0); - let _pipe$2 = $paint.fill(_pipe$1, $paint.colour_hex("#ff6666")); - return $paint.image_scaling_pixelated(_pipe$2); - })(), - (() => { - let _pipe = $paint.text("Click to play!", 48); - let _pipe$1 = $paint.translate_xy(_pipe, 420.0, 680.0); - let _pipe$2 = $paint.fill(_pipe$1, $paint.colour_hex("#ffaff3")); - return $paint.image_scaling_pixelated(_pipe$2); - })(), - ]), - ); -} - -function draw_game_over(final_score) { - return $paint.combine( - toList([ - (() => { - let _pipe = $paint.text("Well done!", 128); - let _pipe$1 = $paint.translate_xy(_pipe, 300.0, 175.0); - let _pipe$2 = $paint.fill(_pipe$1, $paint.colour_hex("#ffaff3")); - return $paint.image_scaling_pixelated(_pipe$2); - })(), - (() => { - let _pipe = $paint.text("Final Score: ", 48); - let _pipe$1 = $paint.translate_xy(_pipe, 440.0, 400.0); - let _pipe$2 = $paint.fill(_pipe$1, $paint.colour_hex("#ffffff")); - return $paint.image_scaling_pixelated(_pipe$2); - })(), - (() => { - let _pipe = $paint.text($int.to_string(final_score), 48); - let _pipe$1 = $paint.translate_xy(_pipe, 710.0, 400.0); - let _pipe$2 = $paint.fill(_pipe$1, $paint.colour_hex("#ffaff3")); - return $paint.image_scaling_pixelated(_pipe$2); - })(), - (() => { - let _pipe = $paint.text("Click to play again!", 32); - let _pipe$1 = $paint.translate_xy(_pipe, 455.0, 600.0); - let _pipe$2 = $paint.fill(_pipe$1, $paint.colour_hex("#ffaff3")); - return $paint.image_scaling_pixelated(_pipe$2); - })(), - ]), - ); -} - -function draw_playing(playing_state) { - let target_pictures = $list.map( - playing_state.targets, - (target) => { - let position; - let rigid_body; - let paintable; - position = target.position; - rigid_body = target.rigid_body; - paintable = target.paintable; - let _pipe = $target.paintable_to_picture(paintable); - let _pipe$1 = $paint.rotate(_pipe, $paint.angle_deg(rigid_body.rotation)); - return $paint.translate_xy(_pipe$1, position.x, position.y); - }, - ); - let hud_without_crosshair = $paint.combine( - toList([ - $hud.health_to_picture(playing_state.hud.health), - $hud.score_to_picture(playing_state.hud.score), - ]), - ); - let crosshair = $hud.cross_hair_to_picture(playing_state.hud.cross_hair); - return $paint.combine( - listPrepend( - hud_without_crosshair, - $list.append(target_pictures, toList([crosshair])), - ), - ); -} - -export function render(state) { - let _block; - if (state instanceof MainMenu) { - _block = draw_main_menu(); - } else if (state instanceof Playing) { - let playing_state = state.state; - _block = draw_playing(playing_state); - } else { - let final_score = state.final_score; - _block = draw_game_over(final_score); - } - let picture = _block; - return $canvas.display((_) => { return picture; }, "#canvas"); -} diff --git a/build/dev/javascript/stellar_prune/target.mjs b/build/dev/javascript/stellar_prune/target.mjs deleted file mode 100644 index 04732a2..0000000 --- a/build/dev/javascript/stellar_prune/target.mjs +++ /dev/null @@ -1,194 +0,0 @@ -import * as $int from "../gleam_stdlib/gleam/int.mjs"; -import * as $paint from "../paint/paint.mjs"; -import * as $canvas from "../paint/paint/canvas.mjs"; -import { CustomType as $CustomType } from "./gleam.mjs"; -import * as $math from "./math/math.mjs"; -import * as $physics from "./physics.mjs"; -import { RigidBody, Vec2, add_vec2 } from "./physics.mjs"; - -export class Colorable extends $CustomType { - constructor(color) { - super(); - this.color = color; - } -} -export const Colorable$Colorable = (color) => new Colorable(color); -export const Colorable$isColorable = (value) => value instanceof Colorable; -export const Colorable$Colorable$color = (value) => value.color; -export const Colorable$Colorable$0 = (value) => value.color; - -export class Size extends $CustomType { - constructor(width, height) { - super(); - this.width = width; - this.height = height; - } -} -export const Size$Size = (width, height) => new Size(width, height); -export const Size$isSize = (value) => value instanceof Size; -export const Size$Size$width = (value) => value.width; -export const Size$Size$0 = (value) => value.width; -export const Size$Size$height = (value) => value.height; -export const Size$Size$1 = (value) => value.height; - -export class Square extends $CustomType { - constructor(colorable, size) { - super(); - this.colorable = colorable; - this.size = size; - } -} -export const Paintable$Square = (colorable, size) => - new Square(colorable, size); -export const Paintable$isSquare = (value) => value instanceof Square; -export const Paintable$Square$colorable = (value) => value.colorable; -export const Paintable$Square$0 = (value) => value.colorable; -export const Paintable$Square$size = (value) => value.size; -export const Paintable$Square$1 = (value) => value.size; - -export class Sprite extends $CustomType { - constructor(image, size) { - super(); - this.image = image; - this.size = size; - } -} -export const Paintable$Sprite = (image, size) => new Sprite(image, size); -export const Paintable$isSprite = (value) => value instanceof Sprite; -export const Paintable$Sprite$image = (value) => value.image; -export const Paintable$Sprite$0 = (value) => value.image; -export const Paintable$Sprite$size = (value) => value.size; -export const Paintable$Sprite$1 = (value) => value.size; - -export class Lucy extends $CustomType {} -export const TargetKind$Lucy = () => new Lucy(); -export const TargetKind$isLucy = (value) => value instanceof Lucy; - -export class Diamond extends $CustomType { - constructor(points_value) { - super(); - this.points_value = points_value; - } -} -export const TargetKind$Diamond = (points_value) => new Diamond(points_value); -export const TargetKind$isDiamond = (value) => value instanceof Diamond; -export const TargetKind$Diamond$points_value = (value) => value.points_value; -export const TargetKind$Diamond$0 = (value) => value.points_value; - -export class Rocket extends $CustomType {} -export const TargetKind$Rocket = () => new Rocket(); -export const TargetKind$isRocket = (value) => value instanceof Rocket; - -export class Target extends $CustomType { - constructor(position, rigid_body, paintable, kind) { - super(); - this.position = position; - this.rigid_body = rigid_body; - this.paintable = paintable; - this.kind = kind; - } -} -export const Target$Target = (position, rigid_body, paintable, kind) => - new Target(position, rigid_body, paintable, kind); -export const Target$isTarget = (value) => value instanceof Target; -export const Target$Target$position = (value) => value.position; -export const Target$Target$0 = (value) => value.position; -export const Target$Target$rigid_body = (value) => value.rigid_body; -export const Target$Target$1 = (value) => value.rigid_body; -export const Target$Target$paintable = (value) => value.paintable; -export const Target$Target$2 = (value) => value.paintable; -export const Target$Target$kind = (value) => value.kind; -export const Target$Target$3 = (value) => value.kind; - -export function create_target() { - let vx = ($math.random() * 6.0) - 3.0; - let vy = ($math.random() * -4.0) - 8.0; - let rotation_vel = ($math.random() * 2.0) - 1.0; - let start_x = ($math.random() * 600.0) + 200.0; - let random_type = $math.random(); - let _block; - let r = random_type; - if (r < 0.7) { - _block = ["../res/lucy.svg", new Lucy()]; - } else { - let r$1 = random_type; - if (r$1 < 0.85) { - _block = ["../res/diamond.svg", new Diamond(3)]; - } else { - _block = ["../res/rocket.svg", new Rocket()]; - } - } - let $ = _block; - let sprite_path; - let target_kind; - sprite_path = $[0]; - target_kind = $[1]; - return new Target( - new Vec2(start_x, 900.0), - new RigidBody(new Vec2(vx, vy), new Vec2(0.0, 0.0), 0.0, rotation_vel), - new Sprite($canvas.image_from_src(sprite_path), new Size(120, 120)), - target_kind, - ); -} - -export function update_target(target, gravity) { - let $ = target.rigid_body; - let velocity; - let acceleration; - let rotation; - let rotation_velocity; - velocity = $.velocity; - acceleration = $.acceleration; - rotation = $.rotation; - rotation_velocity = $.rotation_velocity; - let total_acceleration = add_vec2(acceleration, gravity); - let new_velocity = add_vec2(velocity, total_acceleration); - let new_position = add_vec2(target.position, new_velocity); - let new_rigid_body = new RigidBody( - new_velocity, - acceleration, - rotation + rotation_velocity, - rotation_velocity, - ); - return new Target(new_position, new_rigid_body, target.paintable, target.kind); -} - -export function is_point_in_target(point, target) { - let dx = point.x - target.position.x; - let dy = point.y - target.position.y; - let angle_rad = ((target.rigid_body.rotation * $math.pi())) / 180.0; - let cos_angle = $math.cos(angle_rad); - let sin_angle = $math.sin(angle_rad); - let local_x = (dx * cos_angle) + (dy * sin_angle); - let local_y = (dy * cos_angle) - (dx * sin_angle); - let $ = target.paintable; - if ($ instanceof Square) { - let size = $.size; - let half_size = size / 2.0; - return (((local_x >= (0.0 - half_size)) && (local_x <= half_size)) && (local_y >= (0.0 - half_size))) && (local_y <= half_size); - } else { - let size = $.size; - let half_width = $int.to_float(size.width) / 2.0; - let half_height = $int.to_float(size.height) / 2.0; - return (((local_x >= (0.0 - half_width)) && (local_x <= half_width)) && (local_y >= (0.0 - half_height))) && (local_y <= half_height); - } -} - -export function paintable_to_picture(paintable) { - if (paintable instanceof Square) { - let colorable = paintable.colorable; - let size = paintable.size; - let _pipe = $paint.square(size); - return $paint.fill(_pipe, colorable.color); - } else { - let image = paintable.image; - let size = paintable.size; - let _pipe = $paint.image(image, size.width, size.height); - let _pipe$1 = $paint.image_scaling_pixelated(_pipe); - return $paint.translate_xy( - _pipe$1, - 0.0 - ($int.to_float(size.width) / 2.0), - 0.0 - ($int.to_float(size.height) / 2.0), - ); - } -} diff --git a/build/dev/javascript/stellar_prune/types.mjs b/build/dev/javascript/stellar_prune/types.mjs deleted file mode 100644 index 72fff8f..0000000 --- a/build/dev/javascript/stellar_prune/types.mjs +++ /dev/null @@ -1,66 +0,0 @@ -import { CustomType as $CustomType } from "./gleam.mjs"; -import * as $hud from "./hud.mjs"; -import * as $physics from "./physics.mjs"; -import * as $target from "./target.mjs"; - -export class PlayingState extends $CustomType { - constructor(targets, physics, hud, mouse, spawn_timer) { - super(); - this.targets = targets; - this.physics = physics; - this.hud = hud; - this.mouse = mouse; - this.spawn_timer = spawn_timer; - } -} -export const PlayingState$PlayingState = (targets, physics, hud, mouse, spawn_timer) => - new PlayingState(targets, physics, hud, mouse, spawn_timer); -export const PlayingState$isPlayingState = (value) => - value instanceof PlayingState; -export const PlayingState$PlayingState$targets = (value) => value.targets; -export const PlayingState$PlayingState$0 = (value) => value.targets; -export const PlayingState$PlayingState$physics = (value) => value.physics; -export const PlayingState$PlayingState$1 = (value) => value.physics; -export const PlayingState$PlayingState$hud = (value) => value.hud; -export const PlayingState$PlayingState$2 = (value) => value.hud; -export const PlayingState$PlayingState$mouse = (value) => value.mouse; -export const PlayingState$PlayingState$3 = (value) => value.mouse; -export const PlayingState$PlayingState$spawn_timer = (value) => - value.spawn_timer; -export const PlayingState$PlayingState$4 = (value) => value.spawn_timer; - -export class MainMenu extends $CustomType {} -export const GameState$MainMenu = () => new MainMenu(); -export const GameState$isMainMenu = (value) => value instanceof MainMenu; - -export class Playing extends $CustomType { - constructor(state, previous_mouse_pressed) { - super(); - this.state = state; - this.previous_mouse_pressed = previous_mouse_pressed; - } -} -export const GameState$Playing = (state, previous_mouse_pressed) => - new Playing(state, previous_mouse_pressed); -export const GameState$isPlaying = (value) => value instanceof Playing; -export const GameState$Playing$state = (value) => value.state; -export const GameState$Playing$0 = (value) => value.state; -export const GameState$Playing$previous_mouse_pressed = (value) => - value.previous_mouse_pressed; -export const GameState$Playing$1 = (value) => value.previous_mouse_pressed; - -export class GameOver extends $CustomType { - constructor(final_score, previous_mouse_pressed) { - super(); - this.final_score = final_score; - this.previous_mouse_pressed = previous_mouse_pressed; - } -} -export const GameState$GameOver = (final_score, previous_mouse_pressed) => - new GameOver(final_score, previous_mouse_pressed); -export const GameState$isGameOver = (value) => value instanceof GameOver; -export const GameState$GameOver$final_score = (value) => value.final_score; -export const GameState$GameOver$0 = (value) => value.final_score; -export const GameState$GameOver$previous_mouse_pressed = (value) => - value.previous_mouse_pressed; -export const GameState$GameOver$1 = (value) => value.previous_mouse_pressed; diff --git a/build/gleam-dev-erlang.lock b/build/gleam-dev-erlang.lock deleted file mode 100644 index e69de29..0000000 diff --git a/build/gleam-dev-javascript.lock b/build/gleam-dev-javascript.lock deleted file mode 100644 index e69de29..0000000 diff --git a/build/gleam-lsp-erlang.lock b/build/gleam-lsp-erlang.lock deleted file mode 100644 index e69de29..0000000 diff --git a/build/gleam-lsp-javascript.lock b/build/gleam-lsp-javascript.lock deleted file mode 100644 index e69de29..0000000 diff --git a/build/gleam-prod-erlang.lock b/build/gleam-prod-erlang.lock deleted file mode 100644 index e69de29..0000000 diff --git a/build/gleam-prod-javascript.lock b/build/gleam-prod-javascript.lock deleted file mode 100644 index e69de29..0000000 diff --git a/build/packages/gleam.lock b/build/packages/gleam.lock deleted file mode 100644 index e69de29..0000000 diff --git a/build/packages/gleam_community_colour/LICENCE b/build/packages/gleam_community_colour/LICENCE deleted file mode 100644 index a84f0ec..0000000 --- a/build/packages/gleam_community_colour/LICENCE +++ /dev/null @@ -1,190 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - Copyright 2023 Gleam Community Contributors - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. \ No newline at end of file diff --git a/build/packages/gleam_community_colour/README.md b/build/packages/gleam_community_colour/README.md deleted file mode 100644 index 0eccdd7..0000000 --- a/build/packages/gleam_community_colour/README.md +++ /dev/null @@ -1,36 +0,0 @@ -# gleam-community/colour - -A package for a standard Colour type, conversions, and other utilities. - -[![Package Version](https://img.shields.io/hexpm/v/gleam_community_colour)](https://hex.pm/packages/gleam_community_colour) -[![Hex Docs](https://img.shields.io/badge/hex-docs-ffaff3)](https://hexdocs.pm/gleam_community_colour/) - -✨ This project is written in pure Gleam so you can use it anywhere Gleam runs: Erlang, Elixir, Node, Deno, and the browser! - ---- - -## Quickstart - -```gleam -import gleam_community/colour -import gleam_community/colour/accessibility - -pub fn main() { - let foreground = colour.from_hsl(h: 0.858, s: 1.0, l: 0.843) - - let background_options = [colour.light_grey, colour.dark_grey] - - let background = accessibility.maximum_contrast(foreground, background_options) -} -``` - -## Installation - -`gleam_community` packages are published to [hex.pm](https://hex.pm/packages/gleam_community_colour) -with the prefix `gleam_community_`. You can add them to your Gleam projects directly: - -```sh -gleam add gleam_community_colour -``` - -The docs can be found over at [hexdocs.pm](https://hexdocs.pm/gleam_community_colour). diff --git a/build/packages/gleam_community_colour/gleam.toml b/build/packages/gleam_community_colour/gleam.toml deleted file mode 100644 index 3b7155c..0000000 --- a/build/packages/gleam_community_colour/gleam.toml +++ /dev/null @@ -1,13 +0,0 @@ -name = "gleam_community_colour" -version = "2.0.2" -licences = ["Apache-2.0"] -description = "Colour types, conversions, and other utilities" -repository = { type = "github", user = "gleam-community", repo = "colour" } -gleam = ">= 1.4.0" - -[dependencies] -gleam_stdlib = ">= 0.50.0 and < 2.0.0" -gleam_json = ">= 2.2.0 and < 4.0.0" - -[dev-dependencies] -gleeunit = ">= 1.3.0 and < 2.0.0" diff --git a/build/packages/gleam_community_colour/include/gleam_community@colour_Hsla.hrl b/build/packages/gleam_community_colour/include/gleam_community@colour_Hsla.hrl deleted file mode 100644 index 06116df..0000000 --- a/build/packages/gleam_community_colour/include/gleam_community@colour_Hsla.hrl +++ /dev/null @@ -1 +0,0 @@ --record(hsla, {h :: float(), s :: float(), l :: float(), a :: float()}). diff --git a/build/packages/gleam_community_colour/include/gleam_community@colour_Rgba.hrl b/build/packages/gleam_community_colour/include/gleam_community@colour_Rgba.hrl deleted file mode 100644 index fff139e..0000000 --- a/build/packages/gleam_community_colour/include/gleam_community@colour_Rgba.hrl +++ /dev/null @@ -1 +0,0 @@ --record(rgba, {r :: float(), g :: float(), b :: float(), a :: float()}). diff --git a/build/packages/gleam_community_colour/src/gleam_community/colour.gleam b/build/packages/gleam_community_colour/src/gleam_community/colour.gleam deleted file mode 100644 index f394cff..0000000 --- a/build/packages/gleam_community_colour/src/gleam_community/colour.gleam +++ /dev/null @@ -1,1214 +0,0 @@ -//// -//// - **Types** -//// - [`Colour`](#Colour) -//// - [`Color`](#Color) -//// - **Constructors** -//// - [`from_rgb255`](#from_rgb255) -//// - [`from_rgb`](#from_rgb) -//// - [`from_rgba`](#from_rgba) -//// - [`from_hsl`](#from_hsl) -//// - [`from_hsla`](#from_hsla) -//// - [`from_rgb_hex`](#from_rgb_hex) -//// - [`from_rgba_hex`](#from_rgba_hex) -//// - [`from_rgb_hex_string`](#from_rgb_hex_string) -//// - [`from_rgba_hex_string`](#from_rgba_hex_string) -//// - **Conversions** -//// - [`to_rgba`](#to_rgba) -//// - [`to_hsla`](#hsla) -//// - [`to_css_rgba_string`](#to_css_rgba_string) -//// - [`to_rgba_hex_string`](#to_rgba_hex_string) -//// - [`to_rgb_hex_string`](#to_rgb_hex_string) -//// - [`to_rgba_hex`](#to_rgba_hex) -//// - [`to_rgb_hex`](#to_rgb_hex) -//// - **JSON** -//// - [`encode`](#encode) -//// - [`decoder`](#decoder) -//// - **Colours** -//// - [`light_red`](#light_red) -//// - [`red`](#red) -//// - [`dark_red`](#dark_red) -//// - [`light_orange`](#light_orange) -//// - [`orange`](#orange) -//// - [`dark_orange`](#dark_orange) -//// - [`light_yellow`](#light_yellow) -//// - [`yellow`](#yellow) -//// - [`dark_yellow`](#dark_yellow) -//// - [`light_green`](#light_green) -//// - [`green`](#green) -//// - [`dark_green`](#dark_green) -//// - [`light_blue`](#light_blue) -//// - [`blue`](#blue) -//// - [`dark_blue`](#dark_blue) -//// - [`light_purple`](#light_purple) -//// - [`purple`](#purple) -//// - [`dark_purple`](#dark_purple) -//// - [`light_brown`](#light_brown) -//// - [`brown`](#brown) -//// - [`dark_brown`](#dark_brown) -//// - [`black`](#black) -//// - [`white`](#white) -//// - [`light_grey`](#light_grey) -//// - [`grey`](#grey) -//// - [`dark_grey`](#dark_grey) -//// - [`light_gray`](#light_gray) -//// - [`gray`](#gray) -//// - [`dark_gray`](#dark_gray) -//// - [`light_charcoal`](#light_charcoal) -//// - [`charcoal`](#charcoal) -//// - [`dark_charcoal`](#dark_charcoal) -//// - [`pink`](#pink) -//// -//// --- -//// -//// This package was heavily inspired by the `elm-color` module. -//// The original source code can be found -//// here. -//// -////
-//// The license of that package is produced below: -//// -//// -//// > MIT License -//// -//// > Copyright 2018 Aaron VonderHaar -//// -//// > Redistribution and use in source and binary forms, with or without modification, -//// are permitted provided that the following conditions are met: -//// -//// 1. Redistributions of source code must retain the above copyright notice, -//// this list of conditions and the following disclaimer. -//// -//// 2. Redistributions in binary form must reproduce the above copyright notice, -//// this list of conditions and the following disclaimer in the documentation -//// and/or other materials provided with the distribution. -//// -//// 3. Neither the name of the copyright holder nor the names of its contributors -//// may be used to endorse or promote products derived from this software without -//// specific prior written permission. -//// -//// > THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -//// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES -//// OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL -//// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -//// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -//// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -//// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -//// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -//// -//// > The above copyright notice and this permission notice shall be included in all -//// copies or substantial portions of the Software. -////
-//// - -// Just in case we decide in the future to no longer include the above reference -// and license, this package was initially a port of the `elm-color` module: -// -// https://github.com/avh4/elm-color/ -// - -// IMPORTS -------------------------------------------------------------------- - -import gleam/dynamic/decode -import gleam/float -import gleam/int -import gleam/json.{type Json} -import gleam/list -import gleam/result -import gleam/string - -// TYPES ---------------------------------------------------------------------- - -/// A representation of a colour that can be converted to RGBA or HSLA format. -/// -/// -///
-/// -pub opaque type Colour { - Rgba(r: Float, g: Float, b: Float, a: Float) - Hsla(h: Float, s: Float, l: Float, a: Float) -} - -/// Type alias for `Colour` -/// -/// -///
-/// -pub type Color = - Colour - -// UTILITY -------------------------------------------------------------------- - -fn valid_colour_value(c: Float) -> Result(Float, Nil) { - case c >. 1.0 || c <. 0.0 { - True -> Error(Nil) - False -> Ok(c) - } -} - -fn hue_to_rgb(hue: Float, m1: Float, m2: Float) -> Float { - let h = case hue { - _ if hue <. 0.0 -> hue +. 1.0 - _ if hue >. 1.0 -> hue -. 1.0 - _ -> hue - } - - let h_t_6 = h *. 6.0 - let h_t_2 = h *. 2.0 - let h_t_3 = h *. 3.0 - - case h { - _ if h_t_6 <. 1.0 -> m1 +. { m2 -. m1 } *. h *. 6.0 - _ if h_t_2 <. 1.0 -> m2 - _ if h_t_3 <. 2.0 -> m1 +. { m2 -. m1 } *. { 2.0 /. 3.0 -. h } *. 6.0 - _ -> m1 - } -} - -fn hex_string_to_int(hex_string: String) -> Result(Int, Nil) { - let hex = case hex_string { - "#" <> hex_number -> hex_number - "0x" <> hex_number -> hex_number - _ -> hex_string - } - - hex - |> string.lowercase() - |> string.to_graphemes() - |> list.reverse() - |> list.index_fold(Ok(0), fn(total, char, index) { - case total { - Error(Nil) -> Error(Nil) - Ok(v) -> { - use num <- result.try(case char { - "a" -> Ok(10) - "b" -> Ok(11) - "c" -> Ok(12) - "d" -> Ok(13) - "e" -> Ok(14) - "f" -> Ok(15) - _ -> int.parse(char) - }) - use base <- result.try(int.power(16, int.to_float(index))) - Ok(v + float.round(int.to_float(num) *. base)) - } - } - }) -} - -fn hsla_to_rgba( - h: Float, - s: Float, - l: Float, - a: Float, -) -> #(Float, Float, Float, Float) { - let m2 = case l <=. 0.5 { - True -> l *. { s +. 1.0 } - False -> l +. s -. l *. s - } - - let m1 = l *. 2.0 -. m2 - - let r = hue_to_rgb(h +. 1.0 /. 3.0, m1, m2) - let g = hue_to_rgb(h, m1, m2) - let b = hue_to_rgb(h -. 1.0 /. 3.0, m1, m2) - - #(r, g, b, a) -} - -fn rgba_to_hsla( - r: Float, - g: Float, - b: Float, - a: Float, -) -> #(Float, Float, Float, Float) { - let min_colour = float.min(r, float.min(g, b)) - - let max_colour = float.max(r, float.max(g, b)) - - let h1 = case True { - _ if max_colour == r -> float.divide(g -. b, max_colour -. min_colour) - _ if max_colour == g -> - float.divide(b -. r, max_colour -. min_colour) - |> result.try(fn(d) { Ok(2.0 +. d) }) - _ -> - float.divide(r -. g, max_colour -. min_colour) - |> result.try(fn(d) { Ok(4.0 +. d) }) - } - - let h2 = case h1 { - Ok(v) -> Ok(v *. { 1.0 /. 6.0 }) - _ -> h1 - } - - let h3 = case h2 { - Ok(v) if v <. 0.0 -> v +. 1.0 - Ok(v) -> v - _ -> 0.0 - } - - let l = { min_colour +. max_colour } /. 2.0 - - let s = case True { - _ if min_colour == max_colour -> 0.0 - _ if l <. 0.5 -> - { max_colour -. min_colour } /. { max_colour +. min_colour } - _ -> { max_colour -. min_colour } /. { 2.0 -. max_colour -. min_colour } - } - - #(h3, s, l, a) -} - -// CONSTRUCTORS --------------------------------------------------------------- - -/// Returns a `Result(Colour)` created from the given 8 bit RGB values. -/// -/// Returns `Error(Nil)` if the supplied RGB values are greater than 255 or less than 0. -/// -///
-/// Example: -/// -/// ```gleam -/// fn example() { -/// assert Ok(red) = from_rgb255(255, 0, 0) -/// } -/// ``` -///
-/// -/// -/// -pub fn from_rgb255(r red: Int, g green: Int, b blue: Int) -> Result(Colour, Nil) { - use r <- result.try( - red - |> int.to_float() - |> float.divide(255.0) - |> result.try(valid_colour_value), - ) - - use g <- result.try( - green - |> int.to_float() - |> float.divide(255.0) - |> result.try(valid_colour_value), - ) - - use b <- result.try( - blue - |> int.to_float() - |> float.divide(255.0) - |> result.try(valid_colour_value), - ) - - Ok(Rgba(r: r, g: g, b: b, a: 1.0)) -} - -/// Returns `Result(Colour)` created from the given RGB values. -/// -/// If the supplied RGB values are greater than 1.0 or less than 0.0 returns `Error(Nil)` -/// -///
-/// Example: -/// -/// ```gleam -/// fn example() { -/// assert Ok(red) = from_rgb(1.0, 0.0, 0.0) -/// } -/// ``` -///
-/// -/// -/// -pub fn from_rgb( - r red: Float, - g green: Float, - b blue: Float, -) -> Result(Colour, Nil) { - use r <- result.try(valid_colour_value(red)) - use g <- result.try(valid_colour_value(green)) - use b <- result.try(valid_colour_value(blue)) - - Ok(Rgba(r: r, g: g, b: b, a: 1.0)) -} - -/// Returns `Result(Colour)` created from the given RGBA values. -/// -/// Returns `Error(Nil)` if the supplied RGBA values are greater than 1.0 or less than 0.0. -/// -///
-/// Example: -/// -/// ```gleam -/// fn example() { -/// assert Ok(red_half_opacity) = from_rbga(1.0, 0.0, 0.0, 0.5) -/// } -/// ``` -///
-/// -/// -/// -pub fn from_rgba( - r red: Float, - g green: Float, - b blue: Float, - a alpha: Float, -) -> Result(Colour, Nil) { - use r <- result.try(valid_colour_value(red)) - use g <- result.try(valid_colour_value(green)) - use b <- result.try(valid_colour_value(blue)) - use a <- result.try(valid_colour_value(alpha)) - - Ok(Rgba(r: r, g: g, b: b, a: a)) -} - -/// Returns `Result(Colour)` created from the given HSLA values. -/// -/// Returns `Error(Nil)`f the supplied HSLA values are greater than 1.0 or less than 0.0. -/// -///
-/// Example: -/// -/// ```gleam -/// fn example() { -/// assert Ok(red_half_opacity) = from_hsla(0.0, 1.0, 0.5, 0.5) -/// } -/// ``` -///
-/// -/// -/// -pub fn from_hsla( - h hue: Float, - s saturation: Float, - l lightness: Float, - a alpha: Float, -) -> Result(Colour, Nil) { - use h <- result.try(valid_colour_value(hue)) - use s <- result.try(valid_colour_value(saturation)) - use l <- result.try(valid_colour_value(lightness)) - use a <- result.try(valid_colour_value(alpha)) - - Ok(Hsla(h: h, s: s, l: l, a: a)) -} - -/// Returns `Result(Colour)` created from the given HSL values. -/// -/// Returns `Error(Nil)` if the supplied HSL values are greater than 1.0 or less than 0.0. -/// -///
-/// Example: -/// -/// ```gleam -/// fn example() { -/// assert Ok(red) = from_hsla(0.0, 1.0, 0.5) -/// } -/// ``` -///
-/// -/// -/// -pub fn from_hsl( - h hue: Float, - s saturation: Float, - l lightness: Float, -) -> Result(Colour, Nil) { - from_hsla(hue, saturation, lightness, 1.0) -} - -/// Returns a `Result(Colour)` created from the given hex `Int`. -/// -/// Returns `Error(Nil)` if the supplied hex `Int is greater than 0xffffff or less than 0x0. -/// -///
-/// Example: -/// -/// ```gleam -/// fn example() { -/// assert Ok(red) = from_rgb_hex(0xff0000) -/// } -/// ``` -///
-/// -/// -/// -pub fn from_rgb_hex(hex: Int) -> Result(Colour, Nil) { - case hex > 0xffffff || hex < 0 { - True -> Error(Nil) - False -> { - let r = - int.bitwise_shift_right(hex, 16) - |> int.bitwise_and(0xff) - let g = - int.bitwise_shift_right(hex, 8) - |> int.bitwise_and(0xff) - let b = int.bitwise_and(hex, 0xff) - from_rgb255(r, g, b) - } - } -} - -/// Returns a `Result(Colour)` created from the given RGB hex `String`. -/// -/// Returns `Error(Nil)` if the supplied hex `String` is invalid, or greater than `"#ffffff" or less than `"#0"` -/// -///
-/// Example: -/// -/// ```gleam -/// fn example() { -/// assert Ok(red) = from_rgb_hex_string("#ff0000") -/// } -/// ``` -///
-/// -/// -/// -pub fn from_rgb_hex_string(hex_string: String) -> Result(Colour, Nil) { - use hex_int <- result.try(hex_string_to_int(hex_string)) - - from_rgb_hex(hex_int) -} - -/// Returns a `Result(Colour)` created from the given RGBA hex `String`. -/// -/// Returns `Error(Nil)` if the supplied hex `String` is invalid, or greater than `"#ffffffff" or less than `"#0"` -/// -///
-/// Example: -/// -/// ```gleam -/// fn example() { -/// assert Ok(red_half_opacity) = from_rgba_hex_string("#ff00007f") -/// } -/// ``` -///
-/// -/// -/// -pub fn from_rgba_hex_string(hex_string: String) -> Result(Colour, Nil) { - use hex_int <- result.try(hex_string_to_int(hex_string)) - - from_rgba_hex(hex_int) -} - -/// Returns a `Result(Colour)` created from the given hex `Int`. -/// -/// Returns `Error(Nil)` if the supplied hex `Int is greater than 0xffffffff or less than 0x0. -/// -///
-/// Example: -/// -/// ```gleam -/// fn example() { -/// assert Ok(red_half_opacity) = from_rgba_hex(0xff00007f) -/// } -/// ``` -///
-/// -/// -/// -pub fn from_rgba_hex(hex: Int) -> Result(Colour, Nil) { - case hex > 0xffffffff || hex < 0 { - True -> Error(Nil) - False -> { - // This won't fail because we are always dividing by 255.0 - let assert Ok(r) = - int.bitwise_shift_right(hex, 24) - |> int.bitwise_and(0xff) - |> int.to_float() - |> float.divide(255.0) - // This won't fail because we are always dividing by 255.0 - let assert Ok(g) = - int.bitwise_shift_right(hex, 16) - |> int.bitwise_and(0xff) - |> int.to_float() - |> float.divide(255.0) - // This won't fail because we are always dividing by 255.0 - let assert Ok(b) = - int.bitwise_shift_right(hex, 8) - |> int.bitwise_and(0xff) - |> int.to_float() - |> float.divide(255.0) - // This won't fail because we are always dividing by 255.0 - let assert Ok(a) = - int.bitwise_and(hex, 0xff) - |> int.to_float() - |> float.divide(255.0) - from_rgba(r, g, b, a) - } - } -} - -// CONVERSIONS ---------------------------------------------------------------- - -/// Returns `#(Float, Float, Float, Float)` representing the given `Colour`'s -/// R, G, B, and A values respectively. -/// -///
-/// Example: -/// -/// ```gleam -/// fn example() { -/// assert Ok(red) = from_rgb255(255, 0, 0) -/// let #(r, g, b, a) = to_rgba(red) -/// } -/// ``` -///
-/// -/// -/// -pub fn to_rgba(colour: Colour) -> #(Float, Float, Float, Float) { - case colour { - Rgba(r, g, b, a) -> #(r, g, b, a) - Hsla(h, s, l, a) -> hsla_to_rgba(h, s, l, a) - } -} - -/// Returns `#(Float, Float, Float, Float)` representing the given `Colour`'s -/// H, S, L, and A values respectively. -/// -///
-/// Example: -/// -/// ```gleam -/// fn example() { -/// assert Ok(red) = from_rgb255(255, 0, 0) -/// let #(h, s, l, a) = to_hsla(red) -/// } -/// ``` -///
-/// -/// -/// -pub fn to_hsla(colour: Colour) -> #(Float, Float, Float, Float) { - case colour { - Hsla(h, s, l, a) -> #(h, s, l, a) - Rgba(r, g, b, a) -> rgba_to_hsla(r, g, b, a) - } -} - -/// Returns an rgba formatted CSS `String` created from the given `Colour`. -/// -///
-/// Example: -/// -/// ```gleam -/// fn example() { -/// assert Ok(red) = from_rgb255(255, 0, 0) -/// let css_red = to_css_rgba_string(red) -/// } -/// ``` -///
-/// -/// -/// -pub fn to_css_rgba_string(colour: Colour) -> String { - let #(r, g, b, a) = to_rgba(colour) - - let percent = fn(x: Float) -> Float { - // This won't fail because we are always dividing by 100.0 - let assert Ok(p) = - x - |> float.multiply(10_000.0) - |> float.round() - |> int.to_float() - |> float.divide(100.0) - - p - } - - let round_to = fn(x: Float) -> Float { - // This won't fail because we are always dividing by 1000.0 - let assert Ok(r) = - x - |> float.multiply(1000.0) - |> float.round() - |> int.to_float() - |> float.divide(1000.0) - - r - } - - string.join( - [ - "rgba(", - float.to_string(percent(r)) <> "%,", - float.to_string(percent(g)) <> "%,", - float.to_string(percent(b)) <> "%,", - float.to_string(round_to(a)), - ")", - ], - "", - ) -} - -/// Returns an rgba hex formatted `String` created from the given `Colour`. -/// -///
-/// Example: -/// -/// ```gleam -/// fn example() { -/// assert Ok(red) = from_rgba(1.0, 0.0, 0.0, 1.0) -/// let red_hex = to_rgba_hex_string(red) -/// } -/// ``` -///
-/// -/// -/// -pub fn to_rgba_hex_string(colour: Colour) -> String { - let hex_string = - to_rgba_hex(colour) - |> int.to_base16() - - case string.length(hex_string) { - 8 -> hex_string - l -> string.repeat("0", 8 - l) <> hex_string - } -} - -/// Returns an rgb hex formatted `String` created from the given `Colour`. -/// -///
-/// Example: -/// -/// ```gleam -/// fn example() { -/// assert Ok(red) = from_rgba(255, 0, 0) -/// let red_hex = to_rgb_hex_string(red) -/// } -/// ``` -///
-/// -/// -/// -pub fn to_rgb_hex_string(colour: Colour) -> String { - let hex_string = - to_rgb_hex(colour) - |> int.to_base16() - - case string.length(hex_string) { - 6 -> hex_string - l -> string.repeat("0", 6 - l) <> hex_string - } -} - -/// Returns an hex `Int` created from the given `Colour`. -/// -///
-/// Example: -/// -/// ```gleam -/// fn example() { -/// assert Ok(red) = from_rgba(1.0, 0.0, 0.0, 1.0) -/// let red_hex_int = to_rgba_hex(red) -/// } -/// ``` -///
-/// -/// -/// -pub fn to_rgba_hex(colour: Colour) -> Int { - let #(r, g, b, a) = to_rgba(colour) - - let red = - r *. 255.0 - |> float.round() - |> int.bitwise_shift_left(24) - - let green = - g *. 255.0 - |> float.round() - |> int.bitwise_shift_left(16) - - let blue = - b *. 255.0 - |> float.round() - |> int.bitwise_shift_left(8) - - let alpha = - a *. 255.0 - |> float.round() - - red + green + blue + alpha -} - -/// Returns a rgb hex `Int` created from the given `Colour`. -/// -///
-/// Example: -/// -/// ```gleam -/// fn example() { -/// assert Ok(red) = from_rgba(255, 0, 0) -/// let red_hex_int = to_rgb_hex(red) -/// } -/// ``` -///
-/// -/// -/// -pub fn to_rgb_hex(colour: Colour) -> Int { - let #(r, g, b, _) = to_rgba(colour) - - let red = - r *. 255.0 - |> float.round() - |> int.bitwise_shift_left(16) - - let green = - g *. 255.0 - |> float.round() - |> int.bitwise_shift_left(8) - - let blue = - b *. 255.0 - |> float.round() - - red + green + blue -} - -// JSON ------------------------------------------------------------------------ - -/// Encodes a `Colour` value as a Gleam [`Json`](https://hexdocs.pm/gleam_json/gleam/json.html#Json) -/// value. You'll need this if you want to send a `Colour` value over the network -/// in a HTTP request or response, for example. -/// -/// -/// -pub fn encode(colour: Colour) -> Json { - case colour { - Rgba(r, g, b, a) -> encode_rgba(r, g, b, a) - Hsla(h, s, l, a) -> encode_hsla(h, s, l, a) - } -} - -fn encode_rgba(r: Float, g: Float, b: Float, a: Float) -> Json { - json.object([ - #("r", json.float(r)), - #("g", json.float(g)), - #("b", json.float(b)), - #("a", json.float(a)), - ]) -} - -fn encode_hsla(h: Float, s: Float, l: Float, a: Float) -> Json { - json.object([ - #("h", json.float(h)), - #("s", json.float(s)), - #("l", json.float(l)), - #("a", json.float(a)), - ]) -} - -/// Attempt to decode some [`Dynamic`](https://hexdocs.pm/gleam_stdlib/gleam/dynamic.html#Dynamic) -/// value into a `Colour`. Most often you'll use this to decode some JSON. -/// -/// -/// -pub fn decoder() -> decode.Decoder(Colour) { - decode.one_of(rgba_decoder(), or: [hsla_decoder()]) -} - -fn rgba_decoder() -> decode.Decoder(Colour) { - use r <- decode.field("r", decode.float) - use g <- decode.field("g", decode.float) - use b <- decode.field("b", decode.float) - use a <- decode.field("a", decode.float) - - decode.success(Rgba(r, g, b, a)) -} - -fn hsla_decoder() -> decode.Decoder(Colour) { - use h <- decode.field("h", decode.float) - use s <- decode.field("s", decode.float) - use l <- decode.field("l", decode.float) - use a <- decode.field("a", decode.float) - - decode.success(Hsla(h, s, l, a)) -} - -// COLOURS --------------------------------------------------------------------- - -/// A `Colour` reprsenting the colour RGBA(239, 41, 41, 1.0) -pub const light_red = Rgba( - r: 0.9372549019607843, - g: 0.1607843137254902, - b: 0.1607843137254902, - a: 1.0, -) - -/// A `Colour` reprsenting the colour RGBA(204, 0, 0, 1.0) -pub const red = Rgba(r: 0.8, g: 0.0, b: 0.0, a: 1.0) - -/// A `Colour` reprsenting the colour RGBA(164, 0, 0, 1.0) -pub const dark_red = Rgba(r: 0.6431372549019608, g: 0.0, b: 0.0, a: 1.0) - -/// A `Colour` reprsenting the colour RGBA(252, 175, 62, 1.0) -pub const light_orange = Rgba( - r: 0.9882352941176471, - g: 0.6862745098039216, - b: 0.24313725490196078, - a: 1.0, -) - -/// A `Colour` reprsenting the colour RGBA(245, 121, 0, 1.0) -pub const orange = Rgba( - r: 0.9607843137254902, - g: 0.4745098039215686, - b: 0.0, - a: 1.0, -) - -/// A `Colour` reprsenting the colour RGBA(206, 92, 0, 1.0) -pub const dark_orange = Rgba( - r: 0.807843137254902, - g: 0.3607843137254902, - b: 0.0, - a: 1.0, -) - -/// A `Colour` reprsenting the colour RGBA(255, 233, 79, 1.0) -pub const light_yellow = Rgba( - r: 1.0, - g: 0.9137254901960784, - b: 0.30980392156862746, - a: 1.0, -) - -/// A `Colour` reprsenting the colour RGBA(237, 212, 0, 1.0) -pub const yellow = Rgba( - r: 0.9294117647058824, - g: 0.8313725490196079, - b: 0.0, - a: 1.0, -) - -/// A `Colour` reprsenting the colour RGBA(196, 160, 0, 1.0) -pub const dark_yellow = Rgba( - r: 0.7686274509803922, - g: 0.6274509803921569, - b: 0.0, - a: 1.0, -) - -/// A `Colour` reprsenting the colour RGBA(138, 226, 52, 1.0) -pub const light_green = Rgba( - r: 0.5411764705882353, - g: 0.8862745098039215, - b: 0.20392156862745098, - a: 1.0, -) - -/// A `Colour` reprsenting the colour RGBA(115, 210, 22, 1.0) -pub const green = Rgba( - r: 0.45098039215686275, - g: 0.8235294117647058, - b: 0.08627450980392157, - a: 1.0, -) - -/// A `Colour` reprsenting the colour RGBA(78, 154, 6, 1.0) -pub const dark_green = Rgba( - r: 0.3058823529411765, - g: 0.6039215686274509, - b: 0.023529411764705882, - a: 1.0, -) - -/// A `Colour` reprsenting the colour RGBA(114, 159, 207, 1.0) -pub const light_blue = Rgba( - r: 0.4470588235294118, - g: 0.6235294117647059, - b: 0.8117647058823529, - a: 1.0, -) - -/// A `Colour` reprsenting the colour RGBA(52, 101, 164, 1.0) -pub const blue = Rgba( - r: 0.20392156862745098, - g: 0.396078431372549, - b: 0.6431372549019608, - a: 1.0, -) - -/// A `Colour` reprsenting the colour RGBA(32, 74, 135, 1.0) -pub const dark_blue = Rgba( - r: 0.12549019607843137, - g: 0.2901960784313726, - b: 0.5294117647058824, - a: 1.0, -) - -/// A `Colour` reprsenting the colour RGBA(173, 127, 168, 1.0) -pub const light_purple = Rgba( - r: 0.6784313725490196, - g: 0.4980392156862745, - b: 0.6588235294117647, - a: 1.0, -) - -/// A `Colour` reprsenting the colour RGBA(117, 80, 123, 1.0) -pub const purple = Rgba( - r: 0.4588235294117647, - g: 0.3137254901960784, - b: 0.4823529411764706, - a: 1.0, -) - -/// A `Colour` reprsenting the colour RGBA(92, 53, 102, 1.0) -pub const dark_purple = Rgba( - r: 0.3607843137254902, - g: 0.20784313725490197, - b: 0.4, - a: 1.0, -) - -/// A `Colour` reprsenting the colour RGBA(233, 185, 110, 1.0) -pub const light_brown = Rgba( - r: 0.9137254901960784, - g: 0.7254901960784313, - b: 0.43137254901960786, - a: 1.0, -) - -/// A `Colour` reprsenting the colour RGBA(193, 125, 17, 1.0) -pub const brown = Rgba( - r: 0.7568627450980392, - g: 0.49019607843137253, - b: 0.06666666666666667, - a: 1.0, -) - -/// A `Colour` reprsenting the colour RGBA(143, 89, 2, 1.0) -pub const dark_brown = Rgba( - r: 0.5607843137254902, - g: 0.34901960784313724, - b: 0.00784313725490196, - a: 1.0, -) - -/// A `Colour` reprsenting the colour RGBA(0, 0, 0, 1.0) -pub const black = Rgba(r: 0.0, g: 0.0, b: 0.0, a: 1.0) - -/// A `Colour` reprsenting the colour RGBA(255, 255, 255, 1.0) -pub const white = Rgba(r: 1.0, g: 1.0, b: 1.0, a: 1.0) - -/// A `Colour` reprsenting the colour RGBA(238, 238, 236, 1.0) -pub const light_grey = Rgba( - r: 0.9333333333333333, - g: 0.9333333333333333, - b: 0.9254901960784314, - a: 1.0, -) - -/// A `Colour` reprsenting the colour RGBA(211, 215, 207, 1.0) -pub const grey = Rgba( - r: 0.8274509803921568, - g: 0.8431372549019608, - b: 0.8117647058823529, - a: 1.0, -) - -/// A `Colour` reprsenting the colour RGBA(186, 189, 182, 1.0) -pub const dark_grey = Rgba( - r: 0.7294117647058823, - g: 0.7411764705882353, - b: 0.7137254901960784, - a: 1.0, -) - -/// A `Colour` reprsenting the colour RGBA(238, 238, 236, 1.0) -pub const light_gray = Rgba( - r: 0.9333333333333333, - g: 0.9333333333333333, - b: 0.9254901960784314, - a: 1.0, -) - -/// A `Colour` reprsenting the colour RGBA(211, 215, 207, 1.0) -pub const gray = Rgba( - r: 0.8274509803921568, - g: 0.8431372549019608, - b: 0.8117647058823529, - a: 1.0, -) - -/// A `Colour` reprsenting the colour RGBA(186, 189, 182, 1.0) -pub const dark_gray = Rgba( - r: 0.7294117647058823, - g: 0.7411764705882353, - b: 0.7137254901960784, - a: 1.0, -) - -/// A `Colour` reprsenting the colour RGBA(136, 138, 133, 1.0) -pub const light_charcoal = Rgba( - r: 0.5333333333333333, - g: 0.5411764705882353, - b: 0.5215686274509804, - a: 1.0, -) - -/// A `Colour` reprsenting the colour RGBA(85, 87, 83, 1.0) -pub const charcoal = Rgba( - r: 0.3333333333333333, - g: 0.3411764705882353, - b: 0.3254901960784314, - a: 1.0, -) - -/// A `Colour` reprsenting the colour RGBA(46, 52, 54, 1.0) -pub const dark_charcoal = Rgba( - r: 0.1803921568627451, - g: 0.20392156862745098, - b: 0.21176470588235294, - a: 1.0, -) - -/// A `Colour` reprsenting the colour RGBA(255, 175, 243, 1.0) -pub const pink = Rgba( - r: 1.0, - g: 0.6862745098039216, - b: 0.9529411764705882, - a: 1.0, -) diff --git a/build/packages/gleam_community_colour/src/gleam_community/colour/accessibility.gleam b/build/packages/gleam_community_colour/src/gleam_community/colour/accessibility.gleam deleted file mode 100644 index 54f75e4..0000000 --- a/build/packages/gleam_community_colour/src/gleam_community/colour/accessibility.gleam +++ /dev/null @@ -1,173 +0,0 @@ -//// -//// - **Accessibility** -//// - [`luminance`](#luminance) -//// - [`contrast_ratio`](#contrast_ratio) -//// - [`maximum_contrast`](#maximum_contrast) -//// -//// --- -//// -//// This package was heavily inspired by the `elm-color-extra` module. -//// The original source code can be found -//// here. -//// -////
-//// The license of that package is produced below: -//// -//// -//// > MIT License -//// -//// > Copyright (c) 2016 Andreas Köberle -//// -//// > Permission is hereby granted, free of charge, to any person obtaining a copy -//// of this software and associated documentation files (the "Software"), to deal -//// in the Software without restriction, including without limitation the rights -//// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -//// copies of the Software, and to permit persons to whom the Software is -//// furnished to do so, subject to the following conditions: -//// -//// > The above copyright notice and this permission notice shall be included in all -//// copies or substantial portions of the Software. -//// -//// > THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -//// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -//// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -//// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -//// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -//// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -//// SOFTWARE. -//// -////
-//// - -// Just in case we decide in the future to no longer include the above reference -// and license, this package was initially a port of the `elm-color-extra` module: -// -// https://github.com/noahzgordon/elm-color-extra -// - -// IMPORTS -------------------------------------------------------------------- - -import gleam/float -import gleam/list -import gleam_community/colour.{type Colour} - -// UTILITIES ------------------------------------------------------------------ - -fn intensity(colour_value: Float) -> Float { - // Calculation taken from https://www.w3.org/TR/WCAG20/#relativeluminancedef - case True { - _ if colour_value <=. 0.03928 -> colour_value /. 12.92 - _ -> { - // Is this guaranteed to be `OK`? - let assert Ok(i) = float.power({ colour_value +. 0.055 } /. 1.055, 2.4) - i - } - } -} - -// ACCESSIBILITY -------------------------------------------------------------- - -/// Returns the relative brightness of the given `Colour` as a `Float` between -/// 0.0, and 1.0 with 0.0 being the darkest possible colour and 1.0 being the lightest. -/// -///
-/// Example: -/// -/// ```gleam -/// fn example() { -/// luminance(colour.white) // 1.0 -/// } -/// ``` -///
-/// -/// -/// -pub fn luminance(colour: Colour) -> Float { - // Calculation taken from https://www.w3.org/TR/WCAG20/#relativeluminancedef - let #(r, g, b, _) = colour.to_rgba(colour) - - let r_intensity = intensity(r) - let g_intensity = intensity(g) - let b_intensity = intensity(b) - - 0.2126 *. r_intensity +. 0.7152 *. g_intensity +. 0.0722 *. b_intensity -} - -/// Returns the contrast between two `Colour` values as a `Float` between 1.0, -/// and 21.0 with 1.0 being no contrast and, 21.0 being the highest possible contrast. -/// -///
-/// Example: -/// -/// ```gleam -/// fn example() { -/// contrast_ratio(between: colour.white, and: colour.black) // 21.0 -/// } -/// ``` -///
-/// -/// -/// -pub fn contrast_ratio(between colour_a: Colour, and colour_b: Colour) -> Float { - // Calculation taken from https://www.w3.org/TR/WCAG20/#contrast-ratiodef - let luminance_a = luminance(colour_a) +. 0.05 - let luminance_b = luminance(colour_b) +. 0.05 - - case luminance_a >. luminance_b { - True -> luminance_a /. luminance_b - False -> luminance_b /. luminance_a - } -} - -/// Returns the `Colour` with the highest contrast between the base `Colour`, -/// and and the other provided `Colour` values. -/// -///
-/// Example: -/// -/// ```gleam -/// fn example() { -/// maximum_contrast( -/// colour.yellow, -/// [colour.white, colour.dark_blue, colour.green], -/// ) -/// } -/// ``` -///
-/// -/// -/// -pub fn maximum_contrast( - base: Colour, - colours: List(Colour), -) -> Result(Colour, Nil) { - colours - |> list.sort(fn(colour_a, colour_b) { - let contrast_a = contrast_ratio(base, colour_a) - let contrast_b = contrast_ratio(base, colour_b) - - float.compare(contrast_b, contrast_a) - }) - |> list.first() -} diff --git a/build/packages/gleam_community_colour/src/gleam_community@colour.erl b/build/packages/gleam_community_colour/src/gleam_community@colour.erl deleted file mode 100644 index faee070..0000000 --- a/build/packages/gleam_community_colour/src/gleam_community@colour.erl +++ /dev/null @@ -1,1199 +0,0 @@ --module(gleam_community@colour). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch]). --define(FILEPATH, "src/gleam_community/colour.gleam"). --export([from_rgb255/3, from_rgb/3, from_rgba/4, from_hsla/4, from_hsl/3, from_rgb_hex/1, from_rgb_hex_string/1, from_rgba_hex/1, from_rgba_hex_string/1, to_rgba/1, to_hsla/1, to_css_rgba_string/1, to_rgba_hex/1, to_rgba_hex_string/1, to_rgb_hex/1, to_rgb_hex_string/1, encode/1, decoder/0]). --export_type([colour/0]). - --if(?OTP_RELEASE >= 27). --define(MODULEDOC(Str), -moduledoc(Str)). --define(DOC(Str), -doc(Str)). --else. --define(MODULEDOC(Str), -compile([])). --define(DOC(Str), -compile([])). --endif. - -?MODULEDOC( - "\n" - " - **Types**\n" - " - [`Colour`](#Colour)\n" - " - [`Color`](#Color)\n" - " - **Constructors**\n" - " - [`from_rgb255`](#from_rgb255)\n" - " - [`from_rgb`](#from_rgb)\n" - " - [`from_rgba`](#from_rgba)\n" - " - [`from_hsl`](#from_hsl)\n" - " - [`from_hsla`](#from_hsla)\n" - " - [`from_rgb_hex`](#from_rgb_hex)\n" - " - [`from_rgba_hex`](#from_rgba_hex)\n" - " - [`from_rgb_hex_string`](#from_rgb_hex_string)\n" - " - [`from_rgba_hex_string`](#from_rgba_hex_string)\n" - " - **Conversions**\n" - " - [`to_rgba`](#to_rgba)\n" - " - [`to_hsla`](#hsla)\n" - " - [`to_css_rgba_string`](#to_css_rgba_string)\n" - " - [`to_rgba_hex_string`](#to_rgba_hex_string)\n" - " - [`to_rgb_hex_string`](#to_rgb_hex_string)\n" - " - [`to_rgba_hex`](#to_rgba_hex)\n" - " - [`to_rgb_hex`](#to_rgb_hex)\n" - " - **JSON**\n" - " - [`encode`](#encode)\n" - " - [`decoder`](#decoder)\n" - " - **Colours**\n" - " - [`light_red`](#light_red)\n" - " - [`red`](#red)\n" - " - [`dark_red`](#dark_red)\n" - " - [`light_orange`](#light_orange)\n" - " - [`orange`](#orange)\n" - " - [`dark_orange`](#dark_orange)\n" - " - [`light_yellow`](#light_yellow)\n" - " - [`yellow`](#yellow)\n" - " - [`dark_yellow`](#dark_yellow)\n" - " - [`light_green`](#light_green)\n" - " - [`green`](#green)\n" - " - [`dark_green`](#dark_green)\n" - " - [`light_blue`](#light_blue)\n" - " - [`blue`](#blue)\n" - " - [`dark_blue`](#dark_blue)\n" - " - [`light_purple`](#light_purple)\n" - " - [`purple`](#purple)\n" - " - [`dark_purple`](#dark_purple)\n" - " - [`light_brown`](#light_brown)\n" - " - [`brown`](#brown)\n" - " - [`dark_brown`](#dark_brown)\n" - " - [`black`](#black)\n" - " - [`white`](#white)\n" - " - [`light_grey`](#light_grey)\n" - " - [`grey`](#grey)\n" - " - [`dark_grey`](#dark_grey)\n" - " - [`light_gray`](#light_gray)\n" - " - [`gray`](#gray)\n" - " - [`dark_gray`](#dark_gray)\n" - " - [`light_charcoal`](#light_charcoal)\n" - " - [`charcoal`](#charcoal)\n" - " - [`dark_charcoal`](#dark_charcoal)\n" - " - [`pink`](#pink)\n" - "\n" - " ---\n" - "\n" - " This package was heavily inspired by the `elm-color` module.\n" - " The original source code can be found\n" - " here.\n" - "\n" - "
\n" - " The license of that package is produced below:\n" - "\n" - "\n" - " > MIT License\n" - "\n" - " > Copyright 2018 Aaron VonderHaar\n" - "\n" - " > Redistribution and use in source and binary forms, with or without modification,\n" - " are permitted provided that the following conditions are met:\n" - "\n" - " 1. Redistributions of source code must retain the above copyright notice,\n" - " this list of conditions and the following disclaimer.\n" - "\n" - " 2. Redistributions in binary form must reproduce the above copyright notice,\n" - " this list of conditions and the following disclaimer in the documentation\n" - " and/or other materials provided with the distribution.\n" - "\n" - " 3. Neither the name of the copyright holder nor the names of its contributors\n" - " may be used to endorse or promote products derived from this software without\n" - " specific prior written permission.\n" - "\n" - " > THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\n" - " ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\n" - " OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL\n" - " THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n" - " EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n" - " OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n" - " THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n" - " ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n" - "\n" - " > The above copyright notice and this permission notice shall be included in all\n" - " copies or substantial portions of the Software.\n" - "
\n" - "\n" -). - --opaque colour() :: {rgba, float(), float(), float(), float()} | - {hsla, float(), float(), float(), float()}. - --file("src/gleam_community/colour.gleam", 155). --spec valid_colour_value(float()) -> {ok, float()} | {error, nil}. -valid_colour_value(C) -> - case (C > 1.0) orelse (C < +0.0) of - true -> - {error, nil}; - - false -> - {ok, C} - end. - --file("src/gleam_community/colour.gleam", 162). --spec hue_to_rgb(float(), float(), float()) -> float(). -hue_to_rgb(Hue, M1, M2) -> - H = case Hue of - _ when Hue < +0.0 -> - Hue + 1.0; - - _ when Hue > 1.0 -> - Hue - 1.0; - - _ -> - Hue - end, - H_t_6 = H * 6.0, - H_t_2 = H * 2.0, - H_t_3 = H * 3.0, - case H of - _ when H_t_6 < 1.0 -> - M1 + (((M2 - M1) * H) * 6.0); - - _ when H_t_2 < 1.0 -> - M2; - - _ when H_t_3 < 2.0 -> - M1 + (((M2 - M1) * ((2.0 / 3.0) - H)) * 6.0); - - _ -> - M1 - end. - --file("src/gleam_community/colour.gleam", 181). --spec hex_string_to_int(binary()) -> {ok, integer()} | {error, nil}. -hex_string_to_int(Hex_string) -> - Hex = case Hex_string of - <<"#"/utf8, Hex_number/binary>> -> - Hex_number; - - <<"0x"/utf8, Hex_number@1/binary>> -> - Hex_number@1; - - _ -> - Hex_string - end, - _pipe = Hex, - _pipe@1 = string:lowercase(_pipe), - _pipe@2 = gleam@string:to_graphemes(_pipe@1), - _pipe@3 = lists:reverse(_pipe@2), - gleam@list:index_fold( - _pipe@3, - {ok, 0}, - fun(Total, Char, Index) -> case Total of - {error, nil} -> - {error, nil}; - - {ok, V} -> - gleam@result:'try'(case Char of - <<"a"/utf8>> -> - {ok, 10}; - - <<"b"/utf8>> -> - {ok, 11}; - - <<"c"/utf8>> -> - {ok, 12}; - - <<"d"/utf8>> -> - {ok, 13}; - - <<"e"/utf8>> -> - {ok, 14}; - - <<"f"/utf8>> -> - {ok, 15}; - - _ -> - gleam_stdlib:parse_int(Char) - end, fun(Num) -> - gleam@result:'try'( - gleam@int:power(16, erlang:float(Index)), - fun(Base) -> - {ok, - V + erlang:round( - erlang:float(Num) * Base - )} - end - ) - end) - end end - ). - --file("src/gleam_community/colour.gleam", 212). --spec hsla_to_rgba(float(), float(), float(), float()) -> {float(), - float(), - float(), - float()}. -hsla_to_rgba(H, S, L, A) -> - M2 = case L =< 0.5 of - true -> - L * (S + 1.0); - - false -> - (L + S) - (L * S) - end, - M1 = (L * 2.0) - M2, - R = hue_to_rgb(H + (1.0 / 3.0), M1, M2), - G = hue_to_rgb(H, M1, M2), - B = hue_to_rgb(H - (1.0 / 3.0), M1, M2), - {R, G, B, A}. - --file("src/gleam_community/colour.gleam", 232). --spec rgba_to_hsla(float(), float(), float(), float()) -> {float(), - float(), - float(), - float()}. -rgba_to_hsla(R, G, B, A) -> - Min_colour = gleam@float:min(R, gleam@float:min(G, B)), - Max_colour = gleam@float:max(R, gleam@float:max(G, B)), - H1 = case true of - _ when Max_colour =:= R -> - gleam@float:divide(G - B, Max_colour - Min_colour); - - _ when Max_colour =:= G -> - _pipe = gleam@float:divide(B - R, Max_colour - Min_colour), - gleam@result:'try'(_pipe, fun(D) -> {ok, 2.0 + D} end); - - _ -> - _pipe@1 = gleam@float:divide(R - G, Max_colour - Min_colour), - gleam@result:'try'(_pipe@1, fun(D@1) -> {ok, 4.0 + D@1} end) - end, - H2 = case H1 of - {ok, V} -> - {ok, V * (1.0 / 6.0)}; - - _ -> - H1 - end, - H3 = case H2 of - {ok, V@1} when V@1 < +0.0 -> - V@1 + 1.0; - - {ok, V@2} -> - V@2; - - _ -> - +0.0 - end, - L = (Min_colour + Max_colour) / 2.0, - S = case true of - _ when Min_colour =:= Max_colour -> - +0.0; - - _ when L < 0.5 -> - case (Max_colour + Min_colour) of - +0.0 -> +0.0; - -0.0 -> -0.0; - Gleam@denominator -> (Max_colour - Min_colour) / Gleam@denominator - end; - - _ -> - case ((2.0 - Max_colour) - Min_colour) of - +0.0 -> +0.0; - -0.0 -> -0.0; - Gleam@denominator@1 -> (Max_colour - Min_colour) / Gleam@denominator@1 - end - end, - {H3, S, L, A}. - --file("src/gleam_community/colour.gleam", 300). -?DOC( - " Returns a `Result(Colour)` created from the given 8 bit RGB values.\n" - "\n" - " Returns `Error(Nil)` if the supplied RGB values are greater than 255 or less than 0.\n" - "\n" - "
\n" - " Example:\n" - "\n" - " ```gleam\n" - " fn example() {\n" - " assert Ok(red) = from_rgb255(255, 0, 0)\n" - " }\n" - " ```\n" - "
\n" - "\n" - " \n" -). --spec from_rgb255(integer(), integer(), integer()) -> {ok, colour()} | - {error, nil}. -from_rgb255(Red, Green, Blue) -> - gleam@result:'try'( - begin - _pipe = Red, - _pipe@1 = erlang:float(_pipe), - _pipe@2 = gleam@float:divide(_pipe@1, 255.0), - gleam@result:'try'(_pipe@2, fun valid_colour_value/1) - end, - fun(R) -> - gleam@result:'try'( - begin - _pipe@3 = Green, - _pipe@4 = erlang:float(_pipe@3), - _pipe@5 = gleam@float:divide(_pipe@4, 255.0), - gleam@result:'try'(_pipe@5, fun valid_colour_value/1) - end, - fun(G) -> - gleam@result:'try'( - begin - _pipe@6 = Blue, - _pipe@7 = erlang:float(_pipe@6), - _pipe@8 = gleam@float:divide(_pipe@7, 255.0), - gleam@result:'try'( - _pipe@8, - fun valid_colour_value/1 - ) - end, - fun(B) -> {ok, {rgba, R, G, B, 1.0}} end - ) - end - ) - end - ). - --file("src/gleam_community/colour.gleam", 348). -?DOC( - " Returns `Result(Colour)` created from the given RGB values.\n" - "\n" - " If the supplied RGB values are greater than 1.0 or less than 0.0 returns `Error(Nil)`\n" - "\n" - "
\n" - " Example:\n" - "\n" - " ```gleam\n" - " fn example() {\n" - " assert Ok(red) = from_rgb(1.0, 0.0, 0.0)\n" - " }\n" - " ```\n" - "
\n" - "\n" - " \n" -). --spec from_rgb(float(), float(), float()) -> {ok, colour()} | {error, nil}. -from_rgb(Red, Green, Blue) -> - gleam@result:'try'( - valid_colour_value(Red), - fun(R) -> - gleam@result:'try'( - valid_colour_value(Green), - fun(G) -> - gleam@result:'try'( - valid_colour_value(Blue), - fun(B) -> {ok, {rgba, R, G, B, 1.0}} end - ) - end - ) - end - ). - --file("src/gleam_community/colour.gleam", 383). -?DOC( - " Returns `Result(Colour)` created from the given RGBA values.\n" - "\n" - " Returns `Error(Nil)` if the supplied RGBA values are greater than 1.0 or less than 0.0.\n" - "\n" - "
\n" - " Example:\n" - "\n" - " ```gleam\n" - " fn example() {\n" - " assert Ok(red_half_opacity) = from_rbga(1.0, 0.0, 0.0, 0.5)\n" - " }\n" - " ```\n" - "
\n" - "\n" - " \n" -). --spec from_rgba(float(), float(), float(), float()) -> {ok, colour()} | - {error, nil}. -from_rgba(Red, Green, Blue, Alpha) -> - gleam@result:'try'( - valid_colour_value(Red), - fun(R) -> - gleam@result:'try'( - valid_colour_value(Green), - fun(G) -> - gleam@result:'try'( - valid_colour_value(Blue), - fun(B) -> - gleam@result:'try'( - valid_colour_value(Alpha), - fun(A) -> {ok, {rgba, R, G, B, A}} end - ) - end - ) - end - ) - end - ). - --file("src/gleam_community/colour.gleam", 420). -?DOC( - " Returns `Result(Colour)` created from the given HSLA values.\n" - "\n" - " Returns `Error(Nil)`f the supplied HSLA values are greater than 1.0 or less than 0.0.\n" - "\n" - "
\n" - " Example:\n" - "\n" - " ```gleam\n" - " fn example() {\n" - " assert Ok(red_half_opacity) = from_hsla(0.0, 1.0, 0.5, 0.5)\n" - " }\n" - " ```\n" - "
\n" - "\n" - " \n" -). --spec from_hsla(float(), float(), float(), float()) -> {ok, colour()} | - {error, nil}. -from_hsla(Hue, Saturation, Lightness, Alpha) -> - gleam@result:'try'( - valid_colour_value(Hue), - fun(H) -> - gleam@result:'try'( - valid_colour_value(Saturation), - fun(S) -> - gleam@result:'try'( - valid_colour_value(Lightness), - fun(L) -> - gleam@result:'try'( - valid_colour_value(Alpha), - fun(A) -> {ok, {hsla, H, S, L, A}} end - ) - end - ) - end - ) - end - ). - --file("src/gleam_community/colour.gleam", 457). -?DOC( - " Returns `Result(Colour)` created from the given HSL values.\n" - "\n" - " Returns `Error(Nil)` if the supplied HSL values are greater than 1.0 or less than 0.0.\n" - "\n" - "
\n" - " Example:\n" - "\n" - " ```gleam\n" - " fn example() {\n" - " assert Ok(red) = from_hsla(0.0, 1.0, 0.5)\n" - " }\n" - " ```\n" - "
\n" - "\n" - " \n" -). --spec from_hsl(float(), float(), float()) -> {ok, colour()} | {error, nil}. -from_hsl(Hue, Saturation, Lightness) -> - from_hsla(Hue, Saturation, Lightness, 1.0). - --file("src/gleam_community/colour.gleam", 488). -?DOC( - " Returns a `Result(Colour)` created from the given hex `Int`.\n" - "\n" - " Returns `Error(Nil)` if the supplied hex `Int is greater than 0xffffff or less than 0x0.\n" - "\n" - "
\n" - " Example:\n" - "\n" - " ```gleam\n" - " fn example() {\n" - " assert Ok(red) = from_rgb_hex(0xff0000)\n" - " }\n" - " ```\n" - "
\n" - "\n" - " \n" -). --spec from_rgb_hex(integer()) -> {ok, colour()} | {error, nil}. -from_rgb_hex(Hex) -> - case (Hex > 16#ffffff) orelse (Hex < 0) of - true -> - {error, nil}; - - false -> - R = begin - _pipe = erlang:'bsr'(Hex, 16), - erlang:'band'(_pipe, 16#ff) - end, - G = begin - _pipe@1 = erlang:'bsr'(Hex, 8), - erlang:'band'(_pipe@1, 16#ff) - end, - B = erlang:'band'(Hex, 16#ff), - from_rgb255(R, G, B) - end. - --file("src/gleam_community/colour.gleam", 527). -?DOC( - " Returns a `Result(Colour)` created from the given RGB hex `String`.\n" - "\n" - " Returns `Error(Nil)` if the supplied hex `String` is invalid, or greater than `\"#ffffff\" or less than `\"#0\"`\n" - "\n" - "
\n" - " Example:\n" - "\n" - " ```gleam\n" - " fn example() {\n" - " assert Ok(red) = from_rgb_hex_string(\"#ff0000\")\n" - " }\n" - " ```\n" - "
\n" - "\n" - " \n" -). --spec from_rgb_hex_string(binary()) -> {ok, colour()} | {error, nil}. -from_rgb_hex_string(Hex_string) -> - gleam@result:'try'( - hex_string_to_int(Hex_string), - fun(Hex_int) -> from_rgb_hex(Hex_int) end - ). - --file("src/gleam_community/colour.gleam", 585). -?DOC( - " Returns a `Result(Colour)` created from the given hex `Int`.\n" - "\n" - " Returns `Error(Nil)` if the supplied hex `Int is greater than 0xffffffff or less than 0x0.\n" - "\n" - "
\n" - " Example:\n" - "\n" - " ```gleam\n" - " fn example() {\n" - " assert Ok(red_half_opacity) = from_rgba_hex(0xff00007f)\n" - " }\n" - " ```\n" - "
\n" - "\n" - " \n" -). --spec from_rgba_hex(integer()) -> {ok, colour()} | {error, nil}. -from_rgba_hex(Hex) -> - case (Hex > 16#ffffffff) orelse (Hex < 0) of - true -> - {error, nil}; - - false -> - R@1 = case begin - _pipe = erlang:'bsr'(Hex, 24), - _pipe@1 = erlang:'band'(_pipe, 16#ff), - _pipe@2 = erlang:float(_pipe@1), - gleam@float:divide(_pipe@2, 255.0) - end of - {ok, R} -> R; - _assert_fail -> - erlang:error(#{gleam_error => let_assert, - message => <<"Pattern match failed, no pattern matched the value."/utf8>>, - file => <>, - module => <<"gleam_community/colour"/utf8>>, - function => <<"from_rgba_hex"/utf8>>, - line => 590, - value => _assert_fail, - start => 17111, - 'end' => 17260, - pattern_start => 17122, - pattern_end => 17127}) - end, - G@1 = case begin - _pipe@3 = erlang:'bsr'(Hex, 16), - _pipe@4 = erlang:'band'(_pipe@3, 16#ff), - _pipe@5 = erlang:float(_pipe@4), - gleam@float:divide(_pipe@5, 255.0) - end of - {ok, G} -> G; - _assert_fail@1 -> - erlang:error(#{gleam_error => let_assert, - message => <<"Pattern match failed, no pattern matched the value."/utf8>>, - file => <>, - module => <<"gleam_community/colour"/utf8>>, - function => <<"from_rgba_hex"/utf8>>, - line => 596, - value => _assert_fail@1, - start => 17332, - 'end' => 17481, - pattern_start => 17343, - pattern_end => 17348}) - end, - B@1 = case begin - _pipe@6 = erlang:'bsr'(Hex, 8), - _pipe@7 = erlang:'band'(_pipe@6, 16#ff), - _pipe@8 = erlang:float(_pipe@7), - gleam@float:divide(_pipe@8, 255.0) - end of - {ok, B} -> B; - _assert_fail@2 -> - erlang:error(#{gleam_error => let_assert, - message => <<"Pattern match failed, no pattern matched the value."/utf8>>, - file => <>, - module => <<"gleam_community/colour"/utf8>>, - function => <<"from_rgba_hex"/utf8>>, - line => 602, - value => _assert_fail@2, - start => 17553, - 'end' => 17701, - pattern_start => 17564, - pattern_end => 17569}) - end, - A@1 = case begin - _pipe@9 = erlang:'band'(Hex, 16#ff), - _pipe@10 = erlang:float(_pipe@9), - gleam@float:divide(_pipe@10, 255.0) - end of - {ok, A} -> A; - _assert_fail@3 -> - erlang:error(#{gleam_error => let_assert, - message => <<"Pattern match failed, no pattern matched the value."/utf8>>, - file => <>, - module => <<"gleam_community/colour"/utf8>>, - function => <<"from_rgba_hex"/utf8>>, - line => 608, - value => _assert_fail@3, - start => 17773, - 'end' => 17883, - pattern_start => 17784, - pattern_end => 17789}) - end, - from_rgba(R@1, G@1, B@1, A@1) - end. - --file("src/gleam_community/colour.gleam", 556). -?DOC( - " Returns a `Result(Colour)` created from the given RGBA hex `String`.\n" - "\n" - " Returns `Error(Nil)` if the supplied hex `String` is invalid, or greater than `\"#ffffffff\" or less than `\"#0\"`\n" - "\n" - "
\n" - " Example:\n" - "\n" - " ```gleam\n" - " fn example() {\n" - " assert Ok(red_half_opacity) = from_rgba_hex_string(\"#ff00007f\")\n" - " }\n" - " ```\n" - "
\n" - "\n" - " \n" -). --spec from_rgba_hex_string(binary()) -> {ok, colour()} | {error, nil}. -from_rgba_hex_string(Hex_string) -> - gleam@result:'try'( - hex_string_to_int(Hex_string), - fun(Hex_int) -> from_rgba_hex(Hex_int) end - ). - --file("src/gleam_community/colour.gleam", 642). -?DOC( - " Returns `#(Float, Float, Float, Float)` representing the given `Colour`'s\n" - " R, G, B, and A values respectively.\n" - "\n" - "
\n" - " Example:\n" - "\n" - " ```gleam\n" - " fn example() {\n" - " assert Ok(red) = from_rgb255(255, 0, 0)\n" - " let #(r, g, b, a) = to_rgba(red)\n" - " }\n" - " ```\n" - "
\n" - "\n" - " \n" -). --spec to_rgba(colour()) -> {float(), float(), float(), float()}. -to_rgba(Colour) -> - case Colour of - {rgba, R, G, B, A} -> - {R, G, B, A}; - - {hsla, H, S, L, A@1} -> - hsla_to_rgba(H, S, L, A@1) - end. - --file("src/gleam_community/colour.gleam", 672). -?DOC( - " Returns `#(Float, Float, Float, Float)` representing the given `Colour`'s\n" - " H, S, L, and A values respectively.\n" - "\n" - "
\n" - " Example:\n" - "\n" - " ```gleam\n" - " fn example() {\n" - " assert Ok(red) = from_rgb255(255, 0, 0)\n" - " let #(h, s, l, a) = to_hsla(red)\n" - " }\n" - " ```\n" - "
\n" - "\n" - " \n" -). --spec to_hsla(colour()) -> {float(), float(), float(), float()}. -to_hsla(Colour) -> - case Colour of - {hsla, H, S, L, A} -> - {H, S, L, A}; - - {rgba, R, G, B, A@1} -> - rgba_to_hsla(R, G, B, A@1) - end. - --file("src/gleam_community/colour.gleam", 701). -?DOC( - " Returns an rgba formatted CSS `String` created from the given `Colour`.\n" - "\n" - "
\n" - " Example:\n" - "\n" - " ```gleam\n" - " fn example() {\n" - " assert Ok(red) = from_rgb255(255, 0, 0)\n" - " let css_red = to_css_rgba_string(red)\n" - " }\n" - " ```\n" - "
\n" - "\n" - " \n" -). --spec to_css_rgba_string(colour()) -> binary(). -to_css_rgba_string(Colour) -> - {R, G, B, A} = to_rgba(Colour), - Percent = fun(X) -> - P@1 = case begin - _pipe = X, - _pipe@1 = gleam@float:multiply(_pipe, 10000.0), - _pipe@2 = erlang:round(_pipe@1), - _pipe@3 = erlang:float(_pipe@2), - gleam@float:divide(_pipe@3, 100.0) - end of - {ok, P} -> P; - _assert_fail -> - erlang:error(#{gleam_error => let_assert, - message => <<"Pattern match failed, no pattern matched the value."/utf8>>, - file => <>, - module => <<"gleam_community/colour"/utf8>>, - function => <<"to_css_rgba_string"/utf8>>, - line => 706, - value => _assert_fail, - start => 20510, - 'end' => 20646, - pattern_start => 20521, - pattern_end => 20526}) - end, - P@1 - end, - Round_to = fun(X@1) -> - R@2 = case begin - _pipe@4 = X@1, - _pipe@5 = gleam@float:multiply(_pipe@4, 1000.0), - _pipe@6 = erlang:round(_pipe@5), - _pipe@7 = erlang:float(_pipe@6), - gleam@float:divide(_pipe@7, 1000.0) - end of - {ok, R@1} -> R@1; - _assert_fail@1 -> - erlang:error(#{gleam_error => let_assert, - message => <<"Pattern match failed, no pattern matched the value."/utf8>>, - file => <>, - module => <<"gleam_community/colour"/utf8>>, - function => <<"to_css_rgba_string"/utf8>>, - line => 718, - value => _assert_fail@1, - start => 20768, - 'end' => 20903, - pattern_start => 20779, - pattern_end => 20784}) - end, - R@2 - end, - gleam@string:join( - [<<"rgba("/utf8>>, - <<(gleam_stdlib:float_to_string(Percent(R)))/binary, "%,"/utf8>>, - <<(gleam_stdlib:float_to_string(Percent(G)))/binary, "%,"/utf8>>, - <<(gleam_stdlib:float_to_string(Percent(B)))/binary, "%,"/utf8>>, - gleam_stdlib:float_to_string(Round_to(A)), - <<")"/utf8>>], - <<""/utf8>> - ). - --file("src/gleam_community/colour.gleam", 829). -?DOC( - " Returns an hex `Int` created from the given `Colour`.\n" - "\n" - "
\n" - " Example:\n" - "\n" - " ```gleam\n" - " fn example() {\n" - " assert Ok(red) = from_rgba(1.0, 0.0, 0.0, 1.0)\n" - " let red_hex_int = to_rgba_hex(red)\n" - " }\n" - " ```\n" - "
\n" - "\n" - " \n" -). --spec to_rgba_hex(colour()) -> integer(). -to_rgba_hex(Colour) -> - {R, G, B, A} = to_rgba(Colour), - Red = begin - _pipe = R * 255.0, - _pipe@1 = erlang:round(_pipe), - erlang:'bsl'(_pipe@1, 24) - end, - Green = begin - _pipe@2 = G * 255.0, - _pipe@3 = erlang:round(_pipe@2), - erlang:'bsl'(_pipe@3, 16) - end, - Blue = begin - _pipe@4 = B * 255.0, - _pipe@5 = erlang:round(_pipe@4), - erlang:'bsl'(_pipe@5, 8) - end, - Alpha = begin - _pipe@6 = A * 255.0, - erlang:round(_pipe@6) - end, - ((Red + Green) + Blue) + Alpha. - --file("src/gleam_community/colour.gleam", 763). -?DOC( - " Returns an rgba hex formatted `String` created from the given `Colour`.\n" - "\n" - "
\n" - " Example:\n" - "\n" - " ```gleam\n" - " fn example() {\n" - " assert Ok(red) = from_rgba(1.0, 0.0, 0.0, 1.0)\n" - " let red_hex = to_rgba_hex_string(red)\n" - " }\n" - " ```\n" - "
\n" - "\n" - " \n" -). --spec to_rgba_hex_string(colour()) -> binary(). -to_rgba_hex_string(Colour) -> - Hex_string = begin - _pipe = to_rgba_hex(Colour), - gleam@int:to_base16(_pipe) - end, - case string:length(Hex_string) of - 8 -> - Hex_string; - - L -> - <<(gleam@string:repeat(<<"0"/utf8>>, 8 - L))/binary, - Hex_string/binary>> - end. - --file("src/gleam_community/colour.gleam", 876). -?DOC( - " Returns a rgb hex `Int` created from the given `Colour`.\n" - "\n" - "
\n" - " Example:\n" - "\n" - " ```gleam\n" - " fn example() {\n" - " assert Ok(red) = from_rgba(255, 0, 0)\n" - " let red_hex_int = to_rgb_hex(red)\n" - " }\n" - " ```\n" - "
\n" - "\n" - " \n" -). --spec to_rgb_hex(colour()) -> integer(). -to_rgb_hex(Colour) -> - {R, G, B, _} = to_rgba(Colour), - Red = begin - _pipe = R * 255.0, - _pipe@1 = erlang:round(_pipe), - erlang:'bsl'(_pipe@1, 16) - end, - Green = begin - _pipe@2 = G * 255.0, - _pipe@3 = erlang:round(_pipe@2), - erlang:'bsl'(_pipe@3, 8) - end, - Blue = begin - _pipe@4 = B * 255.0, - erlang:round(_pipe@4) - end, - (Red + Green) + Blue. - --file("src/gleam_community/colour.gleam", 796). -?DOC( - " Returns an rgb hex formatted `String` created from the given `Colour`.\n" - "\n" - "
\n" - " Example:\n" - "\n" - " ```gleam\n" - " fn example() {\n" - " assert Ok(red) = from_rgba(255, 0, 0)\n" - " let red_hex = to_rgb_hex_string(red)\n" - " }\n" - " ```\n" - "
\n" - "\n" - " \n" -). --spec to_rgb_hex_string(colour()) -> binary(). -to_rgb_hex_string(Colour) -> - Hex_string = begin - _pipe = to_rgb_hex(Colour), - gleam@int:to_base16(_pipe) - end, - case string:length(Hex_string) of - 6 -> - Hex_string; - - L -> - <<(gleam@string:repeat(<<"0"/utf8>>, 6 - L))/binary, - Hex_string/binary>> - end. - --file("src/gleam_community/colour.gleam", 918). --spec encode_rgba(float(), float(), float(), float()) -> gleam@json:json(). -encode_rgba(R, G, B, A) -> - gleam@json:object( - [{<<"r"/utf8>>, gleam@json:float(R)}, - {<<"g"/utf8>>, gleam@json:float(G)}, - {<<"b"/utf8>>, gleam@json:float(B)}, - {<<"a"/utf8>>, gleam@json:float(A)}] - ). - --file("src/gleam_community/colour.gleam", 927). --spec encode_hsla(float(), float(), float(), float()) -> gleam@json:json(). -encode_hsla(H, S, L, A) -> - gleam@json:object( - [{<<"h"/utf8>>, gleam@json:float(H)}, - {<<"s"/utf8>>, gleam@json:float(S)}, - {<<"l"/utf8>>, gleam@json:float(L)}, - {<<"a"/utf8>>, gleam@json:float(A)}] - ). - --file("src/gleam_community/colour.gleam", 911). -?DOC( - " Encodes a `Colour` value as a Gleam [`Json`](https://hexdocs.pm/gleam_json/gleam/json.html#Json)\n" - " value. You'll need this if you want to send a `Colour` value over the network\n" - " in a HTTP request or response, for example.\n" - "\n" - " \n" -). --spec encode(colour()) -> gleam@json:json(). -encode(Colour) -> - case Colour of - {rgba, R, G, B, A} -> - encode_rgba(R, G, B, A); - - {hsla, H, S, L, A@1} -> - encode_hsla(H, S, L, A@1) - end. - --file("src/gleam_community/colour.gleam", 952). --spec rgba_decoder() -> gleam@dynamic@decode:decoder(colour()). -rgba_decoder() -> - gleam@dynamic@decode:field( - <<"r"/utf8>>, - {decoder, fun gleam@dynamic@decode:decode_float/1}, - fun(R) -> - gleam@dynamic@decode:field( - <<"g"/utf8>>, - {decoder, fun gleam@dynamic@decode:decode_float/1}, - fun(G) -> - gleam@dynamic@decode:field( - <<"b"/utf8>>, - {decoder, fun gleam@dynamic@decode:decode_float/1}, - fun(B) -> - gleam@dynamic@decode:field( - <<"a"/utf8>>, - {decoder, - fun gleam@dynamic@decode:decode_float/1}, - fun(A) -> - gleam@dynamic@decode:success( - {rgba, R, G, B, A} - ) - end - ) - end - ) - end - ) - end - ). - --file("src/gleam_community/colour.gleam", 961). --spec hsla_decoder() -> gleam@dynamic@decode:decoder(colour()). -hsla_decoder() -> - gleam@dynamic@decode:field( - <<"h"/utf8>>, - {decoder, fun gleam@dynamic@decode:decode_float/1}, - fun(H) -> - gleam@dynamic@decode:field( - <<"s"/utf8>>, - {decoder, fun gleam@dynamic@decode:decode_float/1}, - fun(S) -> - gleam@dynamic@decode:field( - <<"l"/utf8>>, - {decoder, fun gleam@dynamic@decode:decode_float/1}, - fun(L) -> - gleam@dynamic@decode:field( - <<"a"/utf8>>, - {decoder, - fun gleam@dynamic@decode:decode_float/1}, - fun(A) -> - gleam@dynamic@decode:success( - {hsla, H, S, L, A} - ) - end - ) - end - ) - end - ) - end - ). - --file("src/gleam_community/colour.gleam", 948). -?DOC( - " Attempt to decode some [`Dynamic`](https://hexdocs.pm/gleam_stdlib/gleam/dynamic.html#Dynamic)\n" - " value into a `Colour`. Most often you'll use this to decode some JSON.\n" - "\n" - " \n" -). --spec decoder() -> gleam@dynamic@decode:decoder(colour()). -decoder() -> - gleam@dynamic@decode:one_of(rgba_decoder(), [hsla_decoder()]). diff --git a/build/packages/gleam_community_colour/src/gleam_community@colour@accessibility.erl b/build/packages/gleam_community_colour/src/gleam_community@colour@accessibility.erl deleted file mode 100644 index 35c1d67..0000000 --- a/build/packages/gleam_community_colour/src/gleam_community@colour@accessibility.erl +++ /dev/null @@ -1,203 +0,0 @@ --module(gleam_community@colour@accessibility). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch]). --define(FILEPATH, "src/gleam_community/colour/accessibility.gleam"). --export([luminance/1, contrast_ratio/2, maximum_contrast/2]). - --if(?OTP_RELEASE >= 27). --define(MODULEDOC(Str), -moduledoc(Str)). --define(DOC(Str), -doc(Str)). --else. --define(MODULEDOC(Str), -compile([])). --define(DOC(Str), -compile([])). --endif. - -?MODULEDOC( - " \n" - " - **Accessibility**\n" - " - [`luminance`](#luminance)\n" - " - [`contrast_ratio`](#contrast_ratio)\n" - " - [`maximum_contrast`](#maximum_contrast)\n" - "\n" - " ---\n" - "\n" - " This package was heavily inspired by the `elm-color-extra` module.\n" - " The original source code can be found\n" - " here.\n" - "\n" - "
\n" - " The license of that package is produced below:\n" - " \n" - " \n" - " > MIT License\n" - "\n" - " > Copyright (c) 2016 Andreas Köberle\n" - "\n" - " > Permission is hereby granted, free of charge, to any person obtaining a copy\n" - " of this software and associated documentation files (the \"Software\"), to deal\n" - " in the Software without restriction, including without limitation the rights\n" - " to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n" - " copies of the Software, and to permit persons to whom the Software is\n" - " furnished to do so, subject to the following conditions:\n" - "\n" - " > The above copyright notice and this permission notice shall be included in all\n" - " copies or substantial portions of the Software.\n" - "\n" - " > THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n" - " IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n" - " FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n" - " AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n" - " LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n" - " OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n" - " SOFTWARE.\n" - "\n" - "
\n" - "\n" -). - --file("src/gleam_community/colour/accessibility.gleam", 56). --spec intensity(float()) -> float(). -intensity(Colour_value) -> - case true of - _ when Colour_value =< 0.03928 -> - Colour_value / 12.92; - - _ -> - I@1 = case gleam@float:power((Colour_value + 0.055) / 1.055, 2.4) of - {ok, I} -> I; - _assert_fail -> - erlang:error(#{gleam_error => let_assert, - message => <<"Pattern match failed, no pattern matched the value."/utf8>>, - file => <>, - module => <<"gleam_community/colour/accessibility"/utf8>>, - function => <<"intensity"/utf8>>, - line => 62, - value => _assert_fail, - start => 2399, - 'end' => 2470, - pattern_start => 2410, - pattern_end => 2415}) - end, - I@1 - end. - --file("src/gleam_community/colour/accessibility.gleam", 92). -?DOC( - " Returns the relative brightness of the given `Colour` as a `Float` between\n" - " 0.0, and 1.0 with 0.0 being the darkest possible colour and 1.0 being the lightest.\n" - "\n" - "
\n" - " Example:\n" - "\n" - " ```gleam\n" - " fn example() {\n" - " luminance(colour.white) // 1.0\n" - " }\n" - " ```\n" - "
\n" - "\n" - " \n" -). --spec luminance(gleam_community@colour:colour()) -> float(). -luminance(Colour) -> - {R, G, B, _} = gleam_community@colour:to_rgba(Colour), - R_intensity = intensity(R), - G_intensity = intensity(G), - B_intensity = intensity(B), - ((0.2126 * R_intensity) + (0.7152 * G_intensity)) + (0.0722 * B_intensity). - --file("src/gleam_community/colour/accessibility.gleam", 125). -?DOC( - " Returns the contrast between two `Colour` values as a `Float` between 1.0,\n" - " and 21.0 with 1.0 being no contrast and, 21.0 being the highest possible contrast.\n" - "\n" - "
\n" - " Example:\n" - "\n" - " ```gleam\n" - " fn example() {\n" - " contrast_ratio(between: colour.white, and: colour.black) // 21.0\n" - " }\n" - " ```\n" - "
\n" - "\n" - " \n" -). --spec contrast_ratio( - gleam_community@colour:colour(), - gleam_community@colour:colour() -) -> float(). -contrast_ratio(Colour_a, Colour_b) -> - Luminance_a = luminance(Colour_a) + 0.05, - Luminance_b = luminance(Colour_b) + 0.05, - case Luminance_a > Luminance_b of - true -> - case Luminance_b of - +0.0 -> +0.0; - -0.0 -> -0.0; - Gleam@denominator -> Luminance_a / Gleam@denominator - end; - - false -> - case Luminance_a of - +0.0 -> +0.0; - -0.0 -> -0.0; - Gleam@denominator@1 -> Luminance_b / Gleam@denominator@1 - end - end. - --file("src/gleam_community/colour/accessibility.gleam", 161). -?DOC( - " Returns the `Colour` with the highest contrast between the base `Colour`,\n" - " and and the other provided `Colour` values.\n" - "\n" - "
\n" - " Example:\n" - "\n" - " ```gleam\n" - " fn example() {\n" - " maximum_contrast(\n" - " colour.yellow,\n" - " [colour.white, colour.dark_blue, colour.green],\n" - " )\n" - " }\n" - " ```\n" - "
\n" - "\n" - " \n" -). --spec maximum_contrast( - gleam_community@colour:colour(), - list(gleam_community@colour:colour()) -) -> {ok, gleam_community@colour:colour()} | {error, nil}. -maximum_contrast(Base, Colours) -> - _pipe = Colours, - _pipe@1 = gleam@list:sort( - _pipe, - fun(Colour_a, Colour_b) -> - Contrast_a = contrast_ratio(Base, Colour_a), - Contrast_b = contrast_ratio(Base, Colour_b), - gleam@float:compare(Contrast_b, Contrast_a) - end - ), - gleam@list:first(_pipe@1). diff --git a/build/packages/gleam_community_colour/src/gleam_community_colour.app.src b/build/packages/gleam_community_colour/src/gleam_community_colour.app.src deleted file mode 100644 index 0d22534..0000000 --- a/build/packages/gleam_community_colour/src/gleam_community_colour.app.src +++ /dev/null @@ -1,10 +0,0 @@ -{application, gleam_community_colour, [ - {vsn, "2.0.2"}, - {applications, [gleam_json, - gleam_stdlib]}, - {description, "Colour types, conversions, and other utilities"}, - {modules, [gleam_community@colour, - gleam_community@colour@accessibility, - gleam_community_colour@@main]}, - {registered, []} -]}. diff --git a/build/packages/gleam_json/LICENCE b/build/packages/gleam_json/LICENCE deleted file mode 100644 index 3d89615..0000000 --- a/build/packages/gleam_json/LICENCE +++ /dev/null @@ -1,191 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - Copyright 2021 - present, Louis Pilfold . - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - diff --git a/build/packages/gleam_json/README.md b/build/packages/gleam_json/README.md deleted file mode 100644 index 1a06b52..0000000 --- a/build/packages/gleam_json/README.md +++ /dev/null @@ -1,47 +0,0 @@ -# json 🐑 - -Work with JSON in Gleam! - -## Installation - -```shell -gleam add gleam_json@3 -``` - -## Encoding - -```gleam -import myapp.{type Cat} -import gleam/json - -pub fn cat_to_json(cat: Cat) -> String { - json.object([ - #("name", json.string(cat.name)), - #("lives", json.int(cat.lives)), - #("flaws", json.null()), - #("nicknames", json.array(cat.nicknames, of: json.string)), - ]) - |> json.to_string -} -``` - -## Parsing - -JSON is parsed into a `Dynamic` value which can be decoded using the -`gleam/dynamic/decode` module from the Gleam standard library. - -```gleam -import myapp.{Cat} -import gleam/json -import gleam/dynamic/decode - -pub fn cat_from_json(json_string: String) -> Result(Cat, json.DecodeError) { - let cat_decoder = { - use name <- decode.field("name", decode.string) - use lives <- decode.field("lives", decode.int) - use nicknames <- decode.field("nicknames", decode.list(decode.string)) - decode.success(Cat(name:, lives:, nicknames:)) - } - json.parse(from: json_string, using: cat_decoder) -} -``` diff --git a/build/packages/gleam_json/gleam.toml b/build/packages/gleam_json/gleam.toml deleted file mode 100644 index f7e7f8d..0000000 --- a/build/packages/gleam_json/gleam.toml +++ /dev/null @@ -1,18 +0,0 @@ -name = "gleam_json" -version = "3.1.0" -gleam = ">= 1.13.0" - -licences = ["Apache-2.0"] -description = "Work with JSON in Gleam" - -repository = { type = "github", user = "gleam-lang", repo = "json" } -links = [ - { title = "Website", href = "https://gleam.run" }, - { title = "Sponsor", href = "https://github.com/sponsors/lpil" }, -] - -[dependencies] -gleam_stdlib = ">= 0.51.0 and < 2.0.0" - -[dev-dependencies] -gleeunit = ">= 1.2.0 and < 2.0.0" diff --git a/build/packages/gleam_json/src/gleam/json.gleam b/build/packages/gleam_json/src/gleam/json.gleam deleted file mode 100644 index e3a3cae..0000000 --- a/build/packages/gleam_json/src/gleam/json.gleam +++ /dev/null @@ -1,316 +0,0 @@ -import gleam/bit_array -import gleam/dict.{type Dict} -import gleam/dynamic.{type Dynamic} -import gleam/dynamic/decode -import gleam/list -import gleam/option.{type Option, None, Some} -import gleam/result -import gleam/string_tree.{type StringTree} - -pub type Json - -pub type DecodeError { - UnexpectedEndOfInput - UnexpectedByte(String) - UnexpectedSequence(String) - UnableToDecode(List(decode.DecodeError)) -} - -/// Decode a JSON string into dynamically typed data which can be decoded into -/// typed data with the `gleam/dynamic` module. -/// -/// ## Examples -/// -/// ```gleam -/// > parse("[1,2,3]", decode.list(of: decode.int)) -/// Ok([1, 2, 3]) -/// ``` -/// -/// ```gleam -/// > parse("[", decode.list(of: decode.int)) -/// Error(UnexpectedEndOfInput) -/// ``` -/// -/// ```gleam -/// > parse("1", decode.string) -/// Error(UnableToDecode([decode.DecodeError("String", "Int", [])])) -/// ``` -/// -pub fn parse( - from json: String, - using decoder: decode.Decoder(t), -) -> Result(t, DecodeError) { - do_parse(from: json, using: decoder) -} - -@target(erlang) -fn do_parse( - from json: String, - using decoder: decode.Decoder(t), -) -> Result(t, DecodeError) { - let bits = bit_array.from_string(json) - parse_bits(bits, decoder) -} - -@target(javascript) -fn do_parse( - from json: String, - using decoder: decode.Decoder(t), -) -> Result(t, DecodeError) { - use dynamic_value <- result.try(decode_string(json)) - decode.run(dynamic_value, decoder) - |> result.map_error(UnableToDecode) -} - -@external(javascript, "../gleam_json_ffi.mjs", "decode") -fn decode_string(a: String) -> Result(Dynamic, DecodeError) - -/// Decode a JSON bit string into dynamically typed data which can be decoded -/// into typed data with the `gleam/dynamic` module. -/// -/// ## Examples -/// -/// ```gleam -/// > parse_bits(<<"[1,2,3]">>, decode.list(of: decode.int)) -/// Ok([1, 2, 3]) -/// ``` -/// -/// ```gleam -/// > parse_bits(<<"[">>, decode.list(of: decode.int)) -/// Error(UnexpectedEndOfInput) -/// ``` -/// -/// ```gleam -/// > parse_bits(<<"1">>, decode.string) -/// Error(UnableToDecode([decode.DecodeError("String", "Int", [])])), -/// ``` -/// -pub fn parse_bits( - from json: BitArray, - using decoder: decode.Decoder(t), -) -> Result(t, DecodeError) { - use dynamic_value <- result.try(decode_to_dynamic(json)) - decode.run(dynamic_value, decoder) - |> result.map_error(UnableToDecode) -} - -@external(erlang, "gleam_json_ffi", "decode") -fn decode_to_dynamic(json: BitArray) -> Result(Dynamic, DecodeError) { - case bit_array.to_string(json) { - Ok(string) -> decode_string(string) - Error(Nil) -> Error(UnexpectedByte("")) - } -} - -/// Convert a JSON value into a string. -/// -/// Where possible prefer the `to_string_tree` function as it is faster than -/// this function, and BEAM VM IO is optimised for sending `StringTree` data. -/// -/// ## Examples -/// -/// ```gleam -/// > to_string(array([1, 2, 3], of: int)) -/// "[1,2,3]" -/// ``` -/// -pub fn to_string(json: Json) -> String { - do_to_string(json) -} - -@external(erlang, "gleam_json_ffi", "json_to_string") -@external(javascript, "../gleam_json_ffi.mjs", "json_to_string") -fn do_to_string(a: Json) -> String - -/// Convert a JSON value into a string tree. -/// -/// Where possible prefer this function to the `to_string` function as it is -/// slower than this function, and BEAM VM IO is optimised for sending -/// `StringTree` data. -/// -/// ## Examples -/// -/// ```gleam -/// > to_string_tree(array([1, 2, 3], of: int)) -/// string_tree.from_string("[1,2,3]") -/// ``` -/// -@external(erlang, "gleam_json_ffi", "json_to_iodata") -@external(javascript, "../gleam_json_ffi.mjs", "json_to_string") -pub fn to_string_tree(json: Json) -> StringTree - -/// Encode a string into JSON, using normal JSON escaping. -/// -/// ## Examples -/// -/// ```gleam -/// > to_string(string("Hello!")) -/// "\"Hello!\"" -/// ``` -/// -pub fn string(input: String) -> Json { - do_string(input) -} - -@external(erlang, "gleam_json_ffi", "string") -@external(javascript, "../gleam_json_ffi.mjs", "identity") -fn do_string(a: String) -> Json - -/// Encode a bool into JSON. -/// -/// ## Examples -/// -/// ```gleam -/// > to_string(bool(False)) -/// "false" -/// ``` -/// -pub fn bool(input: Bool) -> Json { - do_bool(input) -} - -@external(erlang, "gleam_json_ffi", "bool") -@external(javascript, "../gleam_json_ffi.mjs", "identity") -fn do_bool(a: Bool) -> Json - -/// Encode an int into JSON. -/// -/// ## Examples -/// -/// ```gleam -/// > to_string(int(50)) -/// "50" -/// ``` -/// -pub fn int(input: Int) -> Json { - do_int(input) -} - -@external(erlang, "gleam_json_ffi", "int") -@external(javascript, "../gleam_json_ffi.mjs", "identity") -fn do_int(a: Int) -> Json - -/// Encode a float into JSON. -/// -/// ## Examples -/// -/// ```gleam -/// > to_string(float(4.7)) -/// "4.7" -/// ``` -/// -pub fn float(input: Float) -> Json { - do_float(input) -} - -@external(erlang, "gleam_json_ffi", "float") -@external(javascript, "../gleam_json_ffi.mjs", "identity") -fn do_float(input input: Float) -> Json - -/// The JSON value null. -/// -/// ## Examples -/// -/// ```gleam -/// > to_string(null()) -/// "null" -/// ``` -/// -pub fn null() -> Json { - do_null() -} - -@external(erlang, "gleam_json_ffi", "null") -@external(javascript, "../gleam_json_ffi.mjs", "do_null") -fn do_null() -> Json - -/// Encode an optional value into JSON, using null if it is the `None` variant. -/// -/// ## Examples -/// -/// ```gleam -/// > to_string(nullable(Some(50), of: int)) -/// "50" -/// ``` -/// -/// ```gleam -/// > to_string(nullable(None, of: int)) -/// "null" -/// ``` -/// -pub fn nullable(from input: Option(a), of inner_type: fn(a) -> Json) -> Json { - case input { - Some(value) -> inner_type(value) - None -> null() - } -} - -/// Encode a list of key-value pairs into a JSON object. -/// -/// ## Examples -/// -/// ```gleam -/// > to_string(object([ -/// #("game", string("Pac-Man")), -/// #("score", int(3333360)), -/// ])) -/// "{\"game\":\"Pac-Mac\",\"score\":3333360}" -/// ``` -/// -pub fn object(entries: List(#(String, Json))) -> Json { - do_object(entries) -} - -@external(erlang, "gleam_json_ffi", "object") -@external(javascript, "../gleam_json_ffi.mjs", "object") -fn do_object(entries entries: List(#(String, Json))) -> Json - -/// Encode a list into a JSON array. -/// -/// ## Examples -/// -/// ```gleam -/// > to_string(array([1, 2, 3], of: int)) -/// "[1, 2, 3]" -/// ``` -/// -pub fn array(from entries: List(a), of inner_type: fn(a) -> Json) -> Json { - entries - |> list.map(inner_type) - |> preprocessed_array -} - -/// Encode a list of JSON values into a JSON array. -/// -/// ## Examples -/// -/// ```gleam -/// > to_string(preprocessed_array([int(1), float(2.0), string("3")])) -/// "[1, 2.0, \"3\"]" -/// ``` -/// -pub fn preprocessed_array(from: List(Json)) -> Json { - do_preprocessed_array(from) -} - -@external(erlang, "gleam_json_ffi", "array") -@external(javascript, "../gleam_json_ffi.mjs", "array") -fn do_preprocessed_array(from from: List(Json)) -> Json - -/// Encode a Dict into a JSON object using the supplied functions to encode -/// the keys and the values respectively. -/// -/// ## Examples -/// -/// ```gleam -/// > to_string(dict(dict.from_list([ #(3, 3.0), #(4, 4.0)]), int.to_string, float) -/// "{\"3\": 3.0, \"4\": 4.0}" -/// ``` -/// -pub fn dict( - dict: Dict(k, v), - keys: fn(k) -> String, - values: fn(v) -> Json, -) -> Json { - object(dict.fold(dict, [], fn(acc, k, v) { [#(keys(k), values(v)), ..acc] })) -} diff --git a/build/packages/gleam_json/src/gleam@json.erl b/build/packages/gleam_json/src/gleam@json.erl deleted file mode 100644 index 8a33e49..0000000 --- a/build/packages/gleam_json/src/gleam@json.erl +++ /dev/null @@ -1,304 +0,0 @@ --module(gleam@json). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "src/gleam/json.gleam"). --export([parse_bits/2, parse/2, to_string/1, to_string_tree/1, string/1, bool/1, int/1, float/1, null/0, nullable/2, object/1, preprocessed_array/1, array/2, dict/3]). --export_type([json/0, decode_error/0]). - --if(?OTP_RELEASE >= 27). --define(MODULEDOC(Str), -moduledoc(Str)). --define(DOC(Str), -doc(Str)). --else. --define(MODULEDOC(Str), -compile([])). --define(DOC(Str), -compile([])). --endif. - --type json() :: any(). - --type decode_error() :: unexpected_end_of_input | - {unexpected_byte, binary()} | - {unexpected_sequence, binary()} | - {unable_to_decode, list(gleam@dynamic@decode:decode_error())}. - --file("src/gleam/json.gleam", 88). -?DOC( - " Decode a JSON bit string into dynamically typed data which can be decoded\n" - " into typed data with the `gleam/dynamic` module.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " > parse_bits(<<\"[1,2,3]\">>, decode.list(of: decode.int))\n" - " Ok([1, 2, 3])\n" - " ```\n" - "\n" - " ```gleam\n" - " > parse_bits(<<\"[\">>, decode.list(of: decode.int))\n" - " Error(UnexpectedEndOfInput)\n" - " ```\n" - "\n" - " ```gleam\n" - " > parse_bits(<<\"1\">>, decode.string)\n" - " Error(UnableToDecode([decode.DecodeError(\"String\", \"Int\", [])])),\n" - " ```\n" -). --spec parse_bits(bitstring(), gleam@dynamic@decode:decoder(DNO)) -> {ok, DNO} | - {error, decode_error()}. -parse_bits(Json, Decoder) -> - gleam@result:'try'( - gleam_json_ffi:decode(Json), - fun(Dynamic_value) -> - _pipe = gleam@dynamic@decode:run(Dynamic_value, Decoder), - gleam@result:map_error( - _pipe, - fun(Field@0) -> {unable_to_decode, Field@0} end - ) - end - ). - --file("src/gleam/json.gleam", 47). --spec do_parse(binary(), gleam@dynamic@decode:decoder(DNI)) -> {ok, DNI} | - {error, decode_error()}. -do_parse(Json, Decoder) -> - Bits = gleam_stdlib:identity(Json), - parse_bits(Bits, Decoder). - --file("src/gleam/json.gleam", 39). -?DOC( - " Decode a JSON string into dynamically typed data which can be decoded into\n" - " typed data with the `gleam/dynamic` module.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " > parse(\"[1,2,3]\", decode.list(of: decode.int))\n" - " Ok([1, 2, 3])\n" - " ```\n" - "\n" - " ```gleam\n" - " > parse(\"[\", decode.list(of: decode.int))\n" - " Error(UnexpectedEndOfInput)\n" - " ```\n" - "\n" - " ```gleam\n" - " > parse(\"1\", decode.string)\n" - " Error(UnableToDecode([decode.DecodeError(\"String\", \"Int\", [])]))\n" - " ```\n" -). --spec parse(binary(), gleam@dynamic@decode:decoder(DNE)) -> {ok, DNE} | - {error, decode_error()}. -parse(Json, Decoder) -> - do_parse(Json, Decoder). - --file("src/gleam/json.gleam", 117). -?DOC( - " Convert a JSON value into a string.\n" - "\n" - " Where possible prefer the `to_string_tree` function as it is faster than\n" - " this function, and BEAM VM IO is optimised for sending `StringTree` data.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " > to_string(array([1, 2, 3], of: int))\n" - " \"[1,2,3]\"\n" - " ```\n" -). --spec to_string(json()) -> binary(). -to_string(Json) -> - gleam_json_ffi:json_to_string(Json). - --file("src/gleam/json.gleam", 140). -?DOC( - " Convert a JSON value into a string tree.\n" - "\n" - " Where possible prefer this function to the `to_string` function as it is\n" - " slower than this function, and BEAM VM IO is optimised for sending\n" - " `StringTree` data.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " > to_string_tree(array([1, 2, 3], of: int))\n" - " string_tree.from_string(\"[1,2,3]\")\n" - " ```\n" -). --spec to_string_tree(json()) -> gleam@string_tree:string_tree(). -to_string_tree(Json) -> - gleam_json_ffi:json_to_iodata(Json). - --file("src/gleam/json.gleam", 151). -?DOC( - " Encode a string into JSON, using normal JSON escaping.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " > to_string(string(\"Hello!\"))\n" - " \"\\\"Hello!\\\"\"\n" - " ```\n" -). --spec string(binary()) -> json(). -string(Input) -> - gleam_json_ffi:string(Input). - --file("src/gleam/json.gleam", 168). -?DOC( - " Encode a bool into JSON.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " > to_string(bool(False))\n" - " \"false\"\n" - " ```\n" -). --spec bool(boolean()) -> json(). -bool(Input) -> - gleam_json_ffi:bool(Input). - --file("src/gleam/json.gleam", 185). -?DOC( - " Encode an int into JSON.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " > to_string(int(50))\n" - " \"50\"\n" - " ```\n" -). --spec int(integer()) -> json(). -int(Input) -> - gleam_json_ffi:int(Input). - --file("src/gleam/json.gleam", 202). -?DOC( - " Encode a float into JSON.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " > to_string(float(4.7))\n" - " \"4.7\"\n" - " ```\n" -). --spec float(float()) -> json(). -float(Input) -> - gleam_json_ffi:float(Input). - --file("src/gleam/json.gleam", 219). -?DOC( - " The JSON value null.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " > to_string(null())\n" - " \"null\"\n" - " ```\n" -). --spec null() -> json(). -null() -> - gleam_json_ffi:null(). - --file("src/gleam/json.gleam", 241). -?DOC( - " Encode an optional value into JSON, using null if it is the `None` variant.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " > to_string(nullable(Some(50), of: int))\n" - " \"50\"\n" - " ```\n" - "\n" - " ```gleam\n" - " > to_string(nullable(None, of: int))\n" - " \"null\"\n" - " ```\n" -). --spec nullable(gleam@option:option(DNU), fun((DNU) -> json())) -> json(). -nullable(Input, Inner_type) -> - case Input of - {some, Value} -> - Inner_type(Value); - - none -> - null() - end. - --file("src/gleam/json.gleam", 260). -?DOC( - " Encode a list of key-value pairs into a JSON object.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " > to_string(object([\n" - " #(\"game\", string(\"Pac-Man\")),\n" - " #(\"score\", int(3333360)),\n" - " ]))\n" - " \"{\\\"game\\\":\\\"Pac-Mac\\\",\\\"score\\\":3333360}\"\n" - " ```\n" -). --spec object(list({binary(), json()})) -> json(). -object(Entries) -> - gleam_json_ffi:object(Entries). - --file("src/gleam/json.gleam", 292). -?DOC( - " Encode a list of JSON values into a JSON array.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " > to_string(preprocessed_array([int(1), float(2.0), string(\"3\")]))\n" - " \"[1, 2.0, \\\"3\\\"]\"\n" - " ```\n" -). --spec preprocessed_array(list(json())) -> json(). -preprocessed_array(From) -> - gleam_json_ffi:array(From). - --file("src/gleam/json.gleam", 277). -?DOC( - " Encode a list into a JSON array.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " > to_string(array([1, 2, 3], of: int))\n" - " \"[1, 2, 3]\"\n" - " ```\n" -). --spec array(list(DNY), fun((DNY) -> json())) -> json(). -array(Entries, Inner_type) -> - _pipe = Entries, - _pipe@1 = gleam@list:map(_pipe, Inner_type), - preprocessed_array(_pipe@1). - --file("src/gleam/json.gleam", 310). -?DOC( - " Encode a Dict into a JSON object using the supplied functions to encode\n" - " the keys and the values respectively.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " > to_string(dict(dict.from_list([ #(3, 3.0), #(4, 4.0)]), int.to_string, float)\n" - " \"{\\\"3\\\": 3.0, \\\"4\\\": 4.0}\"\n" - " ```\n" -). --spec dict( - gleam@dict:dict(DOC, DOD), - fun((DOC) -> binary()), - fun((DOD) -> json()) -) -> json(). -dict(Dict, Keys, Values) -> - object( - gleam@dict:fold( - Dict, - [], - fun(Acc, K, V) -> [{Keys(K), Values(V)} | Acc] end - ) - ). diff --git a/build/packages/gleam_json/src/gleam_json.app.src b/build/packages/gleam_json/src/gleam_json.app.src deleted file mode 100644 index 3bad27e..0000000 --- a/build/packages/gleam_json/src/gleam_json.app.src +++ /dev/null @@ -1,9 +0,0 @@ -{application, gleam_json, [ - {vsn, "3.1.0"}, - {applications, [gleam_stdlib]}, - {description, "Work with JSON in Gleam"}, - {modules, [gleam@json, - gleam_json@@main, - gleam_json_ffi]}, - {registered, []} -]}. diff --git a/build/packages/gleam_json/src/gleam_json_ffi.erl b/build/packages/gleam_json/src/gleam_json_ffi.erl deleted file mode 100644 index 06a26a0..0000000 --- a/build/packages/gleam_json/src/gleam_json_ffi.erl +++ /dev/null @@ -1,66 +0,0 @@ --module(gleam_json_ffi). - --export([ - decode/1, json_to_iodata/1, json_to_string/1, int/1, float/1, string/1, - bool/1, null/0, array/1, object/1 -]). - --if(?OTP_RELEASE < 27). --define(bad_version, - error({erlang_otp_27_required, << "Insufficient Erlang/OTP version. - -`gleam_json` uses the Erlang `json` module introduced in Erlang/OTP 27. -You are using Erlang/OTP "/utf8, (integer_to_binary(?OTP_RELEASE))/binary, " -Please upgrade your Erlang install or downgrade to `gleam_json` v1.0.1. -"/utf8>>})). - -decode(_) -> ?bad_version. -json_to_iodata(_) -> ?bad_version. -json_to_string(_) -> ?bad_version. -int(_) -> ?bad_version. -float(_) -> ?bad_version. -string(_) -> ?bad_version. -bool(_) -> ?bad_version. -array(_) -> ?bad_version. -object(_) -> ?bad_version. -null() -> ?bad_version. --else. - -decode(Json) -> - try - {ok, json:decode(Json)} - catch - error:unexpected_end -> {error, unexpected_end_of_input}; - error:{invalid_byte, Byte} -> {error, {unexpected_byte, hex(Byte)}}; - error:{unexpected_sequence, Byte} -> {error, {unexpected_sequence, Byte}} - end. - -hex(I) -> - H = list_to_binary(integer_to_list(I, 16)), - <<"0x"/utf8, H/binary>>. - -json_to_iodata(Json) -> - Json. - -json_to_string(Json) when is_binary(Json) -> - Json; -json_to_string(Json) when is_list(Json) -> - list_to_binary(Json). - -null() -> <<"null">>. -bool(true) -> <<"true">>; -bool(false) -> <<"false">>. -int(X) -> json:encode_integer(X). -float(X) -> json:encode_float(X). -string(X) -> json:encode_binary(X). - -array([]) -> <<"[]">>; -array([First | Rest]) -> [$[, First | array_loop(Rest)]. -array_loop([]) -> "]"; -array_loop([Elem | Rest]) -> [$,, Elem | array_loop(Rest)]. - -object(List) -> encode_object([[$,, string(Key), $: | Value] || {Key, Value} <- List]). -encode_object([]) -> <<"{}">>; -encode_object([[_Comma | Entry] | Rest]) -> ["{", Entry, Rest, "}"]. - --endif. diff --git a/build/packages/gleam_json/src/gleam_json_ffi.mjs b/build/packages/gleam_json/src/gleam_json_ffi.mjs deleted file mode 100644 index 1d8d3ff..0000000 --- a/build/packages/gleam_json/src/gleam_json_ffi.mjs +++ /dev/null @@ -1,201 +0,0 @@ -import { - Result$Ok, - Result$Error, - List$isNonEmpty, - List$NonEmpty$first, - List$NonEmpty$rest, -} from "./gleam.mjs"; -import { - DecodeError$UnexpectedByte, - DecodeError$UnexpectedEndOfInput, -} from "./gleam/json.mjs"; - -export function json_to_string(json) { - return JSON.stringify(json); -} - -export function object(entries) { - return Object.fromEntries(entries); -} - -export function identity(x) { - return x; -} - -export function array(list) { - const array = []; - while (List$isNonEmpty(list)) { - array.push(List$NonEmpty$first(list)); - list = List$NonEmpty$rest(list); - } - return array; -} - -export function do_null() { - return null; -} - -export function decode(string) { - try { - const result = JSON.parse(string); - return Result$Ok(result); - } catch (err) { - return Result$Error(getJsonDecodeError(err, string)); - } -} - -export function getJsonDecodeError(stdErr, json) { - if (isUnexpectedEndOfInput(stdErr)) return DecodeError$UnexpectedEndOfInput(); - return toUnexpectedByteError(stdErr, json); -} - -/** - * Matches unexpected end of input messages in: - * - Chromium (edge, chrome, node) - * - Spidermonkey (firefox) - * - JavascriptCore (safari) - * - * Note that Spidermonkey and JavascriptCore will both incorrectly report some - * UnexpectedByte errors as UnexpectedEndOfInput errors. For example: - * - * @example - * // in JavascriptCore - * JSON.parse('{"a"]: "b"}) - * // => JSON Parse error: Expected ':' before value - * - * JSON.parse('{"a"') - * // => JSON Parse error: Expected ':' before value - * - * // in Chromium (correct) - * JSON.parse('{"a"]: "b"}) - * // => Unexpected token ] in JSON at position 4 - * - * JSON.parse('{"a"') - * // => Unexpected end of JSON input - */ -function isUnexpectedEndOfInput(err) { - const unexpectedEndOfInputRegex = - /((unexpected (end|eof))|(end of data)|(unterminated string)|(json( parse error|\.parse)\: expected '(\:|\}|\])'))/i; - return unexpectedEndOfInputRegex.test(err.message); -} - -/** - * Converts a SyntaxError to an UnexpectedByte error based on the JS runtime. - * - * For Chromium, the unexpected byte and position are reported by the runtime. - * - * For JavascriptCore, only the unexpected byte is reported by the runtime, so - * there is no way to know which position that character is in unless we then - * parse the string again ourselves. So instead, the position is reported as 0. - * - * For Spidermonkey, the position is reported by the runtime as a line and column number - * and the unexpected byte is found using those coordinates. - */ -function toUnexpectedByteError(err, json) { - let converters = [ - v8UnexpectedByteError, - oldV8UnexpectedByteError, - jsCoreUnexpectedByteError, - spidermonkeyUnexpectedByteError, - ]; - - for (let converter of converters) { - let result = converter(err, json); - if (result) return result; - } - - return DecodeError$UnexpectedByte(""); -} - -/** - * Matches unexpected byte messages in: - * - V8 (edge, chrome, node) - * - * Matches the character but not the position as this is no longer reported by - * V8. Boo! - */ -function v8UnexpectedByteError(err) { - const regex = /unexpected token '(.)', ".+" is not valid JSON/i; - const match = regex.exec(err.message); - if (!match) return null; - const byte = toHex(match[1]); - return DecodeError$UnexpectedByte(byte); -} - -/** - * Matches unexpected byte messages in: - * - V8 (edge, chrome, node) - * - * No longer works in current versions of V8. - * - * Matches the character and its position. - */ -function oldV8UnexpectedByteError(err) { - const regex = /unexpected token (.) in JSON at position (\d+)/i; - const match = regex.exec(err.message); - if (!match) return null; - const byte = toHex(match[1]); - return DecodeError$UnexpectedByte(byte); -} - -/** - * Matches unexpected byte messages in: - * - Spidermonkey (firefox) - * - * Matches the position in a 2d grid only and not the character. - */ -function spidermonkeyUnexpectedByteError(err, json) { - const regex = - /(unexpected character|expected .*) at line (\d+) column (\d+)/i; - const match = regex.exec(err.message); - if (!match) return null; - const line = Number(match[2]); - const column = Number(match[3]); - const position = getPositionFromMultiline(line, column, json); - const byte = toHex(json[position]); - return DecodeError$UnexpectedByte(byte); -} - -/** - * Matches unexpected byte messages in: - * - JavascriptCore (safari) - * - * JavascriptCore only reports what the character is and not its position. - */ -function jsCoreUnexpectedByteError(err) { - const regex = /unexpected (identifier|token) "(.)"/i; - const match = regex.exec(err.message); - if (!match) return null; - const byte = toHex(match[2]); - return DecodeError$UnexpectedByte(byte); -} - -function toHex(char) { - return "0x" + char.charCodeAt(0).toString(16).toUpperCase(); -} - -/** - * Gets the position of a character in a flattened (i.e. single line) string - * from a line and column number. Note that the position is 0-indexed and - * the line and column numbers are 1-indexed. - * - * @param {number} line - * @param {number} column - * @param {string} string - */ -function getPositionFromMultiline(line, column, string) { - if (line === 1) return column - 1; - - let currentLn = 1; - let position = 0; - string.split("").find((char, idx) => { - if (char === "\n") currentLn += 1; - if (currentLn === line) { - position = idx + column; - return true; - } - return false; - }); - - return position; -} diff --git a/build/packages/gleam_stdlib/LICENCE b/build/packages/gleam_stdlib/LICENCE deleted file mode 100644 index c1dabd0..0000000 --- a/build/packages/gleam_stdlib/LICENCE +++ /dev/null @@ -1,191 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - Copyright 2018, Louis Pilfold . - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - diff --git a/build/packages/gleam_stdlib/README.md b/build/packages/gleam_stdlib/README.md deleted file mode 100644 index 5e1ed4c..0000000 --- a/build/packages/gleam_stdlib/README.md +++ /dev/null @@ -1,34 +0,0 @@ -# stdlib - -[![Package Version](https://img.shields.io/hexpm/v/gleam_stdlib)](https://hex.pm/packages/gleam_stdlib) -[![Hex Docs](https://img.shields.io/badge/hex-docs-ffaff3)](https://hexdocs.pm/gleam_stdlib/) -[![Discord chat](https://img.shields.io/discord/768594524158427167?color=blue)](https://discord.gg/Fm8Pwmy) - -Gleam's standard library! -Documentation available on [HexDocs](https://hexdocs.pm/gleam_stdlib/). - -## Installation - -Add `gleam_stdlib` to your Gleam project. - -```sh -gleam add gleam_stdlib -``` -```gleam -import gleam/io - -pub fn greet(name: String) -> Nil { - io.println("Hello " <> name <> "!") -} -``` - -## Targets - -Gleam's standard library supports both targets: Erlang and JavaScript. - -### Compatibility - -This library is compatible with all versions of Erlang/OTP 26 and higher, -as well as all NodeJS, Deno, Bun, and major browsers that are currently -supported by their maintainers. If you have a compatibility issue with -any platform open an issue and we'll see what we can do to help. diff --git a/build/packages/gleam_stdlib/gleam.toml b/build/packages/gleam_stdlib/gleam.toml deleted file mode 100644 index 27c3f0e..0000000 --- a/build/packages/gleam_stdlib/gleam.toml +++ /dev/null @@ -1,14 +0,0 @@ -name = "gleam_stdlib" -version = "0.65.0" -gleam = ">= 1.11.0" -licences = ["Apache-2.0"] -description = "A standard library for the Gleam programming language" - -repository = { type = "github", user = "gleam-lang", repo = "stdlib" } -links = [ - { title = "Website", href = "https://gleam.run" }, - { title = "Sponsor", href = "https://github.com/sponsors/lpil" }, -] - -[javascript.deno] -allow_read = ["./"] diff --git a/build/packages/gleam_stdlib/include/gleam@dynamic@decode_DecodeError.hrl b/build/packages/gleam_stdlib/include/gleam@dynamic@decode_DecodeError.hrl deleted file mode 100644 index b1135f2..0000000 --- a/build/packages/gleam_stdlib/include/gleam@dynamic@decode_DecodeError.hrl +++ /dev/null @@ -1,5 +0,0 @@ --record(decode_error, { - expected :: binary(), - found :: binary(), - path :: list(binary()) -}). diff --git a/build/packages/gleam_stdlib/include/gleam@dynamic@decode_Decoder.hrl b/build/packages/gleam_stdlib/include/gleam@dynamic@decode_Decoder.hrl deleted file mode 100644 index a2fcfc6..0000000 --- a/build/packages/gleam_stdlib/include/gleam@dynamic@decode_Decoder.hrl +++ /dev/null @@ -1,4 +0,0 @@ --record(decoder, { - function :: fun((gleam@dynamic:dynamic_()) -> {any(), - list(gleam@dynamic@decode:decode_error())}) -}). diff --git a/build/packages/gleam_stdlib/include/gleam@set_Set.hrl b/build/packages/gleam_stdlib/include/gleam@set_Set.hrl deleted file mode 100644 index 51fb778..0000000 --- a/build/packages/gleam_stdlib/include/gleam@set_Set.hrl +++ /dev/null @@ -1 +0,0 @@ --record(set, {dict :: gleam@dict:dict(any(), list(nil))}). diff --git a/build/packages/gleam_stdlib/include/gleam@uri_Uri.hrl b/build/packages/gleam_stdlib/include/gleam@uri_Uri.hrl deleted file mode 100644 index 50150f4..0000000 --- a/build/packages/gleam_stdlib/include/gleam@uri_Uri.hrl +++ /dev/null @@ -1,9 +0,0 @@ --record(uri, { - scheme :: gleam@option:option(binary()), - userinfo :: gleam@option:option(binary()), - host :: gleam@option:option(binary()), - port :: gleam@option:option(integer()), - path :: binary(), - 'query' :: gleam@option:option(binary()), - fragment :: gleam@option:option(binary()) -}). diff --git a/build/packages/gleam_stdlib/src/dict.mjs b/build/packages/gleam_stdlib/src/dict.mjs deleted file mode 100644 index f39cd54..0000000 --- a/build/packages/gleam_stdlib/src/dict.mjs +++ /dev/null @@ -1,993 +0,0 @@ -/** - * This file uses jsdoc to annotate types. - * These types can be checked using the typescript compiler with "checkjs" option. - */ - -import { isEqual } from "./gleam.mjs"; - -const referenceMap = /* @__PURE__ */ new WeakMap(); -const tempDataView = /* @__PURE__ */ new DataView( - /* @__PURE__ */ new ArrayBuffer(8), -); -let referenceUID = 0; -/** - * hash the object by reference using a weak map and incrementing uid - * @param {any} o - * @returns {number} - */ -function hashByReference(o) { - const known = referenceMap.get(o); - if (known !== undefined) { - return known; - } - const hash = referenceUID++; - if (referenceUID === 0x7fffffff) { - referenceUID = 0; - } - referenceMap.set(o, hash); - return hash; -} - -/** - * merge two hashes in an order sensitive way - * @param {number} a - * @param {number} b - * @returns {number} - */ -function hashMerge(a, b) { - return (a ^ (b + 0x9e3779b9 + (a << 6) + (a >> 2))) | 0; -} - -/** - * standard string hash popularised by java - * @param {string} s - * @returns {number} - */ -function hashString(s) { - let hash = 0; - const len = s.length; - for (let i = 0; i < len; i++) { - hash = (Math.imul(31, hash) + s.charCodeAt(i)) | 0; - } - return hash; -} - -/** - * hash a number by converting to two integers and do some jumbling - * @param {number} n - * @returns {number} - */ -function hashNumber(n) { - tempDataView.setFloat64(0, n); - const i = tempDataView.getInt32(0); - const j = tempDataView.getInt32(4); - return Math.imul(0x45d9f3b, (i >> 16) ^ i) ^ j; -} - -/** - * hash a BigInt by converting it to a string and hashing that - * @param {BigInt} n - * @returns {number} - */ -function hashBigInt(n) { - return hashString(n.toString()); -} - -/** - * hash any js object - * @param {any} o - * @returns {number} - */ -function hashObject(o) { - const proto = Object.getPrototypeOf(o); - if (proto !== null && typeof proto.hashCode === "function") { - try { - const code = o.hashCode(o); - if (typeof code === "number") { - return code; - } - } catch {} - } - if (o instanceof Promise || o instanceof WeakSet || o instanceof WeakMap) { - return hashByReference(o); - } - if (o instanceof Date) { - return hashNumber(o.getTime()); - } - let h = 0; - if (o instanceof ArrayBuffer) { - o = new Uint8Array(o); - } - if (Array.isArray(o) || o instanceof Uint8Array) { - for (let i = 0; i < o.length; i++) { - h = (Math.imul(31, h) + getHash(o[i])) | 0; - } - } else if (o instanceof Set) { - o.forEach((v) => { - h = (h + getHash(v)) | 0; - }); - } else if (o instanceof Map) { - o.forEach((v, k) => { - h = (h + hashMerge(getHash(v), getHash(k))) | 0; - }); - } else { - const keys = Object.keys(o); - for (let i = 0; i < keys.length; i++) { - const k = keys[i]; - const v = o[k]; - h = (h + hashMerge(getHash(v), hashString(k))) | 0; - } - } - return h; -} - -/** - * hash any js value - * @param {any} u - * @returns {number} - */ -export function getHash(u) { - if (u === null) return 0x42108422; - if (u === undefined) return 0x42108423; - if (u === true) return 0x42108421; - if (u === false) return 0x42108420; - switch (typeof u) { - case "number": - return hashNumber(u); - case "string": - return hashString(u); - case "bigint": - return hashBigInt(u); - case "object": - return hashObject(u); - case "symbol": - return hashByReference(u); - case "function": - return hashByReference(u); - default: - return 0; // should be unreachable - } -} - -/** - * @template K,V - * @typedef {ArrayNode | IndexNode | CollisionNode} Node - */ -/** - * @template K,V - * @typedef {{ type: typeof ENTRY, k: K, v: V }} Entry - */ -/** - * @template K,V - * @typedef {{ type: typeof ARRAY_NODE, size: number, array: (undefined | Entry | Node)[] }} ArrayNode - */ -/** - * @template K,V - * @typedef {{ type: typeof INDEX_NODE, bitmap: number, array: (Entry | Node)[] }} IndexNode - */ -/** - * @template K,V - * @typedef {{ type: typeof COLLISION_NODE, hash: number, array: Entry[] }} CollisionNode - */ -/** - * @typedef {{ val: boolean }} Flag - */ -const SHIFT = 5; // number of bits you need to shift by to get the next bucket -const BUCKET_SIZE = Math.pow(2, SHIFT); -const MASK = BUCKET_SIZE - 1; // used to zero out all bits not in the bucket -const MAX_INDEX_NODE = BUCKET_SIZE / 2; // when does index node grow into array node -const MIN_ARRAY_NODE = BUCKET_SIZE / 4; // when does array node shrink to index node -const ENTRY = 0; -const ARRAY_NODE = 1; -const INDEX_NODE = 2; -const COLLISION_NODE = 3; - -/** @type {IndexNode} */ -const EMPTY = { - type: INDEX_NODE, - bitmap: 0, - array: [], -}; -/** - * Mask the hash to get only the bucket corresponding to shift - * @param {number} hash - * @param {number} shift - * @returns {number} - */ -function mask(hash, shift) { - return (hash >>> shift) & MASK; -} - -/** - * Set only the Nth bit where N is the masked hash - * @param {number} hash - * @param {number} shift - * @returns {number} - */ -function bitpos(hash, shift) { - return 1 << mask(hash, shift); -} - -/** - * Count the number of 1 bits in a number - * @param {number} x - * @returns {number} - */ -function bitcount(x) { - x -= (x >> 1) & 0x55555555; - x = (x & 0x33333333) + ((x >> 2) & 0x33333333); - x = (x + (x >> 4)) & 0x0f0f0f0f; - x += x >> 8; - x += x >> 16; - return x & 0x7f; -} - -/** - * Calculate the array index of an item in a bitmap index node - * @param {number} bitmap - * @param {number} bit - * @returns {number} - */ -function index(bitmap, bit) { - return bitcount(bitmap & (bit - 1)); -} - -/** - * Efficiently copy an array and set one value at an index - * @template T - * @param {T[]} arr - * @param {number} at - * @param {T} val - * @returns {T[]} - */ -function cloneAndSet(arr, at, val) { - const len = arr.length; - const out = new Array(len); - for (let i = 0; i < len; ++i) { - out[i] = arr[i]; - } - out[at] = val; - return out; -} - -/** - * Efficiently copy an array and insert one value at an index - * @template T - * @param {T[]} arr - * @param {number} at - * @param {T} val - * @returns {T[]} - */ -function spliceIn(arr, at, val) { - const len = arr.length; - const out = new Array(len + 1); - let i = 0; - let g = 0; - while (i < at) { - out[g++] = arr[i++]; - } - out[g++] = val; - while (i < len) { - out[g++] = arr[i++]; - } - return out; -} - -/** - * Efficiently copy an array and remove one value at an index - * @template T - * @param {T[]} arr - * @param {number} at - * @returns {T[]} - */ -function spliceOut(arr, at) { - const len = arr.length; - const out = new Array(len - 1); - let i = 0; - let g = 0; - while (i < at) { - out[g++] = arr[i++]; - } - ++i; - while (i < len) { - out[g++] = arr[i++]; - } - return out; -} - -/** - * Create a new node containing two entries - * @template K,V - * @param {number} shift - * @param {K} key1 - * @param {V} val1 - * @param {number} key2hash - * @param {K} key2 - * @param {V} val2 - * @returns {Node} - */ -function createNode(shift, key1, val1, key2hash, key2, val2) { - const key1hash = getHash(key1); - if (key1hash === key2hash) { - return { - type: COLLISION_NODE, - hash: key1hash, - array: [ - { type: ENTRY, k: key1, v: val1 }, - { type: ENTRY, k: key2, v: val2 }, - ], - }; - } - const addedLeaf = { val: false }; - return assoc( - assocIndex(EMPTY, shift, key1hash, key1, val1, addedLeaf), - shift, - key2hash, - key2, - val2, - addedLeaf, - ); -} - -/** - * @template T,K,V - * @callback AssocFunction - * @param {T} root - * @param {number} shift - * @param {number} hash - * @param {K} key - * @param {V} val - * @param {Flag} addedLeaf - * @returns {Node} - */ -/** - * Associate a node with a new entry, creating a new node - * @template T,K,V - * @type {AssocFunction,K,V>} - */ -function assoc(root, shift, hash, key, val, addedLeaf) { - switch (root.type) { - case ARRAY_NODE: - return assocArray(root, shift, hash, key, val, addedLeaf); - case INDEX_NODE: - return assocIndex(root, shift, hash, key, val, addedLeaf); - case COLLISION_NODE: - return assocCollision(root, shift, hash, key, val, addedLeaf); - } -} -/** - * @template T,K,V - * @type {AssocFunction,K,V>} - */ -function assocArray(root, shift, hash, key, val, addedLeaf) { - const idx = mask(hash, shift); - const node = root.array[idx]; - // if the corresponding index is empty set the index to a newly created node - if (node === undefined) { - addedLeaf.val = true; - return { - type: ARRAY_NODE, - size: root.size + 1, - array: cloneAndSet(root.array, idx, { type: ENTRY, k: key, v: val }), - }; - } - if (node.type === ENTRY) { - // if keys are equal replace the entry - if (isEqual(key, node.k)) { - if (val === node.v) { - return root; - } - return { - type: ARRAY_NODE, - size: root.size, - array: cloneAndSet(root.array, idx, { - type: ENTRY, - k: key, - v: val, - }), - }; - } - // otherwise upgrade the entry to a node and insert - addedLeaf.val = true; - return { - type: ARRAY_NODE, - size: root.size, - array: cloneAndSet( - root.array, - idx, - createNode(shift + SHIFT, node.k, node.v, hash, key, val), - ), - }; - } - // otherwise call assoc on the child node - const n = assoc(node, shift + SHIFT, hash, key, val, addedLeaf); - // if the child node hasn't changed just return the old root - if (n === node) { - return root; - } - // otherwise set the index to the new node - return { - type: ARRAY_NODE, - size: root.size, - array: cloneAndSet(root.array, idx, n), - }; -} -/** - * @template T,K,V - * @type {AssocFunction,K,V>} - */ -function assocIndex(root, shift, hash, key, val, addedLeaf) { - const bit = bitpos(hash, shift); - const idx = index(root.bitmap, bit); - // if there is already a item at this hash index.. - if ((root.bitmap & bit) !== 0) { - // if there is a node at the index (not an entry), call assoc on the child node - const node = root.array[idx]; - if (node.type !== ENTRY) { - const n = assoc(node, shift + SHIFT, hash, key, val, addedLeaf); - if (n === node) { - return root; - } - return { - type: INDEX_NODE, - bitmap: root.bitmap, - array: cloneAndSet(root.array, idx, n), - }; - } - // otherwise there is an entry at the index - // if the keys are equal replace the entry with the updated value - const nodeKey = node.k; - if (isEqual(key, nodeKey)) { - if (val === node.v) { - return root; - } - return { - type: INDEX_NODE, - bitmap: root.bitmap, - array: cloneAndSet(root.array, idx, { - type: ENTRY, - k: key, - v: val, - }), - }; - } - // if the keys are not equal, replace the entry with a new child node - addedLeaf.val = true; - return { - type: INDEX_NODE, - bitmap: root.bitmap, - array: cloneAndSet( - root.array, - idx, - createNode(shift + SHIFT, nodeKey, node.v, hash, key, val), - ), - }; - } else { - // else there is currently no item at the hash index - const n = root.array.length; - // if the number of nodes is at the maximum, expand this node into an array node - if (n >= MAX_INDEX_NODE) { - // create a 32 length array for the new array node (one for each bit in the hash) - const nodes = new Array(32); - // create and insert a node for the new entry - const jdx = mask(hash, shift); - nodes[jdx] = assocIndex(EMPTY, shift + SHIFT, hash, key, val, addedLeaf); - let j = 0; - let bitmap = root.bitmap; - // place each item in the index node into the correct spot in the array node - // loop through all 32 bits / array positions - for (let i = 0; i < 32; i++) { - if ((bitmap & 1) !== 0) { - const node = root.array[j++]; - nodes[i] = node; - } - // shift the bitmap to process the next bit - bitmap = bitmap >>> 1; - } - return { - type: ARRAY_NODE, - size: n + 1, - array: nodes, - }; - } else { - // else there is still space in this index node - // simply insert a new entry at the hash index - const newArray = spliceIn(root.array, idx, { - type: ENTRY, - k: key, - v: val, - }); - addedLeaf.val = true; - return { - type: INDEX_NODE, - bitmap: root.bitmap | bit, - array: newArray, - }; - } - } -} -/** - * @template T,K,V - * @type {AssocFunction,K,V>} - */ -function assocCollision(root, shift, hash, key, val, addedLeaf) { - // if there is a hash collision - if (hash === root.hash) { - const idx = collisionIndexOf(root, key); - // if this key already exists replace the entry with the new value - if (idx !== -1) { - const entry = root.array[idx]; - if (entry.v === val) { - return root; - } - return { - type: COLLISION_NODE, - hash: hash, - array: cloneAndSet(root.array, idx, { type: ENTRY, k: key, v: val }), - }; - } - // otherwise insert the entry at the end of the array - const size = root.array.length; - addedLeaf.val = true; - return { - type: COLLISION_NODE, - hash: hash, - array: cloneAndSet(root.array, size, { type: ENTRY, k: key, v: val }), - }; - } - // if there is no hash collision, upgrade to an index node - return assoc( - { - type: INDEX_NODE, - bitmap: bitpos(root.hash, shift), - array: [root], - }, - shift, - hash, - key, - val, - addedLeaf, - ); -} -/** - * Find the index of a key in the collision node's array - * @template K,V - * @param {CollisionNode} root - * @param {K} key - * @returns {number} - */ -function collisionIndexOf(root, key) { - const size = root.array.length; - for (let i = 0; i < size; i++) { - if (isEqual(key, root.array[i].k)) { - return i; - } - } - return -1; -} -/** - * @template T,K,V - * @callback FindFunction - * @param {T} root - * @param {number} shift - * @param {number} hash - * @param {K} key - * @returns {undefined | Entry} - */ -/** - * Return the found entry or undefined if not present in the root - * @template K,V - * @type {FindFunction,K,V>} - */ -function find(root, shift, hash, key) { - switch (root.type) { - case ARRAY_NODE: - return findArray(root, shift, hash, key); - case INDEX_NODE: - return findIndex(root, shift, hash, key); - case COLLISION_NODE: - return findCollision(root, key); - } -} -/** - * @template K,V - * @type {FindFunction,K,V>} - */ -function findArray(root, shift, hash, key) { - const idx = mask(hash, shift); - const node = root.array[idx]; - if (node === undefined) { - return undefined; - } - if (node.type !== ENTRY) { - return find(node, shift + SHIFT, hash, key); - } - if (isEqual(key, node.k)) { - return node; - } - return undefined; -} -/** - * @template K,V - * @type {FindFunction,K,V>} - */ -function findIndex(root, shift, hash, key) { - const bit = bitpos(hash, shift); - if ((root.bitmap & bit) === 0) { - return undefined; - } - const idx = index(root.bitmap, bit); - const node = root.array[idx]; - if (node.type !== ENTRY) { - return find(node, shift + SHIFT, hash, key); - } - if (isEqual(key, node.k)) { - return node; - } - return undefined; -} -/** - * @template K,V - * @param {CollisionNode} root - * @param {K} key - * @returns {undefined | Entry} - */ -function findCollision(root, key) { - const idx = collisionIndexOf(root, key); - if (idx < 0) { - return undefined; - } - return root.array[idx]; -} -/** - * @template T,K,V - * @callback WithoutFunction - * @param {T} root - * @param {number} shift - * @param {number} hash - * @param {K} key - * @returns {undefined | Node} - */ -/** - * Remove an entry from the root, returning the updated root. - * Returns undefined if the node should be removed from the parent. - * @template K,V - * @type {WithoutFunction,K,V>} - * */ -function without(root, shift, hash, key) { - switch (root.type) { - case ARRAY_NODE: - return withoutArray(root, shift, hash, key); - case INDEX_NODE: - return withoutIndex(root, shift, hash, key); - case COLLISION_NODE: - return withoutCollision(root, key); - } -} -/** - * @template K,V - * @type {WithoutFunction,K,V>} - */ -function withoutArray(root, shift, hash, key) { - const idx = mask(hash, shift); - const node = root.array[idx]; - if (node === undefined) { - return root; // already empty - } - let n = undefined; - // if node is an entry and the keys are not equal there is nothing to remove - // if node is not an entry do a recursive call - if (node.type === ENTRY) { - if (!isEqual(node.k, key)) { - return root; // no changes - } - } else { - n = without(node, shift + SHIFT, hash, key); - if (n === node) { - return root; // no changes - } - } - // if the recursive call returned undefined the node should be removed - if (n === undefined) { - // if the number of child nodes is at the minimum, pack into an index node - if (root.size <= MIN_ARRAY_NODE) { - const arr = root.array; - const out = new Array(root.size - 1); - let i = 0; - let j = 0; - let bitmap = 0; - while (i < idx) { - const nv = arr[i]; - if (nv !== undefined) { - out[j] = nv; - bitmap |= 1 << i; - ++j; - } - ++i; - } - ++i; // skip copying the removed node - while (i < arr.length) { - const nv = arr[i]; - if (nv !== undefined) { - out[j] = nv; - bitmap |= 1 << i; - ++j; - } - ++i; - } - return { - type: INDEX_NODE, - bitmap: bitmap, - array: out, - }; - } - return { - type: ARRAY_NODE, - size: root.size - 1, - array: cloneAndSet(root.array, idx, n), - }; - } - return { - type: ARRAY_NODE, - size: root.size, - array: cloneAndSet(root.array, idx, n), - }; -} -/** - * @template K,V - * @type {WithoutFunction,K,V>} - */ -function withoutIndex(root, shift, hash, key) { - const bit = bitpos(hash, shift); - if ((root.bitmap & bit) === 0) { - return root; // already empty - } - const idx = index(root.bitmap, bit); - const node = root.array[idx]; - // if the item is not an entry - if (node.type !== ENTRY) { - const n = without(node, shift + SHIFT, hash, key); - if (n === node) { - return root; // no changes - } - // if not undefined, the child node still has items, so update it - if (n !== undefined) { - return { - type: INDEX_NODE, - bitmap: root.bitmap, - array: cloneAndSet(root.array, idx, n), - }; - } - // otherwise the child node should be removed - // if it was the only child node, remove this node from the parent - if (root.bitmap === bit) { - return undefined; - } - // otherwise just remove the child node - return { - type: INDEX_NODE, - bitmap: root.bitmap ^ bit, - array: spliceOut(root.array, idx), - }; - } - // otherwise the item is an entry, remove it if the key matches - if (isEqual(key, node.k)) { - if (root.bitmap === bit) { - return undefined; - } - return { - type: INDEX_NODE, - bitmap: root.bitmap ^ bit, - array: spliceOut(root.array, idx), - }; - } - return root; -} -/** - * @template K,V - * @param {CollisionNode} root - * @param {K} key - * @returns {undefined | Node} - */ -function withoutCollision(root, key) { - const idx = collisionIndexOf(root, key); - // if the key not found, no changes - if (idx < 0) { - return root; - } - // otherwise the entry was found, remove it - // if it was the only entry in this node, remove the whole node - if (root.array.length === 1) { - return undefined; - } - // otherwise just remove the entry - return { - type: COLLISION_NODE, - hash: root.hash, - array: spliceOut(root.array, idx), - }; -} -/** - * @template K,V - * @param {undefined | Node} root - * @param {(value:V,key:K)=>void} fn - * @returns {void} - */ -function forEach(root, fn) { - if (root === undefined) { - return; - } - const items = root.array; - const size = items.length; - for (let i = 0; i < size; i++) { - const item = items[i]; - if (item === undefined) { - continue; - } - if (item.type === ENTRY) { - fn(item.v, item.k); - continue; - } - forEach(item, fn); - } -} - -/** - * Extra wrapper to keep track of Dict size and clean up the API - * @template K,V - */ -export default class Dict { - /** - * @template V - * @param {Record} o - * @returns {Dict} - */ - static fromObject(o) { - const keys = Object.keys(o); - /** @type Dict */ - let m = Dict.new(); - for (let i = 0; i < keys.length; i++) { - const k = keys[i]; - m = m.set(k, o[k]); - } - return m; - } - - /** - * @template K,V - * @param {Map} o - * @returns {Dict} - */ - static fromMap(o) { - /** @type Dict */ - let m = Dict.new(); - o.forEach((v, k) => { - m = m.set(k, v); - }); - return m; - } - - static new() { - return new Dict(undefined, 0); - } - - /** - * @param {undefined | Node} root - * @param {number} size - */ - constructor(root, size) { - this.root = root; - this.size = size; - } - /** - * @template NotFound - * @param {K} key - * @param {NotFound} notFound - * @returns {NotFound | V} - */ - get(key, notFound) { - if (this.root === undefined) { - return notFound; - } - const found = find(this.root, 0, getHash(key), key); - if (found === undefined) { - return notFound; - } - return found.v; - } - /** - * @param {K} key - * @param {V} val - * @returns {Dict} - */ - set(key, val) { - const addedLeaf = { val: false }; - const root = this.root === undefined ? EMPTY : this.root; - const newRoot = assoc(root, 0, getHash(key), key, val, addedLeaf); - if (newRoot === this.root) { - return this; - } - return new Dict(newRoot, addedLeaf.val ? this.size + 1 : this.size); - } - /** - * @param {K} key - * @returns {Dict} - */ - delete(key) { - if (this.root === undefined) { - return this; - } - const newRoot = without(this.root, 0, getHash(key), key); - if (newRoot === this.root) { - return this; - } - if (newRoot === undefined) { - return Dict.new(); - } - return new Dict(newRoot, this.size - 1); - } - /** - * @param {K} key - * @returns {boolean} - */ - has(key) { - if (this.root === undefined) { - return false; - } - return find(this.root, 0, getHash(key), key) !== undefined; - } - /** - * @returns {[K,V][]} - */ - entries() { - if (this.root === undefined) { - return []; - } - /** @type [K,V][] */ - const result = []; - this.forEach((v, k) => result.push([k, v])); - return result; - } - /** - * - * @param {(val:V,key:K)=>void} fn - */ - forEach(fn) { - forEach(this.root, fn); - } - hashCode() { - let h = 0; - this.forEach((v, k) => { - h = (h + hashMerge(getHash(v), getHash(k))) | 0; - }); - return h; - } - /** - * @param {unknown} o - * @returns {boolean} - */ - equals(o) { - if (!(o instanceof Dict) || this.size !== o.size) { - return false; - } - - try { - this.forEach((v, k) => { - if (!isEqual(o.get(k, !v), v)) { - throw unequalDictSymbol; - } - }); - return true; - } catch (e) { - if (e === unequalDictSymbol) { - return false; - } - - throw e; - } - } -} - -// This is thrown internally in Dict.equals() so that it returns false as soon -// as a non-matching key is found -const unequalDictSymbol = /* @__PURE__ */ Symbol(); diff --git a/build/packages/gleam_stdlib/src/gleam/bit_array.gleam b/build/packages/gleam_stdlib/src/gleam/bit_array.gleam deleted file mode 100644 index 544b74a..0000000 --- a/build/packages/gleam_stdlib/src/gleam/bit_array.gleam +++ /dev/null @@ -1,280 +0,0 @@ -//// BitArrays are a sequence of binary data of any length. - -import gleam/int -import gleam/order -import gleam/string - -/// Converts a UTF-8 `String` type into a `BitArray`. -/// -@external(erlang, "gleam_stdlib", "identity") -@external(javascript, "../gleam_stdlib.mjs", "bit_array_from_string") -pub fn from_string(x: String) -> BitArray - -/// Returns an integer which is the number of bits in the bit array. -/// -@external(erlang, "erlang", "bit_size") -@external(javascript, "../gleam_stdlib.mjs", "bit_array_bit_size") -pub fn bit_size(x: BitArray) -> Int - -/// Returns an integer which is the number of bytes in the bit array. -/// -@external(erlang, "erlang", "byte_size") -@external(javascript, "../gleam_stdlib.mjs", "bit_array_byte_size") -pub fn byte_size(x: BitArray) -> Int - -/// Pads a bit array with zeros so that it is a whole number of bytes. -/// -@external(erlang, "gleam_stdlib", "bit_array_pad_to_bytes") -@external(javascript, "../gleam_stdlib.mjs", "bit_array_pad_to_bytes") -pub fn pad_to_bytes(x: BitArray) -> BitArray - -/// Creates a new bit array by joining two bit arrays. -/// -/// ## Examples -/// -/// ```gleam -/// append(to: from_string("butter"), suffix: from_string("fly")) -/// // -> from_string("butterfly") -/// ``` -/// -pub fn append(to first: BitArray, suffix second: BitArray) -> BitArray { - concat([first, second]) -} - -/// Extracts a sub-section of a bit array. -/// -/// The slice will start at given position and continue up to specified -/// length. -/// A negative length can be used to extract bytes at the end of a bit array. -/// -/// This function runs in constant time. -/// -@external(erlang, "gleam_stdlib", "bit_array_slice") -@external(javascript, "../gleam_stdlib.mjs", "bit_array_slice") -pub fn slice( - from string: BitArray, - at position: Int, - take length: Int, -) -> Result(BitArray, Nil) - -/// Tests to see whether a bit array is valid UTF-8. -/// -pub fn is_utf8(bits: BitArray) -> Bool { - is_utf8_loop(bits) -} - -@target(erlang) -fn is_utf8_loop(bits: BitArray) -> Bool { - case bits { - <<>> -> True - <<_:utf8, rest:bytes>> -> is_utf8_loop(rest) - _ -> False - } -} - -@target(javascript) -fn is_utf8_loop(bits: BitArray) -> Bool { - case to_string(bits) { - Ok(_) -> True - Error(_) -> False - } -} - -/// Converts a bit array to a string. -/// -/// Returns an error if the bit array is invalid UTF-8 data. -/// -@external(javascript, "../gleam_stdlib.mjs", "bit_array_to_string") -pub fn to_string(bits: BitArray) -> Result(String, Nil) { - case is_utf8(bits) { - True -> Ok(unsafe_to_string(bits)) - False -> Error(Nil) - } -} - -@external(erlang, "gleam_stdlib", "identity") -fn unsafe_to_string(a: BitArray) -> String - -/// Creates a new bit array by joining multiple binaries. -/// -/// ## Examples -/// -/// ```gleam -/// concat([from_string("butter"), from_string("fly")]) -/// // -> from_string("butterfly") -/// ``` -/// -@external(erlang, "gleam_stdlib", "bit_array_concat") -@external(javascript, "../gleam_stdlib.mjs", "bit_array_concat") -pub fn concat(bit_arrays: List(BitArray)) -> BitArray - -/// Encodes a BitArray into a base 64 encoded string. -/// -/// If the bit array does not contain a whole number of bytes then it is padded -/// with zero bits prior to being encoded. -/// -@external(erlang, "gleam_stdlib", "base64_encode") -@external(javascript, "../gleam_stdlib.mjs", "base64_encode") -pub fn base64_encode(input: BitArray, padding: Bool) -> String - -/// Decodes a base 64 encoded string into a `BitArray`. -/// -pub fn base64_decode(encoded: String) -> Result(BitArray, Nil) { - let padded = case byte_size(from_string(encoded)) % 4 { - 0 -> encoded - n -> string.append(encoded, string.repeat("=", 4 - n)) - } - decode64(padded) -} - -@external(erlang, "gleam_stdlib", "base64_decode") -@external(javascript, "../gleam_stdlib.mjs", "base64_decode") -fn decode64(a: String) -> Result(BitArray, Nil) - -/// 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. -/// -pub fn base64_url_encode(input: BitArray, padding: Bool) -> String { - input - |> base64_encode(padding) - |> string.replace("+", "-") - |> string.replace("/", "_") -} - -/// Decodes a base 64 encoded string with URL and filename safe alphabet into a -/// `BitArray`. -/// -pub fn base64_url_decode(encoded: String) -> Result(BitArray, Nil) { - encoded - |> string.replace("-", "+") - |> string.replace("_", "/") - |> base64_decode() -} - -/// Encodes a `BitArray` into a base 16 encoded string. -/// -/// If the bit array does not contain a whole number of bytes then it is padded -/// with zero bits prior to being encoded. -/// -@external(erlang, "gleam_stdlib", "base16_encode") -@external(javascript, "../gleam_stdlib.mjs", "base16_encode") -pub fn base16_encode(input: BitArray) -> String - -/// Decodes a base 16 encoded string into a `BitArray`. -/// -@external(erlang, "gleam_stdlib", "base16_decode") -@external(javascript, "../gleam_stdlib.mjs", "base16_decode") -pub fn base16_decode(input: String) -> Result(BitArray, Nil) - -/// 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)>>" -/// ``` -/// -pub fn inspect(input: BitArray) -> String { - inspect_loop(input, "<<") <> ">>" -} - -fn inspect_loop(input: BitArray, accumulator: String) -> String { - case input { - <<>> -> accumulator - - <> -> accumulator <> int.to_string(x) <> ":size(1)" - <> -> accumulator <> int.to_string(x) <> ":size(2)" - <> -> accumulator <> int.to_string(x) <> ":size(3)" - <> -> accumulator <> int.to_string(x) <> ":size(4)" - <> -> accumulator <> int.to_string(x) <> ":size(5)" - <> -> accumulator <> int.to_string(x) <> ":size(6)" - <> -> accumulator <> int.to_string(x) <> ":size(7)" - - <> -> { - let suffix = case rest { - <<>> -> "" - _ -> ", " - } - - let accumulator = accumulator <> int.to_string(x) <> suffix - inspect_loop(rest, accumulator) - } - - _ -> accumulator - } -} - -/// 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 -/// ``` -/// -pub fn compare(a: BitArray, with b: BitArray) -> order.Order { - case a, b { - <>, <> -> - case first_byte, second_byte { - f, s if f > s -> order.Gt - f, s if f < s -> order.Lt - _, _ -> compare(first_rest, second_rest) - } - - <<>>, <<>> -> order.Eq - // First has more items, example: "AB" > "A": - _, <<>> -> order.Gt - // Second has more items, example: "A" < "AB": - <<>>, _ -> order.Lt - // This happens when there's unusually sized elements. - // Handle these special cases via custom erlang function. - first, second -> - case bit_array_to_int_and_size(first), bit_array_to_int_and_size(second) { - #(a, _), #(b, _) if a > b -> order.Gt - #(a, _), #(b, _) if a < b -> order.Lt - #(_, size_a), #(_, size_b) if size_a > size_b -> order.Gt - #(_, size_a), #(_, size_b) if size_a < size_b -> order.Lt - _, _ -> order.Eq - } - } -} - -@external(erlang, "gleam_stdlib", "bit_array_to_int_and_size") -@external(javascript, "../gleam_stdlib.mjs", "bit_array_to_int_and_size") -fn bit_array_to_int_and_size(a: BitArray) -> #(Int, Int) - -/// Checks whether the first `BitArray` starts with the second one. -/// -/// ## Examples -/// -/// ```gleam -/// starts_with(<<1, 2, 3, 4>>, <<1, 2>>) -/// // -> True -/// ``` -/// -@external(javascript, "../gleam_stdlib.mjs", "bit_array_starts_with") -pub fn starts_with(bits: BitArray, prefix: BitArray) -> Bool { - let prefix_size = bit_size(prefix) - - case bits { - <> if pref == prefix -> True - _ -> False - } -} diff --git a/build/packages/gleam_stdlib/src/gleam/bool.gleam b/build/packages/gleam_stdlib/src/gleam/bool.gleam deleted file mode 100644 index 26a6ac4..0000000 --- a/build/packages/gleam_stdlib/src/gleam/bool.gleam +++ /dev/null @@ -1,316 +0,0 @@ -//// A type with two possible values, `True` and `False`. Used to indicate whether -//// things are... true or false! -//// -//// Often is it clearer and offers more type safety to define a custom type -//// than to use `Bool`. For example, rather than having a `is_teacher: Bool` -//// field consider having a `role: SchoolRole` field where `SchoolRole` is a custom -//// type that can be either `Student` or `Teacher`. - -/// 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 -/// ``` -/// -pub fn and(a: Bool, b: Bool) -> Bool { - 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 -/// ``` -/// -pub fn or(a: Bool, b: Bool) -> Bool { - 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 -/// ``` -/// -pub fn negate(bool: Bool) -> Bool { - !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 -/// ``` -/// -pub fn nor(a: Bool, b: Bool) -> Bool { - !{ 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 -/// ``` -/// -pub fn nand(a: Bool, b: Bool) -> Bool { - !{ 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 -/// ``` -/// -pub fn exclusive_or(a: Bool, b: Bool) -> Bool { - 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 -/// ``` -/// -pub fn exclusive_nor(a: Bool, b: Bool) -> Bool { - a == b -} - -/// Returns a string representation of the given bool. -/// -/// ## Examples -/// -/// ```gleam -/// to_string(True) -/// // -> "True" -/// ``` -/// -/// ```gleam -/// to_string(False) -/// // -> "False" -/// ``` -/// -pub fn to_string(bool: Bool) -> String { - case bool { - False -> "False" - True -> "True" - } -} - -/// 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" -/// ``` -/// -pub fn guard( - when requirement: Bool, - return consequence: a, - otherwise alternative: fn() -> a, -) -> a { - case requirement { - True -> consequence - False -> 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" -/// ``` -/// -pub fn lazy_guard( - when requirement: Bool, - return consequence: fn() -> a, - otherwise alternative: fn() -> a, -) -> a { - case requirement { - True -> consequence() - False -> alternative() - } -} diff --git a/build/packages/gleam_stdlib/src/gleam/bytes_tree.gleam b/build/packages/gleam_stdlib/src/gleam/bytes_tree.gleam deleted file mode 100644 index 832fbee..0000000 --- a/build/packages/gleam_stdlib/src/gleam/bytes_tree.gleam +++ /dev/null @@ -1,190 +0,0 @@ -//// `BytesTree` is a type used for efficiently building binary content to be -//// written to a file or a socket. Internally it is represented as tree so to -//// append or prepend to a bytes tree is a constant time operation that -//// allocates a new node in the tree without copying any of the content. When -//// writing to an output stream the tree is traversed and the content is sent -//// directly rather than copying it into a single buffer beforehand. -//// -//// If we append one bit array to another the bit arrays must be copied to a -//// new location in memory so that they can sit together. This behaviour -//// enables efficient reading of the data but copying can be expensive, -//// especially if we want to join many bit arrays together. -//// -//// BytesTree is different in that it can be joined together in constant -//// time using minimal memory, and then can be efficiently converted to a -//// bit array using the `to_bit_array` function. -//// -//// Byte trees are always byte aligned, so that a number of bits that is not -//// divisible by 8 will be padded with 0s. -//// -//// On Erlang this type is compatible with Erlang's iolists. - -import gleam/bit_array -import gleam/list -import gleam/string_tree.{type StringTree} - -pub opaque type BytesTree { - Bytes(BitArray) - Text(StringTree) - Many(List(BytesTree)) -} - -/// Create an empty `BytesTree`. Useful as the start of a pipe chaining many -/// trees together. -/// -pub fn new() -> BytesTree { - concat([]) -} - -/// Prepends a bit array to the start of a bytes tree. -/// -/// Runs in constant time. -/// -pub fn prepend(to second: BytesTree, prefix first: BitArray) -> BytesTree { - append_tree(from_bit_array(first), second) -} - -/// Appends a bit array to the end of a bytes tree. -/// -/// Runs in constant time. -/// -pub fn append(to first: BytesTree, suffix second: BitArray) -> BytesTree { - append_tree(first, from_bit_array(second)) -} - -/// Prepends a bytes tree onto the start of another. -/// -/// Runs in constant time. -/// -pub fn prepend_tree(to second: BytesTree, prefix first: BytesTree) -> BytesTree { - append_tree(first, second) -} - -/// Appends a bytes tree onto the end of another. -/// -/// Runs in constant time. -/// -@external(erlang, "gleam_stdlib", "iodata_append") -pub fn append_tree(to first: BytesTree, suffix second: BytesTree) -> BytesTree { - case second { - Many(trees) -> Many([first, ..trees]) - Text(_) | Bytes(_) -> Many([first, second]) - } -} - -/// 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. -/// -pub fn prepend_string(to second: BytesTree, prefix first: String) -> BytesTree { - 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. -/// -pub fn append_string(to first: BytesTree, suffix second: String) -> BytesTree { - append_tree(first, from_string(second)) -} - -/// Joins a list of bytes trees into a single one. -/// -/// Runs in constant time. -/// -@external(erlang, "gleam_stdlib", "identity") -pub fn concat(trees: List(BytesTree)) -> BytesTree { - Many(trees) -} - -/// Joins a list of bit arrays into a single bytes tree. -/// -/// Runs in constant time. -/// -pub fn concat_bit_arrays(bits: List(BitArray)) -> BytesTree { - bits - |> list.map(from_bit_array) - |> concat() -} - -/// Creates a new bytes tree from a string. -/// -/// Runs in constant time when running on Erlang. -/// Runs in linear time otherwise. -/// -@external(erlang, "gleam_stdlib", "wrap_list") -pub fn from_string(string: String) -> BytesTree { - Text(string_tree.from_string(string)) -} - -/// Creates a new bytes tree from a string tree. -/// -/// Runs in constant time when running on Erlang. -/// Runs in linear time otherwise. -/// -@external(erlang, "gleam_stdlib", "wrap_list") -pub fn from_string_tree(tree: string_tree.StringTree) -> BytesTree { - Text(tree) -} - -/// Creates a new bytes tree from a bit array. -/// -/// Runs in constant time. -/// -pub fn from_bit_array(bits: BitArray) -> BytesTree { - bits - |> bit_array.pad_to_bytes - |> wrap_list -} - -@external(erlang, "gleam_stdlib", "wrap_list") -fn wrap_list(bits: BitArray) -> BytesTree { - Bytes(bits) -} - -/// 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. -/// -@external(erlang, "erlang", "list_to_bitstring") -pub fn to_bit_array(tree: BytesTree) -> BitArray { - [[tree]] - |> to_list([]) - |> list.reverse - |> bit_array.concat -} - -fn to_list(stack: List(List(BytesTree)), acc: List(BitArray)) -> List(BitArray) { - case stack { - [] -> acc - - [[], ..remaining_stack] -> to_list(remaining_stack, acc) - - [[Bytes(bits), ..rest], ..remaining_stack] -> - to_list([rest, ..remaining_stack], [bits, ..acc]) - - [[Text(tree), ..rest], ..remaining_stack] -> { - let bits = bit_array.from_string(string_tree.to_string(tree)) - to_list([rest, ..remaining_stack], [bits, ..acc]) - } - - [[Many(trees), ..rest], ..remaining_stack] -> - to_list([trees, rest, ..remaining_stack], acc) - } -} - -/// Returns the size of the bytes tree's content in bytes. -/// -/// Runs in linear time. -/// -@external(erlang, "erlang", "iolist_size") -pub fn byte_size(tree: BytesTree) -> Int { - [[tree]] - |> to_list([]) - |> list.fold(0, fn(acc, bits) { bit_array.byte_size(bits) + acc }) -} diff --git a/build/packages/gleam_stdlib/src/gleam/dict.gleam b/build/packages/gleam_stdlib/src/gleam/dict.gleam deleted file mode 100644 index 2942727..0000000 --- a/build/packages/gleam_stdlib/src/gleam/dict.gleam +++ /dev/null @@ -1,548 +0,0 @@ -import gleam/option.{type Option} - -/// A dictionary of keys and values. -/// -/// Any type can be used for the keys and values of a dict, but all the keys -/// must be of the same type and all the values must be of the same type. -/// -/// Each key can only be present in a dict once. -/// -/// Dicts are not ordered in any way, and any unintentional ordering is not to -/// be relied upon in your code as it may change in future versions of Erlang -/// or Gleam. -/// -/// See [the Erlang map module](https://erlang.org/doc/man/maps.html) for more -/// information. -/// -pub type Dict(key, value) - -/// Determines the number of key-value pairs in the dict. -/// This function runs in constant time and does not need to iterate the dict. -/// -/// ## Examples -/// -/// ```gleam -/// new() |> size -/// // -> 0 -/// ``` -/// -/// ```gleam -/// new() |> insert("key", "value") |> size -/// // -> 1 -/// ``` -/// -@external(erlang, "maps", "size") -@external(javascript, "../gleam_stdlib.mjs", "map_size") -pub fn size(dict: Dict(k, v)) -> Int - -/// Determines whether or not the dict is empty. -/// -/// ## Examples -/// -/// ```gleam -/// new() |> is_empty -/// // -> True -/// ``` -/// -/// ```gleam -/// new() |> insert("b", 1) |> is_empty -/// // -> False -/// ``` -/// -pub fn is_empty(dict: Dict(k, v)) -> Bool { - size(dict) == 0 -} - -/// Converts the dict to a list of 2-element tuples `#(key, value)`, one for -/// each key-value pair in the dict. -/// -/// The tuples in the list have no specific order. -/// -/// ## Examples -/// -/// Calling `to_list` on an empty `dict` returns an empty list. -/// -/// ```gleam -/// new() |> to_list -/// // -> [] -/// ``` -/// -/// The ordering of elements in the resulting list is an implementation detail -/// that should not be relied upon. -/// -/// ```gleam -/// new() |> insert("b", 1) |> insert("a", 0) |> insert("c", 2) |> to_list -/// // -> [#("a", 0), #("b", 1), #("c", 2)] -/// ``` -/// -@external(erlang, "maps", "to_list") -@external(javascript, "../gleam_stdlib.mjs", "map_to_list") -pub fn to_list(dict: Dict(k, v)) -> List(#(k, v)) - -/// 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. -/// -@external(erlang, "maps", "from_list") -pub fn from_list(list: List(#(k, v))) -> Dict(k, v) { - from_list_loop(list, new()) -} - -fn from_list_loop( - over list: List(#(k, v)), - from initial: Dict(k, v), -) -> Dict(k, v) { - case list { - [] -> initial - [#(key, value), ..rest] -> from_list_loop(rest, insert(initial, key, value)) - } -} - -/// 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 -/// ``` -/// -pub fn has_key(dict: Dict(k, v), key: k) -> Bool { - do_has_key(key, dict) -} - -@external(erlang, "maps", "is_key") -fn do_has_key(key: k, dict: Dict(k, v)) -> Bool { - get(dict, key) != Error(Nil) -} - -/// Creates a fresh dict that contains no values. -/// -@external(erlang, "maps", "new") -@external(javascript, "../gleam_stdlib.mjs", "new_map") -pub fn new() -> Dict(k, v) - -/// Fetches a value from a dict for a given key. -/// -/// The dict may not have a value for the key, so the value is wrapped in a -/// `Result`. -/// -/// ## Examples -/// -/// ```gleam -/// new() |> insert("a", 0) |> get("a") -/// // -> Ok(0) -/// ``` -/// -/// ```gleam -/// new() |> insert("a", 0) |> get("b") -/// // -> Error(Nil) -/// ``` -/// -@external(erlang, "gleam_stdlib", "map_get") -@external(javascript, "../gleam_stdlib.mjs", "map_get") -pub fn get(from: Dict(k, v), get: k) -> Result(v, Nil) - -/// 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)]) -/// ``` -/// -pub fn insert(into dict: Dict(k, v), for key: k, insert value: v) -> Dict(k, v) { - do_insert(key, value, dict) -} - -@external(erlang, "maps", "put") -@external(javascript, "../gleam_stdlib.mjs", "map_insert") -fn do_insert(key: k, value: v, dict: Dict(k, v)) -> Dict(k, v) - -/// 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)]) -/// ``` -/// -pub fn map_values(in dict: Dict(k, v), with fun: fn(k, v) -> a) -> Dict(k, a) { - do_map_values(fun, dict) -} - -@external(erlang, "maps", "map") -fn do_map_values(f: fn(k, v) -> a, dict: Dict(k, v)) -> Dict(k, a) { - let f = fn(dict, k, v) { insert(dict, k, f(k, v)) } - fold(dict, from: new(), with: f) -} - -/// 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"] -/// ``` -/// -@external(erlang, "maps", "keys") -pub fn keys(dict: Dict(k, v)) -> List(k) { - do_keys_loop(to_list(dict), []) -} - -fn do_keys_loop(list: List(#(k, v)), acc: List(k)) -> List(k) { - case list { - [] -> reverse_and_concat(acc, []) - [#(key, _value), ..rest] -> do_keys_loop(rest, [key, ..acc]) - } -} - -fn reverse_and_concat(remaining: List(a), accumulator: List(a)) -> List(a) { - case remaining { - [] -> accumulator - [first, ..rest] -> reverse_and_concat(rest, [first, ..accumulator]) - } -} - -/// 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] -/// ``` -/// -@external(erlang, "maps", "values") -pub fn values(dict: Dict(k, v)) -> List(v) { - let list_of_pairs = to_list(dict) - do_values_loop(list_of_pairs, []) -} - -fn do_values_loop(list: List(#(k, v)), acc: List(v)) -> List(v) { - case list { - [] -> reverse_and_concat(acc, []) - [#(_key, value), ..rest] -> do_values_loop(rest, [value, ..acc]) - } -} - -/// 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)]) -/// ``` -/// -pub fn filter( - in dict: Dict(k, v), - keeping predicate: fn(k, v) -> Bool, -) -> Dict(k, v) { - do_filter(predicate, dict) -} - -@external(erlang, "maps", "filter") -fn do_filter(f: fn(k, v) -> Bool, dict: Dict(k, v)) -> Dict(k, v) { - let insert = fn(dict, k, v) { - case f(k, v) { - True -> insert(dict, k, v) - False -> dict - } - } - - fold(dict, from: new(), with: insert) -} - -/// 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)]) -/// ``` -/// -pub fn take(from dict: Dict(k, v), keeping desired_keys: List(k)) -> Dict(k, v) { - do_take(desired_keys, dict) -} - -@external(erlang, "maps", "with") -fn do_take(desired_keys: List(k), dict: Dict(k, v)) -> Dict(k, v) { - do_take_loop(dict, desired_keys, new()) -} - -fn do_take_loop( - dict: Dict(k, v), - desired_keys: List(k), - acc: Dict(k, v), -) -> Dict(k, v) { - let insert = fn(taken, key) { - case get(dict, key) { - Ok(value) -> insert(taken, key, value) - Error(_) -> taken - } - } - case desired_keys { - [] -> acc - [first, ..rest] -> do_take_loop(dict, rest, insert(acc, 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)]) -/// ``` -/// -@external(erlang, "maps", "merge") -pub fn merge(into dict: Dict(k, v), from new_entries: Dict(k, v)) -> Dict(k, v) { - new_entries - |> to_list - |> fold_inserts(dict) -} - -fn fold_inserts(new_entries: List(#(k, v)), dict: Dict(k, v)) -> Dict(k, v) { - case new_entries { - [] -> dict - [first, ..rest] -> fold_inserts(rest, insert_pair(dict, first)) - } -} - -fn insert_pair(dict: Dict(k, v), pair: #(k, v)) -> Dict(k, v) { - insert(dict, pair.0, pair.1) -} - -/// 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)]) -/// ``` -/// -pub fn delete(from dict: Dict(k, v), delete key: k) -> Dict(k, v) { - do_delete(key, dict) -} - -@external(erlang, "maps", "remove") -@external(javascript, "../gleam_stdlib.mjs", "map_remove") -fn do_delete(a: k, b: Dict(k, v)) -> Dict(k, v) - -/// 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([]) -/// ``` -/// -pub fn drop(from dict: Dict(k, v), drop disallowed_keys: List(k)) -> Dict(k, v) { - case disallowed_keys { - [] -> dict - [first, ..rest] -> drop(delete(dict, first), 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)]) -/// ``` -/// -pub fn upsert( - in dict: Dict(k, v), - update key: k, - with fun: fn(Option(v)) -> v, -) -> Dict(k, v) { - case get(dict, key) { - Ok(value) -> insert(dict, key, fun(option.Some(value))) - Error(_) -> insert(dict, key, fun(option.None)) - } -} - -/// 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" -/// ``` -/// -pub fn fold( - over dict: Dict(k, v), - from initial: acc, - with fun: fn(acc, k, v) -> acc, -) -> acc { - fold_loop(to_list(dict), initial, fun) -} - -fn fold_loop( - list: List(#(k, v)), - initial: acc, - fun: fn(acc, k, v) -> acc, -) -> acc { - case list { - [] -> initial - [#(k, v), ..rest] -> fold_loop(rest, fun(initial, k, v), fun) - } -} - -/// 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. -/// -pub fn each(dict: Dict(k, v), fun: fn(k, v) -> a) -> Nil { - fold(dict, Nil, fn(nil, k, v) { - fun(k, v) - 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)]) -/// ``` -/// -pub fn combine( - dict: Dict(k, v), - other: Dict(k, v), - with fun: fn(v, v) -> v, -) -> Dict(k, v) { - use acc, key, value <- fold(over: dict, from: other) - case get(acc, key) { - Ok(other_value) -> insert(acc, key, fun(value, other_value)) - Error(_) -> insert(acc, key, value) - } -} diff --git a/build/packages/gleam_stdlib/src/gleam/dynamic.gleam b/build/packages/gleam_stdlib/src/gleam/dynamic.gleam deleted file mode 100644 index 6dfcbe6..0000000 --- a/build/packages/gleam_stdlib/src/gleam/dynamic.gleam +++ /dev/null @@ -1,100 +0,0 @@ -import gleam/dict - -/// `Dynamic` data is data that we don't know the type of yet. -/// We likely get data like this from interop with Erlang, or from -/// IO with the outside world. -/// -/// This module contains code for forming dynamic data, and the -/// `gleam/dynamic/decode` module contains code for turning dynamic data back -/// into Gleam data with known types. You will likely mostly use the other -/// module in your projects. -/// -/// The exact runtime representation of dynamic values will depend on the -/// compilation target used. -/// -pub type Dynamic - -/// Return a string indicating the type of the dynamic value. -/// -/// This function may be useful for constructing error messages or logs. If you -/// want to turn dynamic data into well typed data then you want the -/// `gleam/dynamic/decode` module. -/// -/// ```gleam -/// classify(string("Hello")) -/// // -> "String" -/// ``` -/// -@external(erlang, "gleam_stdlib", "classify_dynamic") -@external(javascript, "../gleam_stdlib.mjs", "classify_dynamic") -pub fn classify(data: Dynamic) -> String - -/// Create a dynamic value from a bool. -/// -@external(erlang, "gleam_stdlib", "identity") -@external(javascript, "../gleam_stdlib.mjs", "identity") -pub fn bool(a: Bool) -> Dynamic - -/// Create a dynamic value from a string. -/// -/// On Erlang this will be a binary string rather than a character list. -/// -@external(erlang, "gleam_stdlib", "identity") -@external(javascript, "../gleam_stdlib.mjs", "identity") -pub fn string(a: String) -> Dynamic - -/// Create a dynamic value from a float. -/// -@external(erlang, "gleam_stdlib", "identity") -@external(javascript, "../gleam_stdlib.mjs", "identity") -pub fn float(a: Float) -> Dynamic - -/// Create a dynamic value from an int. -/// -@external(erlang, "gleam_stdlib", "identity") -@external(javascript, "../gleam_stdlib.mjs", "identity") -pub fn int(a: Int) -> Dynamic - -/// Create a dynamic value from a bit array. -/// -@external(erlang, "gleam_stdlib", "identity") -@external(javascript, "../gleam_stdlib.mjs", "identity") -pub fn bit_array(a: BitArray) -> Dynamic - -/// Create a dynamic value from a list. -/// -@external(erlang, "gleam_stdlib", "identity") -@external(javascript, "../gleam_stdlib.mjs", "identity") -pub fn list(a: List(Dynamic)) -> Dynamic - -/// Create a dynamic value from a list, converting it to a sequential runtime -/// format rather than the regular list format. -/// -/// On Erlang this will be a tuple, on JavaScript this will be an array. -/// -@external(erlang, "erlang", "list_to_tuple") -@external(javascript, "../gleam_stdlib.mjs", "list_to_array") -pub fn array(a: List(Dynamic)) -> Dynamic - -/// 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. -/// -pub fn properties(entries: List(#(Dynamic, Dynamic))) -> Dynamic { - cast(dict.from_list(entries)) -} - -/// A dynamic value representing nothing. -/// -/// On Erlang this will be the atom `nil`, on JavaScript this will be -/// `undefined`. -/// -pub fn nil() -> Dynamic { - cast(Nil) -} - -@external(erlang, "gleam_stdlib", "identity") -@external(javascript, "../gleam_stdlib.mjs", "identity") -fn cast(a: anything) -> Dynamic diff --git a/build/packages/gleam_stdlib/src/gleam/dynamic/decode.gleam b/build/packages/gleam_stdlib/src/gleam/dynamic/decode.gleam deleted file mode 100644 index 03ee2ac..0000000 --- a/build/packages/gleam_stdlib/src/gleam/dynamic/decode.gleam +++ /dev/null @@ -1,1061 +0,0 @@ -//// The `Dynamic` type is used to represent dynamically typed data. That is, data -//// that we don't know the precise type of yet, so we need to introspect the data to -//// see if it is of the desired type before we can use it. Typically data like this -//// would come from user input or from untyped languages such as Erlang or JavaScript. -//// -//// This module provides the `Decoder` type and associated functions, which provides -//// a type-safe and composable way to convert dynamic data into some desired type, -//// or into errors if the data doesn't have the desired structure. -//// -//// The `Decoder` type is generic and has 1 type parameter, which is the type that -//// it attempts to decode. A `Decoder(String)` can be used to decode strings, and a -//// `Decoder(Option(Int))` can be used to decode `Option(Int)`s -//// -//// Decoders work using _runtime reflection_ and the data structures of the target -//// platform. Differences between Erlang and JavaScript data structures may impact -//// your decoders, so it is important to test your decoders on all supported -//// platforms. -//// -//// The decoding technique used by this module was inspired by Juraj Petráš' -//// [Toy](https://github.com/Hackder/toy), Go's `encoding/json`, and Elm's -//// `Json.Decode`. Thank you to them! -//// -//// # Examples -//// -//// Dynamic data may come from various sources and so many different syntaxes could -//// be used to describe or construct them. In these examples a pseudocode -//// syntax is used to describe the data. -//// -//// ## Simple types -//// -//// This module defines decoders for simple data types such as [`string`](#string), -//// [`int`](#int), [`float`](#float), [`bit_array`](#bit_array), and [`bool`](#bool). -//// -//// ```gleam -//// // Data: -//// // "Hello, Joe!" -//// -//// let result = decode.run(data, decode.string) -//// assert result == Ok("Hello, Joe!") -//// ``` -//// -//// ## Lists -//// -//// The [`list`](#list) decoder decodes `List`s. To use it you must construct it by -//// passing in another decoder into the `list` function, which is the decoder that -//// is to be used for the elements of the list, type checking both the list and its -//// elements. -//// -//// ```gleam -//// // Data: -//// // [1, 2, 3, 4] -//// -//// let result = decode.run(data, decode.list(decode.int)) -//// assert result == Ok([1, 2, 3, 4]) -//// ``` -//// -//// On Erlang this decoder can decode from lists, and on JavaScript it can -//// decode from lists as well as JavaScript arrays. -//// -//// ## Options -//// -//// The [`optional`](#optional) decoder is used to decode values that may or may not -//// be present. In other environment these might be called "nullable" values. -//// -//// Like the `list` decoder, the `optional` decoder takes another decoder, -//// which is used to decode the value if it is present. -//// -//// ```gleam -//// // Data: -//// // 12.45 -//// -//// let result = decode.run(data, decode.optional(decode.float)) -//// assert result == Ok(option.Some(12.45)) -//// ``` -//// ```gleam -//// // Data: -//// // null -//// -//// let result = decode.run(data, decode.optional(decode.int)) -//// assert result == Ok(option.None) -//// ``` -//// -//// This decoder knows how to handle multiple different runtime representations of -//// absent values, including `Nil`, `None`, `null`, and `undefined`. -//// -//// ## Dicts -//// -//// The [`dict`](#dict) decoder decodes `Dicts` and contains two other decoders, one -//// for the keys, one for the values. -//// -//// ```gleam -//// // Data: -//// // { "Lucy" -> 10, "Nubi" -> 20 } -//// -//// let result = decode.run(data, decode.dict(decode.string, decode.int)) -//// assert result == Ok(dict.from_list([ -//// #("Lucy", 10), -//// #("Nubi", 20), -//// ])) -//// ``` -//// -//// ## Indexing objects -//// -//// The [`at`](#at) decoder can be used to decode a value that is nested within -//// key-value containers such as Gleam dicts, Erlang maps, or JavaScript objects. -//// -//// ```gleam -//// // Data: -//// // { "one" -> { "two" -> 123 } } -//// -//// let result = decode.run(data, decode.at(["one", "two"], decode.int)) -//// assert result == Ok(123) -//// ``` -//// -//// ## Indexing arrays -//// -//// If you use ints as keys then the [`at`](#at) decoder can be used to index into -//// array-like containers such as Gleam or Erlang tuples, or JavaScript arrays. -//// -//// ```gleam -//// // Data: -//// // ["one", "two", "three"] -//// -//// let result = decode.run(data, decode.at([1], decode.string)) -//// assert result == Ok("two") -//// ``` -//// -//// ## Records -//// -//// Decoding records from dynamic data is more complex and requires combining a -//// decoder for each field and a special constructor that builds your records with -//// the decoded field values. -//// -//// ```gleam -//// // Data: -//// // { -//// // "score" -> 180, -//// // "name" -> "Mel Smith", -//// // "is-admin" -> false, -//// // "enrolled" -> true, -//// // "colour" -> "Red", -//// // } -//// -//// let decoder = { -//// use name <- decode.field("name", decode.string) -//// use score <- decode.field("score", decode.int) -//// use colour <- decode.field("colour", decode.string) -//// use enrolled <- decode.field("enrolled", decode.bool) -//// decode.success(Player(name:, score:, colour:, enrolled:)) -//// } -//// -//// let result = decode.run(data, decoder) -//// assert result == Ok(Player("Mel Smith", 180, "Red", True)) -//// ``` -//// -//// ## Enum variants -//// -//// Imagine you have a custom type where all the variants do not contain any values. -//// -//// ```gleam -//// pub type PocketMonsterType { -//// Fire -//// Water -//// Grass -//// Electric -//// } -//// ``` -//// -//// You might choose to encode these variants as strings, `"fire"` for `Fire`, -//// `"water"` for `Water`, and so on. To decode them you'll need to decode the dynamic -//// data as a string, but then you'll need to decode it further still as not all -//// strings are valid values for the enum. This can be done with the `then` -//// function, which enables running a second decoder after the first one -//// succeeds. -//// -//// ```gleam -//// let decoder = { -//// use decoded_string <- decode.then(decode.string) -//// case decoded_string { -//// // Return succeeding decoders for valid strings -//// "fire" -> decode.success(Fire) -//// "water" -> decode.success(Water) -//// "grass" -> decode.success(Grass) -//// "electric" -> decode.success(Electric) -//// // Return a failing decoder for any other strings -//// _ -> decode.failure(Fire, "PocketMonsterType") -//// } -//// } -//// -//// let result = decode.run(dynamic.string("water"), decoder) -//// assert result == Ok(Water) -//// -//// let result = decode.run(dynamic.string("wobble"), decoder) -//// assert result == Error([DecodeError("PocketMonsterType", "String", [])]) -//// ``` -//// -//// ## Record variants -//// -//// Decoding type variants that contain other values is done by combining the -//// techniques from the "enum variants" and "records" examples. Imagine you have -//// this custom type that you want to decode: -//// -//// ```gleam -//// pub type PocketMonsterPerson { -//// Trainer(name: String, badge_count: Int) -//// GymLeader(name: String, speciality: PocketMonsterType) -//// } -//// ``` -//// And you would like to be able to decode these from dynamic data like this: -//// ```erlang -//// { -//// "type" -> "trainer", -//// "name" -> "Ash", -//// "badge-count" -> 1, -//// } -//// ``` -//// ```erlang -//// { -//// "type" -> "gym-leader", -//// "name" -> "Misty", -//// "speciality" -> "water", -//// } -//// ``` -//// -//// Notice how both documents have a `"type"` field, which is used to indicate which -//// variant the data is for. -//// -//// First, define decoders for each of the variants: -//// -//// ```gleam -//// let trainer_decoder = { -//// use name <- decode.field("name", decode.string) -//// use badge_count <- decode.field("badge-count", decode.int) -//// decode.success(Trainer(name, badge_count)) -//// } -//// -//// let gym_leader_decoder = { -//// use name <- decode.field("name", decode.string) -//// use speciality <- decode.field("speciality", pocket_monster_type_decoder) -//// decode.success(GymLeader(name, speciality)) -//// } -//// ``` -//// -//// A third decoder can be used to extract and decode the `"type"` field, and the -//// expression can evaluate to whichever decoder is suitable for the document. -//// -//// ```gleam -//// // Data: -//// // { -//// // "type" -> "gym-leader", -//// // "name" -> "Misty", -//// // "speciality" -> "water", -//// // } -//// -//// let decoder = { -//// use tag <- decode.field("type", decode.string) -//// case tag { -//// "gym-leader" -> gym_leader_decoder -//// _ -> trainer_decoder -//// } -//// } -//// -//// let result = decode.run(data, decoder) -//// assert result == Ok(GymLeader("Misty", Water)) -//// ``` - -import gleam/bit_array -import gleam/dict.{type Dict} -import gleam/dynamic -import gleam/int -import gleam/list -import gleam/option.{type Option, None, Some} - -/// `Dynamic` data is data that we don't know the type of yet, originating from -/// external untyped systems. -/// -/// You should never be converting your well typed data to dynamic data. -/// -pub type Dynamic = - dynamic.Dynamic - -/// Error returned when unexpected data is encountered -/// -pub type DecodeError { - DecodeError(expected: String, found: String, path: List(String)) -} - -/// A decoder is a value that can be used to turn dynamically typed `Dynamic` -/// data into typed data using the `run` function. -/// -/// Several smaller decoders can be combined to make larger decoders using -/// functions such as `list` and `field`. -/// -pub opaque type Decoder(t) { - Decoder(function: fn(Dynamic) -> #(t, List(DecodeError))) -} - -/// 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")) -/// ``` -/// -pub fn subfield( - field_path: List(name), - field_decoder: Decoder(t), - next: fn(t) -> Decoder(final), -) -> Decoder(final) { - Decoder(function: fn(data) { - let #(out, errors1) = - index(field_path, [], field_decoder.function, data, fn(data, position) { - let #(default, _) = field_decoder.function(data) - #(default, [DecodeError("Field", "Nothing", [])]) - |> push_path(list.reverse(position)) - }) - let #(out, errors2) = next(out).function(data) - #(out, list.append(errors1, errors2)) - }) -} - -/// 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) -/// ``` -/// -pub fn run(data: Dynamic, decoder: Decoder(t)) -> Result(t, List(DecodeError)) { - let #(maybe_invalid_data, errors) = decoder.function(data) - case errors { - [] -> Ok(maybe_invalid_data) - [_, ..] -> Error(errors) - } -} - -/// 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) -/// ``` -/// -pub fn at(path: List(segment), inner: Decoder(a)) -> Decoder(a) { - Decoder(function: fn(data) { - index(path, [], inner.function, data, fn(data, position) { - let #(default, _) = inner.function(data) - #(default, [DecodeError("Field", "Nothing", [])]) - |> push_path(list.reverse(position)) - }) - }) -} - -fn index( - path: List(a), - position: List(a), - inner: fn(Dynamic) -> #(b, List(DecodeError)), - data: Dynamic, - handle_miss: fn(Dynamic, List(a)) -> #(b, List(DecodeError)), -) -> #(b, List(DecodeError)) { - case path { - [] -> { - data - |> inner - |> push_path(list.reverse(position)) - } - - [key, ..path] -> { - case bare_index(data, key) { - Ok(Some(data)) -> { - index(path, [key, ..position], inner, data, handle_miss) - } - Ok(None) -> { - handle_miss(data, [key, ..position]) - } - Error(kind) -> { - let #(default, _) = inner(data) - #(default, [DecodeError(kind, dynamic.classify(data), [])]) - |> push_path(list.reverse(position)) - } - } - } - } -} - -@external(erlang, "gleam_stdlib", "index") -@external(javascript, "../../gleam_stdlib.mjs", "index") -fn bare_index(data: Dynamic, key: anything) -> Result(Option(Dynamic), String) - -fn push_path( - layer: #(t, List(DecodeError)), - path: List(key), -) -> #(t, List(DecodeError)) { - let decoder = one_of(string, [int |> map(int.to_string)]) - let path = - list.map(path, fn(key) { - let key = cast(key) - case run(key, decoder) { - Ok(key) -> key - Error(_) -> "<" <> dynamic.classify(key) <> ">" - } - }) - let errors = - list.map(layer.1, fn(error) { - DecodeError(..error, path: list.append(path, error.path)) - }) - #(layer.0, 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")) -/// ``` -/// -pub fn success(data: t) -> Decoder(t) { - Decoder(function: fn(_) { #(data, []) }) -} - -/// Construct a decode error for some unexpected dynamic data. -/// -pub fn decode_error( - expected expected: String, - found found: Dynamic, -) -> List(DecodeError) { - [DecodeError(expected: expected, found: dynamic.classify(found), path: [])] -} - -/// 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). -/// -pub fn field( - field_name: name, - field_decoder: Decoder(t), - next: fn(t) -> Decoder(final), -) -> Decoder(final) { - subfield([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")) -/// ``` -/// -pub fn optional_field( - key: name, - default: t, - field_decoder: Decoder(t), - next: fn(t) -> Decoder(final), -) -> Decoder(final) { - Decoder(function: fn(data) { - let #(out, errors1) = - case bare_index(data, key) { - Ok(Some(data)) -> field_decoder.function(data) - Ok(None) -> #(default, []) - Error(kind) -> #(default, [ - DecodeError(kind, dynamic.classify(data), []), - ]) - } - |> push_path([key]) - let #(out, errors2) = next(out).function(data) - #(out, 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) -/// ``` -/// -pub fn optionally_at( - path: List(segment), - default: a, - inner: Decoder(a), -) -> Decoder(a) { - Decoder(function: fn(data) { - index(path, [], inner.function, data, fn(_, _) { #(default, []) }) - }) -} - -fn run_dynamic_function( - data: Dynamic, - name: String, - f: fn(Dynamic) -> Result(t, t), -) -> #(t, List(DecodeError)) { - case f(data) { - Ok(data) -> #(data, []) - Error(zero) -> #(zero, [DecodeError(name, dynamic.classify(data), [])]) - } -} - -/// A decoder that decodes `String` values. -/// -/// # Examples -/// -/// ```gleam -/// let result = decode.run(dynamic.string("Hello!"), decode.string) -/// assert result == Ok("Hello!") -/// ``` -/// -pub const string: Decoder(String) = Decoder(decode_string) - -fn decode_string(data: Dynamic) -> #(String, List(DecodeError)) { - run_dynamic_function(data, "String", dynamic_string) -} - -@external(javascript, "../../gleam_stdlib.mjs", "string") -fn dynamic_string(from data: Dynamic) -> Result(String, String) { - case dynamic_bit_array(data) { - Ok(data) -> - case bit_array.to_string(data) { - Ok(string) -> Ok(string) - Error(_) -> Error("") - } - Error(_) -> Error("") - } -} - -/// A decoder that decodes `Bool` values. -/// -/// # Examples -/// -/// ```gleam -/// let result = decode.run(dynamic.bool(True), decode.bool) -/// assert result == Ok(True) -/// ``` -/// -pub const bool: Decoder(Bool) = Decoder(decode_bool) - -fn decode_bool(data: Dynamic) -> #(Bool, List(DecodeError)) { - case cast(True) == data { - True -> #(True, []) - False -> - case cast(False) == data { - True -> #(False, []) - False -> #(False, decode_error("Bool", data)) - } - } -} - -/// A decoder that decodes `Int` values. -/// -/// # Examples -/// -/// ```gleam -/// let result = decode.run(dynamic.int(147), decode.int) -/// assert result == Ok(147) -/// ``` -/// -pub const int: Decoder(Int) = Decoder(decode_int) - -fn decode_int(data: Dynamic) -> #(Int, List(DecodeError)) { - run_dynamic_function(data, "Int", dynamic_int) -} - -@external(erlang, "gleam_stdlib", "int") -@external(javascript, "../../gleam_stdlib.mjs", "int") -fn dynamic_int(data: Dynamic) -> Result(Int, Int) - -/// A decoder that decodes `Float` values. -/// -/// # Examples -/// -/// ```gleam -/// let result = decode.run(dynamic.float(3.14), decode.float) -/// assert result == Ok(3.14) -/// ``` -/// -pub const float: Decoder(Float) = Decoder(decode_float) - -fn decode_float(data: Dynamic) -> #(Float, List(DecodeError)) { - run_dynamic_function(data, "Float", dynamic_float) -} - -@external(erlang, "gleam_stdlib", "float") -@external(javascript, "../../gleam_stdlib.mjs", "float") -fn dynamic_float(data: Dynamic) -> Result(Float, Float) - -/// 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)) -/// ``` -/// -pub const dynamic: Decoder(Dynamic) = Decoder(decode_dynamic) - -fn decode_dynamic(data: Dynamic) -> #(Dynamic, List(DecodeError)) { - #(data, []) -} - -/// 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>>) -/// ``` -/// -pub const bit_array: Decoder(BitArray) = Decoder(decode_bit_array) - -fn decode_bit_array(data: Dynamic) -> #(BitArray, List(DecodeError)) { - run_dynamic_function(data, "BitArray", dynamic_bit_array) -} - -@external(erlang, "gleam_stdlib", "bit_array") -@external(javascript, "../../gleam_stdlib.mjs", "bit_array") -fn dynamic_bit_array(data: Dynamic) -> Result(BitArray, BitArray) - -/// 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]) -/// ``` -/// -pub fn list(of inner: Decoder(a)) -> Decoder(List(a)) { - Decoder(fn(data) { - decode_list(data, inner.function, fn(p, k) { push_path(p, [k]) }, 0, []) - }) -} - -@external(erlang, "gleam_stdlib", "list") -@external(javascript, "../../gleam_stdlib.mjs", "list") -fn decode_list( - data: Dynamic, - item: fn(Dynamic) -> #(t, List(DecodeError)), - push_path: fn(#(t, List(DecodeError)), key) -> #(t, List(DecodeError)), - index: Int, - acc: List(t), -) -> #(List(t), List(DecodeError)) - -/// 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) -/// ``` -/// -pub fn dict( - key: Decoder(key), - value: Decoder(value), -) -> Decoder(Dict(key, value)) { - Decoder(fn(data) { - case decode_dict(data) { - Error(_) -> #(dict.new(), decode_error("Dict", data)) - Ok(dict) -> - dict.fold(dict, #(dict.new(), []), fn(a, k, v) { - // If there are any errors from previous key-value pairs then we - // don't need to run the decoders, instead return the existing acc. - case a.1 { - [] -> fold_dict(a, k, v, key.function, value.function) - [_, ..] -> a - } - }) - } - }) -} - -fn fold_dict( - acc: #(Dict(k, v), List(DecodeError)), - key: Dynamic, - value: Dynamic, - key_decoder: fn(Dynamic) -> #(k, List(DecodeError)), - value_decoder: fn(Dynamic) -> #(v, List(DecodeError)), -) -> #(Dict(k, v), List(DecodeError)) { - // First we decode the key. - case key_decoder(key) { - #(key, []) -> - // Then we decode the value. - case value_decoder(value) { - #(value, []) -> { - // It worked! Insert the new key-value pair so we can move onto the next. - let dict = dict.insert(acc.0, key, value) - #(dict, acc.1) - } - #(_, errors) -> push_path(#(dict.new(), errors), ["values"]) - } - #(_, errors) -> push_path(#(dict.new(), errors), ["keys"]) - } -} - -@external(erlang, "gleam_stdlib", "dict") -@external(javascript, "../../gleam_stdlib.mjs", "dict") -fn decode_dict(data: Dynamic) -> Result(Dict(Dynamic, Dynamic), Nil) - -/// 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) -/// ``` -/// -pub fn optional(inner: Decoder(a)) -> Decoder(Option(a)) { - Decoder(function: fn(data) { - case is_null(data) { - True -> #(option.None, []) - False -> { - let #(data, errors) = inner.function(data) - #(option.Some(data), errors) - } - } - }) -} - -/// 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") -/// ``` -/// -pub fn map(decoder: Decoder(a), transformer: fn(a) -> b) -> Decoder(b) { - Decoder(function: fn(d) { - let #(data, errors) = decoder.function(d) - #(transformer(data), errors) - }) -} - -/// Apply a transformation function to any errors returned by the decoder. -/// -pub fn map_errors( - decoder: Decoder(a), - transformer: fn(List(DecodeError)) -> List(DecodeError), -) -> Decoder(a) { - Decoder(function: fn(d) { - let #(data, errors) = decoder.function(d) - #(data, transformer(errors)) - }) -} - -/// 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", [])]) -/// ``` -/// -pub fn collapse_errors(decoder: Decoder(a), name: String) -> Decoder(a) { - Decoder(function: fn(dynamic_data) { - let #(data, errors) as layer = decoder.function(dynamic_data) - case errors { - [] -> layer - [_, ..] -> #(data, decode_error(name, dynamic_data)) - } - }) -} - -/// 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. -/// -pub fn then(decoder: Decoder(a), next: fn(a) -> Decoder(b)) -> Decoder(b) { - Decoder(function: fn(dynamic_data) { - let #(data, errors) = decoder.function(dynamic_data) - let decoder = next(data) - let #(data, _) as layer = decoder.function(dynamic_data) - case errors { - [] -> layer - [_, ..] -> #(data, errors) - } - }) -} - -/// 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") -/// ``` -/// -pub fn one_of( - first: Decoder(a), - or alternatives: List(Decoder(a)), -) -> Decoder(a) { - Decoder(function: fn(dynamic_data) { - let #(_, errors) as layer = first.function(dynamic_data) - case errors { - [] -> layer - [_, ..] -> run_decoders(dynamic_data, layer, alternatives) - } - }) -} - -fn run_decoders( - data: Dynamic, - failure: #(a, List(DecodeError)), - decoders: List(Decoder(a)), -) -> #(a, List(DecodeError)) { - case decoders { - [] -> failure - - [decoder, ..decoders] -> { - let #(_, errors) as layer = decoder.function(data) - case errors { - [] -> layer - [_, ..] -> run_decoders(data, failure, decoders) - } - } - } -} - -/// Define a decoder that always fails. The parameter for this function is the -/// name of the type that has failed to decode. -/// -pub fn failure(zero: a, expected: String) -> Decoder(a) { - Decoder(function: fn(d) { #(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) -/// } -/// }) -/// } -/// ``` -/// -pub fn new_primitive_decoder( - name: String, - decoding_function: fn(Dynamic) -> Result(t, t), -) -> Decoder(t) { - Decoder(function: fn(d) { - case decoding_function(d) { - Ok(t) -> #(t, []) - Error(zero) -> #(zero, [DecodeError(name, dynamic.classify(d), [])]) - } - }) -} - -/// 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), -/// ]) -/// } -/// ``` -/// -pub fn recursive(inner: fn() -> Decoder(a)) -> Decoder(a) { - Decoder(function: fn(data) { - let decoder = inner() - decoder.function(data) - }) -} - -@external(erlang, "gleam_stdlib", "identity") -@external(javascript, "../../gleam_stdlib.mjs", "identity") -fn cast(a: anything) -> Dynamic - -@external(erlang, "gleam_stdlib", "is_null") -@external(javascript, "../../gleam_stdlib.mjs", "is_null") -fn is_null(a: Dynamic) -> Bool diff --git a/build/packages/gleam_stdlib/src/gleam/float.gleam b/build/packages/gleam_stdlib/src/gleam/float.gleam deleted file mode 100644 index 83bfa6e..0000000 --- a/build/packages/gleam_stdlib/src/gleam/float.gleam +++ /dev/null @@ -1,661 +0,0 @@ -//// Functions for working with floats. -//// -//// ## Float representation -//// -//// Floats are represented as 64 bit floating point numbers on both the Erlang -//// and JavaScript runtimes. The floating point behaviour is native to their -//// respective runtimes, so their exact behaviour will be slightly different on -//// the two runtimes. -//// -//// ### Infinity and NaN -//// -//// Under the JavaScript runtime, exceeding the maximum (or minimum) -//// representable value for a floating point value will result in Infinity (or -//// -Infinity). Should you try to divide two infinities you will get NaN as a -//// result. -//// -//// When running on BEAM, exceeding the maximum (or minimum) representable -//// value for a floating point value will raise an error. -//// -//// ## Division by zero -//// -//// Gleam runs on the Erlang virtual machine, which does not follow the IEEE -//// 754 standard for floating point arithmetic and does not have an `Infinity` -//// value. In Erlang division by zero results in a crash, however Gleam does -//// not have partial functions and operators in core so instead division by zero -//// returns zero, a behaviour taken from Pony, Coq, and Lean. -//// -//// This may seem unexpected at first, but it is no less mathematically valid -//// than crashing or returning a special value. Division by zero is undefined -//// in mathematics. - -import gleam/order.{type Order} - -/// Attempts to parse a string as a `Float`, returning `Error(Nil)` if it was -/// not possible. -/// -/// ## Examples -/// -/// ```gleam -/// parse("2.3") -/// // -> Ok(2.3) -/// ``` -/// -/// ```gleam -/// parse("ABC") -/// // -> Error(Nil) -/// ``` -/// -@external(erlang, "gleam_stdlib", "parse_float") -@external(javascript, "../gleam_stdlib.mjs", "parse_float") -pub fn parse(string: String) -> Result(Float, Nil) - -/// Returns the string representation of the provided `Float`. -/// -/// ## Examples -/// -/// ```gleam -/// to_string(2.3) -/// // -> "2.3" -/// ``` -/// -@external(erlang, "gleam_stdlib", "float_to_string") -@external(javascript, "../gleam_stdlib.mjs", "float_to_string") -pub fn to_string(x: Float) -> String - -/// Restricts a `Float` between a lower and upper bound. -/// -/// ## Examples -/// -/// ```gleam -/// clamp(1.2, min: 1.4, max: 1.6) -/// // -> 1.4 -/// ``` -/// -pub fn clamp(x: Float, min min_bound: Float, max max_bound: Float) -> Float { - x - |> min(max_bound) - |> max(min_bound) -} - -/// 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. -/// -pub fn compare(a: Float, with b: Float) -> Order { - case a == b { - True -> order.Eq - False -> - case a <. b { - True -> order.Lt - False -> order.Gt - } - } -} - -/// 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. -/// -pub fn loosely_compare( - a: Float, - with b: Float, - tolerating tolerance: Float, -) -> Order { - let difference = absolute_value(a -. b) - case difference <=. tolerance { - True -> order.Eq - False -> 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 -/// ``` -/// -pub fn loosely_equals( - a: Float, - with b: Float, - tolerating tolerance: Float, -) -> Bool { - let difference = absolute_value(a -. b) - difference <=. tolerance -} - -/// Compares two `Float`s, returning the smaller of the two. -/// -/// ## Examples -/// -/// ```gleam -/// min(2.0, 2.3) -/// // -> 2.0 -/// ``` -/// -pub fn min(a: Float, b: Float) -> Float { - case a <. b { - True -> a - False -> b - } -} - -/// Compares two `Float`s, returning the larger of the two. -/// -/// ## Examples -/// -/// ```gleam -/// max(2.0, 2.3) -/// // -> 2.3 -/// ``` -/// -pub fn max(a: Float, b: Float) -> Float { - case a >. b { - True -> a - False -> b - } -} - -/// Rounds the value to the next highest whole number as a `Float`. -/// -/// ## Examples -/// -/// ```gleam -/// ceiling(2.3) -/// // -> 3.0 -/// ``` -/// -@external(erlang, "math", "ceil") -@external(javascript, "../gleam_stdlib.mjs", "ceiling") -pub fn ceiling(x: Float) -> Float - -/// Rounds the value to the next lowest whole number as a `Float`. -/// -/// ## Examples -/// -/// ```gleam -/// floor(2.3) -/// // -> 2.0 -/// ``` -/// -@external(erlang, "math", "floor") -@external(javascript, "../gleam_stdlib.mjs", "floor") -pub fn floor(x: Float) -> Float - -/// Rounds the value to the nearest whole number as an `Int`. -/// -/// ## Examples -/// -/// ```gleam -/// round(2.3) -/// // -> 2 -/// ``` -/// -/// ```gleam -/// round(2.5) -/// // -> 3 -/// ``` -/// -@external(erlang, "erlang", "round") -pub fn round(x: Float) -> Int { - case x >=. 0.0 { - True -> js_round(x) - False -> 0 - js_round(negate(x)) - } -} - -@external(javascript, "../gleam_stdlib.mjs", "round") -fn js_round(a: Float) -> Int - -/// Returns the value as an `Int`, truncating all decimal digits. -/// -/// ## Examples -/// -/// ```gleam -/// truncate(2.4343434847383438) -/// // -> 2 -/// ``` -/// -@external(erlang, "erlang", "trunc") -@external(javascript, "../gleam_stdlib.mjs", "truncate") -pub fn truncate(x: Float) -> Int - -/// 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 -/// ``` -/// -pub fn to_precision(x: Float, precision: Int) -> Float { - case precision <= 0 { - True -> { - let factor = do_power(10.0, do_to_float(-precision)) - do_to_float(round(x /. factor)) *. factor - } - False -> { - let factor = do_power(10.0, do_to_float(precision)) - do_to_float(round(x *. factor)) /. factor - } - } -} - -@external(erlang, "erlang", "float") -@external(javascript, "../gleam_stdlib.mjs", "identity") -fn do_to_float(a: Int) -> Float - -/// 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 -/// ``` -/// -pub fn absolute_value(x: Float) -> Float { - case x >=. 0.0 { - True -> x - False -> 0.0 -. x - } -} - -/// 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) -/// ``` -/// -pub fn power(base: Float, of exponent: Float) -> Result(Float, Nil) { - let fractional: Bool = ceiling(exponent) -. exponent >. 0.0 - // In the following check: - // 1. If the base is negative and the exponent is fractional then - // return an error as it will otherwise be an imaginary number - // 2. If the base is 0 and the exponent is negative then the expression - // is equivalent to the exponent divided by 0 and an error should be - // returned - case base <. 0.0 && fractional || base == 0.0 && exponent <. 0.0 { - True -> Error(Nil) - False -> Ok(do_power(base, exponent)) - } -} - -@external(erlang, "math", "pow") -@external(javascript, "../gleam_stdlib.mjs", "power") -fn do_power(a: Float, b: Float) -> Float - -/// 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) -/// ``` -/// -pub fn square_root(x: Float) -> Result(Float, Nil) { - power(x, 0.5) -} - -/// Returns the negative of the value provided. -/// -/// ## Examples -/// -/// ```gleam -/// negate(1.0) -/// // -> -1.0 -/// ``` -/// -pub fn negate(x: Float) -> Float { - -1.0 *. x -} - -/// Sums a list of `Float`s. -/// -/// ## Example -/// -/// ```gleam -/// sum([1.0, 2.2, 3.3]) -/// // -> 6.5 -/// ``` -/// -pub fn sum(numbers: List(Float)) -> Float { - sum_loop(numbers, 0.0) -} - -fn sum_loop(numbers: List(Float), initial: Float) -> Float { - case numbers { - [first, ..rest] -> sum_loop(rest, first +. initial) - [] -> initial - } -} - -/// Multiplies a list of `Float`s and returns the product. -/// -/// ## Example -/// -/// ```gleam -/// product([2.5, 3.2, 4.2]) -/// // -> 33.6 -/// ``` -/// -pub fn product(numbers: List(Float)) -> Float { - product_loop(numbers, 1.0) -} - -fn product_loop(numbers: List(Float), initial: Float) -> Float { - case numbers { - [first, ..rest] -> product_loop(rest, first *. initial) - [] -> initial - } -} - -/// Generates a random float between the given zero (inclusive) and one -/// (exclusive). -/// -/// On Erlang this updates the random state in the process dictionary. -/// See: -/// -/// ## Examples -/// -/// ```gleam -/// random() -/// // -> 0.646355926896028 -/// ``` -/// -@external(erlang, "rand", "uniform") -@external(javascript, "../gleam_stdlib.mjs", "random_uniform") -pub fn random() -> Float - -/// 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) -/// ``` -/// -pub fn modulo(dividend: Float, by divisor: Float) -> Result(Float, Nil) { - case divisor { - 0.0 -> Error(Nil) - _ -> Ok(dividend -. floor(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) -/// ``` -/// -pub fn divide(a: Float, by b: Float) -> Result(Float, Nil) { - case b { - 0.0 -> Error(Nil) - b -> Ok(a /. b) - } -} - -/// 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 -/// ``` -/// -pub fn add(a: Float, b: Float) -> Float { - 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 -/// ``` -/// -pub fn multiply(a: Float, b: Float) -> Float { - 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 -/// ``` -/// -pub fn subtract(a: Float, b: Float) -> Float { - 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) -/// ``` -/// -pub fn logarithm(x: Float) -> Result(Float, Nil) { - // In the following check: - // 1. If x is negative then return an error as the natural logarithm - // of a negative number is undefined (would be a complex number) - // 2. If x is 0 then return an error as the natural logarithm of 0 - // approaches negative infinity - case x <=. 0.0 { - True -> Error(Nil) - False -> Ok(do_log(x)) - } -} - -@external(erlang, "math", "log") -@external(javascript, "../gleam_stdlib.mjs", "log") -fn do_log(x: Float) -> Float - -/// Returns e (Euler's number) raised to the power of the given exponent, as -/// a `Float`. -/// -/// ## Examples -/// -/// ```gleam -/// exponential(0.0) -/// // -> Ok(1.0) -/// ``` -/// -/// ```gleam -/// exponential(1.0) -/// // -> Ok(2.718281828459045) -/// ``` -/// -/// ```gleam -/// exponential(-1.0) -/// // -> Ok(0.36787944117144233) -/// ``` -/// -@external(erlang, "math", "exp") -@external(javascript, "../gleam_stdlib.mjs", "exp") -pub fn exponential(x: Float) -> Float diff --git a/build/packages/gleam_stdlib/src/gleam/function.gleam b/build/packages/gleam_stdlib/src/gleam/function.gleam deleted file mode 100644 index 6ae3a62..0000000 --- a/build/packages/gleam_stdlib/src/gleam/function.gleam +++ /dev/null @@ -1,15 +0,0 @@ -/// Takes a single argument and always returns its input value. -/// -pub fn identity(x: a) -> a { - 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. -/// -pub fn tap(arg: a, effect: fn(a) -> b) -> a { - effect(arg) - arg -} diff --git a/build/packages/gleam_stdlib/src/gleam/int.gleam b/build/packages/gleam_stdlib/src/gleam/int.gleam deleted file mode 100644 index fa8aaef..0000000 --- a/build/packages/gleam_stdlib/src/gleam/int.gleam +++ /dev/null @@ -1,828 +0,0 @@ -//// Functions for working with integers. -//// -//// ## Division by zero -//// -//// In Erlang division by zero results in a crash, however Gleam does not have -//// partial functions and operators in core so instead division by zero returns -//// zero, a behaviour taken from Pony, Coq, and Lean. -//// -//// This may seem unexpected at first, but it is no less mathematically valid -//// than crashing or returning a special value. Division by zero is undefined -//// in mathematics. - -import gleam/float -import gleam/order.{type Order} - -/// Returns the absolute value of the input. -/// -/// ## Examples -/// -/// ```gleam -/// absolute_value(-12) -/// // -> 12 -/// ``` -/// -/// ```gleam -/// absolute_value(10) -/// // -> 10 -/// ``` -/// -pub fn absolute_value(x: Int) -> Int { - case x >= 0 { - True -> x - False -> x * -1 - } -} - -/// 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) -/// ``` -/// -pub fn power(base: Int, of exponent: Float) -> Result(Float, Nil) { - base - |> to_float - |> float.power(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) -/// ``` -/// -pub fn square_root(x: Int) -> Result(Float, Nil) { - x - |> to_float - |> float.square_root() -} - -/// Parses a given string as an int if possible. -/// -/// ## Examples -/// -/// ```gleam -/// parse("2") -/// // -> Ok(2) -/// ``` -/// -/// ```gleam -/// parse("ABC") -/// // -> Error(Nil) -/// ``` -/// -@external(erlang, "gleam_stdlib", "parse_int") -@external(javascript, "../gleam_stdlib.mjs", "parse_int") -pub fn parse(string: String) -> Result(Int, Nil) - -/// 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) -/// ``` -/// -pub fn base_parse(string: String, base: Int) -> Result(Int, Nil) { - case base >= 2 && base <= 36 { - True -> do_base_parse(string, base) - False -> Error(Nil) - } -} - -@external(erlang, "gleam_stdlib", "int_from_base_string") -@external(javascript, "../gleam_stdlib.mjs", "int_from_base_string") -fn do_base_parse(a: String, b: Int) -> Result(Int, Nil) - -/// Prints a given int to a string. -/// -/// ## Examples -/// -/// ```gleam -/// to_string(2) -/// // -> "2" -/// ``` -/// -@external(erlang, "erlang", "integer_to_binary") -@external(javascript, "../gleam_stdlib.mjs", "to_string") -pub fn to_string(x: Int) -> String - -/// 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) -/// ``` -/// -pub fn to_base_string(x: Int, base: Int) -> Result(String, Nil) { - case base >= 2 && base <= 36 { - True -> Ok(do_to_base_string(x, base)) - False -> Error(Nil) - } -} - -@external(erlang, "erlang", "integer_to_binary") -@external(javascript, "../gleam_stdlib.mjs", "int_to_base_string") -fn do_to_base_string(a: Int, b: Int) -> String - -/// Prints a given int to a string using base-2. -/// -/// ## Examples -/// -/// ```gleam -/// to_base2(2) -/// // -> "10" -/// ``` -/// -pub fn to_base2(x: Int) -> String { - do_to_base_string(x, 2) -} - -/// Prints a given int to a string using base-8. -/// -/// ## Examples -/// -/// ```gleam -/// to_base8(15) -/// // -> "17" -/// ``` -/// -pub fn to_base8(x: Int) -> String { - do_to_base_string(x, 8) -} - -/// Prints a given int to a string using base-16. -/// -/// ## Examples -/// -/// ```gleam -/// to_base16(48) -/// // -> "30" -/// ``` -/// -pub fn to_base16(x: Int) -> String { - do_to_base_string(x, 16) -} - -/// Prints a given int to a string using base-36. -/// -/// ## Examples -/// -/// ```gleam -/// to_base36(48) -/// // -> "1C" -/// ``` -/// -pub fn to_base36(x: Int) -> String { - do_to_base_string(x, 36) -} - -/// Takes an int and returns its value as a float. -/// -/// ## Examples -/// -/// ```gleam -/// to_float(5) -/// // -> 5.0 -/// ``` -/// -/// ```gleam -/// to_float(0) -/// // -> 0.0 -/// ``` -/// -/// ```gleam -/// to_float(-3) -/// // -> -3.0 -/// ``` -/// -@external(erlang, "erlang", "float") -@external(javascript, "../gleam_stdlib.mjs", "identity") -pub fn to_float(x: Int) -> Float - -/// Restricts an int between a lower and upper bound. -/// -/// ## Examples -/// -/// ```gleam -/// clamp(40, min: 50, max: 60) -/// // -> 50 -/// ``` -/// -pub fn clamp(x: Int, min min_bound: Int, max max_bound: Int) -> Int { - x - |> min(max_bound) - |> max(min_bound) -} - -/// Compares two ints, returning an order. -/// -/// ## Examples -/// -/// ```gleam -/// compare(2, 3) -/// // -> Lt -/// ``` -/// -/// ```gleam -/// compare(4, 3) -/// // -> Gt -/// ``` -/// -/// ```gleam -/// compare(3, 3) -/// // -> Eq -/// ``` -/// -pub fn compare(a: Int, with b: Int) -> Order { - case a == b { - True -> order.Eq - False -> - case a < b { - True -> order.Lt - False -> order.Gt - } - } -} - -/// Compares two ints, returning the smaller of the two. -/// -/// ## Examples -/// -/// ```gleam -/// min(2, 3) -/// // -> 2 -/// ``` -/// -pub fn min(a: Int, b: Int) -> Int { - case a < b { - True -> a - False -> b - } -} - -/// Compares two ints, returning the larger of the two. -/// -/// ## Examples -/// -/// ```gleam -/// max(2, 3) -/// // -> 3 -/// ``` -/// -pub fn max(a: Int, b: Int) -> Int { - case a > b { - True -> a - False -> b - } -} - -/// Returns whether the value provided is even. -/// -/// ## Examples -/// -/// ```gleam -/// is_even(2) -/// // -> True -/// ``` -/// -/// ```gleam -/// is_even(3) -/// // -> False -/// ``` -/// -pub fn is_even(x: Int) -> Bool { - x % 2 == 0 -} - -/// Returns whether the value provided is odd. -/// -/// ## Examples -/// -/// ```gleam -/// is_odd(3) -/// // -> True -/// ``` -/// -/// ```gleam -/// is_odd(2) -/// // -> False -/// ``` -/// -pub fn is_odd(x: Int) -> Bool { - x % 2 != 0 -} - -/// Returns the negative of the value provided. -/// -/// ## Examples -/// -/// ```gleam -/// negate(1) -/// // -> -1 -/// ``` -/// -pub fn negate(x: Int) -> Int { - -1 * x -} - -/// Sums a list of ints. -/// -/// ## Example -/// -/// ```gleam -/// sum([1, 2, 3]) -/// // -> 6 -/// ``` -/// -pub fn sum(numbers: List(Int)) -> Int { - sum_loop(numbers, 0) -} - -fn sum_loop(numbers: List(Int), initial: Int) -> Int { - case numbers { - [first, ..rest] -> sum_loop(rest, first + initial) - [] -> initial - } -} - -/// Multiplies a list of ints and returns the product. -/// -/// ## Example -/// -/// ```gleam -/// product([2, 3, 4]) -/// // -> 24 -/// ``` -/// -pub fn product(numbers: List(Int)) -> Int { - product_loop(numbers, 1) -} - -fn product_loop(numbers: List(Int), initial: Int) -> Int { - case numbers { - [first, ..rest] -> product_loop(rest, first * initial) - [] -> initial - } -} - -@deprecated("Vendor this function into your codebase") -pub fn digits(x: Int, base: Int) -> Result(List(Int), Nil) { - case base < 2 { - True -> Error(Nil) - False -> Ok(digits_loop(x, base, [])) - } -} - -fn digits_loop(x: Int, base: Int, acc: List(Int)) -> List(Int) { - case absolute_value(x) < base { - True -> [x, ..acc] - False -> digits_loop(x / base, base, [x % base, ..acc]) - } -} - -@deprecated("Vendor this function into your codebase") -pub fn undigits(numbers: List(Int), base: Int) -> Result(Int, Nil) { - case base < 2 { - True -> Error(Nil) - False -> undigits_loop(numbers, base, 0) - } -} - -fn undigits_loop(numbers: List(Int), base: Int, acc: Int) -> Result(Int, Nil) { - case numbers { - [] -> Ok(acc) - [digit, ..] if digit >= base -> Error(Nil) - [digit, ..rest] -> undigits_loop(rest, base, acc * base + digit) - } -} - -/// 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 -/// ``` -/// -pub fn random(max: Int) -> Int { - { float.random() *. to_float(max) } - |> float.floor - |> float.round -} - -/// 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) -/// ``` -/// -pub fn divide(dividend: Int, by divisor: Int) -> Result(Int, Nil) { - case divisor { - 0 -> Error(Nil) - divisor -> Ok(dividend / divisor) - } -} - -/// 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) -/// ``` -/// -pub fn remainder(dividend: Int, by divisor: Int) -> Result(Int, Nil) { - case divisor { - 0 -> Error(Nil) - divisor -> Ok(dividend % divisor) - } -} - -/// 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) -/// ``` -/// -pub fn modulo(dividend: Int, by divisor: Int) -> Result(Int, Nil) { - case divisor { - 0 -> Error(Nil) - _ -> { - let remainder = dividend % divisor - case remainder * divisor < 0 { - True -> Ok(remainder + divisor) - False -> Ok(remainder) - } - } - } -} - -/// 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) -/// ``` -/// -pub fn floor_divide(dividend: Int, by divisor: Int) -> Result(Int, Nil) { - case divisor { - 0 -> Error(Nil) - divisor -> - case dividend * divisor < 0 && dividend % divisor != 0 { - True -> Ok(dividend / divisor - 1) - False -> Ok(dividend / divisor) - } - } -} - -/// 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 -/// ``` -/// -pub fn add(a: Int, b: Int) -> Int { - 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 -/// ``` -/// -pub fn multiply(a: Int, b: Int) -> Int { - 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 -/// ``` -/// -pub fn subtract(a: Int, b: Int) -> Int { - a - b -} - -/// Calculates the bitwise AND of its arguments. -/// -/// The exact behaviour of this function depends on the target platform. -/// On Erlang it is equivalent to bitwise operations on ints, on JavaScript it -/// is equivalent to bitwise operations on big-ints. -/// -@external(erlang, "erlang", "band") -@external(javascript, "../gleam_stdlib.mjs", "bitwise_and") -pub fn bitwise_and(x: Int, y: Int) -> Int - -/// Calculates the bitwise NOT of its argument. -/// -/// The exact behaviour of this function depends on the target platform. -/// On Erlang it is equivalent to bitwise operations on ints, on JavaScript it -/// is equivalent to bitwise operations on big-ints. -/// -@external(erlang, "erlang", "bnot") -@external(javascript, "../gleam_stdlib.mjs", "bitwise_not") -pub fn bitwise_not(x: Int) -> Int - -/// Calculates the bitwise OR of its arguments. -/// -/// The exact behaviour of this function depends on the target platform. -/// On Erlang it is equivalent to bitwise operations on ints, on JavaScript it -/// is equivalent to bitwise operations on big-ints. -/// -@external(erlang, "erlang", "bor") -@external(javascript, "../gleam_stdlib.mjs", "bitwise_or") -pub fn bitwise_or(x: Int, y: Int) -> Int - -/// Calculates the bitwise XOR of its arguments. -/// -/// The exact behaviour of this function depends on the target platform. -/// On Erlang it is equivalent to bitwise operations on ints, on JavaScript it -/// is equivalent to bitwise operations on big-ints. -/// -@external(erlang, "erlang", "bxor") -@external(javascript, "../gleam_stdlib.mjs", "bitwise_exclusive_or") -pub fn bitwise_exclusive_or(x: Int, y: Int) -> Int - -/// Calculates the result of an arithmetic left bitshift. -/// -/// The exact behaviour of this function depends on the target platform. -/// On Erlang it is equivalent to bitwise operations on ints, on JavaScript it -/// is equivalent to bitwise operations on big-ints. -/// -@external(erlang, "erlang", "bsl") -@external(javascript, "../gleam_stdlib.mjs", "bitwise_shift_left") -pub fn bitwise_shift_left(x: Int, y: Int) -> Int - -/// Calculates the result of an arithmetic right bitshift. -/// -/// The exact behaviour of this function depends on the target platform. -/// On Erlang it is equivalent to bitwise operations on ints, on JavaScript it -/// is equivalent to bitwise operations on big-ints. -/// -@external(erlang, "erlang", "bsr") -@external(javascript, "../gleam_stdlib.mjs", "bitwise_shift_right") -pub fn bitwise_shift_right(x: Int, y: Int) -> Int diff --git a/build/packages/gleam_stdlib/src/gleam/io.gleam b/build/packages/gleam_stdlib/src/gleam/io.gleam deleted file mode 100644 index 67088eb..0000000 --- a/build/packages/gleam_stdlib/src/gleam/io.gleam +++ /dev/null @@ -1,59 +0,0 @@ -/// Writes a string to standard output (stdout). -/// -/// If you want your output to be printed on its own line see `println`. -/// -/// ## Example -/// -/// ```gleam -/// io.print("Hi mum") -/// // -> Nil -/// // Hi mum -/// ``` -/// -@external(erlang, "gleam_stdlib", "print") -@external(javascript, "../gleam_stdlib.mjs", "print") -pub fn print(string: String) -> Nil - -/// Writes a string to standard error (stderr). -/// -/// If you want your output to be printed on its own line see `println_error`. -/// -/// ## Example -/// -/// ``` -/// io.print_error("Hi pop") -/// // -> Nil -/// // Hi pop -/// ``` -/// -@external(erlang, "gleam_stdlib", "print_error") -@external(javascript, "../gleam_stdlib.mjs", "print_error") -pub fn print_error(string: String) -> Nil - -/// Writes a string to standard output (stdout), appending a newline to the end. -/// -/// ## Example -/// -/// ```gleam -/// io.println("Hi mum") -/// // -> Nil -/// // Hi mum -/// ``` -/// -@external(erlang, "gleam_stdlib", "println") -@external(javascript, "../gleam_stdlib.mjs", "console_log") -pub fn println(string: String) -> Nil - -/// Writes a string to standard error (stderr), appending a newline to the end. -/// -/// ## Example -/// -/// ```gleam -/// io.println_error("Hi pop") -/// // -> Nil -/// // Hi pop -/// ``` -/// -@external(erlang, "gleam_stdlib", "println_error") -@external(javascript, "../gleam_stdlib.mjs", "console_error") -pub fn println_error(string: String) -> Nil diff --git a/build/packages/gleam_stdlib/src/gleam/list.gleam b/build/packages/gleam_stdlib/src/gleam/list.gleam deleted file mode 100644 index 6373efb..0000000 --- a/build/packages/gleam_stdlib/src/gleam/list.gleam +++ /dev/null @@ -1,2426 +0,0 @@ -//// Lists are an ordered sequence of elements and are one of the most common -//// data types in Gleam. -//// -//// New elements can be added and removed from the front of a list in -//// constant time, while adding and removing from the end requires traversing -//// and copying the whole list, so keep this in mind when designing your -//// programs. -//// -//// There is a dedicated syntax for prefixing to a list: -//// -//// ```gleam -//// let new_list = [1, 2, ..existing_list] -//// ``` -//// -//// And a matching syntax for getting the first elements of a list: -//// -//// ```gleam -//// case list { -//// [first_element, ..rest] -> first_element -//// _ -> "this pattern matches when the list is empty" -//// } -//// ``` -//// - -import gleam/dict.{type Dict} -import gleam/float -import gleam/int -import gleam/order.{type Order} - -/// Counts the number of elements in a given list. -/// -/// This function has to traverse the list to determine the number of elements, -/// so it runs in linear time. -/// -/// This function is natively implemented by the virtual machine and is highly -/// optimised. -/// -/// ## Examples -/// -/// ```gleam -/// length([]) -/// // -> 0 -/// ``` -/// -/// ```gleam -/// length([1]) -/// // -> 1 -/// ``` -/// -/// ```gleam -/// length([1, 2]) -/// // -> 2 -/// ``` -/// -@external(erlang, "erlang", "length") -pub fn length(of list: List(a)) -> Int { - length_loop(list, 0) -} - -fn length_loop(list: List(a), count: Int) -> Int { - case list { - [_, ..list] -> length_loop(list, count + 1) - [] -> count - } -} - -/// Counts the number of elements in a given list satisfying a given predicate. -/// -/// This function has to traverse the list to determine the number of elements, -/// so it runs in linear time. -/// -/// ## Examples -/// -/// ```gleam -/// count([], fn(a) { a > 0 }) -/// // -> 0 -/// ``` -/// -/// ```gleam -/// count([1], fn(a) { a > 0 }) -/// // -> 1 -/// ``` -/// -/// ```gleam -/// count([1, 2, 3], int.is_odd) -/// // -> 2 -/// ``` -/// -pub fn count(list: List(a), where predicate: fn(a) -> Bool) -> Int { - count_loop(list, predicate, 0) -} - -fn count_loop(list: List(a), predicate: fn(a) -> Bool, acc: Int) -> Int { - case list { - [] -> acc - [first, ..rest] -> - case predicate(first) { - True -> count_loop(rest, predicate, acc + 1) - False -> count_loop(rest, predicate, acc) - } - } -} - -/// Creates a new list from a given list containing the same elements but in the -/// opposite order. -/// -/// This function has to traverse the list to create the new reversed list, so -/// it runs in linear time. -/// -/// This function is natively implemented by the virtual machine and is highly -/// optimised. -/// -/// ## Examples -/// -/// ```gleam -/// reverse([]) -/// // -> [] -/// ``` -/// -/// ```gleam -/// reverse([1]) -/// // -> [1] -/// ``` -/// -/// ```gleam -/// reverse([1, 2]) -/// // -> [2, 1] -/// ``` -/// -@external(erlang, "lists", "reverse") -pub fn reverse(list: List(a)) -> List(a) { - reverse_and_prepend(list, []) -} - -/// Reverses a list and prepends it to another list. -/// This function runs in linear time, proportional to the length of the list -/// to prepend. -/// -@external(erlang, "lists", "reverse") -fn reverse_and_prepend(list prefix: List(a), to suffix: List(a)) -> List(a) { - case prefix { - [] -> suffix - [first, ..rest] -> reverse_and_prepend(list: rest, to: [first, ..suffix]) - } -} - -/// Determines whether or not the list is empty. -/// -/// This function runs in constant time. -/// -/// ## Examples -/// -/// ```gleam -/// is_empty([]) -/// // -> True -/// ``` -/// -/// ```gleam -/// is_empty([1]) -/// // -> False -/// ``` -/// -/// ```gleam -/// is_empty([1, 1]) -/// // -> False -/// ``` -/// -pub fn is_empty(list: List(a)) -> Bool { - list == [] -} - -/// Determines whether or not a given element exists within a given list. -/// -/// This function traverses the list to find the element, so it runs in linear -/// time. -/// -/// ## Examples -/// -/// ```gleam -/// [] |> contains(any: 0) -/// // -> False -/// ``` -/// -/// ```gleam -/// [0] |> contains(any: 0) -/// // -> True -/// ``` -/// -/// ```gleam -/// [1] |> contains(any: 0) -/// // -> False -/// ``` -/// -/// ```gleam -/// [1, 1] |> contains(any: 0) -/// // -> False -/// ``` -/// -/// ```gleam -/// [1, 0] |> contains(any: 0) -/// // -> True -/// ``` -/// -pub fn contains(list: List(a), any elem: a) -> Bool { - case list { - [] -> False - [first, ..] if first == elem -> True - [_, ..rest] -> contains(rest, elem) - } -} - -/// Gets the first element from the start of the list, if there is one. -/// -/// ## Examples -/// -/// ```gleam -/// first([]) -/// // -> Error(Nil) -/// ``` -/// -/// ```gleam -/// first([0]) -/// // -> Ok(0) -/// ``` -/// -/// ```gleam -/// first([1, 2]) -/// // -> Ok(1) -/// ``` -/// -pub fn first(list: List(a)) -> Result(a, Nil) { - case list { - [] -> Error(Nil) - [first, ..] -> Ok(first) - } -} - -/// Returns the list minus the first element. If the list is empty, `Error(Nil)` is -/// returned. -/// -/// This function runs in constant time and does not make a copy of the list. -/// -/// ## Examples -/// -/// ```gleam -/// rest([]) -/// // -> Error(Nil) -/// ``` -/// -/// ```gleam -/// rest([0]) -/// // -> Ok([]) -/// ``` -/// -/// ```gleam -/// rest([1, 2]) -/// // -> Ok([2]) -/// ``` -/// -pub fn rest(list: List(a)) -> Result(List(a), Nil) { - case list { - [] -> Error(Nil) - [_, ..rest] -> Ok(rest) - } -} - -/// Groups the elements from the given list by the given key function. -/// -/// Does not preserve the initial value order. -/// -/// ## Examples -/// -/// ```gleam -/// import gleam/dict -/// -/// [Ok(3), Error("Wrong"), Ok(200), Ok(73)] -/// |> group(by: fn(i) { -/// case i { -/// Ok(_) -> "Successful" -/// Error(_) -> "Failed" -/// } -/// }) -/// |> dict.to_list -/// // -> [ -/// // #("Failed", [Error("Wrong")]), -/// // #("Successful", [Ok(73), Ok(200), Ok(3)]) -/// // ] -/// ``` -/// -/// ```gleam -/// import gleam/dict -/// -/// group([1,2,3,4,5], by: fn(i) { i - i / 3 * 3 }) -/// |> dict.to_list -/// // -> [#(0, [3]), #(1, [4, 1]), #(2, [5, 2])] -/// ``` -/// -pub fn group(list: List(v), by key: fn(v) -> k) -> Dict(k, List(v)) { - group_loop(list, key, dict.new()) -} - -fn group_loop( - list: List(v), - to_key: fn(v) -> k, - groups: Dict(k, List(v)), -) -> Dict(k, List(v)) { - case list { - [] -> groups - [first, ..rest] -> { - let key = to_key(first) - let groups = case dict.get(groups, key) { - Error(_) -> dict.insert(groups, key, [first]) - Ok(existing) -> dict.insert(groups, key, [first, ..existing]) - } - group_loop(rest, to_key, groups) - } - } -} - -/// Returns a new list containing only the elements from the first list for -/// which the given functions returns `True`. -/// -/// ## Examples -/// -/// ```gleam -/// filter([2, 4, 6, 1], fn(x) { x > 2 }) -/// // -> [4, 6] -/// ``` -/// -/// ```gleam -/// filter([2, 4, 6, 1], fn(x) { x > 6 }) -/// // -> [] -/// ``` -/// -pub fn filter(list: List(a), keeping predicate: fn(a) -> Bool) -> List(a) { - filter_loop(list, predicate, []) -} - -fn filter_loop(list: List(a), fun: fn(a) -> Bool, acc: List(a)) -> List(a) { - case list { - [] -> reverse(acc) - [first, ..rest] -> { - let new_acc = case fun(first) { - True -> [first, ..acc] - False -> acc - } - filter_loop(rest, fun, new_acc) - } - } -} - -/// Returns a new list containing only the elements from the first list for -/// which the given functions returns `Ok(_)`. -/// -/// ## Examples -/// -/// ```gleam -/// filter_map([2, 4, 6, 1], Error) -/// // -> [] -/// ``` -/// -/// ```gleam -/// filter_map([2, 4, 6, 1], fn(x) { Ok(x + 1) }) -/// // -> [3, 5, 7, 2] -/// ``` -/// -pub fn filter_map(list: List(a), with fun: fn(a) -> Result(b, e)) -> List(b) { - filter_map_loop(list, fun, []) -} - -fn filter_map_loop( - list: List(a), - fun: fn(a) -> Result(b, e), - acc: List(b), -) -> List(b) { - case list { - [] -> reverse(acc) - [first, ..rest] -> { - let new_acc = case fun(first) { - Ok(first) -> [first, ..acc] - Error(_) -> acc - } - filter_map_loop(rest, fun, new_acc) - } - } -} - -/// Returns a new list containing only the elements of the first list after the -/// function has been applied to each one. -/// -/// ## Examples -/// -/// ```gleam -/// map([2, 4, 6], fn(x) { x * 2 }) -/// // -> [4, 8, 12] -/// ``` -/// -pub fn map(list: List(a), with fun: fn(a) -> b) -> List(b) { - map_loop(list, fun, []) -} - -fn map_loop(list: List(a), fun: fn(a) -> b, acc: List(b)) -> List(b) { - case list { - [] -> reverse(acc) - [first, ..rest] -> map_loop(rest, fun, [fun(first), ..acc]) - } -} - -/// Combines two lists into a single list using the given function. -/// -/// If a list is longer than the other the extra elements are dropped. -/// -/// ## Examples -/// -/// ```gleam -/// map2([1, 2, 3], [4, 5, 6], fn(x, y) { x + y }) -/// // -> [5, 7, 9] -/// ``` -/// -/// ```gleam -/// map2([1, 2], ["a", "b", "c"], fn(i, x) { #(i, x) }) -/// // -> [#(1, "a"), #(2, "b")] -/// ``` -/// -pub fn map2(list1: List(a), list2: List(b), with fun: fn(a, b) -> c) -> List(c) { - map2_loop(list1, list2, fun, []) -} - -fn map2_loop( - list1: List(a), - list2: List(b), - fun: fn(a, b) -> c, - acc: List(c), -) -> List(c) { - case list1, list2 { - [], _ | _, [] -> reverse(acc) - [a, ..as_], [b, ..bs] -> map2_loop(as_, bs, fun, [fun(a, b), ..acc]) - } -} - -/// Similar to `map` but also lets you pass around an accumulated value. -/// -/// ## Examples -/// -/// ```gleam -/// map_fold( -/// over: [1, 2, 3], -/// from: 100, -/// with: fn(memo, i) { #(memo + i, i * 2) } -/// ) -/// // -> #(106, [2, 4, 6]) -/// ``` -/// -pub fn map_fold( - over list: List(a), - from initial: acc, - with fun: fn(acc, a) -> #(acc, b), -) -> #(acc, List(b)) { - map_fold_loop(list, fun, initial, []) -} - -fn map_fold_loop( - list: List(a), - fun: fn(acc, a) -> #(acc, b), - acc: acc, - list_acc: List(b), -) -> #(acc, List(b)) { - case list { - [] -> #(acc, reverse(list_acc)) - [first, ..rest] -> { - let #(acc, first) = fun(acc, first) - map_fold_loop(rest, fun, acc, [first, ..list_acc]) - } - } -} - -/// Returns a new list containing only the elements of the first list after the -/// function has been applied to each one and their index. -/// -/// The index starts at 0, so the first element is 0, the second is 1, and so -/// on. -/// -/// ## Examples -/// -/// ```gleam -/// index_map(["a", "b"], fn(x, i) { #(i, x) }) -/// // -> [#(0, "a"), #(1, "b")] -/// ``` -/// -pub fn index_map(list: List(a), with fun: fn(a, Int) -> b) -> List(b) { - index_map_loop(list, fun, 0, []) -} - -fn index_map_loop( - list: List(a), - fun: fn(a, Int) -> b, - index: Int, - acc: List(b), -) -> List(b) { - case list { - [] -> reverse(acc) - [first, ..rest] -> { - let acc = [fun(first, index), ..acc] - index_map_loop(rest, fun, index + 1, acc) - } - } -} - -/// Takes a function that returns a `Result` and applies it to each element in a -/// given list in turn. -/// -/// If the function returns `Ok(new_value)` for all elements in the list then a -/// list of the new values is returned. -/// -/// If the function returns `Error(reason)` for any of the elements then it is -/// returned immediately. None of the elements in the list are processed after -/// one returns an `Error`. -/// -/// ## Examples -/// -/// ```gleam -/// try_map([1, 2, 3], fn(x) { Ok(x + 2) }) -/// // -> Ok([3, 4, 5]) -/// ``` -/// -/// ```gleam -/// try_map([1, 2, 3], fn(_) { Error(0) }) -/// // -> Error(0) -/// ``` -/// -/// ```gleam -/// try_map([[1], [2, 3]], first) -/// // -> Ok([1, 2]) -/// ``` -/// -/// ```gleam -/// try_map([[1], [], [2]], first) -/// // -> Error(Nil) -/// ``` -/// -pub fn try_map( - over list: List(a), - with fun: fn(a) -> Result(b, e), -) -> Result(List(b), e) { - try_map_loop(list, fun, []) -} - -fn try_map_loop( - list: List(a), - fun: fn(a) -> Result(b, e), - acc: List(b), -) -> Result(List(b), e) { - case list { - [] -> Ok(reverse(acc)) - [first, ..rest] -> - case fun(first) { - Ok(first) -> try_map_loop(rest, fun, [first, ..acc]) - Error(error) -> Error(error) - } - } -} - -/// Returns a list that is the given list with up to the given number of -/// elements removed from the front of the list. -/// -/// If the element has less than the number of elements an empty list is -/// returned. -/// -/// This function runs in linear time but does not copy the list. -/// -/// ## Examples -/// -/// ```gleam -/// drop([1, 2, 3, 4], 2) -/// // -> [3, 4] -/// ``` -/// -/// ```gleam -/// drop([1, 2, 3, 4], 9) -/// // -> [] -/// ``` -/// -pub fn drop(from list: List(a), up_to n: Int) -> List(a) { - case n <= 0 { - True -> list - False -> - case list { - [] -> [] - [_, ..rest] -> drop(rest, n - 1) - } - } -} - -/// Returns a list containing the first given number of elements from the given -/// list. -/// -/// If the element has less than the number of elements then the full list is -/// returned. -/// -/// This function runs in linear time. -/// -/// ## Examples -/// -/// ```gleam -/// take([1, 2, 3, 4], 2) -/// // -> [1, 2] -/// ``` -/// -/// ```gleam -/// take([1, 2, 3, 4], 9) -/// // -> [1, 2, 3, 4] -/// ``` -/// -pub fn take(from list: List(a), up_to n: Int) -> List(a) { - take_loop(list, n, []) -} - -fn take_loop(list: List(a), n: Int, acc: List(a)) -> List(a) { - case n <= 0 { - True -> reverse(acc) - False -> - case list { - [] -> reverse(acc) - [first, ..rest] -> take_loop(rest, n - 1, [first, ..acc]) - } - } -} - -/// Returns a new empty list. -/// -/// ## Examples -/// -/// ```gleam -/// new() -/// // -> [] -/// ``` -/// -pub fn new() -> List(a) { - [] -} - -/// Returns the given item wrapped in a list. -/// -/// ## Examples -/// -/// ```gleam -/// wrap(1) -/// // -> [1] -/// -/// wrap(["a", "b", "c"]) -/// // -> [["a", "b", "c"]] -/// -/// wrap([[]]) -/// // -> [[[]]] -/// ``` -/// -/// -pub fn wrap(item: a) -> List(a) { - [item] -} - -/// Joins one list onto the end of another. -/// -/// This function runs in linear time, and it traverses and copies the first -/// list. -/// -/// ## Examples -/// -/// ```gleam -/// append([1, 2], [3]) -/// // -> [1, 2, 3] -/// ``` -/// -@external(erlang, "lists", "append") -pub fn append(first: List(a), second: List(a)) -> List(a) { - append_loop(reverse(first), second) -} - -fn append_loop(first: List(a), second: List(a)) -> List(a) { - case first { - [] -> second - [first, ..rest] -> append_loop(rest, [first, ..second]) - } -} - -/// Prefixes an item to a list. This can also be done using the dedicated -/// syntax instead -/// -/// ```gleam -/// let existing_list = [2, 3, 4] -/// -/// [1, ..existing_list] -/// // -> [1, 2, 3, 4] -/// -/// prepend(to: existing_list, this: 1) -/// // -> [1, 2, 3, 4] -/// ``` -/// -pub fn prepend(to list: List(a), this item: a) -> List(a) { - [item, ..list] -} - -/// Joins a list of lists into a single list. -/// -/// This function traverses all elements twice on the JavaScript target. -/// This function traverses all elements once on the Erlang target. -/// -/// ## Examples -/// -/// ```gleam -/// flatten([[1], [2, 3], []]) -/// // -> [1, 2, 3] -/// ``` -/// -@external(erlang, "lists", "append") -pub fn flatten(lists: List(List(a))) -> List(a) { - flatten_loop(lists, []) -} - -fn flatten_loop(lists: List(List(a)), acc: List(a)) -> List(a) { - case lists { - [] -> reverse(acc) - [list, ..further_lists] -> - flatten_loop(further_lists, reverse_and_prepend(list, to: acc)) - } -} - -/// Maps the list with the given function into a list of lists, and then flattens it. -/// -/// ## Examples -/// -/// ```gleam -/// flat_map([2, 4, 6], fn(x) { [x, x + 1] }) -/// // -> [2, 3, 4, 5, 6, 7] -/// ``` -/// -pub fn flat_map(over list: List(a), with fun: fn(a) -> List(b)) -> List(b) { - flatten(map(list, fun)) -} - -/// Reduces a list of elements into a single value by calling a given function -/// on each element, going from left to right. -/// -/// `fold([1, 2, 3], 0, add)` is the equivalent of -/// `add(add(add(0, 1), 2), 3)`. -/// -/// This function runs in linear time. -/// -pub fn fold( - over list: List(a), - from initial: acc, - with fun: fn(acc, a) -> acc, -) -> acc { - case list { - [] -> initial - [first, ..rest] -> fold(rest, fun(initial, first), fun) - } -} - -/// Reduces a list of elements into a single value by calling a given function -/// on each element, going from right to left. -/// -/// `fold_right([1, 2, 3], 0, add)` is the equivalent of -/// `add(add(add(0, 3), 2), 1)`. -/// -/// This function runs in linear time. -/// -/// Unlike `fold` this function is not tail recursive. Where possible use -/// `fold` instead as it will use less memory. -/// -pub fn fold_right( - over list: List(a), - from initial: acc, - with fun: fn(acc, a) -> acc, -) -> acc { - case list { - [] -> initial - [first, ..rest] -> fun(fold_right(rest, initial, fun), first) - } -} - -/// Like fold but the folding function also receives the index of the current element. -/// -/// ## Examples -/// -/// ```gleam -/// ["a", "b", "c"] -/// |> index_fold("", fn(acc, item, index) { -/// acc <> int.to_string(index) <> ":" <> item <> " " -/// }) -/// // -> "0:a 1:b 2:c" -/// ``` -/// -/// ```gleam -/// [10, 20, 30] -/// |> index_fold(0, fn(acc, item, index) { acc + item * index }) -/// // -> 80 -/// ``` -/// -pub fn index_fold( - over list: List(a), - from initial: acc, - with fun: fn(acc, a, Int) -> acc, -) -> acc { - index_fold_loop(list, initial, fun, 0) -} - -fn index_fold_loop( - over: List(a), - acc: acc, - with: fn(acc, a, Int) -> acc, - index: Int, -) -> acc { - case over { - [] -> acc - [first, ..rest] -> - index_fold_loop(rest, with(acc, first, index), with, index + 1) - } -} - -/// A variant of fold that might fail. -/// -/// The folding function should return `Result(accumulator, error)`. -/// If the returned value is `Ok(accumulator)` try_fold will try the next value in the list. -/// If the returned value is `Error(error)` try_fold will stop and return that error. -/// -/// ## Examples -/// -/// ```gleam -/// [1, 2, 3, 4] -/// |> try_fold(0, fn(acc, i) { -/// case i < 3 { -/// True -> Ok(acc + i) -/// False -> Error(Nil) -/// } -/// }) -/// // -> Error(Nil) -/// ``` -/// -pub fn try_fold( - over list: List(a), - from initial: acc, - with fun: fn(acc, a) -> Result(acc, e), -) -> Result(acc, e) { - case list { - [] -> Ok(initial) - [first, ..rest] -> - case fun(initial, first) { - Ok(result) -> try_fold(rest, result, fun) - Error(_) as error -> error - } - } -} - -pub type ContinueOrStop(a) { - Continue(a) - Stop(a) -} - -/// A variant of fold that allows to stop folding earlier. -/// -/// The folding function should return `ContinueOrStop(accumulator)`. -/// If the returned value is `Continue(accumulator)` fold_until will try the next value in the list. -/// If the returned value is `Stop(accumulator)` fold_until will stop and return that accumulator. -/// -/// ## Examples -/// -/// ```gleam -/// [1, 2, 3, 4] -/// |> fold_until(0, fn(acc, i) { -/// case i < 3 { -/// True -> Continue(acc + i) -/// False -> Stop(acc) -/// } -/// }) -/// // -> 3 -/// ``` -/// -pub fn fold_until( - over list: List(a), - from initial: acc, - with fun: fn(acc, a) -> ContinueOrStop(acc), -) -> acc { - case list { - [] -> initial - [first, ..rest] -> - case fun(initial, first) { - Continue(next_accumulator) -> fold_until(rest, next_accumulator, fun) - Stop(b) -> b - } - } -} - -/// Finds the first element in a given list for which the given function returns -/// `True`. -/// -/// Returns `Error(Nil)` if no such element is found. -/// -/// ## Examples -/// -/// ```gleam -/// find([1, 2, 3], fn(x) { x > 2 }) -/// // -> Ok(3) -/// ``` -/// -/// ```gleam -/// find([1, 2, 3], fn(x) { x > 4 }) -/// // -> Error(Nil) -/// ``` -/// -/// ```gleam -/// find([], fn(_) { True }) -/// // -> Error(Nil) -/// ``` -/// -pub fn find( - in list: List(a), - one_that is_desired: fn(a) -> Bool, -) -> Result(a, Nil) { - case list { - [] -> Error(Nil) - [first, ..rest] -> - case is_desired(first) { - True -> Ok(first) - False -> find(in: rest, one_that: is_desired) - } - } -} - -/// Finds the first element in a given list for which the given function returns -/// `Ok(new_value)`, then returns the wrapped `new_value`. -/// -/// Returns `Error(Nil)` if no such element is found. -/// -/// ## Examples -/// -/// ```gleam -/// find_map([[], [2], [3]], first) -/// // -> Ok(2) -/// ``` -/// -/// ```gleam -/// find_map([[], []], first) -/// // -> Error(Nil) -/// ``` -/// -/// ```gleam -/// find_map([], first) -/// // -> Error(Nil) -/// ``` -/// -pub fn find_map( - in list: List(a), - with fun: fn(a) -> Result(b, c), -) -> Result(b, Nil) { - case list { - [] -> Error(Nil) - [first, ..rest] -> - case fun(first) { - Ok(first) -> Ok(first) - Error(_) -> find_map(in: rest, with: fun) - } - } -} - -/// Returns `True` if the given function returns `True` for all the elements in -/// the given list. If the function returns `False` for any of the elements it -/// immediately returns `False` without checking the rest of the list. -/// -/// ## Examples -/// -/// ```gleam -/// all([], fn(x) { x > 3 }) -/// // -> True -/// ``` -/// -/// ```gleam -/// all([4, 5], fn(x) { x > 3 }) -/// // -> True -/// ``` -/// -/// ```gleam -/// all([4, 3], fn(x) { x > 3 }) -/// // -> False -/// ``` -/// -pub fn all(in list: List(a), satisfying predicate: fn(a) -> Bool) -> Bool { - case list { - [] -> True - [first, ..rest] -> - case predicate(first) { - True -> all(rest, predicate) - False -> False - } - } -} - -/// Returns `True` if the given function returns `True` for any the elements in -/// the given list. If the function returns `True` for any of the elements it -/// immediately returns `True` without checking the rest of the list. -/// -/// ## Examples -/// -/// ```gleam -/// any([], fn(x) { x > 3 }) -/// // -> False -/// ``` -/// -/// ```gleam -/// any([4, 5], fn(x) { x > 3 }) -/// // -> True -/// ``` -/// -/// ```gleam -/// any([4, 3], fn(x) { x > 4 }) -/// // -> False -/// ``` -/// -/// ```gleam -/// any([3, 4], fn(x) { x > 3 }) -/// // -> True -/// ``` -/// -pub fn any(in list: List(a), satisfying predicate: fn(a) -> Bool) -> Bool { - case list { - [] -> False - [first, ..rest] -> - case predicate(first) { - True -> True - False -> any(rest, predicate) - } - } -} - -/// Takes two lists and returns a single list of 2-element tuples. -/// -/// If one of the lists is longer than the other, the remaining elements from -/// the longer list are not used. -/// -/// ## Examples -/// -/// ```gleam -/// zip([], []) -/// // -> [] -/// ``` -/// -/// ```gleam -/// zip([1, 2], [3]) -/// // -> [#(1, 3)] -/// ``` -/// -/// ```gleam -/// zip([1], [3, 4]) -/// // -> [#(1, 3)] -/// ``` -/// -/// ```gleam -/// zip([1, 2], [3, 4]) -/// // -> [#(1, 3), #(2, 4)] -/// ``` -/// -pub fn zip(list: List(a), with other: List(b)) -> List(#(a, b)) { - zip_loop(list, other, []) -} - -fn zip_loop(one: List(a), other: List(b), acc: List(#(a, b))) -> List(#(a, b)) { - case one, other { - [first_one, ..rest_one], [first_other, ..rest_other] -> - zip_loop(rest_one, rest_other, [#(first_one, first_other), ..acc]) - _, _ -> reverse(acc) - } -} - -/// Takes two lists and returns a single list of 2-element tuples. -/// -/// If one of the lists is longer than the other, an `Error` is returned. -/// -/// ## Examples -/// -/// ```gleam -/// strict_zip([], []) -/// // -> Ok([]) -/// ``` -/// -/// ```gleam -/// strict_zip([1, 2], [3]) -/// // -> Error(Nil) -/// ``` -/// -/// ```gleam -/// strict_zip([1], [3, 4]) -/// // -> Error(Nil) -/// ``` -/// -/// ```gleam -/// strict_zip([1, 2], [3, 4]) -/// // -> Ok([#(1, 3), #(2, 4)]) -/// ``` -/// -pub fn strict_zip( - list: List(a), - with other: List(b), -) -> Result(List(#(a, b)), Nil) { - strict_zip_loop(list, other, []) -} - -fn strict_zip_loop( - one: List(a), - other: List(b), - acc: List(#(a, b)), -) -> Result(List(#(a, b)), Nil) { - case one, other { - [], [] -> Ok(reverse(acc)) - [], _ | _, [] -> Error(Nil) - [first_one, ..rest_one], [first_other, ..rest_other] -> - strict_zip_loop(rest_one, rest_other, [#(first_one, first_other), ..acc]) - } -} - -/// Takes a single list of 2-element tuples and returns two lists. -/// -/// ## Examples -/// -/// ```gleam -/// unzip([#(1, 2), #(3, 4)]) -/// // -> #([1, 3], [2, 4]) -/// ``` -/// -/// ```gleam -/// unzip([]) -/// // -> #([], []) -/// ``` -/// -pub fn unzip(input: List(#(a, b))) -> #(List(a), List(b)) { - unzip_loop(input, [], []) -} - -fn unzip_loop( - input: List(#(a, b)), - one: List(a), - other: List(b), -) -> #(List(a), List(b)) { - case input { - [] -> #(reverse(one), reverse(other)) - [#(first_one, first_other), ..rest] -> - unzip_loop(rest, [first_one, ..one], [first_other, ..other]) - } -} - -/// Inserts a given value between each existing element in a given list. -/// -/// This function runs in linear time and copies the list. -/// -/// ## Examples -/// -/// ```gleam -/// intersperse([1, 1, 1], 2) -/// // -> [1, 2, 1, 2, 1] -/// ``` -/// -/// ```gleam -/// intersperse([], 2) -/// // -> [] -/// ``` -/// -pub fn intersperse(list: List(a), with elem: a) -> List(a) { - case list { - [] | [_] -> list - [first, ..rest] -> intersperse_loop(rest, elem, [first]) - } -} - -fn intersperse_loop(list: List(a), separator: a, acc: List(a)) -> List(a) { - case list { - [] -> reverse(acc) - [first, ..rest] -> - intersperse_loop(rest, separator, [first, separator, ..acc]) - } -} - -/// Removes any duplicate elements from a given list. -/// -/// This function returns in loglinear time. -/// -/// ## Examples -/// -/// ```gleam -/// unique([1, 1, 1, 4, 7, 3, 3, 4]) -/// // -> [1, 4, 7, 3] -/// ``` -/// -pub fn unique(list: List(a)) -> List(a) { - unique_loop(list, dict.new(), []) -} - -fn unique_loop(list: List(a), seen: Dict(a, Nil), acc: List(a)) -> List(a) { - case list { - [] -> reverse(acc) - [first, ..rest] -> - case dict.has_key(seen, first) { - True -> unique_loop(rest, seen, acc) - False -> - unique_loop(rest, dict.insert(seen, first, Nil), [first, ..acc]) - } - } -} - -/// Sorts from smallest to largest based upon the ordering specified by a given -/// function. -/// -/// ## Examples -/// -/// ```gleam -/// import gleam/int -/// -/// sort([4, 3, 6, 5, 4, 1, 2], by: int.compare) -/// // -> [1, 2, 3, 4, 4, 5, 6] -/// ``` -/// -pub fn sort(list: List(a), by compare: fn(a, a) -> Order) -> List(a) { - // This is a natural, tail recursive, stable merge sort: - // - natural: it is very efficient if you call it on a list that is already - // (pre)sorted because it works on slices of the original list. - // - tail recursive: the stack won't grow linearly with the size of the list. - // - stable: if two items are considered to be equal then their original - // relative order is preserved. - case list { - // If the list has zero/one item then it's already sorted. - [] -> [] - [x] -> [x] - - // Otherwise the algorithm works as follow: we split the list in sequences - // of already sorted values as they appear in the list and then we merge - // those together two by two using `merge_all`. - [x, y, ..rest] -> { - // We need to compare the first two items to properly call `sequences` - // with the correct initial values. If the second item is <= than the - // first, then we know we'll start by growing a descending sequence - // (and an ascending one in the opposite case). - let direction = case compare(x, y) { - order.Lt | order.Eq -> Ascending - order.Gt -> Descending - } - - // `sequences` produces sequences in ascending order so we call the - // `merge_all` function saying it to expect all sequences to be sorted - // that way. - let sequences = sequences(rest, compare, [x], direction, y, []) - merge_all(sequences, Ascending, compare) - } - } -} - -type Sorting { - Ascending - Descending -} - -/// Given a list it returns slices of it that are locally sorted in ascending -/// order. -/// -/// Imagine you have this list: -/// -/// ``` -/// [1, 2, 3, 2, 1, 0] -/// ^^^^^^^ ^^^^^^^ This is a slice in descending order -/// | -/// | This is a slice that is sorted in ascending order -/// ``` -/// -/// So the produced result will contain these two slices, each one sorted in -/// ascending order: `[[1, 2, 3], [0, 1, 2]]`. -/// -/// - `growing` is an accumulator with the current slice being grown -/// - `direction` is the growing direction of the slice being grown, it could -/// either be ascending or strictly descending -/// - `prev` is the previous element that needs to be added to the growing slice -/// it is carried around to check whether we have to keep growing the current -/// slice or not -/// - `acc` is the accumulator containing the slices sorted in ascending order -/// -fn sequences( - list: List(a), - compare: fn(a, a) -> Order, - growing: List(a), - direction: Sorting, - prev: a, - acc: List(List(a)), -) -> List(List(a)) { - // First of all we must not forget to add the previous element to the - // currently growing slice. - let growing = [prev, ..growing] - - case list { - [] -> - case direction { - // Notice how we have to reverse the accumulator we're growing: since - // we always add items to the head, `growing` is built in the opposite - // sorting order of what it actually is in the original list. - Ascending -> [reverse(growing), ..acc] - Descending -> [growing, ..acc] - } - - [new, ..rest] -> - case compare(prev, new), direction { - // In case the new element respects the ordering of the growing - // sequence, then we just keep growing it. - // Notice how a growing sequence is weakly growing (that is it can have - // consecutive equal items) while a decreasing sequence is strictly - // decreasing (no consecutive equal items), this is needed to make the - // algorithm stable! - order.Gt, Descending | order.Lt, Ascending | order.Eq, Ascending -> - sequences(rest, compare, growing, direction, new, acc) - - // We were growing an ascending (descending) sequence and the new item - // is smaller (bigger) than the previous one, this means we have to stop - // growing this sequence and start with a new one whose first item will - // be the one we just found. - order.Gt, Ascending | order.Lt, Descending | order.Eq, Descending -> { - let acc = case direction { - Ascending -> [reverse(growing), ..acc] - Descending -> [growing, ..acc] - } - case rest { - // The list is over so we just create a sequence containing the last - // item we saw and add it to the accumulator before returning it. - [] -> [[new], ..acc] - - // If the list is not over we have a peek at the next item to decide - // in which direction is growing the new sequence and make the - // recursive call with the appropriate arguments. - [next, ..rest] -> { - let direction = case compare(new, next) { - order.Lt | order.Eq -> Ascending - order.Gt -> Descending - } - sequences(rest, compare, [new], direction, next, acc) - } - } - } - } - } -} - -/// Given some some sorted sequences (assumed to be sorted in `direction`) it -/// merges them all together until we're left with just a list sorted in -/// ascending order. -/// -fn merge_all( - sequences: List(List(a)), - direction: Sorting, - compare: fn(a, a) -> Order, -) -> List(a) { - case sequences, direction { - [], _ -> [] - - // If we have a single list in ascending order then we're done. - [sequence], Ascending -> sequence - - // If we have a single list in descending order, we reverse it to make sure - // it's in ascending order and we're done. - [sequence], Descending -> reverse(sequence) - - // Merging together sequences that are in ascending (descending) order - // reverses their order, so the recursive call will assume to be merging - // lists sorted in the opposite order! - _, Ascending -> { - let sequences = merge_ascending_pairs(sequences, compare, []) - merge_all(sequences, Descending, compare) - } - - _, Descending -> { - let sequences = merge_descending_pairs(sequences, compare, []) - merge_all(sequences, Ascending, compare) - } - } -} - -/// Given a list of ascending lists, it merges adjacent pairs into a single -/// descending list, halving their number. -/// It returns a list of the remaining descending lists. -/// -fn merge_ascending_pairs( - sequences: List(List(a)), - compare: fn(a, a) -> Order, - acc: List(List(a)), -) { - case sequences { - [] -> reverse(acc) - - // Beware, if we have just one item left we must reverse it: we take - // ascending lists as input and have to return descending ones. - // If we returned it like it is it would be sorted in ascending order. - [sequence] -> reverse([reverse(sequence), ..acc]) - - [ascending1, ascending2, ..rest] -> { - let descending = merge_ascendings(ascending1, ascending2, compare, []) - merge_ascending_pairs(rest, compare, [descending, ..acc]) - } - } -} - -/// This is the same as merge_ascending_pairs but flipped for descending lists. -/// -fn merge_descending_pairs( - sequences: List(List(a)), - compare: fn(a, a) -> Order, - acc: List(List(a)), -) { - case sequences { - [] -> reverse(acc) - - [sequence] -> reverse([reverse(sequence), ..acc]) - - [descending1, descending2, ..rest] -> { - let ascending = merge_descendings(descending1, descending2, compare, []) - merge_descending_pairs(rest, compare, [ascending, ..acc]) - } - } -} - -/// Merges two lists sorted in ascending order into a single list sorted in -/// descending order according to the given comparator function. -/// -/// This reversing of the sort order is not avoidable if we want to implement -/// merge as a tail recursive function. We could reverse the accumulator before -/// returning it but that would end up being less efficient; so the merging -/// algorithm has to play around this. -/// -fn merge_ascendings( - list1: List(a), - list2: List(a), - compare: fn(a, a) -> Order, - acc: List(a), -) -> List(a) { - case list1, list2 { - [], list | list, [] -> reverse_and_prepend(list, acc) - - [first1, ..rest1], [first2, ..rest2] -> - case compare(first1, first2) { - order.Lt -> merge_ascendings(rest1, list2, compare, [first1, ..acc]) - order.Gt | order.Eq -> - merge_ascendings(list1, rest2, compare, [first2, ..acc]) - } - } -} - -/// This is exactly the same as merge_ascendings but mirrored: it merges two -/// lists sorted in descending order into a single list sorted in ascending -/// order according to the given comparator function. -/// -/// This reversing of the sort order is not avoidable if we want to implement -/// merge as a tail recursive function. We could reverse the accumulator before -/// returning it but that would end up being less efficient; so the merging -/// algorithm has to play around this. -/// -fn merge_descendings( - list1: List(a), - list2: List(a), - compare: fn(a, a) -> Order, - acc: List(a), -) -> List(a) { - case list1, list2 { - [], list | list, [] -> reverse_and_prepend(list, acc) - [first1, ..rest1], [first2, ..rest2] -> - case compare(first1, first2) { - order.Lt -> merge_descendings(list1, rest2, compare, [first2, ..acc]) - order.Gt | order.Eq -> - merge_descendings(rest1, list2, compare, [first1, ..acc]) - } - } -} - -/// Creates a list of ints ranging from a given start and finish. -/// -/// ## Examples -/// -/// ```gleam -/// range(0, 0) -/// // -> [0] -/// ``` -/// -/// ```gleam -/// range(0, 5) -/// // -> [0, 1, 2, 3, 4, 5] -/// ``` -/// -/// ```gleam -/// range(1, -5) -/// // -> [1, 0, -1, -2, -3, -4, -5] -/// ``` -/// -pub fn range(from start: Int, to stop: Int) -> List(Int) { - range_loop(start, stop, []) -} - -fn range_loop(start: Int, stop: Int, acc: List(Int)) -> List(Int) { - case int.compare(start, stop) { - order.Eq -> [stop, ..acc] - order.Gt -> range_loop(start, stop + 1, [stop, ..acc]) - order.Lt -> range_loop(start, stop - 1, [stop, ..acc]) - } -} - -/// Builds a list of a given value a given number of times. -/// -/// ## Examples -/// -/// ```gleam -/// repeat("a", times: 0) -/// // -> [] -/// ``` -/// -/// ```gleam -/// repeat("a", times: 5) -/// // -> ["a", "a", "a", "a", "a"] -/// ``` -/// -pub fn repeat(item a: a, times times: Int) -> List(a) { - repeat_loop(a, times, []) -} - -fn repeat_loop(item: a, times: Int, acc: List(a)) -> List(a) { - case times <= 0 { - True -> acc - False -> repeat_loop(item, times - 1, [item, ..acc]) - } -} - -/// Splits a list in two before the given index. -/// -/// If the list is not long enough to have the given index the before list will -/// be the input list, and the after list will be empty. -/// -/// ## Examples -/// -/// ```gleam -/// split([6, 7, 8, 9], 0) -/// // -> #([], [6, 7, 8, 9]) -/// ``` -/// -/// ```gleam -/// split([6, 7, 8, 9], 2) -/// // -> #([6, 7], [8, 9]) -/// ``` -/// -/// ```gleam -/// split([6, 7, 8, 9], 4) -/// // -> #([6, 7, 8, 9], []) -/// ``` -/// -pub fn split(list list: List(a), at index: Int) -> #(List(a), List(a)) { - split_loop(list, index, []) -} - -fn split_loop(list: List(a), n: Int, taken: List(a)) -> #(List(a), List(a)) { - case n <= 0 { - True -> #(reverse(taken), list) - False -> - case list { - [] -> #(reverse(taken), []) - [first, ..rest] -> split_loop(rest, n - 1, [first, ..taken]) - } - } -} - -/// Splits a list in two before the first element that a given function returns -/// `False` for. -/// -/// If the function returns `True` for all elements the first list will be the -/// input list, and the second list will be empty. -/// -/// ## Examples -/// -/// ```gleam -/// split_while([1, 2, 3, 4, 5], fn(x) { x <= 3 }) -/// // -> #([1, 2, 3], [4, 5]) -/// ``` -/// -/// ```gleam -/// split_while([1, 2, 3, 4, 5], fn(x) { x <= 5 }) -/// // -> #([1, 2, 3, 4, 5], []) -/// ``` -/// -pub fn split_while( - list list: List(a), - satisfying predicate: fn(a) -> Bool, -) -> #(List(a), List(a)) { - split_while_loop(list, predicate, []) -} - -fn split_while_loop( - list: List(a), - f: fn(a) -> Bool, - acc: List(a), -) -> #(List(a), List(a)) { - case list { - [] -> #(reverse(acc), []) - [first, ..rest] -> - case f(first) { - True -> split_while_loop(rest, f, [first, ..acc]) - False -> #(reverse(acc), list) - } - } -} - -/// Given a list of 2-element tuples, finds the first tuple that has a given -/// key as the first element and returns the second element. -/// -/// If no tuple is found with the given key then `Error(Nil)` is returned. -/// -/// This function may be useful for interacting with Erlang code where lists of -/// tuples are common. -/// -/// ## Examples -/// -/// ```gleam -/// key_find([#("a", 0), #("b", 1)], "a") -/// // -> Ok(0) -/// ``` -/// -/// ```gleam -/// key_find([#("a", 0), #("b", 1)], "b") -/// // -> Ok(1) -/// ``` -/// -/// ```gleam -/// key_find([#("a", 0), #("b", 1)], "c") -/// // -> Error(Nil) -/// ``` -/// -pub fn key_find( - in keyword_list: List(#(k, v)), - find desired_key: k, -) -> Result(v, Nil) { - find_map(keyword_list, fn(keyword) { - let #(key, value) = keyword - case key == desired_key { - True -> Ok(value) - False -> Error(Nil) - } - }) -} - -/// Given a list of 2-element tuples, finds all tuples that have a given -/// key as the first element and returns the second element. -/// -/// This function may be useful for interacting with Erlang code where lists of -/// tuples are common. -/// -/// ## Examples -/// -/// ```gleam -/// key_filter([#("a", 0), #("b", 1), #("a", 2)], "a") -/// // -> [0, 2] -/// ``` -/// -/// ```gleam -/// key_filter([#("a", 0), #("b", 1)], "c") -/// // -> [] -/// ``` -/// -pub fn key_filter( - in keyword_list: List(#(k, v)), - find desired_key: k, -) -> List(v) { - filter_map(keyword_list, fn(keyword) { - let #(key, value) = keyword - case key == desired_key { - True -> Ok(value) - False -> Error(Nil) - } - }) -} - -/// Given a list of 2-element tuples, finds the first tuple that has a given -/// key as the first element. This function will return the second element -/// of the found tuple and list with tuple removed. -/// -/// If no tuple is found with the given key then `Error(Nil)` is returned. -/// -/// ## Examples -/// -/// ```gleam -/// key_pop([#("a", 0), #("b", 1)], "a") -/// // -> Ok(#(0, [#("b", 1)])) -/// ``` -/// -/// ```gleam -/// key_pop([#("a", 0), #("b", 1)], "b") -/// // -> Ok(#(1, [#("a", 0)])) -/// ``` -/// -/// ```gleam -/// key_pop([#("a", 0), #("b", 1)], "c") -/// // -> Error(Nil) -/// ``` -/// -pub fn key_pop(list: List(#(k, v)), key: k) -> Result(#(v, List(#(k, v))), Nil) { - key_pop_loop(list, key, []) -} - -fn key_pop_loop( - list: List(#(k, v)), - key: k, - checked: List(#(k, v)), -) -> Result(#(v, List(#(k, v))), Nil) { - case list { - [] -> Error(Nil) - [#(k, v), ..rest] if k == key -> - Ok(#(v, reverse_and_prepend(checked, rest))) - [first, ..rest] -> key_pop_loop(rest, key, [first, ..checked]) - } -} - -/// Given a list of 2-element tuples, inserts a key and value into the list. -/// -/// If there was already a tuple with the key then it is replaced, otherwise it -/// is added to the end of the list. -/// -/// ## Examples -/// -/// ```gleam -/// key_set([#(5, 0), #(4, 1)], 4, 100) -/// // -> [#(5, 0), #(4, 100)] -/// ``` -/// -/// ```gleam -/// key_set([#(5, 0), #(4, 1)], 1, 100) -/// // -> [#(5, 0), #(4, 1), #(1, 100)] -/// ``` -/// -pub fn key_set(list: List(#(k, v)), key: k, value: v) -> List(#(k, v)) { - key_set_loop(list, key, value, []) -} - -fn key_set_loop( - list: List(#(k, v)), - key: k, - value: v, - inspected: List(#(k, v)), -) -> List(#(k, v)) { - case list { - [#(k, _), ..rest] if k == key -> - reverse_and_prepend(inspected, [#(k, value), ..rest]) - [first, ..rest] -> key_set_loop(rest, key, value, [first, ..inspected]) - [] -> reverse([#(key, value), ..inspected]) - } -} - -/// Calls a function for each element in a list, discarding the return value. -/// -/// Useful for calling a side effect for every item of a list. -/// -/// ```gleam -/// import gleam/io -/// -/// each(["1", "2", "3"], io.println) -/// // -> Nil -/// // 1 -/// // 2 -/// // 3 -/// ``` -/// -pub fn each(list: List(a), f: fn(a) -> b) -> Nil { - case list { - [] -> Nil - [first, ..rest] -> { - f(first) - each(rest, f) - } - } -} - -/// Calls a `Result` returning function for each element in a list, discarding -/// the return value. If the function returns `Error` then the iteration is -/// stopped and the error is returned. -/// -/// Useful for calling a side effect for every item of a list. -/// -/// ## Examples -/// -/// ```gleam -/// try_each( -/// over: [1, 2, 3], -/// with: function_that_might_fail, -/// ) -/// // -> Ok(Nil) -/// ``` -/// -pub fn try_each( - over list: List(a), - with fun: fn(a) -> Result(b, e), -) -> Result(Nil, e) { - case list { - [] -> Ok(Nil) - [first, ..rest] -> - case fun(first) { - Ok(_) -> try_each(over: rest, with: fun) - Error(e) -> Error(e) - } - } -} - -/// Partitions a list into a tuple/pair of lists -/// by a given categorisation function. -/// -/// ## Examples -/// -/// ```gleam -/// import gleam/int -/// -/// [1, 2, 3, 4, 5] |> partition(int.is_odd) -/// // -> #([1, 3, 5], [2, 4]) -/// ``` -/// -pub fn partition( - list: List(a), - with categorise: fn(a) -> Bool, -) -> #(List(a), List(a)) { - partition_loop(list, categorise, [], []) -} - -fn partition_loop(list, categorise, trues, falses) { - case list { - [] -> #(reverse(trues), reverse(falses)) - [first, ..rest] -> - case categorise(first) { - True -> partition_loop(rest, categorise, [first, ..trues], falses) - False -> partition_loop(rest, categorise, trues, [first, ..falses]) - } - } -} - -/// Returns all the permutations of a list. -/// -/// ## Examples -/// -/// ```gleam -/// permutations([1, 2]) -/// // -> [[1, 2], [2, 1]] -/// ``` -/// -pub fn permutations(list: List(a)) -> List(List(a)) { - case list { - [] -> [[]] - l -> permutation_zip(l, [], []) - } -} - -fn permutation_zip( - list: List(a), - rest: List(a), - acc: List(List(a)), -) -> List(List(a)) { - case list { - [] -> reverse(acc) - [head, ..tail] -> - permutation_prepend( - head, - permutations(reverse_and_prepend(rest, tail)), - tail, - [head, ..rest], - acc, - ) - } -} - -fn permutation_prepend( - el: a, - permutations: List(List(a)), - list_1: List(a), - list_2: List(a), - acc: List(List(a)), -) -> List(List(a)) { - case permutations { - [] -> permutation_zip(list_1, list_2, acc) - [head, ..tail] -> - permutation_prepend(el, tail, list_1, list_2, [[el, ..head], ..acc]) - } -} - -/// Returns a list of sliding windows. -/// -/// ## Examples -/// -/// ```gleam -/// window([1,2,3,4,5], 3) -/// // -> [[1, 2, 3], [2, 3, 4], [3, 4, 5]] -/// ``` -/// -/// ```gleam -/// window([1, 2], 4) -/// // -> [] -/// ``` -/// -pub fn window(list: List(a), by n: Int) -> List(List(a)) { - case n <= 0 { - True -> [] - False -> window_loop([], list, n) - } -} - -fn window_loop(acc: List(List(a)), list: List(a), n: Int) -> List(List(a)) { - let window = take(list, n) - - case length(window) == n { - True -> window_loop([window, ..acc], drop(list, 1), n) - False -> reverse(acc) - } -} - -/// Returns a list of tuples containing two contiguous elements. -/// -/// ## Examples -/// -/// ```gleam -/// window_by_2([1,2,3,4]) -/// // -> [#(1, 2), #(2, 3), #(3, 4)] -/// ``` -/// -/// ```gleam -/// window_by_2([1]) -/// // -> [] -/// ``` -/// -pub fn window_by_2(list: List(a)) -> List(#(a, a)) { - zip(list, drop(list, 1)) -} - -/// Drops the first elements in a given list for which the predicate function returns `True`. -/// -/// ## Examples -/// -/// ```gleam -/// drop_while([1, 2, 3, 4], fn (x) { x < 3 }) -/// // -> [3, 4] -/// ``` -/// -pub fn drop_while( - in list: List(a), - satisfying predicate: fn(a) -> Bool, -) -> List(a) { - case list { - [] -> [] - [first, ..rest] -> - case predicate(first) { - True -> drop_while(rest, predicate) - False -> [first, ..rest] - } - } -} - -/// Takes the first elements in a given list for which the predicate function returns `True`. -/// -/// ## Examples -/// -/// ```gleam -/// take_while([1, 2, 3, 2, 4], fn (x) { x < 3 }) -/// // -> [1, 2] -/// ``` -/// -pub fn take_while( - in list: List(a), - satisfying predicate: fn(a) -> Bool, -) -> List(a) { - take_while_loop(list, predicate, []) -} - -fn take_while_loop( - list: List(a), - predicate: fn(a) -> Bool, - acc: List(a), -) -> List(a) { - case list { - [] -> reverse(acc) - [first, ..rest] -> - case predicate(first) { - True -> take_while_loop(rest, predicate, [first, ..acc]) - False -> reverse(acc) - } - } -} - -/// Returns a list of chunks in which -/// the return value of calling `f` on each element is the same. -/// -/// ## Examples -/// -/// ```gleam -/// [1, 2, 2, 3, 4, 4, 6, 7, 7] |> chunk(by: fn(n) { n % 2 }) -/// // -> [[1], [2, 2], [3], [4, 4, 6], [7, 7]] -/// ``` -/// -pub fn chunk(in list: List(a), by f: fn(a) -> k) -> List(List(a)) { - case list { - [] -> [] - [first, ..rest] -> chunk_loop(rest, f, f(first), [first], []) - } -} - -fn chunk_loop( - list: List(a), - f: fn(a) -> k, - previous_key: k, - current_chunk: List(a), - acc: List(List(a)), -) -> List(List(a)) { - case list { - [first, ..rest] -> { - let key = f(first) - case key == previous_key { - True -> chunk_loop(rest, f, key, [first, ..current_chunk], acc) - False -> { - let new_acc = [reverse(current_chunk), ..acc] - chunk_loop(rest, f, key, [first], new_acc) - } - } - } - [] -> reverse([reverse(current_chunk), ..acc]) - } -} - -/// Returns a list of chunks containing `count` elements each. -/// -/// If the last chunk does not have `count` elements, it is instead -/// a partial chunk, with less than `count` elements. -/// -/// For any `count` less than 1 this function behaves as if it was set to 1. -/// -/// ## Examples -/// -/// ```gleam -/// [1, 2, 3, 4, 5, 6] |> sized_chunk(into: 2) -/// // -> [[1, 2], [3, 4], [5, 6]] -/// ``` -/// -/// ```gleam -/// [1, 2, 3, 4, 5, 6, 7, 8] |> sized_chunk(into: 3) -/// // -> [[1, 2, 3], [4, 5, 6], [7, 8]] -/// ``` -/// -pub fn sized_chunk(in list: List(a), into count: Int) -> List(List(a)) { - sized_chunk_loop(list, count, count, [], []) -} - -fn sized_chunk_loop( - list: List(a), - count: Int, - left: Int, - current_chunk: List(a), - acc: List(List(a)), -) -> List(List(a)) { - case list { - [] -> - case current_chunk { - [] -> reverse(acc) - remaining -> reverse([reverse(remaining), ..acc]) - } - [first, ..rest] -> { - let chunk = [first, ..current_chunk] - case left > 1 { - True -> sized_chunk_loop(rest, count, left - 1, chunk, acc) - False -> - sized_chunk_loop(rest, count, count, [], [reverse(chunk), ..acc]) - } - } - } -} - -/// This function acts similar to fold, but does not take an initial state. -/// Instead, it starts from the first element in the list -/// and combines it with each subsequent element in turn using the given -/// function. The function is called as `fun(accumulator, current_element)`. -/// -/// Returns `Ok` to indicate a successful run, and `Error` if called on an -/// empty list. -/// -/// ## Examples -/// -/// ```gleam -/// [] |> reduce(fn(acc, x) { acc + x }) -/// // -> Error(Nil) -/// ``` -/// -/// ```gleam -/// [1, 2, 3, 4, 5] |> reduce(fn(acc, x) { acc + x }) -/// // -> Ok(15) -/// ``` -/// -pub fn reduce(over list: List(a), with fun: fn(a, a) -> a) -> Result(a, Nil) { - case list { - [] -> Error(Nil) - [first, ..rest] -> Ok(fold(rest, first, fun)) - } -} - -/// Similar to `fold`, but yields the state of the accumulator at each stage. -/// -/// ## Examples -/// -/// ```gleam -/// scan(over: [1, 2, 3], from: 100, with: fn(acc, i) { acc + i }) -/// // -> [101, 103, 106] -/// ``` -/// -pub fn scan( - over list: List(a), - from initial: acc, - with fun: fn(acc, a) -> acc, -) -> List(acc) { - scan_loop(list, initial, [], fun) -} - -fn scan_loop( - list: List(a), - accumulator: acc, - accumulated: List(acc), - fun: fn(acc, a) -> acc, -) -> List(acc) { - case list { - [] -> reverse(accumulated) - [first, ..rest] -> { - let next = fun(accumulator, first) - scan_loop(rest, next, [next, ..accumulated], fun) - } - } -} - -/// Returns the last element in the given list. -/// -/// Returns `Error(Nil)` if the list is empty. -/// -/// This function runs in linear time. -/// -/// ## Examples -/// -/// ```gleam -/// last([]) -/// // -> Error(Nil) -/// ``` -/// -/// ```gleam -/// last([1, 2, 3, 4, 5]) -/// // -> Ok(5) -/// ``` -/// -pub fn last(list: List(a)) -> Result(a, Nil) { - case list { - [] -> Error(Nil) - [last] -> Ok(last) - [_, ..rest] -> last(rest) - } -} - -/// Return unique combinations of elements in the list. -/// -/// ## Examples -/// -/// ```gleam -/// combinations([1, 2, 3], 2) -/// // -> [[1, 2], [1, 3], [2, 3]] -/// ``` -/// -/// ```gleam -/// combinations([1, 2, 3, 4], 3) -/// // -> [[1, 2, 3], [1, 2, 4], [1, 3, 4], [2, 3, 4]] -/// ``` -/// -pub fn combinations(items: List(a), by n: Int) -> List(List(a)) { - case n, items { - 0, _ -> [[]] - _, [] -> [] - _, [first, ..rest] -> - rest - |> combinations(n - 1) - |> map(fn(combination) { [first, ..combination] }) - |> reverse - |> fold(combinations(rest, n), fn(acc, c) { [c, ..acc] }) - } -} - -/// Return unique pair combinations of elements in the list. -/// -/// ## Examples -/// -/// ```gleam -/// combination_pairs([1, 2, 3]) -/// // -> [#(1, 2), #(1, 3), #(2, 3)] -/// ``` -/// -pub fn combination_pairs(items: List(a)) -> List(#(a, a)) { - combination_pairs_loop(items, []) -} - -fn combination_pairs_loop(items: List(a), acc: List(#(a, a))) -> List(#(a, a)) { - case items { - [] -> reverse(acc) - [first, ..rest] -> { - let first_combinations = map(rest, with: fn(other) { #(first, other) }) - let acc = reverse_and_prepend(first_combinations, acc) - combination_pairs_loop(rest, acc) - } - } -} - -/// Make a list alternating the elements from the given lists -/// -/// ## Examples -/// -/// ```gleam -/// interleave([[1, 2], [101, 102], [201, 202]]) -/// // -> [1, 101, 201, 2, 102, 202] -/// ``` -/// -pub fn interleave(list: List(List(a))) -> List(a) { - list - |> transpose - |> flatten -} - -/// Transpose rows and columns of the list of lists. -/// -/// Notice: This function is not tail recursive, -/// and thus may exceed stack size if called, -/// with large lists (on the JavaScript target). -/// -/// ## Examples -/// -/// ```gleam -/// transpose([[1, 2, 3], [101, 102, 103]]) -/// // -> [[1, 101], [2, 102], [3, 103]] -/// ``` -/// -pub fn transpose(list_of_lists: List(List(a))) -> List(List(a)) { - transpose_loop(list_of_lists, []) -} - -fn transpose_loop(rows: List(List(a)), columns: List(List(a))) -> List(List(a)) { - case rows { - [] -> reverse(columns) - _ -> { - let #(column, rest) = take_firsts(rows, [], []) - case column { - [_, ..] -> transpose_loop(rest, [column, ..columns]) - [] -> transpose_loop(rest, columns) - } - } - } -} - -fn take_firsts( - rows: List(List(a)), - column: List(a), - remaining_rows: List(List(a)), -) -> #(List(a), List(List(a))) { - case rows { - [] -> #(reverse(column), reverse(remaining_rows)) - [[], ..rest] -> take_firsts(rest, column, remaining_rows) - [[first, ..remaining_row], ..rest_rows] -> { - let remaining_rows = [remaining_row, ..remaining_rows] - take_firsts(rest_rows, [first, ..column], remaining_rows) - } - } -} - -/// Takes a list, randomly sorts all items and returns the shuffled list. -/// -/// This function uses `float.random` to decide the order of the elements. -/// -/// ## Example -/// -/// ```gleam -/// range(1, 10) |> shuffle() -/// // -> [1, 6, 9, 10, 3, 8, 4, 2, 7, 5] -/// ``` -/// -pub fn shuffle(list: List(a)) -> List(a) { - list - |> fold(from: [], with: fn(acc, a) { [#(float.random(), a), ..acc] }) - |> do_shuffle_by_pair_indexes() - |> shuffle_pair_unwrap_loop([]) -} - -fn shuffle_pair_unwrap_loop(list: List(#(Float, a)), acc: List(a)) -> List(a) { - case list { - [] -> acc - [elem_pair, ..enumerable] -> - shuffle_pair_unwrap_loop(enumerable, [elem_pair.1, ..acc]) - } -} - -fn do_shuffle_by_pair_indexes( - list_of_pairs: List(#(Float, a)), -) -> List(#(Float, a)) { - sort(list_of_pairs, fn(a_pair: #(Float, a), b_pair: #(Float, a)) -> Order { - float.compare(a_pair.0, b_pair.0) - }) -} - -/// Takes a list and a comparator, and returns the maximum element in the list -/// -/// -/// ## Example -/// -/// ```gleam -/// range(1, 10) |> list.max(int.compare) -/// // -> Ok(10) -/// ``` -/// -/// ```gleam -/// ["a", "c", "b"] |> list.max(string.compare) -/// // -> Ok("c") -/// ``` -pub fn max( - over list: List(a), - with compare: fn(a, a) -> Order, -) -> Result(a, Nil) { - case list { - [] -> Error(Nil) - [first, ..rest] -> Ok(max_loop(rest, compare, first)) - } -} - -fn max_loop(list, compare, max) { - case list { - [] -> max - [first, ..rest] -> - case compare(first, max) { - order.Gt -> max_loop(rest, compare, first) - order.Lt | order.Eq -> max_loop(rest, compare, max) - } - } -} - -/// Returns a random sample of up to n elements from a list using reservoir -/// sampling via [Algorithm L](https://en.wikipedia.org/wiki/Reservoir_sampling#Optimal:_Algorithm_L). -/// Returns an empty list if the sample size is less than or equal to 0. -/// -/// Order is not random, only selection is. -/// -/// ## Examples -/// -/// ```gleam -/// reservoir_sample([1, 2, 3, 4, 5], 3) -/// // -> [2, 4, 5] // A random sample of 3 items -/// ``` -/// -pub fn sample(from list: List(a), up_to n: Int) -> List(a) { - let #(reservoir, rest) = build_reservoir(from: list, sized: n) - - case dict.is_empty(reservoir) { - // If the reservoire is empty that means we were asking to sample 0 or - // less items. That doesn't make much sense, so we just return an empty - // list. - True -> [] - - // Otherwise we keep looping over the remaining part of the list replacing - // random elements in the reservoir. - False -> { - let w = float.exponential(log_random() /. int.to_float(n)) - dict.values(sample_loop(rest, reservoir, n, w)) - } - } -} - -fn sample_loop( - list: List(a), - reservoir: Dict(Int, a), - n: Int, - w: Float, -) -> Dict(Int, a) { - let skip = { - let assert Ok(log) = float.logarithm(1.0 -. w) - float.round(float.floor(log_random() /. log)) - } - - case drop(list, skip) { - [] -> reservoir - [first, ..rest] -> { - let reservoir = dict.insert(reservoir, int.random(n), first) - let w = w *. float.exponential(log_random() /. int.to_float(n)) - sample_loop(rest, reservoir, n, w) - } - } -} - -const min_positive = 2.2250738585072014e-308 - -fn log_random() -> Float { - let assert Ok(random) = float.logarithm(float.random() +. min_positive) - random -} - -/// Builds the initial reservoir used by Algorithm L. -/// This is a dictionary with keys ranging from `0` up to `n - 1` where each -/// value is the corresponding element at that position in `list`. -/// -/// This also returns the remaining elements of `list` that didn't end up in -/// the reservoir. -/// -fn build_reservoir(from list: List(a), sized n: Int) -> #(Dict(Int, a), List(a)) { - build_reservoir_loop(list, n, dict.new()) -} - -fn build_reservoir_loop( - list: List(a), - size: Int, - reservoir: Dict(Int, a), -) -> #(Dict(Int, a), List(a)) { - let reservoir_size = dict.size(reservoir) - case reservoir_size >= size { - // The reservoir already has the size we wanted. - True -> #(reservoir, list) - - // Otherwise we add another element from the list to the reservoir - False -> - case list { - [] -> #(reservoir, []) - [first, ..rest] -> { - let reservoir = dict.insert(reservoir, reservoir_size, first) - build_reservoir_loop(rest, size, reservoir) - } - } - } -} diff --git a/build/packages/gleam_stdlib/src/gleam/option.gleam b/build/packages/gleam_stdlib/src/gleam/option.gleam deleted file mode 100644 index af5d864..0000000 --- a/build/packages/gleam_stdlib/src/gleam/option.gleam +++ /dev/null @@ -1,358 +0,0 @@ -/// `Option` represents a value that may be present or not. `Some` means the value is -/// present, `None` means the value is not. -/// -/// This is Gleam's alternative to having a value that could be Null, as is -/// possible in some other languages. -/// -/// ## `Option` and `Result` -/// -/// In other languages fallible functions may return either `Result` or -/// `Option` depending on whether there is more information to be given about the -/// failure. In Gleam all fallible functions return `Result`, and `Nil` is used -/// as the error if there is no extra detail to give. This consistency removes -/// the boilerplate that would otherwise be needed to convert between `Option` -/// and `Result` types, and makes APIs more predictable. -/// -/// The `Option` type should only be used for taking optional values as -/// function arguments, or for storing them in other data structures. -/// -pub type Option(a) { - Some(a) - 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 -/// ``` -/// -pub fn all(list: List(Option(a))) -> Option(List(a)) { - all_loop(list, []) -} - -fn all_loop(list: List(Option(a)), acc: List(a)) -> Option(List(a)) { - case list { - [] -> Some(reverse(acc)) - [None, ..] -> None - [Some(first), ..rest] -> all_loop(rest, [first, ..acc]) - } -} - -// This is copied from the list module and not imported as importing it would -// result in a circular dependency! -@external(erlang, "lists", "reverse") -fn reverse(list: List(a)) -> List(a) { - reverse_and_prepend(list, []) -} - -fn reverse_and_prepend(list prefix: List(a), to suffix: List(a)) -> List(a) { - case prefix { - [] -> suffix - [first, ..rest] -> reverse_and_prepend(list: rest, to: [first, ..suffix]) - } -} - -/// Checks whether the `Option` is a `Some` value. -/// -/// ## Examples -/// -/// ```gleam -/// is_some(Some(1)) -/// // -> True -/// ``` -/// -/// ```gleam -/// is_some(None) -/// // -> False -/// ``` -/// -pub fn is_some(option: Option(a)) -> Bool { - option != None -} - -/// Checks whether the `Option` is a `None` value. -/// -/// ## Examples -/// -/// ```gleam -/// is_none(Some(1)) -/// // -> False -/// ``` -/// -/// ```gleam -/// is_none(None) -/// // -> True -/// ``` -/// -pub fn is_none(option: Option(a)) -> Bool { - option == 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") -/// ``` -/// -pub fn to_result(option: Option(a), e) -> Result(a, e) { - case option { - Some(a) -> Ok(a) - None -> 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 -/// ``` -/// -pub fn from_result(result: Result(a, e)) -> Option(a) { - case result { - Ok(a) -> Some(a) - Error(_) -> 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 -/// ``` -/// -pub fn unwrap(option: Option(a), or default: a) -> a { - case option { - Some(x) -> x - None -> 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 -/// ``` -/// -pub fn lazy_unwrap(option: Option(a), or default: fn() -> a) -> a { - case option { - Some(x) -> x - None -> 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 -/// ``` -/// -pub fn map(over option: Option(a), with fun: fn(a) -> b) -> Option(b) { - case option { - Some(x) -> Some(fun(x)) - None -> None - } -} - -/// 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 -/// ``` -/// -pub fn flatten(option: Option(Option(a))) -> Option(a) { - case option { - Some(x) -> x - None -> None - } -} - -/// 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 -/// ``` -/// -pub fn then(option: Option(a), apply fun: fn(a) -> Option(b)) -> Option(b) { - case option { - Some(x) -> fun(x) - None -> None - } -} - -/// 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 -/// ``` -/// -pub fn or(first: Option(a), second: Option(a)) -> Option(a) { - case first { - Some(_) -> first - None -> 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 -/// ``` -/// -pub fn lazy_or(first: Option(a), second: fn() -> Option(a)) -> Option(a) { - case first { - Some(_) -> first - None -> second() - } -} - -/// Given a list of `Option`s, -/// returns only the values inside `Some`. -/// -/// ## Examples -/// -/// ```gleam -/// values([Some(1), None, Some(3)]) -/// // -> [1, 3] -/// ``` -/// -pub fn values(options: List(Option(a))) -> List(a) { - values_loop(options, []) -} - -fn values_loop(list: List(Option(a)), acc: List(a)) -> List(a) { - case list { - [] -> reverse(acc) - [None, ..rest] -> values_loop(rest, acc) - [Some(first), ..rest] -> values_loop(rest, [first, ..acc]) - } -} diff --git a/build/packages/gleam_stdlib/src/gleam/order.gleam b/build/packages/gleam_stdlib/src/gleam/order.gleam deleted file mode 100644 index be8b599..0000000 --- a/build/packages/gleam_stdlib/src/gleam/order.gleam +++ /dev/null @@ -1,156 +0,0 @@ -/// Represents the result of a single comparison to determine the precise -/// ordering of two values. -/// -pub type Order { - /// Less-than - Lt - - /// Equal - Eq - - /// Greater than - 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 -/// ``` -/// -pub fn negate(order: Order) -> Order { - case order { - Lt -> Gt - Eq -> Eq - Gt -> Lt - } -} - -/// Produces a numeric representation of the order. -/// -/// ## Examples -/// -/// ```gleam -/// to_int(Lt) -/// // -> -1 -/// ``` -/// -/// ```gleam -/// to_int(Eq) -/// // -> 0 -/// ``` -/// -/// ```gleam -/// to_int(Gt) -/// // -> 1 -/// ``` -/// -pub fn to_int(order: Order) -> Int { - case order { - Lt -> -1 - Eq -> 0 - Gt -> 1 - } -} - -/// Compares two `Order` values to one another, producing a new `Order`. -/// -/// ## Examples -/// -/// ```gleam -/// compare(Eq, with: Lt) -/// // -> Gt -/// ``` -/// -pub fn compare(a: Order, with b: Order) -> Order { - case a, b { - x, y if x == y -> Eq - Lt, _ | Eq, Gt -> Lt - _, _ -> 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] -/// ``` -/// -pub fn reverse(orderer: fn(a, a) -> Order) -> fn(a, a) -> Order { - fn(a, b) { 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 -/// ``` -/// -pub fn break_tie(in order: Order, with other: Order) -> Order { - case order { - Lt | Gt -> order - Eq -> other - } -} - -/// 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 -/// ``` -/// -pub fn lazy_break_tie(in order: Order, with comparison: fn() -> Order) -> Order { - case order { - Lt | Gt -> order - Eq -> comparison() - } -} diff --git a/build/packages/gleam_stdlib/src/gleam/pair.gleam b/build/packages/gleam_stdlib/src/gleam/pair.gleam deleted file mode 100644 index 566fc9c..0000000 --- a/build/packages/gleam_stdlib/src/gleam/pair.gleam +++ /dev/null @@ -1,85 +0,0 @@ -/// Returns the first element in a pair. -/// -/// ## Examples -/// -/// ```gleam -/// first(#(1, 2)) -/// // -> 1 -/// ``` -/// -pub fn first(pair: #(a, b)) -> a { - let #(a, _) = pair - a -} - -/// Returns the second element in a pair. -/// -/// ## Examples -/// -/// ```gleam -/// second(#(1, 2)) -/// // -> 2 -/// ``` -/// -pub fn second(pair: #(a, b)) -> b { - let #(_, a) = pair - a -} - -/// Returns a new pair with the elements swapped. -/// -/// ## Examples -/// -/// ```gleam -/// swap(#(1, 2)) -/// // -> #(2, 1) -/// ``` -/// -pub fn swap(pair: #(a, b)) -> #(b, a) { - let #(a, b) = pair - #(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) -/// ``` -/// -pub fn map_first(of pair: #(a, b), with fun: fn(a) -> c) -> #(c, b) { - let #(a, b) = pair - #(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) -/// ``` -/// -pub fn map_second(of pair: #(a, b), with fun: fn(b) -> c) -> #(a, c) { - let #(a, b) = pair - #(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) -/// ``` -/// -pub fn new(first: a, second: b) -> #(a, b) { - #(first, second) -} diff --git a/build/packages/gleam_stdlib/src/gleam/result.gleam b/build/packages/gleam_stdlib/src/gleam/result.gleam deleted file mode 100644 index 741754d..0000000 --- a/build/packages/gleam_stdlib/src/gleam/result.gleam +++ /dev/null @@ -1,453 +0,0 @@ -//// Result represents the result of something that may succeed or not. -//// `Ok` means it was successful, `Error` means it was not successful. - -import gleam/list - -/// Checks whether the result is an `Ok` value. -/// -/// ## Examples -/// -/// ```gleam -/// is_ok(Ok(1)) -/// // -> True -/// ``` -/// -/// ```gleam -/// is_ok(Error(Nil)) -/// // -> False -/// ``` -/// -pub fn is_ok(result: Result(a, e)) -> Bool { - case result { - Error(_) -> False - Ok(_) -> True - } -} - -/// Checks whether the result is an `Error` value. -/// -/// ## Examples -/// -/// ```gleam -/// is_error(Ok(1)) -/// // -> False -/// ``` -/// -/// ```gleam -/// is_error(Error(Nil)) -/// // -> True -/// ``` -/// -pub fn is_error(result: Result(a, e)) -> Bool { - case result { - Ok(_) -> False - Error(_) -> 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) -/// ``` -/// -pub fn map(over result: Result(a, e), with fun: fn(a) -> b) -> Result(b, e) { - case result { - Ok(x) -> Ok(fun(x)) - Error(e) -> Error(e) - } -} - -/// 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) -/// ``` -/// -pub fn map_error( - over result: Result(a, e), - with fun: fn(e) -> f, -) -> Result(a, f) { - case result { - Ok(x) -> Ok(x) - Error(error) -> 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) -/// ``` -/// -pub fn flatten(result: Result(Result(a, e), e)) -> Result(a, e) { - case result { - Ok(x) -> x - Error(error) -> Error(error) - } -} - -/// "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) -/// ``` -/// -pub fn try( - result: Result(a, e), - apply fun: fn(a) -> Result(b, e), -) -> Result(b, e) { - case result { - Ok(x) -> fun(x) - Error(e) -> Error(e) - } -} - -@deprecated("This function is an alias of result.try, use that instead") -pub fn then( - result: Result(a, e), - apply fun: fn(a) -> Result(b, e), -) -> Result(b, e) { - 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 -/// ``` -/// -pub fn unwrap(result: Result(a, e), or default: a) -> a { - case result { - Ok(v) -> v - Error(_) -> 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 -/// ``` -/// -pub fn lazy_unwrap(result: Result(a, e), or default: fn() -> a) -> a { - case result { - Ok(v) -> v - Error(_) -> 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 -/// ``` -/// -pub fn unwrap_error(result: Result(a, e), or default: e) -> e { - case result { - Ok(_) -> default - Error(e) -> e - } -} - -@deprecated("Use a case expression instead of this function") -pub fn unwrap_both(result: Result(a, a)) -> a { - case result { - Ok(a) -> a - Error(a) -> 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") -/// ``` -/// -pub fn or(first: Result(a, e), second: Result(a, e)) -> Result(a, e) { - case first { - Ok(_) -> first - Error(_) -> 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") -/// ``` -/// -pub fn lazy_or( - first: Result(a, e), - second: fn() -> Result(a, e), -) -> Result(a, e) { - case first { - Ok(_) -> first - Error(_) -> 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") -/// ``` -/// -pub fn all(results: List(Result(a, e))) -> Result(List(a), e) { - list.try_map(results, fn(result) { result }) -} - -/// 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"]) -/// ``` -/// -pub fn partition(results: List(Result(a, e))) -> #(List(a), List(e)) { - partition_loop(results, [], []) -} - -fn partition_loop(results: List(Result(a, e)), oks: List(a), errors: List(e)) { - case results { - [] -> #(oks, errors) - [Ok(a), ..rest] -> partition_loop(rest, [a, ..oks], errors) - [Error(e), ..rest] -> partition_loop(rest, oks, [e, ..errors]) - } -} - -/// Replace the value within a result -/// -/// ## Examples -/// -/// ```gleam -/// replace(Ok(1), Nil) -/// // -> Ok(Nil) -/// ``` -/// -/// ```gleam -/// replace(Error(1), Nil) -/// // -> Error(1) -/// ``` -/// -pub fn replace(result: Result(a, e), value: b) -> Result(b, e) { - case result { - Ok(_) -> Ok(value) - Error(error) -> Error(error) - } -} - -/// Replace the error within a result -/// -/// ## Examples -/// -/// ```gleam -/// replace_error(Error(1), Nil) -/// // -> Error(Nil) -/// ``` -/// -/// ```gleam -/// replace_error(Ok(1), Nil) -/// // -> Ok(1) -/// ``` -/// -pub fn replace_error(result: Result(a, e), error: f) -> Result(a, f) { - case result { - Ok(x) -> Ok(x) - Error(_) -> Error(error) - } -} - -/// Given a list of results, returns only the values inside `Ok`. -/// -/// ## Examples -/// -/// ```gleam -/// values([Ok(1), Error("a"), Ok(3)]) -/// // -> [1, 3] -/// ``` -/// -pub fn values(results: List(Result(a, e))) -> List(a) { - list.filter_map(results, fn(result) { 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") -/// ``` -/// -pub fn try_recover( - result: Result(a, e), - with fun: fn(e) -> Result(a, f), -) -> Result(a, f) { - case result { - Ok(value) -> Ok(value) - Error(error) -> fun(error) - } -} diff --git a/build/packages/gleam_stdlib/src/gleam/set.gleam b/build/packages/gleam_stdlib/src/gleam/set.gleam deleted file mode 100644 index 6ae5e9e..0000000 --- a/build/packages/gleam_stdlib/src/gleam/set.gleam +++ /dev/null @@ -1,407 +0,0 @@ -import gleam/dict.{type Dict} -import gleam/list -import gleam/result - -// A list is used as the dict value as an empty list has the smallest -// representation in Erlang's binary format -@target(erlang) -type Token = - List(Nil) - -@target(erlang) -const token = [] - -@target(javascript) -type Token = - Nil - -@target(javascript) -const token = Nil - -/// A set is a collection of unique members of the same type. -/// -/// It is implemented using the `gleam/dict` module, so inserts and lookups have -/// logarithmic time complexity. -/// -pub opaque type Set(member) { - Set(dict: Dict(member, Token)) -} - -/// Creates a new empty set. -/// -pub fn new() -> Set(member) { - 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 -/// ``` -/// -pub fn size(set: Set(member)) -> Int { - 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 -/// ``` -/// -pub fn is_empty(set: Set(member)) -> Bool { - set == new() -} - -/// Inserts an member into the set. -/// -/// This function runs in logarithmic time. -/// -/// ## Examples -/// -/// ```gleam -/// new() -/// |> insert(1) -/// |> insert(2) -/// |> size -/// // -> 2 -/// ``` -/// -pub fn insert(into set: Set(member), this member: member) -> Set(member) { - Set(dict: dict.insert(set.dict, member, token)) -} - -/// 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 -/// ``` -/// -pub fn contains(in set: Set(member), this member: member) -> Bool { - set.dict - |> dict.get(member) - |> result.is_ok -} - -/// 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 -/// ``` -/// -pub fn delete(from set: Set(member), this member: member) -> Set(member) { - Set(dict: 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] -/// ``` -/// -pub fn to_list(set: Set(member)) -> List(member) { - dict.keys(set.dict) -} - -/// 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] -/// ``` -/// -pub fn from_list(members: List(member)) -> Set(member) { - let dict = - list.fold(over: members, from: dict.new(), with: fn(m, k) { - dict.insert(m, k, token) - }) - 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 -/// ``` -/// -pub fn fold( - over set: Set(member), - from initial: acc, - with reducer: fn(acc, member) -> acc, -) -> acc { - dict.fold(over: set.dict, from: initial, with: fn(a, k, _) { 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] -/// ``` -/// -pub fn filter( - in set: Set(member), - keeping predicate: fn(member) -> Bool, -) -> Set(member) { - Set(dict.filter(in: set.dict, keeping: fn(m, _) { predicate(m) })) -} - -/// 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] -/// ``` -pub fn map(set: Set(member), with fun: fn(member) -> mapped) -> Set(mapped) { - fold(over: set, from: new(), with: fn(acc, member) { - insert(acc, fun(member)) - }) -} - -/// 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] -/// ``` -pub fn drop(from set: Set(member), drop disallowed: List(member)) -> Set(member) { - list.fold(over: disallowed, from: set, with: 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] -/// ``` -/// -pub fn take(from set: Set(member), keeping desired: List(member)) -> Set(member) { - Set(dict.take(from: set.dict, keeping: desired)) -} - -/// 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] -/// ``` -/// -pub fn union(of first: Set(member), and second: Set(member)) -> Set(member) { - let #(larger, smaller) = order(first, second) - fold(over: smaller, from: larger, with: insert) -} - -fn order(first: Set(member), second: Set(member)) -> #(Set(member), Set(member)) { - case dict.size(first.dict) > dict.size(second.dict) { - True -> #(first, second) - False -> #(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] -/// ``` -/// -pub fn intersection( - of first: Set(member), - and second: Set(member), -) -> Set(member) { - let #(larger, smaller) = order(first, second) - take(from: larger, keeping: 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] -/// ``` -/// -pub fn difference( - from first: Set(member), - minus second: Set(member), -) -> Set(member) { - drop(from: first, drop: 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 -/// ``` -/// -pub fn is_subset(first: Set(member), of second: Set(member)) -> Bool { - intersection(of: first, and: 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 -/// ``` -/// -pub fn is_disjoint(first: Set(member), from second: Set(member)) -> Bool { - intersection(of: first, and: second) == new() -} - -/// 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] -/// ``` -/// -pub fn symmetric_difference( - of first: Set(member), - and second: Set(member), -) -> Set(member) { - difference( - from: union(of: first, and: second), - minus: intersection(of: first, and: second), - ) -} - -/// 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. -/// -pub fn each(set: Set(member), fun: fn(member) -> a) -> Nil { - fold(set, Nil, fn(nil, member) { - fun(member) - nil - }) -} diff --git a/build/packages/gleam_stdlib/src/gleam/string.gleam b/build/packages/gleam_stdlib/src/gleam/string.gleam deleted file mode 100644 index c5945b5..0000000 --- a/build/packages/gleam_stdlib/src/gleam/string.gleam +++ /dev/null @@ -1,900 +0,0 @@ -//// Strings in Gleam are UTF-8 binaries. They can be written in your code as -//// text surrounded by `"double quotes"`. - -import gleam/list -import gleam/option.{type Option, None, Some} -import gleam/order -import gleam/string_tree.{type StringTree} - -/// Determines if a `String` is empty. -/// -/// ## Examples -/// -/// ```gleam -/// is_empty("") -/// // -> True -/// ``` -/// -/// ```gleam -/// is_empty("the world") -/// // -> False -/// ``` -/// -pub fn is_empty(str: String) -> Bool { - str == "" -} - -/// Gets the number of grapheme clusters in a given `String`. -/// -/// This function has to iterate across the whole string to count the number of -/// graphemes, so it runs in linear time. Avoid using this in a loop. -/// -/// ## Examples -/// -/// ```gleam -/// length("Gleam") -/// // -> 5 -/// ``` -/// -/// ```gleam -/// length("ß↑e̊") -/// // -> 3 -/// ``` -/// -/// ```gleam -/// length("") -/// // -> 0 -/// ``` -/// -@external(erlang, "string", "length") -@external(javascript, "../gleam_stdlib.mjs", "string_length") -pub fn length(string: String) -> Int - -/// 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" -/// ``` -/// -pub fn reverse(string: String) -> String { - string - |> string_tree.from_string - |> string_tree.reverse - |> string_tree.to_string -} - -/// 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" -/// ``` -/// -pub fn replace( - in string: String, - each pattern: String, - with substitute: String, -) -> String { - string - |> string_tree.from_string - |> string_tree.replace(each: pattern, with: substitute) - |> string_tree.to_string -} - -/// Creates a new `String` with all the graphemes in the input `String` converted to -/// lowercase. -/// -/// Useful for case-insensitive comparisons. -/// -/// ## Examples -/// -/// ```gleam -/// lowercase("X-FILES") -/// // -> "x-files" -/// ``` -/// -@external(erlang, "string", "lowercase") -@external(javascript, "../gleam_stdlib.mjs", "lowercase") -pub fn lowercase(string: String) -> String - -/// Creates a new `String` with all the graphemes in the input `String` converted to -/// uppercase. -/// -/// Useful for case-insensitive comparisons and VIRTUAL YELLING. -/// -/// ## Examples -/// -/// ```gleam -/// uppercase("skinner") -/// // -> "SKINNER" -/// ``` -/// -@external(erlang, "string", "uppercase") -@external(javascript, "../gleam_stdlib.mjs", "uppercase") -pub fn uppercase(string: String) -> String - -/// 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 -/// ``` -/// -pub fn compare(a: String, b: String) -> order.Order { - case a == b { - True -> order.Eq - _ -> - case less_than(a, b) { - True -> order.Lt - False -> order.Gt - } - } -} - -@external(erlang, "gleam_stdlib", "less_than") -@external(javascript, "../gleam_stdlib.mjs", "less_than") -fn less_than(a: String, b: String) -> Bool - -/// 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) -/// // -> "" -/// ``` -/// -pub fn slice(from string: String, at_index idx: Int, length len: Int) -> String { - case len <= 0 { - True -> "" - False -> - case idx < 0 { - True -> { - let translated_idx = length(string) + idx - case translated_idx < 0 { - True -> "" - False -> grapheme_slice(string, translated_idx, len) - } - } - False -> grapheme_slice(string, idx, len) - } - } -} - -@external(erlang, "gleam_stdlib", "slice") -@external(javascript, "../gleam_stdlib.mjs", "string_grapheme_slice") -fn grapheme_slice(string: String, index: Int, length: Int) -> String - -@external(erlang, "binary", "part") -@external(javascript, "../gleam_stdlib.mjs", "string_byte_slice") -fn unsafe_byte_slice(string: String, index: Int, length: Int) -> String - -/// Drops contents of the first `String` that occur before the second `String`. -/// If the `from` string does not contain the `before` string, `from` is -/// returned unchanged. -/// -/// ## Examples -/// -/// ```gleam -/// crop(from: "The Lone Gunmen", before: "Lone") -/// // -> "Lone Gunmen" -/// ``` -/// -@external(erlang, "gleam_stdlib", "crop_string") -@external(javascript, "../gleam_stdlib.mjs", "crop_string") -pub fn crop(from string: String, before substring: String) -> String - -/// 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" -/// ``` -/// -pub fn drop_start(from string: String, up_to num_graphemes: Int) -> String { - case num_graphemes <= 0 { - True -> string - False -> { - let prefix = grapheme_slice(string, 0, num_graphemes) - let prefix_size = byte_size(prefix) - unsafe_byte_slice(string, prefix_size, byte_size(string) - prefix_size) - } - } -} - -/// 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" -/// ``` -/// -pub fn drop_end(from string: String, up_to num_graphemes: Int) -> String { - case num_graphemes <= 0 { - True -> string - False -> slice(string, 0, length(string) - num_graphemes) - } -} - -/// Checks if the first `String` contains the second. -/// -/// ## Examples -/// -/// ```gleam -/// contains(does: "theory", contain: "ory") -/// // -> True -/// ``` -/// -/// ```gleam -/// contains(does: "theory", contain: "the") -/// // -> True -/// ``` -/// -/// ```gleam -/// contains(does: "theory", contain: "THE") -/// // -> False -/// ``` -/// -@external(erlang, "gleam_stdlib", "contains_string") -@external(javascript, "../gleam_stdlib.mjs", "contains_string") -pub fn contains(does haystack: String, contain needle: String) -> Bool - -/// Checks whether the first `String` starts with the second one. -/// -/// ## Examples -/// -/// ```gleam -/// starts_with("theory", "ory") -/// // -> False -/// ``` -/// -@external(erlang, "gleam_stdlib", "string_starts_with") -@external(javascript, "../gleam_stdlib.mjs", "starts_with") -pub fn starts_with(string: String, prefix: String) -> Bool - -/// Checks whether the first `String` ends with the second one. -/// -/// ## Examples -/// -/// ```gleam -/// ends_with("theory", "ory") -/// // -> True -/// ``` -/// -@external(erlang, "gleam_stdlib", "string_ends_with") -@external(javascript, "../gleam_stdlib.mjs", "ends_with") -pub fn ends_with(string: String, suffix: String) -> Bool - -/// 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", ""] -/// ``` -/// -pub fn split(x: String, on substring: String) -> List(String) { - case substring { - "" -> to_graphemes(x) - _ -> - x - |> string_tree.from_string - |> string_tree.split(on: substring) - |> list.map(with: string_tree.to_string) - } -} - -/// Splits a `String` a single time on the given substring. -/// -/// Returns an `Error` if substring not present. -/// -/// ## Examples -/// -/// ```gleam -/// split_once("home/gleam/desktop/", on: "/") -/// // -> Ok(#("home", "gleam/desktop/")) -/// ``` -/// -/// ```gleam -/// split_once("home/gleam/desktop/", on: "?") -/// // -> Error(Nil) -/// ``` -/// -@external(javascript, "../gleam_stdlib.mjs", "split_once") -pub fn split_once( - string: String, - on substring: String, -) -> Result(#(String, String), Nil) { - case erl_split(string, substring) { - [first, rest] -> Ok(#(first, rest)) - _ -> Error(Nil) - } -} - -@external(erlang, "string", "split") -fn erl_split(a: String, b: String) -> List(String) - -/// 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" -/// ``` -/// -pub fn append(to first: String, suffix second: String) -> String { - first <> second -} - -/// 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" -/// ``` -/// -@external(erlang, "erlang", "list_to_binary") -pub fn concat(strings: List(String)) -> String { - concat_loop(strings, "") -} - -fn concat_loop(strings: List(String), accumulator: String) -> String { - case strings { - [string, ..strings] -> concat_loop(strings, accumulator <> string) - [] -> accumulator - } -} - -/// 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" -/// ``` -/// -pub fn repeat(string: String, times times: Int) -> String { - case times <= 0 { - True -> "" - False -> repeat_loop(times, string, "") - } -} - -fn repeat_loop(times: Int, doubling_acc: String, acc: String) -> String { - let acc = case times % 2 { - 0 -> acc - _ -> acc <> doubling_acc - } - let times = times / 2 - case times <= 0 { - True -> acc - False -> repeat_loop(times, doubling_acc <> doubling_acc, acc) - } -} - -/// 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" -/// ``` -/// -pub fn join(strings: List(String), with separator: String) -> String { - case strings { - [] -> "" - [first, ..rest] -> join_loop(rest, separator, first) - } -} - -fn join_loop( - strings: List(String), - separator: String, - accumulator: String, -) -> String { - case strings { - [] -> accumulator - [string, ..strings] -> - join_loop(strings, separator, accumulator <> separator <> string) - } -} - -/// 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" -/// ``` -/// -pub fn pad_start( - string: String, - to desired_length: Int, - with pad_string: String, -) -> String { - let current_length = length(string) - let to_pad_length = desired_length - current_length - - case to_pad_length <= 0 { - True -> string - False -> 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" -/// ``` -/// -pub fn pad_end( - string: String, - to desired_length: Int, - with pad_string: String, -) -> String { - let current_length = length(string) - let to_pad_length = desired_length - current_length - - case to_pad_length <= 0 { - True -> string - False -> string <> padding(to_pad_length, pad_string) - } -} - -fn padding(size: Int, pad_string: String) -> String { - let pad_string_length = length(pad_string) - let num_pads = size / pad_string_length - let extra = size % pad_string_length - - repeat(pad_string, num_pads) <> slice(pad_string, 0, extra) -} - -/// 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" -/// ``` -/// -pub fn trim(string: String) -> String { - string |> trim_start |> trim_end -} - -@external(erlang, "string", "trim") -fn erl_trim(a: String, b: Direction) -> String - -type Direction { - Leading - Trailing -} - -/// Removes whitespace at the start of a `String`. -/// -/// ## Examples -/// -/// ```gleam -/// trim_start(" hats \n") -/// // -> "hats \n" -/// ``` -/// -@external(javascript, "../gleam_stdlib.mjs", "trim_start") -pub fn trim_start(string: String) -> String { - erl_trim(string, Leading) -} - -/// Removes whitespace at the end of a `String`. -/// -/// ## Examples -/// -/// ```gleam -/// trim_end(" hats \n") -/// // -> " hats" -/// ``` -/// -@external(javascript, "../gleam_stdlib.mjs", "trim_end") -pub fn trim_end(string: String) -> String { - erl_trim(string, Trailing) -} - -/// Splits a non-empty `String` into its first element (head) and rest (tail). -/// This lets you pattern match on `String`s exactly as you would with lists. -/// -/// ## Performance -/// -/// There is a notable overhead to using this function, so you may not want to -/// use it in a tight loop. If you wish to efficiently parse a string you may -/// want to use alternatives such as the [splitter package](https://hex.pm/packages/splitter). -/// -/// ## Examples -/// -/// ```gleam -/// pop_grapheme("gleam") -/// // -> Ok(#("g", "leam")) -/// ``` -/// -/// ```gleam -/// pop_grapheme("") -/// // -> Error(Nil) -/// ``` -/// -@external(erlang, "gleam_stdlib", "string_pop_grapheme") -@external(javascript, "../gleam_stdlib.mjs", "pop_grapheme") -pub fn pop_grapheme(string: String) -> Result(#(String, String), Nil) - -/// Converts a `String` to a list of -/// [graphemes](https://en.wikipedia.org/wiki/Grapheme). -/// -/// ```gleam -/// to_graphemes("abc") -/// // -> ["a", "b", "c"] -/// ``` -/// -@external(javascript, "../gleam_stdlib.mjs", "graphemes") -pub fn to_graphemes(string: String) -> List(String) { - string - |> to_graphemes_loop([]) - |> list.reverse -} - -fn to_graphemes_loop(string: String, acc: List(String)) -> List(String) { - case pop_grapheme(string) { - Ok(#(grapheme, rest)) -> to_graphemes_loop(rest, [grapheme, ..acc]) - Error(_) -> acc - } -} - -@external(erlang, "gleam_stdlib", "identity") -@external(javascript, "../gleam_stdlib.mjs", "codepoint") -fn unsafe_int_to_utf_codepoint(a: Int) -> UtfCodepoint - -/// Converts a `String` to a `List` of `UtfCodepoint`. -/// -/// See and -/// for an -/// explanation on code points. -/// -/// ## Examples -/// -/// ```gleam -/// "a" |> to_utf_codepoints -/// // -> [UtfCodepoint(97)] -/// ``` -/// -/// ```gleam -/// // Semantically the same as: -/// // ["🏳", "️", "‍", "🌈"] or: -/// // [waving_white_flag, variant_selector_16, zero_width_joiner, rainbow] -/// "🏳️‍🌈" |> to_utf_codepoints -/// // -> [ -/// // UtfCodepoint(127987), -/// // UtfCodepoint(65039), -/// // UtfCodepoint(8205), -/// // UtfCodepoint(127752), -/// // ] -/// ``` -/// -pub fn to_utf_codepoints(string: String) -> List(UtfCodepoint) { - do_to_utf_codepoints(string) -} - -@target(erlang) -fn do_to_utf_codepoints(string: String) -> List(UtfCodepoint) { - to_utf_codepoints_loop(<>, []) -} - -@target(erlang) -fn to_utf_codepoints_loop( - bit_array: BitArray, - acc: List(UtfCodepoint), -) -> List(UtfCodepoint) { - case bit_array { - <> -> - to_utf_codepoints_loop(rest, [first, ..acc]) - _ -> list.reverse(acc) - } -} - -@target(javascript) -fn do_to_utf_codepoints(string: String) -> List(UtfCodepoint) { - string - |> string_to_codepoint_integer_list - |> list.map(unsafe_int_to_utf_codepoint) -} - -@target(javascript) -@external(javascript, "../gleam_stdlib.mjs", "string_to_codepoint_integer_list") -fn string_to_codepoint_integer_list(string: String) -> List(Int) - -/// Converts a `List` of `UtfCodepoint`s to a `String`. -/// -/// See and -/// for an -/// explanation on code points. -/// -/// ## Examples -/// -/// ```gleam -/// let assert Ok(a) = utf_codepoint(97) -/// let assert Ok(b) = utf_codepoint(98) -/// let assert Ok(c) = utf_codepoint(99) -/// from_utf_codepoints([a, b, c]) -/// // -> "abc" -/// ``` -/// -@external(erlang, "gleam_stdlib", "utf_codepoint_list_to_string") -@external(javascript, "../gleam_stdlib.mjs", "utf_codepoint_list_to_string") -pub fn from_utf_codepoints(utf_codepoints: List(UtfCodepoint)) -> String - -/// Converts an integer to a `UtfCodepoint`. -/// -/// Returns an `Error` if the integer does not represent a valid UTF codepoint. -/// -pub fn utf_codepoint(value: Int) -> Result(UtfCodepoint, Nil) { - case value { - i if i > 1_114_111 -> Error(Nil) - i if i >= 55_296 && i <= 57_343 -> Error(Nil) - i if i < 0 -> Error(Nil) - i -> Ok(unsafe_int_to_utf_codepoint(i)) - } -} - -/// Converts an UtfCodepoint to its ordinal code point value. -/// -/// ## Examples -/// -/// ```gleam -/// let assert [utf_codepoint, ..] = to_utf_codepoints("💜") -/// utf_codepoint_to_int(utf_codepoint) -/// // -> 128156 -/// ``` -/// -@external(erlang, "gleam_stdlib", "identity") -@external(javascript, "../gleam_stdlib.mjs", "utf_codepoint_to_int") -pub fn utf_codepoint_to_int(cp: UtfCodepoint) -> Int - -/// Converts a `String` into `Option(String)` where an empty `String` becomes -/// `None`. -/// -/// ## Examples -/// -/// ```gleam -/// to_option("") -/// // -> None -/// ``` -/// -/// ```gleam -/// to_option("hats") -/// // -> Some("hats") -/// ``` -/// -pub fn to_option(string: String) -> Option(String) { - case string { - "" -> None - _ -> 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") -/// ``` -/// -pub fn first(string: String) -> Result(String, Nil) { - case pop_grapheme(string) { - Ok(#(first, _)) -> Ok(first) - Error(e) -> Error(e) - } -} - -/// 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") -/// ``` -/// -pub fn last(string: String) -> Result(String, Nil) { - case pop_grapheme(string) { - Ok(#(first, "")) -> Ok(first) - Ok(#(_, rest)) -> Ok(slice(rest, -1, 1)) - Error(e) -> Error(e) - } -} - -/// 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" -/// ``` -/// -pub fn capitalise(string: String) -> String { - case pop_grapheme(string) { - Ok(#(first, rest)) -> append(to: uppercase(first), suffix: lowercase(rest)) - Error(_) -> "" - } -} - -/// 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. -/// -pub fn inspect(term: anything) -> String { - term - |> do_inspect - |> string_tree.to_string -} - -@external(erlang, "gleam_stdlib", "inspect") -@external(javascript, "../gleam_stdlib.mjs", "inspect") -fn do_inspect(term: anything) -> StringTree - -/// Returns the number of bytes in a `String`. -/// -/// This function runs in constant time on Erlang and in linear time on -/// JavaScript. -/// -/// ## Examples -/// -/// ```gleam -/// byte_size("🏳️‍⚧️🏳️‍🌈👩🏾‍❤️‍👨🏻") -/// // -> 58 -/// ``` -/// -@external(erlang, "erlang", "byte_size") -@external(javascript, "../gleam_stdlib.mjs", "byte_size") -pub fn byte_size(string: String) -> Int diff --git a/build/packages/gleam_stdlib/src/gleam/string_tree.gleam b/build/packages/gleam_stdlib/src/gleam/string_tree.gleam deleted file mode 100644 index 22937e2..0000000 --- a/build/packages/gleam_stdlib/src/gleam/string_tree.gleam +++ /dev/null @@ -1,208 +0,0 @@ -import gleam/list - -/// `StringTree` is a type used for efficiently building text content to be -/// written to a file or a socket. Internally it is represented as tree so to -/// append or prepend to a string tree is a constant time operation that -/// allocates a new node in the tree without copying any of the content. When -/// writing to an output stream the tree is traversed and the content is sent -/// directly rather than copying it into a single buffer beforehand. -/// -/// On Erlang this type is compatible with Erlang's iodata. On JavaScript this -/// type is compatible with normal strings. -/// -/// The BEAM virtual machine has an optimisation for appending strings, where it -/// will mutate the string buffer when safe to do so, so if you are looking to -/// build a string through appending many small strings then you may get better -/// performance by not using a string tree. Always benchmark your performance -/// sensitive code. -/// -pub type StringTree - -/// Create an empty `StringTree`. Useful as the start of a pipe chaining many -/// trees together. -/// -pub fn new() -> StringTree { - from_strings([]) -} - -/// Prepends a `String` onto the start of some `StringTree`. -/// -/// Runs in constant time. -/// -pub fn prepend(to tree: StringTree, prefix prefix: String) -> StringTree { - append_tree(from_string(prefix), tree) -} - -/// Appends a `String` onto the end of some `StringTree`. -/// -/// Runs in constant time. -/// -pub fn append(to tree: StringTree, suffix second: String) -> StringTree { - append_tree(tree, from_string(second)) -} - -/// Prepends some `StringTree` onto the start of another. -/// -/// Runs in constant time. -/// -pub fn prepend_tree( - to tree: StringTree, - prefix prefix: StringTree, -) -> StringTree { - append_tree(prefix, tree) -} - -/// Appends some `StringTree` onto the end of another. -/// -/// Runs in constant time. -/// -@external(erlang, "gleam_stdlib", "iodata_append") -@external(javascript, "../gleam_stdlib.mjs", "add") -pub fn append_tree(to tree: StringTree, suffix suffix: StringTree) -> StringTree - -/// Converts a list of strings into a `StringTree`. -/// -/// Runs in constant time. -/// -@external(erlang, "gleam_stdlib", "identity") -@external(javascript, "../gleam_stdlib.mjs", "concat") -pub fn from_strings(strings: List(String)) -> StringTree - -/// Joins a list of trees into a single tree. -/// -/// Runs in constant time. -/// -@external(erlang, "gleam_stdlib", "identity") -@external(javascript, "../gleam_stdlib.mjs", "concat") -pub fn concat(trees: List(StringTree)) -> StringTree - -/// Converts a string into a `StringTree`. -/// -/// Runs in constant time. -/// -@external(erlang, "gleam_stdlib", "identity") -@external(javascript, "../gleam_stdlib.mjs", "identity") -pub fn from_string(string: String) -> StringTree - -/// Turns a `StringTree` into a `String` -/// -/// This function is implemented natively by the virtual machine and is highly -/// optimised. -/// -@external(erlang, "unicode", "characters_to_binary") -@external(javascript, "../gleam_stdlib.mjs", "identity") -pub fn to_string(tree: StringTree) -> String - -/// Returns the size of the `StringTree` in bytes. -/// -@external(erlang, "erlang", "iolist_size") -@external(javascript, "../gleam_stdlib.mjs", "length") -pub fn byte_size(tree: StringTree) -> Int - -/// Joins the given trees into a new tree separated with the given string. -/// -pub fn join(trees: List(StringTree), with sep: String) -> StringTree { - trees - |> list.intersperse(from_string(sep)) - |> concat -} - -/// Converts a `StringTree` to a new one where the contents have been -/// lowercased. -/// -@external(erlang, "string", "lowercase") -@external(javascript, "../gleam_stdlib.mjs", "lowercase") -pub fn lowercase(tree: StringTree) -> StringTree - -/// Converts a `StringTree` to a new one where the contents have been -/// uppercased. -/// -@external(erlang, "string", "uppercase") -@external(javascript, "../gleam_stdlib.mjs", "uppercase") -pub fn uppercase(tree: StringTree) -> StringTree - -/// Converts a `StringTree` to a new one with the contents reversed. -/// -@external(erlang, "string", "reverse") -pub fn reverse(tree: StringTree) -> StringTree { - tree - |> to_string - |> do_to_graphemes - |> list.reverse - |> from_strings -} - -@external(javascript, "../gleam_stdlib.mjs", "graphemes") -fn do_to_graphemes(string: String) -> List(String) - -type Direction { - All -} - -/// Splits a `StringTree` on a given pattern into a list of trees. -/// -@external(javascript, "../gleam_stdlib.mjs", "split") -pub fn split(tree: StringTree, on pattern: String) -> List(StringTree) { - erl_split(tree, pattern, All) -} - -@external(erlang, "string", "split") -fn erl_split(a: StringTree, b: String, c: Direction) -> List(StringTree) - -/// Replaces all instances of a pattern with a given string substitute. -/// -@external(erlang, "gleam_stdlib", "string_replace") -@external(javascript, "../gleam_stdlib.mjs", "string_replace") -pub fn replace( - in tree: StringTree, - each pattern: String, - with substitute: String, -) -> StringTree - -/// 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 -/// ``` -/// -@external(erlang, "string", "equal") -pub fn is_equal(a: StringTree, b: StringTree) -> Bool { - 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 -/// ``` -/// -@external(erlang, "string", "is_empty") -pub fn is_empty(tree: StringTree) -> Bool { - from_string("") == tree -} diff --git a/build/packages/gleam_stdlib/src/gleam/uri.gleam b/build/packages/gleam_stdlib/src/gleam/uri.gleam deleted file mode 100644 index 9413b99..0000000 --- a/build/packages/gleam_stdlib/src/gleam/uri.gleam +++ /dev/null @@ -1,770 +0,0 @@ -//// Utilities for working with URIs -//// -//// This module provides functions for working with URIs (for example, parsing -//// URIs or encoding query strings). The functions in this module are implemented -//// according to [RFC 3986](https://tools.ietf.org/html/rfc3986). -//// -//// Query encoding (Form encoding) is defined in the -//// [W3C specification](https://www.w3.org/TR/html52/sec-forms.html#urlencoded-form-data). - -import gleam/int -import gleam/list -import gleam/option.{type Option, None, Some} -import gleam/string -import gleam/string_tree.{type StringTree} - -/// Type representing holding the parsed components of an URI. -/// All components of a URI are optional, except the path. -/// -pub type Uri { - Uri( - scheme: Option(String), - userinfo: Option(String), - host: Option(String), - port: Option(Int), - path: String, - query: Option(String), - fragment: Option(String), - ) -} - -/// Constant representing an empty URI, equivalent to "". -/// -/// ## Examples -/// -/// ```gleam -/// let uri = Uri(..empty, scheme: Some("https"), host: Some("example.com")) -/// // -> Uri( -/// // scheme: Some("https"), -/// // userinfo: None, -/// // host: Some("example.com"), -/// // port: None, -/// // path: "", -/// // query: None, -/// // fragment: None, -/// // ) -/// ``` -/// -pub const empty = Uri( - scheme: None, - userinfo: None, - host: None, - port: None, - path: "", - query: None, - fragment: None, -) - -/// Parses a compliant URI string into the `Uri` Type. -/// If the string is not a valid URI string then an error is returned. -/// -/// The opposite operation is `uri.to_string`. -/// -/// ## Examples -/// -/// ```gleam -/// parse("https://example.com:1234/a/b?query=true#fragment") -/// // -> Ok( -/// // Uri( -/// // scheme: Some("https"), -/// // userinfo: None, -/// // host: Some("example.com"), -/// // port: Some(1234), -/// // path: "/a/b", -/// // query: Some("query=true"), -/// // fragment: Some("fragment") -/// // ) -/// // ) -/// ``` -/// -@external(erlang, "gleam_stdlib", "uri_parse") -pub fn parse(uri_string: String) -> Result(Uri, Nil) { - // This parses a uri_string following the regex defined in - // https://tools.ietf.org/html/rfc3986#appendix-B - // - // TODO: This is not perfect and will be more permissive than its Erlang - // counterpart, ideally we want to replicate Erlang's implementation on the js - // target as well. - parse_scheme_loop(uri_string, uri_string, empty, 0) -} - -fn parse_scheme_loop( - original: String, - uri_string: String, - pieces: Uri, - size: Int, -) -> Result(Uri, Nil) { - case uri_string { - // `/` is not allowed to appear in a scheme so we know it's over and we can - // start parsing the authority with slashes. - "/" <> _ if size == 0 -> parse_authority_with_slashes(uri_string, pieces) - "/" <> _ -> { - let scheme = codeunit_slice(original, at_index: 0, length: size) - let pieces = Uri(..pieces, scheme: Some(string.lowercase(scheme))) - parse_authority_with_slashes(uri_string, pieces) - } - - // `?` is not allowed to appear in a schemem, in an authority, or in a path; - // so if we see it we know it marks the beginning of the query part. - "?" <> rest if size == 0 -> parse_query_with_question_mark(rest, pieces) - "?" <> rest -> { - let scheme = codeunit_slice(original, at_index: 0, length: size) - let pieces = Uri(..pieces, scheme: Some(string.lowercase(scheme))) - parse_query_with_question_mark(rest, pieces) - } - - // `#` is not allowed to appear in a scheme, in an authority, in a path or - // in a query; so if we see it we know it marks the beginning of the final - // fragment. - "#" <> rest if size == 0 -> parse_fragment(rest, pieces) - "#" <> rest -> { - let scheme = codeunit_slice(original, at_index: 0, length: size) - let pieces = Uri(..pieces, scheme: Some(string.lowercase(scheme))) - parse_fragment(rest, pieces) - } - - // A colon marks the end of a uri scheme, but if it is not preceded by any - // character then it's not a valid URI. - ":" <> _ if size == 0 -> Error(Nil) - ":" <> rest -> { - let scheme = codeunit_slice(original, at_index: 0, length: size) - let pieces = Uri(..pieces, scheme: Some(string.lowercase(scheme))) - parse_authority_with_slashes(rest, pieces) - } - - // If we could get to the end of the string and we've met no special - // chars whatsoever, that means the entire string is just a long path. - "" -> Ok(Uri(..pieces, path: original)) - - // In all other cases the first character is just a valid URI scheme - // character and we just keep munching characters until we reach the end of - // the uri scheme (or the end of the string and that would mean this is not - // a valid uri scheme since we found no `:`). - _ -> { - let #(_, rest) = pop_codeunit(uri_string) - parse_scheme_loop(original, rest, pieces, size + 1) - } - } -} - -fn parse_authority_with_slashes( - uri_string: String, - pieces: Uri, -) -> Result(Uri, Nil) { - case uri_string { - // To be a valid authority the string must start with a `//`, otherwise - // there's no authority and we just skip ahead to parsing the path. - "//" -> Ok(Uri(..pieces, host: Some(""))) - "//" <> rest -> parse_authority_pieces(rest, pieces) - _ -> parse_path(uri_string, pieces) - } -} - -fn parse_authority_pieces(string: String, pieces: Uri) -> Result(Uri, Nil) { - parse_userinfo_loop(string, string, pieces, 0) -} - -fn parse_userinfo_loop( - original: String, - uri_string: String, - pieces: Uri, - size: Int, -) -> Result(Uri, Nil) { - case uri_string { - // `@` marks the end of the userinfo and the start of the host part in the - // authority string. - "@" <> rest if size == 0 -> parse_host(rest, pieces) - "@" <> rest -> { - let userinfo = codeunit_slice(original, at_index: 0, length: size) - let pieces = Uri(..pieces, userinfo: Some(userinfo)) - parse_host(rest, pieces) - } - - // If we reach the end of the authority string without finding an `@` - // special character, then we know that the authority doesn't actually - // contain the userinfo part. - // The entire string we just went through was a host! So we parse it as - // such. - "" | "/" <> _ | "?" <> _ | "#" <> _ -> parse_host(original, pieces) - - // In all other cases we just keep munching characters increasing the size - // of the userinfo bit. - _ -> { - let #(_, rest) = pop_codeunit(uri_string) - parse_userinfo_loop(original, rest, pieces, size + 1) - } - } -} - -fn parse_host(uri_string: String, pieces: Uri) -> Result(Uri, Nil) { - // A host string can be in two formats: - // - \[[:.a-zA-Z0-9]*\] - // - [^:] - case uri_string { - // If we find an opening bracket we know it's the first format. - "[" <> _ -> parse_host_within_brackets(uri_string, pieces) - - // A `:` marks the beginning of the port part of the authority string. - ":" <> _ -> { - let pieces = Uri(..pieces, host: Some("")) - parse_port(uri_string, pieces) - } - - // If the string is empty then there's no need to keep going. The host is - // empty. - "" -> Ok(Uri(..pieces, host: Some(""))) - - // Otherwise it's the second format - _ -> parse_host_outside_of_brackets(uri_string, pieces) - } -} - -fn parse_host_within_brackets( - uri_string: String, - pieces: Uri, -) -> Result(Uri, Nil) { - parse_host_within_brackets_loop(uri_string, uri_string, pieces, 0) -} - -fn parse_host_within_brackets_loop( - original: String, - uri_string: String, - pieces: Uri, - size: Int, -) -> Result(Uri, Nil) { - case uri_string { - // If the string is over the entire string we were iterating through is the - // host part. - "" -> Ok(Uri(..pieces, host: Some(uri_string))) - - // A `]` marks the end of the host and the start of the port part. - "]" <> rest if size == 0 -> parse_port(rest, pieces) - "]" <> rest -> { - let host = codeunit_slice(original, at_index: 0, length: size + 1) - let pieces = Uri(..pieces, host: Some(host)) - parse_port(rest, pieces) - } - - // `/` marks the beginning of a path. - "/" <> _ if size == 0 -> parse_path(uri_string, pieces) - "/" <> _ -> { - let host = codeunit_slice(original, at_index: 0, length: size) - let pieces = Uri(..pieces, host: Some(host)) - parse_path(uri_string, pieces) - } - - // `?` marks the beginning of the query with question mark. - "?" <> rest if size == 0 -> parse_query_with_question_mark(rest, pieces) - "?" <> rest -> { - let host = codeunit_slice(original, at_index: 0, length: size) - let pieces = Uri(..pieces, host: Some(host)) - parse_query_with_question_mark(rest, pieces) - } - - // `#` marks the beginning of the fragment part. - "#" <> rest if size == 0 -> parse_fragment(rest, pieces) - "#" <> rest -> { - let host = codeunit_slice(original, at_index: 0, length: size) - let pieces = Uri(..pieces, host: Some(host)) - parse_fragment(rest, pieces) - } - - // In all other cases we just keep iterating. - _ -> { - let #(char, rest) = pop_codeunit(uri_string) - // Inside `[...]` there can only be some characters, if we find a special - // one then we know that we're actually parsing the other format for the - // host and we switch to that! - case is_valid_host_within_brackets_char(char) { - True -> - parse_host_within_brackets_loop(original, rest, pieces, size + 1) - - False -> - parse_host_outside_of_brackets_loop(original, original, pieces, 0) - } - } - } -} - -fn is_valid_host_within_brackets_char(char: Int) -> Bool { - // [0-9] - { 48 >= char && char <= 57 } - // [A-Z] - || { 65 >= char && char <= 90 } - // [a-z] - || { 97 >= char && char <= 122 } - // : - || char == 58 - // . - || char == 46 -} - -fn parse_host_outside_of_brackets( - uri_string: String, - pieces: Uri, -) -> Result(Uri, Nil) { - parse_host_outside_of_brackets_loop(uri_string, uri_string, pieces, 0) -} - -fn parse_host_outside_of_brackets_loop( - original: String, - uri_string: String, - pieces: Uri, - size: Int, -) -> Result(Uri, Nil) { - case uri_string { - "" -> Ok(Uri(..pieces, host: Some(original))) - - // `:` marks the beginning of the port. - ":" <> _ -> { - let host = codeunit_slice(original, at_index: 0, length: size) - let pieces = Uri(..pieces, host: Some(host)) - parse_port(uri_string, pieces) - } - - // `/` marks the beginning of a path. - "/" <> _ -> { - let host = codeunit_slice(original, at_index: 0, length: size) - let pieces = Uri(..pieces, host: Some(host)) - parse_path(uri_string, pieces) - } - - // `?` marks the beginning of the query with question mark. - "?" <> rest -> { - let host = codeunit_slice(original, at_index: 0, length: size) - let pieces = Uri(..pieces, host: Some(host)) - parse_query_with_question_mark(rest, pieces) - } - - // `#` marks the beginning of the fragment part. - "#" <> rest -> { - let host = codeunit_slice(original, at_index: 0, length: size) - let pieces = Uri(..pieces, host: Some(host)) - parse_fragment(rest, pieces) - } - - _ -> { - let #(_, rest) = pop_codeunit(uri_string) - parse_host_outside_of_brackets_loop(original, rest, pieces, size + 1) - } - } -} - -fn parse_port(uri_string: String, pieces: Uri) -> Result(Uri, Nil) { - case uri_string { - ":0" <> rest -> parse_port_loop(rest, pieces, 0) - ":1" <> rest -> parse_port_loop(rest, pieces, 1) - ":2" <> rest -> parse_port_loop(rest, pieces, 2) - ":3" <> rest -> parse_port_loop(rest, pieces, 3) - ":4" <> rest -> parse_port_loop(rest, pieces, 4) - ":5" <> rest -> parse_port_loop(rest, pieces, 5) - ":6" <> rest -> parse_port_loop(rest, pieces, 6) - ":7" <> rest -> parse_port_loop(rest, pieces, 7) - ":8" <> rest -> parse_port_loop(rest, pieces, 8) - ":9" <> rest -> parse_port_loop(rest, pieces, 9) - - // The port could be empty and be followed by any of the next delimiters. - // Like `:#`, `:?` or `:/` - ":" | "" -> Ok(pieces) - - // `?` marks the beginning of the query with question mark. - "?" <> rest | ":?" <> rest -> parse_query_with_question_mark(rest, pieces) - - // `#` marks the beginning of the fragment part. - "#" <> rest | ":#" <> rest -> parse_fragment(rest, pieces) - - // `/` marks the beginning of a path. - "/" <> _ -> parse_path(uri_string, pieces) - ":" <> rest -> - case rest { - "/" <> _ -> parse_path(rest, pieces) - _ -> Error(Nil) - } - - _ -> Error(Nil) - } -} - -fn parse_port_loop( - uri_string: String, - pieces: Uri, - port: Int, -) -> Result(Uri, Nil) { - case uri_string { - // As long as we find port numbers we keep accumulating those. - "0" <> rest -> parse_port_loop(rest, pieces, port * 10) - "1" <> rest -> parse_port_loop(rest, pieces, port * 10 + 1) - "2" <> rest -> parse_port_loop(rest, pieces, port * 10 + 2) - "3" <> rest -> parse_port_loop(rest, pieces, port * 10 + 3) - "4" <> rest -> parse_port_loop(rest, pieces, port * 10 + 4) - "5" <> rest -> parse_port_loop(rest, pieces, port * 10 + 5) - "6" <> rest -> parse_port_loop(rest, pieces, port * 10 + 6) - "7" <> rest -> parse_port_loop(rest, pieces, port * 10 + 7) - "8" <> rest -> parse_port_loop(rest, pieces, port * 10 + 8) - "9" <> rest -> parse_port_loop(rest, pieces, port * 10 + 9) - - // `?` marks the beginning of the query with question mark. - "?" <> rest -> { - let pieces = Uri(..pieces, port: Some(port)) - parse_query_with_question_mark(rest, pieces) - } - - // `#` marks the beginning of the fragment part. - "#" <> rest -> { - let pieces = Uri(..pieces, port: Some(port)) - parse_fragment(rest, pieces) - } - - // `/` marks the beginning of a path. - "/" <> _ -> { - let pieces = Uri(..pieces, port: Some(port)) - parse_path(uri_string, pieces) - } - - // The string (and so the port) is over, we return what we parsed so far. - "" -> Ok(Uri(..pieces, port: Some(port))) - - // In all other cases we've ran into some invalid character inside the port - // so the uri is invalid! - _ -> Error(Nil) - } -} - -fn parse_path(uri_string: String, pieces: Uri) -> Result(Uri, Nil) { - parse_path_loop(uri_string, uri_string, pieces, 0) -} - -fn parse_path_loop( - original: String, - uri_string: String, - pieces: Uri, - size: Int, -) -> Result(Uri, Nil) { - case uri_string { - // `?` marks the beginning of the query with question mark. - "?" <> rest -> { - let path = codeunit_slice(original, at_index: 0, length: size) - let pieces = Uri(..pieces, path: path) - parse_query_with_question_mark(rest, pieces) - } - - // `#` marks the beginning of the fragment part. - "#" <> rest -> { - let path = codeunit_slice(original, at_index: 0, length: size) - let pieces = Uri(..pieces, path: path) - parse_fragment(rest, pieces) - } - - // If the string is over that means the entirety of the string was the path - // and it has an empty query and fragment. - "" -> Ok(Uri(..pieces, path: original)) - - // In all other cases the character is allowed to be part of the path so we - // just keep munching until we reach to its end. - _ -> { - let #(_, rest) = pop_codeunit(uri_string) - parse_path_loop(original, rest, pieces, size + 1) - } - } -} - -fn parse_query_with_question_mark( - uri_string: String, - pieces: Uri, -) -> Result(Uri, Nil) { - parse_query_with_question_mark_loop(uri_string, uri_string, pieces, 0) -} - -fn parse_query_with_question_mark_loop( - original: String, - uri_string: String, - pieces: Uri, - size: Int, -) -> Result(Uri, Nil) { - case uri_string { - // `#` marks the beginning of the fragment part. - "#" <> rest if size == 0 -> parse_fragment(rest, pieces) - "#" <> rest -> { - let query = codeunit_slice(original, at_index: 0, length: size) - let pieces = Uri(..pieces, query: Some(query)) - parse_fragment(rest, pieces) - } - - // If the string is over that means the entirety of the string was the query - // and it has an empty fragment. - "" -> Ok(Uri(..pieces, query: Some(original))) - - // In all other cases the character is allowed to be part of the query so we - // just keep munching until we reach to its end. - _ -> { - let #(_, rest) = pop_codeunit(uri_string) - parse_query_with_question_mark_loop(original, rest, pieces, size + 1) - } - } -} - -fn parse_fragment(rest: String, pieces: Uri) -> Result(Uri, Nil) { - Ok(Uri(..pieces, fragment: Some(rest))) -} - -// WARN: this function returns invalid strings! -// We need to return a String anyways to have this as the representation on the -// JavaScript target. -// Alternatively, we could rewrite the entire code to use a single -// `fold_codeunits`-style loop and a state machine. -@external(erlang, "gleam_stdlib", "string_pop_codeunit") -@external(javascript, "../gleam_stdlib.mjs", "pop_codeunit") -fn pop_codeunit(str: String) -> #(Int, String) - -@external(erlang, "binary", "part") -@external(javascript, "../gleam_stdlib.mjs", "string_codeunit_slice") -fn codeunit_slice(str: String, at_index from: Int, length length: Int) -> String - -/// Parses an urlencoded query string into a list of key value pairs. -/// Returns an error for invalid encoding. -/// -/// The opposite operation is `uri.query_to_string`. -/// -/// ## Examples -/// -/// ```gleam -/// parse_query("a=1&b=2") -/// // -> Ok([#("a", "1"), #("b", "2")]) -/// ``` -/// -@external(erlang, "gleam_stdlib", "parse_query") -@external(javascript, "../gleam_stdlib.mjs", "parse_query") -pub fn parse_query(query: String) -> Result(List(#(String, String)), Nil) - -/// Encodes a list of key value pairs as a URI query string. -/// -/// The opposite operation is `uri.parse_query`. -/// -/// ## Examples -/// -/// ```gleam -/// query_to_string([#("a", "1"), #("b", "2")]) -/// // -> "a=1&b=2" -/// ``` -/// -pub fn query_to_string(query: List(#(String, String))) -> String { - query - |> list.map(query_pair) - |> list.intersperse(string_tree.from_string("&")) - |> string_tree.concat - |> string_tree.to_string -} - -fn query_pair(pair: #(String, String)) -> StringTree { - string_tree.from_strings([percent_encode(pair.0), "=", percent_encode(pair.1)]) -} - -/// Encodes a string into a percent encoded representation. -/// -/// ## Examples -/// -/// ```gleam -/// percent_encode("100% great") -/// // -> "100%25%20great" -/// ``` -/// -@external(erlang, "gleam_stdlib", "percent_encode") -@external(javascript, "../gleam_stdlib.mjs", "percent_encode") -pub fn percent_encode(value: String) -> String - -/// Decodes a percent encoded string. -/// -/// ## Examples -/// -/// ```gleam -/// percent_decode("100%25%20great+fun") -/// // -> Ok("100% great+fun") -/// ``` -/// -@external(erlang, "gleam_stdlib", "percent_decode") -@external(javascript, "../gleam_stdlib.mjs", "percent_decode") -pub fn percent_decode(value: String) -> Result(String, Nil) - -/// Splits the path section of a URI into it's constituent segments. -/// -/// Removes empty segments and resolves dot-segments as specified in -/// [section 5.2](https://www.ietf.org/rfc/rfc3986.html#section-5.2) of the RFC. -/// -/// ## Examples -/// -/// ```gleam -/// path_segments("/users/1") -/// // -> ["users" ,"1"] -/// ``` -/// -pub fn path_segments(path: String) -> List(String) { - remove_dot_segments(string.split(path, "/")) -} - -fn remove_dot_segments(input: List(String)) -> List(String) { - remove_dot_segments_loop(input, []) -} - -fn remove_dot_segments_loop( - input: List(String), - accumulator: List(String), -) -> List(String) { - case input { - [] -> list.reverse(accumulator) - [segment, ..rest] -> { - let accumulator = case segment, accumulator { - "", accumulator -> accumulator - ".", accumulator -> accumulator - "..", [] -> [] - "..", [_, ..accumulator] -> accumulator - segment, accumulator -> [segment, ..accumulator] - } - remove_dot_segments_loop(rest, accumulator) - } - } -} - -/// Encodes a `Uri` value as a URI string. -/// -/// The opposite operation is `uri.parse`. -/// -/// ## Examples -/// -/// ```gleam -/// let uri = Uri(..empty, scheme: Some("https"), host: Some("example.com")) -/// to_string(uri) -/// // -> "https://example.com" -/// ``` -/// -pub fn to_string(uri: Uri) -> String { - let parts = case uri.fragment { - Some(fragment) -> ["#", fragment] - None -> [] - } - let parts = case uri.query { - Some(query) -> ["?", query, ..parts] - None -> parts - } - let parts = [uri.path, ..parts] - let parts = case uri.host, string.starts_with(uri.path, "/") { - Some(host), False if host != "" -> ["/", ..parts] - _, _ -> parts - } - let parts = case uri.host, uri.port { - Some(_), Some(port) -> [":", int.to_string(port), ..parts] - _, _ -> parts - } - let parts = case uri.scheme, uri.userinfo, uri.host { - Some(s), Some(u), Some(h) -> [s, "://", u, "@", h, ..parts] - Some(s), None, Some(h) -> [s, "://", h, ..parts] - Some(s), Some(_), None | Some(s), None, None -> [s, ":", ..parts] - None, None, Some(h) -> ["//", h, ..parts] - _, _, _ -> parts - } - string.concat(parts) -} - -/// Fetches the origin of a URI. -/// -/// Returns the origin of a uri as defined in -/// [RFC 6454](https://tools.ietf.org/html/rfc6454) -/// -/// The supported URI schemes are `http` and `https`. -/// URLs without a scheme will return `Error`. -/// -/// ## Examples -/// -/// ```gleam -/// let assert Ok(uri) = parse("https://example.com/path?foo#bar") -/// origin(uri) -/// // -> Ok("https://example.com") -/// ``` -/// -pub fn origin(uri: Uri) -> Result(String, Nil) { - let Uri(scheme: scheme, host: host, port: port, ..) = uri - case host, scheme { - Some(h), Some("https") if port == Some(443) -> - Ok(string.concat(["https://", h])) - Some(h), Some("http") if port == Some(80) -> - Ok(string.concat(["http://", h])) - Some(h), Some(s) if s == "http" || s == "https" -> { - case port { - Some(p) -> Ok(string.concat([s, "://", h, ":", int.to_string(p)])) - None -> Ok(string.concat([s, "://", h])) - } - } - _, _ -> Error(Nil) - } -} - -/// Resolves a URI with respect to the given base URI. -/// -/// The base URI must be an absolute URI or this function will return an error. -/// The algorithm for merging uris is described in -/// [RFC 3986](https://tools.ietf.org/html/rfc3986#section-5.2). -/// -pub fn merge(base: Uri, relative: Uri) -> Result(Uri, Nil) { - case base { - Uri(scheme: Some(_), host: Some(_), ..) -> - case relative { - Uri(host: Some(_), ..) -> { - let path = - relative.path - |> string.split("/") - |> remove_dot_segments() - |> join_segments() - let resolved = - Uri( - option.or(relative.scheme, base.scheme), - None, - relative.host, - option.or(relative.port, base.port), - path, - relative.query, - relative.fragment, - ) - Ok(resolved) - } - _ -> { - let #(new_path, new_query) = case relative.path { - "" -> #(base.path, option.or(relative.query, base.query)) - _ -> { - let path_segments = case string.starts_with(relative.path, "/") { - True -> string.split(relative.path, "/") - False -> - base.path - |> string.split("/") - |> drop_last() - |> list.append(string.split(relative.path, "/")) - } - let path = - path_segments - |> remove_dot_segments() - |> join_segments() - #(path, relative.query) - } - } - let resolved = - Uri( - base.scheme, - None, - base.host, - base.port, - new_path, - new_query, - relative.fragment, - ) - Ok(resolved) - } - } - _ -> Error(Nil) - } -} - -fn drop_last(elements: List(a)) -> List(a) { - list.take(from: elements, up_to: list.length(elements) - 1) -} - -fn join_segments(segments: List(String)) -> String { - string.join(["", ..segments], "/") -} diff --git a/build/packages/gleam_stdlib/src/gleam@bit_array.erl b/build/packages/gleam_stdlib/src/gleam@bit_array.erl deleted file mode 100644 index 7df56ce..0000000 --- a/build/packages/gleam_stdlib/src/gleam@bit_array.erl +++ /dev/null @@ -1,347 +0,0 @@ --module(gleam@bit_array). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "src/gleam/bit_array.gleam"). --export([from_string/1, bit_size/1, byte_size/1, pad_to_bytes/1, slice/3, is_utf8/1, to_string/1, concat/1, append/2, base64_encode/2, base64_decode/1, base64_url_encode/2, base64_url_decode/1, base16_encode/1, base16_decode/1, inspect/1, compare/2, starts_with/2]). - --if(?OTP_RELEASE >= 27). --define(MODULEDOC(Str), -moduledoc(Str)). --define(DOC(Str), -doc(Str)). --else. --define(MODULEDOC(Str), -compile([])). --define(DOC(Str), -compile([])). --endif. - -?MODULEDOC(" BitArrays are a sequence of binary data of any length.\n"). - --file("src/gleam/bit_array.gleam", 11). -?DOC(" Converts a UTF-8 `String` type into a `BitArray`.\n"). --spec from_string(binary()) -> bitstring(). -from_string(X) -> - gleam_stdlib:identity(X). - --file("src/gleam/bit_array.gleam", 17). -?DOC(" Returns an integer which is the number of bits in the bit array.\n"). --spec bit_size(bitstring()) -> integer(). -bit_size(X) -> - erlang:bit_size(X). - --file("src/gleam/bit_array.gleam", 23). -?DOC(" Returns an integer which is the number of bytes in the bit array.\n"). --spec byte_size(bitstring()) -> integer(). -byte_size(X) -> - erlang:byte_size(X). - --file("src/gleam/bit_array.gleam", 29). -?DOC(" Pads a bit array with zeros so that it is a whole number of bytes.\n"). --spec pad_to_bytes(bitstring()) -> bitstring(). -pad_to_bytes(X) -> - gleam_stdlib:bit_array_pad_to_bytes(X). - --file("src/gleam/bit_array.gleam", 54). -?DOC( - " Extracts a sub-section of a bit array.\n" - "\n" - " The slice will start at given position and continue up to specified\n" - " length.\n" - " A negative length can be used to extract bytes at the end of a bit array.\n" - "\n" - " This function runs in constant time.\n" -). --spec slice(bitstring(), integer(), integer()) -> {ok, bitstring()} | - {error, nil}. -slice(String, Position, Length) -> - gleam_stdlib:bit_array_slice(String, Position, Length). - --file("src/gleam/bit_array.gleam", 67). --spec is_utf8_loop(bitstring()) -> boolean(). -is_utf8_loop(Bits) -> - case Bits of - <<>> -> - true; - - <<_/utf8, Rest/binary>> -> - is_utf8_loop(Rest); - - _ -> - false - end. - --file("src/gleam/bit_array.gleam", 62). -?DOC(" Tests to see whether a bit array is valid UTF-8.\n"). --spec is_utf8(bitstring()) -> boolean(). -is_utf8(Bits) -> - is_utf8_loop(Bits). - --file("src/gleam/bit_array.gleam", 88). -?DOC( - " Converts a bit array to a string.\n" - "\n" - " Returns an error if the bit array is invalid UTF-8 data.\n" -). --spec to_string(bitstring()) -> {ok, binary()} | {error, nil}. -to_string(Bits) -> - case is_utf8(Bits) of - true -> - {ok, gleam_stdlib:identity(Bits)}; - - false -> - {error, nil} - end. - --file("src/gleam/bit_array.gleam", 109). -?DOC( - " Creates a new bit array by joining multiple binaries.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " concat([from_string(\"butter\"), from_string(\"fly\")])\n" - " // -> from_string(\"butterfly\")\n" - " ```\n" -). --spec concat(list(bitstring())) -> bitstring(). -concat(Bit_arrays) -> - gleam_stdlib:bit_array_concat(Bit_arrays). - --file("src/gleam/bit_array.gleam", 40). -?DOC( - " Creates a new bit array by joining two bit arrays.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " append(to: from_string(\"butter\"), suffix: from_string(\"fly\"))\n" - " // -> from_string(\"butterfly\")\n" - " ```\n" -). --spec append(bitstring(), bitstring()) -> bitstring(). -append(First, Second) -> - gleam_stdlib:bit_array_concat([First, Second]). - --file("src/gleam/bit_array.gleam", 118). -?DOC( - " Encodes a BitArray into a base 64 encoded string.\n" - "\n" - " If the bit array does not contain a whole number of bytes then it is padded\n" - " with zero bits prior to being encoded.\n" -). --spec base64_encode(bitstring(), boolean()) -> binary(). -base64_encode(Input, Padding) -> - gleam_stdlib:base64_encode(Input, Padding). - --file("src/gleam/bit_array.gleam", 122). -?DOC(" Decodes a base 64 encoded string into a `BitArray`.\n"). --spec base64_decode(binary()) -> {ok, bitstring()} | {error, nil}. -base64_decode(Encoded) -> - Padded = case erlang:byte_size(gleam_stdlib:identity(Encoded)) rem 4 of - 0 -> - Encoded; - - N -> - gleam@string:append( - Encoded, - gleam@string:repeat(<<"="/utf8>>, 4 - N) - ) - end, - gleam_stdlib:base64_decode(Padded). - --file("src/gleam/bit_array.gleam", 140). -?DOC( - " Encodes a `BitArray` into a base 64 encoded string with URL and filename\n" - " safe alphabet.\n" - "\n" - " If the bit array does not contain a whole number of bytes then it is padded\n" - " with zero bits prior to being encoded.\n" -). --spec base64_url_encode(bitstring(), boolean()) -> binary(). -base64_url_encode(Input, Padding) -> - _pipe = Input, - _pipe@1 = gleam_stdlib:base64_encode(_pipe, Padding), - _pipe@2 = gleam@string:replace(_pipe@1, <<"+"/utf8>>, <<"-"/utf8>>), - gleam@string:replace(_pipe@2, <<"/"/utf8>>, <<"_"/utf8>>). - --file("src/gleam/bit_array.gleam", 150). -?DOC( - " Decodes a base 64 encoded string with URL and filename safe alphabet into a\n" - " `BitArray`.\n" -). --spec base64_url_decode(binary()) -> {ok, bitstring()} | {error, nil}. -base64_url_decode(Encoded) -> - _pipe = Encoded, - _pipe@1 = gleam@string:replace(_pipe, <<"-"/utf8>>, <<"+"/utf8>>), - _pipe@2 = gleam@string:replace(_pipe@1, <<"_"/utf8>>, <<"/"/utf8>>), - base64_decode(_pipe@2). - --file("src/gleam/bit_array.gleam", 164). -?DOC( - " Encodes a `BitArray` into a base 16 encoded string.\n" - "\n" - " If the bit array does not contain a whole number of bytes then it is padded\n" - " with zero bits prior to being encoded.\n" -). --spec base16_encode(bitstring()) -> binary(). -base16_encode(Input) -> - gleam_stdlib:base16_encode(Input). - --file("src/gleam/bit_array.gleam", 170). -?DOC(" Decodes a base 16 encoded string into a `BitArray`.\n"). --spec base16_decode(binary()) -> {ok, bitstring()} | {error, nil}. -base16_decode(Input) -> - gleam_stdlib:base16_decode(Input). - --file("src/gleam/bit_array.gleam", 191). --spec inspect_loop(bitstring(), binary()) -> binary(). -inspect_loop(Input, Accumulator) -> - case Input of - <<>> -> - Accumulator; - - <> -> - <<<>/binary, - ":size(1)"/utf8>>; - - <> -> - <<<>/binary, - ":size(2)"/utf8>>; - - <> -> - <<<>/binary, - ":size(3)"/utf8>>; - - <> -> - <<<>/binary, - ":size(4)"/utf8>>; - - <> -> - <<<>/binary, - ":size(5)"/utf8>>; - - <> -> - <<<>/binary, - ":size(6)"/utf8>>; - - <> -> - <<<>/binary, - ":size(7)"/utf8>>; - - <> -> - Suffix = case Rest of - <<>> -> - <<""/utf8>>; - - _ -> - <<", "/utf8>> - end, - Accumulator@1 = <<<>/binary, - Suffix/binary>>, - inspect_loop(Rest, Accumulator@1); - - _ -> - Accumulator - end. - --file("src/gleam/bit_array.gleam", 187). -?DOC( - " Converts a bit array to a string containing the decimal value of each byte.\n" - "\n" - " Use this over `string.inspect` when you have a bit array you want printed\n" - " in the array syntax even if it is valid UTF-8.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " inspect(<<0, 20, 0x20, 255>>)\n" - " // -> \"<<0, 20, 32, 255>>\"\n" - "\n" - " inspect(<<100, 5:3>>)\n" - " // -> \"<<100, 5:size(3)>>\"\n" - " ```\n" -). --spec inspect(bitstring()) -> binary(). -inspect(Input) -> - <<(inspect_loop(Input, <<"<<"/utf8>>))/binary, ">>"/utf8>>. - --file("src/gleam/bit_array.gleam", 232). -?DOC( - " Compare two bit arrays as sequences of bytes.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " compare(<<1>>, <<2>>)\n" - " // -> Lt\n" - "\n" - " compare(<<\"AB\":utf8>>, <<\"AA\":utf8>>)\n" - " // -> Gt\n" - "\n" - " compare(<<1, 2:size(2)>>, with: <<1, 2:size(2)>>)\n" - " // -> Eq\n" - " ```\n" -). --spec compare(bitstring(), bitstring()) -> gleam@order:order(). -compare(A, B) -> - case {A, B} of - {<>, - <>} -> - case {First_byte, Second_byte} of - {F, S} when F > S -> - gt; - - {F@1, S@1} when F@1 < S@1 -> - lt; - - {_, _} -> - compare(First_rest, Second_rest) - end; - - {<<>>, <<>>} -> - eq; - - {_, <<>>} -> - gt; - - {<<>>, _} -> - lt; - - {First, Second} -> - case {gleam_stdlib:bit_array_to_int_and_size(First), - gleam_stdlib:bit_array_to_int_and_size(Second)} of - {{A@1, _}, {B@1, _}} when A@1 > B@1 -> - gt; - - {{A@2, _}, {B@2, _}} when A@2 < B@2 -> - lt; - - {{_, Size_a}, {_, Size_b}} when Size_a > Size_b -> - gt; - - {{_, Size_a@1}, {_, Size_b@1}} when Size_a@1 < Size_b@1 -> - lt; - - {_, _} -> - eq - end - end. - --file("src/gleam/bit_array.gleam", 273). -?DOC( - " Checks whether the first `BitArray` starts with the second one.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " starts_with(<<1, 2, 3, 4>>, <<1, 2>>)\n" - " // -> True\n" - " ```\n" -). --spec starts_with(bitstring(), bitstring()) -> boolean(). -starts_with(Bits, Prefix) -> - Prefix_size = erlang:bit_size(Prefix), - case Bits of - <> when Pref =:= Prefix -> - true; - - _ -> - false - end. diff --git a/build/packages/gleam_stdlib/src/gleam@bool.erl b/build/packages/gleam_stdlib/src/gleam@bool.erl deleted file mode 100644 index 01307b3..0000000 --- a/build/packages/gleam_stdlib/src/gleam@bool.erl +++ /dev/null @@ -1,352 +0,0 @@ --module(gleam@bool). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "src/gleam/bool.gleam"). --export(['and'/2, 'or'/2, negate/1, nor/2, nand/2, exclusive_or/2, exclusive_nor/2, to_string/1, guard/3, lazy_guard/3]). - --if(?OTP_RELEASE >= 27). --define(MODULEDOC(Str), -moduledoc(Str)). --define(DOC(Str), -doc(Str)). --else. --define(MODULEDOC(Str), -compile([])). --define(DOC(Str), -compile([])). --endif. - -?MODULEDOC( - " A type with two possible values, `True` and `False`. Used to indicate whether\n" - " things are... true or false!\n" - "\n" - " Often is it clearer and offers more type safety to define a custom type\n" - " than to use `Bool`. For example, rather than having a `is_teacher: Bool`\n" - " field consider having a `role: SchoolRole` field where `SchoolRole` is a custom\n" - " type that can be either `Student` or `Teacher`.\n" -). - --file("src/gleam/bool.gleam", 31). -?DOC( - " Returns the and of two bools, but it evaluates both arguments.\n" - "\n" - " It's the function equivalent of the `&&` operator.\n" - " This function is useful in higher order functions or pipes.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " and(True, True)\n" - " // -> True\n" - " ```\n" - "\n" - " ```gleam\n" - " and(False, True)\n" - " // -> False\n" - " ```\n" - "\n" - " ```gleam\n" - " False |> and(True)\n" - " // -> False\n" - " ```\n" -). --spec 'and'(boolean(), boolean()) -> boolean(). -'and'(A, B) -> - A andalso B. - --file("src/gleam/bool.gleam", 57). -?DOC( - " Returns the or of two bools, but it evaluates both arguments.\n" - "\n" - " It's the function equivalent of the `||` operator.\n" - " This function is useful in higher order functions or pipes.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " or(True, True)\n" - " // -> True\n" - " ```\n" - "\n" - " ```gleam\n" - " or(False, True)\n" - " // -> True\n" - " ```\n" - "\n" - " ```gleam\n" - " False |> or(True)\n" - " // -> True\n" - " ```\n" -). --spec 'or'(boolean(), boolean()) -> boolean(). -'or'(A, B) -> - A orelse B. - --file("src/gleam/bool.gleam", 77). -?DOC( - " Returns the opposite bool value.\n" - "\n" - " This is the same as the `!` or `not` operators in some other languages.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " negate(True)\n" - " // -> False\n" - " ```\n" - "\n" - " ```gleam\n" - " negate(False)\n" - " // -> True\n" - " ```\n" -). --spec negate(boolean()) -> boolean(). -negate(Bool) -> - not Bool. - --file("src/gleam/bool.gleam", 105). -?DOC( - " Returns the nor of two bools.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " nor(False, False)\n" - " // -> True\n" - " ```\n" - "\n" - " ```gleam\n" - " nor(False, True)\n" - " // -> False\n" - " ```\n" - "\n" - " ```gleam\n" - " nor(True, False)\n" - " // -> False\n" - " ```\n" - "\n" - " ```gleam\n" - " nor(True, True)\n" - " // -> False\n" - " ```\n" -). --spec nor(boolean(), boolean()) -> boolean(). -nor(A, B) -> - not (A orelse B). - --file("src/gleam/bool.gleam", 133). -?DOC( - " Returns the nand of two bools.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " nand(False, False)\n" - " // -> True\n" - " ```\n" - "\n" - " ```gleam\n" - " nand(False, True)\n" - " // -> True\n" - " ```\n" - "\n" - " ```gleam\n" - " nand(True, False)\n" - " // -> True\n" - " ```\n" - "\n" - " ```gleam\n" - " nand(True, True)\n" - " // -> False\n" - " ```\n" -). --spec nand(boolean(), boolean()) -> boolean(). -nand(A, B) -> - not (A andalso B). - --file("src/gleam/bool.gleam", 161). -?DOC( - " Returns the exclusive or of two bools.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " exclusive_or(False, False)\n" - " // -> False\n" - " ```\n" - "\n" - " ```gleam\n" - " exclusive_or(False, True)\n" - " // -> True\n" - " ```\n" - "\n" - " ```gleam\n" - " exclusive_or(True, False)\n" - " // -> True\n" - " ```\n" - "\n" - " ```gleam\n" - " exclusive_or(True, True)\n" - " // -> False\n" - " ```\n" -). --spec exclusive_or(boolean(), boolean()) -> boolean(). -exclusive_or(A, B) -> - A /= B. - --file("src/gleam/bool.gleam", 189). -?DOC( - " Returns the exclusive nor of two bools.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " exclusive_nor(False, False)\n" - " // -> True\n" - " ```\n" - "\n" - " ```gleam\n" - " exclusive_nor(False, True)\n" - " // -> False\n" - " ```\n" - "\n" - " ```gleam\n" - " exclusive_nor(True, False)\n" - " // -> False\n" - " ```\n" - "\n" - " ```gleam\n" - " exclusive_nor(True, True)\n" - " // -> True\n" - " ```\n" -). --spec exclusive_nor(boolean(), boolean()) -> boolean(). -exclusive_nor(A, B) -> - A =:= B. - --file("src/gleam/bool.gleam", 207). -?DOC( - " Returns a string representation of the given bool.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " to_string(True)\n" - " // -> \"True\"\n" - " ```\n" - "\n" - " ```gleam\n" - " to_string(False)\n" - " // -> \"False\"\n" - " ```\n" -). --spec to_string(boolean()) -> binary(). -to_string(Bool) -> - case Bool of - false -> - <<"False"/utf8>>; - - true -> - <<"True"/utf8>> - end. - --file("src/gleam/bool.gleam", 266). -?DOC( - " Run a callback function if the given bool is `False`, otherwise return a\n" - " default value.\n" - "\n" - " With a `use` expression this function can simulate the early-return pattern\n" - " found in some other programming languages.\n" - "\n" - " In a procedural language:\n" - "\n" - " ```js\n" - " if (predicate) return value;\n" - " // ...\n" - " ```\n" - "\n" - " In Gleam with a `use` expression:\n" - "\n" - " ```gleam\n" - " use <- guard(when: predicate, return: value)\n" - " // ...\n" - " ```\n" - "\n" - " Like everything in Gleam `use` is an expression, so it short circuits the\n" - " current block, not the entire function. As a result you can assign the value\n" - " to a variable:\n" - "\n" - " ```gleam\n" - " let x = {\n" - " use <- guard(when: predicate, return: value)\n" - " // ...\n" - " }\n" - " ```\n" - "\n" - " Note that unlike in procedural languages the `return` value is evaluated\n" - " even when the predicate is `False`, so it is advisable not to perform\n" - " expensive computation nor side-effects there.\n" - "\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " let name = \"\"\n" - " use <- guard(when: name == \"\", return: \"Welcome!\")\n" - " \"Hello, \" <> name\n" - " // -> \"Welcome!\"\n" - " ```\n" - "\n" - " ```gleam\n" - " let name = \"Kamaka\"\n" - " use <- guard(when: name == \"\", return: \"Welcome!\")\n" - " \"Hello, \" <> name\n" - " // -> \"Hello, Kamaka\"\n" - " ```\n" -). --spec guard(boolean(), BSY, fun(() -> BSY)) -> BSY. -guard(Requirement, Consequence, Alternative) -> - case Requirement of - true -> - Consequence; - - false -> - Alternative() - end. - --file("src/gleam/bool.gleam", 307). -?DOC( - " Runs a callback function if the given bool is `True`, otherwise runs an\n" - " alternative callback function.\n" - "\n" - " Useful when further computation should be delayed regardless of the given\n" - " bool's value.\n" - "\n" - " See [`guard`](#guard) for more info.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " let name = \"Kamaka\"\n" - " let inquiry = fn() { \"How may we address you?\" }\n" - " use <- lazy_guard(when: name == \"\", return: inquiry)\n" - " \"Hello, \" <> name\n" - " // -> \"Hello, Kamaka\"\n" - " ```\n" - "\n" - " ```gleam\n" - " import gleam/int\n" - "\n" - " let name = \"\"\n" - " let greeting = fn() { \"Hello, \" <> name }\n" - " use <- lazy_guard(when: name == \"\", otherwise: greeting)\n" - " let number = int.random(99)\n" - " let name = \"User \" <> int.to_string(number)\n" - " \"Welcome, \" <> name\n" - " // -> \"Welcome, User 54\"\n" - " ```\n" -). --spec lazy_guard(boolean(), fun(() -> BSZ), fun(() -> BSZ)) -> BSZ. -lazy_guard(Requirement, Consequence, Alternative) -> - case Requirement of - true -> - Consequence(); - - false -> - Alternative() - end. diff --git a/build/packages/gleam_stdlib/src/gleam@bytes_tree.erl b/build/packages/gleam_stdlib/src/gleam@bytes_tree.erl deleted file mode 100644 index a96eaa2..0000000 --- a/build/packages/gleam_stdlib/src/gleam@bytes_tree.erl +++ /dev/null @@ -1,211 +0,0 @@ --module(gleam@bytes_tree). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "src/gleam/bytes_tree.gleam"). --export([append_tree/2, prepend_tree/2, concat/1, new/0, from_string/1, prepend_string/2, append_string/2, from_string_tree/1, from_bit_array/1, prepend/2, append/2, concat_bit_arrays/1, to_bit_array/1, byte_size/1]). --export_type([bytes_tree/0]). - --if(?OTP_RELEASE >= 27). --define(MODULEDOC(Str), -moduledoc(Str)). --define(DOC(Str), -doc(Str)). --else. --define(MODULEDOC(Str), -compile([])). --define(DOC(Str), -compile([])). --endif. - -?MODULEDOC( - " `BytesTree` is a type used for efficiently building binary content to be\n" - " written to a file or a socket. Internally it is represented as tree so to\n" - " append or prepend to a bytes tree is a constant time operation that\n" - " allocates a new node in the tree without copying any of the content. When\n" - " writing to an output stream the tree is traversed and the content is sent\n" - " directly rather than copying it into a single buffer beforehand.\n" - "\n" - " If we append one bit array to another the bit arrays must be copied to a\n" - " new location in memory so that they can sit together. This behaviour\n" - " enables efficient reading of the data but copying can be expensive,\n" - " especially if we want to join many bit arrays together.\n" - "\n" - " BytesTree is different in that it can be joined together in constant\n" - " time using minimal memory, and then can be efficiently converted to a\n" - " bit array using the `to_bit_array` function.\n" - "\n" - " Byte trees are always byte aligned, so that a number of bits that is not\n" - " divisible by 8 will be padded with 0s.\n" - "\n" - " On Erlang this type is compatible with Erlang's iolists.\n" -). - --opaque bytes_tree() :: {bytes, bitstring()} | - {text, gleam@string_tree:string_tree()} | - {many, list(bytes_tree())}. - --file("src/gleam/bytes_tree.gleam", 68). -?DOC( - " Appends a bytes tree onto the end of another.\n" - "\n" - " Runs in constant time.\n" -). --spec append_tree(bytes_tree(), bytes_tree()) -> bytes_tree(). -append_tree(First, Second) -> - gleam_stdlib:iodata_append(First, Second). - --file("src/gleam/bytes_tree.gleam", 59). -?DOC( - " Prepends a bytes tree onto the start of another.\n" - "\n" - " Runs in constant time.\n" -). --spec prepend_tree(bytes_tree(), bytes_tree()) -> bytes_tree(). -prepend_tree(Second, First) -> - gleam_stdlib:iodata_append(First, Second). - --file("src/gleam/bytes_tree.gleam", 98). -?DOC( - " Joins a list of bytes trees into a single one.\n" - "\n" - " Runs in constant time.\n" -). --spec concat(list(bytes_tree())) -> bytes_tree(). -concat(Trees) -> - gleam_stdlib:identity(Trees). - --file("src/gleam/bytes_tree.gleam", 35). -?DOC( - " Create an empty `BytesTree`. Useful as the start of a pipe chaining many\n" - " trees together.\n" -). --spec new() -> bytes_tree(). -new() -> - gleam_stdlib:identity([]). - --file("src/gleam/bytes_tree.gleam", 118). -?DOC( - " Creates a new bytes tree from a string.\n" - "\n" - " Runs in constant time when running on Erlang.\n" - " Runs in linear time otherwise.\n" -). --spec from_string(binary()) -> bytes_tree(). -from_string(String) -> - gleam_stdlib:wrap_list(String). - --file("src/gleam/bytes_tree.gleam", 80). -?DOC( - " Prepends a string onto the start of a bytes tree.\n" - "\n" - " Runs in constant time when running on Erlang.\n" - " Runs in linear time with the length of the string otherwise.\n" -). --spec prepend_string(bytes_tree(), binary()) -> bytes_tree(). -prepend_string(Second, First) -> - gleam_stdlib:iodata_append(gleam_stdlib:wrap_list(First), Second). - --file("src/gleam/bytes_tree.gleam", 89). -?DOC( - " Appends a string onto the end of a bytes tree.\n" - "\n" - " Runs in constant time when running on Erlang.\n" - " Runs in linear time with the length of the string otherwise.\n" -). --spec append_string(bytes_tree(), binary()) -> bytes_tree(). -append_string(First, Second) -> - gleam_stdlib:iodata_append(First, gleam_stdlib:wrap_list(Second)). - --file("src/gleam/bytes_tree.gleam", 128). -?DOC( - " Creates a new bytes tree from a string tree.\n" - "\n" - " Runs in constant time when running on Erlang.\n" - " Runs in linear time otherwise.\n" -). --spec from_string_tree(gleam@string_tree:string_tree()) -> bytes_tree(). -from_string_tree(Tree) -> - gleam_stdlib:wrap_list(Tree). - --file("src/gleam/bytes_tree.gleam", 136). -?DOC( - " Creates a new bytes tree from a bit array.\n" - "\n" - " Runs in constant time.\n" -). --spec from_bit_array(bitstring()) -> bytes_tree(). -from_bit_array(Bits) -> - _pipe = Bits, - _pipe@1 = gleam_stdlib:bit_array_pad_to_bytes(_pipe), - gleam_stdlib:wrap_list(_pipe@1). - --file("src/gleam/bytes_tree.gleam", 43). -?DOC( - " Prepends a bit array to the start of a bytes tree.\n" - "\n" - " Runs in constant time.\n" -). --spec prepend(bytes_tree(), bitstring()) -> bytes_tree(). -prepend(Second, First) -> - gleam_stdlib:iodata_append(from_bit_array(First), Second). - --file("src/gleam/bytes_tree.gleam", 51). -?DOC( - " Appends a bit array to the end of a bytes tree.\n" - "\n" - " Runs in constant time.\n" -). --spec append(bytes_tree(), bitstring()) -> bytes_tree(). -append(First, Second) -> - gleam_stdlib:iodata_append(First, from_bit_array(Second)). - --file("src/gleam/bytes_tree.gleam", 106). -?DOC( - " Joins a list of bit arrays into a single bytes tree.\n" - "\n" - " Runs in constant time.\n" -). --spec concat_bit_arrays(list(bitstring())) -> bytes_tree(). -concat_bit_arrays(Bits) -> - _pipe = Bits, - _pipe@1 = gleam@list:map(_pipe, fun from_bit_array/1), - gleam_stdlib:identity(_pipe@1). - --file("src/gleam/bytes_tree.gleam", 162). --spec to_list(list(list(bytes_tree())), list(bitstring())) -> list(bitstring()). -to_list(Stack, Acc) -> - case Stack of - [] -> - Acc; - - [[] | Remaining_stack] -> - to_list(Remaining_stack, Acc); - - [[{bytes, Bits} | Rest] | Remaining_stack@1] -> - to_list([Rest | Remaining_stack@1], [Bits | Acc]); - - [[{text, Tree} | Rest@1] | Remaining_stack@2] -> - Bits@1 = gleam_stdlib:identity(unicode:characters_to_binary(Tree)), - to_list([Rest@1 | Remaining_stack@2], [Bits@1 | Acc]); - - [[{many, Trees} | Rest@2] | Remaining_stack@3] -> - to_list([Trees, Rest@2 | Remaining_stack@3], Acc) - end. - --file("src/gleam/bytes_tree.gleam", 155). -?DOC( - " Turns a bytes tree into a bit array.\n" - "\n" - " Runs in linear time.\n" - "\n" - " When running on Erlang this function is implemented natively by the\n" - " virtual machine and is highly optimised.\n" -). --spec to_bit_array(bytes_tree()) -> bitstring(). -to_bit_array(Tree) -> - erlang:list_to_bitstring(Tree). - --file("src/gleam/bytes_tree.gleam", 186). -?DOC( - " Returns the size of the bytes tree's content in bytes.\n" - "\n" - " Runs in linear time.\n" -). --spec byte_size(bytes_tree()) -> integer(). -byte_size(Tree) -> - erlang:iolist_size(Tree). diff --git a/build/packages/gleam_stdlib/src/gleam@dict.erl b/build/packages/gleam_stdlib/src/gleam@dict.erl deleted file mode 100644 index d496afb..0000000 --- a/build/packages/gleam_stdlib/src/gleam@dict.erl +++ /dev/null @@ -1,561 +0,0 @@ --module(gleam@dict). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "src/gleam/dict.gleam"). --export([size/1, is_empty/1, to_list/1, new/0, get/2, has_key/2, insert/3, from_list/1, keys/1, values/1, take/2, merge/2, delete/2, drop/2, upsert/3, fold/3, map_values/2, filter/2, each/2, combine/3]). --export_type([dict/2]). - --if(?OTP_RELEASE >= 27). --define(MODULEDOC(Str), -moduledoc(Str)). --define(DOC(Str), -doc(Str)). --else. --define(MODULEDOC(Str), -compile([])). --define(DOC(Str), -compile([])). --endif. - --type dict(KG, KH) :: any() | {gleam_phantom, KG, KH}. - --file("src/gleam/dict.gleam", 36). -?DOC( - " Determines the number of key-value pairs in the dict.\n" - " This function runs in constant time and does not need to iterate the dict.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " new() |> size\n" - " // -> 0\n" - " ```\n" - "\n" - " ```gleam\n" - " new() |> insert(\"key\", \"value\") |> size\n" - " // -> 1\n" - " ```\n" -). --spec size(dict(any(), any())) -> integer(). -size(Dict) -> - maps:size(Dict). - --file("src/gleam/dict.gleam", 52). -?DOC( - " Determines whether or not the dict is empty.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " new() |> is_empty\n" - " // -> True\n" - " ```\n" - "\n" - " ```gleam\n" - " new() |> insert(\"b\", 1) |> is_empty\n" - " // -> False\n" - " ```\n" -). --spec is_empty(dict(any(), any())) -> boolean(). -is_empty(Dict) -> - maps:size(Dict) =:= 0. - --file("src/gleam/dict.gleam", 80). -?DOC( - " Converts the dict to a list of 2-element tuples `#(key, value)`, one for\n" - " each key-value pair in the dict.\n" - "\n" - " The tuples in the list have no specific order.\n" - "\n" - " ## Examples\n" - "\n" - " Calling `to_list` on an empty `dict` returns an empty list.\n" - "\n" - " ```gleam\n" - " new() |> to_list\n" - " // -> []\n" - " ```\n" - "\n" - " The ordering of elements in the resulting list is an implementation detail\n" - " that should not be relied upon.\n" - "\n" - " ```gleam\n" - " new() |> insert(\"b\", 1) |> insert(\"a\", 0) |> insert(\"c\", 2) |> to_list\n" - " // -> [#(\"a\", 0), #(\"b\", 1), #(\"c\", 2)]\n" - " ```\n" -). --spec to_list(dict(KQ, KR)) -> list({KQ, KR}). -to_list(Dict) -> - maps:to_list(Dict). - --file("src/gleam/dict.gleam", 129). -?DOC(" Creates a fresh dict that contains no values.\n"). --spec new() -> dict(any(), any()). -new() -> - maps:new(). - --file("src/gleam/dict.gleam", 150). -?DOC( - " Fetches a value from a dict for a given key.\n" - "\n" - " The dict may not have a value for the key, so the value is wrapped in a\n" - " `Result`.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " new() |> insert(\"a\", 0) |> get(\"a\")\n" - " // -> Ok(0)\n" - " ```\n" - "\n" - " ```gleam\n" - " new() |> insert(\"a\", 0) |> get(\"b\")\n" - " // -> Error(Nil)\n" - " ```\n" -). --spec get(dict(LT, LU), LT) -> {ok, LU} | {error, nil}. -get(From, Get) -> - gleam_stdlib:map_get(From, Get). - --file("src/gleam/dict.gleam", 116). -?DOC( - " Determines whether or not a value present in the dict for a given key.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " new() |> insert(\"a\", 0) |> has_key(\"a\")\n" - " // -> True\n" - " ```\n" - "\n" - " ```gleam\n" - " new() |> insert(\"a\", 0) |> has_key(\"b\")\n" - " // -> False\n" - " ```\n" -). --spec has_key(dict(LH, any()), LH) -> boolean(). -has_key(Dict, Key) -> - maps:is_key(Key, Dict). - --file("src/gleam/dict.gleam", 169). -?DOC( - " Inserts a value into the dict with the given key.\n" - "\n" - " If the dict already has a value for the given key then the value is\n" - " replaced with the new value.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " new() |> insert(\"a\", 0)\n" - " // -> from_list([#(\"a\", 0)])\n" - " ```\n" - "\n" - " ```gleam\n" - " new() |> insert(\"a\", 0) |> insert(\"a\", 5)\n" - " // -> from_list([#(\"a\", 5)])\n" - " ```\n" -). --spec insert(dict(LZ, MA), LZ, MA) -> dict(LZ, MA). -insert(Dict, Key, Value) -> - maps:put(Key, Value, Dict). - --file("src/gleam/dict.gleam", 92). --spec from_list_loop(list({LA, LB}), dict(LA, LB)) -> dict(LA, LB). -from_list_loop(List, Initial) -> - case List of - [] -> - Initial; - - [{Key, Value} | Rest] -> - from_list_loop(Rest, insert(Initial, Key, Value)) - end. - --file("src/gleam/dict.gleam", 88). -?DOC( - " Converts a list of 2-element tuples `#(key, value)` to a dict.\n" - "\n" - " If two tuples have the same key the last one in the list will be the one\n" - " that is present in the dict.\n" -). --spec from_list(list({KV, KW})) -> dict(KV, KW). -from_list(List) -> - maps:from_list(List). - --file("src/gleam/dict.gleam", 223). --spec reverse_and_concat(list(NJ), list(NJ)) -> list(NJ). -reverse_and_concat(Remaining, Accumulator) -> - case Remaining of - [] -> - Accumulator; - - [First | Rest] -> - reverse_and_concat(Rest, [First | Accumulator]) - end. - --file("src/gleam/dict.gleam", 216). --spec do_keys_loop(list({NE, any()}), list(NE)) -> list(NE). -do_keys_loop(List, Acc) -> - case List of - [] -> - reverse_and_concat(Acc, []); - - [{Key, _} | Rest] -> - do_keys_loop(Rest, [Key | Acc]) - end. - --file("src/gleam/dict.gleam", 212). -?DOC( - " Gets a list of all keys in a given dict.\n" - "\n" - " Dicts are not ordered so the keys are not returned in any specific order. Do\n" - " not write code that relies on the order keys are returned by this function\n" - " as it may change in later versions of Gleam or Erlang.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " from_list([#(\"a\", 0), #(\"b\", 1)]) |> keys\n" - " // -> [\"a\", \"b\"]\n" - " ```\n" -). --spec keys(dict(MZ, any())) -> list(MZ). -keys(Dict) -> - maps:keys(Dict). - --file("src/gleam/dict.gleam", 249). --spec do_values_loop(list({any(), NT}), list(NT)) -> list(NT). -do_values_loop(List, Acc) -> - case List of - [] -> - reverse_and_concat(Acc, []); - - [{_, Value} | Rest] -> - do_values_loop(Rest, [Value | Acc]) - end. - --file("src/gleam/dict.gleam", 244). -?DOC( - " Gets a list of all values in a given dict.\n" - "\n" - " Dicts are not ordered so the values are not returned in any specific order. Do\n" - " not write code that relies on the order values are returned by this function\n" - " as it may change in later versions of Gleam or Erlang.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " from_list([#(\"a\", 0), #(\"b\", 1)]) |> values\n" - " // -> [0, 1]\n" - " ```\n" -). --spec values(dict(any(), NO)) -> list(NO). -values(Dict) -> - maps:values(Dict). - --file("src/gleam/dict.gleam", 318). --spec do_take_loop(dict(OX, OY), list(OX), dict(OX, OY)) -> dict(OX, OY). -do_take_loop(Dict, Desired_keys, Acc) -> - Insert = fun(Taken, Key) -> case gleam_stdlib:map_get(Dict, Key) of - {ok, Value} -> - insert(Taken, Key, Value); - - {error, _} -> - Taken - end end, - case Desired_keys of - [] -> - Acc; - - [First | Rest] -> - do_take_loop(Dict, Rest, Insert(Acc, First)) - end. - --file("src/gleam/dict.gleam", 309). -?DOC( - " Creates a new dict from a given dict, only including any entries for which the\n" - " keys are in a given list.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " from_list([#(\"a\", 0), #(\"b\", 1)])\n" - " |> take([\"b\"])\n" - " // -> from_list([#(\"b\", 1)])\n" - " ```\n" - "\n" - " ```gleam\n" - " from_list([#(\"a\", 0), #(\"b\", 1)])\n" - " |> take([\"a\", \"b\", \"c\"])\n" - " // -> from_list([#(\"a\", 0), #(\"b\", 1)])\n" - " ```\n" -). --spec take(dict(OJ, OK), list(OJ)) -> dict(OJ, OK). -take(Dict, Desired_keys) -> - maps:with(Desired_keys, Dict). - --file("src/gleam/dict.gleam", 363). --spec insert_pair(dict(PV, PW), {PV, PW}) -> dict(PV, PW). -insert_pair(Dict, Pair) -> - insert(Dict, erlang:element(1, Pair), erlang:element(2, Pair)). - --file("src/gleam/dict.gleam", 356). --spec fold_inserts(list({PO, PP}), dict(PO, PP)) -> dict(PO, PP). -fold_inserts(New_entries, Dict) -> - case New_entries of - [] -> - Dict; - - [First | Rest] -> - fold_inserts(Rest, insert_pair(Dict, First)) - end. - --file("src/gleam/dict.gleam", 350). -?DOC( - " Creates a new dict from a pair of given dicts by combining their entries.\n" - "\n" - " If there are entries with the same keys in both dicts the entry from the\n" - " second dict takes precedence.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " let a = from_list([#(\"a\", 0), #(\"b\", 1)])\n" - " let b = from_list([#(\"b\", 2), #(\"c\", 3)])\n" - " merge(a, b)\n" - " // -> from_list([#(\"a\", 0), #(\"b\", 2), #(\"c\", 3)])\n" - " ```\n" -). --spec merge(dict(PG, PH), dict(PG, PH)) -> dict(PG, PH). -merge(Dict, New_entries) -> - maps:merge(Dict, New_entries). - --file("src/gleam/dict.gleam", 382). -?DOC( - " Creates a new dict from a given dict with all the same entries except for the\n" - " one with a given key, if it exists.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " from_list([#(\"a\", 0), #(\"b\", 1)]) |> delete(\"a\")\n" - " // -> from_list([#(\"b\", 1)])\n" - " ```\n" - "\n" - " ```gleam\n" - " from_list([#(\"a\", 0), #(\"b\", 1)]) |> delete(\"c\")\n" - " // -> from_list([#(\"a\", 0), #(\"b\", 1)])\n" - " ```\n" -). --spec delete(dict(QB, QC), QB) -> dict(QB, QC). -delete(Dict, Key) -> - maps:remove(Key, Dict). - --file("src/gleam/dict.gleam", 410). -?DOC( - " Creates a new dict from a given dict with all the same entries except any with\n" - " keys found in a given list.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " from_list([#(\"a\", 0), #(\"b\", 1)]) |> drop([\"a\"])\n" - " // -> from_list([#(\"b\", 1)])\n" - " ```\n" - "\n" - " ```gleam\n" - " from_list([#(\"a\", 0), #(\"b\", 1)]) |> drop([\"c\"])\n" - " // -> from_list([#(\"a\", 0), #(\"b\", 1)])\n" - " ```\n" - "\n" - " ```gleam\n" - " from_list([#(\"a\", 0), #(\"b\", 1)]) |> drop([\"a\", \"b\", \"c\"])\n" - " // -> from_list([])\n" - " ```\n" -). --spec drop(dict(QN, QO), list(QN)) -> dict(QN, QO). -drop(Dict, Disallowed_keys) -> - case Disallowed_keys of - [] -> - Dict; - - [First | Rest] -> - drop(delete(Dict, First), Rest) - end. - --file("src/gleam/dict.gleam", 440). -?DOC( - " Creates a new dict with one entry inserted or updated using a given function.\n" - "\n" - " If there was not an entry in the dict for the given key then the function\n" - " gets `None` as its argument, otherwise it gets `Some(value)`.\n" - "\n" - " ## Example\n" - "\n" - " ```gleam\n" - " let dict = from_list([#(\"a\", 0)])\n" - " let increment = fn(x) {\n" - " case x {\n" - " Some(i) -> i + 1\n" - " None -> 0\n" - " }\n" - " }\n" - "\n" - " upsert(dict, \"a\", increment)\n" - " // -> from_list([#(\"a\", 1)])\n" - "\n" - " upsert(dict, \"b\", increment)\n" - " // -> from_list([#(\"a\", 0), #(\"b\", 0)])\n" - " ```\n" -). --spec upsert(dict(QU, QV), QU, fun((gleam@option:option(QV)) -> QV)) -> dict(QU, QV). -upsert(Dict, Key, Fun) -> - case gleam_stdlib:map_get(Dict, Key) of - {ok, Value} -> - insert(Dict, Key, Fun({some, Value})); - - {error, _} -> - insert(Dict, Key, Fun(none)) - end. - --file("src/gleam/dict.gleam", 484). --spec fold_loop(list({RG, RH}), RJ, fun((RJ, RG, RH) -> RJ)) -> RJ. -fold_loop(List, Initial, Fun) -> - case List of - [] -> - Initial; - - [{K, V} | Rest] -> - fold_loop(Rest, Fun(Initial, K, V), Fun) - end. - --file("src/gleam/dict.gleam", 476). -?DOC( - " Combines all entries into a single value by calling a given function on each\n" - " one.\n" - "\n" - " Dicts are not ordered so the values are not returned in any specific order. Do\n" - " not write code that relies on the order entries are used by this function\n" - " as it may change in later versions of Gleam or Erlang.\n" - "\n" - " # Examples\n" - "\n" - " ```gleam\n" - " let dict = from_list([#(\"a\", 1), #(\"b\", 3), #(\"c\", 9)])\n" - " fold(dict, 0, fn(accumulator, key, value) { accumulator + value })\n" - " // -> 13\n" - " ```\n" - "\n" - " ```gleam\n" - " import gleam/string\n" - "\n" - " let dict = from_list([#(\"a\", 1), #(\"b\", 3), #(\"c\", 9)])\n" - " fold(dict, \"\", fn(accumulator, key, value) {\n" - " string.append(accumulator, key)\n" - " })\n" - " // -> \"abc\"\n" - " ```\n" -). --spec fold(dict(RB, RC), RF, fun((RF, RB, RC) -> RF)) -> RF. -fold(Dict, Initial, Fun) -> - fold_loop(maps:to_list(Dict), Initial, Fun). - --file("src/gleam/dict.gleam", 188). -?DOC( - " Updates all values in a given dict by calling a given function on each key\n" - " and value.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " from_list([#(3, 3), #(2, 4)])\n" - " |> map_values(fn(key, value) { key * value })\n" - " // -> from_list([#(3, 9), #(2, 8)])\n" - " ```\n" -). --spec map_values(dict(ML, MM), fun((ML, MM) -> MP)) -> dict(ML, MP). -map_values(Dict, Fun) -> - maps:map(Fun, Dict). - --file("src/gleam/dict.gleam", 273). -?DOC( - " Creates a new dict from a given dict, minus any entries that a given function\n" - " returns `False` for.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " from_list([#(\"a\", 0), #(\"b\", 1)])\n" - " |> filter(fn(key, value) { value != 0 })\n" - " // -> from_list([#(\"b\", 1)])\n" - " ```\n" - "\n" - " ```gleam\n" - " from_list([#(\"a\", 0), #(\"b\", 1)])\n" - " |> filter(fn(key, value) { True })\n" - " // -> from_list([#(\"a\", 0), #(\"b\", 1)])\n" - " ```\n" -). --spec filter(dict(NX, NY), fun((NX, NY) -> boolean())) -> dict(NX, NY). -filter(Dict, Predicate) -> - maps:filter(Predicate, Dict). - --file("src/gleam/dict.gleam", 517). -?DOC( - " Calls a function for each key and value in a dict, discarding the return\n" - " value.\n" - "\n" - " Useful for producing a side effect for every item of a dict.\n" - "\n" - " ```gleam\n" - " import gleam/io\n" - "\n" - " let dict = from_list([#(\"a\", \"apple\"), #(\"b\", \"banana\"), #(\"c\", \"cherry\")])\n" - "\n" - " each(dict, fn(k, v) {\n" - " io.println(key <> \" => \" <> value)\n" - " })\n" - " // -> Nil\n" - " // a => apple\n" - " // b => banana\n" - " // c => cherry\n" - " ```\n" - "\n" - " The order of elements in the iteration is an implementation detail that\n" - " should not be relied upon.\n" -). --spec each(dict(RK, RL), fun((RK, RL) -> any())) -> nil. -each(Dict, Fun) -> - fold( - Dict, - nil, - fun(Nil, K, V) -> - Fun(K, V), - Nil - end - ). - --file("src/gleam/dict.gleam", 538). -?DOC( - " Creates a new dict from a pair of given dicts by combining their entries.\n" - "\n" - " If there are entries with the same keys in both dicts the given function is\n" - " used to determine the new value to use in the resulting dict.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " let a = from_list([#(\"a\", 0), #(\"b\", 1)])\n" - " let b = from_list([#(\"a\", 2), #(\"c\", 3)])\n" - " combine(a, b, fn(one, other) { one + other })\n" - " // -> from_list([#(\"a\", 2), #(\"b\", 1), #(\"c\", 3)])\n" - " ```\n" -). --spec combine(dict(RP, RQ), dict(RP, RQ), fun((RQ, RQ) -> RQ)) -> dict(RP, RQ). -combine(Dict, Other, Fun) -> - fold( - Dict, - Other, - fun(Acc, Key, Value) -> case gleam_stdlib:map_get(Acc, Key) of - {ok, Other_value} -> - insert(Acc, Key, Fun(Value, Other_value)); - - {error, _} -> - insert(Acc, Key, Value) - end end - ). diff --git a/build/packages/gleam_stdlib/src/gleam@dynamic.erl b/build/packages/gleam_stdlib/src/gleam@dynamic.erl deleted file mode 100644 index f057ca2..0000000 --- a/build/packages/gleam_stdlib/src/gleam@dynamic.erl +++ /dev/null @@ -1,106 +0,0 @@ --module(gleam@dynamic). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "src/gleam/dynamic.gleam"). --export([classify/1, bool/1, string/1, float/1, int/1, bit_array/1, list/1, array/1, properties/1, nil/0]). --export_type([dynamic_/0]). - --if(?OTP_RELEASE >= 27). --define(MODULEDOC(Str), -moduledoc(Str)). --define(DOC(Str), -doc(Str)). --else. --define(MODULEDOC(Str), -compile([])). --define(DOC(Str), -compile([])). --endif. - --type dynamic_() :: any(). - --file("src/gleam/dynamic.gleam", 30). -?DOC( - " Return a string indicating the type of the dynamic value.\n" - "\n" - " This function may be useful for constructing error messages or logs. If you\n" - " want to turn dynamic data into well typed data then you want the\n" - " `gleam/dynamic/decode` module.\n" - "\n" - " ```gleam\n" - " classify(string(\"Hello\"))\n" - " // -> \"String\"\n" - " ```\n" -). --spec classify(dynamic_()) -> binary(). -classify(Data) -> - gleam_stdlib:classify_dynamic(Data). - --file("src/gleam/dynamic.gleam", 36). -?DOC(" Create a dynamic value from a bool.\n"). --spec bool(boolean()) -> dynamic_(). -bool(A) -> - gleam_stdlib:identity(A). - --file("src/gleam/dynamic.gleam", 44). -?DOC( - " Create a dynamic value from a string.\n" - "\n" - " On Erlang this will be a binary string rather than a character list.\n" -). --spec string(binary()) -> dynamic_(). -string(A) -> - gleam_stdlib:identity(A). - --file("src/gleam/dynamic.gleam", 50). -?DOC(" Create a dynamic value from a float.\n"). --spec float(float()) -> dynamic_(). -float(A) -> - gleam_stdlib:identity(A). - --file("src/gleam/dynamic.gleam", 56). -?DOC(" Create a dynamic value from an int.\n"). --spec int(integer()) -> dynamic_(). -int(A) -> - gleam_stdlib:identity(A). - --file("src/gleam/dynamic.gleam", 62). -?DOC(" Create a dynamic value from a bit array.\n"). --spec bit_array(bitstring()) -> dynamic_(). -bit_array(A) -> - gleam_stdlib:identity(A). - --file("src/gleam/dynamic.gleam", 68). -?DOC(" Create a dynamic value from a list.\n"). --spec list(list(dynamic_())) -> dynamic_(). -list(A) -> - gleam_stdlib:identity(A). - --file("src/gleam/dynamic.gleam", 77). -?DOC( - " Create a dynamic value from a list, converting it to a sequential runtime\n" - " format rather than the regular list format.\n" - "\n" - " On Erlang this will be a tuple, on JavaScript this will be an array.\n" -). --spec array(list(dynamic_())) -> dynamic_(). -array(A) -> - erlang:list_to_tuple(A). - --file("src/gleam/dynamic.gleam", 85). -?DOC( - " Create a dynamic value made an unordered series of keys and values, where\n" - " the keys are unique.\n" - "\n" - " On Erlang this will be a map, on JavaScript this will be a Gleam dict\n" - " object.\n" -). --spec properties(list({dynamic_(), dynamic_()})) -> dynamic_(). -properties(Entries) -> - gleam_stdlib:identity(maps:from_list(Entries)). - --file("src/gleam/dynamic.gleam", 94). -?DOC( - " A dynamic value representing nothing.\n" - "\n" - " On Erlang this will be the atom `nil`, on JavaScript this will be\n" - " `undefined`.\n" -). --spec nil() -> dynamic_(). -nil() -> - gleam_stdlib:identity(nil). diff --git a/build/packages/gleam_stdlib/src/gleam@dynamic@decode.erl b/build/packages/gleam_stdlib/src/gleam@dynamic@decode.erl deleted file mode 100644 index bf4b951..0000000 --- a/build/packages/gleam_stdlib/src/gleam@dynamic@decode.erl +++ /dev/null @@ -1,1088 +0,0 @@ --module(gleam@dynamic@decode). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "src/gleam/dynamic/decode.gleam"). --export([run/2, success/1, decode_dynamic/1, map/2, map_errors/2, then/2, one_of/2, recursive/1, optional/1, decode_error/2, decode_bool/1, decode_int/1, decode_float/1, decode_bit_array/1, collapse_errors/2, failure/2, new_primitive_decoder/2, decode_string/1, dict/2, list/1, subfield/3, at/2, field/3, optional_field/4, optionally_at/3]). --export_type([decode_error/0, decoder/1]). - --if(?OTP_RELEASE >= 27). --define(MODULEDOC(Str), -moduledoc(Str)). --define(DOC(Str), -doc(Str)). --else. --define(MODULEDOC(Str), -compile([])). --define(DOC(Str), -compile([])). --endif. - -?MODULEDOC( - " The `Dynamic` type is used to represent dynamically typed data. That is, data\n" - " that we don't know the precise type of yet, so we need to introspect the data to\n" - " see if it is of the desired type before we can use it. Typically data like this\n" - " would come from user input or from untyped languages such as Erlang or JavaScript.\n" - "\n" - " This module provides the `Decoder` type and associated functions, which provides\n" - " a type-safe and composable way to convert dynamic data into some desired type,\n" - " or into errors if the data doesn't have the desired structure.\n" - "\n" - " The `Decoder` type is generic and has 1 type parameter, which is the type that\n" - " it attempts to decode. A `Decoder(String)` can be used to decode strings, and a\n" - " `Decoder(Option(Int))` can be used to decode `Option(Int)`s\n" - "\n" - " Decoders work using _runtime reflection_ and the data structures of the target\n" - " platform. Differences between Erlang and JavaScript data structures may impact\n" - " your decoders, so it is important to test your decoders on all supported\n" - " platforms.\n" - "\n" - " The decoding technique used by this module was inspired by Juraj Petráš'\n" - " [Toy](https://github.com/Hackder/toy), Go's `encoding/json`, and Elm's\n" - " `Json.Decode`. Thank you to them!\n" - "\n" - " # Examples\n" - "\n" - " Dynamic data may come from various sources and so many different syntaxes could\n" - " be used to describe or construct them. In these examples a pseudocode\n" - " syntax is used to describe the data.\n" - "\n" - " ## Simple types\n" - "\n" - " This module defines decoders for simple data types such as [`string`](#string),\n" - " [`int`](#int), [`float`](#float), [`bit_array`](#bit_array), and [`bool`](#bool).\n" - "\n" - " ```gleam\n" - " // Data:\n" - " // \"Hello, Joe!\"\n" - "\n" - " let result = decode.run(data, decode.string)\n" - " assert result == Ok(\"Hello, Joe!\")\n" - " ```\n" - "\n" - " ## Lists\n" - "\n" - " The [`list`](#list) decoder decodes `List`s. To use it you must construct it by\n" - " passing in another decoder into the `list` function, which is the decoder that\n" - " is to be used for the elements of the list, type checking both the list and its\n" - " elements.\n" - "\n" - " ```gleam\n" - " // Data:\n" - " // [1, 2, 3, 4]\n" - "\n" - " let result = decode.run(data, decode.list(decode.int))\n" - " assert result == Ok([1, 2, 3, 4])\n" - " ```\n" - "\n" - " On Erlang this decoder can decode from lists, and on JavaScript it can\n" - " decode from lists as well as JavaScript arrays.\n" - "\n" - " ## Options\n" - "\n" - " The [`optional`](#optional) decoder is used to decode values that may or may not\n" - " be present. In other environment these might be called \"nullable\" values.\n" - "\n" - " Like the `list` decoder, the `optional` decoder takes another decoder,\n" - " which is used to decode the value if it is present.\n" - "\n" - " ```gleam\n" - " // Data:\n" - " // 12.45\n" - "\n" - " let result = decode.run(data, decode.optional(decode.float))\n" - " assert result == Ok(option.Some(12.45))\n" - " ```\n" - " ```gleam\n" - " // Data:\n" - " // null\n" - "\n" - " let result = decode.run(data, decode.optional(decode.int))\n" - " assert result == Ok(option.None)\n" - " ```\n" - "\n" - " This decoder knows how to handle multiple different runtime representations of\n" - " absent values, including `Nil`, `None`, `null`, and `undefined`.\n" - "\n" - " ## Dicts\n" - "\n" - " The [`dict`](#dict) decoder decodes `Dicts` and contains two other decoders, one\n" - " for the keys, one for the values.\n" - "\n" - " ```gleam\n" - " // Data:\n" - " // { \"Lucy\" -> 10, \"Nubi\" -> 20 }\n" - "\n" - " let result = decode.run(data, decode.dict(decode.string, decode.int))\n" - " assert result == Ok(dict.from_list([\n" - " #(\"Lucy\", 10),\n" - " #(\"Nubi\", 20),\n" - " ]))\n" - " ```\n" - "\n" - " ## Indexing objects\n" - "\n" - " The [`at`](#at) decoder can be used to decode a value that is nested within\n" - " key-value containers such as Gleam dicts, Erlang maps, or JavaScript objects.\n" - "\n" - " ```gleam\n" - " // Data:\n" - " // { \"one\" -> { \"two\" -> 123 } }\n" - "\n" - " let result = decode.run(data, decode.at([\"one\", \"two\"], decode.int))\n" - " assert result == Ok(123)\n" - " ```\n" - "\n" - " ## Indexing arrays\n" - "\n" - " If you use ints as keys then the [`at`](#at) decoder can be used to index into\n" - " array-like containers such as Gleam or Erlang tuples, or JavaScript arrays.\n" - "\n" - " ```gleam\n" - " // Data:\n" - " // [\"one\", \"two\", \"three\"]\n" - "\n" - " let result = decode.run(data, decode.at([1], decode.string))\n" - " assert result == Ok(\"two\")\n" - " ```\n" - "\n" - " ## Records\n" - "\n" - " Decoding records from dynamic data is more complex and requires combining a\n" - " decoder for each field and a special constructor that builds your records with\n" - " the decoded field values.\n" - "\n" - " ```gleam\n" - " // Data:\n" - " // {\n" - " // \"score\" -> 180,\n" - " // \"name\" -> \"Mel Smith\",\n" - " // \"is-admin\" -> false,\n" - " // \"enrolled\" -> true,\n" - " // \"colour\" -> \"Red\",\n" - " // }\n" - "\n" - " let decoder = {\n" - " use name <- decode.field(\"name\", decode.string)\n" - " use score <- decode.field(\"score\", decode.int)\n" - " use colour <- decode.field(\"colour\", decode.string)\n" - " use enrolled <- decode.field(\"enrolled\", decode.bool)\n" - " decode.success(Player(name:, score:, colour:, enrolled:))\n" - " }\n" - "\n" - " let result = decode.run(data, decoder)\n" - " assert result == Ok(Player(\"Mel Smith\", 180, \"Red\", True))\n" - " ```\n" - "\n" - " ## Enum variants\n" - "\n" - " Imagine you have a custom type where all the variants do not contain any values.\n" - "\n" - " ```gleam\n" - " pub type PocketMonsterType {\n" - " Fire\n" - " Water\n" - " Grass\n" - " Electric\n" - " }\n" - " ```\n" - "\n" - " You might choose to encode these variants as strings, `\"fire\"` for `Fire`,\n" - " `\"water\"` for `Water`, and so on. To decode them you'll need to decode the dynamic\n" - " data as a string, but then you'll need to decode it further still as not all\n" - " strings are valid values for the enum. This can be done with the `then`\n" - " function, which enables running a second decoder after the first one\n" - " succeeds.\n" - "\n" - " ```gleam\n" - " let decoder = {\n" - " use decoded_string <- decode.then(decode.string)\n" - " case decoded_string {\n" - " // Return succeeding decoders for valid strings\n" - " \"fire\" -> decode.success(Fire)\n" - " \"water\" -> decode.success(Water)\n" - " \"grass\" -> decode.success(Grass)\n" - " \"electric\" -> decode.success(Electric)\n" - " // Return a failing decoder for any other strings\n" - " _ -> decode.failure(Fire, \"PocketMonsterType\")\n" - " }\n" - " }\n" - "\n" - " let result = decode.run(dynamic.string(\"water\"), decoder)\n" - " assert result == Ok(Water)\n" - "\n" - " let result = decode.run(dynamic.string(\"wobble\"), decoder)\n" - " assert result == Error([DecodeError(\"PocketMonsterType\", \"String\", [])])\n" - " ```\n" - "\n" - " ## Record variants\n" - "\n" - " Decoding type variants that contain other values is done by combining the\n" - " techniques from the \"enum variants\" and \"records\" examples. Imagine you have\n" - " this custom type that you want to decode:\n" - "\n" - " ```gleam\n" - " pub type PocketMonsterPerson {\n" - " Trainer(name: String, badge_count: Int)\n" - " GymLeader(name: String, speciality: PocketMonsterType)\n" - " }\n" - " ```\n" - " And you would like to be able to decode these from dynamic data like this:\n" - " ```erlang\n" - " {\n" - " \"type\" -> \"trainer\",\n" - " \"name\" -> \"Ash\",\n" - " \"badge-count\" -> 1,\n" - " }\n" - " ```\n" - " ```erlang\n" - " {\n" - " \"type\" -> \"gym-leader\",\n" - " \"name\" -> \"Misty\",\n" - " \"speciality\" -> \"water\",\n" - " }\n" - " ```\n" - "\n" - " Notice how both documents have a `\"type\"` field, which is used to indicate which\n" - " variant the data is for.\n" - "\n" - " First, define decoders for each of the variants:\n" - "\n" - " ```gleam\n" - " let trainer_decoder = {\n" - " use name <- decode.field(\"name\", decode.string)\n" - " use badge_count <- decode.field(\"badge-count\", decode.int)\n" - " decode.success(Trainer(name, badge_count))\n" - " }\n" - "\n" - " let gym_leader_decoder = {\n" - " use name <- decode.field(\"name\", decode.string)\n" - " use speciality <- decode.field(\"speciality\", pocket_monster_type_decoder)\n" - " decode.success(GymLeader(name, speciality))\n" - " }\n" - " ```\n" - "\n" - " A third decoder can be used to extract and decode the `\"type\"` field, and the\n" - " expression can evaluate to whichever decoder is suitable for the document.\n" - "\n" - " ```gleam\n" - " // Data:\n" - " // {\n" - " // \"type\" -> \"gym-leader\",\n" - " // \"name\" -> \"Misty\",\n" - " // \"speciality\" -> \"water\",\n" - " // }\n" - "\n" - " let decoder = {\n" - " use tag <- decode.field(\"type\", decode.string)\n" - " case tag {\n" - " \"gym-leader\" -> gym_leader_decoder\n" - " _ -> trainer_decoder\n" - " }\n" - " }\n" - "\n" - " let result = decode.run(data, decoder)\n" - " assert result == Ok(GymLeader(\"Misty\", Water))\n" - " ```\n" -). - --type decode_error() :: {decode_error, binary(), binary(), list(binary())}. - --opaque decoder(BUW) :: {decoder, - fun((gleam@dynamic:dynamic_()) -> {BUW, list(decode_error())})}. - --file("src/gleam/dynamic/decode.gleam", 356). -?DOC( - " Run a decoder on a `Dynamic` value, decoding the value if it is of the\n" - " desired type, or returning errors.\n" - "\n" - " # Examples\n" - "\n" - " ```gleam\n" - " let decoder = {\n" - " use name <- decode.field(\"email\", decode.string)\n" - " use email <- decode.field(\"password\", decode.string)\n" - " decode.success(SignUp(name: name, email: email))\n" - " }\n" - "\n" - " decode.run(data, decoder)\n" - " ```\n" -). --spec run(gleam@dynamic:dynamic_(), decoder(BVE)) -> {ok, BVE} | - {error, list(decode_error())}. -run(Data, Decoder) -> - {Maybe_invalid_data, Errors} = (erlang:element(2, Decoder))(Data), - case Errors of - [] -> - {ok, Maybe_invalid_data}; - - [_ | _] -> - {error, Errors} - end. - --file("src/gleam/dynamic/decode.gleam", 479). -?DOC( - " Finalise a decoder having successfully extracted a value.\n" - "\n" - " # Examples\n" - "\n" - " ```gleam\n" - " let data = dynamic.properties([\n" - " #(dynamic.string(\"email\"), dynamic.string(\"lucy@example.com\")),\n" - " #(dynamic.string(\"name\"), dynamic.string(\"Lucy\")),\n" - " ]))\n" - "\n" - " let decoder = {\n" - " use name <- decode.field(\"name\", string)\n" - " use email <- decode.field(\"email\", string)\n" - " decode.success(SignUp(name: name, email: email))\n" - " }\n" - "\n" - " let result = decode.run(data, decoder)\n" - " assert result == Ok(SignUp(name: \"Lucy\", email: \"lucy@example.com\"))\n" - " ```\n" -). --spec success(BWF) -> decoder(BWF). -success(Data) -> - {decoder, fun(_) -> {Data, []} end}. - --file("src/gleam/dynamic/decode.gleam", 718). --spec decode_dynamic(gleam@dynamic:dynamic_()) -> {gleam@dynamic:dynamic_(), - list(decode_error())}. -decode_dynamic(Data) -> - {Data, []}. - --file("src/gleam/dynamic/decode.gleam", 875). -?DOC( - " Apply a transformation function to any value decoded by the decoder.\n" - "\n" - " # Examples\n" - "\n" - " ```gleam\n" - " let decoder = decode.int |> decode.map(int.to_string)\n" - " let result = decode.run(dynamic.int(1000), decoder)\n" - " assert result == Ok(\"1000\")\n" - " ```\n" -). --spec map(decoder(BZC), fun((BZC) -> BZE)) -> decoder(BZE). -map(Decoder, Transformer) -> - {decoder, - fun(D) -> - {Data, Errors} = (erlang:element(2, Decoder))(D), - {Transformer(Data), Errors} - end}. - --file("src/gleam/dynamic/decode.gleam", 884). -?DOC(" Apply a transformation function to any errors returned by the decoder.\n"). --spec map_errors( - decoder(BZG), - fun((list(decode_error())) -> list(decode_error())) -) -> decoder(BZG). -map_errors(Decoder, Transformer) -> - {decoder, - fun(D) -> - {Data, Errors} = (erlang:element(2, Decoder))(D), - {Data, Transformer(Errors)} - end}. - --file("src/gleam/dynamic/decode.gleam", 922). -?DOC( - " Create a new decoder based upon the value of a previous decoder.\n" - "\n" - " This may be useful to run one previous decoder to use in further decoding.\n" -). --spec then(decoder(BZO), fun((BZO) -> decoder(BZQ))) -> decoder(BZQ). -then(Decoder, Next) -> - {decoder, - fun(Dynamic_data) -> - {Data, Errors} = (erlang:element(2, Decoder))(Dynamic_data), - Decoder@1 = Next(Data), - {Data@1, _} = Layer = (erlang:element(2, Decoder@1))(Dynamic_data), - case Errors of - [] -> - Layer; - - [_ | _] -> - {Data@1, Errors} - end - end}. - --file("src/gleam/dynamic/decode.gleam", 965). --spec run_decoders( - gleam@dynamic:dynamic_(), - {BZY, list(decode_error())}, - list(decoder(BZY)) -) -> {BZY, list(decode_error())}. -run_decoders(Data, Failure, Decoders) -> - case Decoders of - [] -> - Failure; - - [Decoder | Decoders@1] -> - {_, Errors} = Layer = (erlang:element(2, Decoder))(Data), - case Errors of - [] -> - Layer; - - [_ | _] -> - run_decoders(Data, Failure, Decoders@1) - end - end. - --file("src/gleam/dynamic/decode.gleam", 952). -?DOC( - " Create a new decoder from several other decoders. Each of the inner\n" - " decoders is run in turn, and the value from the first to succeed is used.\n" - "\n" - " If no decoder succeeds then the errors from the first decoder is used.\n" - " If you wish for different errors then you may wish to use the\n" - " `collapse_errors` or `map_errors` functions.\n" - "\n" - " # Examples\n" - "\n" - " ```gleam\n" - " let decoder = decode.one_of(decode.string, or: [\n" - " decode.int |> decode.map(int.to_string),\n" - " decode.float |> decode.map(float.to_string),\n" - " ])\n" - " decode.run(dynamic.int(1000), decoder)\n" - " // -> Ok(\"1000\")\n" - " ```\n" -). --spec one_of(decoder(BZT), list(decoder(BZT))) -> decoder(BZT). -one_of(First, Alternatives) -> - {decoder, - fun(Dynamic_data) -> - {_, Errors} = Layer = (erlang:element(2, First))(Dynamic_data), - case Errors of - [] -> - Layer; - - [_ | _] -> - run_decoders(Dynamic_data, Layer, Alternatives) - end - end}. - --file("src/gleam/dynamic/decode.gleam", 1048). -?DOC( - " Create a decoder that can refer to itself, useful for decoding deeply\n" - " nested data.\n" - "\n" - " Attempting to create a recursive decoder without this function could result\n" - " in an infinite loop. If you are using `field` or other `use`able functions\n" - " then you may not need to use this function.\n" - "\n" - " ```gleam\n" - " type Nested {\n" - " Nested(List(Nested))\n" - " Value(String)\n" - " }\n" - "\n" - " fn nested_decoder() -> decode.Decoder(Nested) {\n" - " use <- decode.recursive\n" - " decode.one_of(decode.string |> decode.map(Value), [\n" - " decode.list(nested_decoder()) |> decode.map(Nested),\n" - " ])\n" - " }\n" - " ```\n" -). --spec recursive(fun(() -> decoder(CAJ))) -> decoder(CAJ). -recursive(Inner) -> - {decoder, - fun(Data) -> - Decoder = Inner(), - (erlang:element(2, Decoder))(Data) - end}. - --file("src/gleam/dynamic/decode.gleam", 853). -?DOC( - " A decoder that decodes nullable values of a type decoded by with a given\n" - " decoder.\n" - "\n" - " This function can handle common representations of null on all runtimes, such as\n" - " `nil`, `null`, and `undefined` on Erlang, and `undefined` and `null` on\n" - " JavaScript.\n" - "\n" - " # Examples\n" - "\n" - " ```gleam\n" - " let result = decode.run(dynamic.int(100), decode.optional(decode.int))\n" - " assert result == Ok(option.Some(100))\n" - " ```\n" - "\n" - " ```gleam\n" - " let result = decode.run(dynamic.nil(), decode.optional(decode.int))\n" - " assert result == Ok(option.None)\n" - " ```\n" -). --spec optional(decoder(BYY)) -> decoder(gleam@option:option(BYY)). -optional(Inner) -> - {decoder, fun(Data) -> case gleam_stdlib:is_null(Data) of - true -> - {none, []}; - - false -> - {Data@1, Errors} = (erlang:element(2, Inner))(Data), - {{some, Data@1}, Errors} - end end}. - --file("src/gleam/dynamic/decode.gleam", 485). -?DOC(" Construct a decode error for some unexpected dynamic data.\n"). --spec decode_error(binary(), gleam@dynamic:dynamic_()) -> list(decode_error()). -decode_error(Expected, Found) -> - [{decode_error, Expected, gleam_stdlib:classify_dynamic(Found), []}]. - --file("src/gleam/dynamic/decode.gleam", 609). --spec run_dynamic_function( - gleam@dynamic:dynamic_(), - binary(), - fun((gleam@dynamic:dynamic_()) -> {ok, BWZ} | {error, BWZ}) -) -> {BWZ, list(decode_error())}. -run_dynamic_function(Data, Name, F) -> - case F(Data) of - {ok, Data@1} -> - {Data@1, []}; - - {error, Zero} -> - {Zero, - [{decode_error, Name, gleam_stdlib:classify_dynamic(Data), []}]} - end. - --file("src/gleam/dynamic/decode.gleam", 658). --spec decode_bool(gleam@dynamic:dynamic_()) -> {boolean(), list(decode_error())}. -decode_bool(Data) -> - case gleam_stdlib:identity(true) =:= Data of - true -> - {true, []}; - - false -> - case gleam_stdlib:identity(false) =:= Data of - true -> - {false, []}; - - false -> - {false, decode_error(<<"Bool"/utf8>>, Data)} - end - end. - --file("src/gleam/dynamic/decode.gleam", 680). --spec decode_int(gleam@dynamic:dynamic_()) -> {integer(), list(decode_error())}. -decode_int(Data) -> - run_dynamic_function(Data, <<"Int"/utf8>>, fun gleam_stdlib:int/1). - --file("src/gleam/dynamic/decode.gleam", 699). --spec decode_float(gleam@dynamic:dynamic_()) -> {float(), list(decode_error())}. -decode_float(Data) -> - run_dynamic_function(Data, <<"Float"/utf8>>, fun gleam_stdlib:float/1). - --file("src/gleam/dynamic/decode.gleam", 733). --spec decode_bit_array(gleam@dynamic:dynamic_()) -> {bitstring(), - list(decode_error())}. -decode_bit_array(Data) -> - run_dynamic_function( - Data, - <<"BitArray"/utf8>>, - fun gleam_stdlib:bit_array/1 - ). - --file("src/gleam/dynamic/decode.gleam", 908). -?DOC( - " Replace all errors produced by a decoder with one single error for a named\n" - " expected type.\n" - "\n" - " This function may be useful if you wish to simplify errors before\n" - " presenting them to a user, particularly when using the `one_of` function.\n" - "\n" - " # Examples\n" - "\n" - " ```gleam\n" - " let decoder = decode.string |> decode.collapse_errors(\"MyThing\")\n" - " let result = decode.run(dynamic.int(1000), decoder)\n" - " assert result == Error([DecodeError(\"MyThing\", \"Int\", [])])\n" - " ```\n" -). --spec collapse_errors(decoder(BZL), binary()) -> decoder(BZL). -collapse_errors(Decoder, Name) -> - {decoder, - fun(Dynamic_data) -> - {Data, Errors} = Layer = (erlang:element(2, Decoder))(Dynamic_data), - case Errors of - [] -> - Layer; - - [_ | _] -> - {Data, decode_error(Name, Dynamic_data)} - end - end}. - --file("src/gleam/dynamic/decode.gleam", 986). -?DOC( - " Define a decoder that always fails. The parameter for this function is the\n" - " name of the type that has failed to decode.\n" -). --spec failure(CAD, binary()) -> decoder(CAD). -failure(Zero, Expected) -> - {decoder, fun(D) -> {Zero, decode_error(Expected, D)} end}. - --file("src/gleam/dynamic/decode.gleam", 1015). -?DOC( - " Create a decoder for a new data type from a decoding function.\n" - "\n" - " This function is used for new primitive types. For example, you might\n" - " define a decoder for Erlang's pid type.\n" - "\n" - " A default \"zero\" value is also required to make a decoder. When this\n" - " decoder is used as part of a larger decoder this zero value used as\n" - " a placeholder so that the rest of the decoder can continue to run and\n" - " collect all decoding errors.\n" - "\n" - " If you were to make a decoder for the `String` type (rather than using the\n" - " build-in `string` decoder) you would define it like so:\n" - "\n" - " ```gleam\n" - " pub fn string_decoder() -> decode.Decoder(String) {\n" - " let default = \"\"\n" - " decode.new_primitive_decoder(\"String\", fn(data) {\n" - " case dynamic.string(data) {\n" - " Ok(x) -> Ok(x)\n" - " Error(_) -> Error(default)\n" - " }\n" - " })\n" - " }\n" - " ```\n" -). --spec new_primitive_decoder( - binary(), - fun((gleam@dynamic:dynamic_()) -> {ok, CAF} | {error, CAF}) -) -> decoder(CAF). -new_primitive_decoder(Name, Decoding_function) -> - {decoder, fun(D) -> case Decoding_function(D) of - {ok, T} -> - {T, []}; - - {error, Zero} -> - {Zero, - [{decode_error, - Name, - gleam_stdlib:classify_dynamic(D), - []}]} - end end}. - --file("src/gleam/dynamic/decode.gleam", 636). --spec dynamic_string(gleam@dynamic:dynamic_()) -> {ok, binary()} | - {error, binary()}. -dynamic_string(Data) -> - case gleam_stdlib:bit_array(Data) of - {ok, Data@1} -> - case gleam@bit_array:to_string(Data@1) of - {ok, String} -> - {ok, String}; - - {error, _} -> - {error, <<""/utf8>>} - end; - - {error, _} -> - {error, <<""/utf8>>} - end. - --file("src/gleam/dynamic/decode.gleam", 631). --spec decode_string(gleam@dynamic:dynamic_()) -> {binary(), - list(decode_error())}. -decode_string(Data) -> - run_dynamic_function(Data, <<"String"/utf8>>, fun dynamic_string/1). - --file("src/gleam/dynamic/decode.gleam", 807). --spec fold_dict( - {gleam@dict:dict(BYK, BYL), list(decode_error())}, - gleam@dynamic:dynamic_(), - gleam@dynamic:dynamic_(), - fun((gleam@dynamic:dynamic_()) -> {BYK, list(decode_error())}), - fun((gleam@dynamic:dynamic_()) -> {BYL, list(decode_error())}) -) -> {gleam@dict:dict(BYK, BYL), list(decode_error())}. -fold_dict(Acc, Key, Value, Key_decoder, Value_decoder) -> - case Key_decoder(Key) of - {Key@1, []} -> - case Value_decoder(Value) of - {Value@1, []} -> - Dict = gleam@dict:insert( - erlang:element(1, Acc), - Key@1, - Value@1 - ), - {Dict, erlang:element(2, Acc)}; - - {_, Errors} -> - push_path({maps:new(), Errors}, [<<"values"/utf8>>]) - end; - - {_, Errors@1} -> - push_path({maps:new(), Errors@1}, [<<"keys"/utf8>>]) - end. - --file("src/gleam/dynamic/decode.gleam", 787). -?DOC( - " A decoder that decodes dicts where all keys and vales are decoded with\n" - " given decoders.\n" - "\n" - " # Examples\n" - "\n" - " ```gleam\n" - " let values = dynamic.properties([\n" - " #(dynamic.string(\"one\"), dynamic.int(1)),\n" - " #(dynamic.string(\"two\"), dynamic.int(2)),\n" - " ])\n" - "\n" - " let result =\n" - " decode.run(values, decode.dict(decode.string, decode.int))\n" - " assert result == Ok(values)\n" - " ```\n" -). --spec dict(decoder(BYD), decoder(BYF)) -> decoder(gleam@dict:dict(BYD, BYF)). -dict(Key, Value) -> - {decoder, fun(Data) -> case gleam_stdlib:dict(Data) of - {error, _} -> - {maps:new(), decode_error(<<"Dict"/utf8>>, Data)}; - - {ok, Dict} -> - gleam@dict:fold( - Dict, - {maps:new(), []}, - fun(A, K, V) -> case erlang:element(2, A) of - [] -> - fold_dict( - A, - K, - V, - erlang:element(2, Key), - erlang:element(2, Value) - ); - - [_ | _] -> - A - end end - ) - end end}. - --file("src/gleam/dynamic/decode.gleam", 755). -?DOC( - " A decoder that decodes lists where all elements are decoded with a given\n" - " decoder.\n" - "\n" - " # Examples\n" - "\n" - " ```gleam\n" - " let result =\n" - " [1, 2, 3]\n" - " |> list.map(dynamic.int)\n" - " |> dynamic.list\n" - " |> decode.run(decode.list(of: decode.int))\n" - " assert result == Ok([1, 2, 3])\n" - " ```\n" -). --spec list(decoder(BXR)) -> decoder(list(BXR)). -list(Inner) -> - {decoder, - fun(Data) -> - gleam_stdlib:list( - Data, - erlang:element(2, Inner), - fun(P, K) -> push_path(P, [K]) end, - 0, - [] - ) - end}. - --file("src/gleam/dynamic/decode.gleam", 439). --spec push_path({BWA, list(decode_error())}, list(any())) -> {BWA, - list(decode_error())}. -push_path(Layer, Path) -> - Decoder = one_of( - {decoder, fun decode_string/1}, - [begin - _pipe = {decoder, fun decode_int/1}, - map(_pipe, fun erlang:integer_to_binary/1) - end] - ), - Path@1 = gleam@list:map( - Path, - fun(Key) -> - Key@1 = gleam_stdlib:identity(Key), - case run(Key@1, Decoder) of - {ok, Key@2} -> - Key@2; - - {error, _} -> - <<<<"<"/utf8, - (gleam_stdlib:classify_dynamic(Key@1))/binary>>/binary, - ">"/utf8>> - end - end - ), - Errors = gleam@list:map( - erlang:element(2, Layer), - fun(Error) -> - {decode_error, - erlang:element(2, Error), - erlang:element(3, Error), - lists:append(Path@1, erlang:element(4, Error))} - end - ), - {erlang:element(1, Layer), Errors}. - --file("src/gleam/dynamic/decode.gleam", 403). --spec index( - list(BVO), - list(BVO), - fun((gleam@dynamic:dynamic_()) -> {BVR, list(decode_error())}), - gleam@dynamic:dynamic_(), - fun((gleam@dynamic:dynamic_(), list(BVO)) -> {BVR, list(decode_error())}) -) -> {BVR, list(decode_error())}. -index(Path, Position, Inner, Data, Handle_miss) -> - case Path of - [] -> - _pipe = Data, - _pipe@1 = Inner(_pipe), - push_path(_pipe@1, lists:reverse(Position)); - - [Key | Path@1] -> - case gleam_stdlib:index(Data, Key) of - {ok, {some, Data@1}} -> - index(Path@1, [Key | Position], Inner, Data@1, Handle_miss); - - {ok, none} -> - Handle_miss(Data, [Key | Position]); - - {error, Kind} -> - {Default, _} = Inner(Data), - _pipe@2 = {Default, - [{decode_error, - Kind, - gleam_stdlib:classify_dynamic(Data), - []}]}, - push_path(_pipe@2, lists:reverse(Position)) - end - end. - --file("src/gleam/dynamic/decode.gleam", 324). -?DOC( - " The same as [`field`](#field), except taking a path to the value rather\n" - " than a field name.\n" - "\n" - " This function will index into dictionaries with any key type, and if the key is\n" - " an int then it'll also index into Erlang tuples and JavaScript arrays, and\n" - " the first eight elements of Gleam lists.\n" - "\n" - " # Examples\n" - "\n" - " ```gleam\n" - " let data = dynamic.properties([\n" - " #(dynamic.string(\"data\"), dynamic.properties([\n" - " #(dynamic.string(\"email\"), dynamic.string(\"lucy@example.com\")),\n" - " #(dynamic.string(\"name\"), dynamic.string(\"Lucy\")),\n" - " ])\n" - " ]))\n" - "\n" - " let decoder = {\n" - " use name <- decode.subfield([\"data\", \"name\"], decode.string)\n" - " use email <- decode.subfield([\"data\", \"email\"], decode.string)\n" - " decode.success(SignUp(name: name, email: email))\n" - " }\n" - " let result = decode.run(data, decoder)\n" - " assert result == Ok(SignUp(name: \"Lucy\", email: \"lucy@example.com\"))\n" - " ```\n" -). --spec subfield(list(any()), decoder(BUZ), fun((BUZ) -> decoder(BVB))) -> decoder(BVB). -subfield(Field_path, Field_decoder, Next) -> - {decoder, - fun(Data) -> - {Out, Errors1} = index( - Field_path, - [], - erlang:element(2, Field_decoder), - Data, - fun(Data@1, Position) -> - {Default, _} = (erlang:element(2, Field_decoder))(Data@1), - _pipe = {Default, - [{decode_error, - <<"Field"/utf8>>, - <<"Nothing"/utf8>>, - []}]}, - push_path(_pipe, lists:reverse(Position)) - end - ), - {Out@1, Errors2} = (erlang:element(2, Next(Out)))(Data), - {Out@1, lists:append(Errors1, Errors2)} - end}. - --file("src/gleam/dynamic/decode.gleam", 393). -?DOC( - " A decoder that decodes a value that is nested within other values. For\n" - " example, decoding a value that is within some deeply nested JSON objects.\n" - "\n" - " This function will index into dictionaries with any key type, and if the key is\n" - " an int then it'll also index into Erlang tuples and JavaScript arrays, and\n" - " the first eight elements of Gleam lists.\n" - "\n" - " # Examples\n" - "\n" - " ```gleam\n" - " let decoder = decode.at([\"one\", \"two\"], decode.int)\n" - "\n" - " let data = dynamic.properties([\n" - " #(dynamic.string(\"one\"), dynamic.properties([\n" - " #(dynamic.string(\"two\"), dynamic.int(1000)),\n" - " ])),\n" - " ]))\n" - "\n" - "\n" - " decode.run(data, decoder)\n" - " // -> Ok(1000)\n" - " ```\n" - "\n" - " ```gleam\n" - " dynamic.nil()\n" - " |> decode.run(decode.optional(decode.int))\n" - " // -> Ok(option.None)\n" - " ```\n" -). --spec at(list(any()), decoder(BVL)) -> decoder(BVL). -at(Path, Inner) -> - {decoder, - fun(Data) -> - index( - Path, - [], - erlang:element(2, Inner), - Data, - fun(Data@1, Position) -> - {Default, _} = (erlang:element(2, Inner))(Data@1), - _pipe = {Default, - [{decode_error, - <<"Field"/utf8>>, - <<"Nothing"/utf8>>, - []}]}, - push_path(_pipe, lists:reverse(Position)) - end - ) - end}. - --file("src/gleam/dynamic/decode.gleam", 524). -?DOC( - " Run a decoder on a field of a `Dynamic` value, decoding the value if it is\n" - " of the desired type, or returning errors. An error is returned if there is\n" - " no field for the specified key.\n" - "\n" - " This function will index into dictionaries with any key type, and if the key is\n" - " an int then it'll also index into Erlang tuples and JavaScript arrays, and\n" - " the first eight elements of Gleam lists.\n" - "\n" - " # Examples\n" - "\n" - " ```gleam\n" - " let data = dynamic.properties([\n" - " #(dynamic.string(\"email\"), dynamic.string(\"lucy@example.com\")),\n" - " #(dynamic.string(\"name\"), dynamic.string(\"Lucy\")),\n" - " ]))\n" - "\n" - " let decoder = {\n" - " use name <- decode.field(\"name\", string)\n" - " use email <- decode.field(\"email\", string)\n" - " decode.success(SignUp(name: name, email: email))\n" - " }\n" - "\n" - " let result = decode.run(data, decoder)\n" - " assert result == Ok(SignUp(name: \"Lucy\", email: \"lucy@example.com\"))\n" - " ```\n" - "\n" - " If you wish to decode a value that is more deeply nested within the dynamic\n" - " data, see [`subfield`](#subfield) and [`at`](#at).\n" - "\n" - " If you wish to return a default in the event that a field is not present,\n" - " see [`optional_field`](#optional_field) and / [`optionally_at`](#optionally_at).\n" -). --spec field(any(), decoder(BWJ), fun((BWJ) -> decoder(BWL))) -> decoder(BWL). -field(Field_name, Field_decoder, Next) -> - subfield([Field_name], Field_decoder, Next). - --file("src/gleam/dynamic/decode.gleam", 557). -?DOC( - " Run a decoder on a field of a `Dynamic` value, decoding the value if it is\n" - " of the desired type, or returning errors. The given default value is\n" - " returned if there is no field for the specified key.\n" - "\n" - " This function will index into dictionaries with any key type, and if the key is\n" - " an int then it'll also index into Erlang tuples and JavaScript arrays, and\n" - " the first eight elements of Gleam lists.\n" - "\n" - " # Examples\n" - "\n" - " ```gleam\n" - " let data = dynamic.properties([\n" - " #(dynamic.string(\"name\"), dynamic.string(\"Lucy\")),\n" - " ]))\n" - "\n" - " let decoder = {\n" - " use name <- decode.field(\"name\", string)\n" - " use email <- decode.optional_field(\"email\", \"n/a\", string)\n" - " decode.success(SignUp(name: name, email: email))\n" - " }\n" - "\n" - " let result = decode.run(data, decoder)\n" - " assert result == Ok(SignUp(name: \"Lucy\", email: \"n/a\"))\n" - " ```\n" -). --spec optional_field(any(), BWP, decoder(BWP), fun((BWP) -> decoder(BWR))) -> decoder(BWR). -optional_field(Key, Default, Field_decoder, Next) -> - {decoder, - fun(Data) -> - {Out, Errors1} = begin - _pipe = case gleam_stdlib:index(Data, Key) of - {ok, {some, Data@1}} -> - (erlang:element(2, Field_decoder))(Data@1); - - {ok, none} -> - {Default, []}; - - {error, Kind} -> - {Default, - [{decode_error, - Kind, - gleam_stdlib:classify_dynamic(Data), - []}]} - end, - push_path(_pipe, [Key]) - end, - {Out@1, Errors2} = (erlang:element(2, Next(Out)))(Data), - {Out@1, lists:append(Errors1, Errors2)} - end}. - --file("src/gleam/dynamic/decode.gleam", 599). -?DOC( - " A decoder that decodes a value that is nested within other values. For\n" - " example, decoding a value that is within some deeply nested JSON objects.\n" - "\n" - " This function will index into dictionaries with any key type, and if the key is\n" - " an int then it'll also index into Erlang tuples and JavaScript arrays, and\n" - " the first eight elements of Gleam lists.\n" - "\n" - " # Examples\n" - "\n" - " ```gleam\n" - " let decoder = decode.optionally_at([\"one\", \"two\"], 100, decode.int)\n" - "\n" - " let data = dynamic.properties([\n" - " #(dynamic.string(\"one\"), dynamic.properties([])),\n" - " ]))\n" - "\n" - "\n" - " decode.run(data, decoder)\n" - " // -> Ok(100)\n" - " ```\n" -). --spec optionally_at(list(any()), BWW, decoder(BWW)) -> decoder(BWW). -optionally_at(Path, Default, Inner) -> - {decoder, - fun(Data) -> - index( - Path, - [], - erlang:element(2, Inner), - Data, - fun(_, _) -> {Default, []} end - ) - end}. diff --git a/build/packages/gleam_stdlib/src/gleam@float.erl b/build/packages/gleam_stdlib/src/gleam@float.erl deleted file mode 100644 index 6b55b47..0000000 --- a/build/packages/gleam_stdlib/src/gleam@float.erl +++ /dev/null @@ -1,744 +0,0 @@ --module(gleam@float). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "src/gleam/float.gleam"). --export([parse/1, to_string/1, compare/2, min/2, max/2, clamp/3, ceiling/1, floor/1, truncate/1, absolute_value/1, loosely_compare/3, loosely_equals/3, power/2, square_root/1, negate/1, round/1, to_precision/2, sum/1, product/1, random/0, modulo/2, divide/2, add/2, multiply/2, subtract/2, logarithm/1, exponential/1]). - --if(?OTP_RELEASE >= 27). --define(MODULEDOC(Str), -moduledoc(Str)). --define(DOC(Str), -doc(Str)). --else. --define(MODULEDOC(Str), -compile([])). --define(DOC(Str), -compile([])). --endif. - -?MODULEDOC( - " Functions for working with floats.\n" - "\n" - " ## Float representation\n" - "\n" - " Floats are represented as 64 bit floating point numbers on both the Erlang\n" - " and JavaScript runtimes. The floating point behaviour is native to their\n" - " respective runtimes, so their exact behaviour will be slightly different on\n" - " the two runtimes.\n" - "\n" - " ### Infinity and NaN\n" - "\n" - " Under the JavaScript runtime, exceeding the maximum (or minimum)\n" - " representable value for a floating point value will result in Infinity (or\n" - " -Infinity). Should you try to divide two infinities you will get NaN as a\n" - " result.\n" - "\n" - " When running on BEAM, exceeding the maximum (or minimum) representable\n" - " value for a floating point value will raise an error.\n" - "\n" - " ## Division by zero\n" - "\n" - " Gleam runs on the Erlang virtual machine, which does not follow the IEEE\n" - " 754 standard for floating point arithmetic and does not have an `Infinity`\n" - " value. In Erlang division by zero results in a crash, however Gleam does\n" - " not have partial functions and operators in core so instead division by zero\n" - " returns zero, a behaviour taken from Pony, Coq, and Lean.\n" - "\n" - " This may seem unexpected at first, but it is no less mathematically valid\n" - " than crashing or returning a special value. Division by zero is undefined\n" - " in mathematics.\n" -). - --file("src/gleam/float.gleam", 51). -?DOC( - " Attempts to parse a string as a `Float`, returning `Error(Nil)` if it was\n" - " not possible.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " parse(\"2.3\")\n" - " // -> Ok(2.3)\n" - " ```\n" - "\n" - " ```gleam\n" - " parse(\"ABC\")\n" - " // -> Error(Nil)\n" - " ```\n" -). --spec parse(binary()) -> {ok, float()} | {error, nil}. -parse(String) -> - gleam_stdlib:parse_float(String). - --file("src/gleam/float.gleam", 64). -?DOC( - " Returns the string representation of the provided `Float`.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " to_string(2.3)\n" - " // -> \"2.3\"\n" - " ```\n" -). --spec to_string(float()) -> binary(). -to_string(X) -> - gleam_stdlib:float_to_string(X). - --file("src/gleam/float.gleam", 95). -?DOC( - " Compares two `Float`s, returning an `Order`:\n" - " `Lt` for lower than, `Eq` for equals, or `Gt` for greater than.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " compare(2.0, 2.3)\n" - " // -> Lt\n" - " ```\n" - "\n" - " To handle\n" - " [Floating Point Imprecision](https://en.wikipedia.org/wiki/Floating-point_arithmetic#Accuracy_problems)\n" - " you may use [`loosely_compare`](#loosely_compare) instead.\n" -). --spec compare(float(), float()) -> gleam@order:order(). -compare(A, B) -> - case A =:= B of - true -> - eq; - - false -> - case A < B of - true -> - lt; - - false -> - gt - end - end. - --file("src/gleam/float.gleam", 176). -?DOC( - " Compares two `Float`s, returning the smaller of the two.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " min(2.0, 2.3)\n" - " // -> 2.0\n" - " ```\n" -). --spec min(float(), float()) -> float(). -min(A, B) -> - case A < B of - true -> - A; - - false -> - B - end. - --file("src/gleam/float.gleam", 192). -?DOC( - " Compares two `Float`s, returning the larger of the two.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " max(2.0, 2.3)\n" - " // -> 2.3\n" - " ```\n" -). --spec max(float(), float()) -> float(). -max(A, B) -> - case A > B of - true -> - A; - - false -> - B - end. - --file("src/gleam/float.gleam", 75). -?DOC( - " Restricts a `Float` between a lower and upper bound.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " clamp(1.2, min: 1.4, max: 1.6)\n" - " // -> 1.4\n" - " ```\n" -). --spec clamp(float(), float(), float()) -> float(). -clamp(X, Min_bound, Max_bound) -> - _pipe = X, - _pipe@1 = min(_pipe, Max_bound), - max(_pipe@1, Min_bound). - --file("src/gleam/float.gleam", 210). -?DOC( - " Rounds the value to the next highest whole number as a `Float`.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " ceiling(2.3)\n" - " // -> 3.0\n" - " ```\n" -). --spec ceiling(float()) -> float(). -ceiling(X) -> - math:ceil(X). - --file("src/gleam/float.gleam", 223). -?DOC( - " Rounds the value to the next lowest whole number as a `Float`.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " floor(2.3)\n" - " // -> 2.0\n" - " ```\n" -). --spec floor(float()) -> float(). -floor(X) -> - math:floor(X). - --file("src/gleam/float.gleam", 261). -?DOC( - " Returns the value as an `Int`, truncating all decimal digits.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " truncate(2.4343434847383438)\n" - " // -> 2\n" - " ```\n" -). --spec truncate(float()) -> integer(). -truncate(X) -> - erlang:trunc(X). - --file("src/gleam/float.gleam", 311). -?DOC( - " Returns the absolute value of the input as a `Float`.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " absolute_value(-12.5)\n" - " // -> 12.5\n" - " ```\n" - "\n" - " ```gleam\n" - " absolute_value(10.2)\n" - " // -> 10.2\n" - " ```\n" -). --spec absolute_value(float()) -> float(). -absolute_value(X) -> - case X >= +0.0 of - true -> - X; - - false -> - +0.0 - X - end. - --file("src/gleam/float.gleam", 125). -?DOC( - " Compares two `Float`s within a tolerance, returning an `Order`:\n" - " `Lt` for lower than, `Eq` for equals, or `Gt` for greater than.\n" - "\n" - " This function allows Float comparison while handling\n" - " [Floating Point Imprecision](https://en.wikipedia.org/wiki/Floating-point_arithmetic#Accuracy_problems).\n" - "\n" - " Notice: For `Float`s the tolerance won't be exact:\n" - " `5.3 - 5.0` is not exactly `0.3`.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " loosely_compare(5.0, with: 5.3, tolerating: 0.5)\n" - " // -> Eq\n" - " ```\n" - "\n" - " If you want to check only for equality you may use\n" - " [`loosely_equals`](#loosely_equals) instead.\n" -). --spec loosely_compare(float(), float(), float()) -> gleam@order:order(). -loosely_compare(A, B, Tolerance) -> - Difference = absolute_value(A - B), - case Difference =< Tolerance of - true -> - eq; - - false -> - compare(A, B) - end. - --file("src/gleam/float.gleam", 158). -?DOC( - " Checks for equality of two `Float`s within a tolerance,\n" - " returning an `Bool`.\n" - "\n" - " This function allows Float comparison while handling\n" - " [Floating Point Imprecision](https://en.wikipedia.org/wiki/Floating-point_arithmetic#Accuracy_problems).\n" - "\n" - " Notice: For `Float`s the tolerance won't be exact:\n" - " `5.3 - 5.0` is not exactly `0.3`.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " loosely_equals(5.0, with: 5.3, tolerating: 0.5)\n" - " // -> True\n" - " ```\n" - "\n" - " ```gleam\n" - " loosely_equals(5.0, with: 5.1, tolerating: 0.1)\n" - " // -> False\n" - " ```\n" -). --spec loosely_equals(float(), float(), float()) -> boolean(). -loosely_equals(A, B, Tolerance) -> - Difference = absolute_value(A - B), - Difference =< Tolerance. - --file("src/gleam/float.gleam", 348). -?DOC( - " Returns the results of the base being raised to the power of the\n" - " exponent, as a `Float`.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " power(2.0, -1.0)\n" - " // -> Ok(0.5)\n" - " ```\n" - "\n" - " ```gleam\n" - " power(2.0, 2.0)\n" - " // -> Ok(4.0)\n" - " ```\n" - "\n" - " ```gleam\n" - " power(8.0, 1.5)\n" - " // -> Ok(22.627416997969522)\n" - " ```\n" - "\n" - " ```gleam\n" - " 4.0 |> power(of: 2.0)\n" - " // -> Ok(16.0)\n" - " ```\n" - "\n" - " ```gleam\n" - " power(-1.0, 0.5)\n" - " // -> Error(Nil)\n" - " ```\n" -). --spec power(float(), float()) -> {ok, float()} | {error, nil}. -power(Base, Exponent) -> - Fractional = (math:ceil(Exponent) - Exponent) > +0.0, - case ((Base < +0.0) andalso Fractional) orelse ((Base =:= +0.0) andalso (Exponent - < +0.0)) of - true -> - {error, nil}; - - false -> - {ok, math:pow(Base, Exponent)} - end. - --file("src/gleam/float.gleam", 380). -?DOC( - " Returns the square root of the input as a `Float`.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " square_root(4.0)\n" - " // -> Ok(2.0)\n" - " ```\n" - "\n" - " ```gleam\n" - " square_root(-16.0)\n" - " // -> Error(Nil)\n" - " ```\n" -). --spec square_root(float()) -> {ok, float()} | {error, nil}. -square_root(X) -> - power(X, 0.5). - --file("src/gleam/float.gleam", 393). -?DOC( - " Returns the negative of the value provided.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " negate(1.0)\n" - " // -> -1.0\n" - " ```\n" -). --spec negate(float()) -> float(). -negate(X) -> - -1.0 * X. - --file("src/gleam/float.gleam", 240). -?DOC( - " Rounds the value to the nearest whole number as an `Int`.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " round(2.3)\n" - " // -> 2\n" - " ```\n" - "\n" - " ```gleam\n" - " round(2.5)\n" - " // -> 3\n" - " ```\n" -). --spec round(float()) -> integer(). -round(X) -> - erlang:round(X). - --file("src/gleam/float.gleam", 280). -?DOC( - " Converts the value to a given precision as a `Float`.\n" - " The precision is the number of allowed decimal places.\n" - " Negative precisions are allowed and force rounding\n" - " to the nearest tenth, hundredth, thousandth etc.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " to_precision(2.43434348473, precision: 2)\n" - " // -> 2.43\n" - " ```\n" - "\n" - " ```gleam\n" - " to_precision(547890.453444, precision: -3)\n" - " // -> 548000.0\n" - " ```\n" -). --spec to_precision(float(), integer()) -> float(). -to_precision(X, Precision) -> - case Precision =< 0 of - true -> - Factor = math:pow(10.0, erlang:float(- Precision)), - erlang:float(erlang:round(case Factor of - +0.0 -> +0.0; - -0.0 -> -0.0; - Gleam@denominator -> X / Gleam@denominator - end)) * Factor; - - false -> - Factor@1 = math:pow(10.0, erlang:float(Precision)), - case Factor@1 of - +0.0 -> +0.0; - -0.0 -> -0.0; - Gleam@denominator@1 -> erlang:float(erlang:round(X * Factor@1)) - / Gleam@denominator@1 - end - end. - --file("src/gleam/float.gleam", 410). --spec sum_loop(list(float()), float()) -> float(). -sum_loop(Numbers, Initial) -> - case Numbers of - [First | Rest] -> - sum_loop(Rest, First + Initial); - - [] -> - Initial - end. - --file("src/gleam/float.gleam", 406). -?DOC( - " Sums a list of `Float`s.\n" - "\n" - " ## Example\n" - "\n" - " ```gleam\n" - " sum([1.0, 2.2, 3.3])\n" - " // -> 6.5\n" - " ```\n" -). --spec sum(list(float())) -> float(). -sum(Numbers) -> - sum_loop(Numbers, +0.0). - --file("src/gleam/float.gleam", 430). --spec product_loop(list(float()), float()) -> float(). -product_loop(Numbers, Initial) -> - case Numbers of - [First | Rest] -> - product_loop(Rest, First * Initial); - - [] -> - Initial - end. - --file("src/gleam/float.gleam", 426). -?DOC( - " Multiplies a list of `Float`s and returns the product.\n" - "\n" - " ## Example\n" - "\n" - " ```gleam\n" - " product([2.5, 3.2, 4.2])\n" - " // -> 33.6\n" - " ```\n" -). --spec product(list(float())) -> float(). -product(Numbers) -> - product_loop(Numbers, 1.0). - --file("src/gleam/float.gleam", 452). -?DOC( - " Generates a random float between the given zero (inclusive) and one\n" - " (exclusive).\n" - "\n" - " On Erlang this updates the random state in the process dictionary.\n" - " See: \n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " random()\n" - " // -> 0.646355926896028\n" - " ```\n" -). --spec random() -> float(). -random() -> - rand:uniform(). - --file("src/gleam/float.gleam", 481). -?DOC( - " Computes the modulo of an float division of inputs as a `Result`.\n" - "\n" - " Returns division of the inputs as a `Result`: If the given divisor equals\n" - " `0`, this function returns an `Error`.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " modulo(13.3, by: 3.3)\n" - " // -> Ok(0.1)\n" - " ```\n" - "\n" - " ```gleam\n" - " modulo(-13.3, by: 3.3)\n" - " // -> Ok(3.2)\n" - " ```\n" - "\n" - " ```gleam\n" - " modulo(13.3, by: -3.3)\n" - " // -> Ok(-3.2)\n" - " ```\n" - "\n" - " ```gleam\n" - " modulo(-13.3, by: -3.3)\n" - " // -> Ok(-0.1)\n" - " ```\n" -). --spec modulo(float(), float()) -> {ok, float()} | {error, nil}. -modulo(Dividend, Divisor) -> - case Divisor of - +0.0 -> - {error, nil}; - - _ -> - {ok, Dividend - (math:floor(case Divisor of - +0.0 -> +0.0; - -0.0 -> -0.0; - Gleam@denominator -> Dividend / Gleam@denominator - end) * Divisor)} - end. - --file("src/gleam/float.gleam", 502). -?DOC( - " Returns division of the inputs as a `Result`.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " divide(0.0, 1.0)\n" - " // -> Ok(0.0)\n" - " ```\n" - "\n" - " ```gleam\n" - " divide(1.0, 0.0)\n" - " // -> Error(Nil)\n" - " ```\n" -). --spec divide(float(), float()) -> {ok, float()} | {error, nil}. -divide(A, B) -> - case B of - +0.0 -> - {error, nil}; - - B@1 -> - {ok, case B@1 of - +0.0 -> +0.0; - -0.0 -> -0.0; - Gleam@denominator -> A / Gleam@denominator - end} - end. - --file("src/gleam/float.gleam", 533). -?DOC( - " Adds two floats together.\n" - "\n" - " It's the function equivalent of the `+.` operator.\n" - " This function is useful in higher order functions or pipes.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " add(1.0, 2.0)\n" - " // -> 3.0\n" - " ```\n" - "\n" - " ```gleam\n" - " import gleam/list\n" - "\n" - " list.fold([1.0, 2.0, 3.0], 0.0, add)\n" - " // -> 6.0\n" - " ```\n" - "\n" - " ```gleam\n" - " 3.0 |> add(2.0)\n" - " // -> 5.0\n" - " ```\n" -). --spec add(float(), float()) -> float(). -add(A, B) -> - A + B. - --file("src/gleam/float.gleam", 561). -?DOC( - " Multiplies two floats together.\n" - "\n" - " It's the function equivalent of the `*.` operator.\n" - " This function is useful in higher order functions or pipes.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " multiply(2.0, 4.0)\n" - " // -> 8.0\n" - " ```\n" - "\n" - " ```gleam\n" - " import gleam/list\n" - "\n" - " list.fold([2.0, 3.0, 4.0], 1.0, multiply)\n" - " // -> 24.0\n" - " ```\n" - "\n" - " ```gleam\n" - " 3.0 |> multiply(2.0)\n" - " // -> 6.0\n" - " ```\n" -). --spec multiply(float(), float()) -> float(). -multiply(A, B) -> - A * B. - --file("src/gleam/float.gleam", 594). -?DOC( - " Subtracts one float from another.\n" - "\n" - " It's the function equivalent of the `-.` operator.\n" - " This function is useful in higher order functions or pipes.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " subtract(3.0, 1.0)\n" - " // -> 2.0\n" - " ```\n" - "\n" - " ```gleam\n" - " import gleam/list\n" - "\n" - " list.fold([1.0, 2.0, 3.0], 10.0, subtract)\n" - " // -> 4.0\n" - " ```\n" - "\n" - " ```gleam\n" - " 3.0 |> subtract(_, 2.0)\n" - " // -> 1.0\n" - " ```\n" - "\n" - " ```gleam\n" - " 3.0 |> subtract(2.0, _)\n" - " // -> -1.0\n" - " ```\n" -). --spec subtract(float(), float()) -> float(). -subtract(A, B) -> - A - B. - --file("src/gleam/float.gleam", 623). -?DOC( - " Returns the natural logarithm (base e) of the given as a `Result`. If the\n" - " input is less than or equal to 0, returns `Error(Nil)`.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " logarithm(1.0)\n" - " // -> Ok(0.0)\n" - " ```\n" - "\n" - " ```gleam\n" - " logarithm(2.718281828459045) // e\n" - " // -> Ok(1.0)\n" - " ```\n" - "\n" - " ```gleam\n" - " logarithm(0.0)\n" - " // -> Error(Nil)\n" - " ```\n" - "\n" - " ```gleam\n" - " logarithm(-1.0)\n" - " // -> Error(Nil)\n" - " ```\n" -). --spec logarithm(float()) -> {ok, float()} | {error, nil}. -logarithm(X) -> - case X =< +0.0 of - true -> - {error, nil}; - - false -> - {ok, math:log(X)} - end. - --file("src/gleam/float.gleam", 661). -?DOC( - " Returns e (Euler's number) raised to the power of the given exponent, as\n" - " a `Float`.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " exponential(0.0)\n" - " // -> Ok(1.0)\n" - " ```\n" - "\n" - " ```gleam\n" - " exponential(1.0)\n" - " // -> Ok(2.718281828459045)\n" - " ```\n" - "\n" - " ```gleam\n" - " exponential(-1.0)\n" - " // -> Ok(0.36787944117144233)\n" - " ```\n" -). --spec exponential(float()) -> float(). -exponential(X) -> - math:exp(X). diff --git a/build/packages/gleam_stdlib/src/gleam@function.erl b/build/packages/gleam_stdlib/src/gleam@function.erl deleted file mode 100644 index a6dec81..0000000 --- a/build/packages/gleam_stdlib/src/gleam@function.erl +++ /dev/null @@ -1,30 +0,0 @@ --module(gleam@function). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "src/gleam/function.gleam"). --export([identity/1, tap/2]). - --if(?OTP_RELEASE >= 27). --define(MODULEDOC(Str), -moduledoc(Str)). --define(DOC(Str), -doc(Str)). --else. --define(MODULEDOC(Str), -compile([])). --define(DOC(Str), -compile([])). --endif. - --file("src/gleam/function.gleam", 3). -?DOC(" Takes a single argument and always returns its input value.\n"). --spec identity(CLA) -> CLA. -identity(X) -> - X. - --file("src/gleam/function.gleam", 12). -?DOC( - " Takes an argument and a single function, calls that function with that\n" - " argument and returns that argument instead of the function return value.\n" - "\n" - " Useful for running synchronous side effects in a pipeline.\n" -). --spec tap(CLB, fun((CLB) -> any())) -> CLB. -tap(Arg, Effect) -> - Effect(Arg), - Arg. diff --git a/build/packages/gleam_stdlib/src/gleam@int.erl b/build/packages/gleam_stdlib/src/gleam@int.erl deleted file mode 100644 index 5e298da..0000000 --- a/build/packages/gleam_stdlib/src/gleam@int.erl +++ /dev/null @@ -1,986 +0,0 @@ --module(gleam@int). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "src/gleam/int.gleam"). --export([absolute_value/1, parse/1, base_parse/2, to_string/1, to_base_string/2, to_base2/1, to_base8/1, to_base16/1, to_base36/1, to_float/1, power/2, square_root/1, compare/2, min/2, max/2, clamp/3, is_even/1, is_odd/1, negate/1, sum/1, product/1, digits/2, undigits/2, random/1, divide/2, remainder/2, modulo/2, floor_divide/2, add/2, multiply/2, subtract/2, bitwise_and/2, bitwise_not/1, bitwise_or/2, bitwise_exclusive_or/2, bitwise_shift_left/2, bitwise_shift_right/2]). - --if(?OTP_RELEASE >= 27). --define(MODULEDOC(Str), -moduledoc(Str)). --define(DOC(Str), -doc(Str)). --else. --define(MODULEDOC(Str), -compile([])). --define(DOC(Str), -compile([])). --endif. - -?MODULEDOC( - " Functions for working with integers.\n" - "\n" - " ## Division by zero\n" - "\n" - " In Erlang division by zero results in a crash, however Gleam does not have\n" - " partial functions and operators in core so instead division by zero returns\n" - " zero, a behaviour taken from Pony, Coq, and Lean.\n" - "\n" - " This may seem unexpected at first, but it is no less mathematically valid\n" - " than crashing or returning a special value. Division by zero is undefined\n" - " in mathematics.\n" -). - --file("src/gleam/int.gleam", 30). -?DOC( - " Returns the absolute value of the input.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " absolute_value(-12)\n" - " // -> 12\n" - " ```\n" - "\n" - " ```gleam\n" - " absolute_value(10)\n" - " // -> 10\n" - " ```\n" -). --spec absolute_value(integer()) -> integer(). -absolute_value(X) -> - case X >= 0 of - true -> - X; - - false -> - X * -1 - end. - --file("src/gleam/int.gleam", 109). -?DOC( - " Parses a given string as an int if possible.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " parse(\"2\")\n" - " // -> Ok(2)\n" - " ```\n" - "\n" - " ```gleam\n" - " parse(\"ABC\")\n" - " // -> Error(Nil)\n" - " ```\n" -). --spec parse(binary()) -> {ok, integer()} | {error, nil}. -parse(String) -> - gleam_stdlib:parse_int(String). - --file("src/gleam/int.gleam", 141). -?DOC( - " Parses a given string as an int in a given base if possible.\n" - " Supports only bases 2 to 36, for values outside of which this function returns an `Error(Nil)`.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " base_parse(\"10\", 2)\n" - " // -> Ok(2)\n" - " ```\n" - "\n" - " ```gleam\n" - " base_parse(\"30\", 16)\n" - " // -> Ok(48)\n" - " ```\n" - "\n" - " ```gleam\n" - " base_parse(\"1C\", 36)\n" - " // -> Ok(48)\n" - " ```\n" - "\n" - " ```gleam\n" - " base_parse(\"48\", 1)\n" - " // -> Error(Nil)\n" - " ```\n" - "\n" - " ```gleam\n" - " base_parse(\"48\", 37)\n" - " // -> Error(Nil)\n" - " ```\n" -). --spec base_parse(binary(), integer()) -> {ok, integer()} | {error, nil}. -base_parse(String, Base) -> - case (Base >= 2) andalso (Base =< 36) of - true -> - gleam_stdlib:int_from_base_string(String, Base); - - false -> - {error, nil} - end. - --file("src/gleam/int.gleam", 163). -?DOC( - " Prints a given int to a string.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " to_string(2)\n" - " // -> \"2\"\n" - " ```\n" -). --spec to_string(integer()) -> binary(). -to_string(X) -> - erlang:integer_to_binary(X). - --file("src/gleam/int.gleam", 196). -?DOC( - " Prints a given int to a string using the base number provided.\n" - " Supports only bases 2 to 36, for values outside of which this function returns an `Error(Nil)`.\n" - " For common bases (2, 8, 16, 36), use the `to_baseN` functions.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " to_base_string(2, 2)\n" - " // -> Ok(\"10\")\n" - " ```\n" - "\n" - " ```gleam\n" - " to_base_string(48, 16)\n" - " // -> Ok(\"30\")\n" - " ```\n" - "\n" - " ```gleam\n" - " to_base_string(48, 36)\n" - " // -> Ok(\"1C\")\n" - " ```\n" - "\n" - " ```gleam\n" - " to_base_string(48, 1)\n" - " // -> Error(Nil)\n" - " ```\n" - "\n" - " ```gleam\n" - " to_base_string(48, 37)\n" - " // -> Error(Nil)\n" - " ```\n" -). --spec to_base_string(integer(), integer()) -> {ok, binary()} | {error, nil}. -to_base_string(X, Base) -> - case (Base >= 2) andalso (Base =< 36) of - true -> - {ok, erlang:integer_to_binary(X, Base)}; - - false -> - {error, nil} - end. - --file("src/gleam/int.gleam", 216). -?DOC( - " Prints a given int to a string using base-2.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " to_base2(2)\n" - " // -> \"10\"\n" - " ```\n" -). --spec to_base2(integer()) -> binary(). -to_base2(X) -> - erlang:integer_to_binary(X, 2). - --file("src/gleam/int.gleam", 229). -?DOC( - " Prints a given int to a string using base-8.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " to_base8(15)\n" - " // -> \"17\"\n" - " ```\n" -). --spec to_base8(integer()) -> binary(). -to_base8(X) -> - erlang:integer_to_binary(X, 8). - --file("src/gleam/int.gleam", 242). -?DOC( - " Prints a given int to a string using base-16.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " to_base16(48)\n" - " // -> \"30\"\n" - " ```\n" -). --spec to_base16(integer()) -> binary(). -to_base16(X) -> - erlang:integer_to_binary(X, 16). - --file("src/gleam/int.gleam", 255). -?DOC( - " Prints a given int to a string using base-36.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " to_base36(48)\n" - " // -> \"1C\"\n" - " ```\n" -). --spec to_base36(integer()) -> binary(). -to_base36(X) -> - erlang:integer_to_binary(X, 36). - --file("src/gleam/int.gleam", 280). -?DOC( - " Takes an int and returns its value as a float.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " to_float(5)\n" - " // -> 5.0\n" - " ```\n" - "\n" - " ```gleam\n" - " to_float(0)\n" - " // -> 0.0\n" - " ```\n" - "\n" - " ```gleam\n" - " to_float(-3)\n" - " // -> -3.0\n" - " ```\n" -). --spec to_float(integer()) -> float(). -to_float(X) -> - erlang:float(X). - --file("src/gleam/int.gleam", 67). -?DOC( - " Returns the results of the base being raised to the power of the\n" - " exponent, as a `Float`.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " power(2, -1.0)\n" - " // -> Ok(0.5)\n" - " ```\n" - "\n" - " ```gleam\n" - " power(2, 2.0)\n" - " // -> Ok(4.0)\n" - " ```\n" - "\n" - " ```gleam\n" - " power(8, 1.5)\n" - " // -> Ok(22.627416997969522)\n" - " ```\n" - "\n" - " ```gleam\n" - " 4 |> power(of: 2.0)\n" - " // -> Ok(16.0)\n" - " ```\n" - "\n" - " ```gleam\n" - " power(-1, 0.5)\n" - " // -> Error(Nil)\n" - " ```\n" -). --spec power(integer(), float()) -> {ok, float()} | {error, nil}. -power(Base, Exponent) -> - _pipe = Base, - _pipe@1 = erlang:float(_pipe), - gleam@float:power(_pipe@1, Exponent). - --file("src/gleam/int.gleam", 87). -?DOC( - " Returns the square root of the input as a `Float`.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " square_root(4)\n" - " // -> Ok(2.0)\n" - " ```\n" - "\n" - " ```gleam\n" - " square_root(-16)\n" - " // -> Error(Nil)\n" - " ```\n" -). --spec square_root(integer()) -> {ok, float()} | {error, nil}. -square_root(X) -> - _pipe = X, - _pipe@1 = erlang:float(_pipe), - gleam@float:square_root(_pipe@1). - --file("src/gleam/int.gleam", 316). -?DOC( - " Compares two ints, returning an order.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " compare(2, 3)\n" - " // -> Lt\n" - " ```\n" - "\n" - " ```gleam\n" - " compare(4, 3)\n" - " // -> Gt\n" - " ```\n" - "\n" - " ```gleam\n" - " compare(3, 3)\n" - " // -> Eq\n" - " ```\n" -). --spec compare(integer(), integer()) -> gleam@order:order(). -compare(A, B) -> - case A =:= B of - true -> - eq; - - false -> - case A < B of - true -> - lt; - - false -> - gt - end - end. - --file("src/gleam/int.gleam", 336). -?DOC( - " Compares two ints, returning the smaller of the two.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " min(2, 3)\n" - " // -> 2\n" - " ```\n" -). --spec min(integer(), integer()) -> integer(). -min(A, B) -> - case A < B of - true -> - A; - - false -> - B - end. - --file("src/gleam/int.gleam", 352). -?DOC( - " Compares two ints, returning the larger of the two.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " max(2, 3)\n" - " // -> 3\n" - " ```\n" -). --spec max(integer(), integer()) -> integer(). -max(A, B) -> - case A > B of - true -> - A; - - false -> - B - end. - --file("src/gleam/int.gleam", 291). -?DOC( - " Restricts an int between a lower and upper bound.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " clamp(40, min: 50, max: 60)\n" - " // -> 50\n" - " ```\n" -). --spec clamp(integer(), integer(), integer()) -> integer(). -clamp(X, Min_bound, Max_bound) -> - _pipe = X, - _pipe@1 = min(_pipe, Max_bound), - max(_pipe@1, Min_bound). - --file("src/gleam/int.gleam", 373). -?DOC( - " Returns whether the value provided is even.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " is_even(2)\n" - " // -> True\n" - " ```\n" - "\n" - " ```gleam\n" - " is_even(3)\n" - " // -> False\n" - " ```\n" -). --spec is_even(integer()) -> boolean(). -is_even(X) -> - (X rem 2) =:= 0. - --file("src/gleam/int.gleam", 391). -?DOC( - " Returns whether the value provided is odd.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " is_odd(3)\n" - " // -> True\n" - " ```\n" - "\n" - " ```gleam\n" - " is_odd(2)\n" - " // -> False\n" - " ```\n" -). --spec is_odd(integer()) -> boolean(). -is_odd(X) -> - (X rem 2) /= 0. - --file("src/gleam/int.gleam", 404). -?DOC( - " Returns the negative of the value provided.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " negate(1)\n" - " // -> -1\n" - " ```\n" -). --spec negate(integer()) -> integer(). -negate(X) -> - -1 * X. - --file("src/gleam/int.gleam", 421). --spec sum_loop(list(integer()), integer()) -> integer(). -sum_loop(Numbers, Initial) -> - case Numbers of - [First | Rest] -> - sum_loop(Rest, First + Initial); - - [] -> - Initial - end. - --file("src/gleam/int.gleam", 417). -?DOC( - " Sums a list of ints.\n" - "\n" - " ## Example\n" - "\n" - " ```gleam\n" - " sum([1, 2, 3])\n" - " // -> 6\n" - " ```\n" -). --spec sum(list(integer())) -> integer(). -sum(Numbers) -> - sum_loop(Numbers, 0). - --file("src/gleam/int.gleam", 441). --spec product_loop(list(integer()), integer()) -> integer(). -product_loop(Numbers, Initial) -> - case Numbers of - [First | Rest] -> - product_loop(Rest, First * Initial); - - [] -> - Initial - end. - --file("src/gleam/int.gleam", 437). -?DOC( - " Multiplies a list of ints and returns the product.\n" - "\n" - " ## Example\n" - "\n" - " ```gleam\n" - " product([2, 3, 4])\n" - " // -> 24\n" - " ```\n" -). --spec product(list(integer())) -> integer(). -product(Numbers) -> - product_loop(Numbers, 1). - --file("src/gleam/int.gleam", 456). --spec digits_loop(integer(), integer(), list(integer())) -> list(integer()). -digits_loop(X, Base, Acc) -> - case absolute_value(X) < Base of - true -> - [X | Acc]; - - false -> - digits_loop(case Base of - 0 -> 0; - Gleam@denominator -> X div Gleam@denominator - end, Base, [case Base of - 0 -> 0; - Gleam@denominator@1 -> X rem Gleam@denominator@1 - end | Acc]) - end. - --file("src/gleam/int.gleam", 449). --spec digits(integer(), integer()) -> {ok, list(integer())} | {error, nil}. -digits(X, Base) -> - case Base < 2 of - true -> - {error, nil}; - - false -> - {ok, digits_loop(X, Base, [])} - end. - --file("src/gleam/int.gleam", 471). --spec undigits_loop(list(integer()), integer(), integer()) -> {ok, integer()} | - {error, nil}. -undigits_loop(Numbers, Base, Acc) -> - case Numbers of - [] -> - {ok, Acc}; - - [Digit | _] when Digit >= Base -> - {error, nil}; - - [Digit@1 | Rest] -> - undigits_loop(Rest, Base, (Acc * Base) + Digit@1) - end. - --file("src/gleam/int.gleam", 464). --spec undigits(list(integer()), integer()) -> {ok, integer()} | {error, nil}. -undigits(Numbers, Base) -> - case Base < 2 of - true -> - {error, nil}; - - false -> - undigits_loop(Numbers, Base, 0) - end. - --file("src/gleam/int.gleam", 500). -?DOC( - " Generates a random int between zero and the given maximum.\n" - "\n" - " The lower number is inclusive, the upper number is exclusive.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " random(10)\n" - " // -> 4\n" - " ```\n" - "\n" - " ```gleam\n" - " random(1)\n" - " // -> 0\n" - " ```\n" - "\n" - " ```gleam\n" - " random(-1)\n" - " // -> -1\n" - " ```\n" -). --spec random(integer()) -> integer(). -random(Max) -> - _pipe = (rand:uniform() * erlang:float(Max)), - _pipe@1 = math:floor(_pipe), - erlang:round(_pipe@1). - --file("src/gleam/int.gleam", 533). -?DOC( - " Performs a truncated integer division.\n" - "\n" - " Returns division of the inputs as a `Result`: If the given divisor equals\n" - " `0`, this function returns an `Error`.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " divide(0, 1)\n" - " // -> Ok(0)\n" - " ```\n" - "\n" - " ```gleam\n" - " divide(1, 0)\n" - " // -> Error(Nil)\n" - " ```\n" - "\n" - " ```gleam\n" - " divide(5, 2)\n" - " // -> Ok(2)\n" - " ```\n" - "\n" - " ```gleam\n" - " divide(-99, 2)\n" - " // -> Ok(-49)\n" - " ```\n" -). --spec divide(integer(), integer()) -> {ok, integer()} | {error, nil}. -divide(Dividend, Divisor) -> - case Divisor of - 0 -> - {error, nil}; - - Divisor@1 -> - {ok, case Divisor@1 of - 0 -> 0; - Gleam@denominator -> Dividend div Gleam@denominator - end} - end. - --file("src/gleam/int.gleam", 585). -?DOC( - " Computes the remainder of an integer division of inputs as a `Result`.\n" - "\n" - " Returns division of the inputs as a `Result`: If the given divisor equals\n" - " `0`, this function returns an `Error`.\n" - "\n" - " Most the time you will want to use the `%` operator instead of this\n" - " function.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " remainder(3, 2)\n" - " // -> Ok(1)\n" - " ```\n" - "\n" - " ```gleam\n" - " remainder(1, 0)\n" - " // -> Error(Nil)\n" - " ```\n" - "\n" - " ```gleam\n" - " remainder(10, -1)\n" - " // -> Ok(0)\n" - " ```\n" - "\n" - " ```gleam\n" - " remainder(13, by: 3)\n" - " // -> Ok(1)\n" - " ```\n" - "\n" - " ```gleam\n" - " remainder(-13, by: 3)\n" - " // -> Ok(-1)\n" - " ```\n" - "\n" - " ```gleam\n" - " remainder(13, by: -3)\n" - " // -> Ok(1)\n" - " ```\n" - "\n" - " ```gleam\n" - " remainder(-13, by: -3)\n" - " // -> Ok(-1)\n" - " ```\n" -). --spec remainder(integer(), integer()) -> {ok, integer()} | {error, nil}. -remainder(Dividend, Divisor) -> - case Divisor of - 0 -> - {error, nil}; - - Divisor@1 -> - {ok, case Divisor@1 of - 0 -> 0; - Gleam@denominator -> Dividend rem Gleam@denominator - end} - end. - --file("src/gleam/int.gleam", 627). -?DOC( - " Computes the modulo of an integer division of inputs as a `Result`.\n" - "\n" - " Returns division of the inputs as a `Result`: If the given divisor equals\n" - " `0`, this function returns an `Error`.\n" - "\n" - " Most the time you will want to use the `%` operator instead of this\n" - " function.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " modulo(3, 2)\n" - " // -> Ok(1)\n" - " ```\n" - "\n" - " ```gleam\n" - " modulo(1, 0)\n" - " // -> Error(Nil)\n" - " ```\n" - "\n" - " ```gleam\n" - " modulo(10, -1)\n" - " // -> Ok(0)\n" - " ```\n" - "\n" - " ```gleam\n" - " modulo(13, by: 3)\n" - " // -> Ok(1)\n" - " ```\n" - "\n" - " ```gleam\n" - " modulo(-13, by: 3)\n" - " // -> Ok(2)\n" - " ```\n" -). --spec modulo(integer(), integer()) -> {ok, integer()} | {error, nil}. -modulo(Dividend, Divisor) -> - case Divisor of - 0 -> - {error, nil}; - - _ -> - Remainder = case Divisor of - 0 -> 0; - Gleam@denominator -> Dividend rem Gleam@denominator - end, - case (Remainder * Divisor) < 0 of - true -> - {ok, Remainder + Divisor}; - - false -> - {ok, Remainder} - end - end. - --file("src/gleam/int.gleam", 671). -?DOC( - " Performs a *floored* integer division, which means that the result will\n" - " always be rounded towards negative infinity.\n" - "\n" - " If you want to perform truncated integer division (rounding towards zero),\n" - " use `int.divide()` or the `/` operator instead.\n" - "\n" - " Returns division of the inputs as a `Result`: If the given divisor equals\n" - " `0`, this function returns an `Error`.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " floor_divide(1, 0)\n" - " // -> Error(Nil)\n" - " ```\n" - "\n" - " ```gleam\n" - " floor_divide(5, 2)\n" - " // -> Ok(2)\n" - " ```\n" - "\n" - " ```gleam\n" - " floor_divide(6, -4)\n" - " // -> Ok(-2)\n" - " ```\n" - "\n" - " ```gleam\n" - " floor_divide(-99, 2)\n" - " // -> Ok(-50)\n" - " ```\n" -). --spec floor_divide(integer(), integer()) -> {ok, integer()} | {error, nil}. -floor_divide(Dividend, Divisor) -> - case Divisor of - 0 -> - {error, nil}; - - Divisor@1 -> - case ((Dividend * Divisor@1) < 0) andalso ((case Divisor@1 of - 0 -> 0; - Gleam@denominator -> Dividend rem Gleam@denominator - end) /= 0) of - true -> - {ok, (case Divisor@1 of - 0 -> 0; - Gleam@denominator@1 -> Dividend div Gleam@denominator@1 - end) - 1}; - - false -> - {ok, case Divisor@1 of - 0 -> 0; - Gleam@denominator@2 -> Dividend div Gleam@denominator@2 - end} - end - end. - --file("src/gleam/int.gleam", 705). -?DOC( - " Adds two integers together.\n" - "\n" - " It's the function equivalent of the `+` operator.\n" - " This function is useful in higher order functions or pipes.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " add(1, 2)\n" - " // -> 3\n" - " ```\n" - "\n" - " ```gleam\n" - " import gleam/list\n" - " list.fold([1, 2, 3], 0, add)\n" - " // -> 6\n" - " ```\n" - "\n" - " ```gleam\n" - " 3 |> add(2)\n" - " // -> 5\n" - " ```\n" -). --spec add(integer(), integer()) -> integer(). -add(A, B) -> - A + B. - --file("src/gleam/int.gleam", 733). -?DOC( - " Multiplies two integers together.\n" - "\n" - " It's the function equivalent of the `*` operator.\n" - " This function is useful in higher order functions or pipes.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " multiply(2, 4)\n" - " // -> 8\n" - " ```\n" - "\n" - " ```gleam\n" - " import gleam/list\n" - "\n" - " list.fold([2, 3, 4], 1, multiply)\n" - " // -> 24\n" - " ```\n" - "\n" - " ```gleam\n" - " 3 |> multiply(2)\n" - " // -> 6\n" - " ```\n" -). --spec multiply(integer(), integer()) -> integer(). -multiply(A, B) -> - A * B. - --file("src/gleam/int.gleam", 766). -?DOC( - " Subtracts one int from another.\n" - "\n" - " It's the function equivalent of the `-` operator.\n" - " This function is useful in higher order functions or pipes.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " subtract(3, 1)\n" - " // -> 2\n" - " ```\n" - "\n" - " ```gleam\n" - " import gleam/list\n" - "\n" - " list.fold([1, 2, 3], 10, subtract)\n" - " // -> 4\n" - " ```\n" - "\n" - " ```gleam\n" - " 3 |> subtract(2)\n" - " // -> 1\n" - " ```\n" - "\n" - " ```gleam\n" - " 3 |> subtract(2, _)\n" - " // -> -1\n" - " ```\n" -). --spec subtract(integer(), integer()) -> integer(). -subtract(A, B) -> - A - B. - --file("src/gleam/int.gleam", 778). -?DOC( - " Calculates the bitwise AND of its arguments.\n" - "\n" - " The exact behaviour of this function depends on the target platform.\n" - " On Erlang it is equivalent to bitwise operations on ints, on JavaScript it\n" - " is equivalent to bitwise operations on big-ints.\n" -). --spec bitwise_and(integer(), integer()) -> integer(). -bitwise_and(X, Y) -> - erlang:'band'(X, Y). - --file("src/gleam/int.gleam", 788). -?DOC( - " Calculates the bitwise NOT of its argument.\n" - "\n" - " The exact behaviour of this function depends on the target platform.\n" - " On Erlang it is equivalent to bitwise operations on ints, on JavaScript it\n" - " is equivalent to bitwise operations on big-ints.\n" -). --spec bitwise_not(integer()) -> integer(). -bitwise_not(X) -> - erlang:'bnot'(X). - --file("src/gleam/int.gleam", 798). -?DOC( - " Calculates the bitwise OR of its arguments.\n" - "\n" - " The exact behaviour of this function depends on the target platform.\n" - " On Erlang it is equivalent to bitwise operations on ints, on JavaScript it\n" - " is equivalent to bitwise operations on big-ints.\n" -). --spec bitwise_or(integer(), integer()) -> integer(). -bitwise_or(X, Y) -> - erlang:'bor'(X, Y). - --file("src/gleam/int.gleam", 808). -?DOC( - " Calculates the bitwise XOR of its arguments.\n" - "\n" - " The exact behaviour of this function depends on the target platform.\n" - " On Erlang it is equivalent to bitwise operations on ints, on JavaScript it\n" - " is equivalent to bitwise operations on big-ints.\n" -). --spec bitwise_exclusive_or(integer(), integer()) -> integer(). -bitwise_exclusive_or(X, Y) -> - erlang:'bxor'(X, Y). - --file("src/gleam/int.gleam", 818). -?DOC( - " Calculates the result of an arithmetic left bitshift.\n" - "\n" - " The exact behaviour of this function depends on the target platform.\n" - " On Erlang it is equivalent to bitwise operations on ints, on JavaScript it\n" - " is equivalent to bitwise operations on big-ints.\n" -). --spec bitwise_shift_left(integer(), integer()) -> integer(). -bitwise_shift_left(X, Y) -> - erlang:'bsl'(X, Y). - --file("src/gleam/int.gleam", 828). -?DOC( - " Calculates the result of an arithmetic right bitshift.\n" - "\n" - " The exact behaviour of this function depends on the target platform.\n" - " On Erlang it is equivalent to bitwise operations on ints, on JavaScript it\n" - " is equivalent to bitwise operations on big-ints.\n" -). --spec bitwise_shift_right(integer(), integer()) -> integer(). -bitwise_shift_right(X, Y) -> - erlang:'bsr'(X, Y). diff --git a/build/packages/gleam_stdlib/src/gleam@io.erl b/build/packages/gleam_stdlib/src/gleam@io.erl deleted file mode 100644 index e60295e..0000000 --- a/build/packages/gleam_stdlib/src/gleam@io.erl +++ /dev/null @@ -1,80 +0,0 @@ --module(gleam@io). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "src/gleam/io.gleam"). --export([print/1, print_error/1, println/1, println_error/1]). - --if(?OTP_RELEASE >= 27). --define(MODULEDOC(Str), -moduledoc(Str)). --define(DOC(Str), -doc(Str)). --else. --define(MODULEDOC(Str), -compile([])). --define(DOC(Str), -compile([])). --endif. - --file("src/gleam/io.gleam", 15). -?DOC( - " Writes a string to standard output (stdout).\n" - "\n" - " If you want your output to be printed on its own line see `println`.\n" - "\n" - " ## Example\n" - "\n" - " ```gleam\n" - " io.print(\"Hi mum\")\n" - " // -> Nil\n" - " // Hi mum\n" - " ```\n" -). --spec print(binary()) -> nil. -print(String) -> - gleam_stdlib:print(String). - --file("src/gleam/io.gleam", 31). -?DOC( - " Writes a string to standard error (stderr).\n" - "\n" - " If you want your output to be printed on its own line see `println_error`.\n" - "\n" - " ## Example\n" - "\n" - " ```\n" - " io.print_error(\"Hi pop\")\n" - " // -> Nil\n" - " // Hi pop\n" - " ```\n" -). --spec print_error(binary()) -> nil. -print_error(String) -> - gleam_stdlib:print_error(String). - --file("src/gleam/io.gleam", 45). -?DOC( - " Writes a string to standard output (stdout), appending a newline to the end.\n" - "\n" - " ## Example\n" - "\n" - " ```gleam\n" - " io.println(\"Hi mum\")\n" - " // -> Nil\n" - " // Hi mum\n" - " ```\n" -). --spec println(binary()) -> nil. -println(String) -> - gleam_stdlib:println(String). - --file("src/gleam/io.gleam", 59). -?DOC( - " Writes a string to standard error (stderr), appending a newline to the end.\n" - "\n" - " ## Example\n" - "\n" - " ```gleam\n" - " io.println_error(\"Hi pop\")\n" - " // -> Nil\n" - " // Hi pop\n" - " ```\n" -). --spec println_error(binary()) -> nil. -println_error(String) -> - gleam_stdlib:println_error(String). diff --git a/build/packages/gleam_stdlib/src/gleam@list.erl b/build/packages/gleam_stdlib/src/gleam@list.erl deleted file mode 100644 index 0c96ecb..0000000 --- a/build/packages/gleam_stdlib/src/gleam@list.erl +++ /dev/null @@ -1,2873 +0,0 @@ --module(gleam@list). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "src/gleam/list.gleam"). --export([length/1, count/2, reverse/1, is_empty/1, contains/2, first/1, rest/1, group/2, filter/2, filter_map/2, map/2, map2/3, map_fold/3, index_map/2, try_map/2, drop/2, take/2, new/0, wrap/1, append/2, prepend/2, flatten/1, flat_map/2, fold/3, fold_right/3, index_fold/3, try_fold/3, fold_until/3, find/2, find_map/2, all/2, any/2, zip/2, strict_zip/2, unzip/1, intersperse/2, unique/1, sort/2, range/2, repeat/2, split/2, split_while/2, key_find/2, key_filter/2, key_pop/2, key_set/3, each/2, try_each/2, partition/2, window/2, window_by_2/1, drop_while/2, take_while/2, chunk/2, sized_chunk/2, reduce/2, scan/3, last/1, combinations/2, combination_pairs/1, transpose/1, interleave/1, shuffle/1, max/2, sample/2, permutations/1]). --export_type([continue_or_stop/1, sorting/0]). - --if(?OTP_RELEASE >= 27). --define(MODULEDOC(Str), -moduledoc(Str)). --define(DOC(Str), -doc(Str)). --else. --define(MODULEDOC(Str), -compile([])). --define(DOC(Str), -compile([])). --endif. - -?MODULEDOC( - " Lists are an ordered sequence of elements and are one of the most common\n" - " data types in Gleam.\n" - "\n" - " New elements can be added and removed from the front of a list in\n" - " constant time, while adding and removing from the end requires traversing\n" - " and copying the whole list, so keep this in mind when designing your\n" - " programs.\n" - "\n" - " There is a dedicated syntax for prefixing to a list:\n" - "\n" - " ```gleam\n" - " let new_list = [1, 2, ..existing_list]\n" - " ```\n" - "\n" - " And a matching syntax for getting the first elements of a list:\n" - "\n" - " ```gleam\n" - " case list {\n" - " [first_element, ..rest] -> first_element\n" - " _ -> \"this pattern matches when the list is empty\"\n" - " }\n" - " ```\n" - "\n" -). - --type continue_or_stop(XG) :: {continue, XG} | {stop, XG}. - --type sorting() :: ascending | descending. - --file("src/gleam/list.gleam", 60). --spec length_loop(list(any()), integer()) -> integer(). -length_loop(List, Count) -> - case List of - [_ | List@1] -> - length_loop(List@1, Count + 1); - - [] -> - Count - end. - --file("src/gleam/list.gleam", 56). -?DOC( - " Counts the number of elements in a given list.\n" - "\n" - " This function has to traverse the list to determine the number of elements,\n" - " so it runs in linear time.\n" - "\n" - " This function is natively implemented by the virtual machine and is highly\n" - " optimised.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " length([])\n" - " // -> 0\n" - " ```\n" - "\n" - " ```gleam\n" - " length([1])\n" - " // -> 1\n" - " ```\n" - "\n" - " ```gleam\n" - " length([1, 2])\n" - " // -> 2\n" - " ```\n" -). --spec length(list(any())) -> integer(). -length(List) -> - erlang:length(List). - --file("src/gleam/list.gleam", 93). --spec count_loop(list(XN), fun((XN) -> boolean()), integer()) -> integer(). -count_loop(List, Predicate, Acc) -> - case List of - [] -> - Acc; - - [First | Rest] -> - case Predicate(First) of - true -> - count_loop(Rest, Predicate, Acc + 1); - - false -> - count_loop(Rest, Predicate, Acc) - end - end. - --file("src/gleam/list.gleam", 89). -?DOC( - " Counts the number of elements in a given list satisfying a given predicate.\n" - "\n" - " This function has to traverse the list to determine the number of elements,\n" - " so it runs in linear time.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " count([], fn(a) { a > 0 })\n" - " // -> 0\n" - " ```\n" - "\n" - " ```gleam\n" - " count([1], fn(a) { a > 0 })\n" - " // -> 1\n" - " ```\n" - "\n" - " ```gleam\n" - " count([1, 2, 3], int.is_odd)\n" - " // -> 2\n" - " ```\n" -). --spec count(list(XL), fun((XL) -> boolean())) -> integer(). -count(List, Predicate) -> - count_loop(List, Predicate, 0). - --file("src/gleam/list.gleam", 131). -?DOC( - " Creates a new list from a given list containing the same elements but in the\n" - " opposite order.\n" - "\n" - " This function has to traverse the list to create the new reversed list, so\n" - " it runs in linear time.\n" - "\n" - " This function is natively implemented by the virtual machine and is highly\n" - " optimised.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " reverse([])\n" - " // -> []\n" - " ```\n" - "\n" - " ```gleam\n" - " reverse([1])\n" - " // -> [1]\n" - " ```\n" - "\n" - " ```gleam\n" - " reverse([1, 2])\n" - " // -> [2, 1]\n" - " ```\n" -). --spec reverse(list(XP)) -> list(XP). -reverse(List) -> - lists:reverse(List). - --file("src/gleam/list.gleam", 168). -?DOC( - " Determines whether or not the list is empty.\n" - "\n" - " This function runs in constant time.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " is_empty([])\n" - " // -> True\n" - " ```\n" - "\n" - " ```gleam\n" - " is_empty([1])\n" - " // -> False\n" - " ```\n" - "\n" - " ```gleam\n" - " is_empty([1, 1])\n" - " // -> False\n" - " ```\n" -). --spec is_empty(list(any())) -> boolean(). -is_empty(List) -> - List =:= []. - --file("src/gleam/list.gleam", 204). -?DOC( - " Determines whether or not a given element exists within a given list.\n" - "\n" - " This function traverses the list to find the element, so it runs in linear\n" - " time.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " [] |> contains(any: 0)\n" - " // -> False\n" - " ```\n" - "\n" - " ```gleam\n" - " [0] |> contains(any: 0)\n" - " // -> True\n" - " ```\n" - "\n" - " ```gleam\n" - " [1] |> contains(any: 0)\n" - " // -> False\n" - " ```\n" - "\n" - " ```gleam\n" - " [1, 1] |> contains(any: 0)\n" - " // -> False\n" - " ```\n" - "\n" - " ```gleam\n" - " [1, 0] |> contains(any: 0)\n" - " // -> True\n" - " ```\n" -). --spec contains(list(XY), XY) -> boolean(). -contains(List, Elem) -> - case List of - [] -> - false; - - [First | _] when First =:= Elem -> - true; - - [_ | Rest] -> - contains(Rest, Elem) - end. - --file("src/gleam/list.gleam", 231). -?DOC( - " Gets the first element from the start of the list, if there is one.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " first([])\n" - " // -> Error(Nil)\n" - " ```\n" - "\n" - " ```gleam\n" - " first([0])\n" - " // -> Ok(0)\n" - " ```\n" - "\n" - " ```gleam\n" - " first([1, 2])\n" - " // -> Ok(1)\n" - " ```\n" -). --spec first(list(YA)) -> {ok, YA} | {error, nil}. -first(List) -> - case List of - [] -> - {error, nil}; - - [First | _] -> - {ok, First} - end. - --file("src/gleam/list.gleam", 260). -?DOC( - " Returns the list minus the first element. If the list is empty, `Error(Nil)` is\n" - " returned.\n" - "\n" - " This function runs in constant time and does not make a copy of the list.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " rest([])\n" - " // -> Error(Nil)\n" - " ```\n" - "\n" - " ```gleam\n" - " rest([0])\n" - " // -> Ok([])\n" - " ```\n" - "\n" - " ```gleam\n" - " rest([1, 2])\n" - " // -> Ok([2])\n" - " ```\n" -). --spec rest(list(YE)) -> {ok, list(YE)} | {error, nil}. -rest(List) -> - case List of - [] -> - {error, nil}; - - [_ | Rest] -> - {ok, Rest} - end. - --file("src/gleam/list.gleam", 302). --spec group_loop(list(YP), fun((YP) -> YR), gleam@dict:dict(YR, list(YP))) -> gleam@dict:dict(YR, list(YP)). -group_loop(List, To_key, Groups) -> - case List of - [] -> - Groups; - - [First | Rest] -> - Key = To_key(First), - Groups@1 = case gleam_stdlib:map_get(Groups, Key) of - {error, _} -> - gleam@dict:insert(Groups, Key, [First]); - - {ok, Existing} -> - gleam@dict:insert(Groups, Key, [First | Existing]) - end, - group_loop(Rest, To_key, Groups@1) - end. - --file("src/gleam/list.gleam", 298). -?DOC( - " Groups the elements from the given list by the given key function.\n" - "\n" - " Does not preserve the initial value order.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " import gleam/dict\n" - "\n" - " [Ok(3), Error(\"Wrong\"), Ok(200), Ok(73)]\n" - " |> group(by: fn(i) {\n" - " case i {\n" - " Ok(_) -> \"Successful\"\n" - " Error(_) -> \"Failed\"\n" - " }\n" - " })\n" - " |> dict.to_list\n" - " // -> [\n" - " // #(\"Failed\", [Error(\"Wrong\")]),\n" - " // #(\"Successful\", [Ok(73), Ok(200), Ok(3)])\n" - " // ]\n" - " ```\n" - "\n" - " ```gleam\n" - " import gleam/dict\n" - "\n" - " group([1,2,3,4,5], by: fn(i) { i - i / 3 * 3 })\n" - " |> dict.to_list\n" - " // -> [#(0, [3]), #(1, [4, 1]), #(2, [5, 2])]\n" - " ```\n" -). --spec group(list(YJ), fun((YJ) -> YL)) -> gleam@dict:dict(YL, list(YJ)). -group(List, Key) -> - group_loop(List, Key, maps:new()). - --file("src/gleam/list.gleam", 339). --spec filter_loop(list(AAB), fun((AAB) -> boolean()), list(AAB)) -> list(AAB). -filter_loop(List, Fun, Acc) -> - case List of - [] -> - lists:reverse(Acc); - - [First | Rest] -> - New_acc = case Fun(First) of - true -> - [First | Acc]; - - false -> - Acc - end, - filter_loop(Rest, Fun, New_acc) - end. - --file("src/gleam/list.gleam", 335). -?DOC( - " Returns a new list containing only the elements from the first list for\n" - " which the given functions returns `True`.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " filter([2, 4, 6, 1], fn(x) { x > 2 })\n" - " // -> [4, 6]\n" - " ```\n" - "\n" - " ```gleam\n" - " filter([2, 4, 6, 1], fn(x) { x > 6 })\n" - " // -> []\n" - " ```\n" -). --spec filter(list(YY), fun((YY) -> boolean())) -> list(YY). -filter(List, Predicate) -> - filter_loop(List, Predicate, []). - --file("src/gleam/list.gleam", 371). --spec filter_map_loop( - list(AAM), - fun((AAM) -> {ok, AAO} | {error, any()}), - list(AAO) -) -> list(AAO). -filter_map_loop(List, Fun, Acc) -> - case List of - [] -> - lists:reverse(Acc); - - [First | Rest] -> - New_acc = case Fun(First) of - {ok, First@1} -> - [First@1 | Acc]; - - {error, _} -> - Acc - end, - filter_map_loop(Rest, Fun, New_acc) - end. - --file("src/gleam/list.gleam", 367). -?DOC( - " Returns a new list containing only the elements from the first list for\n" - " which the given functions returns `Ok(_)`.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " filter_map([2, 4, 6, 1], Error)\n" - " // -> []\n" - " ```\n" - "\n" - " ```gleam\n" - " filter_map([2, 4, 6, 1], fn(x) { Ok(x + 1) })\n" - " // -> [3, 5, 7, 2]\n" - " ```\n" -). --spec filter_map(list(AAF), fun((AAF) -> {ok, AAH} | {error, any()})) -> list(AAH). -filter_map(List, Fun) -> - filter_map_loop(List, Fun, []). - --file("src/gleam/list.gleam", 402). --spec map_loop(list(AAY), fun((AAY) -> ABA), list(ABA)) -> list(ABA). -map_loop(List, Fun, Acc) -> - case List of - [] -> - lists:reverse(Acc); - - [First | Rest] -> - map_loop(Rest, Fun, [Fun(First) | Acc]) - end. - --file("src/gleam/list.gleam", 398). -?DOC( - " Returns a new list containing only the elements of the first list after the\n" - " function has been applied to each one.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " map([2, 4, 6], fn(x) { x * 2 })\n" - " // -> [4, 8, 12]\n" - " ```\n" -). --spec map(list(AAU), fun((AAU) -> AAW)) -> list(AAW). -map(List, Fun) -> - map_loop(List, Fun, []). - --file("src/gleam/list.gleam", 429). --spec map2_loop(list(ABJ), list(ABL), fun((ABJ, ABL) -> ABN), list(ABN)) -> list(ABN). -map2_loop(List1, List2, Fun, Acc) -> - case {List1, List2} of - {[], _} -> - lists:reverse(Acc); - - {_, []} -> - lists:reverse(Acc); - - {[A | As_], [B | Bs]} -> - map2_loop(As_, Bs, Fun, [Fun(A, B) | Acc]) - end. - --file("src/gleam/list.gleam", 425). -?DOC( - " Combines two lists into a single list using the given function.\n" - "\n" - " If a list is longer than the other the extra elements are dropped.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " map2([1, 2, 3], [4, 5, 6], fn(x, y) { x + y })\n" - " // -> [5, 7, 9]\n" - " ```\n" - "\n" - " ```gleam\n" - " map2([1, 2], [\"a\", \"b\", \"c\"], fn(i, x) { #(i, x) })\n" - " // -> [#(1, \"a\"), #(2, \"b\")]\n" - " ```\n" -). --spec map2(list(ABD), list(ABF), fun((ABD, ABF) -> ABH)) -> list(ABH). -map2(List1, List2, Fun) -> - map2_loop(List1, List2, Fun, []). - --file("src/gleam/list.gleam", 462). --spec map_fold_loop(list(ABV), fun((ABX, ABV) -> {ABX, ABY}), ABX, list(ABY)) -> {ABX, - list(ABY)}. -map_fold_loop(List, Fun, Acc, List_acc) -> - case List of - [] -> - {Acc, lists:reverse(List_acc)}; - - [First | Rest] -> - {Acc@1, First@1} = Fun(Acc, First), - map_fold_loop(Rest, Fun, Acc@1, [First@1 | List_acc]) - end. - --file("src/gleam/list.gleam", 454). -?DOC( - " Similar to `map` but also lets you pass around an accumulated value.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " map_fold(\n" - " over: [1, 2, 3],\n" - " from: 100,\n" - " with: fn(memo, i) { #(memo + i, i * 2) }\n" - " )\n" - " // -> #(106, [2, 4, 6])\n" - " ```\n" -). --spec map_fold(list(ABQ), ABS, fun((ABS, ABQ) -> {ABS, ABT})) -> {ABS, - list(ABT)}. -map_fold(List, Initial, Fun) -> - map_fold_loop(List, Fun, Initial, []). - --file("src/gleam/list.gleam", 494). --spec index_map_loop( - list(ACF), - fun((ACF, integer()) -> ACH), - integer(), - list(ACH) -) -> list(ACH). -index_map_loop(List, Fun, Index, Acc) -> - case List of - [] -> - lists:reverse(Acc); - - [First | Rest] -> - Acc@1 = [Fun(First, Index) | Acc], - index_map_loop(Rest, Fun, Index + 1, Acc@1) - end. - --file("src/gleam/list.gleam", 490). -?DOC( - " Returns a new list containing only the elements of the first list after the\n" - " function has been applied to each one and their index.\n" - "\n" - " The index starts at 0, so the first element is 0, the second is 1, and so\n" - " on.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " index_map([\"a\", \"b\"], fn(x, i) { #(i, x) })\n" - " // -> [#(0, \"a\"), #(1, \"b\")]\n" - " ```\n" -). --spec index_map(list(ACB), fun((ACB, integer()) -> ACD)) -> list(ACD). -index_map(List, Fun) -> - index_map_loop(List, Fun, 0, []). - --file("src/gleam/list.gleam", 548). --spec try_map_loop(list(ACT), fun((ACT) -> {ok, ACV} | {error, ACW}), list(ACV)) -> {ok, - list(ACV)} | - {error, ACW}. -try_map_loop(List, Fun, Acc) -> - case List of - [] -> - {ok, lists:reverse(Acc)}; - - [First | Rest] -> - case Fun(First) of - {ok, First@1} -> - try_map_loop(Rest, Fun, [First@1 | Acc]); - - {error, Error} -> - {error, Error} - end - end. - --file("src/gleam/list.gleam", 541). -?DOC( - " Takes a function that returns a `Result` and applies it to each element in a\n" - " given list in turn.\n" - "\n" - " If the function returns `Ok(new_value)` for all elements in the list then a\n" - " list of the new values is returned.\n" - "\n" - " If the function returns `Error(reason)` for any of the elements then it is\n" - " returned immediately. None of the elements in the list are processed after\n" - " one returns an `Error`.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " try_map([1, 2, 3], fn(x) { Ok(x + 2) })\n" - " // -> Ok([3, 4, 5])\n" - " ```\n" - "\n" - " ```gleam\n" - " try_map([1, 2, 3], fn(_) { Error(0) })\n" - " // -> Error(0)\n" - " ```\n" - "\n" - " ```gleam\n" - " try_map([[1], [2, 3]], first)\n" - " // -> Ok([1, 2])\n" - " ```\n" - "\n" - " ```gleam\n" - " try_map([[1], [], [2]], first)\n" - " // -> Error(Nil)\n" - " ```\n" -). --spec try_map(list(ACK), fun((ACK) -> {ok, ACM} | {error, ACN})) -> {ok, - list(ACM)} | - {error, ACN}. -try_map(List, Fun) -> - try_map_loop(List, Fun, []). - --file("src/gleam/list.gleam", 583). -?DOC( - " Returns a list that is the given list with up to the given number of\n" - " elements removed from the front of the list.\n" - "\n" - " If the element has less than the number of elements an empty list is\n" - " returned.\n" - "\n" - " This function runs in linear time but does not copy the list.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " drop([1, 2, 3, 4], 2)\n" - " // -> [3, 4]\n" - " ```\n" - "\n" - " ```gleam\n" - " drop([1, 2, 3, 4], 9)\n" - " // -> []\n" - " ```\n" -). --spec drop(list(ADD), integer()) -> list(ADD). -drop(List, N) -> - case N =< 0 of - true -> - List; - - false -> - case List of - [] -> - []; - - [_ | Rest] -> - drop(Rest, N - 1) - end - end. - --file("src/gleam/list.gleam", 618). --spec take_loop(list(ADJ), integer(), list(ADJ)) -> list(ADJ). -take_loop(List, N, Acc) -> - case N =< 0 of - true -> - lists:reverse(Acc); - - false -> - case List of - [] -> - lists:reverse(Acc); - - [First | Rest] -> - take_loop(Rest, N - 1, [First | Acc]) - end - end. - --file("src/gleam/list.gleam", 614). -?DOC( - " Returns a list containing the first given number of elements from the given\n" - " list.\n" - "\n" - " If the element has less than the number of elements then the full list is\n" - " returned.\n" - "\n" - " This function runs in linear time.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " take([1, 2, 3, 4], 2)\n" - " // -> [1, 2]\n" - " ```\n" - "\n" - " ```gleam\n" - " take([1, 2, 3, 4], 9)\n" - " // -> [1, 2, 3, 4]\n" - " ```\n" -). --spec take(list(ADG), integer()) -> list(ADG). -take(List, N) -> - take_loop(List, N, []). - --file("src/gleam/list.gleam", 638). -?DOC( - " Returns a new empty list.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " new()\n" - " // -> []\n" - " ```\n" -). --spec new() -> list(any()). -new() -> - []. - --file("src/gleam/list.gleam", 658). -?DOC( - " Returns the given item wrapped in a list.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " wrap(1)\n" - " // -> [1]\n" - "\n" - " wrap([\"a\", \"b\", \"c\"])\n" - " // -> [[\"a\", \"b\", \"c\"]]\n" - "\n" - " wrap([[]])\n" - " // -> [[[]]]\n" - " ```\n" -). --spec wrap(ADP) -> list(ADP). -wrap(Item) -> - [Item]. - --file("src/gleam/list.gleam", 679). --spec append_loop(list(ADV), list(ADV)) -> list(ADV). -append_loop(First, Second) -> - case First of - [] -> - Second; - - [First@1 | Rest] -> - append_loop(Rest, [First@1 | Second]) - end. - --file("src/gleam/list.gleam", 675). -?DOC( - " Joins one list onto the end of another.\n" - "\n" - " This function runs in linear time, and it traverses and copies the first\n" - " list.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " append([1, 2], [3])\n" - " // -> [1, 2, 3]\n" - " ```\n" -). --spec append(list(ADR), list(ADR)) -> list(ADR). -append(First, Second) -> - lists:append(First, Second). - --file("src/gleam/list.gleam", 699). -?DOC( - " Prefixes an item to a list. This can also be done using the dedicated\n" - " syntax instead\n" - "\n" - " ```gleam\n" - " let existing_list = [2, 3, 4]\n" - "\n" - " [1, ..existing_list]\n" - " // -> [1, 2, 3, 4]\n" - "\n" - " prepend(to: existing_list, this: 1)\n" - " // -> [1, 2, 3, 4]\n" - " ```\n" -). --spec prepend(list(ADZ), ADZ) -> list(ADZ). -prepend(List, Item) -> - [Item | List]. - --file("src/gleam/list.gleam", 720). --spec flatten_loop(list(list(AEG)), list(AEG)) -> list(AEG). -flatten_loop(Lists, Acc) -> - case Lists of - [] -> - lists:reverse(Acc); - - [List | Further_lists] -> - flatten_loop(Further_lists, lists:reverse(List, Acc)) - end. - --file("src/gleam/list.gleam", 716). -?DOC( - " Joins a list of lists into a single list.\n" - "\n" - " This function traverses all elements twice on the JavaScript target.\n" - " This function traverses all elements once on the Erlang target.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " flatten([[1], [2, 3], []])\n" - " // -> [1, 2, 3]\n" - " ```\n" -). --spec flatten(list(list(AEC))) -> list(AEC). -flatten(Lists) -> - lists:append(Lists). - --file("src/gleam/list.gleam", 737). -?DOC( - " Maps the list with the given function into a list of lists, and then flattens it.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " flat_map([2, 4, 6], fn(x) { [x, x + 1] })\n" - " // -> [2, 3, 4, 5, 6, 7]\n" - " ```\n" -). --spec flat_map(list(AEL), fun((AEL) -> list(AEN))) -> list(AEN). -flat_map(List, Fun) -> - lists:append(map(List, Fun)). - --file("src/gleam/list.gleam", 749). -?DOC( - " Reduces a list of elements into a single value by calling a given function\n" - " on each element, going from left to right.\n" - "\n" - " `fold([1, 2, 3], 0, add)` is the equivalent of\n" - " `add(add(add(0, 1), 2), 3)`.\n" - "\n" - " This function runs in linear time.\n" -). --spec fold(list(AEQ), AES, fun((AES, AEQ) -> AES)) -> AES. -fold(List, Initial, Fun) -> - case List of - [] -> - Initial; - - [First | Rest] -> - fold(Rest, Fun(Initial, First), Fun) - end. - --file("src/gleam/list.gleam", 771). -?DOC( - " Reduces a list of elements into a single value by calling a given function\n" - " on each element, going from right to left.\n" - "\n" - " `fold_right([1, 2, 3], 0, add)` is the equivalent of\n" - " `add(add(add(0, 3), 2), 1)`.\n" - "\n" - " This function runs in linear time.\n" - "\n" - " Unlike `fold` this function is not tail recursive. Where possible use\n" - " `fold` instead as it will use less memory.\n" -). --spec fold_right(list(AET), AEV, fun((AEV, AET) -> AEV)) -> AEV. -fold_right(List, Initial, Fun) -> - case List of - [] -> - Initial; - - [First | Rest] -> - Fun(fold_right(Rest, Initial, Fun), First) - end. - --file("src/gleam/list.gleam", 808). --spec index_fold_loop( - list(AEZ), - AFB, - fun((AFB, AEZ, integer()) -> AFB), - integer() -) -> AFB. -index_fold_loop(Over, Acc, With, Index) -> - case Over of - [] -> - Acc; - - [First | Rest] -> - index_fold_loop(Rest, With(Acc, First, Index), With, Index + 1) - end. - --file("src/gleam/list.gleam", 800). -?DOC( - " Like fold but the folding function also receives the index of the current element.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " [\"a\", \"b\", \"c\"]\n" - " |> index_fold(\"\", fn(acc, item, index) {\n" - " acc <> int.to_string(index) <> \":\" <> item <> \" \"\n" - " })\n" - " // -> \"0:a 1:b 2:c\"\n" - " ```\n" - "\n" - " ```gleam\n" - " [10, 20, 30]\n" - " |> index_fold(0, fn(acc, item, index) { acc + item * index })\n" - " // -> 80\n" - " ```\n" -). --spec index_fold(list(AEW), AEY, fun((AEY, AEW, integer()) -> AEY)) -> AEY. -index_fold(List, Initial, Fun) -> - index_fold_loop(List, Initial, Fun, 0). - --file("src/gleam/list.gleam", 840). -?DOC( - " A variant of fold that might fail.\n" - "\n" - " The folding function should return `Result(accumulator, error)`.\n" - " If the returned value is `Ok(accumulator)` try_fold will try the next value in the list.\n" - " If the returned value is `Error(error)` try_fold will stop and return that error.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " [1, 2, 3, 4]\n" - " |> try_fold(0, fn(acc, i) {\n" - " case i < 3 {\n" - " True -> Ok(acc + i)\n" - " False -> Error(Nil)\n" - " }\n" - " })\n" - " // -> Error(Nil)\n" - " ```\n" -). --spec try_fold(list(AFC), AFE, fun((AFE, AFC) -> {ok, AFE} | {error, AFF})) -> {ok, - AFE} | - {error, AFF}. -try_fold(List, Initial, Fun) -> - case List of - [] -> - {ok, Initial}; - - [First | Rest] -> - case Fun(Initial, First) of - {ok, Result} -> - try_fold(Rest, Result, Fun); - - {error, _} = Error -> - Error - end - end. - --file("src/gleam/list.gleam", 879). -?DOC( - " A variant of fold that allows to stop folding earlier.\n" - "\n" - " The folding function should return `ContinueOrStop(accumulator)`.\n" - " If the returned value is `Continue(accumulator)` fold_until will try the next value in the list.\n" - " If the returned value is `Stop(accumulator)` fold_until will stop and return that accumulator.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " [1, 2, 3, 4]\n" - " |> fold_until(0, fn(acc, i) {\n" - " case i < 3 {\n" - " True -> Continue(acc + i)\n" - " False -> Stop(acc)\n" - " }\n" - " })\n" - " // -> 3\n" - " ```\n" -). --spec fold_until(list(AFK), AFM, fun((AFM, AFK) -> continue_or_stop(AFM))) -> AFM. -fold_until(List, Initial, Fun) -> - case List of - [] -> - Initial; - - [First | Rest] -> - case Fun(Initial, First) of - {continue, Next_accumulator} -> - fold_until(Rest, Next_accumulator, Fun); - - {stop, B} -> - B - end - end. - --file("src/gleam/list.gleam", 916). -?DOC( - " Finds the first element in a given list for which the given function returns\n" - " `True`.\n" - "\n" - " Returns `Error(Nil)` if no such element is found.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " find([1, 2, 3], fn(x) { x > 2 })\n" - " // -> Ok(3)\n" - " ```\n" - "\n" - " ```gleam\n" - " find([1, 2, 3], fn(x) { x > 4 })\n" - " // -> Error(Nil)\n" - " ```\n" - "\n" - " ```gleam\n" - " find([], fn(_) { True })\n" - " // -> Error(Nil)\n" - " ```\n" -). --spec find(list(AFO), fun((AFO) -> boolean())) -> {ok, AFO} | {error, nil}. -find(List, Is_desired) -> - case List of - [] -> - {error, nil}; - - [First | Rest] -> - case Is_desired(First) of - true -> - {ok, First}; - - false -> - find(Rest, Is_desired) - end - end. - --file("src/gleam/list.gleam", 952). -?DOC( - " Finds the first element in a given list for which the given function returns\n" - " `Ok(new_value)`, then returns the wrapped `new_value`.\n" - "\n" - " Returns `Error(Nil)` if no such element is found.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " find_map([[], [2], [3]], first)\n" - " // -> Ok(2)\n" - " ```\n" - "\n" - " ```gleam\n" - " find_map([[], []], first)\n" - " // -> Error(Nil)\n" - " ```\n" - "\n" - " ```gleam\n" - " find_map([], first)\n" - " // -> Error(Nil)\n" - " ```\n" -). --spec find_map(list(AFS), fun((AFS) -> {ok, AFU} | {error, any()})) -> {ok, AFU} | - {error, nil}. -find_map(List, Fun) -> - case List of - [] -> - {error, nil}; - - [First | Rest] -> - case Fun(First) of - {ok, First@1} -> - {ok, First@1}; - - {error, _} -> - find_map(Rest, Fun) - end - end. - --file("src/gleam/list.gleam", 987). -?DOC( - " Returns `True` if the given function returns `True` for all the elements in\n" - " the given list. If the function returns `False` for any of the elements it\n" - " immediately returns `False` without checking the rest of the list.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " all([], fn(x) { x > 3 })\n" - " // -> True\n" - " ```\n" - "\n" - " ```gleam\n" - " all([4, 5], fn(x) { x > 3 })\n" - " // -> True\n" - " ```\n" - "\n" - " ```gleam\n" - " all([4, 3], fn(x) { x > 3 })\n" - " // -> False\n" - " ```\n" -). --spec all(list(AGA), fun((AGA) -> boolean())) -> boolean(). -all(List, Predicate) -> - case List of - [] -> - true; - - [First | Rest] -> - case Predicate(First) of - true -> - all(Rest, Predicate); - - false -> - false - end - end. - --file("src/gleam/list.gleam", 1024). -?DOC( - " Returns `True` if the given function returns `True` for any the elements in\n" - " the given list. If the function returns `True` for any of the elements it\n" - " immediately returns `True` without checking the rest of the list.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " any([], fn(x) { x > 3 })\n" - " // -> False\n" - " ```\n" - "\n" - " ```gleam\n" - " any([4, 5], fn(x) { x > 3 })\n" - " // -> True\n" - " ```\n" - "\n" - " ```gleam\n" - " any([4, 3], fn(x) { x > 4 })\n" - " // -> False\n" - " ```\n" - "\n" - " ```gleam\n" - " any([3, 4], fn(x) { x > 3 })\n" - " // -> True\n" - " ```\n" -). --spec any(list(AGC), fun((AGC) -> boolean())) -> boolean(). -any(List, Predicate) -> - case List of - [] -> - false; - - [First | Rest] -> - case Predicate(First) of - true -> - true; - - false -> - any(Rest, Predicate) - end - end. - --file("src/gleam/list.gleam", 1066). --spec zip_loop(list(AGJ), list(AGL), list({AGJ, AGL})) -> list({AGJ, AGL}). -zip_loop(One, Other, Acc) -> - case {One, Other} of - {[First_one | Rest_one], [First_other | Rest_other]} -> - zip_loop(Rest_one, Rest_other, [{First_one, First_other} | Acc]); - - {_, _} -> - lists:reverse(Acc) - end. - --file("src/gleam/list.gleam", 1062). -?DOC( - " Takes two lists and returns a single list of 2-element tuples.\n" - "\n" - " If one of the lists is longer than the other, the remaining elements from\n" - " the longer list are not used.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " zip([], [])\n" - " // -> []\n" - " ```\n" - "\n" - " ```gleam\n" - " zip([1, 2], [3])\n" - " // -> [#(1, 3)]\n" - " ```\n" - "\n" - " ```gleam\n" - " zip([1], [3, 4])\n" - " // -> [#(1, 3)]\n" - " ```\n" - "\n" - " ```gleam\n" - " zip([1, 2], [3, 4])\n" - " // -> [#(1, 3), #(2, 4)]\n" - " ```\n" -). --spec zip(list(AGE), list(AGG)) -> list({AGE, AGG}). -zip(List, Other) -> - zip_loop(List, Other, []). - --file("src/gleam/list.gleam", 1107). --spec strict_zip_loop(list(AGW), list(AGY), list({AGW, AGY})) -> {ok, - list({AGW, AGY})} | - {error, nil}. -strict_zip_loop(One, Other, Acc) -> - case {One, Other} of - {[], []} -> - {ok, lists:reverse(Acc)}; - - {[], _} -> - {error, nil}; - - {_, []} -> - {error, nil}; - - {[First_one | Rest_one], [First_other | Rest_other]} -> - strict_zip_loop( - Rest_one, - Rest_other, - [{First_one, First_other} | Acc] - ) - end. - --file("src/gleam/list.gleam", 1100). -?DOC( - " Takes two lists and returns a single list of 2-element tuples.\n" - "\n" - " If one of the lists is longer than the other, an `Error` is returned.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " strict_zip([], [])\n" - " // -> Ok([])\n" - " ```\n" - "\n" - " ```gleam\n" - " strict_zip([1, 2], [3])\n" - " // -> Error(Nil)\n" - " ```\n" - "\n" - " ```gleam\n" - " strict_zip([1], [3, 4])\n" - " // -> Error(Nil)\n" - " ```\n" - "\n" - " ```gleam\n" - " strict_zip([1, 2], [3, 4])\n" - " // -> Ok([#(1, 3), #(2, 4)])\n" - " ```\n" -). --spec strict_zip(list(AGP), list(AGR)) -> {ok, list({AGP, AGR})} | {error, nil}. -strict_zip(List, Other) -> - strict_zip_loop(List, Other, []). - --file("src/gleam/list.gleam", 1138). --spec unzip_loop(list({AHJ, AHK}), list(AHJ), list(AHK)) -> {list(AHJ), - list(AHK)}. -unzip_loop(Input, One, Other) -> - case Input of - [] -> - {lists:reverse(One), lists:reverse(Other)}; - - [{First_one, First_other} | Rest] -> - unzip_loop(Rest, [First_one | One], [First_other | Other]) - end. - --file("src/gleam/list.gleam", 1134). -?DOC( - " Takes a single list of 2-element tuples and returns two lists.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " unzip([#(1, 2), #(3, 4)])\n" - " // -> #([1, 3], [2, 4])\n" - " ```\n" - "\n" - " ```gleam\n" - " unzip([])\n" - " // -> #([], [])\n" - " ```\n" -). --spec unzip(list({AHE, AHF})) -> {list(AHE), list(AHF)}. -unzip(Input) -> - unzip_loop(Input, [], []). - --file("src/gleam/list.gleam", 1173). --spec intersperse_loop(list(AHT), AHT, list(AHT)) -> list(AHT). -intersperse_loop(List, Separator, Acc) -> - case List of - [] -> - lists:reverse(Acc); - - [First | Rest] -> - intersperse_loop(Rest, Separator, [First, Separator | Acc]) - end. - --file("src/gleam/list.gleam", 1166). -?DOC( - " Inserts a given value between each existing element in a given list.\n" - "\n" - " This function runs in linear time and copies the list.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " intersperse([1, 1, 1], 2)\n" - " // -> [1, 2, 1, 2, 1]\n" - " ```\n" - "\n" - " ```gleam\n" - " intersperse([], 2)\n" - " // -> []\n" - " ```\n" -). --spec intersperse(list(AHQ), AHQ) -> list(AHQ). -intersperse(List, Elem) -> - case List of - [] -> - List; - - [_] -> - List; - - [First | Rest] -> - intersperse_loop(Rest, Elem, [First]) - end. - --file("src/gleam/list.gleam", 1196). --spec unique_loop(list(AIA), gleam@dict:dict(AIA, nil), list(AIA)) -> list(AIA). -unique_loop(List, Seen, Acc) -> - case List of - [] -> - lists:reverse(Acc); - - [First | Rest] -> - case gleam@dict:has_key(Seen, First) of - true -> - unique_loop(Rest, Seen, Acc); - - false -> - unique_loop( - Rest, - gleam@dict:insert(Seen, First, nil), - [First | Acc] - ) - end - end. - --file("src/gleam/list.gleam", 1192). -?DOC( - " Removes any duplicate elements from a given list.\n" - "\n" - " This function returns in loglinear time.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " unique([1, 1, 1, 4, 7, 3, 3, 4])\n" - " // -> [1, 4, 7, 3]\n" - " ```\n" -). --spec unique(list(AHX)) -> list(AHX). -unique(List) -> - unique_loop(List, maps:new(), []). - --file("src/gleam/list.gleam", 1282). -?DOC( - " Given a list it returns slices of it that are locally sorted in ascending\n" - " order.\n" - "\n" - " Imagine you have this list:\n" - "\n" - " ```\n" - " [1, 2, 3, 2, 1, 0]\n" - " ^^^^^^^ ^^^^^^^ This is a slice in descending order\n" - " |\n" - " | This is a slice that is sorted in ascending order\n" - " ```\n" - "\n" - " So the produced result will contain these two slices, each one sorted in\n" - " ascending order: `[[1, 2, 3], [0, 1, 2]]`.\n" - "\n" - " - `growing` is an accumulator with the current slice being grown\n" - " - `direction` is the growing direction of the slice being grown, it could\n" - " either be ascending or strictly descending\n" - " - `prev` is the previous element that needs to be added to the growing slice\n" - " it is carried around to check whether we have to keep growing the current\n" - " slice or not\n" - " - `acc` is the accumulator containing the slices sorted in ascending order\n" -). --spec sequences( - list(AIJ), - fun((AIJ, AIJ) -> gleam@order:order()), - list(AIJ), - sorting(), - AIJ, - list(list(AIJ)) -) -> list(list(AIJ)). -sequences(List, Compare, Growing, Direction, Prev, Acc) -> - Growing@1 = [Prev | Growing], - case List of - [] -> - case Direction of - ascending -> - [lists:reverse(Growing@1) | Acc]; - - descending -> - [Growing@1 | Acc] - end; - - [New | Rest] -> - case {Compare(Prev, New), Direction} of - {gt, descending} -> - sequences(Rest, Compare, Growing@1, Direction, New, Acc); - - {lt, ascending} -> - sequences(Rest, Compare, Growing@1, Direction, New, Acc); - - {eq, ascending} -> - sequences(Rest, Compare, Growing@1, Direction, New, Acc); - - {gt, ascending} -> - Acc@1 = case Direction of - ascending -> - [lists:reverse(Growing@1) | Acc]; - - descending -> - [Growing@1 | Acc] - end, - case Rest of - [] -> - [[New] | Acc@1]; - - [Next | Rest@1] -> - Direction@1 = case Compare(New, Next) of - lt -> - ascending; - - eq -> - ascending; - - gt -> - descending - end, - sequences( - Rest@1, - Compare, - [New], - Direction@1, - Next, - Acc@1 - ) - end; - - {lt, descending} -> - Acc@1 = case Direction of - ascending -> - [lists:reverse(Growing@1) | Acc]; - - descending -> - [Growing@1 | Acc] - end, - case Rest of - [] -> - [[New] | Acc@1]; - - [Next | Rest@1] -> - Direction@1 = case Compare(New, Next) of - lt -> - ascending; - - eq -> - ascending; - - gt -> - descending - end, - sequences( - Rest@1, - Compare, - [New], - Direction@1, - Next, - Acc@1 - ) - end; - - {eq, descending} -> - Acc@1 = case Direction of - ascending -> - [lists:reverse(Growing@1) | Acc]; - - descending -> - [Growing@1 | Acc] - end, - case Rest of - [] -> - [[New] | Acc@1]; - - [Next | Rest@1] -> - Direction@1 = case Compare(New, Next) of - lt -> - ascending; - - eq -> - ascending; - - gt -> - descending - end, - sequences( - Rest@1, - Compare, - [New], - Direction@1, - Next, - Acc@1 - ) - end - end - end. - --file("src/gleam/list.gleam", 1430). -?DOC( - " Merges two lists sorted in ascending order into a single list sorted in\n" - " descending order according to the given comparator function.\n" - "\n" - " This reversing of the sort order is not avoidable if we want to implement\n" - " merge as a tail recursive function. We could reverse the accumulator before\n" - " returning it but that would end up being less efficient; so the merging\n" - " algorithm has to play around this.\n" -). --spec merge_ascendings( - list(AJG), - list(AJG), - fun((AJG, AJG) -> gleam@order:order()), - list(AJG) -) -> list(AJG). -merge_ascendings(List1, List2, Compare, Acc) -> - case {List1, List2} of - {[], List} -> - lists:reverse(List, Acc); - - {List, []} -> - lists:reverse(List, Acc); - - {[First1 | Rest1], [First2 | Rest2]} -> - case Compare(First1, First2) of - lt -> - merge_ascendings(Rest1, List2, Compare, [First1 | Acc]); - - gt -> - merge_ascendings(List1, Rest2, Compare, [First2 | Acc]); - - eq -> - merge_ascendings(List1, Rest2, Compare, [First2 | Acc]) - end - end. - --file("src/gleam/list.gleam", 1383). -?DOC( - " Given a list of ascending lists, it merges adjacent pairs into a single\n" - " descending list, halving their number.\n" - " It returns a list of the remaining descending lists.\n" -). --spec merge_ascending_pairs( - list(list(AIU)), - fun((AIU, AIU) -> gleam@order:order()), - list(list(AIU)) -) -> list(list(AIU)). -merge_ascending_pairs(Sequences, Compare, Acc) -> - case Sequences of - [] -> - lists:reverse(Acc); - - [Sequence] -> - lists:reverse([lists:reverse(Sequence) | Acc]); - - [Ascending1, Ascending2 | Rest] -> - Descending = merge_ascendings(Ascending1, Ascending2, Compare, []), - merge_ascending_pairs(Rest, Compare, [Descending | Acc]) - end. - --file("src/gleam/list.gleam", 1457). -?DOC( - " This is exactly the same as merge_ascendings but mirrored: it merges two\n" - " lists sorted in descending order into a single list sorted in ascending\n" - " order according to the given comparator function.\n" - "\n" - " This reversing of the sort order is not avoidable if we want to implement\n" - " merge as a tail recursive function. We could reverse the accumulator before\n" - " returning it but that would end up being less efficient; so the merging\n" - " algorithm has to play around this.\n" -). --spec merge_descendings( - list(AJL), - list(AJL), - fun((AJL, AJL) -> gleam@order:order()), - list(AJL) -) -> list(AJL). -merge_descendings(List1, List2, Compare, Acc) -> - case {List1, List2} of - {[], List} -> - lists:reverse(List, Acc); - - {List, []} -> - lists:reverse(List, Acc); - - {[First1 | Rest1], [First2 | Rest2]} -> - case Compare(First1, First2) of - lt -> - merge_descendings(List1, Rest2, Compare, [First2 | Acc]); - - gt -> - merge_descendings(Rest1, List2, Compare, [First1 | Acc]); - - eq -> - merge_descendings(Rest1, List2, Compare, [First1 | Acc]) - end - end. - --file("src/gleam/list.gleam", 1405). -?DOC(" This is the same as merge_ascending_pairs but flipped for descending lists.\n"). --spec merge_descending_pairs( - list(list(AJA)), - fun((AJA, AJA) -> gleam@order:order()), - list(list(AJA)) -) -> list(list(AJA)). -merge_descending_pairs(Sequences, Compare, Acc) -> - case Sequences of - [] -> - lists:reverse(Acc); - - [Sequence] -> - lists:reverse([lists:reverse(Sequence) | Acc]); - - [Descending1, Descending2 | Rest] -> - Ascending = merge_descendings(Descending1, Descending2, Compare, []), - merge_descending_pairs(Rest, Compare, [Ascending | Acc]) - end. - --file("src/gleam/list.gleam", 1349). -?DOC( - " Given some some sorted sequences (assumed to be sorted in `direction`) it\n" - " merges them all together until we're left with just a list sorted in\n" - " ascending order.\n" -). --spec merge_all( - list(list(AIQ)), - sorting(), - fun((AIQ, AIQ) -> gleam@order:order()) -) -> list(AIQ). -merge_all(Sequences, Direction, Compare) -> - case {Sequences, Direction} of - {[], _} -> - []; - - {[Sequence], ascending} -> - Sequence; - - {[Sequence@1], descending} -> - lists:reverse(Sequence@1); - - {_, ascending} -> - Sequences@1 = merge_ascending_pairs(Sequences, Compare, []), - merge_all(Sequences@1, descending, Compare); - - {_, descending} -> - Sequences@2 = merge_descending_pairs(Sequences, Compare, []), - merge_all(Sequences@2, ascending, Compare) - end. - --file("src/gleam/list.gleam", 1220). -?DOC( - " Sorts from smallest to largest based upon the ordering specified by a given\n" - " function.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " import gleam/int\n" - "\n" - " sort([4, 3, 6, 5, 4, 1, 2], by: int.compare)\n" - " // -> [1, 2, 3, 4, 4, 5, 6]\n" - " ```\n" -). --spec sort(list(AIG), fun((AIG, AIG) -> gleam@order:order())) -> list(AIG). -sort(List, Compare) -> - case List of - [] -> - []; - - [X] -> - [X]; - - [X@1, Y | Rest] -> - Direction = case Compare(X@1, Y) of - lt -> - ascending; - - eq -> - ascending; - - gt -> - descending - end, - Sequences = sequences(Rest, Compare, [X@1], Direction, Y, []), - merge_all(Sequences, ascending, Compare) - end. - --file("src/gleam/list.gleam", 1497). --spec range_loop(integer(), integer(), list(integer())) -> list(integer()). -range_loop(Start, Stop, Acc) -> - case gleam@int:compare(Start, Stop) of - eq -> - [Stop | Acc]; - - gt -> - range_loop(Start, Stop + 1, [Stop | Acc]); - - lt -> - range_loop(Start, Stop - 1, [Stop | Acc]) - end. - --file("src/gleam/list.gleam", 1493). -?DOC( - " Creates a list of ints ranging from a given start and finish.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " range(0, 0)\n" - " // -> [0]\n" - " ```\n" - "\n" - " ```gleam\n" - " range(0, 5)\n" - " // -> [0, 1, 2, 3, 4, 5]\n" - " ```\n" - "\n" - " ```gleam\n" - " range(1, -5)\n" - " // -> [1, 0, -1, -2, -3, -4, -5]\n" - " ```\n" -). --spec range(integer(), integer()) -> list(integer()). -range(Start, Stop) -> - range_loop(Start, Stop, []). - --file("src/gleam/list.gleam", 1523). --spec repeat_loop(AJV, integer(), list(AJV)) -> list(AJV). -repeat_loop(Item, Times, Acc) -> - case Times =< 0 of - true -> - Acc; - - false -> - repeat_loop(Item, Times - 1, [Item | Acc]) - end. - --file("src/gleam/list.gleam", 1519). -?DOC( - " Builds a list of a given value a given number of times.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " repeat(\"a\", times: 0)\n" - " // -> []\n" - " ```\n" - "\n" - " ```gleam\n" - " repeat(\"a\", times: 5)\n" - " // -> [\"a\", \"a\", \"a\", \"a\", \"a\"]\n" - " ```\n" -). --spec repeat(AJT, integer()) -> list(AJT). -repeat(A, Times) -> - repeat_loop(A, Times, []). - --file("src/gleam/list.gleam", 1556). --spec split_loop(list(AKC), integer(), list(AKC)) -> {list(AKC), list(AKC)}. -split_loop(List, N, Taken) -> - case N =< 0 of - true -> - {lists:reverse(Taken), List}; - - false -> - case List of - [] -> - {lists:reverse(Taken), []}; - - [First | Rest] -> - split_loop(Rest, N - 1, [First | Taken]) - end - end. - --file("src/gleam/list.gleam", 1552). -?DOC( - " Splits a list in two before the given index.\n" - "\n" - " If the list is not long enough to have the given index the before list will\n" - " be the input list, and the after list will be empty.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " split([6, 7, 8, 9], 0)\n" - " // -> #([], [6, 7, 8, 9])\n" - " ```\n" - "\n" - " ```gleam\n" - " split([6, 7, 8, 9], 2)\n" - " // -> #([6, 7], [8, 9])\n" - " ```\n" - "\n" - " ```gleam\n" - " split([6, 7, 8, 9], 4)\n" - " // -> #([6, 7, 8, 9], [])\n" - " ```\n" -). --spec split(list(AJY), integer()) -> {list(AJY), list(AJY)}. -split(List, Index) -> - split_loop(List, Index, []). - --file("src/gleam/list.gleam", 1592). --spec split_while_loop(list(AKL), fun((AKL) -> boolean()), list(AKL)) -> {list(AKL), - list(AKL)}. -split_while_loop(List, F, Acc) -> - case List of - [] -> - {lists:reverse(Acc), []}; - - [First | Rest] -> - case F(First) of - true -> - split_while_loop(Rest, F, [First | Acc]); - - false -> - {lists:reverse(Acc), List} - end - end. - --file("src/gleam/list.gleam", 1585). -?DOC( - " Splits a list in two before the first element that a given function returns\n" - " `False` for.\n" - "\n" - " If the function returns `True` for all elements the first list will be the\n" - " input list, and the second list will be empty.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " split_while([1, 2, 3, 4, 5], fn(x) { x <= 3 })\n" - " // -> #([1, 2, 3], [4, 5])\n" - " ```\n" - "\n" - " ```gleam\n" - " split_while([1, 2, 3, 4, 5], fn(x) { x <= 5 })\n" - " // -> #([1, 2, 3, 4, 5], [])\n" - " ```\n" -). --spec split_while(list(AKH), fun((AKH) -> boolean())) -> {list(AKH), list(AKH)}. -split_while(List, Predicate) -> - split_while_loop(List, Predicate, []). - --file("src/gleam/list.gleam", 1632). -?DOC( - " Given a list of 2-element tuples, finds the first tuple that has a given\n" - " key as the first element and returns the second element.\n" - "\n" - " If no tuple is found with the given key then `Error(Nil)` is returned.\n" - "\n" - " This function may be useful for interacting with Erlang code where lists of\n" - " tuples are common.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " key_find([#(\"a\", 0), #(\"b\", 1)], \"a\")\n" - " // -> Ok(0)\n" - " ```\n" - "\n" - " ```gleam\n" - " key_find([#(\"a\", 0), #(\"b\", 1)], \"b\")\n" - " // -> Ok(1)\n" - " ```\n" - "\n" - " ```gleam\n" - " key_find([#(\"a\", 0), #(\"b\", 1)], \"c\")\n" - " // -> Error(Nil)\n" - " ```\n" -). --spec key_find(list({AKQ, AKR}), AKQ) -> {ok, AKR} | {error, nil}. -key_find(Keyword_list, Desired_key) -> - find_map( - Keyword_list, - fun(Keyword) -> - {Key, Value} = Keyword, - case Key =:= Desired_key of - true -> - {ok, Value}; - - false -> - {error, nil} - end - end - ). - --file("src/gleam/list.gleam", 1663). -?DOC( - " Given a list of 2-element tuples, finds all tuples that have a given\n" - " key as the first element and returns the second element.\n" - "\n" - " This function may be useful for interacting with Erlang code where lists of\n" - " tuples are common.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " key_filter([#(\"a\", 0), #(\"b\", 1), #(\"a\", 2)], \"a\")\n" - " // -> [0, 2]\n" - " ```\n" - "\n" - " ```gleam\n" - " key_filter([#(\"a\", 0), #(\"b\", 1)], \"c\")\n" - " // -> []\n" - " ```\n" -). --spec key_filter(list({AKV, AKW}), AKV) -> list(AKW). -key_filter(Keyword_list, Desired_key) -> - filter_map( - Keyword_list, - fun(Keyword) -> - {Key, Value} = Keyword, - case Key =:= Desired_key of - true -> - {ok, Value}; - - false -> - {error, nil} - end - end - ). - --file("src/gleam/list.gleam", 1703). --spec key_pop_loop(list({ALF, ALG}), ALF, list({ALF, ALG})) -> {ok, - {ALG, list({ALF, ALG})}} | - {error, nil}. -key_pop_loop(List, Key, Checked) -> - case List of - [] -> - {error, nil}; - - [{K, V} | Rest] when K =:= Key -> - {ok, {V, lists:reverse(Checked, Rest)}}; - - [First | Rest@1] -> - key_pop_loop(Rest@1, Key, [First | Checked]) - end. - --file("src/gleam/list.gleam", 1699). -?DOC( - " Given a list of 2-element tuples, finds the first tuple that has a given\n" - " key as the first element. This function will return the second element\n" - " of the found tuple and list with tuple removed.\n" - "\n" - " If no tuple is found with the given key then `Error(Nil)` is returned.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " key_pop([#(\"a\", 0), #(\"b\", 1)], \"a\")\n" - " // -> Ok(#(0, [#(\"b\", 1)]))\n" - " ```\n" - "\n" - " ```gleam\n" - " key_pop([#(\"a\", 0), #(\"b\", 1)], \"b\")\n" - " // -> Ok(#(1, [#(\"a\", 0)]))\n" - " ```\n" - "\n" - " ```gleam\n" - " key_pop([#(\"a\", 0), #(\"b\", 1)], \"c\")\n" - " // -> Error(Nil)\n" - " ```\n" -). --spec key_pop(list({AKZ, ALA}), AKZ) -> {ok, {ALA, list({AKZ, ALA})}} | - {error, nil}. -key_pop(List, Key) -> - key_pop_loop(List, Key, []). - --file("src/gleam/list.gleam", 1737). --spec key_set_loop(list({ALQ, ALR}), ALQ, ALR, list({ALQ, ALR})) -> list({ALQ, - ALR}). -key_set_loop(List, Key, Value, Inspected) -> - case List of - [{K, _} | Rest] when K =:= Key -> - lists:reverse(Inspected, [{K, Value} | Rest]); - - [First | Rest@1] -> - key_set_loop(Rest@1, Key, Value, [First | Inspected]); - - [] -> - lists:reverse([{Key, Value} | Inspected]) - end. - --file("src/gleam/list.gleam", 1733). -?DOC( - " Given a list of 2-element tuples, inserts a key and value into the list.\n" - "\n" - " If there was already a tuple with the key then it is replaced, otherwise it\n" - " is added to the end of the list.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " key_set([#(5, 0), #(4, 1)], 4, 100)\n" - " // -> [#(5, 0), #(4, 100)]\n" - " ```\n" - "\n" - " ```gleam\n" - " key_set([#(5, 0), #(4, 1)], 1, 100)\n" - " // -> [#(5, 0), #(4, 1), #(1, 100)]\n" - " ```\n" -). --spec key_set(list({ALM, ALN}), ALM, ALN) -> list({ALM, ALN}). -key_set(List, Key, Value) -> - key_set_loop(List, Key, Value, []). - --file("src/gleam/list.gleam", 1765). -?DOC( - " Calls a function for each element in a list, discarding the return value.\n" - "\n" - " Useful for calling a side effect for every item of a list.\n" - "\n" - " ```gleam\n" - " import gleam/io\n" - "\n" - " each([\"1\", \"2\", \"3\"], io.println)\n" - " // -> Nil\n" - " // 1\n" - " // 2\n" - " // 3\n" - " ```\n" -). --spec each(list(ALV), fun((ALV) -> any())) -> nil. -each(List, F) -> - case List of - [] -> - nil; - - [First | Rest] -> - F(First), - each(Rest, F) - end. - --file("src/gleam/list.gleam", 1791). -?DOC( - " Calls a `Result` returning function for each element in a list, discarding\n" - " the return value. If the function returns `Error` then the iteration is\n" - " stopped and the error is returned.\n" - "\n" - " Useful for calling a side effect for every item of a list.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " try_each(\n" - " over: [1, 2, 3],\n" - " with: function_that_might_fail,\n" - " )\n" - " // -> Ok(Nil)\n" - " ```\n" -). --spec try_each(list(ALY), fun((ALY) -> {ok, any()} | {error, AMB})) -> {ok, nil} | - {error, AMB}. -try_each(List, Fun) -> - case List of - [] -> - {ok, nil}; - - [First | Rest] -> - case Fun(First) of - {ok, _} -> - try_each(Rest, Fun); - - {error, E} -> - {error, E} - end - end. - --file("src/gleam/list.gleam", 1824). --spec partition_loop(list(BFR), fun((BFR) -> boolean()), list(BFR), list(BFR)) -> {list(BFR), - list(BFR)}. -partition_loop(List, Categorise, Trues, Falses) -> - case List of - [] -> - {lists:reverse(Trues), lists:reverse(Falses)}; - - [First | Rest] -> - case Categorise(First) of - true -> - partition_loop(Rest, Categorise, [First | Trues], Falses); - - false -> - partition_loop(Rest, Categorise, Trues, [First | Falses]) - end - end. - --file("src/gleam/list.gleam", 1817). -?DOC( - " Partitions a list into a tuple/pair of lists\n" - " by a given categorisation function.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " import gleam/int\n" - "\n" - " [1, 2, 3, 4, 5] |> partition(int.is_odd)\n" - " // -> #([1, 3, 5], [2, 4])\n" - " ```\n" -). --spec partition(list(AMG), fun((AMG) -> boolean())) -> {list(AMG), list(AMG)}. -partition(List, Categorise) -> - partition_loop(List, Categorise, [], []). - --file("src/gleam/list.gleam", 1904). --spec window_loop(list(list(ANN)), list(ANN), integer()) -> list(list(ANN)). -window_loop(Acc, List, N) -> - Window = take(List, N), - case erlang:length(Window) =:= N of - true -> - window_loop([Window | Acc], drop(List, 1), N); - - false -> - lists:reverse(Acc) - end. - --file("src/gleam/list.gleam", 1897). -?DOC( - " Returns a list of sliding windows.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " window([1,2,3,4,5], 3)\n" - " // -> [[1, 2, 3], [2, 3, 4], [3, 4, 5]]\n" - " ```\n" - "\n" - " ```gleam\n" - " window([1, 2], 4)\n" - " // -> []\n" - " ```\n" -). --spec window(list(ANJ), integer()) -> list(list(ANJ)). -window(List, N) -> - case N =< 0 of - true -> - []; - - false -> - window_loop([], List, N) - end. - --file("src/gleam/list.gleam", 1927). -?DOC( - " Returns a list of tuples containing two contiguous elements.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " window_by_2([1,2,3,4])\n" - " // -> [#(1, 2), #(2, 3), #(3, 4)]\n" - " ```\n" - "\n" - " ```gleam\n" - " window_by_2([1])\n" - " // -> []\n" - " ```\n" -). --spec window_by_2(list(ANT)) -> list({ANT, ANT}). -window_by_2(List) -> - zip(List, drop(List, 1)). - --file("src/gleam/list.gleam", 1940). -?DOC( - " Drops the first elements in a given list for which the predicate function returns `True`.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " drop_while([1, 2, 3, 4], fn (x) { x < 3 })\n" - " // -> [3, 4]\n" - " ```\n" -). --spec drop_while(list(ANW), fun((ANW) -> boolean())) -> list(ANW). -drop_while(List, Predicate) -> - case List of - [] -> - []; - - [First | Rest] -> - case Predicate(First) of - true -> - drop_while(Rest, Predicate); - - false -> - [First | Rest] - end - end. - --file("src/gleam/list.gleam", 1970). --spec take_while_loop(list(AOC), fun((AOC) -> boolean()), list(AOC)) -> list(AOC). -take_while_loop(List, Predicate, Acc) -> - case List of - [] -> - lists:reverse(Acc); - - [First | Rest] -> - case Predicate(First) of - true -> - take_while_loop(Rest, Predicate, [First | Acc]); - - false -> - lists:reverse(Acc) - end - end. - --file("src/gleam/list.gleam", 1963). -?DOC( - " Takes the first elements in a given list for which the predicate function returns `True`.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " take_while([1, 2, 3, 2, 4], fn (x) { x < 3 })\n" - " // -> [1, 2]\n" - " ```\n" -). --spec take_while(list(ANZ), fun((ANZ) -> boolean())) -> list(ANZ). -take_while(List, Predicate) -> - take_while_loop(List, Predicate, []). - --file("src/gleam/list.gleam", 2002). --spec chunk_loop(list(AOL), fun((AOL) -> AON), AON, list(AOL), list(list(AOL))) -> list(list(AOL)). -chunk_loop(List, F, Previous_key, Current_chunk, Acc) -> - case List of - [First | Rest] -> - Key = F(First), - case Key =:= Previous_key of - true -> - chunk_loop(Rest, F, Key, [First | Current_chunk], Acc); - - false -> - New_acc = [lists:reverse(Current_chunk) | Acc], - chunk_loop(Rest, F, Key, [First], New_acc) - end; - - [] -> - lists:reverse([lists:reverse(Current_chunk) | Acc]) - end. - --file("src/gleam/list.gleam", 1995). -?DOC( - " Returns a list of chunks in which\n" - " the return value of calling `f` on each element is the same.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " [1, 2, 2, 3, 4, 4, 6, 7, 7] |> chunk(by: fn(n) { n % 2 })\n" - " // -> [[1], [2, 2], [3], [4, 4, 6], [7, 7]]\n" - " ```\n" -). --spec chunk(list(AOG), fun((AOG) -> any())) -> list(list(AOG)). -chunk(List, F) -> - case List of - [] -> - []; - - [First | Rest] -> - chunk_loop(Rest, F, F(First), [First], []) - end. - --file("src/gleam/list.gleam", 2047). --spec sized_chunk_loop( - list(AOX), - integer(), - integer(), - list(AOX), - list(list(AOX)) -) -> list(list(AOX)). -sized_chunk_loop(List, Count, Left, Current_chunk, Acc) -> - case List of - [] -> - case Current_chunk of - [] -> - lists:reverse(Acc); - - Remaining -> - lists:reverse([lists:reverse(Remaining) | Acc]) - end; - - [First | Rest] -> - Chunk = [First | Current_chunk], - case Left > 1 of - true -> - sized_chunk_loop(Rest, Count, Left - 1, Chunk, Acc); - - false -> - sized_chunk_loop( - Rest, - Count, - Count, - [], - [lists:reverse(Chunk) | Acc] - ) - end - end. - --file("src/gleam/list.gleam", 2043). -?DOC( - " Returns a list of chunks containing `count` elements each.\n" - "\n" - " If the last chunk does not have `count` elements, it is instead\n" - " a partial chunk, with less than `count` elements.\n" - "\n" - " For any `count` less than 1 this function behaves as if it was set to 1.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " [1, 2, 3, 4, 5, 6] |> sized_chunk(into: 2)\n" - " // -> [[1, 2], [3, 4], [5, 6]]\n" - " ```\n" - "\n" - " ```gleam\n" - " [1, 2, 3, 4, 5, 6, 7, 8] |> sized_chunk(into: 3)\n" - " // -> [[1, 2, 3], [4, 5, 6], [7, 8]]\n" - " ```\n" -). --spec sized_chunk(list(AOT), integer()) -> list(list(AOT)). -sized_chunk(List, Count) -> - sized_chunk_loop(List, Count, Count, [], []). - --file("src/gleam/list.gleam", 2091). -?DOC( - " This function acts similar to fold, but does not take an initial state.\n" - " Instead, it starts from the first element in the list\n" - " and combines it with each subsequent element in turn using the given\n" - " function. The function is called as `fun(accumulator, current_element)`.\n" - "\n" - " Returns `Ok` to indicate a successful run, and `Error` if called on an\n" - " empty list.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " [] |> reduce(fn(acc, x) { acc + x })\n" - " // -> Error(Nil)\n" - " ```\n" - "\n" - " ```gleam\n" - " [1, 2, 3, 4, 5] |> reduce(fn(acc, x) { acc + x })\n" - " // -> Ok(15)\n" - " ```\n" -). --spec reduce(list(APE), fun((APE, APE) -> APE)) -> {ok, APE} | {error, nil}. -reduce(List, Fun) -> - case List of - [] -> - {error, nil}; - - [First | Rest] -> - {ok, fold(Rest, First, Fun)} - end. - --file("src/gleam/list.gleam", 2115). --spec scan_loop(list(APM), APO, list(APO), fun((APO, APM) -> APO)) -> list(APO). -scan_loop(List, Accumulator, Accumulated, Fun) -> - case List of - [] -> - lists:reverse(Accumulated); - - [First | Rest] -> - Next = Fun(Accumulator, First), - scan_loop(Rest, Next, [Next | Accumulated], Fun) - end. - --file("src/gleam/list.gleam", 2107). -?DOC( - " Similar to `fold`, but yields the state of the accumulator at each stage.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " scan(over: [1, 2, 3], from: 100, with: fn(acc, i) { acc + i })\n" - " // -> [101, 103, 106]\n" - " ```\n" -). --spec scan(list(API), APK, fun((APK, API) -> APK)) -> list(APK). -scan(List, Initial, Fun) -> - scan_loop(List, Initial, [], Fun). - --file("src/gleam/list.gleam", 2148). -?DOC( - " Returns the last element in the given list.\n" - "\n" - " Returns `Error(Nil)` if the list is empty.\n" - "\n" - " This function runs in linear time.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " last([])\n" - " // -> Error(Nil)\n" - " ```\n" - "\n" - " ```gleam\n" - " last([1, 2, 3, 4, 5])\n" - " // -> Ok(5)\n" - " ```\n" -). --spec last(list(APR)) -> {ok, APR} | {error, nil}. -last(List) -> - case List of - [] -> - {error, nil}; - - [Last] -> - {ok, Last}; - - [_ | Rest] -> - last(Rest) - end. - --file("src/gleam/list.gleam", 2170). -?DOC( - " Return unique combinations of elements in the list.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " combinations([1, 2, 3], 2)\n" - " // -> [[1, 2], [1, 3], [2, 3]]\n" - " ```\n" - "\n" - " ```gleam\n" - " combinations([1, 2, 3, 4], 3)\n" - " // -> [[1, 2, 3], [1, 2, 4], [1, 3, 4], [2, 3, 4]]\n" - " ```\n" -). --spec combinations(list(APV), integer()) -> list(list(APV)). -combinations(Items, N) -> - case {N, Items} of - {0, _} -> - [[]]; - - {_, []} -> - []; - - {_, [First | Rest]} -> - _pipe = Rest, - _pipe@1 = combinations(_pipe, N - 1), - _pipe@2 = map( - _pipe@1, - fun(Combination) -> [First | Combination] end - ), - _pipe@3 = lists:reverse(_pipe@2), - fold(_pipe@3, combinations(Rest, N), fun(Acc, C) -> [C | Acc] end) - end. - --file("src/gleam/list.gleam", 2196). --spec combination_pairs_loop(list(AQC), list({AQC, AQC})) -> list({AQC, AQC}). -combination_pairs_loop(Items, Acc) -> - case Items of - [] -> - lists:reverse(Acc); - - [First | Rest] -> - First_combinations = map(Rest, fun(Other) -> {First, Other} end), - Acc@1 = lists:reverse(First_combinations, Acc), - combination_pairs_loop(Rest, Acc@1) - end. - --file("src/gleam/list.gleam", 2192). -?DOC( - " Return unique pair combinations of elements in the list.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " combination_pairs([1, 2, 3])\n" - " // -> [#(1, 2), #(1, 3), #(2, 3)]\n" - " ```\n" -). --spec combination_pairs(list(APZ)) -> list({APZ, APZ}). -combination_pairs(Items) -> - combination_pairs_loop(Items, []). - --file("src/gleam/list.gleam", 2252). --spec take_firsts(list(list(AQW)), list(AQW), list(list(AQW))) -> {list(AQW), - list(list(AQW))}. -take_firsts(Rows, Column, Remaining_rows) -> - case Rows of - [] -> - {lists:reverse(Column), lists:reverse(Remaining_rows)}; - - [[] | Rest] -> - take_firsts(Rest, Column, Remaining_rows); - - [[First | Remaining_row] | Rest_rows] -> - Remaining_rows@1 = [Remaining_row | Remaining_rows], - take_firsts(Rest_rows, [First | Column], Remaining_rows@1) - end. - --file("src/gleam/list.gleam", 2239). --spec transpose_loop(list(list(AQP)), list(list(AQP))) -> list(list(AQP)). -transpose_loop(Rows, Columns) -> - case Rows of - [] -> - lists:reverse(Columns); - - _ -> - {Column, Rest} = take_firsts(Rows, [], []), - case Column of - [_ | _] -> - transpose_loop(Rest, [Column | Columns]); - - [] -> - transpose_loop(Rest, Columns) - end - end. - --file("src/gleam/list.gleam", 2235). -?DOC( - " Transpose rows and columns of the list of lists.\n" - "\n" - " Notice: This function is not tail recursive,\n" - " and thus may exceed stack size if called,\n" - " with large lists (on the JavaScript target).\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " transpose([[1, 2, 3], [101, 102, 103]])\n" - " // -> [[1, 101], [2, 102], [3, 103]]\n" - " ```\n" -). --spec transpose(list(list(AQK))) -> list(list(AQK)). -transpose(List_of_lists) -> - transpose_loop(List_of_lists, []). - --file("src/gleam/list.gleam", 2216). -?DOC( - " Make a list alternating the elements from the given lists\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " interleave([[1, 2], [101, 102], [201, 202]])\n" - " // -> [1, 101, 201, 2, 102, 202]\n" - " ```\n" -). --spec interleave(list(list(AQG))) -> list(AQG). -interleave(List) -> - _pipe = List, - _pipe@1 = transpose(_pipe), - lists:append(_pipe@1). - --file("src/gleam/list.gleam", 2285). --spec shuffle_pair_unwrap_loop(list({float(), ARI}), list(ARI)) -> list(ARI). -shuffle_pair_unwrap_loop(List, Acc) -> - case List of - [] -> - Acc; - - [Elem_pair | Enumerable] -> - shuffle_pair_unwrap_loop( - Enumerable, - [erlang:element(2, Elem_pair) | Acc] - ) - end. - --file("src/gleam/list.gleam", 2293). --spec do_shuffle_by_pair_indexes(list({float(), ARM})) -> list({float(), ARM}). -do_shuffle_by_pair_indexes(List_of_pairs) -> - sort( - List_of_pairs, - fun(A_pair, B_pair) -> - gleam@float:compare( - erlang:element(1, A_pair), - erlang:element(1, B_pair) - ) - end - ). - --file("src/gleam/list.gleam", 2278). -?DOC( - " Takes a list, randomly sorts all items and returns the shuffled list.\n" - "\n" - " This function uses `float.random` to decide the order of the elements.\n" - "\n" - " ## Example\n" - "\n" - " ```gleam\n" - " range(1, 10) |> shuffle()\n" - " // -> [1, 6, 9, 10, 3, 8, 4, 2, 7, 5]\n" - " ```\n" -). --spec shuffle(list(ARF)) -> list(ARF). -shuffle(List) -> - _pipe = List, - _pipe@1 = fold(_pipe, [], fun(Acc, A) -> [{rand:uniform(), A} | Acc] end), - _pipe@2 = do_shuffle_by_pair_indexes(_pipe@1), - shuffle_pair_unwrap_loop(_pipe@2, []). - --file("src/gleam/list.gleam", 2325). --spec max_loop(list(ARW), fun((ARW, ARW) -> gleam@order:order()), ARW) -> ARW. -max_loop(List, Compare, Max) -> - case List of - [] -> - Max; - - [First | Rest] -> - case Compare(First, Max) of - gt -> - max_loop(Rest, Compare, First); - - lt -> - max_loop(Rest, Compare, Max); - - eq -> - max_loop(Rest, Compare, Max) - end - end. - --file("src/gleam/list.gleam", 2315). -?DOC( - " Takes a list and a comparator, and returns the maximum element in the list\n" - "\n" - "\n" - " ## Example\n" - "\n" - " ```gleam\n" - " range(1, 10) |> list.max(int.compare)\n" - " // -> Ok(10)\n" - " ```\n" - "\n" - " ```gleam\n" - " [\"a\", \"c\", \"b\"] |> list.max(string.compare)\n" - " // -> Ok(\"c\")\n" - " ```\n" -). --spec max(list(ARP), fun((ARP, ARP) -> gleam@order:order())) -> {ok, ARP} | - {error, nil}. -max(List, Compare) -> - case List of - [] -> - {error, nil}; - - [First | Rest] -> - {ok, max_loop(Rest, Compare, First)} - end. - --file("src/gleam/list.gleam", 2406). --spec build_reservoir_loop( - list(ASL), - integer(), - gleam@dict:dict(integer(), ASL) -) -> {gleam@dict:dict(integer(), ASL), list(ASL)}. -build_reservoir_loop(List, Size, Reservoir) -> - Reservoir_size = maps:size(Reservoir), - case Reservoir_size >= Size of - true -> - {Reservoir, List}; - - false -> - case List of - [] -> - {Reservoir, []}; - - [First | Rest] -> - Reservoir@1 = gleam@dict:insert( - Reservoir, - Reservoir_size, - First - ), - build_reservoir_loop(Rest, Size, Reservoir@1) - end - end. - --file("src/gleam/list.gleam", 2402). -?DOC( - " Builds the initial reservoir used by Algorithm L.\n" - " This is a dictionary with keys ranging from `0` up to `n - 1` where each\n" - " value is the corresponding element at that position in `list`.\n" - "\n" - " This also returns the remaining elements of `list` that didn't end up in\n" - " the reservoir.\n" -). --spec build_reservoir(list(ASG), integer()) -> {gleam@dict:dict(integer(), ASG), - list(ASG)}. -build_reservoir(List, N) -> - build_reservoir_loop(List, N, maps:new()). - --file("src/gleam/list.gleam", 2390). --spec log_random() -> float(). -log_random() -> - Random@1 = case gleam@float:logarithm( - rand:uniform() + 2.2250738585072014e-308 - ) of - {ok, Random} -> Random; - _assert_fail -> - erlang:error(#{gleam_error => let_assert, - message => <<"Pattern match failed, no pattern matched the value."/utf8>>, - file => <>, - module => <<"gleam/list"/utf8>>, - function => <<"log_random"/utf8>>, - line => 2391, - value => _assert_fail, - start => 56078, - 'end' => 56149, - pattern_start => 56089, - pattern_end => 56099}) - end, - Random@1. - --file("src/gleam/list.gleam", 2367). --spec sample_loop( - list(ASA), - gleam@dict:dict(integer(), ASA), - integer(), - float() -) -> gleam@dict:dict(integer(), ASA). -sample_loop(List, Reservoir, N, W) -> - Skip = begin - Log@1 = case gleam@float:logarithm(1.0 - W) of - {ok, Log} -> Log; - _assert_fail -> - erlang:error(#{gleam_error => let_assert, - message => <<"Pattern match failed, no pattern matched the value."/utf8>>, - file => <>, - module => <<"gleam/list"/utf8>>, - function => <<"sample_loop"/utf8>>, - line => 2374, - value => _assert_fail, - start => 55639, - 'end' => 55685, - pattern_start => 55650, - pattern_end => 55657}) - end, - erlang:round(math:floor(case Log@1 of - +0.0 -> +0.0; - -0.0 -> -0.0; - Gleam@denominator -> log_random() / Gleam@denominator - end)) - end, - case drop(List, Skip) of - [] -> - Reservoir; - - [First | Rest] -> - Reservoir@1 = gleam@dict:insert( - Reservoir, - gleam@int:random(N), - First - ), - W@1 = W * math:exp(case erlang:float(N) of - +0.0 -> +0.0; - -0.0 -> -0.0; - Gleam@denominator@1 -> log_random() / Gleam@denominator@1 - end), - sample_loop(Rest, Reservoir@1, N, W@1) - end. - --file("src/gleam/list.gleam", 2349). -?DOC( - " Returns a random sample of up to n elements from a list using reservoir\n" - " sampling via [Algorithm L](https://en.wikipedia.org/wiki/Reservoir_sampling#Optimal:_Algorithm_L).\n" - " Returns an empty list if the sample size is less than or equal to 0.\n" - "\n" - " Order is not random, only selection is.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " reservoir_sample([1, 2, 3, 4, 5], 3)\n" - " // -> [2, 4, 5] // A random sample of 3 items\n" - " ```\n" -). --spec sample(list(ARX), integer()) -> list(ARX). -sample(List, N) -> - {Reservoir, Rest} = build_reservoir(List, N), - case gleam@dict:is_empty(Reservoir) of - true -> - []; - - false -> - W = math:exp(case erlang:float(N) of - +0.0 -> +0.0; - -0.0 -> -0.0; - Gleam@denominator -> log_random() / Gleam@denominator - end), - maps:values(sample_loop(Rest, Reservoir, N, W)) - end. - --file("src/gleam/list.gleam", 1851). --spec permutation_zip(list(AMT), list(AMT), list(list(AMT))) -> list(list(AMT)). -permutation_zip(List, Rest, Acc) -> - case List of - [] -> - lists:reverse(Acc); - - [Head | Tail] -> - permutation_prepend( - Head, - permutations(lists:reverse(Rest, Tail)), - Tail, - [Head | Rest], - Acc - ) - end. - --file("src/gleam/list.gleam", 1869). --spec permutation_prepend( - ANA, - list(list(ANA)), - list(ANA), - list(ANA), - list(list(ANA)) -) -> list(list(ANA)). -permutation_prepend(El, Permutations, List_1, List_2, Acc) -> - case Permutations of - [] -> - permutation_zip(List_1, List_2, Acc); - - [Head | Tail] -> - permutation_prepend(El, Tail, List_1, List_2, [[El | Head] | Acc]) - end. - --file("src/gleam/list.gleam", 1844). -?DOC( - " Returns all the permutations of a list.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " permutations([1, 2])\n" - " // -> [[1, 2], [2, 1]]\n" - " ```\n" -). --spec permutations(list(AMP)) -> list(list(AMP)). -permutations(List) -> - case List of - [] -> - [[]]; - - L -> - permutation_zip(L, [], []) - end. diff --git a/build/packages/gleam_stdlib/src/gleam@option.erl b/build/packages/gleam_stdlib/src/gleam@option.erl deleted file mode 100644 index 8e86a8e..0000000 --- a/build/packages/gleam_stdlib/src/gleam@option.erl +++ /dev/null @@ -1,413 +0,0 @@ --module(gleam@option). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "src/gleam/option.gleam"). --export([all/1, is_some/1, is_none/1, to_result/2, from_result/1, unwrap/2, lazy_unwrap/2, map/2, flatten/1, then/2, 'or'/2, lazy_or/2, values/1]). --export_type([option/1]). - --if(?OTP_RELEASE >= 27). --define(MODULEDOC(Str), -moduledoc(Str)). --define(DOC(Str), -doc(Str)). --else. --define(MODULEDOC(Str), -compile([])). --define(DOC(Str), -compile([])). --endif. - --type option(FG) :: {some, FG} | none. - --file("src/gleam/option.gleam", 59). --spec reverse_and_prepend(list(FV), list(FV)) -> list(FV). -reverse_and_prepend(Prefix, Suffix) -> - case Prefix of - [] -> - Suffix; - - [First | Rest] -> - reverse_and_prepend(Rest, [First | Suffix]) - end. - --file("src/gleam/option.gleam", 44). --spec all_loop(list(option(FM)), list(FM)) -> option(list(FM)). -all_loop(List, Acc) -> - case List of - [] -> - {some, lists:reverse(Acc)}; - - [none | _] -> - none; - - [{some, First} | Rest] -> - all_loop(Rest, [First | Acc]) - end. - --file("src/gleam/option.gleam", 40). -?DOC( - " Combines a list of `Option`s into a single `Option`.\n" - " If all elements in the list are `Some` then returns a `Some` holding the list of values.\n" - " If any element is `None` then returns`None`.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " all([Some(1), Some(2)])\n" - " // -> Some([1, 2])\n" - " ```\n" - "\n" - " ```gleam\n" - " all([Some(1), None])\n" - " // -> None\n" - " ```\n" -). --spec all(list(option(FH))) -> option(list(FH)). -all(List) -> - all_loop(List, []). - --file("src/gleam/option.gleam", 80). -?DOC( - " Checks whether the `Option` is a `Some` value.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " is_some(Some(1))\n" - " // -> True\n" - " ```\n" - "\n" - " ```gleam\n" - " is_some(None)\n" - " // -> False\n" - " ```\n" -). --spec is_some(option(any())) -> boolean(). -is_some(Option) -> - Option /= none. - --file("src/gleam/option.gleam", 98). -?DOC( - " Checks whether the `Option` is a `None` value.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " is_none(Some(1))\n" - " // -> False\n" - " ```\n" - "\n" - " ```gleam\n" - " is_none(None)\n" - " // -> True\n" - " ```\n" -). --spec is_none(option(any())) -> boolean(). -is_none(Option) -> - Option =:= none. - --file("src/gleam/option.gleam", 116). -?DOC( - " Converts an `Option` type to a `Result` type.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " to_result(Some(1), \"some_error\")\n" - " // -> Ok(1)\n" - " ```\n" - "\n" - " ```gleam\n" - " to_result(None, \"some_error\")\n" - " // -> Error(\"some_error\")\n" - " ```\n" -). --spec to_result(option(GD), GG) -> {ok, GD} | {error, GG}. -to_result(Option, E) -> - case Option of - {some, A} -> - {ok, A}; - - none -> - {error, E} - end. - --file("src/gleam/option.gleam", 137). -?DOC( - " Converts a `Result` type to an `Option` type.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " from_result(Ok(1))\n" - " // -> Some(1)\n" - " ```\n" - "\n" - " ```gleam\n" - " from_result(Error(\"some_error\"))\n" - " // -> None\n" - " ```\n" -). --spec from_result({ok, GJ} | {error, any()}) -> option(GJ). -from_result(Result) -> - case Result of - {ok, A} -> - {some, A}; - - {error, _} -> - none - end. - --file("src/gleam/option.gleam", 158). -?DOC( - " Extracts the value from an `Option`, returning a default value if there is none.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " unwrap(Some(1), 0)\n" - " // -> 1\n" - " ```\n" - "\n" - " ```gleam\n" - " unwrap(None, 0)\n" - " // -> 0\n" - " ```\n" -). --spec unwrap(option(GO), GO) -> GO. -unwrap(Option, Default) -> - case Option of - {some, X} -> - X; - - none -> - Default - end. - --file("src/gleam/option.gleam", 179). -?DOC( - " Extracts the value from an `Option`, evaluating the default function if the option is `None`.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " lazy_unwrap(Some(1), fn() { 0 })\n" - " // -> 1\n" - " ```\n" - "\n" - " ```gleam\n" - " lazy_unwrap(None, fn() { 0 })\n" - " // -> 0\n" - " ```\n" -). --spec lazy_unwrap(option(GQ), fun(() -> GQ)) -> GQ. -lazy_unwrap(Option, Default) -> - case Option of - {some, X} -> - X; - - none -> - Default() - end. - --file("src/gleam/option.gleam", 204). -?DOC( - " Updates a value held within the `Some` of an `Option` by calling a given function\n" - " on it.\n" - "\n" - " If the `Option` is a `None` rather than `Some`, the function is not called and the\n" - " `Option` stays the same.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " map(over: Some(1), with: fn(x) { x + 1 })\n" - " // -> Some(2)\n" - " ```\n" - "\n" - " ```gleam\n" - " map(over: None, with: fn(x) { x + 1 })\n" - " // -> None\n" - " ```\n" -). --spec map(option(GS), fun((GS) -> GU)) -> option(GU). -map(Option, Fun) -> - case Option of - {some, X} -> - {some, Fun(X)}; - - none -> - none - end. - --file("src/gleam/option.gleam", 230). -?DOC( - " Merges a nested `Option` into a single layer.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " flatten(Some(Some(1)))\n" - " // -> Some(1)\n" - " ```\n" - "\n" - " ```gleam\n" - " flatten(Some(None))\n" - " // -> None\n" - " ```\n" - "\n" - " ```gleam\n" - " flatten(None)\n" - " // -> None\n" - " ```\n" -). --spec flatten(option(option(GW))) -> option(GW). -flatten(Option) -> - case Option of - {some, X} -> - X; - - none -> - none - end. - --file("src/gleam/option.gleam", 269). -?DOC( - " Updates a value held within the `Some` of an `Option` by calling a given function\n" - " on it, where the given function also returns an `Option`. The two options are\n" - " then merged together into one `Option`.\n" - "\n" - " If the `Option` is a `None` rather than `Some` the function is not called and the\n" - " option stays the same.\n" - "\n" - " This function is the equivalent of calling `map` followed by `flatten`, and\n" - " it is useful for chaining together multiple functions that return `Option`.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " then(Some(1), fn(x) { Some(x + 1) })\n" - " // -> Some(2)\n" - " ```\n" - "\n" - " ```gleam\n" - " then(Some(1), fn(x) { Some(#(\"a\", x)) })\n" - " // -> Some(#(\"a\", 1))\n" - " ```\n" - "\n" - " ```gleam\n" - " then(Some(1), fn(_) { None })\n" - " // -> None\n" - " ```\n" - "\n" - " ```gleam\n" - " then(None, fn(x) { Some(x + 1) })\n" - " // -> None\n" - " ```\n" -). --spec then(option(HA), fun((HA) -> option(HC))) -> option(HC). -then(Option, Fun) -> - case Option of - {some, X} -> - Fun(X); - - none -> - none - end. - --file("src/gleam/option.gleam", 300). -?DOC( - " Returns the first value if it is `Some`, otherwise returns the second value.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " or(Some(1), Some(2))\n" - " // -> Some(1)\n" - " ```\n" - "\n" - " ```gleam\n" - " or(Some(1), None)\n" - " // -> Some(1)\n" - " ```\n" - "\n" - " ```gleam\n" - " or(None, Some(2))\n" - " // -> Some(2)\n" - " ```\n" - "\n" - " ```gleam\n" - " or(None, None)\n" - " // -> None\n" - " ```\n" -). --spec 'or'(option(HF), option(HF)) -> option(HF). -'or'(First, Second) -> - case First of - {some, _} -> - First; - - none -> - Second - end. - --file("src/gleam/option.gleam", 331). -?DOC( - " Returns the first value if it is `Some`, otherwise evaluates the given function for a fallback value.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " lazy_or(Some(1), fn() { Some(2) })\n" - " // -> Some(1)\n" - " ```\n" - "\n" - " ```gleam\n" - " lazy_or(Some(1), fn() { None })\n" - " // -> Some(1)\n" - " ```\n" - "\n" - " ```gleam\n" - " lazy_or(None, fn() { Some(2) })\n" - " // -> Some(2)\n" - " ```\n" - "\n" - " ```gleam\n" - " lazy_or(None, fn() { None })\n" - " // -> None\n" - " ```\n" -). --spec lazy_or(option(HJ), fun(() -> option(HJ))) -> option(HJ). -lazy_or(First, Second) -> - case First of - {some, _} -> - First; - - none -> - Second() - end. - --file("src/gleam/option.gleam", 352). --spec values_loop(list(option(HR)), list(HR)) -> list(HR). -values_loop(List, Acc) -> - case List of - [] -> - lists:reverse(Acc); - - [none | Rest] -> - values_loop(Rest, Acc); - - [{some, First} | Rest@1] -> - values_loop(Rest@1, [First | Acc]) - end. - --file("src/gleam/option.gleam", 348). -?DOC( - " Given a list of `Option`s,\n" - " returns only the values inside `Some`.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " values([Some(1), None, Some(3)])\n" - " // -> [1, 3]\n" - " ```\n" -). --spec values(list(option(HN))) -> list(HN). -values(Options) -> - values_loop(Options, []). diff --git a/build/packages/gleam_stdlib/src/gleam@order.erl b/build/packages/gleam_stdlib/src/gleam@order.erl deleted file mode 100644 index ec2bb84..0000000 --- a/build/packages/gleam_stdlib/src/gleam@order.erl +++ /dev/null @@ -1,200 +0,0 @@ --module(gleam@order). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "src/gleam/order.gleam"). --export([negate/1, to_int/1, compare/2, reverse/1, break_tie/2, lazy_break_tie/2]). --export_type([order/0]). - --if(?OTP_RELEASE >= 27). --define(MODULEDOC(Str), -moduledoc(Str)). --define(DOC(Str), -doc(Str)). --else. --define(MODULEDOC(Str), -compile([])). --define(DOC(Str), -compile([])). --endif. - --type order() :: lt | eq | gt. - --file("src/gleam/order.gleam", 35). -?DOC( - " Inverts an order, so less-than becomes greater-than and greater-than\n" - " becomes less-than.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " negate(Lt)\n" - " // -> Gt\n" - " ```\n" - "\n" - " ```gleam\n" - " negate(Eq)\n" - " // -> Eq\n" - " ```\n" - "\n" - " ```gleam\n" - " negate(Gt)\n" - " // -> Lt\n" - " ```\n" -). --spec negate(order()) -> order(). -negate(Order) -> - case Order of - lt -> - gt; - - eq -> - eq; - - gt -> - lt - end. - --file("src/gleam/order.gleam", 62). -?DOC( - " Produces a numeric representation of the order.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " to_int(Lt)\n" - " // -> -1\n" - " ```\n" - "\n" - " ```gleam\n" - " to_int(Eq)\n" - " // -> 0\n" - " ```\n" - "\n" - " ```gleam\n" - " to_int(Gt)\n" - " // -> 1\n" - " ```\n" -). --spec to_int(order()) -> integer(). -to_int(Order) -> - case Order of - lt -> - -1; - - eq -> - 0; - - gt -> - 1 - end. - --file("src/gleam/order.gleam", 79). -?DOC( - " Compares two `Order` values to one another, producing a new `Order`.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " compare(Eq, with: Lt)\n" - " // -> Gt\n" - " ```\n" -). --spec compare(order(), order()) -> order(). -compare(A, B) -> - case {A, B} of - {X, Y} when X =:= Y -> - eq; - - {lt, _} -> - lt; - - {eq, gt} -> - lt; - - {_, _} -> - gt - end. - --file("src/gleam/order.gleam", 100). -?DOC( - " Inverts an ordering function, so less-than becomes greater-than and greater-than\n" - " becomes less-than.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " import gleam/int\n" - " import gleam/list\n" - "\n" - " list.sort([1, 5, 4], by: reverse(int.compare))\n" - " // -> [5, 4, 1]\n" - " ```\n" -). --spec reverse(fun((I, I) -> order())) -> fun((I, I) -> order()). -reverse(Orderer) -> - fun(A, B) -> Orderer(B, A) end. - --file("src/gleam/order.gleam", 122). -?DOC( - " Return a fallback `Order` in case the first argument is `Eq`.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " import gleam/int\n" - "\n" - " break_tie(in: int.compare(1, 1), with: Lt)\n" - " // -> Lt\n" - " ```\n" - "\n" - " ```gleam\n" - " import gleam/int\n" - "\n" - " break_tie(in: int.compare(1, 0), with: Eq)\n" - " // -> Gt\n" - " ```\n" -). --spec break_tie(order(), order()) -> order(). -break_tie(Order, Other) -> - case Order of - lt -> - Order; - - gt -> - Order; - - eq -> - Other - end. - --file("src/gleam/order.gleam", 151). -?DOC( - " Invokes a fallback function returning an `Order` in case the first argument\n" - " is `Eq`.\n" - "\n" - " This can be useful when the fallback comparison might be expensive and it\n" - " needs to be delayed until strictly necessary.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " import gleam/int\n" - "\n" - " lazy_break_tie(in: int.compare(1, 1), with: fn() { Lt })\n" - " // -> Lt\n" - " ```\n" - "\n" - " ```gleam\n" - " import gleam/int\n" - "\n" - " lazy_break_tie(in: int.compare(1, 0), with: fn() { Eq })\n" - " // -> Gt\n" - " ```\n" -). --spec lazy_break_tie(order(), fun(() -> order())) -> order(). -lazy_break_tie(Order, Comparison) -> - case Order of - lt -> - Order; - - gt -> - Order; - - eq -> - Comparison() - end. diff --git a/build/packages/gleam_stdlib/src/gleam@pair.erl b/build/packages/gleam_stdlib/src/gleam@pair.erl deleted file mode 100644 index cb18264..0000000 --- a/build/packages/gleam_stdlib/src/gleam@pair.erl +++ /dev/null @@ -1,110 +0,0 @@ --module(gleam@pair). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "src/gleam/pair.gleam"). --export([first/1, second/1, swap/1, map_first/2, map_second/2, new/2]). - --if(?OTP_RELEASE >= 27). --define(MODULEDOC(Str), -moduledoc(Str)). --define(DOC(Str), -doc(Str)). --else. --define(MODULEDOC(Str), -compile([])). --define(DOC(Str), -compile([])). --endif. - --file("src/gleam/pair.gleam", 10). -?DOC( - " Returns the first element in a pair.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " first(#(1, 2))\n" - " // -> 1\n" - " ```\n" -). --spec first({CLF, any()}) -> CLF. -first(Pair) -> - {A, _} = Pair, - A. - --file("src/gleam/pair.gleam", 24). -?DOC( - " Returns the second element in a pair.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " second(#(1, 2))\n" - " // -> 2\n" - " ```\n" -). --spec second({any(), CLI}) -> CLI. -second(Pair) -> - {_, A} = Pair, - A. - --file("src/gleam/pair.gleam", 38). -?DOC( - " Returns a new pair with the elements swapped.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " swap(#(1, 2))\n" - " // -> #(2, 1)\n" - " ```\n" -). --spec swap({CLJ, CLK}) -> {CLK, CLJ}. -swap(Pair) -> - {A, B} = Pair, - {B, A}. - --file("src/gleam/pair.gleam", 53). -?DOC( - " Returns a new pair with the first element having had `with` applied to\n" - " it.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " #(1, 2) |> map_first(fn(n) { n * 2 })\n" - " // -> #(2, 2)\n" - " ```\n" -). --spec map_first({CLL, CLM}, fun((CLL) -> CLN)) -> {CLN, CLM}. -map_first(Pair, Fun) -> - {A, B} = Pair, - {Fun(A), B}. - --file("src/gleam/pair.gleam", 68). -?DOC( - " Returns a new pair with the second element having had `with` applied to\n" - " it.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " #(1, 2) |> map_second(fn(n) { n * 2 })\n" - " // -> #(1, 4)\n" - " ```\n" -). --spec map_second({CLO, CLP}, fun((CLP) -> CLQ)) -> {CLO, CLQ}. -map_second(Pair, Fun) -> - {A, B} = Pair, - {A, Fun(B)}. - --file("src/gleam/pair.gleam", 83). -?DOC( - " Returns a new pair with the given elements. This can also be done using the dedicated\n" - " syntax instead: `new(1, 2) == #(1, 2)`.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " new(1, 2)\n" - " // -> #(1, 2)\n" - " ```\n" -). --spec new(CLR, CLS) -> {CLR, CLS}. -new(First, Second) -> - {First, Second}. diff --git a/build/packages/gleam_stdlib/src/gleam@result.erl b/build/packages/gleam_stdlib/src/gleam@result.erl deleted file mode 100644 index 9d89ff7..0000000 --- a/build/packages/gleam_stdlib/src/gleam@result.erl +++ /dev/null @@ -1,550 +0,0 @@ --module(gleam@result). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "src/gleam/result.gleam"). --export([is_ok/1, is_error/1, map/2, map_error/2, flatten/1, 'try'/2, then/2, unwrap/2, lazy_unwrap/2, unwrap_error/2, unwrap_both/1, 'or'/2, lazy_or/2, all/1, partition/1, replace/2, replace_error/2, values/1, try_recover/2]). - --if(?OTP_RELEASE >= 27). --define(MODULEDOC(Str), -moduledoc(Str)). --define(DOC(Str), -doc(Str)). --else. --define(MODULEDOC(Str), -compile([])). --define(DOC(Str), -compile([])). --endif. - -?MODULEDOC( - " Result represents the result of something that may succeed or not.\n" - " `Ok` means it was successful, `Error` means it was not successful.\n" -). - --file("src/gleam/result.gleam", 20). -?DOC( - " Checks whether the result is an `Ok` value.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " is_ok(Ok(1))\n" - " // -> True\n" - " ```\n" - "\n" - " ```gleam\n" - " is_ok(Error(Nil))\n" - " // -> False\n" - " ```\n" -). --spec is_ok({ok, any()} | {error, any()}) -> boolean(). -is_ok(Result) -> - case Result of - {error, _} -> - false; - - {ok, _} -> - true - end. - --file("src/gleam/result.gleam", 41). -?DOC( - " Checks whether the result is an `Error` value.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " is_error(Ok(1))\n" - " // -> False\n" - " ```\n" - "\n" - " ```gleam\n" - " is_error(Error(Nil))\n" - " // -> True\n" - " ```\n" -). --spec is_error({ok, any()} | {error, any()}) -> boolean(). -is_error(Result) -> - case Result of - {ok, _} -> - false; - - {error, _} -> - true - end. - --file("src/gleam/result.gleam", 66). -?DOC( - " Updates a value held within the `Ok` of a result by calling a given function\n" - " on it.\n" - "\n" - " If the result is an `Error` rather than `Ok` the function is not called and the\n" - " result stays the same.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " map(over: Ok(1), with: fn(x) { x + 1 })\n" - " // -> Ok(2)\n" - " ```\n" - "\n" - " ```gleam\n" - " map(over: Error(1), with: fn(x) { x + 1 })\n" - " // -> Error(1)\n" - " ```\n" -). --spec map({ok, CMC} | {error, CMD}, fun((CMC) -> CMG)) -> {ok, CMG} | - {error, CMD}. -map(Result, Fun) -> - case Result of - {ok, X} -> - {ok, Fun(X)}; - - {error, E} -> - {error, E} - end. - --file("src/gleam/result.gleam", 91). -?DOC( - " Updates a value held within the `Error` of a result by calling a given function\n" - " on it.\n" - "\n" - " If the result is `Ok` rather than `Error` the function is not called and the\n" - " result stays the same.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " map_error(over: Error(1), with: fn(x) { x + 1 })\n" - " // -> Error(2)\n" - " ```\n" - "\n" - " ```gleam\n" - " map_error(over: Ok(1), with: fn(x) { x + 1 })\n" - " // -> Ok(1)\n" - " ```\n" -). --spec map_error({ok, CMJ} | {error, CMK}, fun((CMK) -> CMN)) -> {ok, CMJ} | - {error, CMN}. -map_error(Result, Fun) -> - case Result of - {ok, X} -> - {ok, X}; - - {error, Error} -> - {error, Fun(Error)} - end. - --file("src/gleam/result.gleam", 120). -?DOC( - " Merges a nested `Result` into a single layer.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " flatten(Ok(Ok(1)))\n" - " // -> Ok(1)\n" - " ```\n" - "\n" - " ```gleam\n" - " flatten(Ok(Error(\"\")))\n" - " // -> Error(\"\")\n" - " ```\n" - "\n" - " ```gleam\n" - " flatten(Error(Nil))\n" - " // -> Error(Nil)\n" - " ```\n" -). --spec flatten({ok, {ok, CMQ} | {error, CMR}} | {error, CMR}) -> {ok, CMQ} | - {error, CMR}. -flatten(Result) -> - case Result of - {ok, X} -> - X; - - {error, Error} -> - {error, Error} - end. - --file("src/gleam/result.gleam", 158). -?DOC( - " \"Updates\" an `Ok` result by passing its value to a function that yields a result,\n" - " and returning the yielded result. (This may \"replace\" the `Ok` with an `Error`.)\n" - "\n" - " If the input is an `Error` rather than an `Ok`, the function is not called and\n" - " the original `Error` is returned.\n" - "\n" - " This function is the equivalent of calling `map` followed by `flatten`, and\n" - " it is useful for chaining together multiple functions that may fail.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " try(Ok(1), fn(x) { Ok(x + 1) })\n" - " // -> Ok(2)\n" - " ```\n" - "\n" - " ```gleam\n" - " try(Ok(1), fn(x) { Ok(#(\"a\", x)) })\n" - " // -> Ok(#(\"a\", 1))\n" - " ```\n" - "\n" - " ```gleam\n" - " try(Ok(1), fn(_) { Error(\"Oh no\") })\n" - " // -> Error(\"Oh no\")\n" - " ```\n" - "\n" - " ```gleam\n" - " try(Error(Nil), fn(x) { Ok(x + 1) })\n" - " // -> Error(Nil)\n" - " ```\n" -). --spec 'try'({ok, CMY} | {error, CMZ}, fun((CMY) -> {ok, CNC} | {error, CMZ})) -> {ok, - CNC} | - {error, CMZ}. -'try'(Result, Fun) -> - case Result of - {ok, X} -> - Fun(X); - - {error, E} -> - {error, E} - end. - --file("src/gleam/result.gleam", 169). --spec then({ok, CNH} | {error, CNI}, fun((CNH) -> {ok, CNL} | {error, CNI})) -> {ok, - CNL} | - {error, CNI}. -then(Result, Fun) -> - 'try'(Result, Fun). - --file("src/gleam/result.gleam", 191). -?DOC( - " Extracts the `Ok` value from a result, returning a default value if the result\n" - " is an `Error`.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " unwrap(Ok(1), 0)\n" - " // -> 1\n" - " ```\n" - "\n" - " ```gleam\n" - " unwrap(Error(\"\"), 0)\n" - " // -> 0\n" - " ```\n" -). --spec unwrap({ok, CNQ} | {error, any()}, CNQ) -> CNQ. -unwrap(Result, Default) -> - case Result of - {ok, V} -> - V; - - {error, _} -> - Default - end. - --file("src/gleam/result.gleam", 213). -?DOC( - " Extracts the `Ok` value from a result, evaluating the default function if the result\n" - " is an `Error`.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " lazy_unwrap(Ok(1), fn() { 0 })\n" - " // -> 1\n" - " ```\n" - "\n" - " ```gleam\n" - " lazy_unwrap(Error(\"\"), fn() { 0 })\n" - " // -> 0\n" - " ```\n" -). --spec lazy_unwrap({ok, CNU} | {error, any()}, fun(() -> CNU)) -> CNU. -lazy_unwrap(Result, Default) -> - case Result of - {ok, V} -> - V; - - {error, _} -> - Default() - end. - --file("src/gleam/result.gleam", 235). -?DOC( - " Extracts the `Error` value from a result, returning a default value if the result\n" - " is an `Ok`.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " unwrap_error(Error(1), 0)\n" - " // -> 1\n" - " ```\n" - "\n" - " ```gleam\n" - " unwrap_error(Ok(\"\"), 0)\n" - " // -> 0\n" - " ```\n" -). --spec unwrap_error({ok, any()} | {error, CNZ}, CNZ) -> CNZ. -unwrap_error(Result, Default) -> - case Result of - {ok, _} -> - Default; - - {error, E} -> - E - end. - --file("src/gleam/result.gleam", 243). --spec unwrap_both({ok, COC} | {error, COC}) -> COC. -unwrap_both(Result) -> - case Result of - {ok, A} -> - A; - - {error, A@1} -> - A@1 - end. - --file("src/gleam/result.gleam", 274). -?DOC( - " Returns the first value if it is `Ok`, otherwise returns the second value.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " or(Ok(1), Ok(2))\n" - " // -> Ok(1)\n" - " ```\n" - "\n" - " ```gleam\n" - " or(Ok(1), Error(\"Error 2\"))\n" - " // -> Ok(1)\n" - " ```\n" - "\n" - " ```gleam\n" - " or(Error(\"Error 1\"), Ok(2))\n" - " // -> Ok(2)\n" - " ```\n" - "\n" - " ```gleam\n" - " or(Error(\"Error 1\"), Error(\"Error 2\"))\n" - " // -> Error(\"Error 2\")\n" - " ```\n" -). --spec 'or'({ok, COF} | {error, COG}, {ok, COF} | {error, COG}) -> {ok, COF} | - {error, COG}. -'or'(First, Second) -> - case First of - {ok, _} -> - First; - - {error, _} -> - Second - end. - --file("src/gleam/result.gleam", 307). -?DOC( - " Returns the first value if it is `Ok`, otherwise evaluates the given function for a fallback value.\n" - "\n" - " If you need access to the initial error value, use `result.try_recover`.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " lazy_or(Ok(1), fn() { Ok(2) })\n" - " // -> Ok(1)\n" - " ```\n" - "\n" - " ```gleam\n" - " lazy_or(Ok(1), fn() { Error(\"Error 2\") })\n" - " // -> Ok(1)\n" - " ```\n" - "\n" - " ```gleam\n" - " lazy_or(Error(\"Error 1\"), fn() { Ok(2) })\n" - " // -> Ok(2)\n" - " ```\n" - "\n" - " ```gleam\n" - " lazy_or(Error(\"Error 1\"), fn() { Error(\"Error 2\") })\n" - " // -> Error(\"Error 2\")\n" - " ```\n" -). --spec lazy_or({ok, CON} | {error, COO}, fun(() -> {ok, CON} | {error, COO})) -> {ok, - CON} | - {error, COO}. -lazy_or(First, Second) -> - case First of - {ok, _} -> - First; - - {error, _} -> - Second() - end. - --file("src/gleam/result.gleam", 333). -?DOC( - " Combines a list of results into a single result.\n" - " If all elements in the list are `Ok` then returns an `Ok` holding the list of values.\n" - " If any element is `Error` then returns the first error.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " all([Ok(1), Ok(2)])\n" - " // -> Ok([1, 2])\n" - " ```\n" - "\n" - " ```gleam\n" - " all([Ok(1), Error(\"e\")])\n" - " // -> Error(\"e\")\n" - " ```\n" -). --spec all(list({ok, COV} | {error, COW})) -> {ok, list(COV)} | {error, COW}. -all(Results) -> - gleam@list:try_map(Results, fun(Result) -> Result end). - --file("src/gleam/result.gleam", 353). --spec partition_loop(list({ok, CPK} | {error, CPL}), list(CPK), list(CPL)) -> {list(CPK), - list(CPL)}. -partition_loop(Results, Oks, Errors) -> - case Results of - [] -> - {Oks, Errors}; - - [{ok, A} | Rest] -> - partition_loop(Rest, [A | Oks], Errors); - - [{error, E} | Rest@1] -> - partition_loop(Rest@1, Oks, [E | Errors]) - end. - --file("src/gleam/result.gleam", 349). -?DOC( - " Given a list of results, returns a pair where the first element is a list\n" - " of all the values inside `Ok` and the second element is a list with all the\n" - " values inside `Error`. The values in both lists appear in reverse order with\n" - " respect to their position in the original list of results.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " partition([Ok(1), Error(\"a\"), Error(\"b\"), Ok(2)])\n" - " // -> #([2, 1], [\"b\", \"a\"])\n" - " ```\n" -). --spec partition(list({ok, CPD} | {error, CPE})) -> {list(CPD), list(CPE)}. -partition(Results) -> - partition_loop(Results, [], []). - --file("src/gleam/result.gleam", 375). -?DOC( - " Replace the value within a result\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " replace(Ok(1), Nil)\n" - " // -> Ok(Nil)\n" - " ```\n" - "\n" - " ```gleam\n" - " replace(Error(1), Nil)\n" - " // -> Error(1)\n" - " ```\n" -). --spec replace({ok, any()} | {error, CPT}, CPW) -> {ok, CPW} | {error, CPT}. -replace(Result, Value) -> - case Result of - {ok, _} -> - {ok, Value}; - - {error, Error} -> - {error, Error} - end. - --file("src/gleam/result.gleam", 396). -?DOC( - " Replace the error within a result\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " replace_error(Error(1), Nil)\n" - " // -> Error(Nil)\n" - " ```\n" - "\n" - " ```gleam\n" - " replace_error(Ok(1), Nil)\n" - " // -> Ok(1)\n" - " ```\n" -). --spec replace_error({ok, CPZ} | {error, any()}, CQD) -> {ok, CPZ} | {error, CQD}. -replace_error(Result, Error) -> - case Result of - {ok, X} -> - {ok, X}; - - {error, _} -> - {error, Error} - end. - --file("src/gleam/result.gleam", 412). -?DOC( - " Given a list of results, returns only the values inside `Ok`.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " values([Ok(1), Error(\"a\"), Ok(3)])\n" - " // -> [1, 3]\n" - " ```\n" -). --spec values(list({ok, CQG} | {error, any()})) -> list(CQG). -values(Results) -> - gleam@list:filter_map(Results, fun(Result) -> Result end). - --file("src/gleam/result.gleam", 445). -?DOC( - " Updates a value held within the `Error` of a result by calling a given function\n" - " on it, where the given function also returns a result. The two results are\n" - " then merged together into one result.\n" - "\n" - " If the result is an `Ok` rather than `Error` the function is not called and the\n" - " result stays the same.\n" - "\n" - " This function is useful for chaining together computations that may fail\n" - " and trying to recover from possible errors.\n" - "\n" - " If you do not need access to the initial error value, use `result.lazy_or`.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " Ok(1) |> try_recover(with: fn(_) { Error(\"failed to recover\") })\n" - " // -> Ok(1)\n" - " ```\n" - "\n" - " ```gleam\n" - " Error(1) |> try_recover(with: fn(error) { Ok(error + 1) })\n" - " // -> Ok(2)\n" - " ```\n" - "\n" - " ```gleam\n" - " Error(1) |> try_recover(with: fn(error) { Error(\"failed to recover\") })\n" - " // -> Error(\"failed to recover\")\n" - " ```\n" -). --spec try_recover( - {ok, CQM} | {error, CQN}, - fun((CQN) -> {ok, CQM} | {error, CQQ}) -) -> {ok, CQM} | {error, CQQ}. -try_recover(Result, Fun) -> - case Result of - {ok, Value} -> - {ok, Value}; - - {error, Error} -> - Fun(Error) - end. diff --git a/build/packages/gleam_stdlib/src/gleam@set.erl b/build/packages/gleam_stdlib/src/gleam@set.erl deleted file mode 100644 index bb3c417..0000000 --- a/build/packages/gleam_stdlib/src/gleam@set.erl +++ /dev/null @@ -1,429 +0,0 @@ --module(gleam@set). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "src/gleam/set.gleam"). --export([new/0, size/1, is_empty/1, contains/2, delete/2, to_list/1, fold/3, filter/2, drop/2, take/2, intersection/2, difference/2, is_subset/2, is_disjoint/2, each/2, insert/2, from_list/1, map/2, union/2, symmetric_difference/2]). --export_type([set/1]). - --if(?OTP_RELEASE >= 27). --define(MODULEDOC(Str), -moduledoc(Str)). --define(DOC(Str), -doc(Str)). --else. --define(MODULEDOC(Str), -compile([])). --define(DOC(Str), -compile([])). --endif. - --opaque set(CVL) :: {set, gleam@dict:dict(CVL, list(nil))}. - --file("src/gleam/set.gleam", 32). -?DOC(" Creates a new empty set.\n"). --spec new() -> set(any()). -new() -> - {set, maps:new()}. - --file("src/gleam/set.gleam", 50). -?DOC( - " Gets the number of members in a set.\n" - "\n" - " This function runs in constant time.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " new()\n" - " |> insert(1)\n" - " |> insert(2)\n" - " |> size\n" - " // -> 2\n" - " ```\n" -). --spec size(set(any())) -> integer(). -size(Set) -> - maps:size(erlang:element(2, Set)). - --file("src/gleam/set.gleam", 68). -?DOC( - " Determines whether or not the set is empty.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " new() |> is_empty\n" - " // -> True\n" - " ```\n" - "\n" - " ```gleam\n" - " new() |> insert(1) |> is_empty\n" - " // -> False\n" - " ```\n" -). --spec is_empty(set(any())) -> boolean(). -is_empty(Set) -> - Set =:= new(). - --file("src/gleam/set.gleam", 110). -?DOC( - " Checks whether a set contains a given member.\n" - "\n" - " This function runs in logarithmic time.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " new()\n" - " |> insert(2)\n" - " |> contains(2)\n" - " // -> True\n" - " ```\n" - "\n" - " ```gleam\n" - " new()\n" - " |> insert(2)\n" - " |> contains(1)\n" - " // -> False\n" - " ```\n" -). --spec contains(set(CVW), CVW) -> boolean(). -contains(Set, Member) -> - _pipe = erlang:element(2, Set), - _pipe@1 = gleam_stdlib:map_get(_pipe, Member), - gleam@result:is_ok(_pipe@1). - --file("src/gleam/set.gleam", 131). -?DOC( - " Removes a member from a set. If the set does not contain the member then\n" - " the set is returned unchanged.\n" - "\n" - " This function runs in logarithmic time.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " new()\n" - " |> insert(2)\n" - " |> delete(2)\n" - " |> contains(1)\n" - " // -> False\n" - " ```\n" -). --spec delete(set(CVY), CVY) -> set(CVY). -delete(Set, Member) -> - {set, gleam@dict:delete(erlang:element(2, Set), Member)}. - --file("src/gleam/set.gleam", 149). -?DOC( - " Converts the set into a list of the contained members.\n" - "\n" - " The list has no specific ordering, any unintentional ordering may change in\n" - " future versions of Gleam or Erlang.\n" - "\n" - " This function runs in linear time.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " new() |> insert(2) |> to_list\n" - " // -> [2]\n" - " ```\n" -). --spec to_list(set(CWB)) -> list(CWB). -to_list(Set) -> - maps:keys(erlang:element(2, Set)). - --file("src/gleam/set.gleam", 190). -?DOC( - " Combines all entries into a single value by calling a given function on each\n" - " one.\n" - "\n" - " Sets are not ordered so the values are not returned in any specific order.\n" - " Do not write code that relies on the order entries are used by this\n" - " function as it may change in later versions of Gleam or Erlang.\n" - "\n" - " # Examples\n" - "\n" - " ```gleam\n" - " from_list([1, 3, 9])\n" - " |> fold(0, fn(accumulator, member) { accumulator + member })\n" - " // -> 13\n" - " ```\n" -). --spec fold(set(CWH), CWJ, fun((CWJ, CWH) -> CWJ)) -> CWJ. -fold(Set, Initial, Reducer) -> - gleam@dict:fold( - erlang:element(2, Set), - Initial, - fun(A, K, _) -> Reducer(A, K) end - ). - --file("src/gleam/set.gleam", 214). -?DOC( - " Creates a new set from an existing set, minus any members that a given\n" - " function returns `False` for.\n" - "\n" - " This function runs in loglinear time.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " import gleam/int\n" - "\n" - " from_list([1, 4, 6, 3, 675, 44, 67])\n" - " |> filter(keeping: int.is_even)\n" - " |> to_list\n" - " // -> [4, 6, 44]\n" - " ```\n" -). --spec filter(set(CWK), fun((CWK) -> boolean())) -> set(CWK). -filter(Set, Predicate) -> - {set, - gleam@dict:filter(erlang:element(2, Set), fun(M, _) -> Predicate(M) end)}. - --file("src/gleam/set.gleam", 249). -?DOC( - " Creates a new set from a given set with all the same entries except any\n" - " entry found on the given list.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " from_list([1, 2, 3, 4])\n" - " |> drop([1, 3])\n" - " |> to_list\n" - " // -> [2, 4]\n" - " ```\n" -). --spec drop(set(CWR), list(CWR)) -> set(CWR). -drop(Set, Disallowed) -> - gleam@list:fold(Disallowed, Set, fun delete/2). - --file("src/gleam/set.gleam", 267). -?DOC( - " Creates a new set from a given set, only including any members which are in\n" - " a given list.\n" - "\n" - " This function runs in loglinear time.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " from_list([1, 2, 3])\n" - " |> take([1, 3, 5])\n" - " |> to_list\n" - " // -> [1, 3]\n" - " ```\n" -). --spec take(set(CWV), list(CWV)) -> set(CWV). -take(Set, Desired) -> - {set, gleam@dict:take(erlang:element(2, Set), Desired)}. - --file("src/gleam/set.gleam", 287). --spec order(set(CXD), set(CXD)) -> {set(CXD), set(CXD)}. -order(First, Second) -> - case maps:size(erlang:element(2, First)) > maps:size( - erlang:element(2, Second) - ) of - true -> - {First, Second}; - - false -> - {Second, First} - end. - --file("src/gleam/set.gleam", 305). -?DOC( - " Creates a new set that contains members that are present in both given sets.\n" - "\n" - " This function runs in loglinear time.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " intersection(from_list([1, 2]), from_list([2, 3])) |> to_list\n" - " // -> [2]\n" - " ```\n" -). --spec intersection(set(CXI), set(CXI)) -> set(CXI). -intersection(First, Second) -> - {Larger, Smaller} = order(First, Second), - take(Larger, to_list(Smaller)). - --file("src/gleam/set.gleam", 323). -?DOC( - " Creates a new set that contains members that are present in the first set\n" - " but not the second.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " difference(from_list([1, 2]), from_list([2, 3, 4])) |> to_list\n" - " // -> [1]\n" - " ```\n" -). --spec difference(set(CXM), set(CXM)) -> set(CXM). -difference(First, Second) -> - drop(First, to_list(Second)). - --file("src/gleam/set.gleam", 344). -?DOC( - " Determines if a set is fully contained by another.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " is_subset(from_list([1]), from_list([1, 2]))\n" - " // -> True\n" - " ```\n" - "\n" - " ```gleam\n" - " is_subset(from_list([1, 2, 3]), from_list([3, 4, 5]))\n" - " // -> False\n" - " ```\n" -). --spec is_subset(set(CXQ), set(CXQ)) -> boolean(). -is_subset(First, Second) -> - intersection(First, Second) =:= First. - --file("src/gleam/set.gleam", 362). -?DOC( - " Determines if two sets contain no common members\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " is_disjoint(from_list([1, 2, 3]), from_list([4, 5, 6]))\n" - " // -> True\n" - " ```\n" - "\n" - " ```gleam\n" - " is_disjoint(from_list([1, 2, 3]), from_list([3, 4, 5]))\n" - " // -> False\n" - " ```\n" -). --spec is_disjoint(set(CXT), set(CXT)) -> boolean(). -is_disjoint(First, Second) -> - intersection(First, Second) =:= new(). - --file("src/gleam/set.gleam", 402). -?DOC( - " Calls a function for each member in a set, discarding the return\n" - " value.\n" - "\n" - " Useful for producing a side effect for every item of a set.\n" - "\n" - " ```gleam\n" - " let set = from_list([\"apple\", \"banana\", \"cherry\"])\n" - "\n" - " each(set, io.println)\n" - " // -> Nil\n" - " // apple\n" - " // banana\n" - " // cherry\n" - " ```\n" - "\n" - " The order of elements in the iteration is an implementation detail that\n" - " should not be relied upon.\n" -). --spec each(set(CYA), fun((CYA) -> any())) -> nil. -each(Set, Fun) -> - fold( - Set, - nil, - fun(Nil, Member) -> - Fun(Member), - Nil - end - ). - --file("src/gleam/set.gleam", 86). -?DOC( - " Inserts an member into the set.\n" - "\n" - " This function runs in logarithmic time.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " new()\n" - " |> insert(1)\n" - " |> insert(2)\n" - " |> size\n" - " // -> 2\n" - " ```\n" -). --spec insert(set(CVT), CVT) -> set(CVT). -insert(Set, Member) -> - {set, gleam@dict:insert(erlang:element(2, Set), Member, [])}. - --file("src/gleam/set.gleam", 167). -?DOC( - " Creates a new set of the members in a given list.\n" - "\n" - " This function runs in loglinear time.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " import gleam/int\n" - " import gleam/list\n" - "\n" - " [1, 1, 2, 4, 3, 2] |> from_list |> to_list |> list.sort(by: int.compare)\n" - " // -> [1, 2, 3, 4]\n" - " ```\n" -). --spec from_list(list(CWE)) -> set(CWE). -from_list(Members) -> - Dict = gleam@list:fold( - Members, - maps:new(), - fun(M, K) -> gleam@dict:insert(M, K, []) end - ), - {set, Dict}. - --file("src/gleam/set.gleam", 232). -?DOC( - " Creates a new set from a given set with the result of applying the given\n" - " function to each member.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " from_list([1, 2, 3, 4])\n" - " |> map(with: fn(x) { x * 2 })\n" - " |> to_list\n" - " // -> [2, 4, 6, 8]\n" - " ```\n" -). --spec map(set(CWN), fun((CWN) -> CWP)) -> set(CWP). -map(Set, Fun) -> - fold(Set, new(), fun(Acc, Member) -> insert(Acc, Fun(Member)) end). - --file("src/gleam/set.gleam", 282). -?DOC( - " Creates a new set that contains all members of both given sets.\n" - "\n" - " This function runs in loglinear time.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " union(from_list([1, 2]), from_list([2, 3])) |> to_list\n" - " // -> [1, 2, 3]\n" - " ```\n" -). --spec union(set(CWZ), set(CWZ)) -> set(CWZ). -union(First, Second) -> - {Larger, Smaller} = order(First, Second), - fold(Smaller, Larger, fun insert/2). - --file("src/gleam/set.gleam", 374). -?DOC( - " Creates a new set that contains members that are present in either set, but\n" - " not both.\n" - "\n" - " ```gleam\n" - " symmetric_difference(from_list([1, 2, 3]), from_list([3, 4])) |> to_list\n" - " // -> [1, 2, 4]\n" - " ```\n" -). --spec symmetric_difference(set(CXW), set(CXW)) -> set(CXW). -symmetric_difference(First, Second) -> - difference(union(First, Second), intersection(First, Second)). diff --git a/build/packages/gleam_stdlib/src/gleam@string.erl b/build/packages/gleam_stdlib/src/gleam@string.erl deleted file mode 100644 index 63006b8..0000000 --- a/build/packages/gleam_stdlib/src/gleam@string.erl +++ /dev/null @@ -1,1012 +0,0 @@ --module(gleam@string). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "src/gleam/string.gleam"). --export([is_empty/1, length/1, reverse/1, replace/3, lowercase/1, uppercase/1, compare/2, slice/3, crop/2, drop_end/2, contains/2, starts_with/2, ends_with/2, split_once/2, append/2, concat/1, repeat/2, join/2, pad_start/3, pad_end/3, trim_start/1, trim_end/1, trim/1, pop_grapheme/1, to_graphemes/1, split/2, to_utf_codepoints/1, from_utf_codepoints/1, utf_codepoint/1, utf_codepoint_to_int/1, to_option/1, first/1, last/1, capitalise/1, inspect/1, byte_size/1, drop_start/2]). --export_type([direction/0]). - --if(?OTP_RELEASE >= 27). --define(MODULEDOC(Str), -moduledoc(Str)). --define(DOC(Str), -doc(Str)). --else. --define(MODULEDOC(Str), -compile([])). --define(DOC(Str), -compile([])). --endif. - -?MODULEDOC( - " Strings in Gleam are UTF-8 binaries. They can be written in your code as\n" - " text surrounded by `\"double quotes\"`.\n" -). - --type direction() :: leading | trailing. - --file("src/gleam/string.gleam", 23). -?DOC( - " Determines if a `String` is empty.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " is_empty(\"\")\n" - " // -> True\n" - " ```\n" - "\n" - " ```gleam\n" - " is_empty(\"the world\")\n" - " // -> False\n" - " ```\n" -). --spec is_empty(binary()) -> boolean(). -is_empty(Str) -> - Str =:= <<""/utf8>>. - --file("src/gleam/string.gleam", 51). -?DOC( - " Gets the number of grapheme clusters in a given `String`.\n" - "\n" - " This function has to iterate across the whole string to count the number of\n" - " graphemes, so it runs in linear time. Avoid using this in a loop.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " length(\"Gleam\")\n" - " // -> 5\n" - " ```\n" - "\n" - " ```gleam\n" - " length(\"ß↑e̊\")\n" - " // -> 3\n" - " ```\n" - "\n" - " ```gleam\n" - " length(\"\")\n" - " // -> 0\n" - " ```\n" -). --spec length(binary()) -> integer(). -length(String) -> - string:length(String). - --file("src/gleam/string.gleam", 65). -?DOC( - " Reverses a `String`.\n" - "\n" - " This function has to iterate across the whole `String` so it runs in linear\n" - " time. Avoid using this in a loop.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " reverse(\"stressed\")\n" - " // -> \"desserts\"\n" - " ```\n" -). --spec reverse(binary()) -> binary(). -reverse(String) -> - _pipe = String, - _pipe@1 = gleam_stdlib:identity(_pipe), - _pipe@2 = string:reverse(_pipe@1), - unicode:characters_to_binary(_pipe@2). - --file("src/gleam/string.gleam", 86). -?DOC( - " Creates a new `String` by replacing all occurrences of a given substring.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " replace(\"www.example.com\", each: \".\", with: \"-\")\n" - " // -> \"www-example-com\"\n" - " ```\n" - "\n" - " ```gleam\n" - " replace(\"a,b,c,d,e\", each: \",\", with: \"/\")\n" - " // -> \"a/b/c/d/e\"\n" - " ```\n" -). --spec replace(binary(), binary(), binary()) -> binary(). -replace(String, Pattern, Substitute) -> - _pipe = String, - _pipe@1 = gleam_stdlib:identity(_pipe), - _pipe@2 = gleam_stdlib:string_replace(_pipe@1, Pattern, Substitute), - unicode:characters_to_binary(_pipe@2). - --file("src/gleam/string.gleam", 111). -?DOC( - " Creates a new `String` with all the graphemes in the input `String` converted to\n" - " lowercase.\n" - "\n" - " Useful for case-insensitive comparisons.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " lowercase(\"X-FILES\")\n" - " // -> \"x-files\"\n" - " ```\n" -). --spec lowercase(binary()) -> binary(). -lowercase(String) -> - string:lowercase(String). - --file("src/gleam/string.gleam", 127). -?DOC( - " Creates a new `String` with all the graphemes in the input `String` converted to\n" - " uppercase.\n" - "\n" - " Useful for case-insensitive comparisons and VIRTUAL YELLING.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " uppercase(\"skinner\")\n" - " // -> \"SKINNER\"\n" - " ```\n" -). --spec uppercase(binary()) -> binary(). -uppercase(String) -> - string:uppercase(String). - --file("src/gleam/string.gleam", 145). -?DOC( - " Compares two `String`s to see which is \"larger\" by comparing their graphemes.\n" - "\n" - " This does not compare the size or length of the given `String`s.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " compare(\"Anthony\", \"Anthony\")\n" - " // -> order.Eq\n" - " ```\n" - "\n" - " ```gleam\n" - " compare(\"A\", \"B\")\n" - " // -> order.Lt\n" - " ```\n" -). --spec compare(binary(), binary()) -> gleam@order:order(). -compare(A, B) -> - case A =:= B of - true -> - eq; - - _ -> - case gleam_stdlib:less_than(A, B) of - true -> - lt; - - false -> - gt - end - end. - --file("src/gleam/string.gleam", 194). -?DOC( - " Takes a substring given a start grapheme index and a length. Negative indexes\n" - " are taken starting from the *end* of the list.\n" - "\n" - " This function runs in linear time with the size of the index and the\n" - " length. Negative indexes are linear with the size of the input string in\n" - " addition to the other costs.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " slice(from: \"gleam\", at_index: 1, length: 2)\n" - " // -> \"le\"\n" - " ```\n" - "\n" - " ```gleam\n" - " slice(from: \"gleam\", at_index: 1, length: 10)\n" - " // -> \"leam\"\n" - " ```\n" - "\n" - " ```gleam\n" - " slice(from: \"gleam\", at_index: 10, length: 3)\n" - " // -> \"\"\n" - " ```\n" - "\n" - " ```gleam\n" - " slice(from: \"gleam\", at_index: -2, length: 2)\n" - " // -> \"am\"\n" - " ```\n" - "\n" - " ```gleam\n" - " slice(from: \"gleam\", at_index: -12, length: 2)\n" - " // -> \"\"\n" - " ```\n" -). --spec slice(binary(), integer(), integer()) -> binary(). -slice(String, Idx, Len) -> - case Len =< 0 of - true -> - <<""/utf8>>; - - false -> - case Idx < 0 of - true -> - Translated_idx = string:length(String) + Idx, - case Translated_idx < 0 of - true -> - <<""/utf8>>; - - false -> - gleam_stdlib:slice(String, Translated_idx, Len) - end; - - false -> - gleam_stdlib:slice(String, Idx, Len) - end - end. - --file("src/gleam/string.gleam", 232). -?DOC( - " Drops contents of the first `String` that occur before the second `String`.\n" - " If the `from` string does not contain the `before` string, `from` is\n" - " returned unchanged.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " crop(from: \"The Lone Gunmen\", before: \"Lone\")\n" - " // -> \"Lone Gunmen\"\n" - " ```\n" -). --spec crop(binary(), binary()) -> binary(). -crop(String, Substring) -> - gleam_stdlib:crop_string(String, Substring). - --file("src/gleam/string.gleam", 268). -?DOC( - " Drops *n* graphemes from the end of a `String`.\n" - "\n" - " This function traverses the full string, so it runs in linear time with the\n" - " size of the string. Avoid using this in a loop.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " drop_end(from: \"Cigarette Smoking Man\", up_to: 2)\n" - " // -> \"Cigarette Smoking M\"\n" - " ```\n" -). --spec drop_end(binary(), integer()) -> binary(). -drop_end(String, Num_graphemes) -> - case Num_graphemes =< 0 of - true -> - String; - - false -> - slice(String, 0, string:length(String) - Num_graphemes) - end. - --file("src/gleam/string.gleam", 296). -?DOC( - " Checks if the first `String` contains the second.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " contains(does: \"theory\", contain: \"ory\")\n" - " // -> True\n" - " ```\n" - "\n" - " ```gleam\n" - " contains(does: \"theory\", contain: \"the\")\n" - " // -> True\n" - " ```\n" - "\n" - " ```gleam\n" - " contains(does: \"theory\", contain: \"THE\")\n" - " // -> False\n" - " ```\n" -). --spec contains(binary(), binary()) -> boolean(). -contains(Haystack, Needle) -> - gleam_stdlib:contains_string(Haystack, Needle). - --file("src/gleam/string.gleam", 309). -?DOC( - " Checks whether the first `String` starts with the second one.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " starts_with(\"theory\", \"ory\")\n" - " // -> False\n" - " ```\n" -). --spec starts_with(binary(), binary()) -> boolean(). -starts_with(String, Prefix) -> - gleam_stdlib:string_starts_with(String, Prefix). - --file("src/gleam/string.gleam", 322). -?DOC( - " Checks whether the first `String` ends with the second one.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " ends_with(\"theory\", \"ory\")\n" - " // -> True\n" - " ```\n" -). --spec ends_with(binary(), binary()) -> boolean(). -ends_with(String, Suffix) -> - gleam_stdlib:string_ends_with(String, Suffix). - --file("src/gleam/string.gleam", 361). -?DOC( - " Splits a `String` a single time on the given substring.\n" - "\n" - " Returns an `Error` if substring not present.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " split_once(\"home/gleam/desktop/\", on: \"/\")\n" - " // -> Ok(#(\"home\", \"gleam/desktop/\"))\n" - " ```\n" - "\n" - " ```gleam\n" - " split_once(\"home/gleam/desktop/\", on: \"?\")\n" - " // -> Error(Nil)\n" - " ```\n" -). --spec split_once(binary(), binary()) -> {ok, {binary(), binary()}} | - {error, nil}. -split_once(String, Substring) -> - case string:split(String, Substring) of - [First, Rest] -> - {ok, {First, Rest}}; - - _ -> - {error, nil} - end. - --file("src/gleam/string.gleam", 392). -?DOC( - " Creates a new `String` by joining two `String`s together.\n" - "\n" - " This function typically copies both `String`s and runs in linear time, but\n" - " the exact behaviour will depend on how the runtime you are using optimises\n" - " your code. Benchmark and profile your code if you need to understand its\n" - " performance better.\n" - "\n" - " If you are joining together large string and want to avoid copying any data\n" - " you may want to investigate using the [`string_tree`](../gleam/string_tree.html)\n" - " module.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " append(to: \"butter\", suffix: \"fly\")\n" - " // -> \"butterfly\"\n" - " ```\n" -). --spec append(binary(), binary()) -> binary(). -append(First, Second) -> - <>. - --file("src/gleam/string.gleam", 412). --spec concat_loop(list(binary()), binary()) -> binary(). -concat_loop(Strings, Accumulator) -> - case Strings of - [String | Strings@1] -> - concat_loop(Strings@1, <>); - - [] -> - Accumulator - end. - --file("src/gleam/string.gleam", 408). -?DOC( - " Creates a new `String` by joining many `String`s together.\n" - "\n" - " This function copies all the `String`s and runs in linear time.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " concat([\"never\", \"the\", \"less\"])\n" - " // -> \"nevertheless\"\n" - " ```\n" -). --spec concat(list(binary())) -> binary(). -concat(Strings) -> - erlang:list_to_binary(Strings). - --file("src/gleam/string.gleam", 437). --spec repeat_loop(integer(), binary(), binary()) -> binary(). -repeat_loop(Times, Doubling_acc, Acc) -> - Acc@1 = case Times rem 2 of - 0 -> - Acc; - - _ -> - <> - end, - Times@1 = Times div 2, - case Times@1 =< 0 of - true -> - Acc@1; - - false -> - repeat_loop( - Times@1, - <>, - Acc@1 - ) - end. - --file("src/gleam/string.gleam", 430). -?DOC( - " Creates a new `String` by repeating a `String` a given number of times.\n" - "\n" - " This function runs in loglinear time.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " repeat(\"ha\", times: 3)\n" - " // -> \"hahaha\"\n" - " ```\n" -). --spec repeat(binary(), integer()) -> binary(). -repeat(String, Times) -> - case Times =< 0 of - true -> - <<""/utf8>>; - - false -> - repeat_loop(Times, String, <<""/utf8>>) - end. - --file("src/gleam/string.gleam", 467). --spec join_loop(list(binary()), binary(), binary()) -> binary(). -join_loop(Strings, Separator, Accumulator) -> - case Strings of - [] -> - Accumulator; - - [String | Strings@1] -> - join_loop( - Strings@1, - Separator, - <<<>/binary, - String/binary>> - ) - end. - --file("src/gleam/string.gleam", 460). -?DOC( - " Joins many `String`s together with a given separator.\n" - "\n" - " This function runs in linear time.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " join([\"home\",\"evan\",\"Desktop\"], with: \"/\")\n" - " // -> \"home/evan/Desktop\"\n" - " ```\n" -). --spec join(list(binary()), binary()) -> binary(). -join(Strings, Separator) -> - case Strings of - [] -> - <<""/utf8>>; - - [First | Rest] -> - join_loop(Rest, Separator, First) - end. - --file("src/gleam/string.gleam", 545). --spec padding(integer(), binary()) -> binary(). -padding(Size, Pad_string) -> - Pad_string_length = string:length(Pad_string), - Num_pads = case Pad_string_length of - 0 -> 0; - Gleam@denominator -> Size div Gleam@denominator - end, - Extra = case Pad_string_length of - 0 -> 0; - Gleam@denominator@1 -> Size rem Gleam@denominator@1 - end, - <<(repeat(Pad_string, Num_pads))/binary, - (slice(Pad_string, 0, Extra))/binary>>. - --file("src/gleam/string.gleam", 498). -?DOC( - " Pads the start of a `String` until it has a given length.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " pad_start(\"121\", to: 5, with: \".\")\n" - " // -> \"..121\"\n" - " ```\n" - "\n" - " ```gleam\n" - " pad_start(\"121\", to: 3, with: \".\")\n" - " // -> \"121\"\n" - " ```\n" - "\n" - " ```gleam\n" - " pad_start(\"121\", to: 2, with: \".\")\n" - " // -> \"121\"\n" - " ```\n" -). --spec pad_start(binary(), integer(), binary()) -> binary(). -pad_start(String, Desired_length, Pad_string) -> - Current_length = string:length(String), - To_pad_length = Desired_length - Current_length, - case To_pad_length =< 0 of - true -> - String; - - false -> - <<(padding(To_pad_length, Pad_string))/binary, String/binary>> - end. - --file("src/gleam/string.gleam", 531). -?DOC( - " Pads the end of a `String` until it has a given length.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " pad_end(\"123\", to: 5, with: \".\")\n" - " // -> \"123..\"\n" - " ```\n" - "\n" - " ```gleam\n" - " pad_end(\"123\", to: 3, with: \".\")\n" - " // -> \"123\"\n" - " ```\n" - "\n" - " ```gleam\n" - " pad_end(\"123\", to: 2, with: \".\")\n" - " // -> \"123\"\n" - " ```\n" -). --spec pad_end(binary(), integer(), binary()) -> binary(). -pad_end(String, Desired_length, Pad_string) -> - Current_length = string:length(String), - To_pad_length = Desired_length - Current_length, - case To_pad_length =< 0 of - true -> - String; - - false -> - <> - end. - --file("src/gleam/string.gleam", 589). -?DOC( - " Removes whitespace at the start of a `String`.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " trim_start(\" hats \\n\")\n" - " // -> \"hats \\n\"\n" - " ```\n" -). --spec trim_start(binary()) -> binary(). -trim_start(String) -> - string:trim(String, leading). - --file("src/gleam/string.gleam", 603). -?DOC( - " Removes whitespace at the end of a `String`.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " trim_end(\" hats \\n\")\n" - " // -> \" hats\"\n" - " ```\n" -). --spec trim_end(binary()) -> binary(). -trim_end(String) -> - string:trim(String, trailing). - --file("src/gleam/string.gleam", 567). -?DOC( - " Removes whitespace on both sides of a `String`.\n" - "\n" - " Whitespace in this function is the set of nonbreakable whitespace\n" - " codepoints, defined as Pattern_White_Space in [Unicode Standard Annex #31][1].\n" - "\n" - " [1]: https://unicode.org/reports/tr31/\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " trim(\" hats \\n\")\n" - " // -> \"hats\"\n" - " ```\n" -). --spec trim(binary()) -> binary(). -trim(String) -> - _pipe = String, - _pipe@1 = trim_start(_pipe), - trim_end(_pipe@1). - --file("src/gleam/string.gleam", 630). -?DOC( - " Splits a non-empty `String` into its first element (head) and rest (tail).\n" - " This lets you pattern match on `String`s exactly as you would with lists.\n" - "\n" - " ## Performance\n" - "\n" - " There is a notable overhead to using this function, so you may not want to\n" - " use it in a tight loop. If you wish to efficiently parse a string you may\n" - " want to use alternatives such as the [splitter package](https://hex.pm/packages/splitter).\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " pop_grapheme(\"gleam\")\n" - " // -> Ok(#(\"g\", \"leam\"))\n" - " ```\n" - "\n" - " ```gleam\n" - " pop_grapheme(\"\")\n" - " // -> Error(Nil)\n" - " ```\n" -). --spec pop_grapheme(binary()) -> {ok, {binary(), binary()}} | {error, nil}. -pop_grapheme(String) -> - gleam_stdlib:string_pop_grapheme(String). - --file("src/gleam/string.gleam", 647). --spec to_graphemes_loop(binary(), list(binary())) -> list(binary()). -to_graphemes_loop(String, Acc) -> - case gleam_stdlib:string_pop_grapheme(String) of - {ok, {Grapheme, Rest}} -> - to_graphemes_loop(Rest, [Grapheme | Acc]); - - {error, _} -> - Acc - end. - --file("src/gleam/string.gleam", 641). -?DOC( - " Converts a `String` to a list of\n" - " [graphemes](https://en.wikipedia.org/wiki/Grapheme).\n" - "\n" - " ```gleam\n" - " to_graphemes(\"abc\")\n" - " // -> [\"a\", \"b\", \"c\"]\n" - " ```\n" -). --spec to_graphemes(binary()) -> list(binary()). -to_graphemes(String) -> - _pipe = String, - _pipe@1 = to_graphemes_loop(_pipe, []), - lists:reverse(_pipe@1). - --file("src/gleam/string.gleam", 333). -?DOC( - " Creates a list of `String`s by splitting a given string on a given substring.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " split(\"home/gleam/desktop/\", on: \"/\")\n" - " // -> [\"home\", \"gleam\", \"desktop\", \"\"]\n" - " ```\n" -). --spec split(binary(), binary()) -> list(binary()). -split(X, Substring) -> - case Substring of - <<""/utf8>> -> - to_graphemes(X); - - _ -> - _pipe = X, - _pipe@1 = gleam_stdlib:identity(_pipe), - _pipe@2 = gleam@string_tree:split(_pipe@1, Substring), - gleam@list:map(_pipe@2, fun unicode:characters_to_binary/1) - end. - --file("src/gleam/string.gleam", 694). --spec to_utf_codepoints_loop(bitstring(), list(integer())) -> list(integer()). -to_utf_codepoints_loop(Bit_array, Acc) -> - case Bit_array of - <> -> - to_utf_codepoints_loop(Rest, [First | Acc]); - - _ -> - lists:reverse(Acc) - end. - --file("src/gleam/string.gleam", 689). --spec do_to_utf_codepoints(binary()) -> list(integer()). -do_to_utf_codepoints(String) -> - to_utf_codepoints_loop(<>, []). - --file("src/gleam/string.gleam", 684). -?DOC( - " Converts a `String` to a `List` of `UtfCodepoint`.\n" - "\n" - " See and\n" - " for an\n" - " explanation on code points.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " \"a\" |> to_utf_codepoints\n" - " // -> [UtfCodepoint(97)]\n" - " ```\n" - "\n" - " ```gleam\n" - " // Semantically the same as:\n" - " // [\"🏳\", \"️\", \"‍\", \"🌈\"] or:\n" - " // [waving_white_flag, variant_selector_16, zero_width_joiner, rainbow]\n" - " \"🏳️‍🌈\" |> to_utf_codepoints\n" - " // -> [\n" - " // UtfCodepoint(127987),\n" - " // UtfCodepoint(65039),\n" - " // UtfCodepoint(8205),\n" - " // UtfCodepoint(127752),\n" - " // ]\n" - " ```\n" -). --spec to_utf_codepoints(binary()) -> list(integer()). -to_utf_codepoints(String) -> - do_to_utf_codepoints(String). - --file("src/gleam/string.gleam", 734). -?DOC( - " Converts a `List` of `UtfCodepoint`s to a `String`.\n" - "\n" - " See and\n" - " for an\n" - " explanation on code points.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " let assert Ok(a) = utf_codepoint(97)\n" - " let assert Ok(b) = utf_codepoint(98)\n" - " let assert Ok(c) = utf_codepoint(99)\n" - " from_utf_codepoints([a, b, c])\n" - " // -> \"abc\"\n" - " ```\n" -). --spec from_utf_codepoints(list(integer())) -> binary(). -from_utf_codepoints(Utf_codepoints) -> - gleam_stdlib:utf_codepoint_list_to_string(Utf_codepoints). - --file("src/gleam/string.gleam", 740). -?DOC( - " Converts an integer to a `UtfCodepoint`.\n" - "\n" - " Returns an `Error` if the integer does not represent a valid UTF codepoint.\n" -). --spec utf_codepoint(integer()) -> {ok, integer()} | {error, nil}. -utf_codepoint(Value) -> - case Value of - I when I > 1114111 -> - {error, nil}; - - I@1 when (I@1 >= 55296) andalso (I@1 =< 57343) -> - {error, nil}; - - I@2 when I@2 < 0 -> - {error, nil}; - - I@3 -> - {ok, gleam_stdlib:identity(I@3)} - end. - --file("src/gleam/string.gleam", 761). -?DOC( - " Converts an UtfCodepoint to its ordinal code point value.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " let assert [utf_codepoint, ..] = to_utf_codepoints(\"💜\")\n" - " utf_codepoint_to_int(utf_codepoint)\n" - " // -> 128156\n" - " ```\n" -). --spec utf_codepoint_to_int(integer()) -> integer(). -utf_codepoint_to_int(Cp) -> - gleam_stdlib:identity(Cp). - --file("src/gleam/string.gleam", 778). -?DOC( - " Converts a `String` into `Option(String)` where an empty `String` becomes\n" - " `None`.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " to_option(\"\")\n" - " // -> None\n" - " ```\n" - "\n" - " ```gleam\n" - " to_option(\"hats\")\n" - " // -> Some(\"hats\")\n" - " ```\n" -). --spec to_option(binary()) -> gleam@option:option(binary()). -to_option(String) -> - case String of - <<""/utf8>> -> - none; - - _ -> - {some, String} - end. - --file("src/gleam/string.gleam", 801). -?DOC( - " Returns the first grapheme cluster in a given `String` and wraps it in a\n" - " `Result(String, Nil)`. If the `String` is empty, it returns `Error(Nil)`.\n" - " Otherwise, it returns `Ok(String)`.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " first(\"\")\n" - " // -> Error(Nil)\n" - " ```\n" - "\n" - " ```gleam\n" - " first(\"icecream\")\n" - " // -> Ok(\"i\")\n" - " ```\n" -). --spec first(binary()) -> {ok, binary()} | {error, nil}. -first(String) -> - case gleam_stdlib:string_pop_grapheme(String) of - {ok, {First, _}} -> - {ok, First}; - - {error, E} -> - {error, E} - end. - --file("src/gleam/string.gleam", 827). -?DOC( - " Returns the last grapheme cluster in a given `String` and wraps it in a\n" - " `Result(String, Nil)`. If the `String` is empty, it returns `Error(Nil)`.\n" - " Otherwise, it returns `Ok(String)`.\n" - "\n" - " This function traverses the full string, so it runs in linear time with the\n" - " length of the string. Avoid using this in a loop.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " last(\"\")\n" - " // -> Error(Nil)\n" - " ```\n" - "\n" - " ```gleam\n" - " last(\"icecream\")\n" - " // -> Ok(\"m\")\n" - " ```\n" -). --spec last(binary()) -> {ok, binary()} | {error, nil}. -last(String) -> - case gleam_stdlib:string_pop_grapheme(String) of - {ok, {First, <<""/utf8>>}} -> - {ok, First}; - - {ok, {_, Rest}} -> - {ok, slice(Rest, -1, 1)}; - - {error, E} -> - {error, E} - end. - --file("src/gleam/string.gleam", 845). -?DOC( - " Creates a new `String` with the first grapheme in the input `String`\n" - " converted to uppercase and the remaining graphemes to lowercase.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " capitalise(\"mamouna\")\n" - " // -> \"Mamouna\"\n" - " ```\n" -). --spec capitalise(binary()) -> binary(). -capitalise(String) -> - case gleam_stdlib:string_pop_grapheme(String) of - {ok, {First, Rest}} -> - append(string:uppercase(First), string:lowercase(Rest)); - - {error, _} -> - <<""/utf8>> - end. - --file("src/gleam/string.gleam", 876). -?DOC( - " Returns a `String` representation of a term in Gleam syntax.\n" - "\n" - " This may be occasionally useful for quick-and-dirty printing of values in\n" - " scripts. For error reporting and other uses prefer constructing strings by\n" - " pattern matching on the values.\n" - "\n" - " ## Limitations\n" - "\n" - " The output format of this function is not stable and could change at any\n" - " time. The output is not suitable for parsing.\n" - "\n" - " This function works using runtime reflection, so the output may not be\n" - " perfectly accurate for data structures where the runtime structure doesn't\n" - " hold enough information to determine the original syntax. For example,\n" - " tuples with an Erlang atom in the first position will be mistaken for Gleam\n" - " records.\n" - "\n" - " ## Security and safety\n" - "\n" - " There is no limit to how large the strings that this function can produce.\n" - " Be careful not to call this function with large data structures or you\n" - " could use very large amounts of memory, potentially causing runtime\n" - " problems.\n" -). --spec inspect(any()) -> binary(). -inspect(Term) -> - _pipe = Term, - _pipe@1 = gleam_stdlib:inspect(_pipe), - unicode:characters_to_binary(_pipe@1). - --file("src/gleam/string.gleam", 900). -?DOC( - " Returns the number of bytes in a `String`.\n" - "\n" - " This function runs in constant time on Erlang and in linear time on\n" - " JavaScript.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " byte_size(\"🏳️‍⚧️🏳️‍🌈👩🏾‍❤️‍👨🏻\")\n" - " // -> 58\n" - " ```\n" -). --spec byte_size(binary()) -> integer(). -byte_size(String) -> - erlang:byte_size(String). - --file("src/gleam/string.gleam", 245). -?DOC( - " Drops *n* graphemes from the start of a `String`.\n" - "\n" - " This function runs in linear time with the number of graphemes to drop.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " drop_start(from: \"The Lone Gunmen\", up_to: 2)\n" - " // -> \"e Lone Gunmen\"\n" - " ```\n" -). --spec drop_start(binary(), integer()) -> binary(). -drop_start(String, Num_graphemes) -> - case Num_graphemes =< 0 of - true -> - String; - - false -> - Prefix = gleam_stdlib:slice(String, 0, Num_graphemes), - Prefix_size = erlang:byte_size(Prefix), - binary:part( - String, - Prefix_size, - erlang:byte_size(String) - Prefix_size - ) - end. diff --git a/build/packages/gleam_stdlib/src/gleam@string_tree.erl b/build/packages/gleam_stdlib/src/gleam@string_tree.erl deleted file mode 100644 index 0d72b4d..0000000 --- a/build/packages/gleam_stdlib/src/gleam@string_tree.erl +++ /dev/null @@ -1,207 +0,0 @@ --module(gleam@string_tree). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "src/gleam/string_tree.gleam"). --export([append_tree/2, prepend_tree/2, from_strings/1, new/0, concat/1, from_string/1, prepend/2, append/2, to_string/1, byte_size/1, join/2, lowercase/1, uppercase/1, reverse/1, split/2, replace/3, is_equal/2, is_empty/1]). --export_type([string_tree/0, direction/0]). - --if(?OTP_RELEASE >= 27). --define(MODULEDOC(Str), -moduledoc(Str)). --define(DOC(Str), -doc(Str)). --else. --define(MODULEDOC(Str), -compile([])). --define(DOC(Str), -compile([])). --endif. - --type string_tree() :: any(). - --type direction() :: all. - --file("src/gleam/string_tree.gleam", 61). -?DOC( - " Appends some `StringTree` onto the end of another.\n" - "\n" - " Runs in constant time.\n" -). --spec append_tree(string_tree(), string_tree()) -> string_tree(). -append_tree(Tree, Suffix) -> - gleam_stdlib:iodata_append(Tree, Suffix). - --file("src/gleam/string_tree.gleam", 48). -?DOC( - " Prepends some `StringTree` onto the start of another.\n" - "\n" - " Runs in constant time.\n" -). --spec prepend_tree(string_tree(), string_tree()) -> string_tree(). -prepend_tree(Tree, Prefix) -> - gleam_stdlib:iodata_append(Prefix, Tree). - --file("src/gleam/string_tree.gleam", 69). -?DOC( - " Converts a list of strings into a `StringTree`.\n" - "\n" - " Runs in constant time.\n" -). --spec from_strings(list(binary())) -> string_tree(). -from_strings(Strings) -> - gleam_stdlib:identity(Strings). - --file("src/gleam/string_tree.gleam", 24). -?DOC( - " Create an empty `StringTree`. Useful as the start of a pipe chaining many\n" - " trees together.\n" -). --spec new() -> string_tree(). -new() -> - gleam_stdlib:identity([]). - --file("src/gleam/string_tree.gleam", 77). -?DOC( - " Joins a list of trees into a single tree.\n" - "\n" - " Runs in constant time.\n" -). --spec concat(list(string_tree())) -> string_tree(). -concat(Trees) -> - gleam_stdlib:identity(Trees). - --file("src/gleam/string_tree.gleam", 85). -?DOC( - " Converts a string into a `StringTree`.\n" - "\n" - " Runs in constant time.\n" -). --spec from_string(binary()) -> string_tree(). -from_string(String) -> - gleam_stdlib:identity(String). - --file("src/gleam/string_tree.gleam", 32). -?DOC( - " Prepends a `String` onto the start of some `StringTree`.\n" - "\n" - " Runs in constant time.\n" -). --spec prepend(string_tree(), binary()) -> string_tree(). -prepend(Tree, Prefix) -> - gleam_stdlib:iodata_append(gleam_stdlib:identity(Prefix), Tree). - --file("src/gleam/string_tree.gleam", 40). -?DOC( - " Appends a `String` onto the end of some `StringTree`.\n" - "\n" - " Runs in constant time.\n" -). --spec append(string_tree(), binary()) -> string_tree(). -append(Tree, Second) -> - gleam_stdlib:iodata_append(Tree, gleam_stdlib:identity(Second)). - --file("src/gleam/string_tree.gleam", 94). -?DOC( - " Turns a `StringTree` into a `String`\n" - "\n" - " This function is implemented natively by the virtual machine and is highly\n" - " optimised.\n" -). --spec to_string(string_tree()) -> binary(). -to_string(Tree) -> - unicode:characters_to_binary(Tree). - --file("src/gleam/string_tree.gleam", 100). -?DOC(" Returns the size of the `StringTree` in bytes.\n"). --spec byte_size(string_tree()) -> integer(). -byte_size(Tree) -> - erlang:iolist_size(Tree). - --file("src/gleam/string_tree.gleam", 104). -?DOC(" Joins the given trees into a new tree separated with the given string.\n"). --spec join(list(string_tree()), binary()) -> string_tree(). -join(Trees, Sep) -> - _pipe = Trees, - _pipe@1 = gleam@list:intersperse(_pipe, gleam_stdlib:identity(Sep)), - gleam_stdlib:identity(_pipe@1). - --file("src/gleam/string_tree.gleam", 115). -?DOC( - " Converts a `StringTree` to a new one where the contents have been\n" - " lowercased.\n" -). --spec lowercase(string_tree()) -> string_tree(). -lowercase(Tree) -> - string:lowercase(Tree). - --file("src/gleam/string_tree.gleam", 122). -?DOC( - " Converts a `StringTree` to a new one where the contents have been\n" - " uppercased.\n" -). --spec uppercase(string_tree()) -> string_tree(). -uppercase(Tree) -> - string:uppercase(Tree). - --file("src/gleam/string_tree.gleam", 127). -?DOC(" Converts a `StringTree` to a new one with the contents reversed.\n"). --spec reverse(string_tree()) -> string_tree(). -reverse(Tree) -> - string:reverse(Tree). - --file("src/gleam/string_tree.gleam", 145). -?DOC(" Splits a `StringTree` on a given pattern into a list of trees.\n"). --spec split(string_tree(), binary()) -> list(string_tree()). -split(Tree, Pattern) -> - string:split(Tree, Pattern, all). - --file("src/gleam/string_tree.gleam", 156). -?DOC(" Replaces all instances of a pattern with a given string substitute.\n"). --spec replace(string_tree(), binary(), binary()) -> string_tree(). -replace(Tree, Pattern, Substitute) -> - gleam_stdlib:string_replace(Tree, Pattern, Substitute). - --file("src/gleam/string_tree.gleam", 182). -?DOC( - " Compares two string trees to determine if they have the same textual\n" - " content.\n" - "\n" - " Comparing two string trees using the `==` operator may return `False` even\n" - " if they have the same content as they may have been build in different ways,\n" - " so using this function is often preferred.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " from_strings([\"a\", \"b\"]) == from_string(\"ab\")\n" - " // -> False\n" - " ```\n" - "\n" - " ```gleam\n" - " is_equal(from_strings([\"a\", \"b\"]), from_string(\"ab\"))\n" - " // -> True\n" - " ```\n" -). --spec is_equal(string_tree(), string_tree()) -> boolean(). -is_equal(A, B) -> - string:equal(A, B). - --file("src/gleam/string_tree.gleam", 206). -?DOC( - " Inspects a `StringTree` to determine if it is equivalent to an empty string.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " from_string(\"ok\") |> is_empty\n" - " // -> False\n" - " ```\n" - "\n" - " ```gleam\n" - " from_string(\"\") |> is_empty\n" - " // -> True\n" - " ```\n" - "\n" - " ```gleam\n" - " from_strings([]) |> is_empty\n" - " // -> True\n" - " ```\n" -). --spec is_empty(string_tree()) -> boolean(). -is_empty(Tree) -> - string:is_empty(Tree). diff --git a/build/packages/gleam_stdlib/src/gleam@uri.erl b/build/packages/gleam_stdlib/src/gleam@uri.erl deleted file mode 100644 index 0819463..0000000 --- a/build/packages/gleam_stdlib/src/gleam@uri.erl +++ /dev/null @@ -1,1044 +0,0 @@ --module(gleam@uri). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "src/gleam/uri.gleam"). --export([parse_query/1, percent_encode/1, query_to_string/1, percent_decode/1, path_segments/1, to_string/1, origin/1, merge/2, parse/1]). --export_type([uri/0]). - --if(?OTP_RELEASE >= 27). --define(MODULEDOC(Str), -moduledoc(Str)). --define(DOC(Str), -doc(Str)). --else. --define(MODULEDOC(Str), -compile([])). --define(DOC(Str), -compile([])). --endif. - -?MODULEDOC( - " Utilities for working with URIs\n" - "\n" - " This module provides functions for working with URIs (for example, parsing\n" - " URIs or encoding query strings). The functions in this module are implemented\n" - " according to [RFC 3986](https://tools.ietf.org/html/rfc3986).\n" - "\n" - " Query encoding (Form encoding) is defined in the\n" - " [W3C specification](https://www.w3.org/TR/html52/sec-forms.html#urlencoded-form-data).\n" -). - --type uri() :: {uri, - gleam@option:option(binary()), - gleam@option:option(binary()), - gleam@option:option(binary()), - gleam@option:option(integer()), - binary(), - gleam@option:option(binary()), - gleam@option:option(binary())}. - --file("src/gleam/uri.gleam", 289). --spec is_valid_host_within_brackets_char(integer()) -> boolean(). -is_valid_host_within_brackets_char(Char) -> - (((((48 >= Char) andalso (Char =< 57)) orelse ((65 >= Char) andalso (Char =< 90))) - orelse ((97 >= Char) andalso (Char =< 122))) - orelse (Char =:= 58)) - orelse (Char =:= 46). - --file("src/gleam/uri.gleam", 506). --spec parse_fragment(binary(), uri()) -> {ok, uri()} | {error, nil}. -parse_fragment(Rest, Pieces) -> - {ok, - {uri, - erlang:element(2, Pieces), - erlang:element(3, Pieces), - erlang:element(4, Pieces), - erlang:element(5, Pieces), - erlang:element(6, Pieces), - erlang:element(7, Pieces), - {some, Rest}}}. - --file("src/gleam/uri.gleam", 478). --spec parse_query_with_question_mark_loop(binary(), binary(), uri(), integer()) -> {ok, - uri()} | - {error, nil}. -parse_query_with_question_mark_loop(Original, Uri_string, Pieces, Size) -> - case Uri_string of - <<"#"/utf8, Rest/binary>> when Size =:= 0 -> - parse_fragment(Rest, Pieces); - - <<"#"/utf8, Rest@1/binary>> -> - Query = binary:part(Original, 0, Size), - Pieces@1 = {uri, - erlang:element(2, Pieces), - erlang:element(3, Pieces), - erlang:element(4, Pieces), - erlang:element(5, Pieces), - erlang:element(6, Pieces), - {some, Query}, - erlang:element(8, Pieces)}, - parse_fragment(Rest@1, Pieces@1); - - <<""/utf8>> -> - {ok, - {uri, - erlang:element(2, Pieces), - erlang:element(3, Pieces), - erlang:element(4, Pieces), - erlang:element(5, Pieces), - erlang:element(6, Pieces), - {some, Original}, - erlang:element(8, Pieces)}}; - - _ -> - {_, Rest@2} = gleam_stdlib:string_pop_codeunit(Uri_string), - parse_query_with_question_mark_loop( - Original, - Rest@2, - Pieces, - Size + 1 - ) - end. - --file("src/gleam/uri.gleam", 471). --spec parse_query_with_question_mark(binary(), uri()) -> {ok, uri()} | - {error, nil}. -parse_query_with_question_mark(Uri_string, Pieces) -> - parse_query_with_question_mark_loop(Uri_string, Uri_string, Pieces, 0). - --file("src/gleam/uri.gleam", 437). --spec parse_path_loop(binary(), binary(), uri(), integer()) -> {ok, uri()} | - {error, nil}. -parse_path_loop(Original, Uri_string, Pieces, Size) -> - case Uri_string of - <<"?"/utf8, Rest/binary>> -> - Path = binary:part(Original, 0, Size), - Pieces@1 = {uri, - erlang:element(2, Pieces), - erlang:element(3, Pieces), - erlang:element(4, Pieces), - erlang:element(5, Pieces), - Path, - erlang:element(7, Pieces), - erlang:element(8, Pieces)}, - parse_query_with_question_mark(Rest, Pieces@1); - - <<"#"/utf8, Rest@1/binary>> -> - Path@1 = binary:part(Original, 0, Size), - Pieces@2 = {uri, - erlang:element(2, Pieces), - erlang:element(3, Pieces), - erlang:element(4, Pieces), - erlang:element(5, Pieces), - Path@1, - erlang:element(7, Pieces), - erlang:element(8, Pieces)}, - parse_fragment(Rest@1, Pieces@2); - - <<""/utf8>> -> - {ok, - {uri, - erlang:element(2, Pieces), - erlang:element(3, Pieces), - erlang:element(4, Pieces), - erlang:element(5, Pieces), - Original, - erlang:element(7, Pieces), - erlang:element(8, Pieces)}}; - - _ -> - {_, Rest@2} = gleam_stdlib:string_pop_codeunit(Uri_string), - parse_path_loop(Original, Rest@2, Pieces, Size + 1) - end. - --file("src/gleam/uri.gleam", 433). --spec parse_path(binary(), uri()) -> {ok, uri()} | {error, nil}. -parse_path(Uri_string, Pieces) -> - parse_path_loop(Uri_string, Uri_string, Pieces, 0). - --file("src/gleam/uri.gleam", 388). --spec parse_port_loop(binary(), uri(), integer()) -> {ok, uri()} | {error, nil}. -parse_port_loop(Uri_string, Pieces, Port) -> - case Uri_string of - <<"0"/utf8, Rest/binary>> -> - parse_port_loop(Rest, Pieces, Port * 10); - - <<"1"/utf8, Rest@1/binary>> -> - parse_port_loop(Rest@1, Pieces, (Port * 10) + 1); - - <<"2"/utf8, Rest@2/binary>> -> - parse_port_loop(Rest@2, Pieces, (Port * 10) + 2); - - <<"3"/utf8, Rest@3/binary>> -> - parse_port_loop(Rest@3, Pieces, (Port * 10) + 3); - - <<"4"/utf8, Rest@4/binary>> -> - parse_port_loop(Rest@4, Pieces, (Port * 10) + 4); - - <<"5"/utf8, Rest@5/binary>> -> - parse_port_loop(Rest@5, Pieces, (Port * 10) + 5); - - <<"6"/utf8, Rest@6/binary>> -> - parse_port_loop(Rest@6, Pieces, (Port * 10) + 6); - - <<"7"/utf8, Rest@7/binary>> -> - parse_port_loop(Rest@7, Pieces, (Port * 10) + 7); - - <<"8"/utf8, Rest@8/binary>> -> - parse_port_loop(Rest@8, Pieces, (Port * 10) + 8); - - <<"9"/utf8, Rest@9/binary>> -> - parse_port_loop(Rest@9, Pieces, (Port * 10) + 9); - - <<"?"/utf8, Rest@10/binary>> -> - Pieces@1 = {uri, - erlang:element(2, Pieces), - erlang:element(3, Pieces), - erlang:element(4, Pieces), - {some, Port}, - erlang:element(6, Pieces), - erlang:element(7, Pieces), - erlang:element(8, Pieces)}, - parse_query_with_question_mark(Rest@10, Pieces@1); - - <<"#"/utf8, Rest@11/binary>> -> - Pieces@2 = {uri, - erlang:element(2, Pieces), - erlang:element(3, Pieces), - erlang:element(4, Pieces), - {some, Port}, - erlang:element(6, Pieces), - erlang:element(7, Pieces), - erlang:element(8, Pieces)}, - parse_fragment(Rest@11, Pieces@2); - - <<"/"/utf8, _/binary>> -> - Pieces@3 = {uri, - erlang:element(2, Pieces), - erlang:element(3, Pieces), - erlang:element(4, Pieces), - {some, Port}, - erlang:element(6, Pieces), - erlang:element(7, Pieces), - erlang:element(8, Pieces)}, - parse_path(Uri_string, Pieces@3); - - <<""/utf8>> -> - {ok, - {uri, - erlang:element(2, Pieces), - erlang:element(3, Pieces), - erlang:element(4, Pieces), - {some, Port}, - erlang:element(6, Pieces), - erlang:element(7, Pieces), - erlang:element(8, Pieces)}}; - - _ -> - {error, nil} - end. - --file("src/gleam/uri.gleam", 353). --spec parse_port(binary(), uri()) -> {ok, uri()} | {error, nil}. -parse_port(Uri_string, Pieces) -> - case Uri_string of - <<":0"/utf8, Rest/binary>> -> - parse_port_loop(Rest, Pieces, 0); - - <<":1"/utf8, Rest@1/binary>> -> - parse_port_loop(Rest@1, Pieces, 1); - - <<":2"/utf8, Rest@2/binary>> -> - parse_port_loop(Rest@2, Pieces, 2); - - <<":3"/utf8, Rest@3/binary>> -> - parse_port_loop(Rest@3, Pieces, 3); - - <<":4"/utf8, Rest@4/binary>> -> - parse_port_loop(Rest@4, Pieces, 4); - - <<":5"/utf8, Rest@5/binary>> -> - parse_port_loop(Rest@5, Pieces, 5); - - <<":6"/utf8, Rest@6/binary>> -> - parse_port_loop(Rest@6, Pieces, 6); - - <<":7"/utf8, Rest@7/binary>> -> - parse_port_loop(Rest@7, Pieces, 7); - - <<":8"/utf8, Rest@8/binary>> -> - parse_port_loop(Rest@8, Pieces, 8); - - <<":9"/utf8, Rest@9/binary>> -> - parse_port_loop(Rest@9, Pieces, 9); - - <<":"/utf8>> -> - {ok, Pieces}; - - <<""/utf8>> -> - {ok, Pieces}; - - <<"?"/utf8, Rest@10/binary>> -> - parse_query_with_question_mark(Rest@10, Pieces); - - <<":?"/utf8, Rest@10/binary>> -> - parse_query_with_question_mark(Rest@10, Pieces); - - <<"#"/utf8, Rest@11/binary>> -> - parse_fragment(Rest@11, Pieces); - - <<":#"/utf8, Rest@11/binary>> -> - parse_fragment(Rest@11, Pieces); - - <<"/"/utf8, _/binary>> -> - parse_path(Uri_string, Pieces); - - <<":"/utf8, Rest@12/binary>> -> - case Rest@12 of - <<"/"/utf8, _/binary>> -> - parse_path(Rest@12, Pieces); - - _ -> - {error, nil} - end; - - _ -> - {error, nil} - end. - --file("src/gleam/uri.gleam", 309). --spec parse_host_outside_of_brackets_loop(binary(), binary(), uri(), integer()) -> {ok, - uri()} | - {error, nil}. -parse_host_outside_of_brackets_loop(Original, Uri_string, Pieces, Size) -> - case Uri_string of - <<""/utf8>> -> - {ok, - {uri, - erlang:element(2, Pieces), - erlang:element(3, Pieces), - {some, Original}, - erlang:element(5, Pieces), - erlang:element(6, Pieces), - erlang:element(7, Pieces), - erlang:element(8, Pieces)}}; - - <<":"/utf8, _/binary>> -> - Host = binary:part(Original, 0, Size), - Pieces@1 = {uri, - erlang:element(2, Pieces), - erlang:element(3, Pieces), - {some, Host}, - erlang:element(5, Pieces), - erlang:element(6, Pieces), - erlang:element(7, Pieces), - erlang:element(8, Pieces)}, - parse_port(Uri_string, Pieces@1); - - <<"/"/utf8, _/binary>> -> - Host@1 = binary:part(Original, 0, Size), - Pieces@2 = {uri, - erlang:element(2, Pieces), - erlang:element(3, Pieces), - {some, Host@1}, - erlang:element(5, Pieces), - erlang:element(6, Pieces), - erlang:element(7, Pieces), - erlang:element(8, Pieces)}, - parse_path(Uri_string, Pieces@2); - - <<"?"/utf8, Rest/binary>> -> - Host@2 = binary:part(Original, 0, Size), - Pieces@3 = {uri, - erlang:element(2, Pieces), - erlang:element(3, Pieces), - {some, Host@2}, - erlang:element(5, Pieces), - erlang:element(6, Pieces), - erlang:element(7, Pieces), - erlang:element(8, Pieces)}, - parse_query_with_question_mark(Rest, Pieces@3); - - <<"#"/utf8, Rest@1/binary>> -> - Host@3 = binary:part(Original, 0, Size), - Pieces@4 = {uri, - erlang:element(2, Pieces), - erlang:element(3, Pieces), - {some, Host@3}, - erlang:element(5, Pieces), - erlang:element(6, Pieces), - erlang:element(7, Pieces), - erlang:element(8, Pieces)}, - parse_fragment(Rest@1, Pieces@4); - - _ -> - {_, Rest@2} = gleam_stdlib:string_pop_codeunit(Uri_string), - parse_host_outside_of_brackets_loop( - Original, - Rest@2, - Pieces, - Size + 1 - ) - end. - --file("src/gleam/uri.gleam", 229). --spec parse_host_within_brackets_loop(binary(), binary(), uri(), integer()) -> {ok, - uri()} | - {error, nil}. -parse_host_within_brackets_loop(Original, Uri_string, Pieces, Size) -> - case Uri_string of - <<""/utf8>> -> - {ok, - {uri, - erlang:element(2, Pieces), - erlang:element(3, Pieces), - {some, Uri_string}, - erlang:element(5, Pieces), - erlang:element(6, Pieces), - erlang:element(7, Pieces), - erlang:element(8, Pieces)}}; - - <<"]"/utf8, Rest/binary>> when Size =:= 0 -> - parse_port(Rest, Pieces); - - <<"]"/utf8, Rest@1/binary>> -> - Host = binary:part(Original, 0, Size + 1), - Pieces@1 = {uri, - erlang:element(2, Pieces), - erlang:element(3, Pieces), - {some, Host}, - erlang:element(5, Pieces), - erlang:element(6, Pieces), - erlang:element(7, Pieces), - erlang:element(8, Pieces)}, - parse_port(Rest@1, Pieces@1); - - <<"/"/utf8, _/binary>> when Size =:= 0 -> - parse_path(Uri_string, Pieces); - - <<"/"/utf8, _/binary>> -> - Host@1 = binary:part(Original, 0, Size), - Pieces@2 = {uri, - erlang:element(2, Pieces), - erlang:element(3, Pieces), - {some, Host@1}, - erlang:element(5, Pieces), - erlang:element(6, Pieces), - erlang:element(7, Pieces), - erlang:element(8, Pieces)}, - parse_path(Uri_string, Pieces@2); - - <<"?"/utf8, Rest@2/binary>> when Size =:= 0 -> - parse_query_with_question_mark(Rest@2, Pieces); - - <<"?"/utf8, Rest@3/binary>> -> - Host@2 = binary:part(Original, 0, Size), - Pieces@3 = {uri, - erlang:element(2, Pieces), - erlang:element(3, Pieces), - {some, Host@2}, - erlang:element(5, Pieces), - erlang:element(6, Pieces), - erlang:element(7, Pieces), - erlang:element(8, Pieces)}, - parse_query_with_question_mark(Rest@3, Pieces@3); - - <<"#"/utf8, Rest@4/binary>> when Size =:= 0 -> - parse_fragment(Rest@4, Pieces); - - <<"#"/utf8, Rest@5/binary>> -> - Host@3 = binary:part(Original, 0, Size), - Pieces@4 = {uri, - erlang:element(2, Pieces), - erlang:element(3, Pieces), - {some, Host@3}, - erlang:element(5, Pieces), - erlang:element(6, Pieces), - erlang:element(7, Pieces), - erlang:element(8, Pieces)}, - parse_fragment(Rest@5, Pieces@4); - - _ -> - {Char, Rest@6} = gleam_stdlib:string_pop_codeunit(Uri_string), - case is_valid_host_within_brackets_char(Char) of - true -> - parse_host_within_brackets_loop( - Original, - Rest@6, - Pieces, - Size + 1 - ); - - false -> - parse_host_outside_of_brackets_loop( - Original, - Original, - Pieces, - 0 - ) - end - end. - --file("src/gleam/uri.gleam", 222). --spec parse_host_within_brackets(binary(), uri()) -> {ok, uri()} | {error, nil}. -parse_host_within_brackets(Uri_string, Pieces) -> - parse_host_within_brackets_loop(Uri_string, Uri_string, Pieces, 0). - --file("src/gleam/uri.gleam", 302). --spec parse_host_outside_of_brackets(binary(), uri()) -> {ok, uri()} | - {error, nil}. -parse_host_outside_of_brackets(Uri_string, Pieces) -> - parse_host_outside_of_brackets_loop(Uri_string, Uri_string, Pieces, 0). - --file("src/gleam/uri.gleam", 199). --spec parse_host(binary(), uri()) -> {ok, uri()} | {error, nil}. -parse_host(Uri_string, Pieces) -> - case Uri_string of - <<"["/utf8, _/binary>> -> - parse_host_within_brackets(Uri_string, Pieces); - - <<":"/utf8, _/binary>> -> - Pieces@1 = {uri, - erlang:element(2, Pieces), - erlang:element(3, Pieces), - {some, <<""/utf8>>}, - erlang:element(5, Pieces), - erlang:element(6, Pieces), - erlang:element(7, Pieces), - erlang:element(8, Pieces)}, - parse_port(Uri_string, Pieces@1); - - <<""/utf8>> -> - {ok, - {uri, - erlang:element(2, Pieces), - erlang:element(3, Pieces), - {some, <<""/utf8>>}, - erlang:element(5, Pieces), - erlang:element(6, Pieces), - erlang:element(7, Pieces), - erlang:element(8, Pieces)}}; - - _ -> - parse_host_outside_of_brackets(Uri_string, Pieces) - end. - --file("src/gleam/uri.gleam", 167). --spec parse_userinfo_loop(binary(), binary(), uri(), integer()) -> {ok, uri()} | - {error, nil}. -parse_userinfo_loop(Original, Uri_string, Pieces, Size) -> - case Uri_string of - <<"@"/utf8, Rest/binary>> when Size =:= 0 -> - parse_host(Rest, Pieces); - - <<"@"/utf8, Rest@1/binary>> -> - Userinfo = binary:part(Original, 0, Size), - Pieces@1 = {uri, - erlang:element(2, Pieces), - {some, Userinfo}, - erlang:element(4, Pieces), - erlang:element(5, Pieces), - erlang:element(6, Pieces), - erlang:element(7, Pieces), - erlang:element(8, Pieces)}, - parse_host(Rest@1, Pieces@1); - - <<""/utf8>> -> - parse_host(Original, Pieces); - - <<"/"/utf8, _/binary>> -> - parse_host(Original, Pieces); - - <<"?"/utf8, _/binary>> -> - parse_host(Original, Pieces); - - <<"#"/utf8, _/binary>> -> - parse_host(Original, Pieces); - - _ -> - {_, Rest@2} = gleam_stdlib:string_pop_codeunit(Uri_string), - parse_userinfo_loop(Original, Rest@2, Pieces, Size + 1) - end. - --file("src/gleam/uri.gleam", 163). --spec parse_authority_pieces(binary(), uri()) -> {ok, uri()} | {error, nil}. -parse_authority_pieces(String, Pieces) -> - parse_userinfo_loop(String, String, Pieces, 0). - --file("src/gleam/uri.gleam", 150). --spec parse_authority_with_slashes(binary(), uri()) -> {ok, uri()} | - {error, nil}. -parse_authority_with_slashes(Uri_string, Pieces) -> - case Uri_string of - <<"//"/utf8>> -> - {ok, - {uri, - erlang:element(2, Pieces), - erlang:element(3, Pieces), - {some, <<""/utf8>>}, - erlang:element(5, Pieces), - erlang:element(6, Pieces), - erlang:element(7, Pieces), - erlang:element(8, Pieces)}}; - - <<"//"/utf8, Rest/binary>> -> - parse_authority_pieces(Rest, Pieces); - - _ -> - parse_path(Uri_string, Pieces) - end. - --file("src/gleam/uri.gleam", 91). --spec parse_scheme_loop(binary(), binary(), uri(), integer()) -> {ok, uri()} | - {error, nil}. -parse_scheme_loop(Original, Uri_string, Pieces, Size) -> - case Uri_string of - <<"/"/utf8, _/binary>> when Size =:= 0 -> - parse_authority_with_slashes(Uri_string, Pieces); - - <<"/"/utf8, _/binary>> -> - Scheme = binary:part(Original, 0, Size), - Pieces@1 = {uri, - {some, string:lowercase(Scheme)}, - erlang:element(3, Pieces), - erlang:element(4, Pieces), - erlang:element(5, Pieces), - erlang:element(6, Pieces), - erlang:element(7, Pieces), - erlang:element(8, Pieces)}, - parse_authority_with_slashes(Uri_string, Pieces@1); - - <<"?"/utf8, Rest/binary>> when Size =:= 0 -> - parse_query_with_question_mark(Rest, Pieces); - - <<"?"/utf8, Rest@1/binary>> -> - Scheme@1 = binary:part(Original, 0, Size), - Pieces@2 = {uri, - {some, string:lowercase(Scheme@1)}, - erlang:element(3, Pieces), - erlang:element(4, Pieces), - erlang:element(5, Pieces), - erlang:element(6, Pieces), - erlang:element(7, Pieces), - erlang:element(8, Pieces)}, - parse_query_with_question_mark(Rest@1, Pieces@2); - - <<"#"/utf8, Rest@2/binary>> when Size =:= 0 -> - parse_fragment(Rest@2, Pieces); - - <<"#"/utf8, Rest@3/binary>> -> - Scheme@2 = binary:part(Original, 0, Size), - Pieces@3 = {uri, - {some, string:lowercase(Scheme@2)}, - erlang:element(3, Pieces), - erlang:element(4, Pieces), - erlang:element(5, Pieces), - erlang:element(6, Pieces), - erlang:element(7, Pieces), - erlang:element(8, Pieces)}, - parse_fragment(Rest@3, Pieces@3); - - <<":"/utf8, _/binary>> when Size =:= 0 -> - {error, nil}; - - <<":"/utf8, Rest@4/binary>> -> - Scheme@3 = binary:part(Original, 0, Size), - Pieces@4 = {uri, - {some, string:lowercase(Scheme@3)}, - erlang:element(3, Pieces), - erlang:element(4, Pieces), - erlang:element(5, Pieces), - erlang:element(6, Pieces), - erlang:element(7, Pieces), - erlang:element(8, Pieces)}, - parse_authority_with_slashes(Rest@4, Pieces@4); - - <<""/utf8>> -> - {ok, - {uri, - erlang:element(2, Pieces), - erlang:element(3, Pieces), - erlang:element(4, Pieces), - erlang:element(5, Pieces), - Original, - erlang:element(7, Pieces), - erlang:element(8, Pieces)}}; - - _ -> - {_, Rest@5} = gleam_stdlib:string_pop_codeunit(Uri_string), - parse_scheme_loop(Original, Rest@5, Pieces, Size + 1) - end. - --file("src/gleam/uri.gleam", 537). -?DOC( - " Parses an urlencoded query string into a list of key value pairs.\n" - " Returns an error for invalid encoding.\n" - "\n" - " The opposite operation is `uri.query_to_string`.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " parse_query(\"a=1&b=2\")\n" - " // -> Ok([#(\"a\", \"1\"), #(\"b\", \"2\")])\n" - " ```\n" -). --spec parse_query(binary()) -> {ok, list({binary(), binary()})} | {error, nil}. -parse_query(Query) -> - gleam_stdlib:parse_query(Query). - --file("src/gleam/uri.gleam", 573). -?DOC( - " Encodes a string into a percent encoded representation.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " percent_encode(\"100% great\")\n" - " // -> \"100%25%20great\"\n" - " ```\n" -). --spec percent_encode(binary()) -> binary(). -percent_encode(Value) -> - gleam_stdlib:percent_encode(Value). - --file("src/gleam/uri.gleam", 558). --spec query_pair({binary(), binary()}) -> gleam@string_tree:string_tree(). -query_pair(Pair) -> - gleam_stdlib:identity( - [gleam_stdlib:percent_encode(erlang:element(1, Pair)), - <<"="/utf8>>, - gleam_stdlib:percent_encode(erlang:element(2, Pair))] - ). - --file("src/gleam/uri.gleam", 550). -?DOC( - " Encodes a list of key value pairs as a URI query string.\n" - "\n" - " The opposite operation is `uri.parse_query`.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " query_to_string([#(\"a\", \"1\"), #(\"b\", \"2\")])\n" - " // -> \"a=1&b=2\"\n" - " ```\n" -). --spec query_to_string(list({binary(), binary()})) -> binary(). -query_to_string(Query) -> - _pipe = Query, - _pipe@1 = gleam@list:map(_pipe, fun query_pair/1), - _pipe@2 = gleam@list:intersperse( - _pipe@1, - gleam_stdlib:identity(<<"&"/utf8>>) - ), - _pipe@3 = gleam_stdlib:identity(_pipe@2), - unicode:characters_to_binary(_pipe@3). - --file("src/gleam/uri.gleam", 586). -?DOC( - " Decodes a percent encoded string.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " percent_decode(\"100%25%20great+fun\")\n" - " // -> Ok(\"100% great+fun\")\n" - " ```\n" -). --spec percent_decode(binary()) -> {ok, binary()} | {error, nil}. -percent_decode(Value) -> - gleam_stdlib:percent_decode(Value). - --file("src/gleam/uri.gleam", 608). --spec remove_dot_segments_loop(list(binary()), list(binary())) -> list(binary()). -remove_dot_segments_loop(Input, Accumulator) -> - case Input of - [] -> - lists:reverse(Accumulator); - - [Segment | Rest] -> - Accumulator@5 = case {Segment, Accumulator} of - {<<""/utf8>>, Accumulator@1} -> - Accumulator@1; - - {<<"."/utf8>>, Accumulator@2} -> - Accumulator@2; - - {<<".."/utf8>>, []} -> - []; - - {<<".."/utf8>>, [_ | Accumulator@3]} -> - Accumulator@3; - - {Segment@1, Accumulator@4} -> - [Segment@1 | Accumulator@4] - end, - remove_dot_segments_loop(Rest, Accumulator@5) - end. - --file("src/gleam/uri.gleam", 604). --spec remove_dot_segments(list(binary())) -> list(binary()). -remove_dot_segments(Input) -> - remove_dot_segments_loop(Input, []). - --file("src/gleam/uri.gleam", 600). -?DOC( - " Splits the path section of a URI into it's constituent segments.\n" - "\n" - " Removes empty segments and resolves dot-segments as specified in\n" - " [section 5.2](https://www.ietf.org/rfc/rfc3986.html#section-5.2) of the RFC.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " path_segments(\"/users/1\")\n" - " // -> [\"users\" ,\"1\"]\n" - " ```\n" -). --spec path_segments(binary()) -> list(binary()). -path_segments(Path) -> - remove_dot_segments(gleam@string:split(Path, <<"/"/utf8>>)). - --file("src/gleam/uri.gleam", 639). -?DOC( - " Encodes a `Uri` value as a URI string.\n" - "\n" - " The opposite operation is `uri.parse`.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " let uri = Uri(..empty, scheme: Some(\"https\"), host: Some(\"example.com\"))\n" - " to_string(uri)\n" - " // -> \"https://example.com\"\n" - " ```\n" -). --spec to_string(uri()) -> binary(). -to_string(Uri) -> - Parts = case erlang:element(8, Uri) of - {some, Fragment} -> - [<<"#"/utf8>>, Fragment]; - - none -> - [] - end, - Parts@1 = case erlang:element(7, Uri) of - {some, Query} -> - [<<"?"/utf8>>, Query | Parts]; - - none -> - Parts - end, - Parts@2 = [erlang:element(6, Uri) | Parts@1], - Parts@3 = case {erlang:element(4, Uri), - gleam_stdlib:string_starts_with(erlang:element(6, Uri), <<"/"/utf8>>)} of - {{some, Host}, false} when Host =/= <<""/utf8>> -> - [<<"/"/utf8>> | Parts@2]; - - {_, _} -> - Parts@2 - end, - Parts@4 = case {erlang:element(4, Uri), erlang:element(5, Uri)} of - {{some, _}, {some, Port}} -> - [<<":"/utf8>>, erlang:integer_to_binary(Port) | Parts@3]; - - {_, _} -> - Parts@3 - end, - Parts@5 = case {erlang:element(2, Uri), - erlang:element(3, Uri), - erlang:element(4, Uri)} of - {{some, S}, {some, U}, {some, H}} -> - [S, <<"://"/utf8>>, U, <<"@"/utf8>>, H | Parts@4]; - - {{some, S@1}, none, {some, H@1}} -> - [S@1, <<"://"/utf8>>, H@1 | Parts@4]; - - {{some, S@2}, {some, _}, none} -> - [S@2, <<":"/utf8>> | Parts@4]; - - {{some, S@2}, none, none} -> - [S@2, <<":"/utf8>> | Parts@4]; - - {none, none, {some, H@2}} -> - [<<"//"/utf8>>, H@2 | Parts@4]; - - {_, _, _} -> - Parts@4 - end, - erlang:list_to_binary(Parts@5). - --file("src/gleam/uri.gleam", 683). -?DOC( - " Fetches the origin of a URI.\n" - "\n" - " Returns the origin of a uri as defined in\n" - " [RFC 6454](https://tools.ietf.org/html/rfc6454)\n" - "\n" - " The supported URI schemes are `http` and `https`.\n" - " URLs without a scheme will return `Error`.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " let assert Ok(uri) = parse(\"https://example.com/path?foo#bar\")\n" - " origin(uri)\n" - " // -> Ok(\"https://example.com\")\n" - " ```\n" -). --spec origin(uri()) -> {ok, binary()} | {error, nil}. -origin(Uri) -> - {uri, Scheme, _, Host, Port, _, _, _} = Uri, - case {Host, Scheme} of - {{some, H}, {some, <<"https"/utf8>>}} when Port =:= {some, 443} -> - {ok, erlang:list_to_binary([<<"https://"/utf8>>, H])}; - - {{some, H@1}, {some, <<"http"/utf8>>}} when Port =:= {some, 80} -> - {ok, erlang:list_to_binary([<<"http://"/utf8>>, H@1])}; - - {{some, H@2}, {some, S}} when (S =:= <<"http"/utf8>>) orelse (S =:= <<"https"/utf8>>) -> - case Port of - {some, P} -> - {ok, - erlang:list_to_binary( - [S, - <<"://"/utf8>>, - H@2, - <<":"/utf8>>, - erlang:integer_to_binary(P)] - )}; - - none -> - {ok, erlang:list_to_binary([S, <<"://"/utf8>>, H@2])} - end; - - {_, _} -> - {error, nil} - end. - --file("src/gleam/uri.gleam", 764). --spec drop_last(list(DDO)) -> list(DDO). -drop_last(Elements) -> - gleam@list:take(Elements, erlang:length(Elements) - 1). - --file("src/gleam/uri.gleam", 768). --spec join_segments(list(binary())) -> binary(). -join_segments(Segments) -> - gleam@string:join([<<""/utf8>> | Segments], <<"/"/utf8>>). - --file("src/gleam/uri.gleam", 706). -?DOC( - " Resolves a URI with respect to the given base URI.\n" - "\n" - " The base URI must be an absolute URI or this function will return an error.\n" - " The algorithm for merging uris is described in\n" - " [RFC 3986](https://tools.ietf.org/html/rfc3986#section-5.2).\n" -). --spec merge(uri(), uri()) -> {ok, uri()} | {error, nil}. -merge(Base, Relative) -> - case Base of - {uri, {some, _}, _, {some, _}, _, _, _, _} -> - case Relative of - {uri, _, _, {some, _}, _, _, _, _} -> - Path = begin - _pipe = erlang:element(6, Relative), - _pipe@1 = gleam@string:split(_pipe, <<"/"/utf8>>), - _pipe@2 = remove_dot_segments(_pipe@1), - join_segments(_pipe@2) - end, - Resolved = {uri, - gleam@option:'or'( - erlang:element(2, Relative), - erlang:element(2, Base) - ), - none, - erlang:element(4, Relative), - gleam@option:'or'( - erlang:element(5, Relative), - erlang:element(5, Base) - ), - Path, - erlang:element(7, Relative), - erlang:element(8, Relative)}, - {ok, Resolved}; - - _ -> - {New_path, New_query} = case erlang:element(6, Relative) of - <<""/utf8>> -> - {erlang:element(6, Base), - gleam@option:'or'( - erlang:element(7, Relative), - erlang:element(7, Base) - )}; - - _ -> - Path_segments = case gleam_stdlib:string_starts_with( - erlang:element(6, Relative), - <<"/"/utf8>> - ) of - true -> - gleam@string:split( - erlang:element(6, Relative), - <<"/"/utf8>> - ); - - false -> - _pipe@3 = erlang:element(6, Base), - _pipe@4 = gleam@string:split( - _pipe@3, - <<"/"/utf8>> - ), - _pipe@5 = drop_last(_pipe@4), - lists:append( - _pipe@5, - gleam@string:split( - erlang:element(6, Relative), - <<"/"/utf8>> - ) - ) - end, - Path@1 = begin - _pipe@6 = Path_segments, - _pipe@7 = remove_dot_segments(_pipe@6), - join_segments(_pipe@7) - end, - {Path@1, erlang:element(7, Relative)} - end, - Resolved@1 = {uri, - erlang:element(2, Base), - none, - erlang:element(4, Base), - erlang:element(5, Base), - New_path, - New_query, - erlang:element(8, Relative)}, - {ok, Resolved@1} - end; - - _ -> - {error, nil} - end. - --file("src/gleam/uri.gleam", 81). -?DOC( - " Parses a compliant URI string into the `Uri` Type.\n" - " If the string is not a valid URI string then an error is returned.\n" - "\n" - " The opposite operation is `uri.to_string`.\n" - "\n" - " ## Examples\n" - "\n" - " ```gleam\n" - " parse(\"https://example.com:1234/a/b?query=true#fragment\")\n" - " // -> Ok(\n" - " // Uri(\n" - " // scheme: Some(\"https\"),\n" - " // userinfo: None,\n" - " // host: Some(\"example.com\"),\n" - " // port: Some(1234),\n" - " // path: \"/a/b\",\n" - " // query: Some(\"query=true\"),\n" - " // fragment: Some(\"fragment\")\n" - " // )\n" - " // )\n" - " ```\n" -). --spec parse(binary()) -> {ok, uri()} | {error, nil}. -parse(Uri_string) -> - gleam_stdlib:uri_parse(Uri_string). diff --git a/build/packages/gleam_stdlib/src/gleam_stdlib.app.src b/build/packages/gleam_stdlib/src/gleam_stdlib.app.src deleted file mode 100644 index 761251e..0000000 --- a/build/packages/gleam_stdlib/src/gleam_stdlib.app.src +++ /dev/null @@ -1,31 +0,0 @@ -{application, gleam_stdlib, [ - {vsn, "0.65.0"}, - {applications, []}, - {description, "A standard library for the Gleam programming language"}, - {modules, [gleam@bit_array, - gleam@bool, - gleam@bytes_tree, - gleam@dict, - gleam@dynamic, - gleam@dynamic@decode, - gleam@float, - gleam@function, - gleam@int, - gleam@io, - gleam@list, - gleam@option, - gleam@order, - gleam@pair, - gleam@result, - gleam@set, - gleam@string, - gleam@string_tree, - gleam@uri, - gleam_stdlib, - gleam_stdlib@@main, - gleam_stdlib_test_ffi, - gleeunit_ffi, - gleeunit_gleam_panic_ffi, - gleeunit_progress]}, - {registered, []} -]}. diff --git a/build/packages/gleam_stdlib/src/gleam_stdlib.erl b/build/packages/gleam_stdlib/src/gleam_stdlib.erl deleted file mode 100644 index 2c416f4..0000000 --- a/build/packages/gleam_stdlib/src/gleam_stdlib.erl +++ /dev/null @@ -1,534 +0,0 @@ --module(gleam_stdlib). - --export([ - map_get/2, iodata_append/2, identity/1, parse_int/1, parse_float/1, - less_than/2, string_pop_grapheme/1, string_pop_codeunit/1, - string_starts_with/2, wrap_list/1, string_ends_with/2, string_pad/4, - uri_parse/1, bit_array_slice/3, percent_encode/1, percent_decode/1, - base64_decode/1, parse_query/1, bit_array_concat/1, - base64_encode/2, tuple_get/2, classify_dynamic/1, print/1, - println/1, print_error/1, println_error/1, inspect/1, float_to_string/1, - int_from_base_string/2, utf_codepoint_list_to_string/1, contains_string/2, - crop_string/2, base16_encode/1, base16_decode/1, string_replace/3, slice/3, - bit_array_to_int_and_size/1, bit_array_pad_to_bytes/1, index/2, list/5, - dict/1, int/1, float/1, bit_array/1, is_null/1 -]). - -%% Taken from OTP's uri_string module --define(DEC2HEX(X), - if ((X) >= 0) andalso ((X) =< 9) -> (X) + $0; - ((X) >= 10) andalso ((X) =< 15) -> (X) + $A - 10 - end). - -%% Taken from OTP's uri_string module --define(HEX2DEC(X), - if ((X) >= $0) andalso ((X) =< $9) -> (X) - $0; - ((X) >= $A) andalso ((X) =< $F) -> (X) - $A + 10; - ((X) >= $a) andalso ((X) =< $f) -> (X) - $a + 10 - end). - --define(is_lowercase_char(X), - (X > 96 andalso X < 123)). --define(is_underscore_char(X), - (X == 95)). --define(is_digit_char(X), - (X > 47 andalso X < 58)). --define(is_ascii_character(X), - (erlang:is_integer(X) andalso X >= 32 andalso X =< 126)). - -uppercase(X) -> X - 32. - -map_get(Map, Key) -> - case maps:find(Key, Map) of - error -> {error, nil}; - OkFound -> OkFound - end. - -iodata_append(Iodata, String) -> [Iodata, String]. - -identity(X) -> X. - -classify_dynamic(nil) -> <<"Nil">>; -classify_dynamic(null) -> <<"Nil">>; -classify_dynamic(undefined) -> <<"Nil">>; -classify_dynamic(X) when is_boolean(X) -> <<"Bool">>; -classify_dynamic(X) when is_atom(X) -> <<"Atom">>; -classify_dynamic(X) when is_binary(X) -> <<"String">>; -classify_dynamic(X) when is_bitstring(X) -> <<"BitArray">>; -classify_dynamic(X) when is_integer(X) -> <<"Int">>; -classify_dynamic(X) when is_float(X) -> <<"Float">>; -classify_dynamic(X) when is_list(X) -> <<"List">>; -classify_dynamic(X) when is_map(X) -> <<"Dict">>; -classify_dynamic(X) when is_tuple(X) -> <<"Array">>; -classify_dynamic(X) when is_reference(X) -> <<"Reference">>; -classify_dynamic(X) when is_pid(X) -> <<"Pid">>; -classify_dynamic(X) when is_port(X) -> <<"Port">>; -classify_dynamic(X) when - is_function(X, 0) orelse is_function(X, 1) orelse is_function(X, 2) orelse - is_function(X, 3) orelse is_function(X, 4) orelse is_function(X, 5) orelse - is_function(X, 6) orelse is_function(X, 7) orelse is_function(X, 8) orelse - is_function(X, 9) orelse is_function(X, 10) orelse is_function(X, 11) orelse - is_function(X, 12) -> <<"Function">>; -classify_dynamic(_) -> <<"Unknown">>. - -tuple_get(_tup, Index) when Index < 0 -> {error, nil}; -tuple_get(Data, Index) when Index >= tuple_size(Data) -> {error, nil}; -tuple_get(Data, Index) -> {ok, element(Index + 1, Data)}. - -int_from_base_string(String, Base) -> - case catch binary_to_integer(String, Base) of - Int when is_integer(Int) -> {ok, Int}; - _ -> {error, nil} - end. - -parse_int(String) -> - case catch binary_to_integer(String) of - Int when is_integer(Int) -> {ok, Int}; - _ -> {error, nil} - end. - -parse_float(String) -> - case catch binary_to_float(String) of - Float when is_float(Float) -> {ok, Float}; - _ -> {error, nil} - end. - -less_than(Lhs, Rhs) -> - Lhs < Rhs. - -string_starts_with(_, <<>>) -> true; -string_starts_with(String, Prefix) when byte_size(Prefix) > byte_size(String) -> false; -string_starts_with(String, Prefix) -> - PrefixSize = byte_size(Prefix), - Prefix == binary_part(String, 0, PrefixSize). - -string_ends_with(_, <<>>) -> true; -string_ends_with(String, Suffix) when byte_size(Suffix) > byte_size(String) -> false; -string_ends_with(String, Suffix) -> - SuffixSize = byte_size(Suffix), - Suffix == binary_part(String, byte_size(String) - SuffixSize, SuffixSize). - -string_pad(String, Length, Dir, PadString) -> - Chars = string:pad(String, Length, Dir, binary_to_list(PadString)), - case unicode:characters_to_binary(Chars) of - Bin when is_binary(Bin) -> Bin; - Error -> erlang:error({gleam_error, {string_invalid_utf8, Error}}) - end. - -string_pop_grapheme(String) -> - case string:next_grapheme(String) of - [ Next | Rest ] when is_binary(Rest) -> - {ok, {unicode:characters_to_binary([Next]), Rest}}; - - [ Next | Rest ] -> - {ok, {unicode:characters_to_binary([Next]), unicode:characters_to_binary(Rest)}}; - - _ -> {error, nil} - end. - -string_pop_codeunit(<>) -> {Cp, Rest}; -string_pop_codeunit(Binary) -> {0, Binary}. - -bit_array_pad_to_bytes(Bin) -> - case erlang:bit_size(Bin) rem 8 of - 0 -> Bin; - TrailingBits -> - PaddingBits = 8 - TrailingBits, - <> - end. - -bit_array_concat(BitArrays) -> - list_to_bitstring(BitArrays). - --if(?OTP_RELEASE >= 26). -base64_encode(Bin, Padding) -> - PaddedBin = bit_array_pad_to_bytes(Bin), - base64:encode(PaddedBin, #{padding => Padding}). --else. -base64_encode(_Bin, _Padding) -> - erlang:error(<<"Erlang OTP/26 or higher is required to use base64:encode">>). --endif. - -bit_array_slice(Bin, Pos, Len) -> - try {ok, binary:part(Bin, Pos, Len)} - catch error:badarg -> {error, nil} - end. - -base64_decode(S) -> - try {ok, base64:decode(S)} - catch error:_ -> {error, nil} - end. - -wrap_list(X) when is_list(X) -> X; -wrap_list(X) -> [X]. - -parse_query(Query) -> - case uri_string:dissect_query(Query) of - {error, _, _} -> {error, nil}; - Pairs -> - Pairs1 = lists:map(fun - ({K, true}) -> {K, <<"">>}; - (Pair) -> Pair - end, Pairs), - {ok, Pairs1} - end. - -percent_encode(B) -> percent_encode(B, <<>>). -percent_encode(<<>>, Acc) -> - Acc; -percent_encode(<>, Acc) -> - case percent_ok(H) of - true -> - percent_encode(T, <>); - false -> - <> = <>, - percent_encode(T, <>) - end. - -percent_decode(Cs) -> percent_decode(Cs, <<>>). -percent_decode(<<$%, C0, C1, Cs/binary>>, Acc) -> - case is_hex_digit(C0) andalso is_hex_digit(C1) of - true -> - B = ?HEX2DEC(C0)*16+?HEX2DEC(C1), - percent_decode(Cs, <>); - false -> - {error, nil} - end; -percent_decode(<>, Acc) -> - percent_decode(Cs, <>); -percent_decode(<<>>, Acc) -> - check_utf8(Acc). - -percent_ok($!) -> true; -percent_ok($$) -> true; -percent_ok($') -> true; -percent_ok($() -> true; -percent_ok($)) -> true; -percent_ok($*) -> true; -percent_ok($+) -> true; -percent_ok($-) -> true; -percent_ok($.) -> true; -percent_ok($_) -> true; -percent_ok($~) -> true; -percent_ok(C) when $0 =< C, C =< $9 -> true; -percent_ok(C) when $A =< C, C =< $Z -> true; -percent_ok(C) when $a =< C, C =< $z -> true; -percent_ok(_) -> false. - -is_hex_digit(C) -> - ($0 =< C andalso C =< $9) orelse ($a =< C andalso C =< $f) orelse ($A =< C andalso C =< $F). - -check_utf8(Cs) -> - case unicode:characters_to_list(Cs) of - {incomplete, _, _} -> {error, nil}; - {error, _, _} -> {error, nil}; - _ -> {ok, Cs} - end. - -uri_parse(String) -> - case uri_string:parse(String) of - {error, _, _} -> {error, nil}; - Uri -> - Port = - try maps:get(port, Uri) of - undefined -> none; - Value -> {some, Value} - catch _:_ -> none - end, - {ok, {uri, - maps_get_optional(Uri, scheme), - maps_get_optional(Uri, userinfo), - maps_get_optional(Uri, host), - Port, - maps_get_or(Uri, path, <<>>), - maps_get_optional(Uri, query), - maps_get_optional(Uri, fragment) - }} - end. - -maps_get_optional(Map, Key) -> - try {some, maps:get(Key, Map)} - catch _:_ -> none - end. - -maps_get_or(Map, Key, Default) -> - try maps:get(Key, Map) - catch _:_ -> Default - end. - -print(String) -> - io:put_chars(String), - nil. - -println(String) -> - io:put_chars([String, $\n]), - nil. - -print_error(String) -> - io:put_chars(standard_error, String), - nil. - -println_error(String) -> - io:put_chars(standard_error, [String, $\n]), - nil. - -inspect(true) -> - "True"; -inspect(false) -> - "False"; -inspect(nil) -> - "Nil"; -inspect(Data) when is_map(Data) -> - Fields = [ - [<<"#(">>, inspect(Key), <<", ">>, inspect(Value), <<")">>] - || {Key, Value} <- maps:to_list(Data) - ], - ["dict.from_list([", lists:join(", ", Fields), "])"]; -inspect(Atom) when is_atom(Atom) -> - erlang:element(2, inspect_atom(Atom)); -inspect(Any) when is_integer(Any) -> - erlang:integer_to_list(Any); -inspect(Any) when is_float(Any) -> - io_lib_format:fwrite_g(Any); -inspect(Binary) when is_binary(Binary) -> - case inspect_maybe_utf8_string(Binary, <<>>) of - {ok, InspectedUtf8String} -> InspectedUtf8String; - {error, not_a_utf8_string} -> - Segments = [erlang:integer_to_list(X) || <> <= Binary], - ["<<", lists:join(", ", Segments), ">>"] - end; -inspect(Bits) when is_bitstring(Bits) -> - inspect_bit_array(Bits); -inspect(List) when is_list(List) -> - case inspect_list(List, true) of - {charlist, _} -> ["charlist.from_string(\"", list_to_binary(List), "\")"]; - {proper, Elements} -> ["[", Elements, "]"]; - {improper, Elements} -> ["//erl([", Elements, "])"] - end; -inspect(Any) when is_tuple(Any) % Record constructors - andalso is_atom(element(1, Any)) - andalso element(1, Any) =/= false - andalso element(1, Any) =/= true - andalso element(1, Any) =/= nil --> - [Atom | ArgsList] = erlang:tuple_to_list(Any), - InspectedArgs = lists:map(fun inspect/1, ArgsList), - case inspect_atom(Atom) of - {gleam_atom, GleamAtom} -> - Args = lists:join(<<", ">>, InspectedArgs), - [GleamAtom, "(", Args, ")"]; - {erlang_atom, ErlangAtom} -> - Args = lists:join(<<", ">>, [ErlangAtom | InspectedArgs]), - ["#(", Args, ")"] - end; -inspect(Tuple) when is_tuple(Tuple) -> - Elements = lists:map(fun inspect/1, erlang:tuple_to_list(Tuple)), - ["#(", lists:join(", ", Elements), ")"]; -inspect(Any) when is_function(Any) -> - {arity, Arity} = erlang:fun_info(Any, arity), - ArgsAsciiCodes = lists:seq($a, $a + Arity - 1), - Args = lists:join(<<", ">>, - lists:map(fun(Arg) -> <> end, ArgsAsciiCodes) - ), - ["//fn(", Args, ") { ... }"]; -inspect(Any) -> - ["//erl(", io_lib:format("~p", [Any]), ")"]. - -inspect_atom(Atom) -> - Binary = erlang:atom_to_binary(Atom), - case inspect_maybe_gleam_atom(Binary, none, <<>>) of - {ok, Inspected} -> {gleam_atom, Inspected}; - {error, _} -> {erlang_atom, ["atom.create(\"", Binary, "\")"]} - end. - -inspect_maybe_gleam_atom(<<>>, none, _) -> - {error, nil}; -inspect_maybe_gleam_atom(<>, none, _) when ?is_digit_char(First) -> - {error, nil}; -inspect_maybe_gleam_atom(<<"_", _Rest/binary>>, none, _) -> - {error, nil}; -inspect_maybe_gleam_atom(<<"_">>, _PrevChar, _Acc) -> - {error, nil}; -inspect_maybe_gleam_atom(<<"_", _Rest/binary>>, $_, _Acc) -> - {error, nil}; -inspect_maybe_gleam_atom(<>, _PrevChar, _Acc) - when not (?is_lowercase_char(First) orelse ?is_underscore_char(First) orelse ?is_digit_char(First)) -> - {error, nil}; -inspect_maybe_gleam_atom(<>, none, Acc) -> - inspect_maybe_gleam_atom(Rest, First, <>); -inspect_maybe_gleam_atom(<<"_", Rest/binary>>, _PrevChar, Acc) -> - inspect_maybe_gleam_atom(Rest, $_, Acc); -inspect_maybe_gleam_atom(<>, $_, Acc) -> - inspect_maybe_gleam_atom(Rest, First, <>); -inspect_maybe_gleam_atom(<>, _PrevChar, Acc) -> - inspect_maybe_gleam_atom(Rest, First, <>); -inspect_maybe_gleam_atom(<<>>, _PrevChar, Acc) -> - {ok, Acc}; -inspect_maybe_gleam_atom(A, B, C) -> - erlang:display({A, B, C}), - throw({gleam_error, A, B, C}). - -inspect_list([], _) -> - {proper, []}; -inspect_list([First], true) when ?is_ascii_character(First) -> - {charlist, nil}; -inspect_list([First], _) -> - {proper, [inspect(First)]}; -inspect_list([First | Rest], ValidCharlist) when is_list(Rest) -> - StillValidCharlist = ValidCharlist andalso ?is_ascii_character(First), - {Kind, Inspected} = inspect_list(Rest, StillValidCharlist), - {Kind, [inspect(First), <<", ">> | Inspected]}; -inspect_list([First | ImproperTail], _) -> - {improper, [inspect(First), <<" | ">>, inspect(ImproperTail)]}. - -inspect_bit_array(Bits) -> - Text = inspect_bit_array(Bits, <<"<<">>), - <>">>. - -inspect_bit_array(<<>>, Acc) -> - Acc; -inspect_bit_array(<>, Acc) -> - inspect_bit_array(Rest, append_segment(Acc, erlang:integer_to_binary(X))); -inspect_bit_array(Rest, Acc) -> - Size = bit_size(Rest), - <> = Rest, - X1 = erlang:integer_to_binary(X), - Size1 = erlang:integer_to_binary(Size), - Segment = <>, - inspect_bit_array(<<>>, append_segment(Acc, Segment)). - -bit_array_to_int_and_size(A) -> - Size = bit_size(A), - <> = A, - {A1, Size}. - -append_segment(<<"<<">>, Segment) -> - <<"<<", Segment/binary>>; -append_segment(Acc, Segment) -> - <>. - - -inspect_maybe_utf8_string(Binary, Acc) -> - case Binary of - <<>> -> {ok, <<$", Acc/binary, $">>}; - <> -> - Escaped = case First of - $" -> <<$\\, $">>; - $\\ -> <<$\\, $\\>>; - $\r -> <<$\\, $r>>; - $\n -> <<$\\, $n>>; - $\t -> <<$\\, $t>>; - $\f -> <<$\\, $f>>; - X when X > 126, X < 160 -> convert_to_u(X); - X when X < 32 -> convert_to_u(X); - Other -> <> - end, - inspect_maybe_utf8_string(Rest, <>); - _ -> {error, not_a_utf8_string} - end. - -convert_to_u(Code) -> - list_to_binary(io_lib:format("\\u{~4.16.0B}", [Code])). - -float_to_string(Float) when is_float(Float) -> - erlang:iolist_to_binary(io_lib_format:fwrite_g(Float)). - -utf_codepoint_list_to_string(List) -> - case unicode:characters_to_binary(List) of - {error, _} -> erlang:error({gleam_error, {string_invalid_utf8, List}}); - Binary -> Binary - end. - -crop_string(String, Prefix) -> - case string:find(String, Prefix) of - nomatch -> String; - New -> New - end. - -contains_string(String, Substring) -> - is_bitstring(string:find(String, Substring)). - -base16_encode(Bin) -> - PaddedBin = bit_array_pad_to_bytes(Bin), - binary:encode_hex(PaddedBin). - -base16_decode(String) -> - try - {ok, binary:decode_hex(String)} - catch - _:_ -> {error, nil} - end. - -string_replace(String, Pattern, Replacement) -> - string:replace(String, Pattern, Replacement, all). - -slice(String, Index, Length) -> - case string:slice(String, Index, Length) of - X when is_binary(X) -> X; - X when is_list(X) -> unicode:characters_to_binary(X) - end. - -index([X | _], 0) -> - {ok, {some, X}}; -index([_, X | _], 1) -> - {ok, {some, X}}; -index([_, _, X | _], 2) -> - {ok, {some, X}}; -index([_, _, _, X | _], 3) -> - {ok, {some, X}}; -index([_, _, _, _, X | _], 4) -> - {ok, {some, X}}; -index([_, _, _, _, _, X | _], 5) -> - {ok, {some, X}}; -index([_, _, _, _, _, _, X | _], 6) -> - {ok, {some, X}}; -index([_, _, _, _, _, _, _, X | _], 7) -> - {ok, {some, X}}; -index(Tuple, Index) when is_tuple(Tuple) andalso is_integer(Index) -> - {ok, try - {some, element(Index + 1, Tuple)} - catch _:_ -> - none - end}; -index(Map, Key) when is_map(Map) -> - {ok, try - {some, maps:get(Key, Map)} - catch _:_ -> - none - end}; -index(_, Index) when is_integer(Index) -> - {error, <<"Indexable">>}; -index(_, _) -> - {error, <<"Dict">>}. - -list(T, A, B, C, D) when is_tuple(T) -> - list(tuple_to_list(T), A, B, C, D); -list([], _, _, _, Acc) -> - {lists:reverse(Acc), []}; -list([X | Xs], Decode, PushPath, Index, Acc) -> - {Out, Errors} = Decode(X), - case Errors of - [] -> list(Xs, Decode, PushPath, Index + 1, [Out | Acc]); - _ -> PushPath({[], Errors}, integer_to_binary(Index)) - end; -list(Unexpected, _, _, _, []) -> - Found = gleam@dynamic:classify(Unexpected), - Error = {decode_error, <<"List"/utf8>>, Found, []}, - {[], [Error]}; -list(_, _, _, _, Acc) -> - {lists:reverse(Acc), []}. - -dict(#{} = Data) -> {ok, Data}; -dict(_) -> {error, nil}. - -int(I) when is_integer(I) -> {ok, I}; -int(_) -> {error, 0}. - -float(F) when is_float(F) -> {ok, F}; -float(_) -> {error, 0.0}. - -bit_array(B) when is_bitstring(B) -> {ok, B}; -bit_array(_) -> {error, <<>>}. - -is_null(X) -> - X =:= undefined orelse X =:= null orelse X =:= nil. diff --git a/build/packages/gleam_stdlib/src/gleam_stdlib.mjs b/build/packages/gleam_stdlib/src/gleam_stdlib.mjs deleted file mode 100644 index ebac45f..0000000 --- a/build/packages/gleam_stdlib/src/gleam_stdlib.mjs +++ /dev/null @@ -1,1048 +0,0 @@ -import { - BitArray, - Error, - List, - Ok, - Result, - UtfCodepoint, - stringBits, - toBitArray, - bitArraySlice, - NonEmpty, - Empty, - CustomType, -} from "./gleam.mjs"; -import { Some, None } from "./gleam/option.mjs"; -import Dict from "./dict.mjs"; -import { classify } from "./gleam/dynamic.mjs"; -import { DecodeError } from "./gleam/dynamic/decode.mjs"; - -const Nil = undefined; -const NOT_FOUND = {}; - -export function identity(x) { - return x; -} - -export function parse_int(value) { - if (/^[-+]?(\d+)$/.test(value)) { - return new Ok(parseInt(value)); - } else { - return new Error(Nil); - } -} - -export function parse_float(value) { - if (/^[-+]?(\d+)\.(\d+)([eE][-+]?\d+)?$/.test(value)) { - return new Ok(parseFloat(value)); - } else { - return new Error(Nil); - } -} - -export function to_string(term) { - return term.toString(); -} - -export function int_to_base_string(int, base) { - return int.toString(base).toUpperCase(); -} - -const int_base_patterns = { - 2: /[^0-1]/, - 3: /[^0-2]/, - 4: /[^0-3]/, - 5: /[^0-4]/, - 6: /[^0-5]/, - 7: /[^0-6]/, - 8: /[^0-7]/, - 9: /[^0-8]/, - 10: /[^0-9]/, - 11: /[^0-9a]/, - 12: /[^0-9a-b]/, - 13: /[^0-9a-c]/, - 14: /[^0-9a-d]/, - 15: /[^0-9a-e]/, - 16: /[^0-9a-f]/, - 17: /[^0-9a-g]/, - 18: /[^0-9a-h]/, - 19: /[^0-9a-i]/, - 20: /[^0-9a-j]/, - 21: /[^0-9a-k]/, - 22: /[^0-9a-l]/, - 23: /[^0-9a-m]/, - 24: /[^0-9a-n]/, - 25: /[^0-9a-o]/, - 26: /[^0-9a-p]/, - 27: /[^0-9a-q]/, - 28: /[^0-9a-r]/, - 29: /[^0-9a-s]/, - 30: /[^0-9a-t]/, - 31: /[^0-9a-u]/, - 32: /[^0-9a-v]/, - 33: /[^0-9a-w]/, - 34: /[^0-9a-x]/, - 35: /[^0-9a-y]/, - 36: /[^0-9a-z]/, -}; - -export function int_from_base_string(string, base) { - if (int_base_patterns[base].test(string.replace(/^-/, "").toLowerCase())) { - return new Error(Nil); - } - - const result = parseInt(string, base); - - if (isNaN(result)) { - return new Error(Nil); - } - - return new Ok(result); -} - -export function string_replace(string, target, substitute) { - return string.replaceAll(target, substitute); -} - -export function string_reverse(string) { - return [...string].reverse().join(""); -} - -export function string_length(string) { - if (string === "") { - return 0; - } - const iterator = graphemes_iterator(string); - if (iterator) { - let i = 0; - for (const _ of iterator) { - i++; - } - return i; - } else { - return string.match(/./gsu).length; - } -} - -export function graphemes(string) { - const iterator = graphemes_iterator(string); - if (iterator) { - return List.fromArray(Array.from(iterator).map((item) => item.segment)); - } else { - return List.fromArray(string.match(/./gsu)); - } -} - -let segmenter = undefined; - -function graphemes_iterator(string) { - if (globalThis.Intl && Intl.Segmenter) { - segmenter ||= new Intl.Segmenter(); - return segmenter.segment(string)[Symbol.iterator](); - } -} - -export function pop_grapheme(string) { - let first; - const iterator = graphemes_iterator(string); - if (iterator) { - first = iterator.next().value?.segment; - } else { - first = string.match(/./su)?.[0]; - } - if (first) { - return new Ok([first, string.slice(first.length)]); - } else { - return new Error(Nil); - } -} - -export function pop_codeunit(str) { - return [str.charCodeAt(0) | 0, str.slice(1)]; -} - -export function lowercase(string) { - return string.toLowerCase(); -} - -export function uppercase(string) { - return string.toUpperCase(); -} - -export function less_than(a, b) { - return a < b; -} - -export function add(a, b) { - return a + b; -} - -export function split(xs, pattern) { - return List.fromArray(xs.split(pattern)); -} - -export function concat(xs) { - let result = ""; - for (const x of xs) { - result = result + x; - } - return result; -} - -export function length(data) { - return data.length; -} - -export function string_byte_slice(string, index, length) { - return string.slice(index, index + length); -} - -export function string_grapheme_slice(string, idx, len) { - if (len <= 0 || idx >= string.length) { - return ""; - } - - const iterator = graphemes_iterator(string); - if (iterator) { - while (idx-- > 0) { - iterator.next(); - } - - let result = ""; - - while (len-- > 0) { - const v = iterator.next().value; - if (v === undefined) { - break; - } - - result += v.segment; - } - - return result; - } else { - return string - .match(/./gsu) - .slice(idx, idx + len) - .join(""); - } -} - -export function string_codeunit_slice(str, from, length) { - return str.slice(from, from + length); -} -export function crop_string(string, substring) { - return string.substring(string.indexOf(substring)); -} - -export function contains_string(haystack, needle) { - return haystack.indexOf(needle) >= 0; -} - -export function starts_with(haystack, needle) { - return haystack.startsWith(needle); -} - -export function ends_with(haystack, needle) { - return haystack.endsWith(needle); -} - -export function split_once(haystack, needle) { - const index = haystack.indexOf(needle); - if (index >= 0) { - const before = haystack.slice(0, index); - const after = haystack.slice(index + needle.length); - return new Ok([before, after]); - } else { - return new Error(Nil); - } -} - -const unicode_whitespaces = [ - "\u0020", // Space - "\u0009", // Horizontal tab - "\u000A", // Line feed - "\u000B", // Vertical tab - "\u000C", // Form feed - "\u000D", // Carriage return - "\u0085", // Next line - "\u2028", // Line separator - "\u2029", // Paragraph separator -].join(""); - -const trim_start_regex = /* @__PURE__ */ new RegExp( - `^[${unicode_whitespaces}]*`, -); -const trim_end_regex = /* @__PURE__ */ new RegExp(`[${unicode_whitespaces}]*$`); - -export function trim_start(string) { - return string.replace(trim_start_regex, ""); -} - -export function trim_end(string) { - return string.replace(trim_end_regex, ""); -} - -export function bit_array_from_string(string) { - return toBitArray([stringBits(string)]); -} - -export function bit_array_bit_size(bit_array) { - return bit_array.bitSize; -} - -export function bit_array_byte_size(bit_array) { - return bit_array.byteSize; -} - -export function bit_array_pad_to_bytes(bit_array) { - const trailingBitsCount = bit_array.bitSize % 8; - - // If the bit array is a whole number of bytes it can be returned unchanged - if (trailingBitsCount === 0) { - return bit_array; - } - - const finalByte = bit_array.byteAt(bit_array.byteSize - 1); - - // The required final byte has its unused trailing bits set to zero - const unusedBitsCount = 8 - trailingBitsCount; - const correctFinalByte = (finalByte >> unusedBitsCount) << unusedBitsCount; - - // If the unused bits in the final byte are already set to zero then the - // existing buffer can be re-used, avoiding a copy - if (finalByte === correctFinalByte) { - return new BitArray( - bit_array.rawBuffer, - bit_array.byteSize * 8, - bit_array.bitOffset, - ); - } - - // Copy the bit array into a new aligned buffer and set the correct final byte - const buffer = new Uint8Array(bit_array.byteSize); - for (let i = 0; i < buffer.length - 1; i++) { - buffer[i] = bit_array.byteAt(i); - } - buffer[buffer.length - 1] = correctFinalByte; - - return new BitArray(buffer); -} - -export function bit_array_concat(bit_arrays) { - return toBitArray(bit_arrays.toArray()); -} - -export function console_log(term) { - console.log(term); -} - -export function console_error(term) { - console.error(term); -} - -export function crash(message) { - throw new globalThis.Error(message); -} - -export function bit_array_to_string(bit_array) { - // If the bit array isn't a whole number of bytes then return an error - if (bit_array.bitSize % 8 !== 0) { - return new Error(Nil); - } - - try { - const decoder = new TextDecoder("utf-8", { fatal: true }); - - if (bit_array.bitOffset === 0) { - return new Ok(decoder.decode(bit_array.rawBuffer)); - } else { - // The input data isn't aligned, so copy it into a new aligned buffer so - // that TextDecoder can be used - const buffer = new Uint8Array(bit_array.byteSize); - for (let i = 0; i < buffer.length; i++) { - buffer[i] = bit_array.byteAt(i); - } - return new Ok(decoder.decode(buffer)); - } - } catch { - return new Error(Nil); - } -} - -export function print(string) { - if (typeof process === "object" && process.stdout?.write) { - process.stdout.write(string); // We can write without a trailing newline - } else if (typeof Deno === "object") { - Deno.stdout.writeSync(new TextEncoder().encode(string)); // We can write without a trailing newline - } else { - console.log(string); // We're in a browser. Newlines are mandated - } -} - -export function print_error(string) { - if (typeof process === "object" && process.stderr?.write) { - process.stderr.write(string); // We can write without a trailing newline - } else if (typeof Deno === "object") { - Deno.stderr.writeSync(new TextEncoder().encode(string)); // We can write without a trailing newline - } else { - console.error(string); // We're in a browser. Newlines are mandated - } -} - -export function print_debug(string) { - if (typeof process === "object" && process.stderr?.write) { - process.stderr.write(string + "\n"); // If we're in Node.js, use `stderr` - } else if (typeof Deno === "object") { - Deno.stderr.writeSync(new TextEncoder().encode(string + "\n")); // If we're in Deno, use `stderr` - } else { - console.log(string); // Otherwise, use `console.log` (so that it doesn't look like an error) - } -} - -export function ceiling(float) { - return Math.ceil(float); -} - -export function floor(float) { - return Math.floor(float); -} - -export function round(float) { - return Math.round(float); -} - -export function truncate(float) { - return Math.trunc(float); -} - -export function power(base, exponent) { - // It is checked in Gleam that: - // - The base is non-negative and that the exponent is not fractional. - // - The base is non-zero and the exponent is non-negative (otherwise - // the result will essentially be division by zero). - // It can thus be assumed that valid input is passed to the Math.pow - // function and a NaN or Infinity value will not be produced. - return Math.pow(base, exponent); -} - -export function random_uniform() { - const random_uniform_result = Math.random(); - // With round-to-nearest-even behavior, the ranges claimed for the functions below - // (excluding the one for Math.random() itself) aren't exact. - // If extremely large bounds are chosen (2^53 or higher), - // it's possible in extremely rare cases to calculate the usually-excluded upper bound. - // Note that as numbers in JavaScript are IEEE 754 floating point numbers - // See: - // Because of this, we just loop 'until' we get a valid result where 0.0 <= x < 1.0: - if (random_uniform_result === 1.0) { - return random_uniform(); - } - return random_uniform_result; -} - -export function bit_array_slice(bits, position, length) { - const start = Math.min(position, position + length); - const end = Math.max(position, position + length); - - if (start < 0 || end * 8 > bits.bitSize) { - return new Error(Nil); - } - - return new Ok(bitArraySlice(bits, start * 8, end * 8)); -} - -export function codepoint(int) { - return new UtfCodepoint(int); -} - -export function string_to_codepoint_integer_list(string) { - return List.fromArray(Array.from(string).map((item) => item.codePointAt(0))); -} - -export function utf_codepoint_list_to_string(utf_codepoint_integer_list) { - return utf_codepoint_integer_list - .toArray() - .map((x) => String.fromCodePoint(x.value)) - .join(""); -} - -export function utf_codepoint_to_int(utf_codepoint) { - return utf_codepoint.value; -} - -export function new_map() { - return Dict.new(); -} - -export function map_size(map) { - return map.size; -} - -export function map_to_list(map) { - return List.fromArray(map.entries()); -} - -export function map_remove(key, map) { - return map.delete(key); -} - -export function map_get(map, key) { - const value = map.get(key, NOT_FOUND); - if (value === NOT_FOUND) { - return new Error(Nil); - } - return new Ok(value); -} - -export function map_insert(key, value, map) { - return map.set(key, value); -} - -function unsafe_percent_decode(string) { - return decodeURIComponent(string || ""); -} - -function unsafe_percent_decode_query(string) { - return decodeURIComponent((string || "").replace("+", " ")); -} - -export function percent_decode(string) { - try { - return new Ok(unsafe_percent_decode(string)); - } catch { - return new Error(Nil); - } -} - -export function percent_encode(string) { - return encodeURIComponent(string).replace("%2B", "+"); -} - -export function parse_query(query) { - try { - const pairs = []; - for (const section of query.split("&")) { - const [key, value] = section.split("="); - if (!key) continue; - - const decodedKey = unsafe_percent_decode_query(key); - const decodedValue = unsafe_percent_decode_query(value); - pairs.push([decodedKey, decodedValue]); - } - return new Ok(List.fromArray(pairs)); - } catch { - return new Error(Nil); - } -} - -const b64EncodeLookup = [ - 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, - 84, 85, 86, 87, 88, 89, 90, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, - 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, - 122, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 43, 47, -]; - -let b64TextDecoder; - -// Implementation based on https://github.com/mitschabaude/fast-base64/blob/main/js.js -export function base64_encode(bit_array, padding) { - b64TextDecoder ??= new TextDecoder(); - - bit_array = bit_array_pad_to_bytes(bit_array); - - const m = bit_array.byteSize; - const k = m % 3; - const n = Math.floor(m / 3) * 4 + (k && k + 1); - const N = Math.ceil(m / 3) * 4; - const encoded = new Uint8Array(N); - - for (let i = 0, j = 0; j < m; i += 4, j += 3) { - const y = - (bit_array.byteAt(j) << 16) + - (bit_array.byteAt(j + 1) << 8) + - (bit_array.byteAt(j + 2) | 0); - - encoded[i] = b64EncodeLookup[y >> 18]; - encoded[i + 1] = b64EncodeLookup[(y >> 12) & 0x3f]; - encoded[i + 2] = b64EncodeLookup[(y >> 6) & 0x3f]; - encoded[i + 3] = b64EncodeLookup[y & 0x3f]; - } - - let base64 = b64TextDecoder.decode(new Uint8Array(encoded.buffer, 0, n)); - - if (padding) { - if (k === 1) { - base64 += "=="; - } else if (k === 2) { - base64 += "="; - } - } - - return base64; -} - -// From https://developer.mozilla.org/en-US/docs/Glossary/Base64 -export function base64_decode(sBase64) { - try { - const binString = atob(sBase64); - const length = binString.length; - const array = new Uint8Array(length); - for (let i = 0; i < length; i++) { - array[i] = binString.charCodeAt(i); - } - return new Ok(new BitArray(array)); - } catch { - return new Error(Nil); - } -} - -export function classify_dynamic(data) { - if (typeof data === "string") { - return "String"; - } else if (typeof data === "boolean") { - return "Bool"; - } else if (data instanceof Result) { - return "Result"; - } else if (data instanceof List) { - return "List"; - } else if (data instanceof BitArray) { - return "BitArray"; - } else if (data instanceof Dict) { - return "Dict"; - } else if (Number.isInteger(data)) { - return "Int"; - } else if (Array.isArray(data)) { - return `Array`; - } else if (typeof data === "number") { - return "Float"; - } else if (data === null) { - return "Nil"; - } else if (data === undefined) { - return "Nil"; - } else { - const type = typeof data; - return type.charAt(0).toUpperCase() + type.slice(1); - } -} - -export function byte_size(string) { - return new TextEncoder().encode(string).length; -} - -// In JavaScript bitwise operations convert numbers to a sequence of 32 bits -// while Erlang uses arbitrary precision. -// To get around this problem and get consistent results use BigInt and then -// downcast the value back to a Number value. - -export function bitwise_and(x, y) { - return Number(BigInt(x) & BigInt(y)); -} - -export function bitwise_not(x) { - return Number(~BigInt(x)); -} - -export function bitwise_or(x, y) { - return Number(BigInt(x) | BigInt(y)); -} - -export function bitwise_exclusive_or(x, y) { - return Number(BigInt(x) ^ BigInt(y)); -} - -export function bitwise_shift_left(x, y) { - return Number(BigInt(x) << BigInt(y)); -} - -export function bitwise_shift_right(x, y) { - return Number(BigInt(x) >> BigInt(y)); -} - -export function inspect(v) { - return new Inspector().inspect(v); -} - -export function float_to_string(float) { - const string = float.toString().replace("+", ""); - if (string.indexOf(".") >= 0) { - return string; - } else { - const index = string.indexOf("e"); - if (index >= 0) { - return string.slice(0, index) + ".0" + string.slice(index); - } else { - return string + ".0"; - } - } -} - -class Inspector { - #references = new Set(); - - inspect(v) { - const t = typeof v; - if (v === true) return "True"; - if (v === false) return "False"; - if (v === null) return "//js(null)"; - if (v === undefined) return "Nil"; - if (t === "string") return this.#string(v); - if (t === "bigint" || Number.isInteger(v)) return v.toString(); - if (t === "number") return float_to_string(v); - if (v instanceof UtfCodepoint) return this.#utfCodepoint(v); - if (v instanceof BitArray) return this.#bit_array(v); - if (v instanceof RegExp) return `//js(${v})`; - if (v instanceof Date) return `//js(Date("${v.toISOString()}"))`; - if (v instanceof globalThis.Error) return `//js(${v.toString()})`; - if (v instanceof Function) { - const args = []; - for (const i of Array(v.length).keys()) - args.push(String.fromCharCode(i + 97)); - return `//fn(${args.join(", ")}) { ... }`; - } - - if (this.#references.size === this.#references.add(v).size) { - return "//js(circular reference)"; - } - - let printed; - if (Array.isArray(v)) { - printed = `#(${v.map((v) => this.inspect(v)).join(", ")})`; - } else if (v instanceof List) { - printed = this.#list(v); - } else if (v instanceof CustomType) { - printed = this.#customType(v); - } else if (v instanceof Dict) { - printed = this.#dict(v); - } else if (v instanceof Set) { - return `//js(Set(${[...v].map((v) => this.inspect(v)).join(", ")}))`; - } else { - printed = this.#object(v); - } - this.#references.delete(v); - return printed; - } - - #object(v) { - const name = Object.getPrototypeOf(v)?.constructor?.name || "Object"; - const props = []; - for (const k of Object.keys(v)) { - props.push(`${this.inspect(k)}: ${this.inspect(v[k])}`); - } - const body = props.length ? " " + props.join(", ") + " " : ""; - const head = name === "Object" ? "" : name + " "; - return `//js(${head}{${body}})`; - } - - #dict(map) { - let body = "dict.from_list(["; - let first = true; - map.forEach((value, key) => { - if (!first) body = body + ", "; - body = body + "#(" + this.inspect(key) + ", " + this.inspect(value) + ")"; - first = false; - }); - return body + "])"; - } - - #customType(record) { - const props = Object.keys(record) - .map((label) => { - const value = this.inspect(record[label]); - return isNaN(parseInt(label)) ? `${label}: ${value}` : value; - }) - .join(", "); - return props - ? `${record.constructor.name}(${props})` - : record.constructor.name; - } - - #list(list) { - if (list instanceof Empty) { - return "[]"; - } - - let char_out = 'charlist.from_string("'; - let list_out = "["; - - let current = list; - while (current instanceof NonEmpty) { - let element = current.head; - current = current.tail; - - if (list_out !== "[") { - list_out += ", "; - } - list_out += this.inspect(element); - - if (char_out) { - if (Number.isInteger(element) && element >= 32 && element <= 126) { - char_out += String.fromCharCode(element); - } else { - char_out = null; - } - } - } - - if (char_out) { - return char_out + '")'; - } else { - return list_out + "]"; - } - } - - #string(str) { - let new_str = '"'; - for (let i = 0; i < str.length; i++) { - const char = str[i]; - switch (char) { - case "\n": - new_str += "\\n"; - break; - case "\r": - new_str += "\\r"; - break; - case "\t": - new_str += "\\t"; - break; - case "\f": - new_str += "\\f"; - break; - case "\\": - new_str += "\\\\"; - break; - case '"': - new_str += '\\"'; - break; - default: - if (char < " " || (char > "~" && char < "\u{00A0}")) { - new_str += - "\\u{" + - char.charCodeAt(0).toString(16).toUpperCase().padStart(4, "0") + - "}"; - } else { - new_str += char; - } - } - } - new_str += '"'; - return new_str; - } - - #utfCodepoint(codepoint) { - return `//utfcodepoint(${String.fromCodePoint(codepoint.value)})`; - } - - #bit_array(bits) { - if (bits.bitSize === 0) { - return "<<>>"; - } - - let acc = "<<"; - - for (let i = 0; i < bits.byteSize - 1; i++) { - acc += bits.byteAt(i).toString(); - acc += ", "; - } - - if (bits.byteSize * 8 === bits.bitSize) { - acc += bits.byteAt(bits.byteSize - 1).toString(); - } else { - const trailingBitsCount = bits.bitSize % 8; - acc += bits.byteAt(bits.byteSize - 1) >> (8 - trailingBitsCount); - acc += `:size(${trailingBitsCount})`; - } - - acc += ">>"; - return acc; - } -} - -export function base16_encode(bit_array) { - const trailingBitsCount = bit_array.bitSize % 8; - - let result = ""; - - for (let i = 0; i < bit_array.byteSize; i++) { - let byte = bit_array.byteAt(i); - - if (i === bit_array.byteSize - 1 && trailingBitsCount !== 0) { - const unusedBitsCount = 8 - trailingBitsCount; - byte = (byte >> unusedBitsCount) << unusedBitsCount; - } - - result += byte.toString(16).padStart(2, "0").toUpperCase(); - } - - return result; -} - -export function base16_decode(string) { - const bytes = new Uint8Array(string.length / 2); - for (let i = 0; i < string.length; i += 2) { - const a = parseInt(string[i], 16); - const b = parseInt(string[i + 1], 16); - if (isNaN(a) || isNaN(b)) return new Error(Nil); - bytes[i / 2] = a * 16 + b; - } - return new Ok(new BitArray(bytes)); -} - -export function bit_array_to_int_and_size(bits) { - const trailingBitsCount = bits.bitSize % 8; - const unusedBitsCount = trailingBitsCount === 0 ? 0 : 8 - trailingBitsCount; - - return [bits.byteAt(0) >> unusedBitsCount, bits.bitSize]; -} - -export function bit_array_starts_with(bits, prefix) { - if (prefix.bitSize > bits.bitSize) { - return false; - } - - // Check any whole bytes - const byteCount = Math.trunc(prefix.bitSize / 8); - for (let i = 0; i < byteCount; i++) { - if (bits.byteAt(i) !== prefix.byteAt(i)) { - return false; - } - } - - // Check any trailing bits at the end of the prefix - if (prefix.bitSize % 8 !== 0) { - const unusedBitsCount = 8 - (prefix.bitSize % 8); - if ( - bits.byteAt(byteCount) >> unusedBitsCount !== - prefix.byteAt(byteCount) >> unusedBitsCount - ) { - return false; - } - } - - return true; -} - -export function log(x) { - // It is checked in Gleam that: - // - The input is strictly positive (x > 0) - // - This ensures that Math.log will never return NaN or -Infinity - // The function can thus safely pass the input to Math.log - // and a valid finite float will always be produced. - return Math.log(x); -} - -export function exp(x) { - return Math.exp(x); -} - -export function list_to_array(list) { - let current = list; - let array = []; - while (current instanceof NonEmpty) { - array.push(current.head); - current = current.tail; - } - return array; -} - -export function index(data, key) { - // Dictionaries and dictionary-like objects can be indexed - if (data instanceof Dict || data instanceof WeakMap || data instanceof Map) { - const token = {}; - const entry = data.get(key, token); - if (entry === token) return new Ok(new None()); - return new Ok(new Some(entry)); - } - - const key_is_int = Number.isInteger(key); - - // Only elements 0-7 of lists can be indexed, negative indices are not allowed - if (key_is_int && key >= 0 && key < 8 && data instanceof List) { - let i = 0; - for (const value of data) { - if (i === key) return new Ok(new Some(value)); - i++; - } - return new Error("Indexable"); - } - - // Arrays and objects can be indexed - if ( - (key_is_int && Array.isArray(data)) || - (data && typeof data === "object") || - (data && Object.getPrototypeOf(data) === Object.prototype) - ) { - if (key in data) return new Ok(new Some(data[key])); - return new Ok(new None()); - } - - return new Error(key_is_int ? "Indexable" : "Dict"); -} - -export function list(data, decode, pushPath, index, emptyList) { - if (!(data instanceof List || Array.isArray(data))) { - const error = new DecodeError("List", classify(data), emptyList); - return [emptyList, List.fromArray([error])]; - } - - const decoded = []; - - for (const element of data) { - const layer = decode(element); - const [out, errors] = layer; - - if (errors instanceof NonEmpty) { - const [_, errors] = pushPath(layer, index.toString()); - return [emptyList, errors]; - } - decoded.push(out); - index++; - } - - return [List.fromArray(decoded), emptyList]; -} - -export function dict(data) { - if (data instanceof Dict) { - return new Ok(data); - } - if (data instanceof Map || data instanceof WeakMap) { - return new Ok(Dict.fromMap(data)); - } - if (data == null) { - return new Error("Dict"); - } - if (typeof data !== "object") { - return new Error("Dict"); - } - const proto = Object.getPrototypeOf(data); - if (proto === Object.prototype || proto === null) { - return new Ok(Dict.fromObject(data)); - } - return new Error("Dict"); -} - -export function bit_array(data) { - if (data instanceof BitArray) return new Ok(data); - if (data instanceof Uint8Array) return new Ok(new BitArray(data)); - return new Error(new BitArray(new Uint8Array())); -} - -export function float(data) { - if (typeof data === "number") return new Ok(data); - return new Error(0.0); -} - -export function int(data) { - if (Number.isInteger(data)) return new Ok(data); - return new Error(0); -} - -export function string(data) { - if (typeof data === "string") return new Ok(data); - return new Error(""); -} - -export function is_null(data) { - return data === null || data === undefined; -} diff --git a/build/packages/gleam_time/README.md b/build/packages/gleam_time/README.md deleted file mode 100644 index 4c4360f..0000000 --- a/build/packages/gleam_time/README.md +++ /dev/null @@ -1,101 +0,0 @@ -# Time 🕰️ - -Work with time in Gleam! - -[![Package Version](https://img.shields.io/hexpm/v/gleam_time)](https://hex.pm/packages/gleam_time) -[![Hex Docs](https://img.shields.io/badge/hex-docs-ffaff3)](https://hexdocs.pm/gleam_time/) - -```sh -gleam add gleam_time -``` - -This package is the foundation of all code that works with time in Gleam. If -your program uses time then you should be using the types in this package, and -you might choose to add other packages to provide additional functionality. - -## How not to have time related bugs - -Time is famously difficult to work with! It's a very complex area, and there's -many approaches that seem reasonable or obvious, but then commonly result in -bugs. This package is carefully designed to help you avoid these problems, so -it is wise to read this documentation before continuing. - -It is important to understand there are two main ways that time is represented: - -- **Calendar time**: This is how humans commonly think and communicate about - time. For example, "10pm on the 5th of January". This is easy for a human to - read, but is it typically ambiguous and hard to work with! 10pm in - Killorglin, Ireland is not the same point in time as 10pm in Harare, - Zimbabwe. The exact meaning of calendar time depends on daylight savings - time, leap years, leap seconds, and continuously changing national and - political declarations. To make calendar time unambiguous you will need to - know what time zone it is for, and to have an up-to-date time zone database. - -- **Epoch time**: Epoch time is defined as an exact amount of since some fixed - point in time. It is always unambiguous as is not impacted by geopolitics, - time zones, etc. It is efficient for computers to work with, and it is less - likely to result in buggy code. - -In this package epoch time is provided by the `gleam/time/timestamp` module, -and calendar time is provided by the `gleam/time/calendar` module. - -Time zone information has to be loaded from elsewhere, but which approch is -best will depend on your application. User interfaces may want to read current -time zone information from the user's web browser or operating system. Server -side applications may want to embed or downloads a full copy of the time zone -database and then ask clients which time zone they want to use. - -For an entertaining overview of some of the problems of calendar time view this -video: ["The Problem with Time & Timezones" by Computerphile](https://www.youtube.com/watch?v=-5wpm-gesOY). - -### Which time representation should you use? - -> **tldr**: Use `gleam/time/timestamp`. - -The longer, more detailed answer: - -- Default to `gleam/time/timestamp`, which is epoch time. It is - unambiguous, efficient, and significantly less likely to result in logic - bugs. - -- When writing time to a database or other data storage use epoch time, - using whatever epoch format it supports. For example, PostgreSQL - `timestamp` and `timestampz` are both epoch time, and `timestamp` is - preferred as it is more straightforward to use as your application is - also using epoch time. - -- When communicating with other computer systems continue to use epoch - time. For example, when sending times to another program you could - encode time as UNIX timestamps (seconds since 00:00:00 UTC on 1 January - 1970). - -- When communicating with humans use epoch time internally, and convert - to-and-from calendar time at the last moment, when iteracting with the - human user. It may also help the users to also show the time as a fuzzy - duration from the present time, such as "about 4 days ago". - -- When representing "fuzzy" human time concepts that don't exact periods - in time, such as "one month" (varies depending on which month, which - year, and in which time zone) and "Christmas Day" (varies depending on - which year and time zone) then use calendar time. - -Any time you do use calendar time you should be extra careful! It is very -easy to make mistake with. Avoid it where possible. - -## Special thanks - -This package was created with great help from several kind contributors. In -alphabetical order: - -- [Hayleigh Thompson](https://github.com/hayleigh-dot-dev) -- [John Strunk](https://github.com/jrstrunk) -- [Ryan Moore](https://github.com/mooreryan) -- [Shayan Javani](https://github.com/massivefermion) - -These non-Gleam projects where highly influential on the design of this -package: - -- Elm's `elm/time` package. -- Go's `time` module. -- Rust's `std::time` module. -- Elixir's standard library time modules and `timex` package. diff --git a/build/packages/gleam_time/gleam.toml b/build/packages/gleam_time/gleam.toml deleted file mode 100644 index 90f4a22..0000000 --- a/build/packages/gleam_time/gleam.toml +++ /dev/null @@ -1,19 +0,0 @@ -name = "gleam_time" -version = "1.6.0" -description = "Work with time in Gleam!" -gleam = ">= 1.11.0" -licences = ["Apache-2.0"] -repository = { type = "github", user = "gleam-lang", repo = "time" } -links = [ - { title = "Sponsor", href = "https://github.com/sponsors/lpil" } -] - -[dependencies] -gleam_stdlib = ">= 0.44.0 and < 2.0.0" - -[dev-dependencies] -gleeunit = ">= 1.0.0 and < 2.0.0" -qcheck = ">= 1.0.0 and < 2.0.0" -simplifile = ">= 2.2.0 and < 3.0.0" -gleam_regexp = ">= 1.0.0 and < 2.0.0" -prng = ">= 4.0.1 and < 5.0.0" diff --git a/build/packages/gleam_time/include/gleam@time@calendar_Date.hrl b/build/packages/gleam_time/include/gleam@time@calendar_Date.hrl deleted file mode 100644 index b746fad..0000000 --- a/build/packages/gleam_time/include/gleam@time@calendar_Date.hrl +++ /dev/null @@ -1,5 +0,0 @@ --record(date, { - year :: integer(), - month :: gleam@time@calendar:month(), - day :: integer() -}). diff --git a/build/packages/gleam_time/include/gleam@time@calendar_TimeOfDay.hrl b/build/packages/gleam_time/include/gleam@time@calendar_TimeOfDay.hrl deleted file mode 100644 index b5a103d..0000000 --- a/build/packages/gleam_time/include/gleam@time@calendar_TimeOfDay.hrl +++ /dev/null @@ -1,6 +0,0 @@ --record(time_of_day, { - hours :: integer(), - minutes :: integer(), - seconds :: integer(), - nanoseconds :: integer() -}). diff --git a/build/packages/gleam_time/include/gleam@time@duration_Duration.hrl b/build/packages/gleam_time/include/gleam@time@duration_Duration.hrl deleted file mode 100644 index 5477733..0000000 --- a/build/packages/gleam_time/include/gleam@time@duration_Duration.hrl +++ /dev/null @@ -1 +0,0 @@ --record(duration, {seconds :: integer(), nanoseconds :: integer()}). diff --git a/build/packages/gleam_time/include/gleam@time@timestamp_Timestamp.hrl b/build/packages/gleam_time/include/gleam@time@timestamp_Timestamp.hrl deleted file mode 100644 index b05bafe..0000000 --- a/build/packages/gleam_time/include/gleam@time@timestamp_Timestamp.hrl +++ /dev/null @@ -1 +0,0 @@ --record(timestamp, {seconds :: integer(), nanoseconds :: integer()}). diff --git a/build/packages/gleam_time/src/gleam/time/calendar.gleam b/build/packages/gleam_time/src/gleam/time/calendar.gleam deleted file mode 100644 index ac81c11..0000000 --- a/build/packages/gleam_time/src/gleam/time/calendar.gleam +++ /dev/null @@ -1,346 +0,0 @@ -//// This module is for working with the Gregorian calendar, established by -//// Pope Gregory XIII in 1582! -//// -//// ## When should you use this module? -//// -//// > **tldr:** You probably want to use [`gleam/time/timestamp`](./timestamp.html) -//// > instead! -//// -//// Calendar time is difficult to work with programmatically, it is the source -//// of most time-related bugs in software. Compared to _epoch time_, which the -//// `gleam/time/timestamp` module uses, there are many disadvantages to -//// calendar time: -//// -//// - They are ambiguous if you don't know what time-zone is being used. -//// -//// - A time-zone database is required to understand calendar time even when -//// you have the time zone. These are large and your program has to -//// continously be updated as new versions of the database are published. -//// -//// - The type permits invalid states. e.g. `days` could be set to the number -//// 32, but this should not be possible! -//// -//// - There is not a single unique canonical value for each point in time, -//// thanks to time zones. Two different `Date` + `TimeOfDay` value pairs -//// could represent the same point in time. This means that you can't check -//// for time equality with `==` when using calendar types. -//// -//// - They are computationally complex, using a more memory to represent and -//// requiring a lot more CPU time to manipulate. -//// -//// There are also advantages to calendar time: -//// -//// - Calendar time is how human's talk about time, so if you want to show a -//// time or take a time from a human user then calendar time will make it -//// easier for them. -//// -//// - They can represent more abstract time periods such as "New Year's Day". -//// This may seem like an exact window of time at first, but really the -//// definition of "New Year's Day" is more fuzzy than that. When it starts -//// and ends will depend where in the world you are, so if you want to refer -//// to a day as a global concept instead of a fixed window of time for that -//// day in a specific location, then calendar time can represent that. -//// -//// So when should you use calendar time? These are our recommendations: -//// -//// - Default to `gleam/time/timestamp`, which is epoch time. It is -//// unambiguous, efficient, and significantly less likely to result in logic -//// bugs. -//// -//// - When writing time to a database or other data storage use epoch time, -//// using whatever epoch format it supports. For example, PostgreSQL -//// `timestamp` and `timestampz` are both epoch time, and `timestamp` is -//// preferred as it is more straightforward to use as your application is -//// also using epoch time. -//// -//// - When communicating with other computer systems continue to use epoch -//// time. For example, when sending times to another program you could -//// encode time as UNIX timestamps (seconds since 00:00:00 UTC on 1 January -//// 1970). -//// -//// - When communicating with humans use epoch time internally, and convert -//// to-and-from calendar time at the last moment, when iteracting with the -//// human user. It may also help the users to also show the time as a fuzzy -//// duration from the present time, such as "about 4 days ago". -//// -//// - When representing "fuzzy" human time concepts that don't exact periods -//// in time, such as "one month" (varies depending on which month, which -//// year, and in which time zone) and "Christmas Day" (varies depending on -//// which year and time zone) then use calendar time. -//// -//// Any time you do use calendar time you should be extra careful! It is very -//// easy to make mistake with. Avoid it where possible. -//// -//// ## Time zone offsets -//// -//// This package includes the `utc_offset` value and the `local_offset` -//// function, which are the offset for the UTC time zone and get the time -//// offset the computer running the program is configured to respectively. -//// -//// If you need to use other offsets in your program then you will need to get -//// them from somewhere else, such as from a package which loads the -//// [IANA Time Zone Database](https://www.iana.org/time-zones), or from the -//// website visitor's web browser, which your frontend can send for you. -//// -//// ## Use in APIs -//// -//// If you are making an API such as a HTTP JSON API you are encouraged to use -//// Unix timestamps instead of calendar times. - -import gleam/int -import gleam/order.{type Order} -import gleam/time/duration - -/// The Gregorian calendar date. Ambiguous without a time zone. -/// -/// Prefer to represent your time using the `Timestamp` type, and convert it -/// only to calendar types when you need to display them. See the documentation -/// for this module for more information. -/// -pub type Date { - Date(year: Int, month: Month, day: Int) -} - -/// The time of day. Ambiguous without a date and time zone. -/// -pub type TimeOfDay { - TimeOfDay(hours: Int, minutes: Int, seconds: Int, nanoseconds: Int) -} - -/// The 12 months of the year. -pub type Month { - January - February - March - April - May - June - July - August - September - October - November - December -} - -/// The offset for the [Coordinated Universal Time (UTC)](https://en.wikipedia.org/wiki/Coordinated_Universal_Time) -/// time zone. -/// -/// The utc zone has no time adjustments, it is always zero. It never observes -/// daylight-saving time and it never shifts around based on political -/// restructuring. -/// -pub const utc_offset = duration.empty - -/// Get the offset for the computer's currently configured time zone. -/// -/// Note this may not be the time zone that is correct to use for your user. -/// For example, if you are making a web application that runs on a server you -/// want _their_ computer's time zone, not yours. -/// -/// This is the _current local_ offset, not the current local time zone. This -/// means that while it will result in the expected outcome for the current -/// time, it may result in unexpected output if used with other timestamps. For -/// example: a timestamp that would locally be during daylight savings time if -/// is it not currently daylight savings time when this function is called. -/// -pub fn local_offset() -> duration.Duration { - duration.seconds(local_time_offset_seconds()) -} - -@external(erlang, "gleam_time_ffi", "local_time_offset_seconds") -@external(javascript, "../../gleam_time_ffi.mjs", "local_time_offset_seconds") -fn local_time_offset_seconds() -> Int - -/// Returns the English name for a month. -/// -/// # Examples -/// -/// ```gleam -/// month_to_string(April) -/// // -> "April" -/// ``` -pub fn month_to_string(month: Month) -> String { - case month { - January -> "January" - February -> "February" - March -> "March" - April -> "April" - May -> "May" - June -> "June" - July -> "July" - August -> "August" - September -> "September" - October -> "October" - November -> "November" - December -> "December" - } -} - -/// Returns the number for the month, where January is 1 and December is 12. -/// -/// # Examples -/// -/// ```gleam -/// month_to_int(January) -/// // -> 1 -/// ``` -pub fn month_to_int(month: Month) -> Int { - case month { - January -> 1 - February -> 2 - March -> 3 - April -> 4 - May -> 5 - June -> 6 - July -> 7 - August -> 8 - September -> 9 - October -> 10 - November -> 11 - December -> 12 - } -} - -/// Returns the month for a given number, where January is 1 and December is 12. -/// -/// # Examples -/// -/// ```gleam -/// month_from_int(1) -/// // -> Ok(January) -/// ``` -pub fn month_from_int(month: Int) -> Result(Month, Nil) { - case month { - 1 -> Ok(January) - 2 -> Ok(February) - 3 -> Ok(March) - 4 -> Ok(April) - 5 -> Ok(May) - 6 -> Ok(June) - 7 -> Ok(July) - 8 -> Ok(August) - 9 -> Ok(September) - 10 -> Ok(October) - 11 -> Ok(November) - 12 -> Ok(December) - _ -> Error(Nil) - } -} - -/// Checks if a given date is valid. -/// -/// This function properly accounts for leap years when validating February days. -/// A leap year occurs every 4 years, except for years divisible by 100, -/// unless they are also divisible by 400. -/// -/// # Examples -/// -/// ```gleam -/// is_valid_date(Date(2023, April, 15)) -/// // -> True -/// ``` -/// -/// ```gleam -/// is_valid_date(Date(2023, April, 31)) -/// // -> False -/// ``` -/// -/// ```gleam -/// is_valid_date(Date(2024, February, 29)) -/// // -> True (2024 is a leap year) -/// ``` -/// -pub fn is_valid_date(date: Date) -> Bool { - let Date(year:, month:, day:) = date - case day < 1 { - True -> False - False -> - case month { - January | March | May | July | August | October | December -> day <= 31 - April | June | September | November -> day <= 30 - February -> { - let max_february_days = case is_leap_year(year) { - True -> 29 - False -> 28 - } - day <= max_february_days - } - } - } -} - -/// Determines if a given year is a leap year. -/// -/// A leap year occurs every 4 years, except for years divisible by 100, -/// unless they are also divisible by 400. -/// -/// # Examples -/// -/// ```gleam -/// is_leap_year(2024) -/// // -> True -/// ``` -/// -/// ```gleam -/// is_leap_year(2023) -/// // -> False -/// ``` -/// -pub fn is_leap_year(year: Int) -> Bool { - case year % 400 == 0 { - True -> True - False -> - case year % 100 == 0 { - True -> False - False -> year % 4 == 0 - } - } -} - -/// Checks if a time of day is valid. -/// -/// Validates that hours are 0-23, minutes are 0-59, seconds are 0-59, -/// and nanoseconds are 0-999,999,999. -/// -/// # Examples -/// -/// ```gleam -/// is_valid_time_of_day(TimeOfDay(12, 30, 45, 123456789)) -/// // -> True -/// ``` -/// -pub fn is_valid_time_of_day(time: TimeOfDay) -> Bool { - let TimeOfDay(hours:, minutes:, seconds:, nanoseconds:) = time - - hours >= 0 - && hours <= 23 - && minutes >= 0 - && minutes <= 59 - && seconds >= 0 - && seconds <= 59 - && nanoseconds >= 0 - && nanoseconds <= 999_999_999 -} - -/// Naively compares two dates without any time zone information, returning an -/// order. -/// -/// ## Correctness -/// -/// This function compares dates without any time zone information, only using -/// the rules for the gregorian calendar. This is typically sufficient, but be -/// aware that in reality some time zones will change their calendar date -/// occasionally. This can result in days being skipped, out of order, or -/// happening multiple times. -/// -/// If you need real-world correct time ordering then use the -/// `gleam/time/timestamp` module instead. -/// -pub fn naive_date_compare(one: Date, other: Date) -> Order { - int.compare(one.year, other.year) - |> order.lazy_break_tie(fn() { - int.compare(month_to_int(one.month), month_to_int(other.month)) - }) - |> order.lazy_break_tie(fn() { int.compare(one.day, other.day) }) -} diff --git a/build/packages/gleam_time/src/gleam/time/duration.gleam b/build/packages/gleam_time/src/gleam/time/duration.gleam deleted file mode 100644 index a3b7483..0000000 --- a/build/packages/gleam_time/src/gleam/time/duration.gleam +++ /dev/null @@ -1,297 +0,0 @@ -import gleam/bool -import gleam/int -import gleam/order -import gleam/string - -/// An amount of time, with up to nanosecond precision. -/// -/// This type does not represent calendar periods such as "1 month" or "2 -/// days". Those periods will be different lengths of time depending on which -/// month or day they apply to. For example, January is longer than February. -/// A different type should be used for calendar periods. -/// -pub opaque type Duration { - // When compiling to JavaScript ints have limited precision and size. This - // means that if we were to store the the timestamp in a single int the - // duration would not be able to represent very large or small durations. - // Durations are instead represented as a number of seconds and a number of - // nanoseconds. - // - // If you have manually adjusted the seconds and nanoseconds values the - // `normalise` function can be used to ensure the time is represented the - // intended way, with `nanoseconds` being positive and less than 1 second. - // - // The duration is the sum of the seconds and the nanoseconds. - Duration(seconds: Int, nanoseconds: Int) -} - -/// A division of time. -/// -/// Note that not all months and years are the same length, so a reasonable -/// average length is used by this module. -/// -pub type Unit { - Nanosecond - /// 1000 nanoseconds. - Microsecond - /// 1000 microseconds. - Millisecond - /// 1000 milliseconds. - Second - /// 60 seconds. - Minute - /// 60 minutes. - Hour - /// 24 hours. - Day - /// 7 days. - Week - /// About 30.4375 days. Real calendar months vary in length. - Month - /// About 365.25 days. Real calendar years vary in length. - Year -} - -/// Convert a duration to a number of the largest number of a unit, serving as -/// a rough description of the duration that a human can understand. -/// -/// The size used for each unit are described in the documentation for the -/// `Unit` type. -/// -/// ```gleam -/// seconds(125) -/// |> approximate -/// // -> #(2, Minute) -/// ``` -/// -/// This function rounds _towards zero_. This means that if a duration is just -/// short of 2 days then it will approximate to 1 day. -/// -/// ```gleam -/// hours(47) -/// |> approximate -/// // -> #(1, Day) -/// ``` -/// -pub fn approximate(duration: Duration) -> #(Int, Unit) { - let Duration(seconds: s, nanoseconds: ns) = duration - let minute = 60 - let hour = minute * 60 - let day = hour * 24 - let week = day * 7 - let year = day * 365 + hour * 6 - let month = year / 12 - let microsecond = 1000 - let millisecond = microsecond * 1000 - case Nil { - _ if s < 0 -> { - let #(amount, unit) = Duration(-s, -ns) |> normalise |> approximate - #(-amount, unit) - } - _ if s >= year -> #(s / year, Year) - _ if s >= month -> #(s / month, Month) - _ if s >= week -> #(s / week, Week) - _ if s >= day -> #(s / day, Day) - _ if s >= hour -> #(s / hour, Hour) - _ if s >= minute -> #(s / minute, Minute) - _ if s > 0 -> #(s, Second) - _ if ns >= millisecond -> #(ns / millisecond, Millisecond) - _ if ns >= microsecond -> #(ns / microsecond, Microsecond) - _ -> #(ns, Nanosecond) - } -} - -/// Ensure the duration is represented with `nanoseconds` being positive and -/// less than 1 second. -/// -/// This function does not change the amount of time that the duratoin refers -/// to, it only adjusts the values used to represent the time. -/// -fn normalise(duration: Duration) -> Duration { - let multiplier = 1_000_000_000 - let nanoseconds = duration.nanoseconds % multiplier - let overflow = duration.nanoseconds - nanoseconds - let seconds = duration.seconds + overflow / multiplier - case nanoseconds >= 0 { - True -> Duration(seconds, nanoseconds) - False -> Duration(seconds - 1, multiplier + nanoseconds) - } -} - -/// Compare one duration to another, indicating whether the first spans a -/// larger amount of time (and so is greater) or smaller amount of time (and so -/// is lesser) than the second. -/// -/// # Examples -/// -/// ```gleam -/// compare(seconds(1), seconds(2)) -/// // -> order.Lt -/// ``` -/// -/// Whether a duration is negative or positive doesn't matter for comparing -/// them, only the amount of time spanned matters. -/// -/// ```gleam -/// compare(seconds(-2), seconds(1)) -/// // -> order.Gt -/// ``` -/// -pub fn compare(left: Duration, right: Duration) -> order.Order { - let parts = fn(x: Duration) { - case x.seconds >= 0 { - True -> #(x.seconds, x.nanoseconds) - False -> #(x.seconds * -1 - 1, 1_000_000_000 - x.nanoseconds) - } - } - let #(ls, lns) = parts(left) - let #(rs, rns) = parts(right) - int.compare(ls, rs) - |> order.break_tie(int.compare(lns, rns)) -} - -/// Calculate the difference between two durations. -/// -/// This is effectively substracting the first duration from the second. -/// -/// # Examples -/// -/// ```gleam -/// difference(seconds(1), seconds(5)) -/// // -> seconds(4) -/// ``` -/// -pub fn difference(left: Duration, right: Duration) -> Duration { - Duration(right.seconds - left.seconds, right.nanoseconds - left.nanoseconds) - |> normalise -} - -/// Add two durations together. -/// -/// # Examples -/// -/// ```gleam -/// add(seconds(1), seconds(5)) -/// // -> seconds(6) -/// ``` -/// -pub fn add(left: Duration, right: Duration) -> Duration { - Duration(left.seconds + right.seconds, left.nanoseconds + right.nanoseconds) - |> normalise -} - -/// Convert the duration to an [ISO8601][1] formatted duration string. -/// -/// The ISO8601 duration format is ambiguous without context due to months and -/// years having different lengths, and because of leap seconds. This function -/// encodes the duration as days, hours, and seconds without any leap seconds. -/// Be sure to take this into account when using the duration strings. -/// -/// [1]: https://en.wikipedia.org/wiki/ISO_8601#Durations -/// -pub fn to_iso8601_string(duration: Duration) -> String { - use <- bool.guard(duration == empty, "PT0S") - let split = fn(total, limit) { - let amount = total % limit - let remainder = { total - amount } / limit - #(amount, remainder) - } - let #(seconds, rest) = split(duration.seconds, 60) - let #(minutes, rest) = split(rest, 60) - let #(hours, rest) = split(rest, 24) - let days = rest - let add = fn(out, value, unit) { - case value { - 0 -> out - _ -> out <> int.to_string(value) <> unit - } - } - let output = - "P" - |> add(days, "D") - |> string.append("T") - |> add(hours, "H") - |> add(minutes, "M") - case seconds, duration.nanoseconds { - 0, 0 -> output - _, 0 -> output <> int.to_string(seconds) <> "S" - _, _ -> { - let f = nanosecond_digits(duration.nanoseconds, 0, "") - output <> int.to_string(seconds) <> "." <> f <> "S" - } - } -} - -fn nanosecond_digits(n: Int, position: Int, acc: String) -> String { - case position { - 9 -> acc - _ if acc == "" && n % 10 == 0 -> { - nanosecond_digits(n / 10, position + 1, acc) - } - _ -> { - let acc = int.to_string(n % 10) <> acc - nanosecond_digits(n / 10, position + 1, acc) - } - } -} - -/// Create a duration of a number of seconds. -pub fn seconds(amount: Int) -> Duration { - Duration(amount, 0) -} - -/// Create a duration of a number of minutes. -pub fn minutes(amount: Int) -> Duration { - seconds(amount * 60) -} - -/// Create a duration of a number of hours. -pub fn hours(amount: Int) -> Duration { - seconds(amount * 60 * 60) -} - -/// Create a duration of a number of milliseconds. -pub fn milliseconds(amount: Int) -> Duration { - let remainder = amount % 1000 - let overflow = amount - remainder - let nanoseconds = remainder * 1_000_000 - let seconds = overflow / 1000 - Duration(seconds, nanoseconds) - |> normalise -} - -/// Create a duration of a number of nanoseconds. -/// -/// # JavaScript int limitations -/// -/// Remember that JavaScript can only perfectly represent ints between positive -/// and negative 9,007,199,254,740,991! If you use a single call to this -/// function to create durations larger than that number of nanoseconds then -/// you will likely not get exactly the value you expect. Use `seconds` and -/// `milliseconds` as much as possible for large durations. -/// -pub fn nanoseconds(amount: Int) -> Duration { - Duration(0, amount) - |> normalise -} - -/// Convert the duration to a number of seconds. -/// -/// There may be some small loss of precision due to `Duration` being -/// nanosecond accurate and `Float` not being able to represent this. -/// -pub fn to_seconds(duration: Duration) -> Float { - let seconds = int.to_float(duration.seconds) - let nanoseconds = int.to_float(duration.nanoseconds) - seconds +. { nanoseconds /. 1_000_000_000.0 } -} - -/// Convert the duration to a number of seconds and nanoseconds. There is no -/// loss of precision with this conversion on any target. -/// -pub fn to_seconds_and_nanoseconds(duration: Duration) -> #(Int, Int) { - #(duration.seconds, duration.nanoseconds) -} - -@internal -pub const empty = Duration(0, 0) diff --git a/build/packages/gleam_time/src/gleam/time/timestamp.gleam b/build/packages/gleam_time/src/gleam/time/timestamp.gleam deleted file mode 100644 index 02fa890..0000000 --- a/build/packages/gleam_time/src/gleam/time/timestamp.gleam +++ /dev/null @@ -1,899 +0,0 @@ -//// Welcome to the timestamp module! This module and its `Timestamp` type are -//// what you will be using most commonly when working with time in Gleam. -//// -//// A timestamp represents a moment in time, represented as an amount of time -//// since the calendar time 00:00:00 UTC on 1 January 1970, also known as the -//// _Unix epoch_. -//// -//// # Wall clock time and monotonicity -//// -//// Time is very complicated, especially on computers! While they generally do -//// a good job of keeping track of what the time is, computers can get -//// out-of-sync and start to report a time that is too late or too early. Most -//// computers use "network time protocol" to tell each other what they think -//// the time is, and computers that realise they are running too fast or too -//// slow will adjust their clock to correct it. When this happens it can seem -//// to your program that the current time has changed, and it may have even -//// jumped backwards in time! -//// -//// This measure of time is called _wall clock time_, and it is what people -//// commonly think of when they think of time. It is important to be aware that -//// it can go backwards, and your program must not rely on it only ever going -//// forwards at a steady rate. For example, for tracking what order events happen -//// in. -//// -//// This module uses wall clock time. If your program needs time values to always -//// increase you will need a _monotonic_ time instead. It's uncommon that you -//// would need monotonic time, one example might be if you're making a -//// benchmarking framework. -//// -//// The exact way that time works will depend on what runtime you use. The -//// Erlang documentation on time has a lot of detail about time generally as well -//// as how it works on the BEAM, it is worth reading. -//// . -//// -//// # Converting to local calendar time -//// -//// Timestamps don't take into account time zones, so a moment in time will -//// have the same timestamp value regardless of where you are in the world. To -//// convert them to local time you will need to know the offset for the time -//// zone you wish to use, likely from a time zone database. See the -//// `gleam/time/calendar` module for more information. -//// - -import gleam/bit_array -import gleam/float -import gleam/int -import gleam/list -import gleam/order -import gleam/result -import gleam/string -import gleam/time/calendar -import gleam/time/duration.{type Duration} - -const seconds_per_day: Int = 86_400 - -const seconds_per_hour: Int = 3600 - -const seconds_per_minute: Int = 60 - -const nanoseconds_per_second: Int = 1_000_000_000 - -/// The `:` character as a byte -const byte_colon: Int = 0x3A - -/// The `-` character as a byte -const byte_minus: Int = 0x2D - -/// The `0` character as a byte -const byte_zero: Int = 0x30 - -/// The `9` character as a byte -const byte_nine: Int = 0x39 - -/// The `t` character as a byte -const byte_t_lowercase: Int = 0x74 - -/// The `T` character as a byte -const byte_t_uppercase: Int = 0x54 - -/// The `T` character as a byte -const byte_space: Int = 0x20 - -/// The Julian seconds of the UNIX epoch (Julian day is 2_440_588) -const julian_seconds_unix_epoch: Int = 210_866_803_200 - -/// The main time type, which you should favour over other types such as -/// calendar time types. It is efficient, unambiguous, and it is not possible -/// to construct an invalid timestamp. -/// -/// The most common situation in which you may need a different time data -/// structure is when you need to display time to human for them to read. When -/// you need to do this convert the timestamp to calendar time when presenting -/// it, but internally always keep the time as a timestamp. -/// -pub opaque type Timestamp { - // When compiling to JavaScript ints have limited precision and size. This - // means that if we were to store the the timestamp in a single int the - // timestamp would not be able to represent times far in the future or in the - // past, or distinguish between two times that are close together. Timestamps - // are instead represented as a number of seconds and a number of nanoseconds. - // - // If you have manually adjusted the seconds and nanoseconds values the - // `normalise` function can be used to ensure the time is represented the - // intended way, with `nanoseconds` being positive and less than 1 second. - // - // The timestamp is the sum of the seconds and the nanoseconds. - Timestamp(seconds: Int, nanoseconds: Int) -} - -/// The epoch of Unix time, which is 00:00:00 UTC on 1 January 1970. -pub const unix_epoch = Timestamp(0, 0) - -/// Ensure the time is represented with `nanoseconds` being positive and less -/// than 1 second. -/// -/// This function does not change the time that the timestamp refers to, it -/// only adjusts the values used to represent the time. -/// -fn normalise(timestamp: Timestamp) -> Timestamp { - let multiplier = 1_000_000_000 - let nanoseconds = timestamp.nanoseconds % multiplier - let overflow = timestamp.nanoseconds - nanoseconds - let seconds = timestamp.seconds + overflow / multiplier - case nanoseconds >= 0 { - True -> Timestamp(seconds, nanoseconds) - False -> Timestamp(seconds - 1, multiplier + nanoseconds) - } -} - -/// Compare one timestamp to another, indicating whether the first is further -/// into the future (greater) or further into the past (lesser) than the -/// second. -/// -/// # Examples -/// -/// ```gleam -/// compare(from_unix_seconds(1), from_unix_seconds(2)) -/// // -> order.Lt -/// ``` -/// -pub fn compare(left: Timestamp, right: Timestamp) -> order.Order { - order.break_tie( - int.compare(left.seconds, right.seconds), - int.compare(left.nanoseconds, right.nanoseconds), - ) -} - -/// Get the current system time. -/// -/// Note this time is not unique or monotonic, it could change at any time or -/// even go backwards! The exact behaviour will depend on the runtime used. See -/// the module documentation for more information. -/// -/// On Erlang this uses [`erlang:system_time/1`][1]. On JavaScript this uses -/// [`Date.now`][2]. -/// -/// [1]: https://www.erlang.org/doc/apps/erts/erlang#system_time/1 -/// [2]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/now -/// -pub fn system_time() -> Timestamp { - let #(seconds, nanoseconds) = get_system_time() - normalise(Timestamp(seconds, nanoseconds)) -} - -@external(erlang, "gleam_time_ffi", "system_time") -@external(javascript, "../../gleam_time_ffi.mjs", "system_time") -fn get_system_time() -> #(Int, Int) - -/// Calculate the difference between two timestamps. -/// -/// This is effectively substracting the first timestamp from the second. -/// -/// # Examples -/// -/// ```gleam -/// difference(from_unix_seconds(1), from_unix_seconds(5)) -/// // -> duration.seconds(4) -/// ``` -/// -pub fn difference(left: Timestamp, right: Timestamp) -> Duration { - let seconds = duration.seconds(right.seconds - left.seconds) - let nanoseconds = duration.nanoseconds(right.nanoseconds - left.nanoseconds) - duration.add(seconds, nanoseconds) -} - -/// Add a duration to a timestamp. -/// -/// # Examples -/// -/// ```gleam -/// add(from_unix_seconds(1000), duration.seconds(5)) -/// // -> from_unix_seconds(1005) -/// ``` -/// -pub fn add(timestamp: Timestamp, duration: Duration) -> Timestamp { - let #(seconds, nanoseconds) = duration.to_seconds_and_nanoseconds(duration) - Timestamp(timestamp.seconds + seconds, timestamp.nanoseconds + nanoseconds) - |> normalise -} - -/// Convert a timestamp to a RFC 3339 formatted time string, with an offset -/// supplied as an additional argument. -/// -/// The output of this function is also ISO 8601 compatible so long as the -/// offset not negative. Offsets have at-most minute precision, so an offset -/// with higher precision will be rounded to the nearest minute. -/// -/// If you are making an API such as a HTTP JSON API you are encouraged to use -/// Unix timestamps instead of this format or ISO 8601. Unix timestamps are a -/// better choice as they don't contain offset information. Consider: -/// -/// - UTC offsets are not time zones. This does not and cannot tell us the time -/// zone in which the date was recorded. So what are we supposed to do with -/// this information? -/// - Users typically want dates formatted according to their local time zone. -/// What if the provided UTC offset is different from the current user's time -/// zone? What are we supposed to do with it then? -/// - Despite it being useless (or worse, a source of bugs), the UTC offset -/// creates a larger payload to transfer. -/// -/// They also uses more memory than a unix timestamp. The way they are better -/// than Unix timestamp is that it is easier for a human to read them, but -/// this is a hinderance that tooling can remedy, and APIs are not primarily -/// for humans. -/// -/// # Examples -/// -/// ```gleam -/// timestamp.from_unix_seconds_and_nanoseconds(1000, 123_000_000) -/// |> to_rfc3339(calendar.utc_offset) -/// // -> "1970-01-01T00:16:40.123Z" -/// ``` -/// -/// ```gleam -/// timestamp.from_unix_seconds(1000) -/// |> to_rfc3339(duration.seconds(3600)) -/// // -> "1970-01-01T01:16:40+01:00" -/// ``` -/// -pub fn to_rfc3339(timestamp: Timestamp, offset: Duration) -> String { - let offset = duration_to_minutes(offset) - let #(years, months, days, hours, minutes, seconds) = - to_calendar_from_offset(timestamp, offset) - - let offset_minutes = modulo(offset, 60) - let offset_hours = int.absolute_value(floored_div(offset, 60.0)) - - let n2 = pad_digit(_, to: 2) - let n4 = pad_digit(_, to: 4) - let out = "" - let out = out <> n4(years) <> "-" <> n2(months) <> "-" <> n2(days) - let out = out <> "T" - let out = out <> n2(hours) <> ":" <> n2(minutes) <> ":" <> n2(seconds) - let out = out <> show_second_fraction(timestamp.nanoseconds) - case int.compare(offset, 0) { - order.Eq -> out <> "Z" - order.Gt -> out <> "+" <> n2(offset_hours) <> ":" <> n2(offset_minutes) - order.Lt -> out <> "-" <> n2(offset_hours) <> ":" <> n2(offset_minutes) - } -} - -fn pad_digit(digit: Int, to desired_length: Int) -> String { - int.to_string(digit) |> string.pad_start(desired_length, "0") -} - -/// Convert a `Timestamp` to calendar time, suitable for presenting to a human -/// to read. -/// -/// If you want a machine to use the time value then you should not use this -/// function and should instead keep it as a timestamp. See the documentation -/// for the `gleam/time/calendar` module for more information. -/// -/// # Examples -/// -/// ```gleam -/// timestamp.from_unix_seconds(0) -/// |> timestamp.to_calendar(calendar.utc_offset) -/// // -> #(Date(1970, January, 1), TimeOfDay(0, 0, 0, 0)) -/// ``` -/// -pub fn to_calendar( - timestamp: Timestamp, - offset: Duration, -) -> #(calendar.Date, calendar.TimeOfDay) { - let offset = duration_to_minutes(offset) - let #(year, month, day, hours, minutes, seconds) = - to_calendar_from_offset(timestamp, offset) - let month = case month { - 1 -> calendar.January - 2 -> calendar.February - 3 -> calendar.March - 4 -> calendar.April - 5 -> calendar.May - 6 -> calendar.June - 7 -> calendar.July - 8 -> calendar.August - 9 -> calendar.September - 10 -> calendar.October - 11 -> calendar.November - _ -> calendar.December - } - let nanoseconds = timestamp.nanoseconds - let date = calendar.Date(year:, month:, day:) - let time = calendar.TimeOfDay(hours:, minutes:, seconds:, nanoseconds:) - #(date, time) -} - -fn duration_to_minutes(duration: duration.Duration) -> Int { - float.round(duration.to_seconds(duration) /. 60.0) -} - -fn to_calendar_from_offset( - timestamp: Timestamp, - offset: Int, -) -> #(Int, Int, Int, Int, Int, Int) { - let total = timestamp.seconds + { offset * 60 } - let seconds = modulo(total, 60) - let total_minutes = floored_div(total, 60.0) - let minutes = modulo(total, 60 * 60) / 60 - let hours = modulo(total, 24 * 60 * 60) / { 60 * 60 } - let #(year, month, day) = to_civil(total_minutes) - #(year, month, day, hours, minutes, seconds) -} - -/// Create a `Timestamp` from a human-readable calendar time. -/// -/// # Examples -/// -/// ```gleam -/// timestamp.from_calendar( -/// date: calendar.Date(2024, calendar.December, 25), -/// time: calendar.TimeOfDay(12, 30, 50, 0), -/// offset: calendar.utc_offset, -/// ) -/// |> timestamp.to_rfc3339(calendar.utc_offset) -/// // -> "2024-12-25T12:30:50Z" -/// ``` -/// -pub fn from_calendar( - date date: calendar.Date, - time time: calendar.TimeOfDay, - offset offset: Duration, -) -> Timestamp { - let month = case date.month { - calendar.January -> 1 - calendar.February -> 2 - calendar.March -> 3 - calendar.April -> 4 - calendar.May -> 5 - calendar.June -> 6 - calendar.July -> 7 - calendar.August -> 8 - calendar.September -> 9 - calendar.October -> 10 - calendar.November -> 11 - calendar.December -> 12 - } - from_date_time( - year: date.year, - month:, - day: date.day, - hours: time.hours, - minutes: time.minutes, - seconds: time.seconds, - second_fraction_as_nanoseconds: time.nanoseconds, - offset_seconds: float.round(duration.to_seconds(offset)), - ) -} - -fn modulo(n: Int, m: Int) -> Int { - case int.modulo(n, m) { - Ok(n) -> n - Error(_) -> 0 - } -} - -fn floored_div(numerator: Int, denominator: Float) -> Int { - let n = int.to_float(numerator) /. denominator - float.round(float.floor(n)) -} - -// Adapted from Elm's Time module -fn to_civil(minutes: Int) -> #(Int, Int, Int) { - let raw_day = floored_div(minutes, { 60.0 *. 24.0 }) + 719_468 - let era = case raw_day >= 0 { - True -> raw_day / 146_097 - False -> { raw_day - 146_096 } / 146_097 - } - let day_of_era = raw_day - era * 146_097 - let year_of_era = - { - day_of_era - - { day_of_era / 1460 } - + { day_of_era / 36_524 } - - { day_of_era / 146_096 } - } - / 365 - let year = year_of_era + era * 400 - let day_of_year = - day_of_era - - { 365 * year_of_era + { year_of_era / 4 } - { year_of_era / 100 } } - let mp = { 5 * day_of_year + 2 } / 153 - let month = case mp < 10 { - True -> mp + 3 - False -> mp - 9 - } - let day = day_of_year - { 153 * mp + 2 } / 5 + 1 - let year = case month <= 2 { - True -> year + 1 - False -> year - } - #(year, month, day) -} - -/// Converts nanoseconds into a `String` representation of fractional seconds. -/// -/// Assumes that `nanoseconds < 1_000_000_000`, which will be true for any -/// normalised timestamp. -/// -fn show_second_fraction(nanoseconds: Int) -> String { - case int.compare(nanoseconds, 0) { - // Zero fractional seconds are not shown. - order.Lt | order.Eq -> "" - order.Gt -> { - let second_fraction_part = { - nanoseconds - |> get_zero_padded_digits - |> remove_trailing_zeros - |> list.map(int.to_string) - |> string.join("") - } - - "." <> second_fraction_part - } - } -} - -/// Given a list of digits, return new list with any trailing zeros removed. -/// -fn remove_trailing_zeros(digits: List(Int)) -> List(Int) { - let reversed_digits = list.reverse(digits) - - do_remove_trailing_zeros(reversed_digits) -} - -fn do_remove_trailing_zeros(reversed_digits) { - case reversed_digits { - [] -> [] - [digit, ..digits] if digit == 0 -> do_remove_trailing_zeros(digits) - reversed_digits -> list.reverse(reversed_digits) - } -} - -/// Returns the list of digits of `number`. If the number of digits is less -/// than 9, the result is zero-padded at the front. -/// -fn get_zero_padded_digits(number: Int) -> List(Int) { - do_get_zero_padded_digits(number, [], 0) -} - -fn do_get_zero_padded_digits( - number: Int, - digits: List(Int), - count: Int, -) -> List(Int) { - case number { - number if number <= 0 && count >= 9 -> digits - number if number <= 0 -> - // Zero-pad the digits at the front until we have at least 9 digits. - do_get_zero_padded_digits(number, [0, ..digits], count + 1) - number -> { - let digit = number % 10 - let number = floored_div(number, 10.0) - do_get_zero_padded_digits(number, [digit, ..digits], count + 1) - } - } -} - -/// Parses an [RFC 3339 formatted time string][spec] into a `Timestamp`. -/// -/// [spec]: https://datatracker.ietf.org/doc/html/rfc3339#section-5.6 -/// -/// # Examples -/// -/// ```gleam -/// let assert Ok(ts) = timestamp.parse_rfc3339("1970-01-01T00:00:01Z") -/// timestamp.to_unix_seconds_and_nanoseconds(ts) -/// // -> #(1, 0) -/// ``` -/// -/// Parsing an invalid timestamp returns an error. -/// -/// ```gleam -/// let assert Error(Nil) = timestamp.parse_rfc3339("1995-10-31") -/// ``` -/// -/// ## Time zones -/// -/// It may at first seem that the RFC 3339 format includes timezone -/// information, as it can specify an offset such as `Z` or `+3`, so why does -/// this function not return calendar time with a time zone? There are multiple -/// reasons: -/// -/// - RFC 3339's timestamp format is based on calendar time, but it is -/// unambigous, so it can be converted into epoch time when being parsed. It -/// is always better to internally use epoch time to represent unambiguous -/// points in time, so we perform that conversion as a convenience and to -/// ensure that programmers with less time experience don't accidentally use -/// a less suitable time representation. -/// -/// - RFC 3339's contains _calendar time offset_ information, not time zone -/// information. This is enough to convert it to an unambiguous timestamp, -/// but it is not enough information to reliably work with calendar time. -/// Without the time zone and the time zone database it's not possible to -/// know what time period that offset is valid for, so it cannot be used -/// without risk of bugs. -/// -/// ## Behaviour details -/// -/// - Follows the grammar specified in section 5.6 Internet Date/Time Format of -/// RFC 3339 . -/// - The `T` and `Z` characters may alternatively be lower case `t` or `z`, -/// respectively. -/// - Full dates and full times must be separated by `T` or `t`. A space is also -/// permitted. -/// - Leap seconds rules are not considered. That is, any timestamp may -/// specify digts `00` - `60` for the seconds. -/// - Any part of a fractional second that cannot be represented in the -/// nanosecond precision is tructated. That is, for the time string, -/// `"1970-01-01T00:00:00.1234567899Z"`, the fractional second `.1234567899` -/// will be represented as `123_456_789` in the `Timestamp`. -/// -pub fn parse_rfc3339(input: String) -> Result(Timestamp, Nil) { - let bytes = bit_array.from_string(input) - - // Date - use #(year, bytes) <- result.try(parse_year(from: bytes)) - use bytes <- result.try(accept_byte(from: bytes, value: byte_minus)) - use #(month, bytes) <- result.try(parse_month(from: bytes)) - use bytes <- result.try(accept_byte(from: bytes, value: byte_minus)) - use #(day, bytes) <- result.try(parse_day(from: bytes, year:, month:)) - - use bytes <- result.try(accept_date_time_separator(from: bytes)) - - // Time - use #(hours, bytes) <- result.try(parse_hours(from: bytes)) - use bytes <- result.try(accept_byte(from: bytes, value: byte_colon)) - use #(minutes, bytes) <- result.try(parse_minutes(from: bytes)) - use bytes <- result.try(accept_byte(from: bytes, value: byte_colon)) - use #(seconds, bytes) <- result.try(parse_seconds(from: bytes)) - use #(second_fraction_as_nanoseconds, bytes) <- result.try( - parse_second_fraction_as_nanoseconds(from: bytes), - ) - - // Offset - use #(offset_seconds, bytes) <- result.try(parse_offset(from: bytes)) - - // Done - use Nil <- result.try(accept_empty(bytes)) - - Ok(from_date_time( - year:, - month:, - day:, - hours:, - minutes:, - seconds:, - second_fraction_as_nanoseconds:, - offset_seconds:, - )) -} - -fn parse_year(from bytes: BitArray) -> Result(#(Int, BitArray), Nil) { - parse_digits(from: bytes, count: 4) -} - -fn parse_month(from bytes: BitArray) -> Result(#(Int, BitArray), Nil) { - use #(month, bytes) <- result.try(parse_digits(from: bytes, count: 2)) - case 1 <= month && month <= 12 { - True -> Ok(#(month, bytes)) - False -> Error(Nil) - } -} - -fn parse_day( - from bytes: BitArray, - year year, - month month, -) -> Result(#(Int, BitArray), Nil) { - use #(day, bytes) <- result.try(parse_digits(from: bytes, count: 2)) - - use max_day <- result.try(case month { - 1 | 3 | 5 | 7 | 8 | 10 | 12 -> Ok(31) - 4 | 6 | 9 | 11 -> Ok(30) - 2 -> { - case is_leap_year(year) { - True -> Ok(29) - False -> Ok(28) - } - } - _ -> Error(Nil) - }) - - case 1 <= day && day <= max_day { - True -> Ok(#(day, bytes)) - False -> Error(Nil) - } -} - -// Implementation from RFC 3339 Appendix C -fn is_leap_year(year: Int) -> Bool { - year % 4 == 0 && { year % 100 != 0 || year % 400 == 0 } -} - -fn parse_hours(from bytes: BitArray) -> Result(#(Int, BitArray), Nil) { - use #(hours, bytes) <- result.try(parse_digits(from: bytes, count: 2)) - case 0 <= hours && hours <= 23 { - True -> Ok(#(hours, bytes)) - False -> Error(Nil) - } -} - -fn parse_minutes(from bytes: BitArray) -> Result(#(Int, BitArray), Nil) { - use #(minutes, bytes) <- result.try(parse_digits(from: bytes, count: 2)) - case 0 <= minutes && minutes <= 59 { - True -> Ok(#(minutes, bytes)) - False -> Error(Nil) - } -} - -fn parse_seconds(from bytes: BitArray) -> Result(#(Int, BitArray), Nil) { - use #(seconds, bytes) <- result.try(parse_digits(from: bytes, count: 2)) - // Max of 60 for leap seconds. We don't bother to check if this leap second - // actually occurred in the past or not. - case 0 <= seconds && seconds <= 60 { - True -> Ok(#(seconds, bytes)) - False -> Error(Nil) - } -} - -// Truncates any part of the fraction that is beyond the nanosecond precision. -fn parse_second_fraction_as_nanoseconds(from bytes: BitArray) { - case bytes { - <<".", byte, remaining_bytes:bytes>> - if byte_zero <= byte && byte <= byte_nine - -> { - do_parse_second_fraction_as_nanoseconds( - from: <>, - acc: 0, - power: nanoseconds_per_second, - ) - } - // bytes starts with a ".", which should introduce a fraction, but it does - // not, and so it is an ill-formed input. - <<".", _:bytes>> -> Error(Nil) - // bytes does not start with a "." so there is no fraction. Call this 0 - // nanoseconds. - _ -> Ok(#(0, bytes)) - } -} - -fn do_parse_second_fraction_as_nanoseconds( - from bytes: BitArray, - acc acc: Int, - power power: Int, -) -> Result(#(Int, BitArray), a) { - // Each digit place to the left in the fractional second is 10x fewer - // nanoseconds. - let power = power / 10 - - case bytes { - <> - if byte_zero <= byte && byte <= byte_nine && power < 1 - -> { - // We already have the max precision for nanoseconds. Truncate any - // remaining digits. - do_parse_second_fraction_as_nanoseconds( - from: remaining_bytes, - acc:, - power:, - ) - } - <> if byte_zero <= byte && byte <= byte_nine -> { - // We have not yet reached the precision limit. Parse the next digit. - let digit = byte - 0x30 - do_parse_second_fraction_as_nanoseconds( - from: remaining_bytes, - acc: acc + digit * power, - power:, - ) - } - _ -> Ok(#(acc, bytes)) - } -} - -fn parse_offset(from bytes: BitArray) -> Result(#(Int, BitArray), Nil) { - case bytes { - <<"Z", remaining_bytes:bytes>> | <<"z", remaining_bytes:bytes>> -> - Ok(#(0, remaining_bytes)) - _ -> parse_numeric_offset(bytes) - } -} - -fn parse_numeric_offset(from bytes: BitArray) -> Result(#(Int, BitArray), Nil) { - use #(sign, bytes) <- result.try(parse_sign(from: bytes)) - use #(hours, bytes) <- result.try(parse_hours(from: bytes)) - use bytes <- result.try(accept_byte(from: bytes, value: byte_colon)) - use #(minutes, bytes) <- result.try(parse_minutes(from: bytes)) - - let offset_seconds = offset_to_seconds(sign, hours:, minutes:) - - Ok(#(offset_seconds, bytes)) -} - -fn parse_sign(from bytes) { - case bytes { - <<"+", remaining_bytes:bytes>> -> Ok(#("+", remaining_bytes)) - <<"-", remaining_bytes:bytes>> -> Ok(#("-", remaining_bytes)) - _ -> Error(Nil) - } -} - -fn offset_to_seconds(sign, hours hours, minutes minutes) { - let abs_seconds = hours * seconds_per_hour + minutes * seconds_per_minute - - case sign { - "-" -> -abs_seconds - _ -> abs_seconds - } -} - -/// Parse and return the given number of digits from the given bytes. -/// -fn parse_digits( - from bytes: BitArray, - count count: Int, -) -> Result(#(Int, BitArray), Nil) { - do_parse_digits(from: bytes, count:, acc: 0, k: 0) -} - -fn do_parse_digits( - from bytes: BitArray, - count count: Int, - acc acc: Int, - k k: Int, -) -> Result(#(Int, BitArray), Nil) { - case bytes { - _ if k >= count -> Ok(#(acc, bytes)) - <> if byte_zero <= byte && byte <= byte_nine -> - do_parse_digits( - from: remaining_bytes, - count:, - acc: acc * 10 + { byte - 0x30 }, - k: k + 1, - ) - _ -> Error(Nil) - } -} - -/// Accept the given value from `bytes` and move past it if found. -/// -fn accept_byte(from bytes: BitArray, value value: Int) -> Result(BitArray, Nil) { - case bytes { - <> if byte == value -> Ok(remaining_bytes) - _ -> Error(Nil) - } -} - -fn accept_date_time_separator(from bytes: BitArray) -> Result(BitArray, Nil) { - case bytes { - <> - if byte == byte_t_uppercase - || byte == byte_t_lowercase - || byte == byte_space - -> Ok(remaining_bytes) - _ -> Error(Nil) - } -} - -fn accept_empty(from bytes: BitArray) -> Result(Nil, Nil) { - case bytes { - <<>> -> Ok(Nil) - _ -> Error(Nil) - } -} - -/// Note: The caller of this function must ensure that all inputs are valid. -/// -fn from_date_time( - year year: Int, - month month: Int, - day day: Int, - hours hours: Int, - minutes minutes: Int, - seconds seconds: Int, - second_fraction_as_nanoseconds second_fraction_as_nanoseconds: Int, - offset_seconds offset_seconds: Int, -) -> Timestamp { - let julian_seconds = - julian_seconds_from_parts(year:, month:, day:, hours:, minutes:, seconds:) - - let julian_seconds_since_epoch = julian_seconds - julian_seconds_unix_epoch - - Timestamp( - seconds: julian_seconds_since_epoch - offset_seconds, - nanoseconds: second_fraction_as_nanoseconds, - ) - |> normalise -} - -/// `julian_seconds_from_parts(year, month, day, hours, minutes, seconds)` -/// returns the number of Julian -/// seconds represented by the given arguments. -/// -/// Note: It is the callers responsibility to ensure the inputs are valid. -/// -/// See https://www.tondering.dk/claus/cal/julperiod.php#formula -/// -fn julian_seconds_from_parts( - year year: Int, - month month: Int, - day day: Int, - hours hours: Int, - minutes minutes: Int, - seconds seconds: Int, -) { - let julian_day_seconds = - julian_day_from_ymd(year:, month:, day:) * seconds_per_day - - julian_day_seconds - + { hours * seconds_per_hour } - + { minutes * seconds_per_minute } - + seconds -} - -/// Note: It is the callers responsibility to ensure the inputs are valid. -/// -/// See https://www.tondering.dk/claus/cal/julperiod.php#formula -/// -fn julian_day_from_ymd(year year: Int, month month: Int, day day: Int) -> Int { - let adjustment = { 14 - month } / 12 - let adjusted_year = year + 4800 - adjustment - let adjusted_month = month + 12 * adjustment - 3 - - day - + { { 153 * adjusted_month } + 2 } - / 5 - + 365 - * adjusted_year - + { adjusted_year / 4 } - - { adjusted_year / 100 } - + { adjusted_year / 400 } - - 32_045 -} - -/// Create a timestamp from a number of seconds since 00:00:00 UTC on 1 January -/// 1970. -/// -pub fn from_unix_seconds(seconds: Int) -> Timestamp { - Timestamp(seconds, 0) -} - -/// Create a timestamp from a number of seconds and nanoseconds since 00:00:00 -/// UTC on 1 January 1970. -/// -/// # JavaScript int limitations -/// -/// Remember that JavaScript can only perfectly represent ints between positive -/// and negative 9,007,199,254,740,991! If you only use the nanosecond field -/// then you will almost certainly not get the date value you want due to this -/// loss of precision. Always use seconds primarily and then use nanoseconds -/// for the final sub-second adjustment. -/// -pub fn from_unix_seconds_and_nanoseconds( - seconds seconds: Int, - nanoseconds nanoseconds: Int, -) -> Timestamp { - Timestamp(seconds, nanoseconds) - |> normalise -} - -/// Convert the timestamp to a number of seconds since 00:00:00 UTC on 1 -/// January 1970. -/// -/// There may be some small loss of precision due to `Timestamp` being -/// nanosecond accurate and `Float` not being able to represent this. -/// -pub fn to_unix_seconds(timestamp: Timestamp) -> Float { - let seconds = int.to_float(timestamp.seconds) - let nanoseconds = int.to_float(timestamp.nanoseconds) - seconds +. { nanoseconds /. 1_000_000_000.0 } -} - -/// Convert the timestamp to a number of seconds and nanoseconds since 00:00:00 -/// UTC on 1 January 1970. There is no loss of precision with this conversion -/// on any target. -pub fn to_unix_seconds_and_nanoseconds(timestamp: Timestamp) -> #(Int, Int) { - #(timestamp.seconds, timestamp.nanoseconds) -} diff --git a/build/packages/gleam_time/src/gleam@time@calendar.erl b/build/packages/gleam_time/src/gleam@time@calendar.erl deleted file mode 100644 index e295d09..0000000 --- a/build/packages/gleam_time/src/gleam@time@calendar.erl +++ /dev/null @@ -1,468 +0,0 @@ --module(gleam@time@calendar). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "src/gleam/time/calendar.gleam"). --export([local_offset/0, month_to_string/1, month_to_int/1, month_from_int/1, is_leap_year/1, is_valid_date/1, is_valid_time_of_day/1, naive_date_compare/2]). --export_type([date/0, time_of_day/0, month/0]). - --if(?OTP_RELEASE >= 27). --define(MODULEDOC(Str), -moduledoc(Str)). --define(DOC(Str), -doc(Str)). --else. --define(MODULEDOC(Str), -compile([])). --define(DOC(Str), -compile([])). --endif. - -?MODULEDOC( - " This module is for working with the Gregorian calendar, established by\n" - " Pope Gregory XIII in 1582!\n" - "\n" - " ## When should you use this module?\n" - "\n" - " > **tldr:** You probably want to use [`gleam/time/timestamp`](./timestamp.html)\n" - " > instead!\n" - "\n" - " Calendar time is difficult to work with programmatically, it is the source\n" - " of most time-related bugs in software. Compared to _epoch time_, which the\n" - " `gleam/time/timestamp` module uses, there are many disadvantages to\n" - " calendar time:\n" - "\n" - " - They are ambiguous if you don't know what time-zone is being used.\n" - "\n" - " - A time-zone database is required to understand calendar time even when\n" - " you have the time zone. These are large and your program has to\n" - " continously be updated as new versions of the database are published.\n" - "\n" - " - The type permits invalid states. e.g. `days` could be set to the number\n" - " 32, but this should not be possible!\n" - "\n" - " - There is not a single unique canonical value for each point in time,\n" - " thanks to time zones. Two different `Date` + `TimeOfDay` value pairs\n" - " could represent the same point in time. This means that you can't check\n" - " for time equality with `==` when using calendar types.\n" - "\n" - " - They are computationally complex, using a more memory to represent and\n" - " requiring a lot more CPU time to manipulate.\n" - "\n" - " There are also advantages to calendar time:\n" - "\n" - " - Calendar time is how human's talk about time, so if you want to show a\n" - " time or take a time from a human user then calendar time will make it\n" - " easier for them.\n" - "\n" - " - They can represent more abstract time periods such as \"New Year's Day\".\n" - " This may seem like an exact window of time at first, but really the\n" - " definition of \"New Year's Day\" is more fuzzy than that. When it starts\n" - " and ends will depend where in the world you are, so if you want to refer\n" - " to a day as a global concept instead of a fixed window of time for that\n" - " day in a specific location, then calendar time can represent that.\n" - "\n" - " So when should you use calendar time? These are our recommendations:\n" - "\n" - " - Default to `gleam/time/timestamp`, which is epoch time. It is\n" - " unambiguous, efficient, and significantly less likely to result in logic\n" - " bugs.\n" - "\n" - " - When writing time to a database or other data storage use epoch time,\n" - " using whatever epoch format it supports. For example, PostgreSQL\n" - " `timestamp` and `timestampz` are both epoch time, and `timestamp` is\n" - " preferred as it is more straightforward to use as your application is\n" - " also using epoch time.\n" - "\n" - " - When communicating with other computer systems continue to use epoch\n" - " time. For example, when sending times to another program you could\n" - " encode time as UNIX timestamps (seconds since 00:00:00 UTC on 1 January\n" - " 1970).\n" - "\n" - " - When communicating with humans use epoch time internally, and convert\n" - " to-and-from calendar time at the last moment, when iteracting with the\n" - " human user. It may also help the users to also show the time as a fuzzy\n" - " duration from the present time, such as \"about 4 days ago\".\n" - "\n" - " - When representing \"fuzzy\" human time concepts that don't exact periods\n" - " in time, such as \"one month\" (varies depending on which month, which\n" - " year, and in which time zone) and \"Christmas Day\" (varies depending on\n" - " which year and time zone) then use calendar time.\n" - "\n" - " Any time you do use calendar time you should be extra careful! It is very\n" - " easy to make mistake with. Avoid it where possible.\n" - "\n" - " ## Time zone offsets\n" - "\n" - " This package includes the `utc_offset` value and the `local_offset`\n" - " function, which are the offset for the UTC time zone and get the time\n" - " offset the computer running the program is configured to respectively.\n" - "\n" - " If you need to use other offsets in your program then you will need to get\n" - " them from somewhere else, such as from a package which loads the\n" - " [IANA Time Zone Database](https://www.iana.org/time-zones), or from the\n" - " website visitor's web browser, which your frontend can send for you.\n" - "\n" - " ## Use in APIs\n" - "\n" - " If you are making an API such as a HTTP JSON API you are encouraged to use\n" - " Unix timestamps instead of calendar times.\n" -). - --type date() :: {date, integer(), month(), integer()}. - --type time_of_day() :: {time_of_day, integer(), integer(), integer(), integer()}. - --type month() :: january | - february | - march | - april | - may | - june | - july | - august | - september | - october | - november | - december. - --file("src/gleam/time/calendar.gleam", 147). -?DOC( - " Get the offset for the computer's currently configured time zone.\n" - "\n" - " Note this may not be the time zone that is correct to use for your user.\n" - " For example, if you are making a web application that runs on a server you\n" - " want _their_ computer's time zone, not yours.\n" - "\n" - " This is the _current local_ offset, not the current local time zone. This\n" - " means that while it will result in the expected outcome for the current\n" - " time, it may result in unexpected output if used with other timestamps. For\n" - " example: a timestamp that would locally be during daylight savings time if\n" - " is it not currently daylight savings time when this function is called.\n" -). --spec local_offset() -> gleam@time@duration:duration(). -local_offset() -> - gleam@time@duration:seconds(gleam_time_ffi:local_time_offset_seconds()). - --file("src/gleam/time/calendar.gleam", 163). -?DOC( - " Returns the English name for a month.\n" - "\n" - " # Examples\n" - "\n" - " ```gleam\n" - " month_to_string(April)\n" - " // -> \"April\"\n" - " ```\n" -). --spec month_to_string(month()) -> binary(). -month_to_string(Month) -> - case Month of - january -> - <<"January"/utf8>>; - - february -> - <<"February"/utf8>>; - - march -> - <<"March"/utf8>>; - - april -> - <<"April"/utf8>>; - - may -> - <<"May"/utf8>>; - - june -> - <<"June"/utf8>>; - - july -> - <<"July"/utf8>>; - - august -> - <<"August"/utf8>>; - - september -> - <<"September"/utf8>>; - - october -> - <<"October"/utf8>>; - - november -> - <<"November"/utf8>>; - - december -> - <<"December"/utf8>> - end. - --file("src/gleam/time/calendar.gleam", 188). -?DOC( - " Returns the number for the month, where January is 1 and December is 12.\n" - "\n" - " # Examples\n" - "\n" - " ```gleam\n" - " month_to_int(January)\n" - " // -> 1\n" - " ```\n" -). --spec month_to_int(month()) -> integer(). -month_to_int(Month) -> - case Month of - january -> - 1; - - february -> - 2; - - march -> - 3; - - april -> - 4; - - may -> - 5; - - june -> - 6; - - july -> - 7; - - august -> - 8; - - september -> - 9; - - october -> - 10; - - november -> - 11; - - december -> - 12 - end. - --file("src/gleam/time/calendar.gleam", 213). -?DOC( - " Returns the month for a given number, where January is 1 and December is 12.\n" - "\n" - " # Examples\n" - "\n" - " ```gleam\n" - " month_from_int(1)\n" - " // -> Ok(January)\n" - " ```\n" -). --spec month_from_int(integer()) -> {ok, month()} | {error, nil}. -month_from_int(Month) -> - case Month of - 1 -> - {ok, january}; - - 2 -> - {ok, february}; - - 3 -> - {ok, march}; - - 4 -> - {ok, april}; - - 5 -> - {ok, may}; - - 6 -> - {ok, june}; - - 7 -> - {ok, july}; - - 8 -> - {ok, august}; - - 9 -> - {ok, september}; - - 10 -> - {ok, october}; - - 11 -> - {ok, november}; - - 12 -> - {ok, december}; - - _ -> - {error, nil} - end. - --file("src/gleam/time/calendar.gleam", 290). -?DOC( - " Determines if a given year is a leap year.\n" - "\n" - " A leap year occurs every 4 years, except for years divisible by 100,\n" - " unless they are also divisible by 400.\n" - "\n" - " # Examples\n" - "\n" - " ```gleam\n" - " is_leap_year(2024)\n" - " // -> True\n" - " ```\n" - "\n" - " ```gleam\n" - " is_leap_year(2023)\n" - " // -> False\n" - " ```\n" -). --spec is_leap_year(integer()) -> boolean(). -is_leap_year(Year) -> - case (Year rem 400) =:= 0 of - true -> - true; - - false -> - case (Year rem 100) =:= 0 of - true -> - false; - - false -> - (Year rem 4) =:= 0 - end - end. - --file("src/gleam/time/calendar.gleam", 254). -?DOC( - " Checks if a given date is valid.\n" - "\n" - " This function properly accounts for leap years when validating February days.\n" - " A leap year occurs every 4 years, except for years divisible by 100,\n" - " unless they are also divisible by 400.\n" - "\n" - " # Examples\n" - "\n" - " ```gleam\n" - " is_valid_date(Date(2023, April, 15))\n" - " // -> True\n" - " ```\n" - "\n" - " ```gleam\n" - " is_valid_date(Date(2023, April, 31))\n" - " // -> False\n" - " ```\n" - "\n" - " ```gleam\n" - " is_valid_date(Date(2024, February, 29))\n" - " // -> True (2024 is a leap year)\n" - " ```\n" -). --spec is_valid_date(date()) -> boolean(). -is_valid_date(Date) -> - {date, Year, Month, Day} = Date, - case Day < 1 of - true -> - false; - - false -> - case Month of - january -> - Day =< 31; - - march -> - Day =< 31; - - may -> - Day =< 31; - - july -> - Day =< 31; - - august -> - Day =< 31; - - october -> - Day =< 31; - - december -> - Day =< 31; - - april -> - Day =< 30; - - june -> - Day =< 30; - - september -> - Day =< 30; - - november -> - Day =< 30; - - february -> - Max_february_days = case is_leap_year(Year) of - true -> - 29; - - false -> - 28 - end, - Day =< Max_february_days - end - end. - --file("src/gleam/time/calendar.gleam", 313). -?DOC( - " Checks if a time of day is valid.\n" - "\n" - " Validates that hours are 0-23, minutes are 0-59, seconds are 0-59,\n" - " and nanoseconds are 0-999,999,999.\n" - "\n" - " # Examples\n" - "\n" - " ```gleam\n" - " is_valid_time_of_day(TimeOfDay(12, 30, 45, 123456789))\n" - " // -> True\n" - " ```\n" -). --spec is_valid_time_of_day(time_of_day()) -> boolean(). -is_valid_time_of_day(Time) -> - {time_of_day, Hours, Minutes, Seconds, Nanoseconds} = Time, - (((((((Hours >= 0) andalso (Hours =< 23)) andalso (Minutes >= 0)) andalso (Minutes - =< 59)) - andalso (Seconds >= 0)) - andalso (Seconds =< 59)) - andalso (Nanoseconds >= 0)) - andalso (Nanoseconds =< 999999999). - --file("src/gleam/time/calendar.gleam", 340). -?DOC( - " Naively compares two dates without any time zone information, returning an\n" - " order.\n" - "\n" - " ## Correctness\n" - "\n" - " This function compares dates without any time zone information, only using\n" - " the rules for the gregorian calendar. This is typically sufficient, but be\n" - " aware that in reality some time zones will change their calendar date\n" - " occasionally. This can result in days being skipped, out of order, or\n" - " happening multiple times.\n" - "\n" - " If you need real-world correct time ordering then use the\n" - " `gleam/time/timestamp` module instead.\n" -). --spec naive_date_compare(date(), date()) -> gleam@order:order(). -naive_date_compare(One, Other) -> - _pipe = gleam@int:compare(erlang:element(2, One), erlang:element(2, Other)), - _pipe@1 = gleam@order:lazy_break_tie( - _pipe, - fun() -> - gleam@int:compare( - month_to_int(erlang:element(3, One)), - month_to_int(erlang:element(3, Other)) - ) - end - ), - gleam@order:lazy_break_tie( - _pipe@1, - fun() -> - gleam@int:compare(erlang:element(4, One), erlang:element(4, Other)) - end - ). diff --git a/build/packages/gleam_time/src/gleam@time@duration.erl b/build/packages/gleam_time/src/gleam@time@duration.erl deleted file mode 100644 index 7ba7ad2..0000000 --- a/build/packages/gleam_time/src/gleam@time@duration.erl +++ /dev/null @@ -1,381 +0,0 @@ --module(gleam@time@duration). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "src/gleam/time/duration.gleam"). --export([approximate/1, compare/2, difference/2, add/2, seconds/1, minutes/1, hours/1, milliseconds/1, nanoseconds/1, to_seconds/1, to_seconds_and_nanoseconds/1, to_iso8601_string/1]). --export_type([duration/0, unit/0]). - --if(?OTP_RELEASE >= 27). --define(MODULEDOC(Str), -moduledoc(Str)). --define(DOC(Str), -doc(Str)). --else. --define(MODULEDOC(Str), -compile([])). --define(DOC(Str), -compile([])). --endif. - --opaque duration() :: {duration, integer(), integer()}. - --type unit() :: nanosecond | - microsecond | - millisecond | - second | - minute | - hour | - day | - week | - month | - year. - --file("src/gleam/time/duration.gleam", 110). -?DOC( - " Ensure the duration is represented with `nanoseconds` being positive and\n" - " less than 1 second.\n" - "\n" - " This function does not change the amount of time that the duratoin refers\n" - " to, it only adjusts the values used to represent the time.\n" -). --spec normalise(duration()) -> duration(). -normalise(Duration) -> - Multiplier = 1000000000, - Nanoseconds = case Multiplier of - 0 -> 0; - Gleam@denominator -> erlang:element(3, Duration) rem Gleam@denominator - end, - Overflow = erlang:element(3, Duration) - Nanoseconds, - Seconds = erlang:element(2, Duration) + (case Multiplier of - 0 -> 0; - Gleam@denominator@1 -> Overflow div Gleam@denominator@1 - end), - case Nanoseconds >= 0 of - true -> - {duration, Seconds, Nanoseconds}; - - false -> - {duration, Seconds - 1, Multiplier + Nanoseconds} - end. - --file("src/gleam/time/duration.gleam", 76). -?DOC( - " Convert a duration to a number of the largest number of a unit, serving as\n" - " a rough description of the duration that a human can understand.\n" - "\n" - " The size used for each unit are described in the documentation for the\n" - " `Unit` type.\n" - "\n" - " ```gleam\n" - " seconds(125)\n" - " |> approximate\n" - " // -> #(2, Minute)\n" - " ```\n" - "\n" - " This function rounds _towards zero_. This means that if a duration is just\n" - " short of 2 days then it will approximate to 1 day.\n" - "\n" - " ```gleam\n" - " hours(47)\n" - " |> approximate\n" - " // -> #(1, Day)\n" - " ```\n" -). --spec approximate(duration()) -> {integer(), unit()}. -approximate(Duration) -> - {duration, S, Ns} = Duration, - Minute = 60, - Hour = Minute * 60, - Day = Hour * 24, - Week = Day * 7, - Year = (Day * 365) + (Hour * 6), - Month = Year div 12, - Microsecond = 1000, - Millisecond = Microsecond * 1000, - case nil of - _ when S < 0 -> - {Amount, Unit} = begin - _pipe = {duration, - S, - Ns}, - _pipe@1 = normalise(_pipe), - approximate(_pipe@1) - end, - {- Amount, Unit}; - - _ when S >= Year -> - {case Year of - 0 -> 0; - Gleam@denominator -> S div Gleam@denominator - end, year}; - - _ when S >= Month -> - {case Month of - 0 -> 0; - Gleam@denominator@1 -> S div Gleam@denominator@1 - end, month}; - - _ when S >= Week -> - {case Week of - 0 -> 0; - Gleam@denominator@2 -> S div Gleam@denominator@2 - end, week}; - - _ when S >= Day -> - {case Day of - 0 -> 0; - Gleam@denominator@3 -> S div Gleam@denominator@3 - end, day}; - - _ when S >= Hour -> - {case Hour of - 0 -> 0; - Gleam@denominator@4 -> S div Gleam@denominator@4 - end, hour}; - - _ when S >= Minute -> - {case Minute of - 0 -> 0; - Gleam@denominator@5 -> S div Gleam@denominator@5 - end, minute}; - - _ when S > 0 -> - {S, second}; - - _ when Ns >= Millisecond -> - {case Millisecond of - 0 -> 0; - Gleam@denominator@6 -> Ns div Gleam@denominator@6 - end, millisecond}; - - _ when Ns >= Microsecond -> - {case Microsecond of - 0 -> 0; - Gleam@denominator@7 -> Ns div Gleam@denominator@7 - end, microsecond}; - - _ -> - {Ns, nanosecond} - end. - --file("src/gleam/time/duration.gleam", 140). -?DOC( - " Compare one duration to another, indicating whether the first spans a\n" - " larger amount of time (and so is greater) or smaller amount of time (and so\n" - " is lesser) than the second.\n" - "\n" - " # Examples\n" - "\n" - " ```gleam\n" - " compare(seconds(1), seconds(2))\n" - " // -> order.Lt\n" - " ```\n" - "\n" - " Whether a duration is negative or positive doesn't matter for comparing\n" - " them, only the amount of time spanned matters.\n" - "\n" - " ```gleam\n" - " compare(seconds(-2), seconds(1))\n" - " // -> order.Gt\n" - " ```\n" -). --spec compare(duration(), duration()) -> gleam@order:order(). -compare(Left, Right) -> - Parts = fun(X) -> case erlang:element(2, X) >= 0 of - true -> - {erlang:element(2, X), erlang:element(3, X)}; - - false -> - {(erlang:element(2, X) * -1) - 1, - 1000000000 - erlang:element(3, X)} - end end, - {Ls, Lns} = Parts(Left), - {Rs, Rns} = Parts(Right), - _pipe = gleam@int:compare(Ls, Rs), - gleam@order:break_tie(_pipe, gleam@int:compare(Lns, Rns)). - --file("src/gleam/time/duration.gleam", 164). -?DOC( - " Calculate the difference between two durations.\n" - "\n" - " This is effectively substracting the first duration from the second.\n" - "\n" - " # Examples\n" - "\n" - " ```gleam\n" - " difference(seconds(1), seconds(5))\n" - " // -> seconds(4)\n" - " ```\n" -). --spec difference(duration(), duration()) -> duration(). -difference(Left, Right) -> - _pipe = {duration, - erlang:element(2, Right) - erlang:element(2, Left), - erlang:element(3, Right) - erlang:element(3, Left)}, - normalise(_pipe). - --file("src/gleam/time/duration.gleam", 178). -?DOC( - " Add two durations together.\n" - "\n" - " # Examples\n" - "\n" - " ```gleam\n" - " add(seconds(1), seconds(5))\n" - " // -> seconds(6)\n" - " ```\n" -). --spec add(duration(), duration()) -> duration(). -add(Left, Right) -> - _pipe = {duration, - erlang:element(2, Left) + erlang:element(2, Right), - erlang:element(3, Left) + erlang:element(3, Right)}, - normalise(_pipe). - --file("src/gleam/time/duration.gleam", 225). --spec nanosecond_digits(integer(), integer(), binary()) -> binary(). -nanosecond_digits(N, Position, Acc) -> - case Position of - 9 -> - Acc; - - _ when (Acc =:= <<""/utf8>>) andalso ((N rem 10) =:= 0) -> - nanosecond_digits(N div 10, Position + 1, Acc); - - _ -> - Acc@1 = <<(erlang:integer_to_binary(N rem 10))/binary, Acc/binary>>, - nanosecond_digits(N div 10, Position + 1, Acc@1) - end. - --file("src/gleam/time/duration.gleam", 239). -?DOC(" Create a duration of a number of seconds.\n"). --spec seconds(integer()) -> duration(). -seconds(Amount) -> - {duration, Amount, 0}. - --file("src/gleam/time/duration.gleam", 244). -?DOC(" Create a duration of a number of minutes.\n"). --spec minutes(integer()) -> duration(). -minutes(Amount) -> - seconds(Amount * 60). - --file("src/gleam/time/duration.gleam", 249). -?DOC(" Create a duration of a number of hours.\n"). --spec hours(integer()) -> duration(). -hours(Amount) -> - seconds((Amount * 60) * 60). - --file("src/gleam/time/duration.gleam", 254). -?DOC(" Create a duration of a number of milliseconds.\n"). --spec milliseconds(integer()) -> duration(). -milliseconds(Amount) -> - Remainder = Amount rem 1000, - Overflow = Amount - Remainder, - Nanoseconds = Remainder * 1000000, - Seconds = Overflow div 1000, - _pipe = {duration, Seconds, Nanoseconds}, - normalise(_pipe). - --file("src/gleam/time/duration.gleam", 273). -?DOC( - " Create a duration of a number of nanoseconds.\n" - "\n" - " # JavaScript int limitations\n" - "\n" - " Remember that JavaScript can only perfectly represent ints between positive\n" - " and negative 9,007,199,254,740,991! If you use a single call to this\n" - " function to create durations larger than that number of nanoseconds then\n" - " you will likely not get exactly the value you expect. Use `seconds` and\n" - " `milliseconds` as much as possible for large durations.\n" -). --spec nanoseconds(integer()) -> duration(). -nanoseconds(Amount) -> - _pipe = {duration, 0, Amount}, - normalise(_pipe). - --file("src/gleam/time/duration.gleam", 283). -?DOC( - " Convert the duration to a number of seconds.\n" - "\n" - " There may be some small loss of precision due to `Duration` being\n" - " nanosecond accurate and `Float` not being able to represent this.\n" -). --spec to_seconds(duration()) -> float(). -to_seconds(Duration) -> - Seconds = erlang:float(erlang:element(2, Duration)), - Nanoseconds = erlang:float(erlang:element(3, Duration)), - Seconds + (Nanoseconds / 1000000000.0). - --file("src/gleam/time/duration.gleam", 292). -?DOC( - " Convert the duration to a number of seconds and nanoseconds. There is no\n" - " loss of precision with this conversion on any target.\n" -). --spec to_seconds_and_nanoseconds(duration()) -> {integer(), integer()}. -to_seconds_and_nanoseconds(Duration) -> - {erlang:element(2, Duration), erlang:element(3, Duration)}. - --file("src/gleam/time/duration.gleam", 192). -?DOC( - " Convert the duration to an [ISO8601][1] formatted duration string.\n" - "\n" - " The ISO8601 duration format is ambiguous without context due to months and\n" - " years having different lengths, and because of leap seconds. This function\n" - " encodes the duration as days, hours, and seconds without any leap seconds.\n" - " Be sure to take this into account when using the duration strings.\n" - "\n" - " [1]: https://en.wikipedia.org/wiki/ISO_8601#Durations\n" -). --spec to_iso8601_string(duration()) -> binary(). -to_iso8601_string(Duration) -> - gleam@bool:guard( - Duration =:= {duration, 0, 0}, - <<"PT0S"/utf8>>, - fun() -> - Split = fun(Total, Limit) -> - Amount = case Limit of - 0 -> 0; - Gleam@denominator -> Total rem Gleam@denominator - end, - Remainder = case Limit of - 0 -> 0; - Gleam@denominator@1 -> (Total - Amount) div Gleam@denominator@1 - end, - {Amount, Remainder} - end, - {Seconds, Rest} = Split(erlang:element(2, Duration), 60), - {Minutes, Rest@1} = Split(Rest, 60), - {Hours, Rest@2} = Split(Rest@1, 24), - Days = Rest@2, - Add = fun(Out, Value, Unit) -> case Value of - 0 -> - Out; - - _ -> - <<<>/binary, - Unit/binary>> - end end, - Output = begin - _pipe = <<"P"/utf8>>, - _pipe@1 = Add(_pipe, Days, <<"D"/utf8>>), - _pipe@2 = gleam@string:append(_pipe@1, <<"T"/utf8>>), - _pipe@3 = Add(_pipe@2, Hours, <<"H"/utf8>>), - Add(_pipe@3, Minutes, <<"M"/utf8>>) - end, - case {Seconds, erlang:element(3, Duration)} of - {0, 0} -> - Output; - - {_, 0} -> - <<<>/binary, - "S"/utf8>>; - - {_, _} -> - F = nanosecond_digits( - erlang:element(3, Duration), - 0, - <<""/utf8>> - ), - <<<<<<<>/binary, - "."/utf8>>/binary, - F/binary>>/binary, - "S"/utf8>> - end - end - ). diff --git a/build/packages/gleam_time/src/gleam@time@timestamp.erl b/build/packages/gleam_time/src/gleam@time@timestamp.erl deleted file mode 100644 index 0d7413a..0000000 --- a/build/packages/gleam_time/src/gleam@time@timestamp.erl +++ /dev/null @@ -1,1188 +0,0 @@ --module(gleam@time@timestamp). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "src/gleam/time/timestamp.gleam"). --export([compare/2, system_time/0, difference/2, add/2, to_calendar/2, to_rfc3339/2, from_unix_seconds/1, from_unix_seconds_and_nanoseconds/2, to_unix_seconds/1, to_unix_seconds_and_nanoseconds/1, from_calendar/3, parse_rfc3339/1]). --export_type([timestamp/0]). - --if(?OTP_RELEASE >= 27). --define(MODULEDOC(Str), -moduledoc(Str)). --define(DOC(Str), -doc(Str)). --else. --define(MODULEDOC(Str), -compile([])). --define(DOC(Str), -compile([])). --endif. - -?MODULEDOC( - " Welcome to the timestamp module! This module and its `Timestamp` type are\n" - " what you will be using most commonly when working with time in Gleam.\n" - "\n" - " A timestamp represents a moment in time, represented as an amount of time\n" - " since the calendar time 00:00:00 UTC on 1 January 1970, also known as the\n" - " _Unix epoch_.\n" - "\n" - " # Wall clock time and monotonicity\n" - "\n" - " Time is very complicated, especially on computers! While they generally do\n" - " a good job of keeping track of what the time is, computers can get\n" - " out-of-sync and start to report a time that is too late or too early. Most\n" - " computers use \"network time protocol\" to tell each other what they think\n" - " the time is, and computers that realise they are running too fast or too\n" - " slow will adjust their clock to correct it. When this happens it can seem\n" - " to your program that the current time has changed, and it may have even\n" - " jumped backwards in time!\n" - "\n" - " This measure of time is called _wall clock time_, and it is what people\n" - " commonly think of when they think of time. It is important to be aware that\n" - " it can go backwards, and your program must not rely on it only ever going\n" - " forwards at a steady rate. For example, for tracking what order events happen\n" - " in. \n" - "\n" - " This module uses wall clock time. If your program needs time values to always\n" - " increase you will need a _monotonic_ time instead. It's uncommon that you\n" - " would need monotonic time, one example might be if you're making a\n" - " benchmarking framework.\n" - "\n" - " The exact way that time works will depend on what runtime you use. The\n" - " Erlang documentation on time has a lot of detail about time generally as well\n" - " as how it works on the BEAM, it is worth reading.\n" - " .\n" - "\n" - " # Converting to local calendar time\n" - "\n" - " Timestamps don't take into account time zones, so a moment in time will\n" - " have the same timestamp value regardless of where you are in the world. To\n" - " convert them to local time you will need to know the offset for the time\n" - " zone you wish to use, likely from a time zone database. See the\n" - " `gleam/time/calendar` module for more information.\n" - "\n" -). - --opaque timestamp() :: {timestamp, integer(), integer()}. - --file("src/gleam/time/timestamp.gleam", 119). -?DOC( - " Ensure the time is represented with `nanoseconds` being positive and less\n" - " than 1 second.\n" - "\n" - " This function does not change the time that the timestamp refers to, it\n" - " only adjusts the values used to represent the time.\n" -). --spec normalise(timestamp()) -> timestamp(). -normalise(Timestamp) -> - Multiplier = 1000000000, - Nanoseconds = case Multiplier of - 0 -> 0; - Gleam@denominator -> erlang:element(3, Timestamp) rem Gleam@denominator - end, - Overflow = erlang:element(3, Timestamp) - Nanoseconds, - Seconds = erlang:element(2, Timestamp) + (case Multiplier of - 0 -> 0; - Gleam@denominator@1 -> Overflow div Gleam@denominator@1 - end), - case Nanoseconds >= 0 of - true -> - {timestamp, Seconds, Nanoseconds}; - - false -> - {timestamp, Seconds - 1, Multiplier + Nanoseconds} - end. - --file("src/gleam/time/timestamp.gleam", 141). -?DOC( - " Compare one timestamp to another, indicating whether the first is further\n" - " into the future (greater) or further into the past (lesser) than the\n" - " second.\n" - "\n" - " # Examples\n" - "\n" - " ```gleam\n" - " compare(from_unix_seconds(1), from_unix_seconds(2))\n" - " // -> order.Lt\n" - " ```\n" -). --spec compare(timestamp(), timestamp()) -> gleam@order:order(). -compare(Left, Right) -> - gleam@order:break_tie( - gleam@int:compare(erlang:element(2, Left), erlang:element(2, Right)), - gleam@int:compare(erlang:element(3, Left), erlang:element(3, Right)) - ). - --file("src/gleam/time/timestamp.gleam", 160). -?DOC( - " Get the current system time.\n" - "\n" - " Note this time is not unique or monotonic, it could change at any time or\n" - " even go backwards! The exact behaviour will depend on the runtime used. See\n" - " the module documentation for more information.\n" - "\n" - " On Erlang this uses [`erlang:system_time/1`][1]. On JavaScript this uses\n" - " [`Date.now`][2].\n" - "\n" - " [1]: https://www.erlang.org/doc/apps/erts/erlang#system_time/1\n" - " [2]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/now\n" -). --spec system_time() -> timestamp(). -system_time() -> - {Seconds, Nanoseconds} = gleam_time_ffi:system_time(), - normalise({timestamp, Seconds, Nanoseconds}). - --file("src/gleam/time/timestamp.gleam", 180). -?DOC( - " Calculate the difference between two timestamps.\n" - "\n" - " This is effectively substracting the first timestamp from the second.\n" - "\n" - " # Examples\n" - "\n" - " ```gleam\n" - " difference(from_unix_seconds(1), from_unix_seconds(5))\n" - " // -> duration.seconds(4)\n" - " ```\n" -). --spec difference(timestamp(), timestamp()) -> gleam@time@duration:duration(). -difference(Left, Right) -> - Seconds = gleam@time@duration:seconds( - erlang:element(2, Right) - erlang:element(2, Left) - ), - Nanoseconds = gleam@time@duration:nanoseconds( - erlang:element(3, Right) - erlang:element(3, Left) - ), - gleam@time@duration:add(Seconds, Nanoseconds). - --file("src/gleam/time/timestamp.gleam", 195). -?DOC( - " Add a duration to a timestamp.\n" - "\n" - " # Examples\n" - "\n" - " ```gleam\n" - " add(from_unix_seconds(1000), duration.seconds(5))\n" - " // -> from_unix_seconds(1005)\n" - " ```\n" -). --spec add(timestamp(), gleam@time@duration:duration()) -> timestamp(). -add(Timestamp, Duration) -> - {Seconds, Nanoseconds} = gleam@time@duration:to_seconds_and_nanoseconds( - Duration - ), - _pipe = {timestamp, - erlang:element(2, Timestamp) + Seconds, - erlang:element(3, Timestamp) + Nanoseconds}, - normalise(_pipe). - --file("src/gleam/time/timestamp.gleam", 262). --spec pad_digit(integer(), integer()) -> binary(). -pad_digit(Digit, Desired_length) -> - _pipe = erlang:integer_to_binary(Digit), - gleam@string:pad_start(_pipe, Desired_length, <<"0"/utf8>>). - --file("src/gleam/time/timestamp.gleam", 308). --spec duration_to_minutes(gleam@time@duration:duration()) -> integer(). -duration_to_minutes(Duration) -> - erlang:round(gleam@time@duration:to_seconds(Duration) / 60.0). - --file("src/gleam/time/timestamp.gleam", 370). --spec modulo(integer(), integer()) -> integer(). -modulo(N, M) -> - case gleam@int:modulo(N, M) of - {ok, N@1} -> - N@1; - - {error, _} -> - 0 - end. - --file("src/gleam/time/timestamp.gleam", 377). --spec floored_div(integer(), float()) -> integer(). -floored_div(Numerator, Denominator) -> - N = case Denominator of - +0.0 -> +0.0; - -0.0 -> -0.0; - Gleam@denominator -> erlang:float(Numerator) / Gleam@denominator - end, - erlang:round(math:floor(N)). - --file("src/gleam/time/timestamp.gleam", 383). --spec to_civil(integer()) -> {integer(), integer(), integer()}. -to_civil(Minutes) -> - Raw_day = floored_div(Minutes, (60.0 * 24.0)) + 719468, - Era = case Raw_day >= 0 of - true -> - Raw_day div 146097; - - false -> - (Raw_day - 146096) div 146097 - end, - Day_of_era = Raw_day - (Era * 146097), - Year_of_era = (((Day_of_era - (Day_of_era div 1460)) + (Day_of_era div 36524)) - - (Day_of_era div 146096)) - div 365, - Year = Year_of_era + (Era * 400), - Day_of_year = Day_of_era - (((365 * Year_of_era) + (Year_of_era div 4)) - (Year_of_era - div 100)), - Mp = ((5 * Day_of_year) + 2) div 153, - Month = case Mp < 10 of - true -> - Mp + 3; - - false -> - Mp - 9 - end, - Day = (Day_of_year - (((153 * Mp) + 2) div 5)) + 1, - Year@1 = case Month =< 2 of - true -> - Year + 1; - - false -> - Year - end, - {Year@1, Month, Day}. - --file("src/gleam/time/timestamp.gleam", 312). --spec to_calendar_from_offset(timestamp(), integer()) -> {integer(), - integer(), - integer(), - integer(), - integer(), - integer()}. -to_calendar_from_offset(Timestamp, Offset) -> - Total = erlang:element(2, Timestamp) + (Offset * 60), - Seconds = modulo(Total, 60), - Total_minutes = floored_div(Total, 60.0), - Minutes = modulo(Total, 60 * 60) div 60, - Hours = case (60 * 60) of - 0 -> 0; - Gleam@denominator -> modulo(Total, (24 * 60) * 60) div Gleam@denominator - end, - {Year, Month, Day} = to_civil(Total_minutes), - {Year, Month, Day, Hours, Minutes, Seconds}. - --file("src/gleam/time/timestamp.gleam", 281). -?DOC( - " Convert a `Timestamp` to calendar time, suitable for presenting to a human\n" - " to read.\n" - "\n" - " If you want a machine to use the time value then you should not use this\n" - " function and should instead keep it as a timestamp. See the documentation\n" - " for the `gleam/time/calendar` module for more information.\n" - "\n" - " # Examples\n" - "\n" - " ```gleam\n" - " timestamp.from_unix_seconds(0)\n" - " |> timestamp.to_calendar(calendar.utc_offset)\n" - " // -> #(Date(1970, January, 1), TimeOfDay(0, 0, 0, 0))\n" - " ```\n" -). --spec to_calendar(timestamp(), gleam@time@duration:duration()) -> {gleam@time@calendar:date(), - gleam@time@calendar:time_of_day()}. -to_calendar(Timestamp, Offset) -> - Offset@1 = duration_to_minutes(Offset), - {Year, Month, Day, Hours, Minutes, Seconds} = to_calendar_from_offset( - Timestamp, - Offset@1 - ), - Month@1 = case Month of - 1 -> - january; - - 2 -> - february; - - 3 -> - march; - - 4 -> - april; - - 5 -> - may; - - 6 -> - june; - - 7 -> - july; - - 8 -> - august; - - 9 -> - september; - - 10 -> - october; - - 11 -> - november; - - _ -> - december - end, - Nanoseconds = erlang:element(3, Timestamp), - Date = {date, Year, Month@1, Day}, - Time = {time_of_day, Hours, Minutes, Seconds, Nanoseconds}, - {Date, Time}. - --file("src/gleam/time/timestamp.gleam", 446). --spec do_remove_trailing_zeros(list(integer())) -> list(integer()). -do_remove_trailing_zeros(Reversed_digits) -> - case Reversed_digits of - [] -> - []; - - [Digit | Digits] when Digit =:= 0 -> - do_remove_trailing_zeros(Digits); - - Reversed_digits@1 -> - lists:reverse(Reversed_digits@1) - end. - --file("src/gleam/time/timestamp.gleam", 440). -?DOC(" Given a list of digits, return new list with any trailing zeros removed.\n"). --spec remove_trailing_zeros(list(integer())) -> list(integer()). -remove_trailing_zeros(Digits) -> - Reversed_digits = lists:reverse(Digits), - do_remove_trailing_zeros(Reversed_digits). - --file("src/gleam/time/timestamp.gleam", 461). --spec do_get_zero_padded_digits(integer(), list(integer()), integer()) -> list(integer()). -do_get_zero_padded_digits(Number, Digits, Count) -> - case Number of - Number@1 when (Number@1 =< 0) andalso (Count >= 9) -> - Digits; - - Number@2 when Number@2 =< 0 -> - do_get_zero_padded_digits(Number@2, [0 | Digits], Count + 1); - - Number@3 -> - Digit = Number@3 rem 10, - Number@4 = floored_div(Number@3, 10.0), - do_get_zero_padded_digits(Number@4, [Digit | Digits], Count + 1) - end. - --file("src/gleam/time/timestamp.gleam", 457). -?DOC( - " Returns the list of digits of `number`. If the number of digits is less \n" - " than 9, the result is zero-padded at the front.\n" -). --spec get_zero_padded_digits(integer()) -> list(integer()). -get_zero_padded_digits(Number) -> - do_get_zero_padded_digits(Number, [], 0). - --file("src/gleam/time/timestamp.gleam", 420). -?DOC( - " Converts nanoseconds into a `String` representation of fractional seconds.\n" - " \n" - " Assumes that `nanoseconds < 1_000_000_000`, which will be true for any \n" - " normalised timestamp.\n" -). --spec show_second_fraction(integer()) -> binary(). -show_second_fraction(Nanoseconds) -> - case gleam@int:compare(Nanoseconds, 0) of - lt -> - <<""/utf8>>; - - eq -> - <<""/utf8>>; - - gt -> - Second_fraction_part = begin - _pipe = Nanoseconds, - _pipe@1 = get_zero_padded_digits(_pipe), - _pipe@2 = remove_trailing_zeros(_pipe@1), - _pipe@3 = gleam@list:map( - _pipe@2, - fun erlang:integer_to_binary/1 - ), - gleam@string:join(_pipe@3, <<""/utf8>>) - end, - <<"."/utf8, Second_fraction_part/binary>> - end. - --file("src/gleam/time/timestamp.gleam", 240). -?DOC( - " Convert a timestamp to a RFC 3339 formatted time string, with an offset\n" - " supplied as an additional argument.\n" - "\n" - " The output of this function is also ISO 8601 compatible so long as the\n" - " offset not negative. Offsets have at-most minute precision, so an offset\n" - " with higher precision will be rounded to the nearest minute.\n" - "\n" - " If you are making an API such as a HTTP JSON API you are encouraged to use\n" - " Unix timestamps instead of this format or ISO 8601. Unix timestamps are a\n" - " better choice as they don't contain offset information. Consider:\n" - "\n" - " - UTC offsets are not time zones. This does not and cannot tell us the time\n" - " zone in which the date was recorded. So what are we supposed to do with\n" - " this information?\n" - " - Users typically want dates formatted according to their local time zone.\n" - " What if the provided UTC offset is different from the current user's time\n" - " zone? What are we supposed to do with it then?\n" - " - Despite it being useless (or worse, a source of bugs), the UTC offset\n" - " creates a larger payload to transfer.\n" - "\n" - " They also uses more memory than a unix timestamp. The way they are better\n" - " than Unix timestamp is that it is easier for a human to read them, but\n" - " this is a hinderance that tooling can remedy, and APIs are not primarily\n" - " for humans.\n" - "\n" - " # Examples\n" - "\n" - " ```gleam\n" - " timestamp.from_unix_seconds_and_nanoseconds(1000, 123_000_000)\n" - " |> to_rfc3339(calendar.utc_offset)\n" - " // -> \"1970-01-01T00:16:40.123Z\"\n" - " ```\n" - "\n" - " ```gleam\n" - " timestamp.from_unix_seconds(1000)\n" - " |> to_rfc3339(duration.seconds(3600))\n" - " // -> \"1970-01-01T01:16:40+01:00\"\n" - " ```\n" -). --spec to_rfc3339(timestamp(), gleam@time@duration:duration()) -> binary(). -to_rfc3339(Timestamp, Offset) -> - Offset@1 = duration_to_minutes(Offset), - {Years, Months, Days, Hours, Minutes, Seconds} = to_calendar_from_offset( - Timestamp, - Offset@1 - ), - Offset_minutes = modulo(Offset@1, 60), - Offset_hours = gleam@int:absolute_value(floored_div(Offset@1, 60.0)), - N2 = fun(_capture) -> pad_digit(_capture, 2) end, - N4 = fun(_capture@1) -> pad_digit(_capture@1, 4) end, - Out = <<""/utf8>>, - Out@1 = <<<<<<<<<>/binary, "-"/utf8>>/binary, - (N2(Months))/binary>>/binary, - "-"/utf8>>/binary, - (N2(Days))/binary>>, - Out@2 = <>, - Out@3 = <<<<<<<<<>/binary, ":"/utf8>>/binary, - (N2(Minutes))/binary>>/binary, - ":"/utf8>>/binary, - (N2(Seconds))/binary>>, - Out@4 = <>, - case gleam@int:compare(Offset@1, 0) of - eq -> - <>; - - gt -> - <<<<<<<>/binary, (N2(Offset_hours))/binary>>/binary, - ":"/utf8>>/binary, - (N2(Offset_minutes))/binary>>; - - lt -> - <<<<<<<>/binary, (N2(Offset_hours))/binary>>/binary, - ":"/utf8>>/binary, - (N2(Offset_minutes))/binary>> - end. - --file("src/gleam/time/timestamp.gleam", 611). --spec is_leap_year(integer()) -> boolean(). -is_leap_year(Year) -> - ((Year rem 4) =:= 0) andalso (((Year rem 100) /= 0) orelse ((Year rem 400) - =:= 0)). - --file("src/gleam/time/timestamp.gleam", 715). --spec parse_sign(bitstring()) -> {ok, {binary(), bitstring()}} | {error, nil}. -parse_sign(Bytes) -> - case Bytes of - <<"+"/utf8, Remaining_bytes/binary>> -> - {ok, {<<"+"/utf8>>, Remaining_bytes}}; - - <<"-"/utf8, Remaining_bytes@1/binary>> -> - {ok, {<<"-"/utf8>>, Remaining_bytes@1}}; - - _ -> - {error, nil} - end. - --file("src/gleam/time/timestamp.gleam", 762). -?DOC(" Accept the given value from `bytes` and move past it if found.\n"). --spec accept_byte(bitstring(), integer()) -> {ok, bitstring()} | {error, nil}. -accept_byte(Bytes, Value) -> - case Bytes of - <> when Byte =:= Value -> - {ok, Remaining_bytes}; - - _ -> - {error, nil} - end. - --file("src/gleam/time/timestamp.gleam", 780). --spec accept_empty(bitstring()) -> {ok, nil} | {error, nil}. -accept_empty(Bytes) -> - case Bytes of - <<>> -> - {ok, nil}; - - _ -> - {error, nil} - end. - --file("src/gleam/time/timestamp.gleam", 840). -?DOC( - " Note: It is the callers responsibility to ensure the inputs are valid.\n" - " \n" - " See https://www.tondering.dk/claus/cal/julperiod.php#formula\n" -). --spec julian_day_from_ymd(integer(), integer(), integer()) -> integer(). -julian_day_from_ymd(Year, Month, Day) -> - Adjustment = (14 - Month) div 12, - Adjusted_year = (Year + 4800) - Adjustment, - Adjusted_month = (Month + (12 * Adjustment)) - 3, - (((((Day + (((153 * Adjusted_month) + 2) div 5)) + (365 * Adjusted_year)) + (Adjusted_year - div 4)) - - (Adjusted_year div 100)) - + (Adjusted_year div 400)) - - 32045. - --file("src/gleam/time/timestamp.gleam", 859). -?DOC( - " Create a timestamp from a number of seconds since 00:00:00 UTC on 1 January\n" - " 1970.\n" -). --spec from_unix_seconds(integer()) -> timestamp(). -from_unix_seconds(Seconds) -> - {timestamp, Seconds, 0}. - --file("src/gleam/time/timestamp.gleam", 874). -?DOC( - " Create a timestamp from a number of seconds and nanoseconds since 00:00:00\n" - " UTC on 1 January 1970.\n" - "\n" - " # JavaScript int limitations\n" - "\n" - " Remember that JavaScript can only perfectly represent ints between positive\n" - " and negative 9,007,199,254,740,991! If you only use the nanosecond field\n" - " then you will almost certainly not get the date value you want due to this\n" - " loss of precision. Always use seconds primarily and then use nanoseconds\n" - " for the final sub-second adjustment.\n" -). --spec from_unix_seconds_and_nanoseconds(integer(), integer()) -> timestamp(). -from_unix_seconds_and_nanoseconds(Seconds, Nanoseconds) -> - _pipe = {timestamp, Seconds, Nanoseconds}, - normalise(_pipe). - --file("src/gleam/time/timestamp.gleam", 888). -?DOC( - " Convert the timestamp to a number of seconds since 00:00:00 UTC on 1\n" - " January 1970.\n" - "\n" - " There may be some small loss of precision due to `Timestamp` being\n" - " nanosecond accurate and `Float` not being able to represent this.\n" -). --spec to_unix_seconds(timestamp()) -> float(). -to_unix_seconds(Timestamp) -> - Seconds = erlang:float(erlang:element(2, Timestamp)), - Nanoseconds = erlang:float(erlang:element(3, Timestamp)), - Seconds + (Nanoseconds / 1000000000.0). - --file("src/gleam/time/timestamp.gleam", 897). -?DOC( - " Convert the timestamp to a number of seconds and nanoseconds since 00:00:00\n" - " UTC on 1 January 1970. There is no loss of precision with this conversion\n" - " on any target.\n" -). --spec to_unix_seconds_and_nanoseconds(timestamp()) -> {integer(), integer()}. -to_unix_seconds_and_nanoseconds(Timestamp) -> - {erlang:element(2, Timestamp), erlang:element(3, Timestamp)}. - --file("src/gleam/time/timestamp.gleam", 723). --spec offset_to_seconds(binary(), integer(), integer()) -> integer(). -offset_to_seconds(Sign, Hours, Minutes) -> - Abs_seconds = (Hours * 3600) + (Minutes * 60), - case Sign of - <<"-"/utf8>> -> - - Abs_seconds; - - _ -> - Abs_seconds - end. - --file("src/gleam/time/timestamp.gleam", 819). -?DOC( - " `julian_seconds_from_parts(year, month, day, hours, minutes, seconds)` \n" - " returns the number of Julian \n" - " seconds represented by the given arguments.\n" - " \n" - " Note: It is the callers responsibility to ensure the inputs are valid.\n" - " \n" - " See https://www.tondering.dk/claus/cal/julperiod.php#formula\n" -). --spec julian_seconds_from_parts( - integer(), - integer(), - integer(), - integer(), - integer(), - integer() -) -> integer(). -julian_seconds_from_parts(Year, Month, Day, Hours, Minutes, Seconds) -> - Julian_day_seconds = julian_day_from_ymd(Year, Month, Day) * 86400, - ((Julian_day_seconds + (Hours * 3600)) + (Minutes * 60)) + Seconds. - --file("src/gleam/time/timestamp.gleam", 662). --spec do_parse_second_fraction_as_nanoseconds(bitstring(), integer(), integer()) -> {ok, - {integer(), bitstring()}} | - {error, any()}. -do_parse_second_fraction_as_nanoseconds(Bytes, Acc, Power) -> - Power@1 = Power div 10, - case Bytes of - <> when ((16#30 =< Byte) andalso (Byte =< 16#39)) andalso (Power@1 < 1) -> - do_parse_second_fraction_as_nanoseconds( - Remaining_bytes, - Acc, - Power@1 - ); - - <> when (16#30 =< Byte@1) andalso (Byte@1 =< 16#39) -> - Digit = Byte@1 - 16#30, - do_parse_second_fraction_as_nanoseconds( - Remaining_bytes@1, - Acc + (Digit * Power@1), - Power@1 - ); - - _ -> - {ok, {Acc, Bytes}} - end. - --file("src/gleam/time/timestamp.gleam", 642). --spec parse_second_fraction_as_nanoseconds(bitstring()) -> {ok, - {integer(), bitstring()}} | - {error, nil}. -parse_second_fraction_as_nanoseconds(Bytes) -> - case Bytes of - <<"."/utf8, Byte, Remaining_bytes/binary>> when (16#30 =< Byte) andalso (Byte =< 16#39) -> - do_parse_second_fraction_as_nanoseconds( - <>, - 0, - 1000000000 - ); - - <<"."/utf8, _/binary>> -> - {error, nil}; - - _ -> - {ok, {0, Bytes}} - end. - --file("src/gleam/time/timestamp.gleam", 741). --spec do_parse_digits(bitstring(), integer(), integer(), integer()) -> {ok, - {integer(), bitstring()}} | - {error, nil}. -do_parse_digits(Bytes, Count, Acc, K) -> - case Bytes of - _ when K >= Count -> - {ok, {Acc, Bytes}}; - - <> when (16#30 =< Byte) andalso (Byte =< 16#39) -> - do_parse_digits( - Remaining_bytes, - Count, - (Acc * 10) + (Byte - 16#30), - K + 1 - ); - - _ -> - {error, nil} - end. - --file("src/gleam/time/timestamp.gleam", 734). -?DOC(" Parse and return the given number of digits from the given bytes.\n"). --spec parse_digits(bitstring(), integer()) -> {ok, {integer(), bitstring()}} | - {error, nil}. -parse_digits(Bytes, Count) -> - do_parse_digits(Bytes, Count, 0, 0). - --file("src/gleam/time/timestamp.gleam", 573). --spec parse_year(bitstring()) -> {ok, {integer(), bitstring()}} | {error, nil}. -parse_year(Bytes) -> - parse_digits(Bytes, 4). - --file("src/gleam/time/timestamp.gleam", 577). --spec parse_month(bitstring()) -> {ok, {integer(), bitstring()}} | {error, nil}. -parse_month(Bytes) -> - gleam@result:'try'( - parse_digits(Bytes, 2), - fun(_use0) -> - {Month, Bytes@1} = _use0, - case (1 =< Month) andalso (Month =< 12) of - true -> - {ok, {Month, Bytes@1}}; - - false -> - {error, nil} - end - end - ). - --file("src/gleam/time/timestamp.gleam", 585). --spec parse_day(bitstring(), integer(), integer()) -> {ok, - {integer(), bitstring()}} | - {error, nil}. -parse_day(Bytes, Year, Month) -> - gleam@result:'try'( - parse_digits(Bytes, 2), - fun(_use0) -> - {Day, Bytes@1} = _use0, - gleam@result:'try'(case Month of - 1 -> - {ok, 31}; - - 3 -> - {ok, 31}; - - 5 -> - {ok, 31}; - - 7 -> - {ok, 31}; - - 8 -> - {ok, 31}; - - 10 -> - {ok, 31}; - - 12 -> - {ok, 31}; - - 4 -> - {ok, 30}; - - 6 -> - {ok, 30}; - - 9 -> - {ok, 30}; - - 11 -> - {ok, 30}; - - 2 -> - case is_leap_year(Year) of - true -> - {ok, 29}; - - false -> - {ok, 28} - end; - - _ -> - {error, nil} - end, fun(Max_day) -> case (1 =< Day) andalso (Day =< Max_day) of - true -> - {ok, {Day, Bytes@1}}; - - false -> - {error, nil} - end end) - end - ). - --file("src/gleam/time/timestamp.gleam", 615). --spec parse_hours(bitstring()) -> {ok, {integer(), bitstring()}} | {error, nil}. -parse_hours(Bytes) -> - gleam@result:'try'( - parse_digits(Bytes, 2), - fun(_use0) -> - {Hours, Bytes@1} = _use0, - case (0 =< Hours) andalso (Hours =< 23) of - true -> - {ok, {Hours, Bytes@1}}; - - false -> - {error, nil} - end - end - ). - --file("src/gleam/time/timestamp.gleam", 623). --spec parse_minutes(bitstring()) -> {ok, {integer(), bitstring()}} | - {error, nil}. -parse_minutes(Bytes) -> - gleam@result:'try'( - parse_digits(Bytes, 2), - fun(_use0) -> - {Minutes, Bytes@1} = _use0, - case (0 =< Minutes) andalso (Minutes =< 59) of - true -> - {ok, {Minutes, Bytes@1}}; - - false -> - {error, nil} - end - end - ). - --file("src/gleam/time/timestamp.gleam", 631). --spec parse_seconds(bitstring()) -> {ok, {integer(), bitstring()}} | - {error, nil}. -parse_seconds(Bytes) -> - gleam@result:'try'( - parse_digits(Bytes, 2), - fun(_use0) -> - {Seconds, Bytes@1} = _use0, - case (0 =< Seconds) andalso (Seconds =< 60) of - true -> - {ok, {Seconds, Bytes@1}}; - - false -> - {error, nil} - end - end - ). - --file("src/gleam/time/timestamp.gleam", 704). --spec parse_numeric_offset(bitstring()) -> {ok, {integer(), bitstring()}} | - {error, nil}. -parse_numeric_offset(Bytes) -> - gleam@result:'try'( - parse_sign(Bytes), - fun(_use0) -> - {Sign, Bytes@1} = _use0, - gleam@result:'try'( - parse_hours(Bytes@1), - fun(_use0@1) -> - {Hours, Bytes@2} = _use0@1, - gleam@result:'try'( - accept_byte(Bytes@2, 16#3A), - fun(Bytes@3) -> - gleam@result:'try'( - parse_minutes(Bytes@3), - fun(_use0@2) -> - {Minutes, Bytes@4} = _use0@2, - Offset_seconds = offset_to_seconds( - Sign, - Hours, - Minutes - ), - {ok, {Offset_seconds, Bytes@4}} - end - ) - end - ) - end - ) - end - ). - --file("src/gleam/time/timestamp.gleam", 696). --spec parse_offset(bitstring()) -> {ok, {integer(), bitstring()}} | {error, nil}. -parse_offset(Bytes) -> - case Bytes of - <<"Z"/utf8, Remaining_bytes/binary>> -> - {ok, {0, Remaining_bytes}}; - - <<"z"/utf8, Remaining_bytes/binary>> -> - {ok, {0, Remaining_bytes}}; - - _ -> - parse_numeric_offset(Bytes) - end. - --file("src/gleam/time/timestamp.gleam", 769). --spec accept_date_time_separator(bitstring()) -> {ok, bitstring()} | - {error, nil}. -accept_date_time_separator(Bytes) -> - case Bytes of - <> when ((Byte =:= 16#54) orelse (Byte =:= 16#74)) orelse (Byte =:= 16#20) -> - {ok, Remaining_bytes}; - - _ -> - {error, nil} - end. - --file("src/gleam/time/timestamp.gleam", 789). -?DOC(" Note: The caller of this function must ensure that all inputs are valid.\n"). --spec from_date_time( - integer(), - integer(), - integer(), - integer(), - integer(), - integer(), - integer(), - integer() -) -> timestamp(). -from_date_time( - Year, - Month, - Day, - Hours, - Minutes, - Seconds, - Second_fraction_as_nanoseconds, - Offset_seconds -) -> - Julian_seconds = julian_seconds_from_parts( - Year, - Month, - Day, - Hours, - Minutes, - Seconds - ), - Julian_seconds_since_epoch = Julian_seconds - 210866803200, - _pipe = {timestamp, - Julian_seconds_since_epoch - Offset_seconds, - Second_fraction_as_nanoseconds}, - normalise(_pipe). - --file("src/gleam/time/timestamp.gleam", 339). -?DOC( - " Create a `Timestamp` from a human-readable calendar time.\n" - "\n" - " # Examples\n" - "\n" - " ```gleam\n" - " timestamp.from_calendar(\n" - " date: calendar.Date(2024, calendar.December, 25),\n" - " time: calendar.TimeOfDay(12, 30, 50, 0),\n" - " offset: calendar.utc_offset,\n" - " )\n" - " |> timestamp.to_rfc3339(calendar.utc_offset)\n" - " // -> \"2024-12-25T12:30:50Z\"\n" - " ```\n" -). --spec from_calendar( - gleam@time@calendar:date(), - gleam@time@calendar:time_of_day(), - gleam@time@duration:duration() -) -> timestamp(). -from_calendar(Date, Time, Offset) -> - Month = case erlang:element(3, Date) of - january -> - 1; - - february -> - 2; - - march -> - 3; - - april -> - 4; - - may -> - 5; - - june -> - 6; - - july -> - 7; - - august -> - 8; - - september -> - 9; - - october -> - 10; - - november -> - 11; - - december -> - 12 - end, - from_date_time( - erlang:element(2, Date), - Month, - erlang:element(4, Date), - erlang:element(2, Time), - erlang:element(3, Time), - erlang:element(4, Time), - erlang:element(5, Time), - erlang:round(gleam@time@duration:to_seconds(Offset)) - ). - --file("src/gleam/time/timestamp.gleam", 533). -?DOC( - " Parses an [RFC 3339 formatted time string][spec] into a `Timestamp`.\n" - "\n" - " [spec]: https://datatracker.ietf.org/doc/html/rfc3339#section-5.6\n" - " \n" - " # Examples\n" - "\n" - " ```gleam\n" - " let assert Ok(ts) = timestamp.parse_rfc3339(\"1970-01-01T00:00:01Z\")\n" - " timestamp.to_unix_seconds_and_nanoseconds(ts)\n" - " // -> #(1, 0)\n" - " ```\n" - " \n" - " Parsing an invalid timestamp returns an error.\n" - " \n" - " ```gleam\n" - " let assert Error(Nil) = timestamp.parse_rfc3339(\"1995-10-31\")\n" - " ```\n" - "\n" - " ## Time zones\n" - "\n" - " It may at first seem that the RFC 3339 format includes timezone\n" - " information, as it can specify an offset such as `Z` or `+3`, so why does\n" - " this function not return calendar time with a time zone? There are multiple\n" - " reasons:\n" - "\n" - " - RFC 3339's timestamp format is based on calendar time, but it is\n" - " unambigous, so it can be converted into epoch time when being parsed. It\n" - " is always better to internally use epoch time to represent unambiguous\n" - " points in time, so we perform that conversion as a convenience and to\n" - " ensure that programmers with less time experience don't accidentally use\n" - " a less suitable time representation.\n" - "\n" - " - RFC 3339's contains _calendar time offset_ information, not time zone\n" - " information. This is enough to convert it to an unambiguous timestamp,\n" - " but it is not enough information to reliably work with calendar time.\n" - " Without the time zone and the time zone database it's not possible to\n" - " know what time period that offset is valid for, so it cannot be used\n" - " without risk of bugs.\n" - "\n" - " ## Behaviour details\n" - " \n" - " - Follows the grammar specified in section 5.6 Internet Date/Time Format of \n" - " RFC 3339 .\n" - " - The `T` and `Z` characters may alternatively be lower case `t` or `z`, \n" - " respectively.\n" - " - Full dates and full times must be separated by `T` or `t`. A space is also \n" - " permitted.\n" - " - Leap seconds rules are not considered. That is, any timestamp may \n" - " specify digts `00` - `60` for the seconds.\n" - " - Any part of a fractional second that cannot be represented in the \n" - " nanosecond precision is tructated. That is, for the time string, \n" - " `\"1970-01-01T00:00:00.1234567899Z\"`, the fractional second `.1234567899` \n" - " will be represented as `123_456_789` in the `Timestamp`.\n" -). --spec parse_rfc3339(binary()) -> {ok, timestamp()} | {error, nil}. -parse_rfc3339(Input) -> - Bytes = gleam_stdlib:identity(Input), - gleam@result:'try'( - parse_year(Bytes), - fun(_use0) -> - {Year, Bytes@1} = _use0, - gleam@result:'try'( - accept_byte(Bytes@1, 16#2D), - fun(Bytes@2) -> - gleam@result:'try'( - parse_month(Bytes@2), - fun(_use0@1) -> - {Month, Bytes@3} = _use0@1, - gleam@result:'try'( - accept_byte(Bytes@3, 16#2D), - fun(Bytes@4) -> - gleam@result:'try'( - parse_day(Bytes@4, Year, Month), - fun(_use0@2) -> - {Day, Bytes@5} = _use0@2, - gleam@result:'try'( - accept_date_time_separator( - Bytes@5 - ), - fun(Bytes@6) -> - gleam@result:'try'( - parse_hours(Bytes@6), - fun(_use0@3) -> - {Hours, Bytes@7} = _use0@3, - gleam@result:'try'( - accept_byte( - Bytes@7, - 16#3A - ), - fun(Bytes@8) -> - gleam@result:'try'( - parse_minutes( - Bytes@8 - ), - fun( - _use0@4 - ) -> - {Minutes, - Bytes@9} = _use0@4, - gleam@result:'try'( - accept_byte( - Bytes@9, - 16#3A - ), - fun( - Bytes@10 - ) -> - gleam@result:'try'( - parse_seconds( - Bytes@10 - ), - fun( - _use0@5 - ) -> - {Seconds, - Bytes@11} = _use0@5, - gleam@result:'try'( - parse_second_fraction_as_nanoseconds( - Bytes@11 - ), - fun( - _use0@6 - ) -> - {Second_fraction_as_nanoseconds, - Bytes@12} = _use0@6, - gleam@result:'try'( - parse_offset( - Bytes@12 - ), - fun( - _use0@7 - ) -> - {Offset_seconds, - Bytes@13} = _use0@7, - gleam@result:'try'( - accept_empty( - Bytes@13 - ), - fun( - _use0@8 - ) -> - nil = _use0@8, - {ok, - from_date_time( - Year, - Month, - Day, - Hours, - Minutes, - Seconds, - Second_fraction_as_nanoseconds, - Offset_seconds - )} - end - ) - end - ) - end - ) - end - ) - end - ) - end - ) - end - ) - end - ) - end - ) - end - ) - end - ) - end - ) - end - ) - end - ). diff --git a/build/packages/gleam_time/src/gleam_time.app.src b/build/packages/gleam_time/src/gleam_time.app.src deleted file mode 100644 index 1e7cce4..0000000 --- a/build/packages/gleam_time/src/gleam_time.app.src +++ /dev/null @@ -1,12 +0,0 @@ -{application, gleam_time, [ - {vsn, "1.6.0"}, - {applications, [gleam_stdlib]}, - {description, "Work with time in Gleam!"}, - {modules, [gleam@time@calendar, - gleam@time@duration, - gleam@time@timestamp, - gleam_time@@main, - gleam_time_ffi, - gleam_time_test_ffi]}, - {registered, []} -]}. diff --git a/build/packages/gleam_time/src/gleam_time_ffi.erl b/build/packages/gleam_time/src/gleam_time_ffi.erl deleted file mode 100644 index 34d8c88..0000000 --- a/build/packages/gleam_time/src/gleam_time_ffi.erl +++ /dev/null @@ -1,12 +0,0 @@ --module(gleam_time_ffi). --export([system_time/0, local_time_offset_seconds/0]). - -system_time() -> - {0, erlang:system_time(nanosecond)}. - -local_time_offset_seconds() -> - Utc = calendar:universal_time(), - Local = calendar:local_time(), - UtcSeconds = calendar:datetime_to_gregorian_seconds(Utc), - LocalSeconds = calendar:datetime_to_gregorian_seconds(Local), - LocalSeconds - UtcSeconds. diff --git a/build/packages/gleam_time/src/gleam_time_ffi.mjs b/build/packages/gleam_time/src/gleam_time_ffi.mjs deleted file mode 100644 index 27d09aa..0000000 --- a/build/packages/gleam_time/src/gleam_time_ffi.mjs +++ /dev/null @@ -1,11 +0,0 @@ -export function system_time() { - const now = Date.now(); - const milliseconds = now % 1_000; - const nanoseconds = milliseconds * 1000_000; - const seconds = (now - milliseconds) / 1_000; - return [seconds, nanoseconds]; -} - -export function local_time_offset_seconds() { - return new Date().getTimezoneOffset() * -60; -} diff --git a/build/packages/gleeunit/LICENCE b/build/packages/gleeunit/LICENCE deleted file mode 100644 index c7967c3..0000000 --- a/build/packages/gleeunit/LICENCE +++ /dev/null @@ -1,191 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - Copyright 2021, Louis Pilfold . - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - diff --git a/build/packages/gleeunit/README.md b/build/packages/gleeunit/README.md deleted file mode 100644 index 4d81364..0000000 --- a/build/packages/gleeunit/README.md +++ /dev/null @@ -1,44 +0,0 @@ -# gleeunit - -A simple test runner for Gleam, using EUnit on Erlang and a custom runner on JS. - -[![Package Version](https://img.shields.io/hexpm/v/gleeunit)](https://hex.pm/packages/gleeunit) -[![Hex Docs](https://img.shields.io/badge/hex-docs-ffaff3)](https://hexdocs.pm/gleeunit/) - - -```sh -gleam add gleeunit@1 --dev -``` -```gleam -// In test/yourapp_test.gleam -import gleeunit - -pub fn main() { - gleeunit.main() -} -``` - -Now any public function with a name ending in `_test` in the `test` directory -will be found and run as a test. - -```gleam -pub fn some_function_test() { - assert some_function() == "Hello!" -} -``` - -Run the tests by entering `gleam test` in the command line. - -### Deno - -If using the Deno JavaScript runtime, you will need to add the following to your -`gleam.toml`. - -```toml -[javascript.deno] -allow_read = [ - "gleam.toml", - "test", - "build", -] -``` diff --git a/build/packages/gleeunit/gleam.toml b/build/packages/gleeunit/gleam.toml deleted file mode 100644 index c7df0c5..0000000 --- a/build/packages/gleeunit/gleam.toml +++ /dev/null @@ -1,16 +0,0 @@ -name = "gleeunit" -version = "1.9.0" -licences = ["Apache-2.0"] -description = "A simple test runner for Gleam, using EUnit on Erlang" -repository = { type = "github", user = "lpil", repo = "gleeunit" } -links = [{ title = "Sponsor", href = "https://github.com/sponsors/lpil" }] -gleam = ">= 1.13.0" - -[javascript.deno] -allow_read = ["gleam.toml", "test", "build"] - -[dependencies] -gleam_stdlib = ">= 0.60.0 and < 1.0.0" - -[dev-dependencies] -testhelper = { "path" = "./testhelper" } diff --git a/build/packages/gleeunit/include/gleeunit@internal@gleam_panic_Assert.hrl b/build/packages/gleeunit/include/gleeunit@internal@gleam_panic_Assert.hrl deleted file mode 100644 index 9360941..0000000 --- a/build/packages/gleeunit/include/gleeunit@internal@gleam_panic_Assert.hrl +++ /dev/null @@ -1,6 +0,0 @@ --record(assert, { - start :: integer(), - 'end' :: integer(), - expression_start :: integer(), - kind :: gleeunit@internal@gleam_panic:assert_kind() -}). diff --git a/build/packages/gleeunit/include/gleeunit@internal@gleam_panic_AssertedExpression.hrl b/build/packages/gleeunit/include/gleeunit@internal@gleam_panic_AssertedExpression.hrl deleted file mode 100644 index 812663c..0000000 --- a/build/packages/gleeunit/include/gleeunit@internal@gleam_panic_AssertedExpression.hrl +++ /dev/null @@ -1,5 +0,0 @@ --record(asserted_expression, { - start :: integer(), - 'end' :: integer(), - kind :: gleeunit@internal@gleam_panic:expression_kind() -}). diff --git a/build/packages/gleeunit/include/gleeunit@internal@gleam_panic_BinaryOperator.hrl b/build/packages/gleeunit/include/gleeunit@internal@gleam_panic_BinaryOperator.hrl deleted file mode 100644 index eee44c9..0000000 --- a/build/packages/gleeunit/include/gleeunit@internal@gleam_panic_BinaryOperator.hrl +++ /dev/null @@ -1,5 +0,0 @@ --record(binary_operator, { - operator :: binary(), - left :: gleeunit@internal@gleam_panic:asserted_expression(), - right :: gleeunit@internal@gleam_panic:asserted_expression() -}). diff --git a/build/packages/gleeunit/include/gleeunit@internal@gleam_panic_Expression.hrl b/build/packages/gleeunit/include/gleeunit@internal@gleam_panic_Expression.hrl deleted file mode 100644 index e7ffaa0..0000000 --- a/build/packages/gleeunit/include/gleeunit@internal@gleam_panic_Expression.hrl +++ /dev/null @@ -1 +0,0 @@ --record(expression, {value :: gleam@dynamic:dynamic_()}). diff --git a/build/packages/gleeunit/include/gleeunit@internal@gleam_panic_FunctionCall.hrl b/build/packages/gleeunit/include/gleeunit@internal@gleam_panic_FunctionCall.hrl deleted file mode 100644 index 9d55488..0000000 --- a/build/packages/gleeunit/include/gleeunit@internal@gleam_panic_FunctionCall.hrl +++ /dev/null @@ -1,3 +0,0 @@ --record(function_call, { - arguments :: list(gleeunit@internal@gleam_panic:asserted_expression()) -}). diff --git a/build/packages/gleeunit/include/gleeunit@internal@gleam_panic_GleamPanic.hrl b/build/packages/gleeunit/include/gleeunit@internal@gleam_panic_GleamPanic.hrl deleted file mode 100644 index cf36764..0000000 --- a/build/packages/gleeunit/include/gleeunit@internal@gleam_panic_GleamPanic.hrl +++ /dev/null @@ -1,8 +0,0 @@ --record(gleam_panic, { - message :: binary(), - file :: binary(), - module :: binary(), - function :: binary(), - line :: integer(), - kind :: gleeunit@internal@gleam_panic:panic_kind() -}). diff --git a/build/packages/gleeunit/include/gleeunit@internal@gleam_panic_LetAssert.hrl b/build/packages/gleeunit/include/gleeunit@internal@gleam_panic_LetAssert.hrl deleted file mode 100644 index 11f865e..0000000 --- a/build/packages/gleeunit/include/gleeunit@internal@gleam_panic_LetAssert.hrl +++ /dev/null @@ -1,7 +0,0 @@ --record(let_assert, { - start :: integer(), - 'end' :: integer(), - pattern_start :: integer(), - pattern_end :: integer(), - value :: gleam@dynamic:dynamic_() -}). diff --git a/build/packages/gleeunit/include/gleeunit@internal@gleam_panic_Literal.hrl b/build/packages/gleeunit/include/gleeunit@internal@gleam_panic_Literal.hrl deleted file mode 100644 index 2396489..0000000 --- a/build/packages/gleeunit/include/gleeunit@internal@gleam_panic_Literal.hrl +++ /dev/null @@ -1 +0,0 @@ --record(literal, {value :: gleam@dynamic:dynamic_()}). diff --git a/build/packages/gleeunit/include/gleeunit@internal@gleam_panic_OtherExpression.hrl b/build/packages/gleeunit/include/gleeunit@internal@gleam_panic_OtherExpression.hrl deleted file mode 100644 index 0424990..0000000 --- a/build/packages/gleeunit/include/gleeunit@internal@gleam_panic_OtherExpression.hrl +++ /dev/null @@ -1,3 +0,0 @@ --record(other_expression, { - expression :: gleeunit@internal@gleam_panic:asserted_expression() -}). diff --git a/build/packages/gleeunit/include/gleeunit@internal@reporting_State.hrl b/build/packages/gleeunit/include/gleeunit@internal@reporting_State.hrl deleted file mode 100644 index 575ccce..0000000 --- a/build/packages/gleeunit/include/gleeunit@internal@reporting_State.hrl +++ /dev/null @@ -1 +0,0 @@ --record(state, {passed :: integer(), failed :: integer(), skipped :: integer()}). diff --git a/build/packages/gleeunit/src/gleeunit.app.src b/build/packages/gleeunit/src/gleeunit.app.src deleted file mode 100644 index e72987c..0000000 --- a/build/packages/gleeunit/src/gleeunit.app.src +++ /dev/null @@ -1,16 +0,0 @@ -{application, gleeunit, [ - {vsn, "1.9.0"}, - {applications, [gleam_stdlib]}, - {description, "A simple test runner for Gleam, using EUnit on Erlang"}, - {modules, [erlang_test_module, - gleeunit, - gleeunit@@main, - gleeunit@internal@gleam_panic, - gleeunit@internal@reporting, - gleeunit@should, - gleeunit_ffi, - gleeunit_gleam_panic_ffi, - gleeunit_progress, - gleeunit_test_ffi]}, - {registered, []} -]}. diff --git a/build/packages/gleeunit/src/gleeunit.erl b/build/packages/gleeunit/src/gleeunit.erl deleted file mode 100644 index bcb58b6..0000000 --- a/build/packages/gleeunit/src/gleeunit.erl +++ /dev/null @@ -1,89 +0,0 @@ --module(gleeunit). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "src/gleeunit.gleam"). --export([main/0]). --export_type([atom_/0, encoding/0, report_module_name/0, gleeunit_progress_option/0, eunit_option/0]). - --if(?OTP_RELEASE >= 27). --define(MODULEDOC(Str), -moduledoc(Str)). --define(DOC(Str), -doc(Str)). --else. --define(MODULEDOC(Str), -compile([])). --define(DOC(Str), -compile([])). --endif. - --type atom_() :: any(). - --type encoding() :: utf8. - --type report_module_name() :: gleeunit_progress. - --type gleeunit_progress_option() :: {colored, boolean()}. - --type eunit_option() :: verbose | - no_tty | - {report, {report_module_name(), list(gleeunit_progress_option())}} | - {scale_timeouts, integer()}. - --file("src/gleeunit.gleam", 42). --spec gleam_to_erlang_module_name(binary()) -> binary(). -gleam_to_erlang_module_name(Path) -> - case gleam_stdlib:string_ends_with(Path, <<".gleam"/utf8>>) of - true -> - _pipe = Path, - _pipe@1 = gleam@string:replace( - _pipe, - <<".gleam"/utf8>>, - <<""/utf8>> - ), - gleam@string:replace(_pipe@1, <<"/"/utf8>>, <<"@"/utf8>>); - - false -> - _pipe@2 = Path, - _pipe@3 = gleam@string:split(_pipe@2, <<"/"/utf8>>), - _pipe@4 = gleam@list:last(_pipe@3), - _pipe@5 = gleam@result:unwrap(_pipe@4, Path), - gleam@string:replace(_pipe@5, <<".erl"/utf8>>, <<""/utf8>>) - end. - --file("src/gleeunit.gleam", 18). --spec do_main() -> nil. -do_main() -> - Options = [verbose, - no_tty, - {report, {gleeunit_progress, [{colored, true}]}}, - {scale_timeouts, 10}], - Result = begin - _pipe = gleeunit_ffi:find_files( - <<"**/*.{erl,gleam}"/utf8>>, - <<"test"/utf8>> - ), - _pipe@1 = gleam@list:map(_pipe, fun gleam_to_erlang_module_name/1), - _pipe@2 = gleam@list:map( - _pipe@1, - fun(_capture) -> erlang:binary_to_atom(_capture, utf8) end - ), - gleeunit_ffi:run_eunit(_pipe@2, Options) - end, - Code = case Result of - {ok, _} -> - 0; - - {error, _} -> - 1 - end, - erlang:halt(Code). - --file("src/gleeunit.gleam", 13). -?DOC( - " Find and run all test functions for the current project using Erlang's EUnit\n" - " test framework, or a custom JavaScript test runner.\n" - "\n" - " Any Erlang or Gleam function in the `test` directory with a name ending in\n" - " `_test` is considered a test function and will be run.\n" - "\n" - " A test that panics is considered a failure.\n" -). --spec main() -> nil. -main() -> - do_main(). diff --git a/build/packages/gleeunit/src/gleeunit.gleam b/build/packages/gleeunit/src/gleeunit.gleam deleted file mode 100644 index 7d3155e..0000000 --- a/build/packages/gleeunit/src/gleeunit.gleam +++ /dev/null @@ -1,86 +0,0 @@ -import gleam/list -import gleam/result -import gleam/string - -/// Find and run all test functions for the current project using Erlang's EUnit -/// test framework, or a custom JavaScript test runner. -/// -/// Any Erlang or Gleam function in the `test` directory with a name ending in -/// `_test` is considered a test function and will be run. -/// -/// A test that panics is considered a failure. -/// -pub fn main() -> Nil { - do_main() -} - -@external(javascript, "./gleeunit_ffi.mjs", "main") -fn do_main() -> Nil { - let options = [ - Verbose, - NoTty, - Report(#(GleeunitProgress, [Colored(True)])), - ScaleTimeouts(10), - ] - - let result = - find_files(matching: "**/*.{erl,gleam}", in: "test") - |> list.map(gleam_to_erlang_module_name) - |> list.map(dangerously_convert_string_to_atom(_, Utf8)) - |> run_eunit(options) - - let code = case result { - Ok(_) -> 0 - Error(_) -> 1 - } - halt(code) -} - -@external(erlang, "erlang", "halt") -fn halt(a: Int) -> Nil - -fn gleam_to_erlang_module_name(path: String) -> String { - case string.ends_with(path, ".gleam") { - True -> - path - |> string.replace(".gleam", "") - |> string.replace("/", "@") - - False -> - path - |> string.split("/") - |> list.last - |> result.unwrap(path) - |> string.replace(".erl", "") - } -} - -@external(erlang, "gleeunit_ffi", "find_files") -fn find_files(matching matching: String, in in: String) -> List(String) - -type Atom - -type Encoding { - Utf8 -} - -@external(erlang, "erlang", "binary_to_atom") -fn dangerously_convert_string_to_atom(a: String, b: Encoding) -> Atom - -type ReportModuleName { - GleeunitProgress -} - -type GleeunitProgressOption { - Colored(Bool) -} - -type EunitOption { - Verbose - NoTty - Report(#(ReportModuleName, List(GleeunitProgressOption))) - ScaleTimeouts(Int) -} - -@external(erlang, "gleeunit_ffi", "run_eunit") -fn run_eunit(a: List(Atom), b: List(EunitOption)) -> Result(Nil, a) diff --git a/build/packages/gleeunit/src/gleeunit/internal/gleam_panic.gleam b/build/packages/gleeunit/src/gleeunit/internal/gleam_panic.gleam deleted file mode 100644 index 6a5d309..0000000 --- a/build/packages/gleeunit/src/gleeunit/internal/gleam_panic.gleam +++ /dev/null @@ -1,49 +0,0 @@ -import gleam/dynamic - -pub type GleamPanic { - GleamPanic( - message: String, - file: String, - module: String, - function: String, - line: Int, - kind: PanicKind, - ) -} - -pub type PanicKind { - Todo - Panic - LetAssert( - start: Int, - end: Int, - pattern_start: Int, - pattern_end: Int, - value: dynamic.Dynamic, - ) - Assert(start: Int, end: Int, expression_start: Int, kind: AssertKind) -} - -pub type AssertKind { - BinaryOperator( - operator: String, - left: AssertedExpression, - right: AssertedExpression, - ) - FunctionCall(arguments: List(AssertedExpression)) - OtherExpression(expression: AssertedExpression) -} - -pub type AssertedExpression { - AssertedExpression(start: Int, end: Int, kind: ExpressionKind) -} - -pub type ExpressionKind { - Literal(value: dynamic.Dynamic) - Expression(value: dynamic.Dynamic) - Unevaluated -} - -@external(erlang, "gleeunit_gleam_panic_ffi", "from_dynamic") -@external(javascript, "./gleeunit_gleam_panic_ffi.mjs", "from_dynamic") -pub fn from_dynamic(data: dynamic.Dynamic) -> Result(GleamPanic, Nil) diff --git a/build/packages/gleeunit/src/gleeunit/internal/gleeunit_gleam_panic_ffi.erl b/build/packages/gleeunit/src/gleeunit/internal/gleeunit_gleam_panic_ffi.erl deleted file mode 100644 index d78f5e5..0000000 --- a/build/packages/gleeunit/src/gleeunit/internal/gleeunit_gleam_panic_ffi.erl +++ /dev/null @@ -1,49 +0,0 @@ --module(gleeunit_gleam_panic_ffi). --export([from_dynamic/1]). - -from_dynamic(#{ - gleam_error := assert, - start := Start, - 'end' := End, - expression_start := EStart -} = E) -> - wrap(E, {assert, Start, End, EStart, assert_kind(E)}); -from_dynamic(#{ - gleam_error := let_assert, - start := Start, - 'end' := End, - pattern_start := PStart, - pattern_end := PEnd, - value := Value -} = E) -> - wrap(E, {let_assert, Start, End, PStart, PEnd, Value}); -from_dynamic(#{gleam_error := panic} = E) -> - wrap(E, panic); -from_dynamic(#{gleam_error := todo} = E) -> - wrap(E, todo); -from_dynamic(_) -> - {error, nil}. - -assert_kind(#{kind := binary_operator, left := L, right := R, operator := O}) -> - {binary_operator, atom_to_binary(O), expression(L), expression(R)}; -assert_kind(#{kind := function_call, arguments := Arguments}) -> - {function_call, lists:map(fun expression/1, Arguments)}; -assert_kind(#{kind := expression, expression := Expression}) -> - {other_expression, expression(Expression)}. - -expression(#{start := S, 'end' := E, kind := literal, value := Value}) -> - {asserted_expression, S, E, {literal, Value}}; -expression(#{start := S, 'end' := E, kind := expression, value := Value}) -> - {asserted_expression, S, E, {expression, Value}}; -expression(#{start := S, 'end' := E, kind := unevaluated}) -> - {asserted_expression, S, E, unevaluated}. - -wrap(#{ - gleam_error := _, - file := File, - message := Message, - module := Module, - function := Function, - line := Line -}, Kind) -> - {ok, {gleam_panic, Message, File, Module, Function, Line, Kind}}. diff --git a/build/packages/gleeunit/src/gleeunit/internal/gleeunit_gleam_panic_ffi.mjs b/build/packages/gleeunit/src/gleeunit/internal/gleeunit_gleam_panic_ffi.mjs deleted file mode 100644 index 03f6025..0000000 --- a/build/packages/gleeunit/src/gleeunit/internal/gleeunit_gleam_panic_ffi.mjs +++ /dev/null @@ -1,91 +0,0 @@ -import { Result$Ok, Result$Error, List$Empty, List$NonEmpty } from "../../gleam.mjs"; -import { - GleamPanic$GleamPanic, - PanicKind$Todo, - PanicKind$Panic, - PanicKind$LetAssert, - PanicKind$Assert, - AssertKind$BinaryOperator, - AssertKind$FunctionCall, - AssertKind$OtherExpression, - AssertedExpression$AssertedExpression, - ExpressionKind$Literal, - ExpressionKind$Expression, - ExpressionKind$Unevaluated, -} from "./gleam_panic.mjs"; - -export function from_dynamic(error) { - if (!(error instanceof globalThis.Error) || !error.gleam_error) { - return Result$Error(undefined); - } - - if (error.gleam_error === "todo") { - return wrap(error, PanicKind$Todo()); - } - - if (error.gleam_error === "panic") { - return wrap(error, PanicKind$Panic()); - } - - if (error.gleam_error === "let_assert") { - let kind = PanicKind$LetAssert( - error.start, - error.end, - error.pattern_start, - error.pattern_end, - error.value, - ); - return wrap(error, kind); - } - - if (error.gleam_error === "assert") { - let kind = PanicKind$Assert( - error.start, - error.end, - error.expression_start, - assert_kind(error), - ); - return wrap(error, kind); - } - - return Result$Error(undefined); -} - -function assert_kind(error) { - if (error.kind == "binary_operator") { - return AssertKind$BinaryOperator( - error.operator, - expression(error.left), - expression(error.right), - ); - } - - if (error.kind == "function_call") { - let list = List$Empty(); - let i = error.arguments.length; - while (i--) { - list = List$NonEmpty(expression(error.arguments[i]), list); - } - return AssertKind$FunctionCall(list); - } - - return AssertKind$OtherExpression(expression(error.expression)); -} - -function expression(data) { - const expression = AssertedExpression$AssertedExpression(data.start, data.end, undefined); - if (data.kind == "literal") { - expression.kind = ExpressionKind$Literal(data.value); - } else if (data.kind == "expression") { - expression.kind = ExpressionKind$Expression(data.value); - } else { - expression.kind = ExpressionKind$Unevaluated(); - } - return expression; -} - -function wrap(e, kind) { - return Result$Ok( - GleamPanic$GleamPanic(e.message, e.file, e.module, e.function, e.line, kind), - ); -} diff --git a/build/packages/gleeunit/src/gleeunit/internal/reporting.gleam b/build/packages/gleeunit/src/gleeunit/internal/reporting.gleam deleted file mode 100644 index 72f766f..0000000 --- a/build/packages/gleeunit/src/gleeunit/internal/reporting.gleam +++ /dev/null @@ -1,240 +0,0 @@ -import gleam/bit_array -import gleam/dynamic -import gleam/int -import gleam/io -import gleam/list -import gleam/option.{type Option} -import gleam/result -import gleam/string -import gleeunit/internal/gleam_panic.{type GleamPanic} - -pub type State { - State(passed: Int, failed: Int, skipped: Int) -} - -pub fn new_state() -> State { - State(passed: 0, failed: 0, skipped: 0) -} - -pub fn finished(state: State) -> Int { - case state { - State(passed: 0, failed: 0, skipped: 0) -> { - io.println("\nNo tests found!") - 1 - } - State(failed: 0, skipped: 0, ..) -> { - let message = - "\n" <> int.to_string(state.passed) <> " passed, no failures" - io.println(green(message)) - 0 - } - State(skipped: 0, ..) -> { - let message = - "\n" - <> int.to_string(state.passed) - <> " passed, " - <> int.to_string(state.failed) - <> " failures" - io.println(red(message)) - 1 - } - State(failed: 0, ..) -> { - let message = - "\n" - <> int.to_string(state.passed) - <> " passed, 0 failures, " - <> int.to_string(state.skipped) - <> " skipped" - io.println(yellow(message)) - 1 - } - State(..) -> { - let message = - "\n" - <> int.to_string(state.passed) - <> " passed, " - <> int.to_string(state.failed) - <> " failures, " - <> int.to_string(state.skipped) - <> " skipped" - io.println(red(message)) - 1 - } - } -} - -pub fn test_passed(state: State) -> State { - io.print(green(".")) - State(..state, passed: state.passed + 1) -} - -pub fn test_failed( - state: State, - module: String, - function: String, - error: dynamic.Dynamic, -) -> State { - let message = case gleam_panic.from_dynamic(error) { - Ok(error) -> { - let src = option.from_result(read_file(error.file)) - format_gleam_error(error, module, function, src) - } - Error(_) -> format_unknown(module, function, error) - } - - io.print("\n" <> message) - State(..state, failed: state.failed + 1) -} - -pub fn eunit_missing() -> Result(never, Nil) { - let message = bold(red("Error")) <> ": EUnit libraries not found. - -Your Erlang installation seems to be incomplete. If you installed Erlang using -a package manager ensure that you have installed the full Erlang -distribution instead of a stripped-down version. -" - io.print_error(message) - Error(Nil) -} - -fn format_unknown( - module: String, - function: String, - error: dynamic.Dynamic, -) -> String { - string.concat([ - grey(module <> "." <> function) <> "\n", - "An unexpected error occurred:\n", - "\n", - " " <> string.inspect(error) <> "\n", - ]) -} - -fn format_gleam_error( - error: GleamPanic, - module: String, - function: String, - src: Option(BitArray), -) -> String { - let location = grey(error.file <> ":" <> int.to_string(error.line)) - - case error.kind { - gleam_panic.Panic -> { - string.concat([ - bold(red("panic")) <> " " <> location <> "\n", - cyan(" test") <> ": " <> module <> "." <> function <> "\n", - cyan(" info") <> ": " <> error.message <> "\n", - ]) - } - - gleam_panic.Todo -> { - string.concat([ - bold(yellow("todo")) <> " " <> location <> "\n", - cyan(" test") <> ": " <> module <> "." <> function <> "\n", - cyan(" info") <> ": " <> error.message <> "\n", - ]) - } - - gleam_panic.Assert(start:, end:, kind:, ..) -> { - string.concat([ - bold(red("assert")) <> " " <> location <> "\n", - cyan(" test") <> ": " <> module <> "." <> function <> "\n", - code_snippet(src, start, end), - assert_info(kind), - cyan(" info") <> ": " <> error.message <> "\n", - ]) - } - - gleam_panic.LetAssert(start:, end:, value:, ..) -> { - string.concat([ - bold(red("let assert")) <> " " <> location <> "\n", - cyan(" test") <> ": " <> module <> "." <> function <> "\n", - code_snippet(src, start, end), - cyan("value") <> ": " <> string.inspect(value) <> "\n", - cyan(" info") <> ": " <> error.message <> "\n", - ]) - } - } -} - -fn assert_info(kind: gleam_panic.AssertKind) -> String { - case kind { - gleam_panic.BinaryOperator(left:, right:, ..) -> { - string.concat([assert_value(" left", left), assert_value("right", right)]) - } - - gleam_panic.FunctionCall(arguments:) -> { - arguments - |> list.index_map(fn(e, i) { - let number = string.pad_start(int.to_string(i), 5, " ") - assert_value(number, e) - }) - |> string.concat - } - - gleam_panic.OtherExpression(..) -> "" - } -} - -fn assert_value(name: String, value: gleam_panic.AssertedExpression) -> String { - cyan(name) <> ": " <> inspect_value(value) <> "\n" -} - -fn inspect_value(value: gleam_panic.AssertedExpression) -> String { - case value.kind { - gleam_panic.Unevaluated -> grey("unevaluated") - gleam_panic.Literal(..) -> grey("literal") - gleam_panic.Expression(value:) -> string.inspect(value) - } -} - -fn code_snippet(src: Option(BitArray), start: Int, end: Int) -> String { - { - use src <- result.try(option.to_result(src, Nil)) - use snippet <- result.try(bit_array.slice(src, start, end - start)) - use snippet <- result.try(bit_array.to_string(snippet)) - let snippet = cyan(" code") <> ": " <> snippet <> "\n" - Ok(snippet) - } - |> result.unwrap("") -} - -pub fn test_skipped(state: State, module: String, function: String) -> State { - io.print("\n" <> module <> "." <> function <> yellow(" skipped")) - State(..state, skipped: state.skipped + 1) -} - -fn bold(text: String) -> String { - "\u{001b}[1m" <> text <> "\u{001b}[22m" -} - -fn cyan(text: String) -> String { - "\u{001b}[36m" <> text <> "\u{001b}[39m" -} - -fn yellow(text: String) -> String { - "\u{001b}[33m" <> text <> "\u{001b}[39m" -} - -fn green(text: String) -> String { - "\u{001b}[32m" <> text <> "\u{001b}[39m" -} - -fn red(text: String) -> String { - "\u{001b}[31m" <> text <> "\u{001b}[39m" -} - -fn grey(text: String) -> String { - "\u{001b}[90m" <> text <> "\u{001b}[39m" -} - -@external(erlang, "file", "read_file") -fn read_file(path: String) -> Result(BitArray, dynamic.Dynamic) { - case read_file_text(path) { - Ok(text) -> Ok(bit_array.from_string(text)) - Error(e) -> Error(e) - } -} - -@external(javascript, "../../gleeunit_ffi.mjs", "read_file") -fn read_file_text(path: String) -> Result(String, dynamic.Dynamic) diff --git a/build/packages/gleeunit/src/gleeunit/should.gleam b/build/packages/gleeunit/src/gleeunit/should.gleam deleted file mode 100644 index 99cd16c..0000000 --- a/build/packages/gleeunit/src/gleeunit/should.gleam +++ /dev/null @@ -1,72 +0,0 @@ -//// Use the `assert` keyword instead of this module. - -import gleam/option.{type Option, None, Some} -import gleam/string - -pub fn equal(a: t, b: t) -> Nil { - case a == b { - True -> Nil - _ -> - panic as string.concat([ - "\n", - string.inspect(a), - "\nshould equal\n", - string.inspect(b), - ]) - } -} - -pub fn not_equal(a: t, b: t) -> Nil { - case a != b { - True -> Nil - _ -> - panic as string.concat([ - "\n", - string.inspect(a), - "\nshould not equal\n", - string.inspect(b), - ]) - } -} - -pub fn be_ok(a: Result(a, e)) -> a { - case a { - Ok(value) -> value - _ -> panic as string.concat(["\n", string.inspect(a), "\nshould be ok"]) - } -} - -pub fn be_error(a: Result(a, e)) -> e { - case a { - Error(error) -> error - _ -> panic as string.concat(["\n", string.inspect(a), "\nshould be error"]) - } -} - -pub fn be_some(a: Option(a)) -> a { - case a { - Some(value) -> value - _ -> panic as string.concat(["\n", string.inspect(a), "\nshould be some"]) - } -} - -pub fn be_none(a: Option(a)) -> Nil { - case a { - None -> Nil - _ -> panic as string.concat(["\n", string.inspect(a), "\nshould be none"]) - } -} - -pub fn be_true(actual: Bool) -> Nil { - actual - |> equal(True) -} - -pub fn be_false(actual: Bool) -> Nil { - actual - |> equal(False) -} - -pub fn fail() -> Nil { - be_true(False) -} diff --git a/build/packages/gleeunit/src/gleeunit@internal@gleam_panic.erl b/build/packages/gleeunit/src/gleeunit@internal@gleam_panic.erl deleted file mode 100644 index 398ea7d..0000000 --- a/build/packages/gleeunit/src/gleeunit@internal@gleam_panic.erl +++ /dev/null @@ -1,56 +0,0 @@ --module(gleeunit@internal@gleam_panic). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "src/gleeunit/internal/gleam_panic.gleam"). --export([from_dynamic/1]). --export_type([gleam_panic/0, panic_kind/0, assert_kind/0, asserted_expression/0, expression_kind/0]). - --if(?OTP_RELEASE >= 27). --define(MODULEDOC(Str), -moduledoc(Str)). --define(DOC(Str), -doc(Str)). --else. --define(MODULEDOC(Str), -compile([])). --define(DOC(Str), -compile([])). --endif. - -?MODULEDOC(false). - --type gleam_panic() :: {gleam_panic, - binary(), - binary(), - binary(), - binary(), - integer(), - panic_kind()}. - --type panic_kind() :: todo | - panic | - {let_assert, - integer(), - integer(), - integer(), - integer(), - gleam@dynamic:dynamic_()} | - {assert, integer(), integer(), integer(), assert_kind()}. - --type assert_kind() :: {binary_operator, - binary(), - asserted_expression(), - asserted_expression()} | - {function_call, list(asserted_expression())} | - {other_expression, asserted_expression()}. - --type asserted_expression() :: {asserted_expression, - integer(), - integer(), - expression_kind()}. - --type expression_kind() :: {literal, gleam@dynamic:dynamic_()} | - {expression, gleam@dynamic:dynamic_()} | - unevaluated. - --file("src/gleeunit/internal/gleam_panic.gleam", 49). -?DOC(false). --spec from_dynamic(gleam@dynamic:dynamic_()) -> {ok, gleam_panic()} | - {error, nil}. -from_dynamic(Data) -> - gleeunit_gleam_panic_ffi:from_dynamic(Data). diff --git a/build/packages/gleeunit/src/gleeunit@internal@reporting.erl b/build/packages/gleeunit/src/gleeunit@internal@reporting.erl deleted file mode 100644 index 8c37c79..0000000 --- a/build/packages/gleeunit/src/gleeunit@internal@reporting.erl +++ /dev/null @@ -1,343 +0,0 @@ --module(gleeunit@internal@reporting). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "src/gleeunit/internal/reporting.gleam"). --export([new_state/0, test_skipped/3, test_passed/1, finished/1, eunit_missing/0, test_failed/4]). --export_type([state/0]). - --if(?OTP_RELEASE >= 27). --define(MODULEDOC(Str), -moduledoc(Str)). --define(DOC(Str), -doc(Str)). --else. --define(MODULEDOC(Str), -compile([])). --define(DOC(Str), -compile([])). --endif. - -?MODULEDOC(false). - --type state() :: {state, integer(), integer(), integer()}. - --file("src/gleeunit/internal/reporting.gleam", 15). -?DOC(false). --spec new_state() -> state(). -new_state() -> - {state, 0, 0, 0}. - --file("src/gleeunit/internal/reporting.gleam", 207). -?DOC(false). --spec bold(binary()) -> binary(). -bold(Text) -> - <<<<"\x{001b}[1m"/utf8, Text/binary>>/binary, "\x{001b}[22m"/utf8>>. - --file("src/gleeunit/internal/reporting.gleam", 211). -?DOC(false). --spec cyan(binary()) -> binary(). -cyan(Text) -> - <<<<"\x{001b}[36m"/utf8, Text/binary>>/binary, "\x{001b}[39m"/utf8>>. - --file("src/gleeunit/internal/reporting.gleam", 191). -?DOC(false). --spec code_snippet(gleam@option:option(bitstring()), integer(), integer()) -> binary(). -code_snippet(Src, Start, End) -> - _pipe = begin - gleam@result:'try'( - gleam@option:to_result(Src, nil), - fun(Src@1) -> - gleam@result:'try'( - gleam_stdlib:bit_array_slice(Src@1, Start, End - Start), - fun(Snippet) -> - gleam@result:'try'( - gleam@bit_array:to_string(Snippet), - fun(Snippet@1) -> - Snippet@2 = <<<<<<(cyan(<<" code"/utf8>>))/binary, - ": "/utf8>>/binary, - Snippet@1/binary>>/binary, - "\n"/utf8>>, - {ok, Snippet@2} - end - ) - end - ) - end - ) - end, - gleam@result:unwrap(_pipe, <<""/utf8>>). - --file("src/gleeunit/internal/reporting.gleam", 215). -?DOC(false). --spec yellow(binary()) -> binary(). -yellow(Text) -> - <<<<"\x{001b}[33m"/utf8, Text/binary>>/binary, "\x{001b}[39m"/utf8>>. - --file("src/gleeunit/internal/reporting.gleam", 202). -?DOC(false). --spec test_skipped(state(), binary(), binary()) -> state(). -test_skipped(State, Module, Function) -> - gleam_stdlib:print( - <<<<<<<<"\n"/utf8, Module/binary>>/binary, "."/utf8>>/binary, - Function/binary>>/binary, - (yellow(<<" skipped"/utf8>>))/binary>> - ), - {state, - erlang:element(2, State), - erlang:element(3, State), - erlang:element(4, State) + 1}. - --file("src/gleeunit/internal/reporting.gleam", 219). -?DOC(false). --spec green(binary()) -> binary(). -green(Text) -> - <<<<"\x{001b}[32m"/utf8, Text/binary>>/binary, "\x{001b}[39m"/utf8>>. - --file("src/gleeunit/internal/reporting.gleam", 66). -?DOC(false). --spec test_passed(state()) -> state(). -test_passed(State) -> - gleam_stdlib:print(green(<<"."/utf8>>)), - {state, - erlang:element(2, State) + 1, - erlang:element(3, State), - erlang:element(4, State)}. - --file("src/gleeunit/internal/reporting.gleam", 223). -?DOC(false). --spec red(binary()) -> binary(). -red(Text) -> - <<<<"\x{001b}[31m"/utf8, Text/binary>>/binary, "\x{001b}[39m"/utf8>>. - --file("src/gleeunit/internal/reporting.gleam", 19). -?DOC(false). --spec finished(state()) -> integer(). -finished(State) -> - case State of - {state, 0, 0, 0} -> - gleam_stdlib:println(<<"\nNo tests found!"/utf8>>), - 1; - - {state, _, 0, 0} -> - Message = <<<<"\n"/utf8, - (erlang:integer_to_binary(erlang:element(2, State)))/binary>>/binary, - " passed, no failures"/utf8>>, - gleam_stdlib:println(green(Message)), - 0; - - {state, _, _, 0} -> - Message@1 = <<<<<<<<"\n"/utf8, - (erlang:integer_to_binary(erlang:element(2, State)))/binary>>/binary, - " passed, "/utf8>>/binary, - (erlang:integer_to_binary(erlang:element(3, State)))/binary>>/binary, - " failures"/utf8>>, - gleam_stdlib:println(red(Message@1)), - 1; - - {state, _, 0, _} -> - Message@2 = <<<<<<<<"\n"/utf8, - (erlang:integer_to_binary(erlang:element(2, State)))/binary>>/binary, - " passed, 0 failures, "/utf8>>/binary, - (erlang:integer_to_binary(erlang:element(4, State)))/binary>>/binary, - " skipped"/utf8>>, - gleam_stdlib:println(yellow(Message@2)), - 1; - - {state, _, _, _} -> - Message@3 = <<<<<<<<<<<<"\n"/utf8, - (erlang:integer_to_binary( - erlang:element(2, State) - ))/binary>>/binary, - " passed, "/utf8>>/binary, - (erlang:integer_to_binary(erlang:element(3, State)))/binary>>/binary, - " failures, "/utf8>>/binary, - (erlang:integer_to_binary(erlang:element(4, State)))/binary>>/binary, - " skipped"/utf8>>, - gleam_stdlib:println(red(Message@3)), - 1 - end. - --file("src/gleeunit/internal/reporting.gleam", 89). -?DOC(false). --spec eunit_missing() -> {ok, any()} | {error, nil}. -eunit_missing() -> - Message = <<(bold(red(<<"Error"/utf8>>)))/binary, - ": EUnit libraries not found. - -Your Erlang installation seems to be incomplete. If you installed Erlang using -a package manager ensure that you have installed the full Erlang -distribution instead of a stripped-down version. -"/utf8>>, - gleam_stdlib:print_error(Message), - {error, nil}. - --file("src/gleeunit/internal/reporting.gleam", 227). -?DOC(false). --spec grey(binary()) -> binary(). -grey(Text) -> - <<<<"\x{001b}[90m"/utf8, Text/binary>>/binary, "\x{001b}[39m"/utf8>>. - --file("src/gleeunit/internal/reporting.gleam", 100). -?DOC(false). --spec format_unknown(binary(), binary(), gleam@dynamic:dynamic_()) -> binary(). -format_unknown(Module, Function, Error) -> - erlang:list_to_binary( - [<<(grey(<<<>/binary, Function/binary>>))/binary, - "\n"/utf8>>, - <<"An unexpected error occurred:\n"/utf8>>, - <<"\n"/utf8>>, - <<<<" "/utf8, (gleam@string:inspect(Error))/binary>>/binary, - "\n"/utf8>>] - ). - --file("src/gleeunit/internal/reporting.gleam", 183). -?DOC(false). --spec inspect_value(gleeunit@internal@gleam_panic:asserted_expression()) -> binary(). -inspect_value(Value) -> - case erlang:element(4, Value) of - unevaluated -> - grey(<<"unevaluated"/utf8>>); - - {literal, _} -> - grey(<<"literal"/utf8>>); - - {expression, Value@1} -> - gleam@string:inspect(Value@1) - end. - --file("src/gleeunit/internal/reporting.gleam", 179). -?DOC(false). --spec assert_value( - binary(), - gleeunit@internal@gleam_panic:asserted_expression() -) -> binary(). -assert_value(Name, Value) -> - <<<<<<(cyan(Name))/binary, ": "/utf8>>/binary, - (inspect_value(Value))/binary>>/binary, - "\n"/utf8>>. - --file("src/gleeunit/internal/reporting.gleam", 160). -?DOC(false). --spec assert_info(gleeunit@internal@gleam_panic:assert_kind()) -> binary(). -assert_info(Kind) -> - case Kind of - {binary_operator, _, Left, Right} -> - erlang:list_to_binary( - [assert_value(<<" left"/utf8>>, Left), - assert_value(<<"right"/utf8>>, Right)] - ); - - {function_call, Arguments} -> - _pipe = Arguments, - _pipe@1 = gleam@list:index_map( - _pipe, - fun(E, I) -> - Number = gleam@string:pad_start( - erlang:integer_to_binary(I), - 5, - <<" "/utf8>> - ), - assert_value(Number, E) - end - ), - erlang:list_to_binary(_pipe@1); - - {other_expression, _} -> - <<""/utf8>> - end. - --file("src/gleeunit/internal/reporting.gleam", 113). -?DOC(false). --spec format_gleam_error( - gleeunit@internal@gleam_panic:gleam_panic(), - binary(), - binary(), - gleam@option:option(bitstring()) -) -> binary(). -format_gleam_error(Error, Module, Function, Src) -> - Location = grey( - <<<<(erlang:element(3, Error))/binary, ":"/utf8>>/binary, - (erlang:integer_to_binary(erlang:element(6, Error)))/binary>> - ), - case erlang:element(7, Error) of - panic -> - erlang:list_to_binary( - [<<<<<<(bold(red(<<"panic"/utf8>>)))/binary, " "/utf8>>/binary, - Location/binary>>/binary, - "\n"/utf8>>, - <<<<<<<<<<(cyan(<<" test"/utf8>>))/binary, ": "/utf8>>/binary, - Module/binary>>/binary, - "."/utf8>>/binary, - Function/binary>>/binary, - "\n"/utf8>>, - <<<<<<(cyan(<<" info"/utf8>>))/binary, ": "/utf8>>/binary, - (erlang:element(2, Error))/binary>>/binary, - "\n"/utf8>>] - ); - - todo -> - erlang:list_to_binary( - [<<<<<<(bold(yellow(<<"todo"/utf8>>)))/binary, " "/utf8>>/binary, - Location/binary>>/binary, - "\n"/utf8>>, - <<<<<<<<<<(cyan(<<" test"/utf8>>))/binary, ": "/utf8>>/binary, - Module/binary>>/binary, - "."/utf8>>/binary, - Function/binary>>/binary, - "\n"/utf8>>, - <<<<<<(cyan(<<" info"/utf8>>))/binary, ": "/utf8>>/binary, - (erlang:element(2, Error))/binary>>/binary, - "\n"/utf8>>] - ); - - {assert, Start, End, _, Kind} -> - erlang:list_to_binary( - [<<<<<<(bold(red(<<"assert"/utf8>>)))/binary, " "/utf8>>/binary, - Location/binary>>/binary, - "\n"/utf8>>, - <<<<<<<<<<(cyan(<<" test"/utf8>>))/binary, ": "/utf8>>/binary, - Module/binary>>/binary, - "."/utf8>>/binary, - Function/binary>>/binary, - "\n"/utf8>>, - code_snippet(Src, Start, End), - assert_info(Kind), - <<<<<<(cyan(<<" info"/utf8>>))/binary, ": "/utf8>>/binary, - (erlang:element(2, Error))/binary>>/binary, - "\n"/utf8>>] - ); - - {let_assert, Start@1, End@1, _, _, Value} -> - erlang:list_to_binary( - [<<<<<<(bold(red(<<"let assert"/utf8>>)))/binary, " "/utf8>>/binary, - Location/binary>>/binary, - "\n"/utf8>>, - <<<<<<<<<<(cyan(<<" test"/utf8>>))/binary, ": "/utf8>>/binary, - Module/binary>>/binary, - "."/utf8>>/binary, - Function/binary>>/binary, - "\n"/utf8>>, - code_snippet(Src, Start@1, End@1), - <<<<<<(cyan(<<"value"/utf8>>))/binary, ": "/utf8>>/binary, - (gleam@string:inspect(Value))/binary>>/binary, - "\n"/utf8>>, - <<<<<<(cyan(<<" info"/utf8>>))/binary, ": "/utf8>>/binary, - (erlang:element(2, Error))/binary>>/binary, - "\n"/utf8>>] - ) - end. - --file("src/gleeunit/internal/reporting.gleam", 71). -?DOC(false). --spec test_failed(state(), binary(), binary(), gleam@dynamic:dynamic_()) -> state(). -test_failed(State, Module, Function, Error) -> - Message = case gleeunit_gleam_panic_ffi:from_dynamic(Error) of - {ok, Error@1} -> - Src = gleam@option:from_result( - file:read_file(erlang:element(3, Error@1)) - ), - format_gleam_error(Error@1, Module, Function, Src); - - {error, _} -> - format_unknown(Module, Function, Error) - end, - gleam_stdlib:print(<<"\n"/utf8, Message/binary>>), - {state, - erlang:element(2, State), - erlang:element(3, State) + 1, - erlang:element(4, State)}. diff --git a/build/packages/gleeunit/src/gleeunit@should.erl b/build/packages/gleeunit/src/gleeunit@should.erl deleted file mode 100644 index 81048de..0000000 --- a/build/packages/gleeunit/src/gleeunit@should.erl +++ /dev/null @@ -1,153 +0,0 @@ --module(gleeunit@should). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). --define(FILEPATH, "src/gleeunit/should.gleam"). --export([equal/2, not_equal/2, be_ok/1, be_error/1, be_some/1, be_none/1, be_true/1, be_false/1, fail/0]). - --if(?OTP_RELEASE >= 27). --define(MODULEDOC(Str), -moduledoc(Str)). --define(DOC(Str), -doc(Str)). --else. --define(MODULEDOC(Str), -compile([])). --define(DOC(Str), -compile([])). --endif. - -?MODULEDOC(" Use the `assert` keyword instead of this module.\n"). - --file("src/gleeunit/should.gleam", 6). --spec equal(DOF, DOF) -> nil. -equal(A, B) -> - case A =:= B of - true -> - nil; - - _ -> - erlang:error(#{gleam_error => panic, - message => erlang:list_to_binary( - [<<"\n"/utf8>>, - gleam@string:inspect(A), - <<"\nshould equal\n"/utf8>>, - gleam@string:inspect(B)] - ), - file => <>, - module => <<"gleeunit/should"/utf8>>, - function => <<"equal"/utf8>>, - line => 10}) - end. - --file("src/gleeunit/should.gleam", 19). --spec not_equal(DOG, DOG) -> nil. -not_equal(A, B) -> - case A /= B of - true -> - nil; - - _ -> - erlang:error(#{gleam_error => panic, - message => erlang:list_to_binary( - [<<"\n"/utf8>>, - gleam@string:inspect(A), - <<"\nshould not equal\n"/utf8>>, - gleam@string:inspect(B)] - ), - file => <>, - module => <<"gleeunit/should"/utf8>>, - function => <<"not_equal"/utf8>>, - line => 23}) - end. - --file("src/gleeunit/should.gleam", 32). --spec be_ok({ok, DOH} | {error, any()}) -> DOH. -be_ok(A) -> - case A of - {ok, Value} -> - Value; - - _ -> - erlang:error(#{gleam_error => panic, - message => erlang:list_to_binary( - [<<"\n"/utf8>>, - gleam@string:inspect(A), - <<"\nshould be ok"/utf8>>] - ), - file => <>, - module => <<"gleeunit/should"/utf8>>, - function => <<"be_ok"/utf8>>, - line => 35}) - end. - --file("src/gleeunit/should.gleam", 39). --spec be_error({ok, any()} | {error, DOM}) -> DOM. -be_error(A) -> - case A of - {error, Error} -> - Error; - - _ -> - erlang:error(#{gleam_error => panic, - message => erlang:list_to_binary( - [<<"\n"/utf8>>, - gleam@string:inspect(A), - <<"\nshould be error"/utf8>>] - ), - file => <>, - module => <<"gleeunit/should"/utf8>>, - function => <<"be_error"/utf8>>, - line => 42}) - end. - --file("src/gleeunit/should.gleam", 46). --spec be_some(gleam@option:option(DOP)) -> DOP. -be_some(A) -> - case A of - {some, Value} -> - Value; - - _ -> - erlang:error(#{gleam_error => panic, - message => erlang:list_to_binary( - [<<"\n"/utf8>>, - gleam@string:inspect(A), - <<"\nshould be some"/utf8>>] - ), - file => <>, - module => <<"gleeunit/should"/utf8>>, - function => <<"be_some"/utf8>>, - line => 49}) - end. - --file("src/gleeunit/should.gleam", 53). --spec be_none(gleam@option:option(any())) -> nil. -be_none(A) -> - case A of - none -> - nil; - - _ -> - erlang:error(#{gleam_error => panic, - message => erlang:list_to_binary( - [<<"\n"/utf8>>, - gleam@string:inspect(A), - <<"\nshould be none"/utf8>>] - ), - file => <>, - module => <<"gleeunit/should"/utf8>>, - function => <<"be_none"/utf8>>, - line => 56}) - end. - --file("src/gleeunit/should.gleam", 60). --spec be_true(boolean()) -> nil. -be_true(Actual) -> - _pipe = Actual, - equal(_pipe, true). - --file("src/gleeunit/should.gleam", 65). --spec be_false(boolean()) -> nil. -be_false(Actual) -> - _pipe = Actual, - equal(_pipe, false). - --file("src/gleeunit/should.gleam", 70). --spec fail() -> nil. -fail() -> - be_true(false). diff --git a/build/packages/gleeunit/src/gleeunit_ffi.erl b/build/packages/gleeunit/src/gleeunit_ffi.erl deleted file mode 100644 index 05c7490..0000000 --- a/build/packages/gleeunit/src/gleeunit_ffi.erl +++ /dev/null @@ -1,21 +0,0 @@ --module(gleeunit_ffi). - --export([find_files/2, run_eunit/2]). - -find_files(Pattern, In) -> - Results = filelib:wildcard(binary_to_list(Pattern), binary_to_list(In)), - lists:map(fun list_to_binary/1, Results). - -run_eunit(Tests, Options) -> - case code:which(eunit) of - non_existing -> - gleeunit@internal@reporting:eunit_missing(); - - _ -> - case eunit:test(Tests, Options) of - ok -> {ok, nil}; - error -> {error, nil}; - {error, Term} -> {error, Term} - end - end. - diff --git a/build/packages/gleeunit/src/gleeunit_ffi.mjs b/build/packages/gleeunit/src/gleeunit_ffi.mjs deleted file mode 100644 index 7bdc071..0000000 --- a/build/packages/gleeunit/src/gleeunit_ffi.mjs +++ /dev/null @@ -1,100 +0,0 @@ -import { readFileSync } from "node:fs"; -import { Result$Ok, Result$Error } from "./gleam.mjs"; -import * as reporting from "./gleeunit/internal/reporting.mjs"; - -export function read_file(path) { - try { - return Result$Ok(readFileSync(path)); - } catch { - return Result$Error(undefined); - } -} - -async function* gleamFiles(directory) { - for (let entry of await read_dir(directory)) { - let path = join_path(directory, entry); - if (path.endsWith(".gleam")) { - yield path; - } else { - try { - yield* gleamFiles(path); - } catch (error) { - // Could not read directory, assume it's a file - } - } - } -} - -async function readRootPackageName() { - let toml = await async_read_file("gleam.toml", "utf-8"); - for (let line of toml.split("\n")) { - let matches = line.match(/\s*name\s*=\s*"([a-z][a-z0-9_]*)"/); // Match regexp in compiler-cli/src/new.rs in validate_name() - if (matches) return matches[1]; - } - throw new Error("Could not determine package name from gleam.toml"); -} - -export async function main() { - let state = reporting.new_state(); - - let packageName = await readRootPackageName(); - let dist = `../${packageName}/`; - - for await (let path of await gleamFiles("test")) { - let js_path = path.slice("test/".length).replace(".gleam", ".mjs"); - let module = await import(join_path(dist, js_path)); - for (let fnName of Object.keys(module)) { - if (!fnName.endsWith("_test")) continue; - try { - await module[fnName](); - state = reporting.test_passed(state); - } catch (error) { - let moduleName = js_path.slice(0, -4); - state = reporting.test_failed(state, moduleName, fnName, error); - } - } - } - - const status = reporting.finished(state); - exit(status); -} - -export function crash(message) { - throw new Error(message); -} - -function exit(code) { - if (globalThis.Deno) { - Deno.exit(code); - } else { - process.exit(code); - } -} - -async function read_dir(path) { - if (globalThis.Deno) { - let items = []; - for await (let item of Deno.readDir(path, { withFileTypes: true })) { - items.push(item.name); - } - return items; - } else { - let { readdir } = await import("node:fs/promises"); - return readdir(path); - } -} - -function join_path(a, b) { - if (a.endsWith("/")) return a + b; - return a + "/" + b; -} - -async function async_read_file(path) { - if (globalThis.Deno) { - return Deno.readTextFile(path); - } else { - let { readFile } = await import("node:fs/promises"); - let contents = await readFile(path); - return contents.toString(); - } -} diff --git a/build/packages/gleeunit/src/gleeunit_progress.erl b/build/packages/gleeunit/src/gleeunit_progress.erl deleted file mode 100644 index e6576a5..0000000 --- a/build/packages/gleeunit/src/gleeunit_progress.erl +++ /dev/null @@ -1,72 +0,0 @@ -%% A formatter adapted from Sean Cribb's https://github.com/seancribbs/eunit_formatters - --module(gleeunit_progress). --define(NOTEST, true). - -%% eunit_listener callbacks --export([ - init/1, handle_begin/3, handle_end/3, handle_cancel/3, terminate/2, - start/0, start/1 -]). - --define(reporting, gleeunit@internal@reporting). - -start() -> - start([]). - -start(Options) -> - eunit_listener:start(?MODULE, Options). - -init(_Options) -> - ?reporting:new_state(). - -handle_begin(_test_or_group, _data, State) -> - State. - -handle_end(group, _data, State) -> - State; -handle_end(test, Data, State) -> - {AtomModule, AtomFunction, _Arity} = proplists:get_value(source, Data), - Module = erlang:atom_to_binary(AtomModule), - Function = erlang:atom_to_binary(AtomFunction), - - % EUnit swallows stdout, so print it to make debugging easier. - case proplists:get_value(output, Data) of - undefined -> ok; - <<>> -> ok; - Out -> gleam@io:print(Out) - end, - - case proplists:get_value(status, Data) of - ok -> - ?reporting:test_passed(State); - {skipped, _Reason} -> - ?reporting:test_skipped(State, Module, Function); - {error, {_, Exception, _Stack}} -> - ?reporting:test_failed(State, Module, Function, Exception) - end. - - -handle_cancel(_test_or_group, Data, State) -> - ?reporting:test_failed(State, <<"gleeunit">>, <<"main">>, Data). - -terminate({ok, _Data}, State) -> - ?reporting:finished(State), - ok; -terminate({error, Reason}, State) -> - ?reporting:finished(State), - io:fwrite(" -Eunit failed: - -~80p - -This is probably a bug in gleeunit. Please report it. -", [Reason]), - sync_end(error). - -sync_end(Result) -> - receive - {stop, Reference, ReplyTo} -> - ReplyTo ! {result, Reference, Result}, - ok - end. diff --git a/build/packages/packages.toml b/build/packages/packages.toml deleted file mode 100644 index 6098d78..0000000 --- a/build/packages/packages.toml +++ /dev/null @@ -1,7 +0,0 @@ -[packages] -gleam_stdlib = "0.65.0" -gleam_community_colour = "2.0.2" -gleam_json = "3.1.0" -gleeunit = "1.9.0" -paint = "1.0.0" -gleam_time = "1.6.0" diff --git a/build/packages/paint/LICENSE.txt b/build/packages/paint/LICENSE.txt deleted file mode 100644 index 40cce2a..0000000 --- a/build/packages/paint/LICENSE.txt +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2025 Eli Adelhult - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/build/packages/paint/README.md b/build/packages/paint/README.md deleted file mode 100644 index d762383..0000000 --- a/build/packages/paint/README.md +++ /dev/null @@ -1,34 +0,0 @@ -# Paint -**Make 2D drawings, animations, and games using Gleam and the HTML Canvas!** - -[![Package Version](https://img.shields.io/hexpm/v/paint)](https://hex.pm/packages/paint) -[![Hex Docs](https://img.shields.io/badge/hex-docs-ffaff3)](https://hexdocs.pm/paint/) - -Paint is a tiny embedded domain specific language (inspired by [Gloss](https://hackage.haskell.org/package/gloss)). -Make pictures out of basic shapes then style, transform, and combine them using the provided functions. - -![Frame 3(2)](https://github.com/user-attachments/assets/a8b83b58-990a-432a-9034-deebc4d210a6) - -```gleam -import paint as p -import paint/canvas - -fn main() { - let my_picture = p.combine([ - p.circle(30.0), - p.circle(20.0) |> p.fill(p.colour_rgb(0, 200, 200)), - p.rectangle(50.0, 30.0) |> p.rotate(p.angle_deg(30.0)), - p.text("Hello world", 10) |> p.translate_y(-35.0), - ]) - - canvas.display(fn(_: canvas.Config) { my_picture }, "#canvas_id") -} -``` - -**Want to learn more? Read the [docs](https://hexdocs.pm/paint) or browse the [visual examples](https://adelhult.github.io/paint/).** - -## Logo -Lucy is borrowed from the [Gleam branding page](https://gleam.run/branding/) and the brush is made by [Delapouite (game icons)](https://game-icons.net/1x1/delapouite/paint-brush.html). - -## Changelog -API additions and breaking changes can be found in the file `CHANGELOG.md`. diff --git a/build/packages/paint/gleam.toml b/build/packages/paint/gleam.toml deleted file mode 100644 index d912cdd..0000000 --- a/build/packages/paint/gleam.toml +++ /dev/null @@ -1,23 +0,0 @@ -name = "paint" -version = "1.0.0" -target = "javascript" - -# Fill out these fields if you intend to generate HTML documentation or publish -# your project to the Hex package manager. -# -description = "Make 2D drawings, animations, and games (HTML Canvas)" -licences = ["MIT"] -repository = { type = "github", user = "adelhult", repo = "paint" } -links = [ - { title = "Visual examples", href = "https://adelhult.github.io/paint/" }, -] -dev-dependencies = { gleeunit = ">= 1.6.1 and < 2.0.0" } -# -# For a full reference of all the available options, you can have a look at -# https://gleam.run/writing-gleam/gleam-toml/. - - -[dependencies] -gleam_stdlib = ">= 0.58.0 and < 2.0.0" -gleam_community_colour = ">= 2.0.0 and < 3.0.0" -gleam_json = ">= 3.0.2 and < 4.0.0" diff --git a/build/packages/paint/src/impl_canvas_bindings.mjs b/build/packages/paint/src/impl_canvas_bindings.mjs deleted file mode 100644 index 5fed16a..0000000 --- a/build/packages/paint/src/impl_canvas_bindings.mjs +++ /dev/null @@ -1,271 +0,0 @@ -import { Ok, Error } from "./gleam.mjs"; - -class PaintCanvas extends HTMLElement { - // Open an issue if you are in need of any other attributes :) - static observedAttributes = ["width", "height", "style", "picture"]; - - constructor() { - super(); - // Create a canvas - this.canvas = document.createElement("canvas"); - const style = document.createElement("style"); - style.textContent = ` - :host { - display: inline-block; - } - `; - this.shadow = this.attachShadow({ mode: "open" }); - this.shadow.appendChild(style); - this.shadow.appendChild(this.canvas); - this.ctx = this.canvas.getContext("2d"); - } - - attributeChangedCallback(name, _oldValue, newValue) { - if (name === "picture") { - this.picture = newValue; - return; - } else if (name === "width") { - this.width = newValue; - } else if (name === "height") { - this.height = newValue; - } - } - - drawPicture() { - if (!this.pictureString) { - return; - } - - this.ctx.reset(); - const display = - window.PAINT_STATE[ - "display_on_rendering_context_with_default_drawing_state" - ]; - - display(this.pictureString, this.ctx); - } - - set picture(value) { - this.pictureString = value; - this.drawPicture(); - } - - set width(value) { - this.canvas.width = value; - this.drawPicture(); - } - - set height(value) { - this.canvas.height = value; - this.drawPicture(); - } - - get width() { - return this.canvas.width; - } - - get height() { - return this.canvas.height; - } -} - -export function define_web_component() { - window.customElements.define("paint-canvas", PaintCanvas); -} - -export function get_rendering_context(selector) { - // TODO: Handle the case where the canvas element is not found. - return document.querySelector(selector).getContext("2d"); -} - -export function setup_request_animation_frame(callback) { - window.requestAnimationFrame((time) => { - callback(time); - }); -} - -export function setup_input_handler(event_name, callback) { - window.addEventListener(event_name, callback); -} - -export function get_key_code(event) { - return event.keyCode; -} - -export function set_global(state, id) { - if (typeof window.PAINT_STATE == "undefined") { - window.PAINT_STATE = {}; - } - window.PAINT_STATE[id] = state; -} - -export function get_global(id) { - if (!window.PAINT_STATE) { - return new Error(undefined); - } - if (!(id in window.PAINT_STATE)) { - return new Error(undefined); - } - return new Ok(window.PAINT_STATE[id]); -} - -export function get_width(ctx) { - return ctx.canvas.clientWidth; -} - -export function get_height(ctx) { - return ctx.canvas.clientHeight; -} - -// Based on https://stackoverflow.com/questions/17130395/real-mouse-position-in-canvas -export function mouse_pos(ctx, event) { - // Calculate the scaling of the canvas vs its content - const rect = ctx.canvas.getBoundingClientRect(); - const scaleX = ctx.canvas.width / rect.width; - const scaleY = ctx.canvas.height / rect.height; - - return [ - (event.clientX - rect.left) * scaleX, - (event.clientY - rect.top) * scaleY, - ]; -} - -// if check_pressed is true, the function will return true if the button was pressed -// if check_pressed is false, the function will return true if the button was released -export function check_mouse_button( - event, - previous_event, - button_index, - check_pressed, -) { - let previous_buttons = previous_event?.buttons ?? 0; - let current_buttons = event.buttons; - - // ~001 && - // 011 - // ----- - // 010 found the newly pressed! - // - // 011 && - // ~001 - // ----- - // 010 found the newly released! - if (check_pressed) { - previous_buttons = ~previous_buttons; - } else { - current_buttons = ~current_buttons; - } - - let button = previous_buttons & current_buttons & (1 << button_index); - return !!button; -} - -export function reset(ctx) { - ctx.reset(); -} - -export function arc(ctx, radius, start, end, fill, stroke) { - ctx.beginPath(); - ctx.arc(0, 0, radius, start, end); - if (fill) { - ctx.fill(); - } - if (stroke) { - ctx.stroke(); - } -} - -export function polygon(ctx, points, closed, fill, stroke) { - ctx.beginPath(); - ctx.moveTo(0, 0); - let started = false; - for (const point of points) { - let x = point[0]; - let y = point[1]; - if (started) { - ctx.lineTo(x, y); - } else { - ctx.moveTo(x, y); - started = true; - } - } - - if (closed) { - ctx.closePath(); - } - - if (fill && closed) { - ctx.fill(); - } - - if (stroke) { - ctx.stroke(); - } -} - -export function text(ctx, text, style) { - ctx.font = style; - ctx.fillText(text, 0, 0); -} - -export function save(ctx) { - ctx.save(); -} - -export function restore(ctx) { - ctx.restore(); -} - -export function set_fill_colour(ctx, css_colour) { - ctx.fillStyle = css_colour; -} - -export function set_stroke_color(ctx, css_color) { - ctx.strokeStyle = css_color; -} - -export function set_line_width(ctx, width) { - ctx.lineWidth = width; -} - -export function translate(ctx, x, y) { - ctx.translate(x, y); -} - -export function scale(ctx, x, y) { - ctx.scale(x, y); -} - -export function rotate(ctx, radians) { - ctx.rotate(radians); -} - -export function reset_transform(ctx) { - ctx.resetTransform(); -} - -export function draw_image(ctx, image, width_px, height_px) { - ctx.drawImage(image, 0, 0, width_px, height_px); -} - -export function image_from_query(selector) { - return document.querySelector(selector); -} - -export function image_from_src(src) { - const image = new Image(); - image.src = src; - return image; -} - -export function on_image_load(image, callback) { - if (image.complete) { - callback(); - } else { - image.addEventListener("load", callback); - } -} - -export function set_image_smoothing_enabled(ctx, value) { - ctx.imageSmoothingEnabled = value; -} diff --git a/build/packages/paint/src/numbers_ffi.mjs b/build/packages/paint/src/numbers_ffi.mjs deleted file mode 100644 index 0e6e6d3..0000000 --- a/build/packages/paint/src/numbers_ffi.mjs +++ /dev/null @@ -1,3 +0,0 @@ -export function pi() { - return Math.PI; -} diff --git a/build/packages/paint/src/paint.gleam b/build/packages/paint/src/paint.gleam deleted file mode 100644 index 6729228..0000000 --- a/build/packages/paint/src/paint.gleam +++ /dev/null @@ -1,201 +0,0 @@ -//// This module contains the main `Picture` type as well as the -//// function you can use to construct, modify and combine pictures. - -import gleam/result -import gleam_community/colour -import paint/internal/types as internal_implementation - -/// A 2D picture. This is the type which this entire library revolves around. -/// -///> [!NOTE] -///> Unless you intend to author a new backend you should **consider this type opaque and never use any of its constructors**. -///> Instead, make use of the many utility functions defined in this module (`circle`, `combine`, `fill`, etc.) -pub type Picture = - internal_implementation.Picture - -/// A reference to an image (i.e. a texture), not to be confused with the `Picture` type. -/// To create an image, see the image functions in the `canvas` back-end. -pub type Image = - internal_implementation.Image - -/// An angle in clock-wise direction. -/// See: `angle_rad` and `angle_deg`. -pub type Angle = - internal_implementation.Angle - -/// Create an angle expressed in radians -pub fn angle_rad(radians: Float) -> Angle { - internal_implementation.Radians(radians) -} - -/// Create an angle expressed in degrees -pub fn angle_deg(degrees: Float) -> Angle { - internal_implementation.Radians(degrees *. pi() /. 180.0) -} - -/// A rexport of the Colour type from [gleam_community/colour](https://hexdocs.pm/gleam_community_colour/). -/// Paint also includes the functions `colour_hex` and `colour_rgb` to -/// easily construct Colours, but feel free to import the `gleam_community/colour` module -/// and use the many utility that are provided from there. -pub type Colour = - colour.Colour - -/// A utility around [colour.from_rgb_hex_string](https://hexdocs.pm/gleam_community_colour/gleam_community/colour.html#from_rgb_hex_string) -/// (from `gleam_community/colour`) that **panics** on an invalid hex code. -pub fn colour_hex(string: String) -> Colour { - result.lazy_unwrap(colour.from_rgb_hex_string(string), fn() { - panic as "Failed to parse hex code" - }) -} - -/// A utility around [colour.from_rgb255](https://hexdocs.pm/gleam_community_colour/gleam_community/colour.html#from_rgb255) -/// (from `gleam_community/colour`) that **panics** if the values are outside of the allowed range. -pub fn colour_rgb(red: Int, green: Int, blue: Int) -> Colour { - result.lazy_unwrap(colour.from_rgb255(red, green, blue), fn() { - panic as "The value was not inside of the valid range [0-255]" - }) -} - -pub type Vec2 = - #(Float, Float) - -/// A blank picture -pub fn blank() -> Picture { - internal_implementation.Blank -} - -/// A circle with some given radius -pub fn circle(radius: Float) -> Picture { - internal_implementation.Arc( - radius, - start: internal_implementation.Radians(0.0), - end: internal_implementation.Radians(2.0 *. pi()), - ) -} - -/// An arc with some radius going from some -/// starting angle to some other angle in clock-wise direction -pub fn arc(radius: Float, start: Angle, end: Angle) -> Picture { - internal_implementation.Arc(radius, start: start, end: end) -} - -/// A polygon consisting of a list of 2d points -pub fn polygon(points: List(#(Float, Float))) -> Picture { - internal_implementation.Polygon(points, True) -} - -/// Lines (same as a polygon but not a closed shape) -pub fn lines(points: List(#(Float, Float))) -> Picture { - internal_implementation.Polygon(points, False) -} - -/// A rectangle with some given width and height -pub fn rectangle(width: Float, height: Float) -> Picture { - polygon([#(0.0, 0.0), #(width, 0.0), #(width, height), #(0.0, height)]) -} - -/// A square -pub fn square(length: Float) -> Picture { - rectangle(length, length) -} - -/// Draw an image such as a PNG, JPEG or an SVG. See the `canvas` back-end for more details on how to load images. -pub fn image(image: Image, width_px width_px, height_px height_px) -> Picture { - // TODO: add a function that allows us to draw only part of an image, flip, and if we want smooth scaling or not - internal_implementation.ImageRef(image, width_px:, height_px:) -} - -/// Set image scaling to be smooth (this is the default behaviour) -pub fn image_scaling_smooth(picture: Picture) -> Picture { - internal_implementation.ImageScalingBehaviour( - picture, - internal_implementation.ScalingSmooth, - ) -} - -/// Disable smooth image scaling, suitable for pixel art. -pub fn image_scaling_pixelated(picture: Picture) -> Picture { - internal_implementation.ImageScalingBehaviour( - picture, - internal_implementation.ScalingPixelated, - ) -} - -/// Text with some given font size -pub fn text(text: String, px font_size: Int) -> Picture { - internal_implementation.Text( - text, - style: internal_implementation.FontProperties(font_size, "sans-serif"), - ) - // TODO: expose more styling options (font and text alignment) -} - -/// Translate a picture in horizontal and vertical direction -pub fn translate_xy(picture: Picture, x: Float, y: Float) -> Picture { - internal_implementation.Translate(picture, #(x, y)) -} - -/// Translate a picture in the horizontal direction -pub fn translate_x(picture: Picture, x: Float) -> Picture { - translate_xy(picture, x, 0.0) -} - -/// Translate a picture in the vertical direction -pub fn translate_y(picture: Picture, y: Float) -> Picture { - translate_xy(picture, 0.0, y) -} - -/// Scale the picture in the horizontal direction -pub fn scale_x(picture: Picture, factor: Float) -> Picture { - internal_implementation.Scale(picture, #(factor, 1.0)) -} - -/// Scale the picture in the vertical direction -pub fn scale_y(picture: Picture, factor: Float) -> Picture { - internal_implementation.Scale(picture, #(1.0, factor)) -} - -/// Scale the picture uniformly in horizontal and vertical direction -pub fn scale_uniform(picture: Picture, factor: Float) -> Picture { - internal_implementation.Scale(picture, #(factor, factor)) -} - -/// Rotate the picture in a clock-wise direction -pub fn rotate(picture: Picture, angle: Angle) -> Picture { - internal_implementation.Rotate(picture, angle) -} - -/// Fill a picture with some given colour, see `Colour`. -pub fn fill(picture: Picture, colour: Colour) -> Picture { - internal_implementation.Fill(picture, colour) -} - -/// Set a solid stroke with some given colour and width -pub fn stroke(picture: Picture, colour: Colour, width width: Float) -> Picture { - internal_implementation.Stroke( - picture, - internal_implementation.SolidStroke(colour, width), - ) -} - -/// Remove the stroke of the given picture -pub fn stroke_none(picture: Picture) -> Picture { - internal_implementation.Stroke(picture, internal_implementation.NoStroke) -} - -/// Concatenate two pictures -pub fn concat(picture: Picture, another_picture: Picture) -> Picture { - combine([picture, another_picture]) -} - -/// Combine multiple pictures into one -pub fn combine(pictures: List(Picture)) -> Picture { - internal_implementation.Combine(pictures) -} - -// Internal utility function to get Pi π -@external(erlang, "math", "pi") -@external(javascript, "./numbers_ffi.mjs", "pi") -fn pi() -> Float { - 3.1415926 -} diff --git a/build/packages/paint/src/paint/canvas.gleam b/build/packages/paint/src/paint/canvas.gleam deleted file mode 100644 index 061c102..0000000 --- a/build/packages/paint/src/paint/canvas.gleam +++ /dev/null @@ -1,461 +0,0 @@ -//// A HTML canvas backend that can be used for displaying -//// your `Picture`s. There are three different ways of doing so: -//// - `display` (provide a picture and a CSS selector to some canvas element) -//// - `define_web_component` (an alternative to `display` using custom web components, useful if you are using a web framework like Lustre) -//// - `interact` (allows you to make animations and interactive programs) - -import gleam/int -import gleam/option.{type Option, None, Some} -import gleam_community/colour -import paint.{translate_xy} -import paint/encode -import paint/event.{type Event} -import paint/internal/impl_canvas -import paint/internal/types.{ - type Image, type Picture, Arc, Blank, Combine, Fill, FontProperties, Image, - NoStroke, Polygon, Radians, Rotate, Scale, SolidStroke, Stroke, Text, - Translate, -} - -/// The configuration of the "canvas" -pub type Config { - Config(width: Float, height: Float) -} - -/// Create a reference to an image using a CSS query selector. For example: -/// ``` -/// fn kitten() { -/// canvas.image_from_query("#kitten") -/// } -/// // In the HTML file: -/// // -/// ``` -/// -/// > [!WARNING] -/// > **Important**: Make sure the image has loaded before trying to draw a pictures referencing it. -/// > You can do this using `canvas.wait_until_loaded` function. -pub fn image_from_query(selector: String) -> Image { - let id = "image-selector-" <> selector - case impl_canvas.get_global(id) { - // Re-use the cached image if we can - Ok(_) -> { - Nil - } - Error(Nil) -> { - let image = impl_canvas.image_from_query(selector) - impl_canvas.set_global(image, id) - } - } - Image(id) -} - -/// Create a reference to an image using a source path. -/// ``` -/// fn my_logo_image() { -/// canvas.image_from_src("./priv/static/logo.svg") -/// } -/// ``` -/// -/// > [!WARNING] -/// > **Important**: Make sure the image has loaded before trying to draw a pictures referencing it. -/// > You can do this using `canvas.wait_until_loaded` function. -pub fn image_from_src(src: String) -> Image { - let id = "image-src-" <> src - case impl_canvas.get_global(id) { - // Re-use the cached image if we can - Ok(_) -> { - Nil - } - Error(Nil) -> { - let image = impl_canvas.image_from_src(src) - impl_canvas.set_global(image, id) - } - } - Image(id) -} - -/// Wait until a list of images have all been loaded, for example: -/// ``` -/// fn lucy() { -/// canvas.image_from_query("#lucy") -/// } -/// -/// fn cat() { -/// canvas.image_from_src("./path/to/kitten.png") -/// } -/// -/// pub fn main() { -/// use <- canvas.wait_until_loaded([lucy(), kitten()]) -/// // It is now safe to draw Pictures containing the images lucy and kitten :) -/// } -/// ``` -pub fn wait_until_loaded(images: List(Image), on_loaded: fn() -> Nil) -> Nil { - case images { - [] -> on_loaded() - [image, ..rest] -> { - let Image(id:) = image - let assert Ok(js_image) = impl_canvas.get_global(id) - impl_canvas.on_image_load(js_image, fn() { - wait_until_loaded(rest, on_loaded) - }) - } - } -} - -/// Display a picture on a HTML canvas element -/// (specified by some [CSS Selector](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_selectors)). -/// ``` -/// canvas.display(fn (_: canvas.Config) { circle(50.0) }, "#mycanvas") -/// ``` -pub fn display(init: fn(Config) -> Picture, selector: String) { - let ctx = impl_canvas.get_rendering_context(selector) - impl_canvas.reset(ctx) - let picture = - init(Config(impl_canvas.get_width(ctx), impl_canvas.get_height(ctx))) - display_on_rendering_context(picture, ctx, default_drawing_state) -} - -/// Additional state used when drawing -/// (note that the fill and stroke color as well as the stroke width -/// is stored inside of the context) -type DrawingState { - DrawingState(fill: Bool, stroke: Bool) -} - -const default_drawing_state = DrawingState(fill: False, stroke: True) - -fn display_on_rendering_context( - picture: Picture, - ctx: impl_canvas.RenderingContext2D, - state: DrawingState, -) { - case picture { - Blank -> Nil - - Text(text, properties) -> { - let FontProperties(size_px, font_family) = properties - impl_canvas.save(ctx) - impl_canvas.text( - ctx, - text, - int.to_string(size_px) <> "px " <> font_family, - ) - impl_canvas.restore(ctx) - } - - Polygon(points, closed) -> { - impl_canvas.polygon(ctx, points, closed, state.fill, state.stroke) - } - - Arc(radius, start, end) -> { - let Radians(start_radians) = start - let Radians(end_radians) = end - impl_canvas.arc( - ctx, - radius, - start_radians, - end_radians, - state.fill, - state.stroke, - ) - } - - Fill(p, colour) -> { - impl_canvas.save(ctx) - impl_canvas.set_fill_colour(ctx, colour.to_css_rgba_string(colour)) - display_on_rendering_context(p, ctx, DrawingState(..state, fill: True)) - impl_canvas.restore(ctx) - } - - Stroke(p, stroke) -> { - case stroke { - NoStroke -> - display_on_rendering_context( - p, - ctx, - DrawingState(..state, stroke: False), - ) - SolidStroke(color, width) -> { - impl_canvas.save(ctx) - impl_canvas.set_stroke_color(ctx, colour.to_css_rgba_string(color)) - impl_canvas.set_line_width(ctx, width) - display_on_rendering_context( - p, - ctx, - DrawingState(..state, stroke: True), - ) - impl_canvas.restore(ctx) - } - } - } - - Translate(p, vec) -> { - let #(x, y) = vec - impl_canvas.save(ctx) - impl_canvas.translate(ctx, x, y) - display_on_rendering_context(p, ctx, state) - impl_canvas.restore(ctx) - } - - Scale(p, vec) -> { - let #(x, y) = vec - impl_canvas.save(ctx) - impl_canvas.scale(ctx, x, y) - display_on_rendering_context(p, ctx, state) - impl_canvas.restore(ctx) - } - - Rotate(p, angle) -> { - let Radians(rad) = angle - impl_canvas.save(ctx) - impl_canvas.rotate(ctx, rad) - display_on_rendering_context(p, ctx, state) - impl_canvas.restore(ctx) - } - - Combine(pictures) -> { - case pictures { - [] -> Nil - [p, ..ps] -> { - display_on_rendering_context(p, ctx, state) - display_on_rendering_context(Combine(ps), ctx, state) - } - } - } - types.ImageRef(Image(id:), width_px:, height_px:) -> { - // TODO: log an error if this fails? - let assert Ok(image) = impl_canvas.get_global(id) - impl_canvas.draw_image(ctx, image, width_px, height_px) - } - types.ImageScalingBehaviour(p, behaviour) -> { - impl_canvas.save(ctx) - impl_canvas.set_image_smoothing_enabled(ctx, case behaviour { - types.ScalingPixelated -> False - types.ScalingSmooth -> True - }) - display_on_rendering_context(p, ctx, state) - impl_canvas.restore(ctx) - } - } -} - -/// Animations, interactive applications and tiny games can be built using the -/// `interact` function. It roughly follows the [Elm architecture](https://guide.elm-lang.org/architecture/). -/// Here is a short example: -/// ``` -/// type State = -/// Int -/// -/// fn init(_: canvas.Config) -> State { -/// 0 -/// } -/// -/// fn update(state: State, event: event.Event) -> State { -/// case event { -/// event.Tick(_) -> state + 1 -/// _ -> state -/// } -/// } -/// -/// fn view(state: State) -> Picture { -/// paint.circle(int.to_float(state)) -/// } -/// -/// fn main() { -/// interact(init, update, view, "#mycanvas") -/// } -/// ``` -pub fn interact( - init: fn(Config) -> state, - update: fn(state, Event) -> state, - view: fn(state) -> Picture, - selector: String, -) { - let ctx = impl_canvas.get_rendering_context(selector) - let initial_state = - init(Config(impl_canvas.get_width(ctx), impl_canvas.get_height(ctx))) - - impl_canvas.set_global(initial_state, selector) - - // Handle keyboard input - let create_key_handler = fn(event_name, constructor) { - impl_canvas.setup_input_handler( - event_name, - fn(event: impl_canvas.KeyboardEvent) { - let key = parse_key_code(impl_canvas.get_key_code(event)) - case key { - Some(key) -> { - let assert Ok(old_state) = impl_canvas.get_global(selector) - let new_state = update(old_state, constructor(key)) - impl_canvas.set_global(new_state, selector) - } - None -> Nil - } - }, - ) - } - create_key_handler("keydown", event.KeyboardPressed) - create_key_handler("keyup", event.KeyboardRelased) - - // Handle mouse movement - impl_canvas.setup_input_handler( - "mousemove", - fn(event: impl_canvas.MouseEvent) { - let #(x, y) = impl_canvas.mouse_pos(ctx, event) - let assert Ok(old_state) = impl_canvas.get_global(selector) - let new_state = update(old_state, event.MouseMoved(x, y)) - impl_canvas.set_global(new_state, selector) - Nil - }, - ) - - // Handle mouse buttons - let create_mouse_button_handler = fn(event_name, constructor, check_pressed) { - impl_canvas.setup_input_handler( - event_name, - fn(event: impl_canvas.MouseEvent) { - // Read the previous state of the mouse - let previous_event_id = "PAINT_PREVIOUS_MOUSE_INPUT_FOR_" <> selector - let previous_event = impl_canvas.get_global(previous_event_id) - // Save this state - impl_canvas.set_global(event, previous_event_id) - - // A utility to check which buttons was just pressed/released - let check_button = fn(i) { - impl_canvas.check_mouse_button( - event, - previous_event, - i, - check_pressed, - ) - } - - let trigger_update = fn(button) { - let assert Ok(old_state) = impl_canvas.get_global(selector) - let new_state = update(old_state, constructor(button)) - impl_canvas.set_global(new_state, selector) - } - - // Note: it is rather rare, but it seems that multiple buttons - // can be pressed in the very same MouseEvent, so we may need to - // trigger multiple events at once. - case check_button(0) { - True -> trigger_update(event.MouseButtonLeft) - False -> Nil - } - case check_button(1) { - True -> trigger_update(event.MouseButtonRight) - False -> Nil - } - case check_button(2) { - True -> trigger_update(event.MouseButtonMiddle) - False -> Nil - } - - Nil - }, - ) - } - create_mouse_button_handler("mousedown", event.MousePressed, True) - create_mouse_button_handler("mouseup", event.MouseReleased, False) - - impl_canvas.setup_request_animation_frame(get_tick_func( - ctx, - view, - update, - selector, - )) -} - -fn parse_key_code(key_code: Int) -> Option(event.Key) { - case key_code { - 32 -> Some(event.KeySpace) - 37 -> Some(event.KeyLeftArrow) - 38 -> Some(event.KeyUpArrow) - 39 -> Some(event.KeyRightArrow) - 40 -> Some(event.KeyDownArrow) - 87 -> Some(event.KeyW) - 65 -> Some(event.KeyA) - 83 -> Some(event.KeyS) - 68 -> Some(event.KeyD) - 90 -> Some(event.KeyZ) - 88 -> Some(event.KeyX) - 67 -> Some(event.KeyC) - 18 -> Some(event.KeyEnter) - 27 -> Some(event.KeyEscape) - 8 -> Some(event.KeyBackspace) - _ -> None - } -} - -// Gleam does not have recursive let bindings, so I need -// to do this workaround... -fn get_tick_func(ctx, view, update, selector) { - fn(time) { - let assert Ok(current_state) = impl_canvas.get_global(selector) - - // Trigger a tick event before drawing - let new_state = update(current_state, event.Tick(time)) - impl_canvas.set_global(new_state, selector) - - // Create the picture - let picture = view(new_state) - - // Render the picture on the canvas - impl_canvas.reset(ctx) - display_on_rendering_context(picture, ctx, default_drawing_state) - impl_canvas.setup_request_animation_frame( - // call myself - get_tick_func(ctx, view, update, selector), - ) - } -} - -/// If you are using [Lustre](https://github.com/lustre-labs/lustre) or some other framework to build -/// your web application you may prefer to use the [web components](https://developer.mozilla.org/en-US/docs/Web/API/Web_components) API -/// and the `define_web_component` function. -/// ``` -/// // Call this function once to register a custom HTML element -/// canvas.define_web_component() -/// // You can then display your picture by setting the "picture" -/// // property or attribute on the element. -/// -/// // In Lustre it would look something like this: -/// fn canvas(picture: paint.Picture, attributes: List(attribute.Attribute(a))) { -/// element.element( -/// "paint-canvas", -/// [attribute.attribute("picture", encode.to_string(picture)), ..attributes], -/// [], -/// ) -///} -/// ``` -/// A more detailed example for using this API can be found in the `demos/with_lustre` directory. -pub fn define_web_component() -> Nil { - impl_canvas.define_web_component() - // somewhat of an ugly hack, but the setter for the web component will need to call this - // when the picture property changes. Therefore we - // bind this function to the window object so we can access it from the JS side of things. - // - // However, we should be careful of changing this. It is not part of the public API but it seems like - // [Tiramisu](https://hexdocs.pm/tiramisu/index.html) might makes use of it. - impl_canvas.set_global( - fn(encoded_picture, ctx) { - let assert Ok(picture) = encode.from_string(encoded_picture) - as "Invalid picture provided to web component" - display_on_rendering_context(picture, ctx, default_drawing_state) - }, - "display_on_rendering_context_with_default_drawing_state", - ) -} - -/// Utility to set the origin in the center of the canvas -pub fn center(picture: Picture) -> fn(Config) -> Picture { - fn(config) { - let Config(width, height) = config - picture |> translate_xy(width *. 0.5, height *. 0.5) - } -} diff --git a/build/packages/paint/src/paint/encode.gleam b/build/packages/paint/src/paint/encode.gleam deleted file mode 100644 index 96aea01..0000000 --- a/build/packages/paint/src/paint/encode.gleam +++ /dev/null @@ -1,260 +0,0 @@ -import gleam/dynamic/decode.{type Decoder} -import gleam/json.{type Json} -import gleam_community/colour -import paint.{type Picture} -import paint/internal/types.{ - type Angle, type FontProperties, type StrokeProperties, FontProperties, - NoStroke, Radians, SolidStroke, -} - -/// Serialize a `Picture` to a string. -/// -/// Note, serializing an `Image` texture will only store an ID referencing the image. This means that if you deserialize a Picture containing -/// references to images, you are responsible for making sure all images are loaded before drawing the picture. -/// More advanced APIs to support use cases such as these are planned for a future release. -/// -/// Also, if you wish to store the serialized data, remember that the library currently makes no stability guarantee that -/// the data can be deserialized by *future* versions of the library. -pub fn to_string(picture: Picture) -> String { - let version = "paint:unstable" - json.object([ - #("version", json.string(version)), - #("picture", picture_to_json(picture)), - ]) - |> json.to_string -} - -/// Attempt to deserialize a `Picture` -pub fn from_string(string: String) { - let decoder = { - use picture <- decode.field("picture", decode_picture()) - decode.success(picture) - } - json.parse(string, decoder) -} - -fn decode_angle() { - use radians <- decode.field("radians", decode.float) - decode.success(Radians(radians)) -} - -fn decode_picture() -> Decoder(Picture) { - use <- decode.recursive - use ty <- decode.field("type", decode.string) - - case ty { - "arc" -> { - use radius <- decode.field("radius", decode.float) - use start <- decode.field("start", decode_angle()) - use end <- decode.field("end", decode_angle()) - decode.success(types.Arc(radius, start:, end:)) - } - "blank" -> decode.success(types.Blank) - "combine" -> { - use pictures <- decode.field( - "pictures", - decode.list(of: decode_picture()), - ) - decode.success(types.Combine(pictures)) - } - "fill" -> { - use picture <- decode.field("picture", decode_picture()) - use colour <- decode.field("colour", colour.decoder()) - decode.success(types.Fill(picture, colour)) - } - "polygon" -> { - use points <- decode.field("points", decode.list(of: decode_vec2())) - use closed <- decode.field("closed", decode.bool) - decode.success(types.Polygon(points, closed)) - } - "rotate" -> { - use angle <- decode.field("angle", decode_angle()) - use picture <- decode.field("picture", decode_picture()) - decode.success(types.Rotate(picture, angle)) - } - "scale" -> { - use x <- decode.field("x", decode.float) - use y <- decode.field("y", decode.float) - use picture <- decode.field("picture", decode_picture()) - decode.success(types.Scale(picture, #(x, y))) - } - "stroke" -> { - use stroke <- decode.field("stroke", decode_stroke()) - use picture <- decode.field("picture", decode_picture()) - decode.success(types.Stroke(picture, stroke)) - } - "text" -> { - use text <- decode.field("text", decode.string) - use style <- decode.field("style", decode_font()) - decode.success(types.Text(text, style)) - } - "translate" -> { - use x <- decode.field("x", decode.float) - use y <- decode.field("y", decode.float) - use picture <- decode.field("picture", decode_picture()) - decode.success(types.Translate(picture, #(x, y))) - } - "image" -> { - use id <- decode.field("id", decode.string) - use width_px <- decode.field("width_px", decode.int) - use height_px <- decode.field("height_px", decode.int) - decode.success(types.ImageRef(types.Image(id:), width_px:, height_px:)) - } - "image_scaling_behaviour" -> { - use behaviour <- decode.field("behaviour", decode.string) - use picture <- decode.field("picture", decode_picture()) - case behaviour { - "smooth" -> - decode.success(types.ImageScalingBehaviour( - picture, - types.ScalingSmooth, - )) - "pixelated" -> - decode.success(types.ImageScalingBehaviour( - picture, - types.ScalingPixelated, - )) - _ -> decode.failure(types.Blank, "Picture") - } - } - _ -> decode.failure(types.Blank, "Picture") - } -} - -fn decode_font() -> Decoder(FontProperties) { - use size_px <- decode.field("sizePx", decode.int) - use font_family <- decode.field("fontFamily", decode.string) - decode.success(FontProperties(size_px:, font_family:)) -} - -fn decode_stroke() -> Decoder(StrokeProperties) { - use stroke_type <- decode.field("type", decode.string) - case stroke_type { - "noStroke" -> decode.success(NoStroke) - "solidStroke" -> { - use colour <- decode.field("colour", colour.decoder()) - use thickness <- decode.field("thickness", decode.float) - decode.success(SolidStroke(colour, thickness)) - } - _ -> decode.failure(NoStroke, "StrokeProperties") - } -} - -fn decode_vec2() -> Decoder(#(Float, Float)) { - use x <- decode.field("x", decode.float) - use y <- decode.field("y", decode.float) - decode.success(#(x, y)) -} - -fn picture_to_json(picture: Picture) -> Json { - case picture { - types.Arc(radius:, start:, end:) -> - json.object([ - #("type", json.string("arc")), - #("radius", json.float(radius)), - #("start", angle_to_json(start)), - #("end", angle_to_json(end)), - ]) - types.Blank -> json.object([#("type", json.string("blank"))]) - types.Combine(from) -> - json.object([ - #("type", json.string("combine")), - #("pictures", json.array(from:, of: picture_to_json)), - ]) - types.Fill(picture, colour) -> - json.object([ - #("type", json.string("fill")), - #("colour", colour.encode(colour)), - #("picture", picture_to_json(picture)), - ]) - types.Polygon(points, closed:) -> - json.object([ - #("type", json.string("polygon")), - #( - "points", - json.array(from: points, of: fn(point) { - let #(x, y) = point - json.object([#("x", json.float(x)), #("y", json.float(y))]) - }), - ), - #("closed", json.bool(closed)), - ]) - types.Rotate(picture, angle) -> - json.object([ - #("type", json.string("rotate")), - #("angle", angle_to_json(angle)), - #("picture", picture_to_json(picture)), - ]) - types.Scale(picture, #(x, y)) -> - json.object([ - #("type", json.string("scale")), - #("x", json.float(x)), - #("y", json.float(y)), - #("picture", picture_to_json(picture)), - ]) - types.Stroke(picture, stroke) -> - json.object([ - #("type", json.string("stroke")), - #("stroke", stroke_to_json(stroke)), - #("picture", picture_to_json(picture)), - ]) - types.Text(text:, style:) -> - json.object([ - #("type", json.string("text")), - #("text", json.string(text)), - #("style", font_to_json(style)), - ]) - types.Translate(picture, #(x, y)) -> - json.object([ - #("type", json.string("translate")), - #("x", json.float(x)), - #("y", json.float(y)), - #("picture", picture_to_json(picture)), - ]) - types.ImageRef(types.Image(id:), width_px:, height_px:) -> { - json.object([ - #("type", json.string("image")), - #("id", json.string(id)), - #("width_px", json.int(width_px)), - #("height_px", json.int(height_px)), - ]) - } - types.ImageScalingBehaviour(picture, behaviour) -> - json.object([ - #("type", json.string("image_scaling_behaviour")), - #( - "behaviour", - json.string(case behaviour { - types.ScalingPixelated -> "pixelated" - types.ScalingSmooth -> "smooth" - }), - ), - #("picture", picture_to_json(picture)), - ]) - } -} - -fn font_to_json(font: FontProperties) -> Json { - let FontProperties(size_px:, font_family:) = font - json.object([ - #("sizePx", json.int(size_px)), - #("fontFamily", json.string(font_family)), - ]) -} - -fn stroke_to_json(stroke: StrokeProperties) -> Json { - case stroke { - NoStroke -> json.object([#("type", json.string("noStroke"))]) - SolidStroke(colour, thickness) -> - json.object([ - #("type", json.string("solidStroke")), - #("colour", colour.encode(colour)), - #("thickness", json.float(thickness)), - ]) - } -} - -fn angle_to_json(angle: Angle) -> Json { - let Radians(rad) = angle - json.object([#("radians", json.float(rad))]) -} diff --git a/build/packages/paint/src/paint/event.gleam b/build/packages/paint/src/paint/event.gleam deleted file mode 100644 index 08298de..0000000 --- a/build/packages/paint/src/paint/event.gleam +++ /dev/null @@ -1,50 +0,0 @@ -//// This module contains events that can be triggered when -//// building interactive applications. -//// -//// See `paint/canvas` and the `canvas.interact` function for a -//// practical example of how this is used. - -pub type Event { - /// Triggered before drawing. Contains the number of milliseconds elapsed. - Tick(Float) - /// Triggered when a key is pressed - KeyboardPressed(Key) - /// Triggered when a key is released - KeyboardRelased(Key) - /// Triggered when the mouse is moved. Contains - /// the `x` and `y` value for the mouse position. - MouseMoved(Float, Float) - /// Triggered when a mouse button is pressed - MousePressed(MouseButton) - /// Triggered when a mouse button is released. - /// - /// Note, on the web you might encounter issues where the - /// release event for the right mouse button is not triggered - /// because of the context menu. - MouseReleased(MouseButton) -} - -pub type Key { - KeyLeftArrow - KeyRightArrow - KeyUpArrow - KeyDownArrow - KeySpace - KeyW - KeyA - KeyS - KeyD - KeyZ - KeyX - KeyC - KeyEnter - KeyEscape - KeyBackspace -} - -pub type MouseButton { - MouseButtonLeft - MouseButtonRight - /// The scroll wheel button - MouseButtonMiddle -} diff --git a/build/packages/paint/src/paint/internal/impl_canvas.gleam b/build/packages/paint/src/paint/internal/impl_canvas.gleam deleted file mode 100644 index 2b94e9a..0000000 --- a/build/packages/paint/src/paint/internal/impl_canvas.gleam +++ /dev/null @@ -1,118 +0,0 @@ -pub type RenderingContext2D - -@external(javascript, "./../../impl_canvas_bindings.mjs", "define_web_component") -pub fn define_web_component() -> Nil - -// TODO: forward the timestamp from the callback -@external(javascript, "./../../impl_canvas_bindings.mjs", "setup_request_animation_frame") -pub fn setup_request_animation_frame(callback: fn(Float) -> Nil) -> Nil - -@external(javascript, "./../../impl_canvas_bindings.mjs", "get_rendering_context") -pub fn get_rendering_context(selector: String) -> RenderingContext2D - -@external(javascript, "../../impl_canvas_bindings.mjs", "setup_input_handler") -pub fn setup_input_handler(event: String, callback: fn(event) -> Nil) -> Nil - -pub type KeyboardEvent - -@external(javascript, "./../../impl_canvas_bindings.mjs", "get_key_code") -pub fn get_key_code(event: KeyboardEvent) -> Int - -pub type MouseEvent - -@external(javascript, "./../../impl_canvas_bindings.mjs", "mouse_pos") -pub fn mouse_pos(ctx: RenderingContext2D, event: MouseEvent) -> #(Float, Float) - -@external(javascript, "./../../impl_canvas_bindings.mjs", "check_mouse_button") -pub fn check_mouse_button( - event: MouseEvent, - previous_event: Result(MouseEvent, Nil), - button_index: Int, - check_pressed check_pressed: Bool, -) -> Bool - -@external(javascript, "../../impl_canvas_bindings.mjs", "get_width") -pub fn get_width(ctx: RenderingContext2D) -> Float - -@external(javascript, "../../impl_canvas_bindings.mjs", "get_height") -pub fn get_height(ctx: RenderingContext2D) -> Float - -@external(javascript, "../../impl_canvas_bindings.mjs", "set_global") -pub fn set_global(state: state, id: String) -> Nil - -@external(javascript, "../../impl_canvas_bindings.mjs", "get_global") -pub fn get_global(id: String) -> Result(state, Nil) - -@external(javascript, "../../impl_canvas_bindings.mjs", "reset") -pub fn reset(ctx: RenderingContext2D) -> Nil - -@external(javascript, "../../impl_canvas_bindings.mjs", "save") -pub fn save(ctx: RenderingContext2D) -> Nil - -@external(javascript, "../../impl_canvas_bindings.mjs", "restore") -pub fn restore(ctx: RenderingContext2D) -> Nil - -@external(javascript, "../../impl_canvas_bindings.mjs", "translate") -pub fn translate(ctx: RenderingContext2D, x: Float, y: Float) -> Nil - -@external(javascript, "../../impl_canvas_bindings.mjs", "scale") -pub fn scale(ctx: RenderingContext2D, x: Float, y: Float) -> Nil - -@external(javascript, "../../impl_canvas_bindings.mjs", "rotate") -pub fn rotate(ctx: RenderingContext2D, radians: Float) -> Nil - -@external(javascript, "../../impl_canvas_bindings.mjs", "reset_transform") -pub fn reset_transform(ctx: RenderingContext2D) -> Nil - -@external(javascript, "../../impl_canvas_bindings.mjs", "set_fill_colour") -pub fn set_fill_colour(ctx: RenderingContext2D, css_colour: String) -> Nil - -@external(javascript, "../../impl_canvas_bindings.mjs", "set_stroke_color") -pub fn set_stroke_color(ctx: RenderingContext2D, css_color: String) -> Nil - -@external(javascript, "../../impl_canvas_bindings.mjs", "set_line_width") -pub fn set_line_width(ctx: RenderingContext2D, width: Float) -> Nil - -@external(javascript, "../../impl_canvas_bindings.mjs", "set_image_smoothing_enabled") -pub fn set_image_smoothing_enabled(ctx: RenderingContext2D, value: Bool) -> Nil - -@external(javascript, "../../impl_canvas_bindings.mjs", "arc") -pub fn arc( - ctx: RenderingContext2D, - radius: Float, - start: Float, - end: Float, - fill: Bool, - stroke: Bool, -) -> Nil - -@external(javascript, "../../impl_canvas_bindings.mjs", "polygon") -pub fn polygon( - ctx: RenderingContext2D, - points: List(#(Float, Float)), - closed: Bool, - fill: Bool, - stroke: Bool, -) -> Nil - -@external(javascript, "../../impl_canvas_bindings.mjs", "text") -pub fn text(ctx: RenderingContext2D, text: String, style: String) -> Nil - -pub type JsImage - -@external(javascript, "../../impl_canvas_bindings.mjs", "draw_image") -pub fn draw_image( - ctx: RenderingContext2D, - image: JsImage, - width_px: Int, - height_px: Int, -) -> Nil - -@external(javascript, "../../impl_canvas_bindings.mjs", "image_from_query") -pub fn image_from_query(selector: String) -> JsImage - -@external(javascript, "../../impl_canvas_bindings.mjs", "image_from_src") -pub fn image_from_src(src: String) -> JsImage - -@external(javascript, "../../impl_canvas_bindings.mjs", "on_image_load") -pub fn on_image_load(image: JsImage, callback: fn() -> Nil) -> Nil diff --git a/build/packages/paint/src/paint/internal/types.gleam b/build/packages/paint/src/paint/internal/types.gleam deleted file mode 100644 index 4cd6b5c..0000000 --- a/build/packages/paint/src/paint/internal/types.gleam +++ /dev/null @@ -1,48 +0,0 @@ -import gleam_community/colour.{type Colour} - -pub type Picture { - // Shapes - Blank - Polygon(List(Vec2), closed: Bool) - Arc(radius: Float, start: Angle, end: Angle) - Text(text: String, style: FontProperties) - ImageRef(Image, width_px: Int, height_px: Int) - // Styling - // TODO: font - Fill(Picture, Colour) - Stroke(Picture, StrokeProperties) - ImageScalingBehaviour(Picture, ImageScalingBehaviour) - // Transform - Translate(Picture, Vec2) - Scale(Picture, Vec2) - Rotate(Picture, Angle) - // Combine - Combine(List(Picture)) -} - -// The ID for an image -// Invariant: the image object is assumed to already be created and stored somewhere (like the PAINT_STATE for the canvas backend) -pub type Image { - Image(id: String) -} - -pub type ImageScalingBehaviour { - ScalingSmooth - ScalingPixelated -} - -pub type StrokeProperties { - NoStroke - SolidStroke(Colour, Float) -} - -pub type FontProperties { - FontProperties(size_px: Int, font_family: String) -} - -pub type Angle { - Radians(Float) -} - -pub type Vec2 = - #(Float, Float) diff --git a/demo.gif b/demo.gif new file mode 100644 index 0000000..d48bf5b Binary files /dev/null and b/demo.gif differ