Skip to content

Commit cd2cae8

Browse files
authored
Merge pull request #31 from Johnaverse/fix/sonarqube-code-quality-v1.1.0
Fix SonarQube issues and bump version to 1.1.0
2 parents 55bfbc8 + 032c28c commit cd2cae8

8 files changed

Lines changed: 201 additions & 202 deletions

File tree

dataService.js

Lines changed: 28 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1316,13 +1316,39 @@ export function getRelationsById(chainId) {
13161316
* @param {number} maxDepth - Maximum traversal depth (default: 2)
13171317
* @returns {Object|null} Traversal result with nodes and edges, or null if chain not found
13181318
*/
1319+
function collectRelationEdges(chain, chainId, depth, visited, edges, queue, seenEdges) {
1320+
const relations = chain.relations || [];
1321+
for (const rel of relations) {
1322+
if (rel.chainId === undefined) continue;
1323+
1324+
// Deduplicate bidirectional edges (A→B and B→A with same kind) using O(1) Set lookup
1325+
const a = Math.min(chainId, rel.chainId);
1326+
const b = Math.max(chainId, rel.chainId);
1327+
const edgeKey = `${a}-${b}-${rel.kind}`;
1328+
if (!seenEdges.has(edgeKey)) {
1329+
seenEdges.add(edgeKey);
1330+
edges.push({
1331+
from: chainId,
1332+
to: rel.chainId,
1333+
kind: rel.kind,
1334+
source: rel.source
1335+
});
1336+
}
1337+
1338+
if (!visited.has(rel.chainId)) {
1339+
queue.push({ chainId: rel.chainId, depth: depth + 1 });
1340+
}
1341+
}
1342+
}
1343+
13191344
export function traverseRelations(startChainId, maxDepth = 2) {
13201345
if (!cachedData.indexed) return null;
13211346

13221347
const startChain = cachedData.indexed.byChainId[startChainId];
13231348
if (!startChain) return null;
13241349

13251350
const visited = new Set();
1351+
const seenEdges = new Set();
13261352
const queue = [{ chainId: startChainId, depth: 0 }];
13271353
const nodes = [];
13281354
const edges = [];
@@ -1342,28 +1368,8 @@ export function traverseRelations(startChainId, maxDepth = 2) {
13421368
depth
13431369
});
13441370

1345-
if (depth >= maxDepth) continue;
1346-
1347-
const relations = chain.relations || [];
1348-
for (const rel of relations) {
1349-
if (rel.chainId === undefined) continue;
1350-
1351-
// Deduplicate bidirectional edges (A→B and B→A with same kind)
1352-
const a = Math.min(chainId, rel.chainId);
1353-
const b = Math.max(chainId, rel.chainId);
1354-
const isDuplicate = edges.some(e => Math.min(e.from, e.to) === a && Math.max(e.from, e.to) === b && e.kind === rel.kind);
1355-
if (!isDuplicate) {
1356-
edges.push({
1357-
from: chainId,
1358-
to: rel.chainId,
1359-
kind: rel.kind,
1360-
source: rel.source
1361-
});
1362-
}
1363-
1364-
if (!visited.has(rel.chainId)) {
1365-
queue.push({ chainId: rel.chainId, depth: depth + 1 });
1366-
}
1371+
if (depth < maxDepth) {
1372+
collectRelationEdges(chain, chainId, depth, visited, edges, queue, seenEdges);
13671373
}
13681374
}
13691375

index.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import fastifyStatic from '@fastify/static';
66
import { readFile } from 'node:fs/promises';
77
import { basename, resolve, dirname, join } from 'node:path';
88
import { fileURLToPath as toFilePath } from 'node:url';
9+
import pkg from './package.json' with { type: 'json' };
910
import { loadData, initializeDataOnStartup, getCachedData, searchChains, getChainById, getAllChains, getAllRelations, getRelationsById, getEndpointsById, getAllEndpoints, getAllKeywords, validateChainData, traverseRelations, countChainsByTag } from './dataService.js';
1011
import { getMonitoringResults, getMonitoringStatus, startRpcHealthCheck } from './rpcMonitor.js';
1112
import {
@@ -202,7 +203,7 @@ export async function buildApp(options = {}) {
202203
return sendError(reply, 400, 'Invalid chain ID');
203204
}
204205

205-
const depth = request.query.depth !== undefined ? parseIntParam(request.query.depth) : 2;
206+
const depth = request.query.depth === undefined ? 2 : parseIntParam(request.query.depth);
206207
if (depth === null || depth < 1 || depth > 5) {
207208
return sendError(reply, 400, 'Invalid depth. Must be between 1 and 5');
208209
}
@@ -456,7 +457,7 @@ export async function buildApp(options = {}) {
456457
fastify.get('/', async (request, reply) => {
457458
return {
458459
name: 'Chains API',
459-
version: '1.0.0',
460+
version: pkg.version,
460461
description: 'API query service for blockchain chain data from multiple sources',
461462
endpoints: {
462463
'/health': 'Health check and data status',

mcp-tools.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -352,7 +352,7 @@ function handleTraverseRelations(args) {
352352
return errorResponse('Invalid chain ID');
353353
}
354354

355-
const maxDepth = depth !== undefined ? depth : 2;
355+
const maxDepth = depth ?? 2;
356356
if (typeof maxDepth !== 'number' || maxDepth < 1 || maxDepth > 5) {
357357
return errorResponse('Invalid depth. Must be between 1 and 5');
358358
}
@@ -433,7 +433,7 @@ function handleGetRpcMonitorById(args) {
433433
];
434434
for (const ep of chainResults) {
435435
const block = ep.blockNumber == null ? '' : ` — block #${ep.blockNumber}`;
436-
const latency = ep.latencyMs != null ? ` [${ep.latencyMs}ms]` : '';
436+
const latency = ep.latencyMs == null ? '' : ` [${ep.latencyMs}ms]`;
437437
const client = ep.clientVersion && ep.clientVersion !== 'unavailable' ? ` (${ep.clientVersion})` : '';
438438
lines.push(
439439
`- **${ep.status}** ${ep.url}${block}${latency}${client}`,

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "chains-api",
3-
"version": "1.0.12",
3+
"version": "1.1.0",
44
"description": "API query service for blockchain chain data from multiple sources",
55
"main": "index.js",
66
"type": "module",

0 commit comments

Comments
 (0)