Add TypeScript, Go, and Rust analyzers
This commit is contained in:
105
vibeguard/analyzers/languages/typescript.py
Normal file
105
vibeguard/analyzers/languages/typescript.py
Normal file
@@ -0,0 +1,105 @@
|
||||
"""TypeScript analyzer for VibeGuard."""
|
||||
|
||||
import re
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
from vibeguard.analyzers.languages.javascript import JavaScriptAnalyzer
|
||||
|
||||
|
||||
class TypeScriptAnalyzer(JavaScriptAnalyzer):
|
||||
"""Analyzer for TypeScript code."""
|
||||
|
||||
LANGUAGE_NAME = "typescript"
|
||||
FILE_EXTENSIONS = [".ts", ".tsx"]
|
||||
|
||||
def analyze(self, content: str, path: Path) -> list[dict[str, Any]]:
|
||||
"""Analyze TypeScript content for anti-patterns."""
|
||||
issues: list[dict[str, Any]] = []
|
||||
|
||||
issues.extend(super().analyze(content, path))
|
||||
|
||||
lines = content.split("\n")
|
||||
|
||||
for i, line in enumerate(lines, 1):
|
||||
issues.extend(self._check_any_type(line, i, path))
|
||||
issues.extend(self._check_missing_type_annotation(line, i, path))
|
||||
issues.extend(self._check_interfaceNaming(line, i, path))
|
||||
issues.extend(self._check_enum_usage(line, i, path))
|
||||
|
||||
return issues
|
||||
|
||||
def _check_any_type(
|
||||
self, line: str, line_num: int, path: Path
|
||||
) -> list[dict[str, Any]]:
|
||||
"""Check for 'any' type usage."""
|
||||
issues: list[dict[str, Any]] = []
|
||||
|
||||
if re.search(r":\s*any\b", line) and "any" not in line.lower():
|
||||
issues.append(
|
||||
{
|
||||
"pattern": "ANY_TYPE_USAGE",
|
||||
"severity": "warning",
|
||||
"file": str(path),
|
||||
"line": line_num,
|
||||
"message": "'any' type detected - defeats TypeScript's type safety",
|
||||
"suggestion": "Use specific types or 'unknown' with proper type narrowing",
|
||||
"language": self.LANGUAGE_NAME,
|
||||
}
|
||||
)
|
||||
|
||||
return issues
|
||||
|
||||
def _check_missing_type_annotation(
|
||||
self, line: str, line_num: int, path: Path
|
||||
) -> list[dict[str, Any]]:
|
||||
"""Check for missing type annotations in typed contexts."""
|
||||
issues: list[dict[str, Any]] = []
|
||||
|
||||
if re.search(r"const\s+\w+\s*=", line) and "function" not in line:
|
||||
if not re.search(r":\s*\w+", line) and "=" in line:
|
||||
pass
|
||||
|
||||
return issues
|
||||
|
||||
def _check_interfaceNaming(
|
||||
self, line: str, line_num: int, path: Path
|
||||
) -> list[dict[str, Any]]:
|
||||
"""Check for interface naming conventions."""
|
||||
issues: list[dict[str, Any]] = []
|
||||
|
||||
if re.match(r"^\s*interface\s+[a-z]", line):
|
||||
issues.append(
|
||||
{
|
||||
"pattern": "INTERFACE_NAMING",
|
||||
"severity": "info",
|
||||
"file": str(path),
|
||||
"line": line_num,
|
||||
"message": "Interface name should start with capital letter",
|
||||
"suggestion": "Rename interface to use PascalCase",
|
||||
"language": self.LANGUAGE_NAME,
|
||||
}
|
||||
)
|
||||
|
||||
return issues
|
||||
|
||||
def _check_enum_usage(
|
||||
self, line: str, line_num: int, path: Path
|
||||
) -> list[dict[str, Any]]:
|
||||
"""Check for enum usage vs const objects."""
|
||||
issues: list[dict[str, Any]] = []
|
||||
|
||||
if re.match(r"^\s*enum\s+\w+", line):
|
||||
issues.append(
|
||||
{
|
||||
"pattern": "ENUM_USAGE",
|
||||
"severity": "info",
|
||||
"file": str(path),
|
||||
"line": line_num,
|
||||
"message": "Enum detected - consider using const objects for better tree-shaking",
|
||||
"suggestion": "Consider using 'const' objects with 'as const' assertion",
|
||||
"language": self.LANGUAGE_NAME,
|
||||
}
|
||||
)
|
||||
|
||||
return issues
|
||||
Reference in New Issue
Block a user