When you need to read a code file, the better is to directly use a compiler when available.
It turns out acorn is a well known parser and you're probably already using it without knowing because you're probably using babel.
With acorn you can parse a source file into an abstract source tree which in turn can be walked with acorn-walk to find what you need.
example:
testfiletoparse.js
    export function factorialR(n) {
        if (n <= 1) {
            return 1;
        }
        return factorialR(n - 1) * n;
    }
    export function bound(v, min, max) {
        return Math.max(Math.min(v, min), max);
    }
    export function isNullOrEmpty(str) {
        return !str || str.length === 0;
    }
    export const arrowFunction = v => v;
basicparser.js
    import fs from 'fs';
    const acorn = require('acorn');
    const walk = require('acorn-walk');
    require('acorn-object-rest-spread/inject')(acorn);
    require('acorn-static-class-property-initializer/inject')(acorn);
    require('acorn-class-fields/inject')(acorn);
    const filePath = 'src/testfiletoparse.js';
    const sourceCode = String(fs.readFileSync(filePath));
    const program = acorn.parse(
        sourceCode,
        {
            ranges: true,
            locations: true,
            sourceType: 'module',
            plugins: {
                objectRestSpread: true,
                // es7: true,
                staticClassPropertyInitializer: true,
                classFields: true,
            }
        }
    );
    walk.full(
        program,
        /**
         * @param {}
         */
        (node) => {
            if (node.type === 'FunctionDeclaration') {
                console.log(`There's a FunctionDeclaration node at ${JSON.stringify(node.loc.start)}`);
                console.log(`Function name is ${node.id.name}`);
                const params = node.params.map((param) => {
                    return param.name;
                }).join();
                console.log(`Function params are ${params}`);
            }
            // it is a little tricky to catch arrow functions but trial and error will get you through it
            if (node.type === 'VariableDeclarator' && node.init.type === 'ArrowFunctionExpression') {
                console.log(`There's an arrow function expression declaration node at ${JSON.stringify(node.loc.start)}`);
                console.log(`Its name is ${node.id.name}`);
                const params = node.init.params.map((param) => {
                    return param.name;
                }).join();
                console.log(`Function params are ${params}`);
            }
        }
    );
output
    There's a FunctionDeclaration node at {"line":1,"column":7}
    Function name is factorialR
    Function params are n
    There's a FunctionDeclaration node at {"line":8,"column":7}
    Function name is bound
    Function params are v,min,max
    There's a FunctionDeclaration node at {"line":12,"column":7}
    Function name is isNullOrEmpty
    Function params are str
    There's an arrow function expression declaration node at {"line":16,"column":13}
    Its name is arrowFunction
    Function params are v
Starting with this it should be quite straightforward to find a solution to your problem.