Coverage for src\llm_code_lens\analyzer\config.py: 17%

52 statements  

« prev     ^ index     » next       coverage.py v7.7.0, created at 2025-05-25 12:07 +0300

1""" 

2Configuration file analyzers for project context. 

3""" 

4 

5import json 

6from pathlib import Path 

7from typing import Dict, Optional, List 

8 

9try: 

10 import tomli 

11except ImportError: 

12 tomli = None 

13 

14def analyze_package_json(file_path: Path) -> Optional[Dict]: 

15 """Extract key information from package.json.""" 

16 if not file_path.exists(): 

17 return None 

18 

19 try: 

20 with open(file_path, 'r') as f: 

21 data = json.load(f) 

22 

23 return { 

24 'name': data.get('name'), 

25 'version': data.get('version'), 

26 'description': data.get('description'), 

27 'main': data.get('main'), 

28 'scripts': list(data.get('scripts', {}).keys()), 

29 'dependencies': list(data.get('dependencies', {}).keys()), 

30 'devDependencies': list(data.get('devDependencies', {}).keys()), 

31 'framework_indicators': _detect_frameworks(data) 

32 } 

33 except (json.JSONDecodeError, Exception): 

34 return {'error': 'Failed to parse package.json'} 

35 

36def _detect_frameworks(package_data: dict) -> List[str]: 

37 """Detect frameworks based on dependencies.""" 

38 frameworks = [] 

39 all_deps = {**package_data.get('dependencies', {}), **package_data.get('devDependencies', {})} 

40 

41 if 'react' in all_deps: frameworks.append('React') 

42 if 'next' in all_deps: frameworks.append('Next.js') 

43 if 'vue' in all_deps: frameworks.append('Vue.js') 

44 if 'angular' in all_deps: frameworks.append('Angular') 

45 if 'typescript' in all_deps: frameworks.append('TypeScript') 

46 if 'tailwindcss' in all_deps: frameworks.append('Tailwind CSS') 

47 

48 return frameworks 

49 

50def analyze_tsconfig(file_path: Path) -> Optional[Dict]: 

51 """Extract TypeScript configuration.""" 

52 if not file_path.exists(): 

53 return None 

54 

55 try: 

56 with open(file_path, 'r') as f: 

57 # Simple JSON parsing (ignoring comments for now) 

58 content = f.read() 

59 # Remove comments (basic approach) 

60 lines = [line.split('//')[0].strip() for line in content.split('\n')] 

61 clean_content = '\n'.join(lines) 

62 data = json.loads(clean_content) 

63 

64 compiler_options = data.get('compilerOptions', {}) 

65 return { 

66 'target': compiler_options.get('target'), 

67 'module': compiler_options.get('module'), 

68 'jsx': compiler_options.get('jsx'), 

69 'strict': compiler_options.get('strict'), 

70 'baseUrl': compiler_options.get('baseUrl'), 

71 'paths': bool(compiler_options.get('paths')), 

72 'include': data.get('include', []), 

73 'exclude': data.get('exclude', []) 

74 } 

75 except (json.JSONDecodeError, Exception): 

76 return {'error': 'Failed to parse tsconfig.json'} 

77 

78def extract_readme_summary(file_path: Path) -> Optional[Dict]: 

79 """Extract first few lines of README for project description.""" 

80 readme_files = ['README.md', 'README.txt', 'README.rst', 'README'] 

81 

82 for readme_name in readme_files: 

83 readme_path = file_path / readme_name 

84 if readme_path.exists(): 

85 try: 

86 with open(readme_path, 'r', encoding='utf-8') as f: 

87 lines = f.readlines()[:10] # First 10 lines 

88 content = ''.join(lines).strip() 

89 

90 return { 

91 'filename': readme_name, 

92 'summary': content[:500] + '...' if len(content) > 500 else content, 

93 'has_badges': '[![' in content, 

94 'has_installation': any(word in content.lower() for word in ['install', 'setup', 'getting started']) 

95 } 

96 except Exception: 

97 continue 

98 

99 return None