From 3622f0eef369fec2d6ef1c8bdbdf1794bd522b6c Mon Sep 17 00:00:00 2001 From: Elian Cordoba Date: Wed, 29 Jan 2020 16:21:50 -0300 Subject: [PATCH 1/5] Initial approach --- node.js | 57 ++++++++++++++++++++++++++++++++++++++++++++++++++++ package.json | 1 + 2 files changed, 58 insertions(+) diff --git a/node.js b/node.js index 59811045..ce32ce37 100644 --- a/node.js +++ b/node.js @@ -2,6 +2,7 @@ const assert = require('assert') const http = require('http') +const archy = require('archy') const Handlers = buildHandlers() const types = { @@ -189,6 +190,62 @@ Node.prototype.getVersionHandler = function (version, method) { return handlers === null ? handlers : handlers[method] } +Node.prototype.prettyPrintNew = function () { + const tree = { ...this } + traverseTree(tree) + + // Moneky patch needed for the routes that have multiple handlers + return archy(tree) + .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]})` + } else { + node.label = `${node.prefix} (${currentRoute[0]})` + } + } 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]})` + } else { + label = `&(${route[0]})` + } + + return { label: label } + }) + }) + } + + 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]]) + } + } +} + +function mapChildredToArray (children) { + return Object.keys(children).map(i => children[i]) +} + Node.prototype.prettyPrint = function (prefix, tail) { var paramName = '' var handlers = this.handlers || {} diff --git a/package.json b/package.json index fe0621fe..2c0870bb 100644 --- a/package.json +++ b/package.json @@ -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" From d0eee573fec9713fed29f1a4544ecc352ad626ec Mon Sep 17 00:00:00 2001 From: Elian Cordoba Date: Wed, 29 Jan 2020 16:35:06 -0300 Subject: [PATCH 2/5] Log handler name --- node.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/node.js b/node.js index ce32ce37..f7157cb0 100644 --- a/node.js +++ b/node.js @@ -212,9 +212,9 @@ function traverseTree (node) { } else if (routes.length === 1) { const currentRoute = routes[0] if (node.prefix === ':') { - node.label = `:${currentRoute[1].params.join(':')} (${currentRoute[0]})` + node.label = `:${currentRoute[1].params.join(':')} (${currentRoute[0]}) ${currentRoute[1].handler.name}` } else { - node.label = `${node.prefix} (${currentRoute[0]})` + node.label = `${node.prefix} (${currentRoute[0]}) ${currentRoute[1].handler.name}` } } else { node.label = archy({ @@ -223,9 +223,9 @@ function traverseTree (node) { let label // The & is to later find this branches and fix them if (node.prefix === ':') { - label = `&:${route[1].params.join()} (${route[0]})` + label = `&:${route[1].params.join()} (${route[0]}) ${route[0][1].handler.name}` } else { - label = `&(${route[0]})` + label = `&(${route[0]}) ${route[0][1].handler.name}` } return { label: label } From 9d483390f674b685cd648c706c4666759be9dce8 Mon Sep 17 00:00:00 2001 From: Elian Cordoba Date: Wed, 29 Jan 2020 16:43:46 -0300 Subject: [PATCH 3/5] Added test to cover bug with multiple paramters in same route followed by another route --- test/pretty-print.test.js | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/test/pretty-print.test.js b/test/pretty-print.test.js index dd7dd82c..fa11cbdf 100644 --- a/test/pretty-print.test.js +++ b/test/pretty-print.test.js @@ -114,3 +114,24 @@ test('pretty print - parametric routes with same parent and followed by a static 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) +}) From 06e7b29e6d702b64c40390188e850446b0bab436 Mon Sep 17 00:00:00 2001 From: Elian Cordoba Date: Wed, 29 Jan 2020 16:44:55 -0300 Subject: [PATCH 4/5] Log handler names and deleted old method --- node.js | 48 ++++++------------------------------------------ 1 file changed, 6 insertions(+), 42 deletions(-) diff --git a/node.js b/node.js index f7157cb0..5b307894 100644 --- a/node.js +++ b/node.js @@ -190,15 +190,16 @@ Node.prototype.getVersionHandler = function (version, method) { return handlers === null ? handlers : handlers[method] } -Node.prototype.prettyPrintNew = function () { +Node.prototype.prettyPrint = function () { const tree = { ...this } traverseTree(tree) // Moneky patch needed for the routes that have multiple handlers return archy(tree) .replace(/─┬/g, '') - .replace(/│ ├── &/g, '├── ') - .replace(/│ └── &/g, '├── ') + .replace(/│ ├── & /g, '├── ') + .replace(/│ └── & /g, '├── ') + .replace(/ & /g, ' ') } function traverseTree (node) { @@ -223,9 +224,9 @@ function traverseTree (node) { let label // The & is to later find this branches and fix them if (node.prefix === ':') { - label = `&:${route[1].params.join()} (${route[0]}) ${route[0][1].handler.name}` + label = `& :${route[1].params.join()} (${route[0]}) ${route[1].handler.name}` } else { - label = `&(${route[0]}) ${route[0][1].handler.name}` + label = `& (${route[0]}) ${route[1].handler.name}` } return { label: label } @@ -246,43 +247,6 @@ function mapChildredToArray (children) { return Object.keys(children).map(i => children[i]) } -Node.prototype.prettyPrint = function (prefix, tail) { - var paramName = '' - var handlers = this.handlers || {} - var methods = Object.keys(handlers).filter(method => handlers[method] && handlers[method].handler) - - 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 - } - paramName += prefix + ' :' + param + ` (${method})` - paramName += (index === methods.length - 1 ? '' : '\n') - } else { - paramName = params[params.length - 1] + ` (${method})` - } - }) - } 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) - } - return tree -} - function buildHandlers (handlers) { var code = `handlers = handlers || {} ` From aaffaebb34fbe09a55db79abe12ab4756e52327d Mon Sep 17 00:00:00 2001 From: Elian Cordoba Date: Wed, 29 Jan 2020 17:05:02 -0300 Subject: [PATCH 5/5] Updated pretty print tests and added new one to verify handler's name --- test/pretty-print.test.js | 95 +++++++++++++++++++++++++-------------- 1 file changed, 61 insertions(+), 34 deletions(-) diff --git a/test/pretty-print.test.js b/test/pretty-print.test.js index fa11cbdf..8d49d782 100644 --- a/test/pretty-print.test.js +++ b/test/pretty-print.test.js @@ -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') @@ -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') @@ -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') @@ -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') @@ -102,13 +104,15 @@ 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') @@ -126,11 +130,34 @@ test('pretty print - handle multiple handlers in parametric route properly', t = const tree = findMyWay.prettyPrint() const expected = `/ - ├── : - │ ├── :a (GET) - │ └── :b (POST) - │ - └── c (POST) ` +├── : +│ ├── :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') t.equal(tree, expected)