UNPKG

isaacscript-common

Version:

Helper functions and features for IsaacScript mods.

83 lines (66 loc) 2.67 kB
import { getTraceback, isLuaDebugEnabled } from "./functions/debugFunctions"; declare let error: ErrorFunction; declare let __PATCHED_ERROR: boolean | undefined; // eslint-disable-line type ErrorFunction = (this: void, message: string, level?: number) => never; const LINE_SEPARATOR = "\n"; /** * These must be listed in order from how they appear in the traceback from top to bottom, or they * won't be properly removed. */ const USELESS_TRACEBACK_MESSAGES = [ // The second line of the traceback will always be the "getTraceback" function. "in upvalue 'getTraceback'", "in function 'sandbox.GetTraceback'", // The third line of the traceback will always be a line within the "errorWithTraceback" function. "in function 'error'", ] as const; let vanillaError: ErrorFunction | undefined; /** * In Lua, the `error` function will tell you the line number of the error, but not give you a full * traceback of the parent functions, which is unlike how JavaScript works. This function monkey * patches the `error` function to add this functionality. * * Traceback functionality can only be added if the "--luadebug" flag is turned on, so this function * does nothing if the "--luadebug" flag is disabled. */ export function patchErrorFunction(): void { // Only replace the function if the "--luadebug" launch flag is enabled. if (!isLuaDebugEnabled()) { return; } // Do nothing if the function was already patched. if (__PATCHED_ERROR !== undefined) { return; } __PATCHED_ERROR = true; vanillaError = error; error = errorWithTraceback; } function errorWithTraceback(this: void, message: string, level = 1): never { if (vanillaError === undefined) { error(message, level); } const tracebackOutput = getTraceback(); const slimmedTracebackOutput = slimTracebackOutput(tracebackOutput); message += "\n"; message += slimmedTracebackOutput; // We add one to the level so that the error message appears to originate at the parent function. return vanillaError(message, level + 1); } /** * Some lines of the traceback output will not be relevant to the error that just occurred. Thus, to * reduce noise, we can always remove these lines. */ function slimTracebackOutput(tracebackOutput: string) { for (const msg of USELESS_TRACEBACK_MESSAGES) { tracebackOutput = removeLinesContaining(tracebackOutput, msg); } return tracebackOutput; } function removeLinesContaining(msg: string, containsMsg: string) { const lines = msg.split(LINE_SEPARATOR); const linesThatDontContain = lines.filter( (line) => !line.includes(containsMsg), ); return linesThatDontContain.join(LINE_SEPARATOR); }