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.
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;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue