aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG.md3
-rw-r--r--src/gleam_stdlib.erl1
-rw-r--r--src/gleam_stdlib.mjs18
-rw-r--r--test/gleam/dynamic_test.gleam34
-rwxr-xr-xtest/gleam_stdlib_test_ffi.mjs4
5 files changed, 56 insertions, 4 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index f6504dd..a21b485 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,9 @@
## Unreleased
+- Don't crash when `null` or `undefined` is passed to `dynamic.map`
+
+## v0.28.1 - 2023-04-10
- The `iterator` module gains the `each` function.
- Fixed a bug in maps when running on JavaScript where value membership could be
incorrectly stated in some cases.
diff --git a/src/gleam_stdlib.erl b/src/gleam_stdlib.erl
index e1fdbb1..33c9609 100644
--- a/src/gleam_stdlib.erl
+++ b/src/gleam_stdlib.erl
@@ -41,6 +41,7 @@ decode_error_msg(Expected, Data) when is_binary(Expected) ->
decode_error(Expected, Got) when is_binary(Expected) andalso is_binary(Got) ->
{error, [{decode_error, Expected, Got, []}]}.
+classify_dynamic(nil) -> <<"Nil">>;
classify_dynamic(X) when is_atom(X) -> <<"Atom">>;
classify_dynamic(X) when is_binary(X) -> <<"String">>;
classify_dynamic(X) when is_bitstring(X) -> <<"BitString">>;
diff --git a/src/gleam_stdlib.mjs b/src/gleam_stdlib.mjs
index 632c668..2b0a6e1 100644
--- a/src/gleam_stdlib.mjs
+++ b/src/gleam_stdlib.mjs
@@ -392,11 +392,11 @@ export function regex_scan(regex, string) {
const submatches = [];
for (let n = match.length - 1; n > 0; n--) {
if (match[n]) {
- submatches[n-1] = new Some(match[n])
- continue
+ submatches[n - 1] = new Some(match[n]);
+ continue;
}
- if(submatches.length > 0) {
- submatches[n-1] = new None()
+ if (submatches.length > 0) {
+ submatches[n - 1] = new None();
}
}
return new RegexMatch(content, List.fromArray(submatches));
@@ -564,6 +564,10 @@ export function classify_dynamic(data) {
return "Map";
} else if (typeof data === "number") {
return "Float";
+ } else if (data === null) {
+ return "Null";
+ } else if (data === undefined) {
+ return "Nil";
} else {
let type = typeof data;
return type.charAt(0).toUpperCase() + type.slice(1);
@@ -633,6 +637,12 @@ export function decode_map(data) {
if (data instanceof PMap) {
return new Ok(PMap.fromMap(data));
}
+ if (data == null) {
+ return decoder_error("Map", data);
+ }
+ if (typeof data !== "object") {
+ return decoder_error("Map", data);
+ }
const proto = Object.getPrototypeOf(data);
if (proto === Object.prototype || proto === null) {
return new Ok(PMap.fromObject(data));
diff --git a/test/gleam/dynamic_test.gleam b/test/gleam/dynamic_test.gleam
index ffd8b73..a220e6e 100644
--- a/test/gleam/dynamic_test.gleam
+++ b/test/gleam/dynamic_test.gleam
@@ -51,6 +51,35 @@ if javascript {
}
}
+if erlang {
+ pub type MyAtom {
+ ThisIsAnAtom
+ }
+
+ pub fn map_from_atom_test() {
+ ThisIsAnAtom
+ |> dynamic.from
+ |> dynamic.map(dynamic.string, dynamic.int)
+ |> should.equal(Error([
+ DecodeError(expected: "Map", found: "Atom", path: []),
+ ]))
+ }
+}
+
+if javascript {
+ external fn get_null() -> dynamic.Dynamic =
+ "../gleam_stdlib_test_ffi.mjs" "get_null"
+
+ pub fn map_from_null_test() {
+ get_null()
+ |> dynamic.from
+ |> dynamic.map(dynamic.string, dynamic.int)
+ |> should.equal(Error([
+ DecodeError(expected: "Map", found: "Null", path: []),
+ ]))
+ }
+}
+
pub fn string_test() {
""
|> dynamic.from
@@ -758,6 +787,11 @@ pub fn map_test() {
|> should.equal(Error([
DecodeError(expected: "Map", found: "Function", path: []),
]))
+
+ Nil
+ |> dynamic.from
+ |> dynamic.map(dynamic.string, dynamic.int)
+ |> should.equal(Error([DecodeError(expected: "Map", found: "Nil", path: [])]))
}
pub fn shallow_list_test() {
diff --git a/test/gleam_stdlib_test_ffi.mjs b/test/gleam_stdlib_test_ffi.mjs
index 68922c9..c859093 100755
--- a/test/gleam_stdlib_test_ffi.mjs
+++ b/test/gleam_stdlib_test_ffi.mjs
@@ -6,3 +6,7 @@ export function uint8array(list) {
}
return array;
}
+
+export function get_null() {
+ return null;
+}