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
@@ -0,0 +1,526 @@
1
+ ---
2
+ name: autosnippet-reference-kotlin
3
+ description: Kotlin 业界最佳实践参考。涵盖空安全、协程、Flow、扩展函数、sealed class、DSL、委托、集合、Compose、测试,为冷启动分析提供高质量参考标准。
4
+ ---
5
+
6
+ # Kotlin 最佳实践参考 (Industry Reference)
7
+
8
+ > 本 Skill 为 **autosnippet-coldstart** 的 Companion Skill。在冷启动分析 Kotlin 项目时,请参考以下业界标准产出高质量候选。
9
+ > **来源**: Kotlin Coding Conventions (kotlinlang.org), Android Kotlin Style Guide, Effective Kotlin (Moskała), Kotlin Coroutines Guide
10
+
11
+ ---
12
+
13
+ ## 1. 空安全
14
+
15
+ ### 核心规则
16
+
17
+ ```json
18
+ {
19
+ "title": "Kotlin: 空安全最佳实践",
20
+ "content": {
21
+ "markdown": "## Kotlin: 空安全最佳实践\n\n### 标准模式\n```kotlin\n// ✅ 优先使用不可空类型\nfun getUser(id: Long): User { ... }\n\n// ✅ 当值确实可能为 null 时才使用 nullable\nfun findUser(id: Long): User? {\n return userRepository.findById(id)\n}\n\n// ✅ 安全调用链 + Elvis\nval city = user?.address?.city ?: \"Unknown\"\n\n// ✅ let + 安全调用处理 nullable\nuser?.let { activeUser ->\n sendWelcomeEmail(activeUser)\n}\n\n// ✅ require / check 做前置条件校验\nfun updateUser(user: User?) {\n requireNotNull(user) { \"user must not be null\" }\n require(user.age >= 0) { \"age must be non-negative\" }\n check(user.isActive) { \"user must be active\" }\n}\n\n// ✅ 当表达式真正需要 early return\nval name = user?.name ?: return\nval email = user?.email ?: throw IllegalStateException(\"email required\")\n\n// ❌ 避免 !! 操作符\nval name = user!!.name // 可能抛 NPE\n\n// ❌ 避免无意义的 nullable\nfun getCount(): Int? = 42 // Int 就够了\n```",
22
+ "pattern": "// ✅ 优先使用不可空类型\nfun getUser(id: Long): User { ... }\n\n// ✅ 当值确实可能为 null 时才使用 nullable\nfun findUser(id: Long): User? {\n return userRepository.findById(id)\n}\n\n// ✅ 安全调用链 + Elvis\nval city = user?.address?.city ?: \"Unknown\"\n\n// ✅ let + 安全调用处理 nullable\nuser?.let { activeUser ->\n sendWelcomeEmail(activeUser)\n}\n\n// ✅ require / check 做前置条件校验\nfun updateUser(user: User?) {\n requireNotNull(user) { \"user must not be null\" }\n require(user.age >= 0) { \"age must be non-negative\" }\n check(user.isActive) { \"user must be active\" }\n}\n\n// ✅ 当表达式真正需要 early return\nval name = user?.name ?: return\nval email = user?.email ?: throw IllegalStateException(\"email required\")\n\n// ❌ 避免 !! 操作符\nval name = user!!.name // 可能抛 NPE\n\n// ❌ 避免无意义的 nullable\nfun getCount(): Int? = 42 // Int 就够了",
23
+ "rationale": "Kotlin 的类型系统在编译期防止 NPE,应充分利用这一能力"
24
+ },
25
+ "description": "Kotlin: 空安全最佳实践",
26
+ "kind": "rule",
27
+ "doClause": "Apply the Kotlin pattern as described",
28
+ "language": "kotlin",
29
+ "headers": [],
30
+ "category": "Tool",
31
+ "knowledgeType": "code-standard",
32
+ "usageGuide": "### 使用场景\\n触发 `@trigger` 获取Kotlin: 空安全最佳实践的标准实现模式。",
33
+ "scope": "universal",
34
+ "antiPattern": {
35
+ "bad": "val name = user!!.name // 或 user?.let { it.name } ?: \"\" 嵌套过深",
36
+ "why": "!! 绕过编译器保护,运行时可能 NPE;过深 let 嵌套降低可读性",
37
+ "fix": "使用 Elvis 操作符 ?: 或 early return;require/check 做入口校验"
38
+ },
39
+ "reasoning": {
40
+ "whyStandard": "Kotlin 官方编程约定及 Android 推荐",
41
+ "sources": [
42
+ "Kotlin Coding Conventions",
43
+ "Android Kotlin Style Guide"
44
+ ],
45
+ "confidence": 0.95
46
+ }
47
+ }
48
+ ```
49
+
50
+ ---
51
+
52
+ ## 2. 命名约定
53
+
54
+ ```json
55
+ {
56
+ "title": "Kotlin: 命名约定",
57
+ "content": {
58
+ "markdown": "## Kotlin: 命名约定\n\n### 标准模式\n```kotlin\n// ✅ 类/接口/对象: PascalCase\nclass UserService\ninterface UserRepository\nobject AppConfig\nsealed class Result<out T>\n\n// ✅ 函数/属性: camelCase\nfun getUserById(userId: Long): User\nval maxRetryCount = 3\n\n// ✅ 常量: UPPER_SNAKE_CASE\nconst val MAX_CONNECTIONS = 100\nval DEFAULT_TIMEOUT = 30.seconds // Duration, 非 const\n\n// ✅ 包名: 全小写,无下划线\npackage com.example.userservice\n\n// ✅ 后备属性: 下划线前缀\nprivate val _users = MutableStateFlow<List<User>>(emptyList())\nval users: StateFlow<List<User>> = _users.asStateFlow()\n\n// ✅ Composable 函数: PascalCase (特例)\n@Composable\nfun UserProfile(user: User) { ... }\n\n// ✅ 测试方法: 反引号允许空格\n@Test\nfun `findById returns user when exists`() { ... }\n```",
59
+ "pattern": "// ✅ 类/接口/对象: PascalCase\nclass UserService\ninterface UserRepository\nobject AppConfig\nsealed class Result<out T>\n\n// ✅ 函数/属性: camelCase\nfun getUserById(userId: Long): User\nval maxRetryCount = 3\n\n// ✅ 常量: UPPER_SNAKE_CASE\nconst val MAX_CONNECTIONS = 100\nval DEFAULT_TIMEOUT = 30.seconds // Duration, 非 const\n\n// ✅ 包名: 全小写,无下划线\npackage com.example.userservice\n\n// ✅ 后备属性: 下划线前缀\nprivate val _users = MutableStateFlow<List<User>>(emptyList())\nval users: StateFlow<List<User>> = _users.asStateFlow()\n\n// ✅ Composable 函数: PascalCase (特例)\n@Composable\nfun UserProfile(user: User) { ... }\n\n// ✅ 测试方法: 反引号允许空格\n@Test\nfun `findById returns user when exists`() { ... }",
60
+ "rationale": "统一的命名约定降低认知负担,后备属性是 Kotlin 惯用法"
61
+ },
62
+ "description": "Kotlin: 命名约定",
63
+ "kind": "rule",
64
+ "doClause": "Apply the Kotlin pattern as described",
65
+ "language": "kotlin",
66
+ "headers": [],
67
+ "knowledgeType": "code-standard",
68
+ "usageGuide": "### 使用场景\\n触发 `@trigger` 获取Kotlin: 命名约定的标准实现模式。",
69
+ "reasoning": {
70
+ "whyStandard": "Kotlin Coding Conventions - Naming rules",
71
+ "sources": [
72
+ "Kotlin Coding Conventions"
73
+ ],
74
+ "confidence": 0.95
75
+ }
76
+ }
77
+ ```
78
+
79
+ ### 命名速查表
80
+
81
+ | 标识符类型 | 风格 | 示例 |
82
+ |-----------|------|------|
83
+ | 类/接口/object | `PascalCase` | `UserService`, `Runnable` |
84
+ | 函数/属性 | `camelCase` | `getUserById`, `isActive` |
85
+ | 编译时常量 | `UPPER_SNAKE_CASE` | `MAX_RETRIES` |
86
+ | 后备属性 | `_camelCase` | `_users`, `_uiState` |
87
+ | 包 | 全小写 | `com.example.data` |
88
+ | 泛型参数 | 单字母或 `out T` | `T`, `out R` |
89
+ | 枚举值 | `UPPER_SNAKE_CASE` 或 `PascalCase` | `PENDING`, `Loading` |
90
+ | @Composable | `PascalCase` | `UserCard()` |
91
+ | 测试方法 | `` `descriptive name` `` | `` `should return user` `` |
92
+
93
+ ### 命名反模式
94
+
95
+ | 反模式 | 问题 | 修正 |
96
+ |--------|------|------|
97
+ | `IUserRepository` | 非 Kotlin 约定 | `UserRepository` |
98
+ | `mUserName` (m 前缀) | 匈牙利标记 | `userName` |
99
+ | `Companion.create()` | 伴生对象方法暴露 Companion | `User.create()` + `@JvmStatic` |
100
+ | `fun GetUser()` | 函数首字母大写 | `fun getUser()`(除 @Composable) |
101
+
102
+ ---
103
+
104
+ ## 3. Data Class 与 Sealed Class
105
+
106
+ ```json
107
+ {
108
+ "title": "Kotlin: data class 和 sealed class/interface",
109
+ "content": {
110
+ "markdown": "## Kotlin: data class 和 sealed class/interface\n\n### 标准模式\n```kotlin\n// ✅ data class: 不可变数据载体\ndata class User(\n val id: Long,\n val name: String,\n val email: String,\n val createdAt: Instant = Instant.now(),\n)\n\n// ✅ copy() 创建修改后的副本\nval updated = user.copy(name = \"New Name\")\n\n// ✅ sealed interface (推荐, 比 sealed class 更灵活)\nsealed interface Result<out T> {\n data class Success<T>(val data: T) : Result<T>\n data class Error(val message: String, val cause: Throwable? = null) : Result<Nothing>\n data object Loading : Result<Nothing>\n}\n\n// ✅ when 穷举 sealed class — 编译器确保完整\nfun handleResult(result: Result<User>) = when (result) {\n is Result.Success -> showUser(result.data)\n is Result.Error -> showError(result.message)\n is Result.Loading -> showLoading()\n // 无需 else\n}\n\n// ✅ value class (内联类,零开销包装)\n@JvmInline\nvalue class UserId(val value: Long)\n\n@JvmInline\nvalue class Email(val value: String) {\n init { require(value.contains('@')) { \"Invalid email\" } }\n}\n\nfun findUser(id: UserId): User // 类型安全,zero overhead\n```",
111
+ "pattern": "// ✅ data class: 不可变数据载体\ndata class User(\n val id: Long,\n val name: String,\n val email: String,\n val createdAt: Instant = Instant.now(),\n)\n\n// ✅ copy() 创建修改后的副本\nval updated = user.copy(name = \"New Name\")\n\n// ✅ sealed interface (推荐, 比 sealed class 更灵活)\nsealed interface Result<out T> {\n data class Success<T>(val data: T) : Result<T>\n data class Error(val message: String, val cause: Throwable? = null) : Result<Nothing>\n data object Loading : Result<Nothing>\n}\n\n// ✅ when 穷举 sealed class — 编译器确保完整\nfun handleResult(result: Result<User>) = when (result) {\n is Result.Success -> showUser(result.data)\n is Result.Error -> showError(result.message)\n is Result.Loading -> showLoading()\n // 无需 else\n}\n\n// ✅ value class (内联类,零开销包装)\n@JvmInline\nvalue class UserId(val value: Long)\n\n@JvmInline\nvalue class Email(val value: String) {\n init { require(value.contains('@')) { \"Invalid email\" } }\n}\n\nfun findUser(id: UserId): User // 类型安全,zero overhead",
112
+ "rationale": "Kotlin: data class 和 sealed class/interface的标准实现模式。"
113
+ },
114
+ "description": "Kotlin: data class 和 sealed class/interface",
115
+ "kind": "pattern",
116
+ "doClause": "Apply the Kotlin pattern as described",
117
+ "language": "kotlin",
118
+ "headers": [],
119
+ "knowledgeType": "code-pattern",
120
+ "usageGuide": "### 使用场景\\n触发 `@trigger` 获取Kotlin: data class 和 sealed class/interface的标准实现模式。",
121
+ "antiPattern": {
122
+ "bad": "sealed class Result { class Success(val data: Any) : Result() }",
123
+ "why": "data 关键字缺失 → 无 equals/hashCode/copy/toString;Any 类型不安全",
124
+ "fix": "使用 data class + 泛型参数"
125
+ },
126
+ "reasoning": {
127
+ "whyStandard": "Kotlin 官方推荐的 ADT 模式",
128
+ "sources": [
129
+ "Kotlin Docs - Sealed Classes",
130
+ "Kotlin Docs - Inline Classes"
131
+ ],
132
+ "confidence": 0.95
133
+ }
134
+ }
135
+ ```
136
+
137
+ ---
138
+
139
+ ## 4. 协程 (Coroutines)
140
+
141
+ ```json
142
+ {
143
+ "title": "Kotlin: 协程最佳实践",
144
+ "content": {
145
+ "markdown": "## Kotlin: 协程最佳实践\n\n### 标准模式\n```kotlin\nimport kotlinx.coroutines.*\n\n// ✅ suspend 函数 — 主线程安全\nsuspend fun fetchUser(id: Long): User =\n withContext(Dispatchers.IO) {\n api.getUser(id)\n }\n\n// ✅ 结构化并发 — coroutineScope 自动等待所有子任务\nsuspend fun loadDashboard(userId: Long): Dashboard =\n coroutineScope {\n val user = async { fetchUser(userId) }\n val orders = async { fetchOrders(userId) }\n Dashboard(user.await(), orders.await())\n }\n\n// ✅ supervisorScope — 子任务失败不影响兄弟\nsuspend fun loadDashboardSafe(userId: Long): Dashboard =\n supervisorScope {\n val user = async { fetchUser(userId) }\n val orders = async {\n try { fetchOrders(userId) }\n catch (e: Exception) { emptyList() }\n }\n Dashboard(user.await(), orders.await())\n }\n\n// ✅ 异常处理\nval handler = CoroutineExceptionHandler { _, exception ->\n log.error(\"Coroutine failed\", exception)\n}\n\nscope.launch(handler) {\n riskyOperation()\n}\n\n// ✅ 取消协作: 检查 isActive 或使用 ensureActive()\nsuspend fun processItems(items: List<Item>) {\n for (item in items) {\n ensureActive() // 抛 CancellationException 如果已取消\n process(item)\n }\n}\n\n// ❌ 反模式\nGlobalScope.launch { ... } // 不受结构化并发管理,泄漏风险\nrunBlocking { ... } // 阻塞线程,慎用(仅 main/test)\n```",
146
+ "pattern": "import kotlinx.coroutines.*\n\n// ✅ suspend 函数 — 主线程安全\nsuspend fun fetchUser(id: Long): User =\n withContext(Dispatchers.IO) {\n api.getUser(id)\n }\n\n// ✅ 结构化并发 — coroutineScope 自动等待所有子任务\nsuspend fun loadDashboard(userId: Long): Dashboard =\n coroutineScope {\n val user = async { fetchUser(userId) }\n val orders = async { fetchOrders(userId) }\n Dashboard(user.await(), orders.await())\n }\n\n// ✅ supervisorScope — 子任务失败不影响兄弟\nsuspend fun loadDashboardSafe(userId: Long): Dashboard =\n supervisorScope {\n val user = async { fetchUser(userId) }\n val orders = async {\n try { fetchOrders(userId) }\n catch (e: Exception) { emptyList() }\n }\n Dashboard(user.await(), orders.await())\n }\n\n// ✅ 异常处理\nval handler = CoroutineExceptionHandler { _, exception ->\n log.error(\"Coroutine failed\", exception)\n}\n\nscope.launch(handler) {\n riskyOperation()\n}\n\n// ✅ 取消协作: 检查 isActive 或使用 ensureActive()\nsuspend fun processItems(items: List<Item>) {\n for (item in items) {\n ensureActive() // 抛 CancellationException 如果已取消\n process(item)\n }\n}\n\n// ❌ 反模式\nGlobalScope.launch { ... } // 不受结构化并发管理,泄漏风险\nrunBlocking { ... } // 阻塞线程,慎用(仅 main/test)",
147
+ "rationale": "Kotlin: 协程最佳实践的标准实现模式。"
148
+ },
149
+ "description": "Kotlin: 协程最佳实践",
150
+ "kind": "pattern",
151
+ "doClause": "Apply the Kotlin pattern as described",
152
+ "language": "kotlin",
153
+ "headers": [],
154
+ "knowledgeType": "best-practice",
155
+ "usageGuide": "### 使用场景\\n触发 `@trigger` 获取Kotlin: 协程最佳实践的标准实现模式。",
156
+ "antiPattern": {
157
+ "bad": "GlobalScope.launch { fetchUser(id) }",
158
+ "why": "GlobalScope 不受生命周期管理,协程泄漏;异常无法传播",
159
+ "fix": "使用 viewModelScope / lifecycleScope / 自定义 CoroutineScope"
160
+ },
161
+ "reasoning": {
162
+ "whyStandard": "Kotlin Coroutines Guide: Structured Concurrency",
163
+ "sources": [
164
+ "Kotlin Coroutines Guide",
165
+ "Android Coroutines Best Practices"
166
+ ],
167
+ "confidence": 0.95
168
+ }
169
+ }
170
+ ```
171
+
172
+ ### 协程反模式
173
+
174
+ | 反模式 | 问题 | 修正 |
175
+ |--------|------|------|
176
+ | `GlobalScope.launch` | 生命周期泄漏 | 使用结构化 scope |
177
+ | `runBlocking` 在主线程 | 阻塞 UI 线程 | `suspend` + scope.launch |
178
+ | 忽略 `CancellationException` | 破坏取消传播 | 重新抛出或不捕获 |
179
+ | `Dispatchers.IO` 到处用 | 不区分 CPU/IO | CPU 密集用 `Default` |
180
+ | `async { }.await()` 立即 | 失去并发意义 | 直接调用 suspend 函数 |
181
+
182
+ ---
183
+
184
+ ## 5. Flow
185
+
186
+ ```json
187
+ {
188
+ "title": "Kotlin: Flow 响应式数据流",
189
+ "content": {
190
+ "markdown": "## Kotlin: Flow 响应式数据流\n\n### 标准模式\n```kotlin\nimport kotlinx.coroutines.flow.*\n\n// ✅ Flow 生产者\nfun observeUsers(): Flow<List<User>> =\n userDao.observeAll()\n .map { entities -> entities.map { it.toUser() } }\n .distinctUntilChanged()\n .flowOn(Dispatchers.IO) // 上游切换到 IO 线程\n\n// ✅ StateFlow — 状态持有(替代 LiveData)\nclass UserViewModel : ViewModel() {\n private val _uiState = MutableStateFlow<UiState>(UiState.Loading)\n val uiState: StateFlow<UiState> = _uiState.asStateFlow()\n\n fun loadUsers() {\n viewModelScope.launch {\n _uiState.value = UiState.Loading\n try {\n val users = fetchUsers()\n _uiState.value = UiState.Success(users)\n } catch (e: Exception) {\n _uiState.value = UiState.Error(e.message ?: \"Unknown error\")\n }\n }\n }\n\n // ✅ stateIn 转换 Flow → StateFlow\n val users: StateFlow<List<User>> = userRepository.observeUsers()\n .stateIn(\n scope = viewModelScope,\n started = SharingStarted.WhileSubscribed(5_000),\n initialValue = emptyList(),\n )\n}\n\n// ✅ 在 Compose 中安全收集\n@Composable\nfun UserScreen(viewModel: UserViewModel = hiltViewModel()) {\n val uiState by viewModel.uiState.collectAsStateWithLifecycle()\n ...\n}\n\n// ✅ combine 合并多个 Flow\nval dashboard: Flow<Dashboard> = combine(\n userFlow,\n ordersFlow,\n notificationsFlow,\n) { user, orders, notifs -> Dashboard(user, orders, notifs) }\n```",
191
+ "pattern": "import kotlinx.coroutines.flow.*\n\n// ✅ Flow 生产者\nfun observeUsers(): Flow<List<User>> =\n userDao.observeAll()\n .map { entities -> entities.map { it.toUser() } }\n .distinctUntilChanged()\n .flowOn(Dispatchers.IO) // 上游切换到 IO 线程\n\n// ✅ StateFlow — 状态持有(替代 LiveData)\nclass UserViewModel : ViewModel() {\n private val _uiState = MutableStateFlow<UiState>(UiState.Loading)\n val uiState: StateFlow<UiState> = _uiState.asStateFlow()\n\n fun loadUsers() {\n viewModelScope.launch {\n _uiState.value = UiState.Loading\n try {\n val users = fetchUsers()\n _uiState.value = UiState.Success(users)\n } catch (e: Exception) {\n _uiState.value = UiState.Error(e.message ?: \"Unknown error\")\n }\n }\n }\n\n // ✅ stateIn 转换 Flow → StateFlow\n val users: StateFlow<List<User>> = userRepository.observeUsers()\n .stateIn(\n scope = viewModelScope,\n started = SharingStarted.WhileSubscribed(5_000),\n initialValue = emptyList(),\n )\n}\n\n// ✅ 在 Compose 中安全收集\n@Composable\nfun UserScreen(viewModel: UserViewModel = hiltViewModel()) {\n val uiState by viewModel.uiState.collectAsStateWithLifecycle()\n ...\n}\n\n// ✅ combine 合并多个 Flow\nval dashboard: Flow<Dashboard> = combine(\n userFlow,\n ordersFlow,\n notificationsFlow,\n) { user, orders, notifs -> Dashboard(user, orders, notifs) }",
192
+ "rationale": "StateFlow 替代 LiveData 成为 Android 推荐的状态管理方案"
193
+ },
194
+ "description": "Kotlin: Flow 响应式数据流",
195
+ "kind": "pattern",
196
+ "doClause": "Apply the Kotlin pattern as described",
197
+ "language": "kotlin",
198
+ "headers": [],
199
+ "knowledgeType": "code-pattern",
200
+ "usageGuide": "### 使用场景\\n触发 `@trigger` 获取Kotlin: Flow 响应式数据流的标准实现模式。",
201
+ "reasoning": {
202
+ "whyStandard": "Android 官方推荐 StateFlow + collectAsStateWithLifecycle",
203
+ "sources": [
204
+ "Android Docs - StateFlow",
205
+ "Kotlin Flow Guide"
206
+ ],
207
+ "confidence": 0.95
208
+ }
209
+ }
210
+ ```
211
+
212
+ ---
213
+
214
+ ## 6. 扩展函数与 Scope Functions
215
+
216
+ ```json
217
+ {
218
+ "title": "Kotlin: 扩展函数 + Scope Functions 使用指南",
219
+ "content": {
220
+ "markdown": "## Kotlin: 扩展函数 + Scope Functions 使用指南\n\n### 标准模式\n```kotlin\n// ✅ 工具类扩展 — 替代 Java static util 方法\nfun String.toSlug(): String =\n lowercase()\n .replace(Regex(\"[^a-z0-9\\\\s-]\"), \"\")\n .replace(Regex(\"\\\\s+\"), \"-\")\n .trim('-')\n\n// ✅ 为第三方类添加领域方法\nfun Instant.toLocalDate(zone: ZoneId = ZoneId.systemDefault()): LocalDate =\n atZone(zone).toLocalDate()\n\n// ━━━ Scope Functions 选择指南 ━━━\n//\n// | 函数 | 对象引用 | 返回值 | 典型场景 |\n// |--------|---------|---------|---------------------|\n// | let | it | lambda | 非空转换、作用域限定 |\n// | run | this | lambda | 对象配置 + 返回结果 |\n// | with | this | lambda | 对已知非空对象操作 |\n// | apply | this | 对象 | 对象初始化/配置 |\n// | also | it | 对象 | 副作用(日志、调试) |\n\n// ✅ apply: 初始化配置\nval config = ServerConfig().apply {\n host = \"localhost\"\n port = 8080\n maxConnections = 100\n}\n\n// ✅ let: 安全调用 + 转换\nval email = user?.email?.let { parseEmail(it) }\n\n// ✅ also: 日志/调试副作用\nreturn fetchUser(id).also {\n logger.info(\"Fetched user: ${it.name}\")\n}\n\n// ❌ 避免嵌套过深的 scope function\nuser?.let { u ->\n u.address?.let { addr ->\n addr.city?.let { ... } // 3 层嵌套 → 用 ?.chain\n }\n}\n```",
221
+ "pattern": "// ✅ 工具类扩展 — 替代 Java static util 方法\nfun String.toSlug(): String =\n lowercase()\n .replace(Regex(\"[^a-z0-9\\\\s-]\"), \"\")\n .replace(Regex(\"\\\\s+\"), \"-\")\n .trim('-')\n\n// ✅ 为第三方类添加领域方法\nfun Instant.toLocalDate(zone: ZoneId = ZoneId.systemDefault()): LocalDate =\n atZone(zone).toLocalDate()\n\n// ━━━ Scope Functions 选择指南 ━━━\n//\n// | 函数 | 对象引用 | 返回值 | 典型场景 |\n// |--------|---------|---------|---------------------|\n// | let | it | lambda | 非空转换、作用域限定 |\n// | run | this | lambda | 对象配置 + 返回结果 |\n// | with | this | lambda | 对已知非空对象操作 |\n// | apply | this | 对象 | 对象初始化/配置 |\n// | also | it | 对象 | 副作用(日志、调试) |\n\n// ✅ apply: 初始化配置\nval config = ServerConfig().apply {\n host = \"localhost\"\n port = 8080\n maxConnections = 100\n}\n\n// ✅ let: 安全调用 + 转换\nval email = user?.email?.let { parseEmail(it) }\n\n// ✅ also: 日志/调试副作用\nreturn fetchUser(id).also {\n logger.info(\"Fetched user: ${it.name}\")\n}\n\n// ❌ 避免嵌套过深的 scope function\nuser?.let { u ->\n u.address?.let { addr ->\n addr.city?.let { ... } // 3 层嵌套 → 用 ?.chain\n }\n}",
222
+ "rationale": "Kotlin: 扩展函数 + Scope Functions 使用指南的标准实现模式。"
223
+ },
224
+ "description": "Kotlin: 扩展函数 + Scope Functions 使用指南",
225
+ "kind": "pattern",
226
+ "doClause": "Apply the Kotlin pattern as described",
227
+ "language": "kotlin",
228
+ "headers": [],
229
+ "knowledgeType": "code-pattern",
230
+ "usageGuide": "### 使用场景\\n触发 `@trigger` 获取Kotlin: 扩展函数 + Scope Functions 使用指南的标准实现模式。",
231
+ "antiPattern": {
232
+ "bad": "user?.let { it.address?.let { it.city?.let { ... } } }",
233
+ "why": "多层 let 嵌套降低可读性,比 Java null check 更难读",
234
+ "fix": "使用安全调用链: user?.address?.city?.let { ... }"
235
+ },
236
+ "reasoning": {
237
+ "whyStandard": "Kotlin Coding Conventions - Scope functions",
238
+ "sources": [
239
+ "Kotlin Docs - Scope Functions"
240
+ ],
241
+ "confidence": 0.9
242
+ }
243
+ }
244
+ ```
245
+
246
+ ---
247
+
248
+ ## 7. 集合与序列
249
+
250
+ ```json
251
+ {
252
+ "title": "Kotlin: 集合操作最佳实践",
253
+ "content": {
254
+ "markdown": "## Kotlin: 集合操作最佳实践\n\n### 标准模式\n```kotlin\n// ✅ 不可变集合 (默认)\nval users: List<User> = listOf(user1, user2)\nval userMap: Map<Long, User> = mapOf(1L to user1, 2L to user2)\n\n// ✅ 可变集合 — 仅在需要时使用\nval mutableUsers = mutableListOf<User>()\nmutableUsers.add(newUser)\n\n// ✅ 集合变换 — 链式操作\nval activeEmails = users\n .filter { it.isActive }\n .map { it.email }\n .sorted()\n .distinct()\n\n// ✅ Sequence — 大集合惰性求值\nval result = hugeList.asSequence()\n .filter { it.isValid() } // 惰性\n .map { it.transform() } // 惰性\n .take(10) // 短路\n .toList() // 终端操作触发计算\n\n// ✅ buildList / buildMap (Kotlin 1.6+)\nval items = buildList {\n add(\"header\")\n addAll(body)\n if (showFooter) add(\"footer\")\n}\n\n// ✅ groupBy / associateBy\nval usersByRole: Map<Role, List<User>> = users.groupBy { it.role }\nval userById: Map<Long, User> = users.associateBy { it.id }\n\n// ✅ 解构\nval (name, age) = user // data class 解构\nfor ((key, value) in map) { ... }\n\n// ❌ 小集合不需要 Sequence\nlistOf(1, 2, 3).asSequence() // 过度优化\n\n// ❌ 可变集合暴露给外部\nclass Repo {\n val items = mutableListOf<Item>() // 外部可修改\n}\n```",
255
+ "pattern": "// ✅ 不可变集合 (默认)\nval users: List<User> = listOf(user1, user2)\nval userMap: Map<Long, User> = mapOf(1L to user1, 2L to user2)\n\n// ✅ 可变集合 — 仅在需要时使用\nval mutableUsers = mutableListOf<User>()\nmutableUsers.add(newUser)\n\n// ✅ 集合变换 — 链式操作\nval activeEmails = users\n .filter { it.isActive }\n .map { it.email }\n .sorted()\n .distinct()\n\n// ✅ Sequence — 大集合惰性求值\nval result = hugeList.asSequence()\n .filter { it.isValid() } // 惰性\n .map { it.transform() } // 惰性\n .take(10) // 短路\n .toList() // 终端操作触发计算\n\n// ✅ buildList / buildMap (Kotlin 1.6+)\nval items = buildList {\n add(\"header\")\n addAll(body)\n if (showFooter) add(\"footer\")\n}\n\n// ✅ groupBy / associateBy\nval usersByRole: Map<Role, List<User>> = users.groupBy { it.role }\nval userById: Map<Long, User> = users.associateBy { it.id }\n\n// ✅ 解构\nval (name, age) = user // data class 解构\nfor ((key, value) in map) { ... }\n\n// ❌ 小集合不需要 Sequence\nlistOf(1, 2, 3).asSequence() // 过度优化\n\n// ❌ 可变集合暴露给外部\nclass Repo {\n val items = mutableListOf<Item>() // 外部可修改\n}",
256
+ "rationale": "Kotlin 默认不可变集合提供安全性;Sequence 在大集合时避免中间分配"
257
+ },
258
+ "description": "Kotlin: 集合操作最佳实践",
259
+ "kind": "pattern",
260
+ "doClause": "Apply the Kotlin pattern as described",
261
+ "language": "kotlin",
262
+ "headers": [],
263
+ "knowledgeType": "code-pattern",
264
+ "usageGuide": "### 使用场景\\n触发 `@trigger` 获取Kotlin: 集合操作最佳实践的标准实现模式。",
265
+ "reasoning": {
266
+ "whyStandard": "Kotlin Docs - Collections; Effective Kotlin Item 1: 优先使用不可变",
267
+ "sources": [
268
+ "Kotlin Docs - Collections",
269
+ "Effective Kotlin"
270
+ ],
271
+ "confidence": 0.9
272
+ }
273
+ }
274
+ ```
275
+
276
+ ---
277
+
278
+ ## 8. 委托 (Delegation)
279
+
280
+ ```json
281
+ {
282
+ "title": "Kotlin: 属性委托与类委托",
283
+ "content": {
284
+ "markdown": "## Kotlin: 属性委托与类委托\n\n### 标准模式\n```kotlin\nimport kotlin.properties.Delegates\n\n// ✅ by lazy — 线程安全的延迟初始化\nval heavyObject: HeavyThing by lazy {\n HeavyThing.create() // 第一次访问时初始化\n}\n\n// ✅ Delegates.observable — 属性变更监听\nvar name: String by Delegates.observable(\"initial\") { _, old, new ->\n logger.info(\"name changed: $old → $new\")\n}\n\n// ✅ Delegates.vetoable — 带校验的属性\nvar age: Int by Delegates.vetoable(0) { _, _, new ->\n new >= 0 // return false 拒绝修改\n}\n\n// ✅ 自定义委托\nclass SharedPreferenceDelegate<T>(\n private val key: String,\n private val default: T,\n) : ReadWriteProperty<Any, T> {\n override fun getValue(thisRef: Any, property: KProperty<*>): T = ...\n override fun setValue(thisRef: Any, property: KProperty<*>, value: T) { ... }\n}\n\nvar userName: String by SharedPreferenceDelegate(\"user_name\", \"\")\n\n// ✅ 类委托 — 替代继承实现复用\nclass CountingSet<T>(\n private val inner: MutableSet<T> = mutableSetOf()\n) : MutableSet<T> by inner {\n var count = 0\n private set\n\n override fun add(element: T): Boolean {\n count++\n return inner.add(element)\n }\n}\n\n// ✅ Android: by viewModels() / by activityViewModels()\nclass UserFragment : Fragment() {\n private val viewModel: UserViewModel by viewModels()\n private val sharedVm: SharedViewModel by activityViewModels()\n}\n```",
285
+ "pattern": "import kotlin.properties.Delegates\n\n// ✅ by lazy — 线程安全的延迟初始化\nval heavyObject: HeavyThing by lazy {\n HeavyThing.create() // 第一次访问时初始化\n}\n\n// ✅ Delegates.observable — 属性变更监听\nvar name: String by Delegates.observable(\"initial\") { _, old, new ->\n logger.info(\"name changed: $old → $new\")\n}\n\n// ✅ Delegates.vetoable — 带校验的属性\nvar age: Int by Delegates.vetoable(0) { _, _, new ->\n new >= 0 // return false 拒绝修改\n}\n\n// ✅ 自定义委托\nclass SharedPreferenceDelegate<T>(\n private val key: String,\n private val default: T,\n) : ReadWriteProperty<Any, T> {\n override fun getValue(thisRef: Any, property: KProperty<*>): T = ...\n override fun setValue(thisRef: Any, property: KProperty<*>, value: T) { ... }\n}\n\nvar userName: String by SharedPreferenceDelegate(\"user_name\", \"\")\n\n// ✅ 类委托 — 替代继承实现复用\nclass CountingSet<T>(\n private val inner: MutableSet<T> = mutableSetOf()\n) : MutableSet<T> by inner {\n var count = 0\n private set\n\n override fun add(element: T): Boolean {\n count++\n return inner.add(element)\n }\n}\n\n// ✅ Android: by viewModels() / by activityViewModels()\nclass UserFragment : Fragment() {\n private val viewModel: UserViewModel by viewModels()\n private val sharedVm: SharedViewModel by activityViewModels()\n}",
286
+ "rationale": "委托消除样板代码,是 Kotlin 区别于 Java 的核心惯用法之一"
287
+ },
288
+ "description": "Kotlin: 属性委托与类委托",
289
+ "kind": "pattern",
290
+ "doClause": "Apply the Kotlin pattern as described",
291
+ "language": "kotlin",
292
+ "headers": [],
293
+ "knowledgeType": "code-pattern",
294
+ "usageGuide": "### 使用场景\\n触发 `@trigger` 获取Kotlin: 属性委托与类委托的标准实现模式。",
295
+ "reasoning": {
296
+ "whyStandard": "Kotlin Docs - Delegated Properties; Effective Kotlin Item 21",
297
+ "sources": [
298
+ "Kotlin Docs - Delegation"
299
+ ],
300
+ "confidence": 0.9
301
+ }
302
+ }
303
+ ```
304
+
305
+ ---
306
+
307
+ ## 9. 依赖注入
308
+
309
+ ```json
310
+ {
311
+ "title": "Kotlin: 构造函数注入 (Hilt/Koin)",
312
+ "content": {
313
+ "markdown": "## Kotlin: 构造函数注入 (Hilt/Koin)\n\n### 标准模式\n```kotlin\n// ━━━ Hilt (推荐 Android 项目) ━━━\n\n@HiltAndroidApp\nclass MyApplication : Application()\n\n@AndroidEntryPoint\nclass UserFragment : Fragment() {\n private val viewModel: UserViewModel by viewModels()\n}\n\n@HiltViewModel\nclass UserViewModel @Inject constructor(\n private val userRepository: UserRepository,\n private val savedStateHandle: SavedStateHandle,\n) : ViewModel() { ... }\n\n// ✅ Hilt Module 绑定接口\n@Module\n@InstallIn(SingletonComponent::class)\nabstract class RepositoryModule {\n @Binds\n abstract fun bindUserRepo(impl: UserRepositoryImpl): UserRepository\n}\n\n// ━━━ Koin (轻量级, 多平台) ━━━\n\nval appModule = module {\n single<UserRepository> { UserRepositoryImpl(get()) }\n viewModel { UserViewModel(get()) }\n factory { CreateUserUseCase(get()) }\n}\n\n// ❌ 反模式\nclass UserViewModel {\n val repo = UserRepositoryImpl() // 硬编码依赖,不可测试\n}\n```",
314
+ "pattern": "// ━━━ Hilt (推荐 Android 项目) ━━━\n\n@HiltAndroidApp\nclass MyApplication : Application()\n\n@AndroidEntryPoint\nclass UserFragment : Fragment() {\n private val viewModel: UserViewModel by viewModels()\n}\n\n@HiltViewModel\nclass UserViewModel @Inject constructor(\n private val userRepository: UserRepository,\n private val savedStateHandle: SavedStateHandle,\n) : ViewModel() { ... }\n\n// ✅ Hilt Module 绑定接口\n@Module\n@InstallIn(SingletonComponent::class)\nabstract class RepositoryModule {\n @Binds\n abstract fun bindUserRepo(impl: UserRepositoryImpl): UserRepository\n}\n\n// ━━━ Koin (轻量级, 多平台) ━━━\n\nval appModule = module {\n single<UserRepository> { UserRepositoryImpl(get()) }\n viewModel { UserViewModel(get()) }\n factory { CreateUserUseCase(get()) }\n}\n\n// ❌ 反模式\nclass UserViewModel {\n val repo = UserRepositoryImpl() // 硬编码依赖,不可测试\n}",
315
+ "rationale": "构造函数注入让依赖可见、可测试、不可变"
316
+ },
317
+ "description": "Kotlin: 构造函数注入 (Hilt/Koin)",
318
+ "kind": "pattern",
319
+ "doClause": "Apply the Kotlin pattern as described",
320
+ "language": "kotlin",
321
+ "headers": [],
322
+ "knowledgeType": "best-practice",
323
+ "usageGuide": "### 使用场景\\n触发 `@trigger` 获取Kotlin: 构造函数注入 (Hilt/Koin)的标准实现模式。",
324
+ "reasoning": {
325
+ "whyStandard": "Android 官方推荐 Hilt; Koin 是 Kotlin 优先的轻量方案",
326
+ "sources": [
327
+ "Android Hilt Guide",
328
+ "Koin Docs"
329
+ ],
330
+ "confidence": 0.9
331
+ }
332
+ }
333
+ ```
334
+
335
+ ---
336
+
337
+ ## 10. Jetpack Compose
338
+
339
+ ```json
340
+ {
341
+ "title": "Kotlin: Composable 函数约定",
342
+ "content": {
343
+ "markdown": "## Kotlin: Composable 函数约定\n\n### 标准模式\n```kotlin\n@Composable\nfun UserCard(\n user: User,\n onEdit: (User) -> Unit,\n modifier: Modifier = Modifier, // modifier 参数排最后\n) {\n // ✅ remember 缓存计算\n val formattedDate = remember(user.createdAt) {\n dateFormatter.format(user.createdAt)\n }\n\n // ✅ 单向数据流: state hoisting\n Card(modifier = modifier) {\n Text(text = user.name)\n Text(text = formattedDate)\n Button(onClick = { onEdit(user) }) {\n Text(\"Edit\")\n }\n }\n}\n\n// ✅ 状态管理 + collectAsStateWithLifecycle\n@Composable\nfun UserScreen(viewModel: UserViewModel = hiltViewModel()) {\n val uiState by viewModel.uiState.collectAsStateWithLifecycle()\n when (val state = uiState) {\n is UiState.Loading -> CircularProgressIndicator()\n is UiState.Success -> UserList(state.users)\n is UiState.Error -> ErrorMessage(state.message)\n }\n}\n\n// ✅ 副作用 API\n@Composable\nfun UserScreen(userId: Long, viewModel: UserViewModel = hiltViewModel()) {\n // LaunchedEffect: 在 Composition 中启动协程\n LaunchedEffect(userId) {\n viewModel.loadUser(userId)\n }\n\n // DisposableEffect: 需要清理的副作用\n DisposableEffect(Unit) {\n val listener = EventBus.subscribe { ... }\n onDispose { listener.unsubscribe() }\n }\n}\n\n// ✅ Compose 命名约定\n// Stateful: UserScreen() — 包含 ViewModel\n// Stateless: UserContent(state, onAction) — 纯 UI\n\n// ❌ 在 @Composable 中直接调 ViewModel 方法修改状态\n// ❌ remember {} 不带 key — 值永远不更新\n```",
344
+ "pattern": "@Composable\nfun UserCard(\n user: User,\n onEdit: (User) -> Unit,\n modifier: Modifier = Modifier, // modifier 参数排最后\n) {\n // ✅ remember 缓存计算\n val formattedDate = remember(user.createdAt) {\n dateFormatter.format(user.createdAt)\n }\n\n // ✅ 单向数据流: state hoisting\n Card(modifier = modifier) {\n Text(text = user.name)\n Text(text = formattedDate)\n Button(onClick = { onEdit(user) }) {\n Text(\"Edit\")\n }\n }\n}\n\n// ✅ 状态管理 + collectAsStateWithLifecycle\n@Composable\nfun UserScreen(viewModel: UserViewModel = hiltViewModel()) {\n val uiState by viewModel.uiState.collectAsStateWithLifecycle()\n when (val state = uiState) {\n is UiState.Loading -> CircularProgressIndicator()\n is UiState.Success -> UserList(state.users)\n is UiState.Error -> ErrorMessage(state.message)\n }\n}\n\n// ✅ 副作用 API\n@Composable\nfun UserScreen(userId: Long, viewModel: UserViewModel = hiltViewModel()) {\n // LaunchedEffect: 在 Composition 中启动协程\n LaunchedEffect(userId) {\n viewModel.loadUser(userId)\n }\n\n // DisposableEffect: 需要清理的副作用\n DisposableEffect(Unit) {\n val listener = EventBus.subscribe { ... }\n onDispose { listener.unsubscribe() }\n }\n}\n\n// ✅ Compose 命名约定\n// Stateful: UserScreen() — 包含 ViewModel\n// Stateless: UserContent(state, onAction) — 纯 UI\n\n// ❌ 在 @Composable 中直接调 ViewModel 方法修改状态\n// ❌ remember {} 不带 key — 值永远不更新",
345
+ "rationale": "状态提升 + 单向数据流是 Compose 核心架构原则"
346
+ },
347
+ "description": "Kotlin: Composable 函数约定",
348
+ "kind": "pattern",
349
+ "doClause": "Apply the Kotlin pattern as described",
350
+ "language": "kotlin",
351
+ "headers": [],
352
+ "knowledgeType": "code-pattern",
353
+ "usageGuide": "### 使用场景\\n触发 `@trigger` 获取Kotlin: Composable 函数约定的标准实现模式。",
354
+ "reasoning": {
355
+ "whyStandard": "Android Compose 官方架构指南",
356
+ "sources": [
357
+ "Android Compose Docs",
358
+ "Compose API Guidelines"
359
+ ],
360
+ "confidence": 0.9
361
+ }
362
+ }
363
+ ```
364
+
365
+ ---
366
+
367
+ ## 11. DSL 与高阶函数
368
+
369
+ ```json
370
+ {
371
+ "title": "Kotlin: DSL 构建器模式",
372
+ "content": {
373
+ "markdown": "## Kotlin: DSL 构建器模式\n\n### 标准模式\n```kotlin\n// ✅ 类型安全的 DSL Builder\n@DslMarker\nannotation class HtmlDsl\n\n@HtmlDsl\nclass HTML {\n private val children = mutableListOf<Element>()\n fun head(init: Head.() -> Unit) { children += Head().apply(init) }\n fun body(init: Body.() -> Unit) { children += Body().apply(init) }\n}\n\nfun html(init: HTML.() -> Unit): HTML = HTML().apply(init)\n\n// 使用\nval page = html {\n head { title(\"My Page\") }\n body {\n h1(\"Hello\")\n p(\"World\")\n }\n}\n\n// ✅ 高阶函数 — inline 避免 lambda 对象分配\ninline fun <T> measureTime(block: () -> T): Pair<T, Duration> {\n val start = System.nanoTime()\n val result = block()\n val elapsed = (System.nanoTime() - start).nanoseconds\n return result to elapsed\n}\n\n// ✅ trailing lambda 语法\nuserList.filter { it.isActive }\n .sortedBy { it.name }\n .forEach { println(it) }\n\n// ❌ @DslMarker 缺失会导致外层 receiver 泄漏\nhtml {\n body {\n head { ... } // 不应在 body 内调 head\n }\n}\n```",
374
+ "pattern": "// ✅ 类型安全的 DSL Builder\n@DslMarker\nannotation class HtmlDsl\n\n@HtmlDsl\nclass HTML {\n private val children = mutableListOf<Element>()\n fun head(init: Head.() -> Unit) { children += Head().apply(init) }\n fun body(init: Body.() -> Unit) { children += Body().apply(init) }\n}\n\nfun html(init: HTML.() -> Unit): HTML = HTML().apply(init)\n\n// 使用\nval page = html {\n head { title(\"My Page\") }\n body {\n h1(\"Hello\")\n p(\"World\")\n }\n}\n\n// ✅ 高阶函数 — inline 避免 lambda 对象分配\ninline fun <T> measureTime(block: () -> T): Pair<T, Duration> {\n val start = System.nanoTime()\n val result = block()\n val elapsed = (System.nanoTime() - start).nanoseconds\n return result to elapsed\n}\n\n// ✅ trailing lambda 语法\nuserList.filter { it.isActive }\n .sortedBy { it.name }\n .forEach { println(it) }\n\n// ❌ @DslMarker 缺失会导致外层 receiver 泄漏\nhtml {\n body {\n head { ... } // 不应在 body 内调 head\n }\n}",
375
+ "rationale": "DSL 是 Kotlin 特色能力 (Gradle Kotlin DSL, Ktor routing, Compose)"
376
+ },
377
+ "description": "Kotlin: DSL 构建器模式",
378
+ "kind": "pattern",
379
+ "doClause": "Apply the Kotlin pattern as described",
380
+ "language": "kotlin",
381
+ "headers": [],
382
+ "knowledgeType": "code-pattern",
383
+ "usageGuide": "### 使用场景\\n触发 `@trigger` 获取Kotlin: DSL 构建器模式的标准实现模式。",
384
+ "reasoning": {
385
+ "whyStandard": "Kotlin Docs - Type-safe Builders; Effective Kotlin Item 43-44",
386
+ "sources": [
387
+ "Kotlin Docs - Type-safe Builders"
388
+ ],
389
+ "confidence": 0.85
390
+ }
391
+ }
392
+ ```
393
+
394
+ ---
395
+
396
+ ## 12. 错误处理
397
+
398
+ ```json
399
+ {
400
+ "title": "Kotlin: 错误处理模式",
401
+ "content": {
402
+ "markdown": "## Kotlin: 错误处理模式\n\n### 标准模式\n```kotlin\n// ✅ sealed class Result 替代异常 (业务层)\nsealed interface AppResult<out T> {\n data class Success<T>(val data: T) : AppResult<T>\n data class Failure(val error: AppError) : AppResult<Nothing>\n}\n\nsealed class AppError {\n data class NotFound(val resource: String) : AppError()\n data class Validation(val field: String, val message: String) : AppError()\n data class Network(val cause: Throwable) : AppError()\n}\n\n// ✅ runCatching — stdlib 的 Result 封装\nval result: Result<User> = runCatching { api.getUser(id) }\nresult\n .onSuccess { user -> display(user) }\n .onFailure { error -> log.error(\"Failed\", error) }\n\n// ✅ getOrElse / getOrDefault\nval user = runCatching { api.getUser(id) }\n .getOrElse { User.anonymous() }\n\n// ✅ 异常仅用于真正异常情况\nfun parseAge(input: String): Int {\n return input.toIntOrNull()\n ?: throw ValidationException(\"Invalid age: $input\")\n}\n\n// ❌ 不要吞掉 CancellationException\ntry {\n suspendFunction()\n} catch (e: Exception) {\n // ⚠️ 如果 e 是 CancellationException,必须重新抛出\n if (e is CancellationException) throw e\n handleError(e)\n}\n```",
403
+ "pattern": "// ✅ sealed class Result 替代异常 (业务层)\nsealed interface AppResult<out T> {\n data class Success<T>(val data: T) : AppResult<T>\n data class Failure(val error: AppError) : AppResult<Nothing>\n}\n\nsealed class AppError {\n data class NotFound(val resource: String) : AppError()\n data class Validation(val field: String, val message: String) : AppError()\n data class Network(val cause: Throwable) : AppError()\n}\n\n// ✅ runCatching — stdlib 的 Result 封装\nval result: Result<User> = runCatching { api.getUser(id) }\nresult\n .onSuccess { user -> display(user) }\n .onFailure { error -> log.error(\"Failed\", error) }\n\n// ✅ getOrElse / getOrDefault\nval user = runCatching { api.getUser(id) }\n .getOrElse { User.anonymous() }\n\n// ✅ 异常仅用于真正异常情况\nfun parseAge(input: String): Int {\n return input.toIntOrNull()\n ?: throw ValidationException(\"Invalid age: $input\")\n}\n\n// ❌ 不要吞掉 CancellationException\ntry {\n suspendFunction()\n} catch (e: Exception) {\n // ⚠️ 如果 e 是 CancellationException,必须重新抛出\n if (e is CancellationException) throw e\n handleError(e)\n}",
404
+ "rationale": "Kotlin: 错误处理模式的标准实现模式。"
405
+ },
406
+ "description": "Kotlin: 错误处理模式",
407
+ "kind": "pattern",
408
+ "doClause": "Apply the Kotlin pattern as described",
409
+ "language": "kotlin",
410
+ "headers": [],
411
+ "knowledgeType": "best-practice",
412
+ "usageGuide": "### 使用场景\\n触发 `@trigger` 获取Kotlin: 错误处理模式的标准实现模式。",
413
+ "antiPattern": {
414
+ "bad": "try { ... } catch (e: Exception) { /* ignore */ }",
415
+ "why": "吞掉 CancellationException 破坏协程取消机制",
416
+ "fix": "捕获具体异常,或重新抛出 CancellationException"
417
+ },
418
+ "reasoning": {
419
+ "whyStandard": "Kotlin 偏向 sealed class Result 处理预期错误; 异常留给真正异常情况",
420
+ "sources": [
421
+ "Kotlin Result",
422
+ "Effective Kotlin Item 7"
423
+ ],
424
+ "confidence": 0.9
425
+ }
426
+ }
427
+ ```
428
+
429
+ ---
430
+
431
+ ## 13. inline / reified
432
+
433
+ ```json
434
+ {
435
+ "title": "Kotlin: inline 函数与 reified 类型参数",
436
+ "content": {
437
+ "markdown": "## Kotlin: inline 函数与 reified 类型参数\n\n### 标准模式\n```kotlin\n// ✅ inline 消除 lambda 对象分配开销\ninline fun <T> retry(\n times: Int = 3,\n block: () -> T,\n): T {\n var lastException: Exception? = null\n repeat(times) {\n try { return block() }\n catch (e: Exception) { lastException = e }\n }\n throw lastException!!\n}\n\n// ✅ reified — 保留泛型类型信息 (仅 inline 函数可用)\ninline fun <reified T> List<*>.filterIsInstance(): List<T> =\n filter { it is T }.map { it as T }\n\n// ✅ reified + startActivity\ninline fun <reified T : Activity> Context.startActivity(\n vararg extras: Pair<String, Any?>,\n) {\n val intent = Intent(this, T::class.java)\n extras.forEach { (key, value) ->\n when (value) {\n is String -> intent.putExtra(key, value)\n is Int -> intent.putExtra(key, value)\n is Boolean -> intent.putExtra(key, value)\n }\n }\n startActivity(intent)\n}\n\n// 使用\ncontext.startActivity<DetailActivity>(\n \"user_id\" to userId,\n \"show_header\" to true,\n)\n\n// ✅ crossinline — 禁止 non-local return\ninline fun transaction(crossinline block: () -> Unit) {\n try {\n begin()\n block() // block 不能 return 外层函数\n commit()\n } catch (e: Exception) {\n rollback()\n }\n}\n\n// ❌ 大型 inline 函数会导致调用点代码膨胀\ninline fun heavyOperation() { /* 100+ 行 */ } // 不应 inline\n```",
438
+ "pattern": "// ✅ inline 消除 lambda 对象分配开销\ninline fun <T> retry(\n times: Int = 3,\n block: () -> T,\n): T {\n var lastException: Exception? = null\n repeat(times) {\n try { return block() }\n catch (e: Exception) { lastException = e }\n }\n throw lastException!!\n}\n\n// ✅ reified — 保留泛型类型信息 (仅 inline 函数可用)\ninline fun <reified T> List<*>.filterIsInstance(): List<T> =\n filter { it is T }.map { it as T }\n\n// ✅ reified + startActivity\ninline fun <reified T : Activity> Context.startActivity(\n vararg extras: Pair<String, Any?>,\n) {\n val intent = Intent(this, T::class.java)\n extras.forEach { (key, value) ->\n when (value) {\n is String -> intent.putExtra(key, value)\n is Int -> intent.putExtra(key, value)\n is Boolean -> intent.putExtra(key, value)\n }\n }\n startActivity(intent)\n}\n\n// 使用\ncontext.startActivity<DetailActivity>(\n \"user_id\" to userId,\n \"show_header\" to true,\n)\n\n// ✅ crossinline — 禁止 non-local return\ninline fun transaction(crossinline block: () -> Unit) {\n try {\n begin()\n block() // block 不能 return 外层函数\n commit()\n } catch (e: Exception) {\n rollback()\n }\n}\n\n// ❌ 大型 inline 函数会导致调用点代码膨胀\ninline fun heavyOperation() { /* 100+ 行 */ } // 不应 inline",
439
+ "rationale": "inline 消除高阶函数开销; reified 是 Kotlin 独有能力,突破 JVM 类型擦除"
440
+ },
441
+ "description": "Kotlin: inline 函数与 reified 类型参数",
442
+ "kind": "pattern",
443
+ "doClause": "Apply the Kotlin pattern as described",
444
+ "language": "kotlin",
445
+ "headers": [],
446
+ "knowledgeType": "code-pattern",
447
+ "usageGuide": "### 使用场景\\n触发 `@trigger` 获取Kotlin: inline 函数与 reified 类型参数的标准实现模式。",
448
+ "reasoning": {
449
+ "whyStandard": "Kotlin Docs - Inline Functions; Effective Kotlin Item 46-48",
450
+ "sources": [
451
+ "Kotlin Docs - Inline Functions",
452
+ "Effective Kotlin"
453
+ ],
454
+ "confidence": 0.9
455
+ }
456
+ }
457
+ ```
458
+
459
+ ---
460
+
461
+ ## 14. 测试模式
462
+
463
+ ```json
464
+ {
465
+ "title": "Kotlin: 测试最佳实践 (JUnit 5 + Coroutines)",
466
+ "content": {
467
+ "markdown": "## Kotlin: 测试最佳实践 (JUnit 5 + Coroutines)\n\n### 标准模式\n```kotlin\n// ✅ 描述性测试方法名(反引号语法)\nclass UserServiceTest {\n\n private val mockRepo = mockk<UserRepository>()\n private val service = UserService(mockRepo)\n\n @Test\n fun `findById returns user when exists`() {\n // Given\n val user = User(1L, \"Alice\", \"alice@test.com\")\n every { mockRepo.findById(1L) } returns user\n\n // When\n val result = service.findById(1L)\n\n // Then\n assertThat(result).isEqualTo(user)\n verify(exactly = 1) { mockRepo.findById(1L) }\n }\n\n @Test\n fun `findById throws when not found`() {\n every { mockRepo.findById(99L) } returns null\n\n assertThrows<NotFoundException> {\n service.findById(99L)\n }\n }\n}\n\n// ✅ 协程测试 (kotlinx-coroutines-test)\nclass UserViewModelTest {\n\n @Test\n fun `loadUsers updates state`() = runTest {\n val repo = FakeUserRepository()\n val viewModel = UserViewModel(repo)\n\n viewModel.loadUsers()\n advanceUntilIdle() // 等待协程完成\n\n assertThat(viewModel.uiState.value)\n .isInstanceOf(UiState.Success::class.java)\n }\n}\n\n// ✅ Turbine 测试 Flow\n@Test\nfun `observeUsers emits updates`() = runTest {\n val flow = repo.observeUsers()\n flow.test {\n assertThat(awaitItem()).isEmpty()\n repo.insert(user)\n assertThat(awaitItem()).containsExactly(user)\n cancelAndIgnoreRemainingEvents()\n }\n}\n```",
468
+ "pattern": "// ✅ 描述性测试方法名(反引号语法)\nclass UserServiceTest {\n\n private val mockRepo = mockk<UserRepository>()\n private val service = UserService(mockRepo)\n\n @Test\n fun `findById returns user when exists`() {\n // Given\n val user = User(1L, \"Alice\", \"alice@test.com\")\n every { mockRepo.findById(1L) } returns user\n\n // When\n val result = service.findById(1L)\n\n // Then\n assertThat(result).isEqualTo(user)\n verify(exactly = 1) { mockRepo.findById(1L) }\n }\n\n @Test\n fun `findById throws when not found`() {\n every { mockRepo.findById(99L) } returns null\n\n assertThrows<NotFoundException> {\n service.findById(99L)\n }\n }\n}\n\n// ✅ 协程测试 (kotlinx-coroutines-test)\nclass UserViewModelTest {\n\n @Test\n fun `loadUsers updates state`() = runTest {\n val repo = FakeUserRepository()\n val viewModel = UserViewModel(repo)\n\n viewModel.loadUsers()\n advanceUntilIdle() // 等待协程完成\n\n assertThat(viewModel.uiState.value)\n .isInstanceOf(UiState.Success::class.java)\n }\n}\n\n// ✅ Turbine 测试 Flow\n@Test\nfun `observeUsers emits updates`() = runTest {\n val flow = repo.observeUsers()\n flow.test {\n assertThat(awaitItem()).isEmpty()\n repo.insert(user)\n assertThat(awaitItem()).containsExactly(user)\n cancelAndIgnoreRemainingEvents()\n }\n}",
469
+ "rationale": "runTest 确保协程在测试中可控; Turbine 是 Flow 测试的事实标准"
470
+ },
471
+ "description": "Kotlin: 测试最佳实践 (JUnit 5 + Coroutines)",
472
+ "kind": "pattern",
473
+ "doClause": "Apply the Kotlin pattern as described",
474
+ "language": "kotlin",
475
+ "headers": [],
476
+ "knowledgeType": "best-practice",
477
+ "usageGuide": "### 使用场景\\n触发 `@trigger` 获取Kotlin: 测试最佳实践 (JUnit 5 + Coroutines)的标准实现模式。",
478
+ "reasoning": {
479
+ "whyStandard": "kotlinx-coroutines-test + Turbine 是 Android 官方推荐测试方案",
480
+ "sources": [
481
+ "Kotlin Coroutines Testing",
482
+ "Turbine Docs"
483
+ ],
484
+ "confidence": 0.9
485
+ }
486
+ }
487
+ ```
488
+
489
+ ### 测试反模式
490
+
491
+ | 反模式 | 问题 | 修正 |
492
+ |--------|------|------|
493
+ | `runBlocking` 测试协程 | 无法控制 Dispatchers | `runTest` |
494
+ | `Thread.sleep(1000)` | 脆弱、慢 | `advanceUntilIdle()` |
495
+ | 测试使用真实网络 | 不稳定、慢 | 使用 `FakeRepository` 或 MockWebServer |
496
+ | 未验证 StateFlow 初始值 | 遗漏边界情况 | 用 Turbine 依次验证每个 emission |
497
+
498
+ ---
499
+
500
+ ## 15. Kotlin 特有维度 (extraDimensions)
501
+
502
+ 冷启动分析 Kotlin 项目时,除了通用维度,还应额外关注:
503
+
504
+ | 额外维度 | 寻找什么 | 候选类型 |
505
+ |---------|---------|---------|
506
+ | **空安全** | `!!` 使用率、nullable vs non-null 比例、require/check | `code-standard` |
507
+ | **协程模式** | CoroutineScope 管理、Dispatchers 使用、结构化并发 | `code-pattern` |
508
+ | **Flow/状态** | StateFlow, SharedFlow, stateIn, collectAsState | `code-pattern` |
509
+ | **数据建模** | data class, sealed class/interface, value class | `code-pattern` |
510
+ | **Compose** | 状态提升、remember、LaunchedEffect、副作用管理 | `code-pattern` |
511
+ | **委托** | by lazy, by viewModels, 自定义委托 | `code-pattern` |
512
+ | **扩展函数** | 合理使用 vs 滥用、scope function 嵌套深度 | `best-practice` |
513
+ | **多平台** | expect/actual, commonMain, KMP 库选择 | `architecture` |
514
+ | **Gradle** | Kotlin DSL (build.gradle.kts), 版本目录 | `config` |
515
+
516
+ ---
517
+
518
+ ## 关联 Skills
519
+
520
+ - **autosnippet-coldstart**: 冷启动分析模板
521
+ - **autosnippet-reference-java**: Java 业界最佳实践参考
522
+ - **autosnippet-reference-python**: Python 业界最佳实践参考
523
+ - **autosnippet-reference-jsts**: JavaScript/TypeScript 业界最佳实践参考
524
+ - **autosnippet-reference-objc**: Objective-C 业界最佳实践参考
525
+ - **autosnippet-reference-swift**: Swift 业界最佳实践参考
526
+ - **autosnippet-reference-dart**: Dart (Flutter) 业界最佳实践参考