Socket
Socket
Sign inDemoInstall

find-my-way

Package Overview
Dependencies
1
Maintainers
2
Versions
107
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 1.10.4 to 1.11.0

7

bench.js

@@ -11,2 +11,3 @@ 'use strict'

findMyWay.on('GET', '/user/:id', () => true)
findMyWay.on('GET', '/user/:id/static', () => true)
findMyWay.on('GET', '/customer/:name-:surname', () => true)

@@ -32,2 +33,5 @@ findMyWay.on('GET', '/at/:hour(^\\d+)h:minute(^\\d+)m', () => true)

})
.add('lookup long dynamic route', function () {
findMyWay.lookup({ method: 'GET', url: '/user/qwertyuiopasdfghjklzxcvbnm/static' }, null)
})
.add('find static route', function () {

@@ -48,2 +52,5 @@ findMyWay.find('GET', '/')

})
.add('find long dynamic route', function () {
findMyWay.find('GET', '/user/qwertyuiopasdfghjklzxcvbnm/static')
})
.on('cycle', function (event) {

@@ -50,0 +57,0 @@ console.log(String(event.target))

15

example.js
'use strict'
const http = require('http')
const router = require('./')()
const router = require('./')({
defaultRoute: (req, res) => {
res.end('not found')
}
})

@@ -10,4 +14,11 @@ router.on('GET', '/test', (req, res, params) => {

router.on('GET', '/:test', (req, res, params) => {
res.end(JSON.stringify(params))
})
router.on('GET', '/text/hello', (req, res, params) => {
res.end('{"winter":"is here"}')
})
const server = http.createServer((req, res) => {
console.log(req.url)
router.lookup(req, res)

@@ -14,0 +25,0 @@ })

145

index.js

@@ -14,6 +14,7 @@ 'use strict'

const assert = require('assert')
const http = require('http')
const fastDecode = require('fast-decode-uri-component')
const Node = require('./node')
const NODE_TYPES = Node.prototype.types
const httpMethods = ['DELETE', 'GET', 'HEAD', 'PATCH', 'POST', 'PUT', 'OPTIONS', 'TRACE', 'CONNECT']
var errored = false
const httpMethods = http.METHODS

@@ -86,2 +87,3 @@ function Router (opts) {

j = i + 1
// add the static part of the route to the tree
this._insert(method, path.slice(0, i), 0, null, null, null, null)

@@ -122,2 +124,3 @@

}
// add the parameter and continue with the search
this._insert(method, path.slice(0, i), nodeType, params, null, null, regex)

@@ -129,2 +132,3 @@

this._insert(method, path.slice(0, i), 0, null, null, null, null)
// add the wildcard parameter
params.push('*')

@@ -158,4 +162,5 @@ return this._insert(method, path.slice(0, len), 2, params, handler, store, null)

// the longest common prefix is smaller than the current prefix
// let's split the node and add a new child
if (len < prefixLen) {
// split the node in the radix tree and add it to the parent
node = new Node(

@@ -173,13 +178,9 @@ prefix.slice(len),

// reset the parent
currentNode.children = [node]
currentNode.numberOfChildren = 1
currentNode.prefix = prefix.slice(0, len)
currentNode.label = currentNode.prefix[0]
currentNode.handlers = new Node.Handlers()
currentNode.kind = NODE_TYPES.STATIC
currentNode.regex = null
currentNode.wildcardChild = null
currentNode
.reset(prefix.slice(0, len))
.addChild(node)
// if the longest common prefix has the same length of the current path
// the handler should be added to the current node, to a child otherwise
if (len === pathLen) {
// add the handler to the parent node
assert(!currentNode.getHandler(method), `Method '${method}' already declared for route '${route}'`)

@@ -189,23 +190,26 @@ currentNode.setHandler(method, handler, params, store)

} else {
// create a child node and add an handler to it
node = new Node(path.slice(len), [], kind, null, regex)
node = new Node(path.slice(len), {}, kind, null, regex)
node.setHandler(method, handler, params, store)
// add the child to the parent
currentNode.add(node)
currentNode.addChild(node)
}
// the longest common prefix is smaller than the path length,
// but is higher than the prefix
} else if (len < pathLen) {
// remove the prefix
path = path.slice(len)
node = currentNode.findByLabel(path[0])
// check if there is a child with the label extracted from the new path
node = currentNode.findByLabel(path)
// there is a child within the given label, we must go deepen in the tree
if (node) {
// we must go deeper in the tree
currentNode = node
continue
}
// create a new child node
node = new Node(path, [], kind, null, regex)
// there are not children within the given label, let's create a new one!
node = new Node(path, {}, kind, null, regex)
node.setHandler(method, handler, params, store)
// add the child to the parent
currentNode.add(node)
currentNode.addChild(node)
// the node already exist
} else if (handler) {
// the node already exist
assert(!currentNode.getHandler(method), `Method '${method}' already declared for route '${route}'`)

@@ -271,3 +275,3 @@ currentNode.setHandler(method, handler, params, store)

var handle = this.find(req.method, sanitizeUrl(req.url))
if (handle == null) return this._defaultRoute(req, res)
if (handle === null) return this._defaultRoute(req, res)
return handle.handler(req, res, handle.params, handle.store)

@@ -297,3 +301,3 @@ }

var handle = currentNode.handlers[method]
if (handle != null) {
if (handle !== null) {
var paramsObj = {}

@@ -318,3 +322,3 @@ if (handle.paramsLength > 0) {

i = pathLen < prefixLen ? pathLen : prefixLen
while (len < i && path[len] === prefix[len]) len++
while (len < i && path.charCodeAt(len) === prefix.charCodeAt(len)) len++

@@ -326,3 +330,3 @@ if (len === prefixLen) {

var node = currentNode.find(path, method)
var node = currentNode.findChild(path, method)
if (node === null) {

@@ -363,9 +367,7 @@ node = currentNode.parametricBrother

currentNode = node
i = 0
while (i < pathLen && path.charCodeAt(i) !== 47) i++
i = path.indexOf('/')
if (i === -1) i = pathLen
if (i > maxParamLength) return null
decoded = fastDecode(path.slice(0, i))
if (errored === true) {
return null
}
if (decoded === null) return null
params[pindex++] = decoded

@@ -379,5 +381,3 @@ path = path.slice(i)

decoded = fastDecode(path)
if (errored === true) {
return null
}
if (decoded === null) return null
params[pindex] = decoded

@@ -392,9 +392,7 @@ currentNode = node

currentNode = node
i = 0
while (i < pathLen && path.charCodeAt(i) !== 47) i++
i = path.indexOf('/')
if (i === -1) i = pathLen
if (i > maxParamLength) return null
decoded = fastDecode(path.slice(0, i))
if (errored === true) {
return null
}
if (decoded === null) return null
if (!node.regex.test(decoded)) return null

@@ -419,5 +417,3 @@ params[pindex++] = decoded

decoded = fastDecode(path.slice(0, i))
if (errored === true) {
return null
}
if (decoded === null) return null
params[pindex++] = decoded

@@ -445,38 +441,13 @@ path = path.slice(i)

Router.prototype.get = function (path, handler, store) {
return this.on('GET', path, handler, store)
}
for (var i in http.METHODS) {
const m = http.METHODS[i]
const methodName = m.toLowerCase()
Router.prototype.delete = function (path, handler, store) {
return this.on('DELETE', path, handler, store)
}
if (Router.prototype[methodName]) throw new Error('Method already exists: ' + methodName)
Router.prototype.head = function (path, handler, store) {
return this.on('HEAD', path, handler, store)
Router.prototype[methodName] = function (path, handler, store) {
return this.on(m, path, handler, store)
}
}
Router.prototype.patch = function (path, handler, store) {
return this.on('PATCH', path, handler, store)
}
Router.prototype.post = function (path, handler, store) {
return this.on('POST', path, handler, store)
}
Router.prototype.put = function (path, handler, store) {
return this.on('PUT', path, handler, store)
}
Router.prototype.options = function (path, handler, store) {
return this.on('OPTIONS', path, handler, store)
}
Router.prototype.trace = function (path, handler, store) {
return this.on('TRACE', path, handler, store)
}
Router.prototype.connect = function (path, handler, store) {
return this.on('CONNECT', path, handler, store)
}
Router.prototype.all = function (path, handler, store) {

@@ -498,19 +469,8 @@ this.on(httpMethods, path, handler, store)

function fastDecode (path) {
errored = false
try {
return decodeURIComponent(path)
} catch (err) {
errored = true
}
}
function getWildcardNode (node, method, path, len) {
if (node === null) return null
var decoded = fastDecode(path.slice(-len))
if (errored === true) {
return null
}
if (decoded === null) return null
var handle = node.handlers[method]
if (handle != null) {
if (handle !== null) {
return {

@@ -525,11 +485,2 @@ handler: handle.handler,

/**
* Returns the position of the last closing parenthese of the regexp expression.
*
* @param {String} path
* @param {Number} idx
* @returns {Number}
* @throws {TypeError} when a closing parenthese is missing
* @private
*/
function getClosingParenthensePosition (path, idx) {

@@ -536,0 +487,0 @@ // `path.indexOf()` will always return the first position of the closing parenthese,

'use strict'
const assert = require('assert')
const http = require('http')
const Handlers = buildHandlers()
const types = {

@@ -15,6 +19,6 @@ STATIC: 0,

this.label = this.prefix[0]
this.children = children || []
this.numberOfChildren = this.children.length
this.children = children || {}
this.numberOfChildren = Object.keys(this.children).length
this.kind = kind || this.types.STATIC
this.handlers = handlers || new Handlers()
this.handlers = new Handlers(handlers)
this.regex = regex || null

@@ -29,16 +33,38 @@ this.wildcardChild = null

Node.prototype.add = function (node) {
if (node.kind === this.types.MATCH_ALL) {
this.wildcardChild = node
Node.prototype.getLabel = function () {
return this.prefix[0]
}
Node.prototype.addChild = function (node) {
var label = ''
switch (node.kind) {
case this.types.STATIC:
label = node.getLabel()
break
case this.types.PARAM:
case this.types.REGEX:
case this.types.MULTI_PARAM:
label = ':'
break
case this.types.MATCH_ALL:
this.wildcardChild = node
label = '*'
break
default:
throw new Error(`Unknown node kind: ${node.kind}`)
}
this.children.push(node)
this.children.sort((n1, n2) => n1.kind - n2.kind)
this.numberOfChildren++
assert(
this.children[label] === undefined,
`There is already a child with label '${label}'`
)
// Search for a parametric brother and store it in a variable
this.children[label] = node
this.numberOfChildren = Object.keys(this.children).length
const labels = Object.keys(this.children)
var parametricBrother = null
for (var i = 0; i < this.numberOfChildren; i++) {
const child = this.children[i]
if ([this.types.PARAM, this.types.REGEX, this.types.MULTI_PARAM].indexOf(child.kind) > -1) {
for (var i = 0; i < labels.length; i++) {
const child = this.children[labels[i]]
if (child.label === ':') {
parametricBrother = child

@@ -49,30 +75,41 @@ break

// Save the parametric brother inside a static child
for (i = 0; i < this.numberOfChildren; i++) {
if (this.children[i].kind === this.types.STATIC && parametricBrother) {
this.children[i].parametricBrother = parametricBrother
// Save the parametric brother inside a static children
for (i = 0; i < labels.length; i++) {
const child = this.children[labels[i]]
if (child.kind === this.types.STATIC && parametricBrother) {
child.parametricBrother = parametricBrother
}
}
return this
}
Node.prototype.findByLabel = function (label) {
for (var i = 0; i < this.numberOfChildren; i++) {
var child = this.children[i]
if (child.label === label) {
return child
}
}
return null
Node.prototype.reset = function (prefix) {
this.prefix = prefix
this.children = {}
this.kind = this.types.STATIC
this.handlers = new Handlers()
this.numberOfChildren = 0
this.regex = null
this.wildcardChild = null
return this
}
Node.prototype.find = function (path, method) {
for (var i = 0; i < this.numberOfChildren; i++) {
var child = this.children[i]
if (
(child.numberOfChildren !== 0 || child.handlers[method] !== null) &&
(child.kind !== 0 || path.slice(0, child.prefix.length) === child.prefix)
) {
Node.prototype.findByLabel = function (path) {
return this.children[path[0]]
}
Node.prototype.findChild = function (path, method) {
var child = this.children[path[0]]
if (child !== undefined && (child.numberOfChildren > 0 || child.handlers[method] !== null)) {
if (path.slice(0, child.prefix.length) === child.prefix) {
return child
}
}
child = this.children[':'] || this.children['*']
if (child !== undefined && (child.numberOfChildren > 0 || child.handlers[method] !== null)) {
return child
}
return null

@@ -84,2 +121,7 @@ }

assert(
this.handlers[method] !== undefined,
`There is already an handler with method '${method}'`
)
this.handlers[method] = {

@@ -124,7 +166,8 @@ handler: handler,

prefix = `${prefix}${tail ? ' ' : '│ '}`
for (var i = 0; i < this.numberOfChildren - 1; i++) {
tree += this.children[i].prettyPrint(prefix, false)
const labels = Object.keys(this.children)
for (var i = 0; i < labels.length - 1; i++) {
tree += this.children[labels[i]].prettyPrint(prefix, false)
}
if (this.numberOfChildren > 0) {
tree += this.children[this.numberOfChildren - 1].prettyPrint(prefix, true)
if (labels.length > 0) {
tree += this.children[labels[labels.length - 1]].prettyPrint(prefix, true)
}

@@ -134,13 +177,11 @@ return tree

function Handlers (handlers) {
handlers = handlers || {}
this.DELETE = handlers.DELETE || null
this.GET = handlers.GET || null
this.HEAD = handlers.HEAD || null
this.PATCH = handlers.PATCH || null
this.POST = handlers.POST || null
this.PUT = handlers.PUT || null
this.OPTIONS = handlers.OPTIONS || null
this.TRACE = handlers.TRACE || null
this.CONNECT = handlers.CONNECT || null
function buildHandlers (handlers) {
var code = `handlers = handlers || {}
`
for (var i in http.METHODS) {
var m = http.METHODS[i]
code += `this['${m}'] = handlers['${m}'] || null
`
}
return new Function('handlers', code) // eslint-disable-line
}

@@ -147,0 +188,0 @@

{
"name": "find-my-way",
"version": "1.10.4",
"version": "1.11.0",
"description": "Crazy fast http radix based router",

@@ -31,6 +31,10 @@ "main": "index.js",

"coveralls": "^3.0.0",
"pre-commit": "^1.2.2",
"request": "^2.83.0",
"standard": "^10.0.3",
"tap": "^11.0.0"
},
"dependencies": {
"fast-decode-uri-component": "^1.0.0"
}
}

@@ -140,2 +140,6 @@ # find-my-way

<a name="supported-methods"></a>
##### Supported methods
The router is able to route all HTTP methods defined by [`http` core module](https://nodejs.org/api/http.html#http_http_methods).
<a name="off"></a>

@@ -182,2 +186,4 @@ #### off(method, path)

If you want an even nicer api, you can also use the shorthand methods to declare your routes.
For each HTTP supported method, there's the shorthand method. For example:
```js

@@ -191,4 +197,3 @@ router.get(path, handler [, store])

router.options(path, handler [, store])
router.trace(path, handler [, store])
router.connect(path, handler [, store])
// ...
```

@@ -195,0 +200,0 @@

@@ -36,1 +36,17 @@ 'use strict'

})
test('parametric with common prefix', t => {
t.plan(1)
const findMyWay = FindMyWay()
findMyWay.on('GET', '/test', noop)
findMyWay.on('GET', '/:test', (req, res, params) => {
t.deepEqual(
{ test: 'text' },
params
)
})
findMyWay.on('GET', '/text/hello', noop)
findMyWay.lookup({ url: '/text', method: 'GET' })
})

@@ -714,1 +714,23 @@ 'use strict'

})
test('register all known HTTP methods', t => {
t.plan(6)
const findMyWay = FindMyWay()
const http = require('http')
const handlers = {}
for (var i in http.METHODS) {
var m = http.METHODS[i]
handlers[m] = function myHandler () {}
findMyWay.on(m, '/test', handlers[m])
}
t.ok(findMyWay.find('COPY', '/test'))
t.equal(findMyWay.find('COPY', '/test').handler, handlers.COPY)
t.ok(findMyWay.find('SUBSCRIBE', '/test'))
t.equal(findMyWay.find('SUBSCRIBE', '/test').handler, handlers.SUBSCRIBE)
t.ok(findMyWay.find('M-SEARCH', '/test'))
t.equal(findMyWay.find('M-SEARCH', '/test').handler, handlers['M-SEARCH'])
})
'use strict'
const http = require('http')
const t = require('tap')

@@ -7,105 +8,26 @@ const test = t.test

test('should support `.get` shorthand', t => {
t.plan(1)
const findMyWay = FindMyWay()
t.test('should support shorthand', t => {
t.plan(http.METHODS.length)
findMyWay.get('/test', () => {
t.ok('inside the handler')
})
for (var i in http.METHODS) {
const m = http.METHODS[i]
const methodName = m.toLowerCase()
findMyWay.lookup({ method: 'GET', url: '/test' }, null)
})
t.test('`.' + methodName + '`', t => {
t.plan(1)
const findMyWay = FindMyWay()
test('should support `.delete` shorthand', t => {
t.plan(1)
const findMyWay = FindMyWay()
findMyWay[methodName]('/test', () => {
t.ok('inside the handler')
})
findMyWay.delete('/test', () => {
t.ok('inside the handler')
})
findMyWay.lookup({ method: 'DELETE', url: '/test' }, null)
findMyWay.lookup({ method: m, url: '/test' }, null)
})
}
})
test('should support `.head` shorthand', t => {
t.plan(1)
test('should support `.all` shorthand', t => {
t.plan(11)
const findMyWay = FindMyWay()
findMyWay.head('/test', () => {
t.ok('inside the handler')
})
findMyWay.lookup({ method: 'HEAD', url: '/test' }, null)
})
test('should support `.patch` shorthand', t => {
t.plan(1)
const findMyWay = FindMyWay()
findMyWay.patch('/test', () => {
t.ok('inside the handler')
})
findMyWay.lookup({ method: 'PATCH', url: '/test' }, null)
})
test('should support `.post` shorthand', t => {
t.plan(1)
const findMyWay = FindMyWay()
findMyWay.post('/test', () => {
t.ok('inside the handler')
})
findMyWay.lookup({ method: 'POST', url: '/test' }, null)
})
test('should support `.put` shorthand', t => {
t.plan(1)
const findMyWay = FindMyWay()
findMyWay.put('/test', () => {
t.ok('inside the handler')
})
findMyWay.lookup({ method: 'PUT', url: '/test' }, null)
})
test('should support `.options` shorthand', t => {
t.plan(1)
const findMyWay = FindMyWay()
findMyWay.options('/test', () => {
t.ok('inside the handler')
})
findMyWay.lookup({ method: 'OPTIONS', url: '/test' }, null)
})
test('should support `.trace` shorthand', t => {
t.plan(1)
const findMyWay = FindMyWay()
findMyWay.trace('/test', () => {
t.ok('inside the handler')
})
findMyWay.lookup({ method: 'TRACE', url: '/test' }, null)
})
test('should support `.connect` shorthand', t => {
t.plan(1)
const findMyWay = FindMyWay()
findMyWay.connect('/test', () => {
t.ok('inside the handler')
})
findMyWay.lookup({ method: 'CONNECT', url: '/test' }, null)
})
test('should support `.connect` shorthand', t => {
t.plan(9)
const findMyWay = FindMyWay()
findMyWay.all('/test', () => {

@@ -124,2 +46,4 @@ t.ok('inside the handler')

findMyWay.lookup({ method: 'CONNECT', url: '/test' }, null)
findMyWay.lookup({ method: 'COPY', url: '/test' }, null)
findMyWay.lookup({ method: 'SUBSCRIBE', url: '/test' }, null)
})
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap

Packages

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc