HEX
Server: Apache/2.4.52 (Ubuntu)
System: Linux spn-python 5.15.0-89-generic #99-Ubuntu SMP Mon Oct 30 20:42:41 UTC 2023 x86_64
User: arjun (1000)
PHP: 8.1.2-1ubuntu2.20
Disabled: NONE
Upload Files
File: //home/arjun/projects/good-life-be/node_modules/express-mung/index.js
'use strict';

let mung = {};
let faux_fin = { end: () => null };

function isScalar(v) {
    return typeof v !== 'object' && !Array.isArray(v);
}

mung.onError = (err, req, res) => {
    res
        .status(500)
        .set('content-language', 'en')
        .json({ message: err.message })
        .end();
    return res;
};

mung.json = function json (fn, options) {
    return function (req, res, next) {
        let original = res.json;
        options = options || {};
        let mungError = options.mungError;

        function json_hook (json) {
            let originalJson = json;
            res.json = original;
            if (res.headersSent)
                return res;
            if (!mungError && res.statusCode >= 400)
                return original.call(this, json);

            // Run the munger
            try {
                json = fn(json, req, res);
            } catch (e) {
                return mung.onError(e, req, res);
            }
            if (res.headersSent)
                return res;

            // If no returned value from fn, then assume json has been mucked with.
            if (json === undefined)
                json = originalJson;

            // If null, then 204 No Content
            if (json === null)
                return res.status(204).end();

            // If munged scalar value, then text/plain
            if (originalJson !== json && isScalar(json)) {
                res.set('content-type', 'text/plain');
                return res.send(String(json));
            }

            return original.call(this, json);
        }
        res.json = json_hook;

        next && next();
    }
}

mung.jsonAsync = function json (fn, options) {
    return function (req, res, next) {
        let original = res.json;
        options = options || {};
        let mungError = options.mungError;

        function json_async_hook (json) {
            let originalJson = json;
            res.json = original;
            if (res.headersSent)
                return;
            if (!mungError && res.statusCode >= 400)
                return original.call(this, json);
            try {
                fn(json, req, res)
                .then(json => {
                    if (res.headersSent)
                        return;

                    // If null, then 204 No Content
                    if (json === null)
                        return res.status(204).end();

                    // If munged scalar value, then text/plain
                    if (json !== originalJson && isScalar(json)) {
                        res.set('content-type', 'text/plain');
                        return res.send(String(json));
                    }

                    return original.call(this, json);
                })
                .catch(e => mung.onError(e, req, res));
            } catch (e) {
                mung.onError(e, req, res);
            }

            return faux_fin;
        }
        res.json = json_async_hook;

        next && next();
    }
}

mung.headers = function headers (fn) {
    return function (req, res, next) {
        let original = res.end;
        function headers_hook () {
            res.end = original;
            if (!res.headersSent) {
                try {
                    fn(req, res);
                } catch (e) {
                    return mung.onError(e, req, res);
                }
                if (res.headersSent) {
                    console.error('sending response while in mung.headers is undefined behaviour');
                    return;
                }
            }
            return original.apply(this, arguments);
        }
        res.end = headers_hook;

        next && next();
    }
}

mung.headersAsync = function headersAsync (fn) {
    return function (req, res, next) {
        let original = res.end;
        let onError = e => {
            res.end = original;
            return mung.onError(e, req, res);
        };
        function headers_async_hook () {
            if (res.headersSent)
                return original.apply(this, args);
            let args = arguments;
            res.end = () => null;
            try {
                fn(req, res)
                .then(() => {
                    res.end = original;
                    if (res.headersSent)
                        return;
                    original.apply(this, args);
                })
                .catch(e => onError(e, req, res));
            } catch (e) {
                onError(e, req, res);
            }
        }
        res.end = headers_async_hook;

        next && next();
    }
}

mung.write = function write (fn, options = {}) {
    return function (req, res, next) {
        const original = res.write;
        const mungError = options.mungError;

        function write_hook (chunk, encoding, callback) {
            // If res.end has already been called, do nothing.
            if (res.finished) {
                return false;
            }

            // Do not mung on errors
            if (!mungError && res.statusCode >= 400) {
                return original.apply(res, arguments);
            }

            try {

                let modifiedChunk = fn(
                    chunk,
                    // Since `encoding` is an optional argument to `res.write`,
                    // make sure it is a string and not actually the callback.
                    typeof encoding === 'string' ? encoding : null,
                    req,
                    res
                );

                // res.finished is set to `true` once res.end has been called.
                // If it is called in the mung function, stop execution here.
                if (res.finished) {
                    return false;
                }

                // If no returned value from fn, then set it back to the original value
                if (modifiedChunk === undefined) {
                    modifiedChunk = chunk;
                }

                return original.call(res, modifiedChunk, encoding, callback)

            } catch (err) {
                return mung.onError(err, req, res);
            }
        }

        res.write = write_hook;

        next && next();
    }
}

module.exports = mung;