Skip to content

Commit

Permalink
replace archy with a specific implementation, refactor timetree (#211)
Browse files Browse the repository at this point in the history
* fix timetree typo

* integrate pretty printing into avvio

* move time-tree into lib folder

* add test as issue #205 is also solved.

* add jsdoc, remove unreachable code

* use -1 as diff default value
  • Loading branch information
Uzlopak authored Jun 24, 2023
1 parent 58d091d commit 4e4a22d
Show file tree
Hide file tree
Showing 7 changed files with 596 additions and 135 deletions.
4 changes: 2 additions & 2 deletions boot.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ const {
AVV_ERR_ROOT_PLG_BOOTED,
AVV_ERR_READY_TIMEOUT
} = require('./lib/errors')
const TimeTree = require('./time-tree')
const TimeTree = require('./lib/time-tree')
const Plugin = require('./plugin')
const { debug } = require('./lib/debug')
const kAvvio = Symbol('kAvvio')
Expand Down Expand Up @@ -363,7 +363,7 @@ Boot.prototype.ready = function (func) {
}

Boot.prototype.prettyPrint = function () {
return this.pluginTree.prittyPrint()
return this.pluginTree.prettyPrint()
}

Boot.prototype.toJSON = function () {
Expand Down
189 changes: 189 additions & 0 deletions lib/time-tree.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
'use strict'

const kUntrackNode = Symbol('avvio.TimeTree.untrackNode')
const kTrackNode = Symbol('avvio.TimeTree.trackNode')
const kGetParent = Symbol('avvio.TimeTree.getParent')
const kGetNode = Symbol('avvio.TimeTree.getNode')
const kAddNode = Symbol('avvio.TimeTree.addNode')

/**
* Node of the TimeTree
* @typedef {object} TimeTreeNode
* @property {string} id
* @property {string|null} parent
* @property {string} label
* @property {Array<TimeTreeNode>} nodes
* @property {number} start
* @property {number|undefined} stop
* @property {number|undefined} diff
*/

class TimeTree {
constructor () {
/**
* @type {TimeTreeNode|null} root
* @public
*/
this.root = null

/**
* @type {Map<string, TimeTreeNode>} tableId
* @public
*/
this.tableId = new Map()

/**
* @type {Map<string, Array<TimeTreeNode>>} tableLabel
* @public
*/
this.tableLabel = new Map()
}

/**
* @param {TimeTreeNode} node
*/
[kTrackNode] (node) {
this.tableId.set(node.id, node)
if (this.tableLabel.has(node.label)) {
this.tableLabel.get(node.label).push(node)
} else {
this.tableLabel.set(node.label, [node])
}
}

/**
* @param {TimeTreeNode} node
*/
[kUntrackNode] (node) {
this.tableId.delete(node.id)

const labelNode = this.tableLabel.get(node.label)
labelNode.pop()

if (labelNode.length === 0) {
this.tableLabel.delete(node.label)
}
}

/**
* @param {string} parent
* @returns {TimeTreeNode}
*/
[kGetParent] (parent) {
const parentNode = this.tableLabel.get(parent)
return parentNode[parentNode.length - 1]
}

/**
*
* @param {string} nodeId
* @returns {TimeTreeNode}
*/
[kGetNode] (nodeId) {
return this.tableId.get(nodeId)
}

/**
* @param {string} parent
* @param {string} label
* @param {number} start
* @returns {TimeTreeNode["id"]}
*/
[kAddNode] (parent, label, start) {
const isRoot = parent === null
if (isRoot) {
this.root = {
parent: null,
id: 'root',
label,
nodes: [],
start,
stop: undefined,
diff: -1
}
this[kTrackNode](this.root)
return this.root.id
}

const parentNode = this[kGetParent](parent)
const nodeId = `${label}-${Math.random()}`
/**
* @type {TimeTreeNode}
*/
const childNode = {
parent,
id: nodeId,
label,
nodes: [],
start,
stop: undefined,
diff: -1
}
parentNode.nodes.push(childNode)
this[kTrackNode](childNode)
return nodeId
}

/**
* @param {string} parent
* @param {string} label
* @param {number|undefined} start
* @returns {TimeTreeNode["id"]}
*/
start (parent, label, start = Date.now()) {
return this[kAddNode](parent, label, start)
}

/**
* @param {string} nodeId
* @param {number|undefined} stop
*/
stop (nodeId, stop = Date.now()) {
const node = this[kGetNode](nodeId)
if (node) {
node.stop = stop
node.diff = (node.stop - node.start) || 0
this[kUntrackNode](node)
}
}

/**
* @returns {TimeTreeNode}
*/
toJSON () {
return Object.assign({}, this.root)
}

/**
* @returns {string}
*/
prettyPrint () {
return prettyPrintTimeTree(this.toJSON())
}
}

/**
* @param {TimeTreeNode} obj
* @param {string|undefined} prefix
* @returns {string}
*/
function prettyPrintTimeTree (obj, prefix = '') {
let result = prefix

const nodesCount = obj.nodes.length
const lastIndex = nodesCount - 1
result += `${obj.label} ${obj.diff} ms\n`

for (let i = 0; i < nodesCount; ++i) {
const node = obj.nodes[i]
const prefix_ = prefix + (i === lastIndex ? ' ' : '│ ')

result += prefix
result += (i === lastIndex ? '└─' : '├─')
result += (node.nodes.length === 0 ? '─ ' : '┬ ')
result += prettyPrintTimeTree(node, prefix_).slice(prefix.length + 2)
}
return result
}

module.exports = TimeTree
1 change: 0 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,6 @@
"typescript": "^5.0.2"
},
"dependencies": {
"archy": "^1.0.0",
"fastq": "^1.6.1"
}
}
16 changes: 16 additions & 0 deletions test/gh-issues/bug-205.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
'use strict'

const { test } = require('tap')
const boot = require('../..')

test('should print the time tree', (t) => {
t.plan(2)
const app = boot()

app.use(function first (instance, opts, cb) {
const out = instance.prettyPrint().split('\n')
t.equal(out[0], 'bound root -1 ms')
t.equal(out[1], '└── first -1 ms')
cb()
})
})
Loading

0 comments on commit 4e4a22d

Please sign in to comment.