DevToolsInfaillibleUtils.sys.mjs (2960B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 /** 6 * The 3 methods here are duplicated from ThreadSafeDevToolsUtils.js 7 * The ones defined here are used from other sys.mjs files, mostly from the 8 * NetworkObserver codebase, while the ones remaining in ThreadSafeDevToolsUtils.js 9 * are used in commonjs modules, including modules which can be loaded in workers. 10 * 11 * sys.mjs modules are currently not supported in workers, see Bug 1247687. 12 */ 13 14 /** 15 * Report that |who| threw an exception, |exception|. 16 */ 17 function reportException(who, exception) { 18 const msg = `${who} threw an exception: ${safeErrorString(exception)}`; 19 dump(msg + "\n"); 20 21 if (typeof console !== "undefined" && console && console.error) { 22 console.error(exception); 23 } 24 } 25 26 /** 27 * Given a handler function that may throw, return an infallible handler 28 * function that calls the fallible handler, and logs any exceptions it 29 * throws. 30 * 31 * @param handler function 32 * A handler function, which may throw. 33 * @param aName string 34 * A name for handler, for use in error messages. If omitted, we use 35 * handler.name. 36 * 37 * (SpiderMonkey does generate good names for anonymous functions, but we 38 * don't have a way to get at them from JavaScript at the moment.) 39 */ 40 function makeInfallible(handler, name = handler.name) { 41 return function () { 42 try { 43 return handler.apply(this, arguments); 44 } catch (ex) { 45 let who = "Handler function"; 46 if (name) { 47 who += " " + name; 48 } 49 reportException(who, ex); 50 return undefined; 51 } 52 }; 53 } 54 55 /** 56 * Turn the |error| into a string, without fail. 57 * 58 * @param {Error|any} error 59 */ 60 function safeErrorString(error) { 61 try { 62 let errorString = error.toString(); 63 if (typeof errorString == "string") { 64 // Attempt to attach a stack to |errorString|. If it throws an error, or 65 // isn't a string, don't use it. 66 try { 67 if (error.stack) { 68 const stack = error.stack.toString(); 69 if (typeof stack == "string") { 70 errorString += "\nStack: " + stack; 71 } 72 } 73 } catch (ee) { 74 // Ignore. 75 } 76 77 // Append additional line and column number information to the output, 78 // since it might not be part of the stringified error. 79 if ( 80 typeof error.lineNumber == "number" && 81 typeof error.columnNumber == "number" 82 ) { 83 errorString += 84 "Line: " + error.lineNumber + ", column: " + error.columnNumber; 85 } 86 87 return errorString; 88 } 89 } catch (ee) { 90 // Ignore. 91 } 92 93 // We failed to find a good error description, so do the next best thing. 94 return Object.prototype.toString.call(error); 95 } 96 97 export const DevToolsInfaillibleUtils = { 98 makeInfallible, 99 reportException, 100 safeErrorString, 101 };