Skip to content
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
### API changes

- Add `Result.forEach` https://github.com/rescript-association/rescript-core/pull/116
- Add `Error.getUnsafe` https://github.com/rescript-association/rescript-core/pull/123

## 0.2.0

Expand Down
2 changes: 2 additions & 0 deletions src/Core__Error.res
Original file line number Diff line number Diff line change
Expand Up @@ -37,3 +37,5 @@ module URIError = {
external raise: t => 'a = "%raise"

let panic = msg => make(`Panic! ${msg}`)->raise

@get_index external getUnsafe: ('a, string) => option<'b> = ""
24 changes: 24 additions & 0 deletions src/Core__Error.resi
Original file line number Diff line number Diff line change
Expand Up @@ -169,3 +169,27 @@ Error.panic("Uh oh. This was unexpected!")
```
*/
let panic: string => 'a

/**
`getUnsafe` returns a custom property on an error object, given its name. This is useful for working with custom exceptions thrown from JavaScript.

**Warning:** The return type is not guaranteed to be what you expect. It can be a string or null or anthing else. Run-time errors can occur if you use it as something that it is not. Consider the functions in the `Type` module to safely access its contents. ReScript exceptions can be handled in a type-safe way. See [Exceptions in ReScript](https://rescript-lang.org/docs/manual/latest/exception).

## Examples
```rescript
switch exn->Error.fromException {
| None => raise(exn)
| Some(err) =>
switch err->Error.getUnsafe("code") {
| None => raise(exn)
| Some(code) => {
if (code === "invalid-password") {
Console.log("Try again!")
}
}
}
}
```
*/
@get_index
external getUnsafe: (t, string) => option<'a> = ""
37 changes: 37 additions & 0 deletions test/ErrorTests.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import * as Test from "./Test.mjs";
import * as Js_exn from "rescript/lib/es6/js_exn.js";
import * as Caml_option from "rescript/lib/es6/caml_option.js";
import * as RescriptCore from "../src/RescriptCore.mjs";
import * as Caml_js_exceptions from "rescript/lib/es6/caml_js_exceptions.js";

Expand Down Expand Up @@ -33,7 +34,43 @@ function panicTest(param) {

panicTest(undefined);

function catchCustomError(param) {
var authenticationError = new Error("authentication error");
var codeCaught;
authenticationError["code"] = "invalid-password";
try {
throw authenticationError;
}
catch (raw_exn){
var exn = Caml_js_exceptions.internalToOCamlException(raw_exn);
var err = Caml_js_exceptions.as_js_exn(exn);
if (err !== undefined) {
var code = Caml_option.valFromOption(err)["code"];
if (code !== undefined) {
codeCaught = Caml_option.valFromOption(code);
}

} else {
throw exn;
}
}
Test.run([
[
"ErrorTests.res",
34,
15,
39
],
"Can access custom code"
], codeCaught, (function (prim0, prim1) {
return prim0 === prim1;
}), "invalid-password");
}

catchCustomError(undefined);

export {
panicTest ,
catchCustomError ,
}
/* Not a pure module */
30 changes: 30 additions & 0 deletions test/ErrorTests.res
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,33 @@ let panicTest = () => {
}

panicTest()

// This test case is based on catching authentication errors from the Firebase
// SDK. Errors are subclassed from the Error object and contain custom
// properties like "code".
let catchCustomError = () => {
let authenticationError = Error.make("authentication error")
let codeCaught = ref(None)
Object.set(authenticationError->Obj.magic, "code", "invalid-password")
try {
authenticationError->Error.raise
} catch {
| _ as exn =>
switch exn->Error.fromException {
| None => raise(exn)
| Some(err) =>
switch err->Error.getUnsafe("code") {
| None => ()
| Some(code) => codeCaught := Some(code)
}
}
}
Test.run(
__POS_OF__("Can access custom code"),
codeCaught.contents,
\"==",
Some("invalid-password"),
)
}

catchCustomError()
3 changes: 3 additions & 0 deletions test/TestSuite.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ var Concurrently = PromiseTest.Concurrently;

var panicTest = ErrorTests.panicTest;

var catchCustomError = ErrorTests.catchCustomError;

var $$catch = IntTests.$$catch;

var eq = ResultTests.eq;
Expand All @@ -46,6 +48,7 @@ export {
Catching ,
Concurrently ,
panicTest ,
catchCustomError ,
$$catch ,
eq ,
forEachIfOkCallFunction ,
Expand Down