diff --git a/packages/jaeger-ui-components/src/model/transform-trace-data.tsx b/packages/jaeger-ui-components/src/model/transform-trace-data.tsx index f57036cde50..49c10fac0aa 100644 --- a/packages/jaeger-ui-components/src/model/transform-trace-data.tsx +++ b/packages/jaeger-ui-components/src/model/transform-trace-data.tsx @@ -135,10 +135,13 @@ export default function transformTraceData(data: TraceResponse | undefined): Tra // Eslint complains about number type not needed but then TS complains it is implicitly any. // eslint-disable-next-line @typescript-eslint/no-inferrable-types - tree.walk((spanID: string, node: TreeNode, depth: number = 0) => { + tree.walk((spanID: string | number | undefined, node: TreeNode, depth: number = 0) => { if (spanID === '__root__') { return; } + if (typeof spanID !== 'string') { + return; + } const span = spanMap.get(spanID) as TraceSpan; if (!span) { return; diff --git a/packages/jaeger-ui-components/src/utils/TreeNode.test.js b/packages/jaeger-ui-components/src/utils/TreeNode.test.ts similarity index 97% rename from packages/jaeger-ui-components/src/utils/TreeNode.test.js rename to packages/jaeger-ui-components/src/utils/TreeNode.test.ts index 9ed70686c42..5136cdccb2b 100644 --- a/packages/jaeger-ui-components/src/utils/TreeNode.test.js +++ b/packages/jaeger-ui-components/src/utils/TreeNode.test.ts @@ -280,7 +280,7 @@ it('walk() should iterate over every item and compute the right deep on each nod const nodeB0 = new TreeNode('B0'); const nodeB1 = new TreeNode('B1'); const nodeC3 = new TreeNode('C3'); - const depthMap = { A: 0, B0: 1, B1: 1, C0: 2, C1: 2, C2: 2, C3: 2, D: 3 }; + const depthMap: { [key: string]: number } = { A: 0, B0: 1, B1: 1, C0: 2, C1: 2, C2: 2, C3: 2, D: 3 }; nodeA.addChild(nodeB0); nodeA.addChild(nodeB0); nodeA.addChild(nodeB1); @@ -289,5 +289,9 @@ it('walk() should iterate over every item and compute the right deep on each nod nodeB1.addChild('C2'); nodeB1.addChild(nodeC3); nodeC3.addChild('D'); - nodeA.walk((value, node, depth) => expect(depth).toBe(depthMap[value])); + nodeA.walk((value, _, depth) => { + if (typeof value === 'string') { + expect(depth).toBe(depthMap[value]); + } + }); }); diff --git a/packages/jaeger-ui-components/src/utils/TreeNode.js b/packages/jaeger-ui-components/src/utils/TreeNode.ts similarity index 55% rename from packages/jaeger-ui-components/src/utils/TreeNode.js rename to packages/jaeger-ui-components/src/utils/TreeNode.ts index 3235b0a9972..8f8edeeea1e 100644 --- a/packages/jaeger-ui-components/src/utils/TreeNode.js +++ b/packages/jaeger-ui-components/src/utils/TreeNode.ts @@ -12,26 +12,32 @@ // See the License for the specific language governing permissions and // limitations under the License. +type SearchFn = (value: string | number | undefined, node: TreeNode, depth?: number) => boolean; + export default class TreeNode { - static iterFunction(fn, depth = 0) { - return (node) => fn(node.value, node, depth); + value: string | number | undefined; + children: TreeNode[]; + + static iterFunction(fn: SearchFn, depth = 0) { + return (node: TreeNode) => fn(node.value, node, depth); } - static searchFunction(search) { + static searchFunction(search: TreeNode | number | SearchFn) { if (typeof search === 'function') { return search; } - return (value, node) => (search instanceof TreeNode ? node === search : value === search); + return (value: string | number | undefined, node: TreeNode) => + search instanceof TreeNode ? node === search : value === search; } - constructor(value, children = []) { + constructor(value?: string | number, children: TreeNode[] = []) { this.value = value; this.children = children; } - get depth() { - return this.children.reduce((depth, child) => Math.max(child.depth + 1, depth), 1); + get depth(): number { + return this.children?.reduce((depth: number, child: { depth: number }) => Math.max(child.depth + 1, depth), 1); } get size() { @@ -40,12 +46,12 @@ export default class TreeNode { return i; } - addChild(child) { - this.children.push(child instanceof TreeNode ? child : new TreeNode(child)); + addChild(child: string | number | TreeNode) { + this.children?.push(child instanceof TreeNode ? child : new TreeNode(child)); return this; } - find(search) { + find(search: TreeNode | number | SearchFn): TreeNode | null { const searchFn = TreeNode.iterFunction(TreeNode.searchFunction(search)); if (searchFn(this)) { return this; @@ -59,10 +65,10 @@ export default class TreeNode { return null; } - getPath(search) { + getPath(search: TreeNode) { const searchFn = TreeNode.iterFunction(TreeNode.searchFunction(search)); - const findPath = (currentNode, currentPath) => { + const findPath = (currentNode: TreeNode, currentPath: TreeNode[]): TreeNode[] | null => { // skip if we already found the result const attempt = currentPath.concat([currentNode]); // base case: return the array when there is a match @@ -82,18 +88,21 @@ export default class TreeNode { return findPath(this, []); } - walk(fn, depth = 0) { - const nodeStack = []; + walk(fn: (value: string | number | undefined, node: TreeNode, depth?: number) => void, depth = 0) { + const nodeStack: Array<{ node: TreeNode; depth?: number }> = []; let actualDepth = depth; nodeStack.push({ node: this, depth: actualDepth }); while (nodeStack.length) { - const { node, depth: nodeDepth } = nodeStack.pop(); - fn(node.value, node, nodeDepth); - actualDepth = nodeDepth + 1; - let i = node.children.length - 1; - while (i >= 0) { - nodeStack.push({ node: node.children[i], depth: actualDepth }); - i--; + const popped = nodeStack.pop(); + if (popped) { + const { node, depth: nodeDepth } = popped; + fn(node.value, node, nodeDepth); + actualDepth = (nodeDepth || 0) + 1; + let i = node.children.length - 1; + while (i >= 0) { + nodeStack.push({ node: node.children[i], depth: actualDepth }); + i--; + } } } }