From 55a4f1fc869e41aca748c63d3018f0448b1606e0 Mon Sep 17 00:00:00 2001 From: pack Date: Sun, 9 Aug 2026 10:37:07 +0000 Subject: first commit --- node_modules/router/lib/layer.js | 247 +++++++++++++++++++++++++++++++++++++++ node_modules/router/lib/route.js | 242 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 489 insertions(+) create mode 100644 node_modules/router/lib/layer.js create mode 100644 node_modules/router/lib/route.js (limited to 'node_modules/router/lib') diff --git a/node_modules/router/lib/layer.js b/node_modules/router/lib/layer.js new file mode 100644 index 0000000..6a4408f --- /dev/null +++ b/node_modules/router/lib/layer.js @@ -0,0 +1,247 @@ +/*! + * router + * Copyright(c) 2013 Roman Shtylman + * Copyright(c) 2014-2022 Douglas Christopher Wilson + * MIT Licensed + */ + +'use strict' + +/** + * Module dependencies. + * @private + */ + +const isPromise = require('is-promise') +const pathRegexp = require('path-to-regexp') +const debug = require('debug')('router:layer') +const deprecate = require('depd')('router') + +/** + * Module variables. + * @private + */ + +const TRAILING_SLASH_REGEXP = /\/+$/ +const MATCHING_GROUP_REGEXP = /\((?:\?<(.*?)>)?(?!\?)/g + +/** + * Expose `Layer`. + */ + +module.exports = Layer + +function Layer (path, options, fn) { + if (!(this instanceof Layer)) { + return new Layer(path, options, fn) + } + + debug('new %o', path) + const opts = options || {} + + this.handle = fn + this.keys = [] + this.name = fn.name || '' + this.params = undefined + this.path = undefined + this.slash = path === '/' && opts.end === false + + function matcher (_path) { + if (_path instanceof RegExp) { + const keys = [] + let name = 0 + let m + // eslint-disable-next-line no-cond-assign + while (m = MATCHING_GROUP_REGEXP.exec(_path.source)) { + keys.push({ + name: m[1] || name++, + offset: m.index + }) + } + + return function regexpMatcher (p) { + const match = _path.exec(p) + if (!match) { + return false + } + + const params = {} + for (let i = 1; i < match.length; i++) { + const key = keys[i - 1] + const prop = key.name + const val = decodeParam(match[i]) + + if (val !== undefined) { + params[prop] = val + } + } + + return { + params, + path: match[0] + } + } + } + + return pathRegexp.match((opts.strict ? _path : loosen(_path)), { + sensitive: opts.sensitive, + end: opts.end, + trailing: !opts.strict, + decode: decodeParam + }) + } + this.matchers = Array.isArray(path) ? path.map(matcher) : [matcher(path)] +} + +/** + * Handle the error for the layer. + * + * @param {Error} error + * @param {Request} req + * @param {Response} res + * @param {function} next + * @api private + */ + +Layer.prototype.handleError = function handleError (error, req, res, next) { + const fn = this.handle + + if (fn.length !== 4) { + // not a standard error handler + return next(error) + } + + try { + // invoke function + const ret = fn(error, req, res, next) + + // wait for returned promise + if (isPromise(ret)) { + if (!(ret instanceof Promise)) { + deprecate('handlers that are Promise-like are deprecated, use a native Promise instead') + } + + ret.then(null, function (error) { + next(error || new Error('Rejected promise')) + }) + } + } catch (err) { + next(err) + } +} + +/** + * Handle the request for the layer. + * + * @param {Request} req + * @param {Response} res + * @param {function} next + * @api private + */ + +Layer.prototype.handleRequest = function handleRequest (req, res, next) { + const fn = this.handle + + if (fn.length > 3) { + // not a standard request handler + return next() + } + + try { + // invoke function + const ret = fn(req, res, next) + + // wait for returned promise + if (isPromise(ret)) { + if (!(ret instanceof Promise)) { + deprecate('handlers that are Promise-like are deprecated, use a native Promise instead') + } + + ret.then(null, function (error) { + next(error || new Error('Rejected promise')) + }) + } + } catch (err) { + next(err) + } +} + +/** + * Check if this route matches `path`, if so + * populate `.params`. + * + * @param {String} path + * @return {Boolean} + * @api private + */ + +Layer.prototype.match = function match (path) { + let match + + if (path != null) { + // fast path non-ending match for / (any path matches) + if (this.slash) { + this.params = {} + this.path = '' + return true + } + + let i = 0 + while (!match && i < this.matchers.length) { + // match the path + match = this.matchers[i](path) + i++ + } + } + + if (!match) { + this.params = undefined + this.path = undefined + return false + } + + // store values + this.params = match.params + this.path = match.path + this.keys = Object.keys(match.params) + + return true +} + +/** + * Decode param value. + * + * @param {string} val + * @return {string} + * @private + */ + +function decodeParam (val) { + if (typeof val !== 'string' || val.length === 0) { + return val + } + + try { + return decodeURIComponent(val) + } catch (err) { + if (err instanceof URIError) { + err.message = 'Failed to decode param \'' + val + '\'' + err.status = 400 + } + + throw err + } +} + +/** + * Loosens the given path for path-to-regexp matching. + */ +function loosen (path) { + if (path instanceof RegExp || path === '/') { + return path + } + + return Array.isArray(path) + ? path.map(function (p) { return loosen(p) }) + : String(path).replace(TRAILING_SLASH_REGEXP, '') +} diff --git a/node_modules/router/lib/route.js b/node_modules/router/lib/route.js new file mode 100644 index 0000000..1887d78 --- /dev/null +++ b/node_modules/router/lib/route.js @@ -0,0 +1,242 @@ +/*! + * router + * Copyright(c) 2013 Roman Shtylman + * Copyright(c) 2014-2022 Douglas Christopher Wilson + * MIT Licensed + */ + +'use strict' + +/** + * Module dependencies. + * @private + */ + +const debug = require('debug')('router:route') +const Layer = require('./layer') +const { METHODS } = require('node:http') + +/** + * Module variables. + * @private + */ + +const slice = Array.prototype.slice +const flatten = Array.prototype.flat +const methods = METHODS.map((method) => method.toLowerCase()) + +/** + * Expose `Route`. + */ + +module.exports = Route + +/** + * Initialize `Route` with the given `path`, + * + * @param {String} path + * @api private + */ + +function Route (path) { + debug('new %o', path) + this.path = path + this.stack = [] + + // route handlers for various http methods + this.methods = Object.create(null) +} + +/** + * @private + */ + +Route.prototype._handlesMethod = function _handlesMethod (method) { + if (this.methods._all) { + return true + } + + // normalize name + let name = typeof method === 'string' + ? method.toLowerCase() + : method + + if (name === 'head' && !this.methods.head) { + name = 'get' + } + + return Boolean(this.methods[name]) +} + +/** + * @return {array} supported HTTP methods + * @private + */ + +Route.prototype._methods = function _methods () { + const methods = Object.keys(this.methods) + + // append automatic head + if (this.methods.get && !this.methods.head) { + methods.push('head') + } + + for (let i = 0; i < methods.length; i++) { + // make upper case + methods[i] = methods[i].toUpperCase() + } + + return methods +} + +/** + * dispatch req, res into this route + * + * @private + */ + +Route.prototype.dispatch = function dispatch (req, res, done) { + let idx = 0 + const stack = this.stack + let sync = 0 + + if (stack.length === 0) { + return done() + } + + let method = typeof req.method === 'string' + ? req.method.toLowerCase() + : req.method + + if (method === 'head' && !this.methods.head) { + method = 'get' + } + + req.route = this + + next() + + function next (err) { + // signal to exit route + if (err && err === 'route') { + return done() + } + + // signal to exit router + if (err && err === 'router') { + return done(err) + } + + // no more matching layers + if (idx >= stack.length) { + return done(err) + } + + // max sync stack + if (++sync > 100) { + return setImmediate(next, err) + } + + let layer + let match + + // find next matching layer + while (match !== true && idx < stack.length) { + layer = stack[idx++] + match = !layer.method || layer.method === method + } + + // no match + if (match !== true) { + return done(err) + } + + if (err) { + layer.handleError(err, req, res, next) + } else { + layer.handleRequest(req, res, next) + } + + sync = 0 + } +} + +/** + * Add a handler for all HTTP verbs to this route. + * + * Behaves just like middleware and can respond or call `next` + * to continue processing. + * + * You can use multiple `.all` call to add multiple handlers. + * + * function check_something(req, res, next){ + * next() + * } + * + * function validate_user(req, res, next){ + * next() + * } + * + * route + * .all(validate_user) + * .all(check_something) + * .get(function(req, res, next){ + * res.send('hello world') + * }) + * + * @param {array|function} handler + * @return {Route} for chaining + * @api public + */ + +Route.prototype.all = function all (handler) { + const callbacks = flatten.call(slice.call(arguments), Infinity) + + if (callbacks.length === 0) { + throw new TypeError('argument handler is required') + } + + for (let i = 0; i < callbacks.length; i++) { + const fn = callbacks[i] + + if (typeof fn !== 'function') { + throw new TypeError('argument handler must be a function') + } + + const layer = Layer('/', {}, fn) + layer.method = undefined + + this.methods._all = true + this.stack.push(layer) + } + + return this +} + +methods.forEach(function (method) { + Route.prototype[method] = function (handler) { + const callbacks = flatten.call(slice.call(arguments), Infinity) + + if (callbacks.length === 0) { + throw new TypeError('argument handler is required') + } + + for (let i = 0; i < callbacks.length; i++) { + const fn = callbacks[i] + + if (typeof fn !== 'function') { + throw new TypeError('argument handler must be a function') + } + + debug('%s %s', method, this.path) + + const layer = Layer('/', {}, fn) + layer.method = method + + this.methods[method] = true + this.stack.push(layer) + } + + return this + } +}) -- cgit v1.2.3