Skip to content

Commit 109775b

Browse files
committed
feat: more verbose exception output
1 parent bd6aee6 commit 109775b

File tree

2 files changed

+120
-27
lines changed

2 files changed

+120
-27
lines changed

NativeScript/runtime/ModuleInternal.mm

Lines changed: 87 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -114,14 +114,17 @@ bool IsLikelyOptionalModule(const std::string& moduleName) {
114114
void ModuleInternal::RequireCallback(const FunctionCallbackInfo<Value>& info) {
115115
Isolate* isolate = info.GetIsolate();
116116

117+
// Declare these outside try block so they're available in catch
118+
std::string moduleName;
119+
std::string callingModuleDirName;
120+
NSString* fullPath = nil;
121+
117122
try {
118123
ModuleInternal* moduleInternal =
119124
static_cast<ModuleInternal*>(info.Data().As<External>()->Value());
120125

121-
std::string moduleName = tns::ToString(isolate, info[0].As<v8::String>());
122-
std::string callingModuleDirName = tns::ToString(isolate, info[1].As<v8::String>());
123-
124-
NSString* fullPath;
126+
moduleName = tns::ToString(isolate, info[0].As<v8::String>());
127+
callingModuleDirName = tns::ToString(isolate, info[1].As<v8::String>());
125128
if (moduleName.length() > 0 && moduleName[0] != '/') {
126129
if (moduleName[0] == '.') {
127130
fullPath = [[NSString stringWithUTF8String:callingModuleDirName.c_str()]
@@ -173,7 +176,50 @@ bool IsLikelyOptionalModule(const std::string& moduleName) {
173176
info.GetReturnValue().Set(exportsObj);
174177
}
175178
} catch (NativeScriptException& ex) {
176-
ex.ReThrowToV8(isolate);
179+
// Add context about the require call
180+
std::string contextMsg = "Error in require() call:";
181+
contextMsg += "\n Requested module: '" + moduleName + "'";
182+
contextMsg += "\n Called from: " + callingModuleDirName;
183+
if (fullPath != nil) {
184+
contextMsg += "\n Resolved path: " + std::string([fullPath UTF8String]);
185+
}
186+
187+
// Add JavaScript stack trace to show who called require
188+
Local<StackTrace> stackTrace =
189+
StackTrace::CurrentStackTrace(isolate, 10, StackTrace::StackTraceOptions::kDetailed);
190+
std::string jsStackTrace = "";
191+
if (!stackTrace.IsEmpty()) {
192+
for (int i = 0; i < stackTrace->GetFrameCount(); i++) {
193+
Local<StackFrame> frame = stackTrace->GetFrame(isolate, i);
194+
Local<v8::String> scriptName = frame->GetScriptName();
195+
Local<v8::String> functionName = frame->GetFunctionName();
196+
int lineNumber = frame->GetLineNumber();
197+
int columnNumber = frame->GetColumn();
198+
199+
jsStackTrace += "\n at ";
200+
std::string funcName = tns::ToString(isolate, functionName);
201+
std::string scriptNameStr = tns::ToString(isolate, scriptName);
202+
203+
if (!funcName.empty()) {
204+
jsStackTrace += funcName + " (";
205+
} else {
206+
jsStackTrace += "<anonymous> (";
207+
}
208+
jsStackTrace += scriptNameStr + ":" + std::to_string(lineNumber) + ":" +
209+
std::to_string(columnNumber) + ")";
210+
}
211+
}
212+
213+
contextMsg += "\n\nJavaScript stack trace:" + jsStackTrace;
214+
contextMsg += "\n\nOriginal error:\n" + ex.getMessage();
215+
216+
// Include original stack trace if available
217+
if (!ex.getStackTrace().empty()) {
218+
contextMsg += "\n\nOriginal stack trace:\n" + ex.getStackTrace();
219+
}
220+
221+
NativeScriptException contextEx(isolate, contextMsg);
222+
contextEx.ReThrowToV8(isolate);
177223
}
178224
}
179225

@@ -191,7 +237,20 @@ bool IsLikelyOptionalModule(const std::string& moduleName) {
191237

192238
Local<Object> moduleObj;
193239
Local<Value> exportsObj;
194-
std::string path = this->ResolvePath(isolate, baseDir, moduleName);
240+
std::string path;
241+
242+
try {
243+
path = this->ResolvePath(isolate, baseDir, moduleName);
244+
} catch (NativeScriptException& ex) {
245+
// Add context about the module resolution
246+
std::string contextMsg = "Failed to resolve module: '" + moduleName + "'";
247+
contextMsg += "\n Base directory: " + baseDir;
248+
contextMsg += "\n Module name: " + moduleName;
249+
contextMsg += "\n\nOriginal error:\n" + ex.getMessage();
250+
251+
throw NativeScriptException(isolate, contextMsg);
252+
}
253+
195254
if (path.empty()) {
196255
// Create placeholder module for optional modules
197256
if (IsLikelyOptionalModule(moduleName)) {
@@ -531,7 +590,20 @@ ScriptOrigin origin(
531590
// Return empty string to indicate optional module not found
532591
return std::string();
533592
}
534-
throw NativeScriptException("The specified module does not exist: " + moduleName);
593+
594+
// Create a detailed error message with context
595+
std::string errorMsg = "Module not found: '" + moduleName + "'";
596+
errorMsg += "\n Base directory: " + baseDir;
597+
errorMsg += "\n Attempted paths:";
598+
599+
// Show the original path attempt
600+
NSString* originalPath =
601+
[[baseDirStr stringByAppendingPathComponent:moduleNameStr] stringByStandardizingPath];
602+
errorMsg += "\n - " + std::string([originalPath UTF8String]);
603+
errorMsg +=
604+
"\n - " + std::string([[originalPath stringByAppendingPathExtension:@"mjs"] UTF8String]);
605+
606+
throw NativeScriptException(isolate, errorMsg);
535607
}
536608

537609
if (isDirectory == NO) {
@@ -569,7 +641,14 @@ throw NativeScriptException("Unable to locate main entry in " +
569641
// Return empty string to indicate optional module not found
570642
return std::string();
571643
}
572-
throw NativeScriptException("The specified module does not exist: " + moduleName);
644+
645+
// Create a detailed error message with context for package.json resolution
646+
std::string errorMsg = "Module not found: '" + moduleName + "'";
647+
errorMsg += "\n Base directory: " + baseDir;
648+
errorMsg += "\n Attempted final paths:";
649+
errorMsg += "\n - " + std::string([fullPath UTF8String]);
650+
651+
throw NativeScriptException(isolate, errorMsg);
573652
}
574653

575654
return [fullPath UTF8String];
Lines changed: 33 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,45 @@
11
#ifndef NativeScriptException_h
22
#define NativeScriptException_h
33

4-
#include "Common.h"
54
#include <string>
65

6+
#include "Common.h"
7+
78
namespace tns {
89

910
class NativeScriptException {
10-
public:
11-
NativeScriptException(const std::string& message);
12-
NativeScriptException(v8::Isolate* isolate, v8::TryCatch& tc, const std::string& message);
13-
NativeScriptException(v8::Isolate* isolate, const std::string& message, const std::string& name = "NativeScriptException");
14-
~NativeScriptException();
15-
void ReThrowToV8(v8::Isolate* isolate);
16-
static void OnUncaughtError(v8::Local<v8::Message> message, v8::Local<v8::Value> error);
17-
private:
18-
v8::Persistent<v8::Value>* javascriptException_;
19-
std::string name_;
20-
std::string message_;
21-
std::string stackTrace_;
22-
std::string fullMessage_;
23-
static std::string GetErrorStackTrace(v8::Isolate* isolate, const v8::Local<v8::StackTrace>& stackTrace);
24-
static std::string GetErrorMessage(v8::Isolate* isolate, v8::Local<v8::Value>& error, const std::string& prependMessage = "");
25-
static std::string GetFullMessage(v8::Isolate* isolate, const v8::TryCatch& tc, const std::string& jsExceptionMessage);
26-
static std::string GetFullMessage(v8::Isolate* isolate, v8::Local<v8::Message> message, const std::string& jsExceptionMessage);
11+
public:
12+
NativeScriptException(const std::string& message);
13+
NativeScriptException(v8::Isolate* isolate, v8::TryCatch& tc,
14+
const std::string& message);
15+
NativeScriptException(v8::Isolate* isolate, const std::string& message,
16+
const std::string& name = "NativeScriptException");
17+
~NativeScriptException();
18+
void ReThrowToV8(v8::Isolate* isolate);
19+
const std::string& getMessage() const { return message_; }
20+
const std::string& getStackTrace() const { return stackTrace_; }
21+
static void OnUncaughtError(v8::Local<v8::Message> message,
22+
v8::Local<v8::Value> error);
23+
24+
private:
25+
v8::Persistent<v8::Value>* javascriptException_;
26+
std::string name_;
27+
std::string message_;
28+
std::string stackTrace_;
29+
std::string fullMessage_;
30+
static std::string GetErrorStackTrace(
31+
v8::Isolate* isolate, const v8::Local<v8::StackTrace>& stackTrace);
32+
static std::string GetErrorMessage(v8::Isolate* isolate,
33+
v8::Local<v8::Value>& error,
34+
const std::string& prependMessage = "");
35+
static std::string GetFullMessage(v8::Isolate* isolate,
36+
const v8::TryCatch& tc,
37+
const std::string& jsExceptionMessage);
38+
static std::string GetFullMessage(v8::Isolate* isolate,
39+
v8::Local<v8::Message> message,
40+
const std::string& jsExceptionMessage);
2741
};
2842

29-
}
43+
} // namespace tns
3044

3145
#endif /* NativeScriptException_h */

0 commit comments

Comments
 (0)