Created
December 16, 2022 05:32
-
-
Save uladkasach/bdcbad1a7a5152af7d6ceed06a1661eb to your computer and use it in GitHub Desktop.
getFirstFunctionNameFromCallStack
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { getFirstFunctionNameFromCallStack } from './getFirstFunctionNameFromCallStack'; | |
export const someSuperCoolAnonymousFunctionAssignedToAVariableIWantTheNameOf = | |
() => { | |
const methodName = getFirstFunctionNameFromCallStack(); | |
return { methodName }; | |
}; | |
export const someSuperCoolNamedFunctionIWantTheNameOfWhichHappensToAlsoBeAssignedToAVariable = | |
function someSuperCoolNamedFunctionIWantTheNameOf() { | |
const methodName = getFirstFunctionNameFromCallStack(); | |
return { methodName }; | |
}; | |
describe('getFirstMethodNameFromCallStack', () => { | |
it('should return the name of the variable an anonymous function was assigned to, when run in an anonymous function', async () => { | |
const { methodName } = | |
someSuperCoolAnonymousFunctionAssignedToAVariableIWantTheNameOf(); | |
expect(methodName).toEqual( | |
'someSuperCoolAnonymousFunctionAssignedToAVariableIWantTheNameOf', | |
); | |
}); | |
it('returns the declared name of the function, ignoring the name of the variable it was assigned to', () => { | |
const { methodName } = | |
someSuperCoolNamedFunctionIWantTheNameOfWhichHappensToAlsoBeAssignedToAVariable(); | |
expect(methodName).toEqual('someSuperCoolNamedFunctionIWantTheNameOf'); | |
}); | |
}); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* eslint-disable no-restricted-syntax */ | |
/** | |
* returns the first name found in the call stack at runtime | |
* | |
* relevance | |
* - find the name of the variable that an anonymous function was assigned to | |
* | |
* note | |
* - uses Error.prepareStackTrace and Error.captureStackTrace to access the stack trace at runtime | |
* - ⚠️ Error.captureStackTrace is an expensive operation; the results of this operation should be cached | |
* - ⚠️ if the function you want the name of is defined in a jest test file, this method will always return `next`. (try defining your function in a different file and importing it instead) | |
* | |
* ref | |
* - https://v8.dev/docs/stack-trace-api#customizing-stack-traces | |
* - https://stackoverflow.com/a/21666875/3068233 | |
*/ | |
export const getFirstFunctionNameFromCallStack = (): string | null => { | |
const obj = { stack: [] as any[] }; | |
const prepare = Error.prepareStackTrace; | |
Error.prepareStackTrace = (_, stack) => stack; | |
try { | |
Error.captureStackTrace(obj); | |
obj.stack.forEach((stackEntry, index) => { | |
console.log({ | |
methodName: stackEntry.getMethodName(), | |
functionName: stackEntry.getFunctionName(), | |
index, | |
}); | |
}); | |
return ( | |
obj.stack | |
.find((stackEntry: any, index: number) => { | |
// if its the first index, ignore it, since it will always show `getFirstMethodNameFromCallStack` | |
if (index === 0) return false; | |
// return the first stackEntry who's name is not null | |
return stackEntry.getFunctionName() !== null; | |
}) | |
?.getFunctionName() ?? null // now grab the name, and default to null if no item was found | |
); | |
} finally { | |
Error.prepareStackTrace = prepare; // ensure to _always_ reset the prepare function. otherwise, we would have borked all error stack tracing going forward 😬 | |
} | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment