@@ -10,11 +10,8 @@ import { JavaScriptEventWorkerTask } from '../types/javascript-event-worker-task
1010import { BeautifyBacktracePayload } from '../types/beautify-backtrace-payload' ;
1111import HawkCatcher from '@hawk.so/nodejs' ;
1212import { BacktraceFrame , CatcherMessagePayload , CatcherMessageType , ErrorsCatcherType , SourceCodeLine , SourceMapDataExtended } from '@hawk.so/types' ;
13- import { beautifyUserAgent } from './utils' ;
13+ import { beautifyUserAgent , getFunctionContext } from './utils' ;
1414import { Collection } from 'mongodb' ;
15- import { parse } from '@babel/parser' ;
16- import traverse from '@babel/traverse' ;
17- import { extname } from 'path' ;
1815/* eslint-disable-next-line no-unused-vars */
1916import { memoize } from '../../../lib/memoize' ;
2017
@@ -135,6 +132,9 @@ export default class JavascriptEventWorker extends EventWorker {
135132 */
136133 HawkCatcher . send ( error , {
137134 payload : backtrace as unknown as Record < string , never > ,
135+ releaseRecord : JSON . stringify ( releaseRecord ) ,
136+ backtrace : JSON . stringify ( backtrace ) ,
137+ projectId,
138138 } ) ;
139139
140140 return backtrace [ index ] ;
@@ -232,13 +232,13 @@ export default class JavascriptEventWorker extends EventWorker {
232232
233233 const originalContent = consumer . sourceContentFor ( originalLocation . source ) ;
234234
235- functionContext = await this . getFunctionContext (
235+ functionContext = await getFunctionContext (
236236 originalContent ,
237237 originalLocation . line ,
238238 originalLocation . source
239239 ) ?? originalLocation . name ;
240240 } catch ( e ) {
241- HawkCatcher . send ( e ) ;
241+ HawkCatcher . send ( e , { stackFrame : JSON . stringify ( stackFrame ) } ) ;
242242 this . logger . error ( 'Can\'t get function context' ) ;
243243 this . logger . error ( e ) ;
244244 }
@@ -253,103 +253,6 @@ export default class JavascriptEventWorker extends EventWorker {
253253 } ) as BacktraceFrame ;
254254 }
255255
256- /**
257- * Method that is used to parse full function context of the code position
258- *
259- * @param sourceCode - content of the source file
260- * @param line - number of the line from the stack trace
261- * @param sourcePath - original source path from the source map (used to pick parser plugins)
262- * @returns {string | null } - string of the function context or null if it could not be parsed
263- */
264- private getFunctionContext ( sourceCode : string , line : number , sourcePath ?: string ) : string | null {
265- let functionName : string | null = null ;
266- let className : string | null = null ;
267- let isAsync = false ;
268-
269- try {
270- const parserPlugins = this . getBabelParserPluginsForFile ( sourcePath ) ;
271-
272- const ast = parse ( sourceCode , {
273- sourceType : 'module' ,
274- plugins : parserPlugins ,
275- } ) ;
276-
277- traverse ( ast as any , {
278- /**
279- * It is used to get class decorator of the position, it will save class that is related to original position
280- *
281- * @param path
282- */
283- ClassDeclaration ( path ) {
284- if ( path . node . loc && path . node . loc . start . line <= line && path . node . loc . end . line >= line ) {
285- console . log ( `class declaration: loc: ${ path . node . loc } , line: ${ line } , node.start.line: ${ path . node . loc . start . line } , node.end.line: ${ path . node . loc . end . line } ` ) ;
286-
287- className = path . node . id . name || null ;
288- }
289- } ,
290- /**
291- * It is used to get class and its method decorator of the position
292- * It will save class and method, that are related to original position
293- *
294- * @param path
295- */
296- ClassMethod ( path ) {
297- if ( path . node . loc && path . node . loc . start . line <= line && path . node . loc . end . line >= line ) {
298- console . log ( `class declaration: loc: ${ path . node . loc } , line: ${ line } , node.start.line: ${ path . node . loc . start . line } , node.end.line: ${ path . node . loc . end . line } ` ) ;
299-
300- // Handle different key types
301- if ( path . node . key . type === 'Identifier' ) {
302- functionName = path . node . key . name ;
303- }
304- isAsync = path . node . async ;
305- }
306- } ,
307- /**
308- * It is used to get function name that is declared out of class
309- *
310- * @param path
311- */
312- FunctionDeclaration ( path ) {
313- if ( path . node . loc && path . node . loc . start . line <= line && path . node . loc . end . line >= line ) {
314- console . log ( `function declaration: loc: ${ path . node . loc } , line: ${ line } , node.start.line: ${ path . node . loc . start . line } , node.end.line: ${ path . node . loc . end . line } ` ) ;
315-
316- functionName = path . node . id . name || null ;
317- isAsync = path . node . async ;
318- }
319- } ,
320- /**
321- * It is used to get anonimous function names in function expressions or arrow function expressions
322- *
323- * @param path
324- */
325- VariableDeclarator ( path ) {
326- if (
327- path . node . init &&
328- ( path . node . init . type === 'FunctionExpression' || path . node . init . type === 'ArrowFunctionExpression' ) &&
329- path . node . loc &&
330- path . node . loc . start . line <= line &&
331- path . node . loc . end . line >= line
332- ) {
333- console . log ( `variable declaration: node.type: ${ path . node . init . type } , line: ${ line } , ` ) ;
334-
335- // Handle different id types
336- if ( path . node . id . type === 'Identifier' ) {
337- functionName = path . node . id . name ;
338- }
339- isAsync = ( path . node . init as any ) . async ;
340- }
341- } ,
342- } ) ;
343- } catch ( traverseError ) {
344- console . error ( `Failed to parse source code:` ) ;
345- console . error ( traverseError ) ;
346-
347- HawkCatcher . send ( traverseError ) ;
348- }
349-
350- return functionName ? `${ isAsync ? 'async ' : '' } ${ className ? `${ className } .` : '' } ${ functionName } ` : null ;
351- }
352-
353256 /**
354257 * Downloads source map file from Grid FS
355258 *
@@ -451,55 +354,4 @@ export default class JavascriptEventWorker extends EventWorker {
451354 this . logger . error ( `Error on source-map consumer initialization: ${ e } ` ) ;
452355 }
453356 }
454-
455- /**
456- * Choose babel parser plugins based on source file extension
457- *
458- * @param sourcePath - original file path from source map (e.g. "src/App.tsx")
459- */
460- private getBabelParserPluginsForFile ( sourcePath ?: string ) : any [ ] {
461- const basePlugins : string [ ] = [
462- 'classProperties' ,
463- 'decorators' ,
464- 'optionalChaining' ,
465- 'nullishCoalescingOperator' ,
466- 'dynamicImport' ,
467- 'bigInt' ,
468- 'topLevelAwait' ,
469- ] ;
470-
471- /**
472- * Default - use only typescript plugin because it's more stable and less likely will produce errors
473- */
474- let enableTypeScript = true ;
475- let enableJSX = false ;
476-
477- if ( sourcePath ) {
478- // remove query/hash if there is any
479- const cleanPath = sourcePath . split ( '?' ) [ 0 ] . split ( '#' ) [ 0 ] ;
480- const ext = extname ( cleanPath ) . toLowerCase ( ) ;
481-
482- const isTs = ext === '.ts' || ext === '.d.ts' ;
483- const isTsx = ext === '.tsx' ;
484- const isJs = ext === '.js' || ext === '.mjs' || ext === '.cjs' ;
485- const isJsx = ext === '.jsx' ;
486-
487- enableTypeScript = isTs || isTsx ;
488- // JSX:
489- // - for .ts/.d.ts — DISABLE
490- // - for .tsx/.jsx — ENABLE
491- // - for .js — keep enabled, to not break App.js with JSX
492- enableJSX = isTsx || isJsx || isJs ;
493- }
494-
495- if ( enableTypeScript ) {
496- basePlugins . push ( 'typescript' ) ;
497- }
498-
499- if ( enableJSX ) {
500- basePlugins . push ( 'jsx' ) ;
501- }
502-
503- return basePlugins ;
504- }
505357}
0 commit comments