Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pretty print improvements #144

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 50 additions & 29 deletions node.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

const assert = require('assert')
const http = require('http')
const archy = require('archy')
const Handlers = buildHandlers()

const types = {
Expand Down Expand Up @@ -189,41 +190,61 @@ Node.prototype.getVersionHandler = function (version, method) {
return handlers === null ? handlers : handlers[method]
}

Node.prototype.prettyPrint = function (prefix, tail) {
var paramName = ''
var handlers = this.handlers || {}
var methods = Object.keys(handlers).filter(method => handlers[method] && handlers[method].handler)
Node.prototype.prettyPrint = function () {
const tree = { ...this }
traverseTree(tree)

if (this.prefix === ':') {
methods.forEach((method, index) => {
var params = this.handlers[method].params
var param = params[params.length - 1]
if (methods.length > 1) {
if (index === 0) {
paramName += param + ` (${method})\n`
return
// Moneky patch needed for the routes that have multiple handlers
return archy(tree)
.replace(/─┬/g, '')
.replace(/│ ├── & /g, '├── ')
.replace(/│ └── & /g, '├── ')
.replace(/ & /g, ' ')
}

function traverseTree (node) {
// Remove the keys with null value, end up with [ ['GET', { handler }] ]
const routes = Object.entries(node.handlers).filter(object => object[1] !== null)

// Map to label and nodes, this format is needed by archy
node.nodes = mapChildredToArray(node.children)
if (routes.length === 0) {
node.label = node.prefix
} else if (routes.length === 1) {
const currentRoute = routes[0]
if (node.prefix === ':') {
node.label = `:${currentRoute[1].params.join(':')} (${currentRoute[0]}) ${currentRoute[1].handler.name}`
} else {
node.label = `${node.prefix} (${currentRoute[0]}) ${currentRoute[1].handler.name}`
}
} else {
node.label = archy({
label: node.prefix,
nodes: routes.map(route => {
let label
// The & is to later find this branches and fix them
if (node.prefix === ':') {
label = `& :${route[1].params.join()} (${route[0]}) ${route[1].handler.name}`
} else {
label = `& (${route[0]}) ${route[1].handler.name}`
}
paramName += prefix + ' :' + param + ` (${method})`
paramName += (index === methods.length - 1 ? '' : '\n')
} else {
paramName = params[params.length - 1] + ` (${method})`
}

return { label: label }
})
})
} else if (methods.length) {
paramName = ` (${methods.join('|')})`
}

var tree = `${prefix}${tail ? '└── ' : '├── '}${this.prefix}${paramName}\n`

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

function mapChildredToArray (children) {
return Object.keys(children).map(i => children[i])
}

function buildHandlers (handlers) {
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
"typescript": "^3.3.3"
},
"dependencies": {
"archy": "^1.0.0",
"fast-decode-uri-component": "^1.0.0",
"safe-regex2": "^2.0.0",
"semver-store": "^0.3.0"
Expand Down
106 changes: 77 additions & 29 deletions test/pretty-print.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,10 @@ test('pretty print - static routes', t => {

const tree = findMyWay.prettyPrint()

const expected = `└── /
├── test (GET)
└── /hello (GET)
└── hello/world (GET)
const expected = `/
test (GET)
└── /hello (GET)
└── hello/world (GET)
`

t.is(typeof tree, 'string')
Expand All @@ -34,12 +34,12 @@ test('pretty print - parametric routes', t => {

const tree = findMyWay.prettyPrint()

const expected = `└── /
├── test (GET)
│ └── /
└── :hello (GET)
└── hello/
└── :world (GET)
const expected = `/
test (GET)
│ └ /
│ └── :hello (GET)
hello/
└── :world (GET)
`

t.is(typeof tree, 'string')
Expand All @@ -57,12 +57,14 @@ test('pretty print - mixed parametric routes', t => {

const tree = findMyWay.prettyPrint()

const expected = `└── /
└── test (GET)
└── /
└── :hello (GET)
:hello (POST)
└── /world (GET)
const expected = `/
└ test (GET)
└ /
└ :
├── :hello (GET)
├── :hello (POST)
└── /world (GET)
`

t.is(typeof tree, 'string')
Expand All @@ -79,12 +81,12 @@ test('pretty print - wildcard routes', t => {

const tree = findMyWay.prettyPrint()

const expected = `└── /
├── test (GET)
│ └── /
└── * (GET)
└── hello/
└── * (GET)
const expected = `/
test (GET)
│ └ /
│ └── * (GET)
hello/
└── * (GET)
`

t.is(typeof tree, 'string')
Expand All @@ -102,13 +104,59 @@ test('pretty print - parametric routes with same parent and followed by a static

const tree = findMyWay.prettyPrint()

const expected = `└── /
└── test (GET)
└── /hello
├── /
│ └── :id (GET)
│ :id (POST)
└── world (GET)
const expected = `/
└ test (GET)
└ /hello
├ /
│ └── :
│ ├── :id (GET)
│ └── :id (POST)
└── world (GET)
`

t.is(typeof tree, 'string')
t.equal(tree, expected)
})

test('pretty print - handle multiple handlers in parametric route properly', t => {
t.plan(2)

const findMyWay = FindMyWay()
findMyWay.on('GET', '/:a', () => {})
findMyWay.on('POST', '/:b', () => {})
findMyWay.on('POST', '/c', () => {})

const tree = findMyWay.prettyPrint()

const expected = `/
├── :
│ ├── :a (GET)
│ └── :b (POST)
└── c (POST)
`

t.is(typeof tree, 'string')
t.equal(tree, expected)
})

test('pretty print - log handler`s name', t => {
t.plan(2)

const findMyWay = FindMyWay()
findMyWay.on('GET', '/:a', function functionA () {})
findMyWay.on('POST', '/:b', function functionB () {})
findMyWay.on('POST', '/c', function functionC () {})

const tree = findMyWay.prettyPrint()

const expected = `/
├── :
│ ├── :a (GET) functionA
│ └── :b (POST) functionB
└── c (POST) functionC
`

t.is(typeof tree, 'string')
Expand Down