aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authormrkutly <mark.sauer.utley@gmail.com>2022-05-20 22:03:42 -0400
committerLouis Pilfold <louis@lpil.uk>2022-06-11 18:39:10 +0100
commit0edd5bcc7ad03a8d61a44a88882bcbe3b2dddb2f (patch)
tree1592d552f53ed1a247ad7076d7ade2845ef5b23e /src
parentcf3b10fc7c6f12b105eaf5b90dd15a36cfb37d4f (diff)
downloadgleam_json-0edd5bcc7ad03a8d61a44a88882bcbe3b2dddb2f.tar.gz
gleam_json-0edd5bcc7ad03a8d61a44a88882bcbe3b2dddb2f.zip
begin implementing javascript support
Diffstat (limited to 'src')
-rw-r--r--src/gleam/json.gleam151
-rw-r--r--src/gleam_json_ffi.mjs105
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()
+}