@@ -114,14 +114,17 @@ bool IsLikelyOptionalModule(const std::string& moduleName) {
114114void 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\n JavaScript stack trace:" + jsStackTrace;
214+ contextMsg += " \n\n Original error:\n " + ex.getMessage ();
215+
216+ // Include original stack trace if available
217+ if (!ex.getStackTrace ().empty ()) {
218+ contextMsg += " \n\n Original 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\n Original 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 ];
0 commit comments