Initial commit
This commit is contained in:
commit
a6272848f9
379 changed files with 74829 additions and 0 deletions
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
1
build/dev/javascript/gleam_community_colour/gleam.mjs
Normal file
1
build/dev/javascript/gleam_community_colour/gleam.mjs
Normal file
|
|
@ -0,0 +1 @@
|
|||
export * from "../prelude.mjs";
|
||||
File diff suppressed because it is too large
Load diff
|
|
@ -0,0 +1,146 @@
|
|||
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.
|
||||
*
|
||||
* <details>
|
||||
* <summary>Example:</summary>
|
||||
*
|
||||
* ```gleam
|
||||
* fn example() {
|
||||
* luminance(colour.white) // 1.0
|
||||
* }
|
||||
* ```
|
||||
* </details>
|
||||
*
|
||||
* <div style="position: relative;">
|
||||
* <a style="position: absolute; left: 0;" href="https://github.com/gleam-community/colour/issues">
|
||||
* <small>Spot a typo? Open an issue!</small>
|
||||
* </a>
|
||||
* <a style="position: absolute; right: 0;" href="#">
|
||||
* <small>Back to top ↑</small>
|
||||
* </a>
|
||||
* </div>
|
||||
*/
|
||||
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.
|
||||
*
|
||||
* <details>
|
||||
* <summary>Example:</summary>
|
||||
*
|
||||
* ```gleam
|
||||
* fn example() {
|
||||
* contrast_ratio(between: colour.white, and: colour.black) // 21.0
|
||||
* }
|
||||
* ```
|
||||
* </details>
|
||||
*
|
||||
* <div style="position: relative;">
|
||||
* <a style="position: absolute; left: 0;" href="https://github.com/gleam-community/colour/issues">
|
||||
* <small>Spot a typo? Open an issue!</small>
|
||||
* </a>
|
||||
* <a style="position: absolute; right: 0;" href="#">
|
||||
* <small>Back to top ↑</small>
|
||||
* </a>
|
||||
* </div>
|
||||
*/
|
||||
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.
|
||||
*
|
||||
* <details>
|
||||
* <summary>Example:</summary>
|
||||
*
|
||||
* ```gleam
|
||||
* fn example() {
|
||||
* maximum_contrast(
|
||||
* colour.yellow,
|
||||
* [colour.white, colour.dark_blue, colour.green],
|
||||
* )
|
||||
* }
|
||||
* ```
|
||||
* </details>
|
||||
*
|
||||
* <div style="position: relative;">
|
||||
* <a style="position: absolute; left: 0;" href="https://github.com/gleam-community/colour/issues">
|
||||
* <small>Spot a typo? Open an issue!</small>
|
||||
* </a>
|
||||
* <a style="position: absolute; right: 0;" href="#">
|
||||
* <small>Back to top ↑</small>
|
||||
* </a>
|
||||
* </div>
|
||||
*/
|
||||
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);
|
||||
}
|
||||
File diff suppressed because it is too large
Load diff
|
|
@ -0,0 +1,203 @@
|
|||
-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"
|
||||
" <a href=\"https://github.com/noahzgordon/elm-color-extra\">here</a>.\n"
|
||||
"\n"
|
||||
" <details>\n"
|
||||
" <summary>The license of that package is produced below:</summary>\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"
|
||||
" </details>\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 => <<?FILEPATH/utf8>>,
|
||||
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"
|
||||
" <details>\n"
|
||||
" <summary>Example:</summary>\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" fn example() {\n"
|
||||
" luminance(colour.white) // 1.0\n"
|
||||
" }\n"
|
||||
" ```\n"
|
||||
" </details>\n"
|
||||
"\n"
|
||||
" <div style=\"position: relative;\">\n"
|
||||
" <a style=\"position: absolute; left: 0;\" href=\"https://github.com/gleam-community/colour/issues\">\n"
|
||||
" <small>Spot a typo? Open an issue!</small>\n"
|
||||
" </a>\n"
|
||||
" <a style=\"position: absolute; right: 0;\" href=\"#\">\n"
|
||||
" <small>Back to top ↑</small>\n"
|
||||
" </a>\n"
|
||||
" </div>\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"
|
||||
" <details>\n"
|
||||
" <summary>Example:</summary>\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" fn example() {\n"
|
||||
" contrast_ratio(between: colour.white, and: colour.black) // 21.0\n"
|
||||
" }\n"
|
||||
" ```\n"
|
||||
" </details>\n"
|
||||
"\n"
|
||||
" <div style=\"position: relative;\">\n"
|
||||
" <a style=\"position: absolute; left: 0;\" href=\"https://github.com/gleam-community/colour/issues\">\n"
|
||||
" <small>Spot a typo? Open an issue!</small>\n"
|
||||
" </a>\n"
|
||||
" <a style=\"position: absolute; right: 0;\" href=\"#\">\n"
|
||||
" <small>Back to top ↑</small>\n"
|
||||
" </a>\n"
|
||||
" </div>\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"
|
||||
" <details>\n"
|
||||
" <summary>Example:</summary>\n"
|
||||
"\n"
|
||||
" ```gleam\n"
|
||||
" fn example() {\n"
|
||||
" maximum_contrast(\n"
|
||||
" colour.yellow,\n"
|
||||
" [colour.white, colour.dark_blue, colour.green],\n"
|
||||
" )\n"
|
||||
" }\n"
|
||||
" ```\n"
|
||||
" </details>\n"
|
||||
"\n"
|
||||
" <div style=\"position: relative;\">\n"
|
||||
" <a style=\"position: absolute; left: 0;\" href=\"https://github.com/gleam-community/colour/issues\">\n"
|
||||
" <small>Spot a typo? Open an issue!</small>\n"
|
||||
" </a>\n"
|
||||
" <a style=\"position: absolute; right: 0;\" href=\"#\">\n"
|
||||
" <small>Back to top ↑</small>\n"
|
||||
" </a>\n"
|
||||
" </div>\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).
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
1
build/dev/javascript/gleam_json/gleam.mjs
Normal file
1
build/dev/javascript/gleam_json/gleam.mjs
Normal file
|
|
@ -0,0 +1 @@
|
|||
export * from "../prelude.mjs";
|
||||
325
build/dev/javascript/gleam_json/gleam/json.mjs
Normal file
325
build/dev/javascript/gleam_json/gleam/json.mjs
Normal file
|
|
@ -0,0 +1,325 @@
|
|||
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); },
|
||||
),
|
||||
);
|
||||
}
|
||||
304
build/dev/javascript/gleam_json/gleam@json.erl
Normal file
304
build/dev/javascript/gleam_json/gleam@json.erl
Normal file
|
|
@ -0,0 +1,304 @@
|
|||
-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
|
||||
)
|
||||
).
|
||||
66
build/dev/javascript/gleam_json/gleam_json_ffi.erl
Normal file
66
build/dev/javascript/gleam_json/gleam_json_ffi.erl
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
-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.
|
||||
201
build/dev/javascript/gleam_json/gleam_json_ffi.mjs
Normal file
201
build/dev/javascript/gleam_json/gleam_json_ffi.mjs
Normal file
|
|
@ -0,0 +1,201 @@
|
|||
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;
|
||||
}
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
993
build/dev/javascript/gleam_stdlib/dict.mjs
Normal file
993
build/dev/javascript/gleam_stdlib/dict.mjs
Normal file
|
|
@ -0,0 +1,993 @@
|
|||
/**
|
||||
* 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<K,V> | IndexNode<K,V> | CollisionNode<K,V>} 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<K,V> | Node<K,V>)[] }} ArrayNode
|
||||
*/
|
||||
/**
|
||||
* @template K,V
|
||||
* @typedef {{ type: typeof INDEX_NODE, bitmap: number, array: (Entry<K,V> | Node<K,V>)[] }} IndexNode
|
||||
*/
|
||||
/**
|
||||
* @template K,V
|
||||
* @typedef {{ type: typeof COLLISION_NODE, hash: number, array: Entry<K, V>[] }} 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<any,any>} */
|
||||
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<K,V>}
|
||||
*/
|
||||
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<K,V>}
|
||||
*/
|
||||
/**
|
||||
* Associate a node with a new entry, creating a new node
|
||||
* @template T,K,V
|
||||
* @type {AssocFunction<Node<K,V>,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<ArrayNode<K,V>,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<IndexNode<K,V>,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<CollisionNode<K,V>,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<K,V>} 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<K,V>}
|
||||
*/
|
||||
/**
|
||||
* Return the found entry or undefined if not present in the root
|
||||
* @template K,V
|
||||
* @type {FindFunction<Node<K,V>,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<ArrayNode<K,V>,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<IndexNode<K,V>,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<K,V>} root
|
||||
* @param {K} key
|
||||
* @returns {undefined | Entry<K,V>}
|
||||
*/
|
||||
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<K,V>}
|
||||
*/
|
||||
/**
|
||||
* 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<Node<K,V>,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<ArrayNode<K,V>,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<IndexNode<K,V>,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<K,V>} root
|
||||
* @param {K} key
|
||||
* @returns {undefined | Node<K,V>}
|
||||
*/
|
||||
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<K,V>} 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<string,V>} o
|
||||
* @returns {Dict<string,V>}
|
||||
*/
|
||||
static fromObject(o) {
|
||||
const keys = Object.keys(o);
|
||||
/** @type Dict<string,V> */
|
||||
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<K,V>} o
|
||||
* @returns {Dict<K,V>}
|
||||
*/
|
||||
static fromMap(o) {
|
||||
/** @type Dict<K,V> */
|
||||
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<K,V>} 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<K,V>}
|
||||
*/
|
||||
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<K,V>}
|
||||
*/
|
||||
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();
|
||||
1
build/dev/javascript/gleam_stdlib/gleam.mjs
Normal file
1
build/dev/javascript/gleam_stdlib/gleam.mjs
Normal file
|
|
@ -0,0 +1 @@
|
|||
export * from "../prelude.mjs";
|
||||
285
build/dev/javascript/gleam_stdlib/gleam/bit_array.mjs
Normal file
285
build/dev/javascript/gleam_stdlib/gleam/bit_array.mjs
Normal file
|
|
@ -0,0 +1,285 @@
|
|||
import { Ok, toList, bitArraySlice, bitArraySliceToInt } from "../gleam.mjs";
|
||||
import * as $int from "../gleam/int.mjs";
|
||||
import * as $order from "../gleam/order.mjs";
|
||||
import * as $string from "../gleam/string.mjs";
|
||||
import {
|
||||
bit_array_from_string as from_string,
|
||||
bit_array_bit_size as bit_size,
|
||||
bit_array_byte_size as byte_size,
|
||||
bit_array_pad_to_bytes as pad_to_bytes,
|
||||
bit_array_slice as slice,
|
||||
bit_array_concat as concat,
|
||||
base64_encode,
|
||||
base64_decode as decode64,
|
||||
base16_encode,
|
||||
base16_decode,
|
||||
bit_array_to_int_and_size,
|
||||
bit_array_starts_with as starts_with,
|
||||
bit_array_to_string as to_string,
|
||||
} from "../gleam_stdlib.mjs";
|
||||
|
||||
export {
|
||||
base16_decode,
|
||||
base16_encode,
|
||||
base64_encode,
|
||||
bit_size,
|
||||
byte_size,
|
||||
concat,
|
||||
from_string,
|
||||
pad_to_bytes,
|
||||
slice,
|
||||
starts_with,
|
||||
to_string,
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates a new bit array by joining two bit arrays.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* append(to: from_string("butter"), suffix: from_string("fly"))
|
||||
* // -> from_string("butterfly")
|
||||
* ```
|
||||
*/
|
||||
export function append(first, second) {
|
||||
return concat(toList([first, second]));
|
||||
}
|
||||
|
||||
/**
|
||||
* Decodes a base 64 encoded string into a `BitArray`.
|
||||
*/
|
||||
export function base64_decode(encoded) {
|
||||
let _block;
|
||||
let $ = byte_size(from_string(encoded)) % 4;
|
||||
if ($ === 0) {
|
||||
_block = encoded;
|
||||
} else {
|
||||
let n = $;
|
||||
_block = $string.append(encoded, $string.repeat("=", 4 - n));
|
||||
}
|
||||
let padded = _block;
|
||||
return decode64(padded);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes a `BitArray` into a base 64 encoded string with URL and filename
|
||||
* safe alphabet.
|
||||
*
|
||||
* If the bit array does not contain a whole number of bytes then it is padded
|
||||
* with zero bits prior to being encoded.
|
||||
*/
|
||||
export function base64_url_encode(input, padding) {
|
||||
let _pipe = input;
|
||||
let _pipe$1 = base64_encode(_pipe, padding);
|
||||
let _pipe$2 = $string.replace(_pipe$1, "+", "-");
|
||||
return $string.replace(_pipe$2, "/", "_");
|
||||
}
|
||||
|
||||
/**
|
||||
* Decodes a base 64 encoded string with URL and filename safe alphabet into a
|
||||
* `BitArray`.
|
||||
*/
|
||||
export function base64_url_decode(encoded) {
|
||||
let _pipe = encoded;
|
||||
let _pipe$1 = $string.replace(_pipe, "-", "+");
|
||||
let _pipe$2 = $string.replace(_pipe$1, "_", "/");
|
||||
return base64_decode(_pipe$2);
|
||||
}
|
||||
|
||||
function inspect_loop(loop$input, loop$accumulator) {
|
||||
while (true) {
|
||||
let input = loop$input;
|
||||
let accumulator = loop$accumulator;
|
||||
if (input.bitSize === 0) {
|
||||
return accumulator;
|
||||
} else if (input.bitSize === 1) {
|
||||
let x = bitArraySliceToInt(input, 0, 1, true, false);
|
||||
return (accumulator + $int.to_string(x)) + ":size(1)";
|
||||
} else if (input.bitSize === 2) {
|
||||
let x = bitArraySliceToInt(input, 0, 2, true, false);
|
||||
return (accumulator + $int.to_string(x)) + ":size(2)";
|
||||
} else if (input.bitSize === 3) {
|
||||
let x = bitArraySliceToInt(input, 0, 3, true, false);
|
||||
return (accumulator + $int.to_string(x)) + ":size(3)";
|
||||
} else if (input.bitSize === 4) {
|
||||
let x = bitArraySliceToInt(input, 0, 4, true, false);
|
||||
return (accumulator + $int.to_string(x)) + ":size(4)";
|
||||
} else if (input.bitSize === 5) {
|
||||
let x = bitArraySliceToInt(input, 0, 5, true, false);
|
||||
return (accumulator + $int.to_string(x)) + ":size(5)";
|
||||
} else if (input.bitSize === 6) {
|
||||
let x = bitArraySliceToInt(input, 0, 6, true, false);
|
||||
return (accumulator + $int.to_string(x)) + ":size(6)";
|
||||
} else if (input.bitSize === 7) {
|
||||
let x = bitArraySliceToInt(input, 0, 7, true, false);
|
||||
return (accumulator + $int.to_string(x)) + ":size(7)";
|
||||
} else if (input.bitSize >= 8) {
|
||||
let x = input.byteAt(0);
|
||||
let rest = bitArraySlice(input, 8);
|
||||
let _block;
|
||||
if (rest.bitSize === 0) {
|
||||
_block = "";
|
||||
} else {
|
||||
_block = ", ";
|
||||
}
|
||||
let suffix = _block;
|
||||
let accumulator$1 = (accumulator + $int.to_string(x)) + suffix;
|
||||
loop$input = rest;
|
||||
loop$accumulator = accumulator$1;
|
||||
} else {
|
||||
return accumulator;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a bit array to a string containing the decimal value of each byte.
|
||||
*
|
||||
* Use this over `string.inspect` when you have a bit array you want printed
|
||||
* in the array syntax even if it is valid UTF-8.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* inspect(<<0, 20, 0x20, 255>>)
|
||||
* // -> "<<0, 20, 32, 255>>"
|
||||
*
|
||||
* inspect(<<100, 5:3>>)
|
||||
* // -> "<<100, 5:size(3)>>"
|
||||
* ```
|
||||
*/
|
||||
export function inspect(input) {
|
||||
return inspect_loop(input, "<<") + ">>";
|
||||
}
|
||||
|
||||
/**
|
||||
* Compare two bit arrays as sequences of bytes.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* compare(<<1>>, <<2>>)
|
||||
* // -> Lt
|
||||
*
|
||||
* compare(<<"AB":utf8>>, <<"AA":utf8>>)
|
||||
* // -> Gt
|
||||
*
|
||||
* compare(<<1, 2:size(2)>>, with: <<1, 2:size(2)>>)
|
||||
* // -> Eq
|
||||
* ```
|
||||
*/
|
||||
export function compare(loop$a, loop$b) {
|
||||
while (true) {
|
||||
let a = loop$a;
|
||||
let b = loop$b;
|
||||
if (a.bitSize >= 8) {
|
||||
if (b.bitSize >= 8) {
|
||||
let first_byte = a.byteAt(0);
|
||||
let first_rest = bitArraySlice(a, 8);
|
||||
let second_byte = b.byteAt(0);
|
||||
let second_rest = bitArraySlice(b, 8);
|
||||
let f = first_byte;
|
||||
let s = second_byte;
|
||||
if (f > s) {
|
||||
return new $order.Gt();
|
||||
} else {
|
||||
let f$1 = first_byte;
|
||||
let s$1 = second_byte;
|
||||
if (f$1 < s$1) {
|
||||
return new $order.Lt();
|
||||
} else {
|
||||
loop$a = first_rest;
|
||||
loop$b = second_rest;
|
||||
}
|
||||
}
|
||||
} else if (b.bitSize === 0) {
|
||||
return new $order.Gt();
|
||||
} else {
|
||||
let first = a;
|
||||
let second = b;
|
||||
let $ = bit_array_to_int_and_size(first);
|
||||
let $1 = bit_array_to_int_and_size(second);
|
||||
let a$1 = $[0];
|
||||
let b$1 = $1[0];
|
||||
if (a$1 > b$1) {
|
||||
return new $order.Gt();
|
||||
} else {
|
||||
let a$2 = $[0];
|
||||
let b$2 = $1[0];
|
||||
if (a$2 < b$2) {
|
||||
return new $order.Lt();
|
||||
} else {
|
||||
let size_a = $[1];
|
||||
let size_b = $1[1];
|
||||
if (size_a > size_b) {
|
||||
return new $order.Gt();
|
||||
} else {
|
||||
let size_a$1 = $[1];
|
||||
let size_b$1 = $1[1];
|
||||
if (size_a$1 < size_b$1) {
|
||||
return new $order.Lt();
|
||||
} else {
|
||||
return new $order.Eq();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (b.bitSize === 0) {
|
||||
if (a.bitSize === 0) {
|
||||
return new $order.Eq();
|
||||
} else {
|
||||
return new $order.Gt();
|
||||
}
|
||||
} else if (a.bitSize === 0) {
|
||||
return new $order.Lt();
|
||||
} else {
|
||||
let first = a;
|
||||
let second = b;
|
||||
let $ = bit_array_to_int_and_size(first);
|
||||
let $1 = bit_array_to_int_and_size(second);
|
||||
let a$1 = $[0];
|
||||
let b$1 = $1[0];
|
||||
if (a$1 > b$1) {
|
||||
return new $order.Gt();
|
||||
} else {
|
||||
let a$2 = $[0];
|
||||
let b$2 = $1[0];
|
||||
if (a$2 < b$2) {
|
||||
return new $order.Lt();
|
||||
} else {
|
||||
let size_a = $[1];
|
||||
let size_b = $1[1];
|
||||
if (size_a > size_b) {
|
||||
return new $order.Gt();
|
||||
} else {
|
||||
let size_a$1 = $[1];
|
||||
let size_b$1 = $1[1];
|
||||
if (size_a$1 < size_b$1) {
|
||||
return new $order.Lt();
|
||||
} else {
|
||||
return new $order.Eq();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests to see whether a bit array is valid UTF-8.
|
||||
*/
|
||||
export function is_utf8(bits) {
|
||||
return is_utf8_loop(bits);
|
||||
}
|
||||
|
||||
function is_utf8_loop(bits) {
|
||||
let $ = to_string(bits);
|
||||
if ($ instanceof Ok) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
313
build/dev/javascript/gleam_stdlib/gleam/bool.mjs
Normal file
313
build/dev/javascript/gleam_stdlib/gleam/bool.mjs
Normal file
|
|
@ -0,0 +1,313 @@
|
|||
/**
|
||||
* Returns the and of two bools, but it evaluates both arguments.
|
||||
*
|
||||
* It's the function equivalent of the `&&` operator.
|
||||
* This function is useful in higher order functions or pipes.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* and(True, True)
|
||||
* // -> True
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* and(False, True)
|
||||
* // -> False
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* False |> and(True)
|
||||
* // -> False
|
||||
* ```
|
||||
*/
|
||||
export function and(a, b) {
|
||||
return a && b;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the or of two bools, but it evaluates both arguments.
|
||||
*
|
||||
* It's the function equivalent of the `||` operator.
|
||||
* This function is useful in higher order functions or pipes.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* or(True, True)
|
||||
* // -> True
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* or(False, True)
|
||||
* // -> True
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* False |> or(True)
|
||||
* // -> True
|
||||
* ```
|
||||
*/
|
||||
export function or(a, b) {
|
||||
return a || b;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the opposite bool value.
|
||||
*
|
||||
* This is the same as the `!` or `not` operators in some other languages.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* negate(True)
|
||||
* // -> False
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* negate(False)
|
||||
* // -> True
|
||||
* ```
|
||||
*/
|
||||
export function negate(bool) {
|
||||
return !bool;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the nor of two bools.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* nor(False, False)
|
||||
* // -> True
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* nor(False, True)
|
||||
* // -> False
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* nor(True, False)
|
||||
* // -> False
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* nor(True, True)
|
||||
* // -> False
|
||||
* ```
|
||||
*/
|
||||
export function nor(a, b) {
|
||||
return !(a || b);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the nand of two bools.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* nand(False, False)
|
||||
* // -> True
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* nand(False, True)
|
||||
* // -> True
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* nand(True, False)
|
||||
* // -> True
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* nand(True, True)
|
||||
* // -> False
|
||||
* ```
|
||||
*/
|
||||
export function nand(a, b) {
|
||||
return !(a && b);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the exclusive or of two bools.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* exclusive_or(False, False)
|
||||
* // -> False
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* exclusive_or(False, True)
|
||||
* // -> True
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* exclusive_or(True, False)
|
||||
* // -> True
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* exclusive_or(True, True)
|
||||
* // -> False
|
||||
* ```
|
||||
*/
|
||||
export function exclusive_or(a, b) {
|
||||
return a !== b;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the exclusive nor of two bools.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* exclusive_nor(False, False)
|
||||
* // -> True
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* exclusive_nor(False, True)
|
||||
* // -> False
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* exclusive_nor(True, False)
|
||||
* // -> False
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* exclusive_nor(True, True)
|
||||
* // -> True
|
||||
* ```
|
||||
*/
|
||||
export function exclusive_nor(a, b) {
|
||||
return a === b;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string representation of the given bool.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* to_string(True)
|
||||
* // -> "True"
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* to_string(False)
|
||||
* // -> "False"
|
||||
* ```
|
||||
*/
|
||||
export function to_string(bool) {
|
||||
if (bool) {
|
||||
return "True";
|
||||
} else {
|
||||
return "False";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Run a callback function if the given bool is `False`, otherwise return a
|
||||
* default value.
|
||||
*
|
||||
* With a `use` expression this function can simulate the early-return pattern
|
||||
* found in some other programming languages.
|
||||
*
|
||||
* In a procedural language:
|
||||
*
|
||||
* ```js
|
||||
* if (predicate) return value;
|
||||
* // ...
|
||||
* ```
|
||||
*
|
||||
* In Gleam with a `use` expression:
|
||||
*
|
||||
* ```gleam
|
||||
* use <- guard(when: predicate, return: value)
|
||||
* // ...
|
||||
* ```
|
||||
*
|
||||
* Like everything in Gleam `use` is an expression, so it short circuits the
|
||||
* current block, not the entire function. As a result you can assign the value
|
||||
* to a variable:
|
||||
*
|
||||
* ```gleam
|
||||
* let x = {
|
||||
* use <- guard(when: predicate, return: value)
|
||||
* // ...
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* Note that unlike in procedural languages the `return` value is evaluated
|
||||
* even when the predicate is `False`, so it is advisable not to perform
|
||||
* expensive computation nor side-effects there.
|
||||
*
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* let name = ""
|
||||
* use <- guard(when: name == "", return: "Welcome!")
|
||||
* "Hello, " <> name
|
||||
* // -> "Welcome!"
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* let name = "Kamaka"
|
||||
* use <- guard(when: name == "", return: "Welcome!")
|
||||
* "Hello, " <> name
|
||||
* // -> "Hello, Kamaka"
|
||||
* ```
|
||||
*/
|
||||
export function guard(requirement, consequence, alternative) {
|
||||
if (requirement) {
|
||||
return consequence;
|
||||
} else {
|
||||
return alternative();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs a callback function if the given bool is `True`, otherwise runs an
|
||||
* alternative callback function.
|
||||
*
|
||||
* Useful when further computation should be delayed regardless of the given
|
||||
* bool's value.
|
||||
*
|
||||
* See [`guard`](#guard) for more info.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* let name = "Kamaka"
|
||||
* let inquiry = fn() { "How may we address you?" }
|
||||
* use <- lazy_guard(when: name == "", return: inquiry)
|
||||
* "Hello, " <> name
|
||||
* // -> "Hello, Kamaka"
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* import gleam/int
|
||||
*
|
||||
* let name = ""
|
||||
* let greeting = fn() { "Hello, " <> name }
|
||||
* use <- lazy_guard(when: name == "", otherwise: greeting)
|
||||
* let number = int.random(99)
|
||||
* let name = "User " <> int.to_string(number)
|
||||
* "Welcome, " <> name
|
||||
* // -> "Welcome, User 54"
|
||||
* ```
|
||||
*/
|
||||
export function lazy_guard(requirement, consequence, alternative) {
|
||||
if (requirement) {
|
||||
return consequence();
|
||||
} else {
|
||||
return alternative();
|
||||
}
|
||||
}
|
||||
225
build/dev/javascript/gleam_stdlib/gleam/bytes_tree.mjs
Normal file
225
build/dev/javascript/gleam_stdlib/gleam/bytes_tree.mjs
Normal file
|
|
@ -0,0 +1,225 @@
|
|||
import {
|
||||
toList,
|
||||
Empty as $Empty,
|
||||
prepend as listPrepend,
|
||||
CustomType as $CustomType,
|
||||
} from "../gleam.mjs";
|
||||
import * as $bit_array from "../gleam/bit_array.mjs";
|
||||
import * as $list from "../gleam/list.mjs";
|
||||
import * as $string_tree from "../gleam/string_tree.mjs";
|
||||
|
||||
class Bytes extends $CustomType {
|
||||
constructor($0) {
|
||||
super();
|
||||
this[0] = $0;
|
||||
}
|
||||
}
|
||||
|
||||
class Text extends $CustomType {
|
||||
constructor($0) {
|
||||
super();
|
||||
this[0] = $0;
|
||||
}
|
||||
}
|
||||
|
||||
class Many extends $CustomType {
|
||||
constructor($0) {
|
||||
super();
|
||||
this[0] = $0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends a bytes tree onto the end of another.
|
||||
*
|
||||
* Runs in constant time.
|
||||
*/
|
||||
export function append_tree(first, second) {
|
||||
if (second instanceof Bytes) {
|
||||
return new Many(toList([first, second]));
|
||||
} else if (second instanceof Text) {
|
||||
return new Many(toList([first, second]));
|
||||
} else {
|
||||
let trees = second[0];
|
||||
return new Many(listPrepend(first, trees));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepends a bytes tree onto the start of another.
|
||||
*
|
||||
* Runs in constant time.
|
||||
*/
|
||||
export function prepend_tree(second, first) {
|
||||
return append_tree(first, second);
|
||||
}
|
||||
|
||||
/**
|
||||
* Joins a list of bytes trees into a single one.
|
||||
*
|
||||
* Runs in constant time.
|
||||
*/
|
||||
export function concat(trees) {
|
||||
return new Many(trees);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an empty `BytesTree`. Useful as the start of a pipe chaining many
|
||||
* trees together.
|
||||
*/
|
||||
export function new$() {
|
||||
return concat(toList([]));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new bytes tree from a string.
|
||||
*
|
||||
* Runs in constant time when running on Erlang.
|
||||
* Runs in linear time otherwise.
|
||||
*/
|
||||
export function from_string(string) {
|
||||
return new Text($string_tree.from_string(string));
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepends a string onto the start of a bytes tree.
|
||||
*
|
||||
* Runs in constant time when running on Erlang.
|
||||
* Runs in linear time with the length of the string otherwise.
|
||||
*/
|
||||
export function prepend_string(second, first) {
|
||||
return append_tree(from_string(first), second);
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends a string onto the end of a bytes tree.
|
||||
*
|
||||
* Runs in constant time when running on Erlang.
|
||||
* Runs in linear time with the length of the string otherwise.
|
||||
*/
|
||||
export function append_string(first, second) {
|
||||
return append_tree(first, from_string(second));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new bytes tree from a string tree.
|
||||
*
|
||||
* Runs in constant time when running on Erlang.
|
||||
* Runs in linear time otherwise.
|
||||
*/
|
||||
export function from_string_tree(tree) {
|
||||
return new Text(tree);
|
||||
}
|
||||
|
||||
function wrap_list(bits) {
|
||||
return new Bytes(bits);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new bytes tree from a bit array.
|
||||
*
|
||||
* Runs in constant time.
|
||||
*/
|
||||
export function from_bit_array(bits) {
|
||||
let _pipe = bits;
|
||||
let _pipe$1 = $bit_array.pad_to_bytes(_pipe);
|
||||
return wrap_list(_pipe$1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepends a bit array to the start of a bytes tree.
|
||||
*
|
||||
* Runs in constant time.
|
||||
*/
|
||||
export function prepend(second, first) {
|
||||
return append_tree(from_bit_array(first), second);
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends a bit array to the end of a bytes tree.
|
||||
*
|
||||
* Runs in constant time.
|
||||
*/
|
||||
export function append(first, second) {
|
||||
return append_tree(first, from_bit_array(second));
|
||||
}
|
||||
|
||||
/**
|
||||
* Joins a list of bit arrays into a single bytes tree.
|
||||
*
|
||||
* Runs in constant time.
|
||||
*/
|
||||
export function concat_bit_arrays(bits) {
|
||||
let _pipe = bits;
|
||||
let _pipe$1 = $list.map(_pipe, from_bit_array);
|
||||
return concat(_pipe$1);
|
||||
}
|
||||
|
||||
function to_list(loop$stack, loop$acc) {
|
||||
while (true) {
|
||||
let stack = loop$stack;
|
||||
let acc = loop$acc;
|
||||
if (stack instanceof $Empty) {
|
||||
return acc;
|
||||
} else {
|
||||
let $ = stack.head;
|
||||
if ($ instanceof $Empty) {
|
||||
let remaining_stack = stack.tail;
|
||||
loop$stack = remaining_stack;
|
||||
loop$acc = acc;
|
||||
} else {
|
||||
let $1 = $.head;
|
||||
if ($1 instanceof Bytes) {
|
||||
let remaining_stack = stack.tail;
|
||||
let rest = $.tail;
|
||||
let bits = $1[0];
|
||||
loop$stack = listPrepend(rest, remaining_stack);
|
||||
loop$acc = listPrepend(bits, acc);
|
||||
} else if ($1 instanceof Text) {
|
||||
let remaining_stack = stack.tail;
|
||||
let rest = $.tail;
|
||||
let tree = $1[0];
|
||||
let bits = $bit_array.from_string($string_tree.to_string(tree));
|
||||
loop$stack = listPrepend(rest, remaining_stack);
|
||||
loop$acc = listPrepend(bits, acc);
|
||||
} else {
|
||||
let remaining_stack = stack.tail;
|
||||
let rest = $.tail;
|
||||
let trees = $1[0];
|
||||
loop$stack = listPrepend(trees, listPrepend(rest, remaining_stack));
|
||||
loop$acc = acc;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Turns a bytes tree into a bit array.
|
||||
*
|
||||
* Runs in linear time.
|
||||
*
|
||||
* When running on Erlang this function is implemented natively by the
|
||||
* virtual machine and is highly optimised.
|
||||
*/
|
||||
export function to_bit_array(tree) {
|
||||
let _pipe = toList([toList([tree])]);
|
||||
let _pipe$1 = to_list(_pipe, toList([]));
|
||||
let _pipe$2 = $list.reverse(_pipe$1);
|
||||
return $bit_array.concat(_pipe$2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the size of the bytes tree's content in bytes.
|
||||
*
|
||||
* Runs in linear time.
|
||||
*/
|
||||
export function byte_size(tree) {
|
||||
let _pipe = toList([toList([tree])]);
|
||||
let _pipe$1 = to_list(_pipe, toList([]));
|
||||
return $list.fold(
|
||||
_pipe$1,
|
||||
0,
|
||||
(acc, bits) => { return $bit_array.byte_size(bits) + acc; },
|
||||
);
|
||||
}
|
||||
534
build/dev/javascript/gleam_stdlib/gleam/dict.mjs
Normal file
534
build/dev/javascript/gleam_stdlib/gleam/dict.mjs
Normal file
|
|
@ -0,0 +1,534 @@
|
|||
import { Ok, Error, toList, Empty as $Empty, prepend as listPrepend, isEqual } from "../gleam.mjs";
|
||||
import * as $option from "../gleam/option.mjs";
|
||||
import {
|
||||
map_size as size,
|
||||
map_to_list as to_list,
|
||||
new_map as new$,
|
||||
map_get as get,
|
||||
map_insert as do_insert,
|
||||
map_remove as do_delete,
|
||||
} from "../gleam_stdlib.mjs";
|
||||
|
||||
export { get, new$, size, to_list };
|
||||
|
||||
/**
|
||||
* Determines whether or not the dict is empty.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* new() |> is_empty
|
||||
* // -> True
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* new() |> insert("b", 1) |> is_empty
|
||||
* // -> False
|
||||
* ```
|
||||
*/
|
||||
export function is_empty(dict) {
|
||||
return size(dict) === 0;
|
||||
}
|
||||
|
||||
function do_has_key(key, dict) {
|
||||
return !isEqual(get(dict, key), new Error(undefined));
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether or not a value present in the dict for a given key.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* new() |> insert("a", 0) |> has_key("a")
|
||||
* // -> True
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* new() |> insert("a", 0) |> has_key("b")
|
||||
* // -> False
|
||||
* ```
|
||||
*/
|
||||
export function has_key(dict, key) {
|
||||
return do_has_key(key, dict);
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts a value into the dict with the given key.
|
||||
*
|
||||
* If the dict already has a value for the given key then the value is
|
||||
* replaced with the new value.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* new() |> insert("a", 0)
|
||||
* // -> from_list([#("a", 0)])
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* new() |> insert("a", 0) |> insert("a", 5)
|
||||
* // -> from_list([#("a", 5)])
|
||||
* ```
|
||||
*/
|
||||
export function insert(dict, key, value) {
|
||||
return do_insert(key, value, dict);
|
||||
}
|
||||
|
||||
function from_list_loop(loop$list, loop$initial) {
|
||||
while (true) {
|
||||
let list = loop$list;
|
||||
let initial = loop$initial;
|
||||
if (list instanceof $Empty) {
|
||||
return initial;
|
||||
} else {
|
||||
let rest = list.tail;
|
||||
let key = list.head[0];
|
||||
let value = list.head[1];
|
||||
loop$list = rest;
|
||||
loop$initial = insert(initial, key, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a list of 2-element tuples `#(key, value)` to a dict.
|
||||
*
|
||||
* If two tuples have the same key the last one in the list will be the one
|
||||
* that is present in the dict.
|
||||
*/
|
||||
export function from_list(list) {
|
||||
return from_list_loop(list, new$());
|
||||
}
|
||||
|
||||
function reverse_and_concat(loop$remaining, loop$accumulator) {
|
||||
while (true) {
|
||||
let remaining = loop$remaining;
|
||||
let accumulator = loop$accumulator;
|
||||
if (remaining instanceof $Empty) {
|
||||
return accumulator;
|
||||
} else {
|
||||
let first = remaining.head;
|
||||
let rest = remaining.tail;
|
||||
loop$remaining = rest;
|
||||
loop$accumulator = listPrepend(first, accumulator);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function do_keys_loop(loop$list, loop$acc) {
|
||||
while (true) {
|
||||
let list = loop$list;
|
||||
let acc = loop$acc;
|
||||
if (list instanceof $Empty) {
|
||||
return reverse_and_concat(acc, toList([]));
|
||||
} else {
|
||||
let rest = list.tail;
|
||||
let key = list.head[0];
|
||||
loop$list = rest;
|
||||
loop$acc = listPrepend(key, acc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a list of all keys in a given dict.
|
||||
*
|
||||
* Dicts are not ordered so the keys are not returned in any specific order. Do
|
||||
* not write code that relies on the order keys are returned by this function
|
||||
* as it may change in later versions of Gleam or Erlang.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* from_list([#("a", 0), #("b", 1)]) |> keys
|
||||
* // -> ["a", "b"]
|
||||
* ```
|
||||
*/
|
||||
export function keys(dict) {
|
||||
return do_keys_loop(to_list(dict), toList([]));
|
||||
}
|
||||
|
||||
function do_values_loop(loop$list, loop$acc) {
|
||||
while (true) {
|
||||
let list = loop$list;
|
||||
let acc = loop$acc;
|
||||
if (list instanceof $Empty) {
|
||||
return reverse_and_concat(acc, toList([]));
|
||||
} else {
|
||||
let rest = list.tail;
|
||||
let value = list.head[1];
|
||||
loop$list = rest;
|
||||
loop$acc = listPrepend(value, acc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a list of all values in a given dict.
|
||||
*
|
||||
* Dicts are not ordered so the values are not returned in any specific order. Do
|
||||
* not write code that relies on the order values are returned by this function
|
||||
* as it may change in later versions of Gleam or Erlang.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* from_list([#("a", 0), #("b", 1)]) |> values
|
||||
* // -> [0, 1]
|
||||
* ```
|
||||
*/
|
||||
export function values(dict) {
|
||||
let list_of_pairs = to_list(dict);
|
||||
return do_values_loop(list_of_pairs, toList([]));
|
||||
}
|
||||
|
||||
function do_take_loop(loop$dict, loop$desired_keys, loop$acc) {
|
||||
while (true) {
|
||||
let dict = loop$dict;
|
||||
let desired_keys = loop$desired_keys;
|
||||
let acc = loop$acc;
|
||||
let insert$1 = (taken, key) => {
|
||||
let $ = get(dict, key);
|
||||
if ($ instanceof Ok) {
|
||||
let value = $[0];
|
||||
return insert(taken, key, value);
|
||||
} else {
|
||||
return taken;
|
||||
}
|
||||
};
|
||||
if (desired_keys instanceof $Empty) {
|
||||
return acc;
|
||||
} else {
|
||||
let first = desired_keys.head;
|
||||
let rest = desired_keys.tail;
|
||||
loop$dict = dict;
|
||||
loop$desired_keys = rest;
|
||||
loop$acc = insert$1(acc, first);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function do_take(desired_keys, dict) {
|
||||
return do_take_loop(dict, desired_keys, new$());
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new dict from a given dict, only including any entries for which the
|
||||
* keys are in a given list.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* from_list([#("a", 0), #("b", 1)])
|
||||
* |> take(["b"])
|
||||
* // -> from_list([#("b", 1)])
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* from_list([#("a", 0), #("b", 1)])
|
||||
* |> take(["a", "b", "c"])
|
||||
* // -> from_list([#("a", 0), #("b", 1)])
|
||||
* ```
|
||||
*/
|
||||
export function take(dict, desired_keys) {
|
||||
return do_take(desired_keys, dict);
|
||||
}
|
||||
|
||||
function insert_pair(dict, pair) {
|
||||
return insert(dict, pair[0], pair[1]);
|
||||
}
|
||||
|
||||
function fold_inserts(loop$new_entries, loop$dict) {
|
||||
while (true) {
|
||||
let new_entries = loop$new_entries;
|
||||
let dict = loop$dict;
|
||||
if (new_entries instanceof $Empty) {
|
||||
return dict;
|
||||
} else {
|
||||
let first = new_entries.head;
|
||||
let rest = new_entries.tail;
|
||||
loop$new_entries = rest;
|
||||
loop$dict = insert_pair(dict, first);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new dict from a pair of given dicts by combining their entries.
|
||||
*
|
||||
* If there are entries with the same keys in both dicts the entry from the
|
||||
* second dict takes precedence.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* let a = from_list([#("a", 0), #("b", 1)])
|
||||
* let b = from_list([#("b", 2), #("c", 3)])
|
||||
* merge(a, b)
|
||||
* // -> from_list([#("a", 0), #("b", 2), #("c", 3)])
|
||||
* ```
|
||||
*/
|
||||
export function merge(dict, new_entries) {
|
||||
let _pipe = new_entries;
|
||||
let _pipe$1 = to_list(_pipe);
|
||||
return fold_inserts(_pipe$1, dict);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new dict from a given dict with all the same entries except for the
|
||||
* one with a given key, if it exists.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* from_list([#("a", 0), #("b", 1)]) |> delete("a")
|
||||
* // -> from_list([#("b", 1)])
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* from_list([#("a", 0), #("b", 1)]) |> delete("c")
|
||||
* // -> from_list([#("a", 0), #("b", 1)])
|
||||
* ```
|
||||
*/
|
||||
export function delete$(dict, key) {
|
||||
return do_delete(key, dict);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new dict from a given dict with all the same entries except any with
|
||||
* keys found in a given list.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* from_list([#("a", 0), #("b", 1)]) |> drop(["a"])
|
||||
* // -> from_list([#("b", 1)])
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* from_list([#("a", 0), #("b", 1)]) |> drop(["c"])
|
||||
* // -> from_list([#("a", 0), #("b", 1)])
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* from_list([#("a", 0), #("b", 1)]) |> drop(["a", "b", "c"])
|
||||
* // -> from_list([])
|
||||
* ```
|
||||
*/
|
||||
export function drop(loop$dict, loop$disallowed_keys) {
|
||||
while (true) {
|
||||
let dict = loop$dict;
|
||||
let disallowed_keys = loop$disallowed_keys;
|
||||
if (disallowed_keys instanceof $Empty) {
|
||||
return dict;
|
||||
} else {
|
||||
let first = disallowed_keys.head;
|
||||
let rest = disallowed_keys.tail;
|
||||
loop$dict = delete$(dict, first);
|
||||
loop$disallowed_keys = rest;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new dict with one entry inserted or updated using a given function.
|
||||
*
|
||||
* If there was not an entry in the dict for the given key then the function
|
||||
* gets `None` as its argument, otherwise it gets `Some(value)`.
|
||||
*
|
||||
* ## Example
|
||||
*
|
||||
* ```gleam
|
||||
* let dict = from_list([#("a", 0)])
|
||||
* let increment = fn(x) {
|
||||
* case x {
|
||||
* Some(i) -> i + 1
|
||||
* None -> 0
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* upsert(dict, "a", increment)
|
||||
* // -> from_list([#("a", 1)])
|
||||
*
|
||||
* upsert(dict, "b", increment)
|
||||
* // -> from_list([#("a", 0), #("b", 0)])
|
||||
* ```
|
||||
*/
|
||||
export function upsert(dict, key, fun) {
|
||||
let $ = get(dict, key);
|
||||
if ($ instanceof Ok) {
|
||||
let value = $[0];
|
||||
return insert(dict, key, fun(new $option.Some(value)));
|
||||
} else {
|
||||
return insert(dict, key, fun(new $option.None()));
|
||||
}
|
||||
}
|
||||
|
||||
function fold_loop(loop$list, loop$initial, loop$fun) {
|
||||
while (true) {
|
||||
let list = loop$list;
|
||||
let initial = loop$initial;
|
||||
let fun = loop$fun;
|
||||
if (list instanceof $Empty) {
|
||||
return initial;
|
||||
} else {
|
||||
let rest = list.tail;
|
||||
let k = list.head[0];
|
||||
let v = list.head[1];
|
||||
loop$list = rest;
|
||||
loop$initial = fun(initial, k, v);
|
||||
loop$fun = fun;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Combines all entries into a single value by calling a given function on each
|
||||
* one.
|
||||
*
|
||||
* Dicts are not ordered so the values are not returned in any specific order. Do
|
||||
* not write code that relies on the order entries are used by this function
|
||||
* as it may change in later versions of Gleam or Erlang.
|
||||
*
|
||||
* # Examples
|
||||
*
|
||||
* ```gleam
|
||||
* let dict = from_list([#("a", 1), #("b", 3), #("c", 9)])
|
||||
* fold(dict, 0, fn(accumulator, key, value) { accumulator + value })
|
||||
* // -> 13
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* import gleam/string
|
||||
*
|
||||
* let dict = from_list([#("a", 1), #("b", 3), #("c", 9)])
|
||||
* fold(dict, "", fn(accumulator, key, value) {
|
||||
* string.append(accumulator, key)
|
||||
* })
|
||||
* // -> "abc"
|
||||
* ```
|
||||
*/
|
||||
export function fold(dict, initial, fun) {
|
||||
return fold_loop(to_list(dict), initial, fun);
|
||||
}
|
||||
|
||||
function do_map_values(f, dict) {
|
||||
let f$1 = (dict, k, v) => { return insert(dict, k, f(k, v)); };
|
||||
return fold(dict, new$(), f$1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates all values in a given dict by calling a given function on each key
|
||||
* and value.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* from_list([#(3, 3), #(2, 4)])
|
||||
* |> map_values(fn(key, value) { key * value })
|
||||
* // -> from_list([#(3, 9), #(2, 8)])
|
||||
* ```
|
||||
*/
|
||||
export function map_values(dict, fun) {
|
||||
return do_map_values(fun, dict);
|
||||
}
|
||||
|
||||
function do_filter(f, dict) {
|
||||
let insert$1 = (dict, k, v) => {
|
||||
let $ = f(k, v);
|
||||
if ($) {
|
||||
return insert(dict, k, v);
|
||||
} else {
|
||||
return dict;
|
||||
}
|
||||
};
|
||||
return fold(dict, new$(), insert$1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new dict from a given dict, minus any entries that a given function
|
||||
* returns `False` for.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* from_list([#("a", 0), #("b", 1)])
|
||||
* |> filter(fn(key, value) { value != 0 })
|
||||
* // -> from_list([#("b", 1)])
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* from_list([#("a", 0), #("b", 1)])
|
||||
* |> filter(fn(key, value) { True })
|
||||
* // -> from_list([#("a", 0), #("b", 1)])
|
||||
* ```
|
||||
*/
|
||||
export function filter(dict, predicate) {
|
||||
return do_filter(predicate, dict);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls a function for each key and value in a dict, discarding the return
|
||||
* value.
|
||||
*
|
||||
* Useful for producing a side effect for every item of a dict.
|
||||
*
|
||||
* ```gleam
|
||||
* import gleam/io
|
||||
*
|
||||
* let dict = from_list([#("a", "apple"), #("b", "banana"), #("c", "cherry")])
|
||||
*
|
||||
* each(dict, fn(k, v) {
|
||||
* io.println(key <> " => " <> value)
|
||||
* })
|
||||
* // -> Nil
|
||||
* // a => apple
|
||||
* // b => banana
|
||||
* // c => cherry
|
||||
* ```
|
||||
*
|
||||
* The order of elements in the iteration is an implementation detail that
|
||||
* should not be relied upon.
|
||||
*/
|
||||
export function each(dict, fun) {
|
||||
return fold(
|
||||
dict,
|
||||
undefined,
|
||||
(nil, k, v) => {
|
||||
fun(k, v);
|
||||
return nil;
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new dict from a pair of given dicts by combining their entries.
|
||||
*
|
||||
* If there are entries with the same keys in both dicts the given function is
|
||||
* used to determine the new value to use in the resulting dict.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* let a = from_list([#("a", 0), #("b", 1)])
|
||||
* let b = from_list([#("a", 2), #("c", 3)])
|
||||
* combine(a, b, fn(one, other) { one + other })
|
||||
* // -> from_list([#("a", 2), #("b", 1), #("c", 3)])
|
||||
* ```
|
||||
*/
|
||||
export function combine(dict, other, fun) {
|
||||
return fold(
|
||||
dict,
|
||||
other,
|
||||
(acc, key, value) => {
|
||||
let $ = get(acc, key);
|
||||
if ($ instanceof Ok) {
|
||||
let other_value = $[0];
|
||||
return insert(acc, key, fun(value, other_value));
|
||||
} else {
|
||||
return insert(acc, key, value);
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
35
build/dev/javascript/gleam_stdlib/gleam/dynamic.mjs
Normal file
35
build/dev/javascript/gleam_stdlib/gleam/dynamic.mjs
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
import * as $dict from "../gleam/dict.mjs";
|
||||
import {
|
||||
classify_dynamic as classify,
|
||||
identity as bool,
|
||||
identity as string,
|
||||
identity as float,
|
||||
identity as int,
|
||||
identity as bit_array,
|
||||
identity as list,
|
||||
list_to_array as array,
|
||||
identity as cast,
|
||||
} from "../gleam_stdlib.mjs";
|
||||
|
||||
export { array, bit_array, bool, classify, float, int, list, string };
|
||||
|
||||
/**
|
||||
* Create a dynamic value made an unordered series of keys and values, where
|
||||
* the keys are unique.
|
||||
*
|
||||
* On Erlang this will be a map, on JavaScript this will be a Gleam dict
|
||||
* object.
|
||||
*/
|
||||
export function properties(entries) {
|
||||
return cast($dict.from_list(entries));
|
||||
}
|
||||
|
||||
/**
|
||||
* A dynamic value representing nothing.
|
||||
*
|
||||
* On Erlang this will be the atom `nil`, on JavaScript this will be
|
||||
* `undefined`.
|
||||
*/
|
||||
export function nil() {
|
||||
return cast(undefined);
|
||||
}
|
||||
947
build/dev/javascript/gleam_stdlib/gleam/dynamic/decode.mjs
Normal file
947
build/dev/javascript/gleam_stdlib/gleam/dynamic/decode.mjs
Normal file
|
|
@ -0,0 +1,947 @@
|
|||
import {
|
||||
Ok,
|
||||
Error,
|
||||
toList,
|
||||
Empty as $Empty,
|
||||
prepend as listPrepend,
|
||||
CustomType as $CustomType,
|
||||
isEqual,
|
||||
} from "../../gleam.mjs";
|
||||
import * as $bit_array from "../../gleam/bit_array.mjs";
|
||||
import * as $dict from "../../gleam/dict.mjs";
|
||||
import * as $dynamic from "../../gleam/dynamic.mjs";
|
||||
import * as $int from "../../gleam/int.mjs";
|
||||
import * as $list from "../../gleam/list.mjs";
|
||||
import * as $option from "../../gleam/option.mjs";
|
||||
import { None, Some } from "../../gleam/option.mjs";
|
||||
import {
|
||||
index as bare_index,
|
||||
int as dynamic_int,
|
||||
float as dynamic_float,
|
||||
bit_array as dynamic_bit_array,
|
||||
list as decode_list,
|
||||
dict as decode_dict,
|
||||
identity as cast,
|
||||
is_null,
|
||||
string as dynamic_string,
|
||||
} from "../../gleam_stdlib.mjs";
|
||||
|
||||
export class DecodeError extends $CustomType {
|
||||
constructor(expected, found, path) {
|
||||
super();
|
||||
this.expected = expected;
|
||||
this.found = found;
|
||||
this.path = path;
|
||||
}
|
||||
}
|
||||
export const DecodeError$DecodeError = (expected, found, path) =>
|
||||
new DecodeError(expected, found, path);
|
||||
export const DecodeError$isDecodeError = (value) =>
|
||||
value instanceof DecodeError;
|
||||
export const DecodeError$DecodeError$expected = (value) => value.expected;
|
||||
export const DecodeError$DecodeError$0 = (value) => value.expected;
|
||||
export const DecodeError$DecodeError$found = (value) => value.found;
|
||||
export const DecodeError$DecodeError$1 = (value) => value.found;
|
||||
export const DecodeError$DecodeError$path = (value) => value.path;
|
||||
export const DecodeError$DecodeError$2 = (value) => value.path;
|
||||
|
||||
class Decoder extends $CustomType {
|
||||
constructor(function$) {
|
||||
super();
|
||||
this.function = function$;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Run a decoder on a `Dynamic` value, decoding the value if it is of the
|
||||
* desired type, or returning errors.
|
||||
*
|
||||
* # Examples
|
||||
*
|
||||
* ```gleam
|
||||
* let decoder = {
|
||||
* use name <- decode.field("email", decode.string)
|
||||
* use email <- decode.field("password", decode.string)
|
||||
* decode.success(SignUp(name: name, email: email))
|
||||
* }
|
||||
*
|
||||
* decode.run(data, decoder)
|
||||
* ```
|
||||
*/
|
||||
export function run(data, decoder) {
|
||||
let $ = decoder.function(data);
|
||||
let maybe_invalid_data;
|
||||
let errors;
|
||||
maybe_invalid_data = $[0];
|
||||
errors = $[1];
|
||||
if (errors instanceof $Empty) {
|
||||
return new Ok(maybe_invalid_data);
|
||||
} else {
|
||||
return new Error(errors);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Finalise a decoder having successfully extracted a value.
|
||||
*
|
||||
* # Examples
|
||||
*
|
||||
* ```gleam
|
||||
* let data = dynamic.properties([
|
||||
* #(dynamic.string("email"), dynamic.string("lucy@example.com")),
|
||||
* #(dynamic.string("name"), dynamic.string("Lucy")),
|
||||
* ]))
|
||||
*
|
||||
* let decoder = {
|
||||
* use name <- decode.field("name", string)
|
||||
* use email <- decode.field("email", string)
|
||||
* decode.success(SignUp(name: name, email: email))
|
||||
* }
|
||||
*
|
||||
* let result = decode.run(data, decoder)
|
||||
* assert result == Ok(SignUp(name: "Lucy", email: "lucy@example.com"))
|
||||
* ```
|
||||
*/
|
||||
export function success(data) {
|
||||
return new Decoder((_) => { return [data, toList([])]; });
|
||||
}
|
||||
|
||||
function decode_dynamic(data) {
|
||||
return [data, toList([])];
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply a transformation function to any value decoded by the decoder.
|
||||
*
|
||||
* # Examples
|
||||
*
|
||||
* ```gleam
|
||||
* let decoder = decode.int |> decode.map(int.to_string)
|
||||
* let result = decode.run(dynamic.int(1000), decoder)
|
||||
* assert result == Ok("1000")
|
||||
* ```
|
||||
*/
|
||||
export function map(decoder, transformer) {
|
||||
return new Decoder(
|
||||
(d) => {
|
||||
let $ = decoder.function(d);
|
||||
let data;
|
||||
let errors;
|
||||
data = $[0];
|
||||
errors = $[1];
|
||||
return [transformer(data), errors];
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply a transformation function to any errors returned by the decoder.
|
||||
*/
|
||||
export function map_errors(decoder, transformer) {
|
||||
return new Decoder(
|
||||
(d) => {
|
||||
let $ = decoder.function(d);
|
||||
let data;
|
||||
let errors;
|
||||
data = $[0];
|
||||
errors = $[1];
|
||||
return [data, transformer(errors)];
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new decoder based upon the value of a previous decoder.
|
||||
*
|
||||
* This may be useful to run one previous decoder to use in further decoding.
|
||||
*/
|
||||
export function then$(decoder, next) {
|
||||
return new Decoder(
|
||||
(dynamic_data) => {
|
||||
let $ = decoder.function(dynamic_data);
|
||||
let data;
|
||||
let errors;
|
||||
data = $[0];
|
||||
errors = $[1];
|
||||
let decoder$1 = next(data);
|
||||
let $1 = decoder$1.function(dynamic_data);
|
||||
let layer;
|
||||
let data$1;
|
||||
layer = $1;
|
||||
data$1 = $1[0];
|
||||
if (errors instanceof $Empty) {
|
||||
return layer;
|
||||
} else {
|
||||
return [data$1, errors];
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
function run_decoders(loop$data, loop$failure, loop$decoders) {
|
||||
while (true) {
|
||||
let data = loop$data;
|
||||
let failure = loop$failure;
|
||||
let decoders = loop$decoders;
|
||||
if (decoders instanceof $Empty) {
|
||||
return failure;
|
||||
} else {
|
||||
let decoder = decoders.head;
|
||||
let decoders$1 = decoders.tail;
|
||||
let $ = decoder.function(data);
|
||||
let layer;
|
||||
let errors;
|
||||
layer = $;
|
||||
errors = $[1];
|
||||
if (errors instanceof $Empty) {
|
||||
return layer;
|
||||
} else {
|
||||
loop$data = data;
|
||||
loop$failure = failure;
|
||||
loop$decoders = decoders$1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new decoder from several other decoders. Each of the inner
|
||||
* decoders is run in turn, and the value from the first to succeed is used.
|
||||
*
|
||||
* If no decoder succeeds then the errors from the first decoder is used.
|
||||
* If you wish for different errors then you may wish to use the
|
||||
* `collapse_errors` or `map_errors` functions.
|
||||
*
|
||||
* # Examples
|
||||
*
|
||||
* ```gleam
|
||||
* let decoder = decode.one_of(decode.string, or: [
|
||||
* decode.int |> decode.map(int.to_string),
|
||||
* decode.float |> decode.map(float.to_string),
|
||||
* ])
|
||||
* decode.run(dynamic.int(1000), decoder)
|
||||
* // -> Ok("1000")
|
||||
* ```
|
||||
*/
|
||||
export function one_of(first, alternatives) {
|
||||
return new Decoder(
|
||||
(dynamic_data) => {
|
||||
let $ = first.function(dynamic_data);
|
||||
let layer;
|
||||
let errors;
|
||||
layer = $;
|
||||
errors = $[1];
|
||||
if (errors instanceof $Empty) {
|
||||
return layer;
|
||||
} else {
|
||||
return run_decoders(dynamic_data, layer, alternatives);
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a decoder that can refer to itself, useful for decoding deeply
|
||||
* nested data.
|
||||
*
|
||||
* Attempting to create a recursive decoder without this function could result
|
||||
* in an infinite loop. If you are using `field` or other `use`able functions
|
||||
* then you may not need to use this function.
|
||||
*
|
||||
* ```gleam
|
||||
* type Nested {
|
||||
* Nested(List(Nested))
|
||||
* Value(String)
|
||||
* }
|
||||
*
|
||||
* fn nested_decoder() -> decode.Decoder(Nested) {
|
||||
* use <- decode.recursive
|
||||
* decode.one_of(decode.string |> decode.map(Value), [
|
||||
* decode.list(nested_decoder()) |> decode.map(Nested),
|
||||
* ])
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
export function recursive(inner) {
|
||||
return new Decoder(
|
||||
(data) => {
|
||||
let decoder = inner();
|
||||
return decoder.function(data);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* A decoder that decodes nullable values of a type decoded by with a given
|
||||
* decoder.
|
||||
*
|
||||
* This function can handle common representations of null on all runtimes, such as
|
||||
* `nil`, `null`, and `undefined` on Erlang, and `undefined` and `null` on
|
||||
* JavaScript.
|
||||
*
|
||||
* # Examples
|
||||
*
|
||||
* ```gleam
|
||||
* let result = decode.run(dynamic.int(100), decode.optional(decode.int))
|
||||
* assert result == Ok(option.Some(100))
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* let result = decode.run(dynamic.nil(), decode.optional(decode.int))
|
||||
* assert result == Ok(option.None)
|
||||
* ```
|
||||
*/
|
||||
export function optional(inner) {
|
||||
return new Decoder(
|
||||
(data) => {
|
||||
let $ = is_null(data);
|
||||
if ($) {
|
||||
return [new $option.None(), toList([])];
|
||||
} else {
|
||||
let $1 = inner.function(data);
|
||||
let data$1;
|
||||
let errors;
|
||||
data$1 = $1[0];
|
||||
errors = $1[1];
|
||||
return [new $option.Some(data$1), errors];
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* A decoder that decodes `Dynamic` values. This decoder never returns an error.
|
||||
*
|
||||
* # Examples
|
||||
*
|
||||
* ```gleam
|
||||
* let result = decode.run(dynamic.float(3.14), decode.dynamic)
|
||||
* assert result == Ok(dynamic.float(3.14))
|
||||
* ```
|
||||
*/
|
||||
export const dynamic = /* @__PURE__ */ new Decoder(decode_dynamic);
|
||||
|
||||
/**
|
||||
* Construct a decode error for some unexpected dynamic data.
|
||||
*/
|
||||
export function decode_error(expected, found) {
|
||||
return toList([
|
||||
new DecodeError(expected, $dynamic.classify(found), toList([])),
|
||||
]);
|
||||
}
|
||||
|
||||
function run_dynamic_function(data, name, f) {
|
||||
let $ = f(data);
|
||||
if ($ instanceof Ok) {
|
||||
let data$1 = $[0];
|
||||
return [data$1, toList([])];
|
||||
} else {
|
||||
let zero = $[0];
|
||||
return [
|
||||
zero,
|
||||
toList([new DecodeError(name, $dynamic.classify(data), toList([]))]),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
function decode_bool(data) {
|
||||
let $ = isEqual(cast(true), data);
|
||||
if ($) {
|
||||
return [true, toList([])];
|
||||
} else {
|
||||
let $1 = isEqual(cast(false), data);
|
||||
if ($1) {
|
||||
return [false, toList([])];
|
||||
} else {
|
||||
return [false, decode_error("Bool", data)];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function decode_int(data) {
|
||||
return run_dynamic_function(data, "Int", dynamic_int);
|
||||
}
|
||||
|
||||
function decode_float(data) {
|
||||
return run_dynamic_function(data, "Float", dynamic_float);
|
||||
}
|
||||
|
||||
function decode_bit_array(data) {
|
||||
return run_dynamic_function(data, "BitArray", dynamic_bit_array);
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace all errors produced by a decoder with one single error for a named
|
||||
* expected type.
|
||||
*
|
||||
* This function may be useful if you wish to simplify errors before
|
||||
* presenting them to a user, particularly when using the `one_of` function.
|
||||
*
|
||||
* # Examples
|
||||
*
|
||||
* ```gleam
|
||||
* let decoder = decode.string |> decode.collapse_errors("MyThing")
|
||||
* let result = decode.run(dynamic.int(1000), decoder)
|
||||
* assert result == Error([DecodeError("MyThing", "Int", [])])
|
||||
* ```
|
||||
*/
|
||||
export function collapse_errors(decoder, name) {
|
||||
return new Decoder(
|
||||
(dynamic_data) => {
|
||||
let $ = decoder.function(dynamic_data);
|
||||
let layer;
|
||||
let data;
|
||||
let errors;
|
||||
layer = $;
|
||||
data = $[0];
|
||||
errors = $[1];
|
||||
if (errors instanceof $Empty) {
|
||||
return layer;
|
||||
} else {
|
||||
return [data, decode_error(name, dynamic_data)];
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Define a decoder that always fails. The parameter for this function is the
|
||||
* name of the type that has failed to decode.
|
||||
*/
|
||||
export function failure(zero, expected) {
|
||||
return new Decoder((d) => { return [zero, decode_error(expected, d)]; });
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a decoder for a new data type from a decoding function.
|
||||
*
|
||||
* This function is used for new primitive types. For example, you might
|
||||
* define a decoder for Erlang's pid type.
|
||||
*
|
||||
* A default "zero" value is also required to make a decoder. When this
|
||||
* decoder is used as part of a larger decoder this zero value used as
|
||||
* a placeholder so that the rest of the decoder can continue to run and
|
||||
* collect all decoding errors.
|
||||
*
|
||||
* If you were to make a decoder for the `String` type (rather than using the
|
||||
* build-in `string` decoder) you would define it like so:
|
||||
*
|
||||
* ```gleam
|
||||
* pub fn string_decoder() -> decode.Decoder(String) {
|
||||
* let default = ""
|
||||
* decode.new_primitive_decoder("String", fn(data) {
|
||||
* case dynamic.string(data) {
|
||||
* Ok(x) -> Ok(x)
|
||||
* Error(_) -> Error(default)
|
||||
* }
|
||||
* })
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
export function new_primitive_decoder(name, decoding_function) {
|
||||
return new Decoder(
|
||||
(d) => {
|
||||
let $ = decoding_function(d);
|
||||
if ($ instanceof Ok) {
|
||||
let t = $[0];
|
||||
return [t, toList([])];
|
||||
} else {
|
||||
let zero = $[0];
|
||||
return [
|
||||
zero,
|
||||
toList([new DecodeError(name, $dynamic.classify(d), toList([]))]),
|
||||
];
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* A decoder that decodes `Bool` values.
|
||||
*
|
||||
* # Examples
|
||||
*
|
||||
* ```gleam
|
||||
* let result = decode.run(dynamic.bool(True), decode.bool)
|
||||
* assert result == Ok(True)
|
||||
* ```
|
||||
*/
|
||||
export const bool = /* @__PURE__ */ new Decoder(decode_bool);
|
||||
|
||||
/**
|
||||
* A decoder that decodes `Int` values.
|
||||
*
|
||||
* # Examples
|
||||
*
|
||||
* ```gleam
|
||||
* let result = decode.run(dynamic.int(147), decode.int)
|
||||
* assert result == Ok(147)
|
||||
* ```
|
||||
*/
|
||||
export const int = /* @__PURE__ */ new Decoder(decode_int);
|
||||
|
||||
/**
|
||||
* A decoder that decodes `Float` values.
|
||||
*
|
||||
* # Examples
|
||||
*
|
||||
* ```gleam
|
||||
* let result = decode.run(dynamic.float(3.14), decode.float)
|
||||
* assert result == Ok(3.14)
|
||||
* ```
|
||||
*/
|
||||
export const float = /* @__PURE__ */ new Decoder(decode_float);
|
||||
|
||||
/**
|
||||
* A decoder that decodes `BitArray` values. This decoder never returns an error.
|
||||
*
|
||||
* # Examples
|
||||
*
|
||||
* ```gleam
|
||||
* let result = decode.run(dynamic.bit_array(<<5, 7>>), decode.bit_array)
|
||||
* assert result == Ok(<<5, 7>>)
|
||||
* ```
|
||||
*/
|
||||
export const bit_array = /* @__PURE__ */ new Decoder(decode_bit_array);
|
||||
|
||||
function decode_string(data) {
|
||||
return run_dynamic_function(data, "String", dynamic_string);
|
||||
}
|
||||
|
||||
/**
|
||||
* A decoder that decodes `String` values.
|
||||
*
|
||||
* # Examples
|
||||
*
|
||||
* ```gleam
|
||||
* let result = decode.run(dynamic.string("Hello!"), decode.string)
|
||||
* assert result == Ok("Hello!")
|
||||
* ```
|
||||
*/
|
||||
export const string = /* @__PURE__ */ new Decoder(decode_string);
|
||||
|
||||
function fold_dict(acc, key, value, key_decoder, value_decoder) {
|
||||
let $ = key_decoder(key);
|
||||
let $1 = $[1];
|
||||
if ($1 instanceof $Empty) {
|
||||
let key$1 = $[0];
|
||||
let $2 = value_decoder(value);
|
||||
let $3 = $2[1];
|
||||
if ($3 instanceof $Empty) {
|
||||
let value$1 = $2[0];
|
||||
let dict$1 = $dict.insert(acc[0], key$1, value$1);
|
||||
return [dict$1, acc[1]];
|
||||
} else {
|
||||
let errors = $3;
|
||||
return push_path([$dict.new$(), errors], toList(["values"]));
|
||||
}
|
||||
} else {
|
||||
let errors = $1;
|
||||
return push_path([$dict.new$(), errors], toList(["keys"]));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A decoder that decodes dicts where all keys and vales are decoded with
|
||||
* given decoders.
|
||||
*
|
||||
* # Examples
|
||||
*
|
||||
* ```gleam
|
||||
* let values = dynamic.properties([
|
||||
* #(dynamic.string("one"), dynamic.int(1)),
|
||||
* #(dynamic.string("two"), dynamic.int(2)),
|
||||
* ])
|
||||
*
|
||||
* let result =
|
||||
* decode.run(values, decode.dict(decode.string, decode.int))
|
||||
* assert result == Ok(values)
|
||||
* ```
|
||||
*/
|
||||
export function dict(key, value) {
|
||||
return new Decoder(
|
||||
(data) => {
|
||||
let $ = decode_dict(data);
|
||||
if ($ instanceof Ok) {
|
||||
let dict$1 = $[0];
|
||||
return $dict.fold(
|
||||
dict$1,
|
||||
[$dict.new$(), toList([])],
|
||||
(a, k, v) => {
|
||||
let $1 = a[1];
|
||||
if ($1 instanceof $Empty) {
|
||||
return fold_dict(a, k, v, key.function, value.function);
|
||||
} else {
|
||||
return a;
|
||||
}
|
||||
},
|
||||
);
|
||||
} else {
|
||||
return [$dict.new$(), decode_error("Dict", data)];
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* A decoder that decodes lists where all elements are decoded with a given
|
||||
* decoder.
|
||||
*
|
||||
* # Examples
|
||||
*
|
||||
* ```gleam
|
||||
* let result =
|
||||
* [1, 2, 3]
|
||||
* |> list.map(dynamic.int)
|
||||
* |> dynamic.list
|
||||
* |> decode.run(decode.list(of: decode.int))
|
||||
* assert result == Ok([1, 2, 3])
|
||||
* ```
|
||||
*/
|
||||
export function list(inner) {
|
||||
return new Decoder(
|
||||
(data) => {
|
||||
return decode_list(
|
||||
data,
|
||||
inner.function,
|
||||
(p, k) => { return push_path(p, toList([k])); },
|
||||
0,
|
||||
toList([]),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
function push_path(layer, path) {
|
||||
let decoder = one_of(
|
||||
string,
|
||||
toList([
|
||||
(() => {
|
||||
let _pipe = int;
|
||||
return map(_pipe, $int.to_string);
|
||||
})(),
|
||||
]),
|
||||
);
|
||||
let path$1 = $list.map(
|
||||
path,
|
||||
(key) => {
|
||||
let key$1 = cast(key);
|
||||
let $ = run(key$1, decoder);
|
||||
if ($ instanceof Ok) {
|
||||
let key$2 = $[0];
|
||||
return key$2;
|
||||
} else {
|
||||
return ("<" + $dynamic.classify(key$1)) + ">";
|
||||
}
|
||||
},
|
||||
);
|
||||
let errors = $list.map(
|
||||
layer[1],
|
||||
(error) => {
|
||||
return new DecodeError(
|
||||
error.expected,
|
||||
error.found,
|
||||
$list.append(path$1, error.path),
|
||||
);
|
||||
},
|
||||
);
|
||||
return [layer[0], errors];
|
||||
}
|
||||
|
||||
function index(
|
||||
loop$path,
|
||||
loop$position,
|
||||
loop$inner,
|
||||
loop$data,
|
||||
loop$handle_miss
|
||||
) {
|
||||
while (true) {
|
||||
let path = loop$path;
|
||||
let position = loop$position;
|
||||
let inner = loop$inner;
|
||||
let data = loop$data;
|
||||
let handle_miss = loop$handle_miss;
|
||||
if (path instanceof $Empty) {
|
||||
let _pipe = data;
|
||||
let _pipe$1 = inner(_pipe);
|
||||
return push_path(_pipe$1, $list.reverse(position));
|
||||
} else {
|
||||
let key = path.head;
|
||||
let path$1 = path.tail;
|
||||
let $ = bare_index(data, key);
|
||||
if ($ instanceof Ok) {
|
||||
let $1 = $[0];
|
||||
if ($1 instanceof Some) {
|
||||
let data$1 = $1[0];
|
||||
loop$path = path$1;
|
||||
loop$position = listPrepend(key, position);
|
||||
loop$inner = inner;
|
||||
loop$data = data$1;
|
||||
loop$handle_miss = handle_miss;
|
||||
} else {
|
||||
return handle_miss(data, listPrepend(key, position));
|
||||
}
|
||||
} else {
|
||||
let kind = $[0];
|
||||
let $1 = inner(data);
|
||||
let default$;
|
||||
default$ = $1[0];
|
||||
let _pipe = [
|
||||
default$,
|
||||
toList([new DecodeError(kind, $dynamic.classify(data), toList([]))]),
|
||||
];
|
||||
return push_path(_pipe, $list.reverse(position));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The same as [`field`](#field), except taking a path to the value rather
|
||||
* than a field name.
|
||||
*
|
||||
* This function will index into dictionaries with any key type, and if the key is
|
||||
* an int then it'll also index into Erlang tuples and JavaScript arrays, and
|
||||
* the first eight elements of Gleam lists.
|
||||
*
|
||||
* # Examples
|
||||
*
|
||||
* ```gleam
|
||||
* let data = dynamic.properties([
|
||||
* #(dynamic.string("data"), dynamic.properties([
|
||||
* #(dynamic.string("email"), dynamic.string("lucy@example.com")),
|
||||
* #(dynamic.string("name"), dynamic.string("Lucy")),
|
||||
* ])
|
||||
* ]))
|
||||
*
|
||||
* let decoder = {
|
||||
* use name <- decode.subfield(["data", "name"], decode.string)
|
||||
* use email <- decode.subfield(["data", "email"], decode.string)
|
||||
* decode.success(SignUp(name: name, email: email))
|
||||
* }
|
||||
* let result = decode.run(data, decoder)
|
||||
* assert result == Ok(SignUp(name: "Lucy", email: "lucy@example.com"))
|
||||
* ```
|
||||
*/
|
||||
export function subfield(field_path, field_decoder, next) {
|
||||
return new Decoder(
|
||||
(data) => {
|
||||
let $ = index(
|
||||
field_path,
|
||||
toList([]),
|
||||
field_decoder.function,
|
||||
data,
|
||||
(data, position) => {
|
||||
let $1 = field_decoder.function(data);
|
||||
let default$;
|
||||
default$ = $1[0];
|
||||
let _pipe = [
|
||||
default$,
|
||||
toList([new DecodeError("Field", "Nothing", toList([]))]),
|
||||
];
|
||||
return push_path(_pipe, $list.reverse(position));
|
||||
},
|
||||
);
|
||||
let out;
|
||||
let errors1;
|
||||
out = $[0];
|
||||
errors1 = $[1];
|
||||
let $1 = next(out).function(data);
|
||||
let out$1;
|
||||
let errors2;
|
||||
out$1 = $1[0];
|
||||
errors2 = $1[1];
|
||||
return [out$1, $list.append(errors1, errors2)];
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* A decoder that decodes a value that is nested within other values. For
|
||||
* example, decoding a value that is within some deeply nested JSON objects.
|
||||
*
|
||||
* This function will index into dictionaries with any key type, and if the key is
|
||||
* an int then it'll also index into Erlang tuples and JavaScript arrays, and
|
||||
* the first eight elements of Gleam lists.
|
||||
*
|
||||
* # Examples
|
||||
*
|
||||
* ```gleam
|
||||
* let decoder = decode.at(["one", "two"], decode.int)
|
||||
*
|
||||
* let data = dynamic.properties([
|
||||
* #(dynamic.string("one"), dynamic.properties([
|
||||
* #(dynamic.string("two"), dynamic.int(1000)),
|
||||
* ])),
|
||||
* ]))
|
||||
*
|
||||
*
|
||||
* decode.run(data, decoder)
|
||||
* // -> Ok(1000)
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* dynamic.nil()
|
||||
* |> decode.run(decode.optional(decode.int))
|
||||
* // -> Ok(option.None)
|
||||
* ```
|
||||
*/
|
||||
export function at(path, inner) {
|
||||
return new Decoder(
|
||||
(data) => {
|
||||
return index(
|
||||
path,
|
||||
toList([]),
|
||||
inner.function,
|
||||
data,
|
||||
(data, position) => {
|
||||
let $ = inner.function(data);
|
||||
let default$;
|
||||
default$ = $[0];
|
||||
let _pipe = [
|
||||
default$,
|
||||
toList([new DecodeError("Field", "Nothing", toList([]))]),
|
||||
];
|
||||
return push_path(_pipe, $list.reverse(position));
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Run a decoder on a field of a `Dynamic` value, decoding the value if it is
|
||||
* of the desired type, or returning errors. An error is returned if there is
|
||||
* no field for the specified key.
|
||||
*
|
||||
* This function will index into dictionaries with any key type, and if the key is
|
||||
* an int then it'll also index into Erlang tuples and JavaScript arrays, and
|
||||
* the first eight elements of Gleam lists.
|
||||
*
|
||||
* # Examples
|
||||
*
|
||||
* ```gleam
|
||||
* let data = dynamic.properties([
|
||||
* #(dynamic.string("email"), dynamic.string("lucy@example.com")),
|
||||
* #(dynamic.string("name"), dynamic.string("Lucy")),
|
||||
* ]))
|
||||
*
|
||||
* let decoder = {
|
||||
* use name <- decode.field("name", string)
|
||||
* use email <- decode.field("email", string)
|
||||
* decode.success(SignUp(name: name, email: email))
|
||||
* }
|
||||
*
|
||||
* let result = decode.run(data, decoder)
|
||||
* assert result == Ok(SignUp(name: "Lucy", email: "lucy@example.com"))
|
||||
* ```
|
||||
*
|
||||
* If you wish to decode a value that is more deeply nested within the dynamic
|
||||
* data, see [`subfield`](#subfield) and [`at`](#at).
|
||||
*
|
||||
* If you wish to return a default in the event that a field is not present,
|
||||
* see [`optional_field`](#optional_field) and / [`optionally_at`](#optionally_at).
|
||||
*/
|
||||
export function field(field_name, field_decoder, next) {
|
||||
return subfield(toList([field_name]), field_decoder, next);
|
||||
}
|
||||
|
||||
/**
|
||||
* Run a decoder on a field of a `Dynamic` value, decoding the value if it is
|
||||
* of the desired type, or returning errors. The given default value is
|
||||
* returned if there is no field for the specified key.
|
||||
*
|
||||
* This function will index into dictionaries with any key type, and if the key is
|
||||
* an int then it'll also index into Erlang tuples and JavaScript arrays, and
|
||||
* the first eight elements of Gleam lists.
|
||||
*
|
||||
* # Examples
|
||||
*
|
||||
* ```gleam
|
||||
* let data = dynamic.properties([
|
||||
* #(dynamic.string("name"), dynamic.string("Lucy")),
|
||||
* ]))
|
||||
*
|
||||
* let decoder = {
|
||||
* use name <- decode.field("name", string)
|
||||
* use email <- decode.optional_field("email", "n/a", string)
|
||||
* decode.success(SignUp(name: name, email: email))
|
||||
* }
|
||||
*
|
||||
* let result = decode.run(data, decoder)
|
||||
* assert result == Ok(SignUp(name: "Lucy", email: "n/a"))
|
||||
* ```
|
||||
*/
|
||||
export function optional_field(key, default$, field_decoder, next) {
|
||||
return new Decoder(
|
||||
(data) => {
|
||||
let _block;
|
||||
let _block$1;
|
||||
let $1 = bare_index(data, key);
|
||||
if ($1 instanceof Ok) {
|
||||
let $2 = $1[0];
|
||||
if ($2 instanceof Some) {
|
||||
let data$1 = $2[0];
|
||||
_block$1 = field_decoder.function(data$1);
|
||||
} else {
|
||||
_block$1 = [default$, toList([])];
|
||||
}
|
||||
} else {
|
||||
let kind = $1[0];
|
||||
_block$1 = [
|
||||
default$,
|
||||
toList([new DecodeError(kind, $dynamic.classify(data), toList([]))]),
|
||||
];
|
||||
}
|
||||
let _pipe = _block$1;
|
||||
_block = push_path(_pipe, toList([key]));
|
||||
let $ = _block;
|
||||
let out;
|
||||
let errors1;
|
||||
out = $[0];
|
||||
errors1 = $[1];
|
||||
let $2 = next(out).function(data);
|
||||
let out$1;
|
||||
let errors2;
|
||||
out$1 = $2[0];
|
||||
errors2 = $2[1];
|
||||
return [out$1, $list.append(errors1, errors2)];
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* A decoder that decodes a value that is nested within other values. For
|
||||
* example, decoding a value that is within some deeply nested JSON objects.
|
||||
*
|
||||
* This function will index into dictionaries with any key type, and if the key is
|
||||
* an int then it'll also index into Erlang tuples and JavaScript arrays, and
|
||||
* the first eight elements of Gleam lists.
|
||||
*
|
||||
* # Examples
|
||||
*
|
||||
* ```gleam
|
||||
* let decoder = decode.optionally_at(["one", "two"], 100, decode.int)
|
||||
*
|
||||
* let data = dynamic.properties([
|
||||
* #(dynamic.string("one"), dynamic.properties([])),
|
||||
* ]))
|
||||
*
|
||||
*
|
||||
* decode.run(data, decoder)
|
||||
* // -> Ok(100)
|
||||
* ```
|
||||
*/
|
||||
export function optionally_at(path, default$, inner) {
|
||||
return new Decoder(
|
||||
(data) => {
|
||||
return index(
|
||||
path,
|
||||
toList([]),
|
||||
inner.function,
|
||||
data,
|
||||
(_, _1) => { return [default$, toList([])]; },
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
553
build/dev/javascript/gleam_stdlib/gleam/float.mjs
Normal file
553
build/dev/javascript/gleam_stdlib/gleam/float.mjs
Normal file
|
|
@ -0,0 +1,553 @@
|
|||
import { Ok, Error, Empty as $Empty, divideFloat } from "../gleam.mjs";
|
||||
import * as $order from "../gleam/order.mjs";
|
||||
import {
|
||||
parse_float as parse,
|
||||
float_to_string as to_string,
|
||||
ceiling,
|
||||
floor,
|
||||
round as js_round,
|
||||
truncate,
|
||||
identity as do_to_float,
|
||||
power as do_power,
|
||||
random_uniform as random,
|
||||
log as do_log,
|
||||
exp as exponential,
|
||||
} from "../gleam_stdlib.mjs";
|
||||
|
||||
export { ceiling, exponential, floor, parse, random, to_string, truncate };
|
||||
|
||||
/**
|
||||
* Compares two `Float`s, returning an `Order`:
|
||||
* `Lt` for lower than, `Eq` for equals, or `Gt` for greater than.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* compare(2.0, 2.3)
|
||||
* // -> Lt
|
||||
* ```
|
||||
*
|
||||
* To handle
|
||||
* [Floating Point Imprecision](https://en.wikipedia.org/wiki/Floating-point_arithmetic#Accuracy_problems)
|
||||
* you may use [`loosely_compare`](#loosely_compare) instead.
|
||||
*/
|
||||
export function compare(a, b) {
|
||||
let $ = a === b;
|
||||
if ($) {
|
||||
return new $order.Eq();
|
||||
} else {
|
||||
let $1 = a < b;
|
||||
if ($1) {
|
||||
return new $order.Lt();
|
||||
} else {
|
||||
return new $order.Gt();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares two `Float`s, returning the smaller of the two.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* min(2.0, 2.3)
|
||||
* // -> 2.0
|
||||
* ```
|
||||
*/
|
||||
export function min(a, b) {
|
||||
let $ = a < b;
|
||||
if ($) {
|
||||
return a;
|
||||
} else {
|
||||
return b;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares two `Float`s, returning the larger of the two.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* max(2.0, 2.3)
|
||||
* // -> 2.3
|
||||
* ```
|
||||
*/
|
||||
export function max(a, b) {
|
||||
let $ = a > b;
|
||||
if ($) {
|
||||
return a;
|
||||
} else {
|
||||
return b;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Restricts a `Float` between a lower and upper bound.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* clamp(1.2, min: 1.4, max: 1.6)
|
||||
* // -> 1.4
|
||||
* ```
|
||||
*/
|
||||
export function clamp(x, min_bound, max_bound) {
|
||||
let _pipe = x;
|
||||
let _pipe$1 = min(_pipe, max_bound);
|
||||
return max(_pipe$1, min_bound);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the absolute value of the input as a `Float`.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* absolute_value(-12.5)
|
||||
* // -> 12.5
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* absolute_value(10.2)
|
||||
* // -> 10.2
|
||||
* ```
|
||||
*/
|
||||
export function absolute_value(x) {
|
||||
let $ = x >= 0.0;
|
||||
if ($) {
|
||||
return x;
|
||||
} else {
|
||||
return 0.0 - x;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares two `Float`s within a tolerance, returning an `Order`:
|
||||
* `Lt` for lower than, `Eq` for equals, or `Gt` for greater than.
|
||||
*
|
||||
* This function allows Float comparison while handling
|
||||
* [Floating Point Imprecision](https://en.wikipedia.org/wiki/Floating-point_arithmetic#Accuracy_problems).
|
||||
*
|
||||
* Notice: For `Float`s the tolerance won't be exact:
|
||||
* `5.3 - 5.0` is not exactly `0.3`.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* loosely_compare(5.0, with: 5.3, tolerating: 0.5)
|
||||
* // -> Eq
|
||||
* ```
|
||||
*
|
||||
* If you want to check only for equality you may use
|
||||
* [`loosely_equals`](#loosely_equals) instead.
|
||||
*/
|
||||
export function loosely_compare(a, b, tolerance) {
|
||||
let difference = absolute_value(a - b);
|
||||
let $ = difference <= tolerance;
|
||||
if ($) {
|
||||
return new $order.Eq();
|
||||
} else {
|
||||
return compare(a, b);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks for equality of two `Float`s within a tolerance,
|
||||
* returning an `Bool`.
|
||||
*
|
||||
* This function allows Float comparison while handling
|
||||
* [Floating Point Imprecision](https://en.wikipedia.org/wiki/Floating-point_arithmetic#Accuracy_problems).
|
||||
*
|
||||
* Notice: For `Float`s the tolerance won't be exact:
|
||||
* `5.3 - 5.0` is not exactly `0.3`.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* loosely_equals(5.0, with: 5.3, tolerating: 0.5)
|
||||
* // -> True
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* loosely_equals(5.0, with: 5.1, tolerating: 0.1)
|
||||
* // -> False
|
||||
* ```
|
||||
*/
|
||||
export function loosely_equals(a, b, tolerance) {
|
||||
let difference = absolute_value(a - b);
|
||||
return difference <= tolerance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the results of the base being raised to the power of the
|
||||
* exponent, as a `Float`.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* power(2.0, -1.0)
|
||||
* // -> Ok(0.5)
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* power(2.0, 2.0)
|
||||
* // -> Ok(4.0)
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* power(8.0, 1.5)
|
||||
* // -> Ok(22.627416997969522)
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* 4.0 |> power(of: 2.0)
|
||||
* // -> Ok(16.0)
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* power(-1.0, 0.5)
|
||||
* // -> Error(Nil)
|
||||
* ```
|
||||
*/
|
||||
export function power(base, exponent) {
|
||||
let fractional = (ceiling(exponent) - exponent) > 0.0;
|
||||
let $ = ((base < 0.0) && fractional) || ((base === 0.0) && (exponent < 0.0));
|
||||
if ($) {
|
||||
return new Error(undefined);
|
||||
} else {
|
||||
return new Ok(do_power(base, exponent));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the square root of the input as a `Float`.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* square_root(4.0)
|
||||
* // -> Ok(2.0)
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* square_root(-16.0)
|
||||
* // -> Error(Nil)
|
||||
* ```
|
||||
*/
|
||||
export function square_root(x) {
|
||||
return power(x, 0.5);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the negative of the value provided.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* negate(1.0)
|
||||
* // -> -1.0
|
||||
* ```
|
||||
*/
|
||||
export function negate(x) {
|
||||
return -1.0 * x;
|
||||
}
|
||||
|
||||
/**
|
||||
* Rounds the value to the nearest whole number as an `Int`.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* round(2.3)
|
||||
* // -> 2
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* round(2.5)
|
||||
* // -> 3
|
||||
* ```
|
||||
*/
|
||||
export function round(x) {
|
||||
let $ = x >= 0.0;
|
||||
if ($) {
|
||||
return js_round(x);
|
||||
} else {
|
||||
return 0 - js_round(negate(x));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the value to a given precision as a `Float`.
|
||||
* The precision is the number of allowed decimal places.
|
||||
* Negative precisions are allowed and force rounding
|
||||
* to the nearest tenth, hundredth, thousandth etc.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* to_precision(2.43434348473, precision: 2)
|
||||
* // -> 2.43
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* to_precision(547890.453444, precision: -3)
|
||||
* // -> 548000.0
|
||||
* ```
|
||||
*/
|
||||
export function to_precision(x, precision) {
|
||||
let $ = precision <= 0;
|
||||
if ($) {
|
||||
let factor = do_power(10.0, do_to_float(- precision));
|
||||
return do_to_float(round(divideFloat(x, factor))) * factor;
|
||||
} else {
|
||||
let factor = do_power(10.0, do_to_float(precision));
|
||||
return divideFloat(do_to_float(round(x * factor)), factor);
|
||||
}
|
||||
}
|
||||
|
||||
function sum_loop(loop$numbers, loop$initial) {
|
||||
while (true) {
|
||||
let numbers = loop$numbers;
|
||||
let initial = loop$initial;
|
||||
if (numbers instanceof $Empty) {
|
||||
return initial;
|
||||
} else {
|
||||
let first = numbers.head;
|
||||
let rest = numbers.tail;
|
||||
loop$numbers = rest;
|
||||
loop$initial = first + initial;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sums a list of `Float`s.
|
||||
*
|
||||
* ## Example
|
||||
*
|
||||
* ```gleam
|
||||
* sum([1.0, 2.2, 3.3])
|
||||
* // -> 6.5
|
||||
* ```
|
||||
*/
|
||||
export function sum(numbers) {
|
||||
return sum_loop(numbers, 0.0);
|
||||
}
|
||||
|
||||
function product_loop(loop$numbers, loop$initial) {
|
||||
while (true) {
|
||||
let numbers = loop$numbers;
|
||||
let initial = loop$initial;
|
||||
if (numbers instanceof $Empty) {
|
||||
return initial;
|
||||
} else {
|
||||
let first = numbers.head;
|
||||
let rest = numbers.tail;
|
||||
loop$numbers = rest;
|
||||
loop$initial = first * initial;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Multiplies a list of `Float`s and returns the product.
|
||||
*
|
||||
* ## Example
|
||||
*
|
||||
* ```gleam
|
||||
* product([2.5, 3.2, 4.2])
|
||||
* // -> 33.6
|
||||
* ```
|
||||
*/
|
||||
export function product(numbers) {
|
||||
return product_loop(numbers, 1.0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the modulo of an float division of inputs as a `Result`.
|
||||
*
|
||||
* Returns division of the inputs as a `Result`: If the given divisor equals
|
||||
* `0`, this function returns an `Error`.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* modulo(13.3, by: 3.3)
|
||||
* // -> Ok(0.1)
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* modulo(-13.3, by: 3.3)
|
||||
* // -> Ok(3.2)
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* modulo(13.3, by: -3.3)
|
||||
* // -> Ok(-3.2)
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* modulo(-13.3, by: -3.3)
|
||||
* // -> Ok(-0.1)
|
||||
* ```
|
||||
*/
|
||||
export function modulo(dividend, divisor) {
|
||||
if (divisor === 0.0) {
|
||||
return new Error(undefined);
|
||||
} else {
|
||||
return new Ok(dividend - (floor(divideFloat(dividend, divisor)) * divisor));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns division of the inputs as a `Result`.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* divide(0.0, 1.0)
|
||||
* // -> Ok(0.0)
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* divide(1.0, 0.0)
|
||||
* // -> Error(Nil)
|
||||
* ```
|
||||
*/
|
||||
export function divide(a, b) {
|
||||
if (b === 0.0) {
|
||||
return new Error(undefined);
|
||||
} else {
|
||||
let b$1 = b;
|
||||
return new Ok(divideFloat(a, b$1));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds two floats together.
|
||||
*
|
||||
* It's the function equivalent of the `+.` operator.
|
||||
* This function is useful in higher order functions or pipes.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* add(1.0, 2.0)
|
||||
* // -> 3.0
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* import gleam/list
|
||||
*
|
||||
* list.fold([1.0, 2.0, 3.0], 0.0, add)
|
||||
* // -> 6.0
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* 3.0 |> add(2.0)
|
||||
* // -> 5.0
|
||||
* ```
|
||||
*/
|
||||
export function add(a, b) {
|
||||
return a + b;
|
||||
}
|
||||
|
||||
/**
|
||||
* Multiplies two floats together.
|
||||
*
|
||||
* It's the function equivalent of the `*.` operator.
|
||||
* This function is useful in higher order functions or pipes.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* multiply(2.0, 4.0)
|
||||
* // -> 8.0
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* import gleam/list
|
||||
*
|
||||
* list.fold([2.0, 3.0, 4.0], 1.0, multiply)
|
||||
* // -> 24.0
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* 3.0 |> multiply(2.0)
|
||||
* // -> 6.0
|
||||
* ```
|
||||
*/
|
||||
export function multiply(a, b) {
|
||||
return a * b;
|
||||
}
|
||||
|
||||
/**
|
||||
* Subtracts one float from another.
|
||||
*
|
||||
* It's the function equivalent of the `-.` operator.
|
||||
* This function is useful in higher order functions or pipes.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* subtract(3.0, 1.0)
|
||||
* // -> 2.0
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* import gleam/list
|
||||
*
|
||||
* list.fold([1.0, 2.0, 3.0], 10.0, subtract)
|
||||
* // -> 4.0
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* 3.0 |> subtract(_, 2.0)
|
||||
* // -> 1.0
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* 3.0 |> subtract(2.0, _)
|
||||
* // -> -1.0
|
||||
* ```
|
||||
*/
|
||||
export function subtract(a, b) {
|
||||
return a - b;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the natural logarithm (base e) of the given as a `Result`. If the
|
||||
* input is less than or equal to 0, returns `Error(Nil)`.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* logarithm(1.0)
|
||||
* // -> Ok(0.0)
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* logarithm(2.718281828459045) // e
|
||||
* // -> Ok(1.0)
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* logarithm(0.0)
|
||||
* // -> Error(Nil)
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* logarithm(-1.0)
|
||||
* // -> Error(Nil)
|
||||
* ```
|
||||
*/
|
||||
export function logarithm(x) {
|
||||
let $ = x <= 0.0;
|
||||
if ($) {
|
||||
return new Error(undefined);
|
||||
} else {
|
||||
return new Ok(do_log(x));
|
||||
}
|
||||
}
|
||||
17
build/dev/javascript/gleam_stdlib/gleam/function.mjs
Normal file
17
build/dev/javascript/gleam_stdlib/gleam/function.mjs
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
/**
|
||||
* Takes a single argument and always returns its input value.
|
||||
*/
|
||||
export function identity(x) {
|
||||
return x;
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes an argument and a single function, calls that function with that
|
||||
* argument and returns that argument instead of the function return value.
|
||||
*
|
||||
* Useful for running synchronous side effects in a pipeline.
|
||||
*/
|
||||
export function tap(arg, effect) {
|
||||
effect(arg);
|
||||
return arg;
|
||||
}
|
||||
816
build/dev/javascript/gleam_stdlib/gleam/int.mjs
Normal file
816
build/dev/javascript/gleam_stdlib/gleam/int.mjs
Normal file
|
|
@ -0,0 +1,816 @@
|
|||
import {
|
||||
Ok,
|
||||
Error,
|
||||
toList,
|
||||
Empty as $Empty,
|
||||
prepend as listPrepend,
|
||||
remainderInt,
|
||||
divideInt,
|
||||
} from "../gleam.mjs";
|
||||
import * as $float from "../gleam/float.mjs";
|
||||
import * as $order from "../gleam/order.mjs";
|
||||
import {
|
||||
parse_int as parse,
|
||||
int_from_base_string as do_base_parse,
|
||||
to_string,
|
||||
int_to_base_string as do_to_base_string,
|
||||
identity as to_float,
|
||||
bitwise_and,
|
||||
bitwise_not,
|
||||
bitwise_or,
|
||||
bitwise_exclusive_or,
|
||||
bitwise_shift_left,
|
||||
bitwise_shift_right,
|
||||
} from "../gleam_stdlib.mjs";
|
||||
|
||||
export {
|
||||
bitwise_and,
|
||||
bitwise_exclusive_or,
|
||||
bitwise_not,
|
||||
bitwise_or,
|
||||
bitwise_shift_left,
|
||||
bitwise_shift_right,
|
||||
parse,
|
||||
to_float,
|
||||
to_string,
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the absolute value of the input.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* absolute_value(-12)
|
||||
* // -> 12
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* absolute_value(10)
|
||||
* // -> 10
|
||||
* ```
|
||||
*/
|
||||
export function absolute_value(x) {
|
||||
let $ = x >= 0;
|
||||
if ($) {
|
||||
return x;
|
||||
} else {
|
||||
return x * -1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a given string as an int in a given base if possible.
|
||||
* Supports only bases 2 to 36, for values outside of which this function returns an `Error(Nil)`.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* base_parse("10", 2)
|
||||
* // -> Ok(2)
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* base_parse("30", 16)
|
||||
* // -> Ok(48)
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* base_parse("1C", 36)
|
||||
* // -> Ok(48)
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* base_parse("48", 1)
|
||||
* // -> Error(Nil)
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* base_parse("48", 37)
|
||||
* // -> Error(Nil)
|
||||
* ```
|
||||
*/
|
||||
export function base_parse(string, base) {
|
||||
let $ = (base >= 2) && (base <= 36);
|
||||
if ($) {
|
||||
return do_base_parse(string, base);
|
||||
} else {
|
||||
return new Error(undefined);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints a given int to a string using the base number provided.
|
||||
* Supports only bases 2 to 36, for values outside of which this function returns an `Error(Nil)`.
|
||||
* For common bases (2, 8, 16, 36), use the `to_baseN` functions.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* to_base_string(2, 2)
|
||||
* // -> Ok("10")
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* to_base_string(48, 16)
|
||||
* // -> Ok("30")
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* to_base_string(48, 36)
|
||||
* // -> Ok("1C")
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* to_base_string(48, 1)
|
||||
* // -> Error(Nil)
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* to_base_string(48, 37)
|
||||
* // -> Error(Nil)
|
||||
* ```
|
||||
*/
|
||||
export function to_base_string(x, base) {
|
||||
let $ = (base >= 2) && (base <= 36);
|
||||
if ($) {
|
||||
return new Ok(do_to_base_string(x, base));
|
||||
} else {
|
||||
return new Error(undefined);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints a given int to a string using base-2.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* to_base2(2)
|
||||
* // -> "10"
|
||||
* ```
|
||||
*/
|
||||
export function to_base2(x) {
|
||||
return do_to_base_string(x, 2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints a given int to a string using base-8.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* to_base8(15)
|
||||
* // -> "17"
|
||||
* ```
|
||||
*/
|
||||
export function to_base8(x) {
|
||||
return do_to_base_string(x, 8);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints a given int to a string using base-16.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* to_base16(48)
|
||||
* // -> "30"
|
||||
* ```
|
||||
*/
|
||||
export function to_base16(x) {
|
||||
return do_to_base_string(x, 16);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints a given int to a string using base-36.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* to_base36(48)
|
||||
* // -> "1C"
|
||||
* ```
|
||||
*/
|
||||
export function to_base36(x) {
|
||||
return do_to_base_string(x, 36);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the results of the base being raised to the power of the
|
||||
* exponent, as a `Float`.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* power(2, -1.0)
|
||||
* // -> Ok(0.5)
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* power(2, 2.0)
|
||||
* // -> Ok(4.0)
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* power(8, 1.5)
|
||||
* // -> Ok(22.627416997969522)
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* 4 |> power(of: 2.0)
|
||||
* // -> Ok(16.0)
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* power(-1, 0.5)
|
||||
* // -> Error(Nil)
|
||||
* ```
|
||||
*/
|
||||
export function power(base, exponent) {
|
||||
let _pipe = base;
|
||||
let _pipe$1 = to_float(_pipe);
|
||||
return $float.power(_pipe$1, exponent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the square root of the input as a `Float`.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* square_root(4)
|
||||
* // -> Ok(2.0)
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* square_root(-16)
|
||||
* // -> Error(Nil)
|
||||
* ```
|
||||
*/
|
||||
export function square_root(x) {
|
||||
let _pipe = x;
|
||||
let _pipe$1 = to_float(_pipe);
|
||||
return $float.square_root(_pipe$1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares two ints, returning an order.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* compare(2, 3)
|
||||
* // -> Lt
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* compare(4, 3)
|
||||
* // -> Gt
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* compare(3, 3)
|
||||
* // -> Eq
|
||||
* ```
|
||||
*/
|
||||
export function compare(a, b) {
|
||||
let $ = a === b;
|
||||
if ($) {
|
||||
return new $order.Eq();
|
||||
} else {
|
||||
let $1 = a < b;
|
||||
if ($1) {
|
||||
return new $order.Lt();
|
||||
} else {
|
||||
return new $order.Gt();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares two ints, returning the smaller of the two.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* min(2, 3)
|
||||
* // -> 2
|
||||
* ```
|
||||
*/
|
||||
export function min(a, b) {
|
||||
let $ = a < b;
|
||||
if ($) {
|
||||
return a;
|
||||
} else {
|
||||
return b;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares two ints, returning the larger of the two.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* max(2, 3)
|
||||
* // -> 3
|
||||
* ```
|
||||
*/
|
||||
export function max(a, b) {
|
||||
let $ = a > b;
|
||||
if ($) {
|
||||
return a;
|
||||
} else {
|
||||
return b;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Restricts an int between a lower and upper bound.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* clamp(40, min: 50, max: 60)
|
||||
* // -> 50
|
||||
* ```
|
||||
*/
|
||||
export function clamp(x, min_bound, max_bound) {
|
||||
let _pipe = x;
|
||||
let _pipe$1 = min(_pipe, max_bound);
|
||||
return max(_pipe$1, min_bound);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the value provided is even.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* is_even(2)
|
||||
* // -> True
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* is_even(3)
|
||||
* // -> False
|
||||
* ```
|
||||
*/
|
||||
export function is_even(x) {
|
||||
return (x % 2) === 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the value provided is odd.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* is_odd(3)
|
||||
* // -> True
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* is_odd(2)
|
||||
* // -> False
|
||||
* ```
|
||||
*/
|
||||
export function is_odd(x) {
|
||||
return (x % 2) !== 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the negative of the value provided.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* negate(1)
|
||||
* // -> -1
|
||||
* ```
|
||||
*/
|
||||
export function negate(x) {
|
||||
return -1 * x;
|
||||
}
|
||||
|
||||
function sum_loop(loop$numbers, loop$initial) {
|
||||
while (true) {
|
||||
let numbers = loop$numbers;
|
||||
let initial = loop$initial;
|
||||
if (numbers instanceof $Empty) {
|
||||
return initial;
|
||||
} else {
|
||||
let first = numbers.head;
|
||||
let rest = numbers.tail;
|
||||
loop$numbers = rest;
|
||||
loop$initial = first + initial;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sums a list of ints.
|
||||
*
|
||||
* ## Example
|
||||
*
|
||||
* ```gleam
|
||||
* sum([1, 2, 3])
|
||||
* // -> 6
|
||||
* ```
|
||||
*/
|
||||
export function sum(numbers) {
|
||||
return sum_loop(numbers, 0);
|
||||
}
|
||||
|
||||
function product_loop(loop$numbers, loop$initial) {
|
||||
while (true) {
|
||||
let numbers = loop$numbers;
|
||||
let initial = loop$initial;
|
||||
if (numbers instanceof $Empty) {
|
||||
return initial;
|
||||
} else {
|
||||
let first = numbers.head;
|
||||
let rest = numbers.tail;
|
||||
loop$numbers = rest;
|
||||
loop$initial = first * initial;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Multiplies a list of ints and returns the product.
|
||||
*
|
||||
* ## Example
|
||||
*
|
||||
* ```gleam
|
||||
* product([2, 3, 4])
|
||||
* // -> 24
|
||||
* ```
|
||||
*/
|
||||
export function product(numbers) {
|
||||
return product_loop(numbers, 1);
|
||||
}
|
||||
|
||||
function digits_loop(loop$x, loop$base, loop$acc) {
|
||||
while (true) {
|
||||
let x = loop$x;
|
||||
let base = loop$base;
|
||||
let acc = loop$acc;
|
||||
let $ = absolute_value(x) < base;
|
||||
if ($) {
|
||||
return listPrepend(x, acc);
|
||||
} else {
|
||||
loop$x = divideInt(x, base);
|
||||
loop$base = base;
|
||||
loop$acc = listPrepend(remainderInt(x, base), acc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function digits(x, base) {
|
||||
let $ = base < 2;
|
||||
if ($) {
|
||||
return new Error(undefined);
|
||||
} else {
|
||||
return new Ok(digits_loop(x, base, toList([])));
|
||||
}
|
||||
}
|
||||
|
||||
function undigits_loop(loop$numbers, loop$base, loop$acc) {
|
||||
while (true) {
|
||||
let numbers = loop$numbers;
|
||||
let base = loop$base;
|
||||
let acc = loop$acc;
|
||||
if (numbers instanceof $Empty) {
|
||||
return new Ok(acc);
|
||||
} else {
|
||||
let digit = numbers.head;
|
||||
if (digit >= base) {
|
||||
return new Error(undefined);
|
||||
} else {
|
||||
let digit$1 = numbers.head;
|
||||
let rest = numbers.tail;
|
||||
loop$numbers = rest;
|
||||
loop$base = base;
|
||||
loop$acc = acc * base + digit$1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function undigits(numbers, base) {
|
||||
let $ = base < 2;
|
||||
if ($) {
|
||||
return new Error(undefined);
|
||||
} else {
|
||||
return undigits_loop(numbers, base, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a random int between zero and the given maximum.
|
||||
*
|
||||
* The lower number is inclusive, the upper number is exclusive.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* random(10)
|
||||
* // -> 4
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* random(1)
|
||||
* // -> 0
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* random(-1)
|
||||
* // -> -1
|
||||
* ```
|
||||
*/
|
||||
export function random(max) {
|
||||
let _pipe = ($float.random() * to_float(max));
|
||||
let _pipe$1 = $float.floor(_pipe);
|
||||
return $float.round(_pipe$1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs a truncated integer division.
|
||||
*
|
||||
* Returns division of the inputs as a `Result`: If the given divisor equals
|
||||
* `0`, this function returns an `Error`.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* divide(0, 1)
|
||||
* // -> Ok(0)
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* divide(1, 0)
|
||||
* // -> Error(Nil)
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* divide(5, 2)
|
||||
* // -> Ok(2)
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* divide(-99, 2)
|
||||
* // -> Ok(-49)
|
||||
* ```
|
||||
*/
|
||||
export function divide(dividend, divisor) {
|
||||
if (divisor === 0) {
|
||||
return new Error(undefined);
|
||||
} else {
|
||||
let divisor$1 = divisor;
|
||||
return new Ok(divideInt(dividend, divisor$1));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the remainder of an integer division of inputs as a `Result`.
|
||||
*
|
||||
* Returns division of the inputs as a `Result`: If the given divisor equals
|
||||
* `0`, this function returns an `Error`.
|
||||
*
|
||||
* Most the time you will want to use the `%` operator instead of this
|
||||
* function.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* remainder(3, 2)
|
||||
* // -> Ok(1)
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* remainder(1, 0)
|
||||
* // -> Error(Nil)
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* remainder(10, -1)
|
||||
* // -> Ok(0)
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* remainder(13, by: 3)
|
||||
* // -> Ok(1)
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* remainder(-13, by: 3)
|
||||
* // -> Ok(-1)
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* remainder(13, by: -3)
|
||||
* // -> Ok(1)
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* remainder(-13, by: -3)
|
||||
* // -> Ok(-1)
|
||||
* ```
|
||||
*/
|
||||
export function remainder(dividend, divisor) {
|
||||
if (divisor === 0) {
|
||||
return new Error(undefined);
|
||||
} else {
|
||||
let divisor$1 = divisor;
|
||||
return new Ok(remainderInt(dividend, divisor$1));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the modulo of an integer division of inputs as a `Result`.
|
||||
*
|
||||
* Returns division of the inputs as a `Result`: If the given divisor equals
|
||||
* `0`, this function returns an `Error`.
|
||||
*
|
||||
* Most the time you will want to use the `%` operator instead of this
|
||||
* function.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* modulo(3, 2)
|
||||
* // -> Ok(1)
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* modulo(1, 0)
|
||||
* // -> Error(Nil)
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* modulo(10, -1)
|
||||
* // -> Ok(0)
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* modulo(13, by: 3)
|
||||
* // -> Ok(1)
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* modulo(-13, by: 3)
|
||||
* // -> Ok(2)
|
||||
* ```
|
||||
*/
|
||||
export function modulo(dividend, divisor) {
|
||||
if (divisor === 0) {
|
||||
return new Error(undefined);
|
||||
} else {
|
||||
let remainder$1 = remainderInt(dividend, divisor);
|
||||
let $ = remainder$1 * divisor < 0;
|
||||
if ($) {
|
||||
return new Ok(remainder$1 + divisor);
|
||||
} else {
|
||||
return new Ok(remainder$1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs a *floored* integer division, which means that the result will
|
||||
* always be rounded towards negative infinity.
|
||||
*
|
||||
* If you want to perform truncated integer division (rounding towards zero),
|
||||
* use `int.divide()` or the `/` operator instead.
|
||||
*
|
||||
* Returns division of the inputs as a `Result`: If the given divisor equals
|
||||
* `0`, this function returns an `Error`.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* floor_divide(1, 0)
|
||||
* // -> Error(Nil)
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* floor_divide(5, 2)
|
||||
* // -> Ok(2)
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* floor_divide(6, -4)
|
||||
* // -> Ok(-2)
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* floor_divide(-99, 2)
|
||||
* // -> Ok(-50)
|
||||
* ```
|
||||
*/
|
||||
export function floor_divide(dividend, divisor) {
|
||||
if (divisor === 0) {
|
||||
return new Error(undefined);
|
||||
} else {
|
||||
let divisor$1 = divisor;
|
||||
let $ = (dividend * divisor$1 < 0) && ((remainderInt(dividend, divisor$1)) !== 0);
|
||||
if ($) {
|
||||
return new Ok((divideInt(dividend, divisor$1)) - 1);
|
||||
} else {
|
||||
return new Ok(divideInt(dividend, divisor$1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds two integers together.
|
||||
*
|
||||
* It's the function equivalent of the `+` operator.
|
||||
* This function is useful in higher order functions or pipes.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* add(1, 2)
|
||||
* // -> 3
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* import gleam/list
|
||||
* list.fold([1, 2, 3], 0, add)
|
||||
* // -> 6
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* 3 |> add(2)
|
||||
* // -> 5
|
||||
* ```
|
||||
*/
|
||||
export function add(a, b) {
|
||||
return a + b;
|
||||
}
|
||||
|
||||
/**
|
||||
* Multiplies two integers together.
|
||||
*
|
||||
* It's the function equivalent of the `*` operator.
|
||||
* This function is useful in higher order functions or pipes.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* multiply(2, 4)
|
||||
* // -> 8
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* import gleam/list
|
||||
*
|
||||
* list.fold([2, 3, 4], 1, multiply)
|
||||
* // -> 24
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* 3 |> multiply(2)
|
||||
* // -> 6
|
||||
* ```
|
||||
*/
|
||||
export function multiply(a, b) {
|
||||
return a * b;
|
||||
}
|
||||
|
||||
/**
|
||||
* Subtracts one int from another.
|
||||
*
|
||||
* It's the function equivalent of the `-` operator.
|
||||
* This function is useful in higher order functions or pipes.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* subtract(3, 1)
|
||||
* // -> 2
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* import gleam/list
|
||||
*
|
||||
* list.fold([1, 2, 3], 10, subtract)
|
||||
* // -> 4
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* 3 |> subtract(2)
|
||||
* // -> 1
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* 3 |> subtract(2, _)
|
||||
* // -> -1
|
||||
* ```
|
||||
*/
|
||||
export function subtract(a, b) {
|
||||
return a - b;
|
||||
}
|
||||
8
build/dev/javascript/gleam_stdlib/gleam/io.mjs
Normal file
8
build/dev/javascript/gleam_stdlib/gleam/io.mjs
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
import {
|
||||
print,
|
||||
print_error,
|
||||
console_log as println,
|
||||
console_error as println_error,
|
||||
} from "../gleam_stdlib.mjs";
|
||||
|
||||
export { print, print_error, println, println_error };
|
||||
3209
build/dev/javascript/gleam_stdlib/gleam/list.mjs
Normal file
3209
build/dev/javascript/gleam_stdlib/gleam/list.mjs
Normal file
File diff suppressed because it is too large
Load diff
419
build/dev/javascript/gleam_stdlib/gleam/option.mjs
Normal file
419
build/dev/javascript/gleam_stdlib/gleam/option.mjs
Normal file
|
|
@ -0,0 +1,419 @@
|
|||
import {
|
||||
Ok,
|
||||
Error,
|
||||
toList,
|
||||
Empty as $Empty,
|
||||
prepend as listPrepend,
|
||||
CustomType as $CustomType,
|
||||
isEqual,
|
||||
} from "../gleam.mjs";
|
||||
|
||||
export class Some extends $CustomType {
|
||||
constructor($0) {
|
||||
super();
|
||||
this[0] = $0;
|
||||
}
|
||||
}
|
||||
export const Option$Some = ($0) => new Some($0);
|
||||
export const Option$isSome = (value) => value instanceof Some;
|
||||
export const Option$Some$0 = (value) => value[0];
|
||||
|
||||
export class None extends $CustomType {}
|
||||
export const Option$None = () => new None();
|
||||
export const Option$isNone = (value) => value instanceof None;
|
||||
|
||||
function reverse_and_prepend(loop$prefix, loop$suffix) {
|
||||
while (true) {
|
||||
let prefix = loop$prefix;
|
||||
let suffix = loop$suffix;
|
||||
if (prefix instanceof $Empty) {
|
||||
return suffix;
|
||||
} else {
|
||||
let first = prefix.head;
|
||||
let rest = prefix.tail;
|
||||
loop$prefix = rest;
|
||||
loop$suffix = listPrepend(first, suffix);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function reverse(list) {
|
||||
return reverse_and_prepend(list, toList([]));
|
||||
}
|
||||
|
||||
function all_loop(loop$list, loop$acc) {
|
||||
while (true) {
|
||||
let list = loop$list;
|
||||
let acc = loop$acc;
|
||||
if (list instanceof $Empty) {
|
||||
return new Some(reverse(acc));
|
||||
} else {
|
||||
let $ = list.head;
|
||||
if ($ instanceof Some) {
|
||||
let rest = list.tail;
|
||||
let first = $[0];
|
||||
loop$list = rest;
|
||||
loop$acc = listPrepend(first, acc);
|
||||
} else {
|
||||
return new None();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Combines a list of `Option`s into a single `Option`.
|
||||
* If all elements in the list are `Some` then returns a `Some` holding the list of values.
|
||||
* If any element is `None` then returns`None`.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* all([Some(1), Some(2)])
|
||||
* // -> Some([1, 2])
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* all([Some(1), None])
|
||||
* // -> None
|
||||
* ```
|
||||
*/
|
||||
export function all(list) {
|
||||
return all_loop(list, toList([]));
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the `Option` is a `Some` value.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* is_some(Some(1))
|
||||
* // -> True
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* is_some(None)
|
||||
* // -> False
|
||||
* ```
|
||||
*/
|
||||
export function is_some(option) {
|
||||
return !isEqual(option, new None());
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the `Option` is a `None` value.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* is_none(Some(1))
|
||||
* // -> False
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* is_none(None)
|
||||
* // -> True
|
||||
* ```
|
||||
*/
|
||||
export function is_none(option) {
|
||||
return isEqual(option, new None());
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts an `Option` type to a `Result` type.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* to_result(Some(1), "some_error")
|
||||
* // -> Ok(1)
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* to_result(None, "some_error")
|
||||
* // -> Error("some_error")
|
||||
* ```
|
||||
*/
|
||||
export function to_result(option, e) {
|
||||
if (option instanceof Some) {
|
||||
let a = option[0];
|
||||
return new Ok(a);
|
||||
} else {
|
||||
return new Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a `Result` type to an `Option` type.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* from_result(Ok(1))
|
||||
* // -> Some(1)
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* from_result(Error("some_error"))
|
||||
* // -> None
|
||||
* ```
|
||||
*/
|
||||
export function from_result(result) {
|
||||
if (result instanceof Ok) {
|
||||
let a = result[0];
|
||||
return new Some(a);
|
||||
} else {
|
||||
return new None();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the value from an `Option`, returning a default value if there is none.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* unwrap(Some(1), 0)
|
||||
* // -> 1
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* unwrap(None, 0)
|
||||
* // -> 0
|
||||
* ```
|
||||
*/
|
||||
export function unwrap(option, default$) {
|
||||
if (option instanceof Some) {
|
||||
let x = option[0];
|
||||
return x;
|
||||
} else {
|
||||
return default$;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the value from an `Option`, evaluating the default function if the option is `None`.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* lazy_unwrap(Some(1), fn() { 0 })
|
||||
* // -> 1
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* lazy_unwrap(None, fn() { 0 })
|
||||
* // -> 0
|
||||
* ```
|
||||
*/
|
||||
export function lazy_unwrap(option, default$) {
|
||||
if (option instanceof Some) {
|
||||
let x = option[0];
|
||||
return x;
|
||||
} else {
|
||||
return default$();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates a value held within the `Some` of an `Option` by calling a given function
|
||||
* on it.
|
||||
*
|
||||
* If the `Option` is a `None` rather than `Some`, the function is not called and the
|
||||
* `Option` stays the same.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* map(over: Some(1), with: fn(x) { x + 1 })
|
||||
* // -> Some(2)
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* map(over: None, with: fn(x) { x + 1 })
|
||||
* // -> None
|
||||
* ```
|
||||
*/
|
||||
export function map(option, fun) {
|
||||
if (option instanceof Some) {
|
||||
let x = option[0];
|
||||
return new Some(fun(x));
|
||||
} else {
|
||||
return option;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Merges a nested `Option` into a single layer.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* flatten(Some(Some(1)))
|
||||
* // -> Some(1)
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* flatten(Some(None))
|
||||
* // -> None
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* flatten(None)
|
||||
* // -> None
|
||||
* ```
|
||||
*/
|
||||
export function flatten(option) {
|
||||
if (option instanceof Some) {
|
||||
let x = option[0];
|
||||
return x;
|
||||
} else {
|
||||
return option;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates a value held within the `Some` of an `Option` by calling a given function
|
||||
* on it, where the given function also returns an `Option`. The two options are
|
||||
* then merged together into one `Option`.
|
||||
*
|
||||
* If the `Option` is a `None` rather than `Some` the function is not called and the
|
||||
* option stays the same.
|
||||
*
|
||||
* This function is the equivalent of calling `map` followed by `flatten`, and
|
||||
* it is useful for chaining together multiple functions that return `Option`.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* then(Some(1), fn(x) { Some(x + 1) })
|
||||
* // -> Some(2)
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* then(Some(1), fn(x) { Some(#("a", x)) })
|
||||
* // -> Some(#("a", 1))
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* then(Some(1), fn(_) { None })
|
||||
* // -> None
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* then(None, fn(x) { Some(x + 1) })
|
||||
* // -> None
|
||||
* ```
|
||||
*/
|
||||
export function then$(option, fun) {
|
||||
if (option instanceof Some) {
|
||||
let x = option[0];
|
||||
return fun(x);
|
||||
} else {
|
||||
return option;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the first value if it is `Some`, otherwise returns the second value.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* or(Some(1), Some(2))
|
||||
* // -> Some(1)
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* or(Some(1), None)
|
||||
* // -> Some(1)
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* or(None, Some(2))
|
||||
* // -> Some(2)
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* or(None, None)
|
||||
* // -> None
|
||||
* ```
|
||||
*/
|
||||
export function or(first, second) {
|
||||
if (first instanceof Some) {
|
||||
return first;
|
||||
} else {
|
||||
return second;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the first value if it is `Some`, otherwise evaluates the given function for a fallback value.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* lazy_or(Some(1), fn() { Some(2) })
|
||||
* // -> Some(1)
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* lazy_or(Some(1), fn() { None })
|
||||
* // -> Some(1)
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* lazy_or(None, fn() { Some(2) })
|
||||
* // -> Some(2)
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* lazy_or(None, fn() { None })
|
||||
* // -> None
|
||||
* ```
|
||||
*/
|
||||
export function lazy_or(first, second) {
|
||||
if (first instanceof Some) {
|
||||
return first;
|
||||
} else {
|
||||
return second();
|
||||
}
|
||||
}
|
||||
|
||||
function values_loop(loop$list, loop$acc) {
|
||||
while (true) {
|
||||
let list = loop$list;
|
||||
let acc = loop$acc;
|
||||
if (list instanceof $Empty) {
|
||||
return reverse(acc);
|
||||
} else {
|
||||
let $ = list.head;
|
||||
if ($ instanceof Some) {
|
||||
let rest = list.tail;
|
||||
let first = $[0];
|
||||
loop$list = rest;
|
||||
loop$acc = listPrepend(first, acc);
|
||||
} else {
|
||||
let rest = list.tail;
|
||||
loop$list = rest;
|
||||
loop$acc = acc;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a list of `Option`s,
|
||||
* returns only the values inside `Some`.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* values([Some(1), None, Some(3)])
|
||||
* // -> [1, 3]
|
||||
* ```
|
||||
*/
|
||||
export function values(options) {
|
||||
return values_loop(options, toList([]));
|
||||
}
|
||||
178
build/dev/javascript/gleam_stdlib/gleam/order.mjs
Normal file
178
build/dev/javascript/gleam_stdlib/gleam/order.mjs
Normal file
|
|
@ -0,0 +1,178 @@
|
|||
import { CustomType as $CustomType, isEqual } from "../gleam.mjs";
|
||||
|
||||
export class Lt extends $CustomType {}
|
||||
export const Order$Lt = () => new Lt();
|
||||
export const Order$isLt = (value) => value instanceof Lt;
|
||||
|
||||
export class Eq extends $CustomType {}
|
||||
export const Order$Eq = () => new Eq();
|
||||
export const Order$isEq = (value) => value instanceof Eq;
|
||||
|
||||
export class Gt extends $CustomType {}
|
||||
export const Order$Gt = () => new Gt();
|
||||
export const Order$isGt = (value) => value instanceof Gt;
|
||||
|
||||
/**
|
||||
* Inverts an order, so less-than becomes greater-than and greater-than
|
||||
* becomes less-than.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* negate(Lt)
|
||||
* // -> Gt
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* negate(Eq)
|
||||
* // -> Eq
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* negate(Gt)
|
||||
* // -> Lt
|
||||
* ```
|
||||
*/
|
||||
export function negate(order) {
|
||||
if (order instanceof Lt) {
|
||||
return new Gt();
|
||||
} else if (order instanceof Eq) {
|
||||
return order;
|
||||
} else {
|
||||
return new Lt();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Produces a numeric representation of the order.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* to_int(Lt)
|
||||
* // -> -1
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* to_int(Eq)
|
||||
* // -> 0
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* to_int(Gt)
|
||||
* // -> 1
|
||||
* ```
|
||||
*/
|
||||
export function to_int(order) {
|
||||
if (order instanceof Lt) {
|
||||
return -1;
|
||||
} else if (order instanceof Eq) {
|
||||
return 0;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares two `Order` values to one another, producing a new `Order`.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* compare(Eq, with: Lt)
|
||||
* // -> Gt
|
||||
* ```
|
||||
*/
|
||||
export function compare(a, b) {
|
||||
let x = a;
|
||||
let y = b;
|
||||
if (isEqual(x, y)) {
|
||||
return new Eq();
|
||||
} else if (a instanceof Lt) {
|
||||
return new Lt();
|
||||
} else if (a instanceof Eq && b instanceof Gt) {
|
||||
return new Lt();
|
||||
} else {
|
||||
return new Gt();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Inverts an ordering function, so less-than becomes greater-than and greater-than
|
||||
* becomes less-than.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* import gleam/int
|
||||
* import gleam/list
|
||||
*
|
||||
* list.sort([1, 5, 4], by: reverse(int.compare))
|
||||
* // -> [5, 4, 1]
|
||||
* ```
|
||||
*/
|
||||
export function reverse(orderer) {
|
||||
return (a, b) => { return orderer(b, a); };
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a fallback `Order` in case the first argument is `Eq`.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* import gleam/int
|
||||
*
|
||||
* break_tie(in: int.compare(1, 1), with: Lt)
|
||||
* // -> Lt
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* import gleam/int
|
||||
*
|
||||
* break_tie(in: int.compare(1, 0), with: Eq)
|
||||
* // -> Gt
|
||||
* ```
|
||||
*/
|
||||
export function break_tie(order, other) {
|
||||
if (order instanceof Lt) {
|
||||
return order;
|
||||
} else if (order instanceof Eq) {
|
||||
return other;
|
||||
} else {
|
||||
return order;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Invokes a fallback function returning an `Order` in case the first argument
|
||||
* is `Eq`.
|
||||
*
|
||||
* This can be useful when the fallback comparison might be expensive and it
|
||||
* needs to be delayed until strictly necessary.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* import gleam/int
|
||||
*
|
||||
* lazy_break_tie(in: int.compare(1, 1), with: fn() { Lt })
|
||||
* // -> Lt
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* import gleam/int
|
||||
*
|
||||
* lazy_break_tie(in: int.compare(1, 0), with: fn() { Eq })
|
||||
* // -> Gt
|
||||
* ```
|
||||
*/
|
||||
export function lazy_break_tie(order, comparison) {
|
||||
if (order instanceof Lt) {
|
||||
return order;
|
||||
} else if (order instanceof Eq) {
|
||||
return comparison();
|
||||
} else {
|
||||
return order;
|
||||
}
|
||||
}
|
||||
102
build/dev/javascript/gleam_stdlib/gleam/pair.mjs
Normal file
102
build/dev/javascript/gleam_stdlib/gleam/pair.mjs
Normal file
|
|
@ -0,0 +1,102 @@
|
|||
/**
|
||||
* Returns the first element in a pair.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* first(#(1, 2))
|
||||
* // -> 1
|
||||
* ```
|
||||
*/
|
||||
export function first(pair) {
|
||||
let a;
|
||||
a = pair[0];
|
||||
return a;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the second element in a pair.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* second(#(1, 2))
|
||||
* // -> 2
|
||||
* ```
|
||||
*/
|
||||
export function second(pair) {
|
||||
let a;
|
||||
a = pair[1];
|
||||
return a;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new pair with the elements swapped.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* swap(#(1, 2))
|
||||
* // -> #(2, 1)
|
||||
* ```
|
||||
*/
|
||||
export function swap(pair) {
|
||||
let a;
|
||||
let b;
|
||||
a = pair[0];
|
||||
b = pair[1];
|
||||
return [b, a];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new pair with the first element having had `with` applied to
|
||||
* it.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* #(1, 2) |> map_first(fn(n) { n * 2 })
|
||||
* // -> #(2, 2)
|
||||
* ```
|
||||
*/
|
||||
export function map_first(pair, fun) {
|
||||
let a;
|
||||
let b;
|
||||
a = pair[0];
|
||||
b = pair[1];
|
||||
return [fun(a), b];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new pair with the second element having had `with` applied to
|
||||
* it.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* #(1, 2) |> map_second(fn(n) { n * 2 })
|
||||
* // -> #(1, 4)
|
||||
* ```
|
||||
*/
|
||||
export function map_second(pair, fun) {
|
||||
let a;
|
||||
let b;
|
||||
a = pair[0];
|
||||
b = pair[1];
|
||||
return [a, fun(b)];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new pair with the given elements. This can also be done using the dedicated
|
||||
* syntax instead: `new(1, 2) == #(1, 2)`.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* new(1, 2)
|
||||
* // -> #(1, 2)
|
||||
* ```
|
||||
*/
|
||||
export function new$(first, second) {
|
||||
return [first, second];
|
||||
}
|
||||
494
build/dev/javascript/gleam_stdlib/gleam/result.mjs
Normal file
494
build/dev/javascript/gleam_stdlib/gleam/result.mjs
Normal file
|
|
@ -0,0 +1,494 @@
|
|||
import { Ok, Error, toList, Empty as $Empty, prepend as listPrepend } from "../gleam.mjs";
|
||||
import * as $list from "../gleam/list.mjs";
|
||||
|
||||
/**
|
||||
* Checks whether the result is an `Ok` value.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* is_ok(Ok(1))
|
||||
* // -> True
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* is_ok(Error(Nil))
|
||||
* // -> False
|
||||
* ```
|
||||
*/
|
||||
export function is_ok(result) {
|
||||
if (result instanceof Ok) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the result is an `Error` value.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* is_error(Ok(1))
|
||||
* // -> False
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* is_error(Error(Nil))
|
||||
* // -> True
|
||||
* ```
|
||||
*/
|
||||
export function is_error(result) {
|
||||
if (result instanceof Ok) {
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates a value held within the `Ok` of a result by calling a given function
|
||||
* on it.
|
||||
*
|
||||
* If the result is an `Error` rather than `Ok` the function is not called and the
|
||||
* result stays the same.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* map(over: Ok(1), with: fn(x) { x + 1 })
|
||||
* // -> Ok(2)
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* map(over: Error(1), with: fn(x) { x + 1 })
|
||||
* // -> Error(1)
|
||||
* ```
|
||||
*/
|
||||
export function map(result, fun) {
|
||||
if (result instanceof Ok) {
|
||||
let x = result[0];
|
||||
return new Ok(fun(x));
|
||||
} else {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates a value held within the `Error` of a result by calling a given function
|
||||
* on it.
|
||||
*
|
||||
* If the result is `Ok` rather than `Error` the function is not called and the
|
||||
* result stays the same.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* map_error(over: Error(1), with: fn(x) { x + 1 })
|
||||
* // -> Error(2)
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* map_error(over: Ok(1), with: fn(x) { x + 1 })
|
||||
* // -> Ok(1)
|
||||
* ```
|
||||
*/
|
||||
export function map_error(result, fun) {
|
||||
if (result instanceof Ok) {
|
||||
return result;
|
||||
} else {
|
||||
let error = result[0];
|
||||
return new Error(fun(error));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Merges a nested `Result` into a single layer.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* flatten(Ok(Ok(1)))
|
||||
* // -> Ok(1)
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* flatten(Ok(Error("")))
|
||||
* // -> Error("")
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* flatten(Error(Nil))
|
||||
* // -> Error(Nil)
|
||||
* ```
|
||||
*/
|
||||
export function flatten(result) {
|
||||
if (result instanceof Ok) {
|
||||
let x = result[0];
|
||||
return x;
|
||||
} else {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* "Updates" an `Ok` result by passing its value to a function that yields a result,
|
||||
* and returning the yielded result. (This may "replace" the `Ok` with an `Error`.)
|
||||
*
|
||||
* If the input is an `Error` rather than an `Ok`, the function is not called and
|
||||
* the original `Error` is returned.
|
||||
*
|
||||
* This function is the equivalent of calling `map` followed by `flatten`, and
|
||||
* it is useful for chaining together multiple functions that may fail.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* try(Ok(1), fn(x) { Ok(x + 1) })
|
||||
* // -> Ok(2)
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* try(Ok(1), fn(x) { Ok(#("a", x)) })
|
||||
* // -> Ok(#("a", 1))
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* try(Ok(1), fn(_) { Error("Oh no") })
|
||||
* // -> Error("Oh no")
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* try(Error(Nil), fn(x) { Ok(x + 1) })
|
||||
* // -> Error(Nil)
|
||||
* ```
|
||||
*/
|
||||
export function try$(result, fun) {
|
||||
if (result instanceof Ok) {
|
||||
let x = result[0];
|
||||
return fun(x);
|
||||
} else {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
export function then$(result, fun) {
|
||||
return try$(result, fun);
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the `Ok` value from a result, returning a default value if the result
|
||||
* is an `Error`.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* unwrap(Ok(1), 0)
|
||||
* // -> 1
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* unwrap(Error(""), 0)
|
||||
* // -> 0
|
||||
* ```
|
||||
*/
|
||||
export function unwrap(result, default$) {
|
||||
if (result instanceof Ok) {
|
||||
let v = result[0];
|
||||
return v;
|
||||
} else {
|
||||
return default$;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the `Ok` value from a result, evaluating the default function if the result
|
||||
* is an `Error`.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* lazy_unwrap(Ok(1), fn() { 0 })
|
||||
* // -> 1
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* lazy_unwrap(Error(""), fn() { 0 })
|
||||
* // -> 0
|
||||
* ```
|
||||
*/
|
||||
export function lazy_unwrap(result, default$) {
|
||||
if (result instanceof Ok) {
|
||||
let v = result[0];
|
||||
return v;
|
||||
} else {
|
||||
return default$();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the `Error` value from a result, returning a default value if the result
|
||||
* is an `Ok`.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* unwrap_error(Error(1), 0)
|
||||
* // -> 1
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* unwrap_error(Ok(""), 0)
|
||||
* // -> 0
|
||||
* ```
|
||||
*/
|
||||
export function unwrap_error(result, default$) {
|
||||
if (result instanceof Ok) {
|
||||
return default$;
|
||||
} else {
|
||||
let e = result[0];
|
||||
return e;
|
||||
}
|
||||
}
|
||||
|
||||
export function unwrap_both(result) {
|
||||
if (result instanceof Ok) {
|
||||
let a = result[0];
|
||||
return a;
|
||||
} else {
|
||||
let a = result[0];
|
||||
return a;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the first value if it is `Ok`, otherwise returns the second value.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* or(Ok(1), Ok(2))
|
||||
* // -> Ok(1)
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* or(Ok(1), Error("Error 2"))
|
||||
* // -> Ok(1)
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* or(Error("Error 1"), Ok(2))
|
||||
* // -> Ok(2)
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* or(Error("Error 1"), Error("Error 2"))
|
||||
* // -> Error("Error 2")
|
||||
* ```
|
||||
*/
|
||||
export function or(first, second) {
|
||||
if (first instanceof Ok) {
|
||||
return first;
|
||||
} else {
|
||||
return second;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the first value if it is `Ok`, otherwise evaluates the given function for a fallback value.
|
||||
*
|
||||
* If you need access to the initial error value, use `result.try_recover`.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* lazy_or(Ok(1), fn() { Ok(2) })
|
||||
* // -> Ok(1)
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* lazy_or(Ok(1), fn() { Error("Error 2") })
|
||||
* // -> Ok(1)
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* lazy_or(Error("Error 1"), fn() { Ok(2) })
|
||||
* // -> Ok(2)
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* lazy_or(Error("Error 1"), fn() { Error("Error 2") })
|
||||
* // -> Error("Error 2")
|
||||
* ```
|
||||
*/
|
||||
export function lazy_or(first, second) {
|
||||
if (first instanceof Ok) {
|
||||
return first;
|
||||
} else {
|
||||
return second();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Combines a list of results into a single result.
|
||||
* If all elements in the list are `Ok` then returns an `Ok` holding the list of values.
|
||||
* If any element is `Error` then returns the first error.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* all([Ok(1), Ok(2)])
|
||||
* // -> Ok([1, 2])
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* all([Ok(1), Error("e")])
|
||||
* // -> Error("e")
|
||||
* ```
|
||||
*/
|
||||
export function all(results) {
|
||||
return $list.try_map(results, (result) => { return result; });
|
||||
}
|
||||
|
||||
function partition_loop(loop$results, loop$oks, loop$errors) {
|
||||
while (true) {
|
||||
let results = loop$results;
|
||||
let oks = loop$oks;
|
||||
let errors = loop$errors;
|
||||
if (results instanceof $Empty) {
|
||||
return [oks, errors];
|
||||
} else {
|
||||
let $ = results.head;
|
||||
if ($ instanceof Ok) {
|
||||
let rest = results.tail;
|
||||
let a = $[0];
|
||||
loop$results = rest;
|
||||
loop$oks = listPrepend(a, oks);
|
||||
loop$errors = errors;
|
||||
} else {
|
||||
let rest = results.tail;
|
||||
let e = $[0];
|
||||
loop$results = rest;
|
||||
loop$oks = oks;
|
||||
loop$errors = listPrepend(e, errors);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a list of results, returns a pair where the first element is a list
|
||||
* of all the values inside `Ok` and the second element is a list with all the
|
||||
* values inside `Error`. The values in both lists appear in reverse order with
|
||||
* respect to their position in the original list of results.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* partition([Ok(1), Error("a"), Error("b"), Ok(2)])
|
||||
* // -> #([2, 1], ["b", "a"])
|
||||
* ```
|
||||
*/
|
||||
export function partition(results) {
|
||||
return partition_loop(results, toList([]), toList([]));
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace the value within a result
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* replace(Ok(1), Nil)
|
||||
* // -> Ok(Nil)
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* replace(Error(1), Nil)
|
||||
* // -> Error(1)
|
||||
* ```
|
||||
*/
|
||||
export function replace(result, value) {
|
||||
if (result instanceof Ok) {
|
||||
return new Ok(value);
|
||||
} else {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace the error within a result
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* replace_error(Error(1), Nil)
|
||||
* // -> Error(Nil)
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* replace_error(Ok(1), Nil)
|
||||
* // -> Ok(1)
|
||||
* ```
|
||||
*/
|
||||
export function replace_error(result, error) {
|
||||
if (result instanceof Ok) {
|
||||
return result;
|
||||
} else {
|
||||
return new Error(error);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a list of results, returns only the values inside `Ok`.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* values([Ok(1), Error("a"), Ok(3)])
|
||||
* // -> [1, 3]
|
||||
* ```
|
||||
*/
|
||||
export function values(results) {
|
||||
return $list.filter_map(results, (result) => { return result; });
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates a value held within the `Error` of a result by calling a given function
|
||||
* on it, where the given function also returns a result. The two results are
|
||||
* then merged together into one result.
|
||||
*
|
||||
* If the result is an `Ok` rather than `Error` the function is not called and the
|
||||
* result stays the same.
|
||||
*
|
||||
* This function is useful for chaining together computations that may fail
|
||||
* and trying to recover from possible errors.
|
||||
*
|
||||
* If you do not need access to the initial error value, use `result.lazy_or`.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* Ok(1) |> try_recover(with: fn(_) { Error("failed to recover") })
|
||||
* // -> Ok(1)
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* Error(1) |> try_recover(with: fn(error) { Ok(error + 1) })
|
||||
* // -> Ok(2)
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* Error(1) |> try_recover(with: fn(error) { Error("failed to recover") })
|
||||
* // -> Error("failed to recover")
|
||||
* ```
|
||||
*/
|
||||
export function try_recover(result, fun) {
|
||||
if (result instanceof Ok) {
|
||||
return result;
|
||||
} else {
|
||||
let error = result[0];
|
||||
return fun(error);
|
||||
}
|
||||
}
|
||||
412
build/dev/javascript/gleam_stdlib/gleam/set.mjs
Normal file
412
build/dev/javascript/gleam_stdlib/gleam/set.mjs
Normal file
|
|
@ -0,0 +1,412 @@
|
|||
import { CustomType as $CustomType, isEqual } from "../gleam.mjs";
|
||||
import * as $dict from "../gleam/dict.mjs";
|
||||
import * as $list from "../gleam/list.mjs";
|
||||
import * as $result from "../gleam/result.mjs";
|
||||
|
||||
class Set extends $CustomType {
|
||||
constructor(dict) {
|
||||
super();
|
||||
this.dict = dict;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new empty set.
|
||||
*/
|
||||
export function new$() {
|
||||
return new Set($dict.new$());
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the number of members in a set.
|
||||
*
|
||||
* This function runs in constant time.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* new()
|
||||
* |> insert(1)
|
||||
* |> insert(2)
|
||||
* |> size
|
||||
* // -> 2
|
||||
* ```
|
||||
*/
|
||||
export function size(set) {
|
||||
return $dict.size(set.dict);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether or not the set is empty.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* new() |> is_empty
|
||||
* // -> True
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* new() |> insert(1) |> is_empty
|
||||
* // -> False
|
||||
* ```
|
||||
*/
|
||||
export function is_empty(set) {
|
||||
return isEqual(set, new$());
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether a set contains a given member.
|
||||
*
|
||||
* This function runs in logarithmic time.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* new()
|
||||
* |> insert(2)
|
||||
* |> contains(2)
|
||||
* // -> True
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* new()
|
||||
* |> insert(2)
|
||||
* |> contains(1)
|
||||
* // -> False
|
||||
* ```
|
||||
*/
|
||||
export function contains(set, member) {
|
||||
let _pipe = set.dict;
|
||||
let _pipe$1 = $dict.get(_pipe, member);
|
||||
return $result.is_ok(_pipe$1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a member from a set. If the set does not contain the member then
|
||||
* the set is returned unchanged.
|
||||
*
|
||||
* This function runs in logarithmic time.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* new()
|
||||
* |> insert(2)
|
||||
* |> delete(2)
|
||||
* |> contains(1)
|
||||
* // -> False
|
||||
* ```
|
||||
*/
|
||||
export function delete$(set, member) {
|
||||
return new Set($dict.delete$(set.dict, member));
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the set into a list of the contained members.
|
||||
*
|
||||
* The list has no specific ordering, any unintentional ordering may change in
|
||||
* future versions of Gleam or Erlang.
|
||||
*
|
||||
* This function runs in linear time.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* new() |> insert(2) |> to_list
|
||||
* // -> [2]
|
||||
* ```
|
||||
*/
|
||||
export function to_list(set) {
|
||||
return $dict.keys(set.dict);
|
||||
}
|
||||
|
||||
/**
|
||||
* Combines all entries into a single value by calling a given function on each
|
||||
* one.
|
||||
*
|
||||
* Sets are not ordered so the values are not returned in any specific order.
|
||||
* Do not write code that relies on the order entries are used by this
|
||||
* function as it may change in later versions of Gleam or Erlang.
|
||||
*
|
||||
* # Examples
|
||||
*
|
||||
* ```gleam
|
||||
* from_list([1, 3, 9])
|
||||
* |> fold(0, fn(accumulator, member) { accumulator + member })
|
||||
* // -> 13
|
||||
* ```
|
||||
*/
|
||||
export function fold(set, initial, reducer) {
|
||||
return $dict.fold(set.dict, initial, (a, k, _) => { return reducer(a, k); });
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new set from an existing set, minus any members that a given
|
||||
* function returns `False` for.
|
||||
*
|
||||
* This function runs in loglinear time.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* import gleam/int
|
||||
*
|
||||
* from_list([1, 4, 6, 3, 675, 44, 67])
|
||||
* |> filter(keeping: int.is_even)
|
||||
* |> to_list
|
||||
* // -> [4, 6, 44]
|
||||
* ```
|
||||
*/
|
||||
export function filter(set, predicate) {
|
||||
return new Set($dict.filter(set.dict, (m, _) => { return predicate(m); }));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new set from a given set with all the same entries except any
|
||||
* entry found on the given list.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* from_list([1, 2, 3, 4])
|
||||
* |> drop([1, 3])
|
||||
* |> to_list
|
||||
* // -> [2, 4]
|
||||
* ```
|
||||
*/
|
||||
export function drop(set, disallowed) {
|
||||
return $list.fold(disallowed, set, delete$);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new set from a given set, only including any members which are in
|
||||
* a given list.
|
||||
*
|
||||
* This function runs in loglinear time.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* from_list([1, 2, 3])
|
||||
* |> take([1, 3, 5])
|
||||
* |> to_list
|
||||
* // -> [1, 3]
|
||||
* ```
|
||||
*/
|
||||
export function take(set, desired) {
|
||||
return new Set($dict.take(set.dict, desired));
|
||||
}
|
||||
|
||||
function order(first, second) {
|
||||
let $ = $dict.size(first.dict) > $dict.size(second.dict);
|
||||
if ($) {
|
||||
return [first, second];
|
||||
} else {
|
||||
return [second, first];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new set that contains members that are present in both given sets.
|
||||
*
|
||||
* This function runs in loglinear time.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* intersection(from_list([1, 2]), from_list([2, 3])) |> to_list
|
||||
* // -> [2]
|
||||
* ```
|
||||
*/
|
||||
export function intersection(first, second) {
|
||||
let $ = order(first, second);
|
||||
let larger;
|
||||
let smaller;
|
||||
larger = $[0];
|
||||
smaller = $[1];
|
||||
return take(larger, to_list(smaller));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new set that contains members that are present in the first set
|
||||
* but not the second.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* difference(from_list([1, 2]), from_list([2, 3, 4])) |> to_list
|
||||
* // -> [1]
|
||||
* ```
|
||||
*/
|
||||
export function difference(first, second) {
|
||||
return drop(first, to_list(second));
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if a set is fully contained by another.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* is_subset(from_list([1]), from_list([1, 2]))
|
||||
* // -> True
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* is_subset(from_list([1, 2, 3]), from_list([3, 4, 5]))
|
||||
* // -> False
|
||||
* ```
|
||||
*/
|
||||
export function is_subset(first, second) {
|
||||
return isEqual(intersection(first, second), first);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if two sets contain no common members
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* is_disjoint(from_list([1, 2, 3]), from_list([4, 5, 6]))
|
||||
* // -> True
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* is_disjoint(from_list([1, 2, 3]), from_list([3, 4, 5]))
|
||||
* // -> False
|
||||
* ```
|
||||
*/
|
||||
export function is_disjoint(first, second) {
|
||||
return isEqual(intersection(first, second), new$());
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls a function for each member in a set, discarding the return
|
||||
* value.
|
||||
*
|
||||
* Useful for producing a side effect for every item of a set.
|
||||
*
|
||||
* ```gleam
|
||||
* let set = from_list(["apple", "banana", "cherry"])
|
||||
*
|
||||
* each(set, io.println)
|
||||
* // -> Nil
|
||||
* // apple
|
||||
* // banana
|
||||
* // cherry
|
||||
* ```
|
||||
*
|
||||
* The order of elements in the iteration is an implementation detail that
|
||||
* should not be relied upon.
|
||||
*/
|
||||
export function each(set, fun) {
|
||||
return fold(
|
||||
set,
|
||||
undefined,
|
||||
(nil, member) => {
|
||||
fun(member);
|
||||
return nil;
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
const token = undefined;
|
||||
|
||||
/**
|
||||
* Inserts an member into the set.
|
||||
*
|
||||
* This function runs in logarithmic time.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* new()
|
||||
* |> insert(1)
|
||||
* |> insert(2)
|
||||
* |> size
|
||||
* // -> 2
|
||||
* ```
|
||||
*/
|
||||
export function insert(set, member) {
|
||||
return new Set($dict.insert(set.dict, member, token));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new set of the members in a given list.
|
||||
*
|
||||
* This function runs in loglinear time.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* import gleam/int
|
||||
* import gleam/list
|
||||
*
|
||||
* [1, 1, 2, 4, 3, 2] |> from_list |> to_list |> list.sort(by: int.compare)
|
||||
* // -> [1, 2, 3, 4]
|
||||
* ```
|
||||
*/
|
||||
export function from_list(members) {
|
||||
let dict = $list.fold(
|
||||
members,
|
||||
$dict.new$(),
|
||||
(m, k) => { return $dict.insert(m, k, token); },
|
||||
);
|
||||
return new Set(dict);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new set from a given set with the result of applying the given
|
||||
* function to each member.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* from_list([1, 2, 3, 4])
|
||||
* |> map(with: fn(x) { x * 2 })
|
||||
* |> to_list
|
||||
* // -> [2, 4, 6, 8]
|
||||
* ```
|
||||
*/
|
||||
export function map(set, fun) {
|
||||
return fold(
|
||||
set,
|
||||
new$(),
|
||||
(acc, member) => { return insert(acc, fun(member)); },
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new set that contains all members of both given sets.
|
||||
*
|
||||
* This function runs in loglinear time.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* union(from_list([1, 2]), from_list([2, 3])) |> to_list
|
||||
* // -> [1, 2, 3]
|
||||
* ```
|
||||
*/
|
||||
export function union(first, second) {
|
||||
let $ = order(first, second);
|
||||
let larger;
|
||||
let smaller;
|
||||
larger = $[0];
|
||||
smaller = $[1];
|
||||
return fold(smaller, larger, insert);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new set that contains members that are present in either set, but
|
||||
* not both.
|
||||
*
|
||||
* ```gleam
|
||||
* symmetric_difference(from_list([1, 2, 3]), from_list([3, 4])) |> to_list
|
||||
* // -> [1, 2, 4]
|
||||
* ```
|
||||
*/
|
||||
export function symmetric_difference(first, second) {
|
||||
return difference(union(first, second), intersection(first, second));
|
||||
}
|
||||
723
build/dev/javascript/gleam_stdlib/gleam/string.mjs
Normal file
723
build/dev/javascript/gleam_stdlib/gleam/string.mjs
Normal file
|
|
@ -0,0 +1,723 @@
|
|||
import {
|
||||
Ok,
|
||||
Error,
|
||||
Empty as $Empty,
|
||||
prepend as listPrepend,
|
||||
CustomType as $CustomType,
|
||||
remainderInt,
|
||||
divideInt,
|
||||
} from "../gleam.mjs";
|
||||
import * as $list from "../gleam/list.mjs";
|
||||
import * as $option from "../gleam/option.mjs";
|
||||
import { None, Some } from "../gleam/option.mjs";
|
||||
import * as $order from "../gleam/order.mjs";
|
||||
import * as $string_tree from "../gleam/string_tree.mjs";
|
||||
import {
|
||||
string_length as length,
|
||||
lowercase,
|
||||
uppercase,
|
||||
less_than,
|
||||
string_grapheme_slice as grapheme_slice,
|
||||
string_byte_slice as unsafe_byte_slice,
|
||||
crop_string as crop,
|
||||
contains_string as contains,
|
||||
starts_with,
|
||||
ends_with,
|
||||
split_once,
|
||||
trim_start,
|
||||
trim_end,
|
||||
pop_grapheme,
|
||||
graphemes as to_graphemes,
|
||||
codepoint as unsafe_int_to_utf_codepoint,
|
||||
string_to_codepoint_integer_list,
|
||||
utf_codepoint_list_to_string as from_utf_codepoints,
|
||||
utf_codepoint_to_int,
|
||||
inspect as do_inspect,
|
||||
byte_size,
|
||||
} from "../gleam_stdlib.mjs";
|
||||
|
||||
export {
|
||||
byte_size,
|
||||
contains,
|
||||
crop,
|
||||
ends_with,
|
||||
from_utf_codepoints,
|
||||
length,
|
||||
lowercase,
|
||||
pop_grapheme,
|
||||
split_once,
|
||||
starts_with,
|
||||
to_graphemes,
|
||||
trim_end,
|
||||
trim_start,
|
||||
uppercase,
|
||||
utf_codepoint_to_int,
|
||||
};
|
||||
|
||||
class Leading extends $CustomType {}
|
||||
|
||||
class Trailing extends $CustomType {}
|
||||
|
||||
/**
|
||||
* Determines if a `String` is empty.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* is_empty("")
|
||||
* // -> True
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* is_empty("the world")
|
||||
* // -> False
|
||||
* ```
|
||||
*/
|
||||
export function is_empty(str) {
|
||||
return str === "";
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverses a `String`.
|
||||
*
|
||||
* This function has to iterate across the whole `String` so it runs in linear
|
||||
* time. Avoid using this in a loop.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* reverse("stressed")
|
||||
* // -> "desserts"
|
||||
* ```
|
||||
*/
|
||||
export function reverse(string) {
|
||||
let _pipe = string;
|
||||
let _pipe$1 = $string_tree.from_string(_pipe);
|
||||
let _pipe$2 = $string_tree.reverse(_pipe$1);
|
||||
return $string_tree.to_string(_pipe$2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new `String` by replacing all occurrences of a given substring.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* replace("www.example.com", each: ".", with: "-")
|
||||
* // -> "www-example-com"
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* replace("a,b,c,d,e", each: ",", with: "/")
|
||||
* // -> "a/b/c/d/e"
|
||||
* ```
|
||||
*/
|
||||
export function replace(string, pattern, substitute) {
|
||||
let _pipe = string;
|
||||
let _pipe$1 = $string_tree.from_string(_pipe);
|
||||
let _pipe$2 = $string_tree.replace(_pipe$1, pattern, substitute);
|
||||
return $string_tree.to_string(_pipe$2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares two `String`s to see which is "larger" by comparing their graphemes.
|
||||
*
|
||||
* This does not compare the size or length of the given `String`s.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* compare("Anthony", "Anthony")
|
||||
* // -> order.Eq
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* compare("A", "B")
|
||||
* // -> order.Lt
|
||||
* ```
|
||||
*/
|
||||
export function compare(a, b) {
|
||||
let $ = a === b;
|
||||
if ($) {
|
||||
return new $order.Eq();
|
||||
} else {
|
||||
let $1 = less_than(a, b);
|
||||
if ($1) {
|
||||
return new $order.Lt();
|
||||
} else {
|
||||
return new $order.Gt();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes a substring given a start grapheme index and a length. Negative indexes
|
||||
* are taken starting from the *end* of the list.
|
||||
*
|
||||
* This function runs in linear time with the size of the index and the
|
||||
* length. Negative indexes are linear with the size of the input string in
|
||||
* addition to the other costs.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* slice(from: "gleam", at_index: 1, length: 2)
|
||||
* // -> "le"
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* slice(from: "gleam", at_index: 1, length: 10)
|
||||
* // -> "leam"
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* slice(from: "gleam", at_index: 10, length: 3)
|
||||
* // -> ""
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* slice(from: "gleam", at_index: -2, length: 2)
|
||||
* // -> "am"
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* slice(from: "gleam", at_index: -12, length: 2)
|
||||
* // -> ""
|
||||
* ```
|
||||
*/
|
||||
export function slice(string, idx, len) {
|
||||
let $ = len <= 0;
|
||||
if ($) {
|
||||
return "";
|
||||
} else {
|
||||
let $1 = idx < 0;
|
||||
if ($1) {
|
||||
let translated_idx = length(string) + idx;
|
||||
let $2 = translated_idx < 0;
|
||||
if ($2) {
|
||||
return "";
|
||||
} else {
|
||||
return grapheme_slice(string, translated_idx, len);
|
||||
}
|
||||
} else {
|
||||
return grapheme_slice(string, idx, len);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Drops *n* graphemes from the end of a `String`.
|
||||
*
|
||||
* This function traverses the full string, so it runs in linear time with the
|
||||
* size of the string. Avoid using this in a loop.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* drop_end(from: "Cigarette Smoking Man", up_to: 2)
|
||||
* // -> "Cigarette Smoking M"
|
||||
* ```
|
||||
*/
|
||||
export function drop_end(string, num_graphemes) {
|
||||
let $ = num_graphemes <= 0;
|
||||
if ($) {
|
||||
return string;
|
||||
} else {
|
||||
return slice(string, 0, length(string) - num_graphemes);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new `String` by joining two `String`s together.
|
||||
*
|
||||
* This function typically copies both `String`s and runs in linear time, but
|
||||
* the exact behaviour will depend on how the runtime you are using optimises
|
||||
* your code. Benchmark and profile your code if you need to understand its
|
||||
* performance better.
|
||||
*
|
||||
* If you are joining together large string and want to avoid copying any data
|
||||
* you may want to investigate using the [`string_tree`](../gleam/string_tree.html)
|
||||
* module.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* append(to: "butter", suffix: "fly")
|
||||
* // -> "butterfly"
|
||||
* ```
|
||||
*/
|
||||
export function append(first, second) {
|
||||
return first + second;
|
||||
}
|
||||
|
||||
function concat_loop(loop$strings, loop$accumulator) {
|
||||
while (true) {
|
||||
let strings = loop$strings;
|
||||
let accumulator = loop$accumulator;
|
||||
if (strings instanceof $Empty) {
|
||||
return accumulator;
|
||||
} else {
|
||||
let string = strings.head;
|
||||
let strings$1 = strings.tail;
|
||||
loop$strings = strings$1;
|
||||
loop$accumulator = accumulator + string;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new `String` by joining many `String`s together.
|
||||
*
|
||||
* This function copies all the `String`s and runs in linear time.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* concat(["never", "the", "less"])
|
||||
* // -> "nevertheless"
|
||||
* ```
|
||||
*/
|
||||
export function concat(strings) {
|
||||
return concat_loop(strings, "");
|
||||
}
|
||||
|
||||
function repeat_loop(loop$times, loop$doubling_acc, loop$acc) {
|
||||
while (true) {
|
||||
let times = loop$times;
|
||||
let doubling_acc = loop$doubling_acc;
|
||||
let acc = loop$acc;
|
||||
let _block;
|
||||
let $ = times % 2;
|
||||
if ($ === 0) {
|
||||
_block = acc;
|
||||
} else {
|
||||
_block = acc + doubling_acc;
|
||||
}
|
||||
let acc$1 = _block;
|
||||
let times$1 = globalThis.Math.trunc(times / 2);
|
||||
let $1 = times$1 <= 0;
|
||||
if ($1) {
|
||||
return acc$1;
|
||||
} else {
|
||||
loop$times = times$1;
|
||||
loop$doubling_acc = doubling_acc + doubling_acc;
|
||||
loop$acc = acc$1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new `String` by repeating a `String` a given number of times.
|
||||
*
|
||||
* This function runs in loglinear time.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* repeat("ha", times: 3)
|
||||
* // -> "hahaha"
|
||||
* ```
|
||||
*/
|
||||
export function repeat(string, times) {
|
||||
let $ = times <= 0;
|
||||
if ($) {
|
||||
return "";
|
||||
} else {
|
||||
return repeat_loop(times, string, "");
|
||||
}
|
||||
}
|
||||
|
||||
function join_loop(loop$strings, loop$separator, loop$accumulator) {
|
||||
while (true) {
|
||||
let strings = loop$strings;
|
||||
let separator = loop$separator;
|
||||
let accumulator = loop$accumulator;
|
||||
if (strings instanceof $Empty) {
|
||||
return accumulator;
|
||||
} else {
|
||||
let string = strings.head;
|
||||
let strings$1 = strings.tail;
|
||||
loop$strings = strings$1;
|
||||
loop$separator = separator;
|
||||
loop$accumulator = (accumulator + separator) + string;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Joins many `String`s together with a given separator.
|
||||
*
|
||||
* This function runs in linear time.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* join(["home","evan","Desktop"], with: "/")
|
||||
* // -> "home/evan/Desktop"
|
||||
* ```
|
||||
*/
|
||||
export function join(strings, separator) {
|
||||
if (strings instanceof $Empty) {
|
||||
return "";
|
||||
} else {
|
||||
let first$1 = strings.head;
|
||||
let rest = strings.tail;
|
||||
return join_loop(rest, separator, first$1);
|
||||
}
|
||||
}
|
||||
|
||||
function padding(size, pad_string) {
|
||||
let pad_string_length = length(pad_string);
|
||||
let num_pads = divideInt(size, pad_string_length);
|
||||
let extra = remainderInt(size, pad_string_length);
|
||||
return repeat(pad_string, num_pads) + slice(pad_string, 0, extra);
|
||||
}
|
||||
|
||||
/**
|
||||
* Pads the start of a `String` until it has a given length.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* pad_start("121", to: 5, with: ".")
|
||||
* // -> "..121"
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* pad_start("121", to: 3, with: ".")
|
||||
* // -> "121"
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* pad_start("121", to: 2, with: ".")
|
||||
* // -> "121"
|
||||
* ```
|
||||
*/
|
||||
export function pad_start(string, desired_length, pad_string) {
|
||||
let current_length = length(string);
|
||||
let to_pad_length = desired_length - current_length;
|
||||
let $ = to_pad_length <= 0;
|
||||
if ($) {
|
||||
return string;
|
||||
} else {
|
||||
return padding(to_pad_length, pad_string) + string;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Pads the end of a `String` until it has a given length.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* pad_end("123", to: 5, with: ".")
|
||||
* // -> "123.."
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* pad_end("123", to: 3, with: ".")
|
||||
* // -> "123"
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* pad_end("123", to: 2, with: ".")
|
||||
* // -> "123"
|
||||
* ```
|
||||
*/
|
||||
export function pad_end(string, desired_length, pad_string) {
|
||||
let current_length = length(string);
|
||||
let to_pad_length = desired_length - current_length;
|
||||
let $ = to_pad_length <= 0;
|
||||
if ($) {
|
||||
return string;
|
||||
} else {
|
||||
return string + padding(to_pad_length, pad_string);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes whitespace on both sides of a `String`.
|
||||
*
|
||||
* Whitespace in this function is the set of nonbreakable whitespace
|
||||
* codepoints, defined as Pattern_White_Space in [Unicode Standard Annex #31][1].
|
||||
*
|
||||
* [1]: https://unicode.org/reports/tr31/
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* trim(" hats \n")
|
||||
* // -> "hats"
|
||||
* ```
|
||||
*/
|
||||
export function trim(string) {
|
||||
let _pipe = string;
|
||||
let _pipe$1 = trim_start(_pipe);
|
||||
return trim_end(_pipe$1);
|
||||
}
|
||||
|
||||
function to_graphemes_loop(loop$string, loop$acc) {
|
||||
while (true) {
|
||||
let string = loop$string;
|
||||
let acc = loop$acc;
|
||||
let $ = pop_grapheme(string);
|
||||
if ($ instanceof Ok) {
|
||||
let grapheme = $[0][0];
|
||||
let rest = $[0][1];
|
||||
loop$string = rest;
|
||||
loop$acc = listPrepend(grapheme, acc);
|
||||
} else {
|
||||
return acc;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a list of `String`s by splitting a given string on a given substring.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* split("home/gleam/desktop/", on: "/")
|
||||
* // -> ["home", "gleam", "desktop", ""]
|
||||
* ```
|
||||
*/
|
||||
export function split(x, substring) {
|
||||
if (substring === "") {
|
||||
return to_graphemes(x);
|
||||
} else {
|
||||
let _pipe = x;
|
||||
let _pipe$1 = $string_tree.from_string(_pipe);
|
||||
let _pipe$2 = $string_tree.split(_pipe$1, substring);
|
||||
return $list.map(_pipe$2, $string_tree.to_string);
|
||||
}
|
||||
}
|
||||
|
||||
function do_to_utf_codepoints(string) {
|
||||
let _pipe = string;
|
||||
let _pipe$1 = string_to_codepoint_integer_list(_pipe);
|
||||
return $list.map(_pipe$1, unsafe_int_to_utf_codepoint);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a `String` to a `List` of `UtfCodepoint`.
|
||||
*
|
||||
* See <https://en.wikipedia.org/wiki/Code_point> and
|
||||
* <https://en.wikipedia.org/wiki/Unicode#Codespace_and_Code_Points> for an
|
||||
* explanation on code points.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* "a" |> to_utf_codepoints
|
||||
* // -> [UtfCodepoint(97)]
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* // Semantically the same as:
|
||||
* // ["🏳", "️", "", "🌈"] or:
|
||||
* // [waving_white_flag, variant_selector_16, zero_width_joiner, rainbow]
|
||||
* "🏳️🌈" |> to_utf_codepoints
|
||||
* // -> [
|
||||
* // UtfCodepoint(127987),
|
||||
* // UtfCodepoint(65039),
|
||||
* // UtfCodepoint(8205),
|
||||
* // UtfCodepoint(127752),
|
||||
* // ]
|
||||
* ```
|
||||
*/
|
||||
export function to_utf_codepoints(string) {
|
||||
return do_to_utf_codepoints(string);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts an integer to a `UtfCodepoint`.
|
||||
*
|
||||
* Returns an `Error` if the integer does not represent a valid UTF codepoint.
|
||||
*/
|
||||
export function utf_codepoint(value) {
|
||||
let i = value;
|
||||
if (i > 1_114_111) {
|
||||
return new Error(undefined);
|
||||
} else {
|
||||
let i$1 = value;
|
||||
if ((i$1 >= 55_296) && (i$1 <= 57_343)) {
|
||||
return new Error(undefined);
|
||||
} else {
|
||||
let i$2 = value;
|
||||
if (i$2 < 0) {
|
||||
return new Error(undefined);
|
||||
} else {
|
||||
let i$3 = value;
|
||||
return new Ok(unsafe_int_to_utf_codepoint(i$3));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a `String` into `Option(String)` where an empty `String` becomes
|
||||
* `None`.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* to_option("")
|
||||
* // -> None
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* to_option("hats")
|
||||
* // -> Some("hats")
|
||||
* ```
|
||||
*/
|
||||
export function to_option(string) {
|
||||
if (string === "") {
|
||||
return new None();
|
||||
} else {
|
||||
return new Some(string);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the first grapheme cluster in a given `String` and wraps it in a
|
||||
* `Result(String, Nil)`. If the `String` is empty, it returns `Error(Nil)`.
|
||||
* Otherwise, it returns `Ok(String)`.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* first("")
|
||||
* // -> Error(Nil)
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* first("icecream")
|
||||
* // -> Ok("i")
|
||||
* ```
|
||||
*/
|
||||
export function first(string) {
|
||||
let $ = pop_grapheme(string);
|
||||
if ($ instanceof Ok) {
|
||||
let first$1 = $[0][0];
|
||||
return new Ok(first$1);
|
||||
} else {
|
||||
return $;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the last grapheme cluster in a given `String` and wraps it in a
|
||||
* `Result(String, Nil)`. If the `String` is empty, it returns `Error(Nil)`.
|
||||
* Otherwise, it returns `Ok(String)`.
|
||||
*
|
||||
* This function traverses the full string, so it runs in linear time with the
|
||||
* length of the string. Avoid using this in a loop.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* last("")
|
||||
* // -> Error(Nil)
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* last("icecream")
|
||||
* // -> Ok("m")
|
||||
* ```
|
||||
*/
|
||||
export function last(string) {
|
||||
let $ = pop_grapheme(string);
|
||||
if ($ instanceof Ok) {
|
||||
let $1 = $[0][1];
|
||||
if ($1 === "") {
|
||||
let first$1 = $[0][0];
|
||||
return new Ok(first$1);
|
||||
} else {
|
||||
let rest = $1;
|
||||
return new Ok(slice(rest, -1, 1));
|
||||
}
|
||||
} else {
|
||||
return $;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new `String` with the first grapheme in the input `String`
|
||||
* converted to uppercase and the remaining graphemes to lowercase.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* capitalise("mamouna")
|
||||
* // -> "Mamouna"
|
||||
* ```
|
||||
*/
|
||||
export function capitalise(string) {
|
||||
let $ = pop_grapheme(string);
|
||||
if ($ instanceof Ok) {
|
||||
let first$1 = $[0][0];
|
||||
let rest = $[0][1];
|
||||
return append(uppercase(first$1), lowercase(rest));
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a `String` representation of a term in Gleam syntax.
|
||||
*
|
||||
* This may be occasionally useful for quick-and-dirty printing of values in
|
||||
* scripts. For error reporting and other uses prefer constructing strings by
|
||||
* pattern matching on the values.
|
||||
*
|
||||
* ## Limitations
|
||||
*
|
||||
* The output format of this function is not stable and could change at any
|
||||
* time. The output is not suitable for parsing.
|
||||
*
|
||||
* This function works using runtime reflection, so the output may not be
|
||||
* perfectly accurate for data structures where the runtime structure doesn't
|
||||
* hold enough information to determine the original syntax. For example,
|
||||
* tuples with an Erlang atom in the first position will be mistaken for Gleam
|
||||
* records.
|
||||
*
|
||||
* ## Security and safety
|
||||
*
|
||||
* There is no limit to how large the strings that this function can produce.
|
||||
* Be careful not to call this function with large data structures or you
|
||||
* could use very large amounts of memory, potentially causing runtime
|
||||
* problems.
|
||||
*/
|
||||
export function inspect(term) {
|
||||
let _pipe = term;
|
||||
let _pipe$1 = do_inspect(_pipe);
|
||||
return $string_tree.to_string(_pipe$1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Drops *n* graphemes from the start of a `String`.
|
||||
*
|
||||
* This function runs in linear time with the number of graphemes to drop.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* drop_start(from: "The Lone Gunmen", up_to: 2)
|
||||
* // -> "e Lone Gunmen"
|
||||
* ```
|
||||
*/
|
||||
export function drop_start(string, num_graphemes) {
|
||||
let $ = num_graphemes <= 0;
|
||||
if ($) {
|
||||
return string;
|
||||
} else {
|
||||
let prefix = grapheme_slice(string, 0, num_graphemes);
|
||||
let prefix_size = byte_size(prefix);
|
||||
return unsafe_byte_slice(
|
||||
string,
|
||||
prefix_size,
|
||||
byte_size(string) - prefix_size,
|
||||
);
|
||||
}
|
||||
}
|
||||
133
build/dev/javascript/gleam_stdlib/gleam/string_tree.mjs
Normal file
133
build/dev/javascript/gleam_stdlib/gleam/string_tree.mjs
Normal file
|
|
@ -0,0 +1,133 @@
|
|||
import { toList, CustomType as $CustomType, isEqual } from "../gleam.mjs";
|
||||
import * as $list from "../gleam/list.mjs";
|
||||
import {
|
||||
add as append_tree,
|
||||
concat as from_strings,
|
||||
concat,
|
||||
identity as from_string,
|
||||
identity as to_string,
|
||||
length as byte_size,
|
||||
lowercase,
|
||||
uppercase,
|
||||
graphemes as do_to_graphemes,
|
||||
split,
|
||||
string_replace as replace,
|
||||
} from "../gleam_stdlib.mjs";
|
||||
|
||||
export {
|
||||
append_tree,
|
||||
byte_size,
|
||||
concat,
|
||||
from_string,
|
||||
from_strings,
|
||||
lowercase,
|
||||
replace,
|
||||
split,
|
||||
to_string,
|
||||
uppercase,
|
||||
};
|
||||
|
||||
class All extends $CustomType {}
|
||||
|
||||
/**
|
||||
* Prepends some `StringTree` onto the start of another.
|
||||
*
|
||||
* Runs in constant time.
|
||||
*/
|
||||
export function prepend_tree(tree, prefix) {
|
||||
return append_tree(prefix, tree);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an empty `StringTree`. Useful as the start of a pipe chaining many
|
||||
* trees together.
|
||||
*/
|
||||
export function new$() {
|
||||
return from_strings(toList([]));
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepends a `String` onto the start of some `StringTree`.
|
||||
*
|
||||
* Runs in constant time.
|
||||
*/
|
||||
export function prepend(tree, prefix) {
|
||||
return append_tree(from_string(prefix), tree);
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends a `String` onto the end of some `StringTree`.
|
||||
*
|
||||
* Runs in constant time.
|
||||
*/
|
||||
export function append(tree, second) {
|
||||
return append_tree(tree, from_string(second));
|
||||
}
|
||||
|
||||
/**
|
||||
* Joins the given trees into a new tree separated with the given string.
|
||||
*/
|
||||
export function join(trees, sep) {
|
||||
let _pipe = trees;
|
||||
let _pipe$1 = $list.intersperse(_pipe, from_string(sep));
|
||||
return concat(_pipe$1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a `StringTree` to a new one with the contents reversed.
|
||||
*/
|
||||
export function reverse(tree) {
|
||||
let _pipe = tree;
|
||||
let _pipe$1 = to_string(_pipe);
|
||||
let _pipe$2 = do_to_graphemes(_pipe$1);
|
||||
let _pipe$3 = $list.reverse(_pipe$2);
|
||||
return from_strings(_pipe$3);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares two string trees to determine if they have the same textual
|
||||
* content.
|
||||
*
|
||||
* Comparing two string trees using the `==` operator may return `False` even
|
||||
* if they have the same content as they may have been build in different ways,
|
||||
* so using this function is often preferred.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* from_strings(["a", "b"]) == from_string("ab")
|
||||
* // -> False
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* is_equal(from_strings(["a", "b"]), from_string("ab"))
|
||||
* // -> True
|
||||
* ```
|
||||
*/
|
||||
export function is_equal(a, b) {
|
||||
return isEqual(a, b);
|
||||
}
|
||||
|
||||
/**
|
||||
* Inspects a `StringTree` to determine if it is equivalent to an empty string.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ```gleam
|
||||
* from_string("ok") |> is_empty
|
||||
* // -> False
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* from_string("") |> is_empty
|
||||
* // -> True
|
||||
* ```
|
||||
*
|
||||
* ```gleam
|
||||
* from_strings([]) |> is_empty
|
||||
* // -> True
|
||||
* ```
|
||||
*/
|
||||
export function is_empty(tree) {
|
||||
return isEqual(from_string(""), tree);
|
||||
}
|
||||
1147
build/dev/javascript/gleam_stdlib/gleam/uri.mjs
Normal file
1147
build/dev/javascript/gleam_stdlib/gleam/uri.mjs
Normal file
File diff suppressed because it is too large
Load diff
347
build/dev/javascript/gleam_stdlib/gleam@bit_array.erl
Normal file
347
build/dev/javascript/gleam_stdlib/gleam@bit_array.erl
Normal file
|
|
@ -0,0 +1,347 @@
|
|||
-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;
|
||||
|
||||
<<X:1>> ->
|
||||
<<<<Accumulator/binary, (erlang:integer_to_binary(X))/binary>>/binary,
|
||||
":size(1)"/utf8>>;
|
||||
|
||||
<<X@1:2>> ->
|
||||
<<<<Accumulator/binary, (erlang:integer_to_binary(X@1))/binary>>/binary,
|
||||
":size(2)"/utf8>>;
|
||||
|
||||
<<X@2:3>> ->
|
||||
<<<<Accumulator/binary, (erlang:integer_to_binary(X@2))/binary>>/binary,
|
||||
":size(3)"/utf8>>;
|
||||
|
||||
<<X@3:4>> ->
|
||||
<<<<Accumulator/binary, (erlang:integer_to_binary(X@3))/binary>>/binary,
|
||||
":size(4)"/utf8>>;
|
||||
|
||||
<<X@4:5>> ->
|
||||
<<<<Accumulator/binary, (erlang:integer_to_binary(X@4))/binary>>/binary,
|
||||
":size(5)"/utf8>>;
|
||||
|
||||
<<X@5:6>> ->
|
||||
<<<<Accumulator/binary, (erlang:integer_to_binary(X@5))/binary>>/binary,
|
||||
":size(6)"/utf8>>;
|
||||
|
||||
<<X@6:7>> ->
|
||||
<<<<Accumulator/binary, (erlang:integer_to_binary(X@6))/binary>>/binary,
|
||||
":size(7)"/utf8>>;
|
||||
|
||||
<<X@7, Rest/bitstring>> ->
|
||||
Suffix = case Rest of
|
||||
<<>> ->
|
||||
<<""/utf8>>;
|
||||
|
||||
_ ->
|
||||
<<", "/utf8>>
|
||||
end,
|
||||
Accumulator@1 = <<<<Accumulator/binary,
|
||||
(erlang:integer_to_binary(X@7))/binary>>/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
|
||||
{<<First_byte, First_rest/bitstring>>,
|
||||
<<Second_byte, Second_rest/bitstring>>} ->
|
||||
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
|
||||
<<Pref:Prefix_size/bitstring, _/bitstring>> when Pref =:= Prefix ->
|
||||
true;
|
||||
|
||||
_ ->
|
||||
false
|
||||
end.
|
||||
352
build/dev/javascript/gleam_stdlib/gleam@bool.erl
Normal file
352
build/dev/javascript/gleam_stdlib/gleam@bool.erl
Normal file
|
|
@ -0,0 +1,352 @@
|
|||
-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.
|
||||
211
build/dev/javascript/gleam_stdlib/gleam@bytes_tree.erl
Normal file
211
build/dev/javascript/gleam_stdlib/gleam@bytes_tree.erl
Normal file
|
|
@ -0,0 +1,211 @@
|
|||
-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).
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue