Comparing version 2.0.0-beta.2 to 2.0.0
@@ -0,1 +1,14 @@ | ||
2.0.0 / 2024-09-09 | ||
================== | ||
* Drop support for node <18 | ||
* deps: path-to-regexp@^8.0.0 | ||
- Drop support for partial capture group `router.route('/user(s?)/:user/:op')` but still have optional non-capture `/user{s}/:user/:op` | ||
- `:name?` becomes `{:name}` | ||
- `:name*` becomes `*name`. | ||
- The splat change also changes splat from strings to an array of strings | ||
- Optional splats become `{*name}` | ||
- `:name+` becomes `*name` and thus equivalent to `*name` so I dropped those tests | ||
- Strings as regular expressions are fully removed, need to be converted to native regular expressions | ||
2.0.0-beta.2 / 2024-03-20 | ||
@@ -2,0 +15,0 @@ ========================= |
146
index.js
@@ -15,10 +15,10 @@ /*! | ||
var flatten = require('array-flatten').flatten | ||
var isPromise = require('is-promise') | ||
var Layer = require('./lib/layer') | ||
var methods = require('methods') | ||
var mixin = require('utils-merge') | ||
var parseUrl = require('parseurl') | ||
var Route = require('./lib/route') | ||
var setPrototypeOf = require('setprototypeof') | ||
const flatten = require('array-flatten').flatten | ||
const isPromise = require('is-promise') | ||
const Layer = require('./lib/layer') | ||
const methods = require('methods') | ||
const mixin = require('utils-merge') | ||
const parseUrl = require('parseurl') | ||
const Route = require('./lib/route') | ||
const setPrototypeOf = require('setprototypeof') | ||
@@ -30,3 +30,3 @@ /** | ||
var slice = Array.prototype.slice | ||
const slice = Array.prototype.slice | ||
@@ -58,3 +58,3 @@ /** | ||
var opts = options || {} | ||
const opts = options || {} | ||
@@ -134,3 +134,3 @@ function router (req, res, next) { | ||
var params = this.params[name] | ||
let params = this.params[name] | ||
@@ -157,18 +157,18 @@ if (!params) { | ||
var idx = 0 | ||
var methods | ||
var protohost = getProtohost(req.url) || '' | ||
var removed = '' | ||
var self = this | ||
var slashAdded = false | ||
var sync = 0 | ||
var paramcalled = {} | ||
let idx = 0 | ||
let methods | ||
const protohost = getProtohost(req.url) || '' | ||
let removed = '' | ||
const self = this | ||
let slashAdded = false | ||
let sync = 0 | ||
const paramcalled = {} | ||
// middleware and routes | ||
var stack = this.stack | ||
const stack = this.stack | ||
// manage inter-router variables | ||
var parentParams = req.params | ||
var parentUrl = req.baseUrl || '' | ||
var done = restore(callback, req, 'baseUrl', 'next', 'params') | ||
const parentParams = req.params | ||
const parentUrl = req.baseUrl || '' | ||
let done = restore(callback, req, 'baseUrl', 'next', 'params') | ||
@@ -191,3 +191,3 @@ // setup next layer | ||
function next (err) { | ||
var layerError = err === 'route' | ||
let layerError = err === 'route' | ||
? null | ||
@@ -227,3 +227,3 @@ : err | ||
// get pathname of request | ||
var path = getPathname(req) | ||
const path = getPathname(req) | ||
@@ -235,5 +235,5 @@ if (path == null) { | ||
// find next matching layer | ||
var layer | ||
var match | ||
var route | ||
let layer | ||
let match | ||
let route | ||
@@ -265,4 +265,4 @@ while (match !== true && idx < stack.length) { | ||
var method = req.method | ||
var hasMethod = route._handlesMethod(method) | ||
const method = req.method | ||
const hasMethod = route._handlesMethod(method) | ||
@@ -295,3 +295,3 @@ // build up automatic options response | ||
: layer.params | ||
var layerPath = layer.path | ||
const layerPath = layer.path | ||
@@ -321,3 +321,3 @@ // this should be done for the layer | ||
// Validate path breaks on a path separator | ||
var c = path[layerPath.length] | ||
const c = path[layerPath.length] | ||
if (c && c !== '/') { | ||
@@ -369,4 +369,4 @@ next(layerError) | ||
Router.prototype.use = function use (handler) { | ||
var offset = 0 | ||
var path = '/' | ||
let offset = 0 | ||
let path = '/' | ||
@@ -376,3 +376,3 @@ // default path to '/' | ||
if (typeof handler !== 'function') { | ||
var arg = handler | ||
let arg = handler | ||
@@ -390,3 +390,3 @@ while (Array.isArray(arg) && arg.length !== 0) { | ||
var callbacks = flatten(slice.call(arguments, offset)) | ||
const callbacks = flatten(slice.call(arguments, offset)) | ||
@@ -397,4 +397,4 @@ if (callbacks.length === 0) { | ||
for (var i = 0; i < callbacks.length; i++) { | ||
var fn = callbacks[i] | ||
for (let i = 0; i < callbacks.length; i++) { | ||
const fn = callbacks[i] | ||
@@ -406,3 +406,3 @@ if (typeof fn !== 'function') { | ||
// add the middleware | ||
var layer = new Layer(path, { | ||
const layer = new Layer(path, { | ||
sensitive: this.caseSensitive, | ||
@@ -435,5 +435,5 @@ strict: false, | ||
Router.prototype.route = function route (path) { | ||
var route = new Route(path) | ||
const route = new Route(path) | ||
var layer = new Layer(path, { | ||
const layer = new Layer(path, { | ||
sensitive: this.caseSensitive, | ||
@@ -457,3 +457,3 @@ strict: this.strict, | ||
Router.prototype[method] = function (path) { | ||
var route = this.route(path) | ||
const route = this.route(path) | ||
route[method].apply(route, slice.call(arguments, 1)) | ||
@@ -509,7 +509,7 @@ return this | ||
var searchIndex = url.indexOf('?') | ||
var pathLength = searchIndex !== -1 | ||
const searchIndex = url.indexOf('?') | ||
const pathLength = searchIndex !== -1 | ||
? searchIndex | ||
: url.length | ||
var fqdnIndex = url.substring(0, pathLength).indexOf('://') | ||
const fqdnIndex = url.substring(0, pathLength).indexOf('://') | ||
@@ -549,3 +549,3 @@ return fqdnIndex !== -1 | ||
// make copy of parent for base | ||
var obj = mixin({}, parent) | ||
const obj = mixin({}, parent) | ||
@@ -557,4 +557,4 @@ // simple non-numeric merging | ||
var i = 0 | ||
var o = 0 | ||
let i = 0 | ||
let o = 0 | ||
@@ -592,3 +592,3 @@ // determine numeric gap in params | ||
// captured parameters from the layer, keys and values | ||
var keys = layer.keys | ||
const keys = layer.keys | ||
@@ -600,9 +600,8 @@ // fast track | ||
var i = 0 | ||
var name | ||
var paramIndex = 0 | ||
var key | ||
var paramVal | ||
var paramCallbacks | ||
var paramCalled | ||
let i = 0 | ||
let paramIndex = 0 | ||
let key | ||
let paramVal | ||
let paramCallbacks | ||
let paramCalled | ||
@@ -622,6 +621,5 @@ // process params in order | ||
key = keys[i++] | ||
name = key.name | ||
paramVal = req.params[name] | ||
paramCallbacks = params[name] | ||
paramCalled = called[name] | ||
paramVal = req.params[key] | ||
paramCallbacks = params[key] | ||
paramCalled = called[key] | ||
@@ -636,3 +634,3 @@ if (paramVal === undefined || !paramCallbacks) { | ||
// restore value | ||
req.params[name] = paramCalled.value | ||
req.params[key] = paramCalled.value | ||
@@ -643,3 +641,3 @@ // next param | ||
called[name] = paramCalled = { | ||
called[key] = paramCalled = { | ||
error: null, | ||
@@ -655,6 +653,6 @@ match: paramVal, | ||
function paramCallback (err) { | ||
var fn = paramCallbacks[paramIndex++] | ||
const fn = paramCallbacks[paramIndex++] | ||
// store updated value | ||
paramCalled.value = req.params[key.name] | ||
paramCalled.value = req.params[key] | ||
@@ -671,3 +669,3 @@ if (err) { | ||
try { | ||
var ret = fn(req, res, paramCallback, paramVal, key.name) | ||
const ret = fn(req, res, paramCallback, paramVal, key) | ||
if (isPromise(ret)) { | ||
@@ -693,6 +691,6 @@ ret.then(null, function (error) { | ||
function restore (fn, obj) { | ||
var props = new Array(arguments.length - 2) | ||
var vals = new Array(arguments.length - 2) | ||
const props = new Array(arguments.length - 2) | ||
const vals = new Array(arguments.length - 2) | ||
for (var i = 0; i < props.length; i++) { | ||
for (let i = 0; i < props.length; i++) { | ||
props[i] = arguments[i + 2] | ||
@@ -704,3 +702,3 @@ vals[i] = obj[props[i]] | ||
// restore vals | ||
for (var i = 0; i < props.length; i++) { | ||
for (let i = 0; i < props.length; i++) { | ||
obj[props[i]] = vals[i] | ||
@@ -720,6 +718,6 @@ } | ||
function sendOptionsResponse (res, methods) { | ||
var options = Object.create(null) | ||
const options = Object.create(null) | ||
// build unique method map | ||
for (var i = 0; i < methods.length; i++) { | ||
for (let i = 0; i < methods.length; i++) { | ||
options[methods[i]] = true | ||
@@ -729,3 +727,3 @@ } | ||
// construct the allow list | ||
var allow = Object.keys(options).sort().join(', ') | ||
const allow = Object.keys(options).sort().join(', ') | ||
@@ -762,6 +760,6 @@ // send response | ||
return function proxy () { | ||
var args = new Array(arguments.length + 1) | ||
const args = new Array(arguments.length + 1) | ||
args[0] = old | ||
for (var i = 0, len = arguments.length; i < len; i++) { | ||
for (let i = 0, len = arguments.length; i < len; i++) { | ||
args[i + 1] = arguments[i] | ||
@@ -768,0 +766,0 @@ } |
100
lib/layer.js
@@ -15,4 +15,4 @@ /*! | ||
var isPromise = require('is-promise') | ||
var pathRegexp = require('path-to-regexp') | ||
const isPromise = require('is-promise') | ||
const pathRegexp = require('path-to-regexp') | ||
@@ -24,4 +24,4 @@ /** | ||
var hasOwnProperty = Object.prototype.hasOwnProperty | ||
var TRAILING_SLASH_REGEXP = /\/+$/ | ||
const TRAILING_SLASH_REGEXP = /\/+$/ | ||
const MATCHING_GROUP_REGEXP = /\((?:\?<(.*?)>)?(?!\?)/g | ||
@@ -39,3 +39,3 @@ /** | ||
var opts = options || {} | ||
const opts = options || {} | ||
@@ -47,6 +47,49 @@ this.handle = fn | ||
this.path = undefined | ||
this.regexp = pathRegexp((opts.strict ? path : loosen(path)), this.keys, opts) | ||
this.slash = path === '/' && opts.end === false | ||
// set fast path flags | ||
this.regexp._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)] | ||
} | ||
@@ -65,3 +108,3 @@ | ||
Layer.prototype.handleError = function handleError (error, req, res, next) { | ||
var fn = this.handle | ||
const fn = this.handle | ||
@@ -75,3 +118,3 @@ if (fn.length !== 4) { | ||
// invoke function | ||
var ret = fn(error, req, res, next) | ||
const ret = fn(error, req, res, next) | ||
@@ -99,3 +142,3 @@ // wait for returned promise | ||
Layer.prototype.handleRequest = function handleRequest (req, res, next) { | ||
var fn = this.handle | ||
const fn = this.handle | ||
@@ -109,3 +152,3 @@ if (fn.length > 3) { | ||
// invoke function | ||
var ret = fn(req, res, next) | ||
const ret = fn(req, res, next) | ||
@@ -133,7 +176,7 @@ // wait for returned promise | ||
Layer.prototype.match = function match (path) { | ||
var match | ||
let match | ||
if (path != null) { | ||
// fast path non-ending match for / (any path matches) | ||
if (this.regexp._slash) { | ||
if (this.slash) { | ||
this.params = {} | ||
@@ -144,4 +187,8 @@ this.path = '' | ||
// match the path | ||
match = this.regexp.exec(path) | ||
let i = 0 | ||
while (!match && i < this.matchers.length) { | ||
// match the path | ||
match = this.matchers[i](path) | ||
i++ | ||
} | ||
} | ||
@@ -156,19 +203,6 @@ | ||
// store values | ||
this.params = {} | ||
this.path = match[0] | ||
this.params = match.params | ||
this.path = match.path | ||
this.keys = Object.keys(match.params) | ||
// iterate matches | ||
var keys = this.keys | ||
var params = this.params | ||
for (var i = 1; i < match.length; i++) { | ||
var key = keys[i - 1] | ||
var prop = key.name | ||
var val = decodeParam(match[i]) | ||
if (val !== undefined || !(hasOwnProperty.call(params, prop))) { | ||
params[prop] = val | ||
} | ||
} | ||
return true | ||
@@ -206,3 +240,3 @@ } | ||
function loosen (path) { | ||
if (path instanceof RegExp) { | ||
if (path instanceof RegExp || path === '/') { | ||
return path | ||
@@ -209,0 +243,0 @@ } |
@@ -15,5 +15,5 @@ /*! | ||
var flatten = require('array-flatten').flatten | ||
var Layer = require('./layer') | ||
var methods = require('methods') | ||
const flatten = require('array-flatten').flatten | ||
const Layer = require('./layer') | ||
const methods = require('methods') | ||
@@ -25,6 +25,6 @@ /** | ||
var slice = Array.prototype.slice | ||
const slice = Array.prototype.slice | ||
/* istanbul ignore next */ | ||
var defer = typeof setImmediate === 'function' | ||
const defer = typeof setImmediate === 'function' | ||
? setImmediate | ||
@@ -64,3 +64,3 @@ : function (fn) { process.nextTick(fn.bind.apply(fn, arguments)) } | ||
// normalize name | ||
var name = typeof method === 'string' | ||
let name = typeof method === 'string' | ||
? method.toLowerCase() | ||
@@ -82,3 +82,3 @@ : method | ||
Route.prototype._methods = function _methods () { | ||
var methods = Object.keys(this.methods) | ||
const methods = Object.keys(this.methods) | ||
@@ -90,3 +90,3 @@ // append automatic head | ||
for (var i = 0; i < methods.length; i++) { | ||
for (let i = 0; i < methods.length; i++) { | ||
// make upper case | ||
@@ -106,5 +106,5 @@ methods[i] = methods[i].toUpperCase() | ||
Route.prototype.dispatch = function dispatch (req, res, done) { | ||
var idx = 0 | ||
var stack = this.stack | ||
var sync = 0 | ||
let idx = 0 | ||
const stack = this.stack | ||
let sync = 0 | ||
@@ -115,3 +115,3 @@ if (stack.length === 0) { | ||
var method = typeof req.method === 'string' | ||
let method = typeof req.method === 'string' | ||
? req.method.toLowerCase() | ||
@@ -149,4 +149,4 @@ : req.method | ||
var layer | ||
var match | ||
let layer | ||
let match | ||
@@ -203,3 +203,3 @@ // find next matching layer | ||
Route.prototype.all = function all (handler) { | ||
var callbacks = flatten(slice.call(arguments)) | ||
const callbacks = flatten(slice.call(arguments)) | ||
@@ -210,4 +210,4 @@ if (callbacks.length === 0) { | ||
for (var i = 0; i < callbacks.length; i++) { | ||
var fn = callbacks[i] | ||
for (let i = 0; i < callbacks.length; i++) { | ||
const fn = callbacks[i] | ||
@@ -218,3 +218,3 @@ if (typeof fn !== 'function') { | ||
var layer = Layer('/', {}, fn) | ||
const layer = Layer('/', {}, fn) | ||
layer.method = undefined | ||
@@ -231,3 +231,3 @@ | ||
Route.prototype[method] = function (handler) { | ||
var callbacks = flatten(slice.call(arguments)) | ||
const callbacks = flatten(slice.call(arguments)) | ||
@@ -238,4 +238,4 @@ if (callbacks.length === 0) { | ||
for (var i = 0; i < callbacks.length; i++) { | ||
var fn = callbacks[i] | ||
for (let i = 0; i < callbacks.length; i++) { | ||
const fn = callbacks[i] | ||
@@ -246,3 +246,3 @@ if (typeof fn !== 'function') { | ||
var layer = Layer('/', {}, fn) | ||
const layer = Layer('/', {}, fn) | ||
layer.method = method | ||
@@ -249,0 +249,0 @@ |
{ | ||
"name": "router", | ||
"description": "Simple middleware-style router", | ||
"version": "2.0.0-beta.2", | ||
"version": "2.0.0", | ||
"author": "Douglas Christopher Wilson <doug@somethingdoug.com>", | ||
@@ -16,3 +16,3 @@ "contributors": [ | ||
"parseurl": "~1.3.3", | ||
"path-to-regexp": "3.2.0", | ||
"path-to-regexp": "^8.0.0", | ||
"setprototypeof": "1.2.0", | ||
@@ -23,13 +23,8 @@ "utils-merge": "1.0.1" | ||
"after": "0.8.2", | ||
"eslint": "8.34.0", | ||
"eslint-config-standard": "14.1.1", | ||
"eslint-plugin-import": "2.26.0", | ||
"eslint-plugin-markdown": "3.0.0", | ||
"eslint-plugin-node": "11.1.0", | ||
"eslint-plugin-promise": "5.2.0", | ||
"eslint-plugin-standard": "4.1.0", | ||
"finalhandler": "1.2.0", | ||
"mocha": "10.2.0", | ||
"nyc": "15.1.0", | ||
"run-series": "^1.1.9", | ||
"safe-buffer": "5.2.1", | ||
"standard": "^17.1.0", | ||
"supertest": "6.3.3" | ||
@@ -49,4 +44,5 @@ }, | ||
"scripts": { | ||
"lint": "eslint .", | ||
"lint": "standard", | ||
"test": "mocha --reporter spec --bail --check-leaks test/", | ||
"test:debug": "mocha --reporter spec --bail --check-leaks test/ --inspect --inspect-brk", | ||
"test-ci": "nyc --reporter=lcov --reporter=text npm test", | ||
@@ -53,0 +49,0 @@ "test-cov": "nyc --reporter=text npm test", |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
46769
8
985
1
0
+ Addedpath-to-regexp@8.2.0(transitive)
- Removedpath-to-regexp@3.2.0(transitive)
Updatedpath-to-regexp@^8.0.0