Skip to content

Commit 74e70db

Browse files
committed
feat: better error handling
1 parent e18e9f8 commit 74e70db

File tree

6 files changed

+98
-26
lines changed

6 files changed

+98
-26
lines changed

NativeScript/cli/main.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
#include "ffi/NativeScriptException.h"
21
#ifdef ENABLE_JS_RUNTIME
32

43
#include <filesystem>
54
#include <fstream>
65
#include <iostream>
76

7+
#include "ffi/NativeScriptException.h"
88
#include "runtime/Bundle.h"
99
#include "runtime/Runtime.h"
1010
#include "runtime/RuntimeConfig.h"
@@ -31,8 +31,8 @@ void bootFromModuleSpec(std::string baseDir, std::string spec) {
3131
try {
3232
runtime.RunModule(spec);
3333
} catch (const nativescript::NativeScriptException& e) {
34-
std::cerr << "Error running module: " << e.Description() << std::endl;
35-
return;
34+
std::cerr << "Uncaught Exception: " << e.Description() << std::endl;
35+
std::exit(1);
3636
}
3737

3838
runtime.RunLoop();

NativeScript/ffi/CFunction.mm

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#include "CFunction.h"
22
#include "ClassMember.h"
33
#include "ObjCBridge.h"
4+
#include "ffi/NativeScriptException.h"
45

56
namespace nativescript {
67

@@ -71,7 +72,15 @@
7172
}
7273
}
7374

74-
ffi_call(&cif->cif, FFI_FN(func->fnptr), rvalue, avalues);
75+
@try {
76+
ffi_call(&cif->cif, FFI_FN(func->fnptr), rvalue, avalues);
77+
} @catch (NSException* exception) {
78+
std::string message = exception.description.UTF8String;
79+
NSLog(@"ObjC->JS: Exception in CFunction: %s", message.c_str());
80+
nativescript::NativeScriptException nativeScriptException(message);
81+
nativeScriptException.ReThrowToJS(env);
82+
return nullptr;
83+
}
7584

7685
if (shouldFreeAny) {
7786
for (unsigned int i = 0; i < cif->argc; i++) {

NativeScript/ffi/Closure.mm

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#include "ffi/NativeScriptException.h"
99
#include "js_native_api.h"
1010
#include "js_native_api_types.h"
11+
#include "jsr.h"
1112
#include "node_api_util.h"
1213
#include "objc/message.h"
1314

@@ -22,7 +23,9 @@ inline void JSCallbackInner(Closure* closure, napi_value func, napi_value thisAr
2223
size_t argc, bool* done, void* ret) {
2324
napi_env env = closure->env;
2425

25-
napi_value result;
26+
NapiScope scope(env);
27+
28+
napi_value result;
2629

2730
napi_get_and_clear_last_exception(env, &result);
2831

NativeScript/ffi/NativeScriptException.mm

Lines changed: 24 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -42,12 +42,7 @@
4242
}
4343
}
4444

45-
std::string NativeScriptException::Description() const {
46-
std::stringstream ss;
47-
ss << "NativeScriptException: " << this->message_ << std::endl;
48-
ss << "StackTrace: " << this->stackTrace_ << std::endl;
49-
return ss.str();
50-
}
45+
std::string NativeScriptException::Description() const { return this->fullMessage_; }
5146

5247
void NativeScriptException::OnUncaughtError(napi_env env, napi_value error) {
5348
NapiScope scope(env);
@@ -58,8 +53,12 @@
5853
fullMessageStream << napi_util::get_cxx_string(
5954
env, napi_util::get_property(env, error, "fullMessage"));
6055
} else {
56+
#ifdef TARGET_ENGINE_V8
57+
fullMessageStream << GetErrorStackTrace(env, error);
58+
#else
6159
fullMessageStream << GetErrorMessage(env, error);
6260
fullMessageStream << "\n at \n" << GetErrorStackTrace(env, error);
61+
#endif
6362
}
6463

6564
// TODO: discardUncaughtJsExceptions
@@ -80,8 +79,12 @@
8079

8180
if (napi_util::is_of_type(env, result, napi_object)) {
8281
fullMessageStream << "\n\nError handler threw an error too:\n";
82+
#ifdef TARGET_ENGINE_V8
83+
fullMessageStream << GetErrorStackTrace(env, result);
84+
#else
8385
fullMessageStream << GetErrorMessage(env, result);
8486
fullMessageStream << "\n at \n" << GetErrorStackTrace(env, result);
87+
#endif
8588
} else {
8689
fullMessageStream
8790
<< "\n\nError handler threw an error too, but we couldn't get the error object";
@@ -91,15 +94,15 @@
9194

9295
std::string fullMessage = fullMessageStream.str();
9396

94-
NSLog(@"NativeScriptException: %s", fullMessage.c_str());
97+
NSLog(@"NativeScriptException::OnUncaughtError: %s", fullMessage.c_str());
9598

96-
NSException* objcException = [NSException exceptionWithName:@(fullMessage.c_str())
97-
reason:nil
99+
NSException* objcException = [NSException exceptionWithName:@"NativeScriptException"
100+
reason:@(fullMessage.c_str())
98101
userInfo:@{@"sender" : @"onUncaughtError"}];
99102

100-
dispatch_async(dispatch_get_main_queue(), ^(void) {
101-
@throw objcException;
102-
});
103+
// dispatch_async(dispatch_get_main_queue(), ^(void) {
104+
@throw objcException;
105+
// });
103106
}
104107

105108
void NativeScriptException::ReThrowToJS(napi_env env) {
@@ -204,16 +207,21 @@
204207
return jsExceptionMessage;
205208
}
206209

210+
std::string stackTraceMessage = GetErrorStackTrace(env, error);
211+
207212
std::stringstream ss;
208-
ss << jsExceptionMessage;
209213

210-
std::string stackTraceMessage = GetErrorStackTrace(env, error);
214+
#ifdef TARGET_ENGINE_V8
215+
ss << stackTraceMessage;
216+
#else
217+
ss << jsExceptionMessage;
211218

212-
ss << std::endl << "StackTrace: " << std::endl << stackTraceMessage << std::endl;
219+
ss << std::endl << "StackTrace: " << std::endl << stackTraceMessage;
220+
#endif
213221

214222
std::string loggedMessage = ss.str();
215223

216-
PrintErrorMessage(loggedMessage);
224+
// PrintErrorMessage(loggedMessage);
217225

218226
return loggedMessage;
219227
}

NativeScript/runtime/modules/module/ModuleInternal.cpp

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ napi_value ModuleInternal::RequireCallback(napi_env env,
132132
e.ReThrowToJS(env);
133133
} catch (std::exception& e) {
134134
stringstream ss;
135-
ss << "Error: c++ exception: " << e.what() << endl;
135+
ss << "Error: C++ Exception: " << e.what() << endl;
136136
NativeScriptException nsEx(ss.str());
137137
nsEx.ReThrowToJS(env);
138138
} catch (...) {
@@ -147,7 +147,8 @@ napi_value ModuleInternal::Require(napi_env env, const std::string& moduleName,
147147
const std::string& callingModuleDirName) {
148148
auto isData = false;
149149

150-
auto moduleObj = LoadImpl(env, moduleName, callingModuleDirName, isData);
150+
napi_value moduleObj =
151+
LoadImpl(env, moduleName, callingModuleDirName, isData);
151152

152153
if (isData) {
153154
assert(!napi_util::is_null_or_undefined(env, moduleObj));
@@ -180,7 +181,12 @@ napi_value ModuleInternal::RequireCallbackImpl(napi_env env,
180181
string moduleName = napi_util::get_cxx_string(env, argv[0]);
181182
string callingModuleDirName = napi_util::get_cxx_string(env, argv[1]);
182183

183-
return Require(env, moduleName, callingModuleDirName);
184+
try {
185+
return Require(env, moduleName, callingModuleDirName);
186+
} catch (NativeScriptException& e) {
187+
e.ReThrowToJS(env);
188+
return nullptr;
189+
}
184190
}
185191

186192
napi_value ModuleInternal::RequireNativeCallback(napi_env env,
@@ -419,8 +425,6 @@ napi_value ModuleInternal::LoadImpl(napi_env env, const std::string& moduleName,
419425
path = "lib" + moduleName;
420426
} else if (moduleName.ends_with(".node")) {
421427
std::string libName = moduleName;
422-
// Util::ReplaceAll(libName, ".node", "");
423-
// using c++
424428
libName.replace(libName.find(".node"), 5, "");
425429
path = "lib" + libName + ".so";
426430
} else {

cli_tests/error.js

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
const nsStr = NSString.stringWithString("0123");
2+
3+
try {
4+
console.log(nsStr.substringFromIndex(5));
5+
} catch (e) {
6+
console.log(e.stack);
7+
}
8+
9+
// NSOperationQueue.mainQueue.addOperationWithBlock(() => {
10+
// console.log("Hello, World! from main queue");
11+
12+
// throw new Error("JavaScript error from block");
13+
// });
14+
15+
// NSTimer.scheduledTimerWithTimeIntervalRepeatsBlock(
16+
// 1,
17+
// false,
18+
// () => {
19+
// console.log("Hello, World! from timer");
20+
// throw new Error("JavaScript error from timer");
21+
// },
22+
// );
23+
24+
// class ApplicationDelegate extends NSObject {
25+
// static ObjCProtocols = [NSApplicationDelegate];
26+
27+
// static {
28+
// NativeClass(this);
29+
// }
30+
31+
// applicationDidFinishLaunching(_notification) {
32+
// console.log("Hello, World! from applicationDidFinishLaunching");
33+
// throw new Error("JavaScript error from applicationDidFinishLaunching");
34+
// }
35+
// }
36+
37+
// const appDelegate = ApplicationDelegate.new();
38+
// const app = NSApplication.sharedApplication;
39+
// app.delegate = appDelegate;
40+
// app.setActivationPolicy(NSApplicationActivationPolicy.Regular);
41+
42+
// NSApplicationMain(0, null);
43+
44+
// const arr = NSArray.arrayWithArray([1, 2, 3]);
45+
46+
// arr.enumerateObjectsUsingBlock((_obj, _idx, _stop) => {
47+
// throw new Error("JavaScript error from block");
48+
// });

0 commit comments

Comments
 (0)