import os import json import networkx as nx from pyast_ts import parse import cssutils import logging # Configure logging logging.basicConfig(level=logging.INFO) log = logging.getLogger(__name__) # Configure cssutils to ignore noisy error messages cssutils.log.setLevel(logging.CRITICAL) def analyze_react_project(project_path: str) -> dict: """ Analyzes a React project, building a graph of its components and styles. Args: project_path: The root path of the React project. Returns: A dictionary containing the component graph and analysis report. """ log.info(f"Starting analysis of project at: {project_path}") graph = nx.DiGraph() # Supported extensions for react/js/ts files supported_exts = ('.js', '.jsx', '.ts', '.tsx') for root, _, files in os.walk(project_path): for file in files: file_path = os.path.join(root, file) relative_path = os.path.relpath(file_path, project_path) if file.endswith(supported_exts): graph.add_node(relative_path, type='file', language='typescript') try: with open(file_path, 'r', encoding='utf-8') as f: content = f.read() # Placeholder for AST parsing and analysis # ast = parse(content) # For now, we'll just add the node except Exception as e: log.error(f"Could not process file {file_path}: {e}") elif file.endswith('.css'): graph.add_node(relative_path, type='file', language='css') try: # Placeholder for CSS parsing # sheet = cssutils.parseFile(file_path) pass except Exception as e: log.error(f"Could not parse css file {file_path}: {e}") log.info(f"Analysis complete. Found {graph.number_of_nodes()} files.") # Convert graph to a serializable format serializable_graph = nx.node_link_data(graph) return serializable_graph def save_analysis(project_path: str, analysis_data: dict): """ Saves the analysis data to a file in the project's .dss directory. """ dss_dir = os.path.join(project_path, '.dss') os.makedirs(dss_dir, exist_ok=True) output_path = os.path.join(dss_dir, 'analysis_graph.json') with open(output_path, 'w', encoding='utf-8') as f: json.dump(analysis_data, f, indent=2) log.info(f"Analysis data saved to {output_path}") if __name__ == '__main__': # Example usage: # Replace '.' with the actual path to a React project for testing. # In a real scenario, this would be called by the MCP. target_project_path = '.' analysis_result = analyze_react_project(target_project_path) save_analysis(target_project_path, analysis_result)