super-dev 2.0.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- super_dev/__init__.py +11 -0
- super_dev/analyzer/__init__.py +34 -0
- super_dev/analyzer/analyzer.py +440 -0
- super_dev/analyzer/detectors.py +511 -0
- super_dev/analyzer/models.py +285 -0
- super_dev/cli.py +3257 -0
- super_dev/config/__init__.py +11 -0
- super_dev/config/frontend.py +557 -0
- super_dev/config/manager.py +281 -0
- super_dev/creators/__init__.py +26 -0
- super_dev/creators/creator.py +134 -0
- super_dev/creators/document_generator.py +2473 -0
- super_dev/creators/frontend_builder.py +371 -0
- super_dev/creators/implementation_builder.py +789 -0
- super_dev/creators/prompt_generator.py +289 -0
- super_dev/creators/requirement_parser.py +354 -0
- super_dev/creators/spec_builder.py +195 -0
- super_dev/deployers/__init__.py +20 -0
- super_dev/deployers/cicd.py +1269 -0
- super_dev/deployers/delivery.py +229 -0
- super_dev/deployers/migration.py +1032 -0
- super_dev/design/__init__.py +74 -0
- super_dev/design/aesthetics.py +530 -0
- super_dev/design/charts.py +396 -0
- super_dev/design/codegen.py +379 -0
- super_dev/design/engine.py +528 -0
- super_dev/design/generator.py +395 -0
- super_dev/design/landing.py +422 -0
- super_dev/design/tech_stack.py +524 -0
- super_dev/design/tokens.py +269 -0
- super_dev/design/ux_guide.py +391 -0
- super_dev/exceptions.py +119 -0
- super_dev/experts/__init__.py +19 -0
- super_dev/experts/service.py +161 -0
- super_dev/integrations/__init__.py +7 -0
- super_dev/integrations/manager.py +264 -0
- super_dev/orchestrator/__init__.py +12 -0
- super_dev/orchestrator/engine.py +958 -0
- super_dev/orchestrator/experts.py +423 -0
- super_dev/orchestrator/knowledge.py +352 -0
- super_dev/orchestrator/quality.py +356 -0
- super_dev/reviewers/__init__.py +17 -0
- super_dev/reviewers/code_review.py +471 -0
- super_dev/reviewers/quality_gate.py +964 -0
- super_dev/reviewers/redteam.py +881 -0
- super_dev/skills/__init__.py +7 -0
- super_dev/skills/manager.py +307 -0
- super_dev/specs/__init__.py +44 -0
- super_dev/specs/generator.py +264 -0
- super_dev/specs/manager.py +428 -0
- super_dev/specs/models.py +348 -0
- super_dev/specs/validator.py +415 -0
- super_dev/utils/__init__.py +11 -0
- super_dev/utils/logger.py +133 -0
- super_dev/web/api.py +1402 -0
- super_dev-2.0.0.dist-info/METADATA +252 -0
- super_dev-2.0.0.dist-info/RECORD +61 -0
- super_dev-2.0.0.dist-info/WHEEL +5 -0
- super_dev-2.0.0.dist-info/entry_points.txt +2 -0
- super_dev-2.0.0.dist-info/licenses/LICENSE +21 -0
- super_dev-2.0.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,511 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Super Dev 项目类型检测器
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import json
|
|
6
|
+
import re
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
|
|
9
|
+
# 尝试导入 TOML 解析库
|
|
10
|
+
try:
|
|
11
|
+
import tomllib # Python 3.11+
|
|
12
|
+
except ImportError:
|
|
13
|
+
try:
|
|
14
|
+
import tomli as tomllib # Python < 3.11
|
|
15
|
+
except ImportError:
|
|
16
|
+
tomllib = None
|
|
17
|
+
|
|
18
|
+
from .models import (
|
|
19
|
+
ArchitecturePattern,
|
|
20
|
+
Dependency,
|
|
21
|
+
FrameworkType,
|
|
22
|
+
ProjectCategory,
|
|
23
|
+
TechStack,
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def detect_project_type(project_path: Path) -> ProjectCategory:
|
|
28
|
+
"""
|
|
29
|
+
检测项目类型
|
|
30
|
+
|
|
31
|
+
Args:
|
|
32
|
+
project_path: 项目根目录路径
|
|
33
|
+
|
|
34
|
+
Returns:
|
|
35
|
+
ProjectCategory: 项目类型
|
|
36
|
+
"""
|
|
37
|
+
project_path = Path(project_path).resolve()
|
|
38
|
+
|
|
39
|
+
# 检查关键文件
|
|
40
|
+
package_json = project_path / "package.json"
|
|
41
|
+
requirements_txt = project_path / "requirements.txt"
|
|
42
|
+
pyproject_toml = project_path / "pyproject.toml"
|
|
43
|
+
go_mod = project_path / "go.mod"
|
|
44
|
+
cargo_toml = project_path / "Cargo.toml"
|
|
45
|
+
pom_xml = project_path / "pom.xml"
|
|
46
|
+
build_gradle = project_path / "build.gradle"
|
|
47
|
+
gemfile = project_path / "Gemfile"
|
|
48
|
+
composer_json = project_path / "composer.json"
|
|
49
|
+
|
|
50
|
+
# 检测前后端项目
|
|
51
|
+
if package_json.exists():
|
|
52
|
+
return _detect_node_project_type(project_path)
|
|
53
|
+
|
|
54
|
+
if requirements_txt.exists() or pyproject_toml.exists():
|
|
55
|
+
return _detect_python_project_type(project_path)
|
|
56
|
+
|
|
57
|
+
if go_mod.exists():
|
|
58
|
+
return ProjectCategory.BACKEND
|
|
59
|
+
|
|
60
|
+
if cargo_toml.exists():
|
|
61
|
+
return ProjectCategory.BACKEND
|
|
62
|
+
|
|
63
|
+
if pom_xml.exists() or build_gradle.exists():
|
|
64
|
+
return ProjectCategory.BACKEND
|
|
65
|
+
|
|
66
|
+
if gemfile.exists():
|
|
67
|
+
return ProjectCategory.BACKEND
|
|
68
|
+
|
|
69
|
+
if composer_json.exists():
|
|
70
|
+
# 可能是前端或后端
|
|
71
|
+
return _detect_php_project_type(project_path)
|
|
72
|
+
|
|
73
|
+
# 检查是否有 Android/iOS 项目
|
|
74
|
+
if (project_path / "android").exists() or (project_path / "ios").exists():
|
|
75
|
+
return ProjectCategory.MOBILE
|
|
76
|
+
|
|
77
|
+
# 检查 Electron 项目
|
|
78
|
+
if package_json.exists():
|
|
79
|
+
try:
|
|
80
|
+
with open(package_json, encoding="utf-8") as f:
|
|
81
|
+
data = json.load(f)
|
|
82
|
+
deps = data.get("dependencies", {})
|
|
83
|
+
dev_deps = data.get("devDependencies", {})
|
|
84
|
+
|
|
85
|
+
if "electron" in deps or "electron" in dev_deps:
|
|
86
|
+
return ProjectCategory.DESKTOP
|
|
87
|
+
except (OSError, json.JSONDecodeError):
|
|
88
|
+
pass
|
|
89
|
+
|
|
90
|
+
return ProjectCategory.UNKNOWN
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def _detect_node_project_type(project_path: Path) -> ProjectCategory:
|
|
94
|
+
"""检测 Node.js 项目类型"""
|
|
95
|
+
package_json = project_path / "package.json"
|
|
96
|
+
|
|
97
|
+
try:
|
|
98
|
+
with open(package_json, encoding="utf-8") as f:
|
|
99
|
+
data = json.load(f)
|
|
100
|
+
deps = data.get("dependencies", {})
|
|
101
|
+
dev_deps = data.get("devDependencies", {})
|
|
102
|
+
|
|
103
|
+
all_deps = {**deps, **dev_deps}
|
|
104
|
+
|
|
105
|
+
# 检测前端框架
|
|
106
|
+
frontend_frameworks = [
|
|
107
|
+
"react", "react-dom", "vue", "vue-router", "@angular/core",
|
|
108
|
+
"angular", "svelte", "next", "nuxt", "@remix-run/react",
|
|
109
|
+
]
|
|
110
|
+
|
|
111
|
+
has_frontend = any(fw in all_deps for fw in frontend_frameworks)
|
|
112
|
+
|
|
113
|
+
# 检测后端框架
|
|
114
|
+
backend_frameworks = [
|
|
115
|
+
"express", "fastify", "koa", "nest", "@nestjs/common",
|
|
116
|
+
"hapi", "feathers", "socket.io",
|
|
117
|
+
]
|
|
118
|
+
|
|
119
|
+
has_backend = any(bw in all_deps for bw in backend_frameworks)
|
|
120
|
+
|
|
121
|
+
if has_frontend and has_backend:
|
|
122
|
+
return ProjectCategory.FULLSTACK
|
|
123
|
+
elif has_frontend:
|
|
124
|
+
return ProjectCategory.FRONTEND
|
|
125
|
+
elif has_backend:
|
|
126
|
+
return ProjectCategory.BACKEND
|
|
127
|
+
|
|
128
|
+
# 检查是否是 serverless
|
|
129
|
+
if "serverless" in all_deps or "aws-lambda" in all_deps:
|
|
130
|
+
return ProjectCategory.SERVERLESS
|
|
131
|
+
|
|
132
|
+
return ProjectCategory.BACKEND # 默认为后端
|
|
133
|
+
|
|
134
|
+
except (OSError, json.JSONDecodeError):
|
|
135
|
+
return ProjectCategory.UNKNOWN
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
def _detect_python_project_type(project_path: Path) -> ProjectCategory:
|
|
139
|
+
"""检测 Python 项目类型"""
|
|
140
|
+
requirements_txt = project_path / "requirements.txt"
|
|
141
|
+
pyproject_toml = project_path / "pyproject.toml"
|
|
142
|
+
|
|
143
|
+
dependencies = set()
|
|
144
|
+
|
|
145
|
+
if requirements_txt.exists():
|
|
146
|
+
try:
|
|
147
|
+
with open(requirements_txt, encoding="utf-8") as f:
|
|
148
|
+
for line in f:
|
|
149
|
+
line = line.strip()
|
|
150
|
+
if line and not line.startswith("#"):
|
|
151
|
+
# 提取包名
|
|
152
|
+
match = re.match(r"^([a-zA-Z0-9_-]+)", line)
|
|
153
|
+
if match:
|
|
154
|
+
dependencies.add(match.group(1).lower())
|
|
155
|
+
except OSError:
|
|
156
|
+
pass
|
|
157
|
+
|
|
158
|
+
if pyproject_toml.exists() and tomllib is not None:
|
|
159
|
+
try:
|
|
160
|
+
with open(pyproject_toml, "rb") as f:
|
|
161
|
+
data = tomllib.load(f)
|
|
162
|
+
deps = data.get("project", {}).get("dependencies", [])
|
|
163
|
+
dependencies.update(d.lower().split(">=")[0].split("==")[0] for d in deps)
|
|
164
|
+
except Exception:
|
|
165
|
+
dependencies.update(set())
|
|
166
|
+
|
|
167
|
+
# 检测 Web 框架
|
|
168
|
+
web_frameworks = {
|
|
169
|
+
"django", "flask", "fastapi", "starlette", "tornado",
|
|
170
|
+
"aiohttp", "sanic", "quart",
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
has_web = any(fw in dependencies for fw in web_frameworks)
|
|
174
|
+
|
|
175
|
+
# 检测前端相关
|
|
176
|
+
frontend_related = {
|
|
177
|
+
"webpack", "vite", "rollup", "parcel",
|
|
178
|
+
"react", "vue", "angular",
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
has_frontend = any(fr in dependencies for fr in frontend_related)
|
|
182
|
+
|
|
183
|
+
if has_frontend and has_web:
|
|
184
|
+
return ProjectCategory.FULLSTACK
|
|
185
|
+
elif has_web:
|
|
186
|
+
return ProjectCategory.BACKEND
|
|
187
|
+
|
|
188
|
+
return ProjectCategory.BACKEND
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
def _detect_php_project_type(project_path: Path) -> ProjectCategory:
|
|
192
|
+
"""检测 PHP 项目类型"""
|
|
193
|
+
composer_json = project_path / "composer.json"
|
|
194
|
+
|
|
195
|
+
try:
|
|
196
|
+
with open(composer_json, encoding="utf-8") as f:
|
|
197
|
+
data = json.load(f)
|
|
198
|
+
deps = data.get("require", {})
|
|
199
|
+
|
|
200
|
+
# Laravel/Symfony 等通常是后端
|
|
201
|
+
if any(fw in deps for fw in ["laravel/framework", "symfony/http-kernel"]):
|
|
202
|
+
return ProjectCategory.BACKEND
|
|
203
|
+
|
|
204
|
+
except (OSError, json.JSONDecodeError):
|
|
205
|
+
pass
|
|
206
|
+
|
|
207
|
+
return ProjectCategory.BACKEND
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
def detect_tech_stack(project_path: Path) -> TechStack:
|
|
211
|
+
"""
|
|
212
|
+
检测技术栈
|
|
213
|
+
|
|
214
|
+
Args:
|
|
215
|
+
project_path: 项目根目录路径
|
|
216
|
+
|
|
217
|
+
Returns:
|
|
218
|
+
TechStack: 技术栈信息
|
|
219
|
+
"""
|
|
220
|
+
project_path = Path(project_path).resolve()
|
|
221
|
+
category = detect_project_type(project_path)
|
|
222
|
+
|
|
223
|
+
package_json = project_path / "package.json"
|
|
224
|
+
requirements_txt = project_path / "requirements.txt"
|
|
225
|
+
pyproject_toml = project_path / "pyproject.toml"
|
|
226
|
+
go_mod = project_path / "go.mod"
|
|
227
|
+
|
|
228
|
+
# Node.js 项目
|
|
229
|
+
if package_json.exists():
|
|
230
|
+
return _detect_node_tech_stack(project_path, category)
|
|
231
|
+
|
|
232
|
+
# Python 项目
|
|
233
|
+
if requirements_txt.exists() or pyproject_toml.exists():
|
|
234
|
+
return _detect_python_tech_stack(project_path, category)
|
|
235
|
+
|
|
236
|
+
# Go 项目
|
|
237
|
+
if go_mod.exists():
|
|
238
|
+
return _detect_go_tech_stack(project_path, category)
|
|
239
|
+
|
|
240
|
+
# 默认返回
|
|
241
|
+
return TechStack(
|
|
242
|
+
category=category,
|
|
243
|
+
language="unknown",
|
|
244
|
+
framework=FrameworkType.UNKNOWN,
|
|
245
|
+
)
|
|
246
|
+
|
|
247
|
+
|
|
248
|
+
def _detect_node_tech_stack(project_path: Path, category: ProjectCategory) -> TechStack:
|
|
249
|
+
"""检测 Node.js 技术栈"""
|
|
250
|
+
package_json = project_path / "package.json"
|
|
251
|
+
|
|
252
|
+
try:
|
|
253
|
+
with open(package_json, encoding="utf-8") as f:
|
|
254
|
+
data = json.load(f)
|
|
255
|
+
deps = data.get("dependencies", {})
|
|
256
|
+
dev_deps = data.get("devDependencies", {})
|
|
257
|
+
|
|
258
|
+
all_deps = {**deps, **dev_deps}
|
|
259
|
+
|
|
260
|
+
# 检测框架
|
|
261
|
+
framework = FrameworkType.UNKNOWN
|
|
262
|
+
if "next" in all_deps:
|
|
263
|
+
framework = FrameworkType.NEXTJS
|
|
264
|
+
elif "nuxt" in all_deps:
|
|
265
|
+
framework = FrameworkType.NUXT
|
|
266
|
+
elif "@remix-run/react" in all_deps:
|
|
267
|
+
framework = FrameworkType.REMIX
|
|
268
|
+
elif "react" in all_deps or "react-dom" in all_deps:
|
|
269
|
+
framework = FrameworkType.REACT
|
|
270
|
+
elif "vue" in all_deps:
|
|
271
|
+
framework = FrameworkType.VUE
|
|
272
|
+
elif "@angular/core" in all_deps or "angular" in all_deps:
|
|
273
|
+
framework = FrameworkType.ANGULAR
|
|
274
|
+
elif "svelte" in all_deps:
|
|
275
|
+
framework = FrameworkType.SVELTE
|
|
276
|
+
elif "express" in all_deps:
|
|
277
|
+
framework = FrameworkType.EXPRESS
|
|
278
|
+
|
|
279
|
+
# 检测 UI 库
|
|
280
|
+
ui_library = ""
|
|
281
|
+
ui_libraries = [
|
|
282
|
+
"@mui/material", "@chakra-ui/react", "@mantine/core",
|
|
283
|
+
"antd", "react-bootstrap", "tailwindcss",
|
|
284
|
+
"element-plus", "vuetify", "antd-mobile",
|
|
285
|
+
]
|
|
286
|
+
for lib in ui_libraries:
|
|
287
|
+
if lib in all_deps:
|
|
288
|
+
ui_library = lib
|
|
289
|
+
break
|
|
290
|
+
|
|
291
|
+
# 检测状态管理
|
|
292
|
+
state_management = ""
|
|
293
|
+
state_libs = [
|
|
294
|
+
"redux", "@reduxjs/toolkit", "zustand", "jotai",
|
|
295
|
+
"recoil", "mobx", "pinia", "vuex",
|
|
296
|
+
]
|
|
297
|
+
for lib in state_libs:
|
|
298
|
+
if lib in all_deps:
|
|
299
|
+
state_management = lib
|
|
300
|
+
break
|
|
301
|
+
|
|
302
|
+
# 检测构建工具
|
|
303
|
+
build_tool = ""
|
|
304
|
+
build_tools = [
|
|
305
|
+
"vite", "webpack", "rollup", "parcel",
|
|
306
|
+
"esbuild", "turbo",
|
|
307
|
+
]
|
|
308
|
+
for tool in build_tools:
|
|
309
|
+
if tool in all_deps:
|
|
310
|
+
build_tool = tool
|
|
311
|
+
break
|
|
312
|
+
|
|
313
|
+
# 检测测试框架
|
|
314
|
+
testing_framework = ""
|
|
315
|
+
test_frameworks = [
|
|
316
|
+
"jest", "vitest", "@testing-library/react",
|
|
317
|
+
"mocha", "chai", "jasmine",
|
|
318
|
+
]
|
|
319
|
+
for fw in test_frameworks:
|
|
320
|
+
if fw in all_deps:
|
|
321
|
+
testing_framework = fw
|
|
322
|
+
break
|
|
323
|
+
|
|
324
|
+
# 解析依赖
|
|
325
|
+
dependencies = []
|
|
326
|
+
for name, version in deps.items():
|
|
327
|
+
dependencies.append(
|
|
328
|
+
Dependency(
|
|
329
|
+
name=name,
|
|
330
|
+
version=str(version),
|
|
331
|
+
type="prod",
|
|
332
|
+
)
|
|
333
|
+
)
|
|
334
|
+
|
|
335
|
+
return TechStack(
|
|
336
|
+
category=category,
|
|
337
|
+
language="javascript" if framework != FrameworkType.NEXTJS else "typescript",
|
|
338
|
+
framework=framework,
|
|
339
|
+
ui_library=ui_library,
|
|
340
|
+
state_management=state_management,
|
|
341
|
+
build_tool=build_tool,
|
|
342
|
+
testing_framework=testing_framework,
|
|
343
|
+
dependencies=dependencies,
|
|
344
|
+
)
|
|
345
|
+
|
|
346
|
+
except (OSError, json.JSONDecodeError):
|
|
347
|
+
return TechStack(
|
|
348
|
+
category=category,
|
|
349
|
+
language="javascript",
|
|
350
|
+
framework=FrameworkType.UNKNOWN,
|
|
351
|
+
)
|
|
352
|
+
|
|
353
|
+
|
|
354
|
+
def _detect_python_tech_stack(project_path: Path, category: ProjectCategory) -> TechStack:
|
|
355
|
+
"""检测 Python 技术栈"""
|
|
356
|
+
requirements_txt = project_path / "requirements.txt"
|
|
357
|
+
|
|
358
|
+
dependencies = []
|
|
359
|
+
framework = FrameworkType.UNKNOWN
|
|
360
|
+
testing_framework = ""
|
|
361
|
+
|
|
362
|
+
# 解析依赖
|
|
363
|
+
if requirements_txt.exists():
|
|
364
|
+
try:
|
|
365
|
+
with open(requirements_txt, encoding="utf-8") as f:
|
|
366
|
+
for line in f:
|
|
367
|
+
line = line.strip()
|
|
368
|
+
if line and not line.startswith("#"):
|
|
369
|
+
# 解析 requirement
|
|
370
|
+
match = re.match(r"^([a-zA-Z0-9_-]+)([>=<~]+(.+))?", line)
|
|
371
|
+
if match:
|
|
372
|
+
name = match.group(1)
|
|
373
|
+
version = match.group(3) or ""
|
|
374
|
+
dependencies.append(
|
|
375
|
+
Dependency(
|
|
376
|
+
name=name,
|
|
377
|
+
version=version,
|
|
378
|
+
type="prod",
|
|
379
|
+
)
|
|
380
|
+
)
|
|
381
|
+
except OSError:
|
|
382
|
+
pass
|
|
383
|
+
|
|
384
|
+
# 检测框架
|
|
385
|
+
dep_names = {d.name.lower() for d in dependencies}
|
|
386
|
+
|
|
387
|
+
if "django" in dep_names:
|
|
388
|
+
framework = FrameworkType.DJANGO
|
|
389
|
+
elif "fastapi" in dep_names:
|
|
390
|
+
framework = FrameworkType.FASTAPI
|
|
391
|
+
elif "flask" in dep_names:
|
|
392
|
+
framework = FrameworkType.FLASK
|
|
393
|
+
|
|
394
|
+
# 检测测试框架
|
|
395
|
+
test_frameworks = ["pytest", "unittest", "nose2"]
|
|
396
|
+
for fw in test_frameworks:
|
|
397
|
+
if fw in dep_names:
|
|
398
|
+
testing_framework = fw
|
|
399
|
+
break
|
|
400
|
+
|
|
401
|
+
return TechStack(
|
|
402
|
+
category=category,
|
|
403
|
+
language="python",
|
|
404
|
+
framework=framework,
|
|
405
|
+
testing_framework=testing_framework,
|
|
406
|
+
dependencies=dependencies,
|
|
407
|
+
)
|
|
408
|
+
|
|
409
|
+
|
|
410
|
+
def _detect_go_tech_stack(project_path: Path, category: ProjectCategory) -> TechStack:
|
|
411
|
+
"""检测 Go 技术栈"""
|
|
412
|
+
go_mod = project_path / "go.mod"
|
|
413
|
+
|
|
414
|
+
dependencies = []
|
|
415
|
+
|
|
416
|
+
try:
|
|
417
|
+
with open(go_mod, encoding="utf-8") as f:
|
|
418
|
+
content = f.read()
|
|
419
|
+
# 解析 require 部分
|
|
420
|
+
require_match = re.search(r"require \((.*?)\)", content, re.DOTALL)
|
|
421
|
+
if require_match:
|
|
422
|
+
for line in require_match.group(1).split("\n"):
|
|
423
|
+
line = line.strip()
|
|
424
|
+
match = re.match(r"^([^\s]+)\s+([^\s]+)", line)
|
|
425
|
+
if match:
|
|
426
|
+
dependencies.append(
|
|
427
|
+
Dependency(
|
|
428
|
+
name=match.group(1),
|
|
429
|
+
version=match.group(2),
|
|
430
|
+
type="prod",
|
|
431
|
+
)
|
|
432
|
+
)
|
|
433
|
+
|
|
434
|
+
# 检测框架
|
|
435
|
+
dep_names = {d.name.lower() for d in dependencies}
|
|
436
|
+
|
|
437
|
+
framework = FrameworkType.UNKNOWN
|
|
438
|
+
if "github.com/gin-gonic/gin" in dep_names:
|
|
439
|
+
framework = FrameworkType.GIN
|
|
440
|
+
elif "github.com/labstack/echo/v4" in dep_names:
|
|
441
|
+
framework = FrameworkType.ECHO
|
|
442
|
+
|
|
443
|
+
return TechStack(
|
|
444
|
+
category=category,
|
|
445
|
+
language="go",
|
|
446
|
+
framework=framework,
|
|
447
|
+
dependencies=dependencies,
|
|
448
|
+
)
|
|
449
|
+
|
|
450
|
+
except OSError:
|
|
451
|
+
return TechStack(
|
|
452
|
+
category=category,
|
|
453
|
+
language="go",
|
|
454
|
+
framework=FrameworkType.UNKNOWN,
|
|
455
|
+
)
|
|
456
|
+
|
|
457
|
+
|
|
458
|
+
def detect_architecture_pattern(project_path: Path) -> ArchitecturePattern | None:
|
|
459
|
+
"""
|
|
460
|
+
检测架构模式
|
|
461
|
+
|
|
462
|
+
Args:
|
|
463
|
+
project_path: 项目根目录路径
|
|
464
|
+
|
|
465
|
+
Returns:
|
|
466
|
+
ArchitecturePattern | None: 架构模式
|
|
467
|
+
"""
|
|
468
|
+
project_path = Path(project_path).resolve()
|
|
469
|
+
package_json = project_path / "package.json"
|
|
470
|
+
|
|
471
|
+
# 检查目录结构
|
|
472
|
+
dirs = [d.name for d in project_path.iterdir() if d.is_dir()]
|
|
473
|
+
|
|
474
|
+
# 微服务架构
|
|
475
|
+
if "services" in dirs or "microservices" in dirs:
|
|
476
|
+
return ArchitecturePattern.MICROSERVICES
|
|
477
|
+
|
|
478
|
+
# 检查 Node.js 项目架构
|
|
479
|
+
if package_json.exists():
|
|
480
|
+
return _detect_node_architecture(project_path, dirs)
|
|
481
|
+
|
|
482
|
+
# 分层架构(默认)
|
|
483
|
+
if any(d in dirs for d in ["src", "lib", "app", "server"]):
|
|
484
|
+
return ArchitecturePattern.LAYERED
|
|
485
|
+
|
|
486
|
+
return None
|
|
487
|
+
|
|
488
|
+
|
|
489
|
+
def _detect_node_architecture(project_path: Path, dirs: list[str]) -> ArchitecturePattern | None:
|
|
490
|
+
"""检测 Node.js 项目架构"""
|
|
491
|
+
src_dir = project_path / "src"
|
|
492
|
+
|
|
493
|
+
if src_dir.exists():
|
|
494
|
+
src_dirs = [d.name for d in src_dir.iterdir() if d.is_dir()]
|
|
495
|
+
|
|
496
|
+
# MVC/MVVM 检测
|
|
497
|
+
has_models = "models" in src_dirs or "entities" in src_dirs
|
|
498
|
+
has_views = "views" in src_dirs or "components" in src_dirs
|
|
499
|
+
has_controllers = "controllers" in src_dirs or "handlers" in src_dirs
|
|
500
|
+
|
|
501
|
+
if has_models and has_views and has_controllers:
|
|
502
|
+
return ArchitecturePattern.MVC
|
|
503
|
+
|
|
504
|
+
# 整洁架构检测
|
|
505
|
+
clean_arch_indicators = [
|
|
506
|
+
"domain", "use-cases", "application", "infrastructure",
|
|
507
|
+
]
|
|
508
|
+
if any(ind in src_dirs for ind in clean_arch_indicators):
|
|
509
|
+
return ArchitecturePattern.CLEAN_ARCHITECTURE
|
|
510
|
+
|
|
511
|
+
return ArchitecturePattern.LAYERED
|