Socket
Socket
Sign inDemoInstall

find-my-way

Package Overview
Dependencies
Maintainers
2
Versions
111
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

find-my-way - npm Package Compare versions

Comparing version 7.5.0 to 7.6.0

lib/strategies/http-method.js

25

custom_node.js

@@ -13,4 +13,18 @@ 'use strict'

constructor () {
this.handlerStorage = new HandlerStorage()
this.isLeafNode = false
this.routes = null
this.handlerStorage = null
}
addRoute (route, constrainer) {
if (this.routes === null) {
this.routes = []
}
if (this.handlerStorage === null) {
this.handlerStorage = new HandlerStorage()
}
this.isLeafNode = true
this.routes.push(route)
this.handlerStorage.addHandler(constrainer, route)
}
}

@@ -65,3 +79,3 @@

createParametricChild (regex, staticSuffix) {
createParametricChild (regex, staticSuffix, nodePath) {
const regexpSource = regex && regex.source

@@ -75,6 +89,7 @@

if (parametricChild) {
parametricChild.nodePaths.add(nodePath)
return parametricChild
}
parametricChild = new ParametricNode(regex, staticSuffix)
parametricChild = new ParametricNode(regex, staticSuffix, nodePath)
this.parametricChildren.push(parametricChild)

@@ -168,3 +183,3 @@ this.parametricChildren.sort((child1, child2) => {

class ParametricNode extends ParentNode {
constructor (regex, staticSuffix) {
constructor (regex, staticSuffix, nodePath) {
super()

@@ -175,2 +190,4 @@ this.isRegex = !!regex

this.kind = NODE_TYPES.PARAMETRIC
this.nodePaths = new Set([nodePath])
}

@@ -177,0 +194,0 @@

23

handler_storage.js
'use strict'
const httpMethodStrategy = require('./lib/strategies/http-method')
class HandlerStorage {

@@ -19,16 +21,20 @@ constructor () {

addHandler (handler, params, store, constrainer, constraints) {
addHandler (constrainer, route) {
const params = route.params
const constraints = route.opts.constraints || {}
const handlerObject = {
handler,
params,
constraints,
store: store || null,
handler: route.handler,
store: route.store || null,
_createParamsObject: this._compileCreateParamsObject(params)
}
if (Object.keys(constraints).length === 0) {
const constraintsNames = Object.keys(constraints)
if (constraintsNames.length === 0) {
this.unconstrainedHandler = handlerObject
}
for (const constraint of Object.keys(constraints)) {
for (const constraint of constraintsNames) {
if (!this.constraints.includes(constraint)) {

@@ -44,3 +50,4 @@ if (constraint === 'version') {

if (this.handlers.length >= 32) {
const isMergedTree = constraintsNames.includes(httpMethodStrategy.name)
if (!isMergedTree && this.handlers.length >= 32) {
throw new Error('find-my-way supports a maximum of 32 route handlers per node when there are constraints, limit reached')

@@ -53,3 +60,5 @@ }

this._compileGetHandlerMatchingConstraints(constrainer, constraints)
if (!isMergedTree) {
this._compileGetHandlerMatchingConstraints(constrainer, constraints)
}
}

@@ -56,0 +65,0 @@

@@ -164,3 +164,7 @@ import { IncomingMessage, ServerResponse } from 'http';

prettyPrint(): string;
prettyPrint(opts: { commonPrefix?: boolean, includeMeta?: boolean | (string | symbol)[] }): string;
prettyPrint(opts: {
method?: HTTPMethod,
commonPrefix?: boolean,
includeMeta?: boolean | (string | symbol)[]
}): string;

@@ -167,0 +171,0 @@ hasConstraintStrategy(strategyName: string): boolean;

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

const deepEqual = require('fast-deep-equal')
const { flattenNode, compressFlattenedNode, prettyPrintFlattenedNode, prettyPrintRoutesArray } = require('./lib/pretty-print')
const { prettyPrintTree } = require('./lib/pretty-print')
const { StaticNode, NODE_TYPES } = require('./custom_node')
const Constrainer = require('./lib/constrainer')
const httpMethods = require('./lib/http-methods')
const httpMethodStrategy = require('./lib/strategies/http-method')
const { safeDecodeURI, safeDecodeURIComponent } = require('./lib/url-sanitizer')

@@ -55,2 +56,3 @@

opts = opts || {}
this._opts = opts

@@ -90,7 +92,6 @@ if (opts.defaultRoute) {

this.allowUnsafeRegex = opts.allowUnsafeRegex || false
this.constrainer = new Constrainer(opts.constraints)
this.routes = []
this.trees = {}
this.constrainer = new Constrainer(opts.constraints)
this._routesPatterns = {}
}

@@ -138,4 +139,5 @@

for (const method of methods) {
assert(typeof method === 'string', 'Method should be a string')
assert(httpMethods.includes(method), `Method '${method}' is not an http method.`)
this._on(method, path, opts, handler, store, route)
this.routes.push({ method, path, opts, handler, store })
}

@@ -145,5 +147,2 @@ }

Router.prototype._on = function _on (method, path, opts, handler, store) {
assert(typeof method === 'string', 'Method should be a string')
assert(httpMethods.includes(method), `Method '${method}' is not an http method.`)
let constraints = {}

@@ -164,6 +163,6 @@ if (opts.constraints !== undefined) {

this.trees[method] = new StaticNode('/')
this._routesPatterns[method] = []
}
if (path === '*' && this.trees[method].prefix.length !== 0) {
let pattern = path
if (pattern === '*' && this.trees[method].prefix.length !== 0) {
const currentRoot = this.trees[method]

@@ -178,4 +177,4 @@ this.trees[method] = new StaticNode('')

const params = []
for (let i = 0; i <= path.length; i++) {
if (path.charCodeAt(i) === 58 && path.charCodeAt(i + 1) === 58) {
for (let i = 0; i <= pattern.length; i++) {
if (pattern.charCodeAt(i) === 58 && pattern.charCodeAt(i + 1) === 58) {
// It's a double colon

@@ -186,7 +185,7 @@ i++

const isParametricNode = path.charCodeAt(i) === 58 && path.charCodeAt(i + 1) !== 58
const isWildcardNode = path.charCodeAt(i) === 42
const isParametricNode = pattern.charCodeAt(i) === 58 && pattern.charCodeAt(i + 1) !== 58
const isWildcardNode = pattern.charCodeAt(i) === 42
if (isParametricNode || isWildcardNode || (i === path.length && i !== parentNodePathIndex)) {
let staticNodePath = path.slice(parentNodePathIndex, i)
if (isParametricNode || isWildcardNode || (i === pattern.length && i !== parentNodePathIndex)) {
let staticNodePath = pattern.slice(parentNodePathIndex, i)
if (!this.caseSensitive) {

@@ -207,10 +206,10 @@ staticNodePath = staticNodePath.toLowerCase()

for (let j = lastParamStartIndex; ; j++) {
const charCode = path.charCodeAt(j)
const charCode = pattern.charCodeAt(j)
const isRegexParam = charCode === 40
const isStaticPart = charCode === 45 || charCode === 46
const isEndOfNode = charCode === 47 || j === path.length
const isEndOfNode = charCode === 47 || j === pattern.length
if (isRegexParam || isStaticPart || isEndOfNode) {
const paramName = path.slice(lastParamStartIndex, j)
const paramName = pattern.slice(lastParamStartIndex, j)
params.push(paramName)

@@ -221,4 +220,4 @@

if (isRegexParam) {
const endOfRegexIndex = getClosingParenthensePosition(path, j)
const regexString = path.slice(j, endOfRegexIndex + 1)
const endOfRegexIndex = getClosingParenthensePosition(pattern, j)
const regexString = pattern.slice(j, endOfRegexIndex + 1)

@@ -237,7 +236,7 @@ if (!this.allowUnsafeRegex) {

const staticPartStartIndex = j
for (; j < path.length; j++) {
const charCode = path.charCodeAt(j)
for (; j < pattern.length; j++) {
const charCode = pattern.charCodeAt(j)
if (charCode === 47) break
if (charCode === 58) {
const nextCharCode = path.charCodeAt(j + 1)
const nextCharCode = pattern.charCodeAt(j + 1)
if (nextCharCode === 58) j++

@@ -248,3 +247,3 @@ else break

let staticPart = path.slice(staticPartStartIndex, j)
let staticPart = pattern.slice(staticPartStartIndex, j)
if (staticPart) {

@@ -258,10 +257,11 @@ staticPart = staticPart.split('::').join(':')

if (isEndOfNode || path.charCodeAt(j) === 47 || j === path.length) {
if (isEndOfNode || pattern.charCodeAt(j) === 47 || j === pattern.length) {
const nodePattern = isRegexNode ? '()' + staticPart : staticPart
const nodePath = pattern.slice(i, j)
path = path.slice(0, i + 1) + nodePattern + path.slice(j)
pattern = pattern.slice(0, i + 1) + nodePattern + pattern.slice(j)
i += nodePattern.length
const regex = isRegexNode ? new RegExp('^' + regexps.join('') + '$') : null
currentNode = currentNode.createParametricChild(regex, staticPart || null)
currentNode = currentNode.createParametricChild(regex, staticPart || null, nodePath)
parentNodePathIndex = i + 1

@@ -278,3 +278,3 @@ break

if (i !== path.length - 1) {
if (i !== pattern.length - 1) {
throw new Error('Wildcard must be the last character in the route')

@@ -286,17 +286,23 @@ }

if (!this.caseSensitive) {
path = path.toLowerCase()
pattern = pattern.toLowerCase()
}
if (path === '*') {
path = '/*'
if (pattern === '*') {
pattern = '/*'
}
for (const existRoute of this._routesPatterns[method]) {
if (existRoute.path === path && deepEqual(existRoute.constraints, constraints)) {
throw new Error(`Method '${method}' already declared for route '${path}' with constraints '${JSON.stringify(constraints)}'`)
for (const existRoute of this.routes) {
const routeConstraints = existRoute.opts.constraints || {}
if (
existRoute.method === method &&
existRoute.pattern === pattern &&
deepEqual(routeConstraints, constraints)
) {
throw new Error(`Method '${method}' already declared for route '${pattern}' with constraints '${JSON.stringify(constraints)}'`)
}
}
this._routesPatterns[method].push({ path, params, constraints })
currentNode.handlerStorage.addHandler(handler, params, store, this.constrainer, constraints)
const route = { method, path, pattern, params, opts, handler, store }
this.routes.push(route)
currentNode.addRoute(route, this.constrainer)
}

@@ -316,3 +322,2 @@

this.routes = []
this._routesPatterns = {}
}

@@ -460,5 +465,4 @@

while (true) {
if (pathIndex === pathLen) {
if (pathIndex === pathLen && currentNode.isLeafNode) {
const handle = currentNode.handlerStorage.getMatchingHandler(derivedConstraints)
if (handle !== null) {

@@ -546,3 +550,2 @@ return {

this._on(method, path, opts, handler, store)
this.routes.push({ method, path, opts, handler, store })
}

@@ -574,21 +577,26 @@ }

Router.prototype.prettyPrint = function (opts = {}) {
opts.commonPrefix = opts.commonPrefix === undefined ? true : opts.commonPrefix // default to original behaviour
if (!opts.commonPrefix) return prettyPrintRoutesArray.call(this, this.routes, opts)
const root = {
prefix: '/',
nodes: [],
children: {}
}
Router.prototype.prettyPrint = function (options = {}) {
const method = options.method
for (const method in this.trees) {
const node = this.trees[method]
if (node) {
flattenNode(root, node, method)
}
options.buildPrettyMeta = this.buildPrettyMeta.bind(this)
if (method === undefined) {
const { version, host, ...constraints } = this.constrainer.strategies
constraints[httpMethodStrategy.name] = httpMethodStrategy
const mergedRouter = new Router({ ...this._opts, constraints })
const mergedRoutes = this.routes.map(route => {
const constraints = {
...route.opts.constraints,
[httpMethodStrategy.name]: route.method
}
return { ...route, method: 'MERGED', opts: { constraints } }
})
mergedRouter._rebuild(mergedRoutes)
return prettyPrintTree(mergedRouter.trees.MERGED, options)
}
compressFlattenedNode(root)
return prettyPrintFlattenedNode.call(this, root, '', true, opts)
const tree = this.trees[method]
return prettyPrintTree(tree, options)
}

@@ -595,0 +603,0 @@

'use strict'
/* eslint-disable no-multi-spaces */
const indent = ' '
const branchIndent = '│ '
const midBranchIndent = '├── '
const endBranchIndent = '└── '
const wildcardDelimiter = '*'
const pathDelimiter = '/'
const pathRegExp = /(?=\/)/
/* eslint-enable */
const deepEqual = require('fast-deep-equal')
const httpMethodStrategy = require('./strategies/http-method')
const treeDataSymbol = Symbol('treeData')
function printObjectTree (obj, parentPrefix = '') {
let tree = ''
const keys = Object.keys(obj)
for (let i = 0; i < keys.length; i++) {
const key = keys[i]
const value = obj[key]
const isLast = i === keys.length - 1
const nodePrefix = isLast ? '└── ' : '├── '
const childPrefix = isLast ? ' ' : '│ '
const nodeData = value[treeDataSymbol] || ''
const prefixedNodeData = nodeData.split('\n').join('\n' + parentPrefix + childPrefix)
tree += parentPrefix + nodePrefix + key + prefixedNodeData + '\n'
tree += printObjectTree(value, parentPrefix + childPrefix)
}
return tree
}
function parseFunctionName (fn) {

@@ -28,248 +43,101 @@ let fName = fn.name || ''

function buildMetaObject (route, metaArray) {
const out = {}
const cleanMeta = this.buildPrettyMeta(route)
if (!Array.isArray(metaArray)) metaArray = cleanMeta ? Reflect.ownKeys(cleanMeta) : []
metaArray.forEach(m => {
const metaKey = typeof m === 'symbol' ? m.toString() : m
if (cleanMeta && cleanMeta[m]) {
out[metaKey] = parseMeta(cleanMeta[m])
}
})
return out
}
function getRouteMetaData (route, options) {
if (!options.includeMeta) return {}
function prettyPrintRoutesArray (routeArray, opts = {}) {
if (!this.buildPrettyMeta) throw new Error('buildPrettyMeta not defined')
opts.includeMeta = opts.includeMeta || null // array of meta objects to display
const mergedRouteArray = []
const metaDataObject = options.buildPrettyMeta(route)
const filteredMetaData = {}
let tree = ''
let includeMetaKeys = options.includeMeta
if (!Array.isArray(includeMetaKeys)) {
includeMetaKeys = Reflect.ownKeys(metaDataObject)
}
routeArray.sort((a, b) => {
if (!a.path || !b.path) return 0
return a.path.localeCompare(b.path)
})
for (const metaKey of includeMetaKeys) {
if (!Object.prototype.hasOwnProperty.call(metaDataObject, metaKey)) continue
// merge alike paths
for (let i = 0; i < routeArray.length; i++) {
const route = routeArray[i]
const pathExists = mergedRouteArray.find(r => route.path === r.path)
if (pathExists) {
// path already declared, add new method and break out of loop
pathExists.handlers.push({
method: route.method,
opts: route.opts.constraints || undefined,
meta: opts.includeMeta ? buildMetaObject.call(this, route, opts.includeMeta) : null
})
continue
}
const serializedKey = metaKey.toString()
const metaValue = metaDataObject[metaKey]
const routeHandler = {
method: route.method,
opts: route.opts.constraints || undefined,
meta: opts.includeMeta ? buildMetaObject.call(this, route, opts.includeMeta) : null
if (metaValue !== undefined && metaValue !== null) {
const serializedValue = JSON.stringify(parseMeta(metaValue))
filteredMetaData[serializedKey] = serializedValue
}
mergedRouteArray.push({
path: route.path,
methods: [route.method],
opts: [route.opts],
handlers: [routeHandler]
})
}
// insert root level path if none defined
if (!mergedRouteArray.filter(r => r.path === pathDelimiter).length) {
const rootPath = {
path: pathDelimiter,
truncatedPath: '',
methods: [],
opts: [],
handlers: [{}]
}
return filteredMetaData
}
// if wildcard route exists, insert root level after wildcard
if (mergedRouteArray.filter(r => r.path === wildcardDelimiter).length) {
mergedRouteArray.splice(1, 0, rootPath)
} else {
mergedRouteArray.unshift(rootPath)
}
function serializeMetaData (metaData) {
let serializedMetaData = ''
for (const [key, value] of Object.entries(metaData)) {
serializedMetaData += `\n• (${key}) ${value}`
}
return serializedMetaData
}
// build tree
const routeTree = buildRouteTree(mergedRouteArray)
// draw tree
routeTree.forEach((rootBranch, idx) => {
tree += drawBranch(rootBranch, null, idx === routeTree.length - 1, false, true)
tree += '\n' // newline characters inserted at beginning of drawing function to allow for nested paths
})
return tree
// get original merged tree node route
function normalizeRoute (route) {
const constraints = { ...route.opts.constraints }
const method = constraints[httpMethodStrategy.name]
delete constraints[httpMethodStrategy.name]
return { ...route, method, opts: { constraints } }
}
function buildRouteTree (mergedRouteArray) {
const result = []
const temp = { result }
mergedRouteArray.forEach((route, idx) => {
let splitPath = route.path.split(pathRegExp)
function serializeRoute (route) {
let serializedRoute = ` (${route.method})`
// add preceding slash for proper nesting
if (splitPath[0] !== pathDelimiter) {
// handle wildcard route
if (splitPath[0] !== wildcardDelimiter) splitPath = [pathDelimiter, splitPath[0].slice(1), ...splitPath.slice(1)]
}
const constraints = route.opts.constraints || {}
if (Object.keys(constraints).length !== 0) {
serializedRoute += ' ' + JSON.stringify(constraints)
}
// build tree
splitPath.reduce((acc, path, pidx) => {
if (!acc[path]) {
acc[path] = { result: [] }
const pathSeg = { path, children: acc[path].result }
serializedRoute += serializeMetaData(route.metaData)
return serializedRoute
}
if (pidx === splitPath.length - 1) pathSeg.handlers = route.handlers
acc.result.push(pathSeg)
function mergeSimilarRoutes (routes) {
return routes.reduce((mergedRoutes, route) => {
for (const nodeRoute of mergedRoutes) {
if (
deepEqual(route.opts.constraints, nodeRoute.opts.constraints) &&
deepEqual(route.metaData, nodeRoute.metaData)
) {
nodeRoute.method += ', ' + route.method
return mergedRoutes
}
return acc[path]
}, temp)
})
// unfold root object from array
return result
}
mergedRoutes.push(route)
return mergedRoutes
}, [])
}
function drawBranch (pathSeg, prefix, endBranch, noPrefix, rootBranch) {
let branch = ''
function serializeNode (node, prefix, options) {
let routes = node.routes
if (!noPrefix && !rootBranch) branch += '\n'
if (!noPrefix) branch += `${prefix || ''}${endBranch ? endBranchIndent : midBranchIndent}`
branch += `${pathSeg.path}`
if (pathSeg.handlers) {
const flatHandlers = pathSeg.handlers.reduce((acc, curr) => {
const match = acc.findIndex(h => JSON.stringify(h.opts) === JSON.stringify(curr.opts))
if (match !== -1) {
acc[match].method = [acc[match].method, curr.method].join(', ')
} else {
acc.push(curr)
}
return acc
}, [])
flatHandlers.forEach((handler, idx) => {
if (idx > 0) branch += `${noPrefix ? '' : prefix || ''}${endBranch ? indent : branchIndent}${pathSeg.path}`
branch += ` (${handler.method || '-'})`
if (handler.opts && JSON.stringify(handler.opts) !== '{}') branch += ` ${JSON.stringify(handler.opts)}`
if (handler.meta) {
Reflect.ownKeys(handler.meta).forEach((m, hidx) => {
branch += `\n${noPrefix ? '' : prefix || ''}${endBranch ? indent : branchIndent}`
branch += `• (${m}) ${JSON.stringify(handler.meta[m])}`
})
}
if (flatHandlers.length > 1 && idx !== flatHandlers.length - 1) branch += '\n'
})
} else {
if (pathSeg.children.length > 1) branch += ' (-)'
if (options.method === undefined) {
routes = routes.map(normalizeRoute)
}
if (!noPrefix) prefix = `${prefix || ''}${endBranch ? indent : branchIndent}`
pathSeg.children.forEach((child, idx) => {
const endBranch = idx === pathSeg.children.length - 1
const skipPrefix = (!pathSeg.handlers && pathSeg.children.length === 1)
branch += drawBranch(child, prefix, endBranch, skipPrefix)
routes = routes.map(route => {
route.metaData = getRouteMetaData(route, options)
return route
})
return branch
}
function prettyPrintFlattenedNode (flattenedNode, prefix, tail, opts) {
if (!this.buildPrettyMeta) throw new Error('buildPrettyMeta not defined')
opts.includeMeta = opts.includeMeta || null // array of meta items to display
let paramName = ''
const printHandlers = []
for (const { node, method } of flattenedNode.nodes) {
for (const handler of node.handlerStorage.handlers) {
printHandlers.push({ method, ...handler })
}
if (options.method === undefined) {
routes = mergeSimilarRoutes(routes)
}
if (printHandlers.length) {
printHandlers.forEach((handler, index) => {
let suffix = `(${handler.method || '-'})`
if (Object.keys(handler.constraints).length > 0) {
suffix += ' ' + JSON.stringify(handler.constraints)
}
let name = ''
// find locations of parameters in prefix
const paramIndices = flattenedNode.prefix.split('').map((ch, idx) => ch === ':' ? idx : null).filter(idx => idx !== null)
if (paramIndices.length) {
let prevLoc = 0
paramIndices.forEach((loc, idx) => {
// find parameter in prefix
name += flattenedNode.prefix.slice(prevLoc, loc + 1)
// insert parameters
name += handler.params[handler.params.length - paramIndices.length + idx]
if (idx === paramIndices.length - 1) name += flattenedNode.prefix.slice(loc + 1)
prevLoc = loc + 1
})
} else {
// there are no parameters, return full object
name = flattenedNode.prefix
}
if (index === 0) {
paramName += `${name} ${suffix}`
} else {
paramName += `\n${prefix}${tail ? indent : branchIndent}${name} ${suffix}`
}
if (opts.includeMeta) {
const meta = buildMetaObject.call(this, handler, opts.includeMeta)
Object.keys(meta).forEach((m, hidx) => {
paramName += `\n${prefix || ''}${tail ? indent : branchIndent}`
paramName += `• (${m}) ${JSON.stringify(meta[m])}`
})
}
})
} else {
paramName = flattenedNode.prefix
}
let tree = `${prefix}${tail ? endBranchIndent : midBranchIndent}${paramName}\n`
prefix = `${prefix}${tail ? indent : branchIndent}`
const labels = Object.keys(flattenedNode.children)
for (let i = 0; i < labels.length; i++) {
const child = flattenedNode.children[labels[i]]
tree += prettyPrintFlattenedNode.call(this, child, prefix, i === (labels.length - 1), opts)
}
return tree
return routes.map(serializeRoute).join(`\n${prefix}`)
}
function flattenNode (flattened, node, method) {
if (node.handlerStorage.handlers.length !== 0) {
flattened.nodes.push({ method, node })
}
function buildObjectTree (node, tree, prefix, options) {
if (node.isLeafNode || options.commonPrefix !== false) {
prefix = prefix || '(empty root node)'
tree = tree[prefix] = {}
if (node.parametricChildren && node.parametricChildren[0]) {
if (!flattened.children[':']) {
flattened.children[':'] = {
prefix: ':',
nodes: [],
children: {}
}
if (node.isLeafNode) {
tree[treeDataSymbol] = serializeNode(node, prefix, options)
}
flattenNode(flattened.children[':'], node.parametricChildren[0], method)
}
if (node.wildcardChild) {
if (!flattened.children['*']) {
flattened.children['*'] = {
prefix: '*',
nodes: [],
children: {}
}
}
flattenNode(flattened.children['*'], node.wildcardChild, method)
prefix = ''
}

@@ -279,43 +147,24 @@

for (const child of Object.values(node.staticChildren)) {
// split on the slash separator but use a regex to lookahead and not actually match it, preserving it in the returned string segments
const childPrefixSegments = child.prefix.split(pathRegExp)
let cursor = flattened
let parent
for (const segment of childPrefixSegments) {
parent = cursor
cursor = cursor.children[segment]
if (!cursor) {
cursor = {
prefix: segment,
nodes: [],
children: {}
}
parent.children[segment] = cursor
}
}
flattenNode(cursor, child, method)
buildObjectTree(child, tree, prefix + child.prefix, options)
}
}
}
function compressFlattenedNode (flattenedNode) {
const childKeys = Object.keys(flattenedNode.children)
if (flattenedNode.nodes.length === 0 && childKeys.length === 1) {
const child = flattenedNode.children[childKeys[0]]
if (child.nodes.length <= 1) {
compressFlattenedNode(child)
flattenedNode.nodes = child.nodes
flattenedNode.prefix += child.prefix
flattenedNode.children = child.children
return flattenedNode
if (node.parametricChildren) {
for (const child of Object.values(node.parametricChildren)) {
const childPrefix = Array.from(child.nodePaths).join('|')
buildObjectTree(child, tree, prefix + childPrefix, options)
}
}
for (const key of Object.keys(flattenedNode.children)) {
compressFlattenedNode(flattenedNode.children[key])
if (node.wildcardChild) {
buildObjectTree(node.wildcardChild, tree, '*', options)
}
}
return flattenedNode
function prettyPrintTree (root, options) {
const objectTree = {}
buildObjectTree(root, objectTree, root.prefix, options)
return printObjectTree(objectTree)
}
module.exports = { flattenNode, compressFlattenedNode, prettyPrintFlattenedNode, prettyPrintRoutesArray }
module.exports = { prettyPrintTree }
{
"name": "find-my-way",
"version": "7.5.0",
"version": "7.6.0",
"description": "Crazy fast http radix based router",

@@ -5,0 +5,0 @@ "main": "index.js",

@@ -27,3 +27,3 @@ # find-my-way

- [find(method, path, [constraints])](#findmethod-path-constraints)
- [prettyPrint([{ commonPrefix: false, includeMeta: true || [] }])](#prettyprint-commonprefix-false-includemeta-true---)
- [prettyPrint([{ method: 'GET', commonPrefix: false, includeMeta: true || [] }])](#prettyprint-commonprefix-false-includemeta-true---)
- [reset()](#reset)

@@ -438,3 +438,5 @@ - [routes](#routes)

#### prettyPrint([{ commonPrefix: false, includeMeta: true || [] }])
Prints the representation of the internal radix tree, useful for debugging.
`find-my-way` builds a tree of routes for each HTTP method. If you call the `prettyPrint`
without specifying an HTTP method, it will merge all the trees to one and print it.
The merged tree does't represent the internal router structure. Don't use it for debugging.

@@ -453,19 +455,43 @@ ```js

// │ └── ing (GET)
// │ └── /:param (GET)
// │ └── /
// │ └── :param (GET)
// └── update (PUT)
```
`prettyPrint` accepts an optional setting to use the internal routes array
to render the tree.
If you want to print the internal tree, you can specify the `method` param.
Printed tree will represent the internal router structure. Use it for debugging.
```js
console.log(findMyWay.prettyPrint({ commonPrefix: false }))
// └── / (-)
// ├── test (GET)
// │ └── /hello (GET)
// ├── testing (GET)
// │ └── /:param (GET)
findMyWay.on('GET', '/test', () => {})
findMyWay.on('GET', '/test/hello', () => {})
findMyWay.on('GET', '/testing', () => {})
findMyWay.on('GET', '/testing/:param', () => {})
findMyWay.on('PUT', '/update', () => {})
console.log(findMyWay.prettyPrint({ method: 'GET' }))
// └── /
// └── test (GET)
// ├── /hello (GET)
// └── ing (GET)
// └── /
// └── :param (GET)
console.log(findMyWay.prettyPrint({ method: 'PUT' }))
// └── /
// └── update (PUT)
```
`prettyPrint` accepts an optional setting to print compressed routes. This is useful
when you have a large number of routes with common prefixes. Doesn't represent the
internal router structure. **Don't use it for debugging.**
```js
console.log(findMyWay.prettyPrint({ commonPrefix: false }))
// ├── /test (GET)
// │ ├── /hello (GET)
// │ └── ing (GET)
// │ └── /:param (GET)
// └── /update (PUT)
```
To include a display of the `store` data passed to individual routes, the

@@ -479,3 +505,3 @@ option `includeMeta` may be passed. If set to `true` all items will be

```js
findMyWay.on('GET', '/test', () => {}, { onRequest: () => {}, authIDs => [1,2,3] })
findMyWay.on('GET', '/test', () => {}, { onRequest: () => {}, authIDs: [1, 2, 3] })
findMyWay.on('GET', '/test/hello', () => {}, { token: 'df123-4567' })

@@ -487,20 +513,18 @@ findMyWay.on('GET', '/testing', () => {})

console.log(findMyWay.prettyPrint({ commonPrefix: false, includeMeta: ['onRequest'] }))
// └── /
// ├── test (GET)
// │ • (onRequest) "anonymous()"
// │ ├── /hello (GET)
// │ └── ing (GET)
// │ └── /:param (GET)
// └── update (PUT)
// ├── /test (GET)
// │ • (onRequest) "onRequest()"
// │ ├── /hello (GET)
// │ └── ing (GET)
// │ └── /:param (GET)
// └── /update (PUT)
console.log(findMyWay.prettyPrint({ commonPrefix: true, includeMeta: true }))
// └── / (-)
// ├── test (GET)
// │ • (onRequest) "anonymous()"
// │ • (authIDs) [1,2,3]
// │ └── /hello (GET)
// │ • (token) "df123-4567"
// ├── testing (GET)
// │ └── /:param (GET)
// └── update (PUT)
console.log(findMyWay.prettyPrint({ commonPrefix: false, includeMeta: true }))
// ├── /test (GET)
// │ • (onRequest) "onRequest()"
// │ • (authIDs) [1,2,3]
// │ ├── /hello (GET)
// │ │ • (token) "df123-4567"
// │ └── ing (GET)
// │ └── /:param (GET)
// └── /update (PUT)
```

@@ -507,0 +531,0 @@

@@ -16,4 +16,4 @@ 'use strict'

const tree = findMyWay.prettyPrint()
const expected = `└── /
const expected = `\
└── /
├── test (GET)

@@ -23,3 +23,2 @@ │ └── /hello (GET)

`
t.equal(typeof tree, 'string')

@@ -38,9 +37,38 @@ t.equal(tree, expected)

const tree = findMyWay.prettyPrint()
const expected = `└── /
const expected = `\
└── /
├── test (GET)
│ └── /:hello (GET)
└── hello/:world (GET)
│ └── /
│ └── :hello (GET)
└── hello/
└── :world (GET)
`
t.equal(typeof tree, 'string')
t.equal(tree, expected)
})
test('pretty print - parametric routes', t => {
t.plan(2)
const findMyWay = FindMyWay()
findMyWay.on('GET', '/static', () => {})
findMyWay.on('GET', '/static/:param/suffix1', () => {})
findMyWay.on('GET', '/static/:param(123)/suffix2', () => {})
findMyWay.on('GET', '/static/:param(123).end/suffix3', () => {})
findMyWay.on('GET', '/static/:param1(123).:param2(456)/suffix4', () => {})
const tree = findMyWay.prettyPrint()
const expected = `\
└── /
└── static (GET)
└── /
├── :param(123).end
│ └── /suffix3 (GET)
├── :param(123)
│ └── /suffix2 (GET)
├── :param1(123).:param2(456)
│ └── /suffix4 (GET)
└── :param
└── /suffix1 (GET)
`
t.equal(typeof tree, 'string')

@@ -50,2 +78,24 @@ t.equal(tree, expected)

test('pretty print - parametric routes', t => {
t.plan(2)
const findMyWay = FindMyWay()
findMyWay.on('GET', '/static', () => {})
findMyWay.on('GET', '/static/:param/suffix1', () => {})
findMyWay.on('GET', '/static/:param(123)/suffix2', () => {})
findMyWay.on('GET', '/static/:param(123).end/suffix3', () => {})
findMyWay.on('GET', '/static/:param1(123).:param2(456)/suffix4', () => {})
const tree = findMyWay.prettyPrint({ commonPrefix: false })
const expected = `\
└── /static (GET)
├── /:param(123).end/suffix3 (GET)
├── /:param(123)/suffix2 (GET)
├── /:param1(123).:param2(456)/suffix4 (GET)
└── /:param/suffix1 (GET)
`
t.equal(typeof tree, 'string')
t.equal(tree, expected)
})
test('pretty print - mixed parametric routes', t => {

@@ -61,10 +111,9 @@ t.plan(2)

const tree = findMyWay.prettyPrint()
const expected = `└── /test (GET)
└── /
└── :hello (GET)
:hello (POST)
└── /world (GET)
const expected = `\
└── /
└── test (GET)
└── /
└── :hello (GET, POST)
└── /world (GET)
`
t.equal(typeof tree, 'string')

@@ -83,9 +132,10 @@ t.equal(tree, expected)

const tree = findMyWay.prettyPrint()
const expected = `└── /
const expected = `\
└── /
├── test (GET)
│ └── /* (GET)
└── hello/* (GET)
│ └── /
│ └── * (GET)
└── hello/
└── * (GET)
`
t.equal(typeof tree, 'string')

@@ -105,11 +155,10 @@ t.equal(tree, expected)

const tree = findMyWay.prettyPrint()
const expected = `└── /test (GET)
└── /hello
├── /
│ └── :id (GET)
│ :id (POST)
└── world (GET)
const expected = `\
└── /
└── test (GET)
└── /hello
├── /
│ └── :id (GET, POST)
└── world (GET)
`
t.equal(typeof tree, 'string')

@@ -130,10 +179,32 @@ t.equal(tree, expected)

const tree = findMyWay.prettyPrint()
const expected = `\
└── /
└── test (GET)
test (GET) {"host":"auth.fastify.io"}
└── /
└── :hello (GET)
:hello (GET) {"version":"1.1.2"}
:hello (GET) {"version":"2.0.0"}
`
t.equal(typeof tree, 'string')
t.equal(tree, expected)
})
const expected = `└── /test (GET)
/test (GET) {"host":"auth.fastify.io"}
└── /:hello (GET)
/:hello (GET) {"version":"1.1.2"}
/:hello (GET) {"version":"2.0.0"}
test('pretty print - multiple parameters are drawn appropriately', t => {
t.plan(2)
const findMyWay = FindMyWay()
findMyWay.on('GET', '/test', () => {})
// routes with a nested parameter (i.e. no handler for the /:param) were breaking the display
findMyWay.on('GET', '/test/:hello/there/:ladies', () => {})
findMyWay.on('GET', '/test/:hello/there/:ladies/and/:gents', () => {})
findMyWay.on('GET', '/test/are/:you/:ready/to/:rock', () => {})
const tree = findMyWay.prettyPrint({ commonPrefix: false })
const expected = `\
└── /test (GET)
├── /are/:you/:ready/to/:rock (GET)
└── /:hello/there/:ladies (GET)
└── /and/:gents (GET)
`
t.equal(typeof tree, 'string')

@@ -153,11 +224,9 @@ t.equal(tree, expected)

const tree = findMyWay.prettyPrint()
const expected = `└── /test (GET)
└── /
├── :hello/there/:ladies (GET)
│ └── /and/:gents (GET)
└── are/:you/:ready/to/:rock (GET)
const tree = findMyWay.prettyPrint({ commonPrefix: false })
const expected = `\
└── /test (GET)
├── /are/:you/:ready/to/:rock (GET)
└── /:hello/there/:ladies (GET)
└── /and/:gents (GET)
`
t.equal(typeof tree, 'string')

@@ -181,21 +250,24 @@ t.equal(tree, expected)

const radixExpected = `└── /
const radixExpected = `\
└── /
├── test (GET)
│ ├── /hello (GET)
│ └── ing (GET)
│ └── /:param (GET)
│ └── /
│ └── :param (GET)
└── update (PUT)
`
const arrayExpected = `└── / (-)
├── test (GET)
│ └── /hello (GET)
├── testing (GET)
│ └── /:param (GET)
└── update (PUT)
const arrayExpected = `\
├── /test (GET)
│ ├── /hello (GET)
│ └── ing (GET)
│ └── /:param (GET)
└── /update (PUT)
`
t.equal(typeof radixTree, 'string')
t.equal(radixTree, radixExpected)
t.equal(typeof arrayTree, 'string')
t.equal(radixTree, radixExpected)
t.equal(arrayTree, arrayExpected)

@@ -216,10 +288,9 @@ })

const arrayTree = findMyWay.prettyPrint({ commonPrefix: false })
const arrayExpected = `├── * (OPTIONS)
└── / (-)
├── test/hello (GET)
├── testing (GET)
│ └── /:param (GET)
└── update (PUT)
const arrayExpected = `\
├── /test/hello (GET)
├── /testing (GET)
│ └── /:param (GET)
├── /update (PUT)
└── * (OPTIONS)
`
t.equal(typeof arrayTree, 'string')

@@ -229,2 +300,29 @@ t.equal(arrayTree, arrayExpected)

test('pretty print commonPrefix - handle wildcard root', t => {
t.plan(2)
const findMyWay = FindMyWay()
findMyWay.on('GET', '*', () => {})
findMyWay.on('GET', '/test/hello', () => {})
findMyWay.on('GET', '/testing', () => {})
findMyWay.on('GET', '/testing/:param', () => {})
findMyWay.on('PUT', '/update', () => {})
const radixTree = findMyWay.prettyPrint()
const radixExpected = `\
└── (empty root node)
├── /
│ ├── test
│ │ ├── /hello (GET)
│ │ └── ing (GET)
│ │ └── /
│ │ └── :param (GET)
│ └── update (PUT)
└── * (GET)
`
t.equal(typeof radixTree, 'string')
t.equal(radixTree, radixExpected)
})
test('pretty print commonPrefix - handle constrained routes', t => {

@@ -243,8 +341,8 @@ t.plan(2)

const arrayTree = findMyWay.prettyPrint({ commonPrefix: false })
const arrayExpected = `└── / (-)
└── test (GET)
test (GET) {"host":"auth.fastify.io"}
└── /:hello (GET, PUT)
/:hello (GET) {"version":"1.1.2"}
/:hello (GET) {"version":"2.0.0"}
const arrayExpected = `\
└── /test (GET)
/test (GET) {"host":"auth.fastify.io"}
└── /:hello (GET, PUT)
/:hello (GET) {"version":"1.1.2"}
/:hello (GET) {"version":"2.0.0"}
`

@@ -255,2 +353,42 @@ t.equal(typeof arrayTree, 'string')

test('pretty print commonPrefix - handle method constraint', t => {
t.plan(2)
const findMyWay = FindMyWay()
findMyWay.addConstraintStrategy({
name: 'method',
storage: function () {
const handlers = {}
return {
get: (type) => { return handlers[type] || null },
set: (type, store) => { handlers[type] = store }
}
},
deriveConstraint: (req) => req.headers['x-method'],
mustMatchWhenDerived: true
})
findMyWay.on('GET', '/test', () => {})
findMyWay.on('GET', '/test', { constraints: { method: 'foo' } }, () => {})
findMyWay.on('GET', '/test/:hello', () => {})
findMyWay.on('PUT', '/test/:hello', () => {})
findMyWay.on('GET', '/test/:hello', { constraints: { method: 'bar' } }, () => {})
findMyWay.on('GET', '/test/:hello', { constraints: { method: 'baz' } }, () => {})
const arrayTree = findMyWay.prettyPrint({
commonPrefix: false,
methodConstraintName: 'methodOverride'
})
const arrayExpected = `\
└── /test (GET)
/test (GET) {"method":"foo"}
└── /:hello (GET, PUT)
/:hello (GET) {"method":"bar"}
/:hello (GET) {"method":"baz"}
`
t.equal(typeof arrayTree, 'string')
t.equal(arrayTree, arrayExpected)
})
test('pretty print includeMeta - commonPrefix: true', t => {

@@ -280,30 +418,5 @@ t.plan(6)

const radixTree = findMyWay.prettyPrint({ commonPrefix: true, includeMeta: true })
const radixTreeExpected = `└── /
├── test (GET)
│ • (onRequest) ["anonymous()","namedFunction()"]
│ • (onTimeout) ["anonymous()"]
│ • (genericMeta) "meta"
│ • (mixedMeta) ["mixed items",{"an":"object"}]
│ • (objectMeta) {"one":"1","two":2}
│ • (functionMeta) "namedFunction()"
│ • (Symbol(symbolKey)) "Symbol(symbolValue)"
│ test (GET) {"host":"auth.fastify.io"}
│ • (onRequest) ["anonymous()","namedFunction()"]
│ • (onTimeout) ["anonymous()"]
│ • (genericMeta) "meta"
│ • (mixedMeta) ["mixed items",{"an":"object"}]
│ • (objectMeta) {"one":"1","two":2}
│ • (functionMeta) "namedFunction()"
│ • (Symbol(symbolKey)) "Symbol(symbolValue)"
│ ├── ing/:hello (GET)
│ │ • (onRequest) ["anonymous()","namedFunction()"]
│ │ • (onTimeout) ["anonymous()"]
│ │ • (genericMeta) "meta"
│ │ • (mixedMeta) ["mixed items",{"an":"object"}]
│ │ • (objectMeta) {"one":"1","two":2}
│ │ • (functionMeta) "namedFunction()"
│ │ • (Symbol(symbolKey)) "Symbol(symbolValue)"
│ └── /:hello (GET) {"version":"1.1.2"}
│ /:hello (GET) {"version":"2.0.0"}
└── tested/:hello (PUT)
const radixTreeExpected = `\
└── /
└── test (GET)
• (onRequest) ["anonymous()","namedFunction()"]

@@ -316,31 +429,66 @@ • (onTimeout) ["anonymous()"]

• (Symbol(symbolKey)) "Symbol(symbolValue)"
test (GET) {"host":"auth.fastify.io"}
• (onRequest) ["anonymous()","namedFunction()"]
• (onTimeout) ["anonymous()"]
• (genericMeta) "meta"
• (mixedMeta) ["mixed items",{"an":"object"}]
• (objectMeta) {"one":"1","two":2}
• (functionMeta) "namedFunction()"
• (Symbol(symbolKey)) "Symbol(symbolValue)"
├── ing/
│ └── :hello (GET)
│ • (onRequest) ["anonymous()","namedFunction()"]
│ • (onTimeout) ["anonymous()"]
│ • (genericMeta) "meta"
│ • (mixedMeta) ["mixed items",{"an":"object"}]
│ • (objectMeta) {"one":"1","two":2}
│ • (functionMeta) "namedFunction()"
│ • (Symbol(symbolKey)) "Symbol(symbolValue)"
├── ed/
│ └── :hello (PUT)
│ • (onRequest) ["anonymous()","namedFunction()"]
│ • (onTimeout) ["anonymous()"]
│ • (genericMeta) "meta"
│ • (mixedMeta) ["mixed items",{"an":"object"}]
│ • (objectMeta) {"one":"1","two":2}
│ • (functionMeta) "namedFunction()"
│ • (Symbol(symbolKey)) "Symbol(symbolValue)"
└── /
└── :hello (GET) {"version":"1.1.2"}
:hello (GET) {"version":"2.0.0"}
`
const radixTreeSpecific = findMyWay.prettyPrint({ commonPrefix: true, includeMeta: ['onTimeout', 'objectMeta', 'nonExistent'] })
const radixTreeSpecificExpected = `└── /
├── test (GET)
│ • (onTimeout) ["anonymous()"]
│ • (objectMeta) {"one":"1","two":2}
│ test (GET) {"host":"auth.fastify.io"}
│ • (onTimeout) ["anonymous()"]
│ • (objectMeta) {"one":"1","two":2}
│ ├── ing/:hello (GET)
│ │ • (onTimeout) ["anonymous()"]
│ │ • (objectMeta) {"one":"1","two":2}
│ └── /:hello (GET) {"version":"1.1.2"}
│ /:hello (GET) {"version":"2.0.0"}
└── tested/:hello (PUT)
const radixTreeSpecificExpected = `\
└── /
└── test (GET)
• (onTimeout) ["anonymous()"]
• (objectMeta) {"one":"1","two":2}
test (GET) {"host":"auth.fastify.io"}
• (onTimeout) ["anonymous()"]
• (objectMeta) {"one":"1","two":2}
├── ing/
│ └── :hello (GET)
│ • (onTimeout) ["anonymous()"]
│ • (objectMeta) {"one":"1","two":2}
├── ed/
│ └── :hello (PUT)
│ • (onTimeout) ["anonymous()"]
│ • (objectMeta) {"one":"1","two":2}
└── /
└── :hello (GET) {"version":"1.1.2"}
:hello (GET) {"version":"2.0.0"}
`
const radixTreeNoMeta = findMyWay.prettyPrint({ commonPrefix: true, includeMeta: false })
const radixTreeNoMetaExpected = `└── /
├── test (GET)
│ test (GET) {"host":"auth.fastify.io"}
│ ├── ing/:hello (GET)
│ └── /:hello (GET) {"version":"1.1.2"}
│ /:hello (GET) {"version":"2.0.0"}
└── tested/:hello (PUT)
const radixTreeNoMetaExpected = `\
└── /
└── test (GET)
test (GET) {"host":"auth.fastify.io"}
├── ing/
│ └── :hello (GET)
├── ed/
│ └── :hello (PUT)
└── /
└── :hello (GET) {"version":"1.1.2"}
:hello (GET) {"version":"2.0.0"}
`
t.equal(typeof radixTree, 'string')

@@ -364,2 +512,4 @@ t.equal(radixTree, radixTreeExpected)

onTimeout: [() => {}],
onError: null,
onRegister: undefined,
genericMeta: 'meta',

@@ -375,4 +525,4 @@ mixedMeta: ['mixed items', { an: 'object' }],

findMyWay.on('GET', '/test', { constraints: { host: 'auth.fastify.io' } }, () => {}, store)
findMyWay.on('GET', '/test/:hello', () => {}, store)
findMyWay.on('PUT', '/test/:hello', () => {}, store)
findMyWay.on('GET', '/testing/:hello', () => {}, store)
findMyWay.on('PUT', '/tested/:hello', () => {}, store)
findMyWay.on('GET', '/test/:hello', { constraints: { version: '1.1.2' } }, () => {})

@@ -382,52 +532,63 @@ findMyWay.on('GET', '/test/:hello', { constraints: { version: '2.0.0' } }, () => {})

const arrayTree = findMyWay.prettyPrint({ commonPrefix: false, includeMeta: true })
const arrayExpected = `└── / (-)
└── test (GET)
• (onRequest) ["anonymous()","namedFunction()"]
• (onTimeout) ["anonymous()"]
• (genericMeta) "meta"
• (mixedMeta) ["mixed items",{"an":"object"}]
• (objectMeta) {"one":"1","two":2}
• (functionMeta) "namedFunction()"
• (Symbol(symbolKey)) "Symbol(symbolValue)"
test (GET) {"host":"auth.fastify.io"}
• (onRequest) ["anonymous()","namedFunction()"]
• (onTimeout) ["anonymous()"]
• (genericMeta) "meta"
• (mixedMeta) ["mixed items",{"an":"object"}]
• (objectMeta) {"one":"1","two":2}
• (functionMeta) "namedFunction()"
• (Symbol(symbolKey)) "Symbol(symbolValue)"
└── /:hello (GET, PUT)
• (onRequest) ["anonymous()","namedFunction()"]
• (onTimeout) ["anonymous()"]
• (genericMeta) "meta"
• (mixedMeta) ["mixed items",{"an":"object"}]
• (objectMeta) {"one":"1","two":2}
• (functionMeta) "namedFunction()"
• (Symbol(symbolKey)) "Symbol(symbolValue)"
/:hello (GET) {"version":"1.1.2"}
/:hello (GET) {"version":"2.0.0"}
const arrayExpected = `\
└── /test (GET)
• (onRequest) ["anonymous()","namedFunction()"]
• (onTimeout) ["anonymous()"]
• (genericMeta) "meta"
• (mixedMeta) ["mixed items",{"an":"object"}]
• (objectMeta) {"one":"1","two":2}
• (functionMeta) "namedFunction()"
• (Symbol(symbolKey)) "Symbol(symbolValue)"
/test (GET) {"host":"auth.fastify.io"}
• (onRequest) ["anonymous()","namedFunction()"]
• (onTimeout) ["anonymous()"]
• (genericMeta) "meta"
• (mixedMeta) ["mixed items",{"an":"object"}]
• (objectMeta) {"one":"1","two":2}
• (functionMeta) "namedFunction()"
• (Symbol(symbolKey)) "Symbol(symbolValue)"
├── ing/:hello (GET)
│ • (onRequest) ["anonymous()","namedFunction()"]
│ • (onTimeout) ["anonymous()"]
│ • (genericMeta) "meta"
│ • (mixedMeta) ["mixed items",{"an":"object"}]
│ • (objectMeta) {"one":"1","two":2}
│ • (functionMeta) "namedFunction()"
│ • (Symbol(symbolKey)) "Symbol(symbolValue)"
├── ed/:hello (PUT)
│ • (onRequest) ["anonymous()","namedFunction()"]
│ • (onTimeout) ["anonymous()"]
│ • (genericMeta) "meta"
│ • (mixedMeta) ["mixed items",{"an":"object"}]
│ • (objectMeta) {"one":"1","two":2}
│ • (functionMeta) "namedFunction()"
│ • (Symbol(symbolKey)) "Symbol(symbolValue)"
└── /:hello (GET) {"version":"1.1.2"}
/:hello (GET) {"version":"2.0.0"}
`
const arraySpecific = findMyWay.prettyPrint({ commonPrefix: false, includeMeta: ['onRequest', 'mixedMeta', 'nonExistent'] })
const arraySpecificExpected = `└── / (-)
└── test (GET)
• (onRequest) ["anonymous()","namedFunction()"]
• (mixedMeta) ["mixed items",{"an":"object"}]
test (GET) {"host":"auth.fastify.io"}
• (onRequest) ["anonymous()","namedFunction()"]
• (mixedMeta) ["mixed items",{"an":"object"}]
└── /:hello (GET, PUT)
• (onRequest) ["anonymous()","namedFunction()"]
• (mixedMeta) ["mixed items",{"an":"object"}]
/:hello (GET) {"version":"1.1.2"}
/:hello (GET) {"version":"2.0.0"}
const arraySpecificExpected = `\
└── /test (GET)
• (onRequest) ["anonymous()","namedFunction()"]
• (mixedMeta) ["mixed items",{"an":"object"}]
/test (GET) {"host":"auth.fastify.io"}
• (onRequest) ["anonymous()","namedFunction()"]
• (mixedMeta) ["mixed items",{"an":"object"}]
├── ing/:hello (GET)
│ • (onRequest) ["anonymous()","namedFunction()"]
│ • (mixedMeta) ["mixed items",{"an":"object"}]
├── ed/:hello (PUT)
│ • (onRequest) ["anonymous()","namedFunction()"]
│ • (mixedMeta) ["mixed items",{"an":"object"}]
└── /:hello (GET) {"version":"1.1.2"}
/:hello (GET) {"version":"2.0.0"}
`
const arrayNoMeta = findMyWay.prettyPrint({ commonPrefix: false, includeMeta: false })
const arrayNoMetaExpected = `└── / (-)
└── test (GET)
test (GET) {"host":"auth.fastify.io"}
└── /:hello (GET, PUT)
/:hello (GET) {"version":"1.1.2"}
/:hello (GET) {"version":"2.0.0"}
const arrayNoMetaExpected = `\
└── /test (GET)
/test (GET) {"host":"auth.fastify.io"}
├── ing/:hello (GET)
├── ed/:hello (PUT)
└── /:hello (GET) {"version":"1.1.2"}
/:hello (GET) {"version":"2.0.0"}
`

@@ -450,5 +611,3 @@

buildPrettyMeta: route => {
// routes from radix tree do not contain a path element
// returns 'no path' to avoid an undefined value
return { metaKey: route.path || 'no path' }
return { metaKey: route.method === 'PUT' ? 'Hide PUT route path' : route.path }
}

@@ -472,2 +631,3 @@ })

findMyWay.on('PUT', '/test/:hello', () => {}, store)
findMyWay.on('POST', '/test/:hello', () => {}, store)
findMyWay.on('GET', '/test/:hello', { constraints: { version: '1.1.2' } }, () => {})

@@ -477,3 +637,19 @@ findMyWay.on('GET', '/test/:hello', { constraints: { version: '2.0.0' } }, () => {})

const arrayTree = findMyWay.prettyPrint({ commonPrefix: false, includeMeta: true })
const arrayExpected = `└── / (-)
const arrayExpected = `\
└── /test (GET)
• (metaKey) "/test"
/test (GET) {"host":"auth.fastify.io"}
• (metaKey) "/test"
└── /:hello (GET, POST)
• (metaKey) "/test/:hello"
/:hello (PUT)
• (metaKey) "Hide PUT route path"
/:hello (GET) {"version":"1.1.2"}
• (metaKey) "/test/:hello"
/:hello (GET) {"version":"2.0.0"}
• (metaKey) "/test/:hello"
`
const radixTree = findMyWay.prettyPrint({ includeMeta: true })
const radixExpected = `\
└── /
└── test (GET)

@@ -483,24 +659,12 @@ • (metaKey) "/test"

• (metaKey) "/test"
└── /:hello (GET, PUT)
• (metaKey) "/test/:hello"
/:hello (GET) {"version":"1.1.2"}
• (metaKey) "/test/:hello"
/:hello (GET) {"version":"2.0.0"}
• (metaKey) "/test/:hello"
└── /
└── :hello (GET, POST)
• (metaKey) "/test/:hello"
:hello (PUT)
• (metaKey) "Hide PUT route path"
:hello (GET) {"version":"1.1.2"}
• (metaKey) "/test/:hello"
:hello (GET) {"version":"2.0.0"}
• (metaKey) "/test/:hello"
`
const radixTree = findMyWay.prettyPrint({ includeMeta: true })
const radixExpected = `└── /test (GET)
• (metaKey) "no path"
/test (GET) {"host":"auth.fastify.io"}
• (metaKey) "no path"
└── /
└── :hello (GET)
• (metaKey) "no path"
:hello (GET) {"version":"1.1.2"}
• (metaKey) "no path"
:hello (GET) {"version":"2.0.0"}
• (metaKey) "no path"
:hello (PUT)
• (metaKey) "no path"
`
t.equal(typeof arrayTree, 'string')

@@ -512,1 +676,19 @@ t.equal(arrayTree, arrayExpected)

})
test('pretty print - print all methods', t => {
t.plan(2)
const findMyWay = FindMyWay()
findMyWay.all('/test', () => {})
const tree = findMyWay.prettyPrint()
const expected = `\
└── /
└── test (ACL, BIND, CHECKOUT, CONNECT, COPY, DELETE, GET, HEAD, LINK, LOCK, \
M-SEARCH, MERGE, MKACTIVITY, MKCALENDAR, MKCOL, MOVE, NOTIFY, OPTIONS, PATCH, \
POST, PROPFIND, PROPPATCH, PURGE, PUT, REBIND, REPORT, SEARCH, SOURCE, SUBSCRIBE, \
TRACE, UNBIND, UNLINK, UNLOCK, UNSUBSCRIBE)
`
t.equal(typeof tree, 'string')
t.equal(tree, expected)
})

@@ -24,3 +24,3 @@ 'use strict'

findMyWay.routes.map((route, idx) => {
t.same(route, {
t.match(route, {
method: 'GET',

@@ -27,0 +27,0 @@ path: '/test-route-' + idx,

@@ -60,2 +60,3 @@ import { expectType } from 'tsd'

expectType<string>(router.prettyPrint())
expectType<string>(router.prettyPrint({ method: 'GET' }))
expectType<string>(router.prettyPrint({ commonPrefix: false }))

@@ -62,0 +63,0 @@ expectType<string>(router.prettyPrint({ commonPrefix: true }))

SocketSocket SOC 2 Logo

Product

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

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc