All files index.js

93.33% Statements 56/60
75.76% Branches 25/33
100% Functions 13/13
93.33% Lines 56/60
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176          8x 8x 8x               8x 8x                       7x   7x 1x     6x     7x 8x 8x                   6x 6x   6x 4x 4x   2x 2x 2x     6x 1x     5x                   3x 3x 3x 1x     2x                 7x 7x     7x   4x   4x 3x     4x   4x 4x 4x         3x 3x               4x     4x 6x                     4x     4x     4x     8x       8x     8x     8x 2x       8x 2x     6x     6x                 1x
class TcbRouter {
 
    constructor({ event = {} } = {}) {
 
        // 中间件
        this._routerMiddlewares = {};
        this._req = { event, url: event.$url };
        this._res = {};
    }
 
    /**
     * add path to _routerMiddlewares
     * @param {String} path
     */
    _addRoute(path) {
        Eif (!this._routerMiddlewares.hasOwnProperty(path)) {
            this._routerMiddlewares[path] = {
                middlewares: []
            };
        }
    }
 
    /**
     * add middleware to _routerMiddlewares
     * @param {String|Array} path
     * @param {Function} middleware
     */
    _addMiddleware(path, middleware) {
        let paths = [];
 
        if (Array.isArray(path)) {
            paths = path;
        }
        else {
            paths = [path];
        }
 
        paths.forEach((p) => {
            this._addRoute(p);
            this._routerMiddlewares[p].middlewares.push(middleware);
        });
    }
 
    /**
     * use middleware for all routes
     * @param {String} path
     * @param {Function} middleware
     */
    use() {
        let path = null;
        let handler = null;
 
        if (arguments.length === 1) {
            path = '*';
            handler = arguments[0];
        }
        else Eif (arguments.length > 1) {
            path = arguments[0];
            handler = arguments[1];
        }
 
        if (typeof handler !== 'function') {
            return console.warn('Handler should be a function. The middleware is not installed correctly.');
        }
 
        this._addMiddleware(path, handler);
    }
 
    /**
     * set routes
     * @param {String|Array} path 
     * @param {Function} middleware
     */
    router(path = '*') {
 
        for (let i = 1, len = arguments.length; i < len; i++) {
            let handler = arguments[i];
            if (typeof handler !== 'function') {
                return console.warn('Handler should be a function. The middleware is not installed correctly.');
            }
 
            this._addMiddleware(path, handler);
        }
    }
 
    /**
     * start the route server
     */
    serve() {
 
        let _routerMiddlewares = this._routerMiddlewares;
        let url = this._req.url;
 
        // try to  match path
        if (_routerMiddlewares.hasOwnProperty(url)
            || _routerMiddlewares.hasOwnProperty('*')) {
            let middlewares = (_routerMiddlewares[url]) ? _routerMiddlewares[url].middlewares : [];
            // put * path middlewares on the queue head
            if (_routerMiddlewares['*']) {
                middlewares = [].concat(_routerMiddlewares['*'].middlewares, middlewares);
            }
 
            const fn = compose(middlewares);
 
            return new Promise((resolve, reject) => {
                fn(this).then((res) => {
                    resolve(this.body);
                }).catch(reject);
            });
        }
        else {
            return new Promise((resolve) => {
                resolve();
            });
        }
 
    }
}
 
function compose(middleware) {
    Iif (!Array.isArray(middleware)) {
        throw new TypeError('Middleware must be an array!');
    }
    for (const fn of middleware) {
        Iif (typeof fn !== 'function') {
            throw new TypeError('Handler should be a function. The middleware is not installed correctly.');
        }
    }
 
    /**
     * @param {Object} context
     * @return {Promise}
     * @api public
     */
 
    return function (context, next) {
        // parameter 'next' is empty when this the main flow
        // last called middleware #
        let index = -1;
 
        // dispatch the first middleware
        return dispatch(0);
 
        function dispatch(i) {
            Iif (i <= index) {
                return Promise.reject(new Error('next() called multiple times'));
            }
 
            index = i;
 
            // get the handler and path of the middlware
            let handler = middleware[i];
 
            // reach the end, call the last handler 
            if (i === middleware.length) {
                handler = next;
            }
 
            // if handler is missing, just return Promise.resolve
            if (!handler) {
                return Promise.resolve();
            }
 
            try {
                // handle request, call handler one by one using dispatch
                // Promise.resolve will help trigger the handler to be invoked
                return Promise.resolve(handler(context, dispatch.bind(null, i + 1)));
            }
            catch (err) {
                return Promise.reject(err);
            }
        }
    }
}
 
module.exports = TcbRouter;