From ac3559e19f66615cc10d689345396b4f75a20659 Mon Sep 17 00:00:00 2001 From: abhigyantrumio Date: Mon, 4 Aug 2025 03:49:32 +0530 Subject: [PATCH] Handled built in function --- src/ui/components/graph/SourceViewer.tsx | 238 +++++++++++++++++++++- src/ui/components/graph/Visualization.tsx | 155 ++++++++++++-- src/ui/pages/HomePage.tsx | 5 + 3 files changed, 368 insertions(+), 30 deletions(-) diff --git a/src/ui/components/graph/SourceViewer.tsx b/src/ui/components/graph/SourceViewer.tsx index 618e4a65f..cdab30ab4 100644 --- a/src/ui/components/graph/SourceViewer.tsx +++ b/src/ui/components/graph/SourceViewer.tsx @@ -226,6 +226,151 @@ public class ${name.replace(/\.[^/.]+$/, "")} { } }; + // Generate content for built-in functions + const generateBuiltinFunctionContent = (functionName: string): string => { + switch (functionName) { + case 'round': + return `# Built-in Function: ${functionName} +""" +Rounds a number to the nearest integer. +""" + +def round(number: float, ndigits: int = 0) -> float: + """ + Rounds a number to the nearest integer. + Args: + number (float): The number to round. + ndigits (int, optional): The number of decimal places to round to. Defaults to 0. + Returns: + float: The rounded number. + """ + # Implementation here + pass`; + case 'len': + return `# Built-in Function: ${functionName} +""" +Returns the number of items in an object. +""" + +def len(obj: Any) -> int: + """ + Returns the number of items in an object. + Args: + obj (Any): The object to get the length of. + Returns: + int: The number of items. + """ + # Implementation here + pass`; + case 'print': + return `# Built-in Function: ${functionName} +""" +Prints the given arguments to the standard output. +""" + +def print(*args, sep: str = " ", end: str = "\\n") -> None: + """ + Prints the given arguments to the standard output. + Args: + *args: The arguments to print. + sep (str, optional): The separator between arguments. Defaults to " ". + end (str, optional): The string to print at the end. Defaults to "\\n". + """ + # Implementation here + pass`; + case 'input': + return `# Built-in Function: ${functionName} +""" +Reads a line from the standard input. +""" + +def input(prompt: str = "") -> str: + """ + Reads a line from the standard input. + Args: + prompt (str, optional): The prompt to display. Defaults to "". + Returns: + str: The input string. + """ + # Implementation here + pass`; + case 'open': + return `# Built-in Function: ${functionName} +""" +Opens a file and returns a file object. +""" + +def open(file: str, mode: str = "r", buffering: int = -1, encoding: str | None = None, errors: str | None = None, newline: str | None = None) -> Any: + """ + Opens a file and returns a file object. + Args: + file (str): The path to the file. + mode (str, optional): The mode in which the file is opened. Defaults to "r". + buffering (int, optional): The buffering strategy. Defaults to -1. + encoding (str | None, optional): The encoding to use. Defaults to None. + errors (str | None, optional): How to handle encoding errors. Defaults to None. + newline (str | None, optional): How to handle newlines. Defaults to None. + Returns: + Any: The file object. + """ + # Implementation here + pass`; + case 'type': + return `# Built-in Function: ${functionName} +""" +Returns the type of an object. +""" + +def type(obj: Any) -> type: + """ + Returns the type of an object. + Args: + obj (Any): The object to get the type of. + Returns: + type: The type of the object. + """ + # Implementation here + pass`; + case 'isinstance': + return `# Built-in Function: ${functionName} +""" +Checks if an object is an instance of a class or a tuple of classes. +""" + +def isinstance(obj: Any, classinfo: type | tuple[type, ...]) -> bool: + """ + Checks if an object is an instance of a class or a tuple of classes. + Args: + obj (Any): The object to check. + classinfo (type | tuple[type, ...]): The class or tuple of classes to check against. + Returns: + bool: True if the object is an instance of the class or one of the classes in the tuple. + """ + # Implementation here + pass`; + case 'hasattr': + return `# Built-in Function: ${functionName} +""" +Checks if an object has an attribute. +""" + +def hasattr(obj: Any, name: str) -> bool: + """ + Checks if an object has an attribute. + Args: + obj (Any): The object to check. + name (str): The name of the attribute to check for. + Returns: + bool: True if the object has the attribute, False otherwise. + """ + # Implementation here + pass`; + default: + return `# Built-in Function: ${functionName} +# No specific content available`; + } + }; + // Get source info for selected node const sourceInfo = useMemo((): SourceInfo | null => { if (!selectedNodeId || !graph?.nodes) return null; @@ -258,21 +403,64 @@ public class ${name.replace(/\.[^/.]+$/, "")} { // If still no file path, try reverse lookup by searching for the node name in file contents if (!filePath && fileContents) { console.log('SourceViewer - Searching file contents for node:', nodeName); + + // Try multiple search patterns for the function + const searchPatterns = [ + `def ${nodeName}(`, // Python function + `def ${nodeName} (`, // Python function with space + `function ${nodeName}(`, // JavaScript function + `function ${nodeName} (`, // JavaScript function with space + `const ${nodeName} =`, // JavaScript const + `let ${nodeName} =`, // JavaScript let + `var ${nodeName} =`, // JavaScript var + `class ${nodeName}`, // Class definition + `${nodeName}:`, // Object property or TypeScript type + `export const ${nodeName}`, // ES6 export + `export function ${nodeName}`, // ES6 export function + `public ${nodeName}(`, // Java/C# method + `private ${nodeName}(`, // Java/C# method + `protected ${nodeName}(`, // Java/C# method + // Also try with underscores and variations + `def ${nodeName}_`, // Python with underscore + `function ${nodeName}_`, // JavaScript with underscore + ]; + for (const [path, content] of fileContents) { - const patterns = [ - `def ${nodeName}(`, // Python function - `function ${nodeName}(`, // JavaScript function - `const ${nodeName} =`, // JavaScript const - `class ${nodeName}`, // Class definition - `${nodeName}:`, // Object property or TypeScript type - ]; + console.log(`SourceViewer - Checking file: ${path}`); - if (patterns.some(pattern => content.includes(pattern))) { + // Check if any pattern matches + const foundPattern = searchPatterns.find(pattern => { + const found = content.includes(pattern); + if (found) { + console.log(`SourceViewer - Found pattern "${pattern}" in ${path}`); + } + return found; + }); + + if (foundPattern) { filePath = path; console.log('SourceViewer - Found file through content search:', filePath); break; } } + + // If still not found, try a more lenient search (case-insensitive) + if (!filePath) { + console.log('SourceViewer - Trying case-insensitive search for:', nodeName); + for (const [path, content] of fileContents) { + const lowerContent = content.toLowerCase(); + const lowerNodeName = nodeName.toLowerCase(); + + if (lowerContent.includes(`def ${lowerNodeName}(`) || + lowerContent.includes(`function ${lowerNodeName}(`) || + lowerContent.includes(`const ${lowerNodeName} =`) || + lowerContent.includes(`class ${lowerNodeName}`)) { + filePath = path; + console.log('SourceViewer - Found file through case-insensitive search:', filePath); + break; + } + } + } } } @@ -285,7 +473,23 @@ public class ${name.replace(/\.[^/.]+$/, "")} { fileName, nodeLabel: node.label, nodeProperties: node.properties, - fileContentsSize: fileContents?.size || 0 + fileContentsSize: fileContents?.size || 0, + // Add detailed relationship debugging + allRelationships: graph?.relationships?.length || 0, + containsRelationships: graph?.relationships?.filter(rel => rel.type === 'CONTAINS').length || 0, + relationshipsForThisNode: graph?.relationships?.filter(rel => rel.target === selectedNodeId || rel.source === selectedNodeId) || [], + fileNodesInGraph: graph?.nodes?.filter(n => n.label === 'File').map(n => ({ + id: n.id, + path: n.properties.path, + filePath: n.properties.filePath, + name: n.properties.name + })) || [], + availableFileContents: fileContents ? Array.from(fileContents.entries()).map(([path, content]) => ({ + path, + size: content.length, + firstLines: content.split('\n').slice(0, 3).join('\\n'), + containsSub: content.includes('def sub(') || content.includes('function sub(') + })) : [] }); // Try to get actual file content @@ -304,8 +508,20 @@ public class ${name.replace(/\.[^/.]+$/, "")} { } } } else { - console.log('SourceViewer - No file content found, using mock content'); - content = generateMockContent(node); + console.log('SourceViewer - No file content found, checking if this is a built-in function'); + + // Check if this is a built-in function + if (node.id.includes('builtin_') || nodeName === 'round' || nodeName === 'len' || nodeName === 'print' || + ['round', 'len', 'str', 'int', 'float', 'bool', 'list', 'dict', 'tuple', 'set', + 'range', 'enumerate', 'zip', 'map', 'filter', 'sum', 'max', 'min', 'abs', + 'print', 'input', 'open', 'type', 'isinstance', 'hasattr'].includes(nodeName)) { + + content = generateBuiltinFunctionContent(nodeName); + console.log('SourceViewer - Using built-in function content for:', nodeName); + } else { + console.log('SourceViewer - Using mock content for user-defined node:', nodeName); + content = generateMockContent(node); + } } // Detect language from file extension diff --git a/src/ui/components/graph/Visualization.tsx b/src/ui/components/graph/Visualization.tsx index e0d6fac8b..b04ed9bec 100644 --- a/src/ui/components/graph/Visualization.tsx +++ b/src/ui/components/graph/Visualization.tsx @@ -47,59 +47,165 @@ const GraphVisualization: React.FC = ({ const convertToD3Format = (graph: KnowledgeGraph) => { const nodeIds = new Set(); - // Convert nodes - const nodes: D3Node[] = graph.nodes.map((node: GraphNode) => { - nodeIds.add(node.id); + // First pass: collect all node IDs and analyze the graph structure + graph.nodes.forEach(node => nodeIds.add(node.id)); + + // Calculate node metrics for intelligent sizing + const nodeMetrics = new Map(); + + // Initialize metrics + graph.nodes.forEach(node => { + nodeMetrics.set(node.id, { + inDegree: 0, + outDegree: 0, + totalDegree: 0, + depth: 0, + isRoot: false, + childrenCount: 0 + }); + }); + + // Calculate degrees and relationships + graph.relationships.forEach(rel => { + const sourceMetrics = nodeMetrics.get(rel.source); + const targetMetrics = nodeMetrics.get(rel.target); - // Determine node color and size based on type + if (sourceMetrics && targetMetrics) { + sourceMetrics.outDegree++; + targetMetrics.inDegree++; + + // For CONTAINS relationships, count children + if (rel.type.toLowerCase() === 'contains') { + sourceMetrics.childrenCount++; + } + } + }); + + // Calculate total degree and identify root nodes + nodeMetrics.forEach((metrics) => { + metrics.totalDegree = metrics.inDegree + metrics.outDegree; + // Root nodes typically have high out-degree and low/zero in-degree + metrics.isRoot = metrics.inDegree === 0 && metrics.outDegree > 0; + }); + + // Calculate depth (simplified - could be more sophisticated) + const calculateDepth = (nodeId: string, visited = new Set()): number => { + if (visited.has(nodeId)) return 0; + visited.add(nodeId); + + const parentRels = graph.relationships.filter(rel => + rel.target === nodeId && rel.type.toLowerCase() === 'contains' + ); + + if (parentRels.length === 0) return 0; // Root level + + const parentDepths = parentRels.map(rel => calculateDepth(rel.source, new Set(visited))); + return Math.max(...parentDepths, 0) + 1; + }; + + // Calculate depths for all nodes + graph.nodes.forEach(node => { + const metrics = nodeMetrics.get(node.id); + if (metrics) { + metrics.depth = calculateDepth(node.id); + } + }); + + // Convert nodes with intelligent sizing + const nodes: D3Node[] = graph.nodes.map((node: GraphNode) => { + const metrics = nodeMetrics.get(node.id)!; + + // Determine base color and size based on type let color = '#69b3a2'; - let size = 8; + let baseSize = 8; switch (node.label.toLowerCase()) { case 'project': color = '#2E7D32'; - size = 20; + baseSize = 25; // Largest - project root break; case 'folder': color = '#F57C00'; - size = 12; + baseSize = 16; break; case 'file': color = '#1976D2'; - size = 10; + baseSize = 12; break; case 'function': color = '#00796B'; - size = 8; + baseSize = 8; break; case 'method': color = '#00695C'; - size = 7; + baseSize = 7; break; case 'class': color = '#C2185B'; - size = 10; + baseSize = 12; break; case 'variable': color = '#546E7A'; - size = 6; + baseSize = 6; break; default: color = '#69b3a2'; - size = 8; + baseSize = 8; } + // Calculate final size based on multiple factors + let finalSize = baseSize; + + // Factor 1: Hierarchy depth (higher levels = bigger) + const depthMultiplier = Math.max(0.7, 1.5 - (metrics.depth * 0.15)); + finalSize *= depthMultiplier; + + // Factor 2: Connection importance (more connections = bigger) + if (metrics.totalDegree > 0) { + const connectionMultiplier = 1 + Math.min(0.8, metrics.totalDegree * 0.1); + finalSize *= connectionMultiplier; + } + + // Factor 3: Container nodes (nodes with children) should be bigger + if (metrics.childrenCount > 0) { + const containerMultiplier = 1 + Math.min(0.6, metrics.childrenCount * 0.08); + finalSize *= containerMultiplier; + } + + // Factor 4: Root nodes get a boost + if (metrics.isRoot) { + finalSize *= 1.4; + } + + // Factor 5: Special boost for hub nodes (high degree centrality) + if (metrics.totalDegree > 10) { + finalSize *= 1.3; + color = adjustColorBrightness(color, 20); // Make hub nodes slightly brighter + } + + // Ensure size bounds + finalSize = Math.max(4, Math.min(35, finalSize)); + return { id: node.id, label: node.properties.name as string || node.id, nodeType: node.label.toLowerCase(), properties: node.properties, color, - size + size: Math.round(finalSize), + // Store metrics for potential future use + metrics }; }); - // Convert links with validation + // Convert links with validation (unchanged) const links: D3Link[] = []; graph.relationships.forEach((rel: GraphRelationship) => { // Validate that both source and target nodes exist @@ -152,6 +258,18 @@ const GraphVisualization: React.FC = ({ return { nodes, links }; }; + // Helper function to adjust color brightness + const adjustColorBrightness = (hex: string, percent: number): string => { + const num = parseInt(hex.replace("#", ""), 16); + const amt = Math.round(2.55 * percent); + const R = (num >> 16) + amt; + const G = (num >> 8 & 0x00FF) + amt; + const B = (num & 0x0000FF) + amt; + return "#" + (0x1000000 + (R < 255 ? R < 1 ? 0 : R : 255) * 0x10000 + + (G < 255 ? G < 1 ? 0 : G : 255) * 0x100 + + (B < 255 ? B < 1 ? 0 : B : 255)).toString(16).slice(1); + }; + // Initialize D3 visualization useEffect(() => { if (!svgRef.current || !graph) return; @@ -435,18 +553,17 @@ const GraphVisualization: React.FC = ({ const defaultStyle: React.CSSProperties = { width: '100%', - height: style.height || '700px', - minHeight: '600px', + height: '100%', + minHeight: '400px', border: '1px solid #37474F', borderRadius: '8px', backgroundColor: '#263238', - position: 'relative', boxShadow: '0 4px 20px rgba(0,0,0,0.1)', ...style }; return ( -
+
{ 100% { transform: rotate(360deg); } } + #root { + height: 100vh; + width: 100vw; + } + input:focus, textarea:focus { border-color: ${colors.primary} !important; box-shadow: 0 0 0 3px ${colors.primary}20 !important;