diff options
Diffstat (limited to 'alarm/node_modules/polka/index.js')
-rw-r--r-- | alarm/node_modules/polka/index.js | 102 |
1 files changed, 102 insertions, 0 deletions
diff --git a/alarm/node_modules/polka/index.js b/alarm/node_modules/polka/index.js new file mode 100644 index 0000000..f32a29c --- /dev/null +++ b/alarm/node_modules/polka/index.js @@ -0,0 +1,102 @@ +const http = require('http'); +const Router = require('trouter'); +const { parse } = require('querystring'); +const parser = require('@polka/url'); + +function lead(x) { + return x.charCodeAt(0) === 47 ? x : ('/' + x); +} + +function value(x) { + let y = x.indexOf('/', 1); + return y > 1 ? x.substring(0, y) : x; +} + +function mutate(str, req) { + req.url = req.url.substring(str.length) || '/'; + req.path = req.path.substring(str.length) || '/'; +} + +function onError(err, req, res, next) { + let code = (res.statusCode = err.code || err.status || 500); + res.end(err.length && err || err.message || http.STATUS_CODES[code]); +} + +class Polka extends Router { + constructor(opts={}) { + super(opts); + this.apps = {}; + this.wares = []; + this.bwares = {}; + this.parse = parser; + this.server = opts.server; + this.handler = this.handler.bind(this); + this.onError = opts.onError || onError; // catch-all handler + this.onNoMatch = opts.onNoMatch || this.onError.bind(null, { code:404 }); + } + + add(method, pattern, ...fns) { + let base = lead(value(pattern)); + if (this.apps[base] !== void 0) throw new Error(`Cannot mount ".${method.toLowerCase()}('${lead(pattern)}')" because a Polka application at ".use('${base}')" already exists! You should move this handler into your Polka application instead.`); + return super.add(method, pattern, ...fns); + } + + use(base, ...fns) { + if (typeof base === 'function') { + this.wares = this.wares.concat(base, fns); + } else if (base === '/') { + this.wares = this.wares.concat(fns); + } else { + base = lead(base); + fns.forEach(fn => { + if (fn instanceof Polka) { + this.apps[base] = fn; + } else { + let arr = this.bwares[base] || []; + arr.length > 0 || arr.push((r, _, nxt) => (mutate(base, r),nxt())); + this.bwares[base] = arr.concat(fn); + } + }); + } + return this; // chainable + } + + listen() { + (this.server = this.server || http.createServer()).on('request', this.handler); + this.server.listen.apply(this.server, arguments); + return this; + } + + handler(req, res, info) { + info = info || this.parse(req); + let fns=[], arr=this.wares, obj=this.find(req.method, info.pathname); + req.originalUrl = req.originalUrl || req.url; + let base = value(req.path = info.pathname); + if (this.bwares[base] !== void 0) { + arr = arr.concat(this.bwares[base]); + } + if (obj) { + fns = obj.handlers; + req.params = obj.params; + } else if (this.apps[base] !== void 0) { + mutate(base, req); info.pathname=req.path; //=> updates + fns.push(this.apps[base].handler.bind(null, req, res, info)); + } else if (fns.length === 0) { + fns.push(this.onNoMatch); + } + // Grab addl values from `info` + req.search = info.search; + req.query = parse(info.query); + // Exit if only a single function + let i=0, len=arr.length, num=fns.length; + if (len === i && num === 1) return fns[0](req, res); + // Otherwise loop thru all middlware + let next = err => err ? this.onError(err, req, res, next) : loop(); + let loop = _ => res.finished || (i < len) && arr[i++](req, res, next); + arr = arr.concat(fns); + len += num; + loop(); // init + } +} + +module.exports = opts => new Polka(opts); |