Skip to content

Commit b29e84f

Browse files
committed
imp(): move getFunctionContext to utils
1 parent d08c1ba commit b29e84f

File tree

4 files changed

+287
-294
lines changed

4 files changed

+287
-294
lines changed

workers/javascript/src/index.ts

Lines changed: 2 additions & 116 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,8 @@ import { JavaScriptEventWorkerTask } from '../types/javascript-event-worker-task
1010
import { BeautifyBacktracePayload } from '../types/beautify-backtrace-payload';
1111
import HawkCatcher from '@hawk.so/nodejs';
1212
import { BacktraceFrame, CatcherMessagePayload, CatcherMessageType, ErrorsCatcherType, SourceCodeLine, SourceMapDataExtended } from '@hawk.so/types';
13-
import { beautifyUserAgent, getBabelParserPluginsForFile, extractScriptFromSFC } from './utils';
13+
import { beautifyUserAgent, getBabelParserPluginsForFile, extractScriptFromSFC, getFunctionContext } from './utils';
1414
import { Collection } from 'mongodb';
15-
import { parse } from '@babel/parser';
16-
import traverse from '@babel/traverse';
1715
/* eslint-disable-next-line no-unused-vars */
1816
import { memoize } from '../../../lib/memoize';
1917

@@ -234,7 +232,7 @@ export default class JavascriptEventWorker extends EventWorker {
234232

235233
const originalContent = consumer.sourceContentFor(originalLocation.source);
236234

237-
functionContext = await this.getFunctionContext(
235+
functionContext = await getFunctionContext(
238236
originalContent,
239237
originalLocation.line,
240238
originalLocation.source
@@ -255,118 +253,6 @@ export default class JavascriptEventWorker extends EventWorker {
255253
}) as BacktraceFrame;
256254
}
257255

258-
/**
259-
* Method that is used to parse full function context of the code position
260-
*
261-
* @param sourceCode - content of the source file
262-
* @param line - number of the line from the stack trace
263-
* @param sourcePath - original source path from the source map (used to pick parser plugins)
264-
* @returns {string | null} - string of the function context or null if it could not be parsed
265-
*/
266-
private getFunctionContext(sourceCode: string, line: number, sourcePath?: string): string | null {
267-
if (!sourceCode) {
268-
return null;
269-
}
270-
271-
const {
272-
code: codeToParse,
273-
targetLine,
274-
hasTypeScriptLang,
275-
} = extractScriptFromSFC(sourceCode, line, sourcePath);
276-
277-
let functionName: string | null = null;
278-
let className: string | null = null;
279-
let isAsync = false;
280-
281-
try {
282-
const parserPlugins = getBabelParserPluginsForFile(sourcePath, hasTypeScriptLang);
283-
284-
const ast = parse(codeToParse, {
285-
sourceType: 'module',
286-
plugins: parserPlugins,
287-
});
288-
289-
traverse(ast as any, {
290-
/**
291-
* It is used to get class decorator of the position, it will save class that is related to original position
292-
*
293-
* @param path
294-
*/
295-
ClassDeclaration(path) {
296-
if (path.node.loc && path.node.loc.start.line <= targetLine && path.node.loc.end.line >= targetLine) {
297-
console.log(`class declaration: loc: ${path.node.loc}, targetLine: ${targetLine}, node.start.line: ${path.node.loc.start.line}, node.end.line: ${path.node.loc.end.line}`);
298-
299-
className = path.node.id.name || null;
300-
}
301-
},
302-
/**
303-
* It is used to get class and its method decorator of the position
304-
* It will save class and method, that are related to original position
305-
*
306-
* @param path
307-
*/
308-
ClassMethod(path) {
309-
if (path.node.loc && path.node.loc.start.line <= targetLine && path.node.loc.end.line >= targetLine) {
310-
console.log(`class declaration: loc: ${path.node.loc}, targetLine: ${targetLine}, node.start.line: ${path.node.loc.start.line}, node.end.line: ${path.node.loc.end.line}`);
311-
312-
// Handle different key types
313-
if (path.node.key.type === 'Identifier') {
314-
functionName = path.node.key.name;
315-
}
316-
isAsync = path.node.async;
317-
}
318-
},
319-
/**
320-
* It is used to get function name that is declared out of class
321-
*
322-
* @param path
323-
*/
324-
FunctionDeclaration(path) {
325-
if (path.node.loc && path.node.loc.start.line <= targetLine && path.node.loc.end.line >= targetLine) {
326-
console.log(`function declaration: loc: ${path.node.loc}, targetLine: ${targetLine}, node.start.line: ${path.node.loc.start.line}, node.end.line: ${path.node.loc.end.line}`);
327-
328-
functionName = path.node.id.name || null;
329-
isAsync = path.node.async;
330-
}
331-
},
332-
/**
333-
* It is used to get anonimous function names in function expressions or arrow function expressions
334-
*
335-
* @param path
336-
*/
337-
VariableDeclarator(path) {
338-
if (
339-
path.node.init &&
340-
(path.node.init.type === 'FunctionExpression' || path.node.init.type === 'ArrowFunctionExpression') &&
341-
path.node.loc &&
342-
path.node.loc.start.line <= targetLine &&
343-
path.node.loc.end.line >= targetLine
344-
) {
345-
console.log(`variable declaration: node.type: ${path.node.init.type}, targetLine: ${targetLine}, `);
346-
347-
// Handle different id types
348-
if (path.node.id.type === 'Identifier') {
349-
functionName = path.node.id.name;
350-
}
351-
isAsync = (path.node.init as any).async;
352-
}
353-
},
354-
});
355-
} catch (traverseError) {
356-
console.error(`Failed to parse source code:`);
357-
console.error(traverseError);
358-
359-
HawkCatcher.send(traverseError, {
360-
sourceCode: codeToParse,
361-
targetLine,
362-
hasTypeScriptLang,
363-
sourcePath,
364-
});
365-
}
366-
367-
return functionName ? `${isAsync ? 'async ' : ''}${className ? `${className}.` : ''}${functionName}` : null;
368-
}
369-
370256
/**
371257
* Downloads source map file from Grid FS
372258
*

workers/javascript/src/utils.ts

Lines changed: 116 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
import { JavaScriptAddons } from '@hawk.so/types';
22
import useragent from 'useragent';
33
import { extname } from 'path';
4+
import { parse } from '@babel/parser';
5+
import traverse from '@babel/traverse';
6+
import HawkCatcher from '@hawk.so/nodejs';
47

58
/**
69
* Converts userAgent to strict format for: browser browserVersion / OS OsVersion
@@ -166,4 +169,116 @@ export function getBabelParserPluginsForFile(sourcePath?: string, hasTypeScriptL
166169
}
167170

168171
return basePlugins;
169-
}
172+
}
173+
174+
/**
175+
* Method that is used to parse full function context of the code position
176+
*
177+
* @param sourceCode - content of the source file
178+
* @param line - number of the line from the stack trace
179+
* @param sourcePath - original source path from the source map (used to pick parser plugins)
180+
* @returns {string | null} - string of the function context or null if it could not be parsed
181+
*/
182+
export function getFunctionContext(sourceCode: string, line: number, sourcePath?: string): string | null {
183+
if (!sourceCode) {
184+
return null;
185+
}
186+
187+
const {
188+
code: codeToParse,
189+
targetLine,
190+
hasTypeScriptLang,
191+
} = extractScriptFromSFC(sourceCode, line, sourcePath);
192+
193+
let functionName: string | null = null;
194+
let className: string | null = null;
195+
let isAsync = false;
196+
197+
try {
198+
const parserPlugins = getBabelParserPluginsForFile(sourcePath, hasTypeScriptLang);
199+
200+
const ast = parse(codeToParse, {
201+
sourceType: 'module',
202+
plugins: parserPlugins,
203+
});
204+
205+
traverse(ast as any, {
206+
/**
207+
* It is used to get class decorator of the position, it will save class that is related to original position
208+
*
209+
* @param path
210+
*/
211+
ClassDeclaration(path) {
212+
if (path.node.loc && path.node.loc.start.line <= targetLine && path.node.loc.end.line >= targetLine) {
213+
console.log(`class declaration: loc: ${path.node.loc}, targetLine: ${targetLine}, node.start.line: ${path.node.loc.start.line}, node.end.line: ${path.node.loc.end.line}`);
214+
215+
className = path.node.id.name || null;
216+
}
217+
},
218+
/**
219+
* It is used to get class and its method decorator of the position
220+
* It will save class and method, that are related to original position
221+
*
222+
* @param path
223+
*/
224+
ClassMethod(path) {
225+
if (path.node.loc && path.node.loc.start.line <= targetLine && path.node.loc.end.line >= targetLine) {
226+
console.log(`class declaration: loc: ${path.node.loc}, targetLine: ${targetLine}, node.start.line: ${path.node.loc.start.line}, node.end.line: ${path.node.loc.end.line}`);
227+
228+
// Handle different key types
229+
if (path.node.key.type === 'Identifier') {
230+
functionName = path.node.key.name;
231+
}
232+
isAsync = path.node.async;
233+
}
234+
},
235+
/**
236+
* It is used to get function name that is declared out of class
237+
*
238+
* @param path
239+
*/
240+
FunctionDeclaration(path) {
241+
if (path.node.loc && path.node.loc.start.line <= targetLine && path.node.loc.end.line >= targetLine) {
242+
console.log(`function declaration: loc: ${path.node.loc}, targetLine: ${targetLine}, node.start.line: ${path.node.loc.start.line}, node.end.line: ${path.node.loc.end.line}`);
243+
244+
functionName = path.node.id.name || null;
245+
isAsync = path.node.async;
246+
}
247+
},
248+
/**
249+
* It is used to get anonimous function names in function expressions or arrow function expressions
250+
*
251+
* @param path
252+
*/
253+
VariableDeclarator(path) {
254+
if (
255+
path.node.init &&
256+
(path.node.init.type === 'FunctionExpression' || path.node.init.type === 'ArrowFunctionExpression') &&
257+
path.node.loc &&
258+
path.node.loc.start.line <= targetLine &&
259+
path.node.loc.end.line >= targetLine
260+
) {
261+
console.log(`variable declaration: node.type: ${path.node.init.type}, targetLine: ${targetLine}, `);
262+
263+
// Handle different id types
264+
if (path.node.id.type === 'Identifier') {
265+
functionName = path.node.id.name;
266+
}
267+
isAsync = (path.node.init as any).async;
268+
}
269+
},
270+
});
271+
} catch (traverseError) {
272+
console.error(`Failed to parse source code:`);
273+
console.error(traverseError);
274+
275+
HawkCatcher.send(traverseError, {
276+
sourceCode: codeToParse,
277+
targetLine,
278+
hasTypeScriptLang,
279+
sourcePath,
280+
});
281+
}
282+
283+
return functionName ? `${isAsync ? 'async ' : ''}${className ? `${className}.` : ''}${functionName}` : null;
284+
}

0 commit comments

Comments
 (0)