diff options
author | mrkutly <mark.sauer.utley@gmail.com> | 2022-05-20 22:03:42 -0400 |
---|---|---|
committer | Louis Pilfold <louis@lpil.uk> | 2022-06-11 18:39:10 +0100 |
commit | 0edd5bcc7ad03a8d61a44a88882bcbe3b2dddb2f (patch) | |
tree | 1592d552f53ed1a247ad7076d7ade2845ef5b23e /src | |
parent | cf3b10fc7c6f12b105eaf5b90dd15a36cfb37d4f (diff) | |
download | gleam_json-0edd5bcc7ad03a8d61a44a88882bcbe3b2dddb2f.tar.gz gleam_json-0edd5bcc7ad03a8d61a44a88882bcbe3b2dddb2f.zip |
begin implementing javascript support
Diffstat (limited to 'src')
-rw-r--r-- | src/gleam/json.gleam | 151 | ||||
-rw-r--r-- | src/gleam_json_ffi.mjs | 105 |
2 files changed, 235 insertions, 21 deletions
diff --git a/src/gleam/json.gleam b/src/gleam/json.gleam index b19c121..5faaa48 100644 --- a/src/gleam/json.gleam +++ b/src/gleam/json.gleam @@ -1,4 +1,3 @@ -import gleam/map import gleam/list import gleam/result import gleam/bit_string @@ -72,8 +71,19 @@ pub fn decode_bits( |> result.map_error(UnexpectedFormat) } -external fn decode_to_dynamic(BitString) -> Result(Dynamic, DecodeError) = - "gleam_json_ffi" "decode" +fn decode_to_dynamic(bit_string: BitString) -> Result(Dynamic, DecodeError) { + do_decode_to_dynamic(bit_string) +} + +if erlang { + external fn do_decode_to_dynamic(BitString) -> Result(Dynamic, DecodeError) = + "gleam_json_ffi" "decode" +} + +if javascript { + external fn do_decode_to_dynamic(BitString) -> Result(Dynamic, DecodeError) = + "../gleam_json_ffi.mjs" "decode" +} /// Convert a JSON value into a string. /// @@ -87,8 +97,19 @@ external fn decode_to_dynamic(BitString) -> Result(Dynamic, DecodeError) = /// "[1,2,3]" /// ``` /// -pub external fn to_string(Json) -> String = - "gleam_json_ffi" "json_to_string" +pub fn to_string(json: Json) -> String { + do_to_string(json) +} + +if erlang { + external fn do_to_string(Json) -> String = + "gleam_json_ffi" "json_to_string" +} + +if javascript { + external fn do_to_string(Json) -> String = + "../gleam_json_ffi.mjs" "json_to_string" +} /// Convert a JSON value into a string builder. /// @@ -103,8 +124,19 @@ pub external fn to_string(Json) -> String = /// string_builder.from_string("[1,2,3]") /// ``` /// -pub external fn to_string_builder(Json) -> StringBuilder = - "gleam_json_ffi" "json_to_iodata" +pub fn to_string_builder(json: Json) -> StringBuilder { + do_to_string_builder(json) +} + +if erlang { + external fn do_to_string_builder(Json) -> StringBuilder = + "gleam_json_ffi" "json_to_iodata" +} + +if javascript { + external fn do_to_string_builder(Json) -> StringBuilder = + "../gleam_json_ffi.mjs" "json_to_string" +} /// Encode a string into JSON, using normal JSON escaping. /// @@ -115,8 +147,19 @@ pub external fn to_string_builder(Json) -> StringBuilder = /// "\"Hello!\"" /// ``` /// -pub external fn string(input: String) -> Json = - "gleam_json_ffi" "string" +pub fn string(input: String) -> Json { + do_string(input) +} + +if erlang { + external fn do_string(String) -> Json = + "gleam_json_ffi" "string" +} + +if javascript { + external fn do_string(String) -> Json = + "../gleam_json_ffi.mjs" "identity" +} /// Encode a bool into JSON. /// @@ -127,8 +170,19 @@ pub external fn string(input: String) -> Json = /// "false" /// ``` /// -pub external fn bool(input: Bool) -> Json = - "gleam_json_ffi" "bool" +pub fn bool(input: Bool) -> Json { + do_bool(input) +} + +if erlang { + external fn do_bool(Bool) -> Json = + "gleam_json_ffi" "bool" +} + +if javascript { + external fn do_bool(Bool) -> Json = + "../gleam_json_ffi.mjs" "identity" +} /// Encode an int into JSON. /// @@ -139,8 +193,19 @@ pub external fn bool(input: Bool) -> Json = /// "50" /// ``` /// -pub external fn int(input: Int) -> Json = - "gleam_json_ffi" "int" +pub fn int(input: Int) -> Json { + do_int(input) +} + +if erlang { + external fn do_int(Int) -> Json = + "gleam_json_ffi" "int" +} + +if javascript { + external fn do_int(Int) -> Json = + "../gleam_json_ffi.mjs" "identity" +} /// Encode an float into JSON. /// @@ -151,8 +216,19 @@ pub external fn int(input: Int) -> Json = /// "4.7" /// ``` /// -pub external fn float(input: Float) -> Json = - "gleam_json_ffi" "float" +pub fn float(input: Float) -> Json { + do_float(input) +} + +if erlang { + external fn do_float(input: Float) -> Json = + "gleam_json_ffi" "float" +} + +if javascript { + external fn do_float(input: Float) -> Json = + "../gleam_json_ffi.mjs" "identity" +} /// The JSON value null. /// @@ -163,8 +239,19 @@ pub external fn float(input: Float) -> Json = /// "null" /// ``` /// -pub external fn null() -> Json = - "gleam_json_ffi" "null" +pub fn null() -> Json { + do_null() +} + +if erlang { + external fn do_null() -> Json = + "gleam_json_ffi" "null" +} + +if javascript { + external fn do_null() -> Json = + "../gleam_json_ffi.mjs" "do_null" +} /// Encode an optional value into JSON, using null if it the `None` variant. /// @@ -199,8 +286,19 @@ pub fn nullable(from input: Option(a), of inner_type: fn(a) -> Json) -> Json { /// "{\"game\":\"Pac-Mac\",\"score\":3333360}" /// ``` /// -pub external fn object(entries: List(#(String, Json))) -> Json = - "gleam_json_ffi" "object" +pub fn object(entries: List(#(String, Json))) -> Json { + do_object(entries) +} + +if erlang { + external fn do_object(entries: List(#(String, Json))) -> Json = + "gleam_json_ffi" "object" +} + +if javascript { + external fn do_object(entries: List(#(String, Json))) -> Json = + "../gleam_json_ffi.mjs" "object_from" +} /// Encode a list into a JSON array. /// @@ -226,5 +324,16 @@ pub fn array(from entries: List(a), of inner_type: fn(a) -> Json) -> Json { /// "[1, 2.0, \"3\"]" /// ``` /// -pub external fn preprocessed_array(from: List(Json)) -> Json = - "gleam_json_ffi" "array" +pub fn preprocessed_array(from: List(Json)) -> Json { + do_preprocessed_array(from) +} + +if erlang { + external fn do_preprocessed_array(from: List(Json)) -> Json = + "gleam_json_ffi" "array" +} + +if javascript { + external fn do_preprocessed_array(from: List(Json)) -> Json = + "../gleam_json_ffi.mjs" "array" +} diff --git a/src/gleam_json_ffi.mjs b/src/gleam_json_ffi.mjs new file mode 100644 index 0000000..e7cdecd --- /dev/null +++ b/src/gleam_json_ffi.mjs @@ -0,0 +1,105 @@ +import { Ok, Error, CustomType } from './gleam.mjs' +import { bit_string_to_string } from '../../gleam_stdlib/dist/gleam_stdlib.mjs' + +export class DecodeError extends CustomType { + get __gleam_prelude_variant__() { + return "DecodeError"; + } +} + +export class UnexpectedEndOfInput extends CustomType { + static isInstance(err) { + return err.message === 'Unexpected end of JSON input' + } + + get __gleam_prelude_variant__() { + return "UnexpectedEndOfInput" + } +} + +export class UnexpectedByte extends CustomType { + static regex = /Unexpected token (.) in JSON at position (\d+)/ + + static isInstance(err) { + return this.regex.test(err) + } + + constructor(err) { + super() + const match = UnexpectedByte.regex.exec(err.message) + this.byte = "0x" + match[1].charCodeAt(0).toString(16).toUpperCase() + this.position = Number(match[2]) + } + + get __gleam_prelude_variant__() { + return `UnexpectedByte`; + } +} + +export class UnexpectedSequence extends CustomType { + static isInstance(err) { + return false + } + + get __gleam_prelude_variant__() { + return "UnexpectedSequence"; + } +} + +export class UnexpectedFormat extends CustomType { + static isInstance(err) { + return false + } + + constructor(decodeErrs) { + super() + this[0] = decodeErrs + } + + get __gleam_prelude_variant__() { + return "UnexpectedFormat"; + } +} + +export function json_to_string(json) { + return JSON.stringify(json) +} + +export function object_from(entries) { + return Object.fromEntries(entries) +} + +export function array(list) { + return list.toArray() +} + +export function do_null() { + return null +} + +export function identity(x) { + return x +} + +export function decode(bit_string) { + const stringResult = bit_string_to_string(bit_string) + if (!stringResult.isOk()) return stringResult + try { + const result = JSON.parse(stringResult[0]) + return new Ok(result) + } catch (err) { + return getJsonDecodeError(err) + } +} + +function getJsonDecodeError(stdErr) { + const ErrClass = [ + UnexpectedByte, + UnexpectedEndOfInput, + UnexpectedFormat, + UnexpectedSequence, + ].find((klass) => klass.isInstance(stdErr)) + + if (ErrClass) return new Error(new ErrClass(stdErr)) + else return new Error() +} |