autosnippet 3.0.0 → 3.0.2

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 (290) hide show
  1. package/README.md +230 -324
  2. package/bin/api-server.js +1 -1
  3. package/bin/cli.js +204 -244
  4. package/bin/mcp-server.js +5 -3
  5. package/config/knowledge-base.config.js +132 -132
  6. package/dashboard/dist/assets/{icons-CEfgGaZi.js → icons-Cdq22n2i.js} +95 -100
  7. package/dashboard/dist/assets/index-ClkyPkDX.js +133 -0
  8. package/dashboard/dist/assets/index-t4QrJwv1.css +1 -0
  9. package/dashboard/dist/index.html +3 -3
  10. package/lib/bootstrap.js +8 -8
  11. package/lib/cli/AiScanService.js +86 -40
  12. package/lib/cli/KnowledgeSyncService.js +113 -74
  13. package/lib/cli/SetupService.js +439 -277
  14. package/lib/cli/UpgradeService.js +63 -100
  15. package/lib/core/AstAnalyzer.js +276 -597
  16. package/lib/core/ast/ProjectGraph.js +101 -40
  17. package/lib/core/ast/ensure-grammars.js +232 -0
  18. package/lib/core/ast/index.js +115 -0
  19. package/lib/core/ast/lang-dart.js +661 -0
  20. package/lib/core/ast/lang-go.js +530 -0
  21. package/lib/core/ast/lang-java.js +435 -0
  22. package/lib/core/ast/lang-javascript.js +272 -0
  23. package/lib/core/ast/lang-kotlin.js +423 -0
  24. package/lib/core/ast/lang-objc.js +388 -0
  25. package/lib/core/ast/lang-python.js +371 -0
  26. package/lib/core/ast/lang-swift.js +337 -0
  27. package/lib/core/ast/lang-typescript.js +503 -0
  28. package/lib/core/capability/CapabilityProbe.js +18 -9
  29. package/lib/core/constitution/Constitution.js +2 -3
  30. package/lib/core/constitution/ConstitutionValidator.js +65 -24
  31. package/lib/core/discovery/DartDiscoverer.js +534 -0
  32. package/lib/core/discovery/DiscovererRegistry.js +83 -0
  33. package/lib/core/discovery/GenericDiscoverer.js +225 -0
  34. package/lib/core/discovery/GoDiscoverer.js +541 -0
  35. package/lib/core/discovery/JvmDiscoverer.js +506 -0
  36. package/lib/core/discovery/NodeDiscoverer.js +466 -0
  37. package/lib/core/discovery/ProjectDiscoverer.js +93 -0
  38. package/lib/core/discovery/PythonDiscoverer.js +338 -0
  39. package/lib/core/discovery/SpmDiscoverer.js +5 -0
  40. package/lib/core/discovery/index.js +53 -0
  41. package/lib/core/enhancement/EnhancementPack.js +71 -0
  42. package/lib/core/enhancement/EnhancementRegistry.js +47 -0
  43. package/lib/core/enhancement/android-enhancement.js +102 -0
  44. package/lib/core/enhancement/django-enhancement.js +70 -0
  45. package/lib/core/enhancement/fastapi-enhancement.js +63 -0
  46. package/lib/core/enhancement/go-grpc-enhancement.js +152 -0
  47. package/lib/core/enhancement/go-web-enhancement.js +201 -0
  48. package/lib/core/enhancement/index.js +65 -0
  49. package/lib/core/enhancement/node-server-enhancement.js +88 -0
  50. package/lib/core/enhancement/react-enhancement.js +86 -0
  51. package/lib/core/enhancement/spring-enhancement.js +112 -0
  52. package/lib/core/enhancement/vue-enhancement.js +96 -0
  53. package/lib/core/gateway/Gateway.js +8 -9
  54. package/lib/core/gateway/GatewayActionRegistry.js +1 -1
  55. package/lib/core/permission/PermissionManager.js +12 -8
  56. package/lib/domain/index.js +13 -9
  57. package/lib/domain/knowledge/KnowledgeEntry.js +111 -101
  58. package/lib/domain/knowledge/KnowledgeRepository.js +0 -1
  59. package/lib/domain/knowledge/Lifecycle.js +22 -22
  60. package/lib/domain/knowledge/index.js +9 -12
  61. package/lib/domain/knowledge/values/Constraints.js +31 -21
  62. package/lib/domain/knowledge/values/Content.js +21 -13
  63. package/lib/domain/knowledge/values/Quality.js +31 -18
  64. package/lib/domain/knowledge/values/Reasoning.js +20 -12
  65. package/lib/domain/knowledge/values/Relations.js +37 -25
  66. package/lib/domain/knowledge/values/Stats.js +18 -12
  67. package/lib/domain/knowledge/values/index.js +4 -3
  68. package/lib/domain/snippet/Snippet.js +35 -10
  69. package/lib/external/ai/AiFactory.js +48 -16
  70. package/lib/external/ai/AiProvider.js +184 -90
  71. package/lib/external/ai/providers/ClaudeProvider.js +25 -12
  72. package/lib/external/ai/providers/GoogleGeminiProvider.js +59 -30
  73. package/lib/external/ai/providers/MockProvider.js +9 -3
  74. package/lib/external/ai/providers/OpenAiProvider.js +51 -29
  75. package/lib/external/mcp/McpServer.js +66 -36
  76. package/lib/external/mcp/errorHandler.js +23 -11
  77. package/lib/external/mcp/handlers/LanguageExtensions.js +138 -53
  78. package/lib/external/mcp/handlers/TargetClassifier.js +52 -16
  79. package/lib/external/mcp/handlers/bootstrap/pipeline/BootstrapSnapshot.js +81 -20
  80. package/lib/external/mcp/handlers/bootstrap/pipeline/EpisodicMemory.js +71 -42
  81. package/lib/external/mcp/handlers/bootstrap/pipeline/IncrementalBootstrap.js +9 -17
  82. package/lib/external/mcp/handlers/bootstrap/pipeline/ToolResultCache.js +14 -9
  83. package/lib/external/mcp/handlers/bootstrap/pipeline/dimension-context.js +15 -7
  84. package/lib/external/mcp/handlers/bootstrap/pipeline/orchestrator.js +352 -153
  85. package/lib/external/mcp/handlers/bootstrap/pipeline/tier-scheduler.js +52 -12
  86. package/lib/external/mcp/handlers/bootstrap/skills.js +143 -39
  87. package/lib/external/mcp/handlers/bootstrap.js +691 -168
  88. package/lib/external/mcp/handlers/browse.js +66 -22
  89. package/lib/external/mcp/handlers/candidate.js +118 -35
  90. package/lib/external/mcp/handlers/consolidated.js +49 -17
  91. package/lib/external/mcp/handlers/guard.js +104 -39
  92. package/lib/external/mcp/handlers/knowledge.js +60 -36
  93. package/lib/external/mcp/handlers/search.js +43 -14
  94. package/lib/external/mcp/handlers/skill.js +120 -45
  95. package/lib/external/mcp/handlers/structure.js +240 -86
  96. package/lib/external/mcp/handlers/system.js +42 -12
  97. package/lib/external/mcp/handlers/wiki.js +58 -33
  98. package/lib/external/mcp/tools.js +306 -123
  99. package/lib/http/HttpServer.js +72 -47
  100. package/lib/http/middleware/RateLimiter.js +5 -3
  101. package/lib/http/middleware/errorHandler.js +6 -1
  102. package/lib/http/middleware/requestLogger.js +14 -3
  103. package/lib/http/middleware/roleResolver.js +30 -23
  104. package/lib/http/routes/ai.js +387 -265
  105. package/lib/http/routes/auth.js +81 -61
  106. package/lib/http/routes/candidates.js +430 -320
  107. package/lib/http/routes/commands.js +289 -189
  108. package/lib/http/routes/extract.js +158 -125
  109. package/lib/http/routes/guardRules.js +309 -217
  110. package/lib/http/routes/knowledge.js +213 -154
  111. package/lib/http/routes/modules.js +578 -0
  112. package/lib/http/routes/monitoring.js +6 -6
  113. package/lib/http/routes/recipes.js +104 -93
  114. package/lib/http/routes/search.js +361 -305
  115. package/lib/http/routes/skills.js +145 -98
  116. package/lib/http/routes/snippets.js +42 -30
  117. package/lib/http/routes/spm.js +3 -405
  118. package/lib/http/routes/violations.js +113 -93
  119. package/lib/http/routes/wiki.js +211 -170
  120. package/lib/http/utils/routeHelpers.js +3 -1
  121. package/lib/http/utils/sse-sessions.js +16 -6
  122. package/lib/http/utils/sse.js +15 -5
  123. package/lib/infrastructure/audit/AuditLogger.js +5 -2
  124. package/lib/infrastructure/audit/AuditStore.js +10 -7
  125. package/lib/infrastructure/cache/CacheService.js +3 -1
  126. package/lib/infrastructure/cache/GraphCache.js +8 -4
  127. package/lib/infrastructure/cache/UnifiedCacheAdapter.js +1 -1
  128. package/lib/infrastructure/config/ConfigLoader.js +9 -5
  129. package/lib/infrastructure/config/Defaults.js +30 -10
  130. package/lib/infrastructure/config/Paths.js +28 -8
  131. package/lib/infrastructure/config/TriggerSymbol.js +22 -10
  132. package/lib/infrastructure/database/DatabaseConnection.js +15 -10
  133. package/lib/infrastructure/database/migrations/001_initial_schema.js +0 -1
  134. package/lib/infrastructure/external/ClipboardManager.js +6 -2
  135. package/lib/infrastructure/external/NativeUi.js +50 -43
  136. package/lib/infrastructure/external/OpenBrowser.js +14 -17
  137. package/lib/infrastructure/external/XcodeAutomation.js +14 -258
  138. package/lib/infrastructure/logging/Logger.js +46 -30
  139. package/lib/infrastructure/monitoring/ErrorTracker.js +7 -5
  140. package/lib/infrastructure/monitoring/PerformanceMonitor.js +12 -4
  141. package/lib/infrastructure/paths/HeaderResolver.js +25 -9
  142. package/lib/infrastructure/paths/PathFinder.js +34 -12
  143. package/lib/infrastructure/plugin/PluginManager.js +26 -8
  144. package/lib/infrastructure/realtime/RealtimeService.js +2 -2
  145. package/lib/infrastructure/vector/Chunker.js +22 -7
  146. package/lib/infrastructure/vector/IndexingPipeline.js +46 -22
  147. package/lib/infrastructure/vector/JsonVectorAdapter.js +90 -53
  148. package/lib/infrastructure/vector/VectorStore.js +28 -10
  149. package/lib/injection/ServiceContainer.js +247 -93
  150. package/lib/platform/ios/index.js +63 -0
  151. package/lib/platform/ios/routes/spm.js +437 -0
  152. package/lib/platform/ios/snippet/PlaceholderConverter.js +55 -0
  153. package/lib/platform/ios/snippet/XcodeCodec.js +112 -0
  154. package/lib/{service → platform/ios}/spm/DependencyGraph.js +41 -17
  155. package/lib/{service → platform/ios}/spm/PackageSwiftParser.js +41 -14
  156. package/lib/{service → platform/ios}/spm/PolicyEngine.js +9 -4
  157. package/lib/platform/ios/spm/SpmDiscoverer.js +122 -0
  158. package/lib/{service → platform/ios}/spm/SpmService.js +385 -127
  159. package/lib/{service/automation → platform/ios/xcode}/SaveEventFilter.js +8 -7
  160. package/lib/platform/ios/xcode/XcodeAutomation.js +350 -0
  161. package/lib/{service/automation → platform/ios/xcode}/XcodeIntegration.js +325 -145
  162. package/lib/repository/base/BaseRepository.js +7 -9
  163. package/lib/repository/knowledge/KnowledgeRepository.impl.js +98 -75
  164. package/lib/repository/token/TokenUsageStore.js +4 -2
  165. package/lib/service/automation/ActionPipeline.js +1 -1
  166. package/lib/service/automation/AutomationOrchestrator.js +8 -4
  167. package/lib/service/automation/ContextCollector.js +7 -5
  168. package/lib/service/automation/DirectiveDetector.js +23 -16
  169. package/lib/service/automation/FileWatcher.js +112 -56
  170. package/lib/service/automation/TriggerResolver.js +6 -4
  171. package/lib/service/automation/handlers/AlinkHandler.js +24 -12
  172. package/lib/service/automation/handlers/CreateHandler.js +19 -20
  173. package/lib/service/automation/handlers/DraftHandler.js +14 -8
  174. package/lib/service/automation/handlers/GuardHandler.js +93 -63
  175. package/lib/service/automation/handlers/HeaderHandler.js +1 -6
  176. package/lib/service/automation/handlers/SearchHandler.js +155 -88
  177. package/lib/service/bootstrap/BootstrapTaskManager.js +77 -35
  178. package/lib/service/candidate/SimilarityService.js +25 -9
  179. package/lib/service/chat/AnalystAgent.js +50 -24
  180. package/lib/service/chat/CandidateGuardrail.js +143 -17
  181. package/lib/service/chat/ChatAgent.js +759 -243
  182. package/lib/service/chat/ContextWindow.js +116 -71
  183. package/lib/service/chat/ConversationStore.js +77 -36
  184. package/lib/service/chat/EpisodicConsolidator.js +47 -23
  185. package/lib/service/chat/HandoffProtocol.js +98 -22
  186. package/lib/service/chat/Memory.js +34 -14
  187. package/lib/service/chat/ProducerAgent.js +40 -20
  188. package/lib/service/chat/ProjectSemanticMemory.js +109 -78
  189. package/lib/service/chat/ReasoningLayer.js +148 -70
  190. package/lib/service/chat/ReasoningTrace.js +44 -32
  191. package/lib/service/chat/TaskPipeline.js +39 -19
  192. package/lib/service/chat/ToolRegistry.js +48 -29
  193. package/lib/service/chat/WorkingMemory.js +44 -18
  194. package/lib/service/chat/tools.js +1096 -494
  195. package/lib/service/context/RecipeExtractor.js +132 -51
  196. package/lib/service/cursor/CursorDeliveryPipeline.js +82 -37
  197. package/lib/service/cursor/KnowledgeCompressor.js +25 -22
  198. package/lib/service/cursor/RulesGenerator.js +13 -7
  199. package/lib/service/cursor/SkillsSyncer.js +77 -27
  200. package/lib/service/cursor/TokenBudget.js +2 -2
  201. package/lib/service/cursor/TopicClassifier.js +54 -20
  202. package/lib/service/guard/ComplianceReporter.js +55 -43
  203. package/lib/service/guard/ExclusionManager.js +67 -29
  204. package/lib/service/guard/GuardCheckEngine.js +381 -86
  205. package/lib/service/guard/GuardFeedbackLoop.js +22 -10
  206. package/lib/service/guard/GuardService.js +29 -19
  207. package/lib/service/guard/RuleLearner.js +55 -23
  208. package/lib/service/guard/SourceFileCollector.js +27 -20
  209. package/lib/service/guard/ViolationsStore.js +43 -38
  210. package/lib/service/knowledge/CodeEntityGraph.js +147 -82
  211. package/lib/service/knowledge/ConfidenceRouter.js +12 -10
  212. package/lib/service/knowledge/KnowledgeFileWriter.js +147 -56
  213. package/lib/service/knowledge/KnowledgeGraphService.js +81 -34
  214. package/lib/service/knowledge/KnowledgeService.js +222 -112
  215. package/lib/service/module/ModuleService.js +969 -0
  216. package/lib/service/quality/FeedbackCollector.js +27 -15
  217. package/lib/service/quality/QualityScorer.js +78 -24
  218. package/lib/service/recipe/RecipeCandidateValidator.js +110 -44
  219. package/lib/service/recipe/RecipeParser.js +78 -45
  220. package/lib/service/search/CoarseRanker.js +43 -28
  221. package/lib/service/search/CrossEncoderReranker.js +32 -21
  222. package/lib/service/search/InvertedIndex.js +21 -7
  223. package/lib/service/search/MultiSignalRanker.js +90 -28
  224. package/lib/service/search/RetrievalFunnel.js +45 -24
  225. package/lib/service/search/SearchEngine.js +255 -103
  226. package/lib/service/skills/EventAggregator.js +32 -15
  227. package/lib/service/skills/SignalCollector.js +140 -64
  228. package/lib/service/skills/SkillAdvisor.js +79 -42
  229. package/lib/service/skills/SkillHooks.js +16 -14
  230. package/lib/service/snippet/PlaceholderConverter.js +5 -0
  231. package/lib/service/snippet/SnippetFactory.js +116 -99
  232. package/lib/service/snippet/SnippetInstaller.js +234 -62
  233. package/lib/service/snippet/codecs/SnippetCodec.js +67 -0
  234. package/lib/service/snippet/codecs/VSCodeCodec.js +102 -0
  235. package/lib/service/snippet/codecs/XcodeCodec.js +5 -0
  236. package/lib/service/wiki/WikiGenerator.js +637 -263
  237. package/lib/shared/DimensionCopyRegistry.js +472 -0
  238. package/lib/shared/LanguageService.js +399 -0
  239. package/lib/shared/PathGuard.js +45 -28
  240. package/lib/shared/RecipeReadinessChecker.js +72 -12
  241. package/lib/shared/constants.js +41 -41
  242. package/lib/shared/errors/BaseError.js +2 -2
  243. package/lib/shared/errors/index.js +4 -4
  244. package/lib/shared/similarity.js +25 -8
  245. package/lib/shared/token-utils.js +6 -2
  246. package/lib/shared/utils/common.js +12 -4
  247. package/package.json +49 -13
  248. package/scripts/bench-real-projects.mjs +256 -0
  249. package/scripts/build-native-ui.js +30 -30
  250. package/scripts/clear-old-vector-index.js +5 -35
  251. package/scripts/clear-vector-cache.js +7 -37
  252. package/scripts/collect-test-project-stats.mjs +160 -0
  253. package/scripts/diagnose-mcp.js +41 -32
  254. package/scripts/ensure-parse-package.js +6 -9
  255. package/scripts/generate-recipe-drafts.js +116 -77
  256. package/scripts/init-db.js +3 -20
  257. package/scripts/init-snippets.js +305 -0
  258. package/scripts/init-vector-db.js +173 -170
  259. package/scripts/install-cursor-skill.js +148 -104
  260. package/scripts/install-full.js +8 -21
  261. package/scripts/install-vscode-copilot.js +146 -145
  262. package/scripts/migrate-md-to-knowledge.mjs +139 -151
  263. package/scripts/postinstall-safe.js +5 -17
  264. package/scripts/recipe-audit.js +106 -82
  265. package/scripts/release.js +283 -323
  266. package/scripts/setup-mcp-config.js +60 -52
  267. package/scripts/verify-context-api.js +20 -20
  268. package/skills/autosnippet-analysis/SKILL.md +10 -6
  269. package/skills/autosnippet-candidates/SKILL.md +27 -26
  270. package/skills/autosnippet-coldstart/SKILL.md +555 -38
  271. package/skills/autosnippet-concepts/SKILL.md +349 -337
  272. package/skills/autosnippet-create/SKILL.md +5 -5
  273. package/skills/autosnippet-reference-dart/SKILL.md +543 -0
  274. package/skills/autosnippet-reference-go/SKILL.md +539 -0
  275. package/skills/autosnippet-reference-java/SKILL.md +534 -0
  276. package/skills/autosnippet-reference-jsts/SKILL.md +41 -9
  277. package/skills/autosnippet-reference-kotlin/SKILL.md +526 -0
  278. package/skills/autosnippet-reference-objc/SKILL.md +29 -6
  279. package/skills/autosnippet-reference-python/SKILL.md +800 -0
  280. package/skills/autosnippet-reference-swift/SKILL.md +70 -14
  281. package/skills/autosnippet-structure/SKILL.md +4 -4
  282. package/templates/cursor-rules/autosnippet-conventions.mdc +2 -2
  283. package/templates/recipes-setup/README.md +2 -2
  284. package/templates/recipes-setup/_template.md +1 -1
  285. package/dashboard/dist/assets/index-Bun3ld_J.css +0 -1
  286. package/dashboard/dist/assets/index-_Sk_Dmg3.js +0 -143
  287. package/resources/asd-entry/main.swift +0 -159
  288. package/scripts/build-asd-entry.js +0 -51
  289. package/scripts/init-xcode-snippets.js +0 -311
  290. package/template.json +0 -39
@@ -16,10 +16,10 @@ This skill tells the agent how to **submit module usage code** (that Cursor has
16
16
  3. **When user asks for "candidates"**: Use MCP **`autosnippet_submit_knowledge_batch`** for structured items (title/summary/trigger/code/usageGuide); use **`autosnippet_submit_knowledge_batch`** for Markdown draft files (prefer draft folder + multiple files; delete draft folder after submit).
17
17
  4. **One Recipe = one scenario**: If you are drafting content, **split** into multiple Recipes by scenario. Never combine multiple usage patterns into one Recipe file or one candidate.
18
18
  5. **Recipe candidates can be intro-only**: Intro-only docs (no code block) can be submitted as candidates; after approval they become Recipes and **do not generate a Snippet**—used only for search and Guard context.
19
- 6. **MUST follow standard Recipe format**: Use the complete template from **autosnippet-concepts** skill. Include all required fields: frontmatter with `title`, `trigger`, `category` (one of 8 standard values), `language` (must be `swift` or `objectivec`), `summary_cn`, `summary_en`, `headers` (complete import statements), plus `## Snippet / Code Reference` and `## AI Context / Usage Guide` section.
20
- - **MCP 不再使用项目内 AI**: 外部 Agent 必须自行填写所有字段,包括 summary_en、usageGuide_en、headers 等。提交后检查返回值中的 `recipeReadyHints`,缺失字段需补全后重新提交。
21
- - **双语建议 (RECOMMENDED)**: 同时提供中英文版本——`summary_cn` + `summary_en` + `usageGuide` + `usageGuide_en`。英文提升检索、AI 理解和团队复用(token 增加仅约20-30%,收益高)。纯中文也可接受。
22
- - **Placeholders**: Prefer Xcode placeholders in snippets (e.g. `<#URL#>`, `<#Token#>`) and explain each placeholder in the Usage Guide.
19
+ 6. **MUST follow V3 Recipe format**: Include all required fields: `title`, `trigger`, `category` (one of 8 standard values), `language`, `kind` (rule/pattern/fact), `doClause`, `description`, `content` (object with markdown, pattern, rationale), `headers` (complete import statements), `usageGuide` (Markdown ### 章节), `knowledgeType`, `reasoning` (whyStandard + sources + confidence).
20
+ - **MCP 不再使用项目内 AI**: 外部 Agent 必须自行填写所有字段。提交后检查返回值中的 `recipeReadyHints`,缺失字段需补全后重新提交。
21
+ - **禁止使用旧字段**: 不要使用 `code`、`summary_cn`、`summary_en`,改用 V3 `content` 对象 + `description`。
22
+ - **Placeholders**: Use IDE-appropriate placeholders in snippets Xcode format `<#URL#>`, `<#Token#>` (auto-converted to VSCode `${N:...}` on install). Explain each placeholder in the Usage Guide.
23
23
  - **Usage Guide structure (强制格式要求)**:
24
24
  * **MUST use structured format with clear section headings** (### heading name):**NEVER put all content in one continuous line**
25
25
  * **MUST use newlines (`\n`) to separate sections and bullet points** — at least 2-3 newlines between major sections
@@ -105,7 +105,7 @@ This skill tells the agent how to **submit module usage code** (that Cursor has
105
105
  | Way | When to use |
106
106
  |-----|-------------|
107
107
  | **New Recipe → Scan File** | Code is already in a project file; user enters relative path (e.g. `Sources/MyMod/Foo.m`) → Scan File → AI extracts → save in Dashboard. |
108
- | **SPM Explorer** | Mine usage from an SPM Target: select Target → scan → review in Dashboard → save as Recipe (or Snippet + Recipe). |
108
+ | **Module Explorer** | Mine usage from a module Target: select Target → scan → review in Dashboard → save as Recipe (or Snippet + Recipe). |
109
109
  | **Candidates** | Batch: run **`asd ais <Target>`** or **`asd ais --all`** → open Dashboard **Candidates** → approve items → saved to knowledge base. |
110
110
 
111
111
  All of these **submit through the web (Dashboard)** and result in content in **`AutoSnippet/recipes/`** (and optionally Snippet). The main flow above (Use Copied Code) is for **code that Cursor has just written**.
@@ -0,0 +1,543 @@
1
+ ```skill
2
+ ---
3
+ name: autosnippet-reference-dart
4
+ description: Dart (Flutter) 业界最佳实践参考。涵盖命名约定、空安全、Widget 设计、状态管理 (BLoC/Riverpod/Provider)、异步 (Future/Stream)、Freezed 不可变模型、测试、Clean Architecture,为冷启动分析提供高质量参考标准。
5
+ ---
6
+
7
+ # Dart (Flutter) 最佳实践参考 (Industry Reference)
8
+
9
+ > 本 Skill 为 **autosnippet-coldstart** 的 Companion Skill。在冷启动分析 Dart / Flutter 项目时,请参考以下业界标准产出高质量候选。
10
+ > **来源**: Effective Dart (dart.dev), Flutter Style Guide, Dart Lints (flutter_lints / very_good_analysis), Reso Coder Clean Architecture, Vandad Nahavandipoor Flutter Tips
11
+
12
+ ---
13
+
14
+ ## 1. 命名约定
15
+
16
+ ### 核心规则
17
+
18
+ ```json
19
+ {
20
+ "title": "Dart: Effective Dart 命名规范",
21
+ "content": {
22
+ "markdown": "## Dart: Effective Dart 命名规范\n\n### 标准模式\n```dart\n// ✅ 类/枚举/typedef/extension: UpperCamelCase\nclass UserService { }\nenum AuthStatus { authenticated, unauthenticated }\ntypedef JsonMap = Map<String, dynamic>;\nextension StringX on String { }\n\n// ✅ 变量/函数/参数/命名参数: lowerCamelCase\nfinal currentUser = User();\nvoid fetchUserProfile() { }\nWidget build({required String title}) { }\n\n// ✅ 常量: lowerCamelCase (不用 SCREAMING_CAPS)\nconst defaultTimeout = Duration(seconds: 30);\nconst maxRetryCount = 3;\n\n// ✅ 文件名: snake_case\n// user_service.dart\n// home_page.dart\n// auth_repository.dart\n\n// ✅ library / package: snake_case\nlibrary my_app;\n\n// ✅ 私有成员: 下划线前缀\nclass _UserState extends State<UserPage> { }\nfinal _logger = Logger('AuthService');\n\n// ✅ bool 变量/getter: is/has/can/should 前缀\nbool get isLoading => _isLoading;\nbool hasPermission(String role) => ...;\n\n// ❌ 反模式\nconst MAX_RETRY_COUNT = 3; // Dart 不用 SCREAMING_CAPS\nclass user_service { } // 类名应 UpperCamelCase\nString UserName = ''; // 变量应 lowerCamelCase\n```",
23
+ "pattern": "class UserService { }\nenum AuthStatus { authenticated, unauthenticated }\ntypedef JsonMap = Map<String, dynamic>;\nfinal currentUser = User();\nvoid fetchUserProfile() { }\nconst defaultTimeout = Duration(seconds: 30);\n// 文件名: user_service.dart",
24
+ "rationale": "Effective Dart 规定类名 UpperCamelCase,变量/函数 lowerCamelCase,常量也用 lowerCamelCase(区别于 Java/C++),文件名 snake_case"
25
+ },
26
+ "description": "Dart: Effective Dart 命名规范",
27
+ "kind": "rule",
28
+ "doClause": "Apply the Dart naming conventions as described",
29
+ "language": "dart",
30
+ "headers": [],
31
+ "knowledgeType": "code-standard",
32
+ "usageGuide": "### 使用场景\\n触发 `@trigger` 获取 Dart 命名规范的标准模式。",
33
+ "scope": "universal",
34
+ "antiPattern": {
35
+ "bad": "const MAX_RETRY = 3;\nclass user_service { }",
36
+ "why": "SCREAMING_CAPS 和下划线类名不符合 Dart 惯例",
37
+ "fix": "const maxRetry = 3;\nclass UserService { }"
38
+ },
39
+ "reasoning": {
40
+ "whyStandard": "Effective Dart - Style; dart_lints enforce",
41
+ "sources": [
42
+ "Effective Dart - Style",
43
+ "Dart Linter Rules"
44
+ ],
45
+ "confidence": 0.95
46
+ }
47
+ }
48
+ ```
49
+
50
+ ### 命名速查表
51
+
52
+ | 标识符类型 | 风格 | 示例 |
53
+ |-----------|------|------|
54
+ | 类/枚举/extension | `UpperCamelCase` | `UserService`, `AuthStatus` |
55
+ | 变量/函数/参数 | `lowerCamelCase` | `currentUser`, `fetchData()` |
56
+ | 常量 | `lowerCamelCase` | `defaultTimeout`, `maxRetry` |
57
+ | 文件名 | `snake_case` | `user_service.dart` |
58
+ | 私有成员 | `_` 前缀 | `_isLoading`, `_UserState` |
59
+ | 布尔值 | `is/has/can/should` 前缀 | `isLoading`, `hasPermission` |
60
+
61
+ ---
62
+
63
+ ## 2. 空安全 (Null Safety)
64
+
65
+ ```json
66
+ {
67
+ "title": "Dart: 空安全最佳实践",
68
+ "content": {
69
+ "markdown": "## Dart: 空安全最佳实践\n\n### 标准模式\n```dart\n// ✅ 优先使用不可空类型\nString name = 'Alice';\nint count = 0;\n\n// ✅ 确实可能为 null 时用 nullable\nUser? findUserById(int id) {\n return _cache[id]; // 可能不存在\n}\n\n// ✅ 安全调用链 + ?? 默认值\nfinal city = user?.address?.city ?? 'Unknown';\n\n// ✅ null-aware 赋值\n_cache ??= {};\nname ??= 'Guest';\n\n// ✅ 模式匹配(Dart 3+)\nif (user case User(:final name, :final email)) {\n print('$name: $email');\n}\n\n// ✅ late 用于确定会初始化但无法在声明时赋值的场景\nlate final TextEditingController _controller;\n\n@override\nvoid initState() {\n super.initState();\n _controller = TextEditingController();\n}\n\n// ❌ 避免 ! 强制解包\nfinal name = user!.name; // 可能抛 TypeError\n\n// ❌ 避免不必要的 nullable\nString? getName() => 'Alice'; // String 就够了\n\n// ❌ 避免 late 滥用\nlate String title; // 如果不确定会赋值,用 String? 更安全\n```",
70
+ "pattern": "final city = user?.address?.city ?? 'Unknown';\n_cache ??= {};\nif (user case User(:final name, :final email)) { ... }\nlate final TextEditingController _controller;",
71
+ "rationale": "Dart 3 的 sound null safety 在编译期防止 null 错误,应充分利用"
72
+ },
73
+ "description": "Dart: 空安全最佳实践",
74
+ "kind": "rule",
75
+ "doClause": "Apply Dart null safety best practices",
76
+ "language": "dart",
77
+ "headers": [],
78
+ "knowledgeType": "code-standard",
79
+ "usageGuide": "### 使用场景\\n处理可空值时参考此规范。",
80
+ "antiPattern": {
81
+ "bad": "final name = user!.name;",
82
+ "why": "! 绕过编译器保护,运行时可能 TypeError",
83
+ "fix": "final name = user?.name ?? 'Unknown';"
84
+ },
85
+ "reasoning": {
86
+ "whyStandard": "Dart Sound Null Safety 官方规范",
87
+ "sources": [
88
+ "Effective Dart - Usage (Null)",
89
+ "Dart Null Safety Migration Guide"
90
+ ],
91
+ "confidence": 0.95
92
+ }
93
+ }
94
+ ```
95
+
96
+ ---
97
+
98
+ ## 3. Widget 设计
99
+
100
+ ```json
101
+ {
102
+ "title": "Dart: Widget 组合与设计原则",
103
+ "content": {
104
+ "markdown": "## Flutter: Widget 组合设计\n\n### 标准模式\n```dart\n// ✅ 小组件拆分 — 每个 Widget 职责单一\nclass UserAvatar extends StatelessWidget {\n const UserAvatar({super.key, required this.url, this.radius = 24});\n\n final String url;\n final double radius;\n\n @override\n Widget build(BuildContext context) {\n return CircleAvatar(\n radius: radius,\n backgroundImage: NetworkImage(url),\n );\n }\n}\n\n// ✅ const 构造函数 — 优化 Widget 重建\nclass AppButton extends StatelessWidget {\n const AppButton({super.key, required this.label, required this.onPressed});\n\n final String label;\n final VoidCallback onPressed;\n\n @override\n Widget build(BuildContext context) {\n return ElevatedButton(\n onPressed: onPressed,\n child: Text(label),\n );\n }\n}\n\n// 使用时加 const\nconst AppButton(label: 'Submit', onPressed: _handleSubmit);\n\n// ✅ 组合优于继承 — 不要继承 MaterialApp/Scaffold 等\nclass HomePage extends StatelessWidget {\n const HomePage({super.key});\n\n @override\n Widget build(BuildContext context) {\n return Scaffold(\n appBar: const HomeAppBar(),\n body: const HomeBody(),\n floatingActionButton: const HomeFab(),\n );\n }\n}\n\n// ✅ BuildContext 不要跨 async gap\nFuture<void> _handleTap(BuildContext context) async {\n final navigator = Navigator.of(context); // 缓存 navigator\n await someAsyncWork();\n navigator.push(...); // 安全使用\n}\n\n// ❌ 反模式: 超大 build 方法\n// ❌ 反模式: Widget 中直接用 MediaQuery.of(context).size(触发全局重建)\n// ❌ 反模式: 在 build 中创建 controller / 订阅 Stream\n```",
105
+ "pattern": "class UserAvatar extends StatelessWidget {\n const UserAvatar({super.key, required this.url, this.radius = 24});\n final String url;\n final double radius;\n @override\n Widget build(BuildContext context) { ... }\n}",
106
+ "rationale": "Flutter Widget 是廉价对象,应大量拆分小 Widget 而非写超大 build 方法"
107
+ },
108
+ "description": "Flutter Widget 组合设计原则",
109
+ "kind": "rule",
110
+ "doClause": "Design widgets following composition over inheritance with const constructors",
111
+ "language": "dart",
112
+ "headers": ["import 'package:flutter/material.dart';"],
113
+ "knowledgeType": "code-pattern",
114
+ "usageGuide": "### 使用场景\\n创建新 Widget 时参考组合设计原则。",
115
+ "antiPattern": {
116
+ "bad": "// 500 行的 build 方法\n@override\nWidget build(BuildContext context) { /* 500 行嵌套 */ }",
117
+ "why": "超大 build 方法难以维护和测试,也无法利用 const 优化",
118
+ "fix": "拆分为多个小型 StatelessWidget,加 const 构造函数"
119
+ },
120
+ "reasoning": {
121
+ "whyStandard": "Flutter 官方 Performance Best Practices; Widget inspector 推荐",
122
+ "sources": [
123
+ "Flutter Performance Best Practices",
124
+ "Flutter Widget Catalog"
125
+ ],
126
+ "confidence": 0.9
127
+ }
128
+ }
129
+ ```
130
+
131
+ ### Widget 拆分速查表
132
+
133
+ | 场景 | 正确做法 | 错误做法 |
134
+ |------|---------|---------|
135
+ | 重复 UI 块 | 提取为 `const StatelessWidget` | 复制粘贴、用函数返回 Widget |
136
+ | 有状态组件 | `StatefulWidget` + 最小化状态 | 所有状态放在一个巨型 `State` |
137
+ | 动画 | `AnimatedFoo` / `TweenAnimationBuilder` | 手动 `Timer` |
138
+ | 列表项 | 独立 Widget(利于 `const` 缓存) | 在 `ListView.builder` 内联 |
139
+
140
+ ---
141
+
142
+ ## 4. 状态管理
143
+
144
+ ```json
145
+ {
146
+ "title": "Dart: 状态管理方案比较与最佳实践",
147
+ "content": {
148
+ "markdown": "## Flutter: 状态管理\n\n### BLoC / Cubit 模式\n```dart\n// ✅ Cubit — 简单状态\nclass CounterCubit extends Cubit<int> {\n CounterCubit() : super(0);\n\n void increment() => emit(state + 1);\n void decrement() => emit(state - 1);\n}\n\n// ✅ BLoC — 事件驱动\nsealed class AuthEvent {}\nclass LoginRequested extends AuthEvent {\n final String email;\n final String password;\n LoginRequested({required this.email, required this.password});\n}\nclass LogoutRequested extends AuthEvent {}\n\nsealed class AuthState {}\nclass AuthInitial extends AuthState {}\nclass AuthLoading extends AuthState {}\nclass AuthAuthenticated extends AuthState {\n final User user;\n AuthAuthenticated(this.user);\n}\nclass AuthError extends AuthState {\n final String message;\n AuthError(this.message);\n}\n\nclass AuthBloc extends Bloc<AuthEvent, AuthState> {\n AuthBloc({required AuthRepository authRepo})\n : _authRepo = authRepo,\n super(AuthInitial()) {\n on<LoginRequested>(_onLogin);\n on<LogoutRequested>(_onLogout);\n }\n\n final AuthRepository _authRepo;\n\n Future<void> _onLogin(LoginRequested event, Emitter<AuthState> emit) async {\n emit(AuthLoading());\n try {\n final user = await _authRepo.login(event.email, event.password);\n emit(AuthAuthenticated(user));\n } catch (e) {\n emit(AuthError(e.toString()));\n }\n }\n\n Future<void> _onLogout(LogoutRequested event, Emitter<AuthState> emit) async {\n await _authRepo.logout();\n emit(AuthInitial());\n }\n}\n```\n\n### Riverpod 模式\n```dart\n// ✅ Riverpod 2.0 — 声明式 Provider\n@riverpod\nFuture<List<User>> users(UsersRef ref) async {\n final repo = ref.watch(userRepositoryProvider);\n return repo.fetchAll();\n}\n\n@riverpod\nclass Counter extends _$Counter {\n @override\n int build() => 0;\n\n void increment() => state++;\n void decrement() => state--;\n}\n\n// 在 Widget 中消费\nclass UsersPage extends ConsumerWidget {\n const UsersPage({super.key});\n\n @override\n Widget build(BuildContext context, WidgetRef ref) {\n final asyncUsers = ref.watch(usersProvider);\n return asyncUsers.when(\n data: (users) => ListView.builder(...),\n loading: () => const CircularProgressIndicator(),\n error: (e, st) => Text('Error: $e'),\n );\n }\n}\n```\n\n### Provider (ChangeNotifier)\n```dart\n// ✅ 简单场景可用 ChangeNotifier\nclass CartNotifier extends ChangeNotifier {\n final List<CartItem> _items = [];\n List<CartItem> get items => List.unmodifiable(_items);\n\n void add(CartItem item) {\n _items.add(item);\n notifyListeners();\n }\n\n void remove(int index) {\n _items.removeAt(index);\n notifyListeners();\n }\n}\n```",
149
+ "pattern": "// Cubit\nclass CounterCubit extends Cubit<int> {\n CounterCubit() : super(0);\n void increment() => emit(state + 1);\n}\n\n// BLoC\nclass AuthBloc extends Bloc<AuthEvent, AuthState> { ... }\n\n// Riverpod\n@riverpod\nclass Counter extends _$Counter { ... }",
150
+ "rationale": "BLoC 适合复杂事件驱动流程,Riverpod 适合声明式数据流,ChangeNotifier 适合简单场景"
151
+ },
152
+ "description": "Flutter 状态管理方案与最佳实践",
153
+ "kind": "pattern",
154
+ "doClause": "Choose state management approach based on complexity",
155
+ "language": "dart",
156
+ "headers": ["import 'package:flutter_bloc/flutter_bloc.dart';"],
157
+ "knowledgeType": "code-pattern",
158
+ "usageGuide": "### 使用场景\\n选择状态管理方案时参考此对比。",
159
+ "reasoning": {
160
+ "whyStandard": "Flutter 官方推荐 + 社区主流方案",
161
+ "sources": [
162
+ "flutter_bloc documentation",
163
+ "Riverpod documentation",
164
+ "Flutter State Management"
165
+ ],
166
+ "confidence": 0.9
167
+ }
168
+ }
169
+ ```
170
+
171
+ ### 状态管理选型
172
+
173
+ | 方案 | 适合场景 | 核心概念 |
174
+ |------|---------|---------|
175
+ | `setState` | 单 Widget 局部状态 | 最简单,不超出 Widget 边界 |
176
+ | `ChangeNotifier` + `Provider` | 中小型应用 | 熟悉的观察者模式 |
177
+ | `BLoC / Cubit` | 复杂事件驱动流程 | Event → State 单向数据流 |
178
+ | `Riverpod` | 声明式数据流 + 依赖注入 | Provider + code generation |
179
+ | `GetX` | 快速原型 | 响应式 + 路由 + DI 一体化 |
180
+
181
+ ---
182
+
183
+ ## 5. 异步编程 (Future / Stream / async-await)
184
+
185
+ ```json
186
+ {
187
+ "title": "Dart: 异步编程最佳实践",
188
+ "content": {
189
+ "markdown": "## Dart: 异步编程\n\n### Future / async-await\n```dart\n// ✅ async-await — 清晰的异步控制流\nFuture<User> fetchUser(int id) async {\n final response = await http.get(Uri.parse('/api/users/$id'));\n if (response.statusCode != 200) {\n throw HttpException('Failed to fetch user: ${response.statusCode}');\n }\n return User.fromJson(jsonDecode(response.body));\n}\n\n// ✅ 并发请求 — Future.wait\nFuture<(User, List<Order>)> fetchUserWithOrders(int userId) async {\n final results = await Future.wait([\n fetchUser(userId),\n fetchOrders(userId),\n ]);\n return (results[0] as User, results[1] as List<Order>);\n}\n\n// ✅ 超时控制\nfinal user = await fetchUser(id).timeout(\n const Duration(seconds: 10),\n onTimeout: () => throw TimeoutException('fetchUser timeout'),\n);\n```\n\n### Stream\n```dart\n// ✅ StreamController — 自管理 Stream\nclass PositionService {\n final _controller = StreamController<Position>.broadcast();\n Stream<Position> get positionStream => _controller.stream;\n\n void updatePosition(Position pos) {\n _controller.add(pos);\n }\n\n void dispose() {\n _controller.close(); // 务必关闭!\n }\n}\n\n// ✅ async* 生成器\nStream<int> countDown(int from) async* {\n for (var i = from; i >= 0; i--) {\n yield i;\n await Future.delayed(const Duration(seconds: 1));\n }\n}\n\n// ✅ Stream 变换\nfinal filtered = positionStream\n .where((pos) => pos.accuracy < 10)\n .map((pos) => LatLng(pos.latitude, pos.longitude))\n .distinct();\n\n// ❌ 反模式: 忘记取消 StreamSubscription\n// ❌ 反模式: 忘记关闭 StreamController\n```",
190
+ "pattern": "Future<User> fetchUser(int id) async {\n final response = await http.get(...);\n return User.fromJson(jsonDecode(response.body));\n}\n\nStream<int> countDown(int from) async* {\n for (var i = from; i >= 0; i--) {\n yield i;\n await Future.delayed(const Duration(seconds: 1));\n }\n}",
191
+ "rationale": "Dart 的 async-await 基于 Future,Stream 用于多值异步,两者是 Dart 异步编程的核心"
192
+ },
193
+ "description": "Dart 异步编程: Future/Stream/async-await",
194
+ "kind": "pattern",
195
+ "doClause": "Use async-await for single values, Stream for multiple async values",
196
+ "language": "dart",
197
+ "headers": ["import 'dart:async';"],
198
+ "knowledgeType": "code-pattern",
199
+ "usageGuide": "### 使用场景\\n处理异步操作时参考此规范。",
200
+ "antiPattern": {
201
+ "bad": "// 忘记 await\nfetchUser(id); // Future 被忽略,错误静默丢失\n// 忘记取消订阅\nstream.listen(print); // 永不取消",
202
+ "why": "未 await 的 Future 错误会静默丢失;未取消的 StreamSubscription 导致内存泄漏",
203
+ "fix": "await fetchUser(id);\nfinal sub = stream.listen(print);\n// 在 dispose 中: sub.cancel();"
204
+ },
205
+ "reasoning": {
206
+ "whyStandard": "Dart 语言官方异步编程指南",
207
+ "sources": [
208
+ "Dart Asynchronous Programming",
209
+ "Effective Dart - Usage (Async)"
210
+ ],
211
+ "confidence": 0.95
212
+ }
213
+ }
214
+ ```
215
+
216
+ ---
217
+
218
+ ## 6. 不可变数据模型 (Freezed / sealed class)
219
+
220
+ ```json
221
+ {
222
+ "title": "Dart: Freezed 不可变数据模型",
223
+ "content": {
224
+ "markdown": "## Dart: Freezed + sealed class 数据建模\n\n### Freezed — 不可变值对象 + union type\n```dart\n// ✅ Freezed 数据类\n@freezed\nclass User with _$User {\n const factory User({\n required int id,\n required String name,\n required String email,\n @Default('') String avatarUrl,\n }) = _User;\n\n factory User.fromJson(Map<String, dynamic> json) => _$UserFromJson(json);\n}\n\n// 使用: copyWith 创建修改后的副本\nfinal updated = user.copyWith(name: 'Bob');\n\n// ✅ Freezed union (ADT)\n@freezed\nsealed class Result<T> with _$Result<T> {\n const factory Result.success(T data) = Success<T>;\n const factory Result.failure(String message) = Failure<T>;\n const factory Result.loading() = Loading<T>;\n}\n\n// 使用: 模式匹配 (Dart 3)\nfinal widget = switch (result) {\n Success(:final data) => Text('$data'),\n Failure(:final message) => Text('Error: $message'),\n Loading() => const CircularProgressIndicator(),\n};\n```\n\n### Dart 3 sealed class(无 Freezed)\n```dart\n// ✅ 纯 Dart 3 sealed class\nsealed class AuthState {}\n\nclass Authenticated extends AuthState {\n final User user;\n Authenticated(this.user);\n}\n\nclass Unauthenticated extends AuthState {}\n\nclass AuthLoading extends AuthState {}\n\n// 编译器强制 exhaustive switch\nString describe(AuthState state) => switch (state) {\n Authenticated(:final user) => 'Hello ${user.name}',\n Unauthenticated() => 'Please login',\n AuthLoading() => 'Loading...',\n};\n```",
225
+ "pattern": "@freezed\nclass User with _$User {\n const factory User({required int id, required String name}) = _User;\n factory User.fromJson(Map<String, dynamic> json) => _$UserFromJson(json);\n}\n\nsealed class Result<T> with _$Result<T> {\n const factory Result.success(T data) = Success<T>;\n const factory Result.failure(String message) = Failure<T>;\n}",
226
+ "rationale": "Freezed 自动生成 copyWith/==/hashCode/toString/JSON 序列化,sealed class 配合 Dart 3 模式匹配实现编译器级别的穷尽检查"
227
+ },
228
+ "description": "Dart Freezed 不可变数据模型 + sealed class",
229
+ "kind": "pattern",
230
+ "doClause": "Use Freezed for immutable data models and sealed class for union types",
231
+ "language": "dart",
232
+ "headers": ["import 'package:freezed_annotation/freezed_annotation.dart';"],
233
+ "knowledgeType": "code-pattern",
234
+ "usageGuide": "### 使用场景\\n定义数据模型或状态类型时参考。",
235
+ "antiPattern": {
236
+ "bad": "class User {\n String name;\n User(this.name);\n // 手写 ==, hashCode, copyWith, toString, toJson ...\n}",
237
+ "why": "手写样板代码容易出错且维护成本高",
238
+ "fix": "使用 @freezed 自动生成"
239
+ },
240
+ "reasoning": {
241
+ "whyStandard": "Freezed 是 Flutter 社区最流行的代码生成方案",
242
+ "sources": [
243
+ "freezed package documentation",
244
+ "Dart 3 Patterns and Records"
245
+ ],
246
+ "confidence": 0.9
247
+ }
248
+ }
249
+ ```
250
+
251
+ ---
252
+
253
+ ## 7. 错误处理
254
+
255
+ ```json
256
+ {
257
+ "title": "Dart: 错误处理最佳实践",
258
+ "content": {
259
+ "markdown": "## Dart: 错误处理\n\n### 标准模式\n```dart\n// ✅ 自定义 Exception 类型\nclass NetworkException implements Exception {\n final int statusCode;\n final String message;\n const NetworkException(this.statusCode, this.message);\n\n @override\n String toString() => 'NetworkException($statusCode): $message';\n}\n\nclass TimeoutException extends NetworkException {\n const TimeoutException() : super(408, 'Request timeout');\n}\n\n// ✅ 明确 catch 类型\nFuture<User> getUser(int id) async {\n try {\n return await _api.fetchUser(id);\n } on TimeoutException {\n return _cache.getUser(id) ?? rethrow;\n } on NetworkException catch (e) {\n _logger.warning('Network error: $e');\n rethrow;\n } on FormatException catch (e) {\n _logger.severe('Parse error: $e');\n throw DataException('Invalid response format');\n }\n}\n\n// ✅ Result 类型(函数式风格)\nsealed class Result<T> {\n const Result();\n}\nclass Success<T> extends Result<T> {\n final T data;\n const Success(this.data);\n}\nclass Failure<T> extends Result<T> {\n final Object error;\n final StackTrace stackTrace;\n const Failure(this.error, this.stackTrace);\n}\n\nFuture<Result<User>> getUserSafe(int id) async {\n try {\n final user = await _api.fetchUser(id);\n return Success(user);\n } catch (e, st) {\n return Failure(e, st);\n }\n}\n\n// ❌ 避免: catch 所有错误后忽略\ntry { ... } catch (_) { } // 吞掉所有错误\n\n// ❌ 避免: 用 String 表示错误\nthrow 'Something went wrong'; // 没有堆栈信息\n```",
260
+ "pattern": "class NetworkException implements Exception {\n final int statusCode;\n final String message;\n const NetworkException(this.statusCode, this.message);\n}\n\ntry {\n ...\n} on TimeoutException {\n ...\n} on NetworkException catch (e) {\n rethrow;\n}",
261
+ "rationale": "Dart 用 on .. catch 精确捕获不同异常类型,rethrow 保留原始堆栈"
262
+ },
263
+ "description": "Dart 错误处理: 自定义 Exception + on-catch + Result 模式",
264
+ "kind": "pattern",
265
+ "doClause": "Use custom Exception types with specific on-catch blocks",
266
+ "language": "dart",
267
+ "headers": [],
268
+ "knowledgeType": "best-practice",
269
+ "usageGuide": "### 使用场景\\n设计错误处理逻辑时参考。",
270
+ "antiPattern": {
271
+ "bad": "try { ... } catch (_) { } // 或 throw 'error string'",
272
+ "why": "吞掉所有错误让 bug 难以排查;throw String 丢失堆栈信息",
273
+ "fix": "自定义 Exception 类 + on .. catch 精确捕获 + rethrow"
274
+ },
275
+ "reasoning": {
276
+ "whyStandard": "Effective Dart - Error handling",
277
+ "sources": [
278
+ "Effective Dart - Usage (Errors)",
279
+ "Dart Language Tour - Exceptions"
280
+ ],
281
+ "confidence": 0.95
282
+ }
283
+ }
284
+ ```
285
+
286
+ ---
287
+
288
+ ## 8. 依赖注入
289
+
290
+ ```json
291
+ {
292
+ "title": "Dart: 依赖注入模式",
293
+ "content": {
294
+ "markdown": "## Dart: 依赖注入\n\n### get_it + injectable\n```dart\n// ✅ 定义抽象层\nabstract class UserRepository {\n Future<User> getById(int id);\n Future<List<User>> getAll();\n}\n\n// ✅ 实现\n@LazySingleton(as: UserRepository)\nclass UserRepositoryImpl implements UserRepository {\n final ApiClient _api;\n final LocalDatabase _db;\n\n UserRepositoryImpl(this._api, this._db);\n\n @override\n Future<User> getById(int id) async {\n try {\n return await _api.fetchUser(id);\n } catch (_) {\n return await _db.getUser(id);\n }\n }\n\n @override\n Future<List<User>> getAll() => _api.fetchUsers();\n}\n\n// ✅ 注册 (injectable 自动生成)\n@InjectableInit()\nvoid configureDependencies() => getIt.init();\n\n// ✅ 消费\nclass UserBloc extends Bloc<UserEvent, UserState> {\n UserBloc({required UserRepository userRepo})\n : _userRepo = userRepo,\n super(UserInitial());\n\n final UserRepository _userRepo;\n}\n```\n\n### Riverpod DI(无 get_it)\n```dart\n// ✅ Riverpod 天然 DI\n@riverpod\nUserRepository userRepository(UserRepositoryRef ref) {\n return UserRepositoryImpl(\n ref.watch(apiClientProvider),\n ref.watch(localDatabaseProvider),\n );\n}\n\n// 测试时 override\nvoid main() {\n testWidgets('...', (tester) async {\n await tester.pumpWidget(\n ProviderScope(\n overrides: [\n userRepositoryProvider.overrideWithValue(MockUserRepository()),\n ],\n child: const MyApp(),\n ),\n );\n });\n}\n```",
295
+ "pattern": "@LazySingleton(as: UserRepository)\nclass UserRepositoryImpl implements UserRepository { ... }\n\n@InjectableInit()\nvoid configureDependencies() => getIt.init();",
296
+ "rationale": "DI 解耦接口与实现,便于测试 mock 和替换"
297
+ },
298
+ "description": "Dart 依赖注入: get_it + injectable / Riverpod",
299
+ "kind": "pattern",
300
+ "doClause": "Use DI to decouple interface from implementation",
301
+ "language": "dart",
302
+ "headers": ["import 'package:injectable/injectable.dart';", "import 'package:get_it/get_it.dart';"],
303
+ "knowledgeType": "architecture",
304
+ "usageGuide": "### 使用场景\\n设计服务层依赖关系时参考。",
305
+ "reasoning": {
306
+ "whyStandard": "get_it + injectable 是 Flutter DI 最流行方案; Riverpod 自带 DI",
307
+ "sources": [
308
+ "get_it package documentation",
309
+ "injectable package documentation",
310
+ "Riverpod documentation"
311
+ ],
312
+ "confidence": 0.9
313
+ }
314
+ }
315
+ ```
316
+
317
+ ---
318
+
319
+ ## 9. Clean Architecture
320
+
321
+ ```json
322
+ {
323
+ "title": "Dart: Flutter Clean Architecture",
324
+ "content": {
325
+ "markdown": "## Flutter: Clean Architecture\n\n### 标准分层\n```\nlib/\n├── core/ # 共享基础设施\n│ ├── error/ # Exception / Failure 定义\n│ ├── network/ # Dio/http 封装\n│ ├── router/ # GoRouter 路由配置\n│ └── theme/ # 主题定义\n├── features/ # 按功能模块划分\n│ └── auth/\n│ ├── data/\n│ │ ├── datasources/ # Remote + Local 数据源\n│ │ ├── models/ # DTO (JSON 序列化)\n│ │ └── repositories/ # Repository 实现\n│ ├── domain/\n│ │ ├── entities/ # 业务实体 (纯 Dart)\n│ │ ├── repositories/ # Repository 抽象接口\n│ │ └── usecases/ # 用例 (业务逻辑)\n│ └── presentation/\n│ ├── bloc/ # BLoC / Cubit\n│ ├── pages/ # 页面 Widget\n│ └── widgets/ # 局部 Widget\n├── injection_container.dart # DI 配置\n└── main.dart\n```\n\n### 依赖规则\n```\nPresentation → Domain ← Data\n ↓ ↑ ↓\n BLoC UseCase Repository\n ↓ ↑ ↓\n Widget Entity DataSource\n```\n\n- **Domain 层不依赖任何外层** (纯 Dart, 无 Flutter import)\n- **Data 层实现 Domain 定义的抽象接口**\n- **Presentation 层只依赖 Domain 层**\n\n### UseCase 模式\n```dart\nabstract class UseCase<Type, Params> {\n Future<Either<Failure, Type>> call(Params params);\n}\n\nclass GetUser implements UseCase<User, int> {\n final UserRepository _repo;\n GetUser(this._repo);\n\n @override\n Future<Either<Failure, User>> call(int id) {\n return _repo.getById(id);\n }\n}\n```",
326
+ "pattern": "lib/\n├── core/\n├── features/\n│ └── auth/\n│ ├── data/ (datasources, models, repositories impl)\n│ ├── domain/ (entities, repository interfaces, usecases)\n│ └── presentation/ (bloc, pages, widgets)\n├── injection_container.dart\n└── main.dart",
327
+ "rationale": "Clean Architecture 保证核心业务逻辑(Domain)不依赖框架和外部库,Data 和 Presentation 可独立替换"
328
+ },
329
+ "description": "Flutter Clean Architecture 分层结构",
330
+ "kind": "fact",
331
+ "doClause": "Follow Clean Architecture layering: Presentation → Domain ← Data",
332
+ "language": "dart",
333
+ "headers": [],
334
+ "knowledgeType": "architecture",
335
+ "usageGuide": "### 使用场景\\n设计项目架构时参考。",
336
+ "reasoning": {
337
+ "whyStandard": "Reso Coder Flutter Clean Architecture 系列 + Uncle Bob Clean Architecture",
338
+ "sources": [
339
+ "Reso Coder - Flutter TDD Clean Architecture",
340
+ "Robert C. Martin - Clean Architecture"
341
+ ],
342
+ "confidence": 0.85
343
+ }
344
+ }
345
+ ```
346
+
347
+ ---
348
+
349
+ ## 10. Extension 与 Mixin
350
+
351
+ ```json
352
+ {
353
+ "title": "Dart: Extension 与 Mixin",
354
+ "content": {
355
+ "markdown": "## Dart: Extension 与 Mixin\n\n### Extension — 为已有类型添加方法\n```dart\n// ✅ 为 BuildContext 添加便捷方法\nextension BuildContextX on BuildContext {\n ThemeData get theme => Theme.of(this);\n TextTheme get textTheme => Theme.of(this).textTheme;\n ColorScheme get colorScheme => Theme.of(this).colorScheme;\n MediaQueryData get mediaQuery => MediaQuery.of(this);\n double get screenWidth => mediaQuery.size.width;\n\n void showSnackBar(String message) {\n ScaffoldMessenger.of(this).showSnackBar(\n SnackBar(content: Text(message)),\n );\n }\n}\n\n// ✅ 为 String 添加工具方法\nextension StringX on String {\n String get capitalized =>\n isEmpty ? this : '${this[0].toUpperCase()}${substring(1)}';\n bool get isValidEmail =>\n RegExp(r'^[\\w-\\.]+@[\\w-]+\\.[a-z]{2,}$').hasMatch(this);\n}\n\n// ✅ 为 DateTime 添加格式化\nextension DateTimeX on DateTime {\n String get ymd => '$year-${month.toString().padLeft(2, '0')}-${day.toString().padLeft(2, '0')}';\n bool get isToday {\n final now = DateTime.now();\n return year == now.year && month == now.month && day == now.day;\n }\n}\n```\n\n### Mixin — 跨类复用行为\n```dart\n// ✅ Mixin 复用日志能力\nmixin LoggerMixin {\n late final Logger _logger = Logger(runtimeType.toString());\n\n void logInfo(String msg) => _logger.info(msg);\n void logWarning(String msg) => _logger.warning(msg);\n void logError(String msg, [Object? error]) => _logger.severe(msg, error);\n}\n\nclass AuthService with LoggerMixin {\n Future<void> login(String email, String password) async {\n logInfo('Attempting login for $email');\n // ...\n }\n}\n\n// ✅ Mixin with on — 约束宿主类型\nmixin AutoDisposeMixin on State {\n final _disposables = <VoidCallback>[];\n\n void autoDispose(VoidCallback callback) => _disposables.add(callback);\n\n @override\n void dispose() {\n for (final fn in _disposables) { fn(); }\n super.dispose();\n }\n}\n```",
356
+ "pattern": "extension BuildContextX on BuildContext {\n ThemeData get theme => Theme.of(this);\n void showSnackBar(String message) { ... }\n}\n\nmixin LoggerMixin {\n late final Logger _logger = Logger(runtimeType.toString());\n void logInfo(String msg) => _logger.info(msg);\n}",
357
+ "rationale": "Extension 为已有类型添加方法而不修改源码;Mixin 在类间复用行为而不用继承"
358
+ },
359
+ "description": "Dart Extension 与 Mixin 复用模式",
360
+ "kind": "pattern",
361
+ "doClause": "Use Extension for utility methods on existing types, Mixin for cross-class behavior reuse",
362
+ "language": "dart",
363
+ "headers": [],
364
+ "knowledgeType": "code-pattern",
365
+ "usageGuide": "### 使用场景\\n需要为已有类型添加方法或跨类复用逻辑时参考。",
366
+ "reasoning": {
367
+ "whyStandard": "Dart 语言特性,社区广泛使用",
368
+ "sources": [
369
+ "Dart Language Tour - Extensions",
370
+ "Dart Language Tour - Mixins"
371
+ ],
372
+ "confidence": 0.9
373
+ }
374
+ }
375
+ ```
376
+
377
+ ---
378
+
379
+ ## 11. 测试
380
+
381
+ ```json
382
+ {
383
+ "title": "Dart: Flutter 测试最佳实践",
384
+ "content": {
385
+ "markdown": "## Flutter: 测试金字塔\n\n### 单元测试\n```dart\n// ✅ 用 group + test 组织\ngroup('UserRepository', () {\n late MockApiClient mockApi;\n late UserRepositoryImpl repo;\n\n setUp(() {\n mockApi = MockApiClient();\n repo = UserRepositoryImpl(mockApi);\n });\n\n test('getById returns user on success', () async {\n when(() => mockApi.fetchUser(1)).thenAnswer(\n (_) async => UserModel(id: 1, name: 'Alice'),\n );\n\n final result = await repo.getById(1);\n\n expect(result.name, equals('Alice'));\n verify(() => mockApi.fetchUser(1)).called(1);\n });\n\n test('getById throws on network error', () {\n when(() => mockApi.fetchUser(any())).thenThrow(\n const NetworkException(500, 'Server error'),\n );\n\n expect(() => repo.getById(1), throwsA(isA<NetworkException>()));\n });\n});\n```\n\n### Widget 测试\n```dart\ntestWidgets('LoginPage shows error on invalid input', (tester) async {\n await tester.pumpWidget(\n const MaterialApp(home: LoginPage()),\n );\n\n // 点击提交(空输入)\n await tester.tap(find.byType(ElevatedButton));\n await tester.pump();\n\n // 验证错误提示\n expect(find.text('Email is required'), findsOneWidget);\n});\n```\n\n### BLoC 测试\n```dart\nblocTest<AuthBloc, AuthState>(\n 'emits [AuthLoading, AuthAuthenticated] on successful login',\n build: () {\n when(() => mockRepo.login(any(), any())).thenAnswer(\n (_) async => User(id: 1, name: 'Alice'),\n );\n return AuthBloc(authRepo: mockRepo);\n },\n act: (bloc) => bloc.add(\n LoginRequested(email: 'a@b.com', password: '123'),\n ),\n expect: () => [\n isA<AuthLoading>(),\n isA<AuthAuthenticated>(),\n ],\n);\n```\n\n### Golden 测试\n```dart\ntestWidgets('UserCard matches golden', (tester) async {\n await tester.pumpWidget(\n MaterialApp(\n home: UserCard(user: User(id: 1, name: 'Alice')),\n ),\n );\n\n await expectLater(\n find.byType(UserCard),\n matchesGoldenFile('goldens/user_card.png'),\n );\n});\n```",
386
+ "pattern": "// 单元测试\ngroup('UserRepository', () {\n test('getById returns user', () async { ... });\n});\n\n// Widget 测试\ntestWidgets('...', (tester) async {\n await tester.pumpWidget(...);\n expect(find.text('...'), findsOneWidget);\n});\n\n// BLoC 测试\nblocTest<AuthBloc, AuthState>('...', build: () => ..., act: ..., expect: ...);",
387
+ "rationale": "Flutter 提供三层测试: unit → widget → integration,应优先保证 unit 和 widget 覆盖"
388
+ },
389
+ "description": "Flutter 测试: 单元/Widget/BLoC/Golden",
390
+ "kind": "pattern",
391
+ "doClause": "Write unit, widget, BLoC, and golden tests following the test pyramid",
392
+ "language": "dart",
393
+ "headers": ["import 'package:flutter_test/flutter_test.dart';", "import 'package:mocktail/mocktail.dart';"],
394
+ "knowledgeType": "best-practice",
395
+ "usageGuide": "### 使用场景\\n编写测试代码时参考。",
396
+ "reasoning": {
397
+ "whyStandard": "Flutter 官方测试指南 + bloc_test 文档",
398
+ "sources": [
399
+ "Flutter Testing Documentation",
400
+ "bloc_test package",
401
+ "mocktail package"
402
+ ],
403
+ "confidence": 0.9
404
+ }
405
+ }
406
+ ```
407
+
408
+ ### 测试工具速查表
409
+
410
+ | 工具 | 用途 |
411
+ |------|------|
412
+ | `flutter_test` | Widget 测试 |
413
+ | `mocktail` / `mockito` | Mock 框架 |
414
+ | `bloc_test` | BLoC/Cubit 测试 |
415
+ | `golden_toolkit` | Golden 截图测试 |
416
+ | `integration_test` | 集成/E2E 测试 |
417
+ | `patrol` | 原生 UI 测试 |
418
+
419
+ ---
420
+
421
+ ## 12. 导航与路由
422
+
423
+ ```json
424
+ {
425
+ "title": "Dart: Flutter 路由最佳实践",
426
+ "content": {
427
+ "markdown": "## Flutter: 声明式路由 (GoRouter)\n\n### 标准模式\n```dart\n// ✅ GoRouter 声明式路由\nfinal router = GoRouter(\n initialLocation: '/',\n redirect: (context, state) {\n final isAuth = ref.read(authProvider).isAuthenticated;\n if (!isAuth && !state.matchedLocation.startsWith('/login')) {\n return '/login';\n }\n return null;\n },\n routes: [\n GoRoute(\n path: '/',\n builder: (context, state) => const HomePage(),\n routes: [\n GoRoute(\n path: 'users/:id',\n builder: (context, state) {\n final id = int.parse(state.pathParameters['id']!);\n return UserDetailPage(userId: id);\n },\n ),\n ],\n ),\n GoRoute(\n path: '/login',\n builder: (context, state) => const LoginPage(),\n ),\n ],\n);\n\n// ✅ 类型安全路由 (go_router_builder)\n@TypedGoRoute<HomeRoute>(path: '/')\nclass HomeRoute extends GoRouteData {\n const HomeRoute();\n @override\n Widget build(BuildContext context, GoRouterState state) => const HomePage();\n}\n\n// ✅ 导航\ncontext.go('/users/42'); // 替换\ncontext.push('/users/42'); // 压栈\ncontext.pop(); // 返回\nconst HomeRoute().go(context); // 类型安全\n```",
428
+ "pattern": "final router = GoRouter(\n routes: [\n GoRoute(path: '/', builder: (_, __) => const HomePage()),\n ],\n);\ncontext.go('/users/42');",
429
+ "rationale": "GoRouter 是 Flutter 官方推荐的声明式路由方案,支持深链接和 Web"
430
+ },
431
+ "description": "Flutter 声明式路由 (GoRouter)",
432
+ "kind": "pattern",
433
+ "doClause": "Use GoRouter for declarative routing with type-safe navigation",
434
+ "language": "dart",
435
+ "headers": ["import 'package:go_router/go_router.dart';"],
436
+ "knowledgeType": "architecture",
437
+ "usageGuide": "### 使用场景\\n设计应用路由时参考。",
438
+ "reasoning": {
439
+ "whyStandard": "GoRouter 是 Flutter 官方维护的路由库",
440
+ "sources": [
441
+ "go_router documentation",
442
+ "Flutter Navigation and Routing"
443
+ ],
444
+ "confidence": 0.9
445
+ }
446
+ }
447
+ ```
448
+
449
+ ---
450
+
451
+ ## 13. 平台通道与 FFI
452
+
453
+ ```json
454
+ {
455
+ "title": "Dart: 平台通道与 FFI",
456
+ "content": {
457
+ "markdown": "## Flutter: 平台通道\n\n### MethodChannel (消息传递)\n```dart\n// ✅ Dart 侧\nclass BatteryService {\n static const _channel = MethodChannel('com.example/battery');\n\n Future<int> getBatteryLevel() async {\n final level = await _channel.invokeMethod<int>('getBatteryLevel');\n return level ?? -1;\n }\n}\n\n// ✅ Android 侧 (Kotlin)\nclass MainActivity : FlutterActivity() {\n override fun configureFlutterEngine(flutterEngine: FlutterEngine) {\n MethodChannel(flutterEngine.dartExecutor, \"com.example/battery\")\n .setMethodCallHandler { call, result ->\n if (call.method == \"getBatteryLevel\") {\n result.success(getBatteryLevel())\n } else {\n result.notImplemented()\n }\n }\n }\n}\n```\n\n### Pigeon (类型安全)\n```dart\n// ✅ 用 Pigeon 生成类型安全的通道代码\n@HostApi()\nabstract class BatteryApi {\n int getBatteryLevel();\n bool isCharging();\n}\n\n// 自动生成 Dart + Kotlin/Swift 代码\n// pigeon --input pigeons/battery.dart\n```\n\n### dart:ffi (C 互操作)\n```dart\n// ✅ FFI 调用原生库\nfinal dylib = DynamicLibrary.open('libnative.so');\ntypedef NativeAdd = Int32 Function(Int32, Int32);\ntypedef DartAdd = int Function(int, int);\nfinal add = dylib.lookupFunction<NativeAdd, DartAdd>('add');\nprint(add(3, 4)); // 7\n```",
458
+ "pattern": "static const _channel = MethodChannel('com.example/battery');\nfinal level = await _channel.invokeMethod<int>('getBatteryLevel');",
459
+ "rationale": "MethodChannel 适合简单 RPC;Pigeon 消除手动序列化错误;FFI 适合高性能 C 库调用"
460
+ },
461
+ "description": "Flutter 平台通道: MethodChannel / Pigeon / FFI",
462
+ "kind": "fact",
463
+ "doClause": "Use Pigeon for type-safe platform channels, FFI for C interop",
464
+ "language": "dart",
465
+ "headers": ["import 'package:flutter/services.dart';"],
466
+ "knowledgeType": "architecture",
467
+ "usageGuide": "### 使用场景\\n需要调用原生平台 API 时参考。",
468
+ "reasoning": {
469
+ "whyStandard": "Flutter 官方平台交互文档",
470
+ "sources": [
471
+ "Flutter Platform Channels",
472
+ "Pigeon documentation",
473
+ "dart:ffi documentation"
474
+ ],
475
+ "confidence": 0.85
476
+ }
477
+ }
478
+ ```
479
+
480
+ ---
481
+
482
+ ## 14. 性能优化
483
+
484
+ ```json
485
+ {
486
+ "title": "Dart: Flutter 性能优化",
487
+ "content": {
488
+ "markdown": "## Flutter: 性能优化\n\n### Widget 重建优化\n```dart\n// ✅ const Widget — 避免不必要重建\nconst SizedBox(height: 16);\nconst Divider();\nconst AppHeader(title: 'Home');\n\n// ✅ RepaintBoundary — 隔离重绘区域\nRepaintBoundary(\n child: ComplexAnimation(),\n)\n\n// ✅ 避免在 build 中创建对象\n// ❌ 错误\n@override\nWidget build(BuildContext context) {\n final style = TextStyle(fontSize: 16); // 每次 build 都创建\n return Text('Hello', style: style);\n}\n\n// ✅ 正确\nstatic const _style = TextStyle(fontSize: 16);\n@override\nWidget build(BuildContext context) {\n return const Text('Hello', style: _style);\n}\n```\n\n### 列表优化\n```dart\n// ✅ ListView.builder (懒加载)\nListView.builder(\n itemCount: items.length,\n itemBuilder: (context, index) => ItemCard(item: items[index]),\n)\n\n// ✅ 指定 itemExtent 提升滚动性能\nListView.builder(\n itemCount: items.length,\n itemExtent: 72, // 固定高度\n itemBuilder: (context, index) => ItemCard(item: items[index]),\n)\n\n// ❌ 避免 ListView(children: []) 一次加载所有子 Widget\n```\n\n### 图片优化\n```dart\n// ✅ 指定 cacheWidth/cacheHeight 降低解码内存\nImage.network(\n imageUrl,\n cacheWidth: 200, // 按显示尺寸解码\n cacheHeight: 200,\n)\n\n// ✅ 使用 cached_network_image\nCachedNetworkImage(\n imageUrl: url,\n placeholder: (_, __) => const Shimmer(),\n errorWidget: (_, __, ___) => const Icon(Icons.error),\n)\n```",
489
+ "pattern": "const Widget(...);\nRepaintBoundary(child: ...);\nListView.builder(itemExtent: 72, itemBuilder: ...);\nImage.network(url, cacheWidth: 200);",
490
+ "rationale": "Flutter 60fps 要求每帧 16ms,优化 Widget 重建和图片解码是关键"
491
+ },
492
+ "description": "Flutter 性能优化: const Widget / RepaintBoundary / 列表懒加载",
493
+ "kind": "rule",
494
+ "doClause": "Use const constructors, RepaintBoundary, and ListView.builder for performance",
495
+ "language": "dart",
496
+ "headers": ["import 'package:flutter/material.dart';"],
497
+ "knowledgeType": "best-practice",
498
+ "usageGuide": "### 使用场景\\n需要优化 Flutter 渲染性能时参考。",
499
+ "reasoning": {
500
+ "whyStandard": "Flutter Performance Best Practices 官方文档",
501
+ "sources": [
502
+ "Flutter Performance Best Practices",
503
+ "Flutter DevTools Profiling"
504
+ ],
505
+ "confidence": 0.9
506
+ }
507
+ }
508
+ ```
509
+
510
+ ---
511
+
512
+ ## 15. Dart (Flutter) 特有维度 (extraDimensions)
513
+
514
+ 冷启动分析 Dart / Flutter 项目时,除了通用维度,还应额外关注:
515
+
516
+ | 额外维度 | 寻找什么 | 候选类型 |
517
+ |---------|---------|---------|
518
+ | **Widget 设计模式** | StatelessWidget 拆分、const 使用率、组合 vs 继承 | `code-pattern` |
519
+ | **状态管理** | BLoC/Cubit/Riverpod/Provider/GetX 选型与使用模式 | `architecture` |
520
+ | **空安全** | nullable 使用、! 操作符频率、late 使用场景 | `code-standard` |
521
+ | **不可变模型** | Freezed 使用、sealed class/union type、copyWith 模式 | `code-pattern` |
522
+ | **路由架构** | GoRouter/auto_route 配置、深链接、路由守卫 | `architecture` |
523
+ | **异步模式** | Future/Stream 使用、StreamController 生命周期、取消策略 | `code-pattern` |
524
+ | **平台交互** | MethodChannel/Pigeon/FFI、iOS/Android 原生集成 | `architecture` |
525
+ | **测试覆盖** | Widget test/BLoC test/Golden test/Integration test 策略 | `best-practice` |
526
+ | **依赖注入** | get_it + injectable / Riverpod DI / Provider | `architecture` |
527
+ | **构建配置** | Flavors/多环境、build_runner、code generation | `config` |
528
+ | **性能** | const Widget、RepaintBoundary、ListView.builder、图片缓存 | `best-practice` |
529
+ | **项目布局** | Clean Architecture 分层、features/ 模块化、Melos monorepo | `architecture` |
530
+
531
+ ---
532
+
533
+ ## 关联 Skills
534
+
535
+ - **autosnippet-coldstart**: 冷启动分析模板
536
+ - **autosnippet-reference-swift**: Swift 业界最佳实践参考
537
+ - **autosnippet-reference-objc**: Objective-C 业界最佳实践参考
538
+ - **autosnippet-reference-jsts**: JavaScript/TypeScript 业界最佳实践参考
539
+ - **autosnippet-reference-python**: Python 业界最佳实践参考
540
+ - **autosnippet-reference-java**: Java 业界最佳实践参考
541
+ - **autosnippet-reference-kotlin**: Kotlin 业界最佳实践参考
542
+ - **autosnippet-reference-go**: Go 业界最佳实践参考
543
+ ```