How do I get descriptor for JavaScript class constructor function?

Is it possible for me to get the descriptor for the actual constructor method of a JS class? I am writing my own little wrapper around Express to try and procedurally generate routes and stuff (and I am sure there are plenty of other libraries to do this, but it’s a learning experience).

If I iterate through the function descriptors for a class prototype, I can convert the ‘value’ property to a string that represents a single method. If I call getString() on the descriptor for ‘constructor’ I get the entire class. I ONLY want the body of the constructor. I could add more parsing logic, but there has to be a way to do this.

    /**
     * Register all controllers and their routes
     * @param {import('./application')} application
     */
    static async registerControllersAsync(application) {
        const 
            config = application.config, 
            app = application.express;

        let controllerDir = path.resolve(config.rootDirectory, config.getValue('server.controllerDirectory', 'controllers')),
            controllerFiles = (await readdir(controllerDir))
                .filter(f => f.indexOf('Controller') > -1)
                .map(f => path.join(controllerDir, f)),
            parseMethodName = /(?<verb>(get|post|head|delete|put|connect|trace|patch))(?<path>.*)/;

        for(const controllerFile of controllerFiles) {
            const 
                controllerType = require(controllerFile),
                router = express.Router(),
                pathPrefix = controllerType.pathPrefix || false,
                controllerName = controllerType.name.slice(0, controllerType.name.indexOf('Controller')).toLowerCase();
            let
                viewSearchPath = [ path.resolve(`${config.getValue('server.paths.viewPathRoot', 'views')}`, controllerName) ]
                    .concat(config.getValue('server.paths.sharedViews', [])
                        .map(p => path.resolve(config.rootDirectory, p)));
            const
                controllerSettings = {
                    application,
                    config,
                    constructorParameters: [],
                    controllerName,
                    controllerType,
                    viewLookupCache: BaseController.getControllerViewCache(controllerName),
                    viewSearchPath
                };


            if (typeof controllerType.registerRoutes === 'function')
                controllerType.registerRoutes(app, router);
            else {
                /**
                 * Autowire "by convention" steps: 
                 * (1) find methods beginning with valid HTTP verbs (e.g. get, post),
                 * (2) use remainder of method name as path,
                 * (3) extract any parameter names from handler and append to path as placeholders,
                 * (4) create the actual callback handle wrapper for incoming requests in the controller router,
                 */
                let descriptors = Object.getOwnPropertyDescriptors(controllerType.prototype);
                /** @type {{ parameters: string[], verb: string, name: string, urlPath: string, ranking: number, defaultView: string }[]} */
                let sortedRoutes = Object.keys(descriptors).map(name => {
                    /**
                     * Extract parameter names from a function
                     * @param {string} methodDef The raw method text to parse
                     * @returns 
                     */
                    function getParameterNames(methodDef) {
                        const parameterListStart = methodDef.indexOf('(') + 1,
                            parameterListEnd = methodDef.indexOf(')'),
                            parameterList = methodDef.slice(parameterListStart, parameterListEnd),
                            parameters = parameterList.split(',')
                                .filter(p => p.length > 0)
                                .map(p => {
                                    let n = p.indexOf('=');
                                    if (n > -1) {
                                        p = p.slice(0, n);
                                        return p.trim();
                                    }
                                    return p.trim();
                                });
                            return parameters;
                    }
                    let desc = descriptors[name];
                    if (typeof desc.value === 'function') {
                        let m = parseMethodName.exec(name),
                            //  Routes with fewer parameters rank higher than those with more
                            ranking = 0;

                        if (m) {
                            /** @type {[string, string]} */
                            let { verb, path } = m.groups,
                                defaultView = path || 'index',
                                urlPath = controllerType.prototype[name].urlPath,
                                /** @type {string[]} */
                                parameters = getParameterNames(desc.value.toString());

                            if (typeof urlPath !== 'string') {
                                ranking += parameters.length;

                                if (parameters.length > 0) {
                                    const pathSpecifier = parameters
                                        .map(p => `:${p}`)
                                        .join('/');

                                    urlPath = `/${path}/${pathSpecifier}`;
                                }
                                else {
                                    urlPath = '/' + path;
                                }
                            }

                            return { parameters, verb, name, urlPath, ranking, defaultView };
                        }
                        else if (name === 'constructor') {
                            //  Default controller constructor only takes settings;
                            //  Other parameters are assumed to be DI container references
                            const parameters = getParameterNames(desc.value.toString()).slice(1);
                            controllerSettings.constructorParameters.push(...parameters);
                        }
                    }
                    return false;
                })
                .filter(r => r !== false)
                .sort((a, b) => {
                    if (a.ranking < b.ranking)
                        return -1;
                    else if (a.ranking > b.ranking)
                        return 1;
                    else
                        return a.name.localeCompare(b);
                });

                sortedRoutes.forEach(route => {
                    controllerType.prototype[route.name].defaultView = route.defaultView; 
                    router[route.verb].call(router, route.urlPath, 
                        /**
                         * @param {express.Request} request The incomming request message
                         * @param {express.Response} response The response to send back to the client.
                         */
                        async (request, response) => {
                            try {
                                const 
                                    /** Create new controller for request, pass settings, and DI requirements @type {BaseController} */
                                    controller = BaseController.createController(application, controllerName, request, response),
                                    /** Fill the parameters with their respective values @type {string[]} */
                                    parameterList = route.parameters.map(p => {
                                        if (p in request.params)
                                            return request.params[p];
                                        else if (p in request.body)
                                            return request.body[p];
                                    });

                                await controller[route.name].apply(controller, parameterList); 
                            }
                            catch(err) {
                                application.handleError(request, response, err);
                            }
                        });
                });
            }

            BaseController.addControllerType(controllerSettings);

            if (pathPrefix)
                app.use(pathPrefix, router);
            else
                app.use(router);
            }


        app.get('/', (req, res) => {
            res.sendStatus(404);
        });
    }

And here is my simple controller:

const
    BaseController = require('../src/baseController');

/**
 * Handle requests for the home page
 */
class HomeController extends BaseController {
    /**
     * @param {import('../src/baseController').ControllerSettings} settings Controller settings
     * @param {import('../src/vault/vaultClient')} vault Injected vault client
     */
    constructor(settings, vault) {
        super(settings);
        this.vault = vault;
    }

    /**
     * Serve the landing page
     * @returns 
     */
    async get() {
        await this.renderAsync('index', { pageTitle: 'Pechanga Demo' });
    }
}

module.exports = HomeController;

Here is what currently comes back for ‘get’:

Object.getOwnPropertyDescriptor(controllerType.prototype, 'get').value.toString()
"async get() {
        await this.renderAsync('index', { pageTitle: 'Pechanga Demo' });
    }"

And, of course, this is what comes back for ‘constructor’:

"async get() {
        await this.renderAsync('index', { pageTitle: 'Pechanga Demo' });
    }"
Object.getOwnPropertyDescriptor(controllerType.prototype, 'constructor').value.toString()
"class HomeController extends BaseController {
    /**
     * @param {import('../src/baseController').ControllerSettings} settings Controller settings
     * @param {import('../src/vault/vaultClient')} vault Injected vault client
     */
    constructor(settings, vault) {
        super(settings);
        this.vault = vault;
    }

    /**
     * Serve the landing page
     * @returns 
     */
    async get() {
        await this.renderAsync('index', { pageTitle: 'Pechanga Demo' });
    }
}"

But what I really want is just:

    constructor(settings, vault) {
        super(settings);
        this.vault = vault;
    }

Is this possible without parsing the entire class body?

Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa Dịch vụ tổ chức sự kiện 5 sao Thông tin về chúng tôi Dịch vụ sinh nhật bé trai Dịch vụ sinh nhật bé gái Sự kiện trọn gói Các tiết mục giải trí Dịch vụ bổ trợ Tiệc cưới sang trọng Dịch vụ khai trương Tư vấn tổ chức sự kiện Hình ảnh sự kiện Cập nhật tin tức Liên hệ ngay Thuê chú hề chuyên nghiệp Tiệc tất niên cho công ty Trang trí tiệc cuối năm Tiệc tất niên độc đáo Sinh nhật bé Hải Đăng Sinh nhật đáng yêu bé Khánh Vân Sinh nhật sang trọng Bích Ngân Tiệc sinh nhật bé Thanh Trang Dịch vụ ông già Noel Xiếc thú vui nhộn Biểu diễn xiếc quay đĩa Dịch vụ tổ chức tiệc uy tín Khám phá dịch vụ của chúng tôi Tiệc sinh nhật cho bé trai Trang trí tiệc cho bé gái Gói sự kiện chuyên nghiệp Chương trình giải trí hấp dẫn Dịch vụ hỗ trợ sự kiện Trang trí tiệc cưới đẹp Khởi đầu thành công với khai trương Chuyên gia tư vấn sự kiện Xem ảnh các sự kiện đẹp Tin mới về sự kiện Kết nối với đội ngũ chuyên gia Chú hề vui nhộn cho tiệc sinh nhật Ý tưởng tiệc cuối năm Tất niên độc đáo Trang trí tiệc hiện đại Tổ chức sinh nhật cho Hải Đăng Sinh nhật độc quyền Khánh Vân Phong cách tiệc Bích Ngân Trang trí tiệc bé Thanh Trang Thuê dịch vụ ông già Noel chuyên nghiệp Xem xiếc khỉ đặc sắc Xiếc quay đĩa thú vị
Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa
Thiết kế website Thiết kế website Thiết kế website Cách kháng tài khoản quảng cáo Mua bán Fanpage Facebook Dịch vụ SEO Tổ chức sinh nhật