All files / server/src/router index.js

77.59% Statements 45/58
66.67% Branches 24/36
58.82% Functions 10/17
80.43% Lines 37/46
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  9x 9x     9x 60x 60x       9x     54x   54x   54x     62x     52x     48x 48x     40x   40x 40x     40x 9x           9x 40x 10x 9x 9x   9x   9x   6x 6x 6x     6x     6x 6x 6x 6x     6x     9x     9x   63x                              
// Perform the routing required
const join = require('../join');
const params = require('path-to-regexp-wrap')();
 
// Parse the request parameters
const parse = middle => {
  const path = typeof middle[0] === 'string' ? middle.shift() : '*';
  return { path, middle };
};
 
// Generic request handler
const generic = (method, ...all) => {
 
  // Extracted or otherwise it'd shift once per call; also more performant
  const { path, middle } = parse(all);
 
  const match = params(path);
 
  return async ctx => {
 
    // A route should be solved only once per request
    if (ctx.req.solved) return;
 
    // Only for the correct method
    if (method !== ctx.req.method) return;
 
    // Only do this if the correct path
    ctx.req.params = match(ctx.req.path);
    if (!ctx.req.params) return;
 
    // Perform this promise chain
    await join(middle)(ctx);
 
    ctx.req.solved = true;
    Iif (ctx.ret && ctx.ret.res && ctx.ret.req && ctx.ret.options) {
      console.log('You should NOT return the ctx in middleware!');
    }
    if (ctx.ret && !ctx.res.headersSent) {
      ctx.res.send(ctx.ret || '');
    }
  };
};
 
// Create a middleware that splits paths
exports.all  = (...middle) => generic(   'ALL', ...middle);
exports.get  = (...middle) => generic(   'GET', ...middle);
exports.post = (...middle) => generic(  'POST', ...middle);
exports.put  = (...middle) => generic(   'PUT', ...middle);
exports.del  = (...middle) => generic('DELETE', ...middle);
 
exports.join = join;
 
exports.error = (...all) => {
  // Extracted or otherwise it'd shift once per call; also more performant
  const { path, middle } = parse(all);
  const generic = () => {};
  generic.error = async ctx => {
 
    // TODO: find a way to fix this
    const frag = ctx.error.path ? ctx.error.path.slice(0, path.length) : '';
 
    // All of them if there's no path
    Eif (path === '*' || frag === path) {
      const ret = await middle[0](ctx);
      delete ctx.error;
      ctx.ret = ret || ctx.ret;
    }
  };
  return generic;
};
 
exports.join = join;
 
// Allow for calling to routers that do not exist yet
module.exports = new Proxy(exports, {
  get: (orig, key) => {
    Eif (orig[key]) return orig[key];
    return (...middle) => {
      const path = typeof middle[0] === 'string' ? middle.shift() : '*';
      middle = join(middle);
      let called;
      return ctx => {
        if (!called) {
          called = true;
          const routers = ctx.plugins.filter(p => p.name === key && p.router).map(p => p.router);
          routers.forEach(router => router(ctx, path, middle));
        }
      }
    }
  }
});