dash-devtools 1.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.
Files changed (53) hide show
  1. dash_devtools/__init__.py +8 -0
  2. dash_devtools/__main__.py +11 -0
  3. dash_devtools/ai_engine.py +441 -0
  4. dash_devtools/browser.py +541 -0
  5. dash_devtools/cli.py +1452 -0
  6. dash_devtools/database.py +338 -0
  7. dash_devtools/dbdiagram.py +183 -0
  8. dash_devtools/e2e.py +329 -0
  9. dash_devtools/fixers/__init__.py +57 -0
  10. dash_devtools/fixers/migration_fixer.py +115 -0
  11. dash_devtools/fixers/ux_fixer.py +106 -0
  12. dash_devtools/fixers/version_bumper.py +115 -0
  13. dash_devtools/gas_mes_test.py +1241 -0
  14. dash_devtools/generators/__init__.py +84 -0
  15. dash_devtools/health.py +476 -0
  16. dash_devtools/hooks/__init__.py +250 -0
  17. dash_devtools/hooks/pre_commit.py +161 -0
  18. dash_devtools/hooks/pre_push.py +275 -0
  19. dash_devtools/init_test.py +352 -0
  20. dash_devtools/markdown_report.py +309 -0
  21. dash_devtools/migrators/__init__.py +21 -0
  22. dash_devtools/perf.py +321 -0
  23. dash_devtools/report.py +667 -0
  24. dash_devtools/reporters/__init__.py +11 -0
  25. dash_devtools/spec.py +230 -0
  26. dash_devtools/stats.py +355 -0
  27. dash_devtools/test_suite.py +690 -0
  28. dash_devtools/testing.py +416 -0
  29. dash_devtools/validators/__init__.py +157 -0
  30. dash_devtools/validators/backend/__init__.py +12 -0
  31. dash_devtools/validators/backend/nodejs.py +245 -0
  32. dash_devtools/validators/backend/python.py +439 -0
  33. dash_devtools/validators/code_quality.py +243 -0
  34. dash_devtools/validators/common/__init__.py +11 -0
  35. dash_devtools/validators/common/quality.py +319 -0
  36. dash_devtools/validators/common/security.py +270 -0
  37. dash_devtools/validators/common/spec.py +273 -0
  38. dash_devtools/validators/detector.py +394 -0
  39. dash_devtools/validators/frontend/__init__.py +14 -0
  40. dash_devtools/validators/frontend/angular.py +245 -0
  41. dash_devtools/validators/frontend/gas.py +310 -0
  42. dash_devtools/validators/frontend/vite.py +539 -0
  43. dash_devtools/validators/migration.py +292 -0
  44. dash_devtools/validators/performance.py +167 -0
  45. dash_devtools/validators/security.py +205 -0
  46. dash_devtools/vision/__init__.py +368 -0
  47. dash_devtools/watch.py +266 -0
  48. dash_devtools/word_report.py +690 -0
  49. dash_devtools-1.0.0.dist-info/METADATA +834 -0
  50. dash_devtools-1.0.0.dist-info/RECORD +53 -0
  51. dash_devtools-1.0.0.dist-info/WHEEL +5 -0
  52. dash_devtools-1.0.0.dist-info/entry_points.txt +2 -0
  53. dash_devtools-1.0.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,8 @@
1
+ """
2
+ DashAI DevTools - 大許開發工具集
3
+
4
+ 統一的開發、驗證、遷移工具
5
+ """
6
+
7
+ __version__ = "1.0.0"
8
+ __author__ = "DashAI"
@@ -0,0 +1,11 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ DashAI DevTools - Module Entry Point
4
+
5
+ 允許使用 python3 -m dash_devtools 執行
6
+ """
7
+
8
+ from .cli import main
9
+
10
+ if __name__ == '__main__':
11
+ main()
@@ -0,0 +1,441 @@
1
+ """
2
+ DashAI DevTools - AI Engine
3
+ 使用 Google GenAI SDK (Gemini) - 新版 API
4
+ """
5
+
6
+ import os
7
+ from pathlib import Path
8
+ from typing import Optional
9
+ from dataclasses import dataclass
10
+ from enum import Enum
11
+
12
+ # 檢查 Google GenAI SDK (新版)
13
+ GENAI_AVAILABLE = False
14
+ _GENAI_IMPORT_ERROR = ""
15
+
16
+ try:
17
+ from google import genai
18
+ from google.genai import types
19
+ GENAI_AVAILABLE = True
20
+ except ImportError as e:
21
+ _GENAI_IMPORT_ERROR = str(e)
22
+
23
+
24
+ def _load_dotenv_multi_path() -> list[str]:
25
+ """
26
+ 多路徑載入 .env 檔案
27
+
28
+ 搜尋順序:
29
+ 1. 當前工作目錄 .env
30
+ 2. 使用者家目錄 ~/.env
31
+ 3. dash-devtools 專案目錄 .env
32
+
33
+ Returns:
34
+ 成功載入的路徑列表
35
+ """
36
+ loaded_paths = []
37
+
38
+ try:
39
+ from dotenv import load_dotenv
40
+ except ImportError:
41
+ return loaded_paths # dotenv 未安裝
42
+
43
+ # 搜尋路徑列表
44
+ search_paths = [
45
+ Path.cwd() / '.env', # 當前目錄
46
+ Path.home() / '.env', # 家目錄
47
+ Path(__file__).parent.parent / '.env', # dash-devtools 根目錄
48
+ ]
49
+
50
+ for env_path in search_paths:
51
+ if env_path.exists():
52
+ load_dotenv(env_path, override=False) # 不覆蓋已存在的值
53
+ loaded_paths.append(str(env_path))
54
+
55
+ return loaded_paths
56
+
57
+
58
+ def _mask_api_key(key: str) -> str:
59
+ """隱藏 API Key 中間字元"""
60
+ if len(key) <= 8:
61
+ return key[:2] + '*' * (len(key) - 2)
62
+ return key[:4] + '*' * (len(key) - 8) + key[-4:]
63
+
64
+
65
+ def _debug_env_info() -> str:
66
+ """產生除錯資訊"""
67
+ lines = []
68
+
69
+ # 檢查 GEMINI_API_KEY 是否存在
70
+ api_key = os.environ.get("GEMINI_API_KEY")
71
+ if api_key:
72
+ lines.append(f" GEMINI_API_KEY: {_mask_api_key(api_key)} (已設定)")
73
+ else:
74
+ lines.append(" GEMINI_API_KEY: (未設定)")
75
+
76
+ # 列出所有 GEMINI 或 GOOGLE 相關的環境變數
77
+ related_keys = [k for k in os.environ.keys()
78
+ if 'GEMINI' in k.upper() or 'GOOGLE' in k.upper()]
79
+ if related_keys:
80
+ lines.append(" 相關環境變數:")
81
+ for k in sorted(related_keys):
82
+ val = os.environ.get(k, "")
83
+ if 'KEY' in k.upper() or 'SECRET' in k.upper() or 'TOKEN' in k.upper():
84
+ val = _mask_api_key(val) if val else "(空)"
85
+ else:
86
+ val = val[:50] + "..." if len(val) > 50 else val
87
+ lines.append(f" {k}: {val}")
88
+
89
+ return "\n".join(lines)
90
+
91
+
92
+ class AIModel(Enum):
93
+ """可用的 AI 模型"""
94
+ GEMINI_FLASH = "gemini-2.5-flash" # 最新快速版
95
+ GEMINI_PRO = "gemini-2.0-flash" # 穩定版
96
+ GEMINI_FLASH_LITE = "gemini-2.0-flash-lite" # 輕量版
97
+
98
+
99
+ @dataclass
100
+ class AIResponse:
101
+ """AI 回應結構"""
102
+ success: bool
103
+ content: str
104
+ model: str
105
+ prompt_tokens: int = 0
106
+ completion_tokens: int = 0
107
+ error: Optional[str] = None
108
+
109
+
110
+ class AIEngine:
111
+ """
112
+ DashAI DevTools AI 引擎
113
+
114
+ 使用方式:
115
+ from dash_devtools.ai_engine import AIEngine
116
+
117
+ ai = AIEngine()
118
+ response = ai.analyze_code("def foo(): pass")
119
+ """
120
+
121
+ def __init__(
122
+ self,
123
+ model: AIModel = AIModel.GEMINI_FLASH,
124
+ api_key: Optional[str] = None
125
+ ):
126
+ """
127
+ 初始化 AI 引擎
128
+
129
+ Args:
130
+ model: 使用的模型 (預設 gemini-2.5-flash)
131
+ api_key: API Key (預設從環境變數 GEMINI_API_KEY 讀取)
132
+ """
133
+ # 在 __init__ 最前面載入 .env (多路徑搜尋)
134
+ loaded_paths = _load_dotenv_multi_path()
135
+
136
+ if not GENAI_AVAILABLE:
137
+ raise ImportError(
138
+ f"Google GenAI SDK 未安裝或載入失敗。\n"
139
+ f"錯誤: {_GENAI_IMPORT_ERROR}\n"
140
+ f"請執行: pip install google-genai"
141
+ )
142
+
143
+ self.api_key = api_key or os.environ.get("GEMINI_API_KEY")
144
+ if not self.api_key:
145
+ # 除錯資訊
146
+ debug_info = _debug_env_info()
147
+ loaded_info = ""
148
+ if loaded_paths:
149
+ loaded_info = f"\n已搜尋的 .env 檔案:\n " + "\n ".join(loaded_paths)
150
+ else:
151
+ loaded_info = "\n未找到任何 .env 檔案"
152
+
153
+ raise ValueError(
154
+ f"未設定 GEMINI_API_KEY。\n"
155
+ f"請設定環境變數: export GEMINI_API_KEY='your-api-key'\n"
156
+ f"或在 .env 檔案中設定: GEMINI_API_KEY=your-api-key\n"
157
+ f"\n診斷資訊:\n{debug_info}"
158
+ f"{loaded_info}"
159
+ )
160
+
161
+ self.model_name = model.value
162
+ self.client = genai.Client(api_key=self.api_key)
163
+
164
+ def generate(
165
+ self,
166
+ prompt: str,
167
+ system_prompt: Optional[str] = None,
168
+ temperature: float = 0.7,
169
+ max_tokens: int = 2048
170
+ ) -> AIResponse:
171
+ """
172
+ 生成文字回應
173
+
174
+ Args:
175
+ prompt: 使用者提示
176
+ system_prompt: 系統提示 (可選)
177
+ temperature: 創意度 (0.0-1.0)
178
+ max_tokens: 最大輸出 token 數
179
+
180
+ Returns:
181
+ AIResponse 物件
182
+ """
183
+ try:
184
+ full_prompt = prompt
185
+ if system_prompt:
186
+ full_prompt = f"{system_prompt}\n\n{prompt}"
187
+
188
+ config = types.GenerateContentConfig(
189
+ temperature=temperature,
190
+ max_output_tokens=max_tokens
191
+ )
192
+
193
+ response = self.client.models.generate_content(
194
+ model=self.model_name,
195
+ contents=full_prompt,
196
+ config=config
197
+ )
198
+
199
+ # 取得 token 使用量
200
+ prompt_tokens = 0
201
+ completion_tokens = 0
202
+ if hasattr(response, 'usage_metadata') and response.usage_metadata:
203
+ prompt_tokens = getattr(response.usage_metadata, 'prompt_token_count', 0) or 0
204
+ completion_tokens = getattr(response.usage_metadata, 'candidates_token_count', 0) or 0
205
+
206
+ return AIResponse(
207
+ success=True,
208
+ content=response.text,
209
+ model=self.model_name,
210
+ prompt_tokens=prompt_tokens,
211
+ completion_tokens=completion_tokens
212
+ )
213
+ except Exception as e:
214
+ return AIResponse(
215
+ success=False,
216
+ content="",
217
+ model=self.model_name,
218
+ error=str(e)
219
+ )
220
+
221
+ def analyze_code(
222
+ self,
223
+ code: str,
224
+ language: str = "auto",
225
+ focus: str = "general"
226
+ ) -> AIResponse:
227
+ """
228
+ 分析程式碼
229
+
230
+ Args:
231
+ code: 要分析的程式碼
232
+ language: 程式語言 (auto 自動偵測)
233
+ focus: 分析重點 (general/security/performance/quality)
234
+
235
+ Returns:
236
+ AIResponse 物件
237
+ """
238
+ focus_prompts = {
239
+ "general": "請全面分析這段程式碼,包括可讀性、潛在問題、最佳實踐建議。",
240
+ "security": "請從安全性角度分析這段程式碼,找出潛在的安全漏洞和風險。",
241
+ "performance": "請從效能角度分析這段程式碼,找出可能的效能瓶頸和優化建議。",
242
+ "quality": "請從程式碼品質角度分析,包括命名規範、結構設計、可維護性。"
243
+ }
244
+
245
+ system_prompt = """你是一位資深的軟體工程師和程式碼審查專家。
246
+ 請用正體中文(台灣用語)回答。
247
+ 回答要具體、有建設性,並提供改善範例。"""
248
+
249
+ prompt = f"""
250
+ {focus_prompts.get(focus, focus_prompts["general"])}
251
+
252
+ 程式語言: {language}
253
+
254
+ ```
255
+ {code}
256
+ ```
257
+ """
258
+ return self.generate(prompt, system_prompt, temperature=0.3)
259
+
260
+ def suggest_fix(
261
+ self,
262
+ code: str,
263
+ error_message: str,
264
+ language: str = "auto"
265
+ ) -> AIResponse:
266
+ """
267
+ 建議修復方案
268
+
269
+ Args:
270
+ code: 有問題的程式碼
271
+ error_message: 錯誤訊息
272
+ language: 程式語言
273
+
274
+ Returns:
275
+ AIResponse 物件包含修復建議
276
+ """
277
+ system_prompt = """你是一位除錯專家。
278
+ 請用正體中文(台灣用語)回答。
279
+ 請提供:
280
+ 1. 問題原因分析
281
+ 2. 修復後的完整程式碼
282
+ 3. 預防類似問題的建議"""
283
+
284
+ prompt = f"""
285
+ 請幫我修復以下程式碼的問題:
286
+
287
+ 錯誤訊息:
288
+ ```
289
+ {error_message}
290
+ ```
291
+
292
+ 程式碼 ({language}):
293
+ ```
294
+ {code}
295
+ ```
296
+ """
297
+ return self.generate(prompt, system_prompt, temperature=0.2)
298
+
299
+ def generate_tests(
300
+ self,
301
+ code: str,
302
+ framework: str = "auto",
303
+ coverage: str = "comprehensive"
304
+ ) -> AIResponse:
305
+ """
306
+ 生成測試程式碼
307
+
308
+ Args:
309
+ code: 要測試的程式碼
310
+ framework: 測試框架 (auto/pytest/jest/vitest)
311
+ coverage: 覆蓋範圍 (basic/comprehensive/edge-cases)
312
+
313
+ Returns:
314
+ AIResponse 物件包含測試程式碼
315
+ """
316
+ coverage_desc = {
317
+ "basic": "基本功能測試",
318
+ "comprehensive": "全面測試,包括正常流程和邊界情況",
319
+ "edge-cases": "專注於邊界條件和異常處理"
320
+ }
321
+
322
+ system_prompt = f"""你是一位測試專家。
323
+ 請用正體中文註解。
324
+ 測試框架: {framework}
325
+ 覆蓋範圍: {coverage_desc.get(coverage, coverage_desc["comprehensive"])}"""
326
+
327
+ prompt = f"""
328
+ 請為以下程式碼生成測試:
329
+
330
+ ```
331
+ {code}
332
+ ```
333
+
334
+ 要求:
335
+ - 使用 {framework} 框架
336
+ - 包含 {coverage_desc.get(coverage, coverage)} 的測試案例
337
+ - 每個測試案例都要有清楚的名稱和註解
338
+ """
339
+ return self.generate(prompt, system_prompt, temperature=0.3)
340
+
341
+ def explain_code(
342
+ self,
343
+ code: str,
344
+ detail_level: str = "medium"
345
+ ) -> AIResponse:
346
+ """
347
+ 解釋程式碼
348
+
349
+ Args:
350
+ code: 要解釋的程式碼
351
+ detail_level: 詳細程度 (brief/medium/detailed)
352
+
353
+ Returns:
354
+ AIResponse 物件包含解釋
355
+ """
356
+ detail_prompts = {
357
+ "brief": "請簡潔說明這段程式碼的功能(2-3 句話)。",
358
+ "medium": "請說明這段程式碼的功能、主要邏輯和使用方式。",
359
+ "detailed": "請詳細說明這段程式碼,包括每個函數的作用、資料流、設計模式等。"
360
+ }
361
+
362
+ system_prompt = """你是一位技術文件撰寫專家。
363
+ 請用正體中文(台灣用語)回答。
364
+ 使用清晰的結構化格式。"""
365
+
366
+ prompt = f"""
367
+ {detail_prompts.get(detail_level, detail_prompts["medium"])}
368
+
369
+ ```
370
+ {code}
371
+ ```
372
+ """
373
+ return self.generate(prompt, system_prompt, temperature=0.3)
374
+
375
+ def review_commit(
376
+ self,
377
+ diff: str,
378
+ commit_message: str = ""
379
+ ) -> AIResponse:
380
+ """
381
+ 審查 Git Commit
382
+
383
+ Args:
384
+ diff: Git diff 內容
385
+ commit_message: Commit 訊息
386
+
387
+ Returns:
388
+ AIResponse 物件包含審查結果
389
+ """
390
+ system_prompt = """你是一位資深的程式碼審查員。
391
+ 請用正體中文(台灣用語)回答。
392
+ 審查要點:
393
+ 1. 程式碼品質
394
+ 2. 潛在問題
395
+ 3. 安全性考量
396
+ 4. Commit 訊息是否清楚描述變更"""
397
+
398
+ prompt = f"""
399
+ 請審查這個 commit:
400
+
401
+ Commit 訊息: {commit_message or "(無)"}
402
+
403
+ 變更內容:
404
+ ```diff
405
+ {diff}
406
+ ```
407
+ """
408
+ return self.generate(prompt, system_prompt, temperature=0.3)
409
+
410
+
411
+ # 快速存取函數
412
+ def get_ai(model: AIModel = AIModel.GEMINI_FLASH) -> AIEngine:
413
+ """
414
+ 取得 AI 引擎實例
415
+
416
+ Args:
417
+ model: 使用的模型
418
+
419
+ Returns:
420
+ AIEngine 實例
421
+ """
422
+ return AIEngine(model=model)
423
+
424
+
425
+ # CLI 整合
426
+ def ai_analyze_command(path: str, focus: str = "general") -> None:
427
+ """CLI 分析指令"""
428
+ try:
429
+ ai = get_ai()
430
+ with open(path, 'r', encoding='utf-8') as f:
431
+ code = f.read()
432
+
433
+ response = ai.analyze_code(code, focus=focus)
434
+ if response.success:
435
+ print(response.content)
436
+ else:
437
+ print(f"[!] 錯誤: {response.error}")
438
+ except FileNotFoundError:
439
+ print(f"[!] 找不到檔案: {path}")
440
+ except Exception as e:
441
+ print(f"[!] 錯誤: {e}")