feat(languages): Expand supported languages and improve code analysis
- Add Swift and Kotlin as supported programming languages - Update language detection and file upload logic in InstantAnalysis page - Refactor language-related code to use centralized SUPPORTED_LANGUAGES constant - Enhance project detail page to handle repository scanning with more flexibility - Improve error handling and user guidance for project audits - Add language name formatting utility in ProjectDetail component - Update file input accept types to include new language extensions
This commit is contained in:
parent
d8f6b2470a
commit
a26552c86b
|
|
@ -2,15 +2,12 @@ import type { CodeAnalysisResult } from "@/shared/types";
|
|||
import { LLMService } from '@/shared/services/llm';
|
||||
import { getCurrentLLMApiKey, getCurrentLLMModel, env } from '@/shared/config/env';
|
||||
import type { LLMConfig } from '@/shared/services/llm/types';
|
||||
import { SUPPORTED_LANGUAGES } from '@/shared/constants';
|
||||
|
||||
// 基于 LLM 的代码分析引擎
|
||||
export class CodeAnalysisEngine {
|
||||
private static readonly SUPPORTED_LANGUAGES = [
|
||||
'javascript', 'typescript', 'python', 'java', 'go', 'rust', 'cpp', 'csharp', 'php', 'ruby'
|
||||
];
|
||||
|
||||
static getSupportedLanguages(): string[] {
|
||||
return [...this.SUPPORTED_LANGUAGES];
|
||||
return [...SUPPORTED_LANGUAGES];
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -146,6 +146,65 @@ public class Example {
|
|||
private String getData() {
|
||||
return "data";
|
||||
}
|
||||
}`,
|
||||
swift: `// 示例Swift代码 - 包含多种问题
|
||||
import Foundation
|
||||
|
||||
class UserManager {
|
||||
var password = "admin123" // 硬编码密码
|
||||
|
||||
func validateUser(input: String) -> Bool {
|
||||
if input == password { // 直接比较密码
|
||||
print("User validated") // 使用print而非日志
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// 强制解包可能导致崩溃
|
||||
func processData(data: [String]?) {
|
||||
let items = data! // 强制解包
|
||||
for item in items {
|
||||
print(item)
|
||||
}
|
||||
}
|
||||
|
||||
// 内存泄漏风险:循环引用
|
||||
var closure: (() -> Void)?
|
||||
func setupClosure() {
|
||||
closure = {
|
||||
print(self.password) // 未使用 [weak self]
|
||||
}
|
||||
}
|
||||
}`,
|
||||
kotlin: `// 示例Kotlin代码 - 包含多种问题
|
||||
class UserManager {
|
||||
private val password = "admin123" // 硬编码密码
|
||||
|
||||
fun validateUser(input: String): Boolean {
|
||||
if (input == password) { // 直接比较密码
|
||||
println("User validated") // 使用println而非日志
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// 空指针风险
|
||||
fun processData(data: List<String>?) {
|
||||
val items = data!! // 强制非空断言
|
||||
for (item in items) {
|
||||
println(item)
|
||||
}
|
||||
}
|
||||
|
||||
// 性能问题:循环中重复计算
|
||||
fun inefficientLoop(items: List<String>) {
|
||||
for (i in 0 until items.size) {
|
||||
for (j in 0 until items.size) { // O(n²) 复杂度
|
||||
println(items[i] + items[j])
|
||||
}
|
||||
}
|
||||
}
|
||||
}`
|
||||
};
|
||||
|
||||
|
|
@ -231,7 +290,9 @@ public class Example {
|
|||
'hh': 'cpp',
|
||||
'cs': 'csharp',
|
||||
'php': 'php',
|
||||
'rb': 'ruby'
|
||||
'rb': 'ruby',
|
||||
'swift': 'swift',
|
||||
'kt': 'kotlin'
|
||||
};
|
||||
|
||||
if (extension && languageMap[extension]) {
|
||||
|
|
@ -526,7 +587,7 @@ public class Example {
|
|||
<input
|
||||
ref={fileInputRef}
|
||||
type="file"
|
||||
accept=".js,.jsx,.ts,.tsx,.py,.java,.go,.rs,.cpp,.c,.cc,.h,.hh,.cs,.php,.rb"
|
||||
accept=".js,.jsx,.ts,.tsx,.py,.java,.go,.rs,.cpp,.c,.cc,.h,.hh,.cs,.php,.rb,.swift,.kt"
|
||||
onChange={handleFileUpload}
|
||||
className="hidden"
|
||||
/>
|
||||
|
|
@ -562,6 +623,24 @@ public class Example {
|
|||
>
|
||||
Java
|
||||
</Button>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={() => loadExampleCode('swift')}
|
||||
disabled={analyzing}
|
||||
className="h-7 px-2 text-xs"
|
||||
>
|
||||
Swift
|
||||
</Button>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={() => loadExampleCode('kotlin')}
|
||||
disabled={analyzing}
|
||||
className="h-7 px-2 text-xs"
|
||||
>
|
||||
Kotlin
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
{/* 代码编辑器 */}
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ import { loadZipFile } from "@/shared/utils/zipStorage";
|
|||
import { toast } from "sonner";
|
||||
import CreateTaskDialog from "@/components/audit/CreateTaskDialog";
|
||||
import TerminalProgressDialog from "@/components/audit/TerminalProgressDialog";
|
||||
import { SUPPORTED_LANGUAGES } from "@/shared/constants";
|
||||
|
||||
export default function ProjectDetail() {
|
||||
const { id } = useParams<{ id: string }>();
|
||||
|
|
@ -50,9 +51,26 @@ export default function ProjectDetail() {
|
|||
programming_languages: []
|
||||
});
|
||||
|
||||
const supportedLanguages = [
|
||||
'JavaScript', 'TypeScript', 'Python', 'Java', 'Go', 'Rust', 'C++', 'C#', 'PHP', 'Ruby'
|
||||
];
|
||||
// 将小写语言名转换为显示格式
|
||||
const formatLanguageName = (lang: string): string => {
|
||||
const nameMap: Record<string, string> = {
|
||||
'javascript': 'JavaScript',
|
||||
'typescript': 'TypeScript',
|
||||
'python': 'Python',
|
||||
'java': 'Java',
|
||||
'go': 'Go',
|
||||
'rust': 'Rust',
|
||||
'cpp': 'C++',
|
||||
'csharp': 'C#',
|
||||
'php': 'PHP',
|
||||
'ruby': 'Ruby',
|
||||
'swift': 'Swift',
|
||||
'kotlin': 'Kotlin'
|
||||
};
|
||||
return nameMap[lang] || lang.charAt(0).toUpperCase() + lang.slice(1);
|
||||
};
|
||||
|
||||
const supportedLanguages = SUPPORTED_LANGUAGES.map(formatLanguageName);
|
||||
|
||||
useEffect(() => {
|
||||
if (id) {
|
||||
|
|
@ -83,16 +101,18 @@ export default function ProjectDetail() {
|
|||
const handleRunAudit = async () => {
|
||||
if (!project || !id) return;
|
||||
|
||||
// 如果是GitHub项目且有仓库地址,直接启动审计
|
||||
if (project.repository_type === 'github' && project.repository_url) {
|
||||
// 检查是否有仓库地址
|
||||
if (project.repository_url) {
|
||||
// 有仓库地址,启动仓库审计
|
||||
try {
|
||||
setScanning(true);
|
||||
console.log('开始启动审计任务...');
|
||||
console.log('开始启动仓库审计任务...');
|
||||
const taskId = await runRepositoryAudit({
|
||||
projectId: id,
|
||||
repoUrl: project.repository_url,
|
||||
branch: project.default_branch || 'main',
|
||||
githubToken: undefined,
|
||||
gitlabToken: undefined,
|
||||
createdBy: undefined
|
||||
});
|
||||
|
||||
|
|
@ -111,7 +131,7 @@ export default function ProjectDetail() {
|
|||
setScanning(false);
|
||||
}
|
||||
} else {
|
||||
// 对于ZIP项目,尝试从IndexedDB加载保存的文件
|
||||
// 没有仓库地址,尝试从IndexedDB加载保存的ZIP文件
|
||||
try {
|
||||
setScanning(true);
|
||||
const file = await loadZipFile(id);
|
||||
|
|
@ -143,14 +163,13 @@ export default function ProjectDetail() {
|
|||
}
|
||||
} else {
|
||||
setScanning(false);
|
||||
toast.error('未找到保存的ZIP文件,请通过"新建任务"上传');
|
||||
setShowCreateTaskDialog(true);
|
||||
toast.warning('此项目未配置仓库地址,也未上传ZIP文件。请先在项目设置中配置仓库地址,或通过"新建任务"上传ZIP文件。');
|
||||
// 不自动打开对话框,让用户自己选择
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('启动审计失败:', error);
|
||||
setScanning(false);
|
||||
toast.error('读取ZIP文件失败,请通过"新建任务"重新上传');
|
||||
setShowCreateTaskDialog(true);
|
||||
toast.error('读取ZIP文件失败,请检查项目配置');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ import { saveZipFile } from "@/shared/utils/zipStorage";
|
|||
import { Link } from "react-router-dom";
|
||||
import { toast } from "sonner";
|
||||
import CreateTaskDialog from "@/components/audit/CreateTaskDialog";
|
||||
import { SUPPORTED_LANGUAGES } from "@/shared/constants";
|
||||
|
||||
export default function Projects() {
|
||||
const [projects, setProjects] = useState<Project[]>([]);
|
||||
|
|
@ -67,9 +68,26 @@ export default function Projects() {
|
|||
programming_languages: []
|
||||
});
|
||||
|
||||
const supportedLanguages = [
|
||||
'JavaScript', 'TypeScript', 'Python', 'Java', 'Go', 'Rust', 'C++', 'C#', 'PHP', 'Ruby'
|
||||
];
|
||||
// 将小写语言名转换为显示格式
|
||||
const formatLanguageName = (lang: string): string => {
|
||||
const nameMap: Record<string, string> = {
|
||||
'javascript': 'JavaScript',
|
||||
'typescript': 'TypeScript',
|
||||
'python': 'Python',
|
||||
'java': 'Java',
|
||||
'go': 'Go',
|
||||
'rust': 'Rust',
|
||||
'cpp': 'C++',
|
||||
'csharp': 'C#',
|
||||
'php': 'PHP',
|
||||
'ruby': 'Ruby',
|
||||
'swift': 'Swift',
|
||||
'kotlin': 'Kotlin'
|
||||
};
|
||||
return nameMap[lang] || lang.charAt(0).toUpperCase() + lang.slice(1);
|
||||
};
|
||||
|
||||
const supportedLanguages = SUPPORTED_LANGUAGES.map(formatLanguageName);
|
||||
|
||||
useEffect(() => {
|
||||
loadProjects();
|
||||
|
|
|
|||
Loading…
Reference in New Issue