Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 51 additions & 4 deletions extract.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ const allFunctions: string[] = [];
const calledFunctions: Map<string, string[]> = new Map();

let currentFunction = undefined; // to keep track of which function we are inside
let currentClass = undefined; // to keep track of which class we are inside

// =================================================================================================

Expand All @@ -34,6 +35,25 @@ function extractFunctionCalls(node: ts.Node, sourceFile: ts.SourceFile, indentLe
});
}

// e.g. `this.hello()`
if (ts.isMethodDeclaration(node)) {
if (node.name && ts.isIdentifier(node.name)) {
const methodName: string = node.name.getText(sourceFile);
const declaredFunction: string = currentClass ? `${currentClass}.${methodName}` : methodName;
if (!allFunctions.includes(declaredFunction)) { // This guard is necessary to prevent duplicates of class methods from appearing.
updateDeclaredFunctions(declaredFunction);
}
}
}

// e.g. `constructor()`
if (ts.isConstructorDeclaration(node)) {
const declaredFunction = currentClass ? `${currentClass}.constructor` : 'constructor';
if (!allFunctions.includes(declaredFunction)) {
updateDeclaredFunctions(declaredFunction);
}
}

// Arrow function
if (
ts.isVariableDeclaration(node) &&
Expand All @@ -51,16 +71,43 @@ function extractFunctionCalls(node: ts.Node, sourceFile: ts.SourceFile, indentLe
// First child must be `Identifier`
// examples of what gets skipped: `fs.readFile('lol.json')` or `ipc.on('something', () => {})`
if (ts.isCallExpression(node)) {
const child = node.getChildAt(0, sourceFile);
if (ts.isIdentifier(child)) {
const calledFunction: string = child.getText(sourceFile);
const expression = node.expression;
if (ts.isIdentifier(expression)) {
const calledFunction: string = expression.getText(sourceFile);
updateCalledFunctions(calledFunction);
}

// method call: ClassName.foo()
if (ts.isPropertyAccessExpression(expression)) {
const methodName = expression.name.getText(sourceFile);

if (expression.expression.kind === ts.SyntaxKind.ThisKeyword && currentClass) {
updateCalledFunctions(`${currentClass}.${methodName}`);
} else if (ts.isIdentifier(expression.expression)) {
const classOrObject = expression.expression.getText(sourceFile);
updateCalledFunctions(`${classOrObject}.${methodName}`);
}
}
}

// e.g. `new ClassName()`
if (ts.isNewExpression(node) && ts.isIdentifier(node.expression)) {
updateCalledFunctions(node.expression.getText(sourceFile));
}

// e.g. `class ClassName`
if (ts.isClassDeclaration(node) && node.name) {
currentClass = node.name.getText(sourceFile);
}

// logNode(node, sourceFile, indentLevel);

node.forEachChild(child => extractFunctionCalls(child, sourceFile, indentLevel + 1));

// Exit the current class
if (ts.isClassDeclaration(node)) {
currentClass = undefined;
}
}

/**
Expand Down Expand Up @@ -161,7 +208,7 @@ export function processFiles(filenames: string[]) {
}
});

console.log(calledFunctions);
// console.log(calledFunctions);

const functions = {
all: allFunctions,
Expand Down